summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile62
-rw-r--r--abc.dsp1314
-rw-r--r--abc.dsw29
-rw-r--r--abc.optbin0 -> 52736 bytes
-rw-r--r--abc.plg962
-rw-r--r--abc.rc26
-rwxr-xr-xdepends.sh13
-rw-r--r--src/base/abc/abc.c2158
-rw-r--r--src/base/abc/abc.h557
-rw-r--r--src/base/abc/abcAig.c321
-rw-r--r--src/base/abc/abcAttach.c396
-rw-r--r--src/base/abc/abcCheck.c848
-rw-r--r--src/base/abc/abcCollapse.c271
-rw-r--r--src/base/abc/abcCreate.c1121
-rw-r--r--src/base/abc/abcDfs.c446
-rw-r--r--src/base/abc/abcDsd.c48
-rw-r--r--src/base/abc/abcFanio.c196
-rw-r--r--src/base/abc/abcFpga.c247
-rw-r--r--src/base/abc/abcFraig.c585
-rw-r--r--src/base/abc/abcFunc.c419
-rw-r--r--src/base/abc/abcInt.h46
-rw-r--r--src/base/abc/abcLatch.c260
-rw-r--r--src/base/abc/abcMap.c439
-rw-r--r--src/base/abc/abcMinBase.c167
-rw-r--r--src/base/abc/abcMiter.c502
-rw-r--r--src/base/abc/abcNames.c406
-rw-r--r--src/base/abc/abcNetlist.c93
-rw-r--r--src/base/abc/abcPrint.c288
-rw-r--r--src/base/abc/abcRefs.c133
-rw-r--r--src/base/abc/abcRenode.c605
-rw-r--r--src/base/abc/abcSat.c252
-rw-r--r--src/base/abc/abcSop.c461
-rw-r--r--src/base/abc/abcStrash.c541
-rw-r--r--src/base/abc/abcSweep.c434
-rw-r--r--src/base/abc/abcTiming.c631
-rw-r--r--src/base/abc/abcUtil.c780
-rw-r--r--src/base/abc/abcVerify.c310
-rw-r--r--src/base/abc/module.make28
-rw-r--r--src/base/cmd/cmd.c1498
-rw-r--r--src/base/cmd/cmd.h65
-rw-r--r--src/base/cmd/cmdAlias.c120
-rw-r--r--src/base/cmd/cmdApi.c104
-rw-r--r--src/base/cmd/cmdFlag.c112
-rw-r--r--src/base/cmd/cmdHist.c55
-rw-r--r--src/base/cmd/cmdInt.h82
-rw-r--r--src/base/cmd/cmdUtils.c598
-rw-r--r--src/base/cmd/module.make6
-rw-r--r--src/base/io/io.c766
-rw-r--r--src/base/io/io.h74
-rw-r--r--src/base/io/ioInt.h49
-rw-r--r--src/base/io/ioRead.c74
-rw-r--r--src/base/io/ioReadBench.c227
-rw-r--r--src/base/io/ioReadBlif.c642
-rw-r--r--src/base/io/ioReadVerilog.c888
-rw-r--r--src/base/io/ioWriteBench.c224
-rw-r--r--src/base/io/ioWriteBlif.c344
-rw-r--r--src/base/io/ioWriteBlifLogic.c402
-rw-r--r--src/base/io/ioWriteCnf.c76
-rw-r--r--src/base/io/ioWriteGate.c263
-rw-r--r--src/base/io/module.make10
-rw-r--r--src/base/main/main.c267
-rw-r--r--src/base/main/main.h109
-rw-r--r--src/base/main/mainFrame.c417
-rw-r--r--src/base/main/mainInit.c96
-rw-r--r--src/base/main/mainInt.h107
-rw-r--r--src/base/main/mainUtils.c218
-rw-r--r--src/base/main/module.make4
-rw-r--r--src/bdd/cudd/cuBdd.make41
-rw-r--r--src/bdd/cudd/cudd.h959
-rw-r--r--src/bdd/cudd/cudd.make42
-rw-r--r--src/bdd/cudd/cuddAPI.c4409
-rw-r--r--src/bdd/cudd/cuddAddAbs.c566
-rw-r--r--src/bdd/cudd/cuddAddApply.c917
-rw-r--r--src/bdd/cudd/cuddAddFind.c283
-rw-r--r--src/bdd/cudd/cuddAddInv.c172
-rw-r--r--src/bdd/cudd/cuddAddIte.c613
-rw-r--r--src/bdd/cudd/cuddAddNeg.c262
-rw-r--r--src/bdd/cudd/cuddAddWalsh.c364
-rw-r--r--src/bdd/cudd/cuddAndAbs.c306
-rw-r--r--src/bdd/cudd/cuddAnneal.c788
-rw-r--r--src/bdd/cudd/cuddApa.c930
-rw-r--r--src/bdd/cudd/cuddApprox.c2192
-rw-r--r--src/bdd/cudd/cuddBddAbs.c689
-rw-r--r--src/bdd/cudd/cuddBddCorr.c481
-rw-r--r--src/bdd/cudd/cuddBddIte.c1254
-rw-r--r--src/bdd/cudd/cuddBridge.c981
-rw-r--r--src/bdd/cudd/cuddCache.c1023
-rw-r--r--src/bdd/cudd/cuddCheck.c851
-rw-r--r--src/bdd/cudd/cuddClip.c531
-rw-r--r--src/bdd/cudd/cuddCof.c300
-rw-r--r--src/bdd/cudd/cuddCompose.c1722
-rw-r--r--src/bdd/cudd/cuddDecomp.c2150
-rw-r--r--src/bdd/cudd/cuddEssent.c279
-rw-r--r--src/bdd/cudd/cuddExact.c1004
-rw-r--r--src/bdd/cudd/cuddExport.c1289
-rw-r--r--src/bdd/cudd/cuddGenCof.c1968
-rw-r--r--src/bdd/cudd/cuddGenetic.c921
-rw-r--r--src/bdd/cudd/cuddGroup.c2142
-rw-r--r--src/bdd/cudd/cuddHarwell.c541
-rw-r--r--src/bdd/cudd/cuddInit.c283
-rw-r--r--src/bdd/cudd/cuddInt.h1133
-rw-r--r--src/bdd/cudd/cuddInteract.c402
-rw-r--r--src/bdd/cudd/cuddLCache.c1428
-rw-r--r--src/bdd/cudd/cuddLevelQ.c533
-rw-r--r--src/bdd/cudd/cuddLinear.c1333
-rw-r--r--src/bdd/cudd/cuddLiteral.c237
-rw-r--r--src/bdd/cudd/cuddMatMult.c680
-rw-r--r--src/bdd/cudd/cuddPriority.c1475
-rw-r--r--src/bdd/cudd/cuddRead.c490
-rw-r--r--src/bdd/cudd/cuddRef.c781
-rw-r--r--src/bdd/cudd/cuddReorder.c2090
-rw-r--r--src/bdd/cudd/cuddSat.c1305
-rw-r--r--src/bdd/cudd/cuddSign.c292
-rw-r--r--src/bdd/cudd/cuddSolve.c339
-rw-r--r--src/bdd/cudd/cuddSplit.c657
-rw-r--r--src/bdd/cudd/cuddSubsetHB.c1311
-rw-r--r--src/bdd/cudd/cuddSubsetSP.c1624
-rw-r--r--src/bdd/cudd/cuddSymmetry.c1668
-rw-r--r--src/bdd/cudd/cuddTable.c3141
-rw-r--r--src/bdd/cudd/cuddUtil.c3633
-rw-r--r--src/bdd/cudd/cuddWindow.c997
-rw-r--r--src/bdd/cudd/cuddZddCount.c324
-rw-r--r--src/bdd/cudd/cuddZddFuncs.c1603
-rw-r--r--src/bdd/cudd/cuddZddGroup.c1317
-rw-r--r--src/bdd/cudd/cuddZddIsop.c885
-rw-r--r--src/bdd/cudd/cuddZddLin.c939
-rw-r--r--src/bdd/cudd/cuddZddMisc.c252
-rw-r--r--src/bdd/cudd/cuddZddPort.c354
-rw-r--r--src/bdd/cudd/cuddZddReord.c1633
-rw-r--r--src/bdd/cudd/cuddZddSetop.c1137
-rw-r--r--src/bdd/cudd/cuddZddSymm.c1677
-rw-r--r--src/bdd/cudd/cuddZddUtil.c1021
-rw-r--r--src/bdd/cudd/module.make61
-rw-r--r--src/bdd/cudd/r7x8.1.mat53
-rw-r--r--src/bdd/cudd/testcudd.c988
-rw-r--r--src/bdd/dsd/dsd.h115
-rw-r--r--src/bdd/dsd/dsdApi.c95
-rw-r--r--src/bdd/dsd/dsdCheck.c314
-rw-r--r--src/bdd/dsd/dsdInt.h88
-rw-r--r--src/bdd/dsd/dsdLocal.c337
-rw-r--r--src/bdd/dsd/dsdMan.c113
-rw-r--r--src/bdd/dsd/dsdProc.c1607
-rw-r--r--src/bdd/dsd/dsdTree.c838
-rw-r--r--src/bdd/dsd/module.make6
-rw-r--r--src/bdd/epd/epd.c1314
-rw-r--r--src/bdd/epd/epd.h160
-rw-r--r--src/bdd/epd/module.make1
-rw-r--r--src/bdd/mtr/module.make2
-rw-r--r--src/bdd/mtr/mtr.h173
-rw-r--r--src/bdd/mtr/mtrBasic.c426
-rw-r--r--src/bdd/mtr/mtrGroup.c690
-rw-r--r--src/bdd/mtr/mtrInt.h65
-rw-r--r--src/bdd/parse/module.make2
-rw-r--r--src/bdd/parse/parse.h53
-rw-r--r--src/bdd/parse/parseCore.c504
-rw-r--r--src/bdd/parse/parseInt.h73
-rw-r--r--src/bdd/parse/parseStack.c243
-rw-r--r--src/bdd/reo/module.make7
-rw-r--r--src/bdd/reo/reo.h222
-rw-r--r--src/bdd/reo/reoApi.c289
-rw-r--r--src/bdd/reo/reoCore.c438
-rw-r--r--src/bdd/reo/reoProfile.c365
-rw-r--r--src/bdd/reo/reoSift.c341
-rw-r--r--src/bdd/reo/reoSwap.c898
-rw-r--r--src/bdd/reo/reoTest.c251
-rw-r--r--src/bdd/reo/reoTransfer.c199
-rw-r--r--src/bdd/reo/reoUnits.c184
-rw-r--r--src/generic.c47
-rw-r--r--src/generic.h51
-rw-r--r--src/map/fpga/fpga.c239
-rw-r--r--src/map/fpga/fpga.h158
-rw-r--r--src/map/fpga/fpgaCore.c241
-rw-r--r--src/map/fpga/fpgaCreate.c585
-rw-r--r--src/map/fpga/fpgaCut.c1150
-rw-r--r--src/map/fpga/fpgaCutUtils.c571
-rw-r--r--src/map/fpga/fpgaFanout.c139
-rw-r--r--src/map/fpga/fpgaGENERIC.c46
-rw-r--r--src/map/fpga/fpgaInt.h395
-rw-r--r--src/map/fpga/fpgaLib.c183
-rw-r--r--src/map/fpga/fpgaMatch.c729
-rw-r--r--src/map/fpga/fpgaTime.c189
-rw-r--r--src/map/fpga/fpgaTruth.c107
-rw-r--r--src/map/fpga/fpgaUtils.c1289
-rw-r--r--src/map/fpga/fpgaVec.c408
-rw-r--r--src/map/fpga/module.make12
-rw-r--r--src/map/mapper/mapper.c176
-rw-r--r--src/map/mapper/mapper.h181
-rw-r--r--src/map/mapper/mapperCanon.c161
-rw-r--r--src/map/mapper/mapperCore.c167
-rw-r--r--src/map/mapper/mapperCreate.c592
-rw-r--r--src/map/mapper/mapperCut.c1072
-rw-r--r--src/map/mapper/mapperCutUtils.c273
-rw-r--r--src/map/mapper/mapperFanout.c139
-rw-r--r--src/map/mapper/mapperGENERIC.c46
-rw-r--r--src/map/mapper/mapperInt.h475
-rw-r--r--src/map/mapper/mapperLib.c233
-rw-r--r--src/map/mapper/mapperMatch.c578
-rw-r--r--src/map/mapper/mapperRefs.c541
-rw-r--r--src/map/mapper/mapperSuper.c449
-rw-r--r--src/map/mapper/mapperTable.c402
-rw-r--r--src/map/mapper/mapperTime.c508
-rw-r--r--src/map/mapper/mapperTree.c804
-rw-r--r--src/map/mapper/mapperTruth.c449
-rw-r--r--src/map/mapper/mapperUtils.c1254
-rw-r--r--src/map/mapper/mapperVec.c318
-rw-r--r--src/map/mapper/module.make17
-rw-r--r--src/map/mio/mio.c269
-rw-r--r--src/map/mio/mio.h136
-rw-r--r--src/map/mio/mioApi.c145
-rw-r--r--src/map/mio/mioFunc.c268
-rw-r--r--src/map/mio/mioGENERIC.c46
-rw-r--r--src/map/mio/mioInt.h124
-rw-r--r--src/map/mio/mioRead.c572
-rw-r--r--src/map/mio/mioUtils.c531
-rw-r--r--src/map/mio/module.make5
-rw-r--r--src/map/super/module.make4
-rw-r--r--src/map/super/super.c319
-rw-r--r--src/map/super/super.h51
-rw-r--r--src/map/super/superAnd.c696
-rw-r--r--src/map/super/superGENERIC.c46
-rw-r--r--src/map/super/superGate.c1324
-rw-r--r--src/map/super/superInt.h62
-rw-r--r--src/map/super/superWrite.c76
-rw-r--r--src/misc/extra/extra.h220
-rw-r--r--src/misc/extra/extraUtilBdd.c1018
-rw-r--r--src/misc/extra/extraUtilFile.c382
-rw-r--r--src/misc/extra/extraUtilMemory.c564
-rw-r--r--src/misc/extra/extraUtilMisc.c380
-rw-r--r--src/misc/extra/extraUtilProgress.c164
-rw-r--r--src/misc/extra/extraUtilReader.c367
-rw-r--r--src/misc/extra/module.make6
-rw-r--r--src/misc/st/module.make2
-rw-r--r--src/misc/st/st.c606
-rw-r--r--src/misc/st/st.h88
-rw-r--r--src/misc/st/stmm.c683
-rw-r--r--src/misc/st/stmm.h119
-rw-r--r--src/misc/util/cpu_stats.c122
-rw-r--r--src/misc/util/cpu_time.c128
-rw-r--r--src/misc/util/datalimit.c95
-rw-r--r--src/misc/util/getopt.c84
-rw-r--r--src/misc/util/leaks.h30
-rw-r--r--src/misc/util/module.make8
-rw-r--r--src/misc/util/pathsearch.c131
-rw-r--r--src/misc/util/safe_mem.c104
-rw-r--r--src/misc/util/stdlib_hack.h4
-rw-r--r--src/misc/util/strsav.c157
-rw-r--r--src/misc/util/texpand.c66
-rw-r--r--src/misc/util/util.h331
-rw-r--r--src/misc/vec/module.make1
-rw-r--r--src/misc/vec/vec.h58
-rw-r--r--src/misc/vec/vecFan.h361
-rw-r--r--src/misc/vec/vecInt.h496
-rw-r--r--src/misc/vec/vecPtr.h461
-rw-r--r--src/misc/vec/vecStr.h466
-rw-r--r--src/opt/module.make1
-rw-r--r--src/sat/asat/added.c126
-rw-r--r--src/sat/asat/main.c195
-rw-r--r--src/sat/asat/module.make2
-rw-r--r--src/sat/asat/solver.c1167
-rw-r--r--src/sat/asat/solver.h137
-rw-r--r--src/sat/asat/solver_vec.h53
-rw-r--r--src/sat/fraig/fraig.h194
-rw-r--r--src/sat/fraig/fraigApi.c280
-rw-r--r--src/sat/fraig/fraigCanon.c216
-rw-r--r--src/sat/fraig/fraigFanout.c175
-rw-r--r--src/sat/fraig/fraigFeed.c772
-rw-r--r--src/sat/fraig/fraigInt.h442
-rw-r--r--src/sat/fraig/fraigMan.c237
-rw-r--r--src/sat/fraig/fraigMem.c246
-rw-r--r--src/sat/fraig/fraigNode.c308
-rw-r--r--src/sat/fraig/fraigPrime.c142
-rw-r--r--src/sat/fraig/fraigSat.c1085
-rw-r--r--src/sat/fraig/fraigTable.c596
-rw-r--r--src/sat/fraig/fraigUtil.c969
-rw-r--r--src/sat/fraig/fraigVec.c545
-rw-r--r--src/sat/fraig/module.make12
-rw-r--r--src/sat/msat/module.make13
-rw-r--r--src/sat/msat/msat.h160
-rw-r--r--src/sat/msat/msatActivity.c158
-rw-r--r--src/sat/msat/msatClause.c524
-rw-r--r--src/sat/msat/msatClauseVec.c232
-rw-r--r--src/sat/msat/msatInt.h304
-rw-r--r--src/sat/msat/msatMem.c529
-rw-r--r--src/sat/msat/msatOrderH.c405
-rw-r--r--src/sat/msat/msatOrderJ.c466
-rw-r--r--src/sat/msat/msatQueue.c157
-rw-r--r--src/sat/msat/msatRead.c268
-rw-r--r--src/sat/msat/msatSolverApi.c488
-rw-r--r--src/sat/msat/msatSolverCore.c187
-rw-r--r--src/sat/msat/msatSolverIo.c177
-rw-r--r--src/sat/msat/msatSolverSearch.c623
-rw-r--r--src/sat/msat/msatSort.c173
-rw-r--r--src/sat/msat/msatVec.c495
-rw-r--r--src/seq/module.make1
-rw-r--r--src/sop/ft/ft.h105
-rw-r--r--src/sop/ft/ftFactor.c842
-rw-r--r--src/sop/ft/ftPrint.c255
-rw-r--r--src/sop/ft/module.make2
-rw-r--r--src/sop/mvc/module.make16
-rw-r--r--src/sop/mvc/mvc.c46
-rw-r--r--src/sop/mvc/mvc.h733
-rw-r--r--src/sop/mvc/mvcApi.c233
-rw-r--r--src/sop/mvc/mvcCompare.c369
-rw-r--r--src/sop/mvc/mvcContain.c173
-rw-r--r--src/sop/mvc/mvcCover.c251
-rw-r--r--src/sop/mvc/mvcCube.c175
-rw-r--r--src/sop/mvc/mvcDivide.c436
-rw-r--r--src/sop/mvc/mvcDivisor.c90
-rw-r--r--src/sop/mvc/mvcList.c362
-rw-r--r--src/sop/mvc/mvcLits.c345
-rw-r--r--src/sop/mvc/mvcMan.c77
-rw-r--r--src/sop/mvc/mvcOpAlg.c163
-rw-r--r--src/sop/mvc/mvcOpBool.c151
-rw-r--r--src/sop/mvc/mvcPrint.c220
-rw-r--r--src/sop/mvc/mvcSort.c141
-rw-r--r--src/sop/mvc/mvcUtils.c868
316 files changed, 150814 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 00000000..5b4f3fab
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,62 @@
+
+CC := gcc
+CXX := g++
+LD := g++
+CP := cp
+
+PROG := abc
+
+MODULES := src/base/abc src/base/cmd src/base/io src/base/main \
+ src/bdd/cudd src/bdd/epd src/bdd/mtr src/bdd/parse \
+ src/map/fpga src/map/mapper src/map/mio src/map/super \
+ src/misc/extra src/misc/st src/misc/util src/misc/vec \
+ src/sat/asat src/sat/fraig src/sat/msat \
+ src/seq \
+ src/sop/ft src/sop/mvc
+
+default: $(PROG)
+
+CFLAGS += -Wall -Wno-unused-function -g -O $(patsubst %, -I%, $(MODULES))
+CXXFLAGS += $(CFLAGS)
+
+LIBS :=
+SRC :=
+GARBAGE := core core.* *.stackdump ./tags $(PROG)
+
+.PHONY: tags clean docs
+
+include $(patsubst %, %/module.make, $(MODULES))
+
+OBJ := \
+ $(patsubst %.cc, %.o, $(filter %.cc, $(SRC))) \
+ $(patsubst %.c, %.o, $(filter %.c, $(SRC))) \
+ $(patsubst %.y, %.o, $(filter %.y, $(SRC)))
+
+DEP := $(OBJ:.o=.d)
+
+# implicit rules
+
+%.d: %.c
+ ./depends.sh $(CC) `dirname $*.c` $(CFLAGS) $*.c > $@
+
+%.d: %.cc
+ ./depends.sh $(CXX) `dirname $*.cc` $(CXXFLAGS) $(CFLAGS) $*.cc > $@
+
+-include $(DEP)
+
+# Actual targets
+
+depend: $(DEP)
+
+clean:
+ rm -rf $(PROG) $(OBJ) $(GARBAGE) $(OBJ:.o=.d)
+
+tags:
+ ctags -R .
+
+$(PROG): $(OBJ)
+ $(LD) -o $@ $^ $(LIBS)
+
+docs:
+ doxygen doxygen.conf
+
diff --git a/abc.dsp b/abc.dsp
new file mode 100644
index 00000000..7b906c53
--- /dev/null
+++ b/abc.dsp
@@ -0,0 +1,1314 @@
+# Microsoft Developer Studio Project File - Name="abc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=abc - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "abc.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "abc.mak" CFG="abc - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "abc - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "abc - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "abc - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "src\base\abc" /I "src\base\cmd" /I "src\base\io" /I "src\base\main" /I "src\bdd\cudd" /I "src\bdd\epd" /I "src\bdd\mtr" /I "src\bdd\parse" /I "src\sop\mvc" /I "src\sop\ft" /I "src\sat\asat" /I "src\sat\msat" /I "src\sat\fraig" /I "src\opt\fxa" /I "src\map\fpga" /I "src\map\mapper" /I "src\map\mio" /I "src\map\super" /I "src\misc\extra" /I "src\misc\st" /I "src\misc\util" /I "src\misc\vec" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "__STDC__" /D "HAVE_ASSERT_H" /FR /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"_TEST/abc.exe"
+
+!ELSEIF "$(CFG)" == "abc - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "src\base\abc" /I "src\base\cmd" /I "src\base\io" /I "src\base\main" /I "src\bdd\cudd" /I "src\bdd\epd" /I "src\bdd\mtr" /I "src\bdd\parse" /I "src\sop\mvc" /I "src\sop\ft" /I "src\sat\asat" /I "src\sat\msat" /I "src\sat\fraig" /I "src\opt\fxa" /I "src\map\fpga" /I "src\map\mapper" /I "src\map\mio" /I "src\map\super" /I "src\misc\extra" /I "src\misc\st" /I "src\misc\util" /I "src\misc\vec" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "__STDC__" /D "HAVE_ASSERT_H" /FR /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"_TEST/abc.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "abc - Win32 Release"
+# Name "abc - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Group "base"
+
+# PROP Default_Filter ""
+# Begin Group "abc"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\base\abc\abc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcAig.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcAttach.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcCheck.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcCollapse.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcCreate.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcDfs.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcDsd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcFanio.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcFpga.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcFraig.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcFunc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcLatch.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcMap.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcMinBase.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcMiter.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcNames.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcNetlist.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcPrint.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcRefs.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcRenode.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcSat.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcSop.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcStrash.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcSweep.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcTiming.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcUtil.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\abc\abcVerify.c
+# End Source File
+# End Group
+# Begin Group "cmd"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\base\cmd\cmd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\cmd\cmd.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\cmd\cmdAlias.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\cmd\cmdApi.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\cmd\cmdFlag.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\cmd\cmdHist.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\cmd\cmdInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\cmd\cmdUtils.c
+# End Source File
+# End Group
+# Begin Group "io"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\base\io\io.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\io\io.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\io\ioInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\io\ioRead.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\io\ioReadBench.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\io\ioReadBlif.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\io\ioReadVerilog.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\io\ioWriteBench.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\io\ioWriteBlif.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\io\ioWriteBlifLogic.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\io\ioWriteCnf.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\io\ioWriteGate.c
+# End Source File
+# End Group
+# Begin Group "main"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\base\main\main.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\main\main.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\main\mainFrame.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\main\mainInit.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\main\mainInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\base\main\mainUtils.c
+# End Source File
+# End Group
+# End Group
+# Begin Group "bdd"
+
+# PROP Default_Filter ""
+# Begin Group "cudd"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cudd.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddAddAbs.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddAddApply.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddAddFind.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddAddInv.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddAddIte.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddAddNeg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddAddWalsh.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddAndAbs.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddAnneal.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddApa.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddAPI.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddApprox.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddBddAbs.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddBddCorr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddBddIte.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddBridge.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddCache.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddCheck.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddClip.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddCof.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddCompose.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddDecomp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddEssent.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddExact.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddExport.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddGenCof.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddGenetic.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddGroup.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddHarwell.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddInit.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddInteract.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddLCache.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddLevelQ.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddLinear.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddLiteral.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddMatMult.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddPriority.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddRead.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddRef.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddReorder.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddSat.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddSign.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddSolve.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddSplit.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddSubsetHB.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddSubsetSP.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddSymmetry.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddTable.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddUtil.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddWindow.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddZddCount.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddZddFuncs.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddZddGroup.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddZddIsop.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddZddLin.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddZddMisc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddZddPort.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddZddReord.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddZddSetop.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddZddSymm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\cudd\cuddZddUtil.c
+# End Source File
+# End Group
+# Begin Group "epd"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\bdd\epd\epd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\epd\epd.h
+# End Source File
+# End Group
+# Begin Group "mtr"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\bdd\mtr\mtr.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\mtr\mtrBasic.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\mtr\mtrGroup.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\mtr\mtrInt.h
+# End Source File
+# End Group
+# Begin Group "parse"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\bdd\parse\parse.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\parse\parseCore.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\parse\parseInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\parse\parseStack.c
+# End Source File
+# End Group
+# Begin Group "dsd"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\bdd\dsd\dsd.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\dsd\dsdApi.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\dsd\dsdCheck.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\dsd\dsdInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\dsd\dsdLocal.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\dsd\dsdMan.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\dsd\dsdProc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\dsd\dsdTree.c
+# End Source File
+# End Group
+# Begin Group "reo"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\bdd\reo\reo.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\reo\reoApi.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\reo\reoCore.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\reo\reoProfile.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\reo\reoSift.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\reo\reoSwap.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\reo\reoTest.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\reo\reoTransfer.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\bdd\reo\reoUnits.c
+# End Source File
+# End Group
+# End Group
+# Begin Group "sop"
+
+# PROP Default_Filter ""
+# Begin Group "mvc"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\sop\mvc\mvc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sop\mvc\mvc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sop\mvc\mvcApi.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sop\mvc\mvcCompare.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sop\mvc\mvcContain.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sop\mvc\mvcCover.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sop\mvc\mvcCube.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sop\mvc\mvcDivide.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sop\mvc\mvcDivisor.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sop\mvc\mvcList.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sop\mvc\mvcLits.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sop\mvc\mvcMan.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sop\mvc\mvcOpAlg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sop\mvc\mvcOpBool.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sop\mvc\mvcPrint.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sop\mvc\mvcSort.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sop\mvc\mvcUtils.c
+# End Source File
+# End Group
+# Begin Group "ft"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\sop\ft\ft.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sop\ft\ftFactor.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sop\ft\ftPrint.c
+# End Source File
+# End Group
+# End Group
+# Begin Group "sat"
+
+# PROP Default_Filter ""
+# Begin Group "asat"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\sat\asat\added.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\asat\solver.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\asat\solver.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\asat\solver_vec.h
+# End Source File
+# End Group
+# Begin Group "msat"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\sat\msat\msat.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\msat\msatActivity.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\msat\msatClause.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\msat\msatClauseVec.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\msat\msatInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\msat\msatMem.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\msat\msatOrderJ.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\msat\msatQueue.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\msat\msatRead.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\msat\msatSolverApi.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\msat\msatSolverCore.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\msat\msatSolverIo.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\msat\msatSolverSearch.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\msat\msatSort.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\msat\msatVec.c
+# End Source File
+# End Group
+# Begin Group "fraig"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\sat\fraig\fraig.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\fraig\fraigApi.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\fraig\fraigCanon.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\fraig\fraigFanout.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\fraig\fraigFeed.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\fraig\fraigInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\fraig\fraigMan.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\fraig\fraigMem.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\fraig\fraigNode.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\fraig\fraigPrime.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\fraig\fraigSat.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\fraig\fraigTable.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\fraig\fraigUtil.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sat\fraig\fraigVec.c
+# End Source File
+# End Group
+# End Group
+# Begin Group "opt"
+
+# PROP Default_Filter ""
+# Begin Group "fxa"
+
+# PROP Default_Filter ""
+# End Group
+# End Group
+# Begin Group "map"
+
+# PROP Default_Filter ""
+# Begin Group "fpga"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\map\fpga\fpga.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\fpga\fpga.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\fpga\fpgaCore.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\fpga\fpgaCreate.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\fpga\fpgaCut.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\fpga\fpgaCutUtils.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\fpga\fpgaFanout.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\fpga\fpgaInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\fpga\fpgaLib.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\fpga\fpgaMatch.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\fpga\fpgaTime.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\fpga\fpgaTruth.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\fpga\fpgaUtils.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\fpga\fpgaVec.c
+# End Source File
+# End Group
+# Begin Group "mapper"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\map\mapper\mapper.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mapper\mapper.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mapper\mapperCanon.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mapper\mapperCore.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mapper\mapperCreate.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mapper\mapperCut.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mapper\mapperCutUtils.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mapper\mapperFanout.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mapper\mapperInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mapper\mapperLib.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mapper\mapperMatch.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mapper\mapperRefs.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mapper\mapperSuper.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mapper\mapperTable.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mapper\mapperTime.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mapper\mapperTree.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mapper\mapperTruth.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mapper\mapperUtils.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mapper\mapperVec.c
+# End Source File
+# End Group
+# Begin Group "mio"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\map\mio\mio.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mio\mio.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mio\mioApi.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mio\mioFunc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mio\mioInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mio\mioRead.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\mio\mioUtils.c
+# End Source File
+# End Group
+# Begin Group "super"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\map\super\super.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\super\super.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\super\superAnd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\super\superGate.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\super\superInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\map\super\superWrite.c
+# End Source File
+# End Group
+# End Group
+# Begin Group "seq"
+
+# PROP Default_Filter ""
+# End Group
+# Begin Group "misc"
+
+# PROP Default_Filter ""
+# Begin Group "extra"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\misc\extra\extra.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\extra\extraUtilBdd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\extra\extraUtilFile.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\extra\extraUtilMemory.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\extra\extraUtilMisc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\extra\extraUtilProgress.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\extra\extraUtilReader.c
+# End Source File
+# End Group
+# Begin Group "st"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\misc\st\st.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\st\st.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\st\stmm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\st\stmm.h
+# End Source File
+# End Group
+# Begin Group "util"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\misc\util\cpu_stats.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\util\cpu_time.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\util\datalimit.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\util\getopt.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\util\leaks.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\util\pathsearch.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\util\safe_mem.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\util\stdlib_hack.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\util\strsav.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\util\texpand.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\util\util.h
+# End Source File
+# End Group
+# Begin Group "vec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\misc\vec\vec.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\vec\vecFan.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\vec\vecInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\vec\vecPtr.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc\vec\vecStr.h
+# End Source File
+# End Group
+# End Group
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/abc.dsw b/abc.dsw
new file mode 100644
index 00000000..83f94950
--- /dev/null
+++ b/abc.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "abc"=.\abc.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/abc.opt b/abc.opt
new file mode 100644
index 00000000..ca1164e8
--- /dev/null
+++ b/abc.opt
Binary files differ
diff --git a/abc.plg b/abc.plg
new file mode 100644
index 00000000..18db3d30
--- /dev/null
+++ b/abc.plg
@@ -0,0 +1,962 @@
+<html>
+<body>
+<pre>
+<h1>Build Log</h1>
+<h3>
+--------------------Configuration: abc - Win32 Release--------------------
+</h3>
+<h3>Command Lines</h3>
+Creating temporary file "C:\DOCUME~1\alanmi\LOCALS~1\Temp\RSP27C8.tmp" with contents
+[
+/nologo /ML /W3 /GX /O2 /I "src\base\abc" /I "src\base\cmd" /I "src\base\io" /I "src\base\main" /I "src\bdd\cudd" /I "src\bdd\epd" /I "src\bdd\mtr" /I "src\bdd\parse" /I "src\sop\mvc" /I "src\sop\ft" /I "src\sat\asat" /I "src\sat\msat" /I "src\sat\fraig" /I "src\opt\fxa" /I "src\map\fpga" /I "src\map\mapper" /I "src\map\mio" /I "src\map\super" /I "src\misc\extra" /I "src\misc\st" /I "src\misc\util" /I "src\misc\vec" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "__STDC__" /D "HAVE_ASSERT_H" /FR"Release/" /Fp"Release/abc.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c
+"C:\_projects\abc\src\base\abc\abc.c"
+"C:\_projects\abc\src\base\abc\abcAig.c"
+"C:\_projects\abc\src\base\abc\abcAttach.c"
+"C:\_projects\abc\src\base\abc\abcCheck.c"
+"C:\_projects\abc\src\base\abc\abcCollapse.c"
+"C:\_projects\abc\src\base\abc\abcCreate.c"
+"C:\_projects\abc\src\base\abc\abcDfs.c"
+"C:\_projects\abc\src\base\abc\abcDsd.c"
+"C:\_projects\abc\src\base\abc\abcFanio.c"
+"C:\_projects\abc\src\base\abc\abcFpga.c"
+"C:\_projects\abc\src\base\abc\abcFraig.c"
+"C:\_projects\abc\src\base\abc\abcFunc.c"
+"C:\_projects\abc\src\base\abc\abcLatch.c"
+"C:\_projects\abc\src\base\abc\abcMap.c"
+"C:\_projects\abc\src\base\abc\abcMinBase.c"
+"C:\_projects\abc\src\base\abc\abcMiter.c"
+"C:\_projects\abc\src\base\abc\abcNames.c"
+"C:\_projects\abc\src\base\abc\abcNetlist.c"
+"C:\_projects\abc\src\base\abc\abcPrint.c"
+"C:\_projects\abc\src\base\abc\abcRefs.c"
+"C:\_projects\abc\src\base\abc\abcRenode.c"
+"C:\_projects\abc\src\base\abc\abcSat.c"
+"C:\_projects\abc\src\base\abc\abcSop.c"
+"C:\_projects\abc\src\base\abc\abcStrash.c"
+"C:\_projects\abc\src\base\abc\abcSweep.c"
+"C:\_projects\abc\src\base\abc\abcTiming.c"
+"C:\_projects\abc\src\base\abc\abcUtil.c"
+"C:\_projects\abc\src\base\abc\abcVerify.c"
+"C:\_projects\abc\src\base\cmd\cmd.c"
+"C:\_projects\abc\src\base\cmd\cmdAlias.c"
+"C:\_projects\abc\src\base\cmd\cmdApi.c"
+"C:\_projects\abc\src\base\cmd\cmdFlag.c"
+"C:\_projects\abc\src\base\cmd\cmdHist.c"
+"C:\_projects\abc\src\base\cmd\cmdUtils.c"
+"C:\_projects\abc\src\base\io\io.c"
+"C:\_projects\abc\src\base\io\ioRead.c"
+"C:\_projects\abc\src\base\io\ioReadBench.c"
+"C:\_projects\abc\src\base\io\ioReadBlif.c"
+"C:\_projects\abc\src\base\io\ioReadVerilog.c"
+"C:\_projects\abc\src\base\io\ioWriteBench.c"
+"C:\_projects\abc\src\base\io\ioWriteBlif.c"
+"C:\_projects\abc\src\base\io\ioWriteBlifLogic.c"
+"C:\_projects\abc\src\base\io\ioWriteCnf.c"
+"C:\_projects\abc\src\base\io\ioWriteGate.c"
+"C:\_projects\abc\src\base\main\main.c"
+"C:\_projects\abc\src\base\main\mainFrame.c"
+"C:\_projects\abc\src\base\main\mainInit.c"
+"C:\_projects\abc\src\base\main\mainUtils.c"
+"C:\_projects\abc\src\bdd\cudd\cuddAddAbs.c"
+"C:\_projects\abc\src\bdd\cudd\cuddAddApply.c"
+"C:\_projects\abc\src\bdd\cudd\cuddAddFind.c"
+"C:\_projects\abc\src\bdd\cudd\cuddAddInv.c"
+"C:\_projects\abc\src\bdd\cudd\cuddAddIte.c"
+"C:\_projects\abc\src\bdd\cudd\cuddAddNeg.c"
+"C:\_projects\abc\src\bdd\cudd\cuddAddWalsh.c"
+"C:\_projects\abc\src\bdd\cudd\cuddAndAbs.c"
+"C:\_projects\abc\src\bdd\cudd\cuddAnneal.c"
+"C:\_projects\abc\src\bdd\cudd\cuddApa.c"
+"C:\_projects\abc\src\bdd\cudd\cuddAPI.c"
+"C:\_projects\abc\src\bdd\cudd\cuddApprox.c"
+"C:\_projects\abc\src\bdd\cudd\cuddBddAbs.c"
+"C:\_projects\abc\src\bdd\cudd\cuddBddCorr.c"
+"C:\_projects\abc\src\bdd\cudd\cuddBddIte.c"
+"C:\_projects\abc\src\bdd\cudd\cuddBridge.c"
+"C:\_projects\abc\src\bdd\cudd\cuddCache.c"
+"C:\_projects\abc\src\bdd\cudd\cuddCheck.c"
+"C:\_projects\abc\src\bdd\cudd\cuddClip.c"
+"C:\_projects\abc\src\bdd\cudd\cuddCof.c"
+"C:\_projects\abc\src\bdd\cudd\cuddCompose.c"
+"C:\_projects\abc\src\bdd\cudd\cuddDecomp.c"
+"C:\_projects\abc\src\bdd\cudd\cuddEssent.c"
+"C:\_projects\abc\src\bdd\cudd\cuddExact.c"
+"C:\_projects\abc\src\bdd\cudd\cuddExport.c"
+"C:\_projects\abc\src\bdd\cudd\cuddGenCof.c"
+"C:\_projects\abc\src\bdd\cudd\cuddGenetic.c"
+"C:\_projects\abc\src\bdd\cudd\cuddGroup.c"
+"C:\_projects\abc\src\bdd\cudd\cuddHarwell.c"
+"C:\_projects\abc\src\bdd\cudd\cuddInit.c"
+"C:\_projects\abc\src\bdd\cudd\cuddInteract.c"
+"C:\_projects\abc\src\bdd\cudd\cuddLCache.c"
+"C:\_projects\abc\src\bdd\cudd\cuddLevelQ.c"
+"C:\_projects\abc\src\bdd\cudd\cuddLinear.c"
+"C:\_projects\abc\src\bdd\cudd\cuddLiteral.c"
+"C:\_projects\abc\src\bdd\cudd\cuddMatMult.c"
+"C:\_projects\abc\src\bdd\cudd\cuddPriority.c"
+"C:\_projects\abc\src\bdd\cudd\cuddRead.c"
+"C:\_projects\abc\src\bdd\cudd\cuddRef.c"
+"C:\_projects\abc\src\bdd\cudd\cuddReorder.c"
+"C:\_projects\abc\src\bdd\cudd\cuddSat.c"
+"C:\_projects\abc\src\bdd\cudd\cuddSign.c"
+"C:\_projects\abc\src\bdd\cudd\cuddSolve.c"
+"C:\_projects\abc\src\bdd\cudd\cuddSplit.c"
+"C:\_projects\abc\src\bdd\cudd\cuddSubsetHB.c"
+"C:\_projects\abc\src\bdd\cudd\cuddSubsetSP.c"
+"C:\_projects\abc\src\bdd\cudd\cuddSymmetry.c"
+"C:\_projects\abc\src\bdd\cudd\cuddTable.c"
+"C:\_projects\abc\src\bdd\cudd\cuddUtil.c"
+"C:\_projects\abc\src\bdd\cudd\cuddWindow.c"
+"C:\_projects\abc\src\bdd\cudd\cuddZddCount.c"
+"C:\_projects\abc\src\bdd\cudd\cuddZddFuncs.c"
+"C:\_projects\abc\src\bdd\cudd\cuddZddGroup.c"
+"C:\_projects\abc\src\bdd\cudd\cuddZddIsop.c"
+"C:\_projects\abc\src\bdd\cudd\cuddZddLin.c"
+"C:\_projects\abc\src\bdd\cudd\cuddZddMisc.c"
+"C:\_projects\abc\src\bdd\cudd\cuddZddPort.c"
+"C:\_projects\abc\src\bdd\cudd\cuddZddReord.c"
+"C:\_projects\abc\src\bdd\cudd\cuddZddSetop.c"
+"C:\_projects\abc\src\bdd\cudd\cuddZddSymm.c"
+"C:\_projects\abc\src\bdd\cudd\cuddZddUtil.c"
+"C:\_projects\abc\src\bdd\epd\epd.c"
+"C:\_projects\abc\src\bdd\mtr\mtrBasic.c"
+"C:\_projects\abc\src\bdd\mtr\mtrGroup.c"
+"C:\_projects\abc\src\bdd\parse\parseCore.c"
+"C:\_projects\abc\src\bdd\parse\parseStack.c"
+"C:\_projects\abc\src\bdd\dsd\dsdApi.c"
+"C:\_projects\abc\src\bdd\dsd\dsdCheck.c"
+"C:\_projects\abc\src\bdd\dsd\dsdLocal.c"
+"C:\_projects\abc\src\bdd\dsd\dsdMan.c"
+"C:\_projects\abc\src\bdd\dsd\dsdProc.c"
+"C:\_projects\abc\src\bdd\dsd\dsdTree.c"
+"C:\_projects\abc\src\bdd\reo\reoApi.c"
+"C:\_projects\abc\src\bdd\reo\reoCore.c"
+"C:\_projects\abc\src\bdd\reo\reoProfile.c"
+"C:\_projects\abc\src\bdd\reo\reoSift.c"
+"C:\_projects\abc\src\bdd\reo\reoSwap.c"
+"C:\_projects\abc\src\bdd\reo\reoTest.c"
+"C:\_projects\abc\src\bdd\reo\reoTransfer.c"
+"C:\_projects\abc\src\bdd\reo\reoUnits.c"
+"C:\_projects\abc\src\sop\mvc\mvc.c"
+"C:\_projects\abc\src\sop\mvc\mvcApi.c"
+"C:\_projects\abc\src\sop\mvc\mvcCompare.c"
+"C:\_projects\abc\src\sop\mvc\mvcContain.c"
+"C:\_projects\abc\src\sop\mvc\mvcCover.c"
+"C:\_projects\abc\src\sop\mvc\mvcCube.c"
+"C:\_projects\abc\src\sop\mvc\mvcDivide.c"
+"C:\_projects\abc\src\sop\mvc\mvcDivisor.c"
+"C:\_projects\abc\src\sop\mvc\mvcList.c"
+"C:\_projects\abc\src\sop\mvc\mvcLits.c"
+"C:\_projects\abc\src\sop\mvc\mvcMan.c"
+"C:\_projects\abc\src\sop\mvc\mvcOpAlg.c"
+"C:\_projects\abc\src\sop\mvc\mvcOpBool.c"
+"C:\_projects\abc\src\sop\mvc\mvcPrint.c"
+"C:\_projects\abc\src\sop\mvc\mvcSort.c"
+"C:\_projects\abc\src\sop\mvc\mvcUtils.c"
+"C:\_projects\abc\src\sop\ft\ftFactor.c"
+"C:\_projects\abc\src\sop\ft\ftPrint.c"
+"C:\_projects\abc\src\sat\asat\added.c"
+"C:\_projects\abc\src\sat\asat\solver.c"
+"C:\_projects\abc\src\sat\msat\msatActivity.c"
+"C:\_projects\abc\src\sat\msat\msatClause.c"
+"C:\_projects\abc\src\sat\msat\msatClauseVec.c"
+"C:\_projects\abc\src\sat\msat\msatMem.c"
+"C:\_projects\abc\src\sat\msat\msatOrderJ.c"
+"C:\_projects\abc\src\sat\msat\msatQueue.c"
+"C:\_projects\abc\src\sat\msat\msatRead.c"
+"C:\_projects\abc\src\sat\msat\msatSolverApi.c"
+"C:\_projects\abc\src\sat\msat\msatSolverCore.c"
+"C:\_projects\abc\src\sat\msat\msatSolverIo.c"
+"C:\_projects\abc\src\sat\msat\msatSolverSearch.c"
+"C:\_projects\abc\src\sat\msat\msatSort.c"
+"C:\_projects\abc\src\sat\msat\msatVec.c"
+"C:\_projects\abc\src\sat\fraig\fraigApi.c"
+"C:\_projects\abc\src\sat\fraig\fraigCanon.c"
+"C:\_projects\abc\src\sat\fraig\fraigFanout.c"
+"C:\_projects\abc\src\sat\fraig\fraigFeed.c"
+"C:\_projects\abc\src\sat\fraig\fraigMan.c"
+"C:\_projects\abc\src\sat\fraig\fraigMem.c"
+"C:\_projects\abc\src\sat\fraig\fraigNode.c"
+"C:\_projects\abc\src\sat\fraig\fraigPrime.c"
+"C:\_projects\abc\src\sat\fraig\fraigSat.c"
+"C:\_projects\abc\src\sat\fraig\fraigTable.c"
+"C:\_projects\abc\src\sat\fraig\fraigUtil.c"
+"C:\_projects\abc\src\sat\fraig\fraigVec.c"
+"C:\_projects\abc\src\map\fpga\fpga.c"
+"C:\_projects\abc\src\map\fpga\fpgaCore.c"
+"C:\_projects\abc\src\map\fpga\fpgaCreate.c"
+"C:\_projects\abc\src\map\fpga\fpgaCut.c"
+"C:\_projects\abc\src\map\fpga\fpgaCutUtils.c"
+"C:\_projects\abc\src\map\fpga\fpgaFanout.c"
+"C:\_projects\abc\src\map\fpga\fpgaLib.c"
+"C:\_projects\abc\src\map\fpga\fpgaMatch.c"
+"C:\_projects\abc\src\map\fpga\fpgaTime.c"
+"C:\_projects\abc\src\map\fpga\fpgaTruth.c"
+"C:\_projects\abc\src\map\fpga\fpgaUtils.c"
+"C:\_projects\abc\src\map\fpga\fpgaVec.c"
+"C:\_projects\abc\src\map\mapper\mapper.c"
+"C:\_projects\abc\src\map\mapper\mapperCanon.c"
+"C:\_projects\abc\src\map\mapper\mapperCore.c"
+"C:\_projects\abc\src\map\mapper\mapperCreate.c"
+"C:\_projects\abc\src\map\mapper\mapperCut.c"
+"C:\_projects\abc\src\map\mapper\mapperCutUtils.c"
+"C:\_projects\abc\src\map\mapper\mapperFanout.c"
+"C:\_projects\abc\src\map\mapper\mapperLib.c"
+"C:\_projects\abc\src\map\mapper\mapperMatch.c"
+"C:\_projects\abc\src\map\mapper\mapperRefs.c"
+"C:\_projects\abc\src\map\mapper\mapperSuper.c"
+"C:\_projects\abc\src\map\mapper\mapperTable.c"
+"C:\_projects\abc\src\map\mapper\mapperTime.c"
+"C:\_projects\abc\src\map\mapper\mapperTree.c"
+"C:\_projects\abc\src\map\mapper\mapperTruth.c"
+"C:\_projects\abc\src\map\mapper\mapperUtils.c"
+"C:\_projects\abc\src\map\mapper\mapperVec.c"
+"C:\_projects\abc\src\map\mio\mio.c"
+"C:\_projects\abc\src\map\mio\mioApi.c"
+"C:\_projects\abc\src\map\mio\mioFunc.c"
+"C:\_projects\abc\src\map\mio\mioRead.c"
+"C:\_projects\abc\src\map\mio\mioUtils.c"
+"C:\_projects\abc\src\map\super\super.c"
+"C:\_projects\abc\src\map\super\superAnd.c"
+"C:\_projects\abc\src\map\super\superGate.c"
+"C:\_projects\abc\src\map\super\superWrite.c"
+"C:\_projects\abc\src\misc\extra\extraUtilBdd.c"
+"C:\_projects\abc\src\misc\extra\extraUtilFile.c"
+"C:\_projects\abc\src\misc\extra\extraUtilMemory.c"
+"C:\_projects\abc\src\misc\extra\extraUtilMisc.c"
+"C:\_projects\abc\src\misc\extra\extraUtilProgress.c"
+"C:\_projects\abc\src\misc\extra\extraUtilReader.c"
+"C:\_projects\abc\src\misc\st\st.c"
+"C:\_projects\abc\src\misc\st\stmm.c"
+"C:\_projects\abc\src\misc\util\cpu_stats.c"
+"C:\_projects\abc\src\misc\util\cpu_time.c"
+"C:\_projects\abc\src\misc\util\datalimit.c"
+"C:\_projects\abc\src\misc\util\getopt.c"
+"C:\_projects\abc\src\misc\util\pathsearch.c"
+"C:\_projects\abc\src\misc\util\safe_mem.c"
+"C:\_projects\abc\src\misc\util\strsav.c"
+"C:\_projects\abc\src\misc\util\texpand.c"
+]
+Creating command line "cl.exe @C:\DOCUME~1\alanmi\LOCALS~1\Temp\RSP27C8.tmp"
+Creating temporary file "C:\DOCUME~1\alanmi\LOCALS~1\Temp\RSP27C9.tmp" with contents
+[
+kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /pdb:"Release/abc.pdb" /machine:I386 /out:"_TEST/abc.exe"
+.\Release\abc.obj
+.\Release\abcAig.obj
+.\Release\abcAttach.obj
+.\Release\abcCheck.obj
+.\Release\abcCollapse.obj
+.\Release\abcCreate.obj
+.\Release\abcDfs.obj
+.\Release\abcDsd.obj
+.\Release\abcFanio.obj
+.\Release\abcFpga.obj
+.\Release\abcFraig.obj
+.\Release\abcFunc.obj
+.\Release\abcLatch.obj
+.\Release\abcMap.obj
+.\Release\abcMinBase.obj
+.\Release\abcMiter.obj
+.\Release\abcNames.obj
+.\Release\abcNetlist.obj
+.\Release\abcPrint.obj
+.\Release\abcRefs.obj
+.\Release\abcRenode.obj
+.\Release\abcSat.obj
+.\Release\abcSop.obj
+.\Release\abcStrash.obj
+.\Release\abcSweep.obj
+.\Release\abcTiming.obj
+.\Release\abcUtil.obj
+.\Release\abcVerify.obj
+.\Release\cmd.obj
+.\Release\cmdAlias.obj
+.\Release\cmdApi.obj
+.\Release\cmdFlag.obj
+.\Release\cmdHist.obj
+.\Release\cmdUtils.obj
+.\Release\io.obj
+.\Release\ioRead.obj
+.\Release\ioReadBench.obj
+.\Release\ioReadBlif.obj
+.\Release\ioReadVerilog.obj
+.\Release\ioWriteBench.obj
+.\Release\ioWriteBlif.obj
+.\Release\ioWriteBlifLogic.obj
+.\Release\ioWriteCnf.obj
+.\Release\ioWriteGate.obj
+.\Release\main.obj
+.\Release\mainFrame.obj
+.\Release\mainInit.obj
+.\Release\mainUtils.obj
+.\Release\cuddAddAbs.obj
+.\Release\cuddAddApply.obj
+.\Release\cuddAddFind.obj
+.\Release\cuddAddInv.obj
+.\Release\cuddAddIte.obj
+.\Release\cuddAddNeg.obj
+.\Release\cuddAddWalsh.obj
+.\Release\cuddAndAbs.obj
+.\Release\cuddAnneal.obj
+.\Release\cuddApa.obj
+.\Release\cuddAPI.obj
+.\Release\cuddApprox.obj
+.\Release\cuddBddAbs.obj
+.\Release\cuddBddCorr.obj
+.\Release\cuddBddIte.obj
+.\Release\cuddBridge.obj
+.\Release\cuddCache.obj
+.\Release\cuddCheck.obj
+.\Release\cuddClip.obj
+.\Release\cuddCof.obj
+.\Release\cuddCompose.obj
+.\Release\cuddDecomp.obj
+.\Release\cuddEssent.obj
+.\Release\cuddExact.obj
+.\Release\cuddExport.obj
+.\Release\cuddGenCof.obj
+.\Release\cuddGenetic.obj
+.\Release\cuddGroup.obj
+.\Release\cuddHarwell.obj
+.\Release\cuddInit.obj
+.\Release\cuddInteract.obj
+.\Release\cuddLCache.obj
+.\Release\cuddLevelQ.obj
+.\Release\cuddLinear.obj
+.\Release\cuddLiteral.obj
+.\Release\cuddMatMult.obj
+.\Release\cuddPriority.obj
+.\Release\cuddRead.obj
+.\Release\cuddRef.obj
+.\Release\cuddReorder.obj
+.\Release\cuddSat.obj
+.\Release\cuddSign.obj
+.\Release\cuddSolve.obj
+.\Release\cuddSplit.obj
+.\Release\cuddSubsetHB.obj
+.\Release\cuddSubsetSP.obj
+.\Release\cuddSymmetry.obj
+.\Release\cuddTable.obj
+.\Release\cuddUtil.obj
+.\Release\cuddWindow.obj
+.\Release\cuddZddCount.obj
+.\Release\cuddZddFuncs.obj
+.\Release\cuddZddGroup.obj
+.\Release\cuddZddIsop.obj
+.\Release\cuddZddLin.obj
+.\Release\cuddZddMisc.obj
+.\Release\cuddZddPort.obj
+.\Release\cuddZddReord.obj
+.\Release\cuddZddSetop.obj
+.\Release\cuddZddSymm.obj
+.\Release\cuddZddUtil.obj
+.\Release\epd.obj
+.\Release\mtrBasic.obj
+.\Release\mtrGroup.obj
+.\Release\parseCore.obj
+.\Release\parseStack.obj
+.\Release\dsdApi.obj
+.\Release\dsdCheck.obj
+.\Release\dsdLocal.obj
+.\Release\dsdMan.obj
+.\Release\dsdProc.obj
+.\Release\dsdTree.obj
+.\Release\reoApi.obj
+.\Release\reoCore.obj
+.\Release\reoProfile.obj
+.\Release\reoSift.obj
+.\Release\reoSwap.obj
+.\Release\reoTest.obj
+.\Release\reoTransfer.obj
+.\Release\reoUnits.obj
+.\Release\mvc.obj
+.\Release\mvcApi.obj
+.\Release\mvcCompare.obj
+.\Release\mvcContain.obj
+.\Release\mvcCover.obj
+.\Release\mvcCube.obj
+.\Release\mvcDivide.obj
+.\Release\mvcDivisor.obj
+.\Release\mvcList.obj
+.\Release\mvcLits.obj
+.\Release\mvcMan.obj
+.\Release\mvcOpAlg.obj
+.\Release\mvcOpBool.obj
+.\Release\mvcPrint.obj
+.\Release\mvcSort.obj
+.\Release\mvcUtils.obj
+.\Release\ftFactor.obj
+.\Release\ftPrint.obj
+.\Release\added.obj
+.\Release\solver.obj
+.\Release\msatActivity.obj
+.\Release\msatClause.obj
+.\Release\msatClauseVec.obj
+.\Release\msatMem.obj
+.\Release\msatOrderJ.obj
+.\Release\msatQueue.obj
+.\Release\msatRead.obj
+.\Release\msatSolverApi.obj
+.\Release\msatSolverCore.obj
+.\Release\msatSolverIo.obj
+.\Release\msatSolverSearch.obj
+.\Release\msatSort.obj
+.\Release\msatVec.obj
+.\Release\fraigApi.obj
+.\Release\fraigCanon.obj
+.\Release\fraigFanout.obj
+.\Release\fraigFeed.obj
+.\Release\fraigMan.obj
+.\Release\fraigMem.obj
+.\Release\fraigNode.obj
+.\Release\fraigPrime.obj
+.\Release\fraigSat.obj
+.\Release\fraigTable.obj
+.\Release\fraigUtil.obj
+.\Release\fraigVec.obj
+.\Release\fpga.obj
+.\Release\fpgaCore.obj
+.\Release\fpgaCreate.obj
+.\Release\fpgaCut.obj
+.\Release\fpgaCutUtils.obj
+.\Release\fpgaFanout.obj
+.\Release\fpgaLib.obj
+.\Release\fpgaMatch.obj
+.\Release\fpgaTime.obj
+.\Release\fpgaTruth.obj
+.\Release\fpgaUtils.obj
+.\Release\fpgaVec.obj
+.\Release\mapper.obj
+.\Release\mapperCanon.obj
+.\Release\mapperCore.obj
+.\Release\mapperCreate.obj
+.\Release\mapperCut.obj
+.\Release\mapperCutUtils.obj
+.\Release\mapperFanout.obj
+.\Release\mapperLib.obj
+.\Release\mapperMatch.obj
+.\Release\mapperRefs.obj
+.\Release\mapperSuper.obj
+.\Release\mapperTable.obj
+.\Release\mapperTime.obj
+.\Release\mapperTree.obj
+.\Release\mapperTruth.obj
+.\Release\mapperUtils.obj
+.\Release\mapperVec.obj
+.\Release\mio.obj
+.\Release\mioApi.obj
+.\Release\mioFunc.obj
+.\Release\mioRead.obj
+.\Release\mioUtils.obj
+.\Release\super.obj
+.\Release\superAnd.obj
+.\Release\superGate.obj
+.\Release\superWrite.obj
+.\Release\extraUtilBdd.obj
+.\Release\extraUtilFile.obj
+.\Release\extraUtilMemory.obj
+.\Release\extraUtilMisc.obj
+.\Release\extraUtilProgress.obj
+.\Release\extraUtilReader.obj
+.\Release\st.obj
+.\Release\stmm.obj
+.\Release\cpu_stats.obj
+.\Release\cpu_time.obj
+.\Release\datalimit.obj
+.\Release\getopt.obj
+.\Release\pathsearch.obj
+.\Release\safe_mem.obj
+.\Release\strsav.obj
+.\Release\texpand.obj
+]
+Creating command line "link.exe @C:\DOCUME~1\alanmi\LOCALS~1\Temp\RSP27C9.tmp"
+<h3>Output Window</h3>
+Compiling...
+abc.c
+abcAig.c
+abcAttach.c
+abcCheck.c
+abcCollapse.c
+abcCreate.c
+abcDfs.c
+abcDsd.c
+abcFanio.c
+abcFpga.c
+abcFraig.c
+abcFunc.c
+abcLatch.c
+abcMap.c
+abcMinBase.c
+abcMiter.c
+abcNames.c
+abcNetlist.c
+abcPrint.c
+abcRefs.c
+abcRenode.c
+abcSat.c
+abcSop.c
+abcStrash.c
+abcSweep.c
+abcTiming.c
+abcUtil.c
+abcVerify.c
+cmd.c
+cmdAlias.c
+cmdApi.c
+cmdFlag.c
+cmdHist.c
+cmdUtils.c
+io.c
+ioRead.c
+ioReadBench.c
+ioReadBlif.c
+ioReadVerilog.c
+ioWriteBench.c
+ioWriteBlif.c
+ioWriteBlifLogic.c
+ioWriteCnf.c
+ioWriteGate.c
+main.c
+mainFrame.c
+mainInit.c
+mainUtils.c
+cuddAddAbs.c
+cuddAddApply.c
+cuddAddFind.c
+cuddAddInv.c
+cuddAddIte.c
+cuddAddNeg.c
+cuddAddWalsh.c
+cuddAndAbs.c
+cuddAnneal.c
+cuddApa.c
+C:\_projects\abc\src\bdd\cudd\cuddApa.c(181) : warning C4244: 'return' : conversion from 'unsigned long ' to 'unsigned short ', possible loss of data
+C:\_projects\abc\src\bdd\cudd\cuddApa.c(213) : warning C4244: 'return' : conversion from 'unsigned long ' to 'unsigned short ', possible loss of data
+C:\_projects\abc\src\bdd\cudd\cuddApa.c(530) : warning C4244: '=' : conversion from 'unsigned short ' to 'unsigned char ', possible loss of data
+C:\_projects\abc\src\bdd\cudd\cuddApa.c(588) : warning C4244: '=' : conversion from 'unsigned short ' to 'unsigned char ', possible loss of data
+cuddAPI.c
+cuddApprox.c
+cuddBddAbs.c
+cuddBddCorr.c
+cuddBddIte.c
+cuddBridge.c
+cuddCache.c
+C:\_projects\abc\src\bdd\cudd\cuddCache.c(902) : warning C4146: unary minus operator applied to unsigned type, result still unsigned
+cuddCheck.c
+cuddClip.c
+cuddCof.c
+cuddCompose.c
+cuddDecomp.c
+cuddEssent.c
+cuddExact.c
+cuddExport.c
+cuddGenCof.c
+cuddGenetic.c
+cuddGroup.c
+C:\_projects\abc\src\bdd\cudd\cuddGroup.c(2062) : warning C4018: '<=' : signed/unsigned mismatch
+cuddHarwell.c
+cuddInit.c
+cuddInteract.c
+cuddLCache.c
+C:\_projects\abc\src\bdd\cudd\cuddLCache.c(1387) : warning C4146: unary minus operator applied to unsigned type, result still unsigned
+cuddLevelQ.c
+cuddLinear.c
+cuddLiteral.c
+cuddMatMult.c
+cuddPriority.c
+cuddRead.c
+cuddRef.c
+cuddReorder.c
+C:\_projects\abc\src\bdd\cudd\cuddReorder.c(395) : warning C4146: unary minus operator applied to unsigned type, result still unsigned
+cuddSat.c
+C:\_projects\abc\src\bdd\cudd\cuddReorder.c(2016) : warning C4700: local variable 'minLevel' used without having been initialized
+C:\_projects\abc\src\bdd\cudd\cuddReorder.c(2020) : warning C4700: local variable 'maxLevel' used without having been initialized
+cuddSign.c
+cuddSolve.c
+cuddSplit.c
+cuddSubsetHB.c
+cuddSubsetSP.c
+cuddSymmetry.c
+cuddTable.c
+C:\_projects\abc\src\bdd\cudd\cuddTable.c(1822) : warning C4018: '<' : signed/unsigned mismatch
+C:\_projects\abc\src\bdd\cudd\cuddTable.c(1927) : warning C4018: '<' : signed/unsigned mismatch
+C:\_projects\abc\src\bdd\cudd\cuddTable.c(2235) : warning C4018: '<' : signed/unsigned mismatch
+C:\_projects\abc\src\bdd\cudd\cuddTable.c(2303) : warning C4018: '<' : signed/unsigned mismatch
+C:\_projects\abc\src\bdd\cudd\cuddTable.c(2358) : warning C4146: unary minus operator applied to unsigned type, result still unsigned
+cuddUtil.c
+cuddWindow.c
+cuddZddCount.c
+cuddZddFuncs.c
+cuddZddGroup.c
+cuddZddIsop.c
+cuddZddLin.c
+cuddZddMisc.c
+cuddZddPort.c
+cuddZddReord.c
+cuddZddSetop.c
+cuddZddSymm.c
+cuddZddUtil.c
+epd.c
+mtrBasic.c
+mtrGroup.c
+parseCore.c
+parseStack.c
+dsdApi.c
+dsdCheck.c
+dsdLocal.c
+dsdMan.c
+dsdProc.c
+dsdTree.c
+reoApi.c
+reoCore.c
+reoProfile.c
+reoSift.c
+reoSwap.c
+reoTest.c
+reoTransfer.c
+reoUnits.c
+mvc.c
+mvcApi.c
+mvcCompare.c
+mvcContain.c
+mvcCover.c
+mvcCube.c
+mvcDivide.c
+mvcDivisor.c
+mvcList.c
+mvcLits.c
+mvcMan.c
+mvcOpAlg.c
+mvcOpBool.c
+mvcPrint.c
+mvcSort.c
+mvcUtils.c
+ftFactor.c
+ftPrint.c
+added.c
+solver.c
+msatActivity.c
+msatClause.c
+msatClauseVec.c
+msatMem.c
+msatOrderJ.c
+msatQueue.c
+msatRead.c
+msatSolverApi.c
+msatSolverCore.c
+msatSolverIo.c
+msatSolverSearch.c
+msatSort.c
+msatVec.c
+fraigApi.c
+fraigCanon.c
+fraigFanout.c
+fraigFeed.c
+fraigMan.c
+fraigMem.c
+fraigNode.c
+fraigPrime.c
+fraigSat.c
+fraigTable.c
+fraigUtil.c
+fraigVec.c
+fpga.c
+fpgaCore.c
+fpgaCreate.c
+fpgaCut.c
+fpgaCutUtils.c
+fpgaFanout.c
+fpgaLib.c
+fpgaMatch.c
+fpgaTime.c
+fpgaTruth.c
+fpgaUtils.c
+fpgaVec.c
+mapper.c
+mapperCanon.c
+mapperCore.c
+mapperCreate.c
+mapperCut.c
+mapperCutUtils.c
+mapperFanout.c
+mapperLib.c
+mapperMatch.c
+mapperRefs.c
+mapperSuper.c
+mapperTable.c
+mapperTime.c
+mapperTree.c
+mapperTruth.c
+mapperUtils.c
+mapperVec.c
+mio.c
+mioApi.c
+mioFunc.c
+mioRead.c
+mioUtils.c
+super.c
+superAnd.c
+superGate.c
+superWrite.c
+extraUtilBdd.c
+extraUtilFile.c
+extraUtilMemory.c
+extraUtilMisc.c
+extraUtilProgress.c
+extraUtilReader.c
+st.c
+stmm.c
+cpu_stats.c
+cpu_time.c
+datalimit.c
+getopt.c
+C:\_projects\abc\src\misc\util\getopt.c(64) : warning C4013: 'index' undefined; assuming extern returning int
+C:\_projects\abc\src\misc\util\getopt.c(64) : warning C4047: '=' : 'char *' differs in levels of indirection from 'int '
+pathsearch.c
+C:\_projects\abc\src\misc\util\pathsearch.c(103) : warning C4013: 'index' undefined; assuming extern returning int
+C:\_projects\abc\src\misc\util\pathsearch.c(103) : warning C4047: '=' : 'char *' differs in levels of indirection from 'int '
+safe_mem.c
+strsav.c
+texpand.c
+Linking...
+Creating temporary file "C:\DOCUME~1\alanmi\LOCALS~1\Temp\RSP27CB.tmp" with contents
+[
+/nologo /o"Release/abc.bsc"
+.\Release\abc.sbr
+.\Release\abcAig.sbr
+.\Release\abcAttach.sbr
+.\Release\abcCheck.sbr
+.\Release\abcCollapse.sbr
+.\Release\abcCreate.sbr
+.\Release\abcDfs.sbr
+.\Release\abcDsd.sbr
+.\Release\abcFanio.sbr
+.\Release\abcFpga.sbr
+.\Release\abcFraig.sbr
+.\Release\abcFunc.sbr
+.\Release\abcLatch.sbr
+.\Release\abcMap.sbr
+.\Release\abcMinBase.sbr
+.\Release\abcMiter.sbr
+.\Release\abcNames.sbr
+.\Release\abcNetlist.sbr
+.\Release\abcPrint.sbr
+.\Release\abcRefs.sbr
+.\Release\abcRenode.sbr
+.\Release\abcSat.sbr
+.\Release\abcSop.sbr
+.\Release\abcStrash.sbr
+.\Release\abcSweep.sbr
+.\Release\abcTiming.sbr
+.\Release\abcUtil.sbr
+.\Release\abcVerify.sbr
+.\Release\cmd.sbr
+.\Release\cmdAlias.sbr
+.\Release\cmdApi.sbr
+.\Release\cmdFlag.sbr
+.\Release\cmdHist.sbr
+.\Release\cmdUtils.sbr
+.\Release\io.sbr
+.\Release\ioRead.sbr
+.\Release\ioReadBench.sbr
+.\Release\ioReadBlif.sbr
+.\Release\ioReadVerilog.sbr
+.\Release\ioWriteBench.sbr
+.\Release\ioWriteBlif.sbr
+.\Release\ioWriteBlifLogic.sbr
+.\Release\ioWriteCnf.sbr
+.\Release\ioWriteGate.sbr
+.\Release\main.sbr
+.\Release\mainFrame.sbr
+.\Release\mainInit.sbr
+.\Release\mainUtils.sbr
+.\Release\cuddAddAbs.sbr
+.\Release\cuddAddApply.sbr
+.\Release\cuddAddFind.sbr
+.\Release\cuddAddInv.sbr
+.\Release\cuddAddIte.sbr
+.\Release\cuddAddNeg.sbr
+.\Release\cuddAddWalsh.sbr
+.\Release\cuddAndAbs.sbr
+.\Release\cuddAnneal.sbr
+.\Release\cuddApa.sbr
+.\Release\cuddAPI.sbr
+.\Release\cuddApprox.sbr
+.\Release\cuddBddAbs.sbr
+.\Release\cuddBddCorr.sbr
+.\Release\cuddBddIte.sbr
+.\Release\cuddBridge.sbr
+.\Release\cuddCache.sbr
+.\Release\cuddCheck.sbr
+.\Release\cuddClip.sbr
+.\Release\cuddCof.sbr
+.\Release\cuddCompose.sbr
+.\Release\cuddDecomp.sbr
+.\Release\cuddEssent.sbr
+.\Release\cuddExact.sbr
+.\Release\cuddExport.sbr
+.\Release\cuddGenCof.sbr
+.\Release\cuddGenetic.sbr
+.\Release\cuddGroup.sbr
+.\Release\cuddHarwell.sbr
+.\Release\cuddInit.sbr
+.\Release\cuddInteract.sbr
+.\Release\cuddLCache.sbr
+.\Release\cuddLevelQ.sbr
+.\Release\cuddLinear.sbr
+.\Release\cuddLiteral.sbr
+.\Release\cuddMatMult.sbr
+.\Release\cuddPriority.sbr
+.\Release\cuddRead.sbr
+.\Release\cuddRef.sbr
+.\Release\cuddReorder.sbr
+.\Release\cuddSat.sbr
+.\Release\cuddSign.sbr
+.\Release\cuddSolve.sbr
+.\Release\cuddSplit.sbr
+.\Release\cuddSubsetHB.sbr
+.\Release\cuddSubsetSP.sbr
+.\Release\cuddSymmetry.sbr
+.\Release\cuddTable.sbr
+.\Release\cuddUtil.sbr
+.\Release\cuddWindow.sbr
+.\Release\cuddZddCount.sbr
+.\Release\cuddZddFuncs.sbr
+.\Release\cuddZddGroup.sbr
+.\Release\cuddZddIsop.sbr
+.\Release\cuddZddLin.sbr
+.\Release\cuddZddMisc.sbr
+.\Release\cuddZddPort.sbr
+.\Release\cuddZddReord.sbr
+.\Release\cuddZddSetop.sbr
+.\Release\cuddZddSymm.sbr
+.\Release\cuddZddUtil.sbr
+.\Release\epd.sbr
+.\Release\mtrBasic.sbr
+.\Release\mtrGroup.sbr
+.\Release\parseCore.sbr
+.\Release\parseStack.sbr
+.\Release\dsdApi.sbr
+.\Release\dsdCheck.sbr
+.\Release\dsdLocal.sbr
+.\Release\dsdMan.sbr
+.\Release\dsdProc.sbr
+.\Release\dsdTree.sbr
+.\Release\reoApi.sbr
+.\Release\reoCore.sbr
+.\Release\reoProfile.sbr
+.\Release\reoSift.sbr
+.\Release\reoSwap.sbr
+.\Release\reoTest.sbr
+.\Release\reoTransfer.sbr
+.\Release\reoUnits.sbr
+.\Release\mvc.sbr
+.\Release\mvcApi.sbr
+.\Release\mvcCompare.sbr
+.\Release\mvcContain.sbr
+.\Release\mvcCover.sbr
+.\Release\mvcCube.sbr
+.\Release\mvcDivide.sbr
+.\Release\mvcDivisor.sbr
+.\Release\mvcList.sbr
+.\Release\mvcLits.sbr
+.\Release\mvcMan.sbr
+.\Release\mvcOpAlg.sbr
+.\Release\mvcOpBool.sbr
+.\Release\mvcPrint.sbr
+.\Release\mvcSort.sbr
+.\Release\mvcUtils.sbr
+.\Release\ftFactor.sbr
+.\Release\ftPrint.sbr
+.\Release\added.sbr
+.\Release\solver.sbr
+.\Release\msatActivity.sbr
+.\Release\msatClause.sbr
+.\Release\msatClauseVec.sbr
+.\Release\msatMem.sbr
+.\Release\msatOrderJ.sbr
+.\Release\msatQueue.sbr
+.\Release\msatRead.sbr
+.\Release\msatSolverApi.sbr
+.\Release\msatSolverCore.sbr
+.\Release\msatSolverIo.sbr
+.\Release\msatSolverSearch.sbr
+.\Release\msatSort.sbr
+.\Release\msatVec.sbr
+.\Release\fraigApi.sbr
+.\Release\fraigCanon.sbr
+.\Release\fraigFanout.sbr
+.\Release\fraigFeed.sbr
+.\Release\fraigMan.sbr
+.\Release\fraigMem.sbr
+.\Release\fraigNode.sbr
+.\Release\fraigPrime.sbr
+.\Release\fraigSat.sbr
+.\Release\fraigTable.sbr
+.\Release\fraigUtil.sbr
+.\Release\fraigVec.sbr
+.\Release\fpga.sbr
+.\Release\fpgaCore.sbr
+.\Release\fpgaCreate.sbr
+.\Release\fpgaCut.sbr
+.\Release\fpgaCutUtils.sbr
+.\Release\fpgaFanout.sbr
+.\Release\fpgaLib.sbr
+.\Release\fpgaMatch.sbr
+.\Release\fpgaTime.sbr
+.\Release\fpgaTruth.sbr
+.\Release\fpgaUtils.sbr
+.\Release\fpgaVec.sbr
+.\Release\mapper.sbr
+.\Release\mapperCanon.sbr
+.\Release\mapperCore.sbr
+.\Release\mapperCreate.sbr
+.\Release\mapperCut.sbr
+.\Release\mapperCutUtils.sbr
+.\Release\mapperFanout.sbr
+.\Release\mapperLib.sbr
+.\Release\mapperMatch.sbr
+.\Release\mapperRefs.sbr
+.\Release\mapperSuper.sbr
+.\Release\mapperTable.sbr
+.\Release\mapperTime.sbr
+.\Release\mapperTree.sbr
+.\Release\mapperTruth.sbr
+.\Release\mapperUtils.sbr
+.\Release\mapperVec.sbr
+.\Release\mio.sbr
+.\Release\mioApi.sbr
+.\Release\mioFunc.sbr
+.\Release\mioRead.sbr
+.\Release\mioUtils.sbr
+.\Release\super.sbr
+.\Release\superAnd.sbr
+.\Release\superGate.sbr
+.\Release\superWrite.sbr
+.\Release\extraUtilBdd.sbr
+.\Release\extraUtilFile.sbr
+.\Release\extraUtilMemory.sbr
+.\Release\extraUtilMisc.sbr
+.\Release\extraUtilProgress.sbr
+.\Release\extraUtilReader.sbr
+.\Release\st.sbr
+.\Release\stmm.sbr
+.\Release\cpu_stats.sbr
+.\Release\cpu_time.sbr
+.\Release\datalimit.sbr
+.\Release\getopt.sbr
+.\Release\pathsearch.sbr
+.\Release\safe_mem.sbr
+.\Release\strsav.sbr
+.\Release\texpand.sbr]
+Creating command line "bscmake.exe @C:\DOCUME~1\alanmi\LOCALS~1\Temp\RSP27CB.tmp"
+Creating browse info file...
+<h3>Output Window</h3>
+
+
+
+<h3>Results</h3>
+abc.exe - 0 error(s), 19 warning(s)
+</pre>
+</body>
+</html>
diff --git a/abc.rc b/abc.rc
new file mode 100644
index 00000000..21a99e8d
--- /dev/null
+++ b/abc.rc
@@ -0,0 +1,26 @@
+alias b balance
+alias clp collapse
+alias f fraig
+alias fs fraig_sweep
+alias pf print_factor
+alias pfan print_fanio
+alias pio print_io
+alias ps print_stats
+alias q quit
+alias r read
+alias rl read_blif
+alias rb read_bench
+alias rv read_verilog
+alias rsup read_super
+alias rlib read_library
+alias sa set autoexec ps
+alias so source -x
+alias st strash
+alias u undo
+alias wb write_blif
+alias wg write_gate
+alias wl write_blif
+alias cnf "st; renode -c; write_cnf"
+alias prove "st; renode -c; sat"
+alias opt "st; b; renode; sop; ps"
+alias opts "st; b; renode; sop; st; b; ps"
diff --git a/depends.sh b/depends.sh
new file mode 100755
index 00000000..d302cd04
--- /dev/null
+++ b/depends.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+#echo "## Got: $*"
+CC="$1"
+DIR="$2"
+shift 2
+case "$DIR" in
+ "" | ".")
+ $CC -MM -MG "$@" | sed -e 's@^\(.*\)\.o:@\1.d \1.o:@'
+ ;;
+ *)
+ $CC -MM -MG "$@" | sed -e "s@^\(.*\)\.o:@$DIR/\1.d $DIR/\1.o:@"
+ ;;
+esac
diff --git a/src/base/abc/abc.c b/src/base/abc/abc.c
new file mode 100644
index 00000000..f9bcde33
--- /dev/null
+++ b/src/base/abc/abc.c
@@ -0,0 +1,2158 @@
+/**CFile****************************************************************
+
+ FileName [abc.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Command file.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abc.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+#include "mainInt.h"
+#include "ft.h"
+#include "fraig.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Ntk_CommandPrintStats ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int Ntk_CommandPrintIo ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int Ntk_CommandPrintFanio ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int Ntk_CommandPrintFactor ( Abc_Frame_t * pAbc, int argc, char ** argv );
+
+static int Ntk_CommandCollapse ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int Ntk_CommandStrash ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int Ntk_CommandBalance ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int Ntk_CommandRenode ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int Ntk_CommandCleanup ( Abc_Frame_t * pAbc, int argc, char ** argv );
+
+static int Ntk_CommandLogic ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int Ntk_CommandMiter ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int Ntk_CommandFrames ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int Ntk_CommandSop ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int Ntk_CommandBdd ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int Ntk_CommandSat ( Abc_Frame_t * pAbc, int argc, char ** argv );
+
+static int Ntk_CommandFraig ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int Ntk_CommandFraigTrust ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int Ntk_CommandFraigStore ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int Ntk_CommandFraigRestore ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int Ntk_CommandFraigClean ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int Ntk_CommandFraigSweep ( Abc_Frame_t * pAbc, int argc, char ** argv );
+
+static int Ntk_CommandMap ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int Ntk_CommandUnmap ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int Ntk_CommandAttach ( Abc_Frame_t * pAbc, int argc, char ** argv );
+
+static int Ntk_CommandFpga ( Abc_Frame_t * pAbc, int argc, char ** argv );
+
+static int Ntk_CommandCec ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int Ntk_CommandSec ( Abc_Frame_t * pAbc, int argc, char ** argv );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_Init( Abc_Frame_t * pAbc )
+{
+ Cmd_CommandAdd( pAbc, "Printing", "print_stats", Ntk_CommandPrintStats, 0 );
+ Cmd_CommandAdd( pAbc, "Printing", "print_io", Ntk_CommandPrintIo, 0 );
+ Cmd_CommandAdd( pAbc, "Printing", "print_fanio", Ntk_CommandPrintFanio, 0 );
+ Cmd_CommandAdd( pAbc, "Printing", "print_factor", Ntk_CommandPrintFactor, 0 );
+
+ Cmd_CommandAdd( pAbc, "Synthesis", "collapse", Ntk_CommandCollapse, 1 );
+ Cmd_CommandAdd( pAbc, "Synthesis", "strash", Ntk_CommandStrash, 1 );
+ Cmd_CommandAdd( pAbc, "Synthesis", "balance", Ntk_CommandBalance, 1 );
+ Cmd_CommandAdd( pAbc, "Synthesis", "renode", Ntk_CommandRenode, 1 );
+ Cmd_CommandAdd( pAbc, "Synthesis", "cleanup", Ntk_CommandCleanup, 1 );
+
+ Cmd_CommandAdd( pAbc, "Various", "logic", Ntk_CommandLogic, 1 );
+ Cmd_CommandAdd( pAbc, "Various", "miter", Ntk_CommandMiter, 1 );
+ Cmd_CommandAdd( pAbc, "Various", "frames", Ntk_CommandFrames, 1 );
+ Cmd_CommandAdd( pAbc, "Various", "sop", Ntk_CommandSop, 0 );
+ Cmd_CommandAdd( pAbc, "Various", "bdd", Ntk_CommandBdd, 0 );
+ Cmd_CommandAdd( pAbc, "Various", "sat", Ntk_CommandSat, 0 );
+
+ Cmd_CommandAdd( pAbc, "Fraiging", "fraig", Ntk_CommandFraig, 1 );
+ Cmd_CommandAdd( pAbc, "Fraiging", "fraig_trust", Ntk_CommandFraigTrust, 1 );
+ Cmd_CommandAdd( pAbc, "Fraiging", "fraig_store", Ntk_CommandFraigStore, 0 );
+ Cmd_CommandAdd( pAbc, "Fraiging", "fraig_restore", Ntk_CommandFraigRestore, 1 );
+ Cmd_CommandAdd( pAbc, "Fraiging", "fraig_clean", Ntk_CommandFraigClean, 0 );
+ Cmd_CommandAdd( pAbc, "Fraiging", "fraig_sweep", Ntk_CommandFraigSweep, 1 );
+
+ Cmd_CommandAdd( pAbc, "SC mapping", "map", Ntk_CommandMap, 1 );
+ Cmd_CommandAdd( pAbc, "SC mapping", "unmap", Ntk_CommandUnmap, 1 );
+ Cmd_CommandAdd( pAbc, "SC mapping", "attach", Ntk_CommandAttach, 1 );
+
+ Cmd_CommandAdd( pAbc, "FPGA mapping", "fpga", Ntk_CommandFpga, 1 );
+
+ Cmd_CommandAdd( pAbc, "Verification", "cec", Ntk_CommandCec, 0 );
+ Cmd_CommandAdd( pAbc, "Verification", "sec", Ntk_CommandSec, 0 );
+
+ Ft_FactorStartMan();
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_End()
+{
+ Ft_FactorStopMan();
+ Abc_NtkFraigStoreClean();
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandPrintStats( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk;
+ bool fShort;
+ int c;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set the defaults
+ fShort = 1;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "sh" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 's':
+ fShort ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( Abc_FrameReadErr(pAbc), "Empty network\n" );
+ return 1;
+ }
+ Abc_NtkPrintStats( pOut, pNtk );
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: print_stats [-h]\n" );
+ fprintf( pErr, "\t prints the network statistics and\n" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandPrintIo( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk;
+ Abc_Obj_t * pNode;
+ int c;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "h" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ return 1;
+ }
+
+ if ( argc > util_optind + 1 )
+ {
+ fprintf( pErr, "Wrong number of auguments.\n" );
+ goto usage;
+ }
+
+ if ( argc == util_optind + 1 )
+ {
+ pNode = Abc_NtkFindNode( pNtk, argv[util_optind] );
+ if ( pNode == NULL )
+ {
+ fprintf( pErr, "Cannot find node \"%s\".\n", argv[util_optind] );
+ return 1;
+ }
+ Abc_NodePrintFanio( pOut, pNode );
+ return 0;
+ }
+ // print the nodes
+ Abc_NtkPrintIo( pOut, pNtk );
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: print_io [-h]\n" );
+ fprintf( pErr, "\t prints the PIs/POs or fanins/fanouts of a node\n" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandPrintFanio( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk;
+ int c;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "h" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ return 1;
+ }
+
+ // print the nodes
+ Abc_NtkPrintFanio( pOut, pNtk );
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: print_fanio [-h]\n" );
+ fprintf( pErr, "\t prints the statistics about fanins/fanouts of all nodes\n" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandPrintFactor( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk;
+ Abc_Obj_t * pNode;
+ int c;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "h" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ return 1;
+ }
+
+ if ( !Abc_NtkIsNetlist(pNtk) && !Abc_NtkIsLogicSop(pNtk) )
+ {
+ fprintf( pErr, "Printing factored forms can be done for netlist and SOP networks.\n" );
+ return 1;
+ }
+
+ if ( argc > util_optind + 1 )
+ {
+ fprintf( pErr, "Wrong number of auguments.\n" );
+ goto usage;
+ }
+
+ if ( argc == util_optind + 1 )
+ {
+ pNode = Abc_NtkFindNode( pNtk, argv[util_optind] );
+ if ( pNode == NULL )
+ {
+ fprintf( pErr, "Cannot find node \"%s\".\n", argv[util_optind] );
+ return 1;
+ }
+// Ft_FactorStartMan();
+ Abc_NodePrintFactor( pOut, pNode );
+// Ft_FactorStopMan();
+ return 0;
+ }
+ // print the nodes
+// Ft_FactorStartMan();
+ Abc_NtkPrintFactor( pOut, pNtk );
+// Ft_FactorStopMan();
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: print_factor [-h] <node>\n" );
+ fprintf( pErr, "\t prints the factored forms of nodes\n" );
+ fprintf( pErr, "\tnode : (optional) one node to consider\n");
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandCollapse( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk, * pNtkRes;
+ int c;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "h" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ return 1;
+ }
+
+ if ( !Abc_NtkIsLogic(pNtk) && !Abc_NtkIsAig(pNtk) )
+ {
+ fprintf( pErr, "Can only collapse a logic network.\n" );
+ return 1;
+ }
+
+ // get the new network
+ if ( Abc_NtkIsAig(pNtk) )
+ pNtkRes = Abc_NtkCollapse( pNtk, 1 );
+ else
+ {
+ pNtk = Abc_NtkStrash( pNtk );
+ pNtkRes = Abc_NtkCollapse( pNtk, 1 );
+ Abc_NtkDelete( pNtk );
+ }
+ if ( pNtkRes == NULL )
+ {
+ fprintf( pErr, "Collapsing has failed.\n" );
+ return 1;
+ }
+ // replace the current network
+ Abc_FrameReplaceCurrentNetwork( pAbc, pNtkRes );
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: collapse [-h]\n" );
+ fprintf( pErr, "\t collapses the network by constructing global BDDs\n" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandStrash( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk, * pNtkRes;
+ int c;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "h" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ return 1;
+ }
+
+ // get the new network
+ pNtkRes = Abc_NtkStrash( pNtk );
+ if ( pNtkRes == NULL )
+ {
+ fprintf( pErr, "Strashing has failed.\n" );
+ return 1;
+ }
+ // replace the current network
+ Abc_FrameReplaceCurrentNetwork( pAbc, pNtkRes );
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: strash [-h]\n" );
+ fprintf( pErr, "\t transforms combinational logic into an AIG\n" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandBalance( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk, * pNtkRes;
+ int c;
+ int fDuplicate;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ fDuplicate = 0;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "dh" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'd':
+ fDuplicate ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ return 1;
+ }
+ if ( !Abc_NtkIsAig(pNtk) )
+ {
+ fprintf( pErr, "Cannot balance a network that is not an AIG.\n" );
+ return 1;
+ }
+
+ // get the new network
+ pNtkRes = Abc_NtkBalance( pNtk, fDuplicate );
+ if ( pNtkRes == NULL )
+ {
+ fprintf( pErr, "Balancing has failed.\n" );
+ return 1;
+ }
+ // replace the current network
+ Abc_FrameReplaceCurrentNetwork( pAbc, pNtkRes );
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: balance [-dh]\n" );
+ fprintf( pErr, "\t transforms an AIG into a well-balanced AIG\n" );
+ fprintf( pErr, "\t-d : toggle duplication of logic [default = %s]\n", fDuplicate? "yes": "no" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandRenode( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk, * pNtkRes;
+ int nThresh, nFaninMax, c;
+ int fCnf;
+ int fMulti;
+ int fSimple;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ nThresh = 0;
+ nFaninMax = 20;
+ fCnf = 0;
+ fMulti = 0;
+ fSimple = 0;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "tfmcsh" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 't':
+ if ( util_optind >= argc )
+ {
+ fprintf( pErr, "Command line switch \"-t\" should be followed by an integer.\n" );
+ goto usage;
+ }
+ nThresh = atoi(argv[util_optind]);
+ util_optind++;
+ if ( nThresh < 0 )
+ goto usage;
+ break;
+ case 'f':
+ if ( util_optind >= argc )
+ {
+ fprintf( pErr, "Command line switch \"-f\" should be followed by an integer.\n" );
+ goto usage;
+ }
+ nFaninMax = atoi(argv[util_optind]);
+ util_optind++;
+ if ( nFaninMax < 0 )
+ goto usage;
+ break;
+ case 'c':
+ fCnf ^= 1;
+ break;
+ case 'm':
+ fMulti ^= 1;
+ break;
+ case 's':
+ fSimple ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ return 1;
+ }
+ if ( !Abc_NtkIsAig(pNtk) )
+ {
+ fprintf( pErr, "Cannot renode a network that is not an AIG.\n" );
+ return 1;
+ }
+
+ // get the new network
+ pNtkRes = Abc_NtkRenode( pNtk, nThresh, nFaninMax, fCnf, fMulti, fSimple );
+ if ( pNtkRes == NULL )
+ {
+ fprintf( pErr, "Renoding has failed.\n" );
+ return 1;
+ }
+ // replace the current network
+ Abc_FrameReplaceCurrentNetwork( pAbc, pNtkRes );
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: renode [-t num] [-f num] [-cmsh]\n" );
+ fprintf( pErr, "\t transforms an AIG into a logic network by creating larger nodes\n" );
+ fprintf( pErr, "\t-t num : the threshold for AIG node duplication [default = %d]\n", nThresh );
+ fprintf( pErr, "\t-f num : the maximum fanin size after renoding [default = %d]\n", nFaninMax );
+ fprintf( pErr, "\t-c : performs renoding to derive the CNF [default = %s]\n", fCnf? "yes": "no" );
+ fprintf( pErr, "\t-m : creates multi-input AND graph [default = %s]\n", fMulti? "yes": "no" );
+ fprintf( pErr, "\t-s : creates a simple AIG (no renoding) [default = %s]\n", fSimple? "yes": "no" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandCleanup( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk;
+ int c;
+ int fDuplicate;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ fDuplicate = 0;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "dh" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'd':
+ fDuplicate ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ return 1;
+ }
+
+ // modify the current network
+ Abc_NtkCleanup( pNtk, 0 );
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: cleanup [-h]\n" );
+ fprintf( pErr, "\t removes dangling nodes\n" );
+// fprintf( pErr, "\t-d : toggle duplication of logic [default = %s]\n", fDuplicate? "yes": "no" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandLogic( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk, * pNtkRes;
+ int c;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "h" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ return 1;
+ }
+
+ if ( !Abc_NtkIsNetlist( pNtk ) )
+ {
+ fprintf( pErr, "This command is only applicable to netlists.\n" );
+ return 1;
+ }
+
+ // get the new network
+ pNtkRes = Abc_NtkLogic( pNtk );
+ if ( pNtkRes == NULL )
+ {
+ fprintf( pErr, "Converting to a logic network has failed.\n" );
+ return 1;
+ }
+ // replace the current network
+ Abc_FrameReplaceCurrentNetwork( pAbc, pNtkRes );
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: logic [-h]\n" );
+ fprintf( pErr, "\t transforms a netlist into a logic network\n" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandMiter( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk, * pNtk1, * pNtk2, * pNtkRes;
+ int fDelete1, fDelete2;
+ char ** pArgvNew;
+ int nArgcNew;
+ int c;
+ int fCheck;
+ int fComb;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ fComb = 1;
+ fCheck = 1;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "ch" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'c':
+ fComb ^= 1;
+ break;
+ default:
+ goto usage;
+ }
+ }
+
+ pArgvNew = argv + util_optind;
+ nArgcNew = argc - util_optind;
+ if ( !Abc_NtkPrepareCommand( pErr, pNtk, pArgvNew, nArgcNew, &pNtk1, &pNtk2, &fDelete1, &fDelete2 ) )
+ return 1;
+
+ // compute the miter
+ pNtkRes = Abc_NtkMiter( pNtk1, pNtk2, fComb );
+ if ( fDelete1 ) Abc_NtkDelete( pNtk1 );
+ if ( fDelete2 ) Abc_NtkDelete( pNtk2 );
+
+ // get the new network
+ if ( pNtkRes == NULL )
+ {
+ fprintf( pErr, "Miter computation has failed.\n" );
+ return 1;
+ }
+ // replace the current network
+ Abc_FrameReplaceCurrentNetwork( pAbc, pNtkRes );
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: miter [-ch] <file1> <file2>\n" );
+ fprintf( pErr, "\t computes the miter of the two circuits\n" );
+ fprintf( pErr, "\t-c : computes combinational miter (latches as POs) [default = %s]\n", fComb? "yes": "no" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ fprintf( pErr, "\tfile1 : (optional) the file with the first network\n");
+ fprintf( pErr, "\tfile2 : (optional) the file with the second network\n");
+ fprintf( pErr, "\t if no files are given, uses the current network and its spec\n");
+ fprintf( pErr, "\t if one file is given, uses the current network and the file\n");
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandFrames( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk, * pNtkTemp, * pNtkRes;
+ int fInitial;
+ int nFrames;
+ int c;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ fInitial = 0;
+ nFrames = 5;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "fih" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'f':
+ if ( util_optind >= argc )
+ {
+ fprintf( pErr, "Command line switch \"-n\" should be followed by an integer.\n" );
+ goto usage;
+ }
+ nFrames = atoi(argv[util_optind]);
+ util_optind++;
+ if ( nFrames < 0 )
+ goto usage;
+ break;
+ case 'i':
+ fInitial ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ return 1;
+ }
+
+ // get the new network
+ if ( !Abc_NtkIsAig(pNtk) )
+ {
+ pNtkTemp = Abc_NtkStrash( pNtk );
+ pNtkRes = Abc_NtkFrames( pNtkTemp, nFrames, fInitial );
+ Abc_NtkDelete( pNtkTemp );
+ }
+ else
+ pNtkRes = Abc_NtkFrames( pNtk, nFrames, fInitial );
+ if ( pNtkRes == NULL )
+ {
+ fprintf( pErr, "Unrolling the network has failed.\n" );
+ return 1;
+ }
+ // replace the current network
+ Abc_FrameReplaceCurrentNetwork( pAbc, pNtkRes );
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: frames [-f num] [-ih]\n" );
+ fprintf( pErr, "\t unrolls the network for a number of time frames\n" );
+ fprintf( pErr, "\t-f num : the number of frames to unroll [default = %d]\n", nFrames );
+ fprintf( pErr, "\t-i : toggles initializing the first frame [default = %s]\n", fInitial? "yes": "no" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandSop( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk;
+ int c;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "h" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ return 1;
+ }
+
+ // get the new network
+ if ( !Abc_NtkIsLogicBdd(pNtk) )
+ {
+ fprintf( pErr, "Converting to SOP is possible when node functions are BDDs.\n" );
+ return 1;
+ }
+ if ( !Abc_NtkBddToSop( pNtk ) )
+ {
+ fprintf( pErr, "Converting to SOP has failed.\n" );
+ return 1;
+ }
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: sop [-h]\n" );
+ fprintf( pErr, "\t converts node functions from BDD to SOP\n" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandBdd( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk;
+ int c;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "h" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ return 1;
+ }
+
+ // get the new network
+ if ( !Abc_NtkIsLogicSop(pNtk) )
+ {
+ fprintf( pErr, "Converting to BDD is possible when node functions are SOPs.\n" );
+ return 1;
+ }
+ if ( !Abc_NtkSopToBdd( pNtk ) )
+ {
+ fprintf( pErr, "Converting to BDD has failed.\n" );
+ return 1;
+ }
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: bdd [-h]\n" );
+ fprintf( pErr, "\t converts node functions from SOP to BDD\n" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandSat( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk;
+ int c;
+ int fVerbose;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ fVerbose = 0;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "vh" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'v':
+ fVerbose ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ return 1;
+ }
+ if ( Abc_NtkLatchNum(pNtk) > 0 )
+ {
+ fprintf( stdout, "Currently can only solve the miter for combinational circuits.\n" );
+ return 0;
+ }
+ if ( !(Abc_NtkIsLogicSop(pNtk) || Abc_NtkIsLogicBdd(pNtk)) )
+ {
+ fprintf( stdout, "First convert node representation into BDDs or SOPs.\n" );
+ return 0;
+ }
+ if ( Abc_NtkIsLogicSop(pNtk) )
+ {
+// printf( "Converting node functions from SOP to BDD.\n" );
+ Abc_NtkSopToBdd(pNtk);
+ }
+
+ if ( Abc_NtkMiterSat( pNtk, fVerbose ) )
+ printf( "The miter is satisfiable.\n" );
+ else
+ printf( "The miter is unsatisfiable.\n" );
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: sat [-vh]\n" );
+ fprintf( pErr, "\t solves the miter\n" );
+ fprintf( pErr, "\t-v : prints verbose information [default = %s]\n", fVerbose? "yes": "no" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandFraig( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ char Buffer[100];
+ Fraig_Params_t Params;
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk, * pNtkRes;
+ int c;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ Params.nPatsRand = 2048; // the number of words of random simulation info
+ Params.nPatsDyna = 2048; // the number of words of dynamic simulation info
+ Params.nBTLimit = 99; // the max number of backtracks to perform
+ Params.fFuncRed = 1; // performs only one level hashing
+ Params.fFeedBack = 1; // enables solver feedback
+ Params.fDist1Pats = 1; // enables distance-1 patterns
+ Params.fDoSparse = 0; // performs equiv tests for sparse functions
+ Params.fChoicing = 0; // enables recording structural choices
+ Params.fTryProve = 0; // tries to solve the final miter
+ Params.fVerbose = 0; // the verbosiness flag
+ Params.fVerboseP = 0; // the verbosiness flag
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "RDBrscpvh" ) ) != EOF )
+ {
+ switch ( c )
+ {
+
+ case 'R':
+ if ( util_optind >= argc )
+ {
+ fprintf( pErr, "Command line switch \"-r\" should be followed by an integer.\n" );
+ goto usage;
+ }
+ Params.nPatsRand = atoi(argv[util_optind]);
+ util_optind++;
+ if ( Params.nPatsRand < 0 )
+ goto usage;
+ break;
+ case 'D':
+ if ( util_optind >= argc )
+ {
+ fprintf( pErr, "Command line switch \"-d\" should be followed by an integer.\n" );
+ goto usage;
+ }
+ Params.nPatsDyna = atoi(argv[util_optind]);
+ util_optind++;
+ if ( Params.nPatsDyna < 0 )
+ goto usage;
+ break;
+ case 'B':
+ if ( util_optind >= argc )
+ {
+ fprintf( pErr, "Command line switch \"-b\" should be followed by an integer.\n" );
+ goto usage;
+ }
+ Params.nBTLimit = atoi(argv[util_optind]);
+ util_optind++;
+ if ( Params.nBTLimit < 0 )
+ goto usage;
+ break;
+
+ case 'r':
+ Params.fFuncRed ^= 1;
+ break;
+ case 's':
+ Params.fDoSparse ^= 1;
+ break;
+ case 'c':
+ Params.fChoicing ^= 1;
+ break;
+ case 'p':
+ Params.fTryProve ^= 1;
+ break;
+ case 'v':
+ Params.fVerbose ^= 1;
+ break;
+
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ return 1;
+ }
+ if ( !Abc_NtkIsLogic(pNtk) && !Abc_NtkIsAig(pNtk) )
+ {
+ fprintf( pErr, "Can only fraig a logic network.\n" );
+ return 1;
+ }
+
+ // report the proof
+ Params.fVerboseP = Params.fTryProve;
+
+ // get the new network
+ if ( Abc_NtkIsAig(pNtk) )
+ pNtkRes = Abc_NtkFraig( pNtk, &Params, 0 );
+ else
+ {
+ pNtk = Abc_NtkStrash( pNtk );
+ pNtkRes = Abc_NtkFraig( pNtk, &Params, 0 );
+ Abc_NtkDelete( pNtk );
+ }
+ if ( pNtkRes == NULL )
+ {
+ fprintf( pErr, "Fraiging has failed.\n" );
+ return 1;
+ }
+
+ if ( Params.fTryProve ) // report the result
+ Abc_NtkMiterReport( pNtkRes );
+
+ // replace the current network
+ Abc_FrameReplaceCurrentNetwork( pAbc, pNtkRes );
+ return 0;
+
+usage:
+ sprintf( Buffer, "%d", Params.nBTLimit );
+ fprintf( pErr, "usage: fraig [-R num] [-D num] [-B num] [-rscpvh]\n" );
+ fprintf( pErr, "\t transforms a logic network into a functionally reduced AIG\n" );
+ fprintf( pErr, "\t-R num : number of random patterns (127 < num < 32769) [default = %d]\n", Params.nPatsRand );
+ fprintf( pErr, "\t-D num : number of systematic patterns (127 < num < 32769) [default = %d]\n", Params.nPatsDyna );
+ fprintf( pErr, "\t-B num : number of backtracks for one SAT problem [default = %s]\n", Params.nBTLimit==-1? "infinity" : Buffer );
+ fprintf( pErr, "\t-r : toggle functional reduction [default = %s]\n", Params.fFuncRed? "yes": "no" );
+ fprintf( pErr, "\t-s : toggle considering sparse functions [default = %s]\n", Params.fDoSparse? "yes": "no" );
+ fprintf( pErr, "\t-c : toggle accumulation of choices [default = %s]\n", Params.fChoicing? "yes": "no" );
+ fprintf( pErr, "\t-p : toggle proving the final miter [default = %s]\n", Params.fTryProve? "yes": "no" );
+ fprintf( pErr, "\t-v : toggle verbose output [default = %s]\n", Params.fVerbose? "yes": "no" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandFraigTrust( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk, * pNtkRes;
+ int c;
+ int fDuplicate;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ fDuplicate = 0;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "dh" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'd':
+ fDuplicate ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ return 1;
+ }
+
+ // get the new network
+ pNtkRes = Abc_NtkFraigTrust( pNtk );
+ if ( pNtkRes == NULL )
+ {
+ fprintf( pErr, "Fraiging in the trust mode has failed.\n" );
+ return 1;
+ }
+ // replace the current network
+ Abc_FrameReplaceCurrentNetwork( pAbc, pNtkRes );
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: fraig_trust [-h]\n" );
+ fprintf( pErr, "\t transforms the current network into an AIG assuming it is FRAIG with choices\n" );
+// fprintf( pErr, "\t-d : toggle duplication of logic [default = %s]\n", fDuplicate? "yes": "no" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandFraigStore( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk;
+ int c;
+ int fDuplicate;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ fDuplicate = 0;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "dh" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'd':
+ fDuplicate ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ return 1;
+ }
+
+ // get the new network
+ if ( !Abc_NtkFraigStore( pNtk ) )
+ {
+ fprintf( pErr, "Fraig storing has failed.\n" );
+ return 1;
+ }
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: fraig_store [-h]\n" );
+ fprintf( pErr, "\t saves the current network in the AIG database\n" );
+// fprintf( pErr, "\t-d : toggle duplication of logic [default = %s]\n", fDuplicate? "yes": "no" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandFraigRestore( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk, * pNtkRes;
+ int c;
+ int fDuplicate;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ fDuplicate = 0;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "dh" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'd':
+ fDuplicate ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ return 1;
+ }
+
+ // get the new network
+ pNtkRes = Abc_NtkFraigRestore();
+ if ( pNtkRes == NULL )
+ {
+ fprintf( pErr, "Fraig restoring has failed.\n" );
+ return 1;
+ }
+ // replace the current network
+ Abc_FrameReplaceCurrentNetwork( pAbc, pNtkRes );
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: fraig_restore [-h]\n" );
+ fprintf( pErr, "\t makes the current network by fraiging the AIG database\n" );
+// fprintf( pErr, "\t-d : toggle duplication of logic [default = %s]\n", fDuplicate? "yes": "no" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandFraigClean( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk;
+ int c;
+ int fDuplicate;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ fDuplicate = 0;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "dh" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'd':
+ fDuplicate ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+ Abc_NtkFraigStoreClean();
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: fraig_clean [-h]\n" );
+ fprintf( pErr, "\t cleans the internal FRAIG storage\n" );
+// fprintf( pErr, "\t-d : toggle duplication of logic [default = %s]\n", fDuplicate? "yes": "no" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandFraigSweep( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk;
+ int c;
+ int fUseInv;
+ int fVerbose;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ fUseInv = 1;
+ fVerbose = 0;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "ivh" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'i':
+ fUseInv ^= 1;
+ break;
+ case 'v':
+ fVerbose ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ return 1;
+ }
+ if ( Abc_NtkIsNetlist(pNtk) )
+ {
+ fprintf( pErr, "Cannot sweep a netlist. Please transform into a logic network.\n" );
+ return 1;
+ }
+ if ( Abc_NtkIsAig(pNtk) )
+ {
+ fprintf( pErr, "Cannot sweep AIGs (use \"fraig\").\n" );
+ return 1;
+ }
+ // modify the current network
+ if ( !Abc_NtkFraigSweep( pNtk, fUseInv, fVerbose ) )
+ {
+ fprintf( pErr, "Sweeping has failed.\n" );
+ return 1;
+ }
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: fraig_sweep [-vh]\n" );
+ fprintf( pErr, "\t performs technology-dependent sweep\n" );
+// fprintf( pErr, "\t-i : toggle using inverter for complemented nodes [default = %s]\n", fUseInv? "yes": "no" );
+ fprintf( pErr, "\t-v : prints verbose information [default = %s]\n", fVerbose? "yes": "no" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandMap( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk, * pNtkRes;
+ char Buffer[100];
+ double DelayTarget;
+ int fRecovery;
+ int fVerbose;
+ int fSweep;
+ int c;
+ extern Abc_Ntk_t * Abc_NtkMap( Abc_Ntk_t * pNtk, double DelayTarget, int fRecovery, int fVerbose );
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ DelayTarget =-1;
+ fRecovery = 1;
+ fSweep = 1;
+ fVerbose = 0;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "dasvh" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'd':
+ if ( util_optind >= argc )
+ {
+ fprintf( pErr, "Command line switch \"-d\" should be followed by a floating point number.\n" );
+ goto usage;
+ }
+ DelayTarget = (float)atof(argv[util_optind]);
+ util_optind++;
+ if ( DelayTarget <= 0.0 )
+ goto usage;
+ break;
+ case 'a':
+ fRecovery ^= 1;
+ break;
+ case 's':
+ fSweep ^= 1;
+ break;
+ case 'v':
+ fVerbose ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ return 1;
+ }
+
+ if ( !Abc_NtkIsAig(pNtk) )
+ {
+ pNtk = Abc_NtkStrash( pNtk );
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Strashing before mapping has failed.\n" );
+ return 1;
+ }
+ pNtk = Abc_NtkBalance( pNtkRes = pNtk, 0 );
+ Abc_NtkDelete( pNtkRes );
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Balancing before mapping has failed.\n" );
+ return 1;
+ }
+ fprintf( pOut, "The network was strashed and balanced before mapping.\n" );
+ // get the new network
+ pNtkRes = Abc_NtkMap( pNtk, DelayTarget, fRecovery, fVerbose );
+ if ( pNtkRes == NULL )
+ {
+ Abc_NtkDelete( pNtk );
+ fprintf( pErr, "Mapping has failed.\n" );
+ return 1;
+ }
+ Abc_NtkDelete( pNtk );
+ }
+ else
+ {
+ // get the new network
+ pNtkRes = Abc_NtkMap( pNtk, DelayTarget, fRecovery, fVerbose );
+ if ( pNtkRes == NULL )
+ {
+ fprintf( pErr, "Mapping has failed.\n" );
+ return 1;
+ }
+ }
+
+ if ( fSweep )
+ Abc_NtkFraigSweep( pNtkRes, 0, 0 );
+
+ // replace the current network
+ Abc_FrameReplaceCurrentNetwork( pAbc, pNtkRes );
+ return 0;
+
+usage:
+ if ( DelayTarget == -1 )
+ sprintf( Buffer, "not used" );
+ else
+ sprintf( Buffer, "%.3f", DelayTarget );
+ fprintf( pErr, "usage: map [-d num] [-asvh]\n" );
+ fprintf( pErr, "\t performs standard cell mapping of the current network\n" );
+ fprintf( pErr, "\t-d num : sets the global required times [default = %s]\n", Buffer );
+ fprintf( pErr, "\t-a : toggles area recovery [default = %s]\n", fRecovery? "yes": "no" );
+ fprintf( pErr, "\t-s : toggles sweep after mapping [default = %s]\n", fSweep? "yes": "no" );
+ fprintf( pErr, "\t-v : toggles verbose output [default = %s]\n", fVerbose? "yes": "no" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandUnmap( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk;
+ int c;
+ extern int Abc_NtkUnmap( Abc_Ntk_t * pNtk );
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "h" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ return 1;
+ }
+ if ( !Abc_NtkIsLogicMap(pNtk) )
+ {
+ fprintf( pErr, "Cannot unmap the network that is not mapped.\n" );
+ return 1;
+ }
+
+ // get the new network
+ if ( !Abc_NtkUnmap( pNtk ) )
+ {
+ fprintf( pErr, "Unmapping has failed.\n" );
+ return 1;
+ }
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: unmap [-h]\n" );
+ fprintf( pErr, "\t replaces the library gates by the logic nodes represented using SOPs\n" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandAttach( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk;
+ int c;
+ extern int Abc_NtkUnmap( Abc_Ntk_t * pNtk );
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "h" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ return 1;
+ }
+
+ if ( !Abc_NtkIsLogicSop(pNtk) )
+ {
+ fprintf( pErr, "Can only attach gates if the nodes have SOP representations.\n" );
+ return 1;
+ }
+
+ // get the new network
+ if ( !Abc_NtkAttach( pNtk ) )
+ {
+ fprintf( pErr, "Attaching gates has failed.\n" );
+ return 1;
+ }
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: attach [-h]\n" );
+ fprintf( pErr, "\t replaces the SOP functions by the gates from the library\n" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandFpga( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk, * pNtkRes;
+ int c;
+ int fRecovery;
+ int fVerbose;
+ extern Abc_Ntk_t * Abc_NtkFpga( Abc_Ntk_t * pNtk, int fRecovery, int fVerbose );
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ fRecovery = 1;
+ fVerbose = 0;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "avh" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'a':
+ fRecovery ^= 1;
+ break;
+ case 'v':
+ fVerbose ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ return 1;
+ }
+
+ if ( !Abc_NtkIsAig(pNtk) )
+ {
+ // strash and balance the network
+ pNtk = Abc_NtkStrash( pNtk );
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Strashing before FPGA mapping has failed.\n" );
+ return 1;
+ }
+ pNtk = Abc_NtkBalance( pNtkRes = pNtk, 0 );
+ Abc_NtkDelete( pNtkRes );
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Balancing before FPGA mapping has failed.\n" );
+ return 1;
+ }
+ fprintf( pOut, "The network was strashed and balanced before FPGA mapping.\n" );
+ // get the new network
+ pNtkRes = Abc_NtkFpga( pNtk, fRecovery, fVerbose );
+ if ( pNtkRes == NULL )
+ {
+ Abc_NtkDelete( pNtk );
+ fprintf( pErr, "FPGA mapping has failed.\n" );
+ return 1;
+ }
+ Abc_NtkDelete( pNtk );
+ }
+ else
+ {
+ // get the new network
+ pNtkRes = Abc_NtkFpga( pNtk, fRecovery, fVerbose );
+ if ( pNtkRes == NULL )
+ {
+ fprintf( pErr, "FPGA mapping has failed.\n" );
+ return 1;
+ }
+ }
+ // replace the current network
+ Abc_FrameReplaceCurrentNetwork( pAbc, pNtkRes );
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: fpga [-avh]\n" );
+ fprintf( pErr, "\t performs FPGA mapping of the current network\n" );
+ fprintf( pErr, "\t-a : toggles area recovery [default = %s]\n", fRecovery? "yes": "no" );
+ fprintf( pErr, "\t-v : toggles verbose output [default = %s]\n", fVerbose? "yes": "no" );
+ fprintf( pErr, "\t-h : prints the command usage\n");
+ return 1;
+}
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandCec( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk, * pNtk1, * pNtk2;
+ int fDelete1, fDelete2;
+ char ** pArgvNew;
+ int nArgcNew;
+ int c;
+ int fSat;
+
+ extern void Abc_NtkCecSat( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2 );
+ extern void Abc_NtkCecFraig( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2 );
+
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ fSat = 0;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "sh" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 's':
+ fSat ^= 1;
+ break;
+ default:
+ goto usage;
+ }
+ }
+
+ pArgvNew = argv + util_optind;
+ nArgcNew = argc - util_optind;
+ if ( !Abc_NtkPrepareCommand( pErr, pNtk, pArgvNew, nArgcNew, &pNtk1, &pNtk2, &fDelete1, &fDelete2 ) )
+ return 1;
+
+ // perform equivalence checking
+ if ( fSat )
+ Abc_NtkCecSat( pNtk1, pNtk2 );
+ else
+ Abc_NtkCecFraig( pNtk1, pNtk2 );
+
+ if ( fDelete1 ) Abc_NtkDelete( pNtk1 );
+ if ( fDelete2 ) Abc_NtkDelete( pNtk2 );
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: cec [-sh] <file1> <file2>\n" );
+ fprintf( pErr, "\t performs combinational equivalence checking\n" );
+ fprintf( pErr, "\t-s : toggle \"SAT only\" and \"FRAIG + SAT\" [default = %s]\n", fSat? "SAT only": "FRAIG + SAT" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ fprintf( pErr, "\tfile1 : (optional) the file with the first network\n");
+ fprintf( pErr, "\tfile2 : (optional) the file with the second network\n");
+ fprintf( pErr, "\t if no files are given, uses the current network and its spec\n");
+ fprintf( pErr, "\t if one file is given, uses the current network and the file\n");
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ntk_CommandSec( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk, * pNtk1, * pNtk2;
+ int fDelete1, fDelete2;
+ char ** pArgvNew;
+ int nArgcNew;
+ int c;
+ int fSat;
+ int nFrames;
+
+ extern void Abc_NtkSecSat( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int nFrames );
+ extern void Abc_NtkSecFraig( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int nFrames );
+
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set defaults
+ nFrames = 3;
+ fSat = 0;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "fsh" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'f':
+ if ( util_optind >= argc )
+ {
+ fprintf( pErr, "Command line switch \"-t\" should be followed by an integer.\n" );
+ goto usage;
+ }
+ nFrames = atoi(argv[util_optind]);
+ util_optind++;
+ if ( nFrames < 0 )
+ goto usage;
+ break;
+ case 's':
+ fSat ^= 1;
+ break;
+ default:
+ goto usage;
+ }
+ }
+
+ pArgvNew = argv + util_optind;
+ nArgcNew = argc - util_optind;
+ if ( !Abc_NtkPrepareCommand( pErr, pNtk, pArgvNew, nArgcNew, &pNtk1, &pNtk2, &fDelete1, &fDelete2 ) )
+ return 1;
+
+ // perform equivalence checking
+ if ( fSat )
+ Abc_NtkSecSat( pNtk1, pNtk2, nFrames );
+ else
+ Abc_NtkSecFraig( pNtk1, pNtk2, nFrames );
+
+ if ( fDelete1 ) Abc_NtkDelete( pNtk1 );
+ if ( fDelete2 ) Abc_NtkDelete( pNtk2 );
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: sec [-sh] [-f num] <file1> <file2>\n" );
+ fprintf( pErr, "\t performs bounded sequential equivalence checking\n" );
+ fprintf( pErr, "\t-s : toggle \"SAT only\" and \"FRAIG + SAT\" [default = %s]\n", fSat? "SAT only": "FRAIG + SAT" );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ fprintf( pErr, "\t-f num : the number of time frames to use [default = %d]\n", nFrames );
+ fprintf( pErr, "\tfile1 : (optional) the file with the first network\n");
+ fprintf( pErr, "\tfile2 : (optional) the file with the second network\n");
+ fprintf( pErr, "\t if no files are given, uses the current network and its spec\n");
+ fprintf( pErr, "\t if one file is given, uses the current network and the file\n");
+ return 1;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abc.h b/src/base/abc/abc.h
new file mode 100644
index 00000000..d918cbc2
--- /dev/null
+++ b/src/base/abc/abc.h
@@ -0,0 +1,557 @@
+/**CFile****************************************************************
+
+ FileName [abc.h]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [External declarations.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abc.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __ABC_H__
+#define __ABC_H__
+
+/*
+ In the netlist, the PI/PO arrays store PI/PO nets.
+ The names belongs to the nets and are stored in pNet->pData.
+ When a netlist is made combinational:
+ - LO/LI nets are added to PI/PO arrays,
+ - the array of latches is temporarily stored in vLatch2,
+ - the original number of PIs/POs is remembered in nPisOld/nPosOld.
+
+ In a logic network, the PI/PO arrays store PI/PO nodes.
+ The PO nodes have only one fanin edge, which can be complemented.
+ The arrays vNamesPi/vNamesPo/vNamesLatch store PI/PO/latch names.
+ The internal nodes are nameless.
+ When a logic network is made combinational:
+ - laches are added to the PI/PO arrays,
+ - the arrays of names are not changed,
+ - the array of latches is temporarily stored in vLatch2,
+ - the original number of PIs/POs is remembered in nPisOld/nPosOld.
+*/
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <time.h>
+
+#include "cuddInt.h"
+#include "extra.h"
+#include "solver.h"
+#include "vec.h"
+#include "stmm.h"
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+// network types
+typedef enum {
+ ABC_NTK_NONE, // unknown
+ ABC_NTK_NETLIST, // net and node list as in the input file
+ ABC_NTK_LOGIC_SOP, // only SOP logic nodes (similar to SIS network)
+ ABC_NTK_LOGIC_BDD, // only BDD logic nodes (similar to BDS network)
+ ABC_NTK_LOGIC_MAP, // only mapped logic nodes (similar to mapped SIS network)
+ ABC_NTK_AIG, // AIG or FRAIG (two input gates with c-attributes on edges)
+ ABC_NTK_SEQ, // sequential AIG (two input gates with c- and latch-attributes on edges)
+ ABC_NTK_OTHER // unused
+} Abc_NtkType_t;
+
+// object types
+typedef enum {
+ ABC_OBJ_TYPE_NONE, // unknown
+ ABC_OBJ_TYPE_NET, // net
+ ABC_OBJ_TYPE_NODE, // node
+ ABC_OBJ_TYPE_LATCH, // latch
+ ABC_OBJ_TYPE_TERM, // terminal
+ ABC_OBJ_TYPE_OTHER // unused
+} Abc_ObjType_t;
+
+// object subtypes
+typedef enum {
+ ABC_OBJ_SUBTYPE_PI = 0x01, // primary input
+ ABC_OBJ_SUBTYPE_PO = 0x02, // primary output
+ ABC_OBJ_SUBTYPE_LI = 0x04, // primary latch input
+ ABC_OBJ_SUBTYPE_LO = 0x08 // primary latch output
+} Abc_ObjSubtype_t;
+
+////////////////////////////////////////////////////////////////////////
+/// BASIC TYPES ///
+////////////////////////////////////////////////////////////////////////
+
+//typedef int bool;
+#ifndef bool
+#define bool int
+#endif
+
+typedef struct Abc_Obj_t_ Abc_Obj_t;
+typedef struct Abc_Ntk_t_ Abc_Ntk_t;
+typedef struct Abc_Aig_t_ Abc_Aig_t;
+typedef struct Abc_ManTime_t_ Abc_ManTime_t;
+typedef struct Abc_Time_t_ Abc_Time_t;
+
+struct Abc_Time_t_
+{
+ float Rise;
+ float Fall;
+ float Worst;
+};
+
+struct Abc_Obj_t_ // 12 words
+{
+ // high-level information
+ unsigned Type : 4; // the object type
+ unsigned Subtype : 4; // the object subtype
+ unsigned Id : 24; // the ID of the object
+ // internal information
+ unsigned fMarkA : 1; // the multipurpose mark
+ unsigned fMarkB : 1; // the multipurpose mark
+ unsigned fMarkC : 1; // the multipurpose mark
+ unsigned fPhase : 1; // the flag to mark the phase of equivalent node
+ unsigned TravId : 12; // the traversal ID
+ unsigned Level : 16; // the level of the node
+ // connectivity
+ Vec_Fan_t vFanins; // the array of fanins
+ Vec_Fan_t vFanouts; // the array of fanouts
+ // miscellaneous
+ Abc_Ntk_t * pNtk; // the host network
+ void * pData; // the network specific data (SOP, BDD, gate, equiv class, etc)
+ Abc_Obj_t * pNext; // the next pointer in the hash table
+ Abc_Obj_t * pCopy; // the copy of this object
+};
+
+struct Abc_Ntk_t_
+{
+ // general information about the network
+ Abc_NtkType_t Type; // type of the network
+ char * pName; // the network name
+ char * pSpec; // the name of the spec file if present
+ // name representation in the netlist
+ stmm_table * tName2Net; // the table hashing net names into net pointer
+ // name representation in the logic network
+ Vec_Ptr_t * vNamesPi; // the array of PI node names
+ Vec_Ptr_t * vNamesLatch; // the array of latch names names
+ Vec_Ptr_t * vNamesPo; // the array of PO node names
+ // components of the network
+ Vec_Ptr_t * vObjs; // the array of all objects (net, nodes, latches)
+ Vec_Ptr_t * vPis; // the array of PIs
+ Vec_Ptr_t * vPos; // the array of POs
+ Vec_Ptr_t * vLatches; // the array of latches (or the cutset in the sequential network)
+ // the stats about the number of living objects
+ int nObjs; // the number of living objs
+ int nNets; // the number of living nets
+ int nNodes; // the number of living nodes
+ int nLatches; // the number of latches
+ int nPis; // the number of primary inputs
+ int nPos; // the number of primary outputs
+ // the functionality manager
+ void * pManFunc; // AIG manager, BDD manager, or memory manager for SOPs
+ // the timing manager
+ Abc_ManTime_t * pManTime; // stores arrival/required times for all nodes
+ // the external don't-care if given
+ Abc_Ntk_t * pExdc; // the EXDC network
+ // miscellaneous data members
+ Vec_Ptr_t * vLatches2; // the temporary array of latches
+ int nPisOld; // the number of old PIs
+ int nPosOld; // the number of old PIs
+ unsigned nTravIds; // the unique traversal IDs of nodes
+ Vec_Ptr_t * vPtrTemp; // the temporary array
+ Vec_Int_t * vIntTemp; // the temporary array
+ Vec_Str_t * vStrTemp; // the temporary array
+ // the backup network and the step number
+ Abc_Ntk_t * pNetBackup; // the pointer to the previous backup network
+ int iStep; // the generation number for the given network
+ // memory management
+ Extra_MmFlex_t * pMmNames; // memory manager for net names
+ Extra_MmFixed_t* pMmObj; // memory manager for objects
+ Extra_MmStep_t * pMmStep; // memory manager for arrays
+};
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// reading data members of the network
+static inline char * Abc_NtkName( Abc_Ntk_t * pNtk ) { return pNtk->pName; }
+static inline char * Abc_NtkSpec( Abc_Ntk_t * pNtk ) { return pNtk->pSpec; }
+static inline int Abc_NtkTravId( Abc_Ntk_t * pNtk ) { return pNtk->nTravIds; }
+static inline Abc_Ntk_t * Abc_NtkExdc( Abc_Ntk_t * pNtk ) { return pNtk->pExdc; }
+static inline Abc_Ntk_t * Abc_NtkBackup( Abc_Ntk_t * pNtk ) { return pNtk->pNetBackup; }
+static inline int Abc_NtkStep ( Abc_Ntk_t * pNtk ) { return pNtk->iStep; }
+
+static inline Vec_Ptr_t * Abc_NtkObjVec( Abc_Ntk_t * pNtk ) { return pNtk->vObjs; }
+static inline Vec_Ptr_t * Abc_NtkLatchVec( Abc_Ntk_t * pNtk ) { return pNtk->vLatches; }
+static inline Vec_Ptr_t * Abc_NtkPiVec( Abc_Ntk_t * pNtk ) { return pNtk->vPis; }
+static inline Vec_Ptr_t * Abc_NtkPoVec( Abc_Ntk_t * pNtk ) { return pNtk->vPos; }
+
+static inline Abc_Obj_t * Abc_NtkObj( Abc_Ntk_t * pNtk, int i ) { return pNtk->vObjs->pArray[i]; }
+static inline Abc_Obj_t * Abc_NtkLatch( Abc_Ntk_t * pNtk, int i ) { return pNtk->vLatches->pArray[i]; }
+static inline Abc_Obj_t * Abc_NtkPi( Abc_Ntk_t * pNtk, int i ) { return pNtk->vPis->pArray[i]; }
+static inline Abc_Obj_t * Abc_NtkPo( Abc_Ntk_t * pNtk, int i ) { return pNtk->vPos->pArray[i]; }
+static inline Abc_Obj_t * Abc_NtkCi( Abc_Ntk_t * pNtk, int i ) { return pNtk->vPis->pArray[i]; }
+static inline Abc_Obj_t * Abc_NtkCo( Abc_Ntk_t * pNtk, int i ) { return pNtk->vPos->pArray[i]; }
+
+// setting data members of the network
+static inline void Abc_NtkSetName ( Abc_Ntk_t * pNtk, char * pName ) { pNtk->pName = pName; }
+static inline void Abc_NtkSetSpec ( Abc_Ntk_t * pNtk, char * pName ) { pNtk->pSpec = pName; }
+static inline void Abc_NtkSetBackup( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNetBackup ) { pNtk->pNetBackup = pNetBackup; }
+static inline void Abc_NtkSetStep ( Abc_Ntk_t * pNtk, int iStep ) { pNtk->iStep = iStep; }
+
+// checking the network type
+static inline bool Abc_NtkIsNetlist( Abc_Ntk_t * pNtk ) { return pNtk->Type == ABC_NTK_NETLIST; }
+static inline bool Abc_NtkIsLogicSop( Abc_Ntk_t * pNtk ) { return pNtk->Type == ABC_NTK_LOGIC_SOP; }
+static inline bool Abc_NtkIsLogicBdd( Abc_Ntk_t * pNtk ) { return pNtk->Type == ABC_NTK_LOGIC_BDD; }
+static inline bool Abc_NtkIsLogicMap( Abc_Ntk_t * pNtk ) { return pNtk->Type == ABC_NTK_LOGIC_MAP; }
+static inline bool Abc_NtkIsLogic( Abc_Ntk_t * pNtk ) { return pNtk->Type == ABC_NTK_LOGIC_SOP || pNtk->Type == ABC_NTK_LOGIC_BDD || pNtk->Type == ABC_NTK_LOGIC_MAP; }
+static inline bool Abc_NtkIsAig( Abc_Ntk_t * pNtk ) { return pNtk->Type == ABC_NTK_AIG; }
+static inline bool Abc_NtkIsSeq( Abc_Ntk_t * pNtk ) { return pNtk->Type == ABC_NTK_SEQ; }
+
+// getting the number of different objects in the network
+static inline int Abc_NtkObjNum( Abc_Ntk_t * pNtk ) { return pNtk->nObjs; }
+static inline int Abc_NtkNetNum( Abc_Ntk_t * pNtk ) { return pNtk->nNets; }
+static inline int Abc_NtkNodeNum( Abc_Ntk_t * pNtk ) { return pNtk->nNodes; }
+static inline int Abc_NtkLatchNum( Abc_Ntk_t * pNtk ) { return pNtk->nLatches; }
+static inline int Abc_NtkPiNum( Abc_Ntk_t * pNtk ) { return pNtk->nPis; }
+static inline int Abc_NtkPoNum( Abc_Ntk_t * pNtk ) { return pNtk->nPos; }
+static inline int Abc_NtkCiNum( Abc_Ntk_t * pNtk ) { return pNtk->vPis->nSize; }
+static inline int Abc_NtkCoNum( Abc_Ntk_t * pNtk ) { return pNtk->vPos->nSize; }
+
+// getting hold of the names of the PIs/POs/latches
+static inline char * Abc_NtkNameLatch(Abc_Ntk_t * pNtk, int i){ return pNtk->vNamesLatch->pArray[i]; }
+static inline char * Abc_NtkNamePi( Abc_Ntk_t * pNtk, int i ) { return pNtk->vNamesPi->pArray[i]; }
+static inline char * Abc_NtkNamePo( Abc_Ntk_t * pNtk, int i ) { return pNtk->vNamesPo->pArray[i]; }
+static inline char * Abc_NtkNameCi( Abc_Ntk_t * pNtk, int i ) { return pNtk->vNamesPi->pArray[i]; }
+static inline char * Abc_NtkNameCo( Abc_Ntk_t * pNtk, int i ) { return pNtk->vNamesPo->pArray[i]; }
+
+// working with complemented attributes of objects
+static inline bool Abc_ObjIsComplement( Abc_Obj_t * p ) { return (bool)(((unsigned)p) & 01); }
+static inline Abc_Obj_t * Abc_ObjRegular( Abc_Obj_t * p ) { return (Abc_Obj_t *)((unsigned)(p) & ~01); }
+static inline Abc_Obj_t * Abc_ObjNot( Abc_Obj_t * p ) { return (Abc_Obj_t *)((unsigned)(p) ^ 01); }
+static inline Abc_Obj_t * Abc_ObjNotCond( Abc_Obj_t * p, int c ) { return (Abc_Obj_t *)((unsigned)(p) ^ (c)); }
+
+// reading data members of the object
+static inline unsigned Abc_ObjType( Abc_Obj_t * pObj ) { return pObj->Type; }
+static inline unsigned Abc_ObjSubtype( Abc_Obj_t * pObj ) { return pObj->Subtype; }
+static inline unsigned Abc_ObjId( Abc_Obj_t * pObj ) { return pObj->Id; }
+static inline int Abc_ObjTravId( Abc_Obj_t * pObj ) { return pObj->TravId; }
+static inline Vec_Fan_t * Abc_ObjFaninVec( Abc_Obj_t * pObj ) { return &pObj->vFanins; }
+static inline Vec_Fan_t * Abc_ObjFanoutVec( Abc_Obj_t * pObj ) { return &pObj->vFanouts; }
+static inline Abc_Obj_t * Abc_ObjCopy( Abc_Obj_t * pObj ) { return pObj->pCopy; }
+static inline Abc_Ntk_t * Abc_ObjNtk( Abc_Obj_t * pObj ) { return pObj->pNtk; }
+static inline void * Abc_ObjData( Abc_Obj_t * pObj ) { return pObj->pData; }
+
+static inline int Abc_ObjFaninNum( Abc_Obj_t * pObj ) { return pObj->vFanins.nSize; }
+static inline int Abc_ObjFanoutNum( Abc_Obj_t * pObj ) { return pObj->vFanouts.nSize; }
+static inline Abc_Obj_t * Abc_ObjFanout( Abc_Obj_t * pObj, int i ){ return pObj->pNtk->vObjs->pArray[ pObj->vFanouts.pArray[i].iFan ]; }
+static inline Abc_Obj_t * Abc_ObjFanout0( Abc_Obj_t * pObj ) { return pObj->pNtk->vObjs->pArray[ pObj->vFanouts.pArray[0].iFan ]; }
+static inline Abc_Obj_t * Abc_ObjFanin( Abc_Obj_t * pObj, int i ) { return pObj->pNtk->vObjs->pArray[ pObj->vFanins.pArray[i].iFan ]; }
+static inline Abc_Obj_t * Abc_ObjFanin0( Abc_Obj_t * pObj ) { return pObj->pNtk->vObjs->pArray[ pObj->vFanins.pArray[0].iFan ]; }
+static inline Abc_Obj_t * Abc_ObjFanin1( Abc_Obj_t * pObj ) { return pObj->pNtk->vObjs->pArray[ pObj->vFanins.pArray[1].iFan ]; }
+static inline int Abc_ObjFaninId( Abc_Obj_t * pObj, int i){ return pObj->vFanins.pArray[i].iFan; }
+static inline int Abc_ObjFaninId0( Abc_Obj_t * pObj ) { return pObj->vFanins.pArray[0].iFan; }
+static inline int Abc_ObjFaninId1( Abc_Obj_t * pObj ) { return pObj->vFanins.pArray[1].iFan; }
+static inline bool Abc_ObjFaninC( Abc_Obj_t * pObj, int i ){ return pObj->vFanins.pArray[i].fCompl; }
+static inline bool Abc_ObjFaninC0( Abc_Obj_t * pObj ) { return pObj->vFanins.pArray[0].fCompl; }
+static inline bool Abc_ObjFaninC1( Abc_Obj_t * pObj ) { return pObj->vFanins.pArray[1].fCompl; }
+static inline Abc_Obj_t * Abc_ObjChild0( Abc_Obj_t * pObj ) { return Abc_ObjNotCond( Abc_ObjFanin0(pObj), Abc_ObjFaninC0(pObj) );}
+static inline Abc_Obj_t * Abc_ObjChild1( Abc_Obj_t * pObj ) { return Abc_ObjNotCond( Abc_ObjFanin1(pObj), Abc_ObjFaninC1(pObj) );}
+static inline void Abc_ObjSetFaninC( Abc_Obj_t * pObj, int i ){ pObj->vFanins.pArray[i].fCompl = 1; }
+static inline void Abc_ObjXorFaninC( Abc_Obj_t * pObj, int i ){ pObj->vFanins.pArray[i].fCompl ^= 1; }
+
+// setting data members of the network
+static inline void Abc_ObjSetCopy( Abc_Obj_t * pObj, Abc_Obj_t * pCopy ) { pObj->pCopy = pCopy; }
+static inline void Abc_ObjSetData( Abc_Obj_t * pObj, void * pData ) { pObj->pData = pData; }
+static inline void Abc_ObjSetSubtype( Abc_Obj_t * pObj, Abc_ObjSubtype_t Subtype ) { pObj->Subtype |= Subtype; }
+static inline void Abc_ObjUnsetSubtype( Abc_Obj_t * pObj, Abc_ObjSubtype_t Subtype ) { pObj->Subtype &= ~Subtype; }
+
+// checking the object type
+static inline bool Abc_ObjIsNode( Abc_Obj_t * pObj ) { return pObj->Type == ABC_OBJ_TYPE_NODE; }
+static inline bool Abc_ObjIsNet( Abc_Obj_t * pObj ) { return pObj->Type == ABC_OBJ_TYPE_NET; }
+static inline bool Abc_ObjIsLatch( Abc_Obj_t * pObj ) { return pObj->Type == ABC_OBJ_TYPE_LATCH; }
+static inline bool Abc_ObjIsTerm( Abc_Obj_t * pObj ) { return pObj->Type == ABC_OBJ_TYPE_TERM; }
+
+static inline bool Abc_ObjIsPi( Abc_Obj_t * pObj ) { return ((pObj->Subtype & ABC_OBJ_SUBTYPE_PI) > 0); }
+static inline bool Abc_ObjIsPo( Abc_Obj_t * pObj ) { return ((pObj->Subtype & ABC_OBJ_SUBTYPE_PO) > 0); }
+static inline bool Abc_ObjIsLi( Abc_Obj_t * pObj ) { return ((pObj->Subtype & ABC_OBJ_SUBTYPE_LI) > 0); }
+static inline bool Abc_ObjIsLo( Abc_Obj_t * pObj ) { return ((pObj->Subtype & ABC_OBJ_SUBTYPE_LO) > 0); }
+static inline bool Abc_ObjIsCi( Abc_Obj_t * pObj ) { if ( Abc_NtkIsNetlist(pObj->pNtk) ) return ((pObj->Subtype & (ABC_OBJ_SUBTYPE_PI | ABC_OBJ_SUBTYPE_LO)) > 0); else return (Abc_ObjIsPi(pObj) || Abc_ObjIsLatch(pObj)); }
+static inline bool Abc_ObjIsCo( Abc_Obj_t * pObj ) { if ( Abc_NtkIsNetlist(pObj->pNtk) ) return ((pObj->Subtype & (ABC_OBJ_SUBTYPE_PO | ABC_OBJ_SUBTYPE_LI)) > 0); else return (Abc_ObjIsPo(pObj) || Abc_ObjIsLatch(pObj)); }
+
+// checking the node type
+static inline bool Abc_NodeIsAnd( Abc_Obj_t * pNode ) { assert(Abc_ObjIsNode(Abc_ObjRegular(pNode))); assert(Abc_NtkIsAig(Abc_ObjRegular(pNode)->pNtk)); return Abc_ObjFaninNum(Abc_ObjRegular(pNode)) == 2; }
+static inline bool Abc_NodeIsChoice( Abc_Obj_t * pNode ) { assert(Abc_ObjIsNode(Abc_ObjRegular(pNode))); assert(Abc_NtkIsAig(Abc_ObjRegular(pNode)->pNtk)); return Abc_ObjRegular(pNode)->pData != NULL && Abc_ObjFanoutNum(Abc_ObjRegular(pNode)) > 0; }
+static inline bool Abc_NodeIsConst( Abc_Obj_t * pNode ) { assert(Abc_ObjIsNode(Abc_ObjRegular(pNode))); return Abc_ObjFaninNum(Abc_ObjRegular(pNode)) == 0; }
+extern bool Abc_NodeIsConst0( Abc_Obj_t * pNode );
+extern bool Abc_NodeIsConst1( Abc_Obj_t * pNode );
+extern bool Abc_NodeIsBuf( Abc_Obj_t * pNode );
+extern bool Abc_NodeIsInv( Abc_Obj_t * pNode );
+
+// working with the traversal ID
+static inline void Abc_NodeSetTravId( Abc_Obj_t * pNode, int TravId ) { pNode->TravId = TravId; }
+static inline void Abc_NodeSetTravIdCurrent( Abc_Obj_t * pNode ) { pNode->TravId = pNode->pNtk->nTravIds; }
+static inline void Abc_NodeSetTravIdPrevious( Abc_Obj_t * pNode ) { pNode->TravId = pNode->pNtk->nTravIds - 1; }
+static inline bool Abc_NodeIsTravIdCurrent( Abc_Obj_t * pNode ) { return (bool)(pNode->TravId == pNode->pNtk->nTravIds); }
+static inline bool Abc_NodeIsTravIdPrevious( Abc_Obj_t * pNode ) { return (bool)(pNode->TravId == pNode->pNtk->nTravIds - 1); }
+
+// maximum/minimum operators
+#define ABC_MIN(a,b) (((a) < (b))? (a) : (b))
+#define ABC_MAX(a,b) (((a) > (b))? (a) : (b))
+#define ABC_INFINITY (10000000)
+
+// outputs the runtime in seconds
+#define PRT(a,t) printf("%s = ", (a)); printf("%6.2f sec\n", (float)(t)/(float)(CLOCKS_PER_SEC))
+
+////////////////////////////////////////////////////////////////////////
+/// ITERATORS ///
+////////////////////////////////////////////////////////////////////////
+
+// objects of the network
+#define Abc_NtkForEachObj( pNtk, pObj, i ) \
+ for ( i = 0; i < Vec_PtrSize(pNtk->vObjs); i++ ) \
+ if ( pObj = Abc_NtkObj(pNtk, i) )
+#define Abc_NtkForEachNet( pNtk, pNet, i ) \
+ for ( i = 0; i < Vec_PtrSize(pNtk->vObjs); i++ ) \
+ if ( (pNet = Abc_NtkObj(pNtk, i)) && Abc_ObjIsNet(pNet) )
+#define Abc_NtkForEachNode( pNtk, pNode, i ) \
+ for ( i = 0; i < Vec_PtrSize(pNtk->vObjs); i++ ) \
+ if ( (pNode = Abc_NtkObj(pNtk, i)) && Abc_ObjIsNode(pNode) )
+#define Abc_NtkForEachLatch( pNtk, pObj, i ) \
+ for ( i = 0; i < Vec_PtrSize(pNtk->vLatches); i++ ) \
+ if ( pObj = Abc_NtkLatch(pNtk, i) )
+// inputs and outputs
+#define Abc_NtkForEachPi( pNtk, pPi, i ) \
+ for ( i = 0; i < Abc_NtkPiNum(pNtk); i++ ) \
+ if ( pPi = Abc_NtkPi(pNtk, i) )
+#define Abc_NtkForEachPo( pNtk, pPo, i ) \
+ for ( i = 0; i < Abc_NtkPoNum(pNtk); i++ ) \
+ if ( pPo = Abc_NtkPo(pNtk, i) )
+#define Abc_NtkForEachCi( pNtk, pPi, i ) \
+ for ( i = 0; i < Abc_NtkCiNum(pNtk); i++ ) \
+ if ( pPi = Abc_NtkPi(pNtk, i) )
+#define Abc_NtkForEachCo( pNtk, pPo, i ) \
+ for ( i = 0; i < Abc_NtkCoNum(pNtk); i++ ) \
+ if ( pPo = Abc_NtkPo(pNtk, i) )
+// fanin and fanouts
+#define Abc_ObjForEachFanin( pObj, pFanin, i ) \
+ for ( i = 0; i < Abc_ObjFaninNum(pObj); i++ ) \
+ if ( pFanin = Abc_ObjFanin(pObj, i) )
+#define Abc_ObjForEachFanout( pObj, pFanout, i ) \
+ for ( i = 0; i < Abc_ObjFanoutNum(pObj); i++ ) \
+ if ( pFanout = Abc_ObjFanout(pObj, i) )
+// cubes and literals
+#define Abc_SopForEachCube( pSop, nFanins, pCube ) \
+ for ( pCube = (pSop); *pCube; pCube += (nFanins) + 3 )
+#define Abc_CubeForEachVar( pCube, Value, i ) \
+ for ( i = 0; (pCube[i] != ' ') && (Value = pCube[i]); i++ )
+
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== abcAig.c ==========================================================*/
+extern Abc_Aig_t * Abc_AigAlloc( Abc_Ntk_t * pNtk );
+extern void Abc_AigFree( Abc_Aig_t * pMan );
+extern Abc_Obj_t * Abc_AigConst1( Abc_Aig_t * pMan );
+extern Abc_Obj_t * Abc_AigAnd( Abc_Aig_t * pMan, Abc_Obj_t * p0, Abc_Obj_t * p1 );
+extern Abc_Obj_t * Abc_AigOr( Abc_Aig_t * pMan, Abc_Obj_t * p0, Abc_Obj_t * p1 );
+extern Abc_Obj_t * Abc_AigXor( Abc_Aig_t * pMan, Abc_Obj_t * p0, Abc_Obj_t * p1 );
+extern Abc_Obj_t * Abc_AigMiter( Abc_Aig_t * pMan, Vec_Ptr_t * vPairs );
+extern bool Abc_AigNodeIsUsedCompl( Abc_Obj_t * pNode );
+/*=== abcAttach.c ==========================================================*/
+extern int Abc_NtkAttach( Abc_Ntk_t * pNtk );
+/*=== abcCheck.c ==========================================================*/
+extern bool Abc_NtkCheck( Abc_Ntk_t * pNtk );
+extern bool Abc_NtkCompareSignals( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int fComb );
+/*=== abcCollapse.c ==========================================================*/
+extern Abc_Ntk_t * Abc_NtkCollapse( Abc_Ntk_t * pNtk, int fVerbose );
+/*=== abcCreate.c ==========================================================*/
+extern Abc_Ntk_t * Abc_NtkAlloc( Abc_NtkType_t Type );
+extern Abc_Ntk_t * Abc_NtkStartFrom( Abc_Ntk_t * pNtk, Abc_NtkType_t Type );
+extern void Abc_NtkFinalize( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew );
+extern void Abc_NtkFinalizeRegular( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew );
+extern Abc_Ntk_t * Abc_NtkDup( Abc_Ntk_t * pNtk );
+extern void Abc_NtkDelete( Abc_Ntk_t * pNtk );
+extern Abc_Obj_t * Abc_NtkDupObj( Abc_Ntk_t * pNtkNew, Abc_Obj_t * pObj );
+extern void Abc_NtkDeleteObj( Abc_Obj_t * pObj );
+extern void Abc_NtkMarkNetPi( Abc_Obj_t * pObj );
+extern void Abc_NtkMarkNetPo( Abc_Obj_t * pObj );
+extern Abc_Obj_t * Abc_NtkAddPoNode( Abc_Obj_t * pObj );
+extern void Abc_NtkRemovePoNode( Abc_Obj_t * pNode );
+extern Abc_Obj_t * Abc_NtkFindNode( Abc_Ntk_t * pNtk, char * pName );
+extern Abc_Obj_t * Abc_NtkFindNet( Abc_Ntk_t * pNtk, char * pName );
+extern Abc_Obj_t * Abc_NtkFindOrCreateNet( Abc_Ntk_t * pNtk, char * pName );
+extern Abc_Obj_t * Abc_NtkCreateNode( Abc_Ntk_t * pNtk );
+extern Abc_Obj_t * Abc_NtkCreateTermPi( Abc_Ntk_t * pNtk );
+extern Abc_Obj_t * Abc_NtkCreateTermPo( Abc_Ntk_t * pNtk );
+extern Abc_Obj_t * Abc_NtkCreateLatch( Abc_Ntk_t * pNtk );
+extern Abc_Obj_t * Abc_NodeCreateConst0( Abc_Ntk_t * pNtk );
+extern Abc_Obj_t * Abc_NodeCreateConst1( Abc_Ntk_t * pNtk );
+extern Abc_Obj_t * Abc_NodeCreateInv( Abc_Ntk_t * pNtk, Abc_Obj_t * pFanin );
+extern Abc_Obj_t * Abc_NodeCreateBuf( Abc_Ntk_t * pNtk, Abc_Obj_t * pFanin );
+extern Abc_Obj_t * Abc_NodeCreateAnd( Abc_Ntk_t * pNtk, Vec_Ptr_t * vFanins );
+extern Abc_Obj_t * Abc_NodeCreateOr( Abc_Ntk_t * pNtk, Vec_Ptr_t * vFanins );
+extern Abc_Obj_t * Abc_NodeCreateMux( Abc_Ntk_t * pNtk, Abc_Obj_t * pNodeC, Abc_Obj_t * pNode1, Abc_Obj_t * pNode0 );
+/*=== abcDfs.c ==========================================================*/
+extern Vec_Ptr_t * Abc_NtkDfs( Abc_Ntk_t * pNtk );
+extern Vec_Ptr_t * Abc_AigDfs( Abc_Ntk_t * pNtk );
+extern int Abc_NtkGetLevelNum( Abc_Ntk_t * pNtk );
+extern bool Abc_NtkIsAcyclic( Abc_Ntk_t * pNtk );
+/*=== abcFanio.c ==========================================================*/
+extern void Abc_ObjAddFanin( Abc_Obj_t * pObj, Abc_Obj_t * pFanin );
+extern void Abc_ObjDeleteFanin( Abc_Obj_t * pObj, Abc_Obj_t * pFanin );
+extern void Abc_ObjPatchFanin( Abc_Obj_t * pObj, Abc_Obj_t * pFaninOld, Abc_Obj_t * pFaninNew );
+extern void Abc_ObjTransferFanout( Abc_Obj_t * pObjOld, Abc_Obj_t * pObjNew );
+extern void Abc_ObjReplace( Abc_Obj_t * pObjOld, Abc_Obj_t * pObjNew );
+/*=== abcFraig.c ==========================================================*/
+extern Abc_Ntk_t * Abc_NtkFraig( Abc_Ntk_t * pNtk, void * pParams, int fAllNodes );
+extern Abc_Ntk_t * Abc_NtkFraigTrust( Abc_Ntk_t * pNtk );
+extern int Abc_NtkFraigStore( Abc_Ntk_t * pNtk );
+extern Abc_Ntk_t * Abc_NtkFraigRestore();
+extern void Abc_NtkFraigStoreClean();
+/*=== abcFunc.c ==========================================================*/
+extern int Abc_NtkSopToBdd( Abc_Ntk_t * pNtk );
+extern char * Abc_ConvertBddToSop( Extra_MmFlex_t * pMan, DdManager * dd, DdNode * bFunc, int nFanins, Vec_Str_t * vCube, int fMode );
+extern int Abc_NtkBddToSop( Abc_Ntk_t * pNtk );
+extern void Abc_NodeBddToCnf( Abc_Obj_t * pNode, Extra_MmFlex_t * pMmMan, Vec_Str_t * vCube, char ** ppSop0, char ** ppSop1 );
+extern int Abc_CountZddCubes( DdManager * dd, DdNode * zCover );
+/*=== abcLatch.c ==========================================================*/
+extern bool Abc_NtkIsComb( Abc_Ntk_t * pNtk );
+extern bool Abc_NtkMakeComb( Abc_Ntk_t * pNtk );
+extern bool Abc_NtkMakeSeq( Abc_Ntk_t * pNtk );
+extern bool Abc_NtkLatchIsSelfFeed( Abc_Obj_t * pLatch );
+extern int Abc_NtkCountSelfFeedLatches( Abc_Ntk_t * pNtk );
+/*=== abcMap.c ==========================================================*/
+extern Abc_Ntk_t * Abc_NtkMap( Abc_Ntk_t * pNtk, double DelayTarget, int fRecovery, int fVerbose );
+extern int Abc_NtkUnmap( Abc_Ntk_t * pNtk );
+/*=== abcMiter.c ==========================================================*/
+extern int Abc_NtkMinimumBase( Abc_Ntk_t * pNtk );
+extern int Abc_NodeMinimumBase( Abc_Obj_t * pNode );
+/*=== abcMiter.c ==========================================================*/
+extern Abc_Ntk_t * Abc_NtkMiter( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int fComb );
+extern int Abc_NtkMiterIsConstant( Abc_Ntk_t * pMiter );
+extern void Abc_NtkMiterReport( Abc_Ntk_t * pMiter );
+extern int Abc_NtkAppend( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2 );
+extern Abc_Ntk_t * Abc_NtkFrames( Abc_Ntk_t * pNtk, int nFrames, int fInitial );
+/*=== abcNames.c ====================================================*/
+extern char * Abc_NtkRegisterName( Abc_Ntk_t * pNtk, char * pName );
+extern char * Abc_NtkRegisterNamePlus( Abc_Ntk_t * pNtk, char * pName, char * pSuffix );
+extern stmm_table * Abc_NtkLogicHashNames( Abc_Ntk_t * pNtk, int Type, int fComb );
+extern void Abc_NtkLogicTransferNames( Abc_Ntk_t * pNtk );
+extern char * Abc_NtkNameLatchInput( Abc_Ntk_t * pNtk, int i );
+extern char * Abc_ObjName( Abc_Obj_t * pNode );
+extern char * Abc_ObjNameUnique( Abc_Ntk_t * pNtk, char * pName );
+extern char * Abc_NtkLogicStoreName( Abc_Obj_t * pNodeNew, char * pNameOld );
+extern char * Abc_NtkLogicStoreNamePlus( Abc_Obj_t * pNodeNew, char * pNameOld, char * pSuffix );
+extern void Abc_NtkDupNameArrays( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew );
+extern void Abc_NtkCreateNameArrays( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew );
+/*=== abcNetlist.c ==========================================================*/
+extern Abc_Ntk_t * Abc_NtkLogic( Abc_Ntk_t * pNtk );
+/*=== abcPrint.c ==========================================================*/
+extern void Abc_NtkPrintStats( FILE * pFile, Abc_Ntk_t * pNtk );
+extern void Abc_NtkPrintIo( FILE * pFile, Abc_Ntk_t * pNtk );
+extern void Abc_NtkPrintFanio( FILE * pFile, Abc_Ntk_t * pNtk );
+extern void Abc_NodePrintFanio( FILE * pFile, Abc_Obj_t * pNode );
+extern void Abc_NtkPrintFactor( FILE * pFile, Abc_Ntk_t * pNtk );
+extern void Abc_NodePrintFactor( FILE * pFile, Abc_Obj_t * pNode );
+/*=== abcRefs.c ==========================================================*/
+extern int Abc_NodeMffcSize( Abc_Obj_t * pNode );
+extern int Abc_NodeMffcRemove( Abc_Obj_t * pNode );
+/*=== abcRenode.c ==========================================================*/
+extern Abc_Ntk_t * Abc_NtkRenode( Abc_Ntk_t * pNtk, int nThresh, int nFaninMax, int fCnf, int fMulti, int fSimple );
+extern DdNode * Abc_NtkRenodeDeriveBdd( DdManager * dd, Abc_Obj_t * pNodeOld, Vec_Ptr_t * vFaninsOld );
+/*=== abcSat.c ==========================================================*/
+extern bool Abc_NtkMiterSat( Abc_Ntk_t * pNtk, int fVerbose );
+extern solver * Abc_NtkMiterSatCreate( Abc_Ntk_t * pNtk );
+/*=== abcSop.c ==========================================================*/
+extern char * Abc_SopRegister( Extra_MmFlex_t * pMan, char * pName );
+extern int Abc_SopGetCubeNum( char * pSop );
+extern int Abc_SopGetLitNum( char * pSop );
+extern int Abc_SopGetVarNum( char * pSop );
+extern int Abc_SopGetPhase( char * pSop );
+extern bool Abc_SopIsConst0( char * pSop );
+extern bool Abc_SopIsConst1( char * pSop );
+extern bool Abc_SopIsBuf( char * pSop );
+extern bool Abc_SopIsInv( char * pSop );
+extern bool Abc_SopIsAndType( char * pSop );
+extern bool Abc_SopIsOrType( char * pSop );
+extern int Abc_SopGetIthCareLit( char * pSop, int i );
+extern void Abc_SopComplement( char * pSop );
+extern bool Abc_SopCheck( char * pSop, int nFanins );
+extern void Abc_SopWriteCnf( FILE * pFile, char * pClauses, Vec_Int_t * vVars );
+extern void Abc_SopAddCnfToSolver( solver * pSat, char * pClauses, Vec_Int_t * vVars, Vec_Int_t * vTemp );
+/*=== abcStrash.c ==========================================================*/
+extern Abc_Ntk_t * Abc_NtkStrash( Abc_Ntk_t * pNtk );
+extern int Abc_NtkAppend( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2 );
+extern Abc_Ntk_t * Abc_NtkBalance( Abc_Ntk_t * pNtk, bool fDuplicate );
+/*=== abcSweep.c ==========================================================*/
+extern bool Abc_NtkFraigSweep( Abc_Ntk_t * pNtk, int fUseInv, int fVerbose );
+extern int Abc_NtkCleanup( Abc_Ntk_t * pNtk, int fVerbose );
+/*=== abcTiming.c ==========================================================*/
+extern Abc_Time_t * Abc_NodeReadArrival( Abc_Obj_t * pNode );
+extern Abc_Time_t * Abc_NodeReadRequired( Abc_Obj_t * pNode );
+extern Abc_Time_t * Abc_NtkReadDefaultArrival( Abc_Ntk_t * pNtk );
+extern Abc_Time_t * Abc_NtkReadDefaultRequired( Abc_Ntk_t * pNtk );
+extern void Abc_NtkTimeSetDefaultArrival( Abc_Ntk_t * pNtk, float Rise, float Fall );
+extern void Abc_NtkTimeSetDefaultRequired( Abc_Ntk_t * pNtk, float Rise, float Fall );
+extern void Abc_NtkTimeSetArrival( Abc_Ntk_t * pNtk, int ObjId, float Rise, float Fall );
+extern void Abc_NtkTimeSetRequired( Abc_Ntk_t * pNtk, int ObjId, float Rise, float Fall );
+extern void Abc_NtkTimeFinalize( Abc_Ntk_t * pNtk );
+extern void Abc_ManTimeStop( Abc_ManTime_t * p );
+extern void Abc_ManTimeDup( Abc_Ntk_t * pNtkOld, Abc_Ntk_t * pNtkNew );
+extern void Abc_NtkSetNodeLevelsArrival( Abc_Ntk_t * pNtk );
+extern float * Abc_NtkGetCiArrivalFloats( Abc_Ntk_t * pNtk );
+extern Abc_Time_t * Abc_NtkGetCiArrivalTimes( Abc_Ntk_t * pNtk );
+extern float Abc_NtkDelayTrace( Abc_Ntk_t * pNtk );
+/*=== abcTravId.c ==========================================================*/
+extern void Abc_NtkIncrementTravId( Abc_Ntk_t * pNtk );
+extern void Abc_NodeSetTravId( Abc_Obj_t * pObj, int TravId );
+extern void Abc_NodeSetTravIdCurrent( Abc_Obj_t * pObj );
+extern void Abc_NodeSetTravIdPrevious( Abc_Obj_t * pObj );
+extern bool Abc_NodeIsTravIdCurrent( Abc_Obj_t * pObj );
+extern bool Abc_NodeIsTravIdPrevious( Abc_Obj_t * pObj );
+/*=== abcUtil.c ==========================================================*/
+extern void Abc_NtkIncrementTravId( Abc_Ntk_t * pNtk );
+extern int Abc_NtkGetCubeNum( Abc_Ntk_t * pNtk );
+extern int Abc_NtkGetLitNum( Abc_Ntk_t * pNtk );
+extern int Abc_NtkGetLitFactNum( Abc_Ntk_t * pNtk );
+extern int Abc_NtkGetBddNodeNum( Abc_Ntk_t * pNtk );
+extern int Abc_NtkGetClauseNum( Abc_Ntk_t * pNtk );
+extern double Abc_NtkGetMappedArea( Abc_Ntk_t * pNtk );
+extern int Abc_NtkGetFaninMax( Abc_Ntk_t * pNtk );
+extern void Abc_NtkCleanCopy( Abc_Ntk_t * pNtk );
+extern Abc_Obj_t * Abc_NodeHasUniqueNamedFanout( Abc_Obj_t * pNode );
+extern bool Abc_NtkLogicHasSimplePos( Abc_Ntk_t * pNtk );
+extern int Abc_NtkLogicMakeSimplePos( Abc_Ntk_t * pNtk );
+extern void Abc_VecObjPushUniqueOrderByLevel( Vec_Ptr_t * p, Abc_Obj_t * pNode );
+extern bool Abc_NodeIsMuxType( Abc_Obj_t * pNode );
+extern Abc_Obj_t * Abc_NodeRecognizeMux( Abc_Obj_t * pNode, Abc_Obj_t ** ppNodeT, Abc_Obj_t ** ppNodeE );
+extern int Abc_NtkCountChoiceNodes( Abc_Ntk_t * pNtk );
+extern int Abc_NtkPrepareCommand( FILE * pErr, Abc_Ntk_t * pNtk, char ** argv, int argc, Abc_Ntk_t ** ppNtk1, Abc_Ntk_t ** ppNtk2, int * pfDelete1, int * pfDelete2 );
+extern void Abc_NodeCollectFanins( Abc_Obj_t * pNode, Vec_Ptr_t * vNodes );
+extern void Abc_NodeCollectFanouts( Abc_Obj_t * pNode, Vec_Ptr_t * vNodes );
+extern int Abc_NodeCompareLevelsIncrease( Abc_Obj_t ** pp1, Abc_Obj_t ** pp2 );
+extern int Abc_NodeCompareLevelsDecrease( Abc_Obj_t ** pp1, Abc_Obj_t ** pp2 );
+extern Vec_Ptr_t * Abc_AigCollectAll( Abc_Ntk_t * pNtk );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/src/base/abc/abcAig.c b/src/base/abc/abcAig.c
new file mode 100644
index 00000000..5ec0d97a
--- /dev/null
+++ b/src/base/abc/abcAig.c
@@ -0,0 +1,321 @@
+/**CFile****************************************************************
+
+ FileName [abcAig.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Simple structural hashing package.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcAig.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// the simple AIG manager
+struct Abc_Aig_t_
+{
+ Abc_Ntk_t * pAig; // the AIG network
+ Abc_Obj_t * pConst1; // the constant 1 node
+ Abc_Obj_t ** pBins; // the table bins
+ int nBins; // the size of the table
+ int nEntries; // the total number of entries in the table
+ Vec_Ptr_t * vNodes; // the temporary array of nodes
+};
+
+// iterators through the entries in the linked lists of nodes
+#define Abc_AigBinForEachEntry( pBin, pEnt ) \
+ for ( pEnt = pBin; \
+ pEnt; \
+ pEnt = pEnt->pNext )
+#define Abc_AigBinForEachEntrySafe( pBin, pEnt, pEnt2 ) \
+ for ( pEnt = pBin, \
+ pEnt2 = pEnt? pEnt->pNext: NULL; \
+ pEnt; \
+ pEnt = pEnt2, \
+ pEnt2 = pEnt? pEnt->pNext: NULL )
+
+// hash key for the structural hash table
+static inline unsigned Abc_HashKey2( Abc_Obj_t * p0, Abc_Obj_t * p1, int TableSize ) { return ((unsigned)(p0) + (unsigned)(p1) * 12582917) % TableSize; }
+//static inline unsigned Abc_HashKey2( Abc_Obj_t * p0, Abc_Obj_t * p1, int TableSize ) { return ((unsigned)((a)->Id + (b)->Id) * ((a)->Id + (b)->Id + 1) / 2) % TableSize; }
+
+// static hash table procedures
+static void Abc_AigResize( Abc_Aig_t * pMan );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Allocates the local AIG manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Aig_t * Abc_AigAlloc( Abc_Ntk_t * pNtkAig )
+{
+ Abc_Aig_t * pMan;
+ // start the manager
+ pMan = ALLOC( Abc_Aig_t, 1 );
+ memset( pMan, 0, sizeof(Abc_Aig_t) );
+ // allocate the table
+ pMan->nBins = Cudd_PrimeCopy( 10000 );
+ pMan->pBins = ALLOC( Abc_Obj_t *, pMan->nBins );
+ memset( pMan->pBins, 0, sizeof(Abc_Obj_t *) * pMan->nBins );
+ pMan->vNodes = Vec_PtrAlloc( 100 );
+ // save the current network
+ pMan->pAig = pNtkAig;
+ pMan->pConst1 = Abc_NtkCreateNode( pNtkAig );
+ return pMan;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Deallocates the local AIG manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_AigFree( Abc_Aig_t * pMan )
+{
+ // free the table
+ Vec_PtrFree( pMan->vNodes );
+ free( pMan->pBins );
+ free( pMan );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Read the constant 1 node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_AigConst1( Abc_Aig_t * pMan )
+{
+ return pMan->pConst1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs canonicization step.]
+
+ Description [The argument nodes can be complemented.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_AigAnd( Abc_Aig_t * pMan, Abc_Obj_t * p0, Abc_Obj_t * p1 )
+{
+ Abc_Obj_t * pAnd;
+ unsigned Key;
+ // check for trivial cases
+ if ( p0 == p1 )
+ return p0;
+ if ( p0 == Abc_ObjNot(p1) )
+ return Abc_ObjNot(pMan->pConst1);
+ if ( Abc_ObjRegular(p0) == pMan->pConst1 )
+ {
+ if ( p0 == pMan->pConst1 )
+ return p1;
+ return Abc_ObjNot(pMan->pConst1);
+ }
+ if ( Abc_ObjRegular(p1) == pMan->pConst1 )
+ {
+ if ( p1 == pMan->pConst1 )
+ return p0;
+ return Abc_ObjNot(pMan->pConst1);
+ }
+ // order the arguments
+ if ( Abc_ObjRegular(p0)->Id > Abc_ObjRegular(p1)->Id )
+ pAnd = p0, p0 = p1, p1 = pAnd;
+ // get the hash key for these two nodes
+ Key = Abc_HashKey2( p0, p1, pMan->nBins );
+ // find the mataching node in the table
+ Abc_AigBinForEachEntry( pMan->pBins[Key], pAnd )
+ if ( Abc_ObjFanin0(pAnd) == Abc_ObjRegular(p0) &&
+ Abc_ObjFanin1(pAnd) == Abc_ObjRegular(p1) &&
+ Abc_ObjFaninC0(pAnd) == Abc_ObjIsComplement(p0) &&
+ Abc_ObjFaninC1(pAnd) == Abc_ObjIsComplement(p1) )
+ return pAnd;
+ // check if it is a good time for table resizing
+ if ( pMan->nEntries > 2 * pMan->nBins )
+ {
+ Abc_AigResize( pMan );
+ Key = Abc_HashKey2( p0, p1, pMan->nBins );
+ }
+ // create the new node
+ pAnd = Abc_NtkCreateNode( pMan->pAig );
+ Abc_ObjAddFanin( pAnd, p0 );
+ Abc_ObjAddFanin( pAnd, p1 );
+ // set the level of the new node
+ pAnd->Level = 1 + ABC_MAX( Abc_ObjRegular(p0)->Level, Abc_ObjRegular(p1)->Level );
+ // add the node to the corresponding linked list in the table
+ pAnd->pNext = pMan->pBins[Key];
+ pMan->pBins[Key] = pAnd;
+ pMan->nEntries++;
+ return pAnd;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Implements Boolean AND.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_AigOr( Abc_Aig_t * pMan, Abc_Obj_t * p0, Abc_Obj_t * p1 )
+{
+ return Abc_ObjNot( Abc_AigAnd( pMan, Abc_ObjNot(p0), Abc_ObjNot(p1) ) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Implements Boolean AND.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_AigXor( Abc_Aig_t * pMan, Abc_Obj_t * p0, Abc_Obj_t * p1 )
+{
+ return Abc_AigOr( pMan, Abc_AigAnd(pMan, p0, Abc_ObjNot(p1)),
+ Abc_AigAnd(pMan, p1, Abc_ObjNot(p0)) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Implements the miter.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_AigMiter( Abc_Aig_t * pMan, Vec_Ptr_t * vPairs )
+{
+ Abc_Obj_t * pMiter, * pXor;
+ int i;
+ assert( vPairs->nSize % 2 == 0 );
+ // go through the cubes of the node's SOP
+ pMiter = Abc_ObjNot(pMan->pConst1);
+ for ( i = 0; i < vPairs->nSize; i += 2 )
+ {
+ pXor = Abc_AigXor( pMan, vPairs->pArray[i], vPairs->pArray[i+1] );
+ pMiter = Abc_AigOr( pMan, pMiter, pXor );
+ }
+ return pMiter;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if the node has at least one complemented fanout.]
+
+ Description [A fanout is complemented if the fanout's fanin edge pointing
+ to the given node is complemented.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_AigNodeIsUsedCompl( Abc_Obj_t * pNode )
+{
+ Abc_Obj_t * pFanout;
+ int i, iFanin;
+ Abc_ObjForEachFanout( pNode, pFanout, i )
+ {
+ iFanin = Vec_FanFindEntry( &pFanout->vFanins, pNode->Id );
+ assert( iFanin >= 0 );
+ if ( Abc_ObjFaninC( pFanout, iFanin ) )
+ return 1;
+ }
+ return 0;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_AigResize( Abc_Aig_t * pMan )
+{
+ Abc_Obj_t ** pBinsNew;
+ Abc_Obj_t * pEnt, * pEnt2;
+ int nBinsNew, Counter, i, clk;
+ unsigned Key;
+
+clk = clock();
+ // get the new table size
+ nBinsNew = Cudd_PrimeCopy(2 * pMan->nBins);
+ // allocate a new array
+ pBinsNew = ALLOC( Abc_Obj_t *, nBinsNew );
+ memset( pBinsNew, 0, sizeof(Abc_Obj_t *) * nBinsNew );
+ // rehash the entries from the old table
+ Counter = 0;
+ for ( i = 0; i < pMan->nBins; i++ )
+ Abc_AigBinForEachEntrySafe( pMan->pBins[i], pEnt, pEnt2 )
+ {
+ Key = Abc_HashKey2( Abc_ObjFanin(pEnt,0), Abc_ObjFanin(pEnt,1), nBinsNew );
+ pEnt->pNext = pBinsNew[Key];
+ pBinsNew[Key] = pEnt;
+ Counter++;
+ }
+ assert( Counter == pMan->nEntries );
+// printf( "Increasing the structural table size from %6d to %6d. ", pMan->nBins, nBinsNew );
+// PRT( "Time", clock() - clk );
+ // replace the table and the parameters
+ free( pMan->pBins );
+ pMan->pBins = pBinsNew;
+ pMan->nBins = nBinsNew;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcAttach.c b/src/base/abc/abcAttach.c
new file mode 100644
index 00000000..9d9c378f
--- /dev/null
+++ b/src/base/abc/abcAttach.c
@@ -0,0 +1,396 @@
+/**CFile****************************************************************
+
+ FileName [abcAttach.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Attaches the library gates to the current network.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcAttach.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+#include "main.h"
+#include "mio.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+#define ATTACH_FULL (~((unsigned)0))
+#define ATTACH_MASK(n) ((~((unsigned)0)) >> (32-(n)))
+
+static void Abc_AttachSetupTruthTables( unsigned uTruths[][2] );
+static void Abc_AttachComputeTruth( char * pSop, unsigned uTruthsIn[][2], unsigned * uTruthNode );
+static Mio_Gate_t * Abc_AttachFind( Mio_Gate_t ** ppGates, unsigned ** puTruthGates, int nGates, unsigned * uTruthNode, int * Perm );
+static int Abc_AttachCompare( unsigned ** puTruthGates, int nGates, unsigned * uTruthNode );
+static int Abc_NodeAttach( Abc_Obj_t * pNode, Mio_Gate_t ** ppGates, unsigned ** puTruthGates, int nGates, unsigned uTruths[][2] );
+static void Abc_TruthPermute( char * pPerm, int nVars, unsigned * uTruthNode, unsigned * uTruthPerm );
+
+static char ** s_pPerms = NULL;
+static int s_nPerms;
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Attaches gates from the current library to the internal nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkAttach( Abc_Ntk_t * pNtk )
+{
+ int fCheck = 1;
+ Mio_Library_t * pGenlib;
+ unsigned ** puTruthGates;
+ unsigned uTruths[6][2];
+ Abc_Obj_t * pNode;
+ Mio_Gate_t ** ppGates;
+ int nGates, nFanins, i;
+
+ assert( Abc_NtkIsLogicSop(pNtk) );
+
+ // check that the library is available
+ pGenlib = Abc_FrameReadLibGen(Abc_FrameGetGlobalFrame());
+ if ( pGenlib == NULL )
+ {
+ printf( "The current library is not available.\n" );
+ return 0;
+ }
+
+ // start the truth tables
+ Abc_AttachSetupTruthTables( uTruths );
+
+ // collect all the gates
+ ppGates = Mio_CollectRoots( pGenlib, 6, (float)1.0e+20, 1, &nGates );
+
+ // derive the gate truth tables
+ puTruthGates = ALLOC( unsigned *, nGates );
+ puTruthGates[0] = ALLOC( unsigned, 2 * nGates );
+ for ( i = 1; i < nGates; i++ )
+ puTruthGates[i] = puTruthGates[i-1] + 2;
+ for ( i = 0; i < nGates; i++ )
+ Mio_DeriveTruthTable( ppGates[i], uTruths, Mio_GateReadInputs(ppGates[i]), 6, puTruthGates[i] );
+
+ // assign the gates to pNode->pCopy
+ Abc_NtkCleanCopy( pNtk );
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ nFanins = Abc_ObjFaninNum(pNode);
+ if ( nFanins == 0 )
+ {
+ if ( Abc_SopIsConst1(pNode->pData) )
+ pNode->pCopy = (Abc_Obj_t *)Mio_LibraryReadConst1(pGenlib);
+ else
+ pNode->pCopy = (Abc_Obj_t *)Mio_LibraryReadConst0(pGenlib);
+ }
+ else if ( nFanins == 1 )
+ {
+ if ( Abc_SopIsBuf(pNode->pData) )
+ pNode->pCopy = (Abc_Obj_t *)Mio_LibraryReadBuf(pGenlib);
+ else
+ pNode->pCopy = (Abc_Obj_t *)Mio_LibraryReadInv(pGenlib);
+ }
+ else if ( nFanins > 6 )
+ {
+ printf( "Cannot attach gate with more than 6 inputs to node %s.\n", Abc_ObjName(pNode) );
+ free( puTruthGates[0] );
+ free( puTruthGates );
+ free( ppGates );
+ return 0;
+ }
+ else if ( !Abc_NodeAttach( pNode, ppGates, puTruthGates, nGates, uTruths ) )
+ {
+ printf( "Could not attach the library gate to node %s.\n", Abc_ObjName(pNode) );
+ free( puTruthGates[0] );
+ free( puTruthGates );
+ free( ppGates );
+ return 0;
+ }
+ }
+ free( puTruthGates[0] );
+ free( puTruthGates );
+ free( ppGates );
+ FREE( s_pPerms );
+
+ // perform the final transformation
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ if ( pNode->pCopy == NULL )
+ {
+ printf( "Some elementary gates (constant, buffer, or inverter) are missing in the library.\n" );
+ return 0;
+ }
+ }
+
+ // replace SOP representation by the gate representation
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ pNode->pData = pNode->pCopy, pNode->pCopy = NULL;
+ pNtk->Type = ABC_NTK_LOGIC_MAP;
+ Extra_MmFlexStop( pNtk->pManFunc, 0 );
+ pNtk->pManFunc = NULL;
+
+ printf( "Library gates are successfully attached to the nodes.\n" );
+
+ // make sure that everything is okay
+ if ( fCheck && !Abc_NtkCheck( pNtk ) )
+ {
+ printf( "Abc_NtkAttach: The network check has failed.\n" );
+ return 0;
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NodeAttach( Abc_Obj_t * pNode, Mio_Gate_t ** ppGates, unsigned ** puTruthGates, int nGates, unsigned uTruths[][2] )
+{
+ int Perm[10];
+ int pTempInts[10];
+ unsigned uTruthNode[2];
+ Abc_Obj_t * pFanin;
+ Mio_Gate_t * pGate;
+ int nFanins, i;
+
+ // compute the node's truth table
+ Abc_AttachComputeTruth( pNode->pData, uTruths, uTruthNode );
+ // find the matching gate and permutation
+ pGate = Abc_AttachFind( ppGates, puTruthGates, nGates, uTruthNode, Perm );
+ if ( pGate == NULL )
+ return 0;
+ // permute the fanins
+ nFanins = Abc_ObjFaninNum(pNode);
+ Abc_ObjForEachFanin( pNode, pFanin, i )
+ pTempInts[i] = pFanin->Id;
+ for ( i = 0; i < nFanins; i++ )
+ pNode->vFanins.pArray[Perm[i]].iFan = pTempInts[i];
+ // set the gate
+ pNode->pCopy = (Abc_Obj_t *)pGate;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets up the truth tables.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_AttachSetupTruthTables( unsigned uTruths[][2] )
+{
+ int m, v;
+ for ( v = 0; v < 5; v++ )
+ uTruths[v][0] = 0;
+ // set up the truth tables
+ for ( m = 0; m < 32; m++ )
+ for ( v = 0; v < 5; v++ )
+ if ( m & (1 << v) )
+ uTruths[v][0] |= (1 << m);
+ // make adjustments for the case of 6 variables
+ for ( v = 0; v < 5; v++ )
+ uTruths[v][1] = uTruths[v][0];
+ uTruths[5][0] = 0;
+ uTruths[5][1] = ATTACH_FULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compute the truth table of the node's cover.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_AttachComputeTruth( char * pSop, unsigned uTruthsIn[][2], unsigned * uTruthRes )
+{
+// Mvc_Cube_t * pCube;
+ unsigned uSignCube[2];
+ int Value;
+// int nInputs = pCover->nBits/2;
+ int nInputs = 6;
+ int nFanins = Abc_SopGetVarNum(pSop);
+ char * pCube;
+ int k;
+
+ // make sure that the number of input truth tables in equal to the number of gate inputs
+ assert( nInputs < 7 );
+
+ // clean the resulting truth table
+ uTruthRes[0] = 0;
+ uTruthRes[1] = 0;
+ if ( nInputs < 6 )
+ {
+ // consider the case when only one unsigned can be used
+// Mvc_CoverForEachCube( pCover, pCube )
+ Abc_SopForEachCube( pSop, nFanins, pCube )
+ {
+ uSignCube[0] = ATTACH_FULL;
+// Mvc_CubeForEachVarValue( pCover, pCube, Var, Value )
+ Abc_CubeForEachVar( pCube, Value, k )
+ {
+ if ( Value == '0' )
+ uSignCube[0] &= ~uTruthsIn[k][0];
+ else if ( Value == '1' )
+ uSignCube[0] &= uTruthsIn[k][0];
+ }
+ uTruthRes[0] |= uSignCube[0];
+ }
+ if ( nInputs < 5 )
+ uTruthRes[0] &= ATTACH_MASK(1<<nInputs);
+ }
+ else
+ {
+ // consider the case when two unsigneds should be used
+// Mvc_CoverForEachCube( pCover, pCube )
+ Abc_SopForEachCube( pSop, nFanins, pCube )
+ {
+ uSignCube[0] = ATTACH_FULL;
+ uSignCube[1] = ATTACH_FULL;
+// Mvc_CubeForEachVarValue( pCover, pCube, Var, Value )
+ Abc_CubeForEachVar( pCube, Value, k )
+ {
+ if ( Value == '0' )
+ {
+ uSignCube[0] &= ~uTruthsIn[k][0];
+ uSignCube[1] &= ~uTruthsIn[k][1];
+ }
+ else if ( Value == '1' )
+ {
+ uSignCube[0] &= uTruthsIn[k][0];
+ uSignCube[1] &= uTruthsIn[k][1];
+ }
+ }
+ uTruthRes[0] |= uSignCube[0];
+ uTruthRes[1] |= uSignCube[1];
+ }
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Find the gate by truth table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mio_Gate_t * Abc_AttachFind( Mio_Gate_t ** ppGates, unsigned ** puTruthGates, int nGates, unsigned * uTruthNode, int * Perm )
+{
+ unsigned uTruthPerm[2];
+ int i, v, iNum;
+
+ // try the gates without permutation
+ if ( (iNum = Abc_AttachCompare( puTruthGates, nGates, uTruthNode )) >= 0 )
+ {
+ for ( v = 0; v < 6; v++ )
+ Perm[v] = v;
+ return ppGates[iNum];
+ }
+ // get permutations
+ if ( s_pPerms == NULL )
+ {
+ s_pPerms = Extra_Permutations( 6 );
+ s_nPerms = Extra_Factorial( 6 );
+ }
+ // try permutations
+ for ( i = 0; i < s_nPerms; i++ )
+ {
+ Abc_TruthPermute( s_pPerms[i], 6, uTruthNode, uTruthPerm );
+ if ( (iNum = Abc_AttachCompare( puTruthGates, nGates, uTruthPerm )) >= 0 )
+ {
+ for ( v = 0; v < 6; v++ )
+ Perm[v] = (int)s_pPerms[i][v];
+ return ppGates[iNum];
+ }
+ }
+ return NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Find the gate by truth table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_AttachCompare( unsigned ** puTruthGates, int nGates, unsigned * uTruthNode )
+{
+ int i;
+ for ( i = 0; i < nGates; i++ )
+ if ( puTruthGates[i][0] == uTruthNode[0] && puTruthGates[i][1] == uTruthNode[1] )
+ return i;
+ return -1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Permutes the 6-input truth table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_TruthPermute( char * pPerm, int nVars, unsigned * uTruthNode, unsigned * uTruthPerm )
+{
+ int nMints, iMintPerm, iMint, v;
+ uTruthPerm[0] = uTruthPerm[1] = 0;
+ nMints = (1 << nVars);
+ for ( iMint = 0; iMint < nMints; iMint++ )
+ {
+ if ( (uTruthNode[iMint/32] & (1 << (iMint%32))) == 0 )
+ continue;
+ iMintPerm = 0;
+ for ( v = 0; v < nVars; v++ )
+ if ( iMint & (1 << v) )
+ iMintPerm |= (1 << pPerm[v]);
+ uTruthPerm[iMintPerm/32] |= (1 << (iMintPerm%32));
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcCheck.c b/src/base/abc/abcCheck.c
new file mode 100644
index 00000000..67cfe9df
--- /dev/null
+++ b/src/base/abc/abcCheck.c
@@ -0,0 +1,848 @@
+/**CFile****************************************************************
+
+ FileName [abcCheck.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Consistency checking procedures.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcCheck.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static bool Abc_NtkCheckNames( Abc_Ntk_t * pNtk );
+static bool Abc_NtkCheckPis( Abc_Ntk_t * pNtk );
+static bool Abc_NtkCheckPos( Abc_Ntk_t * pNtk );
+static bool Abc_NtkCheckObj( Abc_Ntk_t * pNtk, Abc_Obj_t * pObj );
+static bool Abc_NtkCheckNet( Abc_Ntk_t * pNtk, Abc_Obj_t * pNet );
+static bool Abc_NtkCheckNode( Abc_Ntk_t * pNtk, Abc_Obj_t * pNode );
+static bool Abc_NtkCheckLatch( Abc_Ntk_t * pNtk, Abc_Obj_t * pLatch );
+
+static bool Abc_NtkComparePis( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int fComb );
+static bool Abc_NtkComparePos( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int fComb );
+static bool Abc_NtkCompareLatches( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int fComb );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Checks the integrity of the network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkCheck( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pObj, * pNet, * pNode;
+ int i;
+
+ if ( !Abc_NtkIsNetlist(pNtk) && !Abc_NtkIsAig(pNtk) && !Abc_NtkIsLogic(pNtk) )
+ {
+ fprintf( stdout, "NetworkCheck: Unknown network type.\n" );
+ return 0;
+ }
+
+ // check the names
+ if ( !Abc_NtkCheckNames( pNtk ) )
+ return 0;
+
+ // check PIs and POs
+ Abc_NtkCleanCopy( pNtk );
+ if ( !Abc_NtkCheckPis( pNtk ) )
+ return 0;
+ if ( !Abc_NtkCheckPos( pNtk ) )
+ return 0;
+
+ // check the connectivity of objects
+ Abc_NtkForEachObj( pNtk, pObj, i )
+ if ( !Abc_NtkCheckObj( pNtk, pObj ) )
+ return 0;
+
+ // if it is a netlist change nets and latches
+ if ( Abc_NtkIsNetlist(pNtk) )
+ {
+ // check the nets
+ Abc_NtkForEachNet( pNtk, pNet, i )
+ if ( !Abc_NtkCheckNet( pNtk, pNet ) )
+ return 0;
+ }
+
+ // check the nodes
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ if ( !Abc_NtkCheckNode( pNtk, pNode ) )
+ return 0;
+ // check the latches
+ Abc_NtkForEachLatch( pNtk, pNode, i )
+ if ( !Abc_NtkCheckLatch( pNtk, pNode ) )
+ return 0;
+
+ // finally, check for combinational loops
+// clk = clock();
+ if ( !Abc_NtkIsAcyclic( pNtk ) )
+ {
+ fprintf( stdout, "NetworkCheck: Network contains a combinational loop.\n" );
+ return 0;
+ }
+// PRT( "Acyclic ", clock() - clk );
+
+ // check the EXDC network if present
+ if ( pNtk->pExdc )
+ {
+ if ( pNtk->Type != pNtk->pExdc->Type )
+ {
+ fprintf( stdout, "NetworkCheck: Network and its EXDC have different types.\n" );
+ return 0;
+ }
+ return Abc_NtkCheck( pNtk->pExdc );
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks the names.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkCheckNames( Abc_Ntk_t * pNtk )
+{
+ stmm_generator * gen;
+ Abc_Obj_t * pNet, * pNet2;
+ char * pName;
+ int i;
+
+ if ( Abc_NtkIsNetlist(pNtk) )
+ {
+ // check that the nets in the table are also in the network
+ stmm_foreach_item( pNtk->tName2Net, gen, &pName, (char**)&pNet )
+ {
+ if ( pNet->pData != pName )
+ {
+ fprintf( stdout, "NetworkCheck: Net \"%s\" has different name compared to the one in the name table.\n", pNet->pData );
+ return 0;
+ }
+ }
+ // check that the nets with names are also in the table
+ Abc_NtkForEachNet( pNtk, pNet, i )
+ {
+ if ( pNet->pData && !stmm_lookup( pNtk->tName2Net, pNet->pData, (char**)&pNet2 ) )
+ {
+ fprintf( stdout, "NetworkCheck: Net \"%s\" is in the network but not in the name table.\n", pNet->pData );
+ return 0;
+ }
+ }
+ }
+ else
+ {
+ if ( pNtk->vPis->nSize != pNtk->nPis + pNtk->nLatches )
+ {
+ fprintf( stdout, "NetworkCheck: Incorrect size of the PI array.\n" );
+ return 0;
+ }
+ if ( pNtk->vPos->nSize != pNtk->nPos + pNtk->nLatches )
+ {
+ fprintf( stdout, "NetworkCheck: Incorrect size of the PO array.\n" );
+ return 0;
+ }
+ if ( pNtk->vLatches->nSize != pNtk->nLatches )
+ {
+ fprintf( stdout, "NetworkCheck: Incorrect size of the latch array.\n" );
+ return 0;
+ }
+
+ if ( pNtk->vNamesPi->nSize != pNtk->vPis->nSize )
+ {
+ fprintf( stdout, "NetworkCheck: Incorrect size of the PI names array.\n" );
+ return 0;
+ }
+ if ( pNtk->vNamesPo->nSize != pNtk->vPos->nSize )
+ {
+ fprintf( stdout, "NetworkCheck: Incorrect size of the PO names array.\n" );
+ return 0;
+ }
+ if ( pNtk->vNamesLatch->nSize != pNtk->vLatches->nSize )
+ {
+ fprintf( stdout, "NetworkCheck: Incorrect size of the latch names array.\n" );
+ return 0;
+ }
+
+ /*
+ Abc_Obj_t * pNode, * pNode2;
+ Abc_NtkForEachPi( pNtk, pNode, i )
+ {
+ if ( !stmm_lookup( pNtk->tName2Net, Abc_NtkNamePi(pNtk,i), (char**)&pNode2 ) )
+ {
+ fprintf( stdout, "NetworkCheck: PI \"%s\" is in the network but not in the name table.\n", Abc_NtkNamePi(pNtk,i) );
+ return 0;
+ }
+ if ( pNode != pNode2 )
+ {
+ fprintf( stdout, "NetworkCheck: PI \"%s\" has a different pointer in the name table.\n", Abc_NtkNamePi(pNtk,i) );
+ return 0;
+ }
+ }
+ Abc_NtkForEachPo( pNtk, pNode, i )
+ {
+ if ( !stmm_lookup( pNtk->tName2Net, Abc_NtkNamePo(pNtk,i), (char**)&pNode2 ) )
+ {
+ fprintf( stdout, "NetworkCheck: PO \"%s\" is in the network but not in the name table.\n", Abc_NtkNamePo(pNtk,i) );
+ return 0;
+ }
+ if ( pNode != pNode2 )
+ {
+ fprintf( stdout, "NetworkCheck: PO \"%s\" has a different pointer in the name table.\n", Abc_NtkNamePo(pNtk,i) );
+ return 0;
+ }
+ }
+ Abc_NtkForEachLatch( pNtk, pNode, i )
+ {
+ if ( !stmm_lookup( pNtk->tName2Net, Abc_NtkNameLatch(pNtk,i), (char**)&pNode2 ) )
+ {
+ fprintf( stdout, "NetworkCheck: Latch \"%s\" is in the network but not in the name table.\n", Abc_NtkNameLatch(pNtk,i) );
+ return 0;
+ }
+ if ( pNode != pNode2 )
+ {
+ fprintf( stdout, "NetworkCheck: Latch \"%s\" has a different pointer in the name table.\n", Abc_NtkNameLatch(pNtk,i) );
+ return 0;
+ }
+ }
+ */
+ }
+ return 1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Checks the PIs of the network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkCheckPis( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pObj;
+ int i;
+
+ // check that PIs are indeed PIs
+ Abc_NtkForEachPi( pNtk, pObj, i )
+ {
+ if ( Abc_NtkIsNetlist(pNtk) )
+ {
+ if ( !Abc_ObjIsNet(pObj) )
+ {
+ fprintf( stdout, "NetworkCheck: A PI \"%s\" is not a net.\n", Abc_ObjName(pObj) );
+ return 0;
+ }
+ }
+ else
+ {
+ if ( !Abc_ObjIsTerm(pObj) )
+ {
+ fprintf( stdout, "NetworkCheck: A PI \"%s\" is not a terminal node.\n", Abc_ObjName(pObj) );
+ return 0;
+ }
+ if ( pObj->pData )
+ {
+ fprintf( stdout, "NetworkCheck: A PI \"%s\" has a logic function.\n", Abc_ObjName(pObj) );
+ return 0;
+ }
+ }
+ if ( !Abc_ObjIsPi(pObj) )
+ {
+ fprintf( stdout, "NetworkCheck: Object \"%s\" (id=%d) is in the PI list but is not a PI.\n", Abc_ObjName(pObj), pObj->Id );
+ return 0;
+ }
+ pObj->pCopy = (Abc_Obj_t *)1;
+ }
+ Abc_NtkForEachObj( pNtk, pObj, i )
+ {
+ if ( pObj->pCopy == NULL && Abc_ObjIsPi(pObj) )
+ {
+ fprintf( stdout, "NetworkCheck: Object \"%s\" (id=%d) is a PI but is not in the PI list.\n", Abc_ObjName(pObj), pObj->Id );
+ return 0;
+ }
+ pObj->pCopy = NULL;
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks the POs of the network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkCheckPos( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pObj;
+ int i;
+
+ // check that POs are indeed POs
+ Abc_NtkForEachPo( pNtk, pObj, i )
+ {
+ if ( Abc_NtkIsNetlist(pNtk) )
+ {
+ if ( !Abc_ObjIsNet(pObj) )
+ {
+ fprintf( stdout, "NetworkCheck: A PO \"%s\" is not a net.\n", Abc_ObjName(pObj) );
+ return 0;
+ }
+ }
+ else
+ {
+ if ( !Abc_ObjIsTerm(pObj) )
+ {
+ fprintf( stdout, "NetworkCheck: A PO \"%s\" is not a terminal node.\n", Abc_ObjName(pObj) );
+ return 0;
+ }
+ if ( pObj->pData )
+ {
+ fprintf( stdout, "NetworkCheck: A PO \"%s\" has a logic function.\n", Abc_ObjName(pObj) );
+ return 0;
+ }
+ }
+ if ( !Abc_ObjIsPo(pObj) )
+ {
+ fprintf( stdout, "NetworkCheck: Net \"%s\" (id=%d) is in the PO list but is not a PO.\n", Abc_ObjName(pObj), pObj->Id );
+ return 0;
+ }
+ pObj->pCopy = (Abc_Obj_t *)1;
+ }
+ Abc_NtkForEachObj( pNtk, pObj, i )
+ {
+ if ( pObj->pCopy == NULL && Abc_ObjIsPo(pObj) )
+ {
+ fprintf( stdout, "NetworkCheck: Net \"%s\" (id=%d) is in a PO but is not in the PO list.\n", Abc_ObjName(pObj), pObj->Id );
+ return 0;
+ }
+ pObj->pCopy = NULL;
+ }
+ return 1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Checks the connectivity of the object.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkCheckObj( Abc_Ntk_t * pNtk, Abc_Obj_t * pObj )
+{
+ Abc_Obj_t * pFanin, * pFanout;
+ int i, Value = 1;
+
+ // check the network
+ if ( pObj->pNtk != pNtk )
+ {
+ fprintf( stdout, "NetworkCheck: Object \"%s\" does not belong to the network.\n", Abc_ObjName(pObj) );
+ return 0;
+ }
+ // the object cannot be a net if it is not a netlist
+ if ( Abc_ObjIsNet(pObj) && !Abc_NtkIsNetlist(pNtk) )
+ {
+ fprintf( stdout, "NetworkCheck: Object \"%s\" is a net but the network is not a netlist.\n", Abc_ObjName(pObj) );
+ return 0;
+ }
+ // check the object ID
+ if ( pObj->Id < 0 || (int)pObj->Id > pNtk->vObjs->nSize )
+ {
+ fprintf( stdout, "NetworkCheck: Object \"%s\" has incorrect ID.\n", Abc_ObjName(pObj) );
+ return 0;
+ }
+ // a PI has no fanins
+ if ( Abc_ObjIsPi(pObj) && Abc_ObjFaninNum(pObj) > 0 )
+ {
+ fprintf( stdout, "PI \"%s\" has fanins.\n", Abc_ObjName(pObj) );
+ return 0;
+ }
+ // detect internal nets that are not driven
+ if ( !Abc_ObjIsPi(pObj) && Abc_ObjFaninNum(pObj) == 0 && Abc_ObjIsNet(pObj) )
+ {
+ fprintf( stdout, "Net \"%s\" is not driven.\n", Abc_ObjName(pObj) );
+ return 0;
+ }
+ // go through the fanins of the object and make sure fanins have this object as a fanout
+ Abc_ObjForEachFanin( pObj, pFanin, i )
+ {
+ if ( Vec_FanFindEntry( &pFanin->vFanouts, pObj->Id ) == -1 )
+ {
+ fprintf( stdout, "NodeCheck: Object \"%s\" has fanin ", Abc_ObjName(pObj) );
+ fprintf( stdout, "\"%s\" but the fanin does not have it as a fanout.\n", Abc_ObjName(pFanin) );
+ Value = 0;
+ }
+ }
+ // go through the fanouts of the object and make sure fanouts have this object as a fanin
+ Abc_ObjForEachFanout( pObj, pFanout, i )
+ {
+ if ( Vec_FanFindEntry( &pFanout->vFanins, pObj->Id ) == -1 )
+ {
+ fprintf( stdout, "NodeCheck: Object \"%s\" has fanout ", Abc_ObjName(pObj) );
+ fprintf( stdout, "\"%s\" but the fanout does not have it as a fanin.\n", Abc_ObjName(pFanout) );
+ Value = 0;
+ }
+ }
+ return Value;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks the integrity of a net.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkCheckNet( Abc_Ntk_t * pNtk, Abc_Obj_t * pNet )
+{
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks the integrity of a node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkCheckNode( Abc_Ntk_t * pNtk, Abc_Obj_t * pNode )
+{
+ // the node should have a function assigned unless it is an AIG
+ if ( pNode->pData == NULL && !Abc_NtkIsAig(pNtk) )
+ {
+ fprintf( stdout, "NodeCheck: An internal node \"%s\" has no logic function.\n", Abc_ObjName(pNode) );
+ return 0;
+ }
+
+ // the netlist and SOP logic network should have SOPs
+ if ( Abc_NtkIsNetlist(pNtk) || Abc_NtkIsLogicSop(pNtk) )
+ {
+ if ( !Abc_SopCheck( pNode->pData, Abc_ObjFaninNum(pNode) ) )
+ {
+ fprintf( stdout, "NodeCheck: SOP check for node \"%s\" has failed.\n", Abc_ObjName(pNode) );
+ return 0;
+ }
+ }
+ else if ( Abc_NtkIsLogicBdd(pNtk) )
+ {
+ int nSuppSize = Cudd_SupportSize(pNtk->pManFunc, pNode->pData);
+ if ( nSuppSize > Abc_ObjFaninNum(pNode) )
+ {
+ fprintf( stdout, "NodeCheck: BDD of the node \"%s\" has incorrect support size.\n", Abc_ObjName(pNode) );
+ return 0;
+ }
+ }
+ else if ( !Abc_NtkIsAig(pNtk) && !Abc_NtkIsLogicMap(pNtk) )
+ {
+ assert( 0 );
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks the integrity of a latch.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkCheckLatch( Abc_Ntk_t * pNtk, Abc_Obj_t * pLatch )
+{
+ Abc_Obj_t * pObj;
+ int Value = 1;
+ // check whether the object is a latch
+ if ( !Abc_ObjIsLatch(pLatch) )
+ {
+ fprintf( stdout, "NodeCheck: Latch \"%s\" is in a latch list but has not latch label.\n", Abc_ObjName(pLatch) );
+ Value = 0;
+ }
+ // make sure the latch has a reasonable return value
+ if ( (int)pLatch->pData < 0 || (int)pLatch->pData > 2 )
+ {
+ fprintf( stdout, "NodeCheck: Latch \"%s\" has incorrect reset value (%d).\n",
+ Abc_ObjName(pLatch), (int)pLatch->pData );
+ Value = 0;
+ }
+ // make sure the latch has only one fanin
+ if ( Abc_ObjFaninNum(pLatch) != 1 )
+ {
+ fprintf( stdout, "NodeCheck: Latch \"%s\" has wrong number (%d) of fanins.\n", Abc_ObjName(pLatch), Abc_ObjFaninNum(pLatch) );
+ Value = 0;
+ }
+ // make sure the latch has fanins and fanouts that are labeled accordingly
+ if ( Abc_NtkIsNetlist(pNtk) )
+ {
+ pObj = Abc_ObjFanin0( pLatch );
+ if ( !Abc_ObjIsLi(pObj) )
+ {
+ fprintf( stdout, "NodeCheck: Latch \"%s\" has a fanin that is not labeled as LI.\n", Abc_ObjName(pLatch) );
+ Value = 0;
+ }
+ pObj = Abc_ObjFanout0( pLatch );
+ if ( !Abc_ObjIsLo(pObj) )
+ {
+ fprintf( stdout, "NodeCheck: Latch \"%s\" has a fanout that is not labeled as LO.\n", Abc_ObjName(pLatch) );
+ Value = 0;
+ }
+ }
+ return Value;
+}
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Compares the PIs of the two networks.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkComparePis( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int fComb )
+{
+ Abc_Obj_t * pNode1;
+ int i;
+ if ( Abc_NtkPiNum(pNtk1) != Abc_NtkPiNum(pNtk2) )
+ {
+ printf( "Networks have different number of primary inputs.\n" );
+ return 0;
+ }
+ // for each PI of pNet1 find corresponding PI of pNet2 and reorder them
+ Abc_NtkForEachPi( pNtk1, pNode1, i )
+ {
+ if ( strcmp( Abc_NtkNamePi(pNtk1,i), Abc_NtkNamePi(pNtk2,i) ) != 0 )
+ {
+ printf( "Primary input #%d is different in network 1 ( \"%s\") and in network 2 (\"%s\").\n",
+ i, Abc_NtkNamePi(pNtk1,i), Abc_NtkNamePi(pNtk2,i) );
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares the POs of the two networks.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkComparePos( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int fComb )
+{
+ Abc_Obj_t * pNode1;
+ int i;
+ if ( Abc_NtkPoNum(pNtk1) != Abc_NtkPoNum(pNtk2) )
+ {
+ printf( "Networks have different number of primary outputs.\n" );
+ return 0;
+ }
+ // for each PI of pNet1 find corresponding PI of pNet2 and reorder them
+ Abc_NtkForEachPo( pNtk1, pNode1, i )
+ {
+ if ( strcmp( Abc_NtkNamePo(pNtk1,i), Abc_NtkNamePo(pNtk2,i) ) != 0 )
+ {
+ printf( "Primary output #%d is different in network 1 ( \"%s\") and in network 2 (\"%s\").\n",
+ i, Abc_NtkNamePo(pNtk1,i), Abc_NtkNamePo(pNtk2,i) );
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares the latches of the two networks.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkCompareLatches( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int fComb )
+{
+ Abc_Obj_t * pNode1;
+ int i;
+ if ( !fComb )
+ return 1;
+ if ( Abc_NtkLatchNum(pNtk1) != Abc_NtkLatchNum(pNtk2) )
+ {
+ printf( "Networks have different number of latches.\n" );
+ return 0;
+ }
+ // for each PI of pNet1 find corresponding PI of pNet2 and reorder them
+ Abc_NtkForEachLatch( pNtk1, pNode1, i )
+ {
+ if ( strcmp( Abc_NtkNameLatch(pNtk1,i), Abc_NtkNameLatch(pNtk2,i) ) != 0 )
+ {
+ printf( "Latch #%d is different in network 1 ( \"%s\") and in network 2 (\"%s\").\n",
+ i, Abc_NtkNameLatch(pNtk1,i), Abc_NtkNameLatch(pNtk2,i) );
+ return 0;
+ }
+ }
+ return 1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Compares the PIs of the two networks.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkComparePis2( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int fComb )
+{
+ Abc_Obj_t * pNode1, * pNode2;
+ Vec_Ptr_t * vNodesNew, * vNamesNew;
+ stmm_table * tNames;
+ int i;
+
+ if ( Abc_NtkPiNum(pNtk1) != Abc_NtkPiNum(pNtk2) )
+ {
+ printf( "Networks have different number of primary inputs.\n" );
+ return 0;
+ }
+
+ // for each PI of pNet1 find corresponding PI of pNet2 and reorder them
+ vNodesNew = Vec_PtrAlloc( 100 );
+ vNamesNew = Vec_PtrAlloc( 100 );
+ tNames = Abc_NtkLogicHashNames( pNtk2, 0, fComb );
+ Abc_NtkForEachCi( pNtk1, pNode1, i )
+ {
+ if ( stmm_lookup( tNames, Abc_NtkNamePi(pNtk1,i), (char **)&pNode2 ) )
+ {
+ Vec_PtrPush( vNodesNew, pNode2 );
+ Vec_PtrPush( vNamesNew, pNode2->pCopy );
+ }
+ else
+ {
+ printf( "Primary input \"%s\" of network 1 is not in network 2.\n", pNtk1->vNamesPi->pArray[i] );
+ Vec_PtrFree( vNodesNew );
+ Vec_PtrFree( vNamesNew );
+ return 0;
+ }
+ if ( !fComb && i == Abc_NtkPiNum(pNtk2)-1 )
+ break;
+ }
+ stmm_free_table( tNames );
+ // add latches to the PI/PO lists to work as CIs/COs
+ if ( !fComb )
+ {
+ Abc_NtkForEachLatch( pNtk2, pNode2, i )
+ {
+ Vec_PtrPush( vNodesNew, pNode2 );
+ Vec_PtrPush( vNamesNew, Abc_NtkNameLatch(pNtk2,i) );
+ }
+ }
+ Vec_PtrFree( pNtk2->vPis ); pNtk2->vPis = vNodesNew; vNodesNew = NULL;
+ Vec_PtrFree( pNtk2->vNamesPi ); pNtk2->vNamesPi = vNamesNew; vNamesNew = NULL;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares the POs of the two networks.]
+
+ Description [If the flag is 1, compares the first n POs of pNet1, where
+ n is the number of POs in pNet2.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkComparePos2( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int fComb )
+{
+ Abc_Obj_t * pNode1, * pNode2;
+ Vec_Ptr_t * vNodesNew, * vNamesNew;
+ stmm_table * tNames;
+ int i;
+
+ if ( Abc_NtkPoNum(pNtk1) != Abc_NtkPoNum(pNtk2) )
+ {
+ printf( "Networks have different number of primary outputs.\n" );
+ return 0;
+ }
+
+ // for each PO of pNet1 find corresponding PO of pNet2 and reorder them
+ vNodesNew = Vec_PtrAlloc( 100 );
+ vNamesNew = Vec_PtrAlloc( 100 );
+ tNames = Abc_NtkLogicHashNames( pNtk2, 1, fComb );
+ Abc_NtkForEachCo( pNtk1, pNode1, i )
+ {
+ if ( stmm_lookup( tNames, Abc_NtkNamePo(pNtk1,i), (char **)&pNode2 ) )
+ {
+ Vec_PtrPush( vNodesNew, pNode2 );
+ Vec_PtrPush( vNamesNew, pNode2->pCopy );
+ }
+ else
+ {
+ printf( "Primary output \"%s\" of network 1 is not in network 2.\n", pNtk1->vNamesPo->pArray[i] );
+ Vec_PtrFree( vNodesNew );
+ Vec_PtrFree( vNamesNew );
+ return 0;
+ }
+ if ( !fComb && i == Abc_NtkPoNum(pNtk2)-1 )
+ break;
+ }
+ stmm_free_table( tNames );
+ // add latches to the PI/PO lists to work as CIs/COs
+ if ( !fComb )
+ {
+ Abc_NtkForEachLatch( pNtk2, pNode2, i )
+ {
+ Vec_PtrPush( vNodesNew, pNode2 );
+ Vec_PtrPush( vNamesNew, Abc_NtkNameLatch(pNtk2,i) );
+ }
+ }
+ Vec_PtrFree( pNtk2->vPos ); pNtk2->vPos = vNodesNew; vNodesNew = NULL;
+ Vec_PtrFree( pNtk2->vNamesPo ); pNtk2->vNamesPo = vNamesNew; vNamesNew = NULL;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares the latches of the two networks.]
+
+ Description [This comparison procedure should be always called before
+ the other two.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkCompareLatches2( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int fComb )
+{
+ Abc_Obj_t * pNode1, * pNode2;
+ Vec_Ptr_t * vNodesNew, * vNamesNew;
+ stmm_table * tNames;
+ int i;
+
+ if ( !fComb )
+ return 1;
+
+ if ( Abc_NtkLatchNum(pNtk1) != Abc_NtkLatchNum(pNtk2) )
+ {
+ printf( "Networks have different number of latches.\n" );
+ return 0;
+ }
+
+ // for each latch of pNet1 find corresponding latch of pNet2 and reorder them
+ vNodesNew = Vec_PtrAlloc( 100 );
+ vNamesNew = Vec_PtrAlloc( 100 );
+ tNames = Abc_NtkLogicHashNames( pNtk2, 2, fComb );
+ Abc_NtkForEachLatch( pNtk1, pNode1, i )
+ {
+ if ( stmm_lookup( tNames, Abc_NtkNameLatch(pNtk1,i), (char **)&pNode2 ) )
+ {
+ Vec_PtrPush( vNodesNew, pNode2 );
+ Vec_PtrPush( vNamesNew, pNode2->pCopy );
+ }
+ else
+ {
+ printf( "Latch \"%s\" of network 1 is not in network 2.\n", pNtk1->vNamesLatch->pArray[i] );
+ Vec_PtrFree( vNodesNew );
+ Vec_PtrFree( vNamesNew );
+ return 0;
+ }
+ }
+ stmm_free_table( tNames );
+ Vec_PtrFree( pNtk2->vLatches ); pNtk2->vLatches = vNodesNew; vNodesNew = NULL;
+ Vec_PtrFree( pNtk2->vNamesLatch ); pNtk2->vNamesLatch = vNamesNew; vNamesNew = NULL;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares the signals of the networks.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkCompareSignals( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int fComb )
+{
+ if ( !Abc_NtkCompareLatches( pNtk1, pNtk2, fComb ) )
+ return 0;
+ if ( !Abc_NtkComparePis( pNtk1, pNtk2, fComb ) )
+ return 0;
+// if ( !Abc_NtkComparePos( pNtk1, pNtk2, fComb ) )
+// return 0;
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcCollapse.c b/src/base/abc/abcCollapse.c
new file mode 100644
index 00000000..372b1553
--- /dev/null
+++ b/src/base/abc/abcCollapse.c
@@ -0,0 +1,271 @@
+/**CFile****************************************************************
+
+ FileName [abcCollapse.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Collapsing the network into two-levels.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcCollapse.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static DdManager * Abc_NtkGlobalBdds( Abc_Ntk_t * pNtk );
+static DdNode * Abc_NtkGlobalBdds_rec( DdManager * dd, Abc_Obj_t * pNode );
+static Abc_Ntk_t * Abc_NtkFromGlobalBdds( DdManager * dd, Abc_Ntk_t * pNtk );
+static Abc_Obj_t * Abc_NodeFromGlobalBdds( Abc_Ntk_t * pNtkNew, DdManager * dd, DdNode * bFunc );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Collapses the network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Abc_NtkCollapse( Abc_Ntk_t * pNtk, int fVerbose )
+{
+ int fCheck = 1;
+ Abc_Ntk_t * pNtkNew;
+ DdManager * dd;
+
+ assert( Abc_NtkIsAig(pNtk) );
+
+ // perform FPGA mapping
+ dd = Abc_NtkGlobalBdds( pNtk );
+ if ( dd == NULL )
+ return NULL;
+ if ( fVerbose )
+ printf( "The shared BDD size is %d nodes.\n", Cudd_ReadKeys(dd) - Cudd_ReadDead(dd) );
+/*
+ {
+ Abc_Obj_t * pNode;
+ int i;
+ Abc_NtkForEachPo( pNtk, pNode, i )
+ {
+ Cudd_RecursiveDeref( dd, (DdNode *)pNode->pNext );
+ pNode->pNext = NULL;
+ }
+ Abc_NtkForEachLatch( pNtk, pNode, i )
+ {
+ Cudd_RecursiveDeref( dd, (DdNode *)pNode->pNext );
+ pNode->pNext = NULL;
+ }
+ }
+ Extra_StopManager( dd );
+ return NULL;
+*/
+
+ // transform the result of mapping into a BDD network
+ pNtkNew = Abc_NtkFromGlobalBdds( dd, pNtk );
+ if ( pNtkNew == NULL )
+ {
+ Cudd_Quit( dd );
+ return NULL;
+ }
+ Extra_StopManager( dd );
+
+ // make the network minimum base
+ Abc_NtkMinimumBase( pNtkNew );
+
+ // make sure that everything is okay
+ if ( fCheck && !Abc_NtkCheck( pNtkNew ) )
+ {
+ printf( "Abc_NtkCollapse: The network check has failed.\n" );
+ Abc_NtkDelete( pNtkNew );
+ return NULL;
+ }
+ return pNtkNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Derives global BDDs for the node function.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdManager * Abc_NtkGlobalBdds( Abc_Ntk_t * pNtk )
+{
+ ProgressBar * pProgress;
+ Abc_Obj_t * pNode;
+ DdNode * bFunc;
+ DdManager * dd;
+ int i;
+
+ // start the manager
+ dd = Cudd_Init( Abc_NtkCiNum(pNtk), 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 );
+ Cudd_AutodynEnable( dd, CUDD_REORDER_SYMM_SIFT );
+
+ // set the elementary variables
+ Abc_NtkCleanCopy( pNtk );
+ Abc_NtkForEachCi( pNtk, pNode, i )
+ pNode->pCopy = (Abc_Obj_t *)dd->vars[i];
+ // assign the constant node BDD
+ pNode = Abc_AigConst1( pNtk->pManFunc );
+ pNode->pCopy = (Abc_Obj_t *)dd->one; Cudd_Ref( dd->one );
+
+ // construct the BDDs
+ pProgress = Extra_ProgressBarStart( stdout, Abc_NtkCoNum(pNtk) );
+ Abc_NtkForEachCo( pNtk, pNode, i )
+ {
+ Extra_ProgressBarUpdate( pProgress, i, NULL );
+ bFunc = Abc_NtkGlobalBdds_rec( dd, Abc_ObjFanin0(pNode) );
+ if ( bFunc == NULL )
+ {
+ printf( "Constructing global BDDs timed out.\n" );
+ Extra_ProgressBarStop( pProgress );
+ Cudd_Quit( dd );
+ return NULL;
+ }
+ bFunc = Cudd_NotCond( bFunc, Abc_ObjFaninC0(pNode) );
+ pNode->pNext = (Abc_Obj_t *)bFunc; Cudd_Ref( bFunc );
+ }
+ Extra_ProgressBarStop( pProgress );
+
+ // derefence the intermediate BDDs
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ if ( pNode->pCopy )
+ Cudd_RecursiveDeref( dd, (DdNode *)pNode->pCopy );
+ Abc_NtkCleanCopy( pNtk );
+ // reorder one more time
+ Cudd_ReduceHeap( dd, CUDD_REORDER_SYMM_SIFT, 0 );
+ return dd;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Derives the global BDD of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Abc_NtkGlobalBdds_rec( DdManager * dd, Abc_Obj_t * pNode )
+{
+ DdNode * bFunc, * bFunc0, * bFunc1;
+ assert( !Abc_ObjIsComplement(pNode) );
+ if ( Cudd_ReadKeys(dd) > 500000 )
+ return NULL;
+ // if the result is available return
+ if ( pNode->pCopy )
+ return (DdNode *)pNode->pCopy;
+ // compute the result for both branches
+ bFunc0 = Abc_NtkGlobalBdds_rec( dd, Abc_ObjFanin(pNode,0) );
+ if ( bFunc0 == NULL )
+ return NULL;
+ Cudd_Ref( bFunc0 );
+ bFunc1 = Abc_NtkGlobalBdds_rec( dd, Abc_ObjFanin(pNode,1) );
+ if ( bFunc1 == NULL )
+ return NULL;
+ Cudd_Ref( bFunc1 );
+ bFunc0 = Cudd_NotCond( bFunc0, Abc_ObjFaninC0(pNode) );
+ bFunc1 = Cudd_NotCond( bFunc1, Abc_ObjFaninC1(pNode) );
+ // get the final result
+ bFunc = Cudd_bddAnd( dd, bFunc0, bFunc1 ); Cudd_Ref( bFunc );
+ Cudd_RecursiveDeref( dd, bFunc0 );
+ Cudd_RecursiveDeref( dd, bFunc1 );
+ // set the result
+ assert( pNode->pCopy == NULL );
+ pNode->pCopy = (Abc_Obj_t *)bFunc;
+ return bFunc;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Derives the network with the given global BDD.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Abc_NtkFromGlobalBdds( DdManager * dd, Abc_Ntk_t * pNtk )
+{
+ ProgressBar * pProgress;
+ Abc_Ntk_t * pNtkNew;
+ Abc_Obj_t * pNode, * pNodeNew;
+ int i;
+ // start the new network
+ pNtkNew = Abc_NtkStartFrom( pNtk, ABC_NTK_LOGIC_BDD );
+ // make sure the new manager has the same number of inputs
+ Cudd_bddIthVar( pNtkNew->pManFunc, dd->size-1 );
+ // process the POs
+ pProgress = Extra_ProgressBarStart( stdout, Abc_NtkCoNum(pNtk) );
+ Abc_NtkForEachCo( pNtk, pNode, i )
+ {
+ Extra_ProgressBarUpdate( pProgress, i, NULL );
+ pNodeNew = Abc_NodeFromGlobalBdds( pNtkNew, dd, (DdNode *)pNode->pNext );
+ Abc_ObjAddFanin( pNode->pCopy, pNodeNew );
+ // deref the BDD of the PO
+ Cudd_RecursiveDeref( dd, (DdNode *)pNode->pNext );
+ pNode->pNext = NULL;
+ }
+ Extra_ProgressBarStop( pProgress );
+ // transfer the names
+ Abc_NtkDupNameArrays( pNtk, pNtkNew );
+ Abc_ManTimeDup( pNtk, pNtkNew );
+ return pNtkNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Derives the network with the given global BDD.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NodeFromGlobalBdds( Abc_Ntk_t * pNtkNew, DdManager * dd, DdNode * bFunc )
+{
+ Abc_Obj_t * pNodeNew, * pTemp;
+ int i;
+ // create a new node
+ pNodeNew = Abc_NtkCreateNode( pNtkNew );
+ // add the fanins in the order, in which they appear in the reordered manager
+ Abc_NtkForEachCi( pNtkNew, pTemp, i )
+ Abc_ObjAddFanin( pNodeNew, Abc_NtkCi(pNtkNew, dd->invperm[i]) );
+ // transfer the function
+ pNodeNew->pData = Extra_TransferLevelByLevel( dd, pNtkNew->pManFunc, bFunc ); Cudd_Ref( pNodeNew->pData );
+ return pNodeNew;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcCreate.c b/src/base/abc/abcCreate.c
new file mode 100644
index 00000000..e4cfb7e3
--- /dev/null
+++ b/src/base/abc/abcCreate.c
@@ -0,0 +1,1121 @@
+/**CFile****************************************************************
+
+ FileName [abcCreate.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Creation/duplication/deletion procedures.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcCreate.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+#include "main.h"
+#include "mio.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+#define ABC_NUM_STEPS 10
+
+static Abc_Obj_t * Abc_ObjAlloc( Abc_Ntk_t * pNtk, Abc_ObjType_t Type );
+static void Abc_ObjRecycle( Abc_Obj_t * pObj );
+static void Abc_ObjAdd( Abc_Obj_t * pObj );
+
+extern void Extra_StopManager( DdManager * dd );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Creates a new Ntk.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Abc_NtkAlloc( Abc_NtkType_t Type )
+{
+ Abc_Ntk_t * pNtk;
+ pNtk = ALLOC( Abc_Ntk_t, 1 );
+ memset( pNtk, 0, sizeof(Abc_Ntk_t) );
+ pNtk->Type = Type;
+ // start the object storage
+ pNtk->vObjs = Vec_PtrAlloc( 100 );
+ pNtk->vLatches = Vec_PtrAlloc( 100 );
+ pNtk->vPis = Vec_PtrAlloc( 100 );
+ pNtk->vPos = Vec_PtrAlloc( 100 );
+ pNtk->vNamesPi = Vec_PtrAlloc( 100 );
+ pNtk->vNamesPo = Vec_PtrAlloc( 100 );
+ pNtk->vNamesLatch = Vec_PtrAlloc( 100 );
+ pNtk->vPtrTemp = Vec_PtrAlloc( 100 );
+ pNtk->vIntTemp = Vec_IntAlloc( 100 );
+ pNtk->vStrTemp = Vec_StrAlloc( 100 );
+ // start the hash table
+ pNtk->tName2Net = stmm_init_table(strcmp, stmm_strhash);
+ // start the memory managers
+ pNtk->pMmNames = Extra_MmFlexStart();
+ pNtk->pMmObj = Extra_MmFixedStart( sizeof(Abc_Obj_t) );
+ pNtk->pMmStep = Extra_MmStepStart( ABC_NUM_STEPS );
+ // get ready to assign the first Obj ID
+ pNtk->nTravIds = 1;
+ // start the functionality manager
+ if ( Abc_NtkIsNetlist(pNtk) || Abc_NtkIsLogicSop(pNtk) )
+ pNtk->pManFunc = Extra_MmFlexStart();
+ else if ( Abc_NtkIsLogicBdd(pNtk) )
+ pNtk->pManFunc = Cudd_Init( 20, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 );
+ else if ( Abc_NtkIsAig(pNtk) )
+ pNtk->pManFunc = Abc_AigAlloc( pNtk );
+ else if ( !Abc_NtkIsLogicMap(pNtk) )
+ assert( 0 );
+ return pNtk;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Starts a new network using existing network as a model.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Abc_NtkStartFrom( Abc_Ntk_t * pNtk, Abc_NtkType_t Type )
+{
+ Abc_Ntk_t * pNtkNew;
+ Abc_Obj_t * pObj, * pObjNew;
+ int i;
+ if ( pNtk == NULL )
+ return NULL;
+ assert( Type != ABC_NTK_NETLIST );
+ // start the network
+ pNtkNew = Abc_NtkAlloc( Type );
+ // duplicate the name and the spec
+ pNtkNew->pName = util_strsav(pNtk->pName);
+ pNtkNew->pSpec = util_strsav(pNtk->pSpec);
+ // clone the PIs/POs/latches
+ Abc_NtkForEachPi( pNtk, pObj, i )
+ Abc_NtkDupObj(pNtkNew, pObj);
+ Abc_NtkForEachPo( pNtk, pObj, i )
+ Abc_NtkDupObj(pNtkNew, pObj);
+ Abc_NtkForEachLatch( pNtk, pObj, i )
+ {
+ pObjNew = Abc_NtkDupObj(pNtkNew, pObj);
+ Vec_PtrPush( pNtkNew->vPis, pObjNew );
+ Vec_PtrPush( pNtkNew->vPos, pObjNew );
+ }
+ // clean the node copy fields
+ Abc_NtkForEachNode( pNtk, pObj, i )
+ pObj->pCopy = NULL;
+ return pNtkNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Finalizes the network using the existing network as a model.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkFinalize( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew )
+{
+ Abc_Obj_t * pObj, * pDriver, * pDriverNew;
+ int i;
+ assert( !Abc_NtkIsNetlist(pNtk) );
+ // set the COs of the strashed network
+ Abc_NtkForEachCo( pNtk, pObj, i )
+ {
+ pDriver = Abc_ObjFanin0(pObj);
+ pDriverNew = Abc_ObjNotCond(pDriver->pCopy, Abc_ObjFaninC0(pObj));
+ Abc_ObjAddFanin( pObj->pCopy, pDriverNew );
+ }
+ // transfer the names
+ Abc_NtkDupNameArrays( pNtk, pNtkNew );
+ Abc_ManTimeDup( pNtk, pNtkNew );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Finalizes the network using the existing network as a model.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkFinalizeRegular( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew )
+{
+ Abc_Obj_t * pObj, * pDriver, * pDriverNew;
+ int i;
+ assert( !Abc_NtkIsNetlist(pNtk) );
+ // set the COs of the strashed network
+ Abc_NtkForEachCo( pNtk, pObj, i )
+ {
+ pDriver = Abc_ObjFanin0(pObj);
+ pDriverNew = pDriver->pCopy;
+ Abc_ObjAddFanin( pObj->pCopy, pDriverNew );
+ }
+ // transfer the names
+ Abc_NtkDupNameArrays( pNtk, pNtkNew );
+ Abc_ManTimeDup( pNtk, pNtkNew );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Duplicate the Ntk.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Abc_NtkDup( Abc_Ntk_t * pNtk )
+{
+ Abc_Ntk_t * pNtkNew;
+ Abc_Obj_t * pObj, * pFanin;
+ int i, k;
+ if ( pNtk == NULL )
+ return NULL;
+ // start the network
+ pNtkNew = Abc_NtkAlloc( pNtk->Type );
+ // duplicate the name and the spec
+ pNtkNew->pName = util_strsav(pNtk->pName);
+ pNtkNew->pSpec = util_strsav(pNtk->pSpec);
+ // duplicate the objects
+ Abc_NtkForEachObj( pNtk, pObj, i )
+ Abc_NtkDupObj(pNtkNew, pObj);
+ // connect the objects
+ Abc_NtkForEachObj( pNtk, pObj, i )
+ Abc_ObjForEachFanin( pObj, pFanin, k )
+ {
+ Abc_ObjAddFanin( pObj->pCopy, pFanin->pCopy );
+ if ( Abc_ObjFaninC( pObj, k ) )
+ Abc_ObjSetFaninC( pObj->pCopy, k );
+ // latch numbers on edges are not copied
+ }
+ // postprocess
+ if ( Abc_NtkIsNetlist(pNtk) )
+ {
+ // mark the PI/PO nets of the new network
+ Abc_NtkForEachPi( pNtk, pObj, i )
+ Abc_NtkMarkNetPi( pObj->pCopy );
+ Abc_NtkForEachPo( pNtk, pObj, i )
+ Abc_NtkMarkNetPo( pObj->pCopy );
+ }
+ else
+ {
+ // add latches to the PI/PO lists to work as CIs/COs
+ Abc_NtkForEachLatch( pNtk, pObj, i )
+ {
+ Vec_PtrPush( pNtkNew->vPis, pObj->pCopy );
+ Vec_PtrPush( pNtkNew->vPos, pObj->pCopy );
+ }
+ }
+ // copy the CI/CO names if saved
+ if ( !Abc_NtkIsNetlist(pNtk) )
+ Abc_NtkDupNameArrays( pNtk, pNtkNew );
+ // copy the timing info
+ Abc_ManTimeDup( pNtk, pNtkNew );
+ // duplicate the EXDC Ntk
+ if ( pNtk->pExdc )
+ pNtkNew->pExdc = Abc_NtkDup( pNtk->pExdc );
+ if ( !Abc_NtkCheck( pNtkNew ) )
+ fprintf( stdout, "Abc_NtkDup(): Network check has failed.\n" );
+ return pNtkNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Deletes the Ntk.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkDelete( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pObj;
+ int TotalMemory, i;
+ int LargePiece = (4 << ABC_NUM_STEPS);
+ if ( pNtk == NULL )
+ return;
+ // make sure all the marks are clean
+ Abc_NtkForEachObj( pNtk, pObj, i )
+ {
+ // free large fanout arrays
+ if ( pObj->vFanouts.nCap * 4 > LargePiece )
+ FREE( pObj->vFanouts.pArray );
+ // check that the other things are okay
+ assert( pObj->fMarkA == 0 );
+ assert( pObj->fMarkB == 0 );
+ assert( pObj->fMarkC == 0 );
+ }
+
+ // dereference the BDDs
+ if ( Abc_NtkIsLogicBdd(pNtk) )
+ Abc_NtkForEachNode( pNtk, pObj, i )
+ Cudd_RecursiveDeref( pNtk->pManFunc, pObj->pData );
+
+ FREE( pNtk->pName );
+ FREE( pNtk->pSpec );
+ // copy the EXDC Ntk
+ if ( pNtk->pExdc )
+ Abc_NtkDelete( pNtk->pExdc );
+ // free the arrays
+ Vec_PtrFree( pNtk->vObjs );
+ Vec_PtrFree( pNtk->vLatches );
+ Vec_PtrFree( pNtk->vPis );
+ Vec_PtrFree( pNtk->vPos );
+ Vec_PtrFree( pNtk->vNamesPi );
+ Vec_PtrFree( pNtk->vNamesPo );
+ Vec_PtrFree( pNtk->vNamesLatch );
+ Vec_PtrFree( pNtk->vPtrTemp );
+ Vec_IntFree( pNtk->vIntTemp );
+ Vec_StrFree( pNtk->vStrTemp );
+ // free the hash table of Obj name into Obj ID
+ stmm_free_table( pNtk->tName2Net );
+ TotalMemory = 0;
+ TotalMemory += Extra_MmFlexReadMemUsage(pNtk->pMmNames);
+ TotalMemory += Extra_MmFixedReadMemUsage(pNtk->pMmObj);
+ TotalMemory += Extra_MmStepReadMemUsage(pNtk->pMmStep);
+// fprintf( stdout, "The total memory allocated internally by the network = %0.2f Mb.\n", ((double)TotalMemory)/(1<<20) );
+ // free the storage
+ Extra_MmFlexStop ( pNtk->pMmNames, 0 );
+ Extra_MmFixedStop( pNtk->pMmObj, 0 );
+ Extra_MmStepStop ( pNtk->pMmStep, 0 );
+ // free the timing manager
+ if ( pNtk->pManTime )
+ Abc_ManTimeStop( pNtk->pManTime );
+ // start the functionality manager
+ if ( Abc_NtkIsNetlist(pNtk) || Abc_NtkIsLogicSop(pNtk) )
+ Extra_MmFlexStop( pNtk->pManFunc, 0 );
+ else if ( Abc_NtkIsLogicBdd(pNtk) )
+ Extra_StopManager( pNtk->pManFunc );
+ else if ( Abc_NtkIsAig(pNtk) )
+ Abc_AigFree( pNtk->pManFunc );
+ else if ( !Abc_NtkIsLogicMap(pNtk) )
+ assert( 0 );
+ free( pNtk );
+}
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Creates a new Obj.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_ObjAlloc( Abc_Ntk_t * pNtk, Abc_ObjType_t Type )
+{
+ Abc_Obj_t * pObj;
+ pObj = (Abc_Obj_t *)Extra_MmFixedEntryFetch( pNtk->pMmObj );
+ memset( pObj, 0, sizeof(Abc_Obj_t) );
+ pObj->Id = -1;
+ pObj->pNtk = pNtk;
+ pObj->Type = Type;
+ return pObj;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recycles the Obj.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_ObjRecycle( Abc_Obj_t * pObj )
+{
+ Extra_MmFixedEntryRecycle( pObj->pNtk->pMmObj, (char *)pObj );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Adds the node to the network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_ObjAdd( Abc_Obj_t * pObj )
+{
+ Abc_Ntk_t * pNtk = pObj->pNtk;
+ assert( !Abc_ObjIsComplement(pObj) );
+ // add to the array of objects
+ pObj->Id = pNtk->vObjs->nSize;
+ Vec_PtrPush( pNtk->vObjs, pObj );
+ pNtk->nObjs++;
+ // perform specialized operations depending on the object type
+ if ( Abc_ObjIsNet(pObj) )
+ {
+ // add the name to the table
+ if ( pObj->pData && stmm_insert( pNtk->tName2Net, pObj->pData, (char *)pObj ) )
+ {
+ printf( "Error: The net is already in the table...\n" );
+ assert( 0 );
+ }
+ pNtk->nNets++;
+ }
+ else if ( Abc_ObjIsNode(pObj) )
+ {
+ assert( pObj->Subtype == 0 );
+ pNtk->nNodes++;
+ }
+ else if ( Abc_ObjIsLatch(pObj) )
+ {
+ Vec_PtrPush( pNtk->vLatches, pObj );
+ pNtk->nLatches++;
+ }
+ else if ( Abc_ObjIsTerm(pObj) )
+ {
+ // if it is PIs/POs, add it
+ assert( !(Abc_ObjIsPi(pObj) && Abc_ObjIsPo(pObj)) );
+ if ( Abc_ObjIsPi(pObj) )
+ Vec_PtrPush( pNtk->vPis, pObj ), pNtk->nPis++;
+ else if ( Abc_ObjIsPo(pObj) )
+ Vec_PtrPush( pNtk->vPos, pObj ), pNtk->nPos++;
+ else
+ assert( 0 );
+ }
+ else
+ {
+ assert( 0 );
+ }
+ assert( pObj->Id >= 0 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Duplicate the Obj.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NtkDupObj( Abc_Ntk_t * pNtkNew, Abc_Obj_t * pObj )
+{
+ Abc_Obj_t * pObjNew;
+ pObjNew = Abc_ObjAlloc( pNtkNew, pObj->Type );
+ pObjNew->Subtype = pObj->Subtype;
+ if ( Abc_ObjIsNode(pObj) ) // copy the function
+ {
+ if ( Abc_NtkIsNetlist(pNtkNew) || Abc_NtkIsLogicSop(pNtkNew) )
+ pObjNew->pData = Abc_SopRegister( pNtkNew->pManFunc, pObj->pData );
+ else if ( Abc_NtkIsLogicBdd(pNtkNew) )
+ pObjNew->pData = Cudd_bddTransfer(pObj->pNtk->pManFunc, pNtkNew->pManFunc, pObj->pData), Cudd_Ref(pObjNew->pData);
+ else if ( Abc_NtkIsLogicMap(pNtkNew) )
+ pObjNew->pData = pObj->pData;
+ else if ( !Abc_NtkIsAig(pNtkNew) )
+ assert( 0 );
+ }
+ else if ( Abc_ObjIsNet(pObj) ) // copy the name
+ pObjNew->pData = Abc_NtkRegisterName( pNtkNew, pObj->pData );
+ else if ( Abc_ObjIsLatch(pObj) ) // copy the reset value
+ pObjNew->pData = pObj->pData;
+ pObj->pCopy = pObjNew;
+ // add the object to the network
+ Abc_ObjAdd( pObjNew );
+ return pObjNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Deletes the object from the network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkDeleteObj( Abc_Obj_t * pObj )
+{
+ Vec_Ptr_t * vNodes = pObj->pNtk->vPtrTemp;
+ Abc_Ntk_t * pNtk = pObj->pNtk;
+ int i;
+
+ assert( !Abc_ObjIsComplement(pObj) );
+
+ // delete fanins and fanouts
+ Abc_NodeCollectFanouts( pObj, vNodes );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ Abc_ObjDeleteFanin( vNodes->pArray[i], pObj );
+ Abc_NodeCollectFanins( pObj, vNodes );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ Abc_ObjDeleteFanin( pObj, vNodes->pArray[i] );
+
+ // remove from the list of objects
+ Vec_PtrWriteEntry( pNtk->vObjs, pObj->Id, NULL );
+ pNtk->nObjs--;
+
+ // perform specialized operations depending on the object type
+ if ( Abc_ObjIsNet(pObj) )
+ {
+ // remove the net from the hash table of nets
+ if ( pObj->pData && !stmm_delete( pNtk->tName2Net, (char **)&pObj->pData, (char **)&pObj ) )
+ {
+ printf( "Error: The net is not in the table...\n" );
+ assert( 0 );
+ }
+ pNtk->nNets--;
+ assert( !Abc_ObjIsPi(pObj) && !Abc_ObjIsPo(pObj) );
+ }
+ else if ( Abc_ObjIsNode(pObj) )
+ {
+ pNtk->nNodes--;
+ }
+ else if ( Abc_ObjIsLatch(pObj) )
+ {
+ pNtk->nLatches--;
+ assert( 0 ); // currently do not allow removing latches
+ }
+ else if ( Abc_ObjIsTerm(pObj) )
+ {
+ assert( 0 ); // currently do not allow removing latches
+ }
+ else
+ assert( 0 );
+ // recycle the net itself
+ Abc_ObjRecycle( pObj );
+}
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Adds a new PI net to the network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkMarkNetPi( Abc_Obj_t * pObj )
+{
+ assert( Abc_NtkIsNetlist(pObj->pNtk) );
+ assert( Abc_ObjIsNet(pObj) );
+ assert( pObj->Id >= 0 );
+ Abc_ObjSetSubtype( pObj, ABC_OBJ_SUBTYPE_PI );
+ Vec_PtrPush( pObj->pNtk->vPis, pObj );
+ pObj->pNtk->nPis++;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Adds a new PO Obj to the Objwork.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkMarkNetPo( Abc_Obj_t * pObj )
+{
+ assert( Abc_NtkIsNetlist(pObj->pNtk) );
+ assert( Abc_ObjIsNet(pObj) );
+ assert( pObj->Id >= 0 );
+ Abc_ObjSetSubtype( pObj, ABC_OBJ_SUBTYPE_PO );
+ Vec_PtrPush( pObj->pNtk->vPos, pObj );
+ pObj->pNtk->nPos++;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Adds a new PO node to the network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NtkAddPoNode( Abc_Obj_t * pDriver )
+{
+ Abc_Obj_t * pNodePo, * pDriverR = Abc_ObjRegular(pDriver);
+ Abc_Ntk_t * pNtk = pDriverR->pNtk;
+ // this function only works for logic networks
+ assert( !Abc_NtkIsNetlist(pNtk) );
+ assert( pDriverR->Id >= 0 );
+ // the cannot be a PO node
+ assert( !Abc_ObjIsPo(pDriverR) );
+ // create a new PO node
+ pNodePo = Abc_NtkCreateTermPo( pNtk );
+ // create the fanin (possibly complemented)
+ Abc_ObjAddFanin( pNodePo, pDriver );
+ return pNodePo;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Removes a node from the network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkRemovePoNode( Abc_Obj_t * pNode )
+{
+ assert( Abc_ObjFanoutNum(pNode) == 0 );
+ assert( Abc_ObjIsPo(pNode) );
+ Abc_ObjDeleteFanin( pNode, Abc_ObjFanin0(pNode) );
+ pNode->pNtk->vObjs->pArray[ pNode->Id ] = NULL;
+ pNode->pNtk->nNodes--;
+ pNode->pNtk->nPos--;
+ Abc_ObjRecycle( pNode );
+}
+
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Returns the net with the given name.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NtkFindNode( Abc_Ntk_t * pNtk, char * pName )
+{
+ return NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the net with the given name.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NtkFindNet( Abc_Ntk_t * pNtk, char * pName )
+{
+ Abc_Obj_t * pNet;
+ assert( Abc_NtkIsNetlist(pNtk) );
+ if ( stmm_lookup( pNtk->tName2Net, pName, (char**)&pNet ) )
+ return pNet;
+ return NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Finds or creates the net.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NtkFindOrCreateNet( Abc_Ntk_t * pNtk, char * pName )
+{
+ Abc_Obj_t * pNet;
+ assert( Abc_NtkIsNetlist(pNtk) );
+ if ( pNet = Abc_NtkFindNet( pNtk, pName ) )
+ return pNet;
+ // create a new net
+ pNet = Abc_ObjAlloc( pNtk, ABC_OBJ_TYPE_NET );
+ pNet->pData = Abc_NtkRegisterName( pNtk, pName );
+ Abc_ObjAdd( pNet );
+ return pNet;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Create the new node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NtkCreateNode( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pObj;
+ pObj = Abc_ObjAlloc( pNtk, ABC_OBJ_TYPE_NODE );
+ Abc_ObjAdd( pObj );
+ return pObj;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Create the new node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NtkCreateTermPi( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pObj;
+ pObj = Abc_ObjAlloc( pNtk, ABC_OBJ_TYPE_TERM );
+ Abc_ObjSetSubtype( pObj, ABC_OBJ_SUBTYPE_PI );
+ Abc_ObjAdd( pObj );
+ return pObj;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Create the new node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NtkCreateTermPo( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pObj;
+ pObj = Abc_ObjAlloc( pNtk, ABC_OBJ_TYPE_TERM );
+ Abc_ObjSetSubtype( pObj, ABC_OBJ_SUBTYPE_PO );
+ Abc_ObjAdd( pObj );
+// Abc_NtkAddPo( pObj );
+ return pObj;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Create the new node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NtkCreateLatch( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pObj;
+ pObj = Abc_ObjAlloc( pNtk, ABC_OBJ_TYPE_LATCH );
+ Abc_ObjAdd( pObj );
+ return pObj;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates inverter.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NodeCreateConst0( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ assert( Abc_NtkIsLogic(pNtk) );
+ pNode = Abc_NtkCreateNode( pNtk );
+ if ( Abc_NtkIsLogicSop(pNtk) )
+ pNode->pData = Abc_SopRegister( pNtk->pManFunc, " 0\n" );
+ else if ( Abc_NtkIsLogicBdd(pNtk) )
+ pNode->pData = Cudd_ReadLogicZero(pNtk->pManFunc), Cudd_Ref( pNode->pData );
+ else if ( Abc_NtkIsLogicMap(pNtk) )
+ pNode->pData = Mio_LibraryReadConst0(Abc_FrameReadLibGen(Abc_FrameGetGlobalFrame()));
+ else
+ assert( 0 );
+ return pNode;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates inverter.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NodeCreateConst1( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ assert( Abc_NtkIsLogic(pNtk) );
+ pNode = Abc_NtkCreateNode( pNtk );
+ if ( Abc_NtkIsLogicSop(pNtk) )
+ pNode->pData = Abc_SopRegister( pNtk->pManFunc, " 1\n" );
+ else if ( Abc_NtkIsLogicBdd(pNtk) )
+ pNode->pData = Cudd_ReadOne(pNtk->pManFunc), Cudd_Ref( pNode->pData );
+ else if ( Abc_NtkIsLogicMap(pNtk) )
+ pNode->pData = Mio_LibraryReadConst1(Abc_FrameReadLibGen(Abc_FrameGetGlobalFrame()));
+ else
+ assert( 0 );
+ return pNode;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates inverter.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NodeCreateInv( Abc_Ntk_t * pNtk, Abc_Obj_t * pFanin )
+{
+ Abc_Obj_t * pNode;
+ assert( Abc_NtkIsLogic(pNtk) );
+ pNode = Abc_NtkCreateNode( pNtk );
+ Abc_ObjAddFanin( pNode, pFanin );
+ if ( Abc_NtkIsLogicSop(pNtk) )
+ pNode->pData = Abc_SopRegister( pNtk->pManFunc, "0 1\n" );
+ else if ( Abc_NtkIsLogicBdd(pNtk) )
+ pNode->pData = Cudd_Not(Cudd_bddIthVar(pNtk->pManFunc,0)), Cudd_Ref( pNode->pData );
+ else if ( Abc_NtkIsLogicMap(pNtk) )
+ pNode->pData = Mio_LibraryReadInv(Abc_FrameReadLibGen(Abc_FrameGetGlobalFrame()));
+ else
+ assert( 0 );
+ return pNode;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates buffer.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NodeCreateBuf( Abc_Ntk_t * pNtk, Abc_Obj_t * pFanin )
+{
+ Abc_Obj_t * pNode;
+ assert( Abc_NtkIsLogic(pNtk) );
+ pNode = Abc_NtkCreateNode( pNtk );
+ Abc_ObjAddFanin( pNode, pFanin );
+ if ( Abc_NtkIsLogicSop(pNtk) )
+ pNode->pData = Abc_SopRegister( pNtk->pManFunc, "1 1\n" );
+ else if ( Abc_NtkIsLogicBdd(pNtk) )
+ pNode->pData = Cudd_bddIthVar(pNtk->pManFunc,0), Cudd_Ref( pNode->pData );
+ else if ( Abc_NtkIsLogicMap(pNtk) )
+ pNode->pData = Mio_LibraryReadBuf(Abc_FrameReadLibGen(Abc_FrameGetGlobalFrame()));
+ else
+ assert( 0 );
+ return pNode;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates inverter.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NodeCreateAnd( Abc_Ntk_t * pNtk, Vec_Ptr_t * vFanins )
+{
+ Abc_Obj_t * pNode;
+ int i;
+ assert( Abc_NtkIsLogic(pNtk) );
+ pNode = Abc_NtkCreateNode( pNtk );
+ for ( i = 0; i < vFanins->nSize; i++ )
+ Abc_ObjAddFanin( pNode, vFanins->pArray[i] );
+ if ( Abc_NtkIsLogicSop(pNtk) )
+ {
+ char * pSop;
+ pSop = Extra_MmFlexEntryFetch( pNtk->pManFunc, vFanins->nSize + 4 );
+ for ( i = 0; i < vFanins->nSize; i++ )
+ pSop[i] = '1';
+ pSop[i++] = ' ';
+ pSop[i++] = '1';
+ pSop[i++] = '\n';
+ pSop[i++] = 0;
+ assert( i == vFanins->nSize + 4 );
+ pNode->pData = pSop;
+ }
+ else if ( Abc_NtkIsLogicBdd(pNtk) )
+ {
+ DdManager * dd = pNtk->pManFunc;
+ DdNode * bFunc, * bTemp;
+ bFunc = Cudd_ReadOne(dd); Cudd_Ref( bFunc );
+ for ( i = 0; i < vFanins->nSize; i++ )
+ {
+ bFunc = Cudd_bddAnd( dd, bTemp = bFunc, Cudd_bddIthVar(pNtk->pManFunc,i) ); Cudd_Ref( bFunc );
+ Cudd_RecursiveDeref( dd, bTemp );
+ }
+ pNode->pData = bFunc;
+ }
+ else
+ assert( 0 );
+ return pNode;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates inverter.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NodeCreateOr( Abc_Ntk_t * pNtk, Vec_Ptr_t * vFanins )
+{
+ Abc_Obj_t * pNode;
+ int i;
+ assert( Abc_NtkIsLogic(pNtk) );
+ pNode = Abc_NtkCreateNode( pNtk );
+ for ( i = 0; i < vFanins->nSize; i++ )
+ Abc_ObjAddFanin( pNode, vFanins->pArray[i] );
+ if ( Abc_NtkIsLogicSop(pNtk) )
+ {
+ char * pSop;
+ pSop = Extra_MmFlexEntryFetch( pNtk->pManFunc, vFanins->nSize + 4 );
+ for ( i = 0; i < vFanins->nSize; i++ )
+ pSop[i] = '0';
+ pSop[i++] = ' ';
+ pSop[i++] = '0';
+ pSop[i++] = '\n';
+ pSop[i++] = 0;
+ assert( i == vFanins->nSize + 4 );
+ pNode->pData = pSop;
+ }
+ else if ( Abc_NtkIsLogicBdd(pNtk) )
+ {
+ DdManager * dd = pNtk->pManFunc;
+ DdNode * bFunc, * bTemp;
+ bFunc = Cudd_ReadLogicZero(dd); Cudd_Ref( bFunc );
+ for ( i = 0; i < vFanins->nSize; i++ )
+ {
+ bFunc = Cudd_bddOr( dd, bTemp = bFunc, Cudd_bddIthVar(pNtk->pManFunc,i) ); Cudd_Ref( bFunc );
+ Cudd_RecursiveDeref( dd, bTemp );
+ }
+ pNode->pData = bFunc;
+ }
+ else
+ assert( 0 );
+ return pNode;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates inverter.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NodeCreateMux( Abc_Ntk_t * pNtk, Abc_Obj_t * pNodeC, Abc_Obj_t * pNode1, Abc_Obj_t * pNode0 )
+{
+ Abc_Obj_t * pNode;
+ assert( Abc_NtkIsLogic(pNtk) );
+ pNode = Abc_NtkCreateNode( pNtk );
+ Abc_ObjAddFanin( pNode, pNodeC );
+ Abc_ObjAddFanin( pNode, pNode1 );
+ Abc_ObjAddFanin( pNode, pNode0 );
+ if ( Abc_NtkIsLogicSop(pNtk) )
+ pNode->pData = Abc_SopRegister( pNtk->pManFunc, "11- 1\n0-1 1\n" );
+ else if ( Abc_NtkIsLogicBdd(pNtk) )
+ pNode->pData = Cudd_bddIte(pNtk->pManFunc,Cudd_bddIthVar(pNtk->pManFunc,0),Cudd_bddIthVar(pNtk->pManFunc,1),Cudd_bddIthVar(pNtk->pManFunc,2)), Cudd_Ref( pNode->pData );
+ else
+ assert( 0 );
+ return pNode;
+}
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NodeIsConst0( Abc_Obj_t * pNode )
+{
+ Abc_Ntk_t * pNtk = pNode->pNtk;
+ assert(Abc_ObjIsNode(pNode));
+ assert(Abc_NodeIsConst(pNode));
+ if ( Abc_NtkIsNetlist(pNtk) || Abc_NtkIsLogicSop(pNtk) )
+ return Abc_SopIsConst0(pNode->pData);
+ if ( Abc_NtkIsLogicBdd(pNtk) )
+ return Cudd_IsComplement(pNode->pData);
+ if ( Abc_NtkIsAig(pNtk) )
+ return Abc_ObjNot(pNode) == Abc_AigConst1(pNode->pNtk->pManFunc);
+ if ( Abc_NtkIsLogicMap(pNtk) )
+ return pNode->pData == Mio_LibraryReadConst0(Abc_FrameReadLibSuper(Abc_FrameGetGlobalFrame()));
+ assert( 0 );
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NodeIsConst1( Abc_Obj_t * pNode )
+{
+ Abc_Ntk_t * pNtk = pNode->pNtk;
+ assert(Abc_ObjIsNode(pNode));
+ assert(Abc_NodeIsConst(pNode));
+ if ( Abc_NtkIsNetlist(pNtk) || Abc_NtkIsLogicSop(pNtk) )
+ return Abc_SopIsConst1(pNode->pData);
+ if ( Abc_NtkIsLogicBdd(pNtk) )
+ return !Cudd_IsComplement(pNode->pData);
+ if ( Abc_NtkIsAig(pNtk) )
+ return pNode == Abc_AigConst1(pNode->pNtk->pManFunc);
+ if ( Abc_NtkIsLogicMap(pNtk) )
+ return pNode->pData == Mio_LibraryReadConst1(Abc_FrameReadLibSuper(Abc_FrameGetGlobalFrame()));
+ assert( 0 );
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NodeIsBuf( Abc_Obj_t * pNode )
+{
+ Abc_Ntk_t * pNtk = pNode->pNtk;
+ assert(Abc_ObjIsNode(pNode));
+ if ( Abc_ObjFaninNum(pNode) != 1 )
+ return 0;
+ if ( Abc_NtkIsNetlist(pNtk) || Abc_NtkIsLogicSop(pNtk) )
+ return Abc_SopIsBuf(pNode->pData);
+ if ( Abc_NtkIsLogicBdd(pNtk) )
+ return !Cudd_IsComplement(pNode->pData);
+ if ( Abc_NtkIsAig(pNtk) )
+ return 0;
+ if ( Abc_NtkIsLogicMap(pNtk) )
+ return pNode->pData == Mio_LibraryReadBuf(Abc_FrameReadLibSuper(Abc_FrameGetGlobalFrame()));
+ assert( 0 );
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NodeIsInv( Abc_Obj_t * pNode )
+{
+ Abc_Ntk_t * pNtk = pNode->pNtk;
+ assert(Abc_ObjIsNode(pNode));
+ if ( Abc_ObjFaninNum(pNode) != 1 )
+ return 0;
+ if ( Abc_NtkIsNetlist(pNtk) || Abc_NtkIsLogicSop(pNtk) )
+ return Abc_SopIsInv(pNode->pData);
+ if ( Abc_NtkIsLogicBdd(pNtk) )
+ return Cudd_IsComplement(pNode->pData);
+ if ( Abc_NtkIsAig(pNtk) )
+ return 0;
+ if ( Abc_NtkIsLogicMap(pNtk) )
+ return pNode->pData == Mio_LibraryReadInv(Abc_FrameReadLibSuper(Abc_FrameGetGlobalFrame()));
+ assert( 0 );
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcDfs.c b/src/base/abc/abcDfs.c
new file mode 100644
index 00000000..7b330b95
--- /dev/null
+++ b/src/base/abc/abcDfs.c
@@ -0,0 +1,446 @@
+/**CFile****************************************************************
+
+ FileName [abcDfs.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Procedures that use depth-first search.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcDfs.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Abc_NtkDfs_rec( Abc_Obj_t * pNode, Vec_Ptr_t * vNodes );
+static void Abc_AigDfs_rec( Abc_Obj_t * pNode, Vec_Ptr_t * vNodes );
+static int Abc_NtkGetLevelNum_rec( Abc_Obj_t * pNode );
+static bool Abc_NtkIsAcyclic_rec( Abc_Obj_t * pNode );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Returns the DFS ordered array of logic nodes.]
+
+ Description [Collects only the internal nodes, leaving out PIs, POs and latches.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Vec_Ptr_t * Abc_NtkDfs( Abc_Ntk_t * pNtk )
+{
+ Vec_Ptr_t * vNodes;
+ Abc_Obj_t * pNet, * pNode;
+ int i, fMadeComb;
+ // set the traversal ID
+ Abc_NtkIncrementTravId( pNtk );
+ // start the array of nodes
+ vNodes = Vec_PtrAlloc( 100 );
+ // go through the PO nodes and call for each of them
+ if ( Abc_NtkIsNetlist(pNtk) )
+ {
+ fMadeComb = Abc_NtkMakeComb( pNtk );
+ Abc_NtkForEachPo( pNtk, pNet, i )
+ {
+ if ( Abc_ObjIsCi(pNet) )
+ continue;
+ Abc_NtkDfs_rec( Abc_ObjFanin0(pNet), vNodes );
+ }
+ if ( fMadeComb ) Abc_NtkMakeSeq( pNtk );
+ }
+ else
+ {
+ Abc_NtkForEachCo( pNtk, pNode, i )
+ Abc_NtkDfs_rec( Abc_ObjFanin0(pNode), vNodes );
+ }
+ return vNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs DFS for one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkDfs_rec( Abc_Obj_t * pNode, Vec_Ptr_t * vNodes )
+{
+ Abc_Obj_t * pFanin;
+ int i;
+ assert( !Abc_ObjIsComplement( pNode ) );
+ // skip the PI
+ if ( Abc_ObjIsPi(pNode) || Abc_ObjIsLatch(pNode) )
+ return;
+ assert( Abc_ObjIsNode( pNode ) );
+
+ // if this node is already visited, skip
+ if ( Abc_NodeIsTravIdCurrent( pNode ) )
+ return;
+ // mark the node as visited
+ Abc_NodeSetTravIdCurrent( pNode );
+
+ // visit the transitive fanin of the node
+ if ( Abc_NtkIsNetlist(pNode->pNtk) )
+ {
+ Abc_ObjForEachFanin( pNode, pFanin, i )
+ {
+ if ( Abc_ObjIsCi(pFanin) )
+ continue;
+ pFanin = Abc_ObjFanin0(pFanin);
+ Abc_NtkDfs_rec( pFanin, vNodes );
+ }
+ }
+ else
+ {
+ Abc_ObjForEachFanin( pNode, pFanin, i )
+ Abc_NtkDfs_rec( pFanin, vNodes );
+ }
+ // add the node after the fanins have been added
+ Vec_PtrPush( vNodes, pNode );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Returns the DFS ordered array of logic nodes.]
+
+ Description [Collects only the internal nodes, leaving out PIs, POs and latches.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Vec_Ptr_t * Abc_AigDfs( Abc_Ntk_t * pNtk )
+{
+ Vec_Ptr_t * vNodes;
+ Abc_Obj_t * pNode;
+ int i;
+ assert( Abc_NtkIsAig(pNtk) );
+ // set the traversal ID
+ Abc_NtkIncrementTravId( pNtk );
+ // start the array of nodes
+ vNodes = Vec_PtrAlloc( 100 );
+ // go through the PO nodes and call for each of them
+ Abc_NtkForEachCo( pNtk, pNode, i )
+ Abc_AigDfs_rec( Abc_ObjFanin0(pNode), vNodes );
+ return vNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs DFS for one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_AigDfs_rec( Abc_Obj_t * pNode, Vec_Ptr_t * vNodes )
+{
+ Abc_Obj_t * pFanin;
+ int i;
+ assert( !Abc_ObjIsComplement( pNode ) );
+ // skip the PI
+ if ( Abc_ObjIsPi(pNode) || Abc_ObjIsLatch(pNode) )
+ return;
+ assert( Abc_ObjIsNode( pNode ) );
+ // if this node is already visited, skip
+ if ( Abc_NodeIsTravIdCurrent( pNode ) )
+ return;
+ // mark the node as visited
+ Abc_NodeSetTravIdCurrent( pNode );
+ // visit the transitive fanin of the node
+ Abc_ObjForEachFanin( pNode, pFanin, i )
+ Abc_AigDfs_rec( pFanin, vNodes );
+ // visit the equivalent nodes
+ if ( Abc_NodeIsChoice( pNode ) )
+ for ( pFanin = pNode->pData; pFanin; pFanin = pFanin->pData )
+ Abc_AigDfs_rec( pFanin, vNodes );
+ // add the node after the fanins have been added
+ Vec_PtrPush( vNodes, pNode );
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Computes the number of logic levels not counting PIs/POs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkGetLevelNum( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNet, * pNode, * pDriver;
+ unsigned LevelsMax;
+ int i, fMadeComb;
+
+ // set the traversal ID for this traversal
+ Abc_NtkIncrementTravId( pNtk );
+ // perform the traversal
+ LevelsMax = 0;
+ if ( Abc_NtkIsNetlist(pNtk) )
+ {
+ fMadeComb = Abc_NtkMakeComb( pNtk );
+ Abc_NtkForEachPo( pNtk, pNet, i )
+ {
+ if ( Abc_ObjIsCi(pNet) )
+ continue;
+ pDriver = Abc_ObjFanin0( pNet );
+ Abc_NtkGetLevelNum_rec( pDriver );
+ if ( LevelsMax < pDriver->Level )
+ LevelsMax = pDriver->Level;
+ }
+ if ( fMadeComb ) Abc_NtkMakeSeq( pNtk );
+ }
+ else
+ {
+ Abc_NtkForEachCo( pNtk, pNode, i )
+ {
+ pDriver = Abc_ObjFanin0( pNode );
+ Abc_NtkGetLevelNum_rec( pDriver );
+ if ( LevelsMax < pDriver->Level )
+ LevelsMax = pDriver->Level;
+ }
+ }
+ return LevelsMax;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively counts the number of logic levels of one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkGetLevelNum_rec( Abc_Obj_t * pNode )
+{
+ Abc_Obj_t * pFanin;
+ int i;
+ assert( !Abc_ObjIsComplement( pNode ) );
+ // skip the PI
+ if ( Abc_ObjIsPi(pNode) || Abc_ObjIsLatch(pNode) )
+ return 0;
+ assert( Abc_ObjIsNode( pNode ) );
+
+ // if this node is already visited, return
+ if ( Abc_NodeIsTravIdCurrent( pNode ) )
+ return pNode->Level;
+ // mark the node as visited
+ Abc_NodeSetTravIdCurrent( pNode );
+
+ // visit the transitive fanin
+ pNode->Level = 0;
+ if ( Abc_NtkIsNetlist(pNode->pNtk) )
+ {
+ Abc_ObjForEachFanin( pNode, pFanin, i )
+ {
+ if ( Abc_ObjIsCi(pFanin) )
+ continue;
+ pFanin = Abc_ObjFanin0(pFanin);
+ Abc_NtkGetLevelNum_rec( pFanin );
+ if ( pNode->Level < pFanin->Level )
+ pNode->Level = pFanin->Level;
+ }
+ }
+ else
+ {
+ Abc_ObjForEachFanin( pNode, pFanin, i )
+ {
+ Abc_NtkGetLevelNum_rec( pFanin );
+ if ( pNode->Level < pFanin->Level )
+ pNode->Level = pFanin->Level;
+ }
+ }
+ pNode->Level++;
+ return pNode->Level;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Detects combinational loops.]
+
+ Description [This procedure is based on the idea suggested by Donald Chai.
+ As we traverse the network and visit the nodes, we need to distinquish
+ three types of nodes: (1) those that are visited for the first time,
+ (2) those that have been visited in this traversal but are currently not
+ on the traversal path, (3) those that have been visited and are currently
+ on the travesal path. When the node of type (3) is encountered, it means
+ that there is a combinational loop. To mark the three types of nodes,
+ two new values of the traversal IDs are used.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkIsAcyclic( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNet, * pNode;
+ int fAcyclic, fMadeComb, i;
+ // set the traversal ID for this DFS ordering
+ Abc_NtkIncrementTravId( pNtk );
+ Abc_NtkIncrementTravId( pNtk );
+ // pNode->TravId == pNet->nTravIds means "pNode is on the path"
+ // pNode->TravId == pNet->nTravIds - 1 means "pNode is visited but is not on the path"
+ // pNode->TravId < pNet->nTravIds - 1 means "pNode is not visited"
+ // traverse the network to detect cycles
+ fAcyclic = 1;
+ if ( Abc_NtkIsNetlist(pNtk) )
+ {
+ fMadeComb = Abc_NtkMakeComb( pNtk );
+ Abc_NtkForEachPo( pNtk, pNet, i )
+ {
+ if ( Abc_ObjIsCi(pNet) )
+ continue;
+ pNode = Abc_ObjFanin0( pNet );
+ if ( Abc_NodeIsTravIdPrevious(pNode) )
+ continue;
+ // traverse the output logic cone to detect the combinational loops
+ if ( (fAcyclic = Abc_NtkIsAcyclic_rec( pNode )) == 0 )
+ { // stop as soon as the first loop is detected
+ fprintf( stdout, " (the output node)\n" );
+ break;
+ }
+ }
+ if ( fMadeComb ) Abc_NtkMakeSeq( pNtk );
+ }
+ else
+ {
+ Abc_NtkForEachCo( pNtk, pNode, i )
+ {
+ pNode = Abc_ObjFanin0( pNode );
+ if ( Abc_NodeIsTravIdPrevious(pNode) )
+ continue;
+ // traverse the output logic cone to detect the combinational loops
+ if ( (fAcyclic = Abc_NtkIsAcyclic_rec( pNode )) == 0 )
+ { // stop as soon as the first loop is detected
+ fprintf( stdout, " (the output node)\n" );
+ break;
+ }
+ }
+ }
+ return fAcyclic;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively detects combinational loops.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkIsAcyclic_rec( Abc_Obj_t * pNode )
+{
+ Abc_Ntk_t * pNtk = pNode->pNtk;
+ Abc_Obj_t * pFanin;
+ int fAcyclic, i;
+
+ assert( !Abc_ObjIsComplement( pNode ) );
+ // skip the PI
+ if ( Abc_ObjIsPi(pNode) || Abc_ObjIsLatch(pNode) )
+ return 1;
+ assert( Abc_ObjIsNode( pNode ) );
+
+ // make sure the node is not visited
+ assert( !Abc_NodeIsTravIdPrevious(pNode) );
+ // check if the node is part of the combinational loop
+ if ( Abc_NodeIsTravIdCurrent(pNode) )
+ {
+ fprintf( stdout, "Network \"%s\" contains combinational loop!\n", pNtk->pName );
+ fprintf( stdout, "Node \"%s\" is encountered twice on the following path:\n", Abc_ObjName(pNode) );
+ fprintf( stdout, " %s", Abc_ObjName(pNode) );
+ return 0;
+ }
+ // mark this node as a node on the current path
+ Abc_NodeSetTravIdCurrent( pNode );
+
+ // visit the transitive fanin
+ if ( Abc_NtkIsNetlist(pNode->pNtk) )
+ {
+ Abc_ObjForEachFanin( pNode, pFanin, i )
+ {
+ if ( Abc_ObjIsCi(pFanin) )
+ continue;
+ pFanin = Abc_ObjFanin0(pFanin);
+ // make sure there is no mixing of networks
+ assert( pFanin->pNtk == pNode->pNtk );
+ // check if the fanin is visited
+ if ( Abc_NodeIsTravIdPrevious(pFanin) )
+ continue;
+ // traverse searching for the loop
+ fAcyclic = Abc_NtkIsAcyclic_rec( pFanin );
+ // return as soon as the loop is detected
+ if ( fAcyclic == 0 )
+ {
+ fprintf( stdout, " <-- %s", Abc_ObjName(pNode) );
+ return 0;
+ }
+ }
+ }
+ else
+ {
+ Abc_ObjForEachFanin( pNode, pFanin, i )
+ {
+ // make sure there is no mixing of networks
+ assert( pFanin->pNtk == pNode->pNtk );
+ // check if the fanin is visited
+ if ( Abc_NodeIsTravIdPrevious(pFanin) )
+ continue;
+ // traverse searching for the loop
+ fAcyclic = Abc_NtkIsAcyclic_rec( pFanin );
+ // return as soon as the loop is detected
+ if ( fAcyclic == 0 )
+ {
+ fprintf( stdout, " <-- %s", Abc_ObjName(pNode) );
+ return 0;
+ }
+ }
+ }
+ // mark this node as a visited node
+ Abc_NodeSetTravIdPrevious( pNode );
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcDsd.c b/src/base/abc/abcDsd.c
new file mode 100644
index 00000000..47b288d3
--- /dev/null
+++ b/src/base/abc/abcDsd.c
@@ -0,0 +1,48 @@
+/**CFile****************************************************************
+
+ FileName [abcDsd.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Decomposes the network using disjoint-support decomposition.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcDsd.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Decomposes the network using disjoint-support decomposition.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcFanio.c b/src/base/abc/abcFanio.c
new file mode 100644
index 00000000..51fc73ce
--- /dev/null
+++ b/src/base/abc/abcFanio.c
@@ -0,0 +1,196 @@
+/**CFile****************************************************************
+
+ FileName [abcFanio.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Various procedures to connect fanins/fanouts.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcFanio.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Creates fanout/fanin relationship between the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_ObjAddFanin( Abc_Obj_t * pObj, Abc_Obj_t * pFanin )
+{
+ Abc_Obj_t * pFaninR = Abc_ObjRegular(pFanin);
+ assert( !Abc_ObjIsComplement(pObj) );
+ assert( pObj->pNtk == pFaninR->pNtk );
+ assert( pObj->Id >= 0 && pFaninR->Id >= 0 );
+ assert( pObj->Id < (1<<21)-1 ); // created but forgot to add it to the network?
+ assert( pFaninR->Id < (1<<21)-1 ); // created but forgot to add it to the network?
+ Vec_FanPush( pObj->pNtk->pMmStep, &pObj->vFanins, Vec_Int2Fan(pFaninR->Id) );
+ Vec_FanPush( pObj->pNtk->pMmStep, &pFaninR->vFanouts, Vec_Int2Fan(pObj->Id) );
+ if ( Abc_ObjIsComplement(pFanin) )
+ Abc_ObjSetFaninC( pObj, Abc_ObjFaninNum(pObj)-1 );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Destroys fanout/fanin relationship between the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_ObjDeleteFanin( Abc_Obj_t * pObj, Abc_Obj_t * pFanin )
+{
+ assert( !Abc_ObjIsComplement(pObj) );
+ assert( !Abc_ObjIsComplement(pFanin) );
+ assert( pObj->pNtk == pFanin->pNtk );
+ assert( pObj->Id >= 0 && pFanin->Id >= 0 );
+ assert( pObj->Id < (1<<21)-1 ); // created but forgot to add it to the network?
+ assert( pFanin->Id < (1<<21)-1 ); // created but forgot to add it to the network?
+ if ( !Vec_FanDeleteEntry( &pObj->vFanins, pFanin->Id ) )
+ {
+ printf( "The obj %d is not found among the fanins of obj %d ...\n", pFanin->Id, pObj->Id );
+ return;
+ }
+ if ( !Vec_FanDeleteEntry( &pFanin->vFanouts, pObj->Id ) )
+ {
+ printf( "The obj %d is not found among the fanouts of obj %d ...\n", pObj->Id, pFanin->Id );
+ return;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Replaces a fanin of the node.]
+
+ Description [The node is pObj. An old fanin of this node (pFaninOld) has to be
+ replaced by a new fanin (pFaninNew). Assumes that the node and the old fanin
+ are not complemented. The new fanin can be complemented. In this case, the
+ polarity of the new fanin will change, compared to the polarity of the old fanin.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_ObjPatchFanin( Abc_Obj_t * pObj, Abc_Obj_t * pFaninOld, Abc_Obj_t * pFaninNew )
+{
+ Abc_Obj_t * pFaninNewR = Abc_ObjRegular(pFaninNew);
+ int iFanin, fCompl;
+ assert( !Abc_ObjIsComplement(pObj) );
+ assert( !Abc_ObjIsComplement(pFaninOld) );
+ assert( pFaninOld != pFaninNewR );
+ assert( pObj->pNtk == pFaninOld->pNtk );
+ assert( pObj->pNtk == pFaninNewR->pNtk );
+ if ( (iFanin = Vec_FanFindEntry( &pObj->vFanins, pFaninOld->Id )) == -1 )
+ {
+ printf( "Fanin node %d is not among the fanins of node %d...\n", pFaninOld->Id, pObj->Id );
+ return;
+ }
+ // remember the polarity of the old fanin
+ fCompl = Abc_ObjFaninC(pObj, iFanin);
+ // replace the old fanin entry by the new fanin entry (removes polarity)
+ Vec_FanWriteEntry( &pObj->vFanins, iFanin, Vec_Int2Fan(pFaninNewR->Id) );
+ // set the polarity of the new fanin
+ if ( fCompl ^ Abc_ObjIsComplement(pFaninNew) )
+ Abc_ObjSetFaninC( pObj, iFanin );
+ // update the fanout of the fanin
+ if ( !Vec_FanDeleteEntry( &pFaninOld->vFanouts, pObj->Id ) )
+ {
+ printf( "The node %d is not among the fanouts of its old fanin %d...\n", pObj->Id, pFaninOld->Id );
+ return;
+ }
+ Vec_FanPush( pObj->pNtk->pMmStep, &pFaninNewR->vFanouts, Vec_Int2Fan(pObj->Id) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Transfers fanout from the old node to the new node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_ObjTransferFanout( Abc_Obj_t * pNodeFrom, Abc_Obj_t * pNodeTo )
+{
+ Vec_Ptr_t * vFanouts = pNodeFrom->pNtk->vPtrTemp;
+ int nFanoutsOld, i;
+ assert( !Abc_ObjIsComplement(pNodeFrom) );
+ assert( !Abc_ObjIsComplement(pNodeTo) );
+ assert( Abc_ObjIsNode(pNodeFrom) );
+ assert( Abc_ObjIsNode(pNodeTo) );
+ assert( pNodeFrom->pNtk == pNodeTo->pNtk );
+ assert( pNodeFrom != pNodeTo );
+ assert( Abc_ObjFanoutNum(pNodeFrom) > 0 );
+ // get the fanouts of the old node
+ nFanoutsOld = Abc_ObjFanoutNum(pNodeTo);
+ Abc_NodeCollectFanouts( pNodeFrom, vFanouts );
+ // patch the fanin of each of them
+ for ( i = 0; i < vFanouts->nSize; i++ )
+ Abc_ObjPatchFanin( vFanouts->pArray[i], pNodeFrom, pNodeTo );
+ assert( Abc_ObjFanoutNum(pNodeFrom) == 0 );
+ assert( Abc_ObjFanoutNum(pNodeTo) == nFanoutsOld + vFanouts->nSize );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Replaces the node by a new node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_ObjReplace( Abc_Obj_t * pNodeOld, Abc_Obj_t * pNodeNew )
+{
+ assert( !Abc_ObjIsComplement(pNodeOld) );
+ assert( !Abc_ObjIsComplement(pNodeNew) );
+ assert( Abc_ObjIsNode(pNodeOld) );
+ assert( Abc_ObjIsNode(pNodeNew) );
+ assert( pNodeOld->pNtk == pNodeNew->pNtk );
+ assert( pNodeOld != pNodeNew );
+ assert( Abc_ObjFanoutNum(pNodeOld) > 0 );
+ assert( Abc_ObjFanoutNum(pNodeNew) == 0 );
+ // transfer the fanouts to the old node
+ Abc_ObjTransferFanout( pNodeOld, pNodeNew );
+ // remove the old node
+ Abc_NtkDeleteObj( pNodeOld );
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcFpga.c b/src/base/abc/abcFpga.c
new file mode 100644
index 00000000..975fbc98
--- /dev/null
+++ b/src/base/abc/abcFpga.c
@@ -0,0 +1,247 @@
+/**CFile****************************************************************
+
+ FileName [abcFpga.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Interface with the FPGA mapping package.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcFpga.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+#include "fpgaInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static Fpga_Man_t * Abc_NtkToFpga( Abc_Ntk_t * pNtk, int fRecovery, int fVerbose );
+static Abc_Ntk_t * Abc_NtkFromFpga( Fpga_Man_t * pMan, Abc_Ntk_t * pNtk );
+static Abc_Obj_t * Abc_NodeFromFpga_rec( Abc_Ntk_t * pNtkNew, Fpga_Node_t * pNodeFpga );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Interface with the FPGA mapping package.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Abc_NtkFpga( Abc_Ntk_t * pNtk, int fRecovery, int fVerbose )
+{
+ int fCheck = 1;
+ Abc_Ntk_t * pNtkNew;
+ Fpga_Man_t * pMan;
+
+ assert( Abc_NtkIsAig(pNtk) );
+
+ // print a warning about choice nodes
+ if ( Abc_NtkCountChoiceNodes( pNtk ) )
+ printf( "Performing FPGA mapping with choices.\n" );
+
+ // perform FPGA mapping
+ pMan = Abc_NtkToFpga( pNtk, fRecovery, fVerbose );
+ if ( pMan == NULL )
+ return NULL;
+ if ( !Fpga_Mapping( pMan ) )
+ {
+ Fpga_ManFree( pMan );
+ return NULL;
+ }
+
+ // transform the result of mapping into a BDD network
+ pNtkNew = Abc_NtkFromFpga( pMan, pNtk );
+ if ( pNtkNew == NULL )
+ return NULL;
+ Fpga_ManFree( pMan );
+
+ // make the network minimum base
+ Abc_NtkMinimumBase( pNtkNew );
+
+ // make sure that everything is okay
+ if ( fCheck && !Abc_NtkCheck( pNtkNew ) )
+ {
+ printf( "Abc_NtkFpga: The network check has failed.\n" );
+ Abc_NtkDelete( pNtkNew );
+ return NULL;
+ }
+ return pNtkNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Load the network into FPGA manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_Man_t * Abc_NtkToFpga( Abc_Ntk_t * pNtk, int fRecovery, int fVerbose )
+{
+ Fpga_Man_t * pMan;
+ ProgressBar * pProgress;
+ Fpga_Node_t * pNodeFpga;
+ Vec_Ptr_t * vNodes;
+ Abc_Obj_t * pNode, * pFanin, * pPrev;
+ int i;
+
+ assert( Abc_NtkIsAig(pNtk) );
+
+ // start the mapping manager and set its parameters
+ pMan = Fpga_ManCreate( Abc_NtkPiNum(pNtk) + Abc_NtkLatchNum(pNtk), Abc_NtkPoNum(pNtk) + Abc_NtkLatchNum(pNtk), fVerbose );
+ if ( pMan == NULL )
+ return NULL;
+ Fpga_ManSetAreaRecovery( pMan, fRecovery );
+ Fpga_ManSetOutputNames( pMan, (char **)pNtk->vNamesPo->pArray );
+ Fpga_ManSetInputArrivals( pMan, Abc_NtkGetCiArrivalFloats(pNtk) );
+
+ // create PIs and remember them in the old nodes
+ Abc_NtkCleanCopy( pNtk );
+ Abc_NtkForEachCi( pNtk, pNode, i )
+ pNode->pCopy = (Abc_Obj_t *)Fpga_ManReadInputs(pMan)[i];
+
+ // load the AIG into the mapper
+ vNodes = Abc_AigDfs( pNtk );
+ pProgress = Extra_ProgressBarStart( stdout, vNodes->nSize );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ {
+ Extra_ProgressBarUpdate( pProgress, i, NULL );
+ // consider the case of a constant
+ pNode = vNodes->pArray[i];
+ if ( Abc_NodeIsConst(pNode) )
+ {
+ Abc_AigConst1(pNtk->pManFunc)->pCopy = (Abc_Obj_t *)Fpga_ManReadConst1(pMan);
+ continue;
+ }
+ // add the node to the mapper
+ pNodeFpga = Fpga_NodeAnd( pMan,
+ Fpga_NotCond( Abc_ObjFanin0(pNode)->pCopy, Abc_ObjFaninC0(pNode) ),
+ Fpga_NotCond( Abc_ObjFanin1(pNode)->pCopy, Abc_ObjFaninC1(pNode) ) );
+ assert( pNode->pCopy == NULL );
+ // remember the node
+ pNode->pCopy = (Abc_Obj_t *)pNodeFpga;
+ // set up the choice node
+ if ( Abc_NodeIsChoice( pNode ) )
+ for ( pPrev = pNode, pFanin = pNode->pData; pFanin; pPrev = pFanin, pFanin = pFanin->pData )
+ {
+ Fpga_NodeSetNextE( (Fpga_Node_t *)pPrev->pCopy, (Fpga_Node_t *)pFanin->pCopy );
+ Fpga_NodeSetRepr( (Fpga_Node_t *)pFanin->pCopy, (Fpga_Node_t *)pNode->pCopy );
+ }
+ }
+ Extra_ProgressBarStop( pProgress );
+ Vec_PtrFree( vNodes );
+
+ // set the primary outputs without copying the phase
+ Abc_NtkForEachCo( pNtk, pNode, i )
+ Fpga_ManReadOutputs(pMan)[i] = (Fpga_Node_t *)Abc_ObjFanin0(pNode)->pCopy;
+ return pMan;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates the mapped network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Abc_NtkFromFpga( Fpga_Man_t * pMan, Abc_Ntk_t * pNtk )
+{
+ ProgressBar * pProgress;
+ Abc_Ntk_t * pNtkNew;
+ Abc_Obj_t * pNode, * pNodeNew;
+ int i, nDupGates;
+ // create the new network
+ pNtkNew = Abc_NtkStartFrom( pNtk, ABC_NTK_LOGIC_BDD );
+ // make the mapper point to the new network
+ Fpga_CutsCleanSign( pMan );
+ Fpga_ManCleanData0( pMan );
+ Abc_NtkForEachCi( pNtk, pNode, i )
+ Fpga_NodeSetData0( Fpga_ManReadInputs(pMan)[i], (char *)pNode->pCopy );
+ // set the constant node
+ if ( Abc_ObjFanoutNum( Abc_AigConst1(pNtk->pManFunc) ) > 0 )
+ Fpga_NodeSetData0( Fpga_ManReadConst1(pMan), (char *)Abc_NodeCreateConst1(pNtkNew) );
+ // process the nodes in topological order
+ pProgress = Extra_ProgressBarStart( stdout, Abc_NtkCoNum(pNtk) );
+ Abc_NtkForEachCo( pNtk, pNode, i )
+ {
+ Extra_ProgressBarUpdate( pProgress, i, NULL );
+ pNodeNew = Abc_NodeFromFpga_rec( pNtkNew, Fpga_ManReadOutputs(pMan)[i] );
+ assert( !Abc_ObjIsComplement(pNodeNew) );
+ Abc_ObjFanin0(pNode)->pCopy = pNodeNew;
+ }
+ Extra_ProgressBarStop( pProgress );
+ // finalize the new network
+ Abc_NtkFinalize( pNtk, pNtkNew );
+ // decouple the PO driver nodes to reduce the number of levels
+ nDupGates = Abc_NtkLogicMakeSimplePos( pNtkNew );
+ if ( nDupGates && Fpga_ManReadVerbose(pMan) )
+ printf( "Duplicated %d gates to decouple the PO drivers.\n", nDupGates );
+ return pNtkNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Derive one node after FPGA mapping.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NodeFromFpga_rec( Abc_Ntk_t * pNtkNew, Fpga_Node_t * pNodeFpga )
+{
+ Fpga_Cut_t * pCutBest;
+ Fpga_Node_t ** ppLeaves;
+ Abc_Obj_t * pNodeNew;
+ int i, nLeaves;
+ assert( !Fpga_IsComplement(pNodeFpga) );
+ // return if the result if known
+ pNodeNew = (Abc_Obj_t *)Fpga_NodeReadData0( pNodeFpga );
+ if ( pNodeNew )
+ return pNodeNew;
+ assert( Fpga_NodeIsAnd(pNodeFpga) );
+ // get the parameters of the best cut
+ pCutBest = Fpga_NodeReadCutBest( pNodeFpga );
+ ppLeaves = Fpga_CutReadLeaves( pCutBest );
+ nLeaves = Fpga_CutReadLeavesNum( pCutBest );
+ // create a new node
+ pNodeNew = Abc_NtkCreateNode( pNtkNew );
+ for ( i = 0; i < nLeaves; i++ )
+ Abc_ObjAddFanin( pNodeNew, Abc_NodeFromFpga_rec(pNtkNew, ppLeaves[i]) );
+ // derive the function of this node
+ pNodeNew->pData = Fpga_TruthsCutBdd( pNtkNew->pManFunc, pCutBest ); Cudd_Ref( pNodeNew->pData );
+ Fpga_NodeSetData0( pNodeFpga, (char *)pNodeNew );
+ return pNodeNew;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcFraig.c b/src/base/abc/abcFraig.c
new file mode 100644
index 00000000..85dba6f3
--- /dev/null
+++ b/src/base/abc/abcFraig.c
@@ -0,0 +1,585 @@
+/**CFile****************************************************************
+
+ FileName [abcFraig.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Procedures interfacing with the FRAIG package.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcFraig.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+#include "fraig.h"
+#include "main.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+extern Fraig_Man_t * Abc_NtkToFraig( Abc_Ntk_t * pNtk, Fraig_Params_t * pParams, int fAllNodes );
+static Abc_Ntk_t * Abc_NtkFromFraig( Fraig_Man_t * pMan, Abc_Ntk_t * pNtk );
+static Abc_Obj_t * Abc_NodeFromFraig_rec( Abc_Ntk_t * pNtkNew, Fraig_Node_t * pNodeFraig );
+
+static int Abc_NtkFraigTrustCheck( Abc_Ntk_t * pNtk );
+static void Abc_NtkFraigTrustOne( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew );
+static Abc_Obj_t * Abc_NodeFraigTrust( Abc_Aig_t * pMan, Abc_Obj_t * pNode );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Interfaces the network with the FRAIG package.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Abc_NtkFraig( Abc_Ntk_t * pNtk, void * pParams, int fAllNodes )
+{
+ int fCheck = 1;
+ Abc_Ntk_t * pNtkNew;
+ Fraig_Man_t * pMan;
+ // perform fraiging
+ pMan = Abc_NtkToFraig( pNtk, pParams, fAllNodes );
+ // prove the miter if asked to
+ if ( ((Fraig_Params_t *)pParams)->fTryProve )
+ Fraig_ManProveMiter( pMan );
+ // reconstruct FRAIG in the new network
+ pNtkNew = Abc_NtkFromFraig( pMan, pNtk );
+ Fraig_ManFree( pMan );
+ // make sure that everything is okay
+ if ( fCheck && !Abc_NtkCheck( pNtkNew ) )
+ {
+ printf( "Abc_NtkFraig: The network check has failed.\n" );
+ Abc_NtkDelete( pNtkNew );
+ return NULL;
+ }
+ return pNtkNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Transforms the strashed network into FRAIG.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_Man_t * Abc_NtkToFraig( Abc_Ntk_t * pNtk, Fraig_Params_t * pParams, int fAllNodes )
+{
+ Fraig_Man_t * pMan;
+ ProgressBar * pProgress;
+ Fraig_Node_t * pNodeFraig;
+ Vec_Ptr_t * vNodes;
+ Abc_Obj_t * pNode, * pConst1;
+ int i;
+
+ assert( Abc_NtkIsAig(pNtk) );
+
+ // create the FRAIG manager
+ pMan = Fraig_ManCreate( pParams );
+
+ // create PIs and remember them in the old nodes
+ Abc_NtkCleanCopy( pNtk );
+ Abc_NtkForEachCi( pNtk, pNode, i )
+ pNode->pCopy = (Abc_Obj_t *)Fraig_ManReadIthVar(pMan, i);
+ pConst1 = Abc_AigConst1( pNtk->pManFunc );
+
+ // perform strashing
+ if ( fAllNodes )
+ vNodes = Abc_AigCollectAll( pNtk );
+ else
+ vNodes = Abc_AigDfs( pNtk );
+ pProgress = Extra_ProgressBarStart( stdout, vNodes->nSize );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ {
+ Extra_ProgressBarUpdate( pProgress, i, NULL );
+ pNode = vNodes->pArray[i];
+ if ( pNode == pConst1 )
+ pNodeFraig = Fraig_ManReadConst1(pMan);
+ else
+ pNodeFraig = Fraig_NodeAnd( pMan,
+ Fraig_NotCond( Abc_ObjFanin0(pNode)->pCopy, Abc_ObjFaninC0(pNode) ),
+ Fraig_NotCond( Abc_ObjFanin1(pNode)->pCopy, Abc_ObjFaninC1(pNode) ) );
+ assert( pNode->pCopy == NULL );
+ pNode->pCopy = (Abc_Obj_t *)pNodeFraig;
+ }
+ Extra_ProgressBarStop( pProgress );
+ Vec_PtrFree( vNodes );
+
+ // set the primary outputs
+ Abc_NtkForEachCo( pNtk, pNode, i )
+ Fraig_ManSetPo( pMan, (Fraig_Node_t *)Abc_ObjFanin0(pNode)->pCopy );
+ return pMan;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Transforms FRAIG into what looks like a strashed network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Abc_NtkFromFraig( Fraig_Man_t * pMan, Abc_Ntk_t * pNtk )
+{
+ ProgressBar * pProgress;
+ Abc_Ntk_t * pNtkNew;
+ Abc_Obj_t * pNode;//, * pNodeNew;
+ int i;
+ // create the new network
+ pNtkNew = Abc_NtkStartFrom( pNtk, ABC_NTK_AIG );
+ // make the mapper point to the new network
+ Abc_NtkForEachCi( pNtk, pNode, i )
+ Fraig_NodeSetData1( Fraig_ManReadIthVar(pMan, i), (Fraig_Node_t *)pNode->pCopy );
+ // set the constant node
+ Fraig_NodeSetData1( Fraig_ManReadConst1(pMan), (Fraig_Node_t *)Abc_AigConst1(pNtkNew->pManFunc) );
+ // process the nodes in topological order
+ pProgress = Extra_ProgressBarStart( stdout, Abc_NtkCoNum(pNtk) );
+ Abc_NtkForEachCo( pNtk, pNode, i )
+ {
+ Extra_ProgressBarUpdate( pProgress, i, NULL );
+ Abc_ObjFanin0(pNode)->pCopy = Abc_NodeFromFraig_rec( pNtkNew, Fraig_ManReadOutputs(pMan)[i] );
+ }
+ Extra_ProgressBarStop( pProgress );
+ // finalize the new network
+ Abc_NtkFinalize( pNtk, pNtkNew );
+ return pNtkNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Transforms into AIG one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NodeFromFraig_rec( Abc_Ntk_t * pNtkNew, Fraig_Node_t * pNodeFraig )
+{
+ Abc_Obj_t * pRes, * pRes0, * pRes1, * pResMin, * pResCur;
+ Fraig_Node_t * pNodeTemp, * pNodeFraigR = Fraig_Regular(pNodeFraig);
+ void ** ppTail;
+ // check if the node was already considered
+ if ( pRes = (Abc_Obj_t *)Fraig_NodeReadData1(pNodeFraigR) )
+ return Abc_ObjNotCond( pRes, Fraig_IsComplement(pNodeFraig) );
+ // solve the children
+ pRes0 = Abc_NodeFromFraig_rec( pNtkNew, Fraig_NodeReadOne(pNodeFraigR) );
+ pRes1 = Abc_NodeFromFraig_rec( pNtkNew, Fraig_NodeReadTwo(pNodeFraigR) );
+ // derive the new node
+ pRes = Abc_AigAnd( pNtkNew->pManFunc, pRes0, pRes1 );
+ pRes->fPhase = Fraig_NodeReadSimInv( pNodeFraigR );
+ // if the node has an equivalence class, find its representative
+ if ( Fraig_NodeReadRepr(pNodeFraigR) == NULL && Fraig_NodeReadNextE(pNodeFraigR) != NULL )
+ {
+ // go through the FRAIG nodes belonging to this equivalence class
+ // and find the representative node (the node with the smallest level)
+ pResMin = pRes;
+ for ( pNodeTemp = Fraig_NodeReadNextE(pNodeFraigR); pNodeTemp; pNodeTemp = Fraig_NodeReadNextE(pNodeTemp) )
+ {
+ assert( Fraig_NodeReadData1(pNodeTemp) == NULL );
+ pResCur = Abc_NodeFromFraig_rec( pNtkNew, pNodeTemp );
+ if ( pResMin->Level > pResCur->Level )
+ pResMin = pResCur;
+ }
+ // link the nodes in such a way that representative goes first
+ ppTail = &pResMin->pData;
+ if ( pRes != pResMin )
+ {
+ *ppTail = pRes;
+ ppTail = &pRes->pData;
+ }
+ for ( pNodeTemp = Fraig_NodeReadNextE(pNodeFraigR); pNodeTemp; pNodeTemp = Fraig_NodeReadNextE(pNodeTemp) )
+ {
+ pResCur = (Abc_Obj_t *)Fraig_NodeReadData1(pNodeTemp);
+ assert( pResCur );
+ if ( pResMin == pResCur )
+ continue;
+ *ppTail = pResCur;
+ ppTail = &pResCur->pData;
+ }
+ assert( *ppTail == NULL );
+
+ // update the phase of the node
+ pRes = Abc_ObjNotCond( pResMin, (pRes->fPhase ^ pResMin->fPhase) );
+ }
+ Fraig_NodeSetData1( pNodeFraigR, (Fraig_Node_t *)pRes );
+ return Abc_ObjNotCond( pRes, Fraig_IsComplement(pNodeFraig) );
+}
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Interfaces the network with the FRAIG package.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Abc_NtkFraigTrust( Abc_Ntk_t * pNtk )
+{
+ int fCheck = 1;
+ Abc_Ntk_t * pNtkNew;
+
+ if ( !Abc_NtkIsNetlist(pNtk) && !Abc_NtkIsLogicSop(pNtk) )
+ {
+ printf( "Abc_NtkFraigTrust: Trust mode works for netlists and logic SOP networks.\n" );
+ return NULL;
+ }
+
+ if ( !Abc_NtkFraigTrustCheck(pNtk) )
+ {
+ printf( "Abc_NtkFraigTrust: The network does not look like an AIG with choice nodes.\n" );
+ return NULL;
+ }
+
+ // perform strashing
+ pNtkNew = Abc_NtkStartFrom( pNtk, ABC_NTK_AIG );
+ Abc_NtkFraigTrustOne( pNtk, pNtkNew );
+ Abc_NtkFinalize( pNtk, pNtkNew );
+
+ // print a warning about choice nodes
+ printf( "Warning: The resulting AIG contains %d choice nodes.\n", Abc_NtkCountChoiceNodes( pNtkNew ) );
+
+ // make sure that everything is okay
+ if ( fCheck && !Abc_NtkCheck( pNtkNew ) )
+ {
+ printf( "Abc_NtkFraigTrust: The network check has failed.\n" );
+ Abc_NtkDelete( pNtkNew );
+ return NULL;
+ }
+ return pNtkNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks whether the node can be processed in the trust mode.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkFraigTrustCheck( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ int i, nFanins;
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ nFanins = Abc_ObjFaninNum(pNode);
+ if ( nFanins < 2 )
+ continue;
+ if ( nFanins == 2 && Abc_SopIsAndType(pNode->pData) )
+ continue;
+ if ( !Abc_SopIsOrType(pNode->pData) )
+ return 0;
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Interfaces the network with the FRAIG package.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkFraigTrustOne( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew )
+{
+ ProgressBar * pProgress;
+ Abc_Aig_t * pMan = pNtkNew->pManFunc;
+ Vec_Ptr_t * vNodes;
+ Abc_Obj_t * pNode, * pNodeNew, * pObj;
+ int i;
+
+ // perform strashing
+ vNodes = Abc_NtkDfs( pNtk );
+ pProgress = Extra_ProgressBarStart( stdout, vNodes->nSize );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ {
+ Extra_ProgressBarUpdate( pProgress, i, NULL );
+ // get the node
+ pNode = vNodes->pArray[i];
+ assert( Abc_ObjIsNode(pNode) );
+ // strash the node
+ pNodeNew = Abc_NodeFraigTrust( pMan, pNode );
+ // get the old object
+ if ( Abc_NtkIsNetlist(pNtk) )
+ pObj = Abc_ObjFanout0( pNode ); // the fanout net
+ else
+ pObj = pNode; // the node itself
+ // make sure the node is not yet strashed
+ assert( pObj->pCopy == NULL );
+ // mark the old object with the new AIG node
+ pObj->pCopy = pNodeNew;
+ }
+ Vec_PtrFree( vNodes );
+ Extra_ProgressBarStop( pProgress );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Transforms one node into a FRAIG in the trust mode.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NodeFraigTrust( Abc_Aig_t * pMan, Abc_Obj_t * pNode )
+{
+ Abc_Obj_t * pSum, * pFanin;
+ Abc_Obj_t * pConst1 = Abc_AigConst1(pMan);
+ void ** ppTail;
+ int i, nFanins, fCompl;
+
+ assert( Abc_ObjIsNode(pNode) );
+ // get the number of node's fanins
+ nFanins = Abc_ObjFaninNum( pNode );
+ assert( nFanins == Abc_SopGetVarNum(pNode->pData) );
+ // check if it is a constant
+ if ( nFanins == 0 )
+ return Abc_ObjNotCond( pConst1, Abc_SopIsConst0(pNode->pData) );
+ if ( nFanins == 1 )
+ return Abc_ObjNotCond( Abc_ObjFanin0(pNode)->pCopy, Abc_SopIsInv(pNode->pData) );
+ if ( nFanins == 2 && Abc_SopIsAndType(pNode->pData) )
+ return Abc_AigAnd( pMan,
+ Abc_ObjNotCond( Abc_ObjFanin0(pNode)->pCopy, !Abc_SopGetIthCareLit(pNode->pData,0) ),
+ Abc_ObjNotCond( Abc_ObjFanin1(pNode)->pCopy, !Abc_SopGetIthCareLit(pNode->pData,1) ) );
+ assert( Abc_SopIsOrType(pNode->pData) );
+ fCompl = Abc_SopGetIthCareLit(pNode->pData,0);
+ // get the root of the choice node (the first fanin)
+ pSum = Abc_ObjFanin0(pNode)->pCopy;
+ // connect other fanins
+ ppTail = &pSum->pData;
+ Abc_ObjForEachFanin( pNode, pFanin, i )
+ {
+ if ( i == 0 )
+ continue;
+ *ppTail = pFanin->pCopy;
+ ppTail = &pFanin->pCopy->pData;
+ // set the complemented bit of this cut
+ if ( fCompl ^ Abc_SopGetIthCareLit(pNode->pData, i) )
+ pFanin->pCopy->fPhase = 1;
+ }
+ assert( *ppTail == NULL );
+ return pSum;
+}
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Interfaces the network with the FRAIG package.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkFraigStore( Abc_Ntk_t * pNtk )
+{
+ Abc_Frame_t * p;
+ Abc_Ntk_t * pStore;
+ int nAndsOld;
+
+ if ( !Abc_NtkIsLogic(pNtk) && !Abc_NtkIsAig(pNtk) )
+ {
+ printf( "Convert netlist into a logic network before adding to storage.\n" );
+ return 0;
+ }
+
+ // get the network currently stored
+ p = Abc_FrameGetGlobalFrame();
+ pStore = Abc_FrameReadNtkStore(p);
+ if ( pStore == NULL )
+ {
+ // start the stored network
+ pStore = Abc_NtkStrash( pNtk );
+ if ( pStore == NULL )
+ {
+ printf( "Abc_NtkFraigStore: Initial strashing has failed.\n" );
+ return 0;
+ }
+ // save the parameters
+ Abc_FrameSetNtkStore( p, pStore );
+ Abc_FrameSetNtkStoreSize( p, 1 );
+ nAndsOld = 0;
+ }
+ else
+ {
+ // add the new network to storage
+ nAndsOld = Abc_NtkNodeNum( pStore );
+ if ( !Abc_NtkAppend( pStore, pNtk ) )
+ {
+ printf( "The current network cannot be appended to the stored network.\n" );
+ return 0;
+ }
+ // set the number of networks stored
+ Abc_FrameSetNtkStoreSize( p, Abc_FrameReadNtkStoreSize(p) + 1 );
+ }
+ printf( "The number of AIG nodes added to storage = %5d.\n", Abc_NtkNodeNum(pStore) - nAndsOld );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Interfaces the network with the FRAIG package.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Abc_NtkFraigRestore()
+{
+ Abc_Frame_t * p;
+ Fraig_Params_t Params;
+ Abc_Ntk_t * pStore, * pFraig;
+ int nWords1, nWords2, nWordsMin;
+
+ // get the stored network
+ p = Abc_FrameGetGlobalFrame();
+ pStore = Abc_FrameReadNtkStore(p);
+ Abc_FrameSetNtkStore( p, NULL );
+ if ( pStore == NULL )
+ {
+ printf( "There are no network currently in storage.\n" );
+ return NULL;
+ }
+ printf( "Currently stored %d networks with %d nodes will be fraiged.\n",
+ Abc_FrameReadNtkStoreSize(p), Abc_NtkNodeNum(pStore) );
+
+ // to determine the number of simulation patterns
+ // use the following strategy
+ // at least 64 words (32 words random and 32 words dynamic)
+ // no more than 256M for one circuit (128M + 128M)
+ nWords1 = 32;
+ nWords2 = (1<<27) / (Abc_NtkNodeNum(pStore) + Abc_NtkCiNum(pStore));
+ nWordsMin = ABC_MIN( nWords1, nWords2 );
+
+ // set parameters for fraiging
+ Fraig_ParamsSetDefault( &Params );
+ Params.nPatsRand = nWordsMin * 32; // the number of words of random simulation info
+ Params.nPatsDyna = nWordsMin * 32; // the number of words of dynamic simulation info
+ Params.nBTLimit = 99; // the max number of backtracks to perform
+ Params.fFuncRed = 1; // performs only one level hashing
+ Params.fFeedBack = 1; // enables solver feedback
+ Params.fDist1Pats = 1; // enables distance-1 patterns
+ Params.fDoSparse = 1; // performs equiv tests for sparse functions
+ Params.fChoicing = 1; // enables recording structural choices
+ Params.fTryProve = 0; // tries to solve the final miter
+ Params.fVerbose = 0; // the verbosiness flag
+
+// Fraig_ManReportChoices( p );
+ // transform it into FRAIG
+ pFraig = Abc_NtkFraig( pStore, &Params, 1 );
+ if ( pFraig == NULL )
+ return NULL;
+ Abc_NtkDelete( pStore );
+ return pFraig;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Interfaces the network with the FRAIG package.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkFraigStoreClean()
+{
+ Abc_Frame_t * p;
+ Abc_Ntk_t * pStore;
+ // get the stored network
+ p = Abc_FrameGetGlobalFrame();
+ pStore = Abc_FrameReadNtkStore(p);
+ if ( pStore )
+ Abc_NtkDelete( pStore );
+ Abc_FrameSetNtkStore( p, NULL );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks the correctness of stored networks.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkFraigStoreCheck( Abc_Ntk_t * pFraig )
+{
+ Abc_Obj_t * pNode0, * pNode1;
+ int nPoOrig, nPoFinal, nStored;
+ int i, k;
+ // check that the PO functions are correct
+ nPoFinal = Abc_NtkPoNum(pFraig);
+ nStored = Abc_FrameReadNtkStoreSize(Abc_FrameGetGlobalFrame());
+ assert( nPoFinal % nStored == 0 );
+ nPoOrig = nPoFinal / nStored;
+ for ( i = 0; i < nPoOrig; i++ )
+ {
+ pNode0 = Abc_ObjFanin0( Abc_NtkPo(pFraig, i) );
+ for ( k = 1; k < nStored; k++ )
+ {
+ pNode1 = Abc_ObjFanin0( Abc_NtkPo(pFraig, k*nPoOrig+i) );
+ if ( pNode0 != pNode1 )
+ printf( "Verification for PO #%d of network #%d has failed. The PO function is not used.\n", i+1, k+1 );
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcFunc.c b/src/base/abc/abcFunc.c
new file mode 100644
index 00000000..59f0dc34
--- /dev/null
+++ b/src/base/abc/abcFunc.c
@@ -0,0 +1,419 @@
+/**CFile****************************************************************
+
+ FileName [abcFunc.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Transformations between different functionality representations.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcFunc.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static DdNode * Abc_ConvertSopToBdd( DdManager * dd, char * pSop, int nFanins );
+static int Abc_ConvertZddToSop( DdManager * dd, DdNode * zCover, char * pSop, int nFanins, Vec_Str_t * vCube, int fPhase );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Converts the network from SOP to BDD representation.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkSopToBdd( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ DdManager * dd;
+ int nFaninsMax, i;
+
+ assert( Abc_NtkIsLogicSop(pNtk) );
+
+ // start the functionality manager
+ nFaninsMax = Abc_NtkGetFaninMax( pNtk );
+ if ( nFaninsMax == 0 )
+ printf( "Warning: The network has only constant nodes.\n" );
+
+ dd = Cudd_Init( nFaninsMax, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 );
+
+ // convert each node from SOP to BDD
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ assert( pNode->pData );
+ pNode->pData = Abc_ConvertSopToBdd( dd, pNode->pData, Abc_ObjFaninNum(pNode) );
+ if ( pNode->pData == NULL )
+ {
+ printf( "Abc_NtkSopToBdd: Error while converting SOP into BDD.\n" );
+ return 0;
+ }
+ Cudd_Ref( pNode->pData );
+ }
+
+ Extra_MmFlexStop( pNtk->pManFunc, 0 );
+ pNtk->pManFunc = dd;
+
+ // update the network type
+ pNtk->Type = ABC_NTK_LOGIC_BDD;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Converts the node from SOP to BDD representation.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Abc_ConvertSopToBdd( DdManager * dd, char * pSop, int nFanins )
+{
+ DdNode * bCube, * bTemp, * bVar, * bRes;
+ char * pCube;
+ int i, c;
+
+ bRes = Cudd_Not(dd->one); Cudd_Ref( bRes );
+ for ( c = 0; ; c++ )
+ {
+ // get the cube
+ pCube = pSop + c * (nFanins + 3);
+ if ( *pCube == 0 )
+ break;
+ // construct BDD for the cube
+ bCube = dd->one; Cudd_Ref( bCube );
+ for ( i = 0; i < nFanins; i++ )
+ {
+ if ( pCube[i] == '0' )
+ bVar = Cudd_Not( dd->vars[i] );
+ else if ( pCube[i] == '1' )
+ bVar = dd->vars[i];
+ else
+ continue;
+ bCube = Cudd_bddAnd( dd, bTemp = bCube, bVar ); Cudd_Ref( bCube );
+ Cudd_RecursiveDeref( dd, bTemp );
+ }
+ bRes = Cudd_bddOr( dd, bTemp = bRes, bCube ); Cudd_Ref( bRes );
+ Cudd_RecursiveDeref( dd, bTemp );
+ Cudd_RecursiveDeref( dd, bCube );
+ }
+ // decide if we need to complement the result
+ pCube = pSop + nFanins + 1;
+ assert( *pCube == '0' || *pCube == '1' );
+ if ( *pCube == '0' )
+ bRes = Cudd_Not(bRes);
+ Cudd_Deref( bRes );
+ return bRes;
+}
+
+
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Converts the network from BDD to SOP representation.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkBddToSop( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ DdManager * dd = pNtk->pManFunc;
+ DdNode * bFunc;
+ int RetValue, i;
+ Vec_Str_t * vCube;
+
+ assert( Abc_NtkIsLogicBdd(pNtk) );
+ Cudd_zddVarsFromBddVars( dd, 2 );
+ // allocate the new manager
+ pNtk->pManFunc = Extra_MmFlexStart();
+ // update the network type
+ pNtk->Type = ABC_NTK_LOGIC_SOP;
+
+ // go through the objects
+ vCube = Vec_StrAlloc( 100 );
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ assert( pNode->pData );
+ bFunc = pNode->pData;
+//Extra_bddPrint( dd, bFunc ); printf( "\n" ); printf( "\n" );
+ pNode->pData = Abc_ConvertBddToSop( pNtk->pManFunc, dd, bFunc, Abc_ObjFaninNum(pNode), vCube, -1 );
+ if ( pNode->pData == NULL )
+ return 0;
+ Cudd_RecursiveDeref( dd, bFunc );
+ }
+ Vec_StrFree( vCube );
+
+ // check for remaining references in the package
+ RetValue = Cudd_CheckZeroRef( dd );
+ if ( RetValue > 0 )
+ printf( "\nThe number of referenced nodes = %d\n\n", RetValue );
+// Cudd_PrintInfo( dd, stdout );
+ Cudd_Quit( dd );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Converts the node from BDD to SOP representation.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Abc_ConvertBddToSop( Extra_MmFlex_t * pMan, DdManager * dd, DdNode * bFunc, int nFanins, Vec_Str_t * vCube, int fMode )
+{
+ char * pSop;
+ DdNode * bFuncNew, * bCover, * zCover, * zCover0, * zCover1;
+ int nCubes, nCubes0, nCubes1, fPhase;
+
+ if ( Cudd_IsConstant(bFunc) )
+ {
+ Vec_StrFill( vCube, nFanins, '-' );
+ Vec_StrPush( vCube, '\0' );
+ pSop = Extra_MmFlexEntryFetch( pMan, nFanins + 4 );
+ if ( bFunc == Cudd_ReadLogicZero(dd) )
+ sprintf( pSop, "%s 0\n", vCube->pArray );
+ else
+ sprintf( pSop, "%s 1\n", vCube->pArray );
+ return pSop;
+ }
+
+
+ if ( fMode == -1 )
+ { // try both phases
+
+ // get the ZDD of the negative polarity
+ bCover = Cudd_zddIsop( dd, Cudd_Not(bFunc), Cudd_Not(bFunc), &zCover0 );
+ Cudd_Ref( zCover0 );
+ Cudd_Ref( bCover );
+ Cudd_RecursiveDeref( dd, bCover );
+ nCubes0 = Abc_CountZddCubes( dd, zCover0 );
+
+ // get the ZDD of the positive polarity
+ bCover = Cudd_zddIsop( dd, bFunc, bFunc, &zCover1 );
+ Cudd_Ref( zCover1 );
+ Cudd_Ref( bCover );
+ Cudd_RecursiveDeref( dd, bCover );
+ nCubes1 = Abc_CountZddCubes( dd, zCover1 );
+
+ // compare the number of cubes
+ if ( nCubes1 <= nCubes0 )
+ { // use positive polarity
+ nCubes = nCubes1;
+ zCover = zCover1;
+ Cudd_RecursiveDerefZdd( dd, zCover0 );
+ fPhase = 1;
+ }
+ else
+ { // use negative polarity
+ nCubes = nCubes0;
+ zCover = zCover0;
+ Cudd_RecursiveDerefZdd( dd, zCover1 );
+ fPhase = 0;
+ }
+ }
+ else if ( fMode == 0 )
+ {
+ // get the ZDD of the positive polarity
+ bCover = Cudd_zddIsop( dd, Cudd_Not(bFunc), Cudd_Not(bFunc), &zCover );
+ Cudd_Ref( zCover );
+ Cudd_Ref( bCover );
+ Cudd_RecursiveDeref( dd, bCover );
+ nCubes = Abc_CountZddCubes( dd, zCover );
+ fPhase = 0;
+ }
+ else if ( fMode == 1 )
+ {
+ // get the ZDD of the positive polarity
+ bCover = Cudd_zddIsop( dd, bFunc, bFunc, &zCover );
+ Cudd_Ref( zCover );
+ Cudd_Ref( bCover );
+ Cudd_RecursiveDeref( dd, bCover );
+ nCubes = Abc_CountZddCubes( dd, zCover );
+ fPhase = 1;
+ }
+ else
+ {
+ assert( 0 );
+ }
+
+ // allocate memory for the cover
+ pSop = Extra_MmFlexEntryFetch( pMan, (nFanins + 3) * nCubes + 1 );
+ pSop[(nFanins + 3) * nCubes] = 0;
+ // create the SOP
+ Vec_StrFill( vCube, nFanins, '-' );
+ Vec_StrPush( vCube, '\0' );
+ Abc_ConvertZddToSop( dd, zCover, pSop, nFanins, vCube, fPhase );
+ Cudd_RecursiveDerefZdd( dd, zCover );
+
+ // verify
+ bFuncNew = Abc_ConvertSopToBdd( dd, pSop, nFanins ); Cudd_Ref( bFuncNew );
+//Extra_bddPrint( dd, bFunc );
+//Extra_bddPrint( dd, bFuncNew );
+ if ( bFuncNew != bFunc )
+ printf( "Verification failed.\n" );
+ Cudd_RecursiveDeref( dd, bFuncNew );
+ return pSop;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Derive the SOP from the ZDD representation of the cubes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_ConvertZddToSop_rec( DdManager * dd, DdNode * zCover, char * pSop, int nFanins, Vec_Str_t * vCube, int fPhase, int * pnCubes )
+{
+ DdNode * zC0, * zC1, * zC2;
+ int Index;
+
+ if ( zCover == dd->zero )
+ return;
+ if ( zCover == dd->one )
+ {
+ char * pCube;
+ pCube = pSop + (*pnCubes) * (nFanins + 3);
+ sprintf( pCube, "%s %d\n", vCube->pArray, fPhase );
+ (*pnCubes)++;
+ return;
+ }
+ Index = zCover->index/2;
+ assert( Index < nFanins );
+ extraDecomposeCover( dd, zCover, &zC0, &zC1, &zC2 );
+ vCube->pArray[Index] = '0';
+ Abc_ConvertZddToSop_rec( dd, zC0, pSop, nFanins, vCube, fPhase, pnCubes );
+ vCube->pArray[Index] = '1';
+ Abc_ConvertZddToSop_rec( dd, zC1, pSop, nFanins, vCube, fPhase, pnCubes );
+ vCube->pArray[Index] = '-';
+ Abc_ConvertZddToSop_rec( dd, zC2, pSop, nFanins, vCube, fPhase, pnCubes );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Derive the BDD for the function in the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_ConvertZddToSop( DdManager * dd, DdNode * zCover, char * pSop, int nFanins, Vec_Str_t * vCube, int fPhase )
+{
+ int nCubes = 0;
+ Abc_ConvertZddToSop_rec( dd, zCover, pSop, nFanins, vCube, fPhase, &nCubes );
+ return nCubes;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Computes the SOPs of the negative and positive phase of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NodeBddToCnf( Abc_Obj_t * pNode, Extra_MmFlex_t * pMmMan, Vec_Str_t * vCube, char ** ppSop0, char ** ppSop1 )
+{
+ assert( Abc_NtkIsLogicBdd(pNode->pNtk) );
+ *ppSop0 = Abc_ConvertBddToSop( pMmMan, pNode->pNtk->pManFunc, pNode->pData, Abc_ObjFaninNum(pNode), vCube, 0 );
+ *ppSop1 = Abc_ConvertBddToSop( pMmMan, pNode->pNtk->pManFunc, pNode->pData, Abc_ObjFaninNum(pNode), vCube, 1 );
+}
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Count the number of paths in the ZDD.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_CountZddCubes_rec( DdManager * dd, DdNode * zCover, int * pnCubes )
+{
+ DdNode * zC0, * zC1, * zC2;
+ if ( zCover == dd->zero )
+ return;
+ if ( zCover == dd->one )
+ {
+ (*pnCubes)++;
+ return;
+ }
+ extraDecomposeCover( dd, zCover, &zC0, &zC1, &zC2 );
+ Abc_CountZddCubes_rec( dd, zC0, pnCubes );
+ Abc_CountZddCubes_rec( dd, zC1, pnCubes );
+ Abc_CountZddCubes_rec( dd, zC2, pnCubes );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Count the number of paths in the ZDD.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_CountZddCubes( DdManager * dd, DdNode * zCover )
+{
+ int nCubes = 0;
+ Abc_CountZddCubes_rec( dd, zCover, &nCubes );
+ return nCubes;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcInt.h b/src/base/abc/abcInt.h
new file mode 100644
index 00000000..1a1ab75f
--- /dev/null
+++ b/src/base/abc/abcInt.h
@@ -0,0 +1,46 @@
+/**CFile****************************************************************
+
+ FileName [abcInt.h]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Internal declarations.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcInt.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __ABC_INT_H__
+#define __ABC_INT_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
+
+
diff --git a/src/base/abc/abcLatch.c b/src/base/abc/abcLatch.c
new file mode 100644
index 00000000..a5bb9544
--- /dev/null
+++ b/src/base/abc/abcLatch.c
@@ -0,0 +1,260 @@
+/**CFile****************************************************************
+
+ FileName [abcLatch.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Procedures working with latches.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcLatch.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Checks whether the network is combinational.]
+
+ Description [The network is combinational if it has no latches.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkIsComb( Abc_Ntk_t * pNtk )
+{
+ return pNtk->vLatches->nSize == 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Makes the network combinational.]
+
+ Description [If the network is sequential, the latches are disconnected,
+ while the latch inputs and outputs are added to the PIs and POs.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkMakeComb( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pLatch, * pNet;
+ int i;
+
+ if ( !Abc_NtkIsNetlist(pNtk) )
+ return 0;
+
+ // skip if the network is already combinational
+ if ( Abc_NtkIsComb( pNtk ) )
+ return 0;
+
+ // save the number of PIs/POs
+ assert( pNtk->nPisOld == 0 );
+ assert( pNtk->nPosOld == 0 );
+ pNtk->nPisOld = pNtk->vPis->nSize;
+ pNtk->nPosOld = pNtk->vPos->nSize;
+ if ( Abc_NtkIsNetlist(pNtk) )
+ {
+ // go through the latches
+ // - disconnect LO/LI nets from latches
+ // - add them to the PI/PO lists
+ Abc_NtkForEachLatch( pNtk, pLatch, i )
+ {
+ // process the input of the latch
+ pNet = Abc_ObjFanin0( pLatch );
+ assert( Abc_ObjIsLi( pNet ) );
+ if ( !Vec_FanDeleteEntry( &pNet->vFanouts, pLatch->Id ) )
+ {
+ printf( "Abc_NtkMakeComb: The latch is not found among the fanouts of the fanin net...\n" );
+ return 0;
+ }
+ if ( !Abc_ObjIsPo( pNet ) )
+ Abc_NtkMarkNetPo( pNet );
+
+ // process the output of the latch
+ pNet = Abc_ObjFanout0( pLatch );
+ assert( Abc_ObjIsLo( pNet ) );
+ if ( !Vec_FanDeleteEntry( &pNet->vFanins, pLatch->Id ) )
+ {
+ printf( "Abc_NtkMakeComb: The latch is not found among the fanins of the fanout net...\n" );
+ return 0;
+ }
+ assert( !Abc_ObjIsPi( pNet ) );
+ Abc_NtkMarkNetPi( pNet );
+ }
+ }
+ else
+ {
+ assert( 0 );
+/*
+ // go through the latches and add them to PIs and POs
+ Abc_NtkForEachLatch( pNtk, pLatch, i )
+ {
+// pLatch->Type = ABC_OBJ_TYPE_NODE;
+ Vec_PtrPush( pNtk->vPis, pLatch );
+ Vec_PtrPush( pNtk->vPos, pLatch );
+ // add the names of the latches to the names of the PIs
+ Vec_PtrPush( pNtk->vNamesPi, pNtk->vNamesLatch->pArray[i] );
+ }
+*/
+ }
+ // save the latches in the backup place
+ pNtk->vLatches2 = pNtk->vLatches;
+ pNtk->vLatches = Vec_PtrAlloc( 0 );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Makes the network sequential again.]
+
+ Description [If the network was made combinational by disconnecting
+ latches, this procedure makes it sequential again.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkMakeSeq( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pLatch, * pNet;
+ int i;
+
+ if ( !Abc_NtkIsNetlist(pNtk) )
+ return 0;
+
+ // skip if the network has no latches
+ if ( pNtk->vLatches2 == NULL || pNtk->vLatches2->nSize == 0 )
+ return 0;
+ // move the latches from the backup place
+ Vec_PtrFree( pNtk->vLatches );
+ pNtk->vLatches = pNtk->vLatches2;
+ pNtk->vLatches2 = NULL;
+ if ( Abc_NtkIsNetlist(pNtk) )
+ {
+ // go through the latches and connect the LI/LO nets back to the latches
+ Abc_NtkForEachLatch( pNtk, pLatch, i )
+ {
+ // process the input of the latch
+ pNet = Abc_ObjFanin0( pLatch );
+ assert( Abc_ObjIsLi( pNet ) );
+ Vec_FanPush( pNtk->pMmStep, &pNet->vFanouts, Vec_Int2Fan(pLatch->Id) );
+ // process the output of the latch
+ pNet = Abc_ObjFanout0( pLatch );
+ assert( Abc_ObjIsLo( pNet ) );
+ Vec_FanPush( pNtk->pMmStep, &pNet->vFanins, Vec_Int2Fan(pLatch->Id) );
+ }
+ // clean the PI/PO attributes of the former latch variables
+ for ( i = pNtk->nPisOld; i < pNtk->vPis->nSize; i++ )
+ Abc_ObjUnsetSubtype( Abc_NtkPi(pNtk, i), ABC_OBJ_SUBTYPE_PI );
+ for ( i = pNtk->nPosOld; i < pNtk->vPos->nSize; i++ )
+ Abc_ObjUnsetSubtype( Abc_NtkPo(pNtk, i), ABC_OBJ_SUBTYPE_PO );
+ }
+ else
+ {
+ assert( 0 );
+// Vec_PtrShrink( pNtk->vNamesPi, pNtk->nPisOld );
+ }
+ // remove the nodes from the PI/PO lists
+ Vec_PtrShrink( pNtk->vPis, pNtk->nPisOld );
+ Vec_PtrShrink( pNtk->vPos, pNtk->nPosOld );
+ pNtk->nPis = pNtk->vPis->nSize;
+ pNtk->nPos = pNtk->vPos->nSize;
+ pNtk->nPisOld = 0;
+ pNtk->nPosOld = 0;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks if latches form self-loop.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkLatchIsSelfFeed_rec( Abc_Obj_t * pLatch, Abc_Obj_t * pLatchRoot )
+{
+ Abc_Obj_t * pFanin;
+ assert( Abc_ObjIsLatch(pLatch) );
+ if ( pLatch == pLatchRoot )
+ return 1;
+ pFanin = Abc_ObjFanin0(pLatch);
+ if ( !Abc_ObjIsLatch(pFanin) )
+ return 0;
+ return Abc_NtkLatchIsSelfFeed_rec( pFanin, pLatch );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks if latches form self-loop.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkLatchIsSelfFeed( Abc_Obj_t * pLatch )
+{
+ Abc_Obj_t * pFanin;
+ assert( Abc_ObjIsLatch(pLatch) );
+ pFanin = Abc_ObjFanin0(pLatch);
+ if ( !Abc_ObjIsLatch(pFanin) )
+ return 0;
+ return Abc_NtkLatchIsSelfFeed_rec( pFanin, pLatch );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks if latches form self-loop.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkCountSelfFeedLatches( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pLatch;
+ int i, Counter;
+ Counter = 0;
+ Abc_NtkForEachLatch( pNtk, pLatch, i )
+ Counter += Abc_NtkLatchIsSelfFeed( pLatch );
+ return Counter;
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcMap.c b/src/base/abc/abcMap.c
new file mode 100644
index 00000000..ca326ea1
--- /dev/null
+++ b/src/base/abc/abcMap.c
@@ -0,0 +1,439 @@
+/**CFile****************************************************************
+
+ FileName [abcMap.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Interface with the SC mapping package.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcMap.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+#include "main.h"
+#include "mio.h"
+#include "mapper.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static Map_Man_t * Abc_NtkToMap( Abc_Ntk_t * pNtk, double DelayTarget, int fRecovery, int fVerbose );
+static Abc_Ntk_t * Abc_NtkFromMap( Map_Man_t * pMan, Abc_Ntk_t * pNtk );
+static Abc_Obj_t * Abc_NodeFromMap_rec( Abc_Ntk_t * pNtkNew, Map_Node_t * pNodeMap, int fPhase );
+static Abc_Obj_t * Abc_NodeFromMapPhase_rec( Abc_Ntk_t * pNtkNew, Map_Node_t * pNodeMap, int fPhase );
+static Abc_Obj_t * Abc_NodeFromMapSuper_rec( Abc_Ntk_t * pNtkNew, Map_Node_t * pNodeMap, Map_Super_t * pSuper, Abc_Obj_t * pNodePis[], int nNodePis );
+static Abc_Obj_t * Abc_NtkFixCiDriver( Abc_Obj_t * pNode );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Interface with the mapping package.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Abc_NtkMap( Abc_Ntk_t * pNtk, double DelayTarget, int fRecovery, int fVerbose )
+{
+ int fCheck = 1;
+ Abc_Ntk_t * pNtkNew;
+
+ Map_Man_t * pMan;
+
+ assert( Abc_NtkIsAig(pNtk) );
+
+ // check that the library is available
+ if ( Abc_FrameReadLibGen(Abc_FrameGetGlobalFrame()) == NULL )
+ {
+ printf( "The current library is not available.\n" );
+ return 0;
+ }
+
+ // derive the supergate library
+ if ( Abc_FrameReadLibSuper(Abc_FrameGetGlobalFrame()) == NULL && Abc_FrameReadLibGen(Abc_FrameGetGlobalFrame()) )
+ {
+ printf( "A simple supergate library is derived from gate library \"%s\".\n",
+ Mio_LibraryReadName(Abc_FrameReadLibGen(Abc_FrameGetGlobalFrame())) );
+ Map_SuperLibDeriveFromGenlib( Abc_FrameReadLibGen(Abc_FrameGetGlobalFrame()) );
+ }
+
+ // print a warning about choice nodes
+ if ( Abc_NtkCountChoiceNodes( pNtk ) )
+ printf( "Performing mapping with choices.\n" );
+
+ // perform the mapping
+ pMan = Abc_NtkToMap( pNtk, DelayTarget, fRecovery, fVerbose );
+ if ( pMan == NULL )
+ return NULL;
+ if ( !Map_Mapping( pMan ) )
+ {
+ Map_ManFree( pMan );
+ return NULL;
+ }
+
+ // reconstruct the network after mapping
+ pNtkNew = Abc_NtkFromMap( pMan, pNtk );
+ if ( pNtkNew == NULL )
+ return NULL;
+ Map_ManFree( pMan );
+
+ // make sure that everything is okay
+ if ( fCheck && !Abc_NtkCheck( pNtkNew ) )
+ {
+ printf( "Abc_NtkMap: The network check has failed.\n" );
+ Abc_NtkDelete( pNtkNew );
+ return NULL;
+ }
+ return pNtkNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Load the network into manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Man_t * Abc_NtkToMap( Abc_Ntk_t * pNtk, double DelayTarget, int fRecovery, int fVerbose )
+{
+ Map_Man_t * pMan;
+ ProgressBar * pProgress;
+ Map_Node_t * pNodeMap;
+ Vec_Ptr_t * vNodes;
+ Abc_Obj_t * pNode, * pFanin, * pPrev;
+ int i;
+
+ assert( Abc_NtkIsAig(pNtk) );
+
+ // start the mapping manager and set its parameters
+ pMan = Map_ManCreate( Abc_NtkPiNum(pNtk) + Abc_NtkLatchNum(pNtk), Abc_NtkPoNum(pNtk) + Abc_NtkLatchNum(pNtk), fVerbose );
+ if ( pMan == NULL )
+ return NULL;
+ Map_ManSetAreaRecovery( pMan, fRecovery );
+ Map_ManSetOutputNames( pMan, (char **)pNtk->vNamesPo->pArray );
+ Map_ManSetDelayTarget( pMan, (float)DelayTarget );
+ Map_ManSetInputArrivals( pMan, (Map_Time_t *)Abc_NtkGetCiArrivalTimes(pNtk) );
+
+ // create PIs and remember them in the old nodes
+ Abc_NtkCleanCopy( pNtk );
+ Abc_NtkForEachCi( pNtk, pNode, i )
+ pNode->pCopy = (Abc_Obj_t *)Map_ManReadInputs(pMan)[i];
+
+ // load the AIG into the mapper
+ vNodes = Abc_AigDfs( pNtk );
+ pProgress = Extra_ProgressBarStart( stdout, vNodes->nSize );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ {
+ Extra_ProgressBarUpdate( pProgress, i, NULL );
+ // consider the case of a constant
+ pNode = vNodes->pArray[i];
+ if ( Abc_NodeIsConst(pNode) )
+ {
+ Abc_AigConst1(pNtk->pManFunc)->pCopy = (Abc_Obj_t *)Map_ManReadConst1(pMan);
+ continue;
+ }
+ // add the node to the mapper
+ pNodeMap = Map_NodeAnd( pMan,
+ Map_NotCond( Abc_ObjFanin0(pNode)->pCopy, Abc_ObjFaninC0(pNode) ),
+ Map_NotCond( Abc_ObjFanin1(pNode)->pCopy, Abc_ObjFaninC1(pNode) ) );
+ assert( pNode->pCopy == NULL );
+ // remember the node
+ pNode->pCopy = (Abc_Obj_t *)pNodeMap;
+ // set up the choice node
+ if ( Abc_NodeIsChoice( pNode ) )
+ for ( pPrev = pNode, pFanin = pNode->pData; pFanin; pPrev = pFanin, pFanin = pFanin->pData )
+ {
+ Map_NodeSetNextE( (Map_Node_t *)pPrev->pCopy, (Map_Node_t *)pFanin->pCopy );
+ Map_NodeSetRepr( (Map_Node_t *)pFanin->pCopy, (Map_Node_t *)pNode->pCopy );
+ }
+ }
+ Extra_ProgressBarStop( pProgress );
+ Vec_PtrFree( vNodes );
+
+ // set the primary outputs in the required phase
+ Abc_NtkForEachCo( pNtk, pNode, i )
+ Map_ManReadOutputs(pMan)[i] = Map_NotCond( (Map_Node_t *)Abc_ObjFanin0(pNode)->pCopy, Abc_ObjFaninC0(pNode) );
+ return pMan;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates the mapped network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Abc_NtkFromMap( Map_Man_t * pMan, Abc_Ntk_t * pNtk )
+{
+ ProgressBar * pProgress;
+ Abc_Ntk_t * pNtkNew;
+ Map_Node_t * pNodeMap;
+ Abc_Obj_t * pNode, * pNodeNew;
+ int i, nDupGates;
+
+ // create the new network
+ pNtkNew = Abc_NtkStartFrom( pNtk, ABC_NTK_LOGIC_MAP );
+ // make the mapper point to the new network
+ Map_ManCleanData( pMan );
+ Abc_NtkForEachCi( pNtk, pNode, i )
+ Map_NodeSetData( Map_ManReadInputs(pMan)[i], 1, (char *)pNode->pCopy );
+ // set the constant node
+ if ( Abc_ObjFanoutNum( Abc_AigConst1(pNtk->pManFunc) ) > 0 )
+ Map_NodeSetData( Map_ManReadConst1(pMan), 1, (char *)Abc_NodeCreateConst1(pNtkNew) );
+
+ // assign the mapping of the required phase to the POs
+ pProgress = Extra_ProgressBarStart( stdout, Abc_NtkCoNum(pNtk) );
+ Abc_NtkForEachCo( pNtk, pNode, i )
+ {
+ Extra_ProgressBarUpdate( pProgress, i, NULL );
+ pNodeMap = Map_ManReadOutputs(pMan)[i];
+ pNodeNew = Abc_NodeFromMap_rec( pNtkNew, Map_Regular(pNodeMap), !Map_IsComplement(pNodeMap) );
+ assert( !Abc_ObjIsComplement(pNodeNew) );
+ if ( !Abc_ObjIsNode(pNodeNew) )
+ pNodeNew = Abc_NtkFixCiDriver( pNodeNew );
+ Abc_ObjAddFanin( pNode->pCopy, pNodeNew );
+ }
+ Extra_ProgressBarStop( pProgress );
+
+ // transfer the names
+ Abc_NtkDupNameArrays( pNtk, pNtkNew );
+ Abc_ManTimeDup( pNtk, pNtkNew );
+ // decouple the PO driver nodes to reduce the number of levels
+ nDupGates = Abc_NtkLogicMakeSimplePos( pNtkNew );
+ if ( nDupGates && Map_ManReadVerbose(pMan) )
+ printf( "Duplicated %d gates to decouple the PO drivers.\n", nDupGates );
+ return pNtkNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Constructs the nodes corrresponding to one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NodeFromMap_rec( Abc_Ntk_t * pNtkNew, Map_Node_t * pNodeMap, int fPhase )
+{
+ Abc_Obj_t * pNodeNew, * pNodeInv;
+
+ // check if the phase is already implemented
+ pNodeNew = (Abc_Obj_t *)Map_NodeReadData( pNodeMap, fPhase );
+ if ( pNodeNew )
+ return pNodeNew;
+
+ // implement the node if the best cut is assigned
+ if ( Map_NodeReadCutBest(pNodeMap, fPhase) != NULL )
+ return Abc_NodeFromMapPhase_rec( pNtkNew, pNodeMap, fPhase );
+
+ // if the cut is not assigned, implement the node
+ assert( Map_NodeReadCutBest(pNodeMap, !fPhase) != NULL || Map_NodeIsConst(pNodeMap) );
+ pNodeNew = Abc_NodeFromMapPhase_rec( pNtkNew, pNodeMap, !fPhase );
+
+ // add the inverter
+ pNodeInv = Abc_NtkCreateNode( pNtkNew );
+ Abc_ObjAddFanin( pNodeInv, pNodeNew );
+ pNodeInv->pData = Mio_LibraryReadInv(Map_ManReadGenLib(Map_NodeReadMan(pNodeMap)));
+
+ // set the inverter
+ Map_NodeSetData( pNodeMap, fPhase, (char *)pNodeInv );
+ return pNodeInv;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Constructs the nodes corrresponding to one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NodeFromMapPhase_rec( Abc_Ntk_t * pNtkNew, Map_Node_t * pNodeMap, int fPhase )
+{
+ Abc_Obj_t * pNodePIs[10];
+ Abc_Obj_t * pNodeNew;
+ Map_Node_t ** ppLeaves;
+ Map_Cut_t * pCutBest;
+ Map_Super_t * pSuperBest;
+ unsigned uPhaseBest;
+ int i, fInvPin, nLeaves;
+
+ // make sure the node can be implemented in this phase
+ assert( Map_NodeReadCutBest(pNodeMap, fPhase) != NULL || Map_NodeIsConst(pNodeMap) );
+ // check if the phase is already implemented
+ pNodeNew = (Abc_Obj_t *)Map_NodeReadData( pNodeMap, fPhase );
+ if ( pNodeNew )
+ return pNodeNew;
+
+ // get the information about the best cut
+ pCutBest = Map_NodeReadCutBest( pNodeMap, fPhase );
+ pSuperBest = Map_CutReadSuperBest( pCutBest, fPhase );
+ uPhaseBest = Map_CutReadPhaseBest( pCutBest, fPhase );
+ nLeaves = Map_CutReadLeavesNum( pCutBest );
+ ppLeaves = Map_CutReadLeaves( pCutBest );
+
+ // collect the PI nodes
+ for ( i = 0; i < nLeaves; i++ )
+ {
+ fInvPin = ((uPhaseBest & (1 << i)) > 0);
+ pNodePIs[i] = Abc_NodeFromMap_rec( pNtkNew, ppLeaves[i], !fInvPin );
+ assert( pNodePIs[i] != NULL );
+ }
+
+ // implement the supergate
+ pNodeNew = Abc_NodeFromMapSuper_rec( pNtkNew, pNodeMap, pSuperBest, pNodePIs, nLeaves );
+ Map_NodeSetData( pNodeMap, fPhase, (char *)pNodeNew );
+ return pNodeNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Constructs the nodes corrresponding to one supergate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NodeFromMapSuper_rec( Abc_Ntk_t * pNtkNew, Map_Node_t * pNodeMap, Map_Super_t * pSuper, Abc_Obj_t * pNodePis[], int nNodePis )
+{
+ Mio_Gate_t * pRoot;
+ Map_Super_t ** ppFanins;
+ Abc_Obj_t * pNodeNew, * pNodeFanin;
+ int nFanins, Number, i;
+
+ // get the parameters of the supergate
+ pRoot = Map_SuperReadRoot(pSuper);
+ if ( pRoot == NULL )
+ {
+ Number = Map_SuperReadNum(pSuper);
+ if ( Number < nNodePis )
+ {
+ return pNodePis[Number];
+ }
+ else
+ {
+ assert( 0 );
+ /* It might happen that a super gate with 5 inputs is constructed that
+ * actually depends only on the first four variables; i.e the fifth is a
+ * don't care -- in that case we connect constant node for the fifth
+ * (since the cut only has 4 variables). An interesting question is what
+ * if the first variable (and not the fifth one is the redundant one;
+ * can that happen?) */
+ return Abc_NodeCreateConst0(pNtkNew);
+ }
+ }
+
+ // get information about the fanins of the supergate
+ nFanins = Map_SuperReadFaninNum( pSuper );
+ ppFanins = Map_SuperReadFanins( pSuper );
+ // create a new node with these fanins
+ pNodeNew = Abc_NtkCreateNode( pNtkNew );
+ for ( i = 0; i < nFanins; i++ )
+ {
+ pNodeFanin = Abc_NodeFromMapSuper_rec( pNtkNew, pNodeMap, ppFanins[i], pNodePis, nNodePis );
+ Abc_ObjAddFanin( pNodeNew, pNodeFanin );
+ }
+ pNodeNew->pData = pRoot;
+ return pNodeNew;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Unmaps the network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkUnmap( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ char * pSop;
+ int i;
+
+ assert( Abc_NtkIsLogicMap(pNtk) );
+ // update the functionality manager
+ assert( pNtk->pManFunc == NULL );
+ pNtk->pManFunc = Extra_MmFlexStart();
+ pNtk->Type = ABC_NTK_LOGIC_SOP;
+ // update the nodes
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ pSop = Mio_GateReadSop(pNode->pData);
+ assert( Abc_SopGetVarNum(pSop) == Abc_ObjFaninNum(pNode) );
+ pNode->pData = Abc_SopRegister( pNtk->pManFunc, pSop );
+ }
+ return 1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Add buffer when the CO driver is a CI.]
+
+ Description [Hack: If the PO has the same name as the PI, it will still count
+ as the buffer but this node will not be written into file during writing]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NtkFixCiDriver( Abc_Obj_t * pNode )
+{
+ Mio_Gate_t * pGateBuffer = Mio_LibraryReadBuf(Abc_FrameReadLibGen(Abc_FrameGetGlobalFrame()));
+ Mio_Gate_t * pGateInv = Mio_LibraryReadInv(Abc_FrameReadLibGen(Abc_FrameGetGlobalFrame()));
+ // add the buffer
+ if ( pGateBuffer )
+ return Abc_NodeCreateBuf( pNode->pNtk, pNode );
+ // add two inverters
+ if ( pGateInv )
+ return Abc_NodeCreateInv( pNode->pNtk, Abc_NodeCreateInv(pNode->pNtk, pNode) );
+ assert( 0 );
+ return NULL;
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcMinBase.c b/src/base/abc/abcMinBase.c
new file mode 100644
index 00000000..d2d88ebf
--- /dev/null
+++ b/src/base/abc/abcMinBase.c
@@ -0,0 +1,167 @@
+/**CFile****************************************************************
+
+ FileName [abcMinBase.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Makes nodes of the network minimum base.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcMinBase.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Abc_NodeSupport( DdNode * bFunc, Vec_Str_t * vSupport, int nVars );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Makes nodes minimum base.]
+
+ Description [Returns the number of changed nodes.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkMinimumBase( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ int i, Counter;
+ assert( Abc_NtkIsLogicBdd(pNtk) );
+ Counter = 0;
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ Counter += Abc_NodeMinimumBase( pNode );
+ return Counter;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Makes one node minimum base.]
+
+ Description [Returns 1 if the node is changed.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NodeMinimumBase( Abc_Obj_t * pNode )
+{
+ Vec_Str_t * vSupport = pNode->pNtk->vStrTemp;
+ Vec_Ptr_t * vFanins = pNode->pNtk->vPtrTemp;
+ DdNode * bTemp;
+ int i, nVars;
+
+ assert( Abc_NtkIsLogicBdd(pNode->pNtk) );
+ assert( Abc_ObjIsNode(pNode) );
+
+ // compute support
+ nVars = Abc_NodeSupport( Cudd_Regular(pNode->pData), vSupport, Abc_ObjFaninNum(pNode) );
+ if ( nVars == Abc_ObjFaninNum(pNode) )
+ return 0;
+
+ // remove unused fanins
+ Abc_NodeCollectFanins( pNode, vFanins );
+ for ( i = 0; i < vFanins->nSize; i++ )
+ if ( vSupport->pArray[i] == 0 )
+ Abc_ObjDeleteFanin( pNode, vFanins->pArray[i] );
+ assert( nVars == Abc_ObjFaninNum(pNode) );
+
+ // update the function of the node
+ pNode->pData = Extra_bddRemapUp( pNode->pNtk->pManFunc, bTemp = pNode->pData ); Cudd_Ref( pNode->pData );
+ Cudd_RecursiveDeref( pNode->pNtk->pManFunc, bTemp );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes support of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NodeSupport_rec( DdNode * bFunc, Vec_Str_t * vSupport )
+{
+ if ( cuddIsConstant(bFunc) || Cudd_IsComplement(bFunc->next) )
+ return;
+ vSupport->pArray[ bFunc->index ] = 1;
+ Abc_NodeSupport_rec( cuddT(bFunc), vSupport );
+ Abc_NodeSupport_rec( Cudd_Regular(cuddE(bFunc)), vSupport );
+ bFunc->next = Cudd_Not(bFunc->next);
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes support of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NodeSupportClear_rec( DdNode * bFunc )
+{
+ if ( !Cudd_IsComplement(bFunc->next) )
+ return;
+ bFunc->next = Cudd_Regular(bFunc->next);
+ if ( cuddIsConstant(bFunc) )
+ return;
+ Abc_NodeSupportClear_rec( cuddT(bFunc) );
+ Abc_NodeSupportClear_rec( Cudd_Regular(cuddE(bFunc)) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes support of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NodeSupport( DdNode * bFunc, Vec_Str_t * vSupport, int nVars )
+{
+ int Counter, i;
+ // compute the support by marking the BDD
+ Vec_StrFill( vSupport, nVars, 0 );
+ Abc_NodeSupport_rec( bFunc, vSupport );
+ // clear the marak
+ Abc_NodeSupportClear_rec( bFunc );
+ // get the number of support variables
+ Counter = 0;
+ for ( i = 0; i < nVars; i++ )
+ Counter += vSupport->pArray[i];
+ return Counter;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcMiter.c b/src/base/abc/abcMiter.c
new file mode 100644
index 00000000..f1037dd2
--- /dev/null
+++ b/src/base/abc/abcMiter.c
@@ -0,0 +1,502 @@
+/**CFile****************************************************************
+
+ FileName [abcMiter.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Procedures to derive the miter of two circuits.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcMiter.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static Abc_Ntk_t * Abc_NtkMiterInt( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int fComb );
+static void Abc_NtkMiterPrepare( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, Abc_Ntk_t * pNtkMiter, int fComb );
+static void Abc_NtkMiterAddOne( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkMiter );
+static void Abc_NtkMiterFinalize( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, Abc_Ntk_t * pNtkMiter, int fComb );
+static void Abc_NtkAddFrame( Abc_Ntk_t * pNetNew, Abc_Ntk_t * pNet, int iFrame, Vec_Ptr_t * vNodes );
+
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Derives the miter of two networks.]
+
+ Description [Preprocesses the networks to make sure that they are strashed.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Abc_NtkMiter( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int fComb )
+{
+ Abc_Ntk_t * pTemp = NULL;
+ int fRemove1, fRemove2;
+ // make sure the circuits are strashed
+ fRemove1 = (!Abc_NtkIsAig(pNtk1)) && (pNtk1 = Abc_NtkStrash(pNtk1));
+ fRemove2 = (!Abc_NtkIsAig(pNtk2)) && (pNtk2 = Abc_NtkStrash(pNtk2));
+ if ( pNtk1 && pNtk2 )
+ {
+ // check that the networks have the same PIs/POs/latches
+ // reorder PIs/POs/latches of pNtk2 according to pNtk1
+ // compute the miter of two strashed sequential networks
+ if ( Abc_NtkCompareSignals( pNtk1, pNtk2, fComb ) )
+ pTemp = Abc_NtkMiterInt( pNtk1, pNtk2, fComb );
+ }
+ if ( fRemove1 ) Abc_NtkDelete( pNtk1 );
+ if ( fRemove2 ) Abc_NtkDelete( pNtk2 );
+ return pTemp;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Derives the miter of two sequential networks.]
+
+ Description [Assumes that the networks are strashed.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Abc_NtkMiterInt( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int fComb )
+{
+ int fCheck = 1;
+ char Buffer[100];
+ Abc_Ntk_t * pNtkMiter;
+
+ assert( Abc_NtkIsAig(pNtk1) );
+ assert( Abc_NtkIsAig(pNtk2) );
+
+ // start the new network
+ pNtkMiter = Abc_NtkAlloc( ABC_NTK_AIG );
+ sprintf( Buffer, "%s_%s_miter", pNtk1->pName, pNtk2->pName );
+ pNtkMiter->pName = util_strsav(Buffer);
+
+ // perform strashing
+ Abc_NtkMiterPrepare( pNtk1, pNtk2, pNtkMiter, fComb );
+ Abc_NtkMiterAddOne( pNtk1, pNtkMiter );
+ Abc_NtkMiterAddOne( pNtk2, pNtkMiter );
+ Abc_NtkMiterFinalize( pNtk1, pNtk2, pNtkMiter, fComb );
+
+ // make sure that everything is okay
+ if ( fCheck && !Abc_NtkCheck( pNtkMiter ) )
+ {
+ printf( "Abc_NtkMiter: The network check has failed.\n" );
+ Abc_NtkDelete( pNtkMiter );
+ return NULL;
+ }
+ return pNtkMiter;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prepares the network for mitering.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkMiterPrepare( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, Abc_Ntk_t * pNtkMiter, int fComb )
+{
+ Abc_Obj_t * pObj, * pObjNew;
+ int i;
+ // clean the copy field in all objects
+ Abc_NtkCleanCopy( pNtk1 );
+ Abc_NtkCleanCopy( pNtk2 );
+ if ( fComb )
+ {
+ // create new PIs and remember them in the old PIs
+ Abc_NtkForEachCi( pNtk1, pObj, i )
+ {
+ pObjNew = Abc_NtkCreateTermPi( pNtkMiter );
+ // remember this PI in the old PIs
+ pObj->pCopy = pObjNew;
+ pObj = Abc_NtkCi(pNtk2, i);
+ pObj->pCopy = pObjNew;
+ // add name
+ Abc_NtkLogicStoreName( pObjNew, pNtk1->vNamesPi->pArray[i] );
+ }
+ // create the only PO
+ pObjNew = Abc_NtkCreateTermPo( pNtkMiter );
+ // add the PO name
+ Abc_NtkLogicStoreName( pObjNew, "miter" );
+ }
+ else
+ {
+ // create new PIs and remember them in the old PIs
+ Abc_NtkForEachPi( pNtk1, pObj, i )
+ {
+ pObjNew = Abc_NtkCreateTermPi( pNtkMiter );
+ // remember this PI in the old PIs
+ pObj->pCopy = pObjNew;
+ pObj = Abc_NtkPi(pNtk2, i);
+ pObj->pCopy = pObjNew;
+ // add name
+ Abc_NtkLogicStoreName( pObjNew, pNtk1->vNamesPi->pArray[i] );
+ }
+ // create the only PO
+ pObjNew = Abc_NtkCreateTermPo( pNtkMiter );
+ // add the PO name
+ Abc_NtkLogicStoreName( pObjNew, "miter" );
+ // create the latches
+ Abc_NtkForEachLatch( pNtk1, pObj, i )
+ {
+ pObjNew = Abc_NtkDupObj( pNtkMiter, pObj );
+ Vec_PtrPush( pNtkMiter->vPis, pObjNew );
+ Vec_PtrPush( pNtkMiter->vPos, pObjNew );
+ // add name
+ Abc_NtkLogicStoreNamePlus( pObjNew, pNtk1->vNamesLatch->pArray[i], "_1" );
+ }
+ Abc_NtkForEachLatch( pNtk2, pObj, i )
+ {
+ pObjNew = Abc_NtkDupObj( pNtkMiter, pObj );
+ Vec_PtrPush( pNtkMiter->vPis, pObjNew );
+ Vec_PtrPush( pNtkMiter->vPos, pObjNew );
+ // add name
+ Abc_NtkLogicStoreNamePlus( pObjNew, pNtk2->vNamesLatch->pArray[i], "_2" );
+ }
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs mitering for one network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkMiterAddOne( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkMiter )
+{
+ ProgressBar * pProgress;
+ Vec_Ptr_t * vNodes;
+ Abc_Obj_t * pNode, * pNodeNew, * pConst1, * pConst1New;
+ int i;
+ // get the constant nodes
+ pConst1 = Abc_AigConst1( pNtk->pManFunc );
+ pConst1New = Abc_AigConst1( pNtkMiter->pManFunc );
+ // perform strashing
+ vNodes = Abc_NtkDfs( pNtk );
+ pProgress = Extra_ProgressBarStart( stdout, vNodes->nSize );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ {
+ Extra_ProgressBarUpdate( pProgress, i, NULL );
+ pNode = vNodes->pArray[i];
+ if ( pNode == pConst1 )
+ pNodeNew = pConst1New;
+ else
+ pNodeNew = Abc_AigAnd( pNtkMiter->pManFunc,
+ Abc_ObjNotCond( Abc_ObjFanin0(pNode)->pCopy, Abc_ObjFaninC0(pNode) ),
+ Abc_ObjNotCond( Abc_ObjFanin1(pNode)->pCopy, Abc_ObjFaninC1(pNode) ) );
+ pNode->pCopy = pNodeNew;
+ }
+ Vec_PtrFree( vNodes );
+ Extra_ProgressBarStop( pProgress );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Finalizes the miter by adding the output part.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkMiterFinalize( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, Abc_Ntk_t * pNtkMiter, int fComb )
+{
+ Vec_Ptr_t * vPairs;
+ Abc_Obj_t * pDriverNew, * pMiter, * pNode;
+ int i;
+ // collect the PO pairs from both networks
+ vPairs = Vec_PtrAlloc( 100 );
+ if ( fComb )
+ {
+ // collect the CO nodes for the miter
+ Abc_NtkForEachCo( pNtk1, pNode, i )
+ {
+ pDriverNew = Abc_ObjNotCond( Abc_ObjFanin0(pNode)->pCopy, Abc_ObjFaninC0(pNode) );
+ Vec_PtrPush( vPairs, pDriverNew );
+ pNode = Abc_NtkPo( pNtk2, i );
+ pDriverNew = Abc_ObjNotCond( Abc_ObjFanin0(pNode)->pCopy, Abc_ObjFaninC0(pNode) );
+ Vec_PtrPush( vPairs, pDriverNew );
+ }
+ }
+ else
+ {
+ // collect the PO nodes for the miter
+ Abc_NtkForEachPo( pNtk1, pNode, i )
+ {
+ pDriverNew = Abc_ObjNotCond( Abc_ObjFanin0(pNode)->pCopy, Abc_ObjFaninC0(pNode) );
+ Vec_PtrPush( vPairs, pDriverNew );
+ pNode = Abc_NtkPo( pNtk2, i );
+ pDriverNew = Abc_ObjNotCond( Abc_ObjFanin0(pNode)->pCopy, Abc_ObjFaninC0(pNode) );
+ Vec_PtrPush( vPairs, pDriverNew );
+ }
+ // connect new latches
+ Abc_NtkForEachLatch( pNtk1, pNode, i )
+ {
+ pDriverNew = Abc_ObjNotCond( Abc_ObjFanin0(pNode)->pCopy, Abc_ObjFaninC0(pNode) );
+ Abc_ObjAddFanin( pNode->pCopy, pDriverNew );
+ }
+ Abc_NtkForEachLatch( pNtk2, pNode, i )
+ {
+ pDriverNew = Abc_ObjNotCond( Abc_ObjFanin0(pNode)->pCopy, Abc_ObjFaninC0(pNode) );
+ Abc_ObjAddFanin( pNode->pCopy, pDriverNew );
+ }
+ }
+ // add the miter
+ pMiter = Abc_AigMiter( pNtkMiter->pManFunc, vPairs );
+ Abc_ObjAddFanin( Abc_NtkPo(pNtkMiter,0), pMiter );
+ Vec_PtrFree( vPairs );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks the status of the miter.]
+
+ Description [Return 1 if the miter is sat for at least one output.
+ Return 0 if the miter is unsat for all its outputs. Returns -1 if the
+ miter is undecided for some outputs.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkMiterIsConstant( Abc_Ntk_t * pMiter )
+{
+ Abc_Obj_t * pNodePo, * pChild;
+ int i;
+ assert( Abc_NtkIsAig(pMiter) );
+ Abc_NtkForEachPo( pMiter, pNodePo, i )
+ {
+ pChild = Abc_ObjChild0( Abc_NtkPo(pMiter,i) );
+ if ( Abc_NodeIsConst(pChild) )
+ {
+ assert( Abc_ObjRegular(pChild) == Abc_AigConst1(pMiter->pManFunc) );
+ if ( !Abc_ObjIsComplement(pChild) )
+ {
+ // if the miter is constant 1, return immediately
+ printf( "MITER IS CONSTANT 1!\n" );
+ return 1;
+ }
+ }
+ // if the miter is undecided (or satisfiable), return immediately
+ else
+ return -1;
+ }
+ // return 0, meaning all outputs are constant zero
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reports the status of the miter.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkMiterReport( Abc_Ntk_t * pMiter )
+{
+ Abc_Obj_t * pChild, * pNode;
+ int i;
+ if ( Abc_NtkPoNum(pMiter) == 1 )
+ {
+ pChild = Abc_ObjChild0( Abc_NtkPo(pMiter,0) );
+ if ( Abc_NodeIsConst(Abc_ObjRegular(pChild)) )
+ {
+ if ( Abc_ObjIsComplement(pChild) )
+ printf( "Unsatisfiable.\n" );
+ else
+ printf( "Satisfiable. (Constant 1).\n" );
+ }
+ else
+ printf( "Satisfiable.\n" );
+ }
+ else
+ {
+ Abc_NtkForEachPo( pMiter, pNode, i )
+ {
+ pChild = Abc_ObjChild0( Abc_NtkPo(pMiter,i) );
+ printf( "Output #%2d : ", i );
+ if ( Abc_NodeIsConst(Abc_ObjRegular(pChild)) )
+ {
+ if ( Abc_ObjIsComplement(pChild) )
+ printf( "Unsatisfiable.\n" );
+ else
+ printf( "Satisfiable. (Constant 1).\n" );
+ }
+ else
+ printf( "Satisfiable.\n" );
+ }
+ }
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Derives the time frames of the network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Abc_NtkFrames( Abc_Ntk_t * pNtk, int nFrames, int fInitial )
+{
+ int fCheck = 1;
+ char Buffer[100];
+ ProgressBar * pProgress;
+ Abc_Ntk_t * pNtkFrames;
+ Vec_Ptr_t * vNodes;
+ Abc_Obj_t * pLatch, * pLatchNew;
+ int i;
+ assert( nFrames > 0 );
+ assert( Abc_NtkIsAig(pNtk) );
+ // start the new network
+ pNtkFrames = Abc_NtkAlloc( ABC_NTK_AIG );
+ sprintf( Buffer, "%s_%d_frames", pNtk->pName, nFrames );
+ pNtkFrames->pName = util_strsav(Buffer);
+ // create new latches (or their initial values) and remember them in the new latches
+ if ( !fInitial )
+ {
+ Abc_NtkForEachLatch( pNtk, pLatch, i )
+ Abc_NtkDupObj( pNtkFrames, pLatch );
+ }
+ else
+ {
+ Abc_NtkForEachLatch( pNtk, pLatch, i )
+ pLatch->pCopy = Abc_ObjNotCond( Abc_AigConst1(pNtkFrames->pManFunc), ((int)pLatch->pData)!=1 );
+ }
+
+ // create the timeframes
+ vNodes = Abc_NtkDfs( pNtk );
+ pProgress = Extra_ProgressBarStart( stdout, nFrames );
+ for ( i = 0; i < nFrames; i++ )
+ {
+ Extra_ProgressBarUpdate( pProgress, i, NULL );
+ Abc_NtkAddFrame( pNtkFrames, pNtk, i, vNodes );
+ }
+ Extra_ProgressBarStop( pProgress );
+ Vec_PtrFree( vNodes );
+
+ // connect the new latches to the outputs of the last frame
+ if ( !fInitial )
+ {
+ Abc_NtkForEachLatch( pNtk, pLatch, i )
+ {
+ pLatchNew = Abc_NtkLatch(pNtkFrames, i);
+ Abc_ObjAddFanin( pLatchNew, Abc_ObjFanin0(pLatch)->pCopy );
+ Vec_PtrPush( pNtkFrames->vPis, pLatchNew );
+ Vec_PtrPush( pNtkFrames->vPos, pLatchNew );
+ Abc_NtkLogicStoreName( pLatchNew, pNtk->vNamesLatch->pArray[i] );
+ }
+ assert( pNtkFrames->vPis->nSize == pNtkFrames->vNamesPi->nSize );
+ assert( pNtkFrames->vPos->nSize == pNtkFrames->vNamesPo->nSize );
+ }
+ // make sure that everything is okay
+ if ( fCheck && !Abc_NtkCheck( pNtkFrames ) )
+ {
+ printf( "Abc_NtkFrames: The network check has failed.\n" );
+ Abc_NtkDelete( pNtkFrames );
+ return NULL;
+ }
+ return pNtkFrames;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Adds one time frame to the new network.]
+
+ Description [Assumes that the latches of the old network point
+ to the outputs of the previous frame of the new network (pLatch->pCopy).
+ In the end, updates the latches of the old network to point to the
+ outputs of the current frame of the new network.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkAddFrame( Abc_Ntk_t * pNtkFrames, Abc_Ntk_t * pNtk, int iFrame, Vec_Ptr_t * vNodes )
+{
+ char Buffer[10];
+ Abc_Obj_t * pNode, * pNodeNew, * pLatch;
+ Abc_Obj_t * pConst1, * pConst1New;
+ int i;
+ // get the constant nodes
+ pConst1 = Abc_AigConst1( pNtk->pManFunc );
+ pConst1New = Abc_AigConst1( pNtkFrames->pManFunc );
+ // create the prefix to be added to the node names
+ sprintf( Buffer, "_%02d", iFrame );
+ // add the new PI nodes
+ Abc_NtkForEachPi( pNtk, pNode, i )
+ {
+ pNodeNew = Abc_NtkDupObj( pNtkFrames, pNode );
+ Abc_NtkLogicStoreNamePlus( pNodeNew, pNtk->vNamesPi->pArray[i], Buffer );
+ }
+ // add the internal nodes
+ for ( i = 0; i < vNodes->nSize; i++ )
+ {
+ pNode = vNodes->pArray[i];
+ if ( pNode == pConst1 )
+ pNodeNew = pConst1New;
+ else
+ pNodeNew = Abc_AigAnd( pNtkFrames->pManFunc,
+ Abc_ObjNotCond( Abc_ObjFanin0(pNode)->pCopy, Abc_ObjFaninC0(pNode) ),
+ Abc_ObjNotCond( Abc_ObjFanin1(pNode)->pCopy, Abc_ObjFaninC1(pNode) ) );
+ pNode->pCopy = pNodeNew;
+ }
+ // add the new POs
+ Abc_NtkForEachPo( pNtk, pNode, i )
+ {
+ pNodeNew = Abc_NtkDupObj( pNtkFrames, pNode );
+ Abc_ObjAddFanin( pNodeNew, Abc_ObjNotCond( Abc_ObjFanin0(pNode)->pCopy, Abc_ObjFaninC0(pNode) ) );
+ Abc_NtkLogicStoreNamePlus( pNodeNew, pNtk->vNamesPo->pArray[i], Buffer );
+ }
+ // transfer the implementation of the latch drivers to the latches
+ Abc_NtkForEachLatch( pNtk, pLatch, i )
+ pLatch->pCopy = Abc_ObjNotCond( Abc_ObjFanin0(pLatch)->pCopy, Abc_ObjFaninC0(pLatch) );
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcNames.c b/src/base/abc/abcNames.c
new file mode 100644
index 00000000..da68bf50
--- /dev/null
+++ b/src/base/abc/abcNames.c
@@ -0,0 +1,406 @@
+/**CFile****************************************************************
+
+ FileName [abcNames.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Procedures working with net and node names.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcNames.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Registers the name with the string memory manager.]
+
+ Description [This function should be used to register all names
+ permanentsly stored with the network. The pointer returned by
+ this procedure contains the copy of the name, which should be used
+ in all network manipulation procedures.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Abc_NtkRegisterName( Abc_Ntk_t * pNtk, char * pName )
+{
+ char * pRegName;
+ if ( pName == NULL ) return NULL;
+ pRegName = Extra_MmFlexEntryFetch( pNtk->pMmNames, strlen(pName) + 1 );
+ strcpy( pRegName, pName );
+ return pRegName;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Registers the name with the string memory manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Abc_NtkRegisterNamePlus( Abc_Ntk_t * pNtk, char * pName, char * pSuffix )
+{
+ char * pRegName;
+ assert( pName && pSuffix );
+ pRegName = Extra_MmFlexEntryFetch( pNtk->pMmNames, strlen(pName) + strlen(pSuffix) + 1 );
+ sprintf( pRegName, "%s%s", pName, pSuffix );
+ return pRegName;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the hash table of node names.]
+
+ Description [Creates the hash table of names into nodes for the given
+ type of nodes. Additionally, sets the node copy pointers to the names.
+ Returns NULL if name duplication is detected.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+stmm_table * Abc_NtkLogicHashNames( Abc_Ntk_t * pNtk, int Type, int fComb )
+{
+ stmm_table * tNames;
+ int i, Limit;
+ tNames = stmm_init_table( strcmp, stmm_strhash );
+ if ( Type == 0 ) // PI
+ {
+ Limit = fComb? Abc_NtkCiNum(pNtk) : Abc_NtkPiNum(pNtk);
+ for ( i = 0; i < Limit; i++ )
+ {
+ if ( stmm_insert( tNames, Abc_NtkNameCi(pNtk,i), (char *)Abc_NtkCi(pNtk,i) ) )
+ {
+ printf( "Error: The name is already in the table...\n" );
+ return NULL;
+ }
+ Abc_NtkCi(pNtk,i)->pCopy = (Abc_Obj_t *)Abc_NtkNameCi(pNtk,i);
+ }
+ }
+ else if ( Type == 1 ) // PO
+ {
+ Limit = fComb? Abc_NtkCoNum(pNtk) : Abc_NtkPoNum(pNtk);
+ for ( i = 0; i < Limit; i++ )
+ {
+ if ( stmm_insert( tNames, Abc_NtkNameCo(pNtk,i), (char *)Abc_NtkCo(pNtk,i) ) )
+ {
+ printf( "Error: The name is already in the table...\n" );
+ return NULL;
+ }
+ Abc_NtkCo(pNtk,i)->pCopy = (Abc_Obj_t *)Abc_NtkNameCo(pNtk,i);
+ }
+ }
+ else if ( Type == 2 ) // latch
+ {
+ for ( i = 0; i < Abc_NtkLatchNum(pNtk); i++ )
+ {
+ if ( stmm_insert( tNames, Abc_NtkNameLatch(pNtk,i), (char *)Abc_NtkLatch(pNtk,i) ) )
+ {
+ printf( "Error: The name is already in the table...\n" );
+ return NULL;
+ }
+ Abc_NtkLatch(pNtk,i)->pCopy = (Abc_Obj_t *)Abc_NtkNameLatch(pNtk,i);
+ }
+ }
+ return tNames;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Transfers the names to the node copy pointers.]
+
+ Description [This procedure is used for writing networks into a file.
+ Assumes that the latch input names are created from latch names using
+ suffix "_in".]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkLogicTransferNames( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode, * pDriver, * pFanoutNamed;
+ int i;
+ // transfer the PI/PO/latch names
+ Abc_NtkForEachPi( pNtk, pNode, i )
+ pNode->pCopy = (Abc_Obj_t *)Abc_NtkNamePi(pNtk,i);
+ Abc_NtkForEachPo( pNtk, pNode, i )
+ pNode->pCopy = (Abc_Obj_t *)Abc_NtkNamePo(pNtk,i);
+ Abc_NtkForEachLatch( pNtk, pNode, i )
+ pNode->pCopy = (Abc_Obj_t *)Abc_NtkNameLatch(pNtk,i);
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ pNode->pCopy = NULL;
+ // additionally, transfer the names to the CO drivers if they have unique COs
+ Abc_NtkForEachPo( pNtk, pNode, i )
+ {
+ pDriver = Abc_ObjFanin0(pNode);
+ // skip the drivers already having names
+ if ( pDriver->pCopy )
+ continue;
+ // get the named fanout
+ pFanoutNamed = Abc_NodeHasUniqueNamedFanout( pDriver );
+ if ( pFanoutNamed == NULL || pFanoutNamed != pNode )
+ continue;
+ // assign the name;
+ assert( pNode == pFanoutNamed );
+ pDriver->pCopy = pFanoutNamed->pCopy;
+ }
+ Abc_NtkForEachLatch( pNtk, pNode, i )
+ {
+ pDriver = Abc_ObjFanin0(pNode);
+ // skip the drivers already having names
+ if ( pDriver->pCopy )
+ continue;
+ // get the named fanout
+ pFanoutNamed = Abc_NodeHasUniqueNamedFanout( pDriver );
+ if ( pFanoutNamed == NULL || pFanoutNamed != pNode )
+ continue;
+ // assign the name;
+ assert( pNode == Abc_NtkLatch(pNtk,i) );
+ pDriver->pCopy = (Abc_Obj_t *)Abc_NtkRegisterName( pNtk, Abc_NtkNameLatchInput(pNtk,i) );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Gets the long name of the node.]
+
+ Description [This name is the output net's name.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Abc_NtkNameLatchInput( Abc_Ntk_t * pNtk, int i )
+{
+ static char Buffer[500];
+ sprintf( Buffer, "%s_in", Abc_NtkNameLatch(pNtk, i) );
+ return Buffer;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Gets the long name of the node.]
+
+ Description [This name is the output net's name.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Abc_ObjName( Abc_Obj_t * pObj )
+{
+ static char Buffer[500];
+ assert( !Abc_NtkIsSeq(pObj->pNtk) );
+ // consider network types
+ if ( Abc_NtkIsNetlist(pObj->pNtk) )
+ {
+ // in a netlist, nets have names, nodes have no names
+ assert( Abc_ObjIsNet(pObj) );
+ // if the name is not given, invent it
+ if ( pObj->pData )
+ sprintf( Buffer, "%s", pObj->pData );
+ else
+ sprintf( Buffer, "[%d]", pObj->Id ); // make sure this name is unique!!!
+ }
+ else
+ {
+ // in a logic network, PIs/POs/latches have names, internal nodes have no names
+ // (exception: an internal node borrows name from its unique non-complemented CO fanout)
+ assert( !Abc_ObjIsNet(pObj) );
+ if ( pObj->pCopy )
+ sprintf( Buffer, "%s", (char *)pObj->pCopy );
+ else
+ sprintf( Buffer, "[%d]", pObj->Id );
+ }
+ return Buffer;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Finds a unique name for the node.]
+
+ Description [If the name exists, tries appending numbers to it until
+ it becomes unique.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Abc_ObjNameUnique( Abc_Ntk_t * pNtk, char * pName )
+{
+ static char Buffer[1000];
+ int Counter;
+ assert( 0 );
+ if ( !stmm_is_member( pNtk->tName2Net, pName ) )
+ return pName;
+ for ( Counter = 1; ; Counter++ )
+ {
+ sprintf( Buffer, "%s_%d", pName, Counter );
+ if ( !stmm_is_member( pNtk->tName2Net, Buffer ) )
+ return Buffer;
+ }
+ return NULL;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Adds new name to the network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Abc_NtkLogicStoreName( Abc_Obj_t * pNodeNew, char * pNameOld )
+{
+ char * pNewName;
+ assert( !Abc_ObjIsComplement(pNodeNew) );
+ // get the new name
+ pNewName = Abc_NtkRegisterName( pNodeNew->pNtk, pNameOld );
+ // add the name
+ if ( Abc_ObjIsPi(pNodeNew) )
+ Vec_PtrPush( pNodeNew->pNtk->vNamesPi, pNewName );
+ else if ( Abc_ObjIsPo(pNodeNew) )
+ Vec_PtrPush( pNodeNew->pNtk->vNamesPo, pNewName );
+ else if ( Abc_ObjIsLatch(pNodeNew) )
+ {
+ Vec_PtrPush( pNodeNew->pNtk->vNamesLatch, pNewName );
+ Vec_PtrPush( pNodeNew->pNtk->vNamesPi, pNewName );
+ Vec_PtrPush( pNodeNew->pNtk->vNamesPo, pNewName );
+ }
+ else
+ assert( 0 );
+ return pNewName;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Adds new name to the network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Abc_NtkLogicStoreNamePlus( Abc_Obj_t * pNodeNew, char * pNameOld, char * pSuffix )
+{
+ char * pNewName;
+ assert( !Abc_ObjIsComplement(pNodeNew) );
+ assert( pSuffix );
+ // get the new name
+ pNewName = Abc_NtkRegisterNamePlus( pNodeNew->pNtk, pNameOld, pSuffix );
+ // add the name
+ if ( Abc_ObjIsPi(pNodeNew) )
+ Vec_PtrPush( pNodeNew->pNtk->vNamesPi, pNewName );
+ else if ( Abc_ObjIsPo(pNodeNew) )
+ Vec_PtrPush( pNodeNew->pNtk->vNamesPo, pNewName );
+ else if ( Abc_ObjIsLatch(pNodeNew) )
+ {
+ Vec_PtrPush( pNodeNew->pNtk->vNamesLatch, pNewName );
+ Vec_PtrPush( pNodeNew->pNtk->vNamesPi, pNewName );
+ Vec_PtrPush( pNodeNew->pNtk->vNamesPo, pNewName );
+ }
+ else
+ assert( 0 );
+ return pNewName;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates the name arrays from the old network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkCreateNameArrays( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew )
+{
+ Abc_Obj_t * pNet, * pLatch;
+ int i;
+ assert( Abc_NtkIsNetlist(pNtk) );
+ assert( !Abc_NtkIsNetlist(pNtkNew) );
+ assert( Abc_NtkPiNum(pNtk) == Abc_NtkPiNum(pNtkNew) );
+ assert( Abc_NtkPoNum(pNtk) == Abc_NtkPoNum(pNtkNew) );
+ assert( Abc_NtkLatchNum(pNtk) == Abc_NtkLatchNum(pNtkNew) );
+ assert( st_count(pNtkNew->tName2Net) == 0 );
+ Abc_NtkForEachPi( pNtk, pNet, i )
+ Abc_NtkLogicStoreName( pNtkNew->vPis->pArray[i], pNet->pData );
+ Abc_NtkForEachPo( pNtk, pNet, i )
+ Abc_NtkLogicStoreName( pNtkNew->vPos->pArray[i], pNet->pData );
+ Abc_NtkForEachLatch( pNtk, pLatch, i )
+ Abc_NtkLogicStoreName( pNtkNew->vLatches->pArray[i], Abc_ObjFanout0(pLatch)->pData );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Duplicates the name arrays.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkDupNameArrays( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew )
+{
+ Abc_Obj_t * pObj, * pLatch;
+ int i;
+ assert( !Abc_NtkIsNetlist(pNtk) );
+ assert( !Abc_NtkIsNetlist(pNtkNew) );
+ assert( Abc_NtkPiNum(pNtk) == Abc_NtkPiNum(pNtkNew) );
+ assert( Abc_NtkPoNum(pNtk) == Abc_NtkPoNum(pNtkNew) );
+ assert( Abc_NtkLatchNum(pNtk) == Abc_NtkLatchNum(pNtkNew) );
+ assert( st_count(pNtkNew->tName2Net) == 0 );
+ // copy the CI/CO names if given
+ Abc_NtkForEachPi( pNtk, pObj, i )
+ Abc_NtkLogicStoreName( pNtkNew->vPis->pArray[i], pNtk->vNamesPi->pArray[i] );
+ Abc_NtkForEachPo( pNtk, pObj, i )
+ Abc_NtkLogicStoreName( pNtkNew->vPos->pArray[i], pNtk->vNamesPo->pArray[i] );
+ Abc_NtkForEachLatch( pNtk, pLatch, i )
+ Abc_NtkLogicStoreName( pNtkNew->vLatches->pArray[i], pNtk->vNamesLatch->pArray[i] );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcNetlist.c b/src/base/abc/abcNetlist.c
new file mode 100644
index 00000000..671fa9bc
--- /dev/null
+++ b/src/base/abc/abcNetlist.c
@@ -0,0 +1,93 @@
+/**CFile****************************************************************
+
+ FileName [abcNetlist.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Transforms netlist into a logic network and vice versa.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcNetlist.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Transform the netlist into a logic network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Abc_NtkLogic( Abc_Ntk_t * pNtk )
+{
+ Abc_Ntk_t * pNtkNew;
+ Abc_Obj_t * pObj, * pFanin;
+ int i, k;
+ assert( Abc_NtkIsNetlist(pNtk) );
+ // start the network
+ pNtkNew = Abc_NtkAlloc( ABC_NTK_LOGIC_SOP );
+ // duplicate the name and the spec
+ pNtkNew->pName = util_strsav(pNtk->pName);
+ pNtkNew->pSpec = util_strsav(pNtk->pSpec);
+ // clean the copy field
+ Abc_NtkCleanCopy( pNtk );
+ // create the PIs and point to them from the nets
+ Abc_NtkForEachPi( pNtk, pObj, i )
+ pObj->pCopy = Abc_NtkCreateTermPi( pNtkNew );
+ // create the latches and point to them from the latch fanout nets
+ Abc_NtkForEachLatch( pNtk, pObj, i )
+ Abc_ObjFanout0(pObj)->pCopy = Abc_NtkDupObj(pNtkNew, pObj);
+ // duplicate the nodes and point to them from the fanout nets
+ Abc_NtkForEachNode( pNtk, pObj, i )
+ Abc_ObjFanout0(pObj)->pCopy = Abc_NtkDupObj(pNtkNew, pObj);
+ // reconnect the internal nodes in the new network
+ Abc_NtkForEachNode( pNtk, pObj, i )
+ Abc_ObjForEachFanin( pObj, pFanin, k )
+ Abc_ObjAddFanin( pObj->pCopy, pFanin->pCopy );
+ // create and connect the POs
+ Abc_NtkForEachPo( pNtk, pObj, i )
+ Abc_ObjAddFanin( Abc_NtkCreateTermPo(pNtkNew), Abc_ObjFanin0(pObj)->pCopy );
+ // connect the latches
+ Abc_NtkForEachLatch( pNtk, pObj, i )
+ Abc_ObjAddFanin( pObj->pCopy, Abc_ObjFanin0(pObj)->pCopy );
+ // add the latches to the PI/PO arrays to make them look at CIs/COs
+ Abc_NtkForEachLatch( pNtk, pObj, i )
+ Vec_PtrPush( pNtkNew->vPis, pObj->pCopy );
+ Abc_NtkForEachLatch( pNtk, pObj, i )
+ Vec_PtrPush( pNtkNew->vPos, pObj->pCopy );
+ // transfer the names
+ Abc_NtkCreateNameArrays( pNtk, pNtkNew );
+ // duplicate EXDC
+ if ( pNtk->pExdc )
+ pNtkNew->pExdc = Abc_NtkLogic( pNtk->pExdc );
+ if ( !Abc_NtkCheck( pNtkNew ) )
+ fprintf( stdout, "Abc_NtkLogic(): Network check has failed.\n" );
+ return pNtkNew;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcPrint.c b/src/base/abc/abcPrint.c
new file mode 100644
index 00000000..0c3a2b5e
--- /dev/null
+++ b/src/base/abc/abcPrint.c
@@ -0,0 +1,288 @@
+/**CFile****************************************************************
+
+ FileName [abcPrint.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Printing statistics.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcPrint.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+#include "ft.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Print the vital stats of the network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkPrintStats( FILE * pFile, Abc_Ntk_t * pNtk )
+{
+ fprintf( pFile, "%-15s:", pNtk->pName );
+ fprintf( pFile, " i/o = %3d/%3d", Abc_NtkPiNum(pNtk), Abc_NtkPoNum(pNtk) );
+ fprintf( pFile, " lat = %4d", Abc_NtkLatchNum(pNtk) );
+
+ if ( Abc_NtkIsNetlist(pNtk) )
+ {
+ fprintf( pFile, " net = %5d", Abc_NtkNetNum(pNtk) );
+ fprintf( pFile, " nd = %5d", Abc_NtkNodeNum(pNtk) );
+ }
+ else if ( Abc_NtkIsAig(pNtk) )
+ fprintf( pFile, " and = %5d", Abc_NtkNodeNum(pNtk) );
+ else
+ fprintf( pFile, " nd = %5d", Abc_NtkNodeNum(pNtk) );
+
+ if ( Abc_NtkIsLogicSop(pNtk) )
+ {
+ fprintf( pFile, " cube = %5d", Abc_NtkGetCubeNum(pNtk) );
+// fprintf( pFile, " lit(sop) = %5d", Abc_NtkGetLitNum(pNtk) );
+ fprintf( pFile, " lit(fac) = %5d", Abc_NtkGetLitFactNum(pNtk) );
+ }
+ else if ( Abc_NtkIsLogicBdd(pNtk) )
+ fprintf( pFile, " bdd = %5d", Abc_NtkGetBddNodeNum(pNtk) );
+ else if ( Abc_NtkIsLogicMap(pNtk) )
+ {
+ fprintf( pFile, " area = %5.2f", Abc_NtkGetMappedArea(pNtk) );
+ fprintf( pFile, " delay = %5.2f", Abc_NtkDelayTrace(pNtk) );
+ }
+ fprintf( pFile, " lev = %2d", Abc_NtkGetLevelNum(pNtk) );
+ fprintf( pFile, "\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints PIs/POs and LIs/LOs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkPrintIo( FILE * pFile, Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNet, * pLatch;
+ int i;
+
+ if ( Abc_NtkIsNetlist(pNtk) )
+ {
+ fprintf( pFile, "Primary inputs (%d): ", Abc_NtkPiNum(pNtk) );
+ Abc_NtkForEachPi( pNtk, pNet, i )
+ fprintf( pFile, " %s", Abc_ObjName(pNet) );
+ fprintf( pFile, "\n" );
+
+ fprintf( pFile, "Primary outputs (%d):", Abc_NtkPoNum(pNtk) );
+ Abc_NtkForEachPo( pNtk, pNet, i )
+ fprintf( pFile, " %s", Abc_ObjName(pNet) );
+ fprintf( pFile, "\n" );
+
+ fprintf( pFile, "Latches (%d): ", Abc_NtkLatchNum(pNtk) );
+ Abc_NtkForEachLatch( pNtk, pLatch, i )
+ fprintf( pFile, " %s", Abc_ObjName(Abc_ObjFanout0(pLatch)) );
+ fprintf( pFile, "\n" );
+ }
+ else
+ {
+ fprintf( pFile, "Primary inputs (%d): ", Abc_NtkPiNum(pNtk) );
+ Abc_NtkForEachPi( pNtk, pNet, i )
+ fprintf( pFile, " %s", pNtk->vNamesPi->pArray[i] );
+ fprintf( pFile, "\n" );
+
+ fprintf( pFile, "Primary outputs (%d):", Abc_NtkPoNum(pNtk) );
+ Abc_NtkForEachPo( pNtk, pNet, i )
+ fprintf( pFile, " %s", pNtk->vNamesPo->pArray[i] );
+ fprintf( pFile, "\n" );
+
+ fprintf( pFile, "Latches (%d): ", Abc_NtkLatchNum(pNtk) );
+ Abc_NtkForEachLatch( pNtk, pLatch, i )
+ fprintf( pFile, " %s", pNtk->vNamesLatch->pArray[i] );
+ fprintf( pFile, "\n" );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the distribution of fanins/fanouts in the network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkPrintFanio( FILE * pFile, Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ int i, k, nFanins, nFanouts;
+ Vec_Int_t * vFanins, * vFanouts;
+ int nOldSize, nNewSize;
+
+ vFanins = Vec_IntAlloc( 0 );
+ vFanouts = Vec_IntAlloc( 0 );
+ Vec_IntFill( vFanins, 100, 0 );
+ Vec_IntFill( vFanouts, 100, 0 );
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ nFanins = Abc_ObjFaninNum(pNode);
+ if ( Abc_NtkIsNetlist(pNtk) )
+ nFanouts = Abc_ObjFanoutNum( Abc_ObjFanout0(pNode) );
+ else
+ nFanouts = Abc_ObjFanoutNum(pNode);
+ if ( nFanins > vFanins->nSize || nFanouts > vFanouts->nSize )
+ {
+ nOldSize = vFanins->nSize;
+ nNewSize = ABC_MAX(nFanins, nFanouts) + 10;
+ Vec_IntGrow( vFanins, nNewSize );
+ Vec_IntGrow( vFanouts, nNewSize );
+ for ( k = nOldSize; k < nNewSize; k++ )
+ {
+ Vec_IntPush( vFanins, 0 );
+ Vec_IntPush( vFanouts, 0 );
+ }
+ }
+ vFanins->pArray[nFanins]++;
+ vFanouts->pArray[nFanouts]++;
+ }
+ fprintf( pFile, "The distribution of fanins and fanouts in the network:\n" );
+ fprintf( pFile, " Number Nodes with fanin Nodes with fanout\n" );
+ for ( k = 0; k < vFanins->nSize; k++ )
+ {
+ if ( vFanins->pArray[k] == 0 && vFanouts->pArray[k] == 0 )
+ continue;
+ fprintf( pFile, "%5d : ", k );
+ if ( vFanins->pArray[k] == 0 )
+ fprintf( pFile, " " );
+ else
+ fprintf( pFile, "%12d ", vFanins->pArray[k] );
+ fprintf( pFile, " " );
+ if ( vFanouts->pArray[k] == 0 )
+ fprintf( pFile, " " );
+ else
+ fprintf( pFile, "%12d ", vFanouts->pArray[k] );
+ fprintf( pFile, "\n" );
+ }
+ Vec_IntFree( vFanins );
+ Vec_IntFree( vFanouts );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the fanins/fanouts of a node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NodePrintFanio( FILE * pFile, Abc_Obj_t * pNode )
+{
+ Abc_Obj_t * pNode2;
+ int i;
+ if ( Abc_ObjIsPo(pNode) )
+ pNode = Abc_ObjFanin0(pNode);
+
+ fprintf( pFile, "Fanins (%d): ", Abc_ObjFaninNum(pNode) );
+ Abc_ObjForEachFanin( pNode, pNode2, i )
+ {
+ pNode2->pCopy = NULL;
+ fprintf( pFile, " %s", Abc_ObjName(pNode2) );
+ }
+ fprintf( pFile, "\n" );
+
+ fprintf( pFile, "\n" );
+ fprintf( pFile, "Fanouts (%d): ", Abc_ObjFaninNum(pNode) );
+ Abc_ObjForEachFanout( pNode, pNode2, i )
+ {
+ pNode2->pCopy = NULL;
+ fprintf( pFile, " %s", Abc_ObjName(pNode2) );
+ }
+ fprintf( pFile, "\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the factored form of one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkPrintFactor( FILE * pFile, Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ int i;
+ assert( Abc_NtkIsNetlist(pNtk) || Abc_NtkIsLogicSop(pNtk) );
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ Abc_NodePrintFactor( pFile, pNode );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the factored form of one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NodePrintFactor( FILE * pFile, Abc_Obj_t * pNode )
+{
+ Vec_Int_t * vFactor;
+ if ( Abc_ObjIsPo(pNode) )
+ pNode = Abc_ObjFanin0(pNode);
+ if ( Abc_ObjIsPi(pNode) )
+ {
+ printf( "Skipping the PI node.\n" );
+ return;
+ }
+ if ( Abc_ObjIsLatch(pNode) )
+ {
+ printf( "Skipping the latch.\n" );
+ return;
+ }
+ assert( Abc_ObjIsNode(pNode) );
+ vFactor = Ft_Factor( pNode->pData );
+ pNode->pCopy = NULL;
+ Ft_FactorPrint( stdout, vFactor, NULL, Abc_ObjName(pNode) );
+ Vec_IntFree( vFactor );
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcRefs.c b/src/base/abc/abcRefs.c
new file mode 100644
index 00000000..b6a7dce1
--- /dev/null
+++ b/src/base/abc/abcRefs.c
@@ -0,0 +1,133 @@
+/**CFile****************************************************************
+
+ FileName [abcRefs.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Reference counting of the nodes.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcRefs.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Abc_NodeRefDeref( Abc_Obj_t * pNode, bool fFanouts, bool fReference );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Procedure returns the size of the MFFC of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NodeMffcSize( Abc_Obj_t * pNode )
+{
+ int nConeSize1, nConeSize2;
+ assert( !Abc_ObjIsComplement( pNode ) );
+ assert( Abc_ObjIsNode( pNode ) );
+ nConeSize1 = Abc_NodeRefDeref( pNode, 0, 0 ); // dereference
+ nConeSize2 = Abc_NodeRefDeref( pNode, 0, 1 ); // reference
+ assert( nConeSize1 == nConeSize2 );
+ assert( nConeSize1 > 0 );
+ return nConeSize1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Procedure returns the size of the MFFC of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NodeMffcRemove( Abc_Obj_t * pNode )
+{
+ assert( !Abc_ObjIsComplement( pNode ) );
+ assert( Abc_ObjIsNode( pNode ) );
+ return Abc_NodeRefDeref( pNode, 1, 0 ); // dereference
+}
+
+/**Function*************************************************************
+
+ Synopsis [References/references the node and returns MFFC size.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NodeRefDeref( Abc_Obj_t * pNode, bool fFanouts, bool fReference )
+{
+ Abc_Obj_t * pNode0, * pNode1;
+ int Counter;
+ if ( Abc_ObjIsPi(pNode) || Abc_ObjIsLatch(pNode) )
+ return 0;
+ pNode0 = Abc_ObjFanin( pNode, 0 );
+ pNode1 = Abc_ObjFanin( pNode, 1 );
+ Counter = 1;
+ if ( fReference )
+ {
+ if ( pNode0->vFanouts.nSize++ == 0 )
+ {
+ Counter += Abc_NodeRefDeref( pNode0, fFanouts, fReference );
+ if ( fFanouts )
+ Abc_ObjAddFanin( pNode, pNode0 );
+ }
+ if ( pNode1->vFanouts.nSize++ == 0 )
+ {
+ Counter += Abc_NodeRefDeref( pNode1, fFanouts, fReference );
+ if ( fFanouts )
+ Abc_ObjAddFanin( pNode, pNode1 );
+ }
+ }
+ else
+ {
+ assert( pNode0->vFanouts.nSize > 0 );
+ assert( pNode1->vFanouts.nSize > 0 );
+ if ( --pNode0->vFanouts.nSize == 0 )
+ {
+ Counter += Abc_NodeRefDeref( pNode0, fFanouts, fReference );
+ if ( fFanouts )
+ Abc_ObjDeleteFanin( pNode, pNode0 );
+ }
+ if ( --pNode1->vFanouts.nSize == 0 )
+ {
+ Counter += Abc_NodeRefDeref( pNode1, fFanouts, fReference );
+ if ( fFanouts )
+ Abc_ObjDeleteFanin( pNode, pNode1 );
+ }
+ }
+ return Counter;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcRenode.c b/src/base/abc/abcRenode.c
new file mode 100644
index 00000000..6a24ab80
--- /dev/null
+++ b/src/base/abc/abcRenode.c
@@ -0,0 +1,605 @@
+/**CFile****************************************************************
+
+ FileName [abcRenode.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Procedures which transform an AIG into the network of nodes.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcRenode.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Abc_NtkRenodeInt( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew );
+static Abc_Obj_t * Abc_NtkRenode_rec( Abc_Ntk_t * pNtkNew, Abc_Obj_t * pNodeOld );
+
+static DdNode * Abc_NtkRenodeDeriveBdd_rec( DdManager * dd, Abc_Obj_t * pNodeOld, Vec_Ptr_t * vFanins );
+
+static void Abc_NtkRenodeSetBounds( Abc_Ntk_t * pNtk, int nThresh, int nFaninMax );
+static void Abc_NtkRenodeSetBoundsCnf( Abc_Ntk_t * pNtk );
+static void Abc_NtkRenodeSetBoundsMulti( Abc_Ntk_t * pNtk );
+static void Abc_NtkRenodeSetBoundsSimple( Abc_Ntk_t * pNtk );
+static void Abc_NtkRenodeCone( Abc_Obj_t * pNode, Vec_Ptr_t * vCone );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Transforms the AIG into nodes.]
+
+ Description [Threhold is the max number of nodes duplicated at a node.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Abc_NtkRenode( Abc_Ntk_t * pNtk, int nThresh, int nFaninMax, int fCnf, int fMulti, int fSimple )
+{
+ int fCheck = 1;
+ Abc_Ntk_t * pNtkNew;
+
+ assert( Abc_NtkIsAig(pNtk) );
+ assert( nThresh >= 0 );
+ assert( nFaninMax > 1 );
+
+ // print a warning about choice nodes
+ if ( Abc_NtkCountChoiceNodes( pNtk ) )
+ printf( "Warning: The choice nodes in the AIG are removed by renoding.\n" );
+
+ // define the boundary
+ if ( fCnf )
+ Abc_NtkRenodeSetBoundsCnf( pNtk );
+ else if ( fMulti )
+ Abc_NtkRenodeSetBoundsMulti( pNtk );
+ else if ( fSimple )
+ Abc_NtkRenodeSetBoundsSimple( pNtk );
+ else
+ Abc_NtkRenodeSetBounds( pNtk, nThresh, nFaninMax );
+
+ // perform renoding for this boundary
+ pNtkNew = Abc_NtkStartFrom( pNtk, ABC_NTK_LOGIC_BDD );
+ Abc_NtkRenodeInt( pNtk, pNtkNew );
+ Abc_NtkFinalize( pNtk, pNtkNew );
+
+ // make the network minimum base
+ Abc_NtkMinimumBase( pNtkNew );
+
+ // report the number of CNF objects
+ if ( fCnf )
+ {
+// int nClauses = Abc_NtkGetClauseNum(pNtkNew) + 2*Abc_NtkPoNum(pNtkNew) + 2*Abc_NtkLatchNum(pNtkNew);
+// printf( "CNF variables = %d. CNF clauses = %d.\n", Abc_NtkNodeNum(pNtkNew), nClauses );
+ }
+//printf( "Maximum fanin = %d.\n", Abc_NtkGetFaninMax(pNtkNew) );
+
+ // make sure everything is okay
+ if ( fCheck && !Abc_NtkCheck( pNtkNew ) )
+ {
+ printf( "Abc_NtkRenode: The network check has failed.\n" );
+ Abc_NtkDelete( pNtkNew );
+ return NULL;
+ }
+ return pNtkNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Transforms the AIG into nodes.]
+
+ Description [Threhold is the max number of nodes duplicated at a node.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkRenodeInt( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew )
+{
+ ProgressBar * pProgress;
+ Abc_Obj_t * pNode, * pConst1, * pNodeNew;
+ int i;
+
+ // set the constant node
+ pConst1 = Abc_AigConst1(pNtk->pManFunc);
+ if ( Abc_ObjFanoutNum(pConst1) > 0 )
+ {
+ pNodeNew = Abc_NtkCreateNode( pNtkNew );
+ pNodeNew->pData = Cudd_ReadOne( pNtkNew->pManFunc ); Cudd_Ref( pNodeNew->pData );
+ pConst1->pCopy = pNodeNew;
+ }
+
+ // perform renoding for POs
+ pProgress = Extra_ProgressBarStart( stdout, Abc_NtkCoNum(pNtk) );
+ Abc_NtkForEachCo( pNtk, pNode, i )
+ {
+ Extra_ProgressBarUpdate( pProgress, i, NULL );
+ Abc_NtkRenode_rec( pNtkNew, Abc_ObjFanin0(pNode) );
+ }
+ Extra_ProgressBarStop( pProgress );
+
+ // clean the boundaries and data field in the old network
+ Abc_NtkForEachObj( pNtk, pNode, i )
+ {
+ pNode->fMarkA = 0;
+ pNode->pData = NULL;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Find the best multi-input node rooted at the given node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NtkRenode_rec( Abc_Ntk_t * pNtkNew, Abc_Obj_t * pNodeOld )
+{
+ Vec_Ptr_t * vCone;
+ Abc_Obj_t * pNodeNew;
+ int i;
+
+ assert( !Abc_ObjIsComplement(pNodeOld) );
+ // return if the result if known
+ if ( pNodeOld->pCopy )
+ return pNodeOld->pCopy;
+ assert( Abc_ObjIsNode(pNodeOld) );
+ assert( !Abc_NodeIsConst(pNodeOld) );
+ assert( pNodeOld->fMarkA );
+
+ // collect the renoding cone
+ vCone = Vec_PtrAlloc( 10 );
+ Abc_NtkRenodeCone( pNodeOld, vCone );
+
+ // create a new node
+ pNodeNew = Abc_NtkCreateNode( pNtkNew );
+ for ( i = 0; i < vCone->nSize; i++ )
+ Abc_ObjAddFanin( pNodeNew, Abc_NtkRenode_rec(pNtkNew, vCone->pArray[i]) );
+
+ // derive the function of this node
+ pNodeNew->pData = Abc_NtkRenodeDeriveBdd( pNtkNew->pManFunc, pNodeOld, vCone );
+ Cudd_Ref( pNodeNew->pData );
+ Vec_PtrFree( vCone );
+
+ // remember the node
+ pNodeOld->pCopy = pNodeNew;
+ return pNodeOld->pCopy;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Derives the local BDD of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Abc_NtkRenodeDeriveBdd( DdManager * dd, Abc_Obj_t * pNodeOld, Vec_Ptr_t * vFaninsOld )
+{
+ Abc_Obj_t * pFaninOld;
+ DdNode * bFunc;
+ int i;
+ assert( !Abc_NodeIsConst(pNodeOld) );
+ assert( Abc_ObjIsNode(pNodeOld) );
+ // set the elementary BDD variables for the input nodes
+ for ( i = 0; i < vFaninsOld->nSize; i++ )
+ {
+ pFaninOld = vFaninsOld->pArray[i];
+ pFaninOld->pData = Cudd_bddIthVar( dd, i ); Cudd_Ref( pFaninOld->pData );
+ pFaninOld->fMarkC = 1;
+ }
+ // call the recursive BDD computation
+ bFunc = Abc_NtkRenodeDeriveBdd_rec( dd, pNodeOld, vFaninsOld ); Cudd_Ref( bFunc );
+ // dereference the intermediate nodes
+ for ( i = 0; i < vFaninsOld->nSize; i++ )
+ {
+ pFaninOld = vFaninsOld->pArray[i];
+ Cudd_RecursiveDeref( dd, pFaninOld->pData );
+ pFaninOld->fMarkC = 0;
+ }
+ Cudd_Deref( bFunc );
+ return bFunc;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Derives the local BDD of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Abc_NtkRenodeDeriveBdd_rec( DdManager * dd, Abc_Obj_t * pNode, Vec_Ptr_t * vFanins )
+{
+ DdNode * bFunc, * bFunc0, * bFunc1;
+ assert( !Abc_ObjIsComplement(pNode) );
+ // if the result is available return
+ if ( pNode->fMarkC )
+ {
+ assert( pNode->pData ); // network has a cycle
+ return pNode->pData;
+ }
+ // mark the node as visited
+ pNode->fMarkC = 1;
+ Vec_PtrPush( vFanins, pNode );
+ // compute the result for both branches
+ bFunc0 = Abc_NtkRenodeDeriveBdd_rec( dd, Abc_ObjFanin(pNode,0), vFanins ); Cudd_Ref( bFunc0 );
+ bFunc1 = Abc_NtkRenodeDeriveBdd_rec( dd, Abc_ObjFanin(pNode,1), vFanins ); Cudd_Ref( bFunc1 );
+ bFunc0 = Cudd_NotCond( bFunc0, Abc_ObjFaninC0(pNode) );
+ bFunc1 = Cudd_NotCond( bFunc1, Abc_ObjFaninC1(pNode) );
+ // get the final result
+ bFunc = Cudd_bddAnd( dd, bFunc0, bFunc1 ); Cudd_Ref( bFunc );
+ Cudd_RecursiveDeref( dd, bFunc0 );
+ Cudd_RecursiveDeref( dd, bFunc1 );
+ // set the result
+ pNode->pData = bFunc;
+ assert( pNode->pData );
+ return bFunc;
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Limits the cones to be no more than the given size.]
+
+ Description [Returns 1 if the last cone was limited. Returns 0 if no changes.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkRenodeLimit_rec( Abc_Obj_t * pNode, Vec_Ptr_t * vCone, int nFaninMax, int fCanStop, int fFirst )
+{
+ int nNodes0, nNodes1;
+ assert( !Abc_ObjIsComplement(pNode) );
+ // check if the node should be added to the fanins
+ if ( !fFirst && (pNode->fMarkA || !Abc_ObjIsNode(pNode)) )
+ {
+ Vec_PtrPushUnique( vCone, pNode );
+ return 0;
+ }
+ // if we cannot stop in this branch, collect all nodes
+ if ( !fCanStop )
+ {
+ Abc_NtkRenodeLimit_rec( Abc_ObjFanin(pNode,0), vCone, nFaninMax, 0, 0 );
+ Abc_NtkRenodeLimit_rec( Abc_ObjFanin(pNode,1), vCone, nFaninMax, 0, 0 );
+ return 0;
+ }
+ // if we can stop, try the left branch first, and return if we stopped
+ assert( vCone->nSize == 0 );
+ if ( Abc_NtkRenodeLimit_rec( Abc_ObjFanin(pNode,0), vCone, nFaninMax, 1, 0 ) )
+ return 1;
+ // save the number of nodes in the left branch and call for the right branch
+ nNodes0 = vCone->nSize;
+ assert( nNodes0 <= nFaninMax );
+ Abc_NtkRenodeLimit_rec( Abc_ObjFanin(pNode,1), vCone, nFaninMax, 0, 0 );
+ // check the number of nodes
+ if ( vCone->nSize <= nFaninMax )
+ return 0;
+ // the number of nodes exceeds the limit
+
+ // get the number of nodes in the right branch
+ vCone->nSize = 0;
+ Abc_NtkRenodeLimit_rec( Abc_ObjFanin(pNode,1), vCone, nFaninMax, 0, 0 );
+ // if this number exceeds the limit, solve the problem for this branch
+ if ( vCone->nSize > nFaninMax )
+ {
+ int RetValue;
+ vCone->nSize = 0;
+ RetValue = Abc_NtkRenodeLimit_rec( Abc_ObjFanin(pNode,1), vCone, nFaninMax, 1, 0 );
+ assert( RetValue == 1 );
+ return 1;
+ }
+
+ nNodes1 = vCone->nSize;
+ assert( nNodes1 <= nFaninMax );
+ if ( nNodes0 >= nNodes1 )
+ { // the left branch is larger - cut it
+ assert( Abc_ObjFanin(pNode,0)->fMarkA == 0 );
+ Abc_ObjFanin(pNode,0)->fMarkA = 1;
+ }
+ else
+ { // the right branch is larger - cut it
+ assert( Abc_ObjFanin(pNode,1)->fMarkA == 0 );
+ Abc_ObjFanin(pNode,1)->fMarkA = 1;
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Limits the cones to be no more than the given size.]
+
+ Description [Returns 1 if the last cone was limited. Returns 0 if no changes.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkRenodeLimit( Abc_Obj_t * pNode, Vec_Ptr_t * vCone, int nFaninMax )
+{
+ vCone->nSize = 0;
+ return Abc_NtkRenodeLimit_rec( pNode, vCone, nFaninMax, 1, 1 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the expansion boundary for multi-input nodes.]
+
+ Description [The boundary includes the set of PIs and all nodes such that
+ when expanding over the node we duplicate no more than nThresh nodes.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkRenodeSetBounds( Abc_Ntk_t * pNtk, int nThresh, int nFaninMax )
+{
+ Vec_Ptr_t * vCone = pNtk->vPtrTemp;
+ Abc_Obj_t * pNode;
+ int i, nFanouts, nConeSize;
+
+ // make sure the mark is not set
+ Abc_NtkForEachObj( pNtk, pNode, i )
+ assert( pNode->fMarkA == 0 );
+
+ // mark the nodes where expansion stops using pNode->fMarkA
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ // skip PI/PO nodes
+ if ( Abc_NodeIsConst(pNode) )
+ continue;
+ // mark the nodes with multiple fanouts
+ nFanouts = Abc_ObjFanoutNum(pNode);
+ nConeSize = Abc_NodeMffcSize(pNode);
+ if ( (nFanouts - 1) * nConeSize > nThresh )
+ pNode->fMarkA = 1;
+ }
+
+ // mark the PO drivers
+ Abc_NtkForEachPo( pNtk, pNode, i )
+ Abc_ObjFanin0(pNode)->fMarkA = 1;
+ Abc_NtkForEachLatch( pNtk, pNode, i )
+ Abc_ObjFanin0(pNode)->fMarkA = 1;
+
+ // make sure the fanin limit is met
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ // skip PI/PO nodes
+ if ( Abc_NodeIsConst(pNode) )
+ continue;
+ if ( pNode->fMarkA == 0 )
+ continue;
+ // continue cutting branches ntil it meets the fanin limit
+ while ( Abc_NtkRenodeLimit(pNode, vCone, nFaninMax) );
+ assert( vCone->nSize <= nFaninMax );
+ }
+/*
+ // make sure the fanin limit is met
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ // skip PI/PO nodes
+ if ( Abc_NodeIsConst(pNode) )
+ continue;
+ if ( pNode->fMarkA == 0 )
+ continue;
+ Abc_NtkRenodeCone( pNode, vCone );
+ assert( vCone->nSize <= nFaninMax );
+ }
+*/
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the expansion boundary for conversion into CNF.]
+
+ Description [The boundary includes the set of PIs, the roots of MUXes,
+ the nodes with multiple fanouts and the nodes with complemented outputs.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkRenodeSetBoundsCnf( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ int i, nMuxes;
+
+ // make sure the mark is not set
+ Abc_NtkForEachObj( pNtk, pNode, i )
+ assert( pNode->fMarkA == 0 );
+
+ // mark the nodes where expansion stops using pNode->fMarkA
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ // skip PI/PO nodes
+ if ( Abc_NodeIsConst(pNode) )
+ continue;
+ // mark the nodes with multiple fanouts
+ if ( Abc_ObjFanoutNum(pNode) > 1 )
+ pNode->fMarkA = 1;
+ // mark the nodes that are roots of MUXes
+ if ( Abc_NodeIsMuxType( pNode ) )
+ {
+ pNode->fMarkA = 1;
+ Abc_ObjFanin0( Abc_ObjFanin0(pNode) )->fMarkA = 1;
+ Abc_ObjFanin0( Abc_ObjFanin1(pNode) )->fMarkA = 1;
+ Abc_ObjFanin1( Abc_ObjFanin0(pNode) )->fMarkA = 1;
+ Abc_ObjFanin1( Abc_ObjFanin1(pNode) )->fMarkA = 1;
+ }
+ else // mark the complemented edges
+ {
+ if ( Abc_ObjFaninC0(pNode) )
+ Abc_ObjFanin0(pNode)->fMarkA = 1;
+ if ( Abc_ObjFaninC1(pNode) )
+ Abc_ObjFanin1(pNode)->fMarkA = 1;
+ }
+ }
+
+ // mark the PO drivers
+ Abc_NtkForEachPo( pNtk, pNode, i )
+ Abc_ObjFanin0(pNode)->fMarkA = 1;
+ Abc_NtkForEachLatch( pNtk, pNode, i )
+ Abc_ObjFanin0(pNode)->fMarkA = 1;
+
+ // count the number of MUXes
+ nMuxes = 0;
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ // skip PI/PO nodes
+ if ( Abc_NodeIsConst(pNode) )
+ continue;
+ if ( Abc_NodeIsMuxType(pNode) &&
+ Abc_ObjFanin0(pNode)->fMarkA == 0 &&
+ Abc_ObjFanin1(pNode)->fMarkA == 0 )
+ nMuxes++;
+ }
+ printf( "The number of MUXes detected = %d (%5.2f %% of logic).\n", nMuxes, 300.0*nMuxes/Abc_NtkNodeNum(pNtk) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the expansion boundary for conversion into multi-input AND graph.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkRenodeSetBoundsMulti( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ int i;
+
+ // make sure the mark is not set
+ Abc_NtkForEachObj( pNtk, pNode, i )
+ assert( pNode->fMarkA == 0 );
+
+ // mark the nodes where expansion stops using pNode->fMarkA
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ // skip PI/PO nodes
+ if ( Abc_NodeIsConst(pNode) )
+ continue;
+ // mark the nodes with multiple fanouts
+ if ( Abc_ObjFanoutNum(pNode) > 1 )
+ pNode->fMarkA = 1;
+ // mark the children if they are pointed by the complemented edges
+ if ( Abc_ObjFaninC0(pNode) )
+ Abc_ObjFanin0(pNode)->fMarkA = 1;
+ if ( Abc_ObjFaninC1(pNode) )
+ Abc_ObjFanin1(pNode)->fMarkA = 1;
+ }
+
+ // mark the PO drivers
+ Abc_NtkForEachPo( pNtk, pNode, i )
+ Abc_ObjFanin0(pNode)->fMarkA = 1;
+ Abc_NtkForEachLatch( pNtk, pNode, i )
+ Abc_ObjFanin0(pNode)->fMarkA = 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets a simple boundary.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkRenodeSetBoundsSimple( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ int i;
+ // make sure the mark is not set
+ Abc_NtkForEachObj( pNtk, pNode, i )
+ assert( pNode->fMarkA == 0 );
+ // mark the nodes where expansion stops using pNode->fMarkA
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ pNode->fMarkA = 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collects the fanins of a large node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkRenodeCone_rec( Abc_Obj_t * pNode, Vec_Ptr_t * vCone )
+{
+ assert( !Abc_ObjIsComplement(pNode) );
+ if ( pNode->fMarkA || !Abc_ObjIsNode(pNode) )
+ {
+ Vec_PtrPushUnique( vCone, pNode );
+ return;
+ }
+ Abc_NtkRenodeCone_rec( Abc_ObjFanin(pNode,0), vCone );
+ Abc_NtkRenodeCone_rec( Abc_ObjFanin(pNode,1), vCone );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collects the fanins of a large node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkRenodeCone( Abc_Obj_t * pNode, Vec_Ptr_t * vCone )
+{
+ assert( !Abc_ObjIsComplement(pNode) );
+ assert( Abc_ObjIsNode(pNode) );
+ vCone->nSize = 0;
+ Abc_NtkRenodeCone_rec( Abc_ObjFanin(pNode,0), vCone );
+ Abc_NtkRenodeCone_rec( Abc_ObjFanin(pNode,1), vCone );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcSat.c b/src/base/abc/abcSat.c
new file mode 100644
index 00000000..fccb7fbc
--- /dev/null
+++ b/src/base/abc/abcSat.c
@@ -0,0 +1,252 @@
+/**CFile****************************************************************
+
+ FileName [abcSat.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Procedures to solve the miter using the internal SAT solver.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcSat.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Abc_NodeAddClauses( solver * pSat, char * pSop0, char * pSop1, Abc_Obj_t * pNode, Vec_Int_t * vVars );
+static void Abc_NodeAddClausesTop( solver * pSat, Abc_Obj_t * pNode, Vec_Int_t * vVars );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Attempts to solve the miter using an internal SAT solver.]
+
+ Description [Returns 1 if the miter is SAT.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkMiterSat( Abc_Ntk_t * pNtk, int fVerbose )
+{
+ solver * pSat;
+ lbool status;
+ int clk;
+
+ assert( Abc_NtkIsLogicBdd(pNtk) );
+ assert( Abc_NtkLatchNum(pNtk) == 0 );
+
+ if ( Abc_NtkPoNum(pNtk) > 1 )
+ fprintf( stdout, "Warning: The miter has more than 1 output. SAT will try to prove all of them.\n" );
+
+ // load clauses into the solver
+ clk = clock();
+ pSat = Abc_NtkMiterSatCreate( pNtk );
+// printf( "Created SAT problem with %d variable and %d clauses. ",
+// solver_nvars(pSat), solver_nclauses(pSat) );
+// PRT( "Time", clock() - clk );
+
+ // simplify the problem
+ clk = clock();
+ status = solver_simplify(pSat);
+// printf( "Simplified the problem to %d variables and %d clauses. ",
+// solver_nvars(pSat), solver_nclauses(pSat) );
+// PRT( "Time", clock() - clk );
+ if ( status == l_False )
+ {
+ solver_delete( pSat );
+ printf( "The problem is UNSAT after simplification.\n" );
+ return 0;
+ }
+
+ // solve the miter
+ clk = clock();
+ if ( fVerbose )
+ pSat->verbosity = 1;
+ status = solver_solve( pSat, NULL, NULL );
+// if ( fVerbose )
+// {
+ printf( "The problem is %5s. ", (status == l_True)? "SAT" : "UNSAT" );
+ PRT( "SAT solver time", clock() - clk );
+// }
+ // free the solver
+ solver_delete( pSat );
+ return status == l_True;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets up the SAT solver.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+solver * Abc_NtkMiterSatCreate( Abc_Ntk_t * pNtk )
+{
+ solver * pSat;
+ Extra_MmFlex_t * pMmFlex;
+ Abc_Obj_t * pNode;
+ Vec_Str_t * vCube;
+ Vec_Int_t * vVars;
+ char * pSop0, * pSop1;
+ int i;
+
+ assert( Abc_NtkIsLogicBdd(pNtk) );
+
+ // start the data structures
+ pSat = solver_new();
+ pMmFlex = Extra_MmFlexStart();
+ vCube = Vec_StrAlloc( 100 );
+ vVars = Vec_IntAlloc( 100 );
+
+ // add clauses for each internal nodes
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ // derive SOPs for both phases of the node
+ Abc_NodeBddToCnf( pNode, pMmFlex, vCube, &pSop0, &pSop1 );
+ // add the clauses to the solver
+ Abc_NodeAddClauses( pSat, pSop0, pSop1, pNode, vVars );
+ }
+ // add clauses for each PO
+ Abc_NtkForEachPo( pNtk, pNode, i )
+ Abc_NodeAddClausesTop( pSat, pNode, vVars );
+
+ // delete
+ Vec_StrFree( vCube );
+ Vec_IntFree( vVars );
+ Extra_MmFlexStop( pMmFlex, 0 );
+ return pSat;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Adds clauses for the internal node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NodeAddClauses( solver * pSat, char * pSop0, char * pSop1, Abc_Obj_t * pNode, Vec_Int_t * vVars )
+{
+ Abc_Obj_t * pFanin;
+ int i, c, nFanins;
+ char * pCube;
+
+ nFanins = Abc_ObjFaninNum( pNode );
+ assert( nFanins == Abc_SopGetVarNum( pSop0 ) );
+
+ // add clauses for the negative phase
+ for ( c = 0; ; c++ )
+ {
+ // get the cube
+ pCube = pSop0 + c * (nFanins + 3);
+ if ( *pCube == 0 )
+ break;
+ // add the clause
+ vVars->nSize = 0;
+ Abc_ObjForEachFanin( pNode, pFanin, i )
+ {
+ if ( pCube[i] == '0' )
+ Vec_IntPush( vVars, toLit(pFanin->Id) );
+ else if ( pCube[i] == '1' )
+ Vec_IntPush( vVars, neg(toLit(pFanin->Id)) );
+ }
+ Vec_IntPush( vVars, neg(toLit(pNode->Id)) );
+ solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize );
+ }
+
+ // add clauses for the positive phase
+ for ( c = 0; ; c++ )
+ {
+ // get the cube
+ pCube = pSop1 + c * (nFanins + 3);
+ if ( *pCube == 0 )
+ break;
+ // add the clause
+ vVars->nSize = 0;
+ Abc_ObjForEachFanin( pNode, pFanin, i )
+ {
+ if ( pCube[i] == '0' )
+ Vec_IntPush( vVars, toLit(pFanin->Id) );
+ else if ( pCube[i] == '1' )
+ Vec_IntPush( vVars, neg(toLit(pFanin->Id)) );
+ }
+ Vec_IntPush( vVars, toLit(pNode->Id) );
+ solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Adds clauses for the PO node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NodeAddClausesTop( solver * pSat, Abc_Obj_t * pNode, Vec_Int_t * vVars )
+{
+ Abc_Obj_t * pFanin;
+
+ pFanin = Abc_ObjFanin0(pNode);
+ if ( Abc_ObjFaninC0(pNode) )
+ {
+ vVars->nSize = 0;
+ Vec_IntPush( vVars, toLit(pFanin->Id) );
+ Vec_IntPush( vVars, toLit(pNode->Id) );
+ solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize );
+
+ vVars->nSize = 0;
+ Vec_IntPush( vVars, neg(toLit(pFanin->Id)) );
+ Vec_IntPush( vVars, neg(toLit(pNode->Id)) );
+ solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize );
+ }
+ else
+ {
+ vVars->nSize = 0;
+ Vec_IntPush( vVars, neg(toLit(pFanin->Id)) );
+ Vec_IntPush( vVars, toLit(pNode->Id) );
+ solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize );
+
+ vVars->nSize = 0;
+ Vec_IntPush( vVars, toLit(pFanin->Id) );
+ Vec_IntPush( vVars, neg(toLit(pNode->Id)) );
+ solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize );
+ }
+
+ vVars->nSize = 0;
+ Vec_IntPush( vVars, toLit(pNode->Id) );
+ solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize );
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcSop.c b/src/base/abc/abcSop.c
new file mode 100644
index 00000000..9862ea8e
--- /dev/null
+++ b/src/base/abc/abcSop.c
@@ -0,0 +1,461 @@
+/**CFile****************************************************************
+
+ FileName [abcSop.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Implementation of a simple SOP representation of nodes.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcSop.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+
+/*
+ The SOPs in this package are represented using char * strings.
+ For example, the SOP of the node:
+
+ .names c d0 d1 MUX
+ 01- 1
+ 1-1 1
+
+ is the string: "01- 1/n1-1 1/n" where '/n' is a single char.
+*/
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Registers the cube string with the network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Abc_SopRegister( Extra_MmFlex_t * pMan, char * pName )
+{
+ char * pRegName;
+ if ( pName == NULL ) return NULL;
+ pRegName = Extra_MmFlexEntryFetch( pMan, strlen(pName) + 1 );
+ strcpy( pRegName, pName );
+ return pRegName;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads the number of cubes in the cover.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_SopGetCubeNum( char * pSop )
+{
+ char * pCur;
+ int nCubes = 0;
+ if ( pSop == NULL )
+ return 0;
+ for ( pCur = pSop; *pCur; pCur++ )
+ nCubes += (*pCur == '\n');
+ return nCubes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads the number of SOP literals in the cover.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_SopGetLitNum( char * pSop )
+{
+ char * pCur;
+ int nLits = 0;
+ if ( pSop == NULL )
+ return 0;
+ for ( pCur = pSop; *pCur; pCur++ )
+ {
+ nLits -= (*pCur == '\n');
+ nLits += (*pCur == '0' || *pCur == '1');
+ }
+ return nLits;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads the number of variables in the cover.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_SopGetVarNum( char * pSop )
+{
+ char * pCur;
+ for ( pCur = pSop; *pCur != '\n'; pCur++ );
+ return pCur - pSop - 2;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads the phase of the cover.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_SopGetPhase( char * pSop )
+{
+ int nVars = Abc_SopGetVarNum( pSop );
+ if ( pSop[nVars+1] == '0' )
+ return 0;
+ if ( pSop[nVars+1] == '1' )
+ return 1;
+ assert( 0 );
+ return -1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks if the cover is constant 0.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_SopIsConst0( char * pSop )
+{
+ return pSop[0] == ' ' && pSop[1] == '0';
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks if the cover is constant 1.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_SopIsConst1( char * pSop )
+{
+ return pSop[0] == ' ' && pSop[1] == '1';
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks if the cover is constant 1.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_SopIsBuf( char * pSop )
+{
+ if ( pSop[4] != 0 )
+ return 0;
+ if ( (pSop[0] == '1' && pSop[2] == '1') || (pSop[0] == '0' && pSop[2] == '0') )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks if the cover is constant 1.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_SopIsInv( char * pSop )
+{
+ if ( pSop[4] != 0 )
+ return 0;
+ if ( (pSop[0] == '0' && pSop[2] == '1') || (pSop[0] == '1' && pSop[2] == '0') )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks if the cover is AND with possibly complemented inputs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_SopIsAndType( char * pSop )
+{
+ char * pCur;
+ if ( Abc_SopGetCubeNum(pSop) != 1 )
+ return 0;
+ for ( pCur = pSop; *pCur != ' '; pCur++ )
+ if ( *pCur == '-' )
+ return 0;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks if the cover is OR with possibly complemented inputs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_SopIsOrType( char * pSop )
+{
+ char * pCube, * pCur;
+ int nVars, nLits, c;
+ nVars = Abc_SopGetVarNum( pSop );
+ for ( c = 0; ; c++ )
+ {
+ // get the cube
+ pCube = pSop + c * (nVars + 3);
+ if ( *pCube == 0 )
+ break;
+ // count the number of literals in the cube
+ nLits = 0;
+ for ( pCur = pCube; *pCur != ' '; pCur++ )
+ nLits += ( *pCur != '-' );
+ if ( nLits != 1 )
+ return 0;
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the i-th literal of the cover.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_SopGetIthCareLit( char * pSop, int i )
+{
+ char * pCube;
+ int nVars, c;
+ nVars = Abc_SopGetVarNum( pSop );
+ for ( c = 0; ; c++ )
+ {
+ // get the cube
+ pCube = pSop + c * (nVars + 3);
+ if ( *pCube == 0 )
+ break;
+ // get the literal
+ if ( pCube[i] != '-' )
+ return pCube[i] - '0';
+ }
+ return -1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_SopComplement( char * pSop )
+{
+ char * pCur;
+ for ( pCur = pSop; *pCur; pCur++ )
+ if ( *pCur == '\n' )
+ {
+ if ( *(pCur - 1) == '0' )
+ *(pCur - 1) = '1';
+ else if ( *(pCur - 1) == '1' )
+ *(pCur - 1) = '0';
+ else
+ assert( 0 );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_SopCheck( char * pSop, int nFanins )
+{
+ char * pCubes, * pCubesOld;
+ int fFound0 = 0, fFound1 = 0;
+
+ // check the logic function of the node
+ for ( pCubes = pSop; *pCubes; pCubes++ )
+ {
+ // get the end of the next cube
+ for ( pCubesOld = pCubes; *pCubes != ' '; pCubes++ );
+ // compare the distance
+ if ( pCubes - pCubesOld != nFanins )
+ {
+ fprintf( stdout, "Abc_SopCheck: SOP has a mismatch between its cover and its fanins.\n" );
+ return 0;
+ }
+ // check the output values for this cube
+ pCubes++;
+ if ( *pCubes == '0' )
+ fFound0 = 1;
+ else if ( *pCubes == '1' )
+ fFound1 = 1;
+ else
+ {
+ fprintf( stdout, "Abc_SopCheck: SOP has a strange character in the output part of its cube.\n" );
+ return 0;
+ }
+ // check the last symbol (new line)
+ pCubes++;
+ if ( *pCubes != '\n' )
+ {
+ fprintf( stdout, "Abc_SopCheck: SOP has a cube without new line in the end.\n" );
+ return 0;
+ }
+ }
+ if ( fFound0 && fFound1 )
+ {
+ fprintf( stdout, "Abc_SopCheck: SOP has cubes in both phases.\n" );
+ return 0;
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Writes the CNF of the SOP into file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_SopWriteCnf( FILE * pFile, char * pClauses, Vec_Int_t * vVars )
+{
+ char * pChar;
+ int i;
+ // check the logic function of the node
+ for ( pChar = pClauses; *pChar; pChar++ )
+ {
+ // write the clause
+ for ( i = 0; i < vVars->nSize; i++, pChar++ )
+ if ( *pChar == '0' )
+ fprintf( pFile, "%d ", vVars->pArray[i] );
+ else if ( *pChar == '1' )
+ fprintf( pFile, "%d ", -vVars->pArray[i] );
+ fprintf( pFile, "0\n" );
+ // check that the remainig part is fine
+ assert( *pChar == ' ' );
+ pChar++;
+ assert( *pChar == '1' );
+ pChar++;
+ assert( *pChar == '\n' );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Adds the clauses of for the CNF to the solver.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_SopAddCnfToSolver( solver * pSat, char * pClauses, Vec_Int_t * vVars, Vec_Int_t * vTemp )
+{
+ char * pChar;
+ int i, RetValue;
+ // check the logic function of the node
+ for ( pChar = pClauses; *pChar; pChar++ )
+ {
+ // add the clause
+ vTemp->nSize = 0;
+ for ( i = 0; i < vVars->nSize; i++, pChar++ )
+ if ( *pChar == '0' )
+ Vec_IntPush( vTemp, toLit(vVars->pArray[i]) );
+ else if ( *pChar == '1' )
+ Vec_IntPush( vTemp, neg(toLit(vVars->pArray[i])) );
+ // add the clause to the solver
+ RetValue = solver_addclause( pSat, vTemp->pArray, vTemp->pArray + vTemp->nSize );
+ assert( RetValue != 1 );
+ // check that the remainig part is fine
+ assert( *pChar == ' ' );
+ pChar++;
+ assert( *pChar == '1' );
+ pChar++;
+ assert( *pChar == '\n' );
+ }
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcStrash.c b/src/base/abc/abcStrash.c
new file mode 100644
index 00000000..eb5b3df7
--- /dev/null
+++ b/src/base/abc/abcStrash.c
@@ -0,0 +1,541 @@
+/**CFile****************************************************************
+
+ FileName [aigStrash.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Strashing of the current network.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: aigStrash.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+#include "extra.h"
+#include "ft.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// static functions
+static void Abc_NtkStrashPerform( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkAig );
+static Abc_Obj_t * Abc_NodeStrash( Abc_Aig_t * pMan, Abc_Obj_t * pNode );
+static Abc_Obj_t * Abc_NodeStrashSop( Abc_Aig_t * pMan, Abc_Obj_t * pNode, char * pSop );
+static Abc_Obj_t * Abc_NodeStrashFactor( Abc_Aig_t * pMan, Abc_Obj_t * pNode, char * pSop );
+
+static void Abc_NtkBalancePerform( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkAig, bool fDuplicate );
+static Abc_Obj_t * Abc_NodeBalance_rec( Abc_Ntk_t * pNtkNew, Abc_Obj_t * pNode, bool fDuplicate );
+static Vec_Ptr_t * Abc_NodeBalanceCone( Abc_Obj_t * pNode, int fDuplicate );
+
+extern char * Mio_GateReadSop( void * pGate );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Creates the strashed AIG network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Abc_NtkStrash( Abc_Ntk_t * pNtk )
+{
+ int fCheck = 1;
+ Abc_Ntk_t * pNtkAig;
+ assert( !Abc_NtkIsNetlist(pNtk) );
+ if ( Abc_NtkIsLogicBdd(pNtk) )
+ {
+// printf( "Converting node functions from BDD to SOP.\n" );
+ Abc_NtkBddToSop(pNtk);
+ }
+ // print warning about choice nodes
+ if ( Abc_NtkCountChoiceNodes( pNtk ) )
+ printf( "Warning: The choice nodes in the initial AIG are removed by strashing.\n" );
+ // perform strashing
+ pNtkAig = Abc_NtkStartFrom( pNtk, ABC_NTK_AIG );
+ Abc_NtkStrashPerform( pNtk, pNtkAig );
+ Abc_NtkFinalize( pNtk, pNtkAig );
+ // print warning about self-feed latches
+ if ( Abc_NtkCountSelfFeedLatches(pNtkAig) )
+ printf( "The network has %d self-feeding latches.\n", Abc_NtkCountSelfFeedLatches(pNtkAig) );
+ // duplicate EXDC
+ if ( pNtk->pExdc )
+ pNtkAig->pExdc = Abc_NtkStrash( pNtk->pExdc );
+ // make sure everything is okay
+ if ( fCheck && !Abc_NtkCheck( pNtkAig ) )
+ {
+ printf( "Abc_NtkStrash: The network check has failed.\n" );
+ Abc_NtkDelete( pNtkAig );
+ return NULL;
+ }
+ return pNtkAig;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prepares the network for strashing.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkStrashPerform( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew )
+{
+ ProgressBar * pProgress;
+ Abc_Aig_t * pMan = pNtkNew->pManFunc;
+ Vec_Ptr_t * vNodes;
+ Abc_Obj_t * pNode, * pNodeNew, * pObj;
+ int i;
+
+ // perform strashing
+ vNodes = Abc_NtkDfs( pNtk );
+ pProgress = Extra_ProgressBarStart( stdout, vNodes->nSize );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ {
+ Extra_ProgressBarUpdate( pProgress, i, NULL );
+ // get the node
+ pNode = vNodes->pArray[i];
+ assert( Abc_ObjIsNode(pNode) );
+ // strash the node
+ pNodeNew = Abc_NodeStrash( pMan, pNode );
+ // get the old object
+ if ( Abc_NtkIsNetlist(pNtk) )
+ pObj = Abc_ObjFanout0( pNode ); // the fanout net
+ else
+ pObj = vNodes->pArray[i]; // the node itself
+ // make sure the node is not yet strashed
+ assert( pObj->pCopy == NULL );
+ // mark the old object with the new AIG node
+ pObj->pCopy = pNodeNew;
+ }
+ Vec_PtrFree( vNodes );
+ Extra_ProgressBarStop( pProgress );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Strashes one logic node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NodeStrash( Abc_Aig_t * pMan, Abc_Obj_t * pNode )
+{
+ int fUseFactor = 1;
+ char * pSop;
+
+ assert( Abc_ObjIsNode(pNode) );
+
+ // consider the case when the graph is an AIG
+ if ( Abc_NtkIsAig(pNode->pNtk) )
+ {
+// Abc_Obj_t * pChild0, * pChild1;
+// pChild0 = Abc_ObjFanin0(pNode);
+// pChild1 = Abc_ObjFanin1(pNode);
+ if ( Abc_NodeIsConst(pNode) )
+ return Abc_AigConst1(pMan);
+ return Abc_AigAnd( pMan,
+ Abc_ObjNotCond( Abc_ObjFanin0(pNode)->pCopy, Abc_ObjFaninC0(pNode) ),
+ Abc_ObjNotCond( Abc_ObjFanin1(pNode)->pCopy, Abc_ObjFaninC1(pNode) ) );
+ }
+
+ // get the SOP of the node
+ if ( Abc_NtkIsLogicMap(pNode->pNtk) )
+ pSop = Mio_GateReadSop(pNode->pData);
+ else
+ pSop = pNode->pData;
+
+ // consider the cconstant node
+ if ( Abc_NodeIsConst(pNode) )
+ {
+ // check if the SOP is constant
+ if ( Abc_SopIsConst1(pSop) )
+ return Abc_AigConst1(pMan);
+ return Abc_ObjNot( Abc_AigConst1(pMan) );
+ }
+
+ // decide when to use factoring
+ if ( fUseFactor && Abc_ObjFaninNum(pNode) > 2 && Abc_SopGetCubeNum(pSop) > 1 )
+ return Abc_NodeStrashFactor( pMan, pNode, pSop );
+ return Abc_NodeStrashSop( pMan, pNode, pSop );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Strashes one logic node using its SOP.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NodeStrashSop( Abc_Aig_t * pMan, Abc_Obj_t * pNode, char * pSop )
+{
+ Abc_Obj_t * pFanin, * pAnd, * pSum;
+ Abc_Obj_t * pConst1 = Abc_AigConst1(pMan);
+ char * pCube;
+ int i, nFanins;
+
+ // get the number of node's fanins
+ nFanins = Abc_ObjFaninNum( pNode );
+ assert( nFanins == Abc_SopGetVarNum(pSop) );
+ // go through the cubes of the node's SOP
+ pSum = Abc_ObjNot(pConst1);
+ Abc_SopForEachCube( pSop, nFanins, pCube )
+ {
+ // create the AND of literals
+ pAnd = pConst1;
+ Abc_ObjForEachFanin( pNode, pFanin, i ) // pFanin can be a net
+ {
+ if ( pCube[i] == '1' )
+ pAnd = Abc_AigAnd( pMan, pAnd, pFanin->pCopy );
+ else if ( pCube[i] == '0' )
+ pAnd = Abc_AigAnd( pMan, pAnd, Abc_ObjNot(pFanin->pCopy) );
+ }
+ // add to the sum of cubes
+ pSum = Abc_AigOr( pMan, pSum, pAnd );
+ }
+ // decide whether to complement the result
+ pCube = pSop;
+ if ( pCube[nFanins + 1] == '0' )
+ pSum = Abc_ObjNot(pSum);
+ return pSum;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Strashes one logic node using its SOP.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NodeStrashFactor( Abc_Aig_t * pMan, Abc_Obj_t * pRoot, char * pSop )
+{
+ Vec_Int_t * vForm;
+ Vec_Ptr_t * vAnds;
+ Abc_Obj_t * pAnd, * pAnd0, * pAnd1, * pFanin;
+ Ft_Node_t * pFtNode;
+ int i, nVars;
+
+ // derive the factored form
+ vForm = Ft_Factor( pSop );
+
+ // sanity checks
+ nVars = Ft_FactorGetNumVars( vForm );
+ assert( nVars >= 0 );
+ assert( vForm->nSize > nVars );
+ assert( nVars == Abc_ObjFaninNum(pRoot) );
+
+ // check for constant Andtion
+ pFtNode = Ft_NodeRead( vForm, 0 );
+ if ( pFtNode->fConst )
+ {
+ Vec_IntFree( vForm );
+ return Abc_ObjNotCond( Abc_AigConst1(pMan), pFtNode->fCompl );
+ }
+
+ // start the array of elementary variables
+ vAnds = Vec_PtrAlloc( 20 );
+ Abc_ObjForEachFanin( pRoot, pFanin, i )
+ Vec_PtrPush( vAnds, pFanin->pCopy );
+
+ // compute the Andtions of other nodes
+ for ( i = nVars; i < vForm->nSize; i++ )
+ {
+ pFtNode = Ft_NodeRead( vForm, i );
+ pAnd0 = Abc_ObjNotCond( vAnds->pArray[pFtNode->iFanin0], pFtNode->fCompl0 );
+ pAnd1 = Abc_ObjNotCond( vAnds->pArray[pFtNode->iFanin1], pFtNode->fCompl1 );
+ pAnd = Abc_AigAnd( pMan, pAnd0, pAnd1 );
+ Vec_PtrPush( vAnds, pAnd );
+ }
+ assert( vForm->nSize = vAnds->nSize );
+ Vec_PtrFree( vAnds );
+
+ // complement the result if necessary
+ pFtNode = Ft_NodeReadLast( vForm );
+ pAnd = Abc_ObjNotCond( pAnd, pFtNode->fCompl );
+ Vec_IntFree( vForm );
+ return pAnd;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Appends the second network to the first.]
+
+ Description [Modifies the first network by adding the logic of the second.
+ Does not add the COs of the second. Does not change the second network.
+ Returns 0 if the appending failed, 1 otherise.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkAppend( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2 )
+{
+ int fCheck = 1;
+ Abc_Obj_t * pObj;
+ int i;
+ // the first network should be an AIG
+ assert( Abc_NtkIsAig(pNtk1) );
+ assert( Abc_NtkIsLogic(pNtk2) || Abc_NtkIsAig(pNtk2) );
+ if ( Abc_NtkIsLogicBdd(pNtk2) )
+ {
+// printf( "Converting node functions from BDD to SOP.\n" );
+ Abc_NtkBddToSop(pNtk2);
+ }
+ // check that the networks have the same PIs
+ // reorder PIs of pNtk2 according to pNtk1
+ if ( !Abc_NtkCompareSignals( pNtk1, pNtk2, 1 ) )
+ return 0;
+ // perform strashing
+ Abc_NtkCleanCopy( pNtk2 );
+ Abc_NtkForEachCi( pNtk2, pObj, i )
+ pObj->pCopy = Abc_NtkCi(pNtk1, i);
+ // add pNtk2 to pNtk1 while strashing
+ Abc_NtkStrashPerform( pNtk2, pNtk1 );
+ // make sure that everything is okay
+ if ( fCheck && !Abc_NtkCheck( pNtk1 ) )
+ {
+ printf( "Abc_NtkAppend: The network check has failed.\n" );
+ return 0;
+ }
+ return 1;
+}
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Balances the AIG network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Abc_NtkBalance( Abc_Ntk_t * pNtk, bool fDuplicate )
+{
+ int fCheck = 1;
+ Abc_Ntk_t * pNtkAig;
+ assert( Abc_NtkIsAig(pNtk) );
+ // perform balancing
+ pNtkAig = Abc_NtkStartFrom( pNtk, ABC_NTK_AIG );
+ Abc_NtkBalancePerform( pNtk, pNtkAig, fDuplicate );
+ Abc_NtkFinalize( pNtk, pNtkAig );
+ // make sure everything is okay
+ if ( fCheck && !Abc_NtkCheck( pNtkAig ) )
+ {
+ printf( "Abc_NtkBalance: The network check has failed.\n" );
+ Abc_NtkDelete( pNtkAig );
+ return NULL;
+ }
+ return pNtkAig;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Balances the AIG network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkBalancePerform( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkAig, bool fDuplicate )
+{
+ int fCheck = 1;
+ ProgressBar * pProgress;
+ Abc_Obj_t * pNode, * pDriver;
+ int i;
+
+ // copy the constant node
+ Abc_AigConst1(pNtk->pManFunc)->pCopy = Abc_AigConst1(pNtkAig->pManFunc);
+ // set the level of PIs of AIG according to the arrival times of the old network
+ Abc_NtkSetNodeLevelsArrival( pNtk );
+ // perform balancing of POs
+ pProgress = Extra_ProgressBarStart( stdout, Abc_NtkCoNum(pNtk) );
+ Abc_NtkForEachCo( pNtk, pNode, i )
+ {
+ Extra_ProgressBarUpdate( pProgress, i, NULL );
+ // strash the driver node
+ pDriver = Abc_ObjFanin0(pNode);
+ Abc_NodeBalance_rec( pNtkAig, pDriver, fDuplicate );
+ }
+ Extra_ProgressBarStop( pProgress );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Rebalances the multi-input node rooted at pNodeOld.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NodeBalance_rec( Abc_Ntk_t * pNtkNew, Abc_Obj_t * pNodeOld, bool fDuplicate )
+{
+ Abc_Aig_t * pMan = pNtkNew->pManFunc;
+ Abc_Obj_t * pNodeNew, * pNode1, * pNode2;
+ Vec_Ptr_t * vSuper;
+ int i;
+ assert( !Abc_ObjIsComplement(pNodeOld) );
+ // return if the result if known
+ if ( pNodeOld->pCopy )
+ return pNodeOld->pCopy;
+ assert( Abc_ObjIsNode(pNodeOld) );
+ // get the implication supergate
+ vSuper = Abc_NodeBalanceCone( pNodeOld, fDuplicate );
+ if ( vSuper->nSize == 0 )
+ { // it means that the supergate contains two nodes in the opposite polarity
+ Vec_PtrFree( vSuper );
+ pNodeOld->pCopy = Abc_ObjNot(Abc_AigConst1(pMan));
+ return pNodeOld->pCopy;
+ }
+ // for each old node, derive the new well-balanced node
+ for ( i = 0; i < vSuper->nSize; i++ )
+ {
+ pNodeNew = Abc_NodeBalance_rec( pNtkNew, Abc_ObjRegular(vSuper->pArray[i]), fDuplicate );
+ vSuper->pArray[i] = Abc_ObjNotCond( pNodeNew, Abc_ObjIsComplement(vSuper->pArray[i]) );
+ }
+ // sort the new nodes by level in the decreasing order
+ Vec_PtrSort( vSuper, Abc_NodeCompareLevelsDecrease );
+ // balance the nodes
+ assert( vSuper->nSize > 1 );
+ while ( vSuper->nSize > 1 )
+ {
+ pNode1 = Vec_PtrPop(vSuper);
+ pNode2 = Vec_PtrPop(vSuper);
+ Abc_VecObjPushUniqueOrderByLevel( vSuper, Abc_AigAnd(pMan, pNode1, pNode2) );
+ }
+ // make sure the balanced node is not assigned
+ assert( pNodeOld->pCopy == NULL );
+ // mark the old node with the new node
+ pNodeOld->pCopy = vSuper->pArray[0];
+ Vec_PtrFree( vSuper );
+ return pNodeOld->pCopy;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Collects the nodes in the cone delimited by fMarkA==1.]
+
+ Description [Returns -1 if the AND-cone has the same node in both polarities.
+ Returns 1 if the AND-cone has the same node in the same polarity. Returns 0
+ if the AND-cone has no repeated nodes.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NodeBalanceCone_rec( Abc_Obj_t * pNode, Vec_Ptr_t * vSuper, bool fFirst, bool fDuplicate )
+{
+ Abc_Obj_t * p0, * p1;
+ int RetValue1, RetValue2, i;
+ // check if the node is visited
+ if ( Abc_ObjRegular(pNode)->fMarkB )
+ {
+ // check if the node occurs in the same polarity
+ for ( i = 0; i < vSuper->nSize; i++ )
+ if ( vSuper->pArray[i] == pNode )
+ return 1;
+ // check if the node is present in the opposite polarity
+ for ( i = 0; i < vSuper->nSize; i++ )
+ if ( vSuper->pArray[i] == Abc_ObjNot(pNode) )
+ return -1;
+ assert( 0 );
+ return 0;
+ }
+ // if the new node is complemented or a PI, another gate begins
+ if ( !fFirst && (Abc_ObjIsComplement(pNode) || !Abc_ObjIsNode(pNode) || !fDuplicate && (Abc_ObjFanoutNum(pNode) > 1)) )
+ {
+ Vec_PtrPush( vSuper, pNode );
+ Abc_ObjRegular(pNode)->fMarkB = 1;
+ return 0;
+ }
+ assert( !Abc_ObjIsComplement(pNode) );
+ assert( Abc_ObjIsNode(pNode) );
+ // get the children
+ p0 = Abc_ObjNotCond( Abc_ObjFanin0(pNode), Abc_ObjFaninC0(pNode) );
+ p1 = Abc_ObjNotCond( Abc_ObjFanin1(pNode), Abc_ObjFaninC1(pNode) );
+ // go through the branches
+ RetValue1 = Abc_NodeBalanceCone_rec( p0, vSuper, 0, fDuplicate );
+ RetValue2 = Abc_NodeBalanceCone_rec( p1, vSuper, 0, fDuplicate );
+ if ( RetValue1 == -1 || RetValue2 == -1 )
+ return -1;
+ // return 1 if at least one branch has a duplicate
+ return RetValue1 || RetValue2;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collects the nodes in the cone delimited by fMarkA==1.]
+
+ Description [Returns -1 if the AND-cone has the same node in both polarities.
+ Returns 1 if the AND-cone has the same node in the same polarity. Returns 0
+ if the AND-cone has no repeated nodes.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Vec_Ptr_t * Abc_NodeBalanceCone( Abc_Obj_t * pNode, int fDuplicate )
+{
+ Vec_Ptr_t * vNodes;
+ int RetValue, i;
+ assert( !Abc_ObjIsComplement(pNode) );
+ vNodes = Vec_PtrAlloc( 4 );
+ RetValue = Abc_NodeBalanceCone_rec( pNode, vNodes, 1, fDuplicate );
+ assert( vNodes->nSize > 0 );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ Abc_ObjRegular((Abc_Obj_t *)vNodes->pArray[i])->fMarkB = 0;
+ if ( RetValue == -1 )
+ vNodes->nSize = 0;
+ return vNodes;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcSweep.c b/src/base/abc/abcSweep.c
new file mode 100644
index 00000000..6890fc57
--- /dev/null
+++ b/src/base/abc/abcSweep.c
@@ -0,0 +1,434 @@
+/**CFile****************************************************************
+
+ FileName [abcDsd.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Technology dependent sweep.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcDsd.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+#include "fraig.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static stmm_table * Abc_NtkFraigEquiv( Fraig_Man_t * p, Abc_Ntk_t * pNtk, int fUseInv, bool fVerbose );
+static void Abc_NtkFraigTransform( Abc_Ntk_t * pNtk, stmm_table * tEquiv, int fUseInv, bool fVerbose );
+static void Abc_NtkFraigMergeClassMapped( Abc_Ntk_t * pNtk, Abc_Obj_t * pChain, int fVerbose, int fUseInv );
+static void Abc_NtkFraigMergeClass( Abc_Ntk_t * pNtk, Abc_Obj_t * pChain, int fVerbose, int fUseInv );
+static int Abc_NodeDroppingCost( Abc_Obj_t * pNode );
+
+extern Fraig_Man_t * Abc_NtkToFraig( Abc_Ntk_t * pNtk, Fraig_Params_t * pParams, int fAllNodes );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Sweping functionally equivalence nodes.]
+
+ Description [Removes gates with equivalent functionality. Works for
+ both technology-independent and mapped networks. If the flag is set,
+ allows adding inverters at the gate outputs.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkFraigSweep( Abc_Ntk_t * pNtk, int fUseInv, int fVerbose )
+{
+ int fCheck = 1;
+ Fraig_Params_t Params;
+ Abc_Ntk_t * pNtkAig;
+ Fraig_Man_t * pMan;
+ stmm_table * tEquiv;
+
+ assert( !Abc_NtkIsAig(pNtk) );
+
+ // derive the AIG
+ pNtkAig = Abc_NtkStrash( pNtk );
+ // perform fraiging of the AIG
+ Fraig_ParamsSetDefault( &Params );
+ pMan = Abc_NtkToFraig( pNtkAig, &Params, 0 );
+ // collect the classes of equivalent nets
+ tEquiv = Abc_NtkFraigEquiv( pMan, pNtk, fUseInv, fVerbose );
+
+ // transform the network into the equivalent one
+ Abc_NtkFraigTransform( pNtk, tEquiv, fUseInv, fVerbose );
+ stmm_free_table( tEquiv );
+
+ // free the manager
+ Fraig_ManFree( pMan );
+ Abc_NtkDelete( pNtkAig );
+
+ // cleanup the dangling nodes
+ Abc_NtkCleanup( pNtk, fVerbose );
+ // check
+ if ( fCheck && !Abc_NtkCheck( pNtk ) )
+ {
+ printf( "Abc_NtkFraigSweep: The network check has failed.\n" );
+ return 0;
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collects equivalence classses of node in the network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+stmm_table * Abc_NtkFraigEquiv( Fraig_Man_t * p, Abc_Ntk_t * pNtk, int fUseInv, bool fVerbose )
+{
+ Abc_Obj_t * pList, * pNode, * pNodeAig;
+ Fraig_Node_t * gNode;
+ Abc_Obj_t ** ppSlot;
+ stmm_table * tStrash2Net;
+ stmm_table * tResult;
+ stmm_generator * gen;
+ int c, Counter;
+
+ // create mapping of strashed nodes into the corresponding network nodes
+ tStrash2Net = stmm_init_table(stmm_ptrcmp,stmm_ptrhash);
+ Abc_NtkForEachNode( pNtk, pNode, c )
+ {
+ // get the strashed node
+ pNodeAig = pNode->pCopy;
+ // skip the dangling nodes
+ if ( pNodeAig == NULL )
+ continue;
+ // skip the constant input nodes
+ if ( Abc_ObjFaninNum(pNode) == 0 )
+ continue;
+ // skip the nodes that fanout into POs
+ if ( Abc_NtkIsLogicMap(pNtk) && Abc_NodeHasUniqueNamedFanout(pNode) )
+ continue;
+ // get the FRAIG node
+ gNode = Fraig_NotCond( Abc_ObjRegular(pNodeAig)->pCopy, Abc_ObjIsComplement(pNodeAig) );
+ if ( !stmm_find_or_add( tStrash2Net, (char *)Fraig_Regular(gNode), (char ***)&ppSlot ) )
+ *ppSlot = NULL;
+ // add the node to the list
+ pNode->pNext = *ppSlot;
+ *ppSlot = pNode;
+ // mark the node if it is complemented
+ pNode->fPhase = Fraig_IsComplement(gNode);
+ }
+
+ // print the classes
+ c = 0;
+ Counter = 0;
+ tResult = stmm_init_table(stmm_ptrcmp,stmm_ptrhash);
+ stmm_foreach_item( tStrash2Net, gen, (char **)&gNode, (char **)&pList )
+ {
+ // skip the trival classes
+ if ( pList == NULL || pList->pNext == NULL )
+ continue;
+ // add the non-trival class
+ stmm_insert( tResult, (char *)pList, NULL );
+ // count nodes in the non-trival classes
+ for ( pNode = pList; pNode; pNode = pNode->pNext )
+ Counter++;
+/*
+ if ( fVerbose )
+ {
+ printf( "Class %2d : {", c );
+ for ( pNode = pList; pNode; pNode = pNode->pNext )
+ {
+ pNode->pCopy = NULL;
+ printf( " %s", Abc_ObjName(pNode) );
+ if ( pNode->fPhase ) printf( "(*)" );
+ }
+ printf( " }\n" );
+ c++;
+ }
+*/
+ }
+ if ( fVerbose )
+ {
+ printf( "Sweeping stats for network \"%s\":\n", pNtk->pName );
+ printf( "Internal nodes = %d. Different functions (up to compl) = %d.\n", Abc_NtkNodeNum(pNtk), stmm_count(tStrash2Net) );
+ printf( "Non-trivial classes = %d. Nodes in non-trivial classes = %d.\n", stmm_count(tResult), Counter );
+ }
+ stmm_free_table( tStrash2Net );
+ return tResult;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Transforms the network using the equivalence relation on nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkFraigTransform( Abc_Ntk_t * pNtk, stmm_table * tEquiv, int fUseInv, bool fVerbose )
+{
+ stmm_generator * gen;
+ Abc_Obj_t * pList;
+ if ( stmm_count(tEquiv) == 0 )
+ return;
+ // assign levels to the nodes of the network
+ Abc_NtkGetLevelNum( pNtk );
+ // merge nodes in the classes
+ if ( Abc_NtkIsLogicMap( pNtk ) )
+ {
+ Abc_NtkDelayTrace( pNtk );
+ stmm_foreach_item( tEquiv, gen, (char **)&pList, NULL )
+ Abc_NtkFraigMergeClassMapped( pNtk, pList, fUseInv, fVerbose );
+ }
+ else
+ {
+ stmm_foreach_item( tEquiv, gen, (char **)&pList, NULL )
+ Abc_NtkFraigMergeClass( pNtk, pList, fUseInv, fVerbose );
+ }
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Transforms the list of one-phase equivalent nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkFraigMergeClassMapped( Abc_Ntk_t * pNtk, Abc_Obj_t * pChain, int fUseInv, int fVerbose )
+{
+ Abc_Obj_t * pListDir, * pListInv;
+ Abc_Obj_t * pNodeMin, * pNode, * pNext;
+ float Arrival1, Arrival2;
+
+ assert( pChain );
+ assert( pChain->pNext );
+
+ // divide the nodes into two parts:
+ // those that need the invertor and those that don't need
+ pListDir = pListInv = NULL;
+ for ( pNode = pChain, pNext = pChain->pNext;
+ pNode;
+ pNode = pNext, pNext = pNode? pNode->pNext : NULL )
+ {
+ // check to which class the node belongs
+ if ( pNode->fPhase == 1 )
+ {
+ pNode->pNext = pListDir;
+ pListDir = pNode;
+ }
+ else
+ {
+ pNode->pNext = pListInv;
+ pListInv = pNode;
+ }
+ }
+
+ // find the node with the smallest number of logic levels
+ pNodeMin = pListDir;
+ for ( pNode = pListDir; pNode; pNode = pNode->pNext )
+ {
+ Arrival1 = Abc_NodeReadArrival(pNodeMin)->Worst;
+ Arrival2 = Abc_NodeReadArrival(pNode )->Worst;
+ assert( Abc_ObjIsPi(pNodeMin) || Arrival1 > 0 );
+ assert( Abc_ObjIsPi(pNode) || Arrival2 > 0 );
+ if ( Arrival1 > Arrival2 ||
+ Arrival1 == Arrival2 && pNodeMin->Level > pNode->Level ||
+ Arrival1 == Arrival2 && pNodeMin->Level == pNode->Level &&
+ Abc_NodeDroppingCost(pNodeMin) < Abc_NodeDroppingCost(pNode) )
+ pNodeMin = pNode;
+ }
+
+ // move the fanouts of the direct nodes
+ for ( pNode = pListDir; pNode; pNode = pNode->pNext )
+ if ( pNode != pNodeMin )
+ Abc_ObjTransferFanout( pNode, pNodeMin );
+
+ // find the node with the smallest number of logic levels
+ pNodeMin = pListInv;
+ for ( pNode = pListInv; pNode; pNode = pNode->pNext )
+ {
+ Arrival1 = Abc_NodeReadArrival(pNodeMin)->Worst;
+ Arrival2 = Abc_NodeReadArrival(pNode )->Worst;
+ assert( Abc_ObjIsPi(pNodeMin) || Arrival1 > 0 );
+ assert( Abc_ObjIsPi(pNode) || Arrival2 > 0 );
+ if ( Arrival1 > Arrival2 ||
+ Arrival1 == Arrival2 && pNodeMin->Level > pNode->Level ||
+ Arrival1 == Arrival2 && pNodeMin->Level == pNode->Level &&
+ Abc_NodeDroppingCost(pNodeMin) < Abc_NodeDroppingCost(pNode) )
+ pNodeMin = pNode;
+ }
+
+ // move the fanouts of the direct nodes
+ for ( pNode = pListInv; pNode; pNode = pNode->pNext )
+ if ( pNode != pNodeMin )
+ Abc_ObjTransferFanout( pNode, pNodeMin );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Process one equivalence class of nodes.]
+
+ Description [This function does not remove the nodes. It only switches
+ around the connections.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkFraigMergeClass( Abc_Ntk_t * pNtk, Abc_Obj_t * pChain, int fUseInv, int fVerbose )
+{
+ Abc_Obj_t * pListDir, * pListInv;
+ Abc_Obj_t * pNodeMin, * pNodeMinInv;
+ Abc_Obj_t * pNode, * pNext;
+
+ assert( pChain );
+ assert( pChain->pNext );
+
+ // find the node with the smallest number of logic levels
+ pNodeMin = pChain;
+ for ( pNode = pChain->pNext; pNode; pNode = pNode->pNext )
+ if ( pNodeMin->Level > pNode->Level ||
+ ( pNodeMin->Level == pNode->Level &&
+ Abc_NodeDroppingCost(pNodeMin) < Abc_NodeDroppingCost(pNode) ) )
+ pNodeMin = pNode;
+
+ // divide the nodes into two parts:
+ // those that need the invertor and those that don't need
+ pListDir = pListInv = NULL;
+ for ( pNode = pChain, pNext = pChain->pNext;
+ pNode;
+ pNode = pNext, pNext = pNode? pNode->pNext : NULL )
+ {
+ if ( pNode == pNodeMin )
+ continue;
+ // check to which class the node belongs
+ if ( pNodeMin->fPhase == pNode->fPhase )
+ {
+ pNode->pNext = pListDir;
+ pListDir = pNode;
+ }
+ else
+ {
+ pNode->pNext = pListInv;
+ pListInv = pNode;
+ }
+ }
+
+ // move the fanouts of the direct nodes
+ for ( pNode = pListDir; pNode; pNode = pNode->pNext )
+ Abc_ObjTransferFanout( pNode, pNodeMin );
+
+ // skip if there are no inverted nodes
+ if ( pListInv == NULL )
+ return;
+
+ // add the invertor
+ pNodeMinInv = Abc_NodeCreateInv( pNtk, pNodeMin );
+
+ // move the fanouts of the inverted nodes
+ for ( pNode = pListInv; pNode; pNode = pNode->pNext )
+ Abc_ObjTransferFanout( pNode, pNodeMinInv );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Returns the number of literals saved if this node becomes useless.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NodeDroppingCost( Abc_Obj_t * pNode )
+{
+ return 1;
+}
+
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Removes dangling nodes.]
+
+ Description [Returns the number of nodes removed.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkCleanup( Abc_Ntk_t * pNtk, int fVerbose )
+{
+ int fCheck = 1;
+ Vec_Ptr_t * vNodes;
+ Abc_Obj_t * pNode;
+ int i, Counter;
+ // mark the nodes reachable from the POs
+ vNodes = Abc_NtkDfs( pNtk );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ {
+ pNode = vNodes->pArray[i];
+ pNode->fMarkA = 1;
+ }
+ Vec_PtrFree( vNodes );
+ // if it is an AIG, also mark the constant 1 node
+ if ( Abc_NtkIsAig(pNtk) )
+ Abc_AigConst1(pNtk->pManFunc)->fMarkA = 1;
+ // remove the non-marked nodes
+ Counter = 0;
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ if ( pNode->fMarkA == 0 )
+ {
+ Abc_NtkDeleteObj( pNode );
+ Counter++;
+ }
+ // unmark the remaining nodes
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ pNode->fMarkA = 0;
+ if ( fVerbose )
+ printf( "Cleanup removed %d dangling nodes.\n", Counter );
+ // check
+ if ( fCheck && !Abc_NtkCheck( pNtk ) )
+ {
+ printf( "Abc_NtkCleanup: The network check has failed.\n" );
+ return -1;
+ }
+ return Counter;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcTiming.c b/src/base/abc/abcTiming.c
new file mode 100644
index 00000000..f017d93c
--- /dev/null
+++ b/src/base/abc/abcTiming.c
@@ -0,0 +1,631 @@
+/**CFile****************************************************************
+
+ FileName [abcTiming.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Computation of timing info for mapped circuits.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcTiming.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+#include "main.h"
+#include "mio.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+struct Abc_ManTime_t_
+{
+ Abc_Time_t tArrDef;
+ Abc_Time_t tReqDef;
+ Vec_Ptr_t * vArrs;
+ Vec_Ptr_t * vReqs;
+};
+
+// static functions
+static Abc_ManTime_t * Abc_ManTimeStart();
+static void Abc_ManTimeExpand( Abc_ManTime_t * p, int nSize, int fProgressive );
+static void Abc_NtkTimePrepare( Abc_Ntk_t * pNtk );
+
+static void Abc_NodeDelayTraceArrival( Abc_Obj_t * pNode );
+
+// accessing the arrival and required times of a node
+static inline Abc_Time_t * Abc_NodeArrival( Abc_Obj_t * pNode ) { return pNode->pNtk->pManTime->vArrs->pArray[pNode->Id]; }
+static inline Abc_Time_t * Abc_NodeRequired( Abc_Obj_t * pNode ) { return pNode->pNtk->pManTime->vReqs->pArray[pNode->Id]; }
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Reads the arrival time of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Time_t * Abc_NodeReadArrival( Abc_Obj_t * pNode )
+{
+ assert( pNode->pNtk->pManTime );
+ return Abc_NodeArrival(pNode);
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads the arrival time of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Time_t * Abc_NodeReadRequired( Abc_Obj_t * pNode )
+{
+ assert( pNode->pNtk->pManTime );
+ return Abc_NodeRequired(pNode);
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads the arrival time of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Time_t * Abc_NtkReadDefaultArrival( Abc_Ntk_t * pNtk )
+{
+ assert( pNtk->pManTime );
+ return &pNtk->pManTime->tArrDef;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads the arrival time of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Time_t * Abc_NtkReadDefaultRequired( Abc_Ntk_t * pNtk )
+{
+ assert( pNtk->pManTime );
+ return &pNtk->pManTime->tReqDef;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the default arrival time for the network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkTimeSetDefaultArrival( Abc_Ntk_t * pNtk, float Rise, float Fall )
+{
+ if ( Rise == 0.0 && Fall == 0.0 )
+ return;
+ if ( pNtk->pManTime == NULL )
+ pNtk->pManTime = Abc_ManTimeStart();
+ pNtk->pManTime->tArrDef.Rise = Rise;
+ pNtk->pManTime->tArrDef.Fall = Fall;
+ pNtk->pManTime->tArrDef.Worst = ABC_MAX( Rise, Fall );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the default arrival time for the network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkTimeSetDefaultRequired( Abc_Ntk_t * pNtk, float Rise, float Fall )
+{
+ if ( Rise == 0.0 && Fall == 0.0 )
+ return;
+ if ( pNtk->pManTime == NULL )
+ pNtk->pManTime = Abc_ManTimeStart();
+ pNtk->pManTime->tReqDef.Rise = Rise;
+ pNtk->pManTime->tReqDef.Rise = Fall;
+ pNtk->pManTime->tReqDef.Worst = ABC_MAX( Rise, Fall );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the arrival time for an object.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkTimeSetArrival( Abc_Ntk_t * pNtk, int ObjId, float Rise, float Fall )
+{
+ Vec_Ptr_t * vTimes;
+ Abc_Time_t * pTime;
+ if ( pNtk->pManTime == NULL )
+ pNtk->pManTime = Abc_ManTimeStart();
+ if ( pNtk->pManTime->tArrDef.Rise == Rise && pNtk->pManTime->tArrDef.Fall == Fall )
+ return;
+ Abc_ManTimeExpand( pNtk->pManTime, ObjId + 1, 1 );
+ // set the arrival time
+ vTimes = pNtk->pManTime->vArrs;
+ pTime = vTimes->pArray[ObjId];
+ pTime->Rise = Rise;
+ pTime->Fall = Rise;
+ pTime->Worst = ABC_MAX( Rise, Fall );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the arrival time for an object.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkTimeSetRequired( Abc_Ntk_t * pNtk, int ObjId, float Rise, float Fall )
+{
+ Vec_Ptr_t * vTimes;
+ Abc_Time_t * pTime;
+ if ( pNtk->pManTime == NULL )
+ pNtk->pManTime = Abc_ManTimeStart();
+ if ( pNtk->pManTime->tReqDef.Rise == Rise && pNtk->pManTime->tReqDef.Fall == Fall )
+ return;
+ Abc_ManTimeExpand( pNtk->pManTime, ObjId + 1, 1 );
+ // set the required time
+ vTimes = pNtk->pManTime->vReqs;
+ pTime = vTimes->pArray[ObjId];
+ pTime->Rise = Rise;
+ pTime->Fall = Rise;
+ pTime->Worst = ABC_MAX( Rise, Fall );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Finalizes the timing manager after setting arr/req times.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkTimeFinalize( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pObj;
+ Abc_Time_t ** ppTimes, * pTime;
+ int i;
+ if ( pNtk->pManTime == NULL )
+ return;
+ Abc_ManTimeExpand( pNtk->pManTime, Abc_NtkObjNum(pNtk), 0 );
+ // set the default timing
+ ppTimes = (Abc_Time_t **)pNtk->pManTime->vArrs->pArray;
+ Abc_NtkForEachPi( pNtk, pObj, i )
+ {
+ pTime = ppTimes[pObj->Id];
+ if ( pTime->Worst != -ABC_INFINITY )
+ continue;
+ *pTime = pNtk->pManTime->tArrDef;
+ }
+ // set the default timing
+ ppTimes = (Abc_Time_t **)pNtk->pManTime->vReqs->pArray;
+ Abc_NtkForEachPo( pNtk, pObj, i )
+ {
+ pTime = ppTimes[pObj->Id];
+ if ( pTime->Worst != -ABC_INFINITY )
+ continue;
+ *pTime = pNtk->pManTime->tArrDef;
+ }
+ // set the 0 arrival times for latches and constant nodes
+ ppTimes = (Abc_Time_t **)pNtk->pManTime->vArrs->pArray;
+ Abc_NtkForEachLatch( pNtk, pObj, i )
+ {
+ pTime = ppTimes[pObj->Id];
+ pTime->Fall = pTime->Rise = pTime->Worst = 0.0;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prepares the timing manager for delay trace.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkTimePrepare( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pObj;
+ Abc_Time_t ** ppTimes, * pTime;
+ int i;
+ // if there is no timing manager, allocate and initialize
+ if ( pNtk->pManTime == NULL )
+ {
+ pNtk->pManTime = Abc_ManTimeStart();
+ Abc_NtkTimeFinalize( pNtk );
+ return;
+ }
+ // if timing manager is given, clean arrivals except for PIs
+ // and required except for POs
+ ppTimes = (Abc_Time_t **)pNtk->pManTime->vArrs->pArray;
+ Abc_NtkForEachNode( pNtk, pObj, i )
+ {
+ pTime = ppTimes[pObj->Id];
+ pTime->Fall = pTime->Rise = pTime->Worst = -ABC_INFINITY;
+ }
+ Abc_NtkForEachPo( pNtk, pObj, i )
+ {
+ pTime = ppTimes[pObj->Id];
+ pTime->Fall = pTime->Rise = pTime->Worst = -ABC_INFINITY;
+ }
+}
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_ManTime_t * Abc_ManTimeStart()
+{
+ Abc_ManTime_t * p;
+ p = ALLOC( Abc_ManTime_t, 1 );
+ memset( p, 0, sizeof(Abc_ManTime_t) );
+ p->vArrs = Vec_PtrAlloc( 0 );
+ p->vReqs = Vec_PtrAlloc( 0 );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_ManTimeStop( Abc_ManTime_t * p )
+{
+ if ( p->vArrs->nSize > 0 )
+ {
+ free( p->vArrs->pArray[0] );
+ Vec_PtrFree( p->vArrs );
+ }
+ if ( p->vReqs->nSize > 0 )
+ {
+ free( p->vReqs->pArray[0] );
+ Vec_PtrFree( p->vReqs );
+ }
+ free( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Duplicates the timing manager with the PI/PO timing info.]
+
+ Description [The PIs/POs of the new network should be allocated.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_ManTimeDup( Abc_Ntk_t * pNtkOld, Abc_Ntk_t * pNtkNew )
+{
+ Abc_Obj_t * pObj;
+ Abc_Time_t ** ppTimesOld, ** ppTimesNew;
+ int i;
+ if ( pNtkOld->pManTime == NULL )
+ return;
+ assert( Abc_NtkPiNum(pNtkOld) == Abc_NtkPiNum(pNtkNew) );
+ assert( Abc_NtkPoNum(pNtkOld) == Abc_NtkPoNum(pNtkNew) );
+ assert( Abc_NtkLatchNum(pNtkOld) == Abc_NtkLatchNum(pNtkNew) );
+ // create the new timing manager
+ pNtkNew->pManTime = Abc_ManTimeStart();
+ Abc_ManTimeExpand( pNtkNew->pManTime, Abc_NtkObjNum(pNtkNew), 0 );
+ // set the default timing
+ pNtkNew->pManTime->tArrDef = pNtkOld->pManTime->tArrDef;
+ pNtkNew->pManTime->tReqDef = pNtkOld->pManTime->tReqDef;
+ // set the PI timing
+ ppTimesOld = (Abc_Time_t **)pNtkOld->pManTime->vArrs->pArray;
+ ppTimesNew = (Abc_Time_t **)pNtkNew->pManTime->vArrs->pArray;
+ Abc_NtkForEachPi( pNtkOld, pObj, i )
+ *ppTimesNew[ Abc_NtkPi(pNtkNew,i)->Id ] = *ppTimesOld[ pObj->Id ];
+ // set the PO timing
+ ppTimesOld = (Abc_Time_t **)pNtkOld->pManTime->vReqs->pArray;
+ ppTimesNew = (Abc_Time_t **)pNtkNew->pManTime->vReqs->pArray;
+ Abc_NtkForEachPo( pNtkOld, pObj, i )
+ *ppTimesNew[ Abc_NtkPo(pNtkNew,i)->Id ] = *ppTimesOld[ pObj->Id ];
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_ManTimeExpand( Abc_ManTime_t * p, int nSize, int fProgressive )
+{
+ Vec_Ptr_t * vTimes;
+ Abc_Time_t * ppTimes, * ppTimesOld, * pTime;
+ int nSizeOld, nSizeNew, i;
+
+ nSizeOld = p->vArrs->nSize;
+ if ( nSizeOld >= nSize )
+ return;
+ nSizeNew = fProgressive? 2 * nSize : nSize;
+ if ( nSizeNew < 100 )
+ nSizeNew = 100;
+
+ vTimes = p->vArrs;
+ Vec_PtrGrow( vTimes, nSizeNew );
+ vTimes->nSize = nSizeNew;
+ ppTimesOld = ( nSizeOld == 0 )? NULL : vTimes->pArray[0];
+ ppTimes = REALLOC( Abc_Time_t, ppTimesOld, nSizeNew );
+ for ( i = 0; i < nSizeNew; i++ )
+ vTimes->pArray[i] = ppTimes + i;
+ for ( i = nSizeOld; i < nSizeNew; i++ )
+ {
+ pTime = vTimes->pArray[i];
+ pTime->Rise = -ABC_INFINITY;
+ pTime->Fall = -ABC_INFINITY;
+ pTime->Worst = -ABC_INFINITY;
+ }
+
+ vTimes = p->vReqs;
+ Vec_PtrGrow( vTimes, nSizeNew );
+ vTimes->nSize = nSizeNew;
+ ppTimesOld = ( nSizeOld == 0 )? NULL : vTimes->pArray[0];
+ ppTimes = REALLOC( Abc_Time_t, ppTimesOld, nSizeNew );
+ for ( i = 0; i < nSizeNew; i++ )
+ vTimes->pArray[i] = ppTimes + i;
+ for ( i = nSizeOld; i < nSizeNew; i++ )
+ {
+ pTime = vTimes->pArray[i];
+ pTime->Rise = -ABC_INFINITY;
+ pTime->Fall = -ABC_INFINITY;
+ pTime->Worst = -ABC_INFINITY;
+ }
+}
+
+
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Sets the CI node levels according to the arrival info.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkSetNodeLevelsArrival( Abc_Ntk_t * pNtkOld )
+{
+ Abc_Obj_t * pNodeOld, * pNodeNew;
+ float tAndDelay;
+ int i;
+ if ( pNtkOld->pManTime == NULL )
+ return;
+ if ( Mio_LibraryReadNand2(Abc_FrameReadLibGen(Abc_FrameGetGlobalFrame())) == NULL )
+ return;
+ tAndDelay = Mio_LibraryReadDelayNand2Max(Abc_FrameReadLibGen(Abc_FrameGetGlobalFrame()));
+ Abc_NtkForEachPi( pNtkOld, pNodeOld, i )
+ {
+ pNodeNew = pNodeOld->pCopy;
+ pNodeNew->Level = (int)(Abc_NodeArrival(pNodeOld)->Worst / tAndDelay);
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the CI node levels according to the arrival info.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Time_t * Abc_NtkGetCiArrivalTimes( Abc_Ntk_t * pNtk )
+{
+ Abc_Time_t * p;
+ Abc_Obj_t * pNode;
+ int i;
+ p = ALLOC( Abc_Time_t, Abc_NtkCiNum(pNtk) );
+ memset( p, 0, sizeof(Abc_Time_t) * Abc_NtkCiNum(pNtk) );
+ if ( pNtk->pManTime == NULL )
+ return p;
+ // set the PI arrival times
+ Abc_NtkForEachPi( pNtk, pNode, i )
+ p[i] = *Abc_NodeArrival(pNode);
+ return p;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Sets the CI node levels according to the arrival info.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float * Abc_NtkGetCiArrivalFloats( Abc_Ntk_t * pNtk )
+{
+ float * p;
+ Abc_Obj_t * pNode;
+ int i;
+ p = ALLOC( float, Abc_NtkCiNum(pNtk) );
+ memset( p, 0, sizeof(float) * Abc_NtkCiNum(pNtk) );
+ if ( pNtk->pManTime == NULL )
+ return p;
+ // set the PI arrival times
+ Abc_NtkForEachPi( pNtk, pNode, i )
+ p[i] = Abc_NodeArrival(pNode)->Worst;
+ return p;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Abc_NtkDelayTrace( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode, * pDriver;
+ Vec_Ptr_t * vNodes;
+ Abc_Time_t * pTime;
+ float tArrivalMax;
+ int i;
+
+ assert( Abc_NtkIsLogicMap(pNtk) );
+
+ Abc_NtkTimePrepare( pNtk );
+ vNodes = Abc_NtkDfs( pNtk );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ Abc_NodeDelayTraceArrival( vNodes->pArray[i] );
+ Vec_PtrFree( vNodes );
+
+ // get the latest arrival times
+ tArrivalMax = -ABC_INFINITY;
+ Abc_NtkForEachCo( pNtk, pNode, i )
+ {
+ pDriver = Abc_ObjFanin0(pNode);
+ pTime = Abc_NodeArrival(pDriver);
+ if ( tArrivalMax < pTime->Worst )
+ tArrivalMax = pTime->Worst;
+ }
+ return tArrivalMax;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NodeDelayTraceArrival( Abc_Obj_t * pNode )
+{
+ Abc_Obj_t * pFanin;
+ Abc_Time_t * pTimeIn, * pTimeOut;
+ float tDelayBlockRise, tDelayBlockFall;
+ Mio_PinPhase_t PinPhase;
+ Mio_Pin_t * pPin;
+ int i;
+
+ // start the arrival time of the node
+ pTimeOut = Abc_NodeArrival(pNode);
+ pTimeOut->Rise = pTimeOut->Fall = 0;
+ // go through the pins of the gate
+ pPin = Mio_GateReadPins(pNode->pData);
+ Abc_ObjForEachFanin( pNode, pFanin, i )
+ {
+ pTimeIn = Abc_NodeArrival(pFanin);
+ assert( pTimeIn->Worst != -ABC_INFINITY );
+ // get the interesting parameters of this pin
+ PinPhase = Mio_PinReadPhase(pPin);
+ tDelayBlockRise = (float)Mio_PinReadDelayBlockRise( pPin );
+ tDelayBlockFall = (float)Mio_PinReadDelayBlockFall( pPin );
+ // compute the arrival times of the positive phase
+ if ( PinPhase != MIO_PHASE_INV ) // NONINV phase is present
+ {
+ if ( pTimeOut->Rise < pTimeIn->Rise + tDelayBlockRise )
+ pTimeOut->Rise = pTimeIn->Rise + tDelayBlockRise;
+ if ( pTimeOut->Fall < pTimeIn->Fall + tDelayBlockFall )
+ pTimeOut->Fall = pTimeIn->Fall + tDelayBlockFall;
+ }
+ if ( PinPhase != MIO_PHASE_NONINV ) // INV phase is present
+ {
+ if ( pTimeOut->Rise < pTimeIn->Fall + tDelayBlockRise )
+ pTimeOut->Rise = pTimeIn->Fall + tDelayBlockRise;
+ if ( pTimeOut->Fall < pTimeIn->Rise + tDelayBlockFall )
+ pTimeOut->Fall = pTimeIn->Rise + tDelayBlockFall;
+ }
+ pPin = Mio_PinReadNext(pPin);
+ }
+ pTimeOut->Worst = ABC_MAX( pTimeOut->Rise, pTimeOut->Fall );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcUtil.c b/src/base/abc/abcUtil.c
new file mode 100644
index 00000000..1c826f95
--- /dev/null
+++ b/src/base/abc/abcUtil.c
@@ -0,0 +1,780 @@
+/**CFile****************************************************************
+
+ FileName [abcUtils.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Various utilities.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcUtils.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+#include "main.h"
+#include "mio.h"
+#include "ft.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Abc_NodeRefDeref( Abc_Obj_t * pNode, bool fFanouts, bool fReference );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Increments the current traversal ID of the network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkIncrementTravId( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pObj;
+ int i;
+ if ( pNtk->nTravIds == (1<<12)-1 )
+ {
+ pNtk->nTravIds = 0;
+ Abc_NtkForEachObj( pNtk, pObj, i )
+ pObj->TravId = 0;
+ }
+ pNtk->nTravIds++;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads the number of cubes of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkGetCubeNum( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ int i, nCubes = 0;
+ assert( Abc_NtkIsNetlist(pNtk) || Abc_NtkIsLogicSop(pNtk) );
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ assert( pNode->pData );
+ nCubes += Abc_SopGetCubeNum( pNode->pData );
+ }
+ return nCubes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads the number of cubes of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkGetLitNum( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ int i, nLits = 0;
+ assert( Abc_NtkIsNetlist(pNtk) || Abc_NtkIsLogicSop(pNtk) );
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ assert( pNode->pData );
+ nLits += Abc_SopGetLitNum( pNode->pData );
+ }
+ return nLits;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Counts the number of literals in the factored forms.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkGetLitFactNum( Abc_Ntk_t * pNtk )
+{
+ Vec_Int_t * vFactor;
+ Abc_Obj_t * pNode;
+ int nNodes, i;
+ assert( Abc_NtkIsNetlist(pNtk) || Abc_NtkIsLogicSop(pNtk) );
+ nNodes = 0;
+// Ft_FactorStartMan();
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ vFactor = Ft_Factor( pNode->pData );
+ nNodes += Ft_FactorGetNumNodes(vFactor);
+ Vec_IntFree( vFactor );
+ }
+// Ft_FactorStopMan();
+ return nNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads the number of BDD nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkGetBddNodeNum( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ int i, nNodes = 0;
+ assert( Abc_NtkIsLogicBdd(pNtk) );
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ assert( pNode->pData );
+ nNodes += pNode->pData? Cudd_DagSize( pNode->pData ) : 0;
+ }
+ return nNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads the number of BDD nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkGetClauseNum( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ DdNode * bCover, * zCover, * bFunc;
+ DdManager * dd = pNtk->pManFunc;
+ int i, nClauses = 0;
+ assert( Abc_NtkIsLogicBdd(pNtk) );
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ assert( pNode->pData );
+ bFunc = pNode->pData;
+
+ bCover = Cudd_zddIsop( dd, bFunc, bFunc, &zCover );
+ Cudd_Ref( bCover );
+ Cudd_Ref( zCover );
+ nClauses += Abc_CountZddCubes( dd, zCover );
+ Cudd_RecursiveDeref( dd, bCover );
+ Cudd_RecursiveDerefZdd( dd, zCover );
+
+ bCover = Cudd_zddIsop( dd, Cudd_Not(bFunc), Cudd_Not(bFunc), &zCover );
+ Cudd_Ref( bCover );
+ Cudd_Ref( zCover );
+ nClauses += Abc_CountZddCubes( dd, zCover );
+ Cudd_RecursiveDeref( dd, bCover );
+ Cudd_RecursiveDerefZdd( dd, zCover );
+ }
+ return nClauses;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the area of the mapped circuit.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+double Abc_NtkGetMappedArea( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ double TotalArea;
+ int i;
+ assert( Abc_NtkIsLogicMap(pNtk) );
+ TotalArea = 0.0;
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ assert( pNode->pData );
+ TotalArea += Mio_GateReadArea( pNode->pData );
+ }
+ return TotalArea;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads the maximum number of fanins.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkGetFaninMax( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ int i, nFaninsMax = 0;
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ if ( nFaninsMax < Abc_ObjFaninNum(pNode) )
+ nFaninsMax = Abc_ObjFaninNum(pNode);
+ }
+ return nFaninsMax;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Cleans the copy field of all objects.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkCleanCopy( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pObj;
+ int i;
+ i = 0;
+ // set the data filed to NULL
+ Abc_NtkForEachObj( pNtk, pObj, i )
+ pObj->pCopy = NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks if the internal node has a unique CO.]
+
+ Description [Checks if the internal node can borrow a name from a CO
+ fanout. This is possible if there is only one CO with non-complemented
+ fanin edge pointing to this node.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NodeHasUniqueNamedFanout( Abc_Obj_t * pNode )
+{
+ Abc_Obj_t * pFanout, * pFanoutNamed;
+ int i, Counter;
+ if ( !Abc_ObjIsNode(pNode) )
+ return NULL;
+ Counter = 0;
+ Abc_ObjForEachFanout( pNode, pFanout, i )
+ {
+ if ( (Abc_ObjIsPo(pFanout) || Abc_ObjIsLatch(pFanout)) && !Abc_ObjFaninC0(pFanout) )
+ {
+ assert( Abc_ObjFaninNum(pFanout) == 1 );
+ assert( Abc_ObjFanin0(pFanout) == pNode );
+ pFanoutNamed = pFanout;
+ Counter++;
+ }
+ }
+ if ( Counter == 1 )
+ return pFanoutNamed;
+ return NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if the PO names can be written directly.]
+
+ Description [This is true if the POs of the logic network are
+ not complemented and not duplicated. This condition has to be
+ specifically enforced after mapping, to make sure additional
+ INVs/BUFs are not written into the file.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NtkLogicHasSimplePos( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ int i;
+ assert( !Abc_NtkIsNetlist(pNtk) );
+ // check if there are complemented or idential POs
+ Abc_NtkIncrementTravId( pNtk );
+ Abc_NtkForEachPo( pNtk, pNode, i )
+ {
+ pNode = Abc_ObjChild0(pNode);
+ if ( Abc_ObjIsComplement(pNode) )
+ return 0;
+ if ( Abc_NodeIsTravIdCurrent(pNode) )
+ return 0;
+ Abc_NodeSetTravIdCurrent(pNode);
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Transforms the network to have simple POs.]
+
+ Description [The POs are simple if the POs of the logic network are
+ not complemented and not duplicated. This condition has to be
+ specifically enforced after FPGA mapping, to make sure additional
+ INVs/BUFs are not written into the file.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkLogicMakeSimplePos( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode, * pDriver, * pDriverDup, * pFanin;
+ int i, k, nDupGates = 0;
+ assert( Abc_NtkIsLogic(pNtk) );
+ // if a PO driver has more than one fanout, duplicate it
+ Abc_NtkForEachCo( pNtk, pNode, i )
+ {
+ pDriver = Abc_ObjFanin0(pNode);
+ if ( Abc_ObjFanoutNum(pDriver) == 1 )
+ continue;
+ // do not modify CI
+ if ( !Abc_ObjIsNode(pDriver) )
+ continue;
+ pDriverDup = Abc_NtkDupObj( pNtk, pDriver );
+ Abc_ObjForEachFanin( pDriver, pFanin, k )
+ Abc_ObjAddFanin( pDriverDup, pFanin );
+ // update the fanin of the PO node
+ Abc_ObjPatchFanin( pNode, pDriver, pDriverDup );
+ assert( Abc_ObjFanoutNum(pDriverDup) == 1 );
+ nDupGates++;
+ }
+ // if a PO comes complemented change the drivers function
+ Abc_NtkForEachCo( pNtk, pNode, i )
+ {
+ pDriver = Abc_ObjFanin0(pNode);
+ if ( !Abc_ObjFaninC0(pNode) )
+ continue;
+ // do not modify PIs and LOs
+ if ( !Abc_ObjIsNode(pDriver) )
+ continue;
+ // the driver is complemented - change polarity
+ if ( Abc_NtkIsLogicSop(pNtk) )
+ Abc_SopComplement( pDriver->pData );
+ else if ( Abc_NtkIsLogicBdd(pNtk) )
+ pDriver->pData = Cudd_Not( pDriver->pData );
+ else
+ assert( 0 );
+ // update the complemented edge of the fanin
+ Abc_ObjXorFaninC(pNode, 0);
+ assert( !Abc_ObjFaninC0(pNode) );
+ }
+ return nDupGates;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Inserts a new node in the order by levels.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_VecObjPushUniqueOrderByLevel( Vec_Ptr_t * p, Abc_Obj_t * pNode )
+{
+ Abc_Obj_t * pNode1, * pNode2;
+ int i;
+ if ( Vec_PtrPushUnique(p, pNode) )
+ return;
+ // find the p of the node
+ for ( i = p->nSize-1; i > 0; i-- )
+ {
+ pNode1 = p->pArray[i ];
+ pNode2 = p->pArray[i-1];
+ if ( Abc_ObjRegular(pNode1)->Level <= Abc_ObjRegular(pNode2)->Level )
+ break;
+ p->pArray[i ] = pNode2;
+ p->pArray[i-1] = pNode1;
+ }
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if the node is the root of MUX or EXOR/NEXOR.]
+
+ Description [The node can be complemented.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_NodeIsMuxType( Abc_Obj_t * pNode )
+{
+ Abc_Obj_t * pNode0, * pNode1;
+ // check that the node is regular
+ assert( !Abc_ObjIsComplement(pNode) );
+ // if the node is not AND, this is not MUX
+ if ( !Abc_NodeIsAnd(pNode) )
+ return 0;
+ // if the children are not complemented, this is not MUX
+ if ( !Abc_ObjFaninC0(pNode) || !Abc_ObjFaninC1(pNode) )
+ return 0;
+ // get children
+ pNode0 = Abc_ObjFanin0(pNode);
+ pNode1 = Abc_ObjFanin1(pNode);
+ // if the children are not ANDs, this is not MUX
+ if ( Abc_ObjFaninNum(pNode0) != 2 || Abc_ObjFaninNum(pNode1) != 2 )
+ return 0;
+ // otherwise the node is MUX iff it has a pair of equal grandchildren
+ return (Abc_ObjFaninId0(pNode0) == Abc_ObjFaninId0(pNode1) && (Abc_ObjFaninC0(pNode0) ^ Abc_ObjFaninC0(pNode1))) ||
+ (Abc_ObjFaninId0(pNode0) == Abc_ObjFaninId1(pNode1) && (Abc_ObjFaninC0(pNode0) ^ Abc_ObjFaninC1(pNode1))) ||
+ (Abc_ObjFaninId1(pNode0) == Abc_ObjFaninId0(pNode1) && (Abc_ObjFaninC1(pNode0) ^ Abc_ObjFaninC0(pNode1))) ||
+ (Abc_ObjFaninId1(pNode0) == Abc_ObjFaninId1(pNode1) && (Abc_ObjFaninC1(pNode0) ^ Abc_ObjFaninC1(pNode1)));
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recognizes what nodes are control and data inputs of a MUX.]
+
+ Description [If the node is a MUX, returns the control variable C.
+ Assigns nodes T and E to be the then and else variables of the MUX.
+ Node C is never complemented. Nodes T and E can be complemented.
+ This function also recognizes EXOR/NEXOR gates as MUXes.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Obj_t * Abc_NodeRecognizeMux( Abc_Obj_t * pNode, Abc_Obj_t ** ppNodeT, Abc_Obj_t ** ppNodeE )
+{
+ Abc_Obj_t * pNode0, * pNode1;
+ assert( !Abc_ObjIsComplement(pNode) );
+ assert( Abc_NodeIsMuxType(pNode) );
+ // get children
+ pNode0 = Abc_ObjFanin0(pNode);
+ pNode1 = Abc_ObjFanin1(pNode);
+ // find the control variable
+// if ( pNode1->p1 == Fraig_Not(pNode2->p1) )
+ if ( Abc_ObjFaninId0(pNode0) == Abc_ObjFaninId0(pNode1) && (Abc_ObjFaninC0(pNode0) ^ Abc_ObjFaninC0(pNode1)) )
+ {
+// if ( Fraig_IsComplement(pNode1->p1) )
+ if ( Abc_ObjFaninC0(pNode0) )
+ { // pNode2->p1 is positive phase of C
+ *ppNodeT = Abc_ObjNot(Abc_ObjChild1(pNode1));//pNode2->p2);
+ *ppNodeE = Abc_ObjNot(Abc_ObjChild1(pNode0));//pNode1->p2);
+ return Abc_ObjChild0(pNode1);//pNode2->p1;
+ }
+ else
+ { // pNode1->p1 is positive phase of C
+ *ppNodeT = Abc_ObjNot(Abc_ObjChild1(pNode0));//pNode1->p2);
+ *ppNodeE = Abc_ObjNot(Abc_ObjChild1(pNode1));//pNode2->p2);
+ return Abc_ObjChild0(pNode0);//pNode1->p1;
+ }
+ }
+// else if ( pNode1->p1 == Fraig_Not(pNode2->p2) )
+ else if ( Abc_ObjFaninId0(pNode0) == Abc_ObjFaninId1(pNode1) && (Abc_ObjFaninC0(pNode0) ^ Abc_ObjFaninC1(pNode1)) )
+ {
+// if ( Fraig_IsComplement(pNode1->p1) )
+ if ( Abc_ObjFaninC0(pNode0) )
+ { // pNode2->p2 is positive phase of C
+ *ppNodeT = Abc_ObjNot(Abc_ObjChild0(pNode1));//pNode2->p1);
+ *ppNodeE = Abc_ObjNot(Abc_ObjChild1(pNode0));//pNode1->p2);
+ return Abc_ObjChild1(pNode1);//pNode2->p2;
+ }
+ else
+ { // pNode1->p1 is positive phase of C
+ *ppNodeT = Abc_ObjNot(Abc_ObjChild1(pNode0));//pNode1->p2);
+ *ppNodeE = Abc_ObjNot(Abc_ObjChild0(pNode1));//pNode2->p1);
+ return Abc_ObjChild0(pNode0);//pNode1->p1;
+ }
+ }
+// else if ( pNode1->p2 == Fraig_Not(pNode2->p1) )
+ else if ( Abc_ObjFaninId1(pNode0) == Abc_ObjFaninId0(pNode1) && (Abc_ObjFaninC1(pNode0) ^ Abc_ObjFaninC0(pNode1)) )
+ {
+// if ( Fraig_IsComplement(pNode1->p2) )
+ if ( Abc_ObjFaninC1(pNode0) )
+ { // pNode2->p1 is positive phase of C
+ *ppNodeT = Abc_ObjNot(Abc_ObjChild1(pNode1));//pNode2->p2);
+ *ppNodeE = Abc_ObjNot(Abc_ObjChild0(pNode0));//pNode1->p1);
+ return Abc_ObjChild0(pNode1);//pNode2->p1;
+ }
+ else
+ { // pNode1->p2 is positive phase of C
+ *ppNodeT = Abc_ObjNot(Abc_ObjChild0(pNode0));//pNode1->p1);
+ *ppNodeE = Abc_ObjNot(Abc_ObjChild1(pNode1));//pNode2->p2);
+ return Abc_ObjChild1(pNode0);//pNode1->p2;
+ }
+ }
+// else if ( pNode1->p2 == Fraig_Not(pNode2->p2) )
+ else if ( Abc_ObjFaninId1(pNode0) == Abc_ObjFaninId1(pNode1) && (Abc_ObjFaninC1(pNode0) ^ Abc_ObjFaninC1(pNode1)) )
+ {
+// if ( Fraig_IsComplement(pNode1->p2) )
+ if ( Abc_ObjFaninC1(pNode0) )
+ { // pNode2->p2 is positive phase of C
+ *ppNodeT = Abc_ObjNot(Abc_ObjChild0(pNode1));//pNode2->p1);
+ *ppNodeE = Abc_ObjNot(Abc_ObjChild0(pNode0));//pNode1->p1);
+ return Abc_ObjChild1(pNode1);//pNode2->p2;
+ }
+ else
+ { // pNode1->p2 is positive phase of C
+ *ppNodeT = Abc_ObjNot(Abc_ObjChild0(pNode0));//pNode1->p1);
+ *ppNodeE = Abc_ObjNot(Abc_ObjChild0(pNode1));//pNode2->p1);
+ return Abc_ObjChild1(pNode0);//pNode1->p2;
+ }
+ }
+ assert( 0 ); // this is not MUX
+ return NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if it is an AIG with choice nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkCountChoiceNodes( Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ int i, Counter;
+ if ( !Abc_NtkIsAig(pNtk) )
+ return 0;
+ Counter = 0;
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ Counter += Abc_NodeIsChoice( pNode );
+ return Counter;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prepares two network for a two-argument command similar to "verify".]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NtkPrepareCommand( FILE * pErr, Abc_Ntk_t * pNtk, char ** argv, int argc,
+ Abc_Ntk_t ** ppNtk1, Abc_Ntk_t ** ppNtk2, int * pfDelete1, int * pfDelete2 )
+{
+ int fCheck = 1;
+ FILE * pFile;
+ Abc_Ntk_t * pNtk1, * pNtk2;
+ int util_optind = 0;
+
+ *pfDelete1 = 0;
+ *pfDelete2 = 0;
+ if ( argc == util_optind )
+ { // use the spec
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty current network.\n" );
+ return 0;
+ }
+ if ( pNtk->pSpec == NULL )
+ {
+ fprintf( pErr, "The external spec is not given.\n" );
+ return 0;
+ }
+ pFile = fopen( pNtk->pSpec, "r" );
+ if ( pFile == NULL )
+ {
+ fprintf( pErr, "Cannot open the external spec file \"%s\".\n", pNtk->pSpec );
+ return 0;
+ }
+ else
+ fclose( pFile );
+
+ pNtk1 = pNtk;
+ pNtk2 = Io_Read( pNtk->pSpec, fCheck );
+ if ( pNtk2 == NULL )
+ return 0;
+ *pfDelete2 = 1;
+ }
+ else if ( argc == util_optind + 1 )
+ {
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty current network.\n" );
+ return 0;
+ }
+ pNtk1 = pNtk;
+ pNtk2 = Io_Read( argv[util_optind], fCheck );
+ if ( pNtk2 == NULL )
+ return 0;
+ *pfDelete2 = 1;
+ }
+ else if ( argc == util_optind + 2 )
+ {
+ pNtk1 = Io_Read( argv[util_optind], fCheck );
+ if ( pNtk1 == NULL )
+ return 0;
+ pNtk2 = Io_Read( argv[util_optind+1], fCheck );
+ if ( pNtk2 == NULL )
+ {
+ Abc_NtkDelete( pNtk1 );
+ return 0;
+ }
+ *pfDelete1 = 1;
+ *pfDelete2 = 1;
+ }
+ else
+ {
+ fprintf( pErr, "Wrong number of arguments.\n" );
+ return 0;
+ }
+ *ppNtk1 = pNtk1;
+ *ppNtk2 = pNtk2;
+ return 1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if it is an AIG with choice nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NodeCollectFanins( Abc_Obj_t * pNode, Vec_Ptr_t * vNodes )
+{
+ Abc_Obj_t * pFanin;
+ int i;
+ vNodes->nSize = 0;
+ Abc_ObjForEachFanin( pNode, pFanin, i )
+ Vec_PtrPush( vNodes, pFanin );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if it is an AIG with choice nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NodeCollectFanouts( Abc_Obj_t * pNode, Vec_Ptr_t * vNodes )
+{
+ Abc_Obj_t * pFanout;
+ int i;
+ vNodes->nSize = 0;
+ Abc_ObjForEachFanout( pNode, pFanout, i )
+ Vec_PtrPush( vNodes, pFanout );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Procedure used for sorting the nodes in decreasing order of levels.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NodeCompareLevelsIncrease( Abc_Obj_t ** pp1, Abc_Obj_t ** pp2 )
+{
+ int Diff = Abc_ObjRegular(*pp1)->Level - Abc_ObjRegular(*pp2)->Level;
+ if ( Diff < 0 )
+ return -1;
+ if ( Diff > 0 )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Procedure used for sorting the nodes in decreasing order of levels.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_NodeCompareLevelsDecrease( Abc_Obj_t ** pp1, Abc_Obj_t ** pp2 )
+{
+ int Diff = Abc_ObjRegular(*pp1)->Level - Abc_ObjRegular(*pp2)->Level;
+ if ( Diff > 0 )
+ return -1;
+ if ( Diff < 0 )
+ return 1;
+ return 0;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Collect all nodes by level.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Vec_Ptr_t * Abc_AigCollectAll( Abc_Ntk_t * pNtk )
+{
+ Vec_Ptr_t * vNodes;
+ Abc_Obj_t * pNode;
+ int i;
+ vNodes = Vec_PtrAlloc( 100 );
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ Vec_PtrPush( vNodes, pNode );
+ Vec_PtrSort( vNodes, Abc_NodeCompareLevelsIncrease );
+ return vNodes;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/abcVerify.c b/src/base/abc/abcVerify.c
new file mode 100644
index 00000000..d0b424a9
--- /dev/null
+++ b/src/base/abc/abcVerify.c
@@ -0,0 +1,310 @@
+/**CFile****************************************************************
+
+ FileName [abcVerify.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network and node package.]
+
+ Synopsis [Combinational and sequential verification for two networks.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: abcVerify.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+#include "fraig.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Verifies combinational equivalence by brute-force SAT.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkCecSat( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2 )
+{
+ Abc_Ntk_t * pMiter;
+ Abc_Ntk_t * pCnf;
+ int RetValue;
+
+ // get the miter of the two networks
+ pMiter = Abc_NtkMiter( pNtk1, pNtk2, 1 );
+ if ( pMiter == NULL )
+ {
+ printf( "Miter computation has failed.\n" );
+ return;
+ }
+ RetValue = Abc_NtkMiterIsConstant( pMiter );
+ if ( RetValue == 1 )
+ {
+ Abc_NtkDelete( pMiter );
+ printf( "Networks are not equivalent.\n" );
+ return;
+ }
+ if ( RetValue == 0 )
+ {
+ Abc_NtkDelete( pMiter );
+ printf( "Networks are equivalent after structural hashing.\n" );
+ return;
+ }
+
+ // convert the miter into a CNF
+ pCnf = Abc_NtkRenode( pMiter, 0, 100, 1, 0, 0 );
+ Abc_NtkDelete( pMiter );
+ if ( pCnf == NULL )
+ {
+ printf( "Renoding for CNF has failed.\n" );
+ return;
+ }
+
+ // solve the CNF using the SAT solver
+ if ( Abc_NtkMiterSat( pCnf, 0 ) )
+ printf( "Networks are not equivalent.\n" );
+ else
+ printf( "Networks are equivalent.\n" );
+ Abc_NtkDelete( pCnf );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Verifies sequential equivalence by fraiging followed by SAT.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkCecFraig( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2 )
+{
+ Fraig_Params_t Params;
+ Abc_Ntk_t * pMiter;
+ Abc_Ntk_t * pFraig;
+ int RetValue;
+
+ // get the miter of the two networks
+ pMiter = Abc_NtkMiter( pNtk1, pNtk2, 1 );
+ if ( pMiter == NULL )
+ {
+ printf( "Miter computation has failed.\n" );
+ return;
+ }
+ RetValue = Abc_NtkMiterIsConstant( pMiter );
+ if ( RetValue == 1 )
+ {
+ Abc_NtkDelete( pMiter );
+ printf( "Networks are not equivalent.\n" );
+ return;
+ }
+ if ( RetValue == 0 )
+ {
+ Abc_NtkDelete( pMiter );
+ printf( "Networks are equivalent after structural hashing.\n" );
+ return;
+ }
+
+ // convert the miter into a FRAIG
+ Fraig_ParamsSetDefault( &Params );
+ pFraig = Abc_NtkFraig( pMiter, &Params, 0 );
+ Abc_NtkDelete( pMiter );
+ if ( pFraig == NULL )
+ {
+ printf( "Fraiging has failed.\n" );
+ return;
+ }
+ RetValue = Abc_NtkMiterIsConstant( pFraig );
+ Abc_NtkDelete( pFraig );
+ if ( RetValue == 0 )
+ {
+ printf( "Networks are equivalent after fraiging.\n" );
+ return;
+ }
+ printf( "Networks are not equivalent.\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Verifies sequential equivalence by brute-force SAT.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkSecSat( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int nFrames )
+{
+ Abc_Ntk_t * pMiter;
+ Abc_Ntk_t * pFrames;
+ Abc_Ntk_t * pCnf;
+ int RetValue;
+
+ // get the miter of the two networks
+ pMiter = Abc_NtkMiter( pNtk1, pNtk2, 0 );
+ if ( pMiter == NULL )
+ {
+ printf( "Miter computation has failed.\n" );
+ return;
+ }
+ RetValue = Abc_NtkMiterIsConstant( pMiter );
+ if ( RetValue == 1 )
+ {
+ Abc_NtkDelete( pMiter );
+ printf( "Networks are not equivalent.\n" );
+ return;
+ }
+ if ( RetValue == 0 )
+ {
+ Abc_NtkDelete( pMiter );
+ printf( "Networks are equivalent after structural hashing.\n" );
+ return;
+ }
+
+ // create the timeframes
+ pFrames = Abc_NtkFrames( pMiter, nFrames, 1 );
+ Abc_NtkDelete( pMiter );
+ if ( pFrames == NULL )
+ {
+ printf( "Frames computation has failed.\n" );
+ return;
+ }
+ RetValue = Abc_NtkMiterIsConstant( pFrames );
+ if ( RetValue == 1 )
+ {
+ Abc_NtkDelete( pFrames );
+ printf( "Networks are not equivalent.\n" );
+ return;
+ }
+ if ( RetValue == 0 )
+ {
+ Abc_NtkDelete( pFrames );
+ printf( "Networks are equivalent after framing.\n" );
+ return;
+ }
+
+ // convert the miter into a CNF
+ pCnf = Abc_NtkRenode( pFrames, 0, 100, 1, 0, 0 );
+ Abc_NtkDelete( pFrames );
+ if ( pCnf == NULL )
+ {
+ printf( "Renoding for CNF has failed.\n" );
+ return;
+ }
+
+ // solve the CNF using the SAT solver
+ if ( Abc_NtkMiterSat( pCnf, 0 ) )
+ printf( "Networks are not equivalent.\n" );
+ else
+ printf( "Networks are equivalent.\n" );
+ Abc_NtkDelete( pCnf );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Verifies combinational equivalence by fraiging followed by SAT]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_NtkSecFraig( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int nFrames )
+{
+ Fraig_Params_t Params;
+ Abc_Ntk_t * pMiter;
+ Abc_Ntk_t * pFraig;
+ Abc_Ntk_t * pFrames;
+ int RetValue;
+
+ // get the miter of the two networks
+ pMiter = Abc_NtkMiter( pNtk1, pNtk2, 0 );
+ if ( pMiter == NULL )
+ {
+ printf( "Miter computation has failed.\n" );
+ return;
+ }
+ RetValue = Abc_NtkMiterIsConstant( pMiter );
+ if ( RetValue == 1 )
+ {
+ Abc_NtkDelete( pMiter );
+ printf( "Networks are not equivalent.\n" );
+ return;
+ }
+ if ( RetValue == 0 )
+ {
+ Abc_NtkDelete( pMiter );
+ printf( "Networks are equivalent after structural hashing.\n" );
+ return;
+ }
+
+ // create the timeframes
+ pFrames = Abc_NtkFrames( pMiter, nFrames, 1 );
+ Abc_NtkDelete( pMiter );
+ if ( pFrames == NULL )
+ {
+ printf( "Frames computation has failed.\n" );
+ return;
+ }
+ RetValue = Abc_NtkMiterIsConstant( pFrames );
+ if ( RetValue == 1 )
+ {
+ Abc_NtkDelete( pFrames );
+ printf( "Networks are not equivalent.\n" );
+ return;
+ }
+ if ( RetValue == 0 )
+ {
+ Abc_NtkDelete( pFrames );
+ printf( "Networks are equivalent after framing.\n" );
+ return;
+ }
+
+ // convert the miter into a FRAIG
+ Fraig_ParamsSetDefault( &Params );
+ pFraig = Abc_NtkFraig( pMiter, &Params, 0 );
+ Abc_NtkDelete( pFrames );
+ if ( pFraig == NULL )
+ {
+ printf( "Fraiging has failed.\n" );
+ return;
+ }
+ RetValue = Abc_NtkMiterIsConstant( pFraig );
+ Abc_NtkDelete( pFraig );
+ if ( RetValue == 0 )
+ {
+ printf( "Networks are equivalent after fraiging.\n" );
+ return;
+ }
+ printf( "Networks are not equivalent.\n" );
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/abc/module.make b/src/base/abc/module.make
new file mode 100644
index 00000000..1eb88224
--- /dev/null
+++ b/src/base/abc/module.make
@@ -0,0 +1,28 @@
+SRC += src/base/abc/abc.c \
+ src/base/abc/abcAig.c \
+ src/base/abc/abcAttach.c \
+ src/base/abc/abcCheck.c \
+ src/base/abc/abcCollapse.c \
+ src/base/abc/abcCreate.c \
+ src/base/abc/abcDfs.c \
+ src/base/abc/abcDsd.c \
+ src/base/abc/abcFanio.c \
+ src/base/abc/abcFpga.c \
+ src/base/abc/abcFraig.c \
+ src/base/abc/abcFunc.c \
+ src/base/abc/abcLatch.c \
+ src/base/abc/abcMap.c \
+ src/base/abc/abcMinBase.c \
+ src/base/abc/abcMiter.c \
+ src/base/abc/abcNames.c \
+ src/base/abc/abcNetlist.c \
+ src/base/abc/abcPrint.c \
+ src/base/abc/abcRefs.c \
+ src/base/abc/abcRenode.c \
+ src/base/abc/abcSat.c \
+ src/base/abc/abcSop.c \
+ src/base/abc/abcStrash.c \
+ src/base/abc/abcSweep.c \
+ src/base/abc/abcTiming.c \
+ src/base/abc/abcUtil.c \
+ src/base/abc/abcVerify.c
diff --git a/src/base/cmd/cmd.c b/src/base/cmd/cmd.c
new file mode 100644
index 00000000..aa15c0af
--- /dev/null
+++ b/src/base/cmd/cmd.c
@@ -0,0 +1,1498 @@
+/**CFile****************************************************************
+
+ FileName [cmd.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Command processing package.]
+
+ Synopsis [Command file.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: cmd.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mainInt.h"
+#include "cmdInt.h"
+#include "abc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int CmdCommandTime ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int CmdCommandEcho ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int CmdCommandQuit ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int CmdCommandUsage ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int CmdCommandWhich ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int CmdCommandHistory ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int CmdCommandAlias ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int CmdCommandUnalias ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int CmdCommandHelp ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int CmdCommandSource ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int CmdCommandSetVariable ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int CmdCommandUnsetVariable ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int CmdCommandUndo ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int CmdCommandRecall ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int CmdCommandEmpty ( Abc_Frame_t * pAbc, int argc, char ** argv );
+#ifdef WIN32
+static int CmdCommandLs ( Abc_Frame_t * pAbc, int argc, char ** argv );
+#endif
+static int CmdCommandSis ( Abc_Frame_t * pAbc, int argc, char ** argv );
+static int CmdCommandMvsis ( Abc_Frame_t * pAbc, int argc, char ** argv );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function********************************************************************
+
+ Synopsis [Initializes the command package.]
+
+ SideEffects [Commands are added to the command table.]
+
+ SeeAlso [Cmd_End]
+
+******************************************************************************/
+void Cmd_Init( Abc_Frame_t * pAbc )
+{
+ pAbc->tCommands = st_init_table(strcmp, st_strhash);
+ pAbc->tAliases = st_init_table(strcmp, st_strhash);
+ pAbc->tFlags = st_init_table(strcmp, st_strhash);
+ pAbc->aHistory = Vec_PtrAlloc( 100 );
+
+ Cmd_CommandAdd( pAbc, "Basic", "time", CmdCommandTime, 0);
+ Cmd_CommandAdd( pAbc, "Basic", "echo", CmdCommandEcho, 0);
+ Cmd_CommandAdd( pAbc, "Basic", "quit", CmdCommandQuit, 0);
+// Cmd_CommandAdd( pAbc, "Basic", "usage", CmdCommandUsage, 0);
+ Cmd_CommandAdd( pAbc, "Basic", "history", CmdCommandHistory, 0);
+ Cmd_CommandAdd( pAbc, "Basic", "alias", CmdCommandAlias, 0);
+ Cmd_CommandAdd( pAbc, "Basic", "unalias", CmdCommandUnalias, 0);
+ Cmd_CommandAdd( pAbc, "Basic", "help", CmdCommandHelp, 0);
+ Cmd_CommandAdd( pAbc, "Basic", "source", CmdCommandSource, 0);
+ Cmd_CommandAdd( pAbc, "Basic", "set", CmdCommandSetVariable, 0);
+ Cmd_CommandAdd( pAbc, "Basic", "unset", CmdCommandUnsetVariable, 0);
+ Cmd_CommandAdd( pAbc, "Basic", "undo", CmdCommandUndo, 0);
+// Cmd_CommandAdd( pAbc, "Basic", "recall", CmdCommandRecall, 0);
+ Cmd_CommandAdd( pAbc, "Basic", "empty", CmdCommandEmpty, 0);
+#ifdef WIN32
+ Cmd_CommandAdd( pAbc, "Basic", "ls", CmdCommandLs, 0 );
+#endif
+
+ Cmd_CommandAdd( pAbc, "Various", "sis", CmdCommandSis, 1);
+ Cmd_CommandAdd( pAbc, "Various", "mvsis", CmdCommandMvsis, 1);
+}
+
+/**Function********************************************************************
+
+ Synopsis [Ends the command package.]
+
+ Description [Ends the command package. Tables are freed.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void Cmd_End( Abc_Frame_t * pAbc )
+{
+ st_generator * gen;
+ char * pKey, * pValue;
+ int i;
+
+// st_free_table( pAbc->tCommands, (void (*)()) 0, CmdCommandFree );
+// st_free_table( pAbc->tAliases, (void (*)()) 0, CmdCommandAliasFree );
+// st_free_table( pAbc->tFlags, free, free );
+
+ st_foreach_item( pAbc->tCommands, gen, (char **)&pKey, (char **)&pValue )
+ CmdCommandFree( (Abc_Command *)pValue );
+ st_free_table( pAbc->tCommands );
+
+ st_foreach_item( pAbc->tAliases, gen, (char **)&pKey, (char **)&pValue )
+ CmdCommandAliasFree( (Abc_Alias *)pValue );
+ st_free_table( pAbc->tAliases );
+
+ st_foreach_item( pAbc->tFlags, gen, (char **)&pKey, (char **)&pValue )
+ free( pKey ), free( pValue );
+ st_free_table( pAbc->tFlags );
+
+ for ( i = 0; i < pAbc->aHistory->nSize; i++ )
+ free( pAbc->aHistory->pArray[i] );
+ Vec_PtrFree( pAbc->aHistory );
+}
+
+
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int CmdCommandTime( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ int c;
+
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "h" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( argc != util_optind )
+ {
+ goto usage;
+ }
+
+ pAbc->TimeTotal += pAbc->TimeCommand;
+ fprintf( pAbc->Out, "elapse: %3.2f seconds, total: %3.2f seconds\n",
+ (float)pAbc->TimeCommand / CLOCKS_PER_SEC, (float)pAbc->TimeTotal / CLOCKS_PER_SEC );
+ pAbc->TimeCommand = 0;
+ return 0;
+
+ usage:
+ fprintf( pAbc->Err, "usage: time [-h]\n" );
+ fprintf( pAbc->Err, " -h \t\tprint the command usage\n" );
+ return 1;
+}
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int CmdCommandEcho( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ int i;
+ int c;
+ int n = 1;
+
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "hn" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'n':
+ n = 0;
+ break;
+ case 'h':
+ goto usage;
+ break;
+ default:
+ goto usage;
+ }
+ }
+
+ for ( i = util_optind; i < argc; i++ )
+ fprintf( pAbc->Out, "%s ", argv[i] );
+ if ( n )
+ fprintf( pAbc->Out, "\n" );
+ else
+ fflush ( pAbc->Out );
+ return 0;
+
+ usage:
+ fprintf( pAbc->Err, "usage: echo [-h] string \n" );
+ fprintf( pAbc->Err, " -n \t\tsuppress newline at the end\n" );
+ fprintf( pAbc->Err, " -h \t\tprint the command usage\n" );
+ return ( 1 );
+}
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int CmdCommandQuit( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ int c;
+
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "hs" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ break;
+ case 's':
+ return -2;
+ break;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( argc != util_optind )
+ goto usage;
+ return -1;
+
+ usage:
+ fprintf( pAbc->Err, "usage: quit [-h] [-s]\n" );
+ fprintf( pAbc->Err, " -h print the command usage\n" );
+ fprintf( pAbc->Err,
+ " -s frees all the memory before quitting\n" );
+ return 1;
+}
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int CmdCommandUsage( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ int c;
+
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "h" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ break;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( argc != util_optind )
+ goto usage;
+ util_print_cpu_stats( pAbc->Out );
+ return 0;
+
+ usage:
+ fprintf( pAbc->Err, "usage: usage [-h]\n" );
+ fprintf( pAbc->Err, " -h \t\tprint the command usage\n" );
+ return 1;
+}
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int CmdCommandWhich( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ return 0;
+}
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int CmdCommandHistory( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ int i, num;
+ int size;
+ int c;
+ num = 30;
+
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "h" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ break;
+ }
+ }
+
+ if ( argc > 3 )
+ goto usage;
+
+ size = pAbc->aHistory->nSize;
+ num = ( num < size ) ? num : size;
+ for ( i = size - num; i < size; i++ )
+ fprintf( pAbc->Out, "%s", pAbc->aHistory->pArray[i] );
+ return 0;
+
+ usage:
+ fprintf( pAbc->Err, "usage: history [-h] [num]\n" );
+ fprintf( pAbc->Err, " -h \t\tprint the command usage\n" );
+ fprintf( pAbc->Err, " num \t\tprint the last num commands\n" );
+ return ( 1 );
+}
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int CmdCommandAlias( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ char *key, *value;
+ st_generator *gen;
+ int c;
+
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "h" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ break;
+ default:
+ goto usage;
+ }
+ }
+
+
+ if ( argc == 1 )
+ {
+ st_foreach_item( pAbc->tAliases, gen, &key, &value )
+ CmdCommandAliasPrint( pAbc, ( Abc_Alias * ) value );
+ return 0;
+
+ }
+ else if ( argc == 2 )
+ {
+ if ( st_lookup( pAbc->tAliases, argv[1], &value ) )
+ CmdCommandAliasPrint( pAbc, ( Abc_Alias * ) value );
+ return 0;
+ }
+
+ // delete any existing alias
+ key = argv[1];
+ if ( st_delete( pAbc->tAliases, &key, &value ) )
+ CmdCommandAliasFree( ( Abc_Alias * ) value );
+ CmdCommandAliasAdd( pAbc, argv[1], argc - 2, argv + 2 );
+ return 0;
+
+usage:
+ fprintf( pAbc->Err, "usage: alias [-h] [command [string]]\n" );
+ fprintf( pAbc->Err, " -h \t\tprint the command usage\n" );
+ return ( 1 );
+}
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int CmdCommandUnalias( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ int i;
+ char *key, *value;
+ int c;
+
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "h" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ break;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( argc < 2 )
+ {
+ goto usage;
+ }
+
+ for ( i = 1; i < argc; i++ )
+ {
+ key = argv[i];
+ if ( st_delete( pAbc->tAliases, &key, &value ) )
+ {
+ CmdCommandAliasFree( ( Abc_Alias * ) value );
+ }
+ }
+ return 0;
+
+ usage:
+ fprintf( pAbc->Err, "usage: unalias [-h] alias_names\n" );
+ fprintf( pAbc->Err, " -h \t\tprint the command usage\n" );
+ return 1;
+}
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int CmdCommandHelp( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ bool fPrintAll;
+ int c;
+
+ fPrintAll = 0;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "ah" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'a':
+ case 'v':
+ fPrintAll ^= 1;
+ break;
+ break;
+ case 'h':
+ goto usage;
+ break;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( argc != util_optind )
+ goto usage;
+
+ CmdCommandPrint( pAbc, fPrintAll );
+ return 0;
+
+usage:
+ fprintf( pAbc->Err, "usage: help [-a] [-h]\n" );
+ fprintf( pAbc->Err, " prints the list of available commands by group\n" );
+ fprintf( pAbc->Err, " -a toggle printing hidden commands [default = %s]\n", fPrintAll? "yes": "no" );
+ fprintf( pAbc->Err, " -h print the command usage\n" );
+ return 1;
+}
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int CmdCommandSource( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ int c, echo, prompt, silent, interactive, quit_count, lp_count;
+ int status = 0; /* initialize so that lint doesn't complain */
+ int lp_file_index, did_subst;
+ char *prompt_string, *real_filename, line[MAX_STR], *command;
+ FILE *fp;
+
+ interactive = silent = prompt = echo = 0;
+
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "hipsx" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ break;
+ case 'i': /* a hack to distinguish EOF from stdin */
+ interactive = 1;
+ break;
+ case 'p':
+ prompt = 1;
+ break;
+ case 's':
+ silent = 1;
+ break;
+ case 'x':
+ echo ^= 1;
+ break;
+ default:
+ goto usage;
+ }
+ }
+
+ /* added to avoid core-dumping when no script file is specified */
+ if ( argc == util_optind )
+ {
+ goto usage;
+ }
+
+ lp_file_index = util_optind;
+ lp_count = 0;
+
+ /*
+ * FIX (Tom, 5/7/95): I'm not sure what the purpose of this outer do loop
+ * is. In particular, lp_file_index is never modified in the loop, so it
+ * looks it would just read the same file over again. Also, SIS had
+ * lp_count initialized to -1, and hence, any file sourced by SIS (if -l or
+ * -t options on "source" were used in SIS) would actually be executed
+ * twice.
+ */
+ do
+ {
+ lp_count++; /* increment the loop counter */
+
+ fp = CmdFileOpen( pAbc, argv[lp_file_index], "r", &real_filename, silent );
+ if ( fp == NULL )
+ {
+ FREE( real_filename );
+ return !silent; /* error return if not silent */
+ }
+
+ quit_count = 0;
+ do
+ {
+ if ( prompt )
+ {
+ prompt_string = Cmd_FlagReadByName( pAbc, "prompt" );
+ if ( prompt_string == NULL )
+ prompt_string = "abc> ";
+
+ }
+ else
+ {
+ prompt_string = NIL( char );
+ }
+
+ /* clear errors -- e.g., EOF reached from stdin */
+ clearerr( fp );
+
+ /* read another command line */
+// if (CmdFgetsFilec(line, MAX_STR, fp, prompt_string) == NULL) {
+// Abc_UtilsPrintPrompt(prompt_string);
+// fflush(stdout);
+ if ( fgets( line, MAX_STR, fp ) == NULL )
+ {
+ if ( interactive )
+ {
+ if ( quit_count++ < 5 )
+ {
+ fprintf( pAbc->Err, "\nUse \"quit\" to leave ABC.\n" );
+ continue;
+ }
+ status = -1; /* fake a 'quit' */
+ }
+ else
+ {
+ status = 0; /* successful end of 'source' ; loop? */
+ }
+ break;
+ }
+ quit_count = 0;
+
+ if ( echo )
+ {
+ fprintf( pAbc->Out, "abc - > %s", line );
+ }
+ command = CmdHistorySubstitution( pAbc, line, &did_subst );
+ if ( command == NIL( char ) )
+ {
+ status = 1;
+ break;
+ }
+ if ( did_subst )
+ {
+ if ( interactive )
+ {
+ fprintf( pAbc->Out, "%s\n", command );
+ }
+ }
+ if ( command != line )
+ {
+ ( void ) strcpy( line, command );
+ }
+ if ( interactive && *line != '\0' )
+ {
+ Cmd_HistoryAddCommand( pAbc, util_strsav(line) );
+ if ( pAbc->Hst != NIL( FILE ) )
+ {
+ fprintf( pAbc->Hst, "%s\n", line );
+ ( void ) fflush( pAbc->Hst );
+ }
+ }
+
+ status = Cmd_CommandExecute( pAbc, line );
+ }
+ while ( status == 0 );
+
+ if ( fp != stdin )
+ {
+ if ( status > 0 )
+ {
+ fprintf( pAbc->Err,
+ "** cmd error: aborting 'source %s'\n",
+ real_filename );
+ }
+ ( void ) fclose( fp );
+ }
+ FREE( real_filename );
+
+ }
+ while ( ( status == 0 ) && ( lp_count <= 0 ) );
+
+ return status;
+
+ usage:
+ fprintf( pAbc->Err, "usage: source [-h] [-p] [-s] [-x] file_name\n" );
+ fprintf( pAbc->Err, "\t-h print the command usage\n" );
+ fprintf( pAbc->Err, "\t-p supply prompt before reading each line\n" );
+ fprintf( pAbc->Err, "\t-s silently ignore nonexistant file\n" );
+ fprintf( pAbc->Err, "\t-x echo each line as it is executed\n" );
+ return 1;
+}
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int CmdCommandSetVariable( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ char *flag_value, *key, *value;
+ st_generator *gen;
+ int c;
+
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "h" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ break;
+ default:
+ goto usage;
+ }
+ }
+ if ( argc == 0 || argc > 3 )
+ {
+ goto usage;
+ }
+ else if ( argc == 1 )
+ {
+ st_foreach_item( pAbc->tFlags, gen, &key, &value )
+ {
+ fprintf( pAbc->Out, "%s\t%s\n", key, value );
+ }
+ return 0;
+ }
+ else
+ {
+ key = argv[1];
+ if ( st_delete( pAbc->tFlags, &key, &value ) )
+ {
+ FREE( key );
+ FREE( value );
+ }
+
+ flag_value = argc == 2 ? util_strsav( "" ) : util_strsav( argv[2] );
+
+ ( void ) st_insert( pAbc->tFlags, util_strsav( argv[1] ),
+ flag_value );
+
+ if ( strcmp( argv[1], "abcout" ) == 0 )
+ {
+ if ( pAbc->Out != stdout )
+ {
+ ( void ) fclose( pAbc->Out );
+ }
+ if ( strcmp( flag_value, "" ) == 0 )
+ {
+ flag_value = "-";
+ }
+ pAbc->Out = CmdFileOpen( pAbc, flag_value, "w", NIL( char * ), 0 );
+ if ( pAbc->Out == NULL )
+ {
+ pAbc->Out = stdout;
+ }
+#if HAVE_SETVBUF
+ setvbuf( pAbc->Out, ( char * ) NULL, _IOLBF, 0 );
+#endif
+ }
+ if ( strcmp( argv[1], "abcerr" ) == 0 )
+ {
+ if ( pAbc->Err != stderr )
+ {
+ ( void ) fclose( pAbc->Err );
+ }
+ if ( strcmp( flag_value, "" ) == 0 )
+ {
+ flag_value = "-";
+ }
+ pAbc->Err = CmdFileOpen( pAbc, flag_value, "w", NIL( char * ), 0 );
+ if ( pAbc->Err == NULL )
+ {
+ pAbc->Err = stderr;
+ }
+#if HAVE_SETVBUF
+ setvbuf( pAbc->Err, ( char * ) NULL, _IOLBF, 0 );
+#endif
+ }
+ if ( strcmp( argv[1], "history" ) == 0 )
+ {
+ if ( pAbc->Hst != NIL( FILE ) )
+ {
+ ( void ) fclose( pAbc->Hst );
+ }
+ if ( strcmp( flag_value, "" ) == 0 )
+ {
+ pAbc->Hst = NIL( FILE );
+ }
+ else
+ {
+ pAbc->Hst =
+ CmdFileOpen( pAbc, flag_value, "w", NIL( char * ), 0 );
+ if ( pAbc->Hst == NULL )
+ {
+ pAbc->Hst = NIL( FILE );
+ }
+ }
+ }
+ return 0;
+ }
+
+ usage:
+ fprintf( pAbc->Err, "usage: set [-h] [name] [value]\n" );
+ fprintf( pAbc->Err, "\t sets the value of parameter <name>\n" );
+ fprintf( pAbc->Err, "\t-h : print the command usage\n" );
+ return 1;
+
+}
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int CmdCommandUnsetVariable( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ int i;
+ char *key, *value;
+ int c;
+
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "h" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ break;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( argc < 2 )
+ {
+ goto usage;
+ }
+
+ for ( i = 1; i < argc; i++ )
+ {
+ key = argv[i];
+ if ( st_delete( pAbc->tFlags, &key, &value ) )
+ {
+ FREE( key );
+ FREE( value );
+ }
+ }
+ return 0;
+
+
+ usage:
+ fprintf( pAbc->Err, "usage: unset [-h] variables \n" );
+ fprintf( pAbc->Err, " -h \t\tprint the command usage\n" );
+ return 1;
+}
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int CmdCommandUndo( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ if ( pAbc->pNtkCur == NULL )
+ {
+ fprintf( pAbc->Out, "Empty network.\n" );
+ return 0;
+ }
+
+ // if there are no arguments on the command line
+ // set the current network to be the network from the previous step
+ if ( argc == 1 )
+ return CmdCommandRecall( pAbc, argc, argv );
+
+ fprintf( pAbc->Err, "usage: undo\n" );
+ fprintf( pAbc->Err, " sets the current network to be the previously saved network\n" );
+ return 1;
+
+}
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int CmdCommandRecall( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ Abc_Ntk_t * pNtk;
+ int iStep, iStepFound;
+ int nNetsToSave, c;
+ char * pValue;
+ int iStepStart, iStepStop;
+
+ if ( pAbc->pNtkCur == NULL )
+ {
+ fprintf( pAbc->Out, "Empty network.\n" );
+ return 0;
+ }
+
+
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "h" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ // get the number of networks to save
+ pValue = Cmd_FlagReadByName( pAbc, "savesteps" );
+ // if the value of steps to save is not set, assume 1-level undo
+ if ( pValue == NULL )
+ nNetsToSave = 1;
+ else
+ nNetsToSave = atoi(pValue);
+
+ // if there are no arguments on the command line
+ // set the current network to be the network from the previous step
+ if ( argc == 1 )
+ {
+ // get the previously saved network
+ pNtk = Abc_NtkBackup(pAbc->pNtkCur);
+ if ( pNtk == NULL )
+ fprintf( pAbc->Out, "There is no previously saved network.\n" );
+ else // set the current network to be the copy of the previous one
+ Abc_FrameSetCurrentNetwork( pAbc, Abc_NtkDup(pNtk) );
+ return 0;
+ }
+ if ( argc == 2 ) // the second argument is the number of the step to return to
+ {
+ // read the number of the step to return to
+ iStep = atoi(argv[1]);
+ // check whether it is reasonable
+ if ( iStep >= pAbc->nSteps )
+ {
+ iStepStart = pAbc->nSteps - nNetsToSave;
+ if ( iStepStart <= 0 )
+ iStepStart = 1;
+ iStepStop = pAbc->nSteps;
+ if ( iStepStop <= 0 )
+ iStepStop = 1;
+ if ( iStepStart == iStepStop )
+ fprintf( pAbc->Out, "Can only recall step %d.\n", iStepStop );
+ else
+ fprintf( pAbc->Out, "Can only recall steps %d-%d.\n", iStepStart, iStepStop );
+ }
+ else if ( iStep < 0 )
+ fprintf( pAbc->Out, "Cannot recall step %d.\n", iStep );
+ else if ( iStep == 0 )
+ Abc_FrameDeleteAllNetworks( pAbc );
+ else
+ {
+ // scroll backward through the list of networks
+ // to determine if such a network exist
+ iStepFound = 0;
+ for ( pNtk = pAbc->pNtkCur; pNtk; pNtk = Abc_NtkBackup(pNtk) )
+ if ( (iStepFound = Abc_NtkStep(pNtk)) == iStep )
+ break;
+ if ( pNtk == NULL )
+ {
+ iStepStart = iStepFound;
+ if ( iStepStart <= 0 )
+ iStepStart = 1;
+ iStepStop = pAbc->nSteps;
+ if ( iStepStop <= 0 )
+ iStepStop = 1;
+ if ( iStepStart == iStepStop )
+ fprintf( pAbc->Out, "Can only recall step %d.\n", iStepStop );
+ else
+ fprintf( pAbc->Out, "Can only recall steps %d-%d.\n", iStepStart, iStepStop );
+ }
+ else
+ Abc_FrameSetCurrentNetwork( pAbc, Abc_NtkDup(pNtk) );
+ }
+ return 0;
+ }
+
+usage:
+
+ fprintf( pAbc->Err, "usage: recall <num>\n" );
+ fprintf( pAbc->Err, " set the current network to be one of the previous networks\n" );
+ fprintf( pAbc->Err, "<num> : level to return to [default = previous]\n" );
+ return 1;
+}
+
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int CmdCommandEmpty( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ int c;
+
+ if ( pAbc->pNtkCur == NULL )
+ {
+ fprintf( pAbc->Out, "Empty network.\n" );
+ return 0;
+ }
+
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "h" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ Abc_FrameDeleteAllNetworks( pAbc );
+ Abc_FrameRestart( pAbc );
+ return 0;
+usage:
+
+ fprintf( pAbc->Err, "usage: empty [-h]\n" );
+ fprintf( pAbc->Err, " removes all the currently stored networks\n" );
+ fprintf( pAbc->Err, " -h : print the command usage\n");
+ return 1;
+}
+
+
+#if 0
+
+/**Function********************************************************************
+
+ Synopsis [Donald's version.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int CmdCommandUndo( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ Abc_Ntk_t * pNtkTemp;
+ int id, c;
+
+ while ( ( c = util_getopt( argc, argv, "h" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ break;
+ default:
+ goto usage;
+ }
+ }
+ if (util_optind <= argc) {
+ pNtkTemp = pAbc->pNtk;
+ pAbc->pNtk = pAbc->pNtkSaved;
+ pAbc->pNtkSaved = pNtkTemp;
+ }
+ id = atoi(argv[util_optind]);
+ pNtkTemp = Cmd_HistoryGetSnapshot(pAbc, id);
+ if (!pNtkTemp)
+ fprintf( pAbc->Err, "Snapshot %d does not exist\n", id);
+ else
+ pAbc->pNtk = Abc_NtkDup(pNtkTemp, Abc_NtkMan(pNtkTemp));
+
+ return 0;
+usage:
+ fprintf( pAbc->Err, "usage: undo\n" );
+ fprintf( pAbc->Err, " swaps the current network and the backup network\n" );
+ return 1;
+}
+
+#endif
+
+
+#ifdef WIN32
+/**Function*************************************************************
+
+ Synopsis [Command to print the contents of the current directory (Windows).]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+#include <io.h>
+
+// these structures are defined in <io.h> but are for some reason invisible
+typedef unsigned long _fsize_t; // Could be 64 bits for Win32
+
+struct _finddata_t {
+ unsigned attrib;
+ time_t time_create; // -1 for FAT file systems
+ time_t time_access; // -1 for FAT file systems
+ time_t time_write;
+ _fsize_t size;
+ char name[260];
+};
+
+extern long _findfirst( char *filespec, struct _finddata_t *fileinfo );
+extern int _findnext( long handle, struct _finddata_t *fileinfo );
+extern int _findclose( long handle );
+
+int CmdCommandLs( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ struct _finddata_t c_file;
+ long hFile;
+ int fLong = 0;
+ int fOnlyBLIF = 0;
+ char Buffer[25];
+ int Counter = 0;
+ int fPrintedNewLine;
+ char c;
+
+ util_getopt_reset();
+ while ( (c = util_getopt(argc, argv, "lb") ) != EOF )
+ {
+ switch (c)
+ {
+ case 'l':
+ fLong = 1;
+ break;
+ case 'b':
+ fOnlyBLIF = 1;
+ break;
+ default:
+ goto usage;
+ }
+ }
+
+ // find first .mv file in current directory
+ if( (hFile = _findfirst( ((fOnlyBLIF)? "*.mv": "*.*"), &c_file )) == -1L )
+ {
+ if ( fOnlyBLIF )
+ fprintf( pAbc->Out, "No *.mv files in the current directory.\n" );
+ else
+ fprintf( pAbc->Out, "No files in the current directory.\n" );
+ }
+ else
+ {
+ if ( fLong )
+ {
+ fprintf( pAbc->Out, " File Date Size | File Date Size \n" );
+ fprintf( pAbc->Out, " ----------------------------------------------------------------------------- \n" );
+ do
+ {
+ strcpy( Buffer, ctime( &(c_file.time_write) ) );
+ Buffer[16] = 0;
+ fprintf( pAbc->Out, " %-17s %.24s%7ld", c_file.name, Buffer+4, c_file.size );
+ if ( ++Counter % 2 == 0 )
+ {
+ fprintf( pAbc->Out, "\n" );
+ fPrintedNewLine = 1;
+ }
+ else
+ {
+ fprintf( pAbc->Out, " |" );
+ fPrintedNewLine = 0;
+ }
+ }
+ while( _findnext( hFile, &c_file ) == 0 );
+ }
+ else
+ {
+ do
+ {
+ fprintf( pAbc->Out, " %-18s", c_file.name );
+ if ( ++Counter % 4 == 0 )
+ {
+ fprintf( pAbc->Out, "\n" );
+ fPrintedNewLine = 1;
+ }
+ else
+ {
+ fprintf( pAbc->Out, " " );
+ fPrintedNewLine = 0;
+ }
+ }
+ while( _findnext( hFile, &c_file ) == 0 );
+ }
+ if ( !fPrintedNewLine )
+ fprintf( pAbc->Out, "\n" );
+ _findclose( hFile );
+ }
+ return 0;
+
+usage:
+ fprintf( pAbc->Err, "Usage: ls [-l] [-b]\n" );
+ fprintf( pAbc->Err, " print the file names in the current directory\n" );
+ fprintf( pAbc->Err, " -l : print in the long format [default = short]\n" );
+ fprintf( pAbc->Err, " -b : print only .mv files [default = all]\n" );
+ return 1;
+}
+#endif
+
+
+
+#ifdef WIN32
+#define unlink _unlink
+#endif
+
+/**Function********************************************************************
+
+ Synopsis [Calls SIS internally.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int CmdCommandSis( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ FILE * pFile;
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk, * pNtkNew;
+ char Command[1000], Buffer[100];
+ char * pSisName;
+ int i;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ goto usage;
+ }
+
+ if ( strcmp( argv[0], "sis" ) != 0 )
+ {
+ fprintf( pErr, "Wrong command: \"%s\".\n", argv[0] );
+ goto usage;
+ }
+
+ if ( argc == 1 )
+ goto usage;
+ if ( strcmp( argv[1], "-h" ) == 0 )
+ goto usage;
+ if ( strcmp( argv[1], "-?" ) == 0 )
+ goto usage;
+
+ // check if SIS is available
+ if ( (pFile = fopen( "sis.exe", "r" )) )
+ pSisName = "sis.exe";
+ else if ( (pFile = fopen( "sis", "r" )) )
+ pSisName = "sis";
+ else if ( pFile == NULL )
+ {
+ fprintf( pErr, "Cannot find \"%s\" or \"%s\" in the current directory.\n", "sis.exe", "sis" );
+ goto usage;
+ }
+ fclose( pFile );
+
+ if ( Abc_NtkIsLogicBdd(pNtk) )
+ Abc_NtkBddToSop(pNtk);
+
+ // write out the current network
+ Io_WriteBlifLogic( pNtk, "_sis_in.blif", 1 );
+
+ // create the file for sis
+ sprintf( Command, "%s -x -c ", pSisName );
+ strcat ( Command, "\"" );
+ strcat ( Command, "read_blif _sis_in.blif" );
+ strcat ( Command, "; " );
+ for ( i = 1; i < argc; i++ )
+ {
+ sprintf( Buffer, " %s", argv[i] );
+ strcat( Command, Buffer );
+ }
+ strcat( Command, "; " );
+ strcat( Command, "write_blif _sis_out.blif" );
+ strcat( Command, "\"" );
+
+ // call SIS
+ if ( system( Command ) )
+ {
+ fprintf( pErr, "The following command has returned non-zero exit status:\n" );
+ fprintf( pErr, "\"%s\"\n", Command );
+ unlink( "_sis_in.blif" );
+ goto usage;
+ }
+
+ // read in the SIS output
+ if ( (pFile = fopen( "_sis_out.blif", "r" )) == NULL )
+ {
+ fprintf( pErr, "Cannot open SIS output file \"%s\".\n", "_sis_out.blif" );
+ unlink( "_sis_in.blif" );
+ goto usage;
+ }
+ fclose( pFile );
+
+ // set the new network
+ pNtkNew = Io_Read( "_sis_out.blif", 1 );
+ // set the original spec of the new network
+ if ( pNtk->pSpec )
+ {
+ FREE( pNtkNew->pSpec );
+ pNtkNew->pSpec = util_strsav( pNtk->pSpec );
+ }
+ // replace the current network
+ Abc_FrameReplaceCurrentNetwork( pAbc, pNtkNew );
+
+ // remove temporary networks
+ unlink( "_sis_in.blif" );
+ unlink( "_sis_out.blif" );
+ return 0;
+
+usage:
+ fprintf( pErr, "\n" );
+ fprintf( pErr, "Usage: sis [-h] <com>\n");
+ fprintf( pErr, " invokes SIS command for the current ABC network\n" );
+ fprintf( pErr, " (the executable of SIS should be in the same directory)\n" );
+ fprintf( pErr, " -h : print the command usage\n" );
+ fprintf( pErr, " <com> : a SIS command (or a semicolon-separated list of commands in quotes)\n" );
+ fprintf( pErr, " Example 1: sis eliminate 0\n" );
+ fprintf( pErr, " Example 2: sis \"ps; rd; fx; ps\"\n" );
+ fprintf( pErr, " Example 3: sis source script.rugged\n" );
+ return 1; // error exit
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Calls SIS internally.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int CmdCommandMvsis( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ FILE * pFile;
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNtk, * pNtkNew;
+ char Command[1000], Buffer[100];
+ char * pMvsisName;
+ int i;
+
+ pNtk = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pErr, "Empty network.\n" );
+ goto usage;
+ }
+
+ if ( strcmp( argv[0], "mvsis" ) != 0 )
+ {
+ fprintf( pErr, "Wrong command: \"%s\".\n", argv[0] );
+ goto usage;
+ }
+
+ if ( argc == 1 )
+ goto usage;
+ if ( strcmp( argv[1], "-h" ) == 0 )
+ goto usage;
+ if ( strcmp( argv[1], "-?" ) == 0 )
+ goto usage;
+
+ // check if MVSIS is available
+ if ( (pFile = fopen( "mvsis.exe", "r" )) )
+ pMvsisName = "mvsis.exe";
+ else if ( (pFile = fopen( "mvsis", "r" )) )
+ pMvsisName = "mvsis";
+ else if ( pFile == NULL )
+ {
+ fprintf( pErr, "Cannot find \"%s\" or \"%s\" in the current directory.\n", "mvsis.exe", "mvsis" );
+ goto usage;
+ }
+ fclose( pFile );
+
+ if ( Abc_NtkIsLogicBdd(pNtk) )
+ Abc_NtkBddToSop(pNtk);
+
+ // write out the current network
+ Io_WriteBlifLogic( pNtk, "_mvsis_in.blif", 1 );
+
+ // create the file for MVSIS
+ sprintf( Command, "%s -x -c ", pMvsisName );
+ strcat ( Command, "\"" );
+ strcat ( Command, "read_blif _mvsis_in.blif" );
+ strcat ( Command, "; " );
+ for ( i = 1; i < argc; i++ )
+ {
+ sprintf( Buffer, " %s", argv[i] );
+ strcat( Command, Buffer );
+ }
+ strcat( Command, "; " );
+ strcat( Command, "write_blif _mvsis_out.blif" );
+ strcat( Command, "\"" );
+
+ // call MVSIS
+ if ( system( Command ) )
+ {
+ fprintf( pErr, "The following command has returned non-zero exit status:\n" );
+ fprintf( pErr, "\"%s\"\n", Command );
+ unlink( "_mvsis_in.blif" );
+ goto usage;
+ }
+
+ // read in the MVSIS output
+ if ( (pFile = fopen( "_mvsis_out.blif", "r" )) == NULL )
+ {
+ fprintf( pErr, "Cannot open MVSIS output file \"%s\".\n", "_mvsis_out.blif" );
+ unlink( "_mvsis_in.blif" );
+ goto usage;
+ }
+ fclose( pFile );
+
+ // set the new network
+ pNtkNew = Io_Read( "_mvsis_out.blif", 1 );
+ // set the original spec of the new network
+ if ( pNtk->pSpec )
+ {
+ FREE( pNtkNew->pSpec );
+ pNtkNew->pSpec = util_strsav( pNtk->pSpec );
+ }
+ // replace the current network
+ Abc_FrameReplaceCurrentNetwork( pAbc, pNtkNew );
+
+ // remove temporary networks
+ unlink( "_mvsis_in.blif" );
+ unlink( "_mvsis_out.blif" );
+ return 0;
+
+usage:
+ fprintf( pErr, "\n" );
+ fprintf( pErr, "Usage: mvsis [-h] <com>\n");
+ fprintf( pErr, " invokes MVSIS command for the current ABC network\n" );
+ fprintf( pErr, " (the executable of MVSIS should be in the same directory)\n" );
+ fprintf( pErr, " -h : print the command usage\n" );
+ fprintf( pErr, " <com> : a MVSIS command (or a semicolon-separated list of commands in quotes)\n" );
+ fprintf( pErr, " Example 1: mvsis fraig_sweep\n" );
+ fprintf( pErr, " Example 2: mvsis \"ps; fxu; ps\"\n" );
+ fprintf( pErr, " Example 3: mvsis source mvsis.rugged\n" );
+ return 1; // error exit
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/cmd/cmd.h b/src/base/cmd/cmd.h
new file mode 100644
index 00000000..6389afae
--- /dev/null
+++ b/src/base/cmd/cmd.h
@@ -0,0 +1,65 @@
+/**CFile****************************************************************
+
+ FileName [cmd.h]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Command processing package.]
+
+ Synopsis [External declarations of the command package.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: cmd.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __CMD_H__
+#define __CMD_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct MvCommand Abc_Command; // one command
+typedef struct MvAlias Abc_Alias; // one alias
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== cmd.c ===========================================================*/
+extern void Cmd_Init();
+extern void Cmd_End();
+/*=== cmdApi.c ========================================================*/
+extern void Cmd_CommandAdd( Abc_Frame_t * pAbc, char * sGroup, char * sName, void * pFunc, int fChanges );
+extern int Cmd_CommandExecute( Abc_Frame_t * pAbc, char * sCommand );
+/*=== cmdFlag.c ========================================================*/
+extern char * Cmd_FlagReadByName( Abc_Frame_t * pAbc, char * flag );
+extern void Cmd_FlagDeleteByName( Abc_Frame_t * pAbc, char * key );
+extern void Cmd_FlagUpdateValue( Abc_Frame_t * pAbc, char * key, char * value );
+/*=== cmdHist.c ========================================================*/
+extern void Cmd_HistoryAddCommand( Abc_Frame_t * pAbc, char * command );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/src/base/cmd/cmdAlias.c b/src/base/cmd/cmdAlias.c
new file mode 100644
index 00000000..37220ef0
--- /dev/null
+++ b/src/base/cmd/cmdAlias.c
@@ -0,0 +1,120 @@
+/**CFile****************************************************************
+
+ FileName [cmdAlias.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Command processing package.]
+
+ Synopsis [Procedures dealing with aliases in the command package.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: cmdAlias.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "cmdInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void CmdCommandAliasAdd( Abc_Frame_t * pAbc, char * sName, int argc, char ** argv )
+{
+ Abc_Alias * pAlias;
+ int fStatus, i;
+
+ pAlias = ALLOC(Abc_Alias, 1);
+ pAlias->sName = util_strsav(sName);
+ pAlias->argc = argc;
+ pAlias->argv = ALLOC(char *, pAlias->argc);
+ for(i = 0; i < argc; i++)
+ pAlias->argv[i] = util_strsav(argv[i]);
+ fStatus = st_insert( pAbc->tAliases, pAlias->sName, (char *) pAlias );
+ assert(!fStatus);
+}
+
+/**Function********************************************************************
+
+ Synopsis [required]
+
+ Description [optional]
+
+ SideEffects [required]
+
+ SeeAlso [optional]
+
+******************************************************************************/
+void CmdCommandAliasPrint( Abc_Frame_t * pAbc, Abc_Alias * pAlias )
+{
+ int i;
+ fprintf(pAbc->Out, "%s\t", pAlias->sName);
+ for(i = 0; i < pAlias->argc; i++)
+ fprintf( pAbc->Out, " %s", pAlias->argv[i] );
+ fprintf( pAbc->Out, "\n" );
+}
+
+/**Function********************************************************************
+
+ Synopsis [required]
+
+ Description [optional]
+
+ SideEffects [required]
+
+ SeeAlso [optional]
+
+******************************************************************************/
+char * CmdCommandAliasLookup( Abc_Frame_t * pAbc, char * sCommand )
+{
+ Abc_Alias * pAlias;
+ char * value;
+ if (!st_lookup( pAbc->tAliases, sCommand, &value))
+ return sCommand;
+ pAlias = (Abc_Alias *) value;
+ return pAlias->argv[0];
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void CmdCommandAliasFree( Abc_Alias * pAlias )
+{
+ CmdFreeArgv( pAlias->argc, pAlias->argv );
+ FREE(pAlias->sName);
+ FREE(pAlias);
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/cmd/cmdApi.c b/src/base/cmd/cmdApi.c
new file mode 100644
index 00000000..8dd67637
--- /dev/null
+++ b/src/base/cmd/cmdApi.c
@@ -0,0 +1,104 @@
+/**CFile****************************************************************
+
+ FileName [cmdApi.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Command processing package.]
+
+ Synopsis [External procedures of the command package.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: cmdApi.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mainInt.h"
+#include "cmdInt.h"
+#include "abc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Cmd_CommandAdd( Abc_Frame_t * pAbc, char * sGroup, char * sName, void * pFunc, int fChanges )
+{
+ char * key, * value;
+ Abc_Command * pCommand;
+ int fStatus;
+
+ key = sName;
+ if ( st_delete( pAbc->tCommands, &key, &value ) )
+ {
+ // delete existing definition for this command
+ fprintf( pAbc->Err, "Cmd warning: redefining '%s'\n", sName );
+ CmdCommandFree( (Abc_Command *)value );
+ }
+
+ // create the new command
+ pCommand = ALLOC( Abc_Command, 1 );
+ pCommand->sName = util_strsav( sName );
+ pCommand->sGroup = util_strsav( sGroup );
+ pCommand->pFunc = pFunc;
+ pCommand->fChange = fChanges;
+ fStatus = st_insert( pAbc->tCommands, sName, (char *)pCommand );
+ assert( !fStatus ); // the command should not be in the table
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Cmd_CommandExecute( Abc_Frame_t * pAbc, char * sCommand )
+{
+ int fStatus = 0, argc, loop;
+ char * sCommandNext, **argv;
+
+ if ( !pAbc->fAutoexac )
+ Cmd_HistoryAddCommand(pAbc, sCommand);
+ sCommandNext = sCommand;
+ do
+ {
+ sCommandNext = CmdSplitLine( pAbc, sCommandNext, &argc, &argv );
+ loop = 0;
+ fStatus = CmdApplyAlias( pAbc, &argc, &argv, &loop );
+ if ( fStatus == 0 )
+ fStatus = CmdCommandDispatch( pAbc, argc, argv );
+ CmdFreeArgv( argc, argv );
+ }
+ while ( fStatus == 0 && *sCommandNext != '\0' );
+ return fStatus;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/cmd/cmdFlag.c b/src/base/cmd/cmdFlag.c
new file mode 100644
index 00000000..96f1f251
--- /dev/null
+++ b/src/base/cmd/cmdFlag.c
@@ -0,0 +1,112 @@
+/**CFile****************************************************************
+
+ FileName [cmdFlag.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Command processing package.]
+
+ Synopsis [Procedures working with flags.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: cmdFlag.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mainInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up value of flag in table of named values.]
+
+ Description [The command parser maintains a table of named values. These
+ are manipulated using the 'set' and 'unset' commands. The value of the
+ named flag is returned, or NIL(char) is returned if the flag has not been
+ set.]
+
+ SideEffects []
+
+******************************************************************************/
+char * Cmd_FlagReadByName( Abc_Frame_t * pAbc, char * flag )
+{
+ char *value;
+
+ if (st_lookup(pAbc->tFlags, flag, &value)) {
+ return value;
+ }
+ else {
+ return NIL(char);
+ }
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Updates a set value by calling instead of set command.]
+
+ Description [Updates a set value by calling instead of set command.]
+
+ SideEffects []
+
+******************************************************************************/
+void Cmd_FlagUpdateValue( Abc_Frame_t * pAbc, char * key, char * value )
+{
+ char *oldValue, *newValue;
+
+ if (!key)
+ return;
+ if (value)
+ newValue = util_strsav(value);
+ else
+ newValue = util_strsav("");
+
+ if (st_delete(pAbc->tFlags, &key, &oldValue))
+ FREE(oldValue);
+
+ st_insert(pAbc->tFlags, key, newValue);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Deletes a set value by calling instead of unset command.]
+
+ Description [Deletes a set value by calling instead of unset command.]
+
+ SideEffects []
+
+******************************************************************************/
+void Cmd_FlagDeleteByName( Abc_Frame_t * pAbc, char * key )
+{
+ char *value;
+
+ if (!key)
+ return;
+
+ if (st_delete(pAbc->tFlags, &key, &value)) {
+ FREE(key);
+ FREE(value);
+ }
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/cmd/cmdHist.c b/src/base/cmd/cmdHist.c
new file mode 100644
index 00000000..5b46ea00
--- /dev/null
+++ b/src/base/cmd/cmdHist.c
@@ -0,0 +1,55 @@
+/**CFile****************************************************************
+
+ FileName [cmdHist.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Command processing package.]
+
+ Synopsis [Procedures working with history.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: cmdHist.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mainInt.h"
+#include "cmd.h"
+#include "cmdInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Cmd_HistoryAddCommand( Abc_Frame_t * p, char * command )
+{
+ char Buffer[500];
+ strcpy( Buffer, command );
+ if ( command[strlen(command)-1] != '\n' )
+ strcat( Buffer, "\n" );
+ Vec_PtrPush( p->aHistory, util_strsav(Buffer) );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
diff --git a/src/base/cmd/cmdInt.h b/src/base/cmd/cmdInt.h
new file mode 100644
index 00000000..f0289ad4
--- /dev/null
+++ b/src/base/cmd/cmdInt.h
@@ -0,0 +1,82 @@
+/**CFile****************************************************************
+
+ FileName [cmdInt.h]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Command processing package.]
+
+ Synopsis [Internal declarations of the command package.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: cmdInt.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __CMD_INT_H__
+#define __CMD_INT_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+#include "mainInt.h"
+#include "cmd.h"
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+struct MvCommand
+{
+ char * sName; // the command name
+ char * sGroup; // the group name
+ void * pFunc; // the function to execute the command
+ int fChange; // set to 1 to mark that the network is changed
+};
+
+struct MvAlias
+{
+ char * sName; // the alias name
+ int argc; // the number of alias parts
+ char ** argv; // the alias parts
+};
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== cmdAlias.c =============-========================================*/
+extern void CmdCommandAliasAdd( Abc_Frame_t * pAbc, char * sName, int argc, char ** argv );
+extern void CmdCommandAliasPrint( Abc_Frame_t * pAbc, Abc_Alias * pAlias );
+extern char * CmdCommandAliasLookup( Abc_Frame_t * pAbc, char * sCommand );
+extern void CmdCommandAliasFree( Abc_Alias * p );
+/*=== cmdUtils.c =======================================================*/
+extern int CmdCommandDispatch( Abc_Frame_t * pAbc, int argc, char ** argv );
+extern char * CmdSplitLine( Abc_Frame_t * pAbc, char * sCommand, int * argc, char *** argv );
+extern int CmdApplyAlias( Abc_Frame_t * pAbc, int * argc, char *** argv, int * loop );
+extern char * CmdHistorySubstitution( Abc_Frame_t * pAbc, char * line, int * changed );
+extern FILE * CmdFileOpen( Abc_Frame_t * pAbc, char * sFileName, char * sMode, char ** pFileNameReal, int silent );
+extern void CmdFreeArgv( int argc, char ** argv );
+extern void CmdCommandFree( Abc_Command * pCommand );
+extern void CmdCommandPrint( Abc_Frame_t * pAbc, bool fPrintAll );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/src/base/cmd/cmdUtils.c b/src/base/cmd/cmdUtils.c
new file mode 100644
index 00000000..67a290a2
--- /dev/null
+++ b/src/base/cmd/cmdUtils.c
@@ -0,0 +1,598 @@
+/**CFile****************************************************************
+
+ FileName [cmdUtils.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Command processing package.]
+
+ Synopsis [Various utilities of the command package.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: cmdUtils.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mainInt.h"
+#include "abc.h"
+#include "cmdInt.h"
+#include <ctype.h> // proper declaration of isspace
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int CmdCommandPrintCompare( Abc_Command ** ppC1, Abc_Command ** ppC2 );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int cmdCheckShellEscape( Abc_Frame_t * pAbc, int argc, char ** argv)
+{
+ if (argv[0][0] == '!')
+ {
+ const int size = 4096;
+ int i;
+ char buffer[4096];
+ strncpy (buffer, &argv[0][1], size);
+ for (i = 1; i < argc; ++i)
+ {
+ strncat (buffer, " ", size);
+ strncat (buffer, argv[i], size);
+ }
+ if (buffer[0] == 0)
+ strncpy (buffer, "/bin/sh", size);
+ system (buffer);
+
+ // NOTE: Since we reconstruct the cmdline by concatenating
+ // the parts, we lose information. So a command like
+ // `!ls "file name"` will be sent to the system as
+ // `ls file name` which is a BUG
+
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Executes one command.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int CmdCommandDispatch( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ Abc_Ntk_t * pNetCopy;
+ int (*pFunc) ( Abc_Frame_t *, int, char ** );
+ Abc_Command * pCommand;
+ char * value;
+ int fError;
+ int clk;
+
+ if ( argc == 0 )
+ return 0;
+
+ if ( cmdCheckShellEscape( pAbc, argc, argv ) == 1 )
+ return 0;
+
+ // get the command
+ if ( !st_lookup( pAbc->tCommands, argv[0], (char **)&pCommand ) )
+ { // the command is not in the table
+ fprintf( pAbc->Err, "** cmd error: unknown command '%s'\n", argv[0] );
+ return 1;
+ }
+
+ // get the backup network if the command is going to change the network
+ if ( pCommand->fChange )
+ {
+ if ( pAbc->pNtkCur )
+ {
+ pNetCopy = Abc_NtkDup( pAbc->pNtkCur );
+ Abc_FrameSetCurrentNetwork( pAbc, pNetCopy );
+ // swap the current network and the backup network
+ // to prevent the effect of resetting the short names
+ Abc_FrameSwapCurrentAndBackup( pAbc );
+ }
+ }
+
+ // execute the command
+ clk = util_cpu_time();
+ pFunc = ( int (*)( Abc_Frame_t *, int, char ** ) ) pCommand->pFunc;
+ fError = (*pFunc)( pAbc, argc, argv );
+ pAbc->TimeCommand += (util_cpu_time() - clk);
+
+// if ( !fError && pCommand->fChange && pAbc->pNtkCur )
+// {
+// Cmd_HistoryAddSnapshot(pAbc, pAbc->pNet);
+// }
+
+ // automatic execution of arbitrary command after each command
+ // usually this is a passive command ...
+ if ( fError == 0 && !pAbc->fAutoexac )
+ {
+ if ( st_lookup( pAbc->tFlags, "autoexec", &value ) )
+ {
+ pAbc->fAutoexac = 1;
+ fError = Cmd_CommandExecute( pAbc, value );
+ pAbc->fAutoexac = 0;
+ }
+ }
+ return fError;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Splits the command line string into individual commands.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * CmdSplitLine( Abc_Frame_t * pAbc, char *sCommand, int *argc, char ***argv )
+{
+ char *p, *start, c;
+ int i, j;
+ char *new_arg;
+ Vec_Ptr_t * vArgs;
+ int single_quote, double_quote;
+
+ vArgs = Vec_PtrAlloc( 10 );
+
+ p = sCommand;
+ for ( ;; )
+ {
+ // skip leading white space
+ while ( isspace( ( int ) *p ) )
+ {
+ p++;
+ }
+
+ // skip until end of this token
+ single_quote = double_quote = 0;
+ for ( start = p; ( c = *p ) != '\0'; p++ )
+ {
+ if ( c == ';' || c == '#' || isspace( ( int ) c ) )
+ {
+ if ( !single_quote && !double_quote )
+ {
+ break;
+ }
+ }
+ if ( c == '\'' )
+ {
+ single_quote = !single_quote;
+ }
+ if ( c == '"' )
+ {
+ double_quote = !double_quote;
+ }
+ }
+ if ( single_quote || double_quote )
+ {
+ ( void ) fprintf( pAbc->Err, "** cmd warning: ignoring unbalanced quote ...\n" );
+ }
+ if ( start == p )
+ break;
+
+ new_arg = ALLOC( char, p - start + 1 );
+ j = 0;
+ for ( i = 0; i < p - start; i++ )
+ {
+ c = start[i];
+ if ( ( c != '\'' ) && ( c != '\"' ) )
+ {
+ new_arg[j++] = isspace( ( int ) c ) ? ' ' : start[i];
+ }
+ }
+ new_arg[j] = '\0';
+ Vec_PtrPush( vArgs, new_arg );
+ }
+
+ *argc = vArgs->nSize;
+ *argv = (char **)Vec_PtrReleaseArray( vArgs );
+ Vec_PtrFree( vArgs );
+ if ( *p == ';' )
+ {
+ p++;
+ }
+ else if ( *p == '#' )
+ {
+ for ( ; *p != 0; p++ ); // skip to end of line
+ }
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Replaces parts of the command line string by aliases if given.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int CmdApplyAlias( Abc_Frame_t * pAbc, int *argcp, char ***argvp, int *loop )
+{
+ int i, argc, stopit, added, offset, did_subst, subst, fError, newc, j;
+ char *arg, **argv, **newv;
+ Abc_Alias *alias;
+
+ argc = *argcp;
+ argv = *argvp;
+ stopit = 0;
+ for ( ; *loop < 20; ( *loop )++ )
+ {
+ if ( argc == 0 )
+ return 0;
+ if ( stopit != 0 || st_lookup( pAbc->tAliases, argv[0], (char **) &alias ) == 0 )
+ {
+ return 0;
+ }
+ if ( strcmp( argv[0], alias->argv[0] ) == 0 )
+ {
+ stopit = 1;
+ }
+ FREE( argv[0] );
+ added = alias->argc - 1;
+
+ /* shift all the arguments to the right */
+ if ( added != 0 )
+ {
+ argv = REALLOC( char *, argv, argc + added );
+ for ( i = argc - 1; i >= 1; i-- )
+ {
+ argv[i + added] = argv[i];
+ }
+ for ( i = 1; i <= added; i++ )
+ {
+ argv[i] = NIL( char );
+ }
+ argc += added;
+ }
+ subst = 0;
+ for ( i = 0, offset = 0; i < alias->argc; i++, offset++ )
+ {
+ arg = CmdHistorySubstitution( pAbc, alias->argv[i], &did_subst );
+ if ( arg == NIL( char ) )
+ {
+ *argcp = argc;
+ *argvp = argv;
+ return ( 1 );
+ }
+ if ( did_subst != 0 )
+ {
+ subst = 1;
+ }
+ fError = 0;
+ do
+ {
+ arg = CmdSplitLine( pAbc, arg, &newc, &newv );
+ /*
+ * If there's a complete `;' terminated command in `arg',
+ * when split_line() returns arg[0] != '\0'.
+ */
+ if ( arg[0] == '\0' )
+ { /* just a bunch of words */
+ break;
+ }
+ fError = CmdApplyAlias( pAbc, &newc, &newv, loop );
+ if ( fError == 0 )
+ {
+ fError = CmdCommandDispatch( pAbc, newc, newv );
+ }
+ CmdFreeArgv( newc, newv );
+ }
+ while ( fError == 0 );
+ if ( fError != 0 )
+ {
+ *argcp = argc;
+ *argvp = argv;
+ return ( 1 );
+ }
+ added = newc - 1;
+ if ( added != 0 )
+ {
+ argv = REALLOC( char *, argv, argc + added );
+ for ( j = argc - 1; j > offset; j-- )
+ {
+ argv[j + added] = argv[j];
+ }
+ argc += added;
+ }
+ for ( j = 0; j <= added; j++ )
+ {
+ argv[j + offset] = newv[j];
+ }
+ FREE( newv );
+ offset += added;
+ }
+ if ( subst == 1 )
+ {
+ for ( i = offset; i < argc; i++ )
+ {
+ FREE( argv[i] );
+ }
+ argc = offset;
+ }
+ *argcp = argc;
+ *argvp = argv;
+ }
+
+ fprintf( pAbc->Err, "** cmd warning: alias loop\n" );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs history substitution (now, disabled).]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * CmdHistorySubstitution( Abc_Frame_t * pAbc, char *line, int *changed )
+{
+ // as of today, no history substitution
+ *changed = 0;
+ return line;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Opens the file with path (now, disabled).]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+FILE * CmdFileOpen( Abc_Frame_t * pAbc, char *sFileName, char *sMode, char **pFileNameReal, int silent )
+{
+ char * sRealName, * sPathUsr, * sPathLib, * sPathAll;
+ FILE * pFile;
+
+ if (strcmp(sFileName, "-") == 0) {
+ if (strcmp(sMode, "w") == 0) {
+ sRealName = util_strsav( "stdout" );
+ pFile = stdout;
+ }
+ else {
+ sRealName = util_strsav( "stdin" );
+ pFile = stdin;
+ }
+ }
+ else {
+ sRealName = NULL;
+ if (strcmp(sMode, "r") == 0) {
+
+ /* combine both pathes if exist */
+ sPathUsr = Cmd_FlagReadByName(pAbc,"open_path");
+ sPathLib = Cmd_FlagReadByName(pAbc,"lib_path");
+
+ if ( sPathUsr == NULL && sPathLib == NULL ) {
+ sPathAll = NULL;
+ }
+ else if ( sPathUsr == NULL ) {
+ sPathAll = util_strsav( sPathLib );
+ }
+ else if ( sPathLib == NULL ) {
+ sPathAll = util_strsav( sPathUsr );
+ }
+ else {
+ sPathAll = ALLOC( char, strlen(sPathLib)+strlen(sPathUsr)+5 );
+ sprintf( sPathAll, "%s:%s",sPathUsr, sPathLib );
+ }
+ if ( sPathAll != NIL(char) ) {
+ sRealName = util_file_search(sFileName, sPathAll, "r");
+ FREE( sPathAll );
+ }
+ }
+ if (sRealName == NIL(char)) {
+ sRealName = util_tilde_expand(sFileName);
+ }
+ if ((pFile = fopen(sRealName, sMode)) == NIL(FILE)) {
+ if (! silent) {
+ perror(sRealName);
+ }
+ }
+ }
+ if ( pFileNameReal )
+ *pFileNameReal = sRealName;
+ else
+ FREE(sRealName);
+
+ return pFile;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Frees the previously allocated argv array.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void CmdFreeArgv( int argc, char **argv )
+{
+ int i;
+ for ( i = 0; i < argc; i++ )
+ FREE( argv[i] );
+ FREE( argv );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Frees the previously allocated command.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void CmdCommandFree( Abc_Command * pCommand )
+{
+ free( pCommand->sGroup );
+ free( pCommand->sName );
+ free( pCommand );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Prints commands alphabetically by group.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void CmdCommandPrint( Abc_Frame_t * pAbc, bool fPrintAll )
+{
+ char *key, *value;
+ st_generator * gen;
+ Abc_Command ** ppCommands;
+ Abc_Command * pCommands;
+ int nCommands, i;
+ char * sGroupCur;
+ int LenghtMax, nColumns, iCom = 0;
+
+ // put all commands into one array
+ nCommands = st_count( pAbc->tCommands );
+ ppCommands = ALLOC( Abc_Command *, nCommands );
+ i = 0;
+ st_foreach_item( pAbc->tCommands, gen, &key, &value )
+ {
+ pCommands = (Abc_Command *)value;
+ if ( fPrintAll || pCommands->sName[0] != '_' )
+ ppCommands[i++] = pCommands;
+ }
+ nCommands = i;
+
+ // sort command by group and then by name, alphabetically
+ qsort( (void *)ppCommands, nCommands, sizeof(Abc_Command *),
+ (int (*)(const void *, const void *)) CmdCommandPrintCompare );
+ assert( CmdCommandPrintCompare( ppCommands, ppCommands + nCommands - 1 ) <= 0 );
+
+ // get the longest command name
+ LenghtMax = 0;
+ for ( i = 0; i < nCommands; i++ )
+ if ( LenghtMax < (int)strlen(ppCommands[i]->sName) )
+ LenghtMax = (int)strlen(ppCommands[i]->sName);
+ // get the number of columns
+ nColumns = 79 / (LenghtMax + 2);
+
+ // print the starting message
+ fprintf( pAbc->Out, " Welcome to ABC!" );
+
+ // print the command by group
+ sGroupCur = NULL;
+ for ( i = 0; i < nCommands; i++ )
+ if ( sGroupCur && strcmp( sGroupCur, ppCommands[i]->sGroup ) == 0 )
+ { // this command belongs to the same group as the previous one
+ if ( iCom++ % nColumns == 0 )
+ fprintf( pAbc->Out, "\n" );
+ // print this command
+ fprintf( pAbc->Out, " %-*s", LenghtMax, ppCommands[i]->sName );
+ }
+ else
+ { // this command starts the new group of commands
+ // start the new group
+ fprintf( pAbc->Out, "\n" );
+ fprintf( pAbc->Out, "\n" );
+ fprintf( pAbc->Out, "%s commands:\n", ppCommands[i]->sGroup );
+ // print this command
+ fprintf( pAbc->Out, " %-*s", LenghtMax, ppCommands[i]->sName );
+ // remember current command group
+ sGroupCur = ppCommands[i]->sGroup;
+ // reset the command counter
+ iCom = 1;
+ }
+ fprintf( pAbc->Out, "\n" );
+ FREE( ppCommands );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Comparision function used for sorting commands.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int CmdCommandPrintCompare( Abc_Command ** ppC1, Abc_Command ** ppC2 )
+{
+ Abc_Command * pC1 = *ppC1;
+ Abc_Command * pC2 = *ppC2;
+ int RetValue;
+
+ RetValue = strcmp( pC1->sGroup, pC2->sGroup );
+ if ( RetValue < 0 )
+ return -1;
+ if ( RetValue > 0 )
+ return 1;
+ // the command belong to the same group
+
+ // put commands with "_" at the end of the list
+ if ( pC1->sName[0] != '_' && pC2->sName[0] == '_' )
+ return -1;
+ if ( pC1->sName[0] == '_' && pC2->sName[0] != '_' )
+ return 1;
+
+ RetValue = strcmp( pC1->sName, pC2->sName );
+ if ( RetValue < 0 )
+ return -1;
+ if ( RetValue > 0 )
+ return 1;
+ // should not be two indentical commands
+ assert( 0 );
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
diff --git a/src/base/cmd/module.make b/src/base/cmd/module.make
new file mode 100644
index 00000000..1eca3f65
--- /dev/null
+++ b/src/base/cmd/module.make
@@ -0,0 +1,6 @@
+SRC += src/base/cmd/cmd.c \
+ src/base/cmd/cmdAlias.c \
+ src/base/cmd/cmdApi.c \
+ src/base/cmd/cmdFlag.c \
+ src/base/cmd/cmdHist.c \
+ src/base/cmd/cmdUtils.c
diff --git a/src/base/io/io.c b/src/base/io/io.c
new file mode 100644
index 00000000..4698de91
--- /dev/null
+++ b/src/base/io/io.c
@@ -0,0 +1,766 @@
+/**CFile****************************************************************
+
+ FileName [io.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Command processing package.]
+
+ Synopsis [Command file.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: io.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "io.h"
+#include "mainInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int IoCommandRead ( Abc_Frame_t * pAbc, int argc, char **argv );
+static int IoCommandReadBlif ( Abc_Frame_t * pAbc, int argc, char **argv );
+static int IoCommandReadBench ( Abc_Frame_t * pAbc, int argc, char **argv );
+static int IoCommandReadVerilog ( Abc_Frame_t * pAbc, int argc, char **argv );
+static int IoCommandReadPla ( Abc_Frame_t * pAbc, int argc, char **argv );
+
+static int IoCommandWriteBlif ( Abc_Frame_t * pAbc, int argc, char **argv );
+static int IoCommandWriteGate ( Abc_Frame_t * pAbc, int argc, char **argv );
+static int IoCommandWriteBench ( Abc_Frame_t * pAbc, int argc, char **argv );
+static int IoCommandWriteCnf ( Abc_Frame_t * pAbc, int argc, char **argv );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_Init( Abc_Frame_t * pAbc )
+{
+ Cmd_CommandAdd( pAbc, "I/O", "read", IoCommandRead, 1 );
+ Cmd_CommandAdd( pAbc, "I/O", "read_blif", IoCommandReadBlif, 1 );
+ Cmd_CommandAdd( pAbc, "I/O", "read_bench", IoCommandReadBench, 1 );
+ Cmd_CommandAdd( pAbc, "I/O", "read_verilog", IoCommandReadVerilog, 1 );
+ Cmd_CommandAdd( pAbc, "I/O", "read_pla", IoCommandReadPla, 1 );
+
+ Cmd_CommandAdd( pAbc, "I/O", "write_blif", IoCommandWriteBlif, 0 );
+ Cmd_CommandAdd( pAbc, "I/O", "write_gate", IoCommandWriteGate, 0 );
+ Cmd_CommandAdd( pAbc, "I/O", "write_bench", IoCommandWriteBench, 0 );
+ Cmd_CommandAdd( pAbc, "I/O", "write_cnf", IoCommandWriteCnf, 0 );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_End()
+{
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int IoCommandRead( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ Abc_Ntk_t * pNtk;
+ char * FileName;
+ FILE * pFile;
+ int fCheck;
+ int c;
+
+ fCheck = 1;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "ch" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'c':
+ fCheck ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( argc != util_optind + 1 )
+ {
+ goto usage;
+ }
+
+ // get the input file name
+ FileName = argv[util_optind];
+ if ( (pFile = fopen( FileName, "r" )) == NULL )
+ {
+ fprintf( pAbc->Err, "Cannot open input file \"%s\". ", FileName );
+ if ( FileName = Extra_FileGetSimilarName( FileName, ".mv", ".blif", ".pla", ".mvpla", NULL ) )
+ fprintf( pAbc->Err, "Did you mean \"%s\"?", FileName );
+ fprintf( pAbc->Err, "\n" );
+ return 1;
+ }
+ fclose( pFile );
+
+ // set the new network
+ pNtk = Io_Read( FileName, fCheck );
+ if ( pNtk == NULL )
+ {
+ fprintf( pAbc->Err, "Reading network from file has failed.\n" );
+ return 1;
+ }
+ // replace the current network
+ Abc_FrameReplaceCurrentNetwork( pAbc, pNtk );
+ return 0;
+
+usage:
+ fprintf( pAbc->Err, "usage: read [-ch] <file>\n" );
+ fprintf( pAbc->Err, "\t read the network from file in Verilog/BLIF/BENCH format\n" );
+ fprintf( pAbc->Err, "\t-c : toggle network check after reading [default = %s]\n", fCheck? "yes":"no" );
+ fprintf( pAbc->Err, "\t-h : prints the command summary\n" );
+ fprintf( pAbc->Err, "\tfile : the name of a file to read\n" );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int IoCommandReadBlif( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ Abc_Ntk_t * pNtk, * pTemp;
+ char * FileName;
+ FILE * pFile;
+ int fCheck;
+ int c;
+
+ fCheck = 1;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "ch" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'c':
+ fCheck ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( argc != util_optind + 1 )
+ {
+ goto usage;
+ }
+
+ // get the input file name
+ FileName = argv[util_optind];
+ if ( (pFile = fopen( FileName, "r" )) == NULL )
+ {
+ fprintf( pAbc->Err, "Cannot open input file \"%s\". ", FileName );
+ if ( FileName = Extra_FileGetSimilarName( FileName, ".mv", ".blif", ".pla", ".mvpla", NULL ) )
+ fprintf( pAbc->Err, "Did you mean \"%s\"?", FileName );
+ fprintf( pAbc->Err, "\n" );
+ return 1;
+ }
+ fclose( pFile );
+
+ // set the new network
+ pNtk = Io_ReadBlif( FileName, fCheck );
+ if ( pNtk == NULL )
+ {
+ fprintf( pAbc->Err, "Reading network from BLIF file has failed.\n" );
+ return 1;
+ }
+
+ pNtk = Abc_NtkLogic( pTemp = pNtk );
+ Abc_NtkDelete( pTemp );
+ if ( pNtk == NULL )
+ {
+ fprintf( pAbc->Err, "Converting to logic network after reading has failed.\n" );
+ return 1;
+ }
+
+ // replace the current network
+ Abc_FrameReplaceCurrentNetwork( pAbc, pNtk );
+ return 0;
+
+usage:
+ fprintf( pAbc->Err, "usage: read_blif [-ch] <file>\n" );
+ fprintf( pAbc->Err, "\t read the network in binary BLIF format\n" );
+ fprintf( pAbc->Err, "\t-c : toggle network check after reading [default = %s]\n", fCheck? "yes":"no" );
+ fprintf( pAbc->Err, "\t-h : prints the command summary\n" );
+ fprintf( pAbc->Err, "\tfile : the name of a file to read\n" );
+ return 1;
+}
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int IoCommandReadBench( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ Abc_Ntk_t * pNtk, * pTemp;
+ char * FileName;
+ FILE * pFile;
+ int fCheck;
+ int c;
+
+ fCheck = 1;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "ch" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'c':
+ fCheck ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( argc != util_optind + 1 )
+ {
+ goto usage;
+ }
+
+ // get the input file name
+ FileName = argv[util_optind];
+ if ( (pFile = fopen( FileName, "r" )) == NULL )
+ {
+ fprintf( pAbc->Err, "Cannot open input file \"%s\". ", FileName );
+ if ( FileName = Extra_FileGetSimilarName( FileName, ".mv", ".blif", ".pla", ".mvpla", NULL ) )
+ fprintf( pAbc->Err, "Did you mean \"%s\"?", FileName );
+ fprintf( pAbc->Err, "\n" );
+ return 1;
+ }
+ fclose( pFile );
+
+ // set the new network
+ pNtk = Io_ReadBench( FileName, fCheck );
+ if ( pNtk == NULL )
+ {
+ fprintf( pAbc->Err, "Reading network from BENCH file has failed.\n" );
+ return 1;
+ }
+
+ pNtk = Abc_NtkLogic( pTemp = pNtk );
+ Abc_NtkDelete( pTemp );
+ if ( pNtk == NULL )
+ {
+ fprintf( pAbc->Err, "Converting to logic network after reading has failed.\n" );
+ return 1;
+ }
+ // replace the current network
+ Abc_FrameReplaceCurrentNetwork( pAbc, pNtk );
+ return 0;
+
+usage:
+ fprintf( pAbc->Err, "usage: read_bench [-ch] <file>\n" );
+ fprintf( pAbc->Err, "\t read the network in BENCH format\n" );
+ fprintf( pAbc->Err, "\t-c : toggle network check after reading [default = %s]\n", fCheck? "yes":"no" );
+ fprintf( pAbc->Err, "\t-h : prints the command summary\n" );
+ fprintf( pAbc->Err, "\tfile : the name of a file to read\n" );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int IoCommandReadVerilog( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ Abc_Ntk_t * pNtk, * pTemp;
+ char * FileName;
+ FILE * pFile;
+ int fCheck;
+ int c;
+
+ fCheck = 1;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "ch" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'c':
+ fCheck ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( argc != util_optind + 1 )
+ {
+ goto usage;
+ }
+
+ // get the input file name
+ FileName = argv[util_optind];
+ if ( (pFile = fopen( FileName, "r" )) == NULL )
+ {
+ fprintf( pAbc->Err, "Cannot open input file \"%s\". ", FileName );
+ if ( FileName = Extra_FileGetSimilarName( FileName, ".mv", ".blif", ".pla", ".mvpla", NULL ) )
+ fprintf( pAbc->Err, "Did you mean \"%s\"?", FileName );
+ fprintf( pAbc->Err, "\n" );
+ return 1;
+ }
+ fclose( pFile );
+
+ // set the new network
+ pNtk = Io_ReadVerilog( FileName, fCheck );
+ if ( pNtk == NULL )
+ {
+ fprintf( pAbc->Err, "Reading network from Verilog file has failed.\n" );
+ return 1;
+ }
+
+ pNtk = Abc_NtkLogic( pTemp = pNtk );
+ Abc_NtkDelete( pTemp );
+ if ( pNtk == NULL )
+ {
+ fprintf( pAbc->Err, "Converting to logic network after reading has failed.\n" );
+ return 1;
+ }
+ // replace the current network
+ Abc_FrameReplaceCurrentNetwork( pAbc, pNtk );
+ return 0;
+
+usage:
+ fprintf( pAbc->Err, "usage: read_verilog [-ch] <file>\n" );
+ fprintf( pAbc->Err, "\t read the network in Verilog (IWLS 2005 subset)\n" );
+ fprintf( pAbc->Err, "\t-c : toggle network check after reading [default = %s]\n", fCheck? "yes":"no" );
+ fprintf( pAbc->Err, "\t-h : prints the command summary\n" );
+ fprintf( pAbc->Err, "\tfile : the name of a file to read\n" );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int IoCommandReadPla( Abc_Frame_t * pAbc, int argc, char ** argv )
+{
+ Abc_Ntk_t * pNtk, * pTemp;
+ char * FileName;
+ FILE * pFile;
+ int fCheck;
+ int c;
+
+ fCheck = 1;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "ch" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'c':
+ fCheck ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( argc != util_optind + 1 )
+ {
+ goto usage;
+ }
+
+ // get the input file name
+ FileName = argv[util_optind];
+ if ( (pFile = fopen( FileName, "r" )) == NULL )
+ {
+ fprintf( pAbc->Err, "Cannot open input file \"%s\". ", FileName );
+ if ( FileName = Extra_FileGetSimilarName( FileName, ".mv", ".blif", ".pla", ".mvpla", NULL ) )
+ fprintf( pAbc->Err, "Did you mean \"%s\"?", FileName );
+ fprintf( pAbc->Err, "\n" );
+ return 1;
+ }
+ fclose( pFile );
+
+ // set the new network
+// pNtk = Io_ReadPla( FileName, fCheck );
+ fprintf( pAbc->Err, "This command is currently not implemented.\n" );
+ pNtk = NULL;
+ if ( pNtk == NULL )
+ {
+ fprintf( pAbc->Err, "Reading network from PLA file has failed.\n" );
+ return 1;
+ }
+
+ pNtk = Abc_NtkLogic( pTemp = pNtk );
+ Abc_NtkDelete( pTemp );
+ if ( pNtk == NULL )
+ {
+ fprintf( pAbc->Err, "Converting to logic network after reading has failed.\n" );
+ return 1;
+ }
+ // replace the current network
+ Abc_FrameReplaceCurrentNetwork( pAbc, pNtk );
+ return 0;
+
+usage:
+ fprintf( pAbc->Err, "usage: read_pla [-ch] <file>\n" );
+ fprintf( pAbc->Err, "\t read the network in PLA\n" );
+ fprintf( pAbc->Err, "\t-c : toggle network check after reading [default = %s]\n", fCheck? "yes":"no" );
+ fprintf( pAbc->Err, "\t-h : prints the command summary\n" );
+ fprintf( pAbc->Err, "\tfile : the name of a file to read\n" );
+ return 1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int IoCommandWriteBlif( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ char * FileName;
+ int fMadeComb;
+ int fWriteLatches;
+ int c;
+
+ fWriteLatches = 1;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "lh" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'l':
+ fWriteLatches ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pAbc->pNtkCur == NULL )
+ {
+ fprintf( pAbc->Out, "Empty network.\n" );
+ return 0;
+ }
+
+ if ( argc != util_optind + 1 )
+ {
+ goto usage;
+ }
+
+ if ( Abc_NtkIsLogicMap(pAbc->pNtkCur) )
+ {
+ fprintf( pAbc->Out, "Use \"write_gate\" or unmap the network (\"unmap\").\n" );
+ return 1;
+ }
+
+ // get the input file name
+ FileName = argv[util_optind];
+ // write the file
+ if ( Abc_NtkIsNetlist(pAbc->pNtkCur) )
+ {
+ if ( !fWriteLatches )
+ fMadeComb = Abc_NtkMakeComb( pAbc->pNtkCur );
+ Io_WriteBlif( pAbc->pNtkCur, FileName );
+ if ( !fWriteLatches && fMadeComb )
+ Abc_NtkMakeSeq( pAbc->pNtkCur );
+ }
+ else if ( Abc_NtkIsLogicSop(pAbc->pNtkCur) || Abc_NtkIsAig(pAbc->pNtkCur) )
+ {
+ Io_WriteBlifLogic( pAbc->pNtkCur, FileName, fWriteLatches );
+ }
+ else if ( Abc_NtkIsLogicBdd(pAbc->pNtkCur) )
+ {
+// printf( "Converting node functions from BDD to SOP.\n" );
+ Abc_NtkBddToSop(pAbc->pNtkCur);
+ Io_WriteBlifLogic( pAbc->pNtkCur, FileName, fWriteLatches );
+ }
+ else
+ {
+ assert( 0 );
+ }
+ return 0;
+
+usage:
+ fprintf( pAbc->Err, "usage: write_blif [-lh] <file>\n" );
+ fprintf( pAbc->Err, "\t write the network into a BLIF file\n" );
+ fprintf( pAbc->Err, "\t-l : toggle writing latches [default = %s]\n", fWriteLatches? "yes":"no" );
+ fprintf( pAbc->Err, "\t-h : print the help massage\n" );
+ fprintf( pAbc->Err, "\tfile : the name of the file to write\n" );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int IoCommandWriteGate( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ Abc_Ntk_t * pNtk;
+ char * FileName;
+ int fWriteLatches;
+ int c;
+
+ pNtk = pAbc->pNtkCur;
+ fWriteLatches = 1;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "lh" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'l':
+ fWriteLatches ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pAbc->Out, "Empty network.\n" );
+ return 0;
+ }
+
+ if ( !Abc_NtkIsLogicMap(pNtk) )
+ {
+ fprintf( pAbc->Out, "The network is not mapped.\n" );
+ return 0;
+ }
+/*
+ if ( Abc_NtkLatchNum(pNtk) > 0 )
+ {
+ fprintf( pAbc->Out, "The network has latches.\n" );
+ return 0;
+ }
+*/
+ if ( argc != util_optind + 1 )
+ {
+ goto usage;
+ }
+
+ // get the input file name
+ FileName = argv[util_optind];
+ // write the file
+ Io_WriteGate( pNtk, FileName );
+ return 0;
+
+usage:
+ fprintf( pAbc->Err, "usage: write_gate [-h] <file>\n" );
+ fprintf( pAbc->Err, "\t write the network into a mapped BLIF file (.gate ...)\n" );
+// fprintf( pAbc->Err, "\t-l : toggle writing latches [default = %s]\n", fWriteLatches? "yes":"no" );
+ fprintf( pAbc->Err, "\t-h : print the help massage\n" );
+ fprintf( pAbc->Err, "\tfile : the name of the file to write\n" );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int IoCommandWriteBench( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ Abc_Ntk_t * pNtk;
+ char * FileName;
+ int fWriteLatches;
+ int c;
+
+ pNtk = pAbc->pNtkCur;
+ fWriteLatches = 1;
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "lh" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'l':
+ fWriteLatches ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pNtk == NULL )
+ {
+ fprintf( pAbc->Out, "Empty network.\n" );
+ return 0;
+ }
+
+ if ( !Abc_NtkIsAig(pNtk) )
+ {
+ fprintf( pAbc->Out, "The network should be an AIG.\n" );
+ return 0;
+ }
+
+ if ( argc != util_optind + 1 )
+ {
+ goto usage;
+ }
+
+ // get the input file name
+ FileName = argv[util_optind];
+ // write the file
+ Io_WriteBench( pNtk, FileName );
+ return 0;
+
+usage:
+ fprintf( pAbc->Err, "usage: write_bench [-h] <file>\n" );
+ fprintf( pAbc->Err, "\t write the network in BENCH format\n" );
+// fprintf( pAbc->Err, "\t-l : toggle writing latches [default = %s]\n", fWriteLatches? "yes":"no" );
+ fprintf( pAbc->Err, "\t-h : print the help massage\n" );
+ fprintf( pAbc->Err, "\tfile : the name of the file to write\n" );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int IoCommandWriteCnf( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ char * FileName;
+ int c;
+
+ util_getopt_reset();
+ while ( ( c = util_getopt( argc, argv, "h" ) ) != EOF )
+ {
+ switch ( c )
+ {
+ case 'h':
+ goto usage;
+ default:
+ goto usage;
+ }
+ }
+
+ if ( pAbc->pNtkCur == NULL )
+ {
+ fprintf( pAbc->Out, "Empty network.\n" );
+ return 0;
+ }
+
+ if ( argc != util_optind + 1 )
+ {
+ goto usage;
+ }
+
+ // get the input file name
+ FileName = argv[util_optind];
+ // write the file
+ if ( !Io_WriteCnf( pAbc->pNtkCur, FileName ) )
+ {
+ printf( "Writing CNF has failed.\n" );
+ return 1;
+ }
+ return 0;
+
+usage:
+ fprintf( pAbc->Err, "usage: write_cnf [-h] <file>\n" );
+ fprintf( pAbc->Err, "\t write the miter cone into a CNF file\n" );
+ fprintf( pAbc->Err, "\t-h : print the help massage\n" );
+ fprintf( pAbc->Err, "\tfile : the name of the file to write\n" );
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/io/io.h b/src/base/io/io.h
new file mode 100644
index 00000000..ba61faac
--- /dev/null
+++ b/src/base/io/io.h
@@ -0,0 +1,74 @@
+/**CFile****************************************************************
+
+ FileName [io.h]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Command processing package.]
+
+ Synopsis [External declarations.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: io.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __IO_H__
+#define __IO_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+#include "abc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// BASIC TYPES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+#define IO_WRITE_LINE_LENGTH 78 // the output line length
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== abcRead.c ==========================================================*/
+extern Abc_Ntk_t * Io_Read( char * pFileName, int fCheck );
+/*=== abcReadBlif.c ==========================================================*/
+extern Abc_Ntk_t * Io_ReadBlif( char * pFileName, int fCheck );
+/*=== abcReadBench.c ==========================================================*/
+extern Abc_Ntk_t * Io_ReadBench( char * pFileName, int fCheck );
+/*=== abcReadVerilog.c ==========================================================*/
+extern Abc_Ntk_t * Io_ReadVerilog( char * pFileName, int fCheck );
+extern void Io_ReadSetNonDrivenNets( Abc_Ntk_t * pNet );
+/*=== abcWriteBlif.c ==========================================================*/
+extern void Io_WriteBlif( Abc_Ntk_t * pNtk, char * pFileName );
+extern void Io_WriteTimingInfo( FILE * pFile, Abc_Ntk_t * pNtk );
+/*=== abcWriteBlifLogic.c ==========================================================*/
+extern void Io_WriteBlifLogic( Abc_Ntk_t * pNtk, char * pFileName, int fWriteLatches );
+/*=== abcWriteBench.c ==========================================================*/
+extern int Io_WriteBench( Abc_Ntk_t * pNtk, char * FileName );
+/*=== abcWriteGate.c ==========================================================*/
+extern int Io_WriteGate( Abc_Ntk_t * pNtk, char * FileName );
+/*=== abcWriteCnf.c ==========================================================*/
+extern int Io_WriteCnf( Abc_Ntk_t * pNtk, char * FileName );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/src/base/io/ioInt.h b/src/base/io/ioInt.h
new file mode 100644
index 00000000..69d125fc
--- /dev/null
+++ b/src/base/io/ioInt.h
@@ -0,0 +1,49 @@
+/**CFile****************************************************************
+
+ FileName [ioInt.h]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Command processing package.]
+
+ Synopsis [External declarations.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: ioInt.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __IO_INT_H__
+#define __IO_INT_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// BASIC TYPES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/src/base/io/ioRead.c b/src/base/io/ioRead.c
new file mode 100644
index 00000000..18e4b153
--- /dev/null
+++ b/src/base/io/ioRead.c
@@ -0,0 +1,74 @@
+/**CFile****************************************************************
+
+ FileName [ioRead.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Command processing package.]
+
+ Synopsis [Procedure to read network from file.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: ioRead.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "io.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Read the network from a file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Io_Read( char * pFileName, int fCheck )
+{
+ Abc_Ntk_t * pNtk, * pTemp;
+ // set the new network
+ if ( Extra_FileNameCheckExtension( pFileName, "blif" ) )
+ pNtk = Io_ReadBlif( pFileName, fCheck );
+ else if ( Extra_FileNameCheckExtension( pFileName, "v" ) )
+ pNtk = Io_ReadVerilog( pFileName, fCheck );
+ else if ( Extra_FileNameCheckExtension( pFileName, "bench" ) )
+ pNtk = Io_ReadBench( pFileName, fCheck );
+ else
+ {
+ fprintf( stderr, "Unknown file format\n" );
+ return NULL;
+ }
+ if ( pNtk == NULL )
+ return NULL;
+ pNtk = Abc_NtkLogic( pTemp = pNtk );
+ Abc_NtkDelete( pTemp );
+ if ( pNtk == NULL )
+ {
+ fprintf( stdout, "Converting to logic network after reading has failed.\n" );
+ return NULL;
+ }
+ return pNtk;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
+
diff --git a/src/base/io/ioReadBench.c b/src/base/io/ioReadBench.c
new file mode 100644
index 00000000..0660adc7
--- /dev/null
+++ b/src/base/io/ioReadBench.c
@@ -0,0 +1,227 @@
+/**CFile****************************************************************
+
+ FileName [ioReadBench.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Command processing package.]
+
+ Synopsis [Procedures to read BENCH files.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: ioReadBench.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "io.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static Abc_Ntk_t * Io_ReadBenchNetwork( Extra_FileReader_t * p );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Read the network from BENCH file.]
+
+ Description [Currently works only for the miter cone.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Io_ReadBench( char * pFileName, int fCheck )
+{
+ Extra_FileReader_t * p;
+ Abc_Ntk_t * pNtk;
+
+ // start the file
+ p = Extra_FileReaderAlloc( pFileName, "#", "\n", " \t\r,()=" );
+ if ( p == NULL )
+ return NULL;
+
+ // read the network
+ pNtk = Io_ReadBenchNetwork( p );
+ Extra_FileReaderFree( p );
+ if ( pNtk == NULL )
+ return NULL;
+
+ // make sure that everything is okay with the network structure
+ if ( fCheck && !Abc_NtkCheck( pNtk ) )
+ {
+ printf( "Io_ReadBench: The network check has failed.\n" );
+ Abc_NtkDelete( pNtk );
+ return NULL;
+ }
+ return pNtk;
+}
+/**Function*************************************************************
+
+ Synopsis [Read the network from BENCH file.]
+
+ Description [Currently works only for the miter cone.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Io_ReadBenchNetwork( Extra_FileReader_t * p )
+{
+ ProgressBar * pProgress;
+ Vec_Ptr_t * vTokens;
+ Abc_Ntk_t * pNtk;
+ Abc_Obj_t * pNet, * pLatch, * pNode;
+ Vec_Str_t * vString;
+ char * pType;
+ int SymbolIn, SymbolOut, i, iLine;
+
+ // allocate the empty network
+ pNtk = Abc_NtkAlloc( ABC_NTK_NETLIST );
+
+ // set the specs
+ pNtk->pName = util_strsav( Extra_FileReaderGetFileName(p) );
+ pNtk->pSpec = util_strsav( Extra_FileReaderGetFileName(p) );
+
+ // go through the lines of the file
+ vString = Vec_StrAlloc( 100 );
+ pProgress = Extra_ProgressBarStart( stdout, Extra_FileReaderGetFileSize(p) );
+ for ( iLine = 0; vTokens = Extra_FileReaderGetTokens(p); iLine++ )
+ {
+ Extra_ProgressBarUpdate( pProgress, Extra_FileReaderGetCurPosition(p), NULL );
+
+ if ( vTokens->nSize == 1 )
+ {
+ printf( "%s: Wrong input file format.\n", Extra_FileReaderGetFileName(p) );
+ Abc_NtkDelete( pNtk );
+ return NULL;
+ }
+
+ // get the type of the line
+ if ( strncmp( vTokens->pArray[0], "INPUT", 5 ) == 0 )
+ {
+ pNet = Abc_NtkFindOrCreateNet( pNtk, vTokens->pArray[1] );
+ if ( Abc_ObjIsPi(pNet) )
+ printf( "Warning: PI net \"%s\" appears twice in the list.\n", vTokens->pArray[1] );
+ else
+ Abc_NtkMarkNetPi( pNet );
+ }
+ else if ( strncmp( vTokens->pArray[0], "OUTPUT", 5 ) == 0 )
+ {
+ pNet = Abc_NtkFindOrCreateNet( pNtk, vTokens->pArray[1] );
+ if ( Abc_ObjIsPo(pNet) )
+ printf( "Warning: PO net \"%s\" appears twice in the list.\n", vTokens->pArray[1] );
+ else
+ Abc_NtkMarkNetPo( pNet );
+ }
+ else
+ {
+ // get the node name and the node type
+ pType = vTokens->pArray[1];
+ if ( strcmp(pType, "DFF") == 0 )
+ {
+ // create a new node and add it to the network
+ pLatch = Abc_NtkCreateLatch( pNtk );
+ // create the LO (PI)
+ pNet = Abc_NtkFindOrCreateNet( pNtk, vTokens->pArray[0] );
+ Abc_ObjAddFanin( pNet, pLatch );
+ Abc_ObjSetSubtype( pNet, ABC_OBJ_SUBTYPE_LO );
+ // save the LI (PO)
+ pNet = Abc_NtkFindOrCreateNet( pNtk, vTokens->pArray[2] );
+ Abc_ObjAddFanin( pLatch, pNet );
+ Abc_ObjSetSubtype( pNet, ABC_OBJ_SUBTYPE_LI );
+ }
+ else
+ {
+ // create a new node and add it to the network
+ pNode = Abc_NtkCreateNode( pNtk );
+ // get the input symbol to be inserted
+ if ( !strncmp(pType, "BUF", 3) || !strcmp(pType, "AND") || !strcmp(pType, "NAND") )
+ SymbolIn = '1';
+ else if ( !strncmp(pType, "NOT", 3) || !strcmp(pType, "OR") || !strcmp(pType, "NOR") )
+ SymbolIn = '0';
+ else if ( !strcmp(pType, "XOR") || !strcmp(pType, "NXOR") )
+ SymbolIn = '*';
+ else
+ {
+ printf( "Cannot determine gate type \"%s\" in line %d.\n", pType, Extra_FileReaderGetLineNumber(p, 0) );
+ Abc_NtkDelete( pNtk );
+ return NULL;
+ }
+ // get the output symbol
+ if ( !strcmp(pType, "NAND") || !strcmp(pType, "OR") || !strcmp(pType, "NXOR") )
+ SymbolOut = '0';
+ else
+ SymbolOut = '1';
+
+ // add the fanout net
+ pNet = Abc_NtkFindOrCreateNet( pNtk, vTokens->pArray[0] );
+ Abc_ObjAddFanin( pNet, pNode );
+ // add the fanin nets
+ for ( i = 2; i < vTokens->nSize; i++ )
+ {
+ pNet = Abc_NtkFindOrCreateNet( pNtk, vTokens->pArray[i] );
+ Abc_ObjAddFanin( pNode, pNet );
+ }
+ if ( SymbolIn != '*' )
+ {
+ // fill in the function
+ Vec_StrFill( vString, vTokens->nSize - 2, (char)SymbolIn );
+ Vec_StrPush( vString, ' ' );
+ Vec_StrPush( vString, (char)SymbolOut );
+ Vec_StrPush( vString, '\n' );
+ Vec_StrPush( vString, '\0' );
+ Abc_ObjSetData( pNode, Abc_SopRegister(pNtk->pManFunc, vString->pArray) );
+ }
+ else
+ { // write XOR/NXOR gates
+ assert( i == 4 );
+ if ( SymbolOut == '1' )
+ Abc_ObjSetData( pNode, Abc_SopRegister(pNtk->pManFunc, "01 1\n10 1\n") );
+ else
+ Abc_ObjSetData( pNode, Abc_SopRegister(pNtk->pManFunc, "00 1\n11 1\n") );
+ }
+ }
+ }
+ }
+ Extra_ProgressBarStop( pProgress );
+ // check if constant have been added
+ if ( pNet = Abc_NtkFindNet( pNtk, "vdd" ) )
+ {
+ // create the constant 1 node
+ pNode = Abc_NtkCreateNode( pNtk );
+ Abc_ObjAddFanin( pNet, pNode );
+ Abc_ObjSetData( pNode, Abc_SopRegister(pNtk->pManFunc, " 1\n") );
+ }
+ if ( pNet = Abc_NtkFindNet( pNtk, "gnd" ) )
+ {
+ // create the constant 1 node
+ pNode = Abc_NtkCreateNode( pNtk );
+ Abc_ObjAddFanin( pNet, pNode );
+ Abc_ObjSetData( pNode, Abc_SopRegister(pNtk->pManFunc, " 0\n") );
+ }
+
+ Io_ReadSetNonDrivenNets( pNtk );
+ Vec_StrFree( vString );
+ return pNtk;
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
+
diff --git a/src/base/io/ioReadBlif.c b/src/base/io/ioReadBlif.c
new file mode 100644
index 00000000..6d9c2347
--- /dev/null
+++ b/src/base/io/ioReadBlif.c
@@ -0,0 +1,642 @@
+/**CFile****************************************************************
+
+ FileName [ioReadBlif.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Command processing package.]
+
+ Synopsis [Procedures to read BLIF files.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: ioReadBlif.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "io.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct Io_ReadBlif_t_ Io_ReadBlif_t; // all reading info
+struct Io_ReadBlif_t_
+{
+ // general info about file
+ char * pFileName; // the name of the file
+ Extra_FileReader_t* pReader; // the input file reader
+ // current processing info
+ Abc_Ntk_t * pNtk; // the primary network
+ Abc_Ntk_t * pNtkExdc; // the exdc network
+ int fParsingExdc; // this flag is on, when we are parsing EXDC network
+ int LineCur; // the line currently parsed
+ // temporary storage for tokens
+ Vec_Ptr_t * vNewTokens; // the temporary storage for the tokens
+ Vec_Str_t * vCubes; // the temporary storage for the tokens
+ // the error message
+ FILE * Output; // the output stream
+ char sError[1000]; // the error string generated during parsing
+};
+
+static Io_ReadBlif_t * Io_ReadBlifFile( char * pFileName );
+static void Io_ReadBlifFree( Io_ReadBlif_t * p );
+static void Io_ReadBlifPrintErrorMessage( Io_ReadBlif_t * p );
+static Vec_Ptr_t * Io_ReadBlifGetTokens( Io_ReadBlif_t * p );
+static Abc_Ntk_t * Io_ReadBlifNetwork( Io_ReadBlif_t * p );
+
+static int Io_ReadBlifNetworkInputs( Io_ReadBlif_t * p, Vec_Ptr_t * vTokens );
+static int Io_ReadBlifNetworkOutputs( Io_ReadBlif_t * p, Vec_Ptr_t * vTokens );
+static int Io_ReadBlifNetworkLatch( Io_ReadBlif_t * p, Vec_Ptr_t * vTokens );
+static int Io_ReadBlifNetworkNames( Io_ReadBlif_t * p, Vec_Ptr_t ** pvTokens );
+static int Io_ReadBlifNetworkInputArrival( Io_ReadBlif_t * p, Vec_Ptr_t * vTokens );
+static int Io_ReadBlifNetworkDefaultInputArrival( Io_ReadBlif_t * p, Vec_Ptr_t * vTokens );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Read the network from BLIF file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Io_ReadBlif( char * pFileName, int fCheck )
+{
+ Io_ReadBlif_t * p;
+ Abc_Ntk_t * pNtk, * pNtkExdc;
+
+ // start the file
+ p = Io_ReadBlifFile( pFileName );
+ if ( p == NULL )
+ return NULL;
+
+ // read the network
+ pNtk = Io_ReadBlifNetwork( p );
+ if ( pNtk == NULL )
+ {
+ Io_ReadBlifFree( p );
+ return NULL;
+ }
+ Abc_NtkTimeFinalize( pNtk );
+
+ // read the EXDC network
+ if ( p->fParsingExdc )
+ {
+ pNtkExdc = Io_ReadBlifNetwork( p );
+ if ( pNtkExdc == NULL )
+ {
+ Abc_NtkDelete( pNtk );
+ Io_ReadBlifFree( p );
+ return NULL;
+ }
+ pNtk->pExdc = pNtkExdc;
+ }
+ Io_ReadBlifFree( p );
+
+ // make sure that everything is okay with the network structure
+ if ( fCheck && !Abc_NtkCheck( pNtk ) )
+ {
+ printf( "Io_ReadBlif: The network check has failed.\n" );
+ Abc_NtkDelete( pNtk );
+ return NULL;
+ }
+ return pNtk;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Starts the reading data structure.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Io_ReadBlif_t * Io_ReadBlifFile( char * pFileName )
+{
+ Extra_FileReader_t * pReader;
+ Io_ReadBlif_t * p;
+
+ // start the reader
+ pReader = Extra_FileReaderAlloc( pFileName, "#", "\n", " \t\r" );
+ if ( pReader == NULL )
+ return NULL;
+
+ // start the reading data structure
+ p = ALLOC( Io_ReadBlif_t, 1 );
+ memset( p, 0, sizeof(Io_ReadBlif_t) );
+ p->pFileName = pFileName;
+ p->pReader = pReader;
+ p->Output = stdout;
+ p->vNewTokens = Vec_PtrAlloc( 100 );
+ p->vCubes = Vec_StrAlloc( 100 );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Frees the data structure.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_ReadBlifFree( Io_ReadBlif_t * p )
+{
+ Extra_FileReaderFree( p->pReader );
+ Vec_PtrFree( p->vNewTokens );
+ Vec_StrFree( p->vCubes );
+ free( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the error message including the file name and line number.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_ReadBlifPrintErrorMessage( Io_ReadBlif_t * p )
+{
+ if ( p->LineCur == 0 ) // the line number is not given
+ fprintf( p->Output, "%s: %s\n", p->pFileName, p->sError );
+ else // print the error message with the line number
+ fprintf( p->Output, "%s (line %d): %s\n", p->pFileName, p->LineCur, p->sError );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Gets the tokens taking into account the line breaks.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Vec_Ptr_t * Io_ReadBlifGetTokens( Io_ReadBlif_t * p )
+{
+ Vec_Ptr_t * vTokens;
+ char * pLastToken;
+ int i;
+
+ // get rid of the old tokens
+ if ( p->vNewTokens->nSize > 0 )
+ {
+ for ( i = 0; i < p->vNewTokens->nSize; i++ )
+ free( p->vNewTokens->pArray[i] );
+ p->vNewTokens->nSize = 0;
+ }
+
+ // get the new tokens
+ vTokens = Extra_FileReaderGetTokens(p->pReader);
+ if ( vTokens == NULL )
+ return vTokens;
+
+ // check if there is a transfer to another line
+ pLastToken = vTokens->pArray[vTokens->nSize - 1];
+ if ( pLastToken[ strlen(pLastToken)-1 ] != '\\' )
+ return vTokens;
+
+ // remove the slash
+ pLastToken[ strlen(pLastToken)-1 ] = 0;
+ if ( pLastToken[0] == 0 )
+ vTokens->nSize--;
+ // load them into the new array
+ for ( i = 0; i < vTokens->nSize; i++ )
+ Vec_PtrPush( p->vNewTokens, util_strsav(vTokens->pArray[i]) );
+
+ // load as long as there is the line break
+ while ( 1 )
+ {
+ // get the new tokens
+ vTokens = Extra_FileReaderGetTokens(p->pReader);
+ if ( vTokens->nSize == 0 )
+ return p->vNewTokens;
+ // check if there is a transfer to another line
+ pLastToken = vTokens->pArray[vTokens->nSize - 1];
+ if ( pLastToken[ strlen(pLastToken)-1 ] == '\\' )
+ {
+ // remove the slash
+ pLastToken[ strlen(pLastToken)-1 ] = 0;
+ if ( pLastToken[0] == 0 )
+ vTokens->nSize--;
+ // load them into the new array
+ for ( i = 0; i < vTokens->nSize; i++ )
+ Vec_PtrPush( p->vNewTokens, util_strsav(vTokens->pArray[i]) );
+ continue;
+ }
+ // otherwise, load them and break
+ for ( i = 0; i < vTokens->nSize; i++ )
+ Vec_PtrPush( p->vNewTokens, util_strsav(vTokens->pArray[i]) );
+ break;
+ }
+ return p->vNewTokens;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Reads the BLIF file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Io_ReadBlifNetwork( Io_ReadBlif_t * p )
+{
+ ProgressBar * pProgress;
+ Vec_Ptr_t * vTokens;
+ char * pModelName;
+ int iLine, fTokensReady, fStatus;
+
+ // read the model name
+ if ( !p->fParsingExdc )
+ {
+ // read the model name
+ vTokens = Io_ReadBlifGetTokens(p);
+ if ( vTokens == NULL || strcmp( vTokens->pArray[0], ".model" ) )
+ {
+ p->LineCur = 0;
+ sprintf( p->sError, "Wrong input file format." );
+ Io_ReadBlifPrintErrorMessage( p );
+ return NULL;
+ }
+ pModelName = vTokens->pArray[1];
+ // allocate the empty network
+ p->pNtk = Abc_NtkAlloc( ABC_NTK_NETLIST );
+ p->pNtk->pName = util_strsav( pModelName );
+ p->pNtk->pSpec = util_strsav( p->pFileName );
+ }
+ else
+ p->pNtk = Abc_NtkAlloc( ABC_NTK_NETLIST );
+
+ // read the inputs/outputs
+ pProgress = Extra_ProgressBarStart( stdout, Extra_FileReaderGetFileSize(p->pReader) );
+ fTokensReady = fStatus = 0;
+ for ( iLine = 0; fTokensReady || (vTokens = Io_ReadBlifGetTokens(p)); iLine++ )
+ {
+ if ( iLine % 1000 == 0 )
+ Extra_ProgressBarUpdate( pProgress, Extra_FileReaderGetCurPosition(p->pReader), NULL );
+
+ // consider different line types
+ fTokensReady = 0;
+ if ( !strcmp( vTokens->pArray[0], ".names" ) )
+ { fStatus = Io_ReadBlifNetworkNames( p, &vTokens ); fTokensReady = 1; }
+ else if ( !strcmp( vTokens->pArray[0], ".latch" ) )
+ fStatus = Io_ReadBlifNetworkLatch( p, vTokens );
+ else if ( !strcmp( vTokens->pArray[0], ".inputs" ) )
+ fStatus = Io_ReadBlifNetworkInputs( p, vTokens );
+ else if ( !strcmp( vTokens->pArray[0], ".outputs" ) )
+ fStatus = Io_ReadBlifNetworkOutputs( p, vTokens );
+ else if ( !strcmp( vTokens->pArray[0], ".input_arrival" ) )
+ fStatus = Io_ReadBlifNetworkInputArrival( p, vTokens );
+ else if ( !strcmp( vTokens->pArray[0], ".default_input_arrival" ) )
+ fStatus = Io_ReadBlifNetworkDefaultInputArrival( p, vTokens );
+ else if ( !strcmp( vTokens->pArray[0], ".exdc" ) )
+ { p->fParsingExdc = 1; break; }
+ else if ( !strcmp( vTokens->pArray[0], ".end" ) )
+ break;
+ else
+ printf( "%s (line %d): Skipping directive \"%s\".\n", p->pFileName,
+ Extra_FileReaderGetLineNumber(p->pReader, 0), vTokens->pArray[0] );
+ if ( vTokens == NULL ) // some files do not have ".end" in the end
+ break;
+ if ( fStatus == 1 )
+ return NULL;
+ }
+ Extra_ProgressBarStop( pProgress );
+ Io_ReadSetNonDrivenNets( p->pNtk );
+ return p->pNtk;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Io_ReadBlifNetworkInputs( Io_ReadBlif_t * p, Vec_Ptr_t * vTokens )
+{
+ Abc_Ntk_t * pNtk = p->pNtk;
+ Abc_Obj_t * pNet;
+ int i;
+ for ( i = 1; i < vTokens->nSize; i++ )
+ {
+ pNet = Abc_NtkFindOrCreateNet( pNtk, vTokens->pArray[i] );
+ if ( Abc_ObjIsPi(pNet) )
+ printf( "Warning: PI net \"%s\" appears twice in the list.\n", vTokens->pArray[i] );
+ else
+ Abc_NtkMarkNetPi( pNet );
+ }
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Io_ReadBlifNetworkOutputs( Io_ReadBlif_t * p, Vec_Ptr_t * vTokens )
+{
+ Abc_Ntk_t * pNtk = p->pNtk;
+ Abc_Obj_t * pNet;
+ int i;
+ for ( i = 1; i < vTokens->nSize; i++ )
+ {
+ pNet = Abc_NtkFindOrCreateNet( pNtk, vTokens->pArray[i] );
+ if ( Abc_ObjIsPo(pNet) )
+ printf( "Warning: PO net \"%s\" appears twice in the list.\n", vTokens->pArray[i] );
+ else
+ Abc_NtkMarkNetPo( pNet );
+ }
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Io_ReadBlifNetworkLatch( Io_ReadBlif_t * p, Vec_Ptr_t * vTokens )
+{
+ Abc_Ntk_t * pNtk = p->pNtk;
+ Abc_Obj_t * pNet, * pLatch;
+ int ResetValue;
+
+ if ( vTokens->nSize < 3 )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber(p->pReader, 0);
+ sprintf( p->sError, "The .latch line does not have enough tokens." );
+ Io_ReadBlifPrintErrorMessage( p );
+ return 1;
+ }
+ // create a new node and add it to the network
+ pLatch = Abc_NtkCreateLatch( pNtk );
+ // create the LO (PI)
+ pNet = Abc_NtkFindOrCreateNet( pNtk, vTokens->pArray[2] );
+ Abc_ObjAddFanin( pNet, pLatch );
+ Abc_ObjSetSubtype( pNet, ABC_OBJ_SUBTYPE_LO );
+ // save the LI (PO)
+ pNet = Abc_NtkFindOrCreateNet( pNtk, vTokens->pArray[1] );
+ Abc_ObjAddFanin( pLatch, pNet );
+ Abc_ObjSetSubtype( pNet, ABC_OBJ_SUBTYPE_LI );
+ // get the latch reset value
+ if ( vTokens->nSize == 3 )
+ ResetValue = 2;
+ else
+ {
+ ResetValue = atoi(vTokens->pArray[3]);
+ if ( ResetValue != 0 && ResetValue != 1 && ResetValue != 2 )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber(p->pReader, 0);
+ sprintf( p->sError, "The .latch line has an unknown reset value (%s).", vTokens->pArray[3] );
+ Io_ReadBlifPrintErrorMessage( p );
+ return 1;
+ }
+ }
+ Abc_ObjSetData( pLatch, (void *)ResetValue );
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Io_ReadBlifNetworkNames( Io_ReadBlif_t * p, Vec_Ptr_t ** pvTokens )
+{
+ Vec_Ptr_t * vTokens = *pvTokens;
+ Abc_Ntk_t * pNtk = p->pNtk;
+ Abc_Obj_t * pNet, * pNode;
+ char * pToken, Char;
+ int i, nFanins;
+
+ // create a new node and add it to the network
+ pNode = Abc_NtkCreateNode( pNtk );
+ if ( vTokens->nSize < 2 )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber(p->pReader, 0);
+ sprintf( p->sError, "The .names line has less than two tokens." );
+ Io_ReadBlifPrintErrorMessage( p );
+ return 1;
+ }
+ // go through the nets
+ for ( i = 1; i < vTokens->nSize - 1; i++ )
+ {
+ pNet = Abc_NtkFindOrCreateNet( pNtk, vTokens->pArray[i] );
+ Abc_ObjAddFanin( pNode, pNet );
+ }
+ pNet = Abc_NtkFindOrCreateNet( pNtk, vTokens->pArray[vTokens->nSize - 1] );
+ Abc_ObjAddFanin( pNet, pNode );
+
+ // derive the functionality of the node
+ p->vCubes->nSize = 0;
+ nFanins = vTokens->nSize - 2;
+ if ( nFanins == 0 )
+ while ( vTokens = Io_ReadBlifGetTokens(p) )
+ {
+ pToken = vTokens->pArray[0];
+ if ( pToken[0] == '.' )
+ break;
+ // read the cube
+ if ( vTokens->nSize != 1 )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber(p->pReader, 0);
+ sprintf( p->sError, "The number of tokens in the constant cube is wrong." );
+ Io_ReadBlifPrintErrorMessage( p );
+ return 1;
+ }
+ // create the cube
+ Char = ((char *)vTokens->pArray[0])[0];
+ Vec_StrPush( p->vCubes, ' ' );
+ Vec_StrPush( p->vCubes, Char );
+ Vec_StrPush( p->vCubes, '\n' );
+ }
+ else
+ while ( vTokens = Io_ReadBlifGetTokens(p) )
+ {
+ pToken = vTokens->pArray[0];
+ if ( pToken[0] == '.' )
+ break;
+ // read the cube
+ if ( vTokens->nSize != 2 )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber(p->pReader, 0);
+ sprintf( p->sError, "The number of tokens in the cube is wrong." );
+ Io_ReadBlifPrintErrorMessage( p );
+ return 1;
+ }
+ // create the cube
+ for ( i = 0; i < nFanins; i++ )
+ Vec_StrPush( p->vCubes, ((char *)vTokens->pArray[0])[i] );
+ // check the char
+ Char = ((char *)vTokens->pArray[1])[0];
+ if ( Char != '0' && Char != '1' )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber(p->pReader, 0);
+ sprintf( p->sError, "The output character in the constant cube is wrong." );
+ Io_ReadBlifPrintErrorMessage( p );
+ return 1;
+ }
+ Vec_StrPush( p->vCubes, ' ' );
+ Vec_StrPush( p->vCubes, Char );
+ Vec_StrPush( p->vCubes, '\n' );
+ }
+ // if there is nothing there
+ if ( p->vCubes->nSize == 0 )
+ {
+ // create an empty cube
+ Vec_StrPush( p->vCubes, ' ' );
+ Vec_StrPush( p->vCubes, '0' );
+ Vec_StrPush( p->vCubes, '\n' );
+ }
+ Vec_StrPush( p->vCubes, 0 );
+ // set the pointer to the functionality of the node
+ Abc_ObjSetData( pNode, Abc_SopRegister(pNtk->pManFunc, p->vCubes->pArray) );
+ // return the last array of tokens
+ *pvTokens = vTokens;
+ return 0;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Io_ReadBlifNetworkInputArrival( Io_ReadBlif_t * p, Vec_Ptr_t * vTokens )
+{
+ Abc_Obj_t * pNet;
+ char * pFoo1, * pFoo2;
+ double TimeRise, TimeFall;
+
+ // make sure this is indeed the .inputs line
+ assert( strncmp( vTokens->pArray[0], ".input_arrival", 14 ) == 0 );
+ if ( vTokens->nSize != 4 )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber(p->pReader, 0);
+ sprintf( p->sError, "Wrong number of arguments on .input_arrival line." );
+ Io_ReadBlifPrintErrorMessage( p );
+ return 1;
+ }
+ pNet = Abc_NtkFindNet( p->pNtk, vTokens->pArray[1] );
+ if ( pNet == NULL )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber(p->pReader, 0);
+ sprintf( p->sError, "Cannot find object corresponding to %s on .input_arrival line.", vTokens->pArray[1] );
+ Io_ReadBlifPrintErrorMessage( p );
+ return 1;
+ }
+ TimeRise = strtod( vTokens->pArray[2], &pFoo1 );
+ TimeFall = strtod( vTokens->pArray[3], &pFoo2 );
+ if ( *pFoo1 != '\0' || *pFoo2 != '\0' )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber(p->pReader, 0);
+ sprintf( p->sError, "Bad value (%s %s) for rise or fall time on .input_arrival line.", vTokens->pArray[2], vTokens->pArray[3] );
+ Io_ReadBlifPrintErrorMessage( p );
+ return 1;
+ }
+ // set the arrival time
+ Abc_NtkTimeSetArrival( p->pNtk, pNet->Id, (float)TimeRise, (float)TimeFall );
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Io_ReadBlifNetworkDefaultInputArrival( Io_ReadBlif_t * p, Vec_Ptr_t * vTokens )
+{
+ char * pFoo1, * pFoo2;
+ double TimeRise, TimeFall;
+
+ // make sure this is indeed the .inputs line
+ assert( strncmp( vTokens->pArray[0], ".default_input_arrival", 23 ) == 0 );
+ if ( vTokens->nSize != 3 )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber(p->pReader, 0);
+ sprintf( p->sError, "Wrong number of arguments on .default_input_arrival line." );
+ Io_ReadBlifPrintErrorMessage( p );
+ return 1;
+ }
+ TimeRise = strtod( vTokens->pArray[1], &pFoo1 );
+ TimeFall = strtod( vTokens->pArray[2], &pFoo2 );
+ if ( *pFoo1 != '\0' || *pFoo2 != '\0' )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber(p->pReader, 0);
+ sprintf( p->sError, "Bad value (%s %s) for rise or fall time on .default_input_arrival line.", vTokens->pArray[1], vTokens->pArray[2] );
+ Io_ReadBlifPrintErrorMessage( p );
+ return 1;
+ }
+ // set the arrival time
+ Abc_NtkTimeSetDefaultArrival( p->pNtk, (float)TimeRise, (float)TimeFall );
+ return 0;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/io/ioReadVerilog.c b/src/base/io/ioReadVerilog.c
new file mode 100644
index 00000000..a3b5a0bf
--- /dev/null
+++ b/src/base/io/ioReadVerilog.c
@@ -0,0 +1,888 @@
+/**CFile****************************************************************
+
+ FileName [ioReadVerilog.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Command processing package.]
+
+ Synopsis [Procedures to read a subset of structural Verilog from IWLS 2005 benchmark.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: ioReadVerilog.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "io.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct Io_ReadVer_t_ Io_ReadVer_t; // all reading info
+struct Io_ReadVer_t_
+{
+ // general info about file
+ char * pFileName; // the name of the file
+ Extra_FileReader_t* pReader; // the input file reader
+ // current processing info
+ st_table * tKeywords; // mapping of keywords into codes
+ Abc_Ntk_t * pNtk; // the primary network
+ // the error message
+ FILE * Output; // the output stream
+ char sError[1000]; // the error string generated during parsing
+ int LineCur; // the line currently being parsed
+ Vec_Ptr_t * vSkipped; // temporary storage for skipped objects
+};
+
+// verilog keyword types
+typedef enum {
+ VER_NONE = 0,
+ VER_MODULE = -1,
+ VER_ENDMODULE = -2,
+ VER_INPUT = -3,
+ VER_OUTPUT = -4,
+ VER_INOUT = -5,
+ VER_WIRE = -6,
+ VER_ASSIGN = -7
+} Ver_KeywordType_t;
+
+// the list of verilog keywords
+static char * s_Keywords[10] =
+{
+ NULL, // unused
+ "module", // -1
+ "endmodule", // -2
+ "input", // -3
+ "output", // -4
+ "inout", // -5
+ "wire", // -6
+ "assign" // -7
+};
+
+// the list of gates in the Cadence library
+static char * s_CadenceGates[40][5] =
+{
+ { "INVX1", "1", "1", "0 1\n", NULL }, // 0
+ { "INVX2", "1", "1", "0 1\n", NULL }, // 1
+ { "INVX4", "1", "1", "0 1\n", NULL }, // 2
+ { "INVX8", "1", "1", "0 1\n", NULL }, // 3
+ { "BUFX1", "1", "1", "1 1\n", NULL }, // 4
+ { "BUFX3", "1", "1", "1 1\n", NULL }, // 5
+ { "NOR2X1", "2", "1", "00 1\n", NULL }, // 6
+ { "NOR3X1", "3", "1", "000 1\n", NULL }, // 7
+ { "NOR4X1", "4", "1", "0000 1\n", NULL }, // 8
+ { "NAND2X1", "2", "1", "11 0\n", NULL }, // 9
+ { "NAND2X2", "2", "1", "11 0\n", NULL }, // 10
+ { "NAND3X1", "3", "1", "111 0\n", NULL }, // 11
+ { "NAND4X1", "4", "1", "1111 0\n", NULL }, // 12
+ { "OR2X1", "2", "1", "00 0\n", NULL }, // 13
+ { "OR4X1", "4", "1", "0000 0\n", NULL }, // 14
+ { "AND2X1", "2", "1", "11 1\n", NULL }, // 15
+ { "XOR2X1", "2", "1", "01 1\n10 1\n", NULL }, // 16
+ { "MX2X1", "3", "1", "01- 1\n1-1 1\n", NULL }, // 17
+ { "OAI21X1", "3", "1", "00- 1\n--0 1\n", NULL }, // 18
+ { "OAI22X1", "4", "1", "00-- 1\n--00 1\n", NULL }, // 19
+ { "OAI33X1", "6", "1", "000--- 1\n---000 1\n", NULL }, // 20
+ { "AOI21X1", "3", "1", "11- 0\n--1 0\n", NULL }, // 21
+ { "AOI22X1", "4", "1", "11-- 0\n--11 0\n", NULL }, // 22
+ { "CLKBUFX1", "1", "1", "1 1\n", NULL }, // 23
+ { "CLKBUFX2", "1", "1", "1 1\n", NULL }, // 24
+ { "CLKBUFX3", "1", "1", "1 1\n", NULL }, // 25
+ { "ADDHX1", "2", "2", "11 1\n", "01 1\n10 1\n" }, // 26
+ { "ADDFX1", "3", "2", "11- 1\n-11 1\n1-1 1\n", "001 1\n010 1\n100 1\n111 1\n" }, // 27
+ { "DFFSRX1", "1", "1", NULL, NULL }, // 28
+ { "DFFX1", "1", "1", NULL, NULL }, // 29
+ { "SDFFSRX1", "1", "1", NULL, NULL }, // 30
+ { "TLATSRX1", "1", "1", NULL, NULL }, // 31
+ { "TLATX1", "1", "1", NULL, NULL }, // 32
+ { "TBUFX1", "1", "1", NULL, NULL }, // 33
+ { "TBUFX2", "1", "1", NULL, NULL }, // 34
+ { "TBUFX4", "1", "1", NULL, NULL }, // 35
+ { "TBUFX8", "1", "1", NULL, NULL }, // 36
+ { "TINVX1", "1", "1", NULL, NULL } // 37
+};
+
+static Io_ReadVer_t * Io_ReadVerFile( char * pFileName );
+static Abc_Ntk_t * Io_ReadVerNetwork( Io_ReadVer_t * p );
+static bool Io_ReadVerNetworkAssign( Io_ReadVer_t * p, Abc_Ntk_t * pNtk, Vec_Ptr_t * vTokens );
+static bool Io_ReadVerNetworkSignal( Io_ReadVer_t * p, Abc_Ntk_t * pNtk, Vec_Ptr_t * vTokens, int LineType );
+static bool Io_ReadVerNetworkGateSimple( Io_ReadVer_t * p, Abc_Ntk_t * pNtk, Vec_Ptr_t * vTokens, int LineType );
+static bool Io_ReadVerNetworkGateComplex( Io_ReadVer_t * p, Abc_Ntk_t * pNtk, Vec_Ptr_t * vTokens, int LineType );
+static bool Io_ReadVerNetworkLatch( Io_ReadVer_t * p, Abc_Ntk_t * pNtk, Vec_Ptr_t * vTokens );
+static void Io_ReadVerPrintErrorMessage( Io_ReadVer_t * p );
+static void Io_ReadVerFree( Io_ReadVer_t * p );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Read the network from BENCH file.]
+
+ Description [Currently works only for the miter cone.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Io_ReadVerilog( char * pFileName, int fCheck )
+{
+ Io_ReadVer_t * p;
+ Abc_Ntk_t * pNtk;
+
+ // start the file
+ p = Io_ReadVerFile( pFileName );
+ if ( p == NULL )
+ return NULL;
+
+ // read the network
+ pNtk = Io_ReadVerNetwork( p );
+ Io_ReadVerFree( p );
+ if ( pNtk == NULL )
+ return NULL;
+
+ // make sure that everything is okay with the network structure
+ if ( fCheck && !Abc_NtkCheck( pNtk ) )
+ {
+ printf( "Io_ReadVerilog: The network check has failed.\n" );
+ Abc_NtkDelete( pNtk );
+ return NULL;
+ }
+ return pNtk;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Starts the reading data structure.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Io_ReadVer_t * Io_ReadVerFile( char * pFileName )
+{
+ Extra_FileReader_t * pReader;
+ Io_ReadVer_t * p;
+ int i;
+
+ // start the reader
+ pReader = Extra_FileReaderAlloc( pFileName, "/", ";", " \t\r\n,()" );
+ if ( pReader == NULL )
+ return NULL;
+
+ // start the reading data structure
+ p = ALLOC( Io_ReadVer_t, 1 );
+ memset( p, 0, sizeof(Io_ReadVer_t) );
+ p->pFileName = pFileName;
+ p->pReader = pReader;
+ p->Output = stdout;
+ p->vSkipped = Vec_PtrAlloc( 100 );
+
+ // insert the keywords and gate names into the hash table
+ p->tKeywords = st_init_table(strcmp, st_strhash);
+ for ( i = 0; i < 10; i++ )
+ if ( s_Keywords[i] )
+ st_insert( p->tKeywords, (char *)s_Keywords[i], (char *)-i );
+ for ( i = 0; i < 40; i++ )
+ if ( s_CadenceGates[i][0] )
+ st_insert( p->tKeywords, (char *)s_CadenceGates[i][0], (char *)i );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Frees the data structure.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_ReadVerFree( Io_ReadVer_t * p )
+{
+ Extra_FileReaderFree( p->pReader );
+ Vec_PtrFree( p->vSkipped );
+ st_free_table( p->tKeywords );
+ FREE( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the error message including the file name and line number.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_ReadVerPrintErrorMessage( Io_ReadVer_t * p )
+{
+ if ( p->LineCur == 0 ) // the line number is not given
+ fprintf( p->Output, "%s: %s\n", p->pFileName, p->sError );
+ else // print the error message with the line number
+ fprintf( p->Output, "%s (line %d): %s\n", p->pFileName, p->LineCur, p->sError );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads the verilog file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Io_ReadVerNetwork( Io_ReadVer_t * p )
+{
+ char Buffer[1000];
+ ProgressBar * pProgress;
+ Ver_KeywordType_t LineType;
+ Vec_Ptr_t * vTokens;
+ Abc_Ntk_t * pNtk;
+ char * pModelName;
+ int i;
+
+ // read the model name
+ vTokens = Extra_FileReaderGetTokens( p->pReader );
+ if ( vTokens == NULL || strcmp( vTokens->pArray[0], "module" ) )
+ {
+ p->LineCur = 0;
+ sprintf( p->sError, "Wrong input file format." );
+ Io_ReadVerPrintErrorMessage( p );
+ return NULL;
+ }
+ pModelName = vTokens->pArray[1];
+
+ // allocate the empty network
+ pNtk = Abc_NtkAlloc( ABC_NTK_NETLIST );
+ pNtk->pName = util_strsav( pModelName );
+ pNtk->pSpec = util_strsav( p->pFileName );
+
+ // read the inputs/outputs
+ pProgress = Extra_ProgressBarStart( stdout, Extra_FileReaderGetFileSize(p->pReader) );
+ for ( i = 0; vTokens = Extra_FileReaderGetTokens(p->pReader); i++ )
+ {
+ Extra_ProgressBarUpdate( pProgress, Extra_FileReaderGetCurPosition(p->pReader), NULL );
+
+ // get the line type
+ if ( !st_lookup( p->tKeywords, vTokens->pArray[0], (char **)&LineType ) )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber( p->pReader, 0 );
+ sprintf( p->sError, "The first token \"%s\" cannot be recognized.", vTokens->pArray[0] );
+ Io_ReadVerPrintErrorMessage( p );
+ return NULL;
+ }
+ // consider Verilog directives
+ if ( LineType < 0 )
+ {
+ if ( LineType == VER_ENDMODULE )
+ break;
+ if ( LineType == VER_ASSIGN )
+ {
+ if ( !Io_ReadVerNetworkAssign( p, pNtk, vTokens ) )
+ return NULL;
+ continue;
+ }
+ if ( !Io_ReadVerNetworkSignal( p, pNtk, vTokens, LineType ) )
+ return NULL;
+ continue;
+ }
+ // proces single output gates
+ if ( LineType < 26 )
+ {
+ if ( !Io_ReadVerNetworkGateSimple( p, pNtk, vTokens, LineType ) )
+ return NULL;
+ continue;
+ }
+ // process complex gates
+ if ( LineType < 28 )
+ {
+ if ( !Io_ReadVerNetworkGateComplex( p, pNtk, vTokens, LineType ) )
+ return NULL;
+ continue;
+
+ }
+ // process the latches
+ if ( LineType < 33 )
+ {
+ if ( !Io_ReadVerNetworkLatch( p, pNtk, vTokens ) )
+ return NULL;
+ continue;
+ }
+ // add the tri-state element to the skipped ones
+ sprintf( Buffer, "%s %s", vTokens->pArray[0], vTokens->pArray[1] );
+ Vec_PtrPush( p->vSkipped, util_strsav(Buffer) );
+ }
+ Extra_ProgressBarStop( pProgress );
+
+ if ( p->vSkipped->nSize > 0 )
+ {
+ printf( "IoReadVerilog() skipped %d tri-state elements:\n", p->vSkipped->nSize );
+ for ( i = 0; i < p->vSkipped->nSize; i++ )
+ {
+ if ( i < 2 )
+ printf( "%s,\n", p->vSkipped->pArray[i] );
+ else
+ {
+ printf( "%s, etc.\n", p->vSkipped->pArray[i] );
+ break;
+ }
+ }
+ for ( i = 0; i < p->vSkipped->nSize; i++ )
+ free( p->vSkipped->pArray[i] );
+ }
+ Io_ReadSetNonDrivenNets( pNtk );
+ return pNtk;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads one assign directive in the verilog file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Io_ReadVerNetworkAssign( Io_ReadVer_t * p, Abc_Ntk_t * pNtk, Vec_Ptr_t * vTokens )
+{
+ Abc_Obj_t * pNet, * pNode;
+
+ assert( strcmp( vTokens->pArray[0], "assign" ) == 0 );
+
+ if ( strcmp( vTokens->pArray[3], "1'b0" ) != 0 && strcmp( vTokens->pArray[3], "1'b1" ) != 0 )
+ {
+ // handle assignment to a variable
+ if ( vTokens->nSize == 4 && (pNet = Abc_NtkFindNet(pNtk, vTokens->pArray[3])) )
+ {
+ // allocate the buffer node
+ pNode = Abc_NtkCreateNode( pNtk );
+ Abc_ObjSetData( pNode, Abc_SopRegister(pNtk->pManFunc, "1 1\n") );
+ // add the fanin net
+ Abc_ObjAddFanin( pNode, pNet );
+ // add the fanout net
+ pNet = Abc_NtkFindNet(pNtk, vTokens->pArray[1]);
+ Abc_ObjAddFanin( pNet, pNode );
+ return 1;
+ }
+ // produce error in case of more complex assignment
+ p->LineCur = Extra_FileReaderGetLineNumber( p->pReader, 0 );
+ sprintf( p->sError, "The assign operator is handled only for assignment to a variable and a constant." );
+ Io_ReadVerPrintErrorMessage( p );
+ return 0;
+ }
+ // allocate constant node
+ pNode = Abc_NtkCreateNode( pNtk );
+ // set the constant function
+ if ( ((char *)vTokens->pArray[3])[3] == '0' )
+ Abc_ObjSetData( pNode, Abc_SopRegister(pNtk->pManFunc, " 0\n") );
+ else
+ Abc_ObjSetData( pNode, Abc_SopRegister(pNtk->pManFunc, " 1\n") );
+ // set the fanout net
+ pNet = Abc_NtkFindNet( pNtk, vTokens->pArray[1] );
+ if ( pNet == NULL )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber( p->pReader, 1 );
+ sprintf( p->sError, "Cannot find net \"%s\".", vTokens->pArray[1] );
+ Io_ReadVerPrintErrorMessage( p );
+ return 0;
+ }
+ Abc_ObjAddFanin( pNet, pNode );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads one signal the verilog file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Io_ReadVerNetworkSignal( Io_ReadVer_t * p, Abc_Ntk_t * pNtk, Vec_Ptr_t * vTokens, int LineType )
+{
+ char Buffer[1000];
+ Abc_Obj_t * pNet;
+ char * pToken;
+ int nSignals, k, Start, s;
+
+ nSignals = 0;
+ pToken = vTokens->pArray[1];
+ if ( pToken[0] == '[' )
+ {
+ nSignals = atoi(pToken + 1) + 1;
+ if ( nSignals < 1 || nSignals > 1024 )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber( p->pReader, 0 );
+ sprintf( p->sError, "Incorrect number of signals in the expression \"%s\".", pToken );
+ Io_ReadVerPrintErrorMessage( p );
+ return 0;
+ }
+ if ( nSignals == 1 )
+ nSignals = 0;
+ Start = 2;
+ }
+ else
+ Start = 1;
+ for ( k = Start; k < vTokens->nSize; k++ )
+ {
+ pToken = vTokens->pArray[k];
+ // print the signal name
+ if ( nSignals )
+ {
+ for ( s = 0; s < nSignals; s++ )
+ {
+ sprintf( Buffer, "%s[%d]", pToken, s );
+ pNet = Abc_NtkFindOrCreateNet( pNtk, Buffer );
+ if ( LineType == VER_INPUT || LineType == VER_INOUT )
+ Abc_NtkMarkNetPi( pNet );
+ if ( LineType == VER_OUTPUT || LineType == VER_INOUT )
+ Abc_NtkMarkNetPo( pNet );
+ }
+ }
+ else
+ {
+ pNet = Abc_NtkFindOrCreateNet( pNtk, pToken );
+ if ( LineType == VER_INPUT || LineType == VER_INOUT )
+ Abc_NtkMarkNetPi( pNet );
+ if ( LineType == VER_OUTPUT || LineType == VER_INOUT )
+ Abc_NtkMarkNetPo( pNet );
+ }
+ }
+ return 1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Reads a simple gate from the verilog file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Io_ReadVerNetworkGateSimple( Io_ReadVer_t * p, Abc_Ntk_t * pNtk, Vec_Ptr_t * vTokens, int LineType )
+{
+ Abc_Obj_t * pNode, * pNet, * pNodeConst, * pNetConst;
+ char * pToken;
+ int nFanins, k;
+
+ // create the node
+ pNode = Abc_NtkCreateNode( pNtk );
+ // set the function
+ Abc_ObjSetData( pNode, Abc_SopRegister(pNtk->pManFunc, s_CadenceGates[LineType][3]) );
+ // skip the gate type and gate name
+ // add the fanin nets
+ nFanins = s_CadenceGates[LineType][1][0] - '0';
+ for ( k = 2; k < vTokens->nSize - 1; k++ )
+ {
+ pToken = vTokens->pArray[k];
+ if ( pToken[0] == '.' )
+ continue;
+ pNet = Abc_NtkFindNet( pNtk, pToken );
+ if ( pNet )
+ {
+ Abc_ObjAddFanin( pNode, pNet );
+ continue;
+ }
+ // handle the case of a constant
+ if ( strcmp( pToken, "1'b0" ) == 0 || strcmp( pToken, "1'b1" ) == 0 )
+ {
+ // create the net and link it to the node
+ pNetConst = Abc_NtkFindOrCreateNet( pNtk, pToken );
+ Abc_ObjAddFanin( pNode, pNetConst );
+ // allocate constant node
+ pNodeConst = Abc_NtkCreateNode( pNtk );
+ // set the constant function
+ if ( pToken[3] == '0' )
+ Abc_ObjSetData( pNodeConst, Abc_SopRegister(pNtk->pManFunc, " 0\n") );
+ else
+ Abc_ObjSetData( pNodeConst, Abc_SopRegister(pNtk->pManFunc, " 1\n") );
+ // add this node as the fanin of the constant net
+ Abc_ObjAddFanin( pNetConst, pNodeConst );
+ continue;
+ }
+ p->LineCur = Extra_FileReaderGetLineNumber( p->pReader, 0 );
+ sprintf( p->sError, "Cannot find net \"%s\".", pToken );
+ Io_ReadVerPrintErrorMessage( p );
+ return 0;
+ }
+ if ( Abc_ObjFaninNum(pNode) != nFanins )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber( p->pReader, 0 );
+ sprintf( p->sError, "Gate \"%s\" has a wrong number of inputs.", vTokens->pArray[1] );
+ Io_ReadVerPrintErrorMessage( p );
+ return 0;
+ }
+
+ // add the fanout net
+ pToken = vTokens->pArray[vTokens->nSize - 1];
+ if ( pToken[0] == '.' )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber( p->pReader, 0 );
+ sprintf( p->sError, "Gate \"%s\" does not have a fanout.", vTokens->pArray[1] );
+ Io_ReadVerPrintErrorMessage( p );
+ return 0;
+ }
+ pNet = Abc_NtkFindNet( pNtk, pToken );
+ if ( pNet == NULL )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber( p->pReader, 0 );
+ sprintf( p->sError, "Cannot find net \"%s\".", pToken );
+ Io_ReadVerPrintErrorMessage( p );
+ return 0;
+ }
+ Abc_ObjAddFanin( pNet, pNode );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads a complex gate from the verilog file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Io_ReadVerNetworkGateComplex( Io_ReadVer_t * p, Abc_Ntk_t * pNtk, Vec_Ptr_t * vTokens, int LineType )
+{
+ Abc_Obj_t * pNode1, * pNode2, * pNet;
+ char * pToken, * pToken1, * pToken2;
+ int nFanins, k;
+
+ // create the nodes
+ pNode1 = Abc_NtkCreateNode( pNtk );
+ Abc_ObjSetData( pNode1, Abc_SopRegister(pNtk->pManFunc, s_CadenceGates[LineType][3]) );
+ pNode2 = Abc_NtkCreateNode( pNtk );
+ Abc_ObjSetData( pNode2, Abc_SopRegister(pNtk->pManFunc, s_CadenceGates[LineType][4]) );
+ // skip the gate type and gate name
+ // add the fanin nets
+ nFanins = s_CadenceGates[LineType][1][0] - '0';
+ for ( k = 2; k < vTokens->nSize; k++ )
+ {
+ pToken = vTokens->pArray[k];
+ if ( pToken[0] == '.' )
+ continue;
+ pNet = Abc_NtkFindNet( pNtk, pToken );
+ if ( pNet == NULL )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber( p->pReader, 0 );
+ sprintf( p->sError, "Cannot find net \"%s\".", pToken );
+ Io_ReadVerPrintErrorMessage( p );
+ return 0;
+ }
+ Abc_ObjAddFanin( pNode1, pNet );
+ Abc_ObjAddFanin( pNode2, pNet );
+ if ( Abc_ObjFaninNum(pNode1) == nFanins )
+ {
+ k++;
+ break;
+ }
+ }
+ // find the tokens corresponding to the output
+ pToken1 = pToken2 = NULL;
+ for ( ; k < vTokens->nSize; k++ )
+ {
+ pToken = vTokens->pArray[k];
+ if ( pToken[0] == '.' )
+ continue;
+ if ( pToken1 == NULL )
+ pToken1 = pToken;
+ else
+ pToken2 = pToken;
+ }
+ // quit if one of the tokens is not given
+ if ( pToken1 == NULL || pToken2 == NULL )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber( p->pReader, 0 );
+ sprintf( p->sError, "An output of a two-output gate \"%s\" is not specified.", vTokens->pArray[1] );
+ Io_ReadVerPrintErrorMessage( p );
+ return 0;
+ }
+
+ // add the fanout net
+ pNet = Abc_NtkFindNet( pNtk, pToken1 );
+ if ( pNet == NULL )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber( p->pReader, 0 );
+ sprintf( p->sError, "Cannot find net \"%s\".", pToken1 );
+ Io_ReadVerPrintErrorMessage( p );
+ return 0;
+ }
+ Abc_ObjAddFanin( pNet, pNode1 );
+
+ // add the fanout net
+ pNet = Abc_NtkFindNet( pNtk, pToken2 );
+ if ( pNet == NULL )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber( p->pReader, 0 );
+ sprintf( p->sError, "Cannot find net \"%s\".", pToken2 );
+ Io_ReadVerPrintErrorMessage( p );
+ return 0;
+ }
+ Abc_ObjAddFanin( pNet, pNode2 );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads a latch from the verilog file.]
+
+ Description [This procedure treats T-latch as if it were D-latch.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Io_ReadVerNetworkLatch( Io_ReadVer_t * p, Abc_Ntk_t * pNtk, Vec_Ptr_t * vTokens )
+{
+ Abc_Obj_t * pLatch, * pNet, * pNode;
+ char * pToken, * pToken2, * pTokenRN, * pTokenSN, * pTokenSI, * pTokenSE, * pTokenD, * pTokenQ, * pTokenQN;
+ int k, fRN1, fSN1;
+
+ // collect the FF signals
+ pTokenRN = pTokenSN = pTokenSI = pTokenSE = pTokenD = pTokenQ = pTokenQN = NULL;
+ for ( k = 2; k < vTokens->nSize-1; k++ )
+ {
+ pToken = vTokens->pArray[k];
+ pToken2 = vTokens->pArray[k+1];
+ if ( pToken[1] == 'R' && pToken[2] == 'N' && pToken[3] == 0 )
+ pTokenRN = (pToken2[0] == '.')? NULL : pToken2;
+ else if ( pToken[1] == 'S' && pToken[2] == 'N' && pToken[3] == 0 )
+ pTokenSN = (pToken2[0] == '.')? NULL : pToken2;
+ else if ( pToken[1] == 'S' && pToken[2] == 'I' && pToken[3] == 0 )
+ pTokenSI = (pToken2[0] == '.')? NULL : pToken2;
+ else if ( pToken[1] == 'S' && pToken[2] == 'E' && pToken[3] == 0 )
+ pTokenSE = (pToken2[0] == '.')? NULL : pToken2;
+ else if ( pToken[1] == 'D' && pToken[2] == 0 )
+ pTokenD = (pToken2[0] == '.')? NULL : pToken2;
+ else if ( pToken[1] == 'Q' && pToken[2] == 0 )
+ pTokenQ = (pToken2[0] == '.')? NULL : pToken2;
+ else if ( pToken[1] == 'Q' && pToken[2] == 'N' && pToken[3] == 0 )
+ pTokenQN = (pToken2[0] == '.')? NULL : pToken2;
+ else if ( pToken[1] == 'C' && pToken[2] == 'K' && pToken[3] == 0 ) {}
+ else
+ assert( 0 );
+ if ( pToken2[0] != '.' )
+ k++;
+ }
+
+ if ( pTokenD == NULL )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber( p->pReader, 1 );
+ sprintf( p->sError, "Cannot read pin D of the latch \"%s\".", vTokens->pArray[1] );
+ Io_ReadVerPrintErrorMessage( p );
+ return 0;
+ }
+ if ( pTokenQ == NULL && pTokenQN == NULL )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber( p->pReader, 1 );
+ sprintf( p->sError, "Cannot read pins Q/QN of the latch \"%s\".", vTokens->pArray[1] );
+ Io_ReadVerPrintErrorMessage( p );
+ return 0;
+ }
+ if ( (pTokenRN == NULL) ^ (pTokenSN == NULL) )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber( p->pReader, 1 );
+ sprintf( p->sError, "Cannot read pins RN/SN of the latch \"%s\".", vTokens->pArray[1] );
+ Io_ReadVerPrintErrorMessage( p );
+ return 0;
+ }
+
+ // create the latch
+ pLatch = Abc_NtkCreateLatch( pNtk );
+ // create the LO (PI)
+ pNet = Abc_NtkFindOrCreateNet( pNtk, vTokens->pArray[1] );
+ Abc_ObjAddFanin( pNet, pLatch );
+ Abc_ObjSetSubtype( pNet, ABC_OBJ_SUBTYPE_LO );
+ // save the LI (PO)
+ pNet = Abc_NtkFindNet( pNtk, pTokenD );
+ if ( pNet == NULL )
+ {
+ // check the case if it is not a constant input
+ if ( strcmp( pTokenD, "1'b0" ) && strcmp( pTokenD, "1'b1" ) )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber( p->pReader, 0 );
+ sprintf( p->sError, "Cannot find latch input net \"%s\".", pTokenD );
+ Io_ReadVerPrintErrorMessage( p );
+ return 0;
+ }
+
+ // create the constant net
+ if ( strcmp( pTokenD, "1'b0" ) == 0 )
+ pNet = Abc_NtkFindOrCreateNet( pNtk, "Constant0" );
+ else
+ pNet = Abc_NtkFindOrCreateNet( pNtk, "Constant1" );
+
+ // drive it with the constant node
+ if ( Abc_ObjFaninNum( pNet ) == 0 )
+ {
+ // allocate constant node
+ pNode = Abc_NtkCreateNode( pNtk );
+ // set the constant function
+ if ( strcmp( pTokenD, "1'b0" ) == 0 )
+ Abc_ObjSetData( pNode, Abc_SopRegister(pNtk->pManFunc, " 0\n") );
+ else
+ Abc_ObjSetData( pNode, Abc_SopRegister(pNtk->pManFunc, " 1\n") );
+ // add the fanout net
+ Abc_ObjAddFanin( pNet, pNode );
+ }
+ }
+ Abc_ObjAddFanin( pLatch, pNet );
+ Abc_ObjSetSubtype( pNet, ABC_OBJ_SUBTYPE_LI );
+
+ // create the buffer if Q signal is available
+ if ( pTokenQ )
+ {
+ // create the node
+ pNode = Abc_NtkCreateNode( pNtk);
+ // set the function
+ Abc_ObjSetData( pNode, Abc_SopRegister(pNtk->pManFunc, "1 1\n") );
+ // create fanin and fanout nets
+ pNet = Abc_NtkFindNet( pNtk, vTokens->pArray[1] );
+ Abc_ObjAddFanin( pNode, pNet );
+ pNet = Abc_NtkFindNet( pNtk, pTokenQ );
+ if ( pNet == NULL )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber( p->pReader, 0 );
+ sprintf( p->sError, "Cannot find latch output net \"%s\".", pTokenQ );
+ Io_ReadVerPrintErrorMessage( p );
+ return 0;
+ }
+ Abc_ObjAddFanin( pNet, pNode );
+ }
+ if ( pTokenQN )
+ {
+ // create the node
+ pNode = Abc_NtkCreateNode( pNtk );
+ // set the function
+ Abc_ObjSetData( pNode, Abc_SopRegister(pNtk->pManFunc, "0 1\n") );
+ // create fanin and fanout nets
+ pNet = Abc_NtkFindNet( pNtk, vTokens->pArray[1] );
+ Abc_ObjAddFanin( pNode, pNet );
+ pNet = Abc_NtkFindNet( pNtk, pTokenQN );
+ if ( pNet == NULL )
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber( p->pReader, 0 );
+ sprintf( p->sError, "Cannot find latch output net \"%s\".", pTokenQN );
+ Io_ReadVerPrintErrorMessage( p );
+ return 0;
+ }
+ Abc_ObjAddFanin( pNet, pNode );
+ }
+
+ // set the initial value
+ if ( pTokenRN == NULL && pTokenSN == NULL )
+ Abc_ObjSetData( pLatch, (char *)2 );
+ else
+ {
+ fRN1 = (strcmp( pTokenRN, "1'b1" ) == 0);
+ fSN1 = (strcmp( pTokenSN, "1'b1" ) == 0);
+ if ( fRN1 && fSN1 )
+ Abc_ObjSetData( pLatch, (char *)2 );
+ else if ( fRN1 )
+ Abc_ObjSetData( pLatch, (char *)1 );
+ else if ( fSN1 )
+ Abc_ObjSetData( pLatch, (char *)0 );
+ else
+ {
+ p->LineCur = Extra_FileReaderGetLineNumber( p->pReader, 0 );
+ sprintf( p->sError, "Cannot read the initial value of latch \"%s\".", vTokens->pArray[1] );
+ Io_ReadVerPrintErrorMessage( p );
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads the verilog file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_ReadSetNonDrivenNets( Abc_Ntk_t * pNtk )
+{
+ Vec_Ptr_t * vNets;
+ Abc_Obj_t * pNet, * pNode;
+ int i;
+
+ // check for non-driven nets
+ vNets = Vec_PtrAlloc( 100 );
+ Abc_NtkForEachNet( pNtk, pNet, i )
+ {
+ if ( !Abc_ObjIsPi(pNet) && Abc_ObjFaninNum(pNet) == 0 )
+ {
+ // add the constant 0 driver
+ pNode = Abc_NtkCreateNode( pNtk );
+ // set the constant function
+ Abc_ObjSetData( pNode, Abc_SopRegister(pNtk->pManFunc, " 0\n") );
+ // add the fanout net
+ Abc_ObjAddFanin( pNet, pNode );
+ // add the net to those for which the warning will be printed
+ Vec_PtrPush( vNets, pNet->pData );
+ }
+ }
+
+ // print the warning
+ if ( vNets->nSize > 0 )
+ {
+ printf( "The reader added constant-zero driver to %d non-driven nets:\n", vNets->nSize );
+ for ( i = 0; i < vNets->nSize; i++ )
+ {
+ if ( i == 0 )
+ printf( "%s", vNets->pArray[i] );
+ else if ( i == 1 )
+ printf( ", %s", vNets->pArray[i] );
+ else if ( i == 2 )
+ {
+ printf( ", %s, etc.", vNets->pArray[i] );
+ break;
+ }
+ }
+ printf( "\n" );
+ }
+ Vec_PtrFree( vNets );
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
+
diff --git a/src/base/io/ioWriteBench.c b/src/base/io/ioWriteBench.c
new file mode 100644
index 00000000..954c2238
--- /dev/null
+++ b/src/base/io/ioWriteBench.c
@@ -0,0 +1,224 @@
+/**CFile****************************************************************
+
+ FileName [ioWriteBench.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Command processing package.]
+
+ Synopsis [Procedures to write the network in BENCH format.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: ioWriteBench.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "io.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Io_WriteBenchOne( FILE * pFile, Abc_Ntk_t * pNtk );
+static int Io_WriteBenchOneNode( FILE * pFile, Abc_Obj_t * pNode );
+static char * Io_BenchNodeName( Abc_Obj_t * pObj, int fPhase );
+static char * Io_BenchNodeNameInv( Abc_Obj_t * pObj );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Writes the network in BENCH format.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Io_WriteBench( Abc_Ntk_t * pNtk, char * pFileName )
+{
+ Abc_Ntk_t * pExdc;
+ FILE * pFile;
+ assert( Abc_NtkIsAig(pNtk) );
+ pFile = fopen( pFileName, "w" );
+ if ( pFile == NULL )
+ {
+ fprintf( stdout, "Io_WriteBench(): Cannot open the output file.\n" );
+ return 0;
+ }
+ fprintf( pFile, "# Benchmark \"%s\" written by ABC on %s\n", pNtk->pSpec, Extra_TimeStamp() );
+ // write the network
+ Io_WriteBenchOne( pFile, pNtk );
+ // write EXDC network if it exists
+ pExdc = Abc_NtkExdc( pNtk );
+ if ( pExdc )
+ {
+ printf( "Io_WriteBench: EXDC is not written (warning).\n" );
+// fprintf( pFile, "\n" );
+// fprintf( pFile, ".exdc\n" );
+// Io_LogicWriteOne( pFile, pExdc );
+ }
+ // finalize the file
+ fclose( pFile );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Writes the network in BENCH format.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Io_WriteBenchOne( FILE * pFile, Abc_Ntk_t * pNtk )
+{
+ ProgressBar * pProgress;
+ Abc_Obj_t * pNode;
+ int i;
+
+ assert( Abc_NtkIsLogicSop(pNtk) || Abc_NtkIsAig(pNtk) );
+
+ // write the PIs/POs/latches
+ Abc_NtkForEachPi( pNtk, pNode, i )
+ fprintf( pFile, "INPUT(%s)\n", Abc_NtkNamePi(pNtk,i) );
+ Abc_NtkForEachPo( pNtk, pNode, i )
+ fprintf( pFile, "OUTPUT(%s)\n", Abc_NtkNamePo(pNtk,i) );
+ Abc_NtkForEachLatch( pNtk, pNode, i )
+ fprintf( pFile, "%-11s = DFF(%s)\n",
+ Abc_NtkNameLatch(pNtk,i), Abc_NtkNameLatchInput(pNtk,i) );
+
+ // set the node names
+ Abc_NtkCleanCopy( pNtk );
+ Abc_NtkForEachCi( pNtk, pNode, i )
+ pNode->pCopy = (Abc_Obj_t *)Abc_NtkNameCi(pNtk,i);
+
+ // write intervers for COs appearing in negative polarity
+ Abc_NtkForEachCi( pNtk, pNode, i )
+ {
+ if ( Abc_AigNodeIsUsedCompl(pNode) )
+ fprintf( pFile, "%-11s = NOT(%s)\n",
+ Io_BenchNodeNameInv(pNode),
+ Abc_NtkNameCi(pNtk,i) );
+ }
+
+ // write internal nodes
+ pProgress = Extra_ProgressBarStart( stdout, Abc_NtkNodeNum(pNtk) );
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ Extra_ProgressBarUpdate( pProgress, i, NULL );
+ if ( Abc_NodeIsConst(pNode) )
+ continue;
+ Io_WriteBenchOneNode( pFile, pNode );
+ }
+ Extra_ProgressBarStop( pProgress );
+
+ // write buffers for CO
+ Abc_NtkForEachCo( pNtk, pNode, i )
+ {
+ fprintf( pFile, "%-11s = BUFF(%s)\n",
+ (i < Abc_NtkPoNum(pNtk))? Abc_NtkNamePo(pNtk,i) :
+ Abc_NtkNameLatchInput( pNtk, i-Abc_NtkPoNum(pNtk) ),
+ Io_BenchNodeName( Abc_ObjFanin0(pNode), !Abc_ObjFaninC0(pNode) ) );
+ }
+ Abc_NtkCleanCopy( pNtk );
+ return 1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Writes the network in BENCH format.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Io_WriteBenchOneNode( FILE * pFile, Abc_Obj_t * pNode )
+{
+ assert( Abc_ObjIsNode(pNode) );
+ // write the AND gate
+ fprintf( pFile, "%-11s", Io_BenchNodeName( pNode, 1 ) );
+ fprintf( pFile, " = AND(%s, ", Io_BenchNodeName( Abc_ObjFanin0(pNode), !Abc_ObjFaninC0(pNode) ) );
+ fprintf( pFile, "%s)\n", Io_BenchNodeName( Abc_ObjFanin1(pNode), !Abc_ObjFaninC1(pNode) ) );
+
+ // write the inverter if necessary
+ if ( Abc_AigNodeIsUsedCompl(pNode) )
+ {
+ fprintf( pFile, "%-11s = NOT(", Io_BenchNodeName( pNode, 0 ) );
+ fprintf( pFile, "%s)\n", Io_BenchNodeName( pNode, 1 ) );
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the name of an internal AIG node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Io_BenchNodeName( Abc_Obj_t * pObj, int fPhase )
+{
+ static char Buffer[500];
+ if ( pObj->pCopy ) // PIs and latches
+ {
+ sprintf( Buffer, "%s%s", (char *)pObj->pCopy, (fPhase? "":"_c") );
+ return Buffer;
+ }
+ assert( Abc_ObjIsNode(pObj) );
+ if ( Abc_NodeIsConst(pObj) ) // constant node
+ {
+ if ( fPhase )
+ sprintf( Buffer, "%s", "vdd" );
+ else
+ sprintf( Buffer, "%s", "gnd" );
+ return Buffer;
+ }
+ // internal nodes
+ sprintf( Buffer, "%s%s", Abc_ObjName(pObj), (fPhase? "":"_c") );
+ return Buffer;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the name of an internal AIG node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Io_BenchNodeNameInv( Abc_Obj_t * pObj )
+{
+ static char Buffer[500];
+ sprintf( Buffer, "%s%s", Abc_ObjName(pObj), "_c" );
+ return Buffer;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/io/ioWriteBlif.c b/src/base/io/ioWriteBlif.c
new file mode 100644
index 00000000..d9c69273
--- /dev/null
+++ b/src/base/io/ioWriteBlif.c
@@ -0,0 +1,344 @@
+/**CFile****************************************************************
+
+ FileName [ioWriteBlif.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Command processing package.]
+
+ Synopsis [Procedures to write BLIF files.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: ioWriteBlif.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "io.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Io_NtkWriteOne( FILE * pFile, Abc_Ntk_t * pNtk );
+static void Io_NtkWritePis( FILE * pFile, Abc_Ntk_t * pNtk );
+static void Io_NtkWritePos( FILE * pFile, Abc_Ntk_t * pNtk );
+static void Io_NtkWriteNodeFanins( FILE * pFile, Abc_Obj_t * pNode );
+static void Io_NtkWriteNode( FILE * pFile, Abc_Obj_t * pNode );
+static void Io_NtkWriteLatch( FILE * pFile, Abc_Obj_t * pLatch );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Write the network into a BLIF file with the given name.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_WriteBlif( Abc_Ntk_t * pNtk, char * FileName )
+{
+ Abc_Ntk_t * pExdc;
+ FILE * pFile;
+ assert( Abc_NtkIsNetlist(pNtk) );
+ pFile = fopen( FileName, "w" );
+ if ( pFile == NULL )
+ {
+ fprintf( stdout, "Io_WriteBlif(): Cannot open the output file.\n" );
+ return;
+ }
+ // write the model name
+ fprintf( pFile, ".model %s\n", Abc_NtkName(pNtk) );
+ // write the network
+ Io_NtkWriteOne( pFile, pNtk );
+ // write EXDC network if it exists
+ pExdc = Abc_NtkExdc( pNtk );
+ if ( pExdc )
+ {
+ fprintf( pFile, "\n" );
+ fprintf( pFile, ".exdc\n" );
+ Io_NtkWriteOne( pFile, pExdc );
+ }
+ // finalize the file
+ fprintf( pFile, ".end\n" );
+ fclose( pFile );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Write one network.]
+
+ Description [Writes a network composed of PIs, POs, internal nodes,
+ and latches. The following rules are used to print the names of
+ internal nodes:
+ ]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_NtkWriteOne( FILE * pFile, Abc_Ntk_t * pNtk )
+{
+ ProgressBar * pProgress;
+ Abc_Obj_t * pNode, * pLatch;
+ int i;
+
+ // write the PIs
+ fprintf( pFile, ".inputs" );
+ Io_NtkWritePis( pFile, pNtk );
+ fprintf( pFile, "\n" );
+
+ // write the POs
+ fprintf( pFile, ".outputs" );
+ Io_NtkWritePos( pFile, pNtk );
+ fprintf( pFile, "\n" );
+
+ // write the timing info
+ Io_WriteTimingInfo( pFile, pNtk );
+
+ // write the latches
+ if ( !Abc_NtkIsComb(pNtk) )
+ {
+ fprintf( pFile, "\n" );
+ Abc_NtkForEachLatch( pNtk, pLatch, i )
+ Io_NtkWriteLatch( pFile, pLatch );
+ fprintf( pFile, "\n" );
+ }
+
+ // write each internal node
+ pProgress = Extra_ProgressBarStart( stdout, Abc_NtkNodeNum(pNtk) );
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ Extra_ProgressBarUpdate( pProgress, i, NULL );
+ Io_NtkWriteNode( pFile, pNode );
+ }
+ Extra_ProgressBarStop( pProgress );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Writes the primary input list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_NtkWritePis( FILE * pFile, Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNet;
+ int LineLength;
+ int AddedLength;
+ int NameCounter;
+ int i;
+
+ LineLength = 7;
+ NameCounter = 0;
+ Abc_NtkForEachPi( pNtk, pNet, i )
+ {
+ // get the line length after this name is written
+ AddedLength = strlen(Abc_ObjName(pNet)) + 1;
+ if ( NameCounter && LineLength + AddedLength + 3 > IO_WRITE_LINE_LENGTH )
+ { // write the line extender
+ fprintf( pFile, " \\\n" );
+ // reset the line length
+ LineLength = 0;
+ NameCounter = 0;
+ }
+ fprintf( pFile, " %s", Abc_ObjName(pNet) );
+ LineLength += AddedLength;
+ NameCounter++;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Writes the primary input list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_NtkWritePos( FILE * pFile, Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNet;
+ int LineLength;
+ int AddedLength;
+ int NameCounter;
+ int i;
+
+ LineLength = 8;
+ NameCounter = 0;
+ Abc_NtkForEachPo( pNtk, pNet, i )
+ {
+ // get the line length after this name is written
+ AddedLength = strlen(Abc_ObjName(pNet)) + 1;
+ if ( NameCounter && LineLength + AddedLength + 3 > IO_WRITE_LINE_LENGTH )
+ { // write the line extender
+ fprintf( pFile, " \\\n" );
+ // reset the line length
+ LineLength = 0;
+ NameCounter = 0;
+ }
+ fprintf( pFile, " %s", Abc_ObjName(pNet) );
+ LineLength += AddedLength;
+ NameCounter++;
+ }
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Write the latch into a file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_NtkWriteLatch( FILE * pFile, Abc_Obj_t * pLatch )
+{
+ Abc_Obj_t * pNetLi, * pNetLo;
+ int Reset;
+ pNetLi = Abc_ObjFanin0( pLatch );
+ pNetLo = Abc_ObjFanout0( pLatch );
+ Reset = (int)Abc_ObjData( pLatch );
+ // write the latch line
+ fprintf( pFile, ".latch" );
+ fprintf( pFile, " %10s", Abc_ObjName(pNetLi) );
+ fprintf( pFile, " %10s", Abc_ObjName(pNetLo) );
+ fprintf( pFile, " %d\n", Reset );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Write the node into a file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_NtkWriteNode( FILE * pFile, Abc_Obj_t * pNode )
+{
+ // write the .names line
+ fprintf( pFile, ".names" );
+ Io_NtkWriteNodeFanins( pFile, pNode );
+ fprintf( pFile, "\n" );
+ // write the cubes
+ fprintf( pFile, "%s", Abc_ObjData(pNode) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Writes the primary input list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_NtkWriteNodeFanins( FILE * pFile, Abc_Obj_t * pNode )
+{
+ Abc_Obj_t * pNet;
+ int LineLength;
+ int AddedLength;
+ int NameCounter;
+ char * pName;
+ int i;
+
+ LineLength = 6;
+ NameCounter = 0;
+ Abc_ObjForEachFanin( pNode, pNet, i )
+ {
+ // get the fanin name
+ pName = Abc_ObjName(pNet);
+ // get the line length after the fanin name is written
+ AddedLength = strlen(pName) + 1;
+ if ( NameCounter && LineLength + AddedLength + 3 > IO_WRITE_LINE_LENGTH )
+ { // write the line extender
+ fprintf( pFile, " \\\n" );
+ // reset the line length
+ LineLength = 0;
+ NameCounter = 0;
+ }
+ fprintf( pFile, " %s", pName );
+ LineLength += AddedLength;
+ NameCounter++;
+ }
+
+ // get the output name
+ pName = Abc_ObjName(Abc_ObjFanout0(pNode));
+ // get the line length after the output name is written
+ AddedLength = strlen(pName) + 1;
+ if ( NameCounter && LineLength + AddedLength > 75 )
+ { // write the line extender
+ fprintf( pFile, " \\\n" );
+ // reset the line length
+ LineLength = 0;
+ NameCounter = 0;
+ }
+ fprintf( pFile, " %s", pName );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Writes the timing info.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_WriteTimingInfo( FILE * pFile, Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ Abc_Time_t * pTime, * pTimeDef;
+ int i;
+
+ if ( pNtk->pManTime == NULL )
+ return;
+
+ pTimeDef = Abc_NtkReadDefaultArrival( pNtk );
+ fprintf( pFile, ".default_input_arrival %g %g\n", pTimeDef->Rise, pTimeDef->Fall );
+ Abc_NtkForEachPi( pNtk, pNode, i )
+ {
+ pTime = Abc_NodeReadArrival(pNode);
+ if ( pTime->Rise == pTimeDef->Rise && pTime->Fall == pTimeDef->Fall )
+ continue;
+ fprintf( pFile, ".input_arrival %s %g %g\n", Abc_NtkNamePi(pNtk,i), pTime->Rise, pTime->Fall );
+ }
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/io/ioWriteBlifLogic.c b/src/base/io/ioWriteBlifLogic.c
new file mode 100644
index 00000000..aa1d65b9
--- /dev/null
+++ b/src/base/io/ioWriteBlifLogic.c
@@ -0,0 +1,402 @@
+/**CFile****************************************************************
+
+ FileName [ioWriteBlifLogic.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Command processing package.]
+
+ Synopsis [Procedures to write BLIF files for a logic network.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: ioWriteBlifLogic.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "io.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Io_LogicWriteOne( FILE * pFile, Abc_Ntk_t * pNtk, int fWriteLatches );
+static void Io_LogicWritePis( FILE * pFile, Abc_Ntk_t * pNtk, int fWriteLatches );
+static void Io_LogicWritePos( FILE * pFile, Abc_Ntk_t * pNtk, int fWriteLatches );
+static void Io_LogicWriteNodeFanins( FILE * pFile, Abc_Obj_t * pNode, int fMark );
+static void Io_LogicWriteNode( FILE * pFile, Abc_Obj_t * pNode );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Write the network into a BLIF file with the given name.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_WriteBlifLogic( Abc_Ntk_t * pNtk, char * FileName, int fWriteLatches )
+{
+ Abc_Ntk_t * pExdc;
+ FILE * pFile;
+ assert( !Abc_NtkIsNetlist(pNtk) );
+ pFile = fopen( FileName, "w" );
+ if ( pFile == NULL )
+ {
+ fprintf( stdout, "Io_WriteBlifLogic(): Cannot open the output file.\n" );
+ return;
+ }
+ // write the model name
+ fprintf( pFile, ".model %s\n", Abc_NtkName(pNtk) );
+ // write the network
+ Io_LogicWriteOne( pFile, pNtk, fWriteLatches );
+ // write EXDC network if it exists
+ pExdc = Abc_NtkExdc( pNtk );
+ if ( pExdc )
+ {
+ fprintf( pFile, "\n" );
+ fprintf( pFile, ".exdc\n" );
+ Io_LogicWriteOne( pFile, pExdc, 0 );
+ }
+ // finalize the file
+ fprintf( pFile, ".end\n" );
+ fclose( pFile );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Write one network.]
+
+ Description [Writes a network composed of PIs, POs, internal nodes,
+ and latches. The following rules are used to print the names of
+ internal nodes: ]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_LogicWriteOne( FILE * pFile, Abc_Ntk_t * pNtk, int fWriteLatches )
+{
+ ProgressBar * pProgress;
+ Abc_Obj_t * pNode, * pLatch, * pDriver;
+ Vec_Ptr_t * vNodes;
+ int i;
+
+ assert( Abc_NtkIsLogicSop(pNtk) || Abc_NtkIsAig(pNtk) );
+
+ // print a warning about choice nodes
+ if ( i = Abc_NtkCountChoiceNodes( pNtk ) )
+ printf( "Warning: The AIG is written into the file, including %d choice nodes.\n", i );
+
+ // write the PIs
+ fprintf( pFile, ".inputs" );
+ Io_LogicWritePis( pFile, pNtk, fWriteLatches );
+ fprintf( pFile, "\n" );
+
+ // write the POs
+ fprintf( pFile, ".outputs" );
+ Io_LogicWritePos( pFile, pNtk, fWriteLatches );
+ fprintf( pFile, "\n" );
+
+ if ( fWriteLatches )
+ {
+ // write the timing info
+ Io_WriteTimingInfo( pFile, pNtk );
+ // write the latches
+ if ( Abc_NtkLatchNum(pNtk) )
+ {
+ fprintf( pFile, "\n" );
+ Abc_NtkForEachLatch( pNtk, pLatch, i )
+ fprintf( pFile, ".latch %10s %10s %d\n",
+ Abc_NtkNameLatchInput(pNtk,i), Abc_NtkNameLatch(pNtk,i), (int)pLatch->pData );
+ fprintf( pFile, "\n" );
+ }
+ }
+
+ // set the node names
+ Abc_NtkLogicTransferNames( pNtk );
+
+ // collect internal nodes
+ if ( Abc_NtkIsAig(pNtk) )
+ vNodes = Abc_AigDfs( pNtk );
+ else
+ vNodes = Abc_NtkDfs( pNtk );
+ // write internal nodes
+ pProgress = Extra_ProgressBarStart( stdout, vNodes->nSize );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ {
+ Extra_ProgressBarUpdate( pProgress, i, NULL );
+ Io_LogicWriteNode( pFile, Vec_PtrEntry(vNodes, i) );
+ }
+ Extra_ProgressBarStop( pProgress );
+ Vec_PtrFree( vNodes );
+
+ // write inverters/buffers for each CO
+ Abc_NtkForEachLatch( pNtk, pLatch, i )
+ {
+ pDriver = Abc_ObjFanin0(pLatch);
+ // consider the case when the latch is driving itself
+ if ( pDriver == pLatch )
+ {
+ fprintf( pFile, ".names %s %s\n%d 1\n",
+ Abc_NtkNameLatch(pNtk,i), Abc_NtkNameLatchInput(pNtk,i), !Abc_ObjFaninC0(pLatch) );
+ continue;
+ }
+ // skip if they have the same name
+ if ( pDriver->pCopy && strcmp( (char *)pDriver->pCopy, Abc_NtkNameLatchInput(pNtk,i) ) == 0 )
+ {
+ /*
+ Abc_Obj_t * pFanout;
+ int k;
+ printf( "latch name = %s.\n", (char *)pLatch->pCopy );
+ printf( "driver name = %s.\n", (char *)pDriver->pCopy );
+ Abc_ObjForEachFanout( pDriver, pFanout, k )
+ printf( "driver's fanout name = %s. Fanins = %d. Compl0 = %d. \n",
+ Abc_ObjName(pFanout), Abc_ObjFaninNum(pFanout), Abc_ObjFaninC0(pFanout) );
+ */
+ assert( !Abc_ObjFaninC0(pLatch) );
+ continue;
+ }
+ // write inverter/buffer depending on whether the edge is complemented
+ fprintf( pFile, ".names %s %s\n%d 1\n",
+ Abc_ObjName(pDriver), Abc_NtkNameLatchInput(pNtk,i), !Abc_ObjFaninC0(pLatch) );
+ }
+ Abc_NtkForEachPo( pNtk, pNode, i )
+ {
+ pDriver = Abc_ObjFanin0(pNode);
+ // skip if they have the same name
+ if ( pDriver->pCopy && strcmp( (char *)pDriver->pCopy, Abc_NtkNamePo(pNtk,i) ) == 0 )
+ {
+ assert( !Abc_ObjFaninC0(pNode) );
+ continue;
+ }
+ // write inverter/buffer depending on whether the PO is complemented
+ fprintf( pFile, ".names %s %s\n%d 1\n",
+ Abc_ObjName(pDriver), Abc_NtkNamePo(pNtk,i), !Abc_ObjFaninC0(pNode) );
+ }
+ Abc_NtkCleanCopy( pNtk );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Writes the primary input list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_LogicWritePis( FILE * pFile, Abc_Ntk_t * pNtk, int fWriteLatches )
+{
+ char * pName;
+ int LineLength;
+ int AddedLength;
+ int NameCounter;
+ int nLimit;
+ int i;
+
+ LineLength = 7;
+ NameCounter = 0;
+ nLimit = fWriteLatches? Abc_NtkPiNum(pNtk) : Abc_NtkCiNum(pNtk);
+ for ( i = 0; i < nLimit; i++ )
+ {
+ pName = pNtk->vNamesPi->pArray[i];
+ // get the line length after this name is written
+ AddedLength = strlen(pName) + 1;
+ if ( NameCounter && LineLength + AddedLength + 3 > IO_WRITE_LINE_LENGTH )
+ { // write the line extender
+ fprintf( pFile, " \\\n" );
+ // reset the line length
+ LineLength = 0;
+ NameCounter = 0;
+ }
+ fprintf( pFile, " %s", pName );
+ LineLength += AddedLength;
+ NameCounter++;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Writes the primary input list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_LogicWritePos( FILE * pFile, Abc_Ntk_t * pNtk, int fWriteLatches )
+{
+ char * pName;
+ int LineLength;
+ int AddedLength;
+ int NameCounter;
+ int nLimit;
+ int i;
+
+ LineLength = 8;
+ NameCounter = 0;
+ nLimit = fWriteLatches? Abc_NtkPoNum(pNtk) : Abc_NtkCoNum(pNtk);
+ for ( i = 0; i < nLimit; i++ )
+ {
+ pName = pNtk->vNamesPo->pArray[i];
+ // get the line length after this name is written
+ AddedLength = strlen(pName) + 1;
+ if ( NameCounter && LineLength + AddedLength + 3 > IO_WRITE_LINE_LENGTH )
+ { // write the line extender
+ fprintf( pFile, " \\\n" );
+ // reset the line length
+ LineLength = 0;
+ NameCounter = 0;
+ }
+ fprintf( pFile, " %s", pName );
+ LineLength += AddedLength;
+ NameCounter++;
+ }
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Write the node into a file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_LogicWriteNode( FILE * pFile, Abc_Obj_t * pNode )
+{
+ Abc_Obj_t * pTemp;
+ int i, k, nFanins, fMark;
+
+ assert( !Abc_ObjIsComplement( pNode ) );
+ assert( Abc_ObjIsNode(pNode) );
+
+ // set the mark that is true if the node is a choice node
+ fMark = Abc_NtkIsAig(pNode->pNtk) && Abc_NodeIsChoice(pNode);
+
+ // write the .names line
+ fprintf( pFile, ".names" );
+ Io_LogicWriteNodeFanins( pFile, pNode, fMark );
+ fprintf( pFile, "\n" );
+ // write the cubes
+ if ( Abc_NtkIsLogicSop(pNode->pNtk) )
+ fprintf( pFile, "%s", Abc_ObjData(pNode) );
+ else if ( Abc_NtkIsAig(pNode->pNtk) )
+ {
+ if ( pNode == Abc_AigConst1(pNode->pNtk->pManFunc) )
+ {
+ fprintf( pFile, " 1\n" );
+ return;
+ }
+
+ assert( Abc_ObjFaninNum(pNode) == 2 );
+ // write the AND gate
+ for ( i = 0; i < 2; i++ )
+ fprintf( pFile, "%d", !Abc_ObjFaninC(pNode,i) );
+ fprintf( pFile, " 1\n" );
+ // write the choice node if present
+ if ( fMark )
+ {
+ // count the number of fanins of the choice node and write the names line
+ nFanins = 1;
+ fprintf( pFile, ".names %sc", Abc_ObjName(pNode) );
+ for ( pTemp = pNode->pData; pTemp; pTemp = pTemp->pData, nFanins++ )
+ fprintf( pFile, " %s", Abc_ObjName(pTemp) );
+ fprintf( pFile, " %s\n", Abc_ObjName(pNode) );
+ // write the cubes for each of the fanins
+ for ( i = 0, pTemp = pNode; pTemp; pTemp = pTemp->pData, i++ )
+ {
+ for ( k = 0; k < nFanins; k++ )
+ if ( k == i )
+ fprintf( pFile, "%d", (int)(pNode->fPhase == pTemp->fPhase) );
+ else
+ fprintf( pFile, "-" );
+ fprintf( pFile, " 1\n" );
+ }
+ }
+ }
+ else
+ {
+ assert( 0 );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Writes the primary input list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_LogicWriteNodeFanins( FILE * pFile, Abc_Obj_t * pNode, int fMark )
+{
+ Abc_Obj_t * pFanin;
+ int LineLength;
+ int AddedLength;
+ int NameCounter;
+ char * pName;
+ int i;
+
+ LineLength = 6;
+ NameCounter = 0;
+ Abc_ObjForEachFanin( pNode, pFanin, i )
+ {
+ // get the fanin name
+ pName = Abc_ObjName(pFanin);
+ // get the line length after the fanin name is written
+ AddedLength = strlen(pName) + 1;
+ if ( NameCounter && LineLength + AddedLength + 3 > IO_WRITE_LINE_LENGTH )
+ { // write the line extender
+ fprintf( pFile, " \\\n" );
+ // reset the line length
+ LineLength = 0;
+ NameCounter = 0;
+ }
+ fprintf( pFile, " %s", pName );
+ LineLength += AddedLength;
+ NameCounter++;
+ }
+
+ // get the output name
+ pName = Abc_ObjName(pNode);
+ // get the line length after the output name is written
+ AddedLength = strlen(pName) + 1;
+ if ( NameCounter && LineLength + AddedLength > 75 )
+ { // write the line extender
+ fprintf( pFile, " \\\n" );
+ // reset the line length
+ LineLength = 0;
+ NameCounter = 0;
+ }
+ fprintf( pFile, " %s%s", pName, fMark? "c" : "" );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/io/ioWriteCnf.c b/src/base/io/ioWriteCnf.c
new file mode 100644
index 00000000..144ff167
--- /dev/null
+++ b/src/base/io/ioWriteCnf.c
@@ -0,0 +1,76 @@
+/**CFile****************************************************************
+
+ FileName [ioWriteCnf.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Command processing package.]
+
+ Synopsis [Procedures to CNF of the miter cone.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: ioWriteCnf.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "io.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Io_WriteCnfInt( FILE * pFile, Abc_Ntk_t * pNtk );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Write the miter cone into a CNF file for the SAT solver.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Io_WriteCnf( Abc_Ntk_t * pNtk, char * pFileName )
+{
+ solver * pSat;
+ if ( !Abc_NtkIsLogicBdd(pNtk) )
+ {
+ fprintf( stdout, "Io_WriteCnf(): Currently can process logic networks with BDDs.\n" );
+ return 0;
+ }
+ if ( Abc_NtkPoNum(pNtk) != 1 )
+ {
+ fprintf( stdout, "Io_WriteCnf(): Currently can only solve the miter (the network with one PO).\n" );
+ return 0;
+ }
+ if ( Abc_NtkLatchNum(pNtk) != 0 )
+ {
+ fprintf( stdout, "Io_WriteCnf(): Currently can only solve the miter for combinational circuits.\n" );
+ return 0;
+ }
+ // create solver with clauses
+ pSat = Abc_NtkMiterSatCreate( pNtk );
+ // write the clauses
+ Asat_SolverWriteDimacs( pSat, pFileName );
+ // free the solver
+ solver_delete( pSat );
+ return 1;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/io/ioWriteGate.c b/src/base/io/ioWriteGate.c
new file mode 100644
index 00000000..3a3c45eb
--- /dev/null
+++ b/src/base/io/ioWriteGate.c
@@ -0,0 +1,263 @@
+/**CFile****************************************************************
+
+ FileName [ioWriteGate.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Command processing package.]
+
+ Synopsis [Procedures to write the mapped network.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: ioWriteGate.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "io.h"
+#include "main.h"
+#include "mio.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Io_WriteGateOne( FILE * pFile, Abc_Ntk_t * pNtk );
+static void Io_WriteGatePis( FILE * pFile, Abc_Ntk_t * pNtk );
+static void Io_WriteGatePos( FILE * pFile, Abc_Ntk_t * pNtk );
+static void Io_WriteGateNode( FILE * pFile, Abc_Obj_t * pNode, Mio_Gate_t * pGate );
+static char * Io_ReadNodeName( Abc_Obj_t * pNode );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Writes mapped network into a BLIF file compatible with SIS.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Io_WriteGate( Abc_Ntk_t * pNtk, char * pFileName )
+{
+ Abc_Ntk_t * pExdc;
+ FILE * pFile;
+
+ assert( Abc_NtkIsLogicMap(pNtk) );
+ pFile = fopen( pFileName, "w" );
+ if ( pFile == NULL )
+ {
+ fprintf( stdout, "Io_WriteGate(): Cannot open the output file.\n" );
+ return 0;
+ }
+ // write the model name
+ fprintf( pFile, ".model %s\n", Abc_NtkName(pNtk) );
+ // write the network
+ Io_WriteGateOne( pFile, pNtk );
+ // write EXDC network if it exists
+ pExdc = Abc_NtkExdc( pNtk );
+ if ( pExdc )
+ printf( "Io_WriteGate: EXDC is not written (warning).\n" );
+ // finalize the file
+ fprintf( pFile, ".end\n" );
+ fclose( pFile );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Write one network.]
+
+ Description [Writes a network composed of PIs, POs, internal nodes,
+ and latches. The following rules are used to print the names of
+ internal nodes: ]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_WriteGateOne( FILE * pFile, Abc_Ntk_t * pNtk )
+{
+ ProgressBar * pProgress;
+ Abc_Obj_t * pNode, * pLatch;
+ int i;
+
+ assert( Abc_NtkIsLogicMap(pNtk) );
+ assert( Abc_NtkLogicHasSimplePos(pNtk) );
+
+ // write the PIs
+ fprintf( pFile, ".inputs" );
+ Io_WriteGatePis( pFile, pNtk );
+ fprintf( pFile, "\n" );
+
+ // write the POs
+ fprintf( pFile, ".outputs" );
+ Io_WriteGatePos( pFile, pNtk );
+ fprintf( pFile, "\n" );
+
+ // write the timing info
+ Io_WriteTimingInfo( pFile, pNtk );
+
+ // write the latches
+ if ( Abc_NtkLatchNum(pNtk) )
+ {
+ fprintf( pFile, "\n" );
+ Abc_NtkForEachLatch( pNtk, pLatch, i )
+ fprintf( pFile, ".latch %s %s %d\n",
+ Abc_NtkNameLatchInput(pNtk,i), Abc_NtkNameLatch(pNtk,i), (int)pLatch->pData );
+ fprintf( pFile, "\n" );
+ }
+ // set the node names
+ Abc_NtkLogicTransferNames( pNtk );
+ // write internal nodes
+ pProgress = Extra_ProgressBarStart( stdout, Abc_NtkNodeNum(pNtk) );
+ Abc_NtkForEachNode( pNtk, pNode, i )
+ {
+ Extra_ProgressBarUpdate( pProgress, i, NULL );
+ Io_WriteGateNode( pFile, pNode, pNode->pData );
+ }
+ Extra_ProgressBarStop( pProgress );
+ Abc_NtkCleanCopy( pNtk );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Writes the primary input list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_WriteGatePis( FILE * pFile, Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ char * pName;
+ int LineLength;
+ int AddedLength;
+ int NameCounter;
+ int i;
+
+ LineLength = 7;
+ NameCounter = 0;
+ Abc_NtkForEachPi( pNtk, pNode, i )
+ {
+ pName = pNtk->vNamesPi->pArray[i];
+ // get the line length after this name is written
+ AddedLength = strlen(pName) + 1;
+ if ( NameCounter && LineLength + AddedLength + 3 > IO_WRITE_LINE_LENGTH )
+ { // write the line extender
+ fprintf( pFile, " \\\n" );
+ // reset the line length
+ LineLength = 0;
+ NameCounter = 0;
+ }
+ fprintf( pFile, " %s", pName );
+ LineLength += AddedLength;
+ NameCounter++;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Writes the primary input list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_WriteGatePos( FILE * pFile, Abc_Ntk_t * pNtk )
+{
+ Abc_Obj_t * pNode;
+ int LineLength;
+ int AddedLength;
+ int NameCounter;
+ char * pName;
+ int i;
+
+ LineLength = 8;
+ NameCounter = 0;
+ Abc_NtkForEachPo( pNtk, pNode, i )
+ {
+ pName = pNtk->vNamesPo->pArray[i];
+ // get the line length after this name is written
+ AddedLength = strlen(pName) + 1;
+ if ( NameCounter && LineLength + AddedLength + 3 > IO_WRITE_LINE_LENGTH )
+ { // write the line extender
+ fprintf( pFile, " \\\n" );
+ // reset the line length
+ LineLength = 0;
+ NameCounter = 0;
+ }
+ fprintf( pFile, " %s", pName );
+ LineLength += AddedLength;
+ NameCounter++;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Write the node into a file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_WriteGateNode( FILE * pFile, Abc_Obj_t * pNode, Mio_Gate_t * pGate )
+{
+ Mio_Pin_t * pGatePin;
+ int i;
+ // do not write the buffer whose input and output have the same name
+ if ( Abc_ObjFaninNum(pNode) == 1 && Abc_ObjFanin0(pNode)->pCopy && pNode->pCopy )
+ if ( strcmp( (char*)Abc_ObjFanin0(pNode)->pCopy, (char*)pNode->pCopy ) == 0 )
+ return;
+ // write the node
+ fprintf( pFile, ".gate %s ", Mio_GateReadName(pGate) );
+ for ( pGatePin = Mio_GateReadPins(pGate), i = 0; pGatePin; pGatePin = Mio_PinReadNext(pGatePin), i++ )
+ fprintf( pFile, "%s=%s ", Mio_PinReadName(pGatePin), Io_ReadNodeName( Abc_ObjFanin(pNode,i) ) );
+ assert ( i == Abc_ObjFaninNum(pNode) );
+ fprintf( pFile, "%s=%s\n", Mio_GateReadOutName(pGate), Io_ReadNodeName(pNode) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the name of the node to write.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Io_ReadNodeName( Abc_Obj_t * pNode )
+{
+ if ( pNode->pCopy )
+ return (char *)pNode->pCopy;
+ return Abc_ObjName(pNode);
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/io/module.make b/src/base/io/module.make
new file mode 100644
index 00000000..d9f46c2c
--- /dev/null
+++ b/src/base/io/module.make
@@ -0,0 +1,10 @@
+SRC += src/base/io/io.c \
+ src/base/io/ioRead.c \
+ src/base/io/ioReadBench.c \
+ src/base/io/ioReadBlif.c \
+ src/base/io/ioReadVerilog.c \
+ src/base/io/ioWriteBench.c \
+ src/base/io/ioWriteBlif.c \
+ src/base/io/ioWriteBlifLogic.c \
+ src/base/io/ioWriteCnf.c \
+ src/base/io/ioWriteGate.c
diff --git a/src/base/main/main.c b/src/base/main/main.c
new file mode 100644
index 00000000..ed1e929d
--- /dev/null
+++ b/src/base/main/main.c
@@ -0,0 +1,267 @@
+/**CFile****************************************************************
+
+ FileName [main.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [The main package.]
+
+ Synopsis [Here everything starts.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: main.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mainInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int TypeCheck( Abc_Frame_t * pAbc, char * s);
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [The main() procedure.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int main( int argc, char * argv[] )
+{
+ Abc_Frame_t * pAbc;
+ char sCommandUsr[500], sCommandTmp[100], sReadCmd[20], sWriteCmd[20], c;
+ char * sCommand, * sOutFile, * sInFile;
+ int fStatus = 0;
+ bool fBatch, fInitSource, fInitRead, fFinalWrite;
+
+ // added to detect memory leaks:
+#ifdef _DEBUG
+ _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
+#endif
+
+ // get global frame (singleton pattern)
+ // will be initialized on first call
+ pAbc = Abc_FrameGetGlobalFrame();
+
+ // default options
+ fBatch = 0;
+ fInitSource = 1;
+ fInitRead = 0;
+ fFinalWrite = 0;
+ sInFile = sOutFile = NULL;
+ sprintf( sReadCmd, "read_blif_mv" );
+ sprintf( sWriteCmd, "write_blif_mv" );
+
+ util_getopt_reset();
+ while ((c = util_getopt(argc, argv, "c:hf:F:o:st:T:x")) != EOF) {
+ switch(c) {
+ case 'c':
+ strcpy( sCommandUsr, util_optarg );
+ fBatch = 1;
+ break;
+
+ case 'f':
+ sprintf(sCommandUsr, "source %s", util_optarg);
+ fBatch = 1;
+ break;
+
+ case 'F':
+ sprintf(sCommandUsr, "source -x %s", util_optarg);
+ fBatch = 1;
+ break;
+
+ case 'h':
+ goto usage;
+ break;
+
+ case 'o':
+ sOutFile = util_optarg;
+ fFinalWrite = 1;
+ break;
+
+ case 's':
+ fInitSource = 0;
+ break;
+
+ case 't':
+ if ( TypeCheck( pAbc, util_optarg ) )
+ {
+ if ( !strcmp(util_optarg, "none") == 0 )
+ {
+ fInitRead = 1;
+ sprintf( sReadCmd, "read_%s", util_optarg );
+ }
+ }
+ else {
+ goto usage;
+ }
+ fBatch = 1;
+ break;
+
+ case 'T':
+ if ( TypeCheck( pAbc, util_optarg ) )
+ {
+ if (!strcmp(util_optarg, "none") == 0)
+ {
+ fFinalWrite = 1;
+ sprintf( sWriteCmd, "write_%s", util_optarg);
+ }
+ }
+ else {
+ goto usage;
+ }
+ fBatch = 1;
+ break;
+
+ case 'x':
+ fFinalWrite = 0;
+ fInitRead = 0;
+ fBatch = 1;
+ break;
+
+ default:
+ goto usage;
+ }
+ }
+
+ if ( fBatch )
+ {
+ pAbc->fBatchMode = 1;
+
+ if (argc - util_optind == 0)
+ {
+ sInFile = NULL;
+ }
+ else if (argc - util_optind == 1)
+ {
+ fInitRead = 1;
+ sInFile = argv[util_optind];
+ }
+ else
+ {
+ Abc_UtilsPrintUsage( pAbc, argv[0] );
+ }
+
+ // source the resource file
+ if ( fInitSource )
+ {
+ Abc_UtilsSource( pAbc );
+ }
+
+ fStatus = 0;
+ if ( fInitRead && sInFile )
+ {
+ sprintf( sCommandTmp, "%s %s", sReadCmd, sInFile );
+ fStatus = Cmd_CommandExecute( pAbc, sCommandTmp );
+ }
+
+ if ( fStatus == 0 )
+ {
+ /* cmd line contains `source <file>' */
+ fStatus = Cmd_CommandExecute( pAbc, sCommandUsr );
+ if ( (fStatus == 0 || fStatus == -1) && fFinalWrite && sOutFile )
+ {
+ sprintf( sCommandTmp, "%s %s", sWriteCmd, sOutFile );
+ fStatus = Cmd_CommandExecute( pAbc, sCommandTmp );
+ }
+ }
+
+ }
+ else
+ {
+ // start interactive mode
+ // print the hello line
+ Abc_UtilsPrintHello( pAbc );
+
+ // source the resource file
+ if ( fInitSource )
+ {
+ Abc_UtilsSource( pAbc );
+ }
+
+ // execute commands given by the user
+ while ( !feof(stdin) )
+ {
+ // print command line prompt and
+ // get the command from the user
+ sCommand = Abc_UtilsGetUsersInput( pAbc );
+
+ // execute the user's command
+ fStatus = Cmd_CommandExecute( pAbc, sCommand );
+
+ // stop if the user quitted or an error occurred
+ if ( fStatus == -1 || fStatus == -2 )
+ break;
+ }
+ }
+
+ // if the memory should be freed, quit packages
+ if ( fStatus == -2 )
+ {
+ // perform uninitializations
+ Abc_FrameEnd( pAbc );
+ // stop the framework
+ Abc_FrameDeallocate( pAbc );
+ }
+ return 0;
+
+usage:
+ Abc_UtilsPrintHello( pAbc );
+ Abc_UtilsPrintUsage( pAbc, argv[0] );
+ return 1;
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns 1 if s is a file type recognized, else returns 0.]
+
+ Description [Returns 1 if s is a file type recognized by VIS, else returns
+ 0. Recognized types are "blif", "blif_mv", "blif_mvs", and "none".]
+
+ SideEffects []
+
+******************************************************************************/
+static int
+TypeCheck(
+ Abc_Frame_t * pAbc,
+ char * s)
+{
+ if (strcmp(s, "blif") == 0) {
+ return 1;
+ }
+ else if (strcmp(s, "blif_mv") == 0) {
+ return 1;
+ }
+ else if (strcmp(s, "blif_mvs") == 0) {
+ return 1;
+ }
+ else if (strcmp(s, "none") == 0) {
+ return 1;
+ }
+ else {
+ fprintf( pAbc->Err, "unknown type %s\n", s );
+ return 0;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/main/main.h b/src/base/main/main.h
new file mode 100644
index 00000000..c5d6a0c8
--- /dev/null
+++ b/src/base/main/main.h
@@ -0,0 +1,109 @@
+/**CFile****************************************************************
+
+ FileName [main.h]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [The main package.]
+
+ Synopsis [External declarations of the main package.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: main.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __MAIN_H__
+#define __MAIN_H__
+
+////////////////////////////////////////////////////////////////////////
+/// TYPEDEFS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// the framework containing all data
+typedef struct Abc_Frame_t_ Abc_Frame_t;
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+// this include should be the first one in the list
+// it is used to catch memory leaks on Windows
+#include "leaks.h"
+
+// standard includes
+#include <stdio.h>
+#include <string.h>
+
+// includes from GLU
+#include "util.h"
+#include "st.h"
+
+// data structure packages
+#include "extra.h"
+#include "vec.h"
+
+// core packages
+#include "abc.h"
+#include "cmd.h"
+#include "io.h"
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// GLOBAL VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== mvFrame.c ===========================================================*/
+extern Abc_Ntk_t * Abc_FrameReadNet( Abc_Frame_t * p );
+extern FILE * Abc_FrameReadOut( Abc_Frame_t * p );
+extern FILE * Abc_FrameReadErr( Abc_Frame_t * p );
+extern bool Abc_FrameReadMode( Abc_Frame_t * p );
+extern bool Abc_FrameSetMode( Abc_Frame_t * p, bool fNameMode );
+extern void Abc_FrameRestart( Abc_Frame_t * p );
+
+extern void Abc_FrameSetCurrentNetwork( Abc_Frame_t * p, Abc_Ntk_t * pNet );
+extern void Abc_FrameSwapCurrentAndBackup( Abc_Frame_t * p );
+extern void Abc_FrameReplaceCurrentNetwork( Abc_Frame_t * p, Abc_Ntk_t * pNet );
+extern void Abc_FrameDeleteAllNetworks( Abc_Frame_t * p );
+
+extern void Abc_FrameSetGlobalFrame( Abc_Frame_t * p );
+extern Abc_Frame_t * Abc_FrameGetGlobalFrame();
+
+extern Abc_Ntk_t * Abc_FrameReadNtkStore ( Abc_Frame_t * pFrame );
+extern int Abc_FrameReadNtkStoreSize ( Abc_Frame_t * pFrame );
+extern void Abc_FrameSetNtkStore ( Abc_Frame_t * pFrame, Abc_Ntk_t * pNtk );
+extern void Abc_FrameSetNtkStoreSize ( Abc_Frame_t * pFrame, int nStored );
+
+extern void * Abc_FrameReadLibLut ( Abc_Frame_t * pFrame );
+extern void * Abc_FrameReadLibGen ( Abc_Frame_t * pFrame );
+extern void * Abc_FrameReadLibSuper ( Abc_Frame_t * pFrame );
+extern void Abc_FrameSetLibLut ( Abc_Frame_t * pFrame, void * pLib );
+extern void Abc_FrameSetLibGen ( Abc_Frame_t * pFrame, void * pLib );
+extern void Abc_FrameSetLibSuper ( Abc_Frame_t * pFrame, void * pLib );
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
diff --git a/src/base/main/mainFrame.c b/src/base/main/mainFrame.c
new file mode 100644
index 00000000..0b0cbbbd
--- /dev/null
+++ b/src/base/main/mainFrame.c
@@ -0,0 +1,417 @@
+/**CFile****************************************************************
+
+ FileName [mainFrame.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [The main package.]
+
+ Synopsis [The global framework resides in this file.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: mainFrame.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mainInt.h"
+#include "abc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static Abc_Frame_t * Abc_FrameGlobalFrame = 0;
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Frame_t * Abc_FrameAllocate()
+{
+ Abc_Frame_t * p;
+
+ // allocate and clean
+ p = ALLOC( Abc_Frame_t, 1 );
+ memset( p, 0, sizeof(Abc_Frame_t) );
+ // get version
+ p->sVersion = Abc_UtilsGetVersion( p );
+ // set streams
+ p->Err = stderr;
+ p->Out = stdout;
+ p->Hst = NULL;
+ // set the starting step
+ p->nSteps = 1;
+ p->fBatchMode = 0;
+ return p;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_FrameDeallocate( Abc_Frame_t * p )
+{
+ Abc_FrameDeleteAllNetworks( p );
+ free( p );
+ p = NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_FrameRestart( Abc_Frame_t * p )
+{
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Abc_FrameReadNet( Abc_Frame_t * p )
+{
+ return p->pNtkCur;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+FILE * Abc_FrameReadOut( Abc_Frame_t * p )
+{
+ return p->Out;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+FILE * Abc_FrameReadErr( Abc_Frame_t * p )
+{
+ return p->Err;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Abc_FrameReadMode( Abc_Frame_t * p )
+{
+ int fShortNames;
+ char * pValue;
+ pValue = Cmd_FlagReadByName( p, "namemode" );
+ if ( pValue == NULL )
+ fShortNames = 0;
+ else
+ fShortNames = atoi(pValue);
+ return fShortNames;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Abc_FrameSetMode( Abc_Frame_t * p, bool fNameMode )
+{
+ char Buffer[2];
+ bool fNameModeOld;
+ fNameModeOld = Abc_FrameReadMode( p );
+ Buffer[0] = '0' + fNameMode;
+ Buffer[1] = 0;
+ Cmd_FlagUpdateValue( p, "namemode", (char *)Buffer );
+ return fNameModeOld;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Sets the given network to be the current one.]
+
+ Description [Takes the network and makes it the current network.
+ The previous current network is attached to the given network as
+ a backup copy. In the stack of backup networks contains too many
+ networks (defined by the paramater "savesteps"), the bottom
+ most network is deleted.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_FrameSetCurrentNetwork( Abc_Frame_t * p, Abc_Ntk_t * pNetNew )
+{
+ Abc_Ntk_t * pNet, * pNet2, * pNet3;
+ int nNetsPresent;
+ int nNetsToSave;
+ char * pValue;
+
+ // link it to the previous network
+ Abc_NtkSetBackup( pNetNew, p->pNtkCur );
+ // set the step of this network
+ Abc_NtkSetStep( pNetNew, ++p->nSteps );
+ // set this network to be the current network
+ p->pNtkCur = pNetNew;
+
+ // remove any extra network that may happen to be in the stack
+ pValue = Cmd_FlagReadByName( p, "savesteps" );
+ // if the value of steps to save is not set, assume 1-level undo
+ if ( pValue == NULL )
+ nNetsToSave = 1;
+ else
+ nNetsToSave = atoi(pValue);
+
+ // count the network, remember the last one, and the one before the last one
+ nNetsPresent = 0;
+ pNet2 = pNet3 = NULL;
+ for ( pNet = p->pNtkCur; pNet; pNet = Abc_NtkBackup(pNet2) )
+ {
+ nNetsPresent++;
+ pNet3 = pNet2;
+ pNet2 = pNet;
+ }
+
+ // remove the earliest backup network if it is more steps away than we store
+ if ( nNetsPresent - 1 > nNetsToSave )
+ { // delete the last network
+ Abc_NtkDelete( pNet2 );
+ // clean the pointer of the network before the last one
+ Abc_NtkSetBackup( pNet3, NULL );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [This procedure swaps the current and the backup network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_FrameSwapCurrentAndBackup( Abc_Frame_t * p )
+{
+ Abc_Ntk_t * pNtkCur, * pNetBack, * pNetBack2;
+ int iStepCur, iStepBack;
+
+ pNtkCur = p->pNtkCur;
+ pNetBack = Abc_NtkBackup( pNtkCur );
+ iStepCur = Abc_NtkStep ( pNtkCur );
+
+ // if there is no backup nothing to reset
+ if ( pNetBack == NULL )
+ return;
+
+ // remember the backup of the backup
+ pNetBack2 = Abc_NtkBackup( pNetBack );
+ iStepBack = Abc_NtkStep ( pNetBack );
+
+ // set pNtkCur to be the next after the backup's backup
+ Abc_NtkSetBackup( pNtkCur, pNetBack2 );
+ Abc_NtkSetStep ( pNtkCur, iStepBack );
+
+ // set pNtkCur to be the next after the backup
+ Abc_NtkSetBackup( pNetBack, pNtkCur );
+ Abc_NtkSetStep ( pNetBack, iStepCur );
+
+ // set the current network
+ p->pNtkCur = pNetBack;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Replaces the current network by the given one.]
+
+ Description [This procedure does not modify the stack of saved
+ networks.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_FrameReplaceCurrentNetwork( Abc_Frame_t * p, Abc_Ntk_t * pNet )
+{
+ if ( pNet == NULL )
+ return;
+
+ // transfer the parameters to the new network
+ if ( p->pNtkCur )
+ {
+ Abc_NtkSetBackup( pNet, Abc_NtkBackup(p->pNtkCur) );
+ Abc_NtkSetStep( pNet, Abc_NtkStep(p->pNtkCur) );
+ // delete the current network
+ Abc_NtkDelete( p->pNtkCur );
+ }
+ else
+ {
+ Abc_NtkSetBackup( pNet, NULL );
+ Abc_NtkSetStep( pNet, ++p->nSteps );
+ }
+ // set the new current network
+ p->pNtkCur = pNet;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_FrameDeleteAllNetworks( Abc_Frame_t * p )
+{
+ Abc_Ntk_t * pNet, * pNet2;
+ // delete all the currently saved networks
+ for ( pNet = p->pNtkCur,
+ pNet2 = pNet? Abc_NtkBackup(pNet): NULL;
+ pNet;
+ pNet = pNet2,
+ pNet2 = pNet? Abc_NtkBackup(pNet): NULL )
+ Abc_NtkDelete( pNet );
+ // set the current network empty
+ p->pNtkCur = NULL;
+ fprintf( p->Out, "All networks have been deleted.\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_FrameSetGlobalFrame( Abc_Frame_t * p )
+{
+ Abc_FrameGlobalFrame = p;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Frame_t * Abc_FrameGetGlobalFrame()
+{
+ if ( Abc_FrameGlobalFrame == 0 )
+ {
+ // start the framework
+ Abc_FrameGlobalFrame = Abc_FrameAllocate();
+ // perform initializations
+ Abc_FrameInit( Abc_FrameGlobalFrame );
+ }
+ return Abc_FrameGlobalFrame;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Abc_Ntk_t * Abc_FrameReadNtkStore ( Abc_Frame_t * pFrame ) { return pFrame->pStored; }
+int Abc_FrameReadNtkStoreSize ( Abc_Frame_t * pFrame ) { return pFrame->nStored; }
+void Abc_FrameSetNtkStore ( Abc_Frame_t * pFrame, Abc_Ntk_t * pNtk ) { pFrame->pStored = pNtk; }
+void Abc_FrameSetNtkStoreSize ( Abc_Frame_t * pFrame, int nStored ) { pFrame->nStored = nStored; }
+
+void * Abc_FrameReadLibLut ( Abc_Frame_t * pFrame ) { return pFrame->pLibLut; }
+void * Abc_FrameReadLibGen ( Abc_Frame_t * pFrame ) { return pFrame->pLibGen; }
+void * Abc_FrameReadLibSuper ( Abc_Frame_t * pFrame ) { return pFrame->pLibSuper; }
+void Abc_FrameSetLibLut ( Abc_Frame_t * pFrame, void * pLib ) { pFrame->pLibLut = pLib; }
+void Abc_FrameSetLibGen ( Abc_Frame_t * pFrame, void * pLib ) { pFrame->pLibGen = pLib; }
+void Abc_FrameSetLibSuper ( Abc_Frame_t * pFrame, void * pLib ) { pFrame->pLibSuper = pLib; }
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/main/mainInit.c b/src/base/main/mainInit.c
new file mode 100644
index 00000000..13710dcb
--- /dev/null
+++ b/src/base/main/mainInit.c
@@ -0,0 +1,96 @@
+/**CFile****************************************************************
+
+ FileName [mainInit.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [The main package.]
+
+ Synopsis [Initialization procedures.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: mainInit.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mainInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+extern void Abc_Init( Abc_Frame_t * pAbc );
+extern void Abc_End ( Abc_Frame_t * pAbc );
+extern void Io_Init( Abc_Frame_t * pAbc );
+extern void Io_End ( Abc_Frame_t * pAbc );
+extern void Cmd_Init( Abc_Frame_t * pAbc );
+extern void Cmd_End ( Abc_Frame_t * pAbc );
+extern void Fpga_Init( Abc_Frame_t * pAbc );
+extern void Fpga_End ( Abc_Frame_t * pAbc );
+extern void Map_Init( Abc_Frame_t * pAbc );
+extern void Map_End ( Abc_Frame_t * pAbc );
+extern void Mio_Init( Abc_Frame_t * pAbc );
+extern void Mio_End ( Abc_Frame_t * pAbc );
+extern void Super_Init( Abc_Frame_t * pAbc );
+extern void Super_End ( Abc_Frame_t * pAbc );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Starts all the packages.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_FrameInit( Abc_Frame_t * pAbc )
+{
+ Cmd_Init( pAbc );
+ Io_Init( pAbc );
+ Abc_Init( pAbc );
+ Fpga_Init( pAbc );
+ Map_Init( pAbc );
+ Mio_Init( pAbc );
+ Super_Init( pAbc );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Stops all the packages.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_FrameEnd( Abc_Frame_t * pAbc )
+{
+ Abc_End( pAbc );
+ Io_End( pAbc );
+ Cmd_End( pAbc );
+ Fpga_End( pAbc );
+ Map_End( pAbc );
+ Mio_End( pAbc );
+ Super_End( pAbc );
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/main/mainInt.h b/src/base/main/mainInt.h
new file mode 100644
index 00000000..557c4e2f
--- /dev/null
+++ b/src/base/main/mainInt.h
@@ -0,0 +1,107 @@
+/**CFile****************************************************************
+
+ FileName [mainInt.h]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [The main package.]
+
+ Synopsis [Internal declarations of the main package.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: mainInt.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __Abc_INT_H__
+#define __Abc_INT_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+#include "main.h"
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+// the current version
+#define ABC_VERSION "UC Berkeley, ABC 1.0"
+
+// the maximum length of an input line
+#define MAX_STR 32768
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+struct Abc_Frame_t_
+{
+ // general info
+ char * sVersion; // the name of the current version
+ // commands, aliases, etc
+ st_table * tCommands; // the command table
+ st_table * tAliases; // the alias table
+ st_table * tFlags; // the flag table
+ Vec_Ptr_t * aHistory; // the command history
+ // the functionality
+ Abc_Ntk_t * pNtkCur; // the current network
+ int nSteps; // the counter of different network processed
+ // when this flag is 1, the current command is executed in autoexec mode
+ int fAutoexac;
+ // output streams
+ FILE * Out;
+ FILE * Err;
+ FILE * Hst;
+ // used for runtime measurement
+ int TimeCommand; // the runtime of the last command
+ int TimeTotal; // the total runtime of all commands
+ int fBatchMode; // are we invoked in batch mode?
+ // temporary storage for structural choices
+ Abc_Ntk_t * pStored; // the stored networks
+ int nStored; // the number of stored networks
+
+ void * pLibLut; // the current LUT library
+ void * pLibGen; // the current genlib
+ void * pLibSuper; // the current supergate library
+};
+
+////////////////////////////////////////////////////////////////////////
+/// GLOBAL VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== mvMain.c ===========================================================*/
+extern int main( int argc, char * argv[] );
+/*=== mvInit.c ===================================================*/
+extern void Abc_FrameInit( Abc_Frame_t * pAbc );
+extern void Abc_FrameEnd( Abc_Frame_t * pAbc );
+/*=== mvFrame.c =====================================================*/
+extern Abc_Frame_t * Abc_FrameAllocate();
+extern void Abc_FrameDeallocate( Abc_Frame_t * p );
+/*=== mvUtils.c =====================================================*/
+extern char * Abc_UtilsGetVersion( Abc_Frame_t * pAbc );
+extern char * Abc_UtilsGetUsersInput( Abc_Frame_t * pAbc );
+extern void Abc_UtilsPrintHello( Abc_Frame_t * pAbc );
+extern void Abc_UtilsPrintUsage( Abc_Frame_t * pAbc, char * ProgName );
+extern void Abc_UtilsSource( Abc_Frame_t * pAbc );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
diff --git a/src/base/main/mainUtils.c b/src/base/main/mainUtils.c
new file mode 100644
index 00000000..35d3c364
--- /dev/null
+++ b/src/base/main/mainUtils.c
@@ -0,0 +1,218 @@
+/**CFile****************************************************************
+
+ FileName [mainUtils.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [The main package.]
+
+ Synopsis [Miscellaneous utilities.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: mainUtils.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mainInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+static char * DateReadFromDateString(char * datestr);
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Abc_UtilsGetVersion( Abc_Frame_t * pAbc )
+{
+ static char Version[1000];
+ sprintf(Version, "%s (compiled %s %s)", ABC_VERSION, __DATE__, __TIME__);
+ return Version;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Abc_UtilsGetUsersInput( Abc_Frame_t * pAbc )
+{
+ static char Buffer[1000], Prompt[1000];
+ sprintf( Prompt, "abc %02d> ", pAbc->nSteps );
+ fprintf( pAbc->Out, "%s", Prompt );
+ fgets( Buffer, 999, stdin );
+ return Buffer;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_UtilsPrintHello( Abc_Frame_t * pAbc )
+{
+ fprintf( pAbc->Out, "%s\n", pAbc->sVersion );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_UtilsPrintUsage( Abc_Frame_t * pAbc, char * ProgName )
+{
+ fprintf( pAbc->Err, "\n" );
+ fprintf( pAbc->Err,
+ "usage: %s [-c cmd] [-f script] [-h] [-o file] [-s] [-t type] [-T type] [-x] [file]\n",
+ ProgName);
+ fprintf( pAbc->Err, " -c cmd\texecute commands `cmd'\n");
+ fprintf( pAbc->Err, " -F script\texecute commands from a script file and echo commands\n");
+ fprintf( pAbc->Err, " -f script\texecute commands from a script file\n");
+ fprintf( pAbc->Err, " -h\t\tprint the command usage\n");
+ fprintf( pAbc->Err, " -o file\tspecify output filename to store the result\n");
+ fprintf( pAbc->Err, " -s\t\tdo not read any initialization file\n");
+ fprintf( pAbc->Err, " -t type\tspecify input type (blif_mv (default), blif_mvs, blif, or none)\n");
+ fprintf( pAbc->Err, " -T type\tspecify output type (blif_mv (default), blif_mvs, blif, or none)\n");
+ fprintf( pAbc->Err, " -x\t\tequivalent to '-t none -T none'\n");
+ fprintf( pAbc->Err, "\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Abc_UtilsSource( Abc_Frame_t * pAbc )
+{
+#ifdef WIN32
+ if ( Cmd_CommandExecute(pAbc, "source abc.rc") )
+ {
+ if ( Cmd_CommandExecute(pAbc, "source ..\\abc.rc") == 0 )
+ printf( "Loaded \"abc.rc\" from the parent directory.\n" );
+ else if ( Cmd_CommandExecute(pAbc, "source ..\\..\\abc.rc") == 0 )
+ printf( "Loaded \"abc.rc\" from the grandparent directory.\n" );
+ }
+#else
+ {
+ char * sPath1, * sPath2;
+
+ // If .rc is present in both the home and current directories, then read
+ // it from the home directory. Otherwise, read it from wherever it's located.
+ sPath1 = util_file_search(".rc", "~/", "r");
+ sPath2 = util_file_search(".rc", ".", "r");
+
+ if ( sPath1 && sPath2 ) {
+ /* ~/.rc == .rc : Source the file only once */
+ (void) Cmd_CommandExecute(pAbc, "source -s ~/.rc");
+ }
+ else {
+ if (sPath1) {
+ (void) Cmd_CommandExecute(pAbc, "source -s ~/.rc");
+ }
+ if (sPath2) {
+ (void) Cmd_CommandExecute(pAbc, "source -s .rc");
+ }
+ }
+ if ( sPath1 ) FREE(sPath1);
+ if ( sPath2 ) FREE(sPath2);
+
+ /* execute the abc script which can be open with the "open_path" */
+ Cmd_CommandExecute( pAbc, "source -s abc.rc" );
+ }
+#endif //WIN32
+
+ return;
+}
+
+/**Function********************************************************************
+
+ Synopsis [Returns the date in a brief format assuming its coming from
+ the program `date'.]
+
+ Description [optional]
+
+ SideEffects []
+
+******************************************************************************/
+char *
+DateReadFromDateString(
+ char * datestr)
+{
+ static char result[25];
+ char day[10];
+ char month[10];
+ char zone[10];
+ char *at;
+ int date;
+ int hour;
+ int minute;
+ int second;
+ int year;
+
+ if (sscanf(datestr, "%s %s %2d %2d:%2d:%2d %s %4d",
+ day, month, &date, &hour, &minute, &second, zone, &year) == 8) {
+ if (hour >= 12) {
+ if (hour >= 13) hour -= 12;
+ at = "PM";
+ }
+ else {
+ if (hour == 0) hour = 12;
+ at = "AM";
+ }
+ (void) sprintf(result, "%d-%3s-%02d at %d:%02d %s",
+ date, month, year % 100, hour, minute, at);
+ return result;
+ }
+ else {
+ return datestr;
+ }
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/base/main/module.make b/src/base/main/module.make
new file mode 100644
index 00000000..59e1315e
--- /dev/null
+++ b/src/base/main/module.make
@@ -0,0 +1,4 @@
+SRC += src/base/main/main.c \
+ src/base/main/mainFrame.c \
+ src/base/main/mainInit.c \
+ src/base/main/mainUtils.c
diff --git a/src/bdd/cudd/cuBdd.make b/src/bdd/cudd/cuBdd.make
new file mode 100644
index 00000000..b16a27b3
--- /dev/null
+++ b/src/bdd/cudd/cuBdd.make
@@ -0,0 +1,41 @@
+CSRC_cu += cuddAPI.c cuddAddAbs.c cuddAddApply.c cuddAddFind.c cuddAddIte.c \
+ cuddAddInv.c cuddAddNeg.c cuddAddWalsh.c cuddAndAbs.c \
+ cuddAnneal.c cuddApa.c cuddApprox.c cuddBddAbs.c cuddBddCorr.c \
+ cuddBddIte.c cuddBridge.c cuddCache.c cuddCheck.c cuddClip.c \
+ cuddCof.c cuddCompose.c cuddDecomp.c cuddEssent.c cuddExact.c \
+ cuddExport.c cuddGenCof.c cuddGenetic.c \
+ cuddGroup.c cuddHarwell.c cuddInit.c cuddInteract.c \
+ cuddLCache.c cuddLevelQ.c \
+ cuddLinear.c cuddLiteral.c cuddMatMult.c cuddPriority.c \
+ cuddRead.c cuddRef.c cuddReorder.c cuddSat.c cuddSign.c \
+ cuddSolve.c cuddSplit.c cuddSubsetHB.c cuddSubsetSP.c cuddSymmetry.c \
+ cuddTable.c cuddUtil.c cuddWindow.c cuddZddCount.c cuddZddFuncs.c \
+ cuddZddGroup.c cuddZddIsop.c cuddZddLin.c cuddZddMisc.c cuddZddPort.c \
+ cuddZddReord.c cuddZddSetop.c cuddZddSymm.c cuddZddUtil.c
+HEADERS_cu += cudd.h cuddInt.h
+MISC += testcudd.c r7x8.1.mat doc/cudd.ps doc/cuddAllAbs.html doc/cuddAllDet.html \
+ doc/cuddExtAbs.html doc/cuddExtDet.html doc/cuddIntro.css \
+ doc/cuddIntro.html doc/footnode.html doc/img1.gif doc/img2.gif \
+ doc/img3.gif doc/img4.gif doc/img5.gif doc/index.html \
+ doc/node1.html doc/node2.html doc/node3.html doc/node4.html \
+ doc/node5.html doc/node6.html doc/node7.html doc/node8.html \
+ doc/icons/change_begin.gif \
+ doc/icons/change_delete.gif \
+ doc/icons/change_end.gif \
+ doc/icons/contents_motif.gif \
+ doc/icons/cross_ref_motif.gif \
+ doc/icons/foot_motif.gif \
+ doc/icons/image.gif \
+ doc/icons/index_motif.gif \
+ doc/icons/next_group_motif.gif \
+ doc/icons/next_group_motif_gr.gif \
+ doc/icons/next_motif.gif \
+ doc/icons/next_motif_gr.gif \
+ doc/icons/previous_group_motif.gif \
+ doc/icons/previous_group_motif_gr.gif \
+ doc/icons/previous_motif.gif \
+ doc/icons/previous_motif_gr.gif \
+ doc/icons/up_motif.gif \
+ doc/icons/up_motif_gr.gif
+
+DEPENDENCYFILES = $(CSRC_cu)
diff --git a/src/bdd/cudd/cudd.h b/src/bdd/cudd/cudd.h
new file mode 100644
index 00000000..a31fcdae
--- /dev/null
+++ b/src/bdd/cudd/cudd.h
@@ -0,0 +1,959 @@
+/**CHeaderFile*****************************************************************
+
+ FileName [cudd.h]
+
+ PackageName [cudd]
+
+ Synopsis [The University of Colorado decision diagram package.]
+
+ Description [External functions and data strucures of the CUDD package.
+ <ul>
+ <li> To turn on the gathering of statistics, define DD_STATS.
+ <li> To link with mis, define DD_MIS.
+ </ul>
+ Modified by Abelardo Pardo to interface it to VIS.
+ ]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+ Revision [$Id: cudd.h,v 1.1.1.1 2003/02/24 22:23:50 wjiang Exp $]
+
+******************************************************************************/
+
+#ifndef _CUDD
+#define _CUDD
+
+/*---------------------------------------------------------------------------*/
+/* Nested includes */
+/*---------------------------------------------------------------------------*/
+
+#include "mtr.h"
+#include "epd.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define CUDD_VERSION "2.3.1"
+
+#ifndef SIZEOF_VOID_P
+#define SIZEOF_VOID_P 4
+#endif
+#ifndef SIZEOF_INT
+#define SIZEOF_INT 4
+#endif
+#ifndef SIZEOF_LONG
+#define SIZEOF_LONG 4
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define CUDD_VALUE_TYPE double
+#define CUDD_OUT_OF_MEM -1
+/* The sizes of the subtables and the cache must be powers of two. */
+#define CUDD_UNIQUE_SLOTS 256 /* initial size of subtables */
+#define CUDD_CACHE_SLOTS 262144 /* default size of the cache */
+
+/* Constants for residue functions. */
+#define CUDD_RESIDUE_DEFAULT 0
+#define CUDD_RESIDUE_MSB 1
+#define CUDD_RESIDUE_TC 2
+
+/* CUDD_MAXINDEX is defined in such a way that on 32-bit and 64-bit
+** machines one can cast an index to (int) without generating a negative
+** number.
+*/
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+#define CUDD_MAXINDEX (((DdHalfWord) ~0) >> 1)
+#else
+#define CUDD_MAXINDEX ((DdHalfWord) ~0)
+#endif
+
+/* CUDD_CONST_INDEX is the index of constant nodes. Currently this
+** is a synonim for CUDD_MAXINDEX. */
+#define CUDD_CONST_INDEX CUDD_MAXINDEX
+
+/* These constants define the digits used in the representation of
+** arbitrary precision integers. The two configurations tested use 8
+** and 16 bits for each digit. The typedefs should be in agreement
+** with these definitions.
+*/
+#define DD_APA_BITS 16
+#define DD_APA_BASE (1 << DD_APA_BITS)
+#define DD_APA_MASK (DD_APA_BASE - 1)
+#define DD_APA_HEXPRINT "%04x"
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/**Enum************************************************************************
+
+ Synopsis [Type of reordering algorithm.]
+
+ Description [Type of reordering algorithm.]
+
+******************************************************************************/
+typedef enum {
+ CUDD_REORDER_SAME,
+ CUDD_REORDER_NONE,
+ CUDD_REORDER_RANDOM,
+ CUDD_REORDER_RANDOM_PIVOT,
+ CUDD_REORDER_SIFT,
+ CUDD_REORDER_SIFT_CONVERGE,
+ CUDD_REORDER_SYMM_SIFT,
+ CUDD_REORDER_SYMM_SIFT_CONV,
+ CUDD_REORDER_WINDOW2,
+ CUDD_REORDER_WINDOW3,
+ CUDD_REORDER_WINDOW4,
+ CUDD_REORDER_WINDOW2_CONV,
+ CUDD_REORDER_WINDOW3_CONV,
+ CUDD_REORDER_WINDOW4_CONV,
+ CUDD_REORDER_GROUP_SIFT,
+ CUDD_REORDER_GROUP_SIFT_CONV,
+ CUDD_REORDER_ANNEALING,
+ CUDD_REORDER_GENETIC,
+ CUDD_REORDER_LINEAR,
+ CUDD_REORDER_LINEAR_CONVERGE,
+ CUDD_REORDER_LAZY_SIFT,
+ CUDD_REORDER_EXACT
+} Cudd_ReorderingType;
+
+
+/**Enum************************************************************************
+
+ Synopsis [Type of aggregation methods.]
+
+ Description [Type of aggregation methods.]
+
+******************************************************************************/
+typedef enum {
+ CUDD_NO_CHECK,
+ CUDD_GROUP_CHECK,
+ CUDD_GROUP_CHECK2,
+ CUDD_GROUP_CHECK3,
+ CUDD_GROUP_CHECK4,
+ CUDD_GROUP_CHECK5,
+ CUDD_GROUP_CHECK6,
+ CUDD_GROUP_CHECK7,
+ CUDD_GROUP_CHECK8,
+ CUDD_GROUP_CHECK9
+} Cudd_AggregationType;
+
+
+/**Enum************************************************************************
+
+ Synopsis [Type of hooks.]
+
+ Description [Type of hooks.]
+
+******************************************************************************/
+typedef enum {
+ CUDD_PRE_GC_HOOK,
+ CUDD_POST_GC_HOOK,
+ CUDD_PRE_REORDERING_HOOK,
+ CUDD_POST_REORDERING_HOOK
+} Cudd_HookType;
+
+
+/**Enum************************************************************************
+
+ Synopsis [Type of error codes.]
+
+ Description [Type of error codes.]
+
+******************************************************************************/
+typedef enum {
+ CUDD_NO_ERROR,
+ CUDD_MEMORY_OUT,
+ CUDD_TOO_MANY_NODES,
+ CUDD_MAX_MEM_EXCEEDED,
+ CUDD_INVALID_ARG,
+ CUDD_INTERNAL_ERROR
+} Cudd_ErrorType;
+
+
+/**Enum************************************************************************
+
+ Synopsis [Group type for lazy sifting.]
+
+ Description [Group type for lazy sifting.]
+
+******************************************************************************/
+typedef enum {
+ CUDD_LAZY_NONE,
+ CUDD_LAZY_SOFT_GROUP,
+ CUDD_LAZY_HARD_GROUP,
+ CUDD_LAZY_UNGROUP
+} Cudd_LazyGroupType;
+
+
+/**Enum************************************************************************
+
+ Synopsis [Variable type.]
+
+ Description [Variable type. Currently used only in lazy sifting.]
+
+******************************************************************************/
+typedef enum {
+ CUDD_VAR_PRIMARY_INPUT,
+ CUDD_VAR_PRESENT_STATE,
+ CUDD_VAR_NEXT_STATE
+} Cudd_VariableType;
+
+
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+typedef unsigned int DdHalfWord;
+#else
+typedef unsigned short DdHalfWord;
+#endif
+
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+
+typedef struct DdNode DdNode;
+
+typedef struct DdChildren {
+ struct DdNode *T;
+ struct DdNode *E;
+} DdChildren;
+
+/* The DdNode structure is the only one exported out of the package */
+struct DdNode {
+ DdHalfWord index;
+ DdHalfWord ref; /* reference count */
+ DdNode *next; /* next pointer for unique table */
+ union {
+ CUDD_VALUE_TYPE value; /* for constant nodes */
+ DdChildren kids; /* for internal nodes */
+ } type;
+};
+
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+
+typedef struct DdManager DdManager;
+
+typedef struct DdGen DdGen;
+
+/* These typedefs for arbitrary precision arithmetic should agree with
+** the corresponding constant definitions above. */
+typedef unsigned short int DdApaDigit;
+typedef unsigned long int DdApaDoubleDigit;
+typedef DdApaDigit * DdApaNumber;
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns 1 if the node is a constant node.]
+
+ Description [Returns 1 if the node is a constant node (rather than an
+ internal node). All constant nodes have the same index
+ (CUDD_CONST_INDEX). The pointer passed to Cudd_IsConstant may be either
+ regular or complemented.]
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+#define Cudd_IsConstant(node) ((Cudd_Regular(node))->index == CUDD_CONST_INDEX)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Complements a DD.]
+
+ Description [Complements a DD by flipping the complement attribute of
+ the pointer (the least significant bit).]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_NotCond]
+
+******************************************************************************/
+#define Cudd_Not(node) ((DdNode *)((long)(node) ^ 01))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Complements a DD if a condition is true.]
+
+ Description [Complements a DD if condition c is true; c should be
+ either 0 or 1, because it is used directly (for efficiency). If in
+ doubt on the values c may take, use "(c) ? Cudd_Not(node) : node".]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_Not]
+
+******************************************************************************/
+#define Cudd_NotCond(node,c) ((DdNode *)((long)(node) ^ (c)))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the regular version of a pointer.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_Complement Cudd_IsComplement]
+
+******************************************************************************/
+#define Cudd_Regular(node) ((DdNode *)((unsigned long)(node) & ~01))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the complemented version of a pointer.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_Regular Cudd_IsComplement]
+
+******************************************************************************/
+#define Cudd_Complement(node) ((DdNode *)((unsigned long)(node) | 01))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns 1 if a pointer is complemented.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_Regular Cudd_Complement]
+
+******************************************************************************/
+#define Cudd_IsComplement(node) ((int) ((long) (node) & 01))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the then child of an internal node.]
+
+ Description [Returns the then child of an internal node. If
+ <code>node</code> is a constant node, the result is unpredictable.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_E Cudd_V]
+
+******************************************************************************/
+#define Cudd_T(node) ((Cudd_Regular(node))->type.kids.T)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the else child of an internal node.]
+
+ Description [Returns the else child of an internal node. If
+ <code>node</code> is a constant node, the result is unpredictable.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_T Cudd_V]
+
+******************************************************************************/
+#define Cudd_E(node) ((Cudd_Regular(node))->type.kids.E)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the value of a constant node.]
+
+ Description [Returns the value of a constant node. If
+ <code>node</code> is an internal node, the result is unpredictable.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_T Cudd_E]
+
+******************************************************************************/
+#define Cudd_V(node) ((Cudd_Regular(node))->type.value)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the current position in the order of variable
+ index.]
+
+ Description [Returns the current position in the order of variable
+ index. This macro is obsolete and is kept for compatibility. New
+ applications should use Cudd_ReadPerm instead.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_ReadPerm]
+
+******************************************************************************/
+#define Cudd_ReadIndex(dd,index) (Cudd_ReadPerm(dd,index))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Iterates over the cubes of a decision diagram.]
+
+ Description [Iterates over the cubes of a decision diagram f.
+ <ul>
+ <li> DdManager *manager;
+ <li> DdNode *f;
+ <li> DdGen *gen;
+ <li> int *cube;
+ <li> CUDD_VALUE_TYPE value;
+ </ul>
+ Cudd_ForeachCube allocates and frees the generator. Therefore the
+ application should not try to do that. Also, the cube is freed at the
+ end of Cudd_ForeachCube and hence is not available outside of the loop.<p>
+ CAUTION: It is assumed that dynamic reordering will not occur while
+ there are open generators. It is the user's responsibility to make sure
+ that dynamic reordering does not occur. As long as new nodes are not created
+ during generation, and dynamic reordering is not called explicitly,
+ dynamic reordering will not occur. Alternatively, it is sufficient to
+ disable dynamic reordering. It is a mistake to dispose of a diagram
+ on which generation is ongoing.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_ForeachNode Cudd_FirstCube Cudd_NextCube Cudd_GenFree
+ Cudd_IsGenEmpty Cudd_AutodynDisable]
+
+******************************************************************************/
+#define Cudd_ForeachCube(manager, f, gen, cube, value)\
+ for((gen) = Cudd_FirstCube(manager, f, &cube, &value);\
+ Cudd_IsGenEmpty(gen) ? Cudd_GenFree(gen) : TRUE;\
+ (void) Cudd_NextCube(gen, &cube, &value))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Iterates over the nodes of a decision diagram.]
+
+ Description [Iterates over the nodes of a decision diagram f.
+ <ul>
+ <li> DdManager *manager;
+ <li> DdNode *f;
+ <li> DdGen *gen;
+ <li> DdNode *node;
+ </ul>
+ The nodes are returned in a seemingly random order.
+ Cudd_ForeachNode allocates and frees the generator. Therefore the
+ application should not try to do that.<p>
+ CAUTION: It is assumed that dynamic reordering will not occur while
+ there are open generators. It is the user's responsibility to make sure
+ that dynamic reordering does not occur. As long as new nodes are not created
+ during generation, and dynamic reordering is not called explicitly,
+ dynamic reordering will not occur. Alternatively, it is sufficient to
+ disable dynamic reordering. It is a mistake to dispose of a diagram
+ on which generation is ongoing.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_ForeachCube Cudd_FirstNode Cudd_NextNode Cudd_GenFree
+ Cudd_IsGenEmpty Cudd_AutodynDisable]
+
+******************************************************************************/
+#define Cudd_ForeachNode(manager, f, gen, node)\
+ for((gen) = Cudd_FirstNode(manager, f, &node);\
+ Cudd_IsGenEmpty(gen) ? Cudd_GenFree(gen) : TRUE;\
+ (void) Cudd_NextNode(gen, &node))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Iterates over the paths of a ZDD.]
+
+ Description [Iterates over the paths of a ZDD f.
+ <ul>
+ <li> DdManager *manager;
+ <li> DdNode *f;
+ <li> DdGen *gen;
+ <li> int *path;
+ </ul>
+ Cudd_zddForeachPath allocates and frees the generator. Therefore the
+ application should not try to do that. Also, the path is freed at the
+ end of Cudd_zddForeachPath and hence is not available outside of the loop.<p>
+ CAUTION: It is assumed that dynamic reordering will not occur while
+ there are open generators. It is the user's responsibility to make sure
+ that dynamic reordering does not occur. As long as new nodes are not created
+ during generation, and dynamic reordering is not called explicitly,
+ dynamic reordering will not occur. Alternatively, it is sufficient to
+ disable dynamic reordering. It is a mistake to dispose of a diagram
+ on which generation is ongoing.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_zddFirstPath Cudd_zddNextPath Cudd_GenFree
+ Cudd_IsGenEmpty Cudd_AutodynDisable]
+
+******************************************************************************/
+#define Cudd_zddForeachPath(manager, f, gen, path)\
+ for((gen) = Cudd_zddFirstPath(manager, f, &path);\
+ Cudd_IsGenEmpty(gen) ? Cudd_GenFree(gen) : TRUE;\
+ (void) Cudd_zddNextPath(gen, &path))
+
+
+/* These are potential duplicates. */
+#ifndef EXTERN
+# ifdef __cplusplus
+# define EXTERN extern "C"
+# else
+# define EXTERN extern
+# endif
+#endif
+#ifndef ARGS
+# if defined(__STDC__) || defined(__cplusplus)
+# define ARGS(protos) protos /* ANSI C */
+# else /* !(__STDC__ || __cplusplus) */
+# define ARGS(protos) () /* K&R C */
+# endif /* !(__STDC__ || __cplusplus) */
+#endif
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Function prototypes */
+/*---------------------------------------------------------------------------*/
+
+EXTERN DdNode * Cudd_addNewVar ARGS((DdManager *dd));
+EXTERN DdNode * Cudd_addNewVarAtLevel ARGS((DdManager *dd, int level));
+EXTERN DdNode * Cudd_bddNewVar ARGS((DdManager *dd));
+EXTERN DdNode * Cudd_bddNewVarAtLevel ARGS((DdManager *dd, int level));
+EXTERN DdNode * Cudd_addIthVar ARGS((DdManager *dd, int i));
+EXTERN DdNode * Cudd_bddIthVar ARGS((DdManager *dd, int i));
+EXTERN DdNode * Cudd_zddIthVar ARGS((DdManager *dd, int i));
+EXTERN int Cudd_zddVarsFromBddVars ARGS((DdManager *dd, int multiplicity));
+EXTERN DdNode * Cudd_addConst ARGS((DdManager *dd, CUDD_VALUE_TYPE c));
+EXTERN int Cudd_IsNonConstant ARGS((DdNode *f));
+EXTERN void Cudd_AutodynEnable ARGS((DdManager *unique, Cudd_ReorderingType method));
+EXTERN void Cudd_AutodynDisable ARGS((DdManager *unique));
+EXTERN int Cudd_ReorderingStatus ARGS((DdManager *unique, Cudd_ReorderingType *method));
+EXTERN void Cudd_AutodynEnableZdd ARGS((DdManager *unique, Cudd_ReorderingType method));
+EXTERN void Cudd_AutodynDisableZdd ARGS((DdManager *unique));
+EXTERN int Cudd_ReorderingStatusZdd ARGS((DdManager *unique, Cudd_ReorderingType *method));
+EXTERN int Cudd_zddRealignmentEnabled ARGS((DdManager *unique));
+EXTERN void Cudd_zddRealignEnable ARGS((DdManager *unique));
+EXTERN void Cudd_zddRealignDisable ARGS((DdManager *unique));
+EXTERN int Cudd_bddRealignmentEnabled ARGS((DdManager *unique));
+EXTERN void Cudd_bddRealignEnable ARGS((DdManager *unique));
+EXTERN void Cudd_bddRealignDisable ARGS((DdManager *unique));
+EXTERN DdNode * Cudd_ReadOne ARGS((DdManager *dd));
+EXTERN DdNode * Cudd_ReadZddOne ARGS((DdManager *dd, int i));
+EXTERN DdNode * Cudd_ReadZero ARGS((DdManager *dd));
+EXTERN DdNode * Cudd_ReadLogicZero ARGS((DdManager *dd));
+EXTERN DdNode * Cudd_ReadPlusInfinity ARGS((DdManager *dd));
+EXTERN DdNode * Cudd_ReadMinusInfinity ARGS((DdManager *dd));
+EXTERN DdNode * Cudd_ReadBackground ARGS((DdManager *dd));
+EXTERN void Cudd_SetBackground ARGS((DdManager *dd, DdNode *bck));
+EXTERN unsigned int Cudd_ReadCacheSlots ARGS((DdManager *dd));
+EXTERN double Cudd_ReadCacheUsedSlots ARGS((DdManager * dd));
+EXTERN double Cudd_ReadCacheLookUps ARGS((DdManager *dd));
+EXTERN double Cudd_ReadCacheHits ARGS((DdManager *dd));
+EXTERN double Cudd_ReadRecursiveCalls ARGS ((DdManager * dd));
+EXTERN unsigned int Cudd_ReadMinHit ARGS((DdManager *dd));
+EXTERN void Cudd_SetMinHit ARGS((DdManager *dd, unsigned int hr));
+EXTERN unsigned int Cudd_ReadLooseUpTo ARGS((DdManager *dd));
+EXTERN void Cudd_SetLooseUpTo ARGS((DdManager *dd, unsigned int lut));
+EXTERN unsigned int Cudd_ReadMaxCache ARGS((DdManager *dd));
+EXTERN unsigned int Cudd_ReadMaxCacheHard ARGS((DdManager *dd));
+EXTERN void Cudd_SetMaxCacheHard ARGS((DdManager *dd, unsigned int mc));
+EXTERN int Cudd_ReadSize ARGS((DdManager *dd));
+EXTERN int Cudd_ReadZddSize ARGS((DdManager *dd));
+EXTERN unsigned int Cudd_ReadSlots ARGS((DdManager *dd));
+EXTERN double Cudd_ReadUsedSlots ARGS((DdManager * dd));
+EXTERN double Cudd_ExpectedUsedSlots ARGS((DdManager * dd));
+EXTERN unsigned int Cudd_ReadKeys ARGS((DdManager *dd));
+EXTERN unsigned int Cudd_ReadDead ARGS((DdManager *dd));
+EXTERN unsigned int Cudd_ReadMinDead ARGS((DdManager *dd));
+EXTERN int Cudd_ReadReorderings ARGS((DdManager *dd));
+EXTERN long Cudd_ReadReorderingTime ARGS((DdManager * dd));
+EXTERN int Cudd_ReadGarbageCollections ARGS((DdManager * dd));
+EXTERN long Cudd_ReadGarbageCollectionTime ARGS((DdManager * dd));
+EXTERN double Cudd_ReadNodesFreed ARGS((DdManager * dd));
+EXTERN double Cudd_ReadNodesDropped ARGS((DdManager * dd));
+EXTERN double Cudd_ReadUniqueLookUps ARGS((DdManager * dd));
+EXTERN double Cudd_ReadUniqueLinks ARGS((DdManager * dd));
+EXTERN int Cudd_ReadSiftMaxVar ARGS((DdManager *dd));
+EXTERN void Cudd_SetSiftMaxVar ARGS((DdManager *dd, int smv));
+EXTERN int Cudd_ReadSiftMaxSwap ARGS((DdManager *dd));
+EXTERN void Cudd_SetSiftMaxSwap ARGS((DdManager *dd, int sms));
+EXTERN double Cudd_ReadMaxGrowth ARGS((DdManager *dd));
+EXTERN void Cudd_SetMaxGrowth ARGS((DdManager *dd, double mg));
+EXTERN double Cudd_ReadMaxGrowthAlternate ARGS((DdManager * dd));
+EXTERN void Cudd_SetMaxGrowthAlternate ARGS((DdManager * dd, double mg));
+EXTERN int Cudd_ReadReorderingCycle ARGS((DdManager * dd));
+EXTERN void Cudd_SetReorderingCycle ARGS((DdManager * dd, int cycle));
+EXTERN MtrNode * Cudd_ReadTree ARGS((DdManager *dd));
+EXTERN void Cudd_SetTree ARGS((DdManager *dd, MtrNode *tree));
+EXTERN void Cudd_FreeTree ARGS((DdManager *dd));
+EXTERN MtrNode * Cudd_ReadZddTree ARGS((DdManager *dd));
+EXTERN void Cudd_SetZddTree ARGS((DdManager *dd, MtrNode *tree));
+EXTERN void Cudd_FreeZddTree ARGS((DdManager *dd));
+EXTERN unsigned int Cudd_NodeReadIndex ARGS((DdNode *node));
+EXTERN int Cudd_ReadPerm ARGS((DdManager *dd, int i));
+EXTERN int Cudd_ReadPermZdd ARGS((DdManager *dd, int i));
+EXTERN int Cudd_ReadInvPerm ARGS((DdManager *dd, int i));
+EXTERN int Cudd_ReadInvPermZdd ARGS((DdManager *dd, int i));
+EXTERN DdNode * Cudd_ReadVars ARGS((DdManager *dd, int i));
+EXTERN CUDD_VALUE_TYPE Cudd_ReadEpsilon ARGS((DdManager *dd));
+EXTERN void Cudd_SetEpsilon ARGS((DdManager *dd, CUDD_VALUE_TYPE ep));
+EXTERN Cudd_AggregationType Cudd_ReadGroupcheck ARGS((DdManager *dd));
+EXTERN void Cudd_SetGroupcheck ARGS((DdManager *dd, Cudd_AggregationType gc));
+EXTERN int Cudd_GarbageCollectionEnabled ARGS((DdManager *dd));
+EXTERN void Cudd_EnableGarbageCollection ARGS((DdManager *dd));
+EXTERN void Cudd_DisableGarbageCollection ARGS((DdManager *dd));
+EXTERN int Cudd_DeadAreCounted ARGS((DdManager *dd));
+EXTERN void Cudd_TurnOnCountDead ARGS((DdManager *dd));
+EXTERN void Cudd_TurnOffCountDead ARGS((DdManager *dd));
+EXTERN int Cudd_ReadRecomb ARGS((DdManager *dd));
+EXTERN void Cudd_SetRecomb ARGS((DdManager *dd, int recomb));
+EXTERN int Cudd_ReadSymmviolation ARGS((DdManager *dd));
+EXTERN void Cudd_SetSymmviolation ARGS((DdManager *dd, int symmviolation));
+EXTERN int Cudd_ReadArcviolation ARGS((DdManager *dd));
+EXTERN void Cudd_SetArcviolation ARGS((DdManager *dd, int arcviolation));
+EXTERN int Cudd_ReadPopulationSize ARGS((DdManager *dd));
+EXTERN void Cudd_SetPopulationSize ARGS((DdManager *dd, int populationSize));
+EXTERN int Cudd_ReadNumberXovers ARGS((DdManager *dd));
+EXTERN void Cudd_SetNumberXovers ARGS((DdManager *dd, int numberXovers));
+EXTERN long Cudd_ReadMemoryInUse ARGS((DdManager *dd));
+EXTERN int Cudd_PrintInfo ARGS((DdManager *dd, FILE *fp));
+EXTERN long Cudd_ReadPeakNodeCount ARGS((DdManager *dd));
+EXTERN int Cudd_ReadPeakLiveNodeCount ARGS((DdManager * dd));
+EXTERN long Cudd_ReadNodeCount ARGS((DdManager *dd));
+EXTERN long Cudd_zddReadNodeCount ARGS((DdManager *dd));
+EXTERN int Cudd_AddHook ARGS((DdManager *dd, int (*f)(DdManager *, char *, void *), Cudd_HookType where));
+EXTERN int Cudd_RemoveHook ARGS((DdManager *dd, int (*f)(DdManager *, char *, void *), Cudd_HookType where));
+EXTERN int Cudd_IsInHook ARGS((DdManager * dd, int (*f)(DdManager *, char *, void *), Cudd_HookType where));
+EXTERN int Cudd_StdPreReordHook ARGS((DdManager *dd, char *str, void *data));
+EXTERN int Cudd_StdPostReordHook ARGS((DdManager *dd, char *str, void *data));
+EXTERN int Cudd_EnableReorderingReporting ARGS((DdManager *dd));
+EXTERN int Cudd_DisableReorderingReporting ARGS((DdManager *dd));
+EXTERN int Cudd_ReorderingReporting ARGS((DdManager *dd));
+EXTERN Cudd_ErrorType Cudd_ReadErrorCode ARGS((DdManager *dd));
+EXTERN void Cudd_ClearErrorCode ARGS((DdManager *dd));
+EXTERN FILE * Cudd_ReadStdout ARGS((DdManager *dd));
+EXTERN void Cudd_SetStdout ARGS((DdManager *dd, FILE *fp));
+EXTERN FILE * Cudd_ReadStderr ARGS((DdManager *dd));
+EXTERN void Cudd_SetStderr ARGS((DdManager *dd, FILE *fp));
+EXTERN unsigned int Cudd_ReadNextReordering ARGS((DdManager *dd));
+EXTERN void Cudd_SetNextReordering ARGS((DdManager *dd, unsigned int next));
+EXTERN double Cudd_ReadSwapSteps ARGS((DdManager *dd));
+EXTERN unsigned int Cudd_ReadMaxLive ARGS((DdManager *dd));
+EXTERN void Cudd_SetMaxLive ARGS((DdManager *dd, unsigned int maxLive));
+EXTERN long Cudd_ReadMaxMemory ARGS((DdManager *dd));
+EXTERN void Cudd_SetMaxMemory ARGS((DdManager *dd, long maxMemory));
+EXTERN int Cudd_bddBindVar ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddUnbindVar ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddVarIsBound ARGS((DdManager *dd, int index));
+EXTERN DdNode * Cudd_addExistAbstract ARGS((DdManager *manager, DdNode *f, DdNode *cube));
+EXTERN DdNode * Cudd_addUnivAbstract ARGS((DdManager *manager, DdNode *f, DdNode *cube));
+EXTERN DdNode * Cudd_addOrAbstract ARGS((DdManager *manager, DdNode *f, DdNode *cube));
+EXTERN DdNode * Cudd_addApply ARGS((DdManager *dd, DdNode * (*)(DdManager *, DdNode **, DdNode **), DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_addPlus ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addTimes ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addThreshold ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addSetNZ ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addDivide ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addMinus ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addMinimum ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addMaximum ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addOneZeroMaximum ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addDiff ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addAgreement ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addOr ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addNand ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addNor ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addXor ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addXnor ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addMonadicApply ARGS((DdManager * dd, DdNode * (*op)(DdManager *, DdNode *), DdNode * f));
+EXTERN DdNode * Cudd_addLog ARGS((DdManager * dd, DdNode * f));
+EXTERN DdNode * Cudd_addFindMax ARGS((DdManager *dd, DdNode *f));
+EXTERN DdNode * Cudd_addFindMin ARGS((DdManager *dd, DdNode *f));
+EXTERN DdNode * Cudd_addIthBit ARGS((DdManager *dd, DdNode *f, int bit));
+EXTERN DdNode * Cudd_addScalarInverse ARGS((DdManager *dd, DdNode *f, DdNode *epsilon));
+EXTERN DdNode * Cudd_addIte ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *h));
+EXTERN DdNode * Cudd_addIteConstant ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *h));
+EXTERN DdNode * Cudd_addEvalConst ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN int Cudd_addLeq ARGS((DdManager * dd, DdNode * f, DdNode * g));
+EXTERN DdNode * Cudd_addCmpl ARGS((DdManager *dd, DdNode *f));
+EXTERN DdNode * Cudd_addNegate ARGS((DdManager *dd, DdNode *f));
+EXTERN DdNode * Cudd_addRoundOff ARGS((DdManager *dd, DdNode *f, int N));
+EXTERN DdNode * Cudd_addWalsh ARGS((DdManager *dd, DdNode **x, DdNode **y, int n));
+EXTERN DdNode * Cudd_addResidue ARGS((DdManager *dd, int n, int m, int options, int top));
+EXTERN DdNode * Cudd_bddAndAbstract ARGS((DdManager *manager, DdNode *f, DdNode *g, DdNode *cube));
+EXTERN int Cudd_ApaNumberOfDigits ARGS((int binaryDigits));
+EXTERN DdApaNumber Cudd_NewApaNumber ARGS((int digits));
+EXTERN void Cudd_ApaCopy ARGS((int digits, DdApaNumber source, DdApaNumber dest));
+EXTERN DdApaDigit Cudd_ApaAdd ARGS((int digits, DdApaNumber a, DdApaNumber b, DdApaNumber sum));
+EXTERN DdApaDigit Cudd_ApaSubtract ARGS((int digits, DdApaNumber a, DdApaNumber b, DdApaNumber diff));
+EXTERN DdApaDigit Cudd_ApaShortDivision ARGS((int digits, DdApaNumber dividend, DdApaDigit divisor, DdApaNumber quotient));
+EXTERN unsigned int Cudd_ApaIntDivision ARGS((int digits, DdApaNumber dividend, unsigned int divisor, DdApaNumber quotient));
+EXTERN void Cudd_ApaShiftRight ARGS((int digits, DdApaDigit in, DdApaNumber a, DdApaNumber b));
+EXTERN void Cudd_ApaSetToLiteral ARGS((int digits, DdApaNumber number, DdApaDigit literal));
+EXTERN void Cudd_ApaPowerOfTwo ARGS((int digits, DdApaNumber number, int power));
+EXTERN int Cudd_ApaCompare ARGS((int digitsFirst, DdApaNumber first, int digitsSecond, DdApaNumber second));
+EXTERN int Cudd_ApaCompareRatios ARGS ((int digitsFirst, DdApaNumber firstNum, unsigned int firstDen, int digitsSecond, DdApaNumber secondNum, unsigned int secondDen));
+EXTERN int Cudd_ApaPrintHex ARGS((FILE *fp, int digits, DdApaNumber number));
+EXTERN int Cudd_ApaPrintDecimal ARGS((FILE *fp, int digits, DdApaNumber number));
+EXTERN int Cudd_ApaPrintExponential ARGS((FILE * fp, int digits, DdApaNumber number, int precision));
+EXTERN DdApaNumber Cudd_ApaCountMinterm ARGS((DdManager *manager, DdNode *node, int nvars, int *digits));
+EXTERN int Cudd_ApaPrintMinterm ARGS((FILE *fp, DdManager *dd, DdNode *node, int nvars));
+EXTERN int Cudd_ApaPrintMintermExp ARGS((FILE * fp, DdManager * dd, DdNode * node, int nvars, int precision));
+EXTERN int Cudd_ApaPrintDensity ARGS((FILE * fp, DdManager * dd, DdNode * node, int nvars));
+EXTERN DdNode * Cudd_UnderApprox ARGS((DdManager *dd, DdNode *f, int numVars, int threshold, int safe, double quality));
+EXTERN DdNode * Cudd_OverApprox ARGS((DdManager *dd, DdNode *f, int numVars, int threshold, int safe, double quality));
+EXTERN DdNode * Cudd_RemapUnderApprox ARGS((DdManager *dd, DdNode *f, int numVars, int threshold, double quality));
+EXTERN DdNode * Cudd_RemapOverApprox ARGS((DdManager *dd, DdNode *f, int numVars, int threshold, double quality));
+EXTERN DdNode * Cudd_BiasedUnderApprox ARGS((DdManager *dd, DdNode *f, DdNode *b, int numVars, int threshold, double quality1, double quality0));
+EXTERN DdNode * Cudd_BiasedOverApprox ARGS((DdManager *dd, DdNode *f, DdNode *b, int numVars, int threshold, double quality1, double quality0));
+EXTERN DdNode * Cudd_bddExistAbstract ARGS((DdManager *manager, DdNode *f, DdNode *cube));
+EXTERN DdNode * Cudd_bddXorExistAbstract ARGS((DdManager *manager, DdNode *f, DdNode *g, DdNode *cube));
+EXTERN DdNode * Cudd_bddUnivAbstract ARGS((DdManager *manager, DdNode *f, DdNode *cube));
+EXTERN DdNode * Cudd_bddBooleanDiff ARGS((DdManager *manager, DdNode *f, int x));
+EXTERN int Cudd_bddVarIsDependent ARGS((DdManager *dd, DdNode *f, DdNode *var));
+EXTERN double Cudd_bddCorrelation ARGS((DdManager *manager, DdNode *f, DdNode *g));
+EXTERN double Cudd_bddCorrelationWeights ARGS((DdManager *manager, DdNode *f, DdNode *g, double *prob));
+EXTERN DdNode * Cudd_bddIte ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *h));
+EXTERN DdNode * Cudd_bddIteConstant ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *h));
+EXTERN DdNode * Cudd_bddIntersect ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_bddAnd ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_bddOr ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_bddNand ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_bddNor ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_bddXor ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_bddXnor ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN int Cudd_bddLeq ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_addBddThreshold ARGS((DdManager *dd, DdNode *f, CUDD_VALUE_TYPE value));
+EXTERN DdNode * Cudd_addBddStrictThreshold ARGS((DdManager *dd, DdNode *f, CUDD_VALUE_TYPE value));
+EXTERN DdNode * Cudd_addBddInterval ARGS((DdManager *dd, DdNode *f, CUDD_VALUE_TYPE lower, CUDD_VALUE_TYPE upper));
+EXTERN DdNode * Cudd_addBddIthBit ARGS((DdManager *dd, DdNode *f, int bit));
+EXTERN DdNode * Cudd_BddToAdd ARGS((DdManager *dd, DdNode *B));
+EXTERN DdNode * Cudd_addBddPattern ARGS((DdManager *dd, DdNode *f));
+EXTERN DdNode * Cudd_bddTransfer ARGS((DdManager *ddSource, DdManager *ddDestination, DdNode *f));
+EXTERN int Cudd_DebugCheck ARGS((DdManager *table));
+EXTERN int Cudd_CheckKeys ARGS((DdManager *table));
+EXTERN DdNode * Cudd_bddClippingAnd ARGS((DdManager *dd, DdNode *f, DdNode *g, int maxDepth, int direction));
+EXTERN DdNode * Cudd_bddClippingAndAbstract ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *cube, int maxDepth, int direction));
+EXTERN DdNode * Cudd_Cofactor ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_bddCompose ARGS((DdManager *dd, DdNode *f, DdNode *g, int v));
+EXTERN DdNode * Cudd_addCompose ARGS((DdManager *dd, DdNode *f, DdNode *g, int v));
+EXTERN DdNode * Cudd_addPermute ARGS((DdManager *manager, DdNode *node, int *permut));
+EXTERN DdNode * Cudd_addSwapVariables ARGS((DdManager *dd, DdNode *f, DdNode **x, DdNode **y, int n));
+EXTERN DdNode * Cudd_bddPermute ARGS((DdManager *manager, DdNode *node, int *permut));
+EXTERN DdNode * Cudd_bddVarMap ARGS((DdManager *manager, DdNode *f));
+EXTERN int Cudd_SetVarMap ARGS((DdManager *manager, DdNode **x, DdNode **y, int n));
+EXTERN DdNode * Cudd_bddSwapVariables ARGS((DdManager *dd, DdNode *f, DdNode **x, DdNode **y, int n));
+EXTERN DdNode * Cudd_bddAdjPermuteX ARGS((DdManager *dd, DdNode *B, DdNode **x, int n));
+EXTERN DdNode * Cudd_addVectorCompose ARGS((DdManager *dd, DdNode *f, DdNode **vector));
+EXTERN DdNode * Cudd_addGeneralVectorCompose ARGS((DdManager *dd, DdNode *f, DdNode **vectorOn, DdNode **vectorOff));
+EXTERN DdNode * Cudd_addNonSimCompose ARGS((DdManager *dd, DdNode *f, DdNode **vector));
+EXTERN DdNode * Cudd_bddVectorCompose ARGS((DdManager *dd, DdNode *f, DdNode **vector));
+EXTERN int Cudd_bddApproxConjDecomp ARGS((DdManager *dd, DdNode *f, DdNode ***conjuncts));
+EXTERN int Cudd_bddApproxDisjDecomp ARGS((DdManager *dd, DdNode *f, DdNode ***disjuncts));
+EXTERN int Cudd_bddIterConjDecomp ARGS((DdManager *dd, DdNode *f, DdNode ***conjuncts));
+EXTERN int Cudd_bddIterDisjDecomp ARGS((DdManager *dd, DdNode *f, DdNode ***disjuncts));
+EXTERN int Cudd_bddGenConjDecomp ARGS((DdManager *dd, DdNode *f, DdNode ***conjuncts));
+EXTERN int Cudd_bddGenDisjDecomp ARGS((DdManager *dd, DdNode *f, DdNode ***disjuncts));
+EXTERN int Cudd_bddVarConjDecomp ARGS((DdManager *dd, DdNode * f, DdNode ***conjuncts));
+EXTERN int Cudd_bddVarDisjDecomp ARGS((DdManager *dd, DdNode * f, DdNode ***disjuncts));
+EXTERN DdNode * Cudd_FindEssential ARGS((DdManager *dd, DdNode *f));
+EXTERN int Cudd_bddIsVarEssential ARGS((DdManager *manager, DdNode *f, int id, int phase));
+EXTERN int Cudd_DumpBlif ARGS((DdManager *dd, int n, DdNode **f, char **inames, char **onames, char *mname, FILE *fp));
+EXTERN int Cudd_DumpBlifBody ARGS((DdManager *dd, int n, DdNode **f, char **inames, char **onames, FILE *fp));
+EXTERN int Cudd_DumpDot ARGS((DdManager *dd, int n, DdNode **f, char **inames, char **onames, FILE *fp));
+EXTERN int Cudd_DumpDaVinci ARGS((DdManager *dd, int n, DdNode **f, char **inames, char **onames, FILE *fp));
+EXTERN int Cudd_DumpDDcal ARGS((DdManager *dd, int n, DdNode **f, char **inames, char **onames, FILE *fp));
+EXTERN int Cudd_DumpFactoredForm ARGS((DdManager *dd, int n, DdNode **f, char **inames, char **onames, FILE *fp));
+EXTERN DdNode * Cudd_bddConstrain ARGS((DdManager *dd, DdNode *f, DdNode *c));
+EXTERN DdNode * Cudd_bddRestrict ARGS((DdManager *dd, DdNode *f, DdNode *c));
+EXTERN DdNode * Cudd_addConstrain ARGS((DdManager *dd, DdNode *f, DdNode *c));
+EXTERN DdNode ** Cudd_bddConstrainDecomp ARGS((DdManager *dd, DdNode *f));
+EXTERN DdNode * Cudd_addRestrict ARGS((DdManager *dd, DdNode *f, DdNode *c));
+EXTERN DdNode ** Cudd_bddCharToVect ARGS((DdManager *dd, DdNode *f));
+EXTERN DdNode * Cudd_bddLICompaction ARGS((DdManager *dd, DdNode *f, DdNode *c));
+EXTERN DdNode * Cudd_bddSqueeze ARGS((DdManager *dd, DdNode *l, DdNode *u));
+EXTERN DdNode * Cudd_bddMinimize ARGS((DdManager *dd, DdNode *f, DdNode *c));
+EXTERN DdNode * Cudd_SubsetCompress ARGS((DdManager *dd, DdNode *f, int nvars, int threshold));
+EXTERN DdNode * Cudd_SupersetCompress ARGS((DdManager *dd, DdNode *f, int nvars, int threshold));
+EXTERN MtrNode * Cudd_MakeTreeNode ARGS((DdManager *dd, unsigned int low, unsigned int size, unsigned int type));
+EXTERN int Cudd_addHarwell ARGS((FILE *fp, DdManager *dd, DdNode **E, DdNode ***x, DdNode ***y, DdNode ***xn, DdNode ***yn_, int *nx, int *ny, int *m, int *n, int bx, int sx, int by, int sy, int pr));
+EXTERN DdManager * Cudd_Init ARGS((unsigned int numVars, unsigned int numVarsZ, unsigned int numSlots, unsigned int cacheSize, unsigned long maxMemory));
+EXTERN void Cudd_Quit ARGS((DdManager *unique));
+EXTERN int Cudd_PrintLinear ARGS((DdManager *table));
+EXTERN int Cudd_ReadLinear ARGS((DdManager *table, int x, int y));
+EXTERN DdNode * Cudd_bddLiteralSetIntersection ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_addMatrixMultiply ARGS((DdManager *dd, DdNode *A, DdNode *B, DdNode **z, int nz));
+EXTERN DdNode * Cudd_addTimesPlus ARGS((DdManager *dd, DdNode *A, DdNode *B, DdNode **z, int nz));
+EXTERN DdNode * Cudd_addTriangle ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode **z, int nz));
+EXTERN DdNode * Cudd_addOuterSum ARGS((DdManager *dd, DdNode *M, DdNode *r, DdNode *c));
+EXTERN DdNode * Cudd_PrioritySelect ARGS((DdManager *dd, DdNode *R, DdNode **x, DdNode **y, DdNode **z, DdNode *Pi, int n, DdNode * (*)(DdManager *, int, DdNode **, DdNode **, DdNode **)));
+EXTERN DdNode * Cudd_Xgty ARGS((DdManager *dd, int N, DdNode **z, DdNode **x, DdNode **y));
+EXTERN DdNode * Cudd_Xeqy ARGS((DdManager *dd, int N, DdNode **x, DdNode **y));
+EXTERN DdNode * Cudd_addXeqy ARGS((DdManager *dd, int N, DdNode **x, DdNode **y));
+EXTERN DdNode * Cudd_Dxygtdxz ARGS((DdManager *dd, int N, DdNode **x, DdNode **y, DdNode **z));
+EXTERN DdNode * Cudd_Dxygtdyz ARGS((DdManager *dd, int N, DdNode **x, DdNode **y, DdNode **z));
+EXTERN DdNode * Cudd_CProjection ARGS((DdManager *dd, DdNode *R, DdNode *Y));
+EXTERN DdNode * Cudd_addHamming ARGS((DdManager *dd, DdNode **xVars, DdNode **yVars, int nVars));
+EXTERN int Cudd_MinHammingDist ARGS((DdManager *dd, DdNode *f, int *minterm, int upperBound));
+EXTERN DdNode * Cudd_bddClosestCube ARGS((DdManager *dd, DdNode * f, DdNode *g, int *distance));
+EXTERN int Cudd_addRead ARGS((FILE *fp, DdManager *dd, DdNode **E, DdNode ***x, DdNode ***y, DdNode ***xn, DdNode ***yn_, int *nx, int *ny, int *m, int *n, int bx, int sx, int by, int sy));
+EXTERN int Cudd_bddRead ARGS((FILE *fp, DdManager *dd, DdNode **E, DdNode ***x, DdNode ***y, int *nx, int *ny, int *m, int *n, int bx, int sx, int by, int sy));
+EXTERN void Cudd_Ref ARGS((DdNode *n));
+EXTERN void Cudd_RecursiveDeref ARGS((DdManager *table, DdNode *n));
+EXTERN void Cudd_IterDerefBdd ARGS((DdManager *table, DdNode *n));
+EXTERN void Cudd_DelayedDerefBdd ARGS((DdManager * table, DdNode * n));
+EXTERN void Cudd_RecursiveDerefZdd ARGS((DdManager *table, DdNode *n));
+EXTERN void Cudd_Deref ARGS((DdNode *node));
+EXTERN int Cudd_CheckZeroRef ARGS((DdManager *manager));
+EXTERN int Cudd_ReduceHeap ARGS((DdManager *table, Cudd_ReorderingType heuristic, int minsize));
+EXTERN int Cudd_ShuffleHeap ARGS((DdManager *table, int *permutation));
+EXTERN DdNode * Cudd_Eval ARGS((DdManager *dd, DdNode *f, int *inputs));
+EXTERN DdNode * Cudd_ShortestPath ARGS((DdManager *manager, DdNode *f, int *weight, int *support, int *length));
+EXTERN DdNode * Cudd_LargestCube ARGS((DdManager *manager, DdNode *f, int *length));
+EXTERN int Cudd_ShortestLength ARGS((DdManager *manager, DdNode *f, int *weight));
+EXTERN DdNode * Cudd_Decreasing ARGS((DdManager *dd, DdNode *f, int i));
+EXTERN DdNode * Cudd_Increasing ARGS((DdManager *dd, DdNode *f, int i));
+EXTERN int Cudd_EquivDC ARGS((DdManager *dd, DdNode *F, DdNode *G, DdNode *D));
+EXTERN int Cudd_bddLeqUnless ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *D));
+EXTERN int Cudd_EqualSupNorm ARGS((DdManager *dd, DdNode *f, DdNode *g, CUDD_VALUE_TYPE tolerance, int pr));
+EXTERN DdNode * Cudd_bddMakePrime ARGS ((DdManager *dd, DdNode *cube, DdNode *f));
+EXTERN double * Cudd_CofMinterm ARGS((DdManager *dd, DdNode *node));
+EXTERN DdNode * Cudd_SolveEqn ARGS((DdManager * bdd, DdNode *F, DdNode *Y, DdNode **G, int **yIndex, int n));
+EXTERN DdNode * Cudd_VerifySol ARGS((DdManager * bdd, DdNode *F, DdNode **G, int *yIndex, int n));
+EXTERN DdNode * Cudd_SplitSet ARGS((DdManager *manager, DdNode *S, DdNode **xVars, int n, double m));
+EXTERN DdNode * Cudd_SubsetHeavyBranch ARGS((DdManager *dd, DdNode *f, int numVars, int threshold));
+EXTERN DdNode * Cudd_SupersetHeavyBranch ARGS((DdManager *dd, DdNode *f, int numVars, int threshold));
+EXTERN DdNode * Cudd_SubsetShortPaths ARGS((DdManager *dd, DdNode *f, int numVars, int threshold, int hardlimit));
+EXTERN DdNode * Cudd_SupersetShortPaths ARGS((DdManager *dd, DdNode *f, int numVars, int threshold, int hardlimit));
+EXTERN void Cudd_SymmProfile ARGS((DdManager *table, int lower, int upper));
+EXTERN unsigned int Cudd_Prime ARGS((unsigned int p));
+EXTERN int Cudd_PrintMinterm ARGS((DdManager *manager, DdNode *node));
+EXTERN int Cudd_bddPrintCover ARGS((DdManager *dd, DdNode *l, DdNode *u));
+EXTERN int Cudd_PrintDebug ARGS((DdManager *dd, DdNode *f, int n, int pr));
+EXTERN int Cudd_DagSize ARGS((DdNode *node));
+EXTERN int Cudd_EstimateCofactor ARGS((DdManager *dd, DdNode * node, int i, int phase));
+EXTERN int Cudd_EstimateCofactorSimple ARGS((DdNode * node, int i));
+EXTERN int Cudd_SharingSize ARGS((DdNode **nodeArray, int n));
+EXTERN double Cudd_CountMinterm ARGS((DdManager *manager, DdNode *node, int nvars));
+EXTERN int Cudd_EpdCountMinterm ARGS((DdManager *manager, DdNode *node, int nvars, EpDouble *epd));
+EXTERN double Cudd_CountPath ARGS((DdNode *node));
+EXTERN double Cudd_CountPathsToNonZero ARGS((DdNode *node));
+EXTERN DdNode * Cudd_Support ARGS((DdManager *dd, DdNode *f));
+EXTERN int * Cudd_SupportIndex ARGS((DdManager *dd, DdNode *f));
+EXTERN int Cudd_SupportSize ARGS((DdManager *dd, DdNode *f));
+EXTERN DdNode * Cudd_VectorSupport ARGS((DdManager *dd, DdNode **F, int n));
+EXTERN int * Cudd_VectorSupportIndex ARGS((DdManager *dd, DdNode **F, int n));
+EXTERN int Cudd_VectorSupportSize ARGS((DdManager *dd, DdNode **F, int n));
+EXTERN int Cudd_ClassifySupport ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode **common, DdNode **onlyF, DdNode **onlyG));
+EXTERN int Cudd_CountLeaves ARGS((DdNode *node));
+EXTERN int Cudd_bddPickOneCube ARGS((DdManager *ddm, DdNode *node, char *string));
+EXTERN DdNode * Cudd_bddPickOneMinterm ARGS((DdManager *dd, DdNode *f, DdNode **vars, int n));
+EXTERN DdNode ** Cudd_bddPickArbitraryMinterms ARGS((DdManager *dd, DdNode *f, DdNode **vars, int n, int k));
+EXTERN DdNode * Cudd_SubsetWithMaskVars ARGS((DdManager *dd, DdNode *f, DdNode **vars, int nvars, DdNode **maskVars, int mvars));
+EXTERN DdGen * Cudd_FirstCube ARGS((DdManager *dd, DdNode *f, int **cube, CUDD_VALUE_TYPE *value));
+EXTERN int Cudd_NextCube ARGS((DdGen *gen, int **cube, CUDD_VALUE_TYPE *value));
+EXTERN DdNode * Cudd_bddComputeCube ARGS((DdManager *dd, DdNode **vars, int *phase, int n));
+EXTERN DdNode * Cudd_addComputeCube ARGS((DdManager *dd, DdNode **vars, int *phase, int n));
+EXTERN DdNode * Cudd_CubeArrayToBdd ARGS((DdManager *dd, int *array));
+EXTERN int Cudd_BddToCubeArray ARGS((DdManager *dd, DdNode *cube, int *array));
+EXTERN DdGen * Cudd_FirstNode ARGS((DdManager *dd, DdNode *f, DdNode **node));
+EXTERN int Cudd_NextNode ARGS((DdGen *gen, DdNode **node));
+EXTERN int Cudd_GenFree ARGS((DdGen *gen));
+EXTERN int Cudd_IsGenEmpty ARGS((DdGen *gen));
+EXTERN DdNode * Cudd_IndicesToCube ARGS((DdManager *dd, int *array, int n));
+EXTERN void Cudd_PrintVersion ARGS((FILE *fp));
+EXTERN double Cudd_AverageDistance ARGS((DdManager *dd));
+EXTERN long Cudd_Random ARGS(());
+EXTERN void Cudd_Srandom ARGS((long seed));
+EXTERN double Cudd_Density ARGS((DdManager *dd, DdNode *f, int nvars));
+EXTERN void Cudd_OutOfMem ARGS((long size));
+EXTERN int Cudd_zddCount ARGS((DdManager *zdd, DdNode *P));
+EXTERN double Cudd_zddCountDouble ARGS((DdManager *zdd, DdNode *P));
+EXTERN DdNode * Cudd_zddProduct ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_zddUnateProduct ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_zddWeakDiv ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_zddDivide ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_zddWeakDivF ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_zddDivideF ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_zddComplement ARGS((DdManager *dd, DdNode *node));
+EXTERN MtrNode * Cudd_MakeZddTreeNode ARGS((DdManager *dd, unsigned int low, unsigned int size, unsigned int type));
+EXTERN DdNode * Cudd_zddIsop ARGS((DdManager *dd, DdNode *L, DdNode *U, DdNode **zdd_I));
+EXTERN DdNode * Cudd_bddIsop ARGS((DdManager *dd, DdNode *L, DdNode *U));
+EXTERN DdNode * Cudd_MakeBddFromZddCover ARGS((DdManager *dd, DdNode *node));
+EXTERN int Cudd_zddDagSize ARGS((DdNode *p_node));
+EXTERN double Cudd_zddCountMinterm ARGS((DdManager *zdd, DdNode *node, int path));
+EXTERN void Cudd_zddPrintSubtable ARGS((DdManager *table));
+EXTERN DdNode * Cudd_zddPortFromBdd ARGS((DdManager *dd, DdNode *B));
+EXTERN DdNode * Cudd_zddPortToBdd ARGS((DdManager *dd, DdNode *f));
+EXTERN int Cudd_zddReduceHeap ARGS((DdManager *table, Cudd_ReorderingType heuristic, int minsize));
+EXTERN int Cudd_zddShuffleHeap ARGS((DdManager *table, int *permutation));
+EXTERN DdNode * Cudd_zddIte ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *h));
+EXTERN DdNode * Cudd_zddUnion ARGS((DdManager *dd, DdNode *P, DdNode *Q));
+EXTERN DdNode * Cudd_zddIntersect ARGS((DdManager *dd, DdNode *P, DdNode *Q));
+EXTERN DdNode * Cudd_zddDiff ARGS((DdManager *dd, DdNode *P, DdNode *Q));
+EXTERN DdNode * Cudd_zddDiffConst ARGS((DdManager *zdd, DdNode *P, DdNode *Q));
+EXTERN DdNode * Cudd_zddSubset1 ARGS((DdManager *dd, DdNode *P, int var));
+EXTERN DdNode * Cudd_zddSubset0 ARGS((DdManager *dd, DdNode *P, int var));
+EXTERN DdNode * Cudd_zddChange ARGS((DdManager *dd, DdNode *P, int var));
+EXTERN void Cudd_zddSymmProfile ARGS((DdManager *table, int lower, int upper));
+EXTERN int Cudd_zddPrintMinterm ARGS((DdManager *zdd, DdNode *node));
+EXTERN int Cudd_zddPrintCover ARGS((DdManager *zdd, DdNode *node));
+EXTERN int Cudd_zddPrintDebug ARGS((DdManager *zdd, DdNode *f, int n, int pr));
+EXTERN DdGen * Cudd_zddFirstPath ARGS((DdManager *zdd, DdNode *f, int **path));
+EXTERN int Cudd_zddNextPath ARGS((DdGen *gen, int **path));
+EXTERN char * Cudd_zddCoverPathToString ARGS((DdManager *zdd, int *path, char *str));
+EXTERN int Cudd_zddDumpDot ARGS((DdManager *dd, int n, DdNode **f, char **inames, char **onames, FILE *fp));
+EXTERN int Cudd_bddSetPiVar ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddSetPsVar ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddSetNsVar ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddIsPiVar ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddIsPsVar ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddIsNsVar ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddSetPairIndex ARGS((DdManager *dd, int index, int pairIndex));
+EXTERN int Cudd_bddReadPairIndex ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddSetVarToBeGrouped ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddSetVarHardGroup ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddResetVarToBeGrouped ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddIsVarToBeGrouped ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddSetVarToBeUngrouped ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddIsVarToBeUngrouped ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddIsVarHardGroup ARGS((DdManager *dd, int index));
+
+/**AutomaticEnd***************************************************************/
+
+#endif /* _CUDD */
diff --git a/src/bdd/cudd/cudd.make b/src/bdd/cudd/cudd.make
new file mode 100644
index 00000000..7cb342a2
--- /dev/null
+++ b/src/bdd/cudd/cudd.make
@@ -0,0 +1,42 @@
+CSRC += cuddAPI.c cuddAddAbs.c cuddAddApply.c cuddAddFind.c cuddAddIte.c \
+ cuddAddInv.c cuddAddNeg.c cuddAddWalsh.c cuddAndAbs.c \
+ cuddAnneal.c cuddApa.c cuddApprox.c cuddBddAbs.c cuddBddCorr.c\
+ cuddBddIte.c cuddBridge.c cuddCache.c cuddCheck.c cuddClip.c \
+ cuddCof.c cuddCompose.c cuddDecomp.c cuddEssent.c cuddExact.c \
+ cuddExport.c cuddGenCof.c cuddGenetic.c \
+ cuddGroup.c cuddHarwell.c cuddInit.c cuddInteract.c \
+ cuddLCache.c cuddLevelQ.c \
+ cuddLinear.c cuddLiteral.c cuddMatMult.c cuddPriority.c \
+ cuddRead.c cuddRef.c cuddReorder.c cuddSat.c cuddSign.c \
+ cuddSolve.c cuddSplit.c cuddSubsetHB.c cuddSubsetSP.c cuddSymmetry.c \
+ cuddTable.c cuddUtil.c cuddWindow.c cuddZddCount.c cuddZddFuncs.c \
+ cuddZddGroup.c cuddZddIsop.c cuddZddLin.c cuddZddMisc.c cuddZddPort.c \
+ cuddZddReord.c cuddZddSetop.c cuddZddSymm.c cuddZddUtil.c
+
+HEADERS += cudd.h cuddInt.h
+MISC += testcudd.c r7x8.1.mat doc/cudd.ps doc/cuddAllAbs.html doc/cuddAllDet.html \
+ doc/cuddExtAbs.html doc/cuddExtDet.html doc/cuddIntro.css \
+ doc/cuddIntro.html doc/footnode.html doc/img1.gif doc/img2.gif \
+ doc/img3.gif doc/img4.gif doc/img5.gif doc/index.html \
+ doc/node1.html doc/node2.html doc/node3.html doc/node4.html \
+ doc/node5.html doc/node6.html doc/node7.html doc/node8.html \
+ doc/icons/change_begin.gif \
+ doc/icons/change_delete.gif \
+ doc/icons/change_end.gif \
+ doc/icons/contents_motif.gif \
+ doc/icons/cross_ref_motif.gif \
+ doc/icons/foot_motif.gif \
+ doc/icons/image.gif \
+ doc/icons/index_motif.gif \
+ doc/icons/next_group_motif.gif \
+ doc/icons/next_group_motif_gr.gif \
+ doc/icons/next_motif.gif \
+ doc/icons/next_motif_gr.gif \
+ doc/icons/previous_group_motif.gif \
+ doc/icons/previous_group_motif_gr.gif \
+ doc/icons/previous_motif.gif \
+ doc/icons/previous_motif_gr.gif \
+ doc/icons/up_motif.gif \
+ doc/icons/up_motif_gr.gif
+
+DEPENDENCYFILES = $(CSRC)
diff --git a/src/bdd/cudd/cuddAPI.c b/src/bdd/cudd/cuddAPI.c
new file mode 100644
index 00000000..2acde7cd
--- /dev/null
+++ b/src/bdd/cudd/cuddAPI.c
@@ -0,0 +1,4409 @@
+/**CFile***********************************************************************
+
+ FileName [cuddAPI.c]
+
+ PackageName [cudd]
+
+ Synopsis [Application interface functions.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_addNewVar()
+ <li> Cudd_addNewVarAtLevel()
+ <li> Cudd_bddNewVar()
+ <li> Cudd_bddNewVarAtLevel()
+ <li> Cudd_addIthVar()
+ <li> Cudd_bddIthVar()
+ <li> Cudd_zddIthVar()
+ <li> Cudd_zddVarsFromBddVars()
+ <li> Cudd_addConst()
+ <li> Cudd_IsNonConstant()
+ <li> Cudd_AutodynEnable()
+ <li> Cudd_AutodynDisable()
+ <li> Cudd_ReorderingStatus()
+ <li> Cudd_AutodynEnableZdd()
+ <li> Cudd_AutodynDisableZdd()
+ <li> Cudd_ReorderingStatusZdd()
+ <li> Cudd_zddRealignmentEnabled()
+ <li> Cudd_zddRealignEnable()
+ <li> Cudd_zddRealignDisable()
+ <li> Cudd_bddRealignmentEnabled()
+ <li> Cudd_bddRealignEnable()
+ <li> Cudd_bddRealignDisable()
+ <li> Cudd_ReadOne()
+ <li> Cudd_ReadZddOne()
+ <li> Cudd_ReadZero()
+ <li> Cudd_ReadLogicZero()
+ <li> Cudd_ReadPlusInfinity()
+ <li> Cudd_ReadMinusInfinity()
+ <li> Cudd_ReadBackground()
+ <li> Cudd_SetBackground()
+ <li> Cudd_ReadCacheSlots()
+ <li> Cudd_ReadCacheUsedSlots()
+ <li> Cudd_ReadCacheLookUps()
+ <li> Cudd_ReadCacheHits()
+ <li> Cudd_ReadMinHit()
+ <li> Cudd_SetMinHit()
+ <li> Cudd_ReadLooseUpTo()
+ <li> Cudd_SetLooseUpTo()
+ <li> Cudd_ReadMaxCache()
+ <li> Cudd_ReadMaxCacheHard()
+ <li> Cudd_SetMaxCacheHard()
+ <li> Cudd_ReadSize()
+ <li> Cudd_ReadSlots()
+ <li> Cudd_ReadUsedSlots()
+ <li> Cudd_ExpectedUsedSlots()
+ <li> Cudd_ReadKeys()
+ <li> Cudd_ReadDead()
+ <li> Cudd_ReadMinDead()
+ <li> Cudd_ReadReorderings()
+ <li> Cudd_ReadReorderingTime()
+ <li> Cudd_ReadGarbageCollections()
+ <li> Cudd_ReadGarbageCollectionTime()
+ <li> Cudd_ReadNodesFreed()
+ <li> Cudd_ReadNodesDropped()
+ <li> Cudd_ReadUniqueLookUps()
+ <li> Cudd_ReadUniqueLinks()
+ <li> Cudd_ReadSiftMaxVar()
+ <li> Cudd_SetSiftMaxVar()
+ <li> Cudd_ReadMaxGrowth()
+ <li> Cudd_SetMaxGrowth()
+ <li> Cudd_ReadMaxGrowthAlternate()
+ <li> Cudd_SetMaxGrowthAlternate()
+ <li> Cudd_ReadReorderingCycle()
+ <li> Cudd_SetReorderingCycle()
+ <li> Cudd_ReadTree()
+ <li> Cudd_SetTree()
+ <li> Cudd_FreeTree()
+ <li> Cudd_ReadZddTree()
+ <li> Cudd_SetZddTree()
+ <li> Cudd_FreeZddTree()
+ <li> Cudd_NodeReadIndex()
+ <li> Cudd_ReadPerm()
+ <li> Cudd_ReadInvPerm()
+ <li> Cudd_ReadVars()
+ <li> Cudd_ReadEpsilon()
+ <li> Cudd_SetEpsilon()
+ <li> Cudd_ReadGroupCheck()
+ <li> Cudd_SetGroupcheck()
+ <li> Cudd_GarbageCollectionEnabled()
+ <li> Cudd_EnableGarbageCollection()
+ <li> Cudd_DisableGarbageCollection()
+ <li> Cudd_DeadAreCounted()
+ <li> Cudd_TurnOnCountDead()
+ <li> Cudd_TurnOffCountDead()
+ <li> Cudd_ReadRecomb()
+ <li> Cudd_SetRecomb()
+ <li> Cudd_ReadSymmviolation()
+ <li> Cudd_SetSymmviolation()
+ <li> Cudd_ReadArcviolation()
+ <li> Cudd_SetArcviolation()
+ <li> Cudd_ReadPopulationSize()
+ <li> Cudd_SetPopulationSize()
+ <li> Cudd_ReadNumberXovers()
+ <li> Cudd_SetNumberXovers()
+ <li> Cudd_ReadMemoryInUse()
+ <li> Cudd_PrintInfo()
+ <li> Cudd_ReadPeakNodeCount()
+ <li> Cudd_ReadPeakLiveNodeCount()
+ <li> Cudd_ReadNodeCount()
+ <li> Cudd_zddReadNodeCount()
+ <li> Cudd_AddHook()
+ <li> Cudd_RemoveHook()
+ <li> Cudd_IsInHook()
+ <li> Cudd_StdPreReordHook()
+ <li> Cudd_StdPostReordHook()
+ <li> Cudd_EnableReorderingReporting()
+ <li> Cudd_DisableReorderingReporting()
+ <li> Cudd_ReorderingReporting()
+ <li> Cudd_ReadErrorCode()
+ <li> Cudd_ClearErrorCode()
+ <li> Cudd_ReadStdout()
+ <li> Cudd_SetStdout()
+ <li> Cudd_ReadStderr()
+ <li> Cudd_SetStderr()
+ <li> Cudd_ReadNextReordering()
+ <li> Cudd_SetNextReordering()
+ <li> Cudd_ReadSwapSteps()
+ <li> Cudd_ReadMaxLive()
+ <li> Cudd_SetMaxLive()
+ <li> Cudd_ReadMaxMemory()
+ <li> Cudd_SetMaxMemory()
+ <li> Cudd_bddBindVar()
+ <li> Cudd_bddUnbindVar()
+ <li> Cudd_bddVarIsBound()
+ <li> Cudd_bddSetPiVar()
+ <li> Cudd_bddSetPsVar()
+ <li> Cudd_bddSetNsVar()
+ <li> Cudd_bddIsPiVar()
+ <li> Cudd_bddIsPsVar()
+ <li> Cudd_bddIsNsVar()
+ <li> Cudd_bddSetPairIndex()
+ <li> Cudd_bddReadPairIndex()
+ <li> Cudd_bddSetVarToBeGrouped()
+ <li> Cudd_bddSetVarHardGroup()
+ <li> Cudd_bddResetVarToBeGrouped()
+ <li> Cudd_bddIsVarToBeGrouped()
+ <li> Cudd_bddSetVarToBeUngrouped()
+ <li> Cudd_bddIsVarToBeUngrouped()
+ <li> Cudd_bddIsVarHardGroup()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> fixVarTree()
+ </ul>]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddAPI.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static void fixVarTree ARGS((MtrNode *treenode, int *perm, int size));
+static int addMultiplicityGroups ARGS((DdManager *dd, MtrNode *treenode, int multiplicity, char *vmask, char *lmask));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns a new ADD variable.]
+
+ Description [Creates a new ADD variable. The new variable has an
+ index equal to the largest previous index plus 1. Returns a
+ pointer to the new variable if successful; NULL otherwise.
+ An ADD variable differs from a BDD variable because it points to the
+ arithmetic zero, instead of having a complement pointer to 1. ]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddNewVar Cudd_addIthVar Cudd_addConst
+ Cudd_addNewVarAtLevel]
+
+******************************************************************************/
+DdNode *
+Cudd_addNewVar(
+ DdManager * dd)
+{
+ DdNode *res;
+
+ if ((unsigned int) dd->size >= CUDD_MAXINDEX - 1) return(NULL);
+ do {
+ dd->reordered = 0;
+ res = cuddUniqueInter(dd,dd->size,DD_ONE(dd),DD_ZERO(dd));
+ } while (dd->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_addNewVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns a new ADD variable at a specified level.]
+
+ Description [Creates a new ADD variable. The new variable has an
+ index equal to the largest previous index plus 1 and is positioned at
+ the specified level in the order. Returns a pointer to the new
+ variable if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addNewVar Cudd_addIthVar Cudd_bddNewVarAtLevel]
+
+******************************************************************************/
+DdNode *
+Cudd_addNewVarAtLevel(
+ DdManager * dd,
+ int level)
+{
+ DdNode *res;
+
+ if ((unsigned int) dd->size >= CUDD_MAXINDEX - 1) return(NULL);
+ if (level >= dd->size) return(Cudd_addIthVar(dd,level));
+ if (!cuddInsertSubtables(dd,1,level)) return(NULL);
+ do {
+ dd->reordered = 0;
+ res = cuddUniqueInter(dd,dd->size - 1,DD_ONE(dd),DD_ZERO(dd));
+ } while (dd->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_addNewVarAtLevel */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns a new BDD variable.]
+
+ Description [Creates a new BDD variable. The new variable has an
+ index equal to the largest previous index plus 1. Returns a
+ pointer to the new variable if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addNewVar Cudd_bddIthVar Cudd_bddNewVarAtLevel]
+
+******************************************************************************/
+DdNode *
+Cudd_bddNewVar(
+ DdManager * dd)
+{
+ DdNode *res;
+
+ if ((unsigned int) dd->size >= CUDD_MAXINDEX - 1) return(NULL);
+ res = cuddUniqueInter(dd,dd->size,dd->one,Cudd_Not(dd->one));
+
+ return(res);
+
+} /* end of Cudd_bddNewVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns a new BDD variable at a specified level.]
+
+ Description [Creates a new BDD variable. The new variable has an
+ index equal to the largest previous index plus 1 and is positioned at
+ the specified level in the order. Returns a pointer to the new
+ variable if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddNewVar Cudd_bddIthVar Cudd_addNewVarAtLevel]
+
+******************************************************************************/
+DdNode *
+Cudd_bddNewVarAtLevel(
+ DdManager * dd,
+ int level)
+{
+ DdNode *res;
+
+ if ((unsigned int) dd->size >= CUDD_MAXINDEX - 1) return(NULL);
+ if (level >= dd->size) return(Cudd_bddIthVar(dd,level));
+ if (!cuddInsertSubtables(dd,1,level)) return(NULL);
+ res = dd->vars[dd->size - 1];
+
+ return(res);
+
+} /* end of Cudd_bddNewVarAtLevel */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the ADD variable with index i.]
+
+ Description [Retrieves the ADD variable with index i if it already
+ exists, or creates a new ADD variable. Returns a pointer to the
+ variable if successful; NULL otherwise. An ADD variable differs from
+ a BDD variable because it points to the arithmetic zero, instead of
+ having a complement pointer to 1. ]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addNewVar Cudd_bddIthVar Cudd_addConst
+ Cudd_addNewVarAtLevel]
+
+******************************************************************************/
+DdNode *
+Cudd_addIthVar(
+ DdManager * dd,
+ int i)
+{
+ DdNode *res;
+
+ if ((unsigned int) i >= CUDD_MAXINDEX - 1) return(NULL);
+ do {
+ dd->reordered = 0;
+ res = cuddUniqueInter(dd,i,DD_ONE(dd),DD_ZERO(dd));
+ } while (dd->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_addIthVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the BDD variable with index i.]
+
+ Description [Retrieves the BDD variable with index i if it already
+ exists, or creates a new BDD variable. Returns a pointer to the
+ variable if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddNewVar Cudd_addIthVar Cudd_bddNewVarAtLevel
+ Cudd_ReadVars]
+
+******************************************************************************/
+DdNode *
+Cudd_bddIthVar(
+ DdManager * dd,
+ int i)
+{
+ DdNode *res;
+
+ if ((unsigned int) i >= CUDD_MAXINDEX - 1) return(NULL);
+ if (i < dd->size) {
+ res = dd->vars[i];
+ } else {
+ res = cuddUniqueInter(dd,i,dd->one,Cudd_Not(dd->one));
+ }
+
+ return(res);
+
+} /* end of Cudd_bddIthVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the ZDD variable with index i.]
+
+ Description [Retrieves the ZDD variable with index i if it already
+ exists, or creates a new ZDD variable. Returns a pointer to the
+ variable if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIthVar Cudd_addIthVar]
+
+******************************************************************************/
+DdNode *
+Cudd_zddIthVar(
+ DdManager * dd,
+ int i)
+{
+ DdNode *res;
+ DdNode *zvar;
+ DdNode *lower;
+ int j;
+
+ if ((unsigned int) i >= CUDD_MAXINDEX - 1) return(NULL);
+
+ /* The i-th variable function has the following structure:
+ ** at the level corresponding to index i there is a node whose "then"
+ ** child points to the universe, and whose "else" child points to zero.
+ ** Above that level there are nodes with identical children.
+ */
+
+ /* First we build the node at the level of index i. */
+ lower = (i < dd->sizeZ - 1) ? dd->univ[dd->permZ[i]+1] : DD_ONE(dd);
+ do {
+ dd->reordered = 0;
+ zvar = cuddUniqueInterZdd(dd, i, lower, DD_ZERO(dd));
+ } while (dd->reordered == 1);
+
+ if (zvar == NULL)
+ return(NULL);
+ cuddRef(zvar);
+
+ /* Now we add the "filler" nodes above the level of index i. */
+ for (j = dd->permZ[i] - 1; j >= 0; j--) {
+ do {
+ dd->reordered = 0;
+ res = cuddUniqueInterZdd(dd, dd->invpermZ[j], zvar, zvar);
+ } while (dd->reordered == 1);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(dd,zvar);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDerefZdd(dd,zvar);
+ zvar = res;
+ }
+ cuddDeref(zvar);
+ return(zvar);
+
+} /* end of Cudd_zddIthVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Creates one or more ZDD variables for each BDD variable.]
+
+ Description [Creates one or more ZDD variables for each BDD
+ variable. If some ZDD variables already exist, only the missing
+ variables are created. Parameter multiplicity allows the caller to
+ control how many variables are created for each BDD variable in
+ existence. For instance, if ZDDs are used to represent covers, two
+ ZDD variables are required for each BDD variable. The order of the
+ BDD variables is transferred to the ZDD variables. If a variable
+ group tree exists for the BDD variables, a corresponding ZDD
+ variable group tree is created by expanding the BDD variable
+ tree. In any case, the ZDD variables derived from the same BDD
+ variable are merged in a ZDD variable group. If a ZDD variable group
+ tree exists, it is freed. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddNewVar Cudd_bddIthVar Cudd_bddNewVarAtLevel]
+
+******************************************************************************/
+int
+Cudd_zddVarsFromBddVars(
+ DdManager * dd /* DD manager */,
+ int multiplicity /* how many ZDD variables are created for each BDD variable */)
+{
+ int res;
+ int i, j;
+ int allnew;
+ int *permutation;
+
+ if (multiplicity < 1) return(0);
+ allnew = dd->sizeZ == 0;
+ if (dd->size * multiplicity > dd->sizeZ) {
+ res = cuddResizeTableZdd(dd,dd->size * multiplicity - 1);
+ if (res == 0) return(0);
+ }
+ /* Impose the order of the BDD variables to the ZDD variables. */
+ if (allnew) {
+ for (i = 0; i < dd->size; i++) {
+ for (j = 0; j < multiplicity; j++) {
+ dd->permZ[i * multiplicity + j] =
+ dd->perm[i] * multiplicity + j;
+ dd->invpermZ[dd->permZ[i * multiplicity + j]] =
+ i * multiplicity + j;
+ }
+ }
+ for (i = 0; i < dd->sizeZ; i++) {
+ dd->univ[i]->index = dd->invpermZ[i];
+ }
+ } else {
+ permutation = ALLOC(int,dd->sizeZ);
+ if (permutation == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (i = 0; i < dd->size; i++) {
+ for (j = 0; j < multiplicity; j++) {
+ permutation[i * multiplicity + j] =
+ dd->invperm[i] * multiplicity + j;
+ }
+ }
+ for (i = dd->size * multiplicity; i < dd->sizeZ; i++) {
+ permutation[i] = i;
+ }
+ res = Cudd_zddShuffleHeap(dd, permutation);
+ FREE(permutation);
+ if (res == 0) return(0);
+ }
+ /* Copy and expand the variable group tree if it exists. */
+ if (dd->treeZ != NULL) {
+ Cudd_FreeZddTree(dd);
+ }
+ if (dd->tree != NULL) {
+ dd->treeZ = Mtr_CopyTree(dd->tree, multiplicity);
+ if (dd->treeZ == NULL) return(0);
+ } else if (multiplicity > 1) {
+ dd->treeZ = Mtr_InitGroupTree(0, dd->sizeZ);
+ if (dd->treeZ == NULL) return(0);
+ dd->treeZ->index = dd->invpermZ[0];
+ }
+ /* Create groups for the ZDD variables derived from the same BDD variable.
+ */
+ if (multiplicity > 1) {
+ char *vmask, *lmask;
+
+ vmask = ALLOC(char, dd->size);
+ if (vmask == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ lmask = ALLOC(char, dd->size);
+ if (lmask == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (i = 0; i < dd->size; i++) {
+ vmask[i] = lmask[i] = 0;
+ }
+ res = addMultiplicityGroups(dd,dd->treeZ,multiplicity,vmask,lmask);
+ FREE(vmask);
+ FREE(lmask);
+ if (res == 0) return(0);
+ }
+ return(1);
+
+} /* end of Cudd_zddVarsFromBddVars */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the ADD for constant c.]
+
+ Description [Retrieves the ADD for constant c if it already
+ exists, or creates a new ADD. Returns a pointer to the
+ ADD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addNewVar Cudd_addIthVar]
+
+******************************************************************************/
+DdNode *
+Cudd_addConst(
+ DdManager * dd,
+ CUDD_VALUE_TYPE c)
+{
+ return(cuddUniqueConst(dd,c));
+
+} /* end of Cudd_addConst */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns 1 if a DD node is not constant.]
+
+ Description [Returns 1 if a DD node is not constant. This function is
+ useful to test the results of Cudd_bddIteConstant, Cudd_addIteConstant,
+ Cudd_addEvalConst. These results may be a special value signifying
+ non-constant. In the other cases the macro Cudd_IsConstant can be used.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_IsConstant Cudd_bddIteConstant Cudd_addIteConstant
+ Cudd_addEvalConst]
+
+******************************************************************************/
+int
+Cudd_IsNonConstant(
+ DdNode *f)
+{
+ return(f == DD_NON_CONSTANT || !Cudd_IsConstant(f));
+
+} /* end of Cudd_IsNonConstant */
+
+
+/**Function********************************************************************
+
+ Synopsis [Enables automatic dynamic reordering of BDDs and ADDs.]
+
+ Description [Enables automatic dynamic reordering of BDDs and
+ ADDs. Parameter method is used to determine the method used for
+ reordering. If CUDD_REORDER_SAME is passed, the method is
+ unchanged.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_AutodynDisable Cudd_ReorderingStatus
+ Cudd_AutodynEnableZdd]
+
+******************************************************************************/
+void
+Cudd_AutodynEnable(
+ DdManager * unique,
+ Cudd_ReorderingType method)
+{
+ unique->autoDyn = 1;
+ if (method != CUDD_REORDER_SAME) {
+ unique->autoMethod = method;
+ }
+#ifndef DD_NO_DEATH_ROW
+ /* If reordering is enabled, using the death row causes too many
+ ** invocations. Hence, we shrink the death row to just one entry.
+ */
+ cuddClearDeathRow(unique);
+ unique->deathRowDepth = 1;
+ unique->deadMask = unique->deathRowDepth - 1;
+ if ((unsigned) unique->nextDead > unique->deadMask) {
+ unique->nextDead = 0;
+ }
+ unique->deathRow = REALLOC(DdNodePtr, unique->deathRow,
+ unique->deathRowDepth);
+#endif
+ return;
+
+} /* end of Cudd_AutodynEnable */
+
+
+/**Function********************************************************************
+
+ Synopsis [Disables automatic dynamic reordering.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_AutodynEnable Cudd_ReorderingStatus
+ Cudd_AutodynDisableZdd]
+
+******************************************************************************/
+void
+Cudd_AutodynDisable(
+ DdManager * unique)
+{
+ unique->autoDyn = 0;
+ return;
+
+} /* end of Cudd_AutodynDisable */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reports the status of automatic dynamic reordering of BDDs
+ and ADDs.]
+
+ Description [Reports the status of automatic dynamic reordering of
+ BDDs and ADDs. Parameter method is set to the reordering method
+ currently selected. Returns 1 if automatic reordering is enabled; 0
+ otherwise.]
+
+ SideEffects [Parameter method is set to the reordering method currently
+ selected.]
+
+ SeeAlso [Cudd_AutodynEnable Cudd_AutodynDisable
+ Cudd_ReorderingStatusZdd]
+
+******************************************************************************/
+int
+Cudd_ReorderingStatus(
+ DdManager * unique,
+ Cudd_ReorderingType * method)
+{
+ *method = unique->autoMethod;
+ return(unique->autoDyn);
+
+} /* end of Cudd_ReorderingStatus */
+
+
+/**Function********************************************************************
+
+ Synopsis [Enables automatic dynamic reordering of ZDDs.]
+
+ Description [Enables automatic dynamic reordering of ZDDs. Parameter
+ method is used to determine the method used for reordering ZDDs. If
+ CUDD_REORDER_SAME is passed, the method is unchanged.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_AutodynDisableZdd Cudd_ReorderingStatusZdd
+ Cudd_AutodynEnable]
+
+******************************************************************************/
+void
+Cudd_AutodynEnableZdd(
+ DdManager * unique,
+ Cudd_ReorderingType method)
+{
+ unique->autoDynZ = 1;
+ if (method != CUDD_REORDER_SAME) {
+ unique->autoMethodZ = method;
+ }
+ return;
+
+} /* end of Cudd_AutodynEnableZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Disables automatic dynamic reordering of ZDDs.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_AutodynEnableZdd Cudd_ReorderingStatusZdd
+ Cudd_AutodynDisable]
+
+******************************************************************************/
+void
+Cudd_AutodynDisableZdd(
+ DdManager * unique)
+{
+ unique->autoDynZ = 0;
+ return;
+
+} /* end of Cudd_AutodynDisableZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reports the status of automatic dynamic reordering of ZDDs.]
+
+ Description [Reports the status of automatic dynamic reordering of
+ ZDDs. Parameter method is set to the ZDD reordering method currently
+ selected. Returns 1 if automatic reordering is enabled; 0
+ otherwise.]
+
+ SideEffects [Parameter method is set to the ZDD reordering method currently
+ selected.]
+
+ SeeAlso [Cudd_AutodynEnableZdd Cudd_AutodynDisableZdd
+ Cudd_ReorderingStatus]
+
+******************************************************************************/
+int
+Cudd_ReorderingStatusZdd(
+ DdManager * unique,
+ Cudd_ReorderingType * method)
+{
+ *method = unique->autoMethodZ;
+ return(unique->autoDynZ);
+
+} /* end of Cudd_ReorderingStatusZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tells whether the realignment of ZDD order to BDD order is
+ enabled.]
+
+ Description [Returns 1 if the realignment of ZDD order to BDD order is
+ enabled; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddRealignEnable Cudd_zddRealignDisable
+ Cudd_bddRealignEnable Cudd_bddRealignDisable]
+
+******************************************************************************/
+int
+Cudd_zddRealignmentEnabled(
+ DdManager * unique)
+{
+ return(unique->realign);
+
+} /* end of Cudd_zddRealignmentEnabled */
+
+
+/**Function********************************************************************
+
+ Synopsis [Enables realignment of ZDD order to BDD order.]
+
+ Description [Enables realignment of the ZDD variable order to the
+ BDD variable order after the BDDs and ADDs have been reordered. The
+ number of ZDD variables must be a multiple of the number of BDD
+ variables for realignment to make sense. If this condition is not met,
+ Cudd_ReduceHeap will return 0. Let <code>M</code> be the
+ ratio of the two numbers. For the purpose of realignment, the ZDD
+ variables from <code>M*i</code> to <code>(M+1)*i-1</code> are
+ reagarded as corresponding to BDD variable <code>i</code>. Realignment
+ is initially disabled.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReduceHeap Cudd_zddRealignDisable
+ Cudd_zddRealignmentEnabled Cudd_bddRealignDisable
+ Cudd_bddRealignmentEnabled]
+
+******************************************************************************/
+void
+Cudd_zddRealignEnable(
+ DdManager * unique)
+{
+ unique->realign = 1;
+ return;
+
+} /* end of Cudd_zddRealignEnable */
+
+
+/**Function********************************************************************
+
+ Synopsis [Disables realignment of ZDD order to BDD order.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddRealignEnable Cudd_zddRealignmentEnabled
+ Cudd_bddRealignEnable Cudd_bddRealignmentEnabled]
+
+******************************************************************************/
+void
+Cudd_zddRealignDisable(
+ DdManager * unique)
+{
+ unique->realign = 0;
+ return;
+
+} /* end of Cudd_zddRealignDisable */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tells whether the realignment of BDD order to ZDD order is
+ enabled.]
+
+ Description [Returns 1 if the realignment of BDD order to ZDD order is
+ enabled; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddRealignEnable Cudd_bddRealignDisable
+ Cudd_zddRealignEnable Cudd_zddRealignDisable]
+
+******************************************************************************/
+int
+Cudd_bddRealignmentEnabled(
+ DdManager * unique)
+{
+ return(unique->realignZ);
+
+} /* end of Cudd_bddRealignmentEnabled */
+
+
+/**Function********************************************************************
+
+ Synopsis [Enables realignment of BDD order to ZDD order.]
+
+ Description [Enables realignment of the BDD variable order to the
+ ZDD variable order after the ZDDs have been reordered. The
+ number of ZDD variables must be a multiple of the number of BDD
+ variables for realignment to make sense. If this condition is not met,
+ Cudd_zddReduceHeap will return 0. Let <code>M</code> be the
+ ratio of the two numbers. For the purpose of realignment, the ZDD
+ variables from <code>M*i</code> to <code>(M+1)*i-1</code> are
+ reagarded as corresponding to BDD variable <code>i</code>. Realignment
+ is initially disabled.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddReduceHeap Cudd_bddRealignDisable
+ Cudd_bddRealignmentEnabled Cudd_zddRealignDisable
+ Cudd_zddRealignmentEnabled]
+
+******************************************************************************/
+void
+Cudd_bddRealignEnable(
+ DdManager * unique)
+{
+ unique->realignZ = 1;
+ return;
+
+} /* end of Cudd_bddRealignEnable */
+
+
+/**Function********************************************************************
+
+ Synopsis [Disables realignment of ZDD order to BDD order.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddRealignEnable Cudd_bddRealignmentEnabled
+ Cudd_zddRealignEnable Cudd_zddRealignmentEnabled]
+
+******************************************************************************/
+void
+Cudd_bddRealignDisable(
+ DdManager * unique)
+{
+ unique->realignZ = 0;
+ return;
+
+} /* end of Cudd_bddRealignDisable */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the one constant of the manager.]
+
+ Description [Returns the one constant of the manager. The one
+ constant is common to ADDs and BDDs.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadZero Cudd_ReadLogicZero Cudd_ReadZddOne]
+
+******************************************************************************/
+DdNode *
+Cudd_ReadOne(
+ DdManager * dd)
+{
+ return(dd->one);
+
+} /* end of Cudd_ReadOne */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the ZDD for the constant 1 function.]
+
+ Description [Returns the ZDD for the constant 1 function.
+ The representation of the constant 1 function as a ZDD depends on
+ how many variables it (nominally) depends on. The index of the
+ topmost variable in the support is given as argument <code>i</code>.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadOne]
+
+******************************************************************************/
+DdNode *
+Cudd_ReadZddOne(
+ DdManager * dd,
+ int i)
+{
+ if (i < 0)
+ return(NULL);
+ return(i < dd->sizeZ ? dd->univ[i] : DD_ONE(dd));
+
+} /* end of Cudd_ReadZddOne */
+
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the zero constant of the manager.]
+
+ Description [Returns the zero constant of the manager. The zero
+ constant is the arithmetic zero, rather than the logic zero. The
+ latter is the complement of the one constant.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadOne Cudd_ReadLogicZero]
+
+******************************************************************************/
+DdNode *
+Cudd_ReadZero(
+ DdManager * dd)
+{
+ return(DD_ZERO(dd));
+
+} /* end of Cudd_ReadZero */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the logic zero constant of the manager.]
+
+ Description [Returns the zero constant of the manager. The logic zero
+ constant is the complement of the one constant, and is distinct from
+ the arithmetic zero.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadOne Cudd_ReadZero]
+
+******************************************************************************/
+DdNode *
+Cudd_ReadLogicZero(
+ DdManager * dd)
+{
+ return(Cudd_Not(DD_ONE(dd)));
+
+} /* end of Cudd_ReadLogicZero */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the plus-infinity constant from the manager.]
+
+ Description []
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+Cudd_ReadPlusInfinity(
+ DdManager * dd)
+{
+ return(dd->plusinfinity);
+
+} /* end of Cudd_ReadPlusInfinity */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the minus-infinity constant from the manager.]
+
+ Description []
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+Cudd_ReadMinusInfinity(
+ DdManager * dd)
+{
+ return(dd->minusinfinity);
+
+} /* end of Cudd_ReadMinusInfinity */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the background constant of the manager.]
+
+ Description []
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+Cudd_ReadBackground(
+ DdManager * dd)
+{
+ return(dd->background);
+
+} /* end of Cudd_ReadBackground */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the background constant of the manager.]
+
+ Description [Sets the background constant of the manager. It assumes
+ that the DdNode pointer bck is already referenced.]
+
+ SideEffects [None]
+
+******************************************************************************/
+void
+Cudd_SetBackground(
+ DdManager * dd,
+ DdNode * bck)
+{
+ dd->background = bck;
+
+} /* end of Cudd_SetBackground */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the number of slots in the cache.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadCacheUsedSlots]
+
+******************************************************************************/
+unsigned int
+Cudd_ReadCacheSlots(
+ DdManager * dd)
+{
+ return(dd->cacheSlots);
+
+} /* end of Cudd_ReadCacheSlots */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the fraction of used slots in the cache.]
+
+ Description [Reads the fraction of used slots in the cache. The unused
+ slots are those in which no valid data is stored. Garbage collection,
+ variable reordering, and cache resizing may cause used slots to become
+ unused.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadCacheSlots]
+
+******************************************************************************/
+double
+Cudd_ReadCacheUsedSlots(
+ DdManager * dd)
+{
+ unsigned long used = 0;
+ int slots = dd->cacheSlots;
+ DdCache *cache = dd->cache;
+ int i;
+
+ for (i = 0; i < slots; i++) {
+ used += cache[i].h != 0;
+ }
+
+ return((double)used / (double) dd->cacheSlots);
+
+} /* end of Cudd_ReadCacheUsedSlots */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of cache look-ups.]
+
+ Description [Returns the number of cache look-ups.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadCacheHits]
+
+******************************************************************************/
+double
+Cudd_ReadCacheLookUps(
+ DdManager * dd)
+{
+ return(dd->cacheHits + dd->cacheMisses +
+ dd->totCachehits + dd->totCacheMisses);
+
+} /* end of Cudd_ReadCacheLookUps */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of cache hits.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadCacheLookUps]
+
+******************************************************************************/
+double
+Cudd_ReadCacheHits(
+ DdManager * dd)
+{
+ return(dd->cacheHits + dd->totCachehits);
+
+} /* end of Cudd_ReadCacheHits */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of recursive calls.]
+
+ Description [Returns the number of recursive calls if the package is
+ compiled with DD_COUNT defined.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+double
+Cudd_ReadRecursiveCalls(
+ DdManager * dd)
+{
+#ifdef DD_COUNT
+ return(dd->recursiveCalls);
+#else
+ return(-1.0);
+#endif
+
+} /* end of Cudd_ReadRecursiveCalls */
+
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the hit rate that causes resizinig of the computed
+ table.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetMinHit]
+
+******************************************************************************/
+unsigned int
+Cudd_ReadMinHit(
+ DdManager * dd)
+{
+ /* Internally, the package manipulates the ratio of hits to
+ ** misses instead of the ratio of hits to accesses. */
+ return((unsigned int) (0.5 + 100 * dd->minHit / (1 + dd->minHit)));
+
+} /* end of Cudd_ReadMinHit */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the hit rate that causes resizinig of the computed
+ table.]
+
+ Description [Sets the minHit parameter of the manager. This
+ parameter controls the resizing of the computed table. If the hit
+ rate is larger than the specified value, and the cache is not
+ already too large, then its size is doubled.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadMinHit]
+
+******************************************************************************/
+void
+Cudd_SetMinHit(
+ DdManager * dd,
+ unsigned int hr)
+{
+ /* Internally, the package manipulates the ratio of hits to
+ ** misses instead of the ratio of hits to accesses. */
+ dd->minHit = (double) hr / (100.0 - (double) hr);
+
+} /* end of Cudd_SetMinHit */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the looseUpTo parameter of the manager.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetLooseUpTo Cudd_ReadMinHit Cudd_ReadMinDead]
+
+******************************************************************************/
+unsigned int
+Cudd_ReadLooseUpTo(
+ DdManager * dd)
+{
+ return(dd->looseUpTo);
+
+} /* end of Cudd_ReadLooseUpTo */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the looseUpTo parameter of the manager.]
+
+ Description [Sets the looseUpTo parameter of the manager. This
+ parameter of the manager controls the threshold beyond which no fast
+ growth of the unique table is allowed. The threshold is given as a
+ number of slots. If the value passed to this function is 0, the
+ function determines a suitable value based on the available memory.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadLooseUpTo Cudd_SetMinHit]
+
+******************************************************************************/
+void
+Cudd_SetLooseUpTo(
+ DdManager * dd,
+ unsigned int lut)
+{
+ if (lut == 0) {
+ long datalimit = getSoftDataLimit();
+ lut = (unsigned int) (datalimit / (sizeof(DdNode) *
+ DD_MAX_LOOSE_FRACTION));
+ }
+ dd->looseUpTo = lut;
+
+} /* end of Cudd_SetLooseUpTo */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the soft limit for the cache size.]
+
+ Description [Returns the soft limit for the cache size. The soft limit]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadMaxCache]
+
+******************************************************************************/
+unsigned int
+Cudd_ReadMaxCache(
+ DdManager * dd)
+{
+ return(2 * dd->cacheSlots + dd->cacheSlack);
+
+} /* end of Cudd_ReadMaxCache */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the maxCacheHard parameter of the manager.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetMaxCacheHard Cudd_ReadMaxCache]
+
+******************************************************************************/
+unsigned int
+Cudd_ReadMaxCacheHard(
+ DdManager * dd)
+{
+ return(dd->maxCacheHard);
+
+} /* end of Cudd_ReadMaxCache */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the maxCacheHard parameter of the manager.]
+
+ Description [Sets the maxCacheHard parameter of the manager. The
+ cache cannot grow larger than maxCacheHard entries. This parameter
+ allows an application to control the trade-off of memory versus
+ speed. If the value passed to this function is 0, the function
+ determines a suitable maximum cache size based on the available memory.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadMaxCacheHard Cudd_SetMaxCache]
+
+******************************************************************************/
+void
+Cudd_SetMaxCacheHard(
+ DdManager * dd,
+ unsigned int mc)
+{
+ if (mc == 0) {
+ long datalimit = getSoftDataLimit();
+ mc = (unsigned int) (datalimit / (sizeof(DdCache) *
+ DD_MAX_CACHE_FRACTION));
+ }
+ dd->maxCacheHard = mc;
+
+} /* end of Cudd_SetMaxCacheHard */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of BDD variables in existance.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadZddSize]
+
+******************************************************************************/
+int
+Cudd_ReadSize(
+ DdManager * dd)
+{
+ return(dd->size);
+
+} /* end of Cudd_ReadSize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of ZDD variables in existance.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadSize]
+
+******************************************************************************/
+int
+Cudd_ReadZddSize(
+ DdManager * dd)
+{
+ return(dd->sizeZ);
+
+} /* end of Cudd_ReadZddSize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the total number of slots of the unique table.]
+
+ Description [Returns the total number of slots of the unique table.
+ This number ismainly for diagnostic purposes.]
+
+ SideEffects [None]
+
+******************************************************************************/
+unsigned int
+Cudd_ReadSlots(
+ DdManager * dd)
+{
+ return(dd->slots);
+
+} /* end of Cudd_ReadSlots */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the fraction of used slots in the unique table.]
+
+ Description [Reads the fraction of used slots in the unique
+ table. The unused slots are those in which no valid data is
+ stored. Garbage collection, variable reordering, and subtable
+ resizing may cause used slots to become unused.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadSlots]
+
+******************************************************************************/
+double
+Cudd_ReadUsedSlots(
+ DdManager * dd)
+{
+ unsigned long used = 0;
+ int i, j;
+ int size = dd->size;
+ DdNodePtr *nodelist;
+ DdSubtable *subtable;
+ DdNode *node;
+ DdNode *sentinel = &(dd->sentinel);
+
+ /* Scan each BDD/ADD subtable. */
+ for (i = 0; i < size; i++) {
+ subtable = &(dd->subtables[i]);
+ nodelist = subtable->nodelist;
+ for (j = 0; (unsigned) j < subtable->slots; j++) {
+ node = nodelist[j];
+ if (node != sentinel) {
+ used++;
+ }
+ }
+ }
+
+ /* Scan the ZDD subtables. */
+ size = dd->sizeZ;
+
+ for (i = 0; i < size; i++) {
+ subtable = &(dd->subtableZ[i]);
+ nodelist = subtable->nodelist;
+ for (j = 0; (unsigned) j < subtable->slots; j++) {
+ node = nodelist[j];
+ if (node != NULL) {
+ used++;
+ }
+ }
+ }
+
+ /* Constant table. */
+ subtable = &(dd->constants);
+ nodelist = subtable->nodelist;
+ for (j = 0; (unsigned) j < subtable->slots; j++) {
+ node = nodelist[j];
+ if (node != NULL) {
+ used++;
+ }
+ }
+
+ return((double)used / (double) dd->slots);
+
+} /* end of Cudd_ReadUsedSlots */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the expected fraction of used slots in the unique
+ table.]
+
+ Description [Computes the fraction of slots in the unique table that
+ should be in use. This expected value is based on the assumption
+ that the hash function distributes the keys randomly; it can be
+ compared with the result of Cudd_ReadUsedSlots to monitor the
+ performance of the unique table hash function.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadSlots Cudd_ReadUsedSlots]
+
+******************************************************************************/
+double
+Cudd_ExpectedUsedSlots(
+ DdManager * dd)
+{
+ int i;
+ int size = dd->size;
+ DdSubtable *subtable;
+ double empty = 0.0;
+
+ /* To each subtable we apply the corollary to Theorem 8.5 (occupancy
+ ** distribution) from Sedgewick and Flajolet's Analysis of Algorithms.
+ ** The corollary says that for a a table with M buckets and a load ratio
+ ** of r, the expected number of empty buckets is asymptotically given
+ ** by M * exp(-r).
+ */
+
+ /* Scan each BDD/ADD subtable. */
+ for (i = 0; i < size; i++) {
+ subtable = &(dd->subtables[i]);
+ empty += (double) subtable->slots *
+ exp(-(double) subtable->keys / (double) subtable->slots);
+ }
+
+ /* Scan the ZDD subtables. */
+ size = dd->sizeZ;
+
+ for (i = 0; i < size; i++) {
+ subtable = &(dd->subtableZ[i]);
+ empty += (double) subtable->slots *
+ exp(-(double) subtable->keys / (double) subtable->slots);
+ }
+
+ /* Constant table. */
+ subtable = &(dd->constants);
+ empty += (double) subtable->slots *
+ exp(-(double) subtable->keys / (double) subtable->slots);
+
+ return(1.0 - empty / (double) dd->slots);
+
+} /* end of Cudd_ExpectedUsedSlots */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of nodes in the unique table.]
+
+ Description [Returns the total number of nodes currently in the unique
+ table, including the dead nodes.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadDead]
+
+******************************************************************************/
+unsigned int
+Cudd_ReadKeys(
+ DdManager * dd)
+{
+ return(dd->keys);
+
+} /* end of Cudd_ReadKeys */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of dead nodes in the unique table.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadKeys]
+
+******************************************************************************/
+unsigned int
+Cudd_ReadDead(
+ DdManager * dd)
+{
+ return(dd->dead);
+
+} /* end of Cudd_ReadDead */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the minDead parameter of the manager.]
+
+ Description [Reads the minDead parameter of the manager. The minDead
+ parameter is used by the package to decide whether to collect garbage
+ or resize a subtable of the unique table when the subtable becomes
+ too full. The application can indirectly control the value of minDead
+ by setting the looseUpTo parameter.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadDead Cudd_ReadLooseUpTo Cudd_SetLooseUpTo]
+
+******************************************************************************/
+unsigned int
+Cudd_ReadMinDead(
+ DdManager * dd)
+{
+ return(dd->minDead);
+
+} /* end of Cudd_ReadMinDead */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of times reordering has occurred.]
+
+ Description [Returns the number of times reordering has occurred in the
+ manager. The number includes both the calls to Cudd_ReduceHeap from
+ the application program and those automatically performed by the
+ package. However, calls that do not even initiate reordering are not
+ counted. A call may not initiate reordering if there are fewer than
+ minsize live nodes in the manager, or if CUDD_REORDER_NONE is specified
+ as reordering method. The calls to Cudd_ShuffleHeap are not counted.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReduceHeap Cudd_ReadReorderingTime]
+
+******************************************************************************/
+int
+Cudd_ReadReorderings(
+ DdManager * dd)
+{
+ return(dd->reorderings);
+
+} /* end of Cudd_ReadReorderings */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the time spent in reordering.]
+
+ Description [Returns the number of milliseconds spent reordering
+ variables since the manager was initialized. The time spent in collecting
+ garbage before reordering is included.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadReorderings]
+
+******************************************************************************/
+long
+Cudd_ReadReorderingTime(
+ DdManager * dd)
+{
+ return(dd->reordTime);
+
+} /* end of Cudd_ReadReorderingTime */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of times garbage collection has occurred.]
+
+ Description [Returns the number of times garbage collection has
+ occurred in the manager. The number includes both the calls from
+ reordering procedures and those caused by requests to create new
+ nodes.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadGarbageCollectionTime]
+
+******************************************************************************/
+int
+Cudd_ReadGarbageCollections(
+ DdManager * dd)
+{
+ return(dd->garbageCollections);
+
+} /* end of Cudd_ReadGarbageCollections */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the time spent in garbage collection.]
+
+ Description [Returns the number of milliseconds spent doing garbage
+ collection since the manager was initialized.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadGarbageCollections]
+
+******************************************************************************/
+long
+Cudd_ReadGarbageCollectionTime(
+ DdManager * dd)
+{
+ return(dd->GCTime);
+
+} /* end of Cudd_ReadGarbageCollectionTime */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of nodes freed.]
+
+ Description [Returns the number of nodes returned to the free list if the
+ keeping of this statistic is enabled; -1 otherwise. This statistic is
+ enabled only if the package is compiled with DD_STATS defined.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadNodesDropped]
+
+******************************************************************************/
+double
+Cudd_ReadNodesFreed(
+ DdManager * dd)
+{
+#ifdef DD_STATS
+ return(dd->nodesFreed);
+#else
+ return(-1.0);
+#endif
+
+} /* end of Cudd_ReadNodesFreed */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of nodes dropped.]
+
+ Description [Returns the number of nodes killed by dereferencing if the
+ keeping of this statistic is enabled; -1 otherwise. This statistic is
+ enabled only if the package is compiled with DD_STATS defined.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadNodesFreed]
+
+******************************************************************************/
+double
+Cudd_ReadNodesDropped(
+ DdManager * dd)
+{
+#ifdef DD_STATS
+ return(dd->nodesDropped);
+#else
+ return(-1.0);
+#endif
+
+} /* end of Cudd_ReadNodesDropped */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of look-ups in the unique table.]
+
+ Description [Returns the number of look-ups in the unique table if the
+ keeping of this statistic is enabled; -1 otherwise. This statistic is
+ enabled only if the package is compiled with DD_UNIQUE_PROFILE defined.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadUniqueLinks]
+
+******************************************************************************/
+double
+Cudd_ReadUniqueLookUps(
+ DdManager * dd)
+{
+#ifdef DD_UNIQUE_PROFILE
+ return(dd->uniqueLookUps);
+#else
+ return(-1.0);
+#endif
+
+} /* end of Cudd_ReadUniqueLookUps */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of links followed in the unique table.]
+
+ Description [Returns the number of links followed during look-ups in the
+ unique table if the keeping of this statistic is enabled; -1 otherwise.
+ If an item is found in the first position of its collision list, the
+ number of links followed is taken to be 0. If it is in second position,
+ the number of links is 1, and so on. This statistic is enabled only if
+ the package is compiled with DD_UNIQUE_PROFILE defined.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadUniqueLookUps]
+
+******************************************************************************/
+double
+Cudd_ReadUniqueLinks(
+ DdManager * dd)
+{
+#ifdef DD_UNIQUE_PROFILE
+ return(dd->uniqueLinks);
+#else
+ return(-1.0);
+#endif
+
+} /* end of Cudd_ReadUniqueLinks */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the siftMaxVar parameter of the manager.]
+
+ Description [Reads the siftMaxVar parameter of the manager. This
+ parameter gives the maximum number of variables that will be sifted
+ for each invocation of sifting.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadSiftMaxSwap Cudd_SetSiftMaxVar]
+
+******************************************************************************/
+int
+Cudd_ReadSiftMaxVar(
+ DdManager * dd)
+{
+ return(dd->siftMaxVar);
+
+} /* end of Cudd_ReadSiftMaxVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the siftMaxVar parameter of the manager.]
+
+ Description [Sets the siftMaxVar parameter of the manager. This
+ parameter gives the maximum number of variables that will be sifted
+ for each invocation of sifting.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetSiftMaxSwap Cudd_ReadSiftMaxVar]
+
+******************************************************************************/
+void
+Cudd_SetSiftMaxVar(
+ DdManager * dd,
+ int smv)
+{
+ dd->siftMaxVar = smv;
+
+} /* end of Cudd_SetSiftMaxVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the siftMaxSwap parameter of the manager.]
+
+ Description [Reads the siftMaxSwap parameter of the manager. This
+ parameter gives the maximum number of swaps that will be attempted
+ for each invocation of sifting. The real number of swaps may exceed
+ the set limit because the package will always complete the sifting
+ of the variable that causes the limit to be reached.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadSiftMaxVar Cudd_SetSiftMaxSwap]
+
+******************************************************************************/
+int
+Cudd_ReadSiftMaxSwap(
+ DdManager * dd)
+{
+ return(dd->siftMaxSwap);
+
+} /* end of Cudd_ReadSiftMaxSwap */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the siftMaxSwap parameter of the manager.]
+
+ Description [Sets the siftMaxSwap parameter of the manager. This
+ parameter gives the maximum number of swaps that will be attempted
+ for each invocation of sifting. The real number of swaps may exceed
+ the set limit because the package will always complete the sifting
+ of the variable that causes the limit to be reached.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetSiftMaxVar Cudd_ReadSiftMaxSwap]
+
+******************************************************************************/
+void
+Cudd_SetSiftMaxSwap(
+ DdManager * dd,
+ int sms)
+{
+ dd->siftMaxSwap = sms;
+
+} /* end of Cudd_SetSiftMaxSwap */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the maxGrowth parameter of the manager.]
+
+ Description [Reads the maxGrowth parameter of the manager. This
+ parameter determines how much the number of nodes can grow during
+ sifting of a variable. Overall, sifting never increases the size of
+ the decision diagrams. This parameter only refers to intermediate
+ results. A lower value will speed up sifting, possibly at the
+ expense of quality.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetMaxGrowth Cudd_ReadMaxGrowthAlternate]
+
+******************************************************************************/
+double
+Cudd_ReadMaxGrowth(
+ DdManager * dd)
+{
+ return(dd->maxGrowth);
+
+} /* end of Cudd_ReadMaxGrowth */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the maxGrowth parameter of the manager.]
+
+ Description [Sets the maxGrowth parameter of the manager. This
+ parameter determines how much the number of nodes can grow during
+ sifting of a variable. Overall, sifting never increases the size of
+ the decision diagrams. This parameter only refers to intermediate
+ results. A lower value will speed up sifting, possibly at the
+ expense of quality.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadMaxGrowth Cudd_SetMaxGrowthAlternate]
+
+******************************************************************************/
+void
+Cudd_SetMaxGrowth(
+ DdManager * dd,
+ double mg)
+{
+ dd->maxGrowth = mg;
+
+} /* end of Cudd_SetMaxGrowth */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the maxGrowthAlt parameter of the manager.]
+
+ Description [Reads the maxGrowthAlt parameter of the manager. This
+ parameter is analogous to the maxGrowth paramter, and is used every
+ given number of reorderings instead of maxGrowth. The number of
+ reorderings is set with Cudd_SetReorderingCycle. If the number of
+ reorderings is 0 (default) maxGrowthAlt is never used.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadMaxGrowth Cudd_SetMaxGrowthAlternate
+ Cudd_SetReorderingCycle Cudd_ReadReorderingCycle]
+
+******************************************************************************/
+double
+Cudd_ReadMaxGrowthAlternate(
+ DdManager * dd)
+{
+ return(dd->maxGrowthAlt);
+
+} /* end of Cudd_ReadMaxGrowthAlternate */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the maxGrowthAlt parameter of the manager.]
+
+ Description [Sets the maxGrowthAlt parameter of the manager. This
+ parameter is analogous to the maxGrowth paramter, and is used every
+ given number of reorderings instead of maxGrowth. The number of
+ reorderings is set with Cudd_SetReorderingCycle. If the number of
+ reorderings is 0 (default) maxGrowthAlt is never used.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadMaxGrowthAlternate Cudd_SetMaxGrowth
+ Cudd_SetReorderingCycle Cudd_ReadReorderingCycle]
+
+******************************************************************************/
+void
+Cudd_SetMaxGrowthAlternate(
+ DdManager * dd,
+ double mg)
+{
+ dd->maxGrowthAlt = mg;
+
+} /* end of Cudd_SetMaxGrowthAlternate */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the reordCycle parameter of the manager.]
+
+ Description [Reads the reordCycle parameter of the manager. This
+ parameter determines how often the alternate threshold on maximum
+ growth is used in reordering.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadMaxGrowthAlternate Cudd_SetMaxGrowthAlternate
+ Cudd_SetReorderingCycle]
+
+******************************************************************************/
+int
+Cudd_ReadReorderingCycle(
+ DdManager * dd)
+{
+ return(dd->reordCycle);
+
+} /* end of Cudd_ReadReorderingCycle */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the reordCycle parameter of the manager.]
+
+ Description [Sets the reordCycle parameter of the manager. This
+ parameter determines how often the alternate threshold on maximum
+ growth is used in reordering.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadMaxGrowthAlternate Cudd_SetMaxGrowthAlternate
+ Cudd_ReadReorderingCycle]
+
+******************************************************************************/
+void
+Cudd_SetReorderingCycle(
+ DdManager * dd,
+ int cycle)
+{
+ dd->reordCycle = cycle;
+
+} /* end of Cudd_SetReorderingCycle */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the variable group tree of the manager.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetTree Cudd_FreeTree Cudd_ReadZddTree]
+
+******************************************************************************/
+MtrNode *
+Cudd_ReadTree(
+ DdManager * dd)
+{
+ return(dd->tree);
+
+} /* end of Cudd_ReadTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the variable group tree of the manager.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_FreeTree Cudd_ReadTree Cudd_SetZddTree]
+
+******************************************************************************/
+void
+Cudd_SetTree(
+ DdManager * dd,
+ MtrNode * tree)
+{
+ if (dd->tree != NULL) {
+ Mtr_FreeTree(dd->tree);
+ }
+ dd->tree = tree;
+ if (tree == NULL) return;
+
+ fixVarTree(tree, dd->perm, dd->size);
+ return;
+
+} /* end of Cudd_SetTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees the variable group tree of the manager.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetTree Cudd_ReadTree Cudd_FreeZddTree]
+
+******************************************************************************/
+void
+Cudd_FreeTree(
+ DdManager * dd)
+{
+ if (dd->tree != NULL) {
+ Mtr_FreeTree(dd->tree);
+ dd->tree = NULL;
+ }
+ return;
+
+} /* end of Cudd_FreeTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the variable group tree of the manager.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetZddTree Cudd_FreeZddTree Cudd_ReadTree]
+
+******************************************************************************/
+MtrNode *
+Cudd_ReadZddTree(
+ DdManager * dd)
+{
+ return(dd->treeZ);
+
+} /* end of Cudd_ReadZddTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the ZDD variable group tree of the manager.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_FreeZddTree Cudd_ReadZddTree Cudd_SetTree]
+
+******************************************************************************/
+void
+Cudd_SetZddTree(
+ DdManager * dd,
+ MtrNode * tree)
+{
+ if (dd->treeZ != NULL) {
+ Mtr_FreeTree(dd->treeZ);
+ }
+ dd->treeZ = tree;
+ if (tree == NULL) return;
+
+ fixVarTree(tree, dd->permZ, dd->sizeZ);
+ return;
+
+} /* end of Cudd_SetZddTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees the variable group tree of the manager.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetZddTree Cudd_ReadZddTree Cudd_FreeTree]
+
+******************************************************************************/
+void
+Cudd_FreeZddTree(
+ DdManager * dd)
+{
+ if (dd->treeZ != NULL) {
+ Mtr_FreeTree(dd->treeZ);
+ dd->treeZ = NULL;
+ }
+ return;
+
+} /* end of Cudd_FreeZddTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the index of the node.]
+
+ Description [Returns the index of the node. The node pointer can be
+ either regular or complemented.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadIndex]
+
+******************************************************************************/
+unsigned int
+Cudd_NodeReadIndex(
+ DdNode * node)
+{
+ return((unsigned int) Cudd_Regular(node)->index);
+
+} /* end of Cudd_NodeReadIndex */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the current position of the i-th variable in the
+ order.]
+
+ Description [Returns the current position of the i-th variable in
+ the order. If the index is CUDD_CONST_INDEX, returns
+ CUDD_CONST_INDEX; otherwise, if the index is out of bounds returns
+ -1.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadInvPerm Cudd_ReadPermZdd]
+
+******************************************************************************/
+int
+Cudd_ReadPerm(
+ DdManager * dd,
+ int i)
+{
+ if (i == CUDD_CONST_INDEX) return(CUDD_CONST_INDEX);
+ if (i < 0 || i >= dd->size) return(-1);
+ return(dd->perm[i]);
+
+} /* end of Cudd_ReadPerm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the current position of the i-th ZDD variable in the
+ order.]
+
+ Description [Returns the current position of the i-th ZDD variable
+ in the order. If the index is CUDD_CONST_INDEX, returns
+ CUDD_CONST_INDEX; otherwise, if the index is out of bounds returns
+ -1.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadInvPermZdd Cudd_ReadPerm]
+
+******************************************************************************/
+int
+Cudd_ReadPermZdd(
+ DdManager * dd,
+ int i)
+{
+ if (i == CUDD_CONST_INDEX) return(CUDD_CONST_INDEX);
+ if (i < 0 || i >= dd->sizeZ) return(-1);
+ return(dd->permZ[i]);
+
+} /* end of Cudd_ReadPermZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the index of the variable currently in the i-th
+ position of the order.]
+
+ Description [Returns the index of the variable currently in the i-th
+ position of the order. If the index is CUDD_CONST_INDEX, returns
+ CUDD_CONST_INDEX; otherwise, if the index is out of bounds returns -1.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadPerm Cudd_ReadInvPermZdd]
+
+******************************************************************************/
+int
+Cudd_ReadInvPerm(
+ DdManager * dd,
+ int i)
+{
+ if (i == CUDD_CONST_INDEX) return(CUDD_CONST_INDEX);
+ if (i < 0 || i >= dd->size) return(-1);
+ return(dd->invperm[i]);
+
+} /* end of Cudd_ReadInvPerm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the index of the ZDD variable currently in the i-th
+ position of the order.]
+
+ Description [Returns the index of the ZDD variable currently in the
+ i-th position of the order. If the index is CUDD_CONST_INDEX, returns
+ CUDD_CONST_INDEX; otherwise, if the index is out of bounds returns -1.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadPerm Cudd_ReadInvPermZdd]
+
+******************************************************************************/
+int
+Cudd_ReadInvPermZdd(
+ DdManager * dd,
+ int i)
+{
+ if (i == CUDD_CONST_INDEX) return(CUDD_CONST_INDEX);
+ if (i < 0 || i >= dd->sizeZ) return(-1);
+ return(dd->invpermZ[i]);
+
+} /* end of Cudd_ReadInvPermZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the i-th element of the vars array.]
+
+ Description [Returns the i-th element of the vars array if it falls
+ within the array bounds; NULL otherwise. If i is the index of an
+ existing variable, this function produces the same result as
+ Cudd_bddIthVar. However, if the i-th var does not exist yet,
+ Cudd_bddIthVar will create it, whereas Cudd_ReadVars will not.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIthVar]
+
+******************************************************************************/
+DdNode *
+Cudd_ReadVars(
+ DdManager * dd,
+ int i)
+{
+ if (i < 0 || i > dd->size) return(NULL);
+ return(dd->vars[i]);
+
+} /* end of Cudd_ReadVars */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the epsilon parameter of the manager.]
+
+ Description [Reads the epsilon parameter of the manager. The epsilon
+ parameter control the comparison between floating point numbers.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetEpsilon]
+
+******************************************************************************/
+CUDD_VALUE_TYPE
+Cudd_ReadEpsilon(
+ DdManager * dd)
+{
+ return(dd->epsilon);
+
+} /* end of Cudd_ReadEpsilon */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the epsilon parameter of the manager to ep.]
+
+ Description [Sets the epsilon parameter of the manager to ep. The epsilon
+ parameter control the comparison between floating point numbers.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadEpsilon]
+
+******************************************************************************/
+void
+Cudd_SetEpsilon(
+ DdManager * dd,
+ CUDD_VALUE_TYPE ep)
+{
+ dd->epsilon = ep;
+
+} /* end of Cudd_SetEpsilon */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the groupcheck parameter of the manager.]
+
+ Description [Reads the groupcheck parameter of the manager. The
+ groupcheck parameter determines the aggregation criterion in group
+ sifting.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetGroupcheck]
+
+******************************************************************************/
+Cudd_AggregationType
+Cudd_ReadGroupcheck(
+ DdManager * dd)
+{
+ return(dd->groupcheck);
+
+} /* end of Cudd_ReadGroupCheck */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the parameter groupcheck of the manager to gc.]
+
+ Description [Sets the parameter groupcheck of the manager to gc. The
+ groupcheck parameter determines the aggregation criterion in group
+ sifting.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadGroupCheck]
+
+******************************************************************************/
+void
+Cudd_SetGroupcheck(
+ DdManager * dd,
+ Cudd_AggregationType gc)
+{
+ dd->groupcheck = gc;
+
+} /* end of Cudd_SetGroupcheck */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tells whether garbage collection is enabled.]
+
+ Description [Returns 1 if garbage collection is enabled; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_EnableGarbageCollection Cudd_DisableGarbageCollection]
+
+******************************************************************************/
+int
+Cudd_GarbageCollectionEnabled(
+ DdManager * dd)
+{
+ return(dd->gcEnabled);
+
+} /* end of Cudd_GarbageCollectionEnabled */
+
+
+/**Function********************************************************************
+
+ Synopsis [Enables garbage collection.]
+
+ Description [Enables garbage collection. Garbage collection is
+ initially enabled. Therefore it is necessary to call this function
+ only if garbage collection has been explicitly disabled.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DisableGarbageCollection Cudd_GarbageCollectionEnabled]
+
+******************************************************************************/
+void
+Cudd_EnableGarbageCollection(
+ DdManager * dd)
+{
+ dd->gcEnabled = 1;
+
+} /* end of Cudd_EnableGarbageCollection */
+
+
+/**Function********************************************************************
+
+ Synopsis [Disables garbage collection.]
+
+ Description [Disables garbage collection. Garbage collection is
+ initially enabled. This function may be called to disable it.
+ However, garbage collection will still occur when a new node must be
+ created and no memory is left, or when garbage collection is required
+ for correctness. (E.g., before reordering.)]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_EnableGarbageCollection Cudd_GarbageCollectionEnabled]
+
+******************************************************************************/
+void
+Cudd_DisableGarbageCollection(
+ DdManager * dd)
+{
+ dd->gcEnabled = 0;
+
+} /* end of Cudd_DisableGarbageCollection */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tells whether dead nodes are counted towards triggering
+ reordering.]
+
+ Description [Tells whether dead nodes are counted towards triggering
+ reordering. Returns 1 if dead nodes are counted; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_TurnOnCountDead Cudd_TurnOffCountDead]
+
+******************************************************************************/
+int
+Cudd_DeadAreCounted(
+ DdManager * dd)
+{
+ return(dd->countDead == 0 ? 1 : 0);
+
+} /* end of Cudd_DeadAreCounted */
+
+
+/**Function********************************************************************
+
+ Synopsis [Causes the dead nodes to be counted towards triggering
+ reordering.]
+
+ Description [Causes the dead nodes to be counted towards triggering
+ reordering. This causes more frequent reorderings. By default dead
+ nodes are not counted.]
+
+ SideEffects [Changes the manager.]
+
+ SeeAlso [Cudd_TurnOffCountDead Cudd_DeadAreCounted]
+
+******************************************************************************/
+void
+Cudd_TurnOnCountDead(
+ DdManager * dd)
+{
+ dd->countDead = 0;
+
+} /* end of Cudd_TurnOnCountDead */
+
+
+/**Function********************************************************************
+
+ Synopsis [Causes the dead nodes not to be counted towards triggering
+ reordering.]
+
+ Description [Causes the dead nodes not to be counted towards
+ triggering reordering. This causes less frequent reorderings. By
+ default dead nodes are not counted. Therefore there is no need to
+ call this function unless Cudd_TurnOnCountDead has been previously
+ called.]
+
+ SideEffects [Changes the manager.]
+
+ SeeAlso [Cudd_TurnOnCountDead Cudd_DeadAreCounted]
+
+******************************************************************************/
+void
+Cudd_TurnOffCountDead(
+ DdManager * dd)
+{
+ dd->countDead = ~0;
+
+} /* end of Cudd_TurnOffCountDead */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the current value of the recombination parameter used
+ in group sifting.]
+
+ Description [Returns the current value of the recombination
+ parameter used in group sifting. A larger (positive) value makes the
+ aggregation of variables due to the second difference criterion more
+ likely. A smaller (negative) value makes aggregation less likely.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetRecomb]
+
+******************************************************************************/
+int
+Cudd_ReadRecomb(
+ DdManager * dd)
+{
+ return(dd->recomb);
+
+} /* end of Cudd_ReadRecomb */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the value of the recombination parameter used in group
+ sifting.]
+
+ Description [Sets the value of the recombination parameter used in
+ group sifting. A larger (positive) value makes the aggregation of
+ variables due to the second difference criterion more likely. A
+ smaller (negative) value makes aggregation less likely. The default
+ value is 0.]
+
+ SideEffects [Changes the manager.]
+
+ SeeAlso [Cudd_ReadRecomb]
+
+******************************************************************************/
+void
+Cudd_SetRecomb(
+ DdManager * dd,
+ int recomb)
+{
+ dd->recomb = recomb;
+
+} /* end of Cudd_SetRecomb */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the current value of the symmviolation parameter used
+ in group sifting.]
+
+ Description [Returns the current value of the symmviolation
+ parameter. This parameter is used in group sifting to decide how
+ many violations to the symmetry conditions <code>f10 = f01</code> or
+ <code>f11 = f00</code> are tolerable when checking for aggregation
+ due to extended symmetry. The value should be between 0 and 100. A
+ small value causes fewer variables to be aggregated. The default
+ value is 0.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetSymmviolation]
+
+******************************************************************************/
+int
+Cudd_ReadSymmviolation(
+ DdManager * dd)
+{
+ return(dd->symmviolation);
+
+} /* end of Cudd_ReadSymmviolation */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the value of the symmviolation parameter used
+ in group sifting.]
+
+ Description [Sets the value of the symmviolation
+ parameter. This parameter is used in group sifting to decide how
+ many violations to the symmetry conditions <code>f10 = f01</code> or
+ <code>f11 = f00</code> are tolerable when checking for aggregation
+ due to extended symmetry. The value should be between 0 and 100. A
+ small value causes fewer variables to be aggregated. The default
+ value is 0.]
+
+ SideEffects [Changes the manager.]
+
+ SeeAlso [Cudd_ReadSymmviolation]
+
+******************************************************************************/
+void
+Cudd_SetSymmviolation(
+ DdManager * dd,
+ int symmviolation)
+{
+ dd->symmviolation = symmviolation;
+
+} /* end of Cudd_SetSymmviolation */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the current value of the arcviolation parameter used
+ in group sifting.]
+
+ Description [Returns the current value of the arcviolation
+ parameter. This parameter is used in group sifting to decide how
+ many arcs into <code>y</code> not coming from <code>x</code> are
+ tolerable when checking for aggregation due to extended
+ symmetry. The value should be between 0 and 100. A small value
+ causes fewer variables to be aggregated. The default value is 0.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetArcviolation]
+
+******************************************************************************/
+int
+Cudd_ReadArcviolation(
+ DdManager * dd)
+{
+ return(dd->arcviolation);
+
+} /* end of Cudd_ReadArcviolation */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the value of the arcviolation parameter used
+ in group sifting.]
+
+ Description [Sets the value of the arcviolation
+ parameter. This parameter is used in group sifting to decide how
+ many arcs into <code>y</code> not coming from <code>x</code> are
+ tolerable when checking for aggregation due to extended
+ symmetry. The value should be between 0 and 100. A small value
+ causes fewer variables to be aggregated. The default value is 0.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadArcviolation]
+
+******************************************************************************/
+void
+Cudd_SetArcviolation(
+ DdManager * dd,
+ int arcviolation)
+{
+ dd->arcviolation = arcviolation;
+
+} /* end of Cudd_SetArcviolation */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the current size of the population used by the
+ genetic algorithm for reordering.]
+
+ Description [Reads the current size of the population used by the
+ genetic algorithm for variable reordering. A larger population size will
+ cause the genetic algorithm to take more time, but will generally
+ produce better results. The default value is 0, in which case the
+ package uses three times the number of variables as population size,
+ with a maximum of 120.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetPopulationSize]
+
+******************************************************************************/
+int
+Cudd_ReadPopulationSize(
+ DdManager * dd)
+{
+ return(dd->populationSize);
+
+} /* end of Cudd_ReadPopulationSize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the size of the population used by the
+ genetic algorithm for reordering.]
+
+ Description [Sets the size of the population used by the
+ genetic algorithm for variable reordering. A larger population size will
+ cause the genetic algorithm to take more time, but will generally
+ produce better results. The default value is 0, in which case the
+ package uses three times the number of variables as population size,
+ with a maximum of 120.]
+
+ SideEffects [Changes the manager.]
+
+ SeeAlso [Cudd_ReadPopulationSize]
+
+******************************************************************************/
+void
+Cudd_SetPopulationSize(
+ DdManager * dd,
+ int populationSize)
+{
+ dd->populationSize = populationSize;
+
+} /* end of Cudd_SetPopulationSize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the current number of crossovers used by the
+ genetic algorithm for reordering.]
+
+ Description [Reads the current number of crossovers used by the
+ genetic algorithm for variable reordering. A larger number of crossovers will
+ cause the genetic algorithm to take more time, but will generally
+ produce better results. The default value is 0, in which case the
+ package uses three times the number of variables as number of crossovers,
+ with a maximum of 60.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetNumberXovers]
+
+******************************************************************************/
+int
+Cudd_ReadNumberXovers(
+ DdManager * dd)
+{
+ return(dd->numberXovers);
+
+} /* end of Cudd_ReadNumberXovers */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the number of crossovers used by the
+ genetic algorithm for reordering.]
+
+ Description [Sets the number of crossovers used by the genetic
+ algorithm for variable reordering. A larger number of crossovers
+ will cause the genetic algorithm to take more time, but will
+ generally produce better results. The default value is 0, in which
+ case the package uses three times the number of variables as number
+ of crossovers, with a maximum of 60.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadNumberXovers]
+
+******************************************************************************/
+void
+Cudd_SetNumberXovers(
+ DdManager * dd,
+ int numberXovers)
+{
+ dd->numberXovers = numberXovers;
+
+} /* end of Cudd_SetNumberXovers */
+
+/**Function********************************************************************
+
+ Synopsis [Returns the memory in use by the manager measured in bytes.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+long
+Cudd_ReadMemoryInUse(
+ DdManager * dd)
+{
+ return(dd->memused);
+
+} /* end of Cudd_ReadMemoryInUse */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints out statistics and settings for a CUDD manager.]
+
+ Description [Prints out statistics and settings for a CUDD manager.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_PrintInfo(
+ DdManager * dd,
+ FILE * fp)
+{
+ int retval;
+ Cudd_ReorderingType autoMethod, autoMethodZ;
+
+ /* Modifiable parameters. */
+ retval = fprintf(fp,"**** CUDD modifiable parameters ****\n");
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Hard limit for cache size: %u\n",
+ Cudd_ReadMaxCacheHard(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Cache hit threshold for resizing: %u%%\n",
+ Cudd_ReadMinHit(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Garbage collection enabled: %s\n",
+ Cudd_GarbageCollectionEnabled(dd) ? "yes" : "no");
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Limit for fast unique table growth: %u\n",
+ Cudd_ReadLooseUpTo(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,
+ "Maximum number of variables sifted per reordering: %d\n",
+ Cudd_ReadSiftMaxVar(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,
+ "Maximum number of variable swaps per reordering: %d\n",
+ Cudd_ReadSiftMaxSwap(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Maximum growth while sifting a variable: %g\n",
+ Cudd_ReadMaxGrowth(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Dynamic reordering of BDDs enabled: %s\n",
+ Cudd_ReorderingStatus(dd,&autoMethod) ? "yes" : "no");
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Default BDD reordering method: %d\n", autoMethod);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Dynamic reordering of ZDDs enabled: %s\n",
+ Cudd_ReorderingStatusZdd(dd,&autoMethodZ) ? "yes" : "no");
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Default ZDD reordering method: %d\n", autoMethodZ);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Realignment of ZDDs to BDDs enabled: %s\n",
+ Cudd_zddRealignmentEnabled(dd) ? "yes" : "no");
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Realignment of BDDs to ZDDs enabled: %s\n",
+ Cudd_bddRealignmentEnabled(dd) ? "yes" : "no");
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Dead nodes counted in triggering reordering: %s\n",
+ Cudd_DeadAreCounted(dd) ? "yes" : "no");
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Group checking criterion: %d\n",
+ Cudd_ReadGroupcheck(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Recombination threshold: %d\n", Cudd_ReadRecomb(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Symmetry violation threshold: %d\n",
+ Cudd_ReadSymmviolation(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Arc violation threshold: %d\n",
+ Cudd_ReadArcviolation(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"GA population size: %d\n",
+ Cudd_ReadPopulationSize(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of crossovers for GA: %d\n",
+ Cudd_ReadNumberXovers(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Next reordering threshold: %u\n",
+ Cudd_ReadNextReordering(dd));
+ if (retval == EOF) return(0);
+
+ /* Non-modifiable parameters. */
+ retval = fprintf(fp,"**** CUDD non-modifiable parameters ****\n");
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Memory in use: %ld\n", Cudd_ReadMemoryInUse(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Peak number of nodes: %ld\n",
+ Cudd_ReadPeakNodeCount(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Peak number of live nodes: %d\n",
+ Cudd_ReadPeakLiveNodeCount(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of BDD variables: %d\n", dd->size);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of ZDD variables: %d\n", dd->sizeZ);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of cache entries: %u\n", dd->cacheSlots);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of cache look-ups: %.0f\n",
+ Cudd_ReadCacheLookUps(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of cache hits: %.0f\n",
+ Cudd_ReadCacheHits(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of cache insertions: %.0f\n",
+ dd->cacheinserts);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of cache collisions: %.0f\n",
+ dd->cachecollisions);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of cache deletions: %.0f\n",
+ dd->cachedeletions);
+ if (retval == EOF) return(0);
+ retval = cuddCacheProfile(dd,fp);
+ if (retval == 0) return(0);
+ retval = fprintf(fp,"Soft limit for cache size: %u\n",
+ Cudd_ReadMaxCache(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of buckets in unique table: %u\n", dd->slots);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Used buckets in unique table: %.2f%% (expected %.2f%%)\n",
+ 100.0 * Cudd_ReadUsedSlots(dd),
+ 100.0 * Cudd_ExpectedUsedSlots(dd));
+ if (retval == EOF) return(0);
+#ifdef DD_UNIQUE_PROFILE
+ retval = fprintf(fp,"Unique lookups: %.0f\n", dd->uniqueLookUps);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Unique links: %.0f (%g per lookup)\n",
+ dd->uniqueLinks, dd->uniqueLinks / dd->uniqueLookUps);
+ if (retval == EOF) return(0);
+#endif
+ retval = fprintf(fp,"Number of BDD and ADD nodes: %u\n", dd->keys);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of ZDD nodes: %u\n", dd->keysZ);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of dead BDD and ADD nodes: %u\n", dd->dead);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of dead ZDD nodes: %u\n", dd->deadZ);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Total number of nodes allocated: %.0f\n",
+ dd->allocated);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Total number of nodes reclaimed: %.0f\n",
+ dd->reclaimed);
+ if (retval == EOF) return(0);
+#if DD_STATS
+ retval = fprintf(fp,"Nodes freed: %.0f\n", dd->nodesFreed);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Nodes dropped: %.0f\n", dd->nodesDropped);
+ if (retval == EOF) return(0);
+#endif
+#if DD_COUNT
+ retval = fprintf(fp,"Number of recursive calls: %.0f\n",
+ Cudd_ReadRecursiveCalls(dd));
+ if (retval == EOF) return(0);
+#endif
+ retval = fprintf(fp,"Garbage collections so far: %d\n",
+ Cudd_ReadGarbageCollections(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Time for garbage collection: %.2f sec\n",
+ ((double)Cudd_ReadGarbageCollectionTime(dd)/1000.0));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Reorderings so far: %d\n", dd->reorderings);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Time for reordering: %.2f sec\n",
+ ((double)Cudd_ReadReorderingTime(dd)/1000.0));
+ if (retval == EOF) return(0);
+#if DD_COUNT
+ retval = fprintf(fp,"Node swaps in reordering: %.0f\n",
+ Cudd_ReadSwapSteps(dd));
+ if (retval == EOF) return(0);
+#endif
+
+ return(1);
+
+} /* end of Cudd_PrintInfo */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reports the peak number of nodes.]
+
+ Description [Reports the peak number of nodes. This number includes
+ node on the free list. At the peak, the number of nodes on the free
+ list is guaranteed to be less than DD_MEM_CHUNK.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadNodeCount Cudd_PrintInfo]
+
+******************************************************************************/
+long
+Cudd_ReadPeakNodeCount(
+ DdManager * dd)
+{
+ long count = 0;
+ DdNodePtr *scan = dd->memoryList;
+
+ while (scan != NULL) {
+ count += DD_MEM_CHUNK;
+ scan = (DdNodePtr *) *scan;
+ }
+ return(count);
+
+} /* end of Cudd_ReadPeakNodeCount */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reports the peak number of live nodes.]
+
+ Description [Reports the peak number of live nodes. This count is kept
+ only if CUDD is compiled with DD_STATS defined. If DD_STATS is not
+ defined, this function returns -1.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadNodeCount Cudd_PrintInfo Cudd_ReadPeakNodeCount]
+
+******************************************************************************/
+int
+Cudd_ReadPeakLiveNodeCount(
+ DdManager * dd)
+{
+ unsigned int live = dd->keys - dd->dead;
+
+ if (live > dd->peakLiveNodes) {
+ dd->peakLiveNodes = live;
+ }
+ return((int)dd->peakLiveNodes);
+
+} /* end of Cudd_ReadPeakLiveNodeCount */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reports the number of nodes in BDDs and ADDs.]
+
+ Description [Reports the number of live nodes in BDDs and ADDs. This
+ number does not include the isolated projection functions and the
+ unused constants. These nodes that are not counted are not part of
+ the DDs manipulated by the application.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadPeakNodeCount Cudd_zddReadNodeCount]
+
+******************************************************************************/
+long
+Cudd_ReadNodeCount(
+ DdManager * dd)
+{
+ long count;
+ int i;
+
+#ifndef DD_NO_DEATH_ROW
+ cuddClearDeathRow(dd);
+#endif
+
+ count = dd->keys - dd->dead;
+
+ /* Count isolated projection functions. Their number is subtracted
+ ** from the node count because they are not part of the BDDs.
+ */
+ for (i=0; i < dd->size; i++) {
+ if (dd->vars[i]->ref == 1) count--;
+ }
+ /* Subtract from the count the unused constants. */
+ if (DD_ZERO(dd)->ref == 1) count--;
+ if (DD_PLUS_INFINITY(dd)->ref == 1) count--;
+ if (DD_MINUS_INFINITY(dd)->ref == 1) count--;
+
+ return(count);
+
+} /* end of Cudd_ReadNodeCount */
+
+
+
+/**Function********************************************************************
+
+ Synopsis [Reports the number of nodes in ZDDs.]
+
+ Description [Reports the number of nodes in ZDDs. This
+ number always includes the two constants 1 and 0.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadPeakNodeCount Cudd_ReadNodeCount]
+
+******************************************************************************/
+long
+Cudd_zddReadNodeCount(
+ DdManager * dd)
+{
+ return(dd->keysZ - dd->deadZ + 2);
+
+} /* end of Cudd_zddReadNodeCount */
+
+
+/**Function********************************************************************
+
+ Synopsis [Adds a function to a hook.]
+
+ Description [Adds a function to a hook. A hook is a list of
+ application-provided functions called on certain occasions by the
+ package. Returns 1 if the function is successfully added; 2 if the
+ function was already in the list; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_RemoveHook]
+
+******************************************************************************/
+int
+Cudd_AddHook(
+ DdManager * dd,
+ int (*f)(DdManager *, char *, void *) ,
+ Cudd_HookType where)
+{
+ DdHook **hook, *nextHook, *newHook;
+
+ switch (where) {
+ case CUDD_PRE_GC_HOOK:
+ hook = &(dd->preGCHook);
+ break;
+ case CUDD_POST_GC_HOOK:
+ hook = &(dd->postGCHook);
+ break;
+ case CUDD_PRE_REORDERING_HOOK:
+ hook = &(dd->preReorderingHook);
+ break;
+ case CUDD_POST_REORDERING_HOOK:
+ hook = &(dd->postReorderingHook);
+ break;
+ default:
+ return(0);
+ }
+ /* Scan the list and find whether the function is already there.
+ ** If so, just return. */
+ nextHook = *hook;
+ while (nextHook != NULL) {
+ if (nextHook->f == f) {
+ return(2);
+ }
+ hook = &(nextHook->next);
+ nextHook = nextHook->next;
+ }
+ /* The function was not in the list. Create a new item and append it
+ ** to the end of the list. */
+ newHook = ALLOC(DdHook,1);
+ if (newHook == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ newHook->next = NULL;
+ newHook->f = f;
+ *hook = newHook;
+ return(1);
+
+} /* end of Cudd_AddHook */
+
+
+/**Function********************************************************************
+
+ Synopsis [Removes a function from a hook.]
+
+ Description [Removes a function from a hook. A hook is a list of
+ application-provided functions called on certain occasions by the
+ package. Returns 1 if successful; 0 the function was not in the list.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_AddHook]
+
+******************************************************************************/
+int
+Cudd_RemoveHook(
+ DdManager * dd,
+ int (*f)(DdManager *, char *, void *) ,
+ Cudd_HookType where)
+{
+ DdHook **hook, *nextHook;
+
+ switch (where) {
+ case CUDD_PRE_GC_HOOK:
+ hook = &(dd->preGCHook);
+ break;
+ case CUDD_POST_GC_HOOK:
+ hook = &(dd->postGCHook);
+ break;
+ case CUDD_PRE_REORDERING_HOOK:
+ hook = &(dd->preReorderingHook);
+ break;
+ case CUDD_POST_REORDERING_HOOK:
+ hook = &(dd->postReorderingHook);
+ break;
+ default:
+ return(0);
+ }
+ nextHook = *hook;
+ while (nextHook != NULL) {
+ if (nextHook->f == f) {
+ *hook = nextHook->next;
+ FREE(nextHook);
+ return(1);
+ }
+ hook = &(nextHook->next);
+ nextHook = nextHook->next;
+ }
+
+ return(0);
+
+} /* end of Cudd_RemoveHook */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether a function is in a hook.]
+
+ Description [Checks whether a function is in a hook. A hook is a list of
+ application-provided functions called on certain occasions by the
+ package. Returns 1 if the function is found; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_AddHook Cudd_RemoveHook]
+
+******************************************************************************/
+int
+Cudd_IsInHook(
+ DdManager * dd,
+ int (*f)(DdManager *, char *, void *) ,
+ Cudd_HookType where)
+{
+ DdHook *hook;
+
+ switch (where) {
+ case CUDD_PRE_GC_HOOK:
+ hook = dd->preGCHook;
+ break;
+ case CUDD_POST_GC_HOOK:
+ hook = dd->postGCHook;
+ break;
+ case CUDD_PRE_REORDERING_HOOK:
+ hook = dd->preReorderingHook;
+ break;
+ case CUDD_POST_REORDERING_HOOK:
+ hook = dd->postReorderingHook;
+ break;
+ default:
+ return(0);
+ }
+ /* Scan the list and find whether the function is already there. */
+ while (hook != NULL) {
+ if (hook->f == f) {
+ return(1);
+ }
+ hook = hook->next;
+ }
+ return(0);
+
+} /* end of Cudd_IsInHook */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sample hook function to call before reordering.]
+
+ Description [Sample hook function to call before reordering.
+ Prints on the manager's stdout reordering method and initial size.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_StdPostReordHook]
+
+******************************************************************************/
+int
+Cudd_StdPreReordHook(
+ DdManager *dd,
+ char *str,
+ void *data)
+{
+ Cudd_ReorderingType method = (Cudd_ReorderingType) (ptruint) data;
+ int retval;
+
+ retval = fprintf(dd->out,"%s reordering with ", str);
+ if (retval == EOF) return(0);
+ switch (method) {
+ case CUDD_REORDER_SIFT_CONVERGE:
+ case CUDD_REORDER_SYMM_SIFT_CONV:
+ case CUDD_REORDER_GROUP_SIFT_CONV:
+ case CUDD_REORDER_WINDOW2_CONV:
+ case CUDD_REORDER_WINDOW3_CONV:
+ case CUDD_REORDER_WINDOW4_CONV:
+ case CUDD_REORDER_LINEAR_CONVERGE:
+ retval = fprintf(dd->out,"converging ");
+ if (retval == EOF) return(0);
+ break;
+ default:
+ break;
+ }
+ switch (method) {
+ case CUDD_REORDER_RANDOM:
+ case CUDD_REORDER_RANDOM_PIVOT:
+ retval = fprintf(dd->out,"random");
+ break;
+ case CUDD_REORDER_SIFT:
+ case CUDD_REORDER_SIFT_CONVERGE:
+ retval = fprintf(dd->out,"sifting");
+ break;
+ case CUDD_REORDER_SYMM_SIFT:
+ case CUDD_REORDER_SYMM_SIFT_CONV:
+ retval = fprintf(dd->out,"symmetric sifting");
+ break;
+ case CUDD_REORDER_LAZY_SIFT:
+ retval = fprintf(dd->out,"lazy sifting");
+ break;
+ case CUDD_REORDER_GROUP_SIFT:
+ case CUDD_REORDER_GROUP_SIFT_CONV:
+ retval = fprintf(dd->out,"group sifting");
+ break;
+ case CUDD_REORDER_WINDOW2:
+ case CUDD_REORDER_WINDOW3:
+ case CUDD_REORDER_WINDOW4:
+ case CUDD_REORDER_WINDOW2_CONV:
+ case CUDD_REORDER_WINDOW3_CONV:
+ case CUDD_REORDER_WINDOW4_CONV:
+ retval = fprintf(dd->out,"window");
+ break;
+ case CUDD_REORDER_ANNEALING:
+ retval = fprintf(dd->out,"annealing");
+ break;
+ case CUDD_REORDER_GENETIC:
+ retval = fprintf(dd->out,"genetic");
+ break;
+ case CUDD_REORDER_LINEAR:
+ case CUDD_REORDER_LINEAR_CONVERGE:
+ retval = fprintf(dd->out,"linear sifting");
+ break;
+ case CUDD_REORDER_EXACT:
+ retval = fprintf(dd->out,"exact");
+ break;
+ default:
+ return(0);
+ }
+ if (retval == EOF) return(0);
+
+ retval = fprintf(dd->out,": from %ld to ... ", strcmp(str, "BDD") == 0 ?
+ Cudd_ReadNodeCount(dd) : Cudd_zddReadNodeCount(dd));
+ if (retval == EOF) return(0);
+ fflush(dd->out);
+ return(1);
+
+} /* end of Cudd_StdPreReordHook */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sample hook function to call after reordering.]
+
+ Description [Sample hook function to call after reordering.
+ Prints on the manager's stdout final size and reordering time.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_StdPreReordHook]
+
+******************************************************************************/
+int
+Cudd_StdPostReordHook(
+ DdManager *dd,
+ char *str,
+ void *data)
+{
+ long initialTime = (long) data;
+ int retval;
+ long finalTime = util_cpu_time();
+ double totalTimeSec = (double)(finalTime - initialTime) / 1000.0;
+
+ retval = fprintf(dd->out,"%ld nodes in %g sec\n", strcmp(str, "BDD") == 0 ?
+ Cudd_ReadNodeCount(dd) : Cudd_zddReadNodeCount(dd),
+ totalTimeSec);
+ if (retval == EOF) return(0);
+ retval = fflush(dd->out);
+ if (retval == EOF) return(0);
+ return(1);
+
+} /* end of Cudd_StdPostReordHook */
+
+
+/**Function********************************************************************
+
+ Synopsis [Enables reporting of reordering stats.]
+
+ Description [Enables reporting of reordering stats.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [Installs functions in the pre-reordering and post-reordering
+ hooks.]
+
+ SeeAlso [Cudd_DisableReorderingReporting Cudd_ReorderingReporting]
+
+******************************************************************************/
+int
+Cudd_EnableReorderingReporting(
+ DdManager *dd)
+{
+ if (!Cudd_AddHook(dd, Cudd_StdPreReordHook, CUDD_PRE_REORDERING_HOOK)) {
+ return(0);
+ }
+ if (!Cudd_AddHook(dd, Cudd_StdPostReordHook, CUDD_POST_REORDERING_HOOK)) {
+ return(0);
+ }
+ return(1);
+
+} /* end of Cudd_EnableReorderingReporting */
+
+
+/**Function********************************************************************
+
+ Synopsis [Disables reporting of reordering stats.]
+
+ Description [Disables reporting of reordering stats.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [Removes functions from the pre-reordering and post-reordering
+ hooks.]
+
+ SeeAlso [Cudd_EnableReorderingReporting Cudd_ReorderingReporting]
+
+******************************************************************************/
+int
+Cudd_DisableReorderingReporting(
+ DdManager *dd)
+{
+ if (!Cudd_RemoveHook(dd, Cudd_StdPreReordHook, CUDD_PRE_REORDERING_HOOK)) {
+ return(0);
+ }
+ if (!Cudd_RemoveHook(dd, Cudd_StdPostReordHook, CUDD_POST_REORDERING_HOOK)) {
+ return(0);
+ }
+ return(1);
+
+} /* end of Cudd_DisableReorderingReporting */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns 1 if reporting of reordering stats is enabled.]
+
+ Description [Returns 1 if reporting of reordering stats is enabled;
+ 0 otherwise.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_EnableReorderingReporting Cudd_DisableReorderingReporting]
+
+******************************************************************************/
+int
+Cudd_ReorderingReporting(
+ DdManager *dd)
+{
+ return(Cudd_IsInHook(dd, Cudd_StdPreReordHook, CUDD_PRE_REORDERING_HOOK));
+
+} /* end of Cudd_ReorderingReporting */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the code of the last error.]
+
+ Description [Returns the code of the last error. The error codes are
+ defined in cudd.h.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ClearErrorCode]
+
+******************************************************************************/
+Cudd_ErrorType
+Cudd_ReadErrorCode(
+ DdManager *dd)
+{
+ return(dd->errorCode);
+
+} /* end of Cudd_ReadErrorCode */
+
+
+/**Function********************************************************************
+
+ Synopsis [Clear the error code of a manager.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadErrorCode]
+
+******************************************************************************/
+void
+Cudd_ClearErrorCode(
+ DdManager *dd)
+{
+ dd->errorCode = CUDD_NO_ERROR;
+
+} /* end of Cudd_ClearErrorCode */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the stdout of a manager.]
+
+ Description [Reads the stdout of a manager. This is the file pointer to
+ which messages normally going to stdout are written. It is initialized
+ to stdout. Cudd_SetStdout allows the application to redirect it.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetStdout Cudd_ReadStderr]
+
+******************************************************************************/
+FILE *
+Cudd_ReadStdout(
+ DdManager *dd)
+{
+ return(dd->out);
+
+} /* end of Cudd_ReadStdout */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the stdout of a manager.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadStdout Cudd_SetStderr]
+
+******************************************************************************/
+void
+Cudd_SetStdout(
+ DdManager *dd,
+ FILE *fp)
+{
+ dd->out = fp;
+
+} /* end of Cudd_SetStdout */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the stderr of a manager.]
+
+ Description [Reads the stderr of a manager. This is the file pointer to
+ which messages normally going to stderr are written. It is initialized
+ to stderr. Cudd_SetStderr allows the application to redirect it.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetStderr Cudd_ReadStdout]
+
+******************************************************************************/
+FILE *
+Cudd_ReadStderr(
+ DdManager *dd)
+{
+ return(dd->err);
+
+} /* end of Cudd_ReadStderr */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the stderr of a manager.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadStderr Cudd_SetStdout]
+
+******************************************************************************/
+void
+Cudd_SetStderr(
+ DdManager *dd,
+ FILE *fp)
+{
+ dd->err = fp;
+
+} /* end of Cudd_SetStderr */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the threshold for the next dynamic reordering.]
+
+ Description [Returns the threshold for the next dynamic reordering.
+ The threshold is in terms of number of nodes and is in effect only
+ if reordering is enabled. The count does not include the dead nodes,
+ unless the countDead parameter of the manager has been changed from
+ its default setting.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetNextReordering]
+
+******************************************************************************/
+unsigned int
+Cudd_ReadNextReordering(
+ DdManager *dd)
+{
+ return(dd->nextDyn);
+
+} /* end of Cudd_ReadNextReordering */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the threshold for the next dynamic reordering.]
+
+ Description [Sets the threshold for the next dynamic reordering.
+ The threshold is in terms of number of nodes and is in effect only
+ if reordering is enabled. The count does not include the dead nodes,
+ unless the countDead parameter of the manager has been changed from
+ its default setting.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadNextReordering]
+
+******************************************************************************/
+void
+Cudd_SetNextReordering(
+ DdManager *dd,
+ unsigned int next)
+{
+ dd->nextDyn = next;
+
+} /* end of Cudd_SetNextReordering */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the number of elementary reordering steps.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+double
+Cudd_ReadSwapSteps(
+ DdManager *dd)
+{
+#ifdef DD_COUNT
+ return(dd->swapSteps);
+#else
+ return(-1);
+#endif
+
+} /* end of Cudd_ReadSwapSteps */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the maximum allowed number of live nodes.]
+
+ Description [Reads the maximum allowed number of live nodes. When this
+ number is exceeded, the package returns NULL.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_SetMaxLive]
+
+******************************************************************************/
+unsigned int
+Cudd_ReadMaxLive(
+ DdManager *dd)
+{
+ return(dd->maxLive);
+
+} /* end of Cudd_ReadMaxLive */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the maximum allowed number of live nodes.]
+
+ Description [Sets the maximum allowed number of live nodes. When this
+ number is exceeded, the package returns NULL.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_ReadMaxLive]
+
+******************************************************************************/
+void
+Cudd_SetMaxLive(
+ DdManager *dd,
+ unsigned int maxLive)
+{
+ dd->maxLive = maxLive;
+
+} /* end of Cudd_SetMaxLive */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the maximum allowed memory.]
+
+ Description [Reads the maximum allowed memory. When this
+ number is exceeded, the package returns NULL.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_SetMaxMemory]
+
+******************************************************************************/
+long
+Cudd_ReadMaxMemory(
+ DdManager *dd)
+{
+ return(dd->maxmemhard);
+
+} /* end of Cudd_ReadMaxMemory */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the maximum allowed memory.]
+
+ Description [Sets the maximum allowed memory. When this
+ number is exceeded, the package returns NULL.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_ReadMaxMemory]
+
+******************************************************************************/
+void
+Cudd_SetMaxMemory(
+ DdManager *dd,
+ long maxMemory)
+{
+ dd->maxmemhard = maxMemory;
+
+} /* end of Cudd_SetMaxMemory */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prevents sifting of a variable.]
+
+ Description [This function sets a flag to prevent sifting of a
+ variable. Returns 1 if successful; 0 otherwise (i.e., invalid
+ variable index).]
+
+ SideEffects [Changes the "bindVar" flag in DdSubtable.]
+
+ SeeAlso [Cudd_bddUnbindVar]
+
+******************************************************************************/
+int
+Cudd_bddBindVar(
+ DdManager *dd /* manager */,
+ int index /* variable index */)
+{
+ if (index >= dd->size || index < 0) return(0);
+ dd->subtables[dd->perm[index]].bindVar = 1;
+ return(1);
+
+} /* end of Cudd_bddBindVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Allows the sifting of a variable.]
+
+ Description [This function resets the flag that prevents the sifting
+ of a variable. In successive variable reorderings, the variable will
+ NOT be skipped, that is, sifted. Initially all variables can be
+ sifted. It is necessary to call this function only to re-enable
+ sifting after a call to Cudd_bddBindVar. Returns 1 if successful; 0
+ otherwise (i.e., invalid variable index).]
+
+ SideEffects [Changes the "bindVar" flag in DdSubtable.]
+
+ SeeAlso [Cudd_bddBindVar]
+
+******************************************************************************/
+int
+Cudd_bddUnbindVar(
+ DdManager *dd /* manager */,
+ int index /* variable index */)
+{
+ if (index >= dd->size || index < 0) return(0);
+ dd->subtables[dd->perm[index]].bindVar = 0;
+ return(1);
+
+} /* end of Cudd_bddUnbindVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tells whether a variable can be sifted.]
+
+ Description [This function returns 1 if a variable is enabled for
+ sifting. Initially all variables can be sifted. This function returns
+ 0 only if there has been a previous call to Cudd_bddBindVar for that
+ variable not followed by a call to Cudd_bddUnbindVar. The function returns
+ 0 also in the case in which the index of the variable is out of bounds.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_bddBindVar Cudd_bddUnbindVar]
+
+******************************************************************************/
+int
+Cudd_bddVarIsBound(
+ DdManager *dd /* manager */,
+ int index /* variable index */)
+{
+ if (index >= dd->size || index < 0) return(0);
+ return(dd->subtables[dd->perm[index]].bindVar);
+
+} /* end of Cudd_bddVarIsBound */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets a variable type to primary input.]
+
+ Description [Sets a variable type to primary input. The variable type is
+ used by lazy sifting. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [modifies the manager]
+
+ SeeAlso [Cudd_bddSetPsVar Cudd_bddSetNsVar Cudd_bddIsPiVar]
+
+******************************************************************************/
+int
+Cudd_bddSetPiVar(
+ DdManager *dd /* manager */,
+ int index /* variable index */)
+{
+ if (index >= dd->size || index < 0) return (0);
+ dd->subtables[dd->perm[index]].varType = CUDD_VAR_PRIMARY_INPUT;
+ return(1);
+
+} /* end of Cudd_bddSetPiVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets a variable type to present state.]
+
+ Description [Sets a variable type to present state. The variable type is
+ used by lazy sifting. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [modifies the manager]
+
+ SeeAlso [Cudd_bddSetPiVar Cudd_bddSetNsVar Cudd_bddIsPsVar]
+
+******************************************************************************/
+int
+Cudd_bddSetPsVar(
+ DdManager *dd /* manager */,
+ int index /* variable index */)
+{
+ if (index >= dd->size || index < 0) return (0);
+ dd->subtables[dd->perm[index]].varType = CUDD_VAR_PRESENT_STATE;
+ return(1);
+
+} /* end of Cudd_bddSetPsVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets a variable type to next state.]
+
+ Description [Sets a variable type to next state. The variable type is
+ used by lazy sifting. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [modifies the manager]
+
+ SeeAlso [Cudd_bddSetPiVar Cudd_bddSetPsVar Cudd_bddIsNsVar]
+
+******************************************************************************/
+int
+Cudd_bddSetNsVar(
+ DdManager *dd /* manager */,
+ int index /* variable index */)
+{
+ if (index >= dd->size || index < 0) return (0);
+ dd->subtables[dd->perm[index]].varType = CUDD_VAR_NEXT_STATE;
+ return(1);
+
+} /* end of Cudd_bddSetNsVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether a variable is primary input.]
+
+ Description [Checks whether a variable is primary input. Returns 1 if
+ the variable's type is primary input; 0 if the variable exists but is
+ not a primary input; -1 if the variable does not exist.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_bddSetPiVar Cudd_bddIsPsVar Cudd_bddIsNsVar]
+
+******************************************************************************/
+int
+Cudd_bddIsPiVar(
+ DdManager *dd /* manager */,
+ int index /* variable index */)
+{
+ if (index >= dd->size || index < 0) return -1;
+ return (dd->subtables[dd->perm[index]].varType == CUDD_VAR_PRIMARY_INPUT);
+
+} /* end of Cudd_bddIsPiVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether a variable is present state.]
+
+ Description [Checks whether a variable is present state. Returns 1 if
+ the variable's type is present state; 0 if the variable exists but is
+ not a present state; -1 if the variable does not exist.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_bddSetPsVar Cudd_bddIsPiVar Cudd_bddIsNsVar]
+
+******************************************************************************/
+int
+Cudd_bddIsPsVar(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return -1;
+ return (dd->subtables[dd->perm[index]].varType == CUDD_VAR_PRESENT_STATE);
+
+} /* end of Cudd_bddIsPsVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether a variable is next state.]
+
+ Description [Checks whether a variable is next state. Returns 1 if
+ the variable's type is present state; 0 if the variable exists but is
+ not a present state; -1 if the variable does not exist.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_bddSetNsVar Cudd_bddIsPiVar Cudd_bddIsPsVar]
+
+******************************************************************************/
+int
+Cudd_bddIsNsVar(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return -1;
+ return (dd->subtables[dd->perm[index]].varType == CUDD_VAR_NEXT_STATE);
+
+} /* end of Cudd_bddIsNsVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets a corresponding pair index for a given index.]
+
+ Description [Sets a corresponding pair index for a given index.
+ These pair indices are present and next state variable. Returns 1 if
+ successful; 0 otherwise.]
+
+ SideEffects [modifies the manager]
+
+ SeeAlso [Cudd_bddReadPairIndex]
+
+******************************************************************************/
+int
+Cudd_bddSetPairIndex(
+ DdManager *dd /* manager */,
+ int index /* variable index */,
+ int pairIndex /* corresponding variable index */)
+{
+ if (index >= dd->size || index < 0) return(0);
+ dd->subtables[dd->perm[index]].pairIndex = pairIndex;
+ return(1);
+
+} /* end of Cudd_bddSetPairIndex */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads a corresponding pair index for a given index.]
+
+ Description [Reads a corresponding pair index for a given index.
+ These pair indices are present and next state variable. Returns the
+ corresponding variable index if the variable exists; -1 otherwise.]
+
+ SideEffects [modifies the manager]
+
+ SeeAlso [Cudd_bddSetPairIndex]
+
+******************************************************************************/
+int
+Cudd_bddReadPairIndex(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return -1;
+ return dd->subtables[dd->perm[index]].pairIndex;
+
+} /* end of Cudd_bddReadPairIndex */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets a variable to be grouped.]
+
+ Description [Sets a variable to be grouped. This function is used for
+ lazy sifting. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [modifies the manager]
+
+ SeeAlso [Cudd_bddSetVarHardGroup Cudd_bddResetVarToBeGrouped]
+
+******************************************************************************/
+int
+Cudd_bddSetVarToBeGrouped(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return(0);
+ if (dd->subtables[dd->perm[index]].varToBeGrouped <= CUDD_LAZY_SOFT_GROUP) {
+ dd->subtables[dd->perm[index]].varToBeGrouped = CUDD_LAZY_SOFT_GROUP;
+ }
+ return(1);
+
+} /* end of Cudd_bddSetVarToBeGrouped */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets a variable to be a hard group.]
+
+ Description [Sets a variable to be a hard group. This function is used
+ for lazy sifting. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [modifies the manager]
+
+ SeeAlso [Cudd_bddSetVarToBeGrouped Cudd_bddResetVarToBeGrouped
+ Cudd_bddIsVarHardGroup]
+
+******************************************************************************/
+int
+Cudd_bddSetVarHardGroup(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return(0);
+ dd->subtables[dd->perm[index]].varToBeGrouped = CUDD_LAZY_HARD_GROUP;
+ return(1);
+
+} /* end of Cudd_bddSetVarHardGrouped */
+
+
+/**Function********************************************************************
+
+ Synopsis [Resets a variable not to be grouped.]
+
+ Description [Resets a variable not to be grouped. This function is
+ used for lazy sifting. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [modifies the manager]
+
+ SeeAlso [Cudd_bddSetVarToBeGrouped Cudd_bddSetVarHardGroup]
+
+******************************************************************************/
+int
+Cudd_bddResetVarToBeGrouped(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return(0);
+ if (dd->subtables[dd->perm[index]].varToBeGrouped <=
+ CUDD_LAZY_SOFT_GROUP) {
+ dd->subtables[dd->perm[index]].varToBeGrouped = CUDD_LAZY_NONE;
+ }
+ return(1);
+
+} /* end of Cudd_bddResetVarToBeGrouped */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether a variable is set to be grouped.]
+
+ Description [Checks whether a variable is set to be grouped. This
+ function is used for lazy sifting.]
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_bddIsVarToBeGrouped(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return(-1);
+ if (dd->subtables[dd->perm[index]].varToBeGrouped == CUDD_LAZY_UNGROUP)
+ return(0);
+ else
+ return(dd->subtables[dd->perm[index]].varToBeGrouped);
+
+} /* end of Cudd_bddIsVarToBeGrouped */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets a variable to be ungrouped.]
+
+ Description [Sets a variable to be ungrouped. This function is used
+ for lazy sifting. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [modifies the manager]
+
+ SeeAlso [Cudd_bddIsVarToBeUngrouped]
+
+******************************************************************************/
+int
+Cudd_bddSetVarToBeUngrouped(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return(0);
+ dd->subtables[dd->perm[index]].varToBeGrouped = CUDD_LAZY_UNGROUP;
+ return(1);
+
+} /* end of Cudd_bddSetVarToBeGrouped */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether a variable is set to be ungrouped.]
+
+ Description [Checks whether a variable is set to be ungrouped. This
+ function is used for lazy sifting. Returns 1 if the variable is marked
+ to be ungrouped; 0 if the variable exists, but it is not marked to be
+ ungrouped; -1 if the variable does not exist.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_bddSetVarToBeUngrouped]
+
+******************************************************************************/
+int
+Cudd_bddIsVarToBeUngrouped(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return(-1);
+ return dd->subtables[dd->perm[index]].varToBeGrouped == CUDD_LAZY_UNGROUP;
+
+} /* end of Cudd_bddIsVarToBeGrouped */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether a variable is set to be in a hard group.]
+
+ Description [Checks whether a variable is set to be in a hard group. This
+ function is used for lazy sifting. Returns 1 if the variable is marked
+ to be in a hard group; 0 if the variable exists, but it is not marked to be
+ in a hard group; -1 if the variable does not exist.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_bddSetVarHardGroup]
+
+******************************************************************************/
+int
+Cudd_bddIsVarHardGroup(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return(-1);
+ if (dd->subtables[dd->perm[index]].varToBeGrouped == CUDD_LAZY_HARD_GROUP)
+ return(1);
+ return(0);
+
+} /* end of Cudd_bddIsVarToBeGrouped */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Fixes a variable group tree.]
+
+ Description []
+
+ SideEffects [Changes the variable group tree.]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+fixVarTree(
+ MtrNode * treenode,
+ int * perm,
+ int size)
+{
+ treenode->index = treenode->low;
+ treenode->low = ((int) treenode->index < size) ?
+ perm[treenode->index] : treenode->index;
+ if (treenode->child != NULL)
+ fixVarTree(treenode->child, perm, size);
+ if (treenode->younger != NULL)
+ fixVarTree(treenode->younger, perm, size);
+ return;
+
+} /* end of fixVarTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Adds multiplicity groups to a ZDD variable group tree.]
+
+ Description [Adds multiplicity groups to a ZDD variable group tree.
+ Returns 1 if successful; 0 otherwise. This function creates the groups
+ for set of ZDD variables (whose cardinality is given by parameter
+ multiplicity) that are created for each BDD variable in
+ Cudd_zddVarsFromBddVars. The crux of the matter is to determine the index
+ each new group. (The index of the first variable in the group.)
+ We first build all the groups for the children of a node, and then deal
+ with the ZDD variables that are directly attached to the node. The problem
+ for these is that the tree itself does not provide information on their
+ position inside the group. While we deal with the children of the node,
+ therefore, we keep track of all the positions they occupy. The remaining
+ positions in the tree can be freely used. Also, we keep track of all the
+ variables placed in the children. All the remaining variables are directly
+ attached to the group. We can then place any pair of variables not yet
+ grouped in any pair of available positions in the node.]
+
+ SideEffects [Changes the variable group tree.]
+
+ SeeAlso [Cudd_zddVarsFromBddVars]
+
+******************************************************************************/
+static int
+addMultiplicityGroups(
+ DdManager *dd /* manager */,
+ MtrNode *treenode /* current tree node */,
+ int multiplicity /* how many ZDD vars per BDD var */,
+ char *vmask /* variable pairs for which a group has been already built */,
+ char *lmask /* levels for which a group has already been built*/)
+{
+ int startV, stopV, startL;
+ int i, j;
+ MtrNode *auxnode = treenode;
+
+ while (auxnode != NULL) {
+ if (auxnode->child != NULL) {
+ addMultiplicityGroups(dd,auxnode->child,multiplicity,vmask,lmask);
+ }
+ /* Build remaining groups. */
+ startV = dd->permZ[auxnode->index] / multiplicity;
+ startL = auxnode->low / multiplicity;
+ stopV = startV + auxnode->size / multiplicity;
+ /* Walk down vmask starting at startV and build missing groups. */
+ for (i = startV, j = startL; i < stopV; i++) {
+ if (vmask[i] == 0) {
+ MtrNode *node;
+ while (lmask[j] == 1) j++;
+ node = Mtr_MakeGroup(auxnode, j * multiplicity, multiplicity,
+ MTR_FIXED);
+ if (node == NULL) {
+ return(0);
+ }
+ node->index = dd->invpermZ[i * multiplicity];
+ vmask[i] = 1;
+ lmask[j] = 1;
+ }
+ }
+ auxnode = auxnode->younger;
+ }
+ return(1);
+
+} /* end of addMultiplicityGroups */
+
diff --git a/src/bdd/cudd/cuddAddAbs.c b/src/bdd/cudd/cuddAddAbs.c
new file mode 100644
index 00000000..27039908
--- /dev/null
+++ b/src/bdd/cudd/cuddAddAbs.c
@@ -0,0 +1,566 @@
+/**CFile***********************************************************************
+
+ FileName [cuddAddAbs.c]
+
+ PackageName [cudd]
+
+ Synopsis [Quantification functions for ADDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_addExistAbstract()
+ <li> Cudd_addUnivAbstract()
+ <li> Cudd_addOrAbstract()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddAddExistAbstractRecur()
+ <li> cuddAddUnivAbstractRecur()
+ <li> cuddAddOrAbstractRecur()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> addCheckPositiveCube()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddAddAbs.c,v 1.1.1.1 2003/02/24 22:23:50 wjiang Exp $";
+#endif
+
+static DdNode *two;
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int addCheckPositiveCube ARGS((DdManager *manager, DdNode *cube));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Existentially Abstracts all the variables in cube from f.]
+
+ Description [Abstracts all the variables in cube from f by summing
+ over all possible values taken by the variables. Returns the
+ abstracted ADD.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addUnivAbstract Cudd_bddExistAbstract
+ Cudd_addOrAbstract]
+
+******************************************************************************/
+DdNode *
+Cudd_addExistAbstract(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * cube)
+{
+ DdNode *res;
+
+ two = cuddUniqueConst(manager,(CUDD_VALUE_TYPE) 2);
+ if (two == NULL) return(NULL);
+ cuddRef(two);
+
+ if (addCheckPositiveCube(manager, cube) == 0) {
+ (void) fprintf(manager->err,"Error: Can only abstract cubes");
+ return(NULL);
+ }
+
+ do {
+ manager->reordered = 0;
+ res = cuddAddExistAbstractRecur(manager, f, cube);
+ } while (manager->reordered == 1);
+
+ if (res == NULL) {
+ Cudd_RecursiveDeref(manager,two);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(manager,two);
+ cuddDeref(res);
+
+ return(res);
+
+} /* end of Cudd_addExistAbstract */
+
+
+/**Function********************************************************************
+
+ Synopsis [Universally Abstracts all the variables in cube from f.]
+
+ Description [Abstracts all the variables in cube from f by taking
+ the product over all possible values taken by the variable. Returns
+ the abstracted ADD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addExistAbstract Cudd_bddUnivAbstract
+ Cudd_addOrAbstract]
+
+******************************************************************************/
+DdNode *
+Cudd_addUnivAbstract(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * cube)
+{
+ DdNode *res;
+
+ if (addCheckPositiveCube(manager, cube) == 0) {
+ (void) fprintf(manager->err,"Error: Can only abstract cubes");
+ return(NULL);
+ }
+
+ do {
+ manager->reordered = 0;
+ res = cuddAddUnivAbstractRecur(manager, f, cube);
+ } while (manager->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_addUnivAbstract */
+
+
+/**Function********************************************************************
+
+ Synopsis [Disjunctively abstracts all the variables in cube from the
+ 0-1 ADD f.]
+
+ Description [Abstracts all the variables in cube from the 0-1 ADD f
+ by taking the disjunction over all possible values taken by the
+ variables. Returns the abstracted ADD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addUnivAbstract Cudd_addExistAbstract]
+
+******************************************************************************/
+DdNode *
+Cudd_addOrAbstract(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * cube)
+{
+ DdNode *res;
+
+ if (addCheckPositiveCube(manager, cube) == 0) {
+ (void) fprintf(manager->err,"Error: Can only abstract cubes");
+ return(NULL);
+ }
+
+ do {
+ manager->reordered = 0;
+ res = cuddAddOrAbstractRecur(manager, f, cube);
+ } while (manager->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addOrAbstract */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addExistAbstract.]
+
+ Description [Performs the recursive step of Cudd_addExistAbstract.
+ Returns the ADD obtained by abstracting the variables of cube from f,
+ if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddAddExistAbstractRecur(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * cube)
+{
+ DdNode *T, *E, *res, *res1, *res2, *zero;
+
+ statLine(manager);
+ zero = DD_ZERO(manager);
+
+ /* Cube is guaranteed to be a cube at this point. */
+ if (f == zero || cuddIsConstant(cube)) {
+ return(f);
+ }
+
+ /* Abstract a variable that does not appear in f => multiply by 2. */
+ if (cuddI(manager,f->index) > cuddI(manager,cube->index)) {
+ res1 = cuddAddExistAbstractRecur(manager, f, cuddT(cube));
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ /* Use the "internal" procedure to be alerted in case of
+ ** dynamic reordering. If dynamic reordering occurs, we
+ ** have to abort the entire abstraction.
+ */
+ res = cuddAddApplyRecur(manager,Cudd_addTimes,res1,two);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(manager,res1);
+ cuddDeref(res);
+ return(res);
+ }
+
+ if ((res = cuddCacheLookup2(manager, Cudd_addExistAbstract, f, cube)) != NULL) {
+ return(res);
+ }
+
+ T = cuddT(f);
+ E = cuddE(f);
+
+ /* If the two indices are the same, so are their levels. */
+ if (f->index == cube->index) {
+ res1 = cuddAddExistAbstractRecur(manager, T, cuddT(cube));
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ res2 = cuddAddExistAbstractRecur(manager, E, cuddT(cube));
+ if (res2 == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ return(NULL);
+ }
+ cuddRef(res2);
+ res = cuddAddApplyRecur(manager, Cudd_addPlus, res1, res2);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ Cudd_RecursiveDeref(manager,res2);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(manager,res1);
+ Cudd_RecursiveDeref(manager,res2);
+ cuddCacheInsert2(manager, Cudd_addExistAbstract, f, cube, res);
+ cuddDeref(res);
+ return(res);
+ } else { /* if (cuddI(manager,f->index) < cuddI(manager,cube->index)) */
+ res1 = cuddAddExistAbstractRecur(manager, T, cube);
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ res2 = cuddAddExistAbstractRecur(manager, E, cube);
+ if (res2 == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ return(NULL);
+ }
+ cuddRef(res2);
+ res = (res1 == res2) ? res1 :
+ cuddUniqueInter(manager, (int) f->index, res1, res2);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ Cudd_RecursiveDeref(manager,res2);
+ return(NULL);
+ }
+ cuddDeref(res1);
+ cuddDeref(res2);
+ cuddCacheInsert2(manager, Cudd_addExistAbstract, f, cube, res);
+ return(res);
+ }
+
+} /* end of cuddAddExistAbstractRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addUnivAbstract.]
+
+ Description [Performs the recursive step of Cudd_addUnivAbstract.
+ Returns the ADD obtained by abstracting the variables of cube from f,
+ if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddAddUnivAbstractRecur(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * cube)
+{
+ DdNode *T, *E, *res, *res1, *res2, *one, *zero;
+
+ statLine(manager);
+ one = DD_ONE(manager);
+ zero = DD_ZERO(manager);
+
+ /* Cube is guaranteed to be a cube at this point.
+ ** zero and one are the only constatnts c such that c*c=c.
+ */
+ if (f == zero || f == one || cube == one) {
+ return(f);
+ }
+
+ /* Abstract a variable that does not appear in f. */
+ if (cuddI(manager,f->index) > cuddI(manager,cube->index)) {
+ res1 = cuddAddUnivAbstractRecur(manager, f, cuddT(cube));
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ /* Use the "internal" procedure to be alerted in case of
+ ** dynamic reordering. If dynamic reordering occurs, we
+ ** have to abort the entire abstraction.
+ */
+ res = cuddAddApplyRecur(manager, Cudd_addTimes, res1, res1);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(manager,res1);
+ cuddDeref(res);
+ return(res);
+ }
+
+ if ((res = cuddCacheLookup2(manager, Cudd_addUnivAbstract, f, cube)) != NULL) {
+ return(res);
+ }
+
+ T = cuddT(f);
+ E = cuddE(f);
+
+ /* If the two indices are the same, so are their levels. */
+ if (f->index == cube->index) {
+ res1 = cuddAddUnivAbstractRecur(manager, T, cuddT(cube));
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ res2 = cuddAddUnivAbstractRecur(manager, E, cuddT(cube));
+ if (res2 == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ return(NULL);
+ }
+ cuddRef(res2);
+ res = cuddAddApplyRecur(manager, Cudd_addTimes, res1, res2);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ Cudd_RecursiveDeref(manager,res2);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(manager,res1);
+ Cudd_RecursiveDeref(manager,res2);
+ cuddCacheInsert2(manager, Cudd_addUnivAbstract, f, cube, res);
+ cuddDeref(res);
+ return(res);
+ } else { /* if (cuddI(manager,f->index) < cuddI(manager,cube->index)) */
+ res1 = cuddAddUnivAbstractRecur(manager, T, cube);
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ res2 = cuddAddUnivAbstractRecur(manager, E, cube);
+ if (res2 == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ return(NULL);
+ }
+ cuddRef(res2);
+ res = (res1 == res2) ? res1 :
+ cuddUniqueInter(manager, (int) f->index, res1, res2);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ Cudd_RecursiveDeref(manager,res2);
+ return(NULL);
+ }
+ cuddDeref(res1);
+ cuddDeref(res2);
+ cuddCacheInsert2(manager, Cudd_addUnivAbstract, f, cube, res);
+ return(res);
+ }
+
+} /* end of cuddAddUnivAbstractRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addOrAbstract.]
+
+ Description [Performs the recursive step of Cudd_addOrAbstract.
+ Returns the ADD obtained by abstracting the variables of cube from f,
+ if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddAddOrAbstractRecur(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * cube)
+{
+ DdNode *T, *E, *res, *res1, *res2, *one;
+
+ statLine(manager);
+ one = DD_ONE(manager);
+
+ /* Cube is guaranteed to be a cube at this point. */
+ if (cuddIsConstant(f) || cube == one) {
+ return(f);
+ }
+
+ /* Abstract a variable that does not appear in f. */
+ if (cuddI(manager,f->index) > cuddI(manager,cube->index)) {
+ res1 = cuddAddOrAbstractRecur(manager, f, cuddT(cube));
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ /* Use the "internal" procedure to be alerted in case of
+ ** dynamic reordering. If dynamic reordering occurs, we
+ ** have to abort the entire abstraction.
+ */
+ res = cuddAddApplyRecur(manager, Cudd_addOr, res1, res1);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(manager,res1);
+ cuddDeref(res);
+ return(res);
+ }
+
+ if ((res = cuddCacheLookup2(manager, Cudd_addOrAbstract, f, cube)) != NULL) {
+ return(res);
+ }
+
+ T = cuddT(f);
+ E = cuddE(f);
+
+ /* If the two indices are the same, so are their levels. */
+ if (f->index == cube->index) {
+ res1 = cuddAddOrAbstractRecur(manager, T, cuddT(cube));
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ if (res1 != one) {
+ res2 = cuddAddOrAbstractRecur(manager, E, cuddT(cube));
+ if (res2 == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ return(NULL);
+ }
+ cuddRef(res2);
+ res = cuddAddApplyRecur(manager, Cudd_addOr, res1, res2);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ Cudd_RecursiveDeref(manager,res2);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(manager,res1);
+ Cudd_RecursiveDeref(manager,res2);
+ } else {
+ res = res1;
+ }
+ cuddCacheInsert2(manager, Cudd_addOrAbstract, f, cube, res);
+ cuddDeref(res);
+ return(res);
+ } else { /* if (cuddI(manager,f->index) < cuddI(manager,cube->index)) */
+ res1 = cuddAddOrAbstractRecur(manager, T, cube);
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ res2 = cuddAddOrAbstractRecur(manager, E, cube);
+ if (res2 == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ return(NULL);
+ }
+ cuddRef(res2);
+ res = (res1 == res2) ? res1 :
+ cuddUniqueInter(manager, (int) f->index, res1, res2);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ Cudd_RecursiveDeref(manager,res2);
+ return(NULL);
+ }
+ cuddDeref(res1);
+ cuddDeref(res2);
+ cuddCacheInsert2(manager, Cudd_addOrAbstract, f, cube, res);
+ return(res);
+ }
+
+} /* end of cuddAddOrAbstractRecur */
+
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether cube is an ADD representing the product
+ of positive literals.]
+
+ Description [Checks whether cube is an ADD representing the product of
+ positive literals. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+addCheckPositiveCube(
+ DdManager * manager,
+ DdNode * cube)
+{
+ if (Cudd_IsComplement(cube)) return(0);
+ if (cube == DD_ONE(manager)) return(1);
+ if (cuddIsConstant(cube)) return(0);
+ if (cuddE(cube) == DD_ZERO(manager)) {
+ return(addCheckPositiveCube(manager, cuddT(cube)));
+ }
+ return(0);
+
+} /* end of addCheckPositiveCube */
+
diff --git a/src/bdd/cudd/cuddAddApply.c b/src/bdd/cudd/cuddAddApply.c
new file mode 100644
index 00000000..67649913
--- /dev/null
+++ b/src/bdd/cudd/cuddAddApply.c
@@ -0,0 +1,917 @@
+/**CFile***********************************************************************
+
+ FileName [cuddAddApply.c]
+
+ PackageName [cudd]
+
+ Synopsis [Apply functions for ADDs and their operators.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_addApply()
+ <li> Cudd_addMonadicApply()
+ <li> Cudd_addPlus()
+ <li> Cudd_addTimes()
+ <li> Cudd_addThreshold()
+ <li> Cudd_addSetNZ()
+ <li> Cudd_addDivide()
+ <li> Cudd_addMinus()
+ <li> Cudd_addMinimum()
+ <li> Cudd_addMaximum()
+ <li> Cudd_addOneZeroMaximum()
+ <li> Cudd_addDiff()
+ <li> Cudd_addAgreement()
+ <li> Cudd_addOr()
+ <li> Cudd_addNand()
+ <li> Cudd_addNor()
+ <li> Cudd_addXor()
+ <li> Cudd_addXnor()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddAddApplyRecur()
+ <li> cuddAddMonadicApplyRecur()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at Boulder.
+ The University of Colorado at Boulder makes no warranty about the
+ suitability of this software for any purpose. It is presented on an
+ AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddAddApply.c,v 1.1.1.1 2003/02/24 22:23:50 wjiang Exp $";
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Applies op to the corresponding discriminants of f and g.]
+
+ Description [Applies op to the corresponding discriminants of f and g.
+ Returns a pointer to the result if succssful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addMonadicApply Cudd_addPlus Cudd_addTimes
+ Cudd_addThreshold Cudd_addSetNZ Cudd_addDivide Cudd_addMinus Cudd_addMinimum
+ Cudd_addMaximum Cudd_addOneZeroMaximum Cudd_addDiff Cudd_addAgreement
+ Cudd_addOr Cudd_addNand Cudd_addNor Cudd_addXor Cudd_addXnor]
+
+******************************************************************************/
+DdNode *
+Cudd_addApply(
+ DdManager * dd,
+ DdNode * (*op)(DdManager *, DdNode **, DdNode **),
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddAddApplyRecur(dd,op,f,g);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addApply */
+
+
+/**Function********************************************************************
+
+ Synopsis [Integer and floating point addition.]
+
+ Description [Integer and floating point addition. Returns NULL if not
+ a terminal case; f+g otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addPlus(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *res;
+ DdNode *F, *G;
+ CUDD_VALUE_TYPE value;
+
+ F = *f; G = *g;
+ if (F == DD_ZERO(dd)) return(G);
+ if (G == DD_ZERO(dd)) return(F);
+ if (cuddIsConstant(F) && cuddIsConstant(G)) {
+ value = cuddV(F)+cuddV(G);
+ res = cuddUniqueConst(dd,value);
+ return(res);
+ }
+ if (F > G) { /* swap f and g */
+ *f = G;
+ *g = F;
+ }
+ return(NULL);
+
+} /* end of Cudd_addPlus */
+
+
+/**Function********************************************************************
+
+ Synopsis [Integer and floating point multiplication.]
+
+ Description [Integer and floating point multiplication. Returns NULL
+ if not a terminal case; f * g otherwise. This function can be used also
+ to take the AND of two 0-1 ADDs.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addTimes(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *res;
+ DdNode *F, *G;
+ CUDD_VALUE_TYPE value;
+
+ F = *f; G = *g;
+ if (F == DD_ZERO(dd) || G == DD_ZERO(dd)) return(DD_ZERO(dd));
+ if (F == DD_ONE(dd)) return(G);
+ if (G == DD_ONE(dd)) return(F);
+ if (cuddIsConstant(F) && cuddIsConstant(G)) {
+ value = cuddV(F)*cuddV(G);
+ res = cuddUniqueConst(dd,value);
+ return(res);
+ }
+ if (F > G) { /* swap f and g */
+ *f = G;
+ *g = F;
+ }
+ return(NULL);
+
+} /* end of Cudd_addTimes */
+
+
+/**Function********************************************************************
+
+ Synopsis [f if f&gt;=g; 0 if f&lt;g.]
+
+ Description [Threshold operator for Apply (f if f &gt;=g; 0 if f&lt;g).
+ Returns NULL if not a terminal case; f op g otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addThreshold(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *F, *G;
+
+ F = *f; G = *g;
+ if (F == G || F == DD_PLUS_INFINITY(dd)) return(F);
+ if (cuddIsConstant(F) && cuddIsConstant(G)) {
+ if (cuddV(F) >= cuddV(G)) {
+ return(F);
+ } else {
+ return(DD_ZERO(dd));
+ }
+ }
+ return(NULL);
+
+} /* end of Cudd_addThreshold */
+
+
+/**Function********************************************************************
+
+ Synopsis [This operator sets f to the value of g wherever g != 0.]
+
+ Description [This operator sets f to the value of g wherever g != 0.
+ Returns NULL if not a terminal case; f op g otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addSetNZ(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *F, *G;
+
+ F = *f; G = *g;
+ if (F == G) return(F);
+ if (F == DD_ZERO(dd)) return(G);
+ if (G == DD_ZERO(dd)) return(F);
+ if (cuddIsConstant(G)) return(G);
+ return(NULL);
+
+} /* end of Cudd_addSetNZ */
+
+
+/**Function********************************************************************
+
+ Synopsis [Integer and floating point division.]
+
+ Description [Integer and floating point division. Returns NULL if not
+ a terminal case; f / g otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addDivide(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *res;
+ DdNode *F, *G;
+ CUDD_VALUE_TYPE value;
+
+ F = *f; G = *g;
+ /* We would like to use F == G -> F/G == 1, but F and G may
+ ** contain zeroes. */
+ if (F == DD_ZERO(dd)) return(DD_ZERO(dd));
+ if (G == DD_ONE(dd)) return(F);
+ if (cuddIsConstant(F) && cuddIsConstant(G)) {
+ value = cuddV(F)/cuddV(G);
+ res = cuddUniqueConst(dd,value);
+ return(res);
+ }
+ return(NULL);
+
+} /* end of Cudd_addDivide */
+
+
+/**Function********************************************************************
+
+ Synopsis [Integer and floating point subtraction.]
+
+ Description [Integer and floating point subtraction. Returns NULL if
+ not a terminal case; f - g otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addMinus(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *res;
+ DdNode *F, *G;
+ CUDD_VALUE_TYPE value;
+
+ F = *f; G = *g;
+ if (F == G) return(DD_ZERO(dd));
+ if (F == DD_ZERO(dd)) return(cuddAddNegateRecur(dd,G));
+ if (G == DD_ZERO(dd)) return(F);
+ if (cuddIsConstant(F) && cuddIsConstant(G)) {
+ value = cuddV(F)-cuddV(G);
+ res = cuddUniqueConst(dd,value);
+ return(res);
+ }
+ return(NULL);
+
+} /* end of Cudd_addMinus */
+
+
+/**Function********************************************************************
+
+ Synopsis [Integer and floating point min.]
+
+ Description [Integer and floating point min for Cudd_addApply.
+ Returns NULL if not a terminal case; min(f,g) otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addMinimum(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *F, *G;
+
+ F = *f; G = *g;
+ if (F == DD_PLUS_INFINITY(dd)) return(G);
+ if (G == DD_PLUS_INFINITY(dd)) return(F);
+ if (F == G) return(F);
+#if 0
+ /* These special cases probably do not pay off. */
+ if (F == DD_MINUS_INFINITY(dd)) return(F);
+ if (G == DD_MINUS_INFINITY(dd)) return(G);
+#endif
+ if (cuddIsConstant(F) && cuddIsConstant(G)) {
+ if (cuddV(F) <= cuddV(G)) {
+ return(F);
+ } else {
+ return(G);
+ }
+ }
+ if (F > G) { /* swap f and g */
+ *f = G;
+ *g = F;
+ }
+ return(NULL);
+
+} /* end of Cudd_addMinimum */
+
+
+/**Function********************************************************************
+
+ Synopsis [Integer and floating point max.]
+
+ Description [Integer and floating point max for Cudd_addApply.
+ Returns NULL if not a terminal case; max(f,g) otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addMaximum(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *F, *G;
+
+ F = *f; G = *g;
+ if (F == G) return(F);
+ if (F == DD_MINUS_INFINITY(dd)) return(G);
+ if (G == DD_MINUS_INFINITY(dd)) return(F);
+#if 0
+ /* These special cases probably do not pay off. */
+ if (F == DD_PLUS_INFINITY(dd)) return(F);
+ if (G == DD_PLUS_INFINITY(dd)) return(G);
+#endif
+ if (cuddIsConstant(F) && cuddIsConstant(G)) {
+ if (cuddV(F) >= cuddV(G)) {
+ return(F);
+ } else {
+ return(G);
+ }
+ }
+ if (F > G) { /* swap f and g */
+ *f = G;
+ *g = F;
+ }
+ return(NULL);
+
+} /* end of Cudd_addMaximum */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns 1 if f &gt; g and 0 otherwise.]
+
+ Description [Returns 1 if f &gt; g and 0 otherwise. Used in
+ conjunction with Cudd_addApply. Returns NULL if not a terminal
+ case.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addOneZeroMaximum(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+
+ if (*f == *g) return(DD_ZERO(dd));
+ if (*g == DD_PLUS_INFINITY(dd))
+ return DD_ZERO(dd);
+ if (cuddIsConstant(*f) && cuddIsConstant(*g)) {
+ if (cuddV(*f) > cuddV(*g)) {
+ return(DD_ONE(dd));
+ } else {
+ return(DD_ZERO(dd));
+ }
+ }
+
+ return(NULL);
+
+} /* end of Cudd_addOneZeroMaximum */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns plusinfinity if f=g; returns min(f,g) if f!=g.]
+
+ Description [Returns NULL if not a terminal case; f op g otherwise,
+ where f op g is plusinfinity if f=g; min(f,g) if f!=g.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addDiff(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *F, *G;
+
+ F = *f; G = *g;
+ if (F == G) return(DD_PLUS_INFINITY(dd));
+ if (F == DD_PLUS_INFINITY(dd)) return(G);
+ if (G == DD_PLUS_INFINITY(dd)) return(F);
+ if (cuddIsConstant(F) && cuddIsConstant(G)) {
+ if (cuddV(F) != cuddV(G)) {
+ if (cuddV(F) < cuddV(G)) {
+ return(F);
+ } else {
+ return(G);
+ }
+ } else {
+ return(DD_PLUS_INFINITY(dd));
+ }
+ }
+ return(NULL);
+
+} /* end of Cudd_addDiff */
+
+
+/**Function********************************************************************
+
+ Synopsis [f if f==g; background if f!=g.]
+
+ Description [Returns NULL if not a terminal case; f op g otherwise,
+ where f op g is f if f==g; background if f!=g.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addAgreement(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *F, *G;
+
+ F = *f; G = *g;
+ if (F == G) return(F);
+ if (F == dd->background) return(F);
+ if (G == dd->background) return(G);
+ if (cuddIsConstant(F) && cuddIsConstant(G)) return(dd->background);
+ return(NULL);
+
+} /* end of Cudd_addAgreement */
+
+
+/**Function********************************************************************
+
+ Synopsis [Disjunction of two 0-1 ADDs.]
+
+ Description [Disjunction of two 0-1 ADDs. Returns NULL
+ if not a terminal case; f OR g otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addOr(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *F, *G;
+
+ F = *f; G = *g;
+ if (F == DD_ONE(dd) || G == DD_ONE(dd)) return(DD_ONE(dd));
+ if (cuddIsConstant(F)) return(G);
+ if (cuddIsConstant(G)) return(F);
+ if (F == G) return(F);
+ if (F > G) { /* swap f and g */
+ *f = G;
+ *g = F;
+ }
+ return(NULL);
+
+} /* end of Cudd_addOr */
+
+
+/**Function********************************************************************
+
+ Synopsis [NAND of two 0-1 ADDs.]
+
+ Description [NAND of two 0-1 ADDs. Returns NULL
+ if not a terminal case; f NAND g otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addNand(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *F, *G;
+
+ F = *f; G = *g;
+ if (F == DD_ZERO(dd) || G == DD_ZERO(dd)) return(DD_ONE(dd));
+ if (cuddIsConstant(F) && cuddIsConstant(G)) return(DD_ZERO(dd));
+ if (F > G) { /* swap f and g */
+ *f = G;
+ *g = F;
+ }
+ return(NULL);
+
+} /* end of Cudd_addNand */
+
+
+/**Function********************************************************************
+
+ Synopsis [NOR of two 0-1 ADDs.]
+
+ Description [NOR of two 0-1 ADDs. Returns NULL
+ if not a terminal case; f NOR g otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addNor(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *F, *G;
+
+ F = *f; G = *g;
+ if (F == DD_ONE(dd) || G == DD_ONE(dd)) return(DD_ZERO(dd));
+ if (cuddIsConstant(F) && cuddIsConstant(G)) return(DD_ONE(dd));
+ if (F > G) { /* swap f and g */
+ *f = G;
+ *g = F;
+ }
+ return(NULL);
+
+} /* end of Cudd_addNor */
+
+
+/**Function********************************************************************
+
+ Synopsis [XOR of two 0-1 ADDs.]
+
+ Description [XOR of two 0-1 ADDs. Returns NULL
+ if not a terminal case; f XOR g otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addXor(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *F, *G;
+
+ F = *f; G = *g;
+ if (F == G) return(DD_ZERO(dd));
+ if (F == DD_ONE(dd) && G == DD_ZERO(dd)) return(DD_ONE(dd));
+ if (G == DD_ONE(dd) && F == DD_ZERO(dd)) return(DD_ONE(dd));
+ if (cuddIsConstant(F) && cuddIsConstant(G)) return(DD_ZERO(dd));
+ if (F > G) { /* swap f and g */
+ *f = G;
+ *g = F;
+ }
+ return(NULL);
+
+} /* end of Cudd_addXor */
+
+
+/**Function********************************************************************
+
+ Synopsis [XNOR of two 0-1 ADDs.]
+
+ Description [XNOR of two 0-1 ADDs. Returns NULL
+ if not a terminal case; f XNOR g otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addXnor(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *F, *G;
+
+ F = *f; G = *g;
+ if (F == G) return(DD_ONE(dd));
+ if (F == DD_ONE(dd) && G == DD_ONE(dd)) return(DD_ONE(dd));
+ if (G == DD_ZERO(dd) && F == DD_ZERO(dd)) return(DD_ONE(dd));
+ if (cuddIsConstant(F) && cuddIsConstant(G)) return(DD_ZERO(dd));
+ if (F > G) { /* swap f and g */
+ *f = G;
+ *g = F;
+ }
+ return(NULL);
+
+} /* end of Cudd_addXnor */
+
+
+/**Function********************************************************************
+
+ Synopsis [Applies op to the discriminants of f.]
+
+ Description [Applies op to the discriminants of f.
+ Returns a pointer to the result if succssful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply Cudd_addLog]
+
+******************************************************************************/
+DdNode *
+Cudd_addMonadicApply(
+ DdManager * dd,
+ DdNode * (*op)(DdManager *, DdNode *),
+ DdNode * f)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddAddMonadicApplyRecur(dd,op,f);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addMonadicApply */
+
+
+/**Function********************************************************************
+
+ Synopsis [Natural logarithm of an ADD.]
+
+ Description [Natural logarithm of an ADDs. Returns NULL
+ if not a terminal case; log(f) otherwise. The discriminants of f must
+ be positive double's.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addMonadicApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addLog(
+ DdManager * dd,
+ DdNode * f)
+{
+ if (cuddIsConstant(f)) {
+ CUDD_VALUE_TYPE value = log(cuddV(f));
+ DdNode *res = cuddUniqueConst(dd,value);
+ return(res);
+ }
+ return(NULL);
+
+} /* end of Cudd_addLog */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addApply.]
+
+ Description [Performs the recursive step of Cudd_addApply. Returns a
+ pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddAddMonadicApplyRecur]
+
+******************************************************************************/
+DdNode *
+cuddAddApplyRecur(
+ DdManager * dd,
+ DdNode * (*op)(DdManager *, DdNode **, DdNode **),
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res,
+ *fv, *fvn, *gv, *gvn,
+ *T, *E;
+ unsigned int ford, gord;
+ unsigned int index;
+ DdNode *(*cacheOp)(DdManager *, DdNode *, DdNode *);
+
+ /* Check terminal cases. Op may swap f and g to increase the
+ * cache hit rate.
+ */
+ statLine(dd);
+ res = (*op)(dd,&f,&g);
+ if (res != NULL) return(res);
+
+ /* Check cache. */
+ cacheOp = (DdNode *(*)(DdManager *, DdNode *, DdNode *)) op;
+ res = cuddCacheLookup2(dd,cacheOp,f,g);
+ if (res != NULL) return(res);
+
+ /* Recursive step. */
+ ford = cuddI(dd,f->index);
+ gord = cuddI(dd,g->index);
+ if (ford <= gord) {
+ index = f->index;
+ fv = cuddT(f);
+ fvn = cuddE(f);
+ } else {
+ index = g->index;
+ fv = fvn = f;
+ }
+ if (gord <= ford) {
+ gv = cuddT(g);
+ gvn = cuddE(g);
+ } else {
+ gv = gvn = g;
+ }
+
+ T = cuddAddApplyRecur(dd,op,fv,gv);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+
+ E = cuddAddApplyRecur(dd,op,fvn,gvn);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd,T);
+ return(NULL);
+ }
+ cuddRef(E);
+
+ res = (T == E) ? T : cuddUniqueInter(dd,(int)index,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+
+ /* Store result. */
+ cuddCacheInsert2(dd,cacheOp,f,g,res);
+
+ return(res);
+
+} /* end of cuddAddApplyRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addMonadicApply.]
+
+ Description [Performs the recursive step of Cudd_addMonadicApply. Returns a
+ pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddAddApplyRecur]
+
+******************************************************************************/
+DdNode *
+cuddAddMonadicApplyRecur(
+ DdManager * dd,
+ DdNode * (*op)(DdManager *, DdNode *),
+ DdNode * f)
+{
+ DdNode *res, *ft, *fe, *T, *E;
+ unsigned int ford;
+ unsigned int index;
+
+ /* Check terminal cases. */
+ statLine(dd);
+ res = (*op)(dd,f);
+ if (res != NULL) return(res);
+
+ /* Check cache. */
+ res = cuddCacheLookup1(dd,op,f);
+ if (res != NULL) return(res);
+
+ /* Recursive step. */
+ ford = cuddI(dd,f->index);
+ index = f->index;
+ ft = cuddT(f);
+ fe = cuddE(f);
+
+ T = cuddAddMonadicApplyRecur(dd,op,ft);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+
+ E = cuddAddMonadicApplyRecur(dd,op,fe);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd,T);
+ return(NULL);
+ }
+ cuddRef(E);
+
+ res = (T == E) ? T : cuddUniqueInter(dd,(int)index,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+
+ /* Store result. */
+ cuddCacheInsert1(dd,op,f,res);
+
+ return(res);
+
+} /* end of cuddAddMonadicApplyRecur */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/cudd/cuddAddFind.c b/src/bdd/cudd/cuddAddFind.c
new file mode 100644
index 00000000..3399527a
--- /dev/null
+++ b/src/bdd/cudd/cuddAddFind.c
@@ -0,0 +1,283 @@
+/**CFile***********************************************************************
+
+ FileName [cuddAddFind.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions to find maximum and minimum in an ADD and to
+ extract the i-th bit.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_addFindMax()
+ <li> Cudd_addFindMin()
+ <li> Cudd_addIthBit()
+ </ul>
+ Static functions included in this module:
+ <ul>
+ <li> addDoIthBit()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddAddFind.c,v 1.1.1.1 2003/02/24 22:23:50 wjiang Exp $";
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdNode * addDoIthBit ARGS((DdManager *dd, DdNode *f, DdNode *index));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Finds the maximum discriminant of f.]
+
+ Description [Returns a pointer to a constant ADD.]
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+Cudd_addFindMax(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode *t, *e, *res;
+
+ statLine(dd);
+ if (cuddIsConstant(f)) {
+ return(f);
+ }
+
+ res = cuddCacheLookup1(dd,Cudd_addFindMax,f);
+ if (res != NULL) {
+ return(res);
+ }
+
+ t = Cudd_addFindMax(dd,cuddT(f));
+ if (t == DD_PLUS_INFINITY(dd)) return(t);
+
+ e = Cudd_addFindMax(dd,cuddE(f));
+
+ res = (cuddV(t) >= cuddV(e)) ? t : e;
+
+ cuddCacheInsert1(dd,Cudd_addFindMax,f,res);
+
+ return(res);
+
+} /* end of Cudd_addFindMax */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the minimum discriminant of f.]
+
+ Description [Returns a pointer to a constant ADD.]
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+Cudd_addFindMin(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode *t, *e, *res;
+
+ statLine(dd);
+ if (cuddIsConstant(f)) {
+ return(f);
+ }
+
+ res = cuddCacheLookup1(dd,Cudd_addFindMin,f);
+ if (res != NULL) {
+ return(res);
+ }
+
+ t = Cudd_addFindMin(dd,cuddT(f));
+ if (t == DD_MINUS_INFINITY(dd)) return(t);
+
+ e = Cudd_addFindMin(dd,cuddE(f));
+
+ res = (cuddV(t) <= cuddV(e)) ? t : e;
+
+ cuddCacheInsert1(dd,Cudd_addFindMin,f,res);
+
+ return(res);
+
+} /* end of Cudd_addFindMin */
+
+
+/**Function********************************************************************
+
+ Synopsis [Extracts the i-th bit from an ADD.]
+
+ Description [Produces an ADD from another ADD by replacing all
+ discriminants whose i-th bit is equal to 1 with 1, and all other
+ discriminants with 0. The i-th bit refers to the integer
+ representation of the leaf value. If the value is has a fractional
+ part, it is ignored. Repeated calls to this procedure allow one to
+ transform an integer-valued ADD into an array of ADDs, one for each
+ bit of the leaf values. Returns a pointer to the resulting ADD if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addBddIthBit]
+
+******************************************************************************/
+DdNode *
+Cudd_addIthBit(
+ DdManager * dd,
+ DdNode * f,
+ int bit)
+{
+ DdNode *res;
+ DdNode *index;
+
+ /* Use a constant node to remember the bit, so that we can use the
+ ** global cache.
+ */
+ index = cuddUniqueConst(dd,(CUDD_VALUE_TYPE) bit);
+ if (index == NULL) return(NULL);
+ cuddRef(index);
+
+ do {
+ dd->reordered = 0;
+ res = addDoIthBit(dd, f, index);
+ } while (dd->reordered == 1);
+
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, index);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, index);
+ cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_addIthBit */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step for Cudd_addIthBit.]
+
+ Description [Performs the recursive step for Cudd_addIthBit.
+ Returns a pointer to the BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+addDoIthBit(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * index)
+{
+ DdNode *res, *T, *E;
+ DdNode *fv, *fvn;
+ int mask, value;
+ int v;
+
+ statLine(dd);
+ /* Check terminal case. */
+ if (cuddIsConstant(f)) {
+ mask = 1 << ((int) cuddV(index));
+ value = (int) cuddV(f);
+ return((value & mask) == 0 ? DD_ZERO(dd) : DD_ONE(dd));
+ }
+
+ /* Check cache. */
+ res = cuddCacheLookup2(dd,addDoIthBit,f,index);
+ if (res != NULL) return(res);
+
+ /* Recursive step. */
+ v = f->index;
+ fv = cuddT(f); fvn = cuddE(f);
+
+ T = addDoIthBit(dd,fv,index);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+
+ E = addDoIthBit(dd,fvn,index);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ return(NULL);
+ }
+ cuddRef(E);
+
+ res = (T == E) ? T : cuddUniqueInter(dd,v,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+
+ /* Store result. */
+ cuddCacheInsert2(dd,addDoIthBit,f,index,res);
+
+ return(res);
+
+} /* end of addDoIthBit */
+
diff --git a/src/bdd/cudd/cuddAddInv.c b/src/bdd/cudd/cuddAddInv.c
new file mode 100644
index 00000000..cb6dbfbe
--- /dev/null
+++ b/src/bdd/cudd/cuddAddInv.c
@@ -0,0 +1,172 @@
+/**CFile***********************************************************************
+
+ FileName [cuddAddInv.c]
+
+ PackageName [cudd]
+
+ Synopsis [Function to compute the scalar inverse of an ADD.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_addScalarInverse()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddAddScalarInverseRecur()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddAddInv.c,v 1.1.1.1 2003/02/24 22:23:50 wjiang Exp $";
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the scalar inverse of an ADD.]
+
+ Description [Computes an n ADD where the discriminants are the
+ multiplicative inverses of the corresponding discriminants of the
+ argument ADD. Returns a pointer to the resulting ADD in case of
+ success. Returns NULL if any discriminants smaller than epsilon is
+ encountered.]
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+Cudd_addScalarInverse(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * epsilon)
+{
+ DdNode *res;
+
+ if (!cuddIsConstant(epsilon)) {
+ (void) fprintf(dd->err,"Invalid epsilon\n");
+ return(NULL);
+ }
+ do {
+ dd->reordered = 0;
+ res = cuddAddScalarInverseRecur(dd,f,epsilon);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addScalarInverse */
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of addScalarInverse.]
+
+ Description [Returns a pointer to the resulting ADD in case of
+ success. Returns NULL if any discriminants smaller than epsilon is
+ encountered.]
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+cuddAddScalarInverseRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * epsilon)
+{
+ DdNode *t, *e, *res;
+ CUDD_VALUE_TYPE value;
+
+ statLine(dd);
+ if (cuddIsConstant(f)) {
+ if (ddAbs(cuddV(f)) < cuddV(epsilon)) return(NULL);
+ value = 1.0 / cuddV(f);
+ res = cuddUniqueConst(dd,value);
+ return(res);
+ }
+
+ res = cuddCacheLookup2(dd,Cudd_addScalarInverse,f,epsilon);
+ if (res != NULL) return(res);
+
+ t = cuddAddScalarInverseRecur(dd,cuddT(f),epsilon);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+
+ e = cuddAddScalarInverseRecur(dd,cuddE(f),epsilon);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ res = (t == e) ? t : cuddUniqueInter(dd,(int)f->index,t,e);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ Cudd_RecursiveDeref(dd, e);
+ return(NULL);
+ }
+
+ cuddCacheInsert2(dd,Cudd_addScalarInverse,f,epsilon,res);
+
+ return(res);
+
+} /* end of cuddAddScalarInverseRecur */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/cudd/cuddAddIte.c b/src/bdd/cudd/cuddAddIte.c
new file mode 100644
index 00000000..77c4d18a
--- /dev/null
+++ b/src/bdd/cudd/cuddAddIte.c
@@ -0,0 +1,613 @@
+/**CFile***********************************************************************
+
+ FileName [cuddAddIte.c]
+
+ PackageName [cudd]
+
+ Synopsis [ADD ITE function and satellites.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_addIte()
+ <li> Cudd_addIteConstant()
+ <li> Cudd_addEvalConst()
+ <li> Cudd_addCmpl()
+ <li> Cudd_addLeq()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddAddIteRecur()
+ <li> cuddAddCmplRecur()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> addVarToConst()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddAddIte.c,v 1.1.1.1 2003/02/24 22:23:50 wjiang Exp $";
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static void addVarToConst ARGS((DdNode *f, DdNode **gp, DdNode **hp, DdNode *one, DdNode *zero));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements ITE(f,g,h).]
+
+ Description [Implements ITE(f,g,h). This procedure assumes that f is
+ a 0-1 ADD. Returns a pointer to the resulting ADD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIte Cudd_addIteConstant Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addIte(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddAddIteRecur(dd,f,g,h);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addIte */
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements ITEconstant for ADDs.]
+
+ Description [Implements ITEconstant for ADDs. f must be a 0-1 ADD.
+ Returns a pointer to the resulting ADD (which may or may not be
+ constant) or DD_NON_CONSTANT. No new nodes are created. This function
+ can be used, for instance, to check that g has a constant value
+ (specified by h) whenever f is 1. If the constant value is unknown,
+ then one should use Cudd_addEvalConst.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addIte Cudd_addEvalConst Cudd_bddIteConstant]
+
+******************************************************************************/
+DdNode *
+Cudd_addIteConstant(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ DdNode *one,*zero;
+ DdNode *Fv,*Fnv,*Gv,*Gnv,*Hv,*Hnv,*r,*t,*e;
+ unsigned int topf,topg,toph,v;
+
+ statLine(dd);
+ /* Trivial cases. */
+ if (f == (one = DD_ONE(dd))) { /* ITE(1,G,H) = G */
+ return(g);
+ }
+ if (f == (zero = DD_ZERO(dd))) { /* ITE(0,G,H) = H */
+ return(h);
+ }
+
+ /* From now on, f is known not to be a constant. */
+ addVarToConst(f,&g,&h,one,zero);
+
+ /* Check remaining one variable cases. */
+ if (g == h) { /* ITE(F,G,G) = G */
+ return(g);
+ }
+ if (cuddIsConstant(g) && cuddIsConstant(h)) {
+ return(DD_NON_CONSTANT);
+ }
+
+ topf = cuddI(dd,f->index);
+ topg = cuddI(dd,g->index);
+ toph = cuddI(dd,h->index);
+ v = ddMin(topg,toph);
+
+ /* ITE(F,G,H) = (x,G,H) (non constant) if F = (x,1,0), x < top(G,H). */
+ if (topf < v && cuddIsConstant(cuddT(f)) && cuddIsConstant(cuddE(f))) {
+ return(DD_NON_CONSTANT);
+ }
+
+ /* Check cache. */
+ r = cuddConstantLookup(dd,DD_ADD_ITE_CONSTANT_TAG,f,g,h);
+ if (r != NULL) {
+ return(r);
+ }
+
+ /* Compute cofactors. */
+ if (topf <= v) {
+ v = ddMin(topf,v); /* v = top_var(F,G,H) */
+ Fv = cuddT(f); Fnv = cuddE(f);
+ } else {
+ Fv = Fnv = f;
+ }
+ if (topg == v) {
+ Gv = cuddT(g); Gnv = cuddE(g);
+ } else {
+ Gv = Gnv = g;
+ }
+ if (toph == v) {
+ Hv = cuddT(h); Hnv = cuddE(h);
+ } else {
+ Hv = Hnv = h;
+ }
+
+ /* Recursive step. */
+ t = Cudd_addIteConstant(dd,Fv,Gv,Hv);
+ if (t == DD_NON_CONSTANT || !cuddIsConstant(t)) {
+ cuddCacheInsert(dd, DD_ADD_ITE_CONSTANT_TAG, f, g, h, DD_NON_CONSTANT);
+ return(DD_NON_CONSTANT);
+ }
+ e = Cudd_addIteConstant(dd,Fnv,Gnv,Hnv);
+ if (e == DD_NON_CONSTANT || !cuddIsConstant(e) || t != e) {
+ cuddCacheInsert(dd, DD_ADD_ITE_CONSTANT_TAG, f, g, h, DD_NON_CONSTANT);
+ return(DD_NON_CONSTANT);
+ }
+ cuddCacheInsert(dd, DD_ADD_ITE_CONSTANT_TAG, f, g, h, t);
+ return(t);
+
+} /* end of Cudd_addIteConstant */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether ADD g is constant whenever ADD f is 1.]
+
+ Description [Checks whether ADD g is constant whenever ADD f is 1. f
+ must be a 0-1 ADD. Returns a pointer to the resulting ADD (which may
+ or may not be constant) or DD_NON_CONSTANT. If f is identically 0,
+ the check is assumed to be successful, and the background value is
+ returned. No new nodes are created.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addIteConstant Cudd_addLeq]
+
+******************************************************************************/
+DdNode *
+Cudd_addEvalConst(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *zero;
+ DdNode *Fv,*Fnv,*Gv,*Gnv,*r,*t,*e;
+ unsigned int topf,topg;
+
+#ifdef DD_DEBUG
+ assert(!Cudd_IsComplement(f));
+#endif
+
+ statLine(dd);
+ /* Terminal cases. */
+ if (f == DD_ONE(dd) || cuddIsConstant(g)) {
+ return(g);
+ }
+ if (f == (zero = DD_ZERO(dd))) {
+ return(dd->background);
+ }
+
+#ifdef DD_DEBUG
+ assert(!cuddIsConstant(f));
+#endif
+ /* From now on, f and g are known not to be constants. */
+
+ topf = cuddI(dd,f->index);
+ topg = cuddI(dd,g->index);
+
+ /* Check cache. */
+ r = cuddConstantLookup(dd,DD_ADD_EVAL_CONST_TAG,f,g,g);
+ if (r != NULL) {
+ return(r);
+ }
+
+ /* Compute cofactors. */
+ if (topf <= topg) {
+ Fv = cuddT(f); Fnv = cuddE(f);
+ } else {
+ Fv = Fnv = f;
+ }
+ if (topg <= topf) {
+ Gv = cuddT(g); Gnv = cuddE(g);
+ } else {
+ Gv = Gnv = g;
+ }
+
+ /* Recursive step. */
+ if (Fv != zero) {
+ t = Cudd_addEvalConst(dd,Fv,Gv);
+ if (t == DD_NON_CONSTANT || !cuddIsConstant(t)) {
+ cuddCacheInsert2(dd, Cudd_addEvalConst, f, g, DD_NON_CONSTANT);
+ return(DD_NON_CONSTANT);
+ }
+ if (Fnv != zero) {
+ e = Cudd_addEvalConst(dd,Fnv,Gnv);
+ if (e == DD_NON_CONSTANT || !cuddIsConstant(e) || t != e) {
+ cuddCacheInsert2(dd, Cudd_addEvalConst, f, g, DD_NON_CONSTANT);
+ return(DD_NON_CONSTANT);
+ }
+ }
+ cuddCacheInsert2(dd,Cudd_addEvalConst,f,g,t);
+ return(t);
+ } else { /* Fnv must be != zero */
+ e = Cudd_addEvalConst(dd,Fnv,Gnv);
+ cuddCacheInsert2(dd, Cudd_addEvalConst, f, g, e);
+ return(e);
+ }
+
+} /* end of Cudd_addEvalConst */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the complement of an ADD a la C language.]
+
+ Description [Computes the complement of an ADD a la C language: The
+ complement of 0 is 1 and the complement of everything else is 0.
+ Returns a pointer to the resulting ADD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addNegate]
+
+******************************************************************************/
+DdNode *
+Cudd_addCmpl(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddAddCmplRecur(dd,f);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addCmpl */
+
+
+/**Function********************************************************************
+
+ Synopsis [Determines whether f is less than or equal to g.]
+
+ Description [Returns 1 if f is less than or equal to g; 0 otherwise.
+ No new nodes are created. This procedure works for arbitrary ADDs.
+ For 0-1 ADDs Cudd_addEvalConst is more efficient.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addIteConstant Cudd_addEvalConst Cudd_bddLeq]
+
+******************************************************************************/
+int
+Cudd_addLeq(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *tmp, *fv, *fvn, *gv, *gvn;
+ unsigned int topf, topg, res;
+
+ /* Terminal cases. */
+ if (f == g) return(1);
+
+ statLine(dd);
+ if (cuddIsConstant(f)) {
+ if (cuddIsConstant(g)) return(cuddV(f) <= cuddV(g));
+ if (f == DD_MINUS_INFINITY(dd)) return(1);
+ if (f == DD_PLUS_INFINITY(dd)) return(0); /* since f != g */
+ }
+ if (g == DD_PLUS_INFINITY(dd)) return(1);
+ if (g == DD_MINUS_INFINITY(dd)) return(0); /* since f != g */
+
+ /* Check cache. */
+ tmp = cuddCacheLookup2(dd,(DdNode * (*)(DdManager *, DdNode *,
+ DdNode *))Cudd_addLeq,f,g);
+ if (tmp != NULL) {
+ return(tmp == DD_ONE(dd));
+ }
+
+ /* Compute cofactors. One of f and g is not constant. */
+ topf = cuddI(dd,f->index);
+ topg = cuddI(dd,g->index);
+ if (topf <= topg) {
+ fv = cuddT(f); fvn = cuddE(f);
+ } else {
+ fv = fvn = f;
+ }
+ if (topg <= topf) {
+ gv = cuddT(g); gvn = cuddE(g);
+ } else {
+ gv = gvn = g;
+ }
+
+ res = Cudd_addLeq(dd,fvn,gvn) && Cudd_addLeq(dd,fv,gv);
+
+ /* Store result in cache and return. */
+ cuddCacheInsert2(dd,(DdNode * (*)(DdManager *, DdNode *, DdNode *))
+ Cudd_addLeq,f,g,Cudd_NotCond(DD_ONE(dd),res==0));
+ return(res);
+
+} /* end of Cudd_addLeq */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_addIte(f,g,h).]
+
+ Description [Implements the recursive step of Cudd_addIte(f,g,h).
+ Returns a pointer to the resulting ADD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addIte]
+
+******************************************************************************/
+DdNode *
+cuddAddIteRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ DdNode *one,*zero;
+ DdNode *r,*Fv,*Fnv,*Gv,*Gnv,*Hv,*Hnv,*t,*e;
+ unsigned int topf,topg,toph,v;
+ int index;
+
+ statLine(dd);
+ /* Trivial cases. */
+
+ /* One variable cases. */
+ if (f == (one = DD_ONE(dd))) { /* ITE(1,G,H) = G */
+ return(g);
+ }
+ if (f == (zero = DD_ZERO(dd))) { /* ITE(0,G,H) = H */
+ return(h);
+ }
+
+ /* From now on, f is known to not be a constant. */
+ addVarToConst(f,&g,&h,one,zero);
+
+ /* Check remaining one variable cases. */
+ if (g == h) { /* ITE(F,G,G) = G */
+ return(g);
+ }
+
+ if (g == one) { /* ITE(F,1,0) = F */
+ if (h == zero) return(f);
+ }
+
+ topf = cuddI(dd,f->index);
+ topg = cuddI(dd,g->index);
+ toph = cuddI(dd,h->index);
+ v = ddMin(topg,toph);
+
+ /* A shortcut: ITE(F,G,H) = (x,G,H) if F=(x,1,0), x < top(G,H). */
+ if (topf < v && cuddT(f) == one && cuddE(f) == zero) {
+ r = cuddUniqueInter(dd,(int)f->index,g,h);
+ return(r);
+ }
+ if (topf < v && cuddT(f) == zero && cuddE(f) == one) {
+ r = cuddUniqueInter(dd,(int)f->index,h,g);
+ return(r);
+ }
+
+ /* Check cache. */
+ r = cuddCacheLookup(dd,DD_ADD_ITE_TAG,f,g,h);
+ if (r != NULL) {
+ return(r);
+ }
+
+ /* Compute cofactors. */
+ if (topf <= v) {
+ v = ddMin(topf,v); /* v = top_var(F,G,H) */
+ index = f->index;
+ Fv = cuddT(f); Fnv = cuddE(f);
+ } else {
+ Fv = Fnv = f;
+ }
+ if (topg == v) {
+ index = g->index;
+ Gv = cuddT(g); Gnv = cuddE(g);
+ } else {
+ Gv = Gnv = g;
+ }
+ if (toph == v) {
+ index = h->index;
+ Hv = cuddT(h); Hnv = cuddE(h);
+ } else {
+ Hv = Hnv = h;
+ }
+
+ /* Recursive step. */
+ t = cuddAddIteRecur(dd,Fv,Gv,Hv);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+
+ e = cuddAddIteRecur(dd,Fnv,Gnv,Hnv);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd,t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ r = (t == e) ? t : cuddUniqueInter(dd,index,t,e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd,t);
+ Cudd_RecursiveDeref(dd,e);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ cuddCacheInsert(dd,DD_ADD_ITE_TAG,f,g,h,r);
+
+ return(r);
+
+} /* end of cuddAddIteRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addCmpl.]
+
+ Description [Performs the recursive step of Cudd_addCmpl. Returns a
+ pointer to the resulting ADD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addCmpl]
+
+******************************************************************************/
+DdNode *
+cuddAddCmplRecur(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode *one,*zero;
+ DdNode *r,*Fv,*Fnv,*t,*e;
+
+ statLine(dd);
+ one = DD_ONE(dd);
+ zero = DD_ZERO(dd);
+
+ if (cuddIsConstant(f)) {
+ if (f == zero) {
+ return(one);
+ } else {
+ return(zero);
+ }
+ }
+ r = cuddCacheLookup1(dd,Cudd_addCmpl,f);
+ if (r != NULL) {
+ return(r);
+ }
+ Fv = cuddT(f);
+ Fnv = cuddE(f);
+ t = cuddAddCmplRecur(dd,Fv);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = cuddAddCmplRecur(dd,Fnv);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd,t);
+ return(NULL);
+ }
+ cuddRef(e);
+ r = (t == e) ? t : cuddUniqueInter(dd,(int)f->index,t,e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ Cudd_RecursiveDeref(dd, e);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+ cuddCacheInsert1(dd,Cudd_addCmpl,f,r);
+ return(r);
+
+} /* end of cuddAddCmplRecur */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Replaces variables with constants if possible (part of
+ canonical form).]
+
+ Description []
+
+ SideEffects [None]
+
+******************************************************************************/
+static void
+addVarToConst(
+ DdNode * f,
+ DdNode ** gp,
+ DdNode ** hp,
+ DdNode * one,
+ DdNode * zero)
+{
+ DdNode *g = *gp;
+ DdNode *h = *hp;
+
+ if (f == g) { /* ITE(F,F,H) = ITE(F,1,H) = F + H */
+ *gp = one;
+ }
+
+ if (f == h) { /* ITE(F,G,F) = ITE(F,G,0) = F * G */
+ *hp = zero;
+ }
+
+} /* end of addVarToConst */
diff --git a/src/bdd/cudd/cuddAddNeg.c b/src/bdd/cudd/cuddAddNeg.c
new file mode 100644
index 00000000..2420df64
--- /dev/null
+++ b/src/bdd/cudd/cuddAddNeg.c
@@ -0,0 +1,262 @@
+/**CFile***********************************************************************
+
+ FileName [cuddAddNeg.c]
+
+ PackageName [cudd]
+
+ Synopsis [function to compute the negation of an ADD.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_addNegate()
+ <li> Cudd_addRoundOff()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddAddNegateRecur()
+ <li> cuddAddRoundOffRecur()
+ </ul> ]
+
+ Author [Fabio Somenzi, Balakrishna Kumthekar]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddAddNeg.c,v 1.1.1.1 2003/02/24 22:23:50 wjiang Exp $";
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Computes the additive inverse of an ADD.]
+
+ Description [Computes the additive inverse of an ADD. Returns a pointer
+ to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addCmpl]
+
+******************************************************************************/
+DdNode *
+Cudd_addNegate(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode *res;
+
+ do {
+ res = cuddAddNegateRecur(dd,f);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addNegate */
+
+
+/**Function********************************************************************
+
+ Synopsis [Rounds off the discriminants of an ADD.]
+
+ Description [Rounds off the discriminants of an ADD. The discriminants are
+ rounded off to N digits after the decimal. Returns a pointer to the result
+ ADD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_addRoundOff(
+ DdManager * dd,
+ DdNode * f,
+ int N)
+{
+ DdNode *res;
+ double trunc = pow(10.0,(double)N);
+
+ do {
+ res = cuddAddRoundOffRecur(dd,f,trunc);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addRoundOff */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_addNegate.]
+
+ Description [Implements the recursive step of Cudd_addNegate.
+ Returns a pointer to the result.]
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+cuddAddNegateRecur(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode *res,
+ *fv, *fvn,
+ *T, *E;
+
+ statLine(dd);
+ /* Check terminal cases. */
+ if (cuddIsConstant(f)) {
+ res = cuddUniqueConst(dd,-cuddV(f));
+ return(res);
+ }
+
+ /* Check cache */
+ res = cuddCacheLookup1(dd,Cudd_addNegate,f);
+ if (res != NULL) return(res);
+
+ /* Recursive Step */
+ fv = cuddT(f);
+ fvn = cuddE(f);
+ T = cuddAddNegateRecur(dd,fv);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+
+ E = cuddAddNegateRecur(dd,fvn);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd,T);
+ return(NULL);
+ }
+ cuddRef(E);
+ res = (T == E) ? T : cuddUniqueInter(dd,(int)f->index,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+
+ /* Store result. */
+ cuddCacheInsert1(dd,Cudd_addNegate,f,res);
+
+ return(res);
+
+} /* end of cuddAddNegateRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_addRoundOff.]
+
+ Description [Implements the recursive step of Cudd_addRoundOff.
+ Returns a pointer to the result.]
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+cuddAddRoundOffRecur(
+ DdManager * dd,
+ DdNode * f,
+ double trunc)
+{
+
+ DdNode *res, *fv, *fvn, *T, *E;
+ double n;
+ DdNode *(*cacheOp)(DdManager *, DdNode *);
+
+ statLine(dd);
+ if (cuddIsConstant(f)) {
+ n = ceil(cuddV(f)*trunc)/trunc;
+ res = cuddUniqueConst(dd,n);
+ return(res);
+ }
+ cacheOp = (DdNode *(*)(DdManager *, DdNode *)) Cudd_addRoundOff;
+ res = cuddCacheLookup1(dd,cacheOp,f);
+ if (res != NULL) {
+ return(res);
+ }
+ /* Recursive Step */
+ fv = cuddT(f);
+ fvn = cuddE(f);
+ T = cuddAddRoundOffRecur(dd,fv,trunc);
+ if (T == NULL) {
+ return(NULL);
+ }
+ cuddRef(T);
+ E = cuddAddRoundOffRecur(dd,fvn,trunc);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd,T);
+ return(NULL);
+ }
+ cuddRef(E);
+ res = (T == E) ? T : cuddUniqueInter(dd,(int)f->index,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,T);
+ Cudd_RecursiveDeref(dd,E);
+ return(NULL);
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+
+ /* Store result. */
+ cuddCacheInsert1(dd,cacheOp,f,res);
+ return(res);
+
+} /* end of cuddAddRoundOffRecur */
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/cudd/cuddAddWalsh.c b/src/bdd/cudd/cuddAddWalsh.c
new file mode 100644
index 00000000..980ee215
--- /dev/null
+++ b/src/bdd/cudd/cuddAddWalsh.c
@@ -0,0 +1,364 @@
+/**CFile***********************************************************************
+
+ FileName [cuddAddWalsh.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions that generate Walsh matrices and residue
+ functions in ADD form.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_addWalsh()
+ <li> Cudd_addResidue()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> addWalshInt()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddAddWalsh.c,v 1.1.1.1 2003/02/24 22:23:50 wjiang Exp $";
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdNode * addWalshInt ARGS((DdManager *dd, DdNode **x, DdNode **y, int n));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Generates a Walsh matrix in ADD form.]
+
+ Description [Generates a Walsh matrix in ADD form. Returns a pointer
+ to the matrixi if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+Cudd_addWalsh(
+ DdManager * dd,
+ DdNode ** x,
+ DdNode ** y,
+ int n)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = addWalshInt(dd, x, y, n);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addWalsh */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds an ADD for the residue modulo m of an n-bit
+ number.]
+
+ Description [Builds an ADD for the residue modulo m of an n-bit
+ number. The modulus must be at least 2, and the number of bits at
+ least 1. Parameter options specifies whether the MSB should be on top
+ or the LSB; and whther the number whose residue is computed is in
+ two's complement notation or not. The macro CUDD_RESIDUE_DEFAULT
+ specifies LSB on top and unsigned number. The macro CUDD_RESIDUE_MSB
+ specifies MSB on top, and the macro CUDD_RESIDUE_TC specifies two's
+ complement residue. To request MSB on top and two's complement residue
+ simultaneously, one can OR the two macros:
+ CUDD_RESIDUE_MSB | CUDD_RESIDUE_TC.
+ Cudd_addResidue returns a pointer to the resulting ADD if successful;
+ NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_addResidue(
+ DdManager * dd /* manager */,
+ int n /* number of bits */,
+ int m /* modulus */,
+ int options /* options */,
+ int top /* index of top variable */)
+{
+ int msbLsb; /* MSB on top (1) or LSB on top (0) */
+ int tc; /* two's complement (1) or unsigned (0) */
+ int i, j, k, t, residue, thisOne, previous, index;
+ DdNode **array[2], *var, *tmp, *res;
+
+ /* Sanity check. */
+ if (n < 1 && m < 2) return(NULL);
+
+ msbLsb = options & CUDD_RESIDUE_MSB;
+ tc = options & CUDD_RESIDUE_TC;
+
+ /* Allocate and initialize working arrays. */
+ array[0] = ALLOC(DdNode *,m);
+ if (array[0] == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ array[1] = ALLOC(DdNode *,m);
+ if (array[1] == NULL) {
+ FREE(array[0]);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < m; i++) {
+ array[0][i] = array[1][i] = NULL;
+ }
+
+ /* Initialize residues. */
+ for (i = 0; i < m; i++) {
+ tmp = cuddUniqueConst(dd,(CUDD_VALUE_TYPE) i);
+ if (tmp == NULL) {
+ for (j = 0; j < i; j++) {
+ Cudd_RecursiveDeref(dd,array[1][j]);
+ }
+ FREE(array[0]);
+ FREE(array[1]);
+ return(NULL);
+ }
+ cuddRef(tmp);
+ array[1][i] = tmp;
+ }
+
+ /* Main iteration. */
+ residue = 1; /* residue of 2**0 */
+ for (k = 0; k < n; k++) {
+ /* Choose current and previous arrays. */
+ thisOne = k & 1;
+ previous = thisOne ^ 1;
+ /* Build an ADD projection function. */
+ if (msbLsb) {
+ index = top+n-k-1;
+ } else {
+ index = top+k;
+ }
+ var = cuddUniqueInter(dd,index,DD_ONE(dd),DD_ZERO(dd));
+ if (var == NULL) {
+ for (j = 0; j < m; j++) {
+ Cudd_RecursiveDeref(dd,array[previous][j]);
+ }
+ FREE(array[0]);
+ FREE(array[1]);
+ return(NULL);
+ }
+ cuddRef(var);
+ for (i = 0; i < m; i ++) {
+ t = (i + residue) % m;
+ tmp = Cudd_addIte(dd,var,array[previous][t],array[previous][i]);
+ if (tmp == NULL) {
+ for (j = 0; j < i; j++) {
+ Cudd_RecursiveDeref(dd,array[thisOne][j]);
+ }
+ for (j = 0; j < m; j++) {
+ Cudd_RecursiveDeref(dd,array[previous][j]);
+ }
+ FREE(array[0]);
+ FREE(array[1]);
+ return(NULL);
+ }
+ cuddRef(tmp);
+ array[thisOne][i] = tmp;
+ }
+ /* One layer completed. Free the other array for the next iteration. */
+ for (i = 0; i < m; i++) {
+ Cudd_RecursiveDeref(dd,array[previous][i]);
+ }
+ Cudd_RecursiveDeref(dd,var);
+ /* Update residue of 2**k. */
+ residue = (2 * residue) % m;
+ /* Adjust residue for MSB, if this is a two's complement number. */
+ if (tc && (k == n - 1)) {
+ residue = (m - residue) % m;
+ }
+ }
+
+ /* We are only interested in the 0-residue node of the top layer. */
+ for (i = 1; i < m; i++) {
+ Cudd_RecursiveDeref(dd,array[(n - 1) & 1][i]);
+ }
+ res = array[(n - 1) & 1][0];
+
+ FREE(array[0]);
+ FREE(array[1]);
+
+ cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_addResidue */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_addWalsh.]
+
+ Description [Generates a Walsh matrix in ADD form. Returns a pointer
+ to the matrixi if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static DdNode *
+addWalshInt(
+ DdManager * dd,
+ DdNode ** x,
+ DdNode ** y,
+ int n)
+{
+ DdNode *one, *minusone;
+ DdNode *t, *u, *t1, *u1, *v, *w;
+ int i;
+
+ one = DD_ONE(dd);
+ if (n == 0) return(one);
+
+ /* Build bottom part of ADD outside loop */
+ minusone = cuddUniqueConst(dd,(CUDD_VALUE_TYPE) -1);
+ if (minusone == NULL) return(NULL);
+ cuddRef(minusone);
+ v = Cudd_addIte(dd, y[n-1], minusone, one);
+ if (v == NULL) {
+ Cudd_RecursiveDeref(dd, minusone);
+ return(NULL);
+ }
+ cuddRef(v);
+ u = Cudd_addIte(dd, x[n-1], v, one);
+ if (u == NULL) {
+ Cudd_RecursiveDeref(dd, minusone);
+ Cudd_RecursiveDeref(dd, v);
+ return(NULL);
+ }
+ cuddRef(u);
+ Cudd_RecursiveDeref(dd, v);
+ if (n>1) {
+ w = Cudd_addIte(dd, y[n-1], one, minusone);
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, minusone);
+ Cudd_RecursiveDeref(dd, u);
+ return(NULL);
+ }
+ cuddRef(w);
+ t = Cudd_addIte(dd, x[n-1], w, minusone);
+ if (t == NULL) {
+ Cudd_RecursiveDeref(dd, minusone);
+ Cudd_RecursiveDeref(dd, u);
+ Cudd_RecursiveDeref(dd, w);
+ return(NULL);
+ }
+ cuddRef(t);
+ Cudd_RecursiveDeref(dd, w);
+ }
+ cuddDeref(minusone); /* minusone is in the result; it won't die */
+
+ /* Loop to build the rest of the ADD */
+ for (i=n-2; i>=0; i--) {
+ t1 = t; u1 = u;
+ v = Cudd_addIte(dd, y[i], t1, u1);
+ if (v == NULL) {
+ Cudd_RecursiveDeref(dd, u1);
+ Cudd_RecursiveDeref(dd, t1);
+ return(NULL);
+ }
+ cuddRef(v);
+ u = Cudd_addIte(dd, x[i], v, u1);
+ if (u == NULL) {
+ Cudd_RecursiveDeref(dd, u1);
+ Cudd_RecursiveDeref(dd, t1);
+ Cudd_RecursiveDeref(dd, v);
+ return(NULL);
+ }
+ cuddRef(u);
+ Cudd_RecursiveDeref(dd, v);
+ if (i>0) {
+ w = Cudd_addIte(dd, y[i], u1, t1);
+ if (u == NULL) {
+ Cudd_RecursiveDeref(dd, u1);
+ Cudd_RecursiveDeref(dd, t1);
+ Cudd_RecursiveDeref(dd, u);
+ return(NULL);
+ }
+ cuddRef(w);
+ t = Cudd_addIte(dd, x[i], w, t1);
+ if (u == NULL) {
+ Cudd_RecursiveDeref(dd, u1);
+ Cudd_RecursiveDeref(dd, t1);
+ Cudd_RecursiveDeref(dd, u);
+ Cudd_RecursiveDeref(dd, w);
+ return(NULL);
+ }
+ cuddRef(t);
+ Cudd_RecursiveDeref(dd, w);
+ }
+ Cudd_RecursiveDeref(dd, u1);
+ Cudd_RecursiveDeref(dd, t1);
+ }
+
+ cuddDeref(u);
+ return(u);
+
+} /* end of addWalshInt */
diff --git a/src/bdd/cudd/cuddAndAbs.c b/src/bdd/cudd/cuddAndAbs.c
new file mode 100644
index 00000000..3a6ce85f
--- /dev/null
+++ b/src/bdd/cudd/cuddAndAbs.c
@@ -0,0 +1,306 @@
+/**CFile***********************************************************************
+
+ FileName [cuddAndAbs.c]
+
+ PackageName [cudd]
+
+ Synopsis [Combined AND and existential abstraction for BDDs]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_bddAndAbstract()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddBddAndAbstractRecur()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddAndAbs.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Takes the AND of two BDDs and simultaneously abstracts the
+ variables in cube.]
+
+ Description [Takes the AND of two BDDs and simultaneously abstracts
+ the variables in cube. The variables are existentially abstracted.
+ Returns a pointer to the result is successful; NULL otherwise.
+ Cudd_bddAndAbstract implements the semiring matrix multiplication
+ algorithm for the boolean semiring.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addMatrixMultiply Cudd_addTriangle Cudd_bddAnd]
+
+******************************************************************************/
+DdNode *
+Cudd_bddAndAbstract(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * g,
+ DdNode * cube)
+{
+ DdNode *res;
+
+ do {
+ manager->reordered = 0;
+ res = cuddBddAndAbstractRecur(manager, f, g, cube);
+ } while (manager->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddAndAbstract */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Takes the AND of two BDDs and simultaneously abstracts the
+ variables in cube.]
+
+ Description [Takes the AND of two BDDs and simultaneously abstracts
+ the variables in cube. The variables are existentially abstracted.
+ Returns a pointer to the result is successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddAndAbstract]
+
+******************************************************************************/
+DdNode *
+cuddBddAndAbstractRecur(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * g,
+ DdNode * cube)
+{
+ DdNode *F, *ft, *fe, *G, *gt, *ge;
+ DdNode *one, *zero, *r, *t, *e;
+ unsigned int topf, topg, topcube, top, index;
+
+ statLine(manager);
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ /* Terminal cases. */
+ if (f == zero || g == zero || f == Cudd_Not(g)) return(zero);
+ if (f == one && g == one) return(one);
+
+ if (cube == one) {
+ return(cuddBddAndRecur(manager, f, g));
+ }
+ if (f == one || f == g) {
+ return(cuddBddExistAbstractRecur(manager, g, cube));
+ }
+ if (g == one) {
+ return(cuddBddExistAbstractRecur(manager, f, cube));
+ }
+ /* At this point f, g, and cube are not constant. */
+
+ if (f > g) { /* Try to increase cache efficiency. */
+ DdNode *tmp = f;
+ f = g;
+ g = tmp;
+ }
+
+ /* Here we can skip the use of cuddI, because the operands are known
+ ** to be non-constant.
+ */
+ F = Cudd_Regular(f);
+ G = Cudd_Regular(g);
+ topf = manager->perm[F->index];
+ topg = manager->perm[G->index];
+ top = ddMin(topf, topg);
+ topcube = manager->perm[cube->index];
+
+ while (topcube < top) {
+ cube = cuddT(cube);
+ if (cube == one) {
+ return(cuddBddAndRecur(manager, f, g));
+ }
+ topcube = manager->perm[cube->index];
+ }
+ /* Now, topcube >= top. */
+
+ /* Check cache. */
+ if (F->ref != 1 || G->ref != 1) {
+ r = cuddCacheLookup(manager, DD_BDD_AND_ABSTRACT_TAG, f, g, cube);
+ if (r != NULL) {
+ return(r);
+ }
+ }
+
+ if (topf == top) {
+ index = F->index;
+ ft = cuddT(F);
+ fe = cuddE(F);
+ if (Cudd_IsComplement(f)) {
+ ft = Cudd_Not(ft);
+ fe = Cudd_Not(fe);
+ }
+ } else {
+ index = G->index;
+ ft = fe = f;
+ }
+
+ if (topg == top) {
+ gt = cuddT(G);
+ ge = cuddE(G);
+ if (Cudd_IsComplement(g)) {
+ gt = Cudd_Not(gt);
+ ge = Cudd_Not(ge);
+ }
+ } else {
+ gt = ge = g;
+ }
+
+ if (topcube == top) { /* quantify */
+ DdNode *Cube = cuddT(cube);
+ t = cuddBddAndAbstractRecur(manager, ft, gt, Cube);
+ if (t == NULL) return(NULL);
+ /* Special case: 1 OR anything = 1. Hence, no need to compute
+ ** the else branch if t is 1. Likewise t + t * anything == t.
+ ** Notice that t == fe implies that fe does not depend on the
+ ** variables in Cube. Likewise for t == ge.
+ */
+ if (t == one || t == fe || t == ge) {
+ if (F->ref != 1 || G->ref != 1)
+ cuddCacheInsert(manager, DD_BDD_AND_ABSTRACT_TAG,
+ f, g, cube, t);
+ return(t);
+ }
+ cuddRef(t);
+ /* Special case: t + !t * anything == t + anything. */
+ if (t == Cudd_Not(fe)) {
+ e = cuddBddExistAbstractRecur(manager, ge, Cube);
+ } else if (t == Cudd_Not(ge)) {
+ e = cuddBddExistAbstractRecur(manager, fe, Cube);
+ } else {
+ e = cuddBddAndAbstractRecur(manager, fe, ge, Cube);
+ }
+ if (e == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ return(NULL);
+ }
+ if (t == e) {
+ r = t;
+ cuddDeref(t);
+ } else {
+ cuddRef(e);
+ r = cuddBddAndRecur(manager, Cudd_Not(t), Cudd_Not(e));
+ if (r == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ Cudd_IterDerefBdd(manager, e);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ cuddRef(r);
+ Cudd_DelayedDerefBdd(manager, t);
+ Cudd_DelayedDerefBdd(manager, e);
+ cuddDeref(r);
+ }
+ } else {
+ t = cuddBddAndAbstractRecur(manager, ft, gt, cube);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = cuddBddAndAbstractRecur(manager, fe, ge, cube);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ return(NULL);
+ }
+ if (t == e) {
+ r = t;
+ cuddDeref(t);
+ } else {
+ cuddRef(e);
+ if (Cudd_IsComplement(t)) {
+ r = cuddUniqueInter(manager, (int) index,
+ Cudd_Not(t), Cudd_Not(e));
+ if (r == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ Cudd_IterDerefBdd(manager, e);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = cuddUniqueInter(manager,(int)index,t,e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ Cudd_IterDerefBdd(manager, e);
+ return(NULL);
+ }
+ }
+ cuddDeref(e);
+ cuddDeref(t);
+ }
+ }
+
+ if (F->ref != 1 || G->ref != 1)
+ cuddCacheInsert(manager, DD_BDD_AND_ABSTRACT_TAG, f, g, cube, r);
+ return (r);
+
+} /* end of cuddBddAndAbstractRecur */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/cudd/cuddAnneal.c b/src/bdd/cudd/cuddAnneal.c
new file mode 100644
index 00000000..dfc81e86
--- /dev/null
+++ b/src/bdd/cudd/cuddAnneal.c
@@ -0,0 +1,788 @@
+/**CFile***********************************************************************
+
+ FileName [cuddAnneal.c]
+
+ PackageName [cudd]
+
+ Synopsis [Reordering of DDs based on simulated annealing]
+
+ Description [Internal procedures included in this file:
+ <ul>
+ <li> cuddAnnealing()
+ </ul>
+ Static procedures included in this file:
+ <ul>
+ <li> stopping_criterion()
+ <li> random_generator()
+ <li> ddExchange()
+ <li> ddJumpingAux()
+ <li> ddJumpingUp()
+ <li> ddJumpingDown()
+ <li> siftBackwardProb()
+ <li> copyOrder()
+ <li> restoreOrder()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Jae-Young Jang, Jorgen Sivesind]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/* Annealing parameters */
+#define BETA 0.6
+#define ALPHA 0.90
+#define EXC_PROB 0.4
+#define JUMP_UP_PROB 0.36
+#define MAXGEN_RATIO 15.0
+#define STOP_TEMP 1.0
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddAnneal.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+#ifdef DD_STATS
+extern int ddTotalNumberSwapping;
+extern int ddTotalNISwaps;
+static int tosses;
+static int acceptances;
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int stopping_criterion ARGS((int c1, int c2, int c3, int c4, double temp));
+static double random_generator ARGS(());
+static int ddExchange ARGS((DdManager *table, int x, int y, double temp));
+static int ddJumpingAux ARGS((DdManager *table, int x, int x_low, int x_high, double temp));
+static Move * ddJumpingUp ARGS((DdManager *table, int x, int x_low, int initial_size));
+static Move * ddJumpingDown ARGS((DdManager *table, int x, int x_high, int initial_size));
+static int siftBackwardProb ARGS((DdManager *table, Move *moves, int size, double temp));
+static void copyOrder ARGS((DdManager *table, int *array, int lower, int upper));
+static int restoreOrder ARGS((DdManager *table, int *array, int lower, int upper));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Get new variable-order by simulated annealing algorithm.]
+
+ Description [Get x, y by random selection. Choose either
+ exchange or jump randomly. In case of jump, choose between jump_up
+ and jump_down randomly. Do exchange or jump and get optimal case.
+ Loop until there is no improvement or temperature reaches
+ minimum. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddAnnealing(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int nvars;
+ int size;
+ int x,y;
+ int result;
+ int c1, c2, c3, c4;
+ int BestCost;
+ int *BestOrder;
+ double NewTemp, temp;
+ double rand1;
+ int innerloop, maxGen;
+ int ecount, ucount, dcount;
+
+ nvars = upper - lower + 1;
+
+ result = cuddSifting(table,lower,upper);
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n");
+#endif
+ if (result == 0) return(0);
+
+ size = table->keys - table->isolated;
+
+ /* Keep track of the best order. */
+ BestCost = size;
+ BestOrder = ALLOC(int,nvars);
+ if (BestOrder == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ copyOrder(table,BestOrder,lower,upper);
+
+ temp = BETA * size;
+ maxGen = (int) (MAXGEN_RATIO * nvars);
+
+ c1 = size + 10;
+ c2 = c1 + 10;
+ c3 = size;
+ c4 = c2 + 10;
+ ecount = ucount = dcount = 0;
+
+ while (!stopping_criterion(c1, c2, c3, c4, temp)) {
+#ifdef DD_STATS
+ (void) fprintf(table->out,"temp=%f\tsize=%d\tgen=%d\t",
+ temp,size,maxGen);
+ tosses = acceptances = 0;
+#endif
+ for (innerloop = 0; innerloop < maxGen; innerloop++) {
+ /* Choose x, y randomly. */
+ x = (int) Cudd_Random() % nvars;
+ do {
+ y = (int) Cudd_Random() % nvars;
+ } while (x == y);
+ x += lower;
+ y += lower;
+ if (x > y) {
+ int tmp = x;
+ x = y;
+ y = tmp;
+ }
+
+ /* Choose move with roulette wheel. */
+ rand1 = random_generator();
+ if (rand1 < EXC_PROB) {
+ result = ddExchange(table,x,y,temp); /* exchange */
+ ecount++;
+#if 0
+ (void) fprintf(table->out,
+ "Exchange of %d and %d: size = %d\n",
+ x,y,table->keys - table->isolated);
+#endif
+ } else if (rand1 < EXC_PROB + JUMP_UP_PROB) {
+ result = ddJumpingAux(table,y,x,y,temp); /* jumping_up */
+ ucount++;
+#if 0
+ (void) fprintf(table->out,
+ "Jump up of %d to %d: size = %d\n",
+ y,x,table->keys - table->isolated);
+#endif
+ } else {
+ result = ddJumpingAux(table,x,x,y,temp); /* jumping_down */
+ dcount++;
+#if 0
+ (void) fprintf(table->out,
+ "Jump down of %d to %d: size = %d\n",
+ x,y,table->keys - table->isolated);
+#endif
+ }
+
+ if (!result) {
+ FREE(BestOrder);
+ return(0);
+ }
+
+ size = table->keys - table->isolated; /* keep current size */
+ if (size < BestCost) { /* update best order */
+ BestCost = size;
+ copyOrder(table,BestOrder,lower,upper);
+ }
+ }
+ c1 = c2;
+ c2 = c3;
+ c3 = c4;
+ c4 = size;
+ NewTemp = ALPHA * temp;
+ if (NewTemp >= 1.0) {
+ maxGen = (int)(log(NewTemp) / log(temp) * maxGen);
+ }
+ temp = NewTemp; /* control variable */
+#ifdef DD_STATS
+ (void) fprintf(table->out,"uphill = %d\taccepted = %d\n",
+ tosses,acceptances);
+ fflush(table->out);
+#endif
+ }
+
+ result = restoreOrder(table,BestOrder,lower,upper);
+ FREE(BestOrder);
+ if (!result) return(0);
+#ifdef DD_STATS
+ fprintf(table->out,"#:N_EXCHANGE %8d : total exchanges\n",ecount);
+ fprintf(table->out,"#:N_JUMPUP %8d : total jumps up\n",ucount);
+ fprintf(table->out,"#:N_JUMPDOWN %8d : total jumps down",dcount);
+#endif
+ return(1);
+
+} /* end of cuddAnnealing */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Checks termination condition.]
+
+ Description [If temperature is STOP_TEMP or there is no improvement
+ then terminates. Returns 1 if the termination criterion is met; 0
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+stopping_criterion(
+ int c1,
+ int c2,
+ int c3,
+ int c4,
+ double temp)
+{
+ if (STOP_TEMP < temp) {
+ return(0);
+ } else if ((c1 == c2) && (c1 == c3) && (c1 == c4)) {
+ return(1);
+ } else {
+ return(0);
+ }
+
+} /* end of stopping_criterion */
+
+
+/**Function********************************************************************
+
+ Synopsis [Random number generator.]
+
+ Description [Returns a double precision value between 0.0 and 1.0.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static double
+random_generator(
+ )
+{
+ return((double)(Cudd_Random() / 2147483561.0));
+
+} /* end of random_generator */
+
+
+/**Function********************************************************************
+
+ Synopsis [This function is for exchanging two variables, x and y.]
+
+ Description [This is the same funcion as ddSwapping except for
+ comparison expression. Use probability function, exp(-size_change/temp).]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddExchange(
+ DdManager * table,
+ int x,
+ int y,
+ double temp)
+{
+ Move *move,*moves;
+ int tmp;
+ int x_ref,y_ref;
+ int x_next,y_next;
+ int size, result;
+ int initial_size, limit_size;
+
+ x_ref = x;
+ y_ref = y;
+
+ x_next = cuddNextHigh(table,x);
+ y_next = cuddNextLow(table,y);
+ moves = NULL;
+ initial_size = limit_size = table->keys - table->isolated;
+
+ for (;;) {
+ if (x_next == y_next) {
+ size = cuddSwapInPlace(table,x,x_next);
+ if (size == 0) goto ddExchangeOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddExchangeOutOfMem;
+ move->x = x;
+ move->y = x_next;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ size = cuddSwapInPlace(table,y_next,y);
+ if (size == 0) goto ddExchangeOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddExchangeOutOfMem;
+ move->x = y_next;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ size = cuddSwapInPlace(table,x,x_next);
+ if (size == 0) goto ddExchangeOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddExchangeOutOfMem;
+ move->x = x;
+ move->y = x_next;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ tmp = x;
+ x = y;
+ y = tmp;
+ } else if (x == y_next) {
+ size = cuddSwapInPlace(table,x,x_next);
+ if (size == 0) goto ddExchangeOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddExchangeOutOfMem;
+ move->x = x;
+ move->y = x_next;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ tmp = x;
+ x = y;
+ y = tmp;
+ } else {
+ size = cuddSwapInPlace(table,x,x_next);
+ if (size == 0) goto ddExchangeOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddExchangeOutOfMem;
+ move->x = x;
+ move->y = x_next;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ size = cuddSwapInPlace(table,y_next,y);
+ if (size == 0) goto ddExchangeOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddExchangeOutOfMem;
+ move->x = y_next;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ x = x_next;
+ y = y_next;
+ }
+
+ x_next = cuddNextHigh(table,x);
+ y_next = cuddNextLow(table,y);
+ if (x_next > y_ref) break;
+
+ if ((double) size > DD_MAX_REORDER_GROWTH * (double) limit_size) {
+ break;
+ } else if (size < limit_size) {
+ limit_size = size;
+ }
+ }
+
+ if (y_next>=x_ref) {
+ size = cuddSwapInPlace(table,y_next,y);
+ if (size == 0) goto ddExchangeOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddExchangeOutOfMem;
+ move->x = y_next;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ }
+
+ /* move backward and stop at best position or accept uphill move */
+ result = siftBackwardProb(table,moves,initial_size,temp);
+ if (!result) goto ddExchangeOutOfMem;
+
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return(1);
+
+ddExchangeOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table,(DdNode *) moves);
+ moves = move;
+ }
+ return(0);
+
+} /* end of ddExchange */
+
+
+/**Function********************************************************************
+
+ Synopsis [Moves a variable to a specified position.]
+
+ Description [If x==x_low, it executes jumping_down. If x==x_high, it
+ executes jumping_up. This funcion is similar to ddSiftingAux. Returns
+ 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddJumpingAux(
+ DdManager * table,
+ int x,
+ int x_low,
+ int x_high,
+ double temp)
+{
+ Move *move;
+ Move *moves; /* list of moves */
+ int initial_size;
+ int result;
+
+ initial_size = table->keys - table->isolated;
+
+#ifdef DD_DEBUG
+ assert(table->subtables[x].keys > 0);
+#endif
+
+ moves = NULL;
+
+ if (cuddNextLow(table,x) < x_low) {
+ if (cuddNextHigh(table,x) > x_high) return(1);
+ moves = ddJumpingDown(table,x,x_high,initial_size);
+ /* after that point x --> x_high unless early termination */
+ if (moves == NULL) goto ddJumpingAuxOutOfMem;
+ /* move backward and stop at best position or accept uphill move */
+ result = siftBackwardProb(table,moves,initial_size,temp);
+ if (!result) goto ddJumpingAuxOutOfMem;
+ } else if (cuddNextHigh(table,x) > x_high) {
+ moves = ddJumpingUp(table,x,x_low,initial_size);
+ /* after that point x --> x_low unless early termination */
+ if (moves == NULL) goto ddJumpingAuxOutOfMem;
+ /* move backward and stop at best position or accept uphill move */
+ result = siftBackwardProb(table,moves,initial_size,temp);
+ if (!result) goto ddJumpingAuxOutOfMem;
+ } else {
+ (void) fprintf(table->err,"Unexpected condition in ddJumping\n");
+ goto ddJumpingAuxOutOfMem;
+ }
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return(1);
+
+ddJumpingAuxOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return(0);
+
+} /* end of ddJumpingAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [This function is for jumping up.]
+
+ Description [This is a simplified version of ddSiftingUp. It does not
+ use lower bounding. Returns the set of moves in case of success; NULL
+ if memory is full.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static Move *
+ddJumpingUp(
+ DdManager * table,
+ int x,
+ int x_low,
+ int initial_size)
+{
+ Move *moves;
+ Move *move;
+ int y;
+ int size;
+ int limit_size = initial_size;
+
+ moves = NULL;
+ y = cuddNextLow(table,x);
+ while (y >= x_low) {
+ size = cuddSwapInPlace(table,y,x);
+ if (size == 0) goto ddJumpingUpOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddJumpingUpOutOfMem;
+ move->x = y;
+ move->y = x;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ if ((double) size > table->maxGrowth * (double) limit_size) {
+ break;
+ } else if (size < limit_size) {
+ limit_size = size;
+ }
+ x = y;
+ y = cuddNextLow(table,x);
+ }
+ return(moves);
+
+ddJumpingUpOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return(NULL);
+
+} /* end of ddJumpingUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [This function is for jumping down.]
+
+ Description [This is a simplified version of ddSiftingDown. It does not
+ use lower bounding. Returns the set of moves in case of success; NULL
+ if memory is full.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static Move *
+ddJumpingDown(
+ DdManager * table,
+ int x,
+ int x_high,
+ int initial_size)
+{
+ Move *moves;
+ Move *move;
+ int y;
+ int size;
+ int limit_size = initial_size;
+
+ moves = NULL;
+ y = cuddNextHigh(table,x);
+ while (y <= x_high) {
+ size = cuddSwapInPlace(table,x,y);
+ if (size == 0) goto ddJumpingDownOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddJumpingDownOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ if ((double) size > table->maxGrowth * (double) limit_size) {
+ break;
+ } else if (size < limit_size) {
+ limit_size = size;
+ }
+ x = y;
+ y = cuddNextHigh(table,x);
+ }
+ return(moves);
+
+ddJumpingDownOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return(NULL);
+
+} /* end of ddJumpingDown */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the DD to the best position encountered during
+ sifting if there was improvement.]
+
+ Description [Otherwise, "tosses a coin" to decide whether to keep
+ the current configuration or return the DD to the original
+ one. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+siftBackwardProb(
+ DdManager * table,
+ Move * moves,
+ int size,
+ double temp)
+{
+ Move *move;
+ int res;
+ int best_size = size;
+ double coin, threshold;
+
+ /* Look for best size during the last sifting */
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size < best_size) {
+ best_size = move->size;
+ }
+ }
+
+ /* If best_size equals size, the last sifting did not produce any
+ ** improvement. We now toss a coin to decide whether to retain
+ ** this change or not.
+ */
+ if (best_size == size) {
+ coin = random_generator();
+#ifdef DD_STATS
+ tosses++;
+#endif
+ threshold = exp(-((double)(table->keys - table->isolated - size))/temp);
+ if (coin < threshold) {
+#ifdef DD_STATS
+ acceptances++;
+#endif
+ return(1);
+ }
+ }
+
+ /* Either there was improvement, or we have decided not to
+ ** accept the uphill move. Go to best position.
+ */
+ res = table->keys - table->isolated;
+ for (move = moves; move != NULL; move = move->next) {
+ if (res == best_size) return(1);
+ res = cuddSwapInPlace(table,(int)move->x,(int)move->y);
+ if (!res) return(0);
+ }
+
+ return(1);
+
+} /* end of sift_backward_prob */
+
+
+/**Function********************************************************************
+
+ Synopsis [Copies the current variable order to array.]
+
+ Description [Copies the current variable order to array.
+ At the same time inverts the permutation.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+copyOrder(
+ DdManager * table,
+ int * array,
+ int lower,
+ int upper)
+{
+ int i;
+ int nvars;
+
+ nvars = upper - lower + 1;
+ for (i = 0; i < nvars; i++) {
+ array[i] = table->invperm[i+lower];
+ }
+
+} /* end of copyOrder */
+
+
+/**Function********************************************************************
+
+ Synopsis [Restores the variable order in array by a series of sifts up.]
+
+ Description [Restores the variable order in array by a series of sifts up.
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+restoreOrder(
+ DdManager * table,
+ int * array,
+ int lower,
+ int upper)
+{
+ int i, x, y, size;
+ int nvars = upper - lower + 1;
+
+ for (i = 0; i < nvars; i++) {
+ x = table->perm[array[i]];
+#ifdef DD_DEBUG
+ assert(x >= lower && x <= upper);
+#endif
+ y = cuddNextLow(table,x);
+ while (y >= i + lower) {
+ size = cuddSwapInPlace(table,y,x);
+ if (size == 0) return(0);
+ x = y;
+ y = cuddNextLow(table,x);
+ }
+ }
+
+ return(1);
+
+} /* end of restoreOrder */
+
diff --git a/src/bdd/cudd/cuddApa.c b/src/bdd/cudd/cuddApa.c
new file mode 100644
index 00000000..805a4dde
--- /dev/null
+++ b/src/bdd/cudd/cuddApa.c
@@ -0,0 +1,930 @@
+/**CFile***********************************************************************
+
+ FileName [cuddApa.c]
+
+ PackageName [cudd]
+
+ Synopsis [Arbitrary precision arithmetic functions.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li>
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> ()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> ()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddApa.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+static DdNode *background, *zero;
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdApaNumber cuddApaCountMintermAux ARGS((DdNode * node, int digits, DdApaNumber max, DdApaNumber min, st_table * table));
+static enum st_retval cuddApaStCountfree ARGS((char * key, char * value, char * arg));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the number of digits for an arbitrary precision
+ integer.]
+
+ Description [Finds the number of digits for an arbitrary precision
+ integer given the maximum number of binary digits. The number of
+ binary digits should be positive. Returns the number of digits if
+ successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_ApaNumberOfDigits(
+ int binaryDigits)
+{
+ int digits;
+
+ digits = binaryDigits / DD_APA_BITS;
+ if ((digits * DD_APA_BITS) != binaryDigits)
+ digits++;
+ return(digits);
+
+} /* end of Cudd_ApaNumberOfDigits */
+
+
+/**Function********************************************************************
+
+ Synopsis [Allocates memory for an arbitrary precision integer.]
+
+ Description [Allocates memory for an arbitrary precision
+ integer. Returns a pointer to the allocated memory if successful;
+ NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdApaNumber
+Cudd_NewApaNumber(
+ int digits)
+{
+ return(ALLOC(DdApaDigit, digits));
+
+} /* end of Cudd_NewApaNumber */
+
+
+/**Function********************************************************************
+
+ Synopsis [Makes a copy of an arbitrary precision integer.]
+
+ Description [Makes a copy of an arbitrary precision integer.]
+
+ SideEffects [Changes parameter <code>dest</code>.]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+Cudd_ApaCopy(
+ int digits,
+ DdApaNumber source,
+ DdApaNumber dest)
+{
+ int i;
+
+ for (i = 0; i < digits; i++) {
+ dest[i] = source[i];
+ }
+
+} /* end of Cudd_ApaCopy */
+
+
+/**Function********************************************************************
+
+ Synopsis [Adds two arbitrary precision integers.]
+
+ Description [Adds two arbitrary precision integers. Returns the
+ carry out of the most significant digit.]
+
+ SideEffects [The result of the sum is stored in parameter <code>sum</code>.]
+
+ SeeAlso []
+
+******************************************************************************/
+DdApaDigit
+Cudd_ApaAdd(
+ int digits,
+ DdApaNumber a,
+ DdApaNumber b,
+ DdApaNumber sum)
+{
+ int i;
+ DdApaDoubleDigit partial = 0;
+
+ for (i = digits - 1; i >= 0; i--) {
+ partial = a[i] + b[i] + DD_MSDIGIT(partial);
+ sum[i] = (DdApaDigit) DD_LSDIGIT(partial);
+ }
+ return(DD_MSDIGIT(partial));
+
+} /* end of Cudd_ApaAdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Subtracts two arbitrary precision integers.]
+
+ Description [Subtracts two arbitrary precision integers. Returns the
+ borrow out of the most significant digit.]
+
+ SideEffects [The result of the subtraction is stored in parameter
+ <code>diff</code>.]
+
+ SeeAlso []
+
+******************************************************************************/
+DdApaDigit
+Cudd_ApaSubtract(
+ int digits,
+ DdApaNumber a,
+ DdApaNumber b,
+ DdApaNumber diff)
+{
+ int i;
+ DdApaDoubleDigit partial = DD_APA_BASE;
+
+ for (i = digits - 1; i >= 0; i--) {
+ partial = a[i] - b[i] + DD_MSDIGIT(partial) + DD_APA_MASK;
+ diff[i] = (DdApaDigit) DD_LSDIGIT(partial);
+ }
+ return(DD_MSDIGIT(partial) - 1);
+
+} /* end of Cudd_ApaSubtract */
+
+
+/**Function********************************************************************
+
+ Synopsis [Divides an arbitrary precision integer by a digit.]
+
+ Description [Divides an arbitrary precision integer by a digit.]
+
+ SideEffects [The quotient is returned in parameter <code>quotient</code>.]
+
+ SeeAlso []
+
+******************************************************************************/
+DdApaDigit
+Cudd_ApaShortDivision(
+ int digits,
+ DdApaNumber dividend,
+ DdApaDigit divisor,
+ DdApaNumber quotient)
+{
+ int i;
+ DdApaDigit remainder;
+ DdApaDoubleDigit partial;
+
+ remainder = 0;
+ for (i = 0; i < digits; i++) {
+ partial = remainder * DD_APA_BASE + dividend[i];
+ quotient[i] = (DdApaDigit) (partial/(DdApaDoubleDigit)divisor);
+ remainder = (DdApaDigit) (partial % divisor);
+ }
+
+ return(remainder);
+
+} /* end of Cudd_ApaShortDivision */
+
+
+/**Function********************************************************************
+
+ Synopsis [Divides an arbitrary precision integer by an integer.]
+
+ Description [Divides an arbitrary precision integer by a 32-bit
+ unsigned integer. Returns the remainder of the division. This
+ procedure relies on the assumption that the number of bits of a
+ DdApaDigit plus the number of bits of an unsigned int is less the
+ number of bits of the mantissa of a double. This guarantees that the
+ product of a DdApaDigit and an unsigned int can be represented
+ without loss of precision by a double. On machines where this
+ assumption is not satisfied, this procedure will malfunction.]
+
+ SideEffects [The quotient is returned in parameter <code>quotient</code>.]
+
+ SeeAlso [Cudd_ApaShortDivision]
+
+******************************************************************************/
+unsigned int
+Cudd_ApaIntDivision(
+ int digits,
+ DdApaNumber dividend,
+ unsigned int divisor,
+ DdApaNumber quotient)
+{
+ int i;
+ double partial;
+ unsigned int remainder = 0;
+ double ddiv = (double) divisor;
+
+ for (i = 0; i < digits; i++) {
+ partial = (double) remainder * DD_APA_BASE + dividend[i];
+ quotient[i] = (DdApaDigit) (partial / ddiv);
+ remainder = (unsigned int) (partial - ((double)quotient[i] * ddiv));
+ }
+
+ return(remainder);
+
+} /* end of Cudd_ApaIntDivision */
+
+
+/**Function********************************************************************
+
+ Synopsis [Shifts right an arbitrary precision integer by one binary
+ place.]
+
+ Description [Shifts right an arbitrary precision integer by one
+ binary place. The most significant binary digit of the result is
+ taken from parameter <code>in</code>.]
+
+ SideEffects [The result is returned in parameter <code>b</code>.]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+Cudd_ApaShiftRight(
+ int digits,
+ DdApaDigit in,
+ DdApaNumber a,
+ DdApaNumber b)
+{
+ int i;
+
+ for (i = digits - 1; i > 0; i--) {
+ b[i] = (a[i] >> 1) | ((a[i-1] & 1) << (DD_APA_BITS - 1));
+ }
+ b[0] = (a[0] >> 1) | (in << (DD_APA_BITS - 1));
+
+} /* end of Cudd_ApaShiftRight */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets an arbitrary precision integer to a one-digit literal.]
+
+ Description [Sets an arbitrary precision integer to a one-digit literal.]
+
+ SideEffects [The result is returned in parameter <code>number</code>.]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+Cudd_ApaSetToLiteral(
+ int digits,
+ DdApaNumber number,
+ DdApaDigit literal)
+{
+ int i;
+
+ for (i = 0; i < digits - 1; i++)
+ number[i] = 0;
+ number[digits - 1] = literal;
+
+} /* end of Cudd_ApaSetToLiteral */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets an arbitrary precision integer to a power of two.]
+
+ Description [Sets an arbitrary precision integer to a power of
+ two. If the power of two is too large to be represented, the number
+ is set to 0.]
+
+ SideEffects [The result is returned in parameter <code>number</code>.]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+Cudd_ApaPowerOfTwo(
+ int digits,
+ DdApaNumber number,
+ int power)
+{
+ int i;
+ int index;
+
+ for (i = 0; i < digits; i++)
+ number[i] = 0;
+ i = digits - 1 - power / DD_APA_BITS;
+ if (i < 0) return;
+ index = power & (DD_APA_BITS - 1);
+ number[i] = 1 << index;
+
+} /* end of Cudd_ApaPowerOfTwo */
+
+
+/**Function********************************************************************
+
+ Synopsis [Compares two arbitrary precision integers.]
+
+ Description [Compares two arbitrary precision integers. Returns 1 if
+ the first number is larger; 0 if they are equal; -1 if the second
+ number is larger.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_ApaCompare(
+ int digitsFirst,
+ DdApaNumber first,
+ int digitsSecond,
+ DdApaNumber second)
+{
+ int i;
+ int firstNZ, secondNZ;
+
+ /* Find first non-zero in both numbers. */
+ for (firstNZ = 0; firstNZ < digitsFirst; firstNZ++)
+ if (first[firstNZ] != 0) break;
+ for (secondNZ = 0; secondNZ < digitsSecond; secondNZ++)
+ if (second[secondNZ] != 0) break;
+ if (digitsFirst - firstNZ > digitsSecond - secondNZ) return(1);
+ else if (digitsFirst - firstNZ < digitsSecond - secondNZ) return(-1);
+ for (i = 0; i < digitsFirst - firstNZ; i++) {
+ if (first[firstNZ + i] > second[secondNZ + i]) return(1);
+ else if (first[firstNZ + i] < second[secondNZ + i]) return(-1);
+ }
+ return(0);
+
+} /* end of Cudd_ApaCompare */
+
+
+/**Function********************************************************************
+
+ Synopsis [Compares the ratios of two arbitrary precision integers to two
+ unsigned ints.]
+
+ Description [Compares the ratios of two arbitrary precision integers
+ to two unsigned ints. Returns 1 if the first number is larger; 0 if
+ they are equal; -1 if the second number is larger.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_ApaCompareRatios(
+ int digitsFirst,
+ DdApaNumber firstNum,
+ unsigned int firstDen,
+ int digitsSecond,
+ DdApaNumber secondNum,
+ unsigned int secondDen)
+{
+ int result;
+ DdApaNumber first, second;
+ unsigned int firstRem, secondRem;
+
+ first = Cudd_NewApaNumber(digitsFirst);
+ firstRem = Cudd_ApaIntDivision(digitsFirst,firstNum,firstDen,first);
+ second = Cudd_NewApaNumber(digitsSecond);
+ secondRem = Cudd_ApaIntDivision(digitsSecond,secondNum,secondDen,second);
+ result = Cudd_ApaCompare(digitsFirst,first,digitsSecond,second);
+ if (result == 0) {
+ if ((double)firstRem/firstDen > (double)secondRem/secondDen)
+ return(1);
+ else if ((double)firstRem/firstDen < (double)secondRem/secondDen)
+ return(-1);
+ }
+ return(result);
+
+} /* end of Cudd_ApaCompareRatios */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints an arbitrary precision integer in hexadecimal format.]
+
+ Description [Prints an arbitrary precision integer in hexadecimal format.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ApaPrintDecimal Cudd_ApaPrintExponential]
+
+******************************************************************************/
+int
+Cudd_ApaPrintHex(
+ FILE * fp,
+ int digits,
+ DdApaNumber number)
+{
+ int i, result;
+
+ for (i = 0; i < digits; i++) {
+ result = fprintf(fp,DD_APA_HEXPRINT,number[i]);
+ if (result == EOF)
+ return(0);
+ }
+ return(1);
+
+} /* end of Cudd_ApaPrintHex */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints an arbitrary precision integer in decimal format.]
+
+ Description [Prints an arbitrary precision integer in decimal format.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ApaPrintHex Cudd_ApaPrintExponential]
+
+******************************************************************************/
+int
+Cudd_ApaPrintDecimal(
+ FILE * fp,
+ int digits,
+ DdApaNumber number)
+{
+ int i, result;
+ DdApaDigit remainder;
+ DdApaNumber work;
+ unsigned char *decimal;
+ int leadingzero;
+ int decimalDigits = (int) (digits * log10((double) DD_APA_BASE)) + 1;
+
+ work = Cudd_NewApaNumber(digits);
+ if (work == NULL)
+ return(0);
+ decimal = ALLOC(unsigned char, decimalDigits);
+ if (decimal == NULL) {
+ FREE(work);
+ return(0);
+ }
+ Cudd_ApaCopy(digits,number,work);
+ for (i = decimalDigits - 1; i >= 0; i--) {
+ remainder = Cudd_ApaShortDivision(digits,work,(DdApaDigit) 10,work);
+ decimal[i] = remainder;
+ }
+ FREE(work);
+
+ leadingzero = 1;
+ for (i = 0; i < decimalDigits; i++) {
+ leadingzero = leadingzero && (decimal[i] == 0);
+ if ((!leadingzero) || (i == (decimalDigits - 1))) {
+ result = fprintf(fp,"%1d",decimal[i]);
+ if (result == EOF) {
+ FREE(decimal);
+ return(0);
+ }
+ }
+ }
+ FREE(decimal);
+ return(1);
+
+} /* end of Cudd_ApaPrintDecimal */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints an arbitrary precision integer in exponential format.]
+
+ Description [Prints an arbitrary precision integer in exponential format.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ApaPrintHex Cudd_ApaPrintDecimal]
+
+******************************************************************************/
+int
+Cudd_ApaPrintExponential(
+ FILE * fp,
+ int digits,
+ DdApaNumber number,
+ int precision)
+{
+ int i, first, last, result;
+ DdApaDigit remainder;
+ DdApaNumber work;
+ unsigned char *decimal;
+ int decimalDigits = (int) (digits * log10((double) DD_APA_BASE)) + 1;
+
+ work = Cudd_NewApaNumber(digits);
+ if (work == NULL)
+ return(0);
+ decimal = ALLOC(unsigned char, decimalDigits);
+ if (decimal == NULL) {
+ FREE(work);
+ return(0);
+ }
+ Cudd_ApaCopy(digits,number,work);
+ first = decimalDigits - 1;
+ for (i = decimalDigits - 1; i >= 0; i--) {
+ remainder = Cudd_ApaShortDivision(digits,work,(DdApaDigit) 10,work);
+ decimal[i] = remainder;
+ if (remainder != 0) first = i; /* keep track of MS non-zero */
+ }
+ FREE(work);
+ last = ddMin(first + precision, decimalDigits);
+
+ for (i = first; i < last; i++) {
+ result = fprintf(fp,"%s%1d",i == first+1 ? "." : "", decimal[i]);
+ if (result == EOF) {
+ FREE(decimal);
+ return(0);
+ }
+ }
+ FREE(decimal);
+ result = fprintf(fp,"e+%d",decimalDigits - first - 1);
+ if (result == EOF) {
+ return(0);
+ }
+ return(1);
+
+} /* end of Cudd_ApaPrintExponential */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of minterms of a DD.]
+
+ Description [Counts the number of minterms of a DD. The function is
+ assumed to depend on nvars variables. The minterm count is
+ represented as an arbitrary precision unsigned integer, to allow for
+ any number of variables CUDD supports. Returns a pointer to the
+ array representing the number of minterms of the function rooted at
+ node if successful; NULL otherwise.]
+
+ SideEffects [The number of digits of the result is returned in
+ parameter <code>digits</code>.]
+
+ SeeAlso [Cudd_CountMinterm]
+
+******************************************************************************/
+DdApaNumber
+Cudd_ApaCountMinterm(
+ DdManager * manager,
+ DdNode * node,
+ int nvars,
+ int * digits)
+{
+ DdApaNumber max, min;
+ st_table *table;
+ DdApaNumber i,count;
+
+ background = manager->background;
+ zero = Cudd_Not(manager->one);
+
+ *digits = Cudd_ApaNumberOfDigits(nvars+1);
+ max = Cudd_NewApaNumber(*digits);
+ if (max == NULL) {
+ return(NULL);
+ }
+ Cudd_ApaPowerOfTwo(*digits,max,nvars);
+ min = Cudd_NewApaNumber(*digits);
+ if (min == NULL) {
+ FREE(max);
+ return(NULL);
+ }
+ Cudd_ApaSetToLiteral(*digits,min,0);
+ table = st_init_table(st_ptrcmp,st_ptrhash);
+ if (table == NULL) {
+ FREE(max);
+ FREE(min);
+ return(NULL);
+ }
+ i = cuddApaCountMintermAux(Cudd_Regular(node),*digits,max,min,table);
+ if (i == NULL) {
+ FREE(max);
+ FREE(min);
+ st_foreach(table, cuddApaStCountfree, NULL);
+ st_free_table(table);
+ return(NULL);
+ }
+ count = Cudd_NewApaNumber(*digits);
+ if (count == NULL) {
+ FREE(max);
+ FREE(min);
+ st_foreach(table, cuddApaStCountfree, NULL);
+ st_free_table(table);
+ if (Cudd_Regular(node)->ref == 1) FREE(i);
+ return(NULL);
+ }
+ if (Cudd_IsComplement(node)) {
+ (void) Cudd_ApaSubtract(*digits,max,i,count);
+ } else {
+ Cudd_ApaCopy(*digits,i,count);
+ }
+ FREE(max);
+ FREE(min);
+ st_foreach(table, cuddApaStCountfree, NULL);
+ st_free_table(table);
+ if (Cudd_Regular(node)->ref == 1) FREE(i);
+ return(count);
+
+} /* end of Cudd_ApaCountMinterm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints the number of minterms of a BDD or ADD using
+ arbitrary precision arithmetic.]
+
+ Description [Prints the number of minterms of a BDD or ADD using
+ arbitrary precision arithmetic. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ApaPrintMintermExp]
+
+******************************************************************************/
+int
+Cudd_ApaPrintMinterm(
+ FILE * fp,
+ DdManager * dd,
+ DdNode * node,
+ int nvars)
+{
+ int digits;
+ int result;
+ DdApaNumber count;
+
+ count = Cudd_ApaCountMinterm(dd,node,nvars,&digits);
+ if (count == NULL)
+ return(0);
+ result = Cudd_ApaPrintDecimal(fp,digits,count);
+ FREE(count);
+ if (fprintf(fp,"\n") == EOF) {
+ return(0);
+ }
+ return(result);
+
+} /* end of Cudd_ApaPrintMinterm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints the number of minterms of a BDD or ADD in exponential
+ format using arbitrary precision arithmetic.]
+
+ Description [Prints the number of minterms of a BDD or ADD in
+ exponential format using arbitrary precision arithmetic. Parameter
+ precision controls the number of signficant digits printed. Returns
+ 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ApaPrintMinterm]
+
+******************************************************************************/
+int
+Cudd_ApaPrintMintermExp(
+ FILE * fp,
+ DdManager * dd,
+ DdNode * node,
+ int nvars,
+ int precision)
+{
+ int digits;
+ int result;
+ DdApaNumber count;
+
+ count = Cudd_ApaCountMinterm(dd,node,nvars,&digits);
+ if (count == NULL)
+ return(0);
+ result = Cudd_ApaPrintExponential(fp,digits,count,precision);
+ FREE(count);
+ if (fprintf(fp,"\n") == EOF) {
+ return(0);
+ }
+ return(result);
+
+} /* end of Cudd_ApaPrintMintermExp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints the density of a BDD or ADD using
+ arbitrary precision arithmetic.]
+
+ Description [Prints the density of a BDD or ADD using
+ arbitrary precision arithmetic. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_ApaPrintDensity(
+ FILE * fp,
+ DdManager * dd,
+ DdNode * node,
+ int nvars)
+{
+ int digits;
+ int result;
+ DdApaNumber count,density;
+ unsigned int size, remainder, fractional;
+
+ count = Cudd_ApaCountMinterm(dd,node,nvars,&digits);
+ if (count == NULL)
+ return(0);
+ size = Cudd_DagSize(node);
+ density = Cudd_NewApaNumber(digits);
+ remainder = Cudd_ApaIntDivision(digits,count,size,density);
+ result = Cudd_ApaPrintDecimal(fp,digits,density);
+ FREE(count);
+ FREE(density);
+ fractional = (unsigned int)((double)remainder / size * 1000000);
+ if (fprintf(fp,".%u\n", fractional) == EOF) {
+ return(0);
+ }
+ return(result);
+
+} /* end of Cudd_ApaPrintDensity */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_ApaCountMinterm.]
+
+ Description [Performs the recursive step of Cudd_ApaCountMinterm.
+ It is based on the following identity. Let |f| be the
+ number of minterms of f. Then:
+ <xmp>
+ |f| = (|f0|+|f1|)/2
+ </xmp>
+ where f0 and f1 are the two cofactors of f.
+ Uses the identity <code>|f'| = max - |f|</code>.
+ The procedure expects the argument "node" to be a regular pointer, and
+ guarantees this condition is met in the recursive calls.
+ For efficiency, the result of a call is cached only if the node has
+ a reference count greater than 1.
+ Returns the number of minterms of the function rooted at node.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static DdApaNumber
+cuddApaCountMintermAux(
+ DdNode * node,
+ int digits,
+ DdApaNumber max,
+ DdApaNumber min,
+ st_table * table)
+{
+ DdNode *Nt, *Ne;
+ DdApaNumber mint, mint1, mint2;
+ DdApaDigit carryout;
+
+ if (cuddIsConstant(node)) {
+ if (node == background || node == zero) {
+ return(min);
+ } else {
+ return(max);
+ }
+ }
+ if (node->ref > 1 && st_lookup(table, (char *)node, (char **)&mint)) {
+ return(mint);
+ }
+
+ Nt = cuddT(node); Ne = cuddE(node);
+
+ mint1 = cuddApaCountMintermAux(Nt, digits, max, min, table);
+ if (mint1 == NULL) return(NULL);
+ mint2 = cuddApaCountMintermAux(Cudd_Regular(Ne), digits, max, min, table);
+ if (mint2 == NULL) {
+ if (Nt->ref == 1) FREE(mint1);
+ return(NULL);
+ }
+ mint = Cudd_NewApaNumber(digits);
+ if (mint == NULL) {
+ if (Nt->ref == 1) FREE(mint1);
+ if (Cudd_Regular(Ne)->ref == 1) FREE(mint2);
+ return(NULL);
+ }
+ if (Cudd_IsComplement(Ne)) {
+ (void) Cudd_ApaSubtract(digits,max,mint2,mint);
+ carryout = Cudd_ApaAdd(digits,mint1,mint,mint);
+ } else {
+ carryout = Cudd_ApaAdd(digits,mint1,mint2,mint);
+ }
+ Cudd_ApaShiftRight(digits,carryout,mint,mint);
+ /* If the refernce count of a child is 1, its minterm count
+ ** hasn't been stored in table. Therefore, it must be explicitly
+ ** freed here. */
+ if (Nt->ref == 1) FREE(mint1);
+ if (Cudd_Regular(Ne)->ref == 1) FREE(mint2);
+
+ if (node->ref > 1) {
+ if (st_insert(table, (char *)node, (char *)mint) == ST_OUT_OF_MEM) {
+ FREE(mint);
+ return(NULL);
+ }
+ }
+ return(mint);
+
+} /* end of cuddApaCountMintermAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees the memory used to store the minterm counts recorded
+ in the visited table.]
+
+ Description [Frees the memory used to store the minterm counts
+ recorded in the visited table. Returns ST_CONTINUE.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static enum st_retval
+cuddApaStCountfree(
+ char * key,
+ char * value,
+ char * arg)
+{
+ DdApaNumber d;
+
+ d = (DdApaNumber) value;
+ FREE(d);
+ return(ST_CONTINUE);
+
+} /* end of cuddApaStCountfree */
+
+
diff --git a/src/bdd/cudd/cuddApprox.c b/src/bdd/cudd/cuddApprox.c
new file mode 100644
index 00000000..eb6813ff
--- /dev/null
+++ b/src/bdd/cudd/cuddApprox.c
@@ -0,0 +1,2192 @@
+/**CFile***********************************************************************
+
+ FileName [cuddApprox.c]
+
+ PackageName [cudd]
+
+ Synopsis [Procedures to approximate a given BDD.]
+
+ Description [External procedures provided by this module:
+ <ul>
+ <li> Cudd_UnderApprox()
+ <li> Cudd_OverApprox()
+ <li> Cudd_RemapUnderApprox()
+ <li> Cudd_RemapOverApprox()
+ <li> Cudd_BiasedUnderApprox()
+ <li> Cudd_BiasedOverApprox()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddUnderApprox()
+ <li> cuddRemapUnderApprox()
+ <li> cuddBiasedUnderApprox()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> gatherInfoAux()
+ <li> gatherInfo()
+ <li> computeSavings()
+ <li> UAmarkNodes()
+ <li> UAbuildSubset()
+ <li> updateRefs()
+ <li> RAmarkNodes()
+ <li> BAmarkNodes()
+ <li> RAbuildSubset()
+ </ul>
+ ]
+
+ SeeAlso [cuddSubsetHB.c cuddSubsetSP.c cuddGenCof.c]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no
+ warranty about the suitability of this software for any
+ purpose. It is presented on an AS IS basis.]
+
+******************************************************************************/
+
+#ifdef __STDC__
+#include <float.h>
+#else
+#define DBL_MAX_EXP 1024
+#endif
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define NOTHING 0
+#define REPLACE_T 1
+#define REPLACE_E 2
+#define REPLACE_N 3
+#define REPLACE_TT 4
+#define REPLACE_TE 5
+
+#define DONT_CARE 0
+#define CARE 1
+#define TOTAL_CARE 2
+#define CARE_ERROR 3
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/* Data structure to store the information on each node. It keeps the
+** number of minterms of the function rooted at this node in terms of
+** the number of variables specified by the user; the number of
+** minterms of the complement; the impact of the number of minterms of
+** this function on the number of minterms of the root function; the
+** reference count of the node from within the root function; the
+** reference count of the node from an internal node; and the flag
+** that says whether the node should be replaced and how. */
+typedef struct NodeData {
+ double mintermsP; /* minterms for the regular node */
+ double mintermsN; /* minterms for the complemented node */
+ int functionRef; /* references from within this function */
+ char care; /* node intersects care set */
+ char replace; /* replacement decision */
+ short int parity; /* 1: even; 2: odd; 3: both */
+ DdNode *resultP; /* result for even parity */
+ DdNode *resultN; /* result for odd parity */
+} NodeData;
+
+typedef struct ApproxInfo {
+ DdNode *one; /* one constant */
+ DdNode *zero; /* BDD zero constant */
+ NodeData *page; /* per-node information */
+ st_table *table; /* hash table to access the per-node info */
+ int index; /* index of the current node */
+ double max; /* max number of minterms */
+ int size; /* how many nodes are left */
+ double minterms; /* how many minterms are left */
+} ApproxInfo;
+
+/* Item of the queue used in the levelized traversal of the BDD. */
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+typedef struct GlobalQueueItem {
+ struct GlobalQueueItem *next;
+ struct GlobalQueueItem *cnext;
+ DdNode *node;
+ double impactP;
+ double impactN;
+} GlobalQueueItem;
+
+typedef struct LocalQueueItem {
+ struct LocalQueueItem *next;
+ struct LocalQueueItem *cnext;
+ DdNode *node;
+ int localRef;
+} LocalQueueItem;
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddApprox.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static void updateParity ARGS((DdNode *node, ApproxInfo *info, int newparity));
+static NodeData * gatherInfoAux ARGS((DdNode *node, ApproxInfo *info, int parity));
+static ApproxInfo * gatherInfo ARGS((DdManager *dd, DdNode *node, int numVars, int parity));
+static int computeSavings ARGS((DdManager *dd, DdNode *f, DdNode *skip, ApproxInfo *info, DdLevelQueue *queue));
+static int updateRefs ARGS((DdManager *dd, DdNode *f, DdNode *skip, ApproxInfo *info, DdLevelQueue *queue));
+static int UAmarkNodes ARGS((DdManager *dd, DdNode *f, ApproxInfo *info, int threshold, int safe, double quality));
+static DdNode * UAbuildSubset ARGS((DdManager *dd, DdNode *node, ApproxInfo *info));
+static int RAmarkNodes ARGS((DdManager *dd, DdNode *f, ApproxInfo *info, int threshold, double quality));
+static int BAmarkNodes ARGS((DdManager *dd, DdNode *f, ApproxInfo *info, int threshold, double quality1, double quality0));
+static DdNode * RAbuildSubset ARGS((DdManager *dd, DdNode *node, ApproxInfo *info));
+static int BAapplyBias ARGS((DdManager *dd, DdNode *f, DdNode *b, ApproxInfo *info, DdHashTable *cache));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Extracts a dense subset from a BDD with Shiple's
+ underapproximation method.]
+
+ Description [Extracts a dense subset from a BDD. This procedure uses
+ a variant of Tom Shiple's underapproximation method. The main
+ difference from the original method is that density is used as cost
+ function. Returns a pointer to the BDD of the subset if
+ successful. NULL if the procedure runs out of memory. The parameter
+ numVars is the maximum number of variables to be used in minterm
+ calculation. The optimal number should be as close as possible to
+ the size of the support of f. However, it is safe to pass the value
+ returned by Cudd_ReadSize for numVars when the number of variables
+ is under 1023. If numVars is larger than 1023, it will cause
+ overflow. If a 0 parameter is passed then the procedure will compute
+ a value which will avoid overflow but will cause underflow with 2046
+ variables or more.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SubsetShortPaths Cudd_SubsetHeavyBranch Cudd_ReadSize]
+
+******************************************************************************/
+DdNode *
+Cudd_UnderApprox(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be subset */,
+ int numVars /* number of variables in the support of f */,
+ int threshold /* when to stop approximation */,
+ int safe /* enforce safe approximation */,
+ double quality /* minimum improvement for accepted changes */)
+{
+ DdNode *subset;
+
+ do {
+ dd->reordered = 0;
+ subset = cuddUnderApprox(dd, f, numVars, threshold, safe, quality);
+ } while (dd->reordered == 1);
+
+ return(subset);
+
+} /* end of Cudd_UnderApprox */
+
+
+/**Function********************************************************************
+
+ Synopsis [Extracts a dense superset from a BDD with Shiple's
+ underapproximation method.]
+
+ Description [Extracts a dense superset from a BDD. The procedure is
+ identical to the underapproximation procedure except for the fact that it
+ works on the complement of the given function. Extracting the subset
+ of the complement function is equivalent to extracting the superset
+ of the function.
+ Returns a pointer to the BDD of the superset if successful. NULL if
+ intermediate result causes the procedure to run out of memory. The
+ parameter numVars is the maximum number of variables to be used in
+ minterm calculation. The optimal number
+ should be as close as possible to the size of the support of f.
+ However, it is safe to pass the value returned by Cudd_ReadSize for
+ numVars when the number of variables is under 1023. If numVars is
+ larger than 1023, it will overflow. If a 0 parameter is passed then
+ the procedure will compute a value which will avoid overflow but
+ will cause underflow with 2046 variables or more.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SupersetHeavyBranch Cudd_SupersetShortPaths Cudd_ReadSize]
+
+******************************************************************************/
+DdNode *
+Cudd_OverApprox(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be superset */,
+ int numVars /* number of variables in the support of f */,
+ int threshold /* when to stop approximation */,
+ int safe /* enforce safe approximation */,
+ double quality /* minimum improvement for accepted changes */)
+{
+ DdNode *subset, *g;
+
+ g = Cudd_Not(f);
+ do {
+ dd->reordered = 0;
+ subset = cuddUnderApprox(dd, g, numVars, threshold, safe, quality);
+ } while (dd->reordered == 1);
+
+ return(Cudd_NotCond(subset, (subset != NULL)));
+
+} /* end of Cudd_OverApprox */
+
+
+/**Function********************************************************************
+
+ Synopsis [Extracts a dense subset from a BDD with the remapping
+ underapproximation method.]
+
+ Description [Extracts a dense subset from a BDD. This procedure uses
+ a remapping technique and density as the cost function.
+ Returns a pointer to the BDD of the subset if
+ successful. NULL if the procedure runs out of memory. The parameter
+ numVars is the maximum number of variables to be used in minterm
+ calculation. The optimal number should be as close as possible to
+ the size of the support of f. However, it is safe to pass the value
+ returned by Cudd_ReadSize for numVars when the number of variables
+ is under 1023. If numVars is larger than 1023, it will cause
+ overflow. If a 0 parameter is passed then the procedure will compute
+ a value which will avoid overflow but will cause underflow with 2046
+ variables or more.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SubsetShortPaths Cudd_SubsetHeavyBranch Cudd_UnderApprox Cudd_ReadSize]
+
+******************************************************************************/
+DdNode *
+Cudd_RemapUnderApprox(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be subset */,
+ int numVars /* number of variables in the support of f */,
+ int threshold /* when to stop approximation */,
+ double quality /* minimum improvement for accepted changes */)
+{
+ DdNode *subset;
+
+ do {
+ dd->reordered = 0;
+ subset = cuddRemapUnderApprox(dd, f, numVars, threshold, quality);
+ } while (dd->reordered == 1);
+
+ return(subset);
+
+} /* end of Cudd_RemapUnderApprox */
+
+
+/**Function********************************************************************
+
+ Synopsis [Extracts a dense superset from a BDD with the remapping
+ underapproximation method.]
+
+ Description [Extracts a dense superset from a BDD. The procedure is
+ identical to the underapproximation procedure except for the fact that it
+ works on the complement of the given function. Extracting the subset
+ of the complement function is equivalent to extracting the superset
+ of the function.
+ Returns a pointer to the BDD of the superset if successful. NULL if
+ intermediate result causes the procedure to run out of memory. The
+ parameter numVars is the maximum number of variables to be used in
+ minterm calculation. The optimal number
+ should be as close as possible to the size of the support of f.
+ However, it is safe to pass the value returned by Cudd_ReadSize for
+ numVars when the number of variables is under 1023. If numVars is
+ larger than 1023, it will overflow. If a 0 parameter is passed then
+ the procedure will compute a value which will avoid overflow but
+ will cause underflow with 2046 variables or more.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SupersetHeavyBranch Cudd_SupersetShortPaths Cudd_ReadSize]
+
+******************************************************************************/
+DdNode *
+Cudd_RemapOverApprox(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be superset */,
+ int numVars /* number of variables in the support of f */,
+ int threshold /* when to stop approximation */,
+ double quality /* minimum improvement for accepted changes */)
+{
+ DdNode *subset, *g;
+
+ g = Cudd_Not(f);
+ do {
+ dd->reordered = 0;
+ subset = cuddRemapUnderApprox(dd, g, numVars, threshold, quality);
+ } while (dd->reordered == 1);
+
+ return(Cudd_NotCond(subset, (subset != NULL)));
+
+} /* end of Cudd_RemapOverApprox */
+
+
+/**Function********************************************************************
+
+ Synopsis [Extracts a dense subset from a BDD with the biased
+ underapproximation method.]
+
+ Description [Extracts a dense subset from a BDD. This procedure uses
+ a biased remapping technique and density as the cost function. The bias
+ is a function. This procedure tries to approximate where the bias is 0
+ and preserve the given function where the bias is 1.
+ Returns a pointer to the BDD of the subset if
+ successful. NULL if the procedure runs out of memory. The parameter
+ numVars is the maximum number of variables to be used in minterm
+ calculation. The optimal number should be as close as possible to
+ the size of the support of f. However, it is safe to pass the value
+ returned by Cudd_ReadSize for numVars when the number of variables
+ is under 1023. If numVars is larger than 1023, it will cause
+ overflow. If a 0 parameter is passed then the procedure will compute
+ a value which will avoid overflow but will cause underflow with 2046
+ variables or more.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SubsetShortPaths Cudd_SubsetHeavyBranch Cudd_UnderApprox
+ Cudd_RemapUnderApprox Cudd_ReadSize]
+
+******************************************************************************/
+DdNode *
+Cudd_BiasedUnderApprox(
+ DdManager *dd /* manager */,
+ DdNode *f /* function to be subset */,
+ DdNode *b /* bias function */,
+ int numVars /* number of variables in the support of f */,
+ int threshold /* when to stop approximation */,
+ double quality1 /* minimum improvement for accepted changes when b=1 */,
+ double quality0 /* minimum improvement for accepted changes when b=0 */)
+{
+ DdNode *subset;
+
+ do {
+ dd->reordered = 0;
+ subset = cuddBiasedUnderApprox(dd, f, b, numVars, threshold, quality1,
+ quality0);
+ } while (dd->reordered == 1);
+
+ return(subset);
+
+} /* end of Cudd_BiasedUnderApprox */
+
+
+/**Function********************************************************************
+
+ Synopsis [Extracts a dense superset from a BDD with the biased
+ underapproximation method.]
+
+ Description [Extracts a dense superset from a BDD. The procedure is
+ identical to the underapproximation procedure except for the fact that it
+ works on the complement of the given function. Extracting the subset
+ of the complement function is equivalent to extracting the superset
+ of the function.
+ Returns a pointer to the BDD of the superset if successful. NULL if
+ intermediate result causes the procedure to run out of memory. The
+ parameter numVars is the maximum number of variables to be used in
+ minterm calculation. The optimal number
+ should be as close as possible to the size of the support of f.
+ However, it is safe to pass the value returned by Cudd_ReadSize for
+ numVars when the number of variables is under 1023. If numVars is
+ larger than 1023, it will overflow. If a 0 parameter is passed then
+ the procedure will compute a value which will avoid overflow but
+ will cause underflow with 2046 variables or more.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SupersetHeavyBranch Cudd_SupersetShortPaths
+ Cudd_RemapOverApprox Cudd_BiasedUnderApprox Cudd_ReadSize]
+
+******************************************************************************/
+DdNode *
+Cudd_BiasedOverApprox(
+ DdManager *dd /* manager */,
+ DdNode *f /* function to be superset */,
+ DdNode *b /* bias function */,
+ int numVars /* number of variables in the support of f */,
+ int threshold /* when to stop approximation */,
+ double quality1 /* minimum improvement for accepted changes when b=1*/,
+ double quality0 /* minimum improvement for accepted changes when b=0 */)
+{
+ DdNode *subset, *g;
+
+ g = Cudd_Not(f);
+ do {
+ dd->reordered = 0;
+ subset = cuddBiasedUnderApprox(dd, g, b, numVars, threshold, quality1,
+ quality0);
+ } while (dd->reordered == 1);
+
+ return(Cudd_NotCond(subset, (subset != NULL)));
+
+} /* end of Cudd_BiasedOverApprox */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Applies Tom Shiple's underappoximation algorithm.]
+
+ Description [Applies Tom Shiple's underappoximation algorithm. Proceeds
+ in three phases:
+ <ul>
+ <li> collect information on each node in the BDD; this is done via DFS.
+ <li> traverse the BDD in top-down fashion and compute for each node
+ whether its elimination increases density.
+ <li> traverse the BDD via DFS and actually perform the elimination.
+ </ul>
+ Returns the approximated BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_UnderApprox]
+
+******************************************************************************/
+DdNode *
+cuddUnderApprox(
+ DdManager * dd /* DD manager */,
+ DdNode * f /* current DD */,
+ int numVars /* maximum number of variables */,
+ int threshold /* threshold under which approximation stops */,
+ int safe /* enforce safe approximation */,
+ double quality /* minimum improvement for accepted changes */)
+{
+ ApproxInfo *info;
+ DdNode *subset;
+ int result;
+
+ if (f == NULL) {
+ fprintf(dd->err, "Cannot subset, nil object\n");
+ return(NULL);
+ }
+
+ if (Cudd_IsConstant(f)) {
+ return(f);
+ }
+
+ /* Create table where node data are accessible via a hash table. */
+ info = gatherInfo(dd, f, numVars, safe);
+ if (info == NULL) {
+ (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ /* Mark nodes that should be replaced by zero. */
+ result = UAmarkNodes(dd, f, info, threshold, safe, quality);
+ if (result == 0) {
+ (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
+ FREE(info->page);
+ st_free_table(info->table);
+ FREE(info);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ /* Build the result. */
+ subset = UAbuildSubset(dd, f, info);
+#if 1
+ if (subset && info->size < Cudd_DagSize(subset))
+ (void) fprintf(dd->err, "Wrong prediction: %d versus actual %d\n",
+ info->size, Cudd_DagSize(subset));
+#endif
+ FREE(info->page);
+ st_free_table(info->table);
+ FREE(info);
+
+#ifdef DD_DEBUG
+ if (subset != NULL) {
+ cuddRef(subset);
+#if 0
+ (void) Cudd_DebugCheck(dd);
+ (void) Cudd_CheckKeys(dd);
+#endif
+ if (!Cudd_bddLeq(dd, subset, f)) {
+ (void) fprintf(dd->err, "Wrong subset\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ }
+ cuddDeref(subset);
+ }
+#endif
+ return(subset);
+
+} /* end of cuddUnderApprox */
+
+
+/**Function********************************************************************
+
+ Synopsis [Applies the remapping underappoximation algorithm.]
+
+ Description [Applies the remapping underappoximation algorithm.
+ Proceeds in three phases:
+ <ul>
+ <li> collect information on each node in the BDD; this is done via DFS.
+ <li> traverse the BDD in top-down fashion and compute for each node
+ whether remapping increases density.
+ <li> traverse the BDD via DFS and actually perform the elimination.
+ </ul>
+ Returns the approximated BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_RemapUnderApprox]
+
+******************************************************************************/
+DdNode *
+cuddRemapUnderApprox(
+ DdManager * dd /* DD manager */,
+ DdNode * f /* current DD */,
+ int numVars /* maximum number of variables */,
+ int threshold /* threshold under which approximation stops */,
+ double quality /* minimum improvement for accepted changes */)
+{
+ ApproxInfo *info;
+ DdNode *subset;
+ int result;
+
+ if (f == NULL) {
+ fprintf(dd->err, "Cannot subset, nil object\n");
+ dd->errorCode = CUDD_INVALID_ARG;
+ return(NULL);
+ }
+
+ if (Cudd_IsConstant(f)) {
+ return(f);
+ }
+
+ /* Create table where node data are accessible via a hash table. */
+ info = gatherInfo(dd, f, numVars, TRUE);
+ if (info == NULL) {
+ (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ /* Mark nodes that should be replaced by zero. */
+ result = RAmarkNodes(dd, f, info, threshold, quality);
+ if (result == 0) {
+ (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
+ FREE(info->page);
+ st_free_table(info->table);
+ FREE(info);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ /* Build the result. */
+ subset = RAbuildSubset(dd, f, info);
+#if 1
+ if (subset && info->size < Cudd_DagSize(subset))
+ (void) fprintf(dd->err, "Wrong prediction: %d versus actual %d\n",
+ info->size, Cudd_DagSize(subset));
+#endif
+ FREE(info->page);
+ st_free_table(info->table);
+ FREE(info);
+
+#ifdef DD_DEBUG
+ if (subset != NULL) {
+ cuddRef(subset);
+#if 0
+ (void) Cudd_DebugCheck(dd);
+ (void) Cudd_CheckKeys(dd);
+#endif
+ if (!Cudd_bddLeq(dd, subset, f)) {
+ (void) fprintf(dd->err, "Wrong subset\n");
+ }
+ cuddDeref(subset);
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ }
+#endif
+ return(subset);
+
+} /* end of cuddRemapUnderApprox */
+
+
+/**Function********************************************************************
+
+ Synopsis [Applies the biased remapping underappoximation algorithm.]
+
+ Description [Applies the biased remapping underappoximation algorithm.
+ Proceeds in three phases:
+ <ul>
+ <li> collect information on each node in the BDD; this is done via DFS.
+ <li> traverse the BDD in top-down fashion and compute for each node
+ whether remapping increases density.
+ <li> traverse the BDD via DFS and actually perform the elimination.
+ </ul>
+ Returns the approximated BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_BiasedUnderApprox]
+
+******************************************************************************/
+DdNode *
+cuddBiasedUnderApprox(
+ DdManager *dd /* DD manager */,
+ DdNode *f /* current DD */,
+ DdNode *b /* bias function */,
+ int numVars /* maximum number of variables */,
+ int threshold /* threshold under which approximation stops */,
+ double quality1 /* minimum improvement for accepted changes when b=1 */,
+ double quality0 /* minimum improvement for accepted changes when b=1 */)
+{
+ ApproxInfo *info;
+ DdNode *subset;
+ int result;
+ DdHashTable *cache;
+
+ if (f == NULL) {
+ fprintf(dd->err, "Cannot subset, nil object\n");
+ dd->errorCode = CUDD_INVALID_ARG;
+ return(NULL);
+ }
+
+ if (Cudd_IsConstant(f)) {
+ return(f);
+ }
+
+ /* Create table where node data are accessible via a hash table. */
+ info = gatherInfo(dd, f, numVars, TRUE);
+ if (info == NULL) {
+ (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ cache = cuddHashTableInit(dd,2,2);
+ result = BAapplyBias(dd, Cudd_Regular(f), b, info, cache);
+ if (result == CARE_ERROR) {
+ (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
+ cuddHashTableQuit(cache);
+ FREE(info->page);
+ st_free_table(info->table);
+ FREE(info);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ cuddHashTableQuit(cache);
+
+ /* Mark nodes that should be replaced by zero. */
+ result = BAmarkNodes(dd, f, info, threshold, quality1, quality0);
+ if (result == 0) {
+ (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
+ FREE(info->page);
+ st_free_table(info->table);
+ FREE(info);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ /* Build the result. */
+ subset = RAbuildSubset(dd, f, info);
+#if 1
+ if (subset && info->size < Cudd_DagSize(subset))
+ (void) fprintf(dd->err, "Wrong prediction: %d versus actual %d\n",
+ info->size, Cudd_DagSize(subset));
+#endif
+ FREE(info->page);
+ st_free_table(info->table);
+ FREE(info);
+
+#ifdef DD_DEBUG
+ if (subset != NULL) {
+ cuddRef(subset);
+#if 0
+ (void) Cudd_DebugCheck(dd);
+ (void) Cudd_CheckKeys(dd);
+#endif
+ if (!Cudd_bddLeq(dd, subset, f)) {
+ (void) fprintf(dd->err, "Wrong subset\n");
+ }
+ cuddDeref(subset);
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ }
+#endif
+ return(subset);
+
+} /* end of cuddBiasedUnderApprox */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Recursively update the parity of the paths reaching a node.]
+
+ Description [Recursively update the parity of the paths reaching a node.
+ Assumes that node is regular and propagates the invariant.]
+
+ SideEffects [None]
+
+ SeeAlso [gatherInfoAux]
+
+******************************************************************************/
+static void
+updateParity(
+ DdNode * node /* function to analyze */,
+ ApproxInfo * info /* info on BDD */,
+ int newparity /* new parity for node */)
+{
+ NodeData *infoN;
+ DdNode *E;
+
+ if (!st_lookup(info->table, (char *)node, (char **)&infoN)) return;
+ if ((infoN->parity & newparity) != 0) return;
+ infoN->parity |= newparity;
+ if (Cudd_IsConstant(node)) return;
+ updateParity(cuddT(node),info,newparity);
+ E = cuddE(node);
+ if (Cudd_IsComplement(E)) {
+ updateParity(Cudd_Not(E),info,3-newparity);
+ } else {
+ updateParity(E,info,newparity);
+ }
+ return;
+
+} /* end of updateParity */
+
+
+/**Function********************************************************************
+
+ Synopsis [Recursively counts minterms and computes reference counts
+ of each node in the BDD.]
+
+ Description [Recursively counts minterms and computes reference
+ counts of each node in the BDD. Similar to the cuddCountMintermAux
+ which recursively counts the number of minterms for the dag rooted
+ at each node in terms of the total number of variables (max). It assumes
+ that the node pointer passed to it is regular and it maintains the
+ invariant.]
+
+ SideEffects [None]
+
+ SeeAlso [gatherInfo]
+
+******************************************************************************/
+static NodeData *
+gatherInfoAux(
+ DdNode * node /* function to analyze */,
+ ApproxInfo * info /* info on BDD */,
+ int parity /* gather parity information */)
+{
+ DdNode *N, *Nt, *Ne;
+ NodeData *infoN, *infoT, *infoE;
+
+ N = Cudd_Regular(node);
+
+ /* Check whether entry for this node exists. */
+ if (st_lookup(info->table, (char *)N, (char **)&infoN)) {
+ if (parity) {
+ /* Update parity and propagate. */
+ updateParity(N, info, 1 + (int) Cudd_IsComplement(node));
+ }
+ return(infoN);
+ }
+
+ /* Compute the cofactors. */
+ Nt = Cudd_NotCond(cuddT(N), N != node);
+ Ne = Cudd_NotCond(cuddE(N), N != node);
+
+ infoT = gatherInfoAux(Nt, info, parity);
+ if (infoT == NULL) return(NULL);
+ infoE = gatherInfoAux(Ne, info, parity);
+ if (infoE == NULL) return(NULL);
+
+ infoT->functionRef++;
+ infoE->functionRef++;
+
+ /* Point to the correct location in the page. */
+ infoN = &(info->page[info->index++]);
+ infoN->parity |= 1 + (short) Cudd_IsComplement(node);
+
+ infoN->mintermsP = infoT->mintermsP/2;
+ infoN->mintermsN = infoT->mintermsN/2;
+ if (Cudd_IsComplement(Ne) ^ Cudd_IsComplement(node)) {
+ infoN->mintermsP += infoE->mintermsN/2;
+ infoN->mintermsN += infoE->mintermsP/2;
+ } else {
+ infoN->mintermsP += infoE->mintermsP/2;
+ infoN->mintermsN += infoE->mintermsN/2;
+ }
+
+ /* Insert entry for the node in the table. */
+ if (st_insert(info->table,(char *)N, (char *)infoN) == ST_OUT_OF_MEM) {
+ return(NULL);
+ }
+ return(infoN);
+
+} /* end of gatherInfoAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Gathers information about each node.]
+
+ Description [Counts minterms and computes reference counts of each
+ node in the BDD . The minterm count is separately computed for the
+ node and its complement. This is to avoid cancellation
+ errors. Returns a pointer to the data structure holding the
+ information gathered if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddUnderApprox gatherInfoAux]
+
+******************************************************************************/
+static ApproxInfo *
+gatherInfo(
+ DdManager * dd /* manager */,
+ DdNode * node /* function to be analyzed */,
+ int numVars /* number of variables node depends on */,
+ int parity /* gather parity information */)
+{
+ ApproxInfo *info;
+ NodeData *infoTop;
+
+ /* If user did not give numVars value, set it to the maximum
+ ** exponent that the pow function can take. The -1 is due to the
+ ** discrepancy in the value that pow takes and the value that
+ ** log gives.
+ */
+ if (numVars == 0) {
+ numVars = DBL_MAX_EXP - 1;
+ }
+
+ info = ALLOC(ApproxInfo,1);
+ if (info == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ info->max = pow(2.0,(double) numVars);
+ info->one = DD_ONE(dd);
+ info->zero = Cudd_Not(info->one);
+ info->size = Cudd_DagSize(node);
+ /* All the information gathered will be stored in a contiguous
+ ** piece of memory, which is allocated here. This can be done
+ ** efficiently because we have counted the number of nodes of the
+ ** BDD. info->index points to the next available entry in the array
+ ** that stores the per-node information. */
+ info->page = ALLOC(NodeData,info->size);
+ if (info->page == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ FREE(info);
+ return(NULL);
+ }
+ memset(info->page, 0, info->size * sizeof(NodeData)); /* clear all page */
+ info->table = st_init_table(st_ptrcmp,st_ptrhash);
+ if (info->table == NULL) {
+ FREE(info->page);
+ FREE(info);
+ return(NULL);
+ }
+ /* We visit the DAG in post-order DFS. Hence, the constant node is
+ ** in first position, and the root of the DAG is in last position. */
+
+ /* Info for the constant node: Initialize only fields different from 0. */
+ if (st_insert(info->table, (char *)info->one, (char *)info->page) == ST_OUT_OF_MEM) {
+ FREE(info->page);
+ FREE(info);
+ st_free_table(info->table);
+ return(NULL);
+ }
+ info->page[0].mintermsP = info->max;
+ info->index = 1;
+
+ infoTop = gatherInfoAux(node,info,parity);
+ if (infoTop == NULL) {
+ FREE(info->page);
+ st_free_table(info->table);
+ FREE(info);
+ return(NULL);
+ }
+ if (Cudd_IsComplement(node)) {
+ info->minterms = infoTop->mintermsN;
+ } else {
+ info->minterms = infoTop->mintermsP;
+ }
+
+ infoTop->functionRef = 1;
+ return(info);
+
+} /* end of gatherInfo */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the nodes that would be eliminated if a given node
+ were replaced by zero.]
+
+ Description [Counts the nodes that would be eliminated if a given
+ node were replaced by zero. This procedure uses a queue passed by
+ the caller for efficiency: since the queue is left empty at the
+ endof the search, it can be reused as is by the next search. Returns
+ the count (always striclty positive) if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddUnderApprox]
+
+******************************************************************************/
+static int
+computeSavings(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * skip,
+ ApproxInfo * info,
+ DdLevelQueue * queue)
+{
+ NodeData *infoN;
+ LocalQueueItem *item;
+ DdNode *node;
+ int savings = 0;
+
+ node = Cudd_Regular(f);
+ skip = Cudd_Regular(skip);
+ /* Insert the given node in the level queue. Its local reference
+ ** count is set equal to the function reference count so that the
+ ** search will continue from it when it is retrieved. */
+ item = (LocalQueueItem *)
+ cuddLevelQueueEnqueue(queue,node,cuddI(dd,node->index));
+ if (item == NULL)
+ return(0);
+ (void) st_lookup(info->table, (char *)node, (char **)&infoN);
+ item->localRef = infoN->functionRef;
+
+ /* Process the queue. */
+ while (queue->first != NULL) {
+ item = (LocalQueueItem *) queue->first;
+ node = item->node;
+ cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
+ if (node == skip) continue;
+ (void) st_lookup(info->table, (char *)node, (char **)&infoN);
+ if (item->localRef != infoN->functionRef) {
+ /* This node is shared. */
+ continue;
+ }
+ savings++;
+ if (!cuddIsConstant(cuddT(node))) {
+ item = (LocalQueueItem *) cuddLevelQueueEnqueue(queue,cuddT(node),
+ cuddI(dd,cuddT(node)->index));
+ if (item == NULL) return(0);
+ item->localRef++;
+ }
+ if (!Cudd_IsConstant(cuddE(node))) {
+ item = (LocalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(cuddE(node)),
+ cuddI(dd,Cudd_Regular(cuddE(node))->index));
+ if (item == NULL) return(0);
+ item->localRef++;
+ }
+ }
+
+#ifdef DD_DEBUG
+ /* At the end of a local search the queue should be empty. */
+ assert(queue->size == 0);
+#endif
+ return(savings);
+
+} /* end of computeSavings */
+
+
+/**Function********************************************************************
+
+ Synopsis [Update function reference counts.]
+
+ Description [Update function reference counts to account for replacement.
+ Returns the number of nodes saved if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [UAmarkNodes RAmarkNodes]
+
+******************************************************************************/
+static int
+updateRefs(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * skip,
+ ApproxInfo * info,
+ DdLevelQueue * queue)
+{
+ NodeData *infoN;
+ LocalQueueItem *item;
+ DdNode *node;
+ int savings = 0;
+
+ node = Cudd_Regular(f);
+ /* Insert the given node in the level queue. Its function reference
+ ** count is set equal to 0 so that the search will continue from it
+ ** when it is retrieved. */
+ item = (LocalQueueItem *) cuddLevelQueueEnqueue(queue,node,cuddI(dd,node->index));
+ if (item == NULL)
+ return(0);
+ (void) st_lookup(info->table, (char *)node, (char **)&infoN);
+ infoN->functionRef = 0;
+
+ if (skip != NULL) {
+ /* Increase the function reference count of the node to be skipped
+ ** by 1 to account for the node pointing to it that will be created. */
+ skip = Cudd_Regular(skip);
+ (void) st_lookup(info->table, (char *)skip, (char **)&infoN);
+ infoN->functionRef++;
+ }
+
+ /* Process the queue. */
+ while (queue->first != NULL) {
+ item = (LocalQueueItem *) queue->first;
+ node = item->node;
+ cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
+ (void) st_lookup(info->table, (char *)node, (char **)&infoN);
+ if (infoN->functionRef != 0) {
+ /* This node is shared or must be skipped. */
+ continue;
+ }
+ savings++;
+ if (!cuddIsConstant(cuddT(node))) {
+ item = (LocalQueueItem *) cuddLevelQueueEnqueue(queue,cuddT(node),
+ cuddI(dd,cuddT(node)->index));
+ if (item == NULL) return(0);
+ (void) st_lookup(info->table, (char *)cuddT(node),
+ (char **)&infoN);
+ infoN->functionRef--;
+ }
+ if (!Cudd_IsConstant(cuddE(node))) {
+ item = (LocalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(cuddE(node)),
+ cuddI(dd,Cudd_Regular(cuddE(node))->index));
+ if (item == NULL) return(0);
+ (void) st_lookup(info->table, (char *)Cudd_Regular(cuddE(node)),
+ (char **)&infoN);
+ infoN->functionRef--;
+ }
+ }
+
+#ifdef DD_DEBUG
+ /* At the end of a local search the queue should be empty. */
+ assert(queue->size == 0);
+#endif
+ return(savings);
+
+} /* end of updateRefs */
+
+
+/**Function********************************************************************
+
+ Synopsis [Marks nodes for replacement by zero.]
+
+ Description [Marks nodes for replacement by zero. Returns 1 if successful;
+ 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddUnderApprox]
+
+******************************************************************************/
+static int
+UAmarkNodes(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be analyzed */,
+ ApproxInfo * info /* info on BDD */,
+ int threshold /* when to stop approximating */,
+ int safe /* enforce safe approximation */,
+ double quality /* minimum improvement for accepted changes */)
+{
+ DdLevelQueue *queue;
+ DdLevelQueue *localQueue;
+ NodeData *infoN;
+ GlobalQueueItem *item;
+ DdNode *node;
+ double numOnset;
+ double impactP, impactN;
+ int savings;
+
+#if 0
+ (void) printf("initial size = %d initial minterms = %g\n",
+ info->size, info->minterms);
+#endif
+ queue = cuddLevelQueueInit(dd->size,sizeof(GlobalQueueItem),info->size);
+ if (queue == NULL) {
+ return(0);
+ }
+ localQueue = cuddLevelQueueInit(dd->size,sizeof(LocalQueueItem),
+ dd->initSlots);
+ if (localQueue == NULL) {
+ cuddLevelQueueQuit(queue);
+ return(0);
+ }
+ node = Cudd_Regular(f);
+ item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,node,cuddI(dd,node->index));
+ if (item == NULL) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ if (Cudd_IsComplement(f)) {
+ item->impactP = 0.0;
+ item->impactN = 1.0;
+ } else {
+ item->impactP = 1.0;
+ item->impactN = 0.0;
+ }
+ while (queue->first != NULL) {
+ /* If the size of the subset is below the threshold, quit. */
+ if (info->size <= threshold)
+ break;
+ item = (GlobalQueueItem *) queue->first;
+ node = item->node;
+ node = Cudd_Regular(node);
+ (void) st_lookup(info->table, (char *)node, (char **)&infoN);
+ if (safe && infoN->parity == 3) {
+ cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
+ continue;
+ }
+ impactP = item->impactP;
+ impactN = item->impactN;
+ numOnset = infoN->mintermsP * impactP + infoN->mintermsN * impactN;
+ savings = computeSavings(dd,node,NULL,info,localQueue);
+ if (savings == 0) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
+#if 0
+ (void) printf("node %p: impact = %g/%g numOnset = %g savings %d\n",
+ node, impactP, impactN, numOnset, savings);
+#endif
+ if ((1 - numOnset / info->minterms) >
+ quality * (1 - (double) savings / info->size)) {
+ infoN->replace = TRUE;
+ info->size -= savings;
+ info->minterms -=numOnset;
+#if 0
+ (void) printf("replace: new size = %d new minterms = %g\n",
+ info->size, info->minterms);
+#endif
+ savings -= updateRefs(dd,node,NULL,info,localQueue);
+ assert(savings == 0);
+ continue;
+ }
+ if (!cuddIsConstant(cuddT(node))) {
+ item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,cuddT(node),
+ cuddI(dd,cuddT(node)->index));
+ item->impactP += impactP/2.0;
+ item->impactN += impactN/2.0;
+ }
+ if (!Cudd_IsConstant(cuddE(node))) {
+ item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(cuddE(node)),
+ cuddI(dd,Cudd_Regular(cuddE(node))->index));
+ if (Cudd_IsComplement(cuddE(node))) {
+ item->impactP += impactN/2.0;
+ item->impactN += impactP/2.0;
+ } else {
+ item->impactP += impactP/2.0;
+ item->impactN += impactN/2.0;
+ }
+ }
+ }
+
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(1);
+
+} /* end of UAmarkNodes */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds the subset BDD.]
+
+ Description [Builds the subset BDD. Based on the info table,
+ replaces selected nodes by zero. Returns a pointer to the result if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddUnderApprox]
+
+******************************************************************************/
+static DdNode *
+UAbuildSubset(
+ DdManager * dd /* DD manager */,
+ DdNode * node /* current node */,
+ ApproxInfo * info /* node info */)
+{
+
+ DdNode *Nt, *Ne, *N, *t, *e, *r;
+ NodeData *infoN;
+
+ if (Cudd_IsConstant(node))
+ return(node);
+
+ N = Cudd_Regular(node);
+
+ if (st_lookup(info->table, (char *)N, (char **)&infoN)) {
+ if (infoN->replace == TRUE) {
+ return(info->zero);
+ }
+ if (N == node ) {
+ if (infoN->resultP != NULL) {
+ return(infoN->resultP);
+ }
+ } else {
+ if (infoN->resultN != NULL) {
+ return(infoN->resultN);
+ }
+ }
+ } else {
+ (void) fprintf(dd->err,
+ "Something is wrong, ought to be in info table\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+
+ Nt = Cudd_NotCond(cuddT(N), Cudd_IsComplement(node));
+ Ne = Cudd_NotCond(cuddE(N), Cudd_IsComplement(node));
+
+ t = UAbuildSubset(dd, Nt, info);
+ if (t == NULL) {
+ return(NULL);
+ }
+ cuddRef(t);
+
+ e = UAbuildSubset(dd, Ne, info);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd,t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ if (Cudd_IsComplement(t)) {
+ t = Cudd_Not(t);
+ e = Cudd_Not(e);
+ r = (t == e) ? t : cuddUniqueInter(dd, N->index, t, e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, e);
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = (t == e) ? t : cuddUniqueInter(dd, N->index, t, e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, e);
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ if (N == node) {
+ infoN->resultP = r;
+ } else {
+ infoN->resultN = r;
+ }
+
+ return(r);
+
+} /* end of UAbuildSubset */
+
+
+/**Function********************************************************************
+
+ Synopsis [Marks nodes for remapping.]
+
+ Description [Marks nodes for remapping. Returns 1 if successful; 0
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddRemapUnderApprox]
+
+******************************************************************************/
+static int
+RAmarkNodes(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be analyzed */,
+ ApproxInfo * info /* info on BDD */,
+ int threshold /* when to stop approximating */,
+ double quality /* minimum improvement for accepted changes */)
+{
+ DdLevelQueue *queue;
+ DdLevelQueue *localQueue;
+ NodeData *infoN, *infoT, *infoE;
+ GlobalQueueItem *item;
+ DdNode *node, *T, *E;
+ DdNode *shared; /* grandchild shared by the two children of node */
+ double numOnset;
+ double impact, impactP, impactN;
+ double minterms;
+ int savings;
+ int replace;
+
+#if 0
+ (void) fprintf(dd->out,"initial size = %d initial minterms = %g\n",
+ info->size, info->minterms);
+#endif
+ queue = cuddLevelQueueInit(dd->size,sizeof(GlobalQueueItem),info->size);
+ if (queue == NULL) {
+ return(0);
+ }
+ localQueue = cuddLevelQueueInit(dd->size,sizeof(LocalQueueItem),
+ dd->initSlots);
+ if (localQueue == NULL) {
+ cuddLevelQueueQuit(queue);
+ return(0);
+ }
+ /* Enqueue regular pointer to root and initialize impact. */
+ node = Cudd_Regular(f);
+ item = (GlobalQueueItem *)
+ cuddLevelQueueEnqueue(queue,node,cuddI(dd,node->index));
+ if (item == NULL) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ if (Cudd_IsComplement(f)) {
+ item->impactP = 0.0;
+ item->impactN = 1.0;
+ } else {
+ item->impactP = 1.0;
+ item->impactN = 0.0;
+ }
+ /* The nodes retrieved here are guaranteed to be non-terminal.
+ ** The initial node is not terminal because constant nodes are
+ ** dealt with in the calling procedure. Subsequent nodes are inserted
+ ** only if they are not terminal. */
+ while (queue->first != NULL) {
+ /* If the size of the subset is below the threshold, quit. */
+ if (info->size <= threshold)
+ break;
+ item = (GlobalQueueItem *) queue->first;
+ node = item->node;
+#ifdef DD_DEBUG
+ assert(item->impactP >= 0 && item->impactP <= 1.0);
+ assert(item->impactN >= 0 && item->impactN <= 1.0);
+ assert(!Cudd_IsComplement(node));
+ assert(!Cudd_IsConstant(node));
+#endif
+ if (!st_lookup(info->table, (char *)node, (char **)&infoN)) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+#ifdef DD_DEBUG
+ assert(infoN->parity >= 1 && infoN->parity <= 3);
+#endif
+ if (infoN->parity == 3) {
+ /* This node can be reached through paths of different parity.
+ ** It is not safe to replace it, because remapping will give
+ ** an incorrect result, while replacement by 0 may cause node
+ ** splitting. */
+ cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
+ continue;
+ }
+ T = cuddT(node);
+ E = cuddE(node);
+ shared = NULL;
+ impactP = item->impactP;
+ impactN = item->impactN;
+ if (Cudd_bddLeq(dd,T,E)) {
+ /* Here we know that E is regular. */
+#ifdef DD_DEBUG
+ assert(!Cudd_IsComplement(E));
+#endif
+ (void) st_lookup(info->table, (char *)T, (char **)&infoT);
+ (void) st_lookup(info->table, (char *)E, (char **)&infoE);
+ if (infoN->parity == 1) {
+ impact = impactP;
+ minterms = infoE->mintermsP/2.0 - infoT->mintermsP/2.0;
+ if (infoE->functionRef == 1 && !Cudd_IsConstant(E)) {
+ savings = 1 + computeSavings(dd,E,NULL,info,localQueue);
+ if (savings == 1) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ } else {
+ savings = 1;
+ }
+ replace = REPLACE_E;
+ } else {
+#ifdef DD_DEBUG
+ assert(infoN->parity == 2);
+#endif
+ impact = impactN;
+ minterms = infoT->mintermsN/2.0 - infoE->mintermsN/2.0;
+ if (infoT->functionRef == 1 && !Cudd_IsConstant(T)) {
+ savings = 1 + computeSavings(dd,T,NULL,info,localQueue);
+ if (savings == 1) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ } else {
+ savings = 1;
+ }
+ replace = REPLACE_T;
+ }
+ numOnset = impact * minterms;
+ } else if (Cudd_bddLeq(dd,E,T)) {
+ /* Here E may be complemented. */
+ DdNode *Ereg = Cudd_Regular(E);
+ (void) st_lookup(info->table, (char *)T, (char **)&infoT);
+ (void) st_lookup(info->table, (char *)Ereg, (char **)&infoE);
+ if (infoN->parity == 1) {
+ impact = impactP;
+ minterms = infoT->mintermsP/2.0 -
+ ((E == Ereg) ? infoE->mintermsP : infoE->mintermsN)/2.0;
+ if (infoT->functionRef == 1 && !Cudd_IsConstant(T)) {
+ savings = 1 + computeSavings(dd,T,NULL,info,localQueue);
+ if (savings == 1) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ } else {
+ savings = 1;
+ }
+ replace = REPLACE_T;
+ } else {
+#ifdef DD_DEBUG
+ assert(infoN->parity == 2);
+#endif
+ impact = impactN;
+ minterms = ((E == Ereg) ? infoE->mintermsN :
+ infoE->mintermsP)/2.0 - infoT->mintermsN/2.0;
+ if (infoE->functionRef == 1 && !Cudd_IsConstant(E)) {
+ savings = 1 + computeSavings(dd,E,NULL,info,localQueue);
+ if (savings == 1) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ } else {
+ savings = 1;
+ }
+ replace = REPLACE_E;
+ }
+ numOnset = impact * minterms;
+ } else {
+ DdNode *Ereg = Cudd_Regular(E);
+ DdNode *TT = cuddT(T);
+ DdNode *ET = Cudd_NotCond(cuddT(Ereg), Cudd_IsComplement(E));
+ if (T->index == Ereg->index && TT == ET) {
+ shared = TT;
+ replace = REPLACE_TT;
+ } else {
+ DdNode *TE = cuddE(T);
+ DdNode *EE = Cudd_NotCond(cuddE(Ereg), Cudd_IsComplement(E));
+ if (T->index == Ereg->index && TE == EE) {
+ shared = TE;
+ replace = REPLACE_TE;
+ } else {
+ replace = REPLACE_N;
+ }
+ }
+ numOnset = infoN->mintermsP * impactP + infoN->mintermsN * impactN;
+ savings = computeSavings(dd,node,shared,info,localQueue);
+ if (shared != NULL) {
+ NodeData *infoS;
+ (void) st_lookup(info->table, (char *)Cudd_Regular(shared),
+ (char **)&infoS);
+ if (Cudd_IsComplement(shared)) {
+ numOnset -= (infoS->mintermsN * impactP +
+ infoS->mintermsP * impactN)/2.0;
+ } else {
+ numOnset -= (infoS->mintermsP * impactP +
+ infoS->mintermsN * impactN)/2.0;
+ }
+ savings--;
+ }
+ }
+
+ cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
+#if 0
+ if (replace == REPLACE_T || replace == REPLACE_E)
+ (void) printf("node %p: impact = %g numOnset = %g savings %d\n",
+ node, impact, numOnset, savings);
+ else
+ (void) printf("node %p: impact = %g/%g numOnset = %g savings %d\n",
+ node, impactP, impactN, numOnset, savings);
+#endif
+ if ((1 - numOnset / info->minterms) >
+ quality * (1 - (double) savings / info->size)) {
+ infoN->replace = replace;
+ info->size -= savings;
+ info->minterms -=numOnset;
+#if 0
+ (void) printf("remap(%d): new size = %d new minterms = %g\n",
+ replace, info->size, info->minterms);
+#endif
+ if (replace == REPLACE_N) {
+ savings -= updateRefs(dd,node,NULL,info,localQueue);
+ } else if (replace == REPLACE_T) {
+ savings -= updateRefs(dd,node,E,info,localQueue);
+ } else if (replace == REPLACE_E) {
+ savings -= updateRefs(dd,node,T,info,localQueue);
+ } else {
+#ifdef DD_DEBUG
+ assert(replace == REPLACE_TT || replace == REPLACE_TE);
+#endif
+ savings -= updateRefs(dd,node,shared,info,localQueue) - 1;
+ }
+ assert(savings == 0);
+ } else {
+ replace = NOTHING;
+ }
+ if (replace == REPLACE_N) continue;
+ if ((replace == REPLACE_E || replace == NOTHING) &&
+ !cuddIsConstant(cuddT(node))) {
+ item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,cuddT(node),
+ cuddI(dd,cuddT(node)->index));
+ if (replace == REPLACE_E) {
+ item->impactP += impactP;
+ item->impactN += impactN;
+ } else {
+ item->impactP += impactP/2.0;
+ item->impactN += impactN/2.0;
+ }
+ }
+ if ((replace == REPLACE_T || replace == NOTHING) &&
+ !Cudd_IsConstant(cuddE(node))) {
+ item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(cuddE(node)),
+ cuddI(dd,Cudd_Regular(cuddE(node))->index));
+ if (Cudd_IsComplement(cuddE(node))) {
+ if (replace == REPLACE_T) {
+ item->impactP += impactN;
+ item->impactN += impactP;
+ } else {
+ item->impactP += impactN/2.0;
+ item->impactN += impactP/2.0;
+ }
+ } else {
+ if (replace == REPLACE_T) {
+ item->impactP += impactP;
+ item->impactN += impactN;
+ } else {
+ item->impactP += impactP/2.0;
+ item->impactN += impactN/2.0;
+ }
+ }
+ }
+ if ((replace == REPLACE_TT || replace == REPLACE_TE) &&
+ !Cudd_IsConstant(shared)) {
+ item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(shared),
+ cuddI(dd,Cudd_Regular(shared)->index));
+ if (Cudd_IsComplement(shared)) {
+ if (replace == REPLACE_T) {
+ item->impactP += impactN;
+ item->impactN += impactP;
+ } else {
+ item->impactP += impactN/2.0;
+ item->impactN += impactP/2.0;
+ }
+ } else {
+ if (replace == REPLACE_T) {
+ item->impactP += impactP;
+ item->impactN += impactN;
+ } else {
+ item->impactP += impactP/2.0;
+ item->impactN += impactN/2.0;
+ }
+ }
+ }
+ }
+
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(1);
+
+} /* end of RAmarkNodes */
+
+
+/**Function********************************************************************
+
+ Synopsis [Marks nodes for remapping.]
+
+ Description [Marks nodes for remapping. Returns 1 if successful; 0
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddRemapUnderApprox]
+
+******************************************************************************/
+static int
+BAmarkNodes(
+ DdManager *dd /* manager */,
+ DdNode *f /* function to be analyzed */,
+ ApproxInfo *info /* info on BDD */,
+ int threshold /* when to stop approximating */,
+ double quality1 /* minimum improvement for accepted changes when b=1 */,
+ double quality0 /* minimum improvement for accepted changes when b=0 */)
+{
+ DdLevelQueue *queue;
+ DdLevelQueue *localQueue;
+ NodeData *infoN, *infoT, *infoE;
+ GlobalQueueItem *item;
+ DdNode *node, *T, *E;
+ DdNode *shared; /* grandchild shared by the two children of node */
+ double numOnset;
+ double impact, impactP, impactN;
+ double minterms;
+ double quality;
+ int savings;
+ int replace;
+
+#if 0
+ (void) fprintf(dd->out,"initial size = %d initial minterms = %g\n",
+ info->size, info->minterms);
+#endif
+ queue = cuddLevelQueueInit(dd->size,sizeof(GlobalQueueItem),info->size);
+ if (queue == NULL) {
+ return(0);
+ }
+ localQueue = cuddLevelQueueInit(dd->size,sizeof(LocalQueueItem),
+ dd->initSlots);
+ if (localQueue == NULL) {
+ cuddLevelQueueQuit(queue);
+ return(0);
+ }
+ /* Enqueue regular pointer to root and initialize impact. */
+ node = Cudd_Regular(f);
+ item = (GlobalQueueItem *)
+ cuddLevelQueueEnqueue(queue,node,cuddI(dd,node->index));
+ if (item == NULL) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ if (Cudd_IsComplement(f)) {
+ item->impactP = 0.0;
+ item->impactN = 1.0;
+ } else {
+ item->impactP = 1.0;
+ item->impactN = 0.0;
+ }
+ /* The nodes retrieved here are guaranteed to be non-terminal.
+ ** The initial node is not terminal because constant nodes are
+ ** dealt with in the calling procedure. Subsequent nodes are inserted
+ ** only if they are not terminal. */
+ while (queue->first != NULL) {
+ /* If the size of the subset is below the threshold, quit. */
+ if (info->size <= threshold)
+ break;
+ item = (GlobalQueueItem *) queue->first;
+ node = item->node;
+#ifdef DD_DEBUG
+ assert(item->impactP >= 0 && item->impactP <= 1.0);
+ assert(item->impactN >= 0 && item->impactN <= 1.0);
+ assert(!Cudd_IsComplement(node));
+ assert(!Cudd_IsConstant(node));
+#endif
+ if (!st_lookup(info->table, (char *)node, (char **)&infoN)) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ quality = infoN->care ? quality1 : quality0;
+#ifdef DD_DEBUG
+ assert(infoN->parity >= 1 && infoN->parity <= 3);
+#endif
+ if (infoN->parity == 3) {
+ /* This node can be reached through paths of different parity.
+ ** It is not safe to replace it, because remapping will give
+ ** an incorrect result, while replacement by 0 may cause node
+ ** splitting. */
+ cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
+ continue;
+ }
+ T = cuddT(node);
+ E = cuddE(node);
+ shared = NULL;
+ impactP = item->impactP;
+ impactN = item->impactN;
+ if (Cudd_bddLeq(dd,T,E)) {
+ /* Here we know that E is regular. */
+#ifdef DD_DEBUG
+ assert(!Cudd_IsComplement(E));
+#endif
+ (void) st_lookup(info->table, (char *)T, (char **)&infoT);
+ (void) st_lookup(info->table, (char *)E, (char **)&infoE);
+ if (infoN->parity == 1) {
+ impact = impactP;
+ minterms = infoE->mintermsP/2.0 - infoT->mintermsP/2.0;
+ if (infoE->functionRef == 1 && !Cudd_IsConstant(E)) {
+ savings = 1 + computeSavings(dd,E,NULL,info,localQueue);
+ if (savings == 1) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ } else {
+ savings = 1;
+ }
+ replace = REPLACE_E;
+ } else {
+#ifdef DD_DEBUG
+ assert(infoN->parity == 2);
+#endif
+ impact = impactN;
+ minterms = infoT->mintermsN/2.0 - infoE->mintermsN/2.0;
+ if (infoT->functionRef == 1 && !Cudd_IsConstant(T)) {
+ savings = 1 + computeSavings(dd,T,NULL,info,localQueue);
+ if (savings == 1) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ } else {
+ savings = 1;
+ }
+ replace = REPLACE_T;
+ }
+ numOnset = impact * minterms;
+ } else if (Cudd_bddLeq(dd,E,T)) {
+ /* Here E may be complemented. */
+ DdNode *Ereg = Cudd_Regular(E);
+ (void) st_lookup(info->table, (char *)T, (char **)&infoT);
+ (void) st_lookup(info->table, (char *)Ereg, (char **)&infoE);
+ if (infoN->parity == 1) {
+ impact = impactP;
+ minterms = infoT->mintermsP/2.0 -
+ ((E == Ereg) ? infoE->mintermsP : infoE->mintermsN)/2.0;
+ if (infoT->functionRef == 1 && !Cudd_IsConstant(T)) {
+ savings = 1 + computeSavings(dd,T,NULL,info,localQueue);
+ if (savings == 1) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ } else {
+ savings = 1;
+ }
+ replace = REPLACE_T;
+ } else {
+#ifdef DD_DEBUG
+ assert(infoN->parity == 2);
+#endif
+ impact = impactN;
+ minterms = ((E == Ereg) ? infoE->mintermsN :
+ infoE->mintermsP)/2.0 - infoT->mintermsN/2.0;
+ if (infoE->functionRef == 1 && !Cudd_IsConstant(E)) {
+ savings = 1 + computeSavings(dd,E,NULL,info,localQueue);
+ if (savings == 1) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ } else {
+ savings = 1;
+ }
+ replace = REPLACE_E;
+ }
+ numOnset = impact * minterms;
+ } else {
+ DdNode *Ereg = Cudd_Regular(E);
+ DdNode *TT = cuddT(T);
+ DdNode *ET = Cudd_NotCond(cuddT(Ereg), Cudd_IsComplement(E));
+ if (T->index == Ereg->index && TT == ET) {
+ shared = TT;
+ replace = REPLACE_TT;
+ } else {
+ DdNode *TE = cuddE(T);
+ DdNode *EE = Cudd_NotCond(cuddE(Ereg), Cudd_IsComplement(E));
+ if (T->index == Ereg->index && TE == EE) {
+ shared = TE;
+ replace = REPLACE_TE;
+ } else {
+ replace = REPLACE_N;
+ }
+ }
+ numOnset = infoN->mintermsP * impactP + infoN->mintermsN * impactN;
+ savings = computeSavings(dd,node,shared,info,localQueue);
+ if (shared != NULL) {
+ NodeData *infoS;
+ (void) st_lookup(info->table, (char *)Cudd_Regular(shared),
+ (char **)&infoS);
+ if (Cudd_IsComplement(shared)) {
+ numOnset -= (infoS->mintermsN * impactP +
+ infoS->mintermsP * impactN)/2.0;
+ } else {
+ numOnset -= (infoS->mintermsP * impactP +
+ infoS->mintermsN * impactN)/2.0;
+ }
+ savings--;
+ }
+ }
+
+ cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
+#if 0
+ if (replace == REPLACE_T || replace == REPLACE_E)
+ (void) printf("node %p: impact = %g numOnset = %g savings %d\n",
+ node, impact, numOnset, savings);
+ else
+ (void) printf("node %p: impact = %g/%g numOnset = %g savings %d\n",
+ node, impactP, impactN, numOnset, savings);
+#endif
+ if ((1 - numOnset / info->minterms) >
+ quality * (1 - (double) savings / info->size)) {
+ infoN->replace = replace;
+ info->size -= savings;
+ info->minterms -=numOnset;
+#if 0
+ (void) printf("remap(%d): new size = %d new minterms = %g\n",
+ replace, info->size, info->minterms);
+#endif
+ if (replace == REPLACE_N) {
+ savings -= updateRefs(dd,node,NULL,info,localQueue);
+ } else if (replace == REPLACE_T) {
+ savings -= updateRefs(dd,node,E,info,localQueue);
+ } else if (replace == REPLACE_E) {
+ savings -= updateRefs(dd,node,T,info,localQueue);
+ } else {
+#ifdef DD_DEBUG
+ assert(replace == REPLACE_TT || replace == REPLACE_TE);
+#endif
+ savings -= updateRefs(dd,node,shared,info,localQueue) - 1;
+ }
+ assert(savings == 0);
+ } else {
+ replace = NOTHING;
+ }
+ if (replace == REPLACE_N) continue;
+ if ((replace == REPLACE_E || replace == NOTHING) &&
+ !cuddIsConstant(cuddT(node))) {
+ item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,cuddT(node),
+ cuddI(dd,cuddT(node)->index));
+ if (replace == REPLACE_E) {
+ item->impactP += impactP;
+ item->impactN += impactN;
+ } else {
+ item->impactP += impactP/2.0;
+ item->impactN += impactN/2.0;
+ }
+ }
+ if ((replace == REPLACE_T || replace == NOTHING) &&
+ !Cudd_IsConstant(cuddE(node))) {
+ item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(cuddE(node)),
+ cuddI(dd,Cudd_Regular(cuddE(node))->index));
+ if (Cudd_IsComplement(cuddE(node))) {
+ if (replace == REPLACE_T) {
+ item->impactP += impactN;
+ item->impactN += impactP;
+ } else {
+ item->impactP += impactN/2.0;
+ item->impactN += impactP/2.0;
+ }
+ } else {
+ if (replace == REPLACE_T) {
+ item->impactP += impactP;
+ item->impactN += impactN;
+ } else {
+ item->impactP += impactP/2.0;
+ item->impactN += impactN/2.0;
+ }
+ }
+ }
+ if ((replace == REPLACE_TT || replace == REPLACE_TE) &&
+ !Cudd_IsConstant(shared)) {
+ item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(shared),
+ cuddI(dd,Cudd_Regular(shared)->index));
+ if (Cudd_IsComplement(shared)) {
+ if (replace == REPLACE_T) {
+ item->impactP += impactN;
+ item->impactN += impactP;
+ } else {
+ item->impactP += impactN/2.0;
+ item->impactN += impactP/2.0;
+ }
+ } else {
+ if (replace == REPLACE_T) {
+ item->impactP += impactP;
+ item->impactN += impactN;
+ } else {
+ item->impactP += impactP/2.0;
+ item->impactN += impactN/2.0;
+ }
+ }
+ }
+ }
+
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(1);
+
+} /* end of BAmarkNodes */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds the subset BDD for cuddRemapUnderApprox.]
+
+ Description [Builds the subset BDDfor cuddRemapUnderApprox. Based
+ on the info table, performs remapping or replacement at selected
+ nodes. Returns a pointer to the result if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddRemapUnderApprox]
+
+******************************************************************************/
+static DdNode *
+RAbuildSubset(
+ DdManager * dd /* DD manager */,
+ DdNode * node /* current node */,
+ ApproxInfo * info /* node info */)
+{
+ DdNode *Nt, *Ne, *N, *t, *e, *r;
+ NodeData *infoN;
+
+ if (Cudd_IsConstant(node))
+ return(node);
+
+ N = Cudd_Regular(node);
+
+ Nt = Cudd_NotCond(cuddT(N), Cudd_IsComplement(node));
+ Ne = Cudd_NotCond(cuddE(N), Cudd_IsComplement(node));
+
+ if (st_lookup(info->table, (char *)N, (char **)&infoN)) {
+ if (N == node ) {
+ if (infoN->resultP != NULL) {
+ return(infoN->resultP);
+ }
+ } else {
+ if (infoN->resultN != NULL) {
+ return(infoN->resultN);
+ }
+ }
+ if (infoN->replace == REPLACE_T) {
+ r = RAbuildSubset(dd, Ne, info);
+ return(r);
+ } else if (infoN->replace == REPLACE_E) {
+ r = RAbuildSubset(dd, Nt, info);
+ return(r);
+ } else if (infoN->replace == REPLACE_N) {
+ return(info->zero);
+ } else if (infoN->replace == REPLACE_TT) {
+ DdNode *Ntt = Cudd_NotCond(cuddT(cuddT(N)),
+ Cudd_IsComplement(node));
+ int index = cuddT(N)->index;
+ DdNode *e = info->zero;
+ DdNode *t = RAbuildSubset(dd, Ntt, info);
+ if (t == NULL) {
+ return(NULL);
+ }
+ cuddRef(t);
+ if (Cudd_IsComplement(t)) {
+ t = Cudd_Not(t);
+ e = Cudd_Not(e);
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ }
+ cuddDeref(t);
+ return(r);
+ } else if (infoN->replace == REPLACE_TE) {
+ DdNode *Nte = Cudd_NotCond(cuddE(cuddT(N)),
+ Cudd_IsComplement(node));
+ int index = cuddT(N)->index;
+ DdNode *t = info->one;
+ DdNode *e = RAbuildSubset(dd, Nte, info);
+ if (e == NULL) {
+ return(NULL);
+ }
+ cuddRef(e);
+ e = Cudd_Not(e);
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, e);
+ return(NULL);
+ }
+ r =Cudd_Not(r);
+ cuddDeref(e);
+ return(r);
+ }
+ } else {
+ (void) fprintf(dd->err,
+ "Something is wrong, ought to be in info table\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+
+ t = RAbuildSubset(dd, Nt, info);
+ if (t == NULL) {
+ return(NULL);
+ }
+ cuddRef(t);
+
+ e = RAbuildSubset(dd, Ne, info);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd,t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ if (Cudd_IsComplement(t)) {
+ t = Cudd_Not(t);
+ e = Cudd_Not(e);
+ r = (t == e) ? t : cuddUniqueInter(dd, N->index, t, e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, e);
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = (t == e) ? t : cuddUniqueInter(dd, N->index, t, e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, e);
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ if (N == node) {
+ infoN->resultP = r;
+ } else {
+ infoN->resultN = r;
+ }
+
+ return(r);
+
+} /* end of RAbuildSubset */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds don't care nodes.]
+
+ Description [Finds don't care nodes by traversing f and b in parallel.
+ Returns the care status of the visited f node if successful; CARE_ERROR
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddBiasedUnderApprox]
+
+******************************************************************************/
+static int
+BAapplyBias(
+ DdManager *dd,
+ DdNode *f,
+ DdNode *b,
+ ApproxInfo *info,
+ DdHashTable *cache)
+{
+ DdNode *one, *zero, *res;
+ DdNode *Ft, *Fe, *B, *Bt, *Be;
+ unsigned int topf, topb;
+ NodeData *infoF;
+ int careT, careE;
+
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ if (!st_lookup(info->table, (char *) f, (char **)&infoF))
+ return(CARE_ERROR);
+ if (f == one) return(TOTAL_CARE);
+ if (b == zero) return(infoF->care);
+ if (infoF->care == TOTAL_CARE) return(TOTAL_CARE);
+
+ if ((f->ref != 1 || Cudd_Regular(b)->ref != 1) &&
+ (res = cuddHashTableLookup2(cache,f,b)) != NULL) {
+ if (res->ref == 0) {
+ cache->manager->dead++;
+ cache->manager->constants.dead++;
+ }
+ return(infoF->care);
+ }
+
+ topf = dd->perm[f->index];
+ B = Cudd_Regular(b);
+ topb = cuddI(dd,B->index);
+ if (topf <= topb) {
+ Ft = cuddT(f); Fe = cuddE(f);
+ } else {
+ Ft = Fe = f;
+ }
+ if (topb <= topf) {
+ /* We know that b is not constant because f is not. */
+ Bt = cuddT(B); Be = cuddE(B);
+ if (Cudd_IsComplement(b)) {
+ Bt = Cudd_Not(Bt);
+ Be = Cudd_Not(Be);
+ }
+ } else {
+ Bt = Be = b;
+ }
+
+ careT = BAapplyBias(dd, Ft, Bt, info, cache);
+ if (careT == CARE_ERROR)
+ return(CARE_ERROR);
+ careE = BAapplyBias(dd, Cudd_Regular(Fe), Be, info, cache);
+ if (careE == CARE_ERROR)
+ return(CARE_ERROR);
+ if (careT == TOTAL_CARE && careE == TOTAL_CARE) {
+ infoF->care = TOTAL_CARE;
+ } else {
+ infoF->care = CARE;
+ }
+
+ if (f->ref != 1 || Cudd_Regular(b)->ref != 1) {
+ ptrint fanout = (ptrint) f->ref * Cudd_Regular(b)->ref;
+ cuddSatDec(fanout);
+ if (!cuddHashTableInsert2(cache,f,b,one,fanout)) {
+ return(CARE_ERROR);
+ }
+ }
+ return(infoF->care);
+
+} /* end of BAapplyBias */
diff --git a/src/bdd/cudd/cuddBddAbs.c b/src/bdd/cudd/cuddBddAbs.c
new file mode 100644
index 00000000..20a8f15a
--- /dev/null
+++ b/src/bdd/cudd/cuddBddAbs.c
@@ -0,0 +1,689 @@
+/**CFile***********************************************************************
+
+ FileName [cuddBddAbs.c]
+
+ PackageName [cudd]
+
+ Synopsis [Quantification functions for BDDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_bddExistAbstract()
+ <li> Cudd_bddXorExistAbstract()
+ <li> Cudd_bddUnivAbstract()
+ <li> Cudd_bddBooleanDiff()
+ <li> Cudd_bddVarIsDependent()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddBddExistAbstractRecur()
+ <li> cuddBddXorExistAbstractRecur()
+ <li> cuddBddBooleanDiffRecur()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> bddCheckPositiveCube()
+ </ul>
+ ]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddBddAbs.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int bddCheckPositiveCube ARGS((DdManager *manager, DdNode *cube));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Existentially abstracts all the variables in cube from f.]
+
+ Description [Existentially abstracts all the variables in cube from f.
+ Returns the abstracted BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddUnivAbstract Cudd_addExistAbstract]
+
+******************************************************************************/
+DdNode *
+Cudd_bddExistAbstract(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * cube)
+{
+ DdNode *res;
+
+ if (bddCheckPositiveCube(manager, cube) == 0) {
+ (void) fprintf(manager->err,
+ "Error: Can only abstract positive cubes\n");
+ manager->errorCode = CUDD_INVALID_ARG;
+ return(NULL);
+ }
+
+ do {
+ manager->reordered = 0;
+ res = cuddBddExistAbstractRecur(manager, f, cube);
+ } while (manager->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_bddExistAbstract */
+
+
+/**Function********************************************************************
+
+ Synopsis [Takes the exclusive OR of two BDDs and simultaneously abstracts the
+ variables in cube.]
+
+ Description [Takes the exclusive OR of two BDDs and simultaneously abstracts
+ the variables in cube. The variables are existentially abstracted. Returns a
+ pointer to the result is successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddUnivAbstract Cudd_bddExistAbstract Cudd_bddAndAbstract]
+
+******************************************************************************/
+DdNode *
+Cudd_bddXorExistAbstract(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * g,
+ DdNode * cube)
+{
+ DdNode *res;
+
+ if (bddCheckPositiveCube(manager, cube) == 0) {
+ (void) fprintf(manager->err,
+ "Error: Can only abstract positive cubes\n");
+ manager->errorCode = CUDD_INVALID_ARG;
+ return(NULL);
+ }
+
+ do {
+ manager->reordered = 0;
+ res = cuddBddXorExistAbstractRecur(manager, f, g, cube);
+ } while (manager->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_bddXorExistAbstract */
+
+
+/**Function********************************************************************
+
+ Synopsis [Universally abstracts all the variables in cube from f.]
+
+ Description [Universally abstracts all the variables in cube from f.
+ Returns the abstracted BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddExistAbstract Cudd_addUnivAbstract]
+
+******************************************************************************/
+DdNode *
+Cudd_bddUnivAbstract(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * cube)
+{
+ DdNode *res;
+
+ if (bddCheckPositiveCube(manager, cube) == 0) {
+ (void) fprintf(manager->err,
+ "Error: Can only abstract positive cubes\n");
+ manager->errorCode = CUDD_INVALID_ARG;
+ return(NULL);
+ }
+
+ do {
+ manager->reordered = 0;
+ res = cuddBddExistAbstractRecur(manager, Cudd_Not(f), cube);
+ } while (manager->reordered == 1);
+ if (res != NULL) res = Cudd_Not(res);
+
+ return(res);
+
+} /* end of Cudd_bddUnivAbstract */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the boolean difference of f with respect to x.]
+
+ Description [Computes the boolean difference of f with respect to the
+ variable with index x. Returns the BDD of the boolean difference if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_bddBooleanDiff(
+ DdManager * manager,
+ DdNode * f,
+ int x)
+{
+ DdNode *res, *var;
+
+ /* If the variable is not currently in the manager, f cannot
+ ** depend on it.
+ */
+ if (x >= manager->size) return(Cudd_Not(DD_ONE(manager)));
+ var = manager->vars[x];
+
+ do {
+ manager->reordered = 0;
+ res = cuddBddBooleanDiffRecur(manager, Cudd_Regular(f), var);
+ } while (manager->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_bddBooleanDiff */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether a variable is dependent on others in a
+ function.]
+
+ Description [Checks whether a variable is dependent on others in a
+ function. Returns 1 if the variable is dependent; 0 otherwise. No
+ new nodes are created.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_bddVarIsDependent(
+ DdManager *dd, /* manager */
+ DdNode *f, /* function */
+ DdNode *var /* variable */)
+{
+ DdNode *F, *res, *zero, *ft, *fe;
+ unsigned topf, level;
+ DdNode *(*cacheOp)(DdManager *, DdNode *, DdNode *);
+ int retval;
+
+ zero = Cudd_Not(DD_ONE(dd));
+ if (Cudd_IsConstant(f)) return(f == zero);
+
+ /* From now on f is not constant. */
+ F = Cudd_Regular(f);
+ topf = (unsigned) dd->perm[F->index];
+ level = (unsigned) dd->perm[var->index];
+
+ /* Check terminal case. If topf > index of var, f does not depend on var.
+ ** Therefore, var is not dependent in f. */
+ if (topf > level) {
+ return(0);
+ }
+
+ cacheOp =
+ (DdNode *(*)(DdManager *, DdNode *, DdNode *)) Cudd_bddVarIsDependent;
+ res = cuddCacheLookup2(dd,cacheOp,f,var);
+ if (res != NULL) {
+ return(res != zero);
+ }
+
+ /* Compute cofactors. */
+ ft = Cudd_NotCond(cuddT(F), f != F);
+ fe = Cudd_NotCond(cuddE(F), f != F);
+
+ if (topf == level) {
+ retval = Cudd_bddLeq(dd,ft,Cudd_Not(fe));
+ } else {
+ retval = Cudd_bddVarIsDependent(dd,ft,var) &&
+ Cudd_bddVarIsDependent(dd,fe,var);
+ }
+
+ cuddCacheInsert2(dd,cacheOp,f,var,Cudd_NotCond(zero,retval));
+
+ return(retval);
+
+} /* Cudd_bddVarIsDependent */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive steps of Cudd_bddExistAbstract.]
+
+ Description [Performs the recursive steps of Cudd_bddExistAbstract.
+ Returns the BDD obtained by abstracting the variables
+ of cube from f if successful; NULL otherwise. It is also used by
+ Cudd_bddUnivAbstract.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddExistAbstract Cudd_bddUnivAbstract]
+
+******************************************************************************/
+DdNode *
+cuddBddExistAbstractRecur(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * cube)
+{
+ DdNode *F, *T, *E, *res, *res1, *res2, *one;
+
+ statLine(manager);
+ one = DD_ONE(manager);
+ F = Cudd_Regular(f);
+
+ /* Cube is guaranteed to be a cube at this point. */
+ if (cube == one || F == one) {
+ return(f);
+ }
+ /* From now on, f and cube are non-constant. */
+
+ /* Abstract a variable that does not appear in f. */
+ while (manager->perm[F->index] > manager->perm[cube->index]) {
+ cube = cuddT(cube);
+ if (cube == one) return(f);
+ }
+
+ /* Check the cache. */
+ if (F->ref != 1 && (res = cuddCacheLookup2(manager, Cudd_bddExistAbstract, f, cube)) != NULL) {
+ return(res);
+ }
+
+ /* Compute the cofactors of f. */
+ T = cuddT(F); E = cuddE(F);
+ if (f != F) {
+ T = Cudd_Not(T); E = Cudd_Not(E);
+ }
+
+ /* If the two indices are the same, so are their levels. */
+ if (F->index == cube->index) {
+ if (T == one || E == one || T == Cudd_Not(E)) {
+ return(one);
+ }
+ res1 = cuddBddExistAbstractRecur(manager, T, cuddT(cube));
+ if (res1 == NULL) return(NULL);
+ if (res1 == one) {
+ if (F->ref != 1)
+ cuddCacheInsert2(manager, Cudd_bddExistAbstract, f, cube, one);
+ return(one);
+ }
+ cuddRef(res1);
+ res2 = cuddBddExistAbstractRecur(manager, E, cuddT(cube));
+ if (res2 == NULL) {
+ Cudd_IterDerefBdd(manager,res1);
+ return(NULL);
+ }
+ cuddRef(res2);
+ res = cuddBddAndRecur(manager, Cudd_Not(res1), Cudd_Not(res2));
+ if (res == NULL) {
+ Cudd_IterDerefBdd(manager, res1);
+ Cudd_IterDerefBdd(manager, res2);
+ return(NULL);
+ }
+ res = Cudd_Not(res);
+ cuddRef(res);
+ Cudd_IterDerefBdd(manager, res1);
+ Cudd_IterDerefBdd(manager, res2);
+ if (F->ref != 1)
+ cuddCacheInsert2(manager, Cudd_bddExistAbstract, f, cube, res);
+ cuddDeref(res);
+ return(res);
+ } else { /* if (cuddI(manager,F->index) < cuddI(manager,cube->index)) */
+ res1 = cuddBddExistAbstractRecur(manager, T, cube);
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ res2 = cuddBddExistAbstractRecur(manager, E, cube);
+ if (res2 == NULL) {
+ Cudd_IterDerefBdd(manager, res1);
+ return(NULL);
+ }
+ cuddRef(res2);
+ /* ITE takes care of possible complementation of res1 and of the
+ ** case in which res1 == res2. */
+ res = cuddBddIteRecur(manager, manager->vars[F->index], res1, res2);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(manager, res1);
+ Cudd_IterDerefBdd(manager, res2);
+ return(NULL);
+ }
+ cuddDeref(res1);
+ cuddDeref(res2);
+ if (F->ref != 1)
+ cuddCacheInsert2(manager, Cudd_bddExistAbstract, f, cube, res);
+ return(res);
+ }
+
+} /* end of cuddBddExistAbstractRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Takes the exclusive OR of two BDDs and simultaneously abstracts the
+ variables in cube.]
+
+ Description [Takes the exclusive OR of two BDDs and simultaneously abstracts
+ the variables in cube. The variables are existentially abstracted. Returns a
+ pointer to the result is successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddAndAbstract]
+
+******************************************************************************/
+DdNode *
+cuddBddXorExistAbstractRecur(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * g,
+ DdNode * cube)
+{
+ DdNode *F, *fv, *fnv, *G, *gv, *gnv;
+ DdNode *one, *zero, *r, *t, *e, *Cube;
+ unsigned int topf, topg, topcube, top, index;
+
+ statLine(manager);
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ /* Terminal cases. */
+ if (f == g) {
+ return(zero);
+ }
+ if (f == Cudd_Not(g)) {
+ return(one);
+ }
+ if (cube == one) {
+ return(cuddBddXorRecur(manager, f, g));
+ }
+ if (f == one) {
+ return(cuddBddExistAbstractRecur(manager, Cudd_Not(g), cube));
+ }
+ if (g == one) {
+ return(cuddBddExistAbstractRecur(manager, Cudd_Not(f), cube));
+ }
+ if (f == zero) {
+ return(cuddBddExistAbstractRecur(manager, g, cube));
+ }
+ if (g == zero) {
+ return(cuddBddExistAbstractRecur(manager, f, cube));
+ }
+
+ /* At this point f, g, and cube are not constant. */
+
+ if (f > g) { /* Try to increase cache efficiency. */
+ DdNode *tmp = f;
+ f = g;
+ g = tmp;
+ }
+
+ /* Check cache. */
+ r = cuddCacheLookup(manager, DD_BDD_XOR_EXIST_ABSTRACT_TAG, f, g, cube);
+ if (r != NULL) {
+ return(r);
+ }
+
+ /* Here we can skip the use of cuddI, because the operands are known
+ ** to be non-constant.
+ */
+ F = Cudd_Regular(f);
+ topf = manager->perm[F->index];
+ G = Cudd_Regular(g);
+ topg = manager->perm[G->index];
+ top = ddMin(topf, topg);
+ topcube = manager->perm[cube->index];
+
+ if (topcube < top) {
+ return(cuddBddXorExistAbstractRecur(manager, f, g, cuddT(cube)));
+ }
+ /* Now, topcube >= top. */
+
+ if (topf == top) {
+ index = F->index;
+ fv = cuddT(F);
+ fnv = cuddE(F);
+ if (Cudd_IsComplement(f)) {
+ fv = Cudd_Not(fv);
+ fnv = Cudd_Not(fnv);
+ }
+ } else {
+ index = G->index;
+ fv = fnv = f;
+ }
+
+ if (topg == top) {
+ gv = cuddT(G);
+ gnv = cuddE(G);
+ if (Cudd_IsComplement(g)) {
+ gv = Cudd_Not(gv);
+ gnv = Cudd_Not(gnv);
+ }
+ } else {
+ gv = gnv = g;
+ }
+
+ if (topcube == top) {
+ Cube = cuddT(cube);
+ } else {
+ Cube = cube;
+ }
+
+ t = cuddBddXorExistAbstractRecur(manager, fv, gv, Cube);
+ if (t == NULL) return(NULL);
+
+ /* Special case: 1 OR anything = 1. Hence, no need to compute
+ ** the else branch if t is 1.
+ */
+ if (t == one && topcube == top) {
+ cuddCacheInsert(manager, DD_BDD_XOR_EXIST_ABSTRACT_TAG, f, g, cube, one);
+ return(one);
+ }
+ cuddRef(t);
+
+ e = cuddBddXorExistAbstractRecur(manager, fnv, gnv, Cube);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ if (topcube == top) { /* abstract */
+ r = cuddBddAndRecur(manager, Cudd_Not(t), Cudd_Not(e));
+ if (r == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ Cudd_IterDerefBdd(manager, e);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ cuddRef(r);
+ Cudd_IterDerefBdd(manager, t);
+ Cudd_IterDerefBdd(manager, e);
+ cuddDeref(r);
+ } else if (t == e) {
+ r = t;
+ cuddDeref(t);
+ cuddDeref(e);
+ } else {
+ if (Cudd_IsComplement(t)) {
+ r = cuddUniqueInter(manager,(int)index,Cudd_Not(t),Cudd_Not(e));
+ if (r == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ Cudd_IterDerefBdd(manager, e);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = cuddUniqueInter(manager,(int)index,t,e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ Cudd_IterDerefBdd(manager, e);
+ return(NULL);
+ }
+ }
+ cuddDeref(e);
+ cuddDeref(t);
+ }
+ cuddCacheInsert(manager, DD_BDD_XOR_EXIST_ABSTRACT_TAG, f, g, cube, r);
+ return (r);
+
+} /* end of cuddBddXorExistAbstractRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive steps of Cudd_bddBoleanDiff.]
+
+ Description [Performs the recursive steps of Cudd_bddBoleanDiff.
+ Returns the BDD obtained by XORing the cofactors of f with respect to
+ var if successful; NULL otherwise. Exploits the fact that dF/dx =
+ dF'/dx.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddBddBooleanDiffRecur(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * var)
+{
+ DdNode *T, *E, *res, *res1, *res2;
+
+ statLine(manager);
+ if (cuddI(manager,f->index) > manager->perm[var->index]) {
+ /* f does not depend on var. */
+ return(Cudd_Not(DD_ONE(manager)));
+ }
+
+ /* From now on, f is non-constant. */
+
+ /* If the two indices are the same, so are their levels. */
+ if (f->index == var->index) {
+ res = cuddBddXorRecur(manager, cuddT(f), cuddE(f));
+ return(res);
+ }
+
+ /* From now on, cuddI(manager,f->index) < cuddI(manager,cube->index). */
+
+ /* Check the cache. */
+ res = cuddCacheLookup2(manager, cuddBddBooleanDiffRecur, f, var);
+ if (res != NULL) {
+ return(res);
+ }
+
+ /* Compute the cofactors of f. */
+ T = cuddT(f); E = cuddE(f);
+
+ res1 = cuddBddBooleanDiffRecur(manager, T, var);
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ res2 = cuddBddBooleanDiffRecur(manager, Cudd_Regular(E), var);
+ if (res2 == NULL) {
+ Cudd_IterDerefBdd(manager, res1);
+ return(NULL);
+ }
+ cuddRef(res2);
+ /* ITE takes care of possible complementation of res1 and of the
+ ** case in which res1 == res2. */
+ res = cuddBddIteRecur(manager, manager->vars[f->index], res1, res2);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(manager, res1);
+ Cudd_IterDerefBdd(manager, res2);
+ return(NULL);
+ }
+ cuddDeref(res1);
+ cuddDeref(res2);
+ cuddCacheInsert2(manager, cuddBddBooleanDiffRecur, f, var, res);
+ return(res);
+
+} /* end of cuddBddBooleanDiffRecur */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether cube is an BDD representing the product of
+ positive literals.]
+
+ Description [Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+bddCheckPositiveCube(
+ DdManager * manager,
+ DdNode * cube)
+{
+ if (Cudd_IsComplement(cube)) return(0);
+ if (cube == DD_ONE(manager)) return(1);
+ if (cuddIsConstant(cube)) return(0);
+ if (cuddE(cube) == Cudd_Not(DD_ONE(manager))) {
+ return(bddCheckPositiveCube(manager, cuddT(cube)));
+ }
+ return(0);
+
+} /* end of bddCheckPositiveCube */
+
diff --git a/src/bdd/cudd/cuddBddCorr.c b/src/bdd/cudd/cuddBddCorr.c
new file mode 100644
index 00000000..47395ec7
--- /dev/null
+++ b/src/bdd/cudd/cuddBddCorr.c
@@ -0,0 +1,481 @@
+/**CFile***********************************************************************
+
+ FileName [cuddBddCorr.c]
+
+ PackageName [cudd]
+
+ Synopsis [Correlation between BDDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_bddCorrelation()
+ <li> Cudd_bddCorrelationWeights()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> bddCorrelationAux()
+ <li> bddCorrelationWeightsAux()
+ <li> CorrelCompare()
+ <li> CorrelHash()
+ <li> CorrelCleanUp()
+ </ul>
+ ]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+typedef struct hashEntry {
+ DdNode *f;
+ DdNode *g;
+} HashEntry;
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddBddCorr.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+#ifdef CORREL_STATS
+static int num_calls;
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static double bddCorrelationAux ARGS((DdManager *dd, DdNode *f, DdNode *g, st_table *table));
+static double bddCorrelationWeightsAux ARGS((DdManager *dd, DdNode *f, DdNode *g, double *prob, st_table *table));
+static int CorrelCompare ARGS((const char *key1, const char *key2));
+static int CorrelHash ARGS((char *key, int modulus));
+static enum st_retval CorrelCleanUp ARGS((char *key, char *value, char *arg));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the correlation of f and g.]
+
+ Description [Computes the correlation of f and g. If f == g, their
+ correlation is 1. If f == g', their correlation is 0. Returns the
+ fraction of minterms in the ON-set of the EXNOR of f and g. If it
+ runs out of memory, returns (double)CUDD_OUT_OF_MEM.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddCorrelationWeights]
+
+******************************************************************************/
+double
+Cudd_bddCorrelation(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * g)
+{
+
+ st_table *table;
+ double correlation;
+
+#ifdef CORREL_STATS
+ num_calls = 0;
+#endif
+
+ table = st_init_table(CorrelCompare,CorrelHash);
+ if (table == NULL) return((double)CUDD_OUT_OF_MEM);
+ correlation = bddCorrelationAux(manager,f,g,table);
+ st_foreach(table, CorrelCleanUp, NIL(char));
+ st_free_table(table);
+ return(correlation);
+
+} /* end of Cudd_bddCorrelation */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the correlation of f and g for given input
+ probabilities.]
+
+ Description [Computes the correlation of f and g for given input
+ probabilities. On input, prob\[i\] is supposed to contain the
+ probability of the i-th input variable to be 1.
+ If f == g, their correlation is 1. If f == g', their
+ correlation is 0. Returns the probability that f and g have the same
+ value. If it runs out of memory, returns (double)CUDD_OUT_OF_MEM. The
+ correlation of f and the constant one gives the probability of f.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddCorrelation]
+
+******************************************************************************/
+double
+Cudd_bddCorrelationWeights(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * g,
+ double * prob)
+{
+
+ st_table *table;
+ double correlation;
+
+#ifdef CORREL_STATS
+ num_calls = 0;
+#endif
+
+ table = st_init_table(CorrelCompare,CorrelHash);
+ if (table == NULL) return((double)CUDD_OUT_OF_MEM);
+ correlation = bddCorrelationWeightsAux(manager,f,g,prob,table);
+ st_foreach(table, CorrelCleanUp, NIL(char));
+ st_free_table(table);
+ return(correlation);
+
+} /* end of Cudd_bddCorrelationWeights */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddCorrelation.]
+
+ Description [Performs the recursive step of Cudd_bddCorrelation.
+ Returns the fraction of minterms in the ON-set of the EXNOR of f and
+ g.]
+
+ SideEffects [None]
+
+ SeeAlso [bddCorrelationWeightsAux]
+
+******************************************************************************/
+static double
+bddCorrelationAux(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ st_table * table)
+{
+ DdNode *Fv, *Fnv, *G, *Gv, *Gnv;
+ double min, *pmin, min1, min2, *dummy;
+ HashEntry *entry;
+ unsigned int topF, topG;
+
+ statLine(dd);
+#ifdef CORREL_STATS
+ num_calls++;
+#endif
+
+ /* Terminal cases: only work for BDDs. */
+ if (f == g) return(1.0);
+ if (f == Cudd_Not(g)) return(0.0);
+
+ /* Standardize call using the following properties:
+ ** (f EXNOR g) = (g EXNOR f)
+ ** (f' EXNOR g') = (f EXNOR g).
+ */
+ if (f > g) {
+ DdNode *tmp = f;
+ f = g; g = tmp;
+ }
+ if (Cudd_IsComplement(f)) {
+ f = Cudd_Not(f);
+ g = Cudd_Not(g);
+ }
+ /* From now on, f is regular. */
+
+ entry = ALLOC(HashEntry,1);
+ if (entry == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(CUDD_OUT_OF_MEM);
+ }
+ entry->f = f; entry->g = g;
+
+ /* We do not use the fact that
+ ** correlation(f,g') = 1 - correlation(f,g)
+ ** to minimize the risk of cancellation.
+ */
+ if (st_lookup(table, (char *)entry, (char **)&dummy)) {
+ min = *dummy;
+ FREE(entry);
+ return(min);
+ }
+
+ G = Cudd_Regular(g);
+ topF = cuddI(dd,f->index); topG = cuddI(dd,G->index);
+ if (topF <= topG) { Fv = cuddT(f); Fnv = cuddE(f); } else { Fv = Fnv = f; }
+ if (topG <= topF) { Gv = cuddT(G); Gnv = cuddE(G); } else { Gv = Gnv = G; }
+
+ if (g != G) {
+ Gv = Cudd_Not(Gv);
+ Gnv = Cudd_Not(Gnv);
+ }
+
+ min1 = bddCorrelationAux(dd, Fv, Gv, table) / 2.0;
+ if (min1 == (double)CUDD_OUT_OF_MEM) {
+ FREE(entry);
+ return(CUDD_OUT_OF_MEM);
+ }
+ min2 = bddCorrelationAux(dd, Fnv, Gnv, table) / 2.0;
+ if (min2 == (double)CUDD_OUT_OF_MEM) {
+ FREE(entry);
+ return(CUDD_OUT_OF_MEM);
+ }
+ min = (min1+min2);
+
+ pmin = ALLOC(double,1);
+ if (pmin == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ *pmin = min;
+
+ if (st_insert(table,(char *)entry, (char *)pmin) == ST_OUT_OF_MEM) {
+ FREE(entry);
+ FREE(pmin);
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ return(min);
+
+} /* end of bddCorrelationAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddCorrelationWeigths.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [bddCorrelationAux]
+
+******************************************************************************/
+static double
+bddCorrelationWeightsAux(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ double * prob,
+ st_table * table)
+{
+ DdNode *Fv, *Fnv, *G, *Gv, *Gnv;
+ double min, *pmin, min1, min2, *dummy;
+ HashEntry *entry;
+ int topF, topG, index;
+
+ statLine(dd);
+#ifdef CORREL_STATS
+ num_calls++;
+#endif
+
+ /* Terminal cases: only work for BDDs. */
+ if (f == g) return(1.0);
+ if (f == Cudd_Not(g)) return(0.0);
+
+ /* Standardize call using the following properties:
+ ** (f EXNOR g) = (g EXNOR f)
+ ** (f' EXNOR g') = (f EXNOR g).
+ */
+ if (f > g) {
+ DdNode *tmp = f;
+ f = g; g = tmp;
+ }
+ if (Cudd_IsComplement(f)) {
+ f = Cudd_Not(f);
+ g = Cudd_Not(g);
+ }
+ /* From now on, f is regular. */
+
+ entry = ALLOC(HashEntry,1);
+ if (entry == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ entry->f = f; entry->g = g;
+
+ /* We do not use the fact that
+ ** correlation(f,g') = 1 - correlation(f,g)
+ ** to minimize the risk of cancellation.
+ */
+ if (st_lookup(table, (char *)entry, (char **)&dummy)) {
+ min = *dummy;
+ FREE(entry);
+ return(min);
+ }
+
+ G = Cudd_Regular(g);
+ topF = cuddI(dd,f->index); topG = cuddI(dd,G->index);
+ if (topF <= topG) {
+ Fv = cuddT(f); Fnv = cuddE(f);
+ index = f->index;
+ } else {
+ Fv = Fnv = f;
+ index = G->index;
+ }
+ if (topG <= topF) { Gv = cuddT(G); Gnv = cuddE(G); } else { Gv = Gnv = G; }
+
+ if (g != G) {
+ Gv = Cudd_Not(Gv);
+ Gnv = Cudd_Not(Gnv);
+ }
+
+ min1 = bddCorrelationWeightsAux(dd, Fv, Gv, prob, table) * prob[index];
+ if (min1 == (double)CUDD_OUT_OF_MEM) {
+ FREE(entry);
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ min2 = bddCorrelationWeightsAux(dd, Fnv, Gnv, prob, table) * (1.0 - prob[index]);
+ if (min2 == (double)CUDD_OUT_OF_MEM) {
+ FREE(entry);
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ min = (min1+min2);
+
+ pmin = ALLOC(double,1);
+ if (pmin == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ *pmin = min;
+
+ if (st_insert(table,(char *)entry, (char *)pmin) == ST_OUT_OF_MEM) {
+ FREE(entry);
+ FREE(pmin);
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ return(min);
+
+} /* end of bddCorrelationWeightsAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Compares two hash table entries.]
+
+ Description [Compares two hash table entries. Returns 0 if they are
+ identical; 1 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+CorrelCompare(
+ const char * key1,
+ const char * key2)
+{
+ HashEntry *entry1;
+ HashEntry *entry2;
+
+ entry1 = (HashEntry *) key1;
+ entry2 = (HashEntry *) key2;
+ if (entry1->f != entry2->f || entry1->g != entry2->g) return(1);
+
+ return(0);
+
+} /* end of CorrelCompare */
+
+
+/**Function********************************************************************
+
+ Synopsis [Hashes a hash table entry.]
+
+ Description [Hashes a hash table entry. It is patterned after
+ st_strhash. Returns a value between 0 and modulus.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+CorrelHash(
+ char * key,
+ int modulus)
+{
+ HashEntry *entry;
+ int val = 0;
+
+ entry = (HashEntry *) key;
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+ val = ((int) ((long)entry->f))*997 + ((int) ((long)entry->g));
+#else
+ val = ((int) entry->f)*997 + ((int) entry->g);
+#endif
+
+ return ((val < 0) ? -val : val) % modulus;
+
+} /* end of CorrelHash */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees memory associated with hash table.]
+
+ Description [Frees memory associated with hash table. Returns
+ ST_CONTINUE.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static enum st_retval
+CorrelCleanUp(
+ char * key,
+ char * value,
+ char * arg)
+{
+ double *d;
+ HashEntry *entry;
+
+ entry = (HashEntry *) key;
+ FREE(entry);
+ d = (double *)value;
+ FREE(d);
+ return ST_CONTINUE;
+
+} /* end of CorrelCleanUp */
+
diff --git a/src/bdd/cudd/cuddBddIte.c b/src/bdd/cudd/cuddBddIte.c
new file mode 100644
index 00000000..fe0c6500
--- /dev/null
+++ b/src/bdd/cudd/cuddBddIte.c
@@ -0,0 +1,1254 @@
+/**CFile***********************************************************************
+
+ FileName [cuddBddIte.c]
+
+ PackageName [cudd]
+
+ Synopsis [BDD ITE function and satellites.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_bddIte()
+ <li> Cudd_bddIteConstant()
+ <li> Cudd_bddIntersect()
+ <li> Cudd_bddAnd()
+ <li> Cudd_bddOr()
+ <li> Cudd_bddNand()
+ <li> Cudd_bddNor()
+ <li> Cudd_bddXor()
+ <li> Cudd_bddXnor()
+ <li> Cudd_bddLeq()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddBddIteRecur()
+ <li> cuddBddIntersectRecur()
+ <li> cuddBddAndRecur()
+ <li> cuddBddXorRecur()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> bddVarToConst()
+ <li> bddVarToCanonical()
+ <li> bddVarToCanonicalSimple()
+ </ul>]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddBddIte.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static void bddVarToConst ARGS((DdNode *f, DdNode **gp, DdNode **hp, DdNode *one));
+static int bddVarToCanonical ARGS((DdManager *dd, DdNode **fp, DdNode **gp, DdNode **hp, unsigned int *topfp, unsigned int *topgp, unsigned int *tophp));
+static int bddVarToCanonicalSimple ARGS((DdManager *dd, DdNode **fp, DdNode **gp, DdNode **hp, unsigned int *topfp, unsigned int *topgp, unsigned int *tophp));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements ITE(f,g,h).]
+
+ Description [Implements ITE(f,g,h). Returns a pointer to the
+ resulting BDD if successful; NULL if the intermediate result blows
+ up.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addIte Cudd_bddIteConstant Cudd_bddIntersect]
+
+******************************************************************************/
+DdNode *
+Cudd_bddIte(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddIteRecur(dd,f,g,h);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddIte */
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements ITEconstant(f,g,h).]
+
+ Description [Implements ITEconstant(f,g,h). Returns a pointer to the
+ resulting BDD (which may or may not be constant) or DD_NON_CONSTANT.
+ No new nodes are created.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIte Cudd_bddIntersect Cudd_bddLeq Cudd_addIteConstant]
+
+******************************************************************************/
+DdNode *
+Cudd_bddIteConstant(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ DdNode *r, *Fv, *Fnv, *Gv, *Gnv, *H, *Hv, *Hnv, *t, *e;
+ DdNode *one = DD_ONE(dd);
+ DdNode *zero = Cudd_Not(one);
+ int comple;
+ unsigned int topf, topg, toph, v;
+
+ statLine(dd);
+ /* Trivial cases. */
+ if (f == one) /* ITE(1,G,H) => G */
+ return(g);
+
+ if (f == zero) /* ITE(0,G,H) => H */
+ return(h);
+
+ /* f now not a constant. */
+ bddVarToConst(f, &g, &h, one); /* possibly convert g or h */
+ /* to constants */
+
+ if (g == h) /* ITE(F,G,G) => G */
+ return(g);
+
+ if (Cudd_IsConstant(g) && Cudd_IsConstant(h))
+ return(DD_NON_CONSTANT); /* ITE(F,1,0) or ITE(F,0,1) */
+ /* => DD_NON_CONSTANT */
+
+ if (g == Cudd_Not(h))
+ return(DD_NON_CONSTANT); /* ITE(F,G,G') => DD_NON_CONSTANT */
+ /* if F != G and F != G' */
+
+ comple = bddVarToCanonical(dd, &f, &g, &h, &topf, &topg, &toph);
+
+ /* Cache lookup. */
+ r = cuddConstantLookup(dd, DD_BDD_ITE_CONSTANT_TAG, f, g, h);
+ if (r != NULL) {
+ return(Cudd_NotCond(r,comple && r != DD_NON_CONSTANT));
+ }
+
+ v = ddMin(topg, toph);
+
+ /* ITE(F,G,H) = (v,G,H) (non constant) if F = (v,1,0), v < top(G,H). */
+ if (topf < v && cuddT(f) == one && cuddE(f) == zero) {
+ return(DD_NON_CONSTANT);
+ }
+
+ /* Compute cofactors. */
+ if (topf <= v) {
+ v = ddMin(topf, v); /* v = top_var(F,G,H) */
+ Fv = cuddT(f); Fnv = cuddE(f);
+ } else {
+ Fv = Fnv = f;
+ }
+
+ if (topg == v) {
+ Gv = cuddT(g); Gnv = cuddE(g);
+ } else {
+ Gv = Gnv = g;
+ }
+
+ if (toph == v) {
+ H = Cudd_Regular(h);
+ Hv = cuddT(H); Hnv = cuddE(H);
+ if (Cudd_IsComplement(h)) {
+ Hv = Cudd_Not(Hv);
+ Hnv = Cudd_Not(Hnv);
+ }
+ } else {
+ Hv = Hnv = h;
+ }
+
+ /* Recursion. */
+ t = Cudd_bddIteConstant(dd, Fv, Gv, Hv);
+ if (t == DD_NON_CONSTANT || !Cudd_IsConstant(t)) {
+ cuddCacheInsert(dd, DD_BDD_ITE_CONSTANT_TAG, f, g, h, DD_NON_CONSTANT);
+ return(DD_NON_CONSTANT);
+ }
+ e = Cudd_bddIteConstant(dd, Fnv, Gnv, Hnv);
+ if (e == DD_NON_CONSTANT || !Cudd_IsConstant(e) || t != e) {
+ cuddCacheInsert(dd, DD_BDD_ITE_CONSTANT_TAG, f, g, h, DD_NON_CONSTANT);
+ return(DD_NON_CONSTANT);
+ }
+ cuddCacheInsert(dd, DD_BDD_ITE_CONSTANT_TAG, f, g, h, t);
+ return(Cudd_NotCond(t,comple));
+
+} /* end of Cudd_bddIteConstant */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns a function included in the intersection of f and g.]
+
+ Description [Computes a function included in the intersection of f and
+ g. (That is, a witness that the intersection is not empty.)
+ Cudd_bddIntersect tries to build as few new nodes as possible. If the
+ only result of interest is whether f and g intersect,
+ Cudd_bddLeq should be used instead.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLeq Cudd_bddIteConstant]
+
+******************************************************************************/
+DdNode *
+Cudd_bddIntersect(
+ DdManager * dd /* manager */,
+ DdNode * f /* first operand */,
+ DdNode * g /* second operand */)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddIntersectRecur(dd,f,g);
+ } while (dd->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_bddIntersect */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the conjunction of two BDDs f and g.]
+
+ Description [Computes the conjunction of two BDDs f and g. Returns a
+ pointer to the resulting BDD if successful; NULL if the intermediate
+ result blows up.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIte Cudd_addApply Cudd_bddAndAbstract Cudd_bddIntersect
+ Cudd_bddOr Cudd_bddNand Cudd_bddNor Cudd_bddXor Cudd_bddXnor]
+
+******************************************************************************/
+DdNode *
+Cudd_bddAnd(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddAndRecur(dd,f,g);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddAnd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the disjunction of two BDDs f and g.]
+
+ Description [Computes the disjunction of two BDDs f and g. Returns a
+ pointer to the resulting BDD if successful; NULL if the intermediate
+ result blows up.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIte Cudd_addApply Cudd_bddAnd Cudd_bddNand Cudd_bddNor
+ Cudd_bddXor Cudd_bddXnor]
+
+******************************************************************************/
+DdNode *
+Cudd_bddOr(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddAndRecur(dd,Cudd_Not(f),Cudd_Not(g));
+ } while (dd->reordered == 1);
+ res = Cudd_NotCond(res,res != NULL);
+ return(res);
+
+} /* end of Cudd_bddOr */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the NAND of two BDDs f and g.]
+
+ Description [Computes the NAND of two BDDs f and g. Returns a
+ pointer to the resulting BDD if successful; NULL if the intermediate
+ result blows up.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIte Cudd_addApply Cudd_bddAnd Cudd_bddOr Cudd_bddNor
+ Cudd_bddXor Cudd_bddXnor]
+
+******************************************************************************/
+DdNode *
+Cudd_bddNand(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddAndRecur(dd,f,g);
+ } while (dd->reordered == 1);
+ res = Cudd_NotCond(res,res != NULL);
+ return(res);
+
+} /* end of Cudd_bddNand */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the NOR of two BDDs f and g.]
+
+ Description [Computes the NOR of two BDDs f and g. Returns a
+ pointer to the resulting BDD if successful; NULL if the intermediate
+ result blows up.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIte Cudd_addApply Cudd_bddAnd Cudd_bddOr Cudd_bddNand
+ Cudd_bddXor Cudd_bddXnor]
+
+******************************************************************************/
+DdNode *
+Cudd_bddNor(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddAndRecur(dd,Cudd_Not(f),Cudd_Not(g));
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddNor */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the exclusive OR of two BDDs f and g.]
+
+ Description [Computes the exclusive OR of two BDDs f and g. Returns a
+ pointer to the resulting BDD if successful; NULL if the intermediate
+ result blows up.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIte Cudd_addApply Cudd_bddAnd Cudd_bddOr
+ Cudd_bddNand Cudd_bddNor Cudd_bddXnor]
+
+******************************************************************************/
+DdNode *
+Cudd_bddXor(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddXorRecur(dd,f,g);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddXor */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the exclusive NOR of two BDDs f and g.]
+
+ Description [Computes the exclusive NOR of two BDDs f and g. Returns a
+ pointer to the resulting BDD if successful; NULL if the intermediate
+ result blows up.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIte Cudd_addApply Cudd_bddAnd Cudd_bddOr
+ Cudd_bddNand Cudd_bddNor Cudd_bddXor]
+
+******************************************************************************/
+DdNode *
+Cudd_bddXnor(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddXorRecur(dd,f,Cudd_Not(g));
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddXnor */
+
+
+/**Function********************************************************************
+
+ Synopsis [Determines whether f is less than or equal to g.]
+
+ Description [Returns 1 if f is less than or equal to g; 0 otherwise.
+ No new nodes are created.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIteConstant Cudd_addEvalConst]
+
+******************************************************************************/
+int
+Cudd_bddLeq(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *one, *zero, *tmp, *F, *fv, *fvn, *gv, *gvn;
+ unsigned int topf, topg, res;
+
+ statLine(dd);
+ /* Terminal cases and normalization. */
+ if (f == g) return(1);
+
+ if (Cudd_IsComplement(g)) {
+ /* Special case: if f is regular and g is complemented,
+ ** f(1,...,1) = 1 > 0 = g(1,...,1).
+ */
+ if (!Cudd_IsComplement(f)) return(0);
+ /* Both are complemented: Swap and complement because
+ ** f <= g <=> g' <= f' and we want the second argument to be regular.
+ */
+ tmp = g;
+ g = Cudd_Not(f);
+ f = Cudd_Not(tmp);
+ } else if (Cudd_IsComplement(f) && g < f) {
+ tmp = g;
+ g = Cudd_Not(f);
+ f = Cudd_Not(tmp);
+ }
+
+ /* Now g is regular and, if f is not regular, f < g. */
+ one = DD_ONE(dd);
+ if (g == one) return(1); /* no need to test against zero */
+ if (f == one) return(0); /* since at this point g != one */
+ if (Cudd_Not(f) == g) return(0); /* because neither is constant */
+ zero = Cudd_Not(one);
+ if (f == zero) return(1);
+
+ /* Here neither f nor g is constant. */
+
+ /* Check cache. */
+ tmp = cuddCacheLookup2(dd,(DdNode * (*)(DdManager *, DdNode *,
+ DdNode *))Cudd_bddLeq,f,g);
+ if (tmp != NULL) {
+ return(tmp == one);
+ }
+
+ /* Compute cofactors. */
+ F = Cudd_Regular(f);
+ topf = dd->perm[F->index];
+ topg = dd->perm[g->index];
+ if (topf <= topg) {
+ fv = cuddT(F); fvn = cuddE(F);
+ if (f != F) {
+ fv = Cudd_Not(fv);
+ fvn = Cudd_Not(fvn);
+ }
+ } else {
+ fv = fvn = f;
+ }
+ if (topg <= topf) {
+ gv = cuddT(g); gvn = cuddE(g);
+ } else {
+ gv = gvn = g;
+ }
+
+ /* Recursive calls. Since we want to maximize the probability of
+ ** the special case f(1,...,1) > g(1,...,1), we consider the negative
+ ** cofactors first. Indeed, the complementation parity of the positive
+ ** cofactors is the same as the one of the parent functions.
+ */
+ res = Cudd_bddLeq(dd,fvn,gvn) && Cudd_bddLeq(dd,fv,gv);
+
+ /* Store result in cache and return. */
+ cuddCacheInsert2(dd,(DdNode * (*)(DdManager *, DdNode *, DdNode *))Cudd_bddLeq,f,g,(res ? one : zero));
+ return(res);
+
+} /* end of Cudd_bddLeq */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_bddIte.]
+
+ Description [Implements the recursive step of Cudd_bddIte. Returns a
+ pointer to the resulting BDD. NULL if the intermediate result blows
+ up or if reordering occurs.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddBddIteRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ DdNode *one, *zero, *res;
+ DdNode *r, *Fv, *Fnv, *Gv, *Gnv, *H, *Hv, *Hnv, *t, *e;
+ unsigned int topf, topg, toph, v;
+ int index;
+ int comple;
+
+ statLine(dd);
+ /* Terminal cases. */
+
+ /* One variable cases. */
+ if (f == (one = DD_ONE(dd))) /* ITE(1,G,H) = G */
+ return(g);
+
+ if (f == (zero = Cudd_Not(one))) /* ITE(0,G,H) = H */
+ return(h);
+
+ /* From now on, f is known not to be a constant. */
+ if (g == one || f == g) { /* ITE(F,F,H) = ITE(F,1,H) = F + H */
+ if (h == zero) { /* ITE(F,1,0) = F */
+ return(f);
+ } else {
+ res = cuddBddAndRecur(dd,Cudd_Not(f),Cudd_Not(h));
+ return(Cudd_NotCond(res,res != NULL));
+ }
+ } else if (g == zero || f == Cudd_Not(g)) { /* ITE(F,!F,H) = ITE(F,0,H) = !F * H */
+ if (h == one) { /* ITE(F,0,1) = !F */
+ return(Cudd_Not(f));
+ } else {
+ res = cuddBddAndRecur(dd,Cudd_Not(f),h);
+ return(res);
+ }
+ }
+ if (h == zero || f == h) { /* ITE(F,G,F) = ITE(F,G,0) = F * G */
+ res = cuddBddAndRecur(dd,f,g);
+ return(res);
+ } else if (h == one || f == Cudd_Not(h)) { /* ITE(F,G,!F) = ITE(F,G,1) = !F + G */
+ res = cuddBddAndRecur(dd,f,Cudd_Not(g));
+ return(Cudd_NotCond(res,res != NULL));
+ }
+
+ /* Check remaining one variable case. */
+ if (g == h) { /* ITE(F,G,G) = G */
+ return(g);
+ } else if (g == Cudd_Not(h)) { /* ITE(F,G,!G) = F <-> G */
+ res = cuddBddXorRecur(dd,f,h);
+ return(res);
+ }
+
+ /* From here, there are no constants. */
+ comple = bddVarToCanonicalSimple(dd, &f, &g, &h, &topf, &topg, &toph);
+
+ /* f & g are now regular pointers */
+
+ v = ddMin(topg, toph);
+
+ /* A shortcut: ITE(F,G,H) = (v,G,H) if F = (v,1,0), v < top(G,H). */
+ if (topf < v && cuddT(f) == one && cuddE(f) == zero) {
+ r = cuddUniqueInter(dd, (int) f->index, g, h);
+ return(Cudd_NotCond(r,comple && r != NULL));
+ }
+
+ /* Check cache. */
+ r = cuddCacheLookup(dd, DD_BDD_ITE_TAG, f, g, h);
+ if (r != NULL) {
+ return(Cudd_NotCond(r,comple));
+ }
+
+ /* Compute cofactors. */
+ if (topf <= v) {
+ v = ddMin(topf, v); /* v = top_var(F,G,H) */
+ index = f->index;
+ Fv = cuddT(f); Fnv = cuddE(f);
+ } else {
+ Fv = Fnv = f;
+ }
+ if (topg == v) {
+ index = g->index;
+ Gv = cuddT(g); Gnv = cuddE(g);
+ } else {
+ Gv = Gnv = g;
+ }
+ if (toph == v) {
+ H = Cudd_Regular(h);
+ index = H->index;
+ Hv = cuddT(H); Hnv = cuddE(H);
+ if (Cudd_IsComplement(h)) {
+ Hv = Cudd_Not(Hv);
+ Hnv = Cudd_Not(Hnv);
+ }
+ } else {
+ Hv = Hnv = h;
+ }
+
+ /* Recursive step. */
+ t = cuddBddIteRecur(dd,Fv,Gv,Hv);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+
+ e = cuddBddIteRecur(dd,Fnv,Gnv,Hnv);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(dd,t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ r = (t == e) ? t : cuddUniqueInter(dd,index,t,e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd,t);
+ Cudd_IterDerefBdd(dd,e);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ cuddCacheInsert(dd, DD_BDD_ITE_TAG, f, g, h, r);
+ return(Cudd_NotCond(r,comple));
+
+} /* end of cuddBddIteRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_bddIntersect.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIntersect]
+
+******************************************************************************/
+DdNode *
+cuddBddIntersectRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+ DdNode *F, *G, *t, *e;
+ DdNode *fv, *fnv, *gv, *gnv;
+ DdNode *one, *zero;
+ unsigned int index, topf, topg;
+
+ statLine(dd);
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ /* Terminal cases. */
+ if (f == zero || g == zero || f == Cudd_Not(g)) return(zero);
+ if (f == g || g == one) return(f);
+ if (f == one) return(g);
+
+ /* At this point f and g are not constant. */
+ if (f > g) { DdNode *tmp = f; f = g; g = tmp; }
+ res = cuddCacheLookup2(dd,Cudd_bddIntersect,f,g);
+ if (res != NULL) return(res);
+
+ /* Find splitting variable. Here we can skip the use of cuddI,
+ ** because the operands are known to be non-constant.
+ */
+ F = Cudd_Regular(f);
+ topf = dd->perm[F->index];
+ G = Cudd_Regular(g);
+ topg = dd->perm[G->index];
+
+ /* Compute cofactors. */
+ if (topf <= topg) {
+ index = F->index;
+ fv = cuddT(F);
+ fnv = cuddE(F);
+ if (Cudd_IsComplement(f)) {
+ fv = Cudd_Not(fv);
+ fnv = Cudd_Not(fnv);
+ }
+ } else {
+ index = G->index;
+ fv = fnv = f;
+ }
+
+ if (topg <= topf) {
+ gv = cuddT(G);
+ gnv = cuddE(G);
+ if (Cudd_IsComplement(g)) {
+ gv = Cudd_Not(gv);
+ gnv = Cudd_Not(gnv);
+ }
+ } else {
+ gv = gnv = g;
+ }
+
+ /* Compute partial results. */
+ t = cuddBddIntersectRecur(dd,fv,gv);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ if (t != zero) {
+ e = zero;
+ } else {
+ e = cuddBddIntersectRecur(dd,fnv,gnv);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ }
+ cuddRef(e);
+
+ if (t == e) { /* both equal zero */
+ res = t;
+ } else if (Cudd_IsComplement(t)) {
+ res = cuddUniqueInter(dd,(int)index,Cudd_Not(t),Cudd_Not(e));
+ if (res == NULL) {
+ Cudd_IterDerefBdd(dd, t);
+ Cudd_IterDerefBdd(dd, e);
+ return(NULL);
+ }
+ res = Cudd_Not(res);
+ } else {
+ res = cuddUniqueInter(dd,(int)index,t,e);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(dd, t);
+ Cudd_IterDerefBdd(dd, e);
+ return(NULL);
+ }
+ }
+ cuddDeref(e);
+ cuddDeref(t);
+
+ cuddCacheInsert2(dd,Cudd_bddIntersect,f,g,res);
+
+ return(res);
+
+} /* end of cuddBddIntersectRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_bddAnd.]
+
+ Description [Implements the recursive step of Cudd_bddAnd by taking
+ the conjunction of two BDDs. Returns a pointer to the result is
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddAnd]
+
+******************************************************************************/
+DdNode *
+cuddBddAndRecur(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *F, *fv, *fnv, *G, *gv, *gnv;
+ DdNode *one, *r, *t, *e;
+ unsigned int topf, topg, index;
+
+ statLine(manager);
+ one = DD_ONE(manager);
+
+ /* Terminal cases. */
+ F = Cudd_Regular(f);
+ G = Cudd_Regular(g);
+ if (F == G) {
+ if (f == g) return(f);
+ else return(Cudd_Not(one));
+ }
+ if (F == one) {
+ if (f == one) return(g);
+ else return(f);
+ }
+ if (G == one) {
+ if (g == one) return(f);
+ else return(g);
+ }
+
+ /* At this point f and g are not constant. */
+ if (f > g) { /* Try to increase cache efficiency. */
+ DdNode *tmp = f;
+ f = g;
+ g = tmp;
+ F = Cudd_Regular(f);
+ G = Cudd_Regular(g);
+ }
+
+ /* Check cache. */
+ if (F->ref != 1 || G->ref != 1) {
+ r = cuddCacheLookup2(manager, Cudd_bddAnd, f, g);
+ if (r != NULL) return(r);
+ }
+
+ /* Here we can skip the use of cuddI, because the operands are known
+ ** to be non-constant.
+ */
+ topf = manager->perm[F->index];
+ topg = manager->perm[G->index];
+
+ /* Compute cofactors. */
+ if (topf <= topg) {
+ index = F->index;
+ fv = cuddT(F);
+ fnv = cuddE(F);
+ if (Cudd_IsComplement(f)) {
+ fv = Cudd_Not(fv);
+ fnv = Cudd_Not(fnv);
+ }
+ } else {
+ index = G->index;
+ fv = fnv = f;
+ }
+
+ if (topg <= topf) {
+ gv = cuddT(G);
+ gnv = cuddE(G);
+ if (Cudd_IsComplement(g)) {
+ gv = Cudd_Not(gv);
+ gnv = Cudd_Not(gnv);
+ }
+ } else {
+ gv = gnv = g;
+ }
+
+ t = cuddBddAndRecur(manager, fv, gv);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+
+ e = cuddBddAndRecur(manager, fnv, gnv);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ if (t == e) {
+ r = t;
+ } else {
+ if (Cudd_IsComplement(t)) {
+ r = cuddUniqueInter(manager,(int)index,Cudd_Not(t),Cudd_Not(e));
+ if (r == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ Cudd_IterDerefBdd(manager, e);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = cuddUniqueInter(manager,(int)index,t,e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ Cudd_IterDerefBdd(manager, e);
+ return(NULL);
+ }
+ }
+ }
+ cuddDeref(e);
+ cuddDeref(t);
+ if (F->ref != 1 || G->ref != 1)
+ cuddCacheInsert2(manager, Cudd_bddAnd, f, g, r);
+ return(r);
+
+} /* end of cuddBddAndRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_bddXor.]
+
+ Description [Implements the recursive step of Cudd_bddXor by taking
+ the exclusive OR of two BDDs. Returns a pointer to the result is
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddXor]
+
+******************************************************************************/
+DdNode *
+cuddBddXorRecur(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *fv, *fnv, *G, *gv, *gnv;
+ DdNode *one, *zero, *r, *t, *e;
+ unsigned int topf, topg, index;
+
+ statLine(manager);
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ /* Terminal cases. */
+ if (f == g) return(zero);
+ if (f == Cudd_Not(g)) return(one);
+ if (f > g) { /* Try to increase cache efficiency and simplify tests. */
+ DdNode *tmp = f;
+ f = g;
+ g = tmp;
+ }
+ if (g == zero) return(f);
+ if (g == one) return(Cudd_Not(f));
+ if (Cudd_IsComplement(f)) {
+ f = Cudd_Not(f);
+ g = Cudd_Not(g);
+ }
+ /* Now the first argument is regular. */
+ if (f == one) return(Cudd_Not(g));
+
+ /* At this point f and g are not constant. */
+
+ /* Check cache. */
+ r = cuddCacheLookup2(manager, Cudd_bddXor, f, g);
+ if (r != NULL) return(r);
+
+ /* Here we can skip the use of cuddI, because the operands are known
+ ** to be non-constant.
+ */
+ topf = manager->perm[f->index];
+ G = Cudd_Regular(g);
+ topg = manager->perm[G->index];
+
+ /* Compute cofactors. */
+ if (topf <= topg) {
+ index = f->index;
+ fv = cuddT(f);
+ fnv = cuddE(f);
+ } else {
+ index = G->index;
+ fv = fnv = f;
+ }
+
+ if (topg <= topf) {
+ gv = cuddT(G);
+ gnv = cuddE(G);
+ if (Cudd_IsComplement(g)) {
+ gv = Cudd_Not(gv);
+ gnv = Cudd_Not(gnv);
+ }
+ } else {
+ gv = gnv = g;
+ }
+
+ t = cuddBddXorRecur(manager, fv, gv);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+
+ e = cuddBddXorRecur(manager, fnv, gnv);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ if (t == e) {
+ r = t;
+ } else {
+ if (Cudd_IsComplement(t)) {
+ r = cuddUniqueInter(manager,(int)index,Cudd_Not(t),Cudd_Not(e));
+ if (r == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ Cudd_IterDerefBdd(manager, e);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = cuddUniqueInter(manager,(int)index,t,e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ Cudd_IterDerefBdd(manager, e);
+ return(NULL);
+ }
+ }
+ }
+ cuddDeref(e);
+ cuddDeref(t);
+ cuddCacheInsert2(manager, Cudd_bddXor, f, g, r);
+ return(r);
+
+} /* end of cuddBddXorRecur */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Replaces variables with constants if possible.]
+
+ Description [This function performs part of the transformation to
+ standard form by replacing variables with constants if possible.]
+
+ SideEffects [None]
+
+ SeeAlso [bddVarToCanonical bddVarToCanonicalSimple]
+
+******************************************************************************/
+static void
+bddVarToConst(
+ DdNode * f,
+ DdNode ** gp,
+ DdNode ** hp,
+ DdNode * one)
+{
+ DdNode *g = *gp;
+ DdNode *h = *hp;
+
+ if (f == g) { /* ITE(F,F,H) = ITE(F,1,H) = F + H */
+ *gp = one;
+ } else if (f == Cudd_Not(g)) { /* ITE(F,!F,H) = ITE(F,0,H) = !F * H */
+ *gp = Cudd_Not(one);
+ }
+ if (f == h) { /* ITE(F,G,F) = ITE(F,G,0) = F * G */
+ *hp = Cudd_Not(one);
+ } else if (f == Cudd_Not(h)) { /* ITE(F,G,!F) = ITE(F,G,1) = !F + G */
+ *hp = one;
+ }
+
+} /* end of bddVarToConst */
+
+
+/**Function********************************************************************
+
+ Synopsis [Picks unique member from equiv expressions.]
+
+ Description [Reduces 2 variable expressions to canonical form.]
+
+ SideEffects [None]
+
+ SeeAlso [bddVarToConst bddVarToCanonicalSimple]
+
+******************************************************************************/
+static int
+bddVarToCanonical(
+ DdManager * dd,
+ DdNode ** fp,
+ DdNode ** gp,
+ DdNode ** hp,
+ unsigned int * topfp,
+ unsigned int * topgp,
+ unsigned int * tophp)
+{
+ register DdNode *F, *G, *H, *r, *f, *g, *h;
+ register unsigned int topf, topg, toph;
+ DdNode *one = dd->one;
+ int comple, change;
+
+ f = *fp;
+ g = *gp;
+ h = *hp;
+ F = Cudd_Regular(f);
+ G = Cudd_Regular(g);
+ H = Cudd_Regular(h);
+ topf = cuddI(dd,F->index);
+ topg = cuddI(dd,G->index);
+ toph = cuddI(dd,H->index);
+
+ change = 0;
+
+ if (G == one) { /* ITE(F,c,H) */
+ if ((topf > toph) || (topf == toph && f > h)) {
+ r = h;
+ h = f;
+ f = r; /* ITE(F,1,H) = ITE(H,1,F) */
+ if (g != one) { /* g == zero */
+ f = Cudd_Not(f); /* ITE(F,0,H) = ITE(!H,0,!F) */
+ h = Cudd_Not(h);
+ }
+ change = 1;
+ }
+ } else if (H == one) { /* ITE(F,G,c) */
+ if ((topf > topg) || (topf == topg && f > g)) {
+ r = g;
+ g = f;
+ f = r; /* ITE(F,G,0) = ITE(G,F,0) */
+ if (h == one) {
+ f = Cudd_Not(f); /* ITE(F,G,1) = ITE(!G,!F,1) */
+ g = Cudd_Not(g);
+ }
+ change = 1;
+ }
+ } else if (g == Cudd_Not(h)) { /* ITE(F,G,!G) = ITE(G,F,!F) */
+ if ((topf > topg) || (topf == topg && f > g)) {
+ r = f;
+ f = g;
+ g = r;
+ h = Cudd_Not(r);
+ change = 1;
+ }
+ }
+ /* adjust pointers so that the first 2 arguments to ITE are regular */
+ if (Cudd_IsComplement(f) != 0) { /* ITE(!F,G,H) = ITE(F,H,G) */
+ f = Cudd_Not(f);
+ r = g;
+ g = h;
+ h = r;
+ change = 1;
+ }
+ comple = 0;
+ if (Cudd_IsComplement(g) != 0) { /* ITE(F,!G,H) = !ITE(F,G,!H) */
+ g = Cudd_Not(g);
+ h = Cudd_Not(h);
+ change = 1;
+ comple = 1;
+ }
+ if (change != 0) {
+ *fp = f;
+ *gp = g;
+ *hp = h;
+ }
+ *topfp = cuddI(dd,f->index);
+ *topgp = cuddI(dd,g->index);
+ *tophp = cuddI(dd,Cudd_Regular(h)->index);
+
+ return(comple);
+
+} /* end of bddVarToCanonical */
+
+
+/**Function********************************************************************
+
+ Synopsis [Picks unique member from equiv expressions.]
+
+ Description [Makes sure the first two pointers are regular. This
+ mat require the complementation of the result, which is signaled by
+ returning 1 instead of 0. This function is simpler than the general
+ case because it assumes that no two arguments are the same or
+ complementary, and no argument is constant.]
+
+ SideEffects [None]
+
+ SeeAlso [bddVarToConst bddVarToCanonical]
+
+******************************************************************************/
+static int
+bddVarToCanonicalSimple(
+ DdManager * dd,
+ DdNode ** fp,
+ DdNode ** gp,
+ DdNode ** hp,
+ unsigned int * topfp,
+ unsigned int * topgp,
+ unsigned int * tophp)
+{
+ register DdNode *r, *f, *g, *h;
+ int comple, change;
+
+ f = *fp;
+ g = *gp;
+ h = *hp;
+
+ change = 0;
+
+ /* adjust pointers so that the first 2 arguments to ITE are regular */
+ if (Cudd_IsComplement(f)) { /* ITE(!F,G,H) = ITE(F,H,G) */
+ f = Cudd_Not(f);
+ r = g;
+ g = h;
+ h = r;
+ change = 1;
+ }
+ comple = 0;
+ if (Cudd_IsComplement(g)) { /* ITE(F,!G,H) = !ITE(F,G,!H) */
+ g = Cudd_Not(g);
+ h = Cudd_Not(h);
+ change = 1;
+ comple = 1;
+ }
+ if (change) {
+ *fp = f;
+ *gp = g;
+ *hp = h;
+ }
+
+ /* Here we can skip the use of cuddI, because the operands are known
+ ** to be non-constant.
+ */
+ *topfp = dd->perm[f->index];
+ *topgp = dd->perm[g->index];
+ *tophp = dd->perm[Cudd_Regular(h)->index];
+
+ return(comple);
+
+} /* end of bddVarToCanonicalSimple */
+
diff --git a/src/bdd/cudd/cuddBridge.c b/src/bdd/cudd/cuddBridge.c
new file mode 100644
index 00000000..e7e5c89f
--- /dev/null
+++ b/src/bdd/cudd/cuddBridge.c
@@ -0,0 +1,981 @@
+/**CFile***********************************************************************
+
+ FileName [cuddBridge.c]
+
+ PackageName [cudd]
+
+ Synopsis [Translation from BDD to ADD and vice versa and transfer between
+ different managers.]
+
+ Description [External procedures included in this file:
+ <ul>
+ <li> Cudd_addBddThreshold()
+ <li> Cudd_addBddStrictThreshold()
+ <li> Cudd_addBddInterval()
+ <li> Cudd_addBddIthBit()
+ <li> Cudd_BddToAdd()
+ <li> Cudd_addBddPattern()
+ <li> Cudd_bddTransfer()
+ </ul>
+ Internal procedures included in this file:
+ <ul>
+ <li> cuddBddTransfer()
+ <li> cuddAddBddDoPattern()
+ </ul>
+ Static procedures included in this file:
+ <ul>
+ <li> addBddDoThreshold()
+ <li> addBddDoStrictThreshold()
+ <li> addBddDoInterval()
+ <li> addBddDoIthBit()
+ <li> ddBddToAddRecur()
+ <li> cuddBddTransferRecur()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddBridge.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdNode * addBddDoThreshold ARGS((DdManager *dd, DdNode *f, DdNode *val));
+static DdNode * addBddDoStrictThreshold ARGS((DdManager *dd, DdNode *f, DdNode *val));
+static DdNode * addBddDoInterval ARGS((DdManager *dd, DdNode *f, DdNode *l, DdNode *u));
+static DdNode * addBddDoIthBit ARGS((DdManager *dd, DdNode *f, DdNode *index));
+static DdNode * ddBddToAddRecur ARGS((DdManager *dd, DdNode *B));
+static DdNode * cuddBddTransferRecur ARGS((DdManager *ddS, DdManager *ddD, DdNode *f, st_table *table));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts an ADD to a BDD.]
+
+ Description [Converts an ADD to a BDD by replacing all
+ discriminants greater than or equal to value with 1, and all other
+ discriminants with 0. Returns a pointer to the resulting BDD if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addBddInterval Cudd_addBddPattern Cudd_BddToAdd
+ Cudd_addBddStrictThreshold]
+
+******************************************************************************/
+DdNode *
+Cudd_addBddThreshold(
+ DdManager * dd,
+ DdNode * f,
+ CUDD_VALUE_TYPE value)
+{
+ DdNode *res;
+ DdNode *val;
+
+ val = cuddUniqueConst(dd,value);
+ if (val == NULL) return(NULL);
+ cuddRef(val);
+
+ do {
+ dd->reordered = 0;
+ res = addBddDoThreshold(dd, f, val);
+ } while (dd->reordered == 1);
+
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, val);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, val);
+ cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_addBddThreshold */
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts an ADD to a BDD.]
+
+ Description [Converts an ADD to a BDD by replacing all
+ discriminants STRICTLY greater than value with 1, and all other
+ discriminants with 0. Returns a pointer to the resulting BDD if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addBddInterval Cudd_addBddPattern Cudd_BddToAdd
+ Cudd_addBddThreshold]
+
+******************************************************************************/
+DdNode *
+Cudd_addBddStrictThreshold(
+ DdManager * dd,
+ DdNode * f,
+ CUDD_VALUE_TYPE value)
+{
+ DdNode *res;
+ DdNode *val;
+
+ val = cuddUniqueConst(dd,value);
+ if (val == NULL) return(NULL);
+ cuddRef(val);
+
+ do {
+ dd->reordered = 0;
+ res = addBddDoStrictThreshold(dd, f, val);
+ } while (dd->reordered == 1);
+
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, val);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, val);
+ cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_addBddStrictThreshold */
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts an ADD to a BDD.]
+
+ Description [Converts an ADD to a BDD by replacing all
+ discriminants greater than or equal to lower and less than or equal to
+ upper with 1, and all other discriminants with 0. Returns a pointer to
+ the resulting BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addBddThreshold Cudd_addBddStrictThreshold
+ Cudd_addBddPattern Cudd_BddToAdd]
+
+******************************************************************************/
+DdNode *
+Cudd_addBddInterval(
+ DdManager * dd,
+ DdNode * f,
+ CUDD_VALUE_TYPE lower,
+ CUDD_VALUE_TYPE upper)
+{
+ DdNode *res;
+ DdNode *l;
+ DdNode *u;
+
+ /* Create constant nodes for the interval bounds, so that we can use
+ ** the global cache.
+ */
+ l = cuddUniqueConst(dd,lower);
+ if (l == NULL) return(NULL);
+ cuddRef(l);
+ u = cuddUniqueConst(dd,upper);
+ if (u == NULL) {
+ Cudd_RecursiveDeref(dd,l);
+ return(NULL);
+ }
+ cuddRef(u);
+
+ do {
+ dd->reordered = 0;
+ res = addBddDoInterval(dd, f, l, u);
+ } while (dd->reordered == 1);
+
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, l);
+ Cudd_RecursiveDeref(dd, u);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, l);
+ Cudd_RecursiveDeref(dd, u);
+ cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_addBddInterval */
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts an ADD to a BDD by extracting the i-th bit from
+ the leaves.]
+
+ Description [Converts an ADD to a BDD by replacing all
+ discriminants whose i-th bit is equal to 1 with 1, and all other
+ discriminants with 0. The i-th bit refers to the integer
+ representation of the leaf value. If the value is has a fractional
+ part, it is ignored. Repeated calls to this procedure allow one to
+ transform an integer-valued ADD into an array of BDDs, one for each
+ bit of the leaf values. Returns a pointer to the resulting BDD if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addBddInterval Cudd_addBddPattern Cudd_BddToAdd]
+
+******************************************************************************/
+DdNode *
+Cudd_addBddIthBit(
+ DdManager * dd,
+ DdNode * f,
+ int bit)
+{
+ DdNode *res;
+ DdNode *index;
+
+ index = cuddUniqueConst(dd,(CUDD_VALUE_TYPE) bit);
+ if (index == NULL) return(NULL);
+ cuddRef(index);
+
+ do {
+ dd->reordered = 0;
+ res = addBddDoIthBit(dd, f, index);
+ } while (dd->reordered == 1);
+
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, index);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, index);
+ cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_addBddIthBit */
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts a BDD to a 0-1 ADD.]
+
+ Description [Converts a BDD to a 0-1 ADD. Returns a pointer to the
+ resulting ADD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addBddPattern Cudd_addBddThreshold Cudd_addBddInterval
+ Cudd_addBddStrictThreshold]
+
+******************************************************************************/
+DdNode *
+Cudd_BddToAdd(
+ DdManager * dd,
+ DdNode * B)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = ddBddToAddRecur(dd, B);
+ } while (dd->reordered ==1);
+ return(res);
+
+} /* end of Cudd_BddToAdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts an ADD to a BDD.]
+
+ Description [Converts an ADD to a BDD by replacing all
+ discriminants different from 0 with 1. Returns a pointer to the
+ resulting BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_BddToAdd Cudd_addBddThreshold Cudd_addBddInterval
+ Cudd_addBddStrictThreshold]
+
+******************************************************************************/
+DdNode *
+Cudd_addBddPattern(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddAddBddDoPattern(dd, f);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addBddPattern */
+
+
+/**Function********************************************************************
+
+ Synopsis [Convert a BDD from a manager to another one.]
+
+ Description [Convert a BDD from a manager to another one. The orders of the
+ variables in the two managers may be different. Returns a
+ pointer to the BDD in the destination manager if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_bddTransfer(
+ DdManager * ddSource,
+ DdManager * ddDestination,
+ DdNode * f)
+{
+ DdNode *res;
+ do {
+ ddDestination->reordered = 0;
+ res = cuddBddTransfer(ddSource, ddDestination, f);
+ } while (ddDestination->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddTransfer */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Convert a BDD from a manager to another one.]
+
+ Description [Convert a BDD from a manager to another one. Returns a
+ pointer to the BDD in the destination manager if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddTransfer]
+
+******************************************************************************/
+DdNode *
+cuddBddTransfer(
+ DdManager * ddS,
+ DdManager * ddD,
+ DdNode * f)
+{
+ DdNode *res;
+ st_table *table = NULL;
+ st_generator *gen = NULL;
+ DdNode *key, *value;
+
+ table = st_init_table(st_ptrcmp,st_ptrhash);
+ if (table == NULL) goto failure;
+ res = cuddBddTransferRecur(ddS, ddD, f, table);
+ if (res != NULL) cuddRef(res);
+
+ /* Dereference all elements in the table and dispose of the table.
+ ** This must be done also if res is NULL to avoid leaks in case of
+ ** reordering. */
+ gen = st_init_gen(table);
+ if (gen == NULL) goto failure;
+ while (st_gen(gen, (char **) &key, (char **) &value)) {
+ Cudd_RecursiveDeref(ddD, value);
+ }
+ st_free_gen(gen); gen = NULL;
+ st_free_table(table); table = NULL;
+
+ if (res != NULL) cuddDeref(res);
+ return(res);
+
+failure:
+ if (table != NULL) st_free_table(table);
+ if (gen != NULL) st_free_gen(gen);
+ return(NULL);
+
+} /* end of cuddBddTransfer */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step for Cudd_addBddPattern.]
+
+ Description [Performs the recursive step for Cudd_addBddPattern. Returns a
+ pointer to the resulting BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddAddBddDoPattern(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode *res, *T, *E;
+ DdNode *fv, *fvn;
+ int v;
+
+ statLine(dd);
+ /* Check terminal case. */
+ if (cuddIsConstant(f)) {
+ return(Cudd_NotCond(DD_ONE(dd),f == DD_ZERO(dd)));
+ }
+
+ /* Check cache. */
+ res = cuddCacheLookup1(dd,Cudd_addBddPattern,f);
+ if (res != NULL) return(res);
+
+ /* Recursive step. */
+ v = f->index;
+ fv = cuddT(f); fvn = cuddE(f);
+
+ T = cuddAddBddDoPattern(dd,fv);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+
+ E = cuddAddBddDoPattern(dd,fvn);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ return(NULL);
+ }
+ cuddRef(E);
+ if (Cudd_IsComplement(T)) {
+ res = (T == E) ? Cudd_Not(T) : cuddUniqueInter(dd,v,Cudd_Not(T),Cudd_Not(E));
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ res = Cudd_Not(res);
+ } else {
+ res = (T == E) ? T : cuddUniqueInter(dd,v,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+
+ /* Store result. */
+ cuddCacheInsert1(dd,Cudd_addBddPattern,f,res);
+
+ return(res);
+
+} /* end of cuddAddBddDoPattern */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step for Cudd_addBddThreshold.]
+
+ Description [Performs the recursive step for Cudd_addBddThreshold.
+ Returns a pointer to the BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [addBddDoStrictThreshold]
+
+******************************************************************************/
+static DdNode *
+addBddDoThreshold(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * val)
+{
+ DdNode *res, *T, *E;
+ DdNode *fv, *fvn;
+ int v;
+
+ statLine(dd);
+ /* Check terminal case. */
+ if (cuddIsConstant(f)) {
+ return(Cudd_NotCond(DD_ONE(dd),cuddV(f) < cuddV(val)));
+ }
+
+ /* Check cache. */
+ res = cuddCacheLookup2(dd,addBddDoThreshold,f,val);
+ if (res != NULL) return(res);
+
+ /* Recursive step. */
+ v = f->index;
+ fv = cuddT(f); fvn = cuddE(f);
+
+ T = addBddDoThreshold(dd,fv,val);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+
+ E = addBddDoThreshold(dd,fvn,val);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ return(NULL);
+ }
+ cuddRef(E);
+ if (Cudd_IsComplement(T)) {
+ res = (T == E) ? Cudd_Not(T) : cuddUniqueInter(dd,v,Cudd_Not(T),Cudd_Not(E));
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ res = Cudd_Not(res);
+ } else {
+ res = (T == E) ? T : cuddUniqueInter(dd,v,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+
+ /* Store result. */
+ cuddCacheInsert2(dd,addBddDoThreshold,f,val,res);
+
+ return(res);
+
+} /* end of addBddDoThreshold */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step for Cudd_addBddStrictThreshold.]
+
+ Description [Performs the recursive step for Cudd_addBddStrictThreshold.
+ Returns a pointer to the BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [addBddDoThreshold]
+
+******************************************************************************/
+static DdNode *
+addBddDoStrictThreshold(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * val)
+{
+ DdNode *res, *T, *E;
+ DdNode *fv, *fvn;
+ int v;
+
+ statLine(dd);
+ /* Check terminal case. */
+ if (cuddIsConstant(f)) {
+ return(Cudd_NotCond(DD_ONE(dd),cuddV(f) <= cuddV(val)));
+ }
+
+ /* Check cache. */
+ res = cuddCacheLookup2(dd,addBddDoStrictThreshold,f,val);
+ if (res != NULL) return(res);
+
+ /* Recursive step. */
+ v = f->index;
+ fv = cuddT(f); fvn = cuddE(f);
+
+ T = addBddDoStrictThreshold(dd,fv,val);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+
+ E = addBddDoStrictThreshold(dd,fvn,val);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ return(NULL);
+ }
+ cuddRef(E);
+ if (Cudd_IsComplement(T)) {
+ res = (T == E) ? Cudd_Not(T) : cuddUniqueInter(dd,v,Cudd_Not(T),Cudd_Not(E));
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ res = Cudd_Not(res);
+ } else {
+ res = (T == E) ? T : cuddUniqueInter(dd,v,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+
+ /* Store result. */
+ cuddCacheInsert2(dd,addBddDoStrictThreshold,f,val,res);
+
+ return(res);
+
+} /* end of addBddDoStrictThreshold */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step for Cudd_addBddInterval.]
+
+ Description [Performs the recursive step for Cudd_addBddInterval.
+ Returns a pointer to the BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [addBddDoThreshold addBddDoStrictThreshold]
+
+******************************************************************************/
+static DdNode *
+addBddDoInterval(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * l,
+ DdNode * u)
+{
+ DdNode *res, *T, *E;
+ DdNode *fv, *fvn;
+ int v;
+
+ statLine(dd);
+ /* Check terminal case. */
+ if (cuddIsConstant(f)) {
+ return(Cudd_NotCond(DD_ONE(dd),cuddV(f) < cuddV(l) || cuddV(f) > cuddV(u)));
+ }
+
+ /* Check cache. */
+ res = cuddCacheLookup(dd,DD_ADD_BDD_DO_INTERVAL_TAG,f,l,u);
+ if (res != NULL) return(res);
+
+ /* Recursive step. */
+ v = f->index;
+ fv = cuddT(f); fvn = cuddE(f);
+
+ T = addBddDoInterval(dd,fv,l,u);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+
+ E = addBddDoInterval(dd,fvn,l,u);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ return(NULL);
+ }
+ cuddRef(E);
+ if (Cudd_IsComplement(T)) {
+ res = (T == E) ? Cudd_Not(T) : cuddUniqueInter(dd,v,Cudd_Not(T),Cudd_Not(E));
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ res = Cudd_Not(res);
+ } else {
+ res = (T == E) ? T : cuddUniqueInter(dd,v,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+
+ /* Store result. */
+ cuddCacheInsert(dd,DD_ADD_BDD_DO_INTERVAL_TAG,f,l,u,res);
+
+ return(res);
+
+} /* end of addBddDoInterval */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step for Cudd_addBddIthBit.]
+
+ Description [Performs the recursive step for Cudd_addBddIthBit.
+ Returns a pointer to the BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+addBddDoIthBit(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * index)
+{
+ DdNode *res, *T, *E;
+ DdNode *fv, *fvn;
+ int mask, value;
+ int v;
+
+ statLine(dd);
+ /* Check terminal case. */
+ if (cuddIsConstant(f)) {
+ mask = 1 << ((int) cuddV(index));
+ value = (int) cuddV(f);
+ return(Cudd_NotCond(DD_ONE(dd),(value & mask) == 0));
+ }
+
+ /* Check cache. */
+ res = cuddCacheLookup2(dd,addBddDoIthBit,f,index);
+ if (res != NULL) return(res);
+
+ /* Recursive step. */
+ v = f->index;
+ fv = cuddT(f); fvn = cuddE(f);
+
+ T = addBddDoIthBit(dd,fv,index);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+
+ E = addBddDoIthBit(dd,fvn,index);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ return(NULL);
+ }
+ cuddRef(E);
+ if (Cudd_IsComplement(T)) {
+ res = (T == E) ? Cudd_Not(T) : cuddUniqueInter(dd,v,Cudd_Not(T),Cudd_Not(E));
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ res = Cudd_Not(res);
+ } else {
+ res = (T == E) ? T : cuddUniqueInter(dd,v,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+
+ /* Store result. */
+ cuddCacheInsert2(dd,addBddDoIthBit,f,index,res);
+
+ return(res);
+
+} /* end of addBddDoIthBit */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step for Cudd_BddToAdd.]
+
+ Description [Performs the recursive step for Cudd_BddToAdd. Returns a
+ pointer to the resulting ADD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+ddBddToAddRecur(
+ DdManager * dd,
+ DdNode * B)
+{
+ DdNode *one;
+ DdNode *res, *res1, *T, *E, *Bt, *Be;
+ int complement = 0;
+
+ statLine(dd);
+ one = DD_ONE(dd);
+
+ if (Cudd_IsConstant(B)) {
+ if (B == one) {
+ res = one;
+ } else {
+ res = DD_ZERO(dd);
+ }
+ return(res);
+ }
+ /* Check visited table */
+ res = cuddCacheLookup1(dd,ddBddToAddRecur,B);
+ if (res != NULL) return(res);
+
+ if (Cudd_IsComplement(B)) {
+ complement = 1;
+ Bt = cuddT(Cudd_Regular(B));
+ Be = cuddE(Cudd_Regular(B));
+ } else {
+ Bt = cuddT(B);
+ Be = cuddE(B);
+ }
+
+ T = ddBddToAddRecur(dd, Bt);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+
+ E = ddBddToAddRecur(dd, Be);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ return(NULL);
+ }
+ cuddRef(E);
+
+ /* No need to check for T == E, because it is guaranteed not to happen. */
+ res = cuddUniqueInter(dd, (int) Cudd_Regular(B)->index, T, E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd ,T);
+ Cudd_RecursiveDeref(dd ,E);
+ return(NULL);
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+
+ if (complement) {
+ cuddRef(res);
+ res1 = cuddAddCmplRecur(dd, res);
+ if (res1 == NULL) {
+ Cudd_RecursiveDeref(dd, res);
+ return(NULL);
+ }
+ cuddRef(res1);
+ Cudd_RecursiveDeref(dd, res);
+ res = res1;
+ cuddDeref(res);
+ }
+
+ /* Store result. */
+ cuddCacheInsert1(dd,ddBddToAddRecur,B,res);
+
+ return(res);
+
+} /* end of ddBddToAddRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddTransfer.]
+
+ Description [Performs the recursive step of Cudd_bddTransfer.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddBddTransfer]
+
+******************************************************************************/
+static DdNode *
+cuddBddTransferRecur(
+ DdManager * ddS,
+ DdManager * ddD,
+ DdNode * f,
+ st_table * table)
+{
+ DdNode *ft, *fe, *t, *e, *var, *res;
+ DdNode *one, *zero;
+ int index;
+ int comple = 0;
+
+ statLine(ddD);
+ one = DD_ONE(ddD);
+ comple = Cudd_IsComplement(f);
+
+ /* Trivial cases. */
+ if (Cudd_IsConstant(f)) return(Cudd_NotCond(one, comple));
+
+ /* Make canonical to increase the utilization of the cache. */
+ f = Cudd_NotCond(f,comple);
+ /* Now f is a regular pointer to a non-constant node. */
+
+ /* Check the cache. */
+ if(st_lookup(table, (char *)f, (char **) &res))
+ return(Cudd_NotCond(res,comple));
+
+ /* Recursive step. */
+ index = f->index;
+ ft = cuddT(f); fe = cuddE(f);
+
+ t = cuddBddTransferRecur(ddS, ddD, ft, table);
+ if (t == NULL) {
+ return(NULL);
+ }
+ cuddRef(t);
+
+ e = cuddBddTransferRecur(ddS, ddD, fe, table);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(ddD, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ zero = Cudd_Not(one);
+ var = cuddUniqueInter(ddD,index,one,zero);
+ if (var == NULL) {
+ Cudd_RecursiveDeref(ddD, t);
+ Cudd_RecursiveDeref(ddD, e);
+ return(NULL);
+ }
+ res = cuddBddIteRecur(ddD,var,t,e);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(ddD, t);
+ Cudd_RecursiveDeref(ddD, e);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(ddD, t);
+ Cudd_RecursiveDeref(ddD, e);
+
+ if (st_add_direct(table, (char *) f, (char *) res) == ST_OUT_OF_MEM) {
+ Cudd_RecursiveDeref(ddD, res);
+ return(NULL);
+ }
+ return(Cudd_NotCond(res,comple));
+
+} /* end of cuddBddTransferRecur */
+
diff --git a/src/bdd/cudd/cuddCache.c b/src/bdd/cudd/cuddCache.c
new file mode 100644
index 00000000..6598948a
--- /dev/null
+++ b/src/bdd/cudd/cuddCache.c
@@ -0,0 +1,1023 @@
+/**CFile***********************************************************************
+
+ FileName [cuddCache.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for cache insertion and lookup.]
+
+ Description [Internal procedures included in this module:
+ <ul>
+ <li> cuddInitCache()
+ <li> cuddCacheInsert()
+ <li> cuddCacheInsert2()
+ <li> cuddCacheLookup()
+ <li> cuddCacheLookupZdd()
+ <li> cuddCacheLookup2()
+ <li> cuddCacheLookup2Zdd()
+ <li> cuddConstantLookup()
+ <li> cuddCacheProfile()
+ <li> cuddCacheResize()
+ <li> cuddCacheFlush()
+ <li> cuddComputeFloorLog2()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ </ul> ]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifdef DD_CACHE_PROFILE
+#define DD_HYSTO_BINS 8
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddCache.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Initializes the computed table.]
+
+ Description [Initializes the computed table. It is called by
+ Cudd_Init. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Init]
+
+******************************************************************************/
+int
+cuddInitCache(
+ DdManager * unique /* unique table */,
+ unsigned int cacheSize /* initial size of the cache */,
+ unsigned int maxCacheSize /* cache size beyond which no resizing occurs */)
+{
+ int i;
+ unsigned int logSize;
+#ifndef DD_CACHE_PROFILE
+ DdNodePtr *mem;
+ ptruint offset;
+#endif
+
+ /* Round cacheSize to largest power of 2 not greater than the requested
+ ** initial cache size. */
+ logSize = cuddComputeFloorLog2(ddMax(cacheSize,unique->slots/2));
+ cacheSize = 1 << logSize;
+ unique->acache = ALLOC(DdCache,cacheSize+1);
+ if (unique->acache == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ /* If the size of the cache entry is a power of 2, we want to
+ ** enforce alignment to that power of two. This happens when
+ ** DD_CACHE_PROFILE is not defined. */
+#ifdef DD_CACHE_PROFILE
+ unique->cache = unique->acache;
+ unique->memused += (cacheSize) * sizeof(DdCache);
+#else
+ mem = (DdNodePtr *) unique->acache;
+ offset = (ptruint) mem & (sizeof(DdCache) - 1);
+ mem += (sizeof(DdCache) - offset) / sizeof(DdNodePtr);
+ unique->cache = (DdCache *) mem;
+ assert(((ptruint) unique->cache & (sizeof(DdCache) - 1)) == 0);
+ unique->memused += (cacheSize+1) * sizeof(DdCache);
+#endif
+ unique->cacheSlots = cacheSize;
+ unique->cacheShift = sizeof(int) * 8 - logSize;
+ unique->maxCacheHard = maxCacheSize;
+ /* If cacheSlack is non-negative, we can resize. */
+ unique->cacheSlack = (int) ddMin(maxCacheSize,
+ DD_MAX_CACHE_TO_SLOTS_RATIO*unique->slots) -
+ 2 * (int) cacheSize;
+ Cudd_SetMinHit(unique,DD_MIN_HIT);
+ /* Initialize to avoid division by 0 and immediate resizing. */
+ unique->cacheMisses = (double) (int) (cacheSize * unique->minHit + 1);
+ unique->cacheHits = 0;
+ unique->totCachehits = 0;
+ /* The sum of cacheMisses and totCacheMisses is always correct,
+ ** even though cacheMisses is larger than it should for the reasons
+ ** explained above. */
+ unique->totCacheMisses = -unique->cacheMisses;
+ unique->cachecollisions = 0;
+ unique->cacheinserts = 0;
+ unique->cacheLastInserts = 0;
+ unique->cachedeletions = 0;
+
+ /* Initialize the cache */
+ for (i = 0; (unsigned) i < cacheSize; i++) {
+ unique->cache[i].h = 0; /* unused slots */
+ unique->cache[i].data = NULL; /* invalid entry */
+#ifdef DD_CACHE_PROFILE
+ unique->cache[i].count = 0;
+#endif
+ }
+
+ return(1);
+
+} /* end of cuddInitCache */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts a result in the cache.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [cuddCacheInsert2 cuddCacheInsert1]
+
+******************************************************************************/
+void
+cuddCacheInsert(
+ DdManager * table,
+ ptruint op,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h,
+ DdNode * data)
+{
+ int posn;
+ register DdCache *entry;
+ ptruint uf, ug, uh;
+
+ uf = (ptruint) f | (op & 0xe);
+ ug = (ptruint) g | (op >> 4);
+ uh = (ptruint) h;
+
+ posn = ddCHash2(uh,uf,ug,table->cacheShift);
+ entry = &table->cache[posn];
+
+ table->cachecollisions += entry->data != NULL;
+ table->cacheinserts++;
+
+ entry->f = (DdNode *) uf;
+ entry->g = (DdNode *) ug;
+ entry->h = uh;
+ entry->data = data;
+#ifdef DD_CACHE_PROFILE
+ entry->count++;
+#endif
+
+} /* end of cuddCacheInsert */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts a result in the cache for a function with two
+ operands.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [cuddCacheInsert cuddCacheInsert1]
+
+******************************************************************************/
+void
+cuddCacheInsert2(
+ DdManager * table,
+ DdNode * (*op)(DdManager *, DdNode *, DdNode *),
+ DdNode * f,
+ DdNode * g,
+ DdNode * data)
+{
+ int posn;
+ register DdCache *entry;
+
+ posn = ddCHash2(op,f,g,table->cacheShift);
+ entry = &table->cache[posn];
+
+ if (entry->data != NULL) {
+ table->cachecollisions++;
+ }
+ table->cacheinserts++;
+
+ entry->f = f;
+ entry->g = g;
+ entry->h = (ptruint) op;
+ entry->data = data;
+#ifdef DD_CACHE_PROFILE
+ entry->count++;
+#endif
+
+} /* end of cuddCacheInsert2 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts a result in the cache for a function with two
+ operands.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [cuddCacheInsert cuddCacheInsert2]
+
+******************************************************************************/
+void
+cuddCacheInsert1(
+ DdManager * table,
+ DdNode * (*op)(DdManager *, DdNode *),
+ DdNode * f,
+ DdNode * data)
+{
+ int posn;
+ register DdCache *entry;
+
+ posn = ddCHash2(op,f,f,table->cacheShift);
+ entry = &table->cache[posn];
+
+ if (entry->data != NULL) {
+ table->cachecollisions++;
+ }
+ table->cacheinserts++;
+
+ entry->f = f;
+ entry->g = f;
+ entry->h = (ptruint) op;
+ entry->data = data;
+#ifdef DD_CACHE_PROFILE
+ entry->count++;
+#endif
+
+} /* end of cuddCacheInsert1 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up in the cache for the result of op applied to f,
+ g, and h.]
+
+ Description [Returns the result if found; it returns NULL if no
+ result is found.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddCacheLookup2 cuddCacheLookup1]
+
+******************************************************************************/
+DdNode *
+cuddCacheLookup(
+ DdManager * table,
+ ptruint op,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ int posn;
+ DdCache *en,*cache;
+ DdNode *data;
+ ptruint uf, ug, uh;
+
+ uf = (ptruint) f | (op & 0xe);
+ ug = (ptruint) g | (op >> 4);
+ uh = (ptruint) h;
+
+ cache = table->cache;
+#ifdef DD_DEBUG
+ if (cache == NULL) {
+ return(NULL);
+ }
+#endif
+
+ posn = ddCHash2(uh,uf,ug,table->cacheShift);
+ en = &cache[posn];
+ if (en->data != NULL && en->f==(DdNodePtr)uf && en->g==(DdNodePtr)ug &&
+ en->h==uh) {
+ data = Cudd_Regular(en->data);
+ table->cacheHits++;
+ if (data->ref == 0) {
+ cuddReclaim(table,data);
+ }
+ return(en->data);
+ }
+
+ /* Cache miss: decide whether to resize. */
+ table->cacheMisses++;
+
+ if (table->cacheSlack >= 0 &&
+ table->cacheHits > table->cacheMisses * table->minHit) {
+ cuddCacheResize(table);
+ }
+
+ return(NULL);
+
+} /* end of cuddCacheLookup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up in the cache for the result of op applied to f,
+ g, and h.]
+
+ Description [Returns the result if found; it returns NULL if no
+ result is found.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddCacheLookup2Zdd cuddCacheLookup1Zdd]
+
+******************************************************************************/
+DdNode *
+cuddCacheLookupZdd(
+ DdManager * table,
+ ptruint op,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ int posn;
+ DdCache *en,*cache;
+ DdNode *data;
+ ptruint uf, ug, uh;
+
+ uf = (ptruint) f | (op & 0xe);
+ ug = (ptruint) g | (op >> 4);
+ uh = (ptruint) h;
+
+ cache = table->cache;
+#ifdef DD_DEBUG
+ if (cache == NULL) {
+ return(NULL);
+ }
+#endif
+
+ posn = ddCHash2(uh,uf,ug,table->cacheShift);
+ en = &cache[posn];
+ if (en->data != NULL && en->f==(DdNodePtr)uf && en->g==(DdNodePtr)ug &&
+ en->h==uh) {
+ data = Cudd_Regular(en->data);
+ table->cacheHits++;
+ if (data->ref == 0) {
+ cuddReclaimZdd(table,data);
+ }
+ return(en->data);
+ }
+
+ /* Cache miss: decide whether to resize. */
+ table->cacheMisses++;
+
+ if (table->cacheSlack >= 0 &&
+ table->cacheHits > table->cacheMisses * table->minHit) {
+ cuddCacheResize(table);
+ }
+
+ return(NULL);
+
+} /* end of cuddCacheLookupZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up in the cache for the result of op applied to f
+ and g.]
+
+ Description [Returns the result if found; it returns NULL if no
+ result is found.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddCacheLookup cuddCacheLookup1]
+
+******************************************************************************/
+DdNode *
+cuddCacheLookup2(
+ DdManager * table,
+ DdNode * (*op)(DdManager *, DdNode *, DdNode *),
+ DdNode * f,
+ DdNode * g)
+{
+ int posn;
+ DdCache *en,*cache;
+ DdNode *data;
+
+ cache = table->cache;
+#ifdef DD_DEBUG
+ if (cache == NULL) {
+ return(NULL);
+ }
+#endif
+
+ posn = ddCHash2(op,f,g,table->cacheShift);
+ en = &cache[posn];
+ if (en->data != NULL && en->f==f && en->g==g && en->h==(ptruint)op) {
+ data = Cudd_Regular(en->data);
+ table->cacheHits++;
+ if (data->ref == 0) {
+ cuddReclaim(table,data);
+ }
+ return(en->data);
+ }
+
+ /* Cache miss: decide whether to resize. */
+ table->cacheMisses++;
+
+ if (table->cacheSlack >= 0 &&
+ table->cacheHits > table->cacheMisses * table->minHit) {
+ cuddCacheResize(table);
+ }
+
+ return(NULL);
+
+} /* end of cuddCacheLookup2 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up in the cache for the result of op applied to f.]
+
+ Description [Returns the result if found; it returns NULL if no
+ result is found.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddCacheLookup cuddCacheLookup2]
+
+******************************************************************************/
+DdNode *
+cuddCacheLookup1(
+ DdManager * table,
+ DdNode * (*op)(DdManager *, DdNode *),
+ DdNode * f)
+{
+ int posn;
+ DdCache *en,*cache;
+ DdNode *data;
+
+ cache = table->cache;
+#ifdef DD_DEBUG
+ if (cache == NULL) {
+ return(NULL);
+ }
+#endif
+
+ posn = ddCHash2(op,f,f,table->cacheShift);
+ en = &cache[posn];
+ if (en->data != NULL && en->f==f && en->h==(ptruint)op) {
+ data = Cudd_Regular(en->data);
+ table->cacheHits++;
+ if (data->ref == 0) {
+ cuddReclaim(table,data);
+ }
+ return(en->data);
+ }
+
+ /* Cache miss: decide whether to resize. */
+ table->cacheMisses++;
+
+ if (table->cacheSlack >= 0 &&
+ table->cacheHits > table->cacheMisses * table->minHit) {
+ cuddCacheResize(table);
+ }
+
+ return(NULL);
+
+} /* end of cuddCacheLookup1 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up in the cache for the result of op applied to f
+ and g.]
+
+ Description [Returns the result if found; it returns NULL if no
+ result is found.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddCacheLookupZdd cuddCacheLookup1Zdd]
+
+******************************************************************************/
+DdNode *
+cuddCacheLookup2Zdd(
+ DdManager * table,
+ DdNode * (*op)(DdManager *, DdNode *, DdNode *),
+ DdNode * f,
+ DdNode * g)
+{
+ int posn;
+ DdCache *en,*cache;
+ DdNode *data;
+
+ cache = table->cache;
+#ifdef DD_DEBUG
+ if (cache == NULL) {
+ return(NULL);
+ }
+#endif
+
+ posn = ddCHash2(op,f,g,table->cacheShift);
+ en = &cache[posn];
+ if (en->data != NULL && en->f==f && en->g==g && en->h==(ptruint)op) {
+ data = Cudd_Regular(en->data);
+ table->cacheHits++;
+ if (data->ref == 0) {
+ cuddReclaimZdd(table,data);
+ }
+ return(en->data);
+ }
+
+ /* Cache miss: decide whether to resize. */
+ table->cacheMisses++;
+
+ if (table->cacheSlack >= 0 &&
+ table->cacheHits > table->cacheMisses * table->minHit) {
+ cuddCacheResize(table);
+ }
+
+ return(NULL);
+
+} /* end of cuddCacheLookup2Zdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up in the cache for the result of op applied to f.]
+
+ Description [Returns the result if found; it returns NULL if no
+ result is found.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddCacheLookupZdd cuddCacheLookup2Zdd]
+
+******************************************************************************/
+DdNode *
+cuddCacheLookup1Zdd(
+ DdManager * table,
+ DdNode * (*op)(DdManager *, DdNode *),
+ DdNode * f)
+{
+ int posn;
+ DdCache *en,*cache;
+ DdNode *data;
+
+ cache = table->cache;
+#ifdef DD_DEBUG
+ if (cache == NULL) {
+ return(NULL);
+ }
+#endif
+
+ posn = ddCHash2(op,f,f,table->cacheShift);
+ en = &cache[posn];
+ if (en->data != NULL && en->f==f && en->h==(ptruint)op) {
+ data = Cudd_Regular(en->data);
+ table->cacheHits++;
+ if (data->ref == 0) {
+ cuddReclaimZdd(table,data);
+ }
+ return(en->data);
+ }
+
+ /* Cache miss: decide whether to resize. */
+ table->cacheMisses++;
+
+ if (table->cacheSlack >= 0 &&
+ table->cacheHits > table->cacheMisses * table->minHit) {
+ cuddCacheResize(table);
+ }
+
+ return(NULL);
+
+} /* end of cuddCacheLookup1Zdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up in the cache for the result of op applied to f,
+ g, and h.]
+
+ Description [Looks up in the cache for the result of op applied to f,
+ g, and h. Assumes that the calling procedure (e.g.,
+ Cudd_bddIteConstant) is only interested in whether the result is
+ constant or not. Returns the result if found (possibly
+ DD_NON_CONSTANT); otherwise it returns NULL.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddCacheLookup]
+
+******************************************************************************/
+DdNode *
+cuddConstantLookup(
+ DdManager * table,
+ ptruint op,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ int posn;
+ DdCache *en,*cache;
+ ptruint uf, ug, uh;
+
+ uf = (ptruint) f | (op & 0xe);
+ ug = (ptruint) g | (op >> 4);
+ uh = (ptruint) h;
+
+ cache = table->cache;
+#ifdef DD_DEBUG
+ if (cache == NULL) {
+ return(NULL);
+ }
+#endif
+ posn = ddCHash2(uh,uf,ug,table->cacheShift);
+ en = &cache[posn];
+
+ /* We do not reclaim here because the result should not be
+ * referenced, but only tested for being a constant.
+ */
+ if (en->data != NULL &&
+ en->f == (DdNodePtr)uf && en->g == (DdNodePtr)ug && en->h == uh) {
+ table->cacheHits++;
+ return(en->data);
+ }
+
+ /* Cache miss: decide whether to resize. */
+ table->cacheMisses++;
+
+ if (table->cacheSlack >= 0 &&
+ table->cacheHits > table->cacheMisses * table->minHit) {
+ cuddCacheResize(table);
+ }
+
+ return(NULL);
+
+} /* end of cuddConstantLookup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes and prints a profile of the cache usage.]
+
+ Description [Computes and prints a profile of the cache usage.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddCacheProfile(
+ DdManager * table,
+ FILE * fp)
+{
+ DdCache *cache = table->cache;
+ int slots = table->cacheSlots;
+ int nzeroes = 0;
+ int i, retval;
+ double exUsed;
+
+#ifdef DD_CACHE_PROFILE
+ double count, mean, meansq, stddev, expected;
+ long max, min;
+ int imax, imin;
+ double *hystogramQ, *hystogramR; /* histograms by quotient and remainder */
+ int nbins = DD_HYSTO_BINS;
+ int bin;
+ long thiscount;
+ double totalcount, exStddev;
+
+ meansq = mean = expected = 0.0;
+ max = min = (long) cache[0].count;
+ imax = imin = 0;
+ totalcount = 0.0;
+
+ hystogramQ = ALLOC(double, nbins);
+ if (hystogramQ == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ hystogramR = ALLOC(double, nbins);
+ if (hystogramR == NULL) {
+ FREE(hystogramQ);
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (i = 0; i < nbins; i++) {
+ hystogramQ[i] = 0;
+ hystogramR[i] = 0;
+ }
+
+ for (i = 0; i < slots; i++) {
+ thiscount = (long) cache[i].count;
+ if (thiscount > max) {
+ max = thiscount;
+ imax = i;
+ }
+ if (thiscount < min) {
+ min = thiscount;
+ imin = i;
+ }
+ if (thiscount == 0) {
+ nzeroes++;
+ }
+ count = (double) thiscount;
+ mean += count;
+ meansq += count * count;
+ totalcount += count;
+ expected += count * (double) i;
+ bin = (i * nbins) / slots;
+ hystogramQ[bin] += (double) thiscount;
+ bin = i % nbins;
+ hystogramR[bin] += (double) thiscount;
+ }
+ mean /= (double) slots;
+ meansq /= (double) slots;
+
+ /* Compute the standard deviation from both the data and the
+ ** theoretical model for a random distribution. */
+ stddev = sqrt(meansq - mean*mean);
+ exStddev = sqrt((1 - 1/(double) slots) * totalcount / (double) slots);
+
+ retval = fprintf(fp,"Cache average accesses = %g\n", mean);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Cache access standard deviation = %g ", stddev);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"(expected = %g)\n", exStddev);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Cache max accesses = %ld for slot %d\n", max, imax);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Cache min accesses = %ld for slot %d\n", min, imin);
+ if (retval == EOF) return(0);
+ exUsed = 100.0 * (1.0 - exp(-totalcount / (double) slots));
+ retval = fprintf(fp,"Cache used slots = %.2f%% (expected %.2f%%)\n",
+ 100.0 - (double) nzeroes * 100.0 / (double) slots,
+ exUsed);
+ if (retval == EOF) return(0);
+
+ if (totalcount > 0) {
+ expected /= totalcount;
+ retval = fprintf(fp,"Cache access hystogram for %d bins", nbins);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp," (expected bin value = %g)\nBy quotient:",
+ expected);
+ if (retval == EOF) return(0);
+ for (i = nbins - 1; i>=0; i--) {
+ retval = fprintf(fp," %.0f", hystogramQ[i]);
+ if (retval == EOF) return(0);
+ }
+ retval = fprintf(fp,"\nBy residue: ");
+ if (retval == EOF) return(0);
+ for (i = nbins - 1; i>=0; i--) {
+ retval = fprintf(fp," %.0f", hystogramR[i]);
+ if (retval == EOF) return(0);
+ }
+ retval = fprintf(fp,"\n");
+ if (retval == EOF) return(0);
+ }
+
+ FREE(hystogramQ);
+ FREE(hystogramR);
+#else
+ for (i = 0; i < slots; i++) {
+ nzeroes += cache[i].h == 0;
+ }
+ exUsed = 100.0 *
+ (1.0 - exp(-(table->cacheinserts - table->cacheLastInserts) /
+ (double) slots));
+ retval = fprintf(fp,"Cache used slots = %.2f%% (expected %.2f%%)\n",
+ 100.0 - (double) nzeroes * 100.0 / (double) slots,
+ exUsed);
+ if (retval == EOF) return(0);
+#endif
+ return(1);
+
+} /* end of cuddCacheProfile */
+
+
+/**Function********************************************************************
+
+ Synopsis [Resizes the cache.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+cuddCacheResize(
+ DdManager * table)
+{
+ DdCache *cache, *oldcache, *oldacache, *entry, *old;
+ int i;
+ int posn, shift;
+ unsigned int slots, oldslots;
+ double offset;
+ int moved = 0;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+#ifndef DD_CACHE_PROFILE
+ ptruint misalignment;
+ DdNodePtr *mem;
+#endif
+
+ oldcache = table->cache;
+ oldacache = table->acache;
+ oldslots = table->cacheSlots;
+ slots = table->cacheSlots = oldslots << 1;
+
+#ifdef DD_VERBOSE
+ (void) fprintf(table->err,"Resizing the cache from %d to %d entries\n",
+ oldslots, slots);
+ (void) fprintf(table->err,
+ "\thits = %g\tmisses = %g\thit ratio = %5.3f\n",
+ table->cacheHits, table->cacheMisses,
+ table->cacheHits / (table->cacheHits + table->cacheMisses));
+#endif
+
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ table->acache = cache = ALLOC(DdCache,slots+1);
+ MMoutOfMemory = saveHandler;
+ /* If we fail to allocate the new table we just give up. */
+ if (cache == NULL) {
+#ifdef DD_VERBOSE
+ (void) fprintf(table->err,"Resizing failed. Giving up.\n");
+#endif
+ table->cacheSlots = oldslots;
+ table->acache = oldacache;
+ /* Do not try to resize again. */
+ table->maxCacheHard = oldslots - 1;
+ table->cacheSlack = - (oldslots + 1);
+ return;
+ }
+ /* If the size of the cache entry is a power of 2, we want to
+ ** enforce alignment to that power of two. This happens when
+ ** DD_CACHE_PROFILE is not defined. */
+#ifdef DD_CACHE_PROFILE
+ table->cache = cache;
+#else
+ mem = (DdNodePtr *) cache;
+ misalignment = (ptruint) mem & (sizeof(DdCache) - 1);
+ mem += (sizeof(DdCache) - misalignment) / sizeof(DdNodePtr);
+ table->cache = cache = (DdCache *) mem;
+ assert(((ptruint) table->cache & (sizeof(DdCache) - 1)) == 0);
+#endif
+ shift = --(table->cacheShift);
+ table->memused += (slots - oldslots) * sizeof(DdCache);
+ table->cacheSlack -= slots; /* need these many slots to double again */
+
+ /* Clear new cache. */
+ for (i = 0; (unsigned) i < slots; i++) {
+ cache[i].data = NULL;
+ cache[i].h = 0;
+#ifdef DD_CACHE_PROFILE
+ cache[i].count = 0;
+#endif
+ }
+
+ /* Copy from old cache to new one. */
+ for (i = 0; (unsigned) i < oldslots; i++) {
+ old = &oldcache[i];
+ if (old->data != NULL) {
+ posn = ddCHash2(old->h,old->f,old->g,shift);
+ entry = &cache[posn];
+ entry->f = old->f;
+ entry->g = old->g;
+ entry->h = old->h;
+ entry->data = old->data;
+#ifdef DD_CACHE_PROFILE
+ entry->count = 1;
+#endif
+ moved++;
+ }
+ }
+
+ FREE(oldacache);
+
+ /* Reinitialize measurements so as to avoid division by 0 and
+ ** immediate resizing.
+ */
+ offset = (double) (int) (slots * table->minHit + 1);
+ table->totCacheMisses += table->cacheMisses - offset;
+ table->cacheMisses = offset;
+ table->totCachehits += table->cacheHits;
+ table->cacheHits = 0;
+ table->cacheLastInserts = table->cacheinserts - (double) moved;
+
+} /* end of cuddCacheResize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Flushes the cache.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+cuddCacheFlush(
+ DdManager * table)
+{
+ int i, slots;
+ DdCache *cache;
+
+ slots = table->cacheSlots;
+ cache = table->cache;
+ for (i = 0; i < slots; i++) {
+ table->cachedeletions += cache[i].data != NULL;
+ cache[i].data = NULL;
+ }
+ table->cacheLastInserts = table->cacheinserts;
+
+ return;
+
+} /* end of cuddCacheFlush */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the floor of the logarithm to the base 2.]
+
+ Description [Returns the floor of the logarithm to the base 2.
+ The input value is assumed to be greater than 0.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddComputeFloorLog2(
+ unsigned int value)
+{
+ int floorLog = 0;
+#ifdef DD_DEBUG
+ assert(value > 0);
+#endif
+ while (value > 1) {
+ floorLog++;
+ value >>= 1;
+ }
+ return(floorLog);
+
+} /* end of cuddComputeFloorLog2 */
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
diff --git a/src/bdd/cudd/cuddCheck.c b/src/bdd/cudd/cuddCheck.c
new file mode 100644
index 00000000..3db08dd6
--- /dev/null
+++ b/src/bdd/cudd/cuddCheck.c
@@ -0,0 +1,851 @@
+/**CFile***********************************************************************
+
+ FileName [cuddCheck.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions to check consistency of data structures.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_DebugCheck()
+ <li> Cudd_CheckKeys()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddHeapProfile()
+ <li> cuddPrintNode()
+ <li> cuddPrintVarGroups()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> debugFindParent()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddCheck.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static void debugFindParent ARGS((DdManager *table, DdNode *node));
+#if 0
+static void debugCheckParent ARGS((DdManager *table, DdNode *node));
+#endif
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks for inconsistencies in the DD heap.]
+
+ Description [Checks for inconsistencies in the DD heap:
+ <ul>
+ <li> node has illegal index
+ <li> live node has dead children
+ <li> node has illegal Then or Else pointers
+ <li> BDD/ADD node has identical children
+ <li> ZDD node has zero then child
+ <li> wrong number of total nodes
+ <li> wrong number of dead nodes
+ <li> ref count error at node
+ </ul>
+ Returns 0 if no inconsistencies are found; DD_OUT_OF_MEM if there is
+ not enough memory; 1 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_CheckKeys]
+
+******************************************************************************/
+int
+Cudd_DebugCheck(
+ DdManager * table)
+{
+ unsigned int i;
+ int j,count;
+ int slots;
+ DdNodePtr *nodelist;
+ DdNode *f;
+ DdNode *sentinel = &(table->sentinel);
+ st_table *edgeTable; /* stores internal ref count for each node */
+ st_generator *gen;
+ int flag = 0;
+ int totalNode;
+ int deadNode;
+ int index;
+
+
+ edgeTable = st_init_table(st_ptrcmp,st_ptrhash);
+ if (edgeTable == NULL) return(CUDD_OUT_OF_MEM);
+
+ /* Check the BDD/ADD subtables. */
+ for (i = 0; i < (unsigned) table->size; i++) {
+ index = table->invperm[i];
+ if (i != (unsigned) table->perm[index]) {
+ (void) fprintf(table->err,
+ "Permutation corrupted: invperm[%d] = %d\t perm[%d] = %d\n",
+ i, index, index, table->perm[index]);
+ }
+ nodelist = table->subtables[i].nodelist;
+ slots = table->subtables[i].slots;
+
+ totalNode = 0;
+ deadNode = 0;
+ for (j = 0; j < slots; j++) { /* for each subtable slot */
+ f = nodelist[j];
+ while (f != sentinel) {
+ totalNode++;
+ if (cuddT(f) != NULL && cuddE(f) != NULL && f->ref != 0) {
+ if ((int) f->index != index) {
+ (void) fprintf(table->err,
+ "Error: node has illegal index\n");
+ cuddPrintNode(f,table->err);
+ flag = 1;
+ }
+ if ((unsigned) cuddI(table,cuddT(f)->index) <= i ||
+ (unsigned) cuddI(table,Cudd_Regular(cuddE(f))->index)
+ <= i) {
+ (void) fprintf(table->err,
+ "Error: node has illegal children\n");
+ cuddPrintNode(f,table->err);
+ flag = 1;
+ }
+ if (Cudd_Regular(cuddT(f)) != cuddT(f)) {
+ (void) fprintf(table->err,
+ "Error: node has illegal form\n");
+ cuddPrintNode(f,table->err);
+ flag = 1;
+ }
+ if (cuddT(f) == cuddE(f)) {
+ (void) fprintf(table->err,
+ "Error: node has identical children\n");
+ cuddPrintNode(f,table->err);
+ flag = 1;
+ }
+ if (cuddT(f)->ref == 0 || Cudd_Regular(cuddE(f))->ref == 0) {
+ (void) fprintf(table->err,
+ "Error: live node has dead children\n");
+ cuddPrintNode(f,table->err);
+ flag =1;
+ }
+ /* Increment the internal reference count for the
+ ** then child of the current node.
+ */
+ if (st_lookup(edgeTable,(char *)cuddT(f),(char **)&count)) {
+ count++;
+ } else {
+ count = 1;
+ }
+ if (st_insert(edgeTable,(char *)cuddT(f),
+ (char *)(long)count) == ST_OUT_OF_MEM) {
+ st_free_table(edgeTable);
+ return(CUDD_OUT_OF_MEM);
+ }
+
+ /* Increment the internal reference count for the
+ ** else child of the current node.
+ */
+ if (st_lookup(edgeTable,(char *)Cudd_Regular(cuddE(f)),(char **)&count)) {
+ count++;
+ } else {
+ count = 1;
+ }
+ if (st_insert(edgeTable,(char *)Cudd_Regular(cuddE(f)),
+ (char *)(long)count) == ST_OUT_OF_MEM) {
+ st_free_table(edgeTable);
+ return(CUDD_OUT_OF_MEM);
+ }
+ } else if (cuddT(f) != NULL && cuddE(f) != NULL && f->ref == 0) {
+ deadNode++;
+#if 0
+ debugCheckParent(table,f);
+#endif
+ } else {
+ fprintf(table->err,
+ "Error: node has illegal Then or Else pointers\n");
+ cuddPrintNode(f,table->err);
+ flag = 1;
+ }
+
+ f = f->next;
+ } /* for each element of the collision list */
+ } /* for each subtable slot */
+
+ if ((unsigned) totalNode != table->subtables[i].keys) {
+ fprintf(table->err,"Error: wrong number of total nodes\n");
+ flag = 1;
+ }
+ if ((unsigned) deadNode != table->subtables[i].dead) {
+ fprintf(table->err,"Error: wrong number of dead nodes\n");
+ flag = 1;
+ }
+ } /* for each BDD/ADD subtable */
+
+ /* Check the ZDD subtables. */
+ for (i = 0; i < (unsigned) table->sizeZ; i++) {
+ index = table->invpermZ[i];
+ if (i != (unsigned) table->permZ[index]) {
+ (void) fprintf(table->err,
+ "Permutation corrupted: invpermZ[%d] = %d\t permZ[%d] = %d in ZDD\n",
+ i, index, index, table->permZ[index]);
+ }
+ nodelist = table->subtableZ[i].nodelist;
+ slots = table->subtableZ[i].slots;
+
+ totalNode = 0;
+ deadNode = 0;
+ for (j = 0; j < slots; j++) { /* for each subtable slot */
+ f = nodelist[j];
+ while (f != NULL) {
+ totalNode++;
+ if (cuddT(f) != NULL && cuddE(f) != NULL && f->ref != 0) {
+ if ((int) f->index != index) {
+ (void) fprintf(table->err,
+ "Error: ZDD node has illegal index\n");
+ cuddPrintNode(f,table->err);
+ flag = 1;
+ }
+ if (Cudd_IsComplement(cuddT(f)) ||
+ Cudd_IsComplement(cuddE(f))) {
+ (void) fprintf(table->err,
+ "Error: ZDD node has complemented children\n");
+ cuddPrintNode(f,table->err);
+ flag = 1;
+ }
+ if ((unsigned) cuddIZ(table,cuddT(f)->index) <= i ||
+ (unsigned) cuddIZ(table,cuddE(f)->index) <= i) {
+ (void) fprintf(table->err,
+ "Error: ZDD node has illegal children\n");
+ cuddPrintNode(f,table->err);
+ cuddPrintNode(cuddT(f),table->err);
+ cuddPrintNode(cuddE(f),table->err);
+ flag = 1;
+ }
+ if (cuddT(f) == DD_ZERO(table)) {
+ (void) fprintf(table->err,
+ "Error: ZDD node has zero then child\n");
+ cuddPrintNode(f,table->err);
+ flag = 1;
+ }
+ if (cuddT(f)->ref == 0 || cuddE(f)->ref == 0) {
+ (void) fprintf(table->err,
+ "Error: ZDD live node has dead children\n");
+ cuddPrintNode(f,table->err);
+ flag =1;
+ }
+ /* Increment the internal reference count for the
+ ** then child of the current node.
+ */
+ if (st_lookup(edgeTable,(char *)cuddT(f),(char **)&count)) {
+ count++;
+ } else {
+ count = 1;
+ }
+ if (st_insert(edgeTable,(char *)cuddT(f),
+ (char *)(long)count) == ST_OUT_OF_MEM) {
+ st_free_table(edgeTable);
+ return(CUDD_OUT_OF_MEM);
+ }
+
+ /* Increment the internal reference count for the
+ ** else child of the current node.
+ */
+ if (st_lookup(edgeTable,(char *)cuddE(f),(char **)&count)) {
+ count++;
+ } else {
+ count = 1;
+ }
+ if (st_insert(edgeTable,(char *)cuddE(f),
+ (char *)(long)count) == ST_OUT_OF_MEM) {
+ st_free_table(edgeTable);
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(CUDD_OUT_OF_MEM);
+ }
+ } else if (cuddT(f) != NULL && cuddE(f) != NULL && f->ref == 0) {
+ deadNode++;
+#if 0
+ debugCheckParent(table,f);
+#endif
+ } else {
+ fprintf(table->err,
+ "Error: ZDD node has illegal Then or Else pointers\n");
+ cuddPrintNode(f,table->err);
+ flag = 1;
+ }
+
+ f = f->next;
+ } /* for each element of the collision list */
+ } /* for each subtable slot */
+
+ if ((unsigned) totalNode != table->subtableZ[i].keys) {
+ fprintf(table->err,
+ "Error: wrong number of total nodes in ZDD\n");
+ flag = 1;
+ }
+ if ((unsigned) deadNode != table->subtableZ[i].dead) {
+ fprintf(table->err,
+ "Error: wrong number of dead nodes in ZDD\n");
+ flag = 1;
+ }
+ } /* for each ZDD subtable */
+
+ /* Check the constant table. */
+ nodelist = table->constants.nodelist;
+ slots = table->constants.slots;
+
+ totalNode = 0;
+ deadNode = 0;
+ for (j = 0; j < slots; j++) {
+ f = nodelist[j];
+ while (f != NULL) {
+ totalNode++;
+ if (f->ref != 0) {
+ if (f->index != CUDD_CONST_INDEX) {
+ fprintf(table->err,"Error: node has illegal index\n");
+#if SIZEOF_VOID_P == 8
+ fprintf(table->err,
+ " node 0x%lx, id = %d, ref = %d, value = %g\n",
+ (unsigned long)f,f->index,f->ref,cuddV(f));
+#else
+ fprintf(table->err,
+ " node 0x%x, id = %d, ref = %d, value = %g\n",
+ (unsigned)f,f->index,f->ref,cuddV(f));
+#endif
+ flag = 1;
+ }
+ } else {
+ deadNode++;
+ }
+ f = f->next;
+ }
+ }
+ if ((unsigned) totalNode != table->constants.keys) {
+ (void) fprintf(table->err,
+ "Error: wrong number of total nodes in constants\n");
+ flag = 1;
+ }
+ if ((unsigned) deadNode != table->constants.dead) {
+ (void) fprintf(table->err,
+ "Error: wrong number of dead nodes in constants\n");
+ flag = 1;
+ }
+ gen = st_init_gen(edgeTable);
+ while (st_gen(gen,(char **)&f,(char **)&count)) {
+ if (count > (int)(f->ref) && f->ref != DD_MAXREF) {
+#if SIZEOF_VOID_P == 8
+ fprintf(table->err,"ref count error at node 0x%lx, count = %d, id = %d, ref = %d, then = 0x%lx, else = 0x%lx\n",(unsigned long)f,count,f->index,f->ref,(unsigned long)cuddT(f),(unsigned long)cuddE(f));
+#else
+ fprintf(table->err,"ref count error at node 0x%x, count = %d, id = %d, ref = %d, then = 0x%x, else = 0x%x\n",(unsigned)f,count,f->index,f->ref,(unsigned)cuddT(f),(unsigned)cuddE(f));
+#endif
+ debugFindParent(table,f);
+ flag = 1;
+ }
+ }
+ st_free_gen(gen);
+ st_free_table(edgeTable);
+
+ return (flag);
+
+} /* end of Cudd_DebugCheck */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks for several conditions that should not occur.]
+
+ Description [Checks for the following conditions:
+ <ul>
+ <li>Wrong sizes of subtables.
+ <li>Wrong number of keys found in unique subtable.
+ <li>Wrong number of dead found in unique subtable.
+ <li>Wrong number of keys found in the constant table
+ <li>Wrong number of dead found in the constant table
+ <li>Wrong number of total slots found
+ <li>Wrong number of maximum keys found
+ <li>Wrong number of total dead found
+ </ul>
+ Reports the average length of non-empty lists. Returns the number of
+ subtables for which the number of keys is wrong.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DebugCheck]
+
+******************************************************************************/
+int
+Cudd_CheckKeys(
+ DdManager * table)
+{
+ int size;
+ int i,j;
+ DdNodePtr *nodelist;
+ DdNode *node;
+ DdNode *sentinel = &(table->sentinel);
+ DdSubtable *subtable;
+ int keys;
+ int dead;
+ int count = 0;
+ int totalKeys = 0;
+ int totalSlots = 0;
+ int totalDead = 0;
+ int nonEmpty = 0;
+ unsigned int slots;
+ int logSlots;
+ int shift;
+
+ size = table->size;
+
+ for (i = 0; i < size; i++) {
+ subtable = &(table->subtables[i]);
+ nodelist = subtable->nodelist;
+ keys = subtable->keys;
+ dead = subtable->dead;
+ totalKeys += keys;
+ slots = subtable->slots;
+ shift = subtable->shift;
+ logSlots = sizeof(int) * 8 - shift;
+ if (((slots >> logSlots) << logSlots) != slots) {
+ (void) fprintf(table->err,
+ "Unique table %d is not the right power of 2\n", i);
+ (void) fprintf(table->err,
+ " slots = %u shift = %d\n", slots, shift);
+ }
+ totalSlots += slots;
+ totalDead += dead;
+ for (j = 0; (unsigned) j < slots; j++) {
+ node = nodelist[j];
+ if (node != sentinel) {
+ nonEmpty++;
+ }
+ while (node != sentinel) {
+ keys--;
+ if (node->ref == 0) {
+ dead--;
+ }
+ node = node->next;
+ }
+ }
+ if (keys != 0) {
+ (void) fprintf(table->err, "Wrong number of keys found \
+in unique table %d (difference=%d)\n", i, keys);
+ count++;
+ }
+ if (dead != 0) {
+ (void) fprintf(table->err, "Wrong number of dead found \
+in unique table no. %d (difference=%d)\n", i, dead);
+ }
+ } /* for each BDD/ADD subtable */
+
+ /* Check the ZDD subtables. */
+ size = table->sizeZ;
+
+ for (i = 0; i < size; i++) {
+ subtable = &(table->subtableZ[i]);
+ nodelist = subtable->nodelist;
+ keys = subtable->keys;
+ dead = subtable->dead;
+ totalKeys += keys;
+ totalSlots += subtable->slots;
+ totalDead += dead;
+ for (j = 0; (unsigned) j < subtable->slots; j++) {
+ node = nodelist[j];
+ if (node != NULL) {
+ nonEmpty++;
+ }
+ while (node != NULL) {
+ keys--;
+ if (node->ref == 0) {
+ dead--;
+ }
+ node = node->next;
+ }
+ }
+ if (keys != 0) {
+ (void) fprintf(table->err, "Wrong number of keys found \
+in ZDD unique table no. %d (difference=%d)\n", i, keys);
+ count++;
+ }
+ if (dead != 0) {
+ (void) fprintf(table->err, "Wrong number of dead found \
+in ZDD unique table no. %d (difference=%d)\n", i, dead);
+ }
+ } /* for each ZDD subtable */
+
+ /* Check the constant table. */
+ subtable = &(table->constants);
+ nodelist = subtable->nodelist;
+ keys = subtable->keys;
+ dead = subtable->dead;
+ totalKeys += keys;
+ totalSlots += subtable->slots;
+ totalDead += dead;
+ for (j = 0; (unsigned) j < subtable->slots; j++) {
+ node = nodelist[j];
+ if (node != NULL) {
+ nonEmpty++;
+ }
+ while (node != NULL) {
+ keys--;
+ if (node->ref == 0) {
+ dead--;
+ }
+ node = node->next;
+ }
+ }
+ if (keys != 0) {
+ (void) fprintf(table->err, "Wrong number of keys found \
+in the constant table (difference=%d)\n", keys);
+ count++;
+ }
+ if (dead != 0) {
+ (void) fprintf(table->err, "Wrong number of dead found \
+in the constant table (difference=%d)\n", dead);
+ }
+ if ((unsigned) totalKeys != table->keys + table->keysZ) {
+ (void) fprintf(table->err, "Wrong number of total keys found \
+(difference=%d)\n", totalKeys-table->keys);
+ }
+ if ((unsigned) totalSlots != table->slots) {
+ (void) fprintf(table->err, "Wrong number of total slots found \
+(difference=%d)\n", totalSlots-table->slots);
+ }
+ if (table->minDead != (unsigned) (table->gcFrac * table->slots)) {
+ (void) fprintf(table->err, "Wrong number of minimum dead found \
+(%d vs. %d)\n", table->minDead,
+ (unsigned) (table->gcFrac * (double) table->slots));
+ }
+ if ((unsigned) totalDead != table->dead + table->deadZ) {
+ (void) fprintf(table->err, "Wrong number of total dead found \
+(difference=%d)\n", totalDead-table->dead);
+ }
+ (void)printf("Average length of non-empty lists = %g\n",
+ (double) table->keys / (double) nonEmpty);
+
+ return(count);
+
+} /* end of Cudd_CheckKeys */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints information about the heap.]
+
+ Description [Prints to the manager's stdout the number of live nodes for each
+ level of the DD heap that contains at least one live node. It also
+ prints a summary containing:
+ <ul>
+ <li> total number of tables;
+ <li> number of tables with live nodes;
+ <li> table with the largest number of live nodes;
+ <li> number of nodes in that table.
+ </ul>
+ If more than one table contains the maximum number of live nodes,
+ only the one of lowest index is reported. Returns 1 in case of success
+ and 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddHeapProfile(
+ DdManager * dd)
+{
+ int ntables = dd->size;
+ DdSubtable *subtables = dd->subtables;
+ int i, /* loop index */
+ nodes, /* live nodes in i-th layer */
+ retval, /* return value of fprintf */
+ largest = -1, /* index of the table with most live nodes */
+ maxnodes = -1, /* maximum number of live nodes in a table */
+ nonempty = 0; /* number of tables with live nodes */
+
+ /* Print header. */
+#if SIZEOF_VOID_P == 8
+ retval = fprintf(dd->out,"*** DD heap profile for 0x%lx ***\n",
+ (unsigned long) dd);
+#else
+ retval = fprintf(dd->out,"*** DD heap profile for 0x%x ***\n",
+ (unsigned) dd);
+#endif
+ if (retval == EOF) return 0;
+
+ /* Print number of live nodes for each nonempty table. */
+ for (i=0; i<ntables; i++) {
+ nodes = subtables[i].keys - subtables[i].dead;
+ if (nodes) {
+ nonempty++;
+ retval = fprintf(dd->out,"%5d: %5d nodes\n", i, nodes);
+ if (retval == EOF) return 0;
+ if (nodes > maxnodes) {
+ maxnodes = nodes;
+ largest = i;
+ }
+ }
+ }
+
+ nodes = dd->constants.keys - dd->constants.dead;
+ if (nodes) {
+ nonempty++;
+ retval = fprintf(dd->out,"const: %5d nodes\n", nodes);
+ if (retval == EOF) return 0;
+ if (nodes > maxnodes) {
+ maxnodes = nodes;
+ largest = CUDD_CONST_INDEX;
+ }
+ }
+
+ /* Print summary. */
+ retval = fprintf(dd->out,"Summary: %d tables, %d non-empty, largest: %d ",
+ ntables+1, nonempty, largest);
+ if (retval == EOF) return 0;
+ retval = fprintf(dd->out,"(with %d nodes)\n", maxnodes);
+ if (retval == EOF) return 0;
+
+ return(1);
+
+} /* end of cuddHeapProfile */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints out information on a node.]
+
+ Description [Prints out information on a node.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+cuddPrintNode(
+ DdNode * f,
+ FILE *fp)
+{
+ f = Cudd_Regular(f);
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(fp," node 0x%lx, id = %d, ref = %d, then = 0x%lx, else = 0x%lx\n",(unsigned long)f,f->index,f->ref,(unsigned long)cuddT(f),(unsigned long)cuddE(f));
+#else
+ (void) fprintf(fp," node 0x%x, id = %d, ref = %d, then = 0x%x, else = 0x%x\n",(unsigned)f,f->index,f->ref,(unsigned)cuddT(f),(unsigned)cuddE(f));
+#endif
+
+} /* end of cuddPrintNode */
+
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints the variable groups as a parenthesized list.]
+
+ Description [Prints the variable groups as a parenthesized list.
+ For each group the level range that it represents is printed. After
+ each group, the group's flags are printed, preceded by a `|'. For
+ each flag (except MTR_TERMINAL) a character is printed.
+ <ul>
+ <li>F: MTR_FIXED
+ <li>N: MTR_NEWNODE
+ <li>S: MTR_SOFT
+ </ul>
+ The second argument, silent, if different from 0, causes
+ Cudd_PrintVarGroups to only check the syntax of the group tree.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+cuddPrintVarGroups(
+ DdManager * dd /* manager */,
+ MtrNode * root /* root of the group tree */,
+ int zdd /* 0: BDD; 1: ZDD */,
+ int silent /* flag to check tree syntax only */)
+{
+ MtrNode *node;
+ int level;
+
+ assert(root != NULL);
+ assert(root->younger == NULL || root->younger->elder == root);
+ assert(root->elder == NULL || root->elder->younger == root);
+ if (zdd) {
+ level = dd->permZ[root->index];
+ } else {
+ level = dd->perm[root->index];
+ }
+ if (!silent) (void) printf("(%d",level);
+ if (MTR_TEST(root,MTR_TERMINAL) || root->child == NULL) {
+ if (!silent) (void) printf(",");
+ } else {
+ node = root->child;
+ while (node != NULL) {
+ assert(node->low >= root->low && (int) (node->low + node->size) <= (int) (root->low + root->size));
+ assert(node->parent == root);
+ cuddPrintVarGroups(dd,node,zdd,silent);
+ node = node->younger;
+ }
+ }
+ if (!silent) {
+ (void) printf("%d", level + root->size - 1);
+ if (root->flags != MTR_DEFAULT) {
+ (void) printf("|");
+ if (MTR_TEST(root,MTR_FIXED)) (void) printf("F");
+ if (MTR_TEST(root,MTR_NEWNODE)) (void) printf("N");
+ if (MTR_TEST(root,MTR_SOFT)) (void) printf("S");
+ }
+ (void) printf(")");
+ if (root->parent == NULL) (void) printf("\n");
+ }
+ assert((root->flags &~(MTR_TERMINAL | MTR_SOFT | MTR_FIXED | MTR_NEWNODE)) == 0);
+ return;
+
+} /* end of cuddPrintVarGroups */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Searches the subtables above node for its parents.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+debugFindParent(
+ DdManager * table,
+ DdNode * node)
+{
+ int i,j;
+ int slots;
+ DdNodePtr *nodelist;
+ DdNode *f;
+
+ for (i = 0; i < cuddI(table,node->index); i++) {
+ nodelist = table->subtables[i].nodelist;
+ slots = table->subtables[i].slots;
+
+ for (j=0;j<slots;j++) {
+ f = nodelist[j];
+ while (f != NULL) {
+ if (cuddT(f) == node || Cudd_Regular(cuddE(f)) == node) {
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(table->out,"parent is at 0x%lx, id = %d, ref = %d, then = 0x%lx, else = 0x%lx\n",
+ (unsigned long)f,f->index,f->ref,(unsigned long)cuddT(f),(unsigned long)cuddE(f));
+#else
+ (void) fprintf(table->out,"parent is at 0x%x, id = %d, ref = %d, then = 0x%x, else = 0x%x\n",
+ (unsigned)f,f->index,f->ref,(unsigned)cuddT(f),(unsigned)cuddE(f));
+#endif
+ }
+ f = f->next;
+ }
+ }
+ }
+
+} /* end of debugFindParent */
+
+
+#if 0
+/**Function********************************************************************
+
+ Synopsis [Reports an error if a (dead) node has a non-dead parent.]
+
+ Description [Searches all the subtables above node. Very expensive.
+ The same check is now implemented more efficiently in ddDebugCheck.]
+
+ SideEffects [None]
+
+ SeeAlso [debugFindParent]
+
+******************************************************************************/
+static void
+debugCheckParent(
+ DdManager * table,
+ DdNode * node)
+{
+ int i,j;
+ int slots;
+ DdNode **nodelist,*f;
+
+ for (i = 0; i < cuddI(table,node->index); i++) {
+ nodelist = table->subtables[i].nodelist;
+ slots = table->subtables[i].slots;
+
+ for (j=0;j<slots;j++) {
+ f = nodelist[j];
+ while (f != NULL) {
+ if ((Cudd_Regular(cuddE(f)) == node || cuddT(f) == node) && f->ref != 0) {
+ (void) fprintf(table->err,
+ "error with zero ref count\n");
+ (void) fprintf(table->err,"parent is 0x%x, id = %d, ref = %d, then = 0x%x, else = 0x%x\n",f,f->index,f->ref,cuddT(f),cuddE(f));
+ (void) fprintf(table->err,"child is 0x%x, id = %d, ref = %d, then = 0x%x, else = 0x%x\n",node,node->index,node->ref,cuddT(node),cuddE(node));
+ }
+ f = f->next;
+ }
+ }
+ }
+}
+#endif
diff --git a/src/bdd/cudd/cuddClip.c b/src/bdd/cudd/cuddClip.c
new file mode 100644
index 00000000..3c728a56
--- /dev/null
+++ b/src/bdd/cudd/cuddClip.c
@@ -0,0 +1,531 @@
+/**CFile***********************************************************************
+
+ FileName [cuddClip.c]
+
+ PackageName [cudd]
+
+ Synopsis [Clipping functions.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_bddClippingAnd()
+ <li> Cudd_bddClippingAndAbstract()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddBddClippingAnd()
+ <li> cuddBddClippingAndAbstract()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddBddClippingAndRecur()
+ <li> cuddBddClipAndAbsRecur()
+ </ul>
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddClip.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdNode * cuddBddClippingAndRecur ARGS((DdManager *manager, DdNode *f, DdNode *g, int distance, int direction));
+static DdNode * cuddBddClipAndAbsRecur ARGS((DdManager *manager, DdNode *f, DdNode *g, DdNode *cube, int distance, int direction));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Approximates the conjunction of two BDDs f and g.]
+
+ Description [Approximates the conjunction of two BDDs f and g. Returns a
+ pointer to the resulting BDD if successful; NULL if the intermediate
+ result blows up.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddAnd]
+
+******************************************************************************/
+DdNode *
+Cudd_bddClippingAnd(
+ DdManager * dd /* manager */,
+ DdNode * f /* first conjunct */,
+ DdNode * g /* second conjunct */,
+ int maxDepth /* maximum recursion depth */,
+ int direction /* under (0) or over (1) approximation */)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddClippingAnd(dd,f,g,maxDepth,direction);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddClippingAnd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Approximates the conjunction of two BDDs f and g and
+ simultaneously abstracts the variables in cube.]
+
+ Description [Approximates the conjunction of two BDDs f and g and
+ simultaneously abstracts the variables in cube. The variables are
+ existentially abstracted. Returns a pointer to the resulting BDD if
+ successful; NULL if the intermediate result blows up.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddAndAbstract Cudd_bddClippingAnd]
+
+******************************************************************************/
+DdNode *
+Cudd_bddClippingAndAbstract(
+ DdManager * dd /* manager */,
+ DdNode * f /* first conjunct */,
+ DdNode * g /* second conjunct */,
+ DdNode * cube /* cube of variables to be abstracted */,
+ int maxDepth /* maximum recursion depth */,
+ int direction /* under (0) or over (1) approximation */)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddClippingAndAbstract(dd,f,g,cube,maxDepth,direction);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddClippingAndAbstract */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Approximates the conjunction of two BDDs f and g.]
+
+ Description [Approximates the conjunction of two BDDs f and g. Returns a
+ pointer to the resulting BDD if successful; NULL if the intermediate
+ result blows up.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddClippingAnd]
+
+******************************************************************************/
+DdNode *
+cuddBddClippingAnd(
+ DdManager * dd /* manager */,
+ DdNode * f /* first conjunct */,
+ DdNode * g /* second conjunct */,
+ int maxDepth /* maximum recursion depth */,
+ int direction /* under (0) or over (1) approximation */)
+{
+ DdNode *res;
+
+ res = cuddBddClippingAndRecur(dd,f,g,maxDepth,direction);
+
+ return(res);
+
+} /* end of cuddBddClippingAnd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Approximates the conjunction of two BDDs f and g and
+ simultaneously abstracts the variables in cube.]
+
+ Description [Approximates the conjunction of two BDDs f and g and
+ simultaneously abstracts the variables in cube. Returns a
+ pointer to the resulting BDD if successful; NULL if the intermediate
+ result blows up.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddClippingAndAbstract]
+
+******************************************************************************/
+DdNode *
+cuddBddClippingAndAbstract(
+ DdManager * dd /* manager */,
+ DdNode * f /* first conjunct */,
+ DdNode * g /* second conjunct */,
+ DdNode * cube /* cube of variables to be abstracted */,
+ int maxDepth /* maximum recursion depth */,
+ int direction /* under (0) or over (1) approximation */)
+{
+ DdNode *res;
+
+ res = cuddBddClipAndAbsRecur(dd,f,g,cube,maxDepth,direction);
+
+ return(res);
+
+} /* end of cuddBddClippingAndAbstract */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_bddClippingAnd.]
+
+ Description [Implements the recursive step of Cudd_bddClippingAnd by taking
+ the conjunction of two BDDs. Returns a pointer to the result is
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddBddClippingAnd]
+
+******************************************************************************/
+static DdNode *
+cuddBddClippingAndRecur(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * g,
+ int distance,
+ int direction)
+{
+ DdNode *F, *ft, *fe, *G, *gt, *ge;
+ DdNode *one, *zero, *r, *t, *e;
+ unsigned int topf, topg, index;
+ DdNode *(*cacheOp)(DdManager *, DdNode *, DdNode *);
+
+ statLine(manager);
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ /* Terminal cases. */
+ if (f == zero || g == zero || f == Cudd_Not(g)) return(zero);
+ if (f == g || g == one) return(f);
+ if (f == one) return(g);
+ if (distance == 0) {
+ /* One last attempt at returning the right result. We sort of
+ ** cheat by calling Cudd_bddLeq. */
+ if (Cudd_bddLeq(manager,f,g)) return(f);
+ if (Cudd_bddLeq(manager,g,f)) return(g);
+ if (direction == 1) {
+ if (Cudd_bddLeq(manager,f,Cudd_Not(g)) ||
+ Cudd_bddLeq(manager,g,Cudd_Not(f))) return(zero);
+ }
+ return(Cudd_NotCond(one,(direction == 0)));
+ }
+
+ /* At this point f and g are not constant. */
+ distance--;
+
+ /* Check cache. Try to increase cache efficiency by sorting the
+ ** pointers. */
+ if (f > g) {
+ DdNode *tmp = f;
+ f = g; g = tmp;
+ }
+ F = Cudd_Regular(f);
+ G = Cudd_Regular(g);
+ cacheOp = (DdNode *(*)(DdManager *, DdNode *, DdNode *))
+ (direction ? Cudd_bddClippingAnd : cuddBddClippingAnd);
+ if (F->ref != 1 || G->ref != 1) {
+ r = cuddCacheLookup2(manager, cacheOp, f, g);
+ if (r != NULL) return(r);
+ }
+
+ /* Here we can skip the use of cuddI, because the operands are known
+ ** to be non-constant.
+ */
+ topf = manager->perm[F->index];
+ topg = manager->perm[G->index];
+
+ /* Compute cofactors. */
+ if (topf <= topg) {
+ index = F->index;
+ ft = cuddT(F);
+ fe = cuddE(F);
+ if (Cudd_IsComplement(f)) {
+ ft = Cudd_Not(ft);
+ fe = Cudd_Not(fe);
+ }
+ } else {
+ index = G->index;
+ ft = fe = f;
+ }
+
+ if (topg <= topf) {
+ gt = cuddT(G);
+ ge = cuddE(G);
+ if (Cudd_IsComplement(g)) {
+ gt = Cudd_Not(gt);
+ ge = Cudd_Not(ge);
+ }
+ } else {
+ gt = ge = g;
+ }
+
+ t = cuddBddClippingAndRecur(manager, ft, gt, distance, direction);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = cuddBddClippingAndRecur(manager, fe, ge, distance, direction);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(manager, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ if (t == e) {
+ r = t;
+ } else {
+ if (Cudd_IsComplement(t)) {
+ r = cuddUniqueInter(manager,(int)index,Cudd_Not(t),Cudd_Not(e));
+ if (r == NULL) {
+ Cudd_RecursiveDeref(manager, t);
+ Cudd_RecursiveDeref(manager, e);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = cuddUniqueInter(manager,(int)index,t,e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(manager, t);
+ Cudd_RecursiveDeref(manager, e);
+ return(NULL);
+ }
+ }
+ }
+ cuddDeref(e);
+ cuddDeref(t);
+ if (F->ref != 1 || G->ref != 1)
+ cuddCacheInsert2(manager, cacheOp, f, g, r);
+ return(r);
+
+} /* end of cuddBddClippingAndRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Approximates the AND of two BDDs and simultaneously abstracts the
+ variables in cube.]
+
+ Description [Approximates the AND of two BDDs and simultaneously
+ abstracts the variables in cube. The variables are existentially
+ abstracted. Returns a pointer to the result is successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddClippingAndAbstract]
+
+******************************************************************************/
+static DdNode *
+cuddBddClipAndAbsRecur(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * g,
+ DdNode * cube,
+ int distance,
+ int direction)
+{
+ DdNode *F, *ft, *fe, *G, *gt, *ge;
+ DdNode *one, *zero, *r, *t, *e, *Cube;
+ unsigned int topf, topg, topcube, top, index;
+ ptruint cacheTag;
+
+ statLine(manager);
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ /* Terminal cases. */
+ if (f == zero || g == zero || f == Cudd_Not(g)) return(zero);
+ if (f == one && g == one) return(one);
+ if (cube == one) {
+ return(cuddBddClippingAndRecur(manager, f, g, distance, direction));
+ }
+ if (f == one || f == g) {
+ return (cuddBddExistAbstractRecur(manager, g, cube));
+ }
+ if (g == one) {
+ return (cuddBddExistAbstractRecur(manager, f, cube));
+ }
+ if (distance == 0) return(Cudd_NotCond(one,(direction == 0)));
+
+ /* At this point f, g, and cube are not constant. */
+ distance--;
+
+ /* Check cache. */
+ if (f > g) { /* Try to increase cache efficiency. */
+ DdNode *tmp = f;
+ f = g; g = tmp;
+ }
+ F = Cudd_Regular(f);
+ G = Cudd_Regular(g);
+ cacheTag = direction ? DD_BDD_CLIPPING_AND_ABSTRACT_UP_TAG :
+ DD_BDD_CLIPPING_AND_ABSTRACT_DOWN_TAG;
+ if (F->ref != 1 || G->ref != 1) {
+ r = cuddCacheLookup(manager, cacheTag,
+ f, g, cube);
+ if (r != NULL) {
+ return(r);
+ }
+ }
+
+ /* Here we can skip the use of cuddI, because the operands are known
+ ** to be non-constant.
+ */
+ topf = manager->perm[F->index];
+ topg = manager->perm[G->index];
+ top = ddMin(topf, topg);
+ topcube = manager->perm[cube->index];
+
+ if (topcube < top) {
+ return(cuddBddClipAndAbsRecur(manager, f, g, cuddT(cube),
+ distance, direction));
+ }
+ /* Now, topcube >= top. */
+
+ if (topf == top) {
+ index = F->index;
+ ft = cuddT(F);
+ fe = cuddE(F);
+ if (Cudd_IsComplement(f)) {
+ ft = Cudd_Not(ft);
+ fe = Cudd_Not(fe);
+ }
+ } else {
+ index = G->index;
+ ft = fe = f;
+ }
+
+ if (topg == top) {
+ gt = cuddT(G);
+ ge = cuddE(G);
+ if (Cudd_IsComplement(g)) {
+ gt = Cudd_Not(gt);
+ ge = Cudd_Not(ge);
+ }
+ } else {
+ gt = ge = g;
+ }
+
+ if (topcube == top) {
+ Cube = cuddT(cube);
+ } else {
+ Cube = cube;
+ }
+
+ t = cuddBddClipAndAbsRecur(manager, ft, gt, Cube, distance, direction);
+ if (t == NULL) return(NULL);
+
+ /* Special case: 1 OR anything = 1. Hence, no need to compute
+ ** the else branch if t is 1.
+ */
+ if (t == one && topcube == top) {
+ if (F->ref != 1 || G->ref != 1)
+ cuddCacheInsert(manager, cacheTag, f, g, cube, one);
+ return(one);
+ }
+ cuddRef(t);
+
+ e = cuddBddClipAndAbsRecur(manager, fe, ge, Cube, distance, direction);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(manager, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ if (topcube == top) { /* abstract */
+ r = cuddBddClippingAndRecur(manager, Cudd_Not(t), Cudd_Not(e),
+ distance, (direction == 0));
+ if (r == NULL) {
+ Cudd_RecursiveDeref(manager, t);
+ Cudd_RecursiveDeref(manager, e);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ cuddRef(r);
+ Cudd_RecursiveDeref(manager, t);
+ Cudd_RecursiveDeref(manager, e);
+ cuddDeref(r);
+ } else if (t == e) {
+ r = t;
+ cuddDeref(t);
+ cuddDeref(e);
+ } else {
+ if (Cudd_IsComplement(t)) {
+ r = cuddUniqueInter(manager,(int)index,Cudd_Not(t),Cudd_Not(e));
+ if (r == NULL) {
+ Cudd_RecursiveDeref(manager, t);
+ Cudd_RecursiveDeref(manager, e);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = cuddUniqueInter(manager,(int)index,t,e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(manager, t);
+ Cudd_RecursiveDeref(manager, e);
+ return(NULL);
+ }
+ }
+ cuddDeref(e);
+ cuddDeref(t);
+ }
+ if (F->ref != 1 || G->ref != 1)
+ cuddCacheInsert(manager, cacheTag, f, g, cube, r);
+ return (r);
+
+} /* end of cuddBddClipAndAbsRecur */
+
diff --git a/src/bdd/cudd/cuddCof.c b/src/bdd/cudd/cuddCof.c
new file mode 100644
index 00000000..0dfeff6c
--- /dev/null
+++ b/src/bdd/cudd/cuddCof.c
@@ -0,0 +1,300 @@
+/**CFile***********************************************************************
+
+ FileName [cuddCof.c]
+
+ PackageName [cudd]
+
+ Synopsis [Cofactoring functions.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_Cofactor()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddGetBranches()
+ <li> cuddCheckCube()
+ <li> cuddCofactorRecur()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddCof.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the cofactor of f with respect to g.]
+
+ Description [Computes the cofactor of f with respect to g; g must be
+ the BDD or the ADD of a cube. Returns a pointer to the cofactor if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddConstrain Cudd_bddRestrict]
+
+******************************************************************************/
+DdNode *
+Cudd_Cofactor(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res,*zero;
+
+ zero = Cudd_Not(DD_ONE(dd));
+ if (g == zero || g == DD_ZERO(dd)) {
+ (void) fprintf(dd->err,"Cudd_Cofactor: Invalid restriction 1\n");
+ dd->errorCode = CUDD_INVALID_ARG;
+ return(NULL);
+ }
+ do {
+ dd->reordered = 0;
+ res = cuddCofactorRecur(dd,f,g);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_Cofactor */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the children of g.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+cuddGetBranches(
+ DdNode * g,
+ DdNode ** g1,
+ DdNode ** g0)
+{
+ DdNode *G = Cudd_Regular(g);
+
+ *g1 = cuddT(G);
+ *g0 = cuddE(G);
+ if (Cudd_IsComplement(g)) {
+ *g1 = Cudd_Not(*g1);
+ *g0 = Cudd_Not(*g0);
+ }
+
+} /* end of cuddGetBranches */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether g is the BDD of a cube.]
+
+ Description [Checks whether g is the BDD of a cube. Returns 1 in case
+ of success; 0 otherwise. The constant 1 is a valid cube, but all other
+ constant functions cause cuddCheckCube to return 0.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddCheckCube(
+ DdManager * dd,
+ DdNode * g)
+{
+ DdNode *g1,*g0,*one,*zero;
+
+ one = DD_ONE(dd);
+ if (g == one) return(1);
+ if (Cudd_IsConstant(g)) return(0);
+
+ zero = Cudd_Not(one);
+ cuddGetBranches(g,&g1,&g0);
+
+ if (g0 == zero) {
+ return(cuddCheckCube(dd, g1));
+ }
+ if (g1 == zero) {
+ return(cuddCheckCube(dd, g0));
+ }
+ return(0);
+
+} /* end of cuddCheckCube */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_Cofactor.]
+
+ Description [Performs the recursive step of Cudd_Cofactor. Returns a
+ pointer to the cofactor if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Cofactor]
+
+******************************************************************************/
+DdNode *
+cuddCofactorRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *one,*zero,*F,*G,*g1,*g0,*f1,*f0,*t,*e,*r;
+ unsigned int topf,topg;
+ int comple;
+
+ statLine(dd);
+ F = Cudd_Regular(f);
+ if (cuddIsConstant(F)) return(f);
+
+ one = DD_ONE(dd);
+
+ /* The invariant g != 0 is true on entry to this procedure and is
+ ** recursively maintained by it. Therefore it suffices to test g
+ ** against one to make sure it is not constant.
+ */
+ if (g == one) return(f);
+ /* From now on, f and g are known not to be constants. */
+
+ comple = f != F;
+ r = cuddCacheLookup2(dd,Cudd_Cofactor,F,g);
+ if (r != NULL) {
+ return(Cudd_NotCond(r,comple));
+ }
+
+ topf = dd->perm[F->index];
+ G = Cudd_Regular(g);
+ topg = dd->perm[G->index];
+
+ /* We take the cofactors of F because we are going to rely on
+ ** the fact that the cofactors of the complement are the complements
+ ** of the cofactors to better utilize the cache. Variable comple
+ ** remembers whether we have to complement the result or not.
+ */
+ if (topf <= topg) {
+ f1 = cuddT(F); f0 = cuddE(F);
+ } else {
+ f1 = f0 = F;
+ }
+ if (topg <= topf) {
+ g1 = cuddT(G); g0 = cuddE(G);
+ if (g != G) { g1 = Cudd_Not(g1); g0 = Cudd_Not(g0); }
+ } else {
+ g1 = g0 = g;
+ }
+
+ zero = Cudd_Not(one);
+ if (topf >= topg) {
+ if (g0 == zero || g0 == DD_ZERO(dd)) {
+ r = cuddCofactorRecur(dd, f1, g1);
+ } else if (g1 == zero || g1 == DD_ZERO(dd)) {
+ r = cuddCofactorRecur(dd, f0, g0);
+ } else {
+ (void) fprintf(dd->out,
+ "Cudd_Cofactor: Invalid restriction 2\n");
+ dd->errorCode = CUDD_INVALID_ARG;
+ return(NULL);
+ }
+ if (r == NULL) return(NULL);
+ } else /* if (topf < topg) */ {
+ t = cuddCofactorRecur(dd, f1, g);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = cuddCofactorRecur(dd, f0, g);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ if (t == e) {
+ r = t;
+ } else if (Cudd_IsComplement(t)) {
+ r = cuddUniqueInter(dd,(int)F->index,Cudd_Not(t),Cudd_Not(e));
+ if (r != NULL)
+ r = Cudd_Not(r);
+ } else {
+ r = cuddUniqueInter(dd,(int)F->index,t,e);
+ }
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd ,e);
+ Cudd_RecursiveDeref(dd ,t);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+ }
+
+ cuddCacheInsert2(dd,Cudd_Cofactor,F,g,r);
+
+ return(Cudd_NotCond(r,comple));
+
+} /* end of cuddCofactorRecur */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/cudd/cuddCompose.c b/src/bdd/cudd/cuddCompose.c
new file mode 100644
index 00000000..11c6cb7b
--- /dev/null
+++ b/src/bdd/cudd/cuddCompose.c
@@ -0,0 +1,1722 @@
+/**CFile***********************************************************************
+
+ FileName [cuddCompose.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functional composition and variable permutation of DDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_bddCompose()
+ <li> Cudd_addCompose()
+ <li> Cudd_addPermute()
+ <li> Cudd_addSwapVariables()
+ <li> Cudd_bddPermute()
+ <li> Cudd_bddVarMap()
+ <li> Cudd_SetVarMap()
+ <li> Cudd_bddSwapVariables()
+ <li> Cudd_bddAdjPermuteX()
+ <li> Cudd_addVectorCompose()
+ <li> Cudd_addGeneralVectorCompose()
+ <li> Cudd_addNonSimCompose()
+ <li> Cudd_bddVectorCompose()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddBddComposeRecur()
+ <li> cuddAddComposeRecur()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddAddPermuteRecur()
+ <li> cuddBddPermuteRecur()
+ <li> cuddBddVarMapRecur()
+ <li> cuddAddVectorComposeRecur()
+ <li> cuddAddGeneralVectorComposeRecur()
+ <li> cuddAddNonSimComposeRecur()
+ <li> cuddBddVectorComposeRecur()
+ <li> ddIsIthAddVar()
+ <li> ddIsIthAddVarPair()
+ </ul>
+ The permutation functions use a local cache because the results to
+ be remembered depend on the permutation being applied. Since the
+ permutation is just an array, it cannot be stored in the global
+ cache. There are different procedured for BDDs and ADDs. This is
+ because bddPermuteRecur uses cuddBddIteRecur. If this were changed,
+ the procedures could be merged.]
+
+ Author [Fabio Somenzi and Kavita Ravi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddCompose.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+#ifdef DD_DEBUG
+static int addPermuteRecurHits;
+static int bddPermuteRecurHits;
+static int bddVectorComposeHits;
+static int addVectorComposeHits;
+
+static int addGeneralVectorComposeHits;
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdNode * cuddAddPermuteRecur ARGS((DdManager *manager, DdHashTable *table, DdNode *node, int *permut));
+static DdNode * cuddBddPermuteRecur ARGS((DdManager *manager, DdHashTable *table, DdNode *node, int *permut));
+static DdNode * cuddBddVarMapRecur ARGS((DdManager *manager, DdNode *f));
+static DdNode * cuddAddVectorComposeRecur ARGS((DdManager *dd, DdHashTable *table, DdNode *f, DdNode **vector, int deepest));
+static DdNode * cuddAddNonSimComposeRecur ARGS((DdManager *dd, DdNode *f, DdNode **vector, DdNode *key, DdNode *cube, int lastsub));
+static DdNode * cuddBddVectorComposeRecur ARGS((DdManager *dd, DdHashTable *table, DdNode *f, DdNode **vector, int deepest));
+DD_INLINE static int ddIsIthAddVar ARGS((DdManager *dd, DdNode *f, unsigned int i));
+
+static DdNode * cuddAddGeneralVectorComposeRecur ARGS((DdManager *dd, DdHashTable *table, DdNode *f, DdNode **vectorOn, DdNode **vectorOff, int deepest));
+DD_INLINE static int ddIsIthAddVarPair ARGS((DdManager *dd, DdNode *f, DdNode *g, unsigned int i));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Substitutes g for x_v in the BDD for f.]
+
+ Description [Substitutes g for x_v in the BDD for f. v is the index of the
+ variable to be substituted. Cudd_bddCompose passes the corresponding
+ projection function to the recursive procedure, so that the cache may
+ be used. Returns the composed BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addCompose]
+
+******************************************************************************/
+DdNode *
+Cudd_bddCompose(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ int v)
+{
+ DdNode *proj, *res;
+
+ /* Sanity check. */
+ if (v < 0 || v > dd->size) return(NULL);
+
+ proj = dd->vars[v];
+ do {
+ dd->reordered = 0;
+ res = cuddBddComposeRecur(dd,f,g,proj);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddCompose */
+
+
+/**Function********************************************************************
+
+ Synopsis [Substitutes g for x_v in the ADD for f.]
+
+ Description [Substitutes g for x_v in the ADD for f. v is the index of the
+ variable to be substituted. g must be a 0-1 ADD. Cudd_bddCompose passes
+ the corresponding projection function to the recursive procedure, so
+ that the cache may be used. Returns the composed ADD if successful;
+ NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddCompose]
+
+******************************************************************************/
+DdNode *
+Cudd_addCompose(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ int v)
+{
+ DdNode *proj, *res;
+
+ /* Sanity check. */
+ if (v < 0 || v > dd->size) return(NULL);
+
+ proj = dd->vars[v];
+ do {
+ dd->reordered = 0;
+ res = cuddAddComposeRecur(dd,f,g,proj);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addCompose */
+
+
+/**Function********************************************************************
+
+ Synopsis [Permutes the variables of an ADD.]
+
+ Description [Given a permutation in array permut, creates a new ADD
+ with permuted variables. There should be an entry in array permut
+ for each variable in the manager. The i-th entry of permut holds the
+ index of the variable that is to substitute the i-th
+ variable. Returns a pointer to the resulting ADD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddPermute Cudd_addSwapVariables]
+
+******************************************************************************/
+DdNode *
+Cudd_addPermute(
+ DdManager * manager,
+ DdNode * node,
+ int * permut)
+{
+ DdHashTable *table;
+ DdNode *res;
+
+ do {
+ manager->reordered = 0;
+ table = cuddHashTableInit(manager,1,2);
+ if (table == NULL) return(NULL);
+ /* Recursively solve the problem. */
+ res = cuddAddPermuteRecur(manager,table,node,permut);
+ if (res != NULL) cuddRef(res);
+ /* Dispose of local cache. */
+ cuddHashTableQuit(table);
+ } while (manager->reordered == 1);
+
+ if (res != NULL) cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_addPermute */
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps two sets of variables of the same size (x and y) in
+ the ADD f.]
+
+ Description [Swaps two sets of variables of the same size (x and y) in
+ the ADD f. The size is given by n. The two sets of variables are
+ assumed to be disjoint. Returns a pointer to the resulting ADD if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addPermute Cudd_bddSwapVariables]
+
+******************************************************************************/
+DdNode *
+Cudd_addSwapVariables(
+ DdManager * dd,
+ DdNode * f,
+ DdNode ** x,
+ DdNode ** y,
+ int n)
+{
+ DdNode *swapped;
+ int i, j, k;
+ int *permut;
+
+ permut = ALLOC(int,dd->size);
+ if (permut == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < dd->size; i++) permut[i] = i;
+ for (i = 0; i < n; i++) {
+ j = x[i]->index;
+ k = y[i]->index;
+ permut[j] = k;
+ permut[k] = j;
+ }
+
+ swapped = Cudd_addPermute(dd,f,permut);
+ FREE(permut);
+
+ return(swapped);
+
+} /* end of Cudd_addSwapVariables */
+
+
+/**Function********************************************************************
+
+ Synopsis [Permutes the variables of a BDD.]
+
+ Description [Given a permutation in array permut, creates a new BDD
+ with permuted variables. There should be an entry in array permut
+ for each variable in the manager. The i-th entry of permut holds the
+ index of the variable that is to substitute the i-th variable.
+ Returns a pointer to the resulting BDD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addPermute Cudd_bddSwapVariables]
+
+******************************************************************************/
+DdNode *
+Cudd_bddPermute(
+ DdManager * manager,
+ DdNode * node,
+ int * permut)
+{
+ DdHashTable *table;
+ DdNode *res;
+
+ do {
+ manager->reordered = 0;
+ table = cuddHashTableInit(manager,1,2);
+ if (table == NULL) return(NULL);
+ res = cuddBddPermuteRecur(manager,table,node,permut);
+ if (res != NULL) cuddRef(res);
+ /* Dispose of local cache. */
+ cuddHashTableQuit(table);
+
+ } while (manager->reordered == 1);
+
+ if (res != NULL) cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_bddPermute */
+
+
+/**Function********************************************************************
+
+ Synopsis [Remaps the variables of a BDD using the default variable map.]
+
+ Description [Remaps the variables of a BDD using the default
+ variable map. A typical use of this function is to swap two sets of
+ variables. The variable map must be registered with Cudd_SetVarMap.
+ Returns a pointer to the resulting BDD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddPermute Cudd_bddSwapVariables Cudd_SetVarMap]
+
+******************************************************************************/
+DdNode *
+Cudd_bddVarMap(
+ DdManager * manager /* DD manager */,
+ DdNode * f /* function in which to remap variables */)
+{
+ DdNode *res;
+
+ if (manager->map == NULL) return(NULL);
+ do {
+ manager->reordered = 0;
+ res = cuddBddVarMapRecur(manager, f);
+ } while (manager->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_bddVarMap */
+
+
+/**Function********************************************************************
+
+ Synopsis [Registers a variable mapping with the manager.]
+
+ Description [Registers with the manager a variable mapping described
+ by two sets of variables. This variable mapping is then used by
+ functions like Cudd_bddVarMap. This function is convenient for
+ those applications that perform the same mapping several times.
+ However, if several different permutations are used, it may be more
+ efficient not to rely on the registered mapping, because changing
+ mapping causes the cache to be cleared. (The initial setting,
+ however, does not clear the cache.) The two sets of variables (x and
+ y) must have the same size (x and y). The size is given by n. The
+ two sets of variables are normally disjoint, but this restriction is
+ not imposeded by the function. When new variables are created, the
+ map is automatically extended (each new variable maps to
+ itself). The typical use, however, is to wait until all variables
+ are created, and then create the map. Returns 1 if the mapping is
+ successfully registered with the manager; 0 otherwise.]
+
+ SideEffects [Modifies the manager. May clear the cache.]
+
+ SeeAlso [Cudd_bddVarMap Cudd_bddPermute Cudd_bddSwapVariables]
+
+******************************************************************************/
+int
+Cudd_SetVarMap (
+ DdManager *manager /* DD manager */,
+ DdNode **x /* first array of variables */,
+ DdNode **y /* second array of variables */,
+ int n /* length of both arrays */)
+{
+ int i;
+
+ if (manager->map != NULL) {
+ cuddCacheFlush(manager);
+ } else {
+ manager->map = ALLOC(int,manager->maxSize);
+ if (manager->map == NULL) {
+ manager->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ manager->memused += sizeof(int) * manager->maxSize;
+ }
+ /* Initialize the map to the identity. */
+ for (i = 0; i < manager->size; i++) {
+ manager->map[i] = i;
+ }
+ /* Create the map. */
+ for (i = 0; i < n; i++) {
+ manager->map[x[i]->index] = y[i]->index;
+ manager->map[y[i]->index] = x[i]->index;
+ }
+ return(1);
+
+} /* end of Cudd_SetVarMap */
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps two sets of variables of the same size (x and y) in
+ the BDD f.]
+
+ Description [Swaps two sets of variables of the same size (x and y)
+ in the BDD f. The size is given by n. The two sets of variables are
+ assumed to be disjoint. Returns a pointer to the resulting BDD if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddPermute Cudd_addSwapVariables]
+
+******************************************************************************/
+DdNode *
+Cudd_bddSwapVariables(
+ DdManager * dd,
+ DdNode * f,
+ DdNode ** x,
+ DdNode ** y,
+ int n)
+{
+ DdNode *swapped;
+ int i, j, k;
+ int *permut;
+
+ permut = ALLOC(int,dd->size);
+ if (permut == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < dd->size; i++) permut[i] = i;
+ for (i = 0; i < n; i++) {
+ j = x[i]->index;
+ k = y[i]->index;
+ permut[j] = k;
+ permut[k] = j;
+ }
+
+ swapped = Cudd_bddPermute(dd,f,permut);
+ FREE(permut);
+
+ return(swapped);
+
+} /* end of Cudd_bddSwapVariables */
+
+
+/**Function********************************************************************
+
+ Synopsis [Rearranges a set of variables in the BDD B.]
+
+ Description [Rearranges a set of variables in the BDD B. The size of
+ the set is given by n. This procedure is intended for the
+ `randomization' of the priority functions. Returns a pointer to the
+ BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddPermute Cudd_bddSwapVariables
+ Cudd_Dxygtdxz Cudd_Dxygtdyz Cudd_PrioritySelect]
+
+******************************************************************************/
+DdNode *
+Cudd_bddAdjPermuteX(
+ DdManager * dd,
+ DdNode * B,
+ DdNode ** x,
+ int n)
+{
+ DdNode *swapped;
+ int i, j, k;
+ int *permut;
+
+ permut = ALLOC(int,dd->size);
+ if (permut == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < dd->size; i++) permut[i] = i;
+ for (i = 0; i < n-2; i += 3) {
+ j = x[i]->index;
+ k = x[i+1]->index;
+ permut[j] = k;
+ permut[k] = j;
+ }
+
+ swapped = Cudd_bddPermute(dd,B,permut);
+ FREE(permut);
+
+ return(swapped);
+
+} /* end of Cudd_bddAdjPermuteX */
+
+
+/**Function********************************************************************
+
+ Synopsis [Composes an ADD with a vector of 0-1 ADDs.]
+
+ Description [Given a vector of 0-1 ADDs, creates a new ADD by
+ substituting the 0-1 ADDs for the variables of the ADD f. There
+ should be an entry in vector for each variable in the manager.
+ If no substitution is sought for a given variable, the corresponding
+ projection function should be specified in the vector.
+ This function implements simultaneous composition.
+ Returns a pointer to the resulting ADD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addNonSimCompose Cudd_addPermute Cudd_addCompose
+ Cudd_bddVectorCompose]
+
+******************************************************************************/
+DdNode *
+Cudd_addVectorCompose(
+ DdManager * dd,
+ DdNode * f,
+ DdNode ** vector)
+{
+ DdHashTable *table;
+ DdNode *res;
+ int deepest;
+ int i;
+
+ do {
+ dd->reordered = 0;
+ /* Initialize local cache. */
+ table = cuddHashTableInit(dd,1,2);
+ if (table == NULL) return(NULL);
+
+ /* Find deepest real substitution. */
+ for (deepest = dd->size - 1; deepest >= 0; deepest--) {
+ i = dd->invperm[deepest];
+ if (!ddIsIthAddVar(dd,vector[i],i)) {
+ break;
+ }
+ }
+
+ /* Recursively solve the problem. */
+ res = cuddAddVectorComposeRecur(dd,table,f,vector,deepest);
+ if (res != NULL) cuddRef(res);
+
+ /* Dispose of local cache. */
+ cuddHashTableQuit(table);
+ } while (dd->reordered == 1);
+
+ if (res != NULL) cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_addVectorCompose */
+
+
+/**Function********************************************************************
+
+ Synopsis [Composes an ADD with a vector of ADDs.]
+
+ Description [Given a vector of ADDs, creates a new ADD by substituting the
+ ADDs for the variables of the ADD f. vectorOn contains ADDs to be substituted
+ for the x_v and vectorOff the ADDs to be substituted for x_v'. There should
+ be an entry in vector for each variable in the manager. If no substitution
+ is sought for a given variable, the corresponding projection function should
+ be specified in the vector. This function implements simultaneous
+ composition. Returns a pointer to the resulting ADD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addVectorCompose Cudd_addNonSimCompose Cudd_addPermute
+ Cudd_addCompose Cudd_bddVectorCompose]
+
+******************************************************************************/
+DdNode *
+Cudd_addGeneralVectorCompose(
+ DdManager * dd,
+ DdNode * f,
+ DdNode ** vectorOn,
+ DdNode ** vectorOff)
+{
+ DdHashTable *table;
+ DdNode *res;
+ int deepest;
+ int i;
+
+ do {
+ dd->reordered = 0;
+ /* Initialize local cache. */
+ table = cuddHashTableInit(dd,1,2);
+ if (table == NULL) return(NULL);
+
+ /* Find deepest real substitution. */
+ for (deepest = dd->size - 1; deepest >= 0; deepest--) {
+ i = dd->invperm[deepest];
+ if (!ddIsIthAddVarPair(dd,vectorOn[i],vectorOff[i],i)) {
+ break;
+ }
+ }
+
+ /* Recursively solve the problem. */
+ res = cuddAddGeneralVectorComposeRecur(dd,table,f,vectorOn,
+ vectorOff,deepest);
+ if (res != NULL) cuddRef(res);
+
+ /* Dispose of local cache. */
+ cuddHashTableQuit(table);
+ } while (dd->reordered == 1);
+
+ if (res != NULL) cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_addGeneralVectorCompose */
+
+
+/**Function********************************************************************
+
+ Synopsis [Composes an ADD with a vector of 0-1 ADDs.]
+
+ Description [Given a vector of 0-1 ADDs, creates a new ADD by
+ substituting the 0-1 ADDs for the variables of the ADD f. There
+ should be an entry in vector for each variable in the manager.
+ This function implements non-simultaneous composition. If any of the
+ functions being composed depends on any of the variables being
+ substituted, then the result depends on the order of composition,
+ which in turn depends on the variable order: The variables farther from
+ the roots in the order are substituted first.
+ Returns a pointer to the resulting ADD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addVectorCompose Cudd_addPermute Cudd_addCompose]
+
+******************************************************************************/
+DdNode *
+Cudd_addNonSimCompose(
+ DdManager * dd,
+ DdNode * f,
+ DdNode ** vector)
+{
+ DdNode *cube, *key, *var, *tmp, *piece;
+ DdNode *res;
+ int i, lastsub;
+
+ /* The cache entry for this function is composed of three parts:
+ ** f itself, the replacement relation, and the cube of the
+ ** variables being substituted.
+ ** The replacement relation is the product of the terms (yi EXNOR gi).
+ ** This apporach allows us to use the global cache for this function,
+ ** with great savings in memory with respect to using arrays for the
+ ** cache entries.
+ ** First we build replacement relation and cube of substituted
+ ** variables from the vector specifying the desired composition.
+ */
+ key = DD_ONE(dd);
+ cuddRef(key);
+ cube = DD_ONE(dd);
+ cuddRef(cube);
+ for (i = (int) dd->size - 1; i >= 0; i--) {
+ if (ddIsIthAddVar(dd,vector[i],(unsigned int)i)) {
+ continue;
+ }
+ var = Cudd_addIthVar(dd,i);
+ if (var == NULL) {
+ Cudd_RecursiveDeref(dd,key);
+ Cudd_RecursiveDeref(dd,cube);
+ return(NULL);
+ }
+ cuddRef(var);
+ /* Update cube. */
+ tmp = Cudd_addApply(dd,Cudd_addTimes,var,cube);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(dd,key);
+ Cudd_RecursiveDeref(dd,cube);
+ Cudd_RecursiveDeref(dd,var);
+ return(NULL);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(dd,cube);
+ cube = tmp;
+ /* Update replacement relation. */
+ piece = Cudd_addApply(dd,Cudd_addXnor,var,vector[i]);
+ if (piece == NULL) {
+ Cudd_RecursiveDeref(dd,key);
+ Cudd_RecursiveDeref(dd,var);
+ return(NULL);
+ }
+ cuddRef(piece);
+ Cudd_RecursiveDeref(dd,var);
+ tmp = Cudd_addApply(dd,Cudd_addTimes,key,piece);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(dd,key);
+ Cudd_RecursiveDeref(dd,piece);
+ return(NULL);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(dd,key);
+ Cudd_RecursiveDeref(dd,piece);
+ key = tmp;
+ }
+
+ /* Now try composition, until no reordering occurs. */
+ do {
+ /* Find real substitution with largest index. */
+ for (lastsub = dd->size - 1; lastsub >= 0; lastsub--) {
+ if (!ddIsIthAddVar(dd,vector[lastsub],(unsigned int)lastsub)) {
+ break;
+ }
+ }
+
+ /* Recursively solve the problem. */
+ dd->reordered = 0;
+ res = cuddAddNonSimComposeRecur(dd,f,vector,key,cube,lastsub+1);
+ if (res != NULL) cuddRef(res);
+
+ } while (dd->reordered == 1);
+
+ Cudd_RecursiveDeref(dd,key);
+ Cudd_RecursiveDeref(dd,cube);
+ if (res != NULL) cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_addNonSimCompose */
+
+
+/**Function********************************************************************
+
+ Synopsis [Composes a BDD with a vector of BDDs.]
+
+ Description [Given a vector of BDDs, creates a new BDD by
+ substituting the BDDs for the variables of the BDD f. There
+ should be an entry in vector for each variable in the manager.
+ If no substitution is sought for a given variable, the corresponding
+ projection function should be specified in the vector.
+ This function implements simultaneous composition.
+ Returns a pointer to the resulting BDD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddPermute Cudd_bddCompose Cudd_addVectorCompose]
+
+******************************************************************************/
+DdNode *
+Cudd_bddVectorCompose(
+ DdManager * dd,
+ DdNode * f,
+ DdNode ** vector)
+{
+ DdHashTable *table;
+ DdNode *res;
+ int deepest;
+ int i;
+
+ do {
+ dd->reordered = 0;
+ /* Initialize local cache. */
+ table = cuddHashTableInit(dd,1,2);
+ if (table == NULL) return(NULL);
+
+ /* Find deepest real substitution. */
+ for (deepest = dd->size - 1; deepest >= 0; deepest--) {
+ i = dd->invperm[deepest];
+ if (vector[i] != dd->vars[i]) {
+ break;
+ }
+ }
+
+ /* Recursively solve the problem. */
+ res = cuddBddVectorComposeRecur(dd,table,f,vector, deepest);
+ if (res != NULL) cuddRef(res);
+
+ /* Dispose of local cache. */
+ cuddHashTableQuit(table);
+ } while (dd->reordered == 1);
+
+ if (res != NULL) cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_bddVectorCompose */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddCompose.]
+
+ Description [Performs the recursive step of Cudd_bddCompose.
+ Exploits the fact that the composition of f' with g
+ produces the complement of the composition of f with g to better
+ utilize the cache. Returns the composed BDD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddCompose]
+
+******************************************************************************/
+DdNode *
+cuddBddComposeRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ DdNode * proj)
+{
+ DdNode *F, *G, *f1, *f0, *g1, *g0, *r, *t, *e;
+ unsigned int v, topf, topg, topindex;
+ int comple;
+
+ statLine(dd);
+ v = dd->perm[proj->index];
+ F = Cudd_Regular(f);
+ topf = cuddI(dd,F->index);
+
+ /* Terminal case. Subsumes the test for constant f. */
+ if (topf > v) return(f);
+
+ /* We solve the problem for a regular pointer, and then complement
+ ** the result if the pointer was originally complemented.
+ */
+ comple = Cudd_IsComplement(f);
+
+ /* Check cache. */
+ r = cuddCacheLookup(dd,DD_BDD_COMPOSE_RECUR_TAG,F,g,proj);
+ if (r != NULL) {
+ return(Cudd_NotCond(r,comple));
+ }
+
+ if (topf == v) {
+ /* Compose. */
+ f1 = cuddT(F);
+ f0 = cuddE(F);
+ r = cuddBddIteRecur(dd, g, f1, f0);
+ if (r == NULL) return(NULL);
+ } else {
+ /* Compute cofactors of f and g. Remember the index of the top
+ ** variable.
+ */
+ G = Cudd_Regular(g);
+ topg = cuddI(dd,G->index);
+ if (topf > topg) {
+ topindex = G->index;
+ f1 = f0 = F;
+ } else {
+ topindex = F->index;
+ f1 = cuddT(F);
+ f0 = cuddE(F);
+ }
+ if (topg > topf) {
+ g1 = g0 = g;
+ } else {
+ g1 = cuddT(G);
+ g0 = cuddE(G);
+ if (g != G) {
+ g1 = Cudd_Not(g1);
+ g0 = Cudd_Not(g0);
+ }
+ }
+ /* Recursive step. */
+ t = cuddBddComposeRecur(dd, f1, g1, proj);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = cuddBddComposeRecur(dd, f0, g0, proj);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ r = cuddBddIteRecur(dd, dd->vars[topindex], t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, t);
+ Cudd_IterDerefBdd(dd, e);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_IterDerefBdd(dd, t); /* t & e not necessarily part of r */
+ Cudd_IterDerefBdd(dd, e);
+ cuddDeref(r);
+ }
+
+ cuddCacheInsert(dd,DD_BDD_COMPOSE_RECUR_TAG,F,g,proj,r);
+
+ return(Cudd_NotCond(r,comple));
+
+} /* end of cuddBddComposeRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addCompose.]
+
+ Description [Performs the recursive step of Cudd_addCompose.
+ Returns the composed BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addCompose]
+
+******************************************************************************/
+DdNode *
+cuddAddComposeRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ DdNode * proj)
+{
+ DdNode *f1, *f0, *g1, *g0, *r, *t, *e;
+ unsigned int v, topf, topg, topindex;
+
+ statLine(dd);
+ v = dd->perm[proj->index];
+ topf = cuddI(dd,f->index);
+
+ /* Terminal case. Subsumes the test for constant f. */
+ if (topf > v) return(f);
+
+ /* Check cache. */
+ r = cuddCacheLookup(dd,DD_ADD_COMPOSE_RECUR_TAG,f,g,proj);
+ if (r != NULL) {
+ return(r);
+ }
+
+ if (topf == v) {
+ /* Compose. */
+ f1 = cuddT(f);
+ f0 = cuddE(f);
+ r = cuddAddIteRecur(dd, g, f1, f0);
+ if (r == NULL) return(NULL);
+ } else {
+ /* Compute cofactors of f and g. Remember the index of the top
+ ** variable.
+ */
+ topg = cuddI(dd,g->index);
+ if (topf > topg) {
+ topindex = g->index;
+ f1 = f0 = f;
+ } else {
+ topindex = f->index;
+ f1 = cuddT(f);
+ f0 = cuddE(f);
+ }
+ if (topg > topf) {
+ g1 = g0 = g;
+ } else {
+ g1 = cuddT(g);
+ g0 = cuddE(g);
+ }
+ /* Recursive step. */
+ t = cuddAddComposeRecur(dd, f1, g1, proj);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = cuddAddComposeRecur(dd, f0, g0, proj);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ if (t == e) {
+ r = t;
+ } else {
+ r = cuddUniqueInter(dd, (int) topindex, t, e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ Cudd_RecursiveDeref(dd, e);
+ return(NULL);
+ }
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+ }
+
+ cuddCacheInsert(dd,DD_ADD_COMPOSE_RECUR_TAG,f,g,proj,r);
+
+ return(r);
+
+} /* end of cuddAddComposeRecur */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_addPermute.]
+
+ Description [ Recursively puts the ADD in the order given in the
+ array permut. Checks for trivial cases to terminate recursion, then
+ splits on the children of this node. Once the solutions for the
+ children are obtained, it puts into the current position the node
+ from the rest of the ADD that should be here. Then returns this ADD.
+ The key here is that the node being visited is NOT put in its proper
+ place by this instance, but rather is switched when its proper
+ position is reached in the recursion tree.<p>
+ The DdNode * that is returned is the same ADD as passed in as node,
+ but in the new order.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addPermute cuddBddPermuteRecur]
+
+******************************************************************************/
+static DdNode *
+cuddAddPermuteRecur(
+ DdManager * manager /* DD manager */,
+ DdHashTable * table /* computed table */,
+ DdNode * node /* ADD to be reordered */,
+ int * permut /* permutation array */)
+{
+ DdNode *T,*E;
+ DdNode *res,*var;
+ int index;
+
+ statLine(manager);
+ /* Check for terminal case of constant node. */
+ if (cuddIsConstant(node)) {
+ return(node);
+ }
+
+ /* If problem already solved, look up answer and return. */
+ if (node->ref != 1 && (res = cuddHashTableLookup1(table,node)) != NULL) {
+#ifdef DD_DEBUG
+ addPermuteRecurHits++;
+#endif
+ return(res);
+ }
+
+ /* Split and recur on children of this node. */
+ T = cuddAddPermuteRecur(manager,table,cuddT(node),permut);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+ E = cuddAddPermuteRecur(manager,table,cuddE(node),permut);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(manager, T);
+ return(NULL);
+ }
+ cuddRef(E);
+
+ /* Move variable that should be in this position to this position
+ ** by creating a single var ADD for that variable, and calling
+ ** cuddAddIteRecur with the T and E we just created.
+ */
+ index = permut[node->index];
+ var = cuddUniqueInter(manager,index,DD_ONE(manager),DD_ZERO(manager));
+ if (var == NULL) return(NULL);
+ cuddRef(var);
+ res = cuddAddIteRecur(manager,var,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(manager,var);
+ Cudd_RecursiveDeref(manager, T);
+ Cudd_RecursiveDeref(manager, E);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(manager,var);
+ Cudd_RecursiveDeref(manager, T);
+ Cudd_RecursiveDeref(manager, E);
+
+ /* Do not keep the result if the reference count is only 1, since
+ ** it will not be visited again.
+ */
+ if (node->ref != 1) {
+ ptrint fanout = (ptrint) node->ref;
+ cuddSatDec(fanout);
+ if (!cuddHashTableInsert1(table,node,res,fanout)) {
+ Cudd_RecursiveDeref(manager, res);
+ return(NULL);
+ }
+ }
+ cuddDeref(res);
+ return(res);
+
+} /* end of cuddAddPermuteRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_bddPermute.]
+
+ Description [ Recursively puts the BDD in the order given in the array permut.
+ Checks for trivial cases to terminate recursion, then splits on the
+ children of this node. Once the solutions for the children are
+ obtained, it puts into the current position the node from the rest of
+ the BDD that should be here. Then returns this BDD.
+ The key here is that the node being visited is NOT put in its proper
+ place by this instance, but rather is switched when its proper position
+ is reached in the recursion tree.<p>
+ The DdNode * that is returned is the same BDD as passed in as node,
+ but in the new order.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddPermute cuddAddPermuteRecur]
+
+******************************************************************************/
+static DdNode *
+cuddBddPermuteRecur(
+ DdManager * manager /* DD manager */,
+ DdHashTable * table /* computed table */,
+ DdNode * node /* BDD to be reordered */,
+ int * permut /* permutation array */)
+{
+ DdNode *N,*T,*E;
+ DdNode *res;
+ int index;
+
+ statLine(manager);
+ N = Cudd_Regular(node);
+
+ /* Check for terminal case of constant node. */
+ if (cuddIsConstant(N)) {
+ return(node);
+ }
+
+ /* If problem already solved, look up answer and return. */
+ if (N->ref != 1 && (res = cuddHashTableLookup1(table,N)) != NULL) {
+#ifdef DD_DEBUG
+ bddPermuteRecurHits++;
+#endif
+ return(Cudd_NotCond(res,N != node));
+ }
+
+ /* Split and recur on children of this node. */
+ T = cuddBddPermuteRecur(manager,table,cuddT(N),permut);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+ E = cuddBddPermuteRecur(manager,table,cuddE(N),permut);
+ if (E == NULL) {
+ Cudd_IterDerefBdd(manager, T);
+ return(NULL);
+ }
+ cuddRef(E);
+
+ /* Move variable that should be in this position to this position
+ ** by retrieving the single var BDD for that variable, and calling
+ ** cuddBddIteRecur with the T and E we just created.
+ */
+ index = permut[N->index];
+ res = cuddBddIteRecur(manager,manager->vars[index],T,E);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(manager, T);
+ Cudd_IterDerefBdd(manager, E);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_IterDerefBdd(manager, T);
+ Cudd_IterDerefBdd(manager, E);
+
+ /* Do not keep the result if the reference count is only 1, since
+ ** it will not be visited again.
+ */
+ if (N->ref != 1) {
+ ptrint fanout = (ptrint) N->ref;
+ cuddSatDec(fanout);
+ if (!cuddHashTableInsert1(table,N,res,fanout)) {
+ Cudd_IterDerefBdd(manager, res);
+ return(NULL);
+ }
+ }
+ cuddDeref(res);
+ return(Cudd_NotCond(res,N != node));
+
+} /* end of cuddBddPermuteRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_bddVarMap.]
+
+ Description [Implements the recursive step of Cudd_bddVarMap.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddVarMap]
+
+******************************************************************************/
+static DdNode *
+cuddBddVarMapRecur(
+ DdManager *manager /* DD manager */,
+ DdNode *f /* BDD to be remapped */)
+{
+ DdNode *F, *T, *E;
+ DdNode *res;
+ int index;
+
+ statLine(manager);
+ F = Cudd_Regular(f);
+
+ /* Check for terminal case of constant node. */
+ if (cuddIsConstant(F)) {
+ return(f);
+ }
+
+ /* If problem already solved, look up answer and return. */
+ if (F->ref != 1 &&
+ (res = cuddCacheLookup1(manager,Cudd_bddVarMap,F)) != NULL) {
+ return(Cudd_NotCond(res,F != f));
+ }
+
+ /* Split and recur on children of this node. */
+ T = cuddBddVarMapRecur(manager,cuddT(F));
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+ E = cuddBddVarMapRecur(manager,cuddE(F));
+ if (E == NULL) {
+ Cudd_IterDerefBdd(manager, T);
+ return(NULL);
+ }
+ cuddRef(E);
+
+ /* Move variable that should be in this position to this position
+ ** by retrieving the single var BDD for that variable, and calling
+ ** cuddBddIteRecur with the T and E we just created.
+ */
+ index = manager->map[F->index];
+ res = cuddBddIteRecur(manager,manager->vars[index],T,E);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(manager, T);
+ Cudd_IterDerefBdd(manager, E);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_IterDerefBdd(manager, T);
+ Cudd_IterDerefBdd(manager, E);
+
+ /* Do not keep the result if the reference count is only 1, since
+ ** it will not be visited again.
+ */
+ if (F->ref != 1) {
+ cuddCacheInsert1(manager,Cudd_bddVarMap,F,res);
+ }
+ cuddDeref(res);
+ return(Cudd_NotCond(res,F != f));
+
+} /* end of cuddBddVarMapRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addVectorCompose.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+cuddAddVectorComposeRecur(
+ DdManager * dd /* DD manager */,
+ DdHashTable * table /* computed table */,
+ DdNode * f /* ADD in which to compose */,
+ DdNode ** vector /* functions to substitute */,
+ int deepest /* depth of deepest substitution */)
+{
+ DdNode *T,*E;
+ DdNode *res;
+
+ statLine(dd);
+ /* If we are past the deepest substitution, return f. */
+ if (cuddI(dd,f->index) > deepest) {
+ return(f);
+ }
+
+ if ((res = cuddHashTableLookup1(table,f)) != NULL) {
+#ifdef DD_DEBUG
+ addVectorComposeHits++;
+#endif
+ return(res);
+ }
+
+ /* Split and recur on children of this node. */
+ T = cuddAddVectorComposeRecur(dd,table,cuddT(f),vector,deepest);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+ E = cuddAddVectorComposeRecur(dd,table,cuddE(f),vector,deepest);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ return(NULL);
+ }
+ cuddRef(E);
+
+ /* Retrieve the 0-1 ADD for the current top variable and call
+ ** cuddAddIteRecur with the T and E we just created.
+ */
+ res = cuddAddIteRecur(dd,vector[f->index],T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+
+ /* Do not keep the result if the reference count is only 1, since
+ ** it will not be visited again
+ */
+ if (f->ref != 1) {
+ ptrint fanout = (ptrint) f->ref;
+ cuddSatDec(fanout);
+ if (!cuddHashTableInsert1(table,f,res,fanout)) {
+ Cudd_RecursiveDeref(dd, res);
+ return(NULL);
+ }
+ }
+ cuddDeref(res);
+ return(res);
+
+} /* end of cuddAddVectorComposeRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addGeneralVectorCompose.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+cuddAddGeneralVectorComposeRecur(
+ DdManager * dd /* DD manager */,
+ DdHashTable * table /* computed table */,
+ DdNode * f /* ADD in which to compose */,
+ DdNode ** vectorOn /* functions to substitute for x_i */,
+ DdNode ** vectorOff /* functions to substitute for x_i' */,
+ int deepest /* depth of deepest substitution */)
+{
+ DdNode *T,*E,*t,*e;
+ DdNode *res;
+
+ /* If we are past the deepest substitution, return f. */
+ if (cuddI(dd,f->index) > deepest) {
+ return(f);
+ }
+
+ if ((res = cuddHashTableLookup1(table,f)) != NULL) {
+#ifdef DD_DEBUG
+ addGeneralVectorComposeHits++;
+#endif
+ return(res);
+ }
+
+ /* Split and recur on children of this node. */
+ T = cuddAddGeneralVectorComposeRecur(dd,table,cuddT(f),
+ vectorOn,vectorOff,deepest);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+ E = cuddAddGeneralVectorComposeRecur(dd,table,cuddE(f),
+ vectorOn,vectorOff,deepest);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ return(NULL);
+ }
+ cuddRef(E);
+
+ /* Retrieve the compose ADDs for the current top variable and call
+ ** cuddAddApplyRecur with the T and E we just created.
+ */
+ t = cuddAddApplyRecur(dd,Cudd_addTimes,vectorOn[f->index],T);
+ if (t == NULL) {
+ Cudd_RecursiveDeref(dd,T);
+ Cudd_RecursiveDeref(dd,E);
+ return(NULL);
+ }
+ cuddRef(t);
+ e = cuddAddApplyRecur(dd,Cudd_addTimes,vectorOff[f->index],E);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd,T);
+ Cudd_RecursiveDeref(dd,E);
+ Cudd_RecursiveDeref(dd,t);
+ return(NULL);
+ }
+ cuddRef(e);
+ res = cuddAddApplyRecur(dd,Cudd_addPlus,t,e);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,T);
+ Cudd_RecursiveDeref(dd,E);
+ Cudd_RecursiveDeref(dd,t);
+ Cudd_RecursiveDeref(dd,e);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd,T);
+ Cudd_RecursiveDeref(dd,E);
+ Cudd_RecursiveDeref(dd,t);
+ Cudd_RecursiveDeref(dd,e);
+
+ /* Do not keep the result if the reference count is only 1, since
+ ** it will not be visited again
+ */
+ if (f->ref != 1) {
+ ptrint fanout = (ptrint) f->ref;
+ cuddSatDec(fanout);
+ if (!cuddHashTableInsert1(table,f,res,fanout)) {
+ Cudd_RecursiveDeref(dd, res);
+ return(NULL);
+ }
+ }
+ cuddDeref(res);
+ return(res);
+
+} /* end of cuddAddGeneralVectorComposeRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addNonSimCompose.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+cuddAddNonSimComposeRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode ** vector,
+ DdNode * key,
+ DdNode * cube,
+ int lastsub)
+{
+ DdNode *f1, *f0, *key1, *key0, *cube1, *var;
+ DdNode *T,*E;
+ DdNode *r;
+ unsigned int top, topf, topk, topc;
+ unsigned int index;
+ int i;
+ DdNode **vect1;
+ DdNode **vect0;
+
+ statLine(dd);
+ /* If we are past the deepest substitution, return f. */
+ if (cube == DD_ONE(dd) || cuddIsConstant(f)) {
+ return(f);
+ }
+
+ /* If problem already solved, look up answer and return. */
+ r = cuddCacheLookup(dd,DD_ADD_NON_SIM_COMPOSE_TAG,f,key,cube);
+ if (r != NULL) {
+ return(r);
+ }
+
+ /* Find top variable. we just need to look at f, key, and cube,
+ ** because all the varibles in the gi are in key.
+ */
+ topf = cuddI(dd,f->index);
+ topk = cuddI(dd,key->index);
+ top = ddMin(topf,topk);
+ topc = cuddI(dd,cube->index);
+ top = ddMin(top,topc);
+ index = dd->invperm[top];
+
+ /* Compute the cofactors. */
+ if (topf == top) {
+ f1 = cuddT(f);
+ f0 = cuddE(f);
+ } else {
+ f1 = f0 = f;
+ }
+ if (topc == top) {
+ cube1 = cuddT(cube);
+ /* We want to eliminate vector[index] from key. Otherwise
+ ** cache performance is severely affected. Hence we
+ ** existentially quantify the variable with index "index" from key.
+ */
+ var = Cudd_addIthVar(dd, (int) index);
+ if (var == NULL) {
+ return(NULL);
+ }
+ cuddRef(var);
+ key1 = cuddAddExistAbstractRecur(dd, key, var);
+ if (key1 == NULL) {
+ Cudd_RecursiveDeref(dd,var);
+ return(NULL);
+ }
+ cuddRef(key1);
+ Cudd_RecursiveDeref(dd,var);
+ key0 = key1;
+ } else {
+ cube1 = cube;
+ if (topk == top) {
+ key1 = cuddT(key);
+ key0 = cuddE(key);
+ } else {
+ key1 = key0 = key;
+ }
+ cuddRef(key1);
+ }
+
+ /* Allocate two new vectors for the cofactors of vector. */
+ vect1 = ALLOC(DdNode *,lastsub);
+ if (vect1 == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd,key1);
+ return(NULL);
+ }
+ vect0 = ALLOC(DdNode *,lastsub);
+ if (vect0 == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd,key1);
+ FREE(vect1);
+ return(NULL);
+ }
+
+ /* Cofactor the gi. Eliminate vect1[index] and vect0[index], because
+ ** we do not need them.
+ */
+ for (i = 0; i < lastsub; i++) {
+ DdNode *gi = vector[i];
+ if (gi == NULL) {
+ vect1[i] = vect0[i] = NULL;
+ } else if (gi->index == index) {
+ vect1[i] = cuddT(gi);
+ vect0[i] = cuddE(gi);
+ } else {
+ vect1[i] = vect0[i] = gi;
+ }
+ }
+ vect1[index] = vect0[index] = NULL;
+
+ /* Recur on children. */
+ T = cuddAddNonSimComposeRecur(dd,f1,vect1,key1,cube1,lastsub);
+ FREE(vect1);
+ if (T == NULL) {
+ Cudd_RecursiveDeref(dd,key1);
+ FREE(vect0);
+ return(NULL);
+ }
+ cuddRef(T);
+ E = cuddAddNonSimComposeRecur(dd,f0,vect0,key0,cube1,lastsub);
+ FREE(vect0);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd,key1);
+ Cudd_RecursiveDeref(dd,T);
+ return(NULL);
+ }
+ cuddRef(E);
+ Cudd_RecursiveDeref(dd,key1);
+
+ /* Retrieve the 0-1 ADD for the current top variable from vector,
+ ** and call cuddAddIteRecur with the T and E we just created.
+ */
+ r = cuddAddIteRecur(dd,vector[index],T,E);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd,T);
+ Cudd_RecursiveDeref(dd,E);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_RecursiveDeref(dd,T);
+ Cudd_RecursiveDeref(dd,E);
+ cuddDeref(r);
+
+ /* Store answer to trim recursion. */
+ cuddCacheInsert(dd,DD_ADD_NON_SIM_COMPOSE_TAG,f,key,cube,r);
+
+ return(r);
+
+} /* end of cuddAddNonSimComposeRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddVectorCompose.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+cuddBddVectorComposeRecur(
+ DdManager * dd /* DD manager */,
+ DdHashTable * table /* computed table */,
+ DdNode * f /* BDD in which to compose */,
+ DdNode ** vector /* functions to be composed */,
+ int deepest /* depth of the deepest substitution */)
+{
+ DdNode *F,*T,*E;
+ DdNode *res;
+
+ statLine(dd);
+ F = Cudd_Regular(f);
+
+ /* If we are past the deepest substitution, return f. */
+ if (cuddI(dd,F->index) > deepest) {
+ return(f);
+ }
+
+ /* If problem already solved, look up answer and return. */
+ if ((res = cuddHashTableLookup1(table,F)) != NULL) {
+#ifdef DD_DEBUG
+ bddVectorComposeHits++;
+#endif
+ return(Cudd_NotCond(res,F != f));
+ }
+
+ /* Split and recur on children of this node. */
+ T = cuddBddVectorComposeRecur(dd,table,cuddT(F),vector, deepest);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+ E = cuddBddVectorComposeRecur(dd,table,cuddE(F),vector, deepest);
+ if (E == NULL) {
+ Cudd_IterDerefBdd(dd, T);
+ return(NULL);
+ }
+ cuddRef(E);
+
+ /* Call cuddBddIteRecur with the BDD that replaces the current top
+ ** variable and the T and E we just created.
+ */
+ res = cuddBddIteRecur(dd,vector[F->index],T,E);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(dd, T);
+ Cudd_IterDerefBdd(dd, E);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_IterDerefBdd(dd, T);
+ Cudd_IterDerefBdd(dd, E);
+
+ /* Do not keep the result if the reference count is only 1, since
+ ** it will not be visited again.
+ */
+ if (F->ref != 1) {
+ ptrint fanout = (ptrint) F->ref;
+ cuddSatDec(fanout);
+ if (!cuddHashTableInsert1(table,F,res,fanout)) {
+ Cudd_IterDerefBdd(dd, res);
+ return(NULL);
+ }
+ }
+ cuddDeref(res);
+ return(Cudd_NotCond(res,F != f));
+
+} /* end of cuddBddVectorComposeRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Comparison of a function to the i-th ADD variable.]
+
+ Description [Comparison of a function to the i-th ADD variable. Returns 1 if
+ the function is the i-th ADD variable; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DD_INLINE
+static int
+ddIsIthAddVar(
+ DdManager * dd,
+ DdNode * f,
+ unsigned int i)
+{
+ return(f->index == i && cuddT(f) == DD_ONE(dd) && cuddE(f) == DD_ZERO(dd));
+
+} /* end of ddIsIthAddVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Comparison of a pair of functions to the i-th ADD variable.]
+
+ Description [Comparison of a pair of functions to the i-th ADD
+ variable. Returns 1 if the functions are the i-th ADD variable and its
+ complement; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DD_INLINE
+static int
+ddIsIthAddVarPair(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ unsigned int i)
+{
+ return(f->index == i && g->index == i &&
+ cuddT(f) == DD_ONE(dd) && cuddE(f) == DD_ZERO(dd) &&
+ cuddT(g) == DD_ZERO(dd) && cuddE(g) == DD_ONE(dd));
+
+} /* end of ddIsIthAddVarPair */
diff --git a/src/bdd/cudd/cuddDecomp.c b/src/bdd/cudd/cuddDecomp.c
new file mode 100644
index 00000000..d9c28482
--- /dev/null
+++ b/src/bdd/cudd/cuddDecomp.c
@@ -0,0 +1,2150 @@
+/**CFile***********************************************************************
+
+ FileName [cuddDecomp.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for BDD decomposition.]
+
+ Description [External procedures included in this file:
+ <ul>
+ <li> Cudd_bddApproxConjDecomp()
+ <li> Cudd_bddApproxDisjDecomp()
+ <li> Cudd_bddIterConjDecomp()
+ <li> Cudd_bddIterDisjDecomp()
+ <li> Cudd_bddGenConjDecomp()
+ <li> Cudd_bddGenDisjDecomp()
+ <li> Cudd_bddVarConjDecomp()
+ <li> Cudd_bddVarDisjDecomp()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddConjunctsAux()
+ <li> CreateBotDist()
+ <li> BuildConjuncts()
+ <li> ConjunctsFree()
+ </ul>]
+
+ Author [Kavita Ravi, Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+#define DEPTH 5
+#define THRESHOLD 10
+#define NONE 0
+#define PAIR_ST 1
+#define PAIR_CR 2
+#define G_ST 3
+#define G_CR 4
+#define H_ST 5
+#define H_CR 6
+#define BOTH_G 7
+#define BOTH_H 8
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+typedef struct Conjuncts {
+ DdNode *g;
+ DdNode *h;
+} Conjuncts;
+
+typedef struct NodeStat {
+ int distance;
+ int localRef;
+} NodeStat;
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddDecomp.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+static DdNode *one, *zero;
+long lastTimeG;
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+#define FactorsNotStored(factors) ((int)((long)(factors) & 01))
+
+#define FactorsComplement(factors) ((Conjuncts *)((long)(factors) | 01))
+
+#define FactorsUncomplement(factors) ((Conjuncts *)((long)(factors) ^ 01))
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static NodeStat * CreateBotDist ARGS((DdNode * node, st_table * distanceTable));
+static double CountMinterms ARGS((DdNode * node, double max, st_table * mintermTable, FILE *fp));
+static void ConjunctsFree ARGS((DdManager * dd, Conjuncts * factors));
+static int PairInTables ARGS((DdNode * g, DdNode * h, st_table * ghTable));
+static Conjuncts * CheckTablesCacheAndReturn ARGS((DdNode * node, DdNode * g, DdNode * h, st_table * ghTable, st_table * cacheTable));
+static Conjuncts * PickOnePair ARGS((DdNode * node, DdNode * g1, DdNode * h1, DdNode * g2, DdNode * h2, st_table * ghTable, st_table * cacheTable));
+static Conjuncts * CheckInTables ARGS((DdNode * node, DdNode * g1, DdNode * h1, DdNode * g2, DdNode * h2, st_table * ghTable, st_table * cacheTable, int * outOfMem));
+static Conjuncts * ZeroCase ARGS((DdManager * dd, DdNode * node, Conjuncts * factorsNv, st_table * ghTable, st_table * cacheTable, int switched));
+static Conjuncts * BuildConjuncts ARGS((DdManager * dd, DdNode * node, st_table * distanceTable, st_table * cacheTable, int approxDistance, int maxLocalRef, st_table * ghTable, st_table * mintermTable));
+static int cuddConjunctsAux ARGS((DdManager * dd, DdNode * f, DdNode ** c1, DdNode ** c2));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way conjunctive decomposition of a BDD.]
+
+ Description [Performs two-way conjunctive decomposition of a
+ BDD. This procedure owes its name to the use of supersetting to
+ obtain an initial factor of the given function. Returns the number
+ of conjuncts produced, that is, 2 if successful; 1 if no meaningful
+ decomposition was found; 0 otherwise. The conjuncts produced by this
+ procedure tend to be imbalanced.]
+
+ SideEffects [The factors are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the conjuncts are already
+ referenced. If the function returns 0, the array for the conjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddApproxDisjDecomp Cudd_bddIterConjDecomp
+ Cudd_bddGenConjDecomp Cudd_bddVarConjDecomp Cudd_RemapOverApprox
+ Cudd_bddSqueeze Cudd_bddLICompaction]
+
+******************************************************************************/
+int
+Cudd_bddApproxConjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** conjuncts /* address of the first factor */)
+{
+ DdNode *superset1, *superset2, *glocal, *hlocal;
+ int nvars = Cudd_SupportSize(dd,f);
+
+ /* Find a tentative first factor by overapproximation and minimization. */
+ superset1 = Cudd_RemapOverApprox(dd,f,nvars,0,1.0);
+ if (superset1 == NULL) return(0);
+ cuddRef(superset1);
+ superset2 = Cudd_bddSqueeze(dd,f,superset1);
+ if (superset2 == NULL) {
+ Cudd_RecursiveDeref(dd,superset1);
+ return(0);
+ }
+ cuddRef(superset2);
+ Cudd_RecursiveDeref(dd,superset1);
+
+ /* Compute the second factor by minimization. */
+ hlocal = Cudd_bddLICompaction(dd,f,superset2);
+ if (hlocal == NULL) {
+ Cudd_RecursiveDeref(dd,superset2);
+ return(0);
+ }
+ cuddRef(hlocal);
+
+ /* Refine the first factor by minimization. If h turns out to be f, this
+ ** step guarantees that g will be 1. */
+ glocal = Cudd_bddLICompaction(dd,superset2,hlocal);
+ if (glocal == NULL) {
+ Cudd_RecursiveDeref(dd,superset2);
+ Cudd_RecursiveDeref(dd,hlocal);
+ return(0);
+ }
+ cuddRef(glocal);
+ Cudd_RecursiveDeref(dd,superset2);
+
+ if (glocal != DD_ONE(dd)) {
+ if (hlocal != DD_ONE(dd)) {
+ *conjuncts = ALLOC(DdNode *,2);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,glocal);
+ Cudd_RecursiveDeref(dd,hlocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = glocal;
+ (*conjuncts)[1] = hlocal;
+ return(2);
+ } else {
+ Cudd_RecursiveDeref(dd,hlocal);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,glocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = glocal;
+ return(1);
+ }
+ } else {
+ Cudd_RecursiveDeref(dd,glocal);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,hlocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = hlocal;
+ return(1);
+ }
+
+} /* end of Cudd_bddApproxConjDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way disjunctive decomposition of a BDD.]
+
+ Description [Performs two-way disjunctive decomposition of a BDD.
+ Returns the number of disjuncts produced, that is, 2 if successful;
+ 1 if no meaningful decomposition was found; 0 otherwise. The
+ disjuncts produced by this procedure tend to be imbalanced.]
+
+ SideEffects [The two disjuncts are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the disjuncts are already
+ referenced. If the function returns 0, the array for the disjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddApproxConjDecomp Cudd_bddIterDisjDecomp
+ Cudd_bddGenDisjDecomp Cudd_bddVarDisjDecomp]
+
+******************************************************************************/
+int
+Cudd_bddApproxDisjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** disjuncts /* address of the array of the disjuncts */)
+{
+ int result, i;
+
+ result = Cudd_bddApproxConjDecomp(dd,Cudd_Not(f),disjuncts);
+ for (i = 0; i < result; i++) {
+ (*disjuncts)[i] = Cudd_Not((*disjuncts)[i]);
+ }
+ return(result);
+
+} /* end of Cudd_bddApproxDisjDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way conjunctive decomposition of a BDD.]
+
+ Description [Performs two-way conjunctive decomposition of a
+ BDD. This procedure owes its name to the iterated use of
+ supersetting to obtain a factor of the given function. Returns the
+ number of conjuncts produced, that is, 2 if successful; 1 if no
+ meaningful decomposition was found; 0 otherwise. The conjuncts
+ produced by this procedure tend to be imbalanced.]
+
+ SideEffects [The factors are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the conjuncts are already
+ referenced. If the function returns 0, the array for the conjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddIterDisjDecomp Cudd_bddApproxConjDecomp
+ Cudd_bddGenConjDecomp Cudd_bddVarConjDecomp Cudd_RemapOverApprox
+ Cudd_bddSqueeze Cudd_bddLICompaction]
+
+******************************************************************************/
+int
+Cudd_bddIterConjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** conjuncts /* address of the array of conjuncts */)
+{
+ DdNode *superset1, *superset2, *old[2], *res[2];
+ int sizeOld, sizeNew;
+ int nvars = Cudd_SupportSize(dd,f);
+
+ old[0] = DD_ONE(dd);
+ cuddRef(old[0]);
+ old[1] = f;
+ cuddRef(old[1]);
+ sizeOld = Cudd_SharingSize(old,2);
+
+ do {
+ /* Find a tentative first factor by overapproximation and
+ ** minimization. */
+ superset1 = Cudd_RemapOverApprox(dd,old[1],nvars,0,1.0);
+ if (superset1 == NULL) {
+ Cudd_RecursiveDeref(dd,old[0]);
+ Cudd_RecursiveDeref(dd,old[1]);
+ return(0);
+ }
+ cuddRef(superset1);
+ superset2 = Cudd_bddSqueeze(dd,old[1],superset1);
+ if (superset2 == NULL) {
+ Cudd_RecursiveDeref(dd,old[0]);
+ Cudd_RecursiveDeref(dd,old[1]);
+ Cudd_RecursiveDeref(dd,superset1);
+ return(0);
+ }
+ cuddRef(superset2);
+ Cudd_RecursiveDeref(dd,superset1);
+ res[0] = Cudd_bddAnd(dd,old[0],superset2);
+ if (res[0] == NULL) {
+ Cudd_RecursiveDeref(dd,superset2);
+ Cudd_RecursiveDeref(dd,old[0]);
+ Cudd_RecursiveDeref(dd,old[1]);
+ return(0);
+ }
+ cuddRef(res[0]);
+ Cudd_RecursiveDeref(dd,superset2);
+ if (res[0] == old[0]) {
+ Cudd_RecursiveDeref(dd,res[0]);
+ break; /* avoid infinite loop */
+ }
+
+ /* Compute the second factor by minimization. */
+ res[1] = Cudd_bddLICompaction(dd,old[1],res[0]);
+ if (res[1] == NULL) {
+ Cudd_RecursiveDeref(dd,old[0]);
+ Cudd_RecursiveDeref(dd,old[1]);
+ return(0);
+ }
+ cuddRef(res[1]);
+
+ sizeNew = Cudd_SharingSize(res,2);
+ if (sizeNew <= sizeOld) {
+ Cudd_RecursiveDeref(dd,old[0]);
+ old[0] = res[0];
+ Cudd_RecursiveDeref(dd,old[1]);
+ old[1] = res[1];
+ sizeOld = sizeNew;
+ } else {
+ Cudd_RecursiveDeref(dd,res[0]);
+ Cudd_RecursiveDeref(dd,res[1]);
+ break;
+ }
+
+ } while (1);
+
+ /* Refine the first factor by minimization. If h turns out to
+ ** be f, this step guarantees that g will be 1. */
+ superset1 = Cudd_bddLICompaction(dd,old[0],old[1]);
+ if (superset1 == NULL) {
+ Cudd_RecursiveDeref(dd,old[0]);
+ Cudd_RecursiveDeref(dd,old[1]);
+ return(0);
+ }
+ cuddRef(superset1);
+ Cudd_RecursiveDeref(dd,old[0]);
+ old[0] = superset1;
+
+ if (old[0] != DD_ONE(dd)) {
+ if (old[1] != DD_ONE(dd)) {
+ *conjuncts = ALLOC(DdNode *,2);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,old[0]);
+ Cudd_RecursiveDeref(dd,old[1]);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = old[0];
+ (*conjuncts)[1] = old[1];
+ return(2);
+ } else {
+ Cudd_RecursiveDeref(dd,old[1]);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,old[0]);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = old[0];
+ return(1);
+ }
+ } else {
+ Cudd_RecursiveDeref(dd,old[0]);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,old[1]);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = old[1];
+ return(1);
+ }
+
+} /* end of Cudd_bddIterConjDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way disjunctive decomposition of a BDD.]
+
+ Description [Performs two-way disjunctive decomposition of a BDD.
+ Returns the number of disjuncts produced, that is, 2 if successful;
+ 1 if no meaningful decomposition was found; 0 otherwise. The
+ disjuncts produced by this procedure tend to be imbalanced.]
+
+ SideEffects [The two disjuncts are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the disjuncts are already
+ referenced. If the function returns 0, the array for the disjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddIterConjDecomp Cudd_bddApproxDisjDecomp
+ Cudd_bddGenDisjDecomp Cudd_bddVarDisjDecomp]
+
+******************************************************************************/
+int
+Cudd_bddIterDisjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** disjuncts /* address of the array of the disjuncts */)
+{
+ int result, i;
+
+ result = Cudd_bddIterConjDecomp(dd,Cudd_Not(f),disjuncts);
+ for (i = 0; i < result; i++) {
+ (*disjuncts)[i] = Cudd_Not((*disjuncts)[i]);
+ }
+ return(result);
+
+} /* end of Cudd_bddIterDisjDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way conjunctive decomposition of a BDD.]
+
+ Description [Performs two-way conjunctive decomposition of a
+ BDD. This procedure owes its name to the fact tht it generalizes the
+ decomposition based on the cofactors with respect to one
+ variable. Returns the number of conjuncts produced, that is, 2 if
+ successful; 1 if no meaningful decomposition was found; 0
+ otherwise. The conjuncts produced by this procedure tend to be
+ balanced.]
+
+ SideEffects [The two factors are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the conjuncts are already
+ referenced. If the function returns 0, the array for the conjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddGenDisjDecomp Cudd_bddApproxConjDecomp
+ Cudd_bddIterConjDecomp Cudd_bddVarConjDecomp]
+
+******************************************************************************/
+int
+Cudd_bddGenConjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** conjuncts /* address of the array of conjuncts */)
+{
+ int result;
+ DdNode *glocal, *hlocal;
+
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ do {
+ dd->reordered = 0;
+ result = cuddConjunctsAux(dd, f, &glocal, &hlocal);
+ } while (dd->reordered == 1);
+
+ if (result == 0) {
+ return(0);
+ }
+
+ if (glocal != one) {
+ if (hlocal != one) {
+ *conjuncts = ALLOC(DdNode *,2);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,glocal);
+ Cudd_RecursiveDeref(dd,hlocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = glocal;
+ (*conjuncts)[1] = hlocal;
+ return(2);
+ } else {
+ Cudd_RecursiveDeref(dd,hlocal);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,glocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = glocal;
+ return(1);
+ }
+ } else {
+ Cudd_RecursiveDeref(dd,glocal);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,hlocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = hlocal;
+ return(1);
+ }
+
+} /* end of Cudd_bddGenConjDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way disjunctive decomposition of a BDD.]
+
+ Description [Performs two-way disjunctive decomposition of a BDD.
+ Returns the number of disjuncts produced, that is, 2 if successful;
+ 1 if no meaningful decomposition was found; 0 otherwise. The
+ disjuncts produced by this procedure tend to be balanced.]
+
+ SideEffects [The two disjuncts are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the disjuncts are already
+ referenced. If the function returns 0, the array for the disjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddGenConjDecomp Cudd_bddApproxDisjDecomp
+ Cudd_bddIterDisjDecomp Cudd_bddVarDisjDecomp]
+
+******************************************************************************/
+int
+Cudd_bddGenDisjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** disjuncts /* address of the array of the disjuncts */)
+{
+ int result, i;
+
+ result = Cudd_bddGenConjDecomp(dd,Cudd_Not(f),disjuncts);
+ for (i = 0; i < result; i++) {
+ (*disjuncts)[i] = Cudd_Not((*disjuncts)[i]);
+ }
+ return(result);
+
+} /* end of Cudd_bddGenDisjDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way conjunctive decomposition of a BDD.]
+
+ Description [Conjunctively decomposes one BDD according to a
+ variable. If <code>f</code> is the function of the BDD and
+ <code>x</code> is the variable, the decomposition is
+ <code>(f+x)(f+x')</code>. The variable is chosen so as to balance
+ the sizes of the two conjuncts and to keep them small. Returns the
+ number of conjuncts produced, that is, 2 if successful; 1 if no
+ meaningful decomposition was found; 0 otherwise.]
+
+ SideEffects [The two factors are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the conjuncts are already
+ referenced. If the function returns 0, the array for the conjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddVarDisjDecomp Cudd_bddGenConjDecomp
+ Cudd_bddApproxConjDecomp Cudd_bddIterConjDecomp]
+
+*****************************************************************************/
+int
+Cudd_bddVarConjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** conjuncts /* address of the array of conjuncts */)
+{
+ int best;
+ int min;
+ DdNode *support, *scan, *var, *glocal, *hlocal;
+
+ /* Find best cofactoring variable. */
+ support = Cudd_Support(dd,f);
+ if (support == NULL) return(0);
+ if (Cudd_IsConstant(support)) {
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = f;
+ cuddRef((*conjuncts)[0]);
+ return(1);
+ }
+ cuddRef(support);
+ min = 1000000000;
+ best = -1;
+ scan = support;
+ while (!Cudd_IsConstant(scan)) {
+ int i = scan->index;
+ int est1 = Cudd_EstimateCofactor(dd,f,i,1);
+ int est0 = Cudd_EstimateCofactor(dd,f,i,0);
+ /* Minimize the size of the larger of the two cofactors. */
+ int est = (est1 > est0) ? est1 : est0;
+ if (est < min) {
+ min = est;
+ best = i;
+ }
+ scan = cuddT(scan);
+ }
+#ifdef DD_DEBUG
+ assert(best >= 0 && best < dd->size);
+#endif
+ Cudd_RecursiveDeref(dd,support);
+
+ var = Cudd_bddIthVar(dd,best);
+ glocal = Cudd_bddOr(dd,f,var);
+ if (glocal == NULL) {
+ return(0);
+ }
+ cuddRef(glocal);
+ hlocal = Cudd_bddOr(dd,f,Cudd_Not(var));
+ if (hlocal == NULL) {
+ Cudd_RecursiveDeref(dd,glocal);
+ return(0);
+ }
+ cuddRef(hlocal);
+
+ if (glocal != DD_ONE(dd)) {
+ if (hlocal != DD_ONE(dd)) {
+ *conjuncts = ALLOC(DdNode *,2);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,glocal);
+ Cudd_RecursiveDeref(dd,hlocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = glocal;
+ (*conjuncts)[1] = hlocal;
+ return(2);
+ } else {
+ Cudd_RecursiveDeref(dd,hlocal);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,glocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = glocal;
+ return(1);
+ }
+ } else {
+ Cudd_RecursiveDeref(dd,glocal);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,hlocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = hlocal;
+ return(1);
+ }
+
+} /* end of Cudd_bddVarConjDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way disjunctive decomposition of a BDD.]
+
+ Description [Performs two-way disjunctive decomposition of a BDD
+ according to a variable. If <code>f</code> is the function of the
+ BDD and <code>x</code> is the variable, the decomposition is
+ <code>f*x + f*x'</code>. The variable is chosen so as to balance
+ the sizes of the two disjuncts and to keep them small. Returns the
+ number of disjuncts produced, that is, 2 if successful; 1 if no
+ meaningful decomposition was found; 0 otherwise.]
+
+ SideEffects [The two disjuncts are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the disjuncts are already
+ referenced. If the function returns 0, the array for the disjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddVarConjDecomp Cudd_bddApproxDisjDecomp
+ Cudd_bddIterDisjDecomp Cudd_bddGenDisjDecomp]
+
+******************************************************************************/
+int
+Cudd_bddVarDisjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** disjuncts /* address of the array of the disjuncts */)
+{
+ int result, i;
+
+ result = Cudd_bddVarConjDecomp(dd,Cudd_Not(f),disjuncts);
+ for (i = 0; i < result; i++) {
+ (*disjuncts)[i] = Cudd_Not((*disjuncts)[i]);
+ }
+ return(result);
+
+} /* end of Cudd_bddVarDisjDecomp */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Get longest distance of node from constant.]
+
+ Description [Get longest distance of node from constant. Returns the
+ distance of the root from the constant if successful; CUDD_OUT_OF_MEM
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static NodeStat *
+CreateBotDist(
+ DdNode * node,
+ st_table * distanceTable)
+{
+ DdNode *N, *Nv, *Nnv;
+ int distance, distanceNv, distanceNnv;
+ NodeStat *nodeStat, *nodeStatNv, *nodeStatNnv;
+
+#if 0
+ if (Cudd_IsConstant(node)) {
+ return(0);
+ }
+#endif
+
+ /* Return the entry in the table if found. */
+ N = Cudd_Regular(node);
+ if (st_lookup(distanceTable, (char *)N, (char **)&nodeStat)) {
+ nodeStat->localRef++;
+ return(nodeStat);
+ }
+
+ Nv = cuddT(N);
+ Nnv = cuddE(N);
+ Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
+ Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
+
+ /* Recur on the children. */
+ nodeStatNv = CreateBotDist(Nv, distanceTable);
+ if (nodeStatNv == NULL) return(NULL);
+ distanceNv = nodeStatNv->distance;
+
+ nodeStatNnv = CreateBotDist(Nnv, distanceTable);
+ if (nodeStatNnv == NULL) return(NULL);
+ distanceNnv = nodeStatNnv->distance;
+ /* Store max distance from constant; note sometimes this distance
+ ** may be to 0.
+ */
+ distance = (distanceNv > distanceNnv) ? (distanceNv+1) : (distanceNnv + 1);
+
+ nodeStat = ALLOC(NodeStat, 1);
+ if (nodeStat == NULL) {
+ return(0);
+ }
+ nodeStat->distance = distance;
+ nodeStat->localRef = 1;
+
+ if (st_insert(distanceTable, (char *)N, (char *)nodeStat) ==
+ ST_OUT_OF_MEM) {
+ return(0);
+
+ }
+ return(nodeStat);
+
+} /* end of CreateBotDist */
+
+
+/**Function********************************************************************
+
+ Synopsis [Count the number of minterms of each node ina a BDD and
+ store it in a hash table.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static double
+CountMinterms(
+ DdNode * node,
+ double max,
+ st_table * mintermTable,
+ FILE *fp)
+{
+ DdNode *N, *Nv, *Nnv;
+ double min, minNv, minNnv;
+ double *dummy;
+
+ N = Cudd_Regular(node);
+
+ if (cuddIsConstant(N)) {
+ if (node == zero) {
+ return(0);
+ } else {
+ return(max);
+ }
+ }
+
+ /* Return the entry in the table if found. */
+ if (st_lookup(mintermTable, (char *)node, (char **)&dummy)) {
+ min = *dummy;
+ return(min);
+ }
+
+ Nv = cuddT(N);
+ Nnv = cuddE(N);
+ Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
+ Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
+
+ /* Recur on the children. */
+ minNv = CountMinterms(Nv, max, mintermTable, fp);
+ if (minNv == -1.0) return(-1.0);
+ minNnv = CountMinterms(Nnv, max, mintermTable, fp);
+ if (minNnv == -1.0) return(-1.0);
+ min = minNv / 2.0 + minNnv / 2.0;
+ /* store
+ */
+
+ dummy = ALLOC(double, 1);
+ if (dummy == NULL) return(-1.0);
+ *dummy = min;
+ if (st_insert(mintermTable, (char *)node, (char *)dummy) == ST_OUT_OF_MEM) {
+ (void) fprintf(fp, "st table insert failed\n");
+ }
+ return(min);
+
+} /* end of CountMinterms */
+
+
+/**Function********************************************************************
+
+ Synopsis [Free factors structure]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ConjunctsFree(
+ DdManager * dd,
+ Conjuncts * factors)
+{
+ Cudd_RecursiveDeref(dd, factors->g);
+ Cudd_RecursiveDeref(dd, factors->h);
+ FREE(factors);
+ return;
+
+} /* end of ConjunctsFree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Check whether the given pair is in the tables.]
+
+ Description [.Check whether the given pair is in the tables. gTable
+ and hTable are combined.
+ absence in both is indicated by 0,
+ presence in gTable is indicated by 1,
+ presence in hTable by 2 and
+ presence in both by 3.
+ The values returned by this function are PAIR_ST,
+ PAIR_CR, G_ST, G_CR, H_ST, H_CR, BOTH_G, BOTH_H, NONE.
+ PAIR_ST implies g in gTable and h in hTable
+ PAIR_CR implies g in hTable and h in gTable
+ G_ST implies g in gTable and h not in any table
+ G_CR implies g in hTable and h not in any table
+ H_ST implies h in hTable and g not in any table
+ H_CR implies h in gTable and g not in any table
+ BOTH_G implies both in gTable
+ BOTH_H implies both in hTable
+ NONE implies none in table; ]
+
+ SideEffects []
+
+ SeeAlso [CheckTablesCacheAndReturn CheckInTables]
+
+******************************************************************************/
+static int
+PairInTables(
+ DdNode * g,
+ DdNode * h,
+ st_table * ghTable)
+{
+ int valueG, valueH, gPresent, hPresent;
+
+ valueG = valueH = gPresent = hPresent = 0;
+
+ gPresent = st_lookup_int(ghTable, (char *)Cudd_Regular(g), &valueG);
+ hPresent = st_lookup_int(ghTable, (char *)Cudd_Regular(h), &valueH);
+
+ if (!gPresent && !hPresent) return(NONE);
+
+ if (!hPresent) {
+ if (valueG & 1) return(G_ST);
+ if (valueG & 2) return(G_CR);
+ }
+ if (!gPresent) {
+ if (valueH & 1) return(H_CR);
+ if (valueH & 2) return(H_ST);
+ }
+ /* both in tables */
+ if ((valueG & 1) && (valueH & 2)) return(PAIR_ST);
+ if ((valueG & 2) && (valueH & 1)) return(PAIR_CR);
+
+ if (valueG & 1) {
+ return(BOTH_G);
+ } else {
+ return(BOTH_H);
+ }
+
+} /* end of PairInTables */
+
+
+/**Function********************************************************************
+
+ Synopsis [Check the tables for the existence of pair and return one
+ combination, cache the result.]
+
+ Description [Check the tables for the existence of pair and return
+ one combination, cache the result. The assumption is that one of the
+ conjuncts is already in the tables.]
+
+ SideEffects [g and h referenced for the cache]
+
+ SeeAlso [ZeroCase]
+
+******************************************************************************/
+static Conjuncts *
+CheckTablesCacheAndReturn(
+ DdNode * node,
+ DdNode * g,
+ DdNode * h,
+ st_table * ghTable,
+ st_table * cacheTable)
+{
+ int pairValue;
+ int value;
+ Conjuncts *factors;
+
+ value = 0;
+ /* check tables */
+ pairValue = PairInTables(g, h, ghTable);
+ assert(pairValue != NONE);
+ /* if both dont exist in table, we know one exists(either g or h).
+ * Therefore store the other and proceed
+ */
+ factors = ALLOC(Conjuncts, 1);
+ if (factors == NULL) return(NULL);
+ if ((pairValue == BOTH_H) || (pairValue == H_ST)) {
+ if (g != one) {
+ value = 0;
+ if (st_lookup_int(ghTable, (char *)Cudd_Regular(g), &value)) {
+ value |= 1;
+ } else {
+ value = 1;
+ }
+ if (st_insert(ghTable, (char *)Cudd_Regular(g),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ return(NULL);
+ }
+ }
+ factors->g = g;
+ factors->h = h;
+ } else if ((pairValue == BOTH_G) || (pairValue == G_ST)) {
+ if (h != one) {
+ value = 0;
+ if (st_lookup_int(ghTable, (char *)Cudd_Regular(h), &value)) {
+ value |= 2;
+ } else {
+ value = 2;
+ }
+ if (st_insert(ghTable, (char *)Cudd_Regular(h),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ return(NULL);
+ }
+ }
+ factors->g = g;
+ factors->h = h;
+ } else if (pairValue == H_CR) {
+ if (g != one) {
+ value = 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(g),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ return(NULL);
+ }
+ }
+ factors->g = h;
+ factors->h = g;
+ } else if (pairValue == G_CR) {
+ if (h != one) {
+ value = 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(h),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ return(NULL);
+ }
+ }
+ factors->g = h;
+ factors->h = g;
+ } else if (pairValue == PAIR_CR) {
+ /* pair exists in table */
+ factors->g = h;
+ factors->h = g;
+ } else if (pairValue == PAIR_ST) {
+ factors->g = g;
+ factors->h = h;
+ }
+
+ /* cache the result for this node */
+ if (st_insert(cacheTable, (char *)node, (char *)factors) == ST_OUT_OF_MEM) {
+ FREE(factors);
+ return(NULL);
+ }
+
+ return(factors);
+
+} /* end of CheckTablesCacheAndReturn */
+
+/**Function********************************************************************
+
+ Synopsis [Check the tables for the existence of pair and return one
+ combination, store in cache.]
+
+ Description [Check the tables for the existence of pair and return
+ one combination, store in cache. The pair that has more pointers to
+ it is picked. An approximation of the number of local pointers is
+ made by taking the reference count of the pairs sent. ]
+
+ SideEffects []
+
+ SeeAlso [ZeroCase BuildConjuncts]
+
+******************************************************************************/
+static Conjuncts *
+PickOnePair(
+ DdNode * node,
+ DdNode * g1,
+ DdNode * h1,
+ DdNode * g2,
+ DdNode * h2,
+ st_table * ghTable,
+ st_table * cacheTable)
+{
+ int value;
+ Conjuncts *factors;
+ int oneRef, twoRef;
+
+ factors = ALLOC(Conjuncts, 1);
+ if (factors == NULL) return(NULL);
+
+ /* count the number of pointers to pair 2 */
+ if (h2 == one) {
+ twoRef = (Cudd_Regular(g2))->ref;
+ } else if (g2 == one) {
+ twoRef = (Cudd_Regular(h2))->ref;
+ } else {
+ twoRef = ((Cudd_Regular(g2))->ref + (Cudd_Regular(h2))->ref)/2;
+ }
+
+ /* count the number of pointers to pair 1 */
+ if (h1 == one) {
+ oneRef = (Cudd_Regular(g1))->ref;
+ } else if (g1 == one) {
+ oneRef = (Cudd_Regular(h1))->ref;
+ } else {
+ oneRef = ((Cudd_Regular(g1))->ref + (Cudd_Regular(h1))->ref)/2;
+ }
+
+ /* pick the pair with higher reference count */
+ if (oneRef >= twoRef) {
+ factors->g = g1;
+ factors->h = h1;
+ } else {
+ factors->g = g2;
+ factors->h = h2;
+ }
+
+ /*
+ * Store computed factors in respective tables to encourage
+ * recombination.
+ */
+ if (factors->g != one) {
+ /* insert g in htable */
+ value = 0;
+ if (st_lookup_int(ghTable, (char *)Cudd_Regular(factors->g), &value)) {
+ if (value == 2) {
+ value |= 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(factors->g),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else {
+ value = 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(factors->g),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ }
+
+ if (factors->h != one) {
+ /* insert h in htable */
+ value = 0;
+ if (st_lookup_int(ghTable, (char *)Cudd_Regular(factors->h), &value)) {
+ if (value == 1) {
+ value |= 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(factors->h),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else {
+ value = 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(factors->h),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ }
+
+ /* Store factors in cache table for later use. */
+ if (st_insert(cacheTable, (char *)node, (char *)factors) ==
+ ST_OUT_OF_MEM) {
+ FREE(factors);
+ return(NULL);
+ }
+
+ return(factors);
+
+} /* end of PickOnePair */
+
+
+/**Function********************************************************************
+
+ Synopsis [Check if the two pairs exist in the table, If any of the
+ conjuncts do exist, store in the cache and return the corresponding pair.]
+
+ Description [Check if the two pairs exist in the table. If any of
+ the conjuncts do exist, store in the cache and return the
+ corresponding pair.]
+
+ SideEffects []
+
+ SeeAlso [ZeroCase BuildConjuncts]
+
+******************************************************************************/
+static Conjuncts *
+CheckInTables(
+ DdNode * node,
+ DdNode * g1,
+ DdNode * h1,
+ DdNode * g2,
+ DdNode * h2,
+ st_table * ghTable,
+ st_table * cacheTable,
+ int * outOfMem)
+{
+ int pairValue1, pairValue2;
+ Conjuncts *factors;
+ int value;
+
+ *outOfMem = 0;
+
+ /* check existence of pair in table */
+ pairValue1 = PairInTables(g1, h1, ghTable);
+ pairValue2 = PairInTables(g2, h2, ghTable);
+
+ /* if none of the 4 exist in the gh tables, return NULL */
+ if ((pairValue1 == NONE) && (pairValue2 == NONE)) {
+ return NULL;
+ }
+
+ factors = ALLOC(Conjuncts, 1);
+ if (factors == NULL) {
+ *outOfMem = 1;
+ return NULL;
+ }
+
+ /* pairs that already exist in the table get preference. */
+ if (pairValue1 == PAIR_ST) {
+ factors->g = g1;
+ factors->h = h1;
+ } else if (pairValue2 == PAIR_ST) {
+ factors->g = g2;
+ factors->h = h2;
+ } else if (pairValue1 == PAIR_CR) {
+ factors->g = h1;
+ factors->h = g1;
+ } else if (pairValue2 == PAIR_CR) {
+ factors->g = h2;
+ factors->h = g2;
+ } else if (pairValue1 == G_ST) {
+ /* g exists in the table, h is not found in either table */
+ factors->g = g1;
+ factors->h = h1;
+ if (h1 != one) {
+ value = 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(h1),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue1 == BOTH_G) {
+ /* g and h are found in the g table */
+ factors->g = g1;
+ factors->h = h1;
+ if (h1 != one) {
+ value = 3;
+ if (st_insert(ghTable, (char *)Cudd_Regular(h1),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue1 == H_ST) {
+ /* h exists in the table, g is not found in either table */
+ factors->g = g1;
+ factors->h = h1;
+ if (g1 != one) {
+ value = 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(g1),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue1 == BOTH_H) {
+ /* g and h are found in the h table */
+ factors->g = g1;
+ factors->h = h1;
+ if (g1 != one) {
+ value = 3;
+ if (st_insert(ghTable, (char *)Cudd_Regular(g1),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue2 == G_ST) {
+ /* g exists in the table, h is not found in either table */
+ factors->g = g2;
+ factors->h = h2;
+ if (h2 != one) {
+ value = 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(h2),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue2 == BOTH_G) {
+ /* g and h are found in the g table */
+ factors->g = g2;
+ factors->h = h2;
+ if (h2 != one) {
+ value = 3;
+ if (st_insert(ghTable, (char *)Cudd_Regular(h2),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue2 == H_ST) {
+ /* h exists in the table, g is not found in either table */
+ factors->g = g2;
+ factors->h = h2;
+ if (g2 != one) {
+ value = 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(g2),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue2 == BOTH_H) {
+ /* g and h are found in the h table */
+ factors->g = g2;
+ factors->h = h2;
+ if (g2 != one) {
+ value = 3;
+ if (st_insert(ghTable, (char *)Cudd_Regular(g2),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue1 == G_CR) {
+ /* g found in h table and h in none */
+ factors->g = h1;
+ factors->h = g1;
+ if (h1 != one) {
+ value = 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(h1),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue1 == H_CR) {
+ /* h found in g table and g in none */
+ factors->g = h1;
+ factors->h = g1;
+ if (g1 != one) {
+ value = 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(g1),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue2 == G_CR) {
+ /* g found in h table and h in none */
+ factors->g = h2;
+ factors->h = g2;
+ if (h2 != one) {
+ value = 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(h2),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue2 == H_CR) {
+ /* h found in g table and g in none */
+ factors->g = h2;
+ factors->h = g2;
+ if (g2 != one) {
+ value = 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(g2),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ }
+
+ /* Store factors in cache table for later use. */
+ if (st_insert(cacheTable, (char *)node, (char *)factors) ==
+ ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ return factors;
+} /* end of CheckInTables */
+
+
+
+/**Function********************************************************************
+
+ Synopsis [If one child is zero, do explicitly what Restrict does or better]
+
+ Description [If one child is zero, do explicitly what Restrict does or better.
+ First separate a variable and its child in the base case. In case of a cube
+ times a function, separate the cube and function. As a last resort, look in
+ tables.]
+
+ SideEffects [Frees the BDDs in factorsNv. factorsNv itself is not freed
+ because it is freed above.]
+
+ SeeAlso [BuildConjuncts]
+
+******************************************************************************/
+static Conjuncts *
+ZeroCase(
+ DdManager * dd,
+ DdNode * node,
+ Conjuncts * factorsNv,
+ st_table * ghTable,
+ st_table * cacheTable,
+ int switched)
+{
+ int topid;
+ DdNode *g, *h, *g1, *g2, *h1, *h2, *x, *N, *G, *H, *Gv, *Gnv;
+ DdNode *Hv, *Hnv;
+ int value;
+ int outOfMem;
+ Conjuncts *factors;
+
+ /* get var at this node */
+ N = Cudd_Regular(node);
+ topid = N->index;
+ x = dd->vars[topid];
+ x = (switched) ? Cudd_Not(x): x;
+ cuddRef(x);
+
+ /* Seprate variable and child */
+ if (factorsNv->g == one) {
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ factors = ALLOC(Conjuncts, 1);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, x);
+ return(NULL);
+ }
+ factors->g = x;
+ factors->h = factorsNv->h;
+ /* cache the result*/
+ if (st_insert(cacheTable, (char *)node, (char *)factors) == ST_OUT_OF_MEM) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, x);
+ FREE(factors);
+ return NULL;
+ }
+
+ /* store x in g table, the other node is already in the table */
+ if (st_lookup_int(ghTable, (char *)Cudd_Regular(x), &value)) {
+ value |= 1;
+ } else {
+ value = 1;
+ }
+ if (st_insert(ghTable, (char *)Cudd_Regular(x), (char *)(long)value) == ST_OUT_OF_MEM) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return NULL;
+ }
+ return(factors);
+ }
+
+ /* Seprate variable and child */
+ if (factorsNv->h == one) {
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ factors = ALLOC(Conjuncts, 1);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, x);
+ return(NULL);
+ }
+ factors->g = factorsNv->g;
+ factors->h = x;
+ /* cache the result. */
+ if (st_insert(cacheTable, (char *)node, (char *)factors) == ST_OUT_OF_MEM) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, x);
+ FREE(factors);
+ return(NULL);
+ }
+ /* store x in h table, the other node is already in the table */
+ if (st_lookup_int(ghTable, (char *)Cudd_Regular(x), &value)) {
+ value |= 2;
+ } else {
+ value = 2;
+ }
+ if (st_insert(ghTable, (char *)Cudd_Regular(x), (char *)(long)value) == ST_OUT_OF_MEM) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return NULL;
+ }
+ return(factors);
+ }
+
+ G = Cudd_Regular(factorsNv->g);
+ Gv = cuddT(G);
+ Gnv = cuddE(G);
+ Gv = Cudd_NotCond(Gv, Cudd_IsComplement(node));
+ Gnv = Cudd_NotCond(Gnv, Cudd_IsComplement(node));
+ /* if the child below is a variable */
+ if ((Gv == zero) || (Gnv == zero)) {
+ h = factorsNv->h;
+ g = cuddBddAndRecur(dd, x, factorsNv->g);
+ if (g != NULL) cuddRef(g);
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, x);
+ if (g == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ return NULL;
+ }
+ /* CheckTablesCacheAndReturn responsible for allocating
+ * factors structure., g,h referenced for cache store the
+ */
+ factors = CheckTablesCacheAndReturn(node,
+ g,
+ h,
+ ghTable,
+ cacheTable);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, g);
+ Cudd_RecursiveDeref(dd, h);
+ }
+ return(factors);
+ }
+
+ H = Cudd_Regular(factorsNv->h);
+ Hv = cuddT(H);
+ Hnv = cuddE(H);
+ Hv = Cudd_NotCond(Hv, Cudd_IsComplement(node));
+ Hnv = Cudd_NotCond(Hnv, Cudd_IsComplement(node));
+ /* if the child below is a variable */
+ if ((Hv == zero) || (Hnv == zero)) {
+ g = factorsNv->g;
+ h = cuddBddAndRecur(dd, x, factorsNv->h);
+ if (h!= NULL) cuddRef(h);
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, x);
+ if (h == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ return NULL;
+ }
+ /* CheckTablesCacheAndReturn responsible for allocating
+ * factors structure.g,h referenced for table store
+ */
+ factors = CheckTablesCacheAndReturn(node,
+ g,
+ h,
+ ghTable,
+ cacheTable);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, g);
+ Cudd_RecursiveDeref(dd, h);
+ }
+ return(factors);
+ }
+
+ /* build g1 = x*g; h1 = h */
+ /* build g2 = g; h2 = x*h */
+ Cudd_RecursiveDeref(dd, x);
+ h1 = factorsNv->h;
+ g1 = cuddBddAndRecur(dd, x, factorsNv->g);
+ if (g1 != NULL) cuddRef(g1);
+ if (g1 == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ return NULL;
+ }
+
+ g2 = factorsNv->g;
+ h2 = cuddBddAndRecur(dd, x, factorsNv->h);
+ if (h2 != NULL) cuddRef(h2);
+ if (h2 == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ return NULL;
+ }
+
+ /* check whether any pair is in tables */
+ factors = CheckInTables(node, g1, h1, g2, h2, ghTable, cacheTable, &outOfMem);
+ if (outOfMem) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ return NULL;
+ }
+ if (factors != NULL) {
+ if ((factors->g == g1) || (factors->g == h1)) {
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ } else {
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ }
+ return factors;
+ }
+
+ /* check for each pair in tables and choose one */
+ factors = PickOnePair(node,g1, h1, g2, h2, ghTable, cacheTable);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ } else {
+ /* now free what was created and not used */
+ if ((factors->g == g1) || (factors->g == h1)) {
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ } else {
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ }
+ }
+
+ return(factors);
+} /* end of ZeroCase */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds the conjuncts recursively, bottom up.]
+
+ Description [Builds the conjuncts recursively, bottom up. Constants
+ are returned as (f, f). The cache is checked for previously computed
+ result. The decomposition points are determined by the local
+ reference count of this node and the longest distance from the
+ constant. At the decomposition point, the factors returned are (f,
+ 1). Recur on the two children. The order is determined by the
+ heavier branch. Combine the factors of the two children and pick the
+ one that already occurs in the gh table. Occurence in g is indicated
+ by value 1, occurence in h by 2, occurence in both 3.]
+
+ SideEffects []
+
+ SeeAlso [cuddConjunctsAux]
+
+******************************************************************************/
+static Conjuncts *
+BuildConjuncts(
+ DdManager * dd,
+ DdNode * node,
+ st_table * distanceTable,
+ st_table * cacheTable,
+ int approxDistance,
+ int maxLocalRef,
+ st_table * ghTable,
+ st_table * mintermTable)
+{
+ int topid, distance;
+ Conjuncts *factorsNv, *factorsNnv, *factors;
+ Conjuncts *dummy;
+ DdNode *N, *Nv, *Nnv, *temp, *g1, *g2, *h1, *h2, *topv;
+ double minNv = 0.0, minNnv = 0.0;
+ double *doubleDummy;
+ int switched =0;
+ int outOfMem;
+ int freeNv = 0, freeNnv = 0, freeTemp;
+ NodeStat *nodeStat;
+ int value;
+
+ /* if f is constant, return (f,f) */
+ if (Cudd_IsConstant(node)) {
+ factors = ALLOC(Conjuncts, 1);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ factors->g = node;
+ factors->h = node;
+ return(FactorsComplement(factors));
+ }
+
+ /* If result (a pair of conjuncts) in cache, return the factors. */
+ if (st_lookup(cacheTable, (char *)node, (char **)&dummy)) {
+ factors = dummy;
+ return(factors);
+ }
+
+ /* check distance and local reference count of this node */
+ N = Cudd_Regular(node);
+ if (!st_lookup(distanceTable, (char *)N, (char **)&nodeStat)) {
+ (void) fprintf(dd->err, "Not in table, Something wrong\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+ distance = nodeStat->distance;
+
+ /* at or below decomposition point, return (f, 1) */
+ if (((nodeStat->localRef > maxLocalRef*2/3) &&
+ (distance < approxDistance*2/3)) ||
+ (distance <= approxDistance/4)) {
+ factors = ALLOC(Conjuncts, 1);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ /* alternate assigning (f,1) */
+ value = 0;
+ if (st_lookup_int(ghTable, (char *)Cudd_Regular(node), &value)) {
+ if (value == 3) {
+ if (!lastTimeG) {
+ factors->g = node;
+ factors->h = one;
+ lastTimeG = 1;
+ } else {
+ factors->g = one;
+ factors->h = node;
+ lastTimeG = 0;
+ }
+ } else if (value == 1) {
+ factors->g = node;
+ factors->h = one;
+ } else {
+ factors->g = one;
+ factors->h = node;
+ }
+ } else if (!lastTimeG) {
+ factors->g = node;
+ factors->h = one;
+ lastTimeG = 1;
+ value = 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(node), (char *)(long)value) == ST_OUT_OF_MEM) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ FREE(factors);
+ return NULL;
+ }
+ } else {
+ factors->g = one;
+ factors->h = node;
+ lastTimeG = 0;
+ value = 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(node), (char *)(long)value) == ST_OUT_OF_MEM) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ FREE(factors);
+ return NULL;
+ }
+ }
+ return(FactorsComplement(factors));
+ }
+
+ /* get the children and recur */
+ Nv = cuddT(N);
+ Nnv = cuddE(N);
+ Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
+ Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
+
+ /* Choose which subproblem to solve first based on the number of
+ * minterms. We go first where there are more minterms.
+ */
+ if (!Cudd_IsConstant(Nv)) {
+ if (!st_lookup(mintermTable, (char *)Nv, (char **)&doubleDummy)) {
+ (void) fprintf(dd->err, "Not in table: Something wrong\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+ minNv = *doubleDummy;
+ }
+
+ if (!Cudd_IsConstant(Nnv)) {
+ if (!st_lookup(mintermTable, (char *)Nnv, (char **)&doubleDummy)) {
+ (void) fprintf(dd->err, "Not in table: Something wrong\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+ minNnv = *doubleDummy;
+ }
+
+ if (minNv < minNnv) {
+ temp = Nv;
+ Nv = Nnv;
+ Nnv = temp;
+ switched = 1;
+ }
+
+ /* build gt, ht recursively */
+ if (Nv != zero) {
+ factorsNv = BuildConjuncts(dd, Nv, distanceTable,
+ cacheTable, approxDistance, maxLocalRef,
+ ghTable, mintermTable);
+ if (factorsNv == NULL) return(NULL);
+ freeNv = FactorsNotStored(factorsNv);
+ factorsNv = (freeNv) ? FactorsUncomplement(factorsNv) : factorsNv;
+ cuddRef(factorsNv->g);
+ cuddRef(factorsNv->h);
+
+ /* Deal with the zero case */
+ if (Nnv == zero) {
+ /* is responsible for freeing factorsNv */
+ factors = ZeroCase(dd, node, factorsNv, ghTable,
+ cacheTable, switched);
+ if (freeNv) FREE(factorsNv);
+ return(factors);
+ }
+ }
+
+ /* build ge, he recursively */
+ if (Nnv != zero) {
+ factorsNnv = BuildConjuncts(dd, Nnv, distanceTable,
+ cacheTable, approxDistance, maxLocalRef,
+ ghTable, mintermTable);
+ if (factorsNnv == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ if (freeNv) FREE(factorsNv);
+ return(NULL);
+ }
+ freeNnv = FactorsNotStored(factorsNnv);
+ factorsNnv = (freeNnv) ? FactorsUncomplement(factorsNnv) : factorsNnv;
+ cuddRef(factorsNnv->g);
+ cuddRef(factorsNnv->h);
+
+ /* Deal with the zero case */
+ if (Nv == zero) {
+ /* is responsible for freeing factorsNv */
+ factors = ZeroCase(dd, node, factorsNnv, ghTable,
+ cacheTable, switched);
+ if (freeNnv) FREE(factorsNnv);
+ return(factors);
+ }
+ }
+
+ /* construct the 2 pairs */
+ /* g1 = x*gt + x'*ge; h1 = x*ht + x'*he; */
+ /* g2 = x*gt + x'*he; h2 = x*ht + x'*ge */
+ if (switched) {
+ factors = factorsNnv;
+ factorsNnv = factorsNv;
+ factorsNv = factors;
+ freeTemp = freeNv;
+ freeNv = freeNnv;
+ freeNnv = freeTemp;
+ }
+
+ /* Build the factors for this node. */
+ topid = N->index;
+ topv = dd->vars[topid];
+
+ g1 = cuddBddIteRecur(dd, topv, factorsNv->g, factorsNnv->g);
+ if (g1 == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, factorsNnv->g);
+ Cudd_RecursiveDeref(dd, factorsNnv->h);
+ if (freeNv) FREE(factorsNv);
+ if (freeNnv) FREE(factorsNnv);
+ return(NULL);
+ }
+
+ cuddRef(g1);
+
+ h1 = cuddBddIteRecur(dd, topv, factorsNv->h, factorsNnv->h);
+ if (h1 == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, factorsNnv->g);
+ Cudd_RecursiveDeref(dd, factorsNnv->h);
+ Cudd_RecursiveDeref(dd, g1);
+ if (freeNv) FREE(factorsNv);
+ if (freeNnv) FREE(factorsNnv);
+ return(NULL);
+ }
+
+ cuddRef(h1);
+
+ g2 = cuddBddIteRecur(dd, topv, factorsNv->g, factorsNnv->h);
+ if (g2 == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, factorsNnv->g);
+ Cudd_RecursiveDeref(dd, factorsNnv->h);
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ if (freeNv) FREE(factorsNv);
+ if (freeNnv) FREE(factorsNnv);
+ return(NULL);
+ }
+ cuddRef(g2);
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, factorsNnv->h);
+
+ h2 = cuddBddIteRecur(dd, topv, factorsNv->h, factorsNnv->g);
+ if (h2 == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, factorsNnv->g);
+ Cudd_RecursiveDeref(dd, factorsNnv->h);
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ Cudd_RecursiveDeref(dd, g2);
+ if (freeNv) FREE(factorsNv);
+ if (freeNnv) FREE(factorsNnv);
+ return(NULL);
+ }
+ cuddRef(h2);
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, factorsNnv->g);
+ if (freeNv) FREE(factorsNv);
+ if (freeNnv) FREE(factorsNnv);
+
+ /* check for each pair in tables and choose one */
+ factors = CheckInTables(node, g1, h1, g2, h2, ghTable, cacheTable, &outOfMem);
+ if (outOfMem) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ return(NULL);
+ }
+ if (factors != NULL) {
+ if ((factors->g == g1) || (factors->g == h1)) {
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ } else {
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ }
+ return(factors);
+ }
+
+ /* if not in tables, pick one pair */
+ factors = PickOnePair(node,g1, h1, g2, h2, ghTable, cacheTable);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ } else {
+ /* now free what was created and not used */
+ if ((factors->g == g1) || (factors->g == h1)) {
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ } else {
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ }
+ }
+
+ return(factors);
+
+} /* end of BuildConjuncts */
+
+
+/**Function********************************************************************
+
+ Synopsis [Procedure to compute two conjunctive factors of f and place in *c1 and *c2.]
+
+ Description [Procedure to compute two conjunctive factors of f and
+ place in *c1 and *c2. Sets up the required data - table of distances
+ from the constant and local reference count. Also minterm table. ]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddConjunctsAux(
+ DdManager * dd,
+ DdNode * f,
+ DdNode ** c1,
+ DdNode ** c2)
+{
+ st_table *distanceTable = NULL;
+ st_table *cacheTable = NULL;
+ st_table *mintermTable = NULL;
+ st_table *ghTable = NULL;
+ st_generator *stGen;
+ char *key, *value;
+ Conjuncts *factors;
+ int distance, approxDistance;
+ double max, minterms;
+ int freeFactors;
+ NodeStat *nodeStat;
+ int maxLocalRef;
+
+ /* initialize */
+ *c1 = NULL;
+ *c2 = NULL;
+
+ /* initialize distances table */
+ distanceTable = st_init_table(st_ptrcmp,st_ptrhash);
+ if (distanceTable == NULL) goto outOfMem;
+
+ /* make the entry for the constant */
+ nodeStat = ALLOC(NodeStat, 1);
+ if (nodeStat == NULL) goto outOfMem;
+ nodeStat->distance = 0;
+ nodeStat->localRef = 1;
+ if (st_insert(distanceTable, (char *)one, (char *)nodeStat) == ST_OUT_OF_MEM) {
+ goto outOfMem;
+ }
+
+ /* Count node distances from constant. */
+ nodeStat = CreateBotDist(f, distanceTable);
+ if (nodeStat == NULL) goto outOfMem;
+
+ /* set the distance for the decomposition points */
+ approxDistance = (DEPTH < nodeStat->distance) ? nodeStat->distance : DEPTH;
+ distance = nodeStat->distance;
+
+ if (distance < approxDistance) {
+ /* Too small to bother. */
+ *c1 = f;
+ *c2 = DD_ONE(dd);
+ cuddRef(*c1); cuddRef(*c2);
+ stGen = st_init_gen(distanceTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ FREE(value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+ st_free_table(distanceTable);
+ return(1);
+ }
+
+ /* record the maximum local reference count */
+ maxLocalRef = 0;
+ stGen = st_init_gen(distanceTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ nodeStat = (NodeStat *)value;
+ maxLocalRef = (nodeStat->localRef > maxLocalRef) ?
+ nodeStat->localRef : maxLocalRef;
+ }
+ st_free_gen(stGen); stGen = NULL;
+
+
+ /* Count minterms for each node. */
+ max = pow(2.0, (double)Cudd_SupportSize(dd,f)); /* potential overflow */
+ mintermTable = st_init_table(st_ptrcmp,st_ptrhash);
+ if (mintermTable == NULL) goto outOfMem;
+ minterms = CountMinterms(f, max, mintermTable, dd->err);
+ if (minterms == -1.0) goto outOfMem;
+
+ lastTimeG = Cudd_Random() & 1;
+ cacheTable = st_init_table(st_ptrcmp, st_ptrhash);
+ if (cacheTable == NULL) goto outOfMem;
+ ghTable = st_init_table(st_ptrcmp, st_ptrhash);
+ if (ghTable == NULL) goto outOfMem;
+
+ /* Build conjuncts. */
+ factors = BuildConjuncts(dd, f, distanceTable, cacheTable,
+ approxDistance, maxLocalRef, ghTable, mintermTable);
+ if (factors == NULL) goto outOfMem;
+
+ /* free up tables */
+ stGen = st_init_gen(distanceTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ FREE(value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+ st_free_table(distanceTable); distanceTable = NULL;
+ st_free_table(ghTable); ghTable = NULL;
+
+ stGen = st_init_gen(mintermTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ FREE(value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+ st_free_table(mintermTable); mintermTable = NULL;
+
+ freeFactors = FactorsNotStored(factors);
+ factors = (freeFactors) ? FactorsUncomplement(factors) : factors;
+ if (factors != NULL) {
+ *c1 = factors->g;
+ *c2 = factors->h;
+ cuddRef(*c1);
+ cuddRef(*c2);
+ if (freeFactors) FREE(factors);
+
+#if 0
+ if ((*c1 == f) && (!Cudd_IsConstant(f))) {
+ assert(*c2 == one);
+ }
+ if ((*c2 == f) && (!Cudd_IsConstant(f))) {
+ assert(*c1 == one);
+ }
+
+ if ((*c1 != one) && (!Cudd_IsConstant(f))) {
+ assert(!Cudd_bddLeq(dd, *c2, *c1));
+ }
+ if ((*c2 != one) && (!Cudd_IsConstant(f))) {
+ assert(!Cudd_bddLeq(dd, *c1, *c2));
+ }
+#endif
+ }
+
+ stGen = st_init_gen(cacheTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ ConjunctsFree(dd, (Conjuncts *)value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+
+ st_free_table(cacheTable); cacheTable = NULL;
+
+ return(1);
+
+outOfMem:
+ if (distanceTable != NULL) {
+ stGen = st_init_gen(distanceTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ FREE(value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+ st_free_table(distanceTable); distanceTable = NULL;
+ }
+ if (mintermTable != NULL) {
+ stGen = st_init_gen(mintermTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ FREE(value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+ st_free_table(mintermTable); mintermTable = NULL;
+ }
+ if (ghTable != NULL) st_free_table(ghTable);
+ if (cacheTable != NULL) {
+ stGen = st_init_gen(cacheTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ ConjunctsFree(dd, (Conjuncts *)value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+ st_free_table(cacheTable); cacheTable = NULL;
+ }
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+
+} /* end of cuddConjunctsAux */
diff --git a/src/bdd/cudd/cuddEssent.c b/src/bdd/cudd/cuddEssent.c
new file mode 100644
index 00000000..7bd48c5a
--- /dev/null
+++ b/src/bdd/cudd/cuddEssent.c
@@ -0,0 +1,279 @@
+/**CFile***********************************************************************
+
+ FileName [cuddEssent.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for the detection of essential variables.]
+
+ Description [External procedures included in this file:
+ <ul>
+ <li> Cudd_FindEssential()
+ <li> Cudd_bddIsVarEssential()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> ddFindEssentialRecur()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddEssent.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdNode * ddFindEssentialRecur ARGS((DdManager *dd, DdNode *f));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the essential variables of a DD.]
+
+ Description [Returns the cube of the essential variables. A positive
+ literal means that the variable must be set to 1 for the function to be
+ 1. A negative literal means that the variable must be set to 0 for the
+ function to be 1. Returns a pointer to the cube BDD if successful;
+ NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIsVarEssential]
+
+******************************************************************************/
+DdNode *
+Cudd_FindEssential(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = ddFindEssentialRecur(dd,f);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_FindEssential */
+
+
+/**Function********************************************************************
+
+ Synopsis [Determines whether a given variable is essential with a
+ given phase in a BDD.]
+
+ Description [Determines whether a given variable is essential with a
+ given phase in a BDD. Uses Cudd_bddIteConstant. Returns 1 if phase == 1
+ and f-->x_id, or if phase == 0 and f-->x_id'.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_FindEssential]
+
+******************************************************************************/
+int
+Cudd_bddIsVarEssential(
+ DdManager * manager,
+ DdNode * f,
+ int id,
+ int phase)
+{
+ DdNode *var;
+ int res;
+ DdNode *one, *zero;
+
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ var = cuddUniqueInter(manager, id, one, zero);
+
+ var = Cudd_NotCond(var,phase == 0);
+
+ res = Cudd_bddIteConstant(manager, Cudd_Not(f), one, var) == one;
+
+ return(res);
+
+} /* end of Cudd_bddIsVarEssential */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_FindEssential.]
+
+ Description [Implements the recursive step of Cudd_FindEssential.
+ Returns a pointer to the cube BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static DdNode *
+ddFindEssentialRecur(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode *T, *E, *F;
+ DdNode *essT, *essE, *res;
+ int index;
+ DdNode *one, *lzero, *azero;
+
+ one = DD_ONE(dd);
+ F = Cudd_Regular(f);
+ /* If f is constant the set of essential variables is empty. */
+ if (cuddIsConstant(F)) return(one);
+
+ res = cuddCacheLookup1(dd,Cudd_FindEssential,f);
+ if (res != NULL) {
+ return(res);
+ }
+
+ lzero = Cudd_Not(one);
+ azero = DD_ZERO(dd);
+ /* Find cofactors: here f is non-constant. */
+ T = cuddT(F);
+ E = cuddE(F);
+ if (Cudd_IsComplement(f)) {
+ T = Cudd_Not(T); E = Cudd_Not(E);
+ }
+
+ index = F->index;
+ if (Cudd_IsConstant(T) && T != lzero && T != azero) {
+ /* if E is zero, index is essential, otherwise there are no
+ ** essentials, because index is not essential and no other variable
+ ** can be, since setting index = 1 makes the function constant and
+ ** different from 0.
+ */
+ if (E == lzero || E == azero) {
+ res = dd->vars[index];
+ } else {
+ res = one;
+ }
+ } else if (T == lzero || T == azero) {
+ if (Cudd_IsConstant(E)) { /* E cannot be zero here */
+ res = Cudd_Not(dd->vars[index]);
+ } else { /* E == non-constant */
+ /* find essentials in the else branch */
+ essE = ddFindEssentialRecur(dd,E);
+ if (essE == NULL) {
+ return(NULL);
+ }
+ cuddRef(essE);
+
+ /* add index to the set with negative phase */
+ res = cuddUniqueInter(dd,index,one,Cudd_Not(essE));
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,essE);
+ return(NULL);
+ }
+ res = Cudd_Not(res);
+ cuddDeref(essE);
+ }
+ } else { /* T == non-const */
+ if (E == lzero || E == azero) {
+ /* find essentials in the then branch */
+ essT = ddFindEssentialRecur(dd,T);
+ if (essT == NULL) {
+ return(NULL);
+ }
+ cuddRef(essT);
+
+ /* add index to the set with positive phase */
+ /* use And because essT may be complemented */
+ res = cuddBddAndRecur(dd,dd->vars[index],essT);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,essT);
+ return(NULL);
+ }
+ cuddDeref(essT);
+ } else if (!Cudd_IsConstant(E)) {
+ /* if E is a non-zero constant there are no essentials
+ ** because T is non-constant.
+ */
+ essT = ddFindEssentialRecur(dd,T);
+ if (essT == NULL) {
+ return(NULL);
+ }
+ if (essT == one) {
+ res = one;
+ } else {
+ cuddRef(essT);
+ essE = ddFindEssentialRecur(dd,E);
+ if (essE == NULL) {
+ Cudd_RecursiveDeref(dd,essT);
+ return(NULL);
+ }
+ cuddRef(essE);
+
+ /* res = intersection(essT, essE) */
+ res = cuddBddLiteralSetIntersectionRecur(dd,essT,essE);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,essT);
+ Cudd_RecursiveDeref(dd,essE);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd,essT);
+ Cudd_RecursiveDeref(dd,essE);
+ cuddDeref(res);
+ }
+ } else { /* E is a non-zero constant */
+ res = one;
+ }
+ }
+
+ cuddCacheInsert1(dd,Cudd_FindEssential, f, res);
+ return(res);
+
+} /* end of ddFindEssentialRecur */
+
diff --git a/src/bdd/cudd/cuddExact.c b/src/bdd/cudd/cuddExact.c
new file mode 100644
index 00000000..6a81406b
--- /dev/null
+++ b/src/bdd/cudd/cuddExact.c
@@ -0,0 +1,1004 @@
+/**CFile***********************************************************************
+
+ FileName [cuddExact.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for exact variable reordering.]
+
+ Description [External procedures included in this file:
+ <ul>
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddExact()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> getMaxBinomial()
+ <li> gcd()
+ <li> getMatrix()
+ <li> freeMatrix()
+ <li> getLevelKeys()
+ <li> ddShuffle()
+ <li> ddSiftUp()
+ <li> updateUB()
+ <li> ddCountRoots()
+ <li> ddClearGlobal()
+ <li> computeLB()
+ <li> updateEntry()
+ <li> pushDown()
+ <li> initSymmInfo()
+ </ul>]
+
+ Author [Cheng Hua, Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddExact.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+#ifdef DD_STATS
+static int ddTotalShuffles;
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int getMaxBinomial ARGS((int n));
+static int gcd ARGS((int x, int y));
+static DdHalfWord ** getMatrix ARGS((int rows, int cols));
+static void freeMatrix ARGS((DdHalfWord **matrix));
+static int getLevelKeys ARGS((DdManager *table, int l));
+static int ddShuffle ARGS((DdManager *table, DdHalfWord *permutation, int lower, int upper));
+static int ddSiftUp ARGS((DdManager *table, int x, int xLow));
+static int updateUB ARGS((DdManager *table, int oldBound, DdHalfWord *bestOrder, int lower, int upper));
+static int ddCountRoots ARGS((DdManager *table, int lower, int upper));
+static void ddClearGlobal ARGS((DdManager *table, int lower, int maxlevel));
+static int computeLB ARGS((DdManager *table, DdHalfWord *order, int roots, int cost, int lower, int upper, int level));
+static int updateEntry ARGS((DdManager *table, DdHalfWord *order, int level, int cost, DdHalfWord **orders, int *costs, int subsets, char *mask, int lower, int upper));
+static void pushDown ARGS((DdHalfWord *order, int j, int level));
+static DdHalfWord * initSymmInfo ARGS((DdManager *table, int lower, int upper));
+static int checkSymmInfo ARGS((DdManager *table, DdHalfWord *symmInfo, int index, int level));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Exact variable ordering algorithm.]
+
+ Description [Exact variable ordering algorithm. Finds an optimum
+ order for the variables between lower and upper. Returns 1 if
+ successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddExact(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int k, i, j;
+ int maxBinomial, oldSubsets, newSubsets;
+ int subsetCost;
+ int size; /* number of variables to be reordered */
+ int unused, nvars, level, result;
+ int upperBound, lowerBound, cost;
+ int roots;
+ char *mask = NULL;
+ DdHalfWord *symmInfo = NULL;
+ DdHalfWord **newOrder = NULL;
+ DdHalfWord **oldOrder = NULL;
+ int *newCost = NULL;
+ int *oldCost = NULL;
+ DdHalfWord **tmpOrder;
+ int *tmpCost;
+ DdHalfWord *bestOrder = NULL;
+ DdHalfWord *order;
+#ifdef DD_STATS
+ int ddTotalSubsets;
+#endif
+
+ /* Restrict the range to be reordered by excluding unused variables
+ ** at the two ends. */
+ while (table->subtables[lower].keys == 1 &&
+ table->vars[table->invperm[lower]]->ref == 1 &&
+ lower < upper)
+ lower++;
+ while (table->subtables[upper].keys == 1 &&
+ table->vars[table->invperm[upper]]->ref == 1 &&
+ lower < upper)
+ upper--;
+ if (lower == upper) return(1); /* trivial problem */
+
+ /* Apply symmetric sifting to get a good upper bound and to extract
+ ** symmetry information. */
+ result = cuddSymmSiftingConv(table,lower,upper);
+ if (result == 0) goto cuddExactOutOfMem;
+
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n");
+ ddTotalShuffles = 0;
+ ddTotalSubsets = 0;
+#endif
+
+ /* Initialization. */
+ nvars = table->size;
+ size = upper - lower + 1;
+ /* Count unused variable among those to be reordered. This is only
+ ** used to compute maxBinomial. */
+ unused = 0;
+ for (i = lower + 1; i < upper; i++) {
+ if (table->subtables[i].keys == 1 &&
+ table->vars[table->invperm[i]]->ref == 1)
+ unused++;
+ }
+
+ /* Find the maximum number of subsets we may have to store. */
+ maxBinomial = getMaxBinomial(size - unused);
+ if (maxBinomial == -1) goto cuddExactOutOfMem;
+
+ newOrder = getMatrix(maxBinomial, size);
+ if (newOrder == NULL) goto cuddExactOutOfMem;
+
+ newCost = ALLOC(int, maxBinomial);
+ if (newCost == NULL) goto cuddExactOutOfMem;
+
+ oldOrder = getMatrix(maxBinomial, size);
+ if (oldOrder == NULL) goto cuddExactOutOfMem;
+
+ oldCost = ALLOC(int, maxBinomial);
+ if (oldCost == NULL) goto cuddExactOutOfMem;
+
+ bestOrder = ALLOC(DdHalfWord, size);
+ if (bestOrder == NULL) goto cuddExactOutOfMem;
+
+ mask = ALLOC(char, nvars);
+ if (mask == NULL) goto cuddExactOutOfMem;
+
+ symmInfo = initSymmInfo(table, lower, upper);
+ if (symmInfo == NULL) goto cuddExactOutOfMem;
+
+ roots = ddCountRoots(table, lower, upper);
+
+ /* Initialize the old order matrix for the empty subset and the best
+ ** order to the current order. The cost for the empty subset includes
+ ** the cost of the levels between upper and the constants. These levels
+ ** are not going to change. Hence, we count them only once.
+ */
+ oldSubsets = 1;
+ for (i = 0; i < size; i++) {
+ oldOrder[0][i] = bestOrder[i] = (DdHalfWord) table->invperm[i+lower];
+ }
+ subsetCost = table->constants.keys;
+ for (i = upper + 1; i < nvars; i++)
+ subsetCost += getLevelKeys(table,i);
+ oldCost[0] = subsetCost;
+ /* The upper bound is initialized to the current size of the BDDs. */
+ upperBound = table->keys - table->isolated;
+
+ /* Now consider subsets of increasing size. */
+ for (k = 1; k <= size; k++) {
+#if DD_STATS
+ (void) fprintf(table->out,"Processing subsets of size %d\n", k);
+ fflush(table->out);
+#endif
+ newSubsets = 0;
+ level = size - k; /* offset of first bottom variable */
+
+ for (i = 0; i < oldSubsets; i++) { /* for each subset of size k-1 */
+ order = oldOrder[i];
+ cost = oldCost[i];
+ lowerBound = computeLB(table, order, roots, cost, lower, upper,
+ level);
+ if (lowerBound >= upperBound)
+ continue;
+ /* Impose new order. */
+ result = ddShuffle(table, order, lower, upper);
+ if (result == 0) goto cuddExactOutOfMem;
+ upperBound = updateUB(table,upperBound,bestOrder,lower,upper);
+ /* For each top bottom variable. */
+ for (j = level; j >= 0; j--) {
+ /* Skip unused variables. */
+ if (table->subtables[j+lower-1].keys == 1 &&
+ table->vars[table->invperm[j+lower-1]]->ref == 1) continue;
+ /* Find cost under this order. */
+ subsetCost = cost + getLevelKeys(table, lower + level);
+ newSubsets = updateEntry(table, order, level, subsetCost,
+ newOrder, newCost, newSubsets, mask,
+ lower, upper);
+ if (j == 0)
+ break;
+ if (checkSymmInfo(table, symmInfo, order[j-1], level) == 0)
+ continue;
+ pushDown(order,j-1,level);
+ /* Impose new order. */
+ result = ddShuffle(table, order, lower, upper);
+ if (result == 0) goto cuddExactOutOfMem;
+ upperBound = updateUB(table,upperBound,bestOrder,lower,upper);
+ } /* for each bottom variable */
+ } /* for each subset of size k */
+
+ /* New orders become old orders in preparation for next iteration. */
+ tmpOrder = oldOrder; tmpCost = oldCost;
+ oldOrder = newOrder; oldCost = newCost;
+ newOrder = tmpOrder; newCost = tmpCost;
+#ifdef DD_STATS
+ ddTotalSubsets += newSubsets;
+#endif
+ oldSubsets = newSubsets;
+ }
+ result = ddShuffle(table, bestOrder, lower, upper);
+ if (result == 0) goto cuddExactOutOfMem;
+#ifdef DD_STATS
+#ifdef DD_VERBOSE
+ (void) fprintf(table->out,"\n");
+#endif
+ (void) fprintf(table->out,"#:S_EXACT %8d: total subsets\n",
+ ddTotalSubsets);
+ (void) fprintf(table->out,"#:H_EXACT %8d: total shuffles",
+ ddTotalShuffles);
+#endif
+
+ freeMatrix(newOrder);
+ freeMatrix(oldOrder);
+ FREE(bestOrder);
+ FREE(oldCost);
+ FREE(newCost);
+ FREE(symmInfo);
+ FREE(mask);
+ return(1);
+
+cuddExactOutOfMem:
+
+ if (newOrder != NULL) freeMatrix(newOrder);
+ if (oldOrder != NULL) freeMatrix(oldOrder);
+ if (bestOrder != NULL) FREE(bestOrder);
+ if (oldCost != NULL) FREE(oldCost);
+ if (newCost != NULL) FREE(newCost);
+ if (symmInfo != NULL) FREE(symmInfo);
+ if (mask != NULL) FREE(mask);
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+
+} /* end of cuddExact */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the maximum value of (n choose k) for a given n.]
+
+ Description [Computes the maximum value of (n choose k) for a given
+ n. The maximum value occurs for k = n/2 when n is even, or k =
+ (n-1)/2 when n is odd. The algorithm used in this procedure is
+ quite inefficient, but it avoids intermediate overflow problems.
+ Returns the computed value if successful; -1 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+getMaxBinomial(
+ int n)
+{
+ int *numerator;
+ int i, j, k, y, g, result;
+
+ k = (n & ~1) >> 1;
+
+ numerator = ALLOC(int,k);
+ if (numerator == NULL) return(-1);
+
+ for (i = 0; i < k; i++)
+ numerator[i] = n - i;
+
+ for (i = k; i > 1; i--) {
+ y = i;
+ for (j = 0; j < k; j++) {
+ if (numerator[j] == 1) continue;
+ g = gcd(numerator[j], y);
+ if (g != 1) {
+ numerator[j] /= g;
+ if (y == g) break;
+ y /= g;
+ }
+ }
+ }
+
+ result = 1;
+ for (i = 0; i < k; i++)
+ result *= numerator[i];
+
+ FREE(numerator);
+ return(result);
+
+} /* end of getMaxBinomial */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the gcd of two integers.]
+
+ Description [Returns the gcd of two integers. Uses the binary GCD
+ algorithm described in Cormen, Leiserson, and Rivest.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+gcd(
+ int x,
+ int y)
+{
+ int a;
+ int b;
+ int lsbMask;
+
+ /* GCD(n,0) = n. */
+ if (x == 0) return(y);
+ if (y == 0) return(x);
+
+ a = x; b = y; lsbMask = 1;
+
+ /* Here both a and b are != 0. The iteration maintains this invariant.
+ ** Hence, we only need to check for when they become equal.
+ */
+ while (a != b) {
+ if (a & lsbMask) {
+ if (b & lsbMask) { /* both odd */
+ if (a < b) {
+ b = (b - a) >> 1;
+ } else {
+ a = (a - b) >> 1;
+ }
+ } else { /* a odd, b even */
+ b >>= 1;
+ }
+ } else {
+ if (b & lsbMask) { /* a even, b odd */
+ a >>= 1;
+ } else { /* both even */
+ lsbMask <<= 1;
+ }
+ }
+ }
+
+ return(a);
+
+} /* end of gcd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Allocates a two-dimensional matrix of ints.]
+
+ Description [Allocates a two-dimensional matrix of ints.
+ Returns the pointer to the matrix if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [freeMatrix]
+
+******************************************************************************/
+static DdHalfWord **
+getMatrix(
+ int rows /* number of rows */,
+ int cols /* number of columns */)
+{
+ DdHalfWord **matrix;
+ int i;
+
+ if (cols*rows == 0) return(NULL);
+ matrix = ALLOC(DdHalfWord *, rows);
+ if (matrix == NULL) return(NULL);
+ matrix[0] = ALLOC(DdHalfWord, cols*rows);
+ if (matrix[0] == NULL) return(NULL);
+ for (i = 1; i < rows; i++) {
+ matrix[i] = matrix[i-1] + cols;
+ }
+ return(matrix);
+
+} /* end of getMatrix */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees a two-dimensional matrix allocated by getMatrix.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [getMatrix]
+
+******************************************************************************/
+static void
+freeMatrix(
+ DdHalfWord ** matrix)
+{
+ FREE(matrix[0]);
+ FREE(matrix);
+ return;
+
+} /* end of freeMatrix */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of nodes at one level of a unique table.]
+
+ Description [Returns the number of nodes at one level of a unique table.
+ The projection function, if isolated, is not counted.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+getLevelKeys(
+ DdManager * table,
+ int l)
+{
+ int isolated;
+ int x; /* x is an index */
+
+ x = table->invperm[l];
+ isolated = table->vars[x]->ref == 1;
+
+ return(table->subtables[l].keys - isolated);
+
+} /* end of getLevelKeys */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders variables according to a given permutation.]
+
+ Description [Reorders variables according to a given permutation.
+ The i-th permutation array contains the index of the variable that
+ should be brought to the i-th level. ddShuffle assumes that no
+ dead nodes are present and that the interaction matrix is properly
+ initialized. The reordering is achieved by a series of upward sifts.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddShuffle(
+ DdManager * table,
+ DdHalfWord * permutation,
+ int lower,
+ int upper)
+{
+ DdHalfWord index;
+ int level;
+ int position;
+ int numvars;
+ int result;
+#ifdef DD_STATS
+ long localTime;
+ int initialSize;
+#ifdef DD_VERBOSE
+ int finalSize;
+#endif
+ int previousSize;
+#endif
+
+#ifdef DD_STATS
+ localTime = util_cpu_time();
+ initialSize = table->keys - table->isolated;
+#endif
+
+ numvars = table->size;
+
+#if 0
+ (void) fprintf(table->out,"%d:", ddTotalShuffles);
+ for (level = 0; level < numvars; level++) {
+ (void) fprintf(table->out," %d", table->invperm[level]);
+ }
+ (void) fprintf(table->out,"\n");
+#endif
+
+ for (level = 0; level <= upper - lower; level++) {
+ index = permutation[level];
+ position = table->perm[index];
+#ifdef DD_STATS
+ previousSize = table->keys - table->isolated;
+#endif
+ result = ddSiftUp(table,position,level+lower);
+ if (!result) return(0);
+ }
+
+#ifdef DD_STATS
+ ddTotalShuffles++;
+#ifdef DD_VERBOSE
+ finalSize = table->keys - table->isolated;
+ if (finalSize < initialSize) {
+ (void) fprintf(table->out,"-");
+ } else if (finalSize > initialSize) {
+ (void) fprintf(table->out,"+");
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ if ((ddTotalShuffles & 63) == 0) (void) fprintf(table->out,"\n");
+ fflush(table->out);
+#endif
+#endif
+
+ return(1);
+
+} /* end of ddShuffle */
+
+
+/**Function********************************************************************
+
+ Synopsis [Moves one variable up.]
+
+ Description [Takes a variable from position x and sifts it up to
+ position xLow; xLow should be less than or equal to x.
+ Returns 1 if successful; 0 otherwise]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddSiftUp(
+ DdManager * table,
+ int x,
+ int xLow)
+{
+ int y;
+ int size;
+
+ y = cuddNextLow(table,x);
+ while (y >= xLow) {
+ size = cuddSwapInPlace(table,y,x);
+ if (size == 0) {
+ return(0);
+ }
+ x = y;
+ y = cuddNextLow(table,x);
+ }
+ return(1);
+
+} /* end of ddSiftUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Updates the upper bound and saves the best order seen so far.]
+
+ Description [Updates the upper bound and saves the best order seen so far.
+ Returns the current value of the upper bound.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+updateUB(
+ DdManager * table,
+ int oldBound,
+ DdHalfWord * bestOrder,
+ int lower,
+ int upper)
+{
+ int i;
+ int newBound = table->keys - table->isolated;
+
+ if (newBound < oldBound) {
+#ifdef DD_STATS
+ (void) fprintf(table->out,"New upper bound = %d\n", newBound);
+ fflush(table->out);
+#endif
+ for (i = lower; i <= upper; i++)
+ bestOrder[i-lower] = (DdHalfWord) table->invperm[i];
+ return(newBound);
+ } else {
+ return(oldBound);
+ }
+
+} /* end of updateUB */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of roots.]
+
+ Description [Counts the number of roots at the levels between lower and
+ upper. The computation is based on breadth-first search.
+ A node is a root if it is not reachable from any previously visited node.
+ (All the nodes at level lower are therefore considered roots.)
+ The visited flag uses the LSB of the next pointer. Returns the root
+ count. The roots that are constant nodes are always ignored.]
+
+ SideEffects [None]
+
+ SeeAlso [ddClearGlobal]
+
+******************************************************************************/
+static int
+ddCountRoots(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i,j;
+ DdNode *f;
+ DdNodePtr *nodelist;
+ DdNode *sentinel = &(table->sentinel);
+ int slots;
+ int roots = 0;
+ int maxlevel = lower;
+
+ for (i = lower; i <= upper; i++) {
+ nodelist = table->subtables[i].nodelist;
+ slots = table->subtables[i].slots;
+ for (j = 0; j < slots; j++) {
+ f = nodelist[j];
+ while (f != sentinel) {
+ /* A node is a root of the DAG if it cannot be
+ ** reached by nodes above it. If a node was never
+ ** reached during the previous depth-first searches,
+ ** then it is a root, and we start a new depth-first
+ ** search from it.
+ */
+ if (!Cudd_IsComplement(f->next)) {
+ if (f != table->vars[f->index]) {
+ roots++;
+ }
+ }
+ if (!Cudd_IsConstant(cuddT(f))) {
+ cuddT(f)->next = Cudd_Complement(cuddT(f)->next);
+ if (table->perm[cuddT(f)->index] > maxlevel)
+ maxlevel = table->perm[cuddT(f)->index];
+ }
+ if (!Cudd_IsConstant(cuddE(f))) {
+ Cudd_Regular(cuddE(f))->next =
+ Cudd_Complement(Cudd_Regular(cuddE(f))->next);
+ if (table->perm[Cudd_Regular(cuddE(f))->index] > maxlevel)
+ maxlevel = table->perm[Cudd_Regular(cuddE(f))->index];
+ }
+ f = Cudd_Regular(f->next);
+ }
+ }
+ }
+ ddClearGlobal(table, lower, maxlevel);
+
+ return(roots);
+
+} /* end of ddCountRoots */
+
+
+/**Function********************************************************************
+
+ Synopsis [Scans the DD and clears the LSB of the next pointers.]
+
+ Description [Scans the DD and clears the LSB of the next pointers.
+ The LSB of the next pointers are used as markers to tell whether a
+ node was reached. Once the roots are counted, these flags are
+ reset.]
+
+ SideEffects [None]
+
+ SeeAlso [ddCountRoots]
+
+******************************************************************************/
+static void
+ddClearGlobal(
+ DdManager * table,
+ int lower,
+ int maxlevel)
+{
+ int i,j;
+ DdNode *f;
+ DdNodePtr *nodelist;
+ DdNode *sentinel = &(table->sentinel);
+ int slots;
+
+ for (i = lower; i <= maxlevel; i++) {
+ nodelist = table->subtables[i].nodelist;
+ slots = table->subtables[i].slots;
+ for (j = 0; j < slots; j++) {
+ f = nodelist[j];
+ while (f != sentinel) {
+ f->next = Cudd_Regular(f->next);
+ f = f->next;
+ }
+ }
+ }
+
+} /* end of ddClearGlobal */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes a lower bound on the size of a BDD.]
+
+ Description [Computes a lower bound on the size of a BDD from the
+ following factors:
+ <ul>
+ <li> size of the lower part of it;
+ <li> size of the part of the upper part not subjected to reordering;
+ <li> number of roots in the part of the BDD subjected to reordering;
+ <li> variable in the support of the roots in the upper part of the
+ BDD subjected to reordering.
+ <ul/>]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+computeLB(
+ DdManager * table /* manager */,
+ DdHalfWord * order /* optimal order for the subset */,
+ int roots /* roots between lower and upper */,
+ int cost /* minimum cost for the subset */,
+ int lower /* lower level to be reordered */,
+ int upper /* upper level to be reordered */,
+ int level /* offset for the current top bottom var */
+ )
+{
+ int i;
+ int lb = cost;
+ int lb1 = 0;
+ int lb2;
+ int support;
+ DdHalfWord ref;
+
+ /* The levels not involved in reordering are not going to change.
+ ** Add their sizes to the lower bound.
+ */
+ for (i = 0; i < lower; i++) {
+ lb += getLevelKeys(table,i);
+ }
+ /* If a variable is in the support, then there is going
+ ** to be at least one node labeled by that variable.
+ */
+ for (i = lower; i <= lower+level; i++) {
+ support = table->subtables[i].keys > 1 ||
+ table->vars[order[i-lower]]->ref > 1;
+ lb1 += support;
+ }
+
+ /* Estimate the number of nodes required to connect the roots to
+ ** the nodes in the bottom part. */
+ if (lower+level+1 < table->size) {
+ if (lower+level < upper)
+ ref = table->vars[order[level+1]]->ref;
+ else
+ ref = table->vars[table->invperm[upper+1]]->ref;
+ lb2 = table->subtables[lower+level+1].keys -
+ (ref > (DdHalfWord) 1) - roots;
+ } else {
+ lb2 = 0;
+ }
+
+ lb += lb1 > lb2 ? lb1 : lb2;
+
+ return(lb);
+
+} /* end of computeLB */
+
+
+/**Function********************************************************************
+
+ Synopsis [Updates entry for a subset.]
+
+ Description [Updates entry for a subset. Finds the subset, if it exists.
+ If the new order for the subset has lower cost, or if the subset did not
+ exist, it stores the new order and cost. Returns the number of subsets
+ currently in the table.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+updateEntry(
+ DdManager * table,
+ DdHalfWord * order,
+ int level,
+ int cost,
+ DdHalfWord ** orders,
+ int * costs,
+ int subsets,
+ char * mask,
+ int lower,
+ int upper)
+{
+ int i, j;
+ int size = upper - lower + 1;
+
+ /* Build a mask that says what variables are in this subset. */
+ for (i = lower; i <= upper; i++)
+ mask[table->invperm[i]] = 0;
+ for (i = level; i < size; i++)
+ mask[order[i]] = 1;
+
+ /* Check each subset until a match is found or all subsets are examined. */
+ for (i = 0; i < subsets; i++) {
+ DdHalfWord *subset = orders[i];
+ for (j = level; j < size; j++) {
+ if (mask[subset[j]] == 0)
+ break;
+ }
+ if (j == size) /* no mismatches: success */
+ break;
+ }
+ if (i == subsets || cost < costs[i]) { /* add or replace */
+ for (j = 0; j < size; j++)
+ orders[i][j] = order[j];
+ costs[i] = cost;
+ subsets += (i == subsets);
+ }
+ return(subsets);
+
+} /* end of updateEntry */
+
+
+/**Function********************************************************************
+
+ Synopsis [Pushes a variable in the order down to position "level."]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+pushDown(
+ DdHalfWord * order,
+ int j,
+ int level)
+{
+ int i;
+ DdHalfWord tmp;
+
+ tmp = order[j];
+ for (i = j; i < level; i++) {
+ order[i] = order[i+1];
+ }
+ order[level] = tmp;
+ return;
+
+} /* end of pushDown */
+
+
+/**Function********************************************************************
+
+ Synopsis [Gathers symmetry information.]
+
+ Description [Translates the symmetry information stored in the next
+ field of each subtable from level to indices. This procedure is called
+ immediately after symmetric sifting, so that the next fields are correct.
+ By translating this informaton in terms of indices, we make it independent
+ of subsequent reorderings. The format used is that of the next fields:
+ a circular list where each variable points to the next variable in the
+ same symmetry group. Only the entries between lower and upper are
+ considered. The procedure returns a pointer to an array
+ holding the symmetry information if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [checkSymmInfo]
+
+******************************************************************************/
+static DdHalfWord *
+initSymmInfo(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int level, index, next, nextindex;
+ DdHalfWord *symmInfo;
+
+ symmInfo = ALLOC(DdHalfWord, table->size);
+ if (symmInfo == NULL) return(NULL);
+
+ for (level = lower; level <= upper; level++) {
+ index = table->invperm[level];
+ next = table->subtables[level].next;
+ nextindex = table->invperm[next];
+ symmInfo[index] = nextindex;
+ }
+ return(symmInfo);
+
+} /* end of initSymmInfo */
+
+
+/**Function********************************************************************
+
+ Synopsis [Check symmetry condition.]
+
+ Description [Returns 1 if a variable is the one with the highest index
+ among those belonging to a symmetry group that are in the top part of
+ the BDD. The top part is given by level.]
+
+ SideEffects [None]
+
+ SeeAlso [initSymmInfo]
+
+******************************************************************************/
+static int
+checkSymmInfo(
+ DdManager * table,
+ DdHalfWord * symmInfo,
+ int index,
+ int level)
+{
+ int i;
+
+ i = symmInfo[index];
+ while (i != index) {
+ if (index < i && table->perm[i] <= level)
+ return(0);
+ i = symmInfo[i];
+ }
+ return(1);
+
+} /* end of checkSymmInfo */
+
diff --git a/src/bdd/cudd/cuddExport.c b/src/bdd/cudd/cuddExport.c
new file mode 100644
index 00000000..d7b9645b
--- /dev/null
+++ b/src/bdd/cudd/cuddExport.c
@@ -0,0 +1,1289 @@
+/**CFile***********************************************************************
+
+ FileName [cuddExport.c]
+
+ PackageName [cudd]
+
+ Synopsis [Export functions.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_DumpBlif()
+ <li> Cudd_DumpBlifBody()
+ <li> Cudd_DumpDot()
+ <li> Cudd_DumpDaVinci()
+ <li> Cudd_DumpDDcal()
+ <li> Cudd_DumpFactoredForm()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> ddDoDumpBlif()
+ <li> ddDoDumpDaVinci()
+ <li> ddDoDumpDDcal()
+ <li> ddDoDumpFactoredForm()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddExport.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int ddDoDumpBlif ARGS((DdManager *dd, DdNode *f, FILE *fp, st_table *visited, char **names));
+static int ddDoDumpDaVinci ARGS((DdManager *dd, DdNode *f, FILE *fp, st_table *visited, char **names, long mask));
+static int ddDoDumpDDcal ARGS((DdManager *dd, DdNode *f, FILE *fp, st_table *visited, char **names, long mask));
+static int ddDoDumpFactoredForm ARGS((DdManager *dd, DdNode *f, FILE *fp, char **names));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Writes a blif file representing the argument BDDs.]
+
+ Description [Writes a blif file representing the argument BDDs as a
+ network of multiplexers. One multiplexer is written for each BDD
+ node. It returns 1 in case of success; 0 otherwise (e.g.,
+ out-of-memory, file system full, or an ADD with constants different
+ from 0 and 1). Cudd_DumpBlif does not close the file: This is the
+ caller responsibility. Cudd_DumpBlif uses a minimal unique subset of
+ the hexadecimal address of a node as name for it. If the argument
+ inames is non-null, it is assumed to hold the pointers to the names
+ of the inputs. Similarly for onames.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DumpBlifBody Cudd_DumpDot Cudd_PrintDebug Cudd_DumpDDcal
+ Cudd_DumpDaVinci Cudd_DumpFactoredForm]
+
+******************************************************************************/
+int
+Cudd_DumpBlif(
+ DdManager * dd /* manager */,
+ int n /* number of output nodes to be dumped */,
+ DdNode ** f /* array of output nodes to be dumped */,
+ char ** inames /* array of input names (or NULL) */,
+ char ** onames /* array of output names (or NULL) */,
+ char * mname /* model name (or NULL) */,
+ FILE * fp /* pointer to the dump file */)
+{
+ DdNode *support = NULL;
+ DdNode *scan;
+ int *sorted = NULL;
+ int nvars = dd->size;
+ int retval;
+ int i;
+
+ /* Build a bit array with the support of f. */
+ sorted = ALLOC(int,nvars);
+ if (sorted == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ goto failure;
+ }
+ for (i = 0; i < nvars; i++) sorted[i] = 0;
+
+ /* Take the union of the supports of each output function. */
+ support = Cudd_VectorSupport(dd,f,n);
+ if (support == NULL) goto failure;
+ cuddRef(support);
+ scan = support;
+ while (!cuddIsConstant(scan)) {
+ sorted[scan->index] = 1;
+ scan = cuddT(scan);
+ }
+ Cudd_RecursiveDeref(dd,support);
+ support = NULL; /* so that we do not try to free it in case of failure */
+
+ /* Write the header (.model .inputs .outputs). */
+ if (mname == NULL) {
+ retval = fprintf(fp,".model DD\n.inputs");
+ } else {
+ retval = fprintf(fp,".model %s\n.inputs",mname);
+ }
+ if (retval == EOF) return(0);
+
+ /* Write the input list by scanning the support array. */
+ for (i = 0; i < nvars; i++) {
+ if (sorted[i]) {
+ if (inames == NULL) {
+ retval = fprintf(fp," %d", i);
+ } else {
+ retval = fprintf(fp," %s", inames[i]);
+ }
+ if (retval == EOF) goto failure;
+ }
+ }
+ FREE(sorted);
+ sorted = NULL;
+
+ /* Write the .output line. */
+ retval = fprintf(fp,"\n.outputs");
+ if (retval == EOF) goto failure;
+ for (i = 0; i < n; i++) {
+ if (onames == NULL) {
+ retval = fprintf(fp," f%d", i);
+ } else {
+ retval = fprintf(fp," %s", onames[i]);
+ }
+ if (retval == EOF) goto failure;
+ }
+ retval = fprintf(fp,"\n");
+ if (retval == EOF) goto failure;
+
+ retval = Cudd_DumpBlifBody(dd, n, f, inames, onames, fp);
+ if (retval == 0) goto failure;
+
+ /* Write trailer and return. */
+ retval = fprintf(fp,".end\n");
+ if (retval == EOF) goto failure;
+
+ return(1);
+
+failure:
+ if (sorted != NULL) FREE(sorted);
+ if (support != NULL) Cudd_RecursiveDeref(dd,support);
+ return(0);
+
+} /* end of Cudd_DumpBlif */
+
+
+/**Function********************************************************************
+
+ Synopsis [Writes a blif body representing the argument BDDs.]
+
+ Description [Writes a blif body representing the argument BDDs as a
+ network of multiplexers. One multiplexer is written for each BDD
+ node. It returns 1 in case of success; 0 otherwise (e.g.,
+ out-of-memory, file system full, or an ADD with constants different
+ from 0 and 1). Cudd_DumpBlif does not close the file: This is the
+ caller responsibility. Cudd_DumpBlif uses a minimal unique subset of
+ the hexadecimal address of a node as name for it. If the argument
+ inames is non-null, it is assumed to hold the pointers to the names
+ of the inputs. Similarly for onames. This function prints out only
+ .names part.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DumpDot Cudd_PrintDebug Cudd_DumpDDcal
+ Cudd_DumpDaVinci Cudd_DumpFactoredForm]
+
+******************************************************************************/
+int
+Cudd_DumpBlifBody(
+ DdManager * dd /* manager */,
+ int n /* number of output nodes to be dumped */,
+ DdNode ** f /* array of output nodes to be dumped */,
+ char ** inames /* array of input names (or NULL) */,
+ char ** onames /* array of output names (or NULL) */,
+ FILE * fp /* pointer to the dump file */)
+{
+ st_table *visited = NULL;
+ int retval;
+ int i;
+
+ /* Initialize symbol table for visited nodes. */
+ visited = st_init_table(st_ptrcmp, st_ptrhash);
+ if (visited == NULL) goto failure;
+
+ /* Call the function that really gets the job done. */
+ for (i = 0; i < n; i++) {
+ retval = ddDoDumpBlif(dd,Cudd_Regular(f[i]),fp,visited,inames);
+ if (retval == 0) goto failure;
+ }
+
+ /* To account for the possible complement on the root,
+ ** we put either a buffer or an inverter at the output of
+ ** the multiplexer representing the top node.
+ */
+ for (i = 0; i < n; i++) {
+ if (onames == NULL) {
+ retval = fprintf(fp,
+#if SIZEOF_VOID_P == 8
+ ".names %lx f%d\n", (unsigned long) f[i] / (unsigned long) sizeof(DdNode), i);
+#else
+ ".names %x f%d\n", (unsigned) f[i] / (unsigned) sizeof(DdNode), i);
+#endif
+ } else {
+ retval = fprintf(fp,
+#if SIZEOF_VOID_P == 8
+ ".names %lx %s\n", (unsigned long) f[i] / (unsigned long) sizeof(DdNode), onames[i]);
+#else
+ ".names %x %s\n", (unsigned) f[i] / (unsigned) sizeof(DdNode), onames[i]);
+#endif
+ }
+ if (retval == EOF) goto failure;
+ if (Cudd_IsComplement(f[i])) {
+ retval = fprintf(fp,"0 1\n");
+ } else {
+ retval = fprintf(fp,"1 1\n");
+ }
+ if (retval == EOF) goto failure;
+ }
+
+ st_free_table(visited);
+ return(1);
+
+failure:
+ if (visited != NULL) st_free_table(visited);
+ return(0);
+
+} /* end of Cudd_DumpBlifBody */
+
+
+/**Function********************************************************************
+
+ Synopsis [Writes a dot file representing the argument DDs.]
+
+ Description [Writes a file representing the argument DDs in a format
+ suitable for the graph drawing program dot.
+ It returns 1 in case of success; 0 otherwise (e.g., out-of-memory,
+ file system full).
+ Cudd_DumpDot does not close the file: This is the caller
+ responsibility. Cudd_DumpDot uses a minimal unique subset of the
+ hexadecimal address of a node as name for it.
+ If the argument inames is non-null, it is assumed to hold the pointers
+ to the names of the inputs. Similarly for onames.
+ Cudd_DumpDot uses the following convention to draw arcs:
+ <ul>
+ <li> solid line: THEN arcs;
+ <li> dotted line: complement arcs;
+ <li> dashed line: regular ELSE arcs.
+ </ul>
+ The dot options are chosen so that the drawing fits on a letter-size
+ sheet.
+ ]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DumpBlif Cudd_PrintDebug Cudd_DumpDDcal
+ Cudd_DumpDaVinci Cudd_DumpFactoredForm]
+
+******************************************************************************/
+int
+Cudd_DumpDot(
+ DdManager * dd /* manager */,
+ int n /* number of output nodes to be dumped */,
+ DdNode ** f /* array of output nodes to be dumped */,
+ char ** inames /* array of input names (or NULL) */,
+ char ** onames /* array of output names (or NULL) */,
+ FILE * fp /* pointer to the dump file */)
+{
+ DdNode *support = NULL;
+ DdNode *scan;
+ int *sorted = NULL;
+ int nvars = dd->size;
+ st_table *visited = NULL;
+ st_generator *gen = NULL;
+ int retval;
+ int i, j;
+ int slots;
+ DdNodePtr *nodelist;
+ long refAddr, diff, mask;
+
+ /* Build a bit array with the support of f. */
+ sorted = ALLOC(int,nvars);
+ if (sorted == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ goto failure;
+ }
+ for (i = 0; i < nvars; i++) sorted[i] = 0;
+
+ /* Take the union of the supports of each output function. */
+ support = Cudd_VectorSupport(dd,f,n);
+ if (support == NULL) goto failure;
+ cuddRef(support);
+ scan = support;
+ while (!cuddIsConstant(scan)) {
+ sorted[scan->index] = 1;
+ scan = cuddT(scan);
+ }
+ Cudd_RecursiveDeref(dd,support);
+ support = NULL; /* so that we do not try to free it in case of failure */
+
+ /* Initialize symbol table for visited nodes. */
+ visited = st_init_table(st_ptrcmp, st_ptrhash);
+ if (visited == NULL) goto failure;
+
+ /* Collect all the nodes of this DD in the symbol table. */
+ for (i = 0; i < n; i++) {
+ retval = cuddCollectNodes(Cudd_Regular(f[i]),visited);
+ if (retval == 0) goto failure;
+ }
+
+ /* Find how many most significant hex digits are identical
+ ** in the addresses of all the nodes. Build a mask based
+ ** on this knowledge, so that digits that carry no information
+ ** will not be printed. This is done in two steps.
+ ** 1. We scan the symbol table to find the bits that differ
+ ** in at least 2 addresses.
+ ** 2. We choose one of the possible masks. There are 8 possible
+ ** masks for 32-bit integer, and 16 possible masks for 64-bit
+ ** integers.
+ */
+
+ /* Find the bits that are different. */
+ refAddr = (long) Cudd_Regular(f[0]);
+ diff = 0;
+ gen = st_init_gen(visited);
+ if (gen == NULL) goto failure;
+ while (st_gen(gen, (char **) &scan, NULL)) {
+ diff |= refAddr ^ (long) scan;
+ }
+ st_free_gen(gen); gen = NULL;
+
+ /* Choose the mask. */
+ for (i = 0; (unsigned) i < 8 * sizeof(long); i += 4) {
+ mask = (1 << i) - 1;
+ if (diff <= mask) break;
+ }
+
+ /* Write the header and the global attributes. */
+ retval = fprintf(fp,"digraph \"DD\" {\n");
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,
+ "size = \"7.5,10\"\ncenter = true;\nedge [dir = none];\n");
+ if (retval == EOF) return(0);
+
+ /* Write the input name subgraph by scanning the support array. */
+ retval = fprintf(fp,"{ node [shape = plaintext];\n");
+ if (retval == EOF) goto failure;
+ retval = fprintf(fp," edge [style = invis];\n");
+ if (retval == EOF) goto failure;
+ /* We use a name ("CONST NODES") with an embedded blank, because
+ ** it is unlikely to appear as an input name.
+ */
+ retval = fprintf(fp," \"CONST NODES\" [style = invis];\n");
+ if (retval == EOF) goto failure;
+ for (i = 0; i < nvars; i++) {
+ if (sorted[dd->invperm[i]]) {
+ if (inames == NULL || inames[dd->invperm[i]] == NULL) {
+ retval = fprintf(fp,"\" %d \" -> ", dd->invperm[i]);
+ } else {
+ retval = fprintf(fp,"\" %s \" -> ", inames[dd->invperm[i]]);
+ }
+ if (retval == EOF) goto failure;
+ }
+ }
+ retval = fprintf(fp,"\"CONST NODES\"; \n}\n");
+ if (retval == EOF) goto failure;
+
+ /* Write the output node subgraph. */
+ retval = fprintf(fp,"{ rank = same; node [shape = box]; edge [style = invis];\n");
+ if (retval == EOF) goto failure;
+ for (i = 0; i < n; i++) {
+ if (onames == NULL) {
+ retval = fprintf(fp,"\"F%d\"", i);
+ } else {
+ retval = fprintf(fp,"\" %s \"", onames[i]);
+ }
+ if (retval == EOF) goto failure;
+ if (i == n - 1) {
+ retval = fprintf(fp,"; }\n");
+ } else {
+ retval = fprintf(fp," -> ");
+ }
+ if (retval == EOF) goto failure;
+ }
+
+ /* Write rank info: All nodes with the same index have the same rank. */
+ for (i = 0; i < nvars; i++) {
+ if (sorted[dd->invperm[i]]) {
+ retval = fprintf(fp,"{ rank = same; ");
+ if (retval == EOF) goto failure;
+ if (inames == NULL || inames[dd->invperm[i]] == NULL) {
+ retval = fprintf(fp,"\" %d \";\n", dd->invperm[i]);
+ } else {
+ retval = fprintf(fp,"\" %s \";\n", inames[dd->invperm[i]]);
+ }
+ if (retval == EOF) goto failure;
+ nodelist = dd->subtables[i].nodelist;
+ slots = dd->subtables[i].slots;
+ for (j = 0; j < slots; j++) {
+ scan = nodelist[j];
+ while (scan != NULL) {
+ if (st_is_member(visited,(char *) scan)) {
+ retval = fprintf(fp,"\"%lx\";\n", (mask & (long) scan) / sizeof(DdNode));
+ if (retval == EOF) goto failure;
+ }
+ scan = scan->next;
+ }
+ }
+ retval = fprintf(fp,"}\n");
+ if (retval == EOF) goto failure;
+ }
+ }
+
+ /* All constants have the same rank. */
+ retval = fprintf(fp,
+ "{ rank = same; \"CONST NODES\";\n{ node [shape = box]; ");
+ if (retval == EOF) goto failure;
+ nodelist = dd->constants.nodelist;
+ slots = dd->constants.slots;
+ for (j = 0; j < slots; j++) {
+ scan = nodelist[j];
+ while (scan != NULL) {
+ if (st_is_member(visited,(char *) scan)) {
+ retval = fprintf(fp,"\"%lx\";\n", (mask & (long) scan) / sizeof(DdNode));
+ if (retval == EOF) goto failure;
+ }
+ scan = scan->next;
+ }
+ }
+ retval = fprintf(fp,"}\n}\n");
+ if (retval == EOF) goto failure;
+
+ /* Write edge info. */
+ /* Edges from the output nodes. */
+ for (i = 0; i < n; i++) {
+ if (onames == NULL) {
+ retval = fprintf(fp,"\"F%d\"", i);
+ } else {
+ retval = fprintf(fp,"\" %s \"", onames[i]);
+ }
+ if (retval == EOF) goto failure;
+ /* Account for the possible complement on the root. */
+ if (Cudd_IsComplement(f[i])) {
+ retval = fprintf(fp," -> \"%lx\" [style = dotted];\n",
+ (mask & (long) f[i]) / sizeof(DdNode));
+ } else {
+ retval = fprintf(fp," -> \"%lx\" [style = solid];\n",
+ (mask & (long) f[i]) / sizeof(DdNode));
+ }
+ if (retval == EOF) goto failure;
+ }
+
+ /* Edges from internal nodes. */
+ for (i = 0; i < nvars; i++) {
+ if (sorted[dd->invperm[i]]) {
+ nodelist = dd->subtables[i].nodelist;
+ slots = dd->subtables[i].slots;
+ for (j = 0; j < slots; j++) {
+ scan = nodelist[j];
+ while (scan != NULL) {
+ if (st_is_member(visited,(char *) scan)) {
+ retval = fprintf(fp,
+ "\"%lx\" -> \"%lx\";\n",
+ (mask & (long) scan) / sizeof(DdNode),
+ (mask & (long) cuddT(scan)) / sizeof(DdNode));
+ if (retval == EOF) goto failure;
+ if (Cudd_IsComplement(cuddE(scan))) {
+ retval = fprintf(fp,
+ "\"%lx\" -> \"%lx\" [style = dotted];\n",
+ (mask & (long) scan) / sizeof(DdNode),
+ (mask & (long) cuddE(scan)) / sizeof(DdNode));
+ } else {
+ retval = fprintf(fp,
+ "\"%lx\" -> \"%lx\" [style = dashed];\n",
+ (mask & (long) scan) / sizeof(DdNode),
+ (mask & (long) cuddE(scan)) / sizeof(DdNode));
+ }
+ if (retval == EOF) goto failure;
+ }
+ scan = scan->next;
+ }
+ }
+ }
+ }
+
+ /* Write constant labels. */
+ nodelist = dd->constants.nodelist;
+ slots = dd->constants.slots;
+ for (j = 0; j < slots; j++) {
+ scan = nodelist[j];
+ while (scan != NULL) {
+ if (st_is_member(visited,(char *) scan)) {
+ retval = fprintf(fp,"\"%lx\" [label = \"%g\"];\n",
+ (mask & (long) scan) / sizeof(DdNode), cuddV(scan));
+ if (retval == EOF) goto failure;
+ }
+ scan = scan->next;
+ }
+ }
+
+ /* Write trailer and return. */
+ retval = fprintf(fp,"}\n");
+ if (retval == EOF) goto failure;
+
+ st_free_table(visited);
+ FREE(sorted);
+ return(1);
+
+failure:
+ if (sorted != NULL) FREE(sorted);
+ if (support != NULL) Cudd_RecursiveDeref(dd,support);
+ if (visited != NULL) st_free_table(visited);
+ return(0);
+
+} /* end of Cudd_DumpDot */
+
+
+/**Function********************************************************************
+
+ Synopsis [Writes a daVinci file representing the argument BDDs.]
+
+ Description [Writes a daVinci file representing the argument BDDs.
+ It returns 1 in case of success; 0 otherwise (e.g., out-of-memory or
+ file system full). Cudd_DumpDaVinci does not close the file: This
+ is the caller responsibility. Cudd_DumpDaVinci uses a minimal unique
+ subset of the hexadecimal address of a node as name for it. If the
+ argument inames is non-null, it is assumed to hold the pointers to
+ the names of the inputs. Similarly for onames.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DumpDot Cudd_PrintDebug Cudd_DumpBlif Cudd_DumpDDcal
+ Cudd_DumpFactoredForm]
+
+******************************************************************************/
+int
+Cudd_DumpDaVinci(
+ DdManager * dd /* manager */,
+ int n /* number of output nodes to be dumped */,
+ DdNode ** f /* array of output nodes to be dumped */,
+ char ** inames /* array of input names (or NULL) */,
+ char ** onames /* array of output names (or NULL) */,
+ FILE * fp /* pointer to the dump file */)
+{
+ DdNode *support = NULL;
+ DdNode *scan;
+ st_table *visited = NULL;
+ int retval;
+ int i;
+ st_generator *gen;
+ long refAddr, diff, mask;
+
+ /* Initialize symbol table for visited nodes. */
+ visited = st_init_table(st_ptrcmp, st_ptrhash);
+ if (visited == NULL) goto failure;
+
+ /* Collect all the nodes of this DD in the symbol table. */
+ for (i = 0; i < n; i++) {
+ retval = cuddCollectNodes(Cudd_Regular(f[i]),visited);
+ if (retval == 0) goto failure;
+ }
+
+ /* Find how many most significant hex digits are identical
+ ** in the addresses of all the nodes. Build a mask based
+ ** on this knowledge, so that digits that carry no information
+ ** will not be printed. This is done in two steps.
+ ** 1. We scan the symbol table to find the bits that differ
+ ** in at least 2 addresses.
+ ** 2. We choose one of the possible masks. There are 8 possible
+ ** masks for 32-bit integer, and 16 possible masks for 64-bit
+ ** integers.
+ */
+
+ /* Find the bits that are different. */
+ refAddr = (long) Cudd_Regular(f[0]);
+ diff = 0;
+ gen = st_init_gen(visited);
+ while (st_gen(gen, (char **) &scan, NULL)) {
+ diff |= refAddr ^ (long) scan;
+ }
+ st_free_gen(gen);
+
+ /* Choose the mask. */
+ for (i = 0; (unsigned) i < 8 * sizeof(long); i += 4) {
+ mask = (1 << i) - 1;
+ if (diff <= mask) break;
+ }
+ st_free_table(visited);
+
+ /* Initialize symbol table for visited nodes. */
+ visited = st_init_table(st_ptrcmp, st_ptrhash);
+ if (visited == NULL) goto failure;
+
+ retval = fprintf(fp, "[");
+ if (retval == EOF) goto failure;
+ /* Call the function that really gets the job done. */
+ for (i = 0; i < n; i++) {
+ if (onames == NULL) {
+ retval = fprintf(fp,
+ "l(\"f%d\",n(\"root\",[a(\"OBJECT\",\"f%d\")],",
+ i,i);
+ } else {
+ retval = fprintf(fp,
+ "l(\"%s\",n(\"root\",[a(\"OBJECT\",\"%s\")],",
+ onames[i], onames[i]);
+ }
+ if (retval == EOF) goto failure;
+ retval = fprintf(fp, "[e(\"edge\",[a(\"EDGECOLOR\",\"%s\"),a(\"_DIR\",\"none\")],",
+ Cudd_IsComplement(f[i]) ? "red" : "blue");
+ if (retval == EOF) goto failure;
+ retval = ddDoDumpDaVinci(dd,Cudd_Regular(f[i]),fp,visited,inames,mask);
+ if (retval == 0) goto failure;
+ retval = fprintf(fp, ")]))%s", i == n-1 ? "" : ",");
+ if (retval == EOF) goto failure;
+ }
+
+ /* Write trailer and return. */
+ retval = fprintf(fp, "]\n");
+ if (retval == EOF) goto failure;
+
+ st_free_table(visited);
+ return(1);
+
+failure:
+ if (support != NULL) Cudd_RecursiveDeref(dd,support);
+ if (visited != NULL) st_free_table(visited);
+ return(0);
+
+} /* end of Cudd_DumpDaVinci */
+
+
+/**Function********************************************************************
+
+ Synopsis [Writes a DDcal file representing the argument BDDs.]
+
+ Description [Writes a DDcal file representing the argument BDDs.
+ It returns 1 in case of success; 0 otherwise (e.g., out-of-memory or
+ file system full). Cudd_DumpDDcal does not close the file: This
+ is the caller responsibility. Cudd_DumpDDcal uses a minimal unique
+ subset of the hexadecimal address of a node as name for it. If the
+ argument inames is non-null, it is assumed to hold the pointers to
+ the names of the inputs. Similarly for onames.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DumpDot Cudd_PrintDebug Cudd_DumpBlif Cudd_DumpDaVinci
+ Cudd_DumpFactoredForm]
+
+******************************************************************************/
+int
+Cudd_DumpDDcal(
+ DdManager * dd /* manager */,
+ int n /* number of output nodes to be dumped */,
+ DdNode ** f /* array of output nodes to be dumped */,
+ char ** inames /* array of input names (or NULL) */,
+ char ** onames /* array of output names (or NULL) */,
+ FILE * fp /* pointer to the dump file */)
+{
+ DdNode *support = NULL;
+ DdNode *scan;
+ int *sorted = NULL;
+ int nvars = dd->size;
+ st_table *visited = NULL;
+ int retval;
+ int i;
+ st_generator *gen;
+ long refAddr, diff, mask;
+
+ /* Initialize symbol table for visited nodes. */
+ visited = st_init_table(st_ptrcmp, st_ptrhash);
+ if (visited == NULL) goto failure;
+
+ /* Collect all the nodes of this DD in the symbol table. */
+ for (i = 0; i < n; i++) {
+ retval = cuddCollectNodes(Cudd_Regular(f[i]),visited);
+ if (retval == 0) goto failure;
+ }
+
+ /* Find how many most significant hex digits are identical
+ ** in the addresses of all the nodes. Build a mask based
+ ** on this knowledge, so that digits that carry no information
+ ** will not be printed. This is done in two steps.
+ ** 1. We scan the symbol table to find the bits that differ
+ ** in at least 2 addresses.
+ ** 2. We choose one of the possible masks. There are 8 possible
+ ** masks for 32-bit integer, and 16 possible masks for 64-bit
+ ** integers.
+ */
+
+ /* Find the bits that are different. */
+ refAddr = (long) Cudd_Regular(f[0]);
+ diff = 0;
+ gen = st_init_gen(visited);
+ while (st_gen(gen, (char **) &scan, NULL)) {
+ diff |= refAddr ^ (long) scan;
+ }
+ st_free_gen(gen);
+
+ /* Choose the mask. */
+ for (i = 0; (unsigned) i < 8 * sizeof(long); i += 4) {
+ mask = (1 << i) - 1;
+ if (diff <= mask) break;
+ }
+ st_free_table(visited);
+
+ /* Build a bit array with the support of f. */
+ sorted = ALLOC(int,nvars);
+ if (sorted == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ goto failure;
+ }
+ for (i = 0; i < nvars; i++) sorted[i] = 0;
+
+ /* Take the union of the supports of each output function. */
+ support = Cudd_VectorSupport(dd,f,n);
+ if (support == NULL) goto failure;
+ cuddRef(support);
+ scan = support;
+ while (!cuddIsConstant(scan)) {
+ sorted[scan->index] = 1;
+ scan = cuddT(scan);
+ }
+ Cudd_RecursiveDeref(dd,support);
+ support = NULL; /* so that we do not try to free it in case of failure */
+ for (i = 0; i < nvars; i++) {
+ if (sorted[dd->invperm[i]]) {
+ if (inames == NULL || inames[dd->invperm[i]] == NULL) {
+ retval = fprintf(fp,"v%d", dd->invperm[i]);
+ } else {
+ retval = fprintf(fp,"%s", inames[dd->invperm[i]]);
+ }
+ if (retval == EOF) goto failure;
+ }
+ retval = fprintf(fp,"%s", i == nvars - 1 ? "\n" : " * ");
+ if (retval == EOF) goto failure;
+ }
+ FREE(sorted);
+ sorted = NULL;
+
+ /* Initialize symbol table for visited nodes. */
+ visited = st_init_table(st_ptrcmp, st_ptrhash);
+ if (visited == NULL) goto failure;
+
+ /* Call the function that really gets the job done. */
+ for (i = 0; i < n; i++) {
+ retval = ddDoDumpDDcal(dd,Cudd_Regular(f[i]),fp,visited,inames,mask);
+ if (retval == 0) goto failure;
+ if (onames == NULL) {
+ retval = fprintf(fp, "f%d = ", i);
+ } else {
+ retval = fprintf(fp, "%s = ", onames[i]);
+ }
+ if (retval == EOF) goto failure;
+ retval = fprintf(fp, "n%lx%s\n",
+ ((long) f[i] & mask) / sizeof(DdNode),
+ Cudd_IsComplement(f[i]) ? "'" : "");
+ if (retval == EOF) goto failure;
+ }
+
+ /* Write trailer and return. */
+ retval = fprintf(fp, "[");
+ if (retval == EOF) goto failure;
+ for (i = 0; i < n; i++) {
+ if (onames == NULL) {
+ retval = fprintf(fp, "f%d", i);
+ } else {
+ retval = fprintf(fp, "%s", onames[i]);
+ }
+ retval = fprintf(fp, "%s", i == n-1 ? "" : " ");
+ if (retval == EOF) goto failure;
+ }
+ retval = fprintf(fp, "]\n");
+ if (retval == EOF) goto failure;
+
+ st_free_table(visited);
+ return(1);
+
+failure:
+ if (sorted != NULL) FREE(sorted);
+ if (support != NULL) Cudd_RecursiveDeref(dd,support);
+ if (visited != NULL) st_free_table(visited);
+ return(0);
+
+} /* end of Cudd_DumpDDcal */
+
+
+/**Function********************************************************************
+
+ Synopsis [Writes factored forms representing the argument BDDs.]
+
+ Description [Writes factored forms representing the argument BDDs.
+ The format of the factored form is the one used in the genlib files
+ for technology mapping in sis. It returns 1 in case of success; 0
+ otherwise (e.g., file system full). Cudd_DumpFactoredForm does not
+ close the file: This is the caller responsibility. Caution must be
+ exercised because a factored form may be exponentially larger than
+ the argument BDD. If the argument inames is non-null, it is assumed
+ to hold the pointers to the names of the inputs. Similarly for
+ onames.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DumpDot Cudd_PrintDebug Cudd_DumpBlif Cudd_DumpDaVinci
+ Cudd_DumpDDcal]
+
+******************************************************************************/
+int
+Cudd_DumpFactoredForm(
+ DdManager * dd /* manager */,
+ int n /* number of output nodes to be dumped */,
+ DdNode ** f /* array of output nodes to be dumped */,
+ char ** inames /* array of input names (or NULL) */,
+ char ** onames /* array of output names (or NULL) */,
+ FILE * fp /* pointer to the dump file */)
+{
+ int retval;
+ int i;
+
+ /* Call the function that really gets the job done. */
+ for (i = 0; i < n; i++) {
+ if (onames == NULL) {
+ retval = fprintf(fp, "f%d = ", i);
+ } else {
+ retval = fprintf(fp, "%s = ", onames[i]);
+ }
+ if (retval == EOF) return(0);
+ if (f[i] == DD_ONE(dd)) {
+ retval = fprintf(fp, "CONST1");
+ if (retval == EOF) return(0);
+ } else if (f[i] == Cudd_Not(DD_ONE(dd)) || f[i] == DD_ZERO(dd)) {
+ retval = fprintf(fp, "CONST0");
+ if (retval == EOF) return(0);
+ } else {
+ retval = fprintf(fp, "%s", Cudd_IsComplement(f[i]) ? "!(" : "");
+ if (retval == EOF) return(0);
+ retval = ddDoDumpFactoredForm(dd,Cudd_Regular(f[i]),fp,inames);
+ if (retval == 0) return(0);
+ retval = fprintf(fp, "%s", Cudd_IsComplement(f[i]) ? ")" : "");
+ if (retval == EOF) return(0);
+ }
+ retval = fprintf(fp, "%s", i == n-1 ? "" : "\n");
+ if (retval == EOF) return(0);
+ }
+
+ return(1);
+
+} /* end of Cudd_DumpFactoredForm */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_DumpBlif.]
+
+ Description [Performs the recursive step of Cudd_DumpBlif. Traverses
+ the BDD f and writes a multiplexer-network description to the file
+ pointed by fp in blif format. f is assumed to be a regular pointer
+ and ddDoDumpBlif guarantees this assumption in the recursive calls.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddDoDumpBlif(
+ DdManager * dd,
+ DdNode * f,
+ FILE * fp,
+ st_table * visited,
+ char ** names)
+{
+ DdNode *T, *E;
+ int retval;
+
+#ifdef DD_DEBUG
+ assert(!Cudd_IsComplement(f));
+#endif
+
+ /* If already visited, nothing to do. */
+ if (st_is_member(visited, (char *) f) == 1)
+ return(1);
+
+ /* Check for abnormal condition that should never happen. */
+ if (f == NULL)
+ return(0);
+
+ /* Mark node as visited. */
+ if (st_insert(visited, (char *) f, NULL) == ST_OUT_OF_MEM)
+ return(0);
+
+ /* Check for special case: If constant node, generate constant 1. */
+ if (f == DD_ONE(dd)) {
+#if SIZEOF_VOID_P == 8
+ retval = fprintf(fp, ".names %lx\n1\n",(unsigned long) f / (unsigned long) sizeof(DdNode));
+#else
+ retval = fprintf(fp, ".names %x\n1\n",(unsigned) f / (unsigned) sizeof(DdNode));
+#endif
+ if (retval == EOF) {
+ return(0);
+ } else {
+ return(1);
+ }
+ }
+
+ /* Check whether this is an ADD. We deal with 0-1 ADDs, but not
+ ** with the general case.
+ */
+ if (f == DD_ZERO(dd)) {
+#if SIZEOF_VOID_P == 8
+ retval = fprintf(fp, ".names %lx\n",(unsigned long) f / (unsigned long) sizeof(DdNode));
+#else
+ retval = fprintf(fp, ".names %x\n",(unsigned) f / (unsigned) sizeof(DdNode));
+#endif
+ if (retval == EOF) {
+ return(0);
+ } else {
+ return(1);
+ }
+ }
+ if (cuddIsConstant(f))
+ return(0);
+
+ /* Recursive calls. */
+ T = cuddT(f);
+ retval = ddDoDumpBlif(dd,T,fp,visited,names);
+ if (retval != 1) return(retval);
+ E = Cudd_Regular(cuddE(f));
+ retval = ddDoDumpBlif(dd,E,fp,visited,names);
+ if (retval != 1) return(retval);
+
+ /* Write multiplexer taking complement arc into account. */
+ if (names != NULL) {
+ retval = fprintf(fp,".names %s", names[f->index]);
+ } else {
+ retval = fprintf(fp,".names %d", f->index);
+ }
+ if (retval == EOF)
+ return(0);
+
+#if SIZEOF_VOID_P == 8
+ if (Cudd_IsComplement(cuddE(f))) {
+ retval = fprintf(fp," %lx %lx %lx\n11- 1\n0-0 1\n",
+ (unsigned long) T / (unsigned long) sizeof(DdNode),
+ (unsigned long) E / (unsigned long) sizeof(DdNode),
+ (unsigned long) f / (unsigned long) sizeof(DdNode));
+ } else {
+ retval = fprintf(fp," %lx %lx %lx\n11- 1\n0-1 1\n",
+ (unsigned long) T / (unsigned long) sizeof(DdNode),
+ (unsigned long) E / (unsigned long) sizeof(DdNode),
+ (unsigned long) f / (unsigned long) sizeof(DdNode));
+ }
+#else
+ if (Cudd_IsComplement(cuddE(f))) {
+ retval = fprintf(fp," %x %x %x\n11- 1\n0-0 1\n",
+ (unsigned) T / (unsigned) sizeof(DdNode),
+ (unsigned) E / (unsigned) sizeof(DdNode),
+ (unsigned) f / (unsigned) sizeof(DdNode));
+ } else {
+ retval = fprintf(fp," %x %x %x\n11- 1\n0-1 1\n",
+ (unsigned) T / (unsigned) sizeof(DdNode),
+ (unsigned) E / (unsigned) sizeof(DdNode),
+ (unsigned) f / (unsigned) sizeof(DdNode));
+ }
+#endif
+ if (retval == EOF) {
+ return(0);
+ } else {
+ return(1);
+ }
+
+} /* end of ddDoDumpBlif */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_DumpDaVinci.]
+
+ Description [Performs the recursive step of Cudd_DumpDaVinci. Traverses
+ the BDD f and writes a term expression to the file
+ pointed by fp in daVinci format. f is assumed to be a regular pointer
+ and ddDoDumpDaVinci guarantees this assumption in the recursive calls.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddDoDumpDaVinci(
+ DdManager * dd,
+ DdNode * f,
+ FILE * fp,
+ st_table * visited,
+ char ** names,
+ long mask)
+{
+ DdNode *T, *E;
+ int retval;
+ long id;
+
+#ifdef DD_DEBUG
+ assert(!Cudd_IsComplement(f));
+#endif
+
+ id = ((long) f & mask) / sizeof(DdNode);
+
+ /* If already visited, insert a reference. */
+ if (st_is_member(visited, (char *) f) == 1) {
+ retval = fprintf(fp,"r(\"%lx\")", id);
+ if (retval == EOF) {
+ return(0);
+ } else {
+ return(1);
+ }
+ }
+
+ /* Check for abnormal condition that should never happen. */
+ if (f == NULL)
+ return(0);
+
+ /* Mark node as visited. */
+ if (st_insert(visited, (char *) f, NULL) == ST_OUT_OF_MEM)
+ return(0);
+
+ /* Check for special case: If constant node, generate constant 1. */
+ if (Cudd_IsConstant(f)) {
+ retval = fprintf(fp, "l(\"%lx\",n(\"constant\",[a(\"OBJECT\",\"%g\")],[]))", id, cuddV(f));
+ if (retval == EOF) {
+ return(0);
+ } else {
+ return(1);
+ }
+ }
+
+ /* Recursive calls. */
+ if (names != NULL) {
+ retval = fprintf(fp,
+ "l(\"%lx\",n(\"internal\",[a(\"OBJECT\",\"%s\"),",
+ id, names[f->index]);
+ } else {
+ retval = fprintf(fp,
+ "l(\"%lx\",n(\"internal\",[a(\"OBJECT\",\"%d\"),",
+ id, f->index);
+ }
+ retval = fprintf(fp, "a(\"_GO\",\"ellipse\")],[e(\"then\",[a(\"EDGECOLOR\",\"blue\"),a(\"_DIR\",\"none\")],");
+ if (retval == EOF) return(0);
+ T = cuddT(f);
+ retval = ddDoDumpDaVinci(dd,T,fp,visited,names,mask);
+ if (retval != 1) return(retval);
+ retval = fprintf(fp, "),e(\"else\",[a(\"EDGECOLOR\",\"%s\"),a(\"_DIR\",\"none\")],",
+ Cudd_IsComplement(cuddE(f)) ? "red" : "green");
+ if (retval == EOF) return(0);
+ E = Cudd_Regular(cuddE(f));
+ retval = ddDoDumpDaVinci(dd,E,fp,visited,names,mask);
+ if (retval != 1) return(retval);
+
+ retval = fprintf(fp,")]))");
+ if (retval == EOF) {
+ return(0);
+ } else {
+ return(1);
+ }
+
+} /* end of ddDoDumpDaVinci */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_DumpDDcal.]
+
+ Description [Performs the recursive step of Cudd_DumpDDcal. Traverses
+ the BDD f and writes a line for each node to the file
+ pointed by fp in DDcal format. f is assumed to be a regular pointer
+ and ddDoDumpDDcal guarantees this assumption in the recursive calls.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddDoDumpDDcal(
+ DdManager * dd,
+ DdNode * f,
+ FILE * fp,
+ st_table * visited,
+ char ** names,
+ long mask)
+{
+ DdNode *T, *E;
+ int retval;
+ long id, idT, idE;
+
+#ifdef DD_DEBUG
+ assert(!Cudd_IsComplement(f));
+#endif
+
+ id = ((long) f & mask) / sizeof(DdNode);
+
+ /* If already visited, do nothing. */
+ if (st_is_member(visited, (char *) f) == 1) {
+ return(1);
+ }
+
+ /* Check for abnormal condition that should never happen. */
+ if (f == NULL)
+ return(0);
+
+ /* Mark node as visited. */
+ if (st_insert(visited, (char *) f, NULL) == ST_OUT_OF_MEM)
+ return(0);
+
+ /* Check for special case: If constant node, assign constant. */
+ if (Cudd_IsConstant(f)) {
+ if (f != DD_ONE(dd) && f != DD_ZERO(dd))
+ return(0);
+ retval = fprintf(fp, "n%lx = %g\n", id, cuddV(f));
+ if (retval == EOF) {
+ return(0);
+ } else {
+ return(1);
+ }
+ }
+
+ /* Recursive calls. */
+ T = cuddT(f);
+ retval = ddDoDumpDDcal(dd,T,fp,visited,names,mask);
+ if (retval != 1) return(retval);
+ E = Cudd_Regular(cuddE(f));
+ retval = ddDoDumpDDcal(dd,E,fp,visited,names,mask);
+ if (retval != 1) return(retval);
+ idT = ((long) T & mask) / sizeof(DdNode);
+ idE = ((long) E & mask) / sizeof(DdNode);
+ if (names != NULL) {
+ retval = fprintf(fp, "n%lx = %s * n%lx + %s' * n%lx%s\n",
+ id, names[f->index], idT, names[f->index],
+ idE, Cudd_IsComplement(cuddE(f)) ? "'" : "");
+ } else {
+ retval = fprintf(fp, "n%lx = v%d * n%lx + v%d' * n%lx%s\n",
+ id, f->index, idT, f->index,
+ idE, Cudd_IsComplement(cuddE(f)) ? "'" : "");
+ }
+ if (retval == EOF) {
+ return(0);
+ } else {
+ return(1);
+ }
+
+} /* end of ddDoDumpDDcal */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_DumpFactoredForm.]
+
+ Description [Performs the recursive step of
+ Cudd_DumpFactoredForm. Traverses the BDD f and writes a factored
+ form for each node to the file pointed by fp in terms of the
+ factored forms of the children. Constants are propagated, and
+ absorption is applied. f is assumed to be a regular pointer and
+ ddDoDumpFActoredForm guarantees this assumption in the recursive
+ calls.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DumpFactoredForm]
+
+******************************************************************************/
+static int
+ddDoDumpFactoredForm(
+ DdManager * dd,
+ DdNode * f,
+ FILE * fp,
+ char ** names)
+{
+ DdNode *T, *E;
+ int retval;
+
+#ifdef DD_DEBUG
+ assert(!Cudd_IsComplement(f));
+ assert(!Cudd_IsConstant(f));
+#endif
+
+ /* Check for abnormal condition that should never happen. */
+ if (f == NULL)
+ return(0);
+
+ /* Recursive calls. */
+ T = cuddT(f);
+ E = cuddE(f);
+ if (T != DD_ZERO(dd)) {
+ if (E != DD_ONE(dd)) {
+ if (names != NULL) {
+ retval = fprintf(fp, "%s", names[f->index]);
+ } else {
+ retval = fprintf(fp, "x%d", f->index);
+ }
+ if (retval == EOF) return(0);
+ }
+ if (T != DD_ONE(dd)) {
+ retval = fprintf(fp, "%s(", E != DD_ONE(dd) ? " * " : "");
+ if (retval == EOF) return(0);
+ retval = ddDoDumpFactoredForm(dd,T,fp,names);
+ if (retval != 1) return(retval);
+ retval = fprintf(fp, ")");
+ if (retval == EOF) return(0);
+ }
+ if (E == Cudd_Not(DD_ONE(dd)) || E == DD_ZERO(dd)) return(1);
+ retval = fprintf(fp, " + ");
+ if (retval == EOF) return(0);
+ }
+ E = Cudd_Regular(E);
+ if (T != DD_ONE(dd)) {
+ if (names != NULL) {
+ retval = fprintf(fp, "!%s", names[f->index]);
+ } else {
+ retval = fprintf(fp, "!x%d", f->index);
+ }
+ if (retval == EOF) return(0);
+ }
+ if (E != DD_ONE(dd)) {
+ retval = fprintf(fp, "%s%s(", T != DD_ONE(dd) ? " * " : "",
+ E != cuddE(f) ? "!" : "");
+ if (retval == EOF) return(0);
+ retval = ddDoDumpFactoredForm(dd,E,fp,names);
+ if (retval != 1) return(retval);
+ retval = fprintf(fp, ")");
+ if (retval == EOF) return(0);
+ }
+ return(1);
+
+} /* end of ddDoDumpFactoredForm */
+
diff --git a/src/bdd/cudd/cuddGenCof.c b/src/bdd/cudd/cuddGenCof.c
new file mode 100644
index 00000000..59ae55d7
--- /dev/null
+++ b/src/bdd/cudd/cuddGenCof.c
@@ -0,0 +1,1968 @@
+/**CFile***********************************************************************
+
+ FileName [cuddGenCof.c]
+
+ PackageName [cudd]
+
+ Synopsis [Generalized cofactors for BDDs and ADDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_bddConstrain()
+ <li> Cudd_bddRestrict()
+ <li> Cudd_addConstrain()
+ <li> Cudd_bddConstrainDecomp()
+ <li> Cudd_addRestrict()
+ <li> Cudd_bddCharToVect()
+ <li> Cudd_bddLICompaction()
+ <li> Cudd_bddSqueeze()
+ <li> Cudd_SubsetCompress()
+ <li> Cudd_SupersetCompress()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddBddConstrainRecur()
+ <li> cuddBddRestrictRecur()
+ <li> cuddAddConstrainRecur()
+ <li> cuddAddRestrictRecur()
+ <li> cuddBddLICompaction()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddBddConstrainDecomp()
+ <li> cuddBddCharToVect()
+ <li> cuddBddLICMarkEdges()
+ <li> cuddBddLICBuildResult()
+ <li> cuddBddSqueeze()
+ </ul>
+ ]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/* Codes for edge markings in Cudd_bddLICompaction. The codes are defined
+** so that they can be bitwise ORed to implement the code priority scheme.
+*/
+#define DD_LIC_DC 0
+#define DD_LIC_1 1
+#define DD_LIC_0 2
+#define DD_LIC_NL 3
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/* Key for the cache used in the edge marking phase. */
+typedef struct MarkCacheKey {
+ DdNode *f;
+ DdNode *c;
+} MarkCacheKey;
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddGenCof.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int cuddBddConstrainDecomp ARGS((DdManager *dd, DdNode *f, DdNode **decomp));
+static DdNode * cuddBddCharToVect ARGS((DdManager *dd, DdNode *f, DdNode *x));
+static int cuddBddLICMarkEdges ARGS((DdManager *dd, DdNode *f, DdNode *c, st_table *table, st_table *cache));
+static DdNode * cuddBddLICBuildResult ARGS((DdManager *dd, DdNode *f, st_table *cache, st_table *table));
+static int MarkCacheHash ARGS((char *ptr, int modulus));
+static int MarkCacheCompare ARGS((const char *ptr1, const char *ptr2));
+static enum st_retval MarkCacheCleanUp ARGS((char *key, char *value, char *arg));
+static DdNode * cuddBddSqueeze ARGS((DdManager *dd, DdNode *l, DdNode *u));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes f constrain c.]
+
+ Description [Computes f constrain c (f @ c).
+ Uses a canonical form: (f' @ c) = ( f @ c)'. (Note: this is not true
+ for c.) List of special cases:
+ <ul>
+ <li> f @ 0 = 0
+ <li> f @ 1 = f
+ <li> 0 @ c = 0
+ <li> 1 @ c = 1
+ <li> f @ f = 1
+ <li> f @ f'= 0
+ </ul>
+ Returns a pointer to the result if successful; NULL otherwise. Note that if
+ F=(f1,...,fn) and reordering takes place while computing F @ c, then the
+ image restriction property (Img(F,c) = Img(F @ c)) is lost.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddRestrict Cudd_addConstrain]
+
+******************************************************************************/
+DdNode *
+Cudd_bddConstrain(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddConstrainRecur(dd,f,c);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddConstrain */
+
+
+/**Function********************************************************************
+
+ Synopsis [BDD restrict according to Coudert and Madre's algorithm
+ (ICCAD90).]
+
+ Description [BDD restrict according to Coudert and Madre's algorithm
+ (ICCAD90). Returns the restricted BDD if successful; otherwise NULL.
+ If application of restrict results in a BDD larger than the input
+ BDD, the input BDD is returned.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddConstrain Cudd_addRestrict]
+
+******************************************************************************/
+DdNode *
+Cudd_bddRestrict(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *suppF, *suppC, *commonSupport;
+ DdNode *cplus, *res;
+ int retval;
+ int sizeF, sizeRes;
+
+ /* Check terminal cases here to avoid computing supports in trivial cases.
+ ** This also allows us notto check later for the case c == 0, in which
+ ** there is no common support. */
+ if (c == Cudd_Not(DD_ONE(dd))) return(Cudd_Not(DD_ONE(dd)));
+ if (Cudd_IsConstant(f)) return(f);
+ if (f == c) return(DD_ONE(dd));
+ if (f == Cudd_Not(c)) return(Cudd_Not(DD_ONE(dd)));
+
+ /* Check if supports intersect. */
+ retval = Cudd_ClassifySupport(dd,f,c,&commonSupport,&suppF,&suppC);
+ if (retval == 0) {
+ return(NULL);
+ }
+ cuddRef(commonSupport); cuddRef(suppF); cuddRef(suppC);
+ Cudd_IterDerefBdd(dd,suppF);
+
+ if (commonSupport == DD_ONE(dd)) {
+ Cudd_IterDerefBdd(dd,commonSupport);
+ Cudd_IterDerefBdd(dd,suppC);
+ return(f);
+ }
+ Cudd_IterDerefBdd(dd,commonSupport);
+
+ /* Abstract from c the variables that do not appear in f. */
+ cplus = Cudd_bddExistAbstract(dd, c, suppC);
+ if (cplus == NULL) {
+ Cudd_IterDerefBdd(dd,suppC);
+ return(NULL);
+ }
+ cuddRef(cplus);
+ Cudd_IterDerefBdd(dd,suppC);
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddRestrictRecur(dd, f, cplus);
+ } while (dd->reordered == 1);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(dd,cplus);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_IterDerefBdd(dd,cplus);
+ /* Make restric safe by returning the smaller of the input and the
+ ** result. */
+ sizeF = Cudd_DagSize(f);
+ sizeRes = Cudd_DagSize(res);
+ if (sizeF <= sizeRes) {
+ Cudd_IterDerefBdd(dd, res);
+ return(f);
+ } else {
+ cuddDeref(res);
+ return(res);
+ }
+
+} /* end of Cudd_bddRestrict */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes f constrain c for ADDs.]
+
+ Description [Computes f constrain c (f @ c), for f an ADD and c a 0-1
+ ADD. List of special cases:
+ <ul>
+ <li> F @ 0 = 0
+ <li> F @ 1 = F
+ <li> 0 @ c = 0
+ <li> 1 @ c = 1
+ <li> F @ F = 1
+ </ul>
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddConstrain]
+
+******************************************************************************/
+DdNode *
+Cudd_addConstrain(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddAddConstrainRecur(dd,f,c);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addConstrain */
+
+
+/**Function********************************************************************
+
+ Synopsis [BDD conjunctive decomposition as in McMillan's CAV96 paper.]
+
+ Description [BDD conjunctive decomposition as in McMillan's CAV96
+ paper. The decomposition is canonical only for a given variable
+ order. If canonicity is required, variable ordering must be disabled
+ after the decomposition has been computed. Returns an array with one
+ entry for each BDD variable in the manager if successful; otherwise
+ NULL. The components of the solution have their reference counts
+ already incremented (unlike the results of most other functions in
+ the package.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddConstrain Cudd_bddExistAbstract]
+
+******************************************************************************/
+DdNode **
+Cudd_bddConstrainDecomp(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode **decomp;
+ int res;
+ int i;
+
+ /* Create an initialize decomposition array. */
+ decomp = ALLOC(DdNode *,dd->size);
+ if (decomp == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < dd->size; i++) {
+ decomp[i] = NULL;
+ }
+ do {
+ dd->reordered = 0;
+ /* Clean up the decomposition array in case reordering took place. */
+ for (i = 0; i < dd->size; i++) {
+ if (decomp[i] != NULL) {
+ Cudd_IterDerefBdd(dd, decomp[i]);
+ decomp[i] = NULL;
+ }
+ }
+ res = cuddBddConstrainDecomp(dd,f,decomp);
+ } while (dd->reordered == 1);
+ if (res == 0) {
+ FREE(decomp);
+ return(NULL);
+ }
+ /* Missing components are constant ones. */
+ for (i = 0; i < dd->size; i++) {
+ if (decomp[i] == NULL) {
+ decomp[i] = DD_ONE(dd);
+ cuddRef(decomp[i]);
+ }
+ }
+ return(decomp);
+
+} /* end of Cudd_bddConstrainDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [ADD restrict according to Coudert and Madre's algorithm
+ (ICCAD90).]
+
+ Description [ADD restrict according to Coudert and Madre's algorithm
+ (ICCAD90). Returns the restricted ADD if successful; otherwise NULL.
+ If application of restrict results in an ADD larger than the input
+ ADD, the input ADD is returned.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addConstrain Cudd_bddRestrict]
+
+******************************************************************************/
+DdNode *
+Cudd_addRestrict(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *supp_f, *supp_c;
+ DdNode *res, *commonSupport;
+ int intersection;
+ int sizeF, sizeRes;
+
+ /* Check if supports intersect. */
+ supp_f = Cudd_Support(dd, f);
+ if (supp_f == NULL) {
+ return(NULL);
+ }
+ cuddRef(supp_f);
+ supp_c = Cudd_Support(dd, c);
+ if (supp_c == NULL) {
+ Cudd_RecursiveDeref(dd,supp_f);
+ return(NULL);
+ }
+ cuddRef(supp_c);
+ commonSupport = Cudd_bddLiteralSetIntersection(dd, supp_f, supp_c);
+ if (commonSupport == NULL) {
+ Cudd_RecursiveDeref(dd,supp_f);
+ Cudd_RecursiveDeref(dd,supp_c);
+ return(NULL);
+ }
+ cuddRef(commonSupport);
+ Cudd_RecursiveDeref(dd,supp_f);
+ Cudd_RecursiveDeref(dd,supp_c);
+ intersection = commonSupport != DD_ONE(dd);
+ Cudd_RecursiveDeref(dd,commonSupport);
+
+ if (intersection) {
+ do {
+ dd->reordered = 0;
+ res = cuddAddRestrictRecur(dd, f, c);
+ } while (dd->reordered == 1);
+ sizeF = Cudd_DagSize(f);
+ sizeRes = Cudd_DagSize(res);
+ if (sizeF <= sizeRes) {
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, res);
+ return(f);
+ } else {
+ return(res);
+ }
+ } else {
+ return(f);
+ }
+
+} /* end of Cudd_addRestrict */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes a vector whose image equals a non-zero function.]
+
+ Description [Computes a vector of BDDs whose image equals a non-zero
+ function.
+ The result depends on the variable order. The i-th component of the vector
+ depends only on the first i variables in the order. Each BDD in the vector
+ is not larger than the BDD of the given characteristic function. This
+ function is based on the description of char-to-vect in "Verification of
+ Sequential Machines Using Boolean Functional Vectors" by O. Coudert, C.
+ Berthet and J. C. Madre.
+ Returns a pointer to an array containing the result if successful; NULL
+ otherwise. The size of the array equals the number of variables in the
+ manager. The components of the solution have their reference counts
+ already incremented (unlike the results of most other functions in
+ the package.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddConstrain]
+
+******************************************************************************/
+DdNode **
+Cudd_bddCharToVect(
+ DdManager * dd,
+ DdNode * f)
+{
+ int i, j;
+ DdNode **vect;
+ DdNode *res = NULL;
+
+ if (f == Cudd_Not(DD_ONE(dd))) return(NULL);
+
+ vect = ALLOC(DdNode *, dd->size);
+ if (vect == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ do {
+ dd->reordered = 0;
+ for (i = 0; i < dd->size; i++) {
+ res = cuddBddCharToVect(dd,f,dd->vars[dd->invperm[i]]);
+ if (res == NULL) {
+ /* Clean up the vector array in case reordering took place. */
+ for (j = 0; j < i; j++) {
+ Cudd_IterDerefBdd(dd, vect[dd->invperm[j]]);
+ }
+ break;
+ }
+ cuddRef(res);
+ vect[dd->invperm[i]] = res;
+ }
+ } while (dd->reordered == 1);
+ if (res == NULL) {
+ FREE(vect);
+ return(NULL);
+ }
+ return(vect);
+
+} /* end of Cudd_bddCharToVect */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs safe minimization of a BDD.]
+
+ Description [Performs safe minimization of a BDD. Given the BDD
+ <code>f</code> of a function to be minimized and a BDD
+ <code>c</code> representing the care set, Cudd_bddLICompaction
+ produces the BDD of a function that agrees with <code>f</code>
+ wherever <code>c</code> is 1. Safe minimization means that the size
+ of the result is guaranteed not to exceed the size of
+ <code>f</code>. This function is based on the DAC97 paper by Hong et
+ al.. Returns a pointer to the result if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddRestrict]
+
+******************************************************************************/
+DdNode *
+Cudd_bddLICompaction(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be minimized */,
+ DdNode * c /* constraint (care set) */)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddLICompaction(dd,f,c);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddLICompaction */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds a small BDD in a function interval.]
+
+ Description [Finds a small BDD in a function interval. Given BDDs
+ <code>l</code> and <code>u</code>, representing the lower bound and
+ upper bound of a function interval, Cudd_bddSqueeze produces the BDD
+ of a function within the interval with a small BDD. Returns a
+ pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddRestrict Cudd_bddLICompaction]
+
+******************************************************************************/
+DdNode *
+Cudd_bddSqueeze(
+ DdManager * dd /* manager */,
+ DdNode * l /* lower bound */,
+ DdNode * u /* upper bound */)
+{
+ DdNode *res;
+ int sizeRes, sizeL, sizeU;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddSqueeze(dd,l,u);
+ } while (dd->reordered == 1);
+ if (res == NULL) return(NULL);
+ /* We now compare the result with the bounds and return the smallest.
+ ** We first compare to u, so that in case l == 0 and u == 1, we return
+ ** 0 as in other minimization algorithms. */
+ sizeRes = Cudd_DagSize(res);
+ sizeU = Cudd_DagSize(u);
+ if (sizeU <= sizeRes) {
+ cuddRef(res);
+ Cudd_IterDerefBdd(dd,res);
+ res = u;
+ sizeRes = sizeU;
+ }
+ sizeL = Cudd_DagSize(l);
+ if (sizeL <= sizeRes) {
+ cuddRef(res);
+ Cudd_IterDerefBdd(dd,res);
+ res = l;
+ sizeRes = sizeL;
+ }
+ return(res);
+
+} /* end of Cudd_bddSqueeze */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds a small BDD that agrees with <code>f</code> over
+ <code>c</code>.]
+
+ Description [Finds a small BDD that agrees with <code>f</code> over
+ <code>c</code>. Returns a pointer to the result if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddRestrict Cudd_bddLICompaction Cudd_bddSqueeze]
+
+******************************************************************************/
+DdNode *
+Cudd_bddMinimize(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *cplus, *res;
+
+ if (c == Cudd_Not(DD_ONE(dd))) return(c);
+ if (Cudd_IsConstant(f)) return(f);
+ if (f == c) return(DD_ONE(dd));
+ if (f == Cudd_Not(c)) return(Cudd_Not(DD_ONE(dd)));
+
+ cplus = Cudd_RemapOverApprox(dd,c,0,0,1.0);
+ if (cplus == NULL) return(NULL);
+ cuddRef(cplus);
+ res = Cudd_bddLICompaction(dd,f,cplus);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(dd,cplus);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_IterDerefBdd(dd,cplus);
+ cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_bddMinimize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Find a dense subset of BDD <code>f</code>.]
+
+ Description [Finds a dense subset of BDD <code>f</code>. Density is
+ the ratio of number of minterms to number of nodes. Uses several
+ techniques in series. It is more expensive than other subsetting
+ procedures, but often produces better results. See
+ Cudd_SubsetShortPaths for a description of the threshold and nvars
+ parameters. Returns a pointer to the result if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SubsetRemap Cudd_SubsetShortPaths Cudd_SubsetHeavyBranch
+ Cudd_bddSqueeze]
+
+******************************************************************************/
+DdNode *
+Cudd_SubsetCompress(
+ DdManager * dd /* manager */,
+ DdNode * f /* BDD whose subset is sought */,
+ int nvars /* number of variables in the support of f */,
+ int threshold /* maximum number of nodes in the subset */)
+{
+ DdNode *res, *tmp1, *tmp2;
+
+ tmp1 = Cudd_SubsetShortPaths(dd, f, nvars, threshold, 0);
+ if (tmp1 == NULL) return(NULL);
+ cuddRef(tmp1);
+ tmp2 = Cudd_RemapUnderApprox(dd,tmp1,nvars,0,1.0);
+ if (tmp2 == NULL) {
+ Cudd_IterDerefBdd(dd,tmp1);
+ return(NULL);
+ }
+ cuddRef(tmp2);
+ Cudd_IterDerefBdd(dd,tmp1);
+ res = Cudd_bddSqueeze(dd,tmp2,f);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(dd,tmp2);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_IterDerefBdd(dd,tmp2);
+ cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_SubsetCompress */
+
+
+/**Function********************************************************************
+
+ Synopsis [Find a dense superset of BDD <code>f</code>.]
+
+ Description [Finds a dense superset of BDD <code>f</code>. Density is
+ the ratio of number of minterms to number of nodes. Uses several
+ techniques in series. It is more expensive than other supersetting
+ procedures, but often produces better results. See
+ Cudd_SupersetShortPaths for a description of the threshold and nvars
+ parameters. Returns a pointer to the result if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SubsetCompress Cudd_SupersetRemap Cudd_SupersetShortPaths
+ Cudd_SupersetHeavyBranch Cudd_bddSqueeze]
+
+******************************************************************************/
+DdNode *
+Cudd_SupersetCompress(
+ DdManager * dd /* manager */,
+ DdNode * f /* BDD whose superset is sought */,
+ int nvars /* number of variables in the support of f */,
+ int threshold /* maximum number of nodes in the superset */)
+{
+ DdNode *subset;
+
+ subset = Cudd_SubsetCompress(dd, Cudd_Not(f),nvars,threshold);
+
+ return(Cudd_NotCond(subset, (subset != NULL)));
+
+} /* end of Cudd_SupersetCompress */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddConstrain.]
+
+ Description [Performs the recursive step of Cudd_bddConstrain.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddConstrain]
+
+******************************************************************************/
+DdNode *
+cuddBddConstrainRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *Fv, *Fnv, *Cv, *Cnv, *t, *e, *r;
+ DdNode *one, *zero;
+ unsigned int topf, topc;
+ int index;
+ int comple = 0;
+
+ statLine(dd);
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ /* Trivial cases. */
+ if (c == one) return(f);
+ if (c == zero) return(zero);
+ if (Cudd_IsConstant(f)) return(f);
+ if (f == c) return(one);
+ if (f == Cudd_Not(c)) return(zero);
+
+ /* Make canonical to increase the utilization of the cache. */
+ if (Cudd_IsComplement(f)) {
+ f = Cudd_Not(f);
+ comple = 1;
+ }
+ /* Now f is a regular pointer to a non-constant node; c is also
+ ** non-constant, but may be complemented.
+ */
+
+ /* Check the cache. */
+ r = cuddCacheLookup2(dd, Cudd_bddConstrain, f, c);
+ if (r != NULL) {
+ return(Cudd_NotCond(r,comple));
+ }
+
+ /* Recursive step. */
+ topf = dd->perm[f->index];
+ topc = dd->perm[Cudd_Regular(c)->index];
+ if (topf <= topc) {
+ index = f->index;
+ Fv = cuddT(f); Fnv = cuddE(f);
+ } else {
+ index = Cudd_Regular(c)->index;
+ Fv = Fnv = f;
+ }
+ if (topc <= topf) {
+ Cv = cuddT(Cudd_Regular(c)); Cnv = cuddE(Cudd_Regular(c));
+ if (Cudd_IsComplement(c)) {
+ Cv = Cudd_Not(Cv);
+ Cnv = Cudd_Not(Cnv);
+ }
+ } else {
+ Cv = Cnv = c;
+ }
+
+ if (!Cudd_IsConstant(Cv)) {
+ t = cuddBddConstrainRecur(dd, Fv, Cv);
+ if (t == NULL)
+ return(NULL);
+ } else if (Cv == one) {
+ t = Fv;
+ } else { /* Cv == zero: return Fnv @ Cnv */
+ if (Cnv == one) {
+ r = Fnv;
+ } else {
+ r = cuddBddConstrainRecur(dd, Fnv, Cnv);
+ if (r == NULL)
+ return(NULL);
+ }
+ return(Cudd_NotCond(r,comple));
+ }
+ cuddRef(t);
+
+ if (!Cudd_IsConstant(Cnv)) {
+ e = cuddBddConstrainRecur(dd, Fnv, Cnv);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ } else if (Cnv == one) {
+ e = Fnv;
+ } else { /* Cnv == zero: return Fv @ Cv previously computed */
+ cuddDeref(t);
+ return(Cudd_NotCond(t,comple));
+ }
+ cuddRef(e);
+
+ if (Cudd_IsComplement(t)) {
+ t = Cudd_Not(t);
+ e = Cudd_Not(e);
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ cuddCacheInsert2(dd, Cudd_bddConstrain, f, c, r);
+ return(Cudd_NotCond(r,comple));
+
+} /* end of cuddBddConstrainRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddRestrict.]
+
+ Description [Performs the recursive step of Cudd_bddRestrict.
+ Returns the restricted BDD if successful; otherwise NULL.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddRestrict]
+
+******************************************************************************/
+DdNode *
+cuddBddRestrictRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *Fv, *Fnv, *Cv, *Cnv, *t, *e, *r, *one, *zero;
+ unsigned int topf, topc;
+ int index;
+ int comple = 0;
+
+ statLine(dd);
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ /* Trivial cases */
+ if (c == one) return(f);
+ if (c == zero) return(zero);
+ if (Cudd_IsConstant(f)) return(f);
+ if (f == c) return(one);
+ if (f == Cudd_Not(c)) return(zero);
+
+ /* Make canonical to increase the utilization of the cache. */
+ if (Cudd_IsComplement(f)) {
+ f = Cudd_Not(f);
+ comple = 1;
+ }
+ /* Now f is a regular pointer to a non-constant node; c is also
+ ** non-constant, but may be complemented.
+ */
+
+ /* Check the cache. */
+ r = cuddCacheLookup2(dd, Cudd_bddRestrict, f, c);
+ if (r != NULL) {
+ return(Cudd_NotCond(r,comple));
+ }
+
+ topf = dd->perm[f->index];
+ topc = dd->perm[Cudd_Regular(c)->index];
+
+ if (topc < topf) { /* abstract top variable from c */
+ DdNode *d, *s1, *s2;
+
+ /* Find complements of cofactors of c. */
+ if (Cudd_IsComplement(c)) {
+ s1 = cuddT(Cudd_Regular(c));
+ s2 = cuddE(Cudd_Regular(c));
+ } else {
+ s1 = Cudd_Not(cuddT(c));
+ s2 = Cudd_Not(cuddE(c));
+ }
+ /* Take the OR by applying DeMorgan. */
+ d = cuddBddAndRecur(dd, s1, s2);
+ if (d == NULL) return(NULL);
+ d = Cudd_Not(d);
+ cuddRef(d);
+ r = cuddBddRestrictRecur(dd, f, d);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, d);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_IterDerefBdd(dd, d);
+ cuddCacheInsert2(dd, Cudd_bddRestrict, f, c, r);
+ cuddDeref(r);
+ return(Cudd_NotCond(r,comple));
+ }
+
+ /* Recursive step. Here topf <= topc. */
+ index = f->index;
+ Fv = cuddT(f); Fnv = cuddE(f);
+ if (topc == topf) {
+ Cv = cuddT(Cudd_Regular(c)); Cnv = cuddE(Cudd_Regular(c));
+ if (Cudd_IsComplement(c)) {
+ Cv = Cudd_Not(Cv);
+ Cnv = Cudd_Not(Cnv);
+ }
+ } else {
+ Cv = Cnv = c;
+ }
+
+ if (!Cudd_IsConstant(Cv)) {
+ t = cuddBddRestrictRecur(dd, Fv, Cv);
+ if (t == NULL) return(NULL);
+ } else if (Cv == one) {
+ t = Fv;
+ } else { /* Cv == zero: return(Fnv @ Cnv) */
+ if (Cnv == one) {
+ r = Fnv;
+ } else {
+ r = cuddBddRestrictRecur(dd, Fnv, Cnv);
+ if (r == NULL) return(NULL);
+ }
+ return(Cudd_NotCond(r,comple));
+ }
+ cuddRef(t);
+
+ if (!Cudd_IsConstant(Cnv)) {
+ e = cuddBddRestrictRecur(dd, Fnv, Cnv);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ } else if (Cnv == one) {
+ e = Fnv;
+ } else { /* Cnv == zero: return (Fv @ Cv) previously computed */
+ cuddDeref(t);
+ return(Cudd_NotCond(t,comple));
+ }
+ cuddRef(e);
+
+ if (Cudd_IsComplement(t)) {
+ t = Cudd_Not(t);
+ e = Cudd_Not(e);
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ cuddCacheInsert2(dd, Cudd_bddRestrict, f, c, r);
+ return(Cudd_NotCond(r,comple));
+
+} /* end of cuddBddRestrictRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addConstrain.]
+
+ Description [Performs the recursive step of Cudd_addConstrain.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addConstrain]
+
+******************************************************************************/
+DdNode *
+cuddAddConstrainRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *Fv, *Fnv, *Cv, *Cnv, *t, *e, *r;
+ DdNode *one, *zero;
+ unsigned int topf, topc;
+ int index;
+
+ statLine(dd);
+ one = DD_ONE(dd);
+ zero = DD_ZERO(dd);
+
+ /* Trivial cases. */
+ if (c == one) return(f);
+ if (c == zero) return(zero);
+ if (Cudd_IsConstant(f)) return(f);
+ if (f == c) return(one);
+
+ /* Now f and c are non-constant. */
+
+ /* Check the cache. */
+ r = cuddCacheLookup2(dd, Cudd_addConstrain, f, c);
+ if (r != NULL) {
+ return(r);
+ }
+
+ /* Recursive step. */
+ topf = dd->perm[f->index];
+ topc = dd->perm[c->index];
+ if (topf <= topc) {
+ index = f->index;
+ Fv = cuddT(f); Fnv = cuddE(f);
+ } else {
+ index = c->index;
+ Fv = Fnv = f;
+ }
+ if (topc <= topf) {
+ Cv = cuddT(c); Cnv = cuddE(c);
+ } else {
+ Cv = Cnv = c;
+ }
+
+ if (!Cudd_IsConstant(Cv)) {
+ t = cuddAddConstrainRecur(dd, Fv, Cv);
+ if (t == NULL)
+ return(NULL);
+ } else if (Cv == one) {
+ t = Fv;
+ } else { /* Cv == zero: return Fnv @ Cnv */
+ if (Cnv == one) {
+ r = Fnv;
+ } else {
+ r = cuddAddConstrainRecur(dd, Fnv, Cnv);
+ if (r == NULL)
+ return(NULL);
+ }
+ return(r);
+ }
+ cuddRef(t);
+
+ if (!Cudd_IsConstant(Cnv)) {
+ e = cuddAddConstrainRecur(dd, Fnv, Cnv);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ } else if (Cnv == one) {
+ e = Fnv;
+ } else { /* Cnv == zero: return Fv @ Cv previously computed */
+ cuddDeref(t);
+ return(t);
+ }
+ cuddRef(e);
+
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, e);
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ cuddCacheInsert2(dd, Cudd_addConstrain, f, c, r);
+ return(r);
+
+} /* end of cuddAddConstrainRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addRestrict.]
+
+ Description [Performs the recursive step of Cudd_addRestrict.
+ Returns the restricted ADD if successful; otherwise NULL.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addRestrict]
+
+******************************************************************************/
+DdNode *
+cuddAddRestrictRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *Fv, *Fnv, *Cv, *Cnv, *t, *e, *r, *one, *zero;
+ unsigned int topf, topc;
+ int index;
+
+ statLine(dd);
+ one = DD_ONE(dd);
+ zero = DD_ZERO(dd);
+
+ /* Trivial cases */
+ if (c == one) return(f);
+ if (c == zero) return(zero);
+ if (Cudd_IsConstant(f)) return(f);
+ if (f == c) return(one);
+
+ /* Now f and c are non-constant. */
+
+ /* Check the cache. */
+ r = cuddCacheLookup2(dd, Cudd_addRestrict, f, c);
+ if (r != NULL) {
+ return(r);
+ }
+
+ topf = dd->perm[f->index];
+ topc = dd->perm[c->index];
+
+ if (topc < topf) { /* abstract top variable from c */
+ DdNode *d, *s1, *s2;
+
+ /* Find cofactors of c. */
+ s1 = cuddT(c);
+ s2 = cuddE(c);
+ /* Take the OR by applying DeMorgan. */
+ d = cuddAddApplyRecur(dd, Cudd_addOr, s1, s2);
+ if (d == NULL) return(NULL);
+ cuddRef(d);
+ r = cuddAddRestrictRecur(dd, f, d);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, d);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_RecursiveDeref(dd, d);
+ cuddCacheInsert2(dd, Cudd_addRestrict, f, c, r);
+ cuddDeref(r);
+ return(r);
+ }
+
+ /* Recursive step. Here topf <= topc. */
+ index = f->index;
+ Fv = cuddT(f); Fnv = cuddE(f);
+ if (topc == topf) {
+ Cv = cuddT(c); Cnv = cuddE(c);
+ } else {
+ Cv = Cnv = c;
+ }
+
+ if (!Cudd_IsConstant(Cv)) {
+ t = cuddAddRestrictRecur(dd, Fv, Cv);
+ if (t == NULL) return(NULL);
+ } else if (Cv == one) {
+ t = Fv;
+ } else { /* Cv == zero: return(Fnv @ Cnv) */
+ if (Cnv == one) {
+ r = Fnv;
+ } else {
+ r = cuddAddRestrictRecur(dd, Fnv, Cnv);
+ if (r == NULL) return(NULL);
+ }
+ return(r);
+ }
+ cuddRef(t);
+
+ if (!Cudd_IsConstant(Cnv)) {
+ e = cuddAddRestrictRecur(dd, Fnv, Cnv);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ } else if (Cnv == one) {
+ e = Fnv;
+ } else { /* Cnv == zero: return (Fv @ Cv) previously computed */
+ cuddDeref(t);
+ return(t);
+ }
+ cuddRef(e);
+
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, e);
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ cuddCacheInsert2(dd, Cudd_addRestrict, f, c, r);
+ return(r);
+
+} /* end of cuddAddRestrictRecur */
+
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs safe minimization of a BDD.]
+
+ Description [Performs safe minimization of a BDD. Given the BDD
+ <code>f</code> of a function to be minimized and a BDD
+ <code>c</code> representing the care set, Cudd_bddLICompaction
+ produces the BDD of a function that agrees with <code>f</code>
+ wherever <code>c</code> is 1. Safe minimization means that the size
+ of the result is guaranteed not to exceed the size of
+ <code>f</code>. This function is based on the DAC97 paper by Hong et
+ al.. Returns a pointer to the result if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLICompaction]
+
+******************************************************************************/
+DdNode *
+cuddBddLICompaction(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be minimized */,
+ DdNode * c /* constraint (care set) */)
+{
+ st_table *marktable, *markcache, *buildcache;
+ DdNode *res, *zero;
+
+ zero = Cudd_Not(DD_ONE(dd));
+ if (c == zero) return(zero);
+
+ /* We need to use local caches for both steps of this operation.
+ ** The results of the edge marking step are only valid as long as the
+ ** edge markings themselves are available. However, the edge markings
+ ** are lost at the end of one invocation of Cudd_bddLICompaction.
+ ** Hence, the cache entries for the edge marking step must be
+ ** invalidated at the end of this function.
+ ** For the result of the building step we argue as follows. The result
+ ** for a node and a given constrain depends on the BDD in which the node
+ ** appears. Hence, the same node and constrain may give different results
+ ** in successive invocations.
+ */
+ marktable = st_init_table(st_ptrcmp,st_ptrhash);
+ if (marktable == NULL) {
+ return(NULL);
+ }
+ markcache = st_init_table(MarkCacheCompare,MarkCacheHash);
+ if (markcache == NULL) {
+ st_free_table(marktable);
+ return(NULL);
+ }
+ if (cuddBddLICMarkEdges(dd,f,c,marktable,markcache) == CUDD_OUT_OF_MEM) {
+ st_foreach(markcache, MarkCacheCleanUp, NULL);
+ st_free_table(marktable);
+ st_free_table(markcache);
+ return(NULL);
+ }
+ st_foreach(markcache, MarkCacheCleanUp, NULL);
+ st_free_table(markcache);
+ buildcache = st_init_table(st_ptrcmp,st_ptrhash);
+ if (buildcache == NULL) {
+ st_free_table(marktable);
+ return(NULL);
+ }
+ res = cuddBddLICBuildResult(dd,f,buildcache,marktable);
+ st_free_table(buildcache);
+ st_free_table(marktable);
+ return(res);
+
+} /* end of cuddBddLICompaction */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddConstrainDecomp.]
+
+ Description [Performs the recursive step of Cudd_bddConstrainDecomp.
+ Returns f super (i) if successful; otherwise NULL.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddConstrainDecomp]
+
+******************************************************************************/
+static int
+cuddBddConstrainDecomp(
+ DdManager * dd,
+ DdNode * f,
+ DdNode ** decomp)
+{
+ DdNode *F, *fv, *fvn;
+ DdNode *fAbs;
+ DdNode *result;
+ int ok;
+
+ if (Cudd_IsConstant(f)) return(1);
+ /* Compute complements of cofactors. */
+ F = Cudd_Regular(f);
+ fv = cuddT(F);
+ fvn = cuddE(F);
+ if (F == f) {
+ fv = Cudd_Not(fv);
+ fvn = Cudd_Not(fvn);
+ }
+ /* Compute abstraction of top variable. */
+ fAbs = cuddBddAndRecur(dd, fv, fvn);
+ if (fAbs == NULL) {
+ return(0);
+ }
+ cuddRef(fAbs);
+ fAbs = Cudd_Not(fAbs);
+ /* Recursively find the next abstraction and the components of the
+ ** decomposition. */
+ ok = cuddBddConstrainDecomp(dd, fAbs, decomp);
+ if (ok == 0) {
+ Cudd_IterDerefBdd(dd,fAbs);
+ return(0);
+ }
+ /* Compute the component of the decomposition corresponding to the
+ ** top variable and store it in the decomposition array. */
+ result = cuddBddConstrainRecur(dd, f, fAbs);
+ if (result == NULL) {
+ Cudd_IterDerefBdd(dd,fAbs);
+ return(0);
+ }
+ cuddRef(result);
+ decomp[F->index] = result;
+ Cudd_IterDerefBdd(dd, fAbs);
+ return(1);
+
+} /* end of cuddBddConstrainDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddCharToVect.]
+
+ Description [Performs the recursive step of Cudd_bddCharToVect.
+ This function maintains the invariant that f is non-zero.
+ Returns the i-th component of the vector if successful; otherwise NULL.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddCharToVect]
+
+******************************************************************************/
+static DdNode *
+cuddBddCharToVect(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * x)
+{
+ unsigned int topf;
+ unsigned int level;
+ int comple;
+
+ DdNode *one, *zero, *res, *F, *fT, *fE, *T, *E;
+
+ statLine(dd);
+ /* Check the cache. */
+ res = cuddCacheLookup2(dd, cuddBddCharToVect, f, x);
+ if (res != NULL) {
+ return(res);
+ }
+
+ F = Cudd_Regular(f);
+
+ topf = cuddI(dd,F->index);
+ level = dd->perm[x->index];
+
+ if (topf > level) return(x);
+
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ comple = F != f;
+ fT = Cudd_NotCond(cuddT(F),comple);
+ fE = Cudd_NotCond(cuddE(F),comple);
+
+ if (topf == level) {
+ if (fT == zero) return(zero);
+ if (fE == zero) return(one);
+ return(x);
+ }
+
+ /* Here topf < level. */
+ if (fT == zero) return(cuddBddCharToVect(dd, fE, x));
+ if (fE == zero) return(cuddBddCharToVect(dd, fT, x));
+
+ T = cuddBddCharToVect(dd, fT, x);
+ if (T == NULL) {
+ return(NULL);
+ }
+ cuddRef(T);
+ E = cuddBddCharToVect(dd, fE, x);
+ if (E == NULL) {
+ Cudd_IterDerefBdd(dd,T);
+ return(NULL);
+ }
+ cuddRef(E);
+ res = cuddBddIteRecur(dd, dd->vars[F->index], T, E);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(dd,T);
+ Cudd_IterDerefBdd(dd,E);
+ return(NULL);
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+ cuddCacheInsert2(dd, cuddBddCharToVect, f, x, res);
+ return(res);
+
+} /* end of cuddBddCharToVect */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the edge marking step of Cudd_bddLICompaction.]
+
+ Description [Performs the edge marking step of Cudd_bddLICompaction.
+ Returns the LUB of the markings of the two outgoing edges of <code>f</code>
+ if successful; otherwise CUDD_OUT_OF_MEM.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLICompaction cuddBddLICBuildResult]
+
+******************************************************************************/
+static int
+cuddBddLICMarkEdges(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c,
+ st_table * table,
+ st_table * cache)
+{
+ DdNode *Fv, *Fnv, *Cv, *Cnv;
+ DdNode *one, *zero;
+ unsigned int topf, topc;
+ int index;
+ int comple;
+ int resT, resE, res, retval;
+ char **slot;
+ MarkCacheKey *key;
+
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ /* Terminal cases. */
+ if (c == zero) return(DD_LIC_DC);
+ if (f == one) return(DD_LIC_1);
+ if (f == zero) return(DD_LIC_0);
+
+ /* Make canonical to increase the utilization of the cache. */
+ comple = Cudd_IsComplement(f);
+ f = Cudd_Regular(f);
+ /* Now f is a regular pointer to a non-constant node; c may be
+ ** constant, or it may be complemented.
+ */
+
+ /* Check the cache. */
+ key = ALLOC(MarkCacheKey, 1);
+ if (key == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(CUDD_OUT_OF_MEM);
+ }
+ key->f = f; key->c = c;
+ if (st_lookup(cache, (char *)key, (char **)&res)) {
+ FREE(key);
+ if (comple) {
+ if (res == DD_LIC_0) res = DD_LIC_1;
+ else if (res == DD_LIC_1) res = DD_LIC_0;
+ }
+ return(res);
+ }
+
+ /* Recursive step. */
+ topf = dd->perm[f->index];
+ topc = cuddI(dd,Cudd_Regular(c)->index);
+ if (topf <= topc) {
+ index = f->index;
+ Fv = cuddT(f); Fnv = cuddE(f);
+ } else {
+ index = Cudd_Regular(c)->index;
+ Fv = Fnv = f;
+ }
+ if (topc <= topf) {
+ /* We know that c is not constant because f is not. */
+ Cv = cuddT(Cudd_Regular(c)); Cnv = cuddE(Cudd_Regular(c));
+ if (Cudd_IsComplement(c)) {
+ Cv = Cudd_Not(Cv);
+ Cnv = Cudd_Not(Cnv);
+ }
+ } else {
+ Cv = Cnv = c;
+ }
+
+ resT = cuddBddLICMarkEdges(dd, Fv, Cv, table, cache);
+ if (resT == CUDD_OUT_OF_MEM) {
+ FREE(key);
+ return(CUDD_OUT_OF_MEM);
+ }
+ resE = cuddBddLICMarkEdges(dd, Fnv, Cnv, table, cache);
+ if (resE == CUDD_OUT_OF_MEM) {
+ FREE(key);
+ return(CUDD_OUT_OF_MEM);
+ }
+
+ /* Update edge markings. */
+ if (topf <= topc) {
+ retval = st_find_or_add(table, (char *)f, (char ***)&slot);
+ if (retval == 0) {
+ *slot = (char *) (ptrint)((resT << 2) | resE);
+ } else if (retval == 1) {
+ *slot = (char *) (ptrint)((int)((ptrint) *slot) | (resT << 2) | resE);
+ } else {
+ FREE(key);
+ return(CUDD_OUT_OF_MEM);
+ }
+ }
+
+ /* Cache result. */
+ res = resT | resE;
+ if (st_insert(cache, (char *)key, (char *)(ptrint)res) == ST_OUT_OF_MEM) {
+ FREE(key);
+ return(CUDD_OUT_OF_MEM);
+ }
+
+ /* Take into account possible complementation. */
+ if (comple) {
+ if (res == DD_LIC_0) res = DD_LIC_1;
+ else if (res == DD_LIC_1) res = DD_LIC_0;
+ }
+ return(res);
+
+} /* end of cuddBddLICMarkEdges */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds the result of Cudd_bddLICompaction.]
+
+ Description [Builds the results of Cudd_bddLICompaction.
+ Returns a pointer to the minimized BDD if successful; otherwise NULL.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLICompaction cuddBddLICMarkEdges]
+
+******************************************************************************/
+static DdNode *
+cuddBddLICBuildResult(
+ DdManager * dd,
+ DdNode * f,
+ st_table * cache,
+ st_table * table)
+{
+ DdNode *Fv, *Fnv, *r, *t, *e;
+ DdNode *one, *zero;
+ unsigned int topf;
+ int index;
+ int comple;
+ int markT, markE, markings;
+
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ if (Cudd_IsConstant(f)) return(f);
+ /* Make canonical to increase the utilization of the cache. */
+ comple = Cudd_IsComplement(f);
+ f = Cudd_Regular(f);
+
+ /* Check the cache. */
+ if (st_lookup(cache, (char *)f, (char **)&r)) {
+ return(Cudd_NotCond(r,comple));
+ }
+
+ /* Retrieve the edge markings. */
+ if (st_lookup(table, (char *)f, (char **)&markings) == 0)
+ return(NULL);
+ markT = markings >> 2;
+ markE = markings & 3;
+
+ topf = dd->perm[f->index];
+ index = f->index;
+ Fv = cuddT(f); Fnv = cuddE(f);
+
+ if (markT == DD_LIC_NL) {
+ t = cuddBddLICBuildResult(dd,Fv,cache,table);
+ if (t == NULL) {
+ return(NULL);
+ }
+ } else if (markT == DD_LIC_1) {
+ t = one;
+ } else {
+ t = zero;
+ }
+ cuddRef(t);
+ if (markE == DD_LIC_NL) {
+ e = cuddBddLICBuildResult(dd,Fnv,cache,table);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(dd,t);
+ return(NULL);
+ }
+ } else if (markE == DD_LIC_1) {
+ e = one;
+ } else {
+ e = zero;
+ }
+ cuddRef(e);
+
+ if (markT == DD_LIC_DC && markE != DD_LIC_DC) {
+ r = e;
+ } else if (markT != DD_LIC_DC && markE == DD_LIC_DC) {
+ r = t;
+ } else {
+ if (Cudd_IsComplement(t)) {
+ t = Cudd_Not(t);
+ e = Cudd_Not(e);
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ }
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ if (st_insert(cache, (char *)f, (char *)r) == ST_OUT_OF_MEM) {
+ cuddRef(r);
+ Cudd_IterDerefBdd(dd,r);
+ return(NULL);
+ }
+
+ return(Cudd_NotCond(r,comple));
+
+} /* end of cuddBddLICBuildResult */
+
+
+/**Function********************************************************************
+
+ Synopsis [Hash function for the computed table of cuddBddLICMarkEdges.]
+
+ Description [Hash function for the computed table of
+ cuddBddLICMarkEdges. Returns the bucket number.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLICompaction]
+
+******************************************************************************/
+static int
+MarkCacheHash(
+ char * ptr,
+ int modulus)
+{
+ int val = 0;
+ MarkCacheKey *entry;
+
+ entry = (MarkCacheKey *) ptr;
+
+ val = (int) (ptrint) entry->f;
+ val = val * 997 + (int) (ptrint) entry->c;
+
+ return ((val < 0) ? -val : val) % modulus;
+
+} /* end of MarkCacheHash */
+
+
+/**Function********************************************************************
+
+ Synopsis [Comparison function for the computed table of
+ cuddBddLICMarkEdges.]
+
+ Description [Comparison function for the computed table of
+ cuddBddLICMarkEdges. Returns 0 if the two nodes of the key are equal; 1
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLICompaction]
+
+******************************************************************************/
+static int
+MarkCacheCompare(
+ const char * ptr1,
+ const char * ptr2)
+{
+ MarkCacheKey *entry1, *entry2;
+
+ entry1 = (MarkCacheKey *) ptr1;
+ entry2 = (MarkCacheKey *) ptr2;
+
+ return((entry1->f != entry2->f) || (entry1->c != entry2->c));
+
+} /* end of MarkCacheCompare */
+
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees memory associated with computed table of
+ cuddBddLICMarkEdges.]
+
+ Description [Frees memory associated with computed table of
+ cuddBddLICMarkEdges. Returns ST_CONTINUE.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLICompaction]
+
+******************************************************************************/
+static enum st_retval
+MarkCacheCleanUp(
+ char * key,
+ char * value,
+ char * arg)
+{
+ MarkCacheKey *entry;
+
+ entry = (MarkCacheKey *) key;
+ FREE(entry);
+ return ST_CONTINUE;
+
+} /* end of MarkCacheCleanUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddSqueeze.]
+
+ Description [Performs the recursive step of Cudd_bddSqueeze. This
+ procedure exploits the fact that if we complement and swap the
+ bounds of the interval we obtain a valid solution by taking the
+ complement of the solution to the original problem. Therefore, we
+ can enforce the condition that the upper bound is always regular.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddSqueeze]
+
+******************************************************************************/
+static DdNode *
+cuddBddSqueeze(
+ DdManager * dd,
+ DdNode * l,
+ DdNode * u)
+{
+ DdNode *one, *zero, *r, *lt, *le, *ut, *ue, *t, *e;
+#if 0
+ DdNode *ar;
+#endif
+ int comple = 0;
+ unsigned int topu, topl;
+ int index;
+
+ statLine(dd);
+ if (l == u) {
+ return(l);
+ }
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+ /* The only case when l == zero && u == one is at the top level,
+ ** where returning either one or zero is OK. In all other cases
+ ** the procedure will detect such a case and will perform
+ ** remapping. Therefore the order in which we test l and u at this
+ ** point is immaterial. */
+ if (l == zero) return(l);
+ if (u == one) return(u);
+
+ /* Make canonical to increase the utilization of the cache. */
+ if (Cudd_IsComplement(u)) {
+ DdNode *temp;
+ temp = Cudd_Not(l);
+ l = Cudd_Not(u);
+ u = temp;
+ comple = 1;
+ }
+ /* At this point u is regular and non-constant; l is non-constant, but
+ ** may be complemented. */
+
+ /* Here we could check the relative sizes. */
+
+ /* Check the cache. */
+ r = cuddCacheLookup2(dd, Cudd_bddSqueeze, l, u);
+ if (r != NULL) {
+ return(Cudd_NotCond(r,comple));
+ }
+
+ /* Recursive step. */
+ topu = dd->perm[u->index];
+ topl = dd->perm[Cudd_Regular(l)->index];
+ if (topu <= topl) {
+ index = u->index;
+ ut = cuddT(u); ue = cuddE(u);
+ } else {
+ index = Cudd_Regular(l)->index;
+ ut = ue = u;
+ }
+ if (topl <= topu) {
+ lt = cuddT(Cudd_Regular(l)); le = cuddE(Cudd_Regular(l));
+ if (Cudd_IsComplement(l)) {
+ lt = Cudd_Not(lt);
+ le = Cudd_Not(le);
+ }
+ } else {
+ lt = le = l;
+ }
+
+ /* If one interval is contained in the other, use the smaller
+ ** interval. This corresponds to one-sided matching. */
+ if ((lt == zero || Cudd_bddLeq(dd,lt,le)) &&
+ (ut == one || Cudd_bddLeq(dd,ue,ut))) { /* remap */
+ r = cuddBddSqueeze(dd, le, ue);
+ if (r == NULL)
+ return(NULL);
+ return(Cudd_NotCond(r,comple));
+ } else if ((le == zero || Cudd_bddLeq(dd,le,lt)) &&
+ (ue == one || Cudd_bddLeq(dd,ut,ue))) { /* remap */
+ r = cuddBddSqueeze(dd, lt, ut);
+ if (r == NULL)
+ return(NULL);
+ return(Cudd_NotCond(r,comple));
+ } else if ((le == zero || Cudd_bddLeq(dd,le,Cudd_Not(ut))) &&
+ (ue == one || Cudd_bddLeq(dd,Cudd_Not(lt),ue))) { /* c-remap */
+ t = cuddBddSqueeze(dd, lt, ut);
+ cuddRef(t);
+ if (Cudd_IsComplement(t)) {
+ r = cuddUniqueInter(dd, index, Cudd_Not(t), t);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = cuddUniqueInter(dd, index, t, Cudd_Not(t));
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ }
+ cuddDeref(t);
+ if (r == NULL)
+ return(NULL);
+ cuddCacheInsert2(dd, Cudd_bddSqueeze, l, u, r);
+ return(Cudd_NotCond(r,comple));
+ } else if ((lt == zero || Cudd_bddLeq(dd,lt,Cudd_Not(ue))) &&
+ (ut == one || Cudd_bddLeq(dd,Cudd_Not(le),ut))) { /* c-remap */
+ e = cuddBddSqueeze(dd, le, ue);
+ cuddRef(e);
+ if (Cudd_IsComplement(e)) {
+ r = cuddUniqueInter(dd, index, Cudd_Not(e), e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ return(NULL);
+ }
+ } else {
+ r = cuddUniqueInter(dd, index, e, Cudd_Not(e));
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ }
+ cuddDeref(e);
+ if (r == NULL)
+ return(NULL);
+ cuddCacheInsert2(dd, Cudd_bddSqueeze, l, u, r);
+ return(Cudd_NotCond(r,comple));
+ }
+
+#if 0
+ /* If the two intervals intersect, take a solution from
+ ** the intersection of the intervals. This guarantees that the
+ ** splitting variable will not appear in the result.
+ ** This approach corresponds to two-sided matching, and is very
+ ** expensive. */
+ if (Cudd_bddLeq(dd,lt,ue) && Cudd_bddLeq(dd,le,ut)) {
+ DdNode *au, *al;
+ au = cuddBddAndRecur(dd,ut,ue);
+ if (au == NULL)
+ return(NULL);
+ cuddRef(au);
+ al = cuddBddAndRecur(dd,Cudd_Not(lt),Cudd_Not(le));
+ if (al == NULL) {
+ Cudd_IterDerefBdd(dd,au);
+ return(NULL);
+ }
+ cuddRef(al);
+ al = Cudd_Not(al);
+ ar = cuddBddSqueeze(dd, al, au);
+ if (ar == NULL) {
+ Cudd_IterDerefBdd(dd,au);
+ Cudd_IterDerefBdd(dd,al);
+ return(NULL);
+ }
+ cuddRef(ar);
+ Cudd_IterDerefBdd(dd,au);
+ Cudd_IterDerefBdd(dd,al);
+ } else {
+ ar = NULL;
+ }
+#endif
+
+ t = cuddBddSqueeze(dd, lt, ut);
+ if (t == NULL) {
+ return(NULL);
+ }
+ cuddRef(t);
+ e = cuddBddSqueeze(dd, le, ue);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(dd,t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ if (Cudd_IsComplement(t)) {
+ t = Cudd_Not(t);
+ e = Cudd_Not(e);
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+#if 0
+ /* Check whether there is a result obtained by abstraction and whether
+ ** it is better than the one obtained by recursion. */
+ cuddRef(r);
+ if (ar != NULL) {
+ if (Cudd_DagSize(ar) <= Cudd_DagSize(r)) {
+ Cudd_IterDerefBdd(dd, r);
+ r = ar;
+ } else {
+ Cudd_IterDerefBdd(dd, ar);
+ }
+ }
+ cuddDeref(r);
+#endif
+
+ cuddCacheInsert2(dd, Cudd_bddSqueeze, l, u, r);
+ return(Cudd_NotCond(r,comple));
+
+} /* end of cuddBddSqueeze */
diff --git a/src/bdd/cudd/cuddGenetic.c b/src/bdd/cudd/cuddGenetic.c
new file mode 100644
index 00000000..8341dcbd
--- /dev/null
+++ b/src/bdd/cudd/cuddGenetic.c
@@ -0,0 +1,921 @@
+/**CFile***********************************************************************
+
+ FileName [cuddGenetic.c]
+
+ PackageName [cudd]
+
+ Synopsis [Genetic algorithm for variable reordering.]
+
+ Description [Internal procedures included in this file:
+ <ul>
+ <li> cuddGa()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> make_random()
+ <li> sift_up()
+ <li> build_dd()
+ <li> largest()
+ <li> rand_int()
+ <li> array_hash()
+ <li> array_compare()
+ <li> find_best()
+ <li> find_average_fitness()
+ <li> PMX()
+ <li> roulette()
+ </ul>
+
+ The genetic algorithm implemented here is as follows. We start with
+ the current DD order. We sift this order and use this as the
+ reference DD. We only keep 1 DD around for the entire process and
+ simply rearrange the order of this DD, storing the various orders
+ and their corresponding DD sizes. We generate more random orders to
+ build an initial population. This initial population is 3 times the
+ number of variables, with a maximum of 120. Each random order is
+ built (from the reference DD) and its size stored. Each random
+ order is also sifted to keep the DD sizes fairly small. Then a
+ crossover is performed between two orders (picked randomly) and the
+ two resulting DDs are built and sifted. For each new order, if its
+ size is smaller than any DD in the population, it is inserted into
+ the population and the DD with the largest number of nodes is thrown
+ out. The crossover process happens up to 50 times, and at this point
+ the DD in the population with the smallest size is chosen as the
+ result. This DD must then be built from the reference DD.]
+
+ SeeAlso []
+
+ Author [Curt Musfeldt, Alan Shuler, Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddGenetic.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+static int popsize; /* the size of the population */
+static int numvars; /* the number of input variables in the ckt. */
+/* storedd stores the population orders and sizes. This table has two
+** extra rows and one extras column. The two extra rows are used for the
+** offspring produced by a crossover. Each row stores one order and its
+** size. The order is stored by storing the indices of variables in the
+** order in which they appear in the order. The table is in reality a
+** one-dimensional array which is accessed via a macro to give the illusion
+** it is a two-dimensional structure.
+*/
+static int *storedd;
+static st_table *computed; /* hash table to identify existing orders */
+static int *repeat; /* how many times an order is present */
+static int large; /* stores the index of the population with
+ ** the largest number of nodes in the DD */
+static int result;
+static int cross; /* the number of crossovers to perform */
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/* macro used to access the population table as if it were a
+** two-dimensional structure.
+*/
+#define STOREDD(i,j) storedd[(i)*(numvars+1)+(j)]
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int make_random ARGS((DdManager *table, int lower));
+static int sift_up ARGS((DdManager *table, int x, int x_low));
+static int build_dd ARGS((DdManager *table, int num, int lower, int upper));
+static int largest ARGS(());
+static int rand_int ARGS((int a));
+static int array_hash ARGS((char *array, int modulus));
+static int array_compare ARGS((const char *array1, const char *array2));
+static int find_best ARGS(());
+static double find_average_fitness ARGS(());
+static int PMX ARGS((int maxvar));
+static int roulette ARGS((int *p1, int *p2));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Genetic algorithm for DD reordering.]
+
+ Description [Genetic algorithm for DD reordering.
+ The two children of a crossover will be stored in
+ storedd[popsize] and storedd[popsize+1] --- the last two slots in the
+ storedd array. (This will make comparisons and replacement easy.)
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddGa(
+ DdManager * table /* manager */,
+ int lower /* lowest level to be reordered */,
+ int upper /* highest level to be reorderded */)
+{
+ int i,n,m; /* dummy/loop vars */
+ int index;
+ double average_fitness;
+ int small; /* index of smallest DD in population */
+
+ /* Do an initial sifting to produce at least one reasonable individual. */
+ if (!cuddSifting(table,lower,upper)) return(0);
+
+ /* Get the initial values. */
+ numvars = upper - lower + 1; /* number of variables to be reordered */
+ if (table->populationSize == 0) {
+ popsize = 3 * numvars; /* population size is 3 times # of vars */
+ if (popsize > 120) {
+ popsize = 120; /* Maximum population size is 120 */
+ }
+ } else {
+ popsize = table->populationSize; /* user specified value */
+ }
+ if (popsize < 4) popsize = 4; /* enforce minimum population size */
+
+ /* Allocate population table. */
+ storedd = ALLOC(int,(popsize+2)*(numvars+1));
+ if (storedd == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+
+ /* Initialize the computed table. This table is made up of two data
+ ** structures: A hash table with the key given by the order, which says
+ ** if a given order is present in the population; and the repeat
+ ** vector, which says how many copies of a given order are stored in
+ ** the population table. If there are multiple copies of an order, only
+ ** one has a repeat count greater than 1. This copy is the one pointed
+ ** by the computed table.
+ */
+ repeat = ALLOC(int,popsize);
+ if (repeat == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ FREE(storedd);
+ return(0);
+ }
+ for (i = 0; i < popsize; i++) {
+ repeat[i] = 0;
+ }
+ computed = st_init_table(array_compare,array_hash);
+ if (computed == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ FREE(storedd);
+ FREE(repeat);
+ return(0);
+ }
+
+ /* Copy the current DD and its size to the population table. */
+ for (i = 0; i < numvars; i++) {
+ STOREDD(0,i) = table->invperm[i+lower]; /* order of initial DD */
+ }
+ STOREDD(0,numvars) = table->keys - table->isolated; /* size of initial DD */
+
+ /* Store the initial order in the computed table. */
+ if (st_insert(computed,(char *)storedd,(char *) 0) == ST_OUT_OF_MEM) {
+ FREE(storedd);
+ FREE(repeat);
+ st_free_table(computed);
+ return(0);
+ }
+ repeat[0]++;
+
+ /* Insert the reverse order as second element of the population. */
+ for (i = 0; i < numvars; i++) {
+ STOREDD(1,numvars-1-i) = table->invperm[i+lower]; /* reverse order */
+ }
+
+ /* Now create the random orders. make_random fills the population
+ ** table with random permutations. The successive loop builds and sifts
+ ** the DDs for the reverse order and each random permutation, and stores
+ ** the results in the computed table.
+ */
+ if (!make_random(table,lower)) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ FREE(storedd);
+ FREE(repeat);
+ st_free_table(computed);
+ return(0);
+ }
+ for (i = 1; i < popsize; i++) {
+ result = build_dd(table,i,lower,upper); /* build and sift order */
+ if (!result) {
+ FREE(storedd);
+ FREE(repeat);
+ st_free_table(computed);
+ return(0);
+ }
+ if (st_lookup(computed,(char *)&STOREDD(i,0),(char **)&index)) {
+ repeat[index]++;
+ } else {
+ if (st_insert(computed,(char *)&STOREDD(i,0),(char *)(long)i) ==
+ ST_OUT_OF_MEM) {
+ FREE(storedd);
+ FREE(repeat);
+ st_free_table(computed);
+ return(0);
+ }
+ repeat[i]++;
+ }
+ }
+
+#if 0
+#ifdef DD_STATS
+ /* Print the initial population. */
+ (void) fprintf(table->out,"Initial population after sifting\n");
+ for (m = 0; m < popsize; m++) {
+ for (i = 0; i < numvars; i++) {
+ (void) fprintf(table->out," %2d",STOREDD(m,i));
+ }
+ (void) fprintf(table->out," : %3d (%d)\n",
+ STOREDD(m,numvars),repeat[m]);
+ }
+#endif
+#endif
+
+ small = find_best();
+ average_fitness = find_average_fitness();
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\nInitial population: best fitness = %d, average fitness %8.3f",STOREDD(small,numvars),average_fitness);
+#endif
+
+ /* Decide how many crossovers should be tried. */
+ if (table->numberXovers == 0) {
+ cross = 3*numvars;
+ if (cross > 60) { /* do a maximum of 50 crossovers */
+ cross = 60;
+ }
+ } else {
+ cross = table->numberXovers; /* use user specified value */
+ }
+
+ /* Perform the crossovers to get the best order. */
+ for (m = 0; m < cross; m++) {
+ if (!PMX(table->size)) { /* perform one crossover */
+ table->errorCode = CUDD_MEMORY_OUT;
+ FREE(storedd);
+ FREE(repeat);
+ st_free_table(computed);
+ return(0);
+ }
+ /* The offsprings are left in the last two entries of the
+ ** population table. These are now considered in turn.
+ */
+ for (i = popsize; i <= popsize+1; i++) {
+ result = build_dd(table,i,lower,upper); /* build and sift child */
+ if (!result) {
+ FREE(storedd);
+ FREE(repeat);
+ st_free_table(computed);
+ return(0);
+ }
+ large = largest(); /* find the largest DD in population */
+
+ /* If the new child is smaller than the largest DD in the current
+ ** population, enter it into the population in place of the
+ ** largest DD.
+ */
+ if (STOREDD(i,numvars) < STOREDD(large,numvars)) {
+ /* Look up the largest DD in the computed table.
+ ** Decrease its repetition count. If the repetition count
+ ** goes to 0, remove the largest DD from the computed table.
+ */
+ result = st_lookup(computed,(char *)&STOREDD(large,0),(char
+ **)&index);
+ if (!result) {
+ FREE(storedd);
+ FREE(repeat);
+ st_free_table(computed);
+ return(0);
+ }
+ repeat[index]--;
+ if (repeat[index] == 0) {
+ int *pointer = &STOREDD(index,0);
+ result = st_delete(computed, (char **)&pointer,NULL);
+ if (!result) {
+ FREE(storedd);
+ FREE(repeat);
+ st_free_table(computed);
+ return(0);
+ }
+ }
+ /* Copy the new individual to the entry of the
+ ** population table just made available and update the
+ ** computed table.
+ */
+ for (n = 0; n <= numvars; n++) {
+ STOREDD(large,n) = STOREDD(i,n);
+ }
+ if (st_lookup(computed,(char *)&STOREDD(large,0),(char
+ **)&index)) {
+ repeat[index]++;
+ } else {
+ if (st_insert(computed,(char *)&STOREDD(large,0),
+ (char *)(long)large) == ST_OUT_OF_MEM) {
+ FREE(storedd);
+ FREE(repeat);
+ st_free_table(computed);
+ return(0);
+ }
+ repeat[large]++;
+ }
+ }
+ }
+ }
+
+ /* Find the smallest DD in the population and build it;
+ ** that will be the result.
+ */
+ small = find_best();
+
+ /* Print stats on the final population. */
+#ifdef DD_STATS
+ average_fitness = find_average_fitness();
+ (void) fprintf(table->out,"\nFinal population: best fitness = %d, average fitness %8.3f",STOREDD(small,numvars),average_fitness);
+#endif
+
+ /* Clean up, build the result DD, and return. */
+ st_free_table(computed);
+ computed = NULL;
+ result = build_dd(table,small,lower,upper);
+ FREE(storedd);
+ FREE(repeat);
+ return(result);
+
+} /* end of cuddGa */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Generates the random sequences for the initial population.]
+
+ Description [Generates the random sequences for the initial population.
+ The sequences are permutations of the indices between lower and
+ upper in the current order.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+make_random(
+ DdManager * table,
+ int lower)
+{
+ int i,j; /* loop variables */
+ int *used; /* is a number already in a permutation */
+ int next; /* next random number without repetitions */
+
+ used = ALLOC(int,numvars);
+ if (used == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+#if 0
+#ifdef DD_STATS
+ (void) fprintf(table->out,"Initial population before sifting\n");
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < numvars; j++) {
+ (void) fprintf(table->out," %2d",STOREDD(i,j));
+ }
+ (void) fprintf(table->out,"\n");
+ }
+#endif
+#endif
+ for (i = 2; i < popsize; i++) {
+ for (j = 0; j < numvars; j++) {
+ used[j] = 0;
+ }
+ /* Generate a permutation of {0...numvars-1} and use it to
+ ** permute the variables in the layesr from lower to upper.
+ */
+ for (j = 0; j < numvars; j++) {
+ do {
+ next = rand_int(numvars-1);
+ } while (used[next] != 0);
+ used[next] = 1;
+ STOREDD(i,j) = table->invperm[next+lower];
+ }
+#if 0
+#ifdef DD_STATS
+ /* Print the order just generated. */
+ for (j = 0; j < numvars; j++) {
+ (void) fprintf(table->out," %2d",STOREDD(i,j));
+ }
+ (void) fprintf(table->out,"\n");
+#endif
+#endif
+ }
+ FREE(used);
+ return(1);
+
+} /* end of make_random */
+
+
+/**Function********************************************************************
+
+ Synopsis [Moves one variable up.]
+
+ Description [Takes a variable from position x and sifts it up to
+ position x_low; x_low should be less than x. Returns 1 if successful;
+ 0 otherwise]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+sift_up(
+ DdManager * table,
+ int x,
+ int x_low)
+{
+ int y;
+ int size;
+
+ y = cuddNextLow(table,x);
+ while (y >= x_low) {
+ size = cuddSwapInPlace(table,y,x);
+ if (size == 0) {
+ return(0);
+ }
+ x = y;
+ y = cuddNextLow(table,x);
+ }
+ return(1);
+
+} /* end of sift_up */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds a DD from a given order.]
+
+ Description [Builds a DD from a given order. This procedure also
+ sifts the final order and inserts into the array the size in nodes
+ of the result. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+build_dd(
+ DdManager * table,
+ int num /* the index of the individual to be built */,
+ int lower,
+ int upper)
+{
+ int i,j; /* loop vars */
+ int position;
+ int index;
+ int limit; /* how large the DD for this order can grow */
+ int size;
+
+ /* Check the computed table. If the order already exists, it
+ ** suffices to copy the size from the existing entry.
+ */
+ if (computed && st_lookup(computed,(char *)&STOREDD(num,0),(char **)&index)) {
+ STOREDD(num,numvars) = STOREDD(index,numvars);
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\nCache hit for index %d", index);
+#endif
+ return(1);
+ }
+
+ /* Stop if the DD grows 20 times larges than the reference size. */
+ limit = 20 * STOREDD(0,numvars);
+
+ /* Sift up the variables so as to build the desired permutation.
+ ** First the variable that has to be on top is sifted to the top.
+ ** Then the variable that has to occupy the secon position is sifted
+ ** up to the second position, and so on.
+ */
+ for (j = 0; j < numvars; j++) {
+ i = STOREDD(num,j);
+ position = table->perm[i];
+ result = sift_up(table,position,j+lower);
+ if (!result) return(0);
+ size = table->keys - table->isolated;
+ if (size > limit) break;
+ }
+
+ /* Sift the DD just built. */
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n");
+#endif
+ result = cuddSifting(table,lower,upper);
+ if (!result) return(0);
+
+ /* Copy order and size to table. */
+ for (j = 0; j < numvars; j++) {
+ STOREDD(num,j) = table->invperm[lower+j];
+ }
+ STOREDD(num,numvars) = table->keys - table->isolated; /* size of new DD */
+ return(1);
+
+} /* end of build_dd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the largest DD in the population.]
+
+ Description [Finds the largest DD in the population. If an order is
+ repeated, it avoids choosing the copy that is in the computed table
+ (it has repeat[i] > 1).]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+largest(
+ )
+{
+ int i; /* loop var */
+ int big; /* temporary holder to return result */
+
+ big = 0;
+ while (repeat[big] > 1) big++;
+ for (i = big + 1; i < popsize; i++) {
+ if (STOREDD(i,numvars) >= STOREDD(big,numvars) && repeat[i] <= 1) {
+ big = i;
+ }
+ }
+ return(big);
+
+} /* end of largest */
+
+
+/**Function********************************************************************
+
+ Synopsis [Generates a random number between 0 and the integer a.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+rand_int(
+ int a)
+{
+ return(Cudd_Random() % (a+1));
+
+} /* end of rand_int */
+
+
+/**Function********************************************************************
+
+ Synopsis [Hash function for the computed table.]
+
+ Description [Hash function for the computed table. Returns the bucket
+ number.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+array_hash(
+ char * array,
+ int modulus)
+{
+ int val = 0;
+ int i;
+ int *intarray;
+
+ intarray = (int *) array;
+
+ for (i = 0; i < numvars; i++) {
+ val = val * 997 + intarray[i];
+ }
+
+ return ((val < 0) ? -val : val) % modulus;
+
+} /* end of array_hash */
+
+
+/**Function********************************************************************
+
+ Synopsis [Comparison function for the computed table.]
+
+ Description [Comparison function for the computed table. Returns 0 if
+ the two arrays are equal; 1 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+array_compare(
+ const char * array1,
+ const char * array2)
+{
+ int i;
+ int *intarray1, *intarray2;
+
+ intarray1 = (int *) array1;
+ intarray2 = (int *) array2;
+
+ for (i = 0; i < numvars; i++) {
+ if (intarray1[i] != intarray2[i]) return(1);
+ }
+ return(0);
+
+} /* end of array_compare */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the index of the fittest individual.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+find_best(
+ )
+{
+ int i,small;
+
+ small = 0;
+ for (i = 1; i < popsize; i++) {
+ if (STOREDD(i,numvars) < STOREDD(small,numvars)) {
+ small = i;
+ }
+ }
+ return(small);
+
+} /* end of find_best */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the average fitness of the population.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static double
+find_average_fitness(
+ )
+{
+ int i;
+ int total_fitness = 0;
+ double average_fitness;
+
+ for (i = 0; i < popsize; i++) {
+ total_fitness += STOREDD(i,numvars);
+ }
+ average_fitness = (double) total_fitness / (double) popsize;
+ return(average_fitness);
+
+} /* end of find_average_fitness */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the crossover between two parents.]
+
+ Description [Performs the crossover between two randomly chosen
+ parents, and creates two children, x1 and x2. Uses the Partially
+ Matched Crossover operator.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+PMX(
+ int maxvar)
+{
+ int cut1,cut2; /* the two cut positions (random) */
+ int mom,dad; /* the two randomly chosen parents */
+ int *inv1; /* inverse permutations for repair algo */
+ int *inv2;
+ int i; /* loop vars */
+ int u,v; /* aux vars */
+
+ inv1 = ALLOC(int,maxvar);
+ if (inv1 == NULL) {
+ return(0);
+ }
+ inv2 = ALLOC(int,maxvar);
+ if (inv2 == NULL) {
+ FREE(inv1);
+ return(0);
+ }
+
+ /* Choose two orders from the population using roulette wheel. */
+ if (!roulette(&mom,&dad)) {
+ FREE(inv1);
+ FREE(inv2);
+ return(0);
+ }
+
+ /* Choose two random cut positions. A cut in position i means that
+ ** the cut immediately precedes position i. If cut1 < cut2, we
+ ** exchange the middle of the two orderings; otherwise, we
+ ** exchange the beginnings and the ends.
+ */
+ cut1 = rand_int(numvars-1);
+ do {
+ cut2 = rand_int(numvars-1);
+ } while (cut1 == cut2);
+
+#if 0
+ /* Print out the parents. */
+ (void) fprintf(table->out,
+ "Crossover of %d (mom) and %d (dad) between %d and %d\n",
+ mom,dad,cut1,cut2);
+ for (i = 0; i < numvars; i++) {
+ if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
+ (void) fprintf(table->out,"%2d ",STOREDD(mom,i));
+ }
+ (void) fprintf(table->out,"\n");
+ for (i = 0; i < numvars; i++) {
+ if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
+ (void) fprintf(table->out,"%2d ",STOREDD(dad,i));
+ }
+ (void) fprintf(table->out,"\n");
+#endif
+
+ /* Initialize the inverse permutations: -1 means yet undetermined. */
+ for (i = 0; i < maxvar; i++) {
+ inv1[i] = -1;
+ inv2[i] = -1;
+ }
+
+ /* Copy the portions whithin the cuts. */
+ for (i = cut1; i != cut2; i = (i == numvars-1) ? 0 : i+1) {
+ STOREDD(popsize,i) = STOREDD(dad,i);
+ inv1[STOREDD(popsize,i)] = i;
+ STOREDD(popsize+1,i) = STOREDD(mom,i);
+ inv2[STOREDD(popsize+1,i)] = i;
+ }
+
+ /* Now apply the repair algorithm outside the cuts. */
+ for (i = cut2; i != cut1; i = (i == numvars-1 ) ? 0 : i+1) {
+ v = i;
+ do {
+ u = STOREDD(mom,v);
+ v = inv1[u];
+ } while (v != -1);
+ STOREDD(popsize,i) = u;
+ inv1[u] = i;
+ v = i;
+ do {
+ u = STOREDD(dad,v);
+ v = inv2[u];
+ } while (v != -1);
+ STOREDD(popsize+1,i) = u;
+ inv2[u] = i;
+ }
+
+#if 0
+ /* Print the results of crossover. */
+ for (i = 0; i < numvars; i++) {
+ if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
+ (void) fprintf(table->out,"%2d ",STOREDD(popsize,i));
+ }
+ (void) fprintf(table->out,"\n");
+ for (i = 0; i < numvars; i++) {
+ if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
+ (void) fprintf(table->out,"%2d ",STOREDD(popsize+1,i));
+ }
+ (void) fprintf(table->out,"\n");
+#endif
+
+ FREE(inv1);
+ FREE(inv2);
+ return(1);
+
+} /* end of PMX */
+
+
+/**Function********************************************************************
+
+ Synopsis [Selects two parents with the roulette wheel method.]
+
+ Description [Selects two distinct parents with the roulette wheel method.]
+
+ SideEffects [The indices of the selected parents are returned as side
+ effects.]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+roulette(
+ int * p1,
+ int * p2)
+{
+ double *wheel;
+ double spin;
+ int i;
+
+ wheel = ALLOC(double,popsize);
+ if (wheel == NULL) {
+ return(0);
+ }
+
+ /* The fitness of an individual is the reciprocal of its size. */
+ wheel[0] = 1.0 / (double) STOREDD(0,numvars);
+
+ for (i = 1; i < popsize; i++) {
+ wheel[i] = wheel[i-1] + 1.0 / (double) STOREDD(i,numvars);
+ }
+
+ /* Get a random number between 0 and wheel[popsize-1] (that is,
+ ** the sum of all fitness values. 2147483561 is the largest number
+ ** returned by Cudd_Random.
+ */
+ spin = wheel[numvars-1] * (double) Cudd_Random() / 2147483561.0;
+
+ /* Find the lucky element by scanning the wheel. */
+ for (i = 0; i < popsize; i++) {
+ if (spin <= wheel[i]) break;
+ }
+ *p1 = i;
+
+ /* Repeat the process for the second parent, making sure it is
+ ** distinct from the first.
+ */
+ do {
+ spin = wheel[popsize-1] * (double) Cudd_Random() / 2147483561.0;
+ for (i = 0; i < popsize; i++) {
+ if (spin <= wheel[i]) break;
+ }
+ } while (i == *p1);
+ *p2 = i;
+
+ FREE(wheel);
+ return(1);
+
+} /* end of roulette */
+
diff --git a/src/bdd/cudd/cuddGroup.c b/src/bdd/cudd/cuddGroup.c
new file mode 100644
index 00000000..f84f7881
--- /dev/null
+++ b/src/bdd/cudd/cuddGroup.c
@@ -0,0 +1,2142 @@
+/**CFile***********************************************************************
+
+ FileName [cuddGroup.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for group sifting.]
+
+ Description [External procedures included in this file:
+ <ul>
+ <li> Cudd_MakeTreeNode()
+ </ul>
+ Internal procedures included in this file:
+ <ul>
+ <li> cuddTreeSifting()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> ddTreeSiftingAux()
+ <li> ddCountInternalMtrNodes()
+ <li> ddReorderChildren()
+ <li> ddFindNodeHiLo()
+ <li> ddUniqueCompareGroup()
+ <li> ddGroupSifting()
+ <li> ddCreateGroup()
+ <li> ddGroupSiftingAux()
+ <li> ddGroupSiftingUp()
+ <li> ddGroupSiftingDown()
+ <li> ddGroupMove()
+ <li> ddGroupMoveBackward()
+ <li> ddGroupSiftingBackward()
+ <li> ddMergeGroups()
+ <li> ddDissolveGroup()
+ <li> ddNoCheck()
+ <li> ddSecDiffCheck()
+ <li> ddExtSymmCheck()
+ <li> ddVarGroupCheck()
+ <li> ddSetVarHandled()
+ <li> ddResetVarHandled()
+ <li> ddIsVarHandled()
+ </ul>]
+
+ Author [Shipra Panda, Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/* Constants for lazy sifting */
+#define DD_NORMAL_SIFT 0
+#define DD_LAZY_SIFT 1
+
+/* Constants for sifting up and down */
+#define DD_SIFT_DOWN 0
+#define DD_SIFT_UP 1
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddGroup.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+static int *entry;
+extern int ddTotalNumberSwapping;
+#ifdef DD_STATS
+extern int ddTotalNISwaps;
+static int extsymmcalls;
+static int extsymm;
+static int secdiffcalls;
+static int secdiff;
+static int secdiffmisfire;
+#endif
+#ifdef DD_DEBUG
+static int pr = 0; /* flag to enable printing while debugging */
+ /* by depositing a 1 into it */
+#endif
+static int originalSize;
+static int originalLevel;
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int ddTreeSiftingAux ARGS((DdManager *table, MtrNode *treenode, Cudd_ReorderingType method));
+#ifdef DD_STATS
+static int ddCountInternalMtrNodes ARGS((DdManager *table, MtrNode *treenode));
+#endif
+static int ddReorderChildren ARGS((DdManager *table, MtrNode *treenode, Cudd_ReorderingType method));
+static void ddFindNodeHiLo ARGS((DdManager *table, MtrNode *treenode, int *lower, int *upper));
+static int ddUniqueCompareGroup ARGS((int *ptrX, int *ptrY));
+static int ddGroupSifting ARGS((DdManager *table, int lower, int upper, int (*checkFunction)(DdManager *, int, int), int lazyFlag));
+static void ddCreateGroup ARGS((DdManager *table, int x, int y));
+static int ddGroupSiftingAux ARGS((DdManager *table, int x, int xLow, int xHigh, int (*checkFunction)(DdManager *, int, int), int lazyFlag));
+static int ddGroupSiftingUp ARGS((DdManager *table, int y, int xLow, int (*checkFunction)(DdManager *, int, int), Move **moves));
+static int ddGroupSiftingDown ARGS((DdManager *table, int x, int xHigh, int (*checkFunction)(DdManager *, int, int), Move **moves));
+static int ddGroupMove ARGS((DdManager *table, int x, int y, Move **moves));
+static int ddGroupMoveBackward ARGS((DdManager *table, int x, int y));
+static int ddGroupSiftingBackward ARGS((DdManager *table, Move *moves, int size, int upFlag, int lazyFlag));
+static void ddMergeGroups ARGS((DdManager *table, MtrNode *treenode, int low, int high));
+static void ddDissolveGroup ARGS((DdManager *table, int x, int y));
+static int ddNoCheck ARGS((DdManager *table, int x, int y));
+static int ddSecDiffCheck ARGS((DdManager *table, int x, int y));
+static int ddExtSymmCheck ARGS((DdManager *table, int x, int y));
+static int ddVarGroupCheck ARGS((DdManager * table, int x, int y));
+static int ddSetVarHandled ARGS((DdManager *dd, int index));
+static int ddResetVarHandled ARGS((DdManager *dd, int index));
+static int ddIsVarHandled ARGS((DdManager *dd, int index));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Creates a new variable group.]
+
+ Description [Creates a new variable group. The group starts at
+ variable and contains size variables. The parameter low is the index
+ of the first variable. If the variable already exists, its current
+ position in the order is known to the manager. If the variable does
+ not exist yet, the position is assumed to be the same as the index.
+ The group tree is created if it does not exist yet.
+ Returns a pointer to the group if successful; NULL otherwise.]
+
+ SideEffects [The variable tree is changed.]
+
+ SeeAlso [Cudd_MakeZddTreeNode]
+
+******************************************************************************/
+MtrNode *
+Cudd_MakeTreeNode(
+ DdManager * dd /* manager */,
+ unsigned int low /* index of the first group variable */,
+ unsigned int size /* number of variables in the group */,
+ unsigned int type /* MTR_DEFAULT or MTR_FIXED */)
+{
+ MtrNode *group;
+ MtrNode *tree;
+ unsigned int level;
+
+ /* If the variable does not exist yet, the position is assumed to be
+ ** the same as the index. Therefore, applications that rely on
+ ** Cudd_bddNewVarAtLevel or Cudd_addNewVarAtLevel to create new
+ ** variables have to create the variables before they group them.
+ */
+ level = (low < (unsigned int) dd->size) ? dd->perm[low] : low;
+
+ if (level + size - 1> (int) MTR_MAXHIGH)
+ return(NULL);
+
+ /* If the tree does not exist yet, create it. */
+ tree = dd->tree;
+ if (tree == NULL) {
+ dd->tree = tree = Mtr_InitGroupTree(0, dd->size);
+ if (tree == NULL)
+ return(NULL);
+ tree->index = dd->invperm[0];
+ }
+
+ /* Extend the upper bound of the tree if necessary. This allows the
+ ** application to create groups even before the variables are created.
+ */
+ tree->size = ddMax(tree->size, ddMax(level + size, (unsigned) dd->size));
+
+ /* Create the group. */
+ group = Mtr_MakeGroup(tree, level, size, type);
+ if (group == NULL)
+ return(NULL);
+
+ /* Initialize the index field to the index of the variable currently
+ ** in position low. This field will be updated by the reordering
+ ** procedure to provide a handle to the group once it has been moved.
+ */
+ group->index = (MtrHalfWord) low;
+
+ return(group);
+
+} /* end of Cudd_MakeTreeNode */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Tree sifting algorithm.]
+
+ Description [Tree sifting algorithm. Assumes that a tree representing
+ a group hierarchy is passed as a parameter. It then reorders each
+ group in postorder fashion by calling ddTreeSiftingAux. Assumes that
+ no dead nodes are present. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+int
+cuddTreeSifting(
+ DdManager * table /* DD table */,
+ Cudd_ReorderingType method /* reordering method for the groups of leaves */)
+{
+ int i;
+ int nvars;
+ int result;
+ int tempTree;
+
+ /* If no tree is provided we create a temporary one in which all
+ ** variables are in a single group. After reordering this tree is
+ ** destroyed.
+ */
+ tempTree = table->tree == NULL;
+ if (tempTree) {
+ table->tree = Mtr_InitGroupTree(0,table->size);
+ table->tree->index = table->invperm[0];
+ }
+ nvars = table->size;
+
+#ifdef DD_DEBUG
+ if (pr > 0 && !tempTree) (void) fprintf(table->out,"cuddTreeSifting:");
+ Mtr_PrintGroups(table->tree,pr <= 0);
+#endif
+
+#ifdef DD_STATS
+ extsymmcalls = 0;
+ extsymm = 0;
+ secdiffcalls = 0;
+ secdiff = 0;
+ secdiffmisfire = 0;
+
+ (void) fprintf(table->out,"\n");
+ if (!tempTree)
+ (void) fprintf(table->out,"#:IM_NODES %8d: group tree nodes\n",
+ ddCountInternalMtrNodes(table,table->tree));
+#endif
+
+ /* Initialize the group of each subtable to itself. Initially
+ ** there are no groups. Groups are created according to the tree
+ ** structure in postorder fashion.
+ */
+ for (i = 0; i < nvars; i++)
+ table->subtables[i].next = i;
+
+
+ /* Reorder. */
+ result = ddTreeSiftingAux(table, table->tree, method);
+
+#ifdef DD_STATS /* print stats */
+ if (!tempTree && method == CUDD_REORDER_GROUP_SIFT &&
+ (table->groupcheck == CUDD_GROUP_CHECK7 ||
+ table->groupcheck == CUDD_GROUP_CHECK5)) {
+ (void) fprintf(table->out,"\nextsymmcalls = %d\n",extsymmcalls);
+ (void) fprintf(table->out,"extsymm = %d",extsymm);
+ }
+ if (!tempTree && method == CUDD_REORDER_GROUP_SIFT &&
+ table->groupcheck == CUDD_GROUP_CHECK7) {
+ (void) fprintf(table->out,"\nsecdiffcalls = %d\n",secdiffcalls);
+ (void) fprintf(table->out,"secdiff = %d\n",secdiff);
+ (void) fprintf(table->out,"secdiffmisfire = %d",secdiffmisfire);
+ }
+#endif
+
+ if (tempTree)
+ Cudd_FreeTree(table);
+ return(result);
+
+} /* end of cuddTreeSifting */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Visits the group tree and reorders each group.]
+
+ Description [Recursively visits the group tree and reorders each
+ group in postorder fashion. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddTreeSiftingAux(
+ DdManager * table,
+ MtrNode * treenode,
+ Cudd_ReorderingType method)
+{
+ MtrNode *auxnode;
+ int res;
+ Cudd_AggregationType saveCheck;
+
+#ifdef DD_DEBUG
+ Mtr_PrintGroups(treenode,1);
+#endif
+
+ auxnode = treenode;
+ while (auxnode != NULL) {
+ if (auxnode->child != NULL) {
+ if (!ddTreeSiftingAux(table, auxnode->child, method))
+ return(0);
+ saveCheck = table->groupcheck;
+ table->groupcheck = CUDD_NO_CHECK;
+ if (method != CUDD_REORDER_LAZY_SIFT)
+ res = ddReorderChildren(table, auxnode, CUDD_REORDER_GROUP_SIFT);
+ else
+ res = ddReorderChildren(table, auxnode, CUDD_REORDER_LAZY_SIFT);
+ table->groupcheck = saveCheck;
+
+ if (res == 0)
+ return(0);
+ } else if (auxnode->size > 1) {
+ if (!ddReorderChildren(table, auxnode, method))
+ return(0);
+ }
+ auxnode = auxnode->younger;
+ }
+
+ return(1);
+
+} /* end of ddTreeSiftingAux */
+
+
+#ifdef DD_STATS
+/**Function********************************************************************
+
+ Synopsis [Counts the number of internal nodes of the group tree.]
+
+ Description [Counts the number of internal nodes of the group tree.
+ Returns the count.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddCountInternalMtrNodes(
+ DdManager * table,
+ MtrNode * treenode)
+{
+ MtrNode *auxnode;
+ int count,nodeCount;
+
+
+ nodeCount = 0;
+ auxnode = treenode;
+ while (auxnode != NULL) {
+ if (!(MTR_TEST(auxnode,MTR_TERMINAL))) {
+ nodeCount++;
+ count = ddCountInternalMtrNodes(table,auxnode->child);
+ nodeCount += count;
+ }
+ auxnode = auxnode->younger;
+ }
+
+ return(nodeCount);
+
+} /* end of ddCountInternalMtrNodes */
+#endif
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders the children of a group tree node according to
+ the options.]
+
+ Description [Reorders the children of a group tree node according to
+ the options. After reordering puts all the variables in the group
+ and/or its descendents in a single group. This allows hierarchical
+ reordering. If the variables in the group do not exist yet, simply
+ does nothing. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddReorderChildren(
+ DdManager * table,
+ MtrNode * treenode,
+ Cudd_ReorderingType method)
+{
+ int lower;
+ int upper;
+ int result;
+ unsigned int initialSize;
+
+ ddFindNodeHiLo(table,treenode,&lower,&upper);
+ /* If upper == -1 these variables do not exist yet. */
+ if (upper == -1)
+ return(1);
+
+ if (treenode->flags == MTR_FIXED) {
+ result = 1;
+ } else {
+#ifdef DD_STATS
+ (void) fprintf(table->out," ");
+#endif
+ switch (method) {
+ case CUDD_REORDER_RANDOM:
+ case CUDD_REORDER_RANDOM_PIVOT:
+ result = cuddSwapping(table,lower,upper,method);
+ break;
+ case CUDD_REORDER_SIFT:
+ result = cuddSifting(table,lower,upper);
+ break;
+ case CUDD_REORDER_SIFT_CONVERGE:
+ do {
+ initialSize = table->keys - table->isolated;
+ result = cuddSifting(table,lower,upper);
+ if (initialSize <= table->keys - table->isolated)
+ break;
+#ifdef DD_STATS
+ else
+ (void) fprintf(table->out,"\n");
+#endif
+ } while (result != 0);
+ break;
+ case CUDD_REORDER_SYMM_SIFT:
+ result = cuddSymmSifting(table,lower,upper);
+ break;
+ case CUDD_REORDER_SYMM_SIFT_CONV:
+ result = cuddSymmSiftingConv(table,lower,upper);
+ break;
+ case CUDD_REORDER_GROUP_SIFT:
+ if (table->groupcheck == CUDD_NO_CHECK) {
+ result = ddGroupSifting(table,lower,upper,ddNoCheck,
+ DD_NORMAL_SIFT);
+ } else if (table->groupcheck == CUDD_GROUP_CHECK5) {
+ result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
+ DD_NORMAL_SIFT);
+ } else if (table->groupcheck == CUDD_GROUP_CHECK7) {
+ result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
+ DD_NORMAL_SIFT);
+ } else {
+ (void) fprintf(table->err,
+ "Unknown group ckecking method\n");
+ result = 0;
+ }
+ break;
+ case CUDD_REORDER_GROUP_SIFT_CONV:
+ do {
+ initialSize = table->keys - table->isolated;
+ if (table->groupcheck == CUDD_NO_CHECK) {
+ result = ddGroupSifting(table,lower,upper,ddNoCheck,
+ DD_NORMAL_SIFT);
+ } else if (table->groupcheck == CUDD_GROUP_CHECK5) {
+ result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
+ DD_NORMAL_SIFT);
+ } else if (table->groupcheck == CUDD_GROUP_CHECK7) {
+ result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
+ DD_NORMAL_SIFT);
+ } else {
+ (void) fprintf(table->err,
+ "Unknown group ckecking method\n");
+ result = 0;
+ }
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n");
+#endif
+ result = cuddWindowReorder(table,lower,upper,
+ CUDD_REORDER_WINDOW4);
+ if (initialSize <= table->keys - table->isolated)
+ break;
+#ifdef DD_STATS
+ else
+ (void) fprintf(table->out,"\n");
+#endif
+ } while (result != 0);
+ break;
+ case CUDD_REORDER_WINDOW2:
+ case CUDD_REORDER_WINDOW3:
+ case CUDD_REORDER_WINDOW4:
+ case CUDD_REORDER_WINDOW2_CONV:
+ case CUDD_REORDER_WINDOW3_CONV:
+ case CUDD_REORDER_WINDOW4_CONV:
+ result = cuddWindowReorder(table,lower,upper,method);
+ break;
+ case CUDD_REORDER_ANNEALING:
+ result = cuddAnnealing(table,lower,upper);
+ break;
+ case CUDD_REORDER_GENETIC:
+ result = cuddGa(table,lower,upper);
+ break;
+ case CUDD_REORDER_LINEAR:
+ result = cuddLinearAndSifting(table,lower,upper);
+ break;
+ case CUDD_REORDER_LINEAR_CONVERGE:
+ do {
+ initialSize = table->keys - table->isolated;
+ result = cuddLinearAndSifting(table,lower,upper);
+ if (initialSize <= table->keys - table->isolated)
+ break;
+#ifdef DD_STATS
+ else
+ (void) fprintf(table->out,"\n");
+#endif
+ } while (result != 0);
+ break;
+ case CUDD_REORDER_EXACT:
+ result = cuddExact(table,lower,upper);
+ break;
+ case CUDD_REORDER_LAZY_SIFT:
+ result = ddGroupSifting(table,lower,upper,ddVarGroupCheck,
+ DD_LAZY_SIFT);
+ break;
+ default:
+ return(0);
+ }
+ }
+
+ /* Create a single group for all the variables that were sifted,
+ ** so that they will be treated as a single block by successive
+ ** invocations of ddGroupSifting.
+ */
+ ddMergeGroups(table,treenode,lower,upper);
+
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"ddReorderChildren:");
+#endif
+
+ return(result);
+
+} /* end of ddReorderChildren */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the lower and upper bounds of the group represented
+ by treenode.]
+
+ Description [Finds the lower and upper bounds of the group
+ represented by treenode. From the index and size fields we need to
+ derive the current positions, and find maximum and minimum.]
+
+ SideEffects [The bounds are returned as side effects.]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ddFindNodeHiLo(
+ DdManager * table,
+ MtrNode * treenode,
+ int * lower,
+ int * upper)
+{
+ int low;
+ int high;
+
+ /* Check whether no variables in this group already exist.
+ ** If so, return immediately. The calling procedure will know from
+ ** the values of upper that no reordering is needed.
+ */
+ if ((int) treenode->low >= table->size) {
+ *lower = table->size;
+ *upper = -1;
+ return;
+ }
+
+ *lower = low = (unsigned int) table->perm[treenode->index];
+ high = (int) (low + treenode->size - 1);
+
+ if (high >= table->size) {
+ /* This is the case of a partially existing group. The aim is to
+ ** reorder as many variables as safely possible. If the tree
+ ** node is terminal, we just reorder the subset of the group
+ ** that is currently in existence. If the group has
+ ** subgroups, then we only reorder those subgroups that are
+ ** fully instantiated. This way we avoid breaking up a group.
+ */
+ MtrNode *auxnode = treenode->child;
+ if (auxnode == NULL) {
+ *upper = (unsigned int) table->size - 1;
+ } else {
+ /* Search the subgroup that strands the table->size line.
+ ** If the first group starts at 0 and goes past table->size
+ ** upper will get -1, thus correctly signaling that no reordering
+ ** should take place.
+ */
+ while (auxnode != NULL) {
+ int thisLower = table->perm[auxnode->low];
+ int thisUpper = thisLower + auxnode->size - 1;
+ if (thisUpper >= table->size && thisLower < table->size)
+ *upper = (unsigned int) thisLower - 1;
+ auxnode = auxnode->younger;
+ }
+ }
+ } else {
+ /* Normal case: All the variables of the group exist. */
+ *upper = (unsigned int) high;
+ }
+
+#ifdef DD_DEBUG
+ /* Make sure that all variables in group are contiguous. */
+ assert(treenode->size >= *upper - *lower + 1);
+#endif
+
+ return;
+
+} /* end of ddFindNodeHiLo */
+
+
+/**Function********************************************************************
+
+ Synopsis [Comparison function used by qsort.]
+
+ Description [Comparison function used by qsort to order the variables
+ according to the number of keys in the subtables. Returns the
+ difference in number of keys between the two variables being
+ compared.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddUniqueCompareGroup(
+ int * ptrX,
+ int * ptrY)
+{
+#if 0
+ if (entry[*ptrY] == entry[*ptrX]) {
+ return((*ptrX) - (*ptrY));
+ }
+#endif
+ return(entry[*ptrY] - entry[*ptrX]);
+
+} /* end of ddUniqueCompareGroup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts from treenode->low to treenode->high.]
+
+ Description [Sifts from treenode->low to treenode->high. If
+ croupcheck == CUDD_GROUP_CHECK7, it checks for group creation at the
+ end of the initial sifting. If a group is created, it is then sifted
+ again. After sifting one variable, the group that contains it is
+ dissolved. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddGroupSifting(
+ DdManager * table,
+ int lower,
+ int upper,
+ int (*checkFunction)(DdManager *, int, int),
+ int lazyFlag)
+{
+ int *var;
+ int i,j,x,xInit;
+ int nvars;
+ int classes;
+ int result;
+ int *sifted;
+ int merged;
+ int dissolve;
+#ifdef DD_STATS
+ unsigned previousSize;
+#endif
+ int xindex;
+
+ nvars = table->size;
+
+ /* Order variables to sift. */
+ entry = NULL;
+ sifted = NULL;
+ var = ALLOC(int,nvars);
+ if (var == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto ddGroupSiftingOutOfMem;
+ }
+ entry = ALLOC(int,nvars);
+ if (entry == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto ddGroupSiftingOutOfMem;
+ }
+ sifted = ALLOC(int,nvars);
+ if (sifted == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto ddGroupSiftingOutOfMem;
+ }
+
+ /* Here we consider only one representative for each group. */
+ for (i = 0, classes = 0; i < nvars; i++) {
+ sifted[i] = 0;
+ x = table->perm[i];
+ if ((unsigned) x >= table->subtables[x].next) {
+ entry[i] = table->subtables[x].keys;
+ var[classes] = i;
+ classes++;
+ }
+ }
+
+ qsort((void *)var,classes,sizeof(int),
+ (int (*)(const void *, const void *)) ddUniqueCompareGroup);
+
+ if (lazyFlag) {
+ for (i = 0; i < nvars; i ++) {
+ ddResetVarHandled(table, i);
+ }
+ }
+
+ /* Now sift. */
+ for (i = 0; i < ddMin(table->siftMaxVar,classes); i++) {
+ if (ddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ xindex = var[i];
+ if (sifted[xindex] == 1) /* variable already sifted as part of group */
+ continue;
+ x = table->perm[xindex]; /* find current level of this variable */
+
+ if (x < lower || x > upper || table->subtables[x].bindVar == 1)
+ continue;
+#ifdef DD_STATS
+ previousSize = table->keys - table->isolated;
+#endif
+#ifdef DD_DEBUG
+ /* x is bottom of group */
+ assert((unsigned) x >= table->subtables[x].next);
+#endif
+ if ((unsigned) x == table->subtables[x].next) {
+ dissolve = 1;
+ result = ddGroupSiftingAux(table,x,lower,upper,checkFunction,
+ lazyFlag);
+ } else {
+ dissolve = 0;
+ result = ddGroupSiftingAux(table,x,lower,upper,ddNoCheck,lazyFlag);
+ }
+ if (!result) goto ddGroupSiftingOutOfMem;
+
+ /* check for aggregation */
+ merged = 0;
+ if (lazyFlag == 0 && table->groupcheck == CUDD_GROUP_CHECK7) {
+ x = table->perm[xindex]; /* find current level */
+ if ((unsigned) x == table->subtables[x].next) { /* not part of a group */
+ if (x != upper && sifted[table->invperm[x+1]] == 0 &&
+ (unsigned) x+1 == table->subtables[x+1].next) {
+ if (ddSecDiffCheck(table,x,x+1)) {
+ merged =1;
+ ddCreateGroup(table,x,x+1);
+ }
+ }
+ if (x != lower && sifted[table->invperm[x-1]] == 0 &&
+ (unsigned) x-1 == table->subtables[x-1].next) {
+ if (ddSecDiffCheck(table,x-1,x)) {
+ merged =1;
+ ddCreateGroup(table,x-1,x);
+ }
+ }
+ }
+ }
+
+ if (merged) { /* a group was created */
+ /* move x to bottom of group */
+ while ((unsigned) x < table->subtables[x].next)
+ x = table->subtables[x].next;
+ /* sift */
+ result = ddGroupSiftingAux(table,x,lower,upper,ddNoCheck,lazyFlag);
+ if (!result) goto ddGroupSiftingOutOfMem;
+#ifdef DD_STATS
+ if (table->keys < previousSize + table->isolated) {
+ (void) fprintf(table->out,"_");
+ } else if (table->keys > previousSize + table->isolated) {
+ (void) fprintf(table->out,"^");
+ } else {
+ (void) fprintf(table->out,"*");
+ }
+ fflush(table->out);
+ } else {
+ if (table->keys < previousSize + table->isolated) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keys > previousSize + table->isolated) {
+ (void) fprintf(table->out,"+");
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+
+ /* Mark variables in the group just sifted. */
+ x = table->perm[xindex];
+ if ((unsigned) x != table->subtables[x].next) {
+ xInit = x;
+ do {
+ j = table->invperm[x];
+ sifted[j] = 1;
+ x = table->subtables[x].next;
+ } while (x != xInit);
+
+ /* Dissolve the group if it was created. */
+ if (lazyFlag == 0 && dissolve) {
+ do {
+ j = table->subtables[x].next;
+ table->subtables[x].next = x;
+ x = j;
+ } while (x != xInit);
+ }
+ }
+
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"ddGroupSifting:");
+#endif
+
+ if (lazyFlag) ddSetVarHandled(table, xindex);
+ } /* for */
+
+ FREE(sifted);
+ FREE(var);
+ FREE(entry);
+
+ return(1);
+
+ddGroupSiftingOutOfMem:
+ if (entry != NULL) FREE(entry);
+ if (var != NULL) FREE(var);
+ if (sifted != NULL) FREE(sifted);
+
+ return(0);
+
+} /* end of ddGroupSifting */
+
+
+/**Function********************************************************************
+
+ Synopsis [Creates a group encompassing variables from x to y in the
+ DD table.]
+
+ Description [Creates a group encompassing variables from x to y in the
+ DD table. In the current implementation it must be y == x+1.
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static void
+ddCreateGroup(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int gybot;
+
+#ifdef DD_DEBUG
+ assert(y == x+1);
+#endif
+
+ /* Find bottom of second group. */
+ gybot = y;
+ while ((unsigned) gybot < table->subtables[gybot].next)
+ gybot = table->subtables[gybot].next;
+
+ /* Link groups. */
+ table->subtables[x].next = y;
+ table->subtables[gybot].next = x;
+
+ return;
+
+} /* ddCreateGroup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts one variable up and down until it has taken all
+ positions. Checks for aggregation.]
+
+ Description [Sifts one variable up and down until it has taken all
+ positions. Checks for aggregation. There may be at most two sweeps,
+ even if the group grows. Assumes that x is either an isolated
+ variable, or it is the bottom of a group. All groups may not have
+ been found. The variable being moved is returned to the best position
+ seen during sifting. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddGroupSiftingAux(
+ DdManager * table,
+ int x,
+ int xLow,
+ int xHigh,
+ int (*checkFunction)(DdManager *, int, int),
+ int lazyFlag)
+{
+ Move *move;
+ Move *moves; /* list of moves */
+ int initialSize;
+ int result;
+ int y;
+ int topbot;
+
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,
+ "ddGroupSiftingAux from %d to %d\n",xLow,xHigh);
+ assert((unsigned) x >= table->subtables[x].next); /* x is bottom of group */
+#endif
+
+ initialSize = table->keys - table->isolated;
+ moves = NULL;
+
+ originalSize = initialSize; /* for lazy sifting */
+
+ /* If we have a singleton, we check for aggregation in both
+ ** directions before we sift.
+ */
+ if ((unsigned) x == table->subtables[x].next) {
+ /* Will go down first, unless x == xHigh:
+ ** Look for aggregation above x.
+ */
+ for (y = x; y > xLow; y--) {
+ if (!checkFunction(table,y-1,y))
+ break;
+ topbot = table->subtables[y-1].next; /* find top of y-1's group */
+ table->subtables[y-1].next = y;
+ table->subtables[x].next = topbot; /* x is bottom of group so its */
+ /* next is top of y-1's group */
+ y = topbot + 1; /* add 1 for y--; new y is top of group */
+ }
+ /* Will go up first unless x == xlow:
+ ** Look for aggregation below x.
+ */
+ for (y = x; y < xHigh; y++) {
+ if (!checkFunction(table,y,y+1))
+ break;
+ /* find bottom of y+1's group */
+ topbot = y + 1;
+ while ((unsigned) topbot < table->subtables[topbot].next) {
+ topbot = table->subtables[topbot].next;
+ }
+ table->subtables[topbot].next = table->subtables[y].next;
+ table->subtables[y].next = y + 1;
+ y = topbot - 1; /* subtract 1 for y++; new y is bottom of group */
+ }
+ }
+
+ /* Now x may be in the middle of a group.
+ ** Find bottom of x's group.
+ */
+ while ((unsigned) x < table->subtables[x].next)
+ x = table->subtables[x].next;
+
+ originalLevel = x; /* for lazy sifting */
+
+ if (x == xLow) { /* Sift down */
+#ifdef DD_DEBUG
+ /* x must be a singleton */
+ assert((unsigned) x == table->subtables[x].next);
+#endif
+ if (x == xHigh) return(1); /* just one variable */
+
+ if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves))
+ goto ddGroupSiftingAuxOutOfMem;
+ /* at this point x == xHigh, unless early term */
+
+ /* move backward and stop at best position */
+ result = ddGroupSiftingBackward(table,moves,initialSize,
+ DD_SIFT_DOWN,lazyFlag);
+#ifdef DD_DEBUG
+ assert(table->keys - table->isolated <= (unsigned) initialSize);
+#endif
+ if (!result) goto ddGroupSiftingAuxOutOfMem;
+
+ } else if (cuddNextHigh(table,x) > xHigh) { /* Sift up */
+#ifdef DD_DEBUG
+ /* x is bottom of group */
+ assert((unsigned) x >= table->subtables[x].next);
+#endif
+ /* Find top of x's group */
+ x = table->subtables[x].next;
+
+ if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves))
+ goto ddGroupSiftingAuxOutOfMem;
+ /* at this point x == xLow, unless early term */
+
+ /* move backward and stop at best position */
+ result = ddGroupSiftingBackward(table,moves,initialSize,
+ DD_SIFT_UP,lazyFlag);
+#ifdef DD_DEBUG
+ assert(table->keys - table->isolated <= (unsigned) initialSize);
+#endif
+ if (!result) goto ddGroupSiftingAuxOutOfMem;
+
+ } else if (x - xLow > xHigh - x) { /* must go down first: shorter */
+ if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves))
+ goto ddGroupSiftingAuxOutOfMem;
+ /* at this point x == xHigh, unless early term */
+
+ /* Find top of group */
+ if (moves) {
+ x = moves->y;
+ }
+ while ((unsigned) x < table->subtables[x].next)
+ x = table->subtables[x].next;
+ x = table->subtables[x].next;
+#ifdef DD_DEBUG
+ /* x should be the top of a group */
+ assert((unsigned) x <= table->subtables[x].next);
+#endif
+
+ if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves))
+ goto ddGroupSiftingAuxOutOfMem;
+
+ /* move backward and stop at best position */
+ result = ddGroupSiftingBackward(table,moves,initialSize,
+ DD_SIFT_UP,lazyFlag);
+#ifdef DD_DEBUG
+ assert(table->keys - table->isolated <= (unsigned) initialSize);
+#endif
+ if (!result) goto ddGroupSiftingAuxOutOfMem;
+
+ } else { /* moving up first: shorter */
+ /* Find top of x's group */
+ x = table->subtables[x].next;
+
+ if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves))
+ goto ddGroupSiftingAuxOutOfMem;
+ /* at this point x == xHigh, unless early term */
+
+ if (moves) {
+ x = moves->x;
+ }
+ while ((unsigned) x < table->subtables[x].next)
+ x = table->subtables[x].next;
+#ifdef DD_DEBUG
+ /* x is bottom of a group */
+ assert((unsigned) x >= table->subtables[x].next);
+#endif
+
+ if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves))
+ goto ddGroupSiftingAuxOutOfMem;
+
+ /* move backward and stop at best position */
+ result = ddGroupSiftingBackward(table,moves,initialSize,
+ DD_SIFT_DOWN,lazyFlag);
+#ifdef DD_DEBUG
+ assert(table->keys - table->isolated <= (unsigned) initialSize);
+#endif
+ if (!result) goto ddGroupSiftingAuxOutOfMem;
+ }
+
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+
+ return(1);
+
+ddGroupSiftingAuxOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+
+ return(0);
+
+} /* end of ddGroupSiftingAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts up a variable until either it reaches position xLow
+ or the size of the DD heap increases too much.]
+
+ Description [Sifts up a variable until either it reaches position
+ xLow or the size of the DD heap increases too much. Assumes that y is
+ the top of a group (or a singleton). Checks y for aggregation to the
+ adjacent variables. Records all the moves that are appended to the
+ list of moves received as input and returned as a side effect.
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddGroupSiftingUp(
+ DdManager * table,
+ int y,
+ int xLow,
+ int (*checkFunction)(DdManager *, int, int),
+ Move ** moves)
+{
+ Move *move;
+ int x;
+ int size;
+ int i;
+ int gxtop,gybot;
+ int limitSize;
+ int xindex, yindex;
+ int zindex;
+ int z;
+ int isolated;
+ int L; /* lower bound on DD size */
+#ifdef DD_DEBUG
+ int checkL;
+#endif
+
+ yindex = table->invperm[y];
+
+ /* Initialize the lower bound.
+ ** The part of the DD below the bottom of y's group will not change.
+ ** The part of the DD above y that does not interact with any
+ ** variable of y's group will not change.
+ ** The rest may vanish in the best case, except for
+ ** the nodes at level xLow, which will not vanish, regardless.
+ ** What we use here is not really a lower bound, because we ignore
+ ** the interactions with all variables except y.
+ */
+ limitSize = L = table->keys - table->isolated;
+ gybot = y;
+ while ((unsigned) gybot < table->subtables[gybot].next)
+ gybot = table->subtables[gybot].next;
+ for (z = xLow + 1; z <= gybot; z++) {
+ zindex = table->invperm[z];
+ if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ L -= table->subtables[z].keys - isolated;
+ }
+ }
+
+ originalLevel = y; /* for lazy sifting */
+
+ x = cuddNextLow(table,y);
+ while (x >= xLow && L <= limitSize) {
+#ifdef DD_DEBUG
+ gybot = y;
+ while ((unsigned) gybot < table->subtables[gybot].next)
+ gybot = table->subtables[gybot].next;
+ checkL = table->keys - table->isolated;
+ for (z = xLow + 1; z <= gybot; z++) {
+ zindex = table->invperm[z];
+ if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ checkL -= table->subtables[z].keys - isolated;
+ }
+ }
+ if (pr > 0 && L != checkL) {
+ (void) fprintf(table->out,
+ "Inaccurate lower bound: L = %d checkL = %d\n",
+ L, checkL);
+ }
+#endif
+ gxtop = table->subtables[x].next;
+ if (checkFunction(table,x,y)) {
+ /* Group found, attach groups */
+ table->subtables[x].next = y;
+ i = table->subtables[y].next;
+ while (table->subtables[i].next != (unsigned) y)
+ i = table->subtables[i].next;
+ table->subtables[i].next = gxtop;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddGroupSiftingUpOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->flags = MTR_NEWNODE;
+ move->size = table->keys - table->isolated;
+ move->next = *moves;
+ *moves = move;
+ } else if (table->subtables[x].next == (unsigned) x &&
+ table->subtables[y].next == (unsigned) y) {
+ /* x and y are self groups */
+ xindex = table->invperm[x];
+ size = cuddSwapInPlace(table,x,y);
+#ifdef DD_DEBUG
+ assert(table->subtables[x].next == (unsigned) x);
+ assert(table->subtables[y].next == (unsigned) y);
+#endif
+ if (size == 0) goto ddGroupSiftingUpOutOfMem;
+ /* Update the lower bound. */
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[xindex]->ref == 1;
+ L += table->subtables[y].keys - isolated;
+ }
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddGroupSiftingUpOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->flags = MTR_DEFAULT;
+ move->size = size;
+ move->next = *moves;
+ *moves = move;
+
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,
+ "ddGroupSiftingUp (2 single groups):\n");
+#endif
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(1);
+ if (size < limitSize) limitSize = size;
+ } else { /* Group move */
+ size = ddGroupMove(table,x,y,moves);
+ if (size == 0) goto ddGroupSiftingUpOutOfMem;
+ /* Update the lower bound. */
+ z = (*moves)->y;
+ do {
+ zindex = table->invperm[z];
+ if (cuddTestInteract(table,zindex,yindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ L += table->subtables[z].keys - isolated;
+ }
+ z = table->subtables[z].next;
+ } while (z != (int) (*moves)->y);
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(1);
+ if (size < limitSize) limitSize = size;
+ }
+ y = gxtop;
+ x = cuddNextLow(table,y);
+ }
+
+ return(1);
+
+ddGroupSiftingUpOutOfMem:
+ while (*moves != NULL) {
+ move = (*moves)->next;
+ cuddDeallocNode(table, (DdNode *) *moves);
+ *moves = move;
+ }
+ return(0);
+
+} /* end of ddGroupSiftingUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts down a variable until it reaches position xHigh.]
+
+ Description [Sifts down a variable until it reaches position xHigh.
+ Assumes that x is the bottom of a group (or a singleton). Records
+ all the moves. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddGroupSiftingDown(
+ DdManager * table,
+ int x,
+ int xHigh,
+ int (*checkFunction)(DdManager *, int, int),
+ Move ** moves)
+{
+ Move *move;
+ int y;
+ int size;
+ int limitSize;
+ int gxtop,gybot;
+ int R; /* upper bound on node decrease */
+ int xindex, yindex;
+ int isolated, allVars;
+ int z;
+ int zindex;
+#ifdef DD_DEBUG
+ int checkR;
+#endif
+
+ /* If the group consists of simple variables, there is no point in
+ ** sifting it down. This check is redundant if the projection functions
+ ** do not have external references, because the computation of the
+ ** lower bound takes care of the problem. It is necessary otherwise to
+ ** prevent the sifting down of simple variables. */
+ y = x;
+ allVars = 1;
+ do {
+ if (table->subtables[y].keys != 1) {
+ allVars = 0;
+ break;
+ }
+ y = table->subtables[y].next;
+ } while (table->subtables[y].next != (unsigned) x);
+ if (allVars)
+ return(1);
+
+ /* Initialize R. */
+ xindex = table->invperm[x];
+ gxtop = table->subtables[x].next;
+ limitSize = size = table->keys - table->isolated;
+ R = 0;
+ for (z = xHigh; z > gxtop; z--) {
+ zindex = table->invperm[z];
+ if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ R += table->subtables[z].keys - isolated;
+ }
+ }
+
+ originalLevel = x; /* for lazy sifting */
+
+ y = cuddNextHigh(table,x);
+ while (y <= xHigh && size - R < limitSize) {
+#ifdef DD_DEBUG
+ gxtop = table->subtables[x].next;
+ checkR = 0;
+ for (z = xHigh; z > gxtop; z--) {
+ zindex = table->invperm[z];
+ if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ checkR += table->subtables[z].keys - isolated;
+ }
+ }
+ assert(R >= checkR);
+#endif
+ /* Find bottom of y group. */
+ gybot = table->subtables[y].next;
+ while (table->subtables[gybot].next != (unsigned) y)
+ gybot = table->subtables[gybot].next;
+
+ if (checkFunction(table,x,y)) {
+ /* Group found: attach groups and record move. */
+ gxtop = table->subtables[x].next;
+ table->subtables[x].next = y;
+ table->subtables[gybot].next = gxtop;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddGroupSiftingDownOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->flags = MTR_NEWNODE;
+ move->size = table->keys - table->isolated;
+ move->next = *moves;
+ *moves = move;
+ } else if (table->subtables[x].next == (unsigned) x &&
+ table->subtables[y].next == (unsigned) y) {
+ /* x and y are self groups */
+ /* Update upper bound on node decrease. */
+ yindex = table->invperm[y];
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[yindex]->ref == 1;
+ R -= table->subtables[y].keys - isolated;
+ }
+ size = cuddSwapInPlace(table,x,y);
+#ifdef DD_DEBUG
+ assert(table->subtables[x].next == (unsigned) x);
+ assert(table->subtables[y].next == (unsigned) y);
+#endif
+ if (size == 0) goto ddGroupSiftingDownOutOfMem;
+
+ /* Record move. */
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddGroupSiftingDownOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->flags = MTR_DEFAULT;
+ move->size = size;
+ move->next = *moves;
+ *moves = move;
+
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,
+ "ddGroupSiftingDown (2 single groups):\n");
+#endif
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(1);
+ if (size < limitSize) limitSize = size;
+
+ x = y;
+ y = cuddNextHigh(table,x);
+ } else { /* Group move */
+ /* Update upper bound on node decrease: first phase. */
+ gxtop = table->subtables[x].next;
+ z = gxtop + 1;
+ do {
+ zindex = table->invperm[z];
+ if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ R -= table->subtables[z].keys - isolated;
+ }
+ z++;
+ } while (z <= gybot);
+ size = ddGroupMove(table,x,y,moves);
+ if (size == 0) goto ddGroupSiftingDownOutOfMem;
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(1);
+ if (size < limitSize) limitSize = size;
+
+ /* Update upper bound on node decrease: second phase. */
+ gxtop = table->subtables[gybot].next;
+ for (z = gxtop + 1; z <= gybot; z++) {
+ zindex = table->invperm[z];
+ if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ R += table->subtables[z].keys - isolated;
+ }
+ }
+ }
+ x = gybot;
+ y = cuddNextHigh(table,x);
+ }
+
+ return(1);
+
+ddGroupSiftingDownOutOfMem:
+ while (*moves != NULL) {
+ move = (*moves)->next;
+ cuddDeallocNode(table, (DdNode *) *moves);
+ *moves = move;
+ }
+
+ return(0);
+
+} /* end of ddGroupSiftingDown */
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps two groups and records the move.]
+
+ Description [Swaps two groups and records the move. Returns the
+ number of keys in the DD table in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddGroupMove(
+ DdManager * table,
+ int x,
+ int y,
+ Move ** moves)
+{
+ Move *move;
+ int size;
+ int i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
+ int swapx,swapy;
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ int initialSize,bestSize;
+#endif
+
+#if DD_DEBUG
+ /* We assume that x < y */
+ assert(x < y);
+#endif
+ /* Find top, bottom, and size for the two groups. */
+ xbot = x;
+ xtop = table->subtables[x].next;
+ xsize = xbot - xtop + 1;
+ ybot = y;
+ while ((unsigned) ybot < table->subtables[ybot].next)
+ ybot = table->subtables[ybot].next;
+ ytop = y;
+ ysize = ybot - ytop + 1;
+
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ initialSize = bestSize = table->keys - table->isolated;
+#endif
+ /* Sift the variables of the second group up through the first group */
+ for (i = 1; i <= ysize; i++) {
+ for (j = 1; j <= xsize; j++) {
+ size = cuddSwapInPlace(table,x,y);
+ if (size == 0) goto ddGroupMoveOutOfMem;
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ if (size < bestSize)
+ bestSize = size;
+#endif
+ swapx = x; swapy = y;
+ y = x;
+ x = cuddNextLow(table,y);
+ }
+ y = ytop + i;
+ x = cuddNextLow(table,y);
+ }
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ if ((bestSize < initialSize) && (bestSize < size))
+ (void) fprintf(table->out,"Missed local minimum: initialSize:%d bestSize:%d finalSize:%d\n",initialSize,bestSize,size);
+#endif
+
+ /* fix groups */
+ y = xtop; /* ytop is now where xtop used to be */
+ for (i = 0; i < ysize - 1; i++) {
+ table->subtables[y].next = cuddNextHigh(table,y);
+ y = cuddNextHigh(table,y);
+ }
+ table->subtables[y].next = xtop; /* y is bottom of its group, join */
+ /* it to top of its group */
+ x = cuddNextHigh(table,y);
+ newxtop = x;
+ for (i = 0; i < xsize - 1; i++) {
+ table->subtables[x].next = cuddNextHigh(table,x);
+ x = cuddNextHigh(table,x);
+ }
+ table->subtables[x].next = newxtop; /* x is bottom of its group, join */
+ /* it to top of its group */
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"ddGroupMove:\n");
+#endif
+
+ /* Store group move */
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddGroupMoveOutOfMem;
+ move->x = swapx;
+ move->y = swapy;
+ move->flags = MTR_DEFAULT;
+ move->size = table->keys - table->isolated;
+ move->next = *moves;
+ *moves = move;
+
+ return(table->keys - table->isolated);
+
+ddGroupMoveOutOfMem:
+ while (*moves != NULL) {
+ move = (*moves)->next;
+ cuddDeallocNode(table, (DdNode *) *moves);
+ *moves = move;
+ }
+ return(0);
+
+} /* end of ddGroupMove */
+
+
+/**Function********************************************************************
+
+ Synopsis [Undoes the swap two groups.]
+
+ Description [Undoes the swap two groups. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddGroupMoveBackward(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int size;
+ int i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
+
+
+#if DD_DEBUG
+ /* We assume that x < y */
+ assert(x < y);
+#endif
+
+ /* Find top, bottom, and size for the two groups. */
+ xbot = x;
+ xtop = table->subtables[x].next;
+ xsize = xbot - xtop + 1;
+ ybot = y;
+ while ((unsigned) ybot < table->subtables[ybot].next)
+ ybot = table->subtables[ybot].next;
+ ytop = y;
+ ysize = ybot - ytop + 1;
+
+ /* Sift the variables of the second group up through the first group */
+ for (i = 1; i <= ysize; i++) {
+ for (j = 1; j <= xsize; j++) {
+ size = cuddSwapInPlace(table,x,y);
+ if (size == 0)
+ return(0);
+ y = x;
+ x = cuddNextLow(table,y);
+ }
+ y = ytop + i;
+ x = cuddNextLow(table,y);
+ }
+
+ /* fix groups */
+ y = xtop;
+ for (i = 0; i < ysize - 1; i++) {
+ table->subtables[y].next = cuddNextHigh(table,y);
+ y = cuddNextHigh(table,y);
+ }
+ table->subtables[y].next = xtop; /* y is bottom of its group, join */
+ /* to its top */
+ x = cuddNextHigh(table,y);
+ newxtop = x;
+ for (i = 0; i < xsize - 1; i++) {
+ table->subtables[x].next = cuddNextHigh(table,x);
+ x = cuddNextHigh(table,x);
+ }
+ table->subtables[x].next = newxtop; /* x is bottom of its group, join */
+ /* to its top */
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"ddGroupMoveBackward:\n");
+#endif
+
+ return(1);
+
+} /* end of ddGroupMoveBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Determines the best position for a variables and returns
+ it there.]
+
+ Description [Determines the best position for a variables and returns
+ it there. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddGroupSiftingBackward(
+ DdManager * table,
+ Move * moves,
+ int size,
+ int upFlag,
+ int lazyFlag)
+{
+ Move *move;
+ int res;
+ Move *end_move;
+ int diff, tmp_diff;
+ int index, pairlev;
+
+ if (lazyFlag) {
+ end_move = NULL;
+
+ /* Find the minimum size, and the earliest position at which it
+ ** was achieved. */
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size < size) {
+ size = move->size;
+ end_move = move;
+ } else if (move->size == size) {
+ if (end_move == NULL) end_move = move;
+ }
+ }
+
+ /* Find among the moves that give minimum size the one that
+ ** minimizes the distance from the corresponding variable. */
+ if (moves != NULL) {
+ diff = Cudd_ReadSize(table) + 1;
+ index = (upFlag == 1) ?
+ table->invperm[moves->x] : table->invperm[moves->y];
+ pairlev = table->perm[Cudd_bddReadPairIndex(table, index)];
+
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size == size) {
+ if (upFlag == 1) {
+ tmp_diff = (move->x > pairlev) ?
+ move->x - pairlev : pairlev - move->x;
+ } else {
+ tmp_diff = (move->y > pairlev) ?
+ move->y - pairlev : pairlev - move->y;
+ }
+ if (tmp_diff < diff) {
+ diff = tmp_diff;
+ end_move = move;
+ }
+ }
+ }
+ }
+ } else {
+ /* Find the minimum size. */
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size < size) {
+ size = move->size;
+ }
+ }
+ }
+
+ /* In case of lazy sifting, end_move identifies the position at
+ ** which we want to stop. Otherwise, we stop as soon as we meet
+ ** the minimum size. */
+ for (move = moves; move != NULL; move = move->next) {
+ if (lazyFlag) {
+ if (move == end_move) return(1);
+ } else {
+ if (move->size == size) return(1);
+ }
+ if ((table->subtables[move->x].next == move->x) &&
+ (table->subtables[move->y].next == move->y)) {
+ res = cuddSwapInPlace(table,(int)move->x,(int)move->y);
+ if (!res) return(0);
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"ddGroupSiftingBackward:\n");
+ assert(table->subtables[move->x].next == move->x);
+ assert(table->subtables[move->y].next == move->y);
+#endif
+ } else { /* Group move necessary */
+ if (move->flags == MTR_NEWNODE) {
+ ddDissolveGroup(table,(int)move->x,(int)move->y);
+ } else {
+ res = ddGroupMoveBackward(table,(int)move->x,(int)move->y);
+ if (!res) return(0);
+ }
+ }
+
+ }
+
+ return(1);
+
+} /* end of ddGroupSiftingBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Merges groups in the DD table.]
+
+ Description [Creates a single group from low to high and adjusts the
+ index field of the tree node.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static void
+ddMergeGroups(
+ DdManager * table,
+ MtrNode * treenode,
+ int low,
+ int high)
+{
+ int i;
+ MtrNode *auxnode;
+ int saveindex;
+ int newindex;
+
+ /* Merge all variables from low to high in one group, unless
+ ** this is the topmost group. In such a case we do not merge lest
+ ** we lose the symmetry information. */
+ if (treenode != table->tree) {
+ for (i = low; i < high; i++)
+ table->subtables[i].next = i+1;
+ table->subtables[high].next = low;
+ }
+
+ /* Adjust the index fields of the tree nodes. If a node is the
+ ** first child of its parent, then the parent may also need adjustment. */
+ saveindex = treenode->index;
+ newindex = table->invperm[low];
+ auxnode = treenode;
+ do {
+ auxnode->index = newindex;
+ if (auxnode->parent == NULL ||
+ (int) auxnode->parent->index != saveindex)
+ break;
+ auxnode = auxnode->parent;
+ } while (1);
+ return;
+
+} /* end of ddMergeGroups */
+
+
+/**Function********************************************************************
+
+ Synopsis [Dissolves a group in the DD table.]
+
+ Description [x and y are variables in a group to be cut in two. The cut
+ is to pass between x and y.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static void
+ddDissolveGroup(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int topx;
+ int boty;
+
+ /* find top and bottom of the two groups */
+ boty = y;
+ while ((unsigned) boty < table->subtables[boty].next)
+ boty = table->subtables[boty].next;
+
+ topx = table->subtables[boty].next;
+
+ table->subtables[boty].next = y;
+ table->subtables[x].next = topx;
+
+ return;
+
+} /* end of ddDissolveGroup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Pretends to check two variables for aggregation.]
+
+ Description [Pretends to check two variables for aggregation. Always
+ returns 0.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddNoCheck(
+ DdManager * table,
+ int x,
+ int y)
+{
+ return(0);
+
+} /* end of ddNoCheck */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks two variables for aggregation.]
+
+ Description [Checks two variables for aggregation. The check is based
+ on the second difference of the number of nodes as a function of the
+ layer. If the second difference is lower than a given threshold
+ (typically negative) then the two variables should be aggregated.
+ Returns 1 if the two variables pass the test; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddSecDiffCheck(
+ DdManager * table,
+ int x,
+ int y)
+{
+ double Nx,Nx_1;
+ double Sx;
+ double threshold;
+ int xindex,yindex;
+
+ if (x==0) return(0);
+
+#ifdef DD_STATS
+ secdiffcalls++;
+#endif
+ Nx = (double) table->subtables[x].keys;
+ Nx_1 = (double) table->subtables[x-1].keys;
+ Sx = (table->subtables[y].keys/Nx) - (Nx/Nx_1);
+
+ threshold = table->recomb / 100.0;
+ if (Sx < threshold) {
+ xindex = table->invperm[x];
+ yindex = table->invperm[y];
+ if (cuddTestInteract(table,xindex,yindex)) {
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ (void) fprintf(table->out,
+ "Second difference for %d = %g Pos(%d)\n",
+ table->invperm[x],Sx,x);
+#endif
+#ifdef DD_STATS
+ secdiff++;
+#endif
+ return(1);
+ } else {
+#ifdef DD_STATS
+ secdiffmisfire++;
+#endif
+ return(0);
+ }
+
+ }
+ return(0);
+
+} /* end of ddSecDiffCheck */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks for extended symmetry of x and y.]
+
+ Description [Checks for extended symmetry of x and y. Returns 1 in
+ case of extended symmetry; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddExtSymmCheck(
+ DdManager * table,
+ int x,
+ int y)
+{
+ DdNode *f,*f0,*f1,*f01,*f00,*f11,*f10;
+ DdNode *one;
+ int comple; /* f0 is complemented */
+ int notproj; /* f is not a projection function */
+ int arccount; /* number of arcs from layer x to layer y */
+ int TotalRefCount; /* total reference count of layer y minus 1 */
+ int counter; /* number of nodes of layer x that are allowed */
+ /* to violate extended symmetry conditions */
+ int arccounter; /* number of arcs into layer y that are allowed */
+ /* to come from layers other than x */
+ int i;
+ int xindex;
+ int yindex;
+ int res;
+ int slots;
+ DdNodePtr *list;
+ DdNode *sentinel = &(table->sentinel);
+
+ xindex = table->invperm[x];
+ yindex = table->invperm[y];
+
+ /* If the two variables do not interact, we do not want to merge them. */
+ if (!cuddTestInteract(table,xindex,yindex))
+ return(0);
+
+#ifdef DD_DEBUG
+ /* Checks that x and y do not contain just the projection functions.
+ ** With the test on interaction, these test become redundant,
+ ** because an isolated projection function does not interact with
+ ** any other variable.
+ */
+ if (table->subtables[x].keys == 1) {
+ assert(table->vars[xindex]->ref != 1);
+ }
+ if (table->subtables[y].keys == 1) {
+ assert(table->vars[yindex]->ref != 1);
+ }
+#endif
+
+#ifdef DD_STATS
+ extsymmcalls++;
+#endif
+
+ arccount = 0;
+ counter = (int) (table->subtables[x].keys *
+ (table->symmviolation/100.0) + 0.5);
+ one = DD_ONE(table);
+
+ slots = table->subtables[x].slots;
+ list = table->subtables[x].nodelist;
+ for (i = 0; i < slots; i++) {
+ f = list[i];
+ while (f != sentinel) {
+ /* Find f1, f0, f11, f10, f01, f00. */
+ f1 = cuddT(f);
+ f0 = Cudd_Regular(cuddE(f));
+ comple = Cudd_IsComplement(cuddE(f));
+ notproj = f1 != one || f0 != one || f->ref != (DdHalfWord) 1;
+ if (f1->index == yindex) {
+ arccount++;
+ f11 = cuddT(f1); f10 = cuddE(f1);
+ } else {
+ if ((int) f0->index != yindex) {
+ /* If f is an isolated projection function it is
+ ** allowed to bypass layer y.
+ */
+ if (notproj) {
+ if (counter == 0)
+ return(0);
+ counter--; /* f bypasses layer y */
+ }
+ }
+ f11 = f10 = f1;
+ }
+ if ((int) f0->index == yindex) {
+ arccount++;
+ f01 = cuddT(f0); f00 = cuddE(f0);
+ } else {
+ f01 = f00 = f0;
+ }
+ if (comple) {
+ f01 = Cudd_Not(f01);
+ f00 = Cudd_Not(f00);
+ }
+
+ /* Unless we are looking at a projection function
+ ** without external references except the one from the
+ ** table, we insist that f01 == f10 or f11 == f00
+ */
+ if (notproj) {
+ if (f01 != f10 && f11 != f00) {
+ if (counter == 0)
+ return(0);
+ counter--;
+ }
+ }
+
+ f = f->next;
+ } /* while */
+ } /* for */
+
+ /* Calculate the total reference counts of y */
+ TotalRefCount = -1; /* -1 for projection function */
+ slots = table->subtables[y].slots;
+ list = table->subtables[y].nodelist;
+ for (i = 0; i < slots; i++) {
+ f = list[i];
+ while (f != sentinel) {
+ TotalRefCount += f->ref;
+ f = f->next;
+ }
+ }
+
+ arccounter = (int) (table->subtables[y].keys *
+ (table->arcviolation/100.0) + 0.5);
+ res = arccount >= TotalRefCount - arccounter;
+
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ if (res) {
+ (void) fprintf(table->out,
+ "Found extended symmetry! x = %d\ty = %d\tPos(%d,%d)\n",
+ xindex,yindex,x,y);
+ }
+#endif
+
+#ifdef DD_STATS
+ if (res)
+ extsymm++;
+#endif
+ return(res);
+
+} /* end ddExtSymmCheck */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks for grouping of x and y.]
+
+ Description [Checks for grouping of x and y. Returns 1 in
+ case of grouping; 0 otherwise. This function is used for lazy sifting.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddVarGroupCheck(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int xindex = table->invperm[x];
+ int yindex = table->invperm[y];
+
+ if (Cudd_bddIsVarToBeUngrouped(table, xindex)) return(0);
+
+ if (Cudd_bddReadPairIndex(table, xindex) == yindex) {
+ if (ddIsVarHandled(table, xindex) ||
+ ddIsVarHandled(table, yindex)) {
+ if (Cudd_bddIsVarToBeGrouped(table, xindex) ||
+ Cudd_bddIsVarToBeGrouped(table, yindex) ) {
+ if (table->keys - table->isolated <= originalSize) {
+ return(1);
+ }
+ }
+ }
+ }
+
+ return(0);
+
+} /* end of ddVarGroupCheck */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets a variable to already handled.]
+
+ Description [Sets a variable to already handled. This function is used
+ for lazy sifting.]
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddSetVarHandled(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return(0);
+ dd->subtables[dd->perm[index]].varHandled = 1;
+ return(1);
+
+} /* end of ddSetVarHandled */
+
+
+/**Function********************************************************************
+
+ Synopsis [Resets a variable to be processed.]
+
+ Description [Resets a variable to be processed. This function is used
+ for lazy sifting.]
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddResetVarHandled(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return(0);
+ dd->subtables[dd->perm[index]].varHandled = 0;
+ return(1);
+
+} /* end of ddResetVarHandled */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether a variables is already handled.]
+
+ Description [Checks whether a variables is already handled. This
+ function is used for lazy sifting.]
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddIsVarHandled(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return(-1);
+ return dd->subtables[dd->perm[index]].varHandled;
+
+} /* end of ddIsVarHandled */
diff --git a/src/bdd/cudd/cuddHarwell.c b/src/bdd/cudd/cuddHarwell.c
new file mode 100644
index 00000000..10746186
--- /dev/null
+++ b/src/bdd/cudd/cuddHarwell.c
@@ -0,0 +1,541 @@
+/**CFile***********************************************************************
+
+ FileName [cuddHarwell.c]
+
+ PackageName [cudd]
+
+ Synopsis [Function to read a matrix in Harwell format.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_addHarwell()
+ </ul>
+ ]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddHarwell.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Reads in a matrix in the format of the Harwell-Boeing
+ benchmark suite.]
+
+ Description [Reads in a matrix in the format of the Harwell-Boeing
+ benchmark suite. The variables are ordered as follows:
+ <blockquote>
+ x\[0\] y\[0\] x\[1\] y\[1\] ...
+ </blockquote>
+ 0 is the most significant bit. On input, nx and ny hold the numbers
+ of row and column variables already in existence. On output, they
+ hold the numbers of row and column variables actually used by the
+ matrix. m and n are set to the numbers of rows and columns of the
+ matrix. Their values on input are immaterial. Returns 1 on
+ success; 0 otherwise. The ADD for the sparse matrix is returned in
+ E, and its reference count is > 0.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addRead Cudd_bddRead]
+
+******************************************************************************/
+int
+Cudd_addHarwell(
+ FILE * fp /* pointer to the input file */,
+ DdManager * dd /* DD manager */,
+ DdNode ** E /* characteristic function of the graph */,
+ DdNode *** x /* array of row variables */,
+ DdNode *** y /* array of column variables */,
+ DdNode *** xn /* array of complemented row variables */,
+ DdNode *** yn_ /* array of complemented column variables */,
+ int * nx /* number or row variables */,
+ int * ny /* number or column variables */,
+ int * m /* number of rows */,
+ int * n /* number of columns */,
+ int bx /* first index of row variables */,
+ int sx /* step of row variables */,
+ int by /* first index of column variables */,
+ int sy /* step of column variables */,
+ int pr /* verbosity level */)
+{
+ DdNode *one, *zero;
+ DdNode *w;
+ DdNode *cubex, *cubey, *minterm1;
+ int u, v, err, i, j, nv;
+ double val;
+ DdNode **lx, **ly, **lxn, **lyn; /* local copies of x, y, xn, yn_ */
+ int lnx, lny; /* local copies of nx and ny */
+ char title[73], key[9], mxtype[4], rhstyp[4];
+ int totcrd, ptrcrd, indcrd, valcrd, rhscrd,
+ nrow, ncol, nnzero, neltvl,
+ nrhs, nrhsix;
+ int *colptr, *rowind;
+#if 0
+ int nguess, nexact;
+ int *rhsptr, *rhsind;
+#endif
+
+ if (*nx < 0 || *ny < 0) return(0);
+
+ one = DD_ONE(dd);
+ zero = DD_ZERO(dd);
+
+ /* Read the header */
+ err = fscanf(fp, "%72c %8c", title, key);
+ if (err == EOF) {
+ return(0);
+ } else if (err != 2) {
+ return(0);
+ }
+ title[72] = (char) 0;
+ key[8] = (char) 0;
+
+ err = fscanf(fp, "%d %d %d %d %d", &totcrd, &ptrcrd, &indcrd,
+ &valcrd, &rhscrd);
+ if (err == EOF) {
+ return(0);
+ } else if (err != 5) {
+ return(0);
+ }
+
+ err = fscanf(fp, "%3s %d %d %d %d", mxtype, &nrow, &ncol,
+ &nnzero, &neltvl);
+ if (err == EOF) {
+ return(0);
+ } else if (err != 5) {
+ return(0);
+ }
+
+ /* Skip FORTRAN formats */
+ if (rhscrd == 0) {
+ err = fscanf(fp, "%*s %*s %*s \n");
+ } else {
+ err = fscanf(fp, "%*s %*s %*s %*s \n");
+ }
+ if (err == EOF) {
+ return(0);
+ } else if (err != 0) {
+ return(0);
+ }
+
+ /* Print out some stuff if requested to be verbose */
+ if (pr>0) {
+ (void) fprintf(dd->out,"%s: type %s, %d rows, %d columns, %d entries\n", key,
+ mxtype, nrow, ncol, nnzero);
+ if (pr>1) (void) fprintf(dd->out,"%s\n", title);
+ }
+
+ /* Check matrix type */
+ if (mxtype[0] != 'R' || mxtype[1] != 'U' || mxtype[2] != 'A') {
+ (void) fprintf(dd->err,"%s: Illegal matrix type: %s\n",
+ key, mxtype);
+ return(0);
+ }
+ if (neltvl != 0) return(0);
+
+ /* Read optional 5-th line */
+ if (rhscrd != 0) {
+ err = fscanf(fp, "%3c %d %d", rhstyp, &nrhs, &nrhsix);
+ if (err == EOF) {
+ return(0);
+ } else if (err != 3) {
+ return(0);
+ }
+ rhstyp[3] = (char) 0;
+ if (rhstyp[0] != 'F') {
+ (void) fprintf(dd->err,
+ "%s: Sparse right-hand side not yet supported\n", key);
+ return(0);
+ }
+ if (pr>0) (void) fprintf(dd->out,"%d right-hand side(s)\n", nrhs);
+ } else {
+ nrhs = 0;
+ }
+
+ /* Compute the number of variables */
+
+ /* row and column numbers start from 0 */
+ u = nrow - 1;
+ for (i=0; u > 0; i++) {
+ u >>= 1;
+ }
+ lnx = i;
+ if (nrhs == 0) {
+ v = ncol - 1;
+ } else {
+ v = 2* (ddMax(ncol, nrhs) - 1);
+ }
+ for (i=0; v > 0; i++) {
+ v >>= 1;
+ }
+ lny = i;
+
+ /* Allocate or reallocate arrays for variables as needed */
+ if (*nx == 0) {
+ if (lnx > 0) {
+ *x = lx = ALLOC(DdNode *,lnx);
+ if (lx == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ *xn = lxn = ALLOC(DdNode *,lnx);
+ if (lxn == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ } else {
+ *x = *xn = NULL;
+ }
+ } else if (lnx > *nx) {
+ *x = lx = REALLOC(DdNode *, *x, lnx);
+ if (lx == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ *xn = lxn = REALLOC(DdNode *, *xn, lnx);
+ if (lxn == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ } else {
+ lx = *x;
+ lxn = *xn;
+ }
+ if (*ny == 0) {
+ if (lny >0) {
+ *y = ly = ALLOC(DdNode *,lny);
+ if (ly == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ *yn_ = lyn = ALLOC(DdNode *,lny);
+ if (lyn == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ } else {
+ *y = *yn_ = NULL;
+ }
+ } else if (lny > *ny) {
+ *y = ly = REALLOC(DdNode *, *y, lny);
+ if (ly == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ *yn_ = lyn = REALLOC(DdNode *, *yn_, lny);
+ if (lyn == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ } else {
+ ly = *y;
+ lyn = *yn_;
+ }
+
+ /* Create new variables as needed */
+ for (i= *nx,nv=bx+(*nx)*sx; i < lnx; i++,nv+=sx) {
+ do {
+ dd->reordered = 0;
+ lx[i] = cuddUniqueInter(dd, nv, one, zero);
+ } while (dd->reordered == 1);
+ if (lx[i] == NULL) return(0);
+ cuddRef(lx[i]);
+ do {
+ dd->reordered = 0;
+ lxn[i] = cuddUniqueInter(dd, nv, zero, one);
+ } while (dd->reordered == 1);
+ if (lxn[i] == NULL) return(0);
+ cuddRef(lxn[i]);
+ }
+ for (i= *ny,nv=by+(*ny)*sy; i < lny; i++,nv+=sy) {
+ do {
+ dd->reordered = 0;
+ ly[i] = cuddUniqueInter(dd, nv, one, zero);
+ } while (dd->reordered == 1);
+ if (ly[i] == NULL) return(0);
+ cuddRef(ly[i]);
+ do {
+ dd->reordered = 0;
+ lyn[i] = cuddUniqueInter(dd, nv, zero, one);
+ } while (dd->reordered == 1);
+ if (lyn[i] == NULL) return(0);
+ cuddRef(lyn[i]);
+ }
+
+ /* Update matrix parameters */
+ *nx = lnx;
+ *ny = lny;
+ *m = nrow;
+ if (nrhs == 0) {
+ *n = ncol;
+ } else {
+ *n = (1 << (lny - 1)) + nrhs;
+ }
+
+ /* Read structure data */
+ colptr = ALLOC(int, ncol+1);
+ if (colptr == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ rowind = ALLOC(int, nnzero);
+ if (rowind == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+
+ for (i=0; i<ncol+1; i++) {
+ err = fscanf(fp, " %d ", &u);
+ if (err == EOF){
+ FREE(colptr);
+ FREE(rowind);
+ return(0);
+ } else if (err != 1) {
+ FREE(colptr);
+ FREE(rowind);
+ return(0);
+ }
+ colptr[i] = u - 1;
+ }
+ if (colptr[0] != 0) {
+ (void) fprintf(dd->err,"%s: Unexpected colptr[0] (%d)\n",
+ key,colptr[0]);
+ FREE(colptr);
+ FREE(rowind);
+ return(0);
+ }
+ for (i=0; i<nnzero; i++) {
+ err = fscanf(fp, " %d ", &u);
+ if (err == EOF){
+ FREE(colptr);
+ FREE(rowind);
+ return(0);
+ } else if (err != 1) {
+ FREE(colptr);
+ FREE(rowind);
+ return(0);
+ }
+ rowind[i] = u - 1;
+ }
+
+ *E = zero; cuddRef(*E);
+
+ for (j=0; j<ncol; j++) {
+ v = j;
+ cubey = one; cuddRef(cubey);
+ for (nv = lny - 1; nv>=0; nv--) {
+ if (v & 1) {
+ w = Cudd_addApply(dd, Cudd_addTimes, cubey, ly[nv]);
+ } else {
+ w = Cudd_addApply(dd, Cudd_addTimes, cubey, lyn[nv]);
+ }
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, cubey);
+ FREE(colptr);
+ FREE(rowind);
+ return(0);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, cubey);
+ cubey = w;
+ v >>= 1;
+ }
+ for (i=colptr[j]; i<colptr[j+1]; i++) {
+ u = rowind[i];
+ err = fscanf(fp, " %lf ", &val);
+ if (err == EOF || err != 1){
+ Cudd_RecursiveDeref(dd, cubey);
+ FREE(colptr);
+ FREE(rowind);
+ return(0);
+ }
+ /* Create new Constant node if necessary */
+ cubex = cuddUniqueConst(dd, (CUDD_VALUE_TYPE) val);
+ if (cubex == NULL) {
+ Cudd_RecursiveDeref(dd, cubey);
+ FREE(colptr);
+ FREE(rowind);
+ return(0);
+ }
+ cuddRef(cubex);
+
+ for (nv = lnx - 1; nv>=0; nv--) {
+ if (u & 1) {
+ w = Cudd_addApply(dd, Cudd_addTimes, cubex, lx[nv]);
+ } else {
+ w = Cudd_addApply(dd, Cudd_addTimes, cubex, lxn[nv]);
+ }
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, cubey);
+ Cudd_RecursiveDeref(dd, cubex);
+ FREE(colptr);
+ FREE(rowind);
+ return(0);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, cubex);
+ cubex = w;
+ u >>= 1;
+ }
+ minterm1 = Cudd_addApply(dd, Cudd_addTimes, cubey, cubex);
+ if (minterm1 == NULL) {
+ Cudd_RecursiveDeref(dd, cubey);
+ Cudd_RecursiveDeref(dd, cubex);
+ FREE(colptr);
+ FREE(rowind);
+ return(0);
+ }
+ cuddRef(minterm1);
+ Cudd_RecursiveDeref(dd, cubex);
+ w = Cudd_addApply(dd, Cudd_addPlus, *E, minterm1);
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, cubey);
+ FREE(colptr);
+ FREE(rowind);
+ return(0);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, minterm1);
+ Cudd_RecursiveDeref(dd, *E);
+ *E = w;
+ }
+ Cudd_RecursiveDeref(dd, cubey);
+ }
+ FREE(colptr);
+ FREE(rowind);
+
+ /* Read right-hand sides */
+ for (j=0; j<nrhs; j++) {
+ v = j + (1<< (lny-1));
+ cubey = one; cuddRef(cubey);
+ for (nv = lny - 1; nv>=0; nv--) {
+ if (v & 1) {
+ w = Cudd_addApply(dd, Cudd_addTimes, cubey, ly[nv]);
+ } else {
+ w = Cudd_addApply(dd, Cudd_addTimes, cubey, lyn[nv]);
+ }
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, cubey);
+ return(0);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, cubey);
+ cubey = w;
+ v >>= 1;
+ }
+ for (i=0; i<nrow; i++) {
+ u = i;
+ err = fscanf(fp, " %lf ", &val);
+ if (err == EOF || err != 1){
+ Cudd_RecursiveDeref(dd, cubey);
+ return(0);
+ }
+ /* Create new Constant node if necessary */
+ if (val == (double) 0.0) continue;
+ cubex = cuddUniqueConst(dd, (CUDD_VALUE_TYPE) val);
+ if (cubex == NULL) {
+ Cudd_RecursiveDeref(dd, cubey);
+ return(0);
+ }
+ cuddRef(cubex);
+
+ for (nv = lnx - 1; nv>=0; nv--) {
+ if (u & 1) {
+ w = Cudd_addApply(dd, Cudd_addTimes, cubex, lx[nv]);
+ } else {
+ w = Cudd_addApply(dd, Cudd_addTimes, cubex, lxn[nv]);
+ }
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, cubey);
+ Cudd_RecursiveDeref(dd, cubex);
+ return(0);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, cubex);
+ cubex = w;
+ u >>= 1;
+ }
+ minterm1 = Cudd_addApply(dd, Cudd_addTimes, cubey, cubex);
+ if (minterm1 == NULL) {
+ Cudd_RecursiveDeref(dd, cubey);
+ Cudd_RecursiveDeref(dd, cubex);
+ return(0);
+ }
+ cuddRef(minterm1);
+ Cudd_RecursiveDeref(dd, cubex);
+ w = Cudd_addApply(dd, Cudd_addPlus, *E, minterm1);
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, cubey);
+ return(0);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, minterm1);
+ Cudd_RecursiveDeref(dd, *E);
+ *E = w;
+ }
+ Cudd_RecursiveDeref(dd, cubey);
+ }
+
+ return(1);
+
+} /* end of Cudd_addHarwell */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/cudd/cuddInit.c b/src/bdd/cudd/cuddInit.c
new file mode 100644
index 00000000..aec8d286
--- /dev/null
+++ b/src/bdd/cudd/cuddInit.c
@@ -0,0 +1,283 @@
+/**CFile***********************************************************************
+
+ FileName [cuddInit.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions to initialize and shut down the DD manager.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_Init()
+ <li> Cudd_Quit()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddZddInitUniv()
+ <li> cuddZddFreeUniv()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#define CUDD_MAIN
+#include "cuddInt.h"
+#undef CUDD_MAIN
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddInit.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Creates a new DD manager.]
+
+ Description [Creates a new DD manager, initializes the table, the
+ basic constants and the projection functions. If maxMemory is 0,
+ Cudd_Init decides suitable values for the maximum size of the cache
+ and for the limit for fast unique table growth based on the available
+ memory. Returns a pointer to the manager if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Quit]
+
+******************************************************************************/
+DdManager *
+Cudd_Init(
+ unsigned int numVars /* initial number of BDD variables (i.e., subtables) */,
+ unsigned int numVarsZ /* initial number of ZDD variables (i.e., subtables) */,
+ unsigned int numSlots /* initial size of the unique tables */,
+ unsigned int cacheSize /* initial size of the cache */,
+ unsigned long maxMemory /* target maximum memory occupation */)
+{
+ DdManager *unique;
+ int i,result;
+ DdNode *one, *zero;
+ unsigned int maxCacheSize;
+ unsigned int looseUpTo;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+
+ if (maxMemory == 0) {
+ maxMemory = getSoftDataLimit();
+ }
+ looseUpTo = (unsigned int) ((maxMemory / sizeof(DdNode)) /
+ DD_MAX_LOOSE_FRACTION);
+ unique = cuddInitTable(numVars,numVarsZ,numSlots,looseUpTo);
+ unique->maxmem = (unsigned) maxMemory / 10 * 9;
+ if (unique == NULL) return(NULL);
+ maxCacheSize = (unsigned int) ((maxMemory / sizeof(DdCache)) /
+ DD_MAX_CACHE_FRACTION);
+ result = cuddInitCache(unique,cacheSize,maxCacheSize);
+ if (result == 0) return(NULL);
+
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ unique->stash = ALLOC(char,(maxMemory / DD_STASH_FRACTION) + 4);
+ MMoutOfMemory = saveHandler;
+ if (unique->stash == NULL) {
+ (void) fprintf(unique->err,"Unable to set aside memory\n");
+ }
+
+ /* Initialize constants. */
+ unique->one = cuddUniqueConst(unique,1.0);
+ if (unique->one == NULL) return(0);
+ cuddRef(unique->one);
+ unique->zero = cuddUniqueConst(unique,0.0);
+ if (unique->zero == NULL) return(0);
+ cuddRef(unique->zero);
+#ifdef HAVE_IEEE_754
+ if (DD_PLUS_INF_VAL != DD_PLUS_INF_VAL * 3 ||
+ DD_PLUS_INF_VAL != DD_PLUS_INF_VAL / 3) {
+ (void) fprintf(unique->err,"Warning: Crippled infinite values\n");
+ (void) fprintf(unique->err,"Recompile without -DHAVE_IEEE_754\n");
+ }
+#endif
+ unique->plusinfinity = cuddUniqueConst(unique,DD_PLUS_INF_VAL);
+ if (unique->plusinfinity == NULL) return(0);
+ cuddRef(unique->plusinfinity);
+ unique->minusinfinity = cuddUniqueConst(unique,DD_MINUS_INF_VAL);
+ if (unique->minusinfinity == NULL) return(0);
+ cuddRef(unique->minusinfinity);
+ unique->background = unique->zero;
+
+ /* The logical zero is different from the CUDD_VALUE_TYPE zero! */
+ one = unique->one;
+ zero = Cudd_Not(one);
+ /* Create the projection functions. */
+ unique->vars = ALLOC(DdNodePtr,unique->maxSize);
+ if (unique->vars == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < unique->size; i++) {
+ unique->vars[i] = cuddUniqueInter(unique,i,one,zero);
+ if (unique->vars[i] == NULL) return(0);
+ cuddRef(unique->vars[i]);
+ }
+
+ if (unique->sizeZ)
+ cuddZddInitUniv(unique);
+
+ unique->memused += sizeof(DdNode *) * unique->maxSize;
+
+ return(unique);
+
+} /* end of Cudd_Init */
+
+
+/**Function********************************************************************
+
+ Synopsis [Deletes resources associated with a DD manager.]
+
+ Description [Deletes resources associated with a DD manager and
+ resets the global statistical counters. (Otherwise, another manaqger
+ subsequently created would inherit the stats of this one.)]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Init]
+
+******************************************************************************/
+void
+Cudd_Quit(
+ DdManager * unique)
+{
+ if (unique->stash != NULL) FREE(unique->stash);
+ cuddFreeTable(unique);
+
+} /* end of Cudd_Quit */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Initializes the ZDD universe.]
+
+ Description [Initializes the ZDD universe. Returns 1 if successful; 0
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddZddFreeUniv]
+
+******************************************************************************/
+int
+cuddZddInitUniv(
+ DdManager * zdd)
+{
+ DdNode *p, *res;
+ int i;
+
+ zdd->univ = ALLOC(DdNodePtr, zdd->sizeZ);
+ if (zdd->univ == NULL) {
+ zdd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+
+ res = DD_ONE(zdd);
+ cuddRef(res);
+ for (i = zdd->sizeZ - 1; i >= 0; i--) {
+ unsigned int index = zdd->invpermZ[i];
+ p = res;
+ res = cuddUniqueInterZdd(zdd, index, p, p);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(zdd,p);
+ FREE(zdd->univ);
+ return(0);
+ }
+ cuddRef(res);
+ cuddDeref(p);
+ zdd->univ[i] = res;
+ }
+
+#ifdef DD_VERBOSE
+ cuddZddP(zdd, zdd->univ[0]);
+#endif
+
+ return(1);
+
+} /* end of cuddZddInitUniv */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees the ZDD universe.]
+
+ Description [Frees the ZDD universe.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddZddInitUniv]
+
+******************************************************************************/
+void
+cuddZddFreeUniv(
+ DdManager * zdd)
+{
+ if (zdd->univ) {
+ Cudd_RecursiveDerefZdd(zdd, zdd->univ[0]);
+ FREE(zdd->univ);
+ }
+
+} /* end of cuddZddFreeUniv */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/cudd/cuddInt.h b/src/bdd/cudd/cuddInt.h
new file mode 100644
index 00000000..a5d0cf16
--- /dev/null
+++ b/src/bdd/cudd/cuddInt.h
@@ -0,0 +1,1133 @@
+/**CHeaderFile*****************************************************************
+
+ FileName [cuddInt.h]
+
+ PackageName [cudd]
+
+ Synopsis [Internal data structures of the CUDD package.]
+
+ Description []
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+ Revision [$Id: cuddInt.h,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $]
+
+******************************************************************************/
+
+#ifndef _CUDDINT
+#define _CUDDINT
+
+
+/*---------------------------------------------------------------------------*/
+/* Nested includes */
+/*---------------------------------------------------------------------------*/
+
+#ifdef DD_MIS
+#include "array.h"
+#include "list.h"
+#include "st.h"
+#include "espresso.h"
+#include "node.h"
+#ifdef SIS
+#include "graph.h"
+#include "astg.h"
+#endif
+#include "network.h"
+#endif
+
+#include <math.h>
+#include "cudd.h"
+#include "st.h"
+
+#if defined(__GNUC__)
+# define DD_INLINE __inline__
+# if (__GNUC__ >2 || __GNUC_MINOR__ >=7)
+# define DD_UNUSED __attribute__ ((__unused__))
+# else
+# define DD_UNUSED
+# endif
+#else
+# if defined(__cplusplus)
+# define DD_INLINE inline
+# else
+# define DD_INLINE
+# endif
+# define DD_UNUSED
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define DD_MAXREF ((DdHalfWord) ~0)
+
+#define DD_DEFAULT_RESIZE 10 /* how many extra variables */
+ /* should be added when resizing */
+#define DD_MEM_CHUNK 1022
+
+/* These definitions work for CUDD_VALUE_TYPE == double */
+#define DD_ONE_VAL (1.0)
+#define DD_ZERO_VAL (0.0)
+#define DD_EPSILON (1.0e-12)
+
+/* The definitions of +/- infinity in terms of HUGE_VAL work on
+** the DECstations and on many other combinations of OS/compiler.
+*/
+#ifdef HAVE_IEEE_754
+# define DD_PLUS_INF_VAL (HUGE_VAL)
+#else
+# define DD_PLUS_INF_VAL (10e301)
+# define DD_CRI_HI_MARK (10e150)
+# define DD_CRI_LO_MARK (-(DD_CRI_HI_MARK))
+#endif
+#define DD_MINUS_INF_VAL (-(DD_PLUS_INF_VAL))
+
+#define DD_NON_CONSTANT ((DdNode *) 1) /* for Cudd_bddIteConstant */
+
+/* Unique table and cache management constants. */
+#define DD_MAX_SUBTABLE_DENSITY 4 /* tells when to resize a subtable */
+/* gc when this percent are dead (measured w.r.t. slots, not keys)
+** The first limit (LO) applies normally. The second limit applies when
+** the package believes more space for the unique table (i.e., more dead
+** nodes) would improve performance, and the unique table is not already
+** too large. The third limit applies when memory is low.
+*/
+#define DD_GC_FRAC_LO DD_MAX_SUBTABLE_DENSITY * 0.25
+#define DD_GC_FRAC_HI DD_MAX_SUBTABLE_DENSITY * 1.0
+#define DD_GC_FRAC_MIN 0.2
+#define DD_MIN_HIT 30 /* resize cache when hit ratio
+ above this percentage (default) */
+#define DD_MAX_LOOSE_FRACTION 5 /* 1 / (max fraction of memory used for
+ unique table in fast growth mode) */
+#define DD_MAX_CACHE_FRACTION 3 /* 1 / (max fraction of memory used for
+ computed table if resizing enabled) */
+#define DD_STASH_FRACTION 64 /* 1 / (fraction of memory set
+ aside for emergencies) */
+#define DD_MAX_CACHE_TO_SLOTS_RATIO 4 /* used to limit the cache size */
+
+/* Variable ordering default parameter values. */
+#define DD_SIFT_MAX_VAR 1000
+#define DD_SIFT_MAX_SWAPS 2000000
+#define DD_DEFAULT_RECOMB 0
+#define DD_MAX_REORDER_GROWTH 1.2
+#define DD_FIRST_REORDER 4004 /* 4 for the constants */
+#define DD_DYN_RATIO 2 /* when to dynamically reorder */
+
+/* Primes for cache hash functions. */
+#define DD_P1 12582917
+#define DD_P2 4256249
+#define DD_P3 741457
+#define DD_P4 1618033999
+
+/* Cache tags for 3-operand operators. These tags are stored in the
+** least significant bits of the cache operand pointers according to
+** the following scheme. The tag consists of two hex digits. Both digits
+** must be even, so that they do not interfere with complementation bits.
+** The least significant one is stored in Bits 3:1 of the f operand in the
+** cache entry. Bit 1 is always 1, so that we can differentiate
+** three-operand operations from one- and two-operand operations.
+** Therefore, the least significant digit is one of {2,6,a,e}. The most
+** significant digit occupies Bits 3:1 of the g operand in the cache
+** entry. It can by any even digit between 0 and e. This gives a total
+** of 5 bits for the tag proper, which means a maximum of 32 three-operand
+** operations. */
+#define DD_ADD_ITE_TAG 0x02
+#define DD_BDD_AND_ABSTRACT_TAG 0x06
+#define DD_BDD_XOR_EXIST_ABSTRACT_TAG 0x0a
+#define DD_BDD_ITE_TAG 0x0e
+#define DD_ADD_BDD_DO_INTERVAL_TAG 0x22
+#define DD_BDD_CLIPPING_AND_ABSTRACT_UP_TAG 0x26
+#define DD_BDD_CLIPPING_AND_ABSTRACT_DOWN_TAG 0x2a
+#define DD_BDD_COMPOSE_RECUR_TAG 0x2e
+#define DD_ADD_COMPOSE_RECUR_TAG 0x42
+#define DD_ADD_NON_SIM_COMPOSE_TAG 0x46
+#define DD_EQUIV_DC_TAG 0x4a
+#define DD_ZDD_ITE_TAG 0x4e
+#define DD_ADD_ITE_CONSTANT_TAG 0x62
+#define DD_ADD_EVAL_CONST_TAG 0x66
+#define DD_BDD_ITE_CONSTANT_TAG 0x6a
+#define DD_ADD_OUT_SUM_TAG 0x6e
+#define DD_BDD_LEQ_UNLESS_TAG 0x82
+#define DD_ADD_TRIANGLE_TAG 0x86
+
+/* Generator constants. */
+#define CUDD_GEN_CUBES 0
+#define CUDD_GEN_NODES 1
+#define CUDD_GEN_ZDD_PATHS 2
+#define CUDD_GEN_EMPTY 0
+#define CUDD_GEN_NONEMPTY 1
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+struct DdGen {
+ DdManager *manager;
+ int type;
+ int status;
+ union {
+ struct {
+ int *cube;
+ CUDD_VALUE_TYPE value;
+ } cubes;
+ struct {
+ st_table *visited;
+ st_generator *stGen;
+ } nodes;
+ } gen;
+ struct {
+ int sp;
+ DdNode **stack;
+ } stack;
+ DdNode *node;
+};
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/* Hooks in CUDD are functions that the application registers with the
+** manager so that they are called at appropriate times. The functions
+** are passed the manager as argument; they should return 1 if
+** successful and 0 otherwise.
+*/
+typedef struct DdHook { /* hook list element */
+ int (*f) ARGS((DdManager *, char *, void *)); /* function to be called */
+ struct DdHook *next; /* next element in the list */
+} DdHook;
+
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+typedef long ptrint;
+typedef unsigned long ptruint;
+#else
+typedef int ptrint;
+typedef unsigned int ptruint;
+#endif
+
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+
+typedef DdNode *DdNodePtr;
+
+/* Generic local cache item. */
+typedef struct DdLocalCacheItem {
+ DdNode *value;
+#ifdef DD_CACHE_PROFILE
+ ptrint count;
+#endif
+ DdNode *key[1];
+} DdLocalCacheItem;
+
+/* Local cache. */
+typedef struct DdLocalCache {
+ DdLocalCacheItem *item;
+ unsigned int itemsize;
+ unsigned int keysize;
+ unsigned int slots;
+ int shift;
+ double lookUps;
+ double minHit;
+ double hits;
+ unsigned int maxslots;
+ DdManager *manager;
+ struct DdLocalCache *next;
+} DdLocalCache;
+
+/* Generic hash item. */
+typedef struct DdHashItem {
+ struct DdHashItem *next;
+ ptrint count;
+ DdNode *value;
+ DdNode *key[1];
+} DdHashItem;
+
+/* Local hash table */
+typedef struct DdHashTable {
+ unsigned int keysize;
+ unsigned int itemsize;
+ DdHashItem **bucket;
+ DdHashItem *nextFree;
+ DdHashItem **memoryList;
+ unsigned int numBuckets;
+ int shift;
+ unsigned int size;
+ unsigned int maxsize;
+ DdManager *manager;
+} DdHashTable;
+
+typedef struct DdCache {
+ DdNode *f,*g; /* DDs */
+ ptruint h; /* either operator or DD */
+ DdNode *data; /* already constructed DD */
+#ifdef DD_CACHE_PROFILE
+ ptrint count;
+#endif
+} DdCache;
+
+typedef struct DdSubtable { /* subtable for one index */
+ DdNode **nodelist; /* hash table */
+ int shift; /* shift for hash function */
+ unsigned int slots; /* size of the hash table */
+ unsigned int keys; /* number of nodes stored in this table */
+ unsigned int maxKeys; /* slots * DD_MAX_SUBTABLE_DENSITY */
+ unsigned int dead; /* number of dead nodes in this table */
+ unsigned int next; /* index of next variable in group */
+ int bindVar; /* flag to bind this variable to its level */
+ /* Fields for lazy sifting. */
+ Cudd_VariableType varType; /* variable type (ps, ns, pi) */
+ int pairIndex; /* corresponding variable index (ps <-> ns) */
+ int varHandled; /* flag: 1 means variable is already handled */
+ Cudd_LazyGroupType varToBeGrouped; /* tells what grouping to apply */
+} DdSubtable;
+
+struct DdManager { /* specialized DD symbol table */
+ /* Constants */
+ DdNode sentinel; /* for collision lists */
+ DdNode *one; /* constant 1 */
+ DdNode *zero; /* constant 0 */
+ DdNode *plusinfinity; /* plus infinity */
+ DdNode *minusinfinity; /* minus infinity */
+ DdNode *background; /* background value */
+ /* Computed Table */
+ DdCache *acache; /* address of allocated memory for cache */
+ DdCache *cache; /* the cache-based computed table */
+ unsigned int cacheSlots; /* total number of cache entries */
+ int cacheShift; /* shift value for cache hash function */
+ double cacheMisses; /* number of cache misses (since resizing) */
+ double cacheHits; /* number of cache hits (since resizing) */
+ double minHit; /* hit percentage above which to resize */
+ int cacheSlack; /* slots still available for resizing */
+ unsigned int maxCacheHard; /* hard limit for cache size */
+ /* Unique Table */
+ int size; /* number of unique subtables */
+ int sizeZ; /* for ZDD */
+ int maxSize; /* max number of subtables before resizing */
+ int maxSizeZ; /* for ZDD */
+ DdSubtable *subtables; /* array of unique subtables */
+ DdSubtable *subtableZ; /* for ZDD */
+ DdSubtable constants; /* unique subtable for the constants */
+ unsigned int slots; /* total number of hash buckets */
+ unsigned int keys; /* total number of BDD and ADD nodes */
+ unsigned int keysZ; /* total number of ZDD nodes */
+ unsigned int dead; /* total number of dead BDD and ADD nodes */
+ unsigned int deadZ; /* total number of dead ZDD nodes */
+ unsigned int maxLive; /* maximum number of live nodes */
+ unsigned int minDead; /* do not GC if fewer than these dead */
+ double gcFrac; /* gc when this fraction is dead */
+ int gcEnabled; /* gc is enabled */
+ unsigned int looseUpTo; /* slow growth beyond this limit */
+ /* (measured w.r.t. slots, not keys) */
+ unsigned int initSlots; /* initial size of a subtable */
+ DdNode **stack; /* stack for iterative procedures */
+ double allocated; /* number of nodes allocated */
+ /* (not during reordering) */
+ double reclaimed; /* number of nodes brought back from the dead */
+ int isolated; /* isolated projection functions */
+ int *perm; /* current variable perm. (index to level) */
+ int *permZ; /* for ZDD */
+ int *invperm; /* current inv. var. perm. (level to index) */
+ int *invpermZ; /* for ZDD */
+ DdNode **vars; /* projection functions */
+ int *map; /* variable map for fast swap */
+ DdNode **univ; /* ZDD 1 for each variable */
+ int linearSize; /* number of rows and columns of linear */
+ long *interact; /* interacting variable matrix */
+ long *linear; /* linear transform matrix */
+ /* Memory Management */
+ DdNode **memoryList; /* memory manager for symbol table */
+ DdNode *nextFree; /* list of free nodes */
+ char *stash; /* memory reserve */
+#ifndef DD_NO_DEATH_ROW
+ DdNode **deathRow; /* queue for dereferencing */
+ int deathRowDepth; /* number of slots in the queue */
+ int nextDead; /* index in the queue */
+ unsigned deadMask; /* mask for circular index update */
+#endif
+ /* General Parameters */
+ CUDD_VALUE_TYPE epsilon; /* tolerance on comparisons */
+ /* Dynamic Reordering Parameters */
+ int reordered; /* flag set at the end of reordering */
+ int reorderings; /* number of calls to Cudd_ReduceHeap */
+ int siftMaxVar; /* maximum number of vars sifted */
+ int siftMaxSwap; /* maximum number of swaps per sifting */
+ double maxGrowth; /* maximum growth during reordering */
+ double maxGrowthAlt; /* alternate maximum growth for reordering */
+ int reordCycle; /* how often to apply alternate threshold */
+ int autoDyn; /* automatic dynamic reordering flag (BDD) */
+ int autoDynZ; /* automatic dynamic reordering flag (ZDD) */
+ Cudd_ReorderingType autoMethod; /* default reordering method */
+ Cudd_ReorderingType autoMethodZ; /* default reordering method (ZDD) */
+ int realign; /* realign ZDD order after BDD reordering */
+ int realignZ; /* realign BDD order after ZDD reordering */
+ unsigned int nextDyn; /* reorder if this size is reached */
+ unsigned int countDead; /* if 0, count deads to trigger reordering */
+ MtrNode *tree; /* Variable group tree (BDD) */
+ MtrNode *treeZ; /* Variable group tree (ZDD) */
+ Cudd_AggregationType groupcheck; /* Used during group sifting */
+ int recomb; /* Used during group sifting */
+ int symmviolation; /* Used during group sifting */
+ int arcviolation; /* Used during group sifting */
+ int populationSize; /* population size for GA */
+ int numberXovers; /* number of crossovers for GA */
+ DdLocalCache *localCaches; /* local caches currently in existence */
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+ char *hooks; /* application-specific field (used by vis) */
+ DdHook *preGCHook; /* hooks to be called before GC */
+ DdHook *postGCHook; /* hooks to be called after GC */
+ DdHook *preReorderingHook; /* hooks to be called before reordering */
+ DdHook *postReorderingHook; /* hooks to be called after reordering */
+ FILE *out; /* stdout for this manager */
+ FILE *err; /* stderr for this manager */
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ Cudd_ErrorType errorCode; /* info on last error */
+ /* Statistical counters. */
+ long memused; /* total memory allocated for the manager */
+ long maxmem; /* target maximum memory */
+ long maxmemhard; /* hard limit for maximum memory */
+ int garbageCollections; /* number of garbage collections */
+ long GCTime; /* total time spent in garbage collection */
+ long reordTime; /* total time spent in reordering */
+ double totCachehits; /* total number of cache hits */
+ double totCacheMisses; /* total number of cache misses */
+ double cachecollisions; /* number of cache collisions */
+ double cacheinserts; /* number of cache insertions */
+ double cacheLastInserts; /* insertions at the last cache resizing */
+ double cachedeletions; /* number of deletions during garbage coll. */
+#ifdef DD_STATS
+ double nodesFreed; /* number of nodes returned to the free list */
+ double nodesDropped; /* number of nodes killed by dereferencing */
+#endif
+ unsigned int peakLiveNodes; /* maximum number of live nodes */
+#ifdef DD_UNIQUE_PROFILE
+ double uniqueLookUps; /* number of unique table lookups */
+ double uniqueLinks; /* total distance traveled in coll. chains */
+#endif
+#ifdef DD_COUNT
+ double recursiveCalls; /* number of recursive calls */
+#ifdef DD_STATS
+ double nextSample; /* when to write next line of stats */
+#endif
+ double swapSteps; /* number of elementary reordering steps */
+#endif
+#ifdef DD_MIS
+ /* mis/verif compatibility fields */
+ array_t *iton; /* maps ids in ddNode to node_t */
+ array_t *order; /* copy of order_list */
+ lsHandle handle; /* where it is in network BDD list */
+ network_t *network;
+ st_table *local_order; /* for local BDDs */
+ int nvars; /* variables used so far */
+ int threshold; /* for pseudo var threshold value*/
+#endif
+};
+
+typedef struct Move {
+ DdHalfWord x;
+ DdHalfWord y;
+ unsigned int flags;
+ int size;
+ struct Move *next;
+} Move;
+
+/* Generic level queue item. */
+typedef struct DdQueueItem {
+ struct DdQueueItem *next;
+ struct DdQueueItem *cnext;
+ void *key;
+} DdQueueItem;
+
+/* Level queue. */
+typedef struct DdLevelQueue {
+ void *first;
+ DdQueueItem **last;
+ DdQueueItem *freelist;
+ DdQueueItem **buckets;
+ int levels;
+ int itemsize;
+ int size;
+ int maxsize;
+ int numBuckets;
+ int shift;
+} DdLevelQueue;
+
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**Macro***********************************************************************
+
+ Synopsis [Adds node to the head of the free list.]
+
+ Description [Adds node to the head of the free list. Does not
+ deallocate memory chunks that become free. This function is also
+ used by the dynamic reordering functions.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddAllocNode cuddDynamicAllocNode]
+
+******************************************************************************/
+#define cuddDeallocNode(unique,node) \
+ (node)->next = (unique)->nextFree; \
+ (unique)->nextFree = node;
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Increases the reference count of a node, if it is not
+ saturated.]
+
+ Description [Increases the reference count of a node, if it is not
+ saturated. This being a macro, it is faster than Cudd_Ref, but it
+ cannot be used in constructs like cuddRef(a = b()).]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_Ref]
+
+******************************************************************************/
+#define cuddRef(n) cuddSatInc(Cudd_Regular(n)->ref)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Decreases the reference count of a node, if it is not
+ saturated.]
+
+ Description [Decreases the reference count of node. It is primarily
+ used in recursive procedures to decrease the ref count of a result
+ node before returning it. This accomplishes the goal of removing the
+ protection applied by a previous cuddRef. This being a macro, it is
+ faster than Cudd_Deref, but it cannot be used in constructs like
+ cuddDeref(a = b()).]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_Deref]
+
+******************************************************************************/
+#define cuddDeref(n) cuddSatDec(Cudd_Regular(n)->ref)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns 1 if the node is a constant node.]
+
+ Description [Returns 1 if the node is a constant node (rather than an
+ internal node). All constant nodes have the same index
+ (CUDD_CONST_INDEX). The pointer passed to cuddIsConstant must be regular.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_IsConstant]
+
+******************************************************************************/
+#define cuddIsConstant(node) ((node)->index == CUDD_CONST_INDEX)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the then child of an internal node.]
+
+ Description [Returns the then child of an internal node. If
+ <code>node</code> is a constant node, the result is unpredictable.
+ The pointer passed to cuddT must be regular.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_T]
+
+******************************************************************************/
+#define cuddT(node) ((node)->type.kids.T)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the else child of an internal node.]
+
+ Description [Returns the else child of an internal node. If
+ <code>node</code> is a constant node, the result is unpredictable.
+ The pointer passed to cuddE must be regular.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_E]
+
+******************************************************************************/
+#define cuddE(node) ((node)->type.kids.E)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the value of a constant node.]
+
+ Description [Returns the value of a constant node. If
+ <code>node</code> is an internal node, the result is unpredictable.
+ The pointer passed to cuddV must be regular.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_V]
+
+******************************************************************************/
+#define cuddV(node) ((node)->type.value)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Finds the current position of variable index in the
+ order.]
+
+ Description [Finds the current position of variable index in the
+ order. This macro duplicates the functionality of Cudd_ReadPerm,
+ but it does not check for out-of-bounds indices and it is more
+ efficient.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_ReadPerm]
+
+******************************************************************************/
+#define cuddI(dd,index) (((index)==CUDD_CONST_INDEX)?(int)(index):(dd)->perm[(index)])
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Finds the current position of ZDD variable index in the
+ order.]
+
+ Description [Finds the current position of ZDD variable index in the
+ order. This macro duplicates the functionality of Cudd_ReadPermZdd,
+ but it does not check for out-of-bounds indices and it is more
+ efficient.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_ReadPermZdd]
+
+******************************************************************************/
+#define cuddIZ(dd,index) (((index)==CUDD_CONST_INDEX)?(int)(index):(dd)->permZ[(index)])
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Hash function for the unique table.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [ddCHash ddCHash2]
+
+******************************************************************************/
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+#define ddHash(f,g,s) \
+((((unsigned)(unsigned long)(f) * DD_P1 + \
+ (unsigned)(unsigned long)(g)) * DD_P2) >> (s))
+#else
+#define ddHash(f,g,s) \
+((((unsigned)(f) * DD_P1 + (unsigned)(g)) * DD_P2) >> (s))
+#endif
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Hash function for the cache.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [ddHash ddCHash2]
+
+******************************************************************************/
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+#define ddCHash(o,f,g,h,s) \
+((((((unsigned)(unsigned long)(f) + (unsigned)(unsigned long)(o)) * DD_P1 + \
+ (unsigned)(unsigned long)(g)) * DD_P2 + \
+ (unsigned)(unsigned long)(h)) * DD_P3) >> (s))
+#else
+#define ddCHash(o,f,g,h,s) \
+((((((unsigned)(f) + (unsigned)(o)) * DD_P1 + (unsigned)(g)) * DD_P2 + \
+ (unsigned)(h)) * DD_P3) >> (s))
+#endif
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Hash function for the cache for functions with two
+ operands.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [ddHash ddCHash]
+
+******************************************************************************/
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+#define ddCHash2(o,f,g,s) \
+(((((unsigned)(unsigned long)(f) + (unsigned)(unsigned long)(o)) * DD_P1 + \
+ (unsigned)(unsigned long)(g)) * DD_P2) >> (s))
+#else
+#define ddCHash2(o,f,g,s) \
+(((((unsigned)(f) + (unsigned)(o)) * DD_P1 + (unsigned)(g)) * DD_P2) >> (s))
+#endif
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Clears the 4 least significant bits of a pointer.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+#define cuddClean(p) ((DdNode *)((ptruint)(p) & ~0xf))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Computes the minimum of two numbers.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [ddMax]
+
+******************************************************************************/
+#define ddMin(x,y) (((y) < (x)) ? (y) : (x))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Computes the maximum of two numbers.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [ddMin]
+
+******************************************************************************/
+#define ddMax(x,y) (((y) > (x)) ? (y) : (x))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Computes the absolute value of a number.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+#define ddAbs(x) (((x)<0) ? -(x) : (x))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns 1 if the absolute value of the difference of the two
+ arguments x and y is less than e.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+#define ddEqualVal(x,y,e) (ddAbs((x)-(y))<(e))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Saturating increment operator.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [cuddSatDec]
+
+******************************************************************************/
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+#define cuddSatInc(x) ((x)++)
+#else
+#define cuddSatInc(x) ((x) += (x) != (DdHalfWord)DD_MAXREF)
+#endif
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Saturating decrement operator.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [cuddSatInc]
+
+******************************************************************************/
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+#define cuddSatDec(x) ((x)--)
+#else
+#define cuddSatDec(x) ((x) -= (x) != (DdHalfWord)DD_MAXREF)
+#endif
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the constant 1 node.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [DD_ZERO DD_PLUS_INFINITY DD_MINUS_INFINITY]
+
+******************************************************************************/
+#define DD_ONE(dd) ((dd)->one)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the arithmetic 0 constant node.]
+
+ Description [Returns the arithmetic 0 constant node. This is different
+ from the logical zero. The latter is obtained by
+ Cudd_Not(DD_ONE(dd)).]
+
+ SideEffects [none]
+
+ SeeAlso [DD_ONE Cudd_Not DD_PLUS_INFINITY DD_MINUS_INFINITY]
+
+******************************************************************************/
+#define DD_ZERO(dd) ((dd)->zero)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the plus infinity constant node.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [DD_ONE DD_ZERO DD_MINUS_INFINITY]
+
+******************************************************************************/
+#define DD_PLUS_INFINITY(dd) ((dd)->plusinfinity)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the minus infinity constant node.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [DD_ONE DD_ZERO DD_PLUS_INFINITY]
+
+******************************************************************************/
+#define DD_MINUS_INFINITY(dd) ((dd)->minusinfinity)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Enforces DD_MINUS_INF_VAL <= x <= DD_PLUS_INF_VAL.]
+
+ Description [Enforces DD_MINUS_INF_VAL <= x <= DD_PLUS_INF_VAL.
+ Furthermore, if x <= DD_MINUS_INF_VAL/2, x is set to
+ DD_MINUS_INF_VAL. Similarly, if DD_PLUS_INF_VAL/2 <= x, x is set to
+ DD_PLUS_INF_VAL. Normally this macro is a NOOP. However, if
+ HAVE_IEEE_754 is not defined, it makes sure that a value does not
+ get larger than infinity in absolute value, and once it gets to
+ infinity, stays there. If the value overflows before this macro is
+ applied, no recovery is possible.]
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+#ifdef HAVE_IEEE_754
+#define cuddAdjust(x)
+#else
+#define cuddAdjust(x) ((x) = ((x) >= DD_CRI_HI_MARK) ? DD_PLUS_INF_VAL : (((x) <= DD_CRI_LO_MARK) ? DD_MINUS_INF_VAL : (x)))
+#endif
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Extract the least significant digit of a double digit.]
+
+ Description [Extract the least significant digit of a double digit. Used
+ in the manipulation of arbitrary precision integers.]
+
+ SideEffects [None]
+
+ SeeAlso [DD_MSDIGIT]
+
+******************************************************************************/
+#define DD_LSDIGIT(x) ((x) & DD_APA_MASK)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Extract the most significant digit of a double digit.]
+
+ Description [Extract the most significant digit of a double digit. Used
+ in the manipulation of arbitrary precision integers.]
+
+ SideEffects [None]
+
+ SeeAlso [DD_LSDIGIT]
+
+******************************************************************************/
+#define DD_MSDIGIT(x) ((x) >> DD_APA_BITS)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Outputs a line of stats.]
+
+ Description [Outputs a line of stats if DD_COUNT and DD_STATS are
+ defined. Increments the number of recursive calls if DD_COUNT is
+ defined.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+#ifdef DD_COUNT
+#ifdef DD_STATS
+#define statLine(dd) dd->recursiveCalls++; \
+if (dd->recursiveCalls == dd->nextSample) {(void) fprintf(dd->err, \
+"@%.0f: %u nodes %u live %.0f dropped %.0f reclaimed\n", dd->recursiveCalls, \
+dd->keys, dd->keys - dd->dead, dd->nodesDropped, dd->reclaimed); \
+dd->nextSample += 250000;}
+#else
+#define statLine(dd) dd->recursiveCalls++;
+#endif
+#else
+#define statLine(dd)
+#endif
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Function prototypes */
+/*---------------------------------------------------------------------------*/
+
+EXTERN DdNode * cuddAddExistAbstractRecur ARGS((DdManager *manager, DdNode *f, DdNode *cube));
+EXTERN DdNode * cuddAddUnivAbstractRecur ARGS((DdManager *manager, DdNode *f, DdNode *cube));
+EXTERN DdNode * cuddAddOrAbstractRecur ARGS((DdManager *manager, DdNode *f, DdNode *cube));
+EXTERN DdNode * cuddAddApplyRecur ARGS((DdManager *dd, DdNode * (*)(DdManager *, DdNode **, DdNode **), DdNode *f, DdNode *g));
+EXTERN DdNode * cuddAddMonadicApplyRecur ARGS((DdManager * dd, DdNode * (*op)(DdManager *, DdNode *), DdNode * f));
+EXTERN DdNode * cuddAddScalarInverseRecur ARGS((DdManager *dd, DdNode *f, DdNode *epsilon));
+EXTERN DdNode * cuddAddIteRecur ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *h));
+EXTERN DdNode * cuddAddCmplRecur ARGS((DdManager *dd, DdNode *f));
+EXTERN DdNode * cuddAddNegateRecur ARGS((DdManager *dd, DdNode *f));
+EXTERN DdNode * cuddAddRoundOffRecur ARGS((DdManager *dd, DdNode *f, double trunc));
+EXTERN DdNode * cuddUnderApprox ARGS((DdManager *dd, DdNode *f, int numVars, int threshold, int safe, double quality));
+EXTERN DdNode * cuddRemapUnderApprox ARGS((DdManager *dd, DdNode *f, int numVars, int threshold, double quality));
+EXTERN DdNode * cuddBiasedUnderApprox ARGS((DdManager *dd, DdNode *f, DdNode *b, int numVars, int threshold, double quality1, double quality0));
+EXTERN DdNode * cuddBddAndAbstractRecur ARGS((DdManager *manager, DdNode *f, DdNode *g, DdNode *cube));
+EXTERN int cuddAnnealing ARGS((DdManager *table, int lower, int upper));
+EXTERN DdNode * cuddBddExistAbstractRecur ARGS((DdManager *manager, DdNode *f, DdNode *cube));
+EXTERN DdNode * cuddBddXorExistAbstractRecur ARGS((DdManager *manager, DdNode *f, DdNode *g, DdNode *cube));
+EXTERN DdNode * cuddBddBooleanDiffRecur ARGS((DdManager *manager, DdNode *f, DdNode *var));
+EXTERN DdNode * cuddBddIteRecur ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *h));
+EXTERN DdNode * cuddBddIntersectRecur ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * cuddBddAndRecur ARGS((DdManager *manager, DdNode *f, DdNode *g));
+EXTERN DdNode * cuddBddXorRecur ARGS((DdManager *manager, DdNode *f, DdNode *g));
+EXTERN DdNode * cuddBddTransfer ARGS((DdManager *ddS, DdManager *ddD, DdNode *f));
+EXTERN DdNode * cuddAddBddDoPattern ARGS((DdManager *dd, DdNode *f));
+EXTERN int cuddInitCache ARGS((DdManager *unique, unsigned int cacheSize, unsigned int maxCacheSize));
+EXTERN void cuddCacheInsert ARGS((DdManager *table, ptruint op, DdNode *f, DdNode *g, DdNode *h, DdNode *data));
+EXTERN void cuddCacheInsert2 ARGS((DdManager *table, DdNode * (*)(DdManager *, DdNode *, DdNode *), DdNode *f, DdNode *g, DdNode *data));
+EXTERN void cuddCacheInsert1 ARGS((DdManager *table, DdNode * (*)(DdManager *, DdNode *), DdNode *f, DdNode *data));
+EXTERN DdNode * cuddCacheLookup ARGS((DdManager *table, ptruint op, DdNode *f, DdNode *g, DdNode *h));
+EXTERN DdNode * cuddCacheLookupZdd ARGS((DdManager *table, ptruint op, DdNode *f, DdNode *g, DdNode *h));
+EXTERN DdNode * cuddCacheLookup2 ARGS((DdManager *table, DdNode * (*)(DdManager *, DdNode *, DdNode *), DdNode *f, DdNode *g));
+EXTERN DdNode * cuddCacheLookup1 ARGS((DdManager *table, DdNode * (*)(DdManager *, DdNode *), DdNode *f));
+EXTERN DdNode * cuddCacheLookup2Zdd ARGS((DdManager *table, DdNode * (*)(DdManager *, DdNode *, DdNode *), DdNode *f, DdNode *g));
+EXTERN DdNode * cuddCacheLookup1Zdd ARGS((DdManager *table, DdNode * (*)(DdManager *, DdNode *), DdNode *f));
+EXTERN DdNode * cuddConstantLookup ARGS((DdManager *table, ptruint op, DdNode *f, DdNode *g, DdNode *h));
+EXTERN int cuddCacheProfile ARGS((DdManager *table, FILE *fp));
+EXTERN void cuddCacheResize ARGS((DdManager *table));
+EXTERN void cuddCacheFlush ARGS((DdManager *table));
+EXTERN int cuddComputeFloorLog2 ARGS((unsigned int value));
+EXTERN int cuddHeapProfile ARGS((DdManager *dd));
+EXTERN void cuddPrintNode ARGS((DdNode *f, FILE *fp));
+EXTERN void cuddPrintVarGroups ARGS((DdManager * dd, MtrNode * root, int zdd, int silent));
+EXTERN DdNode * cuddBddClippingAnd ARGS((DdManager *dd, DdNode *f, DdNode *g, int maxDepth, int direction));
+EXTERN DdNode * cuddBddClippingAndAbstract ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *cube, int maxDepth, int direction));
+EXTERN void cuddGetBranches ARGS((DdNode *g, DdNode **g1, DdNode **g0));
+EXTERN int cuddCheckCube ARGS((DdManager *dd, DdNode *g));
+EXTERN DdNode * cuddCofactorRecur ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * cuddBddComposeRecur ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *proj));
+EXTERN DdNode * cuddAddComposeRecur ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *proj));
+EXTERN int cuddExact ARGS((DdManager *table, int lower, int upper));
+EXTERN DdNode * cuddBddConstrainRecur ARGS((DdManager *dd, DdNode *f, DdNode *c));
+EXTERN DdNode * cuddBddRestrictRecur ARGS((DdManager *dd, DdNode *f, DdNode *c));
+EXTERN DdNode * cuddAddConstrainRecur ARGS((DdManager *dd, DdNode *f, DdNode *c));
+EXTERN DdNode * cuddAddRestrictRecur ARGS((DdManager *dd, DdNode *f, DdNode *c));
+EXTERN DdNode * cuddBddLICompaction ARGS((DdManager *dd, DdNode *f, DdNode *c));
+EXTERN int cuddGa ARGS((DdManager *table, int lower, int upper));
+EXTERN int cuddTreeSifting ARGS((DdManager *table, Cudd_ReorderingType method));
+EXTERN int cuddZddInitUniv ARGS((DdManager *zdd));
+EXTERN void cuddZddFreeUniv ARGS((DdManager *zdd));
+EXTERN void cuddSetInteract ARGS((DdManager *table, int x, int y));
+EXTERN int cuddTestInteract ARGS((DdManager *table, int x, int y));
+EXTERN int cuddInitInteract ARGS((DdManager *table));
+EXTERN DdLocalCache * cuddLocalCacheInit ARGS((DdManager *manager, unsigned int keySize, unsigned int cacheSize, unsigned int maxCacheSize));
+EXTERN void cuddLocalCacheQuit ARGS((DdLocalCache *cache));
+EXTERN void cuddLocalCacheInsert ARGS((DdLocalCache *cache, DdNodePtr *key, DdNode *value));
+EXTERN DdNode * cuddLocalCacheLookup ARGS((DdLocalCache *cache, DdNodePtr *key));
+EXTERN void cuddLocalCacheClearDead ARGS((DdManager *manager));
+EXTERN int cuddIsInDeathRow ARGS((DdManager *dd, DdNode *f));
+EXTERN int cuddTimesInDeathRow ARGS((DdManager *dd, DdNode *f));
+EXTERN void cuddLocalCacheClearAll ARGS((DdManager *manager));
+#ifdef DD_CACHE_PROFILE
+EXTERN int cuddLocalCacheProfile ARGS((DdLocalCache *cache));
+#endif
+EXTERN DdHashTable * cuddHashTableInit ARGS((DdManager *manager, unsigned int keySize, unsigned int initSize));
+EXTERN void cuddHashTableQuit ARGS((DdHashTable *hash));
+EXTERN int cuddHashTableInsert ARGS((DdHashTable *hash, DdNodePtr *key, DdNode *value, ptrint count));
+EXTERN DdNode * cuddHashTableLookup ARGS((DdHashTable *hash, DdNodePtr *key));
+EXTERN int cuddHashTableInsert1 ARGS((DdHashTable *hash, DdNode *f, DdNode *value, ptrint count));
+EXTERN DdNode * cuddHashTableLookup1 ARGS((DdHashTable *hash, DdNode *f));
+EXTERN int cuddHashTableInsert2 ARGS((DdHashTable *hash, DdNode *f, DdNode *g, DdNode *value, ptrint count));
+EXTERN DdNode * cuddHashTableLookup2 ARGS((DdHashTable *hash, DdNode *f, DdNode *g));
+EXTERN int cuddHashTableInsert3 ARGS((DdHashTable *hash, DdNode *f, DdNode *g, DdNode *h, DdNode *value, ptrint count));
+EXTERN DdNode * cuddHashTableLookup3 ARGS((DdHashTable *hash, DdNode *f, DdNode *g, DdNode *h));
+EXTERN DdLevelQueue * cuddLevelQueueInit ARGS((int levels, int itemSize, int numBuckets));
+EXTERN void cuddLevelQueueQuit ARGS((DdLevelQueue *queue));
+EXTERN void * cuddLevelQueueEnqueue ARGS((DdLevelQueue *queue, void *key, int level));
+EXTERN void cuddLevelQueueDequeue ARGS((DdLevelQueue *queue, int level));
+EXTERN int cuddLinearAndSifting ARGS((DdManager *table, int lower, int upper));
+EXTERN DdNode * cuddBddLiteralSetIntersectionRecur ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * cuddCProjectionRecur ARGS((DdManager *dd, DdNode *R, DdNode *Y, DdNode *Ysupp));
+EXTERN DdNode * cuddBddClosestCube ARGS((DdManager *dd, DdNode *f, DdNode *g, CUDD_VALUE_TYPE bound));
+EXTERN void cuddReclaim ARGS((DdManager *table, DdNode *n));
+EXTERN void cuddReclaimZdd ARGS((DdManager *table, DdNode *n));
+EXTERN void cuddClearDeathRow ARGS((DdManager *table));
+EXTERN void cuddShrinkDeathRow ARGS((DdManager *table));
+EXTERN DdNode * cuddDynamicAllocNode ARGS((DdManager *table));
+EXTERN int cuddSifting ARGS((DdManager *table, int lower, int upper));
+EXTERN int cuddSwapping ARGS((DdManager *table, int lower, int upper, Cudd_ReorderingType heuristic));
+EXTERN int cuddNextHigh ARGS((DdManager *table, int x));
+EXTERN int cuddNextLow ARGS((DdManager *table, int x));
+EXTERN int cuddSwapInPlace ARGS((DdManager *table, int x, int y));
+EXTERN int cuddBddAlignToZdd ARGS((DdManager *table));
+EXTERN DdNode * cuddBddMakePrime ARGS((DdManager *dd, DdNode *cube, DdNode *f));
+EXTERN DdNode * cuddSolveEqnRecur ARGS((DdManager *bdd, DdNode *F, DdNode *Y, DdNode **G, int n, int *yIndex, int i));
+EXTERN DdNode * cuddVerifySol ARGS((DdManager *bdd, DdNode *F, DdNode **G, int *yIndex, int n));
+#ifdef ST_INCLUDED
+EXTERN DdNode* cuddSplitSetRecur ARGS((DdManager *manager, st_table *mtable, int *varSeen, DdNode *p, double n, double max, int index));
+#endif
+EXTERN DdNode * cuddSubsetHeavyBranch ARGS((DdManager *dd, DdNode *f, int numVars, int threshold));
+EXTERN DdNode * cuddSubsetShortPaths ARGS((DdManager *dd, DdNode *f, int numVars, int threshold, int hardlimit));
+EXTERN int cuddSymmCheck ARGS((DdManager *table, int x, int y));
+EXTERN int cuddSymmSifting ARGS((DdManager *table, int lower, int upper));
+EXTERN int cuddSymmSiftingConv ARGS((DdManager *table, int lower, int upper));
+EXTERN DdNode * cuddAllocNode ARGS((DdManager *unique));
+EXTERN DdManager * cuddInitTable ARGS((unsigned int numVars, unsigned int numVarsZ, unsigned int numSlots, unsigned int looseUpTo));
+EXTERN void cuddFreeTable ARGS((DdManager *unique));
+EXTERN int cuddGarbageCollect ARGS((DdManager *unique, int clearCache));
+EXTERN int cuddGarbageCollectZdd ARGS((DdManager *unique, int clearCache));
+EXTERN DdNode * cuddZddGetNode ARGS((DdManager *zdd, int id, DdNode *T, DdNode *E));
+EXTERN DdNode * cuddZddGetNodeIVO ARGS((DdManager *dd, int index, DdNode *g, DdNode *h));
+EXTERN DdNode * cuddUniqueInter ARGS((DdManager *unique, int index, DdNode *T, DdNode *E));
+EXTERN DdNode * cuddUniqueInterIVO ARGS((DdManager *unique, int index, DdNode *T, DdNode *E));
+EXTERN DdNode * cuddUniqueInterZdd ARGS((DdManager *unique, int index, DdNode *T, DdNode *E));
+EXTERN DdNode * cuddUniqueConst ARGS((DdManager *unique, CUDD_VALUE_TYPE value));
+EXTERN void cuddRehash ARGS((DdManager *unique, int i));
+EXTERN void cuddShrinkSubtable ARGS((DdManager *unique, int i));
+EXTERN int cuddInsertSubtables ARGS((DdManager *unique, int n, int level));
+EXTERN int cuddDestroySubtables ARGS((DdManager *unique, int n));
+EXTERN int cuddResizeTableZdd ARGS((DdManager *unique, int index));
+EXTERN void cuddSlowTableGrowth ARGS((DdManager *unique));
+EXTERN int cuddP ARGS((DdManager *dd, DdNode *f));
+#ifdef ST_INCLUDED
+EXTERN enum st_retval cuddStCountfree ARGS((char *key, char *value, char *arg));
+EXTERN int cuddCollectNodes ARGS((DdNode *f, st_table *visited));
+#endif
+EXTERN int cuddWindowReorder ARGS((DdManager *table, int low, int high, Cudd_ReorderingType submethod));
+EXTERN DdNode * cuddZddProduct ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * cuddZddUnateProduct ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * cuddZddWeakDiv ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * cuddZddWeakDivF ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * cuddZddDivide ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * cuddZddDivideF ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN int cuddZddGetCofactors3 ARGS((DdManager *dd, DdNode *f, int v, DdNode **f1, DdNode **f0, DdNode **fd));
+EXTERN int cuddZddGetCofactors2 ARGS((DdManager *dd, DdNode *f, int v, DdNode **f1, DdNode **f0));
+EXTERN DdNode * cuddZddComplement ARGS((DdManager *dd, DdNode *node));
+EXTERN int cuddZddGetPosVarIndex(DdManager * dd, int index);
+EXTERN int cuddZddGetNegVarIndex(DdManager * dd, int index);
+EXTERN int cuddZddGetPosVarLevel(DdManager * dd, int index);
+EXTERN int cuddZddGetNegVarLevel(DdManager * dd, int index);
+EXTERN int cuddZddTreeSifting ARGS((DdManager *table, Cudd_ReorderingType method));
+EXTERN DdNode * cuddZddIsop ARGS((DdManager *dd, DdNode *L, DdNode *U, DdNode **zdd_I));
+EXTERN DdNode * cuddBddIsop ARGS((DdManager *dd, DdNode *L, DdNode *U));
+EXTERN DdNode * cuddMakeBddFromZddCover ARGS((DdManager *dd, DdNode *node));
+EXTERN int cuddZddLinearSifting ARGS((DdManager *table, int lower, int upper));
+EXTERN int cuddZddAlignToBdd ARGS((DdManager *table));
+EXTERN int cuddZddNextHigh ARGS((DdManager *table, int x));
+EXTERN int cuddZddNextLow ARGS((DdManager *table, int x));
+EXTERN int cuddZddUniqueCompare ARGS((int *ptr_x, int *ptr_y));
+EXTERN int cuddZddSwapInPlace ARGS((DdManager *table, int x, int y));
+EXTERN int cuddZddSwapping ARGS((DdManager *table, int lower, int upper, Cudd_ReorderingType heuristic));
+EXTERN int cuddZddSifting ARGS((DdManager *table, int lower, int upper));
+EXTERN DdNode * cuddZddIte ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *h));
+EXTERN DdNode * cuddZddUnion ARGS((DdManager *zdd, DdNode *P, DdNode *Q));
+EXTERN DdNode * cuddZddIntersect ARGS((DdManager *zdd, DdNode *P, DdNode *Q));
+EXTERN DdNode * cuddZddDiff ARGS((DdManager *zdd, DdNode *P, DdNode *Q));
+EXTERN DdNode * cuddZddChangeAux ARGS((DdManager *zdd, DdNode *P, DdNode *zvar));
+EXTERN DdNode * cuddZddSubset1 ARGS((DdManager *dd, DdNode *P, int var));
+EXTERN DdNode * cuddZddSubset0 ARGS((DdManager *dd, DdNode *P, int var));
+EXTERN DdNode * cuddZddChange ARGS((DdManager *dd, DdNode *P, int var));
+EXTERN int cuddZddSymmCheck ARGS((DdManager *table, int x, int y));
+EXTERN int cuddZddSymmSifting ARGS((DdManager *table, int lower, int upper));
+EXTERN int cuddZddSymmSiftingConv ARGS((DdManager *table, int lower, int upper));
+EXTERN int cuddZddP ARGS((DdManager *zdd, DdNode *f));
+
+/**AutomaticEnd***************************************************************/
+
+#endif /* _CUDDINT */
diff --git a/src/bdd/cudd/cuddInteract.c b/src/bdd/cudd/cuddInteract.c
new file mode 100644
index 00000000..5a4ec79a
--- /dev/null
+++ b/src/bdd/cudd/cuddInteract.c
@@ -0,0 +1,402 @@
+/**CFile***********************************************************************
+
+ FileName [cuddInteract.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions to manipulate the variable interaction matrix.]
+
+ Description [Internal procedures included in this file:
+ <ul>
+ <li> cuddSetInteract()
+ <li> cuddTestInteract()
+ <li> cuddInitInteract()
+ </ul>
+ Static procedures included in this file:
+ <ul>
+ <li> ddSuppInteract()
+ <li> ddClearLocal()
+ <li> ddUpdateInteract()
+ <li> ddClearGlobal()
+ </ul>
+ The interaction matrix tells whether two variables are
+ both in the support of some function of the DD. The main use of the
+ interaction matrix is in the in-place swapping. Indeed, if two
+ variables do not interact, there is no arc connecting the two layers;
+ therefore, the swap can be performed in constant time, without
+ scanning the subtables. Another use of the interaction matrix is in
+ the computation of the lower bounds for sifting. Finally, the
+ interaction matrix can be used to speed up aggregation checks in
+ symmetric and group sifting.<p>
+ The computation of the interaction matrix is done with a series of
+ depth-first searches. The searches start from those nodes that have
+ only external references. The matrix is stored as a packed array of bits;
+ since it is symmetric, only the upper triangle is kept in memory.
+ As a final remark, we note that there may be variables that do
+ intercat, but that for a given variable order have no arc connecting
+ their layers when they are adjacent.]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#if SIZEOF_LONG == 8
+#define BPL 64
+#define LOGBPL 6
+#else
+#define BPL 32
+#define LOGBPL 5
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddInteract.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static void ddSuppInteract ARGS((DdNode *f, int *support));
+static void ddClearLocal ARGS((DdNode *f));
+static void ddUpdateInteract ARGS((DdManager *table, int *support));
+static void ddClearGlobal ARGS((DdManager *table));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Set interaction matrix entries.]
+
+ Description [Given a pair of variables 0 <= x < y < table->size,
+ sets the corresponding bit of the interaction matrix to 1.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+cuddSetInteract(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int posn, word, bit;
+
+#ifdef DD_DEBUG
+ assert(x < y);
+ assert(y < table->size);
+ assert(x >= 0);
+#endif
+
+ posn = ((((table->size << 1) - x - 3) * x) >> 1) + y - 1;
+ word = posn >> LOGBPL;
+ bit = posn & (BPL-1);
+ table->interact[word] |= 1L << bit;
+
+} /* end of cuddSetInteract */
+
+
+/**Function********************************************************************
+
+ Synopsis [Test interaction matrix entries.]
+
+ Description [Given a pair of variables 0 <= x < y < table->size,
+ tests whether the corresponding bit of the interaction matrix is 1.
+ Returns the value of the bit.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddTestInteract(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int posn, word, bit, result;
+
+ if (x > y) {
+ int tmp = x;
+ x = y;
+ y = tmp;
+ }
+#ifdef DD_DEBUG
+ assert(x < y);
+ assert(y < table->size);
+ assert(x >= 0);
+#endif
+
+ posn = ((((table->size << 1) - x - 3) * x) >> 1) + y - 1;
+ word = posn >> LOGBPL;
+ bit = posn & (BPL-1);
+ result = (table->interact[word] >> bit) & 1L;
+ return(result);
+
+} /* end of cuddTestInteract */
+
+
+/**Function********************************************************************
+
+ Synopsis [Initializes the interaction matrix.]
+
+ Description [Initializes the interaction matrix. The interaction
+ matrix is implemented as a bit vector storing the upper triangle of
+ the symmetric interaction matrix. The bit vector is kept in an array
+ of long integers. The computation is based on a series of depth-first
+ searches, one for each root of the DAG. Two flags are needed: The
+ local visited flag uses the LSB of the then pointer. The global
+ visited flag uses the LSB of the next pointer.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddInitInteract(
+ DdManager * table)
+{
+ int i,j,k;
+ int words;
+ long *interact;
+ int *support;
+ DdNode *f;
+ DdNode *sentinel = &(table->sentinel);
+ DdNodePtr *nodelist;
+ int slots;
+ int n = table->size;
+
+ words = ((n * (n-1)) >> (1 + LOGBPL)) + 1;
+ table->interact = interact = ALLOC(long,words);
+ if (interact == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (i = 0; i < words; i++) {
+ interact[i] = 0;
+ }
+
+ support = ALLOC(int,n);
+ if (support == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ FREE(interact);
+ return(0);
+ }
+
+ for (i = 0; i < n; i++) {
+ nodelist = table->subtables[i].nodelist;
+ slots = table->subtables[i].slots;
+ for (j = 0; j < slots; j++) {
+ f = nodelist[j];
+ while (f != sentinel) {
+ /* A node is a root of the DAG if it cannot be
+ ** reached by nodes above it. If a node was never
+ ** reached during the previous depth-first searches,
+ ** then it is a root, and we start a new depth-first
+ ** search from it.
+ */
+ if (!Cudd_IsComplement(f->next)) {
+ for (k = 0; k < n; k++) {
+ support[k] = 0;
+ }
+ ddSuppInteract(f,support);
+ ddClearLocal(f);
+ ddUpdateInteract(table,support);
+ }
+ f = Cudd_Regular(f->next);
+ }
+ }
+ }
+ ddClearGlobal(table);
+
+ FREE(support);
+ return(1);
+
+} /* end of cuddInitInteract */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Find the support of f.]
+
+ Description [Performs a DFS from f. Uses the LSB of the then pointer
+ as visited flag.]
+
+ SideEffects [Accumulates in support the variables on which f depends.]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ddSuppInteract(
+ DdNode * f,
+ int * support)
+{
+ if (cuddIsConstant(f) || Cudd_IsComplement(cuddT(f))) {
+ return;
+ }
+
+ support[f->index] = 1;
+ ddSuppInteract(cuddT(f),support);
+ ddSuppInteract(Cudd_Regular(cuddE(f)),support);
+ /* mark as visited */
+ cuddT(f) = Cudd_Complement(cuddT(f));
+ f->next = Cudd_Complement(f->next);
+ return;
+
+} /* end of ddSuppInteract */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs a DFS from f, clearing the LSB of the then pointers.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ddClearLocal(
+ DdNode * f)
+{
+ if (cuddIsConstant(f) || !Cudd_IsComplement(cuddT(f))) {
+ return;
+ }
+ /* clear visited flag */
+ cuddT(f) = Cudd_Regular(cuddT(f));
+ ddClearLocal(cuddT(f));
+ ddClearLocal(Cudd_Regular(cuddE(f)));
+ return;
+
+} /* end of ddClearLocal */
+
+
+/**Function********************************************************************
+
+ Synopsis [Marks as interacting all pairs of variables that appear in
+ support.]
+
+ Description [If support[i] == support[j] == 1, sets the (i,j) entry
+ of the interaction matrix to 1.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ddUpdateInteract(
+ DdManager * table,
+ int * support)
+{
+ int i,j;
+ int n = table->size;
+
+ for (i = 0; i < n-1; i++) {
+ if (support[i] == 1) {
+ for (j = i+1; j < n; j++) {
+ if (support[j] == 1) {
+ cuddSetInteract(table,i,j);
+ }
+ }
+ }
+ }
+
+} /* end of ddUpdateInteract */
+
+
+/**Function********************************************************************
+
+ Synopsis [Scans the DD and clears the LSB of the next pointers.]
+
+ Description [The LSB of the next pointers are used as markers to tell
+ whether a node was reached by at least one DFS. Once the interaction
+ matrix is built, these flags are reset.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ddClearGlobal(
+ DdManager * table)
+{
+ int i,j;
+ DdNode *f;
+ DdNode *sentinel = &(table->sentinel);
+ DdNodePtr *nodelist;
+ int slots;
+
+ for (i = 0; i < table->size; i++) {
+ nodelist = table->subtables[i].nodelist;
+ slots = table->subtables[i].slots;
+ for (j = 0; j < slots; j++) {
+ f = nodelist[j];
+ while (f != sentinel) {
+ f->next = Cudd_Regular(f->next);
+ f = f->next;
+ }
+ }
+ }
+
+} /* end of ddClearGlobal */
+
diff --git a/src/bdd/cudd/cuddLCache.c b/src/bdd/cudd/cuddLCache.c
new file mode 100644
index 00000000..72fbd48a
--- /dev/null
+++ b/src/bdd/cudd/cuddLCache.c
@@ -0,0 +1,1428 @@
+/**CFile***********************************************************************
+
+ FileName [cuddLCache.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for local caches.]
+
+ Description [Internal procedures included in this module:
+ <ul>
+ <li> cuddLocalCacheInit()
+ <li> cuddLocalCacheQuit()
+ <li> cuddLocalCacheInsert()
+ <li> cuddLocalCacheLookup()
+ <li> cuddLocalCacheClearDead()
+ <li> cuddLocalCacheClearAll()
+ <li> cuddLocalCacheProfile()
+ <li> cuddHashTableInit()
+ <li> cuddHashTableQuit()
+ <li> cuddHashTableInsert()
+ <li> cuddHashTableLookup()
+ <li> cuddHashTableInsert2()
+ <li> cuddHashTableLookup2()
+ <li> cuddHashTableInsert3()
+ <li> cuddHashTableLookup3()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddLocalCacheResize()
+ <li> ddLCHash()
+ <li> cuddLocalCacheAddToList()
+ <li> cuddLocalCacheRemoveFromList()
+ <li> cuddHashTableResize()
+ <li> cuddHashTableAlloc()
+ </ul> ]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define DD_MAX_HASHTABLE_DENSITY 2 /* tells when to resize a table */
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddLCache.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**Macro***********************************************************************
+
+ Synopsis [Computes hash function for keys of two operands.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [ddLCHash3 ddLCHash]
+
+******************************************************************************/
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+#define ddLCHash2(f,g,shift) \
+((((unsigned)(unsigned long)(f) * DD_P1 + \
+ (unsigned)(unsigned long)(g)) * DD_P2) >> (shift))
+#else
+#define ddLCHash2(f,g,shift) \
+((((unsigned)(f) * DD_P1 + (unsigned)(g)) * DD_P2) >> (shift))
+#endif
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Computes hash function for keys of three operands.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [ddLCHash2 ddLCHash]
+
+******************************************************************************/
+#define ddLCHash3(f,g,h,shift) ddCHash2(f,g,h,shift)
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static void cuddLocalCacheResize ARGS((DdLocalCache *cache));
+DD_INLINE static unsigned int ddLCHash ARGS((DdNodePtr *key, unsigned int keysize, int shift));
+static void cuddLocalCacheAddToList ARGS((DdLocalCache *cache));
+static void cuddLocalCacheRemoveFromList ARGS((DdLocalCache *cache));
+static int cuddHashTableResize ARGS((DdHashTable *hash));
+DD_INLINE static DdHashItem * cuddHashTableAlloc ARGS((DdHashTable *hash));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Initializes a local computed table.]
+
+ Description [Initializes a computed table. Returns a pointer the
+ the new local cache in case of success; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddInitCache]
+
+******************************************************************************/
+DdLocalCache *
+cuddLocalCacheInit(
+ DdManager * manager /* manager */,
+ unsigned int keySize /* size of the key (number of operands) */,
+ unsigned int cacheSize /* Initial size of the cache */,
+ unsigned int maxCacheSize /* Size of the cache beyond which no resizing occurs */)
+{
+ DdLocalCache *cache;
+ int logSize;
+
+ cache = ALLOC(DdLocalCache,1);
+ if (cache == NULL) {
+ manager->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ cache->manager = manager;
+ cache->keysize = keySize;
+ cache->itemsize = (keySize + 1) * sizeof(DdNode *);
+#ifdef DD_CACHE_PROFILE
+ cache->itemsize += sizeof(ptrint);
+#endif
+ logSize = cuddComputeFloorLog2(ddMax(cacheSize,manager->slots/2));
+ cacheSize = 1 << logSize;
+ cache->item = (DdLocalCacheItem *)
+ ALLOC(char, cacheSize * cache->itemsize);
+ if (cache->item == NULL) {
+ manager->errorCode = CUDD_MEMORY_OUT;
+ FREE(cache);
+ return(NULL);
+ }
+ cache->slots = cacheSize;
+ cache->shift = sizeof(int) * 8 - logSize;
+ cache->maxslots = ddMin(maxCacheSize,manager->slots);
+ cache->minHit = manager->minHit;
+ /* Initialize to avoid division by 0 and immediate resizing. */
+ cache->lookUps = (double) (int) (cacheSize * cache->minHit + 1);
+ cache->hits = 0;
+ manager->memused += cacheSize * cache->itemsize + sizeof(DdLocalCache);
+
+ /* Initialize the cache. */
+ memset(cache->item, 0, cacheSize * cache->itemsize);
+
+ /* Add to manager's list of local caches for GC. */
+ cuddLocalCacheAddToList(cache);
+
+ return(cache);
+
+} /* end of cuddLocalCacheInit */
+
+
+/**Function********************************************************************
+
+ Synopsis [Shuts down a local computed table.]
+
+ Description [Initializes the computed table. It is called by
+ Cudd_Init. Returns a pointer the the new local cache in case of
+ success; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddLocalCacheInit]
+
+******************************************************************************/
+void
+cuddLocalCacheQuit(
+ DdLocalCache * cache /* cache to be shut down */)
+{
+ cache->manager->memused -=
+ cache->slots * cache->itemsize + sizeof(DdLocalCache);
+ cuddLocalCacheRemoveFromList(cache);
+ FREE(cache->item);
+ FREE(cache);
+
+ return;
+
+} /* end of cuddLocalCacheQuit */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts a result in a local cache.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+cuddLocalCacheInsert(
+ DdLocalCache * cache,
+ DdNodePtr * key,
+ DdNode * value)
+{
+ unsigned int posn;
+ DdLocalCacheItem *entry;
+
+ posn = ddLCHash(key,cache->keysize,cache->shift);
+ entry = (DdLocalCacheItem *) ((char *) cache->item +
+ posn * cache->itemsize);
+ memcpy(entry->key,key,cache->keysize * sizeof(DdNode *));
+ entry->value = value;
+#ifdef DD_CACHE_PROFILE
+ entry->count++;
+#endif
+
+} /* end of cuddLocalCacheInsert */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up in a local cache.]
+
+ Description [Looks up in a local cache. Returns the result if found;
+ it returns NULL if no result is found.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddLocalCacheLookup(
+ DdLocalCache * cache,
+ DdNodePtr * key)
+{
+ unsigned int posn;
+ DdLocalCacheItem *entry;
+ DdNode *value;
+
+ cache->lookUps++;
+ posn = ddLCHash(key,cache->keysize,cache->shift);
+ entry = (DdLocalCacheItem *) ((char *) cache->item +
+ posn * cache->itemsize);
+ if (entry->value != NULL &&
+ memcmp(key,entry->key,cache->keysize*sizeof(DdNode *)) == 0) {
+ cache->hits++;
+ value = Cudd_Regular(entry->value);
+ if (value->ref == 0) {
+ cuddReclaim(cache->manager,value);
+ }
+ return(entry->value);
+ }
+
+ /* Cache miss: decide whether to resize */
+
+ if (cache->slots < cache->maxslots &&
+ cache->hits > cache->lookUps * cache->minHit) {
+ cuddLocalCacheResize(cache);
+ }
+
+ return(NULL);
+
+} /* end of cuddLocalCacheLookup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Clears the dead entries of the local caches of a manager.]
+
+ Description [Clears the dead entries of the local caches of a manager.
+ Used during garbage collection.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+cuddLocalCacheClearDead(
+ DdManager * manager)
+{
+ DdLocalCache *cache = manager->localCaches;
+ unsigned int keysize;
+ unsigned int itemsize;
+ unsigned int slots;
+ DdLocalCacheItem *item;
+ DdNodePtr *key;
+ unsigned int i, j;
+
+ while (cache != NULL) {
+ keysize = cache->keysize;
+ itemsize = cache->itemsize;
+ slots = cache->slots;
+ item = cache->item;
+ for (i = 0; i < slots; i++) {
+ if (item->value != NULL && Cudd_Regular(item->value)->ref == 0) {
+ item->value = NULL;
+ } else {
+ key = item->key;
+ for (j = 0; j < keysize; j++) {
+ if (Cudd_Regular(key[j])->ref == 0) {
+ item->value = NULL;
+ break;
+ }
+ }
+ }
+ item = (DdLocalCacheItem *) ((char *) item + itemsize);
+ }
+ cache = cache->next;
+ }
+ return;
+
+} /* end of cuddLocalCacheClearDead */
+
+
+/**Function********************************************************************
+
+ Synopsis [Clears the local caches of a manager.]
+
+ Description [Clears the local caches of a manager.
+ Used before reordering.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+cuddLocalCacheClearAll(
+ DdManager * manager)
+{
+ DdLocalCache *cache = manager->localCaches;
+
+ while (cache != NULL) {
+ memset(cache->item, 0, cache->slots * cache->itemsize);
+ cache = cache->next;
+ }
+ return;
+
+} /* end of cuddLocalCacheClearAll */
+
+
+#ifdef DD_CACHE_PROFILE
+
+#define DD_HYSTO_BINS 8
+
+/**Function********************************************************************
+
+ Synopsis [Computes and prints a profile of a local cache usage.]
+
+ Description [Computes and prints a profile of a local cache usage.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddLocalCacheProfile(
+ DdLocalCache * cache)
+{
+ double count, mean, meansq, stddev, expected;
+ long max, min;
+ int imax, imin;
+ int i, retval, slots;
+ long *hystogram;
+ int nbins = DD_HYSTO_BINS;
+ int bin;
+ long thiscount;
+ double totalcount;
+ int nzeroes;
+ DdLocalCacheItem *entry;
+ FILE *fp = cache->manager->out;
+
+ slots = cache->slots;
+
+ meansq = mean = expected = 0.0;
+ max = min = (long) cache->item[0].count;
+ imax = imin = nzeroes = 0;
+ totalcount = 0.0;
+
+ hystogram = ALLOC(long, nbins);
+ if (hystogram == NULL) {
+ return(0);
+ }
+ for (i = 0; i < nbins; i++) {
+ hystogram[i] = 0;
+ }
+
+ for (i = 0; i < slots; i++) {
+ entry = (DdLocalCacheItem *) ((char *) cache->item +
+ i * cache->itemsize);
+ thiscount = (long) entry->count;
+ if (thiscount > max) {
+ max = thiscount;
+ imax = i;
+ }
+ if (thiscount < min) {
+ min = thiscount;
+ imin = i;
+ }
+ if (thiscount == 0) {
+ nzeroes++;
+ }
+ count = (double) thiscount;
+ mean += count;
+ meansq += count * count;
+ totalcount += count;
+ expected += count * (double) i;
+ bin = (i * nbins) / slots;
+ hystogram[bin] += thiscount;
+ }
+ mean /= (double) slots;
+ meansq /= (double) slots;
+ stddev = sqrt(meansq - mean*mean);
+
+ retval = fprintf(fp,"Cache stats: slots = %d average = %g ", slots, mean);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"standard deviation = %g\n", stddev);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Cache max accesses = %ld for slot %d\n", max, imax);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Cache min accesses = %ld for slot %d\n", min, imin);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Cache unused slots = %d\n", nzeroes);
+ if (retval == EOF) return(0);
+
+ if (totalcount) {
+ expected /= totalcount;
+ retval = fprintf(fp,"Cache access hystogram for %d bins", nbins);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp," (expected bin value = %g)\n# ", expected);
+ if (retval == EOF) return(0);
+ for (i = nbins - 1; i>=0; i--) {
+ retval = fprintf(fp,"%ld ", hystogram[i]);
+ if (retval == EOF) return(0);
+ }
+ retval = fprintf(fp,"\n");
+ if (retval == EOF) return(0);
+ }
+
+ FREE(hystogram);
+ return(1);
+
+} /* end of cuddLocalCacheProfile */
+#endif
+
+
+/**Function********************************************************************
+
+ Synopsis [Initializes a hash table.]
+
+ Description [Initializes a hash table. Returns a pointer to the new
+ table if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddHashTableQuit]
+
+******************************************************************************/
+DdHashTable *
+cuddHashTableInit(
+ DdManager * manager,
+ unsigned int keySize,
+ unsigned int initSize)
+{
+ DdHashTable *hash;
+ int logSize;
+
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ hash = ALLOC(DdHashTable, 1);
+ if (hash == NULL) {
+ manager->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ hash->keysize = keySize;
+ hash->manager = manager;
+ hash->memoryList = NULL;
+ hash->nextFree = NULL;
+ hash->itemsize = (keySize + 1) * sizeof(DdNode *) +
+ sizeof(ptrint) + sizeof(DdHashItem *);
+ /* We have to guarantee that the shift be < 32. */
+ if (initSize < 2) initSize = 2;
+ logSize = cuddComputeFloorLog2(initSize);
+ hash->numBuckets = 1 << logSize;
+ hash->shift = sizeof(int) * 8 - logSize;
+ hash->bucket = ALLOC(DdHashItem *, hash->numBuckets);
+ if (hash->bucket == NULL) {
+ manager->errorCode = CUDD_MEMORY_OUT;
+ FREE(hash);
+ return(NULL);
+ }
+ memset(hash->bucket, 0, hash->numBuckets * sizeof(DdHashItem *));
+ hash->size = 0;
+ hash->maxsize = hash->numBuckets * DD_MAX_HASHTABLE_DENSITY;
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+ return(hash);
+
+} /* end of cuddHashTableInit */
+
+
+/**Function********************************************************************
+
+ Synopsis [Shuts down a hash table.]
+
+ Description [Shuts down a hash table, dereferencing all the values.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddHashTableInit]
+
+******************************************************************************/
+void
+cuddHashTableQuit(
+ DdHashTable * hash)
+{
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ unsigned int i;
+ DdManager *dd = hash->manager;
+ DdHashItem *bucket;
+ DdHashItem **memlist, **nextmem;
+ unsigned int numBuckets = hash->numBuckets;
+
+ for (i = 0; i < numBuckets; i++) {
+ bucket = hash->bucket[i];
+ while (bucket != NULL) {
+ Cudd_RecursiveDeref(dd, bucket->value);
+ bucket = bucket->next;
+ }
+ }
+
+ memlist = hash->memoryList;
+ while (memlist != NULL) {
+ nextmem = (DdHashItem **) memlist[0];
+ FREE(memlist);
+ memlist = nextmem;
+ }
+
+ FREE(hash->bucket);
+ FREE(hash);
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+
+ return;
+
+} /* end of cuddHashTableQuit */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts an item in a hash table.]
+
+ Description [Inserts an item in a hash table when the key has more than
+ three pointers. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [[cuddHashTableInsert1 cuddHashTableInsert2 cuddHashTableInsert3
+ cuddHashTableLookup]
+
+******************************************************************************/
+int
+cuddHashTableInsert(
+ DdHashTable * hash,
+ DdNodePtr * key,
+ DdNode * value,
+ ptrint count)
+{
+ int result;
+ unsigned int posn;
+ DdHashItem *item;
+ unsigned int i;
+
+#ifdef DD_DEBUG
+ assert(hash->keysize > 3);
+#endif
+
+ if (hash->size > hash->maxsize) {
+ result = cuddHashTableResize(hash);
+ if (result == 0) return(0);
+ }
+ item = cuddHashTableAlloc(hash);
+ if (item == NULL) return(0);
+ hash->size++;
+ item->value = value;
+ cuddRef(value);
+ item->count = count;
+ for (i = 0; i < hash->keysize; i++) {
+ item->key[i] = key[i];
+ }
+ posn = ddLCHash(key,hash->keysize,hash->shift);
+ item->next = hash->bucket[posn];
+ hash->bucket[posn] = item;
+
+ return(1);
+
+} /* end of cuddHashTableInsert */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up a key in a hash table.]
+
+ Description [Looks up a key consisting of more than three pointers
+ in a hash table. Returns the value associated to the key if there
+ is an entry for the given key in the table; NULL otherwise. If the
+ entry is present, its reference counter is decremented if not
+ saturated. If the counter reaches 0, the value of the entry is
+ dereferenced, and the entry is returned to the free list.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddHashTableLookup1 cuddHashTableLookup2 cuddHashTableLookup3
+ cuddHashTableInsert]
+
+******************************************************************************/
+DdNode *
+cuddHashTableLookup(
+ DdHashTable * hash,
+ DdNodePtr * key)
+{
+ unsigned int posn;
+ DdHashItem *item, *prev;
+ unsigned int i, keysize;
+
+#ifdef DD_DEBUG
+ assert(hash->keysize > 3);
+#endif
+
+ posn = ddLCHash(key,hash->keysize,hash->shift);
+ item = hash->bucket[posn];
+ prev = NULL;
+
+ keysize = hash->keysize;
+ while (item != NULL) {
+ DdNodePtr *key2 = item->key;
+ int equal = 1;
+ for (i = 0; i < keysize; i++) {
+ if (key[i] != key2[i]) {
+ equal = 0;
+ break;
+ }
+ }
+ if (equal) {
+ DdNode *value = item->value;
+ cuddSatDec(item->count);
+ if (item->count == 0) {
+ cuddDeref(value);
+ if (prev == NULL) {
+ hash->bucket[posn] = item->next;
+ } else {
+ prev->next = item->next;
+ }
+ item->next = hash->nextFree;
+ hash->nextFree = item;
+ hash->size--;
+ }
+ return(value);
+ }
+ prev = item;
+ item = item->next;
+ }
+ return(NULL);
+
+} /* end of cuddHashTableLookup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts an item in a hash table.]
+
+ Description [Inserts an item in a hash table when the key is one pointer.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddHashTableInsert cuddHashTableInsert2 cuddHashTableInsert3
+ cuddHashTableLookup1]
+
+******************************************************************************/
+int
+cuddHashTableInsert1(
+ DdHashTable * hash,
+ DdNode * f,
+ DdNode * value,
+ ptrint count)
+{
+ int result;
+ unsigned int posn;
+ DdHashItem *item;
+
+#ifdef DD_DEBUG
+ assert(hash->keysize == 1);
+#endif
+
+ if (hash->size > hash->maxsize) {
+ result = cuddHashTableResize(hash);
+ if (result == 0) return(0);
+ }
+ item = cuddHashTableAlloc(hash);
+ if (item == NULL) return(0);
+ hash->size++;
+ item->value = value;
+ cuddRef(value);
+ item->count = count;
+ item->key[0] = f;
+ posn = ddLCHash2(f,f,hash->shift);
+ item->next = hash->bucket[posn];
+ hash->bucket[posn] = item;
+
+ return(1);
+
+} /* end of cuddHashTableInsert1 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up a key consisting of one pointer in a hash table.]
+
+ Description [Looks up a key consisting of one pointer in a hash table.
+ Returns the value associated to the key if there is an entry for the given
+ key in the table; NULL otherwise. If the entry is present, its reference
+ counter is decremented if not saturated. If the counter reaches 0, the
+ value of the entry is dereferenced, and the entry is returned to the free
+ list.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddHashTableLookup cuddHashTableLookup2 cuddHashTableLookup3
+ cuddHashTableInsert1]
+
+******************************************************************************/
+DdNode *
+cuddHashTableLookup1(
+ DdHashTable * hash,
+ DdNode * f)
+{
+ unsigned int posn;
+ DdHashItem *item, *prev;
+
+#ifdef DD_DEBUG
+ assert(hash->keysize == 1);
+#endif
+
+ posn = ddLCHash2(f,f,hash->shift);
+ item = hash->bucket[posn];
+ prev = NULL;
+
+ while (item != NULL) {
+ DdNodePtr *key = item->key;
+ if (f == key[0]) {
+ DdNode *value = item->value;
+ cuddSatDec(item->count);
+ if (item->count == 0) {
+ cuddDeref(value);
+ if (prev == NULL) {
+ hash->bucket[posn] = item->next;
+ } else {
+ prev->next = item->next;
+ }
+ item->next = hash->nextFree;
+ hash->nextFree = item;
+ hash->size--;
+ }
+ return(value);
+ }
+ prev = item;
+ item = item->next;
+ }
+ return(NULL);
+
+} /* end of cuddHashTableLookup1 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts an item in a hash table.]
+
+ Description [Inserts an item in a hash table when the key is
+ composed of two pointers. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddHashTableInsert cuddHashTableInsert1 cuddHashTableInsert3
+ cuddHashTableLookup2]
+
+******************************************************************************/
+int
+cuddHashTableInsert2(
+ DdHashTable * hash,
+ DdNode * f,
+ DdNode * g,
+ DdNode * value,
+ ptrint count)
+{
+ int result;
+ unsigned int posn;
+ DdHashItem *item;
+
+#ifdef DD_DEBUG
+ assert(hash->keysize == 2);
+#endif
+
+ if (hash->size > hash->maxsize) {
+ result = cuddHashTableResize(hash);
+ if (result == 0) return(0);
+ }
+ item = cuddHashTableAlloc(hash);
+ if (item == NULL) return(0);
+ hash->size++;
+ item->value = value;
+ cuddRef(value);
+ item->count = count;
+ item->key[0] = f;
+ item->key[1] = g;
+ posn = ddLCHash2(f,g,hash->shift);
+ item->next = hash->bucket[posn];
+ hash->bucket[posn] = item;
+
+ return(1);
+
+} /* end of cuddHashTableInsert2 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up a key consisting of two pointers in a hash table.]
+
+ Description [Looks up a key consisting of two pointer in a hash table.
+ Returns the value associated to the key if there is an entry for the given
+ key in the table; NULL otherwise. If the entry is present, its reference
+ counter is decremented if not saturated. If the counter reaches 0, the
+ value of the entry is dereferenced, and the entry is returned to the free
+ list.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddHashTableLookup cuddHashTableLookup1 cuddHashTableLookup3
+ cuddHashTableInsert2]
+
+******************************************************************************/
+DdNode *
+cuddHashTableLookup2(
+ DdHashTable * hash,
+ DdNode * f,
+ DdNode * g)
+{
+ unsigned int posn;
+ DdHashItem *item, *prev;
+
+#ifdef DD_DEBUG
+ assert(hash->keysize == 2);
+#endif
+
+ posn = ddLCHash2(f,g,hash->shift);
+ item = hash->bucket[posn];
+ prev = NULL;
+
+ while (item != NULL) {
+ DdNodePtr *key = item->key;
+ if ((f == key[0]) && (g == key[1])) {
+ DdNode *value = item->value;
+ cuddSatDec(item->count);
+ if (item->count == 0) {
+ cuddDeref(value);
+ if (prev == NULL) {
+ hash->bucket[posn] = item->next;
+ } else {
+ prev->next = item->next;
+ }
+ item->next = hash->nextFree;
+ hash->nextFree = item;
+ hash->size--;
+ }
+ return(value);
+ }
+ prev = item;
+ item = item->next;
+ }
+ return(NULL);
+
+} /* end of cuddHashTableLookup2 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts an item in a hash table.]
+
+ Description [Inserts an item in a hash table when the key is
+ composed of three pointers. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddHashTableInsert cuddHashTableInsert1 cuddHashTableInsert2
+ cuddHashTableLookup3]
+
+******************************************************************************/
+int
+cuddHashTableInsert3(
+ DdHashTable * hash,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h,
+ DdNode * value,
+ ptrint count)
+{
+ int result;
+ unsigned int posn;
+ DdHashItem *item;
+
+#ifdef DD_DEBUG
+ assert(hash->keysize == 3);
+#endif
+
+ if (hash->size > hash->maxsize) {
+ result = cuddHashTableResize(hash);
+ if (result == 0) return(0);
+ }
+ item = cuddHashTableAlloc(hash);
+ if (item == NULL) return(0);
+ hash->size++;
+ item->value = value;
+ cuddRef(value);
+ item->count = count;
+ item->key[0] = f;
+ item->key[1] = g;
+ item->key[2] = h;
+ posn = ddLCHash3(f,g,h,hash->shift);
+ item->next = hash->bucket[posn];
+ hash->bucket[posn] = item;
+
+ return(1);
+
+} /* end of cuddHashTableInsert3 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up a key consisting of three pointers in a hash table.]
+
+ Description [Looks up a key consisting of three pointers in a hash table.
+ Returns the value associated to the key if there is an entry for the given
+ key in the table; NULL otherwise. If the entry is present, its reference
+ counter is decremented if not saturated. If the counter reaches 0, the
+ value of the entry is dereferenced, and the entry is returned to the free
+ list.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddHashTableLookup cuddHashTableLookup1 cuddHashTableLookup2
+ cuddHashTableInsert3]
+
+******************************************************************************/
+DdNode *
+cuddHashTableLookup3(
+ DdHashTable * hash,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ unsigned int posn;
+ DdHashItem *item, *prev;
+
+#ifdef DD_DEBUG
+ assert(hash->keysize == 3);
+#endif
+
+ posn = ddLCHash3(f,g,h,hash->shift);
+ item = hash->bucket[posn];
+ prev = NULL;
+
+ while (item != NULL) {
+ DdNodePtr *key = item->key;
+ if ((f == key[0]) && (g == key[1]) && (h == key[2])) {
+ DdNode *value = item->value;
+ cuddSatDec(item->count);
+ if (item->count == 0) {
+ cuddDeref(value);
+ if (prev == NULL) {
+ hash->bucket[posn] = item->next;
+ } else {
+ prev->next = item->next;
+ }
+ item->next = hash->nextFree;
+ hash->nextFree = item;
+ hash->size--;
+ }
+ return(value);
+ }
+ prev = item;
+ item = item->next;
+ }
+ return(NULL);
+
+} /* end of cuddHashTableLookup3 */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Resizes a local cache.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+cuddLocalCacheResize(
+ DdLocalCache * cache)
+{
+ DdLocalCacheItem *item, *olditem, *entry, *old;
+ int i, shift;
+ unsigned int posn;
+ unsigned int slots, oldslots;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+
+ olditem = cache->item;
+ oldslots = cache->slots;
+ slots = cache->slots = oldslots << 1;
+
+#ifdef DD_VERBOSE
+ (void) fprintf(cache->manager->err,
+ "Resizing local cache from %d to %d entries\n",
+ oldslots, slots);
+ (void) fprintf(cache->manager->err,
+ "\thits = %.0f\tlookups = %.0f\thit ratio = %5.3f\n",
+ cache->hits, cache->lookUps, cache->hits / cache->lookUps);
+#endif
+
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ cache->item = item =
+ (DdLocalCacheItem *) ALLOC(char, slots * cache->itemsize);
+ MMoutOfMemory = saveHandler;
+ /* If we fail to allocate the new table we just give up. */
+ if (item == NULL) {
+#ifdef DD_VERBOSE
+ (void) fprintf(cache->manager->err,"Resizing failed. Giving up.\n");
+#endif
+ cache->slots = oldslots;
+ cache->item = olditem;
+ /* Do not try to resize again. */
+ cache->maxslots = oldslots - 1;
+ return;
+ }
+ shift = --(cache->shift);
+ cache->manager->memused += (slots - oldslots) * cache->itemsize;
+
+ /* Clear new cache. */
+ memset(item, 0, slots * cache->itemsize);
+
+ /* Copy from old cache to new one. */
+ for (i = 0; (unsigned) i < oldslots; i++) {
+ old = (DdLocalCacheItem *) ((char *) olditem + i * cache->itemsize);
+ if (old->value != NULL) {
+ posn = ddLCHash(old->key,cache->keysize,slots);
+ entry = (DdLocalCacheItem *) ((char *) item +
+ posn * cache->itemsize);
+ memcpy(entry->key,old->key,cache->keysize*sizeof(DdNode *));
+ entry->value = old->value;
+ }
+ }
+
+ FREE(olditem);
+
+ /* Reinitialize measurements so as to avoid division by 0 and
+ ** immediate resizing.
+ */
+ cache->lookUps = (double) (int) (slots * cache->minHit + 1);
+ cache->hits = 0;
+
+} /* end of cuddLocalCacheResize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the hash value for a local cache.]
+
+ Description [Computes the hash value for a local cache. Returns the
+ bucket index.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DD_INLINE
+static unsigned int
+ddLCHash(
+ DdNodePtr * key,
+ unsigned int keysize,
+ int shift)
+{
+ unsigned int val = (unsigned int) (ptrint) key[0];
+ unsigned int i;
+
+ for (i = 1; i < keysize; i++) {
+ val = val * DD_P1 + (int) (ptrint) key[i];
+ }
+
+ return(val >> shift);
+
+} /* end of ddLCHash */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts a local cache in the manager list.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+cuddLocalCacheAddToList(
+ DdLocalCache * cache)
+{
+ DdManager *manager = cache->manager;
+
+ cache->next = manager->localCaches;
+ manager->localCaches = cache;
+ return;
+
+} /* end of cuddLocalCacheAddToList */
+
+
+/**Function********************************************************************
+
+ Synopsis [Removes a local cache from the manager list.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+cuddLocalCacheRemoveFromList(
+ DdLocalCache * cache)
+{
+ DdManager *manager = cache->manager;
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ DdLocalCache **prevCache, *nextCache;
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+
+ prevCache = &(manager->localCaches);
+ nextCache = manager->localCaches;
+
+ while (nextCache != NULL) {
+ if (nextCache == cache) {
+ *prevCache = nextCache->next;
+ return;
+ }
+ prevCache = &(nextCache->next);
+ nextCache = nextCache->next;
+ }
+ return; /* should never get here */
+
+} /* end of cuddLocalCacheRemoveFromList */
+
+
+/**Function********************************************************************
+
+ Synopsis [Resizes a hash table.]
+
+ Description [Resizes a hash table. Returns 1 if successful; 0
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddHashTableInsert]
+
+******************************************************************************/
+static int
+cuddHashTableResize(
+ DdHashTable * hash)
+{
+ int j;
+ unsigned int posn;
+ DdHashItem *item;
+ DdHashItem *next;
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ DdNode **key;
+ int numBuckets;
+ DdHashItem **buckets;
+ DdHashItem **oldBuckets = hash->bucket;
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+ int shift;
+ int oldNumBuckets = hash->numBuckets;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+
+ /* Compute the new size of the table. */
+ numBuckets = oldNumBuckets << 1;
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ buckets = ALLOC(DdHashItem *, numBuckets);
+ MMoutOfMemory = saveHandler;
+ if (buckets == NULL) {
+ hash->maxsize <<= 1;
+ return(1);
+ }
+
+ hash->bucket = buckets;
+ hash->numBuckets = numBuckets;
+ shift = --(hash->shift);
+ hash->maxsize <<= 1;
+ memset(buckets, 0, numBuckets * sizeof(DdHashItem *));
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+ if (hash->keysize == 1) {
+ for (j = 0; j < oldNumBuckets; j++) {
+ item = oldBuckets[j];
+ while (item != NULL) {
+ next = item->next;
+ key = item->key;
+ posn = ddLCHash2(key[0], key[0], shift);
+ item->next = buckets[posn];
+ buckets[posn] = item;
+ item = next;
+ }
+ }
+ } else if (hash->keysize == 2) {
+ for (j = 0; j < oldNumBuckets; j++) {
+ item = oldBuckets[j];
+ while (item != NULL) {
+ next = item->next;
+ key = item->key;
+ posn = ddLCHash2(key[0], key[1], shift);
+ item->next = buckets[posn];
+ buckets[posn] = item;
+ item = next;
+ }
+ }
+ } else if (hash->keysize == 3) {
+ for (j = 0; j < oldNumBuckets; j++) {
+ item = oldBuckets[j];
+ while (item != NULL) {
+ next = item->next;
+ key = item->key;
+ posn = ddLCHash3(key[0], key[1], key[2], shift);
+ item->next = buckets[posn];
+ buckets[posn] = item;
+ item = next;
+ }
+ }
+ } else {
+ for (j = 0; j < oldNumBuckets; j++) {
+ item = oldBuckets[j];
+ while (item != NULL) {
+ next = item->next;
+ posn = ddLCHash(item->key, hash->keysize, shift);
+ item->next = buckets[posn];
+ buckets[posn] = item;
+ item = next;
+ }
+ }
+ }
+ FREE(oldBuckets);
+ return(1);
+
+} /* end of cuddHashTableResize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Fast storage allocation for items in a hash table.]
+
+ Description [Fast storage allocation for items in a hash table. The
+ first 4 bytes of a chunk contain a pointer to the next block; the
+ rest contains DD_MEM_CHUNK spaces for hash items. Returns a pointer to
+ a new item if successful; NULL is memory is full.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddAllocNode cuddDynamicAllocNode]
+
+******************************************************************************/
+DD_INLINE
+static DdHashItem *
+cuddHashTableAlloc(
+ DdHashTable * hash)
+{
+ int i;
+ unsigned int itemsize = hash->itemsize;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ DdHashItem **mem, *thisOne, *next, *item;
+
+ if (hash->nextFree == NULL) {
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ mem = (DdHashItem **) ALLOC(char,(DD_MEM_CHUNK+1) * itemsize);
+ MMoutOfMemory = saveHandler;
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+ if (mem == NULL) {
+ if (hash->manager->stash != NULL) {
+ FREE(hash->manager->stash);
+ hash->manager->stash = NULL;
+ /* Inhibit resizing of tables. */
+ hash->manager->maxCacheHard = hash->manager->cacheSlots - 1;
+ hash->manager->cacheSlack = -(hash->manager->cacheSlots + 1);
+ for (i = 0; i < hash->manager->size; i++) {
+ hash->manager->subtables[i].maxKeys <<= 2;
+ }
+ hash->manager->gcFrac = 0.2;
+ hash->manager->minDead =
+ (unsigned) (0.2 * (double) hash->manager->slots);
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ mem = (DdHashItem **) ALLOC(char,(DD_MEM_CHUNK+1) * itemsize);
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+ }
+ if (mem == NULL) {
+ (*MMoutOfMemory)((DD_MEM_CHUNK + 1) * itemsize);
+ hash->manager->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ }
+
+ mem[0] = (DdHashItem *) hash->memoryList;
+ hash->memoryList = mem;
+
+ thisOne = (DdHashItem *) ((char *) mem + itemsize);
+ hash->nextFree = thisOne;
+ for (i = 1; i < DD_MEM_CHUNK; i++) {
+ next = (DdHashItem *) ((char *) thisOne + itemsize);
+ thisOne->next = next;
+ thisOne = next;
+ }
+
+ thisOne->next = NULL;
+
+ }
+ item = hash->nextFree;
+ hash->nextFree = item->next;
+ return(item);
+
+} /* end of cuddHashTableAlloc */
diff --git a/src/bdd/cudd/cuddLevelQ.c b/src/bdd/cudd/cuddLevelQ.c
new file mode 100644
index 00000000..c4c621e7
--- /dev/null
+++ b/src/bdd/cudd/cuddLevelQ.c
@@ -0,0 +1,533 @@
+/**CFile***********************************************************************
+
+ FileName [cuddLevelQ.c]
+
+ PackageName [cudd]
+
+ Synopsis [Procedure to manage level queues.]
+
+ Description [The functions in this file allow an application to
+ easily manipulate a queue where nodes are prioritized by level. The
+ emphasis is on efficiency. Therefore, the queue items can have
+ variable size. If the application does not need to attach
+ information to the nodes, it can declare the queue items to be of
+ type DdQueueItem. Otherwise, it can declare them to be of a
+ structure type such that the first three fields are data
+ pointers. The third pointer points to the node. The first two
+ pointers are used by the level queue functions. The remaining fields
+ are initialized to 0 when a new item is created, and are then left
+ to the exclusive use of the application. On the DEC Alphas the three
+ pointers must be 32-bit pointers when CUDD is compiled with 32-bit
+ pointers. The level queue functions make sure that each node
+ appears at most once in the queue. They do so by keeping a hash
+ table where the node is used as key. Queue items are recycled via a
+ free list for efficiency.
+
+ Internal procedures provided by this module:
+ <ul>
+ <li> cuddLevelQueueInit()
+ <li> cuddLevelQueueQuit()
+ <li> cuddLevelQueueEnqueue()
+ <li> cuddLevelQueueDequeue()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> hashLookup()
+ <li> hashInsert()
+ <li> hashDelete()
+ <li> hashResize()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no
+ warranty about the suitability of this software for any
+ purpose. It is presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddLevelQ.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Hash function for the table of a level queue.]
+
+ Description [Hash function for the table of a level queue.]
+
+ SideEffects [None]
+
+ SeeAlso [hashInsert hashLookup hashDelete]
+
+******************************************************************************/
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+#define lqHash(key,shift) \
+(((unsigned)(unsigned long)(key) * DD_P1) >> (shift))
+#else
+#define lqHash(key,shift) \
+(((unsigned)(key) * DD_P1) >> (shift))
+#endif
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdQueueItem * hashLookup ARGS((DdLevelQueue *queue, void *key));
+static int hashInsert ARGS((DdLevelQueue *queue, DdQueueItem *item));
+static void hashDelete ARGS((DdLevelQueue *queue, DdQueueItem *item));
+static int hashResize ARGS((DdLevelQueue *queue));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Initializes a level queue.]
+
+ Description [Initializes a level queue. A level queue is a queue
+ where inserts are based on the levels of the nodes. Within each
+ level the policy is FIFO. Level queues are useful in traversing a
+ BDD top-down. Queue items are kept in a free list when dequeued for
+ efficiency. Returns a pointer to the new queue if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddLevelQueueQuit cuddLevelQueueEnqueue cuddLevelQueueDequeue]
+
+******************************************************************************/
+DdLevelQueue *
+cuddLevelQueueInit(
+ int levels /* number of levels */,
+ int itemSize /* size of the item */,
+ int numBuckets /* initial number of hash buckets */)
+{
+ DdLevelQueue *queue;
+ int logSize;
+
+ queue = ALLOC(DdLevelQueue,1);
+ if (queue == NULL)
+ return(NULL);
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ /* Keep pointers to the insertion points for all levels. */
+ queue->last = ALLOC(DdQueueItem *, levels);
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+ if (queue->last == NULL) {
+ FREE(queue);
+ return(NULL);
+ }
+ /* Use a hash table to test for uniqueness. */
+ if (numBuckets < 2) numBuckets = 2;
+ logSize = cuddComputeFloorLog2(numBuckets);
+ queue->numBuckets = 1 << logSize;
+ queue->shift = sizeof(int) * 8 - logSize;
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ queue->buckets = ALLOC(DdQueueItem *, queue->numBuckets);
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+ if (queue->buckets == NULL) {
+ FREE(queue->last);
+ FREE(queue);
+ return(NULL);
+ }
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ memset(queue->last, 0, levels * sizeof(DdQueueItem *));
+ memset(queue->buckets, 0, queue->numBuckets * sizeof(DdQueueItem *));
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+ queue->first = NULL;
+ queue->freelist = NULL;
+ queue->levels = levels;
+ queue->itemsize = itemSize;
+ queue->size = 0;
+ queue->maxsize = queue->numBuckets * DD_MAX_SUBTABLE_DENSITY;
+ return(queue);
+
+} /* end of cuddLevelQueueInit */
+
+
+/**Function********************************************************************
+
+ Synopsis [Shuts down a level queue.]
+
+ Description [Shuts down a level queue and releases all the
+ associated memory.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddLevelQueueInit]
+
+******************************************************************************/
+void
+cuddLevelQueueQuit(
+ DdLevelQueue * queue)
+{
+ DdQueueItem *item;
+
+ while (queue->freelist != NULL) {
+ item = queue->freelist;
+ queue->freelist = item->next;
+ FREE(item);
+ }
+ while (queue->first != NULL) {
+ item = (DdQueueItem *) queue->first;
+ queue->first = item->next;
+ FREE(item);
+ }
+ FREE(queue->buckets);
+ FREE(queue->last);
+ FREE(queue);
+ return;
+
+} /* end of cuddLevelQueueQuit */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts a new key in a level queue.]
+
+ Description [Inserts a new key in a level queue. A new entry is
+ created in the queue only if the node is not already
+ enqueued. Returns a pointer to the queue item if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddLevelQueueInit cuddLevelQueueDequeue]
+
+******************************************************************************/
+void *
+cuddLevelQueueEnqueue(
+ DdLevelQueue * queue /* level queue */,
+ void * key /* key to be enqueued */,
+ int level /* level at which to insert */)
+{
+ int plevel;
+ DdQueueItem *item;
+
+#ifdef DD_DEBUG
+ assert(level < queue->levels);
+#endif
+ /* Check whether entry for this node exists. */
+ item = hashLookup(queue,key);
+ if (item != NULL) return(item);
+
+ /* Get a free item from either the free list or the memory manager. */
+ if (queue->freelist == NULL) {
+ item = (DdQueueItem *) ALLOC(char, queue->itemsize);
+ if (item == NULL)
+ return(NULL);
+ } else {
+ item = queue->freelist;
+ queue->freelist = item->next;
+ }
+ /* Initialize. */
+ memset(item, 0, queue->itemsize);
+ item->key = key;
+ /* Update stats. */
+ queue->size++;
+
+ if (queue->last[level]) {
+ /* There are already items for this level in the queue. */
+ item->next = queue->last[level]->next;
+ queue->last[level]->next = item;
+ } else {
+ /* There are no items at the current level. Look for the first
+ ** non-empty level preceeding this one. */
+ plevel = level;
+ while (plevel != 0 && queue->last[plevel] == NULL)
+ plevel--;
+ if (queue->last[plevel] == NULL) {
+ /* No element precedes this one in the queue. */
+ item->next = (DdQueueItem *) queue->first;
+ queue->first = item;
+ } else {
+ item->next = queue->last[plevel]->next;
+ queue->last[plevel]->next = item;
+ }
+ }
+ queue->last[level] = item;
+
+ /* Insert entry for the key in the hash table. */
+ if (hashInsert(queue,item) == 0) {
+ return(NULL);
+ }
+ return(item);
+
+} /* end of cuddLevelQueueEnqueue */
+
+
+/**Function********************************************************************
+
+ Synopsis [Remove an item from the front of a level queue.]
+
+ Description [Remove an item from the front of a level queue.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddLevelQueueEnqueue]
+
+******************************************************************************/
+void
+cuddLevelQueueDequeue(
+ DdLevelQueue * queue,
+ int level)
+{
+ DdQueueItem *item = (DdQueueItem *) queue->first;
+
+ /* Delete from the hash table. */
+ hashDelete(queue,item);
+
+ /* Since we delete from the front, if this is the last item for
+ ** its level, there are no other items for the same level. */
+ if (queue->last[level] == item)
+ queue->last[level] = NULL;
+
+ queue->first = item->next;
+ /* Put item on the free list. */
+ item->next = queue->freelist;
+ queue->freelist = item;
+ /* Update stats. */
+ queue->size--;
+ return;
+
+} /* end of cuddLevelQueueDequeue */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up a key in the hash table of a level queue.]
+
+ Description [Looks up a key in the hash table of a level queue. Returns
+ a pointer to the item with the given key if the key is found; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddLevelQueueEnqueue hashInsert]
+
+******************************************************************************/
+static DdQueueItem *
+hashLookup(
+ DdLevelQueue * queue,
+ void * key)
+{
+ int posn;
+ DdQueueItem *item;
+
+ posn = lqHash(key,queue->shift);
+ item = queue->buckets[posn];
+
+ while (item != NULL) {
+ if (item->key == key) {
+ return(item);
+ }
+ item = item->cnext;
+ }
+ return(NULL);
+
+} /* end of hashLookup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts an item in the hash table of a level queue.]
+
+ Description [Inserts an item in the hash table of a level queue. Returns
+ 1 if successful; 0 otherwise. No check is performed to see if an item with
+ the same key is already in the hash table.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddLevelQueueEnqueue]
+
+******************************************************************************/
+static int
+hashInsert(
+ DdLevelQueue * queue,
+ DdQueueItem * item)
+{
+ int result;
+ int posn;
+
+ if (queue->size > queue->maxsize) {
+ result = hashResize(queue);
+ if (result == 0) return(0);
+ }
+
+ posn = lqHash(item->key,queue->shift);
+ item->cnext = queue->buckets[posn];
+ queue->buckets[posn] = item;
+
+ return(1);
+
+} /* end of hashInsert */
+
+
+/**Function********************************************************************
+
+ Synopsis [Removes an item from the hash table of a level queue.]
+
+ Description [Removes an item from the hash table of a level queue.
+ Nothing is done if the item is not in the table.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddLevelQueueDequeue hashInsert]
+
+******************************************************************************/
+static void
+hashDelete(
+ DdLevelQueue * queue,
+ DdQueueItem * item)
+{
+ int posn;
+ DdQueueItem *prevItem;
+
+ posn = lqHash(item->key,queue->shift);
+ prevItem = queue->buckets[posn];
+
+ if (prevItem == NULL) return;
+ if (prevItem == item) {
+ queue->buckets[posn] = prevItem->cnext;
+ return;
+ }
+
+ while (prevItem->cnext != NULL) {
+ if (prevItem->cnext == item) {
+ prevItem->cnext = item->cnext;
+ return;
+ }
+ prevItem = prevItem->cnext;
+ }
+ return;
+
+} /* end of hashDelete */
+
+
+/**Function********************************************************************
+
+ Synopsis [Resizes the hash table of a level queue.]
+
+ Description [Resizes the hash table of a level queue. Returns 1 if
+ successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [hashInsert]
+
+******************************************************************************/
+static int
+hashResize(
+ DdLevelQueue * queue)
+{
+ int j;
+ int posn;
+ DdQueueItem *item;
+ DdQueueItem *next;
+ int numBuckets;
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ DdQueueItem **buckets;
+ DdQueueItem **oldBuckets = queue->buckets;
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+ int shift;
+ int oldNumBuckets = queue->numBuckets;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+
+ /* Compute the new size of the subtable. */
+ numBuckets = oldNumBuckets << 1;
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ buckets = queue->buckets = ALLOC(DdQueueItem *, numBuckets);
+ if (buckets == NULL) {
+ queue->maxsize <<= 1;
+ return(1);
+ }
+
+ queue->numBuckets = numBuckets;
+ shift = --(queue->shift);
+ queue->maxsize <<= 1;
+ memset(buckets, 0, numBuckets * sizeof(DdQueueItem *));
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+ for (j = 0; j < oldNumBuckets; j++) {
+ item = oldBuckets[j];
+ while (item != NULL) {
+ next = item->cnext;
+ posn = lqHash(item->key, shift);
+ item->cnext = buckets[posn];
+ buckets[posn] = item;
+ item = next;
+ }
+ }
+ FREE(oldBuckets);
+ return(1);
+
+} /* end of hashResize */
diff --git a/src/bdd/cudd/cuddLinear.c b/src/bdd/cudd/cuddLinear.c
new file mode 100644
index 00000000..cec7c255
--- /dev/null
+++ b/src/bdd/cudd/cuddLinear.c
@@ -0,0 +1,1333 @@
+/**CFile***********************************************************************
+
+ FileName [cuddLinear.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for DD reduction by linear transformations.]
+
+ Description [ Internal procedures included in this module:
+ <ul>
+ <li> cuddLinearAndSifting()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> ddLinearUniqueCompare()
+ <li> ddLinearAndSiftingAux()
+ <li> ddLinearAndSiftingUp()
+ <li> ddLinearAndSiftingDown()
+ <li> ddLinearAndSiftingBackward()
+ <li> ddUndoMoves()
+ <li> ddUpdateInteractionMatrix()
+ <li> cuddLinearInPlace()
+ <li> cuddInitLinear()
+ <li> cuddResizeLinear()
+ <li> cuddXorLinear()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define CUDD_SWAP_MOVE 0
+#define CUDD_LINEAR_TRANSFORM_MOVE 1
+#define CUDD_INVERSE_TRANSFORM_MOVE 2
+#if SIZEOF_LONG == 8
+#define BPL 64
+#define LOGBPL 6
+#else
+#define BPL 32
+#define LOGBPL 5
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddLinear.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+static int *entry;
+
+#ifdef DD_STATS
+extern int ddTotalNumberSwapping;
+extern int ddTotalNISwaps;
+static int ddTotalNumberLinearTr;
+#endif
+
+#ifdef DD_DEBUG
+static int zero = 0;
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int ddLinearUniqueCompare ARGS((int *ptrX, int *ptrY));
+static int ddLinearAndSiftingAux ARGS((DdManager *table, int x, int xLow, int xHigh));
+static Move * ddLinearAndSiftingUp ARGS((DdManager *table, int y, int xLow, Move *prevMoves));
+static Move * ddLinearAndSiftingDown ARGS((DdManager *table, int x, int xHigh, Move *prevMoves));
+static int ddLinearAndSiftingBackward ARGS((DdManager *table, int size, Move *moves));
+static Move* ddUndoMoves ARGS((DdManager *table, Move *moves));
+static int cuddLinearInPlace ARGS((DdManager *table, int x, int y));
+static void ddUpdateInteractionMatrix ARGS((DdManager *table, int xindex, int yindex));
+static int cuddInitLinear ARGS((DdManager *table));
+static int cuddResizeLinear ARGS((DdManager *table));
+static void cuddXorLinear ARGS((DdManager *table, int x, int y));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints the linear transform matrix.]
+
+ Description [Prints the linear transform matrix. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_PrintLinear(
+ DdManager * table)
+{
+ int i,j,k;
+ int retval;
+ int nvars = table->linearSize;
+ int wordsPerRow = ((nvars - 1) >> LOGBPL) + 1;
+ long word;
+
+ for (i = 0; i < nvars; i++) {
+ for (j = 0; j < wordsPerRow; j++) {
+ word = table->linear[i*wordsPerRow + j];
+ for (k = 0; k < BPL; k++) {
+ retval = fprintf(table->out,"%ld",word & 1);
+ if (retval == 0) return(0);
+ word >>= 1;
+ }
+ }
+ retval = fprintf(table->out,"\n");
+ if (retval == 0) return(0);
+ }
+ return(1);
+
+} /* end of Cudd_PrintLinear */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads an entry of the linear transform matrix.]
+
+ Description [Reads an entry of the linear transform matrix.]
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_ReadLinear(
+ DdManager * table /* CUDD manager */,
+ int x /* row index */,
+ int y /* column index */)
+{
+ int nvars = table->size;
+ int wordsPerRow = ((nvars - 1) >> LOGBPL) + 1;
+ long word;
+ int bit;
+ int result;
+
+ assert(table->size == table->linearSize);
+
+ word = wordsPerRow * x + (y >> LOGBPL);
+ bit = y & (BPL-1);
+ result = (int) ((table->linear[word] >> bit) & 1);
+ return(result);
+
+} /* end of Cudd_ReadLinear */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [BDD reduction based on combination of sifting and linear
+ transformations.]
+
+ Description [BDD reduction based on combination of sifting and linear
+ transformations. Assumes that no dead nodes are present.
+ <ol>
+ <li> Order all the variables according to the number of entries
+ in each unique table.
+ <li> Sift the variable up and down, remembering each time the
+ total size of the DD heap. At each position, linear transformation
+ of the two adjacent variables is tried and is accepted if it reduces
+ the size of the DD.
+ <li> Select the best permutation.
+ <li> Repeat 3 and 4 for all variables.
+ </ol>
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+int
+cuddLinearAndSifting(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i;
+ int *var;
+ int size;
+ int x;
+ int result;
+#ifdef DD_STATS
+ int previousSize;
+#endif
+
+#ifdef DD_STATS
+ ddTotalNumberLinearTr = 0;
+#endif
+
+ size = table->size;
+
+ var = NULL;
+ entry = NULL;
+ if (table->linear == NULL) {
+ result = cuddInitLinear(table);
+ if (result == 0) goto cuddLinearAndSiftingOutOfMem;
+#if 0
+ (void) fprintf(table->out,"\n");
+ result = Cudd_PrintLinear(table);
+ if (result == 0) goto cuddLinearAndSiftingOutOfMem;
+#endif
+ } else if (table->size != table->linearSize) {
+ result = cuddResizeLinear(table);
+ if (result == 0) goto cuddLinearAndSiftingOutOfMem;
+#if 0
+ (void) fprintf(table->out,"\n");
+ result = Cudd_PrintLinear(table);
+ if (result == 0) goto cuddLinearAndSiftingOutOfMem;
+#endif
+ }
+
+ /* Find order in which to sift variables. */
+ entry = ALLOC(int,size);
+ if (entry == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddLinearAndSiftingOutOfMem;
+ }
+ var = ALLOC(int,size);
+ if (var == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddLinearAndSiftingOutOfMem;
+ }
+
+ for (i = 0; i < size; i++) {
+ x = table->perm[i];
+ entry[i] = table->subtables[x].keys;
+ var[i] = i;
+ }
+
+ qsort((void *)var,size,sizeof(int),(int (*)(const void *, const void *))ddLinearUniqueCompare);
+
+ /* Now sift. */
+ for (i = 0; i < ddMin(table->siftMaxVar,size); i++) {
+ x = table->perm[var[i]];
+ if (x < lower || x > upper) continue;
+#ifdef DD_STATS
+ previousSize = table->keys - table->isolated;
+#endif
+ result = ddLinearAndSiftingAux(table,x,lower,upper);
+ if (!result) goto cuddLinearAndSiftingOutOfMem;
+#ifdef DD_STATS
+ if (table->keys < (unsigned) previousSize + table->isolated) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keys > (unsigned) previousSize + table->isolated) {
+ (void) fprintf(table->out,"+"); /* should never happen */
+ (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keys - table->isolated, var[i]);
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+#ifdef DD_DEBUG
+ (void) Cudd_DebugCheck(table);
+#endif
+ }
+
+ FREE(var);
+ FREE(entry);
+
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n#:L_LINSIFT %8d: linear trans.",
+ ddTotalNumberLinearTr);
+#endif
+
+ return(1);
+
+cuddLinearAndSiftingOutOfMem:
+
+ if (entry != NULL) FREE(entry);
+ if (var != NULL) FREE(var);
+
+ return(0);
+
+} /* end of cuddLinearAndSifting */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Comparison function used by qsort.]
+
+ Description [Comparison function used by qsort to order the
+ variables according to the number of keys in the subtables.
+ Returns the difference in number of keys between the two
+ variables being compared.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddLinearUniqueCompare(
+ int * ptrX,
+ int * ptrY)
+{
+#if 0
+ if (entry[*ptrY] == entry[*ptrX]) {
+ return((*ptrX) - (*ptrY));
+ }
+#endif
+ return(entry[*ptrY] - entry[*ptrX]);
+
+} /* end of ddLinearUniqueCompare */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries.]
+
+ Description [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries. At each step a linear transformation is tried, and, if it
+ decreases the size of the DD, it is accepted. Finds the best position
+ and does the required changes. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddLinearAndSiftingAux(
+ DdManager * table,
+ int x,
+ int xLow,
+ int xHigh)
+{
+
+ Move *move;
+ Move *moveUp; /* list of up moves */
+ Move *moveDown; /* list of down moves */
+ int initialSize;
+ int result;
+
+ initialSize = table->keys - table->isolated;
+
+ moveDown = NULL;
+ moveUp = NULL;
+
+ if (x == xLow) {
+ moveDown = ddLinearAndSiftingDown(table,x,xHigh,NULL);
+ /* At this point x --> xHigh unless bounding occurred. */
+ if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
+ /* Move backward and stop at best position. */
+ result = ddLinearAndSiftingBackward(table,initialSize,moveDown);
+ if (!result) goto ddLinearAndSiftingAuxOutOfMem;
+
+ } else if (x == xHigh) {
+ moveUp = ddLinearAndSiftingUp(table,x,xLow,NULL);
+ /* At this point x --> xLow unless bounding occurred. */
+ if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
+ /* Move backward and stop at best position. */
+ result = ddLinearAndSiftingBackward(table,initialSize,moveUp);
+ if (!result) goto ddLinearAndSiftingAuxOutOfMem;
+
+ } else if ((x - xLow) > (xHigh - x)) { /* must go down first: shorter */
+ moveDown = ddLinearAndSiftingDown(table,x,xHigh,NULL);
+ /* At this point x --> xHigh unless bounding occurred. */
+ if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
+ moveUp = ddUndoMoves(table,moveDown);
+#ifdef DD_DEBUG
+ assert(moveUp == NULL || moveUp->x == x);
+#endif
+ moveUp = ddLinearAndSiftingUp(table,x,xLow,moveUp);
+ if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
+ /* Move backward and stop at best position. */
+ result = ddLinearAndSiftingBackward(table,initialSize,moveUp);
+ if (!result) goto ddLinearAndSiftingAuxOutOfMem;
+
+ } else { /* must go up first: shorter */
+ moveUp = ddLinearAndSiftingUp(table,x,xLow,NULL);
+ /* At this point x --> xLow unless bounding occurred. */
+ if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
+ moveDown = ddUndoMoves(table,moveUp);
+#ifdef DD_DEBUG
+ assert(moveDown == NULL || moveDown->y == x);
+#endif
+ moveDown = ddLinearAndSiftingDown(table,x,xHigh,moveDown);
+ if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
+ /* Move backward and stop at best position. */
+ result = ddLinearAndSiftingBackward(table,initialSize,moveDown);
+ if (!result) goto ddLinearAndSiftingAuxOutOfMem;
+ }
+
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *) moveDown);
+ moveDown = move;
+ }
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *) moveUp);
+ moveUp = move;
+ }
+
+ return(1);
+
+ddLinearAndSiftingAuxOutOfMem:
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *) moveDown);
+ moveDown = move;
+ }
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *) moveUp);
+ moveUp = move;
+ }
+
+ return(0);
+
+} /* end of ddLinearAndSiftingAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts a variable up and applies linear transformations.]
+
+ Description [Sifts a variable up and applies linear transformations.
+ Moves y up until either it reaches the bound (xLow) or the size of
+ the DD heap increases too much. Returns the set of moves in case of
+ success; NULL if memory is full.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static Move *
+ddLinearAndSiftingUp(
+ DdManager * table,
+ int y,
+ int xLow,
+ Move * prevMoves)
+{
+ Move *moves;
+ Move *move;
+ int x;
+ int size, newsize;
+ int limitSize;
+ int xindex, yindex;
+ int isolated;
+ int L; /* lower bound on DD size */
+#ifdef DD_DEBUG
+ int checkL;
+ int z;
+ int zindex;
+#endif
+
+ moves = prevMoves;
+ yindex = table->invperm[y];
+
+ /* Initialize the lower bound.
+ ** The part of the DD below y will not change.
+ ** The part of the DD above y that does not interact with y will not
+ ** change. The rest may vanish in the best case, except for
+ ** the nodes at level xLow, which will not vanish, regardless.
+ */
+ limitSize = L = table->keys - table->isolated;
+ for (x = xLow + 1; x < y; x++) {
+ xindex = table->invperm[x];
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[xindex]->ref == 1;
+ L -= table->subtables[x].keys - isolated;
+ }
+ }
+ isolated = table->vars[yindex]->ref == 1;
+ L -= table->subtables[y].keys - isolated;
+
+ x = cuddNextLow(table,y);
+ while (x >= xLow && L <= limitSize) {
+ xindex = table->invperm[x];
+#ifdef DD_DEBUG
+ checkL = table->keys - table->isolated;
+ for (z = xLow + 1; z < y; z++) {
+ zindex = table->invperm[z];
+ if (cuddTestInteract(table,zindex,yindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ checkL -= table->subtables[z].keys - isolated;
+ }
+ }
+ isolated = table->vars[yindex]->ref == 1;
+ checkL -= table->subtables[y].keys - isolated;
+ if (L != checkL) {
+ (void) fprintf(table->out, "checkL(%d) != L(%d)\n",checkL,L);
+ }
+#endif
+ size = cuddSwapInPlace(table,x,y);
+ if (size == 0) goto ddLinearAndSiftingUpOutOfMem;
+ newsize = cuddLinearInPlace(table,x,y);
+ if (newsize == 0) goto ddLinearAndSiftingUpOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddLinearAndSiftingUpOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->next = moves;
+ moves = move;
+ move->flags = CUDD_SWAP_MOVE;
+ if (newsize >= size) {
+ /* Undo transformation. The transformation we apply is
+ ** its own inverse. Hence, we just apply the transformation
+ ** again.
+ */
+ newsize = cuddLinearInPlace(table,x,y);
+ if (newsize == 0) goto ddLinearAndSiftingUpOutOfMem;
+#ifdef DD_DEBUG
+ if (newsize != size) {
+ (void) fprintf(table->out,"Change in size after identity transformation! From %d to %d\n",size,newsize);
+ }
+#endif
+ } else if (cuddTestInteract(table,xindex,yindex)) {
+ size = newsize;
+ move->flags = CUDD_LINEAR_TRANSFORM_MOVE;
+ ddUpdateInteractionMatrix(table,xindex,yindex);
+ }
+ move->size = size;
+ /* Update the lower bound. */
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[xindex]->ref == 1;
+ L += table->subtables[y].keys - isolated;
+ }
+ if ((double) size > (double) limitSize * table->maxGrowth) break;
+ if (size < limitSize) limitSize = size;
+ y = x;
+ x = cuddNextLow(table,y);
+ }
+ return(moves);
+
+ddLinearAndSiftingUpOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return((Move *) CUDD_OUT_OF_MEM);
+
+} /* end of ddLinearAndSiftingUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts a variable down and applies linear transformations.]
+
+ Description [Sifts a variable down and applies linear
+ transformations. Moves x down until either it reaches the bound
+ (xHigh) or the size of the DD heap increases too much. Returns the
+ set of moves in case of success; NULL if memory is full.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static Move *
+ddLinearAndSiftingDown(
+ DdManager * table,
+ int x,
+ int xHigh,
+ Move * prevMoves)
+{
+ Move *moves;
+ Move *move;
+ int y;
+ int size, newsize;
+ int R; /* upper bound on node decrease */
+ int limitSize;
+ int xindex, yindex;
+ int isolated;
+#ifdef DD_DEBUG
+ int checkR;
+ int z;
+ int zindex;
+#endif
+
+ moves = prevMoves;
+ /* Initialize R */
+ xindex = table->invperm[x];
+ limitSize = size = table->keys - table->isolated;
+ R = 0;
+ for (y = xHigh; y > x; y--) {
+ yindex = table->invperm[y];
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[yindex]->ref == 1;
+ R += table->subtables[y].keys - isolated;
+ }
+ }
+
+ y = cuddNextHigh(table,x);
+ while (y <= xHigh && size - R < limitSize) {
+#ifdef DD_DEBUG
+ checkR = 0;
+ for (z = xHigh; z > x; z--) {
+ zindex = table->invperm[z];
+ if (cuddTestInteract(table,xindex,zindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ checkR += table->subtables[z].keys - isolated;
+ }
+ }
+ if (R != checkR) {
+ (void) fprintf(table->out, "checkR(%d) != R(%d)\n",checkR,R);
+ }
+#endif
+ /* Update upper bound on node decrease. */
+ yindex = table->invperm[y];
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[yindex]->ref == 1;
+ R -= table->subtables[y].keys - isolated;
+ }
+ size = cuddSwapInPlace(table,x,y);
+ if (size == 0) goto ddLinearAndSiftingDownOutOfMem;
+ newsize = cuddLinearInPlace(table,x,y);
+ if (newsize == 0) goto ddLinearAndSiftingDownOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddLinearAndSiftingDownOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->next = moves;
+ moves = move;
+ move->flags = CUDD_SWAP_MOVE;
+ if (newsize >= size) {
+ /* Undo transformation. The transformation we apply is
+ ** its own inverse. Hence, we just apply the transformation
+ ** again.
+ */
+ newsize = cuddLinearInPlace(table,x,y);
+ if (newsize == 0) goto ddLinearAndSiftingDownOutOfMem;
+ if (newsize != size) {
+ (void) fprintf(table->out,"Change in size after identity transformation! From %d to %d\n",size,newsize);
+ }
+ } else if (cuddTestInteract(table,xindex,yindex)) {
+ size = newsize;
+ move->flags = CUDD_LINEAR_TRANSFORM_MOVE;
+ ddUpdateInteractionMatrix(table,xindex,yindex);
+ }
+ move->size = size;
+ if ((double) size > (double) limitSize * table->maxGrowth) break;
+ if (size < limitSize) limitSize = size;
+ x = y;
+ y = cuddNextHigh(table,x);
+ }
+ return(moves);
+
+ddLinearAndSiftingDownOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return((Move *) CUDD_OUT_OF_MEM);
+
+} /* end of ddLinearAndSiftingDown */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given a set of moves, returns the DD heap to the order
+ giving the minimum size.]
+
+ Description [Given a set of moves, returns the DD heap to the
+ position giving the minimum size. In case of ties, returns to the
+ closest position giving the minimum size. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddLinearAndSiftingBackward(
+ DdManager * table,
+ int size,
+ Move * moves)
+{
+ Move *move;
+ int res;
+
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size < size) {
+ size = move->size;
+ }
+ }
+
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size == size) return(1);
+ if (move->flags == CUDD_LINEAR_TRANSFORM_MOVE) {
+ res = cuddLinearInPlace(table,(int)move->x,(int)move->y);
+ if (!res) return(0);
+ }
+ res = cuddSwapInPlace(table,(int)move->x,(int)move->y);
+ if (!res) return(0);
+ if (move->flags == CUDD_INVERSE_TRANSFORM_MOVE) {
+ res = cuddLinearInPlace(table,(int)move->x,(int)move->y);
+ if (!res) return(0);
+ }
+ }
+
+ return(1);
+
+} /* end of ddLinearAndSiftingBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given a set of moves, returns the DD heap to the order
+ in effect before the moves.]
+
+ Description [Given a set of moves, returns the DD heap to the
+ order in effect before the moves. Returns 1 in case of success;
+ 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static Move*
+ddUndoMoves(
+ DdManager * table,
+ Move * moves)
+{
+ Move *invmoves = NULL;
+ Move *move;
+ Move *invmove;
+ int size;
+
+ for (move = moves; move != NULL; move = move->next) {
+ invmove = (Move *) cuddDynamicAllocNode(table);
+ if (invmove == NULL) goto ddUndoMovesOutOfMem;
+ invmove->x = move->x;
+ invmove->y = move->y;
+ invmove->next = invmoves;
+ invmoves = invmove;
+ if (move->flags == CUDD_SWAP_MOVE) {
+ invmove->flags = CUDD_SWAP_MOVE;
+ size = cuddSwapInPlace(table,(int)move->x,(int)move->y);
+ if (!size) goto ddUndoMovesOutOfMem;
+ } else if (move->flags == CUDD_LINEAR_TRANSFORM_MOVE) {
+ invmove->flags = CUDD_INVERSE_TRANSFORM_MOVE;
+ size = cuddLinearInPlace(table,(int)move->x,(int)move->y);
+ if (!size) goto ddUndoMovesOutOfMem;
+ size = cuddSwapInPlace(table,(int)move->x,(int)move->y);
+ if (!size) goto ddUndoMovesOutOfMem;
+ } else { /* must be CUDD_INVERSE_TRANSFORM_MOVE */
+#ifdef DD_DEBUG
+ (void) fprintf(table->err,"Unforseen event in ddUndoMoves!\n");
+#endif
+ invmove->flags = CUDD_LINEAR_TRANSFORM_MOVE;
+ size = cuddSwapInPlace(table,(int)move->x,(int)move->y);
+ if (!size) goto ddUndoMovesOutOfMem;
+ size = cuddLinearInPlace(table,(int)move->x,(int)move->y);
+ if (!size) goto ddUndoMovesOutOfMem;
+ }
+ invmove->size = size;
+ }
+
+ return(invmoves);
+
+ddUndoMovesOutOfMem:
+ while (invmoves != NULL) {
+ move = invmoves->next;
+ cuddDeallocNode(table, (DdNode *) invmoves);
+ invmoves = move;
+ }
+ return((Move *) CUDD_OUT_OF_MEM);
+
+} /* end of ddUndoMoves */
+
+
+/**Function********************************************************************
+
+ Synopsis [Linearly combines two adjacent variables.]
+
+ Description [Linearly combines two adjacent variables. Specifically,
+ replaces the top variable with the exclusive nor of the two variables.
+ It assumes that no dead nodes are present on entry to this
+ procedure. The procedure then guarantees that no dead nodes will be
+ present when it terminates. cuddLinearInPlace assumes that x &lt;
+ y. Returns the number of keys in the table if successful; 0
+ otherwise.]
+
+ SideEffects [The two subtables corrresponding to variables x and y are
+ modified. The global counters of the unique table are also affected.]
+
+ SeeAlso [cuddSwapInPlace]
+
+******************************************************************************/
+static int
+cuddLinearInPlace(
+ DdManager * table,
+ int x,
+ int y)
+{
+ DdNodePtr *xlist, *ylist;
+ int xindex, yindex;
+ int xslots, yslots;
+ int xshift, yshift;
+ int oldxkeys, oldykeys;
+ int newxkeys, newykeys;
+ int comple, newcomplement;
+ int i;
+ int posn;
+ int isolated;
+ DdNode *f,*f0,*f1,*f01,*f00,*f11,*f10,*newf1,*newf0;
+ DdNode *g,*next,*last;
+ DdNodePtr *previousP;
+ DdNode *tmp;
+ DdNode *sentinel = &(table->sentinel);
+#if DD_DEBUG
+ int count, idcheck;
+#endif
+
+#ifdef DD_DEBUG
+ assert(x < y);
+ assert(cuddNextHigh(table,x) == y);
+ assert(table->subtables[x].keys != 0);
+ assert(table->subtables[y].keys != 0);
+ assert(table->subtables[x].dead == 0);
+ assert(table->subtables[y].dead == 0);
+#endif
+
+ xindex = table->invperm[x];
+ yindex = table->invperm[y];
+
+ if (cuddTestInteract(table,xindex,yindex)) {
+#ifdef DD_STATS
+ ddTotalNumberLinearTr++;
+#endif
+ /* Get parameters of x subtable. */
+ xlist = table->subtables[x].nodelist;
+ oldxkeys = table->subtables[x].keys;
+ xslots = table->subtables[x].slots;
+ xshift = table->subtables[x].shift;
+
+ /* Get parameters of y subtable. */
+ ylist = table->subtables[y].nodelist;
+ oldykeys = table->subtables[y].keys;
+ yslots = table->subtables[y].slots;
+ yshift = table->subtables[y].shift;
+
+ newxkeys = 0;
+ newykeys = oldykeys;
+
+ /* Check whether the two projection functions involved in this
+ ** swap are isolated. At the end, we'll be able to tell how many
+ ** isolated projection functions are there by checking only these
+ ** two functions again. This is done to eliminate the isolated
+ ** projection functions from the node count.
+ */
+ isolated = - ((table->vars[xindex]->ref == 1) +
+ (table->vars[yindex]->ref == 1));
+
+ /* The nodes in the x layer are put in a chain.
+ ** The chain is handled as a FIFO; g points to the beginning and
+ ** last points to the end.
+ */
+ g = NULL;
+ for (i = 0; i < xslots; i++) {
+ f = xlist[i];
+ if (f == sentinel) continue;
+ xlist[i] = sentinel;
+ if (g == NULL) {
+ g = f;
+ } else {
+ last->next = f;
+ }
+ while ((next = f->next) != sentinel) {
+ f = next;
+ } /* while there are elements in the collision chain */
+ last = f;
+ } /* for each slot of the x subtable */
+ last->next = NULL;
+
+#ifdef DD_COUNT
+ table->swapSteps += oldxkeys;
+#endif
+ /* Take care of the x nodes that must be re-expressed.
+ ** They form a linked list pointed by g.
+ */
+ f = g;
+ while (f != NULL) {
+ next = f->next;
+ /* Find f1, f0, f11, f10, f01, f00. */
+ f1 = cuddT(f);
+#ifdef DD_DEBUG
+ assert(!(Cudd_IsComplement(f1)));
+#endif
+ if ((int) f1->index == yindex) {
+ f11 = cuddT(f1); f10 = cuddE(f1);
+ } else {
+ f11 = f10 = f1;
+ }
+#ifdef DD_DEBUG
+ assert(!(Cudd_IsComplement(f11)));
+#endif
+ f0 = cuddE(f);
+ comple = Cudd_IsComplement(f0);
+ f0 = Cudd_Regular(f0);
+ if ((int) f0->index == yindex) {
+ f01 = cuddT(f0); f00 = cuddE(f0);
+ } else {
+ f01 = f00 = f0;
+ }
+ if (comple) {
+ f01 = Cudd_Not(f01);
+ f00 = Cudd_Not(f00);
+ }
+ /* Decrease ref count of f1. */
+ cuddSatDec(f1->ref);
+ /* Create the new T child. */
+ if (f11 == f00) {
+ newf1 = f11;
+ cuddSatInc(newf1->ref);
+ } else {
+ /* Check ylist for triple (yindex,f11,f00). */
+ posn = ddHash(f11, f00, yshift);
+ /* For each element newf1 in collision list ylist[posn]. */
+ previousP = &(ylist[posn]);
+ newf1 = *previousP;
+ while (f11 < cuddT(newf1)) {
+ previousP = &(newf1->next);
+ newf1 = *previousP;
+ }
+ while (f11 == cuddT(newf1) && f00 < cuddE(newf1)) {
+ previousP = &(newf1->next);
+ newf1 = *previousP;
+ }
+ if (cuddT(newf1) == f11 && cuddE(newf1) == f00) {
+ cuddSatInc(newf1->ref);
+ } else { /* no match */
+ newf1 = cuddDynamicAllocNode(table);
+ if (newf1 == NULL)
+ goto cuddLinearOutOfMem;
+ newf1->index = yindex; newf1->ref = 1;
+ cuddT(newf1) = f11;
+ cuddE(newf1) = f00;
+ /* Insert newf1 in the collision list ylist[posn];
+ ** increase the ref counts of f11 and f00.
+ */
+ newykeys++;
+ newf1->next = *previousP;
+ *previousP = newf1;
+ cuddSatInc(f11->ref);
+ tmp = Cudd_Regular(f00);
+ cuddSatInc(tmp->ref);
+ }
+ }
+ cuddT(f) = newf1;
+#ifdef DD_DEBUG
+ assert(!(Cudd_IsComplement(newf1)));
+#endif
+
+ /* Do the same for f0, keeping complement dots into account. */
+ /* decrease ref count of f0 */
+ tmp = Cudd_Regular(f0);
+ cuddSatDec(tmp->ref);
+ /* create the new E child */
+ if (f01 == f10) {
+ newf0 = f01;
+ tmp = Cudd_Regular(newf0);
+ cuddSatInc(tmp->ref);
+ } else {
+ /* make sure f01 is regular */
+ newcomplement = Cudd_IsComplement(f01);
+ if (newcomplement) {
+ f01 = Cudd_Not(f01);
+ f10 = Cudd_Not(f10);
+ }
+ /* Check ylist for triple (yindex,f01,f10). */
+ posn = ddHash(f01, f10, yshift);
+ /* For each element newf0 in collision list ylist[posn]. */
+ previousP = &(ylist[posn]);
+ newf0 = *previousP;
+ while (f01 < cuddT(newf0)) {
+ previousP = &(newf0->next);
+ newf0 = *previousP;
+ }
+ while (f01 == cuddT(newf0) && f10 < cuddE(newf0)) {
+ previousP = &(newf0->next);
+ newf0 = *previousP;
+ }
+ if (cuddT(newf0) == f01 && cuddE(newf0) == f10) {
+ cuddSatInc(newf0->ref);
+ } else { /* no match */
+ newf0 = cuddDynamicAllocNode(table);
+ if (newf0 == NULL)
+ goto cuddLinearOutOfMem;
+ newf0->index = yindex; newf0->ref = 1;
+ cuddT(newf0) = f01;
+ cuddE(newf0) = f10;
+ /* Insert newf0 in the collision list ylist[posn];
+ ** increase the ref counts of f01 and f10.
+ */
+ newykeys++;
+ newf0->next = *previousP;
+ *previousP = newf0;
+ cuddSatInc(f01->ref);
+ tmp = Cudd_Regular(f10);
+ cuddSatInc(tmp->ref);
+ }
+ if (newcomplement) {
+ newf0 = Cudd_Not(newf0);
+ }
+ }
+ cuddE(f) = newf0;
+
+ /* Re-insert the modified f in xlist.
+ ** The modified f does not already exists in xlist.
+ ** (Because of the uniqueness of the cofactors.)
+ */
+ posn = ddHash(newf1, newf0, xshift);
+ newxkeys++;
+ previousP = &(xlist[posn]);
+ tmp = *previousP;
+ while (newf1 < cuddT(tmp)) {
+ previousP = &(tmp->next);
+ tmp = *previousP;
+ }
+ while (newf1 == cuddT(tmp) && newf0 < cuddE(tmp)) {
+ previousP = &(tmp->next);
+ tmp = *previousP;
+ }
+ f->next = *previousP;
+ *previousP = f;
+ f = next;
+ } /* while f != NULL */
+
+ /* GC the y layer. */
+
+ /* For each node f in ylist. */
+ for (i = 0; i < yslots; i++) {
+ previousP = &(ylist[i]);
+ f = *previousP;
+ while (f != sentinel) {
+ next = f->next;
+ if (f->ref == 0) {
+ tmp = cuddT(f);
+ cuddSatDec(tmp->ref);
+ tmp = Cudd_Regular(cuddE(f));
+ cuddSatDec(tmp->ref);
+ cuddDeallocNode(table,f);
+ newykeys--;
+ } else {
+ *previousP = f;
+ previousP = &(f->next);
+ }
+ f = next;
+ } /* while f */
+ *previousP = sentinel;
+ } /* for every collision list */
+
+#if DD_DEBUG
+#if 0
+ (void) fprintf(table->out,"Linearly combining %d and %d\n",x,y);
+#endif
+ count = 0;
+ idcheck = 0;
+ for (i = 0; i < yslots; i++) {
+ f = ylist[i];
+ while (f != sentinel) {
+ count++;
+ if (f->index != (DdHalfWord) yindex)
+ idcheck++;
+ f = f->next;
+ }
+ }
+ if (count != newykeys) {
+ fprintf(table->err,"Error in finding newykeys\toldykeys = %d\tnewykeys = %d\tactual = %d\n",oldykeys,newykeys,count);
+ }
+ if (idcheck != 0)
+ fprintf(table->err,"Error in id's of ylist\twrong id's = %d\n",idcheck);
+ count = 0;
+ idcheck = 0;
+ for (i = 0; i < xslots; i++) {
+ f = xlist[i];
+ while (f != sentinel) {
+ count++;
+ if (f->index != (DdHalfWord) xindex)
+ idcheck++;
+ f = f->next;
+ }
+ }
+ if (count != newxkeys || newxkeys != oldxkeys) {
+ fprintf(table->err,"Error in finding newxkeys\toldxkeys = %d \tnewxkeys = %d \tactual = %d\n",oldxkeys,newxkeys,count);
+ }
+ if (idcheck != 0)
+ fprintf(table->err,"Error in id's of xlist\twrong id's = %d\n",idcheck);
+#endif
+
+ isolated += (table->vars[xindex]->ref == 1) +
+ (table->vars[yindex]->ref == 1);
+ table->isolated += isolated;
+
+ /* Set the appropriate fields in table. */
+ table->subtables[y].keys = newykeys;
+
+ /* Here we should update the linear combination table
+ ** to record that x <- x EXNOR y. This is done by complementing
+ ** the (x,y) entry of the table.
+ */
+
+ table->keys += newykeys - oldykeys;
+
+ cuddXorLinear(table,xindex,yindex);
+ }
+
+#ifdef DD_DEBUG
+ if (zero) {
+ (void) Cudd_DebugCheck(table);
+ }
+#endif
+
+ return(table->keys - table->isolated);
+
+cuddLinearOutOfMem:
+ (void) fprintf(table->err,"Error: cuddLinearInPlace out of memory\n");
+
+ return (0);
+
+} /* end of cuddLinearInPlace */
+
+
+/**Function********************************************************************
+
+ Synopsis [Updates the interaction matrix.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ddUpdateInteractionMatrix(
+ DdManager * table,
+ int xindex,
+ int yindex)
+{
+ int i;
+ for (i = 0; i < yindex; i++) {
+ if (i != xindex && cuddTestInteract(table,i,yindex)) {
+ if (i < xindex) {
+ cuddSetInteract(table,i,xindex);
+ } else {
+ cuddSetInteract(table,xindex,i);
+ }
+ }
+ }
+ for (i = yindex+1; i < table->size; i++) {
+ if (i != xindex && cuddTestInteract(table,yindex,i)) {
+ if (i < xindex) {
+ cuddSetInteract(table,i,xindex);
+ } else {
+ cuddSetInteract(table,xindex,i);
+ }
+ }
+ }
+
+} /* end of ddUpdateInteractionMatrix */
+
+
+/**Function********************************************************************
+
+ Synopsis [Initializes the linear transform matrix.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddInitLinear(
+ DdManager * table)
+{
+ int words;
+ int wordsPerRow;
+ int nvars;
+ int word;
+ int bit;
+ int i;
+ long *linear;
+
+ nvars = table->size;
+ wordsPerRow = ((nvars - 1) >> LOGBPL) + 1;
+ words = wordsPerRow * nvars;
+ table->linear = linear = ALLOC(long,words);
+ if (linear == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ table->memused += words * sizeof(long);
+ table->linearSize = nvars;
+ for (i = 0; i < words; i++) linear[i] = 0;
+ for (i = 0; i < nvars; i++) {
+ word = wordsPerRow * i + (i >> LOGBPL);
+ bit = i & (BPL-1);
+ linear[word] = 1 << bit;
+ }
+ return(1);
+
+} /* end of cuddInitLinear */
+
+
+/**Function********************************************************************
+
+ Synopsis [Resizes the linear transform matrix.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddResizeLinear(
+ DdManager * table)
+{
+ int words,oldWords;
+ int wordsPerRow,oldWordsPerRow;
+ int nvars,oldNvars;
+ int word,oldWord;
+ int bit;
+ int i,j;
+ long *linear,*oldLinear;
+
+ oldNvars = table->linearSize;
+ oldWordsPerRow = ((oldNvars - 1) >> LOGBPL) + 1;
+ oldWords = oldWordsPerRow * oldNvars;
+ oldLinear = table->linear;
+
+ nvars = table->size;
+ wordsPerRow = ((nvars - 1) >> LOGBPL) + 1;
+ words = wordsPerRow * nvars;
+ table->linear = linear = ALLOC(long,words);
+ if (linear == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ table->memused += (words - oldWords) * sizeof(long);
+ for (i = 0; i < words; i++) linear[i] = 0;
+
+ /* Copy old matrix. */
+ for (i = 0; i < oldNvars; i++) {
+ for (j = 0; j < oldWordsPerRow; j++) {
+ oldWord = oldWordsPerRow * i + j;
+ word = wordsPerRow * i + j;
+ linear[word] = oldLinear[oldWord];
+ }
+ }
+ FREE(oldLinear);
+
+ /* Add elements to the diagonal. */
+ for (i = oldNvars; i < nvars; i++) {
+ word = wordsPerRow * i + (i >> LOGBPL);
+ bit = i & (BPL-1);
+ linear[word] = 1 << bit;
+ }
+ table->linearSize = nvars;
+
+ return(1);
+
+} /* end of cuddResizeLinear */
+
+
+/**Function********************************************************************
+
+ Synopsis [XORs two rows of the linear transform matrix.]
+
+ Description [XORs two rows of the linear transform matrix and replaces
+ the first row with the result.]
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+cuddXorLinear(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int i;
+ int nvars = table->size;
+ int wordsPerRow = ((nvars - 1) >> LOGBPL) + 1;
+ int xstart = wordsPerRow * x;
+ int ystart = wordsPerRow * y;
+ long *linear = table->linear;
+
+ for (i = 0; i < wordsPerRow; i++) {
+ linear[xstart+i] ^= linear[ystart+i];
+ }
+
+} /* end of cuddXorLinear */
+
diff --git a/src/bdd/cudd/cuddLiteral.c b/src/bdd/cudd/cuddLiteral.c
new file mode 100644
index 00000000..69594486
--- /dev/null
+++ b/src/bdd/cudd/cuddLiteral.c
@@ -0,0 +1,237 @@
+/**CFile***********************************************************************
+
+ FileName [cuddLiteral.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for manipulation of literal sets represented by
+ BDDs.]
+
+ Description [External procedures included in this file:
+ <ul>
+ <li> Cudd_bddLiteralSetIntersection()
+ </ul>
+ Internal procedures included in this file:
+ <ul>
+ <li> cuddBddLiteralSetIntersectionRecur()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddLiteral.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the intesection of two sets of literals
+ represented as BDDs.]
+
+ Description [Computes the intesection of two sets of literals
+ represented as BDDs. Each set is represented as a cube of the
+ literals in the set. The empty set is represented by the constant 1.
+ No variable can be simultaneously present in both phases in a set.
+ Returns a pointer to the BDD representing the intersected sets, if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+Cudd_bddLiteralSetIntersection(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddLiteralSetIntersectionRecur(dd,f,g);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddLiteralSetIntersection */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of
+ Cudd_bddLiteralSetIntersection.]
+
+ Description [Performs the recursive step of
+ Cudd_bddLiteralSetIntersection. Scans the cubes for common variables,
+ and checks whether they agree in phase. Returns a pointer to the
+ resulting cube if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+cuddBddLiteralSetIntersectionRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res, *tmp;
+ DdNode *F, *G;
+ DdNode *fc, *gc;
+ DdNode *one;
+ DdNode *zero;
+ unsigned int topf, topg, comple;
+ int phasef, phaseg;
+
+ statLine(dd);
+ if (f == g) return(f);
+
+ F = Cudd_Regular(f);
+ G = Cudd_Regular(g);
+ one = DD_ONE(dd);
+
+ /* Here f != g. If F == G, then f and g are complementary.
+ ** Since they are two cubes, this case only occurs when f == v,
+ ** g == v', and v is a variable or its complement.
+ */
+ if (F == G) return(one);
+
+ zero = Cudd_Not(one);
+ topf = cuddI(dd,F->index);
+ topg = cuddI(dd,G->index);
+ /* Look for a variable common to both cubes. If there are none, this
+ ** loop will stop when the constant node is reached in both cubes.
+ */
+ while (topf != topg) {
+ if (topf < topg) { /* move down on f */
+ comple = f != F;
+ f = cuddT(F);
+ if (comple) f = Cudd_Not(f);
+ if (f == zero) {
+ f = cuddE(F);
+ if (comple) f = Cudd_Not(f);
+ }
+ F = Cudd_Regular(f);
+ topf = cuddI(dd,F->index);
+ } else if (topg < topf) {
+ comple = g != G;
+ g = cuddT(G);
+ if (comple) g = Cudd_Not(g);
+ if (g == zero) {
+ g = cuddE(G);
+ if (comple) g = Cudd_Not(g);
+ }
+ G = Cudd_Regular(g);
+ topg = cuddI(dd,G->index);
+ }
+ }
+
+ /* At this point, f == one <=> g == 1. It suffices to test one of them. */
+ if (f == one) return(one);
+
+ res = cuddCacheLookup2(dd,Cudd_bddLiteralSetIntersection,f,g);
+ if (res != NULL) {
+ return(res);
+ }
+
+ /* Here f and g are both non constant and have the same top variable. */
+ comple = f != F;
+ fc = cuddT(F);
+ phasef = 1;
+ if (comple) fc = Cudd_Not(fc);
+ if (fc == zero) {
+ fc = cuddE(F);
+ phasef = 0;
+ if (comple) fc = Cudd_Not(fc);
+ }
+ comple = g != G;
+ gc = cuddT(G);
+ phaseg = 1;
+ if (comple) gc = Cudd_Not(gc);
+ if (gc == zero) {
+ gc = cuddE(G);
+ phaseg = 0;
+ if (comple) gc = Cudd_Not(gc);
+ }
+
+ tmp = cuddBddLiteralSetIntersectionRecur(dd,fc,gc);
+ if (tmp == NULL) {
+ return(NULL);
+ }
+
+ if (phasef != phaseg) {
+ res = tmp;
+ } else {
+ cuddRef(tmp);
+ if (phasef == 0) {
+ res = cuddBddAndRecur(dd,Cudd_Not(dd->vars[F->index]),tmp);
+ } else {
+ res = cuddBddAndRecur(dd,dd->vars[F->index],tmp);
+ }
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,tmp);
+ return(NULL);
+ }
+ cuddDeref(tmp); /* Just cuddDeref, because it is included in result */
+ }
+
+ cuddCacheInsert2(dd,Cudd_bddLiteralSetIntersection,f,g,res);
+
+ return(res);
+
+} /* end of cuddBddLiteralSetIntersectionRecur */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/cudd/cuddMatMult.c b/src/bdd/cudd/cuddMatMult.c
new file mode 100644
index 00000000..b10975ec
--- /dev/null
+++ b/src/bdd/cudd/cuddMatMult.c
@@ -0,0 +1,680 @@
+/**CFile***********************************************************************
+
+ FileName [cuddMatMult.c]
+
+ PackageName [cudd]
+
+ Synopsis [Matrix multiplication functions.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_addMatrixMultiply()
+ <li> Cudd_addTimesPlus()
+ <li> Cudd_addTriangle()
+ <li> Cudd_addOuterSum()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> addMMRecur()
+ <li> addTriangleRecur()
+ <li> cuddAddOuterSumRecur()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddMatMult.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdNode * addMMRecur ARGS((DdManager *dd, DdNode *A, DdNode *B, int topP, int *vars));
+static DdNode * addTriangleRecur ARGS((DdManager *dd, DdNode *f, DdNode *g, int *vars, DdNode *cube));
+static DdNode * cuddAddOuterSumRecur ARGS((DdManager *dd, DdNode *M, DdNode *r, DdNode *c));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Calculates the product of two matrices represented as
+ ADDs.]
+
+ Description [Calculates the product of two matrices, A and B,
+ represented as ADDs. This procedure implements the quasiring multiplication
+ algorithm. A is assumed to depend on variables x (rows) and z
+ (columns). B is assumed to depend on variables z (rows) and y
+ (columns). The product of A and B then depends on x (rows) and y
+ (columns). Only the z variables have to be explicitly identified;
+ they are the "summation" variables. Returns a pointer to the
+ result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addTimesPlus Cudd_addTriangle Cudd_bddAndAbstract]
+
+******************************************************************************/
+DdNode *
+Cudd_addMatrixMultiply(
+ DdManager * dd,
+ DdNode * A,
+ DdNode * B,
+ DdNode ** z,
+ int nz)
+{
+ int i, nvars, *vars;
+ DdNode *res;
+
+ /* Array vars says what variables are "summation" variables. */
+ nvars = dd->size;
+ vars = ALLOC(int,nvars);
+ if (vars == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < nvars; i++) {
+ vars[i] = 0;
+ }
+ for (i = 0; i < nz; i++) {
+ vars[z[i]->index] = 1;
+ }
+
+ do {
+ dd->reordered = 0;
+ res = addMMRecur(dd,A,B,-1,vars);
+ } while (dd->reordered == 1);
+ FREE(vars);
+ return(res);
+
+} /* end of Cudd_addMatrixMultiply */
+
+
+/**Function********************************************************************
+
+ Synopsis [Calculates the product of two matrices represented as
+ ADDs.]
+
+ Description [Calculates the product of two matrices, A and B,
+ represented as ADDs, using the CMU matrix by matrix multiplication
+ procedure by Clarke et al.. Matrix A has x's as row variables and z's
+ as column variables, while matrix B has z's as row variables and y's
+ as column variables. Returns the pointer to the result if successful;
+ NULL otherwise. The resulting matrix has x's as row variables and y's
+ as column variables.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addMatrixMultiply]
+
+******************************************************************************/
+DdNode *
+Cudd_addTimesPlus(
+ DdManager * dd,
+ DdNode * A,
+ DdNode * B,
+ DdNode ** z,
+ int nz)
+{
+ DdNode *w, *cube, *tmp, *res;
+ int i;
+ tmp = Cudd_addApply(dd,Cudd_addTimes,A,B);
+ if (tmp == NULL) return(NULL);
+ Cudd_Ref(tmp);
+ Cudd_Ref(cube = DD_ONE(dd));
+ for (i = nz-1; i >= 0; i--) {
+ w = Cudd_addIte(dd,z[i],cube,DD_ZERO(dd));
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd,tmp);
+ return(NULL);
+ }
+ Cudd_Ref(w);
+ Cudd_RecursiveDeref(dd,cube);
+ cube = w;
+ }
+ res = Cudd_addExistAbstract(dd,tmp,cube);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,tmp);
+ Cudd_RecursiveDeref(dd,cube);
+ return(NULL);
+ }
+ Cudd_Ref(res);
+ Cudd_RecursiveDeref(dd,cube);
+ Cudd_RecursiveDeref(dd,tmp);
+ Cudd_Deref(res);
+ return(res);
+
+} /* end of Cudd_addTimesPlus */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the triangulation step for the shortest path
+ computation.]
+
+ Description [Implements the semiring multiplication algorithm used in
+ the triangulation step for the shortest path computation. f
+ is assumed to depend on variables x (rows) and z (columns). g is
+ assumed to depend on variables z (rows) and y (columns). The product
+ of f and g then depends on x (rows) and y (columns). Only the z
+ variables have to be explicitly identified; they are the
+ "abstraction" variables. Returns a pointer to the result if
+ successful; NULL otherwise. ]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addMatrixMultiply Cudd_bddAndAbstract]
+
+******************************************************************************/
+DdNode *
+Cudd_addTriangle(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ DdNode ** z,
+ int nz)
+{
+ int i, nvars, *vars;
+ DdNode *res, *cube;
+
+ nvars = dd->size;
+ vars = ALLOC(int, nvars);
+ if (vars == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < nvars; i++) vars[i] = -1;
+ for (i = 0; i < nz; i++) vars[z[i]->index] = i;
+ cube = Cudd_addComputeCube(dd, z, NULL, nz);
+ if (cube == NULL) {
+ FREE(vars);
+ return(NULL);
+ }
+ cuddRef(cube);
+
+ do {
+ dd->reordered = 0;
+ res = addTriangleRecur(dd, f, g, vars, cube);
+ } while (dd->reordered == 1);
+ if (res != NULL) cuddRef(res);
+ Cudd_RecursiveDeref(dd,cube);
+ if (res != NULL) cuddDeref(res);
+ FREE(vars);
+ return(res);
+
+} /* end of Cudd_addTriangle */
+
+
+/**Function********************************************************************
+
+ Synopsis [Takes the minimum of a matrix and the outer sum of two vectors.]
+
+ Description [Takes the pointwise minimum of a matrix and the outer
+ sum of two vectors. This procedure is used in the Floyd-Warshall
+ all-pair shortest path algorithm. Returns a pointer to the result if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_addOuterSum(
+ DdManager *dd,
+ DdNode *M,
+ DdNode *r,
+ DdNode *c)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddAddOuterSumRecur(dd, M, r, c);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addOuterSum */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addMatrixMultiply.]
+
+ Description [Performs the recursive step of Cudd_addMatrixMultiply.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static DdNode *
+addMMRecur(
+ DdManager * dd,
+ DdNode * A,
+ DdNode * B,
+ int topP,
+ int * vars)
+{
+ DdNode *zero,
+ *At, /* positive cofactor of first operand */
+ *Ae, /* negative cofactor of first operand */
+ *Bt, /* positive cofactor of second operand */
+ *Be, /* negative cofactor of second operand */
+ *t, /* positive cofactor of result */
+ *e, /* negative cofactor of result */
+ *scaled, /* scaled result */
+ *add_scale, /* ADD representing the scaling factor */
+ *res;
+ int i; /* loop index */
+ double scale; /* scaling factor */
+ int index; /* index of the top variable */
+ CUDD_VALUE_TYPE value;
+ unsigned int topA, topB, topV;
+ DdNode *(*cacheOp)(DdManager *, DdNode *, DdNode *);
+
+ statLine(dd);
+ zero = DD_ZERO(dd);
+
+ if (A == zero || B == zero) {
+ return(zero);
+ }
+
+ if (cuddIsConstant(A) && cuddIsConstant(B)) {
+ /* Compute the scaling factor. It is 2^k, where k is the
+ ** number of summation variables below the current variable.
+ ** Indeed, these constants represent blocks of 2^k identical
+ ** constant values in both A and B.
+ */
+ value = cuddV(A) * cuddV(B);
+ for (i = 0; i < dd->size; i++) {
+ if (vars[i]) {
+ if (dd->perm[i] > topP) {
+ value *= (CUDD_VALUE_TYPE) 2;
+ }
+ }
+ }
+ res = cuddUniqueConst(dd, value);
+ return(res);
+ }
+
+ /* Standardize to increase cache efficiency. Clearly, A*B != B*A
+ ** in matrix multiplication. However, which matrix is which is
+ ** determined by the variables appearing in the ADDs and not by
+ ** which one is passed as first argument.
+ */
+ if (A > B) {
+ DdNode *tmp = A;
+ A = B;
+ B = tmp;
+ }
+
+ topA = cuddI(dd,A->index); topB = cuddI(dd,B->index);
+ topV = ddMin(topA,topB);
+
+ cacheOp = (DdNode *(*)(DdManager *, DdNode *, DdNode *)) addMMRecur;
+ res = cuddCacheLookup2(dd,cacheOp,A,B);
+ if (res != NULL) {
+ /* If the result is 0, there is no need to normalize.
+ ** Otherwise we count the number of z variables between
+ ** the current depth and the top of the ADDs. These are
+ ** the missing variables that determine the size of the
+ ** constant blocks.
+ */
+ if (res == zero) return(res);
+ scale = 1.0;
+ for (i = 0; i < dd->size; i++) {
+ if (vars[i]) {
+ if (dd->perm[i] > topP && (unsigned) dd->perm[i] < topV) {
+ scale *= 2;
+ }
+ }
+ }
+ if (scale > 1.0) {
+ cuddRef(res);
+ add_scale = cuddUniqueConst(dd,(CUDD_VALUE_TYPE)scale);
+ if (add_scale == NULL) {
+ Cudd_RecursiveDeref(dd, res);
+ return(NULL);
+ }
+ cuddRef(add_scale);
+ scaled = cuddAddApplyRecur(dd,Cudd_addTimes,res,add_scale);
+ if (scaled == NULL) {
+ Cudd_RecursiveDeref(dd, add_scale);
+ Cudd_RecursiveDeref(dd, res);
+ return(NULL);
+ }
+ cuddRef(scaled);
+ Cudd_RecursiveDeref(dd, add_scale);
+ Cudd_RecursiveDeref(dd, res);
+ res = scaled;
+ cuddDeref(res);
+ }
+ return(res);
+ }
+
+ /* compute the cofactors */
+ if (topV == topA) {
+ At = cuddT(A);
+ Ae = cuddE(A);
+ } else {
+ At = Ae = A;
+ }
+ if (topV == topB) {
+ Bt = cuddT(B);
+ Be = cuddE(B);
+ } else {
+ Bt = Be = B;
+ }
+
+ t = addMMRecur(dd, At, Bt, (int)topV, vars);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = addMMRecur(dd, Ae, Be, (int)topV, vars);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ index = dd->invperm[topV];
+ if (vars[index] == 0) {
+ /* We have split on either the rows of A or the columns
+ ** of B. We just need to connect the two subresults,
+ ** which correspond to two submatrices of the result.
+ */
+ res = (t == e) ? t : cuddUniqueInter(dd,index,t,e);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ Cudd_RecursiveDeref(dd, e);
+ return(NULL);
+ }
+ cuddRef(res);
+ cuddDeref(t);
+ cuddDeref(e);
+ } else {
+ /* we have simultaneously split on the columns of A and
+ ** the rows of B. The two subresults must be added.
+ */
+ res = cuddAddApplyRecur(dd,Cudd_addPlus,t,e);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ Cudd_RecursiveDeref(dd, e);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, t);
+ Cudd_RecursiveDeref(dd, e);
+ }
+
+ cuddCacheInsert2(dd,cacheOp,A,B,res);
+
+ /* We have computed (and stored in the computed table) a minimal
+ ** result; that is, a result that assumes no summation variables
+ ** between the current depth of the recursion and its top
+ ** variable. We now take into account the z variables by properly
+ ** scaling the result.
+ */
+ if (res != zero) {
+ scale = 1.0;
+ for (i = 0; i < dd->size; i++) {
+ if (vars[i]) {
+ if (dd->perm[i] > topP && (unsigned) dd->perm[i] < topV) {
+ scale *= 2;
+ }
+ }
+ }
+ if (scale > 1.0) {
+ add_scale = cuddUniqueConst(dd,(CUDD_VALUE_TYPE)scale);
+ if (add_scale == NULL) {
+ Cudd_RecursiveDeref(dd, res);
+ return(NULL);
+ }
+ cuddRef(add_scale);
+ scaled = cuddAddApplyRecur(dd,Cudd_addTimes,res,add_scale);
+ if (scaled == NULL) {
+ Cudd_RecursiveDeref(dd, res);
+ Cudd_RecursiveDeref(dd, add_scale);
+ return(NULL);
+ }
+ cuddRef(scaled);
+ Cudd_RecursiveDeref(dd, add_scale);
+ Cudd_RecursiveDeref(dd, res);
+ res = scaled;
+ }
+ }
+ cuddDeref(res);
+ return(res);
+
+} /* end of addMMRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addTriangle.]
+
+ Description [Performs the recursive step of Cudd_addTriangle. Returns
+ a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static DdNode *
+addTriangleRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ int * vars,
+ DdNode *cube)
+{
+ DdNode *fv, *fvn, *gv, *gvn, *t, *e, *res;
+ CUDD_VALUE_TYPE value;
+ int top, topf, topg, index;
+
+ statLine(dd);
+ if (f == DD_PLUS_INFINITY(dd) || g == DD_PLUS_INFINITY(dd)) {
+ return(DD_PLUS_INFINITY(dd));
+ }
+
+ if (cuddIsConstant(f) && cuddIsConstant(g)) {
+ value = cuddV(f) + cuddV(g);
+ res = cuddUniqueConst(dd, value);
+ return(res);
+ }
+ if (f < g) {
+ DdNode *tmp = f;
+ f = g;
+ g = tmp;
+ }
+
+ if (f->ref != 1 || g->ref != 1) {
+ res = cuddCacheLookup(dd, DD_ADD_TRIANGLE_TAG, f, g, cube);
+ if (res != NULL) {
+ return(res);
+ }
+ }
+
+ topf = cuddI(dd,f->index); topg = cuddI(dd,g->index);
+ top = ddMin(topf,topg);
+
+ if (top == topf) {fv = cuddT(f); fvn = cuddE(f);} else {fv = fvn = f;}
+ if (top == topg) {gv = cuddT(g); gvn = cuddE(g);} else {gv = gvn = g;}
+
+ t = addTriangleRecur(dd, fv, gv, vars, cube);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = addTriangleRecur(dd, fvn, gvn, vars, cube);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ index = dd->invperm[top];
+ if (vars[index] < 0) {
+ res = (t == e) ? t : cuddUniqueInter(dd,index,t,e);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ Cudd_RecursiveDeref(dd, e);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+ } else {
+ res = cuddAddApplyRecur(dd,Cudd_addMinimum,t,e);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ Cudd_RecursiveDeref(dd, e);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, t);
+ Cudd_RecursiveDeref(dd, e);
+ cuddDeref(res);
+ }
+
+ if (f->ref != 1 || g->ref != 1) {
+ cuddCacheInsert(dd, DD_ADD_TRIANGLE_TAG, f, g, cube, res);
+ }
+
+ return(res);
+
+} /* end of addTriangleRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addOuterSum.]
+
+ Description [Performs the recursive step of Cudd_addOuterSum.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+cuddAddOuterSumRecur(
+ DdManager *dd,
+ DdNode *M,
+ DdNode *r,
+ DdNode *c)
+{
+ DdNode *P, *R, *Mt, *Me, *rt, *re, *ct, *ce, *Rt, *Re;
+ int topM, topc, topr;
+ int v, index;
+
+ statLine(dd);
+ /* Check special cases. */
+ if (r == DD_PLUS_INFINITY(dd) || c == DD_PLUS_INFINITY(dd)) return(M);
+
+ if (cuddIsConstant(c) && cuddIsConstant(r)) {
+ R = cuddUniqueConst(dd,Cudd_V(c)+Cudd_V(r));
+ cuddRef(R);
+ if (cuddIsConstant(M)) {
+ if (cuddV(R) <= cuddV(M)) {
+ cuddDeref(R);
+ return(R);
+ } else {
+ Cudd_RecursiveDeref(dd,R);
+ return(M);
+ }
+ } else {
+ P = Cudd_addApply(dd,Cudd_addMinimum,R,M);
+ cuddRef(P);
+ Cudd_RecursiveDeref(dd,R);
+ cuddDeref(P);
+ return(P);
+ }
+ }
+
+ /* Check the cache. */
+ R = cuddCacheLookup(dd,DD_ADD_OUT_SUM_TAG,M,r,c);
+ if (R != NULL) return(R);
+
+ topM = cuddI(dd,M->index); topr = cuddI(dd,r->index);
+ topc = cuddI(dd,c->index);
+ v = ddMin(topM,ddMin(topr,topc));
+
+ /* Compute cofactors. */
+ if (topM == v) { Mt = cuddT(M); Me = cuddE(M); } else { Mt = Me = M; }
+ if (topr == v) { rt = cuddT(r); re = cuddE(r); } else { rt = re = r; }
+ if (topc == v) { ct = cuddT(c); ce = cuddE(c); } else { ct = ce = c; }
+
+ /* Recursively solve. */
+ Rt = cuddAddOuterSumRecur(dd,Mt,rt,ct);
+ if (Rt == NULL) return(NULL);
+ cuddRef(Rt);
+ Re = cuddAddOuterSumRecur(dd,Me,re,ce);
+ if (Re == NULL) {
+ Cudd_RecursiveDeref(dd, Rt);
+ return(NULL);
+ }
+ cuddRef(Re);
+ index = dd->invperm[v];
+ R = (Rt == Re) ? Rt : cuddUniqueInter(dd,index,Rt,Re);
+ if (R == NULL) {
+ Cudd_RecursiveDeref(dd, Rt);
+ Cudd_RecursiveDeref(dd, Re);
+ return(NULL);
+ }
+ cuddDeref(Rt);
+ cuddDeref(Re);
+
+ /* Store the result in the cache. */
+ cuddCacheInsert(dd,DD_ADD_OUT_SUM_TAG,M,r,c,R);
+
+ return(R);
+
+} /* end of cuddAddOuterSumRecur */
diff --git a/src/bdd/cudd/cuddPriority.c b/src/bdd/cudd/cuddPriority.c
new file mode 100644
index 00000000..bb0b83d3
--- /dev/null
+++ b/src/bdd/cudd/cuddPriority.c
@@ -0,0 +1,1475 @@
+/**CFile***********************************************************************
+
+ FileName [cuddPriority.c]
+
+ PackageName [cudd]
+
+ Synopsis [Priority functions.]
+
+ Description [External procedures included in this file:
+ <ul>
+ <li> Cudd_PrioritySelect()
+ <li> Cudd_Xgty()
+ <li> Cudd_Xeqy()
+ <li> Cudd_addXeqy()
+ <li> Cudd_Dxygtdxz()
+ <li> Cudd_Dxygtdyz()
+ <li> Cudd_CProjection()
+ <li> Cudd_addHamming()
+ <li> Cudd_MinHammingDist()
+ <li> Cudd_bddClosestCube()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddCProjectionRecur()
+ <li> cuddBddClosestCube()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddMinHammingDistRecur()
+ <li> separateCube()
+ <li> createResult()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddPriority.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+static int cuddMinHammingDistRecur ARGS((DdNode * f, int *minterm, DdHashTable * table, int upperBound));
+static DdNode * separateCube ARGS((DdManager *dd, DdNode *f, CUDD_VALUE_TYPE *distance));
+static DdNode * createResult ARGS((DdManager *dd, unsigned int index, unsigned int phase, DdNode *cube, CUDD_VALUE_TYPE distance));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Selects pairs from R using a priority function.]
+
+ Description [Selects pairs from a relation R(x,y) (given as a BDD)
+ in such a way that a given x appears in one pair only. Uses a
+ priority function to determine which y should be paired to a given x.
+ Cudd_PrioritySelect returns a pointer to
+ the selected function if successful; NULL otherwise.
+ Three of the arguments--x, y, and z--are vectors of BDD variables.
+ The first two are the variables on which R depends. The third vectore
+ is a vector of auxiliary variables, used during the computation. This
+ vector is optional. If a NULL value is passed instead,
+ Cudd_PrioritySelect will create the working variables on the fly.
+ The sizes of x and y (and z if it is not NULL) should equal n.
+ The priority function Pi can be passed as a BDD, or can be built by
+ Cudd_PrioritySelect. If NULL is passed instead of a DdNode *,
+ parameter Pifunc is used by Cudd_PrioritySelect to build a BDD for the
+ priority function. (Pifunc is a pointer to a C function.) If Pi is not
+ NULL, then Pifunc is ignored. Pifunc should have the same interface as
+ the standard priority functions (e.g., Cudd_Dxygtdxz).
+ Cudd_PrioritySelect and Cudd_CProjection can sometimes be used
+ interchangeably. Specifically, calling Cudd_PrioritySelect with
+ Cudd_Xgty as Pifunc produces the same result as calling
+ Cudd_CProjection with the all-zero minterm as reference minterm.
+ However, depending on the application, one or the other may be
+ preferable:
+ <ul>
+ <li> When extracting representatives from an equivalence relation,
+ Cudd_CProjection has the advantage of nor requiring the auxiliary
+ variables.
+ <li> When computing matchings in general bipartite graphs,
+ Cudd_PrioritySelect normally obtains better results because it can use
+ more powerful matching schemes (e.g., Cudd_Dxygtdxz).
+ </ul>
+ ]
+
+ SideEffects [If called with z == NULL, will create new variables in
+ the manager.]
+
+ SeeAlso [Cudd_Dxygtdxz Cudd_Dxygtdyz Cudd_Xgty
+ Cudd_bddAdjPermuteX Cudd_CProjection]
+
+******************************************************************************/
+DdNode *
+Cudd_PrioritySelect(
+ DdManager * dd /* manager */,
+ DdNode * R /* BDD of the relation */,
+ DdNode ** x /* array of x variables */,
+ DdNode ** y /* array of y variables */,
+ DdNode ** z /* array of z variables (optional: may be NULL) */,
+ DdNode * Pi /* BDD of the priority function (optional: may be NULL) */,
+ int n /* size of x, y, and z */,
+ DdNode * (*Pifunc)(DdManager *, int, DdNode **, DdNode **, DdNode **) /* function used to build Pi if it is NULL */)
+{
+ DdNode *res = NULL;
+ DdNode *zcube = NULL;
+ DdNode *Rxz, *Q;
+ int createdZ = 0;
+ int createdPi = 0;
+ int i;
+
+ /* Create z variables if needed. */
+ if (z == NULL) {
+ if (Pi != NULL) return(NULL);
+ z = ALLOC(DdNode *,n);
+ if (z == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ createdZ = 1;
+ for (i = 0; i < n; i++) {
+ if (dd->size >= (int) CUDD_MAXINDEX - 1) goto endgame;
+ z[i] = cuddUniqueInter(dd,dd->size,dd->one,Cudd_Not(dd->one));
+ if (z[i] == NULL) goto endgame;
+ }
+ }
+
+ /* Create priority function BDD if needed. */
+ if (Pi == NULL) {
+ Pi = Pifunc(dd,n,x,y,z);
+ if (Pi == NULL) goto endgame;
+ createdPi = 1;
+ cuddRef(Pi);
+ }
+
+ /* Initialize abstraction cube. */
+ zcube = DD_ONE(dd);
+ cuddRef(zcube);
+ for (i = n - 1; i >= 0; i--) {
+ DdNode *tmpp;
+ tmpp = Cudd_bddAnd(dd,z[i],zcube);
+ if (tmpp == NULL) goto endgame;
+ cuddRef(tmpp);
+ Cudd_RecursiveDeref(dd,zcube);
+ zcube = tmpp;
+ }
+
+ /* Compute subset of (x,y) pairs. */
+ Rxz = Cudd_bddSwapVariables(dd,R,y,z,n);
+ if (Rxz == NULL) goto endgame;
+ cuddRef(Rxz);
+ Q = Cudd_bddAndAbstract(dd,Rxz,Pi,zcube);
+ if (Q == NULL) {
+ Cudd_RecursiveDeref(dd,Rxz);
+ goto endgame;
+ }
+ cuddRef(Q);
+ Cudd_RecursiveDeref(dd,Rxz);
+ res = Cudd_bddAnd(dd,R,Cudd_Not(Q));
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,Q);
+ goto endgame;
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd,Q);
+
+endgame:
+ if (zcube != NULL) Cudd_RecursiveDeref(dd,zcube);
+ if (createdZ) {
+ FREE(z);
+ }
+ if (createdPi) {
+ Cudd_RecursiveDeref(dd,Pi);
+ }
+ if (res != NULL) cuddDeref(res);
+ return(res);
+
+} /* Cudd_PrioritySelect */
+
+
+/**Function********************************************************************
+
+ Synopsis [Generates a BDD for the function x &gt; y.]
+
+ Description [This function generates a BDD for the function x &gt; y.
+ Both x and y are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\] and
+ y\[0\] y\[1\] ... y\[N-1\], with 0 the most significant bit.
+ The BDD is built bottom-up.
+ It has 3*N-1 internal nodes, if the variables are ordered as follows:
+ x\[0\] y\[0\] x\[1\] y\[1\] ... x\[N-1\] y\[N-1\].
+ Argument z is not used by Cudd_Xgty: it is included to make it
+ call-compatible to Cudd_Dxygtdxz and Cudd_Dxygtdyz.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_PrioritySelect Cudd_Dxygtdxz Cudd_Dxygtdyz]
+
+******************************************************************************/
+DdNode *
+Cudd_Xgty(
+ DdManager * dd /* DD manager */,
+ int N /* number of x and y variables */,
+ DdNode ** z /* array of z variables: unused */,
+ DdNode ** x /* array of x variables */,
+ DdNode ** y /* array of y variables */)
+{
+ DdNode *u, *v, *w;
+ int i;
+
+ /* Build bottom part of BDD outside loop. */
+ u = Cudd_bddAnd(dd, x[N-1], Cudd_Not(y[N-1]));
+ if (u == NULL) return(NULL);
+ cuddRef(u);
+
+ /* Loop to build the rest of the BDD. */
+ for (i = N-2; i >= 0; i--) {
+ v = Cudd_bddAnd(dd, y[i], Cudd_Not(u));
+ if (v == NULL) {
+ Cudd_RecursiveDeref(dd, u);
+ return(NULL);
+ }
+ cuddRef(v);
+ w = Cudd_bddAnd(dd, Cudd_Not(y[i]), u);
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, u);
+ Cudd_RecursiveDeref(dd, v);
+ return(NULL);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, u);
+ u = Cudd_bddIte(dd, x[i], Cudd_Not(v), w);
+ if (u == NULL) {
+ Cudd_RecursiveDeref(dd, v);
+ Cudd_RecursiveDeref(dd, w);
+ return(NULL);
+ }
+ cuddRef(u);
+ Cudd_RecursiveDeref(dd, v);
+ Cudd_RecursiveDeref(dd, w);
+
+ }
+ cuddDeref(u);
+ return(u);
+
+} /* end of Cudd_Xgty */
+
+
+/**Function********************************************************************
+
+ Synopsis [Generates a BDD for the function x==y.]
+
+ Description [This function generates a BDD for the function x==y.
+ Both x and y are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\] and
+ y\[0\] y\[1\] ... y\[N-1\], with 0 the most significant bit.
+ The BDD is built bottom-up.
+ It has 3*N-1 internal nodes, if the variables are ordered as follows:
+ x\[0\] y\[0\] x\[1\] y\[1\] ... x\[N-1\] y\[N-1\]. ]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addXeqy]
+
+******************************************************************************/
+DdNode *
+Cudd_Xeqy(
+ DdManager * dd /* DD manager */,
+ int N /* number of x and y variables */,
+ DdNode ** x /* array of x variables */,
+ DdNode ** y /* array of y variables */)
+{
+ DdNode *u, *v, *w;
+ int i;
+
+ /* Build bottom part of BDD outside loop. */
+ u = Cudd_bddIte(dd, x[N-1], y[N-1], Cudd_Not(y[N-1]));
+ if (u == NULL) return(NULL);
+ cuddRef(u);
+
+ /* Loop to build the rest of the BDD. */
+ for (i = N-2; i >= 0; i--) {
+ v = Cudd_bddAnd(dd, y[i], u);
+ if (v == NULL) {
+ Cudd_RecursiveDeref(dd, u);
+ return(NULL);
+ }
+ cuddRef(v);
+ w = Cudd_bddAnd(dd, Cudd_Not(y[i]), u);
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, u);
+ Cudd_RecursiveDeref(dd, v);
+ return(NULL);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, u);
+ u = Cudd_bddIte(dd, x[i], v, w);
+ if (u == NULL) {
+ Cudd_RecursiveDeref(dd, v);
+ Cudd_RecursiveDeref(dd, w);
+ return(NULL);
+ }
+ cuddRef(u);
+ Cudd_RecursiveDeref(dd, v);
+ Cudd_RecursiveDeref(dd, w);
+ }
+ cuddDeref(u);
+ return(u);
+
+} /* end of Cudd_Xeqy */
+
+
+/**Function********************************************************************
+
+ Synopsis [Generates an ADD for the function x==y.]
+
+ Description [This function generates an ADD for the function x==y.
+ Both x and y are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\] and
+ y\[0\] y\[1\] ... y\[N-1\], with 0 the most significant bit.
+ The ADD is built bottom-up.
+ It has 3*N-1 internal nodes, if the variables are ordered as follows:
+ x\[0\] y\[0\] x\[1\] y\[1\] ... x\[N-1\] y\[N-1\]. ]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Xeqy]
+
+******************************************************************************/
+DdNode *
+Cudd_addXeqy(
+ DdManager * dd /* DD manager */,
+ int N /* number of x and y variables */,
+ DdNode ** x /* array of x variables */,
+ DdNode ** y /* array of y variables */)
+{
+ DdNode *one, *zero;
+ DdNode *u, *v, *w;
+ int i;
+
+ one = DD_ONE(dd);
+ zero = DD_ZERO(dd);
+
+ /* Build bottom part of ADD outside loop. */
+ v = Cudd_addIte(dd, y[N-1], one, zero);
+ if (v == NULL) return(NULL);
+ cuddRef(v);
+ w = Cudd_addIte(dd, y[N-1], zero, one);
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, v);
+ return(NULL);
+ }
+ cuddRef(w);
+ u = Cudd_addIte(dd, x[N-1], v, w);
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, v);
+ Cudd_RecursiveDeref(dd, w);
+ return(NULL);
+ }
+ cuddRef(u);
+ Cudd_RecursiveDeref(dd, v);
+ Cudd_RecursiveDeref(dd, w);
+
+ /* Loop to build the rest of the ADD. */
+ for (i = N-2; i >= 0; i--) {
+ v = Cudd_addIte(dd, y[i], u, zero);
+ if (v == NULL) {
+ Cudd_RecursiveDeref(dd, u);
+ return(NULL);
+ }
+ cuddRef(v);
+ w = Cudd_addIte(dd, y[i], zero, u);
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, u);
+ Cudd_RecursiveDeref(dd, v);
+ return(NULL);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, u);
+ u = Cudd_addIte(dd, x[i], v, w);
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, v);
+ Cudd_RecursiveDeref(dd, w);
+ return(NULL);
+ }
+ cuddRef(u);
+ Cudd_RecursiveDeref(dd, v);
+ Cudd_RecursiveDeref(dd, w);
+ }
+ cuddDeref(u);
+ return(u);
+
+} /* end of Cudd_addXeqy */
+
+
+/**Function********************************************************************
+
+ Synopsis [Generates a BDD for the function d(x,y) &gt; d(x,z).]
+
+ Description [This function generates a BDD for the function d(x,y)
+ &gt; d(x,z);
+ x, y, and z are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\],
+ y\[0\] y\[1\] ... y\[N-1\], and z\[0\] z\[1\] ... z\[N-1\],
+ with 0 the most significant bit.
+ The distance d(x,y) is defined as:
+ \sum_{i=0}^{N-1}(|x_i - y_i| \cdot 2^{N-i-1}).
+ The BDD is built bottom-up.
+ It has 7*N-3 internal nodes, if the variables are ordered as follows:
+ x\[0\] y\[0\] z\[0\] x\[1\] y\[1\] z\[1\] ... x\[N-1\] y\[N-1\] z\[N-1\]. ]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_PrioritySelect Cudd_Dxygtdyz Cudd_Xgty Cudd_bddAdjPermuteX]
+
+******************************************************************************/
+DdNode *
+Cudd_Dxygtdxz(
+ DdManager * dd /* DD manager */,
+ int N /* number of x, y, and z variables */,
+ DdNode ** x /* array of x variables */,
+ DdNode ** y /* array of y variables */,
+ DdNode ** z /* array of z variables */)
+{
+ DdNode *one, *zero;
+ DdNode *z1, *z2, *z3, *z4, *y1_, *y2, *x1;
+ int i;
+
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ /* Build bottom part of BDD outside loop. */
+ y1_ = Cudd_bddIte(dd, y[N-1], one, Cudd_Not(z[N-1]));
+ if (y1_ == NULL) return(NULL);
+ cuddRef(y1_);
+ y2 = Cudd_bddIte(dd, y[N-1], z[N-1], one);
+ if (y2 == NULL) {
+ Cudd_RecursiveDeref(dd, y1_);
+ return(NULL);
+ }
+ cuddRef(y2);
+ x1 = Cudd_bddIte(dd, x[N-1], y1_, y2);
+ if (x1 == NULL) {
+ Cudd_RecursiveDeref(dd, y1_);
+ Cudd_RecursiveDeref(dd, y2);
+ return(NULL);
+ }
+ cuddRef(x1);
+ Cudd_RecursiveDeref(dd, y1_);
+ Cudd_RecursiveDeref(dd, y2);
+
+ /* Loop to build the rest of the BDD. */
+ for (i = N-2; i >= 0; i--) {
+ z1 = Cudd_bddIte(dd, z[i], one, Cudd_Not(x1));
+ if (z1 == NULL) {
+ Cudd_RecursiveDeref(dd, x1);
+ return(NULL);
+ }
+ cuddRef(z1);
+ z2 = Cudd_bddIte(dd, z[i], x1, one);
+ if (z2 == NULL) {
+ Cudd_RecursiveDeref(dd, x1);
+ Cudd_RecursiveDeref(dd, z1);
+ return(NULL);
+ }
+ cuddRef(z2);
+ z3 = Cudd_bddIte(dd, z[i], one, x1);
+ if (z3 == NULL) {
+ Cudd_RecursiveDeref(dd, x1);
+ Cudd_RecursiveDeref(dd, z1);
+ Cudd_RecursiveDeref(dd, z2);
+ return(NULL);
+ }
+ cuddRef(z3);
+ z4 = Cudd_bddIte(dd, z[i], x1, zero);
+ if (z4 == NULL) {
+ Cudd_RecursiveDeref(dd, x1);
+ Cudd_RecursiveDeref(dd, z1);
+ Cudd_RecursiveDeref(dd, z2);
+ Cudd_RecursiveDeref(dd, z3);
+ return(NULL);
+ }
+ cuddRef(z4);
+ Cudd_RecursiveDeref(dd, x1);
+ y1_ = Cudd_bddIte(dd, y[i], z2, Cudd_Not(z1));
+ if (y1_ == NULL) {
+ Cudd_RecursiveDeref(dd, z1);
+ Cudd_RecursiveDeref(dd, z2);
+ Cudd_RecursiveDeref(dd, z3);
+ Cudd_RecursiveDeref(dd, z4);
+ return(NULL);
+ }
+ cuddRef(y1_);
+ y2 = Cudd_bddIte(dd, y[i], z4, z3);
+ if (y2 == NULL) {
+ Cudd_RecursiveDeref(dd, z1);
+ Cudd_RecursiveDeref(dd, z2);
+ Cudd_RecursiveDeref(dd, z3);
+ Cudd_RecursiveDeref(dd, z4);
+ Cudd_RecursiveDeref(dd, y1_);
+ return(NULL);
+ }
+ cuddRef(y2);
+ Cudd_RecursiveDeref(dd, z1);
+ Cudd_RecursiveDeref(dd, z2);
+ Cudd_RecursiveDeref(dd, z3);
+ Cudd_RecursiveDeref(dd, z4);
+ x1 = Cudd_bddIte(dd, x[i], y1_, y2);
+ if (x1 == NULL) {
+ Cudd_RecursiveDeref(dd, y1_);
+ Cudd_RecursiveDeref(dd, y2);
+ return(NULL);
+ }
+ cuddRef(x1);
+ Cudd_RecursiveDeref(dd, y1_);
+ Cudd_RecursiveDeref(dd, y2);
+ }
+ cuddDeref(x1);
+ return(Cudd_Not(x1));
+
+} /* end of Cudd_Dxygtdxz */
+
+
+/**Function********************************************************************
+
+ Synopsis [Generates a BDD for the function d(x,y) &gt; d(y,z).]
+
+ Description [This function generates a BDD for the function d(x,y)
+ &gt; d(y,z);
+ x, y, and z are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\],
+ y\[0\] y\[1\] ... y\[N-1\], and z\[0\] z\[1\] ... z\[N-1\],
+ with 0 the most significant bit.
+ The distance d(x,y) is defined as:
+ \sum_{i=0}^{N-1}(|x_i - y_i| \cdot 2^{N-i-1}).
+ The BDD is built bottom-up.
+ It has 7*N-3 internal nodes, if the variables are ordered as follows:
+ x\[0\] y\[0\] z\[0\] x\[1\] y\[1\] z\[1\] ... x\[N-1\] y\[N-1\] z\[N-1\]. ]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_PrioritySelect Cudd_Dxygtdxz Cudd_Xgty Cudd_bddAdjPermuteX]
+
+******************************************************************************/
+DdNode *
+Cudd_Dxygtdyz(
+ DdManager * dd /* DD manager */,
+ int N /* number of x, y, and z variables */,
+ DdNode ** x /* array of x variables */,
+ DdNode ** y /* array of y variables */,
+ DdNode ** z /* array of z variables */)
+{
+ DdNode *one, *zero;
+ DdNode *z1, *z2, *z3, *z4, *y1_, *y2, *x1;
+ int i;
+
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ /* Build bottom part of BDD outside loop. */
+ y1_ = Cudd_bddIte(dd, y[N-1], one, z[N-1]);
+ if (y1_ == NULL) return(NULL);
+ cuddRef(y1_);
+ y2 = Cudd_bddIte(dd, y[N-1], z[N-1], zero);
+ if (y2 == NULL) {
+ Cudd_RecursiveDeref(dd, y1_);
+ return(NULL);
+ }
+ cuddRef(y2);
+ x1 = Cudd_bddIte(dd, x[N-1], y1_, Cudd_Not(y2));
+ if (x1 == NULL) {
+ Cudd_RecursiveDeref(dd, y1_);
+ Cudd_RecursiveDeref(dd, y2);
+ return(NULL);
+ }
+ cuddRef(x1);
+ Cudd_RecursiveDeref(dd, y1_);
+ Cudd_RecursiveDeref(dd, y2);
+
+ /* Loop to build the rest of the BDD. */
+ for (i = N-2; i >= 0; i--) {
+ z1 = Cudd_bddIte(dd, z[i], x1, zero);
+ if (z1 == NULL) {
+ Cudd_RecursiveDeref(dd, x1);
+ return(NULL);
+ }
+ cuddRef(z1);
+ z2 = Cudd_bddIte(dd, z[i], x1, one);
+ if (z2 == NULL) {
+ Cudd_RecursiveDeref(dd, x1);
+ Cudd_RecursiveDeref(dd, z1);
+ return(NULL);
+ }
+ cuddRef(z2);
+ z3 = Cudd_bddIte(dd, z[i], one, x1);
+ if (z3 == NULL) {
+ Cudd_RecursiveDeref(dd, x1);
+ Cudd_RecursiveDeref(dd, z1);
+ Cudd_RecursiveDeref(dd, z2);
+ return(NULL);
+ }
+ cuddRef(z3);
+ z4 = Cudd_bddIte(dd, z[i], one, Cudd_Not(x1));
+ if (z4 == NULL) {
+ Cudd_RecursiveDeref(dd, x1);
+ Cudd_RecursiveDeref(dd, z1);
+ Cudd_RecursiveDeref(dd, z2);
+ Cudd_RecursiveDeref(dd, z3);
+ return(NULL);
+ }
+ cuddRef(z4);
+ Cudd_RecursiveDeref(dd, x1);
+ y1_ = Cudd_bddIte(dd, y[i], z2, z1);
+ if (y1_ == NULL) {
+ Cudd_RecursiveDeref(dd, z1);
+ Cudd_RecursiveDeref(dd, z2);
+ Cudd_RecursiveDeref(dd, z3);
+ Cudd_RecursiveDeref(dd, z4);
+ return(NULL);
+ }
+ cuddRef(y1_);
+ y2 = Cudd_bddIte(dd, y[i], z4, Cudd_Not(z3));
+ if (y2 == NULL) {
+ Cudd_RecursiveDeref(dd, z1);
+ Cudd_RecursiveDeref(dd, z2);
+ Cudd_RecursiveDeref(dd, z3);
+ Cudd_RecursiveDeref(dd, z4);
+ Cudd_RecursiveDeref(dd, y1_);
+ return(NULL);
+ }
+ cuddRef(y2);
+ Cudd_RecursiveDeref(dd, z1);
+ Cudd_RecursiveDeref(dd, z2);
+ Cudd_RecursiveDeref(dd, z3);
+ Cudd_RecursiveDeref(dd, z4);
+ x1 = Cudd_bddIte(dd, x[i], y1_, Cudd_Not(y2));
+ if (x1 == NULL) {
+ Cudd_RecursiveDeref(dd, y1_);
+ Cudd_RecursiveDeref(dd, y2);
+ return(NULL);
+ }
+ cuddRef(x1);
+ Cudd_RecursiveDeref(dd, y1_);
+ Cudd_RecursiveDeref(dd, y2);
+ }
+ cuddDeref(x1);
+ return(Cudd_Not(x1));
+
+} /* end of Cudd_Dxygtdyz */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the compatible projection of R w.r.t. cube Y.]
+
+ Description [Computes the compatible projection of relation R with
+ respect to cube Y. Returns a pointer to the c-projection if
+ successful; NULL otherwise. For a comparison between Cudd_CProjection
+ and Cudd_PrioritySelect, see the documentation of the latter.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_PrioritySelect]
+
+******************************************************************************/
+DdNode *
+Cudd_CProjection(
+ DdManager * dd,
+ DdNode * R,
+ DdNode * Y)
+{
+ DdNode *res;
+ DdNode *support;
+
+ if (cuddCheckCube(dd,Y) == 0) {
+ (void) fprintf(dd->err,
+ "Error: The third argument of Cudd_CProjection should be a cube\n");
+ dd->errorCode = CUDD_INVALID_ARG;
+ return(NULL);
+ }
+
+ /* Compute the support of Y, which is used by the abstraction step
+ ** in cuddCProjectionRecur.
+ */
+ support = Cudd_Support(dd,Y);
+ if (support == NULL) return(NULL);
+ cuddRef(support);
+
+ do {
+ dd->reordered = 0;
+ res = cuddCProjectionRecur(dd,R,Y,support);
+ } while (dd->reordered == 1);
+
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,support);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd,support);
+ cuddDeref(res);
+
+ return(res);
+
+} /* end of Cudd_CProjection */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the Hamming distance ADD.]
+
+ Description [Computes the Hamming distance ADD. Returns an ADD that
+ gives the Hamming distance between its two arguments if successful;
+ NULL otherwise. The two vectors xVars and yVars identify the variables
+ that form the two arguments.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_addHamming(
+ DdManager * dd,
+ DdNode ** xVars,
+ DdNode ** yVars,
+ int nVars)
+{
+ DdNode *result,*tempBdd;
+ DdNode *tempAdd,*temp;
+ int i;
+
+ result = DD_ZERO(dd);
+ cuddRef(result);
+
+ for (i = 0; i < nVars; i++) {
+ tempBdd = Cudd_bddIte(dd,xVars[i],Cudd_Not(yVars[i]),yVars[i]);
+ if (tempBdd == NULL) {
+ Cudd_RecursiveDeref(dd,result);
+ return(NULL);
+ }
+ cuddRef(tempBdd);
+ tempAdd = Cudd_BddToAdd(dd,tempBdd);
+ if (tempAdd == NULL) {
+ Cudd_RecursiveDeref(dd,tempBdd);
+ Cudd_RecursiveDeref(dd,result);
+ return(NULL);
+ }
+ cuddRef(tempAdd);
+ Cudd_RecursiveDeref(dd,tempBdd);
+ temp = Cudd_addApply(dd,Cudd_addPlus,tempAdd,result);
+ if (temp == NULL) {
+ Cudd_RecursiveDeref(dd,tempAdd);
+ Cudd_RecursiveDeref(dd,result);
+ return(NULL);
+ }
+ cuddRef(temp);
+ Cudd_RecursiveDeref(dd,tempAdd);
+ Cudd_RecursiveDeref(dd,result);
+ result = temp;
+ }
+
+ cuddDeref(result);
+ return(result);
+
+} /* end of Cudd_addHamming */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the minimum Hamming distance between f and minterm.]
+
+ Description [Returns the minimum Hamming distance between the
+ minterms of a function f and a reference minterm. The function is
+ given as a BDD; the minterm is given as an array of integers, one
+ for each variable in the manager. Returns the minimum distance if
+ it is less than the upper bound; the upper bound if the minimum
+ distance is at least as large; CUDD_OUT_OF_MEM in case of failure.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addHamming Cudd_bddClosestCube]
+
+******************************************************************************/
+int
+Cudd_MinHammingDist(
+ DdManager *dd /* DD manager */,
+ DdNode *f /* function to examine */,
+ int *minterm /* reference minterm */,
+ int upperBound /* distance above which an approximate answer is OK */)
+{
+ DdHashTable *table;
+ CUDD_VALUE_TYPE epsilon;
+ int res;
+
+ table = cuddHashTableInit(dd,1,2);
+ if (table == NULL) {
+ return(CUDD_OUT_OF_MEM);
+ }
+ epsilon = Cudd_ReadEpsilon(dd);
+ Cudd_SetEpsilon(dd,(CUDD_VALUE_TYPE)0.0);
+ res = cuddMinHammingDistRecur(f,minterm,table,upperBound);
+ cuddHashTableQuit(table);
+ Cudd_SetEpsilon(dd,epsilon);
+
+ return(res);
+
+} /* end of Cudd_MinHammingDist */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds a cube of f at minimum Hamming distance from g.]
+
+ Description [Finds a cube of f at minimum Hamming distance from the
+ minterms of g. All the minterms of the cube are at the minimum
+ distance. If the distance is 0, the cube belongs to the
+ intersection of f and g. Returns the cube if successful; NULL
+ otherwise.]
+
+ SideEffects [The distance is returned as a side effect.]
+
+ SeeAlso [Cudd_MinHammingDist]
+
+******************************************************************************/
+DdNode *
+Cudd_bddClosestCube(
+ DdManager *dd,
+ DdNode * f,
+ DdNode *g,
+ int *distance)
+{
+ DdNode *res, *acube;
+ CUDD_VALUE_TYPE rdist;
+
+ /* Compute the cube and distance as a single ADD. */
+ do {
+ dd->reordered = 0;
+ res = cuddBddClosestCube(dd,f,g,CUDD_CONST_INDEX + 1.0);
+ } while (dd->reordered == 1);
+ if (res == NULL) return(NULL);
+ cuddRef(res);
+
+ /* Unpack distance and cube. */
+ do {
+ dd->reordered = 0;
+ acube = separateCube(dd, res, &rdist);
+ } while (dd->reordered == 1);
+ if (acube == NULL) {
+ Cudd_RecursiveDeref(dd, res);
+ return(NULL);
+ }
+ cuddRef(acube);
+ Cudd_RecursiveDeref(dd, res);
+
+ /* Convert cube from ADD to BDD. */
+ do {
+ dd->reordered = 0;
+ res = cuddAddBddDoPattern(dd, acube);
+ } while (dd->reordered == 1);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, acube);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, acube);
+
+ *distance = (int) rdist;
+ cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_bddClosestCube */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_CProjection.]
+
+ Description [Performs the recursive step of Cudd_CProjection. Returns
+ the projection if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_CProjection]
+
+******************************************************************************/
+DdNode *
+cuddCProjectionRecur(
+ DdManager * dd,
+ DdNode * R,
+ DdNode * Y,
+ DdNode * Ysupp)
+{
+ DdNode *res, *res1, *res2, *resA;
+ DdNode *r, *y, *RT, *RE, *YT, *YE, *Yrest, *Ra, *Ran, *Gamma, *Alpha;
+ unsigned int topR, topY, top, index;
+ DdNode *one = DD_ONE(dd);
+
+ statLine(dd);
+ if (Y == one) return(R);
+
+#ifdef DD_DEBUG
+ assert(!Cudd_IsConstant(Y));
+#endif
+
+ if (R == Cudd_Not(one)) return(R);
+
+ res = cuddCacheLookup2(dd, Cudd_CProjection, R, Y);
+ if (res != NULL) return(res);
+
+ r = Cudd_Regular(R);
+ topR = cuddI(dd,r->index);
+ y = Cudd_Regular(Y);
+ topY = cuddI(dd,y->index);
+
+ top = ddMin(topR, topY);
+
+ /* Compute the cofactors of R */
+ if (topR == top) {
+ index = r->index;
+ RT = cuddT(r);
+ RE = cuddE(r);
+ if (r != R) {
+ RT = Cudd_Not(RT); RE = Cudd_Not(RE);
+ }
+ } else {
+ RT = RE = R;
+ }
+
+ if (topY > top) {
+ /* Y does not depend on the current top variable.
+ ** We just need to compute the results on the two cofactors of R
+ ** and make them the children of a node labeled r->index.
+ */
+ res1 = cuddCProjectionRecur(dd,RT,Y,Ysupp);
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ res2 = cuddCProjectionRecur(dd,RE,Y,Ysupp);
+ if (res2 == NULL) {
+ Cudd_RecursiveDeref(dd,res1);
+ return(NULL);
+ }
+ cuddRef(res2);
+ res = cuddBddIteRecur(dd, dd->vars[index], res1, res2);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,res1);
+ Cudd_RecursiveDeref(dd,res2);
+ return(NULL);
+ }
+ /* If we have reached this point, res1 and res2 are now
+ ** incorporated in res. cuddDeref is therefore sufficient.
+ */
+ cuddDeref(res1);
+ cuddDeref(res2);
+ } else {
+ /* Compute the cofactors of Y */
+ index = y->index;
+ YT = cuddT(y);
+ YE = cuddE(y);
+ if (y != Y) {
+ YT = Cudd_Not(YT); YE = Cudd_Not(YE);
+ }
+ if (YT == Cudd_Not(one)) {
+ Alpha = Cudd_Not(dd->vars[index]);
+ Yrest = YE;
+ Ra = RE;
+ Ran = RT;
+ } else {
+ Alpha = dd->vars[index];
+ Yrest = YT;
+ Ra = RT;
+ Ran = RE;
+ }
+ Gamma = cuddBddExistAbstractRecur(dd,Ra,cuddT(Ysupp));
+ if (Gamma == NULL) return(NULL);
+ if (Gamma == one) {
+ res1 = cuddCProjectionRecur(dd,Ra,Yrest,cuddT(Ysupp));
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ res = cuddBddAndRecur(dd, Alpha, res1);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,res1);
+ return(NULL);
+ }
+ cuddDeref(res1);
+ } else if (Gamma == Cudd_Not(one)) {
+ res1 = cuddCProjectionRecur(dd,Ran,Yrest,cuddT(Ysupp));
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ res = cuddBddAndRecur(dd, Cudd_Not(Alpha), res1);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,res1);
+ return(NULL);
+ }
+ cuddDeref(res1);
+ } else {
+ cuddRef(Gamma);
+ resA = cuddCProjectionRecur(dd,Ran,Yrest,cuddT(Ysupp));
+ if (resA == NULL) {
+ Cudd_RecursiveDeref(dd,Gamma);
+ return(NULL);
+ }
+ cuddRef(resA);
+ res2 = cuddBddAndRecur(dd, Cudd_Not(Gamma), resA);
+ if (res2 == NULL) {
+ Cudd_RecursiveDeref(dd,Gamma);
+ Cudd_RecursiveDeref(dd,resA);
+ return(NULL);
+ }
+ cuddRef(res2);
+ Cudd_RecursiveDeref(dd,Gamma);
+ Cudd_RecursiveDeref(dd,resA);
+ res1 = cuddCProjectionRecur(dd,Ra,Yrest,cuddT(Ysupp));
+ if (res1 == NULL) {
+ Cudd_RecursiveDeref(dd,res2);
+ return(NULL);
+ }
+ cuddRef(res1);
+ res = cuddBddIteRecur(dd, Alpha, res1, res2);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,res1);
+ Cudd_RecursiveDeref(dd,res2);
+ return(NULL);
+ }
+ cuddDeref(res1);
+ cuddDeref(res2);
+ }
+ }
+
+ cuddCacheInsert2(dd,Cudd_CProjection,R,Y,res);
+
+ return(res);
+
+} /* end of cuddCProjectionRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddClosestCube.]
+
+ Description [Performs the recursive step of Cudd_bddClosestCube.
+ Returns the cube if succesful; NULL otherwise. The procedure uses a
+ four-way recursion to examine all four combinations of cofactors of
+ f and g. The most interesting feature of this function is the
+ scheme used for caching the results in the global computed table.
+ Since we have a cube and a distance, we combine them to form an ADD.
+ The combination replaces the zero child of the top node of the cube
+ with the negative of the distance. (The use of the negative is to
+ avoid ambiguity with 1.) The degenerate cases (zero and one) are
+ treated specially because the distance is known (0 for one, and
+ infinity for zero).]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddClosestCube]
+
+******************************************************************************/
+DdNode *
+cuddBddClosestCube(
+ DdManager *dd,
+ DdNode *f,
+ DdNode *g,
+ CUDD_VALUE_TYPE bound)
+{
+ DdNode *res, *F, *G, *ft, *fe, *gt, *ge, *tt, *ee;
+ DdNode *ctt, *cee, *cte, *cet;
+ CUDD_VALUE_TYPE minD, dtt, dee, dte, det;
+ DdNode *one = DD_ONE(dd);
+ DdNode *lzero = Cudd_Not(one);
+ DdNode *azero = DD_ZERO(dd);
+ unsigned int topf, topg, index;
+
+ statLine(dd);
+ if (bound < (f == Cudd_Not(g))) return(azero);
+ /* Terminal cases. */
+ if (g == lzero || f == lzero) return(azero);
+ if (f == one && g == one) return(one);
+
+ /* Check cache. */
+ F = Cudd_Regular(f);
+ G = Cudd_Regular(g);
+ if (F->ref != 1 || G->ref != 1) {
+ res = cuddCacheLookup2(dd,(DdNode * (*)(DdManager *, DdNode *,
+ DdNode *)) Cudd_bddClosestCube, f, g);
+ if (res != NULL) return(res);
+ }
+
+ topf = cuddI(dd,F->index);
+ topg = cuddI(dd,G->index);
+
+ /* Compute cofactors. */
+ if (topf <= topg) {
+ index = F->index;
+ ft = cuddT(F);
+ fe = cuddE(F);
+ if (Cudd_IsComplement(f)) {
+ ft = Cudd_Not(ft);
+ fe = Cudd_Not(fe);
+ }
+ } else {
+ index = G->index;
+ ft = fe = f;
+ }
+
+ if (topg <= topf) {
+ gt = cuddT(G);
+ ge = cuddE(G);
+ if (Cudd_IsComplement(g)) {
+ gt = Cudd_Not(gt);
+ ge = Cudd_Not(ge);
+ }
+ } else {
+ gt = ge = g;
+ }
+
+ tt = cuddBddClosestCube(dd,ft,gt,bound);
+ if (tt == NULL) return(NULL);
+ cuddRef(tt);
+ ctt = separateCube(dd,tt,&dtt);
+ if (ctt == NULL) {
+ Cudd_RecursiveDeref(dd, tt);
+ return(NULL);
+ }
+ cuddRef(ctt);
+ Cudd_RecursiveDeref(dd, tt);
+ minD = dtt;
+ bound = ddMin(bound,minD);
+
+ ee = cuddBddClosestCube(dd,fe,ge,bound);
+ if (ee == NULL) {
+ Cudd_RecursiveDeref(dd, ctt);
+ return(NULL);
+ }
+ cuddRef(ee);
+ cee = separateCube(dd,ee,&dee);
+ if (cee == NULL) {
+ Cudd_RecursiveDeref(dd, ctt);
+ Cudd_RecursiveDeref(dd, ee);
+ return(NULL);
+ }
+ cuddRef(cee);
+ Cudd_RecursiveDeref(dd, ee);
+ minD = ddMin(dtt, dee);
+ bound = ddMin(bound,minD-1);
+
+ if (minD > 0 && topf == topg) {
+ DdNode *te = cuddBddClosestCube(dd,ft,ge,bound-1);
+ if (te == NULL) {
+ Cudd_RecursiveDeref(dd, ctt);
+ Cudd_RecursiveDeref(dd, cee);
+ return(NULL);
+ }
+ cuddRef(te);
+ cte = separateCube(dd,te,&dte);
+ if (cte == NULL) {
+ Cudd_RecursiveDeref(dd, ctt);
+ Cudd_RecursiveDeref(dd, cee);
+ Cudd_RecursiveDeref(dd, te);
+ return(NULL);
+ }
+ cuddRef(cte);
+ Cudd_RecursiveDeref(dd, te);
+ dte += 1.0;
+ minD = ddMin(minD, dte);
+ } else {
+ cte = azero;
+ cuddRef(cte);
+ dte = CUDD_CONST_INDEX + 1.0;
+ }
+ bound = ddMin(bound,minD-1);
+
+ if (minD > 0 && topf == topg) {
+ DdNode *et = cuddBddClosestCube(dd,fe,gt,bound-1);
+ if (et == NULL) {
+ Cudd_RecursiveDeref(dd, ctt);
+ Cudd_RecursiveDeref(dd, cee);
+ Cudd_RecursiveDeref(dd, cte);
+ return(NULL);
+ }
+ cuddRef(et);
+ cet = separateCube(dd,et,&det);
+ if (cet == NULL) {
+ Cudd_RecursiveDeref(dd, ctt);
+ Cudd_RecursiveDeref(dd, cee);
+ Cudd_RecursiveDeref(dd, cte);
+ Cudd_RecursiveDeref(dd, et);
+ return(NULL);
+ }
+ cuddRef(cet);
+ Cudd_RecursiveDeref(dd, et);
+ det += 1.0;
+ minD = ddMin(minD, det);
+ } else {
+ cet = azero;
+ cuddRef(cet);
+ det = CUDD_CONST_INDEX + 1.0;
+ }
+
+ if (minD == dtt) {
+ if (dtt == dee && ctt == cee) {
+ res = createResult(dd,CUDD_CONST_INDEX,1,ctt,dtt);
+ } else {
+ res = createResult(dd,index,1,ctt,dtt);
+ }
+ } else if (minD == dee) {
+ res = createResult(dd,index,0,cee,dee);
+ } else if (minD == dte) {
+ res = createResult(dd,index,(topf <= topg),cte,dte);
+ } else {
+ res = createResult(dd,index,(topf > topg),cet,det);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, ctt);
+ Cudd_RecursiveDeref(dd, cee);
+ Cudd_RecursiveDeref(dd, cte);
+ Cudd_RecursiveDeref(dd, cet);
+
+ if (F->ref != 1 || G->ref != 1)
+ cuddCacheInsert2(dd,(DdNode * (*)(DdManager *, DdNode *,
+ DdNode *)) Cudd_bddClosestCube, f, g, res);
+
+ cuddDeref(res);
+ return(res);
+
+} /* end of cuddBddClosestCube */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_MinHammingDist.]
+
+ Description [Performs the recursive step of Cudd_MinHammingDist.
+ It is based on the following identity. Let H(f) be the
+ minimum Hamming distance of the minterms of f from the reference
+ minterm. Then:
+ <xmp>
+ H(f) = min(H(f0)+h0,H(f1)+h1)
+ </xmp>
+ where f0 and f1 are the two cofactors of f with respect to its top
+ variable; h0 is 1 if the minterm assigns 1 to the top variable of f;
+ h1 is 1 if the minterm assigns 0 to the top variable of f.
+ The upper bound on the distance is used to bound the depth of the
+ recursion.
+ Returns the minimum distance unless it exceeds the upper bound or
+ computation fails.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_MinHammingDist]
+
+******************************************************************************/
+static int
+cuddMinHammingDistRecur(
+ DdNode * f,
+ int *minterm,
+ DdHashTable * table,
+ int upperBound)
+{
+ DdNode *F, *Ft, *Fe;
+ double h, hT, hE;
+ DdNode *zero, *res;
+ DdManager *dd = table->manager;
+
+ statLine(dd);
+ if (upperBound == 0) return(0);
+
+ F = Cudd_Regular(f);
+
+ if (cuddIsConstant(F)) {
+ zero = Cudd_Not(DD_ONE(dd));
+ if (f == dd->background || f == zero) {
+ return(upperBound);
+ } else {
+ return(0);
+ }
+ }
+ if ((res = cuddHashTableLookup1(table,f)) != NULL) {
+ h = cuddV(res);
+ if (res->ref == 0) {
+ dd->dead++;
+ dd->constants.dead++;
+ }
+ return((int) h);
+ }
+
+ Ft = cuddT(F); Fe = cuddE(F);
+ if (Cudd_IsComplement(f)) {
+ Ft = Cudd_Not(Ft); Fe = Cudd_Not(Fe);
+ }
+ if (minterm[F->index] == 0) {
+ DdNode *temp = Ft;
+ Ft = Fe; Fe = temp;
+ }
+
+ hT = cuddMinHammingDistRecur(Ft,minterm,table,upperBound);
+ if (hT == CUDD_OUT_OF_MEM) return(CUDD_OUT_OF_MEM);
+ if (hT == 0) {
+ hE = upperBound;
+ } else {
+ hE = cuddMinHammingDistRecur(Fe,minterm,table,upperBound - 1);
+ if (hE == CUDD_OUT_OF_MEM) return(CUDD_OUT_OF_MEM);
+ }
+ h = ddMin(hT, hE + 1);
+
+ if (F->ref != 1) {
+ ptrint fanout = (ptrint) F->ref;
+ cuddSatDec(fanout);
+ res = cuddUniqueConst(dd, (CUDD_VALUE_TYPE) h);
+ if (!cuddHashTableInsert1(table,f,res,fanout)) {
+ cuddRef(res); Cudd_RecursiveDeref(dd, res);
+ return(CUDD_OUT_OF_MEM);
+ }
+ }
+
+ return((int) h);
+
+} /* end of cuddMinHammingDistRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Separates cube from distance.]
+
+ Description [Separates cube from distance. Returns the cube if
+ successful; NULL otherwise.]
+
+ SideEffects [The distance is returned as a side effect.]
+
+ SeeAlso [cuddBddClosestCube createResult]
+
+******************************************************************************/
+static DdNode *
+separateCube(
+ DdManager *dd,
+ DdNode *f,
+ CUDD_VALUE_TYPE *distance)
+{
+ DdNode *cube, *t;
+
+ /* One and zero are special cases because the distance is implied. */
+ if (Cudd_IsConstant(f)) {
+ *distance = (f == DD_ONE(dd)) ? 0.0 :
+ (1.0 + (CUDD_VALUE_TYPE) CUDD_CONST_INDEX);
+ return(f);
+ }
+
+ /* Find out which branch points to the distance and replace the top
+ ** node with one pointing to zero instead. */
+ t = cuddT(f);
+ if (Cudd_IsConstant(t) && cuddV(t) <= 0) {
+#ifdef DD_DEBUG
+ assert(!Cudd_IsConstant(cuddE(f)) || cuddE(f) == DD_ONE(dd));
+#endif
+ *distance = -cuddV(t);
+ cube = cuddUniqueInter(dd, f->index, DD_ZERO(dd), cuddE(f));
+ } else {
+#ifdef DD_DEBUG
+ assert(!Cudd_IsConstant(t) || t == DD_ONE(dd));
+#endif
+ *distance = -cuddV(cuddE(f));
+ cube = cuddUniqueInter(dd, f->index, t, DD_ZERO(dd));
+ }
+
+ return(cube);
+
+} /* end of separateCube */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds a result for cache storage.]
+
+ Description [Builds a result for cache storage. Returns a pointer
+ to the resulting ADD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddBddClosestCube separateCube]
+
+******************************************************************************/
+static DdNode *
+createResult(
+ DdManager *dd,
+ unsigned int index,
+ unsigned int phase,
+ DdNode *cube,
+ CUDD_VALUE_TYPE distance)
+{
+ DdNode *res, *constant;
+
+ /* Special case. The cube is either one or zero, and we do not
+ ** add any variables. Hence, the result is also one or zero,
+ ** and the distance remains implied by teh value of the constant. */
+ if (index == CUDD_CONST_INDEX && Cudd_IsConstant(cube)) return(cube);
+
+ constant = cuddUniqueConst(dd,-distance);
+ if (constant == NULL) return(NULL);
+ cuddRef(constant);
+
+ if (index == CUDD_CONST_INDEX) {
+ /* Replace the top node. */
+ if (cuddT(cube) == DD_ZERO(dd)) {
+ res = cuddUniqueInter(dd,cube->index,constant,cuddE(cube));
+ } else {
+ res = cuddUniqueInter(dd,cube->index,cuddT(cube),constant);
+ }
+ } else {
+ /* Add a new top node. */
+#ifdef DD_DEBUG
+ assert(cuddI(dd,index) < cuddI(dd,cube->index));
+#endif
+ if (phase) {
+ res = cuddUniqueInter(dd,index,cube,constant);
+ } else {
+ res = cuddUniqueInter(dd,index,constant,cube);
+ }
+ }
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, constant);
+ return(NULL);
+ }
+ cuddDeref(constant); /* safe because constant is part of res */
+
+ return(res);
+
+} /* end of createResult */
diff --git a/src/bdd/cudd/cuddRead.c b/src/bdd/cudd/cuddRead.c
new file mode 100644
index 00000000..eea4c7f3
--- /dev/null
+++ b/src/bdd/cudd/cuddRead.c
@@ -0,0 +1,490 @@
+/**CFile***********************************************************************
+
+ FileName [cuddRead.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions to read in a matrix]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_addRead()
+ <li> Cudd_bddRead()
+ </ul>]
+
+ SeeAlso [cudd_addHarwell.c]
+
+ Author [Fabio Somenzi]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddRead.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads in a sparse matrix.]
+
+ Description [Reads in a sparse matrix specified in a simple format.
+ The first line of the input contains the numbers of rows and columns.
+ The remaining lines contain the elements of the matrix, one per line.
+ Given a background value
+ (specified by the background field of the manager), only the values
+ different from it are explicitly listed. Each foreground element is
+ described by two integers, i.e., the row and column number, and a
+ real number, i.e., the value.<p>
+ Cudd_addRead produces an ADD that depends on two sets of variables: x
+ and y. The x variables (x\[0\] ... x\[nx-1\]) encode the row index and
+ the y variables (y\[0\] ... y\[ny-1\]) encode the column index.
+ x\[0\] and y\[0\] are the most significant bits in the indices.
+ The variables may already exist or may be created by the function.
+ The index of x\[i\] is bx+i*sx, and the index of y\[i\] is by+i*sy.<p>
+ On input, nx and ny hold the numbers
+ of row and column variables already in existence. On output, they
+ hold the numbers of row and column variables actually used by the
+ matrix. When Cudd_addRead creates the variable arrays,
+ the index of x\[i\] is bx+i*sx, and the index of y\[i\] is by+i*sy.
+ When some variables already exist Cudd_addRead expects the indices
+ of the existing x variables to be bx+i*sx, and the indices of the
+ existing y variables to be by+i*sy.<p>
+ m and n are set to the numbers of rows and columns of the
+ matrix. Their values on input are immaterial.
+ The ADD for the
+ sparse matrix is returned in E, and its reference count is > 0.
+ Cudd_addRead returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [nx and ny are set to the numbers of row and column
+ variables. m and n are set to the numbers of rows and columns. x and y
+ are possibly extended to represent the array of row and column
+ variables. Similarly for xn and yn_, which hold on return from
+ Cudd_addRead the complements of the row and column variables.]
+
+ SeeAlso [Cudd_addHarwell Cudd_bddRead]
+
+******************************************************************************/
+int
+Cudd_addRead(
+ FILE * fp /* input file pointer */,
+ DdManager * dd /* DD manager */,
+ DdNode ** E /* characteristic function of the graph */,
+ DdNode *** x /* array of row variables */,
+ DdNode *** y /* array of column variables */,
+ DdNode *** xn /* array of complemented row variables */,
+ DdNode *** yn_ /* array of complemented column variables */,
+ int * nx /* number or row variables */,
+ int * ny /* number or column variables */,
+ int * m /* number of rows */,
+ int * n /* number of columns */,
+ int bx /* first index of row variables */,
+ int sx /* step of row variables */,
+ int by /* first index of column variables */,
+ int sy /* step of column variables */)
+{
+ DdNode *one, *zero;
+ DdNode *w, *neW;
+ DdNode *minterm1;
+ int u, v, err, i, nv;
+ int lnx, lny;
+ CUDD_VALUE_TYPE val;
+ DdNode **lx, **ly, **lxn, **lyn;
+
+ one = DD_ONE(dd);
+ zero = DD_ZERO(dd);
+
+ err = fscanf(fp, "%d %d", &u, &v);
+ if (err == EOF) {
+ return(0);
+ } else if (err != 2) {
+ return(0);
+ }
+
+ *m = u;
+ /* Compute the number of x variables. */
+ lx = *x; lxn = *xn;
+ u--; /* row and column numbers start from 0 */
+ for (lnx=0; u > 0; lnx++) {
+ u >>= 1;
+ }
+ /* Here we rely on the fact that REALLOC of a null pointer is
+ ** translates to an ALLOC.
+ */
+ if (lnx > *nx) {
+ *x = lx = REALLOC(DdNode *, *x, lnx);
+ if (lx == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ *xn = lxn = REALLOC(DdNode *, *xn, lnx);
+ if (lxn == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ }
+
+ *n = v;
+ /* Compute the number of y variables. */
+ ly = *y; lyn = *yn_;
+ v--; /* row and column numbers start from 0 */
+ for (lny=0; v > 0; lny++) {
+ v >>= 1;
+ }
+ /* Here we rely on the fact that REALLOC of a null pointer is
+ ** translates to an ALLOC.
+ */
+ if (lny > *ny) {
+ *y = ly = REALLOC(DdNode *, *y, lny);
+ if (ly == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ *yn_ = lyn = REALLOC(DdNode *, *yn_, lny);
+ if (lyn == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ }
+
+ /* Create all new variables. */
+ for (i = *nx, nv = bx + (*nx) * sx; i < lnx; i++, nv += sx) {
+ do {
+ dd->reordered = 0;
+ lx[i] = cuddUniqueInter(dd, nv, one, zero);
+ } while (dd->reordered == 1);
+ if (lx[i] == NULL) return(0);
+ cuddRef(lx[i]);
+ do {
+ dd->reordered = 0;
+ lxn[i] = cuddUniqueInter(dd, nv, zero, one);
+ } while (dd->reordered == 1);
+ if (lxn[i] == NULL) return(0);
+ cuddRef(lxn[i]);
+ }
+ for (i = *ny, nv = by + (*ny) * sy; i < lny; i++, nv += sy) {
+ do {
+ dd->reordered = 0;
+ ly[i] = cuddUniqueInter(dd, nv, one, zero);
+ } while (dd->reordered == 1);
+ if (ly[i] == NULL) return(0);
+ cuddRef(ly[i]);
+ do {
+ dd->reordered = 0;
+ lyn[i] = cuddUniqueInter(dd, nv, zero, one);
+ } while (dd->reordered == 1);
+ if (lyn[i] == NULL) return(0);
+ cuddRef(lyn[i]);
+ }
+ *nx = lnx;
+ *ny = lny;
+
+ *E = dd->background; /* this call will never cause reordering */
+ cuddRef(*E);
+
+ while (! feof(fp)) {
+ err = fscanf(fp, "%d %d %lf", &u, &v, &val);
+ if (err == EOF) {
+ break;
+ } else if (err != 3) {
+ return(0);
+ } else if (u >= *m || v >= *n || u < 0 || v < 0) {
+ return(0);
+ }
+
+ minterm1 = one; cuddRef(minterm1);
+
+ /* Build minterm1 corresponding to this arc */
+ for (i = lnx - 1; i>=0; i--) {
+ if (u & 1) {
+ w = Cudd_addApply(dd, Cudd_addTimes, minterm1, lx[i]);
+ } else {
+ w = Cudd_addApply(dd, Cudd_addTimes, minterm1, lxn[i]);
+ }
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, minterm1);
+ return(0);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, minterm1);
+ minterm1 = w;
+ u >>= 1;
+ }
+ for (i = lny - 1; i>=0; i--) {
+ if (v & 1) {
+ w = Cudd_addApply(dd, Cudd_addTimes, minterm1, ly[i]);
+ } else {
+ w = Cudd_addApply(dd, Cudd_addTimes, minterm1, lyn[i]);
+ }
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, minterm1);
+ return(0);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, minterm1);
+ minterm1 = w;
+ v >>= 1;
+ }
+ /* Create new constant node if necessary.
+ ** This call will never cause reordering.
+ */
+ neW = cuddUniqueConst(dd, val);
+ if (neW == NULL) {
+ Cudd_RecursiveDeref(dd, minterm1);
+ return(0);
+ }
+ cuddRef(neW);
+
+ w = Cudd_addIte(dd, minterm1, neW, *E);
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, minterm1);
+ Cudd_RecursiveDeref(dd, neW);
+ return(0);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, minterm1);
+ Cudd_RecursiveDeref(dd, neW);
+ Cudd_RecursiveDeref(dd, *E);
+ *E = w;
+ }
+ return(1);
+
+} /* end of Cudd_addRead */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads in a graph (without labels) given as a list of arcs.]
+
+ Description [Reads in a graph (without labels) given as an adjacency
+ matrix. The first line of the input contains the numbers of rows and
+ columns of the adjacency matrix. The remaining lines contain the arcs
+ of the graph, one per line. Each arc is described by two integers,
+ i.e., the row and column number, or the indices of the two endpoints.
+ Cudd_bddRead produces a BDD that depends on two sets of variables: x
+ and y. The x variables (x\[0\] ... x\[nx-1\]) encode
+ the row index and the y variables (y\[0\] ... y\[ny-1\]) encode the
+ column index. x\[0\] and y\[0\] are the most significant bits in the
+ indices.
+ The variables may already exist or may be created by the function.
+ The index of x\[i\] is bx+i*sx, and the index of y\[i\] is by+i*sy.<p>
+ On input, nx and ny hold the numbers of row and column variables already
+ in existence. On output, they hold the numbers of row and column
+ variables actually used by the matrix. When Cudd_bddRead creates the
+ variable arrays, the index of x\[i\] is bx+i*sx, and the index of
+ y\[i\] is by+i*sy. When some variables already exist, Cudd_bddRead
+ expects the indices of the existing x variables to be bx+i*sx, and the
+ indices of the existing y variables to be by+i*sy.<p>
+ m and n are set to the numbers of rows and columns of the
+ matrix. Their values on input are immaterial. The BDD for the graph
+ is returned in E, and its reference count is > 0. Cudd_bddRead returns
+ 1 in case of success; 0 otherwise.]
+
+ SideEffects [nx and ny are set to the numbers of row and column
+ variables. m and n are set to the numbers of rows and columns. x and y
+ are possibly extended to represent the array of row and column
+ variables.]
+
+ SeeAlso [Cudd_addHarwell Cudd_addRead]
+
+******************************************************************************/
+int
+Cudd_bddRead(
+ FILE * fp /* input file pointer */,
+ DdManager * dd /* DD manager */,
+ DdNode ** E /* characteristic function of the graph */,
+ DdNode *** x /* array of row variables */,
+ DdNode *** y /* array of column variables */,
+ int * nx /* number or row variables */,
+ int * ny /* number or column variables */,
+ int * m /* number of rows */,
+ int * n /* number of columns */,
+ int bx /* first index of row variables */,
+ int sx /* step of row variables */,
+ int by /* first index of column variables */,
+ int sy /* step of column variables */)
+{
+ DdNode *one, *zero;
+ DdNode *w;
+ DdNode *minterm1;
+ int u, v, err, i, nv;
+ int lnx, lny;
+ DdNode **lx, **ly;
+
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ err = fscanf(fp, "%d %d", &u, &v);
+ if (err == EOF) {
+ return(0);
+ } else if (err != 2) {
+ return(0);
+ }
+
+ *m = u;
+ /* Compute the number of x variables. */
+ lx = *x;
+ u--; /* row and column numbers start from 0 */
+ for (lnx=0; u > 0; lnx++) {
+ u >>= 1;
+ }
+ if (lnx > *nx) {
+ *x = lx = REALLOC(DdNode *, *x, lnx);
+ if (lx == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ }
+
+ *n = v;
+ /* Compute the number of y variables. */
+ ly = *y;
+ v--; /* row and column numbers start from 0 */
+ for (lny=0; v > 0; lny++) {
+ v >>= 1;
+ }
+ if (lny > *ny) {
+ *y = ly = REALLOC(DdNode *, *y, lny);
+ if (ly == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ }
+
+ /* Create all new variables. */
+ for (i = *nx, nv = bx + (*nx) * sx; i < lnx; i++, nv += sx) {
+ do {
+ dd->reordered = 0;
+ lx[i] = cuddUniqueInter(dd, nv, one, zero);
+ } while (dd->reordered == 1);
+ if (lx[i] == NULL) return(0);
+ cuddRef(lx[i]);
+ }
+ for (i = *ny, nv = by + (*ny) * sy; i < lny; i++, nv += sy) {
+ do {
+ dd->reordered = 0;
+ ly[i] = cuddUniqueInter(dd, nv, one, zero);
+ } while (dd->reordered == 1);
+ if (ly[i] == NULL) return(0);
+ cuddRef(ly[i]);
+ }
+ *nx = lnx;
+ *ny = lny;
+
+ *E = zero; /* this call will never cause reordering */
+ cuddRef(*E);
+
+ while (! feof(fp)) {
+ err = fscanf(fp, "%d %d", &u, &v);
+ if (err == EOF) {
+ break;
+ } else if (err != 2) {
+ return(0);
+ } else if (u >= *m || v >= *n || u < 0 || v < 0) {
+ return(0);
+ }
+
+ minterm1 = one; cuddRef(minterm1);
+
+ /* Build minterm1 corresponding to this arc. */
+ for (i = lnx - 1; i>=0; i--) {
+ if (u & 1) {
+ w = Cudd_bddAnd(dd, minterm1, lx[i]);
+ } else {
+ w = Cudd_bddAnd(dd, minterm1, Cudd_Not(lx[i]));
+ }
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, minterm1);
+ return(0);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd,minterm1);
+ minterm1 = w;
+ u >>= 1;
+ }
+ for (i = lny - 1; i>=0; i--) {
+ if (v & 1) {
+ w = Cudd_bddAnd(dd, minterm1, ly[i]);
+ } else {
+ w = Cudd_bddAnd(dd, minterm1, Cudd_Not(ly[i]));
+ }
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, minterm1);
+ return(0);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, minterm1);
+ minterm1 = w;
+ v >>= 1;
+ }
+
+ w = Cudd_bddAnd(dd, Cudd_Not(minterm1), Cudd_Not(*E));
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, minterm1);
+ return(0);
+ }
+ w = Cudd_Not(w);
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, minterm1);
+ Cudd_RecursiveDeref(dd, *E);
+ *E = w;
+ }
+ return(1);
+
+} /* end of Cudd_bddRead */
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/cudd/cuddRef.c b/src/bdd/cudd/cuddRef.c
new file mode 100644
index 00000000..af08d048
--- /dev/null
+++ b/src/bdd/cudd/cuddRef.c
@@ -0,0 +1,781 @@
+/**CFile***********************************************************************
+
+ FileName [cuddRef.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions that manipulate the reference counts.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_Ref()
+ <li> Cudd_RecursiveDeref()
+ <li> Cudd_IterDerefBdd()
+ <li> Cudd_DelayedDerefBdd()
+ <li> Cudd_RecursiveDerefZdd()
+ <li> Cudd_Deref()
+ <li> Cudd_CheckZeroRef()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddReclaim()
+ <li> cuddReclaimZdd()
+ <li> cuddClearDeathRow()
+ <li> cuddShrinkDeathRow()
+ <li> cuddIsInDeathRow()
+ <li> cuddTimesInDeathRow()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddRef.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Increases the reference count of a node, if it is not
+ saturated.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_RecursiveDeref Cudd_Deref]
+
+******************************************************************************/
+void
+Cudd_Ref(
+ DdNode * n)
+{
+
+ n = Cudd_Regular(n);
+
+ cuddSatInc(n->ref);
+
+} /* end of Cudd_Ref */
+
+
+/**Function********************************************************************
+
+ Synopsis [Decreases the reference count of node n.]
+
+ Description [Decreases the reference count of node n. If n dies,
+ recursively decreases the reference counts of its children. It is
+ used to dispose of a DD that is no longer needed.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Deref Cudd_Ref Cudd_RecursiveDerefZdd]
+
+******************************************************************************/
+void
+Cudd_RecursiveDeref(
+ DdManager * table,
+ DdNode * n)
+{
+ DdNode *N;
+ int ord;
+ DdNodePtr *stack = table->stack;
+ int SP = 1;
+
+ unsigned int live = table->keys - table->dead;
+ if (live > table->peakLiveNodes) {
+ table->peakLiveNodes = live;
+ }
+
+ N = Cudd_Regular(n);
+
+ do {
+#ifdef DD_DEBUG
+ assert(N->ref != 0);
+#endif
+
+ if (N->ref == 1) {
+ N->ref = 0;
+ table->dead++;
+#ifdef DD_STATS
+ table->nodesDropped++;
+#endif
+ if (cuddIsConstant(N)) {
+ table->constants.dead++;
+ N = stack[--SP];
+ } else {
+ ord = table->perm[N->index];
+ stack[SP++] = Cudd_Regular(cuddE(N));
+ table->subtables[ord].dead++;
+ N = cuddT(N);
+ }
+ } else {
+ cuddSatDec(N->ref);
+ N = stack[--SP];
+ }
+ } while (SP != 0);
+
+} /* end of Cudd_RecursiveDeref */
+
+
+/**Function********************************************************************
+
+ Synopsis [Decreases the reference count of BDD node n.]
+
+ Description [Decreases the reference count of node n. If n dies,
+ recursively decreases the reference counts of its children. It is
+ used to dispose of a BDD that is no longer needed. It is more
+ efficient than Cudd_RecursiveDeref, but it cannot be used on
+ ADDs. The greater efficiency comes from being able to assume that no
+ constant node will ever die as a result of a call to this
+ procedure.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_RecursiveDeref Cudd_DelayedDerefBdd]
+
+******************************************************************************/
+void
+Cudd_IterDerefBdd(
+ DdManager * table,
+ DdNode * n)
+{
+ DdNode *N;
+ int ord;
+ DdNodePtr *stack = table->stack;
+ int SP = 1;
+
+ unsigned int live = table->keys - table->dead;
+ if (live > table->peakLiveNodes) {
+ table->peakLiveNodes = live;
+ }
+
+ N = Cudd_Regular(n);
+
+ do {
+#ifdef DD_DEBUG
+ assert(N->ref != 0);
+#endif
+
+ if (N->ref == 1) {
+ N->ref = 0;
+ table->dead++;
+#ifdef DD_STATS
+ table->nodesDropped++;
+#endif
+ ord = table->perm[N->index];
+ stack[SP++] = Cudd_Regular(cuddE(N));
+ table->subtables[ord].dead++;
+ N = cuddT(N);
+ } else {
+ cuddSatDec(N->ref);
+ N = stack[--SP];
+ }
+ } while (SP != 0);
+
+} /* end of Cudd_IterDerefBdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Decreases the reference count of BDD node n.]
+
+ Description [Enqueues node n for later dereferencing. If the queue
+ is full decreases the reference count of the oldest node N to make
+ room for n. If N dies, recursively decreases the reference counts of
+ its children. It is used to dispose of a BDD that is currently not
+ needed, but may be useful again in the near future. The dereferencing
+ proper is done as in Cudd_IterDerefBdd.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_RecursiveDeref Cudd_IterDerefBdd]
+
+******************************************************************************/
+void
+Cudd_DelayedDerefBdd(
+ DdManager * table,
+ DdNode * n)
+{
+ DdNode *N;
+ int ord;
+ DdNodePtr *stack;
+ int SP;
+
+ unsigned int live = table->keys - table->dead;
+ if (live > table->peakLiveNodes) {
+ table->peakLiveNodes = live;
+ }
+
+ n = Cudd_Regular(n);
+#ifdef DD_DEBUG
+ assert(n->ref != 0);
+#endif
+
+#ifdef DD_NO_DEATH_ROW
+ N = n;
+#else
+ if (cuddIsConstant(n) || n->ref > 1) {
+#ifdef DD_DEBUG
+ assert(n->ref != 1 && (!cuddIsConstant(n) || n == DD_ONE(table)));
+#endif
+ cuddSatDec(n->ref);
+ return;
+ }
+
+ N = table->deathRow[table->nextDead];
+
+ if (N != NULL) {
+#endif
+#ifdef DD_DEBUG
+ assert(!Cudd_IsComplement(N));
+#endif
+ stack = table->stack;
+ SP = 1;
+ do {
+#ifdef DD_DEBUG
+ assert(N->ref != 0);
+#endif
+ if (N->ref == 1) {
+ N->ref = 0;
+ table->dead++;
+#ifdef DD_STATS
+ table->nodesDropped++;
+#endif
+ ord = table->perm[N->index];
+ stack[SP++] = Cudd_Regular(cuddE(N));
+ table->subtables[ord].dead++;
+ N = cuddT(N);
+ } else {
+ cuddSatDec(N->ref);
+ N = stack[--SP];
+ }
+ } while (SP != 0);
+#ifndef DD_NO_DEATH_ROW
+ }
+ table->deathRow[table->nextDead] = n;
+
+ /* Udate insertion point. */
+ table->nextDead++;
+ table->nextDead &= table->deadMask;
+#if 0
+ if (table->nextDead == table->deathRowDepth) {
+ if (table->deathRowDepth < table->looseUpTo / 2) {
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long) = MMoutOfMemory;
+ DdNodePtr *newRow;
+ MMoutOfMemory = Cudd_OutOfMem;
+ newRow = REALLOC(DdNodePtr,table->deathRow,2*table->deathRowDepth);
+ MMoutOfMemory = saveHandler;
+ if (newRow == NULL) {
+ table->nextDead = 0;
+ } else {
+ int i;
+ table->memused += table->deathRowDepth;
+ i = table->deathRowDepth;
+ table->deathRowDepth <<= 1;
+ for (; i < table->deathRowDepth; i++) {
+ newRow[i] = NULL;
+ }
+ table->deadMask = table->deathRowDepth - 1;
+ table->deathRow = newRow;
+ }
+ } else {
+ table->nextDead = 0;
+ }
+ }
+#endif
+#endif
+
+} /* end of Cudd_DelayedDerefBdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Decreases the reference count of ZDD node n.]
+
+ Description [Decreases the reference count of ZDD node n. If n dies,
+ recursively decreases the reference counts of its children. It is
+ used to dispose of a ZDD that is no longer needed.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Deref Cudd_Ref Cudd_RecursiveDeref]
+
+******************************************************************************/
+void
+Cudd_RecursiveDerefZdd(
+ DdManager * table,
+ DdNode * n)
+{
+ DdNode *N;
+ int ord;
+ DdNodePtr *stack = table->stack;
+ int SP = 1;
+
+ N = n;
+
+ do {
+#ifdef DD_DEBUG
+ assert(N->ref != 0);
+#endif
+
+ cuddSatDec(N->ref);
+
+ if (N->ref == 0) {
+ table->deadZ++;
+#ifdef DD_STATS
+ table->nodesDropped++;
+#endif
+#ifdef DD_DEBUG
+ assert(!cuddIsConstant(N));
+#endif
+ ord = table->permZ[N->index];
+ stack[SP++] = cuddE(N);
+ table->subtableZ[ord].dead++;
+ N = cuddT(N);
+ } else {
+ N = stack[--SP];
+ }
+ } while (SP != 0);
+
+} /* end of Cudd_RecursiveDerefZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Decreases the reference count of node.]
+
+ Description [Decreases the reference count of node. It is primarily
+ used in recursive procedures to decrease the ref count of a result
+ node before returning it. This accomplishes the goal of removing the
+ protection applied by a previous Cudd_Ref.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_RecursiveDeref Cudd_RecursiveDerefZdd Cudd_Ref]
+
+******************************************************************************/
+void
+Cudd_Deref(
+ DdNode * node)
+{
+ node = Cudd_Regular(node);
+ cuddSatDec(node->ref);
+
+} /* end of Cudd_Deref */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks the unique table for nodes with non-zero reference
+ counts.]
+
+ Description [Checks the unique table for nodes with non-zero
+ reference counts. It is normally called before Cudd_Quit to make sure
+ that there are no memory leaks due to missing Cudd_RecursiveDeref's.
+ Takes into account that reference counts may saturate and that the
+ basic constants and the projection functions are referenced by the
+ manager. Returns the number of nodes with non-zero reference count.
+ (Except for the cases mentioned above.)]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_CheckZeroRef(
+ DdManager * manager)
+{
+ int size;
+ int i, j;
+ int remain; /* the expected number of remaining references to one */
+ DdNodePtr *nodelist;
+ DdNode *node;
+ DdNode *sentinel = &(manager->sentinel);
+ DdSubtable *subtable;
+ int count = 0;
+ int index;
+
+#ifndef DD_NO_DEATH_ROW
+ cuddClearDeathRow(manager);
+#endif
+
+ /* First look at the BDD/ADD subtables. */
+ remain = 1; /* reference from the manager */
+ size = manager->size;
+ remain += 2 * size; /* reference from the BDD projection functions */
+
+ for (i = 0; i < size; i++) {
+ subtable = &(manager->subtables[i]);
+ nodelist = subtable->nodelist;
+ for (j = 0; (unsigned) j < subtable->slots; j++) {
+ node = nodelist[j];
+ while (node != sentinel) {
+ if (node->ref != 0 && node->ref != DD_MAXREF) {
+ index = (int) node->index;
+ if (node != manager->vars[index]) {
+ count++;
+ } else {
+ if (node->ref != 1) {
+ count++;
+ }
+ }
+ }
+ node = node->next;
+ }
+ }
+ }
+
+ /* Then look at the ZDD subtables. */
+ size = manager->sizeZ;
+ if (size) /* references from ZDD universe */
+ remain += 2;
+
+ for (i = 0; i < size; i++) {
+ subtable = &(manager->subtableZ[i]);
+ nodelist = subtable->nodelist;
+ for (j = 0; (unsigned) j < subtable->slots; j++) {
+ node = nodelist[j];
+ while (node != NULL) {
+ if (node->ref != 0 && node->ref != DD_MAXREF) {
+ index = (int) node->index;
+ if (node == manager->univ[manager->permZ[index]]) {
+ if (node->ref > 2) {
+ count++;
+ }
+ } else {
+ count++;
+ }
+ }
+ node = node->next;
+ }
+ }
+ }
+
+ /* Now examine the constant table. Plusinfinity, minusinfinity, and
+ ** zero are referenced by the manager. One is referenced by the
+ ** manager, by the ZDD universe, and by all projection functions.
+ ** All other nodes should have no references.
+ */
+ nodelist = manager->constants.nodelist;
+ for (j = 0; (unsigned) j < manager->constants.slots; j++) {
+ node = nodelist[j];
+ while (node != NULL) {
+ if (node->ref != 0 && node->ref != DD_MAXREF) {
+ if (node == manager->one) {
+ if ((int) node->ref != remain) {
+ count++;
+ }
+ } else if (node == manager->zero ||
+ node == manager->plusinfinity ||
+ node == manager->minusinfinity) {
+ if (node->ref != 1) {
+ count++;
+ }
+ } else {
+ count++;
+ }
+ }
+ node = node->next;
+ }
+ }
+ return(count);
+
+} /* end of Cudd_CheckZeroRef */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Brings children of a dead node back.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [cuddReclaimZdd]
+
+******************************************************************************/
+void
+cuddReclaim(
+ DdManager * table,
+ DdNode * n)
+{
+ DdNode *N;
+ int ord;
+ DdNodePtr *stack = table->stack;
+ int SP = 1;
+ double initialDead = table->dead;
+
+ N = Cudd_Regular(n);
+
+#ifdef DD_DEBUG
+ assert(N->ref == 0);
+#endif
+
+ do {
+ if (N->ref == 0) {
+ N->ref = 1;
+ table->dead--;
+ if (cuddIsConstant(N)) {
+ table->constants.dead--;
+ N = stack[--SP];
+ } else {
+ ord = table->perm[N->index];
+ stack[SP++] = Cudd_Regular(cuddE(N));
+ table->subtables[ord].dead--;
+ N = cuddT(N);
+ }
+ } else {
+ cuddSatInc(N->ref);
+ N = stack[--SP];
+ }
+ } while (SP != 0);
+
+ N = Cudd_Regular(n);
+ cuddSatDec(N->ref);
+ table->reclaimed += initialDead - table->dead;
+
+} /* end of cuddReclaim */
+
+
+/**Function********************************************************************
+
+ Synopsis [Brings children of a dead ZDD node back.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [cuddReclaim]
+
+******************************************************************************/
+void
+cuddReclaimZdd(
+ DdManager * table,
+ DdNode * n)
+{
+ DdNode *N;
+ int ord;
+ DdNodePtr *stack = table->stack;
+ int SP = 1;
+
+ N = n;
+
+#ifdef DD_DEBUG
+ assert(N->ref == 0);
+#endif
+
+ do {
+ cuddSatInc(N->ref);
+
+ if (N->ref == 1) {
+ table->deadZ--;
+ table->reclaimed++;
+#ifdef DD_DEBUG
+ assert(!cuddIsConstant(N));
+#endif
+ ord = table->permZ[N->index];
+ stack[SP++] = cuddE(N);
+ table->subtableZ[ord].dead--;
+ N = cuddT(N);
+ } else {
+ N = stack[--SP];
+ }
+ } while (SP != 0);
+
+ cuddSatDec(n->ref);
+
+} /* end of cuddReclaimZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Shrinks the death row.]
+
+ Description [Shrinks the death row by a factor of four.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddClearDeathRow]
+
+******************************************************************************/
+void
+cuddShrinkDeathRow(
+ DdManager *table)
+{
+#ifndef DD_NO_DEATH_ROW
+ int i;
+
+ if (table->deathRowDepth > 3) {
+ for (i = table->deathRowDepth/4; i < table->deathRowDepth; i++) {
+ if (table->deathRow[i] == NULL) break;
+ Cudd_IterDerefBdd(table,table->deathRow[i]);
+ table->deathRow[i] = NULL;
+ }
+ table->deathRowDepth /= 4;
+ table->deadMask = table->deathRowDepth - 2;
+ if ((unsigned) table->nextDead > table->deadMask) {
+ table->nextDead = 0;
+ }
+ table->deathRow = REALLOC(DdNodePtr, table->deathRow,
+ table->deathRowDepth);
+ }
+#endif
+
+} /* end of cuddShrinkDeathRow */
+
+
+/**Function********************************************************************
+
+ Synopsis [Clears the death row.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DelayedDerefBdd Cudd_IterDerefBdd Cudd_CheckZeroRef
+ cuddGarbageCollect]
+
+******************************************************************************/
+void
+cuddClearDeathRow(
+ DdManager *table)
+{
+#ifndef DD_NO_DEATH_ROW
+ int i;
+
+ for (i = 0; i < table->deathRowDepth; i++) {
+ if (table->deathRow[i] == NULL) break;
+ Cudd_IterDerefBdd(table,table->deathRow[i]);
+ table->deathRow[i] = NULL;
+ }
+#ifdef DD_DEBUG
+ for (; i < table->deathRowDepth; i++) {
+ assert(table->deathRow[i] == NULL);
+ }
+#endif
+ table->nextDead = 0;
+#endif
+
+} /* end of cuddClearDeathRow */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether a node is in the death row.]
+
+ Description [Checks whether a node is in the death row. Returns the
+ position of the first occurrence if the node is present; -1
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DelayedDerefBdd cuddClearDeathRow]
+
+******************************************************************************/
+int
+cuddIsInDeathRow(
+ DdManager *dd,
+ DdNode *f)
+{
+#ifndef DD_NO_DEATH_ROW
+ int i;
+
+ for (i = 0; i < dd->deathRowDepth; i++) {
+ if (f == dd->deathRow[i]) {
+ return(i);
+ }
+ }
+#endif
+
+ return(-1);
+
+} /* end of cuddIsInDeathRow */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts how many times a node is in the death row.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DelayedDerefBdd cuddClearDeathRow cuddIsInDeathRow]
+
+******************************************************************************/
+int
+cuddTimesInDeathRow(
+ DdManager *dd,
+ DdNode *f)
+{
+ int count = 0;
+#ifndef DD_NO_DEATH_ROW
+ int i;
+
+ for (i = 0; i < dd->deathRowDepth; i++) {
+ count += f == dd->deathRow[i];
+ }
+#endif
+
+ return(count);
+
+} /* end of cuddTimesInDeathRow */
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
diff --git a/src/bdd/cudd/cuddReorder.c b/src/bdd/cudd/cuddReorder.c
new file mode 100644
index 00000000..e2b3470b
--- /dev/null
+++ b/src/bdd/cudd/cuddReorder.c
@@ -0,0 +1,2090 @@
+/**CFile***********************************************************************
+
+ FileName [cuddReorder.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for dynamic variable reordering.]
+
+ Description [External procedures included in this file:
+ <ul>
+ <li> Cudd_ReduceHeap()
+ <li> Cudd_ShuffleHeap()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddDynamicAllocNode()
+ <li> cuddSifting()
+ <li> cuddSwapping()
+ <li> cuddNextHigh()
+ <li> cuddNextLow()
+ <li> cuddSwapInPlace()
+ <li> cuddBddAlignToZdd()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> ddUniqueCompare()
+ <li> ddSwapAny()
+ <li> ddSiftingAux()
+ <li> ddSiftingUp()
+ <li> ddSiftingDown()
+ <li> ddSiftingBackward()
+ <li> ddReorderPreprocess()
+ <li> ddReorderPostprocess()
+ <li> ddShuffle()
+ <li> ddSiftUp()
+ <li> bddFixTree()
+ </ul>]
+
+ Author [Shipra Panda, Bernard Plessier, Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define DD_MAX_SUBTABLE_SPARSITY 8
+#define DD_SHRINK_FACTOR 2
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddReorder.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+static int *entry;
+
+int ddTotalNumberSwapping;
+#ifdef DD_STATS
+int ddTotalNISwaps;
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int ddUniqueCompare ARGS((int *ptrX, int *ptrY));
+static Move * ddSwapAny ARGS((DdManager *table, int x, int y));
+static int ddSiftingAux ARGS((DdManager *table, int x, int xLow, int xHigh));
+static Move * ddSiftingUp ARGS((DdManager *table, int y, int xLow));
+static Move * ddSiftingDown ARGS((DdManager *table, int x, int xHigh));
+static int ddSiftingBackward ARGS((DdManager *table, int size, Move *moves));
+static int ddReorderPreprocess ARGS((DdManager *table));
+static int ddReorderPostprocess ARGS((DdManager *table));
+static int ddShuffle ARGS((DdManager *table, int *permutation));
+static int ddSiftUp ARGS((DdManager *table, int x, int xLow));
+static void bddFixTree ARGS((DdManager *table, MtrNode *treenode));
+static int ddUpdateMtrTree ARGS((DdManager *table, MtrNode *treenode, int *perm, int *invperm));
+static int ddCheckPermuation ARGS((DdManager *table, MtrNode *treenode, int *perm, int *invperm));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Main dynamic reordering routine.]
+
+ Description [Main dynamic reordering routine.
+ Calls one of the possible reordering procedures:
+ <ul>
+ <li>Swapping
+ <li>Sifting
+ <li>Symmetric Sifting
+ <li>Group Sifting
+ <li>Window Permutation
+ <li>Simulated Annealing
+ <li>Genetic Algorithm
+ <li>Dynamic Programming (exact)
+ </ul>
+
+ For sifting, symmetric sifting, group sifting, and window
+ permutation it is possible to request reordering to convergence.<p>
+
+ The core of all methods is the reordering procedure
+ cuddSwapInPlace() which swaps two adjacent variables and is based
+ on Rudell's paper.
+ Returns 1 in case of success; 0 otherwise. In the case of symmetric
+ sifting (with and without convergence) returns 1 plus the number of
+ symmetric variables, in case of success.]
+
+ SideEffects [Changes the variable order for all diagrams and clears
+ the cache.]
+
+******************************************************************************/
+int
+Cudd_ReduceHeap(
+ DdManager * table /* DD manager */,
+ Cudd_ReorderingType heuristic /* method used for reordering */,
+ int minsize /* bound below which no reordering occurs */)
+{
+ DdHook *hook;
+ int result;
+ unsigned int nextDyn;
+#ifdef DD_STATS
+ unsigned int initialSize;
+ unsigned int finalSize;
+#endif
+ long localTime;
+
+ /* Don't reorder if there are too many dead nodes. */
+ if (table->keys - table->dead < (unsigned) minsize)
+ return(1);
+
+ if (heuristic == CUDD_REORDER_SAME) {
+ heuristic = table->autoMethod;
+ }
+ if (heuristic == CUDD_REORDER_NONE) {
+ return(1);
+ }
+
+ /* This call to Cudd_ReduceHeap does initiate reordering. Therefore
+ ** we count it.
+ */
+ table->reorderings++;
+
+ localTime = util_cpu_time();
+
+ /* Run the hook functions. */
+ hook = table->preReorderingHook;
+ while (hook != NULL) {
+ int res = (hook->f)(table, "BDD", (void *)heuristic);
+ if (res == 0) return(0);
+ hook = hook->next;
+ }
+
+ if (!ddReorderPreprocess(table)) return(0);
+ ddTotalNumberSwapping = 0;
+
+ if (table->keys > table->peakLiveNodes) {
+ table->peakLiveNodes = table->keys;
+ }
+#ifdef DD_STATS
+ initialSize = table->keys - table->isolated;
+ ddTotalNISwaps = 0;
+
+ switch(heuristic) {
+ case CUDD_REORDER_RANDOM:
+ case CUDD_REORDER_RANDOM_PIVOT:
+ (void) fprintf(table->out,"#:I_RANDOM ");
+ break;
+ case CUDD_REORDER_SIFT:
+ case CUDD_REORDER_SIFT_CONVERGE:
+ case CUDD_REORDER_SYMM_SIFT:
+ case CUDD_REORDER_SYMM_SIFT_CONV:
+ case CUDD_REORDER_GROUP_SIFT:
+ case CUDD_REORDER_GROUP_SIFT_CONV:
+ (void) fprintf(table->out,"#:I_SIFTING ");
+ break;
+ case CUDD_REORDER_WINDOW2:
+ case CUDD_REORDER_WINDOW3:
+ case CUDD_REORDER_WINDOW4:
+ case CUDD_REORDER_WINDOW2_CONV:
+ case CUDD_REORDER_WINDOW3_CONV:
+ case CUDD_REORDER_WINDOW4_CONV:
+ (void) fprintf(table->out,"#:I_WINDOW ");
+ break;
+ case CUDD_REORDER_ANNEALING:
+ (void) fprintf(table->out,"#:I_ANNEAL ");
+ break;
+ case CUDD_REORDER_GENETIC:
+ (void) fprintf(table->out,"#:I_GENETIC ");
+ break;
+ case CUDD_REORDER_LINEAR:
+ case CUDD_REORDER_LINEAR_CONVERGE:
+ (void) fprintf(table->out,"#:I_LINSIFT ");
+ break;
+ case CUDD_REORDER_EXACT:
+ (void) fprintf(table->out,"#:I_EXACT ");
+ break;
+ default:
+ return(0);
+ }
+ (void) fprintf(table->out,"%8d: initial size",initialSize);
+#endif
+
+ /* See if we should use alternate threshold for maximum growth. */
+ if (table->reordCycle && table->reorderings % table->reordCycle == 0) {
+ double saveGrowth = table->maxGrowth;
+ table->maxGrowth = table->maxGrowthAlt;
+ result = cuddTreeSifting(table,heuristic);
+ table->maxGrowth = saveGrowth;
+ } else {
+ result = cuddTreeSifting(table,heuristic);
+ }
+
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n");
+ finalSize = table->keys - table->isolated;
+ (void) fprintf(table->out,"#:F_REORDER %8d: final size\n",finalSize);
+ (void) fprintf(table->out,"#:T_REORDER %8g: total time (sec)\n",
+ ((double)(util_cpu_time() - localTime)/1000.0));
+ (void) fprintf(table->out,"#:N_REORDER %8d: total swaps\n",
+ ddTotalNumberSwapping);
+ (void) fprintf(table->out,"#:M_REORDER %8d: NI swaps\n",ddTotalNISwaps);
+#endif
+
+ if (result == 0)
+ return(0);
+
+ if (!ddReorderPostprocess(table))
+ return(0);
+
+ if (table->realign) {
+ if (!cuddZddAlignToBdd(table))
+ return(0);
+ }
+
+ nextDyn = (table->keys - table->constants.keys + 1) *
+ DD_DYN_RATIO + table->constants.keys;
+ if (table->reorderings < 20 || nextDyn > table->nextDyn)
+ table->nextDyn = nextDyn;
+ else
+ table->nextDyn += 20;
+ table->reordered = 1;
+
+ /* Run hook functions. */
+ hook = table->postReorderingHook;
+ while (hook != NULL) {
+ int res = (hook->f)(table, "BDD", (void *)localTime);
+ if (res == 0) return(0);
+ hook = hook->next;
+ }
+ /* Update cumulative reordering time. */
+ table->reordTime += util_cpu_time() - localTime;
+
+ return(result);
+
+} /* end of Cudd_ReduceHeap */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders variables according to given permutation.]
+
+ Description [Reorders variables according to given permutation.
+ The i-th entry of the permutation array contains the index of the variable
+ that should be brought to the i-th level. The size of the array should be
+ equal or greater to the number of variables currently in use.
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [Changes the variable order for all diagrams and clears
+ the cache.]
+
+ SeeAlso [Cudd_ReduceHeap]
+
+******************************************************************************/
+int
+Cudd_ShuffleHeap(
+ DdManager * table /* DD manager */,
+ int * permutation /* required variable permutation */)
+{
+
+ int result;
+ int i;
+ int identity = 1;
+ int *perm;
+
+ /* Don't waste time in case of identity permutation. */
+ for (i = 0; i < table->size; i++) {
+ if (permutation[i] != table->invperm[i]) {
+ identity = 0;
+ break;
+ }
+ }
+ if (identity == 1) {
+ return(1);
+ }
+ if (!ddReorderPreprocess(table)) return(0);
+ if (table->keys > table->peakLiveNodes) {
+ table->peakLiveNodes = table->keys;
+ }
+
+ perm = ALLOC(int, table->size);
+ for (i = 0; i < table->size; i++)
+ perm[permutation[i]] = i;
+ if (!ddCheckPermuation(table,table->tree,perm,permutation)) {
+ FREE(perm);
+ return(0);
+ }
+ if (!ddUpdateMtrTree(table,table->tree,perm,permutation)) {
+ FREE(perm);
+ return(0);
+ }
+ FREE(perm);
+
+ result = ddShuffle(table,permutation);
+
+ if (!ddReorderPostprocess(table)) return(0);
+
+ return(result);
+
+} /* end of Cudd_ShuffleHeap */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Dynamically allocates a Node.]
+
+ Description [Dynamically allocates a Node. This procedure is similar
+ to cuddAllocNode in Cudd_Table.c, but it does not attempt garbage
+ collection, because during reordering there are no dead nodes.
+ Returns a pointer to a new node if successful; NULL is memory is
+ full.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddAllocNode]
+
+******************************************************************************/
+DdNode *
+cuddDynamicAllocNode(
+ DdManager * table)
+{
+ int i;
+ DdNodePtr *mem;
+ DdNode *list, *node;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+
+ if (table->nextFree == NULL) { /* free list is empty */
+ /* Try to allocate a new block. */
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ mem = (DdNodePtr *) ALLOC(DdNode, DD_MEM_CHUNK + 1);
+ MMoutOfMemory = saveHandler;
+ if (mem == NULL && table->stash != NULL) {
+ FREE(table->stash);
+ table->stash = NULL;
+ /* Inhibit resizing of tables. */
+ table->maxCacheHard = table->cacheSlots - 1;
+ table->cacheSlack = -(table->cacheSlots + 1);
+ for (i = 0; i < table->size; i++) {
+ table->subtables[i].maxKeys <<= 2;
+ }
+ mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
+ }
+ if (mem == NULL) {
+ /* Out of luck. Call the default handler to do
+ ** whatever it specifies for a failed malloc. If this
+ ** handler returns, then set error code, print
+ ** warning, and return. */
+ (*MMoutOfMemory)(sizeof(DdNode)*(DD_MEM_CHUNK + 1));
+ table->errorCode = CUDD_MEMORY_OUT;
+#ifdef DD_VERBOSE
+ (void) fprintf(table->err,
+ "cuddDynamicAllocNode: out of memory");
+ (void) fprintf(table->err,"Memory in use = %ld\n",
+ table->memused);
+#endif
+ return(NULL);
+ } else { /* successful allocation; slice memory */
+ unsigned long offset;
+ table->memused += (DD_MEM_CHUNK + 1) * sizeof(DdNode);
+ mem[0] = (DdNode *) table->memoryList;
+ table->memoryList = mem;
+
+ /* Here we rely on the fact that the size of a DdNode is a
+ ** power of 2 and a multiple of the size of a pointer.
+ ** If we align one node, all the others will be aligned
+ ** as well. */
+ offset = (unsigned long) mem & (sizeof(DdNode) - 1);
+ mem += (sizeof(DdNode) - offset) / sizeof(DdNodePtr);
+#ifdef DD_DEBUG
+ assert(((unsigned long) mem & (sizeof(DdNode) - 1)) == 0);
+#endif
+ list = (DdNode *) mem;
+
+ i = 1;
+ do {
+ list[i - 1].next = &list[i];
+ } while (++i < DD_MEM_CHUNK);
+
+ list[DD_MEM_CHUNK - 1].next = NULL;
+
+ table->nextFree = &list[0];
+ }
+ } /* if free list empty */
+
+ node = table->nextFree;
+ table->nextFree = node->next;
+ return (node);
+
+} /* end of cuddDynamicAllocNode */
+
+
+/**Function********************************************************************
+
+ Synopsis [Implementation of Rudell's sifting algorithm.]
+
+ Description [Implementation of Rudell's sifting algorithm.
+ Assumes that no dead nodes are present.
+ <ol>
+ <li> Order all the variables according to the number of entries
+ in each unique table.
+ <li> Sift the variable up and down, remembering each time the
+ total size of the DD heap.
+ <li> Select the best permutation.
+ <li> Repeat 3 and 4 for all variables.
+ </ol>
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+int
+cuddSifting(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i;
+ int *var;
+ int size;
+ int x;
+ int result;
+#ifdef DD_STATS
+ int previousSize;
+#endif
+
+ size = table->size;
+
+ /* Find order in which to sift variables. */
+ var = NULL;
+ entry = ALLOC(int,size);
+ if (entry == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddSiftingOutOfMem;
+ }
+ var = ALLOC(int,size);
+ if (var == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddSiftingOutOfMem;
+ }
+
+ for (i = 0; i < size; i++) {
+ x = table->perm[i];
+ entry[i] = table->subtables[x].keys;
+ var[i] = i;
+ }
+
+ qsort((void *)var,size,sizeof(int),(int (*)(const void *, const void *))ddUniqueCompare);
+
+ /* Now sift. */
+ for (i = 0; i < ddMin(table->siftMaxVar,size); i++) {
+ if (ddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ x = table->perm[var[i]];
+
+ if (x < lower || x > upper || table->subtables[x].bindVar == 1)
+ continue;
+#ifdef DD_STATS
+ previousSize = table->keys - table->isolated;
+#endif
+ result = ddSiftingAux(table, x, lower, upper);
+ if (!result) goto cuddSiftingOutOfMem;
+#ifdef DD_STATS
+ if (table->keys < (unsigned) previousSize + table->isolated) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keys > (unsigned) previousSize + table->isolated) {
+ (void) fprintf(table->out,"+"); /* should never happen */
+ (void) fprintf(table->err,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keys - table->isolated, var[i]);
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+
+ FREE(var);
+ FREE(entry);
+
+ return(1);
+
+cuddSiftingOutOfMem:
+
+ if (entry != NULL) FREE(entry);
+ if (var != NULL) FREE(var);
+
+ return(0);
+
+} /* end of cuddSifting */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders variables by a sequence of (non-adjacent) swaps.]
+
+ Description [Implementation of Plessier's algorithm that reorders
+ variables by a sequence of (non-adjacent) swaps.
+ <ol>
+ <li> Select two variables (RANDOM or HEURISTIC).
+ <li> Permute these variables.
+ <li> If the nodes have decreased accept the permutation.
+ <li> Otherwise reconstruct the original heap.
+ <li> Loop.
+ </ol>
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+int
+cuddSwapping(
+ DdManager * table,
+ int lower,
+ int upper,
+ Cudd_ReorderingType heuristic)
+{
+ int i, j;
+ int max, keys;
+ int nvars;
+ int x, y;
+ int iterate;
+ int previousSize;
+ Move *moves, *move;
+ int pivot;
+ int modulo;
+ int result;
+
+#ifdef DD_DEBUG
+ /* Sanity check */
+ assert(lower >= 0 && upper < table->size && lower <= upper);
+#endif
+
+ nvars = upper - lower + 1;
+ iterate = nvars;
+
+ for (i = 0; i < iterate; i++) {
+ if (ddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ if (heuristic == CUDD_REORDER_RANDOM_PIVOT) {
+ max = -1;
+ for (j = lower; j <= upper; j++) {
+ if ((keys = table->subtables[j].keys) > max) {
+ max = keys;
+ pivot = j;
+ }
+ }
+
+ modulo = upper - pivot;
+ if (modulo == 0) {
+ y = pivot;
+ } else{
+ y = pivot + 1 + ((int) Cudd_Random() % modulo);
+ }
+
+ modulo = pivot - lower - 1;
+ if (modulo < 1) {
+ x = lower;
+ } else{
+ do {
+ x = (int) Cudd_Random() % modulo;
+ } while (x == y);
+ }
+ } else {
+ x = ((int) Cudd_Random() % nvars) + lower;
+ do {
+ y = ((int) Cudd_Random() % nvars) + lower;
+ } while (x == y);
+ }
+ previousSize = table->keys - table->isolated;
+ moves = ddSwapAny(table,x,y);
+ if (moves == NULL) goto cuddSwappingOutOfMem;
+ result = ddSiftingBackward(table,previousSize,moves);
+ if (!result) goto cuddSwappingOutOfMem;
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+#ifdef DD_STATS
+ if (table->keys < (unsigned) previousSize + table->isolated) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keys > (unsigned) previousSize + table->isolated) {
+ (void) fprintf(table->out,"+"); /* should never happen */
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+#if 0
+ (void) fprintf(table->out,"#:t_SWAPPING %8d: tmp size\n",
+ table->keys - table->isolated);
+#endif
+ }
+
+ return(1);
+
+cuddSwappingOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+
+ return(0);
+
+} /* end of cuddSwapping */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the next subtable with a larger index.]
+
+ Description [Finds the next subtable with a larger index. Returns the
+ index.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddNextLow]
+
+******************************************************************************/
+int
+cuddNextHigh(
+ DdManager * table,
+ int x)
+{
+ return(x+1);
+
+} /* end of cuddNextHigh */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the next subtable with a smaller index.]
+
+ Description [Finds the next subtable with a smaller index. Returns the
+ index.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddNextHigh]
+
+******************************************************************************/
+int
+cuddNextLow(
+ DdManager * table,
+ int x)
+{
+ return(x-1);
+
+} /* end of cuddNextLow */
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps two adjacent variables.]
+
+ Description [Swaps two adjacent variables. It assumes that no dead
+ nodes are present on entry to this procedure. The procedure then
+ guarantees that no dead nodes will be present when it terminates.
+ cuddSwapInPlace assumes that x &lt; y. Returns the number of keys in
+ the table if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+int
+cuddSwapInPlace(
+ DdManager * table,
+ int x,
+ int y)
+{
+ DdNodePtr *xlist, *ylist;
+ int xindex, yindex;
+ int xslots, yslots;
+ int xshift, yshift;
+ int oldxkeys, oldykeys;
+ int newxkeys, newykeys;
+ int comple, newcomplement;
+ int i;
+ Cudd_VariableType varType;
+ Cudd_LazyGroupType groupType;
+ int posn;
+ int isolated;
+ DdNode *f,*f0,*f1,*f01,*f00,*f11,*f10,*newf1,*newf0;
+ DdNode *g,*next;
+ DdNodePtr *previousP;
+ DdNode *tmp;
+ DdNode *sentinel = &(table->sentinel);
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+
+#if DD_DEBUG
+ int count,idcheck;
+#endif
+
+#ifdef DD_DEBUG
+ assert(x < y);
+ assert(cuddNextHigh(table,x) == y);
+ assert(table->subtables[x].keys != 0);
+ assert(table->subtables[y].keys != 0);
+ assert(table->subtables[x].dead == 0);
+ assert(table->subtables[y].dead == 0);
+#endif
+
+ ddTotalNumberSwapping++;
+
+ /* Get parameters of x subtable. */
+ xindex = table->invperm[x];
+ xlist = table->subtables[x].nodelist;
+ oldxkeys = table->subtables[x].keys;
+ xslots = table->subtables[x].slots;
+ xshift = table->subtables[x].shift;
+
+ /* Get parameters of y subtable. */
+ yindex = table->invperm[y];
+ ylist = table->subtables[y].nodelist;
+ oldykeys = table->subtables[y].keys;
+ yslots = table->subtables[y].slots;
+ yshift = table->subtables[y].shift;
+
+ if (!cuddTestInteract(table,xindex,yindex)) {
+#ifdef DD_STATS
+ ddTotalNISwaps++;
+#endif
+ newxkeys = oldxkeys;
+ newykeys = oldykeys;
+ } else {
+ newxkeys = 0;
+ newykeys = oldykeys;
+
+ /* Check whether the two projection functions involved in this
+ ** swap are isolated. At the end, we'll be able to tell how many
+ ** isolated projection functions are there by checking only these
+ ** two functions again. This is done to eliminate the isolated
+ ** projection functions from the node count.
+ */
+ isolated = - ((table->vars[xindex]->ref == 1) +
+ (table->vars[yindex]->ref == 1));
+
+ /* The nodes in the x layer that do not depend on
+ ** y will stay there; the others are put in a chain.
+ ** The chain is handled as a LIFO; g points to the beginning.
+ */
+ g = NULL;
+ if ((oldxkeys >= xslots || (unsigned) xslots == table->initSlots) &&
+ oldxkeys <= DD_MAX_SUBTABLE_DENSITY * xslots) {
+ for (i = 0; i < xslots; i++) {
+ previousP = &(xlist[i]);
+ f = *previousP;
+ while (f != sentinel) {
+ next = f->next;
+ f1 = cuddT(f); f0 = cuddE(f);
+ if (f1->index != (DdHalfWord) yindex &&
+ Cudd_Regular(f0)->index != (DdHalfWord) yindex) {
+ /* stays */
+ newxkeys++;
+ *previousP = f;
+ previousP = &(f->next);
+ } else {
+ f->index = yindex;
+ f->next = g;
+ g = f;
+ }
+ f = next;
+ } /* while there are elements in the collision chain */
+ *previousP = sentinel;
+ } /* for each slot of the x subtable */
+ } else { /* resize xlist */
+ DdNode *h = NULL;
+ DdNodePtr *newxlist;
+ unsigned int newxslots;
+ int newxshift;
+ /* Empty current xlist. Nodes that stay go to list h;
+ ** nodes that move go to list g. */
+ for (i = 0; i < xslots; i++) {
+ f = xlist[i];
+ while (f != sentinel) {
+ next = f->next;
+ f1 = cuddT(f); f0 = cuddE(f);
+ if (f1->index != (DdHalfWord) yindex &&
+ Cudd_Regular(f0)->index != (DdHalfWord) yindex) {
+ /* stays */
+ f->next = h;
+ h = f;
+ newxkeys++;
+ } else {
+ f->index = yindex;
+ f->next = g;
+ g = f;
+ }
+ f = next;
+ } /* while there are elements in the collision chain */
+ } /* for each slot of the x subtable */
+ /* Decide size of new subtable. */
+ if (oldxkeys > DD_MAX_SUBTABLE_DENSITY * xslots) {
+ newxshift = xshift - 1;
+ newxslots = xslots << 1;
+ } else {
+ newxshift = xshift + 1;
+ newxslots = xslots >> 1;
+ }
+ /* Try to allocate new table. Be ready to back off. */
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ newxlist = ALLOC(DdNodePtr, newxslots);
+ MMoutOfMemory = saveHandler;
+ if (newxlist == NULL) {
+ (void) fprintf(table->err, "Unable to resize subtable %d for lack of memory\n", i);
+ newxlist = xlist;
+ newxslots = xslots;
+ newxshift = xshift;
+ } else {
+ table->slots += (newxslots - xslots);
+ table->minDead = (unsigned)
+ (table->gcFrac * (double) table->slots);
+ table->cacheSlack = (int)
+ ddMin(table->maxCacheHard, DD_MAX_CACHE_TO_SLOTS_RATIO
+ * table->slots) - 2 * (int) table->cacheSlots;
+ table->memused += (newxslots - xslots) * sizeof(DdNodePtr);
+ FREE(xlist);
+ xslots = newxslots;
+ xshift = newxshift;
+ xlist = newxlist;
+ }
+ /* Initialize new subtable. */
+ for (i = 0; i < xslots; i++) {
+ xlist[i] = sentinel;
+ }
+ /* Move nodes that were parked in list h to their new home. */
+ f = h;
+ while (f != NULL) {
+ next = f->next;
+ f1 = cuddT(f);
+ f0 = cuddE(f);
+ /* Check xlist for pair (f11,f01). */
+ posn = ddHash(f1, f0, xshift);
+ /* For each element tmp in collision list xlist[posn]. */
+ previousP = &(xlist[posn]);
+ tmp = *previousP;
+ while (f1 < cuddT(tmp)) {
+ previousP = &(tmp->next);
+ tmp = *previousP;
+ }
+ while (f1 == cuddT(tmp) && f0 < cuddE(tmp)) {
+ previousP = &(tmp->next);
+ tmp = *previousP;
+ }
+ f->next = *previousP;
+ *previousP = f;
+ f = next;
+ }
+ }
+
+#ifdef DD_COUNT
+ table->swapSteps += oldxkeys - newxkeys;
+#endif
+ /* Take care of the x nodes that must be re-expressed.
+ ** They form a linked list pointed by g. Their index has been
+ ** already changed to yindex.
+ */
+ f = g;
+ while (f != NULL) {
+ next = f->next;
+ /* Find f1, f0, f11, f10, f01, f00. */
+ f1 = cuddT(f);
+#ifdef DD_DEBUG
+ assert(!(Cudd_IsComplement(f1)));
+#endif
+ if ((int) f1->index == yindex) {
+ f11 = cuddT(f1); f10 = cuddE(f1);
+ } else {
+ f11 = f10 = f1;
+ }
+#ifdef DD_DEBUG
+ assert(!(Cudd_IsComplement(f11)));
+#endif
+ f0 = cuddE(f);
+ comple = Cudd_IsComplement(f0);
+ f0 = Cudd_Regular(f0);
+ if ((int) f0->index == yindex) {
+ f01 = cuddT(f0); f00 = cuddE(f0);
+ } else {
+ f01 = f00 = f0;
+ }
+ if (comple) {
+ f01 = Cudd_Not(f01);
+ f00 = Cudd_Not(f00);
+ }
+ /* Decrease ref count of f1. */
+ cuddSatDec(f1->ref);
+ /* Create the new T child. */
+ if (f11 == f01) {
+ newf1 = f11;
+ cuddSatInc(newf1->ref);
+ } else {
+ /* Check xlist for triple (xindex,f11,f01). */
+ posn = ddHash(f11, f01, xshift);
+ /* For each element newf1 in collision list xlist[posn]. */
+ previousP = &(xlist[posn]);
+ newf1 = *previousP;
+ while (f11 < cuddT(newf1)) {
+ previousP = &(newf1->next);
+ newf1 = *previousP;
+ }
+ while (f11 == cuddT(newf1) && f01 < cuddE(newf1)) {
+ previousP = &(newf1->next);
+ newf1 = *previousP;
+ }
+ if (cuddT(newf1) == f11 && cuddE(newf1) == f01) {
+ cuddSatInc(newf1->ref);
+ } else { /* no match */
+ newf1 = cuddDynamicAllocNode(table);
+ if (newf1 == NULL)
+ goto cuddSwapOutOfMem;
+ newf1->index = xindex; newf1->ref = 1;
+ cuddT(newf1) = f11;
+ cuddE(newf1) = f01;
+ /* Insert newf1 in the collision list xlist[posn];
+ ** increase the ref counts of f11 and f01.
+ */
+ newxkeys++;
+ newf1->next = *previousP;
+ *previousP = newf1;
+ cuddSatInc(f11->ref);
+ tmp = Cudd_Regular(f01);
+ cuddSatInc(tmp->ref);
+ }
+ }
+ cuddT(f) = newf1;
+#ifdef DD_DEBUG
+ assert(!(Cudd_IsComplement(newf1)));
+#endif
+
+ /* Do the same for f0, keeping complement dots into account. */
+ /* Decrease ref count of f0. */
+ tmp = Cudd_Regular(f0);
+ cuddSatDec(tmp->ref);
+ /* Create the new E child. */
+ if (f10 == f00) {
+ newf0 = f00;
+ tmp = Cudd_Regular(newf0);
+ cuddSatInc(tmp->ref);
+ } else {
+ /* make sure f10 is regular */
+ newcomplement = Cudd_IsComplement(f10);
+ if (newcomplement) {
+ f10 = Cudd_Not(f10);
+ f00 = Cudd_Not(f00);
+ }
+ /* Check xlist for triple (xindex,f10,f00). */
+ posn = ddHash(f10, f00, xshift);
+ /* For each element newf0 in collision list xlist[posn]. */
+ previousP = &(xlist[posn]);
+ newf0 = *previousP;
+ while (f10 < cuddT(newf0)) {
+ previousP = &(newf0->next);
+ newf0 = *previousP;
+ }
+ while (f10 == cuddT(newf0) && f00 < cuddE(newf0)) {
+ previousP = &(newf0->next);
+ newf0 = *previousP;
+ }
+ if (cuddT(newf0) == f10 && cuddE(newf0) == f00) {
+ cuddSatInc(newf0->ref);
+ } else { /* no match */
+ newf0 = cuddDynamicAllocNode(table);
+ if (newf0 == NULL)
+ goto cuddSwapOutOfMem;
+ newf0->index = xindex; newf0->ref = 1;
+ cuddT(newf0) = f10;
+ cuddE(newf0) = f00;
+ /* Insert newf0 in the collision list xlist[posn];
+ ** increase the ref counts of f10 and f00.
+ */
+ newxkeys++;
+ newf0->next = *previousP;
+ *previousP = newf0;
+ cuddSatInc(f10->ref);
+ tmp = Cudd_Regular(f00);
+ cuddSatInc(tmp->ref);
+ }
+ if (newcomplement) {
+ newf0 = Cudd_Not(newf0);
+ }
+ }
+ cuddE(f) = newf0;
+
+ /* Insert the modified f in ylist.
+ ** The modified f does not already exists in ylist.
+ ** (Because of the uniqueness of the cofactors.)
+ */
+ posn = ddHash(newf1, newf0, yshift);
+ newykeys++;
+ previousP = &(ylist[posn]);
+ tmp = *previousP;
+ while (newf1 < cuddT(tmp)) {
+ previousP = &(tmp->next);
+ tmp = *previousP;
+ }
+ while (newf1 == cuddT(tmp) && newf0 < cuddE(tmp)) {
+ previousP = &(tmp->next);
+ tmp = *previousP;
+ }
+ f->next = *previousP;
+ *previousP = f;
+ f = next;
+ } /* while f != NULL */
+
+ /* GC the y layer. */
+
+ /* For each node f in ylist. */
+ for (i = 0; i < yslots; i++) {
+ previousP = &(ylist[i]);
+ f = *previousP;
+ while (f != sentinel) {
+ next = f->next;
+ if (f->ref == 0) {
+ tmp = cuddT(f);
+ cuddSatDec(tmp->ref);
+ tmp = Cudd_Regular(cuddE(f));
+ cuddSatDec(tmp->ref);
+ cuddDeallocNode(table,f);
+ newykeys--;
+ } else {
+ *previousP = f;
+ previousP = &(f->next);
+ }
+ f = next;
+ } /* while f */
+ *previousP = sentinel;
+ } /* for i */
+
+#if DD_DEBUG
+#if 0
+ (void) fprintf(table->out,"Swapping %d and %d\n",x,y);
+#endif
+ count = 0;
+ idcheck = 0;
+ for (i = 0; i < yslots; i++) {
+ f = ylist[i];
+ while (f != sentinel) {
+ count++;
+ if (f->index != (DdHalfWord) yindex)
+ idcheck++;
+ f = f->next;
+ }
+ }
+ if (count != newykeys) {
+ (void) fprintf(table->out,
+ "Error in finding newykeys\toldykeys = %d\tnewykeys = %d\tactual = %d\n",
+ oldykeys,newykeys,count);
+ }
+ if (idcheck != 0)
+ (void) fprintf(table->out,
+ "Error in id's of ylist\twrong id's = %d\n",
+ idcheck);
+ count = 0;
+ idcheck = 0;
+ for (i = 0; i < xslots; i++) {
+ f = xlist[i];
+ while (f != sentinel) {
+ count++;
+ if (f->index != (DdHalfWord) xindex)
+ idcheck++;
+ f = f->next;
+ }
+ }
+ if (count != newxkeys) {
+ (void) fprintf(table->out,
+ "Error in finding newxkeys\toldxkeys = %d \tnewxkeys = %d \tactual = %d\n",
+ oldxkeys,newxkeys,count);
+ }
+ if (idcheck != 0)
+ (void) fprintf(table->out,
+ "Error in id's of xlist\twrong id's = %d\n",
+ idcheck);
+#endif
+
+ isolated += (table->vars[xindex]->ref == 1) +
+ (table->vars[yindex]->ref == 1);
+ table->isolated += isolated;
+ }
+
+ /* Set the appropriate fields in table. */
+ table->subtables[x].nodelist = ylist;
+ table->subtables[x].slots = yslots;
+ table->subtables[x].shift = yshift;
+ table->subtables[x].keys = newykeys;
+ table->subtables[x].maxKeys = yslots * DD_MAX_SUBTABLE_DENSITY;
+ i = table->subtables[x].bindVar;
+ table->subtables[x].bindVar = table->subtables[y].bindVar;
+ table->subtables[y].bindVar = i;
+ /* Adjust filds for lazy sifting. */
+ varType = table->subtables[x].varType;
+ table->subtables[x].varType = table->subtables[y].varType;
+ table->subtables[y].varType = varType;
+ i = table->subtables[x].pairIndex;
+ table->subtables[x].pairIndex = table->subtables[y].pairIndex;
+ table->subtables[y].pairIndex = i;
+ i = table->subtables[x].varHandled;
+ table->subtables[x].varHandled = table->subtables[y].varHandled;
+ table->subtables[y].varHandled = i;
+ groupType = table->subtables[x].varToBeGrouped;
+ table->subtables[x].varToBeGrouped = table->subtables[y].varToBeGrouped;
+ table->subtables[y].varToBeGrouped = groupType;
+
+ table->subtables[y].nodelist = xlist;
+ table->subtables[y].slots = xslots;
+ table->subtables[y].shift = xshift;
+ table->subtables[y].keys = newxkeys;
+ table->subtables[y].maxKeys = xslots * DD_MAX_SUBTABLE_DENSITY;
+
+ table->perm[xindex] = y; table->perm[yindex] = x;
+ table->invperm[x] = yindex; table->invperm[y] = xindex;
+
+ table->keys += newxkeys + newykeys - oldxkeys - oldykeys;
+
+ return(table->keys - table->isolated);
+
+cuddSwapOutOfMem:
+ (void) fprintf(table->err,"Error: cuddSwapInPlace out of memory\n");
+
+ return (0);
+
+} /* end of cuddSwapInPlace */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders BDD variables according to the order of the ZDD
+ variables.]
+
+ Description [Reorders BDD variables according to the order of the
+ ZDD variables. This function can be called at the end of ZDD
+ reordering to insure that the order of the BDD variables is
+ consistent with the order of the ZDD variables. The number of ZDD
+ variables must be a multiple of the number of BDD variables. Let
+ <code>M</code> be the ratio of the two numbers. cuddBddAlignToZdd
+ then considers the ZDD variables from <code>M*i</code> to
+ <code>(M+1)*i-1</code> as corresponding to BDD variable
+ <code>i</code>. This function should be normally called from
+ Cudd_zddReduceHeap, which clears the cache. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [Changes the BDD variable order for all diagrams and performs
+ garbage collection of the BDD unique table.]
+
+ SeeAlso [Cudd_ShuffleHeap Cudd_zddReduceHeap]
+
+******************************************************************************/
+int
+cuddBddAlignToZdd(
+ DdManager * table /* DD manager */)
+{
+ int *invperm; /* permutation array */
+ int M; /* ratio of ZDD variables to BDD variables */
+ int i; /* loop index */
+ int result; /* return value */
+
+ /* We assume that a ratio of 0 is OK. */
+ if (table->size == 0)
+ return(1);
+
+ M = table->sizeZ / table->size;
+ /* Check whether the number of ZDD variables is a multiple of the
+ ** number of BDD variables.
+ */
+ if (M * table->size != table->sizeZ)
+ return(0);
+ /* Create and initialize the inverse permutation array. */
+ invperm = ALLOC(int,table->size);
+ if (invperm == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (i = 0; i < table->sizeZ; i += M) {
+ int indexZ = table->invpermZ[i];
+ int index = indexZ / M;
+ invperm[i / M] = index;
+ }
+ /* Eliminate dead nodes. Do not scan the cache again, because we
+ ** assume that Cudd_zddReduceHeap has already cleared it.
+ */
+ cuddGarbageCollect(table,0);
+
+ /* Initialize number of isolated projection functions. */
+ table->isolated = 0;
+ for (i = 0; i < table->size; i++) {
+ if (table->vars[i]->ref == 1) table->isolated++;
+ }
+
+ /* Initialize the interaction matrix. */
+ result = cuddInitInteract(table);
+ if (result == 0) return(0);
+
+ result = ddShuffle(table, invperm);
+ FREE(invperm);
+ /* Free interaction matrix. */
+ FREE(table->interact);
+ /* Fix the BDD variable group tree. */
+ bddFixTree(table,table->tree);
+ return(result);
+
+} /* end of cuddBddAlignToZdd */
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Comparison function used by qsort.]
+
+ Description [Comparison function used by qsort to order the
+ variables according to the number of keys in the subtables.
+ Returns the difference in number of keys between the two
+ variables being compared.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddUniqueCompare(
+ int * ptrX,
+ int * ptrY)
+{
+#if 0
+ if (entry[*ptrY] == entry[*ptrX]) {
+ return((*ptrX) - (*ptrY));
+ }
+#endif
+ return(entry[*ptrY] - entry[*ptrX]);
+
+} /* end of ddUniqueCompare */
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps any two variables.]
+
+ Description [Swaps any two variables. Returns the set of moves.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static Move *
+ddSwapAny(
+ DdManager * table,
+ int x,
+ int y)
+{
+ Move *move, *moves;
+ int xRef,yRef;
+ int xNext,yNext;
+ int size;
+ int limitSize;
+ int tmp;
+
+ if (x >y) {
+ tmp = x; x = y; y = tmp;
+ }
+
+ xRef = x; yRef = y;
+
+ xNext = cuddNextHigh(table,x);
+ yNext = cuddNextLow(table,y);
+ moves = NULL;
+ limitSize = table->keys - table->isolated;
+
+ for (;;) {
+ if ( xNext == yNext) {
+ size = cuddSwapInPlace(table,x,xNext);
+ if (size == 0) goto ddSwapAnyOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddSwapAnyOutOfMem;
+ move->x = x;
+ move->y = xNext;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ size = cuddSwapInPlace(table,yNext,y);
+ if (size == 0) goto ddSwapAnyOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddSwapAnyOutOfMem;
+ move->x = yNext;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ size = cuddSwapInPlace(table,x,xNext);
+ if (size == 0) goto ddSwapAnyOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddSwapAnyOutOfMem;
+ move->x = x;
+ move->y = xNext;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ tmp = x; x = y; y = tmp;
+
+ } else if (x == yNext) {
+
+ size = cuddSwapInPlace(table,x,xNext);
+ if (size == 0) goto ddSwapAnyOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddSwapAnyOutOfMem;
+ move->x = x;
+ move->y = xNext;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ tmp = x; x = y; y = tmp;
+
+ } else {
+ size = cuddSwapInPlace(table,x,xNext);
+ if (size == 0) goto ddSwapAnyOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddSwapAnyOutOfMem;
+ move->x = x;
+ move->y = xNext;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ size = cuddSwapInPlace(table,yNext,y);
+ if (size == 0) goto ddSwapAnyOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddSwapAnyOutOfMem;
+ move->x = yNext;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ x = xNext;
+ y = yNext;
+ }
+
+ xNext = cuddNextHigh(table,x);
+ yNext = cuddNextLow(table,y);
+ if (xNext > yRef) break;
+
+ if ((double) size > table->maxGrowth * (double) limitSize) break;
+ if (size < limitSize) limitSize = size;
+ }
+ if (yNext>=xRef) {
+ size = cuddSwapInPlace(table,yNext,y);
+ if (size == 0) goto ddSwapAnyOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddSwapAnyOutOfMem;
+ move->x = yNext;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ }
+
+ return(moves);
+
+ddSwapAnyOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return(NULL);
+
+} /* end of ddSwapAny */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries.]
+
+ Description [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries. Finds the best position and does the required changes.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddSiftingAux(
+ DdManager * table,
+ int x,
+ int xLow,
+ int xHigh)
+{
+
+ Move *move;
+ Move *moveUp; /* list of up moves */
+ Move *moveDown; /* list of down moves */
+ int initialSize;
+ int result;
+
+ initialSize = table->keys - table->isolated;
+
+ moveDown = NULL;
+ moveUp = NULL;
+
+ if (x == xLow) {
+ moveDown = ddSiftingDown(table,x,xHigh);
+ /* At this point x --> xHigh unless bounding occurred. */
+ if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem;
+ /* Move backward and stop at best position. */
+ result = ddSiftingBackward(table,initialSize,moveDown);
+ if (!result) goto ddSiftingAuxOutOfMem;
+
+ } else if (x == xHigh) {
+ moveUp = ddSiftingUp(table,x,xLow);
+ /* At this point x --> xLow unless bounding occurred. */
+ if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem;
+ /* Move backward and stop at best position. */
+ result = ddSiftingBackward(table,initialSize,moveUp);
+ if (!result) goto ddSiftingAuxOutOfMem;
+
+ } else if ((x - xLow) > (xHigh - x)) { /* must go down first: shorter */
+ moveDown = ddSiftingDown(table,x,xHigh);
+ /* At this point x --> xHigh unless bounding occurred. */
+ if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem;
+ if (moveDown != NULL) {
+ x = moveDown->y;
+ }
+ moveUp = ddSiftingUp(table,x,xLow);
+ if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem;
+ /* Move backward and stop at best position */
+ result = ddSiftingBackward(table,initialSize,moveUp);
+ if (!result) goto ddSiftingAuxOutOfMem;
+
+ } else { /* must go up first: shorter */
+ moveUp = ddSiftingUp(table,x,xLow);
+ /* At this point x --> xLow unless bounding occurred. */
+ if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem;
+ if (moveUp != NULL) {
+ x = moveUp->x;
+ }
+ moveDown = ddSiftingDown(table,x,xHigh);
+ if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem;
+ /* Move backward and stop at best position. */
+ result = ddSiftingBackward(table,initialSize,moveDown);
+ if (!result) goto ddSiftingAuxOutOfMem;
+ }
+
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *) moveDown);
+ moveDown = move;
+ }
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *) moveUp);
+ moveUp = move;
+ }
+
+ return(1);
+
+ddSiftingAuxOutOfMem:
+ if (moveDown != (Move *) CUDD_OUT_OF_MEM) {
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *) moveDown);
+ moveDown = move;
+ }
+ }
+ if (moveUp != (Move *) CUDD_OUT_OF_MEM) {
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *) moveUp);
+ moveUp = move;
+ }
+ }
+
+ return(0);
+
+} /* end of ddSiftingAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts a variable up.]
+
+ Description [Sifts a variable up. Moves y up until either it reaches
+ the bound (xLow) or the size of the DD heap increases too much.
+ Returns the set of moves in case of success; NULL if memory is full.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static Move *
+ddSiftingUp(
+ DdManager * table,
+ int y,
+ int xLow)
+{
+ Move *moves;
+ Move *move;
+ int x;
+ int size;
+ int limitSize;
+ int xindex, yindex;
+ int isolated;
+ int L; /* lower bound on DD size */
+#ifdef DD_DEBUG
+ int checkL;
+ int z;
+ int zindex;
+#endif
+
+ moves = NULL;
+ yindex = table->invperm[y];
+
+ /* Initialize the lower bound.
+ ** The part of the DD below y will not change.
+ ** The part of the DD above y that does not interact with y will not
+ ** change. The rest may vanish in the best case, except for
+ ** the nodes at level xLow, which will not vanish, regardless.
+ */
+ limitSize = L = table->keys - table->isolated;
+ for (x = xLow + 1; x < y; x++) {
+ xindex = table->invperm[x];
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[xindex]->ref == 1;
+ L -= table->subtables[x].keys - isolated;
+ }
+ }
+ isolated = table->vars[yindex]->ref == 1;
+ L -= table->subtables[y].keys - isolated;
+
+ x = cuddNextLow(table,y);
+ while (x >= xLow && L <= limitSize) {
+ xindex = table->invperm[x];
+#ifdef DD_DEBUG
+ checkL = table->keys - table->isolated;
+ for (z = xLow + 1; z < y; z++) {
+ zindex = table->invperm[z];
+ if (cuddTestInteract(table,zindex,yindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ checkL -= table->subtables[z].keys - isolated;
+ }
+ }
+ isolated = table->vars[yindex]->ref == 1;
+ checkL -= table->subtables[y].keys - isolated;
+ assert(L == checkL);
+#endif
+ size = cuddSwapInPlace(table,x,y);
+ if (size == 0) goto ddSiftingUpOutOfMem;
+ /* Update the lower bound. */
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[xindex]->ref == 1;
+ L += table->subtables[y].keys - isolated;
+ }
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddSiftingUpOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ if ((double) size > (double) limitSize * table->maxGrowth) break;
+ if (size < limitSize) limitSize = size;
+ y = x;
+ x = cuddNextLow(table,y);
+ }
+ return(moves);
+
+ddSiftingUpOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return((Move *) CUDD_OUT_OF_MEM);
+
+} /* end of ddSiftingUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts a variable down.]
+
+ Description [Sifts a variable down. Moves x down until either it
+ reaches the bound (xHigh) or the size of the DD heap increases too
+ much. Returns the set of moves in case of success; NULL if memory is
+ full.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static Move *
+ddSiftingDown(
+ DdManager * table,
+ int x,
+ int xHigh)
+{
+ Move *moves;
+ Move *move;
+ int y;
+ int size;
+ int R; /* upper bound on node decrease */
+ int limitSize;
+ int xindex, yindex;
+ int isolated;
+#ifdef DD_DEBUG
+ int checkR;
+ int z;
+ int zindex;
+#endif
+
+ moves = NULL;
+ /* Initialize R */
+ xindex = table->invperm[x];
+ limitSize = size = table->keys - table->isolated;
+ R = 0;
+ for (y = xHigh; y > x; y--) {
+ yindex = table->invperm[y];
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[yindex]->ref == 1;
+ R += table->subtables[y].keys - isolated;
+ }
+ }
+
+ y = cuddNextHigh(table,x);
+ while (y <= xHigh && size - R < limitSize) {
+#ifdef DD_DEBUG
+ checkR = 0;
+ for (z = xHigh; z > x; z--) {
+ zindex = table->invperm[z];
+ if (cuddTestInteract(table,xindex,zindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ checkR += table->subtables[z].keys - isolated;
+ }
+ }
+ assert(R == checkR);
+#endif
+ /* Update upper bound on node decrease. */
+ yindex = table->invperm[y];
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[yindex]->ref == 1;
+ R -= table->subtables[y].keys - isolated;
+ }
+ size = cuddSwapInPlace(table,x,y);
+ if (size == 0) goto ddSiftingDownOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddSiftingDownOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ if ((double) size > (double) limitSize * table->maxGrowth) break;
+ if (size < limitSize) limitSize = size;
+ x = y;
+ y = cuddNextHigh(table,x);
+ }
+ return(moves);
+
+ddSiftingDownOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return((Move *) CUDD_OUT_OF_MEM);
+
+} /* end of ddSiftingDown */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given a set of moves, returns the DD heap to the position
+ giving the minimum size.]
+
+ Description [Given a set of moves, returns the DD heap to the
+ position giving the minimum size. In case of ties, returns to the
+ closest position giving the minimum size. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddSiftingBackward(
+ DdManager * table,
+ int size,
+ Move * moves)
+{
+ Move *move;
+ int res;
+
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size < size) {
+ size = move->size;
+ }
+ }
+
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size == size) return(1);
+ res = cuddSwapInPlace(table,(int)move->x,(int)move->y);
+ if (!res) return(0);
+ }
+
+ return(1);
+
+} /* end of ddSiftingBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prepares the DD heap for dynamic reordering.]
+
+ Description [Prepares the DD heap for dynamic reordering. Does
+ garbage collection, to guarantee that there are no dead nodes;
+ clears the cache, which is invalidated by dynamic reordering; initializes
+ the number of isolated projection functions; and initializes the
+ interaction matrix. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddReorderPreprocess(
+ DdManager * table)
+{
+ int i;
+ int res;
+
+ /* Clear the cache. */
+ cuddCacheFlush(table);
+ cuddLocalCacheClearAll(table);
+
+ /* Eliminate dead nodes. Do not scan the cache again. */
+ cuddGarbageCollect(table,0);
+
+ /* Initialize number of isolated projection functions. */
+ table->isolated = 0;
+ for (i = 0; i < table->size; i++) {
+ if (table->vars[i]->ref == 1) table->isolated++;
+ }
+
+ /* Initialize the interaction matrix. */
+ res = cuddInitInteract(table);
+ if (res == 0) return(0);
+
+ return(1);
+
+} /* end of ddReorderPreprocess */
+
+
+/**Function********************************************************************
+
+ Synopsis [Cleans up at the end of reordering.]
+
+ Description []
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddReorderPostprocess(
+ DdManager * table)
+{
+
+#ifdef DD_VERBOSE
+ (void) fflush(table->out);
+#endif
+
+ /* Free interaction matrix. */
+ FREE(table->interact);
+
+ return(1);
+
+} /* end of ddReorderPostprocess */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders variables according to a given permutation.]
+
+ Description [Reorders variables according to a given permutation.
+ The i-th permutation array contains the index of the variable that
+ should be brought to the i-th level. ddShuffle assumes that no
+ dead nodes are present and that the interaction matrix is properly
+ initialized. The reordering is achieved by a series of upward sifts.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddShuffle(
+ DdManager * table,
+ int * permutation)
+{
+ int index;
+ int level;
+ int position;
+ int numvars;
+ int result;
+#ifdef DD_STATS
+ long localTime;
+ int initialSize;
+ int finalSize;
+ int previousSize;
+#endif
+
+ ddTotalNumberSwapping = 0;
+#ifdef DD_STATS
+ localTime = util_cpu_time();
+ initialSize = table->keys - table->isolated;
+ (void) fprintf(table->out,"#:I_SHUFFLE %8d: initial size\n",
+ initialSize);
+ ddTotalNISwaps = 0;
+#endif
+
+ numvars = table->size;
+
+ for (level = 0; level < numvars; level++) {
+ index = permutation[level];
+ position = table->perm[index];
+#ifdef DD_STATS
+ previousSize = table->keys - table->isolated;
+#endif
+ result = ddSiftUp(table,position,level);
+ if (!result) return(0);
+#ifdef DD_STATS
+ if (table->keys < (unsigned) previousSize + table->isolated) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keys > (unsigned) previousSize + table->isolated) {
+ (void) fprintf(table->out,"+"); /* should never happen */
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n");
+ finalSize = table->keys - table->isolated;
+ (void) fprintf(table->out,"#:F_SHUFFLE %8d: final size\n",finalSize);
+ (void) fprintf(table->out,"#:T_SHUFFLE %8g: total time (sec)\n",
+ ((double)(util_cpu_time() - localTime)/1000.0));
+ (void) fprintf(table->out,"#:N_SHUFFLE %8d: total swaps\n",
+ ddTotalNumberSwapping);
+ (void) fprintf(table->out,"#:M_SHUFFLE %8d: NI swaps\n",ddTotalNISwaps);
+#endif
+
+ return(1);
+
+} /* end of ddShuffle */
+
+
+/**Function********************************************************************
+
+ Synopsis [Moves one variable up.]
+
+ Description [Takes a variable from position x and sifts it up to
+ position xLow; xLow should be less than or equal to x.
+ Returns 1 if successful; 0 otherwise]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddSiftUp(
+ DdManager * table,
+ int x,
+ int xLow)
+{
+ int y;
+ int size;
+
+ y = cuddNextLow(table,x);
+ while (y >= xLow) {
+ size = cuddSwapInPlace(table,y,x);
+ if (size == 0) {
+ return(0);
+ }
+ x = y;
+ y = cuddNextLow(table,x);
+ }
+ return(1);
+
+} /* end of ddSiftUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Fixes the BDD variable group tree after a shuffle.]
+
+ Description [Fixes the BDD variable group tree after a
+ shuffle. Assumes that the order of the variables in a terminal node
+ has not been changed.]
+
+ SideEffects [Changes the BDD variable group tree.]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+bddFixTree(
+ DdManager * table,
+ MtrNode * treenode)
+{
+ if (treenode == NULL) return;
+ treenode->low = ((int) treenode->index < table->size) ?
+ table->perm[treenode->index] : treenode->index;
+ if (treenode->child != NULL) {
+ bddFixTree(table, treenode->child);
+ }
+ if (treenode->younger != NULL)
+ bddFixTree(table, treenode->younger);
+ if (treenode->parent != NULL && treenode->low < treenode->parent->low) {
+ treenode->parent->low = treenode->low;
+ treenode->parent->index = treenode->index;
+ }
+ return;
+
+} /* end of bddFixTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Updates the BDD variable group tree before a shuffle.]
+
+ Description [Updates the BDD variable group tree before a shuffle.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [Changes the BDD variable group tree.]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddUpdateMtrTree(
+ DdManager * table,
+ MtrNode * treenode,
+ int * perm,
+ int * invperm)
+{
+ int i, size, index, level;
+ int minLevel, maxLevel, minIndex;
+
+ if (treenode == NULL) return(1);
+
+ /* i : level */
+ for (i = treenode->low; i < treenode->low + treenode->size; i++) {
+ index = table->invperm[i];
+ level = perm[index];
+ if (level < minLevel) {
+ minLevel = level;
+ minIndex = index;
+ }
+ if (level > maxLevel)
+ maxLevel = level;
+ }
+ size = maxLevel - minLevel + 1;
+ if (size == treenode->size) {
+ treenode->low = minLevel;
+ treenode->index = minIndex;
+ } else
+ return(0);
+
+ if (treenode->child != NULL) {
+ if (!ddUpdateMtrTree(table, treenode->child, perm, invperm))
+ return(0);
+ }
+ if (treenode->younger != NULL) {
+ if (!ddUpdateMtrTree(table, treenode->younger, perm, invperm))
+ return(0);
+ }
+ return(1);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks the BDD variable group tree before a shuffle.]
+
+ Description [Checks the BDD variable group tree before a shuffle.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [Changes the BDD variable group tree.]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddCheckPermuation(
+ DdManager * table,
+ MtrNode * treenode,
+ int * perm,
+ int * invperm)
+{
+ int i, size, index, level;
+ int minLevel, maxLevel;
+
+ if (treenode == NULL) return(1);
+
+ minLevel = table->size;
+ maxLevel = 0;
+ /* i : level */
+ for (i = treenode->low; i < treenode->low + treenode->size; i++) {
+ index = table->invperm[i];
+ level = perm[index];
+ if (level < minLevel)
+ minLevel = level;
+ if (level > maxLevel)
+ maxLevel = level;
+ }
+ size = maxLevel - minLevel + 1;
+ if (size != treenode->size)
+ return(0);
+
+ if (treenode->child != NULL) {
+ if (!ddCheckPermuation(table, treenode->child, perm, invperm))
+ return(0);
+ }
+ if (treenode->younger != NULL) {
+ if (!ddCheckPermuation(table, treenode->younger, perm, invperm))
+ return(0);
+ }
+ return(1);
+}
diff --git a/src/bdd/cudd/cuddSat.c b/src/bdd/cudd/cuddSat.c
new file mode 100644
index 00000000..dde33a5b
--- /dev/null
+++ b/src/bdd/cudd/cuddSat.c
@@ -0,0 +1,1305 @@
+/**CFile***********************************************************************
+
+ FileName [cuddSat.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for the solution of satisfiability related
+ problems.]
+
+ Description [External procedures included in this file:
+ <ul>
+ <li> Cudd_Eval()
+ <li> Cudd_ShortestPath()
+ <li> Cudd_LargestCube()
+ <li> Cudd_ShortestLength()
+ <li> Cudd_Decreasing()
+ <li> Cudd_Increasing()
+ <li> Cudd_EquivDC()
+ <li> Cudd_bddLeqUnless()
+ <li> Cudd_EqualSupNorm()
+ <li> Cudd_bddMakePrime()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddBddMakePrime()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> freePathPair()
+ <li> getShortest()
+ <li> getPath()
+ <li> getLargest()
+ <li> getCube()
+ </ul>]
+
+ Author [Seh-Woong Jeong, Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define DD_BIGGY 1000000
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+typedef struct cuddPathPair {
+ int pos;
+ int neg;
+} cuddPathPair;
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddSat.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+static DdNode *one, *zero;
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+#define WEIGHT(weight, col) ((weight) == NULL ? 1 : weight[col])
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static enum st_retval freePathPair ARGS((char *key, char *value, char *arg));
+static cuddPathPair getShortest ARGS((DdNode *root, int *cost, int *support, st_table *visited));
+static DdNode * getPath ARGS((DdManager *manager, st_table *visited, DdNode *f, int *weight, int cost));
+static cuddPathPair getLargest ARGS((DdNode *root, st_table *visited));
+static DdNode * getCube ARGS((DdManager *manager, st_table *visited, DdNode *f, int cost));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the value of a DD for a given variable assignment.]
+
+ Description [Finds the value of a DD for a given variable
+ assignment. The variable assignment is passed in an array of int's,
+ that should specify a zero or a one for each variable in the support
+ of the function. Returns a pointer to a constant node. No new nodes
+ are produced.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLeq Cudd_addEvalConst]
+
+******************************************************************************/
+DdNode *
+Cudd_Eval(
+ DdManager * dd,
+ DdNode * f,
+ int * inputs)
+{
+ int comple;
+ DdNode *ptr;
+
+ comple = Cudd_IsComplement(f);
+ ptr = Cudd_Regular(f);
+
+ while (!cuddIsConstant(ptr)) {
+ if (inputs[ptr->index] == 1) {
+ ptr = cuddT(ptr);
+ } else {
+ comple ^= Cudd_IsComplement(cuddE(ptr));
+ ptr = Cudd_Regular(cuddE(ptr));
+ }
+ }
+ return(Cudd_NotCond(ptr,comple));
+
+} /* end of Cudd_Eval */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds a shortest path in a DD.]
+
+ Description [Finds a shortest path in a DD. f is the DD we want to
+ get the shortest path for; weight\[i\] is the weight of the THEN arc
+ coming from the node whose index is i. If weight is NULL, then unit
+ weights are assumed for all THEN arcs. All ELSE arcs have 0 weight.
+ If non-NULL, both weight and support should point to arrays with at
+ least as many entries as there are variables in the manager.
+ Returns the shortest path as the BDD of a cube.]
+
+ SideEffects [support contains on return the true support of f.
+ If support is NULL on entry, then Cudd_ShortestPath does not compute
+ the true support info. length contains the length of the path.]
+
+ SeeAlso [Cudd_ShortestLength Cudd_LargestCube]
+
+******************************************************************************/
+DdNode *
+Cudd_ShortestPath(
+ DdManager * manager,
+ DdNode * f,
+ int * weight,
+ int * support,
+ int * length)
+{
+ register DdNode *F;
+ st_table *visited;
+ DdNode *sol;
+ cuddPathPair *rootPair;
+ int complement, cost;
+ int i;
+
+ one = DD_ONE(manager);
+ zero = DD_ZERO(manager);
+
+ /* Initialize support. */
+ if (support) {
+ for (i = 0; i < manager->size; i++) {
+ support[i] = 0;
+ }
+ }
+
+ if (f == Cudd_Not(one) || f == zero) {
+ *length = DD_BIGGY;
+ return(Cudd_Not(one));
+ }
+ /* From this point on, a path exists. */
+
+ /* Initialize visited table. */
+ visited = st_init_table(st_ptrcmp, st_ptrhash);
+
+ /* Now get the length of the shortest path(s) from f to 1. */
+ (void) getShortest(f, weight, support, visited);
+
+ complement = Cudd_IsComplement(f);
+
+ F = Cudd_Regular(f);
+
+ st_lookup(visited, (char *)F, (char **)&rootPair);
+
+ if (complement) {
+ cost = rootPair->neg;
+ } else {
+ cost = rootPair->pos;
+ }
+
+ /* Recover an actual shortest path. */
+ do {
+ manager->reordered = 0;
+ sol = getPath(manager,visited,f,weight,cost);
+ } while (manager->reordered == 1);
+
+ st_foreach(visited, freePathPair, NULL);
+ st_free_table(visited);
+
+ *length = cost;
+ return(sol);
+
+} /* end of Cudd_ShortestPath */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds a largest cube in a DD.]
+
+ Description [Finds a largest cube in a DD. f is the DD we want to
+ get the largest cube for. The problem is translated into the one of
+ finding a shortest path in f, when both THEN and ELSE arcs are assumed to
+ have unit length. This yields a largest cube in the disjoint cover
+ corresponding to the DD. Therefore, it is not necessarily the largest
+ implicant of f. Returns the largest cube as a BDD.]
+
+ SideEffects [The number of literals of the cube is returned in length.]
+
+ SeeAlso [Cudd_ShortestPath]
+
+******************************************************************************/
+DdNode *
+Cudd_LargestCube(
+ DdManager * manager,
+ DdNode * f,
+ int * length)
+{
+ register DdNode *F;
+ st_table *visited;
+ DdNode *sol;
+ cuddPathPair *rootPair;
+ int complement, cost;
+
+ one = DD_ONE(manager);
+ zero = DD_ZERO(manager);
+
+ if (f == Cudd_Not(one) || f == zero) {
+ *length = DD_BIGGY;
+ return(Cudd_Not(one));
+ }
+ /* From this point on, a path exists. */
+
+ /* Initialize visited table. */
+ visited = st_init_table(st_ptrcmp, st_ptrhash);
+
+ /* Now get the length of the shortest path(s) from f to 1. */
+ (void) getLargest(f, visited);
+
+ complement = Cudd_IsComplement(f);
+
+ F = Cudd_Regular(f);
+
+ st_lookup(visited, (char *)F, (char **)&rootPair);
+
+ if (complement) {
+ cost = rootPair->neg;
+ } else {
+ cost = rootPair->pos;
+ }
+
+ /* Recover an actual shortest path. */
+ do {
+ manager->reordered = 0;
+ sol = getCube(manager,visited,f,cost);
+ } while (manager->reordered == 1);
+
+ st_foreach(visited, freePathPair, NULL);
+ st_free_table(visited);
+
+ *length = cost;
+ return(sol);
+
+} /* end of Cudd_LargestCube */
+
+
+/**Function********************************************************************
+
+ Synopsis [Find the length of the shortest path(s) in a DD.]
+
+ Description [Find the length of the shortest path(s) in a DD. f is
+ the DD we want to get the shortest path for; weight\[i\] is the
+ weight of the THEN edge coming from the node whose index is i. All
+ ELSE edges have 0 weight. Returns the length of the shortest
+ path(s) if successful; CUDD_OUT_OF_MEM otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ShortestPath]
+
+******************************************************************************/
+int
+Cudd_ShortestLength(
+ DdManager * manager,
+ DdNode * f,
+ int * weight)
+{
+ register DdNode *F;
+ st_table *visited;
+ cuddPathPair *my_pair;
+ int complement, cost;
+
+ one = DD_ONE(manager);
+ zero = DD_ZERO(manager);
+
+ if (f == Cudd_Not(one) || f == zero) {
+ return(DD_BIGGY);
+ }
+
+ /* From this point on, a path exists. */
+ /* Initialize visited table and support. */
+ visited = st_init_table(st_ptrcmp, st_ptrhash);
+
+ /* Now get the length of the shortest path(s) from f to 1. */
+ (void) getShortest(f, weight, NULL, visited);
+
+ complement = Cudd_IsComplement(f);
+
+ F = Cudd_Regular(f);
+
+ st_lookup(visited, (char *)F, (char **)&my_pair);
+
+ if (complement) {
+ cost = my_pair->neg;
+ } else {
+ cost = my_pair->pos;
+ }
+
+ st_foreach(visited, freePathPair, NULL);
+ st_free_table(visited);
+
+ return(cost);
+
+} /* end of Cudd_ShortestLength */
+
+
+/**Function********************************************************************
+
+ Synopsis [Determines whether a BDD is negative unate in a
+ variable.]
+
+ Description [Determines whether the function represented by BDD f is
+ negative unate (monotonic decreasing) in variable i. Returns the
+ constant one is f is unate and the (logical) constant zero if it is not.
+ This function does not generate any new nodes.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Increasing]
+
+******************************************************************************/
+DdNode *
+Cudd_Decreasing(
+ DdManager * dd,
+ DdNode * f,
+ int i)
+{
+ unsigned int topf, level;
+ DdNode *F, *fv, *fvn, *res;
+ DdNode *(*cacheOp)(DdManager *, DdNode *, DdNode *);
+
+ statLine(dd);
+#ifdef DD_DEBUG
+ assert(0 <= i && i < dd->size);
+#endif
+
+ F = Cudd_Regular(f);
+ topf = cuddI(dd,F->index);
+
+ /* Check terminal case. If topf > i, f does not depend on var.
+ ** Therefore, f is unate in i.
+ */
+ level = (unsigned) dd->perm[i];
+ if (topf > level) {
+ return(DD_ONE(dd));
+ }
+
+ /* From now on, f is not constant. */
+
+ /* Check cache. */
+ cacheOp = (DdNode *(*)(DdManager *, DdNode *, DdNode *)) Cudd_Decreasing;
+ res = cuddCacheLookup2(dd,cacheOp,f,dd->vars[i]);
+ if (res != NULL) {
+ return(res);
+ }
+
+ /* Compute cofactors. */
+ fv = cuddT(F); fvn = cuddE(F);
+ if (F != f) {
+ fv = Cudd_Not(fv);
+ fvn = Cudd_Not(fvn);
+ }
+
+ if (topf == (unsigned) level) {
+ /* Special case: if fv is regular, fv(1,...,1) = 1;
+ ** If in addition fvn is complemented, fvn(1,...,1) = 0.
+ ** But then f(1,1,...,1) > f(0,1,...,1). Hence f is not
+ ** monotonic decreasing in i.
+ */
+ if (!Cudd_IsComplement(fv) && Cudd_IsComplement(fvn)) {
+ return(Cudd_Not(DD_ONE(dd)));
+ }
+ res = Cudd_bddLeq(dd,fv,fvn) ? DD_ONE(dd) : Cudd_Not(DD_ONE(dd));
+ } else {
+ res = Cudd_Decreasing(dd,fv,i);
+ if (res == DD_ONE(dd)) {
+ res = Cudd_Decreasing(dd,fvn,i);
+ }
+ }
+
+ cuddCacheInsert2(dd,cacheOp,f,dd->vars[i],res);
+ return(res);
+
+} /* end of Cudd_Decreasing */
+
+
+/**Function********************************************************************
+
+ Synopsis [Determines whether a BDD is positive unate in a
+ variable.]
+
+ Description [Determines whether the function represented by BDD f is
+ positive unate (monotonic decreasing) in variable i. It is based on
+ Cudd_Decreasing and the fact that f is monotonic increasing in i if
+ and only if its complement is monotonic decreasing in i.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Decreasing]
+
+******************************************************************************/
+DdNode *
+Cudd_Increasing(
+ DdManager * dd,
+ DdNode * f,
+ int i)
+{
+ return(Cudd_Decreasing(dd,Cudd_Not(f),i));
+
+} /* end of Cudd_Increasing */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tells whether F and G are identical wherever D is 0.]
+
+ Description [Tells whether F and G are identical wherever D is 0. F
+ and G are either two ADDs or two BDDs. D is either a 0-1 ADD or a
+ BDD. The function returns 1 if F and G are equivalent, and 0
+ otherwise. No new nodes are created.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLeqUnless]
+
+******************************************************************************/
+int
+Cudd_EquivDC(
+ DdManager * dd,
+ DdNode * F,
+ DdNode * G,
+ DdNode * D)
+{
+ DdNode *tmp, *One, *Gr, *Dr;
+ DdNode *Fv, *Fvn, *Gv, *Gvn, *Dv, *Dvn;
+ int res;
+ unsigned int flevel, glevel, dlevel, top;
+
+ One = DD_ONE(dd);
+
+ statLine(dd);
+ /* Check terminal cases. */
+ if (D == One || F == G) return(1);
+ if (D == Cudd_Not(One) || D == DD_ZERO(dd) || F == Cudd_Not(G)) return(0);
+
+ /* From now on, D is non-constant. */
+
+ /* Normalize call to increase cache efficiency. */
+ if (F > G) {
+ tmp = F;
+ F = G;
+ G = tmp;
+ }
+ if (Cudd_IsComplement(F)) {
+ F = Cudd_Not(F);
+ G = Cudd_Not(G);
+ }
+
+ /* From now on, F is regular. */
+
+ /* Check cache. */
+ tmp = cuddCacheLookup(dd,DD_EQUIV_DC_TAG,F,G,D);
+ if (tmp != NULL) return(tmp == One);
+
+ /* Find splitting variable. */
+ flevel = cuddI(dd,F->index);
+ Gr = Cudd_Regular(G);
+ glevel = cuddI(dd,Gr->index);
+ top = ddMin(flevel,glevel);
+ Dr = Cudd_Regular(D);
+ dlevel = dd->perm[Dr->index];
+ top = ddMin(top,dlevel);
+
+ /* Compute cofactors. */
+ if (top == flevel) {
+ Fv = cuddT(F);
+ Fvn = cuddE(F);
+ } else {
+ Fv = Fvn = F;
+ }
+ if (top == glevel) {
+ Gv = cuddT(Gr);
+ Gvn = cuddE(Gr);
+ if (G != Gr) {
+ Gv = Cudd_Not(Gv);
+ Gvn = Cudd_Not(Gvn);
+ }
+ } else {
+ Gv = Gvn = G;
+ }
+ if (top == dlevel) {
+ Dv = cuddT(Dr);
+ Dvn = cuddE(Dr);
+ if (D != Dr) {
+ Dv = Cudd_Not(Dv);
+ Dvn = Cudd_Not(Dvn);
+ }
+ } else {
+ Dv = Dvn = D;
+ }
+
+ /* Solve recursively. */
+ res = Cudd_EquivDC(dd,Fv,Gv,Dv);
+ if (res != 0) {
+ res = Cudd_EquivDC(dd,Fvn,Gvn,Dvn);
+ }
+ cuddCacheInsert(dd,DD_EQUIV_DC_TAG,F,G,D,(res) ? One : Cudd_Not(One));
+
+ return(res);
+
+} /* end of Cudd_EquivDC */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tells whether f is less than of equal to G unless D is 1.]
+
+ Description [Tells whether f is less than of equal to G unless D is
+ 1. f, g, and D are BDDs. The function returns 1 if f is less than
+ of equal to G, and 0 otherwise. No new nodes are created.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_EquivDC Cudd_bddLeq Cudd_bddIteConstant]
+
+******************************************************************************/
+int
+Cudd_bddLeqUnless(
+ DdManager *dd,
+ DdNode *f,
+ DdNode *g,
+ DdNode *D)
+{
+ DdNode *tmp, *One, *F, *G;
+ DdNode *Ft, *Fe, *Gt, *Ge, *Dt, *De;
+ int res;
+ unsigned int flevel, glevel, dlevel, top;
+
+ statLine(dd);
+
+ One = DD_ONE(dd);
+
+ /* Check terminal cases. */
+ if (f == g || g == One || f == Cudd_Not(One) || D == One ||
+ D == f || D == Cudd_Not(g)) return(1);
+ /* Check for two-operand cases. */
+ if (D == Cudd_Not(One) || D == g || D == Cudd_Not(f))
+ return(Cudd_bddLeq(dd,f,g));
+ if (g == Cudd_Not(One) || g == Cudd_Not(f)) return(Cudd_bddLeq(dd,f,D));
+ if (f == One) return(Cudd_bddLeq(dd,Cudd_Not(g),D));
+
+ /* From now on, f, g, and D are non-constant, distinct, and
+ ** non-complementary. */
+
+ /* Normalize call to increase cache efficiency. We rely on the
+ ** fact that f <= g unless D is equivalent to not(g) <= not(f)
+ ** unless D and to f <= D unless g. We make sure that D is
+ ** regular, and that at most one of f and g is complemented. We also
+ ** ensure that when two operands can be swapped, the one with the
+ ** lowest address comes first. */
+
+ if (Cudd_IsComplement(D)) {
+ if (Cudd_IsComplement(g)) {
+ /* Special case: if f is regular and g is complemented,
+ ** f(1,...,1) = 1 > 0 = g(1,...,1). If D(1,...,1) = 0, return 0.
+ */
+ if (!Cudd_IsComplement(f)) return(0);
+ /* !g <= D unless !f or !D <= g unless !f */
+ tmp = D;
+ D = Cudd_Not(f);
+ if (g < tmp) {
+ f = Cudd_Not(g);
+ g = tmp;
+ } else {
+ f = Cudd_Not(tmp);
+ }
+ } else {
+ if (Cudd_IsComplement(f)) {
+ /* !D <= !f unless g or !D <= g unless !f */
+ tmp = f;
+ f = Cudd_Not(D);
+ if (tmp < g) {
+ D = g;
+ g = Cudd_Not(tmp);
+ } else {
+ D = Cudd_Not(tmp);
+ }
+ } else {
+ /* f <= D unless g or !D <= !f unless g */
+ tmp = D;
+ D = g;
+ if (tmp < f) {
+ g = Cudd_Not(f);
+ f = Cudd_Not(tmp);
+ } else {
+ g = tmp;
+ }
+ }
+ }
+ } else {
+ if (Cudd_IsComplement(g)) {
+ if (Cudd_IsComplement(f)) {
+ /* !g <= !f unless D or !g <= D unless !f */
+ tmp = f;
+ f = Cudd_Not(g);
+ if (D < tmp) {
+ g = D;
+ D = Cudd_Not(tmp);
+ } else {
+ g = Cudd_Not(tmp);
+ }
+ } else {
+ /* f <= g unless D or !g <= !f unless D */
+ if (g < f) {
+ tmp = g;
+ g = Cudd_Not(f);
+ f = Cudd_Not(tmp);
+ }
+ }
+ } else {
+ /* f <= g unless D or f <= D unless g */
+ if (D < g) {
+ tmp = D;
+ D = g;
+ g = tmp;
+ }
+ }
+ }
+
+ /* From now on, D is regular. */
+
+ /* Check cache. */
+ tmp = cuddCacheLookup(dd,DD_BDD_LEQ_UNLESS_TAG,f,g,D);
+ if (tmp != NULL) return(tmp == One);
+
+ /* Find splitting variable. */
+ F = Cudd_Regular(f);
+ flevel = dd->perm[F->index];
+ G = Cudd_Regular(g);
+ glevel = dd->perm[G->index];
+ top = ddMin(flevel,glevel);
+ dlevel = dd->perm[D->index];
+ top = ddMin(top,dlevel);
+
+ /* Compute cofactors. */
+ if (top == flevel) {
+ Ft = cuddT(F);
+ Fe = cuddE(F);
+ if (F != f) {
+ Ft = Cudd_Not(Ft);
+ Fe = Cudd_Not(Fe);
+ }
+ } else {
+ Ft = Fe = f;
+ }
+ if (top == glevel) {
+ Gt = cuddT(G);
+ Ge = cuddE(G);
+ if (G != g) {
+ Gt = Cudd_Not(Gt);
+ Ge = Cudd_Not(Ge);
+ }
+ } else {
+ Gt = Ge = g;
+ }
+ if (top == dlevel) {
+ Dt = cuddT(D);
+ De = cuddE(D);
+ } else {
+ Dt = De = D;
+ }
+
+ /* Solve recursively. */
+ res = Cudd_bddLeqUnless(dd,Ft,Gt,Dt);
+ if (res != 0) {
+ res = Cudd_bddLeqUnless(dd,Fe,Ge,De);
+ }
+ cuddCacheInsert(dd,DD_BDD_LEQ_UNLESS_TAG,f,g,D,Cudd_NotCond(One,!res));
+
+ return(res);
+
+} /* end of Cudd_bddLeqUnless */
+
+
+/**Function********************************************************************
+
+ Synopsis [Compares two ADDs for equality within tolerance.]
+
+ Description [Compares two ADDs for equality within tolerance. Two
+ ADDs are reported to be equal if the maximum difference between them
+ (the sup norm of their difference) is less than or equal to the
+ tolerance parameter. Returns 1 if the two ADDs are equal (within
+ tolerance); 0 otherwise. If parameter <code>pr</code> is positive
+ the first failure is reported to the standard output.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_EqualSupNorm(
+ DdManager * dd /* manager */,
+ DdNode * f /* first ADD */,
+ DdNode * g /* second ADD */,
+ CUDD_VALUE_TYPE tolerance /* maximum allowed difference */,
+ int pr /* verbosity level */)
+{
+ DdNode *fv, *fvn, *gv, *gvn, *r;
+ unsigned int topf, topg;
+
+ statLine(dd);
+ /* Check terminal cases. */
+ if (f == g) return(1);
+ if (Cudd_IsConstant(f) && Cudd_IsConstant(g)) {
+ if (ddEqualVal(cuddV(f),cuddV(g),tolerance)) {
+ return(1);
+ } else {
+ if (pr>0) {
+ (void) fprintf(dd->out,"Offending nodes:\n");
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(dd->out,
+ "f: address = %lx\t value = %40.30f\n",
+ (unsigned long) f, cuddV(f));
+ (void) fprintf(dd->out,
+ "g: address = %lx\t value = %40.30f\n",
+ (unsigned long) g, cuddV(g));
+#else
+ (void) fprintf(dd->out,
+ "f: address = %x\t value = %40.30f\n",
+ (unsigned) f, cuddV(f));
+ (void) fprintf(dd->out,
+ "g: address = %x\t value = %40.30f\n",
+ (unsigned) g, cuddV(g));
+#endif
+ }
+ return(0);
+ }
+ }
+
+ /* We only insert the result in the cache if the comparison is
+ ** successful. Therefore, if we hit we return 1. */
+ r = cuddCacheLookup2(dd,(DdNode * (*)(DdManager *, DdNode *, DdNode *))Cudd_EqualSupNorm,f,g);
+ if (r != NULL) {
+ return(1);
+ }
+
+ /* Compute the cofactors and solve the recursive subproblems. */
+ topf = cuddI(dd,f->index);
+ topg = cuddI(dd,g->index);
+
+ if (topf <= topg) {fv = cuddT(f); fvn = cuddE(f);} else {fv = fvn = f;}
+ if (topg <= topf) {gv = cuddT(g); gvn = cuddE(g);} else {gv = gvn = g;}
+
+ if (!Cudd_EqualSupNorm(dd,fv,gv,tolerance,pr)) return(0);
+ if (!Cudd_EqualSupNorm(dd,fvn,gvn,tolerance,pr)) return(0);
+
+ cuddCacheInsert2(dd,(DdNode * (*)(DdManager *, DdNode *, DdNode *))Cudd_EqualSupNorm,f,g,DD_ONE(dd));
+
+ return(1);
+
+} /* end of Cudd_EqualSupNorm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Expands cube to a prime implicant of f.]
+
+ Description [Expands cube to a prime implicant of f. Returns the prime
+ if successful; NULL otherwise. In particular, NULL is returned if cube
+ is not a real cube or is not an implicant of f.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_bddMakePrime(
+ DdManager *dd /* manager */,
+ DdNode *cube /* cube to be expanded */,
+ DdNode *f /* function of which the cube is to be made a prime */)
+{
+ DdNode *res;
+
+ if (!Cudd_bddLeq(dd,cube,f)) return(NULL);
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddMakePrime(dd,cube,f);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddMakePrime */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddMakePrime.]
+
+ Description [Performs the recursive step of Cudd_bddMakePrime.
+ Returns the prime if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddBddMakePrime(
+ DdManager *dd /* manager */,
+ DdNode *cube /* cube to be expanded */,
+ DdNode *f /* function of which the cube is to be made a prime */)
+{
+ DdNode *scan;
+ DdNode *t, *e;
+ DdNode *res = cube;
+ DdNode *zero = Cudd_Not(DD_ONE(dd));
+
+ Cudd_Ref(res);
+ scan = cube;
+ while (!Cudd_IsConstant(scan)) {
+ DdNode *reg = Cudd_Regular(scan);
+ DdNode *var = dd->vars[reg->index];
+ DdNode *expanded = Cudd_bddExistAbstract(dd,res,var);
+ if (expanded == NULL) {
+ return(NULL);
+ }
+ Cudd_Ref(expanded);
+ if (Cudd_bddLeq(dd,expanded,f)) {
+ Cudd_RecursiveDeref(dd,res);
+ res = expanded;
+ } else {
+ Cudd_RecursiveDeref(dd,expanded);
+ }
+ cuddGetBranches(scan,&t,&e);
+ if (t == zero) {
+ scan = e;
+ } else if (e == zero) {
+ scan = t;
+ } else {
+ Cudd_RecursiveDeref(dd,res);
+ return(NULL); /* cube is not a cube */
+ }
+ }
+
+ if (scan == DD_ONE(dd)) {
+ Cudd_Deref(res);
+ return(res);
+ } else {
+ Cudd_RecursiveDeref(dd,res);
+ return(NULL);
+ }
+
+} /* end of cuddBddMakePrime */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees the entries of the visited symbol table.]
+
+ Description [Frees the entries of the visited symbol table. Returns
+ ST_CONTINUE.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static enum st_retval
+freePathPair(
+ char * key,
+ char * value,
+ char * arg)
+{
+ cuddPathPair *pair;
+
+ pair = (cuddPathPair *) value;
+ FREE(pair);
+ return(ST_CONTINUE);
+
+} /* end of freePathPair */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the length of the shortest path(s) in a DD.]
+
+ Description [Finds the length of the shortest path(s) in a DD.
+ Uses a local symbol table to store the lengths for each
+ node. Only the lengths for the regular nodes are entered in the table,
+ because those for the complement nodes are simply obtained by swapping
+ the two lenghts.
+ Returns a pair of lengths: the length of the shortest path to 1;
+ and the length of the shortest path to 0. This is done so as to take
+ complement arcs into account.]
+
+ SideEffects [Accumulates the support of the DD in support.]
+
+ SeeAlso []
+
+******************************************************************************/
+static cuddPathPair
+getShortest(
+ DdNode * root,
+ int * cost,
+ int * support,
+ st_table * visited)
+{
+ cuddPathPair *my_pair, res_pair, pair_T, pair_E;
+ DdNode *my_root, *T, *E;
+ int weight;
+
+ my_root = Cudd_Regular(root);
+
+ if (st_lookup(visited, (char *)my_root, (char **)&my_pair)) {
+ if (Cudd_IsComplement(root)) {
+ res_pair.pos = my_pair->neg;
+ res_pair.neg = my_pair->pos;
+ } else {
+ res_pair.pos = my_pair->pos;
+ res_pair.neg = my_pair->neg;
+ }
+ return(res_pair);
+ }
+
+ /* In the case of a BDD the following test is equivalent to
+ ** testing whether the BDD is the constant 1. This formulation,
+ ** however, works for ADDs as well, by assuming the usual
+ ** dichotomy of 0 and != 0.
+ */
+ if (cuddIsConstant(my_root)) {
+ if (my_root != zero) {
+ res_pair.pos = 0;
+ res_pair.neg = DD_BIGGY;
+ } else {
+ res_pair.pos = DD_BIGGY;
+ res_pair.neg = 0;
+ }
+ } else {
+ T = cuddT(my_root);
+ E = cuddE(my_root);
+
+ pair_T = getShortest(T, cost, support, visited);
+ pair_E = getShortest(E, cost, support, visited);
+ weight = WEIGHT(cost, my_root->index);
+ res_pair.pos = ddMin(pair_T.pos+weight, pair_E.pos);
+ res_pair.neg = ddMin(pair_T.neg+weight, pair_E.neg);
+
+ /* Update support. */
+ if (support != NULL) {
+ support[my_root->index] = 1;
+ }
+ }
+
+ my_pair = ALLOC(cuddPathPair, 1);
+ if (my_pair == NULL) {
+ if (Cudd_IsComplement(root)) {
+ int tmp = res_pair.pos;
+ res_pair.pos = res_pair.neg;
+ res_pair.neg = tmp;
+ }
+ return(res_pair);
+ }
+ my_pair->pos = res_pair.pos;
+ my_pair->neg = res_pair.neg;
+
+ st_insert(visited, (char *)my_root, (char *)my_pair);
+ if (Cudd_IsComplement(root)) {
+ res_pair.pos = my_pair->neg;
+ res_pair.neg = my_pair->pos;
+ } else {
+ res_pair.pos = my_pair->pos;
+ res_pair.neg = my_pair->neg;
+ }
+ return(res_pair);
+
+} /* end of getShortest */
+
+
+/**Function********************************************************************
+
+ Synopsis [Build a BDD for a shortest path of f.]
+
+ Description [Build a BDD for a shortest path of f.
+ Given the minimum length from the root, and the minimum
+ lengths for each node (in visited), apply triangulation at each node.
+ Of the two children of each node on a shortest path, at least one is
+ on a shortest path. In case of ties the procedure chooses the THEN
+ children.
+ Returns a pointer to the cube BDD representing the path if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+getPath(
+ DdManager * manager,
+ st_table * visited,
+ DdNode * f,
+ int * weight,
+ int cost)
+{
+ DdNode *sol, *tmp;
+ DdNode *my_dd, *T, *E;
+ cuddPathPair *T_pair, *E_pair;
+ int Tcost, Ecost;
+ int complement;
+
+ my_dd = Cudd_Regular(f);
+ complement = Cudd_IsComplement(f);
+
+ sol = one;
+ cuddRef(sol);
+
+ while (!cuddIsConstant(my_dd)) {
+ Tcost = cost - WEIGHT(weight, my_dd->index);
+ Ecost = cost;
+
+ T = cuddT(my_dd);
+ E = cuddE(my_dd);
+
+ if (complement) {T = Cudd_Not(T); E = Cudd_Not(E);}
+
+ st_lookup(visited, (char *)Cudd_Regular(T), (char **)&T_pair);
+ if ((Cudd_IsComplement(T) && T_pair->neg == Tcost) ||
+ (!Cudd_IsComplement(T) && T_pair->pos == Tcost)) {
+ tmp = cuddBddAndRecur(manager,manager->vars[my_dd->index],sol);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(manager,sol);
+ return(NULL);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(manager,sol);
+ sol = tmp;
+
+ complement = Cudd_IsComplement(T);
+ my_dd = Cudd_Regular(T);
+ cost = Tcost;
+ continue;
+ }
+ st_lookup(visited, (char *)Cudd_Regular(E), (char **)&E_pair);
+ if ((Cudd_IsComplement(E) && E_pair->neg == Ecost) ||
+ (!Cudd_IsComplement(E) && E_pair->pos == Ecost)) {
+ tmp = cuddBddAndRecur(manager,Cudd_Not(manager->vars[my_dd->index]),sol);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(manager,sol);
+ return(NULL);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(manager,sol);
+ sol = tmp;
+ complement = Cudd_IsComplement(E);
+ my_dd = Cudd_Regular(E);
+ cost = Ecost;
+ continue;
+ }
+ (void) fprintf(manager->err,"We shouldn't be here!!\n");
+ manager->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+
+ cuddDeref(sol);
+ return(sol);
+
+} /* end of getPath */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the size of the largest cube(s) in a DD.]
+
+ Description [Finds the size of the largest cube(s) in a DD.
+ This problem is translated into finding the shortest paths from a node
+ when both THEN and ELSE arcs have unit lengths.
+ Uses a local symbol table to store the lengths for each
+ node. Only the lengths for the regular nodes are entered in the table,
+ because those for the complement nodes are simply obtained by swapping
+ the two lenghts.
+ Returns a pair of lengths: the length of the shortest path to 1;
+ and the length of the shortest path to 0. This is done so as to take
+ complement arcs into account.]
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+static cuddPathPair
+getLargest(
+ DdNode * root,
+ st_table * visited)
+{
+ cuddPathPair *my_pair, res_pair, pair_T, pair_E;
+ DdNode *my_root, *T, *E;
+
+ my_root = Cudd_Regular(root);
+
+ if (st_lookup(visited, (char *)my_root, (char **)&my_pair)) {
+ if (Cudd_IsComplement(root)) {
+ res_pair.pos = my_pair->neg;
+ res_pair.neg = my_pair->pos;
+ } else {
+ res_pair.pos = my_pair->pos;
+ res_pair.neg = my_pair->neg;
+ }
+ return(res_pair);
+ }
+
+ /* In the case of a BDD the following test is equivalent to
+ ** testing whether the BDD is the constant 1. This formulation,
+ ** however, works for ADDs as well, by assuming the usual
+ ** dichotomy of 0 and != 0.
+ */
+ if (cuddIsConstant(my_root)) {
+ if (my_root != zero) {
+ res_pair.pos = 0;
+ res_pair.neg = DD_BIGGY;
+ } else {
+ res_pair.pos = DD_BIGGY;
+ res_pair.neg = 0;
+ }
+ } else {
+ T = cuddT(my_root);
+ E = cuddE(my_root);
+
+ pair_T = getLargest(T, visited);
+ pair_E = getLargest(E, visited);
+ res_pair.pos = ddMin(pair_T.pos, pair_E.pos) + 1;
+ res_pair.neg = ddMin(pair_T.neg, pair_E.neg) + 1;
+ }
+
+ my_pair = ALLOC(cuddPathPair, 1);
+ if (my_pair == NULL) { /* simlpy do not cache this result */
+ if (Cudd_IsComplement(root)) {
+ int tmp = res_pair.pos;
+ res_pair.pos = res_pair.neg;
+ res_pair.neg = tmp;
+ }
+ return(res_pair);
+ }
+ my_pair->pos = res_pair.pos;
+ my_pair->neg = res_pair.neg;
+
+ st_insert(visited, (char *)my_root, (char *)my_pair);
+ if (Cudd_IsComplement(root)) {
+ res_pair.pos = my_pair->neg;
+ res_pair.neg = my_pair->pos;
+ } else {
+ res_pair.pos = my_pair->pos;
+ res_pair.neg = my_pair->neg;
+ }
+ return(res_pair);
+
+} /* end of getLargest */
+
+
+/**Function********************************************************************
+
+ Synopsis [Build a BDD for a largest cube of f.]
+
+ Description [Build a BDD for a largest cube of f.
+ Given the minimum length from the root, and the minimum
+ lengths for each node (in visited), apply triangulation at each node.
+ Of the two children of each node on a shortest path, at least one is
+ on a shortest path. In case of ties the procedure chooses the THEN
+ children.
+ Returns a pointer to the cube BDD representing the path if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+getCube(
+ DdManager * manager,
+ st_table * visited,
+ DdNode * f,
+ int cost)
+{
+ DdNode *sol, *tmp;
+ DdNode *my_dd, *T, *E;
+ cuddPathPair *T_pair, *E_pair;
+ int Tcost, Ecost;
+ int complement;
+
+ my_dd = Cudd_Regular(f);
+ complement = Cudd_IsComplement(f);
+
+ sol = one;
+ cuddRef(sol);
+
+ while (!cuddIsConstant(my_dd)) {
+ Tcost = cost - 1;
+ Ecost = cost - 1;
+
+ T = cuddT(my_dd);
+ E = cuddE(my_dd);
+
+ if (complement) {T = Cudd_Not(T); E = Cudd_Not(E);}
+
+ st_lookup(visited, (char *)Cudd_Regular(T), (char **)&T_pair);
+ if ((Cudd_IsComplement(T) && T_pair->neg == Tcost) ||
+ (!Cudd_IsComplement(T) && T_pair->pos == Tcost)) {
+ tmp = cuddBddAndRecur(manager,manager->vars[my_dd->index],sol);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(manager,sol);
+ return(NULL);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(manager,sol);
+ sol = tmp;
+
+ complement = Cudd_IsComplement(T);
+ my_dd = Cudd_Regular(T);
+ cost = Tcost;
+ continue;
+ }
+ st_lookup(visited, (char *)Cudd_Regular(E), (char **)&E_pair);
+ if ((Cudd_IsComplement(E) && E_pair->neg == Ecost) ||
+ (!Cudd_IsComplement(E) && E_pair->pos == Ecost)) {
+ tmp = cuddBddAndRecur(manager,Cudd_Not(manager->vars[my_dd->index]),sol);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(manager,sol);
+ return(NULL);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(manager,sol);
+ sol = tmp;
+ complement = Cudd_IsComplement(E);
+ my_dd = Cudd_Regular(E);
+ cost = Ecost;
+ continue;
+ }
+ (void) fprintf(manager->err,"We shouldn't be here!\n");
+ manager->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+
+ cuddDeref(sol);
+ return(sol);
+
+} /* end of getCube */
diff --git a/src/bdd/cudd/cuddSign.c b/src/bdd/cudd/cuddSign.c
new file mode 100644
index 00000000..62477e7f
--- /dev/null
+++ b/src/bdd/cudd/cuddSign.c
@@ -0,0 +1,292 @@
+/**CFile***********************************************************************
+
+ FileName [cuddSign.c]
+
+ PackageName [cudd]
+
+ Synopsis [Computation of signatures]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_CofMinterm();
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> ddCofMintermAux()
+ </ul>
+ ]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddSign.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+static int size;
+
+#ifdef DD_STATS
+static int num_calls; /* should equal 2n-1 (n is the # of nodes) */
+static int table_mem;
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static double * ddCofMintermAux ARGS((DdManager *dd, DdNode *node, st_table *table));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Computes the fraction of minterms in the on-set of all the
+ positive cofactors of a BDD or ADD.]
+
+ Description [Computes the fraction of minterms in the on-set of all
+ the positive cofactors of DD. Returns the pointer to an array of
+ doubles if successful; NULL otherwise. The array hs as many
+ positions as there are BDD variables in the manager plus one. The
+ last position of the array contains the fraction of the minterms in
+ the ON-set of the function represented by the BDD or ADD. The other
+ positions of the array hold the variable signatures.]
+
+ SideEffects [None]
+
+******************************************************************************/
+double *
+Cudd_CofMinterm(
+ DdManager * dd,
+ DdNode * node)
+{
+ st_table *table;
+ double *values;
+ double *result = NULL;
+ int i, firstLevel;
+
+#ifdef DD_STATS
+ long startTime;
+ startTime = util_cpu_time();
+ num_calls = 0;
+ table_mem = sizeof(st_table);
+#endif
+
+ table = st_init_table(st_ptrcmp, st_ptrhash);
+ if (table == NULL) {
+ (void) fprintf(dd->err,
+ "out-of-memory, couldn't measure DD cofactors.\n");
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ size = dd->size;
+ values = ddCofMintermAux(dd, node, table);
+ if (values != NULL) {
+ result = ALLOC(double,size + 1);
+ if (result != NULL) {
+#ifdef DD_STATS
+ table_mem += (size + 1) * sizeof(double);
+#endif
+ if (Cudd_IsConstant(node))
+ firstLevel = 1;
+ else
+ firstLevel = cuddI(dd,Cudd_Regular(node)->index);
+ for (i = 0; i < size; i++) {
+ if (i >= cuddI(dd,Cudd_Regular(node)->index)) {
+ result[dd->invperm[i]] = values[i - firstLevel];
+ } else {
+ result[dd->invperm[i]] = values[size - firstLevel];
+ }
+ }
+ result[size] = values[size - firstLevel];
+ } else {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ }
+ }
+
+#ifdef DD_STATS
+ table_mem += table->num_bins * sizeof(st_table_entry *);
+#endif
+ if (Cudd_Regular(node)->ref == 1) FREE(values);
+ st_foreach(table, cuddStCountfree, NULL);
+ st_free_table(table);
+#ifdef DD_STATS
+ (void) fprintf(dd->out,"Number of calls: %d\tTable memory: %d bytes\n",
+ num_calls, table_mem);
+ (void) fprintf(dd->out,"Time to compute measures: %s\n",
+ util_print_time(util_cpu_time() - startTime));
+#endif
+ if (result == NULL) {
+ (void) fprintf(dd->out,
+ "out-of-memory, couldn't measure DD cofactors.\n");
+ dd->errorCode = CUDD_MEMORY_OUT;
+ }
+ return(result);
+
+} /* end of Cudd_CofMinterm */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Recursive Step for Cudd_CofMinterm function.]
+
+ Description [Traverses the DD node and computes the fraction of
+ minterms in the on-set of all positive cofactors simultaneously.
+ It allocates an array with two more entries than there are
+ variables below the one labeling the node. One extra entry (the
+ first in the array) is for the variable labeling the node. The other
+ entry (the last one in the array) holds the fraction of minterms of
+ the function rooted at node. Each other entry holds the value for
+ one cofactor. The array is put in a symbol table, to avoid repeated
+ computation, and its address is returned by the procedure, for use
+ by the caller. Returns a pointer to the array of cofactor measures.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static double *
+ddCofMintermAux(
+ DdManager * dd,
+ DdNode * node,
+ st_table * table)
+{
+ DdNode *N; /* regular version of node */
+ DdNode *Nv, *Nnv;
+ double *values;
+ double *valuesT, *valuesE;
+ int i;
+ int localSize, localSizeT, localSizeE;
+ double vT, vE;
+
+ statLine(dd);
+#ifdef DD_STATS
+ num_calls++;
+#endif
+
+ if (st_lookup(table, (char *) node, (char **) &values)) {
+ return(values);
+ }
+
+ N = Cudd_Regular(node);
+ if (cuddIsConstant(N)) {
+ localSize = 1;
+ } else {
+ localSize = size - cuddI(dd,N->index) + 1;
+ }
+ values = ALLOC(double, localSize);
+ if (values == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ if (cuddIsConstant(N)) {
+ if (node == DD_ZERO(dd) || node == Cudd_Not(DD_ONE(dd))) {
+ values[0] = 0.0;
+ } else {
+ values[0] = 1.0;
+ }
+ } else {
+ Nv = Cudd_NotCond(cuddT(N),N!=node);
+ Nnv = Cudd_NotCond(cuddE(N),N!=node);
+
+ valuesT = ddCofMintermAux(dd, Nv, table);
+ if (valuesT == NULL) return(NULL);
+ valuesE = ddCofMintermAux(dd, Nnv, table);
+ if (valuesE == NULL) return(NULL);
+
+ if (Cudd_IsConstant(Nv)) {
+ localSizeT = 1;
+ } else {
+ localSizeT = size - cuddI(dd,Cudd_Regular(Nv)->index) + 1;
+ }
+ if (Cudd_IsConstant(Nnv)) {
+ localSizeE = 1;
+ } else {
+ localSizeE = size - cuddI(dd,Cudd_Regular(Nnv)->index) + 1;
+ }
+ values[0] = valuesT[localSizeT - 1];
+ for (i = 1; i < localSize; i++) {
+ if (i >= cuddI(dd,Cudd_Regular(Nv)->index) - cuddI(dd,N->index)) {
+ vT = valuesT[i - cuddI(dd,Cudd_Regular(Nv)->index) +
+ cuddI(dd,N->index)];
+ } else {
+ vT = valuesT[localSizeT - 1];
+ }
+ if (i >= cuddI(dd,Cudd_Regular(Nnv)->index) - cuddI(dd,N->index)) {
+ vE = valuesE[i - cuddI(dd,Cudd_Regular(Nnv)->index) +
+ cuddI(dd,N->index)];
+ } else {
+ vE = valuesE[localSizeE - 1];
+ }
+ values[i] = (vT + vE) / 2.0;
+ }
+ if (Cudd_Regular(Nv)->ref == 1) FREE(valuesT);
+ if (Cudd_Regular(Nnv)->ref == 1) FREE(valuesE);
+ }
+
+ if (N->ref > 1) {
+ if (st_add_direct(table, (char *) node, (char *) values) == ST_OUT_OF_MEM) {
+ FREE(values);
+ return(NULL);
+ }
+#ifdef DD_STATS
+ table_mem += localSize * sizeof(double) + sizeof(st_table_entry);
+#endif
+ }
+ return(values);
+
+} /* end of ddCofMintermAux */
+
diff --git a/src/bdd/cudd/cuddSolve.c b/src/bdd/cudd/cuddSolve.c
new file mode 100644
index 00000000..058e0c08
--- /dev/null
+++ b/src/bdd/cudd/cuddSolve.c
@@ -0,0 +1,339 @@
+/**CFile***********************************************************************
+
+ FileName [cuddSolve.c]
+
+ PackageName [cudd]
+
+ Synopsis [Boolean equation solver and related functions.]
+
+ Description [External functions included in this modoule:
+ <ul>
+ <li> Cudd_SolveEqn()
+ <li> Cudd_VerifySol()
+ </ul>
+ Internal functions included in this module:
+ <ul>
+ <li> cuddSolveEqnRecur()
+ <li> cuddVerifySol()
+ </ul> ]
+
+ SeeAlso []
+
+ Author [Balakrishna Kumthekar]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Structure declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddSolve.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the solution of F(x,y) = 0.]
+
+ Description [Implements the solution for F(x,y) = 0. The return
+ value is the consistency condition. The y variables are the unknowns
+ and the remaining variables are the parameters. Returns the
+ consistency condition if successful; NULL otherwise. Cudd_SolveEqn
+ allocates an array and fills it with the indices of the
+ unknowns. This array is used by Cudd_VerifySol.]
+
+ SideEffects [The solution is returned in G; the indices of the y
+ variables are returned in yIndex.]
+
+ SeeAlso [Cudd_VerifySol]
+
+******************************************************************************/
+DdNode *
+Cudd_SolveEqn(
+ DdManager * bdd,
+ DdNode * F /* the left-hand side of the equation */,
+ DdNode * Y /* the cube of the y variables */,
+ DdNode ** G /* the array of solutions (return parameter) */,
+ int ** yIndex /* index of y variables */,
+ int n /* numbers of unknowns */)
+{
+ DdNode *res;
+ int *temp;
+
+ *yIndex = temp = ALLOC(int, n);
+ if (temp == NULL) {
+ bdd->errorCode = CUDD_MEMORY_OUT;
+ (void) fprintf(bdd->out,
+ "Cudd_SolveEqn: Out of memory for yIndex\n");
+ return(NULL);
+ }
+
+ do {
+ bdd->reordered = 0;
+ res = cuddSolveEqnRecur(bdd, F, Y, G, n, temp, 0);
+ } while (bdd->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_SolveEqn */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks the solution of F(x,y) = 0.]
+
+ Description [Checks the solution of F(x,y) = 0. This procedure
+ substitutes the solution components for the unknowns of F and returns
+ the resulting BDD for F.]
+
+ SideEffects [Frees the memory pointed by yIndex.]
+
+ SeeAlso [Cudd_SolveEqn]
+
+******************************************************************************/
+DdNode *
+Cudd_VerifySol(
+ DdManager * bdd,
+ DdNode * F /* the left-hand side of the equation */,
+ DdNode ** G /* the array of solutions */,
+ int * yIndex /* index of y variables */,
+ int n /* numbers of unknowns */)
+{
+ DdNode *res;
+
+ do {
+ bdd->reordered = 0;
+ res = cuddVerifySol(bdd, F, G, yIndex, n);
+ } while (bdd->reordered == 1);
+
+ FREE(yIndex);
+
+ return(res);
+
+} /* end of Cudd_VerifySol */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_SolveEqn.]
+
+ Description [Implements the recursive step of Cudd_SolveEqn.
+ Returns NULL if the intermediate solution blows up
+ or reordering occurs. The parametric solutions are
+ stored in the array G.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_SolveEqn, Cudd_VerifySol]
+
+******************************************************************************/
+DdNode *
+cuddSolveEqnRecur(
+ DdManager * bdd,
+ DdNode * F /* the left-hand side of the equation */,
+ DdNode * Y /* the cube of remaining y variables */,
+ DdNode ** G /* the array of solutions */,
+ int n /* number of unknowns */,
+ int * yIndex /* array holding the y variable indices */,
+ int i /* level of recursion */)
+{
+ DdNode *Fn, *Fm1, *Fv, *Fvbar, *T, *w, *nextY, *one;
+ DdNodePtr *variables;
+
+ int j;
+
+ statLine(bdd);
+ variables = bdd->vars;
+ one = DD_ONE(bdd);
+
+ /* Base condition. */
+ if (Y == one) {
+ return F;
+ }
+
+ /* Cofactor of Y. */
+ yIndex[i] = Y->index;
+ nextY = Cudd_T(Y);
+
+ /* Universal abstraction of F with respect to the top variable index. */
+ Fm1 = cuddBddExistAbstractRecur(bdd, Cudd_Not(F), variables[yIndex[i]]);
+ if (Fm1) {
+ Fm1 = Cudd_Not(Fm1);
+ cuddRef(Fm1);
+ } else {
+ return(NULL);
+ }
+
+ Fn = cuddSolveEqnRecur(bdd, Fm1, nextY, G, n, yIndex, i+1);
+ if (Fn) {
+ cuddRef(Fn);
+ } else {
+ Cudd_RecursiveDeref(bdd, Fm1);
+ return(NULL);
+ }
+
+ Fv = cuddCofactorRecur(bdd, F, variables[yIndex[i]]);
+ if (Fv) {
+ cuddRef(Fv);
+ } else {
+ Cudd_RecursiveDeref(bdd, Fm1);
+ Cudd_RecursiveDeref(bdd, Fn);
+ return(NULL);
+ }
+
+ Fvbar = cuddCofactorRecur(bdd, F, Cudd_Not(variables[yIndex[i]]));
+ if (Fvbar) {
+ cuddRef(Fvbar);
+ } else {
+ Cudd_RecursiveDeref(bdd, Fm1);
+ Cudd_RecursiveDeref(bdd, Fn);
+ Cudd_RecursiveDeref(bdd, Fv);
+ return(NULL);
+ }
+
+ /* Build i-th component of the solution. */
+ w = cuddBddIteRecur(bdd, variables[yIndex[i]], Cudd_Not(Fv), Fvbar);
+ if (w) {
+ cuddRef(w);
+ } else {
+ Cudd_RecursiveDeref(bdd, Fm1);
+ Cudd_RecursiveDeref(bdd, Fn);
+ Cudd_RecursiveDeref(bdd, Fv);
+ Cudd_RecursiveDeref(bdd, Fvbar);
+ return(NULL);
+ }
+
+ T = cuddBddRestrictRecur(bdd, w, Cudd_Not(Fm1));
+ if(T) {
+ cuddRef(T);
+ } else {
+ Cudd_RecursiveDeref(bdd, Fm1);
+ Cudd_RecursiveDeref(bdd, Fn);
+ Cudd_RecursiveDeref(bdd, Fv);
+ Cudd_RecursiveDeref(bdd, Fvbar);
+ Cudd_RecursiveDeref(bdd, w);
+ return(NULL);
+ }
+
+ Cudd_RecursiveDeref(bdd,Fm1);
+ Cudd_RecursiveDeref(bdd,w);
+ Cudd_RecursiveDeref(bdd,Fv);
+ Cudd_RecursiveDeref(bdd,Fvbar);
+
+ /* Substitute components of solution already found into solution. */
+ for (j = n-1; j > i; j--) {
+ w = cuddBddComposeRecur(bdd,T, G[j], variables[yIndex[j]]);
+ if(w) {
+ cuddRef(w);
+ } else {
+ Cudd_RecursiveDeref(bdd, Fn);
+ Cudd_RecursiveDeref(bdd, T);
+ return(NULL);
+ }
+ Cudd_RecursiveDeref(bdd,T);
+ T = w;
+ }
+ G[i] = T;
+
+ Cudd_Deref(Fn);
+
+ return(Fn);
+
+} /* end of cuddSolveEqnRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_VerifySol. ]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_VerifySol]
+
+******************************************************************************/
+DdNode *
+cuddVerifySol(
+ DdManager * bdd,
+ DdNode * F /* the left-hand side of the equation */,
+ DdNode ** G /* the array of solutions */,
+ int * yIndex /* array holding the y variable indices */,
+ int n /* number of unknowns */)
+{
+ DdNode *w, *R;
+
+ int j;
+
+ R = F;
+ cuddRef(R);
+ for(j = n - 1; j >= 0; j--) {
+ w = Cudd_bddCompose(bdd, R, G[j], yIndex[j]);
+ if (w) {
+ cuddRef(w);
+ } else {
+ return(NULL);
+ }
+ Cudd_RecursiveDeref(bdd,R);
+ R = w;
+ }
+
+ cuddDeref(R);
+
+ return(R);
+
+} /* end of cuddVerifySol */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/cudd/cuddSplit.c b/src/bdd/cudd/cuddSplit.c
new file mode 100644
index 00000000..af7d6372
--- /dev/null
+++ b/src/bdd/cudd/cuddSplit.c
@@ -0,0 +1,657 @@
+/**CFile***********************************************************************
+
+ FileName [cuddSplit.c]
+
+ PackageName [cudd]
+
+ Synopsis [Returns a subset of minterms from a boolean function.]
+
+ Description [External functions included in this modoule:
+ <ul>
+ <li> Cudd_SplitSet()
+ </ul>
+ Internal functions included in this module:
+ <ul>
+ <li> cuddSplitSetRecur()
+ </u>
+ Static functions included in this module:
+ <ul>
+ <li> selectMintermsFromUniverse()
+ <li> mintermsFromUniverse()
+ <li> bddAnnotateMintermCount()
+ </ul> ]
+
+ SeeAlso []
+
+ Author [Balakrishna Kumthekar]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Structure declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdNode * selectMintermsFromUniverse ARGS((DdManager *manager, int *varSeen, double n));
+static DdNode * mintermsFromUniverse ARGS((DdManager *manager, DdNode **vars, int numVars, double n, int index));
+static double bddAnnotateMintermCount ARGS((DdManager *manager, DdNode *node, double max, st_table *table));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns m minterms from a BDD.]
+
+ Description [Returns <code>m</code> minterms from a BDD whose
+ support has <code>n</code> variables at most. The procedure tries
+ to create as few extra nodes as possible. The function represented
+ by <code>S</code> depends on at most <code>n</code> of the variables
+ in <code>xVars</code>. Returns a BDD with <code>m</code> minterms
+ of the on-set of S if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_SplitSet(
+ DdManager * manager,
+ DdNode * S,
+ DdNode ** xVars,
+ int n,
+ double m)
+{
+ DdNode *result;
+ DdNode *zero, *one;
+ double max, num;
+ st_table *mtable;
+ int *varSeen;
+ int i,index, size;
+
+ size = manager->size;
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ /* Trivial cases. */
+ if (m == 0.0) {
+ return(zero);
+ }
+ if (S == zero) {
+ return(NULL);
+ }
+
+ max = pow(2.0,(double)n);
+ if (m > max)
+ return(NULL);
+
+ do {
+ manager->reordered = 0;
+ /* varSeen is used to mark the variables that are encountered
+ ** while traversing the BDD S.
+ */
+ varSeen = ALLOC(int, size);
+ if (varSeen == NULL) {
+ manager->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < size; i++) {
+ varSeen[i] = -1;
+ }
+ for (i = 0; i < n; i++) {
+ index = (xVars[i])->index;
+ varSeen[manager->invperm[index]] = 0;
+ }
+
+ if (S == one) {
+ if (m == max)
+ return(S);
+ result = selectMintermsFromUniverse(manager,varSeen,m);
+ if (result)
+ cuddRef(result);
+ FREE(varSeen);
+ } else {
+ mtable = st_init_table(st_ptrcmp,st_ptrhash);
+ if (mtable == NULL) {
+ (void) fprintf(manager->out,
+ "Cudd_SplitSet: out-of-memory.\n");
+ FREE(varSeen);
+ manager->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ /* The nodes of BDD S are annotated by the number of minterms
+ ** in their onset. The node and the number of minterms in its
+ ** onset are stored in mtable.
+ */
+ num = bddAnnotateMintermCount(manager,S,max,mtable);
+ if (m == num) {
+ st_foreach(mtable,cuddStCountfree,NIL(char));
+ st_free_table(mtable);
+ FREE(varSeen);
+ return(S);
+ }
+
+ result = cuddSplitSetRecur(manager,mtable,varSeen,S,m,max,0);
+ if (result)
+ cuddRef(result);
+ st_foreach(mtable,cuddStCountfree,NULL);
+ st_free_table(mtable);
+ FREE(varSeen);
+ }
+ } while (manager->reordered == 1);
+
+ cuddDeref(result);
+ return(result);
+
+} /* end of Cudd_SplitSet */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_SplitSet.]
+
+ Description [Implements the recursive step of Cudd_SplitSet. The
+ procedure recursively traverses the BDD and checks to see if any
+ node satisfies the minterm requirements as specified by 'n'. At any
+ node X, n is compared to the number of minterms in the onset of X's
+ children. If either of the child nodes have exactly n minterms, then
+ that node is returned; else, if n is greater than the onset of one
+ of the child nodes, that node is retained and the difference in the
+ number of minterms is extracted from the other child. In case n
+ minterms can be extracted from constant 1, the algorithm returns the
+ result with at most log(n) nodes.]
+
+ SideEffects [The array 'varSeen' is updated at every recursive call
+ to set the variables traversed by the procedure.]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode*
+cuddSplitSetRecur(
+ DdManager * manager,
+ st_table * mtable,
+ int * varSeen,
+ DdNode * p,
+ double n,
+ double max,
+ int index)
+{
+ DdNode *one, *zero, *N, *Nv;
+ DdNode *Nnv, *q, *r, *v;
+ DdNode *result;
+ double *dummy, numT, numE;
+ int variable, positive;
+
+ statLine(manager);
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ /* If p is constant, extract n minterms from constant 1. The procedure by
+ ** construction guarantees that minterms will not be extracted from
+ ** constant 0.
+ */
+ if (Cudd_IsConstant(p)) {
+ q = selectMintermsFromUniverse(manager,varSeen,n);
+ return(q);
+ }
+
+ N = Cudd_Regular(p);
+
+ /* Set variable as seen. */
+ variable = N->index;
+ varSeen[manager->invperm[variable]] = -1;
+
+ Nv = cuddT(N);
+ Nnv = cuddE(N);
+ if (Cudd_IsComplement(p)) {
+ Nv = Cudd_Not(Nv);
+ Nnv = Cudd_Not(Nnv);
+ }
+
+ /* If both the children of 'p' are constants, extract n minterms from a
+ ** constant node.
+ */
+ if (Cudd_IsConstant(Nv) && Cudd_IsConstant(Nnv)) {
+ q = selectMintermsFromUniverse(manager,varSeen,n);
+ if (q == NULL) {
+ return(NULL);
+ }
+ cuddRef(q);
+ r = cuddBddAndRecur(manager,p,q);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(manager,q);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_RecursiveDeref(manager,q);
+ cuddDeref(r);
+ return(r);
+ }
+
+ /* Lookup the # of minterms in the onset of the node from the table. */
+ if (!Cudd_IsConstant(Nv)) {
+ st_lookup(mtable,(char *)Nv, (char **)&dummy);
+ numT = *dummy/(2*(1<<index));
+ } else if (Nv == one) {
+ numT = max/(2*(1<<index));
+ } else {
+ numT = 0;
+ }
+
+ if (!Cudd_IsConstant(Nnv)) {
+ st_lookup(mtable,(char *)Nnv, (char **)&dummy);
+ numE = *dummy/(2*(1<<index));
+ } else if (Nnv == one) {
+ numE = max/(2*(1<<index));
+ } else {
+ numE = 0;
+ }
+
+ v = cuddUniqueInter(manager,variable,one,zero);
+ cuddRef(v);
+
+ /* If perfect match. */
+ if (numT == n) {
+ q = cuddBddAndRecur(manager,v,Nv);
+ if (q == NULL) {
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(q);
+ Cudd_RecursiveDeref(manager,v);
+ cuddDeref(q);
+ return(q);
+ }
+ if (numE == n) {
+ q = cuddBddAndRecur(manager,Cudd_Not(v),Nnv);
+ if (q == NULL) {
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(q);
+ Cudd_RecursiveDeref(manager,v);
+ cuddDeref(q);
+ return(q);
+ }
+ /* If n is greater than numT, extract the difference from the ELSE child
+ ** and retain the function represented by the THEN branch.
+ */
+ if (numT < n) {
+ q = cuddSplitSetRecur(manager,mtable,varSeen,
+ Nnv,(n-numT),max,index+1);
+ if (q == NULL) {
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(q);
+ r = cuddBddIteRecur(manager,v,Nv,q);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ cuddDeref(r);
+ return(r);
+ }
+ /* If n is greater than numE, extract the difference from the THEN child
+ ** and retain the function represented by the ELSE branch.
+ */
+ if (numE < n) {
+ q = cuddSplitSetRecur(manager,mtable,varSeen,
+ Nv, (n-numE),max,index+1);
+ if (q == NULL) {
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(q);
+ r = cuddBddIteRecur(manager,v,q,Nnv);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ cuddDeref(r);
+ return(r);
+ }
+
+ /* None of the above cases; (n < numT and n < numE) and either of
+ ** the Nv, Nnv or both are not constants. If possible extract the
+ ** required minterms the constant branch.
+ */
+ if (Cudd_IsConstant(Nv) && !Cudd_IsConstant(Nnv)) {
+ q = selectMintermsFromUniverse(manager,varSeen,n);
+ if (q == NULL) {
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(q);
+ result = cuddBddAndRecur(manager,v,q);
+ if (result == NULL) {
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(result);
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ cuddDeref(result);
+ return(result);
+ } else if (!Cudd_IsConstant(Nv) && Cudd_IsConstant(Nnv)) {
+ q = selectMintermsFromUniverse(manager,varSeen,n);
+ if (q == NULL) {
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(q);
+ result = cuddBddAndRecur(manager,Cudd_Not(v),q);
+ if (result == NULL) {
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(result);
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ cuddDeref(result);
+ return(result);
+ }
+
+ /* Both Nv and Nnv are not constants. So choose the one which
+ ** has fewer minterms in its onset.
+ */
+ positive = 0;
+ if (numT < numE) {
+ q = cuddSplitSetRecur(manager,mtable,varSeen,
+ Nv,n,max,index+1);
+ positive = 1;
+ } else {
+ q = cuddSplitSetRecur(manager,mtable,varSeen,
+ Nnv,n,max,index+1);
+ }
+
+ if (q == NULL) {
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(q);
+
+ if (positive) {
+ result = cuddBddAndRecur(manager,v,q);
+ } else {
+ result = cuddBddAndRecur(manager,Cudd_Not(v),q);
+ }
+ if (result == NULL) {
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(result);
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ cuddDeref(result);
+
+ return(result);
+
+} /* end of cuddSplitSetRecur */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [This function prepares an array of variables which have not been
+ encountered so far when traversing the procedure cuddSplitSetRecur.]
+
+ Description [This function prepares an array of variables which have not been
+ encountered so far when traversing the procedure cuddSplitSetRecur. This
+ array is then used to extract the required number of minterms from a constant
+ 1. The algorithm guarantees that the size of BDD will be utmost \log(n).]
+
+ SideEffects [None]
+
+******************************************************************************/
+static DdNode *
+selectMintermsFromUniverse(
+ DdManager * manager,
+ int * varSeen,
+ double n)
+{
+ int numVars;
+ int i, size, j;
+ DdNode *one, *zero, *result;
+ DdNode **vars;
+
+ numVars = 0;
+ size = manager->size;
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ /* Count the number of variables not encountered so far in procedure
+ ** cuddSplitSetRecur.
+ */
+ for (i = size-1; i >= 0; i--) {
+ if(varSeen[i] == 0)
+ numVars++;
+ }
+ vars = ALLOC(DdNode *, numVars);
+ if (!vars) {
+ manager->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ j = 0;
+ for (i = size-1; i >= 0; i--) {
+ if(varSeen[i] == 0) {
+ vars[j] = cuddUniqueInter(manager,manager->perm[i],one,zero);
+ cuddRef(vars[j]);
+ j++;
+ }
+ }
+
+ /* Compute a function which has n minterms and depends on at most
+ ** numVars variables.
+ */
+ result = mintermsFromUniverse(manager,vars,numVars,n, 0);
+ if (result)
+ cuddRef(result);
+
+ for (i = 0; i < numVars; i++)
+ Cudd_RecursiveDeref(manager,vars[i]);
+ FREE(vars);
+
+ return(result);
+
+} /* end of selectMintermsFromUniverse */
+
+
+/**Function********************************************************************
+
+ Synopsis [Recursive procedure to extract n mintems from constant 1.]
+
+ Description [Recursive procedure to extract n mintems from constant 1.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static DdNode *
+mintermsFromUniverse(
+ DdManager * manager,
+ DdNode ** vars,
+ int numVars,
+ double n,
+ int index)
+{
+ DdNode *one, *zero;
+ DdNode *q, *result;
+ double max, max2;
+
+ statLine(manager);
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ max = pow(2.0, (double)numVars);
+ max2 = max / 2.0;
+
+ if (n == max)
+ return(one);
+ if (n == 0.0)
+ return(zero);
+ /* if n == 2^(numVars-1), return a single variable */
+ if (n == max2)
+ return vars[index];
+ else if (n > max2) {
+ /* When n > 2^(numVars-1), a single variable vars[index]
+ ** contains 2^(numVars-1) minterms. The rest are extracted
+ ** from a constant with 1 less variable.
+ */
+ q = mintermsFromUniverse(manager,vars,numVars-1,(n-max2),index+1);
+ if (q == NULL)
+ return(NULL);
+ cuddRef(q);
+ result = cuddBddIteRecur(manager,vars[index],one,q);
+ } else {
+ /* When n < 2^(numVars-1), a literal of variable vars[index]
+ ** is selected. The required n minterms are extracted from a
+ ** constant with 1 less variable.
+ */
+ q = mintermsFromUniverse(manager,vars,numVars-1,n,index+1);
+ if (q == NULL)
+ return(NULL);
+ cuddRef(q);
+ result = cuddBddAndRecur(manager,vars[index],q);
+ }
+
+ if (result == NULL) {
+ Cudd_RecursiveDeref(manager,q);
+ return(NULL);
+ }
+ cuddRef(result);
+ Cudd_RecursiveDeref(manager,q);
+ cuddDeref(result);
+ return(result);
+
+} /* end of mintermsFromUniverse */
+
+
+/**Function********************************************************************
+
+ Synopsis [Annotates every node in the BDD node with its minterm count.]
+
+ Description [Annotates every node in the BDD node with its minterm count.
+ In this function, every node and the minterm count represented by it are
+ stored in a hash table.]
+
+ SideEffects [Fills up 'table' with the pair <node,minterm_count>.]
+
+******************************************************************************/
+static double
+bddAnnotateMintermCount(
+ DdManager * manager,
+ DdNode * node,
+ double max,
+ st_table * table)
+{
+
+ DdNode *N,*Nv,*Nnv;
+ register double min_v,min_nv;
+ register double min_N;
+ double *pmin;
+ double *dummy;
+
+ statLine(manager);
+ N = Cudd_Regular(node);
+ if (cuddIsConstant(N)) {
+ if (node == DD_ONE(manager)) {
+ return(max);
+ } else {
+ return(0.0);
+ }
+ }
+
+ if (st_lookup(table,(char *)node,(char **)&dummy)) {
+ return(*dummy);
+ }
+
+ Nv = cuddT(N);
+ Nnv = cuddE(N);
+ if (N != node) {
+ Nv = Cudd_Not(Nv);
+ Nnv = Cudd_Not(Nnv);
+ }
+
+ /* Recur on the two branches. */
+ min_v = bddAnnotateMintermCount(manager,Nv,max,table) / 2.0;
+ if (min_v == (double)CUDD_OUT_OF_MEM)
+ return ((double)CUDD_OUT_OF_MEM);
+ min_nv = bddAnnotateMintermCount(manager,Nnv,max,table) / 2.0;
+ if (min_nv == (double)CUDD_OUT_OF_MEM)
+ return ((double)CUDD_OUT_OF_MEM);
+ min_N = min_v + min_nv;
+
+ pmin = ALLOC(double,1);
+ if (pmin == NULL) {
+ manager->errorCode = CUDD_MEMORY_OUT;
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ *pmin = min_N;
+
+ if (st_insert(table,(char *)node, (char *)pmin) == ST_OUT_OF_MEM) {
+ FREE(pmin);
+ return((double)CUDD_OUT_OF_MEM);
+ }
+
+ return(min_N);
+
+} /* end of bddAnnotateMintermCount */
diff --git a/src/bdd/cudd/cuddSubsetHB.c b/src/bdd/cudd/cuddSubsetHB.c
new file mode 100644
index 00000000..43aaf744
--- /dev/null
+++ b/src/bdd/cudd/cuddSubsetHB.c
@@ -0,0 +1,1311 @@
+/**CFile***********************************************************************
+
+ FileName [cuddSubsetHB.c]
+
+ PackageName [cudd]
+
+ Synopsis [Procedure to subset the given BDD by choosing the heavier
+ branches]
+
+
+ Description [External procedures provided by this module:
+ <ul>
+ <li> Cudd_SubsetHeavyBranch()
+ <li> Cudd_SupersetHeavyBranch()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddSubsetHeavyBranch()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> ResizeCountMintermPages();
+ <li> ResizeNodeDataPages()
+ <li> ResizeCountNodePages()
+ <li> SubsetCountMintermAux()
+ <li> SubsetCountMinterm()
+ <li> SubsetCountNodesAux()
+ <li> SubsetCountNodes()
+ <li> BuildSubsetBdd()
+ </ul>
+ ]
+
+ SeeAlso [cuddSubsetSP.c]
+
+ Author [Kavita Ravi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no
+ warranty about the suitability of this software for any
+ purpose. It is presented on an AS IS basis.]
+
+******************************************************************************/
+
+#ifdef __STDC__
+#include <float.h>
+#else
+#define DBL_MAX_EXP 1024
+#endif
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define DEFAULT_PAGE_SIZE 2048
+#define DEFAULT_NODE_DATA_PAGE_SIZE 1024
+#define INITIAL_PAGES 128
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/* data structure to store the information on each node. It keeps
+ * the number of minterms represented by the DAG rooted at this node
+ * in terms of the number of variables specified by the user, number
+ * of nodes in this DAG and the number of nodes of its child with
+ * lesser number of minterms that are not shared by the child with
+ * more minterms
+ */
+struct NodeData {
+ double *mintermPointer;
+ int *nodesPointer;
+ int *lightChildNodesPointer;
+};
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+typedef struct NodeData NodeData_t;
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddSubsetHB.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+static int memOut;
+#ifdef DEBUG
+static int num_calls;
+#endif
+
+static DdNode *zero, *one; /* constant functions */
+static double **mintermPages; /* pointers to the pages */
+static int **nodePages; /* pointers to the pages */
+static int **lightNodePages; /* pointers to the pages */
+static double *currentMintermPage; /* pointer to the current
+ page */
+static double max; /* to store the 2^n value of the number
+ * of variables */
+
+static int *currentNodePage; /* pointer to the current
+ page */
+static int *currentLightNodePage; /* pointer to the
+ * current page */
+static int pageIndex; /* index to next element */
+static int page; /* index to current page */
+static int pageSize = DEFAULT_PAGE_SIZE; /* page size */
+static int maxPages; /* number of page pointers */
+
+static NodeData_t *currentNodeDataPage; /* pointer to the current
+ page */
+static int nodeDataPage; /* index to next element */
+static int nodeDataPageIndex; /* index to next element */
+static NodeData_t **nodeDataPages; /* index to current page */
+static int nodeDataPageSize = DEFAULT_NODE_DATA_PAGE_SIZE;
+ /* page size */
+static int maxNodeDataPages; /* number of page pointers */
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static void ResizeNodeDataPages ARGS(());
+static void ResizeCountMintermPages ARGS(());
+static void ResizeCountNodePages ARGS(());
+static double SubsetCountMintermAux ARGS((DdNode *node, double max, st_table *table));
+static st_table * SubsetCountMinterm ARGS((DdNode *node, int nvars));
+static int SubsetCountNodesAux ARGS((DdNode *node, st_table *table, double max));
+static int SubsetCountNodes ARGS((DdNode *node, st_table *table, int nvars));
+static void StoreNodes ARGS((st_table *storeTable, DdManager *dd, DdNode *node));
+static DdNode * BuildSubsetBdd ARGS((DdManager *dd, DdNode *node, int *size, st_table *visitedTable, int threshold, st_table *storeTable, st_table *approxTable));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Extracts a dense subset from a BDD with the heavy branch
+ heuristic.]
+
+ Description [Extracts a dense subset from a BDD. This procedure
+ builds a subset by throwing away one of the children of each node,
+ starting from the root, until the result is small enough. The child
+ that is eliminated from the result is the one that contributes the
+ fewer minterms. Returns a pointer to the BDD of the subset if
+ successful. NULL if the procedure runs out of memory. The parameter
+ numVars is the maximum number of variables to be used in minterm
+ calculation and node count calculation. The optimal number should
+ be as close as possible to the size of the support of f. However,
+ it is safe to pass the value returned by Cudd_ReadSize for numVars
+ when the number of variables is under 1023. If numVars is larger
+ than 1023, it will overflow. If a 0 parameter is passed then the
+ procedure will compute a value which will avoid overflow but will
+ cause underflow with 2046 variables or more.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SubsetShortPaths Cudd_SupersetHeavyBranch Cudd_ReadSize]
+
+******************************************************************************/
+DdNode *
+Cudd_SubsetHeavyBranch(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be subset */,
+ int numVars /* number of variables in the support of f */,
+ int threshold /* maximum number of nodes in the subset */)
+{
+ DdNode *subset;
+
+ memOut = 0;
+ do {
+ dd->reordered = 0;
+ subset = cuddSubsetHeavyBranch(dd, f, numVars, threshold);
+ } while ((dd->reordered == 1) && (!memOut));
+
+ return(subset);
+
+} /* end of Cudd_SubsetHeavyBranch */
+
+
+/**Function********************************************************************
+
+ Synopsis [Extracts a dense superset from a BDD with the heavy branch
+ heuristic.]
+
+ Description [Extracts a dense superset from a BDD. The procedure is
+ identical to the subset procedure except for the fact that it
+ receives the complement of the given function. Extracting the subset
+ of the complement function is equivalent to extracting the superset
+ of the function. This procedure builds a superset by throwing away
+ one of the children of each node starting from the root of the
+ complement function, until the result is small enough. The child
+ that is eliminated from the result is the one that contributes the
+ fewer minterms.
+ Returns a pointer to the BDD of the superset if successful. NULL if
+ intermediate result causes the procedure to run out of memory. The
+ parameter numVars is the maximum number of variables to be used in
+ minterm calculation and node count calculation. The optimal number
+ should be as close as possible to the size of the support of f.
+ However, it is safe to pass the value returned by Cudd_ReadSize for
+ numVars when the number of variables is under 1023. If numVars is
+ larger than 1023, it will overflow. If a 0 parameter is passed then
+ the procedure will compute a value which will avoid overflow but
+ will cause underflow with 2046 variables or more.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SubsetHeavyBranch Cudd_SupersetShortPaths Cudd_ReadSize]
+
+******************************************************************************/
+DdNode *
+Cudd_SupersetHeavyBranch(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be superset */,
+ int numVars /* number of variables in the support of f */,
+ int threshold /* maximum number of nodes in the superset */)
+{
+ DdNode *subset, *g;
+
+ g = Cudd_Not(f);
+ memOut = 0;
+ do {
+ dd->reordered = 0;
+ subset = cuddSubsetHeavyBranch(dd, g, numVars, threshold);
+ } while ((dd->reordered == 1) && (!memOut));
+
+ return(Cudd_NotCond(subset, (subset != NULL)));
+
+} /* end of Cudd_SupersetHeavyBranch */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [The main procedure that returns a subset by choosing the heavier
+ branch in the BDD.]
+
+ Description [Here a subset BDD is built by throwing away one of the
+ children. Starting at root, annotate each node with the number of
+ minterms (in terms of the total number of variables specified -
+ numVars), number of nodes taken by the DAG rooted at this node and
+ number of additional nodes taken by the child that has the lesser
+ minterms. The child with the lower number of minterms is thrown away
+ and a dyanmic count of the nodes of the subset is kept. Once the
+ threshold is reached the subset is returned to the calling
+ procedure.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SubsetHeavyBranch]
+
+******************************************************************************/
+DdNode *
+cuddSubsetHeavyBranch(
+ DdManager * dd /* DD manager */,
+ DdNode * f /* current DD */,
+ int numVars /* maximum number of variables */,
+ int threshold /* threshold size for the subset */)
+{
+
+ int i, *size;
+ st_table *visitedTable;
+ int numNodes;
+ NodeData_t *currNodeQual;
+ DdNode *subset;
+ double minN;
+ st_table *storeTable, *approxTable;
+ char *key, *value;
+ st_generator *stGen;
+
+ if (f == NULL) {
+ fprintf(dd->err, "Cannot subset, nil object\n");
+ dd->errorCode = CUDD_INVALID_ARG;
+ return(NULL);
+ }
+
+ one = Cudd_ReadOne(dd);
+ zero = Cudd_Not(one);
+
+ /* If user does not know numVars value, set it to the maximum
+ * exponent that the pow function can take. The -1 is due to the
+ * discrepancy in the value that pow takes and the value that
+ * log gives.
+ */
+ if (numVars == 0) {
+ /* set default value */
+ numVars = DBL_MAX_EXP - 1;
+ }
+
+ if (Cudd_IsConstant(f)) {
+ return(f);
+ }
+
+ max = pow(2.0, (double)numVars);
+
+ /* Create visited table where structures for node data are allocated and
+ stored in a st_table */
+ visitedTable = SubsetCountMinterm(f, numVars);
+ if ((visitedTable == NULL) || memOut) {
+ (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ numNodes = SubsetCountNodes(f, visitedTable, numVars);
+ if (memOut) {
+ (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+
+ if (st_lookup(visitedTable, (char *)f, (char **)&currNodeQual)) {
+ minN = *(((NodeData_t *)currNodeQual)->mintermPointer);
+ } else {
+ fprintf(dd->err,
+ "Something is wrong, ought to be node quality table\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ }
+
+ size = ALLOC(int, 1);
+ if (size == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ *size = numNodes;
+
+#ifdef DEBUG
+ num_calls = 0;
+#endif
+ /* table to store nodes being created. */
+ storeTable = st_init_table(st_ptrcmp, st_ptrhash);
+ /* insert the constant */
+ cuddRef(one);
+ if (st_insert(storeTable, (char *)Cudd_ReadOne(dd), NIL(char)) ==
+ ST_OUT_OF_MEM) {
+ fprintf(dd->out, "Something wrong, st_table insert failed\n");
+ }
+ /* table to store approximations of nodes */
+ approxTable = st_init_table(st_ptrcmp, st_ptrhash);
+ subset = (DdNode *)BuildSubsetBdd(dd, f, size, visitedTable, threshold,
+ storeTable, approxTable);
+ if (subset != NULL) {
+ cuddRef(subset);
+ }
+
+ stGen = st_init_gen(approxTable);
+ if (stGen == NULL) {
+ st_free_table(approxTable);
+ return(NULL);
+ }
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ Cudd_RecursiveDeref(dd, (DdNode *)value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+ st_free_table(approxTable);
+
+ stGen = st_init_gen(storeTable);
+ if (stGen == NULL) {
+ st_free_table(storeTable);
+ return(NULL);
+ }
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ Cudd_RecursiveDeref(dd, (DdNode *)key);
+ }
+ st_free_gen(stGen); stGen = NULL;
+ st_free_table(storeTable);
+
+ for (i = 0; i <= page; i++) {
+ FREE(mintermPages[i]);
+ }
+ FREE(mintermPages);
+ for (i = 0; i <= page; i++) {
+ FREE(nodePages[i]);
+ }
+ FREE(nodePages);
+ for (i = 0; i <= page; i++) {
+ FREE(lightNodePages[i]);
+ }
+ FREE(lightNodePages);
+ for (i = 0; i <= nodeDataPage; i++) {
+ FREE(nodeDataPages[i]);
+ }
+ FREE(nodeDataPages);
+ st_free_table(visitedTable);
+ FREE(size);
+#if 0
+ (void) Cudd_DebugCheck(dd);
+ (void) Cudd_CheckKeys(dd);
+#endif
+
+ if (subset != NULL) {
+#ifdef DD_DEBUG
+ if (!Cudd_bddLeq(dd, subset, f)) {
+ fprintf(dd->err, "Wrong subset\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+#endif
+ cuddDeref(subset);
+ return(subset);
+ } else {
+ return(NULL);
+ }
+} /* end of cuddSubsetHeavyBranch */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Resize the number of pages allocated to store the node data.]
+
+ Description [Resize the number of pages allocated to store the node data
+ The procedure moves the counter to the next page when the end of
+ the page is reached and allocates new pages when necessary.]
+
+ SideEffects [Changes the size of pages, page, page index, maximum
+ number of pages freeing stuff in case of memory out. ]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ResizeNodeDataPages(
+ )
+{
+ int i;
+ NodeData_t **newNodeDataPages;
+
+ nodeDataPage++;
+ /* If the current page index is larger than the number of pages
+ * allocated, allocate a new page array. Page numbers are incremented by
+ * INITIAL_PAGES
+ */
+ if (nodeDataPage == maxNodeDataPages) {
+ newNodeDataPages = ALLOC(NodeData_t *,maxNodeDataPages + INITIAL_PAGES);
+ if (newNodeDataPages == NULL) {
+ for (i = 0; i < nodeDataPage; i++) FREE(nodeDataPages[i]);
+ FREE(nodeDataPages);
+ memOut = 1;
+ return;
+ } else {
+ for (i = 0; i < maxNodeDataPages; i++) {
+ newNodeDataPages[i] = nodeDataPages[i];
+ }
+ /* Increase total page count */
+ maxNodeDataPages += INITIAL_PAGES;
+ FREE(nodeDataPages);
+ nodeDataPages = newNodeDataPages;
+ }
+ }
+ /* Allocate a new page */
+ currentNodeDataPage = nodeDataPages[nodeDataPage] =
+ ALLOC(NodeData_t ,nodeDataPageSize);
+ if (currentNodeDataPage == NULL) {
+ for (i = 0; i < nodeDataPage; i++) FREE(nodeDataPages[i]);
+ FREE(nodeDataPages);
+ memOut = 1;
+ return;
+ }
+ /* reset page index */
+ nodeDataPageIndex = 0;
+ return;
+
+} /* end of ResizeNodeDataPages */
+
+
+/**Function********************************************************************
+
+ Synopsis [Resize the number of pages allocated to store the minterm
+ counts. ]
+
+ Description [Resize the number of pages allocated to store the minterm
+ counts. The procedure moves the counter to the next page when the
+ end of the page is reached and allocates new pages when necessary.]
+
+ SideEffects [Changes the size of minterm pages, page, page index, maximum
+ number of pages freeing stuff in case of memory out. ]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ResizeCountMintermPages(
+ )
+{
+ int i;
+ double **newMintermPages;
+
+ page++;
+ /* If the current page index is larger than the number of pages
+ * allocated, allocate a new page array. Page numbers are incremented by
+ * INITIAL_PAGES
+ */
+ if (page == maxPages) {
+ newMintermPages = ALLOC(double *,maxPages + INITIAL_PAGES);
+ if (newMintermPages == NULL) {
+ for (i = 0; i < page; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ memOut = 1;
+ return;
+ } else {
+ for (i = 0; i < maxPages; i++) {
+ newMintermPages[i] = mintermPages[i];
+ }
+ /* Increase total page count */
+ maxPages += INITIAL_PAGES;
+ FREE(mintermPages);
+ mintermPages = newMintermPages;
+ }
+ }
+ /* Allocate a new page */
+ currentMintermPage = mintermPages[page] = ALLOC(double,pageSize);
+ if (currentMintermPage == NULL) {
+ for (i = 0; i < page; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ memOut = 1;
+ return;
+ }
+ /* reset page index */
+ pageIndex = 0;
+ return;
+
+} /* end of ResizeCountMintermPages */
+
+
+/**Function********************************************************************
+
+ Synopsis [Resize the number of pages allocated to store the node counts.]
+
+ Description [Resize the number of pages allocated to store the node counts.
+ The procedure moves the counter to the next page when the end of
+ the page is reached and allocates new pages when necessary.]
+
+ SideEffects [Changes the size of pages, page, page index, maximum
+ number of pages freeing stuff in case of memory out.]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ResizeCountNodePages(
+ )
+{
+ int i;
+ int **newNodePages;
+
+ page++;
+
+ /* If the current page index is larger than the number of pages
+ * allocated, allocate a new page array. The number of pages is incremented
+ * by INITIAL_PAGES.
+ */
+ if (page == maxPages) {
+ newNodePages = ALLOC(int *,maxPages + INITIAL_PAGES);
+ if (newNodePages == NULL) {
+ for (i = 0; i < page; i++) FREE(nodePages[i]);
+ FREE(nodePages);
+ for (i = 0; i < page; i++) FREE(lightNodePages[i]);
+ FREE(lightNodePages);
+ memOut = 1;
+ return;
+ } else {
+ for (i = 0; i < maxPages; i++) {
+ newNodePages[i] = nodePages[i];
+ }
+ FREE(nodePages);
+ nodePages = newNodePages;
+ }
+
+ newNodePages = ALLOC(int *,maxPages + INITIAL_PAGES);
+ if (newNodePages == NULL) {
+ for (i = 0; i < page; i++) FREE(nodePages[i]);
+ FREE(nodePages);
+ for (i = 0; i < page; i++) FREE(lightNodePages[i]);
+ FREE(lightNodePages);
+ memOut = 1;
+ return;
+ } else {
+ for (i = 0; i < maxPages; i++) {
+ newNodePages[i] = lightNodePages[i];
+ }
+ FREE(lightNodePages);
+ lightNodePages = newNodePages;
+ }
+ /* Increase total page count */
+ maxPages += INITIAL_PAGES;
+ }
+ /* Allocate a new page */
+ currentNodePage = nodePages[page] = ALLOC(int,pageSize);
+ if (currentNodePage == NULL) {
+ for (i = 0; i < page; i++) FREE(nodePages[i]);
+ FREE(nodePages);
+ for (i = 0; i < page; i++) FREE(lightNodePages[i]);
+ FREE(lightNodePages);
+ memOut = 1;
+ return;
+ }
+ /* Allocate a new page */
+ currentLightNodePage = lightNodePages[page] = ALLOC(int,pageSize);
+ if (currentLightNodePage == NULL) {
+ for (i = 0; i <= page; i++) FREE(nodePages[i]);
+ FREE(nodePages);
+ for (i = 0; i < page; i++) FREE(lightNodePages[i]);
+ FREE(lightNodePages);
+ memOut = 1;
+ return;
+ }
+ /* reset page index */
+ pageIndex = 0;
+ return;
+
+} /* end of ResizeCountNodePages */
+
+
+/**Function********************************************************************
+
+ Synopsis [Recursively counts minterms of each node in the DAG.]
+
+ Description [Recursively counts minterms of each node in the DAG.
+ Similar to the cuddCountMintermAux which recursively counts the
+ number of minterms for the dag rooted at each node in terms of the
+ total number of variables (max). This procedure creates the node
+ data structure and stores the minterm count as part of the node
+ data structure. ]
+
+ SideEffects [Creates structures of type node quality and fills the st_table]
+
+ SeeAlso [SubsetCountMinterm]
+
+******************************************************************************/
+static double
+SubsetCountMintermAux(
+ DdNode * node /* function to analyze */,
+ double max /* number of minterms of constant 1 */,
+ st_table * table /* visitedTable table */)
+{
+
+ DdNode *N,*Nv,*Nnv; /* nodes to store cofactors */
+ double min,*pmin; /* minterm count */
+ double min1, min2; /* minterm count */
+ NodeData_t *dummy;
+ NodeData_t *newEntry;
+ int i;
+
+#ifdef DEBUG
+ num_calls++;
+#endif
+
+ /* Constant case */
+ if (Cudd_IsConstant(node)) {
+ if (node == zero) {
+ return(0.0);
+ } else {
+ return(max);
+ }
+ } else {
+
+ /* check if entry for this node exists */
+ if (st_lookup(table,(char *)node, (char **)&dummy)) {
+ min = *(dummy->mintermPointer);
+ return(min);
+ }
+
+ /* Make the node regular to extract cofactors */
+ N = Cudd_Regular(node);
+
+ /* store the cofactors */
+ Nv = Cudd_T(N);
+ Nnv = Cudd_E(N);
+
+ Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
+ Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
+
+ min1 = SubsetCountMintermAux(Nv, max,table)/2.0;
+ if (memOut) return(0.0);
+ min2 = SubsetCountMintermAux(Nnv,max,table)/2.0;
+ if (memOut) return(0.0);
+ min = (min1+min2);
+
+ /* if page index is at the bottom, then create a new page */
+ if (pageIndex == pageSize) ResizeCountMintermPages();
+ if (memOut) {
+ for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
+ FREE(nodeDataPages);
+ st_free_table(table);
+ return(0.0);
+ }
+
+ /* point to the correct location in the page */
+ pmin = currentMintermPage+pageIndex;
+ pageIndex++;
+
+ /* store the minterm count of this node in the page */
+ *pmin = min;
+
+ /* Note I allocate the struct here. Freeing taken care of later */
+ if (nodeDataPageIndex == nodeDataPageSize) ResizeNodeDataPages();
+ if (memOut) {
+ for (i = 0; i <= page; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ st_free_table(table);
+ return(0.0);
+ }
+
+ newEntry = currentNodeDataPage + nodeDataPageIndex;
+ nodeDataPageIndex++;
+
+ /* points to the correct location in the page */
+ newEntry->mintermPointer = pmin;
+ /* initialize this field of the Node Quality structure */
+ newEntry->nodesPointer = NULL;
+
+ /* insert entry for the node in the table */
+ if (st_insert(table,(char *)node, (char *)newEntry) == ST_OUT_OF_MEM) {
+ memOut = 1;
+ for (i = 0; i <= page; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
+ FREE(nodeDataPages);
+ st_free_table(table);
+ return(0.0);
+ }
+ return(min);
+ }
+
+} /* end of SubsetCountMintermAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts minterms of each node in the DAG]
+
+ Description [Counts minterms of each node in the DAG. Similar to the
+ Cudd_CountMinterm procedure except this returns the minterm count for
+ all the nodes in the bdd in an st_table.]
+
+ SideEffects [none]
+
+ SeeAlso [SubsetCountMintermAux]
+
+******************************************************************************/
+static st_table *
+SubsetCountMinterm(
+ DdNode * node /* function to be analyzed */,
+ int nvars /* number of variables node depends on */)
+{
+ st_table *table;
+ double num;
+ int i;
+
+
+#ifdef DEBUG
+ num_calls = 0;
+#endif
+
+ max = pow(2.0,(double) nvars);
+ table = st_init_table(st_ptrcmp,st_ptrhash);
+ if (table == NULL) goto OUT_OF_MEM;
+ maxPages = INITIAL_PAGES;
+ mintermPages = ALLOC(double *,maxPages);
+ if (mintermPages == NULL) {
+ st_free_table(table);
+ goto OUT_OF_MEM;
+ }
+ page = 0;
+ currentMintermPage = ALLOC(double,pageSize);
+ mintermPages[page] = currentMintermPage;
+ if (currentMintermPage == NULL) {
+ FREE(mintermPages);
+ st_free_table(table);
+ goto OUT_OF_MEM;
+ }
+ pageIndex = 0;
+ maxNodeDataPages = INITIAL_PAGES;
+ nodeDataPages = ALLOC(NodeData_t *, maxNodeDataPages);
+ if (nodeDataPages == NULL) {
+ for (i = 0; i <= page ; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ st_free_table(table);
+ goto OUT_OF_MEM;
+ }
+ nodeDataPage = 0;
+ currentNodeDataPage = ALLOC(NodeData_t ,nodeDataPageSize);
+ nodeDataPages[nodeDataPage] = currentNodeDataPage;
+ if (currentNodeDataPage == NULL) {
+ for (i = 0; i <= page ; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ FREE(nodeDataPages);
+ st_free_table(table);
+ goto OUT_OF_MEM;
+ }
+ nodeDataPageIndex = 0;
+
+ num = SubsetCountMintermAux(node,max,table);
+ if (memOut) goto OUT_OF_MEM;
+ return(table);
+
+OUT_OF_MEM:
+ memOut = 1;
+ return(NULL);
+
+} /* end of SubsetCountMinterm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Recursively counts the number of nodes under the dag.
+ Also counts the number of nodes under the lighter child of
+ this node.]
+
+ Description [Recursively counts the number of nodes under the dag.
+ Also counts the number of nodes under the lighter child of
+ this node. . Note that the same dag may be the lighter child of two
+ different nodes and have different counts. As with the minterm counts,
+ the node counts are stored in pages to be space efficient and the
+ address for these node counts are stored in an st_table associated
+ to each node. ]
+
+ SideEffects [Updates the node data table with node counts]
+
+ SeeAlso [SubsetCountNodes]
+
+******************************************************************************/
+static int
+SubsetCountNodesAux(
+ DdNode * node /* current node */,
+ st_table * table /* table to update node count, also serves as visited table. */,
+ double max /* maximum number of variables */)
+{
+ int tval, eval, i;
+ DdNode *N, *Nv, *Nnv;
+ double minNv, minNnv;
+ NodeData_t *dummyN, *dummyNv, *dummyNnv, *dummyNBar;
+ int *pmin, *pminBar, *val;
+
+ if ((node == NULL) || Cudd_IsConstant(node))
+ return(0);
+
+ /* if this node has been processed do nothing */
+ if (st_lookup(table, (char *)node, (char **)&dummyN) == 1) {
+ val = dummyN->nodesPointer;
+ if (val != NULL)
+ return(0);
+ } else {
+ return(0);
+ }
+
+ N = Cudd_Regular(node);
+ Nv = Cudd_T(N);
+ Nnv = Cudd_E(N);
+
+ Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
+ Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
+
+ /* find the minterm counts for the THEN and ELSE branches */
+ if (Cudd_IsConstant(Nv)) {
+ if (Nv == zero) {
+ minNv = 0.0;
+ } else {
+ minNv = max;
+ }
+ } else {
+ if (st_lookup(table, (char *)Nv, (char **)&dummyNv) == 1)
+ minNv = *(dummyNv->mintermPointer);
+ else {
+ return(0);
+ }
+ }
+ if (Cudd_IsConstant(Nnv)) {
+ if (Nnv == zero) {
+ minNnv = 0.0;
+ } else {
+ minNnv = max;
+ }
+ } else {
+ if (st_lookup(table, (char *)Nnv, (char **)&dummyNnv) == 1) {
+ minNnv = *(dummyNnv->mintermPointer);
+ }
+ else {
+ return(0);
+ }
+ }
+
+
+ /* recur based on which has larger minterm, */
+ if (minNv >= minNnv) {
+ tval = SubsetCountNodesAux(Nv, table, max);
+ if (memOut) return(0);
+ eval = SubsetCountNodesAux(Nnv, table, max);
+ if (memOut) return(0);
+
+ /* store the node count of the lighter child. */
+ if (pageIndex == pageSize) ResizeCountNodePages();
+ if (memOut) {
+ for (i = 0; i <= page; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
+ FREE(nodeDataPages);
+ st_free_table(table);
+ return(0);
+ }
+ pmin = currentLightNodePage + pageIndex;
+ *pmin = eval; /* Here the ELSE child is lighter */
+ dummyN->lightChildNodesPointer = pmin;
+
+ } else {
+ eval = SubsetCountNodesAux(Nnv, table, max);
+ if (memOut) return(0);
+ tval = SubsetCountNodesAux(Nv, table, max);
+ if (memOut) return(0);
+
+ /* store the node count of the lighter child. */
+ if (pageIndex == pageSize) ResizeCountNodePages();
+ if (memOut) {
+ for (i = 0; i <= page; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
+ FREE(nodeDataPages);
+ st_free_table(table);
+ return(0);
+ }
+ pmin = currentLightNodePage + pageIndex;
+ *pmin = tval; /* Here the THEN child is lighter */
+ dummyN->lightChildNodesPointer = pmin;
+
+ }
+ /* updating the page index for node count storage. */
+ pmin = currentNodePage + pageIndex;
+ *pmin = tval + eval + 1;
+ dummyN->nodesPointer = pmin;
+
+ /* pageIndex is parallel page index for count_nodes and count_lightNodes */
+ pageIndex++;
+
+ /* if this node has been reached first, it belongs to a heavier
+ branch. Its complement will be reached later on a lighter branch.
+ Hence the complement has zero node count. */
+
+ if (st_lookup(table, (char *)Cudd_Not(node), (char **)&dummyNBar) == 1) {
+ if (pageIndex == pageSize) ResizeCountNodePages();
+ if (memOut) {
+ for (i = 0; i < page; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ for (i = 0; i < nodeDataPage; i++) FREE(nodeDataPages[i]);
+ FREE(nodeDataPages);
+ st_free_table(table);
+ return(0);
+ }
+ pminBar = currentLightNodePage + pageIndex;
+ *pminBar = 0;
+ dummyNBar->lightChildNodesPointer = pminBar;
+ /* The lighter child has less nodes than the parent.
+ * So if parent 0 then lighter child zero
+ */
+ if (pageIndex == pageSize) ResizeCountNodePages();
+ if (memOut) {
+ for (i = 0; i < page; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ for (i = 0; i < nodeDataPage; i++) FREE(nodeDataPages[i]);
+ FREE(nodeDataPages);
+ st_free_table(table);
+ return(0);
+ }
+ pminBar = currentNodePage + pageIndex;
+ *pminBar = 0;
+ dummyNBar->nodesPointer = pminBar ; /* maybe should point to zero */
+
+ pageIndex++;
+ }
+ return(*pmin);
+} /*end of SubsetCountNodesAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the nodes under the current node and its lighter child]
+
+ Description [Counts the nodes under the current node and its lighter
+ child. Calls a recursive procedure to count the number of nodes of
+ a DAG rooted at a particular node and the number of nodes taken by its
+ lighter child.]
+
+ SideEffects [None]
+
+ SeeAlso [SubsetCountNodesAux]
+
+******************************************************************************/
+static int
+SubsetCountNodes(
+ DdNode * node /* function to be analyzed */,
+ st_table * table /* node quality table */,
+ int nvars /* number of variables node depends on */)
+{
+ int num;
+ int i;
+
+#ifdef DEBUG
+ num_calls = 0;
+#endif
+
+ max = pow(2.0,(double) nvars);
+ maxPages = INITIAL_PAGES;
+ nodePages = ALLOC(int *,maxPages);
+ if (nodePages == NULL) {
+ goto OUT_OF_MEM;
+ }
+
+ lightNodePages = ALLOC(int *,maxPages);
+ if (lightNodePages == NULL) {
+ for (i = 0; i <= page; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
+ FREE(nodeDataPages);
+ FREE(nodePages);
+ goto OUT_OF_MEM;
+ }
+
+ page = 0;
+ currentNodePage = nodePages[page] = ALLOC(int,pageSize);
+ if (currentNodePage == NULL) {
+ for (i = 0; i <= page; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
+ FREE(nodeDataPages);
+ FREE(lightNodePages);
+ FREE(nodePages);
+ goto OUT_OF_MEM;
+ }
+
+ currentLightNodePage = lightNodePages[page] = ALLOC(int,pageSize);
+ if (currentLightNodePage == NULL) {
+ for (i = 0; i <= page; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
+ FREE(nodeDataPages);
+ FREE(currentNodePage);
+ FREE(lightNodePages);
+ FREE(nodePages);
+ goto OUT_OF_MEM;
+ }
+
+ pageIndex = 0;
+ num = SubsetCountNodesAux(node,table,max);
+ if (memOut) goto OUT_OF_MEM;
+ return(num);
+
+OUT_OF_MEM:
+ memOut = 1;
+ return(0);
+
+} /* end of SubsetCountNodes */
+
+
+/**Function********************************************************************
+
+ Synopsis [Procedure to recursively store nodes that are retained in the subset.]
+
+ Description [rocedure to recursively store nodes that are retained in the subset.]
+
+ SideEffects [None]
+
+ SeeAlso [StoreNodes]
+
+******************************************************************************/
+static void
+StoreNodes(
+ st_table * storeTable,
+ DdManager * dd,
+ DdNode * node)
+{
+ char *dummy;
+ DdNode *N, *Nt, *Ne;
+ if (Cudd_IsConstant(dd)) {
+ return;
+ }
+ N = Cudd_Regular(node);
+ if (st_lookup(storeTable, (char *)N, (char **)&dummy)) {
+ return;
+ }
+ cuddRef(N);
+ if (st_insert(storeTable, (char *)N, NIL(char)) == ST_OUT_OF_MEM) {
+ fprintf(dd->err,"Something wrong, st_table insert failed\n");
+ }
+
+ Nt = Cudd_T(N);
+ Ne = Cudd_E(N);
+
+ StoreNodes(storeTable, dd, Nt);
+ StoreNodes(storeTable, dd, Ne);
+ return;
+
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds the subset BDD using the heavy branch method.]
+
+ Description [The procedure carries out the building of the subset BDD
+ starting at the root. Using the three different counts labelling each node,
+ the procedure chooses the heavier branch starting from the root and keeps
+ track of the number of nodes it discards at each step, thus keeping count
+ of the size of the subset BDD dynamically. Once the threshold is satisfied,
+ the procedure then calls ITE to build the BDD.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+BuildSubsetBdd(
+ DdManager * dd /* DD manager */,
+ DdNode * node /* current node */,
+ int * size /* current size of the subset */,
+ st_table * visitedTable /* visited table storing all node data */,
+ int threshold,
+ st_table * storeTable,
+ st_table * approxTable)
+{
+
+ DdNode *Nv, *Nnv, *N, *topv, *neW;
+ double minNv, minNnv;
+ NodeData_t *currNodeQual;
+ NodeData_t *currNodeQualT;
+ NodeData_t *currNodeQualE;
+ DdNode *ThenBranch, *ElseBranch;
+ unsigned int topid;
+ char *dummy;
+
+#ifdef DEBUG
+ num_calls++;
+#endif
+ /*If the size of the subset is below the threshold, dont do
+ anything. */
+ if ((*size) <= threshold) {
+ /* store nodes below this, so we can recombine if possible */
+ StoreNodes(storeTable, dd, node);
+ return(node);
+ }
+
+ if (Cudd_IsConstant(node))
+ return(node);
+
+ /* Look up minterm count for this node. */
+ if (!st_lookup(visitedTable, (char *)node, (char **)&currNodeQual)) {
+ fprintf(dd->err,
+ "Something is wrong, ought to be in node quality table\n");
+ }
+
+ /* Get children. */
+ N = Cudd_Regular(node);
+ Nv = Cudd_T(N);
+ Nnv = Cudd_E(N);
+
+ /* complement if necessary */
+ Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
+ Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
+
+ if (!Cudd_IsConstant(Nv)) {
+ /* find out minterms and nodes contributed by then child */
+ if (!st_lookup(visitedTable, (char *)Nv,
+ (char **)&currNodeQualT)) {
+ fprintf(dd->out,"Something wrong, couldnt find nodes in node quality table\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+ else {
+ minNv = *(((NodeData_t *)currNodeQualT)->mintermPointer);
+ }
+ } else {
+ if (Nv == zero) {
+ minNv = 0;
+ } else {
+ minNv = max;
+ }
+ }
+ if (!Cudd_IsConstant(Nnv)) {
+ /* find out minterms and nodes contributed by else child */
+ if (!st_lookup(visitedTable, (char *)Nnv, (char **)&currNodeQualE)) {
+ fprintf(dd->out,"Something wrong, couldnt find nodes in node quality table\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ } else {
+ minNnv = *(((NodeData_t *)currNodeQualE)->mintermPointer);
+ }
+ } else {
+ if (Nnv == zero) {
+ minNnv = 0;
+ } else {
+ minNnv = max;
+ }
+ }
+
+ /* keep track of size of subset by subtracting the number of
+ * differential nodes contributed by lighter child
+ */
+ *size = (*(size)) - (int)*(currNodeQual->lightChildNodesPointer);
+ if (minNv >= minNnv) { /*SubsetCountNodesAux procedure takes
+ the Then branch in case of a tie */
+
+ /* recur with the Then branch */
+ ThenBranch = (DdNode *)BuildSubsetBdd(dd, Nv, size,
+ visitedTable, threshold, storeTable, approxTable);
+ if (ThenBranch == NULL) {
+ return(NULL);
+ }
+ cuddRef(ThenBranch);
+ /* The Else branch is either a node that already exists in the
+ * subset, or one whose approximation has been computed, or
+ * Zero.
+ */
+ if (st_lookup(storeTable, (char *)Cudd_Regular(Nnv), (char **)&dummy)) {
+ ElseBranch = Nnv;
+ cuddRef(ElseBranch);
+ } else {
+ if (st_lookup(approxTable, (char *)Nnv, (char **)&dummy)) {
+ ElseBranch = (DdNode *)dummy;
+ cuddRef(ElseBranch);
+ } else {
+ ElseBranch = zero;
+ cuddRef(ElseBranch);
+ }
+ }
+
+ }
+ else {
+ /* recur with the Else branch */
+ ElseBranch = (DdNode *)BuildSubsetBdd(dd, Nnv, size,
+ visitedTable, threshold, storeTable, approxTable);
+ if (ElseBranch == NULL) {
+ return(NULL);
+ }
+ cuddRef(ElseBranch);
+ /* The Then branch is either a node that already exists in the
+ * subset, or one whose approximation has been computed, or
+ * Zero.
+ */
+ if (st_lookup(storeTable, (char *)Cudd_Regular(Nv), (char **)&dummy)) {
+ ThenBranch = Nv;
+ cuddRef(ThenBranch);
+ } else {
+ if (st_lookup(approxTable, (char *)Nv, (char **)&dummy)) {
+ ThenBranch = (DdNode *)dummy;
+ cuddRef(ThenBranch);
+ } else {
+ ThenBranch = zero;
+ cuddRef(ThenBranch);
+ }
+ }
+ }
+
+ /* construct the Bdd with the top variable and the two children */
+ topid = Cudd_NodeReadIndex(N);
+ topv = Cudd_ReadVars(dd, topid);
+ cuddRef(topv);
+ neW = cuddBddIteRecur(dd, topv, ThenBranch, ElseBranch);
+ if (neW != NULL) {
+ cuddRef(neW);
+ }
+ Cudd_RecursiveDeref(dd, topv);
+ Cudd_RecursiveDeref(dd, ThenBranch);
+ Cudd_RecursiveDeref(dd, ElseBranch);
+
+
+ if (neW == NULL)
+ return(NULL);
+ else {
+ /* store this node in the store table */
+ if (!st_lookup(storeTable, (char *)Cudd_Regular(neW), (char **)&dummy)) {
+ cuddRef(neW);
+ st_insert(storeTable, (char *)Cudd_Regular(neW), (char *)NIL(char));
+
+ }
+ /* store the approximation for this node */
+ if (N != Cudd_Regular(neW)) {
+ if (st_lookup(approxTable, (char *)node, (char **)&dummy)) {
+ fprintf(dd->err, "This node should not be in the approximated table\n");
+ } else {
+ cuddRef(neW);
+ st_insert(approxTable, (char *)node, (char *)neW);
+ }
+ }
+ cuddDeref(neW);
+ return(neW);
+ }
+} /* end of BuildSubsetBdd */
+
diff --git a/src/bdd/cudd/cuddSubsetSP.c b/src/bdd/cudd/cuddSubsetSP.c
new file mode 100644
index 00000000..0f7209dd
--- /dev/null
+++ b/src/bdd/cudd/cuddSubsetSP.c
@@ -0,0 +1,1624 @@
+/**CFile***********************************************************************
+
+ FileName [cuddSubsetSP.c]
+
+ PackageName [cudd]
+
+ Synopsis [Procedure to subset the given BDD choosing the shortest paths
+ (largest cubes) in the BDD.]
+
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_SubsetShortPaths()
+ <li> Cudd_SupersetShortPaths()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddSubsetShortPaths()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> BuildSubsetBdd()
+ <li> CreatePathTable()
+ <li> AssessPathLength()
+ <li> CreateTopDist()
+ <li> CreateBotDist()
+ <li> ResizeNodeDistPages()
+ <li> ResizeQueuePages()
+ <li> stPathTableDdFree()
+ </ul>
+ ]
+
+ SeeAlso [cuddSubsetHB.c]
+
+ Author [Kavita Ravi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define DEFAULT_PAGE_SIZE 2048 /* page size to store the BFS queue element type */
+#define DEFAULT_NODE_DIST_PAGE_SIZE 2048 /* page sizesto store NodeDist_t type */
+#define MAXSHORTINT ((DdHalfWord) ~0) /* constant defined to store
+ * maximum distance of a node
+ * from the root or the
+ * constant
+ */
+#define INITIAL_PAGES 128 /* number of initial pages for the
+ * queue/NodeDist_t type */
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/* structure created to store subset results for each node and distances with
+ * odd and even parity of the node from the root and sink. Main data structure
+ * in this procedure.
+ */
+struct NodeDist{
+ DdHalfWord oddTopDist;
+ DdHalfWord evenTopDist;
+ DdHalfWord oddBotDist;
+ DdHalfWord evenBotDist;
+ DdNode *regResult;
+ DdNode *compResult;
+};
+
+/* assorted information needed by the BuildSubsetBdd procedure. */
+struct AssortedInfo {
+ unsigned int maxpath;
+ int findShortestPath;
+ int thresholdReached;
+ st_table *maxpathTable;
+ int threshold;
+};
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+typedef struct NodeDist NodeDist_t;
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddSubsetSP.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+#ifdef DD_DEBUG
+static int numCalls;
+static int hits;
+static int thishit;
+#endif
+
+
+static int memOut; /* flag to indicate out of memory */
+static DdNode *zero, *one; /* constant functions */
+
+static NodeDist_t **nodeDistPages; /* pointers to the pages */
+static int nodeDistPageIndex; /* index to next element */
+static int nodeDistPage; /* index to current page */
+static int nodeDistPageSize = DEFAULT_NODE_DIST_PAGE_SIZE; /* page size */
+static int maxNodeDistPages; /* number of page pointers */
+static NodeDist_t *currentNodeDistPage; /* current page */
+
+static DdNode ***queuePages; /* pointers to the pages */
+static int queuePageIndex; /* index to next element */
+static int queuePage; /* index to current page */
+static int queuePageSize = DEFAULT_PAGE_SIZE; /* page size */
+static int maxQueuePages; /* number of page pointers */
+static DdNode **currentQueuePage; /* current page */
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static void ResizeNodeDistPages ARGS(());
+static void ResizeQueuePages ARGS(());
+static void CreateTopDist ARGS((st_table *pathTable, int parentPage, int parentQueueIndex, int topLen, DdNode **childPage, int childQueueIndex, int numParents, FILE *fp));
+static int CreateBotDist ARGS((DdNode *node, st_table *pathTable, unsigned int *pathLengthArray, FILE *fp));
+static st_table * CreatePathTable ARGS((DdNode *node, unsigned int *pathLengthArray, FILE *fp));
+static unsigned int AssessPathLength ARGS((unsigned int *pathLengthArray, int threshold, int numVars, unsigned int *excess, FILE *fp));
+static DdNode * BuildSubsetBdd ARGS((DdManager *dd, st_table *pathTable, DdNode *node, struct AssortedInfo *info, st_table *subsetNodeTable));
+static enum st_retval stPathTableDdFree ARGS((char *key, char *value, char *arg));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of Exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Extracts a dense subset from a BDD with the shortest paths
+ heuristic.]
+
+ Description [Extracts a dense subset from a BDD. This procedure
+ tries to preserve the shortest paths of the input BDD, because they
+ give many minterms and contribute few nodes. This procedure may
+ increase the number of nodes in trying to create the subset or
+ reduce the number of nodes due to recombination as compared to the
+ original BDD. Hence the threshold may not be strictly adhered to. In
+ practice, recombination overshadows the increase in the number of
+ nodes and results in small BDDs as compared to the threshold. The
+ hardlimit specifies whether threshold needs to be strictly adhered
+ to. If it is set to 1, the procedure ensures that result is never
+ larger than the specified limit but may be considerably less than
+ the threshold. Returns a pointer to the BDD for the subset if
+ successful; NULL otherwise. The value for numVars should be as
+ close as possible to the size of the support of f for better
+ efficiency. However, it is safe to pass the value returned by
+ Cudd_ReadSize for numVars. If 0 is passed, then the value returned
+ by Cudd_ReadSize is used.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SupersetShortPaths Cudd_SubsetHeavyBranch Cudd_ReadSize]
+
+******************************************************************************/
+DdNode *
+Cudd_SubsetShortPaths(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be subset */,
+ int numVars /* number of variables in the support of f */,
+ int threshold /* maximum number of nodes in the subset */,
+ int hardlimit /* flag: 1 if threshold is a hard limit */)
+{
+ DdNode *subset;
+
+ memOut = 0;
+ do {
+ dd->reordered = 0;
+ subset = cuddSubsetShortPaths(dd, f, numVars, threshold, hardlimit);
+ } while((dd->reordered ==1) && (!memOut));
+
+ return(subset);
+
+} /* end of Cudd_SubsetShortPaths */
+
+
+/**Function********************************************************************
+
+ Synopsis [Extracts a dense superset from a BDD with the shortest paths
+ heuristic.]
+
+ Description [Extracts a dense superset from a BDD. The procedure is
+ identical to the subset procedure except for the fact that it
+ receives the complement of the given function. Extracting the subset
+ of the complement function is equivalent to extracting the superset
+ of the function. This procedure tries to preserve the shortest
+ paths of the complement BDD, because they give many minterms and
+ contribute few nodes. This procedure may increase the number of
+ nodes in trying to create the superset or reduce the number of nodes
+ due to recombination as compared to the original BDD. Hence the
+ threshold may not be strictly adhered to. In practice, recombination
+ overshadows the increase in the number of nodes and results in small
+ BDDs as compared to the threshold. The hardlimit specifies whether
+ threshold needs to be strictly adhered to. If it is set to 1, the
+ procedure ensures that result is never larger than the specified
+ limit but may be considerably less than the threshold. Returns a
+ pointer to the BDD for the superset if successful; NULL
+ otherwise. The value for numVars should be as close as possible to
+ the size of the support of f for better efficiency. However, it is
+ safe to pass the value returned by Cudd_ReadSize for numVar. If 0
+ is passed, then the value returned by Cudd_ReadSize is used.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SubsetShortPaths Cudd_SupersetHeavyBranch Cudd_ReadSize]
+
+******************************************************************************/
+DdNode *
+Cudd_SupersetShortPaths(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be superset */,
+ int numVars /* number of variables in the support of f */,
+ int threshold /* maximum number of nodes in the subset */,
+ int hardlimit /* flag: 1 if threshold is a hard limit */)
+{
+ DdNode *subset, *g;
+
+ g = Cudd_Not(f);
+ memOut = 0;
+ do {
+ dd->reordered = 0;
+ subset = cuddSubsetShortPaths(dd, g, numVars, threshold, hardlimit);
+ } while((dd->reordered ==1) && (!memOut));
+
+ return(Cudd_NotCond(subset, (subset != NULL)));
+
+} /* end of Cudd_SupersetShortPaths */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [The outermost procedure to return a subset of the given BDD
+ with the shortest path lengths.]
+
+ Description [The outermost procedure to return a subset of the given
+ BDD with the largest cubes. The path lengths are calculated, the maximum
+ allowable path length is determined and the number of nodes of this
+ path length that can be used to build a subset. If the threshold is
+ larger than the size of the original BDD, the original BDD is
+ returned. ]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SubsetShortPaths]
+
+******************************************************************************/
+DdNode *
+cuddSubsetShortPaths(
+ DdManager * dd /* DD manager */,
+ DdNode * f /* function to be subset */,
+ int numVars /* total number of variables in consideration */,
+ int threshold /* maximum number of nodes allowed in the subset */,
+ int hardlimit /* flag determining whether thershold should be respected strictly */)
+{
+ st_table *pathTable;
+ DdNode *N, *subset;
+
+ unsigned int *pathLengthArray;
+ unsigned int maxpath, oddLen, evenLen, pathLength, *excess;
+ int i;
+ NodeDist_t *nodeStat;
+ struct AssortedInfo *info;
+ st_table *subsetNodeTable;
+
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ if (numVars == 0) {
+ /* set default value */
+ numVars = Cudd_ReadSize(dd);
+ }
+
+ if (threshold > numVars) {
+ threshold = threshold - numVars;
+ }
+ if (f == NULL) {
+ fprintf(dd->err, "Cannot partition, nil object\n");
+ dd->errorCode = CUDD_INVALID_ARG;
+ return(NULL);
+ }
+ if (Cudd_IsConstant(f))
+ return (f);
+
+ pathLengthArray = ALLOC(unsigned int, numVars+1);
+ for (i = 0; i < numVars+1; i++) pathLengthArray[i] = 0;
+
+
+#ifdef DD_DEBUG
+ numCalls = 0;
+#endif
+
+ pathTable = CreatePathTable(f, pathLengthArray, dd->err);
+
+ if ((pathTable == NULL) || (memOut)) {
+ if (pathTable != NULL)
+ st_free_table(pathTable);
+ FREE(pathLengthArray);
+ return (NIL(DdNode));
+ }
+
+ excess = ALLOC(unsigned int, 1);
+ *excess = 0;
+ maxpath = AssessPathLength(pathLengthArray, threshold, numVars, excess,
+ dd->err);
+
+ if (maxpath != (unsigned) (numVars + 1)) {
+
+ info = ALLOC(struct AssortedInfo, 1);
+ info->maxpath = maxpath;
+ info->findShortestPath = 0;
+ info->thresholdReached = *excess;
+ info->maxpathTable = st_init_table(st_ptrcmp, st_ptrhash);
+ info->threshold = threshold;
+
+#ifdef DD_DEBUG
+ (void) fprintf(dd->out, "Path length array\n");
+ for (i = 0; i < (numVars+1); i++) {
+ if (pathLengthArray[i])
+ (void) fprintf(dd->out, "%d ",i);
+ }
+ (void) fprintf(dd->out, "\n");
+ for (i = 0; i < (numVars+1); i++) {
+ if (pathLengthArray[i])
+ (void) fprintf(dd->out, "%d ",pathLengthArray[i]);
+ }
+ (void) fprintf(dd->out, "\n");
+ (void) fprintf(dd->out, "Maxpath = %d, Thresholdreached = %d\n",
+ maxpath, info->thresholdReached);
+#endif
+
+ N = Cudd_Regular(f);
+ if (!st_lookup(pathTable, (char *)N, (char **)&nodeStat)) {
+ fprintf(dd->err, "Something wrong, root node must be in table\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ } else {
+ if ((nodeStat->oddTopDist != MAXSHORTINT) &&
+ (nodeStat->oddBotDist != MAXSHORTINT))
+ oddLen = (nodeStat->oddTopDist + nodeStat->oddBotDist);
+ else
+ oddLen = MAXSHORTINT;
+
+ if ((nodeStat->evenTopDist != MAXSHORTINT) &&
+ (nodeStat->evenBotDist != MAXSHORTINT))
+ evenLen = (nodeStat->evenTopDist +nodeStat->evenBotDist);
+ else
+ evenLen = MAXSHORTINT;
+
+ pathLength = (oddLen <= evenLen) ? oddLen : evenLen;
+ if (pathLength > maxpath) {
+ (void) fprintf(dd->err, "All computations are bogus, since root has path length greater than max path length within threshold %d, %d\n", maxpath, pathLength);
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+ }
+
+#ifdef DD_DEBUG
+ numCalls = 0;
+ hits = 0;
+ thishit = 0;
+#endif
+ /* initialize a table to store computed nodes */
+ if (hardlimit) {
+ subsetNodeTable = st_init_table(st_ptrcmp, st_ptrhash);
+ } else {
+ subsetNodeTable = NIL(st_table);
+ }
+ subset = BuildSubsetBdd(dd, pathTable, f, info, subsetNodeTable);
+ if (subset != NULL) {
+ cuddRef(subset);
+ }
+ /* record the number of times a computed result for a node is hit */
+
+#ifdef DD_DEBUG
+ (void) fprintf(dd->out, "Hits = %d, New==Node = %d, NumCalls = %d\n",
+ hits, thishit, numCalls);
+#endif
+
+ if (subsetNodeTable != NIL(st_table)) {
+ st_free_table(subsetNodeTable);
+ }
+ st_free_table(info->maxpathTable);
+ st_foreach(pathTable, stPathTableDdFree, (char *)dd);
+
+ FREE(info);
+
+ } else {/* if threshold larger than size of dd */
+ subset = f;
+ cuddRef(subset);
+ }
+ FREE(excess);
+ st_free_table(pathTable);
+ FREE(pathLengthArray);
+ for (i = 0; i <= nodeDistPage; i++) FREE(nodeDistPages[i]);
+ FREE(nodeDistPages);
+
+#ifdef DD_DEBUG
+ /* check containment of subset in f */
+ if (subset != NULL) {
+ DdNode *check;
+ check = Cudd_bddIteConstant(dd, subset, f, one);
+ if (check != one) {
+ (void) fprintf(dd->err, "Wrong partition\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+ }
+#endif
+
+ if (subset != NULL) {
+ cuddDeref(subset);
+ return(subset);
+ } else {
+ return(NULL);
+ }
+
+} /* end of cuddSubsetShortPaths */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Resize the number of pages allocated to store the distances
+ related to each node.]
+
+ Description [Resize the number of pages allocated to store the distances
+ related to each node. The procedure moves the counter to the
+ next page when the end of the page is reached and allocates new
+ pages when necessary. ]
+
+ SideEffects [Changes the size of pages, page, page index, maximum
+ number of pages freeing stuff in case of memory out. ]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ResizeNodeDistPages(
+ )
+{
+ int i;
+ NodeDist_t **newNodeDistPages;
+
+ /* move to next page */
+ nodeDistPage++;
+
+ /* If the current page index is larger than the number of pages
+ * allocated, allocate a new page array. Page numbers are incremented by
+ * INITIAL_PAGES
+ */
+ if (nodeDistPage == maxNodeDistPages) {
+ newNodeDistPages = ALLOC(NodeDist_t *,maxNodeDistPages + INITIAL_PAGES);
+ if (newNodeDistPages == NULL) {
+ for (i = 0; i < nodeDistPage; i++) FREE(nodeDistPages[i]);
+ FREE(nodeDistPages);
+ memOut = 1;
+ return;
+ } else {
+ for (i = 0; i < maxNodeDistPages; i++) {
+ newNodeDistPages[i] = nodeDistPages[i];
+ }
+ /* Increase total page count */
+ maxNodeDistPages += INITIAL_PAGES;
+ FREE(nodeDistPages);
+ nodeDistPages = newNodeDistPages;
+ }
+ }
+ /* Allocate a new page */
+ currentNodeDistPage = nodeDistPages[nodeDistPage] = ALLOC(NodeDist_t,
+ nodeDistPageSize);
+ if (currentNodeDistPage == NULL) {
+ for (i = 0; i < nodeDistPage; i++) FREE(nodeDistPages[i]);
+ FREE(nodeDistPages);
+ memOut = 1;
+ return;
+ }
+ /* reset page index */
+ nodeDistPageIndex = 0;
+ return;
+
+} /* end of ResizeNodeDistPages */
+
+
+/**Function********************************************************************
+
+ Synopsis [Resize the number of pages allocated to store nodes in the BFS
+ traversal of the Bdd .]
+
+ Description [Resize the number of pages allocated to store nodes in the BFS
+ traversal of the Bdd. The procedure moves the counter to the
+ next page when the end of the page is reached and allocates new
+ pages when necessary.]
+
+ SideEffects [Changes the size of pages, page, page index, maximum
+ number of pages freeing stuff in case of memory out. ]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ResizeQueuePages(
+ )
+{
+ int i;
+ DdNode ***newQueuePages;
+
+ queuePage++;
+ /* If the current page index is larger than the number of pages
+ * allocated, allocate a new page array. Page numbers are incremented by
+ * INITIAL_PAGES
+ */
+ if (queuePage == maxQueuePages) {
+ newQueuePages = ALLOC(DdNode **,maxQueuePages + INITIAL_PAGES);
+ if (newQueuePages == NULL) {
+ for (i = 0; i < queuePage; i++) FREE(queuePages[i]);
+ FREE(queuePages);
+ memOut = 1;
+ return;
+ } else {
+ for (i = 0; i < maxQueuePages; i++) {
+ newQueuePages[i] = queuePages[i];
+ }
+ /* Increase total page count */
+ maxQueuePages += INITIAL_PAGES;
+ FREE(queuePages);
+ queuePages = newQueuePages;
+ }
+ }
+ /* Allocate a new page */
+ currentQueuePage = queuePages[queuePage] = ALLOC(DdNode *,queuePageSize);
+ if (currentQueuePage == NULL) {
+ for (i = 0; i < queuePage; i++) FREE(queuePages[i]);
+ FREE(queuePages);
+ memOut = 1;
+ return;
+ }
+ /* reset page index */
+ queuePageIndex = 0;
+ return;
+
+} /* end of ResizeQueuePages */
+
+
+/**Function********************************************************************
+
+ Synopsis [ Labels each node with its shortest distance from the root]
+
+ Description [ Labels each node with its shortest distance from the root.
+ This is done in a BFS search of the BDD. The nodes are processed
+ in a queue implemented as pages(array) to reduce memory fragmentation.
+ An entry is created for each node visited. The distance from the root
+ to the node with the corresponding parity is updated. The procedure
+ is called recursively each recusion level handling nodes at a given
+ level from the root.]
+
+
+ SideEffects [Creates entries in the pathTable]
+
+ SeeAlso [CreatePathTable CreateBotDist]
+
+******************************************************************************/
+static void
+CreateTopDist(
+ st_table * pathTable /* hast table to store path lengths */,
+ int parentPage /* the pointer to the page on which the first parent in the queue is to be found. */,
+ int parentQueueIndex /* pointer to the first parent on the page */,
+ int topLen /* current distance from the root */,
+ DdNode ** childPage /* pointer to the page on which the first child is to be added. */,
+ int childQueueIndex /* pointer to the first child */,
+ int numParents /* number of parents to process in this recursive call */,
+ FILE *fp /* where to write messages */)
+{
+ NodeDist_t *nodeStat;
+ DdNode *N, *Nv, *Nnv, *node, *child, *regChild;
+ int i;
+ int processingDone, childrenCount;
+
+#ifdef DD_DEBUG
+ numCalls++;
+
+ /* assume this procedure comes in with only the root node*/
+ /* set queue index to the next available entry for addition */
+ /* set queue page to page of addition */
+ if ((queuePages[parentPage] == childPage) && (parentQueueIndex ==
+ childQueueIndex)) {
+ fprintf(fp, "Should not happen that they are equal\n");
+ }
+ assert(queuePageIndex == childQueueIndex);
+ assert(currentQueuePage == childPage);
+#endif
+ /* number children added to queue is initialized , needed for
+ * numParents in the next call
+ */
+ childrenCount = 0;
+ /* process all the nodes in this level */
+ while (numParents) {
+ numParents--;
+ if (parentQueueIndex == queuePageSize) {
+ parentPage++;
+ parentQueueIndex = 0;
+ }
+ /* a parent to process */
+ node = *(queuePages[parentPage] + parentQueueIndex);
+ parentQueueIndex++;
+ /* get its children */
+ N = Cudd_Regular(node);
+ Nv = Cudd_T(N);
+ Nnv = Cudd_E(N);
+
+ Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
+ Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
+
+ processingDone = 2;
+ while (processingDone) {
+ /* processing the THEN and the ELSE children, the THEN
+ * child first
+ */
+ if (processingDone == 2) {
+ child = Nv;
+ } else {
+ child = Nnv;
+ }
+
+ regChild = Cudd_Regular(child);
+ /* dont process if the child is a constant */
+ if (!Cudd_IsConstant(child)) {
+ /* check is already visited, if not add a new entry in
+ * the path Table
+ */
+ if (!st_lookup(pathTable, (char *)regChild, (char **)&nodeStat)) {
+ /* if not in table, has never been visited */
+ /* create entry for table */
+ if (nodeDistPageIndex == nodeDistPageSize)
+ ResizeNodeDistPages();
+ if (memOut) {
+ for (i = 0; i <= queuePage; i++) FREE(queuePages[i]);
+ FREE(queuePages);
+ st_free_table(pathTable);
+ return;
+ }
+ /* New entry for child in path Table is created here */
+ nodeStat = currentNodeDistPage + nodeDistPageIndex;
+ nodeDistPageIndex++;
+
+ /* Initialize fields of the node data */
+ nodeStat->oddTopDist = MAXSHORTINT;
+ nodeStat->evenTopDist = MAXSHORTINT;
+ nodeStat->evenBotDist = MAXSHORTINT;
+ nodeStat->oddBotDist = MAXSHORTINT;
+ nodeStat->regResult = NULL;
+ nodeStat->compResult = NULL;
+ /* update the table entry element, the distance keeps
+ * track of the parity of the path from the root
+ */
+ if (Cudd_IsComplement(child)) {
+ nodeStat->oddTopDist = (DdHalfWord) topLen + 1;
+ } else {
+ nodeStat->evenTopDist = (DdHalfWord) topLen + 1;
+ }
+
+ /* insert entry element for child in the table */
+ if (st_insert(pathTable, (char *)regChild,
+ (char *)nodeStat) == ST_OUT_OF_MEM) {
+ memOut = 1;
+ for (i = 0; i <= nodeDistPage; i++)
+ FREE(nodeDistPages[i]);
+ FREE(nodeDistPages);
+ for (i = 0; i <= queuePage; i++) FREE(queuePages[i]);
+ FREE(queuePages);
+ st_free_table(pathTable);
+ return;
+ }
+
+ /* Create list element for this child to process its children.
+ * If this node has been processed already, then it appears
+ * in the path table and hence is never added to the list
+ * again.
+ */
+
+ if (queuePageIndex == queuePageSize) ResizeQueuePages();
+ if (memOut) {
+ for (i = 0; i <= nodeDistPage; i++)
+ FREE(nodeDistPages[i]);
+ FREE(nodeDistPages);
+ st_free_table(pathTable);
+ return;
+ }
+ *(currentQueuePage + queuePageIndex) = child;
+ queuePageIndex++;
+
+ childrenCount++;
+ } else {
+ /* if not been met in a path with this parity before */
+ /* put in list */
+ if (((Cudd_IsComplement(child)) && (nodeStat->oddTopDist ==
+ MAXSHORTINT)) || ((!Cudd_IsComplement(child)) &&
+ (nodeStat->evenTopDist == MAXSHORTINT))) {
+
+ if (queuePageIndex == queuePageSize) ResizeQueuePages();
+ if (memOut) {
+ for (i = 0; i <= nodeDistPage; i++)
+ FREE(nodeDistPages[i]);
+ FREE(nodeDistPages);
+ st_free_table(pathTable);
+ return;
+
+ }
+ *(currentQueuePage + queuePageIndex) = child;
+ queuePageIndex++;
+
+ /* update the distance with the appropriate parity */
+ if (Cudd_IsComplement(child)) {
+ nodeStat->oddTopDist = (DdHalfWord) topLen + 1;
+ } else {
+ nodeStat->evenTopDist = (DdHalfWord) topLen + 1;
+ }
+ childrenCount++;
+ }
+
+ } /* end of else (not found in st_table) */
+ } /*end of if Not constant child */
+ processingDone--;
+ } /*end of while processing Nv, Nnv */
+ } /*end of while numParents */
+
+#ifdef DD_DEBUG
+ assert(queuePages[parentPage] == childPage);
+ assert(parentQueueIndex == childQueueIndex);
+#endif
+
+ if (childrenCount != 0) {
+ topLen++;
+ childPage = currentQueuePage;
+ childQueueIndex = queuePageIndex;
+ CreateTopDist(pathTable, parentPage, parentQueueIndex, topLen,
+ childPage, childQueueIndex, childrenCount, fp);
+ }
+
+ return;
+
+} /* end of CreateTopDist */
+
+
+/**Function********************************************************************
+
+ Synopsis [ Labels each node with the shortest distance from the constant.]
+
+ Description [Labels each node with the shortest distance from the constant.
+ This is done in a DFS search of the BDD. Each node has an odd
+ and even parity distance from the sink (since there exists paths to both
+ zero and one) which is less than MAXSHORTINT. At each node these distances
+ are updated using the minimum distance of its children from the constant.
+ SInce now both the length from the root and child is known, the minimum path
+ length(length of the shortest path between the root and the constant that
+ this node lies on) of this node can be calculated and used to update the
+ pathLengthArray]
+
+ SideEffects [Updates Path Table and path length array]
+
+ SeeAlso [CreatePathTable CreateTopDist AssessPathLength]
+
+******************************************************************************/
+static int
+CreateBotDist(
+ DdNode * node /* current node */,
+ st_table * pathTable /* path table with path lengths */,
+ unsigned int * pathLengthArray /* array that stores number of nodes belonging to a particular path length. */,
+ FILE *fp /* where to write messages */)
+{
+ DdNode *N, *Nv, *Nnv;
+ DdNode *realChild;
+ DdNode *child, *regChild;
+ NodeDist_t *nodeStat, *nodeStatChild;
+ unsigned int oddLen, evenLen, pathLength;
+ DdHalfWord botDist;
+ int processingDone;
+
+ if (Cudd_IsConstant(node))
+ return(1);
+ N = Cudd_Regular(node);
+ /* each node has one table entry */
+ /* update as you go down the min dist of each node from
+ the root in each (odd and even) parity */
+ if (!st_lookup(pathTable, (char *)N, (char **)&nodeStat)) {
+ fprintf(fp, "Something wrong, the entry doesn't exist\n");
+ return(0);
+ }
+
+ /* compute length of odd parity distances */
+ if ((nodeStat->oddTopDist != MAXSHORTINT) &&
+ (nodeStat->oddBotDist != MAXSHORTINT))
+ oddLen = (nodeStat->oddTopDist + nodeStat->oddBotDist);
+ else
+ oddLen = MAXSHORTINT;
+
+ /* compute length of even parity distances */
+ if (!((nodeStat->evenTopDist == MAXSHORTINT) ||
+ (nodeStat->evenBotDist == MAXSHORTINT)))
+ evenLen = (nodeStat->evenTopDist +nodeStat->evenBotDist);
+ else
+ evenLen = MAXSHORTINT;
+
+ /* assign pathlength to minimum of the two */
+ pathLength = (oddLen <= evenLen) ? oddLen : evenLen;
+
+ Nv = Cudd_T(N);
+ Nnv = Cudd_E(N);
+
+ /* process each child */
+ processingDone = 0;
+ while (processingDone != 2) {
+ if (!processingDone) {
+ child = Nv;
+ } else {
+ child = Nnv;
+ }
+
+ realChild = Cudd_NotCond(child, Cudd_IsComplement(node));
+ regChild = Cudd_Regular(child);
+ if (Cudd_IsConstant(realChild)) {
+ /* Found a minterm; count parity and shortest distance
+ ** from the constant.
+ */
+ if (Cudd_IsComplement(child))
+ nodeStat->oddBotDist = 1;
+ else
+ nodeStat->evenBotDist = 1;
+ } else {
+ /* If node not in table, recur. */
+ if (!st_lookup(pathTable, (char *) regChild,
+ (char **)&nodeStatChild)) {
+ fprintf(fp, "Something wrong, node in table should have been created in top dist proc.\n");
+ return(0);
+ }
+
+ if (nodeStatChild->oddBotDist == MAXSHORTINT) {
+ if (nodeStatChild->evenBotDist == MAXSHORTINT) {
+ if (!CreateBotDist(realChild, pathTable, pathLengthArray, fp))
+ return(0);
+ } else {
+ fprintf(fp, "Something wrong, both bot nodeStats should be there\n");
+ return(0);
+ }
+ }
+
+ /* Update shortest distance from the constant depending on
+ ** parity. */
+
+ if (Cudd_IsComplement(child)) {
+ /* If parity on the edge then add 1 to even distance
+ ** of child to get odd parity distance and add 1 to
+ ** odd distance of child to get even parity
+ ** distance. Change distance of current node only if
+ ** the calculated distance is less than existing
+ ** distance. */
+ if (nodeStatChild->oddBotDist != MAXSHORTINT)
+ botDist = nodeStatChild->oddBotDist + 1;
+ else
+ botDist = MAXSHORTINT;
+ if (nodeStat->evenBotDist > botDist )
+ nodeStat->evenBotDist = botDist;
+
+ if (nodeStatChild->evenBotDist != MAXSHORTINT)
+ botDist = nodeStatChild->evenBotDist + 1;
+ else
+ botDist = MAXSHORTINT;
+ if (nodeStat->oddBotDist > botDist)
+ nodeStat->oddBotDist = botDist;
+
+ } else {
+ /* If parity on the edge then add 1 to even distance
+ ** of child to get even parity distance and add 1 to
+ ** odd distance of child to get odd parity distance.
+ ** Change distance of current node only if the
+ ** calculated distance is lesser than existing
+ ** distance. */
+ if (nodeStatChild->evenBotDist != MAXSHORTINT)
+ botDist = nodeStatChild->evenBotDist + 1;
+ else
+ botDist = MAXSHORTINT;
+ if (nodeStat->evenBotDist > botDist)
+ nodeStat->evenBotDist = botDist;
+
+ if (nodeStatChild->oddBotDist != MAXSHORTINT)
+ botDist = nodeStatChild->oddBotDist + 1;
+ else
+ botDist = MAXSHORTINT;
+ if (nodeStat->oddBotDist > botDist)
+ nodeStat->oddBotDist = botDist;
+ }
+ } /* end of else (if not constant child ) */
+ processingDone++;
+ } /* end of while processing Nv, Nnv */
+
+ /* Compute shortest path length on the fly. */
+ if ((nodeStat->oddTopDist != MAXSHORTINT) &&
+ (nodeStat->oddBotDist != MAXSHORTINT))
+ oddLen = (nodeStat->oddTopDist + nodeStat->oddBotDist);
+ else
+ oddLen = MAXSHORTINT;
+
+ if ((nodeStat->evenTopDist != MAXSHORTINT) &&
+ (nodeStat->evenBotDist != MAXSHORTINT))
+ evenLen = (nodeStat->evenTopDist +nodeStat->evenBotDist);
+ else
+ evenLen = MAXSHORTINT;
+
+ /* Update path length array that has number of nodes of a particular
+ ** path length. */
+ if (oddLen < pathLength ) {
+ if (pathLength != MAXSHORTINT)
+ pathLengthArray[pathLength]--;
+ if (oddLen != MAXSHORTINT)
+ pathLengthArray[oddLen]++;
+ pathLength = oddLen;
+ }
+ if (evenLen < pathLength ) {
+ if (pathLength != MAXSHORTINT)
+ pathLengthArray[pathLength]--;
+ if (evenLen != MAXSHORTINT)
+ pathLengthArray[evenLen]++;
+ }
+
+ return(1);
+
+} /*end of CreateBotDist */
+
+
+/**Function********************************************************************
+
+ Synopsis [ The outer procedure to label each node with its shortest
+ distance from the root and constant]
+
+ Description [ The outer procedure to label each node with its shortest
+ distance from the root and constant. Calls CreateTopDist and CreateBotDist.
+ The basis for computing the distance between root and constant is that
+ the distance may be the sum of even distances from the node to the root
+ and constant or the sum of odd distances from the node to the root and
+ constant. Both CreateTopDist and CreateBotDist create the odd and
+ even parity distances from the root and constant respectively.]
+
+ SideEffects [None]
+
+ SeeAlso [CreateTopDist CreateBotDist]
+
+******************************************************************************/
+static st_table *
+CreatePathTable(
+ DdNode * node /* root of function */,
+ unsigned int * pathLengthArray /* array of path lengths to store nodes labeled with the various path lengths */,
+ FILE *fp /* where to write messages */)
+{
+
+ st_table *pathTable;
+ NodeDist_t *nodeStat;
+ DdHalfWord topLen;
+ DdNode *N;
+ int i, numParents;
+ int insertValue;
+ DdNode **childPage;
+ int parentPage;
+ int childQueueIndex, parentQueueIndex;
+
+ /* Creating path Table for storing data about nodes */
+ pathTable = st_init_table(st_ptrcmp,st_ptrhash);
+
+ /* initializing pages for info about each node */
+ maxNodeDistPages = INITIAL_PAGES;
+ nodeDistPages = ALLOC(NodeDist_t *, maxNodeDistPages);
+ if (nodeDistPages == NULL) {
+ goto OUT_OF_MEM;
+ }
+ nodeDistPage = 0;
+ currentNodeDistPage = nodeDistPages[nodeDistPage] =
+ ALLOC(NodeDist_t, nodeDistPageSize);
+ if (currentNodeDistPage == NULL) {
+ for (i = 0; i <= nodeDistPage; i++) FREE(nodeDistPages[i]);
+ FREE(nodeDistPages);
+ goto OUT_OF_MEM;
+ }
+ nodeDistPageIndex = 0;
+
+ /* Initializing pages for the BFS search queue, implemented as an array. */
+ maxQueuePages = INITIAL_PAGES;
+ queuePages = ALLOC(DdNode **, maxQueuePages);
+ if (queuePages == NULL) {
+ goto OUT_OF_MEM;
+ }
+ queuePage = 0;
+ currentQueuePage = queuePages[queuePage] = ALLOC(DdNode *, queuePageSize);
+ if (currentQueuePage == NULL) {
+ for (i = 0; i <= queuePage; i++) FREE(queuePages[i]);
+ FREE(queuePages);
+ goto OUT_OF_MEM;
+ }
+ queuePageIndex = 0;
+
+ /* Enter the root node into the queue to start with. */
+ parentPage = queuePage;
+ parentQueueIndex = queuePageIndex;
+ topLen = 0;
+ *(currentQueuePage + queuePageIndex) = node;
+ queuePageIndex++;
+ childPage = currentQueuePage;
+ childQueueIndex = queuePageIndex;
+
+ N = Cudd_Regular(node);
+
+ if (nodeDistPageIndex == nodeDistPageSize) ResizeNodeDistPages();
+ if (memOut) {
+ for (i = 0; i <= nodeDistPage; i++) FREE(nodeDistPages[i]);
+ FREE(nodeDistPages);
+ for (i = 0; i <= queuePage; i++) FREE(queuePages[i]);
+ FREE(queuePages);
+ st_free_table(pathTable);
+ goto OUT_OF_MEM;
+ }
+
+ nodeStat = currentNodeDistPage + nodeDistPageIndex;
+ nodeDistPageIndex++;
+
+ nodeStat->oddTopDist = MAXSHORTINT;
+ nodeStat->evenTopDist = MAXSHORTINT;
+ nodeStat->evenBotDist = MAXSHORTINT;
+ nodeStat->oddBotDist = MAXSHORTINT;
+ nodeStat->regResult = NULL;
+ nodeStat->compResult = NULL;
+
+ insertValue = st_insert(pathTable, (char *)N, (char *)nodeStat);
+ if (insertValue == ST_OUT_OF_MEM) {
+ memOut = 1;
+ for (i = 0; i <= nodeDistPage; i++) FREE(nodeDistPages[i]);
+ FREE(nodeDistPages);
+ for (i = 0; i <= queuePage; i++) FREE(queuePages[i]);
+ FREE(queuePages);
+ st_free_table(pathTable);
+ goto OUT_OF_MEM;
+ } else if (insertValue == 1) {
+ fprintf(fp, "Something wrong, the entry exists but didnt show up in st_lookup\n");
+ return(NULL);
+ }
+
+ if (Cudd_IsComplement(node)) {
+ nodeStat->oddTopDist = 0;
+ } else {
+ nodeStat->evenTopDist = 0;
+ }
+ numParents = 1;
+ /* call the function that counts the distance of each node from the
+ * root
+ */
+#ifdef DD_DEBUG
+ numCalls = 0;
+#endif
+ CreateTopDist(pathTable, parentPage, parentQueueIndex, (int) topLen,
+ childPage, childQueueIndex, numParents, fp);
+ if (memOut) {
+ fprintf(fp, "Out of Memory and cant count path lengths\n");
+ goto OUT_OF_MEM;
+ }
+
+#ifdef DD_DEBUG
+ numCalls = 0;
+#endif
+ /* call the function that counts the distance of each node from the
+ * constant
+ */
+ if (!CreateBotDist(node, pathTable, pathLengthArray, fp)) return(NULL);
+
+ /* free BFS queue pages as no longer required */
+ for (i = 0; i <= queuePage; i++) FREE(queuePages[i]);
+ FREE(queuePages);
+ return(pathTable);
+
+OUT_OF_MEM:
+ (void) fprintf(fp, "Out of Memory, cannot allocate pages\n");
+ memOut = 1;
+ return(NULL);
+
+} /*end of CreatePathTable */
+
+
+/**Function********************************************************************
+
+ Synopsis [Chooses the maximum allowable path length of nodes under the
+ threshold.]
+
+ Description [Chooses the maximum allowable path length under each node.
+ The corner cases are when the threshold is larger than the number
+ of nodes in the BDD iself, in which case 'numVars + 1' is returned.
+ If all nodes of a particular path length are needed, then the
+ maxpath returned is the next one with excess nodes = 0;]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static unsigned int
+AssessPathLength(
+ unsigned int * pathLengthArray /* array determining number of nodes belonging to the different path lengths */,
+ int threshold /* threshold to determine maximum allowable nodes in the subset */,
+ int numVars /* maximum number of variables */,
+ unsigned int * excess /* number of nodes labeled maxpath required in the subset */,
+ FILE *fp /* where to write messages */)
+{
+ unsigned int i, maxpath;
+ int temp;
+
+ temp = threshold;
+ i = 0;
+ maxpath = 0;
+ /* quit loop if i reaches max number of variables or if temp reaches
+ * below zero
+ */
+ while ((i < (unsigned) numVars+1) && (temp > 0)) {
+ if (pathLengthArray[i] > 0) {
+ maxpath = i;
+ temp = temp - pathLengthArray[i];
+ }
+ i++;
+ }
+ /* if all nodes of max path are needed */
+ if (temp >= 0) {
+ maxpath++; /* now maxpath becomes the next maxppath or max number
+ of variables */
+ *excess = 0;
+ } else { /* normal case when subset required is less than size of
+ original BDD */
+ *excess = temp + pathLengthArray[maxpath];
+ }
+
+ if (maxpath == 0) {
+ fprintf(fp, "Path Length array seems to be all zeroes, check\n");
+ }
+ return(maxpath);
+
+} /* end of AssessPathLength */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds the BDD with nodes labeled with path length less than or equal to maxpath]
+
+ Description [Builds the BDD with nodes labeled with path length
+ under maxpath and as many nodes labeled maxpath as determined by the
+ threshold. The procedure uses the path table to determine which nodes
+ in the original bdd need to be retained. This procedure picks a
+ shortest path (tie break decided by taking the child with the shortest
+ distance to the constant) and recurs down the path till it reaches the
+ constant. the procedure then starts building the subset upward from
+ the constant. All nodes labeled by path lengths less than the given
+ maxpath are used to build the subset. However, in the case of nodes
+ that have label equal to maxpath, as many are chosen as required by
+ the threshold. This number is stored in the info structure in the
+ field thresholdReached. This field is decremented whenever a node
+ labeled maxpath is encountered and the nodes labeled maxpath are
+ aggregated in a maxpath table. As soon as the thresholdReached count
+ goes to 0, the shortest path from this node to the constant is found.
+ The extraction of nodes with the above labeling is based on the fact
+ that each node, labeled with a path length, P, has at least one child
+ labeled P or less. So extracting all nodes labeled a given path length
+ P ensures complete paths between the root and the constant. Extraction
+ of a partial number of nodes with a given path length may result in
+ incomplete paths and hence the additional number of nodes are grabbed
+ to complete the path. Since the Bdd is built bottom-up, other nodes
+ labeled maxpath do lie on complete paths. The procedure may cause the
+ subset to have a larger or smaller number of nodes than the specified
+ threshold. The increase in the number of nodes is caused by the
+ building of a subset and the reduction by recombination. However in
+ most cases, the recombination overshadows the increase and the
+ procedure returns a result with lower number of nodes than specified.
+ The subsetNodeTable is NIL when there is no hard limit on the number
+ of nodes. Further efforts towards keeping the subset closer to the
+ threshold number were abandoned in favour of keeping the procedure
+ simple and fast.]
+
+ SideEffects [SubsetNodeTable is changed if it is not NIL.]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+BuildSubsetBdd(
+ DdManager * dd /* DD manager */,
+ st_table * pathTable /* path table with path lengths and computed results */,
+ DdNode * node /* current node */,
+ struct AssortedInfo * info /* assorted information structure */,
+ st_table * subsetNodeTable /* table storing computed results */)
+{
+ DdNode *N, *Nv, *Nnv;
+ DdNode *ThenBranch, *ElseBranch, *childBranch;
+ DdNode *child, *regChild, *regNnv, *regNv;
+ NodeDist_t *nodeStatNv, *nodeStat, *nodeStatNnv;
+ DdNode *neW, *topv, *regNew;
+ char *entry;
+ unsigned int topid;
+ unsigned int childPathLength, oddLen, evenLen, NnvPathLength, NvPathLength;
+ unsigned int NvBotDist, NnvBotDist;
+ int tiebreakChild;
+ int processingDone, thenDone, elseDone;
+
+
+#ifdef DD_DEBUG
+ numCalls++;
+#endif
+ if (Cudd_IsConstant(node))
+ return(node);
+
+ N = Cudd_Regular(node);
+ /* Find node in table. */
+ if (!st_lookup(pathTable, (char *)N, (char **)&nodeStat)) {
+ (void) fprintf(dd->err, "Something wrong, node must be in table \n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+ /* If the node in the table has been visited, then return the corresponding
+ ** Dd. Since a node can become a subset of itself, its
+ ** complement (that is te same node reached by a different parity) will
+ ** become a superset of the original node and result in some minterms
+ ** that were not in the original set. Hence two different results are
+ ** maintained, corresponding to the odd and even parities.
+ */
+
+ /* If this node is reached with an odd parity, get odd parity results. */
+ if (Cudd_IsComplement(node)) {
+ if (nodeStat->compResult != NULL) {
+#ifdef DD_DEBUG
+ hits++;
+#endif
+ return(nodeStat->compResult);
+ }
+ } else {
+ /* if this node is reached with an even parity, get even parity
+ * results
+ */
+ if (nodeStat->regResult != NULL) {
+#ifdef DD_DEBUG
+ hits++;
+#endif
+ return(nodeStat->regResult);
+ }
+ }
+
+
+ /* get children */
+ Nv = Cudd_T(N);
+ Nnv = Cudd_E(N);
+
+ Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
+ Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
+
+ /* no child processed */
+ processingDone = 0;
+ /* then child not processed */
+ thenDone = 0;
+ ThenBranch = NULL;
+ /* else child not processed */
+ elseDone = 0;
+ ElseBranch = NULL;
+ /* if then child constant, branch is the child */
+ if (Cudd_IsConstant(Nv)) {
+ /*shortest path found */
+ if ((Nv == DD_ONE(dd)) && (info->findShortestPath)) {
+ info->findShortestPath = 0;
+ }
+
+ ThenBranch = Nv;
+ cuddRef(ThenBranch);
+ if (ThenBranch == NULL) {
+ return(NULL);
+ }
+
+ thenDone++;
+ processingDone++;
+ NvBotDist = MAXSHORTINT;
+ } else {
+ /* Derive regular child for table lookup. */
+ regNv = Cudd_Regular(Nv);
+ /* Get node data for shortest path length. */
+ if (!st_lookup(pathTable, (char *)regNv, (char **)&nodeStatNv) ) {
+ (void) fprintf(dd->err, "Something wrong, node must be in table\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+ /* Derive shortest path length for child. */
+ if ((nodeStatNv->oddTopDist != MAXSHORTINT) &&
+ (nodeStatNv->oddBotDist != MAXSHORTINT)) {
+ oddLen = (nodeStatNv->oddTopDist + nodeStatNv->oddBotDist);
+ } else {
+ oddLen = MAXSHORTINT;
+ }
+
+ if ((nodeStatNv->evenTopDist != MAXSHORTINT) &&
+ (nodeStatNv->evenBotDist != MAXSHORTINT)) {
+ evenLen = (nodeStatNv->evenTopDist +nodeStatNv->evenBotDist);
+ } else {
+ evenLen = MAXSHORTINT;
+ }
+
+ NvPathLength = (oddLen <= evenLen) ? oddLen : evenLen;
+ NvBotDist = (oddLen <= evenLen) ? nodeStatNv->oddBotDist:
+ nodeStatNv->evenBotDist;
+ }
+ /* if else child constant, branch is the child */
+ if (Cudd_IsConstant(Nnv)) {
+ /*shortest path found */
+ if ((Nnv == DD_ONE(dd)) && (info->findShortestPath)) {
+ info->findShortestPath = 0;
+ }
+
+ ElseBranch = Nnv;
+ cuddRef(ElseBranch);
+ if (ElseBranch == NULL) {
+ return(NULL);
+ }
+
+ elseDone++;
+ processingDone++;
+ NnvBotDist = MAXSHORTINT;
+ } else {
+ /* Derive regular child for table lookup. */
+ regNnv = Cudd_Regular(Nnv);
+ /* Get node data for shortest path length. */
+ if (!st_lookup(pathTable, (char *)regNnv, (char **)&nodeStatNnv) ) {
+ (void) fprintf(dd->err, "Something wrong, node must be in table\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+ /* Derive shortest path length for child. */
+ if ((nodeStatNnv->oddTopDist != MAXSHORTINT) &&
+ (nodeStatNnv->oddBotDist != MAXSHORTINT)) {
+ oddLen = (nodeStatNnv->oddTopDist + nodeStatNnv->oddBotDist);
+ } else {
+ oddLen = MAXSHORTINT;
+ }
+
+ if ((nodeStatNnv->evenTopDist != MAXSHORTINT) &&
+ (nodeStatNnv->evenBotDist != MAXSHORTINT)) {
+ evenLen = (nodeStatNnv->evenTopDist +nodeStatNnv->evenBotDist);
+ } else {
+ evenLen = MAXSHORTINT;
+ }
+
+ NnvPathLength = (oddLen <= evenLen) ? oddLen : evenLen;
+ NnvBotDist = (oddLen <= evenLen) ? nodeStatNnv->oddBotDist :
+ nodeStatNnv->evenBotDist;
+ }
+
+ tiebreakChild = (NvBotDist <= NnvBotDist) ? 1 : 0;
+ /* while both children not processed */
+ while (processingDone != 2) {
+ if (!processingDone) {
+ /* if no child processed */
+ /* pick the child with shortest path length and record which one
+ * picked
+ */
+ if ((NvPathLength < NnvPathLength) ||
+ ((NvPathLength == NnvPathLength) && (tiebreakChild == 1))) {
+ child = Nv;
+ regChild = regNv;
+ thenDone = 1;
+ childPathLength = NvPathLength;
+ } else {
+ child = Nnv;
+ regChild = regNnv;
+ elseDone = 1;
+ childPathLength = NnvPathLength;
+ } /* then path length less than else path length */
+ } else {
+ /* if one child processed, process the other */
+ if (thenDone) {
+ child = Nnv;
+ regChild = regNnv;
+ elseDone = 1;
+ childPathLength = NnvPathLength;
+ } else {
+ child = Nv;
+ regChild = regNv;
+ thenDone = 1;
+ childPathLength = NvPathLength;
+ } /* end of else pick the Then child if ELSE child processed */
+ } /* end of else one child has been processed */
+
+ /* ignore (replace with constant 0) all nodes which lie on paths larger
+ * than the maximum length of the path required
+ */
+ if (childPathLength > info->maxpath) {
+ /* record nodes visited */
+ childBranch = zero;
+ } else {
+ if (childPathLength < info->maxpath) {
+ if (info->findShortestPath) {
+ info->findShortestPath = 0;
+ }
+ childBranch = BuildSubsetBdd(dd, pathTable, child, info,
+ subsetNodeTable);
+
+ } else { /* Case: path length of node = maxpath */
+ /* If the node labeled with maxpath is found in the
+ ** maxpathTable, use it to build the subset BDD. */
+ if (st_lookup(info->maxpathTable, (char *)regChild,
+ (char **)&entry)) {
+ /* When a node that is already been chosen is hit,
+ ** the quest for a complete path is over. */
+ if (info->findShortestPath) {
+ info->findShortestPath = 0;
+ }
+ childBranch = BuildSubsetBdd(dd, pathTable, child, info,
+ subsetNodeTable);
+ } else {
+ /* If node is not found in the maxpathTable and
+ ** the threshold has been reached, then if the
+ ** path needs to be completed, continue. Else
+ ** replace the node with a zero. */
+ if (info->thresholdReached <= 0) {
+ if (info->findShortestPath) {
+ if (st_insert(info->maxpathTable, (char *)regChild,
+ (char *)NIL(char)) == ST_OUT_OF_MEM) {
+ memOut = 1;
+ (void) fprintf(dd->err, "OUT of memory\n");
+ info->thresholdReached = 0;
+ childBranch = zero;
+ } else {
+ info->thresholdReached--;
+ childBranch = BuildSubsetBdd(dd, pathTable,
+ child, info,subsetNodeTable);
+ }
+ } else { /* not find shortest path, we dont need this
+ node */
+ childBranch = zero;
+ }
+ } else { /* Threshold hasn't been reached,
+ ** need the node. */
+ if (st_insert(info->maxpathTable, (char *)regChild,
+ (char *)NIL(char)) == ST_OUT_OF_MEM) {
+ memOut = 1;
+ (void) fprintf(dd->err, "OUT of memory\n");
+ info->thresholdReached = 0;
+ childBranch = zero;
+ } else {
+ info->thresholdReached--;
+ if (info->thresholdReached <= 0) {
+ info->findShortestPath = 1;
+ }
+ childBranch = BuildSubsetBdd(dd, pathTable,
+ child, info, subsetNodeTable);
+
+ } /* end of st_insert successful */
+ } /* end of threshold hasnt been reached yet */
+ } /* end of else node not found in maxpath table */
+ } /* end of if (path length of node = maxpath) */
+ } /* end if !(childPathLength > maxpath) */
+ if (childBranch == NULL) {
+ /* deref other stuff incase reordering has taken place */
+ if (ThenBranch != NULL) {
+ Cudd_RecursiveDeref(dd, ThenBranch);
+ ThenBranch = NULL;
+ }
+ if (ElseBranch != NULL) {
+ Cudd_RecursiveDeref(dd, ElseBranch);
+ ElseBranch = NULL;
+ }
+ return(NULL);
+ }
+
+ cuddRef(childBranch);
+
+ if (child == Nv) {
+ ThenBranch = childBranch;
+ } else {
+ ElseBranch = childBranch;
+ }
+ processingDone++;
+
+ } /*end of while processing Nv, Nnv */
+
+ info->findShortestPath = 0;
+ topid = Cudd_NodeReadIndex(N);
+ topv = Cudd_ReadVars(dd, topid);
+ cuddRef(topv);
+ neW = cuddBddIteRecur(dd, topv, ThenBranch, ElseBranch);
+ if (neW != NULL) {
+ cuddRef(neW);
+ }
+ Cudd_RecursiveDeref(dd, topv);
+ Cudd_RecursiveDeref(dd, ThenBranch);
+ Cudd_RecursiveDeref(dd, ElseBranch);
+
+
+ /* Hard Limit of threshold has been imposed */
+ if (subsetNodeTable != NIL(st_table)) {
+ /* check if a new node is created */
+ regNew = Cudd_Regular(neW);
+ /* subset node table keeps all new nodes that have been created to keep
+ * a running count of how many nodes have been built in the subset.
+ */
+ if (!st_lookup(subsetNodeTable, (char *)regNew, (char **)&entry)) {
+ if (!Cudd_IsConstant(regNew)) {
+ if (st_insert(subsetNodeTable, (char *)regNew,
+ (char *)NULL) == ST_OUT_OF_MEM) {
+ (void) fprintf(dd->err, "Out of memory\n");
+ return (NULL);
+ }
+ if (st_count(subsetNodeTable) > info->threshold) {
+ info->thresholdReached = 0;
+ }
+ }
+ }
+ }
+
+
+ if (neW == NULL) {
+ return(NULL);
+ } else {
+ /*store computed result in regular form*/
+ if (Cudd_IsComplement(node)) {
+ nodeStat->compResult = neW;
+ cuddRef(nodeStat->compResult);
+ /* if the new node is the same as the corresponding node in the
+ * original bdd then its complement need not be computed as it
+ * cannot be larger than the node itself
+ */
+ if (neW == node) {
+#ifdef DD_DEBUG
+ thishit++;
+#endif
+ /* if a result for the node has already been computed, then
+ * it can only be smaller than teh node itself. hence store
+ * the node result in order not to break recombination
+ */
+ if (nodeStat->regResult != NULL) {
+ Cudd_RecursiveDeref(dd, nodeStat->regResult);
+ }
+ nodeStat->regResult = Cudd_Not(neW);
+ cuddRef(nodeStat->regResult);
+ }
+
+ } else {
+ nodeStat->regResult = neW;
+ cuddRef(nodeStat->regResult);
+ if (neW == node) {
+#ifdef DD_DEBUG
+ thishit++;
+#endif
+ if (nodeStat->compResult != NULL) {
+ Cudd_RecursiveDeref(dd, nodeStat->compResult);
+ }
+ nodeStat->compResult = Cudd_Not(neW);
+ cuddRef(nodeStat->compResult);
+ }
+ }
+
+ cuddDeref(neW);
+ return(neW);
+ } /* end of else i.e. Subset != NULL */
+} /* end of BuildSubsetBdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Procedure to free te result dds stored in the NodeDist pages.]
+
+ Description [None]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static enum st_retval
+stPathTableDdFree(
+ char * key,
+ char * value,
+ char * arg)
+{
+ NodeDist_t *nodeStat;
+ DdManager *dd;
+
+ nodeStat = (NodeDist_t *)value;
+ dd = (DdManager *)arg;
+ if (nodeStat->regResult != NULL) {
+ Cudd_RecursiveDeref(dd, nodeStat->regResult);
+ }
+ if (nodeStat->compResult != NULL) {
+ Cudd_RecursiveDeref(dd, nodeStat->compResult);
+ }
+ return(ST_CONTINUE);
+
+} /* end of stPathTableFree */
diff --git a/src/bdd/cudd/cuddSymmetry.c b/src/bdd/cudd/cuddSymmetry.c
new file mode 100644
index 00000000..7b2013e4
--- /dev/null
+++ b/src/bdd/cudd/cuddSymmetry.c
@@ -0,0 +1,1668 @@
+/**CFile***********************************************************************
+
+ FileName [cuddSymmetry.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for symmetry-based variable reordering.]
+
+ Description [External procedures included in this file:
+ <ul>
+ <li> Cudd_SymmProfile()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddSymmCheck()
+ <li> cuddSymmSifting()
+ <li> cuddSymmSiftingConv()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> ddSymmUniqueCompare()
+ <li> ddSymmSiftingAux()
+ <li> ddSymmSiftingConvAux()
+ <li> ddSymmSiftingUp()
+ <li> ddSymmSiftingDown()
+ <li> ddSymmGroupMove()
+ <li> ddSymmGroupMoveBackward()
+ <li> ddSymmSiftingBackward()
+ <li> ddSymmSummary()
+ </ul>]
+
+ Author [Shipra Panda, Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define MV_OOM (Move *)1
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddSymmetry.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+static int *entry;
+
+extern int ddTotalNumberSwapping;
+#ifdef DD_STATS
+extern int ddTotalNISwaps;
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int ddSymmUniqueCompare ARGS((int *ptrX, int *ptrY));
+static int ddSymmSiftingAux ARGS((DdManager *table, int x, int xLow, int xHigh));
+static int ddSymmSiftingConvAux ARGS((DdManager *table, int x, int xLow, int xHigh));
+static Move * ddSymmSiftingUp ARGS((DdManager *table, int y, int xLow));
+static Move * ddSymmSiftingDown ARGS((DdManager *table, int x, int xHigh));
+static int ddSymmGroupMove ARGS((DdManager *table, int x, int y, Move **moves));
+static int ddSymmGroupMoveBackward ARGS((DdManager *table, int x, int y));
+static int ddSymmSiftingBackward ARGS((DdManager *table, Move *moves, int size));
+static void ddSymmSummary ARGS((DdManager *table, int lower, int upper, int *symvars, int *symgroups));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints statistics on symmetric variables.]
+
+ Description []
+
+ SideEffects [None]
+
+******************************************************************************/
+void
+Cudd_SymmProfile(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i,x,gbot;
+ int TotalSymm = 0;
+ int TotalSymmGroups = 0;
+
+ for (i = lower; i <= upper; i++) {
+ if (table->subtables[i].next != (unsigned) i) {
+ x = i;
+ (void) fprintf(table->out,"Group:");
+ do {
+ (void) fprintf(table->out," %d",table->invperm[x]);
+ TotalSymm++;
+ gbot = x;
+ x = table->subtables[x].next;
+ } while (x != i);
+ TotalSymmGroups++;
+#ifdef DD_DEBUG
+ assert(table->subtables[gbot].next == (unsigned) i);
+#endif
+ i = gbot;
+ (void) fprintf(table->out,"\n");
+ }
+ }
+ (void) fprintf(table->out,"Total Symmetric = %d\n",TotalSymm);
+ (void) fprintf(table->out,"Total Groups = %d\n",TotalSymmGroups);
+
+} /* end of Cudd_SymmProfile */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks for symmetry of x and y.]
+
+ Description [Checks for symmetry of x and y. Ignores projection
+ functions, unless they are isolated. Returns 1 in case of symmetry; 0
+ otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+int
+cuddSymmCheck(
+ DdManager * table,
+ int x,
+ int y)
+{
+ DdNode *f,*f0,*f1,*f01,*f00,*f11,*f10;
+ int comple; /* f0 is complemented */
+ int xsymmy; /* x and y may be positively symmetric */
+ int xsymmyp; /* x and y may be negatively symmetric */
+ int arccount; /* number of arcs from layer x to layer y */
+ int TotalRefCount; /* total reference count of layer y minus 1 */
+ int yindex;
+ int i;
+ DdNodePtr *list;
+ int slots;
+ DdNode *sentinel = &(table->sentinel);
+#ifdef DD_DEBUG
+ int xindex;
+#endif
+
+ /* Checks that x and y are not the projection functions.
+ ** For x it is sufficient to check whether there is only one
+ ** node; indeed, if there is one node, it is the projection function
+ ** and it cannot point to y. Hence, if y isn't just the projection
+ ** function, it has one arc coming from a layer different from x.
+ */
+ if (table->subtables[x].keys == 1) {
+ return(0);
+ }
+ yindex = table->invperm[y];
+ if (table->subtables[y].keys == 1) {
+ if (table->vars[yindex]->ref == 1)
+ return(0);
+ }
+
+ xsymmy = xsymmyp = 1;
+ arccount = 0;
+ slots = table->subtables[x].slots;
+ list = table->subtables[x].nodelist;
+ for (i = 0; i < slots; i++) {
+ f = list[i];
+ while (f != sentinel) {
+ /* Find f1, f0, f11, f10, f01, f00. */
+ f1 = cuddT(f);
+ f0 = Cudd_Regular(cuddE(f));
+ comple = Cudd_IsComplement(cuddE(f));
+ if ((int) f1->index == yindex) {
+ arccount++;
+ f11 = cuddT(f1); f10 = cuddE(f1);
+ } else {
+ if ((int) f0->index != yindex) {
+ /* If f is an isolated projection function it is
+ ** allowed to bypass layer y.
+ */
+ if (f1 != DD_ONE(table) || f0 != DD_ONE(table) || f->ref != 1)
+ return(0); /* f bypasses layer y */
+ }
+ f11 = f10 = f1;
+ }
+ if ((int) f0->index == yindex) {
+ arccount++;
+ f01 = cuddT(f0); f00 = cuddE(f0);
+ } else {
+ f01 = f00 = f0;
+ }
+ if (comple) {
+ f01 = Cudd_Not(f01);
+ f00 = Cudd_Not(f00);
+ }
+
+ if (f1 != DD_ONE(table) || f0 != DD_ONE(table) || f->ref != 1) {
+ xsymmy &= f01 == f10;
+ xsymmyp &= f11 == f00;
+ if ((xsymmy == 0) && (xsymmyp == 0))
+ return(0);
+ }
+
+ f = f->next;
+ } /* while */
+ } /* for */
+
+ /* Calculate the total reference counts of y */
+ TotalRefCount = -1; /* -1 for projection function */
+ slots = table->subtables[y].slots;
+ list = table->subtables[y].nodelist;
+ for (i = 0; i < slots; i++) {
+ f = list[i];
+ while (f != sentinel) {
+ TotalRefCount += f->ref;
+ f = f->next;
+ }
+ }
+
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ if (arccount == TotalRefCount) {
+ xindex = table->invperm[x];
+ (void) fprintf(table->out,
+ "Found symmetry! x =%d\ty = %d\tPos(%d,%d)\n",
+ xindex,yindex,x,y);
+ }
+#endif
+
+ return(arccount == TotalRefCount);
+
+} /* end of cuddSymmCheck */
+
+
+/**Function********************************************************************
+
+ Synopsis [Symmetric sifting algorithm.]
+
+ Description [Symmetric sifting algorithm.
+ Assumes that no dead nodes are present.
+ <ol>
+ <li> Order all the variables according to the number of entries in
+ each unique subtable.
+ <li> Sift the variable up and down, remembering each time the total
+ size of the DD heap and grouping variables that are symmetric.
+ <li> Select the best permutation.
+ <li> Repeat 3 and 4 for all variables.
+ </ol>
+ Returns 1 plus the number of symmetric variables if successful; 0
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddSymmSiftingConv]
+
+******************************************************************************/
+int
+cuddSymmSifting(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i;
+ int *var;
+ int size;
+ int x;
+ int result;
+ int symvars;
+ int symgroups;
+#ifdef DD_STATS
+ int previousSize;
+#endif
+
+ size = table->size;
+
+ /* Find order in which to sift variables. */
+ var = NULL;
+ entry = ALLOC(int,size);
+ if (entry == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto ddSymmSiftingOutOfMem;
+ }
+ var = ALLOC(int,size);
+ if (var == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto ddSymmSiftingOutOfMem;
+ }
+
+ for (i = 0; i < size; i++) {
+ x = table->perm[i];
+ entry[i] = table->subtables[x].keys;
+ var[i] = i;
+ }
+
+ qsort((void *)var,size,sizeof(int),(int (*)(const void *, const void *))ddSymmUniqueCompare);
+
+ /* Initialize the symmetry of each subtable to itself. */
+ for (i = lower; i <= upper; i++) {
+ table->subtables[i].next = i;
+ }
+
+ for (i = 0; i < ddMin(table->siftMaxVar,size); i++) {
+ if (ddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ x = table->perm[var[i]];
+#ifdef DD_STATS
+ previousSize = table->keys - table->isolated;
+#endif
+ if (x < lower || x > upper) continue;
+ if (table->subtables[x].next == (unsigned) x) {
+ result = ddSymmSiftingAux(table,x,lower,upper);
+ if (!result) goto ddSymmSiftingOutOfMem;
+#ifdef DD_STATS
+ if (table->keys < (unsigned) previousSize + table->isolated) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keys > (unsigned) previousSize +
+ table->isolated) {
+ (void) fprintf(table->out,"+"); /* should never happen */
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+ }
+
+ FREE(var);
+ FREE(entry);
+
+ ddSymmSummary(table, lower, upper, &symvars, &symgroups);
+
+#ifdef DD_STATS
+ (void) fprintf(table->out, "\n#:S_SIFTING %8d: symmetric variables\n",
+ symvars);
+ (void) fprintf(table->out, "#:G_SIFTING %8d: symmetric groups",
+ symgroups);
+#endif
+
+ return(1+symvars);
+
+ddSymmSiftingOutOfMem:
+
+ if (entry != NULL) FREE(entry);
+ if (var != NULL) FREE(var);
+
+ return(0);
+
+} /* end of cuddSymmSifting */
+
+
+/**Function********************************************************************
+
+ Synopsis [Symmetric sifting to convergence algorithm.]
+
+ Description [Symmetric sifting to convergence algorithm.
+ Assumes that no dead nodes are present.
+ <ol>
+ <li> Order all the variables according to the number of entries in
+ each unique subtable.
+ <li> Sift the variable up and down, remembering each time the total
+ size of the DD heap and grouping variables that are symmetric.
+ <li> Select the best permutation.
+ <li> Repeat 3 and 4 for all variables.
+ <li> Repeat 1-4 until no further improvement.
+ </ol>
+ Returns 1 plus the number of symmetric variables if successful; 0
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddSymmSifting]
+
+******************************************************************************/
+int
+cuddSymmSiftingConv(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i;
+ int *var;
+ int size;
+ int x;
+ int result;
+ int symvars;
+ int symgroups;
+ int classes;
+ int initialSize;
+#ifdef DD_STATS
+ int previousSize;
+#endif
+
+ initialSize = table->keys - table->isolated;
+
+ size = table->size;
+
+ /* Find order in which to sift variables. */
+ var = NULL;
+ entry = ALLOC(int,size);
+ if (entry == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto ddSymmSiftingConvOutOfMem;
+ }
+ var = ALLOC(int,size);
+ if (var == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto ddSymmSiftingConvOutOfMem;
+ }
+
+ for (i = 0; i < size; i++) {
+ x = table->perm[i];
+ entry[i] = table->subtables[x].keys;
+ var[i] = i;
+ }
+
+ qsort((void *)var,size,sizeof(int),(int (*)(const void *, const void *))ddSymmUniqueCompare);
+
+ /* Initialize the symmetry of each subtable to itself
+ ** for first pass of converging symmetric sifting.
+ */
+ for (i = lower; i <= upper; i++) {
+ table->subtables[i].next = i;
+ }
+
+ for (i = 0; i < ddMin(table->siftMaxVar, table->size); i++) {
+ if (ddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ x = table->perm[var[i]];
+ if (x < lower || x > upper) continue;
+ /* Only sift if not in symmetry group already. */
+ if (table->subtables[x].next == (unsigned) x) {
+#ifdef DD_STATS
+ previousSize = table->keys - table->isolated;
+#endif
+ result = ddSymmSiftingAux(table,x,lower,upper);
+ if (!result) goto ddSymmSiftingConvOutOfMem;
+#ifdef DD_STATS
+ if (table->keys < (unsigned) previousSize + table->isolated) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keys > (unsigned) previousSize +
+ table->isolated) {
+ (void) fprintf(table->out,"+");
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+ }
+
+ /* Sifting now until convergence. */
+ while ((unsigned) initialSize > table->keys - table->isolated) {
+ initialSize = table->keys - table->isolated;
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n");
+#endif
+ /* Here we consider only one representative for each symmetry class. */
+ for (x = lower, classes = 0; x <= upper; x++, classes++) {
+ while ((unsigned) x < table->subtables[x].next) {
+ x = table->subtables[x].next;
+ }
+ /* Here x is the largest index in a group.
+ ** Groups consist of adjacent variables.
+ ** Hence, the next increment of x will move it to a new group.
+ */
+ i = table->invperm[x];
+ entry[i] = table->subtables[x].keys;
+ var[classes] = i;
+ }
+
+ qsort((void *)var,classes,sizeof(int),(int (*)(const void *, const void *))ddSymmUniqueCompare);
+
+ /* Now sift. */
+ for (i = 0; i < ddMin(table->siftMaxVar,classes); i++) {
+ if (ddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ x = table->perm[var[i]];
+ if ((unsigned) x >= table->subtables[x].next) {
+#ifdef DD_STATS
+ previousSize = table->keys - table->isolated;
+#endif
+ result = ddSymmSiftingConvAux(table,x,lower,upper);
+ if (!result ) goto ddSymmSiftingConvOutOfMem;
+#ifdef DD_STATS
+ if (table->keys < (unsigned) previousSize + table->isolated) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keys > (unsigned) previousSize +
+ table->isolated) {
+ (void) fprintf(table->out,"+");
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+ } /* for */
+ }
+
+ ddSymmSummary(table, lower, upper, &symvars, &symgroups);
+
+#ifdef DD_STATS
+ (void) fprintf(table->out, "\n#:S_SIFTING %8d: symmetric variables\n",
+ symvars);
+ (void) fprintf(table->out, "#:G_SIFTING %8d: symmetric groups",
+ symgroups);
+#endif
+
+ FREE(var);
+ FREE(entry);
+
+ return(1+symvars);
+
+ddSymmSiftingConvOutOfMem:
+
+ if (entry != NULL) FREE(entry);
+ if (var != NULL) FREE(var);
+
+ return(0);
+
+} /* end of cuddSymmSiftingConv */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Comparison function used by qsort.]
+
+ Description [Comparison function used by qsort to order the variables
+ according to the number of keys in the subtables.
+ Returns the difference in number of keys between the two
+ variables being compared.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddSymmUniqueCompare(
+ int * ptrX,
+ int * ptrY)
+{
+#if 0
+ if (entry[*ptrY] == entry[*ptrX]) {
+ return((*ptrX) - (*ptrY));
+ }
+#endif
+ return(entry[*ptrY] - entry[*ptrX]);
+
+} /* end of ddSymmUniqueCompare */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries.]
+
+ Description [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries. Finds the best position and does the required changes.
+ Assumes that x is not part of a symmetry group. Returns 1 if
+ successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddSymmSiftingAux(
+ DdManager * table,
+ int x,
+ int xLow,
+ int xHigh)
+{
+ Move *move;
+ Move *moveUp; /* list of up moves */
+ Move *moveDown; /* list of down moves */
+ int initialSize;
+ int result;
+ int i;
+ int topbot; /* index to either top or bottom of symmetry group */
+ int initGroupSize, finalGroupSize;
+
+
+#ifdef DD_DEBUG
+ /* check for previously detected symmetry */
+ assert(table->subtables[x].next == (unsigned) x);
+#endif
+
+ initialSize = table->keys - table->isolated;
+
+ moveDown = NULL;
+ moveUp = NULL;
+
+ if ((x - xLow) > (xHigh - x)) {
+ /* Will go down first, unless x == xHigh:
+ ** Look for consecutive symmetries above x.
+ */
+ for (i = x; i > xLow; i--) {
+ if (!cuddSymmCheck(table,i-1,i))
+ break;
+ topbot = table->subtables[i-1].next; /* find top of i-1's group */
+ table->subtables[i-1].next = i;
+ table->subtables[x].next = topbot; /* x is bottom of group so its */
+ /* next is top of i-1's group */
+ i = topbot + 1; /* add 1 for i--; new i is top of symm group */
+ }
+ } else {
+ /* Will go up first unless x == xlow:
+ ** Look for consecutive symmetries below x.
+ */
+ for (i = x; i < xHigh; i++) {
+ if (!cuddSymmCheck(table,i,i+1))
+ break;
+ /* find bottom of i+1's symm group */
+ topbot = i + 1;
+ while ((unsigned) topbot < table->subtables[topbot].next) {
+ topbot = table->subtables[topbot].next;
+ }
+ table->subtables[topbot].next = table->subtables[i].next;
+ table->subtables[i].next = i + 1;
+ i = topbot - 1; /* subtract 1 for i++; new i is bottom of group */
+ }
+ }
+
+ /* Now x may be in the middle of a symmetry group.
+ ** Find bottom of x's symm group.
+ */
+ while ((unsigned) x < table->subtables[x].next)
+ x = table->subtables[x].next;
+
+ if (x == xLow) { /* Sift down */
+
+#ifdef DD_DEBUG
+ /* x must be a singleton */
+ assert((unsigned) x == table->subtables[x].next);
+#endif
+ if (x == xHigh) return(1); /* just one variable */
+
+ initGroupSize = 1;
+
+ moveDown = ddSymmSiftingDown(table,x,xHigh);
+ /* after this point x --> xHigh, unless early term */
+ if (moveDown == MV_OOM) goto ddSymmSiftingAuxOutOfMem;
+ if (moveDown == NULL) return(1);
+
+ x = moveDown->y;
+ /* Find bottom of x's group */
+ i = x;
+ while ((unsigned) i < table->subtables[i].next) {
+ i = table->subtables[i].next;
+ }
+#ifdef DD_DEBUG
+ /* x should be the top of the symmetry group and i the bottom */
+ assert((unsigned) i >= table->subtables[i].next);
+ assert((unsigned) x == table->subtables[i].next);
+#endif
+ finalGroupSize = i - x + 1;
+
+ if (initGroupSize == finalGroupSize) {
+ /* No new symmetry groups detected, return to best position */
+ result = ddSymmSiftingBackward(table,moveDown,initialSize);
+ } else {
+ initialSize = table->keys - table->isolated;
+ moveUp = ddSymmSiftingUp(table,x,xLow);
+ result = ddSymmSiftingBackward(table,moveUp,initialSize);
+ }
+ if (!result) goto ddSymmSiftingAuxOutOfMem;
+
+ } else if (cuddNextHigh(table,x) > xHigh) { /* Sift up */
+ /* Find top of x's symm group */
+ i = x; /* bottom */
+ x = table->subtables[x].next; /* top */
+
+ if (x == xLow) return(1); /* just one big group */
+
+ initGroupSize = i - x + 1;
+
+ moveUp = ddSymmSiftingUp(table,x,xLow);
+ /* after this point x --> xLow, unless early term */
+ if (moveUp == MV_OOM) goto ddSymmSiftingAuxOutOfMem;
+ if (moveUp == NULL) return(1);
+
+ x = moveUp->x;
+ /* Find top of x's group */
+ i = table->subtables[x].next;
+#ifdef DD_DEBUG
+ /* x should be the bottom of the symmetry group and i the top */
+ assert((unsigned) x >= table->subtables[x].next);
+ assert((unsigned) i == table->subtables[x].next);
+#endif
+ finalGroupSize = x - i + 1;
+
+ if (initGroupSize == finalGroupSize) {
+ /* No new symmetry groups detected, return to best position */
+ result = ddSymmSiftingBackward(table,moveUp,initialSize);
+ } else {
+ initialSize = table->keys - table->isolated;
+ moveDown = ddSymmSiftingDown(table,x,xHigh);
+ result = ddSymmSiftingBackward(table,moveDown,initialSize);
+ }
+ if (!result) goto ddSymmSiftingAuxOutOfMem;
+
+ } else if ((x - xLow) > (xHigh - x)) { /* must go down first: shorter */
+
+ moveDown = ddSymmSiftingDown(table,x,xHigh);
+ /* at this point x == xHigh, unless early term */
+ if (moveDown == MV_OOM) goto ddSymmSiftingAuxOutOfMem;
+
+ if (moveDown != NULL) {
+ x = moveDown->y; /* x is top here */
+ i = x;
+ while ((unsigned) i < table->subtables[i].next) {
+ i = table->subtables[i].next;
+ }
+ } else {
+ i = x;
+ while ((unsigned) i < table->subtables[i].next) {
+ i = table->subtables[i].next;
+ }
+ x = table->subtables[i].next;
+ }
+#ifdef DD_DEBUG
+ /* x should be the top of the symmetry group and i the bottom */
+ assert((unsigned) i >= table->subtables[i].next);
+ assert((unsigned) x == table->subtables[i].next);
+#endif
+ initGroupSize = i - x + 1;
+
+ moveUp = ddSymmSiftingUp(table,x,xLow);
+ if (moveUp == MV_OOM) goto ddSymmSiftingAuxOutOfMem;
+
+ if (moveUp != NULL) {
+ x = moveUp->x;
+ i = table->subtables[x].next;
+ } else {
+ i = x;
+ while ((unsigned) x < table->subtables[x].next)
+ x = table->subtables[x].next;
+ }
+#ifdef DD_DEBUG
+ /* x should be the bottom of the symmetry group and i the top */
+ assert((unsigned) x >= table->subtables[x].next);
+ assert((unsigned) i == table->subtables[x].next);
+#endif
+ finalGroupSize = x - i + 1;
+
+ if (initGroupSize == finalGroupSize) {
+ /* No new symmetry groups detected, return to best position */
+ result = ddSymmSiftingBackward(table,moveUp,initialSize);
+ } else {
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *) moveDown);
+ moveDown = move;
+ }
+ initialSize = table->keys - table->isolated;
+ moveDown = ddSymmSiftingDown(table,x,xHigh);
+ result = ddSymmSiftingBackward(table,moveDown,initialSize);
+ }
+ if (!result) goto ddSymmSiftingAuxOutOfMem;
+
+ } else { /* moving up first: shorter */
+ /* Find top of x's symmetry group */
+ x = table->subtables[x].next;
+
+ moveUp = ddSymmSiftingUp(table,x,xLow);
+ /* at this point x == xHigh, unless early term */
+ if (moveUp == MV_OOM) goto ddSymmSiftingAuxOutOfMem;
+
+ if (moveUp != NULL) {
+ x = moveUp->x;
+ i = table->subtables[x].next;
+ } else {
+ while ((unsigned) x < table->subtables[x].next)
+ x = table->subtables[x].next;
+ i = table->subtables[x].next;
+ }
+#ifdef DD_DEBUG
+ /* x is bottom of the symmetry group and i is top */
+ assert((unsigned) x >= table->subtables[x].next);
+ assert((unsigned) i == table->subtables[x].next);
+#endif
+ initGroupSize = x - i + 1;
+
+ moveDown = ddSymmSiftingDown(table,x,xHigh);
+ if (moveDown == MV_OOM) goto ddSymmSiftingAuxOutOfMem;
+
+ if (moveDown != NULL) {
+ x = moveDown->y;
+ i = x;
+ while ((unsigned) i < table->subtables[i].next) {
+ i = table->subtables[i].next;
+ }
+ } else {
+ i = x;
+ x = table->subtables[x].next;
+ }
+#ifdef DD_DEBUG
+ /* x should be the top of the symmetry group and i the bottom */
+ assert((unsigned) i >= table->subtables[i].next);
+ assert((unsigned) x == table->subtables[i].next);
+#endif
+ finalGroupSize = i - x + 1;
+
+ if (initGroupSize == finalGroupSize) {
+ /* No new symmetries detected, go back to best position */
+ result = ddSymmSiftingBackward(table,moveDown,initialSize);
+ } else {
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *) moveUp);
+ moveUp = move;
+ }
+ initialSize = table->keys - table->isolated;
+ moveUp = ddSymmSiftingUp(table,x,xLow);
+ result = ddSymmSiftingBackward(table,moveUp,initialSize);
+ }
+ if (!result) goto ddSymmSiftingAuxOutOfMem;
+ }
+
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *) moveDown);
+ moveDown = move;
+ }
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *) moveUp);
+ moveUp = move;
+ }
+
+ return(1);
+
+ddSymmSiftingAuxOutOfMem:
+ if (moveDown != MV_OOM) {
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *) moveDown);
+ moveDown = move;
+ }
+ }
+ if (moveUp != MV_OOM) {
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *) moveUp);
+ moveUp = move;
+ }
+ }
+
+ return(0);
+
+} /* end of ddSymmSiftingAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries.]
+
+ Description [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries. Finds the best position and does the required changes.
+ Assumes that x is either an isolated variable, or it is the bottom of
+ a symmetry group. All symmetries may not have been found, because of
+ exceeded growth limit. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddSymmSiftingConvAux(
+ DdManager * table,
+ int x,
+ int xLow,
+ int xHigh)
+{
+ Move *move;
+ Move *moveUp; /* list of up moves */
+ Move *moveDown; /* list of down moves */
+ int initialSize;
+ int result;
+ int i;
+ int initGroupSize, finalGroupSize;
+
+
+ initialSize = table->keys - table->isolated;
+
+ moveDown = NULL;
+ moveUp = NULL;
+
+ if (x == xLow) { /* Sift down */
+#ifdef DD_DEBUG
+ /* x is bottom of symmetry group */
+ assert((unsigned) x >= table->subtables[x].next);
+#endif
+ i = table->subtables[x].next;
+ initGroupSize = x - i + 1;
+
+ moveDown = ddSymmSiftingDown(table,x,xHigh);
+ /* at this point x == xHigh, unless early term */
+ if (moveDown == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem;
+ if (moveDown == NULL) return(1);
+
+ x = moveDown->y;
+ i = x;
+ while ((unsigned) i < table->subtables[i].next) {
+ i = table->subtables[i].next;
+ }
+#ifdef DD_DEBUG
+ /* x should be the top of the symmetric group and i the bottom */
+ assert((unsigned) i >= table->subtables[i].next);
+ assert((unsigned) x == table->subtables[i].next);
+#endif
+ finalGroupSize = i - x + 1;
+
+ if (initGroupSize == finalGroupSize) {
+ /* No new symmetries detected, go back to best position */
+ result = ddSymmSiftingBackward(table,moveDown,initialSize);
+ } else {
+ initialSize = table->keys - table->isolated;
+ moveUp = ddSymmSiftingUp(table,x,xLow);
+ result = ddSymmSiftingBackward(table,moveUp,initialSize);
+ }
+ if (!result) goto ddSymmSiftingConvAuxOutOfMem;
+
+ } else if (cuddNextHigh(table,x) > xHigh) { /* Sift up */
+ /* Find top of x's symm group */
+ while ((unsigned) x < table->subtables[x].next)
+ x = table->subtables[x].next;
+ i = x; /* bottom */
+ x = table->subtables[x].next; /* top */
+
+ if (x == xLow) return(1);
+
+ initGroupSize = i - x + 1;
+
+ moveUp = ddSymmSiftingUp(table,x,xLow);
+ /* at this point x == xLow, unless early term */
+ if (moveUp == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem;
+ if (moveUp == NULL) return(1);
+
+ x = moveUp->x;
+ i = table->subtables[x].next;
+#ifdef DD_DEBUG
+ /* x should be the bottom of the symmetry group and i the top */
+ assert((unsigned) x >= table->subtables[x].next);
+ assert((unsigned) i == table->subtables[x].next);
+#endif
+ finalGroupSize = x - i + 1;
+
+ if (initGroupSize == finalGroupSize) {
+ /* No new symmetry groups detected, return to best position */
+ result = ddSymmSiftingBackward(table,moveUp,initialSize);
+ } else {
+ initialSize = table->keys - table->isolated;
+ moveDown = ddSymmSiftingDown(table,x,xHigh);
+ result = ddSymmSiftingBackward(table,moveDown,initialSize);
+ }
+ if (!result)
+ goto ddSymmSiftingConvAuxOutOfMem;
+
+ } else if ((x - xLow) > (xHigh - x)) { /* must go down first: shorter */
+ moveDown = ddSymmSiftingDown(table,x,xHigh);
+ /* at this point x == xHigh, unless early term */
+ if (moveDown == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem;
+
+ if (moveDown != NULL) {
+ x = moveDown->y;
+ i = x;
+ while ((unsigned) i < table->subtables[i].next) {
+ i = table->subtables[i].next;
+ }
+ } else {
+ while ((unsigned) x < table->subtables[x].next)
+ x = table->subtables[x].next;
+ i = x;
+ x = table->subtables[x].next;
+ }
+#ifdef DD_DEBUG
+ /* x should be the top of the symmetry group and i the bottom */
+ assert((unsigned) i >= table->subtables[i].next);
+ assert((unsigned) x == table->subtables[i].next);
+#endif
+ initGroupSize = i - x + 1;
+
+ moveUp = ddSymmSiftingUp(table,x,xLow);
+ if (moveUp == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem;
+
+ if (moveUp != NULL) {
+ x = moveUp->x;
+ i = table->subtables[x].next;
+ } else {
+ i = x;
+ while ((unsigned) x < table->subtables[x].next)
+ x = table->subtables[x].next;
+ }
+#ifdef DD_DEBUG
+ /* x should be the bottom of the symmetry group and i the top */
+ assert((unsigned) x >= table->subtables[x].next);
+ assert((unsigned) i == table->subtables[x].next);
+#endif
+ finalGroupSize = x - i + 1;
+
+ if (initGroupSize == finalGroupSize) {
+ /* No new symmetry groups detected, return to best position */
+ result = ddSymmSiftingBackward(table,moveUp,initialSize);
+ } else {
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *) moveDown);
+ moveDown = move;
+ }
+ initialSize = table->keys - table->isolated;
+ moveDown = ddSymmSiftingDown(table,x,xHigh);
+ result = ddSymmSiftingBackward(table,moveDown,initialSize);
+ }
+ if (!result) goto ddSymmSiftingConvAuxOutOfMem;
+
+ } else { /* moving up first: shorter */
+ /* Find top of x's symmetry group */
+ x = table->subtables[x].next;
+
+ moveUp = ddSymmSiftingUp(table,x,xLow);
+ /* at this point x == xHigh, unless early term */
+ if (moveUp == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem;
+
+ if (moveUp != NULL) {
+ x = moveUp->x;
+ i = table->subtables[x].next;
+ } else {
+ i = x;
+ while ((unsigned) x < table->subtables[x].next)
+ x = table->subtables[x].next;
+ }
+#ifdef DD_DEBUG
+ /* x is bottom of the symmetry group and i is top */
+ assert((unsigned) x >= table->subtables[x].next);
+ assert((unsigned) i == table->subtables[x].next);
+#endif
+ initGroupSize = x - i + 1;
+
+ moveDown = ddSymmSiftingDown(table,x,xHigh);
+ if (moveDown == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem;
+
+ if (moveDown != NULL) {
+ x = moveDown->y;
+ i = x;
+ while ((unsigned) i < table->subtables[i].next) {
+ i = table->subtables[i].next;
+ }
+ } else {
+ i = x;
+ x = table->subtables[x].next;
+ }
+#ifdef DD_DEBUG
+ /* x should be the top of the symmetry group and i the bottom */
+ assert((unsigned) i >= table->subtables[i].next);
+ assert((unsigned) x == table->subtables[i].next);
+#endif
+ finalGroupSize = i - x + 1;
+
+ if (initGroupSize == finalGroupSize) {
+ /* No new symmetries detected, go back to best position */
+ result = ddSymmSiftingBackward(table,moveDown,initialSize);
+ } else {
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *) moveUp);
+ moveUp = move;
+ }
+ initialSize = table->keys - table->isolated;
+ moveUp = ddSymmSiftingUp(table,x,xLow);
+ result = ddSymmSiftingBackward(table,moveUp,initialSize);
+ }
+ if (!result) goto ddSymmSiftingConvAuxOutOfMem;
+ }
+
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *) moveDown);
+ moveDown = move;
+ }
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *) moveUp);
+ moveUp = move;
+ }
+
+ return(1);
+
+ddSymmSiftingConvAuxOutOfMem:
+ if (moveDown != MV_OOM) {
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *) moveDown);
+ moveDown = move;
+ }
+ }
+ if (moveUp != MV_OOM) {
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *) moveUp);
+ moveUp = move;
+ }
+ }
+
+ return(0);
+
+} /* end of ddSymmSiftingConvAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Moves x up until either it reaches the bound (xLow) or
+ the size of the DD heap increases too much.]
+
+ Description [Moves x up until either it reaches the bound (xLow) or
+ the size of the DD heap increases too much. Assumes that x is the top
+ of a symmetry group. Checks x for symmetry to the adjacent
+ variables. If symmetry is found, the symmetry group of x is merged
+ with the symmetry group of the other variable. Returns the set of
+ moves in case of success; MV_OOM if memory is full.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static Move *
+ddSymmSiftingUp(
+ DdManager * table,
+ int y,
+ int xLow)
+{
+ Move *moves;
+ Move *move;
+ int x;
+ int size;
+ int i;
+ int gxtop,gybot;
+ int limitSize;
+ int xindex, yindex;
+ int zindex;
+ int z;
+ int isolated;
+ int L; /* lower bound on DD size */
+#ifdef DD_DEBUG
+ int checkL;
+#endif
+
+
+ moves = NULL;
+ yindex = table->invperm[y];
+
+ /* Initialize the lower bound.
+ ** The part of the DD below the bottom of y' group will not change.
+ ** The part of the DD above y that does not interact with y will not
+ ** change. The rest may vanish in the best case, except for
+ ** the nodes at level xLow, which will not vanish, regardless.
+ */
+ limitSize = L = table->keys - table->isolated;
+ gybot = y;
+ while ((unsigned) gybot < table->subtables[gybot].next)
+ gybot = table->subtables[gybot].next;
+ for (z = xLow + 1; z <= gybot; z++) {
+ zindex = table->invperm[z];
+ if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ L -= table->subtables[z].keys - isolated;
+ }
+ }
+
+ x = cuddNextLow(table,y);
+ while (x >= xLow && L <= limitSize) {
+#ifdef DD_DEBUG
+ gybot = y;
+ while ((unsigned) gybot < table->subtables[gybot].next)
+ gybot = table->subtables[gybot].next;
+ checkL = table->keys - table->isolated;
+ for (z = xLow + 1; z <= gybot; z++) {
+ zindex = table->invperm[z];
+ if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ checkL -= table->subtables[z].keys - isolated;
+ }
+ }
+ assert(L == checkL);
+#endif
+ gxtop = table->subtables[x].next;
+ if (cuddSymmCheck(table,x,y)) {
+ /* Symmetry found, attach symm groups */
+ table->subtables[x].next = y;
+ i = table->subtables[y].next;
+ while (table->subtables[i].next != (unsigned) y)
+ i = table->subtables[i].next;
+ table->subtables[i].next = gxtop;
+ } else if (table->subtables[x].next == (unsigned) x &&
+ table->subtables[y].next == (unsigned) y) {
+ /* x and y have self symmetry */
+ xindex = table->invperm[x];
+ size = cuddSwapInPlace(table,x,y);
+#ifdef DD_DEBUG
+ assert(table->subtables[x].next == (unsigned) x);
+ assert(table->subtables[y].next == (unsigned) y);
+#endif
+ if (size == 0) goto ddSymmSiftingUpOutOfMem;
+ /* Update the lower bound. */
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[xindex]->ref == 1;
+ L += table->subtables[y].keys - isolated;
+ }
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddSymmSiftingUpOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(moves);
+ if (size < limitSize) limitSize = size;
+ } else { /* Group move */
+ size = ddSymmGroupMove(table,x,y,&moves);
+ if (size == 0) goto ddSymmSiftingUpOutOfMem;
+ /* Update the lower bound. */
+ z = moves->y;
+ do {
+ zindex = table->invperm[z];
+ if (cuddTestInteract(table,zindex,yindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ L += table->subtables[z].keys - isolated;
+ }
+ z = table->subtables[z].next;
+ } while (z != (int) moves->y);
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(moves);
+ if (size < limitSize) limitSize = size;
+ }
+ y = gxtop;
+ x = cuddNextLow(table,y);
+ }
+
+ return(moves);
+
+ddSymmSiftingUpOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return(MV_OOM);
+
+} /* end of ddSymmSiftingUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Moves x down until either it reaches the bound (xHigh) or
+ the size of the DD heap increases too much.]
+
+ Description [Moves x down until either it reaches the bound (xHigh)
+ or the size of the DD heap increases too much. Assumes that x is the
+ bottom of a symmetry group. Checks x for symmetry to the adjacent
+ variables. If symmetry is found, the symmetry group of x is merged
+ with the symmetry group of the other variable. Returns the set of
+ moves in case of success; MV_OOM if memory is full.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static Move *
+ddSymmSiftingDown(
+ DdManager * table,
+ int x,
+ int xHigh)
+{
+ Move *moves;
+ Move *move;
+ int y;
+ int size;
+ int limitSize;
+ int gxtop,gybot;
+ int R; /* upper bound on node decrease */
+ int xindex, yindex;
+ int isolated;
+ int z;
+ int zindex;
+#ifdef DD_DEBUG
+ int checkR;
+#endif
+
+ moves = NULL;
+ /* Initialize R */
+ xindex = table->invperm[x];
+ gxtop = table->subtables[x].next;
+ limitSize = size = table->keys - table->isolated;
+ R = 0;
+ for (z = xHigh; z > gxtop; z--) {
+ zindex = table->invperm[z];
+ if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ R += table->subtables[z].keys - isolated;
+ }
+ }
+
+ y = cuddNextHigh(table,x);
+ while (y <= xHigh && size - R < limitSize) {
+#ifdef DD_DEBUG
+ gxtop = table->subtables[x].next;
+ checkR = 0;
+ for (z = xHigh; z > gxtop; z--) {
+ zindex = table->invperm[z];
+ if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ checkR += table->subtables[z].keys - isolated;
+ }
+ }
+ assert(R == checkR);
+#endif
+ gybot = table->subtables[y].next;
+ while (table->subtables[gybot].next != (unsigned) y)
+ gybot = table->subtables[gybot].next;
+ if (cuddSymmCheck(table,x,y)) {
+ /* Symmetry found, attach symm groups */
+ gxtop = table->subtables[x].next;
+ table->subtables[x].next = y;
+ table->subtables[gybot].next = gxtop;
+ } else if (table->subtables[x].next == (unsigned) x &&
+ table->subtables[y].next == (unsigned) y) {
+ /* x and y have self symmetry */
+ /* Update upper bound on node decrease. */
+ yindex = table->invperm[y];
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[yindex]->ref == 1;
+ R -= table->subtables[y].keys - isolated;
+ }
+ size = cuddSwapInPlace(table,x,y);
+#ifdef DD_DEBUG
+ assert(table->subtables[x].next == (unsigned) x);
+ assert(table->subtables[y].next == (unsigned) y);
+#endif
+ if (size == 0) goto ddSymmSiftingDownOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddSymmSiftingDownOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(moves);
+ if (size < limitSize) limitSize = size;
+ } else { /* Group move */
+ /* Update upper bound on node decrease: first phase. */
+ gxtop = table->subtables[x].next;
+ z = gxtop + 1;
+ do {
+ zindex = table->invperm[z];
+ if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ R -= table->subtables[z].keys - isolated;
+ }
+ z++;
+ } while (z <= gybot);
+ size = ddSymmGroupMove(table,x,y,&moves);
+ if (size == 0) goto ddSymmSiftingDownOutOfMem;
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(moves);
+ if (size < limitSize) limitSize = size;
+ /* Update upper bound on node decrease: second phase. */
+ gxtop = table->subtables[gybot].next;
+ for (z = gxtop + 1; z <= gybot; z++) {
+ zindex = table->invperm[z];
+ if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ R += table->subtables[z].keys - isolated;
+ }
+ }
+ }
+ x = gybot;
+ y = cuddNextHigh(table,x);
+ }
+
+ return(moves);
+
+ddSymmSiftingDownOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return(MV_OOM);
+
+} /* end of ddSymmSiftingDown */
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps two groups.]
+
+ Description [Swaps two groups. x is assumed to be the bottom variable
+ of the first group. y is assumed to be the top variable of the second
+ group. Updates the list of moves. Returns the number of keys in the
+ table if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddSymmGroupMove(
+ DdManager * table,
+ int x,
+ int y,
+ Move ** moves)
+{
+ Move *move;
+ int size;
+ int i,j;
+ int xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
+ int swapx,swapy;
+
+#if DD_DEBUG
+ assert(x < y); /* we assume that x < y */
+#endif
+ /* Find top, bottom, and size for the two groups. */
+ xbot = x;
+ xtop = table->subtables[x].next;
+ xsize = xbot - xtop + 1;
+ ybot = y;
+ while ((unsigned) ybot < table->subtables[ybot].next)
+ ybot = table->subtables[ybot].next;
+ ytop = y;
+ ysize = ybot - ytop + 1;
+
+ /* Sift the variables of the second group up through the first group. */
+ for (i = 1; i <= ysize; i++) {
+ for (j = 1; j <= xsize; j++) {
+ size = cuddSwapInPlace(table,x,y);
+ if (size == 0) return(0);
+ swapx = x; swapy = y;
+ y = x;
+ x = y - 1;
+ }
+ y = ytop + i;
+ x = y - 1;
+ }
+
+ /* fix symmetries */
+ y = xtop; /* ytop is now where xtop used to be */
+ for (i = 0; i < ysize-1 ; i++) {
+ table->subtables[y].next = y + 1;
+ y = y + 1;
+ }
+ table->subtables[y].next = xtop; /* y is bottom of its group, join */
+ /* its symmetry to top of its group */
+ x = y + 1;
+ newxtop = x;
+ for (i = 0; i < xsize - 1 ; i++) {
+ table->subtables[x].next = x + 1;
+ x = x + 1;
+ }
+ table->subtables[x].next = newxtop; /* x is bottom of its group, join */
+ /* its symmetry to top of its group */
+ /* Store group move */
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) return(0);
+ move->x = swapx;
+ move->y = swapy;
+ move->size = size;
+ move->next = *moves;
+ *moves = move;
+
+ return(size);
+
+} /* end of ddSymmGroupMove */
+
+
+/**Function********************************************************************
+
+ Synopsis [Undoes the swap of two groups.]
+
+ Description [Undoes the swap of two groups. x is assumed to be the
+ bottom variable of the first group. y is assumed to be the top
+ variable of the second group. Returns the number of keys in the table
+ if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddSymmGroupMoveBackward(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int size;
+ int i,j;
+ int xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
+
+#if DD_DEBUG
+ assert(x < y); /* We assume that x < y */
+#endif
+
+ /* Find top, bottom, and size for the two groups. */
+ xbot = x;
+ xtop = table->subtables[x].next;
+ xsize = xbot - xtop + 1;
+ ybot = y;
+ while ((unsigned) ybot < table->subtables[ybot].next)
+ ybot = table->subtables[ybot].next;
+ ytop = y;
+ ysize = ybot - ytop + 1;
+
+ /* Sift the variables of the second group up through the first group. */
+ for (i = 1; i <= ysize; i++) {
+ for (j = 1; j <= xsize; j++) {
+ size = cuddSwapInPlace(table,x,y);
+ if (size == 0) return(0);
+ y = x;
+ x = cuddNextLow(table,y);
+ }
+ y = ytop + i;
+ x = y - 1;
+ }
+
+ /* Fix symmetries. */
+ y = xtop;
+ for (i = 0; i < ysize-1 ; i++) {
+ table->subtables[y].next = y + 1;
+ y = y + 1;
+ }
+ table->subtables[y].next = xtop; /* y is bottom of its group, join */
+ /* its symmetry to top of its group */
+ x = y + 1;
+ newxtop = x;
+ for (i = 0; i < xsize-1 ; i++) {
+ table->subtables[x].next = x + 1;
+ x = x + 1;
+ }
+ table->subtables[x].next = newxtop; /* x is bottom of its group, join */
+ /* its symmetry to top of its group */
+
+ return(size);
+
+} /* end of ddSymmGroupMoveBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given a set of moves, returns the DD heap to the position
+ giving the minimum size.]
+
+ Description [Given a set of moves, returns the DD heap to the
+ position giving the minimum size. In case of ties, returns to the
+ closest position giving the minimum size. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddSymmSiftingBackward(
+ DdManager * table,
+ Move * moves,
+ int size)
+{
+ Move *move;
+ int res;
+
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size < size) {
+ size = move->size;
+ }
+ }
+
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size == size) return(1);
+ if (table->subtables[move->x].next == move->x && table->subtables[move->y].next == move->y) {
+ res = cuddSwapInPlace(table,(int)move->x,(int)move->y);
+#ifdef DD_DEBUG
+ assert(table->subtables[move->x].next == move->x);
+ assert(table->subtables[move->y].next == move->y);
+#endif
+ } else { /* Group move necessary */
+ res = ddSymmGroupMoveBackward(table,(int)move->x,(int)move->y);
+ }
+ if (!res) return(0);
+ }
+
+ return(1);
+
+} /* end of ddSymmSiftingBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts numbers of symmetric variables and symmetry
+ groups.]
+
+ Description []
+
+ SideEffects [None]
+
+******************************************************************************/
+static void
+ddSymmSummary(
+ DdManager * table,
+ int lower,
+ int upper,
+ int * symvars,
+ int * symgroups)
+{
+ int i,x,gbot;
+ int TotalSymm = 0;
+ int TotalSymmGroups = 0;
+
+ for (i = lower; i <= upper; i++) {
+ if (table->subtables[i].next != (unsigned) i) {
+ TotalSymmGroups++;
+ x = i;
+ do {
+ TotalSymm++;
+ gbot = x;
+ x = table->subtables[x].next;
+ } while (x != i);
+#ifdef DD_DEBUG
+ assert(table->subtables[gbot].next == (unsigned) i);
+#endif
+ i = gbot;
+ }
+ }
+ *symvars = TotalSymm;
+ *symgroups = TotalSymmGroups;
+
+ return;
+
+} /* end of ddSymmSummary */
diff --git a/src/bdd/cudd/cuddTable.c b/src/bdd/cudd/cuddTable.c
new file mode 100644
index 00000000..b118b76a
--- /dev/null
+++ b/src/bdd/cudd/cuddTable.c
@@ -0,0 +1,3141 @@
+/**CFile***********************************************************************
+
+ FileName [cuddTable.c]
+
+ PackageName [cudd]
+
+ Synopsis [Unique table management functions.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_Prime()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddAllocNode()
+ <li> cuddInitTable()
+ <li> cuddFreeTable()
+ <li> cuddGarbageCollect()
+ <li> cuddGarbageCollectZdd()
+ <li> cuddZddGetNode()
+ <li> cuddZddGetNodeIVO()
+ <li> cuddUniqueInter()
+ <li> cuddUniqueInterIVO()
+ <li> cuddUniqueInterZdd()
+ <li> cuddUniqueConst()
+ <li> cuddRehash()
+ <li> cuddShrinkSubtable()
+ <li> cuddInsertSubtables()
+ <li> cuddDestroySubtables()
+ <li> cuddResizeTableZdd()
+ <li> cuddSlowTableGrowth()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> ddRehashZdd()
+ <li> ddResizeTable()
+ <li> cuddFindParent()
+ <li> cuddOrderedInsert()
+ <li> cuddOrderedThread()
+ <li> cuddRotateLeft()
+ <li> cuddRotateRight()
+ <li> cuddDoRebalance()
+ <li> cuddCheckCollisionOrdering()
+ </ul>]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef DD_UNSORTED_FREE_LIST
+/* Constants for red/black trees. */
+#define DD_STACK_SIZE 128
+#define DD_RED 0
+#define DD_BLACK 1
+#define DD_PAGE_SIZE 8192
+#define DD_PAGE_MASK ~(DD_PAGE_SIZE - 1)
+#define DD_INSERT_COMPARE(x,y) \
+ (((ptruint) (x) & DD_PAGE_MASK) - ((ptruint) (y) & DD_PAGE_MASK))
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/* This is a hack for when CUDD_VALUE_TYPE is double */
+typedef union hack {
+ CUDD_VALUE_TYPE value;
+ unsigned int bits[2];
+} hack;
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddTable.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+#ifndef DD_UNSORTED_FREE_LIST
+/* Macros for red/black trees. */
+#define DD_COLOR(p) ((p)->index)
+#define DD_IS_BLACK(p) ((p)->index == DD_BLACK)
+#define DD_IS_RED(p) ((p)->index == DD_RED)
+#define DD_LEFT(p) cuddT(p)
+#define DD_RIGHT(p) cuddE(p)
+#define DD_NEXT(p) ((p)->next)
+#endif
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static void ddRehashZdd ARGS((DdManager *unique, int i));
+static int ddResizeTable ARGS((DdManager *unique, int index));
+static int cuddFindParent ARGS((DdManager *table, DdNode *node));
+DD_INLINE static void ddFixLimits ARGS((DdManager *unique));
+static void cuddOrderedInsert ARGS((DdNodePtr *root, DdNodePtr node));
+static DdNode * cuddOrderedThread ARGS((DdNode *root, DdNode *list));
+static void cuddRotateLeft ARGS((DdNodePtr *nodeP));
+static void cuddRotateRight ARGS((DdNodePtr *nodeP));
+static void cuddDoRebalance ARGS((DdNodePtr **stack, int stackN));
+static void ddPatchTree ARGS((DdManager *dd, MtrNode *treenode));
+#ifdef DD_DEBUG
+static int cuddCheckCollisionOrdering ARGS((DdManager *unique, int i, int j));
+#endif
+static void ddReportRefMess ARGS((DdManager *unique, int i, char *caller));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the next prime &gt;= p.]
+
+ Description []
+
+ SideEffects [None]
+
+******************************************************************************/
+unsigned int
+Cudd_Prime(
+ unsigned int p)
+{
+ int i,pn;
+
+ p--;
+ do {
+ p++;
+ if (p&1) {
+ pn = 1;
+ i = 3;
+ while ((unsigned) (i * i) <= p) {
+ if (p % i == 0) {
+ pn = 0;
+ break;
+ }
+ i += 2;
+ }
+ } else {
+ pn = 0;
+ }
+ } while (!pn);
+ return(p);
+
+} /* end of Cudd_Prime */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Fast storage allocation for DdNodes in the table.]
+
+ Description [Fast storage allocation for DdNodes in the table. The
+ first 4 bytes of a chunk contain a pointer to the next block; the
+ rest contains DD_MEM_CHUNK spaces for DdNodes. Returns a pointer to
+ a new node if successful; NULL is memory is full.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddDynamicAllocNode]
+
+******************************************************************************/
+DdNode *
+cuddAllocNode(
+ DdManager * unique)
+{
+ int i;
+ DdNodePtr *mem;
+ DdNode *list, *node;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+
+ if (unique->nextFree == NULL) { /* free list is empty */
+ /* Check for exceeded limits. */
+ if ((unique->keys - unique->dead) + (unique->keysZ - unique->deadZ) >
+ unique->maxLive) {
+ unique->errorCode = CUDD_TOO_MANY_NODES;
+ return(NULL);
+ }
+ if (unique->stash == NULL || unique->memused > unique->maxmemhard) {
+ (void) cuddGarbageCollect(unique,1);
+ mem = NULL;
+ }
+ if (unique->nextFree == NULL) {
+ if (unique->memused > unique->maxmemhard) {
+ unique->errorCode = CUDD_MAX_MEM_EXCEEDED;
+ return(NULL);
+ }
+ /* Try to allocate a new block. */
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
+ MMoutOfMemory = saveHandler;
+ if (mem == NULL) {
+ /* No more memory: Try collecting garbage. If this succeeds,
+ ** we end up with mem still NULL, but unique->nextFree !=
+ ** NULL. */
+ if (cuddGarbageCollect(unique,1) == 0) {
+ /* Last resort: Free the memory stashed away, if there
+ ** any. If this succeeeds, mem != NULL and
+ ** unique->nextFree still NULL. */
+ if (unique->stash != NULL) {
+ FREE(unique->stash);
+ unique->stash = NULL;
+ /* Inhibit resizing of tables. */
+ cuddSlowTableGrowth(unique);
+ /* Now try again. */
+ mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
+ }
+ if (mem == NULL) {
+ /* Out of luck. Call the default handler to do
+ ** whatever it specifies for a failed malloc.
+ ** If this handler returns, then set error code,
+ ** print warning, and return. */
+ (*MMoutOfMemory)(sizeof(DdNode)*(DD_MEM_CHUNK + 1));
+ unique->errorCode = CUDD_MEMORY_OUT;
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,
+ "cuddAllocNode: out of memory");
+ (void) fprintf(unique->err, "Memory in use = %ld\n",
+ unique->memused);
+#endif
+ return(NULL);
+ }
+ }
+ }
+ if (mem != NULL) { /* successful allocation; slice memory */
+ ptruint offset;
+ unique->memused += (DD_MEM_CHUNK + 1) * sizeof(DdNode);
+ mem[0] = (DdNodePtr) unique->memoryList;
+ unique->memoryList = mem;
+
+ /* Here we rely on the fact that a DdNode is as large
+ ** as 4 pointers. */
+ offset = (ptruint) mem & (sizeof(DdNode) - 1);
+ mem += (sizeof(DdNode) - offset) / sizeof(DdNodePtr);
+ assert(((ptruint) mem & (sizeof(DdNode) - 1)) == 0);
+ list = (DdNode *) mem;
+
+ i = 1;
+ do {
+ list[i - 1].next = &list[i];
+ } while (++i < DD_MEM_CHUNK);
+
+ list[DD_MEM_CHUNK-1].next = NULL;
+
+ unique->nextFree = &list[0];
+ }
+ }
+ }
+ unique->allocated++;
+ node = unique->nextFree;
+ unique->nextFree = node->next;
+ return(node);
+
+} /* end of cuddAllocNode */
+
+
+/**Function********************************************************************
+
+ Synopsis [Creates and initializes the unique table.]
+
+ Description [Creates and initializes the unique table. Returns a pointer
+ to the table if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Init cuddFreeTable]
+
+******************************************************************************/
+DdManager *
+cuddInitTable(
+ unsigned int numVars /* Initial number of BDD variables (and subtables) */,
+ unsigned int numVarsZ /* Initial number of ZDD variables (and subtables) */,
+ unsigned int numSlots /* Initial size of the BDD subtables */,
+ unsigned int looseUpTo /* Limit for fast table growth */)
+{
+ DdManager *unique = ALLOC(DdManager,1);
+ int i, j;
+ DdNodePtr *nodelist;
+ DdNode *sentinel;
+ unsigned int slots;
+ int shift;
+
+ if (unique == NULL) {
+ return(NULL);
+ }
+ sentinel = &(unique->sentinel);
+ sentinel->ref = 0;
+ sentinel->index = 0;
+ cuddT(sentinel) = NULL;
+ cuddE(sentinel) = NULL;
+ sentinel->next = NULL;
+ unique->epsilon = DD_EPSILON;
+ unique->maxGrowth = DD_MAX_REORDER_GROWTH;
+ unique->maxGrowthAlt = 2.0 * DD_MAX_REORDER_GROWTH;
+ unique->reordCycle = 0; /* do not use alternate threshold */
+ unique->size = numVars;
+ unique->sizeZ = numVarsZ;
+ unique->maxSize = ddMax(DD_DEFAULT_RESIZE, numVars);
+ unique->maxSizeZ = ddMax(DD_DEFAULT_RESIZE, numVarsZ);
+
+ /* Adjust the requested number of slots to a power of 2. */
+ slots = 8;
+ while (slots < numSlots) {
+ slots <<= 1;
+ }
+ unique->initSlots = slots;
+ shift = sizeof(int) * 8 - cuddComputeFloorLog2(slots);
+
+ unique->slots = (numVars + numVarsZ + 1) * slots;
+ unique->keys = 0;
+ unique->maxLive = ~0; /* very large number */
+ unique->keysZ = 0;
+ unique->dead = 0;
+ unique->deadZ = 0;
+ unique->gcFrac = DD_GC_FRAC_HI;
+ unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
+ unique->looseUpTo = looseUpTo;
+ unique->gcEnabled = 1;
+ unique->allocated = 0;
+ unique->reclaimed = 0;
+ unique->subtables = ALLOC(DdSubtable,unique->maxSize);
+ if (unique->subtables == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->subtableZ = ALLOC(DdSubtable,unique->maxSizeZ);
+ if (unique->subtableZ == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->perm = ALLOC(int,unique->maxSize);
+ if (unique->perm == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->invperm = ALLOC(int,unique->maxSize);
+ if (unique->invperm == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->permZ = ALLOC(int,unique->maxSizeZ);
+ if (unique->permZ == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->invpermZ = ALLOC(int,unique->maxSizeZ);
+ if (unique->invpermZ == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->map = NULL;
+ unique->stack = ALLOC(DdNodePtr,ddMax(unique->maxSize,unique->maxSizeZ)+1);
+ if (unique->stack == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->stack[0] = NULL; /* to suppress harmless UMR */
+
+#ifndef DD_NO_DEATH_ROW
+ unique->deathRowDepth = 1 << cuddComputeFloorLog2(unique->looseUpTo >> 2);
+ unique->deathRow = ALLOC(DdNodePtr,unique->deathRowDepth);
+ if (unique->deathRow == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (i = 0; i < unique->deathRowDepth; i++) {
+ unique->deathRow[i] = NULL;
+ }
+ unique->nextDead = 0;
+ unique->deadMask = unique->deathRowDepth - 1;
+#endif
+
+ for (i = 0; (unsigned) i < numVars; i++) {
+ unique->subtables[i].slots = slots;
+ unique->subtables[i].shift = shift;
+ unique->subtables[i].keys = 0;
+ unique->subtables[i].dead = 0;
+ unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
+ unique->subtables[i].bindVar = 0;
+ unique->subtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
+ unique->subtables[i].pairIndex = 0;
+ unique->subtables[i].varHandled = 0;
+ unique->subtables[i].varToBeGrouped = CUDD_LAZY_NONE;
+
+ nodelist = unique->subtables[i].nodelist = ALLOC(DdNodePtr,slots);
+ if (nodelist == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (j = 0; (unsigned) j < slots; j++) {
+ nodelist[j] = sentinel;
+ }
+ unique->perm[i] = i;
+ unique->invperm[i] = i;
+ }
+ for (i = 0; (unsigned) i < numVarsZ; i++) {
+ unique->subtableZ[i].slots = slots;
+ unique->subtableZ[i].shift = shift;
+ unique->subtableZ[i].keys = 0;
+ unique->subtableZ[i].dead = 0;
+ unique->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
+ nodelist = unique->subtableZ[i].nodelist = ALLOC(DdNodePtr,slots);
+ if (nodelist == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (j = 0; (unsigned) j < slots; j++) {
+ nodelist[j] = NULL;
+ }
+ unique->permZ[i] = i;
+ unique->invpermZ[i] = i;
+ }
+ unique->constants.slots = slots;
+ unique->constants.shift = shift;
+ unique->constants.keys = 0;
+ unique->constants.dead = 0;
+ unique->constants.maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
+ nodelist = unique->constants.nodelist = ALLOC(DdNodePtr,slots);
+ if (nodelist == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (j = 0; (unsigned) j < slots; j++) {
+ nodelist[j] = NULL;
+ }
+
+ unique->memoryList = NULL;
+ unique->nextFree = NULL;
+
+ unique->memused = sizeof(DdManager) + (unique->maxSize + unique->maxSizeZ)
+ * (sizeof(DdSubtable) + 2 * sizeof(int)) + (numVars + 1) *
+ slots * sizeof(DdNodePtr) +
+ (ddMax(unique->maxSize,unique->maxSizeZ) + 1) * sizeof(DdNodePtr);
+#ifndef DD_NO_DEATH_ROW
+ unique->memused += unique->deathRowDepth * sizeof(DdNodePtr);
+#endif
+
+ /* Initialize fields concerned with automatic dynamic reordering */
+ unique->reorderings = 0;
+ unique->autoDyn = 0; /* initially disabled */
+ unique->autoDynZ = 0; /* initially disabled */
+ unique->realign = 0; /* initially disabled */
+ unique->realignZ = 0; /* initially disabled */
+ unique->reordered = 0;
+ unique->autoMethod = CUDD_REORDER_SIFT;
+ unique->autoMethodZ = CUDD_REORDER_SIFT;
+ unique->nextDyn = DD_FIRST_REORDER;
+ unique->countDead = ~0;
+ unique->siftMaxVar = DD_SIFT_MAX_VAR;
+ unique->siftMaxSwap = DD_SIFT_MAX_SWAPS;
+ unique->tree = NULL;
+ unique->treeZ = NULL;
+ unique->groupcheck = CUDD_GROUP_CHECK7;
+ unique->recomb = DD_DEFAULT_RECOMB;
+ unique->symmviolation = 0;
+ unique->arcviolation = 0;
+ unique->populationSize = 0;
+ unique->numberXovers = 0;
+ unique->linear = NULL;
+ unique->linearSize = 0;
+
+ /* Initialize ZDD universe. */
+ unique->univ = (DdNodePtr *)NULL;
+
+ /* Initialize auxiliary fields. */
+ unique->localCaches = NULL;
+ unique->preGCHook = NULL;
+ unique->postGCHook = NULL;
+ unique->preReorderingHook = NULL;
+ unique->postReorderingHook = NULL;
+ unique->out = stdout;
+ unique->err = stderr;
+ unique->errorCode = CUDD_NO_ERROR;
+
+ /* Initialize statistical counters. */
+ unique->maxmemhard = (long) ((~ (unsigned long) 0) >> 1);
+ unique->garbageCollections = 0;
+ unique->GCTime = 0;
+ unique->reordTime = 0;
+#ifdef DD_STATS
+ unique->nodesDropped = 0;
+ unique->nodesFreed = 0;
+#endif
+ unique->peakLiveNodes = 0;
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLookUps = 0;
+ unique->uniqueLinks = 0;
+#endif
+#ifdef DD_COUNT
+ unique->recursiveCalls = 0;
+ unique->swapSteps = 0;
+#ifdef DD_STATS
+ unique->nextSample = 250000;
+#endif
+#endif
+
+ return(unique);
+
+} /* end of cuddInitTable */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees the resources associated to a unique table.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [cuddInitTable]
+
+******************************************************************************/
+void
+cuddFreeTable(
+ DdManager * unique)
+{
+ DdNodePtr *next;
+ DdNodePtr *memlist = unique->memoryList;
+ int i;
+
+ if (unique->univ != NULL) cuddZddFreeUniv(unique);
+ while (memlist != NULL) {
+ next = (DdNodePtr *) memlist[0]; /* link to next block */
+ FREE(memlist);
+ memlist = next;
+ }
+ unique->nextFree = NULL;
+ unique->memoryList = NULL;
+
+ for (i = 0; i < unique->size; i++) {
+ FREE(unique->subtables[i].nodelist);
+ }
+ for (i = 0; i < unique->sizeZ; i++) {
+ FREE(unique->subtableZ[i].nodelist);
+ }
+ FREE(unique->constants.nodelist);
+ FREE(unique->subtables);
+ FREE(unique->subtableZ);
+ FREE(unique->acache);
+ FREE(unique->perm);
+ FREE(unique->permZ);
+ FREE(unique->invperm);
+ FREE(unique->invpermZ);
+ FREE(unique->vars);
+ if (unique->map != NULL) FREE(unique->map);
+ FREE(unique->stack);
+#ifndef DD_NO_DEATH_ROW
+ FREE(unique->deathRow);
+#endif
+ if (unique->tree != NULL) Mtr_FreeTree(unique->tree);
+ if (unique->treeZ != NULL) Mtr_FreeTree(unique->treeZ);
+ if (unique->linear != NULL) FREE(unique->linear);
+ while (unique->preGCHook != NULL)
+ Cudd_RemoveHook(unique,unique->preGCHook->f,CUDD_PRE_GC_HOOK);
+ while (unique->postGCHook != NULL)
+ Cudd_RemoveHook(unique,unique->postGCHook->f,CUDD_POST_GC_HOOK);
+ while (unique->preReorderingHook != NULL)
+ Cudd_RemoveHook(unique,unique->preReorderingHook->f,
+ CUDD_PRE_REORDERING_HOOK);
+ while (unique->postReorderingHook != NULL)
+ Cudd_RemoveHook(unique,unique->postReorderingHook->f,
+ CUDD_POST_REORDERING_HOOK);
+ FREE(unique);
+
+} /* end of cuddFreeTable */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs garbage collection on a unique table.]
+
+ Description [Performs garbage collection on a unique table.
+ If clearCache is 0, the cache is not cleared. This should only be
+ specified if the cache has been cleared right before calling
+ cuddGarbageCollect. (As in the case of dynamic reordering.)
+ Returns the total number of deleted nodes.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddGarbageCollectZdd]
+
+******************************************************************************/
+int
+cuddGarbageCollect(
+ DdManager * unique,
+ int clearCache)
+{
+ DdHook *hook;
+ DdCache *cache = unique->cache;
+ DdNode *sentinel = &(unique->sentinel);
+ DdNodePtr *nodelist;
+ int i, j, deleted, totalDeleted;
+ DdCache *c;
+ DdNode *node,*next;
+ DdNodePtr *lastP;
+ int slots;
+ long localTime;
+#ifndef DD_UNSORTED_FREE_LIST
+ DdNodePtr tree;
+#endif
+
+#ifndef DD_NO_DEATH_ROW
+ cuddClearDeathRow(unique);
+#endif
+
+ hook = unique->preGCHook;
+ while (hook != NULL) {
+ int res = (hook->f)(unique,"BDD",NULL);
+ if (res == 0) return(0);
+ hook = hook->next;
+ }
+
+ if (unique->dead == 0) {
+ hook = unique->postGCHook;
+ while (hook != NULL) {
+ int res = (hook->f)(unique,"BDD",NULL);
+ if (res == 0) return(0);
+ hook = hook->next;
+ }
+ return(0);
+ }
+
+ /* If many nodes are being reclaimed, we want to resize the tables
+ ** more aggressively, to reduce the frequency of garbage collection.
+ */
+ if (clearCache && unique->gcFrac == DD_GC_FRAC_LO &&
+ unique->slots <= unique->looseUpTo && unique->stash != NULL) {
+ unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_HI);
+ (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
+#endif
+ unique->gcFrac = DD_GC_FRAC_HI;
+ return(0);
+ }
+
+ localTime = util_cpu_time();
+
+ unique->garbageCollections++;
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,
+ "garbage collecting (%d dead out of %d, min %d)...",
+ unique->dead, unique->keys, unique->minDead);
+#endif
+
+ /* Remove references to garbage collected nodes from the cache. */
+ if (clearCache) {
+ slots = unique->cacheSlots;
+ for (i = 0; i < slots; i++) {
+ c = &cache[i];
+ if (c->data != NULL) {
+ if (cuddClean(c->f)->ref == 0 ||
+ cuddClean(c->g)->ref == 0 ||
+ (((ptruint)c->f & 0x2) && Cudd_Regular(c->h)->ref == 0) ||
+ (c->data != DD_NON_CONSTANT &&
+ Cudd_Regular(c->data)->ref == 0)) {
+ c->data = NULL;
+ unique->cachedeletions++;
+ }
+ }
+ }
+ cuddLocalCacheClearDead(unique);
+ }
+
+ /* Now return dead nodes to free list. Count them for sanity check. */
+ totalDeleted = 0;
+#ifndef DD_UNSORTED_FREE_LIST
+ tree = NULL;
+#endif
+
+ for (i = 0; i < unique->size; i++) {
+ if (unique->subtables[i].dead == 0) continue;
+ nodelist = unique->subtables[i].nodelist;
+
+ deleted = 0;
+ slots = unique->subtables[i].slots;
+ for (j = 0; j < slots; j++) {
+ lastP = &(nodelist[j]);
+ node = *lastP;
+ while (node != sentinel) {
+ next = node->next;
+ if (node->ref == 0) {
+ deleted++;
+#ifndef DD_UNSORTED_FREE_LIST
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ cuddOrderedInsert(&tree,node);
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+#else
+ cuddDeallocNode(unique,node);
+#endif
+ } else {
+ *lastP = node;
+ lastP = &(node->next);
+ }
+ node = next;
+ }
+ *lastP = sentinel;
+ }
+ if ((unsigned) deleted != unique->subtables[i].dead) {
+ ddReportRefMess(unique, i, "cuddGarbageCollect");
+ }
+ totalDeleted += deleted;
+ unique->subtables[i].keys -= deleted;
+ unique->subtables[i].dead = 0;
+ }
+ if (unique->constants.dead != 0) {
+ nodelist = unique->constants.nodelist;
+ deleted = 0;
+ slots = unique->constants.slots;
+ for (j = 0; j < slots; j++) {
+ lastP = &(nodelist[j]);
+ node = *lastP;
+ while (node != NULL) {
+ next = node->next;
+ if (node->ref == 0) {
+ deleted++;
+#ifndef DD_UNSORTED_FREE_LIST
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ cuddOrderedInsert(&tree,node);
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+#else
+ cuddDeallocNode(unique,node);
+#endif
+ } else {
+ *lastP = node;
+ lastP = &(node->next);
+ }
+ node = next;
+ }
+ *lastP = NULL;
+ }
+ if ((unsigned) deleted != unique->constants.dead) {
+ ddReportRefMess(unique, CUDD_CONST_INDEX, "cuddGarbageCollect");
+ }
+ totalDeleted += deleted;
+ unique->constants.keys -= deleted;
+ unique->constants.dead = 0;
+ }
+ if ((unsigned) totalDeleted != unique->dead) {
+ ddReportRefMess(unique, -1, "cuddGarbageCollect");
+ }
+ unique->keys -= totalDeleted;
+ unique->dead = 0;
+#ifdef DD_STATS
+ unique->nodesFreed += (double) totalDeleted;
+#endif
+
+#ifndef DD_UNSORTED_FREE_LIST
+ unique->nextFree = cuddOrderedThread(tree,unique->nextFree);
+#endif
+
+ unique->GCTime += util_cpu_time() - localTime;
+
+ hook = unique->postGCHook;
+ while (hook != NULL) {
+ int res = (hook->f)(unique,"BDD",NULL);
+ if (res == 0) return(0);
+ hook = hook->next;
+ }
+
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err," done\n");
+#endif
+
+ return(totalDeleted);
+
+} /* end of cuddGarbageCollect */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs garbage collection on a ZDD unique table.]
+
+ Description [Performs garbage collection on a ZDD unique table.
+ If clearCache is 0, the cache is not cleared. This should only be
+ specified if the cache has been cleared right before calling
+ cuddGarbageCollectZdd. (As in the case of dynamic reordering.)
+ Returns the total number of deleted nodes.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddGarbageCollect]
+
+******************************************************************************/
+int
+cuddGarbageCollectZdd(
+ DdManager * unique,
+ int clearCache)
+{
+ DdHook *hook;
+ DdCache *cache = unique->cache;
+ DdNodePtr *nodelist;
+ int i, j, deleted, totalDeleted;
+ DdCache *c;
+ DdNode *node,*next;
+ DdNodePtr *lastP;
+ int slots;
+ long localTime;
+#ifndef DD_UNSORTED_FREE_LIST
+ DdNodePtr tree;
+#endif
+
+ hook = unique->preGCHook;
+ while (hook != NULL) {
+ int res = (hook->f)(unique,"ZDD",NULL);
+ if (res == 0) return(0);
+ hook = hook->next;
+ }
+
+ if (unique->deadZ == 0) {
+ hook = unique->postGCHook;
+ while (hook != NULL) {
+ int res = (hook->f)(unique,"ZDD",NULL);
+ if (res == 0) return(0);
+ hook = hook->next;
+ }
+ return(0);
+ }
+
+ /* If many nodes are being reclaimed, we want to resize the tables
+ ** more aggressively, to reduce the frequency of garbage collection.
+ */
+ if (clearCache && unique->slots <= unique->looseUpTo) {
+ unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
+#ifdef DD_VERBOSE
+ if (unique->gcFrac == DD_GC_FRAC_LO) {
+ (void) fprintf(unique->err,"GC fraction = %.2f\t",
+ DD_GC_FRAC_HI);
+ (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
+ }
+#endif
+ unique->gcFrac = DD_GC_FRAC_HI;
+ }
+
+ localTime = util_cpu_time();
+
+ unique->garbageCollections++;
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,"garbage collecting (%d dead out of %d)...",
+ unique->deadZ,unique->keysZ);
+#endif
+
+ /* Remove references to garbage collected nodes from the cache. */
+ if (clearCache) {
+ slots = unique->cacheSlots;
+ for (i = 0; i < slots; i++) {
+ c = &cache[i];
+ if (c->data != NULL) {
+ if (cuddClean(c->f)->ref == 0 ||
+ cuddClean(c->g)->ref == 0 ||
+ (((ptruint)c->f & 0x2) && Cudd_Regular(c->h)->ref == 0) ||
+ (c->data != DD_NON_CONSTANT &&
+ Cudd_Regular(c->data)->ref == 0)) {
+ c->data = NULL;
+ unique->cachedeletions++;
+ }
+ }
+ }
+ }
+
+ /* Now return dead nodes to free list. Count them for sanity check. */
+ totalDeleted = 0;
+#ifndef DD_UNSORTED_FREE_LIST
+ tree = NULL;
+#endif
+
+ for (i = 0; i < unique->sizeZ; i++) {
+ if (unique->subtableZ[i].dead == 0) continue;
+ nodelist = unique->subtableZ[i].nodelist;
+
+ deleted = 0;
+ slots = unique->subtableZ[i].slots;
+ for (j = 0; j < slots; j++) {
+ lastP = &(nodelist[j]);
+ node = *lastP;
+ while (node != NULL) {
+ next = node->next;
+ if (node->ref == 0) {
+ deleted++;
+#ifndef DD_UNSORTED_FREE_LIST
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ cuddOrderedInsert(&tree,node);
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+#else
+ cuddDeallocNode(unique,node);
+#endif
+ } else {
+ *lastP = node;
+ lastP = &(node->next);
+ }
+ node = next;
+ }
+ *lastP = NULL;
+ }
+ if ((unsigned) deleted != unique->subtableZ[i].dead) {
+ ddReportRefMess(unique, i, "cuddGarbageCollectZdd");
+ }
+ totalDeleted += deleted;
+ unique->subtableZ[i].keys -= deleted;
+ unique->subtableZ[i].dead = 0;
+ }
+
+ /* No need to examine the constant table for ZDDs.
+ ** If we did we should be careful not to count whatever dead
+ ** nodes we found there among the dead ZDD nodes. */
+ if ((unsigned) totalDeleted != unique->deadZ) {
+ ddReportRefMess(unique, -1, "cuddGarbageCollectZdd");
+ }
+ unique->keysZ -= totalDeleted;
+ unique->deadZ = 0;
+#ifdef DD_STATS
+ unique->nodesFreed += (double) totalDeleted;
+#endif
+
+#ifndef DD_UNSORTED_FREE_LIST
+ unique->nextFree = cuddOrderedThread(tree,unique->nextFree);
+#endif
+
+ unique->GCTime += util_cpu_time() - localTime;
+
+ hook = unique->postGCHook;
+ while (hook != NULL) {
+ int res = (hook->f)(unique,"ZDD",NULL);
+ if (res == 0) return(0);
+ hook = hook->next;
+ }
+
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err," done\n");
+#endif
+
+ return(totalDeleted);
+
+} /* end of cuddGarbageCollectZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Wrapper for cuddUniqueInterZdd.]
+
+ Description [Wrapper for cuddUniqueInterZdd, which applies the ZDD
+ reduction rule. Returns a pointer to the result node under normal
+ conditions; NULL if reordering occurred or memory was exhausted.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddUniqueInterZdd]
+
+******************************************************************************/
+DdNode *
+cuddZddGetNode(
+ DdManager * zdd,
+ int id,
+ DdNode * T,
+ DdNode * E)
+{
+ DdNode *node;
+
+ if (T == DD_ZERO(zdd))
+ return(E);
+ node = cuddUniqueInterZdd(zdd, id, T, E);
+ return(node);
+
+} /* end of cuddZddGetNode */
+
+
+/**Function********************************************************************
+
+ Synopsis [Wrapper for cuddUniqueInterZdd that is independent of variable
+ ordering.]
+
+ Description [Wrapper for cuddUniqueInterZdd that is independent of
+ variable ordering (IVO). This function does not require parameter
+ index to precede the indices of the top nodes of g and h in the
+ variable order. Returns a pointer to the result node under normal
+ conditions; NULL if reordering occurred or memory was exhausted.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddZddGetNode cuddZddIsop]
+
+******************************************************************************/
+DdNode *
+cuddZddGetNodeIVO(
+ DdManager * dd,
+ int index,
+ DdNode * g,
+ DdNode * h)
+{
+ DdNode *f, *r, *t;
+ DdNode *zdd_one = DD_ONE(dd);
+ DdNode *zdd_zero = DD_ZERO(dd);
+
+ f = cuddUniqueInterZdd(dd, index, zdd_one, zdd_zero);
+ if (f == NULL) {
+ return(NULL);
+ }
+ cuddRef(f);
+ t = cuddZddProduct(dd, f, g);
+ if (t == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f);
+ return(NULL);
+ }
+ cuddRef(t);
+ Cudd_RecursiveDerefZdd(dd, f);
+ r = cuddZddUnion(dd, t, h);
+ if (r == NULL) {
+ Cudd_RecursiveDerefZdd(dd, t);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_RecursiveDerefZdd(dd, t);
+
+ cuddDeref(r);
+ return(r);
+
+} /* end of cuddZddGetNodeIVO */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks the unique table for the existence of an internal node.]
+
+ Description [Checks the unique table for the existence of an internal
+ node. If it does not exist, it creates a new one. Does not
+ modify the reference count of whatever is returned. A newly created
+ internal node comes back with a reference count 0. For a newly
+ created node, increments the reference counts of what T and E point
+ to. Returns a pointer to the new node if successful; NULL if memory
+ is exhausted or if reordering took place.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddUniqueInterZdd]
+
+******************************************************************************/
+DdNode *
+cuddUniqueInter(
+ DdManager * unique,
+ int index,
+ DdNode * T,
+ DdNode * E)
+{
+ int pos;
+ unsigned int level;
+ int retval;
+ DdNodePtr *nodelist;
+ DdNode *looking;
+ DdNodePtr *previousP;
+ DdSubtable *subtable;
+ int gcNumber;
+
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLookUps++;
+#endif
+
+ if (index >= unique->size) {
+ if (!ddResizeTable(unique,index)) return(NULL);
+ }
+
+ level = unique->perm[index];
+ subtable = &(unique->subtables[level]);
+
+#ifdef DD_DEBUG
+ assert(level < (unsigned) cuddI(unique,T->index));
+ assert(level < (unsigned) cuddI(unique,Cudd_Regular(E)->index));
+#endif
+
+ pos = ddHash(T, E, subtable->shift);
+ nodelist = subtable->nodelist;
+ previousP = &(nodelist[pos]);
+ looking = *previousP;
+
+ while (T < cuddT(looking)) {
+ previousP = &(looking->next);
+ looking = *previousP;
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLinks++;
+#endif
+ }
+ while (T == cuddT(looking) && E < cuddE(looking)) {
+ previousP = &(looking->next);
+ looking = *previousP;
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLinks++;
+#endif
+ }
+ if (T == cuddT(looking) && E == cuddE(looking)) {
+ if (looking->ref == 0) {
+ cuddReclaim(unique,looking);
+ }
+ return(looking);
+ }
+
+ /* countDead is 0 if deads should be counted and ~0 if they should not. */
+ if (unique->autoDyn &&
+ unique->keys - (unique->dead & unique->countDead) >= unique->nextDyn) {
+#ifdef DD_DEBUG
+ retval = Cudd_DebugCheck(unique);
+ if (retval != 0) return(NULL);
+ retval = Cudd_CheckKeys(unique);
+ if (retval != 0) return(NULL);
+#endif
+ retval = Cudd_ReduceHeap(unique,unique->autoMethod,10); /* 10 = whatever */
+ if (retval == 0) unique->reordered = 2;
+#ifdef DD_DEBUG
+ retval = Cudd_DebugCheck(unique);
+ if (retval != 0) unique->reordered = 2;
+ retval = Cudd_CheckKeys(unique);
+ if (retval != 0) unique->reordered = 2;
+#endif
+ return(NULL);
+ }
+
+ if (subtable->keys > subtable->maxKeys) {
+ if (unique->gcEnabled &&
+ ((unique->dead > unique->minDead) ||
+ ((unique->dead > unique->minDead / 2) &&
+ (subtable->dead > subtable->keys * 0.95)))) { /* too many dead */
+ (void) cuddGarbageCollect(unique,1);
+ } else {
+ cuddRehash(unique,(int)level);
+ }
+ /* Update pointer to insertion point. In the case of rehashing,
+ ** the slot may have changed. In the case of garbage collection,
+ ** the predecessor may have been dead. */
+ pos = ddHash(T, E, subtable->shift);
+ nodelist = subtable->nodelist;
+ previousP = &(nodelist[pos]);
+ looking = *previousP;
+
+ while (T < cuddT(looking)) {
+ previousP = &(looking->next);
+ looking = *previousP;
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLinks++;
+#endif
+ }
+ while (T == cuddT(looking) && E < cuddE(looking)) {
+ previousP = &(looking->next);
+ looking = *previousP;
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLinks++;
+#endif
+ }
+ }
+
+ gcNumber = unique->garbageCollections;
+ looking = cuddAllocNode(unique);
+ if (looking == NULL) {
+ return(NULL);
+ }
+ unique->keys++;
+ subtable->keys++;
+
+ if (gcNumber != unique->garbageCollections) {
+ DdNode *looking2;
+ pos = ddHash(T, E, subtable->shift);
+ nodelist = subtable->nodelist;
+ previousP = &(nodelist[pos]);
+ looking2 = *previousP;
+
+ while (T < cuddT(looking2)) {
+ previousP = &(looking2->next);
+ looking2 = *previousP;
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLinks++;
+#endif
+ }
+ while (T == cuddT(looking2) && E < cuddE(looking2)) {
+ previousP = &(looking2->next);
+ looking2 = *previousP;
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLinks++;
+#endif
+ }
+ }
+ looking->ref = 0;
+ looking->index = index;
+ cuddT(looking) = T;
+ cuddE(looking) = E;
+ looking->next = *previousP;
+ *previousP = looking;
+ cuddSatInc(T->ref); /* we know T is a regular pointer */
+ cuddRef(E);
+
+#ifdef DD_DEBUG
+ cuddCheckCollisionOrdering(unique,level,pos);
+#endif
+
+ return(looking);
+
+} /* end of cuddUniqueInter */
+
+
+/**Function********************************************************************
+
+ Synopsis [Wrapper for cuddUniqueInter that is independent of variable
+ ordering.]
+
+ Description [Wrapper for cuddUniqueInter that is independent of
+ variable ordering (IVO). This function does not require parameter
+ index to precede the indices of the top nodes of T and E in the
+ variable order. Returns a pointer to the result node under normal
+ conditions; NULL if reordering occurred or memory was exhausted.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddUniqueInter Cudd_MakeBddFromZddCover]
+
+******************************************************************************/
+DdNode *
+cuddUniqueInterIVO(
+ DdManager * unique,
+ int index,
+ DdNode * T,
+ DdNode * E)
+{
+ DdNode *result;
+ DdNode *v;
+
+ v = cuddUniqueInter(unique, index, DD_ONE(unique),
+ Cudd_Not(DD_ONE(unique)));
+ if (v == NULL)
+ return(NULL);
+ cuddRef(v);
+ result = cuddBddIteRecur(unique, v, T, E);
+ Cudd_RecursiveDeref(unique, v);
+ return(result);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks the unique table for the existence of an internal
+ ZDD node.]
+
+ Description [Checks the unique table for the existence of an internal
+ ZDD node. If it does not exist, it creates a new one. Does not
+ modify the reference count of whatever is returned. A newly created
+ internal node comes back with a reference count 0. For a newly
+ created node, increments the reference counts of what T and E point
+ to. Returns a pointer to the new node if successful; NULL if memory
+ is exhausted or if reordering took place.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddUniqueInter]
+
+******************************************************************************/
+DdNode *
+cuddUniqueInterZdd(
+ DdManager * unique,
+ int index,
+ DdNode * T,
+ DdNode * E)
+{
+ int pos;
+ unsigned int level;
+ int retval;
+ DdNodePtr *nodelist;
+ DdNode *looking;
+ DdSubtable *subtable;
+
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLookUps++;
+#endif
+
+ if (index >= unique->sizeZ) {
+ if (!cuddResizeTableZdd(unique,index)) return(NULL);
+ }
+
+ level = unique->permZ[index];
+ subtable = &(unique->subtableZ[level]);
+
+#ifdef DD_DEBUG
+ assert(level < (unsigned) cuddIZ(unique,T->index));
+ assert(level < (unsigned) cuddIZ(unique,Cudd_Regular(E)->index));
+#endif
+
+ if (subtable->keys > subtable->maxKeys) {
+ if (unique->gcEnabled && ((unique->deadZ > unique->minDead) ||
+ (10 * subtable->dead > 9 * subtable->keys))) { /* too many dead */
+ (void) cuddGarbageCollectZdd(unique,1);
+ } else {
+ ddRehashZdd(unique,(int)level);
+ }
+ }
+
+ pos = ddHash(T, E, subtable->shift);
+ nodelist = subtable->nodelist;
+ looking = nodelist[pos];
+
+ while (looking != NULL) {
+ if (cuddT(looking) == T && cuddE(looking) == E) {
+ if (looking->ref == 0) {
+ cuddReclaimZdd(unique,looking);
+ }
+ return(looking);
+ }
+ looking = looking->next;
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLinks++;
+#endif
+ }
+
+ /* countDead is 0 if deads should be counted and ~0 if they should not. */
+ if (unique->autoDynZ &&
+ unique->keysZ - (unique->deadZ & unique->countDead) >= unique->nextDyn) {
+#ifdef DD_DEBUG
+ retval = Cudd_DebugCheck(unique);
+ if (retval != 0) return(NULL);
+ retval = Cudd_CheckKeys(unique);
+ if (retval != 0) return(NULL);
+#endif
+ retval = Cudd_zddReduceHeap(unique,unique->autoMethodZ,10); /* 10 = whatever */
+ if (retval == 0) unique->reordered = 2;
+#ifdef DD_DEBUG
+ retval = Cudd_DebugCheck(unique);
+ if (retval != 0) unique->reordered = 2;
+ retval = Cudd_CheckKeys(unique);
+ if (retval != 0) unique->reordered = 2;
+#endif
+ return(NULL);
+ }
+
+ unique->keysZ++;
+ subtable->keys++;
+
+ looking = cuddAllocNode(unique);
+ if (looking == NULL) return(NULL);
+ looking->ref = 0;
+ looking->index = index;
+ cuddT(looking) = T;
+ cuddE(looking) = E;
+ looking->next = nodelist[pos];
+ nodelist[pos] = looking;
+ cuddRef(T);
+ cuddRef(E);
+
+ return(looking);
+
+} /* end of cuddUniqueInterZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks the unique table for the existence of a constant node.]
+
+ Description [Checks the unique table for the existence of a constant node.
+ If it does not exist, it creates a new one. Does not
+ modify the reference count of whatever is returned. A newly created
+ internal node comes back with a reference count 0. Returns a
+ pointer to the new node.]
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+cuddUniqueConst(
+ DdManager * unique,
+ CUDD_VALUE_TYPE value)
+{
+ int pos;
+ DdNodePtr *nodelist;
+ DdNode *looking;
+ hack split;
+
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLookUps++;
+#endif
+
+ if (unique->constants.keys > unique->constants.maxKeys) {
+ if (unique->gcEnabled && ((unique->dead > unique->minDead) ||
+ (10 * unique->constants.dead > 9 * unique->constants.keys))) { /* too many dead */
+ (void) cuddGarbageCollect(unique,1);
+ } else {
+ cuddRehash(unique,CUDD_CONST_INDEX);
+ }
+ }
+
+ cuddAdjust(value); /* for the case of crippled infinities */
+
+ if (ddAbs(value) < unique->epsilon) {
+ value = 0.0;
+ }
+ split.value = value;
+
+ pos = ddHash(split.bits[0], split.bits[1], unique->constants.shift);
+ nodelist = unique->constants.nodelist;
+ looking = nodelist[pos];
+
+ /* Here we compare values both for equality and for difference less
+ * than epsilon. The first comparison is required when values are
+ * infinite, since Infinity - Infinity is NaN and NaN < X is 0 for
+ * every X.
+ */
+ while (looking != NULL) {
+ if (looking->type.value == value ||
+ ddEqualVal(looking->type.value,value,unique->epsilon)) {
+ if (looking->ref == 0) {
+ cuddReclaim(unique,looking);
+ }
+ return(looking);
+ }
+ looking = looking->next;
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLinks++;
+#endif
+ }
+
+ unique->keys++;
+ unique->constants.keys++;
+
+ looking = cuddAllocNode(unique);
+ if (looking == NULL) return(NULL);
+ looking->ref = 0;
+ looking->index = CUDD_CONST_INDEX;
+ looking->type.value = value;
+ looking->next = nodelist[pos];
+ nodelist[pos] = looking;
+
+ return(looking);
+
+} /* end of cuddUniqueConst */
+
+
+/**Function********************************************************************
+
+ Synopsis [Rehashes a unique subtable.]
+
+ Description [Doubles the size of a unique subtable and rehashes its
+ contents.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+cuddRehash(
+ DdManager * unique,
+ int i)
+{
+ unsigned int slots, oldslots;
+ int shift, oldshift;
+ int j, pos;
+ DdNodePtr *nodelist, *oldnodelist;
+ DdNode *node, *next;
+ DdNode *sentinel = &(unique->sentinel);
+ hack split;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+
+ if (unique->gcFrac == DD_GC_FRAC_HI && unique->slots > unique->looseUpTo) {
+ unique->gcFrac = DD_GC_FRAC_LO;
+ unique->minDead = (unsigned) (DD_GC_FRAC_LO * (double) unique->slots);
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_LO);
+ (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
+#endif
+ }
+
+ if (unique->gcFrac != DD_GC_FRAC_MIN && unique->memused > unique->maxmem) {
+ unique->gcFrac = DD_GC_FRAC_MIN;
+ unique->minDead = (unsigned) (DD_GC_FRAC_MIN * (double) unique->slots);
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_MIN);
+ (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
+#endif
+ cuddShrinkDeathRow(unique);
+ if (cuddGarbageCollect(unique,1) > 0) return;
+ }
+
+ if (i != CUDD_CONST_INDEX) {
+ oldslots = unique->subtables[i].slots;
+ oldshift = unique->subtables[i].shift;
+ oldnodelist = unique->subtables[i].nodelist;
+
+ /* Compute the new size of the subtable. */
+ slots = oldslots << 1;
+ shift = oldshift - 1;
+
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ nodelist = ALLOC(DdNodePtr, slots);
+ MMoutOfMemory = saveHandler;
+ if (nodelist == NULL) {
+ (void) fprintf(unique->err,
+ "Unable to resize subtable %d for lack of memory\n",
+ i);
+ /* Prevent frequent resizing attempts. */
+ (void) cuddGarbageCollect(unique,1);
+ if (unique->stash != NULL) {
+ FREE(unique->stash);
+ unique->stash = NULL;
+ /* Inhibit resizing of tables. */
+ cuddSlowTableGrowth(unique);
+ }
+ return;
+ }
+ unique->subtables[i].nodelist = nodelist;
+ unique->subtables[i].slots = slots;
+ unique->subtables[i].shift = shift;
+ unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
+
+ /* Move the nodes from the old table to the new table.
+ ** This code depends on the type of hash function.
+ ** It assumes that the effect of doubling the size of the table
+ ** is to retain one more bit of the 32-bit hash value.
+ ** The additional bit is the LSB. */
+ for (j = 0; (unsigned) j < oldslots; j++) {
+ DdNodePtr *evenP, *oddP;
+ node = oldnodelist[j];
+ evenP = &(nodelist[j<<1]);
+ oddP = &(nodelist[(j<<1)+1]);
+ while (node != sentinel) {
+ next = node->next;
+ pos = ddHash(cuddT(node), cuddE(node), shift);
+ if (pos & 1) {
+ *oddP = node;
+ oddP = &(node->next);
+ } else {
+ *evenP = node;
+ evenP = &(node->next);
+ }
+ node = next;
+ }
+ *evenP = *oddP = sentinel;
+ }
+ FREE(oldnodelist);
+
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,
+ "rehashing layer %d: keys %d dead %d new size %d\n",
+ i, unique->subtables[i].keys,
+ unique->subtables[i].dead, slots);
+#endif
+ } else {
+ oldslots = unique->constants.slots;
+ oldshift = unique->constants.shift;
+ oldnodelist = unique->constants.nodelist;
+
+ /* The constant subtable is never subjected to reordering.
+ ** Therefore, when it is resized, it is because it has just
+ ** reached the maximum load. We can safely just double the size,
+ ** with no need for the loop we use for the other tables.
+ */
+ slots = oldslots << 1;
+ shift = oldshift - 1;
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ nodelist = ALLOC(DdNodePtr, slots);
+ MMoutOfMemory = saveHandler;
+ if (nodelist == NULL) {
+ int j;
+ (void) fprintf(unique->err,
+ "Unable to resize constant subtable for lack of memory\n");
+ (void) cuddGarbageCollect(unique,1);
+ for (j = 0; j < unique->size; j++) {
+ unique->subtables[j].maxKeys <<= 1;
+ }
+ unique->constants.maxKeys <<= 1;
+ return;
+ }
+ unique->constants.slots = slots;
+ unique->constants.shift = shift;
+ unique->constants.maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
+ unique->constants.nodelist = nodelist;
+ for (j = 0; (unsigned) j < slots; j++) {
+ nodelist[j] = NULL;
+ }
+ for (j = 0; (unsigned) j < oldslots; j++) {
+ node = oldnodelist[j];
+ while (node != NULL) {
+ next = node->next;
+ split.value = cuddV(node);
+ pos = ddHash(split.bits[0], split.bits[1], shift);
+ node->next = nodelist[pos];
+ nodelist[pos] = node;
+ node = next;
+ }
+ }
+ FREE(oldnodelist);
+
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,
+ "rehashing constants: keys %d dead %d new size %d\n",
+ unique->constants.keys,unique->constants.dead,slots);
+#endif
+ }
+
+ /* Update global data */
+
+ unique->memused += (slots - oldslots) * sizeof(DdNodePtr);
+ unique->slots += (slots - oldslots);
+ ddFixLimits(unique);
+
+} /* end of cuddRehash */
+
+
+/**Function********************************************************************
+
+ Synopsis [Shrinks a subtable.]
+
+ Description [Shrinks a subtable.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddRehash]
+
+******************************************************************************/
+void
+cuddShrinkSubtable(
+ DdManager *unique,
+ int i)
+{
+ int j;
+ int shift, posn;
+ DdNodePtr *nodelist, *oldnodelist;
+ DdNode *node, *next;
+ DdNode *sentinel = &(unique->sentinel);
+ unsigned int slots, oldslots;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+
+ oldnodelist = unique->subtables[i].nodelist;
+ oldslots = unique->subtables[i].slots;
+ slots = oldslots >> 1;
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ nodelist = ALLOC(DdNodePtr, slots);
+ MMoutOfMemory = saveHandler;
+ if (nodelist == NULL) {
+ return;
+ }
+ unique->subtables[i].nodelist = nodelist;
+ unique->subtables[i].slots = slots;
+ unique->subtables[i].shift++;
+ unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,
+ "shrunk layer %d (%d keys) from %d to %d slots\n",
+ i, unique->subtables[i].keys, oldslots, slots);
+#endif
+
+ for (j = 0; (unsigned) j < slots; j++) {
+ nodelist[j] = sentinel;
+ }
+ shift = unique->subtables[i].shift;
+ for (j = 0; (unsigned) j < oldslots; j++) {
+ node = oldnodelist[j];
+ while (node != sentinel) {
+ DdNode *looking, *T, *E;
+ DdNodePtr *previousP;
+ next = node->next;
+ posn = ddHash(cuddT(node), cuddE(node), shift);
+ previousP = &(nodelist[posn]);
+ looking = *previousP;
+ T = cuddT(node);
+ E = cuddE(node);
+ while (T < cuddT(looking)) {
+ previousP = &(looking->next);
+ looking = *previousP;
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLinks++;
+#endif
+ }
+ while (T == cuddT(looking) && E < cuddE(looking)) {
+ previousP = &(looking->next);
+ looking = *previousP;
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLinks++;
+#endif
+ }
+ node->next = *previousP;
+ *previousP = node;
+ node = next;
+ }
+ }
+ FREE(oldnodelist);
+
+ unique->memused += ((long) slots - (long) oldslots) * sizeof(DdNode *);
+ unique->slots += slots - oldslots;
+ unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
+ unique->cacheSlack = (int)
+ ddMin(unique->maxCacheHard,DD_MAX_CACHE_TO_SLOTS_RATIO * unique->slots)
+ - 2 * (int) unique->cacheSlots;
+
+} /* end of cuddShrinkSubtable */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts n new subtables in a unique table at level.]
+
+ Description [Inserts n new subtables in a unique table at level.
+ The number n should be positive, and level should be an existing level.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddDestroySubtables]
+
+******************************************************************************/
+int
+cuddInsertSubtables(
+ DdManager * unique,
+ int n,
+ int level)
+{
+ DdSubtable *newsubtables;
+ DdNodePtr *newnodelist;
+ DdNodePtr *newvars;
+ DdNode *sentinel = &(unique->sentinel);
+ int oldsize,newsize;
+ int i,j,index,reorderSave;
+ unsigned int numSlots = unique->initSlots;
+ int *newperm, *newinvperm, *newmap;
+ DdNode *one, *zero;
+
+#ifdef DD_DEBUG
+ assert(n > 0 && level < unique->size);
+#endif
+
+ oldsize = unique->size;
+ /* Easy case: there is still room in the current table. */
+ if (oldsize + n <= unique->maxSize) {
+ /* Shift the tables at and below level. */
+ for (i = oldsize - 1; i >= level; i--) {
+ unique->subtables[i+n].slots = unique->subtables[i].slots;
+ unique->subtables[i+n].shift = unique->subtables[i].shift;
+ unique->subtables[i+n].keys = unique->subtables[i].keys;
+ unique->subtables[i+n].maxKeys = unique->subtables[i].maxKeys;
+ unique->subtables[i+n].dead = unique->subtables[i].dead;
+ unique->subtables[i+n].nodelist = unique->subtables[i].nodelist;
+ unique->subtables[i+n].bindVar = unique->subtables[i].bindVar;
+ unique->subtables[i+n].varType = unique->subtables[i].varType;
+ unique->subtables[i+n].pairIndex = unique->subtables[i].pairIndex;
+ unique->subtables[i+n].varHandled = unique->subtables[i].varHandled;
+ unique->subtables[i+n].varToBeGrouped =
+ unique->subtables[i].varToBeGrouped;
+
+ index = unique->invperm[i];
+ unique->invperm[i+n] = index;
+ unique->perm[index] += n;
+ }
+ /* Create new subtables. */
+ for (i = 0; i < n; i++) {
+ unique->subtables[level+i].slots = numSlots;
+ unique->subtables[level+i].shift = sizeof(int) * 8 -
+ cuddComputeFloorLog2(numSlots);
+ unique->subtables[level+i].keys = 0;
+ unique->subtables[level+i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
+ unique->subtables[level+i].dead = 0;
+ unique->subtables[level+i].bindVar = 0;
+ unique->subtables[level+i].varType = CUDD_VAR_PRIMARY_INPUT;
+ unique->subtables[level+i].pairIndex = 0;
+ unique->subtables[level+i].varHandled = 0;
+ unique->subtables[level+i].varToBeGrouped = CUDD_LAZY_NONE;
+
+ unique->perm[oldsize+i] = level + i;
+ unique->invperm[level+i] = oldsize + i;
+ newnodelist = unique->subtables[level+i].nodelist =
+ ALLOC(DdNodePtr, numSlots);
+ if (newnodelist == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (j = 0; j < numSlots; j++) {
+ newnodelist[j] = sentinel;
+ }
+ }
+ if (unique->map != NULL) {
+ for (i = 0; i < n; i++) {
+ unique->map[oldsize+i] = oldsize + i;
+ }
+ }
+ } else {
+ /* The current table is too small: we need to allocate a new,
+ ** larger one; move all old subtables, and initialize the new
+ ** subtables.
+ */
+ newsize = oldsize + n + DD_DEFAULT_RESIZE;
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,
+ "Increasing the table size from %d to %d\n",
+ unique->maxSize, newsize);
+#endif
+ /* Allocate memory for new arrays (except nodelists). */
+ newsubtables = ALLOC(DdSubtable,newsize);
+ if (newsubtables == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ newvars = ALLOC(DdNodePtr,newsize);
+ if (newvars == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ FREE(newsubtables);
+ return(0);
+ }
+ newperm = ALLOC(int,newsize);
+ if (newperm == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ FREE(newsubtables);
+ FREE(newvars);
+ return(0);
+ }
+ newinvperm = ALLOC(int,newsize);
+ if (newinvperm == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ FREE(newsubtables);
+ FREE(newvars);
+ FREE(newperm);
+ return(0);
+ }
+ if (unique->map != NULL) {
+ newmap = ALLOC(int,newsize);
+ if (newmap == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ FREE(newsubtables);
+ FREE(newvars);
+ FREE(newperm);
+ FREE(newinvperm);
+ return(0);
+ }
+ unique->memused += (newsize - unique->maxSize) * sizeof(int);
+ }
+ unique->memused += (newsize - unique->maxSize) * ((numSlots+1) *
+ sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
+ /* Copy levels before insertion points from old tables. */
+ for (i = 0; i < level; i++) {
+ newsubtables[i].slots = unique->subtables[i].slots;
+ newsubtables[i].shift = unique->subtables[i].shift;
+ newsubtables[i].keys = unique->subtables[i].keys;
+ newsubtables[i].maxKeys = unique->subtables[i].maxKeys;
+ newsubtables[i].dead = unique->subtables[i].dead;
+ newsubtables[i].nodelist = unique->subtables[i].nodelist;
+ newsubtables[i].bindVar = unique->subtables[i].bindVar;
+ newsubtables[i].varType = unique->subtables[i].varType;
+ newsubtables[i].pairIndex = unique->subtables[i].pairIndex;
+ newsubtables[i].varHandled = unique->subtables[i].varHandled;
+ newsubtables[i].varToBeGrouped = unique->subtables[i].varToBeGrouped;
+
+ newvars[i] = unique->vars[i];
+ newperm[i] = unique->perm[i];
+ newinvperm[i] = unique->invperm[i];
+ }
+ /* Finish initializing permutation for new table to old one. */
+ for (i = level; i < oldsize; i++) {
+ newperm[i] = unique->perm[i];
+ }
+ /* Initialize new levels. */
+ for (i = level; i < level + n; i++) {
+ newsubtables[i].slots = numSlots;
+ newsubtables[i].shift = sizeof(int) * 8 -
+ cuddComputeFloorLog2(numSlots);
+ newsubtables[i].keys = 0;
+ newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
+ newsubtables[i].dead = 0;
+ newsubtables[i].bindVar = 0;
+ newsubtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
+ newsubtables[i].pairIndex = 0;
+ newsubtables[i].varHandled = 0;
+ newsubtables[i].varToBeGrouped = CUDD_LAZY_NONE;
+
+ newperm[oldsize + i - level] = i;
+ newinvperm[i] = oldsize + i - level;
+ newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
+ if (newnodelist == NULL) {
+ /* We are going to leak some memory. We should clean up. */
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (j = 0; j < numSlots; j++) {
+ newnodelist[j] = sentinel;
+ }
+ }
+ /* Copy the old tables for levels past the insertion point. */
+ for (i = level; i < oldsize; i++) {
+ newsubtables[i+n].slots = unique->subtables[i].slots;
+ newsubtables[i+n].shift = unique->subtables[i].shift;
+ newsubtables[i+n].keys = unique->subtables[i].keys;
+ newsubtables[i+n].maxKeys = unique->subtables[i].maxKeys;
+ newsubtables[i+n].dead = unique->subtables[i].dead;
+ newsubtables[i+n].nodelist = unique->subtables[i].nodelist;
+ newsubtables[i+n].bindVar = unique->subtables[i].bindVar;
+ newsubtables[i+n].varType = unique->subtables[i].varType;
+ newsubtables[i+n].pairIndex = unique->subtables[i].pairIndex;
+ newsubtables[i+n].varHandled = unique->subtables[i].varHandled;
+ newsubtables[i+n].varToBeGrouped =
+ unique->subtables[i].varToBeGrouped;
+
+ newvars[i] = unique->vars[i];
+ index = unique->invperm[i];
+ newinvperm[i+n] = index;
+ newperm[index] += n;
+ }
+ /* Update the map. */
+ if (unique->map != NULL) {
+ for (i = 0; i < oldsize; i++) {
+ newmap[i] = unique->map[i];
+ }
+ for (i = oldsize; i < oldsize + n; i++) {
+ newmap[i] = i;
+ }
+ FREE(unique->map);
+ unique->map = newmap;
+ }
+ /* Install the new tables and free the old ones. */
+ FREE(unique->subtables);
+ unique->subtables = newsubtables;
+ unique->maxSize = newsize;
+ FREE(unique->vars);
+ unique->vars = newvars;
+ FREE(unique->perm);
+ unique->perm = newperm;
+ FREE(unique->invperm);
+ unique->invperm = newinvperm;
+ /* Update the stack for iterative procedures. */
+ if (newsize > unique->maxSizeZ) {
+ FREE(unique->stack);
+ unique->stack = ALLOC(DdNodePtr,newsize + 1);
+ if (unique->stack == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->stack[0] = NULL; /* to suppress harmless UMR */
+ unique->memused +=
+ (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
+ * sizeof(DdNode *);
+ }
+ }
+ /* Update manager parameters to account for the new subtables. */
+ unique->slots += n * numSlots;
+ ddFixLimits(unique);
+ unique->size += n;
+
+ /* Now that the table is in a coherent state, create the new
+ ** projection functions. We need to temporarily disable reordering,
+ ** because we cannot reorder without projection functions in place.
+ **/
+ one = unique->one;
+ zero = Cudd_Not(one);
+
+ reorderSave = unique->autoDyn;
+ unique->autoDyn = 0;
+ for (i = oldsize; i < oldsize + n; i++) {
+ unique->vars[i] = cuddUniqueInter(unique,i,one,zero);
+ if (unique->vars[i] == NULL) {
+ unique->autoDyn = reorderSave;
+ /* Shift everything back so table remains coherent. */
+ for (j = oldsize; j < i; j++) {
+ Cudd_IterDerefBdd(unique,unique->vars[j]);
+ cuddDeallocNode(unique,unique->vars[j]);
+ unique->vars[j] = NULL;
+ }
+ for (j = level; j < oldsize; j++) {
+ unique->subtables[j].slots = unique->subtables[j+n].slots;
+ unique->subtables[j].slots = unique->subtables[j+n].slots;
+ unique->subtables[j].shift = unique->subtables[j+n].shift;
+ unique->subtables[j].keys = unique->subtables[j+n].keys;
+ unique->subtables[j].maxKeys =
+ unique->subtables[j+n].maxKeys;
+ unique->subtables[j].dead = unique->subtables[j+n].dead;
+ FREE(unique->subtables[j].nodelist);
+ unique->subtables[j].nodelist =
+ unique->subtables[j+n].nodelist;
+ unique->subtables[j+n].nodelist = NULL;
+ unique->subtables[j].bindVar =
+ unique->subtables[j+n].bindVar;
+ unique->subtables[j].varType =
+ unique->subtables[j+n].varType;
+ unique->subtables[j].pairIndex =
+ unique->subtables[j+n].pairIndex;
+ unique->subtables[j].varHandled =
+ unique->subtables[j+n].varHandled;
+ unique->subtables[j].varToBeGrouped =
+ unique->subtables[j+n].varToBeGrouped;
+ index = unique->invperm[j+n];
+ unique->invperm[j] = index;
+ unique->perm[index] -= n;
+ }
+ unique->size = oldsize;
+ unique->slots -= n * numSlots;
+ ddFixLimits(unique);
+ (void) Cudd_DebugCheck(unique);
+ return(0);
+ }
+ cuddRef(unique->vars[i]);
+ }
+ if (unique->tree != NULL) {
+ unique->tree->size += n;
+ unique->tree->index = unique->invperm[0];
+ ddPatchTree(unique,unique->tree);
+ }
+ unique->autoDyn = reorderSave;
+
+ return(1);
+
+} /* end of cuddInsertSubtables */
+
+
+/**Function********************************************************************
+
+ Synopsis [Destroys the n most recently created subtables in a unique table.]
+
+ Description [Destroys the n most recently created subtables in a unique
+ table. n should be positive. The subtables should not contain any live
+ nodes, except the (isolated) projection function. The projection
+ functions are freed. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [The variable map used for fast variable substitution is
+ destroyed if it exists. In this case the cache is also cleared.]
+
+ SeeAlso [cuddInsertSubtables Cudd_SetVarMap]
+
+******************************************************************************/
+int
+cuddDestroySubtables(
+ DdManager * unique,
+ int n)
+{
+ DdSubtable *subtables;
+ DdNodePtr *nodelist;
+ DdNodePtr *vars;
+ int firstIndex, lastIndex;
+ int index, level, newlevel;
+ int lowestLevel;
+ int shift;
+ int found;
+
+ /* Sanity check and set up. */
+ if (n <= 0) return(0);
+ if (n > unique->size) n = unique->size;
+
+ subtables = unique->subtables;
+ vars = unique->vars;
+ firstIndex = unique->size - n;
+ lastIndex = unique->size;
+
+ /* Check for nodes labeled by the variables being destroyed
+ ** that may still be in use. It is allowed to destroy a variable
+ ** only if there are no such nodes. Also, find the lowest level
+ ** among the variables being destroyed. This will make further
+ ** processing more efficient.
+ */
+ lowestLevel = unique->size;
+ for (index = firstIndex; index < lastIndex; index++) {
+ level = unique->perm[index];
+ if (level < lowestLevel) lowestLevel = level;
+ nodelist = subtables[level].nodelist;
+ if (subtables[level].keys - subtables[level].dead != 1) return(0);
+ /* The projection function should be isolated. If the ref count
+ ** is 1, everything is OK. If the ref count is saturated, then
+ ** we need to make sure that there are no nodes pointing to it.
+ ** As for the external references, we assume the application is
+ ** responsible for them.
+ */
+ if (vars[index]->ref != 1) {
+ if (vars[index]->ref != DD_MAXREF) return(0);
+ found = cuddFindParent(unique,vars[index]);
+ if (found) {
+ return(0);
+ } else {
+ vars[index]->ref = 1;
+ }
+ }
+ Cudd_RecursiveDeref(unique,vars[index]);
+ }
+
+ /* Collect garbage, because we cannot afford having dead nodes pointing
+ ** to the dead nodes in the subtables being destroyed.
+ */
+ (void) cuddGarbageCollect(unique,1);
+
+ /* Here we know we can destroy our subtables. */
+ for (index = firstIndex; index < lastIndex; index++) {
+ level = unique->perm[index];
+ nodelist = subtables[level].nodelist;
+#ifdef DD_DEBUG
+ assert(subtables[level].keys == 0);
+#endif
+ FREE(nodelist);
+ unique->memused -= sizeof(DdNodePtr) * subtables[level].slots;
+ unique->slots -= subtables[level].slots;
+ unique->dead -= subtables[level].dead;
+ }
+
+ /* Here all subtables to be destroyed have their keys field == 0 and
+ ** their hash tables have been freed.
+ ** We now scan the subtables from level lowestLevel + 1 to level size - 1,
+ ** shifting the subtables as required. We keep a running count of
+ ** how many subtables have been moved, so that we know by how many
+ ** positions each subtable should be shifted.
+ */
+ shift = 1;
+ for (level = lowestLevel + 1; level < unique->size; level++) {
+ if (subtables[level].keys == 0) {
+ shift++;
+ continue;
+ }
+ newlevel = level - shift;
+ subtables[newlevel].slots = subtables[level].slots;
+ subtables[newlevel].shift = subtables[level].shift;
+ subtables[newlevel].keys = subtables[level].keys;
+ subtables[newlevel].maxKeys = subtables[level].maxKeys;
+ subtables[newlevel].dead = subtables[level].dead;
+ subtables[newlevel].nodelist = subtables[level].nodelist;
+ index = unique->invperm[level];
+ unique->perm[index] = newlevel;
+ unique->invperm[newlevel] = index;
+ subtables[newlevel].bindVar = subtables[level].bindVar;
+ subtables[newlevel].varType = subtables[level].varType;
+ subtables[newlevel].pairIndex = subtables[level].pairIndex;
+ subtables[newlevel].varHandled = subtables[level].varHandled;
+ subtables[newlevel].varToBeGrouped = subtables[level].varToBeGrouped;
+ }
+ /* Destroy the map. If a surviving variable is
+ ** mapped to a dying variable, and the map were used again,
+ ** an out-of-bounds access to unique->vars would result. */
+ if (unique->map != NULL) {
+ cuddCacheFlush(unique);
+ FREE(unique->map);
+ unique->map = NULL;
+ }
+
+ unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
+ unique->size -= n;
+
+ return(1);
+
+} /* end of cuddDestroySubtables */
+
+
+/**Function********************************************************************
+
+ Synopsis [Increases the number of ZDD subtables in a unique table so
+ that it meets or exceeds index.]
+
+ Description [Increases the number of ZDD subtables in a unique table so
+ that it meets or exceeds index. When new ZDD variables are created, it
+ is possible to preserve the functions unchanged, or it is possible to
+ preserve the covers unchanged, but not both. cuddResizeTableZdd preserves
+ the covers. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [ddResizeTable]
+
+******************************************************************************/
+int
+cuddResizeTableZdd(
+ DdManager * unique,
+ int index)
+{
+ DdSubtable *newsubtables;
+ DdNodePtr *newnodelist;
+ int oldsize,newsize;
+ int i,j,reorderSave;
+ unsigned int numSlots = unique->initSlots;
+ int *newperm, *newinvperm;
+ DdNode *one, *zero;
+
+ oldsize = unique->sizeZ;
+ /* Easy case: there is still room in the current table. */
+ if (index < unique->maxSizeZ) {
+ for (i = oldsize; i <= index; i++) {
+ unique->subtableZ[i].slots = numSlots;
+ unique->subtableZ[i].shift = sizeof(int) * 8 -
+ cuddComputeFloorLog2(numSlots);
+ unique->subtableZ[i].keys = 0;
+ unique->subtableZ[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
+ unique->subtableZ[i].dead = 0;
+ unique->permZ[i] = i;
+ unique->invpermZ[i] = i;
+ newnodelist = unique->subtableZ[i].nodelist =
+ ALLOC(DdNodePtr, numSlots);
+ if (newnodelist == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (j = 0; j < numSlots; j++) {
+ newnodelist[j] = NULL;
+ }
+ }
+ } else {
+ /* The current table is too small: we need to allocate a new,
+ ** larger one; move all old subtables, and initialize the new
+ ** subtables up to index included.
+ */
+ newsize = index + DD_DEFAULT_RESIZE;
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,
+ "Increasing the ZDD table size from %d to %d\n",
+ unique->maxSizeZ, newsize);
+#endif
+ newsubtables = ALLOC(DdSubtable,newsize);
+ if (newsubtables == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ newperm = ALLOC(int,newsize);
+ if (newperm == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ newinvperm = ALLOC(int,newsize);
+ if (newinvperm == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->memused += (newsize - unique->maxSizeZ) * ((numSlots+1) *
+ sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
+ if (newsize > unique->maxSize) {
+ FREE(unique->stack);
+ unique->stack = ALLOC(DdNodePtr,newsize + 1);
+ if (unique->stack == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->stack[0] = NULL; /* to suppress harmless UMR */
+ unique->memused +=
+ (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
+ * sizeof(DdNode *);
+ }
+ for (i = 0; i < oldsize; i++) {
+ newsubtables[i].slots = unique->subtableZ[i].slots;
+ newsubtables[i].shift = unique->subtableZ[i].shift;
+ newsubtables[i].keys = unique->subtableZ[i].keys;
+ newsubtables[i].maxKeys = unique->subtableZ[i].maxKeys;
+ newsubtables[i].dead = unique->subtableZ[i].dead;
+ newsubtables[i].nodelist = unique->subtableZ[i].nodelist;
+ newperm[i] = unique->permZ[i];
+ newinvperm[i] = unique->invpermZ[i];
+ }
+ for (i = oldsize; i <= index; i++) {
+ newsubtables[i].slots = numSlots;
+ newsubtables[i].shift = sizeof(int) * 8 -
+ cuddComputeFloorLog2(numSlots);
+ newsubtables[i].keys = 0;
+ newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
+ newsubtables[i].dead = 0;
+ newperm[i] = i;
+ newinvperm[i] = i;
+ newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
+ if (newnodelist == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (j = 0; j < numSlots; j++) {
+ newnodelist[j] = NULL;
+ }
+ }
+ FREE(unique->subtableZ);
+ unique->subtableZ = newsubtables;
+ unique->maxSizeZ = newsize;
+ FREE(unique->permZ);
+ unique->permZ = newperm;
+ FREE(unique->invpermZ);
+ unique->invpermZ = newinvperm;
+ }
+ unique->slots += (index + 1 - unique->sizeZ) * numSlots;
+ ddFixLimits(unique);
+ unique->sizeZ = index + 1;
+
+ /* Now that the table is in a coherent state, update the ZDD
+ ** universe. We need to temporarily disable reordering,
+ ** because we cannot reorder without universe in place.
+ */
+ one = unique->one;
+ zero = unique->zero;
+
+ reorderSave = unique->autoDynZ;
+ unique->autoDynZ = 0;
+ cuddZddFreeUniv(unique);
+ if (!cuddZddInitUniv(unique)) {
+ unique->autoDynZ = reorderSave;
+ return(0);
+ }
+ unique->autoDynZ = reorderSave;
+
+ return(1);
+
+} /* end of cuddResizeTableZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Adjusts parameters of a table to slow down its growth.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+cuddSlowTableGrowth(
+ DdManager *unique)
+{
+ int i;
+
+ unique->maxCacheHard = unique->cacheSlots - 1;
+ unique->cacheSlack = -(unique->cacheSlots + 1);
+ for (i = 0; i < unique->size; i++) {
+ unique->subtables[i].maxKeys <<= 2;
+ }
+ unique->gcFrac = DD_GC_FRAC_MIN;
+ unique->minDead = (unsigned) (DD_GC_FRAC_MIN * (double) unique->slots);
+ cuddShrinkDeathRow(unique);
+ (void) fprintf(unique->err,"Slowing down table growth: ");
+ (void) fprintf(unique->err,"GC fraction = %.2f\t", unique->gcFrac);
+ (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
+
+} /* end of cuddSlowTableGrowth */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Rehashes a ZDD unique subtable.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [cuddRehash]
+
+******************************************************************************/
+static void
+ddRehashZdd(
+ DdManager * unique,
+ int i)
+{
+ unsigned int slots, oldslots;
+ int shift, oldshift;
+ int j, pos;
+ DdNodePtr *nodelist, *oldnodelist;
+ DdNode *node, *next;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+
+ if (unique->slots > unique->looseUpTo) {
+ unique->minDead = (unsigned) (DD_GC_FRAC_LO * (double) unique->slots);
+#ifdef DD_VERBOSE
+ if (unique->gcFrac == DD_GC_FRAC_HI) {
+ (void) fprintf(unique->err,"GC fraction = %.2f\t",
+ DD_GC_FRAC_LO);
+ (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
+ }
+#endif
+ unique->gcFrac = DD_GC_FRAC_LO;
+ }
+
+ assert(i != CUDD_MAXINDEX);
+ oldslots = unique->subtableZ[i].slots;
+ oldshift = unique->subtableZ[i].shift;
+ oldnodelist = unique->subtableZ[i].nodelist;
+
+ /* Compute the new size of the subtable. Normally, we just
+ ** double. However, after reordering, a table may be severely
+ ** overloaded. Therefore, we iterate. */
+ slots = oldslots;
+ shift = oldshift;
+ do {
+ slots <<= 1;
+ shift--;
+ } while (slots * DD_MAX_SUBTABLE_DENSITY < unique->subtableZ[i].keys);
+
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ nodelist = ALLOC(DdNodePtr, slots);
+ MMoutOfMemory = saveHandler;
+ if (nodelist == NULL) {
+ int j;
+ (void) fprintf(unique->err,
+ "Unable to resize ZDD subtable %d for lack of memory.\n",
+ i);
+ (void) cuddGarbageCollectZdd(unique,1);
+ for (j = 0; j < unique->sizeZ; j++) {
+ unique->subtableZ[j].maxKeys <<= 1;
+ }
+ return;
+ }
+ unique->subtableZ[i].nodelist = nodelist;
+ unique->subtableZ[i].slots = slots;
+ unique->subtableZ[i].shift = shift;
+ unique->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
+ for (j = 0; (unsigned) j < slots; j++) {
+ nodelist[j] = NULL;
+ }
+ for (j = 0; (unsigned) j < oldslots; j++) {
+ node = oldnodelist[j];
+ while (node != NULL) {
+ next = node->next;
+ pos = ddHash(cuddT(node), cuddE(node), shift);
+ node->next = nodelist[pos];
+ nodelist[pos] = node;
+ node = next;
+ }
+ }
+ FREE(oldnodelist);
+
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,
+ "rehashing layer %d: keys %d dead %d new size %d\n",
+ i, unique->subtableZ[i].keys,
+ unique->subtableZ[i].dead, slots);
+#endif
+
+ /* Update global data. */
+ unique->memused += (slots - oldslots) * sizeof(DdNode *);
+ unique->slots += (slots - oldslots);
+ ddFixLimits(unique);
+
+} /* end of ddRehashZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Increases the number of subtables in a unique table so
+ that it meets or exceeds index.]
+
+ Description [Increases the number of subtables in a unique table so
+ that it meets or exceeds index. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddResizeTableZdd]
+
+******************************************************************************/
+static int
+ddResizeTable(
+ DdManager * unique,
+ int index)
+{
+ DdSubtable *newsubtables;
+ DdNodePtr *newnodelist;
+ DdNodePtr *newvars;
+ DdNode *sentinel = &(unique->sentinel);
+ int oldsize,newsize;
+ int i,j,reorderSave;
+ int numSlots = unique->initSlots;
+ int *newperm, *newinvperm, *newmap;
+ DdNode *one, *zero;
+
+ oldsize = unique->size;
+ /* Easy case: there is still room in the current table. */
+ if (index < unique->maxSize) {
+ for (i = oldsize; i <= index; i++) {
+ unique->subtables[i].slots = numSlots;
+ unique->subtables[i].shift = sizeof(int) * 8 -
+ cuddComputeFloorLog2(numSlots);
+ unique->subtables[i].keys = 0;
+ unique->subtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
+ unique->subtables[i].dead = 0;
+ unique->subtables[i].bindVar = 0;
+ unique->subtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
+ unique->subtables[i].pairIndex = 0;
+ unique->subtables[i].varHandled = 0;
+ unique->subtables[i].varToBeGrouped = CUDD_LAZY_NONE;
+
+ unique->perm[i] = i;
+ unique->invperm[i] = i;
+ newnodelist = unique->subtables[i].nodelist =
+ ALLOC(DdNodePtr, numSlots);
+ if (newnodelist == NULL) {
+ for (j = oldsize; j < i; j++) {
+ FREE(unique->subtables[j].nodelist);
+ }
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (j = 0; j < numSlots; j++) {
+ newnodelist[j] = sentinel;
+ }
+ }
+ if (unique->map != NULL) {
+ for (i = oldsize; i <= index; i++) {
+ unique->map[i] = i;
+ }
+ }
+ } else {
+ /* The current table is too small: we need to allocate a new,
+ ** larger one; move all old subtables, and initialize the new
+ ** subtables up to index included.
+ */
+ newsize = index + DD_DEFAULT_RESIZE;
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,
+ "Increasing the table size from %d to %d\n",
+ unique->maxSize, newsize);
+#endif
+ newsubtables = ALLOC(DdSubtable,newsize);
+ if (newsubtables == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ newvars = ALLOC(DdNodePtr,newsize);
+ if (newvars == NULL) {
+ FREE(newsubtables);
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ newperm = ALLOC(int,newsize);
+ if (newperm == NULL) {
+ FREE(newsubtables);
+ FREE(newvars);
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ newinvperm = ALLOC(int,newsize);
+ if (newinvperm == NULL) {
+ FREE(newsubtables);
+ FREE(newvars);
+ FREE(newperm);
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ if (unique->map != NULL) {
+ newmap = ALLOC(int,newsize);
+ if (newmap == NULL) {
+ FREE(newsubtables);
+ FREE(newvars);
+ FREE(newperm);
+ FREE(newinvperm);
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->memused += (newsize - unique->maxSize) * sizeof(int);
+ }
+ unique->memused += (newsize - unique->maxSize) * ((numSlots+1) *
+ sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
+ if (newsize > unique->maxSizeZ) {
+ FREE(unique->stack);
+ unique->stack = ALLOC(DdNodePtr,newsize + 1);
+ if (unique->stack == NULL) {
+ FREE(newsubtables);
+ FREE(newvars);
+ FREE(newperm);
+ FREE(newinvperm);
+ if (unique->map != NULL) {
+ FREE(newmap);
+ }
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->stack[0] = NULL; /* to suppress harmless UMR */
+ unique->memused +=
+ (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
+ * sizeof(DdNode *);
+ }
+ for (i = 0; i < oldsize; i++) {
+ newsubtables[i].slots = unique->subtables[i].slots;
+ newsubtables[i].shift = unique->subtables[i].shift;
+ newsubtables[i].keys = unique->subtables[i].keys;
+ newsubtables[i].maxKeys = unique->subtables[i].maxKeys;
+ newsubtables[i].dead = unique->subtables[i].dead;
+ newsubtables[i].nodelist = unique->subtables[i].nodelist;
+ newsubtables[i].bindVar = unique->subtables[i].bindVar;
+ newsubtables[i].varType = unique->subtables[i].varType;
+ newsubtables[i].pairIndex = unique->subtables[i].pairIndex;
+ newsubtables[i].varHandled = unique->subtables[i].varHandled;
+ newsubtables[i].varToBeGrouped = unique->subtables[i].varToBeGrouped;
+
+ newvars[i] = unique->vars[i];
+ newperm[i] = unique->perm[i];
+ newinvperm[i] = unique->invperm[i];
+ }
+ for (i = oldsize; i <= index; i++) {
+ newsubtables[i].slots = numSlots;
+ newsubtables[i].shift = sizeof(int) * 8 -
+ cuddComputeFloorLog2(numSlots);
+ newsubtables[i].keys = 0;
+ newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
+ newsubtables[i].dead = 0;
+ newsubtables[i].bindVar = 0;
+ newsubtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
+ newsubtables[i].pairIndex = 0;
+ newsubtables[i].varHandled = 0;
+ newsubtables[i].varToBeGrouped = CUDD_LAZY_NONE;
+
+ newperm[i] = i;
+ newinvperm[i] = i;
+ newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
+ if (newnodelist == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (j = 0; j < numSlots; j++) {
+ newnodelist[j] = sentinel;
+ }
+ }
+ if (unique->map != NULL) {
+ for (i = 0; i < oldsize; i++) {
+ newmap[i] = unique->map[i];
+ }
+ for (i = oldsize; i <= index; i++) {
+ newmap[i] = i;
+ }
+ FREE(unique->map);
+ unique->map = newmap;
+ }
+ FREE(unique->subtables);
+ unique->subtables = newsubtables;
+ unique->maxSize = newsize;
+ FREE(unique->vars);
+ unique->vars = newvars;
+ FREE(unique->perm);
+ unique->perm = newperm;
+ FREE(unique->invperm);
+ unique->invperm = newinvperm;
+ }
+
+ /* Now that the table is in a coherent state, create the new
+ ** projection functions. We need to temporarily disable reordering,
+ ** because we cannot reorder without projection functions in place.
+ **/
+ one = unique->one;
+ zero = Cudd_Not(one);
+
+ unique->size = index + 1;
+ unique->slots += (index + 1 - oldsize) * numSlots;
+ ddFixLimits(unique);
+
+ reorderSave = unique->autoDyn;
+ unique->autoDyn = 0;
+ for (i = oldsize; i <= index; i++) {
+ unique->vars[i] = cuddUniqueInter(unique,i,one,zero);
+ if (unique->vars[i] == NULL) {
+ unique->autoDyn = reorderSave;
+ for (j = oldsize; j < i; j++) {
+ Cudd_IterDerefBdd(unique,unique->vars[j]);
+ cuddDeallocNode(unique,unique->vars[j]);
+ unique->vars[j] = NULL;
+ }
+ for (j = oldsize; j <= index; j++) {
+ FREE(unique->subtables[j].nodelist);
+ unique->subtables[j].nodelist = NULL;
+ }
+ unique->size = oldsize;
+ unique->slots -= (index + 1 - oldsize) * numSlots;
+ ddFixLimits(unique);
+ return(0);
+ }
+ cuddRef(unique->vars[i]);
+ }
+ unique->autoDyn = reorderSave;
+
+ return(1);
+
+} /* end of ddResizeTable */
+
+
+/**Function********************************************************************
+
+ Synopsis [Searches the subtables above node for a parent.]
+
+ Description [Searches the subtables above node for a parent. Returns 1
+ as soon as one parent is found. Returns 0 is the search is fruitless.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddFindParent(
+ DdManager * table,
+ DdNode * node)
+{
+ int i,j;
+ int slots;
+ DdNodePtr *nodelist;
+ DdNode *f;
+
+ for (i = cuddI(table,node->index) - 1; i >= 0; i--) {
+ nodelist = table->subtables[i].nodelist;
+ slots = table->subtables[i].slots;
+
+ for (j = 0; j < slots; j++) {
+ f = nodelist[j];
+ while (cuddT(f) > node) {
+ f = f->next;
+ }
+ while (cuddT(f) == node && Cudd_Regular(cuddE(f)) > node) {
+ f = f->next;
+ }
+ if (cuddT(f) == node && Cudd_Regular(cuddE(f)) == node) {
+ return(1);
+ }
+ }
+ }
+
+ return(0);
+
+} /* end of cuddFindParent */
+
+
+/**Function********************************************************************
+
+ Synopsis [Adjusts the values of table limits.]
+
+ Description [Adjusts the values of table fields controlling the.
+ sizes of subtables and computed table. If the computed table is too small
+ according to the new values, it is resized.]
+
+ SideEffects [Modifies manager fields. May resize computed table.]
+
+ SeeAlso []
+
+******************************************************************************/
+DD_INLINE
+static void
+ddFixLimits(
+ DdManager *unique)
+{
+ unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
+ unique->cacheSlack = (int) ddMin(unique->maxCacheHard,
+ DD_MAX_CACHE_TO_SLOTS_RATIO * unique->slots) -
+ 2 * (int) unique->cacheSlots;
+ if (unique->cacheSlots < unique->slots/2 && unique->cacheSlack >= 0)
+ cuddCacheResize(unique);
+ return;
+
+} /* end of ddFixLimits */
+
+
+#ifndef DD_UNSORTED_FREE_LIST
+/**Function********************************************************************
+
+ Synopsis [Inserts a DdNode in a red/black search tree.]
+
+ Description [Inserts a DdNode in a red/black search tree. Nodes from
+ the same "page" (defined by DD_PAGE_MASK) are linked in a LIFO list.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddOrderedThread]
+
+******************************************************************************/
+static void
+cuddOrderedInsert(
+ DdNodePtr * root,
+ DdNodePtr node)
+{
+ DdNode *scan;
+ DdNodePtr *scanP;
+ DdNodePtr *stack[DD_STACK_SIZE];
+ int stackN = 0;
+
+ scanP = root;
+ while ((scan = *scanP) != NULL) {
+ stack[stackN++] = scanP;
+ if (DD_INSERT_COMPARE(node, scan) == 0) { /* add to page list */
+ DD_NEXT(node) = DD_NEXT(scan);
+ DD_NEXT(scan) = node;
+ return;
+ }
+ scanP = (node < scan) ? &DD_LEFT(scan) : &DD_RIGHT(scan);
+ }
+ DD_RIGHT(node) = DD_LEFT(node) = DD_NEXT(node) = NULL;
+ DD_COLOR(node) = DD_RED;
+ *scanP = node;
+ stack[stackN] = &node;
+ cuddDoRebalance(stack,stackN);
+
+} /* end of cuddOrderedInsert */
+
+
+/**Function********************************************************************
+
+ Synopsis [Threads all the nodes of a search tree into a linear list.]
+
+ Description [Threads all the nodes of a search tree into a linear
+ list. For each node of the search tree, the "left" child, if non-null, has
+ a lower address than its parent, and the "right" child, if non-null, has a
+ higher address than its parent.
+ The list is sorted in order of increasing addresses. The search
+ tree is destroyed as a result of this operation. The last element of
+ the linear list is made to point to the address passed in list. Each
+ node if the search tree is a linearly-linked list of nodes from the
+ same memory page (as defined in DD_PAGE_MASK). When a node is added to
+ the linear list, all the elements of the linked list are added.]
+
+ SideEffects [The search tree is destroyed as a result of this operation.]
+
+ SeeAlso [cuddOrderedInsert]
+
+******************************************************************************/
+static DdNode *
+cuddOrderedThread(
+ DdNode * root,
+ DdNode * list)
+{
+ DdNode *current, *next, *prev, *end;
+
+ current = root;
+ /* The first word in the node is used to implement a stack that holds
+ ** the nodes from the root of the tree to the current node. Here we
+ ** put the root of the tree at the bottom of the stack.
+ */
+ *((DdNodePtr *) current) = NULL;
+
+ while (current != NULL) {
+ if (DD_RIGHT(current) != NULL) {
+ /* If possible, we follow the "right" link. Eventually we'll
+ ** find the node with the largest address in the current tree.
+ ** In this phase we use the first word of a node to implemen
+ ** a stack of the nodes on the path from the root to "current".
+ ** Also, we disconnect the "right" pointers to indicate that
+ ** we have already followed them.
+ */
+ next = DD_RIGHT(current);
+ DD_RIGHT(current) = NULL;
+ *((DdNodePtr *)next) = current;
+ current = next;
+ } else {
+ /* We can't proceed along the "right" links any further.
+ ** Hence "current" is the largest element in the current tree.
+ ** We make this node the new head of "list". (Repeating this
+ ** operation until the tree is empty yields the desired linear
+ ** threading of all nodes.)
+ */
+ prev = *((DdNodePtr *) current); /* save prev node on stack in prev */
+ /* Traverse the linked list of current until the end. */
+ for (end = current; DD_NEXT(end) != NULL; end = DD_NEXT(end));
+ DD_NEXT(end) = list; /* attach "list" at end and make */
+ list = current; /* "current" the new head of "list" */
+ /* Now, if current has a "left" child, we push it on the stack.
+ ** Otherwise, we just continue with the parent of "current".
+ */
+ if (DD_LEFT(current) != NULL) {
+ next = DD_LEFT(current);
+ *((DdNodePtr *) next) = prev;
+ current = next;
+ } else {
+ current = prev;
+ }
+ }
+ }
+
+ return(list);
+
+} /* end of cuddOrderedThread */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the left rotation for red/black trees.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [cuddRotateRight]
+
+******************************************************************************/
+DD_INLINE
+static void
+cuddRotateLeft(
+ DdNodePtr * nodeP)
+{
+ DdNode *newRoot;
+ DdNode *oldRoot = *nodeP;
+
+ *nodeP = newRoot = DD_RIGHT(oldRoot);
+ DD_RIGHT(oldRoot) = DD_LEFT(newRoot);
+ DD_LEFT(newRoot) = oldRoot;
+
+} /* end of cuddRotateLeft */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the right rotation for red/black trees.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [cuddRotateLeft]
+
+******************************************************************************/
+DD_INLINE
+static void
+cuddRotateRight(
+ DdNodePtr * nodeP)
+{
+ DdNode *newRoot;
+ DdNode *oldRoot = *nodeP;
+
+ *nodeP = newRoot = DD_LEFT(oldRoot);
+ DD_LEFT(oldRoot) = DD_RIGHT(newRoot);
+ DD_RIGHT(newRoot) = oldRoot;
+
+} /* end of cuddRotateRight */
+
+
+/**Function********************************************************************
+
+ Synopsis [Rebalances a red/black tree.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+cuddDoRebalance(
+ DdNodePtr ** stack,
+ int stackN)
+{
+ DdNodePtr *xP, *parentP, *grandpaP;
+ DdNode *x, *y, *parent, *grandpa;
+
+ xP = stack[stackN];
+ x = *xP;
+ /* Work our way back up, re-balancing the tree. */
+ while (--stackN >= 0) {
+ parentP = stack[stackN];
+ parent = *parentP;
+ if (DD_IS_BLACK(parent)) break;
+ /* Since the root is black, here a non-null grandparent exists. */
+ grandpaP = stack[stackN-1];
+ grandpa = *grandpaP;
+ if (parent == DD_LEFT(grandpa)) {
+ y = DD_RIGHT(grandpa);
+ if (y != NULL && DD_IS_RED(y)) {
+ DD_COLOR(parent) = DD_BLACK;
+ DD_COLOR(y) = DD_BLACK;
+ DD_COLOR(grandpa) = DD_RED;
+ x = grandpa;
+ stackN--;
+ } else {
+ if (x == DD_RIGHT(parent)) {
+ cuddRotateLeft(parentP);
+ DD_COLOR(x) = DD_BLACK;
+ } else {
+ DD_COLOR(parent) = DD_BLACK;
+ }
+ DD_COLOR(grandpa) = DD_RED;
+ cuddRotateRight(grandpaP);
+ break;
+ }
+ } else {
+ y = DD_LEFT(grandpa);
+ if (y != NULL && DD_IS_RED(y)) {
+ DD_COLOR(parent) = DD_BLACK;
+ DD_COLOR(y) = DD_BLACK;
+ DD_COLOR(grandpa) = DD_RED;
+ x = grandpa;
+ stackN--;
+ } else {
+ if (x == DD_LEFT(parent)) {
+ cuddRotateRight(parentP);
+ DD_COLOR(x) = DD_BLACK;
+ } else {
+ DD_COLOR(parent) = DD_BLACK;
+ }
+ DD_COLOR(grandpa) = DD_RED;
+ cuddRotateLeft(grandpaP);
+ }
+ }
+ }
+ DD_COLOR(*(stack[0])) = DD_BLACK;
+
+} /* end of cuddDoRebalance */
+#endif
+
+
+/**Function********************************************************************
+
+ Synopsis [Fixes a variable tree after the insertion of new subtables.]
+
+ Description [Fixes a variable tree after the insertion of new subtables.
+ After such an insertion, the low fields of the tree below the insertion
+ point are inconsistent.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ddPatchTree(
+ DdManager *dd,
+ MtrNode *treenode)
+{
+ MtrNode *auxnode = treenode;
+
+ while (auxnode != NULL) {
+ auxnode->low = dd->perm[auxnode->index];
+ if (auxnode->child != NULL) {
+ ddPatchTree(dd, auxnode->child);
+ }
+ auxnode = auxnode->younger;
+ }
+
+ return;
+
+} /* end of ddPatchTree */
+
+
+#ifdef DD_DEBUG
+/**Function********************************************************************
+
+ Synopsis [Checks whether a collision list is ordered.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddCheckCollisionOrdering(
+ DdManager *unique,
+ int i,
+ int j)
+{
+ int slots;
+ DdNode *node, *next;
+ DdNodePtr *nodelist;
+ DdNode *sentinel = &(unique->sentinel);
+
+ nodelist = unique->subtables[i].nodelist;
+ slots = unique->subtables[i].slots;
+ node = nodelist[j];
+ if (node == sentinel) return(1);
+ next = node->next;
+ while (next != sentinel) {
+ if (cuddT(node) < cuddT(next) ||
+ (cuddT(node) == cuddT(next) && cuddE(node) < cuddE(next))) {
+ (void) fprintf(unique->err,
+ "Unordered list: index %u, position %d\n", i, j);
+ return(0);
+ }
+ node = next;
+ next = node->next;
+ }
+ return(1);
+
+} /* end of cuddCheckCollisionOrdering */
+#endif
+
+
+
+
+/**Function********************************************************************
+
+ Synopsis [Reports problem in garbage collection.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [cuddGarbageCollect cuddGarbageCollectZdd]
+
+******************************************************************************/
+static void
+ddReportRefMess(
+ DdManager *unique /* manager */,
+ int i /* table in which the problem occurred */,
+ char *caller /* procedure that detected the problem */)
+{
+ if (i == CUDD_CONST_INDEX) {
+ (void) fprintf(unique->err,
+ "%s: problem in constants\n", caller);
+ } else if (i != -1) {
+ (void) fprintf(unique->err,
+ "%s: problem in table %d\n", caller, i);
+ }
+ (void) fprintf(unique->err, " dead count != deleted\n");
+ (void) fprintf(unique->err, " This problem is often due to a missing \
+call to Cudd_Ref\n or to an extra call to Cudd_RecursiveDeref.\n \
+See the CUDD Programmer's Guide for additional details.");
+ abort();
+
+} /* end of ddReportRefMess */
diff --git a/src/bdd/cudd/cuddUtil.c b/src/bdd/cudd/cuddUtil.c
new file mode 100644
index 00000000..c366d534
--- /dev/null
+++ b/src/bdd/cudd/cuddUtil.c
@@ -0,0 +1,3633 @@
+/**CFile***********************************************************************
+
+ FileName [cuddUtil.c]
+
+ PackageName [cudd]
+
+ Synopsis [Utility functions.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_PrintMinterm()
+ <li> Cudd_PrintDebug()
+ <li> Cudd_DagSize()
+ <li> Cudd_EstimateCofactor()
+ <li> Cudd_EstimateCofactorSimple()
+ <li> Cudd_SharingSize()
+ <li> Cudd_CountMinterm()
+ <li> Cudd_EpdCountMinterm()
+ <li> Cudd_CountPath()
+ <li> Cudd_CountPathsToNonZero()
+ <li> Cudd_Support()
+ <li> Cudd_SupportIndex()
+ <li> Cudd_SupportSize()
+ <li> Cudd_VectorSupport()
+ <li> Cudd_VectorSupportIndex()
+ <li> Cudd_VectorSupportSize()
+ <li> Cudd_ClassifySupport()
+ <li> Cudd_CountLeaves()
+ <li> Cudd_bddPickOneCube()
+ <li> Cudd_bddPickOneMinterm()
+ <li> Cudd_bddPickArbitraryMinterms()
+ <li> Cudd_SubsetWithMaskVars()
+ <li> Cudd_FirstCube()
+ <li> Cudd_NextCube()
+ <li> Cudd_bddComputeCube()
+ <li> Cudd_addComputeCube()
+ <li> Cudd_FirstNode()
+ <li> Cudd_NextNode()
+ <li> Cudd_GenFree()
+ <li> Cudd_IsGenEmpty()
+ <li> Cudd_IndicesToCube()
+ <li> Cudd_PrintVersion()
+ <li> Cudd_AverageDistance()
+ <li> Cudd_Random()
+ <li> Cudd_Srandom()
+ <li> Cudd_Density()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddP()
+ <li> cuddStCountfree()
+ <li> cuddCollectNodes()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> dp2()
+ <li> ddPrintMintermAux()
+ <li> ddDagInt()
+ <li> ddCountMintermAux()
+ <li> ddEpdCountMintermAux()
+ <li> ddCountPathAux()
+ <li> ddSupportStep()
+ <li> ddClearFlag()
+ <li> ddLeavesInt()
+ <li> ddPickArbitraryMinterms()
+ <li> ddPickRepresentativeCube()
+ <li> ddEpdFree()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/* Random generator constants. */
+#define MODULUS1 2147483563
+#define LEQA1 40014
+#define LEQQ1 53668
+#define LEQR1 12211
+#define MODULUS2 2147483399
+#define LEQA2 40692
+#define LEQQ2 52774
+#define LEQR2 3791
+#define STAB_SIZE 64
+#define STAB_DIV (1 + (MODULUS1 - 1) / STAB_SIZE)
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddUtil.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+static DdNode *background, *zero;
+
+static long cuddRand = 0;
+static long cuddRand2;
+static long shuffleSelect;
+static long shuffleTable[STAB_SIZE];
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+#define bang(f) ((Cudd_IsComplement(f)) ? '!' : ' ')
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int dp2 ARGS((DdManager *dd, DdNode *f, st_table *t));
+static void ddPrintMintermAux ARGS((DdManager *dd, DdNode *node, int *list));
+static int ddDagInt ARGS((DdNode *n));
+static int cuddEstimateCofactor ARGS((DdManager *dd, st_table *table, DdNode * node, int i, int phase, DdNode ** ptr));
+static DdNode * cuddUniqueLookup ARGS((DdManager * unique, int index, DdNode * T, DdNode * E));
+static int cuddEstimateCofactorSimple ARGS((DdNode * node, int i));
+static double ddCountMintermAux ARGS((DdNode *node, double max, DdHashTable *table));
+static int ddEpdCountMintermAux ARGS((DdNode *node, EpDouble *max, EpDouble *epd, st_table *table));
+static double ddCountPathAux ARGS((DdNode *node, st_table *table));
+static double ddCountPathsToNonZero ARGS((DdNode * N, st_table * table));
+static void ddSupportStep ARGS((DdNode *f, int *support));
+static void ddClearFlag ARGS((DdNode *f));
+static int ddLeavesInt ARGS((DdNode *n));
+static int ddPickArbitraryMinterms ARGS((DdManager *dd, DdNode *node, int nvars, int nminterms, char **string));
+static int ddPickRepresentativeCube ARGS((DdManager *dd, DdNode *node, int nvars, double *weight, char *string));
+static enum st_retval ddEpdFree ARGS((char * key, char * value, char * arg));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints a disjoint sum of products.]
+
+ Description [Prints a disjoint sum of product cover for the function
+ rooted at node. Each product corresponds to a path from node to a
+ leaf node different from the logical zero, and different from the
+ background value. Uses the package default output file. Returns 1
+ if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_PrintDebug Cudd_bddPrintCover]
+
+******************************************************************************/
+int
+Cudd_PrintMinterm(
+ DdManager * manager,
+ DdNode * node)
+{
+ int i, *list;
+
+ background = manager->background;
+ zero = Cudd_Not(manager->one);
+ list = ALLOC(int,manager->size);
+ if (list == NULL) {
+ manager->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (i = 0; i < manager->size; i++) list[i] = 2;
+ ddPrintMintermAux(manager,node,list);
+ FREE(list);
+ return(1);
+
+} /* end of Cudd_PrintMinterm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints a sum of prime implicants of a BDD.]
+
+ Description [Prints a sum of product cover for an incompletely
+ specified function given by a lower bound and an upper bound. Each
+ product is a prime implicant obtained by expanding the product
+ corresponding to a path from node to the constant one. Uses the
+ package default output file. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_PrintMinterm]
+
+******************************************************************************/
+int
+Cudd_bddPrintCover(
+ DdManager *dd,
+ DdNode *l,
+ DdNode *u)
+{
+ int *array;
+ int q, result;
+ DdNode *lb;
+#ifdef DD_DEBUG
+ DdNode *cover;
+#endif
+
+ array = ALLOC(int, Cudd_ReadSize(dd));
+ if (array == NULL) return(0);
+ lb = l;
+ cuddRef(lb);
+#ifdef DD_DEBUG
+ cover = Cudd_ReadLogicZero(dd);
+ cuddRef(cover);
+#endif
+ while (lb != Cudd_ReadLogicZero(dd)) {
+ DdNode *implicant, *prime, *tmp;
+ int length;
+ implicant = Cudd_LargestCube(dd,lb,&length);
+ if (implicant == NULL) {
+ Cudd_RecursiveDeref(dd,lb);
+ FREE(array);
+ return(0);
+ }
+ cuddRef(implicant);
+ prime = Cudd_bddMakePrime(dd,implicant,u);
+ if (prime == NULL) {
+ Cudd_RecursiveDeref(dd,lb);
+ Cudd_RecursiveDeref(dd,implicant);
+ FREE(array);
+ return(0);
+ }
+ cuddRef(prime);
+ Cudd_RecursiveDeref(dd,implicant);
+ tmp = Cudd_bddAnd(dd,lb,Cudd_Not(prime));
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(dd,lb);
+ Cudd_RecursiveDeref(dd,prime);
+ FREE(array);
+ return(0);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(dd,lb);
+ lb = tmp;
+ result = Cudd_BddToCubeArray(dd,prime,array);
+ if (result == 0) {
+ Cudd_RecursiveDeref(dd,lb);
+ Cudd_RecursiveDeref(dd,prime);
+ FREE(array);
+ return(0);
+ }
+ for (q = 0; q < dd->size; q++) {
+ switch (array[q]) {
+ case 0:
+ (void) fprintf(dd->out, "0");
+ break;
+ case 1:
+ (void) fprintf(dd->out, "1");
+ break;
+ case 2:
+ (void) fprintf(dd->out, "-");
+ break;
+ default:
+ (void) fprintf(dd->out, "?");
+ }
+ }
+ (void) fprintf(dd->out, " 1\n");
+#ifdef DD_DEBUG
+ tmp = Cudd_bddOr(dd,prime,cover);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(dd,cover);
+ Cudd_RecursiveDeref(dd,lb);
+ Cudd_RecursiveDeref(dd,prime);
+ FREE(array);
+ return(0);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(dd,cover);
+ cover = tmp;
+#endif
+ Cudd_RecursiveDeref(dd,prime);
+ }
+ (void) fprintf(dd->out, "\n");
+ Cudd_RecursiveDeref(dd,lb);
+ FREE(array);
+#ifdef DD_DEBUG
+ if (!Cudd_bddLeq(dd,cover,u) || !Cudd_bddLeq(dd,l,cover)) {
+ Cudd_RecursiveDeref(dd,cover);
+ return(0);
+ }
+ Cudd_RecursiveDeref(dd,cover);
+#endif
+ return(1);
+
+} /* end of Cudd_bddPrintCover */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints to the standard output a DD and its statistics.]
+
+ Description [Prints to the standard output a DD and its statistics.
+ The statistics include the number of nodes, the number of leaves, and
+ the number of minterms. (The number of minterms is the number of
+ assignments to the variables that cause the function to be different
+ from the logical zero (for BDDs) and from the background value (for
+ ADDs.) The statistics are printed if pr &gt; 0. Specifically:
+ <ul>
+ <li> pr = 0 : prints nothing
+ <li> pr = 1 : prints counts of nodes and minterms
+ <li> pr = 2 : prints counts + disjoint sum of product
+ <li> pr = 3 : prints counts + list of nodes
+ <li> pr &gt; 3 : prints counts + disjoint sum of product + list of nodes
+ </ul>
+ For the purpose of counting the number of minterms, the function is
+ supposed to depend on n variables. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DagSize Cudd_CountLeaves Cudd_CountMinterm
+ Cudd_PrintMinterm]
+
+******************************************************************************/
+int
+Cudd_PrintDebug(
+ DdManager * dd,
+ DdNode * f,
+ int n,
+ int pr)
+{
+ DdNode *azero, *bzero;
+ int nodes;
+ int leaves;
+ double minterms;
+ int retval = 1;
+
+ if (f == NULL) {
+ (void) fprintf(dd->out,": is the NULL DD\n");
+ (void) fflush(dd->out);
+ return(0);
+ }
+ azero = DD_ZERO(dd);
+ bzero = Cudd_Not(DD_ONE(dd));
+ if ((f == azero || f == bzero) && pr > 0){
+ (void) fprintf(dd->out,": is the zero DD\n");
+ (void) fflush(dd->out);
+ return(1);
+ }
+ if (pr > 0) {
+ nodes = Cudd_DagSize(f);
+ if (nodes == CUDD_OUT_OF_MEM) retval = 0;
+ leaves = Cudd_CountLeaves(f);
+ if (leaves == CUDD_OUT_OF_MEM) retval = 0;
+ minterms = Cudd_CountMinterm(dd, f, n);
+ if (minterms == (double)CUDD_OUT_OF_MEM) retval = 0;
+ (void) fprintf(dd->out,": %d nodes %d leaves %g minterms\n",
+ nodes, leaves, minterms);
+ if (pr > 2) {
+ if (!cuddP(dd, f)) retval = 0;
+ }
+ if (pr == 2 || pr > 3) {
+ if (!Cudd_PrintMinterm(dd,f)) retval = 0;
+ (void) fprintf(dd->out,"\n");
+ }
+ (void) fflush(dd->out);
+ }
+ return(retval);
+
+} /* end of Cudd_PrintDebug */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of nodes in a DD.]
+
+ Description [Counts the number of nodes in a DD. Returns the number
+ of nodes in the graph rooted at node.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SharingSize Cudd_PrintDebug]
+
+******************************************************************************/
+int
+Cudd_DagSize(
+ DdNode * node)
+{
+ int i;
+
+ i = ddDagInt(Cudd_Regular(node));
+ ddClearFlag(Cudd_Regular(node));
+
+ return(i);
+
+} /* end of Cudd_DagSize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Estimates the number of nodes in a cofactor of a DD.]
+
+ Description [Estimates the number of nodes in a cofactor of a DD.
+ Returns an estimate of the number of nodes in a cofactor of
+ the graph rooted at node with respect to the variable whose index is i.
+ In case of failure, returns CUDD_OUT_OF_MEM.
+ This function uses a refinement of the algorithm of Cabodi et al.
+ (ICCAD96). The refinement allows the procedure to account for part
+ of the recombination that may occur in the part of the cofactor above
+ the cofactoring variable. This procedure does no create any new node.
+ It does keep a small table of results; therefore itmay run out of memory.
+ If this is a concern, one should use Cudd_EstimateCofactorSimple, which
+ is faster, does not allocate any memory, but is less accurate.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DagSize Cudd_EstimateCofactorSimple]
+
+******************************************************************************/
+int
+Cudd_EstimateCofactor(
+ DdManager *dd /* manager */,
+ DdNode * f /* function */,
+ int i /* index of variable */,
+ int phase /* 1: positive; 0: negative */
+ )
+{
+ int val;
+ DdNode *ptr;
+ st_table *table;
+
+ table = st_init_table(st_ptrcmp,st_ptrhash);
+ if (table == NULL) return(CUDD_OUT_OF_MEM);
+ val = cuddEstimateCofactor(dd,table,Cudd_Regular(f),i,phase,&ptr);
+ ddClearFlag(Cudd_Regular(f));
+ st_free_table(table);
+
+ return(val);
+
+} /* end of Cudd_EstimateCofactor */
+
+
+/**Function********************************************************************
+
+ Synopsis [Estimates the number of nodes in a cofactor of a DD.]
+
+ Description [Estimates the number of nodes in a cofactor of a DD.
+ Returns an estimate of the number of nodes in the positive cofactor of
+ the graph rooted at node with respect to the variable whose index is i.
+ This procedure implements with minor changes the algorithm of Cabodi et al.
+ (ICCAD96). It does not allocate any memory, it does not change the
+ state of the manager, and it is fast. However, it has been observed to
+ overestimate the size of the cofactor by as much as a factor of 2.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DagSize]
+
+******************************************************************************/
+int
+Cudd_EstimateCofactorSimple(
+ DdNode * node,
+ int i)
+{
+ int val;
+
+ val = cuddEstimateCofactorSimple(Cudd_Regular(node),i);
+ ddClearFlag(Cudd_Regular(node));
+
+ return(val);
+
+} /* end of Cudd_EstimateCofactorSimple */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of nodes in an array of DDs.]
+
+ Description [Counts the number of nodes in an array of DDs. Shared
+ nodes are counted only once. Returns the total number of nodes.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DagSize]
+
+******************************************************************************/
+int
+Cudd_SharingSize(
+ DdNode ** nodeArray,
+ int n)
+{
+ int i,j;
+
+ i = 0;
+ for (j = 0; j < n; j++) {
+ i += ddDagInt(Cudd_Regular(nodeArray[j]));
+ }
+ for (j = 0; j < n; j++) {
+ ddClearFlag(Cudd_Regular(nodeArray[j]));
+ }
+ return(i);
+
+} /* end of Cudd_SharingSize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of minterms of a DD.]
+
+ Description [Counts the number of minterms of a DD. The function is
+ assumed to depend on nvars variables. The minterm count is
+ represented as a double, to allow for a larger number of variables.
+ Returns the number of minterms of the function rooted at node if
+ successful; (double) CUDD_OUT_OF_MEM otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_PrintDebug Cudd_CountPath]
+
+******************************************************************************/
+double
+Cudd_CountMinterm(
+ DdManager * manager,
+ DdNode * node,
+ int nvars)
+{
+ double max;
+ DdHashTable *table;
+ double res;
+ CUDD_VALUE_TYPE epsilon;
+
+ background = manager->background;
+ zero = Cudd_Not(manager->one);
+
+ max = pow(2.0,(double)nvars);
+ table = cuddHashTableInit(manager,1,2);
+ if (table == NULL) {
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ epsilon = Cudd_ReadEpsilon(manager);
+ Cudd_SetEpsilon(manager,(CUDD_VALUE_TYPE)0.0);
+ res = ddCountMintermAux(node,max,table);
+ cuddHashTableQuit(table);
+ Cudd_SetEpsilon(manager,epsilon);
+
+ return(res);
+
+} /* end of Cudd_CountMinterm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of paths of a DD.]
+
+ Description [Counts the number of paths of a DD. Paths to all
+ terminal nodes are counted. The path count is represented as a
+ double, to allow for a larger number of variables. Returns the
+ number of paths of the function rooted at node if successful;
+ (double) CUDD_OUT_OF_MEM otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_CountMinterm]
+
+******************************************************************************/
+double
+Cudd_CountPath(
+ DdNode * node)
+{
+
+ st_table *table;
+ double i;
+
+ table = st_init_table(st_ptrcmp,st_ptrhash);
+ if (table == NULL) {
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ i = ddCountPathAux(Cudd_Regular(node),table);
+ st_foreach(table, cuddStCountfree, NULL);
+ st_free_table(table);
+ return(i);
+
+} /* end of Cudd_CountPath */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of minterms of a DD with extended precision.]
+
+ Description [Counts the number of minterms of a DD with extended precision.
+ The function is assumed to depend on nvars variables. The minterm count is
+ represented as an EpDouble, to allow any number of variables.
+ Returns 0 if successful; CUDD_OUT_OF_MEM otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_PrintDebug Cudd_CountPath]
+
+******************************************************************************/
+int
+Cudd_EpdCountMinterm(
+ DdManager * manager,
+ DdNode * node,
+ int nvars,
+ EpDouble * epd)
+{
+ EpDouble max, tmp;
+ st_table *table;
+ int status;
+
+ background = manager->background;
+ zero = Cudd_Not(manager->one);
+
+ EpdPow2(nvars, &max);
+ table = st_init_table(EpdCmp, st_ptrhash);
+ if (table == NULL) {
+ EpdMakeZero(epd, 0);
+ return(CUDD_OUT_OF_MEM);
+ }
+ status = ddEpdCountMintermAux(Cudd_Regular(node),&max,epd,table);
+ st_foreach(table, ddEpdFree, NULL);
+ st_free_table(table);
+ if (status == CUDD_OUT_OF_MEM) {
+ EpdMakeZero(epd, 0);
+ return(CUDD_OUT_OF_MEM);
+ }
+ if (Cudd_IsComplement(node)) {
+ EpdSubtract3(&max, epd, &tmp);
+ EpdCopy(&tmp, epd);
+ }
+ return(0);
+
+} /* end of Cudd_EpdCountMinterm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of paths to a non-zero terminal of a DD.]
+
+ Description [Counts the number of paths to a non-zero terminal of a
+ DD. The path count is
+ represented as a double, to allow for a larger number of variables.
+ Returns the number of paths of the function rooted at node.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_CountMinterm Cudd_CountPath]
+
+******************************************************************************/
+double
+Cudd_CountPathsToNonZero(
+ DdNode * node)
+{
+
+ st_table *table;
+ double i;
+
+ table = st_init_table(st_ptrcmp,st_ptrhash);
+ if (table == NULL) {
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ i = ddCountPathsToNonZero(node,table);
+ st_foreach(table, cuddStCountfree, NULL);
+ st_free_table(table);
+ return(i);
+
+} /* end of Cudd_CountPathsToNonZero */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the variables on which a DD depends.]
+
+ Description [Finds the variables on which a DD depends.
+ Returns a BDD consisting of the product of the variables if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_VectorSupport Cudd_ClassifySupport]
+
+******************************************************************************/
+DdNode *
+Cudd_Support(
+ DdManager * dd /* manager */,
+ DdNode * f /* DD whose support is sought */)
+{
+ int *support;
+ DdNode *res, *tmp, *var;
+ int i,j;
+ int size;
+
+ /* Allocate and initialize support array for ddSupportStep. */
+ size = ddMax(dd->size, dd->sizeZ);
+ support = ALLOC(int,size);
+ if (support == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < size; i++) {
+ support[i] = 0;
+ }
+
+ /* Compute support and clean up markers. */
+ ddSupportStep(Cudd_Regular(f),support);
+ ddClearFlag(Cudd_Regular(f));
+
+ /* Transform support from array to cube. */
+ do {
+ dd->reordered = 0;
+ res = DD_ONE(dd);
+ cuddRef(res);
+ for (j = size - 1; j >= 0; j--) { /* for each level bottom-up */
+ i = (j >= dd->size) ? j : dd->invperm[j];
+ if (support[i] == 1) {
+ var = cuddUniqueInter(dd,i,dd->one,Cudd_Not(dd->one));
+ cuddRef(var);
+ tmp = cuddBddAndRecur(dd,res,var);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(dd,res);
+ Cudd_RecursiveDeref(dd,var);
+ res = NULL;
+ break;
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(dd,res);
+ Cudd_RecursiveDeref(dd,var);
+ res = tmp;
+ }
+ }
+ } while (dd->reordered == 1);
+
+ FREE(support);
+ if (res != NULL) cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_Support */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the variables on which a DD depends.]
+
+ Description [Finds the variables on which a DD depends.
+ Returns an index array of the variables if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Support Cudd_VectorSupport Cudd_ClassifySupport]
+
+******************************************************************************/
+int *
+Cudd_SupportIndex(
+ DdManager * dd /* manager */,
+ DdNode * f /* DD whose support is sought */)
+{
+ int *support;
+ int i;
+ int size;
+
+ /* Allocate and initialize support array for ddSupportStep. */
+ size = ddMax(dd->size, dd->sizeZ);
+ support = ALLOC(int,size);
+ if (support == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < size; i++) {
+ support[i] = 0;
+ }
+
+ /* Compute support and clean up markers. */
+ ddSupportStep(Cudd_Regular(f),support);
+ ddClearFlag(Cudd_Regular(f));
+
+ return(support);
+
+} /* end of Cudd_SupportIndex */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the variables on which a DD depends.]
+
+ Description [Counts the variables on which a DD depends.
+ Returns the number of the variables if successful; CUDD_OUT_OF_MEM
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Support]
+
+******************************************************************************/
+int
+Cudd_SupportSize(
+ DdManager * dd /* manager */,
+ DdNode * f /* DD whose support size is sought */)
+{
+ int *support;
+ int i;
+ int size;
+ int count;
+
+ /* Allocate and initialize support array for ddSupportStep. */
+ size = ddMax(dd->size, dd->sizeZ);
+ support = ALLOC(int,size);
+ if (support == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(CUDD_OUT_OF_MEM);
+ }
+ for (i = 0; i < size; i++) {
+ support[i] = 0;
+ }
+
+ /* Compute support and clean up markers. */
+ ddSupportStep(Cudd_Regular(f),support);
+ ddClearFlag(Cudd_Regular(f));
+
+ /* Count support variables. */
+ count = 0;
+ for (i = 0; i < size; i++) {
+ if (support[i] == 1) count++;
+ }
+
+ FREE(support);
+ return(count);
+
+} /* end of Cudd_SupportSize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the variables on which a set of DDs depends.]
+
+ Description [Finds the variables on which a set of DDs depends.
+ The set must contain either BDDs and ADDs, or ZDDs.
+ Returns a BDD consisting of the product of the variables if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Support Cudd_ClassifySupport]
+
+******************************************************************************/
+DdNode *
+Cudd_VectorSupport(
+ DdManager * dd /* manager */,
+ DdNode ** F /* array of DDs whose support is sought */,
+ int n /* size of the array */)
+{
+ int *support;
+ DdNode *res, *tmp, *var;
+ int i,j;
+ int size;
+
+ /* Allocate and initialize support array for ddSupportStep. */
+ size = ddMax(dd->size, dd->sizeZ);
+ support = ALLOC(int,size);
+ if (support == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < size; i++) {
+ support[i] = 0;
+ }
+
+ /* Compute support and clean up markers. */
+ for (i = 0; i < n; i++) {
+ ddSupportStep(Cudd_Regular(F[i]),support);
+ }
+ for (i = 0; i < n; i++) {
+ ddClearFlag(Cudd_Regular(F[i]));
+ }
+
+ /* Transform support from array to cube. */
+ res = DD_ONE(dd);
+ cuddRef(res);
+ for (j = size - 1; j >= 0; j--) { /* for each level bottom-up */
+ i = (j >= dd->size) ? j : dd->invperm[j];
+ if (support[i] == 1) {
+ var = cuddUniqueInter(dd,i,dd->one,Cudd_Not(dd->one));
+ cuddRef(var);
+ tmp = Cudd_bddAnd(dd,res,var);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(dd,res);
+ Cudd_RecursiveDeref(dd,var);
+ FREE(support);
+ return(NULL);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(dd,res);
+ Cudd_RecursiveDeref(dd,var);
+ res = tmp;
+ }
+ }
+
+ FREE(support);
+ cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_VectorSupport */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the variables on which a set of DDs depends.]
+
+ Description [Finds the variables on which a set of DDs depends.
+ The set must contain either BDDs and ADDs, or ZDDs.
+ Returns an index array of the variables if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SupportIndex Cudd_VectorSupport Cudd_ClassifySupport]
+
+******************************************************************************/
+int *
+Cudd_VectorSupportIndex(
+ DdManager * dd /* manager */,
+ DdNode ** F /* array of DDs whose support is sought */,
+ int n /* size of the array */)
+{
+ int *support;
+ int i;
+ int size;
+
+ /* Allocate and initialize support array for ddSupportStep. */
+ size = ddMax(dd->size, dd->sizeZ);
+ support = ALLOC(int,size);
+ if (support == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < size; i++) {
+ support[i] = 0;
+ }
+
+ /* Compute support and clean up markers. */
+ for (i = 0; i < n; i++) {
+ ddSupportStep(Cudd_Regular(F[i]),support);
+ }
+ for (i = 0; i < n; i++) {
+ ddClearFlag(Cudd_Regular(F[i]));
+ }
+
+ return(support);
+
+} /* end of Cudd_VectorSupportIndex */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the variables on which a set of DDs depends.]
+
+ Description [Counts the variables on which a set of DDs depends.
+ The set must contain either BDDs and ADDs, or ZDDs.
+ Returns the number of the variables if successful; CUDD_OUT_OF_MEM
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_VectorSupport Cudd_SupportSize]
+
+******************************************************************************/
+int
+Cudd_VectorSupportSize(
+ DdManager * dd /* manager */,
+ DdNode ** F /* array of DDs whose support is sought */,
+ int n /* size of the array */)
+{
+ int *support;
+ int i;
+ int size;
+ int count;
+
+ /* Allocate and initialize support array for ddSupportStep. */
+ size = ddMax(dd->size, dd->sizeZ);
+ support = ALLOC(int,size);
+ if (support == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(CUDD_OUT_OF_MEM);
+ }
+ for (i = 0; i < size; i++) {
+ support[i] = 0;
+ }
+
+ /* Compute support and clean up markers. */
+ for (i = 0; i < n; i++) {
+ ddSupportStep(Cudd_Regular(F[i]),support);
+ }
+ for (i = 0; i < n; i++) {
+ ddClearFlag(Cudd_Regular(F[i]));
+ }
+
+ /* Count vriables in support. */
+ count = 0;
+ for (i = 0; i < size; i++) {
+ if (support[i] == 1) count++;
+ }
+
+ FREE(support);
+ return(count);
+
+} /* end of Cudd_VectorSupportSize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Classifies the variables in the support of two DDs.]
+
+ Description [Classifies the variables in the support of two DDs
+ <code>f</code> and <code>g</code>, depending on whther they appear
+ in both DDs, only in <code>f</code>, or only in <code>g</code>.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [The cubes of the three classes of variables are
+ returned as side effects.]
+
+ SeeAlso [Cudd_Support Cudd_VectorSupport]
+
+******************************************************************************/
+int
+Cudd_ClassifySupport(
+ DdManager * dd /* manager */,
+ DdNode * f /* first DD */,
+ DdNode * g /* second DD */,
+ DdNode ** common /* cube of shared variables */,
+ DdNode ** onlyF /* cube of variables only in f */,
+ DdNode ** onlyG /* cube of variables only in g */)
+{
+ int *supportF, *supportG;
+ DdNode *tmp, *var;
+ int i,j;
+ int size;
+
+ /* Allocate and initialize support arrays for ddSupportStep. */
+ size = ddMax(dd->size, dd->sizeZ);
+ supportF = ALLOC(int,size);
+ if (supportF == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ supportG = ALLOC(int,size);
+ if (supportG == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ FREE(supportF);
+ return(0);
+ }
+ for (i = 0; i < size; i++) {
+ supportF[i] = 0;
+ supportG[i] = 0;
+ }
+
+ /* Compute supports and clean up markers. */
+ ddSupportStep(Cudd_Regular(f),supportF);
+ ddClearFlag(Cudd_Regular(f));
+ ddSupportStep(Cudd_Regular(g),supportG);
+ ddClearFlag(Cudd_Regular(g));
+
+ /* Classify variables and create cubes. */
+ *common = *onlyF = *onlyG = DD_ONE(dd);
+ cuddRef(*common); cuddRef(*onlyF); cuddRef(*onlyG);
+ for (j = size - 1; j >= 0; j--) { /* for each level bottom-up */
+ i = (j >= dd->size) ? j : dd->invperm[j];
+ if (supportF[i] == 0 && supportG[i] == 0) continue;
+ var = cuddUniqueInter(dd,i,dd->one,Cudd_Not(dd->one));
+ cuddRef(var);
+ if (supportG[i] == 0) {
+ tmp = Cudd_bddAnd(dd,*onlyF,var);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(dd,*common);
+ Cudd_RecursiveDeref(dd,*onlyF);
+ Cudd_RecursiveDeref(dd,*onlyG);
+ Cudd_RecursiveDeref(dd,var);
+ FREE(supportF); FREE(supportG);
+ return(0);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(dd,*onlyF);
+ *onlyF = tmp;
+ } else if (supportF[i] == 0) {
+ tmp = Cudd_bddAnd(dd,*onlyG,var);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(dd,*common);
+ Cudd_RecursiveDeref(dd,*onlyF);
+ Cudd_RecursiveDeref(dd,*onlyG);
+ Cudd_RecursiveDeref(dd,var);
+ FREE(supportF); FREE(supportG);
+ return(0);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(dd,*onlyG);
+ *onlyG = tmp;
+ } else {
+ tmp = Cudd_bddAnd(dd,*common,var);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(dd,*common);
+ Cudd_RecursiveDeref(dd,*onlyF);
+ Cudd_RecursiveDeref(dd,*onlyG);
+ Cudd_RecursiveDeref(dd,var);
+ FREE(supportF); FREE(supportG);
+ return(0);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(dd,*common);
+ *common = tmp;
+ }
+ Cudd_RecursiveDeref(dd,var);
+ }
+
+ FREE(supportF); FREE(supportG);
+ cuddDeref(*common); cuddDeref(*onlyF); cuddDeref(*onlyG);
+ return(1);
+
+} /* end of Cudd_ClassifySupport */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of leaves in a DD.]
+
+ Description [Counts the number of leaves in a DD. Returns the number
+ of leaves in the DD rooted at node if successful; CUDD_OUT_OF_MEM
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_PrintDebug]
+
+******************************************************************************/
+int
+Cudd_CountLeaves(
+ DdNode * node)
+{
+ int i;
+
+ i = ddLeavesInt(Cudd_Regular(node));
+ ddClearFlag(Cudd_Regular(node));
+ return(i);
+
+} /* end of Cudd_CountLeaves */
+
+
+/**Function********************************************************************
+
+ Synopsis [Picks one on-set cube randomly from the given DD.]
+
+ Description [Picks one on-set cube randomly from the given DD. The
+ cube is written into an array of characters. The array must have at
+ least as many entries as there are variables. Returns 1 if
+ successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddPickOneMinterm]
+
+******************************************************************************/
+int
+Cudd_bddPickOneCube(
+ DdManager * ddm,
+ DdNode * node,
+ char * string)
+{
+ DdNode *N, *T, *E;
+ DdNode *one, *bzero;
+ char dir;
+ int i;
+
+ if (string == NULL || node == NULL) return(0);
+
+ /* The constant 0 function has no on-set cubes. */
+ one = DD_ONE(ddm);
+ bzero = Cudd_Not(one);
+ if (node == bzero) return(0);
+
+ for (i = 0; i < ddm->size; i++) string[i] = 2;
+
+ for (;;) {
+
+ if (node == one) break;
+
+ N = Cudd_Regular(node);
+
+ T = cuddT(N); E = cuddE(N);
+ if (Cudd_IsComplement(node)) {
+ T = Cudd_Not(T); E = Cudd_Not(E);
+ }
+ if (T == bzero) {
+ string[N->index] = 0;
+ node = E;
+ } else if (E == bzero) {
+ string[N->index] = 1;
+ node = T;
+ } else {
+ dir = (char) ((Cudd_Random() & 0x2000) >> 13);
+ string[N->index] = dir;
+ node = dir ? T : E;
+ }
+ }
+ return(1);
+
+} /* end of Cudd_bddPickOneCube */
+
+
+/**Function********************************************************************
+
+ Synopsis [Picks one on-set minterm randomly from the given DD.]
+
+ Description [Picks one on-set minterm randomly from the given
+ DD. The minterm is in terms of <code>vars</code>. The array
+ <code>vars</code> should contain at least all variables in the
+ support of <code>f</code>; if this condition is not met the minterm
+ built by this procedure may not be contained in
+ <code>f</code>. Builds a BDD for the minterm and returns a pointer
+ to it if successful; NULL otherwise. There are three reasons why the
+ procedure may fail:
+ <ul>
+ <li> It may run out of memory;
+ <li> the function <code>f</code> may be the constant 0;
+ <li> the minterm may not be contained in <code>f</code>.
+ </ul>]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddPickOneCube]
+
+******************************************************************************/
+DdNode *
+Cudd_bddPickOneMinterm(
+ DdManager * dd /* manager */,
+ DdNode * f /* function from which to pick one minterm */,
+ DdNode ** vars /* array of variables */,
+ int n /* size of <code>vars</code> */)
+{
+ char *string;
+ int i, size;
+ int *indices;
+ int result;
+ DdNode *old, *neW;
+
+ size = dd->size;
+ string = ALLOC(char, size);
+ if (string == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ indices = ALLOC(int,n);
+ if (indices == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ FREE(string);
+ return(NULL);
+ }
+
+ for (i = 0; i < n; i++) {
+ indices[i] = vars[i]->index;
+ }
+
+ result = Cudd_bddPickOneCube(dd,f,string);
+ if (result == 0) {
+ FREE(string);
+ FREE(indices);
+ return(NULL);
+ }
+
+ /* Randomize choice for don't cares. */
+ for (i = 0; i < n; i++) {
+ if (string[indices[i]] == 2)
+ string[indices[i]] = (char) ((Cudd_Random() & 0x20) >> 5);
+ }
+
+ /* Build result BDD. */
+ old = Cudd_ReadOne(dd);
+ cuddRef(old);
+
+ for (i = n-1; i >= 0; i--) {
+ neW = Cudd_bddAnd(dd,old,Cudd_NotCond(vars[i],string[indices[i]]==0));
+ if (neW == NULL) {
+ FREE(string);
+ FREE(indices);
+ Cudd_RecursiveDeref(dd,old);
+ return(NULL);
+ }
+ cuddRef(neW);
+ Cudd_RecursiveDeref(dd,old);
+ old = neW;
+ }
+
+#ifdef DD_DEBUG
+ /* Test. */
+ if (Cudd_bddLeq(dd,old,f)) {
+ cuddDeref(old);
+ } else {
+ Cudd_RecursiveDeref(dd,old);
+ old = NULL;
+ }
+#else
+ cuddDeref(old);
+#endif
+
+ FREE(string);
+ FREE(indices);
+ return(old);
+
+} /* end of Cudd_bddPickOneMinterm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Picks k on-set minterms evenly distributed from given DD.]
+
+ Description [Picks k on-set minterms evenly distributed from given DD.
+ The minterms are in terms of <code>vars</code>. The array
+ <code>vars</code> should contain at least all variables in the
+ support of <code>f</code>; if this condition is not met the minterms
+ built by this procedure may not be contained in
+ <code>f</code>. Builds an array of BDDs for the minterms and returns a
+ pointer to it if successful; NULL otherwise. There are three reasons
+ why the procedure may fail:
+ <ul>
+ <li> It may run out of memory;
+ <li> the function <code>f</code> may be the constant 0;
+ <li> the minterms may not be contained in <code>f</code>.
+ </ul>]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddPickOneMinterm Cudd_bddPickOneCube]
+
+******************************************************************************/
+DdNode **
+Cudd_bddPickArbitraryMinterms(
+ DdManager * dd /* manager */,
+ DdNode * f /* function from which to pick k minterms */,
+ DdNode ** vars /* array of variables */,
+ int n /* size of <code>vars</code> */,
+ int k /* number of minterms to find */)
+{
+ char **string;
+ int i, j, l, size;
+ int *indices;
+ int result;
+ DdNode **old, *neW;
+ double minterms;
+ char *saveString;
+ int saveFlag, savePoint, isSame;
+
+ minterms = Cudd_CountMinterm(dd,f,n);
+ if ((double)k > minterms) {
+ return(NULL);
+ }
+
+ size = dd->size;
+ string = ALLOC(char *, k);
+ if (string == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < k; i++) {
+ string[i] = ALLOC(char, size + 1);
+ if (string[i] == NULL) {
+ for (j = 0; j < i; j++)
+ FREE(string[i]);
+ FREE(string);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (j = 0; j < size; j++) string[i][j] = '2';
+ string[i][size] = '\0';
+ }
+ indices = ALLOC(int,n);
+ if (indices == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ for (i = 0; i < k; i++)
+ FREE(string[i]);
+ FREE(string);
+ return(NULL);
+ }
+
+ for (i = 0; i < n; i++) {
+ indices[i] = vars[i]->index;
+ }
+
+ result = ddPickArbitraryMinterms(dd,f,n,k,string);
+ if (result == 0) {
+ for (i = 0; i < k; i++)
+ FREE(string[i]);
+ FREE(string);
+ FREE(indices);
+ return(NULL);
+ }
+
+ old = ALLOC(DdNode *, k);
+ if (old == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ for (i = 0; i < k; i++)
+ FREE(string[i]);
+ FREE(string);
+ FREE(indices);
+ return(NULL);
+ }
+ saveString = ALLOC(char, size + 1);
+ if (saveString == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ for (i = 0; i < k; i++)
+ FREE(string[i]);
+ FREE(string);
+ FREE(indices);
+ FREE(old);
+ return(NULL);
+ }
+ saveFlag = 0;
+
+ /* Build result BDD array. */
+ for (i = 0; i < k; i++) {
+ isSame = 0;
+ if (!saveFlag) {
+ for (j = i + 1; j < k; j++) {
+ if (strcmp(string[i], string[j]) == 0) {
+ savePoint = i;
+ strcpy(saveString, string[i]);
+ saveFlag = 1;
+ break;
+ }
+ }
+ } else {
+ if (strcmp(string[i], saveString) == 0) {
+ isSame = 1;
+ } else {
+ saveFlag = 0;
+ for (j = i + 1; j < k; j++) {
+ if (strcmp(string[i], string[j]) == 0) {
+ savePoint = i;
+ strcpy(saveString, string[i]);
+ saveFlag = 1;
+ break;
+ }
+ }
+ }
+ }
+ /* Randomize choice for don't cares. */
+ for (j = 0; j < n; j++) {
+ if (string[i][indices[j]] == '2')
+ string[i][indices[j]] = (Cudd_Random() & 0x20) ? '1' : '0';
+ }
+
+ while (isSame) {
+ isSame = 0;
+ for (j = savePoint; j < i; j++) {
+ if (strcmp(string[i], string[j]) == 0) {
+ isSame = 1;
+ break;
+ }
+ }
+ if (isSame) {
+ strcpy(string[i], saveString);
+ /* Randomize choice for don't cares. */
+ for (j = 0; j < n; j++) {
+ if (string[i][indices[j]] == '2')
+ string[i][indices[j]] = (Cudd_Random() & 0x20) ?
+ '1' : '0';
+ }
+ }
+ }
+
+ old[i] = Cudd_ReadOne(dd);
+ cuddRef(old[i]);
+
+ for (j = 0; j < n; j++) {
+ if (string[i][indices[j]] == '0') {
+ neW = Cudd_bddAnd(dd,old[i],Cudd_Not(vars[j]));
+ } else {
+ neW = Cudd_bddAnd(dd,old[i],vars[j]);
+ }
+ if (neW == NULL) {
+ FREE(saveString);
+ for (l = 0; l < k; l++)
+ FREE(string[l]);
+ FREE(string);
+ FREE(indices);
+ for (l = 0; l <= i; l++)
+ Cudd_RecursiveDeref(dd,old[l]);
+ FREE(old);
+ return(NULL);
+ }
+ cuddRef(neW);
+ Cudd_RecursiveDeref(dd,old[i]);
+ old[i] = neW;
+ }
+
+ /* Test. */
+ if (!Cudd_bddLeq(dd,old[i],f)) {
+ FREE(saveString);
+ for (l = 0; l < k; l++)
+ FREE(string[l]);
+ FREE(string);
+ FREE(indices);
+ for (l = 0; l <= i; l++)
+ Cudd_RecursiveDeref(dd,old[l]);
+ FREE(old);
+ return(NULL);
+ }
+ }
+
+ FREE(saveString);
+ for (i = 0; i < k; i++) {
+ cuddDeref(old[i]);
+ FREE(string[i]);
+ }
+ FREE(string);
+ FREE(indices);
+ return(old);
+
+} /* end of Cudd_bddPickArbitraryMinterms */
+
+
+/**Function********************************************************************
+
+ Synopsis [Extracts a subset from a BDD.]
+
+ Description [Extracts a subset from a BDD in the following procedure.
+ 1. Compute the weight for each mask variable by counting the number of
+ minterms for both positive and negative cofactors of the BDD with
+ respect to each mask variable. (weight = #positive - #negative)
+ 2. Find a representative cube of the BDD by using the weight. From the
+ top variable of the BDD, for each variable, if the weight is greater
+ than 0.0, choose THEN branch, othereise ELSE branch, until meeting
+ the constant 1.
+ 3. Quantify out the variables not in maskVars from the representative
+ cube and if a variable in maskVars is don't care, replace the
+ variable with a constant(1 or 0) depending on the weight.
+ 4. Make a subset of the BDD by multiplying with the modified cube.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_SubsetWithMaskVars(
+ DdManager * dd /* manager */,
+ DdNode * f /* function from which to pick a cube */,
+ DdNode ** vars /* array of variables */,
+ int nvars /* size of <code>vars</code> */,
+ DdNode ** maskVars /* array of variables */,
+ int mvars /* size of <code>maskVars</code> */)
+{
+ double *weight;
+ char *string;
+ int i, size;
+ int *indices, *mask;
+ int result;
+ DdNode *zero, *cube, *newCube, *subset;
+ DdNode *cof;
+
+ DdNode *support;
+ support = Cudd_Support(dd,f);
+ cuddRef(support);
+ Cudd_RecursiveDeref(dd,support);
+
+ zero = Cudd_Not(dd->one);
+ size = dd->size;
+
+ weight = ALLOC(double,size);
+ if (weight == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < size; i++) {
+ weight[i] = 0.0;
+ }
+ for (i = 0; i < mvars; i++) {
+ cof = Cudd_Cofactor(dd, f, maskVars[i]);
+ cuddRef(cof);
+ weight[i] = Cudd_CountMinterm(dd, cof, nvars);
+ Cudd_RecursiveDeref(dd,cof);
+
+ cof = Cudd_Cofactor(dd, f, Cudd_Not(maskVars[i]));
+ cuddRef(cof);
+ weight[i] -= Cudd_CountMinterm(dd, cof, nvars);
+ Cudd_RecursiveDeref(dd,cof);
+ }
+
+ string = ALLOC(char, size + 1);
+ if (string == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ mask = ALLOC(int, size);
+ if (mask == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ FREE(string);
+ return(NULL);
+ }
+ for (i = 0; i < size; i++) {
+ string[i] = '2';
+ mask[i] = 0;
+ }
+ string[size] = '\0';
+ indices = ALLOC(int,nvars);
+ if (indices == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ FREE(string);
+ FREE(mask);
+ return(NULL);
+ }
+ for (i = 0; i < nvars; i++) {
+ indices[i] = vars[i]->index;
+ }
+
+ result = ddPickRepresentativeCube(dd,f,nvars,weight,string);
+ if (result == 0) {
+ FREE(string);
+ FREE(mask);
+ FREE(indices);
+ return(NULL);
+ }
+
+ cube = Cudd_ReadOne(dd);
+ cuddRef(cube);
+ zero = Cudd_Not(Cudd_ReadOne(dd));
+ for (i = 0; i < nvars; i++) {
+ if (string[indices[i]] == '0') {
+ newCube = Cudd_bddIte(dd,cube,Cudd_Not(vars[i]),zero);
+ } else if (string[indices[i]] == '1') {
+ newCube = Cudd_bddIte(dd,cube,vars[i],zero);
+ } else
+ continue;
+ if (newCube == NULL) {
+ FREE(string);
+ FREE(mask);
+ FREE(indices);
+ Cudd_RecursiveDeref(dd,cube);
+ return(NULL);
+ }
+ cuddRef(newCube);
+ Cudd_RecursiveDeref(dd,cube);
+ cube = newCube;
+ }
+ Cudd_RecursiveDeref(dd,cube);
+
+ for (i = 0; i < mvars; i++) {
+ mask[maskVars[i]->index] = 1;
+ }
+ for (i = 0; i < nvars; i++) {
+ if (mask[indices[i]]) {
+ if (string[indices[i]] == '2') {
+ if (weight[indices[i]] >= 0.0)
+ string[indices[i]] = '1';
+ else
+ string[indices[i]] = '0';
+ }
+ } else {
+ string[indices[i]] = '2';
+ }
+ }
+
+ cube = Cudd_ReadOne(dd);
+ cuddRef(cube);
+ zero = Cudd_Not(Cudd_ReadOne(dd));
+
+ /* Build result BDD. */
+ for (i = 0; i < nvars; i++) {
+ if (string[indices[i]] == '0') {
+ newCube = Cudd_bddIte(dd,cube,Cudd_Not(vars[i]),zero);
+ } else if (string[indices[i]] == '1') {
+ newCube = Cudd_bddIte(dd,cube,vars[i],zero);
+ } else
+ continue;
+ if (newCube == NULL) {
+ FREE(string);
+ FREE(mask);
+ FREE(indices);
+ Cudd_RecursiveDeref(dd,cube);
+ return(NULL);
+ }
+ cuddRef(newCube);
+ Cudd_RecursiveDeref(dd,cube);
+ cube = newCube;
+ }
+
+ subset = Cudd_bddAnd(dd,f,cube);
+ cuddRef(subset);
+ Cudd_RecursiveDeref(dd,cube);
+
+ /* Test. */
+ if (Cudd_bddLeq(dd,subset,f)) {
+ cuddDeref(subset);
+ } else {
+ Cudd_RecursiveDeref(dd,subset);
+ subset = NULL;
+ }
+
+ FREE(string);
+ FREE(mask);
+ FREE(indices);
+ FREE(weight);
+ return(subset);
+
+} /* end of Cudd_SubsetWithMaskVars */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the first cube of a decision diagram.]
+
+ Description [Defines an iterator on the onset of a decision diagram
+ and finds its first cube. Returns a generator that contains the
+ information necessary to continue the enumeration if successful; NULL
+ otherwise.<p>
+ A cube is represented as an array of literals, which are integers in
+ {0, 1, 2}; 0 represents a complemented literal, 1 represents an
+ uncomplemented literal, and 2 stands for don't care. The enumeration
+ produces a disjoint cover of the function associated with the diagram.
+ The size of the array equals the number of variables in the manager at
+ the time Cudd_FirstCube is called.<p>
+ For each cube, a value is also returned. This value is always 1 for a
+ BDD, while it may be different from 1 for an ADD.
+ For BDDs, the offset is the set of cubes whose value is the logical zero.
+ For ADDs, the offset is the set of cubes whose value is the
+ background value. The cubes of the offset are not enumerated.]
+
+ SideEffects [The first cube and its value are returned as side effects.]
+
+ SeeAlso [Cudd_ForeachCube Cudd_NextCube Cudd_GenFree Cudd_IsGenEmpty
+ Cudd_FirstNode]
+
+******************************************************************************/
+DdGen *
+Cudd_FirstCube(
+ DdManager * dd,
+ DdNode * f,
+ int ** cube,
+ CUDD_VALUE_TYPE * value)
+{
+ DdGen *gen;
+ DdNode *top, *treg, *next, *nreg, *prev, *preg;
+ int i;
+ int nvars;
+
+ /* Sanity Check. */
+ if (dd == NULL || f == NULL) return(NULL);
+
+ /* Allocate generator an initialize it. */
+ gen = ALLOC(DdGen,1);
+ if (gen == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ gen->manager = dd;
+ gen->type = CUDD_GEN_CUBES;
+ gen->status = CUDD_GEN_EMPTY;
+ gen->gen.cubes.cube = NULL;
+ gen->gen.cubes.value = DD_ZERO_VAL;
+ gen->stack.sp = 0;
+ gen->stack.stack = NULL;
+ gen->node = NULL;
+
+ nvars = dd->size;
+ gen->gen.cubes.cube = ALLOC(int,nvars);
+ if (gen->gen.cubes.cube == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ FREE(gen);
+ return(NULL);
+ }
+ for (i = 0; i < nvars; i++) gen->gen.cubes.cube[i] = 2;
+
+ /* The maximum stack depth is one plus the number of variables.
+ ** because a path may have nodes at all levels, including the
+ ** constant level.
+ */
+ gen->stack.stack = ALLOC(DdNode *, nvars+1);
+ if (gen->stack.stack == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ FREE(gen->gen.cubes.cube);
+ FREE(gen);
+ return(NULL);
+ }
+ for (i = 0; i <= nvars; i++) gen->stack.stack[i] = NULL;
+
+ /* Find the first cube of the onset. */
+ gen->stack.stack[gen->stack.sp] = f; gen->stack.sp++;
+
+ while (1) {
+ top = gen->stack.stack[gen->stack.sp-1];
+ treg = Cudd_Regular(top);
+ if (!cuddIsConstant(treg)) {
+ /* Take the else branch first. */
+ gen->gen.cubes.cube[treg->index] = 0;
+ next = cuddE(treg);
+ if (top != treg) next = Cudd_Not(next);
+ gen->stack.stack[gen->stack.sp] = next; gen->stack.sp++;
+ } else if (top == Cudd_Not(DD_ONE(dd)) || top == dd->background) {
+ /* Backtrack */
+ while (1) {
+ if (gen->stack.sp == 1) {
+ /* The current node has no predecessor. */
+ gen->status = CUDD_GEN_EMPTY;
+ gen->stack.sp--;
+ goto done;
+ }
+ prev = gen->stack.stack[gen->stack.sp-2];
+ preg = Cudd_Regular(prev);
+ nreg = cuddT(preg);
+ if (prev != preg) {next = Cudd_Not(nreg);} else {next = nreg;}
+ if (next != top) { /* follow the then branch next */
+ gen->gen.cubes.cube[preg->index] = 1;
+ gen->stack.stack[gen->stack.sp-1] = next;
+ break;
+ }
+ /* Pop the stack and try again. */
+ gen->gen.cubes.cube[preg->index] = 2;
+ gen->stack.sp--;
+ top = gen->stack.stack[gen->stack.sp-1];
+ treg = Cudd_Regular(top);
+ }
+ } else {
+ gen->status = CUDD_GEN_NONEMPTY;
+ gen->gen.cubes.value = cuddV(top);
+ goto done;
+ }
+ }
+
+done:
+ *cube = gen->gen.cubes.cube;
+ *value = gen->gen.cubes.value;
+ return(gen);
+
+} /* end of Cudd_FirstCube */
+
+
+/**Function********************************************************************
+
+ Synopsis [Generates the next cube of a decision diagram onset.]
+
+ Description [Generates the next cube of a decision diagram onset,
+ using generator gen. Returns 0 if the enumeration is completed; 1
+ otherwise.]
+
+ SideEffects [The cube and its value are returned as side effects. The
+ generator is modified.]
+
+ SeeAlso [Cudd_ForeachCube Cudd_FirstCube Cudd_GenFree Cudd_IsGenEmpty
+ Cudd_NextNode]
+
+******************************************************************************/
+int
+Cudd_NextCube(
+ DdGen * gen,
+ int ** cube,
+ CUDD_VALUE_TYPE * value)
+{
+ DdNode *top, *treg, *next, *nreg, *prev, *preg;
+ DdManager *dd = gen->manager;
+
+ /* Backtrack from previously reached terminal node. */
+ while (1) {
+ if (gen->stack.sp == 1) {
+ /* The current node has no predecessor. */
+ gen->status = CUDD_GEN_EMPTY;
+ gen->stack.sp--;
+ goto done;
+ }
+ top = gen->stack.stack[gen->stack.sp-1];
+ treg = Cudd_Regular(top);
+ prev = gen->stack.stack[gen->stack.sp-2];
+ preg = Cudd_Regular(prev);
+ nreg = cuddT(preg);
+ if (prev != preg) {next = Cudd_Not(nreg);} else {next = nreg;}
+ if (next != top) { /* follow the then branch next */
+ gen->gen.cubes.cube[preg->index] = 1;
+ gen->stack.stack[gen->stack.sp-1] = next;
+ break;
+ }
+ /* Pop the stack and try again. */
+ gen->gen.cubes.cube[preg->index] = 2;
+ gen->stack.sp--;
+ }
+
+ while (1) {
+ top = gen->stack.stack[gen->stack.sp-1];
+ treg = Cudd_Regular(top);
+ if (!cuddIsConstant(treg)) {
+ /* Take the else branch first. */
+ gen->gen.cubes.cube[treg->index] = 0;
+ next = cuddE(treg);
+ if (top != treg) next = Cudd_Not(next);
+ gen->stack.stack[gen->stack.sp] = next; gen->stack.sp++;
+ } else if (top == Cudd_Not(DD_ONE(dd)) || top == dd->background) {
+ /* Backtrack */
+ while (1) {
+ if (gen->stack.sp == 1) {
+ /* The current node has no predecessor. */
+ gen->status = CUDD_GEN_EMPTY;
+ gen->stack.sp--;
+ goto done;
+ }
+ prev = gen->stack.stack[gen->stack.sp-2];
+ preg = Cudd_Regular(prev);
+ nreg = cuddT(preg);
+ if (prev != preg) {next = Cudd_Not(nreg);} else {next = nreg;}
+ if (next != top) { /* follow the then branch next */
+ gen->gen.cubes.cube[preg->index] = 1;
+ gen->stack.stack[gen->stack.sp-1] = next;
+ break;
+ }
+ /* Pop the stack and try again. */
+ gen->gen.cubes.cube[preg->index] = 2;
+ gen->stack.sp--;
+ top = gen->stack.stack[gen->stack.sp-1];
+ treg = Cudd_Regular(top);
+ }
+ } else {
+ gen->status = CUDD_GEN_NONEMPTY;
+ gen->gen.cubes.value = cuddV(top);
+ goto done;
+ }
+ }
+
+done:
+ if (gen->status == CUDD_GEN_EMPTY) return(0);
+ *cube = gen->gen.cubes.cube;
+ *value = gen->gen.cubes.value;
+ return(1);
+
+} /* end of Cudd_NextCube */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the cube of an array of BDD variables.]
+
+ Description [Computes the cube of an array of BDD variables. If
+ non-null, the phase argument indicates which literal of each
+ variable should appear in the cube. If phase\[i\] is nonzero, then the
+ positive literal is used. If phase is NULL, the cube is positive unate.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addComputeCube Cudd_IndicesToCube Cudd_CubeArrayToBdd]
+
+******************************************************************************/
+DdNode *
+Cudd_bddComputeCube(
+ DdManager * dd,
+ DdNode ** vars,
+ int * phase,
+ int n)
+{
+ DdNode *cube;
+ DdNode *fn;
+ int i;
+
+ cube = DD_ONE(dd);
+ cuddRef(cube);
+
+ for (i = n - 1; i >= 0; i--) {
+ if (phase == NULL || phase[i] != 0) {
+ fn = Cudd_bddAnd(dd,vars[i],cube);
+ } else {
+ fn = Cudd_bddAnd(dd,Cudd_Not(vars[i]),cube);
+ }
+ if (fn == NULL) {
+ Cudd_RecursiveDeref(dd,cube);
+ return(NULL);
+ }
+ cuddRef(fn);
+ Cudd_RecursiveDeref(dd,cube);
+ cube = fn;
+ }
+ cuddDeref(cube);
+
+ return(cube);
+
+} /* end of Cudd_bddComputeCube */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the cube of an array of ADD variables.]
+
+ Description [Computes the cube of an array of ADD variables. If
+ non-null, the phase argument indicates which literal of each
+ variable should appear in the cube. If phase\[i\] is nonzero, then the
+ positive literal is used. If phase is NULL, the cube is positive unate.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_bddComputeCube]
+
+******************************************************************************/
+DdNode *
+Cudd_addComputeCube(
+ DdManager * dd,
+ DdNode ** vars,
+ int * phase,
+ int n)
+{
+ DdNode *cube, *zero;
+ DdNode *fn;
+ int i;
+
+ cube = DD_ONE(dd);
+ cuddRef(cube);
+ zero = DD_ZERO(dd);
+
+ for (i = n - 1; i >= 0; i--) {
+ if (phase == NULL || phase[i] != 0) {
+ fn = Cudd_addIte(dd,vars[i],cube,zero);
+ } else {
+ fn = Cudd_addIte(dd,vars[i],zero,cube);
+ }
+ if (fn == NULL) {
+ Cudd_RecursiveDeref(dd,cube);
+ return(NULL);
+ }
+ cuddRef(fn);
+ Cudd_RecursiveDeref(dd,cube);
+ cube = fn;
+ }
+ cuddDeref(cube);
+
+ return(cube);
+
+} /* end of Cudd_addComputeCube */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds the BDD of a cube from a positional array.]
+
+ Description [Builds a cube from a positional array. The array must
+ have one integer entry for each BDD variable. If the i-th entry is
+ 1, the variable of index i appears in true form in the cube; If the
+ i-th entry is 0, the variable of index i appears complemented in the
+ cube; otherwise the variable does not appear in the cube. Returns a
+ pointer to the BDD for the cube if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddComputeCube Cudd_IndicesToCube Cudd_BddToCubeArray]
+
+******************************************************************************/
+DdNode *
+Cudd_CubeArrayToBdd(
+ DdManager *dd,
+ int *array)
+{
+ DdNode *cube, *var, *tmp;
+ int i;
+ int size = Cudd_ReadSize(dd);
+
+ cube = DD_ONE(dd);
+ cuddRef(cube);
+ for (i = size - 1; i >= 0; i--) {
+ if ((array[i] & ~1) == 0) {
+ var = Cudd_bddIthVar(dd,i);
+ tmp = Cudd_bddAnd(dd,cube,Cudd_NotCond(var,array[i]==0));
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(dd,cube);
+ return(NULL);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(dd,cube);
+ cube = tmp;
+ }
+ }
+ cuddDeref(cube);
+ return(cube);
+
+} /* end of Cudd_CubeArrayToBdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds a positional array from the BDD of a cube.]
+
+ Description [Builds a positional array from the BDD of a cube.
+ Array must have one entry for each BDD variable. The positional
+ array has 1 in i-th position if the variable of index i appears in
+ true form in the cube; it has 0 in i-th position if the variable of
+ index i appears in complemented form in the cube; finally, it has 2
+ in i-th position if the variable of index i does not appear in the
+ cube. Returns 1 if successful (the BDD is indeed a cube); 0
+ otherwise.]
+
+ SideEffects [The result is in the array passed by reference.]
+
+ SeeAlso [Cudd_CubeArrayToBdd]
+
+******************************************************************************/
+int
+Cudd_BddToCubeArray(
+ DdManager *dd,
+ DdNode *cube,
+ int *array)
+{
+ DdNode *scan, *t, *e;
+ int i;
+ int size = Cudd_ReadSize(dd);
+ DdNode *zero = Cudd_Not(DD_ONE(dd));
+
+ for (i = size-1; i >= 0; i--) {
+ array[i] = 2;
+ }
+ scan = cube;
+ while (!Cudd_IsConstant(scan)) {
+ int index = Cudd_Regular(scan)->index;
+ cuddGetBranches(scan,&t,&e);
+ if (t == zero) {
+ array[index] = 0;
+ scan = e;
+ } else if (e == zero) {
+ array[index] = 1;
+ scan = t;
+ } else {
+ return(0); /* cube is not a cube */
+ }
+ }
+ if (scan == zero) {
+ return(0);
+ } else {
+ return(1);
+ }
+
+} /* end of Cudd_BddToCubeArray */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the first node of a decision diagram.]
+
+ Description [Defines an iterator on the nodes of a decision diagram
+ and finds its first node. Returns a generator that contains the
+ information necessary to continue the enumeration if successful; NULL
+ otherwise.]
+
+ SideEffects [The first node is returned as a side effect.]
+
+ SeeAlso [Cudd_ForeachNode Cudd_NextNode Cudd_GenFree Cudd_IsGenEmpty
+ Cudd_FirstCube]
+
+******************************************************************************/
+DdGen *
+Cudd_FirstNode(
+ DdManager * dd,
+ DdNode * f,
+ DdNode ** node)
+{
+ DdGen *gen;
+ int retval;
+
+ /* Sanity Check. */
+ if (dd == NULL || f == NULL) return(NULL);
+
+ /* Allocate generator an initialize it. */
+ gen = ALLOC(DdGen,1);
+ if (gen == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ gen->manager = dd;
+ gen->type = CUDD_GEN_NODES;
+ gen->status = CUDD_GEN_EMPTY;
+ gen->gen.nodes.visited = NULL;
+ gen->gen.nodes.stGen = NULL;
+ gen->stack.sp = 0;
+ gen->stack.stack = NULL;
+ gen->node = NULL;
+
+ gen->gen.nodes.visited = st_init_table(st_ptrcmp,st_ptrhash);
+ if (gen->gen.nodes.visited == NULL) {
+ FREE(gen);
+ return(NULL);
+ }
+
+ /* Collect all the nodes in a st table for later perusal. */
+ retval = cuddCollectNodes(Cudd_Regular(f),gen->gen.nodes.visited);
+ if (retval == 0) {
+ st_free_table(gen->gen.nodes.visited);
+ FREE(gen);
+ return(NULL);
+ }
+
+ /* Initialize the st table generator. */
+ gen->gen.nodes.stGen = st_init_gen(gen->gen.nodes.visited);
+ if (gen->gen.nodes.stGen == NULL) {
+ st_free_table(gen->gen.nodes.visited);
+ FREE(gen);
+ return(NULL);
+ }
+
+ /* Find the first node. */
+ retval = st_gen(gen->gen.nodes.stGen, (char **) &(gen->node), NULL);
+ if (retval != 0) {
+ gen->status = CUDD_GEN_NONEMPTY;
+ *node = gen->node;
+ }
+
+ return(gen);
+
+} /* end of Cudd_FirstNode */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the next node of a decision diagram.]
+
+ Description [Finds the node of a decision diagram, using generator
+ gen. Returns 0 if the enumeration is completed; 1 otherwise.]
+
+ SideEffects [The next node is returned as a side effect.]
+
+ SeeAlso [Cudd_ForeachNode Cudd_FirstNode Cudd_GenFree Cudd_IsGenEmpty
+ Cudd_NextCube]
+
+******************************************************************************/
+int
+Cudd_NextNode(
+ DdGen * gen,
+ DdNode ** node)
+{
+ int retval;
+
+ /* Find the next node. */
+ retval = st_gen(gen->gen.nodes.stGen, (char **) &(gen->node), NULL);
+ if (retval == 0) {
+ gen->status = CUDD_GEN_EMPTY;
+ } else {
+ *node = gen->node;
+ }
+
+ return(retval);
+
+} /* end of Cudd_NextNode */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees a CUDD generator.]
+
+ Description [Frees a CUDD generator. Always returns 0, so that it can
+ be used in mis-like foreach constructs.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ForeachCube Cudd_ForeachNode Cudd_FirstCube Cudd_NextCube
+ Cudd_FirstNode Cudd_NextNode Cudd_IsGenEmpty]
+
+******************************************************************************/
+int
+Cudd_GenFree(
+ DdGen * gen)
+{
+
+ if (gen == NULL) return(0);
+ switch (gen->type) {
+ case CUDD_GEN_CUBES:
+ case CUDD_GEN_ZDD_PATHS:
+ FREE(gen->gen.cubes.cube);
+ FREE(gen->stack.stack);
+ break;
+ case CUDD_GEN_NODES:
+ st_free_gen(gen->gen.nodes.stGen);
+ st_free_table(gen->gen.nodes.visited);
+ break;
+ default:
+ return(0);
+ }
+ FREE(gen);
+ return(0);
+
+} /* end of Cudd_GenFree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Queries the status of a generator.]
+
+ Description [Queries the status of a generator. Returns 1 if the
+ generator is empty or NULL; 0 otherswise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ForeachCube Cudd_ForeachNode Cudd_FirstCube Cudd_NextCube
+ Cudd_FirstNode Cudd_NextNode Cudd_GenFree]
+
+******************************************************************************/
+int
+Cudd_IsGenEmpty(
+ DdGen * gen)
+{
+ if (gen == NULL) return(1);
+ return(gen->status == CUDD_GEN_EMPTY);
+
+} /* end of Cudd_IsGenEmpty */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds a cube of BDD variables from an array of indices.]
+
+ Description [Builds a cube of BDD variables from an array of indices.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddComputeCube Cudd_CubeArrayToBdd]
+
+******************************************************************************/
+DdNode *
+Cudd_IndicesToCube(
+ DdManager * dd,
+ int * array,
+ int n)
+{
+ DdNode *cube, *tmp;
+ int i;
+
+ cube = DD_ONE(dd);
+ cuddRef(cube);
+ for (i = n - 1; i >= 0; i--) {
+ tmp = Cudd_bddAnd(dd,Cudd_bddIthVar(dd,array[i]),cube);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(dd,cube);
+ return(NULL);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(dd,cube);
+ cube = tmp;
+ }
+
+ cuddDeref(cube);
+ return(cube);
+
+} /* end of Cudd_IndicesToCube */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints the package version number.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+Cudd_PrintVersion(
+ FILE * fp)
+{
+ (void) fprintf(fp, "%s\n", CUDD_VERSION);
+
+} /* end of Cudd_PrintVersion */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the average distance between adjacent nodes.]
+
+ Description [Computes the average distance between adjacent nodes in
+ the manager. Adjacent nodes are node pairs such that the second node
+ is the then child, else child, or next node in the collision list.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+double
+Cudd_AverageDistance(
+ DdManager * dd)
+{
+ double tetotal, nexttotal;
+ double tesubtotal, nextsubtotal;
+ double temeasured, nextmeasured;
+ int i, j;
+ int slots, nvars;
+ long diff;
+ DdNode *scan;
+ DdNodePtr *nodelist;
+ DdNode *sentinel = &(dd->sentinel);
+
+ nvars = dd->size;
+ if (nvars == 0) return(0.0);
+
+ /* Initialize totals. */
+ tetotal = 0.0;
+ nexttotal = 0.0;
+ temeasured = 0.0;
+ nextmeasured = 0.0;
+
+ /* Scan the variable subtables. */
+ for (i = 0; i < nvars; i++) {
+ nodelist = dd->subtables[i].nodelist;
+ tesubtotal = 0.0;
+ nextsubtotal = 0.0;
+ slots = dd->subtables[i].slots;
+ for (j = 0; j < slots; j++) {
+ scan = nodelist[j];
+ while (scan != sentinel) {
+ diff = (long) scan - (long) cuddT(scan);
+ tesubtotal += (double) ddAbs(diff);
+ diff = (long) scan - (long) Cudd_Regular(cuddE(scan));
+ tesubtotal += (double) ddAbs(diff);
+ temeasured += 2.0;
+ if (scan->next != NULL) {
+ diff = (long) scan - (long) scan->next;
+ nextsubtotal += (double) ddAbs(diff);
+ nextmeasured += 1.0;
+ }
+ scan = scan->next;
+ }
+ }
+ tetotal += tesubtotal;
+ nexttotal += nextsubtotal;
+ }
+
+ /* Scan the constant table. */
+ nodelist = dd->constants.nodelist;
+ nextsubtotal = 0.0;
+ slots = dd->constants.slots;
+ for (j = 0; j < slots; j++) {
+ scan = nodelist[j];
+ while (scan != NULL) {
+ if (scan->next != NULL) {
+ diff = (long) scan - (long) scan->next;
+ nextsubtotal += (double) ddAbs(diff);
+ nextmeasured += 1.0;
+ }
+ scan = scan->next;
+ }
+ }
+ nexttotal += nextsubtotal;
+
+ return((tetotal + nexttotal) / (temeasured + nextmeasured));
+
+} /* end of Cudd_AverageDistance */
+
+
+/**Function********************************************************************
+
+ Synopsis [Portable random number generator.]
+
+ Description [Portable number generator based on ran2 from "Numerical
+ Recipes in C." It is a long period (> 2 * 10^18) random number generator
+ of L'Ecuyer with Bays-Durham shuffle. Returns a long integer uniformly
+ distributed between 0 and 2147483561 (inclusive of the endpoint values).
+ The random generator can be explicitly initialized by calling
+ Cudd_Srandom. If no explicit initialization is performed, then the
+ seed 1 is assumed.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Srandom]
+
+******************************************************************************/
+long
+Cudd_Random(
+ )
+{
+ int i; /* index in the shuffle table */
+ long int w; /* work variable */
+
+ /* cuddRand == 0 if the geneartor has not been initialized yet. */
+ if (cuddRand == 0) Cudd_Srandom(1);
+
+ /* Compute cuddRand = (cuddRand * LEQA1) % MODULUS1 avoiding
+ ** overflows by Schrage's method.
+ */
+ w = cuddRand / LEQQ1;
+ cuddRand = LEQA1 * (cuddRand - w * LEQQ1) - w * LEQR1;
+ cuddRand += (cuddRand < 0) * MODULUS1;
+
+ /* Compute cuddRand2 = (cuddRand2 * LEQA2) % MODULUS2 avoiding
+ ** overflows by Schrage's method.
+ */
+ w = cuddRand2 / LEQQ2;
+ cuddRand2 = LEQA2 * (cuddRand2 - w * LEQQ2) - w * LEQR2;
+ cuddRand2 += (cuddRand2 < 0) * MODULUS2;
+
+ /* cuddRand is shuffled with the Bays-Durham algorithm.
+ ** shuffleSelect and cuddRand2 are combined to generate the output.
+ */
+
+ /* Pick one element from the shuffle table; "i" will be in the range
+ ** from 0 to STAB_SIZE-1.
+ */
+ i = (int) (shuffleSelect / STAB_DIV);
+ /* Mix the element of the shuffle table with the current iterate of
+ ** the second sub-generator, and replace the chosen element of the
+ ** shuffle table with the current iterate of the first sub-generator.
+ */
+ shuffleSelect = shuffleTable[i] - cuddRand2;
+ shuffleTable[i] = cuddRand;
+ shuffleSelect += (shuffleSelect < 1) * (MODULUS1 - 1);
+ /* Since shuffleSelect != 0, and we want to be able to return 0,
+ ** here we subtract 1 before returning.
+ */
+ return(shuffleSelect - 1);
+
+} /* end of Cudd_Random */
+
+
+/**Function********************************************************************
+
+ Synopsis [Initializer for the portable random number generator.]
+
+ Description [Initializer for the portable number generator based on
+ ran2 in "Numerical Recipes in C." The input is the seed for the
+ generator. If it is negative, its absolute value is taken as seed.
+ If it is 0, then 1 is taken as seed. The initialized sets up the two
+ recurrences used to generate a long-period stream, and sets up the
+ shuffle table.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Random]
+
+******************************************************************************/
+void
+Cudd_Srandom(
+ long seed)
+{
+ int i;
+
+ if (seed < 0) cuddRand = -seed;
+ else if (seed == 0) cuddRand = 1;
+ else cuddRand = seed;
+ cuddRand2 = cuddRand;
+ /* Load the shuffle table (after 11 warm-ups). */
+ for (i = 0; i < STAB_SIZE + 11; i++) {
+ long int w;
+ w = cuddRand / LEQQ1;
+ cuddRand = LEQA1 * (cuddRand - w * LEQQ1) - w * LEQR1;
+ cuddRand += (cuddRand < 0) * MODULUS1;
+ shuffleTable[i % STAB_SIZE] = cuddRand;
+ }
+ shuffleSelect = shuffleTable[1 % STAB_SIZE];
+
+} /* end of Cudd_Srandom */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the density of a BDD or ADD.]
+
+ Description [Computes the density of a BDD or ADD. The density is
+ the ratio of the number of minterms to the number of nodes. If 0 is
+ passed as number of variables, the number of variables existing in
+ the manager is used. Returns the density if successful; (double)
+ CUDD_OUT_OF_MEM otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_CountMinterm Cudd_DagSize]
+
+******************************************************************************/
+double
+Cudd_Density(
+ DdManager * dd /* manager */,
+ DdNode * f /* function whose density is sought */,
+ int nvars /* size of the support of f */)
+{
+ double minterms;
+ int nodes;
+ double density;
+
+ if (nvars == 0) nvars = dd->size;
+ minterms = Cudd_CountMinterm(dd,f,nvars);
+ if (minterms == (double) CUDD_OUT_OF_MEM) return(minterms);
+ nodes = Cudd_DagSize(f);
+ density = minterms / (double) nodes;
+ return(density);
+
+} /* end of Cudd_Density */
+
+
+/**Function********************************************************************
+
+ Synopsis [Warns that a memory allocation failed.]
+
+ Description [Warns that a memory allocation failed.
+ This function can be used as replacement of MMout_of_memory to prevent
+ the safe_mem functions of the util package from exiting when malloc
+ returns NULL. One possible use is in case of discretionary allocations;
+ for instance, the allocation of memory to enlarge the computed table.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+Cudd_OutOfMem(
+ long size /* size of the allocation that failed */)
+{
+ (void) fflush(stdout);
+ (void) fprintf(stderr, "\nunable to allocate %ld bytes\n", size);
+ return;
+
+} /* end of Cudd_OutOfMem */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints a DD to the standard output. One line per node is
+ printed.]
+
+ Description [Prints a DD to the standard output. One line per node is
+ printed. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_PrintDebug]
+
+******************************************************************************/
+int
+cuddP(
+ DdManager * dd,
+ DdNode * f)
+{
+ int retval;
+ st_table *table = st_init_table(st_ptrcmp,st_ptrhash);
+
+ if (table == NULL) return(0);
+
+ retval = dp2(dd,f,table);
+ st_free_table(table);
+ (void) fputc('\n',dd->out);
+ return(retval);
+
+} /* end of cuddP */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees the memory used to store the minterm counts recorded
+ in the visited table.]
+
+ Description [Frees the memory used to store the minterm counts
+ recorded in the visited table. Returns ST_CONTINUE.]
+
+ SideEffects [None]
+
+******************************************************************************/
+enum st_retval
+cuddStCountfree(
+ char * key,
+ char * value,
+ char * arg)
+{
+ double *d;
+
+ d = (double *)value;
+ FREE(d);
+ return(ST_CONTINUE);
+
+} /* end of cuddStCountfree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Recursively collects all the nodes of a DD in a symbol
+ table.]
+
+ Description [Traverses the BDD f and collects all its nodes in a
+ symbol table. f is assumed to be a regular pointer and
+ cuddCollectNodes guarantees this assumption in the recursive calls.
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddCollectNodes(
+ DdNode * f,
+ st_table * visited)
+{
+ DdNode *T, *E;
+ int retval;
+
+#ifdef DD_DEBUG
+ assert(!Cudd_IsComplement(f));
+#endif
+
+ /* If already visited, nothing to do. */
+ if (st_is_member(visited, (char *) f) == 1)
+ return(1);
+
+ /* Check for abnormal condition that should never happen. */
+ if (f == NULL)
+ return(0);
+
+ /* Mark node as visited. */
+ if (st_add_direct(visited, (char *) f, NULL) == ST_OUT_OF_MEM)
+ return(0);
+
+ /* Check terminal case. */
+ if (cuddIsConstant(f))
+ return(1);
+
+ /* Recursive calls. */
+ T = cuddT(f);
+ retval = cuddCollectNodes(T,visited);
+ if (retval != 1) return(retval);
+ E = Cudd_Regular(cuddE(f));
+ retval = cuddCollectNodes(E,visited);
+ return(retval);
+
+} /* end of cuddCollectNodes */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of cuddP.]
+
+ Description [Performs the recursive step of cuddP. Returns 1 in case
+ of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+dp2(
+ DdManager *dd,
+ DdNode * f,
+ st_table * t)
+{
+ DdNode *g, *n, *N;
+ int T,E;
+
+ if (f == NULL) {
+ return(0);
+ }
+ g = Cudd_Regular(f);
+ if (cuddIsConstant(g)) {
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(dd->out,"ID = %c0x%lx\tvalue = %-9g\n", bang(f),
+ (unsigned long) g / (unsigned long) sizeof(DdNode),cuddV(g));
+#else
+ (void) fprintf(dd->out,"ID = %c0x%x\tvalue = %-9g\n", bang(f),
+ (unsigned) g / (unsigned) sizeof(DdNode),cuddV(g));
+#endif
+ return(1);
+ }
+ if (st_is_member(t,(char *) g) == 1) {
+ return(1);
+ }
+ if (st_add_direct(t,(char *) g,NULL) == ST_OUT_OF_MEM)
+ return(0);
+#ifdef DD_STATS
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(dd->out,"ID = %c0x%lx\tindex = %d\tr = %d\t", bang(f),
+ (unsigned long) g / (unsigned long) sizeof(DdNode), g->index, g->ref);
+#else
+ (void) fprintf(dd->out,"ID = %c0x%x\tindex = %d\tr = %d\t", bang(f),
+ (unsigned) g / (unsigned) sizeof(DdNode),g->index,g->ref);
+#endif
+#else
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(dd->out,"ID = %c0x%lx\tindex = %d\t", bang(f),
+ (unsigned long) g / (unsigned long) sizeof(DdNode),g->index);
+#else
+ (void) fprintf(dd->out,"ID = %c0x%x\tindex = %d\t", bang(f),
+ (unsigned) g / (unsigned) sizeof(DdNode),g->index);
+#endif
+#endif
+ n = cuddT(g);
+ if (cuddIsConstant(n)) {
+ (void) fprintf(dd->out,"T = %-9g\t",cuddV(n));
+ T = 1;
+ } else {
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(dd->out,"T = 0x%lx\t",(unsigned long) n / (unsigned long) sizeof(DdNode));
+#else
+ (void) fprintf(dd->out,"T = 0x%x\t",(unsigned) n / (unsigned) sizeof(DdNode));
+#endif
+ T = 0;
+ }
+
+ n = cuddE(g);
+ N = Cudd_Regular(n);
+ if (cuddIsConstant(N)) {
+ (void) fprintf(dd->out,"E = %c%-9g\n",bang(n),cuddV(N));
+ E = 1;
+ } else {
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(dd->out,"E = %c0x%lx\n", bang(n), (unsigned long) N/(unsigned long) sizeof(DdNode));
+#else
+ (void) fprintf(dd->out,"E = %c0x%x\n", bang(n), (unsigned) N/(unsigned) sizeof(DdNode));
+#endif
+ E = 0;
+ }
+ if (E == 0) {
+ if (dp2(dd,N,t) == 0)
+ return(0);
+ }
+ if (T == 0) {
+ if (dp2(dd,cuddT(g),t) == 0)
+ return(0);
+ }
+ return(1);
+
+} /* end of dp2 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_PrintMinterm.]
+
+ Description []
+
+ SideEffects [None]
+
+******************************************************************************/
+static void
+ddPrintMintermAux(
+ DdManager * dd /* manager */,
+ DdNode * node /* current node */,
+ int * list /* current recursion path */)
+{
+ DdNode *N,*Nv,*Nnv;
+ int i,v,index;
+
+ N = Cudd_Regular(node);
+
+ if (cuddIsConstant(N)) {
+ /* Terminal case: Print one cube based on the current recursion
+ ** path, unless we have reached the background value (ADDs) or
+ ** the logical zero (BDDs).
+ */
+ if (node != background && node != zero) {
+ for (i = 0; i < dd->size; i++) {
+ v = list[i];
+ if (v == 0) (void) fprintf(dd->out,"0");
+ else if (v == 1) (void) fprintf(dd->out,"1");
+ else (void) fprintf(dd->out,"-");
+ }
+ (void) fprintf(dd->out," % g\n", cuddV(node));
+ }
+ } else {
+ Nv = cuddT(N);
+ Nnv = cuddE(N);
+ if (Cudd_IsComplement(node)) {
+ Nv = Cudd_Not(Nv);
+ Nnv = Cudd_Not(Nnv);
+ }
+ index = N->index;
+ list[index] = 0;
+ ddPrintMintermAux(dd,Nnv,list);
+ list[index] = 1;
+ ddPrintMintermAux(dd,Nv,list);
+ list[index] = 2;
+ }
+ return;
+
+} /* end of ddPrintMintermAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_DagSize.]
+
+ Description [Performs the recursive step of Cudd_DagSize. Returns the
+ number of nodes in the graph rooted at n.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddDagInt(
+ DdNode * n)
+{
+ int tval, eval;
+
+ if (Cudd_IsComplement(n->next)) {
+ return(0);
+ }
+ n->next = Cudd_Not(n->next);
+ if (cuddIsConstant(n)) {
+ return(1);
+ }
+ tval = ddDagInt(cuddT(n));
+ eval = ddDagInt(Cudd_Regular(cuddE(n)));
+ return(1 + tval + eval);
+
+} /* end of ddDagInt */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_CofactorEstimate.]
+
+ Description [Performs the recursive step of Cudd_CofactorEstimate.
+ Returns an estimate of the number of nodes in the DD of a
+ cofactor of node. Uses the least significant bit of the next field as
+ visited flag. node is supposed to be regular; the invariant is maintained
+ by this procedure.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddEstimateCofactor(
+ DdManager *dd,
+ st_table *table,
+ DdNode * node,
+ int i,
+ int phase,
+ DdNode ** ptr)
+{
+ int tval, eval, val;
+ DdNode *ptrT, *ptrE;
+
+ if (Cudd_IsComplement(node->next)) {
+ if (!st_lookup(table,(char *)node,(char **)ptr)) {
+ st_add_direct(table,(char *)node,(char *)node);
+ *ptr = node;
+ }
+ return(0);
+ }
+ node->next = Cudd_Not(node->next);
+ if (cuddIsConstant(node)) {
+ *ptr = node;
+ if (st_add_direct(table,(char *)node,(char *)node) == ST_OUT_OF_MEM)
+ return(CUDD_OUT_OF_MEM);
+ return(1);
+ }
+ if ((int) node->index == i) {
+ if (phase == 1) {
+ *ptr = cuddT(node);
+ val = ddDagInt(cuddT(node));
+ } else {
+ *ptr = cuddE(node);
+ val = ddDagInt(Cudd_Regular(cuddE(node)));
+ }
+ if (node->ref > 1) {
+ if (st_add_direct(table,(char *)node,(char *)*ptr) ==
+ ST_OUT_OF_MEM)
+ return(CUDD_OUT_OF_MEM);
+ }
+ return(val);
+ }
+ if (dd->perm[node->index] > dd->perm[i]) {
+ *ptr = node;
+ tval = ddDagInt(cuddT(node));
+ eval = ddDagInt(Cudd_Regular(cuddE(node)));
+ if (node->ref > 1) {
+ if (st_add_direct(table,(char *)node,(char *)node) ==
+ ST_OUT_OF_MEM)
+ return(CUDD_OUT_OF_MEM);
+ }
+ val = 1 + tval + eval;
+ return(val);
+ }
+ tval = cuddEstimateCofactor(dd,table,cuddT(node),i,phase,&ptrT);
+ eval = cuddEstimateCofactor(dd,table,Cudd_Regular(cuddE(node)),i,
+ phase,&ptrE);
+ ptrE = Cudd_NotCond(ptrE,Cudd_IsComplement(cuddE(node)));
+ if (ptrT == ptrE) { /* recombination */
+ *ptr = ptrT;
+ val = tval;
+ if (node->ref > 1) {
+ if (st_add_direct(table,(char *)node,(char *)*ptr) ==
+ ST_OUT_OF_MEM)
+ return(CUDD_OUT_OF_MEM);
+ }
+ } else if ((ptrT != cuddT(node) || ptrE != cuddE(node)) &&
+ (*ptr = cuddUniqueLookup(dd,node->index,ptrT,ptrE)) != NULL) {
+ if (Cudd_IsComplement((*ptr)->next)) {
+ val = 0;
+ } else {
+ val = 1 + tval + eval;
+ }
+ if (node->ref > 1) {
+ if (st_add_direct(table,(char *)node,(char *)*ptr) ==
+ ST_OUT_OF_MEM)
+ return(CUDD_OUT_OF_MEM);
+ }
+ } else {
+ *ptr = node;
+ val = 1 + tval + eval;
+ }
+ return(val);
+
+} /* end of cuddEstimateCofactor */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks the unique table for the existence of an internal node.]
+
+ Description [Checks the unique table for the existence of an internal
+ node. Returns a pointer to the node if it is in the table; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddUniqueInter]
+
+******************************************************************************/
+static DdNode *
+cuddUniqueLookup(
+ DdManager * unique,
+ int index,
+ DdNode * T,
+ DdNode * E)
+{
+ int posn;
+ unsigned int level;
+ DdNodePtr *nodelist;
+ DdNode *looking;
+ DdSubtable *subtable;
+
+ if (index >= unique->size) {
+ return(NULL);
+ }
+
+ level = unique->perm[index];
+ subtable = &(unique->subtables[level]);
+
+#ifdef DD_DEBUG
+ assert(level < (unsigned) cuddI(unique,T->index));
+ assert(level < (unsigned) cuddI(unique,Cudd_Regular(E)->index));
+#endif
+
+ posn = ddHash(T, E, subtable->shift);
+ nodelist = subtable->nodelist;
+ looking = nodelist[posn];
+
+ while (T < cuddT(looking)) {
+ looking = Cudd_Regular(looking->next);
+ }
+ while (T == cuddT(looking) && E < cuddE(looking)) {
+ looking = Cudd_Regular(looking->next);
+ }
+ if (cuddT(looking) == T && cuddE(looking) == E) {
+ return(looking);
+ }
+
+ return(NULL);
+
+} /* end of cuddUniqueLookup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_CofactorEstimateSimple.]
+
+ Description [Performs the recursive step of Cudd_CofactorEstimateSimple.
+ Returns an estimate of the number of nodes in the DD of the positive
+ cofactor of node. Uses the least significant bit of the next field as
+ visited flag. node is supposed to be regular; the invariant is maintained
+ by this procedure.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddEstimateCofactorSimple(
+ DdNode * node,
+ int i)
+{
+ int tval, eval;
+
+ if (Cudd_IsComplement(node->next)) {
+ return(0);
+ }
+ node->next = Cudd_Not(node->next);
+ if (cuddIsConstant(node)) {
+ return(1);
+ }
+ tval = cuddEstimateCofactorSimple(cuddT(node),i);
+ if ((int) node->index == i) return(tval);
+ eval = cuddEstimateCofactorSimple(Cudd_Regular(cuddE(node)),i);
+ return(1 + tval + eval);
+
+} /* end of cuddEstimateCofactorSimple */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_CountMinterm.]
+
+ Description [Performs the recursive step of Cudd_CountMinterm.
+ It is based on the following identity. Let |f| be the
+ number of minterms of f. Then:
+ <xmp>
+ |f| = (|f0|+|f1|)/2
+ </xmp>
+ where f0 and f1 are the two cofactors of f. Does not use the
+ identity |f'| = max - |f|, to minimize loss of accuracy due to
+ roundoff. Returns the number of minterms of the function rooted at
+ node.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static double
+ddCountMintermAux(
+ DdNode * node,
+ double max,
+ DdHashTable * table)
+{
+ DdNode *N, *Nt, *Ne;
+ double min, minT, minE;
+ DdNode *res;
+
+ N = Cudd_Regular(node);
+
+ if (cuddIsConstant(N)) {
+ if (node == background || node == zero) {
+ return(0.0);
+ } else {
+ return(max);
+ }
+ }
+ if (N->ref != 1 && (res = cuddHashTableLookup1(table,node)) != NULL) {
+ min = cuddV(res);
+ if (res->ref == 0) {
+ table->manager->dead++;
+ table->manager->constants.dead++;
+ }
+ return(min);
+ }
+
+ Nt = cuddT(N); Ne = cuddE(N);
+ if (Cudd_IsComplement(node)) {
+ Nt = Cudd_Not(Nt); Ne = Cudd_Not(Ne);
+ }
+
+ minT = ddCountMintermAux(Nt,max,table);
+ if (minT == (double)CUDD_OUT_OF_MEM) return((double)CUDD_OUT_OF_MEM);
+ minT *= 0.5;
+ minE = ddCountMintermAux(Ne,max,table);
+ if (minE == (double)CUDD_OUT_OF_MEM) return((double)CUDD_OUT_OF_MEM);
+ minE *= 0.5;
+ min = minT + minE;
+
+ if (N->ref != 1) {
+ ptrint fanout = (ptrint) N->ref;
+ cuddSatDec(fanout);
+ res = cuddUniqueConst(table->manager,min);
+ if (!cuddHashTableInsert1(table,node,res,fanout)) {
+ cuddRef(res); Cudd_RecursiveDeref(table->manager, res);
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ }
+
+ return(min);
+
+} /* end of ddCountMintermAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_CountPath.]
+
+ Description [Performs the recursive step of Cudd_CountPath.
+ It is based on the following identity. Let |f| be the
+ number of paths of f. Then:
+ <xmp>
+ |f| = |f0|+|f1|
+ </xmp>
+ where f0 and f1 are the two cofactors of f. Uses the
+ identity |f'| = |f|, to improve the utilization of the (local) cache.
+ Returns the number of paths of the function rooted at node.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static double
+ddCountPathAux(
+ DdNode * node,
+ st_table * table)
+{
+
+ DdNode *Nv, *Nnv;
+ double paths, *ppaths, paths1, paths2;
+ double *dummy;
+
+
+ if (cuddIsConstant(node)) {
+ return(1.0);
+ }
+ if (st_lookup(table, (char *)node, (char **)&dummy)) {
+ paths = *dummy;
+ return(paths);
+ }
+
+ Nv = cuddT(node); Nnv = cuddE(node);
+
+ paths1 = ddCountPathAux(Nv,table);
+ if (paths1 == (double)CUDD_OUT_OF_MEM) return((double)CUDD_OUT_OF_MEM);
+ paths2 = ddCountPathAux(Cudd_Regular(Nnv),table);
+ if (paths2 == (double)CUDD_OUT_OF_MEM) return((double)CUDD_OUT_OF_MEM);
+ paths = paths1 + paths2;
+
+ ppaths = ALLOC(double,1);
+ if (ppaths == NULL) {
+ return((double)CUDD_OUT_OF_MEM);
+ }
+
+ *ppaths = paths;
+
+ if (st_add_direct(table,(char *)node, (char *)ppaths) == ST_OUT_OF_MEM) {
+ FREE(ppaths);
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ return(paths);
+
+} /* end of ddCountPathAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_CountMinterm.]
+
+ Description [Performs the recursive step of Cudd_CountMinterm.
+ It is based on the following identity. Let |f| be the
+ number of minterms of f. Then:
+ <xmp>
+ |f| = (|f0|+|f1|)/2
+ </xmp>
+ where f0 and f1 are the two cofactors of f. Does not use the
+ identity |f'| = max - |f|, to minimize loss of accuracy due to
+ roundoff. Returns the number of minterms of the function rooted at
+ node.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddEpdCountMintermAux(
+ DdNode * node,
+ EpDouble * max,
+ EpDouble * epd,
+ st_table * table)
+{
+ DdNode *Nt, *Ne;
+ EpDouble *min, minT, minE;
+ EpDouble *res;
+ int status;
+
+ if (cuddIsConstant(node)) {
+ if (node == background || node == zero) {
+ EpdMakeZero(epd, 0);
+ } else {
+ EpdCopy(max, epd);
+ }
+ return(0);
+ }
+ if (node->ref != 1 && st_lookup(table, (char *)node, (char **)&res)) {
+ EpdCopy(res, epd);
+ return(0);
+ }
+
+ Nt = cuddT(node); Ne = cuddE(node);
+ if (Cudd_IsComplement(node)) {
+ Nt = Cudd_Not(Nt); Ne = Cudd_Not(Ne);
+ }
+
+ status = ddEpdCountMintermAux(Nt,max,&minT,table);
+ if (status == CUDD_OUT_OF_MEM) return(CUDD_OUT_OF_MEM);
+ EpdMultiply(&minT, (double)0.5);
+ status = ddEpdCountMintermAux(Ne,max,&minE,table);
+ if (status == CUDD_OUT_OF_MEM) return(CUDD_OUT_OF_MEM);
+ if (Cudd_IsComplement(Ne)) {
+ EpdSubtract3(max, &minE, epd);
+ EpdCopy(epd, &minE);
+ }
+ EpdMultiply(&minE, (double)0.5);
+ EpdAdd3(&minT, &minE, epd);
+
+ if (node->ref > 1) {
+ min = EpdAlloc();
+ if (!min)
+ return(CUDD_OUT_OF_MEM);
+ EpdCopy(epd, min);
+ if (st_insert(table, (char *)node, (char *)min) == ST_OUT_OF_MEM) {
+ EpdFree(min);
+ return(CUDD_OUT_OF_MEM);
+ }
+ }
+
+ return(0);
+
+} /* end of ddEpdCountMintermAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_CountPathsToNonZero.]
+
+ Description [Performs the recursive step of Cudd_CountPathsToNonZero.
+ It is based on the following identity. Let |f| be the
+ number of paths of f. Then:
+ <xmp>
+ |f| = |f0|+|f1|
+ </xmp>
+ where f0 and f1 are the two cofactors of f. Returns the number of
+ paths of the function rooted at node.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static double
+ddCountPathsToNonZero(
+ DdNode * N,
+ st_table * table)
+{
+
+ DdNode *node, *Nt, *Ne;
+ double paths, *ppaths, paths1, paths2;
+ double *dummy;
+
+ node = Cudd_Regular(N);
+ if (cuddIsConstant(node)) {
+ return((double) !(Cudd_IsComplement(N) || cuddV(node)==DD_ZERO_VAL));
+ }
+ if (st_lookup(table, (char *)N, (char **)&dummy)) {
+ paths = *dummy;
+ return(paths);
+ }
+
+ Nt = cuddT(node); Ne = cuddE(node);
+ if (node != N) {
+ Nt = Cudd_Not(Nt); Ne = Cudd_Not(Ne);
+ }
+
+ paths1 = ddCountPathsToNonZero(Nt,table);
+ if (paths1 == (double)CUDD_OUT_OF_MEM) return((double)CUDD_OUT_OF_MEM);
+ paths2 = ddCountPathsToNonZero(Ne,table);
+ if (paths2 == (double)CUDD_OUT_OF_MEM) return((double)CUDD_OUT_OF_MEM);
+ paths = paths1 + paths2;
+
+ ppaths = ALLOC(double,1);
+ if (ppaths == NULL) {
+ return((double)CUDD_OUT_OF_MEM);
+ }
+
+ *ppaths = paths;
+
+ if (st_add_direct(table,(char *)N, (char *)ppaths) == ST_OUT_OF_MEM) {
+ FREE(ppaths);
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ return(paths);
+
+} /* end of ddCountPathsToNonZero */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_Support.]
+
+ Description [Performs the recursive step of Cudd_Support. Performs a
+ DFS from f. The support is accumulated in supp as a side effect. Uses
+ the LSB of the then pointer as visited flag.]
+
+ SideEffects [None]
+
+ SeeAlso [ddClearFlag]
+
+******************************************************************************/
+static void
+ddSupportStep(
+ DdNode * f,
+ int * support)
+{
+ if (cuddIsConstant(f) || Cudd_IsComplement(f->next)) {
+ return;
+ }
+
+ support[f->index] = 1;
+ ddSupportStep(cuddT(f),support);
+ ddSupportStep(Cudd_Regular(cuddE(f)),support);
+ /* Mark as visited. */
+ f->next = Cudd_Not(f->next);
+ return;
+
+} /* end of ddSupportStep */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs a DFS from f, clearing the LSB of the next
+ pointers.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [ddSupportStep ddDagInt]
+
+******************************************************************************/
+static void
+ddClearFlag(
+ DdNode * f)
+{
+ if (!Cudd_IsComplement(f->next)) {
+ return;
+ }
+ /* Clear visited flag. */
+ f->next = Cudd_Regular(f->next);
+ if (cuddIsConstant(f)) {
+ return;
+ }
+ ddClearFlag(cuddT(f));
+ ddClearFlag(Cudd_Regular(cuddE(f)));
+ return;
+
+} /* end of ddClearFlag */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_CountLeaves.]
+
+ Description [Performs the recursive step of Cudd_CountLeaves. Returns
+ the number of leaves in the DD rooted at n.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_CountLeaves]
+
+******************************************************************************/
+static int
+ddLeavesInt(
+ DdNode * n)
+{
+ int tval, eval;
+
+ if (Cudd_IsComplement(n->next)) {
+ return(0);
+ }
+ n->next = Cudd_Not(n->next);
+ if (cuddIsConstant(n)) {
+ return(1);
+ }
+ tval = ddLeavesInt(cuddT(n));
+ eval = ddLeavesInt(Cudd_Regular(cuddE(n)));
+ return(tval + eval);
+
+} /* end of ddLeavesInt */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddPickArbitraryMinterms.]
+
+ Description [Performs the recursive step of Cudd_bddPickArbitraryMinterms.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_bddPickArbitraryMinterms]
+
+******************************************************************************/
+static int
+ddPickArbitraryMinterms(
+ DdManager *dd,
+ DdNode *node,
+ int nvars,
+ int nminterms,
+ char **string)
+{
+ DdNode *N, *T, *E;
+ DdNode *one, *bzero;
+ int i, t, result;
+ double min1, min2;
+
+ if (string == NULL || node == NULL) return(0);
+
+ /* The constant 0 function has no on-set cubes. */
+ one = DD_ONE(dd);
+ bzero = Cudd_Not(one);
+ if (nminterms == 0 || node == bzero) return(1);
+ if (node == one) {
+ return(1);
+ }
+
+ N = Cudd_Regular(node);
+ T = cuddT(N); E = cuddE(N);
+ if (Cudd_IsComplement(node)) {
+ T = Cudd_Not(T); E = Cudd_Not(E);
+ }
+
+ min1 = Cudd_CountMinterm(dd, T, nvars) / 2.0;
+ if (min1 == (double)CUDD_OUT_OF_MEM) return(0);
+ min2 = Cudd_CountMinterm(dd, E, nvars) / 2.0;
+ if (min2 == (double)CUDD_OUT_OF_MEM) return(0);
+
+ t = (int)((double)nminterms * min1 / (min1 + min2) + 0.5);
+ for (i = 0; i < t; i++)
+ string[i][N->index] = '1';
+ for (i = t; i < nminterms; i++)
+ string[i][N->index] = '0';
+
+ result = ddPickArbitraryMinterms(dd,T,nvars,t,&string[0]);
+ if (result == 0)
+ return(0);
+ result = ddPickArbitraryMinterms(dd,E,nvars,nminterms-t,&string[t]);
+ return(result);
+
+} /* end of ddPickArbitraryMinterms */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds a representative cube of a BDD.]
+
+ Description [Finds a representative cube of a BDD with the weight of
+ each variable. From the top variable, if the weight is greater than or
+ equal to 0.0, choose THEN branch unless the child is the constant 0.
+ Otherwise, choose ELSE branch unless the child is the constant 0.]
+
+ SideEffects [Cudd_SubsetWithMaskVars Cudd_bddPickOneCube]
+
+******************************************************************************/
+static int
+ddPickRepresentativeCube(
+ DdManager *dd,
+ DdNode *node,
+ int nvars,
+ double *weight,
+ char *string)
+{
+ DdNode *N, *T, *E;
+ DdNode *one, *bzero;
+
+ if (string == NULL || node == NULL) return(0);
+
+ /* The constant 0 function has no on-set cubes. */
+ one = DD_ONE(dd);
+ bzero = Cudd_Not(one);
+ if (node == bzero) return(0);
+
+ if (node == DD_ONE(dd)) return(1);
+
+ for (;;) {
+ N = Cudd_Regular(node);
+ if (N == one)
+ break;
+ T = cuddT(N);
+ E = cuddE(N);
+ if (Cudd_IsComplement(node)) {
+ T = Cudd_Not(T);
+ E = Cudd_Not(E);
+ }
+ if (weight[N->index] >= 0.0) {
+ if (T == bzero) {
+ node = E;
+ string[N->index] = '0';
+ } else {
+ node = T;
+ string[N->index] = '1';
+ }
+ } else {
+ if (E == bzero) {
+ node = T;
+ string[N->index] = '1';
+ } else {
+ node = E;
+ string[N->index] = '0';
+ }
+ }
+ }
+ return(1);
+
+} /* end of ddPickRepresentativeCube */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees the memory used to store the minterm counts recorded
+ in the visited table.]
+
+ Description [Frees the memory used to store the minterm counts
+ recorded in the visited table. Returns ST_CONTINUE.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static enum st_retval
+ddEpdFree(
+ char * key,
+ char * value,
+ char * arg)
+{
+ EpDouble *epd;
+
+ epd = (EpDouble *) value;
+ EpdFree(epd);
+ return(ST_CONTINUE);
+
+} /* end of ddEpdFree */
diff --git a/src/bdd/cudd/cuddWindow.c b/src/bdd/cudd/cuddWindow.c
new file mode 100644
index 00000000..3e6d5686
--- /dev/null
+++ b/src/bdd/cudd/cuddWindow.c
@@ -0,0 +1,997 @@
+/**CFile***********************************************************************
+
+ FileName [cuddWindow.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for window permutation]
+
+ Description [Internal procedures included in this module:
+ <ul>
+ <li> cuddWindowReorder()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> ddWindow2()
+ <li> ddWindowConv2()
+ <li> ddPermuteWindow3()
+ <li> ddWindow3()
+ <li> ddWindowConv3()
+ <li> ddPermuteWindow4()
+ <li> ddWindow4()
+ <li> ddWindowConv4()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddWindow.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+#ifdef DD_STATS
+extern int ddTotalNumberSwapping;
+extern int ddTotalNISwaps;
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int ddWindow2 ARGS((DdManager *table, int low, int high));
+static int ddWindowConv2 ARGS((DdManager *table, int low, int high));
+static int ddPermuteWindow3 ARGS((DdManager *table, int x));
+static int ddWindow3 ARGS((DdManager *table, int low, int high));
+static int ddWindowConv3 ARGS((DdManager *table, int low, int high));
+static int ddPermuteWindow4 ARGS((DdManager *table, int w));
+static int ddWindow4 ARGS((DdManager *table, int low, int high));
+static int ddWindowConv4 ARGS((DdManager *table, int low, int high));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders by applying the method of the sliding window.]
+
+ Description [Reorders by applying the method of the sliding window.
+ Tries all possible permutations to the variables in a window that
+ slides from low to high. The size of the window is determined by
+ submethod. Assumes that no dead nodes are present. Returns 1 in
+ case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+int
+cuddWindowReorder(
+ DdManager * table /* DD table */,
+ int low /* lowest index to reorder */,
+ int high /* highest index to reorder */,
+ Cudd_ReorderingType submethod /* window reordering option */)
+{
+
+ int res;
+#ifdef DD_DEBUG
+ int supposedOpt;
+#endif
+
+ switch (submethod) {
+ case CUDD_REORDER_WINDOW2:
+ res = ddWindow2(table,low,high);
+ break;
+ case CUDD_REORDER_WINDOW3:
+ res = ddWindow3(table,low,high);
+ break;
+ case CUDD_REORDER_WINDOW4:
+ res = ddWindow4(table,low,high);
+ break;
+ case CUDD_REORDER_WINDOW2_CONV:
+ res = ddWindowConv2(table,low,high);
+ break;
+ case CUDD_REORDER_WINDOW3_CONV:
+ res = ddWindowConv3(table,low,high);
+#ifdef DD_DEBUG
+ supposedOpt = table->keys - table->isolated;
+ res = ddWindow3(table,low,high);
+ if (table->keys - table->isolated != (unsigned) supposedOpt) {
+ (void) fprintf(table->err, "Convergence failed! (%d != %d)\n",
+ table->keys - table->isolated, supposedOpt);
+ }
+#endif
+ break;
+ case CUDD_REORDER_WINDOW4_CONV:
+ res = ddWindowConv4(table,low,high);
+#ifdef DD_DEBUG
+ supposedOpt = table->keys - table->isolated;
+ res = ddWindow4(table,low,high);
+ if (table->keys - table->isolated != (unsigned) supposedOpt) {
+ (void) fprintf(table->err,"Convergence failed! (%d != %d)\n",
+ table->keys - table->isolated, supposedOpt);
+ }
+#endif
+ break;
+ default: return(0);
+ }
+
+ return(res);
+
+} /* end of cuddWindowReorder */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Reorders by applying a sliding window of width 2.]
+
+ Description [Reorders by applying a sliding window of width 2.
+ Tries both permutations of the variables in a window
+ that slides from low to high. Assumes that no dead nodes are
+ present. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddWindow2(
+ DdManager * table,
+ int low,
+ int high)
+{
+
+ int x;
+ int res;
+ int size;
+
+#ifdef DD_DEBUG
+ assert(low >= 0 && high < table->size);
+#endif
+
+ if (high-low < 1) return(0);
+
+ res = table->keys - table->isolated;
+ for (x = low; x < high; x++) {
+ size = res;
+ res = cuddSwapInPlace(table,x,x+1);
+ if (res == 0) return(0);
+ if (res >= size) { /* no improvement: undo permutation */
+ res = cuddSwapInPlace(table,x,x+1);
+ if (res == 0) return(0);
+ }
+#ifdef DD_STATS
+ if (res < size) {
+ (void) fprintf(table->out,"-");
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+
+ return(1);
+
+} /* end of ddWindow2 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders by repeatedly applying a sliding window of width 2.]
+
+ Description [Reorders by repeatedly applying a sliding window of width
+ 2. Tries both permutations of the variables in a window
+ that slides from low to high. Assumes that no dead nodes are
+ present. Uses an event-driven approach to determine convergence.
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddWindowConv2(
+ DdManager * table,
+ int low,
+ int high)
+{
+ int x;
+ int res;
+ int nwin;
+ int newevent;
+ int *events;
+ int size;
+
+#ifdef DD_DEBUG
+ assert(low >= 0 && high < table->size);
+#endif
+
+ if (high-low < 1) return(ddWindowConv2(table,low,high));
+
+ nwin = high-low;
+ events = ALLOC(int,nwin);
+ if (events == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (x=0; x<nwin; x++) {
+ events[x] = 1;
+ }
+
+ res = table->keys - table->isolated;
+ do {
+ newevent = 0;
+ for (x=0; x<nwin; x++) {
+ if (events[x]) {
+ size = res;
+ res = cuddSwapInPlace(table,x+low,x+low+1);
+ if (res == 0) {
+ FREE(events);
+ return(0);
+ }
+ if (res >= size) { /* no improvement: undo permutation */
+ res = cuddSwapInPlace(table,x+low,x+low+1);
+ if (res == 0) {
+ FREE(events);
+ return(0);
+ }
+ }
+ if (res < size) {
+ if (x < nwin-1) events[x+1] = 1;
+ if (x > 0) events[x-1] = 1;
+ newevent = 1;
+ }
+ events[x] = 0;
+#ifdef DD_STATS
+ if (res < size) {
+ (void) fprintf(table->out,"-");
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+ }
+#ifdef DD_STATS
+ if (newevent) {
+ (void) fprintf(table->out,"|");
+ fflush(table->out);
+ }
+#endif
+ } while (newevent);
+
+ FREE(events);
+
+ return(1);
+
+} /* end of ddWindowConv3 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tries all the permutations of the three variables between
+ x and x+2 and retains the best.]
+
+ Description [Tries all the permutations of the three variables between
+ x and x+2 and retains the best. Assumes that no dead nodes are
+ present. Returns the index of the best permutation (1-6) in case of
+ success; 0 otherwise.Assumes that no dead nodes are present. Returns
+ the index of the best permutation (1-6) in case of success; 0
+ otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddPermuteWindow3(
+ DdManager * table,
+ int x)
+{
+ int y,z;
+ int size,sizeNew;
+ int best;
+
+#ifdef DD_DEBUG
+ assert(table->dead == 0);
+ assert(x+2 < table->size);
+#endif
+
+ size = table->keys - table->isolated;
+ y = x+1; z = y+1;
+
+ /* The permutation pattern is:
+ ** (x,y)(y,z)
+ ** repeated three times to get all 3! = 6 permutations.
+ */
+#define ABC 1
+ best = ABC;
+
+#define BAC 2
+ sizeNew = cuddSwapInPlace(table,x,y);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = BAC;
+ size = sizeNew;
+ }
+#define BCA 3
+ sizeNew = cuddSwapInPlace(table,y,z);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = BCA;
+ size = sizeNew;
+ }
+#define CBA 4
+ sizeNew = cuddSwapInPlace(table,x,y);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = CBA;
+ size = sizeNew;
+ }
+#define CAB 5
+ sizeNew = cuddSwapInPlace(table,y,z);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = CAB;
+ size = sizeNew;
+ }
+#define ACB 6
+ sizeNew = cuddSwapInPlace(table,x,y);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = ACB;
+ size = sizeNew;
+ }
+
+ /* Now take the shortest route to the best permuytation.
+ ** The initial permutation is ACB.
+ */
+ switch(best) {
+ case BCA: if (!cuddSwapInPlace(table,y,z)) return(0);
+ case CBA: if (!cuddSwapInPlace(table,x,y)) return(0);
+ case ABC: if (!cuddSwapInPlace(table,y,z)) return(0);
+ case ACB: break;
+ case BAC: if (!cuddSwapInPlace(table,y,z)) return(0);
+ case CAB: if (!cuddSwapInPlace(table,x,y)) return(0);
+ break;
+ default: return(0);
+ }
+
+#ifdef DD_DEBUG
+ assert(table->keys - table->isolated == (unsigned) size);
+#endif
+
+ return(best);
+
+} /* end of ddPermuteWindow3 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders by applying a sliding window of width 3.]
+
+ Description [Reorders by applying a sliding window of width 3.
+ Tries all possible permutations to the variables in a
+ window that slides from low to high. Assumes that no dead nodes are
+ present. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddWindow3(
+ DdManager * table,
+ int low,
+ int high)
+{
+
+ int x;
+ int res;
+
+#ifdef DD_DEBUG
+ assert(low >= 0 && high < table->size);
+#endif
+
+ if (high-low < 2) return(ddWindow2(table,low,high));
+
+ for (x = low; x+1 < high; x++) {
+ res = ddPermuteWindow3(table,x);
+ if (res == 0) return(0);
+#ifdef DD_STATS
+ if (res == ABC) {
+ (void) fprintf(table->out,"=");
+ } else {
+ (void) fprintf(table->out,"-");
+ }
+ fflush(table->out);
+#endif
+ }
+
+ return(1);
+
+} /* end of ddWindow3 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders by repeatedly applying a sliding window of width 3.]
+
+ Description [Reorders by repeatedly applying a sliding window of width
+ 3. Tries all possible permutations to the variables in a
+ window that slides from low to high. Assumes that no dead nodes are
+ present. Uses an event-driven approach to determine convergence.
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddWindowConv3(
+ DdManager * table,
+ int low,
+ int high)
+{
+ int x;
+ int res;
+ int nwin;
+ int newevent;
+ int *events;
+
+#ifdef DD_DEBUG
+ assert(low >= 0 && high < table->size);
+#endif
+
+ if (high-low < 2) return(ddWindowConv2(table,low,high));
+
+ nwin = high-low-1;
+ events = ALLOC(int,nwin);
+ if (events == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (x=0; x<nwin; x++) {
+ events[x] = 1;
+ }
+
+ do {
+ newevent = 0;
+ for (x=0; x<nwin; x++) {
+ if (events[x]) {
+ res = ddPermuteWindow3(table,x+low);
+ switch (res) {
+ case ABC:
+ break;
+ case BAC:
+ if (x < nwin-1) events[x+1] = 1;
+ if (x > 1) events[x-2] = 1;
+ newevent = 1;
+ break;
+ case BCA:
+ case CBA:
+ case CAB:
+ if (x < nwin-2) events[x+2] = 1;
+ if (x < nwin-1) events[x+1] = 1;
+ if (x > 0) events[x-1] = 1;
+ if (x > 1) events[x-2] = 1;
+ newevent = 1;
+ break;
+ case ACB:
+ if (x < nwin-2) events[x+2] = 1;
+ if (x > 0) events[x-1] = 1;
+ newevent = 1;
+ break;
+ default:
+ FREE(events);
+ return(0);
+ }
+ events[x] = 0;
+#ifdef DD_STATS
+ if (res == ABC) {
+ (void) fprintf(table->out,"=");
+ } else {
+ (void) fprintf(table->out,"-");
+ }
+ fflush(table->out);
+#endif
+ }
+ }
+#ifdef DD_STATS
+ if (newevent) {
+ (void) fprintf(table->out,"|");
+ fflush(table->out);
+ }
+#endif
+ } while (newevent);
+
+ FREE(events);
+
+ return(1);
+
+} /* end of ddWindowConv3 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tries all the permutations of the four variables between w
+ and w+3 and retains the best.]
+
+ Description [Tries all the permutations of the four variables between
+ w and w+3 and retains the best. Assumes that no dead nodes are
+ present. Returns the index of the best permutation (1-24) in case of
+ success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddPermuteWindow4(
+ DdManager * table,
+ int w)
+{
+ int x,y,z;
+ int size,sizeNew;
+ int best;
+
+#ifdef DD_DEBUG
+ assert(table->dead == 0);
+ assert(w+3 < table->size);
+#endif
+
+ size = table->keys - table->isolated;
+ x = w+1; y = x+1; z = y+1;
+
+ /* The permutation pattern is:
+ * (w,x)(y,z)(w,x)(x,y)
+ * (y,z)(w,x)(y,z)(x,y)
+ * repeated three times to get all 4! = 24 permutations.
+ * This gives a hamiltonian circuit of Cayley's graph.
+ * The codes to the permutation are assigned in topological order.
+ * The permutations at lower distance from the final permutation are
+ * assigned lower codes. This way we can choose, between
+ * permutations that give the same size, one that requires the minimum
+ * number of swaps from the final permutation of the hamiltonian circuit.
+ * There is an exception to this rule: ABCD is given Code 1, to
+ * avoid oscillation when convergence is sought.
+ */
+#define ABCD 1
+ best = ABCD;
+
+#define BACD 7
+ sizeNew = cuddSwapInPlace(table,w,x);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = BACD;
+ size = sizeNew;
+ }
+#define BADC 13
+ sizeNew = cuddSwapInPlace(table,y,z);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = BADC;
+ size = sizeNew;
+ }
+#define ABDC 8
+ sizeNew = cuddSwapInPlace(table,w,x);
+ if (sizeNew < size || (sizeNew == size && ABDC < best)) {
+ if (sizeNew == 0) return(0);
+ best = ABDC;
+ size = sizeNew;
+ }
+#define ADBC 14
+ sizeNew = cuddSwapInPlace(table,x,y);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = ADBC;
+ size = sizeNew;
+ }
+#define ADCB 9
+ sizeNew = cuddSwapInPlace(table,y,z);
+ if (sizeNew < size || (sizeNew == size && ADCB < best)) {
+ if (sizeNew == 0) return(0);
+ best = ADCB;
+ size = sizeNew;
+ }
+#define DACB 15
+ sizeNew = cuddSwapInPlace(table,w,x);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = DACB;
+ size = sizeNew;
+ }
+#define DABC 20
+ sizeNew = cuddSwapInPlace(table,y,z);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = DABC;
+ size = sizeNew;
+ }
+#define DBAC 23
+ sizeNew = cuddSwapInPlace(table,x,y);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = DBAC;
+ size = sizeNew;
+ }
+#define BDAC 19
+ sizeNew = cuddSwapInPlace(table,w,x);
+ if (sizeNew < size || (sizeNew == size && BDAC < best)) {
+ if (sizeNew == 0) return(0);
+ best = BDAC;
+ size = sizeNew;
+ }
+#define BDCA 21
+ sizeNew = cuddSwapInPlace(table,y,z);
+ if (sizeNew < size || (sizeNew == size && BDCA < best)) {
+ if (sizeNew == 0) return(0);
+ best = BDCA;
+ size = sizeNew;
+ }
+#define DBCA 24
+ sizeNew = cuddSwapInPlace(table,w,x);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = DBCA;
+ size = sizeNew;
+ }
+#define DCBA 22
+ sizeNew = cuddSwapInPlace(table,x,y);
+ if (sizeNew < size || (sizeNew == size && DCBA < best)) {
+ if (sizeNew == 0) return(0);
+ best = DCBA;
+ size = sizeNew;
+ }
+#define DCAB 18
+ sizeNew = cuddSwapInPlace(table,y,z);
+ if (sizeNew < size || (sizeNew == size && DCAB < best)) {
+ if (sizeNew == 0) return(0);
+ best = DCAB;
+ size = sizeNew;
+ }
+#define CDAB 12
+ sizeNew = cuddSwapInPlace(table,w,x);
+ if (sizeNew < size || (sizeNew == size && CDAB < best)) {
+ if (sizeNew == 0) return(0);
+ best = CDAB;
+ size = sizeNew;
+ }
+#define CDBA 17
+ sizeNew = cuddSwapInPlace(table,y,z);
+ if (sizeNew < size || (sizeNew == size && CDBA < best)) {
+ if (sizeNew == 0) return(0);
+ best = CDBA;
+ size = sizeNew;
+ }
+#define CBDA 11
+ sizeNew = cuddSwapInPlace(table,x,y);
+ if (sizeNew < size || (sizeNew == size && CBDA < best)) {
+ if (sizeNew == 0) return(0);
+ best = CBDA;
+ size = sizeNew;
+ }
+#define BCDA 16
+ sizeNew = cuddSwapInPlace(table,w,x);
+ if (sizeNew < size || (sizeNew == size && BCDA < best)) {
+ if (sizeNew == 0) return(0);
+ best = BCDA;
+ size = sizeNew;
+ }
+#define BCAD 10
+ sizeNew = cuddSwapInPlace(table,y,z);
+ if (sizeNew < size || (sizeNew == size && BCAD < best)) {
+ if (sizeNew == 0) return(0);
+ best = BCAD;
+ size = sizeNew;
+ }
+#define CBAD 5
+ sizeNew = cuddSwapInPlace(table,w,x);
+ if (sizeNew < size || (sizeNew == size && CBAD < best)) {
+ if (sizeNew == 0) return(0);
+ best = CBAD;
+ size = sizeNew;
+ }
+#define CABD 3
+ sizeNew = cuddSwapInPlace(table,x,y);
+ if (sizeNew < size || (sizeNew == size && CABD < best)) {
+ if (sizeNew == 0) return(0);
+ best = CABD;
+ size = sizeNew;
+ }
+#define CADB 6
+ sizeNew = cuddSwapInPlace(table,y,z);
+ if (sizeNew < size || (sizeNew == size && CADB < best)) {
+ if (sizeNew == 0) return(0);
+ best = CADB;
+ size = sizeNew;
+ }
+#define ACDB 4
+ sizeNew = cuddSwapInPlace(table,w,x);
+ if (sizeNew < size || (sizeNew == size && ACDB < best)) {
+ if (sizeNew == 0) return(0);
+ best = ACDB;
+ size = sizeNew;
+ }
+#define ACBD 2
+ sizeNew = cuddSwapInPlace(table,y,z);
+ if (sizeNew < size || (sizeNew == size && ACBD < best)) {
+ if (sizeNew == 0) return(0);
+ best = ACBD;
+ size = sizeNew;
+ }
+
+ /* Now take the shortest route to the best permutation.
+ ** The initial permutation is ACBD.
+ */
+ switch(best) {
+ case DBCA: if (!cuddSwapInPlace(table,y,z)) return(0);
+ case BDCA: if (!cuddSwapInPlace(table,x,y)) return(0);
+ case CDBA: if (!cuddSwapInPlace(table,w,x)) return(0);
+ case ADBC: if (!cuddSwapInPlace(table,y,z)) return(0);
+ case ABDC: if (!cuddSwapInPlace(table,x,y)) return(0);
+ case ACDB: if (!cuddSwapInPlace(table,y,z)) return(0);
+ case ACBD: break;
+ case DCBA: if (!cuddSwapInPlace(table,y,z)) return(0);
+ case BCDA: if (!cuddSwapInPlace(table,x,y)) return(0);
+ case CBDA: if (!cuddSwapInPlace(table,w,x)) return(0);
+ if (!cuddSwapInPlace(table,x,y)) return(0);
+ if (!cuddSwapInPlace(table,y,z)) return(0);
+ break;
+ case DBAC: if (!cuddSwapInPlace(table,x,y)) return(0);
+ case DCAB: if (!cuddSwapInPlace(table,w,x)) return(0);
+ case DACB: if (!cuddSwapInPlace(table,y,z)) return(0);
+ case BACD: if (!cuddSwapInPlace(table,x,y)) return(0);
+ case CABD: if (!cuddSwapInPlace(table,w,x)) return(0);
+ break;
+ case DABC: if (!cuddSwapInPlace(table,y,z)) return(0);
+ case BADC: if (!cuddSwapInPlace(table,x,y)) return(0);
+ case CADB: if (!cuddSwapInPlace(table,w,x)) return(0);
+ if (!cuddSwapInPlace(table,y,z)) return(0);
+ break;
+ case BDAC: if (!cuddSwapInPlace(table,x,y)) return(0);
+ case CDAB: if (!cuddSwapInPlace(table,w,x)) return(0);
+ case ADCB: if (!cuddSwapInPlace(table,y,z)) return(0);
+ case ABCD: if (!cuddSwapInPlace(table,x,y)) return(0);
+ break;
+ case BCAD: if (!cuddSwapInPlace(table,x,y)) return(0);
+ case CBAD: if (!cuddSwapInPlace(table,w,x)) return(0);
+ if (!cuddSwapInPlace(table,x,y)) return(0);
+ break;
+ default: return(0);
+ }
+
+#ifdef DD_DEBUG
+ assert(table->keys - table->isolated == (unsigned) size);
+#endif
+
+ return(best);
+
+} /* end of ddPermuteWindow4 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders by applying a sliding window of width 4.]
+
+ Description [Reorders by applying a sliding window of width 4.
+ Tries all possible permutations to the variables in a
+ window that slides from low to high. Assumes that no dead nodes are
+ present. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddWindow4(
+ DdManager * table,
+ int low,
+ int high)
+{
+
+ int w;
+ int res;
+
+#ifdef DD_DEBUG
+ assert(low >= 0 && high < table->size);
+#endif
+
+ if (high-low < 3) return(ddWindow3(table,low,high));
+
+ for (w = low; w+2 < high; w++) {
+ res = ddPermuteWindow4(table,w);
+ if (res == 0) return(0);
+#ifdef DD_STATS
+ if (res == ABCD) {
+ (void) fprintf(table->out,"=");
+ } else {
+ (void) fprintf(table->out,"-");
+ }
+ fflush(table->out);
+#endif
+ }
+
+ return(1);
+
+} /* end of ddWindow4 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders by repeatedly applying a sliding window of width 4.]
+
+ Description [Reorders by repeatedly applying a sliding window of width
+ 4. Tries all possible permutations to the variables in a
+ window that slides from low to high. Assumes that no dead nodes are
+ present. Uses an event-driven approach to determine convergence.
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddWindowConv4(
+ DdManager * table,
+ int low,
+ int high)
+{
+ int x;
+ int res;
+ int nwin;
+ int newevent;
+ int *events;
+
+#ifdef DD_DEBUG
+ assert(low >= 0 && high < table->size);
+#endif
+
+ if (high-low < 3) return(ddWindowConv3(table,low,high));
+
+ nwin = high-low-2;
+ events = ALLOC(int,nwin);
+ if (events == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (x=0; x<nwin; x++) {
+ events[x] = 1;
+ }
+
+ do {
+ newevent = 0;
+ for (x=0; x<nwin; x++) {
+ if (events[x]) {
+ res = ddPermuteWindow4(table,x+low);
+ switch (res) {
+ case ABCD:
+ break;
+ case BACD:
+ if (x < nwin-1) events[x+1] = 1;
+ if (x > 2) events[x-3] = 1;
+ newevent = 1;
+ break;
+ case BADC:
+ if (x < nwin-3) events[x+3] = 1;
+ if (x < nwin-1) events[x+1] = 1;
+ if (x > 0) events[x-1] = 1;
+ if (x > 2) events[x-3] = 1;
+ newevent = 1;
+ break;
+ case ABDC:
+ if (x < nwin-3) events[x+3] = 1;
+ if (x > 0) events[x-1] = 1;
+ newevent = 1;
+ break;
+ case ADBC:
+ case ADCB:
+ case ACDB:
+ if (x < nwin-3) events[x+3] = 1;
+ if (x < nwin-2) events[x+2] = 1;
+ if (x > 0) events[x-1] = 1;
+ if (x > 1) events[x-2] = 1;
+ newevent = 1;
+ break;
+ case DACB:
+ case DABC:
+ case DBAC:
+ case BDAC:
+ case BDCA:
+ case DBCA:
+ case DCBA:
+ case DCAB:
+ case CDAB:
+ case CDBA:
+ case CBDA:
+ case BCDA:
+ case CADB:
+ if (x < nwin-3) events[x+3] = 1;
+ if (x < nwin-2) events[x+2] = 1;
+ if (x < nwin-1) events[x+1] = 1;
+ if (x > 0) events[x-1] = 1;
+ if (x > 1) events[x-2] = 1;
+ if (x > 2) events[x-3] = 1;
+ newevent = 1;
+ break;
+ case BCAD:
+ case CBAD:
+ case CABD:
+ if (x < nwin-2) events[x+2] = 1;
+ if (x < nwin-1) events[x+1] = 1;
+ if (x > 1) events[x-2] = 1;
+ if (x > 2) events[x-3] = 1;
+ newevent = 1;
+ break;
+ case ACBD:
+ if (x < nwin-2) events[x+2] = 1;
+ if (x > 1) events[x-2] = 1;
+ newevent = 1;
+ break;
+ default:
+ FREE(events);
+ return(0);
+ }
+ events[x] = 0;
+#ifdef DD_STATS
+ if (res == ABCD) {
+ (void) fprintf(table->out,"=");
+ } else {
+ (void) fprintf(table->out,"-");
+ }
+ fflush(table->out);
+#endif
+ }
+ }
+#ifdef DD_STATS
+ if (newevent) {
+ (void) fprintf(table->out,"|");
+ fflush(table->out);
+ }
+#endif
+ } while (newevent);
+
+ FREE(events);
+
+ return(1);
+
+} /* end of ddWindowConv4 */
+
diff --git a/src/bdd/cudd/cuddZddCount.c b/src/bdd/cudd/cuddZddCount.c
new file mode 100644
index 00000000..29cf0c14
--- /dev/null
+++ b/src/bdd/cudd/cuddZddCount.c
@@ -0,0 +1,324 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddCount.c]
+
+ PackageName [cudd]
+
+ Synopsis [Procedures to count the number of minterms of a ZDD.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_zddCount();
+ <li> Cudd_zddCountDouble();
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddZddCountStep();
+ <li> cuddZddCountDoubleStep();
+ <li> st_zdd_count_dbl_free()
+ <li> st_zdd_countfree()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Hyong-Kyoon Shin, In-Ho Moon]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddCount.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int cuddZddCountStep ARGS((DdNode *P, st_table *table, DdNode *base, DdNode *empty));
+static double cuddZddCountDoubleStep ARGS((DdNode *P, st_table *table, DdNode *base, DdNode *empty));
+static enum st_retval st_zdd_countfree ARGS((char *key, char *value, char *arg));
+static enum st_retval st_zdd_count_dbl_free ARGS((char *key, char *value, char *arg));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of minterms in a ZDD.]
+
+ Description [Returns an integer representing the number of minterms
+ in a ZDD.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddCountDouble]
+
+******************************************************************************/
+int
+Cudd_zddCount(
+ DdManager * zdd,
+ DdNode * P)
+{
+ st_table *table;
+ int res;
+ DdNode *base, *empty;
+
+ base = DD_ONE(zdd);
+ empty = DD_ZERO(zdd);
+ table = st_init_table(st_ptrcmp, st_ptrhash);
+ if (table == NULL) return(CUDD_OUT_OF_MEM);
+ res = cuddZddCountStep(P, table, base, empty);
+ if (res == CUDD_OUT_OF_MEM) {
+ zdd->errorCode = CUDD_MEMORY_OUT;
+ }
+ st_foreach(table, st_zdd_countfree, NIL(char));
+ st_free_table(table);
+
+ return(res);
+
+} /* end of Cudd_zddCount */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of minterms of a ZDD.]
+
+ Description [Counts the number of minterms of a ZDD. The result is
+ returned as a double. If the procedure runs out of memory, it
+ returns (double) CUDD_OUT_OF_MEM. This procedure is used in
+ Cudd_zddCountMinterm.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddCountMinterm Cudd_zddCount]
+
+******************************************************************************/
+double
+Cudd_zddCountDouble(
+ DdManager * zdd,
+ DdNode * P)
+{
+ st_table *table;
+ double res;
+ DdNode *base, *empty;
+
+ base = DD_ONE(zdd);
+ empty = DD_ZERO(zdd);
+ table = st_init_table(st_ptrcmp, st_ptrhash);
+ if (table == NULL) return((double)CUDD_OUT_OF_MEM);
+ res = cuddZddCountDoubleStep(P, table, base, empty);
+ if (res == (double)CUDD_OUT_OF_MEM) {
+ zdd->errorCode = CUDD_MEMORY_OUT;
+ }
+ st_foreach(table, st_zdd_count_dbl_free, NIL(char));
+ st_free_table(table);
+
+ return(res);
+
+} /* end of Cudd_zddCountDouble */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddCount.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddZddCountStep(
+ DdNode * P,
+ st_table * table,
+ DdNode * base,
+ DdNode * empty)
+{
+ int res;
+ int *dummy;
+
+ if (P == empty)
+ return(0);
+ if (P == base)
+ return(1);
+
+ /* Check cache. */
+ if (st_lookup(table, (char *)P, (char **)(&dummy))) {
+ res = *dummy;
+ return(res);
+ }
+
+ res = cuddZddCountStep(cuddE(P), table, base, empty) +
+ cuddZddCountStep(cuddT(P), table, base, empty);
+
+ dummy = ALLOC(int, 1);
+ if (dummy == NULL) {
+ return(CUDD_OUT_OF_MEM);
+ }
+ *dummy = res;
+ if (st_insert(table, (char *)P, (char *)dummy) == ST_OUT_OF_MEM) {
+ FREE(dummy);
+ return(CUDD_OUT_OF_MEM);
+ }
+
+ return(res);
+
+} /* end of cuddZddCountStep */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddCountDouble.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static double
+cuddZddCountDoubleStep(
+ DdNode * P,
+ st_table * table,
+ DdNode * base,
+ DdNode * empty)
+{
+ double res;
+ double *dummy;
+
+ if (P == empty)
+ return((double)0.0);
+ if (P == base)
+ return((double)1.0);
+
+ /* Check cache */
+ if (st_lookup(table, (char *)P, (char **)(&dummy))) {
+ res = *dummy;
+ return(res);
+ }
+
+ res = cuddZddCountDoubleStep(cuddE(P), table, base, empty) +
+ cuddZddCountDoubleStep(cuddT(P), table, base, empty);
+
+ dummy = ALLOC(double, 1);
+ if (dummy == NULL) {
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ *dummy = res;
+ if (st_insert(table, (char *)P, (char *)dummy) == ST_OUT_OF_MEM) {
+ FREE(dummy);
+ return((double)CUDD_OUT_OF_MEM);
+ }
+
+ return(res);
+
+} /* end of cuddZddCountDoubleStep */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees the memory associated with the computed table of
+ Cudd_zddCount.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static enum st_retval
+st_zdd_countfree(
+ char * key,
+ char * value,
+ char * arg)
+{
+ int *d;
+
+ d = (int *)value;
+ FREE(d);
+ return(ST_CONTINUE);
+
+} /* end of st_zdd_countfree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees the memory associated with the computed table of
+ Cudd_zddCountDouble.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static enum st_retval
+st_zdd_count_dbl_free(
+ char * key,
+ char * value,
+ char * arg)
+{
+ double *d;
+
+ d = (double *)value;
+ FREE(d);
+ return(ST_CONTINUE);
+
+} /* end of st_zdd_count_dbl_free */
diff --git a/src/bdd/cudd/cuddZddFuncs.c b/src/bdd/cudd/cuddZddFuncs.c
new file mode 100644
index 00000000..f938e1de
--- /dev/null
+++ b/src/bdd/cudd/cuddZddFuncs.c
@@ -0,0 +1,1603 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddFuncs.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions to manipulate covers represented as ZDDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_zddProduct();
+ <li> Cudd_zddUnateProduct();
+ <li> Cudd_zddWeakDiv();
+ <li> Cudd_zddWeakDivF();
+ <li> Cudd_zddDivide();
+ <li> Cudd_zddDivideF();
+ <li> Cudd_zddComplement();
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddZddProduct();
+ <li> cuddZddUnateProduct();
+ <li> cuddZddWeakDiv();
+ <li> cuddZddWeakDivF();
+ <li> cuddZddDivide();
+ <li> cuddZddDivideF();
+ <li> cuddZddGetCofactors3()
+ <li> cuddZddGetCofactors2()
+ <li> cuddZddComplement();
+ <li> cuddZddGetPosVarIndex();
+ <li> cuddZddGetNegVarIndex();
+ <li> cuddZddGetPosVarLevel();
+ <li> cuddZddGetNegVarLevel();
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [In-Ho Moon]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddFuncs.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the product of two covers represented by ZDDs.]
+
+ Description [Computes the product of two covers represented by
+ ZDDs. The result is also a ZDD. Returns a pointer to the result if
+ successful; NULL otherwise. The covers on which Cudd_zddProduct
+ operates use two ZDD variables for each function variable (one ZDD
+ variable for each literal of the variable). Those two ZDD variables
+ should be adjacent in the order.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddUnateProduct]
+
+******************************************************************************/
+DdNode *
+Cudd_zddProduct(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddProduct(dd, f, g);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_zddProduct */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the product of two unate covers.]
+
+ Description [Computes the product of two unate covers represented as
+ ZDDs. Unate covers use one ZDD variable for each BDD
+ variable. Returns a pointer to the result if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddProduct]
+
+******************************************************************************/
+DdNode *
+Cudd_zddUnateProduct(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddUnateProduct(dd, f, g);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_zddUnateProduct */
+
+
+/**Function********************************************************************
+
+ Synopsis [Applies weak division to two covers.]
+
+ Description [Applies weak division to two ZDDs representing two
+ covers. Returns a pointer to the ZDD representing the result if
+ successful; NULL otherwise. The result of weak division depends on
+ the variable order. The covers on which Cudd_zddWeakDiv operates use
+ two ZDD variables for each function variable (one ZDD variable for
+ each literal of the variable). Those two ZDD variables should be
+ adjacent in the order.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddDivide]
+
+******************************************************************************/
+DdNode *
+Cudd_zddWeakDiv(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddWeakDiv(dd, f, g);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_zddWeakDiv */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the quotient of two unate covers.]
+
+ Description [Computes the quotient of two unate covers represented
+ by ZDDs. Unate covers use one ZDD variable for each BDD
+ variable. Returns a pointer to the resulting ZDD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddWeakDiv]
+
+******************************************************************************/
+DdNode *
+Cudd_zddDivide(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddDivide(dd, f, g);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_zddDivide */
+
+
+/**Function********************************************************************
+
+ Synopsis [Modified version of Cudd_zddWeakDiv.]
+
+ Description [Modified version of Cudd_zddWeakDiv. This function may
+ disappear in future releases.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddWeakDiv]
+
+******************************************************************************/
+DdNode *
+Cudd_zddWeakDivF(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddWeakDivF(dd, f, g);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_zddWeakDivF */
+
+
+/**Function********************************************************************
+
+ Synopsis [Modified version of Cudd_zddDivide.]
+
+ Description [Modified version of Cudd_zddDivide. This function may
+ disappear in future releases.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_zddDivideF(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddDivideF(dd, f, g);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_zddDivideF */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes a complement cover for a ZDD node.]
+
+ Description [Computes a complement cover for a ZDD node. For lack of a
+ better method, we first extract the function BDD from the ZDD cover,
+ then make the complement of the ZDD cover from the complement of the
+ BDD node by using ISOP. Returns a pointer to the resulting cover if
+ successful; NULL otherwise. The result depends on current variable
+ order.]
+
+ SideEffects [The result depends on current variable order.]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_zddComplement(
+ DdManager *dd,
+ DdNode *node)
+{
+ DdNode *b, *isop, *zdd_I;
+
+ /* Check cache */
+ zdd_I = cuddCacheLookup1Zdd(dd, cuddZddComplement, node);
+ if (zdd_I)
+ return(zdd_I);
+
+ b = Cudd_MakeBddFromZddCover(dd, node);
+ if (!b)
+ return(NULL);
+ Cudd_Ref(b);
+ isop = Cudd_zddIsop(dd, Cudd_Not(b), Cudd_Not(b), &zdd_I);
+ if (!isop) {
+ Cudd_RecursiveDeref(dd, b);
+ return(NULL);
+ }
+ Cudd_Ref(isop);
+ Cudd_Ref(zdd_I);
+ Cudd_RecursiveDeref(dd, b);
+ Cudd_RecursiveDeref(dd, isop);
+
+ cuddCacheInsert1(dd, cuddZddComplement, node, zdd_I);
+ Cudd_Deref(zdd_I);
+ return(zdd_I);
+} /* end of Cudd_zddComplement */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddProduct.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddProduct]
+
+******************************************************************************/
+DdNode *
+cuddZddProduct(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ int v, top_f, top_g;
+ DdNode *tmp, *term1, *term2, *term3;
+ DdNode *f0, *f1, *fd, *g0, *g1, *gd;
+ DdNode *R0, *R1, *Rd, *N0, *N1;
+ DdNode *r;
+ DdNode *one = DD_ONE(dd);
+ DdNode *zero = DD_ZERO(dd);
+ int flag;
+ int pv, nv;
+
+ statLine(dd);
+ if (f == zero || g == zero)
+ return(zero);
+ if (f == one)
+ return(g);
+ if (g == one)
+ return(f);
+
+ top_f = dd->permZ[f->index];
+ top_g = dd->permZ[g->index];
+
+ if (top_f > top_g)
+ return(cuddZddProduct(dd, g, f));
+
+ /* Check cache */
+ r = cuddCacheLookup2Zdd(dd, cuddZddProduct, f, g);
+ if (r)
+ return(r);
+
+ v = f->index; /* either yi or zi */
+ flag = cuddZddGetCofactors3(dd, f, v, &f1, &f0, &fd);
+ if (flag == 1)
+ return(NULL);
+ Cudd_Ref(f1);
+ Cudd_Ref(f0);
+ Cudd_Ref(fd);
+ flag = cuddZddGetCofactors3(dd, g, v, &g1, &g0, &gd);
+ if (flag == 1) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ return(NULL);
+ }
+ Cudd_Ref(g1);
+ Cudd_Ref(g0);
+ Cudd_Ref(gd);
+ pv = cuddZddGetPosVarIndex(dd, v);
+ nv = cuddZddGetNegVarIndex(dd, v);
+
+ Rd = cuddZddProduct(dd, fd, gd);
+ if (Rd == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ return(NULL);
+ }
+ Cudd_Ref(Rd);
+
+ term1 = cuddZddProduct(dd, f0, g0);
+ if (term1 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ Cudd_RecursiveDerefZdd(dd, Rd);
+ return(NULL);
+ }
+ Cudd_Ref(term1);
+ term2 = cuddZddProduct(dd, f0, gd);
+ if (term2 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ Cudd_RecursiveDerefZdd(dd, Rd);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ return(NULL);
+ }
+ Cudd_Ref(term2);
+ term3 = cuddZddProduct(dd, fd, g0);
+ if (term3 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ Cudd_RecursiveDerefZdd(dd, Rd);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term2);
+ return(NULL);
+ }
+ Cudd_Ref(term3);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ tmp = cuddZddUnion(dd, term1, term2);
+ if (tmp == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ Cudd_RecursiveDerefZdd(dd, Rd);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term2);
+ Cudd_RecursiveDerefZdd(dd, term3);
+ return(NULL);
+ }
+ Cudd_Ref(tmp);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term2);
+ R0 = cuddZddUnion(dd, tmp, term3);
+ if (R0 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ Cudd_RecursiveDerefZdd(dd, Rd);
+ Cudd_RecursiveDerefZdd(dd, term3);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ return(NULL);
+ }
+ Cudd_Ref(R0);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ Cudd_RecursiveDerefZdd(dd, term3);
+ N0 = cuddZddGetNode(dd, nv, R0, Rd); /* nv = zi */
+ if (N0 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ Cudd_RecursiveDerefZdd(dd, Rd);
+ Cudd_RecursiveDerefZdd(dd, R0);
+ return(NULL);
+ }
+ Cudd_Ref(N0);
+ Cudd_RecursiveDerefZdd(dd, R0);
+ Cudd_RecursiveDerefZdd(dd, Rd);
+
+ term1 = cuddZddProduct(dd, f1, g1);
+ if (term1 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ Cudd_RecursiveDerefZdd(dd, N0);
+ return(NULL);
+ }
+ Cudd_Ref(term1);
+ term2 = cuddZddProduct(dd, f1, gd);
+ if (term2 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ Cudd_RecursiveDerefZdd(dd, N0);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ return(NULL);
+ }
+ Cudd_Ref(term2);
+ term3 = cuddZddProduct(dd, fd, g1);
+ if (term3 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ Cudd_RecursiveDerefZdd(dd, N0);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term2);
+ return(NULL);
+ }
+ Cudd_Ref(term3);
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ tmp = cuddZddUnion(dd, term1, term2);
+ if (tmp == NULL) {
+ Cudd_RecursiveDerefZdd(dd, N0);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term2);
+ Cudd_RecursiveDerefZdd(dd, term3);
+ return(NULL);
+ }
+ Cudd_Ref(tmp);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term2);
+ R1 = cuddZddUnion(dd, tmp, term3);
+ if (R1 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, N0);
+ Cudd_RecursiveDerefZdd(dd, term3);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ return(NULL);
+ }
+ Cudd_Ref(R1);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ Cudd_RecursiveDerefZdd(dd, term3);
+ N1 = cuddZddGetNode(dd, pv, R1, N0); /* pv = yi */
+ if (N1 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, N0);
+ Cudd_RecursiveDerefZdd(dd, R1);
+ return(NULL);
+ }
+ Cudd_Ref(N1);
+ Cudd_RecursiveDerefZdd(dd, R1);
+ Cudd_RecursiveDerefZdd(dd, N0);
+
+ cuddCacheInsert2(dd, cuddZddProduct, f, g, N1);
+ Cudd_Deref(N1);
+ return(N1);
+
+} /* end of cuddZddProduct */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddUnateProduct.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddUnateProduct]
+
+******************************************************************************/
+DdNode *
+cuddZddUnateProduct(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ int v, top_f, top_g;
+ DdNode *term1, *term2, *term3, *term4;
+ DdNode *sum1, *sum2;
+ DdNode *f0, *f1, *g0, *g1;
+ DdNode *r;
+ DdNode *one = DD_ONE(dd);
+ DdNode *zero = DD_ZERO(dd);
+ int flag;
+
+ statLine(dd);
+ if (f == zero || g == zero)
+ return(zero);
+ if (f == one)
+ return(g);
+ if (g == one)
+ return(f);
+
+ top_f = dd->permZ[f->index];
+ top_g = dd->permZ[g->index];
+
+ if (top_f > top_g)
+ return(cuddZddUnateProduct(dd, g, f));
+
+ /* Check cache */
+ r = cuddCacheLookup2Zdd(dd, cuddZddUnateProduct, f, g);
+ if (r)
+ return(r);
+
+ v = f->index; /* either yi or zi */
+ flag = cuddZddGetCofactors2(dd, f, v, &f1, &f0);
+ if (flag == 1)
+ return(NULL);
+ Cudd_Ref(f1);
+ Cudd_Ref(f0);
+ flag = cuddZddGetCofactors2(dd, g, v, &g1, &g0);
+ if (flag == 1) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ return(NULL);
+ }
+ Cudd_Ref(g1);
+ Cudd_Ref(g0);
+
+ term1 = cuddZddUnateProduct(dd, f1, g1);
+ if (term1 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ return(NULL);
+ }
+ Cudd_Ref(term1);
+ term2 = cuddZddUnateProduct(dd, f1, g0);
+ if (term2 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ return(NULL);
+ }
+ Cudd_Ref(term2);
+ term3 = cuddZddUnateProduct(dd, f0, g1);
+ if (term3 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term2);
+ return(NULL);
+ }
+ Cudd_Ref(term3);
+ term4 = cuddZddUnateProduct(dd, f0, g0);
+ if (term4 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term2);
+ Cudd_RecursiveDerefZdd(dd, term3);
+ return(NULL);
+ }
+ Cudd_Ref(term4);
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ sum1 = cuddZddUnion(dd, term1, term2);
+ if (sum1 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term2);
+ Cudd_RecursiveDerefZdd(dd, term3);
+ Cudd_RecursiveDerefZdd(dd, term4);
+ return(NULL);
+ }
+ Cudd_Ref(sum1);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term2);
+ sum2 = cuddZddUnion(dd, sum1, term3);
+ if (sum2 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, term3);
+ Cudd_RecursiveDerefZdd(dd, term4);
+ Cudd_RecursiveDerefZdd(dd, sum1);
+ return(NULL);
+ }
+ Cudd_Ref(sum2);
+ Cudd_RecursiveDerefZdd(dd, sum1);
+ Cudd_RecursiveDerefZdd(dd, term3);
+ r = cuddZddGetNode(dd, v, sum2, term4);
+ if (r == NULL) {
+ Cudd_RecursiveDerefZdd(dd, term4);
+ Cudd_RecursiveDerefZdd(dd, sum2);
+ return(NULL);
+ }
+ Cudd_Ref(r);
+ Cudd_RecursiveDerefZdd(dd, sum2);
+ Cudd_RecursiveDerefZdd(dd, term4);
+
+ cuddCacheInsert2(dd, cuddZddUnateProduct, f, g, r);
+ Cudd_Deref(r);
+ return(r);
+
+} /* end of cuddZddUnateProduct */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddWeakDiv.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddWeakDiv]
+
+******************************************************************************/
+DdNode *
+cuddZddWeakDiv(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ int v;
+ DdNode *one = DD_ONE(dd);
+ DdNode *zero = DD_ZERO(dd);
+ DdNode *f0, *f1, *fd, *g0, *g1, *gd;
+ DdNode *q, *tmp;
+ DdNode *r;
+ int flag;
+
+ statLine(dd);
+ if (g == one)
+ return(f);
+ if (f == zero || f == one)
+ return(zero);
+ if (f == g)
+ return(one);
+
+ /* Check cache. */
+ r = cuddCacheLookup2Zdd(dd, cuddZddWeakDiv, f, g);
+ if (r)
+ return(r);
+
+ v = g->index;
+
+ flag = cuddZddGetCofactors3(dd, f, v, &f1, &f0, &fd);
+ if (flag == 1)
+ return(NULL);
+ Cudd_Ref(f1);
+ Cudd_Ref(f0);
+ Cudd_Ref(fd);
+ flag = cuddZddGetCofactors3(dd, g, v, &g1, &g0, &gd);
+ if (flag == 1) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ return(NULL);
+ }
+ Cudd_Ref(g1);
+ Cudd_Ref(g0);
+ Cudd_Ref(gd);
+
+ q = g;
+
+ if (g0 != zero) {
+ q = cuddZddWeakDiv(dd, f0, g0);
+ if (q == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ return(NULL);
+ }
+ Cudd_Ref(q);
+ }
+ else
+ Cudd_Ref(q);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g0);
+
+ if (q == zero) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ cuddCacheInsert2(dd, cuddZddWeakDiv, f, g, zero);
+ Cudd_Deref(q);
+ return(zero);
+ }
+
+ if (g1 != zero) {
+ Cudd_RecursiveDerefZdd(dd, q);
+ tmp = cuddZddWeakDiv(dd, f1, g1);
+ if (tmp == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ return(NULL);
+ }
+ Cudd_Ref(tmp);
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ if (q == g)
+ q = tmp;
+ else {
+ q = cuddZddIntersect(dd, q, tmp);
+ if (q == NULL) {
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ return(NULL);
+ }
+ Cudd_Ref(q);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ }
+ }
+ else {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ }
+
+ if (q == zero) {
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ cuddCacheInsert2(dd, cuddZddWeakDiv, f, g, zero);
+ Cudd_Deref(q);
+ return(zero);
+ }
+
+ if (gd != zero) {
+ Cudd_RecursiveDerefZdd(dd, q);
+ tmp = cuddZddWeakDiv(dd, fd, gd);
+ if (tmp == NULL) {
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ return(NULL);
+ }
+ Cudd_Ref(tmp);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ if (q == g)
+ q = tmp;
+ else {
+ q = cuddZddIntersect(dd, q, tmp);
+ if (q == NULL) {
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ return(NULL);
+ }
+ Cudd_Ref(q);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ }
+ }
+ else {
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ }
+
+ cuddCacheInsert2(dd, cuddZddWeakDiv, f, g, q);
+ Cudd_Deref(q);
+ return(q);
+
+} /* end of cuddZddWeakDiv */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddWeakDivF.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddWeakDivF]
+
+******************************************************************************/
+DdNode *
+cuddZddWeakDivF(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ int v, top_f, top_g, vf, vg;
+ DdNode *one = DD_ONE(dd);
+ DdNode *zero = DD_ZERO(dd);
+ DdNode *f0, *f1, *fd, *g0, *g1, *gd;
+ DdNode *q, *tmp;
+ DdNode *r;
+ DdNode *term1, *term0, *termd;
+ int flag;
+ int pv, nv;
+
+ statLine(dd);
+ if (g == one)
+ return(f);
+ if (f == zero || f == one)
+ return(zero);
+ if (f == g)
+ return(one);
+
+ /* Check cache. */
+ r = cuddCacheLookup2Zdd(dd, cuddZddWeakDivF, f, g);
+ if (r)
+ return(r);
+
+ top_f = dd->permZ[f->index];
+ top_g = dd->permZ[g->index];
+ vf = top_f >> 1;
+ vg = top_g >> 1;
+ v = ddMin(top_f, top_g);
+
+ if (v == top_f && vf < vg) {
+ v = f->index;
+ flag = cuddZddGetCofactors3(dd, f, v, &f1, &f0, &fd);
+ if (flag == 1)
+ return(NULL);
+ Cudd_Ref(f1);
+ Cudd_Ref(f0);
+ Cudd_Ref(fd);
+
+ pv = cuddZddGetPosVarIndex(dd, v);
+ nv = cuddZddGetNegVarIndex(dd, v);
+
+ term1 = cuddZddWeakDivF(dd, f1, g);
+ if (term1 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ return(NULL);
+ }
+ Cudd_Ref(term1);
+ Cudd_RecursiveDerefZdd(dd, f1);
+ term0 = cuddZddWeakDivF(dd, f0, g);
+ if (term0 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ return(NULL);
+ }
+ Cudd_Ref(term0);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ termd = cuddZddWeakDivF(dd, fd, g);
+ if (termd == NULL) {
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term0);
+ return(NULL);
+ }
+ Cudd_Ref(termd);
+ Cudd_RecursiveDerefZdd(dd, fd);
+
+ tmp = cuddZddGetNode(dd, nv, term0, termd); /* nv = zi */
+ if (tmp == NULL) {
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term0);
+ Cudd_RecursiveDerefZdd(dd, termd);
+ return(NULL);
+ }
+ Cudd_Ref(tmp);
+ Cudd_RecursiveDerefZdd(dd, term0);
+ Cudd_RecursiveDerefZdd(dd, termd);
+ q = cuddZddGetNode(dd, pv, term1, tmp); /* pv = yi */
+ if (q == NULL) {
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ return(NULL);
+ }
+ Cudd_Ref(q);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+
+ cuddCacheInsert2(dd, cuddZddWeakDivF, f, g, q);
+ Cudd_Deref(q);
+ return(q);
+ }
+
+ if (v == top_f)
+ v = f->index;
+ else
+ v = g->index;
+
+ flag = cuddZddGetCofactors3(dd, f, v, &f1, &f0, &fd);
+ if (flag == 1)
+ return(NULL);
+ Cudd_Ref(f1);
+ Cudd_Ref(f0);
+ Cudd_Ref(fd);
+ flag = cuddZddGetCofactors3(dd, g, v, &g1, &g0, &gd);
+ if (flag == 1) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ return(NULL);
+ }
+ Cudd_Ref(g1);
+ Cudd_Ref(g0);
+ Cudd_Ref(gd);
+
+ q = g;
+
+ if (g0 != zero) {
+ q = cuddZddWeakDivF(dd, f0, g0);
+ if (q == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ return(NULL);
+ }
+ Cudd_Ref(q);
+ }
+ else
+ Cudd_Ref(q);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g0);
+
+ if (q == zero) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ cuddCacheInsert2(dd, cuddZddWeakDivF, f, g, zero);
+ Cudd_Deref(q);
+ return(zero);
+ }
+
+ if (g1 != zero) {
+ Cudd_RecursiveDerefZdd(dd, q);
+ tmp = cuddZddWeakDivF(dd, f1, g1);
+ if (tmp == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ return(NULL);
+ }
+ Cudd_Ref(tmp);
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ if (q == g)
+ q = tmp;
+ else {
+ q = cuddZddIntersect(dd, q, tmp);
+ if (q == NULL) {
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ return(NULL);
+ }
+ Cudd_Ref(q);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ }
+ }
+ else {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ }
+
+ if (q == zero) {
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ cuddCacheInsert2(dd, cuddZddWeakDivF, f, g, zero);
+ Cudd_Deref(q);
+ return(zero);
+ }
+
+ if (gd != zero) {
+ Cudd_RecursiveDerefZdd(dd, q);
+ tmp = cuddZddWeakDivF(dd, fd, gd);
+ if (tmp == NULL) {
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ return(NULL);
+ }
+ Cudd_Ref(tmp);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ if (q == g)
+ q = tmp;
+ else {
+ q = cuddZddIntersect(dd, q, tmp);
+ if (q == NULL) {
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ return(NULL);
+ }
+ Cudd_Ref(q);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ }
+ }
+ else {
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ }
+
+ cuddCacheInsert2(dd, cuddZddWeakDivF, f, g, q);
+ Cudd_Deref(q);
+ return(q);
+
+} /* end of cuddZddWeakDivF */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddDivide.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddDivide]
+
+******************************************************************************/
+DdNode *
+cuddZddDivide(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ int v;
+ DdNode *one = DD_ONE(dd);
+ DdNode *zero = DD_ZERO(dd);
+ DdNode *f0, *f1, *g0, *g1;
+ DdNode *q, *r, *tmp;
+ int flag;
+
+ statLine(dd);
+ if (g == one)
+ return(f);
+ if (f == zero || f == one)
+ return(zero);
+ if (f == g)
+ return(one);
+
+ /* Check cache. */
+ r = cuddCacheLookup2Zdd(dd, cuddZddDivide, f, g);
+ if (r)
+ return(r);
+
+ v = g->index;
+
+ flag = cuddZddGetCofactors2(dd, f, v, &f1, &f0);
+ if (flag == 1)
+ return(NULL);
+ Cudd_Ref(f1);
+ Cudd_Ref(f0);
+ flag = cuddZddGetCofactors2(dd, g, v, &g1, &g0); /* g1 != zero */
+ if (flag == 1) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ return(NULL);
+ }
+ Cudd_Ref(g1);
+ Cudd_Ref(g0);
+
+ r = cuddZddDivide(dd, f1, g1);
+ if (r == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ return(NULL);
+ }
+ Cudd_Ref(r);
+
+ if (r != zero && g0 != zero) {
+ tmp = r;
+ q = cuddZddDivide(dd, f0, g0);
+ if (q == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ return(NULL);
+ }
+ Cudd_Ref(q);
+ r = cuddZddIntersect(dd, r, q);
+ if (r == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ Cudd_RecursiveDerefZdd(dd, q);
+ return(NULL);
+ }
+ Cudd_Ref(r);
+ Cudd_RecursiveDerefZdd(dd, q);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ }
+
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+
+ cuddCacheInsert2(dd, cuddZddDivide, f, g, r);
+ Cudd_Deref(r);
+ return(r);
+
+} /* end of cuddZddDivide */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddDivideF.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddDivideF]
+
+******************************************************************************/
+DdNode *
+cuddZddDivideF(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ int v;
+ DdNode *one = DD_ONE(dd);
+ DdNode *zero = DD_ZERO(dd);
+ DdNode *f0, *f1, *g0, *g1;
+ DdNode *q, *r, *tmp;
+ int flag;
+
+ statLine(dd);
+ if (g == one)
+ return(f);
+ if (f == zero || f == one)
+ return(zero);
+ if (f == g)
+ return(one);
+
+ /* Check cache. */
+ r = cuddCacheLookup2Zdd(dd, cuddZddDivideF, f, g);
+ if (r)
+ return(r);
+
+ v = g->index;
+
+ flag = cuddZddGetCofactors2(dd, f, v, &f1, &f0);
+ if (flag == 1)
+ return(NULL);
+ Cudd_Ref(f1);
+ Cudd_Ref(f0);
+ flag = cuddZddGetCofactors2(dd, g, v, &g1, &g0); /* g1 != zero */
+ if (flag == 1) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ return(NULL);
+ }
+ Cudd_Ref(g1);
+ Cudd_Ref(g0);
+
+ r = cuddZddDivideF(dd, f1, g1);
+ if (r == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ return(NULL);
+ }
+ Cudd_Ref(r);
+
+ if (r != zero && g0 != zero) {
+ tmp = r;
+ q = cuddZddDivideF(dd, f0, g0);
+ if (q == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ return(NULL);
+ }
+ Cudd_Ref(q);
+ r = cuddZddIntersect(dd, r, q);
+ if (r == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ Cudd_RecursiveDerefZdd(dd, q);
+ return(NULL);
+ }
+ Cudd_Ref(r);
+ Cudd_RecursiveDerefZdd(dd, q);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ }
+
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+
+ cuddCacheInsert2(dd, cuddZddDivideF, f, g, r);
+ Cudd_Deref(r);
+ return(r);
+
+} /* end of cuddZddDivideF */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the three-way decomposition of f w.r.t. v.]
+
+ Description [Computes the three-way decomposition of function f (represented
+ by a ZDD) wit respect to variable v.]
+
+ SideEffects [The results are returned in f1, f0, and fd.]
+
+ SeeAlso [cuddZddGetCofactors2]
+
+******************************************************************************/
+int
+cuddZddGetCofactors3(
+ DdManager * dd,
+ DdNode * f,
+ int v,
+ DdNode ** f1,
+ DdNode ** f0,
+ DdNode ** fd)
+{
+ DdNode *pc, *nc;
+ DdNode *zero = DD_ZERO(dd);
+ int top, hv, ht, pv, nv;
+ int level;
+
+ top = dd->permZ[f->index];
+ level = dd->permZ[v];
+ hv = level >> 1;
+ ht = top >> 1;
+
+ if (hv < ht) {
+ *f1 = zero;
+ *f0 = zero;
+ *fd = f;
+ }
+ else {
+ pv = cuddZddGetPosVarIndex(dd, v);
+ nv = cuddZddGetNegVarIndex(dd, v);
+
+ /* not to create intermediate ZDD node */
+ if (cuddZddGetPosVarLevel(dd, v) < cuddZddGetNegVarLevel(dd, v)) {
+ pc = cuddZddSubset1(dd, f, pv);
+ if (pc == NULL)
+ return(1);
+ Cudd_Ref(pc);
+ nc = cuddZddSubset0(dd, f, pv);
+ if (nc == NULL) {
+ Cudd_RecursiveDerefZdd(dd, pc);
+ return(1);
+ }
+ Cudd_Ref(nc);
+
+ *f1 = cuddZddSubset0(dd, pc, nv);
+ if (*f1 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, pc);
+ Cudd_RecursiveDerefZdd(dd, nc);
+ return(1);
+ }
+ Cudd_Ref(*f1);
+ *f0 = cuddZddSubset1(dd, nc, nv);
+ if (*f0 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, pc);
+ Cudd_RecursiveDerefZdd(dd, nc);
+ Cudd_RecursiveDerefZdd(dd, *f1);
+ return(1);
+ }
+ Cudd_Ref(*f0);
+
+ *fd = cuddZddSubset0(dd, nc, nv);
+ if (*fd == NULL) {
+ Cudd_RecursiveDerefZdd(dd, pc);
+ Cudd_RecursiveDerefZdd(dd, nc);
+ Cudd_RecursiveDerefZdd(dd, *f1);
+ Cudd_RecursiveDerefZdd(dd, *f0);
+ return(1);
+ }
+ Cudd_Ref(*fd);
+ } else {
+ pc = cuddZddSubset1(dd, f, nv);
+ if (pc == NULL)
+ return(1);
+ Cudd_Ref(pc);
+ nc = cuddZddSubset0(dd, f, nv);
+ if (nc == NULL) {
+ Cudd_RecursiveDerefZdd(dd, pc);
+ return(1);
+ }
+ Cudd_Ref(nc);
+
+ *f0 = cuddZddSubset0(dd, pc, pv);
+ if (*f0 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, pc);
+ Cudd_RecursiveDerefZdd(dd, nc);
+ return(1);
+ }
+ Cudd_Ref(*f0);
+ *f1 = cuddZddSubset1(dd, nc, pv);
+ if (*f1 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, pc);
+ Cudd_RecursiveDerefZdd(dd, nc);
+ Cudd_RecursiveDerefZdd(dd, *f1);
+ return(1);
+ }
+ Cudd_Ref(*f1);
+
+ *fd = cuddZddSubset0(dd, nc, pv);
+ if (*fd == NULL) {
+ Cudd_RecursiveDerefZdd(dd, pc);
+ Cudd_RecursiveDerefZdd(dd, nc);
+ Cudd_RecursiveDerefZdd(dd, *f1);
+ Cudd_RecursiveDerefZdd(dd, *f0);
+ return(1);
+ }
+ Cudd_Ref(*fd);
+ }
+
+ Cudd_RecursiveDerefZdd(dd, pc);
+ Cudd_RecursiveDerefZdd(dd, nc);
+ Cudd_Deref(*f1);
+ Cudd_Deref(*f0);
+ Cudd_Deref(*fd);
+ }
+ return(0);
+
+} /* end of cuddZddGetCofactors3 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the two-way decomposition of f w.r.t. v.]
+
+ Description []
+
+ SideEffects [The results are returned in f1 and f0.]
+
+ SeeAlso [cuddZddGetCofactors3]
+
+******************************************************************************/
+int
+cuddZddGetCofactors2(
+ DdManager * dd,
+ DdNode * f,
+ int v,
+ DdNode ** f1,
+ DdNode ** f0)
+{
+ *f1 = cuddZddSubset1(dd, f, v);
+ if (*f1 == NULL)
+ return(1);
+ *f0 = cuddZddSubset0(dd, f, v);
+ if (*f0 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, *f1);
+ return(1);
+ }
+ return(0);
+
+} /* end of cuddZddGetCofactors2 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes a complement of a ZDD node.]
+
+ Description [Computes the complement of a ZDD node. So far, since we
+ couldn't find a direct way to get the complement of a ZDD cover, we first
+ convert a ZDD cover to a BDD, then make the complement of the ZDD cover
+ from the complement of the BDD node by using ISOP.]
+
+ SideEffects [The result depends on current variable order.]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddZddComplement(
+ DdManager * dd,
+ DdNode *node)
+{
+ DdNode *b, *isop, *zdd_I;
+
+ /* Check cache */
+ zdd_I = cuddCacheLookup1Zdd(dd, cuddZddComplement, node);
+ if (zdd_I)
+ return(zdd_I);
+
+ b = cuddMakeBddFromZddCover(dd, node);
+ if (!b)
+ return(NULL);
+ cuddRef(b);
+ isop = cuddZddIsop(dd, Cudd_Not(b), Cudd_Not(b), &zdd_I);
+ if (!isop) {
+ Cudd_RecursiveDeref(dd, b);
+ return(NULL);
+ }
+ cuddRef(isop);
+ cuddRef(zdd_I);
+ Cudd_RecursiveDeref(dd, b);
+ Cudd_RecursiveDeref(dd, isop);
+
+ cuddCacheInsert1(dd, cuddZddComplement, node, zdd_I);
+ cuddDeref(zdd_I);
+ return(zdd_I);
+} /* end of cuddZddComplement */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the index of positive ZDD variable.]
+
+ Description [Returns the index of positive ZDD variable.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddGetPosVarIndex(
+ DdManager * dd,
+ int index)
+{
+ int pv = (index >> 1) << 1;
+ return(pv);
+} /* end of cuddZddGetPosVarIndex */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the index of negative ZDD variable.]
+
+ Description [Returns the index of negative ZDD variable.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddGetNegVarIndex(
+ DdManager * dd,
+ int index)
+{
+ int nv = index | 0x1;
+ return(nv);
+} /* end of cuddZddGetPosVarIndex */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the level of positive ZDD variable.]
+
+ Description [Returns the level of positive ZDD variable.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddGetPosVarLevel(
+ DdManager * dd,
+ int index)
+{
+ int pv = cuddZddGetPosVarIndex(dd, index);
+ return(dd->permZ[pv]);
+} /* end of cuddZddGetPosVarLevel */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the level of negative ZDD variable.]
+
+ Description [Returns the level of negative ZDD variable.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddGetNegVarLevel(
+ DdManager * dd,
+ int index)
+{
+ int nv = cuddZddGetNegVarIndex(dd, index);
+ return(dd->permZ[nv]);
+} /* end of cuddZddGetNegVarLevel */
diff --git a/src/bdd/cudd/cuddZddGroup.c b/src/bdd/cudd/cuddZddGroup.c
new file mode 100644
index 00000000..35f28881
--- /dev/null
+++ b/src/bdd/cudd/cuddZddGroup.c
@@ -0,0 +1,1317 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddGroup.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for ZDD group sifting.]
+
+ Description [External procedures included in this file:
+ <ul>
+ <li> Cudd_MakeZddTreeNode()
+ </ul>
+ Internal procedures included in this file:
+ <ul>
+ <li> cuddZddTreeSifting()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> zddTreeSiftingAux()
+ <li> zddCountInternalMtrNodes()
+ <li> zddReorderChildren()
+ <li> zddFindNodeHiLo()
+ <li> zddUniqueCompareGroup()
+ <li> zddGroupSifting()
+ <li> zddGroupSiftingAux()
+ <li> zddGroupSiftingUp()
+ <li> zddGroupSiftingDown()
+ <li> zddGroupMove()
+ <li> zddGroupMoveBackward()
+ <li> zddGroupSiftingBackward()
+ <li> zddMergeGroups()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddGroup.c,v 1.1.1.1 2003/02/24 22:23:54 wjiang Exp $";
+#endif
+
+static int *entry;
+extern int zddTotalNumberSwapping;
+#ifdef DD_STATS
+static int extsymmcalls;
+static int extsymm;
+static int secdiffcalls;
+static int secdiff;
+static int secdiffmisfire;
+#endif
+#ifdef DD_DEBUG
+static int pr = 0; /* flag to enable printing while debugging */
+ /* by depositing a 1 into it */
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int zddTreeSiftingAux ARGS((DdManager *table, MtrNode *treenode, Cudd_ReorderingType method));
+#ifdef DD_STATS
+static int zddCountInternalMtrNodes ARGS((DdManager *table, MtrNode *treenode));
+#endif
+static int zddReorderChildren ARGS((DdManager *table, MtrNode *treenode, Cudd_ReorderingType method));
+static void zddFindNodeHiLo ARGS((DdManager *table, MtrNode *treenode, int *lower, int *upper));
+static int zddUniqueCompareGroup ARGS((int *ptrX, int *ptrY));
+static int zddGroupSifting ARGS((DdManager *table, int lower, int upper));
+static int zddGroupSiftingAux ARGS((DdManager *table, int x, int xLow, int xHigh));
+static int zddGroupSiftingUp ARGS((DdManager *table, int y, int xLow, Move **moves));
+static int zddGroupSiftingDown ARGS((DdManager *table, int x, int xHigh, Move **moves));
+static int zddGroupMove ARGS((DdManager *table, int x, int y, Move **moves));
+static int zddGroupMoveBackward ARGS((DdManager *table, int x, int y));
+static int zddGroupSiftingBackward ARGS((DdManager *table, Move *moves, int size));
+static void zddMergeGroups ARGS((DdManager *table, MtrNode *treenode, int low, int high));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Creates a new ZDD variable group.]
+
+ Description [Creates a new ZDD variable group. The group starts at
+ variable and contains size variables. The parameter low is the index
+ of the first variable. If the variable already exists, its current
+ position in the order is known to the manager. If the variable does
+ not exist yet, the position is assumed to be the same as the index.
+ The group tree is created if it does not exist yet.
+ Returns a pointer to the group if successful; NULL otherwise.]
+
+ SideEffects [The ZDD variable tree is changed.]
+
+ SeeAlso [Cudd_MakeTreeNode]
+
+******************************************************************************/
+MtrNode *
+Cudd_MakeZddTreeNode(
+ DdManager * dd /* manager */,
+ unsigned int low /* index of the first group variable */,
+ unsigned int size /* number of variables in the group */,
+ unsigned int type /* MTR_DEFAULT or MTR_FIXED */)
+{
+ MtrNode *group;
+ MtrNode *tree;
+ unsigned int level;
+
+ /* If the variable does not exist yet, the position is assumed to be
+ ** the same as the index. Therefore, applications that rely on
+ ** Cudd_bddNewVarAtLevel or Cudd_addNewVarAtLevel to create new
+ ** variables have to create the variables before they group them.
+ */
+ level = (low < (unsigned int) dd->sizeZ) ? dd->permZ[low] : low;
+
+ if (level + size - 1> (int) MTR_MAXHIGH)
+ return(NULL);
+
+ /* If the tree does not exist yet, create it. */
+ tree = dd->treeZ;
+ if (tree == NULL) {
+ dd->treeZ = tree = Mtr_InitGroupTree(0, dd->sizeZ);
+ if (tree == NULL)
+ return(NULL);
+ tree->index = dd->invpermZ[0];
+ }
+
+ /* Extend the upper bound of the tree if necessary. This allows the
+ ** application to create groups even before the variables are created.
+ */
+ tree->size = ddMax(tree->size, level + size);
+
+ /* Create the group. */
+ group = Mtr_MakeGroup(tree, level, size, type);
+ if (group == NULL)
+ return(NULL);
+
+ /* Initialize the index field to the index of the variable currently
+ ** in position low. This field will be updated by the reordering
+ ** procedure to provide a handle to the group once it has been moved.
+ */
+ group->index = (MtrHalfWord) low;
+
+ return(group);
+
+} /* end of Cudd_MakeZddTreeNode */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Tree sifting algorithm for ZDDs.]
+
+ Description [Tree sifting algorithm for ZDDs. Assumes that a tree
+ representing a group hierarchy is passed as a parameter. It then
+ reorders each group in postorder fashion by calling
+ zddTreeSiftingAux. Assumes that no dead nodes are present. Returns
+ 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+int
+cuddZddTreeSifting(
+ DdManager * table /* DD table */,
+ Cudd_ReorderingType method /* reordering method for the groups of leaves */)
+{
+ int i;
+ int nvars;
+ int result;
+ int tempTree;
+
+ /* If no tree is provided we create a temporary one in which all
+ ** variables are in a single group. After reordering this tree is
+ ** destroyed.
+ */
+ tempTree = table->treeZ == NULL;
+ if (tempTree) {
+ table->treeZ = Mtr_InitGroupTree(0,table->sizeZ);
+ table->treeZ->index = table->invpermZ[0];
+ }
+ nvars = table->sizeZ;
+
+#ifdef DD_DEBUG
+ if (pr > 0 && !tempTree)
+ (void) fprintf(table->out,"cuddZddTreeSifting:");
+ Mtr_PrintGroups(table->treeZ,pr <= 0);
+#endif
+#if 0
+ /* Debugging code. */
+ if (table->tree && table->treeZ) {
+ (void) fprintf(table->out,"\n");
+ Mtr_PrintGroups(table->tree, 0);
+ cuddPrintVarGroups(table,table->tree,0,0);
+ for (i = 0; i < table->size; i++) {
+ (void) fprintf(table->out,"%s%d",
+ (i == 0) ? "" : ",", table->invperm[i]);
+ }
+ (void) fprintf(table->out,"\n");
+ for (i = 0; i < table->size; i++) {
+ (void) fprintf(table->out,"%s%d",
+ (i == 0) ? "" : ",", table->perm[i]);
+ }
+ (void) fprintf(table->out,"\n\n");
+ Mtr_PrintGroups(table->treeZ,0);
+ cuddPrintVarGroups(table,table->treeZ,1,0);
+ for (i = 0; i < table->sizeZ; i++) {
+ (void) fprintf(table->out,"%s%d",
+ (i == 0) ? "" : ",", table->invpermZ[i]);
+ }
+ (void) fprintf(table->out,"\n");
+ for (i = 0; i < table->sizeZ; i++) {
+ (void) fprintf(table->out,"%s%d",
+ (i == 0) ? "" : ",", table->permZ[i]);
+ }
+ (void) fprintf(table->out,"\n");
+ }
+ /* End of debugging code. */
+#endif
+#ifdef DD_STATS
+ extsymmcalls = 0;
+ extsymm = 0;
+ secdiffcalls = 0;
+ secdiff = 0;
+ secdiffmisfire = 0;
+
+ (void) fprintf(table->out,"\n");
+ if (!tempTree)
+ (void) fprintf(table->out,"#:IM_NODES %8d: group tree nodes\n",
+ zddCountInternalMtrNodes(table,table->treeZ));
+#endif
+
+ /* Initialize the group of each subtable to itself. Initially
+ ** there are no groups. Groups are created according to the tree
+ ** structure in postorder fashion.
+ */
+ for (i = 0; i < nvars; i++)
+ table->subtableZ[i].next = i;
+
+ /* Reorder. */
+ result = zddTreeSiftingAux(table, table->treeZ, method);
+
+#ifdef DD_STATS /* print stats */
+ if (!tempTree && method == CUDD_REORDER_GROUP_SIFT &&
+ (table->groupcheck == CUDD_GROUP_CHECK7 ||
+ table->groupcheck == CUDD_GROUP_CHECK5)) {
+ (void) fprintf(table->out,"\nextsymmcalls = %d\n",extsymmcalls);
+ (void) fprintf(table->out,"extsymm = %d",extsymm);
+ }
+ if (!tempTree && method == CUDD_REORDER_GROUP_SIFT &&
+ table->groupcheck == CUDD_GROUP_CHECK7) {
+ (void) fprintf(table->out,"\nsecdiffcalls = %d\n",secdiffcalls);
+ (void) fprintf(table->out,"secdiff = %d\n",secdiff);
+ (void) fprintf(table->out,"secdiffmisfire = %d",secdiffmisfire);
+ }
+#endif
+
+ if (tempTree)
+ Cudd_FreeZddTree(table);
+ return(result);
+
+} /* end of cuddZddTreeSifting */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Visits the group tree and reorders each group.]
+
+ Description [Recursively visits the group tree and reorders each
+ group in postorder fashion. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddTreeSiftingAux(
+ DdManager * table,
+ MtrNode * treenode,
+ Cudd_ReorderingType method)
+{
+ MtrNode *auxnode;
+ int res;
+
+#ifdef DD_DEBUG
+ Mtr_PrintGroups(treenode,1);
+#endif
+
+ auxnode = treenode;
+ while (auxnode != NULL) {
+ if (auxnode->child != NULL) {
+ if (!zddTreeSiftingAux(table, auxnode->child, method))
+ return(0);
+ res = zddReorderChildren(table, auxnode, CUDD_REORDER_GROUP_SIFT);
+ if (res == 0)
+ return(0);
+ } else if (auxnode->size > 1) {
+ if (!zddReorderChildren(table, auxnode, method))
+ return(0);
+ }
+ auxnode = auxnode->younger;
+ }
+
+ return(1);
+
+} /* end of zddTreeSiftingAux */
+
+
+#ifdef DD_STATS
+/**Function********************************************************************
+
+ Synopsis [Counts the number of internal nodes of the group tree.]
+
+ Description [Counts the number of internal nodes of the group tree.
+ Returns the count.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddCountInternalMtrNodes(
+ DdManager * table,
+ MtrNode * treenode)
+{
+ MtrNode *auxnode;
+ int count,nodeCount;
+
+
+ nodeCount = 0;
+ auxnode = treenode;
+ while (auxnode != NULL) {
+ if (!(MTR_TEST(auxnode,MTR_TERMINAL))) {
+ nodeCount++;
+ count = zddCountInternalMtrNodes(table,auxnode->child);
+ nodeCount += count;
+ }
+ auxnode = auxnode->younger;
+ }
+
+ return(nodeCount);
+
+} /* end of zddCountInternalMtrNodes */
+#endif
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders the children of a group tree node according to
+ the options.]
+
+ Description [Reorders the children of a group tree node according to
+ the options. After reordering puts all the variables in the group
+ and/or its descendents in a single group. This allows hierarchical
+ reordering. If the variables in the group do not exist yet, simply
+ does nothing. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddReorderChildren(
+ DdManager * table,
+ MtrNode * treenode,
+ Cudd_ReorderingType method)
+{
+ int lower;
+ int upper;
+ int result;
+ unsigned int initialSize;
+
+ zddFindNodeHiLo(table,treenode,&lower,&upper);
+ /* If upper == -1 these variables do not exist yet. */
+ if (upper == -1)
+ return(1);
+
+ if (treenode->flags == MTR_FIXED) {
+ result = 1;
+ } else {
+#ifdef DD_STATS
+ (void) fprintf(table->out," ");
+#endif
+ switch (method) {
+ case CUDD_REORDER_RANDOM:
+ case CUDD_REORDER_RANDOM_PIVOT:
+ result = cuddZddSwapping(table,lower,upper,method);
+ break;
+ case CUDD_REORDER_SIFT:
+ result = cuddZddSifting(table,lower,upper);
+ break;
+ case CUDD_REORDER_SIFT_CONVERGE:
+ do {
+ initialSize = table->keysZ;
+ result = cuddZddSifting(table,lower,upper);
+ if (initialSize <= table->keysZ)
+ break;
+#ifdef DD_STATS
+ else
+ (void) fprintf(table->out,"\n");
+#endif
+ } while (result != 0);
+ break;
+ case CUDD_REORDER_SYMM_SIFT:
+ result = cuddZddSymmSifting(table,lower,upper);
+ break;
+ case CUDD_REORDER_SYMM_SIFT_CONV:
+ result = cuddZddSymmSiftingConv(table,lower,upper);
+ break;
+ case CUDD_REORDER_GROUP_SIFT:
+ result = zddGroupSifting(table,lower,upper);
+ break;
+ case CUDD_REORDER_LINEAR:
+ result = cuddZddLinearSifting(table,lower,upper);
+ break;
+ case CUDD_REORDER_LINEAR_CONVERGE:
+ do {
+ initialSize = table->keysZ;
+ result = cuddZddLinearSifting(table,lower,upper);
+ if (initialSize <= table->keysZ)
+ break;
+#ifdef DD_STATS
+ else
+ (void) fprintf(table->out,"\n");
+#endif
+ } while (result != 0);
+ break;
+ default:
+ return(0);
+ }
+ }
+
+ /* Create a single group for all the variables that were sifted,
+ ** so that they will be treated as a single block by successive
+ ** invocations of zddGroupSifting.
+ */
+ zddMergeGroups(table,treenode,lower,upper);
+
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"zddReorderChildren:");
+#endif
+
+ return(result);
+
+} /* end of zddReorderChildren */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the lower and upper bounds of the group represented
+ by treenode.]
+
+ Description [Finds the lower and upper bounds of the group represented
+ by treenode. The high and low fields of treenode are indices. From
+ those we need to derive the current positions, and find maximum and
+ minimum.]
+
+ SideEffects [The bounds are returned as side effects.]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+zddFindNodeHiLo(
+ DdManager * table,
+ MtrNode * treenode,
+ int * lower,
+ int * upper)
+{
+ int low;
+ int high;
+
+ /* Check whether no variables in this group already exist.
+ ** If so, return immediately. The calling procedure will know from
+ ** the values of upper that no reordering is needed.
+ */
+ if ((int) treenode->low >= table->sizeZ) {
+ *lower = table->sizeZ;
+ *upper = -1;
+ return;
+ }
+
+ *lower = low = (unsigned int) table->permZ[treenode->index];
+ high = (int) (low + treenode->size - 1);
+
+ if (high >= table->sizeZ) {
+ /* This is the case of a partially existing group. The aim is to
+ ** reorder as many variables as safely possible. If the tree
+ ** node is terminal, we just reorder the subset of the group
+ ** that is currently in existence. If the group has
+ ** subgroups, then we only reorder those subgroups that are
+ ** fully instantiated. This way we avoid breaking up a group.
+ */
+ MtrNode *auxnode = treenode->child;
+ if (auxnode == NULL) {
+ *upper = (unsigned int) table->sizeZ - 1;
+ } else {
+ /* Search the subgroup that strands the table->sizeZ line.
+ ** If the first group starts at 0 and goes past table->sizeZ
+ ** upper will get -1, thus correctly signaling that no reordering
+ ** should take place.
+ */
+ while (auxnode != NULL) {
+ int thisLower = table->permZ[auxnode->low];
+ int thisUpper = thisLower + auxnode->size - 1;
+ if (thisUpper >= table->sizeZ && thisLower < table->sizeZ)
+ *upper = (unsigned int) thisLower - 1;
+ auxnode = auxnode->younger;
+ }
+ }
+ } else {
+ /* Normal case: All the variables of the group exist. */
+ *upper = (unsigned int) high;
+ }
+
+#ifdef DD_DEBUG
+ /* Make sure that all variables in group are contiguous. */
+ assert(treenode->size >= *upper - *lower + 1);
+#endif
+
+ return;
+
+} /* end of zddFindNodeHiLo */
+
+
+/**Function********************************************************************
+
+ Synopsis [Comparison function used by qsort.]
+
+ Description [Comparison function used by qsort to order the variables
+ according to the number of keys in the subtables. Returns the
+ difference in number of keys between the two variables being
+ compared.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddUniqueCompareGroup(
+ int * ptrX,
+ int * ptrY)
+{
+#if 0
+ if (entry[*ptrY] == entry[*ptrX]) {
+ return((*ptrX) - (*ptrY));
+ }
+#endif
+ return(entry[*ptrY] - entry[*ptrX]);
+
+} /* end of zddUniqueCompareGroup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts from treenode->low to treenode->high.]
+
+ Description [Sifts from treenode->low to treenode->high. If
+ croupcheck == CUDD_GROUP_CHECK7, it checks for group creation at the
+ end of the initial sifting. If a group is created, it is then sifted
+ again. After sifting one variable, the group that contains it is
+ dissolved. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddGroupSifting(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int *var;
+ int i,j,x,xInit;
+ int nvars;
+ int classes;
+ int result;
+ int *sifted;
+#ifdef DD_STATS
+ unsigned previousSize;
+#endif
+ int xindex;
+
+ nvars = table->sizeZ;
+
+ /* Order variables to sift. */
+ entry = NULL;
+ sifted = NULL;
+ var = ALLOC(int,nvars);
+ if (var == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto zddGroupSiftingOutOfMem;
+ }
+ entry = ALLOC(int,nvars);
+ if (entry == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto zddGroupSiftingOutOfMem;
+ }
+ sifted = ALLOC(int,nvars);
+ if (sifted == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto zddGroupSiftingOutOfMem;
+ }
+
+ /* Here we consider only one representative for each group. */
+ for (i = 0, classes = 0; i < nvars; i++) {
+ sifted[i] = 0;
+ x = table->permZ[i];
+ if ((unsigned) x >= table->subtableZ[x].next) {
+ entry[i] = table->subtableZ[x].keys;
+ var[classes] = i;
+ classes++;
+ }
+ }
+
+ qsort((void *)var,classes,sizeof(int),(int (*)(const void *, const void *))zddUniqueCompareGroup);
+
+ /* Now sift. */
+ for (i = 0; i < ddMin(table->siftMaxVar,classes); i++) {
+ if (zddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ xindex = var[i];
+ if (sifted[xindex] == 1) /* variable already sifted as part of group */
+ continue;
+ x = table->permZ[xindex]; /* find current level of this variable */
+ if (x < lower || x > upper)
+ continue;
+#ifdef DD_STATS
+ previousSize = table->keysZ;
+#endif
+#ifdef DD_DEBUG
+ /* x is bottom of group */
+ assert((unsigned) x >= table->subtableZ[x].next);
+#endif
+ result = zddGroupSiftingAux(table,x,lower,upper);
+ if (!result) goto zddGroupSiftingOutOfMem;
+
+#ifdef DD_STATS
+ if (table->keysZ < previousSize) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keysZ > previousSize) {
+ (void) fprintf(table->out,"+");
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+
+ /* Mark variables in the group just sifted. */
+ x = table->permZ[xindex];
+ if ((unsigned) x != table->subtableZ[x].next) {
+ xInit = x;
+ do {
+ j = table->invpermZ[x];
+ sifted[j] = 1;
+ x = table->subtableZ[x].next;
+ } while (x != xInit);
+ }
+
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"zddGroupSifting:");
+#endif
+ } /* for */
+
+ FREE(sifted);
+ FREE(var);
+ FREE(entry);
+
+ return(1);
+
+zddGroupSiftingOutOfMem:
+ if (entry != NULL) FREE(entry);
+ if (var != NULL) FREE(var);
+ if (sifted != NULL) FREE(sifted);
+
+ return(0);
+
+} /* end of zddGroupSifting */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts one variable up and down until it has taken all
+ positions. Checks for aggregation.]
+
+ Description [Sifts one variable up and down until it has taken all
+ positions. Checks for aggregation. There may be at most two sweeps,
+ even if the group grows. Assumes that x is either an isolated
+ variable, or it is the bottom of a group. All groups may not have
+ been found. The variable being moved is returned to the best position
+ seen during sifting. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddGroupSiftingAux(
+ DdManager * table,
+ int x,
+ int xLow,
+ int xHigh)
+{
+ Move *move;
+ Move *moves; /* list of moves */
+ int initialSize;
+ int result;
+
+
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"zddGroupSiftingAux from %d to %d\n",xLow,xHigh);
+ assert((unsigned) x >= table->subtableZ[x].next); /* x is bottom of group */
+#endif
+
+ initialSize = table->keysZ;
+ moves = NULL;
+
+ if (x == xLow) { /* Sift down */
+#ifdef DD_DEBUG
+ /* x must be a singleton */
+ assert((unsigned) x == table->subtableZ[x].next);
+#endif
+ if (x == xHigh) return(1); /* just one variable */
+
+ if (!zddGroupSiftingDown(table,x,xHigh,&moves))
+ goto zddGroupSiftingAuxOutOfMem;
+ /* at this point x == xHigh, unless early term */
+
+ /* move backward and stop at best position */
+ result = zddGroupSiftingBackward(table,moves,initialSize);
+#ifdef DD_DEBUG
+ assert(table->keysZ <= (unsigned) initialSize);
+#endif
+ if (!result) goto zddGroupSiftingAuxOutOfMem;
+
+ } else if (cuddZddNextHigh(table,x) > xHigh) { /* Sift up */
+#ifdef DD_DEBUG
+ /* x is bottom of group */
+ assert((unsigned) x >= table->subtableZ[x].next);
+#endif
+ /* Find top of x's group */
+ x = table->subtableZ[x].next;
+
+ if (!zddGroupSiftingUp(table,x,xLow,&moves))
+ goto zddGroupSiftingAuxOutOfMem;
+ /* at this point x == xLow, unless early term */
+
+ /* move backward and stop at best position */
+ result = zddGroupSiftingBackward(table,moves,initialSize);
+#ifdef DD_DEBUG
+ assert(table->keysZ <= (unsigned) initialSize);
+#endif
+ if (!result) goto zddGroupSiftingAuxOutOfMem;
+
+ } else if (x - xLow > xHigh - x) { /* must go down first: shorter */
+ if (!zddGroupSiftingDown(table,x,xHigh,&moves))
+ goto zddGroupSiftingAuxOutOfMem;
+ /* at this point x == xHigh, unless early term */
+
+ /* Find top of group */
+ if (moves) {
+ x = moves->y;
+ }
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ x = table->subtableZ[x].next;
+#ifdef DD_DEBUG
+ /* x should be the top of a group */
+ assert((unsigned) x <= table->subtableZ[x].next);
+#endif
+
+ if (!zddGroupSiftingUp(table,x,xLow,&moves))
+ goto zddGroupSiftingAuxOutOfMem;
+
+ /* move backward and stop at best position */
+ result = zddGroupSiftingBackward(table,moves,initialSize);
+#ifdef DD_DEBUG
+ assert(table->keysZ <= (unsigned) initialSize);
+#endif
+ if (!result) goto zddGroupSiftingAuxOutOfMem;
+
+ } else { /* moving up first: shorter */
+ /* Find top of x's group */
+ x = table->subtableZ[x].next;
+
+ if (!zddGroupSiftingUp(table,x,xLow,&moves))
+ goto zddGroupSiftingAuxOutOfMem;
+ /* at this point x == xHigh, unless early term */
+
+ if (moves) {
+ x = moves->x;
+ }
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+#ifdef DD_DEBUG
+ /* x is bottom of a group */
+ assert((unsigned) x >= table->subtableZ[x].next);
+#endif
+
+ if (!zddGroupSiftingDown(table,x,xHigh,&moves))
+ goto zddGroupSiftingAuxOutOfMem;
+
+ /* move backward and stop at best position */
+ result = zddGroupSiftingBackward(table,moves,initialSize);
+#ifdef DD_DEBUG
+ assert(table->keysZ <= (unsigned) initialSize);
+#endif
+ if (!result) goto zddGroupSiftingAuxOutOfMem;
+ }
+
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+
+ return(1);
+
+zddGroupSiftingAuxOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+
+ return(0);
+
+} /* end of zddGroupSiftingAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts up a variable until either it reaches position xLow
+ or the size of the DD heap increases too much.]
+
+ Description [Sifts up a variable until either it reaches position
+ xLow or the size of the DD heap increases too much. Assumes that y is
+ the top of a group (or a singleton). Checks y for aggregation to the
+ adjacent variables. Records all the moves that are appended to the
+ list of moves received as input and returned as a side effect.
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddGroupSiftingUp(
+ DdManager * table,
+ int y,
+ int xLow,
+ Move ** moves)
+{
+ Move *move;
+ int x;
+ int size;
+ int gxtop;
+ int limitSize;
+ int xindex, yindex;
+
+ yindex = table->invpermZ[y];
+
+ limitSize = table->keysZ;
+
+ x = cuddZddNextLow(table,y);
+ while (x >= xLow) {
+ gxtop = table->subtableZ[x].next;
+ if (table->subtableZ[x].next == (unsigned) x &&
+ table->subtableZ[y].next == (unsigned) y) {
+ /* x and y are self groups */
+ xindex = table->invpermZ[x];
+ size = cuddZddSwapInPlace(table,x,y);
+#ifdef DD_DEBUG
+ assert(table->subtableZ[x].next == (unsigned) x);
+ assert(table->subtableZ[y].next == (unsigned) y);
+#endif
+ if (size == 0) goto zddGroupSiftingUpOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto zddGroupSiftingUpOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->flags = MTR_DEFAULT;
+ move->size = size;
+ move->next = *moves;
+ *moves = move;
+
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"zddGroupSiftingUp (2 single groups):\n");
+#endif
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(1);
+ if (size < limitSize) limitSize = size;
+ } else { /* group move */
+ size = zddGroupMove(table,x,y,moves);
+ if (size == 0) goto zddGroupSiftingUpOutOfMem;
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(1);
+ if (size < limitSize) limitSize = size;
+ }
+ y = gxtop;
+ x = cuddZddNextLow(table,y);
+ }
+
+ return(1);
+
+zddGroupSiftingUpOutOfMem:
+ while (*moves != NULL) {
+ move = (*moves)->next;
+ cuddDeallocNode(table, (DdNode *) *moves);
+ *moves = move;
+ }
+ return(0);
+
+} /* end of zddGroupSiftingUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts down a variable until it reaches position xHigh.]
+
+ Description [Sifts down a variable until it reaches position xHigh.
+ Assumes that x is the bottom of a group (or a singleton). Records
+ all the moves. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddGroupSiftingDown(
+ DdManager * table,
+ int x,
+ int xHigh,
+ Move ** moves)
+{
+ Move *move;
+ int y;
+ int size;
+ int limitSize;
+ int gxtop,gybot;
+ int xindex;
+
+
+ /* Initialize R */
+ xindex = table->invpermZ[x];
+ gxtop = table->subtableZ[x].next;
+ limitSize = size = table->keysZ;
+ y = cuddZddNextHigh(table,x);
+ while (y <= xHigh) {
+ /* Find bottom of y group. */
+ gybot = table->subtableZ[y].next;
+ while (table->subtableZ[gybot].next != (unsigned) y)
+ gybot = table->subtableZ[gybot].next;
+
+ if (table->subtableZ[x].next == (unsigned) x &&
+ table->subtableZ[y].next == (unsigned) y) {
+ /* x and y are self groups */
+ size = cuddZddSwapInPlace(table,x,y);
+#ifdef DD_DEBUG
+ assert(table->subtableZ[x].next == (unsigned) x);
+ assert(table->subtableZ[y].next == (unsigned) y);
+#endif
+ if (size == 0) goto zddGroupSiftingDownOutOfMem;
+
+ /* Record move. */
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto zddGroupSiftingDownOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->flags = MTR_DEFAULT;
+ move->size = size;
+ move->next = *moves;
+ *moves = move;
+
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"zddGroupSiftingDown (2 single groups):\n");
+#endif
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(1);
+ if (size < limitSize) limitSize = size;
+ x = y;
+ y = cuddZddNextHigh(table,x);
+ } else { /* Group move */
+ size = zddGroupMove(table,x,y,moves);
+ if (size == 0) goto zddGroupSiftingDownOutOfMem;
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(1);
+ if (size < limitSize) limitSize = size;
+ }
+ x = gybot;
+ y = cuddZddNextHigh(table,x);
+ }
+
+ return(1);
+
+zddGroupSiftingDownOutOfMem:
+ while (*moves != NULL) {
+ move = (*moves)->next;
+ cuddDeallocNode(table, (DdNode *) *moves);
+ *moves = move;
+ }
+
+ return(0);
+
+} /* end of zddGroupSiftingDown */
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps two groups and records the move.]
+
+ Description [Swaps two groups and records the move. Returns the
+ number of keys in the DD table in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddGroupMove(
+ DdManager * table,
+ int x,
+ int y,
+ Move ** moves)
+{
+ Move *move;
+ int size;
+ int i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
+ int swapx,swapy;
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ int initialSize,bestSize;
+#endif
+
+#if DD_DEBUG
+ /* We assume that x < y */
+ assert(x < y);
+#endif
+ /* Find top, bottom, and size for the two groups. */
+ xbot = x;
+ xtop = table->subtableZ[x].next;
+ xsize = xbot - xtop + 1;
+ ybot = y;
+ while ((unsigned) ybot < table->subtableZ[ybot].next)
+ ybot = table->subtableZ[ybot].next;
+ ytop = y;
+ ysize = ybot - ytop + 1;
+
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ initialSize = bestSize = table->keysZ;
+#endif
+ /* Sift the variables of the second group up through the first group */
+ for (i = 1; i <= ysize; i++) {
+ for (j = 1; j <= xsize; j++) {
+ size = cuddZddSwapInPlace(table,x,y);
+ if (size == 0) goto zddGroupMoveOutOfMem;
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ if (size < bestSize)
+ bestSize = size;
+#endif
+ swapx = x; swapy = y;
+ y = x;
+ x = cuddZddNextLow(table,y);
+ }
+ y = ytop + i;
+ x = cuddZddNextLow(table,y);
+ }
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ if ((bestSize < initialSize) && (bestSize < size))
+ (void) fprintf(table->out,"Missed local minimum: initialSize:%d bestSize:%d finalSize:%d\n",initialSize,bestSize,size);
+#endif
+
+ /* fix groups */
+ y = xtop; /* ytop is now where xtop used to be */
+ for (i = 0; i < ysize - 1; i++) {
+ table->subtableZ[y].next = cuddZddNextHigh(table,y);
+ y = cuddZddNextHigh(table,y);
+ }
+ table->subtableZ[y].next = xtop; /* y is bottom of its group, join */
+ /* it to top of its group */
+ x = cuddZddNextHigh(table,y);
+ newxtop = x;
+ for (i = 0; i < xsize - 1; i++) {
+ table->subtableZ[x].next = cuddZddNextHigh(table,x);
+ x = cuddZddNextHigh(table,x);
+ }
+ table->subtableZ[x].next = newxtop; /* x is bottom of its group, join */
+ /* it to top of its group */
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"zddGroupMove:\n");
+#endif
+
+ /* Store group move */
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto zddGroupMoveOutOfMem;
+ move->x = swapx;
+ move->y = swapy;
+ move->flags = MTR_DEFAULT;
+ move->size = table->keysZ;
+ move->next = *moves;
+ *moves = move;
+
+ return(table->keysZ);
+
+zddGroupMoveOutOfMem:
+ while (*moves != NULL) {
+ move = (*moves)->next;
+ cuddDeallocNode(table, (DdNode *) *moves);
+ *moves = move;
+ }
+ return(0);
+
+} /* end of zddGroupMove */
+
+
+/**Function********************************************************************
+
+ Synopsis [Undoes the swap two groups.]
+
+ Description [Undoes the swap two groups. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddGroupMoveBackward(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int size;
+ int i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
+
+
+#if DD_DEBUG
+ /* We assume that x < y */
+ assert(x < y);
+#endif
+
+ /* Find top, bottom, and size for the two groups. */
+ xbot = x;
+ xtop = table->subtableZ[x].next;
+ xsize = xbot - xtop + 1;
+ ybot = y;
+ while ((unsigned) ybot < table->subtableZ[ybot].next)
+ ybot = table->subtableZ[ybot].next;
+ ytop = y;
+ ysize = ybot - ytop + 1;
+
+ /* Sift the variables of the second group up through the first group */
+ for (i = 1; i <= ysize; i++) {
+ for (j = 1; j <= xsize; j++) {
+ size = cuddZddSwapInPlace(table,x,y);
+ if (size == 0)
+ return(0);
+ y = x;
+ x = cuddZddNextLow(table,y);
+ }
+ y = ytop + i;
+ x = cuddZddNextLow(table,y);
+ }
+
+ /* fix groups */
+ y = xtop;
+ for (i = 0; i < ysize - 1; i++) {
+ table->subtableZ[y].next = cuddZddNextHigh(table,y);
+ y = cuddZddNextHigh(table,y);
+ }
+ table->subtableZ[y].next = xtop; /* y is bottom of its group, join */
+ /* to its top */
+ x = cuddZddNextHigh(table,y);
+ newxtop = x;
+ for (i = 0; i < xsize - 1; i++) {
+ table->subtableZ[x].next = cuddZddNextHigh(table,x);
+ x = cuddZddNextHigh(table,x);
+ }
+ table->subtableZ[x].next = newxtop; /* x is bottom of its group, join */
+ /* to its top */
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"zddGroupMoveBackward:\n");
+#endif
+
+ return(1);
+
+} /* end of zddGroupMoveBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Determines the best position for a variables and returns
+ it there.]
+
+ Description [Determines the best position for a variables and returns
+ it there. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddGroupSiftingBackward(
+ DdManager * table,
+ Move * moves,
+ int size)
+{
+ Move *move;
+ int res;
+
+
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size < size) {
+ size = move->size;
+ }
+ }
+
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size == size) return(1);
+ if ((table->subtableZ[move->x].next == move->x) &&
+ (table->subtableZ[move->y].next == move->y)) {
+ res = cuddZddSwapInPlace(table,(int)move->x,(int)move->y);
+ if (!res) return(0);
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"zddGroupSiftingBackward:\n");
+ assert(table->subtableZ[move->x].next == move->x);
+ assert(table->subtableZ[move->y].next == move->y);
+#endif
+ } else { /* Group move necessary */
+ res = zddGroupMoveBackward(table,(int)move->x,(int)move->y);
+ if (!res) return(0);
+ }
+ }
+
+ return(1);
+
+} /* end of zddGroupSiftingBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Merges groups in the DD table.]
+
+ Description [Creates a single group from low to high and adjusts the
+ idex field of the tree node.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static void
+zddMergeGroups(
+ DdManager * table,
+ MtrNode * treenode,
+ int low,
+ int high)
+{
+ int i;
+ MtrNode *auxnode;
+ int saveindex;
+ int newindex;
+
+ /* Merge all variables from low to high in one group, unless
+ ** this is the topmost group. In such a case we do not merge lest
+ ** we lose the symmetry information. */
+ if (treenode != table->treeZ) {
+ for (i = low; i < high; i++)
+ table->subtableZ[i].next = i+1;
+ table->subtableZ[high].next = low;
+ }
+
+ /* Adjust the index fields of the tree nodes. If a node is the
+ ** first child of its parent, then the parent may also need adjustment. */
+ saveindex = treenode->index;
+ newindex = table->invpermZ[low];
+ auxnode = treenode;
+ do {
+ auxnode->index = newindex;
+ if (auxnode->parent == NULL ||
+ (int) auxnode->parent->index != saveindex)
+ break;
+ auxnode = auxnode->parent;
+ } while (1);
+ return;
+
+} /* end of zddMergeGroups */
+
diff --git a/src/bdd/cudd/cuddZddIsop.c b/src/bdd/cudd/cuddZddIsop.c
new file mode 100644
index 00000000..0918461c
--- /dev/null
+++ b/src/bdd/cudd/cuddZddIsop.c
@@ -0,0 +1,885 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddIsop.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions to find irredundant SOP covers as ZDDs from BDDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_bddIsop()
+ <li> Cudd_zddIsop()
+ <li> Cudd_MakeBddFromZddCover()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddBddIsop()
+ <li> cuddZddIsop()
+ <li> cuddMakeBddFromZddCover()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [In-Ho Moon]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddIsop.c,v 1.1.1.1 2003/02/24 22:23:54 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Computes an ISOP in ZDD form from BDDs.]
+
+ Description [Computes an irredundant sum of products (ISOP) in ZDD
+ form from BDDs. The two BDDs L and U represent the lower bound and
+ the upper bound, respectively, of the function. The ISOP uses two
+ ZDD variables for each BDD variable: One for the positive literal,
+ and one for the negative literal. These two variables should be
+ adjacent in the ZDD order. The two ZDD variables corresponding to
+ BDD variable <code>i</code> should have indices <code>2i</code> and
+ <code>2i+1</code>. The result of this procedure depends on the
+ variable order. If successful, Cudd_zddIsop returns the BDD for
+ the function chosen from the interval. The ZDD representing the
+ irredundant cover is returned as a side effect in zdd_I. In case of
+ failure, NULL is returned.]
+
+ SideEffects [zdd_I holds the pointer to the ZDD for the ISOP on
+ successful return.]
+
+ SeeAlso [Cudd_bddIsop Cudd_zddVarsFromBddVars]
+
+******************************************************************************/
+DdNode *
+Cudd_zddIsop(
+ DdManager * dd,
+ DdNode * L,
+ DdNode * U,
+ DdNode ** zdd_I)
+{
+ DdNode *res;
+ int autoDynZ;
+
+ autoDynZ = dd->autoDynZ;
+ dd->autoDynZ = 0;
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddIsop(dd, L, U, zdd_I);
+ } while (dd->reordered == 1);
+ dd->autoDynZ = autoDynZ;
+ return(res);
+
+} /* end of Cudd_zddIsop */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes a BDD in the interval between L and U with a
+ simple sum-of-produuct cover.]
+
+ Description [Computes a BDD in the interval between L and U with a
+ simple sum-of-produuct cover. This procedure is similar to
+ Cudd_zddIsop, but it does not return the ZDD for the cover. Returns
+ a pointer to the BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddIsop]
+
+******************************************************************************/
+DdNode *
+Cudd_bddIsop(
+ DdManager * dd,
+ DdNode * L,
+ DdNode * U)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddIsop(dd, L, U);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddIsop */
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts a ZDD cover to a BDD graph.]
+
+ Description [Converts a ZDD cover to a BDD graph. If successful, it
+ returns a BDD node, otherwise it returns NULL.]
+
+ SideEffects []
+
+ SeeAlso [cuddMakeBddFromZddCover]
+
+******************************************************************************/
+DdNode *
+Cudd_MakeBddFromZddCover(
+ DdManager * dd,
+ DdNode * node)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddMakeBddFromZddCover(dd, node);
+ } while (dd->reordered == 1);
+ return(res);
+} /* end of Cudd_MakeBddFromZddCover */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddIsop.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddIsop]
+
+******************************************************************************/
+DdNode *
+cuddZddIsop(
+ DdManager * dd,
+ DdNode * L,
+ DdNode * U,
+ DdNode ** zdd_I)
+{
+ DdNode *one = DD_ONE(dd);
+ DdNode *zero = Cudd_Not(one);
+ DdNode *zdd_one = DD_ONE(dd);
+ DdNode *zdd_zero = DD_ZERO(dd);
+ int v, top_l, top_u;
+ DdNode *Lsub0, *Usub0, *Lsub1, *Usub1, *Ld, *Ud;
+ DdNode *Lsuper0, *Usuper0, *Lsuper1, *Usuper1;
+ DdNode *Isub0, *Isub1, *Id;
+ DdNode *zdd_Isub0, *zdd_Isub1, *zdd_Id;
+ DdNode *x;
+ DdNode *term0, *term1, *sum;
+ DdNode *Lv, *Uv, *Lnv, *Unv;
+ DdNode *r, *y, *z;
+ int index;
+ DdNode *(*cacheOp)(DdManager *, DdNode *, DdNode *);
+
+ statLine(dd);
+ if (L == zero) {
+ *zdd_I = zdd_zero;
+ return(zero);
+ }
+ if (U == one) {
+ *zdd_I = zdd_one;
+ return(one);
+ }
+
+ if (U == zero || L == one) {
+ printf("*** ERROR : illegal condition for ISOP (U < L).\n");
+ exit(1);
+ }
+
+ /* Check the cache. We store two results for each recursive call.
+ ** One is the BDD, and the other is the ZDD. Both are needed.
+ ** Hence we need a double hit in the cache to terminate the
+ ** recursion. Clearly, collisions may evict only one of the two
+ ** results. */
+ cacheOp = (DdNode *(*)(DdManager *, DdNode *, DdNode *)) cuddZddIsop;
+ r = cuddCacheLookup2(dd, cuddBddIsop, L, U);
+ if (r) {
+ *zdd_I = cuddCacheLookup2Zdd(dd, cacheOp, L, U);
+ if (*zdd_I)
+ return(r);
+ else {
+ /* The BDD result may have been dead. In that case
+ ** cuddCacheLookup2 would have called cuddReclaim,
+ ** whose effects we now have to undo. */
+ cuddRef(r);
+ Cudd_RecursiveDeref(dd, r);
+ }
+ }
+
+ top_l = dd->perm[Cudd_Regular(L)->index];
+ top_u = dd->perm[Cudd_Regular(U)->index];
+ v = ddMin(top_l, top_u);
+
+ /* Compute cofactors. */
+ if (top_l == v) {
+ index = Cudd_Regular(L)->index;
+ Lv = Cudd_T(L);
+ Lnv = Cudd_E(L);
+ if (Cudd_IsComplement(L)) {
+ Lv = Cudd_Not(Lv);
+ Lnv = Cudd_Not(Lnv);
+ }
+ }
+ else {
+ index = Cudd_Regular(U)->index;
+ Lv = Lnv = L;
+ }
+
+ if (top_u == v) {
+ Uv = Cudd_T(U);
+ Unv = Cudd_E(U);
+ if (Cudd_IsComplement(U)) {
+ Uv = Cudd_Not(Uv);
+ Unv = Cudd_Not(Unv);
+ }
+ }
+ else {
+ Uv = Unv = U;
+ }
+
+ Lsub0 = cuddBddAndRecur(dd, Lnv, Cudd_Not(Uv));
+ if (Lsub0 == NULL)
+ return(NULL);
+ Cudd_Ref(Lsub0);
+ Usub0 = Unv;
+ Lsub1 = cuddBddAndRecur(dd, Lv, Cudd_Not(Unv));
+ if (Lsub1 == NULL) {
+ Cudd_RecursiveDeref(dd, Lsub0);
+ return(NULL);
+ }
+ Cudd_Ref(Lsub1);
+ Usub1 = Uv;
+
+ Isub0 = cuddZddIsop(dd, Lsub0, Usub0, &zdd_Isub0);
+ if (Isub0 == NULL) {
+ Cudd_RecursiveDeref(dd, Lsub0);
+ Cudd_RecursiveDeref(dd, Lsub1);
+ return(NULL);
+ }
+ /*
+ if ((!cuddIsConstant(Cudd_Regular(Isub0))) &&
+ (Cudd_Regular(Isub0)->index != zdd_Isub0->index / 2 ||
+ dd->permZ[index * 2] > dd->permZ[zdd_Isub0->index])) {
+ printf("*** ERROR : illegal permutation in ZDD. ***\n");
+ }
+ */
+ Cudd_Ref(Isub0);
+ Cudd_Ref(zdd_Isub0);
+ Isub1 = cuddZddIsop(dd, Lsub1, Usub1, &zdd_Isub1);
+ if (Isub1 == NULL) {
+ Cudd_RecursiveDeref(dd, Lsub0);
+ Cudd_RecursiveDeref(dd, Lsub1);
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ return(NULL);
+ }
+ /*
+ if ((!cuddIsConstant(Cudd_Regular(Isub1))) &&
+ (Cudd_Regular(Isub1)->index != zdd_Isub1->index / 2 ||
+ dd->permZ[index * 2] > dd->permZ[zdd_Isub1->index])) {
+ printf("*** ERROR : illegal permutation in ZDD. ***\n");
+ }
+ */
+ Cudd_Ref(Isub1);
+ Cudd_Ref(zdd_Isub1);
+ Cudd_RecursiveDeref(dd, Lsub0);
+ Cudd_RecursiveDeref(dd, Lsub1);
+
+ Lsuper0 = cuddBddAndRecur(dd, Lnv, Cudd_Not(Isub0));
+ if (Lsuper0 == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ return(NULL);
+ }
+ Cudd_Ref(Lsuper0);
+ Lsuper1 = cuddBddAndRecur(dd, Lv, Cudd_Not(Isub1));
+ if (Lsuper1 == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDeref(dd, Lsuper0);
+ return(NULL);
+ }
+ Cudd_Ref(Lsuper1);
+ Usuper0 = Unv;
+ Usuper1 = Uv;
+
+ /* Ld = Lsuper0 + Lsuper1 */
+ Ld = cuddBddAndRecur(dd, Cudd_Not(Lsuper0), Cudd_Not(Lsuper1));
+ if (Ld == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDeref(dd, Lsuper0);
+ Cudd_RecursiveDeref(dd, Lsuper1);
+ return(NULL);
+ }
+ Ld = Cudd_Not(Ld);
+ Cudd_Ref(Ld);
+ /* Ud = Usuper0 * Usuper1 */
+ Ud = cuddBddAndRecur(dd, Usuper0, Usuper1);
+ if (Ud == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDeref(dd, Lsuper0);
+ Cudd_RecursiveDeref(dd, Lsuper1);
+ Cudd_RecursiveDeref(dd, Ld);
+ return(NULL);
+ }
+ Cudd_Ref(Ud);
+ Cudd_RecursiveDeref(dd, Lsuper0);
+ Cudd_RecursiveDeref(dd, Lsuper1);
+
+ Id = cuddZddIsop(dd, Ld, Ud, &zdd_Id);
+ if (Id == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDeref(dd, Ld);
+ Cudd_RecursiveDeref(dd, Ud);
+ return(NULL);
+ }
+ /*
+ if ((!cuddIsConstant(Cudd_Regular(Id))) &&
+ (Cudd_Regular(Id)->index != zdd_Id->index / 2 ||
+ dd->permZ[index * 2] > dd->permZ[zdd_Id->index])) {
+ printf("*** ERROR : illegal permutation in ZDD. ***\n");
+ }
+ */
+ Cudd_Ref(Id);
+ Cudd_Ref(zdd_Id);
+ Cudd_RecursiveDeref(dd, Ld);
+ Cudd_RecursiveDeref(dd, Ud);
+
+ x = cuddUniqueInter(dd, index, one, zero);
+ if (x == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDeref(dd, Id);
+ Cudd_RecursiveDerefZdd(dd, zdd_Id);
+ return(NULL);
+ }
+ Cudd_Ref(x);
+ /* term0 = x * Isub0 */
+ term0 = cuddBddAndRecur(dd, Cudd_Not(x), Isub0);
+ if (term0 == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDeref(dd, Id);
+ Cudd_RecursiveDerefZdd(dd, zdd_Id);
+ Cudd_RecursiveDeref(dd, x);
+ return(NULL);
+ }
+ Cudd_Ref(term0);
+ Cudd_RecursiveDeref(dd, Isub0);
+ /* term1 = x * Isub1 */
+ term1 = cuddBddAndRecur(dd, x, Isub1);
+ if (term1 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDeref(dd, Id);
+ Cudd_RecursiveDerefZdd(dd, zdd_Id);
+ Cudd_RecursiveDeref(dd, x);
+ Cudd_RecursiveDeref(dd, term0);
+ return(NULL);
+ }
+ Cudd_Ref(term1);
+ Cudd_RecursiveDeref(dd, x);
+ Cudd_RecursiveDeref(dd, Isub1);
+ /* sum = term0 + term1 */
+ sum = cuddBddAndRecur(dd, Cudd_Not(term0), Cudd_Not(term1));
+ if (sum == NULL) {
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDeref(dd, Id);
+ Cudd_RecursiveDerefZdd(dd, zdd_Id);
+ Cudd_RecursiveDeref(dd, term0);
+ Cudd_RecursiveDeref(dd, term1);
+ return(NULL);
+ }
+ sum = Cudd_Not(sum);
+ Cudd_Ref(sum);
+ Cudd_RecursiveDeref(dd, term0);
+ Cudd_RecursiveDeref(dd, term1);
+ /* r = sum + Id */
+ r = cuddBddAndRecur(dd, Cudd_Not(sum), Cudd_Not(Id));
+ r = Cudd_NotCond(r, r != NULL);
+ if (r == NULL) {
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDeref(dd, Id);
+ Cudd_RecursiveDerefZdd(dd, zdd_Id);
+ Cudd_RecursiveDeref(dd, sum);
+ return(NULL);
+ }
+ Cudd_Ref(r);
+ Cudd_RecursiveDeref(dd, sum);
+ Cudd_RecursiveDeref(dd, Id);
+
+ if (zdd_Isub0 != zdd_zero) {
+ z = cuddZddGetNodeIVO(dd, index * 2 + 1, zdd_Isub0, zdd_Id);
+ if (z == NULL) {
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDerefZdd(dd, zdd_Id);
+ Cudd_RecursiveDeref(dd, r);
+ return(NULL);
+ }
+ }
+ else {
+ z = zdd_Id;
+ }
+ Cudd_Ref(z);
+ if (zdd_Isub1 != zdd_zero) {
+ y = cuddZddGetNodeIVO(dd, index * 2, zdd_Isub1, z);
+ if (y == NULL) {
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDerefZdd(dd, zdd_Id);
+ Cudd_RecursiveDeref(dd, r);
+ Cudd_RecursiveDerefZdd(dd, z);
+ return(NULL);
+ }
+ }
+ else
+ y = z;
+ Cudd_Ref(y);
+
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDerefZdd(dd, zdd_Id);
+ Cudd_RecursiveDerefZdd(dd, z);
+
+ cuddCacheInsert2(dd, cuddBddIsop, L, U, r);
+ cuddCacheInsert2(dd, cacheOp, L, U, y);
+
+ Cudd_Deref(r);
+ Cudd_Deref(y);
+ *zdd_I = y;
+ /*
+ if (Cudd_Regular(r)->index != y->index / 2) {
+ printf("*** ERROR : mismatch in indices between BDD and ZDD. ***\n");
+ }
+ */
+ return(r);
+
+} /* end of cuddZddIsop */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddIsop.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIsop]
+
+******************************************************************************/
+DdNode *
+cuddBddIsop(
+ DdManager * dd,
+ DdNode * L,
+ DdNode * U)
+{
+ DdNode *one = DD_ONE(dd);
+ DdNode *zero = Cudd_Not(one);
+ int v, top_l, top_u;
+ DdNode *Lsub0, *Usub0, *Lsub1, *Usub1, *Ld, *Ud;
+ DdNode *Lsuper0, *Usuper0, *Lsuper1, *Usuper1;
+ DdNode *Isub0, *Isub1, *Id;
+ DdNode *x;
+ DdNode *term0, *term1, *sum;
+ DdNode *Lv, *Uv, *Lnv, *Unv;
+ DdNode *r;
+ int index;
+
+ statLine(dd);
+ if (L == zero)
+ return(zero);
+ if (U == one)
+ return(one);
+
+ /* Check cache */
+ r = cuddCacheLookup2(dd, cuddBddIsop, L, U);
+ if (r)
+ return(r);
+
+ top_l = dd->perm[Cudd_Regular(L)->index];
+ top_u = dd->perm[Cudd_Regular(U)->index];
+ v = ddMin(top_l, top_u);
+
+ /* Compute cofactors */
+ if (top_l == v) {
+ index = Cudd_Regular(L)->index;
+ Lv = Cudd_T(L);
+ Lnv = Cudd_E(L);
+ if (Cudd_IsComplement(L)) {
+ Lv = Cudd_Not(Lv);
+ Lnv = Cudd_Not(Lnv);
+ }
+ }
+ else {
+ index = Cudd_Regular(U)->index;
+ Lv = Lnv = L;
+ }
+
+ if (top_u == v) {
+ Uv = Cudd_T(U);
+ Unv = Cudd_E(U);
+ if (Cudd_IsComplement(U)) {
+ Uv = Cudd_Not(Uv);
+ Unv = Cudd_Not(Unv);
+ }
+ }
+ else {
+ Uv = Unv = U;
+ }
+
+ Lsub0 = cuddBddAndRecur(dd, Lnv, Cudd_Not(Uv));
+ if (Lsub0 == NULL)
+ return(NULL);
+ Cudd_Ref(Lsub0);
+ Usub0 = Unv;
+ Lsub1 = cuddBddAndRecur(dd, Lv, Cudd_Not(Unv));
+ if (Lsub1 == NULL) {
+ Cudd_RecursiveDeref(dd, Lsub0);
+ return(NULL);
+ }
+ Cudd_Ref(Lsub1);
+ Usub1 = Uv;
+
+ Isub0 = cuddBddIsop(dd, Lsub0, Usub0);
+ if (Isub0 == NULL) {
+ Cudd_RecursiveDeref(dd, Lsub0);
+ Cudd_RecursiveDeref(dd, Lsub1);
+ return(NULL);
+ }
+ Cudd_Ref(Isub0);
+ Isub1 = cuddBddIsop(dd, Lsub1, Usub1);
+ if (Isub1 == NULL) {
+ Cudd_RecursiveDeref(dd, Lsub0);
+ Cudd_RecursiveDeref(dd, Lsub1);
+ Cudd_RecursiveDeref(dd, Isub0);
+ return(NULL);
+ }
+ Cudd_Ref(Isub1);
+ Cudd_RecursiveDeref(dd, Lsub0);
+ Cudd_RecursiveDeref(dd, Lsub1);
+
+ Lsuper0 = cuddBddAndRecur(dd, Lnv, Cudd_Not(Isub0));
+ if (Lsuper0 == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ return(NULL);
+ }
+ Cudd_Ref(Lsuper0);
+ Lsuper1 = cuddBddAndRecur(dd, Lv, Cudd_Not(Isub1));
+ if (Lsuper1 == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDeref(dd, Lsuper0);
+ return(NULL);
+ }
+ Cudd_Ref(Lsuper1);
+ Usuper0 = Unv;
+ Usuper1 = Uv;
+
+ /* Ld = Lsuper0 + Lsuper1 */
+ Ld = cuddBddAndRecur(dd, Cudd_Not(Lsuper0), Cudd_Not(Lsuper1));
+ Ld = Cudd_NotCond(Ld, Ld != NULL);
+ if (Ld == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDeref(dd, Lsuper0);
+ Cudd_RecursiveDeref(dd, Lsuper1);
+ return(NULL);
+ }
+ Cudd_Ref(Ld);
+ Ud = cuddBddAndRecur(dd, Usuper0, Usuper1);
+ if (Ud == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDeref(dd, Lsuper0);
+ Cudd_RecursiveDeref(dd, Lsuper1);
+ Cudd_RecursiveDeref(dd, Ld);
+ return(NULL);
+ }
+ Cudd_Ref(Ud);
+ Cudd_RecursiveDeref(dd, Lsuper0);
+ Cudd_RecursiveDeref(dd, Lsuper1);
+
+ Id = cuddBddIsop(dd, Ld, Ud);
+ if (Id == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDeref(dd, Ld);
+ Cudd_RecursiveDeref(dd, Ud);
+ return(NULL);
+ }
+ Cudd_Ref(Id);
+ Cudd_RecursiveDeref(dd, Ld);
+ Cudd_RecursiveDeref(dd, Ud);
+
+ x = cuddUniqueInter(dd, index, one, zero);
+ if (x == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDeref(dd, Id);
+ return(NULL);
+ }
+ Cudd_Ref(x);
+ term0 = cuddBddAndRecur(dd, Cudd_Not(x), Isub0);
+ if (term0 == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDeref(dd, Id);
+ Cudd_RecursiveDeref(dd, x);
+ return(NULL);
+ }
+ Cudd_Ref(term0);
+ Cudd_RecursiveDeref(dd, Isub0);
+ term1 = cuddBddAndRecur(dd, x, Isub1);
+ if (term1 == NULL) {
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDeref(dd, Id);
+ Cudd_RecursiveDeref(dd, x);
+ Cudd_RecursiveDeref(dd, term0);
+ return(NULL);
+ }
+ Cudd_Ref(term1);
+ Cudd_RecursiveDeref(dd, x);
+ Cudd_RecursiveDeref(dd, Isub1);
+ /* sum = term0 + term1 */
+ sum = cuddBddAndRecur(dd, Cudd_Not(term0), Cudd_Not(term1));
+ sum = Cudd_NotCond(sum, sum != NULL);
+ if (sum == NULL) {
+ Cudd_RecursiveDeref(dd, Id);
+ Cudd_RecursiveDeref(dd, term0);
+ Cudd_RecursiveDeref(dd, term1);
+ return(NULL);
+ }
+ Cudd_Ref(sum);
+ Cudd_RecursiveDeref(dd, term0);
+ Cudd_RecursiveDeref(dd, term1);
+ /* r = sum + Id */
+ r = cuddBddAndRecur(dd, Cudd_Not(sum), Cudd_Not(Id));
+ r = Cudd_NotCond(r, r != NULL);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, Id);
+ Cudd_RecursiveDeref(dd, sum);
+ return(NULL);
+ }
+ Cudd_Ref(r);
+ Cudd_RecursiveDeref(dd, sum);
+ Cudd_RecursiveDeref(dd, Id);
+
+ cuddCacheInsert2(dd, cuddBddIsop, L, U, r);
+
+ Cudd_Deref(r);
+ return(r);
+
+} /* end of cuddBddIsop */
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts a ZDD cover to a BDD graph.]
+
+ Description [Converts a ZDD cover to a BDD graph. If successful, it
+ returns a BDD node, otherwise it returns NULL. It is a recursive
+ algorithm as the following. First computes 3 cofactors of a ZDD cover;
+ f1, f0 and fd. Second, compute BDDs(b1, b0 and bd) of f1, f0 and fd.
+ Third, compute T=b1+bd and E=b0+bd. Fourth, compute ITE(v,T,E) where v
+ is the variable which has the index of the top node of the ZDD cover.
+ In this case, since the index of v can be larger than either one of T or
+ one of E, cuddUniqueInterIVO is called, here IVO stands for
+ independent variable ordering.]
+
+ SideEffects []
+
+ SeeAlso [Cudd_MakeBddFromZddCover]
+
+******************************************************************************/
+DdNode *
+cuddMakeBddFromZddCover(
+ DdManager * dd,
+ DdNode * node)
+{
+ DdNode *neW;
+ int v;
+ DdNode *f1, *f0, *fd;
+ DdNode *b1, *b0, *bd;
+ DdNode *T, *E;
+
+ statLine(dd);
+ if (node == dd->one)
+ return(dd->one);
+ if (node == dd->zero)
+ return(Cudd_Not(dd->one));
+
+ /* Check cache */
+ neW = cuddCacheLookup1(dd, cuddMakeBddFromZddCover, node);
+ if (neW)
+ return(neW);
+
+ v = Cudd_Regular(node)->index; /* either yi or zi */
+ cuddZddGetCofactors3(dd, node, v, &f1, &f0, &fd);
+ Cudd_Ref(f1);
+ Cudd_Ref(f0);
+ Cudd_Ref(fd);
+
+ b1 = cuddMakeBddFromZddCover(dd, f1);
+ if (!b1) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ return(NULL);
+ }
+ Cudd_Ref(b1);
+ b0 = cuddMakeBddFromZddCover(dd, f0);
+ if (!b1) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDeref(dd, b1);
+ return(NULL);
+ }
+ Cudd_Ref(b0);
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ if (fd != dd->zero) {
+ bd = cuddMakeBddFromZddCover(dd, fd);
+ if (!bd) {
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDeref(dd, b1);
+ Cudd_RecursiveDeref(dd, b0);
+ return(NULL);
+ }
+ Cudd_Ref(bd);
+ Cudd_RecursiveDerefZdd(dd, fd);
+
+ T = cuddBddAndRecur(dd, Cudd_Not(b1), Cudd_Not(bd));
+ if (!T) {
+ Cudd_RecursiveDeref(dd, b1);
+ Cudd_RecursiveDeref(dd, b0);
+ Cudd_RecursiveDeref(dd, bd);
+ return(NULL);
+ }
+ T = Cudd_NotCond(T, T != NULL);
+ Cudd_Ref(T);
+ Cudd_RecursiveDeref(dd, b1);
+ E = cuddBddAndRecur(dd, Cudd_Not(b0), Cudd_Not(bd));
+ if (!E) {
+ Cudd_RecursiveDeref(dd, b0);
+ Cudd_RecursiveDeref(dd, bd);
+ Cudd_RecursiveDeref(dd, T);
+ return(NULL);
+ }
+ E = Cudd_NotCond(E, E != NULL);
+ Cudd_Ref(E);
+ Cudd_RecursiveDeref(dd, b0);
+ Cudd_RecursiveDeref(dd, bd);
+ }
+ else {
+ Cudd_RecursiveDerefZdd(dd, fd);
+ T = b1;
+ E = b0;
+ }
+
+ if (Cudd_IsComplement(T)) {
+ neW = cuddUniqueInterIVO(dd, v / 2, Cudd_Not(T), Cudd_Not(E));
+ if (!neW) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ neW = Cudd_Not(neW);
+ }
+ else {
+ neW = cuddUniqueInterIVO(dd, v / 2, T, E);
+ if (!neW) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ }
+ Cudd_Ref(neW);
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+
+ cuddCacheInsert1(dd, cuddMakeBddFromZddCover, node, neW);
+ Cudd_Deref(neW);
+ return(neW);
+
+} /* end of cuddMakeBddFromZddCover */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/cudd/cuddZddLin.c b/src/bdd/cudd/cuddZddLin.c
new file mode 100644
index 00000000..9369bb05
--- /dev/null
+++ b/src/bdd/cudd/cuddZddLin.c
@@ -0,0 +1,939 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddLin.c]
+
+ PackageName [cudd]
+
+ Synopsis [Procedures for dynamic variable ordering of ZDDs.]
+
+ Description [Internal procedures included in this module:
+ <ul>
+ <li> cuddZddLinearSifting()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddZddLinearInPlace()
+ <li> cuddZddLinerAux()
+ <li> cuddZddLinearUp()
+ <li> cuddZddLinearDown()
+ <li> cuddZddLinearBackward()
+ <li> cuddZddUndoMoves()
+ </ul>
+ ]
+
+ SeeAlso [cuddLinear.c cuddZddReord.c]
+
+ Author [Fabio Somenzi]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define CUDD_SWAP_MOVE 0
+#define CUDD_LINEAR_TRANSFORM_MOVE 1
+#define CUDD_INVERSE_TRANSFORM_MOVE 2
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddLin.c,v 1.1.1.1 2003/02/24 22:23:54 wjiang Exp $";
+#endif
+
+extern int *zdd_entry;
+extern int zddTotalNumberSwapping;
+static int zddTotalNumberLinearTr;
+static DdNode *empty;
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int cuddZddLinearAux ARGS((DdManager *table, int x, int xLow, int xHigh));
+static Move * cuddZddLinearUp ARGS((DdManager *table, int y, int xLow, Move *prevMoves));
+static Move * cuddZddLinearDown ARGS((DdManager *table, int x, int xHigh, Move *prevMoves));
+static int cuddZddLinearBackward ARGS((DdManager *table, int size, Move *moves));
+static Move* cuddZddUndoMoves ARGS((DdManager *table, Move *moves));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+
+
+/**Function********************************************************************
+
+ Synopsis [Implementation of the linear sifting algorithm for ZDDs.]
+
+ Description [Implementation of the linear sifting algorithm for ZDDs.
+ Assumes that no dead nodes are present.
+ <ol>
+ <li> Order all the variables according to the number of entries
+ in each unique table.
+ <li> Sift the variable up and down and applies the XOR transformation,
+ remembering each time the total size of the DD heap.
+ <li> Select the best permutation.
+ <li> Repeat 3 and 4 for all variables.
+ </ol>
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddLinearSifting(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i;
+ int *var;
+ int size;
+ int x;
+ int result;
+#ifdef DD_STATS
+ int previousSize;
+#endif
+
+ size = table->sizeZ;
+ empty = table->zero;
+
+ /* Find order in which to sift variables. */
+ var = NULL;
+ zdd_entry = ALLOC(int, size);
+ if (zdd_entry == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddZddSiftingOutOfMem;
+ }
+ var = ALLOC(int, size);
+ if (var == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddZddSiftingOutOfMem;
+ }
+
+ for (i = 0; i < size; i++) {
+ x = table->permZ[i];
+ zdd_entry[i] = table->subtableZ[x].keys;
+ var[i] = i;
+ }
+
+ qsort((void *)var, size, sizeof(int), (int (*)(const void *, const void *))cuddZddUniqueCompare);
+
+ /* Now sift. */
+ for (i = 0; i < ddMin(table->siftMaxVar, size); i++) {
+ if (zddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ x = table->permZ[var[i]];
+ if (x < lower || x > upper) continue;
+#ifdef DD_STATS
+ previousSize = table->keysZ;
+#endif
+ result = cuddZddLinearAux(table, x, lower, upper);
+ if (!result)
+ goto cuddZddSiftingOutOfMem;
+#ifdef DD_STATS
+ if (table->keysZ < (unsigned) previousSize) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keysZ > (unsigned) previousSize) {
+ (void) fprintf(table->out,"+"); /* should never happen */
+ (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ , var[i]);
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+
+ FREE(var);
+ FREE(zdd_entry);
+
+ return(1);
+
+cuddZddSiftingOutOfMem:
+
+ if (zdd_entry != NULL) FREE(zdd_entry);
+ if (var != NULL) FREE(var);
+
+ return(0);
+
+} /* end of cuddZddLinearSifting */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Linearly combines two adjacent variables.]
+
+ Description [Linearly combines two adjacent variables. It assumes
+ that no dead nodes are present on entry to this procedure. The
+ procedure then guarantees that no dead nodes will be present when it
+ terminates. cuddZddLinearInPlace assumes that x &lt; y. Returns the
+ number of keys in the table if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddZddSwapInPlace cuddLinearInPlace]
+
+******************************************************************************/
+int
+cuddZddLinearInPlace(
+ DdManager * table,
+ int x,
+ int y)
+{
+ DdNodePtr *xlist, *ylist;
+ int xindex, yindex;
+ int xslots, yslots;
+ int xshift, yshift;
+ int oldxkeys, oldykeys;
+ int newxkeys, newykeys;
+ int i;
+ int posn;
+ DdNode *f, *f1, *f0, *f11, *f10, *f01, *f00;
+ DdNode *newf1, *newf0, *g, *next, *previous;
+ DdNode *special;
+
+#ifdef DD_DEBUG
+ assert(x < y);
+ assert(cuddZddNextHigh(table,x) == y);
+ assert(table->subtableZ[x].keys != 0);
+ assert(table->subtableZ[y].keys != 0);
+ assert(table->subtableZ[x].dead == 0);
+ assert(table->subtableZ[y].dead == 0);
+#endif
+
+ zddTotalNumberLinearTr++;
+
+ /* Get parameters of x subtable. */
+ xindex = table->invpermZ[x];
+ xlist = table->subtableZ[x].nodelist;
+ oldxkeys = table->subtableZ[x].keys;
+ xslots = table->subtableZ[x].slots;
+ xshift = table->subtableZ[x].shift;
+ newxkeys = 0;
+
+ /* Get parameters of y subtable. */
+ yindex = table->invpermZ[y];
+ ylist = table->subtableZ[y].nodelist;
+ oldykeys = table->subtableZ[y].keys;
+ yslots = table->subtableZ[y].slots;
+ yshift = table->subtableZ[y].shift;
+ newykeys = oldykeys;
+
+ /* The nodes in the x layer are put in two chains. The chain
+ ** pointed by g holds the normal nodes. When re-expressed they stay
+ ** in the x list. The chain pointed by special holds the elements
+ ** that will move to the y list.
+ */
+ g = special = NULL;
+ for (i = 0; i < xslots; i++) {
+ f = xlist[i];
+ if (f == NULL) continue;
+ xlist[i] = NULL;
+ while (f != NULL) {
+ next = f->next;
+ f1 = cuddT(f);
+ /* if (f1->index == yindex) */ cuddSatDec(f1->ref);
+ f0 = cuddE(f);
+ /* if (f0->index == yindex) */ cuddSatDec(f0->ref);
+ if ((int) f1->index == yindex && cuddE(f1) == empty &&
+ (int) f0->index != yindex) {
+ f->next = special;
+ special = f;
+ } else {
+ f->next = g;
+ g = f;
+ }
+ f = next;
+ } /* while there are elements in the collision chain */
+ } /* for each slot of the x subtable */
+
+ /* Mark y nodes with pointers from above x. We mark them by
+ ** changing their index to x.
+ */
+ for (i = 0; i < yslots; i++) {
+ f = ylist[i];
+ while (f != NULL) {
+ if (f->ref != 0) {
+ f->index = xindex;
+ }
+ f = f->next;
+ } /* while there are elements in the collision chain */
+ } /* for each slot of the y subtable */
+
+ /* Move special nodes to the y list. */
+ f = special;
+ while (f != NULL) {
+ next = f->next;
+ f1 = cuddT(f);
+ f11 = cuddT(f1);
+ cuddT(f) = f11;
+ cuddSatInc(f11->ref);
+ f0 = cuddE(f);
+ cuddSatInc(f0->ref);
+ f->index = yindex;
+ /* Insert at the beginning of the list so that it will be
+ ** found first if there is a duplicate. The duplicate will
+ ** eventually be moved or garbage collected. No node
+ ** re-expression will add a pointer to it.
+ */
+ posn = ddHash(f11, f0, yshift);
+ f->next = ylist[posn];
+ ylist[posn] = f;
+ newykeys++;
+ f = next;
+ }
+
+ /* Take care of the remaining x nodes that must be re-expressed.
+ ** They form a linked list pointed by g.
+ */
+ f = g;
+ while (f != NULL) {
+#ifdef DD_COUNT
+ table->swapSteps++;
+#endif
+ next = f->next;
+ /* Find f1, f0, f11, f10, f01, f00. */
+ f1 = cuddT(f);
+ if ((int) f1->index == yindex || (int) f1->index == xindex) {
+ f11 = cuddT(f1); f10 = cuddE(f1);
+ } else {
+ f11 = empty; f10 = f1;
+ }
+ f0 = cuddE(f);
+ if ((int) f0->index == yindex || (int) f0->index == xindex) {
+ f01 = cuddT(f0); f00 = cuddE(f0);
+ } else {
+ f01 = empty; f00 = f0;
+ }
+ /* Create the new T child. */
+ if (f01 == empty) {
+ newf1 = f10;
+ cuddSatInc(newf1->ref);
+ } else {
+ /* Check ylist for triple (yindex, f01, f10). */
+ posn = ddHash(f01, f10, yshift);
+ /* For each element newf1 in collision list ylist[posn]. */
+ newf1 = ylist[posn];
+ /* Search the collision chain skipping the marked nodes. */
+ while (newf1 != NULL) {
+ if (cuddT(newf1) == f01 && cuddE(newf1) == f10 &&
+ (int) newf1->index == yindex) {
+ cuddSatInc(newf1->ref);
+ break; /* match */
+ }
+ newf1 = newf1->next;
+ } /* while newf1 */
+ if (newf1 == NULL) { /* no match */
+ newf1 = cuddDynamicAllocNode(table);
+ if (newf1 == NULL)
+ goto zddSwapOutOfMem;
+ newf1->index = yindex; newf1->ref = 1;
+ cuddT(newf1) = f01;
+ cuddE(newf1) = f10;
+ /* Insert newf1 in the collision list ylist[pos];
+ ** increase the ref counts of f01 and f10
+ */
+ newykeys++;
+ newf1->next = ylist[posn];
+ ylist[posn] = newf1;
+ cuddSatInc(f01->ref);
+ cuddSatInc(f10->ref);
+ }
+ }
+ cuddT(f) = newf1;
+
+ /* Do the same for f0. */
+ /* Create the new E child. */
+ if (f11 == empty) {
+ newf0 = f00;
+ cuddSatInc(newf0->ref);
+ } else {
+ /* Check ylist for triple (yindex, f11, f00). */
+ posn = ddHash(f11, f00, yshift);
+ /* For each element newf0 in collision list ylist[posn]. */
+ newf0 = ylist[posn];
+ while (newf0 != NULL) {
+ if (cuddT(newf0) == f11 && cuddE(newf0) == f00 &&
+ (int) newf0->index == yindex) {
+ cuddSatInc(newf0->ref);
+ break; /* match */
+ }
+ newf0 = newf0->next;
+ } /* while newf0 */
+ if (newf0 == NULL) { /* no match */
+ newf0 = cuddDynamicAllocNode(table);
+ if (newf0 == NULL)
+ goto zddSwapOutOfMem;
+ newf0->index = yindex; newf0->ref = 1;
+ cuddT(newf0) = f11; cuddE(newf0) = f00;
+ /* Insert newf0 in the collision list ylist[posn];
+ ** increase the ref counts of f11 and f00.
+ */
+ newykeys++;
+ newf0->next = ylist[posn];
+ ylist[posn] = newf0;
+ cuddSatInc(f11->ref);
+ cuddSatInc(f00->ref);
+ }
+ }
+ cuddE(f) = newf0;
+
+ /* Re-insert the modified f in xlist.
+ ** The modified f does not already exists in xlist.
+ ** (Because of the uniqueness of the cofactors.)
+ */
+ posn = ddHash(newf1, newf0, xshift);
+ newxkeys++;
+ f->next = xlist[posn];
+ xlist[posn] = f;
+ f = next;
+ } /* while f != NULL */
+
+ /* GC the y layer and move the marked nodes to the x list. */
+
+ /* For each node f in ylist. */
+ for (i = 0; i < yslots; i++) {
+ previous = NULL;
+ f = ylist[i];
+ while (f != NULL) {
+ next = f->next;
+ if (f->ref == 0) {
+ cuddSatDec(cuddT(f)->ref);
+ cuddSatDec(cuddE(f)->ref);
+ cuddDeallocNode(table, f);
+ newykeys--;
+ if (previous == NULL)
+ ylist[i] = next;
+ else
+ previous->next = next;
+ } else if ((int) f->index == xindex) { /* move marked node */
+ if (previous == NULL)
+ ylist[i] = next;
+ else
+ previous->next = next;
+ f1 = cuddT(f);
+ cuddSatDec(f1->ref);
+ /* Check ylist for triple (yindex, f1, empty). */
+ posn = ddHash(f1, empty, yshift);
+ /* For each element newf1 in collision list ylist[posn]. */
+ newf1 = ylist[posn];
+ while (newf1 != NULL) {
+ if (cuddT(newf1) == f1 && cuddE(newf1) == empty &&
+ (int) newf1->index == yindex) {
+ cuddSatInc(newf1->ref);
+ break; /* match */
+ }
+ newf1 = newf1->next;
+ } /* while newf1 */
+ if (newf1 == NULL) { /* no match */
+ newf1 = cuddDynamicAllocNode(table);
+ if (newf1 == NULL)
+ goto zddSwapOutOfMem;
+ newf1->index = yindex; newf1->ref = 1;
+ cuddT(newf1) = f1; cuddE(newf1) = empty;
+ /* Insert newf1 in the collision list ylist[posn];
+ ** increase the ref counts of f1 and empty.
+ */
+ newykeys++;
+ newf1->next = ylist[posn];
+ ylist[posn] = newf1;
+ if (posn == i && previous == NULL)
+ previous = newf1;
+ cuddSatInc(f1->ref);
+ cuddSatInc(empty->ref);
+ }
+ cuddT(f) = newf1;
+ f0 = cuddE(f);
+ /* Insert f in x list. */
+ posn = ddHash(newf1, f0, xshift);
+ newxkeys++;
+ newykeys--;
+ f->next = xlist[posn];
+ xlist[posn] = f;
+ } else {
+ previous = f;
+ }
+ f = next;
+ } /* while f */
+ } /* for i */
+
+ /* Set the appropriate fields in table. */
+ table->subtableZ[x].keys = newxkeys;
+ table->subtableZ[y].keys = newykeys;
+
+ table->keysZ += newxkeys + newykeys - oldxkeys - oldykeys;
+
+ /* Update univ section; univ[x] remains the same. */
+ table->univ[y] = cuddT(table->univ[x]);
+
+#if 0
+ (void) fprintf(table->out,"x = %d y = %d\n", x, y);
+ (void) Cudd_DebugCheck(table);
+ (void) Cudd_CheckKeys(table);
+#endif
+
+ return (table->keysZ);
+
+zddSwapOutOfMem:
+ (void) fprintf(table->err, "Error: cuddZddSwapInPlace out of memory\n");
+
+ return (0);
+
+} /* end of cuddZddLinearInPlace */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries.]
+
+ Description [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries. Finds the best position and does the required changes.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddZddLinearAux(
+ DdManager * table,
+ int x,
+ int xLow,
+ int xHigh)
+{
+ Move *move;
+ Move *moveUp; /* list of up move */
+ Move *moveDown; /* list of down move */
+
+ int initial_size;
+ int result;
+
+ initial_size = table->keysZ;
+
+#ifdef DD_DEBUG
+ assert(table->subtableZ[x].keys > 0);
+#endif
+
+ moveDown = NULL;
+ moveUp = NULL;
+
+ if (x == xLow) {
+ moveDown = cuddZddLinearDown(table, x, xHigh, NULL);
+ /* At this point x --> xHigh. */
+ if (moveDown == (Move *) CUDD_OUT_OF_MEM)
+ goto cuddZddLinearAuxOutOfMem;
+ /* Move backward and stop at best position. */
+ result = cuddZddLinearBackward(table, initial_size, moveDown);
+ if (!result)
+ goto cuddZddLinearAuxOutOfMem;
+
+ } else if (x == xHigh) {
+ moveUp = cuddZddLinearUp(table, x, xLow, NULL);
+ /* At this point x --> xLow. */
+ if (moveUp == (Move *) CUDD_OUT_OF_MEM)
+ goto cuddZddLinearAuxOutOfMem;
+ /* Move backward and stop at best position. */
+ result = cuddZddLinearBackward(table, initial_size, moveUp);
+ if (!result)
+ goto cuddZddLinearAuxOutOfMem;
+
+ } else if ((x - xLow) > (xHigh - x)) { /* must go down first: shorter */
+ moveDown = cuddZddLinearDown(table, x, xHigh, NULL);
+ /* At this point x --> xHigh. */
+ if (moveDown == (Move *) CUDD_OUT_OF_MEM)
+ goto cuddZddLinearAuxOutOfMem;
+ moveUp = cuddZddUndoMoves(table,moveDown);
+#ifdef DD_DEBUG
+ assert(moveUp == NULL || moveUp->x == x);
+#endif
+ moveUp = cuddZddLinearUp(table, x, xLow, moveUp);
+ if (moveUp == (Move *) CUDD_OUT_OF_MEM)
+ goto cuddZddLinearAuxOutOfMem;
+ /* Move backward and stop at best position. */
+ result = cuddZddLinearBackward(table, initial_size, moveUp);
+ if (!result)
+ goto cuddZddLinearAuxOutOfMem;
+
+ } else {
+ moveUp = cuddZddLinearUp(table, x, xLow, NULL);
+ /* At this point x --> xHigh. */
+ if (moveUp == (Move *) CUDD_OUT_OF_MEM)
+ goto cuddZddLinearAuxOutOfMem;
+ /* Then move up. */
+ moveDown = cuddZddUndoMoves(table,moveUp);
+#ifdef DD_DEBUG
+ assert(moveDown == NULL || moveDown->y == x);
+#endif
+ moveDown = cuddZddLinearDown(table, x, xHigh, moveDown);
+ if (moveDown == (Move *) CUDD_OUT_OF_MEM)
+ goto cuddZddLinearAuxOutOfMem;
+ /* Move backward and stop at best position. */
+ result = cuddZddLinearBackward(table, initial_size, moveDown);
+ if (!result)
+ goto cuddZddLinearAuxOutOfMem;
+ }
+
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *)moveDown);
+ moveDown = move;
+ }
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *)moveUp);
+ moveUp = move;
+ }
+
+ return(1);
+
+cuddZddLinearAuxOutOfMem:
+ if (moveDown != (Move *) CUDD_OUT_OF_MEM) {
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *)moveDown);
+ moveDown = move;
+ }
+ }
+ if (moveUp != (Move *) CUDD_OUT_OF_MEM) {
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *)moveUp);
+ moveUp = move;
+ }
+ }
+
+ return(0);
+
+} /* end of cuddZddLinearAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts a variable up applying the XOR transformation.]
+
+ Description [Sifts a variable up applying the XOR
+ transformation. Moves y up until either it reaches the bound (xLow)
+ or the size of the ZDD heap increases too much. Returns the set of
+ moves in case of success; NULL if memory is full.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static Move *
+cuddZddLinearUp(
+ DdManager * table,
+ int y,
+ int xLow,
+ Move * prevMoves)
+{
+ Move *moves;
+ Move *move;
+ int x;
+ int size, newsize;
+ int limitSize;
+
+ moves = prevMoves;
+ limitSize = table->keysZ;
+
+ x = cuddZddNextLow(table, y);
+ while (x >= xLow) {
+ size = cuddZddSwapInPlace(table, x, y);
+ if (size == 0)
+ goto cuddZddLinearUpOutOfMem;
+ newsize = cuddZddLinearInPlace(table, x, y);
+ if (newsize == 0)
+ goto cuddZddLinearUpOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto cuddZddLinearUpOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->next = moves;
+ moves = move;
+ move->flags = CUDD_SWAP_MOVE;
+ if (newsize > size) {
+ /* Undo transformation. The transformation we apply is
+ ** its own inverse. Hence, we just apply the transformation
+ ** again.
+ */
+ newsize = cuddZddLinearInPlace(table,x,y);
+ if (newsize == 0) goto cuddZddLinearUpOutOfMem;
+#ifdef DD_DEBUG
+ if (newsize != size) {
+ (void) fprintf(table->err,"Change in size after identity transformation! From %d to %d\n",size,newsize);
+ }
+#endif
+ } else {
+ size = newsize;
+ move->flags = CUDD_LINEAR_TRANSFORM_MOVE;
+ }
+ move->size = size;
+
+ if ((double)size > (double)limitSize * table->maxGrowth)
+ break;
+ if (size < limitSize)
+ limitSize = size;
+
+ y = x;
+ x = cuddZddNextLow(table, y);
+ }
+ return(moves);
+
+cuddZddLinearUpOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *)moves);
+ moves = move;
+ }
+ return((Move *) CUDD_OUT_OF_MEM);
+
+} /* end of cuddZddLinearUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts a variable down and applies the XOR transformation.]
+
+ Description [Sifts a variable down. Moves x down until either it
+ reaches the bound (xHigh) or the size of the ZDD heap increases too
+ much. Returns the set of moves in case of success; NULL if memory is
+ full.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static Move *
+cuddZddLinearDown(
+ DdManager * table,
+ int x,
+ int xHigh,
+ Move * prevMoves)
+{
+ Move *moves;
+ Move *move;
+ int y;
+ int size, newsize;
+ int limitSize;
+
+ moves = prevMoves;
+ limitSize = table->keysZ;
+
+ y = cuddZddNextHigh(table, x);
+ while (y <= xHigh) {
+ size = cuddZddSwapInPlace(table, x, y);
+ if (size == 0)
+ goto cuddZddLinearDownOutOfMem;
+ newsize = cuddZddLinearInPlace(table, x, y);
+ if (newsize == 0)
+ goto cuddZddLinearDownOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto cuddZddLinearDownOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->next = moves;
+ moves = move;
+ move->flags = CUDD_SWAP_MOVE;
+ if (newsize > size) {
+ /* Undo transformation. The transformation we apply is
+ ** its own inverse. Hence, we just apply the transformation
+ ** again.
+ */
+ newsize = cuddZddLinearInPlace(table,x,y);
+ if (newsize == 0) goto cuddZddLinearDownOutOfMem;
+ if (newsize != size) {
+ (void) fprintf(table->err,"Change in size after identity transformation! From %d to %d\n",size,newsize);
+ }
+ } else {
+ size = newsize;
+ move->flags = CUDD_LINEAR_TRANSFORM_MOVE;
+ }
+ move->size = size;
+
+ if ((double)size > (double)limitSize * table->maxGrowth)
+ break;
+ if (size < limitSize)
+ limitSize = size;
+
+ x = y;
+ y = cuddZddNextHigh(table, x);
+ }
+ return(moves);
+
+cuddZddLinearDownOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *)moves);
+ moves = move;
+ }
+ return((Move *) CUDD_OUT_OF_MEM);
+
+} /* end of cuddZddLinearDown */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given a set of moves, returns the ZDD heap to the position
+ giving the minimum size.]
+
+ Description [Given a set of moves, returns the ZDD heap to the
+ position giving the minimum size. In case of ties, returns to the
+ closest position giving the minimum size. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddZddLinearBackward(
+ DdManager * table,
+ int size,
+ Move * moves)
+{
+ Move *move;
+ int res;
+
+ /* Find the minimum size among moves. */
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size < size) {
+ size = move->size;
+ }
+ }
+
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size == size) return(1);
+ if (move->flags == CUDD_LINEAR_TRANSFORM_MOVE) {
+ res = cuddZddLinearInPlace(table,(int)move->x,(int)move->y);
+ if (!res) return(0);
+ }
+ res = cuddZddSwapInPlace(table, move->x, move->y);
+ if (!res)
+ return(0);
+ if (move->flags == CUDD_INVERSE_TRANSFORM_MOVE) {
+ res = cuddZddLinearInPlace(table,(int)move->x,(int)move->y);
+ if (!res) return(0);
+ }
+ }
+
+ return(1);
+
+} /* end of cuddZddLinearBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given a set of moves, returns the ZDD heap to the order
+ in effect before the moves.]
+
+ Description [Given a set of moves, returns the ZDD heap to the
+ order in effect before the moves. Returns 1 in case of success;
+ 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static Move*
+cuddZddUndoMoves(
+ DdManager * table,
+ Move * moves)
+{
+ Move *invmoves = NULL;
+ Move *move;
+ Move *invmove;
+ int size;
+
+ for (move = moves; move != NULL; move = move->next) {
+ invmove = (Move *) cuddDynamicAllocNode(table);
+ if (invmove == NULL) goto cuddZddUndoMovesOutOfMem;
+ invmove->x = move->x;
+ invmove->y = move->y;
+ invmove->next = invmoves;
+ invmoves = invmove;
+ if (move->flags == CUDD_SWAP_MOVE) {
+ invmove->flags = CUDD_SWAP_MOVE;
+ size = cuddZddSwapInPlace(table,(int)move->x,(int)move->y);
+ if (!size) goto cuddZddUndoMovesOutOfMem;
+ } else if (move->flags == CUDD_LINEAR_TRANSFORM_MOVE) {
+ invmove->flags = CUDD_INVERSE_TRANSFORM_MOVE;
+ size = cuddZddLinearInPlace(table,(int)move->x,(int)move->y);
+ if (!size) goto cuddZddUndoMovesOutOfMem;
+ size = cuddZddSwapInPlace(table,(int)move->x,(int)move->y);
+ if (!size) goto cuddZddUndoMovesOutOfMem;
+ } else { /* must be CUDD_INVERSE_TRANSFORM_MOVE */
+#ifdef DD_DEBUG
+ (void) fprintf(table->err,"Unforseen event in ddUndoMoves!\n");
+#endif
+ invmove->flags = CUDD_LINEAR_TRANSFORM_MOVE;
+ size = cuddZddSwapInPlace(table,(int)move->x,(int)move->y);
+ if (!size) goto cuddZddUndoMovesOutOfMem;
+ size = cuddZddLinearInPlace(table,(int)move->x,(int)move->y);
+ if (!size) goto cuddZddUndoMovesOutOfMem;
+ }
+ invmove->size = size;
+ }
+
+ return(invmoves);
+
+cuddZddUndoMovesOutOfMem:
+ while (invmoves != NULL) {
+ move = invmoves->next;
+ cuddDeallocNode(table, (DdNode *) invmoves);
+ invmoves = move;
+ }
+ return((Move *) CUDD_OUT_OF_MEM);
+
+} /* end of cuddZddUndoMoves */
+
diff --git a/src/bdd/cudd/cuddZddMisc.c b/src/bdd/cudd/cuddZddMisc.c
new file mode 100644
index 00000000..d55bb768
--- /dev/null
+++ b/src/bdd/cudd/cuddZddMisc.c
@@ -0,0 +1,252 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddMisc.c]
+
+ PackageName [cudd]
+
+ Synopsis [.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_zddDagSize()
+ <li> Cudd_zddCountMinterm()
+ <li> Cudd_zddPrintSubtable()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddZddDagInt()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Hyong-Kyoon Shin, In-Ho Moon]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include <math.h>
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddMisc.c,v 1.1.1.1 2003/02/24 22:23:54 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int cuddZddDagInt ARGS((DdNode *n, st_table *tab));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of nodes in a ZDD.]
+
+ Description [Counts the number of nodes in a ZDD. This function
+ duplicates Cudd_DagSize and is only retained for compatibility.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DagSize]
+
+******************************************************************************/
+int
+Cudd_zddDagSize(
+ DdNode * p_node)
+{
+
+ int i;
+ st_table *table;
+
+ table = st_init_table(st_ptrcmp, st_ptrhash);
+ i = cuddZddDagInt(p_node, table);
+ st_free_table(table);
+ return(i);
+
+} /* end of Cudd_zddDagSize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of minterms of a ZDD.]
+
+ Description [Counts the number of minterms of the ZDD rooted at
+ <code>node</code>. This procedure takes a parameter
+ <code>path</code> that specifies how many variables are in the
+ support of the function. If the procedure runs out of memory, it
+ returns (double) CUDD_OUT_OF_MEM.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddCountDouble]
+
+******************************************************************************/
+double
+Cudd_zddCountMinterm(
+ DdManager * zdd,
+ DdNode * node,
+ int path)
+{
+ double dc_var, minterms;
+
+ dc_var = (double)((double)(zdd->sizeZ) - (double)path);
+ minterms = Cudd_zddCountDouble(zdd, node) / pow(2.0, dc_var);
+ return(minterms);
+
+} /* end of Cudd_zddCountMinterm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints the ZDD table.]
+
+ Description [Prints the ZDD table for debugging purposes.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+Cudd_zddPrintSubtable(
+ DdManager * table)
+{
+ int i, j;
+ DdNode *z1, *z1_next, *base;
+ DdSubtable *ZSubTable;
+
+ base = table->one;
+ for (i = table->sizeZ - 1; i >= 0; i--) {
+ ZSubTable = &(table->subtableZ[i]);
+ printf("subtable[%d]:\n", i);
+ for (j = ZSubTable->slots - 1; j >= 0; j--) {
+ z1 = ZSubTable->nodelist[j];
+ while (z1 != NIL(DdNode)) {
+ (void) fprintf(table->out,
+#if SIZEOF_VOID_P == 8
+ "ID = 0x%lx\tindex = %d\tr = %d\t",
+ (unsigned long) z1 / (unsigned long) sizeof(DdNode),
+ z1->index, z1->ref);
+#else
+ "ID = 0x%x\tindex = %d\tr = %d\t",
+ (unsigned) z1 / (unsigned) sizeof(DdNode),
+ z1->index, z1->ref);
+#endif
+ z1_next = cuddT(z1);
+ if (Cudd_IsConstant(z1_next)) {
+ (void) fprintf(table->out, "T = %d\t\t",
+ (z1_next == base));
+ }
+ else {
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(table->out, "T = 0x%lx\t",
+ (unsigned long) z1_next / (unsigned long) sizeof(DdNode));
+#else
+ (void) fprintf(table->out, "T = 0x%x\t",
+ (unsigned) z1_next / (unsigned) sizeof(DdNode));
+#endif
+ }
+ z1_next = cuddE(z1);
+ if (Cudd_IsConstant(z1_next)) {
+ (void) fprintf(table->out, "E = %d\n",
+ (z1_next == base));
+ }
+ else {
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(table->out, "E = 0x%lx\n",
+ (unsigned long) z1_next / (unsigned long) sizeof(DdNode));
+#else
+ (void) fprintf(table->out, "E = 0x%x\n",
+ (unsigned) z1_next / (unsigned) sizeof(DdNode));
+#endif
+ }
+
+ z1_next = z1->next;
+ z1 = z1_next;
+ }
+ }
+ }
+ putchar('\n');
+
+} /* Cudd_zddPrintSubtable */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddDagSize.]
+
+ Description [Performs the recursive step of Cudd_zddDagSize. Does
+ not check for out-of-memory conditions.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddZddDagInt(
+ DdNode * n,
+ st_table * tab)
+{
+ if (n == NIL(DdNode))
+ return(0);
+
+ if (st_is_member(tab, (char *)n) == 1)
+ return(0);
+
+ if (Cudd_IsConstant(n))
+ return(0);
+
+ (void)st_insert(tab, (char *)n, NIL(char));
+ return(1 + cuddZddDagInt(cuddT(n), tab) +
+ cuddZddDagInt(cuddE(n), tab));
+
+} /* cuddZddDagInt */
+
diff --git a/src/bdd/cudd/cuddZddPort.c b/src/bdd/cudd/cuddZddPort.c
new file mode 100644
index 00000000..1700ab2b
--- /dev/null
+++ b/src/bdd/cudd/cuddZddPort.c
@@ -0,0 +1,354 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddPort.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions that translate BDDs to ZDDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_zddPortFromBdd()
+ <li> Cudd_zddPortToBdd()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> zddPortFromBddStep()
+ <li> zddPortToBddStep()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Hyong-kyoon Shin, In-Ho Moon]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddPort.c,v 1.1.1.1 2003/02/24 22:23:54 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdNode * zddPortFromBddStep ARGS((DdManager *dd, DdNode *B, int expected));
+static DdNode * zddPortToBddStep ARGS((DdManager *dd, DdNode *f, int depth));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts a BDD into a ZDD.]
+
+ Description [Converts a BDD into a ZDD. This function assumes that
+ there is a one-to-one correspondence between the BDD variables and the
+ ZDD variables, and that the variable order is the same for both types
+ of variables. These conditions are established if the ZDD variables
+ are created by one call to Cudd_zddVarsFromBddVars with multiplicity =
+ 1. Returns a pointer to the resulting ZDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddVarsFromBddVars]
+
+******************************************************************************/
+DdNode *
+Cudd_zddPortFromBdd(
+ DdManager * dd,
+ DdNode * B)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = zddPortFromBddStep(dd,B,0);
+ } while (dd->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_zddPortFromBdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts a ZDD into a BDD.]
+
+ Description [Converts a ZDD into a BDD. Returns a pointer to the resulting
+ ZDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddPortFromBdd]
+
+******************************************************************************/
+DdNode *
+Cudd_zddPortToBdd(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = zddPortToBddStep(dd,f,0);
+ } while (dd->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_zddPortToBdd */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddPortFromBdd.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+zddPortFromBddStep(
+ DdManager * dd,
+ DdNode * B,
+ int expected)
+{
+ DdNode *res, *prevZdd, *t, *e;
+ DdNode *Breg, *Bt, *Be;
+ int id, level;
+
+ statLine(dd);
+ /* Terminal cases. */
+ if (B == Cudd_Not(DD_ONE(dd)))
+ return(DD_ZERO(dd));
+ if (B == DD_ONE(dd)) {
+ if (expected >= dd->sizeZ) {
+ return(DD_ONE(dd));
+ } else {
+ return(dd->univ[expected]);
+ }
+ }
+
+ Breg = Cudd_Regular(B);
+
+ /* Computed table look-up. */
+ res = cuddCacheLookup1Zdd(dd,Cudd_zddPortFromBdd,B);
+ if (res != NULL) {
+ level = cuddI(dd,Breg->index);
+ /* Adding DC vars. */
+ if (expected < level) {
+ /* Add suppressed variables. */
+ cuddRef(res);
+ for (level--; level >= expected; level--) {
+ prevZdd = res;
+ id = dd->invperm[level];
+ res = cuddZddGetNode(dd, id, prevZdd, prevZdd);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(dd, prevZdd);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDerefZdd(dd, prevZdd);
+ }
+ cuddDeref(res);
+ }
+ return(res);
+ } /* end of cache look-up */
+
+ if (Cudd_IsComplement(B)) {
+ Bt = Cudd_Not(cuddT(Breg));
+ Be = Cudd_Not(cuddE(Breg));
+ } else {
+ Bt = cuddT(Breg);
+ Be = cuddE(Breg);
+ }
+
+ id = Breg->index;
+ level = cuddI(dd,id);
+ t = zddPortFromBddStep(dd, Bt, level+1);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = zddPortFromBddStep(dd, Be, level+1);
+ if (e == NULL) {
+ Cudd_RecursiveDerefZdd(dd, t);
+ return(NULL);
+ }
+ cuddRef(e);
+ res = cuddZddGetNode(dd, id, t, e);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(dd, t);
+ Cudd_RecursiveDerefZdd(dd, e);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDerefZdd(dd, t);
+ Cudd_RecursiveDerefZdd(dd, e);
+
+ cuddCacheInsert1(dd,Cudd_zddPortFromBdd,B,res);
+
+ for (level--; level >= expected; level--) {
+ prevZdd = res;
+ id = dd->invperm[level];
+ res = cuddZddGetNode(dd, id, prevZdd, prevZdd);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(dd, prevZdd);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDerefZdd(dd, prevZdd);
+ }
+
+ cuddDeref(res);
+ return(res);
+
+} /* end of zddPortFromBddStep */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddPortToBdd.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+zddPortToBddStep(
+ DdManager * dd /* manager */,
+ DdNode * f /* ZDD to be converted */,
+ int depth /* recursion depth */)
+{
+ DdNode *one, *zero, *T, *E, *res, *var;
+ unsigned int index;
+ unsigned int level;
+
+ statLine(dd);
+ one = DD_ONE(dd);
+ zero = DD_ZERO(dd);
+ if (f == zero) return(Cudd_Not(one));
+
+ if (depth == dd->sizeZ) return(one);
+
+ index = dd->invpermZ[depth];
+ level = cuddIZ(dd,f->index);
+ var = cuddUniqueInter(dd,index,one,Cudd_Not(one));
+ if (var == NULL) return(NULL);
+ cuddRef(var);
+
+ if (level > (unsigned) depth) {
+ E = zddPortToBddStep(dd,f,depth+1);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd,var);
+ return(NULL);
+ }
+ cuddRef(E);
+ res = cuddBddIteRecur(dd,var,Cudd_Not(one),E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,var);
+ Cudd_RecursiveDeref(dd,E);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd,var);
+ Cudd_RecursiveDeref(dd,E);
+ cuddDeref(res);
+ return(res);
+ }
+
+ res = cuddCacheLookup1(dd,Cudd_zddPortToBdd,f);
+ if (res != NULL) {
+ Cudd_RecursiveDeref(dd,var);
+ return(res);
+ }
+
+ T = zddPortToBddStep(dd,cuddT(f),depth+1);
+ if (T == NULL) {
+ Cudd_RecursiveDeref(dd,var);
+ return(NULL);
+ }
+ cuddRef(T);
+ E = zddPortToBddStep(dd,cuddE(f),depth+1);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd,var);
+ Cudd_RecursiveDeref(dd,T);
+ return(NULL);
+ }
+ cuddRef(E);
+
+ res = cuddBddIteRecur(dd,var,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,var);
+ Cudd_RecursiveDeref(dd,T);
+ Cudd_RecursiveDeref(dd,E);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd,var);
+ Cudd_RecursiveDeref(dd,T);
+ Cudd_RecursiveDeref(dd,E);
+ cuddDeref(res);
+
+ cuddCacheInsert1(dd,Cudd_zddPortToBdd,f,res);
+
+ return(res);
+
+} /* end of zddPortToBddStep */
+
diff --git a/src/bdd/cudd/cuddZddReord.c b/src/bdd/cudd/cuddZddReord.c
new file mode 100644
index 00000000..e14ae2ad
--- /dev/null
+++ b/src/bdd/cudd/cuddZddReord.c
@@ -0,0 +1,1633 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddReord.c]
+
+ PackageName [cudd]
+
+ Synopsis [Procedures for dynamic variable ordering of ZDDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_zddReduceHeap()
+ <li> Cudd_zddShuffleHeap()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddZddAlignToBdd()
+ <li> cuddZddNextHigh()
+ <li> cuddZddNextLow()
+ <li> cuddZddUniqueCompare()
+ <li> cuddZddSwapInPlace()
+ <li> cuddZddSwapping()
+ <li> cuddZddSifting()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> zddSwapAny()
+ <li> cuddZddSiftingAux()
+ <li> cuddZddSiftingUp()
+ <li> cuddZddSiftingDown()
+ <li> cuddZddSiftingBackward()
+ <li> zddReorderPreprocess()
+ <li> zddReorderPostprocess()
+ <li> zddShuffle()
+ <li> zddSiftUp()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Hyong-Kyoon Shin, In-Ho Moon]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define DD_MAX_SUBTABLE_SPARSITY 8
+#define DD_SHRINK_FACTOR 2
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddReord.c,v 1.1.1.1 2003/02/24 22:23:54 wjiang Exp $";
+#endif
+
+int *zdd_entry;
+
+int zddTotalNumberSwapping;
+
+static DdNode *empty;
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static Move * zddSwapAny ARGS((DdManager *table, int x, int y));
+static int cuddZddSiftingAux ARGS((DdManager *table, int x, int x_low, int x_high));
+static Move * cuddZddSiftingUp ARGS((DdManager *table, int x, int x_low, int initial_size));
+static Move * cuddZddSiftingDown ARGS((DdManager *table, int x, int x_high, int initial_size));
+static int cuddZddSiftingBackward ARGS((DdManager *table, Move *moves, int size));
+static void zddReorderPreprocess ARGS((DdManager *table));
+static int zddReorderPostprocess ARGS((DdManager *table));
+static int zddShuffle ARGS((DdManager *table, int *permutation));
+static int zddSiftUp ARGS((DdManager *table, int x, int xLow));
+static void zddFixTree ARGS((DdManager *table, MtrNode *treenode));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Main dynamic reordering routine for ZDDs.]
+
+ Description [Main dynamic reordering routine for ZDDs.
+ Calls one of the possible reordering procedures:
+ <ul>
+ <li>Swapping
+ <li>Sifting
+ <li>Symmetric Sifting
+ </ul>
+
+ For sifting and symmetric sifting it is possible to request reordering
+ to convergence.<p>
+
+ The core of all methods is the reordering procedure
+ cuddZddSwapInPlace() which swaps two adjacent variables.
+ Returns 1 in case of success; 0 otherwise. In the case of symmetric
+ sifting (with and without convergence) returns 1 plus the number of
+ symmetric variables, in case of success.]
+
+ SideEffects [Changes the variable order for all ZDDs and clears
+ the cache.]
+
+******************************************************************************/
+int
+Cudd_zddReduceHeap(
+ DdManager * table /* DD manager */,
+ Cudd_ReorderingType heuristic /* method used for reordering */,
+ int minsize /* bound below which no reordering occurs */)
+{
+ DdHook *hook;
+ int result;
+ unsigned int nextDyn;
+#ifdef DD_STATS
+ unsigned int initialSize;
+ unsigned int finalSize;
+#endif
+ long localTime;
+
+ /* Don't reorder if there are too many dead nodes. */
+ if (table->keysZ - table->deadZ < (unsigned) minsize)
+ return(1);
+
+ if (heuristic == CUDD_REORDER_SAME) {
+ heuristic = table->autoMethodZ;
+ }
+ if (heuristic == CUDD_REORDER_NONE) {
+ return(1);
+ }
+
+ /* This call to Cudd_zddReduceHeap does initiate reordering. Therefore
+ ** we count it.
+ */
+ table->reorderings++;
+ empty = table->zero;
+
+ localTime = util_cpu_time();
+
+ /* Run the hook functions. */
+ hook = table->preReorderingHook;
+ while (hook != NULL) {
+ int res = (hook->f)(table, "ZDD", (void *)heuristic);
+ if (res == 0) return(0);
+ hook = hook->next;
+ }
+
+ /* Clear the cache and collect garbage. */
+ zddReorderPreprocess(table);
+ zddTotalNumberSwapping = 0;
+
+#ifdef DD_STATS
+ initialSize = table->keysZ;
+
+ switch(heuristic) {
+ case CUDD_REORDER_RANDOM:
+ case CUDD_REORDER_RANDOM_PIVOT:
+ (void) fprintf(table->out,"#:I_RANDOM ");
+ break;
+ case CUDD_REORDER_SIFT:
+ case CUDD_REORDER_SIFT_CONVERGE:
+ case CUDD_REORDER_SYMM_SIFT:
+ case CUDD_REORDER_SYMM_SIFT_CONV:
+ (void) fprintf(table->out,"#:I_SIFTING ");
+ break;
+ case CUDD_REORDER_LINEAR:
+ case CUDD_REORDER_LINEAR_CONVERGE:
+ (void) fprintf(table->out,"#:I_LINSIFT ");
+ break;
+ default:
+ (void) fprintf(table->err,"Unsupported ZDD reordering method\n");
+ return(0);
+ }
+ (void) fprintf(table->out,"%8d: initial size",initialSize);
+#endif
+
+ result = cuddZddTreeSifting(table,heuristic);
+
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n");
+ finalSize = table->keysZ;
+ (void) fprintf(table->out,"#:F_REORDER %8d: final size\n",finalSize);
+ (void) fprintf(table->out,"#:T_REORDER %8g: total time (sec)\n",
+ ((double)(util_cpu_time() - localTime)/1000.0));
+ (void) fprintf(table->out,"#:N_REORDER %8d: total swaps\n",
+ zddTotalNumberSwapping);
+#endif
+
+ if (result == 0)
+ return(0);
+
+ if (!zddReorderPostprocess(table))
+ return(0);
+
+ if (table->realignZ) {
+ if (!cuddBddAlignToZdd(table))
+ return(0);
+ }
+
+ nextDyn = table->keysZ * DD_DYN_RATIO;
+ if (table->reorderings < 20 || nextDyn > table->nextDyn)
+ table->nextDyn = nextDyn;
+ else
+ table->nextDyn += 20;
+
+ table->reordered = 1;
+
+ /* Run hook functions. */
+ hook = table->postReorderingHook;
+ while (hook != NULL) {
+ int res = (hook->f)(table, "ZDD", (void *)localTime);
+ if (res == 0) return(0);
+ hook = hook->next;
+ }
+ /* Update cumulative reordering time. */
+ table->reordTime += util_cpu_time() - localTime;
+
+ return(result);
+
+} /* end of Cudd_zddReduceHeap */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders ZDD variables according to given permutation.]
+
+ Description [Reorders ZDD variables according to given permutation.
+ The i-th entry of the permutation array contains the index of the variable
+ that should be brought to the i-th level. The size of the array should be
+ equal or greater to the number of variables currently in use.
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [Changes the ZDD variable order for all diagrams and clears
+ the cache.]
+
+ SeeAlso [Cudd_zddReduceHeap]
+
+******************************************************************************/
+int
+Cudd_zddShuffleHeap(
+ DdManager * table /* DD manager */,
+ int * permutation /* required variable permutation */)
+{
+
+ int result;
+
+ empty = table->zero;
+ zddReorderPreprocess(table);
+
+ result = zddShuffle(table,permutation);
+
+ if (!zddReorderPostprocess(table)) return(0);
+
+ return(result);
+
+} /* end of Cudd_zddShuffleHeap */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders ZDD variables according to the order of the BDD
+ variables.]
+
+ Description [Reorders ZDD variables according to the order of the
+ BDD variables. This function can be called at the end of BDD
+ reordering to insure that the order of the ZDD variables is
+ consistent with the order of the BDD variables. The number of ZDD
+ variables must be a multiple of the number of BDD variables. Let
+ <code>M</code> be the ratio of the two numbers. cuddZddAlignToBdd
+ then considers the ZDD variables from <code>M*i</code> to
+ <code>(M+1)*i-1</code> as corresponding to BDD variable
+ <code>i</code>. This function should be normally called from
+ Cudd_ReduceHeap, which clears the cache. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [Changes the ZDD variable order for all diagrams and performs
+ garbage collection of the ZDD unique table.]
+
+ SeeAlso [Cudd_zddShuffleHeap Cudd_ReduceHeap]
+
+******************************************************************************/
+int
+cuddZddAlignToBdd(
+ DdManager * table /* DD manager */)
+{
+ int *invpermZ; /* permutation array */
+ int M; /* ratio of ZDD variables to BDD variables */
+ int i,j; /* loop indices */
+ int result; /* return value */
+
+ /* We assume that a ratio of 0 is OK. */
+ if (table->sizeZ == 0)
+ return(1);
+
+ empty = table->zero;
+ M = table->sizeZ / table->size;
+ /* Check whether the number of ZDD variables is a multiple of the
+ ** number of BDD variables.
+ */
+ if (M * table->size != table->sizeZ)
+ return(0);
+ /* Create and initialize the inverse permutation array. */
+ invpermZ = ALLOC(int,table->sizeZ);
+ if (invpermZ == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (i = 0; i < table->size; i++) {
+ int index = table->invperm[i];
+ int indexZ = index * M;
+ int levelZ = table->permZ[indexZ];
+ levelZ = (levelZ / M) * M;
+ for (j = 0; j < M; j++) {
+ invpermZ[M * i + j] = table->invpermZ[levelZ + j];
+ }
+ }
+ /* Eliminate dead nodes. Do not scan the cache again, because we
+ ** assume that Cudd_ReduceHeap has already cleared it.
+ */
+ cuddGarbageCollectZdd(table,0);
+
+ result = zddShuffle(table, invpermZ);
+ FREE(invpermZ);
+ /* Fix the ZDD variable group tree. */
+ zddFixTree(table,table->treeZ);
+ return(result);
+
+} /* end of cuddZddAlignToBdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the next subtable with a larger index.]
+
+ Description [Finds the next subtable with a larger index. Returns the
+ index.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddNextHigh(
+ DdManager * table,
+ int x)
+{
+ return(x + 1);
+
+} /* end of cuddZddNextHigh */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the next subtable with a smaller index.]
+
+ Description [Finds the next subtable with a smaller index. Returns the
+ index.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddNextLow(
+ DdManager * table,
+ int x)
+{
+ return(x - 1);
+
+} /* end of cuddZddNextLow */
+
+
+/**Function********************************************************************
+
+ Synopsis [Comparison function used by qsort.]
+
+ Description [Comparison function used by qsort to order the
+ variables according to the number of keys in the subtables.
+ Returns the difference in number of keys between the two
+ variables being compared.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddUniqueCompare(
+ int * ptr_x,
+ int * ptr_y)
+{
+ return(zdd_entry[*ptr_y] - zdd_entry[*ptr_x]);
+
+} /* end of cuddZddUniqueCompare */
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps two adjacent variables.]
+
+ Description [Swaps two adjacent variables. It assumes that no dead
+ nodes are present on entry to this procedure. The procedure then
+ guarantees that no dead nodes will be present when it terminates.
+ cuddZddSwapInPlace assumes that x &lt; y. Returns the number of keys in
+ the table if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddSwapInPlace(
+ DdManager * table,
+ int x,
+ int y)
+{
+ DdNodePtr *xlist, *ylist;
+ int xindex, yindex;
+ int xslots, yslots;
+ int xshift, yshift;
+ int oldxkeys, oldykeys;
+ int newxkeys, newykeys;
+ int i;
+ int posn;
+ DdNode *f, *f1, *f0, *f11, *f10, *f01, *f00;
+ DdNode *newf1, *newf0, *next;
+ DdNodePtr g, *lastP, *previousP;
+
+#ifdef DD_DEBUG
+ assert(x < y);
+ assert(cuddZddNextHigh(table,x) == y);
+ assert(table->subtableZ[x].keys != 0);
+ assert(table->subtableZ[y].keys != 0);
+ assert(table->subtableZ[x].dead == 0);
+ assert(table->subtableZ[y].dead == 0);
+#endif
+
+ zddTotalNumberSwapping++;
+
+ /* Get parameters of x subtable. */
+ xindex = table->invpermZ[x];
+ xlist = table->subtableZ[x].nodelist;
+ oldxkeys = table->subtableZ[x].keys;
+ xslots = table->subtableZ[x].slots;
+ xshift = table->subtableZ[x].shift;
+ newxkeys = 0;
+
+ yindex = table->invpermZ[y];
+ ylist = table->subtableZ[y].nodelist;
+ oldykeys = table->subtableZ[y].keys;
+ yslots = table->subtableZ[y].slots;
+ yshift = table->subtableZ[y].shift;
+ newykeys = oldykeys;
+
+ /* The nodes in the x layer that don't depend on y directly
+ ** will stay there; the others are put in a chain.
+ ** The chain is handled as a FIFO; g points to the beginning and
+ ** last points to the end.
+ */
+
+ g = NULL;
+ lastP = &g;
+ for (i = 0; i < xslots; i++) {
+ previousP = &(xlist[i]);
+ f = *previousP;
+ while (f != NULL) {
+ next = f->next;
+ f1 = cuddT(f); f0 = cuddE(f);
+ if ((f1->index != (DdHalfWord) yindex) &&
+ (f0->index != (DdHalfWord) yindex)) { /* stays */
+ newxkeys++;
+ *previousP = f;
+ previousP = &(f->next);
+ } else {
+ f->index = yindex;
+ *lastP = f;
+ lastP = &(f->next);
+ }
+ f = next;
+ } /* while there are elements in the collision chain */
+ *previousP = NULL;
+ } /* for each slot of the x subtable */
+ *lastP = NULL;
+
+
+#ifdef DD_COUNT
+ table->swapSteps += oldxkeys - newxkeys;
+#endif
+ /* Take care of the x nodes that must be re-expressed.
+ ** They form a linked list pointed by g. Their index has been
+ ** changed to yindex already.
+ */
+ f = g;
+ while (f != NULL) {
+ next = f->next;
+ /* Find f1, f0, f11, f10, f01, f00. */
+ f1 = cuddT(f);
+ if ((int) f1->index == yindex) {
+ f11 = cuddT(f1); f10 = cuddE(f1);
+ } else {
+ f11 = empty; f10 = f1;
+ }
+ f0 = cuddE(f);
+ if ((int) f0->index == yindex) {
+ f01 = cuddT(f0); f00 = cuddE(f0);
+ } else {
+ f01 = empty; f00 = f0;
+ }
+
+ /* Decrease ref count of f1. */
+ cuddSatDec(f1->ref);
+ /* Create the new T child. */
+ if (f11 == empty) {
+ if (f01 != empty) {
+ newf1 = f01;
+ cuddSatInc(newf1->ref);
+ }
+ /* else case was already handled when finding nodes
+ ** with both children below level y
+ */
+ } else {
+ /* Check xlist for triple (xindex, f11, f01). */
+ posn = ddHash(f11, f01, xshift);
+ /* For each element newf1 in collision list xlist[posn]. */
+ newf1 = xlist[posn];
+ while (newf1 != NULL) {
+ if (cuddT(newf1) == f11 && cuddE(newf1) == f01) {
+ cuddSatInc(newf1->ref);
+ break; /* match */
+ }
+ newf1 = newf1->next;
+ } /* while newf1 */
+ if (newf1 == NULL) { /* no match */
+ newf1 = cuddDynamicAllocNode(table);
+ if (newf1 == NULL)
+ goto zddSwapOutOfMem;
+ newf1->index = xindex; newf1->ref = 1;
+ cuddT(newf1) = f11;
+ cuddE(newf1) = f01;
+ /* Insert newf1 in the collision list xlist[pos];
+ ** increase the ref counts of f11 and f01
+ */
+ newxkeys++;
+ newf1->next = xlist[posn];
+ xlist[posn] = newf1;
+ cuddSatInc(f11->ref);
+ cuddSatInc(f01->ref);
+ }
+ }
+ cuddT(f) = newf1;
+
+ /* Do the same for f0. */
+ /* Decrease ref count of f0. */
+ cuddSatDec(f0->ref);
+ /* Create the new E child. */
+ if (f10 == empty) {
+ newf0 = f00;
+ cuddSatInc(newf0->ref);
+ } else {
+ /* Check xlist for triple (xindex, f10, f00). */
+ posn = ddHash(f10, f00, xshift);
+ /* For each element newf0 in collision list xlist[posn]. */
+ newf0 = xlist[posn];
+ while (newf0 != NULL) {
+ if (cuddT(newf0) == f10 && cuddE(newf0) == f00) {
+ cuddSatInc(newf0->ref);
+ break; /* match */
+ }
+ newf0 = newf0->next;
+ } /* while newf0 */
+ if (newf0 == NULL) { /* no match */
+ newf0 = cuddDynamicAllocNode(table);
+ if (newf0 == NULL)
+ goto zddSwapOutOfMem;
+ newf0->index = xindex; newf0->ref = 1;
+ cuddT(newf0) = f10; cuddE(newf0) = f00;
+ /* Insert newf0 in the collision list xlist[posn];
+ ** increase the ref counts of f10 and f00.
+ */
+ newxkeys++;
+ newf0->next = xlist[posn];
+ xlist[posn] = newf0;
+ cuddSatInc(f10->ref);
+ cuddSatInc(f00->ref);
+ }
+ }
+ cuddE(f) = newf0;
+
+ /* Insert the modified f in ylist.
+ ** The modified f does not already exists in ylist.
+ ** (Because of the uniqueness of the cofactors.)
+ */
+ posn = ddHash(newf1, newf0, yshift);
+ newykeys++;
+ f->next = ylist[posn];
+ ylist[posn] = f;
+ f = next;
+ } /* while f != NULL */
+
+ /* GC the y layer. */
+
+ /* For each node f in ylist. */
+ for (i = 0; i < yslots; i++) {
+ previousP = &(ylist[i]);
+ f = *previousP;
+ while (f != NULL) {
+ next = f->next;
+ if (f->ref == 0) {
+ cuddSatDec(cuddT(f)->ref);
+ cuddSatDec(cuddE(f)->ref);
+ cuddDeallocNode(table, f);
+ newykeys--;
+ } else {
+ *previousP = f;
+ previousP = &(f->next);
+ }
+ f = next;
+ } /* while f */
+ *previousP = NULL;
+ } /* for i */
+
+ /* Set the appropriate fields in table. */
+ table->subtableZ[x].nodelist = ylist;
+ table->subtableZ[x].slots = yslots;
+ table->subtableZ[x].shift = yshift;
+ table->subtableZ[x].keys = newykeys;
+ table->subtableZ[x].maxKeys = yslots * DD_MAX_SUBTABLE_DENSITY;
+
+ table->subtableZ[y].nodelist = xlist;
+ table->subtableZ[y].slots = xslots;
+ table->subtableZ[y].shift = xshift;
+ table->subtableZ[y].keys = newxkeys;
+ table->subtableZ[y].maxKeys = xslots * DD_MAX_SUBTABLE_DENSITY;
+
+ table->permZ[xindex] = y; table->permZ[yindex] = x;
+ table->invpermZ[x] = yindex; table->invpermZ[y] = xindex;
+
+ table->keysZ += newxkeys + newykeys - oldxkeys - oldykeys;
+
+ /* Update univ section; univ[x] remains the same. */
+ table->univ[y] = cuddT(table->univ[x]);
+
+ return (table->keysZ);
+
+zddSwapOutOfMem:
+ (void) fprintf(table->err, "Error: cuddZddSwapInPlace out of memory\n");
+
+ return (0);
+
+} /* end of cuddZddSwapInPlace */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders variables by a sequence of (non-adjacent) swaps.]
+
+ Description [Implementation of Plessier's algorithm that reorders
+ variables by a sequence of (non-adjacent) swaps.
+ <ol>
+ <li> Select two variables (RANDOM or HEURISTIC).
+ <li> Permute these variables.
+ <li> If the nodes have decreased accept the permutation.
+ <li> Otherwise reconstruct the original heap.
+ <li> Loop.
+ </ol>
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddSwapping(
+ DdManager * table,
+ int lower,
+ int upper,
+ Cudd_ReorderingType heuristic)
+{
+ int i, j;
+ int max, keys;
+ int nvars;
+ int x, y;
+ int iterate;
+ int previousSize;
+ Move *moves, *move;
+ int pivot;
+ int modulo;
+ int result;
+
+#ifdef DD_DEBUG
+ /* Sanity check */
+ assert(lower >= 0 && upper < table->sizeZ && lower <= upper);
+#endif
+
+ nvars = upper - lower + 1;
+ iterate = nvars;
+
+ for (i = 0; i < iterate; i++) {
+ if (heuristic == CUDD_REORDER_RANDOM_PIVOT) {
+ /* Find pivot <= id with maximum keys. */
+ for (max = -1, j = lower; j <= upper; j++) {
+ if ((keys = table->subtableZ[j].keys) > max) {
+ max = keys;
+ pivot = j;
+ }
+ }
+
+ modulo = upper - pivot;
+ if (modulo == 0) {
+ y = pivot; /* y = nvars-1 */
+ } else {
+ /* y = random # from {pivot+1 .. nvars-1} */
+ y = pivot + 1 + (int) (Cudd_Random() % modulo);
+ }
+
+ modulo = pivot - lower - 1;
+ if (modulo < 1) { /* if pivot = 1 or 0 */
+ x = lower;
+ } else {
+ do { /* x = random # from {0 .. pivot-2} */
+ x = (int) Cudd_Random() % modulo;
+ } while (x == y);
+ /* Is this condition really needed, since x and y
+ are in regions separated by pivot? */
+ }
+ } else {
+ x = (int) (Cudd_Random() % nvars) + lower;
+ do {
+ y = (int) (Cudd_Random() % nvars) + lower;
+ } while (x == y);
+ }
+
+ previousSize = table->keysZ;
+ moves = zddSwapAny(table, x, y);
+ if (moves == NULL)
+ goto cuddZddSwappingOutOfMem;
+
+ result = cuddZddSiftingBackward(table, moves, previousSize);
+ if (!result)
+ goto cuddZddSwappingOutOfMem;
+
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+#ifdef DD_STATS
+ if (table->keysZ < (unsigned) previousSize) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keysZ > (unsigned) previousSize) {
+ (void) fprintf(table->out,"+"); /* should never happen */
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+
+ return(1);
+
+cuddZddSwappingOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return(0);
+
+} /* end of cuddZddSwapping */
+
+
+/**Function********************************************************************
+
+ Synopsis [Implementation of Rudell's sifting algorithm.]
+
+ Description [Implementation of Rudell's sifting algorithm.
+ Assumes that no dead nodes are present.
+ <ol>
+ <li> Order all the variables according to the number of entries
+ in each unique table.
+ <li> Sift the variable up and down, remembering each time the
+ total size of the DD heap.
+ <li> Select the best permutation.
+ <li> Repeat 3 and 4 for all variables.
+ </ol>
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddSifting(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i;
+ int *var;
+ int size;
+ int x;
+ int result;
+#ifdef DD_STATS
+ int previousSize;
+#endif
+
+ size = table->sizeZ;
+
+ /* Find order in which to sift variables. */
+ var = NULL;
+ zdd_entry = ALLOC(int, size);
+ if (zdd_entry == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddZddSiftingOutOfMem;
+ }
+ var = ALLOC(int, size);
+ if (var == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddZddSiftingOutOfMem;
+ }
+
+ for (i = 0; i < size; i++) {
+ x = table->permZ[i];
+ zdd_entry[i] = table->subtableZ[x].keys;
+ var[i] = i;
+ }
+
+ qsort((void *)var, size, sizeof(int), (int (*)(const void *, const void *))cuddZddUniqueCompare);
+
+ /* Now sift. */
+ for (i = 0; i < ddMin(table->siftMaxVar, size); i++) {
+ if (zddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ x = table->permZ[var[i]];
+ if (x < lower || x > upper) continue;
+#ifdef DD_STATS
+ previousSize = table->keysZ;
+#endif
+ result = cuddZddSiftingAux(table, x, lower, upper);
+ if (!result)
+ goto cuddZddSiftingOutOfMem;
+#ifdef DD_STATS
+ if (table->keysZ < (unsigned) previousSize) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keysZ > (unsigned) previousSize) {
+ (void) fprintf(table->out,"+"); /* should never happen */
+ (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ , var[i]);
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+
+ FREE(var);
+ FREE(zdd_entry);
+
+ return(1);
+
+cuddZddSiftingOutOfMem:
+
+ if (zdd_entry != NULL) FREE(zdd_entry);
+ if (var != NULL) FREE(var);
+
+ return(0);
+
+} /* end of cuddZddSifting */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps any two variables.]
+
+ Description [Swaps any two variables. Returns the set of moves.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static Move *
+zddSwapAny(
+ DdManager * table,
+ int x,
+ int y)
+{
+ Move *move, *moves;
+ int tmp, size;
+ int x_ref, y_ref;
+ int x_next, y_next;
+ int limit_size;
+
+ if (x > y) { /* make x precede y */
+ tmp = x; x = y; y = tmp;
+ }
+
+ x_ref = x; y_ref = y;
+
+ x_next = cuddZddNextHigh(table, x);
+ y_next = cuddZddNextLow(table, y);
+ moves = NULL;
+ limit_size = table->keysZ;
+
+ for (;;) {
+ if (x_next == y_next) { /* x < x_next = y_next < y */
+ size = cuddZddSwapInPlace(table, x, x_next);
+ if (size == 0)
+ goto zddSwapAnyOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto zddSwapAnyOutOfMem;
+ move->x = x;
+ move->y = x_next;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ size = cuddZddSwapInPlace(table, y_next, y);
+ if (size == 0)
+ goto zddSwapAnyOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto zddSwapAnyOutOfMem;
+ move->x = y_next;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ size = cuddZddSwapInPlace(table, x, x_next);
+ if (size == 0)
+ goto zddSwapAnyOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto zddSwapAnyOutOfMem;
+ move->x = x;
+ move->y = x_next;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ tmp = x; x = y; y = tmp;
+
+ } else if (x == y_next) { /* x = y_next < y = x_next */
+ size = cuddZddSwapInPlace(table, x, x_next);
+ if (size == 0)
+ goto zddSwapAnyOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto zddSwapAnyOutOfMem;
+ move->x = x;
+ move->y = x_next;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ tmp = x; x = y; y = tmp;
+ } else {
+ size = cuddZddSwapInPlace(table, x, x_next);
+ if (size == 0)
+ goto zddSwapAnyOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto zddSwapAnyOutOfMem;
+ move->x = x;
+ move->y = x_next;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ size = cuddZddSwapInPlace(table, y_next, y);
+ if (size == 0)
+ goto zddSwapAnyOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto zddSwapAnyOutOfMem;
+ move->x = y_next;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ x = x_next; y = y_next;
+ }
+
+ x_next = cuddZddNextHigh(table, x);
+ y_next = cuddZddNextLow(table, y);
+ if (x_next > y_ref)
+ break; /* if x == y_ref */
+
+ if ((double) size > table->maxGrowth * (double) limit_size)
+ break;
+ if (size < limit_size)
+ limit_size = size;
+ }
+ if (y_next >= x_ref) {
+ size = cuddZddSwapInPlace(table, y_next, y);
+ if (size == 0)
+ goto zddSwapAnyOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto zddSwapAnyOutOfMem;
+ move->x = y_next;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ }
+
+ return(moves);
+
+zddSwapAnyOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *)moves);
+ moves = move;
+ }
+ return(NULL);
+
+} /* end of zddSwapAny */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries.]
+
+ Description [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries. Finds the best position and does the required changes.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddZddSiftingAux(
+ DdManager * table,
+ int x,
+ int x_low,
+ int x_high)
+{
+ Move *move;
+ Move *moveUp; /* list of up move */
+ Move *moveDown; /* list of down move */
+
+ int initial_size;
+ int result;
+
+ initial_size = table->keysZ;
+
+#ifdef DD_DEBUG
+ assert(table->subtableZ[x].keys > 0);
+#endif
+
+ moveDown = NULL;
+ moveUp = NULL;
+
+ if (x == x_low) {
+ moveDown = cuddZddSiftingDown(table, x, x_high, initial_size);
+ /* after that point x --> x_high */
+ if (moveDown == NULL)
+ goto cuddZddSiftingAuxOutOfMem;
+ result = cuddZddSiftingBackward(table, moveDown,
+ initial_size);
+ /* move backward and stop at best position */
+ if (!result)
+ goto cuddZddSiftingAuxOutOfMem;
+
+ }
+ else if (x == x_high) {
+ moveUp = cuddZddSiftingUp(table, x, x_low, initial_size);
+ /* after that point x --> x_low */
+ if (moveUp == NULL)
+ goto cuddZddSiftingAuxOutOfMem;
+ result = cuddZddSiftingBackward(table, moveUp, initial_size);
+ /* move backward and stop at best position */
+ if (!result)
+ goto cuddZddSiftingAuxOutOfMem;
+ }
+ else if ((x - x_low) > (x_high - x)) {
+ /* must go down first:shorter */
+ moveDown = cuddZddSiftingDown(table, x, x_high, initial_size);
+ /* after that point x --> x_high */
+ if (moveDown == NULL)
+ goto cuddZddSiftingAuxOutOfMem;
+ moveUp = cuddZddSiftingUp(table, moveDown->y, x_low,
+ initial_size);
+ if (moveUp == NULL)
+ goto cuddZddSiftingAuxOutOfMem;
+ result = cuddZddSiftingBackward(table, moveUp, initial_size);
+ /* move backward and stop at best position */
+ if (!result)
+ goto cuddZddSiftingAuxOutOfMem;
+ }
+ else {
+ moveUp = cuddZddSiftingUp(table, x, x_low, initial_size);
+ /* after that point x --> x_high */
+ if (moveUp == NULL)
+ goto cuddZddSiftingAuxOutOfMem;
+ moveDown = cuddZddSiftingDown(table, moveUp->x, x_high,
+ initial_size);
+ /* then move up */
+ if (moveDown == NULL)
+ goto cuddZddSiftingAuxOutOfMem;
+ result = cuddZddSiftingBackward(table, moveDown,
+ initial_size);
+ /* move backward and stop at best position */
+ if (!result)
+ goto cuddZddSiftingAuxOutOfMem;
+ }
+
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *)moveDown);
+ moveDown = move;
+ }
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *)moveUp);
+ moveUp = move;
+ }
+
+ return(1);
+
+cuddZddSiftingAuxOutOfMem:
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *)moveDown);
+ moveDown = move;
+ }
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *)moveUp);
+ moveUp = move;
+ }
+
+ return(0);
+
+} /* end of cuddZddSiftingAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts a variable up.]
+
+ Description [Sifts a variable up. Moves y up until either it reaches
+ the bound (x_low) or the size of the ZDD heap increases too much.
+ Returns the set of moves in case of success; NULL if memory is full.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static Move *
+cuddZddSiftingUp(
+ DdManager * table,
+ int x,
+ int x_low,
+ int initial_size)
+{
+ Move *moves;
+ Move *move;
+ int y;
+ int size;
+ int limit_size = initial_size;
+
+ moves = NULL;
+ y = cuddZddNextLow(table, x);
+ while (y >= x_low) {
+ size = cuddZddSwapInPlace(table, y, x);
+ if (size == 0)
+ goto cuddZddSiftingUpOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto cuddZddSiftingUpOutOfMem;
+ move->x = y;
+ move->y = x;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ if ((double)size > (double)limit_size * table->maxGrowth)
+ break;
+ if (size < limit_size)
+ limit_size = size;
+
+ x = y;
+ y = cuddZddNextLow(table, x);
+ }
+ return(moves);
+
+cuddZddSiftingUpOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *)moves);
+ moves = move;
+ }
+ return(NULL);
+
+} /* end of cuddZddSiftingUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts a variable down.]
+
+ Description [Sifts a variable down. Moves x down until either it
+ reaches the bound (x_high) or the size of the ZDD heap increases too
+ much. Returns the set of moves in case of success; NULL if memory is
+ full.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static Move *
+cuddZddSiftingDown(
+ DdManager * table,
+ int x,
+ int x_high,
+ int initial_size)
+{
+ Move *moves;
+ Move *move;
+ int y;
+ int size;
+ int limit_size = initial_size;
+
+ moves = NULL;
+ y = cuddZddNextHigh(table, x);
+ while (y <= x_high) {
+ size = cuddZddSwapInPlace(table, x, y);
+ if (size == 0)
+ goto cuddZddSiftingDownOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto cuddZddSiftingDownOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ if ((double)size > (double)limit_size * table->maxGrowth)
+ break;
+ if (size < limit_size)
+ limit_size = size;
+
+ x = y;
+ y = cuddZddNextHigh(table, x);
+ }
+ return(moves);
+
+cuddZddSiftingDownOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *)moves);
+ moves = move;
+ }
+ return(NULL);
+
+} /* end of cuddZddSiftingDown */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given a set of moves, returns the ZDD heap to the position
+ giving the minimum size.]
+
+ Description [Given a set of moves, returns the ZDD heap to the
+ position giving the minimum size. In case of ties, returns to the
+ closest position giving the minimum size. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddZddSiftingBackward(
+ DdManager * table,
+ Move * moves,
+ int size)
+{
+ int i;
+ int i_best;
+ Move *move;
+ int res;
+
+ /* Find the minimum size among moves. */
+ i_best = -1;
+ for (move = moves, i = 0; move != NULL; move = move->next, i++) {
+ if (move->size < size) {
+ i_best = i;
+ size = move->size;
+ }
+ }
+
+ for (move = moves, i = 0; move != NULL; move = move->next, i++) {
+ if (i == i_best)
+ break;
+ res = cuddZddSwapInPlace(table, move->x, move->y);
+ if (!res)
+ return(0);
+ if (i_best == -1 && res == size)
+ break;
+ }
+
+ return(1);
+
+} /* end of cuddZddSiftingBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prepares the ZDD heap for dynamic reordering.]
+
+ Description [Prepares the ZDD heap for dynamic reordering. Does
+ garbage collection, to guarantee that there are no dead nodes;
+ and clears the cache, which is invalidated by dynamic reordering.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static void
+zddReorderPreprocess(
+ DdManager * table)
+{
+
+ /* Clear the cache. */
+ cuddCacheFlush(table);
+
+ /* Eliminate dead nodes. Do not scan the cache again. */
+ cuddGarbageCollectZdd(table,0);
+
+ return;
+
+} /* end of ddReorderPreprocess */
+
+
+/**Function********************************************************************
+
+ Synopsis [Shrinks almost empty ZDD subtables at the end of reordering
+ to guarantee that they have a reasonable load factor.]
+
+ Description [Shrinks almost empty subtables at the end of reordering to
+ guarantee that they have a reasonable load factor. However, if there many
+ nodes are being reclaimed, then no resizing occurs. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddReorderPostprocess(
+ DdManager * table)
+{
+ int i, j, posn;
+ DdNodePtr *nodelist, *oldnodelist;
+ DdNode *node, *next;
+ unsigned int slots, oldslots;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+
+#ifdef DD_VERBOSE
+ (void) fflush(table->out);
+#endif
+
+ /* If we have very many reclaimed nodes, we do not want to shrink
+ ** the subtables, because this will lead to more garbage
+ ** collections. More garbage collections mean shorter mean life for
+ ** nodes with zero reference count; hence lower probability of finding
+ ** a result in the cache.
+ */
+ if (table->reclaimed > table->allocated * 0.5) return(1);
+
+ /* Resize subtables. */
+ for (i = 0; i < table->sizeZ; i++) {
+ int shift;
+ oldslots = table->subtableZ[i].slots;
+ if (oldslots < table->subtableZ[i].keys * DD_MAX_SUBTABLE_SPARSITY ||
+ oldslots <= table->initSlots) continue;
+ oldnodelist = table->subtableZ[i].nodelist;
+ slots = oldslots >> 1;
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ nodelist = ALLOC(DdNodePtr, slots);
+ MMoutOfMemory = saveHandler;
+ if (nodelist == NULL) {
+ return(1);
+ }
+ table->subtableZ[i].nodelist = nodelist;
+ table->subtableZ[i].slots = slots;
+ table->subtableZ[i].shift++;
+ table->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
+#ifdef DD_VERBOSE
+ (void) fprintf(table->err,
+ "shrunk layer %d (%d keys) from %d to %d slots\n",
+ i, table->subtableZ[i].keys, oldslots, slots);
+#endif
+
+ for (j = 0; (unsigned) j < slots; j++) {
+ nodelist[j] = NULL;
+ }
+ shift = table->subtableZ[i].shift;
+ for (j = 0; (unsigned) j < oldslots; j++) {
+ node = oldnodelist[j];
+ while (node != NULL) {
+ next = node->next;
+ posn = ddHash(cuddT(node), cuddE(node), shift);
+ node->next = nodelist[posn];
+ nodelist[posn] = node;
+ node = next;
+ }
+ }
+ FREE(oldnodelist);
+
+ table->memused += (slots - oldslots) * sizeof(DdNode *);
+ table->slots += slots - oldslots;
+ table->minDead = (unsigned) (table->gcFrac * (double) table->slots);
+ table->cacheSlack = (int) ddMin(table->maxCacheHard,
+ DD_MAX_CACHE_TO_SLOTS_RATIO*table->slots) -
+ 2 * (int) table->cacheSlots;
+ }
+ /* We don't look at the constant subtable, because it is not
+ ** affected by reordering.
+ */
+
+ return(1);
+
+} /* end of zddReorderPostprocess */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders ZDD variables according to a given permutation.]
+
+ Description [Reorders ZDD variables according to a given permutation.
+ The i-th permutation array contains the index of the variable that
+ should be brought to the i-th level. zddShuffle assumes that no
+ dead nodes are present. The reordering is achieved by a series of
+ upward sifts. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+zddShuffle(
+ DdManager * table,
+ int * permutation)
+{
+ int index;
+ int level;
+ int position;
+ int numvars;
+ int result;
+#ifdef DD_STATS
+ long localTime;
+ int initialSize;
+ int finalSize;
+ int previousSize;
+#endif
+
+ zddTotalNumberSwapping = 0;
+#ifdef DD_STATS
+ localTime = util_cpu_time();
+ initialSize = table->keysZ;
+ (void) fprintf(table->out,"#:I_SHUFFLE %8d: initial size\n",
+ initialSize);
+#endif
+
+ numvars = table->sizeZ;
+
+ for (level = 0; level < numvars; level++) {
+ index = permutation[level];
+ position = table->permZ[index];
+#ifdef DD_STATS
+ previousSize = table->keysZ;
+#endif
+ result = zddSiftUp(table,position,level);
+ if (!result) return(0);
+#ifdef DD_STATS
+ if (table->keysZ < (unsigned) previousSize) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keysZ > (unsigned) previousSize) {
+ (void) fprintf(table->out,"+"); /* should never happen */
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n");
+ finalSize = table->keysZ;
+ (void) fprintf(table->out,"#:F_SHUFFLE %8d: final size\n",finalSize);
+ (void) fprintf(table->out,"#:T_SHUFFLE %8g: total time (sec)\n",
+ ((double)(util_cpu_time() - localTime)/1000.0));
+ (void) fprintf(table->out,"#:N_SHUFFLE %8d: total swaps\n",
+ zddTotalNumberSwapping);
+#endif
+
+ return(1);
+
+} /* end of zddShuffle */
+
+
+/**Function********************************************************************
+
+ Synopsis [Moves one ZDD variable up.]
+
+ Description [Takes a ZDD variable from position x and sifts it up to
+ position xLow; xLow should be less than or equal to x.
+ Returns 1 if successful; 0 otherwise]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+zddSiftUp(
+ DdManager * table,
+ int x,
+ int xLow)
+{
+ int y;
+ int size;
+
+ y = cuddZddNextLow(table,x);
+ while (y >= xLow) {
+ size = cuddZddSwapInPlace(table,y,x);
+ if (size == 0) {
+ return(0);
+ }
+ x = y;
+ y = cuddZddNextLow(table,x);
+ }
+ return(1);
+
+} /* end of zddSiftUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Fixes the ZDD variable group tree after a shuffle.]
+
+ Description [Fixes the ZDD variable group tree after a
+ shuffle. Assumes that the order of the variables in a terminal node
+ has not been changed.]
+
+ SideEffects [Changes the ZDD variable group tree.]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+zddFixTree(
+ DdManager * table,
+ MtrNode * treenode)
+{
+ if (treenode == NULL) return;
+ treenode->low = ((int) treenode->index < table->sizeZ) ?
+ table->permZ[treenode->index] : treenode->index;
+ if (treenode->child != NULL) {
+ zddFixTree(table, treenode->child);
+ }
+ if (treenode->younger != NULL)
+ zddFixTree(table, treenode->younger);
+ if (treenode->parent != NULL && treenode->low < treenode->parent->low) {
+ treenode->parent->low = treenode->low;
+ treenode->parent->index = treenode->index;
+ }
+ return;
+
+} /* end of zddFixTree */
+
diff --git a/src/bdd/cudd/cuddZddSetop.c b/src/bdd/cudd/cuddZddSetop.c
new file mode 100644
index 00000000..cf05210f
--- /dev/null
+++ b/src/bdd/cudd/cuddZddSetop.c
@@ -0,0 +1,1137 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddSetop.c]
+
+ PackageName [cudd]
+
+ Synopsis [Set operations on ZDDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_zddIte()
+ <li> Cudd_zddUnion()
+ <li> Cudd_zddIntersect()
+ <li> Cudd_zddDiff()
+ <li> Cudd_zddDiffConst()
+ <li> Cudd_zddSubset1()
+ <li> Cudd_zddSubset0()
+ <li> Cudd_zddChange()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddZddIte()
+ <li> cuddZddUnion()
+ <li> cuddZddIntersect()
+ <li> cuddZddDiff()
+ <li> cuddZddChangeAux()
+ <li> cuddZddSubset1()
+ <li> cuddZddSubset0()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> zdd_subset1_aux()
+ <li> zdd_subset0_aux()
+ <li> zddVarToConst()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Hyong-Kyoon Shin, In-Ho Moon]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddSetop.c,v 1.1.1.1 2003/02/24 22:23:54 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdNode * zdd_subset1_aux ARGS((DdManager *zdd, DdNode *P, DdNode *zvar));
+static DdNode * zdd_subset0_aux ARGS((DdManager *zdd, DdNode *P, DdNode *zvar));
+static void zddVarToConst ARGS((DdNode *f, DdNode **gp, DdNode **hp, DdNode *base, DdNode *empty));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the ITE of three ZDDs.]
+
+ Description [Computes the ITE of three ZDDs. Returns a pointer to the
+ result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_zddIte(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddIte(dd, f, g, h);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_zddIte */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the union of two ZDDs.]
+
+ Description [Computes the union of two ZDDs. Returns a pointer to the
+ result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_zddUnion(
+ DdManager * dd,
+ DdNode * P,
+ DdNode * Q)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddUnion(dd, P, Q);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_zddUnion */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the intersection of two ZDDs.]
+
+ Description [Computes the intersection of two ZDDs. Returns a pointer to
+ the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_zddIntersect(
+ DdManager * dd,
+ DdNode * P,
+ DdNode * Q)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddIntersect(dd, P, Q);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_zddIntersect */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the difference of two ZDDs.]
+
+ Description [Computes the difference of two ZDDs. Returns a pointer to the
+ result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddDiffConst]
+
+******************************************************************************/
+DdNode *
+Cudd_zddDiff(
+ DdManager * dd,
+ DdNode * P,
+ DdNode * Q)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddDiff(dd, P, Q);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_zddDiff */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the inclusion test for ZDDs (P implies Q).]
+
+ Description [Inclusion test for ZDDs (P implies Q). No new nodes are
+ generated by this procedure. Returns empty if true;
+ a valid pointer different from empty or DD_NON_CONSTANT otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddDiff]
+
+******************************************************************************/
+DdNode *
+Cudd_zddDiffConst(
+ DdManager * zdd,
+ DdNode * P,
+ DdNode * Q)
+{
+ int p_top, q_top;
+ DdNode *empty = DD_ZERO(zdd), *t, *res;
+ DdManager *table = zdd;
+
+ statLine(zdd);
+ if (P == empty)
+ return(empty);
+ if (Q == empty)
+ return(P);
+ if (P == Q)
+ return(empty);
+
+ /* Check cache. The cache is shared by cuddZddDiff(). */
+ res = cuddCacheLookup2Zdd(table, cuddZddDiff, P, Q);
+ if (res != NULL)
+ return(res);
+
+ if (cuddIsConstant(P))
+ p_top = P->index;
+ else
+ p_top = zdd->permZ[P->index];
+ if (cuddIsConstant(Q))
+ q_top = Q->index;
+ else
+ q_top = zdd->permZ[Q->index];
+ if (p_top < q_top) {
+ res = DD_NON_CONSTANT;
+ } else if (p_top > q_top) {
+ res = Cudd_zddDiffConst(zdd, P, cuddE(Q));
+ } else {
+ t = Cudd_zddDiffConst(zdd, cuddT(P), cuddT(Q));
+ if (t != empty)
+ res = DD_NON_CONSTANT;
+ else
+ res = Cudd_zddDiffConst(zdd, cuddE(P), cuddE(Q));
+ }
+
+ cuddCacheInsert2(table, cuddZddDiff, P, Q, res);
+
+ return(res);
+
+} /* end of Cudd_zddDiffConst */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the positive cofactor of a ZDD w.r.t. a variable.]
+
+ Description [Computes the positive cofactor of a ZDD w.r.t. a
+ variable. In terms of combinations, the result is the set of all
+ combinations in which the variable is asserted. Returns a pointer to
+ the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddSubset0]
+
+******************************************************************************/
+DdNode *
+Cudd_zddSubset1(
+ DdManager * dd,
+ DdNode * P,
+ int var)
+{
+ DdNode *r;
+
+ do {
+ dd->reordered = 0;
+ r = cuddZddSubset1(dd, P, var);
+ } while (dd->reordered == 1);
+
+ return(r);
+
+} /* end of Cudd_zddSubset1 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the negative cofactor of a ZDD w.r.t. a variable.]
+
+ Description [Computes the negative cofactor of a ZDD w.r.t. a
+ variable. In terms of combinations, the result is the set of all
+ combinations in which the variable is negated. Returns a pointer to
+ the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddSubset1]
+
+******************************************************************************/
+DdNode *
+Cudd_zddSubset0(
+ DdManager * dd,
+ DdNode * P,
+ int var)
+{
+ DdNode *r;
+
+ do {
+ dd->reordered = 0;
+ r = cuddZddSubset0(dd, P, var);
+ } while (dd->reordered == 1);
+
+ return(r);
+
+} /* end of Cudd_zddSubset0 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Substitutes a variable with its complement in a ZDD.]
+
+ Description [Substitutes a variable with its complement in a ZDD.
+ returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_zddChange(
+ DdManager * dd,
+ DdNode * P,
+ int var)
+{
+ DdNode *res;
+
+ if ((unsigned int) var >= CUDD_MAXINDEX - 1) return(NULL);
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddChange(dd, P, var);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_zddChange */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddIte.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddZddIte(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ DdNode *tautology, *empty;
+ DdNode *r,*Gv,*Gvn,*Hv,*Hvn,*t,*e;
+ unsigned int topf,topg,toph,v,top;
+ int index;
+
+ statLine(dd);
+ /* Trivial cases. */
+ /* One variable cases. */
+ if (f == (empty = DD_ZERO(dd))) { /* ITE(0,G,H) = H */
+ return(h);
+ }
+ topf = cuddIZ(dd,f->index);
+ topg = cuddIZ(dd,g->index);
+ toph = cuddIZ(dd,h->index);
+ v = ddMin(topg,toph);
+ top = ddMin(topf,v);
+
+ tautology = (top == CUDD_MAXINDEX) ? DD_ONE(dd) : dd->univ[top];
+ if (f == tautology) { /* ITE(1,G,H) = G */
+ return(g);
+ }
+
+ /* From now on, f is known to not be a constant. */
+ zddVarToConst(f,&g,&h,tautology,empty);
+
+ /* Check remaining one variable cases. */
+ if (g == h) { /* ITE(F,G,G) = G */
+ return(g);
+ }
+
+ if (g == tautology) { /* ITE(F,1,0) = F */
+ if (h == empty) return(f);
+ }
+
+ /* Check cache. */
+ r = cuddCacheLookupZdd(dd,DD_ZDD_ITE_TAG,f,g,h);
+ if (r != NULL) {
+ return(r);
+ }
+
+ /* Recompute these because they may have changed in zddVarToConst. */
+ topg = cuddIZ(dd,g->index);
+ toph = cuddIZ(dd,h->index);
+ v = ddMin(topg,toph);
+
+ if (topf < v) {
+ r = cuddZddIte(dd,cuddE(f),g,h);
+ if (r == NULL) return(NULL);
+ } else if (topf > v) {
+ if (topg > v) {
+ Gvn = g;
+ index = h->index;
+ } else {
+ Gvn = cuddE(g);
+ index = g->index;
+ }
+ if (toph > v) {
+ Hv = empty; Hvn = h;
+ } else {
+ Hv = cuddT(h); Hvn = cuddE(h);
+ }
+ e = cuddZddIte(dd,f,Gvn,Hvn);
+ if (e == NULL) return(NULL);
+ cuddRef(e);
+ r = cuddZddGetNode(dd,index,Hv,e);
+ if (r == NULL) {
+ Cudd_RecursiveDerefZdd(dd,e);
+ return(NULL);
+ }
+ cuddDeref(e);
+ } else {
+ index = f->index;
+ if (topg > v) {
+ Gv = empty; Gvn = g;
+ } else {
+ Gv = cuddT(g); Gvn = cuddE(g);
+ }
+ if (toph > v) {
+ Hv = empty; Hvn = h;
+ } else {
+ Hv = cuddT(h); Hvn = cuddE(h);
+ }
+ e = cuddZddIte(dd,cuddE(f),Gvn,Hvn);
+ if (e == NULL) return(NULL);
+ cuddRef(e);
+ t = cuddZddIte(dd,cuddT(f),Gv,Hv);
+ if (t == NULL) {
+ Cudd_RecursiveDerefZdd(dd,e);
+ return(NULL);
+ }
+ cuddRef(t);
+ r = cuddZddGetNode(dd,index,t,e);
+ if (r == NULL) {
+ Cudd_RecursiveDerefZdd(dd,e);
+ Cudd_RecursiveDerefZdd(dd,t);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+ }
+
+ cuddCacheInsert(dd,DD_ZDD_ITE_TAG,f,g,h,r);
+
+ return(r);
+
+} /* end of cuddZddIte */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddUnion.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddZddUnion(
+ DdManager * zdd,
+ DdNode * P,
+ DdNode * Q)
+{
+ int p_top, q_top;
+ DdNode *empty = DD_ZERO(zdd), *t, *e, *res;
+ DdManager *table = zdd;
+
+ statLine(zdd);
+ if (P == empty)
+ return(Q);
+ if (Q == empty)
+ return(P);
+ if (P == Q)
+ return(P);
+
+ /* Check cache */
+ res = cuddCacheLookup2Zdd(table, cuddZddUnion, P, Q);
+ if (res != NULL)
+ return(res);
+
+ if (cuddIsConstant(P))
+ p_top = P->index;
+ else
+ p_top = zdd->permZ[P->index];
+ if (cuddIsConstant(Q))
+ q_top = Q->index;
+ else
+ q_top = zdd->permZ[Q->index];
+ if (p_top < q_top) {
+ e = cuddZddUnion(zdd, cuddE(P), Q);
+ if (e == NULL) return (NULL);
+ cuddRef(e);
+ res = cuddZddGetNode(zdd, P->index, cuddT(P), e);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(table, e);
+ return(NULL);
+ }
+ cuddDeref(e);
+ } else if (p_top > q_top) {
+ e = cuddZddUnion(zdd, P, cuddE(Q));
+ if (e == NULL) return(NULL);
+ cuddRef(e);
+ res = cuddZddGetNode(zdd, Q->index, cuddT(Q), e);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(table, e);
+ return(NULL);
+ }
+ cuddDeref(e);
+ } else {
+ t = cuddZddUnion(zdd, cuddT(P), cuddT(Q));
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = cuddZddUnion(zdd, cuddE(P), cuddE(Q));
+ if (e == NULL) {
+ Cudd_RecursiveDerefZdd(table, t);
+ return(NULL);
+ }
+ cuddRef(e);
+ res = cuddZddGetNode(zdd, P->index, t, e);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(table, t);
+ Cudd_RecursiveDerefZdd(table, e);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+ }
+
+ cuddCacheInsert2(table, cuddZddUnion, P, Q, res);
+
+ return(res);
+
+} /* end of cuddZddUnion */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddIntersect.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddZddIntersect(
+ DdManager * zdd,
+ DdNode * P,
+ DdNode * Q)
+{
+ int p_top, q_top;
+ DdNode *empty = DD_ZERO(zdd), *t, *e, *res;
+ DdManager *table = zdd;
+
+ statLine(zdd);
+ if (P == empty)
+ return(empty);
+ if (Q == empty)
+ return(empty);
+ if (P == Q)
+ return(P);
+
+ /* Check cache. */
+ res = cuddCacheLookup2Zdd(table, cuddZddIntersect, P, Q);
+ if (res != NULL)
+ return(res);
+
+ if (cuddIsConstant(P))
+ p_top = P->index;
+ else
+ p_top = zdd->permZ[P->index];
+ if (cuddIsConstant(Q))
+ q_top = Q->index;
+ else
+ q_top = zdd->permZ[Q->index];
+ if (p_top < q_top) {
+ res = cuddZddIntersect(zdd, cuddE(P), Q);
+ if (res == NULL) return(NULL);
+ } else if (p_top > q_top) {
+ res = cuddZddIntersect(zdd, P, cuddE(Q));
+ if (res == NULL) return(NULL);
+ } else {
+ t = cuddZddIntersect(zdd, cuddT(P), cuddT(Q));
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = cuddZddIntersect(zdd, cuddE(P), cuddE(Q));
+ if (e == NULL) {
+ Cudd_RecursiveDerefZdd(table, t);
+ return(NULL);
+ }
+ cuddRef(e);
+ res = cuddZddGetNode(zdd, P->index, t, e);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(table, t);
+ Cudd_RecursiveDerefZdd(table, e);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+ }
+
+ cuddCacheInsert2(table, cuddZddIntersect, P, Q, res);
+
+ return(res);
+
+} /* end of cuddZddIntersect */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddDiff.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddZddDiff(
+ DdManager * zdd,
+ DdNode * P,
+ DdNode * Q)
+{
+ int p_top, q_top;
+ DdNode *empty = DD_ZERO(zdd), *t, *e, *res;
+ DdManager *table = zdd;
+
+ statLine(zdd);
+ if (P == empty)
+ return(empty);
+ if (Q == empty)
+ return(P);
+ if (P == Q)
+ return(empty);
+
+ /* Check cache. The cache is shared by Cudd_zddDiffConst(). */
+ res = cuddCacheLookup2Zdd(table, cuddZddDiff, P, Q);
+ if (res != NULL && res != DD_NON_CONSTANT)
+ return(res);
+
+ if (cuddIsConstant(P))
+ p_top = P->index;
+ else
+ p_top = zdd->permZ[P->index];
+ if (cuddIsConstant(Q))
+ q_top = Q->index;
+ else
+ q_top = zdd->permZ[Q->index];
+ if (p_top < q_top) {
+ e = cuddZddDiff(zdd, cuddE(P), Q);
+ if (e == NULL) return(NULL);
+ cuddRef(e);
+ res = cuddZddGetNode(zdd, P->index, cuddT(P), e);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(table, e);
+ return(NULL);
+ }
+ cuddDeref(e);
+ } else if (p_top > q_top) {
+ res = cuddZddDiff(zdd, P, cuddE(Q));
+ if (res == NULL) return(NULL);
+ } else {
+ t = cuddZddDiff(zdd, cuddT(P), cuddT(Q));
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = cuddZddDiff(zdd, cuddE(P), cuddE(Q));
+ if (e == NULL) {
+ Cudd_RecursiveDerefZdd(table, t);
+ return(NULL);
+ }
+ cuddRef(e);
+ res = cuddZddGetNode(zdd, P->index, t, e);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(table, t);
+ Cudd_RecursiveDerefZdd(table, e);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+ }
+
+ cuddCacheInsert2(table, cuddZddDiff, P, Q, res);
+
+ return(res);
+
+} /* end of cuddZddDiff */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddChange.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddZddChangeAux(
+ DdManager * zdd,
+ DdNode * P,
+ DdNode * zvar)
+{
+ int top_var, level;
+ DdNode *res, *t, *e;
+ DdNode *base = DD_ONE(zdd);
+ DdNode *empty = DD_ZERO(zdd);
+
+ statLine(zdd);
+ if (P == empty)
+ return(empty);
+ if (P == base)
+ return(zvar);
+
+ /* Check cache. */
+ res = cuddCacheLookup2Zdd(zdd, cuddZddChangeAux, P, zvar);
+ if (res != NULL)
+ return(res);
+
+ top_var = zdd->permZ[P->index];
+ level = zdd->permZ[zvar->index];
+
+ if (top_var > level) {
+ res = cuddZddGetNode(zdd, zvar->index, P, DD_ZERO(zdd));
+ if (res == NULL) return(NULL);
+ } else if (top_var == level) {
+ res = cuddZddGetNode(zdd, zvar->index, cuddE(P), cuddT(P));
+ if (res == NULL) return(NULL);
+ } else {
+ t = cuddZddChangeAux(zdd, cuddT(P), zvar);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = cuddZddChangeAux(zdd, cuddE(P), zvar);
+ if (e == NULL) {
+ Cudd_RecursiveDerefZdd(zdd, t);
+ return(NULL);
+ }
+ cuddRef(e);
+ res = cuddZddGetNode(zdd, P->index, t, e);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(zdd, t);
+ Cudd_RecursiveDerefZdd(zdd, e);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+ }
+
+ cuddCacheInsert2(zdd, cuddZddChangeAux, P, zvar, res);
+
+ return(res);
+
+} /* end of cuddZddChangeAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the positive cofactor of a ZDD w.r.t. a variable.]
+
+ Description [Computes the positive cofactor of a ZDD w.r.t. a
+ variable. In terms of combinations, the result is the set of all
+ combinations in which the variable is asserted. Returns a pointer to
+ the result if successful; NULL otherwise. cuddZddSubset1 performs
+ the same function as Cudd_zddSubset1, but does not restart if
+ reordering has taken place. Therefore it can be called from within a
+ recursive procedure.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddZddSubset0 Cudd_zddSubset1]
+
+******************************************************************************/
+DdNode *
+cuddZddSubset1(
+ DdManager * dd,
+ DdNode * P,
+ int var)
+{
+ DdNode *zvar, *r;
+ DdNode *base, *empty;
+
+ base = DD_ONE(dd);
+ empty = DD_ZERO(dd);
+
+ zvar = cuddUniqueInterZdd(dd, var, base, empty);
+ if (zvar == NULL) {
+ return(NULL);
+ } else {
+ cuddRef(zvar);
+ r = zdd_subset1_aux(dd, P, zvar);
+ if (r == NULL) {
+ Cudd_RecursiveDerefZdd(dd, zvar);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_RecursiveDerefZdd(dd, zvar);
+ }
+
+ cuddDeref(r);
+ return(r);
+
+} /* end of cuddZddSubset1 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the negative cofactor of a ZDD w.r.t. a variable.]
+
+ Description [Computes the negative cofactor of a ZDD w.r.t. a
+ variable. In terms of combinations, the result is the set of all
+ combinations in which the variable is negated. Returns a pointer to
+ the result if successful; NULL otherwise. cuddZddSubset0 performs
+ the same function as Cudd_zddSubset0, but does not restart if
+ reordering has taken place. Therefore it can be called from within a
+ recursive procedure.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddZddSubset1 Cudd_zddSubset0]
+
+******************************************************************************/
+DdNode *
+cuddZddSubset0(
+ DdManager * dd,
+ DdNode * P,
+ int var)
+{
+ DdNode *zvar, *r;
+ DdNode *base, *empty;
+
+ base = DD_ONE(dd);
+ empty = DD_ZERO(dd);
+
+ zvar = cuddUniqueInterZdd(dd, var, base, empty);
+ if (zvar == NULL) {
+ return(NULL);
+ } else {
+ cuddRef(zvar);
+ r = zdd_subset0_aux(dd, P, zvar);
+ if (r == NULL) {
+ Cudd_RecursiveDerefZdd(dd, zvar);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_RecursiveDerefZdd(dd, zvar);
+ }
+
+ cuddDeref(r);
+ return(r);
+
+} /* end of cuddZddSubset0 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Substitutes a variable with its complement in a ZDD.]
+
+ Description [Substitutes a variable with its complement in a ZDD.
+ returns a pointer to the result if successful; NULL
+ otherwise. cuddZddChange performs the same function as
+ Cudd_zddChange, but does not restart if reordering has taken
+ place. Therefore it can be called from within a recursive
+ procedure.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddChange]
+
+******************************************************************************/
+DdNode *
+cuddZddChange(
+ DdManager * dd,
+ DdNode * P,
+ int var)
+{
+ DdNode *zvar, *res;
+
+ zvar = cuddUniqueInterZdd(dd, var, DD_ONE(dd), DD_ZERO(dd));
+ if (zvar == NULL) return(NULL);
+ cuddRef(zvar);
+
+ res = cuddZddChangeAux(dd, P, zvar);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(dd,zvar);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDerefZdd(dd,zvar);
+ cuddDeref(res);
+ return(res);
+
+} /* end of cuddZddChange */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddSubset1.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+zdd_subset1_aux(
+ DdManager * zdd,
+ DdNode * P,
+ DdNode * zvar)
+{
+ int top_var, level;
+ DdNode *res, *t, *e;
+ DdNode *base, *empty;
+
+ statLine(zdd);
+ base = DD_ONE(zdd);
+ empty = DD_ZERO(zdd);
+
+ /* Check cache. */
+ res = cuddCacheLookup2Zdd(zdd, zdd_subset1_aux, P, zvar);
+ if (res != NULL)
+ return(res);
+
+ if (cuddIsConstant(P)) {
+ res = empty;
+ cuddCacheInsert2(zdd, zdd_subset1_aux, P, zvar, res);
+ return(res);
+ }
+
+ top_var = zdd->permZ[P->index];
+ level = zdd->permZ[zvar->index];
+
+ if (top_var > level) {
+ res = empty;
+ } else if (top_var == level) {
+ res = cuddT(P);
+ } else {
+ t = zdd_subset1_aux(zdd, cuddT(P), zvar);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = zdd_subset1_aux(zdd, cuddE(P), zvar);
+ if (e == NULL) {
+ Cudd_RecursiveDerefZdd(zdd, t);
+ return(NULL);
+ }
+ cuddRef(e);
+ res = cuddZddGetNode(zdd, P->index, t, e);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(zdd, t);
+ Cudd_RecursiveDerefZdd(zdd, e);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+ }
+
+ cuddCacheInsert2(zdd, zdd_subset1_aux, P, zvar, res);
+
+ return(res);
+
+} /* end of zdd_subset1_aux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddSubset0.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+zdd_subset0_aux(
+ DdManager * zdd,
+ DdNode * P,
+ DdNode * zvar)
+{
+ int top_var, level;
+ DdNode *res, *t, *e;
+ DdNode *base, *empty;
+
+ statLine(zdd);
+ base = DD_ONE(zdd);
+ empty = DD_ZERO(zdd);
+
+ /* Check cache. */
+ res = cuddCacheLookup2Zdd(zdd, zdd_subset0_aux, P, zvar);
+ if (res != NULL)
+ return(res);
+
+ if (cuddIsConstant(P)) {
+ res = P;
+ cuddCacheInsert2(zdd, zdd_subset0_aux, P, zvar, res);
+ return(res);
+ }
+
+ top_var = zdd->permZ[P->index];
+ level = zdd->permZ[zvar->index];
+
+ if (top_var > level) {
+ res = P;
+ }
+ else if (top_var == level) {
+ res = cuddE(P);
+ }
+ else {
+ t = zdd_subset0_aux(zdd, cuddT(P), zvar);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = zdd_subset0_aux(zdd, cuddE(P), zvar);
+ if (e == NULL) {
+ Cudd_RecursiveDerefZdd(zdd, t);
+ return(NULL);
+ }
+ cuddRef(e);
+ res = cuddZddGetNode(zdd, P->index, t, e);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(zdd, t);
+ Cudd_RecursiveDerefZdd(zdd, e);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+ }
+
+ cuddCacheInsert2(zdd, zdd_subset0_aux, P, zvar, res);
+
+ return(res);
+
+} /* end of zdd_subset0_aux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Replaces variables with constants if possible (part of
+ canonical form).]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+zddVarToConst(
+ DdNode * f,
+ DdNode ** gp,
+ DdNode ** hp,
+ DdNode * base,
+ DdNode * empty)
+{
+ DdNode *g = *gp;
+ DdNode *h = *hp;
+
+ if (f == g) { /* ITE(F,F,H) = ITE(F,1,H) = F + H */
+ *gp = base;
+ }
+
+ if (f == h) { /* ITE(F,G,F) = ITE(F,G,0) = F * G */
+ *hp = empty;
+ }
+
+} /* end of zddVarToConst */
+
diff --git a/src/bdd/cudd/cuddZddSymm.c b/src/bdd/cudd/cuddZddSymm.c
new file mode 100644
index 00000000..c9ffaab4
--- /dev/null
+++ b/src/bdd/cudd/cuddZddSymm.c
@@ -0,0 +1,1677 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddSymm.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for symmetry-based ZDD variable reordering.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_zddSymmProfile()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddZddSymmCheck()
+ <li> cuddZddSymmSifting()
+ <li> cuddZddSymmSiftingConv()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddZddUniqueCompare()
+ <li> cuddZddSymmSiftingAux()
+ <li> cuddZddSymmSiftingConvAux()
+ <li> cuddZddSymmSifting_up()
+ <li> cuddZddSymmSifting_down()
+ <li> zdd_group_move()
+ <li> cuddZddSymmSiftingBackward()
+ <li> zdd_group_move_backward()
+ </ul>
+ ]
+
+ SeeAlso [cuddSymmetry.c]
+
+ Author [Hyong-Kyoon Shin, In-Ho Moon]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define ZDD_MV_OOM (Move *)1
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddSymm.c,v 1.1.1.1 2003/02/24 22:23:54 wjiang Exp $";
+#endif
+
+extern int *zdd_entry;
+
+extern int zddTotalNumberSwapping;
+
+static DdNode *empty;
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int cuddZddSymmSiftingAux ARGS((DdManager *table, int x, int x_low, int x_high));
+static int cuddZddSymmSiftingConvAux ARGS((DdManager *table, int x, int x_low, int x_high));
+static Move * cuddZddSymmSifting_up ARGS((DdManager *table, int x, int x_low, int initial_size));
+static Move * cuddZddSymmSifting_down ARGS((DdManager *table, int x, int x_high, int initial_size));
+static int cuddZddSymmSiftingBackward ARGS((DdManager *table, Move *moves, int size));
+static int zdd_group_move ARGS((DdManager *table, int x, int y, Move **moves));
+static int zdd_group_move_backward ARGS((DdManager *table, int x, int y));
+static void cuddZddSymmSummary ARGS((DdManager *table, int lower, int upper, int *symvars, int *symgroups));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints statistics on symmetric ZDD variables.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+Cudd_zddSymmProfile(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i, x, gbot;
+ int TotalSymm = 0;
+ int TotalSymmGroups = 0;
+ int nvars;
+
+ nvars = table->sizeZ;
+
+ for (i = lower; i < upper; i++) {
+ if (table->subtableZ[i].next != (unsigned) i) {
+ x = i;
+ (void) fprintf(table->out,"Group:");
+ do {
+ (void) fprintf(table->out," %d", table->invpermZ[x]);
+ TotalSymm++;
+ gbot = x;
+ x = table->subtableZ[x].next;
+ } while (x != i);
+ TotalSymmGroups++;
+#ifdef DD_DEBUG
+ assert(table->subtableZ[gbot].next == (unsigned) i);
+#endif
+ i = gbot;
+ (void) fprintf(table->out,"\n");
+ }
+ }
+ (void) fprintf(table->out,"Total Symmetric = %d\n", TotalSymm);
+ (void) fprintf(table->out,"Total Groups = %d\n", TotalSymmGroups);
+
+} /* end of Cudd_zddSymmProfile */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks for symmetry of x and y.]
+
+ Description [Checks for symmetry of x and y. Ignores projection
+ functions, unless they are isolated. Returns 1 in case of
+ symmetry; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddSymmCheck(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int i;
+ DdNode *f, *f0, *f1, *f01, *f00, *f11, *f10;
+ int yindex;
+ int xsymmy = 1;
+ int xsymmyp = 1;
+ int arccount = 0;
+ int TotalRefCount = 0;
+ int symm_found;
+
+ empty = table->zero;
+
+ yindex = table->invpermZ[y];
+ for (i = table->subtableZ[x].slots - 1; i >= 0; i--) {
+ f = table->subtableZ[x].nodelist[i];
+ while (f != NULL) {
+ /* Find f1, f0, f11, f10, f01, f00 */
+ f1 = cuddT(f);
+ f0 = cuddE(f);
+ if ((int) f1->index == yindex) {
+ f11 = cuddT(f1);
+ f10 = cuddE(f1);
+ if (f10 != empty)
+ arccount++;
+ } else {
+ if ((int) f0->index != yindex) {
+ return(0); /* f bypasses layer y */
+ }
+ f11 = empty;
+ f10 = f1;
+ }
+ if ((int) f0->index == yindex) {
+ f01 = cuddT(f0);
+ f00 = cuddE(f0);
+ if (f00 != empty)
+ arccount++;
+ } else {
+ f01 = empty;
+ f00 = f0;
+ }
+ if (f01 != f10)
+ xsymmy = 0;
+ if (f11 != f00)
+ xsymmyp = 0;
+ if ((xsymmy == 0) && (xsymmyp == 0))
+ return(0);
+
+ f = f->next;
+ } /* for each element of the collision list */
+ } /* for each slot of the subtable */
+
+ /* Calculate the total reference counts of y
+ ** whose else arc is not empty.
+ */
+ for (i = table->subtableZ[y].slots - 1; i >= 0; i--) {
+ f = table->subtableZ[y].nodelist[i];
+ while (f != NIL(DdNode)) {
+ if (cuddE(f) != empty)
+ TotalRefCount += f->ref;
+ f = f->next;
+ }
+ }
+
+ symm_found = (arccount == TotalRefCount);
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ if (symm_found) {
+ int xindex = table->invpermZ[x];
+ (void) fprintf(table->out,
+ "Found symmetry! x =%d\ty = %d\tPos(%d,%d)\n",
+ xindex,yindex,x,y);
+ }
+#endif
+
+ return(symm_found);
+
+} /* end cuddZddSymmCheck */
+
+
+/**Function********************************************************************
+
+ Synopsis [Symmetric sifting algorithm for ZDDs.]
+
+ Description [Symmetric sifting algorithm.
+ Assumes that no dead nodes are present.
+ <ol>
+ <li> Order all the variables according to the number of entries in
+ each unique subtable.
+ <li> Sift the variable up and down, remembering each time the total
+ size of the ZDD heap and grouping variables that are symmetric.
+ <li> Select the best permutation.
+ <li> Repeat 3 and 4 for all variables.
+ </ol>
+ Returns 1 plus the number of symmetric variables if successful; 0
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddZddSymmSiftingConv]
+
+******************************************************************************/
+int
+cuddZddSymmSifting(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i;
+ int *var;
+ int nvars;
+ int x;
+ int result;
+ int symvars;
+ int symgroups;
+ int iteration;
+#ifdef DD_STATS
+ int previousSize;
+#endif
+
+ nvars = table->sizeZ;
+
+ /* Find order in which to sift variables. */
+ var = NULL;
+ zdd_entry = ALLOC(int, nvars);
+ if (zdd_entry == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddZddSymmSiftingOutOfMem;
+ }
+ var = ALLOC(int, nvars);
+ if (var == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddZddSymmSiftingOutOfMem;
+ }
+
+ for (i = 0; i < nvars; i++) {
+ x = table->permZ[i];
+ zdd_entry[i] = table->subtableZ[x].keys;
+ var[i] = i;
+ }
+
+ qsort((void *)var, nvars, sizeof(int), (int (*)(const void *, const void *))cuddZddUniqueCompare);
+
+ /* Initialize the symmetry of each subtable to itself. */
+ for (i = lower; i <= upper; i++)
+ table->subtableZ[i].next = i;
+
+ iteration = ddMin(table->siftMaxVar, nvars);
+ for (i = 0; i < iteration; i++) {
+ if (zddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ x = table->permZ[var[i]];
+#ifdef DD_STATS
+ previousSize = table->keysZ;
+#endif
+ if (x < lower || x > upper) continue;
+ if (table->subtableZ[x].next == (unsigned) x) {
+ result = cuddZddSymmSiftingAux(table, x, lower, upper);
+ if (!result)
+ goto cuddZddSymmSiftingOutOfMem;
+#ifdef DD_STATS
+ if (table->keysZ < (unsigned) previousSize) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keysZ > (unsigned) previousSize) {
+ (void) fprintf(table->out,"+");
+#ifdef DD_VERBOSE
+ (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ, var[i]);
+#endif
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+ }
+
+ FREE(var);
+ FREE(zdd_entry);
+
+ cuddZddSymmSummary(table, lower, upper, &symvars, &symgroups);
+
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n#:S_SIFTING %8d: symmetric variables\n",symvars);
+ (void) fprintf(table->out,"#:G_SIFTING %8d: symmetric groups\n",symgroups);
+#endif
+
+ return(1+symvars);
+
+cuddZddSymmSiftingOutOfMem:
+
+ if (zdd_entry != NULL)
+ FREE(zdd_entry);
+ if (var != NULL)
+ FREE(var);
+
+ return(0);
+
+} /* end of cuddZddSymmSifting */
+
+
+/**Function********************************************************************
+
+ Synopsis [Symmetric sifting to convergence algorithm for ZDDs.]
+
+ Description [Symmetric sifting to convergence algorithm for ZDDs.
+ Assumes that no dead nodes are present.
+ <ol>
+ <li> Order all the variables according to the number of entries in
+ each unique subtable.
+ <li> Sift the variable up and down, remembering each time the total
+ size of the ZDD heap and grouping variables that are symmetric.
+ <li> Select the best permutation.
+ <li> Repeat 3 and 4 for all variables.
+ <li> Repeat 1-4 until no further improvement.
+ </ol>
+ Returns 1 plus the number of symmetric variables if successful; 0
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddZddSymmSifting]
+
+******************************************************************************/
+int
+cuddZddSymmSiftingConv(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i;
+ int *var;
+ int nvars;
+ int initialSize;
+ int x;
+ int result;
+ int symvars;
+ int symgroups;
+ int classes;
+ int iteration;
+#ifdef DD_STATS
+ int previousSize;
+#endif
+
+ initialSize = table->keysZ;
+
+ nvars = table->sizeZ;
+
+ /* Find order in which to sift variables. */
+ var = NULL;
+ zdd_entry = ALLOC(int, nvars);
+ if (zdd_entry == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddZddSymmSiftingConvOutOfMem;
+ }
+ var = ALLOC(int, nvars);
+ if (var == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddZddSymmSiftingConvOutOfMem;
+ }
+
+ for (i = 0; i < nvars; i++) {
+ x = table->permZ[i];
+ zdd_entry[i] = table->subtableZ[x].keys;
+ var[i] = i;
+ }
+
+ qsort((void *)var, nvars, sizeof(int), (int (*)(const void *, const void *))cuddZddUniqueCompare);
+
+ /* Initialize the symmetry of each subtable to itself
+ ** for first pass of converging symmetric sifting.
+ */
+ for (i = lower; i <= upper; i++)
+ table->subtableZ[i].next = i;
+
+ iteration = ddMin(table->siftMaxVar, table->sizeZ);
+ for (i = 0; i < iteration; i++) {
+ if (zddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ x = table->permZ[var[i]];
+ if (x < lower || x > upper) continue;
+ /* Only sift if not in symmetry group already. */
+ if (table->subtableZ[x].next == (unsigned) x) {
+#ifdef DD_STATS
+ previousSize = table->keysZ;
+#endif
+ result = cuddZddSymmSiftingAux(table, x, lower, upper);
+ if (!result)
+ goto cuddZddSymmSiftingConvOutOfMem;
+#ifdef DD_STATS
+ if (table->keysZ < (unsigned) previousSize) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keysZ > (unsigned) previousSize) {
+ (void) fprintf(table->out,"+");
+#ifdef DD_VERBOSE
+ (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ, var[i]);
+#endif
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+ }
+
+ /* Sifting now until convergence. */
+ while ((unsigned) initialSize > table->keysZ) {
+ initialSize = table->keysZ;
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n");
+#endif
+ /* Here we consider only one representative for each symmetry class. */
+ for (x = lower, classes = 0; x <= upper; x++, classes++) {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ /* Here x is the largest index in a group.
+ ** Groups consists of adjacent variables.
+ ** Hence, the next increment of x will move it to a new group.
+ */
+ i = table->invpermZ[x];
+ zdd_entry[i] = table->subtableZ[x].keys;
+ var[classes] = i;
+ }
+
+ qsort((void *)var,classes,sizeof(int),(int (*)(const void *, const void *))cuddZddUniqueCompare);
+
+ /* Now sift. */
+ iteration = ddMin(table->siftMaxVar, nvars);
+ for (i = 0; i < iteration; i++) {
+ if (zddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ x = table->permZ[var[i]];
+ if ((unsigned) x >= table->subtableZ[x].next) {
+#ifdef DD_STATS
+ previousSize = table->keysZ;
+#endif
+ result = cuddZddSymmSiftingConvAux(table, x, lower, upper);
+ if (!result)
+ goto cuddZddSymmSiftingConvOutOfMem;
+#ifdef DD_STATS
+ if (table->keysZ < (unsigned) previousSize) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keysZ > (unsigned) previousSize) {
+ (void) fprintf(table->out,"+");
+#ifdef DD_VERBOSE
+ (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ, var[i]);
+#endif
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+ } /* for */
+ }
+
+ cuddZddSymmSummary(table, lower, upper, &symvars, &symgroups);
+
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n#:S_SIFTING %8d: symmetric variables\n",
+ symvars);
+ (void) fprintf(table->out,"#:G_SIFTING %8d: symmetric groups\n",
+ symgroups);
+#endif
+
+ FREE(var);
+ FREE(zdd_entry);
+
+ return(1+symvars);
+
+cuddZddSymmSiftingConvOutOfMem:
+
+ if (zdd_entry != NULL)
+ FREE(zdd_entry);
+ if (var != NULL)
+ FREE(var);
+
+ return(0);
+
+} /* end of cuddZddSymmSiftingConv */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Given x_low <= x <= x_high moves x up and down between the
+ boundaries.]
+
+ Description [Given x_low <= x <= x_high moves x up and down between the
+ boundaries. Finds the best position and does the required changes.
+ Assumes that x is not part of a symmetry group. Returns 1 if
+ successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddZddSymmSiftingAux(
+ DdManager * table,
+ int x,
+ int x_low,
+ int x_high)
+{
+ Move *move;
+ Move *move_up; /* list of up move */
+ Move *move_down; /* list of down move */
+ int initial_size;
+ int result;
+ int i;
+ int topbot; /* index to either top or bottom of symmetry group */
+ int init_group_size, final_group_size;
+
+ initial_size = table->keysZ;
+
+ move_down = NULL;
+ move_up = NULL;
+
+ /* Look for consecutive symmetries above x. */
+ for (i = x; i > x_low; i--) {
+ if (!cuddZddSymmCheck(table, i - 1, i))
+ break;
+ /* find top of i-1's symmetry */
+ topbot = table->subtableZ[i - 1].next;
+ table->subtableZ[i - 1].next = i;
+ table->subtableZ[x].next = topbot;
+ /* x is bottom of group so its symmetry is top of i-1's
+ group */
+ i = topbot + 1; /* add 1 for i--, new i is top of symm group */
+ }
+ /* Look for consecutive symmetries below x. */
+ for (i = x; i < x_high; i++) {
+ if (!cuddZddSymmCheck(table, i, i + 1))
+ break;
+ /* find bottom of i+1's symm group */
+ topbot = i + 1;
+ while ((unsigned) topbot < table->subtableZ[topbot].next)
+ topbot = table->subtableZ[topbot].next;
+
+ table->subtableZ[topbot].next = table->subtableZ[i].next;
+ table->subtableZ[i].next = i + 1;
+ i = topbot - 1; /* add 1 for i++,
+ new i is bottom of symm group */
+ }
+
+ /* Now x maybe in the middle of a symmetry group. */
+ if (x == x_low) { /* Sift down */
+ /* Find bottom of x's symm group */
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+
+ i = table->subtableZ[x].next;
+ init_group_size = x - i + 1;
+
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ /* after that point x --> x_high, unless early term */
+ if (move_down == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+
+ if (move_down == NULL ||
+ table->subtableZ[move_down->y].next != move_down->y) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_down != NULL)
+ x = move_down->y;
+ else
+ x = table->subtableZ[x].next;
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ final_group_size = i - x + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetry groups detected,
+ return to best position */
+ result = cuddZddSymmSiftingBackward(table,
+ move_down, initial_size);
+ }
+ else {
+ initial_size = table->keysZ;
+ move_up = cuddZddSymmSifting_up(table, x, x_low,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+ }
+ else if (x == x_high) { /* Sift up */
+ /* Find top of x's symm group */
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ x = table->subtableZ[x].next;
+
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ init_group_size = i - x + 1;
+
+ move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size);
+ /* after that point x --> x_low, unless early term */
+ if (move_up == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+
+ if (move_up == NULL ||
+ table->subtableZ[move_up->x].next != move_up->x) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_up != NULL)
+ x = move_up->x;
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ }
+ i = table->subtableZ[x].next;
+ final_group_size = x - i + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetry groups detected,
+ return to best position */
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ else {
+ initial_size = table->keysZ;
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+ }
+ else if ((x - x_low) > (x_high - x)) { /* must go down first:
+ shorter */
+ /* Find bottom of x's symm group */
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ /* after that point x --> x_high, unless early term */
+ if (move_down == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+
+ if (move_down != NULL) {
+ x = move_down->y;
+ }
+ else {
+ x = table->subtableZ[x].next;
+ }
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ init_group_size = i - x + 1;
+
+ move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size);
+ if (move_up == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+
+ if (move_up == NULL ||
+ table->subtableZ[move_up->x].next != move_up->x) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_up != NULL) {
+ x = move_up->x;
+ }
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ }
+ i = table->subtableZ[x].next;
+ final_group_size = x - i + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetry groups detected,
+ return to best position */
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ else {
+ while (move_down != NULL) {
+ move = move_down->next;
+ cuddDeallocNode(table, (DdNode *)move_down);
+ move_down = move;
+ }
+ initial_size = table->keysZ;
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+ }
+ else { /* moving up first:shorter */
+ /* Find top of x's symmetry group */
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ x = table->subtableZ[x].next;
+
+ move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size);
+ /* after that point x --> x_high, unless early term */
+ if (move_up == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+
+ if (move_up != NULL) {
+ x = move_up->x;
+ }
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ }
+ i = table->subtableZ[x].next;
+ init_group_size = x - i + 1;
+
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ if (move_down == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+
+ if (move_down == NULL ||
+ table->subtableZ[move_down->y].next != move_down->y) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_down != NULL) {
+ x = move_down->y;
+ }
+ else {
+ x = table->subtableZ[x].next;
+ }
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ final_group_size = i - x + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetries detected,
+ go back to best position */
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ }
+ else {
+ while (move_up != NULL) {
+ move = move_up->next;
+ cuddDeallocNode(table, (DdNode *)move_up);
+ move_up = move;
+ }
+ initial_size = table->keysZ;
+ move_up = cuddZddSymmSifting_up(table, x, x_low,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+ }
+
+ while (move_down != NULL) {
+ move = move_down->next;
+ cuddDeallocNode(table, (DdNode *)move_down);
+ move_down = move;
+ }
+ while (move_up != NULL) {
+ move = move_up->next;
+ cuddDeallocNode(table, (DdNode *)move_up);
+ move_up = move;
+ }
+
+ return(1);
+
+cuddZddSymmSiftingAuxOutOfMem:
+ if (move_down != ZDD_MV_OOM) {
+ while (move_down != NULL) {
+ move = move_down->next;
+ cuddDeallocNode(table, (DdNode *)move_down);
+ move_down = move;
+ }
+ }
+ if (move_up != ZDD_MV_OOM) {
+ while (move_up != NULL) {
+ move = move_up->next;
+ cuddDeallocNode(table, (DdNode *)move_up);
+ move_up = move;
+ }
+ }
+
+ return(0);
+
+} /* end of cuddZddSymmSiftingAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given x_low <= x <= x_high moves x up and down between the
+ boundaries.]
+
+ Description [Given x_low <= x <= x_high moves x up and down between the
+ boundaries. Finds the best position and does the required changes.
+ Assumes that x is either an isolated variable, or it is the bottom of
+ a symmetry group. All symmetries may not have been found, because of
+ exceeded growth limit. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddZddSymmSiftingConvAux(
+ DdManager * table,
+ int x,
+ int x_low,
+ int x_high)
+{
+ Move *move;
+ Move *move_up; /* list of up move */
+ Move *move_down; /* list of down move */
+ int initial_size;
+ int result;
+ int i;
+ int init_group_size, final_group_size;
+
+ initial_size = table->keysZ;
+
+ move_down = NULL;
+ move_up = NULL;
+
+ if (x == x_low) { /* Sift down */
+ i = table->subtableZ[x].next;
+ init_group_size = x - i + 1;
+
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ /* after that point x --> x_high, unless early term */
+ if (move_down == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+
+ if (move_down == NULL ||
+ table->subtableZ[move_down->y].next != move_down->y) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_down != NULL)
+ x = move_down->y;
+ else {
+ while ((unsigned) x < table->subtableZ[x].next);
+ x = table->subtableZ[x].next;
+ x = table->subtableZ[x].next;
+ }
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ final_group_size = i - x + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetries detected,
+ go back to best position */
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ }
+ else {
+ initial_size = table->keysZ;
+ move_up = cuddZddSymmSifting_up(table, x, x_low,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+ }
+ else if (x == x_high) { /* Sift up */
+ /* Find top of x's symm group */
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ x = table->subtableZ[x].next;
+
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ init_group_size = i - x + 1;
+
+ move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size);
+ /* after that point x --> x_low, unless early term */
+ if (move_up == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+
+ if (move_up == NULL ||
+ table->subtableZ[move_up->x].next != move_up->x) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_up != NULL)
+ x = move_up->x;
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ }
+ i = table->subtableZ[x].next;
+ final_group_size = x - i + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetry groups detected,
+ return to best position */
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ else {
+ initial_size = table->keysZ;
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+ }
+ else if ((x - x_low) > (x_high - x)) { /* must go down first:
+ shorter */
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ /* after that point x --> x_high */
+ if (move_down == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+
+ if (move_down != NULL) {
+ x = move_down->y;
+ }
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ x = table->subtableZ[x].next;
+ }
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ init_group_size = i - x + 1;
+
+ move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size);
+ if (move_up == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+
+ if (move_up == NULL ||
+ table->subtableZ[move_up->x].next != move_up->x) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_up != NULL) {
+ x = move_up->x;
+ }
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ }
+ i = table->subtableZ[x].next;
+ final_group_size = x - i + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetry groups detected,
+ return to best position */
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ else {
+ while (move_down != NULL) {
+ move = move_down->next;
+ cuddDeallocNode(table, (DdNode *)move_down);
+ move_down = move;
+ }
+ initial_size = table->keysZ;
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+ }
+ else { /* moving up first:shorter */
+ /* Find top of x's symmetry group */
+ x = table->subtableZ[x].next;
+
+ move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size);
+ /* after that point x --> x_high, unless early term */
+ if (move_up == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+
+ if (move_up != NULL) {
+ x = move_up->x;
+ }
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ }
+ i = table->subtableZ[x].next;
+ init_group_size = x - i + 1;
+
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ if (move_down == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+
+ if (move_down == NULL ||
+ table->subtableZ[move_down->y].next != move_down->y) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_down != NULL) {
+ x = move_down->y;
+ }
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ x = table->subtableZ[x].next;
+ }
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ final_group_size = i - x + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetries detected,
+ go back to best position */
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ }
+ else {
+ while (move_up != NULL) {
+ move = move_up->next;
+ cuddDeallocNode(table, (DdNode *)move_up);
+ move_up = move;
+ }
+ initial_size = table->keysZ;
+ move_up = cuddZddSymmSifting_up(table, x, x_low,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+ }
+
+ while (move_down != NULL) {
+ move = move_down->next;
+ cuddDeallocNode(table, (DdNode *)move_down);
+ move_down = move;
+ }
+ while (move_up != NULL) {
+ move = move_up->next;
+ cuddDeallocNode(table, (DdNode *)move_up);
+ move_up = move;
+ }
+
+ return(1);
+
+cuddZddSymmSiftingConvAuxOutOfMem:
+ if (move_down != ZDD_MV_OOM) {
+ while (move_down != NULL) {
+ move = move_down->next;
+ cuddDeallocNode(table, (DdNode *)move_down);
+ move_down = move;
+ }
+ }
+ if (move_up != ZDD_MV_OOM) {
+ while (move_up != NULL) {
+ move = move_up->next;
+ cuddDeallocNode(table, (DdNode *)move_up);
+ move_up = move;
+ }
+ }
+
+ return(0);
+
+} /* end of cuddZddSymmSiftingConvAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Moves x up until either it reaches the bound (x_low) or
+ the size of the ZDD heap increases too much.]
+
+ Description [Moves x up until either it reaches the bound (x_low) or
+ the size of the ZDD heap increases too much. Assumes that x is the top
+ of a symmetry group. Checks x for symmetry to the adjacent
+ variables. If symmetry is found, the symmetry group of x is merged
+ with the symmetry group of the other variable. Returns the set of
+ moves in case of success; ZDD_MV_OOM if memory is full.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static Move *
+cuddZddSymmSifting_up(
+ DdManager * table,
+ int x,
+ int x_low,
+ int initial_size)
+{
+ Move *moves;
+ Move *move;
+ int y;
+ int size;
+ int limit_size = initial_size;
+ int i, gytop;
+
+ moves = NULL;
+ y = cuddZddNextLow(table, x);
+ while (y >= x_low) {
+ gytop = table->subtableZ[y].next;
+ if (cuddZddSymmCheck(table, y, x)) {
+ /* Symmetry found, attach symm groups */
+ table->subtableZ[y].next = x;
+ i = table->subtableZ[x].next;
+ while (table->subtableZ[i].next != (unsigned) x)
+ i = table->subtableZ[i].next;
+ table->subtableZ[i].next = gytop;
+ }
+ else if ((table->subtableZ[x].next == (unsigned) x) &&
+ (table->subtableZ[y].next == (unsigned) y)) {
+ /* x and y have self symmetry */
+ size = cuddZddSwapInPlace(table, y, x);
+ if (size == 0)
+ goto cuddZddSymmSifting_upOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto cuddZddSymmSifting_upOutOfMem;
+ move->x = y;
+ move->y = x;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ if ((double)size >
+ (double)limit_size * table->maxGrowth)
+ return(moves);
+ if (size < limit_size)
+ limit_size = size;
+ }
+ else { /* Group move */
+ size = zdd_group_move(table, y, x, &moves);
+ if ((double)size >
+ (double)limit_size * table->maxGrowth)
+ return(moves);
+ if (size < limit_size)
+ limit_size = size;
+ }
+ x = gytop;
+ y = cuddZddNextLow(table, x);
+ }
+
+ return(moves);
+
+cuddZddSymmSifting_upOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *)moves);
+ moves = move;
+ }
+ return(ZDD_MV_OOM);
+
+} /* end of cuddZddSymmSifting_up */
+
+
+/**Function********************************************************************
+
+ Synopsis [Moves x down until either it reaches the bound (x_high) or
+ the size of the ZDD heap increases too much.]
+
+ Description [Moves x down until either it reaches the bound (x_high)
+ or the size of the ZDD heap increases too much. Assumes that x is the
+ bottom of a symmetry group. Checks x for symmetry to the adjacent
+ variables. If symmetry is found, the symmetry group of x is merged
+ with the symmetry group of the other variable. Returns the set of
+ moves in case of success; ZDD_MV_OOM if memory is full.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static Move *
+cuddZddSymmSifting_down(
+ DdManager * table,
+ int x,
+ int x_high,
+ int initial_size)
+{
+ Move *moves;
+ Move *move;
+ int y;
+ int size;
+ int limit_size = initial_size;
+ int i, gxtop, gybot;
+
+ moves = NULL;
+ y = cuddZddNextHigh(table, x);
+ while (y <= x_high) {
+ gybot = table->subtableZ[y].next;
+ while (table->subtableZ[gybot].next != (unsigned) y)
+ gybot = table->subtableZ[gybot].next;
+ if (cuddZddSymmCheck(table, x, y)) {
+ /* Symmetry found, attach symm groups */
+ gxtop = table->subtableZ[x].next;
+ table->subtableZ[x].next = y;
+ i = table->subtableZ[y].next;
+ while (table->subtableZ[i].next != (unsigned) y)
+ i = table->subtableZ[i].next;
+ table->subtableZ[i].next = gxtop;
+ }
+ else if ((table->subtableZ[x].next == (unsigned) x) &&
+ (table->subtableZ[y].next == (unsigned) y)) {
+ /* x and y have self symmetry */
+ size = cuddZddSwapInPlace(table, x, y);
+ if (size == 0)
+ goto cuddZddSymmSifting_downOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto cuddZddSymmSifting_downOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ if ((double)size >
+ (double)limit_size * table->maxGrowth)
+ return(moves);
+ if (size < limit_size)
+ limit_size = size;
+ x = y;
+ y = cuddZddNextHigh(table, x);
+ }
+ else { /* Group move */
+ size = zdd_group_move(table, x, y, &moves);
+ if ((double)size >
+ (double)limit_size * table->maxGrowth)
+ return(moves);
+ if (size < limit_size)
+ limit_size = size;
+ }
+ x = gybot;
+ y = cuddZddNextHigh(table, x);
+ }
+
+ return(moves);
+
+cuddZddSymmSifting_downOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *)moves);
+ moves = move;
+ }
+ return(ZDD_MV_OOM);
+
+} /* end of cuddZddSymmSifting_down */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given a set of moves, returns the ZDD heap to the position
+ giving the minimum size.]
+
+ Description [Given a set of moves, returns the ZDD heap to the
+ position giving the minimum size. In case of ties, returns to the
+ closest position giving the minimum size. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddZddSymmSiftingBackward(
+ DdManager * table,
+ Move * moves,
+ int size)
+{
+ int i;
+ int i_best;
+ Move *move;
+ int res;
+
+ i_best = -1;
+ for (move = moves, i = 0; move != NULL; move = move->next, i++) {
+ if (move->size < size) {
+ i_best = i;
+ size = move->size;
+ }
+ }
+
+ for (move = moves, i = 0; move != NULL; move = move->next, i++) {
+ if (i == i_best) break;
+ if ((table->subtableZ[move->x].next == move->x) &&
+ (table->subtableZ[move->y].next == move->y)) {
+ res = cuddZddSwapInPlace(table, move->x, move->y);
+ if (!res) return(0);
+ }
+ else { /* Group move necessary */
+ res = zdd_group_move_backward(table, move->x, move->y);
+ }
+ if (i_best == -1 && res == size)
+ break;
+ }
+
+ return(1);
+
+} /* end of cuddZddSymmSiftingBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps two groups.]
+
+ Description [Swaps two groups. x is assumed to be the bottom variable
+ of the first group. y is assumed to be the top variable of the second
+ group. Updates the list of moves. Returns the number of keys in the
+ table if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+zdd_group_move(
+ DdManager * table,
+ int x,
+ int y,
+ Move ** moves)
+{
+ Move *move;
+ int size;
+ int i, temp, gxtop, gxbot, gytop, gybot, yprev;
+ int swapx, swapy;
+
+#ifdef DD_DEBUG
+ assert(x < y); /* we assume that x < y */
+#endif
+ /* Find top and bottom for the two groups. */
+ gxtop = table->subtableZ[x].next;
+ gytop = y;
+ gxbot = x;
+ gybot = table->subtableZ[y].next;
+ while (table->subtableZ[gybot].next != (unsigned) y)
+ gybot = table->subtableZ[gybot].next;
+ yprev = gybot;
+
+ while (x <= y) {
+ while (y > gxtop) {
+ /* Set correct symmetries. */
+ temp = table->subtableZ[x].next;
+ if (temp == x)
+ temp = y;
+ i = gxtop;
+ for (;;) {
+ if (table->subtableZ[i].next == (unsigned) x) {
+ table->subtableZ[i].next = y;
+ break;
+ } else {
+ i = table->subtableZ[i].next;
+ }
+ }
+ if (table->subtableZ[y].next != (unsigned) y) {
+ table->subtableZ[x].next = table->subtableZ[y].next;
+ } else {
+ table->subtableZ[x].next = x;
+ }
+
+ if (yprev != y) {
+ table->subtableZ[yprev].next = x;
+ } else {
+ yprev = x;
+ }
+ table->subtableZ[y].next = temp;
+
+ size = cuddZddSwapInPlace(table, x, y);
+ if (size == 0)
+ goto zdd_group_moveOutOfMem;
+ swapx = x;
+ swapy = y;
+ y = x;
+ x--;
+ } /* while y > gxtop */
+
+ /* Trying to find the next y. */
+ if (table->subtableZ[y].next <= (unsigned) y) {
+ gybot = y;
+ } else {
+ y = table->subtableZ[y].next;
+ }
+
+ yprev = gxtop;
+ gxtop++;
+ gxbot++;
+ x = gxbot;
+ } /* while x <= y, end of group movement */
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto zdd_group_moveOutOfMem;
+ move->x = swapx;
+ move->y = swapy;
+ move->size = table->keysZ;
+ move->next = *moves;
+ *moves = move;
+
+ return(table->keysZ);
+
+zdd_group_moveOutOfMem:
+ while (*moves != NULL) {
+ move = (*moves)->next;
+ cuddDeallocNode(table, (DdNode *)(*moves));
+ *moves = move;
+ }
+ return(0);
+
+} /* end of zdd_group_move */
+
+
+/**Function********************************************************************
+
+ Synopsis [Undoes the swap of two groups.]
+
+ Description [Undoes the swap of two groups. x is assumed to be the
+ bottom variable of the first group. y is assumed to be the top
+ variable of the second group. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+zdd_group_move_backward(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int size;
+ int i, temp, gxtop, gxbot, gytop, gybot, yprev;
+
+#ifdef DD_DEBUG
+ assert(x < y); /* we assume that x < y */
+#endif
+ /* Find top and bottom of the two groups. */
+ gxtop = table->subtableZ[x].next;
+ gytop = y;
+ gxbot = x;
+ gybot = table->subtableZ[y].next;
+ while (table->subtableZ[gybot].next != (unsigned) y)
+ gybot = table->subtableZ[gybot].next;
+ yprev = gybot;
+
+ while (x <= y) {
+ while (y > gxtop) {
+ /* Set correct symmetries. */
+ temp = table->subtableZ[x].next;
+ if (temp == x)
+ temp = y;
+ i = gxtop;
+ for (;;) {
+ if (table->subtableZ[i].next == (unsigned) x) {
+ table->subtableZ[i].next = y;
+ break;
+ } else {
+ i = table->subtableZ[i].next;
+ }
+ }
+ if (table->subtableZ[y].next != (unsigned) y) {
+ table->subtableZ[x].next = table->subtableZ[y].next;
+ } else {
+ table->subtableZ[x].next = x;
+ }
+
+ if (yprev != y) {
+ table->subtableZ[yprev].next = x;
+ } else {
+ yprev = x;
+ }
+ table->subtableZ[y].next = temp;
+
+ size = cuddZddSwapInPlace(table, x, y);
+ if (size == 0)
+ return(0);
+ y = x;
+ x--;
+ } /* while y > gxtop */
+
+ /* Trying to find the next y. */
+ if (table->subtableZ[y].next <= (unsigned) y) {
+ gybot = y;
+ } else {
+ y = table->subtableZ[y].next;
+ }
+
+ yprev = gxtop;
+ gxtop++;
+ gxbot++;
+ x = gxbot;
+ } /* while x <= y, end of group movement backward */
+
+ return(size);
+
+} /* end of zdd_group_move_backward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts numbers of symmetric variables and symmetry
+ groups.]
+
+ Description []
+
+ SideEffects [None]
+
+******************************************************************************/
+static void
+cuddZddSymmSummary(
+ DdManager * table,
+ int lower,
+ int upper,
+ int * symvars,
+ int * symgroups)
+{
+ int i,x,gbot;
+ int TotalSymm = 0;
+ int TotalSymmGroups = 0;
+
+ for (i = lower; i <= upper; i++) {
+ if (table->subtableZ[i].next != (unsigned) i) {
+ TotalSymmGroups++;
+ x = i;
+ do {
+ TotalSymm++;
+ gbot = x;
+ x = table->subtableZ[x].next;
+ } while (x != i);
+#ifdef DD_DEBUG
+ assert(table->subtableZ[gbot].next == (unsigned) i);
+#endif
+ i = gbot;
+ }
+ }
+ *symvars = TotalSymm;
+ *symgroups = TotalSymmGroups;
+
+ return;
+
+} /* end of cuddZddSymmSummary */
+
diff --git a/src/bdd/cudd/cuddZddUtil.c b/src/bdd/cudd/cuddZddUtil.c
new file mode 100644
index 00000000..0795f123
--- /dev/null
+++ b/src/bdd/cudd/cuddZddUtil.c
@@ -0,0 +1,1021 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddUtil.c]
+
+ PackageName [cudd]
+
+ Synopsis [Utility functions for ZDDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_zddPrintMinterm()
+ <li> Cudd_zddPrintCover()
+ <li> Cudd_zddPrintDebug()
+ <li> Cudd_zddDumpDot()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddZddP()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> zp2()
+ <li> zdd_print_minterm_aux()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Hyong-Kyoon Shin, In-Ho Moon]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddUtil.c,v 1.1.1.1 2003/02/24 22:23:54 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int zp2 ARGS((DdManager *zdd, DdNode *f, st_table *t));
+static void zdd_print_minterm_aux ARGS((DdManager *zdd, DdNode *node, int level, int *list));
+static void zddPrintCoverAux ARGS((DdManager *zdd, DdNode *node, int level, int *list));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints a disjoint sum of product form for a ZDD.]
+
+ Description [Prints a disjoint sum of product form for a ZDD. Returns 1
+ if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddPrintDebug Cudd_zddPrintCover]
+
+******************************************************************************/
+int
+Cudd_zddPrintMinterm(
+ DdManager * zdd,
+ DdNode * node)
+{
+ int i, size;
+ int *list;
+
+ size = (int)zdd->sizeZ;
+ list = ALLOC(int, size);
+ if (list == NULL) {
+ zdd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (i = 0; i < size; i++) list[i] = 3; /* bogus value should disappear */
+ zdd_print_minterm_aux(zdd, node, 0, list);
+ FREE(list);
+ return(1);
+
+} /* end of Cudd_zddPrintMinterm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints a sum of products from a ZDD representing a cover.]
+
+ Description [Prints a sum of products from a ZDD representing a cover.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddPrintMinterm]
+
+******************************************************************************/
+int
+Cudd_zddPrintCover(
+ DdManager * zdd,
+ DdNode * node)
+{
+ int i, size;
+ int *list;
+
+ size = (int)zdd->sizeZ;
+ if (size % 2 != 0) return(0); /* number of variables should be even */
+ list = ALLOC(int, size);
+ if (list == NULL) {
+ zdd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (i = 0; i < size; i++) list[i] = 3; /* bogus value should disappear */
+ zddPrintCoverAux(zdd, node, 0, list);
+ FREE(list);
+ return(1);
+
+} /* end of Cudd_zddPrintCover */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints to the standard output a ZDD and its statistics.]
+
+ Description [Prints to the standard output a DD and its statistics.
+ The statistics include the number of nodes and the number of minterms.
+ (The number of minterms is also the number of combinations in the set.)
+ The statistics are printed if pr &gt; 0. Specifically:
+ <ul>
+ <li> pr = 0 : prints nothing
+ <li> pr = 1 : prints counts of nodes and minterms
+ <li> pr = 2 : prints counts + disjoint sum of products
+ <li> pr = 3 : prints counts + list of nodes
+ <li> pr &gt; 3 : prints counts + disjoint sum of products + list of nodes
+ </ul>
+ Returns 1 if successful; 0 otherwise.
+ ]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_zddPrintDebug(
+ DdManager * zdd,
+ DdNode * f,
+ int n,
+ int pr)
+{
+ DdNode *empty = DD_ZERO(zdd);
+ int nodes;
+ double minterms;
+ int retval = 1;
+
+ if (f == empty && pr > 0) {
+ (void) fprintf(zdd->out,": is the empty ZDD\n");
+ (void) fflush(zdd->out);
+ return(1);
+ }
+
+ if (pr > 0) {
+ nodes = Cudd_zddDagSize(f);
+ if (nodes == CUDD_OUT_OF_MEM) retval = 0;
+ minterms = Cudd_zddCountMinterm(zdd, f, n);
+ if (minterms == (double)CUDD_OUT_OF_MEM) retval = 0;
+ (void) fprintf(zdd->out,": %d nodes %g minterms\n",
+ nodes, minterms);
+ if (pr > 2)
+ if (!cuddZddP(zdd, f)) retval = 0;
+ if (pr == 2 || pr > 3) {
+ if (!Cudd_zddPrintMinterm(zdd, f)) retval = 0;
+ (void) fprintf(zdd->out,"\n");
+ }
+ (void) fflush(zdd->out);
+ }
+ return(retval);
+
+} /* end of Cudd_zddPrintDebug */
+
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the first path of a ZDD.]
+
+ Description [Defines an iterator on the paths of a ZDD
+ and finds its first path. Returns a generator that contains the
+ information necessary to continue the enumeration if successful; NULL
+ otherwise.<p>
+ A path is represented as an array of literals, which are integers in
+ {0, 1, 2}; 0 represents an else arc out of a node, 1 represents a then arc
+ out of a node, and 2 stands for the absence of a node.
+ The size of the array equals the number of variables in the manager at
+ the time Cudd_zddFirstCube is called.<p>
+ The paths that end in the empty terminal are not enumerated.]
+
+ SideEffects [The first path is returned as a side effect.]
+
+ SeeAlso [Cudd_zddForeachPath Cudd_zddNextPath Cudd_GenFree
+ Cudd_IsGenEmpty]
+
+******************************************************************************/
+DdGen *
+Cudd_zddFirstPath(
+ DdManager * zdd,
+ DdNode * f,
+ int ** path)
+{
+ DdGen *gen;
+ DdNode *top, *next, *prev;
+ int i;
+ int nvars;
+
+ /* Sanity Check. */
+ if (zdd == NULL || f == NULL) return(NULL);
+
+ /* Allocate generator an initialize it. */
+ gen = ALLOC(DdGen,1);
+ if (gen == NULL) {
+ zdd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ gen->manager = zdd;
+ gen->type = CUDD_GEN_ZDD_PATHS;
+ gen->status = CUDD_GEN_EMPTY;
+ gen->gen.cubes.cube = NULL;
+ gen->gen.cubes.value = DD_ZERO_VAL;
+ gen->stack.sp = 0;
+ gen->stack.stack = NULL;
+ gen->node = NULL;
+
+ nvars = zdd->sizeZ;
+ gen->gen.cubes.cube = ALLOC(int,nvars);
+ if (gen->gen.cubes.cube == NULL) {
+ zdd->errorCode = CUDD_MEMORY_OUT;
+ FREE(gen);
+ return(NULL);
+ }
+ for (i = 0; i < nvars; i++) gen->gen.cubes.cube[i] = 2;
+
+ /* The maximum stack depth is one plus the number of variables.
+ ** because a path may have nodes at all levels, including the
+ ** constant level.
+ */
+ gen->stack.stack = ALLOC(DdNode *, nvars+1);
+ if (gen->stack.stack == NULL) {
+ zdd->errorCode = CUDD_MEMORY_OUT;
+ FREE(gen->gen.cubes.cube);
+ FREE(gen);
+ return(NULL);
+ }
+ for (i = 0; i <= nvars; i++) gen->stack.stack[i] = NULL;
+
+ /* Find the first path of the ZDD. */
+ gen->stack.stack[gen->stack.sp] = f; gen->stack.sp++;
+
+ while (1) {
+ top = gen->stack.stack[gen->stack.sp-1];
+ if (!cuddIsConstant(top)) {
+ /* Take the else branch first. */
+ gen->gen.cubes.cube[top->index] = 0;
+ next = cuddE(top);
+ gen->stack.stack[gen->stack.sp] = next; gen->stack.sp++;
+ } else if (top == DD_ZERO(zdd)) {
+ /* Backtrack. */
+ while (1) {
+ if (gen->stack.sp == 1) {
+ /* The current node has no predecessor. */
+ gen->status = CUDD_GEN_EMPTY;
+ gen->stack.sp--;
+ goto done;
+ }
+ prev = gen->stack.stack[gen->stack.sp-2];
+ next = cuddT(prev);
+ if (next != top) { /* follow the then branch next */
+ gen->gen.cubes.cube[prev->index] = 1;
+ gen->stack.stack[gen->stack.sp-1] = next;
+ break;
+ }
+ /* Pop the stack and try again. */
+ gen->gen.cubes.cube[prev->index] = 2;
+ gen->stack.sp--;
+ top = gen->stack.stack[gen->stack.sp-1];
+ }
+ } else {
+ gen->status = CUDD_GEN_NONEMPTY;
+ gen->gen.cubes.value = cuddV(top);
+ goto done;
+ }
+ }
+
+done:
+ *path = gen->gen.cubes.cube;
+ return(gen);
+
+} /* end of Cudd_zddFirstPath */
+
+
+/**Function********************************************************************
+
+ Synopsis [Generates the next path of a ZDD.]
+
+ Description [Generates the next path of a ZDD onset,
+ using generator gen. Returns 0 if the enumeration is completed; 1
+ otherwise.]
+
+ SideEffects [The path is returned as a side effect. The
+ generator is modified.]
+
+ SeeAlso [Cudd_zddForeachPath Cudd_zddFirstPath Cudd_GenFree
+ Cudd_IsGenEmpty]
+
+******************************************************************************/
+int
+Cudd_zddNextPath(
+ DdGen * gen,
+ int ** path)
+{
+ DdNode *top, *next, *prev;
+ DdManager *zdd = gen->manager;
+
+ /* Backtrack from previously reached terminal node. */
+ while (1) {
+ if (gen->stack.sp == 1) {
+ /* The current node has no predecessor. */
+ gen->status = CUDD_GEN_EMPTY;
+ gen->stack.sp--;
+ goto done;
+ }
+ top = gen->stack.stack[gen->stack.sp-1];
+ prev = gen->stack.stack[gen->stack.sp-2];
+ next = cuddT(prev);
+ if (next != top) { /* follow the then branch next */
+ gen->gen.cubes.cube[prev->index] = 1;
+ gen->stack.stack[gen->stack.sp-1] = next;
+ break;
+ }
+ /* Pop the stack and try again. */
+ gen->gen.cubes.cube[prev->index] = 2;
+ gen->stack.sp--;
+ }
+
+ while (1) {
+ top = gen->stack.stack[gen->stack.sp-1];
+ if (!cuddIsConstant(top)) {
+ /* Take the else branch first. */
+ gen->gen.cubes.cube[top->index] = 0;
+ next = cuddE(top);
+ gen->stack.stack[gen->stack.sp] = next; gen->stack.sp++;
+ } else if (top == DD_ZERO(zdd)) {
+ /* Backtrack. */
+ while (1) {
+ if (gen->stack.sp == 1) {
+ /* The current node has no predecessor. */
+ gen->status = CUDD_GEN_EMPTY;
+ gen->stack.sp--;
+ goto done;
+ }
+ prev = gen->stack.stack[gen->stack.sp-2];
+ next = cuddT(prev);
+ if (next != top) { /* follow the then branch next */
+ gen->gen.cubes.cube[prev->index] = 1;
+ gen->stack.stack[gen->stack.sp-1] = next;
+ break;
+ }
+ /* Pop the stack and try again. */
+ gen->gen.cubes.cube[prev->index] = 2;
+ gen->stack.sp--;
+ top = gen->stack.stack[gen->stack.sp-1];
+ }
+ } else {
+ gen->status = CUDD_GEN_NONEMPTY;
+ gen->gen.cubes.value = cuddV(top);
+ goto done;
+ }
+ }
+
+done:
+ if (gen->status == CUDD_GEN_EMPTY) return(0);
+ *path = gen->gen.cubes.cube;
+ return(1);
+
+} /* end of Cudd_zddNextPath */
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts a path of a ZDD representing a cover to a string.]
+
+ Description [Converts a path of a ZDD representing a cover to a
+ string. The string represents an implicant of the cover. The path
+ is typically produced by Cudd_zddForeachPath. Returns a pointer to
+ the string if successful; NULL otherwise. If the str input is NULL,
+ it allocates a new string. The string passed to this function must
+ have enough room for all variables and for the terminator.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddForeachPath]
+
+******************************************************************************/
+char *
+Cudd_zddCoverPathToString(
+ DdManager *zdd /* DD manager */,
+ int *path /* path of ZDD representing a cover */,
+ char *str /* pointer to string to use if != NULL */
+ )
+{
+ int nvars = zdd->sizeZ;
+ int i;
+ char *res;
+
+ if (nvars & 1) return(NULL);
+ nvars >>= 1;
+ if (str == NULL) {
+ res = ALLOC(char, nvars+1);
+ if (res == NULL) return(NULL);
+ } else {
+ res = str;
+ }
+ for (i = 0; i < nvars; i++) {
+ int v = (path[2*i] << 2) | path[2*i+1];
+ switch (v) {
+ case 0:
+ case 2:
+ case 8:
+ case 10:
+ res[i] = '-';
+ break;
+ case 1:
+ case 9:
+ res[i] = '0';
+ break;
+ case 4:
+ case 6:
+ res[i] = '1';
+ break;
+ default:
+ res[i] = '?';
+ }
+ }
+ res[nvars] = 0;
+
+ return(res);
+
+} /* end of Cudd_zddCoverPathToString */
+
+
+/**Function********************************************************************
+
+ Synopsis [Writes a dot file representing the argument ZDDs.]
+
+ Description [Writes a file representing the argument ZDDs in a format
+ suitable for the graph drawing program dot.
+ It returns 1 in case of success; 0 otherwise (e.g., out-of-memory,
+ file system full).
+ Cudd_zddDumpDot does not close the file: This is the caller
+ responsibility. Cudd_zddDumpDot uses a minimal unique subset of the
+ hexadecimal address of a node as name for it.
+ If the argument inames is non-null, it is assumed to hold the pointers
+ to the names of the inputs. Similarly for onames.
+ Cudd_zddDumpDot uses the following convention to draw arcs:
+ <ul>
+ <li> solid line: THEN arcs;
+ <li> dashed line: ELSE arcs.
+ </ul>
+ The dot options are chosen so that the drawing fits on a letter-size
+ sheet.
+ ]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DumpDot Cudd_zddPrintDebug]
+
+******************************************************************************/
+int
+Cudd_zddDumpDot(
+ DdManager * dd /* manager */,
+ int n /* number of output nodes to be dumped */,
+ DdNode ** f /* array of output nodes to be dumped */,
+ char ** inames /* array of input names (or NULL) */,
+ char ** onames /* array of output names (or NULL) */,
+ FILE * fp /* pointer to the dump file */)
+{
+ DdNode *support = NULL;
+ DdNode *scan;
+ int *sorted = NULL;
+ int nvars = dd->sizeZ;
+ st_table *visited = NULL;
+ st_generator *gen;
+ int retval;
+ int i, j;
+ int slots;
+ DdNodePtr *nodelist;
+ long refAddr, diff, mask;
+
+ /* Build a bit array with the support of f. */
+ sorted = ALLOC(int,nvars);
+ if (sorted == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ goto failure;
+ }
+ for (i = 0; i < nvars; i++) sorted[i] = 0;
+
+ /* Take the union of the supports of each output function. */
+ for (i = 0; i < n; i++) {
+ support = Cudd_Support(dd,f[i]);
+ if (support == NULL) goto failure;
+ cuddRef(support);
+ scan = support;
+ while (!cuddIsConstant(scan)) {
+ sorted[scan->index] = 1;
+ scan = cuddT(scan);
+ }
+ Cudd_RecursiveDeref(dd,support);
+ }
+ support = NULL; /* so that we do not try to free it in case of failure */
+
+ /* Initialize symbol table for visited nodes. */
+ visited = st_init_table(st_ptrcmp, st_ptrhash);
+ if (visited == NULL) goto failure;
+
+ /* Collect all the nodes of this DD in the symbol table. */
+ for (i = 0; i < n; i++) {
+ retval = cuddCollectNodes(f[i],visited);
+ if (retval == 0) goto failure;
+ }
+
+ /* Find how many most significant hex digits are identical
+ ** in the addresses of all the nodes. Build a mask based
+ ** on this knowledge, so that digits that carry no information
+ ** will not be printed. This is done in two steps.
+ ** 1. We scan the symbol table to find the bits that differ
+ ** in at least 2 addresses.
+ ** 2. We choose one of the possible masks. There are 8 possible
+ ** masks for 32-bit integer, and 16 possible masks for 64-bit
+ ** integers.
+ */
+
+ /* Find the bits that are different. */
+ refAddr = (long) f[0];
+ diff = 0;
+ gen = st_init_gen(visited);
+ while (st_gen(gen, (char **) &scan, NULL)) {
+ diff |= refAddr ^ (long) scan;
+ }
+ st_free_gen(gen);
+
+ /* Choose the mask. */
+ for (i = 0; (unsigned) i < 8 * sizeof(long); i += 4) {
+ mask = (1 << i) - 1;
+ if (diff <= mask) break;
+ }
+
+ /* Write the header and the global attributes. */
+ retval = fprintf(fp,"digraph \"ZDD\" {\n");
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,
+ "size = \"7.5,10\"\ncenter = true;\nedge [dir = none];\n");
+ if (retval == EOF) return(0);
+
+ /* Write the input name subgraph by scanning the support array. */
+ retval = fprintf(fp,"{ node [shape = plaintext];\n");
+ if (retval == EOF) goto failure;
+ retval = fprintf(fp," edge [style = invis];\n");
+ if (retval == EOF) goto failure;
+ /* We use a name ("CONST NODES") with an embedded blank, because
+ ** it is unlikely to appear as an input name.
+ */
+ retval = fprintf(fp," \"CONST NODES\" [style = invis];\n");
+ if (retval == EOF) goto failure;
+ for (i = 0; i < nvars; i++) {
+ if (sorted[dd->invpermZ[i]]) {
+ if (inames == NULL) {
+ retval = fprintf(fp,"\" %d \" -> ", dd->invpermZ[i]);
+ } else {
+ retval = fprintf(fp,"\" %s \" -> ", inames[dd->invpermZ[i]]);
+ }
+ if (retval == EOF) goto failure;
+ }
+ }
+ retval = fprintf(fp,"\"CONST NODES\"; \n}\n");
+ if (retval == EOF) goto failure;
+
+ /* Write the output node subgraph. */
+ retval = fprintf(fp,"{ rank = same; node [shape = box]; edge [style = invis];\n");
+ if (retval == EOF) goto failure;
+ for (i = 0; i < n; i++) {
+ if (onames == NULL) {
+ retval = fprintf(fp,"\"F%d\"", i);
+ } else {
+ retval = fprintf(fp,"\" %s \"", onames[i]);
+ }
+ if (retval == EOF) goto failure;
+ if (i == n - 1) {
+ retval = fprintf(fp,"; }\n");
+ } else {
+ retval = fprintf(fp," -> ");
+ }
+ if (retval == EOF) goto failure;
+ }
+
+ /* Write rank info: All nodes with the same index have the same rank. */
+ for (i = 0; i < nvars; i++) {
+ if (sorted[dd->invpermZ[i]]) {
+ retval = fprintf(fp,"{ rank = same; ");
+ if (retval == EOF) goto failure;
+ if (inames == NULL) {
+ retval = fprintf(fp,"\" %d \";\n", dd->invpermZ[i]);
+ } else {
+ retval = fprintf(fp,"\" %s \";\n", inames[dd->invpermZ[i]]);
+ }
+ if (retval == EOF) goto failure;
+ nodelist = dd->subtableZ[i].nodelist;
+ slots = dd->subtableZ[i].slots;
+ for (j = 0; j < slots; j++) {
+ scan = nodelist[j];
+ while (scan != NULL) {
+ if (st_is_member(visited,(char *) scan)) {
+ retval = fprintf(fp,"\"%lx\";\n", (mask & (long) scan) / sizeof(DdNode));
+ if (retval == EOF) goto failure;
+ }
+ scan = scan->next;
+ }
+ }
+ retval = fprintf(fp,"}\n");
+ if (retval == EOF) goto failure;
+ }
+ }
+
+ /* All constants have the same rank. */
+ retval = fprintf(fp,
+ "{ rank = same; \"CONST NODES\";\n{ node [shape = box]; ");
+ if (retval == EOF) goto failure;
+ nodelist = dd->constants.nodelist;
+ slots = dd->constants.slots;
+ for (j = 0; j < slots; j++) {
+ scan = nodelist[j];
+ while (scan != NULL) {
+ if (st_is_member(visited,(char *) scan)) {
+ retval = fprintf(fp,"\"%lx\";\n", (mask & (long) scan) / sizeof(DdNode));
+ if (retval == EOF) goto failure;
+ }
+ scan = scan->next;
+ }
+ }
+ retval = fprintf(fp,"}\n}\n");
+ if (retval == EOF) goto failure;
+
+ /* Write edge info. */
+ /* Edges from the output nodes. */
+ for (i = 0; i < n; i++) {
+ if (onames == NULL) {
+ retval = fprintf(fp,"\"F%d\"", i);
+ } else {
+ retval = fprintf(fp,"\" %s \"", onames[i]);
+ }
+ if (retval == EOF) goto failure;
+ retval = fprintf(fp," -> \"%lx\" [style = solid];\n",
+ (mask & (long) f[i]) / sizeof(DdNode));
+ if (retval == EOF) goto failure;
+ }
+
+ /* Edges from internal nodes. */
+ for (i = 0; i < nvars; i++) {
+ if (sorted[dd->invpermZ[i]]) {
+ nodelist = dd->subtableZ[i].nodelist;
+ slots = dd->subtableZ[i].slots;
+ for (j = 0; j < slots; j++) {
+ scan = nodelist[j];
+ while (scan != NULL) {
+ if (st_is_member(visited,(char *) scan)) {
+ retval = fprintf(fp,
+ "\"%lx\" -> \"%lx\";\n",
+ (mask & (long) scan) / sizeof(DdNode),
+ (mask & (long) cuddT(scan)) / sizeof(DdNode));
+ if (retval == EOF) goto failure;
+ retval = fprintf(fp,
+ "\"%lx\" -> \"%lx\" [style = dashed];\n",
+ (mask & (long) scan) / sizeof(DdNode),
+ (mask & (long) cuddE(scan)) / sizeof(DdNode));
+ if (retval == EOF) goto failure;
+ }
+ scan = scan->next;
+ }
+ }
+ }
+ }
+
+ /* Write constant labels. */
+ nodelist = dd->constants.nodelist;
+ slots = dd->constants.slots;
+ for (j = 0; j < slots; j++) {
+ scan = nodelist[j];
+ while (scan != NULL) {
+ if (st_is_member(visited,(char *) scan)) {
+ retval = fprintf(fp,"\"%lx\" [label = \"%g\"];\n",
+ (mask & (long) scan) / sizeof(DdNode), cuddV(scan));
+ if (retval == EOF) goto failure;
+ }
+ scan = scan->next;
+ }
+ }
+
+ /* Write trailer and return. */
+ retval = fprintf(fp,"}\n");
+ if (retval == EOF) goto failure;
+
+ st_free_table(visited);
+ FREE(sorted);
+ return(1);
+
+failure:
+ if (sorted != NULL) FREE(sorted);
+ if (support != NULL) Cudd_RecursiveDeref(dd,support);
+ if (visited != NULL) st_free_table(visited);
+ return(0);
+
+} /* end of Cudd_zddDumpBlif */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints a ZDD to the standard output. One line per node is
+ printed.]
+
+ Description [Prints a ZDD to the standard output. One line per node is
+ printed. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddPrintDebug]
+
+******************************************************************************/
+int
+cuddZddP(
+ DdManager * zdd,
+ DdNode * f)
+{
+ int retval;
+ st_table *table = st_init_table(st_ptrcmp, st_ptrhash);
+
+ if (table == NULL) return(0);
+
+ retval = zp2(zdd, f, table);
+ st_free_table(table);
+ (void) fputc('\n', zdd->out);
+ return(retval);
+
+} /* end of cuddZddP */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of cuddZddP.]
+
+ Description [Performs the recursive step of cuddZddP. Returns 1 in
+ case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+zp2(
+ DdManager * zdd,
+ DdNode * f,
+ st_table * t)
+{
+ DdNode *n;
+ int T, E;
+ DdNode *base = DD_ONE(zdd);
+
+ if (f == NULL)
+ return(0);
+
+ if (Cudd_IsConstant(f)) {
+ (void)fprintf(zdd->out, "ID = %d\n", (f == base));
+ return(1);
+ }
+ if (st_is_member(t, (char *)f) == 1)
+ return(1);
+
+ if (st_insert(t, (char *) f, NULL) == ST_OUT_OF_MEM)
+ return(0);
+
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(zdd->out, "ID = 0x%lx\tindex = %d\tr = %d\t",
+ (unsigned long)f / (unsigned long) sizeof(DdNode), f->index, f->ref);
+#else
+ (void) fprintf(zdd->out, "ID = 0x%x\tindex = %d\tr = %d\t",
+ (unsigned)f / (unsigned) sizeof(DdNode), f->index, f->ref);
+#endif
+
+ n = cuddT(f);
+ if (Cudd_IsConstant(n)) {
+ (void) fprintf(zdd->out, "T = %d\t\t", (n == base));
+ T = 1;
+ } else {
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(zdd->out, "T = 0x%lx\t", (unsigned long) n /
+ (unsigned long) sizeof(DdNode));
+#else
+ (void) fprintf(zdd->out, "T = 0x%x\t", (unsigned) n / (unsigned) sizeof(DdNode));
+#endif
+ T = 0;
+ }
+
+ n = cuddE(f);
+ if (Cudd_IsConstant(n)) {
+ (void) fprintf(zdd->out, "E = %d\n", (n == base));
+ E = 1;
+ } else {
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(zdd->out, "E = 0x%lx\n", (unsigned long) n /
+ (unsigned long) sizeof(DdNode));
+#else
+ (void) fprintf(zdd->out, "E = 0x%x\n", (unsigned) n / (unsigned) sizeof(DdNode));
+#endif
+ E = 0;
+ }
+
+ if (E == 0)
+ if (zp2(zdd, cuddE(f), t) == 0) return(0);
+ if (T == 0)
+ if (zp2(zdd, cuddT(f), t) == 0) return(0);
+ return(1);
+
+} /* end of zp2 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddPrintMinterm.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+zdd_print_minterm_aux(
+ DdManager * zdd /* manager */,
+ DdNode * node /* current node */,
+ int level /* depth in the recursion */,
+ int * list /* current recursion path */)
+{
+ DdNode *Nv, *Nnv;
+ int i, v;
+ DdNode *base = DD_ONE(zdd);
+
+ if (Cudd_IsConstant(node)) {
+ if (node == base) {
+ /* Check for missing variable. */
+ if (level != zdd->sizeZ) {
+ list[zdd->invpermZ[level]] = 0;
+ zdd_print_minterm_aux(zdd, node, level + 1, list);
+ return;
+ }
+ /* Terminal case: Print one cube based on the current recursion
+ ** path.
+ */
+ for (i = 0; i < zdd->sizeZ; i++) {
+ v = list[i];
+ if (v == 0)
+ (void) fprintf(zdd->out,"0");
+ else if (v == 1)
+ (void) fprintf(zdd->out,"1");
+ else if (v == 3)
+ (void) fprintf(zdd->out,"@"); /* should never happen */
+ else
+ (void) fprintf(zdd->out,"-");
+ }
+ (void) fprintf(zdd->out," 1\n");
+ }
+ } else {
+ /* Check for missing variable. */
+ if (level != cuddIZ(zdd,node->index)) {
+ list[zdd->invpermZ[level]] = 0;
+ zdd_print_minterm_aux(zdd, node, level + 1, list);
+ return;
+ }
+
+ Nnv = cuddE(node);
+ Nv = cuddT(node);
+ if (Nv == Nnv) {
+ list[node->index] = 2;
+ zdd_print_minterm_aux(zdd, Nnv, level + 1, list);
+ return;
+ }
+
+ list[node->index] = 1;
+ zdd_print_minterm_aux(zdd, Nv, level + 1, list);
+ list[node->index] = 0;
+ zdd_print_minterm_aux(zdd, Nnv, level + 1, list);
+ }
+ return;
+
+} /* end of zdd_print_minterm_aux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddPrintCover.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+zddPrintCoverAux(
+ DdManager * zdd /* manager */,
+ DdNode * node /* current node */,
+ int level /* depth in the recursion */,
+ int * list /* current recursion path */)
+{
+ DdNode *Nv, *Nnv;
+ int i, v;
+ DdNode *base = DD_ONE(zdd);
+
+ if (Cudd_IsConstant(node)) {
+ if (node == base) {
+ /* Check for missing variable. */
+ if (level != zdd->sizeZ) {
+ list[zdd->invpermZ[level]] = 0;
+ zddPrintCoverAux(zdd, node, level + 1, list);
+ return;
+ }
+ /* Terminal case: Print one cube based on the current recursion
+ ** path.
+ */
+ for (i = 0; i < zdd->sizeZ; i += 2) {
+ v = list[i] * 4 + list[i+1];
+ if (v == 0)
+ (void) putc('-',zdd->out);
+ else if (v == 4)
+ (void) putc('1',zdd->out);
+ else if (v == 1)
+ (void) putc('0',zdd->out);
+ else
+ (void) putc('@',zdd->out); /* should never happen */
+ }
+ (void) fprintf(zdd->out," 1\n");
+ }
+ } else {
+ /* Check for missing variable. */
+ if (level != cuddIZ(zdd,node->index)) {
+ list[zdd->invpermZ[level]] = 0;
+ zddPrintCoverAux(zdd, node, level + 1, list);
+ return;
+ }
+
+ Nnv = cuddE(node);
+ Nv = cuddT(node);
+ if (Nv == Nnv) {
+ list[node->index] = 2;
+ zddPrintCoverAux(zdd, Nnv, level + 1, list);
+ return;
+ }
+
+ list[node->index] = 1;
+ zddPrintCoverAux(zdd, Nv, level + 1, list);
+ list[node->index] = 0;
+ zddPrintCoverAux(zdd, Nnv, level + 1, list);
+ }
+ return;
+
+} /* end of zddPrintCoverAux */
diff --git a/src/bdd/cudd/module.make b/src/bdd/cudd/module.make
new file mode 100644
index 00000000..c526a50e
--- /dev/null
+++ b/src/bdd/cudd/module.make
@@ -0,0 +1,61 @@
+SRC += src/bdd/cudd/cuddAPI.c \
+ src/bdd/cudd/cuddAddAbs.c \
+ src/bdd/cudd/cuddAddApply.c \
+ src/bdd/cudd/cuddAddFind.c \
+ src/bdd/cudd/cuddAddInv.c \
+ src/bdd/cudd/cuddAddIte.c \
+ src/bdd/cudd/cuddAddNeg.c \
+ src/bdd/cudd/cuddAddWalsh.c \
+ src/bdd/cudd/cuddAndAbs.c \
+ src/bdd/cudd/cuddAnneal.c \
+ src/bdd/cudd/cuddApa.c \
+ src/bdd/cudd/cuddApprox.c \
+ src/bdd/cudd/cuddBddAbs.c \
+ src/bdd/cudd/cuddBddCorr.c \
+ src/bdd/cudd/cuddBddIte.c \
+ src/bdd/cudd/cuddBridge.c \
+ src/bdd/cudd/cuddCache.c \
+ src/bdd/cudd/cuddCheck.c \
+ src/bdd/cudd/cuddClip.c \
+ src/bdd/cudd/cuddCof.c \
+ src/bdd/cudd/cuddCompose.c \
+ src/bdd/cudd/cuddDecomp.c \
+ src/bdd/cudd/cuddEssent.c \
+ src/bdd/cudd/cuddExact.c \
+ src/bdd/cudd/cuddExport.c \
+ src/bdd/cudd/cuddGenCof.c \
+ src/bdd/cudd/cuddGenetic.c \
+ src/bdd/cudd/cuddGroup.c \
+ src/bdd/cudd/cuddHarwell.c \
+ src/bdd/cudd/cuddInit.c \
+ src/bdd/cudd/cuddInteract.c \
+ src/bdd/cudd/cuddLCache.c \
+ src/bdd/cudd/cuddLevelQ.c \
+ src/bdd/cudd/cuddLinear.c \
+ src/bdd/cudd/cuddLiteral.c \
+ src/bdd/cudd/cuddMatMult.c \
+ src/bdd/cudd/cuddPriority.c \
+ src/bdd/cudd/cuddRead.c \
+ src/bdd/cudd/cuddRef.c \
+ src/bdd/cudd/cuddReorder.c \
+ src/bdd/cudd/cuddSat.c \
+ src/bdd/cudd/cuddSign.c \
+ src/bdd/cudd/cuddSolve.c \
+ src/bdd/cudd/cuddSplit.c \
+ src/bdd/cudd/cuddSubsetHB.c \
+ src/bdd/cudd/cuddSubsetSP.c \
+ src/bdd/cudd/cuddSymmetry.c \
+ src/bdd/cudd/cuddTable.c \
+ src/bdd/cudd/cuddUtil.c \
+ src/bdd/cudd/cuddWindow.c \
+ src/bdd/cudd/cuddZddCount.c \
+ src/bdd/cudd/cuddZddFuncs.c \
+ src/bdd/cudd/cuddZddGroup.c \
+ src/bdd/cudd/cuddZddIsop.c \
+ src/bdd/cudd/cuddZddLin.c \
+ src/bdd/cudd/cuddZddMisc.c \
+ src/bdd/cudd/cuddZddPort.c \
+ src/bdd/cudd/cuddZddReord.c \
+ src/bdd/cudd/cuddZddSetop.c \
+ src/bdd/cudd/cuddZddSymm.c \
+ src/bdd/cudd/cuddZddUtil.c
diff --git a/src/bdd/cudd/r7x8.1.mat b/src/bdd/cudd/r7x8.1.mat
new file mode 100644
index 00000000..b0dd0a0a
--- /dev/null
+++ b/src/bdd/cudd/r7x8.1.mat
@@ -0,0 +1,53 @@
+7 9
+0 0 1
+0 1 1
+0 2 1
+0 3 4
+0 4 3
+0 5 3
+0 6 3
+0 8 3
+1 0 4
+1 1 3
+1 2 2
+1 3 4
+1 4 1
+1 5 2
+1 6 4
+1 8 3
+2 0 1
+2 1 1
+2 2 4
+2 4 2
+2 5 3
+2 6 3
+2 8 3
+3 0 2
+3 1 1
+3 3 4
+3 4 4
+3 5 1
+3 8 1
+4 0 2
+4 1 3
+4 2 2
+4 3 4
+4 4 1
+4 5 1
+4 6 2
+4 8 2
+5 0 3
+5 1 3
+5 2 4
+5 3 4
+5 4 1
+5 5 3
+5 6 3
+5 8 4
+6 1 1
+6 2 1
+6 3 4
+6 4 2
+6 5 4
+6 6 4
+6 8 2
diff --git a/src/bdd/cudd/testcudd.c b/src/bdd/cudd/testcudd.c
new file mode 100644
index 00000000..451bb190
--- /dev/null
+++ b/src/bdd/cudd/testcudd.c
@@ -0,0 +1,988 @@
+/**CFile***********************************************************************
+
+ FileName [testcudd.c]
+
+ PackageName [cudd]
+
+ Synopsis [Sanity check tests for some CUDD functions.]
+
+ Description [testcudd reads a matrix with real coefficients and
+ transforms it into an ADD. It then performs various operations on
+ the ADD and on the BDD corresponding to the ADD pattern. Finally,
+ testcudd tests functions relate to Walsh matrices and matrix
+ multiplication.]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define TESTCUDD_VERSION "TestCudd Version #1.0, Release date 3/17/01"
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: testcudd.c,v 1.1.1.1 2003/02/24 22:23:54 wjiang Exp $";
+#endif
+
+static char *onames[] = { "C", "M" }; /* names of functions to be dumped */
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static void usage ARGS((char * prog));
+static FILE *open_file ARGS((char *filename, char *mode));
+static int testIterators ARGS((DdManager *dd, DdNode *M, DdNode *C, int pr));
+static int testXor ARGS((DdManager *dd, DdNode *f, int pr, int nvars));
+static int testHamming ARGS((DdManager *dd, DdNode *f, int pr, int nvars));
+static int testWalsh ARGS((DdManager *dd, int N, int cmu, int approach, int pr));
+
+/**AutomaticEnd***************************************************************/
+
+
+/**Function********************************************************************
+
+ Synopsis [Main function for testcudd.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+main(int argc, char **argv)
+{
+ FILE *fp; /* pointer to input file */
+ char *file = ""; /* input file name */
+ FILE *dfp = NULL; /* pointer to dump file */
+ char *dfile; /* file for DD dump */
+ DdNode *dfunc[2]; /* addresses of the functions to be dumped */
+ DdManager *dd; /* pointer to DD manager */
+ DdNode *one, *zero; /* fast access to constant functions */
+ DdNode *M;
+ DdNode **x; /* pointers to variables */
+ DdNode **y; /* pointers to variables */
+ DdNode **xn; /* complements of row variables */
+ DdNode **yn_; /* complements of column variables */
+ DdNode **xvars;
+ DdNode **yvars;
+ DdNode *C; /* result of converting from ADD to BDD */
+ DdNode *ess; /* cube of essential variables */
+ DdNode *shortP; /* BDD cube of shortest path */
+ DdNode *largest; /* BDD of largest cube */
+ DdNode *shortA; /* ADD cube of shortest path */
+ DdNode *constN; /* value returned by evaluation of ADD */
+ DdNode *ycube; /* cube of the negated y vars for c-proj */
+ DdNode *CP; /* C-Projection of C */
+ DdNode *CPr; /* C-Selection of C */
+ int length; /* length of the shortest path */
+ int nx; /* number of variables */
+ int ny;
+ int maxnx;
+ int maxny;
+ int m;
+ int n;
+ int N;
+ int cmu; /* use CMU multiplication */
+ int pr; /* verbose printout level */
+ int harwell;
+ int multiple; /* read multiple matrices */
+ int ok;
+ int c; /* variable to read in options */
+ int approach; /* reordering approach */
+ int autodyn; /* automatic reordering */
+ int groupcheck; /* option for group sifting */
+ int profile; /* print heap profile if != 0 */
+ int keepperm; /* keep track of permutation */
+ int clearcache; /* clear the cache after each matrix */
+ int blifOrDot; /* dump format: 0 -> dot, 1 -> blif, ... */
+ int retval; /* return value */
+ int i; /* loop index */
+ long startTime; /* initial time */
+ long lapTime;
+ int size;
+ unsigned int cacheSize, maxMemory;
+ unsigned int nvars,nslots;
+
+ startTime = util_cpu_time();
+
+ approach = CUDD_REORDER_NONE;
+ autodyn = 0;
+ pr = 0;
+ harwell = 0;
+ multiple = 0;
+ profile = 0;
+ keepperm = 0;
+ cmu = 0;
+ N = 4;
+ nvars = 4;
+ cacheSize = 127;
+ maxMemory = 0;
+ nslots = CUDD_UNIQUE_SLOTS;
+ clearcache = 0;
+ groupcheck = CUDD_GROUP_CHECK7;
+ dfile = NULL;
+ blifOrDot = 0; /* dot format */
+
+ /* Parse command line. */
+ while ((c = util_getopt(argc, argv, "CDHMPS:a:bcd:g:hkmn:p:v:x:X:"))
+ != EOF) {
+ switch(c) {
+ case 'C':
+ cmu = 1;
+ break;
+ case 'D':
+ autodyn = 1;
+ break;
+ case 'H':
+ harwell = 1;
+ break;
+ case 'M':
+#ifdef MNEMOSYNE
+ (void) mnem_setrecording(0);
+#endif
+ break;
+ case 'P':
+ profile = 1;
+ break;
+ case 'S':
+ nslots = atoi(util_optarg);
+ break;
+ case 'X':
+ maxMemory = atoi(util_optarg);
+ break;
+ case 'a':
+ approach = atoi(util_optarg);
+ break;
+ case 'b':
+ blifOrDot = 1; /* blif format */
+ break;
+ case 'c':
+ clearcache = 1;
+ break;
+ case 'd':
+ dfile = util_optarg;
+ break;
+ case 'g':
+ groupcheck = atoi(util_optarg);
+ break;
+ case 'k':
+ keepperm = 1;
+ break;
+ case 'm':
+ multiple = 1;
+ break;
+ case 'n':
+ N = atoi(util_optarg);
+ break;
+ case 'p':
+ pr = atoi(util_optarg);
+ break;
+ case 'v':
+ nvars = atoi(util_optarg);
+ break;
+ case 'x':
+ cacheSize = atoi(util_optarg);
+ break;
+ case 'h':
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+
+ if (argc - util_optind == 0) {
+ file = "-";
+ } else if (argc - util_optind == 1) {
+ file = argv[util_optind];
+ } else {
+ usage(argv[0]);
+ }
+ if ((approach<0) || (approach>17)) {
+ (void) fprintf(stderr,"Invalid approach: %d \n",approach);
+ usage(argv[0]);
+ }
+
+ if (pr >= 0) {
+ (void) printf("# %s\n", TESTCUDD_VERSION);
+ /* Echo command line and arguments. */
+ (void) printf("#");
+ for (i = 0; i < argc; i++) {
+ (void) printf(" %s", argv[i]);
+ }
+ (void) printf("\n");
+ (void) fflush(stdout);
+ }
+
+ /* Initialize manager and provide easy reference to terminals. */
+ dd = Cudd_Init(nvars,0,nslots,cacheSize,maxMemory);
+ one = DD_ONE(dd);
+ zero = DD_ZERO(dd);
+ dd->groupcheck = (Cudd_AggregationType) groupcheck;
+ if (autodyn) Cudd_AutodynEnable(dd,CUDD_REORDER_SAME);
+
+ /* Open input file. */
+ fp = open_file(file, "r");
+
+ /* Open dump file if requested */
+ if (dfile != NULL) {
+ dfp = open_file(dfile, "w");
+ }
+
+ x = y = xn = yn_ = NULL;
+ do {
+ /* We want to start anew for every matrix. */
+ maxnx = maxny = 0;
+ nx = maxnx; ny = maxny;
+ if (pr>0) lapTime = util_cpu_time();
+ if (harwell) {
+ if (pr >= 0) (void) printf(":name: ");
+ ok = Cudd_addHarwell(fp, dd, &M, &x, &y, &xn, &yn_, &nx, &ny,
+ &m, &n, 0, 2, 1, 2, pr);
+ } else {
+ ok = Cudd_addRead(fp, dd, &M, &x, &y, &xn, &yn_, &nx, &ny,
+ &m, &n, 0, 2, 1, 2);
+ if (pr >= 0)
+ (void) printf(":name: %s: %d rows %d columns\n", file, m, n);
+ }
+ if (!ok) {
+ (void) fprintf(stderr, "Error reading matrix\n");
+ exit(1);
+ }
+
+ if (nx > maxnx) maxnx = nx;
+ if (ny > maxny) maxny = ny;
+
+ /* Build cube of negated y's. */
+ ycube = DD_ONE(dd);
+ Cudd_Ref(ycube);
+ for (i = maxny - 1; i >= 0; i--) {
+ DdNode *tmpp;
+ tmpp = Cudd_bddAnd(dd,Cudd_Not(dd->vars[y[i]->index]),ycube);
+ if (tmpp == NULL) exit(2);
+ Cudd_Ref(tmpp);
+ Cudd_RecursiveDeref(dd,ycube);
+ ycube = tmpp;
+ }
+ /* Initialize vectors of BDD variables used by priority func. */
+ xvars = ALLOC(DdNode *, nx);
+ if (xvars == NULL) exit(2);
+ for (i = 0; i < nx; i++) {
+ xvars[i] = dd->vars[x[i]->index];
+ }
+ yvars = ALLOC(DdNode *, ny);
+ if (yvars == NULL) exit(2);
+ for (i = 0; i < ny; i++) {
+ yvars[i] = dd->vars[y[i]->index];
+ }
+
+ /* Clean up */
+ for (i=0; i < maxnx; i++) {
+ Cudd_RecursiveDeref(dd, x[i]);
+ Cudd_RecursiveDeref(dd, xn[i]);
+ }
+ FREE(x);
+ FREE(xn);
+ for (i=0; i < maxny; i++) {
+ Cudd_RecursiveDeref(dd, y[i]);
+ Cudd_RecursiveDeref(dd, yn_[i]);
+ }
+ FREE(y);
+ FREE(yn_);
+
+ if (pr>0) {(void) printf(":1: M"); Cudd_PrintDebug(dd,M,nx+ny,pr);}
+
+ if (pr>0) (void) printf(":2: time to read the matrix = %s\n",
+ util_print_time(util_cpu_time() - lapTime));
+
+ C = Cudd_addBddPattern(dd, M);
+ if (C == 0) exit(2);
+ Cudd_Ref(C);
+ if (pr>0) {(void) printf(":3: C"); Cudd_PrintDebug(dd,C,nx+ny,pr);}
+
+ /* Test iterators. */
+ retval = testIterators(dd,M,C,pr);
+ if (retval == 0) exit(2);
+
+ cuddCacheProfile(dd,stdout);
+
+ /* Test XOR */
+ retval = testXor(dd,C,pr,nx+ny);
+ if (retval == 0) exit(2);
+
+ /* Test Hamming distance functions. */
+ retval = testHamming(dd,C,pr,nx+ny);
+ if (retval == 0) exit(2);
+
+ /* Test selection functions. */
+ CP = Cudd_CProjection(dd,C,ycube);
+ if (CP == NULL) exit(2);
+ Cudd_Ref(CP);
+ if (pr>0) {(void) printf("ycube"); Cudd_PrintDebug(dd,ycube,nx+ny,pr);}
+ if (pr>0) {(void) printf("CP"); Cudd_PrintDebug(dd,CP,nx+ny,pr);}
+
+ if (nx == ny) {
+ CPr = Cudd_PrioritySelect(dd,C,xvars,yvars,(DdNode **)NULL,
+ (DdNode *)NULL,ny,Cudd_Xgty);
+ if (CPr == NULL) exit(2);
+ Cudd_Ref(CPr);
+ if (pr>0) {(void) printf(":4: CPr"); Cudd_PrintDebug(dd,CPr,nx+ny,pr);}
+ if (CP != CPr) {
+ (void) printf("CP != CPr!\n");
+ }
+ Cudd_RecursiveDeref(dd, CPr);
+ }
+ FREE(xvars); FREE(yvars);
+
+ Cudd_RecursiveDeref(dd, CP);
+ Cudd_RecursiveDeref(dd, ycube);
+
+ /* Test functions for essential variables. */
+ ess = Cudd_FindEssential(dd,C);
+ if (ess == NULL) exit(2);
+ Cudd_Ref(ess);
+ if (pr>0) {(void) printf(":4: ess"); Cudd_PrintDebug(dd,ess,nx+ny,pr);}
+ Cudd_RecursiveDeref(dd, ess);
+
+ /* Test functions for shortest paths. */
+ shortP = Cudd_ShortestPath(dd, M, NULL, NULL, &length);
+ if (shortP == NULL) exit(2);
+ Cudd_Ref(shortP);
+ if (pr>0) {
+ (void) printf(":5: shortP"); Cudd_PrintDebug(dd,shortP,nx+ny,pr);
+ }
+ /* Test functions for largest cubes. */
+ largest = Cudd_LargestCube(dd, Cudd_Not(C), &length);
+ if (largest == NULL) exit(2);
+ Cudd_Ref(largest);
+ if (pr>0) {
+ (void) printf(":5b: largest");
+ Cudd_PrintDebug(dd,largest,nx+ny,pr);
+ }
+ Cudd_RecursiveDeref(dd, largest);
+
+ /* Test Cudd_addEvalConst and Cudd_addIteConstant. */
+ shortA = Cudd_BddToAdd(dd,shortP);
+ if (shortA == NULL) exit(2);
+ Cudd_Ref(shortA);
+ Cudd_RecursiveDeref(dd, shortP);
+ constN = Cudd_addEvalConst(dd,shortA,M);
+ if (constN == DD_NON_CONSTANT) exit(2);
+ if (Cudd_addIteConstant(dd,shortA,M,constN) != constN) exit(2);
+ if (pr>0) {(void) printf("The value of M along the chosen shortest path is %g\n", cuddV(constN));}
+ Cudd_RecursiveDeref(dd, shortA);
+
+ shortP = Cudd_ShortestPath(dd, C, NULL, NULL, &length);
+ if (shortP == NULL) exit(2);
+ Cudd_Ref(shortP);
+ if (pr>0) {
+ (void) printf(":6: shortP"); Cudd_PrintDebug(dd,shortP,nx+ny,pr);
+ }
+
+ /* Test Cudd_bddIteConstant and Cudd_bddLeq. */
+ if (!Cudd_bddLeq(dd,shortP,C)) exit(2);
+ if (Cudd_bddIteConstant(dd,Cudd_Not(shortP),one,C) != one) exit(2);
+ Cudd_RecursiveDeref(dd, shortP);
+
+ if (profile) {
+ retval = cuddHeapProfile(dd);
+ }
+
+ size = dd->size;
+
+ if (pr>0) {
+ (void) printf("Average distance: %g\n", Cudd_AverageDistance(dd));
+ }
+
+ /* Reorder if so requested. */
+ if (approach != CUDD_REORDER_NONE) {
+#ifndef DD_STATS
+ retval = Cudd_EnableReorderingReporting(dd);
+ if (retval == 0) {
+ (void) fprintf(stderr,"Error reported by Cudd_EnableReorderingReporting\n");
+ exit(3);
+ }
+#endif
+#ifdef DD_DEBUG
+ retval = Cudd_DebugCheck(dd);
+ if (retval != 0) {
+ (void) fprintf(stderr,"Error reported by Cudd_DebugCheck\n");
+ exit(3);
+ }
+ retval = Cudd_CheckKeys(dd);
+ if (retval != 0) {
+ (void) fprintf(stderr,"Error reported by Cudd_CheckKeys\n");
+ exit(3);
+ }
+#endif
+ retval = Cudd_ReduceHeap(dd,(Cudd_ReorderingType)approach,5);
+ if (retval == 0) {
+ (void) fprintf(stderr,"Error reported by Cudd_ReduceHeap\n");
+ exit(3);
+ }
+#ifndef DD_STATS
+ retval = Cudd_DisableReorderingReporting(dd);
+ if (retval == 0) {
+ (void) fprintf(stderr,"Error reported by Cudd_DisableReorderingReporting\n");
+ exit(3);
+ }
+#endif
+#ifdef DD_DEBUG
+ retval = Cudd_DebugCheck(dd);
+ if (retval != 0) {
+ (void) fprintf(stderr,"Error reported by Cudd_DebugCheck\n");
+ exit(3);
+ }
+ retval = Cudd_CheckKeys(dd);
+ if (retval != 0) {
+ (void) fprintf(stderr,"Error reported by Cudd_CheckKeys\n");
+ exit(3);
+ }
+#endif
+ if (approach == CUDD_REORDER_SYMM_SIFT ||
+ approach == CUDD_REORDER_SYMM_SIFT_CONV) {
+ Cudd_SymmProfile(dd,0,dd->size-1);
+ }
+
+ if (pr>0) {
+ (void) printf("Average distance: %g\n", Cudd_AverageDistance(dd));
+ }
+
+ if (keepperm) {
+ /* Print variable permutation. */
+ (void) printf("Variable Permutation:");
+ for (i=0; i<size; i++) {
+ if (i%20 == 0) (void) printf("\n");
+ (void) printf("%d ", dd->invperm[i]);
+ }
+ (void) printf("\n");
+ (void) printf("Inverse Permutation:");
+ for (i=0; i<size; i++) {
+ if (i%20 == 0) (void) printf("\n");
+ (void) printf("%d ", dd->perm[i]);
+ }
+ (void) printf("\n");
+ }
+
+ if (pr>0) {(void) printf("M"); Cudd_PrintDebug(dd,M,nx+ny,pr);}
+
+ if (profile) {
+ retval = cuddHeapProfile(dd);
+ }
+
+ }
+
+ /* Dump DDs of C and M if so requested. */
+ if (dfile != NULL) {
+ dfunc[0] = C;
+ dfunc[1] = M;
+ if (blifOrDot == 1) {
+ /* Only dump C because blif cannot handle ADDs */
+ retval = Cudd_DumpBlif(dd,1,dfunc,NULL,onames,NULL,dfp);
+ } else {
+ retval = Cudd_DumpDot(dd,2,dfunc,NULL,onames,dfp);
+ }
+ if (retval != 1) {
+ (void) fprintf(stderr,"abnormal termination\n");
+ exit(2);
+ }
+ }
+
+ Cudd_RecursiveDeref(dd, C);
+ Cudd_RecursiveDeref(dd, M);
+
+ if (clearcache) {
+ if (pr>0) {(void) printf("Clearing the cache... ");}
+ for (i = dd->cacheSlots - 1; i>=0; i--) {
+ dd->cache[i].data = NIL(DdNode);
+ }
+ if (pr>0) {(void) printf("done\n");}
+ }
+ if (pr>0) {
+ (void) printf("Number of variables = %6d\t",dd->size);
+ (void) printf("Number of slots = %6d\n",dd->slots);
+ (void) printf("Number of keys = %6d\t",dd->keys);
+ (void) printf("Number of min dead = %6d\n",dd->minDead);
+ }
+
+ } while (multiple && !feof(fp));
+
+ fclose(fp);
+ if (dfile != NULL) {
+ fclose(dfp);
+ }
+
+ /* Second phase: experiment with Walsh matrices. */
+ if (!testWalsh(dd,N,cmu,approach,pr)) {
+ exit(2);
+ }
+
+ /* Check variable destruction. */
+ assert(cuddDestroySubtables(dd,3));
+ assert(Cudd_DebugCheck(dd) == 0);
+ assert(Cudd_CheckKeys(dd) == 0);
+
+ retval = Cudd_CheckZeroRef(dd);
+ ok = retval != 0; /* ok == 0 means O.K. */
+ if (retval != 0) {
+ (void) fprintf(stderr,
+ "%d non-zero DD reference counts after dereferencing\n", retval);
+ }
+
+ if (pr >= 0) {
+ (void) Cudd_PrintInfo(dd,stdout);
+ }
+
+ Cudd_Quit(dd);
+
+#ifdef MNEMOSYNE
+ mnem_writestats();
+#endif
+
+ if (pr>0) (void) printf("total time = %s\n",
+ util_print_time(util_cpu_time() - startTime));
+
+ if (pr >= 0) util_print_cpu_stats(stdout);
+ exit(ok);
+ /* NOTREACHED */
+
+} /* end of main */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints usage info for testcudd.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+usage(char *prog)
+{
+ (void) fprintf(stderr, "usage: %s [options] [file]\n", prog);
+ (void) fprintf(stderr, " -C\t\tuse CMU multiplication algorithm\n");
+ (void) fprintf(stderr, " -D\t\tenable automatic dynamic reordering\n");
+ (void) fprintf(stderr, " -H\t\tread matrix in Harwell format\n");
+ (void) fprintf(stderr, " -M\t\tturns off memory allocation recording\n");
+ (void) fprintf(stderr, " -P\t\tprint BDD heap profile\n");
+ (void) fprintf(stderr, " -S n\t\tnumber of slots for each subtable\n");
+ (void) fprintf(stderr, " -X n\t\ttarget maximum memory in bytes\n");
+ (void) fprintf(stderr, " -a n\t\tchoose reordering approach (0-13)\n");
+ (void) fprintf(stderr, " \t\t\t0: same as autoMethod\n");
+ (void) fprintf(stderr, " \t\t\t1: no reordering (default)\n");
+ (void) fprintf(stderr, " \t\t\t2: random\n");
+ (void) fprintf(stderr, " \t\t\t3: pivot\n");
+ (void) fprintf(stderr, " \t\t\t4: sifting\n");
+ (void) fprintf(stderr, " \t\t\t5: sifting to convergence\n");
+ (void) fprintf(stderr, " \t\t\t6: symmetric sifting\n");
+ (void) fprintf(stderr, " \t\t\t7: symmetric sifting to convergence\n");
+ (void) fprintf(stderr, " \t\t\t8-10: window of size 2-4\n");
+ (void) fprintf(stderr, " \t\t\t11-13: window of size 2-4 to conv.\n");
+ (void) fprintf(stderr, " \t\t\t14: group sifting\n");
+ (void) fprintf(stderr, " \t\t\t15: group sifting to convergence\n");
+ (void) fprintf(stderr, " \t\t\t16: simulated annealing\n");
+ (void) fprintf(stderr, " \t\t\t17: genetic algorithm\n");
+ (void) fprintf(stderr, " -b\t\tuse blif as format for dumps\n");
+ (void) fprintf(stderr, " -c\t\tclear the cache after each matrix\n");
+ (void) fprintf(stderr, " -d file\tdump DDs to file\n");
+ (void) fprintf(stderr, " -g\t\tselect aggregation criterion (0,5,7)\n");
+ (void) fprintf(stderr, " -h\t\tprints this message\n");
+ (void) fprintf(stderr, " -k\t\tprint the variable permutation\n");
+ (void) fprintf(stderr, " -m\t\tread multiple matrices (only with -H)\n");
+ (void) fprintf(stderr, " -n n\t\tnumber of variables\n");
+ (void) fprintf(stderr, " -p n\t\tcontrol verbosity\n");
+ (void) fprintf(stderr, " -v n\t\tinitial variables in the unique table\n");
+ (void) fprintf(stderr, " -x n\t\tinitial size of the cache\n");
+ exit(2);
+} /* end of usage */
+
+
+/**Function********************************************************************
+
+ Synopsis [Opens a file.]
+
+ Description [Opens a file, or fails with an error message and exits.
+ Allows '-' as a synonym for standard input.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static FILE *
+open_file(char *filename, char *mode)
+{
+ FILE *fp;
+
+ if (strcmp(filename, "-") == 0) {
+ return mode[0] == 'r' ? stdin : stdout;
+ } else if ((fp = fopen(filename, mode)) == NULL) {
+ perror(filename);
+ exit(1);
+ }
+ return fp;
+
+} /* end of open_file */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tests Walsh matrix multiplication.]
+
+ Description [Tests Walsh matrix multiplication. Return 1 if successful;
+ 0 otherwise.]
+
+ SideEffects [May create new variables in the manager.]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+testWalsh(
+ DdManager *dd /* manager */,
+ int N /* number of variables */,
+ int cmu /* use CMU approach to matrix multiplication */,
+ int approach /* reordering approach */,
+ int pr /* verbosity level */)
+{
+ DdNode *walsh1, *walsh2, *wtw;
+ DdNode **x, **v, **z;
+ int i, retval;
+ DdNode *one = DD_ONE(dd);
+ DdNode *zero = DD_ZERO(dd);
+
+ if (N > 3) {
+ x = ALLOC(DdNode *,N);
+ v = ALLOC(DdNode *,N);
+ z = ALLOC(DdNode *,N);
+
+ for (i = N-1; i >= 0; i--) {
+ Cudd_Ref(x[i]=cuddUniqueInter(dd,3*i,one,zero));
+ Cudd_Ref(v[i]=cuddUniqueInter(dd,3*i+1,one,zero));
+ Cudd_Ref(z[i]=cuddUniqueInter(dd,3*i+2,one,zero));
+ }
+ Cudd_Ref(walsh1 = Cudd_addWalsh(dd,v,z,N));
+ if (pr>0) {(void) printf("walsh1"); Cudd_PrintDebug(dd,walsh1,2*N,pr);}
+ Cudd_Ref(walsh2 = Cudd_addWalsh(dd,x,v,N));
+ if (cmu) {
+ Cudd_Ref(wtw = Cudd_addTimesPlus(dd,walsh2,walsh1,v,N));
+ } else {
+ Cudd_Ref(wtw = Cudd_addMatrixMultiply(dd,walsh2,walsh1,v,N));
+ }
+ if (pr>0) {(void) printf("wtw"); Cudd_PrintDebug(dd,wtw,2*N,pr);}
+
+ if (approach != CUDD_REORDER_NONE) {
+#ifdef DD_DEBUG
+ retval = Cudd_DebugCheck(dd);
+ if (retval != 0) {
+ (void) fprintf(stderr,"Error reported by Cudd_DebugCheck\n");
+ return(0);
+ }
+#endif
+ retval = Cudd_ReduceHeap(dd,(Cudd_ReorderingType)approach,5);
+ if (retval == 0) {
+ (void) fprintf(stderr,"Error reported by Cudd_ReduceHeap\n");
+ return(0);
+ }
+#ifdef DD_DEBUG
+ retval = Cudd_DebugCheck(dd);
+ if (retval != 0) {
+ (void) fprintf(stderr,"Error reported by Cudd_DebugCheck\n");
+ return(0);
+ }
+#endif
+ if (approach == CUDD_REORDER_SYMM_SIFT ||
+ approach == CUDD_REORDER_SYMM_SIFT_CONV) {
+ Cudd_SymmProfile(dd,0,dd->size-1);
+ }
+ }
+ /* Clean up. */
+ Cudd_RecursiveDeref(dd, wtw);
+ Cudd_RecursiveDeref(dd, walsh1);
+ Cudd_RecursiveDeref(dd, walsh2);
+ for (i=0; i < N; i++) {
+ Cudd_RecursiveDeref(dd, x[i]);
+ Cudd_RecursiveDeref(dd, v[i]);
+ Cudd_RecursiveDeref(dd, z[i]);
+ }
+ FREE(x);
+ FREE(v);
+ FREE(z);
+ }
+ return(1);
+
+} /* end of testWalsh */
+
+/**Function********************************************************************
+
+ Synopsis [Tests iterators.]
+
+ Description [Tests iterators on cubes and nodes.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+testIterators(
+ DdManager *dd,
+ DdNode *M,
+ DdNode *C,
+ int pr)
+{
+ int *cube;
+ CUDD_VALUE_TYPE value;
+ DdGen *gen;
+ int q;
+
+ /* Test iterator for cubes. */
+ if (pr>1) {
+ (void) printf("Testing iterator on cubes:\n");
+ Cudd_ForeachCube(dd,M,gen,cube,value) {
+ for (q = 0; q < dd->size; q++) {
+ switch (cube[q]) {
+ case 0:
+ (void) printf("0");
+ break;
+ case 1:
+ (void) printf("1");
+ break;
+ case 2:
+ (void) printf("-");
+ break;
+ default:
+ (void) printf("?");
+ }
+ }
+ (void) printf(" %g\n",value);
+ }
+ (void) printf("\n");
+ }
+
+ if (pr>1) {
+ (void) printf("Testing prime expansion of cubes:\n");
+ if (!Cudd_bddPrintCover(dd,C,C)) return(0);
+ }
+
+ /* Test iterator on nodes. */
+ if (pr>2) {
+ DdGen *gen;
+ DdNode *node;
+ (void) printf("Testing iterator on nodes:\n");
+ Cudd_ForeachNode(dd,M,gen,node) {
+ if (Cudd_IsConstant(node)) {
+#if SIZEOF_VOID_P == 8
+ (void) printf("ID = 0x%lx\tvalue = %-9g\n",
+ (unsigned long) node /
+ (unsigned long) sizeof(DdNode),
+ Cudd_V(node));
+#else
+ (void) printf("ID = 0x%x\tvalue = %-9g\n",
+ (unsigned int) node /
+ (unsigned int) sizeof(DdNode),
+ Cudd_V(node));
+#endif
+ } else {
+#if SIZEOF_VOID_P == 8
+ (void) printf("ID = 0x%lx\tindex = %d\tr = %d\n",
+ (unsigned long) node /
+ (unsigned long) sizeof(DdNode),
+ node->index, node->ref);
+#else
+ (void) printf("ID = 0x%x\tindex = %d\tr = %d\n",
+ (unsigned int) node /
+ (unsigned int) sizeof(DdNode),
+ node->index, node->ref);
+#endif
+ }
+ }
+ (void) printf("\n");
+ }
+ return(1);
+
+} /* end of testIterators */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tests the functions related to the exclusive OR.]
+
+ Description [Tests the functions related to the exclusive OR. It
+ builds the boolean difference of the given function in three
+ different ways and checks that the results is the same. Returns 1 if
+ successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+testXor(DdManager *dd, DdNode *f, int pr, int nvars)
+{
+ DdNode *f1, *f0, *res1, *res2;
+ int x;
+
+ /* Extract cofactors w.r.t. mid variable. */
+ x = nvars / 2;
+ f1 = Cudd_Cofactor(dd,f,dd->vars[x]);
+ if (f1 == NULL) return(0);
+ Cudd_Ref(f1);
+
+ f0 = Cudd_Cofactor(dd,f,Cudd_Not(dd->vars[x]));
+ if (f0 == NULL) {
+ Cudd_RecursiveDeref(dd,f1);
+ return(0);
+ }
+ Cudd_Ref(f0);
+
+ /* Compute XOR of cofactors with ITE. */
+ res1 = Cudd_bddIte(dd,f1,Cudd_Not(f0),f0);
+ if (res1 == NULL) return(0);
+ Cudd_Ref(res1);
+
+ if (pr>0) {(void) printf("xor1"); Cudd_PrintDebug(dd,res1,nvars,pr);}
+
+ /* Compute XOR of cofactors with XOR. */
+ res2 = Cudd_bddXor(dd,f1,f0);
+ if (res2 == NULL) {
+ Cudd_RecursiveDeref(dd,res1);
+ return(0);
+ }
+ Cudd_Ref(res2);
+
+ if (res1 != res2) {
+ if (pr>0) {(void) printf("xor2"); Cudd_PrintDebug(dd,res2,nvars,pr);}
+ Cudd_RecursiveDeref(dd,res1);
+ Cudd_RecursiveDeref(dd,res2);
+ return(0);
+ }
+ Cudd_RecursiveDeref(dd,res1);
+ Cudd_RecursiveDeref(dd,f1);
+ Cudd_RecursiveDeref(dd,f0);
+
+ /* Compute boolean difference directly. */
+ res1 = Cudd_bddBooleanDiff(dd,f,x);
+ if (res1 == NULL) {
+ Cudd_RecursiveDeref(dd,res2);
+ return(0);
+ }
+ Cudd_Ref(res1);
+
+ if (res1 != res2) {
+ if (pr>0) {(void) printf("xor3"); Cudd_PrintDebug(dd,res1,nvars,pr);}
+ Cudd_RecursiveDeref(dd,res1);
+ Cudd_RecursiveDeref(dd,res2);
+ return(0);
+ }
+ Cudd_RecursiveDeref(dd,res1);
+ Cudd_RecursiveDeref(dd,res2);
+ return(1);
+
+} /* end of testXor */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tests the Hamming distance functions.]
+
+ Description [Tests the Hammming distance functions. Returns
+ 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+testHamming(
+ DdManager *dd,
+ DdNode *f,
+ int pr,
+ int nvars)
+{
+ DdNode **vars, *minBdd, *zero, *scan;
+ int i;
+ int d;
+ int *minterm;
+ int size = Cudd_ReadSize(dd);
+
+ vars = ALLOC(DdNode *, size);
+ if (vars == NULL) return(0);
+ for (i = 0; i < size; i++) {
+ vars[i] = Cudd_bddIthVar(dd,i);
+ }
+
+ minBdd = Cudd_bddPickOneMinterm(dd,Cudd_Not(f),vars,size);
+ Cudd_Ref(minBdd);
+ if (pr > 0) {
+ (void) printf("Chosen minterm for Hamming distance test: ");
+ Cudd_PrintDebug(dd,minBdd,size,pr);
+ }
+
+ minterm = ALLOC(int,size);
+ if (minterm == NULL) {
+ FREE(vars);
+ Cudd_RecursiveDeref(dd,minBdd);
+ return(0);
+ }
+ scan = minBdd;
+ zero = Cudd_Not(DD_ONE(dd));
+ while (!Cudd_IsConstant(scan)) {
+ DdNode *R = Cudd_Regular(scan);
+ DdNode *T = Cudd_T(R);
+ DdNode *E = Cudd_E(R);
+ if (R != scan) {
+ T = Cudd_Not(T);
+ E = Cudd_Not(E);
+ }
+ if (T == zero) {
+ minterm[R->index] = 0;
+ scan = E;
+ } else {
+ minterm[R->index] = 1;
+ scan = T;
+ }
+ }
+ Cudd_RecursiveDeref(dd,minBdd);
+
+ d = Cudd_MinHammingDist(dd,f,minterm,size);
+
+ (void) printf("Minimum Hamming distance = %d\n", d);
+
+ FREE(vars);
+ FREE(minterm);
+ return(1);
+
+} /* end of testHamming */
diff --git a/src/bdd/dsd/dsd.h b/src/bdd/dsd/dsd.h
new file mode 100644
index 00000000..60cf4a4e
--- /dev/null
+++ b/src/bdd/dsd/dsd.h
@@ -0,0 +1,115 @@
+/**CFile****************************************************************
+
+ FileName [dsd.h]
+
+ PackageName [DSD: Disjoint-support decomposition package.]
+
+ Synopsis [External declarations of the package.
+ This fast BDD-based recursive algorithm for simple
+ (single-output) DSD is based on the following papers:
+ (1) V. Bertacco and M. Damiani, "Disjunctive decomposition of
+ logic functions," Proc. ICCAD '97, pp. 78-82.
+ (2) Y. Matsunaga, "An exact and efficient algorithm for disjunctive
+ decomposition", Proc. SASIMI '98, pp. 44-50.
+ The scope of detected decompositions is the same as in the paper:
+ T. Sasao and M. Matsuura, "DECOMPOS: An integrated system for
+ functional decomposition," Proc. IWLS '98, pp. 471-477.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 8.0. Started - September 22, 2003.]
+
+ Revision [$Id: dsd.h,v 1.0 2002/22/09 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __DSD_H__
+#define __DSD_H__
+
+////////////////////////////////////////////////////////////////////////
+/// TYPEDEF DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct Dsd_Manager_t_ Dsd_Manager_t;
+typedef struct Dsd_Node_t_ Dsd_Node_t;
+typedef enum Dsd_Type_t_ Dsd_Type_t;
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+// types of DSD nodes
+enum Dsd_Type_t_ {
+ DSD_NODE_NONE = 0,
+ DSD_NODE_CONST1 = 1,
+ DSD_NODE_BUF = 2,
+ DSD_NODE_OR = 3,
+ DSD_NODE_EXOR = 4,
+ DSD_NODE_PRIME = 5,
+};
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// complementation and testing for pointers for decomposition entries
+#define Dsd_IsComplement(p) (((int)((long) (p) & 01)))
+#define Dsd_Regular(p) ((Dsd_Node_t *)((unsigned)(p) & ~01))
+#define Dsd_Not(p) ((Dsd_Node_t *)((long)(p) ^ 01))
+#define Dsd_NotCond(p,c) ((Dsd_Node_t *)((long)(p) ^ (c)))
+
+////////////////////////////////////////////////////////////////////////
+/// ITERATORS ///
+////////////////////////////////////////////////////////////////////////
+
+// iterator through the transitions
+#define Dsd_NodeForEachChild( Node, Index, Child ) \
+ for ( Index = 0; \
+ Index < Dsd_NodeReadDecsNum(Node) && \
+ ((Child = Dsd_NodeReadDec(Node,Index))>=0); \
+ Index++ )
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== dsdApi.c =======================================================*/
+extern Dsd_Type_t Dsd_NodeReadType( Dsd_Node_t * p );
+extern DdNode * Dsd_NodeReadFunc( Dsd_Node_t * p );
+extern DdNode * Dsd_NodeReadSupp( Dsd_Node_t * p );
+extern Dsd_Node_t ** Dsd_NodeReadDecs( Dsd_Node_t * p );
+extern Dsd_Node_t * Dsd_NodeReadDec ( Dsd_Node_t * p, int i );
+extern int Dsd_NodeReadDecsNum( Dsd_Node_t * p );
+extern int Dsd_NodeReadMark( Dsd_Node_t * p );
+extern void Dsd_NodeSetMark( Dsd_Node_t * p, int Mark );
+extern Dsd_Node_t * Dsd_ManagerReadRoot( Dsd_Manager_t * pMan, int i );
+extern Dsd_Node_t * Dsd_ManagerReadInput( Dsd_Manager_t * pMan, int i );
+/*=== dsdMan.c =======================================================*/
+extern Dsd_Manager_t * Dsd_ManagerStart( DdManager * dd, int nSuppMax, int fVerbose );
+extern void Dsd_ManagerStop( Dsd_Manager_t * dMan );
+/*=== dsdProc.c =======================================================*/
+extern void Dsd_Decompose( Dsd_Manager_t * dMan, DdNode ** pbFuncs, int nFuncs );
+/*=== dsdTree.c =======================================================*/
+extern void Dsd_TreeNodeGetInfo( Dsd_Manager_t * dMan, int * DepthMax, int * GateSizeMax );
+extern void Dsd_TreeNodeGetInfoOne( Dsd_Node_t * pNode, int * DepthMax, int * GateSizeMax );
+extern int Dsd_TreeCountNonTerminalNodes( Dsd_Manager_t * dMan );
+extern int Dsd_TreeCountNonTerminalNodesOne( Dsd_Node_t * pRoot );
+extern int Dsd_TreeCountPrimeNodes( Dsd_Manager_t * pDsdMan );
+extern int Dsd_TreeCountPrimeNodesOne( Dsd_Node_t * pRoot );
+extern int Dsd_TreeCollectDecomposableVars( Dsd_Manager_t * dMan, int * pVars );
+extern Dsd_Node_t ** Dsd_TreeCollectNodesDfs( Dsd_Manager_t * dMan, int * pnNodes );
+extern void Dsd_TreePrint( FILE * pFile, Dsd_Manager_t * dMan, char * pInputNames[], char * pOutputNames[], int fShortNames, int Output );
+/*=== dsdLocal.c =======================================================*/
+extern DdNode * Dsd_TreeGetPrimeFunction( DdManager * dd, Dsd_Node_t * pNode );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif \ No newline at end of file
diff --git a/src/bdd/dsd/dsdApi.c b/src/bdd/dsd/dsdApi.c
new file mode 100644
index 00000000..f2269092
--- /dev/null
+++ b/src/bdd/dsd/dsdApi.c
@@ -0,0 +1,95 @@
+/**CFile****************************************************************
+
+ FileName [dsdApi.c]
+
+ PackageName [DSD: Disjoint-support decomposition package.]
+
+ Synopsis [Implementation of API functions.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 8.0. Started - September 22, 2003.]
+
+ Revision [$Id: dsdApi.c,v 1.0 2002/22/09 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "dsdInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [APIs of the DSD node.]
+
+ Description [The node's type can be retrieved by calling
+ Dsd_NodeReadType(). The type is one of the following: constant 1 node,
+ the buffer (or the elementary variable), OR gate, EXOR gate, or
+ PRIME function (a non-DSD-decomposable function with more than two
+ inputs). The return value of Dsd_NodeReadFunc() is the global function
+ of the DSD node. The return value of Dsd_NodeReadSupp() is the support
+ of the global function of the DSD node. The array of DSD nodes
+ returned by Dsd_NodeReadDecs() is the array of decomposition nodes for
+ the formal inputs of the given node. The number of decomposition entries
+ returned by Dsd_NodeReadDecsNum() is the number of formal inputs.
+ The mark is explained below.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Dsd_Type_t Dsd_NodeReadType( Dsd_Node_t * p ) { return p->Type; }
+DdNode * Dsd_NodeReadFunc( Dsd_Node_t * p ) { return p->G; }
+DdNode * Dsd_NodeReadSupp( Dsd_Node_t * p ) { return p->S; }
+Dsd_Node_t ** Dsd_NodeReadDecs( Dsd_Node_t * p ) { return p->pDecs; }
+Dsd_Node_t * Dsd_NodeReadDec ( Dsd_Node_t * p, int i ) { return p->pDecs[i]; }
+int Dsd_NodeReadDecsNum( Dsd_Node_t * p ) { return p->nDecs; }
+int Dsd_NodeReadMark( Dsd_Node_t * p ) { return p->Mark; }
+
+/**Function*************************************************************
+
+ Synopsis [APIs of the DSD node.]
+
+ Description [This API allows the user to set the integer mark in the
+ given DSD node. The mark is guaranteed to persist as long as the
+ calls to the decomposition are not performed. In any case, the mark
+ is useful to associate the node with some temporary information, such
+ as its number in the DFS ordered list of the DSD nodes or its number in
+ the BLIF file that it being written.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_NodeSetMark( Dsd_Node_t * p, int Mark ){ p->Mark = Mark; }
+
+/**Function*************************************************************
+
+ Synopsis [APIs of the DSD manager.]
+
+ Description [Allows the use to get hold of an individual leave of
+ the DSD tree (Dsd_ManagerReadInput) or an individual root of the
+ decomposition tree (Dsd_ManagerReadRoot). The root may have the
+ complemented attribute.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Dsd_Node_t * Dsd_ManagerReadRoot( Dsd_Manager_t * pMan, int i ) { return pMan->pRoots[i]; }
+Dsd_Node_t * Dsd_ManagerReadInput( Dsd_Manager_t * pMan, int i ) { return pMan->pInputs[i]; }
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
diff --git a/src/bdd/dsd/dsdCheck.c b/src/bdd/dsd/dsdCheck.c
new file mode 100644
index 00000000..608aa2e3
--- /dev/null
+++ b/src/bdd/dsd/dsdCheck.c
@@ -0,0 +1,314 @@
+/**CFile****************************************************************
+
+ FileName [dsdCheck.c]
+
+ PackageName [DSD: Disjoint-support decomposition package.]
+
+ Synopsis [Procedures to check the identity of root functions.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 8.0. Started - September 22, 2003.]
+
+ Revision [$Id: dsdCheck.c,v 1.0 2002/22/09 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "dsdInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct Dsd_Cache_t_ Dds_Cache_t;
+typedef struct Dsd_Entry_t_ Dsd_Entry_t;
+
+struct Dsd_Cache_t_
+{
+ Dsd_Entry_t * pTable;
+ int nTableSize;
+ int nSuccess;
+ int nFailure;
+};
+
+struct Dsd_Entry_t_
+{
+ DdNode * bX[5];
+};
+
+static Dds_Cache_t * pCache;
+
+static int Dsd_CheckRootFunctionIdentity_rec( DdManager * dd, DdNode * bF1, DdNode * bF2, DdNode * bC1, DdNode * bC2 );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function********************************************************************
+
+ Synopsis [(Re)allocates the local cache.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void Dsd_CheckCacheAllocate( int nEntries )
+{
+ int nRequested;
+
+ pCache = ALLOC( Dds_Cache_t, 1 );
+ memset( pCache, 0, sizeof(Dds_Cache_t) );
+
+ // check what is the size of the current cache
+ nRequested = Cudd_Prime( nEntries );
+ if ( pCache->nTableSize != nRequested )
+ { // the current size is different
+ // deallocate the old, allocate the new
+ if ( pCache->nTableSize )
+ Dsd_CheckCacheDeallocate();
+ // allocate memory for the hash table
+ pCache->nTableSize = nRequested;
+ pCache->pTable = ALLOC( Dsd_Entry_t, nRequested );
+ }
+ // otherwise, there is no need to allocate, just clean
+ Dsd_CheckCacheClear();
+// printf( "\nThe number of allocated cache entries = %d.\n\n", pCache->nTableSize );
+}
+
+/**Function********************************************************************
+
+ Synopsis [Delocates the local cache.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void Dsd_CheckCacheDeallocate()
+{
+ free( pCache->pTable );
+ free( pCache );
+}
+
+/**Function********************************************************************
+
+ Synopsis [Clears the local cache.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void Dsd_CheckCacheClear()
+{
+ int i;
+ for ( i = 0; i < pCache->nTableSize; i++ )
+ pCache->pTable[0].bX[0] = NULL;
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether it is true that bF1(bC1=0) == bF2(bC2=0).]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int Dsd_CheckRootFunctionIdentity( DdManager * dd, DdNode * bF1, DdNode * bF2, DdNode * bC1, DdNode * bC2 )
+{
+ int RetValue;
+// pCache->nSuccess = 0;
+// pCache->nFailure = 0;
+ RetValue = Dsd_CheckRootFunctionIdentity_rec(dd, bF1, bF2, bC1, bC2);
+// printf( "Cache success = %d. Cache failure = %d.\n", pCache->nSuccess, pCache->nFailure );
+ return RetValue;
+}
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Dsd_CheckRootFunctionIdentity().]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int Dsd_CheckRootFunctionIdentity_rec( DdManager * dd, DdNode * bF1, DdNode * bF2, DdNode * bC1, DdNode * bC2 )
+{
+ unsigned HKey;
+
+ // if either bC1 or bC2 is zero, the test is true
+// if ( bC1 == b0 || bC2 == b0 ) return 1;
+ assert( bC1 != b0 );
+ assert( bC2 != b0 );
+
+ // if both bC1 and bC2 are one - perform comparison
+ if ( bC1 == b1 && bC2 == b1 ) return (int)( bF1 == bF2 );
+
+ if ( bF1 == b0 )
+ return Cudd_bddLeq( dd, bC2, Cudd_Not(bF2) );
+
+ if ( bF1 == b1 )
+ return Cudd_bddLeq( dd, bC2, bF2 );
+
+ if ( bF2 == b0 )
+ return Cudd_bddLeq( dd, bC1, Cudd_Not(bF1) );
+
+ if ( bF2 == b1 )
+ return Cudd_bddLeq( dd, bC1, bF1 );
+
+ // otherwise, keep expanding
+
+ // check cache
+// HKey = _Hash( ((unsigned)bF1), ((unsigned)bF2), ((unsigned)bC1), ((unsigned)bC2) );
+ HKey = hashKey4( bF1, bF2, bC1, bC2, pCache->nTableSize );
+ if ( pCache->pTable[HKey].bX[0] == bF1 &&
+ pCache->pTable[HKey].bX[1] == bF2 &&
+ pCache->pTable[HKey].bX[2] == bC1 &&
+ pCache->pTable[HKey].bX[3] == bC2 )
+ {
+ pCache->nSuccess++;
+ return (int)pCache->pTable[HKey].bX[4]; // the last bit records the result (yes/no)
+ }
+ else
+ {
+
+ // determine the top variables
+ int RetValue;
+ DdNode * bA[4] = { bF1, bF2, bC1, bC2 }; // arguments
+ DdNode * bAR[4] = { Cudd_Regular(bF1), Cudd_Regular(bF2), Cudd_Regular(bC1), Cudd_Regular(bC2) }; // regular arguments
+ int CurLevel[4] = { cuddI(dd,bAR[0]->index), cuddI(dd,bAR[1]->index), cuddI(dd,bAR[2]->index), cuddI(dd,bAR[3]->index) };
+ int TopLevel = CUDD_CONST_INDEX;
+ int i;
+ DdNode * bE[4], * bT[4];
+ DdNode * bF1next, * bF2next, * bC1next, * bC2next;
+
+ pCache->nFailure++;
+
+ // determine the top level
+ for ( i = 0; i < 4; i++ )
+ if ( TopLevel > CurLevel[i] )
+ TopLevel = CurLevel[i];
+
+ // compute the cofactors
+ for ( i = 0; i < 4; i++ )
+ if ( TopLevel == CurLevel[i] )
+ {
+ if ( bA[i] != bAR[i] ) // complemented
+ {
+ bE[i] = Cudd_Not(cuddE(bAR[i]));
+ bT[i] = Cudd_Not(cuddT(bAR[i]));
+ }
+ else
+ {
+ bE[i] = cuddE(bAR[i]);
+ bT[i] = cuddT(bAR[i]);
+ }
+ }
+ else
+ bE[i] = bT[i] = bA[i];
+
+ // solve subproblems
+ // three cases are possible
+
+ // (1) the top var belongs to both C1 and C2
+ // in this case, any cofactor of F1 and F2 will do,
+ // as long as the corresponding cofactor of C1 and C2 is not equal to 0
+ if ( TopLevel == CurLevel[2] && TopLevel == CurLevel[3] )
+ {
+ if ( bE[2] != b0 ) // C1
+ {
+ bF1next = bE[0];
+ bC1next = bE[2];
+ }
+ else
+ {
+ bF1next = bT[0];
+ bC1next = bT[2];
+ }
+ if ( bE[3] != b0 ) // C2
+ {
+ bF2next = bE[1];
+ bC2next = bE[3];
+ }
+ else
+ {
+ bF2next = bT[1];
+ bC2next = bT[3];
+ }
+ RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bF1next, bF2next, bC1next, bC2next );
+ }
+ // (2) the top var belongs to either C1 or C2
+ // in this case normal splitting of cofactors
+ else if ( TopLevel == CurLevel[2] && TopLevel != CurLevel[3] )
+ {
+ if ( bE[2] != b0 ) // C1
+ {
+ bF1next = bE[0];
+ bC1next = bE[2];
+ }
+ else
+ {
+ bF1next = bT[0];
+ bC1next = bT[2];
+ }
+ // split around this variable
+ RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bF1next, bE[1], bC1next, bE[3] );
+ if ( RetValue == 1 ) // test another branch; otherwise, there is no need to test
+ RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bF1next, bT[1], bC1next, bT[3] );
+ }
+ else if ( TopLevel != CurLevel[2] && TopLevel == CurLevel[3] )
+ {
+ if ( bE[3] != b0 ) // C2
+ {
+ bF2next = bE[1];
+ bC2next = bE[3];
+ }
+ else
+ {
+ bF2next = bT[1];
+ bC2next = bT[3];
+ }
+ // split around this variable
+ RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bE[0], bF2next, bE[2], bC2next );
+ if ( RetValue == 1 ) // test another branch; otherwise, there is no need to test
+ RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bT[0], bF2next, bT[2], bC2next );
+ }
+ // (3) the top var does not belong to C1 and C2
+ // in this case normal splitting of cofactors
+ else // if ( TopLevel != CurLevel[2] && TopLevel != CurLevel[3] )
+ {
+ // split around this variable
+ RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bE[0], bE[1], bE[2], bE[3] );
+ if ( RetValue == 1 ) // test another branch; otherwise, there is no need to test
+ RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bT[0], bT[1], bT[2], bT[3] );
+ }
+
+ // set cache
+ for ( i = 0; i < 4; i++ )
+ pCache->pTable[HKey].bX[i] = bA[i];
+ pCache->pTable[HKey].bX[4] = (DdNode*)RetValue;
+
+ return RetValue;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/bdd/dsd/dsdInt.h b/src/bdd/dsd/dsdInt.h
new file mode 100644
index 00000000..81440460
--- /dev/null
+++ b/src/bdd/dsd/dsdInt.h
@@ -0,0 +1,88 @@
+/**CFile****************************************************************
+
+ FileName [dsdInt.h]
+
+ PackageName [DSD: Disjoint-support decomposition package.]
+
+ Synopsis [Internal declarations of the package.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 8.0. Started - September 22, 2003.]
+
+ Revision [$Id: dsdInt.h,v 1.0 2002/22/09 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __DSD_INT_H__
+#define __DSD_INT_H__
+
+#include "extra.h"
+#include "dsd.h"
+
+////////////////////////////////////////////////////////////////////////
+/// TYPEDEF DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+typedef unsigned char byte;
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// DSD manager
+struct Dsd_Manager_t_
+{
+ DdManager * dd; // the BDD manager
+ st_table * Table; // the mapping of BDDs into their DEs
+ int nInputs; // the number of primary inputs
+ int nRoots; // the number of primary outputs
+ int nRootsAlloc;// the number of primary outputs
+ Dsd_Node_t ** pInputs; // the primary input nodes
+ Dsd_Node_t ** pRoots; // the primary output nodes
+ int fVerbose; // the verbosity level
+};
+
+// DSD node
+struct Dsd_Node_t_
+{
+ Dsd_Type_t Type; // decomposition type
+ DdNode * G; // function of the node
+ DdNode * S; // support of this function
+ Dsd_Node_t ** pDecs; // pointer to structures for formal inputs
+ int Mark; // the mark used by CASE 4 of disjoint decomposition
+ short nDecs; // the number of formal inputs
+ short nVisits; // the counter of visits
+};
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== dsdCheck.c =======================================================*/
+extern void Dsd_CheckCacheAllocate( int nEntries );
+extern void Dsd_CheckCacheDeallocate();
+extern void Dsd_CheckCacheClear();
+extern int Dsd_CheckRootFunctionIdentity( DdManager * dd, DdNode * bF1, DdNode * bF2, DdNode * bC1, DdNode * bC2 );
+/*=== dsdTree.c =======================================================*/
+extern Dsd_Node_t * Dsd_TreeNodeCreate( int Type, int nDecs, int BlockNum );
+extern void Dsd_TreeNodeDelete( DdManager * dd, Dsd_Node_t * pNode );
+extern void Dsd_TreeUnmark( Dsd_Manager_t * dMan );
+extern DdNode * Dsd_TreeGetPrimeFunctionOld( DdManager * dd, Dsd_Node_t * pNode, int fRemap );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
+#endif \ No newline at end of file
diff --git a/src/bdd/dsd/dsdLocal.c b/src/bdd/dsd/dsdLocal.c
new file mode 100644
index 00000000..6dd6e7d1
--- /dev/null
+++ b/src/bdd/dsd/dsdLocal.c
@@ -0,0 +1,337 @@
+/**CFile****************************************************************
+
+ FileName [dsdLocal.c]
+
+ PackageName [DSD: Disjoint-support decomposition package.]
+
+ Synopsis [Deriving the local function of the DSD node.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 8.0. Started - September 22, 2003.]
+
+ Revision [$Id: dsdLocal.c,v 1.0 2002/22/09 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "dsdInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// STATIC VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+static DdNode * Extra_dsdRemap( DdManager * dd, DdNode * bFunc, st_table * pCache,
+ int * pVar2Form, int * pForm2Var, DdNode * pbCube0[], DdNode * pbCube1[] );
+static DdNode * Extra_bddNodePointedByCube( DdManager * dd, DdNode * bF, DdNode * bC );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Returns the local function of the DSD node. ]
+
+ Description [The local function is computed using the global function
+ of the node and the global functions of the formal inputs. The resulting
+ local function is mapped using the topmost N variables of the manager.
+ The number of variables N is equal to the number of formal inputs.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Dsd_TreeGetPrimeFunction( DdManager * dd, Dsd_Node_t * pNode )
+{
+ int * pForm2Var; // the mapping of each formal input into its first var
+ int * pVar2Form; // the mapping of each var into its formal inputs
+ int i, iVar, iLev, * pPermute;
+ DdNode ** pbCube0, ** pbCube1;
+ DdNode * bFunc, * bRes, * bTemp;
+ st_table * pCache;
+
+ pPermute = ALLOC( int, dd->size );
+ pVar2Form = ALLOC( int, dd->size );
+ pForm2Var = ALLOC( int, dd->size );
+
+ pbCube0 = ALLOC( DdNode *, dd->size );
+ pbCube1 = ALLOC( DdNode *, dd->size );
+
+ // remap the global function in such a way that
+ // the support variables of each formal input are adjacent
+ iLev = 0;
+ for ( i = 0; i < pNode->nDecs; i++ )
+ {
+ pForm2Var[i] = dd->invperm[i];
+ for ( bTemp = pNode->pDecs[i]->S; bTemp != b1; bTemp = cuddT(bTemp) )
+ {
+ iVar = dd->invperm[iLev];
+ pPermute[bTemp->index] = iVar;
+ pVar2Form[iVar] = i;
+ iLev++;
+ }
+
+ // collect the cubes representing each assignment
+ pbCube0[i] = Extra_bddGetOneCube( dd, Cudd_Not(pNode->pDecs[i]->G) );
+ Cudd_Ref( pbCube0[i] );
+ pbCube1[i] = Extra_bddGetOneCube( dd, pNode->pDecs[i]->G );
+ Cudd_Ref( pbCube1[i] );
+ }
+
+ // remap the function
+ bFunc = Cudd_bddPermute( dd, pNode->G, pPermute ); Cudd_Ref( bFunc );
+ // remap the cube
+ for ( i = 0; i < pNode->nDecs; i++ )
+ {
+ pbCube0[i] = Cudd_bddPermute( dd, bTemp = pbCube0[i], pPermute ); Cudd_Ref( pbCube0[i] );
+ Cudd_RecursiveDeref( dd, bTemp );
+ pbCube1[i] = Cudd_bddPermute( dd, bTemp = pbCube1[i], pPermute ); Cudd_Ref( pbCube1[i] );
+ Cudd_RecursiveDeref( dd, bTemp );
+ }
+
+ // remap the function
+ pCache = st_init_table(st_ptrcmp,st_ptrhash);
+ bRes = Extra_dsdRemap( dd, bFunc, pCache, pVar2Form, pForm2Var, pbCube0, pbCube1 ); Cudd_Ref( bRes );
+ st_free_table( pCache );
+
+ Cudd_RecursiveDeref( dd, bFunc );
+ for ( i = 0; i < pNode->nDecs; i++ )
+ {
+ Cudd_RecursiveDeref( dd, pbCube0[i] );
+ Cudd_RecursiveDeref( dd, pbCube1[i] );
+ }
+/*
+////////////
+ // permute the function once again
+ // in such a way that i-th var stood for i-th formal input
+ for ( i = 0; i < dd->size; i++ )
+ pPermute[i] = -1;
+ for ( i = 0; i < pNode->nDecs; i++ )
+ pPermute[dd->invperm[i]] = i;
+ bRes = Cudd_bddPermute( dd, bTemp = bRes, pPermute ); Cudd_Ref( bRes );
+ Cudd_RecursiveDeref( dd, bTemp );
+////////////
+*/
+ FREE(pPermute);
+ FREE(pVar2Form);
+ FREE(pForm2Var);
+ FREE(pbCube0);
+ FREE(pbCube1);
+
+ Cudd_Deref( bRes );
+ return bRes;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Extra_dsdRemap( DdManager * dd, DdNode * bF, st_table * pCache,
+ int * pVar2Form, int * pForm2Var, DdNode * pbCube0[], DdNode * pbCube1[] )
+{
+ DdNode * bFR, * bF0, * bF1;
+ DdNode * bRes0, * bRes1, * bRes;
+ int iForm;
+
+ bFR = Cudd_Regular(bF);
+ if ( cuddIsConstant(bFR) )
+ return bF;
+
+ // check the hash-table
+ if ( bFR->ref != 1 )
+ {
+ if ( st_lookup( pCache, (char *)bF, (char **)&bRes ) )
+ return bRes;
+ }
+
+ // get the formal input
+ iForm = pVar2Form[bFR->index];
+
+ // get the nodes pointed to by the cube
+ bF0 = Extra_bddNodePointedByCube( dd, bF, pbCube0[iForm] );
+ bF1 = Extra_bddNodePointedByCube( dd, bF, pbCube1[iForm] );
+
+ // call recursively for these nodes
+ bRes0 = Extra_dsdRemap( dd, bF0, pCache, pVar2Form, pForm2Var, pbCube0, pbCube1 ); Cudd_Ref( bRes0 );
+ bRes1 = Extra_dsdRemap( dd, bF1, pCache, pVar2Form, pForm2Var, pbCube0, pbCube1 ); Cudd_Ref( bRes1 );
+
+ // derive the result using ITE
+ bRes = Cudd_bddIte( dd, dd->vars[ pForm2Var[iForm] ], bRes1, bRes0 ); Cudd_Ref( bRes );
+ Cudd_RecursiveDeref( dd, bRes0 );
+ Cudd_RecursiveDeref( dd, bRes1 );
+
+ // add to the hash table
+ if ( bFR->ref != 1 )
+ st_insert( pCache, (char *)bF, (char *)bRes );
+ Cudd_Deref( bRes );
+ return bRes;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Extra_bddNodePointedByCube( DdManager * dd, DdNode * bF, DdNode * bC )
+{
+ DdNode * bFR, * bCR;
+ DdNode * bF0, * bF1;
+ DdNode * bC0, * bC1;
+ int LevelF, LevelC;
+
+ assert( bC != b0 );
+ if ( bC == b1 )
+ return bF;
+
+// bRes = cuddCacheLookup2( dd, Extra_bddNodePointedByCube, bF, bC );
+// if ( bRes )
+// return bRes;
+ // there is no need for caching because this operation is very fast
+ // there will no gain reusing the results of this operations
+ // instead, it will flush CUDD cache of other useful entries
+
+
+ bFR = Cudd_Regular( bF );
+ bCR = Cudd_Regular( bC );
+ assert( !cuddIsConstant( bFR ) );
+
+ LevelF = dd->perm[bFR->index];
+ LevelC = dd->perm[bCR->index];
+
+ if ( LevelF <= LevelC )
+ {
+ if ( bFR != bF )
+ {
+ bF0 = Cudd_Not( cuddE(bFR) );
+ bF1 = Cudd_Not( cuddT(bFR) );
+ }
+ else
+ {
+ bF0 = cuddE(bFR);
+ bF1 = cuddT(bFR);
+ }
+ }
+ else
+ {
+ bF0 = bF1 = bF;
+ }
+
+ if ( LevelC <= LevelF )
+ {
+ if ( bCR != bC )
+ {
+ bC0 = Cudd_Not( cuddE(bCR) );
+ bC1 = Cudd_Not( cuddT(bCR) );
+ }
+ else
+ {
+ bC0 = cuddE(bCR);
+ bC1 = cuddT(bCR);
+ }
+ }
+ else
+ {
+ bC0 = bC1 = bC;
+ }
+
+ assert( bC0 == b0 || bC1 == b0 );
+ if ( bC0 == b0 )
+ return Extra_bddNodePointedByCube( dd, bF1, bC1 );
+ return Extra_bddNodePointedByCube( dd, bF0, bC0 );
+}
+
+#if 0
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * dsdTreeGetPrimeFunction( DdManager * dd, Dsd_Node_t * pNode, int fRemap )
+{
+ DdNode * bCof0, * bCof1, * bCube0, * bCube1, * bNewFunc, * bTemp;
+ int i;
+ int fAllBuffs = 1;
+ static int Permute[MAXINPUTS];
+
+ assert( pNode );
+ assert( !Dsd_IsComplement( pNode ) );
+ assert( pNode->Type == DT_PRIME );
+
+ // transform the function of this block to depend on inputs
+ // corresponding to the formal inputs
+
+ // first, substitute those inputs that have some blocks associated with them
+ // second, remap the inputs to the top of the manager (then, it is easy to output them)
+
+ // start the function
+ bNewFunc = pNode->G; Cudd_Ref( bNewFunc );
+ // go over all primary inputs
+ for ( i = 0; i < pNode->nDecs; i++ )
+ if ( pNode->pDecs[i]->Type != DT_BUF ) // remap only if it is not the buffer
+ {
+ bCube0 = Extra_bddFindOneCube( dd, Cudd_Not(pNode->pDecs[i]->G) ); Cudd_Ref( bCube0 );
+ bCof0 = Cudd_Cofactor( dd, bNewFunc, bCube0 ); Cudd_Ref( bCof0 );
+ Cudd_RecursiveDeref( dd, bCube0 );
+
+ bCube1 = Extra_bddFindOneCube( dd, pNode->pDecs[i]->G ); Cudd_Ref( bCube1 );
+ bCof1 = Cudd_Cofactor( dd, bNewFunc, bCube1 ); Cudd_Ref( bCof1 );
+ Cudd_RecursiveDeref( dd, bCube1 );
+
+ Cudd_RecursiveDeref( dd, bNewFunc );
+
+ // use the variable in the i-th level of the manager
+// bNewFunc = Cudd_bddIte( dd, dd->vars[dd->invperm[i]],bCof1,bCof0 ); Cudd_Ref( bNewFunc );
+ // use the first variale in the support of the component
+ bNewFunc = Cudd_bddIte( dd, dd->vars[pNode->pDecs[i]->S->index],bCof1,bCof0 ); Cudd_Ref( bNewFunc );
+ Cudd_RecursiveDeref( dd, bCof0 );
+ Cudd_RecursiveDeref( dd, bCof1 );
+ }
+
+ if ( fRemap )
+ {
+ // remap the function to the top of the manager
+ // remap the function to the first variables of the manager
+ for ( i = 0; i < pNode->nDecs; i++ )
+ // Permute[ pNode->pDecs[i]->S->index ] = dd->invperm[i];
+ Permute[ pNode->pDecs[i]->S->index ] = i;
+
+ bNewFunc = Cudd_bddPermute( dd, bTemp = bNewFunc, Permute ); Cudd_Ref( bNewFunc );
+ Cudd_RecursiveDeref( dd, bTemp );
+ }
+
+ Cudd_Deref( bNewFunc );
+ return bNewFunc;
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
diff --git a/src/bdd/dsd/dsdMan.c b/src/bdd/dsd/dsdMan.c
new file mode 100644
index 00000000..4529e75a
--- /dev/null
+++ b/src/bdd/dsd/dsdMan.c
@@ -0,0 +1,113 @@
+/**CFile****************************************************************
+
+ FileName [dsdMan.c]
+
+ PackageName [DSD: Disjoint-support decomposition package.]
+
+ Synopsis [APIs of the DSD manager.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 8.0. Started - September 22, 2003.]
+
+ Revision [$Id: dsdMan.c,v 1.0 2002/22/09 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "dsdInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// API OF DSD MANAGER ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Starts the DSD manager.]
+
+ Description [Takes the started BDD manager and the maximum support size
+ of the function to be DSD-decomposed. The manager should have at least as
+ many variables as there are variables in the support. The functions should
+ be expressed using the first nSuppSizeMax variables in the manager (these
+ may be ordered not necessarily on top of the manager).]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Dsd_Manager_t * Dsd_ManagerStart( DdManager * dd, int nSuppMax, int fVerbose )
+{
+ Dsd_Manager_t * dMan;
+ Dsd_Node_t * pNode;
+ int i;
+
+ assert( nSuppMax <= dd->size );
+
+ dMan = ALLOC( Dsd_Manager_t, 1 );
+ memset( dMan, 0, sizeof(Dsd_Manager_t) );
+ dMan->dd = dd;
+ dMan->nInputs = nSuppMax;
+ dMan->fVerbose = fVerbose;
+ dMan->nRoots = 0;
+ dMan->nRootsAlloc = 50;
+ dMan->pRoots = (Dsd_Node_t **) malloc( dMan->nRootsAlloc * sizeof(Dsd_Node_t *) );
+ dMan->pInputs = (Dsd_Node_t **) malloc( dMan->nInputs * sizeof(Dsd_Node_t *) );
+
+ // create the primary inputs and insert them into the table
+ dMan->Table = st_init_table(st_ptrcmp, st_ptrhash);
+ for ( i = 0; i < dMan->nInputs; i++ )
+ {
+ pNode = Dsd_TreeNodeCreate( DSD_NODE_BUF, 1, 0 );
+ pNode->G = dd->vars[i]; Cudd_Ref( pNode->G );
+ pNode->S = dd->vars[i]; Cudd_Ref( pNode->S );
+ st_insert( dMan->Table, (char*)dd->vars[i], (char*)pNode );
+ dMan->pInputs[i] = pNode;
+ }
+ pNode = Dsd_TreeNodeCreate( DSD_NODE_CONST1, 0, 0 );
+ pNode->G = b1; Cudd_Ref( pNode->G );
+ pNode->S = b1; Cudd_Ref( pNode->S );
+ st_insert( dMan->Table, (char*)b1, (char*)pNode );
+
+ Dsd_CheckCacheAllocate( 5000 );
+ return dMan;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Stops the DSD manager.]
+
+ Description [Stopping the DSD manager automatically derefereces and
+ deallocates all the DSD nodes that were created during the life time
+ of the DSD manager. As a result, the user does not need to deref or
+ deallocate any DSD nodes or trees that are derived and placed in
+ the manager while it exists.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_ManagerStop( Dsd_Manager_t * dMan )
+{
+ st_generator * gen;
+ Dsd_Node_t * pNode;
+ DdNode * bFunc;
+ // delete the nodes
+ st_foreach_item( dMan->Table, gen, (char**)&bFunc, (char**)&pNode )
+ Dsd_TreeNodeDelete( dMan->dd, Dsd_Regular(pNode) );
+ st_free_table(dMan->Table);
+ free( dMan->pInputs );
+ free( dMan->pRoots );
+ free( dMan );
+ Dsd_CheckCacheDeallocate();
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
diff --git a/src/bdd/dsd/dsdProc.c b/src/bdd/dsd/dsdProc.c
new file mode 100644
index 00000000..38cdc2b8
--- /dev/null
+++ b/src/bdd/dsd/dsdProc.c
@@ -0,0 +1,1607 @@
+/**CFile****************************************************************
+
+ FileName [dsdProc.c]
+
+ PackageName [DSD: Disjoint-support decomposition package.]
+
+ Synopsis [The core procedures of the package.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 8.0. Started - September 22, 2003.]
+
+ Revision [$Id: dsdProc.c,v 1.0 2002/22/09 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "dsdInt.h"
+
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// the most important procedures
+void dsdKernelDecompose( Dsd_Manager_t * pDsdMan, DdNode ** pbFuncs, int nFuncs );
+static Dsd_Node_t * dsdKernelDecompose_rec( Dsd_Manager_t * pDsdMan, DdNode * F );
+
+// additional procedures
+static Dsd_Node_t * dsdKernelFindContainingComponent( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pWhere, DdNode * Var, int * fPolarity );
+static int dsdKernelFindCommonComponents( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pL, Dsd_Node_t * pH, Dsd_Node_t *** pCommon, Dsd_Node_t ** pLastDiffL, Dsd_Node_t ** pLastDiffH );
+static void dsdKernelComputeSumOfComponents( Dsd_Manager_t * pDsdMan, Dsd_Node_t ** pCommon, int nCommon, DdNode ** pCompF, DdNode ** pCompS, int fExor );
+static int dsdKernelCheckContainment( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pL, Dsd_Node_t * pH, Dsd_Node_t ** pLarge, Dsd_Node_t ** pSmall );
+
+// list copying
+static void dsdKernelCopyListPlusOne( Dsd_Node_t * p, Dsd_Node_t * First, Dsd_Node_t ** ppList, int nListSize );
+static void dsdKernelCopyListPlusOneMinusOne( Dsd_Node_t * p, Dsd_Node_t * First, Dsd_Node_t ** ppList, int nListSize, int Skipped );
+
+// debugging procedures
+static int dsdKernelVerifyDecomposition( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pDE );
+
+////////////////////////////////////////////////////////////////////////
+/// STATIC VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+// the counter of marks
+static int s_Mark;
+
+// debugging flag
+static int s_Show = 0;
+// temporary var used for debugging
+static int Depth = 0;
+
+static int s_Loops1;
+static int s_Loops2;
+static int s_Loops3;
+static int s_Pivot;
+static int s_PivotNo;
+static int s_Common;
+static int s_CommonNo;
+
+static int s_Case4Calls;
+static int s_Case4CallsSpecial;
+
+static int s_Case5;
+static int s_Loops2Useless;
+
+
+static int s_DecNodesTotal;
+static int s_DecNodesUsed;
+
+// statistical variables
+static int s_nDecBlocks;
+static int s_nLiterals;
+static int s_nExorGates;
+static int s_nReusedBlocks;
+static int s_nCascades;
+static float s_nArea;
+static float s_MaxDelay;
+static long s_Time;
+static int s_nInvertors;
+static int s_nPrimeBlocks;
+
+static int HashSuccess = 0;
+static int HashFailure = 0;
+
+static int s_CacheEntries;
+
+
+////////////////////////////////////////////////////////////////////////
+/// DECOMPOSITION FUNCTIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Performs DSD for the array of functions represented by BDDs.]
+
+ Description [This function takes the DSD manager, which should be
+ previously allocated by the call to Dsd_ManagerStart(). The resulting
+ DSD tree is stored in the DSD manager (pDsdMan->pRoots, pDsdMan->nRoots).
+ Access to the tree is through the APIs of the manager. The resulting
+ tree is a shared DSD DAG for the functions given in the array. For one
+ function the resulting DAG is always a tree. The root node pointers can
+ be complemented, as discussed in the literature referred to in "dsd.h".
+ This procedure can be called repeatedly for different functions. There is
+ no need to remove the decomposition tree after it is returned, because
+ the next call to the DSD manager will "recycle" the tree. The user should
+ not modify or dereference any data associated with the nodes of the
+ DSD trees (the user can only change the contents of a temporary
+ mark associated with each node by the calling to Dsd_NodeSetMark()).
+ All the decomposition trees and intermediate nodes will be removed when
+ the DSD manager is deallocated at the end by calling Dsd_ManagerStop().]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_Decompose( Dsd_Manager_t * pDsdMan, DdNode ** pbFuncs, int nFuncs )
+{
+ DdManager * dd = pDsdMan->dd;
+ int i;
+ long clk;
+ Dsd_Node_t * pTemp;
+ int SumMaxGateSize = 0;
+ int nDecOutputs = 0;
+ int nCBFOutputs = 0;
+/*
+s_Loops1 = 0;
+s_Loops2 = 0;
+s_Loops3 = 0;
+s_Case4Calls = 0;
+s_Case4CallsSpecial = 0;
+s_Case5 = 0;
+s_Loops2Useless = 0;
+*/
+ // resize the number of roots in the manager
+ if ( pDsdMan->nRootsAlloc < nFuncs )
+ {
+ if ( pDsdMan->nRootsAlloc > 0 )
+ free( pDsdMan->pRoots );
+ pDsdMan->nRootsAlloc = nFuncs;
+ pDsdMan->pRoots = (Dsd_Node_t **) malloc( pDsdMan->nRootsAlloc * sizeof(Dsd_Node_t *) );
+ }
+
+ if ( pDsdMan->fVerbose )
+ printf( "\nDecomposability statistics for individual outputs:\n" );
+
+ // set the counter of decomposition nodes
+ s_nDecBlocks = 0;
+
+ // perform decomposition for all outputs
+ clk = clock();
+ pDsdMan->nRoots = 0;
+ s_nCascades = 0;
+ for ( i = 0; i < nFuncs; i++ )
+ {
+ int nLiteralsPrev;
+ int nDecBlocksPrev;
+ int nExorGatesPrev;
+ int nReusedBlocksPres;
+ int nCascades;
+ int MaxBlock;
+ int nPrimeBlocks;
+ long clk;
+
+ clk = clock();
+ nLiteralsPrev = s_nLiterals;
+ nDecBlocksPrev = s_nDecBlocks;
+ nExorGatesPrev = s_nExorGates;
+ nReusedBlocksPres = s_nReusedBlocks;
+ nPrimeBlocks = s_nPrimeBlocks;
+
+ pDsdMan->pRoots[ pDsdMan->nRoots++ ] = dsdKernelDecompose_rec( pDsdMan, pbFuncs[i] );
+
+ Dsd_TreeNodeGetInfoOne( pDsdMan->pRoots[i], &nCascades, &MaxBlock );
+ s_nCascades = ddMax( s_nCascades, nCascades );
+ pTemp = Dsd_Regular(pDsdMan->pRoots[i]);
+ if ( pTemp->Type != DSD_NODE_PRIME || pTemp->nDecs != Extra_bddSuppSize(dd,pTemp->S) )
+ nDecOutputs++;
+ if ( MaxBlock < 3 )
+ nCBFOutputs++;
+ SumMaxGateSize += MaxBlock;
+
+ if ( pDsdMan->fVerbose )
+ {
+ printf("#%02d: ", i );
+ printf("Ins=%2d. ", Cudd_SupportSize(dd,pbFuncs[i]) );
+ printf("Gts=%3d. ", Dsd_TreeCountNonTerminalNodesOne( pDsdMan->pRoots[i] ) );
+ printf("Pri=%3d. ", Dsd_TreeCountPrimeNodesOne( pDsdMan->pRoots[i] ) );
+ printf("Max=%3d. ", MaxBlock );
+ printf("Reuse=%2d. ", s_nReusedBlocks-nReusedBlocksPres );
+ printf("Csc=%2d. ", nCascades );
+ printf("T= %.2f s. ", (float)(clock()-clk)/(float)(CLOCKS_PER_SEC) ) ;
+ printf("Bdd=%2d. ", Cudd_DagSize(pbFuncs[i]) );
+ printf("\n");
+ fflush( stdout );
+ }
+ }
+ assert( pDsdMan->nRoots == nFuncs );
+
+ if ( pDsdMan->fVerbose )
+ {
+ printf( "\n" );
+ printf( "The cumulative decomposability statistics:\n" );
+ printf( " Total outputs = %5d\n", nFuncs );
+ printf( " Decomposable outputs = %5d\n", nDecOutputs );
+ printf( " Completely decomposable outputs = %5d\n", nCBFOutputs );
+ printf( " The sum of max gate sizes = %5d\n", SumMaxGateSize );
+ printf( " Shared BDD size = %5d\n", Cudd_SharingSize( pbFuncs, nFuncs ) );
+ printf( " Decomposition entries = %5d\n", st_count( pDsdMan->Table ) );
+ printf( " Pure decomposition time = %.2f sec\n", (float)(clock() - clk)/(float)(CLOCKS_PER_SEC) );
+ }
+/*
+ printf( "s_Loops1 = %d.\n", s_Loops1 );
+ printf( "s_Loops2 = %d.\n", s_Loops2 );
+ printf( "s_Loops3 = %d.\n", s_Loops3 );
+ printf( "s_Case4Calls = %d.\n", s_Case4Calls );
+ printf( "s_Case4CallsSpecial = %d.\n", s_Case4CallsSpecial );
+ printf( "s_Case5 = %d.\n", s_Case5 );
+ printf( "s_Loops2Useless = %d.\n", s_Loops2Useless );
+*/
+}
+
+/**Function*************************************************************
+
+ Synopsis [The main function of this module. Recursive implementation of DSD.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Dsd_Node_t * dsdKernelDecompose_rec( Dsd_Manager_t * pDsdMan, DdNode * bFunc0 )
+{
+ DdManager * dd = pDsdMan->dd;
+ DdNode * bLow;
+ DdNode * bLowR;
+ DdNode * bHigh;
+
+ int VarInt;
+ DdNode * bVarCur;
+ Dsd_Node_t * pVarCurDE;
+ // works only if var indices start from 0!!!
+ DdNode * bSuppNew = NULL, * bTemp;
+
+ int fContained;
+ int nSuppLH;
+ int nSuppL;
+ int nSuppH;
+
+
+
+ // various decomposition nodes
+ Dsd_Node_t * pThis, * pL, * pH, * pLR, * pHR;
+
+ Dsd_Node_t * pSmallR, * pLargeR;
+ Dsd_Node_t * pTableEntry;
+
+
+ // treat the complemented case
+ DdNode * bF = Cudd_Regular(bFunc0);
+ int fCompF = (int)(bF != bFunc0);
+
+ // check cache
+ if ( st_lookup( pDsdMan->Table, (char*)bF, (char**)&pTableEntry ) )
+ { // the entry is present
+ HashSuccess++;
+ return Dsd_NotCond( pTableEntry, fCompF );
+ }
+ HashFailure++;
+ Depth++;
+
+ // proceed to consider "four cases"
+ //////////////////////////////////////////////////////////////////////
+ // TERMINAL CASES - CASES 1 and 2
+ //////////////////////////////////////////////////////////////////////
+ bLow = cuddE(bF);
+ bLowR = Cudd_Regular(bLow);
+ bHigh = cuddT(bF);
+ VarInt = bF->index;
+ bVarCur = dd->vars[VarInt];
+ pVarCurDE = pDsdMan->pInputs[VarInt];
+ // works only if var indices start from 0!!!
+ bSuppNew = NULL;
+
+ if ( bLowR->index == CUDD_CONST_INDEX || bHigh->index == CUDD_CONST_INDEX )
+ { // one of the cofactors in the constant
+ if ( bHigh == b1 ) // bHigh cannot be equal to b0, because then it will be complemented
+ if ( bLow == b0 ) // bLow cannot be equal to b1, because then the node will have bLow == bHigh
+ /////////////////////////////////////////////////////////////////
+ // bLow == 0, bHigh == 1, F = x'&0 + x&1 = x
+ /////////////////////////////////////////////////////////////////
+ { // create the elementary variable node
+ assert(0); // should be already in the hash table
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_BUF, 1, s_nDecBlocks++ );
+ pThis->pDecs[0] = NULL;
+ }
+ else // if ( bLow != constant )
+ /////////////////////////////////////////////////////////////////
+ // bLow != const, bHigh == 1, F = x'&bLow + x&1 = bLow + x --- DSD_NODE_OR(x,bLow)
+ /////////////////////////////////////////////////////////////////
+ {
+ pL = dsdKernelDecompose_rec( pDsdMan, bLow );
+ pLR = Dsd_Regular( pL );
+ bSuppNew = Cudd_bddAnd( dd, bVarCur, pLR->S ); Cudd_Ref(bSuppNew);
+ if ( pLR->Type == DSD_NODE_OR && pL == pLR ) // OR and no complement
+ { // add to the components
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, pL->nDecs+1, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOne( pThis, pVarCurDE, pL->pDecs, pL->nDecs );
+ }
+ else // all other cases
+ { // create a new 2-input OR-gate
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, 2, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOne( pThis, pVarCurDE, &pL, 1 );
+ }
+ }
+ else // if ( bHigh != const ) // meaning that bLow should be a constant
+ {
+ pH = dsdKernelDecompose_rec( pDsdMan, bHigh );
+ pHR = Dsd_Regular( pH );
+ bSuppNew = Cudd_bddAnd( dd, bVarCur, pHR->S ); Cudd_Ref(bSuppNew);
+ if ( bLow == b0 )
+ /////////////////////////////////////////////////////////////////
+ // Low == 0, High != 1, F = x'&0+x&High = (x'+High')'--- NOR(x',High')
+ /////////////////////////////////////////////////////////////////
+ if ( pHR->Type == DSD_NODE_OR && pH != pHR ) // DSD_NODE_OR and complement
+ { // add to the components
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, pHR->nDecs+1, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOne( pThis, Dsd_Not(pVarCurDE), pHR->pDecs, pHR->nDecs );
+ pThis = Dsd_Not(pThis);
+ }
+ else // all other cases
+ { // create a new 2-input NOR gate
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, 2, s_nDecBlocks++ );
+ pH = Dsd_Not(pH);
+ dsdKernelCopyListPlusOne( pThis, Dsd_Not(pVarCurDE), &pH, 1 );
+ pThis = Dsd_Not(pThis);
+ }
+ else // if ( bLow == b1 )
+ /////////////////////////////////////////////////////////////////
+ // Low == 1, High != 1, F = x'&1 + x&High = x' + High --- DSD_NODE_OR(x',High)
+ /////////////////////////////////////////////////////////////////
+ if ( pHR->Type == DSD_NODE_OR && pH == pHR ) // OR and no complement
+ { // add to the components
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, pH->nDecs+1, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOne( pThis, Dsd_Not(pVarCurDE), pH->pDecs, pH->nDecs );
+ }
+ else // all other cases
+ { // create a new 2-input OR-gate
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, 2, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOne( pThis, Dsd_Not(pVarCurDE), &pH, 1 );
+ }
+ }
+ goto EXIT;
+ }
+ // else if ( bLow != const && bHigh != const )
+
+ // the case of equal cofactors (up to complementation)
+ if ( bLowR == bHigh )
+ /////////////////////////////////////////////////////////////////
+ // Low == G, High == G', F = x'&G + x&G' = (x(+)G) --- EXOR(x,Low)
+ /////////////////////////////////////////////////////////////////
+ {
+ pL = dsdKernelDecompose_rec( pDsdMan, bLow );
+ pLR = Dsd_Regular( pL );
+ bSuppNew = Cudd_bddAnd( dd, bVarCur, pLR->S ); Cudd_Ref(bSuppNew);
+ if ( pLR->Type == DSD_NODE_EXOR ) // complemented or not - does not matter!
+ { // add to the components
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_EXOR, pLR->nDecs+1, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOne( pThis, pVarCurDE, pLR->pDecs, pLR->nDecs );
+ if ( pL != pLR )
+ pThis = Dsd_Not( pThis );
+ }
+ else // all other cases
+ { // create a new 2-input EXOR-gate
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_EXOR, 2, s_nDecBlocks++ );
+ if ( pL != pLR ) // complemented
+ {
+ dsdKernelCopyListPlusOne( pThis, pVarCurDE, &pLR, 1 );
+ pThis = Dsd_Not( pThis );
+ }
+ else // non-complemented
+ dsdKernelCopyListPlusOne( pThis, pVarCurDE, &pL, 1 );
+ }
+ goto EXIT;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // solve subproblems
+ //////////////////////////////////////////////////////////////////////
+ pL = dsdKernelDecompose_rec( pDsdMan, bLow );
+ pH = dsdKernelDecompose_rec( pDsdMan, bHigh );
+ pLR = Dsd_Regular( pL );
+ pHR = Dsd_Regular( pH );
+
+ assert( pLR->Type == DSD_NODE_BUF || pLR->Type == DSD_NODE_OR || pLR->Type == DSD_NODE_EXOR || pLR->Type == DSD_NODE_PRIME );
+ assert( pHR->Type == DSD_NODE_BUF || pHR->Type == DSD_NODE_OR || pHR->Type == DSD_NODE_EXOR || pHR->Type == DSD_NODE_PRIME );
+
+/*
+if ( Depth == 1 )
+{
+// PRK(bLow,pDecTreeTotal->nInputs);
+// PRK(bHigh,pDecTreeTotal->nInputs);
+if ( s_Show )
+{
+ PRD( pL );
+ PRD( pH );
+}
+}
+*/
+ // compute the new support
+ bTemp = Cudd_bddAnd( dd, pLR->S, pHR->S ); Cudd_Ref( bTemp );
+ nSuppL = Extra_bddSuppSize( dd, pLR->S );
+ nSuppH = Extra_bddSuppSize( dd, pHR->S );
+ nSuppLH = Extra_bddSuppSize( dd, bTemp );
+ bSuppNew = Cudd_bddAnd( dd, bTemp, bVarCur ); Cudd_Ref( bSuppNew );
+ Cudd_RecursiveDeref( dd, bTemp );
+
+
+ // several possibilities are possible
+ // (1) support of one component contains another
+ // (2) none of the supports is contained in another
+ fContained = dsdKernelCheckContainment( pDsdMan, pLR, pHR, &pLargeR, &pSmallR );
+
+ //////////////////////////////////////////////////////////////////////
+ // CASE 3.b One of the cofactors in a constant (OR and EXOR)
+ //////////////////////////////////////////////////////////////////////
+ // the support of the larger component should contain the support of the smaller
+ // it is possible to have PRIME function in this role
+ // for example: F = ITE( a+b, c(+)d, e+f ), F0 = ITE( b, c(+)d, e+f ), F1 = c(+)d
+ if ( fContained )
+ {
+ Dsd_Node_t * pSmall, * pLarge;
+ int c, iCompLarge; // the number of the component is Large is equal to the whole of Small
+ int fLowIsLarge;
+
+ DdNode * bFTemp; // the changed input function
+ Dsd_Node_t * pDETemp, * pDENew;
+
+ Dsd_Node_t * pComp = NULL;
+ int nComp;
+
+ if ( pSmallR == pLR )
+ { // Low is Small => High is Large
+ pSmall = pL;
+ pLarge = pH;
+ fLowIsLarge = 0;
+ }
+ else
+ { // vice versa
+ pSmall = pH;
+ pLarge = pL;
+ fLowIsLarge = 1;
+ }
+
+ // treat the situation when the larger is PRIME
+ if ( pLargeR->Type == DSD_NODE_PRIME ) //&& pLargeR->nDecs != pSmallR->nDecs )
+ {
+ // QUESTION: Is it possible for pLargeR->nDecs > 3
+ // and pSmall contained as one of input in pLarge?
+ // Yes, for example F = a'c + a & MUX(b,c',d) = a'c + abc' + ab'd is non-decomposable
+ // Consider the function H(a->xy) = F( xy, b, c, d )
+ // H0 = H(x=0) = F(0,b,c,d) = c
+ // H1 = F(x=1) = F(y,b,c,d) - non-decomposable
+ //
+ // QUESTION: Is it possible that pLarge is PRIME(3) and pSmall is OR(2),
+ // which is not contained in PRIME as one input?
+ // Yes, for example F = abcd + b'c'd' + a'c'd' = PRIME(ab, c, d)
+ // F(a=0) = c'd' = NOT(OR(a,d)) F(a=1) = bcd + b'c'd' = PRIME(b,c,d)
+ // To find decomposition, we have to prove that F(a=1)|b=0 = F(a=0)
+
+ // Is it possible that (pLargeR->nDecs == pSmallR->nDecs) and yet this case holds?
+ // Yes, consider the function such that F(a=0) = PRIME(a,b+c,d,e) and F(a=1) = OR(b,c,d,e)
+ // They have the same number of inputs and it is possible that they will be the cofactors
+ // as discribed in the previous example.
+
+ // find the component, which when substituted for 0 or 1, produces the desired result
+ int g, fFoundComp; // {0,1} depending on whether setting cofactor to 0 or 1 worked out
+
+ DdNode * bLarge, * bSmall;
+ if ( fLowIsLarge )
+ {
+ bLarge = bLow;
+ bSmall = bHigh;
+ }
+ else
+ {
+ bLarge = bHigh;
+ bSmall = bLow;
+ }
+
+ for ( g = 0; g < pLargeR->nDecs; g++ )
+// if ( g != c )
+ {
+ pDETemp = pLargeR->pDecs[g]; // cannot be complemented
+ if ( Dsd_CheckRootFunctionIdentity( dd, bLarge, bSmall, pDETemp->G, b1 ) )
+ {
+ fFoundComp = 1;
+ break;
+ }
+
+ s_Loops1++;
+
+ if ( Dsd_CheckRootFunctionIdentity( dd, bLarge, bSmall, Cudd_Not(pDETemp->G), b1 ) )
+ {
+ fFoundComp = 0;
+ break;
+ }
+
+ s_Loops1++;
+ }
+
+ if ( g != pLargeR->nDecs )
+ { // decomposition is found
+ if ( fFoundComp )
+ if ( fLowIsLarge )
+ bFTemp = Cudd_bddOr( dd, bVarCur, pLargeR->pDecs[g]->G );
+ else
+ bFTemp = Cudd_bddOr( dd, Cudd_Not(bVarCur), pLargeR->pDecs[g]->G );
+ else
+ if ( fLowIsLarge )
+ bFTemp = Cudd_bddAnd( dd, Cudd_Not(bVarCur), pLargeR->pDecs[g]->G );
+ else
+ bFTemp = Cudd_bddAnd( dd, bVarCur, pLargeR->pDecs[g]->G );
+ Cudd_Ref( bFTemp );
+
+ pDENew = dsdKernelDecompose_rec( pDsdMan, bFTemp );
+ pDENew = Dsd_Regular( pDENew );
+ Cudd_RecursiveDeref( dd, bFTemp );
+
+ // get the new gate
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_PRIME, pLargeR->nDecs, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOneMinusOne( pThis, pDENew, pLargeR->pDecs, pLargeR->nDecs, g );
+ goto EXIT;
+ }
+ }
+
+ // try to find one component in the pLarger that is equal to the whole of pSmaller
+ for ( c = 0; c < pLargeR->nDecs; c++ )
+ if ( pLargeR->pDecs[c] == pSmall || pLargeR->pDecs[c] == Dsd_Not(pSmall) )
+ {
+ iCompLarge = c;
+ break;
+ }
+
+ // assign the equal component
+ if ( c != pLargeR->nDecs ) // the decomposition is possible!
+ {
+ pComp = pLargeR->pDecs[iCompLarge];
+ nComp = 1;
+ }
+ else // the decomposition is still possible
+ { // for example F = OR(ab,c,d), F(a=0) = OR(c,d), F(a=1) = OR(b,c,d)
+ // supp(F0) is contained in supp(F1), Polarity(F(a=0)) == Polarity(F(a=1))
+
+ // try to find a group of common components
+ if ( pLargeR->Type == pSmallR->Type &&
+ (pLargeR->Type == DSD_NODE_EXOR || pSmallR->Type == DSD_NODE_OR&& ((pLarge==pLargeR) == (pSmall==pSmallR))) )
+ {
+ Dsd_Node_t ** pCommon, * pLastDiffL = NULL, * pLastDiffH = NULL;
+ int nCommon = dsdKernelFindCommonComponents( pDsdMan, pLargeR, pSmallR, &pCommon, &pLastDiffL, &pLastDiffH );
+ // if all the components of pSmall are contained in pLarge,
+ // then the decomposition exists
+ if ( nCommon == pSmallR->nDecs )
+ {
+ pComp = pSmallR;
+ nComp = pSmallR->nDecs;
+ }
+ }
+ }
+
+ if ( pComp ) // the decomposition is possible!
+ {
+// Dsd_Node_t * pComp = pLargeR->pDecs[iCompLarge];
+ Dsd_Node_t * pCompR = Dsd_Regular( pComp );
+ int fComp1 = (int)( pLarge != pLargeR );
+ int fComp2 = (int)( pComp != pCompR );
+ int fComp3 = (int)( pSmall != pSmallR );
+
+ DdNode * bFuncComp; // the function of the given component
+ DdNode * bFuncNew; // the function of the input component
+
+ if ( pLargeR->Type == DSD_NODE_OR ) // Figure 4 of Matsunaga's paper
+ {
+ // the decomposition exists only if the polarity assignment
+ // along the paths is the same
+ if ( (fComp1 ^ fComp2) == fComp3 )
+ { // decomposition exists = consider 4 cases
+ // consideration of cases leads to the following conclusion
+ // fComp1 gives the polarity of the resulting DSD_NODE_OR gate
+ // fComp2 gives the polarity of the common component feeding into the DSD_NODE_OR gate
+ //
+ // | fComp1 pL/ |pS
+ // <> .........<=>....... <> |
+ // | / |
+ // [OR] [OR] | fComp3
+ // / \ fComp2 / | \ |
+ // <> <> .......<=>... /..|..<> |
+ // / \ / | \|
+ // [OR] [C] S1 S2 C
+ // / \
+ // <> \
+ // / \
+ // [OR] [x]
+ // / \
+ // S1 S2
+ //
+
+
+ // at this point we have the function F (bFTemp) and the common component C (bFuncComp)
+ // to get the remainder, R, in the relationship F = R + C, supp(R) & supp(C) = 0
+ // we compute the following R = Exist( F - C, supp(C) )
+ bFTemp = (fComp1)? Cudd_Not( bF ): bF;
+ bFuncComp = (fComp2)? Cudd_Not( pCompR->G ): pCompR->G;
+ bFuncNew = Cudd_bddAndAbstract( dd, bFTemp, Cudd_Not(bFuncComp), pCompR->S ); Cudd_Ref( bFuncNew );
+
+ // there is no need to copy the dec entry list first, because pComp is a component
+ // which will not be destroyed by the recursive call to decomposition
+ pDENew = dsdKernelDecompose_rec( pDsdMan, bFuncNew );
+ assert( Dsd_IsComplement(pDENew) ); // follows from the consideration of cases
+ Cudd_RecursiveDeref( dd, bFuncNew );
+
+ // get the new gate
+ if ( nComp == 1 )
+ {
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, 2, s_nDecBlocks++ );
+ pThis->pDecs[0] = pDENew;
+ pThis->pDecs[1] = pComp; // takes the complement
+ }
+ else
+ { // pComp is not complemented
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, nComp+1, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOne( pThis, pDENew, pComp->pDecs, nComp );
+ }
+
+ if ( fComp1 )
+ pThis = Dsd_Not( pThis );
+ goto EXIT;
+ }
+ }
+ else if ( pLargeR->Type == DSD_NODE_EXOR ) // Figure 5 of Matsunaga's paper (with correction)
+ { // decomposition always exists = consider 4 cases
+
+ // consideration of cases leads to the following conclusion
+ // fComp3 gives the COMPLEMENT of the polarity of the resulting EXOR gate
+ // (if fComp3 is 0, the EXOR gate is complemented, and vice versa)
+ //
+ // | fComp1 pL/ |pS
+ // <> .........<=>....... /....| fComp3
+ // | / |
+ // [XOR] [XOR] |
+ // / \ fComp2==0 / | \ |
+ // / \ / | \ |
+ // / \ / | \|
+ // [OR] [C] S1 S2 C
+ // / \
+ // <> \
+ // / \
+ // [XOR] [x]
+ // / \
+ // S1 S2
+ //
+
+ assert( fComp2 == 0 );
+ // find the functionality of the lower gates
+ bFTemp = (fComp3)? bF: Cudd_Not( bF );
+ bFuncNew = Cudd_bddXor( dd, bFTemp, pComp->G ); Cudd_Ref( bFuncNew );
+
+ pDENew = dsdKernelDecompose_rec( pDsdMan, bFuncNew );
+ assert( !Dsd_IsComplement(pDENew) ); // follows from the consideration of cases
+ Cudd_RecursiveDeref( dd, bFuncNew );
+
+ // get the new gate
+ if ( nComp == 1 )
+ {
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_EXOR, 2, s_nDecBlocks++ );
+ pThis->pDecs[0] = pDENew;
+ pThis->pDecs[1] = pComp;
+ }
+ else
+ { // pComp is not complemented
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_EXOR, nComp+1, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOne( pThis, pDENew, pComp->pDecs, nComp );
+ }
+
+ if ( !fComp3 )
+ pThis = Dsd_Not( pThis );
+ goto EXIT;
+ }
+ }
+ }
+
+ // this case was added to fix the trivial bug found November 4, 2002 in Japan
+ // by running the example provided by T. Sasao
+ if ( nSuppLH == nSuppL + nSuppH ) // the supports of the components are disjoint
+ {
+ // create a new component of the type ITE( a, pH, pL )
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_PRIME, 3, s_nDecBlocks++ );
+ if ( dd->perm[pLR->S->index] < dd->perm[pHR->S->index] ) // pLR is higher in the varible order
+ {
+ pThis->pDecs[1] = pLR;
+ pThis->pDecs[2] = pHR;
+ }
+ else // pHR is higher in the varible order
+ {
+ pThis->pDecs[1] = pHR;
+ pThis->pDecs[2] = pLR;
+ }
+ // add the first component
+ pThis->pDecs[0] = pVarCurDE;
+ goto EXIT;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////
+ // CASE 3.a Neither of the cofactors is a constant (OR, EXOR, PRIME)
+ //////////////////////////////////////////////////////////////////////
+ // the component types are identical
+ // and if they are OR, they are either both complemented or both not complemented
+ // and if they are PRIME, their dec numbers should be the same
+ if ( pLR->Type == pHR->Type &&
+ pLR->Type != DSD_NODE_BUF &&
+ (pLR->Type != DSD_NODE_OR || ( pL == pLR && pH == pHR || pL != pLR && pH != pHR ) ) &&
+ (pLR->Type != DSD_NODE_PRIME || pLR->nDecs == pHR->nDecs) )
+ {
+ // array to store common comps in pL and pH
+ Dsd_Node_t ** pCommon, * pLastDiffL = NULL, * pLastDiffH = NULL;
+ int nCommon = dsdKernelFindCommonComponents( pDsdMan, pLR, pHR, &pCommon, &pLastDiffL, &pLastDiffH );
+ if ( nCommon )
+ {
+ if ( pLR->Type == DSD_NODE_OR ) // Figure 2 of Matsunaga's paper
+ { // at this point we have the function F and the group of common components C
+ // to get the remainder, R, in the relationship F = R + C, supp(R) & supp(C) = 0
+ // we compute the following R = Exist( F - C, supp(C) )
+
+ // compute the sum total of the common components and the union of their supports
+ DdNode * bCommF, * bCommS, * bFTemp, * bFuncNew;
+ Dsd_Node_t * pDENew;
+
+ dsdKernelComputeSumOfComponents( pDsdMan, pCommon, nCommon, &bCommF, &bCommS, 0 );
+ Cudd_Ref( bCommF );
+ Cudd_Ref( bCommS );
+ bFTemp = ( pL != pLR )? Cudd_Not(bF): bF;
+
+ bFuncNew = Cudd_bddAndAbstract( dd, bFTemp, Cudd_Not(bCommF), bCommS ); Cudd_Ref( bFuncNew );
+ Cudd_RecursiveDeref( dd, bCommF );
+ Cudd_RecursiveDeref( dd, bCommS );
+
+ // get the new gate
+
+ // copy the components first, then call the decomposition
+ // because decomposition will distroy the list used for copying
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, nCommon + 1, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOne( pThis, NULL, pCommon, nCommon );
+
+ // call the decomposition recursively
+ pDENew = dsdKernelDecompose_rec( pDsdMan, bFuncNew );
+// assert( !Dsd_IsComplement(pDENew) ); // follows from the consideration of cases
+ Cudd_RecursiveDeref( dd, bFuncNew );
+
+ // add the first component
+ pThis->pDecs[0] = pDENew;
+
+ if ( pL != pLR )
+ pThis = Dsd_Not( pThis );
+ goto EXIT;
+ }
+ else
+ if ( pLR->Type == DSD_NODE_EXOR ) // Figure 3 of Matsunaga's paper
+ {
+ // compute the sum total of the common components and the union of their supports
+ DdNode * bCommF, * bFuncNew;
+ Dsd_Node_t * pDENew;
+ int fCompExor;
+
+ dsdKernelComputeSumOfComponents( pDsdMan, pCommon, nCommon, &bCommF, NULL, 1 );
+ Cudd_Ref( bCommF );
+
+ bFuncNew = Cudd_bddXor( dd, bF, bCommF ); Cudd_Ref( bFuncNew );
+ Cudd_RecursiveDeref( dd, bCommF );
+
+ // get the new gate
+
+ // copy the components first, then call the decomposition
+ // because decomposition will distroy the list used for copying
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_EXOR, nCommon + 1, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOne( pThis, NULL, pCommon, nCommon );
+
+ // call the decomposition recursively
+ pDENew = dsdKernelDecompose_rec( pDsdMan, bFuncNew );
+ Cudd_RecursiveDeref( dd, bFuncNew );
+
+ // remember the fact that it was complemented
+ fCompExor = Dsd_IsComplement(pDENew);
+ pDENew = Dsd_Regular(pDENew);
+
+ // add the first component
+ pThis->pDecs[0] = pDENew;
+
+
+ if ( fCompExor )
+ pThis = Dsd_Not( pThis );
+ goto EXIT;
+ }
+ else
+ if ( pLR->Type == DSD_NODE_PRIME && (nCommon == pLR->nDecs-1 || nCommon == pLR->nDecs) )
+ {
+ // for example the function F(a,b,c,d) = ITE(b,c,a(+)d) produces
+ // two cofactors F(a=0) = PRIME(b,c,d) and F(a=1) = PRIME(b,c,d)
+ // with exactly the same list of common components
+
+ Dsd_Node_t * pDENew;
+ DdNode * bFuncNew;
+ int fCompComp = 0; // this flag can be {0,1,2}
+ // if it is 0 there is no identity
+ // if it is 1/2, the cofactored functions are equal in the direct/complemented polarity
+
+ if ( nCommon == pLR->nDecs )
+ { // all the components are the same
+ // find the formal input, in which pLow and pHigh differ (if such input exists)
+ int m;
+ Dsd_Node_t * pTempL, * pTempH;
+
+ s_Common++;
+ for ( m = 0; m < pLR->nDecs; m++ )
+ {
+ pTempL = pLR->pDecs[m]; // cannot be complemented
+ pTempH = pHR->pDecs[m]; // cannot be complemented
+
+ if ( Dsd_CheckRootFunctionIdentity( dd, bLow, bHigh, pTempL->G, Cudd_Not(pTempH->G) ) &&
+ Dsd_CheckRootFunctionIdentity( dd, bLow, bHigh, Cudd_Not(pTempL->G), pTempH->G ) )
+ {
+ pLastDiffL = pTempL;
+ pLastDiffH = pTempH;
+ assert( pLastDiffL == pLastDiffH );
+ fCompComp = 2;
+ break;
+ }
+
+ s_Loops2++;
+ s_Loops2++;
+/*
+ if ( s_Loops2 % 10000 == 0 )
+ {
+ int i;
+ for ( i = 0; i < pLR->nDecs; i++ )
+ printf( " %d(s=%d)", pLR->pDecs[i]->Type,
+ Extra_bddSuppSize(dd, pLR->pDecs[i]->S) );
+ printf( "\n" );
+ }
+*/
+
+ }
+// if ( pLR->nDecs == Extra_bddSuppSize(dd, pLR->S) )
+// s_Loops2Useless += pLR->nDecs * 2;
+
+ if ( fCompComp )
+ { // put the equal components into pCommon, so that they could be copied into the new dec entry
+ nCommon = 0;
+ for ( m = 0; m < pLR->nDecs; m++ )
+ if ( pLR->pDecs[m] != pLastDiffL )
+ pCommon[nCommon++] = pLR->pDecs[m];
+ assert( nCommon = pLR->nDecs-1 );
+ }
+ }
+ else
+ { // the differing components are known - check that they have compatible PRIME function
+
+ s_CommonNo++;
+
+ // find the numbers of different components
+ assert( pLastDiffL );
+ assert( pLastDiffH );
+ // also, they cannot be complemented, because the decomposition type is PRIME
+
+ if ( Dsd_CheckRootFunctionIdentity( dd, bLow, bHigh, Cudd_Not(pLastDiffL->G), Cudd_Not(pLastDiffH->G) ) &&
+ Dsd_CheckRootFunctionIdentity( dd, bLow, bHigh, pLastDiffL->G, pLastDiffH->G ) )
+ fCompComp = 1;
+ else if ( Dsd_CheckRootFunctionIdentity( dd, bLow, bHigh, pLastDiffL->G, Cudd_Not(pLastDiffH->G) ) &&
+ Dsd_CheckRootFunctionIdentity( dd, bLow, bHigh, Cudd_Not(pLastDiffL->G), pLastDiffH->G ) )
+ fCompComp = 2;
+
+ s_Loops3 += 4;
+ }
+
+ if ( fCompComp )
+ {
+ if ( fCompComp == 1 ) // it is true that bLow(G=0) == bHigh(H=0) && bLow(G=1) == bHigh(H=1)
+ bFuncNew = Cudd_bddIte( dd, bVarCur, pLastDiffH->G, pLastDiffL->G );
+ else // it is true that bLow(G=0) == bHigh(H=1) && bLow(G=1) == bHigh(H=0)
+ bFuncNew = Cudd_bddIte( dd, bVarCur, Cudd_Not(pLastDiffH->G), pLastDiffL->G );
+ Cudd_Ref( bFuncNew );
+
+ // get the new gate
+
+ // copy the components first, then call the decomposition
+ // because decomposition will distroy the list used for copying
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_PRIME, pLR->nDecs, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOne( pThis, NULL, pCommon, nCommon );
+
+ // create a new component
+ pDENew = dsdKernelDecompose_rec( pDsdMan, bFuncNew );
+ Cudd_RecursiveDeref( dd, bFuncNew );
+ // the BDD of the argument function in PRIME decomposition, should be regular
+ pDENew = Dsd_Regular(pDENew);
+
+ // add the first component
+ pThis->pDecs[0] = pDENew;
+ goto EXIT;
+ }
+ } // end of PRIME type
+ } // end of existing common components
+ } // end of CASE 3.a
+
+// if ( Depth != 1)
+// {
+
+//CASE4:
+ //////////////////////////////////////////////////////////////////////
+ // CASE 4
+ //////////////////////////////////////////////////////////////////////
+ {
+ // estimate the number of entries in the list
+ int nEntriesMax = pDsdMan->nInputs - dd->perm[VarInt];
+
+ // create the new decomposition entry
+ int nEntries = 0;
+
+ DdNode * SuppL, * SuppH, * SuppL_init, * SuppH_init;
+ Dsd_Node_t *pHigher, *pLower, * pTemp, * pDENew;
+
+
+ int levTopSuppL;
+ int levTopSuppH;
+ int levTop;
+
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_PRIME, nEntriesMax, s_nDecBlocks++ );
+ pThis->pDecs[ nEntries++ ] = pVarCurDE;
+ // other entries will be added to this list one-by-one during analysis
+
+ // count how many times does it happen that the decomposition entries are
+ s_Case4Calls++;
+
+ // consider the simplest case: when the supports are equal
+ // and at least one of the components
+ // is the PRIME without decompositions, or
+ // when both of them are without decomposition
+ if ( (((pLR->Type == DSD_NODE_PRIME && nSuppL == pLR->nDecs) || (pHR->Type == DSD_NODE_PRIME && nSuppH == pHR->nDecs)) && pLR->S == pHR->S) ||
+ ((pLR->Type == DSD_NODE_PRIME && nSuppL == pLR->nDecs) && (pHR->Type == DSD_NODE_PRIME && nSuppH == pHR->nDecs)) )
+ {
+
+ s_Case4CallsSpecial++;
+ // walk through both supports and create the decomposition list composed of simple entries
+ SuppL = pLR->S;
+ SuppH = pHR->S;
+ do
+ {
+ // determine levels
+ levTopSuppL = cuddI(dd,SuppL->index);
+ levTopSuppH = cuddI(dd,SuppH->index);
+
+ // skip the topmost variable in both supports
+ if ( levTopSuppL <= levTopSuppH )
+ {
+ levTop = levTopSuppL;
+ SuppL = cuddT(SuppL);
+ }
+ else
+ levTop = levTopSuppH;
+
+ if ( levTopSuppH <= levTopSuppL )
+ SuppH = cuddT(SuppH);
+
+ // set the new decomposition entry
+ pThis->pDecs[ nEntries++ ] = pDsdMan->pInputs[ dd->invperm[levTop] ];
+ }
+ while ( SuppL != b1 || SuppH != b1 );
+ }
+ else
+ {
+
+ // compare two different decomposition lists
+ SuppL_init = pLR->S;
+ SuppH_init = pHR->S;
+ // start references (because these supports will change)
+ SuppL = pLR->S; Cudd_Ref( SuppL );
+ SuppH = pHR->S; Cudd_Ref( SuppH );
+ while ( SuppL != b1 || SuppH != b1 )
+ {
+ // determine the top level in cofactors and
+ // whether they have the same top level
+ int TopLevL = cuddI(dd,SuppL->index);
+ int TopLevH = cuddI(dd,SuppH->index);
+ int TopLevel = TopLevH;
+ int fEqualLevel = 0;
+
+ DdNode * bVarTop;
+ DdNode * bSuppSubract;
+
+
+ if ( TopLevL < TopLevH )
+ {
+ pHigher = pLR;
+ pLower = pHR;
+ TopLevel = TopLevL;
+ }
+ else if ( TopLevL > TopLevH )
+ {
+ pHigher = pHR;
+ pLower = pLR;
+ }
+ else
+ fEqualLevel = 1;
+ assert( TopLevel != CUDD_CONST_INDEX );
+
+
+ // find the currently top variable in the decomposition lists
+ bVarTop = dd->vars[dd->invperm[TopLevel]];
+
+ if ( !fEqualLevel )
+ {
+ // find the lower support
+ DdNode * bSuppLower = (TopLevL < TopLevH)? SuppH_init: SuppL_init;
+
+ // find the first component in pHigher
+ // whose support does not overlap with supp(Lower)
+ // and remember the previous component
+ int fPolarity;
+ Dsd_Node_t * pPrev = NULL; // the pointer to the component proceeding pCur
+ Dsd_Node_t * pCur = pHigher; // the first component not contained in supp(Lower)
+ while ( Extra_bddSuppOverlapping( dd, pCur->S, bSuppLower ) )
+ { // get the next component
+ pPrev = pCur;
+ pCur = dsdKernelFindContainingComponent( pDsdMan, pCur, bVarTop, &fPolarity );
+ };
+
+ // look for the possibility to subtract more than one component
+ if ( pPrev == NULL || pPrev->Type == DSD_NODE_PRIME )
+ { // if there is no previous component, or if the previous component is PRIME
+ // there is no way to subtract more than one component
+
+ // add the new decomposition entry (it is already regular)
+ pThis->pDecs[ nEntries++ ] = pCur;
+ // assign the support to be subtracted from both components
+ bSuppSubract = pCur->S;
+ }
+ else // all other types
+ {
+ // go through the decomposition list of pPrev and find components
+ // whose support does not overlap with supp(Lower)
+
+ Dsd_Node_t ** pNonOverlap = ALLOC( Dsd_Node_t *, dd->size );
+ int i, nNonOverlap = 0;
+ for ( i = 0; i < pPrev->nDecs; i++ )
+ {
+ pTemp = Dsd_Regular( pPrev->pDecs[i] );
+ if ( !Extra_bddSuppOverlapping( dd, pTemp->S, bSuppLower ) )
+ pNonOverlap[ nNonOverlap++ ] = pPrev->pDecs[i];
+ }
+ assert( nNonOverlap > 0 );
+
+ if ( nNonOverlap == 1 )
+ { // one one component was found, which is the original one
+ assert( Dsd_Regular(pNonOverlap[0]) == pCur);
+ // add the new decomposition entry
+ pThis->pDecs[ nEntries++ ] = pCur;
+ // assign the support to be subtracted from both components
+ bSuppSubract = pCur->S;
+ }
+ else // more than one components was found
+ {
+ // find the OR (EXOR) of the non-overlapping components
+ DdNode * bCommF;
+ dsdKernelComputeSumOfComponents( pDsdMan, pNonOverlap, nNonOverlap, &bCommF, NULL, (int)(pPrev->Type==DSD_NODE_EXOR) );
+ Cudd_Ref( bCommF );
+
+ // create a new gated
+ pDENew = dsdKernelDecompose_rec( pDsdMan, bCommF );
+ Cudd_RecursiveDeref(dd, bCommF);
+ // make it regular... it must be regular already
+ assert( !Dsd_IsComplement(pDENew) );
+
+ // add the new decomposition entry
+ pThis->pDecs[ nEntries++ ] = pDENew;
+ // assign the support to be subtracted from both components
+ bSuppSubract = pDENew->S;
+ }
+ free( pNonOverlap );
+ }
+
+ // subtract its support from the support of upper component
+ if ( TopLevL < TopLevH )
+ {
+ SuppL = Cudd_bddExistAbstract( dd, bTemp = SuppL, bSuppSubract ); Cudd_Ref( SuppL );
+ Cudd_RecursiveDeref(dd, bTemp);
+ }
+ else
+ {
+ SuppH = Cudd_bddExistAbstract( dd, bTemp = SuppH, bSuppSubract ); Cudd_Ref( SuppH );
+ Cudd_RecursiveDeref(dd, bTemp);
+ }
+ } // end of if ( !fEqualLevel )
+ else // if ( fEqualLevel ) -- they have the same top level var
+ {
+ Dsd_Node_t ** pMarkedLeft = ALLOC( Dsd_Node_t *, dd->size ); // the pointers to the marked blocks
+ char * pMarkedPols = ALLOC( char, dd->size ); // polarities of the marked blocks
+ int nMarkedLeft = 0;
+
+ int fPolarity = 0;
+ Dsd_Node_t * pTempL = pLR;
+
+ int fPolarityCurH = 0;
+ Dsd_Node_t * pPrevH = NULL, * pCurH = pHR;
+
+ int fPolarityCurL = 0;
+ Dsd_Node_t * pPrevL = NULL, * pCurL = pLR; // = pMarkedLeft[0];
+ int index = 1;
+
+ // set the new mark
+ s_Mark++;
+
+ // go over the dec list of pL, mark all components that contain the given variable
+ assert( Extra_bddSuppContainVar( dd, pLR->S, bVarTop ) );
+ assert( Extra_bddSuppContainVar( dd, pHR->S, bVarTop ) );
+ do {
+ pTempL->Mark = s_Mark;
+ pMarkedLeft[ nMarkedLeft ] = pTempL;
+ pMarkedPols[ nMarkedLeft ] = fPolarity;
+ nMarkedLeft++;
+ } while ( pTempL = dsdKernelFindContainingComponent( pDsdMan, pTempL, bVarTop, &fPolarity ) );
+
+ // go over the dec list of pH, and find the component that is marked and the previos one
+ // (such component always exists, because they have common variables)
+ while ( pCurH->Mark != s_Mark )
+ {
+ pPrevH = pCurH;
+ pCurH = dsdKernelFindContainingComponent( pDsdMan, pCurH, bVarTop, &fPolarityCurH );
+ assert( pCurH );
+ }
+
+ // go through the first list once again and find
+ // the component proceeding the one marked found in the second list
+ while ( pCurL != pCurH )
+ {
+ pPrevL = pCurL;
+ pCurL = pMarkedLeft[index];
+ fPolarityCurL = pMarkedPols[index];
+ index++;
+ }
+
+ // look for the possibility to subtract more than one component
+ if ( !pPrevL || !pPrevH || pPrevL->Type != pPrevH->Type || pPrevL->Type == DSD_NODE_PRIME || fPolarityCurL != fPolarityCurH )
+ { // there is no way to extract more than one
+ pThis->pDecs[ nEntries++ ] = pCurH;
+ // assign the support to be subtracted from both components
+ bSuppSubract = pCurH->S;
+ }
+ else
+ {
+ // find the equal components in two decomposition lists
+ Dsd_Node_t ** pCommon, * pLastDiffL = NULL, * pLastDiffH = NULL;
+ int nCommon = dsdKernelFindCommonComponents( pDsdMan, pPrevL, pPrevH, &pCommon, &pLastDiffL, &pLastDiffH );
+
+ if ( nCommon == 0 || nCommon == 1 )
+ { // one one component was found, which is the original one
+ // assert( Dsd_Regular(pCommon[0]) == pCurL);
+ // add the new decomposition entry
+ pThis->pDecs[ nEntries++ ] = pCurL;
+ // assign the support to be subtracted from both components
+ bSuppSubract = pCurL->S;
+ }
+ else // more than one components was found
+ {
+ // find the OR (EXOR) of the non-overlapping components
+ DdNode * bCommF;
+ dsdKernelComputeSumOfComponents( pDsdMan, pCommon, nCommon, &bCommF, NULL, (int)(pPrevL->Type==DSD_NODE_EXOR) );
+ Cudd_Ref( bCommF );
+
+ pDENew = dsdKernelDecompose_rec( pDsdMan, bCommF );
+ assert( !Dsd_IsComplement(pDENew) ); // cannot be complemented because of construction
+ Cudd_RecursiveDeref( dd, bCommF );
+
+ // add the new decomposition entry
+ pThis->pDecs[ nEntries++ ] = pDENew;
+
+ // assign the support to be subtracted from both components
+ bSuppSubract = pDENew->S;
+ }
+ }
+
+ SuppL = Cudd_bddExistAbstract( dd, bTemp = SuppL, bSuppSubract ), Cudd_Ref( SuppL );
+ Cudd_RecursiveDeref(dd, bTemp);
+
+ SuppH = Cudd_bddExistAbstract( dd, bTemp = SuppH, bSuppSubract ), Cudd_Ref( SuppH );
+ Cudd_RecursiveDeref(dd, bTemp);
+
+ free( pMarkedLeft );
+ free( pMarkedPols );
+
+ } // end of if ( fEqualLevel )
+
+ } // end of decomposition list comparison
+ Cudd_RecursiveDeref( dd, SuppL );
+ Cudd_RecursiveDeref( dd, SuppH );
+
+ }
+
+ // check that the estimation of the number of entries was okay
+ assert( nEntries <= nEntriesMax );
+
+// if ( nEntries != Extra_bddSuppSize(dd, bSuppNew) )
+// s_Case5++;
+
+ // update the number of entries in the new decomposition list
+ pThis->nDecs = nEntries;
+ }
+//}
+EXIT:
+
+ {
+ // if the component created is complemented, it represents a function without complement
+ // therefore, as it is, without complement, it should recieve the complemented function
+ Dsd_Node_t * pThisR = Dsd_Regular( pThis );
+ assert( pThisR->G == NULL );
+ assert( pThisR->S == NULL );
+
+ if ( pThisR == pThis ) // set regular function
+ pThisR->G = bF;
+ else // set complemented function
+ pThisR->G = Cudd_Not(bF);
+ Cudd_Ref(bF); // reference the function in the component
+
+ assert( bSuppNew );
+ pThisR->S = bSuppNew; // takes the reference from the new support
+ if ( st_insert( pDsdMan->Table, (char*)bF, (char*)pThis ) )
+ {
+ assert( 0 );
+ }
+ s_CacheEntries++;
+
+
+#if 0
+ if ( dsdKernelVerifyDecomposition(dd, pThis) == 0 )
+ {
+ // write the function, for which verification does not work
+ cout << endl << "Internal verification failed!"" );
+
+ // create the variable mask
+ static int s_pVarMask[MAXINPUTS];
+ int nInputCounter = 0;
+
+ Cudd_SupportArray( dd, bF, s_pVarMask );
+ int k;
+ for ( k = 0; k < dd->size; k++ )
+ if ( s_pVarMask[k] )
+ nInputCounter++;
+
+ cout << endl << "The problem function is "" );
+
+ DdNode * zNewFunc = Cudd_zddIsopCover( dd, bF, bF ); Cudd_Ref( zNewFunc );
+ cuddWriteFunctionSop( stdout, dd, zNewFunc, -1, dd->size, "1", s_pVarMask );
+ Cudd_RecursiveDerefZdd( dd, zNewFunc );
+ }
+#endif
+
+ }
+
+ Depth--;
+ return Dsd_NotCond( pThis, fCompF );
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// OTHER FUNCTIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Finds the corresponding decomposition entry.]
+
+ Description [This function returns the non-complemented pointer to the
+ DecEntry of that component which contains the given variable in its
+ support, or NULL if no such component exists]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Dsd_Node_t * dsdKernelFindContainingComponent( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pWhere, DdNode * Var, int * fPolarity )
+
+{
+ Dsd_Node_t * pTemp;
+ int i;
+
+// assert( !Dsd_IsComplement( pWhere ) );
+// assert( Extra_bddSuppContainVar( pDsdMan->dd, pWhere->S, Var ) );
+
+ if ( pWhere->nDecs == 1 )
+ return NULL;
+
+ for( i = 0; i < pWhere->nDecs; i++ )
+ {
+ pTemp = Dsd_Regular( pWhere->pDecs[i] );
+ if ( Extra_bddSuppContainVar( pDsdMan->dd, pTemp->S, Var ) )
+ {
+ *fPolarity = (int)( pTemp != pWhere->pDecs[i] );
+ return pTemp;
+ }
+ }
+ assert( 0 );
+ return NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Find the common decomposition components.]
+
+ Description [This function determines the common components. It counts
+ the number of common components in the decomposition lists of pL and pH
+ and returns their number and the lists of common components. It assumes
+ that pL and pH are regular pointers. It retuns also the pointers to the
+ last different components encountered in pL and pH.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int dsdKernelFindCommonComponents( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pL, Dsd_Node_t * pH, Dsd_Node_t *** pCommon, Dsd_Node_t ** pLastDiffL, Dsd_Node_t ** pLastDiffH )
+{
+ Dsd_Node_t ** Common = ALLOC( Dsd_Node_t *, pDsdMan->dd->size );
+ int nCommon = 0;
+
+ // pointers to the current decomposition entries
+ Dsd_Node_t * pLcur;
+ Dsd_Node_t * pHcur;
+
+ // the pointers to their supports
+ DdNode * bSLcur;
+ DdNode * bSHcur;
+
+ // the top variable in the supports
+ int TopVar;
+
+ // the indices running through the components
+ int iCurL = 0;
+ int iCurH = 0;
+ while ( iCurL < pL->nDecs && iCurH < pH->nDecs )
+ { // both did not run out
+
+ pLcur = Dsd_Regular(pL->pDecs[iCurL]);
+ pHcur = Dsd_Regular(pH->pDecs[iCurH]);
+
+ bSLcur = pLcur->S;
+ bSHcur = pHcur->S;
+
+ // find out what component is higher in the BDD
+ if ( pDsdMan->dd->perm[bSLcur->index] < pDsdMan->dd->perm[bSHcur->index] )
+ TopVar = bSLcur->index;
+ else
+ TopVar = bSHcur->index;
+
+ if ( TopVar == bSLcur->index && TopVar == bSHcur->index )
+ {
+ // the components may be equal - should match exactly!
+ if ( pL->pDecs[iCurL] == pH->pDecs[iCurH] )
+ Common[nCommon++] = pL->pDecs[iCurL];
+ else
+ {
+ *pLastDiffL = pL->pDecs[iCurL];
+ *pLastDiffH = pH->pDecs[iCurH];
+ }
+
+ // skip both
+ iCurL++;
+ iCurH++;
+ }
+ else if ( TopVar == bSLcur->index )
+ { // the components cannot be equal
+ // skip the top-most one
+ *pLastDiffL = pL->pDecs[iCurL++];
+ }
+ else // if ( TopVar == bSHcur->index )
+ { // the components cannot be equal
+ // skip the top-most one
+ *pLastDiffH = pH->pDecs[iCurH++];
+ }
+ }
+
+ // if one of the lists still has components, write the first one down
+ if ( iCurL < pL->nDecs )
+ *pLastDiffL = pL->pDecs[iCurL];
+
+ if ( iCurH < pH->nDecs )
+ *pLastDiffH = pH->pDecs[iCurH];
+
+ // return the pointer to the array
+ *pCommon = Common;
+ // return the number of common components
+ free( Common );
+ return nCommon;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the sum (OR or EXOR) of the functions of the components.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void dsdKernelComputeSumOfComponents( Dsd_Manager_t * pDsdMan, Dsd_Node_t ** pCommon, int nCommon, DdNode ** pCompF, DdNode ** pCompS, int fExor )
+{
+ DdManager * dd = pDsdMan->dd;
+ DdNode * bF, * bS, * bFadd, * bTemp;
+ Dsd_Node_t * pDE, * pDER;
+ int i;
+
+ // start the function
+ bF = b0; Cudd_Ref( bF );
+ // start the support
+ if ( pCompS )
+ bS = b1, Cudd_Ref( bS );
+
+ assert( nCommon > 0 );
+ for ( i = 0; i < nCommon; i++ )
+ {
+ pDE = pCommon[i];
+ pDER = Dsd_Regular( pDE );
+ bFadd = (pDE != pDER)? Cudd_Not(pDER->G): pDER->G;
+ // add to the function
+ if ( fExor )
+ bF = Cudd_bddXor( dd, bTemp = bF, bFadd );
+ else
+ bF = Cudd_bddOr( dd, bTemp = bF, bFadd );
+ Cudd_Ref( bF );
+ Cudd_RecursiveDeref( dd, bTemp );
+ if ( pCompS )
+ {
+ // add to the support
+ bS = Cudd_bddAnd( dd, bTemp = bS, pDER->S ); Cudd_Ref( bS );
+ Cudd_RecursiveDeref( dd, bTemp );
+ }
+ }
+ // return the function
+ Cudd_Deref( bF );
+ *pCompF = bF;
+
+ // return the support
+ if ( pCompS )
+ Cudd_Deref( bS ), *pCompS = bS;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks support containment of the decomposition components.]
+
+ Description [This function returns 1 if support of one component is contained
+ in that of another. In this case, pLarge (pSmall) is assigned to point to the
+ larger (smaller) support. If the supports are identical return 0, and does not
+ assign the components.]
+]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int dsdKernelCheckContainment( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pL, Dsd_Node_t * pH, Dsd_Node_t ** pLarge, Dsd_Node_t ** pSmall )
+{
+ DdManager * dd = pDsdMan->dd;
+ DdNode * bSuppLarge, * bSuppSmall;
+ int RetValue;
+
+ RetValue = Extra_bddSuppCheckContainment( dd, pL->S, pH->S, &bSuppLarge, &bSuppSmall );
+
+ if ( RetValue == 0 )
+ return 0;
+
+ if ( pH->S == bSuppLarge )
+ {
+ *pLarge = pH;
+ *pSmall = pL;
+ }
+ else // if ( pL->S == bSuppLarge )
+ {
+ *pLarge = pL;
+ *pSmall = pH;
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Copies the list of components plus one.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void dsdKernelCopyListPlusOne( Dsd_Node_t * p, Dsd_Node_t * First, Dsd_Node_t ** ppList, int nListSize )
+{
+ int i;
+ assert( nListSize+1 == p->nDecs );
+ p->pDecs[0] = First;
+ for( i = 0; i < nListSize; i++ )
+ p->pDecs[i+1] = ppList[i];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Copies the list of components plus one, and skips one.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void dsdKernelCopyListPlusOneMinusOne( Dsd_Node_t * p, Dsd_Node_t * First, Dsd_Node_t ** ppList, int nListSize, int iSkipped )
+{
+ int i, Counter;
+ assert( nListSize == p->nDecs );
+ p->pDecs[0] = First;
+ for( i = 0, Counter = 1; i < nListSize; i++ )
+ if ( i != iSkipped )
+ p->pDecs[Counter++] = ppList[i];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Debugging procedure to compute the functionality of the decomposed structure.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int dsdKernelVerifyDecomposition( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pDE )
+{
+ DdManager * dd = pDsdMan->dd;
+ Dsd_Node_t * pR = Dsd_Regular(pDE);
+ int fCompP = (int)( pDE != pR );
+ int RetValue;
+
+ DdNode * bRes;
+ if ( pR->Type == DSD_NODE_CONST1 )
+ bRes = b1;
+ else if ( pR->Type == DSD_NODE_BUF )
+ bRes = pR->G;
+ else if ( pR->Type == DSD_NODE_OR || pR->Type == DSD_NODE_EXOR )
+ dsdKernelComputeSumOfComponents( pDsdMan, pR->pDecs, pR->nDecs, &bRes, NULL, (int)(pR->Type == DSD_NODE_EXOR) );
+ else if ( pR->Type == DSD_NODE_PRIME )
+ {
+ int i;
+ DdNode ** bGVars = ALLOC( DdNode *, dd->size );
+ // transform the function of this block, so that it depended on inputs
+ // corresponding to the formal inputs
+ DdNode * bNewFunc = Dsd_TreeGetPrimeFunctionOld( dd, pR, 1 ); Cudd_Ref( bNewFunc );
+
+ // compose this function with the inputs
+ // create the elementary permutation
+ for ( i = 0; i < dd->size; i++ )
+ bGVars[i] = dd->vars[i];
+
+ // assign functions to be composed
+ for ( i = 0; i < pR->nDecs; i++ )
+ bGVars[dd->invperm[i]] = pR->pDecs[i]->G;
+
+ // perform the composition
+ bRes = Cudd_bddVectorCompose( dd, bNewFunc, bGVars ); Cudd_Ref( bRes );
+ Cudd_RecursiveDeref( dd, bNewFunc );
+
+ /////////////////////////////////////////////////////////
+ RetValue = (int)( bRes == pR->G );//|| bRes == Cudd_Not(pR->G) );
+ /////////////////////////////////////////////////////////
+ Cudd_Deref( bRes );
+ free( bGVars );
+ }
+ else
+ {
+ assert(0);
+ }
+
+ Cudd_Ref( bRes );
+ RetValue = (int)( bRes == pR->G );//|| bRes == Cudd_Not(pR->G) );
+ Cudd_RecursiveDeref( dd, bRes );
+ return RetValue;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
diff --git a/src/bdd/dsd/dsdTree.c b/src/bdd/dsd/dsdTree.c
new file mode 100644
index 00000000..b1532715
--- /dev/null
+++ b/src/bdd/dsd/dsdTree.c
@@ -0,0 +1,838 @@
+/**CFile****************************************************************
+
+ FileName [dsdTree.c]
+
+ PackageName [DSD: Disjoint-support decomposition package.]
+
+ Synopsis [Managing the decomposition tree.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 8.0. Started - September 22, 2003.]
+
+ Revision [$Id: dsdTree.c,v 1.0 2002/22/09 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "dsdInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Dsd_TreeUnmark_rec( Dsd_Node_t * pNode );
+static void Dsd_TreeGetInfo_rec( Dsd_Node_t * pNode, int RankCur );
+static int Dsd_TreeCountNonTerminalNodes_rec( Dsd_Node_t * pNode );
+static int Dsd_TreeCountPrimeNodes_rec( Dsd_Node_t * pNode );
+static int Dsd_TreeCollectDecomposableVars_rec( DdManager * dd, Dsd_Node_t * pNode, int * pVars, int * nVars );
+static void Dsd_TreeCollectNodesDfs_rec( Dsd_Node_t * pNode, Dsd_Node_t * ppNodes[], int * pnNodes );
+static void Dsd_TreePrint_rec( FILE * pFile, Dsd_Node_t * pNode, int fCcmp, char * pInputNames[], char * pOutputName, int nOffset, int * pSigCounter, int fShortNames );
+
+
+////////////////////////////////////////////////////////////////////////
+/// STATIC VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+static int s_DepthMax;
+static int s_GateSizeMax;
+
+static int s_CounterBlocks;
+static int s_CounterPos;
+static int s_CounterNeg;
+static int s_CounterNo;
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Create the DSD node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Dsd_Node_t * Dsd_TreeNodeCreate( int Type, int nDecs, int BlockNum )
+{
+ // allocate memory for this node
+ Dsd_Node_t * p = (Dsd_Node_t *) malloc( sizeof(Dsd_Node_t) );
+ memset( p, 0, sizeof(Dsd_Node_t) );
+ p->Type = Type; // the type of this block
+ p->nDecs = nDecs; // the number of decompositions
+ if ( p->nDecs )
+ {
+ p->pDecs = (Dsd_Node_t **) malloc( p->nDecs * sizeof(Dsd_Node_t *) );
+ p->pDecs[0] = NULL;
+ }
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Frees the DSD node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_TreeNodeDelete( DdManager * dd, Dsd_Node_t * pNode )
+{
+ if ( pNode->G ) Cudd_RecursiveDeref( dd, pNode->G );
+ if ( pNode->S ) Cudd_RecursiveDeref( dd, pNode->S );
+ FREE( pNode->pDecs );
+ FREE( pNode );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Unmarks the decomposition tree.]
+
+ Description [This function assumes that originally pNode->nVisits are
+ set to zero!]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_TreeUnmark( Dsd_Manager_t * pDsdMan )
+{
+ int i;
+ for ( i = 0; i < pDsdMan->nRoots; i++ )
+ Dsd_TreeUnmark_rec( Dsd_Regular( pDsdMan->pRoots[i] ) );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Recursive unmarking.]
+
+ Description [This function should be called with a non-complemented
+ pointer.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_TreeUnmark_rec( Dsd_Node_t * pNode )
+{
+ int i;
+
+ assert( pNode );
+ assert( !Dsd_IsComplement( pNode ) );
+ assert( pNode->nVisits > 0 );
+
+ if ( --pNode->nVisits ) // if this is not the last visit, return
+ return;
+
+ // upon the last visit, go through the list of successors and call recursively
+ if ( pNode->Type != DSD_NODE_BUF && pNode->Type != DSD_NODE_CONST1 )
+ for ( i = 0; i < pNode->nDecs; i++ )
+ Dsd_TreeUnmark_rec( Dsd_Regular(pNode->pDecs[i]) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Getting information about the node.]
+
+ Description [This function computes the max depth and the max gate size
+ of the tree rooted at the node.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_TreeNodeGetInfo( Dsd_Manager_t * pDsdMan, int * DepthMax, int * GateSizeMax )
+{
+ int i;
+ s_DepthMax = 0;
+ s_GateSizeMax = 0;
+
+ for ( i = 0; i < pDsdMan->nRoots; i++ )
+ Dsd_TreeGetInfo_rec( Dsd_Regular( pDsdMan->pRoots[i] ), 0 );
+
+ if ( DepthMax )
+ *DepthMax = s_DepthMax;
+ if ( GateSizeMax )
+ *GateSizeMax = s_GateSizeMax;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Getting information about the node.]
+
+ Description [This function computes the max depth and the max gate size
+ of the tree rooted at the node.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_TreeNodeGetInfoOne( Dsd_Node_t * pNode, int * DepthMax, int * GateSizeMax )
+{
+ s_DepthMax = 0;
+ s_GateSizeMax = 0;
+
+ Dsd_TreeGetInfo_rec( Dsd_Regular(pNode), 0 );
+
+ if ( DepthMax )
+ *DepthMax = s_DepthMax;
+ if ( GateSizeMax )
+ *GateSizeMax = s_GateSizeMax;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Performs the recursive step of Dsd_TreeNodeGetInfo().]
+
+ Description [pNode is the node, for the tree rooted in which we are
+ determining info. RankCur is the current rank to assign to the node.
+ fSetRank is the flag saying whether the rank will be written in the
+ node. s_DepthMax is the maximum depths of the tree. s_GateSizeMax is
+ the maximum gate size.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_TreeGetInfo_rec( Dsd_Node_t * pNode, int RankCur )
+{
+ int i;
+ int GateSize;
+
+ assert( pNode );
+ assert( !Dsd_IsComplement( pNode ) );
+ assert( pNode->nVisits >= 0 );
+
+ // we don't want the two-input gates to count for non-decomposable blocks
+ if ( pNode->Type == DSD_NODE_OR ||
+ pNode->Type == DSD_NODE_EXOR )
+ GateSize = 2;
+ else
+ GateSize = pNode->nDecs;
+
+ // update the max size of the node
+ if ( s_GateSizeMax < GateSize )
+ s_GateSizeMax = GateSize;
+
+ if ( pNode->nDecs < 2 )
+ return;
+
+ // update the max rank
+ if ( s_DepthMax < RankCur+1 )
+ s_DepthMax = RankCur+1;
+
+ // call recursively
+ for ( i = 0; i < pNode->nDecs; i++ )
+ Dsd_TreeGetInfo_rec( Dsd_Regular(pNode->pDecs[i]), RankCur+1 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Counts non-terminal nodes of the DSD tree.]
+
+ Description [Nonterminal nodes include all the nodes with the
+ support more than 1. These are OR, EXOR, and PRIME nodes. They
+ do not include the elementary variable nodes and the constant 1
+ node.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Dsd_TreeCountNonTerminalNodes( Dsd_Manager_t * pDsdMan )
+{
+ int Counter, i;
+ Counter = 0;
+ for ( i = 0; i < pDsdMan->nRoots; i++ )
+ Counter += Dsd_TreeCountNonTerminalNodes_rec( Dsd_Regular( pDsdMan->pRoots[i] ) );
+ Dsd_TreeUnmark( pDsdMan );
+ return Counter;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Dsd_TreeCountNonTerminalNodesOne( Dsd_Node_t * pRoot )
+{
+ int Counter = 0;
+
+ // go through the list of successors and call recursively
+ Counter = Dsd_TreeCountNonTerminalNodes_rec( Dsd_Regular(pRoot) );
+
+ Dsd_TreeUnmark_rec( Dsd_Regular(pRoot) );
+ return Counter;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Counts non-terminal nodes for one root.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Dsd_TreeCountNonTerminalNodes_rec( Dsd_Node_t * pNode )
+{
+ int i;
+ int Counter = 0;
+
+ assert( pNode );
+ assert( !Dsd_IsComplement( pNode ) );
+ assert( pNode->nVisits >= 0 );
+
+ if ( pNode->nVisits++ ) // if this is not the first visit, return zero
+ return 0;
+
+ if ( pNode->nDecs <= 1 )
+ return 0;
+
+ // upon the first visit, go through the list of successors and call recursively
+ for ( i = 0; i < pNode->nDecs; i++ )
+ Counter += Dsd_TreeCountNonTerminalNodes_rec( Dsd_Regular(pNode->pDecs[i]) );
+
+ return Counter + 1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Counts prime nodes of the DSD tree.]
+
+ Description [Prime nodes are nodes with the support more than 2,
+ that is not an OR or EXOR gate.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Dsd_TreeCountPrimeNodes( Dsd_Manager_t * pDsdMan )
+{
+ int Counter, i;
+ Counter = 0;
+ for ( i = 0; i < pDsdMan->nRoots; i++ )
+ Counter += Dsd_TreeCountPrimeNodes_rec( Dsd_Regular( pDsdMan->pRoots[i] ) );
+ Dsd_TreeUnmark( pDsdMan );
+ return Counter;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Counts prime nodes for one root.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Dsd_TreeCountPrimeNodesOne( Dsd_Node_t * pRoot )
+{
+ int Counter = 0;
+
+ // go through the list of successors and call recursively
+ Counter = Dsd_TreeCountPrimeNodes_rec( Dsd_Regular(pRoot) );
+
+ Dsd_TreeUnmark_rec( Dsd_Regular(pRoot) );
+ return Counter;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Dsd_TreeCountPrimeNodes_rec( Dsd_Node_t * pNode )
+{
+ int i;
+ int Counter = 0;
+
+ assert( pNode );
+ assert( !Dsd_IsComplement( pNode ) );
+ assert( pNode->nVisits >= 0 );
+
+ if ( pNode->nVisits++ ) // if this is not the first visit, return zero
+ return 0;
+
+ if ( pNode->nDecs <= 1 )
+ return 0;
+
+ // upon the first visit, go through the list of successors and call recursively
+ for ( i = 0; i < pNode->nDecs; i++ )
+ Counter += Dsd_TreeCountPrimeNodes_rec( Dsd_Regular(pNode->pDecs[i]) );
+
+ if ( pNode->Type == DSD_NODE_PRIME )
+ Counter++;
+
+ return Counter;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Collects the decomposable vars on the PI side.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Dsd_TreeCollectDecomposableVars( Dsd_Manager_t * pDsdMan, int * pVars )
+{
+ int nVars;
+
+ // set the vars collected to 0
+ nVars = 0;
+ Dsd_TreeCollectDecomposableVars_rec( pDsdMan->dd, Dsd_Regular(pDsdMan->pRoots[0]), pVars, &nVars );
+ // return the number of collected vars
+ return nVars;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Implements the recursive part of Dsd_TreeCollectDecomposableVars().]
+
+ Description [Adds decomposable variables as they are found to pVars and increments
+ nVars. Returns 1 if a non-dec node with more than 4 inputs was encountered
+ in the processed subtree. Returns 0, otherwise. ]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Dsd_TreeCollectDecomposableVars_rec( DdManager * dd, Dsd_Node_t * pNode, int * pVars, int * nVars )
+{
+ int fSkipThisNode, i;
+ Dsd_Node_t * pTemp;
+ int fVerbose = 0;
+
+ assert( pNode );
+ assert( !Dsd_IsComplement( pNode ) );
+
+ if ( pNode->nDecs <= 1 )
+ return 0;
+
+ // go through the list of successors and call recursively
+ fSkipThisNode = 0;
+ for ( i = 0; i < pNode->nDecs; i++ )
+ if ( Dsd_TreeCollectDecomposableVars_rec(dd, Dsd_Regular(pNode->pDecs[i]), pVars, nVars) )
+ fSkipThisNode = 1;
+
+ if ( !fSkipThisNode && (pNode->Type == DSD_NODE_OR || pNode->Type == DSD_NODE_EXOR || pNode->nDecs <= 4) )
+ {
+if ( fVerbose )
+printf( "Node of type <%d> (OR=6,EXOR=8,RAND=1): ", pNode->Type );
+
+ for ( i = 0; i < pNode->nDecs; i++ )
+ {
+ pTemp = Dsd_Regular(pNode->pDecs[i]);
+ if ( pTemp->Type == DSD_NODE_BUF )
+ {
+ if ( pVars )
+ pVars[ (*nVars)++ ] = pTemp->S->index;
+ else
+ (*nVars)++;
+
+if ( fVerbose )
+printf( "%d ", pTemp->S->index );
+ }
+ }
+if ( fVerbose )
+printf( "\n" );
+ }
+ else
+ fSkipThisNode = 1;
+
+
+ return fSkipThisNode;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Creates the DFS ordered array of DSD nodes in the tree.]
+
+ Description [The collected nodes do not include the terminal nodes
+ and the constant 1 node. The array of nodes is returned. The number
+ of entries in the array is returned in the variale pnNodes.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Dsd_Node_t ** Dsd_TreeCollectNodesDfs( Dsd_Manager_t * pDsdMan, int * pnNodes )
+{
+ Dsd_Node_t ** ppNodes;
+ int nNodes, nNodesAlloc;
+ int i;
+
+ nNodesAlloc = Dsd_TreeCountNonTerminalNodes(pDsdMan);
+ nNodes = 0;
+ ppNodes = ALLOC( Dsd_Node_t *, nNodesAlloc );
+ for ( i = 0; i < pDsdMan->nRoots; i++ )
+ Dsd_TreeCollectNodesDfs_rec( Dsd_Regular(pDsdMan->pRoots[i]), ppNodes, &nNodes );
+ Dsd_TreeUnmark( pDsdMan );
+ assert( nNodesAlloc == nNodes );
+ *pnNodes = nNodes;
+ return ppNodes;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_TreeCollectNodesDfs_rec( Dsd_Node_t * pNode, Dsd_Node_t * ppNodes[], int * pnNodes )
+{
+ int i;
+ assert( pNode );
+ assert( !Dsd_IsComplement(pNode) );
+ assert( pNode->nVisits >= 0 );
+
+ if ( pNode->nVisits++ ) // if this is not the first visit, return zero
+ return;
+ if ( pNode->nDecs <= 1 )
+ return;
+
+ // upon the first visit, go through the list of successors and call recursively
+ for ( i = 0; i < pNode->nDecs; i++ )
+ Dsd_TreeCollectNodesDfs_rec( Dsd_Regular(pNode->pDecs[i]), ppNodes, pnNodes );
+
+ ppNodes[ (*pnNodes)++ ] = pNode;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the decompostion tree into file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_TreePrint( FILE * pFile, Dsd_Manager_t * pDsdMan, char * pInputNames[], char * pOutputNames[], int fShortNames, int Output )
+{
+ Dsd_Node_t * pNode;
+ int SigCounter;
+ int i;
+ SigCounter = 1;
+
+ if ( Output == -1 )
+ {
+ for ( i = 0; i < pDsdMan->nRoots; i++ )
+ {
+ pNode = Dsd_Regular( pDsdMan->pRoots[i] );
+ Dsd_TreePrint_rec( pFile, pNode, (pNode != pDsdMan->pRoots[i]), pInputNames, pOutputNames[i], 0, &SigCounter, fShortNames );
+ }
+ }
+ else
+ {
+ assert( Output >= 0 && Output < pDsdMan->nRoots );
+ pNode = Dsd_Regular( pDsdMan->pRoots[Output] );
+ Dsd_TreePrint_rec( pFile, pNode, (pNode != pDsdMan->pRoots[Output]), pInputNames, pOutputNames[Output], 0, &SigCounter, fShortNames );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the decompostion tree into file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_TreePrint_rec( FILE * pFile, Dsd_Node_t * pNode, int fComp, char * pInputNames[], char * pOutputName, int nOffset, int * pSigCounter, int fShortNames )
+{
+ char Buffer[100];
+ Dsd_Node_t * pInput;
+ int * pInputNums;
+ int fCompNew, i;
+
+ assert( pNode->Type == DSD_NODE_BUF || pNode->Type == DSD_NODE_CONST1 ||
+ pNode->Type == DSD_NODE_PRIME || pNode->Type == DSD_NODE_OR || pNode->Type == DSD_NODE_EXOR );
+
+ Extra_PrintSymbols( pFile, ' ', nOffset, 0 );
+ fprintf( pFile, "%s: ", pOutputName );
+ pInputNums = ALLOC( int, pNode->nDecs );
+ if ( pNode->Type == DSD_NODE_CONST1 )
+ {
+ if ( fComp )
+ fprintf( pFile, " Constant 0.\n" );
+ else
+ fprintf( pFile, " Constant 1.\n" );
+ }
+ else if ( pNode->Type == DSD_NODE_BUF )
+ {
+ if ( fComp )
+ fprintf( pFile, " NOT(" );
+ else
+ fprintf( pFile, " " );
+ if ( fShortNames )
+ fprintf( pFile, "%d", pNode->S->index );
+ else
+ fprintf( pFile, "%s", pInputNames[pNode->S->index] );
+ if ( fComp )
+ fprintf( pFile, ")" );
+ fprintf( pFile, "\n" );
+ }
+ else if ( pNode->Type == DSD_NODE_PRIME )
+ {
+ // print the line
+ fprintf( pFile, "PRIME(" );
+ for ( i = 0; i < pNode->nDecs; i++ )
+ {
+ pInput = Dsd_Regular( pNode->pDecs[i] );
+ fCompNew = (int)( pInput != pNode->pDecs[i] );
+ if ( i )
+ fprintf( pFile, "," );
+ if ( pInput->Type == DSD_NODE_BUF )
+ {
+ pInputNums[i] = 0;
+ if ( fCompNew )
+ fprintf( pFile, " NOT(" );
+ else
+ fprintf( pFile, " " );
+ if ( fShortNames )
+ fprintf( pFile, "%d", pInput->S->index );
+ else
+ fprintf( pFile, "%s", pInputNames[pInput->S->index] );
+ if ( fCompNew )
+ fprintf( pFile, ")" );
+ }
+ else
+ {
+ pInputNums[i] = (*pSigCounter)++;
+ fprintf( pFile, " <%d>", pInputNums[i] );
+ }
+ }
+ fprintf( pFile, " )\n" );
+ // call recursively for the following blocks
+ for ( i = 0; i < pNode->nDecs; i++ )
+ if ( pInputNums[i] )
+ {
+ pInput = Dsd_Regular( pNode->pDecs[i] );
+ fCompNew = (int)( pInput != pNode->pDecs[i] );
+ sprintf( Buffer, "<%d>", pInputNums[i] );
+ Dsd_TreePrint_rec( pFile, Dsd_Regular( pNode->pDecs[i] ), fCompNew, pInputNames, Buffer, nOffset + 6, pSigCounter, fShortNames );
+ }
+ }
+ else if ( pNode->Type == DSD_NODE_OR )
+ {
+ // print the line
+ if ( fComp )
+ fprintf( pFile, "AND(" );
+ else
+ fprintf( pFile, "OR(" );
+ for ( i = 0; i < pNode->nDecs; i++ )
+ {
+ pInput = Dsd_Regular( pNode->pDecs[i] );
+ fCompNew = (int)( pInput != pNode->pDecs[i] );
+ if ( i )
+ fprintf( pFile, "," );
+ if ( pInput->Type == DSD_NODE_BUF )
+ {
+ pInputNums[i] = 0;
+ if ( fCompNew )
+ fprintf( pFile, " NOT(" );
+ else
+ fprintf( pFile, " " );
+ if ( fShortNames )
+ fprintf( pFile, "%d", pInput->S->index );
+ else
+ fprintf( pFile, "%s", pInputNames[pInput->S->index] );
+ if ( fCompNew )
+ fprintf( pFile, ")" );
+ }
+ else
+ {
+ pInputNums[i] = (*pSigCounter)++;
+ fprintf( pFile, " <%d>", pInputNums[i] );
+ }
+ }
+ fprintf( pFile, " )\n" );
+ // call recursively for the following blocks
+ for ( i = 0; i < pNode->nDecs; i++ )
+ if ( pInputNums[i] )
+ {
+ pInput = Dsd_Regular( pNode->pDecs[i] );
+ fCompNew = (int)( pInput != pNode->pDecs[i] );
+ sprintf( Buffer, "<%d>", pInputNums[i] );
+ Dsd_TreePrint_rec( pFile, Dsd_Regular( pNode->pDecs[i] ), fComp ^ fCompNew, pInputNames, Buffer, nOffset + 6, pSigCounter, fShortNames );
+ }
+ }
+ else if ( pNode->Type == DSD_NODE_EXOR )
+ {
+ // print the line
+ if ( fComp )
+ fprintf( pFile, "NEXOR(" );
+ else
+ fprintf( pFile, "EXOR(" );
+ for ( i = 0; i < pNode->nDecs; i++ )
+ {
+ pInput = Dsd_Regular( pNode->pDecs[i] );
+ fCompNew = (int)( pInput != pNode->pDecs[i] );
+ if ( i )
+ fprintf( pFile, "," );
+ if ( pInput->Type == DSD_NODE_BUF )
+ {
+ pInputNums[i] = 0;
+ if ( fCompNew )
+ fprintf( pFile, " NOT(" );
+ else
+ fprintf( pFile, " " );
+ if ( fShortNames )
+ fprintf( pFile, "%d", pInput->S->index );
+ else
+ fprintf( pFile, "%s", pInputNames[pInput->S->index] );
+ if ( fCompNew )
+ fprintf( pFile, ")" );
+ }
+ else
+ {
+ pInputNums[i] = (*pSigCounter)++;
+ fprintf( pFile, " <%d>", pInputNums[i] );
+ }
+ }
+ fprintf( pFile, " )\n" );
+ // call recursively for the following blocks
+ for ( i = 0; i < pNode->nDecs; i++ )
+ if ( pInputNums[i] )
+ {
+ pInput = Dsd_Regular( pNode->pDecs[i] );
+ fCompNew = (int)( pInput != pNode->pDecs[i] );
+ sprintf( Buffer, "<%d>", pInputNums[i] );
+ Dsd_TreePrint_rec( pFile, Dsd_Regular( pNode->pDecs[i] ), fCompNew, pInputNames, Buffer, nOffset + 6, pSigCounter, fShortNames );
+ }
+ }
+ free( pInputNums );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Retuns the function of one node of the decomposition tree.]
+
+ Description [This is the old procedure. It is now superceded by the
+ procedure Dsd_TreeGetPrimeFunction() found in "dsdLocal.c".]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Dsd_TreeGetPrimeFunctionOld( DdManager * dd, Dsd_Node_t * pNode, int fRemap )
+{
+ DdNode * bCof0, * bCof1, * bCube0, * bCube1, * bNewFunc, * bTemp;
+ int i;
+ int fAllBuffs = 1;
+ int * pPermute;
+
+ pPermute = ALLOC( int, dd->size );
+
+ assert( pNode );
+ assert( !Dsd_IsComplement( pNode ) );
+ assert( pNode->Type == DSD_NODE_PRIME );
+
+ // transform the function of this block to depend on inputs
+ // corresponding to the formal inputs
+
+ // first, substitute those inputs that have some blocks associated with them
+ // second, remap the inputs to the top of the manager (then, it is easy to output them)
+
+ // start the function
+ bNewFunc = pNode->G; Cudd_Ref( bNewFunc );
+ // go over all primary inputs
+ for ( i = 0; i < pNode->nDecs; i++ )
+ if ( pNode->pDecs[i]->Type != DSD_NODE_BUF ) // remap only if it is not the buffer
+ {
+ bCube0 = Extra_bddFindOneCube( dd, Cudd_Not(pNode->pDecs[i]->G) ); Cudd_Ref( bCube0 );
+ bCof0 = Cudd_Cofactor( dd, bNewFunc, bCube0 ); Cudd_Ref( bCof0 );
+ Cudd_RecursiveDeref( dd, bCube0 );
+
+ bCube1 = Extra_bddFindOneCube( dd, pNode->pDecs[i]->G ); Cudd_Ref( bCube1 );
+ bCof1 = Cudd_Cofactor( dd, bNewFunc, bCube1 ); Cudd_Ref( bCof1 );
+ Cudd_RecursiveDeref( dd, bCube1 );
+
+ Cudd_RecursiveDeref( dd, bNewFunc );
+
+ // use the variable in the i-th level of the manager
+// bNewFunc = Cudd_bddIte( dd, dd->vars[dd->invperm[i]],bCof1,bCof0 ); Cudd_Ref( bNewFunc );
+ // use the first variale in the support of the component
+ bNewFunc = Cudd_bddIte( dd, dd->vars[pNode->pDecs[i]->S->index],bCof1,bCof0 ); Cudd_Ref( bNewFunc );
+ Cudd_RecursiveDeref( dd, bCof0 );
+ Cudd_RecursiveDeref( dd, bCof1 );
+ }
+
+ if ( fRemap )
+ {
+ // remap the function to the top of the manager
+ // remap the function to the first variables of the manager
+ for ( i = 0; i < pNode->nDecs; i++ )
+ // Permute[ pNode->pDecs[i]->S->index ] = dd->invperm[i];
+ pPermute[ pNode->pDecs[i]->S->index ] = i;
+
+ bNewFunc = Cudd_bddPermute( dd, bTemp = bNewFunc, pPermute ); Cudd_Ref( bNewFunc );
+ Cudd_RecursiveDeref( dd, bTemp );
+ }
+
+ Cudd_Deref( bNewFunc );
+ free( pPermute );
+ return bNewFunc;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
diff --git a/src/bdd/dsd/module.make b/src/bdd/dsd/module.make
new file mode 100644
index 00000000..f6418492
--- /dev/null
+++ b/src/bdd/dsd/module.make
@@ -0,0 +1,6 @@
+SRC += bdd\dsd\dsdApi.c \
+ bdd\dsd\dsdCheck.c \
+ bdd\dsd\dsdLocal.c \
+ bdd\dsd\dsdMan.c \
+ bdd\dsd\dsdProc.c \
+ bdd\dsd\dsdTree.c
diff --git a/src/bdd/epd/epd.c b/src/bdd/epd/epd.c
new file mode 100644
index 00000000..a843b986
--- /dev/null
+++ b/src/bdd/epd/epd.c
@@ -0,0 +1,1314 @@
+/**CFile***********************************************************************
+
+ FileName [epd.c]
+
+ PackageName [epd]
+
+ Synopsis [Arithmetic functions with extended double precision.]
+
+ Description []
+
+ SeeAlso []
+
+ Author [In-Ho Moon]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+ Revision [$Id: epd.c,v 1.1.1.1 2003/02/24 22:23:57 wjiang Exp $]
+
+******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "util.h"
+#include "epd.h"
+
+
+/**Function********************************************************************
+
+ Synopsis [Allocates an EpDouble struct.]
+
+ Description [Allocates an EpDouble struct.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+EpDouble *
+EpdAlloc()
+{
+ EpDouble *epd;
+
+ epd = ALLOC(EpDouble, 1);
+ return(epd);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Compares two EpDouble struct.]
+
+ Description [Compares two EpDouble struct.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+EpdCmp(const char *key1, const char *key2)
+{
+ EpDouble *epd1 = (EpDouble *) key1;
+ EpDouble *epd2 = (EpDouble *) key2;
+ if (epd1->type.value != epd2->type.value ||
+ epd1->exponent != epd2->exponent) {
+ return(1);
+ }
+ return(0);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees an EpDouble struct.]
+
+ Description [Frees an EpDouble struct.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdFree(EpDouble *epd)
+{
+ FREE(epd);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Multiplies two arbitrary precision double values.]
+
+ Description [Multiplies two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdGetString(EpDouble *epd, char *str)
+{
+ double value;
+ int exponent;
+ char *pos;
+
+ if (IsNanDouble(epd->type.value)) {
+ sprintf(str, "NaN");
+ return;
+ } else if (IsInfDouble(epd->type.value)) {
+ if (epd->type.bits.sign == 1)
+ sprintf(str, "-Inf");
+ else
+ sprintf(str, "Inf");
+ return;
+ }
+
+ assert(epd->type.bits.exponent == EPD_MAX_BIN ||
+ epd->type.bits.exponent == 0);
+
+ EpdGetValueAndDecimalExponent(epd, &value, &exponent);
+ sprintf(str, "%e", value);
+ pos = strstr(str, "e");
+ if (exponent >= 0) {
+ if (exponent < 10)
+ sprintf(pos + 1, "+0%d", exponent);
+ else
+ sprintf(pos + 1, "+%d", exponent);
+ } else {
+ exponent *= -1;
+ if (exponent < 10)
+ sprintf(pos + 1, "-0%d", exponent);
+ else
+ sprintf(pos + 1, "-%d", exponent);
+ }
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts double to EpDouble struct.]
+
+ Description [Converts double to EpDouble struct.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdConvert(double value, EpDouble *epd)
+{
+ epd->type.value = value;
+ epd->exponent = 0;
+ EpdNormalize(epd);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Multiplies two arbitrary precision double values.]
+
+ Description [Multiplies two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdMultiply(EpDouble *epd1, double value)
+{
+ EpDouble epd2;
+ double tmp;
+ int exponent;
+
+ if (EpdIsNan(epd1) || IsNanDouble(value)) {
+ EpdMakeNan(epd1);
+ return;
+ } else if (EpdIsInf(epd1) || IsInfDouble(value)) {
+ int sign;
+
+ EpdConvert(value, &epd2);
+ sign = epd1->type.bits.sign ^ epd2.type.bits.sign;
+ EpdMakeInf(epd1, sign);
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+
+ EpdConvert(value, &epd2);
+ tmp = epd1->type.value * epd2.type.value;
+ exponent = epd1->exponent + epd2.exponent;
+ epd1->type.value = tmp;
+ epd1->exponent = exponent;
+ EpdNormalize(epd1);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Multiplies two arbitrary precision double values.]
+
+ Description [Multiplies two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdMultiply2(EpDouble *epd1, EpDouble *epd2)
+{
+ double value;
+ int exponent;
+
+ if (EpdIsNan(epd1) || EpdIsNan(epd2)) {
+ EpdMakeNan(epd1);
+ return;
+ } else if (EpdIsInf(epd1) || EpdIsInf(epd2)) {
+ int sign;
+
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ EpdMakeInf(epd1, sign);
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+ assert(epd2->type.bits.exponent == EPD_MAX_BIN);
+
+ value = epd1->type.value * epd2->type.value;
+ exponent = epd1->exponent + epd2->exponent;
+ epd1->type.value = value;
+ epd1->exponent = exponent;
+ EpdNormalize(epd1);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Multiplies two arbitrary precision double values.]
+
+ Description [Multiplies two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdMultiply2Decimal(EpDouble *epd1, EpDouble *epd2)
+{
+ double value;
+ int exponent;
+
+ if (EpdIsNan(epd1) || EpdIsNan(epd2)) {
+ EpdMakeNan(epd1);
+ return;
+ } else if (EpdIsInf(epd1) || EpdIsInf(epd2)) {
+ int sign;
+
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ EpdMakeInf(epd1, sign);
+ return;
+ }
+
+ value = epd1->type.value * epd2->type.value;
+ exponent = epd1->exponent + epd2->exponent;
+ epd1->type.value = value;
+ epd1->exponent = exponent;
+ EpdNormalizeDecimal(epd1);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Multiplies two arbitrary precision double values.]
+
+ Description [Multiplies two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdMultiply3(EpDouble *epd1, EpDouble *epd2, EpDouble *epd3)
+{
+ if (EpdIsNan(epd1) || EpdIsNan(epd2)) {
+ EpdMakeNan(epd1);
+ return;
+ } else if (EpdIsInf(epd1) || EpdIsInf(epd2)) {
+ int sign;
+
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ EpdMakeInf(epd3, sign);
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+ assert(epd2->type.bits.exponent == EPD_MAX_BIN);
+
+ epd3->type.value = epd1->type.value * epd2->type.value;
+ epd3->exponent = epd1->exponent + epd2->exponent;
+ EpdNormalize(epd3);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Multiplies two arbitrary precision double values.]
+
+ Description [Multiplies two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdMultiply3Decimal(EpDouble *epd1, EpDouble *epd2, EpDouble *epd3)
+{
+ if (EpdIsNan(epd1) || EpdIsNan(epd2)) {
+ EpdMakeNan(epd1);
+ return;
+ } else if (EpdIsInf(epd1) || EpdIsInf(epd2)) {
+ int sign;
+
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ EpdMakeInf(epd3, sign);
+ return;
+ }
+
+ epd3->type.value = epd1->type.value * epd2->type.value;
+ epd3->exponent = epd1->exponent + epd2->exponent;
+ EpdNormalizeDecimal(epd3);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Divides two arbitrary precision double values.]
+
+ Description [Divides two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdDivide(EpDouble *epd1, double value)
+{
+ EpDouble epd2;
+ double tmp;
+ int exponent;
+
+ if (EpdIsNan(epd1) || IsNanDouble(value)) {
+ EpdMakeNan(epd1);
+ return;
+ } else if (EpdIsInf(epd1) || IsInfDouble(value)) {
+ int sign;
+
+ EpdConvert(value, &epd2);
+ if (EpdIsInf(epd1) && IsInfDouble(value)) {
+ EpdMakeNan(epd1);
+ } else if (EpdIsInf(epd1)) {
+ sign = epd1->type.bits.sign ^ epd2.type.bits.sign;
+ EpdMakeInf(epd1, sign);
+ } else {
+ sign = epd1->type.bits.sign ^ epd2.type.bits.sign;
+ EpdMakeZero(epd1, sign);
+ }
+ return;
+ }
+
+ if (value == 0.0) {
+ EpdMakeNan(epd1);
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+
+ EpdConvert(value, &epd2);
+ tmp = epd1->type.value / epd2.type.value;
+ exponent = epd1->exponent - epd2.exponent;
+ epd1->type.value = tmp;
+ epd1->exponent = exponent;
+ EpdNormalize(epd1);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Divides two arbitrary precision double values.]
+
+ Description [Divides two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdDivide2(EpDouble *epd1, EpDouble *epd2)
+{
+ double value;
+ int exponent;
+
+ if (EpdIsNan(epd1) || EpdIsNan(epd2)) {
+ EpdMakeNan(epd1);
+ return;
+ } else if (EpdIsInf(epd1) || EpdIsInf(epd2)) {
+ int sign;
+
+ if (EpdIsInf(epd1) && EpdIsInf(epd2)) {
+ EpdMakeNan(epd1);
+ } else if (EpdIsInf(epd1)) {
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ EpdMakeInf(epd1, sign);
+ } else {
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ EpdMakeZero(epd1, sign);
+ }
+ return;
+ }
+
+ if (epd2->type.value == 0.0) {
+ EpdMakeNan(epd1);
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+ assert(epd2->type.bits.exponent == EPD_MAX_BIN);
+
+ value = epd1->type.value / epd2->type.value;
+ exponent = epd1->exponent - epd2->exponent;
+ epd1->type.value = value;
+ epd1->exponent = exponent;
+ EpdNormalize(epd1);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Divides two arbitrary precision double values.]
+
+ Description [Divides two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdDivide3(EpDouble *epd1, EpDouble *epd2, EpDouble *epd3)
+{
+ if (EpdIsNan(epd1) || EpdIsNan(epd2)) {
+ EpdMakeNan(epd3);
+ return;
+ } else if (EpdIsInf(epd1) || EpdIsInf(epd2)) {
+ int sign;
+
+ if (EpdIsInf(epd1) && EpdIsInf(epd2)) {
+ EpdMakeNan(epd3);
+ } else if (EpdIsInf(epd1)) {
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ EpdMakeInf(epd3, sign);
+ } else {
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ EpdMakeZero(epd3, sign);
+ }
+ return;
+ }
+
+ if (epd2->type.value == 0.0) {
+ EpdMakeNan(epd3);
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+ assert(epd2->type.bits.exponent == EPD_MAX_BIN);
+
+ epd3->type.value = epd1->type.value / epd2->type.value;
+ epd3->exponent = epd1->exponent - epd2->exponent;
+ EpdNormalize(epd3);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Adds two arbitrary precision double values.]
+
+ Description [Adds two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdAdd(EpDouble *epd1, double value)
+{
+ EpDouble epd2;
+ double tmp;
+ int exponent, diff;
+
+ if (EpdIsNan(epd1) || IsNanDouble(value)) {
+ EpdMakeNan(epd1);
+ return;
+ } else if (EpdIsInf(epd1) || IsInfDouble(value)) {
+ int sign;
+
+ EpdConvert(value, &epd2);
+ if (EpdIsInf(epd1) && IsInfDouble(value)) {
+ sign = epd1->type.bits.sign ^ epd2.type.bits.sign;
+ if (sign == 1)
+ EpdMakeNan(epd1);
+ } else if (EpdIsInf(&epd2)) {
+ EpdCopy(&epd2, epd1);
+ }
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+
+ EpdConvert(value, &epd2);
+ if (epd1->exponent > epd2.exponent) {
+ diff = epd1->exponent - epd2.exponent;
+ if (diff <= EPD_MAX_BIN)
+ tmp = epd1->type.value + epd2.type.value / pow((double)2.0, (double)diff);
+ else
+ tmp = epd1->type.value;
+ exponent = epd1->exponent;
+ } else if (epd1->exponent < epd2.exponent) {
+ diff = epd2.exponent - epd1->exponent;
+ if (diff <= EPD_MAX_BIN)
+ tmp = epd1->type.value / pow((double)2.0, (double)diff) + epd2.type.value;
+ else
+ tmp = epd2.type.value;
+ exponent = epd2.exponent;
+ } else {
+ tmp = epd1->type.value + epd2.type.value;
+ exponent = epd1->exponent;
+ }
+ epd1->type.value = tmp;
+ epd1->exponent = exponent;
+ EpdNormalize(epd1);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Adds two arbitrary precision double values.]
+
+ Description [Adds two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdAdd2(EpDouble *epd1, EpDouble *epd2)
+{
+ double value;
+ int exponent, diff;
+
+ if (EpdIsNan(epd1) || EpdIsNan(epd2)) {
+ EpdMakeNan(epd1);
+ return;
+ } else if (EpdIsInf(epd1) || EpdIsInf(epd2)) {
+ int sign;
+
+ if (EpdIsInf(epd1) && EpdIsInf(epd2)) {
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ if (sign == 1)
+ EpdMakeNan(epd1);
+ } else if (EpdIsInf(epd2)) {
+ EpdCopy(epd2, epd1);
+ }
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+ assert(epd2->type.bits.exponent == EPD_MAX_BIN);
+
+ if (epd1->exponent > epd2->exponent) {
+ diff = epd1->exponent - epd2->exponent;
+ if (diff <= EPD_MAX_BIN) {
+ value = epd1->type.value +
+ epd2->type.value / pow((double)2.0, (double)diff);
+ } else
+ value = epd1->type.value;
+ exponent = epd1->exponent;
+ } else if (epd1->exponent < epd2->exponent) {
+ diff = epd2->exponent - epd1->exponent;
+ if (diff <= EPD_MAX_BIN) {
+ value = epd1->type.value / pow((double)2.0, (double)diff) +
+ epd2->type.value;
+ } else
+ value = epd2->type.value;
+ exponent = epd2->exponent;
+ } else {
+ value = epd1->type.value + epd2->type.value;
+ exponent = epd1->exponent;
+ }
+ epd1->type.value = value;
+ epd1->exponent = exponent;
+ EpdNormalize(epd1);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Adds two arbitrary precision double values.]
+
+ Description [Adds two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdAdd3(EpDouble *epd1, EpDouble *epd2, EpDouble *epd3)
+{
+ double value;
+ int exponent, diff;
+
+ if (EpdIsNan(epd1) || EpdIsNan(epd2)) {
+ EpdMakeNan(epd3);
+ return;
+ } else if (EpdIsInf(epd1) || EpdIsInf(epd2)) {
+ int sign;
+
+ if (EpdIsInf(epd1) && EpdIsInf(epd2)) {
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ if (sign == 1)
+ EpdMakeNan(epd3);
+ else
+ EpdCopy(epd1, epd3);
+ } else if (EpdIsInf(epd1)) {
+ EpdCopy(epd1, epd3);
+ } else {
+ EpdCopy(epd2, epd3);
+ }
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+ assert(epd2->type.bits.exponent == EPD_MAX_BIN);
+
+ if (epd1->exponent > epd2->exponent) {
+ diff = epd1->exponent - epd2->exponent;
+ if (diff <= EPD_MAX_BIN) {
+ value = epd1->type.value +
+ epd2->type.value / pow((double)2.0, (double)diff);
+ } else
+ value = epd1->type.value;
+ exponent = epd1->exponent;
+ } else if (epd1->exponent < epd2->exponent) {
+ diff = epd2->exponent - epd1->exponent;
+ if (diff <= EPD_MAX_BIN) {
+ value = epd1->type.value / pow((double)2.0, (double)diff) +
+ epd2->type.value;
+ } else
+ value = epd2->type.value;
+ exponent = epd2->exponent;
+ } else {
+ value = epd1->type.value + epd2->type.value;
+ exponent = epd1->exponent;
+ }
+ epd3->type.value = value;
+ epd3->exponent = exponent;
+ EpdNormalize(epd3);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Subtracts two arbitrary precision double values.]
+
+ Description [Subtracts two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdSubtract(EpDouble *epd1, double value)
+{
+ EpDouble epd2;
+ double tmp;
+ int exponent, diff;
+
+ if (EpdIsNan(epd1) || IsNanDouble(value)) {
+ EpdMakeNan(epd1);
+ return;
+ } else if (EpdIsInf(epd1) || IsInfDouble(value)) {
+ int sign;
+
+ EpdConvert(value, &epd2);
+ if (EpdIsInf(epd1) && IsInfDouble(value)) {
+ sign = epd1->type.bits.sign ^ epd2.type.bits.sign;
+ if (sign == 0)
+ EpdMakeNan(epd1);
+ } else if (EpdIsInf(&epd2)) {
+ EpdCopy(&epd2, epd1);
+ }
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+
+ EpdConvert(value, &epd2);
+ if (epd1->exponent > epd2.exponent) {
+ diff = epd1->exponent - epd2.exponent;
+ if (diff <= EPD_MAX_BIN)
+ tmp = epd1->type.value - epd2.type.value / pow((double)2.0, (double)diff);
+ else
+ tmp = epd1->type.value;
+ exponent = epd1->exponent;
+ } else if (epd1->exponent < epd2.exponent) {
+ diff = epd2.exponent - epd1->exponent;
+ if (diff <= EPD_MAX_BIN)
+ tmp = epd1->type.value / pow((double)2.0, (double)diff) - epd2.type.value;
+ else
+ tmp = epd2.type.value * (double)(-1.0);
+ exponent = epd2.exponent;
+ } else {
+ tmp = epd1->type.value - epd2.type.value;
+ exponent = epd1->exponent;
+ }
+ epd1->type.value = tmp;
+ epd1->exponent = exponent;
+ EpdNormalize(epd1);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Subtracts two arbitrary precision double values.]
+
+ Description [Subtracts two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdSubtract2(EpDouble *epd1, EpDouble *epd2)
+{
+ double value;
+ int exponent, diff;
+
+ if (EpdIsNan(epd1) || EpdIsNan(epd2)) {
+ EpdMakeNan(epd1);
+ return;
+ } else if (EpdIsInf(epd1) || EpdIsInf(epd2)) {
+ int sign;
+
+ if (EpdIsInf(epd1) && EpdIsInf(epd2)) {
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ if (sign == 0)
+ EpdMakeNan(epd1);
+ } else if (EpdIsInf(epd2)) {
+ EpdCopy(epd2, epd1);
+ }
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+ assert(epd2->type.bits.exponent == EPD_MAX_BIN);
+
+ if (epd1->exponent > epd2->exponent) {
+ diff = epd1->exponent - epd2->exponent;
+ if (diff <= EPD_MAX_BIN) {
+ value = epd1->type.value -
+ epd2->type.value / pow((double)2.0, (double)diff);
+ } else
+ value = epd1->type.value;
+ exponent = epd1->exponent;
+ } else if (epd1->exponent < epd2->exponent) {
+ diff = epd2->exponent - epd1->exponent;
+ if (diff <= EPD_MAX_BIN) {
+ value = epd1->type.value / pow((double)2.0, (double)diff) -
+ epd2->type.value;
+ } else
+ value = epd2->type.value * (double)(-1.0);
+ exponent = epd2->exponent;
+ } else {
+ value = epd1->type.value - epd2->type.value;
+ exponent = epd1->exponent;
+ }
+ epd1->type.value = value;
+ epd1->exponent = exponent;
+ EpdNormalize(epd1);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Subtracts two arbitrary precision double values.]
+
+ Description [Subtracts two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdSubtract3(EpDouble *epd1, EpDouble *epd2, EpDouble *epd3)
+{
+ double value;
+ int exponent, diff;
+
+ if (EpdIsNan(epd1) || EpdIsNan(epd2)) {
+ EpdMakeNan(epd3);
+ return;
+ } else if (EpdIsInf(epd1) || EpdIsInf(epd2)) {
+ int sign;
+
+ if (EpdIsInf(epd1) && EpdIsInf(epd2)) {
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ if (sign == 0)
+ EpdCopy(epd1, epd3);
+ else
+ EpdMakeNan(epd3);
+ } else if (EpdIsInf(epd1)) {
+ EpdCopy(epd1, epd1);
+ } else {
+ sign = epd2->type.bits.sign ^ 0x1;
+ EpdMakeInf(epd3, sign);
+ }
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+ assert(epd2->type.bits.exponent == EPD_MAX_BIN);
+
+ if (epd1->exponent > epd2->exponent) {
+ diff = epd1->exponent - epd2->exponent;
+ if (diff <= EPD_MAX_BIN) {
+ value = epd1->type.value -
+ epd2->type.value / pow((double)2.0, (double)diff);
+ } else
+ value = epd1->type.value;
+ exponent = epd1->exponent;
+ } else if (epd1->exponent < epd2->exponent) {
+ diff = epd2->exponent - epd1->exponent;
+ if (diff <= EPD_MAX_BIN) {
+ value = epd1->type.value / pow((double)2.0, (double)diff) -
+ epd2->type.value;
+ } else
+ value = epd2->type.value * (double)(-1.0);
+ exponent = epd2->exponent;
+ } else {
+ value = epd1->type.value - epd2->type.value;
+ exponent = epd1->exponent;
+ }
+ epd3->type.value = value;
+ epd3->exponent = exponent;
+ EpdNormalize(epd3);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes arbitrary precision pow of base 2.]
+
+ Description [Computes arbitrary precision pow of base 2.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdPow2(int n, EpDouble *epd)
+{
+ if (n <= EPD_MAX_BIN) {
+ EpdConvert(pow((double)2.0, (double)n), epd);
+ } else {
+ EpDouble epd1, epd2;
+ int n1, n2;
+
+ n1 = n / 2;
+ n2 = n - n1;
+ EpdPow2(n1, &epd1);
+ EpdPow2(n2, &epd2);
+ EpdMultiply3(&epd1, &epd2, epd);
+ }
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes arbitrary precision pow of base 2.]
+
+ Description [Computes arbitrary precision pow of base 2.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdPow2Decimal(int n, EpDouble *epd)
+{
+ if (n <= EPD_MAX_BIN) {
+ epd->type.value = pow((double)2.0, (double)n);
+ epd->exponent = 0;
+ EpdNormalizeDecimal(epd);
+ } else {
+ EpDouble epd1, epd2;
+ int n1, n2;
+
+ n1 = n / 2;
+ n2 = n - n1;
+ EpdPow2Decimal(n1, &epd1);
+ EpdPow2Decimal(n2, &epd2);
+ EpdMultiply3Decimal(&epd1, &epd2, epd);
+ }
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Normalize an arbitrary precision double value.]
+
+ Description [Normalize an arbitrary precision double value.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdNormalize(EpDouble *epd)
+{
+ int exponent;
+
+ if (IsNanOrInfDouble(epd->type.value)) {
+ epd->exponent = 0;
+ return;
+ }
+
+ exponent = EpdGetExponent(epd->type.value);
+ if (exponent == EPD_MAX_BIN)
+ return;
+ exponent -= EPD_MAX_BIN;
+ epd->type.bits.exponent = EPD_MAX_BIN;
+ epd->exponent += exponent;
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Normalize an arbitrary precision double value.]
+
+ Description [Normalize an arbitrary precision double value.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdNormalizeDecimal(EpDouble *epd)
+{
+ int exponent;
+
+ if (IsNanOrInfDouble(epd->type.value)) {
+ epd->exponent = 0;
+ return;
+ }
+
+ exponent = EpdGetExponentDecimal(epd->type.value);
+ epd->type.value /= pow((double)10.0, (double)exponent);
+ epd->exponent += exponent;
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns value and decimal exponent of EpDouble.]
+
+ Description [Returns value and decimal exponent of EpDouble.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdGetValueAndDecimalExponent(EpDouble *epd, double *value, int *exponent)
+{
+ EpDouble epd1, epd2;
+
+ if (EpdIsNanOrInf(epd))
+ return;
+
+ if (EpdIsZero(epd)) {
+ *value = 0.0;
+ *exponent = 0;
+ return;
+ }
+
+ epd1.type.value = epd->type.value;
+ epd1.exponent = 0;
+ EpdPow2Decimal(epd->exponent, &epd2);
+ EpdMultiply2Decimal(&epd1, &epd2);
+
+ *value = epd1.type.value;
+ *exponent = epd1.exponent;
+}
+
+/**Function********************************************************************
+
+ Synopsis [Returns the exponent value of a double.]
+
+ Description [Returns the exponent value of a double.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+EpdGetExponent(double value)
+{
+ int exponent;
+ EpDouble epd;
+
+ epd.type.value = value;
+ exponent = epd.type.bits.exponent;
+ return(exponent);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the decimal exponent value of a double.]
+
+ Description [Returns the decimal exponent value of a double.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+EpdGetExponentDecimal(double value)
+{
+ char *pos, str[24];
+ int exponent;
+
+ sprintf(str, "%E", value);
+ pos = strstr(str, "E");
+ sscanf(pos, "E%d", &exponent);
+ return(exponent);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Makes EpDouble Inf.]
+
+ Description [Makes EpDouble Inf.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdMakeInf(EpDouble *epd, int sign)
+{
+ epd->type.bits.mantissa1 = 0;
+ epd->type.bits.mantissa0 = 0;
+ epd->type.bits.exponent = EPD_EXP_INF;
+ epd->type.bits.sign = sign;
+ epd->exponent = 0;
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Makes EpDouble Zero.]
+
+ Description [Makes EpDouble Zero.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdMakeZero(EpDouble *epd, int sign)
+{
+ epd->type.bits.mantissa1 = 0;
+ epd->type.bits.mantissa0 = 0;
+ epd->type.bits.exponent = 0;
+ epd->type.bits.sign = sign;
+ epd->exponent = 0;
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Makes EpDouble NaN.]
+
+ Description [Makes EpDouble NaN.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdMakeNan(EpDouble *epd)
+{
+ epd->type.nan.mantissa1 = 0;
+ epd->type.nan.mantissa0 = 0;
+ epd->type.nan.quiet_bit = 1;
+ epd->type.nan.exponent = EPD_EXP_INF;
+ epd->type.nan.sign = 1;
+ epd->exponent = 0;
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Copies a EpDouble struct.]
+
+ Description [Copies a EpDouble struct.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdCopy(EpDouble *from, EpDouble *to)
+{
+ to->type.value = from->type.value;
+ to->exponent = from->exponent;
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether the value is Inf.]
+
+ Description [Checks whether the value is Inf.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+EpdIsInf(EpDouble *epd)
+{
+ return(IsInfDouble(epd->type.value));
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether the value is Zero.]
+
+ Description [Checks whether the value is Zero.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+EpdIsZero(EpDouble *epd)
+{
+ if (epd->type.value == 0.0)
+ return(1);
+ else
+ return(0);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether the value is NaN.]
+
+ Description [Checks whether the value is NaN.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+EpdIsNan(EpDouble *epd)
+{
+ return(IsNanDouble(epd->type.value));
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether the value is NaN or Inf.]
+
+ Description [Checks whether the value is NaN or Inf.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+EpdIsNanOrInf(EpDouble *epd)
+{
+ return(IsNanOrInfDouble(epd->type.value));
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether the value is Inf.]
+
+ Description [Checks whether the value is Inf.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+IsInfDouble(double value)
+{
+ IeeeDouble *ptr = (IeeeDouble *)(&value);
+
+ if (ptr->exponent == EPD_EXP_INF &&
+ ptr->mantissa0 == 0 &&
+ ptr->mantissa1 == 0) {
+ if (ptr->sign == 0)
+ return(1);
+ else
+ return(-1);
+ }
+ return(0);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether the value is NaN.]
+
+ Description [Checks whether the value is NaN.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+IsNanDouble(double value)
+{
+ IeeeNan *ptr = (IeeeNan *)(&value);
+
+ if (ptr->exponent == EPD_EXP_INF &&
+ ptr->sign == 1 &&
+ ptr->quiet_bit == 1 &&
+ ptr->mantissa0 == 0 &&
+ ptr->mantissa1 == 0) {
+ return(1);
+ }
+ return(0);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether the value is NaN or Inf.]
+
+ Description [Checks whether the value is NaN or Inf.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+IsNanOrInfDouble(double value)
+{
+ IeeeNan *ptr = (IeeeNan *)(&value);
+
+ if (ptr->exponent == EPD_EXP_INF &&
+ ptr->mantissa0 == 0 &&
+ ptr->mantissa1 == 0 &&
+ (ptr->sign == 1 || ptr->quiet_bit == 0)) {
+ return(1);
+ }
+ return(0);
+}
diff --git a/src/bdd/epd/epd.h b/src/bdd/epd/epd.h
new file mode 100644
index 00000000..66db80e3
--- /dev/null
+++ b/src/bdd/epd/epd.h
@@ -0,0 +1,160 @@
+/**CHeaderFile*****************************************************************
+
+ FileName [epd.h]
+
+ PackageName [epd]
+
+ Synopsis [The University of Colorado extended double precision package.]
+
+ Description [arithmetic functions with extended double precision.]
+
+ SeeAlso []
+
+ Author [In-Ho Moon]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+ Revision [$Id: epd.h,v 1.1.1.1 2003/02/24 22:23:57 wjiang Exp $]
+
+******************************************************************************/
+
+#ifndef _EPD
+#define _EPD
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define EPD_MAX_BIN 1023
+#define EPD_MAX_DEC 308
+#define EPD_EXP_INF 0x7ff
+
+/*---------------------------------------------------------------------------*/
+/* Structure declarations */
+/*---------------------------------------------------------------------------*/
+
+/**Struct**********************************************************************
+
+ Synopsis [IEEE double struct.]
+
+ Description [IEEE double struct.]
+
+ SeeAlso []
+
+******************************************************************************/
+#ifdef EPD_BIG_ENDIAN
+struct IeeeDoubleStruct { /* BIG_ENDIAN */
+ unsigned int sign: 1;
+ unsigned int exponent: 11;
+ unsigned int mantissa0: 20;
+ unsigned int mantissa1: 32;
+};
+#else
+struct IeeeDoubleStruct { /* LITTLE_ENDIAN */
+ unsigned int mantissa1: 32;
+ unsigned int mantissa0: 20;
+ unsigned int exponent: 11;
+ unsigned int sign: 1;
+};
+#endif
+
+/**Struct**********************************************************************
+
+ Synopsis [IEEE double NaN struct.]
+
+ Description [IEEE double NaN struct.]
+
+ SeeAlso []
+
+******************************************************************************/
+#ifdef EPD_BIG_ENDIAN
+struct IeeeNanStruct { /* BIG_ENDIAN */
+ unsigned int sign: 1;
+ unsigned int exponent: 11;
+ unsigned int quiet_bit: 1;
+ unsigned int mantissa0: 19;
+ unsigned int mantissa1: 32;
+};
+#else
+struct IeeeNanStruct { /* LITTLE_ENDIAN */
+ unsigned int mantissa1: 32;
+ unsigned int mantissa0: 19;
+ unsigned int quiet_bit: 1;
+ unsigned int exponent: 11;
+ unsigned int sign: 1;
+};
+#endif
+
+/**Struct**********************************************************************
+
+ Synopsis [Extended precision double to keep very large value.]
+
+ Description [Extended precision double to keep very large value.]
+
+ SeeAlso []
+
+******************************************************************************/
+struct EpDoubleStruct {
+ union {
+ double value;
+ struct IeeeDoubleStruct bits;
+ struct IeeeNanStruct nan;
+ } type;
+ int exponent;
+};
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+typedef struct EpDoubleStruct EpDouble;
+typedef struct IeeeDoubleStruct IeeeDouble;
+typedef struct IeeeNanStruct IeeeNan;
+
+
+/*---------------------------------------------------------------------------*/
+/* Function prototypes */
+/*---------------------------------------------------------------------------*/
+
+EpDouble *EpdAlloc();
+int EpdCmp(const char *key1, const char *key2);
+void EpdFree(EpDouble *epd);
+void EpdGetString(EpDouble *epd, char *str);
+void EpdConvert(double value, EpDouble *epd);
+void EpdMultiply(EpDouble *epd1, double value);
+void EpdMultiply2(EpDouble *epd1, EpDouble *epd2);
+void EpdMultiply2Decimal(EpDouble *epd1, EpDouble *epd2);
+void EpdMultiply3(EpDouble *epd1, EpDouble *epd2, EpDouble *epd3);
+void EpdMultiply3Decimal(EpDouble *epd1, EpDouble *epd2, EpDouble *epd3);
+void EpdDivide(EpDouble *epd1, double value);
+void EpdDivide2(EpDouble *epd1, EpDouble *epd2);
+void EpdDivide3(EpDouble *epd1, EpDouble *epd2, EpDouble *epd3);
+void EpdAdd(EpDouble *epd1, double value);
+void EpdAdd2(EpDouble *epd1, EpDouble *epd2);
+void EpdAdd3(EpDouble *epd1, EpDouble *epd2, EpDouble *epd3);
+void EpdSubtract(EpDouble *epd1, double value);
+void EpdSubtract2(EpDouble *epd1, EpDouble *epd2);
+void EpdSubtract3(EpDouble *epd1, EpDouble *epd2, EpDouble *epd3);
+void EpdPow2(int n, EpDouble *epd);
+void EpdPow2Decimal(int n, EpDouble *epd);
+void EpdNormalize(EpDouble *epd);
+void EpdNormalizeDecimal(EpDouble *epd);
+void EpdGetValueAndDecimalExponent(EpDouble *epd, double *value, int *exponent);
+int EpdGetExponent(double value);
+int EpdGetExponentDecimal(double value);
+void EpdMakeInf(EpDouble *epd, int sign);
+void EpdMakeZero(EpDouble *epd, int sign);
+void EpdMakeNan(EpDouble *epd);
+void EpdCopy(EpDouble *from, EpDouble *to);
+int EpdIsInf(EpDouble *epd);
+int EpdIsZero(EpDouble *epd);
+int EpdIsNan(EpDouble *epd);
+int EpdIsNanOrInf(EpDouble *epd);
+int IsInfDouble(double value);
+int IsNanDouble(double value);
+int IsNanOrInfDouble(double value);
+
+#endif /* _EPD */
diff --git a/src/bdd/epd/module.make b/src/bdd/epd/module.make
new file mode 100644
index 00000000..a8084db1
--- /dev/null
+++ b/src/bdd/epd/module.make
@@ -0,0 +1 @@
+SRC += src/bdd/epd/epd.c
diff --git a/src/bdd/mtr/module.make b/src/bdd/mtr/module.make
new file mode 100644
index 00000000..d7fa63d9
--- /dev/null
+++ b/src/bdd/mtr/module.make
@@ -0,0 +1,2 @@
+SRC += src/bdd/mtr/mtrBasic.c \
+ src/bdd/mtr/mtrGroup.c
diff --git a/src/bdd/mtr/mtr.h b/src/bdd/mtr/mtr.h
new file mode 100644
index 00000000..201329ae
--- /dev/null
+++ b/src/bdd/mtr/mtr.h
@@ -0,0 +1,173 @@
+/**CHeaderFile*****************************************************************
+
+ FileName [mtr.h]
+
+ PackageName [mtr]
+
+ Synopsis [Multiway-branch tree manipulation]
+
+ Description [This package provides two layers of functions. Functions
+ of the lower level manipulate multiway-branch trees, implemented
+ according to the classical scheme whereby each node points to its
+ first child and its previous and next siblings. These functions are
+ collected in mtrBasic.c.<p>
+ Functions of the upper layer deal with group trees, that is the trees
+ used by group sifting to represent the grouping of variables. These
+ functions are collected in mtrGroup.c.]
+
+ SeeAlso [The CUDD package documentation; specifically on group
+ sifting.]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+ Revision [$Id: mtr.h,v 1.1.1.1 2003/02/24 22:24:02 wjiang Exp $]
+
+******************************************************************************/
+
+#ifndef __MTR
+#define __MTR
+
+/*---------------------------------------------------------------------------*/
+/* Nested includes */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef SIZEOF_VOID_P
+#define SIZEOF_VOID_P 4
+#endif
+#ifndef SIZEOF_INT
+#define SIZEOF_INT 4
+#endif
+
+#undef CONST
+#if defined(__STDC__) || defined(__cplusplus)
+#define CONST const
+#else /* !(__STDC__ || __cplusplus) */
+#define CONST
+#endif /* !(__STDC__ || __cplusplus) */
+
+/* These are potential duplicates. */
+#ifndef EXTERN
+# ifdef __cplusplus
+# define EXTERN extern "C"
+# else
+# define EXTERN extern
+# endif
+#endif
+#ifndef ARGS
+# if defined(__STDC__) || defined(__cplusplus)
+# define ARGS(protos) protos /* ANSI C */
+# else /* !(__STDC__ || __cplusplus) */
+# define ARGS(protos) () /* K&R C */
+# endif /* !(__STDC__ || __cplusplus) */
+#endif
+
+#if defined(__GNUC__)
+#define MTR_INLINE __inline__
+# if (__GNUC__ >2 || __GNUC_MINOR__ >=7)
+# define MTR_UNUSED __attribute__ ((unused))
+# else
+# define MTR_UNUSED
+# endif
+#else
+#define MTR_INLINE
+#define MTR_UNUSED
+#endif
+
+/* Flag definitions */
+#define MTR_DEFAULT 0x00000000
+#define MTR_TERMINAL 0x00000001
+#define MTR_SOFT 0x00000002
+#define MTR_FIXED 0x00000004
+#define MTR_NEWNODE 0x00000008
+
+/* MTR_MAXHIGH is defined in such a way that on 32-bit and 64-bit
+** machines one can cast a value to (int) without generating a negative
+** number.
+*/
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+#define MTR_MAXHIGH (((MtrHalfWord) ~0) >> 1)
+#else
+#define MTR_MAXHIGH ((MtrHalfWord) ~0)
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+typedef unsigned int MtrHalfWord;
+#else
+typedef unsigned short MtrHalfWord;
+#endif
+
+typedef struct MtrNode {
+ MtrHalfWord flags;
+ MtrHalfWord low;
+ MtrHalfWord size;
+ MtrHalfWord index;
+ struct MtrNode *parent;
+ struct MtrNode *child;
+ struct MtrNode *elder;
+ struct MtrNode *younger;
+} MtrNode;
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/* Flag manipulation macros */
+#define MTR_SET(node, flag) (node->flags |= (flag))
+#define MTR_RESET(node, flag) (node->flags &= ~ (flag))
+#define MTR_TEST(node, flag) (node->flags & (flag))
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Function prototypes */
+/*---------------------------------------------------------------------------*/
+
+EXTERN MtrNode * Mtr_AllocNode ARGS(());
+EXTERN void Mtr_DeallocNode ARGS((MtrNode *node));
+EXTERN MtrNode * Mtr_InitTree ARGS(());
+EXTERN void Mtr_FreeTree ARGS((MtrNode *node));
+EXTERN MtrNode * Mtr_CopyTree ARGS((MtrNode *node, int expansion));
+EXTERN void Mtr_MakeFirstChild ARGS((MtrNode *parent, MtrNode *child));
+EXTERN void Mtr_MakeLastChild ARGS((MtrNode *parent, MtrNode *child));
+EXTERN MtrNode * Mtr_CreateFirstChild ARGS((MtrNode *parent));
+EXTERN MtrNode * Mtr_CreateLastChild ARGS((MtrNode *parent));
+EXTERN void Mtr_MakeNextSibling ARGS((MtrNode *first, MtrNode *second));
+EXTERN void Mtr_PrintTree ARGS((MtrNode *node));
+EXTERN MtrNode * Mtr_InitGroupTree ARGS((int lower, int size));
+EXTERN MtrNode * Mtr_MakeGroup ARGS((MtrNode *root, unsigned int low, unsigned int high, unsigned int flags));
+EXTERN MtrNode * Mtr_DissolveGroup ARGS((MtrNode *group));
+EXTERN MtrNode * Mtr_FindGroup ARGS((MtrNode *root, unsigned int low, unsigned int high));
+EXTERN int Mtr_SwapGroups ARGS((MtrNode *first, MtrNode *second));
+EXTERN void Mtr_PrintGroups ARGS((MtrNode *root, int silent));
+EXTERN MtrNode * Mtr_ReadGroups ARGS((FILE *fp, int nleaves));
+
+/**AutomaticEnd***************************************************************/
+
+#endif /* __MTR */
diff --git a/src/bdd/mtr/mtrBasic.c b/src/bdd/mtr/mtrBasic.c
new file mode 100644
index 00000000..2aec8d6b
--- /dev/null
+++ b/src/bdd/mtr/mtrBasic.c
@@ -0,0 +1,426 @@
+/**CFile***********************************************************************
+
+ FileName [mtrBasic.c]
+
+ PackageName [mtr]
+
+ Synopsis [Basic manipulation of multiway branching trees.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Mtr_AllocNode()
+ <li> Mtr_DeallocNode()
+ <li> Mtr_InitTree()
+ <li> Mtr_FreeTree()
+ <li> Mtr_CopyTree()
+ <li> Mtr_MakeFirstChild()
+ <li> Mtr_MakeLastChild()
+ <li> Mtr_CreateFirstChild()
+ <li> Mtr_CreateLastChild()
+ <li> Mtr_MakeNextSibling()
+ <li> Mtr_PrintTree()
+ </ul>
+ ]
+
+ SeeAlso [cudd package]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "mtrInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] MTR_UNUSED = "$Id: mtrBasic.c,v 1.1.1.1 2003/02/24 22:24:02 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Allocates new tree node.]
+
+ Description [Allocates new tree node. Returns pointer to node.]
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_DeallocNode]
+
+******************************************************************************/
+MtrNode *
+Mtr_AllocNode(
+ )
+{
+ MtrNode *node;
+
+ node = ALLOC(MtrNode,1);
+ return node;
+
+} /* Mtr_AllocNode */
+
+
+/**Function********************************************************************
+
+ Synopsis [Deallocates tree node.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_AllocNode]
+
+******************************************************************************/
+void
+Mtr_DeallocNode(
+ MtrNode * node /* node to be deallocated */)
+{
+ FREE(node);
+ return;
+
+} /* end of Mtr_DeallocNode */
+
+
+/**Function********************************************************************
+
+ Synopsis [Initializes tree with one node.]
+
+ Description [Initializes tree with one node. Returns pointer to node.]
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_FreeTree Mtr_InitGroupTree]
+
+******************************************************************************/
+MtrNode *
+Mtr_InitTree(
+ )
+{
+ MtrNode *node;
+
+ node = Mtr_AllocNode();
+ if (node == NULL) return(NULL);
+
+ node->parent = node->child = node->elder = node->younger = NULL;
+ node->flags = 0;
+
+ return(node);
+
+} /* end of Mtr_InitTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Disposes of tree rooted at node.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_InitTree]
+
+******************************************************************************/
+void
+Mtr_FreeTree(
+ MtrNode * node)
+{
+ if (node == NULL) return;
+ if (! MTR_TEST(node,MTR_TERMINAL)) Mtr_FreeTree(node->child);
+ Mtr_FreeTree(node->younger);
+ Mtr_DeallocNode(node);
+ return;
+
+} /* end of Mtr_FreeTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Makes a copy of tree.]
+
+ Description [Makes a copy of tree. If parameter expansion is greater
+ than 1, it will expand the tree by that factor. It is an error for
+ expansion to be less than 1. Returns a pointer to the copy if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_InitTree]
+
+******************************************************************************/
+MtrNode *
+Mtr_CopyTree(
+ MtrNode * node,
+ int expansion)
+{
+ MtrNode *copy;
+
+ if (node == NULL) return(NULL);
+ if (expansion < 1) return(NULL);
+ copy = Mtr_AllocNode();
+ if (copy == NULL) return(NULL);
+ copy->parent = copy->elder = copy->child = copy->younger = NULL;
+ if (node->child != NULL) {
+ copy->child = Mtr_CopyTree(node->child, expansion);
+ if (copy->child == NULL) {
+ Mtr_DeallocNode(copy);
+ return(NULL);
+ }
+ }
+ if (node->younger != NULL) {
+ copy->younger = Mtr_CopyTree(node->younger, expansion);
+ if (copy->younger == NULL) {
+ Mtr_FreeTree(copy);
+ return(NULL);
+ }
+ }
+ copy->flags = node->flags;
+ copy->low = node->low * expansion;
+ copy->size = node->size * expansion;
+ copy->index = node->index * expansion;
+ if (copy->younger) copy->younger->elder = copy;
+ if (copy->child) {
+ MtrNode *auxnode = copy->child;
+ while (auxnode != NULL) {
+ auxnode->parent = copy;
+ auxnode = auxnode->younger;
+ }
+ }
+ return(copy);
+
+} /* end of Mtr_CopyTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Makes child the first child of parent.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_MakeLastChild Mtr_CreateFirstChild]
+
+******************************************************************************/
+void
+Mtr_MakeFirstChild(
+ MtrNode * parent,
+ MtrNode * child)
+{
+ child->parent = parent;
+ child->younger = parent->child;
+ child->elder = NULL;
+ if (parent->child != NULL) {
+#ifdef MTR_DEBUG
+ assert(parent->child->elder == NULL);
+#endif
+ parent->child->elder = child;
+ }
+ parent->child = child;
+ return;
+
+} /* end of Mtr_MakeFirstChild */
+
+
+/**Function********************************************************************
+
+ Synopsis [Makes child the last child of parent.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_MakeFirstChild Mtr_CreateLastChild]
+
+******************************************************************************/
+void
+Mtr_MakeLastChild(
+ MtrNode * parent,
+ MtrNode * child)
+{
+ MtrNode *node;
+
+ child->younger = NULL;
+
+ if (parent->child == NULL) {
+ parent->child = child;
+ child->elder = NULL;
+ } else {
+ for (node = parent->child;
+ node->younger != NULL;
+ node = node->younger);
+ node->younger = child;
+ child->elder = node;
+ }
+ child->parent = parent;
+ return;
+
+} /* end of Mtr_MakeLastChild */
+
+
+/**Function********************************************************************
+
+ Synopsis [Creates a new node and makes it the first child of parent.]
+
+ Description [Creates a new node and makes it the first child of
+ parent. Returns pointer to new child.]
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_MakeFirstChild Mtr_CreateLastChild]
+
+******************************************************************************/
+MtrNode *
+Mtr_CreateFirstChild(
+ MtrNode * parent)
+{
+ MtrNode *child;
+
+ child = Mtr_AllocNode();
+ if (child == NULL) return(NULL);
+
+ child->child = child->younger = child-> elder = NULL;
+ child->flags = 0;
+ Mtr_MakeFirstChild(parent,child);
+ return(child);
+
+} /* end of Mtr_CreateFirstChild */
+
+
+/**Function********************************************************************
+
+ Synopsis [Creates a new node and makes it the last child of parent.]
+
+ Description [Creates a new node and makes it the last child of parent.
+ Returns pointer to new child.]
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_MakeLastChild Mtr_CreateFirstChild]
+
+******************************************************************************/
+MtrNode *
+Mtr_CreateLastChild(
+ MtrNode * parent)
+{
+ MtrNode *child;
+
+ child = Mtr_AllocNode();
+ if (child == NULL) return(NULL);
+
+ child->child = child->younger = child->elder = NULL;
+ child->flags = 0;
+ Mtr_MakeLastChild(parent,child);
+ return(child);
+
+} /* end of Mtr_CreateLastChild */
+
+
+/**Function********************************************************************
+
+ Synopsis [Makes second the next sibling of first.]
+
+ Description [Makes second the next sibling of first. Second becomes a
+ child of the parent of first.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+Mtr_MakeNextSibling(
+ MtrNode * first,
+ MtrNode * second)
+{
+ second->younger = first->younger;
+ if (first->younger != NULL) {
+ first->younger->elder = second;
+ }
+ second->parent = first->parent;
+ first->younger = second;
+ second->elder = first;
+ return;
+
+} /* end of Mtr_MakeNextSibling */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints a tree, one node per line.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_PrintGroups]
+
+******************************************************************************/
+void
+Mtr_PrintTree(
+ MtrNode * node)
+{
+ if (node == NULL) return;
+ (void) fprintf(stdout,
+#if SIZEOF_VOID_P == 8
+ "N=0x%-8lx C=0x%-8lx Y=0x%-8lx E=0x%-8lx P=0x%-8lx F=%x L=%d S=%d\n",
+ (unsigned long) node, (unsigned long) node->child,
+ (unsigned long) node->younger, (unsigned long) node->elder,
+ (unsigned long) node->parent, node->flags, node->low, node->size);
+#else
+ "N=0x%-8x C=0x%-8x Y=0x%-8x E=0x%-8x P=0x%-8x F=%x L=%d S=%d\n",
+ (unsigned) node, (unsigned) node->child,
+ (unsigned) node->younger, (unsigned) node->elder,
+ (unsigned) node->parent, node->flags, node->low, node->size);
+#endif
+ if (!MTR_TEST(node,MTR_TERMINAL)) Mtr_PrintTree(node->child);
+ Mtr_PrintTree(node->younger);
+ return;
+
+} /* end of Mtr_PrintTree */
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/mtr/mtrGroup.c b/src/bdd/mtr/mtrGroup.c
new file mode 100644
index 00000000..ae9c5c2f
--- /dev/null
+++ b/src/bdd/mtr/mtrGroup.c
@@ -0,0 +1,690 @@
+/**CFile***********************************************************************
+
+ FileName [mtrGroup.c]
+
+ PackageName [mtr]
+
+ Synopsis [Functions to support group specification for reordering.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Mtr_InitGroupTree()
+ <li> Mtr_MakeGroup()
+ <li> Mtr_DissolveGroup()
+ <li> Mtr_FindGroup()
+ <li> Mtr_SwapGroups()
+ <li> Mtr_PrintGroups()
+ <li> Mtr_ReadGroups()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> mtrShiftHL
+ </ul>
+ ]
+
+ SeeAlso [cudd package]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "mtrInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] MTR_UNUSED = "$Id: mtrGroup.c,v 1.1.1.1 2003/02/24 22:24:02 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int mtrShiftHL ARGS((MtrNode *node, int shift));
+
+/**AutomaticEnd***************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Allocate new tree.]
+
+ Description [Allocate new tree with one node, whose low and size
+ fields are specified by the lower and size parameters.
+ Returns pointer to tree root.]
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_InitTree Mtr_FreeTree]
+
+******************************************************************************/
+MtrNode *
+Mtr_InitGroupTree(
+ int lower,
+ int size)
+{
+ MtrNode *root;
+
+ root = Mtr_InitTree();
+ if (root == NULL) return(NULL);
+ root->flags = MTR_DEFAULT;
+ root->low = lower;
+ root->size = size;
+ return(root);
+
+} /* end of Mtr_InitGroupTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Makes a new group with size leaves starting at low.]
+
+ Description [Makes a new group with size leaves starting at low.
+ If the new group intersects an existing group, it must
+ either contain it or be contained by it. This procedure relies on
+ the low and size fields of each node. It also assumes that the
+ children of each node are sorted in order of increasing low. In
+ case of a valid request, the flags of the new group are set to the
+ value passed in `flags.' This can also be used to change the flags
+ of an existing group. Returns the pointer to the root of the new
+ group upon successful termination; NULL otherwise. If the group
+ already exists, the pointer to its root is returned.]
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_DissolveGroup Mtr_ReadGroups Mtr_FindGroup]
+
+******************************************************************************/
+MtrNode *
+Mtr_MakeGroup(
+ MtrNode * root /* root of the group tree */,
+ unsigned int low /* lower bound of the group */,
+ unsigned int size /* upper bound of the group */,
+ unsigned int flags /* flags for the new group */)
+{
+ MtrNode *node,
+ *first,
+ *last,
+ *previous,
+ *newn;
+
+ /* Sanity check. */
+ if (size == 0)
+ return(NULL);
+
+ /* Check whether current group includes new group. This check is
+ ** necessary at the top-level call. In the subsequent calls it is
+ ** redundant. */
+ if (low < (unsigned int) root->low ||
+ low + size > (unsigned int) (root->low + root->size))
+ return(NULL);
+
+ /* Trying to create an existing group has the effect of updating
+ ** the flags. */
+ if (root->size == size && root->low == low) {
+ root->flags = flags;
+ return(root);
+ }
+
+ /* At this point we know that the new group is properly contained
+ ** in the group of root. We have two possible cases here: - root
+ ** is a terminal node; - root has children. */
+
+ /* Root has no children: create a new group. */
+ if (root->child == NULL) {
+ newn = Mtr_AllocNode();
+ if (newn == NULL) return(NULL); /* out of memory */
+ newn->low = low;
+ newn->size = size;
+ newn->flags = flags;
+ newn->parent = root;
+ newn->elder = newn->younger = newn->child = NULL;
+ root->child = newn;
+ return(newn);
+ }
+
+ /* Root has children: Find all chidren of root that are included
+ ** in the new group. If the group of any child entirely contains
+ ** the new group, call Mtr_MakeGroup recursively. */
+ previous = NULL;
+ first = root->child; /* guaranteed to be non-NULL */
+ while (first != NULL && low >= (unsigned int) (first->low + first->size)) {
+ previous = first;
+ first = first->younger;
+ }
+ if (first == NULL) {
+ /* We have scanned the entire list and we need to append a new
+ ** child at the end of it. Previous points to the last child
+ ** of root. */
+ newn = Mtr_AllocNode();
+ if (newn == NULL) return(NULL); /* out of memory */
+ newn->low = low;
+ newn->size = size;
+ newn->flags = flags;
+ newn->parent = root;
+ newn->elder = previous;
+ previous->younger = newn;
+ newn->younger = newn->child = NULL;
+ return(newn);
+ }
+ /* Here first is non-NULL and low < first->low + first->size. */
+ if (low >= (unsigned int) first->low &&
+ low + size <= (unsigned int) (first->low + first->size)) {
+ /* The new group is contained in the group of first. */
+ newn = Mtr_MakeGroup(first, low, size, flags);
+ return(newn);
+ } else if (low + size <= first->low) {
+ /* The new group is entirely contained in the gap between
+ ** previous and first. */
+ newn = Mtr_AllocNode();
+ if (newn == NULL) return(NULL); /* out of memory */
+ newn->low = low;
+ newn->size = size;
+ newn->flags = flags;
+ newn->child = NULL;
+ newn->parent = root;
+ newn->elder = previous;
+ newn->younger = first;
+ first->elder = newn;
+ if (previous != NULL) {
+ previous->younger = newn;
+ } else {
+ root->child = newn;
+ }
+ return(newn);
+ } else if (low < (unsigned int) first->low &&
+ low + size < (unsigned int) (first->low + first->size)) {
+ /* Trying to cut an existing group: not allowed. */
+ return(NULL);
+ } else if (low > first->low) {
+ /* The new group neither is contained in the group of first
+ ** (this was tested above) nor contains it. It is therefore
+ ** trying to cut an existing group: not allowed. */
+ return(NULL);
+ }
+
+ /* First holds the pointer to the first child contained in the new
+ ** group. Here low <= first->low and low + size >= first->low +
+ ** first->size. One of the two inequalities is strict. */
+ last = first->younger;
+ while (last != NULL &&
+ (unsigned int) (last->low + last->size) < low + size) {
+ last = last->younger;
+ }
+ if (last == NULL) {
+ /* All the chilren of root from first onward become children
+ ** of the new group. */
+ newn = Mtr_AllocNode();
+ if (newn == NULL) return(NULL); /* out of memory */
+ newn->low = low;
+ newn->size = size;
+ newn->flags = flags;
+ newn->child = first;
+ newn->parent = root;
+ newn->elder = previous;
+ newn->younger = NULL;
+ first->elder = NULL;
+ if (previous != NULL) {
+ previous->younger = newn;
+ } else {
+ root->child = newn;
+ }
+ last = first;
+ while (last != NULL) {
+ last->parent = newn;
+ last = last->younger;
+ }
+ return(newn);
+ }
+
+ /* Here last != NULL and low + size <= last->low + last->size. */
+ if (low + size - 1 >= (unsigned int) last->low &&
+ low + size < (unsigned int) (last->low + last->size)) {
+ /* Trying to cut an existing group: not allowed. */
+ return(NULL);
+ }
+
+ /* First and last point to the first and last of the children of
+ ** root that are included in the new group. Allocate a new node
+ ** and make all children of root between first and last chidren of
+ ** the new node. Previous points to the child of root immediately
+ ** preceeding first. If it is NULL, then first is the first child
+ ** of root. */
+ newn = Mtr_AllocNode();
+ if (newn == NULL) return(NULL); /* out of memory */
+ newn->low = low;
+ newn->size = size;
+ newn->flags = flags;
+ newn->child = first;
+ newn->parent = root;
+ if (previous == NULL) {
+ root->child = newn;
+ } else {
+ previous->younger = newn;
+ }
+ newn->elder = previous;
+ newn->younger = last->younger;
+ if (last->younger != NULL) {
+ last->younger->elder = newn;
+ }
+ last->younger = NULL;
+ first->elder = NULL;
+ for (node = first; node != NULL; node = node->younger) {
+ node->parent = newn;
+ }
+
+ return(newn);
+
+} /* end of Mtr_MakeGroup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Merges the children of `group' with the children of its
+ parent.]
+
+ Description [Merges the children of `group' with the children of its
+ parent. Disposes of the node pointed by group. If group is the
+ root of the group tree, this procedure leaves the tree unchanged.
+ Returns the pointer to the parent of `group' upon successful
+ termination; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_MakeGroup]
+
+******************************************************************************/
+MtrNode *
+Mtr_DissolveGroup(
+ MtrNode * group /* group to be dissolved */)
+{
+ MtrNode *parent;
+ MtrNode *last;
+
+ parent = group->parent;
+
+ if (parent == NULL) return(NULL);
+ if (MTR_TEST(group,MTR_TERMINAL) || group->child == NULL) return(NULL);
+
+ /* Make all children of group children of its parent, and make
+ ** last point to the last child of group. */
+ for (last = group->child; last->younger != NULL; last = last->younger) {
+ last->parent = parent;
+ }
+ last->parent = parent;
+
+ last->younger = group->younger;
+ if (group->younger != NULL) {
+ group->younger->elder = last;
+ }
+
+ group->child->elder = group->elder;
+ if (group == parent->child) {
+ parent->child = group->child;
+ } else {
+ group->elder->younger = group->child;
+ }
+
+ Mtr_DeallocNode(group);
+ return(parent);
+
+} /* end of Mtr_DissolveGroup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds a group with size leaves starting at low, if it exists.]
+
+ Description [Finds a group with size leaves starting at low, if it
+ exists. This procedure relies on the low and size fields of each
+ node. It also assumes that the children of each node are sorted in
+ order of increasing low. Returns the pointer to the root of the
+ group upon successful termination; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+MtrNode *
+Mtr_FindGroup(
+ MtrNode * root /* root of the group tree */,
+ unsigned int low /* lower bound of the group */,
+ unsigned int size /* upper bound of the group */)
+{
+ MtrNode *node;
+
+#ifdef MTR_DEBUG
+ /* We cannot have a non-empty proper subgroup of a singleton set. */
+ assert(!MTR_TEST(root,MTR_TERMINAL));
+#endif
+
+ /* Sanity check. */
+ if (size < 1) return(NULL);
+
+ /* Check whether current group includes the group sought. This
+ ** check is necessary at the top-level call. In the subsequent
+ ** calls it is redundant. */
+ if (low < (unsigned int) root->low ||
+ low + size > (unsigned int) (root->low + root->size))
+ return(NULL);
+
+ if (root->size == size && root->low == low)
+ return(root);
+
+ if (root->child == NULL)
+ return(NULL);
+
+ /* Find all chidren of root that are included in the new group. If
+ ** the group of any child entirely contains the new group, call
+ ** Mtr_MakeGroup recursively. */
+ node = root->child;
+ while (low >= (unsigned int) (node->low + node->size)) {
+ node = node->younger;
+ }
+ if (low + size <= (unsigned int) (node->low + node->size)) {
+ /* The group is contained in the group of node. */
+ node = Mtr_FindGroup(node, low, size);
+ return(node);
+ } else {
+ return(NULL);
+ }
+
+} /* end of Mtr_FindGroup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps two children of a tree node.]
+
+ Description [Swaps two children of a tree node. Adjusts the high and
+ low fields of the two nodes and their descendants. The two children
+ must be adjacent. However, first may be the younger sibling of second.
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Mtr_SwapGroups(
+ MtrNode * first /* first node to be swapped */,
+ MtrNode * second /* second node to be swapped */)
+{
+ MtrNode *node;
+ MtrNode *parent;
+ int sizeFirst;
+ int sizeSecond;
+
+ if (second->younger == first) { /* make first first */
+ node = first;
+ first = second;
+ second = node;
+ } else if (first->younger != second) { /* non-adjacent */
+ return(0);
+ }
+
+ sizeFirst = first->size;
+ sizeSecond = second->size;
+
+ /* Swap the two nodes. */
+ parent = first->parent;
+ if (parent == NULL || second->parent != parent) return(0);
+ if (parent->child == first) {
+ parent->child = second;
+ } else { /* first->elder != NULL */
+ first->elder->younger = second;
+ }
+ if (second->younger != NULL) {
+ second->younger->elder = first;
+ }
+ first->younger = second->younger;
+ second->elder = first->elder;
+ first->elder = second;
+ second->younger = first;
+
+ /* Adjust the high and low fields. */
+ if (!mtrShiftHL(first,sizeSecond)) return(0);
+ if (!mtrShiftHL(second,-sizeFirst)) return(0);
+
+ return(1);
+
+} /* end of Mtr_SwapGroups */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints the groups as a parenthesized list.]
+
+ Description [Prints the groups as a parenthesized list. After each
+ group, the group's flag are printed, preceded by a `|'. For each
+ flag (except MTR_TERMINAL) a character is printed.
+ <ul>
+ <li>F: MTR_FIXED
+ <li>N: MTR_NEWNODE
+ <li>S: MTR_SOFT
+ </ul>
+ The second argument, silent, if different from 0, causes
+ Mtr_PrintGroups to only check the syntax of the group tree.
+ ]
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_PrintTree]
+
+******************************************************************************/
+void
+Mtr_PrintGroups(
+ MtrNode * root /* root of the group tree */,
+ int silent /* flag to check tree syntax only */)
+{
+ MtrNode *node;
+
+ assert(root != NULL);
+ assert(root->younger == NULL || root->younger->elder == root);
+ assert(root->elder == NULL || root->elder->younger == root);
+ if (!silent) (void) printf("(%d",root->low);
+ if (MTR_TEST(root,MTR_TERMINAL) || root->child == NULL) {
+ if (!silent) (void) printf(",");
+ } else {
+ node = root->child;
+ while (node != NULL) {
+ assert(node->low >= root->low && (int) (node->low + node->size) <= (int) (root->low + root->size));
+ assert(node->parent == root);
+ Mtr_PrintGroups(node,silent);
+ node = node->younger;
+ }
+ }
+ if (!silent) {
+ (void) printf("%d", root->low + root->size - 1);
+ if (root->flags != MTR_DEFAULT) {
+ (void) printf("|");
+ if (MTR_TEST(root,MTR_FIXED)) (void) printf("F");
+ if (MTR_TEST(root,MTR_NEWNODE)) (void) printf("N");
+ if (MTR_TEST(root,MTR_SOFT)) (void) printf("S");
+ }
+ (void) printf(")");
+ if (root->parent == NULL) (void) printf("\n");
+ }
+ assert((root->flags &~(MTR_TERMINAL | MTR_SOFT | MTR_FIXED | MTR_NEWNODE)) == 0);
+ return;
+
+} /* end of Mtr_PrintGroups */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads groups from a file and creates a group tree.]
+
+ Description [Reads groups from a file and creates a group tree.
+ Each group is specified by three fields:
+ <xmp>
+ low size flags.
+ </xmp>
+ Low and size are (short) integers. Flags is a string composed of the
+ following characters (with associated translation):
+ <ul>
+ <li>D: MTR_DEFAULT
+ <li>F: MTR_FIXED
+ <li>N: MTR_NEWNODE
+ <li>S: MTR_SOFT
+ <li>T: MTR_TERMINAL
+ </ul>
+ Normally, the only flags that are needed are D and F. Groups and
+ fields are separated by white space (spaces, tabs, and newlines).
+ Returns a pointer to the group tree if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_InitGroupTree Mtr_MakeGroup]
+
+******************************************************************************/
+MtrNode *
+Mtr_ReadGroups(
+ FILE * fp /* file pointer */,
+ int nleaves /* number of leaves of the new tree */)
+{
+ int low;
+ int size;
+ int err;
+ unsigned int flags;
+ MtrNode *root;
+ MtrNode *node;
+ char attrib[8*sizeof(unsigned int)+1];
+ char *c;
+
+ root = Mtr_InitGroupTree(0,nleaves);
+ if (root == NULL) return NULL;
+
+ while (! feof(fp)) {
+ /* Read a triple and check for consistency. */
+ err = fscanf(fp, "%d %d %s", &low, &size, attrib);
+ if (err == EOF) {
+ break;
+ } else if (err != 3) {
+ return(NULL);
+ } else if (low < 0 || low+size > nleaves || size < 1) {
+ return(NULL);
+ } else if (strlen(attrib) > 8 * sizeof(MtrHalfWord)) {
+ /* Not enough bits in the flags word to store these many
+ ** attributes. */
+ return(NULL);
+ }
+
+ /* Parse the flag string. Currently all flags are permitted,
+ ** to make debugging easier. Normally, specifying NEWNODE
+ ** wouldn't be allowed. */
+ flags = MTR_DEFAULT;
+ for (c=attrib; *c != 0; c++) {
+ switch (*c) {
+ case 'D':
+ break;
+ case 'F':
+ flags |= MTR_FIXED;
+ break;
+ case 'N':
+ flags |= MTR_NEWNODE;
+ break;
+ case 'S':
+ flags |= MTR_SOFT;
+ break;
+ case 'T':
+ flags |= MTR_TERMINAL;
+ break;
+ default:
+ return NULL;
+ }
+ }
+ node = Mtr_MakeGroup(root, (MtrHalfWord) low, (MtrHalfWord) size,
+ flags);
+ if (node == NULL) return(NULL);
+ }
+
+ return(root);
+
+} /* end of Mtr_ReadGroups */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Adjusts the low fields of a node and its descendants.]
+
+ Description [Adjusts the low fields of a node and its
+ descendants. Adds shift to low of each node. Checks that no
+ out-of-bounds values result. Returns 1 in case of success; 0
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+mtrShiftHL(
+ MtrNode * node /* group tree node */,
+ int shift /* amount by which low should be changed */)
+{
+ MtrNode *auxnode;
+ int low;
+
+ low = (int) node->low;
+
+
+ low += shift;
+
+ if (low < 0 || low + (int) (node->size - 1) > (int) MTR_MAXHIGH) return(0);
+
+ node->low = (MtrHalfWord) low;
+
+ if (!MTR_TEST(node,MTR_TERMINAL) && node->child != NULL) {
+ auxnode = node->child;
+ do {
+ if (!mtrShiftHL(auxnode,shift)) return(0);
+ auxnode = auxnode->younger;
+ } while (auxnode != NULL);
+ }
+
+ return(1);
+
+} /* end of mtrShiftHL */
+
diff --git a/src/bdd/mtr/mtrInt.h b/src/bdd/mtr/mtrInt.h
new file mode 100644
index 00000000..a8d5aa6c
--- /dev/null
+++ b/src/bdd/mtr/mtrInt.h
@@ -0,0 +1,65 @@
+/**CHeaderFile*****************************************************************
+
+ FileName [mtrInt.h]
+
+ PackageName [mtr]
+
+ Synopsis [Internal data structures of the mtr package]
+
+ Description [In this package all definitions are external.]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+ Revision [$Id: mtrInt.h,v 1.1.1.1 2003/02/24 22:24:02 wjiang Exp $]
+
+******************************************************************************/
+
+#ifndef _MTRINT
+#define _MTRINT
+
+#include "mtr.h"
+
+/*---------------------------------------------------------------------------*/
+/* Nested includes */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+#endif /* _MTRINT */
diff --git a/src/bdd/parse/module.make b/src/bdd/parse/module.make
new file mode 100644
index 00000000..ea535e6e
--- /dev/null
+++ b/src/bdd/parse/module.make
@@ -0,0 +1,2 @@
+SRC += src/bdd/parse/parseCore.c \
+ src/bdd/parse/parseStack.c
diff --git a/src/bdd/parse/parse.h b/src/bdd/parse/parse.h
new file mode 100644
index 00000000..8364e782
--- /dev/null
+++ b/src/bdd/parse/parse.h
@@ -0,0 +1,53 @@
+/**CFile****************************************************************
+
+ FileName [parse.h]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Parsing symbolic Boolean formulas into BDDs.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - September 8, 2003.]
+
+ Revision [$Id: parse.h,v 1.0 2003/09/08 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __PARSE_H__
+#define __PARSE_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// GLOBAL VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== parseCore.c =============================================================*/
+extern DdNode * Parse_FormulaParser( FILE * pOutput, char * pFormula, int nVars, int nRanks,
+ char * ppVarNames[], DdManager * dd, DdNode * pbVars[] );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+#endif
diff --git a/src/bdd/parse/parseCore.c b/src/bdd/parse/parseCore.c
new file mode 100644
index 00000000..d60687a3
--- /dev/null
+++ b/src/bdd/parse/parseCore.c
@@ -0,0 +1,504 @@
+/**CFile****************************************************************
+
+ FileNameIn [parseCore.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Boolean formula parser.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - February 1, 2003.]
+
+ Revision [$Id: parseCore.c,v 1.0 2003/02/01 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+/*
+ Some aspects of Boolean Formula Parser:
+
+ 1) The names in the boolean formulas can be any strings of symbols
+ that start with char or underscore and contain chars, digits
+ and underscores: For example: 1) a&b <+> c'&d => a + b;
+ 2) a1 b2 c3' dummy' + (a2+b2')c3 dummy
+ 2) Constant values 0 and 1 can be used just like normal variables
+ 3) Any boolean operator (listed below) and parantheses can be used
+ any number of times provided there are equal number of opening
+ and closing parantheses.
+ 4) By default, absence of an operator between vars and before and
+ after parantheses is taken for AND.
+ 5) Both complementation prefix and complementation suffix can be
+ used at the same time (but who needs this?)
+ 6) Spaces (tabs, end-of-lines) may be inserted anywhere,
+ except between characters of the operations: <=>, =>, <=, <+>
+ 7) The stack size is defined by macro STACKSIZE and is used by the
+ stack constructor.
+*/
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+#include "parseInt.h"
+
+// the list of operation symbols to be used in expressions
+#define PARSE_SYM_OPEN '(' // opening paranthesis
+#define PARSE_SYM_CLOSE ')' // closing paranthesis
+#define PARSE_SYM_LOWER '[' // shifts one rank down
+#define PARSE_SYM_RAISE ']' // shifts one rank up
+#define PARSE_SYM_CONST0 '0' // constant 0
+#define PARSE_SYM_CONST1 '1' // constant 1
+#define PARSE_SYM_NEGBEF1 '!' // negation before the variable
+#define PARSE_SYM_NEGBEF2 '~' // negation before the variable
+#define PARSE_SYM_NEGAFT '\'' // negation after the variable
+#define PARSE_SYM_AND1 '&' // logic AND
+#define PARSE_SYM_AND2 '*' // logic AND
+#define PARSE_SYM_XOR1 '<' // logic EXOR (the 1st symbol)
+#define PARSE_SYM_XOR2 '+' // logic EXOR (the 2nd symbol)
+#define PARSE_SYM_XOR3 '>' // logic EXOR (the 3rd symbol)
+#define PARSE_SYM_OR '+' // logic OR
+#define PARSE_SYM_EQU1 '<' // equvalence (the 1st symbol)
+#define PARSE_SYM_EQU2 '=' // equvalence (the 2nd symbol)
+#define PARSE_SYM_EQU3 '>' // equvalence (the 3rd symbol)
+#define PARSE_SYM_FLR1 '=' // implication (the 1st symbol)
+#define PARSE_SYM_FLR2 '>' // implication (the 2nd symbol)
+#define PARSE_SYM_FLL1 '<' // backward imp (the 1st symbol)
+#define PARSE_SYM_FLL2 '=' // backward imp (the 2nd symbol)
+// PARSE_SYM_FLR1 and PARSE_SYM_FLR2 should be the same as PARSE_SYM_EQU2 and PARSE_SYM_EQU3!
+
+// the list of opcodes (also specifying operation precedence)
+#define PARSE_OPER_NEG 10 // negation
+#define PARSE_OPER_AND 9 // logic AND
+#define PARSE_OPER_XOR 8 // logic EXOR (a'b | ab')
+#define PARSE_OPER_OR 7 // logic OR
+#define PARSE_OPER_EQU 6 // equvalence (a'b'| ab )
+#define PARSE_OPER_FLR 5 // implication ( a' | b )
+#define PARSE_OPER_FLL 4 // backward imp ( 'b | a )
+#define PARSE_OPER_MARK 1 // OpStack token standing for an opening paranthesis
+
+// these are values of the internal Flag
+#define PARSE_FLAG_START 1 // after the opening parenthesis
+#define PARSE_FLAG_VAR 2 // after operation is received
+#define PARSE_FLAG_OPER 3 // after operation symbol is received
+#define PARSE_FLAG_ERROR 4 // when error is detected
+
+#define STACKSIZE 1000
+
+static DdNode * Parse_ParserPerformTopOp( DdManager * dd, Parse_StackFn_t * pStackFn, int Oper );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Derives the BDD corresponding to the formula in language L.]
+
+ Description [Takes the stream to output messages, the formula, the number
+ variables and the rank in the formula. The array of variable names is also
+ given. The BDD manager and the elementary 0-rank variable are the last two
+ arguments. The manager should have at least as many variables as
+ nVars * (nRanks + 1). The 0-rank variables should have numbers larger
+ than the variables of other ranks.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Parse_FormulaParser( FILE * pOutput, char * pFormulaInit, int nVars, int nRanks,
+ char * ppVarNames[], DdManager * dd, DdNode * pbVars[] )
+{
+ char * pFormula;
+ Parse_StackFn_t * pStackFn;
+ Parse_StackOp_t * pStackOp;
+ DdNode * bFunc, * bTemp;
+ char * pTemp;
+ int nParans, fFound, Flag;
+ int Oper, Oper1, Oper2;
+ int i, v, fLower;
+
+ // make sure that the number of vars and ranks is correct
+ if ( nVars * (nRanks + 1) > dd->size )
+ {
+ printf( "Parse_FormulaParser(): The BDD manager does not have enough variables.\n" );
+ return NULL;
+ }
+
+ // make sure that the number of opening and closing parantheses is the same
+ nParans = 0;
+ for ( pTemp = pFormulaInit; *pTemp; pTemp++ )
+ if ( *pTemp == '(' )
+ nParans++;
+ else if ( *pTemp == ')' )
+ nParans--;
+ if ( nParans != 0 )
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): Different number of opening and closing parantheses ().\n" );
+ return NULL;
+ }
+
+ nParans = 0;
+ for ( pTemp = pFormulaInit; *pTemp; pTemp++ )
+ if ( *pTemp == '[' )
+ nParans++;
+ else if ( *pTemp == ']' )
+ nParans--;
+ if ( nParans != 0 )
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): Different number of opening and closing brackets [].\n" );
+ return NULL;
+ }
+
+ // copy the formula
+ pFormula = ALLOC( char, strlen(pFormulaInit) + 3 );
+ sprintf( pFormula, "(%s)", pFormulaInit );
+
+ // start the stacks
+ pStackFn = Parse_StackFnStart( STACKSIZE );
+ pStackOp = Parse_StackOpStart( STACKSIZE );
+
+ Flag = PARSE_FLAG_START;
+ fLower = 0;
+ for ( pTemp = pFormula; *pTemp; pTemp++ )
+ {
+ switch ( *pTemp )
+ {
+ // skip all spaces, tabs, and end-of-lines
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ continue;
+
+ // treat Constant 0 as a variable
+ case PARSE_SYM_CONST0:
+ Parse_StackFnPush( pStackFn, b0 ); Cudd_Ref( b0 );
+ if ( Flag == PARSE_FLAG_VAR )
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): No operation symbol before constant 0.\n" );
+ Flag = PARSE_FLAG_ERROR;
+ break;
+ }
+ Flag = PARSE_FLAG_VAR;
+ break;
+
+ // the same for Constant 1
+ case PARSE_SYM_CONST1:
+ Parse_StackFnPush( pStackFn, b1 ); Cudd_Ref( b1 );
+ if ( Flag == PARSE_FLAG_VAR )
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): No operation symbol before constant 1.\n" );
+ Flag = PARSE_FLAG_ERROR;
+ break;
+ }
+ Flag = PARSE_FLAG_VAR;
+ break;
+
+ case PARSE_SYM_NEGBEF1:
+ case PARSE_SYM_NEGBEF2:
+ if ( Flag == PARSE_FLAG_VAR )
+ {// if NEGBEF follows a variable, AND is assumed
+ Parse_StackOpPush( pStackOp, PARSE_OPER_AND );
+ Flag = PARSE_FLAG_OPER;
+ }
+ Parse_StackOpPush( pStackOp, PARSE_OPER_NEG );
+ break;
+
+ case PARSE_SYM_NEGAFT:
+ if ( Flag != PARSE_FLAG_VAR )
+ {// if there is no variable before NEGAFT, it is an error
+ fprintf( pOutput, "Parse_FormulaParser(): No variable is specified before the negation suffix.\n" );
+ Flag = PARSE_FLAG_ERROR;
+ break;
+ }
+ else // if ( Flag == PARSE_FLAG_VAR )
+ Parse_StackFnPush( pStackFn, Cudd_Not( Parse_StackFnPop(pStackFn) ) );
+ break;
+
+ case PARSE_SYM_AND1:
+ case PARSE_SYM_AND2:
+ case PARSE_SYM_OR:
+ if ( Flag != PARSE_FLAG_VAR )
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): There is no variable before AND, EXOR, or OR.\n" );
+ Flag = PARSE_FLAG_ERROR;
+ break;
+ }
+ if ( *pTemp == PARSE_SYM_AND1 || *pTemp == PARSE_SYM_AND2 )
+ Parse_StackOpPush( pStackOp, PARSE_OPER_AND );
+ else //if ( Str[Pos] == PARSE_SYM_OR )
+ Parse_StackOpPush( pStackOp, PARSE_OPER_OR );
+ Flag = PARSE_FLAG_OPER;
+ break;
+
+ case PARSE_SYM_EQU1:
+ if ( Flag != PARSE_FLAG_VAR )
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): There is no variable before Equivalence or Implication\n" );
+ Flag = PARSE_FLAG_ERROR; break;
+ }
+ if ( pTemp[1] == PARSE_SYM_EQU2 )
+ { // check what is the next symbol in the string
+ pTemp++;
+ if ( pTemp[1] == PARSE_SYM_EQU3 )
+ {
+ pTemp++;
+ Parse_StackOpPush( pStackOp, PARSE_OPER_EQU );
+ }
+ else
+ {
+ Parse_StackOpPush( pStackOp, PARSE_OPER_FLL );
+ }
+ }
+ else if ( pTemp[1] == PARSE_SYM_XOR2 )
+ {
+ pTemp++;
+ if ( pTemp[1] == PARSE_SYM_XOR3 )
+ {
+ pTemp++;
+ Parse_StackOpPush( pStackOp, PARSE_OPER_XOR );
+ }
+ else
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): Wrong symbol after \"%c%c\"\n", PARSE_SYM_EQU1, PARSE_SYM_XOR2 );
+ Flag = PARSE_FLAG_ERROR;
+ break;
+ }
+ }
+ else
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): Wrong symbol after \"%c\"\n", PARSE_SYM_EQU1 );
+ Flag = PARSE_FLAG_ERROR;
+ break;
+ }
+ Flag = PARSE_FLAG_OPER;
+ break;
+
+ case PARSE_SYM_EQU2:
+ if ( Flag != PARSE_FLAG_VAR )
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): There is no variable before Reverse Implication\n" );
+ Flag = PARSE_FLAG_ERROR;
+ break;
+ }
+ if ( pTemp[1] == PARSE_SYM_EQU3 )
+ {
+ pTemp++;
+ Parse_StackOpPush( pStackOp, PARSE_OPER_FLR );
+ }
+ else
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): Wrong symbol after \"%c\"\n", PARSE_SYM_EQU2 );
+ Flag = PARSE_FLAG_ERROR;
+ break;
+ }
+ Flag = PARSE_FLAG_OPER;
+ break;
+
+ case PARSE_SYM_LOWER:
+ case PARSE_SYM_OPEN:
+ if ( Flag == PARSE_FLAG_VAR )
+ Parse_StackOpPush( pStackOp, PARSE_OPER_AND );
+ Parse_StackOpPush( pStackOp, PARSE_OPER_MARK );
+ // after an opening bracket, it feels like starting over again
+ Flag = PARSE_FLAG_START;
+ break;
+
+ case PARSE_SYM_RAISE:
+ fLower = 1;
+ case PARSE_SYM_CLOSE:
+ if ( !Parse_StackOpIsEmpty( pStackOp ) )
+ {
+ while ( 1 )
+ {
+ if ( Parse_StackOpIsEmpty( pStackOp ) )
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): There is no opening paranthesis\n" );
+ Flag = PARSE_FLAG_ERROR;
+ break;
+ }
+ Oper = Parse_StackOpPop( pStackOp );
+ if ( Oper == PARSE_OPER_MARK )
+ break;
+
+ // perform the given operation
+ if ( Parse_ParserPerformTopOp( dd, pStackFn, Oper ) == NULL )
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): Unknown operation\n" );
+ free( pFormula );
+ return NULL;
+ }
+ }
+
+ if ( fLower )
+ {
+ bFunc = Parse_StackFnPop( pStackFn );
+ bFunc = Extra_bddMove( dd, bTemp = bFunc, -nVars ); Cudd_Ref( bFunc );
+ Cudd_RecursiveDeref( dd, bTemp );
+ Parse_StackFnPush( pStackFn, bFunc );
+ }
+ }
+ else
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): There is no opening paranthesis\n" );
+ Flag = PARSE_FLAG_ERROR;
+ break;
+ }
+ if ( Flag != PARSE_FLAG_ERROR )
+ Flag = PARSE_FLAG_VAR;
+ fLower = 0;
+ break;
+
+
+ default:
+ // scan the next name
+ fFound = 0;
+ for ( i = 0; pTemp[i] && pTemp[i] != ' ' && pTemp[i] != '\t' && pTemp[i] != '\r' && pTemp[i] != '\n'; i++ )
+ {
+ for ( v = 0; v < nVars; v++ )
+ if ( strncmp( pTemp, ppVarNames[v], i+1 ) == 0 && strlen(ppVarNames[v]) == (unsigned)(i+1) )
+ {
+ pTemp += i;
+ fFound = 1;
+ break;
+ }
+ if ( fFound )
+ break;
+ }
+ if ( !fFound )
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): The parser cannot find var \"%s\" in the input var list.\n", pTemp );
+ Flag = PARSE_FLAG_ERROR;
+ break;
+ }
+
+ // assume operation AND, if vars follow one another
+ if ( Flag == PARSE_FLAG_VAR )
+ Parse_StackOpPush( pStackOp, PARSE_OPER_AND );
+ Parse_StackFnPush( pStackFn, pbVars[v] ); Cudd_Ref( pbVars[v] );
+ Flag = PARSE_FLAG_VAR;
+ break;
+ }
+
+ if ( Flag == PARSE_FLAG_ERROR )
+ break; // error exit
+ else if ( Flag == PARSE_FLAG_START )
+ continue; // go on parsing
+ else if ( Flag == PARSE_FLAG_VAR )
+ while ( 1 )
+ { // check if there are negations in the OpStack
+ if ( Parse_StackOpIsEmpty(pStackOp) )
+ break;
+ Oper = Parse_StackOpPop( pStackOp );
+ if ( Oper != PARSE_OPER_NEG )
+ {
+ Parse_StackOpPush( pStackOp, Oper );
+ break;
+ }
+ else
+ {
+ Parse_StackFnPush( pStackFn, Cudd_Not(Parse_StackFnPop(pStackFn)) );
+ }
+ }
+ else // if ( Flag == PARSE_FLAG_OPER )
+ while ( 1 )
+ { // execute all the operations in the OpStack
+ // with precedence higher or equal than the last one
+ Oper1 = Parse_StackOpPop( pStackOp ); // the last operation
+ if ( Parse_StackOpIsEmpty(pStackOp) )
+ { // if it is the only operation, push it back
+ Parse_StackOpPush( pStackOp, Oper1 );
+ break;
+ }
+ Oper2 = Parse_StackOpPop( pStackOp ); // the operation before the last one
+ if ( Oper2 >= Oper1 )
+ { // if Oper2 precedence is higher or equal, execute it
+// Parse_StackPush( pStackFn, Operation( FunStack.Pop(), FunStack.Pop(), Oper2 ) );
+ if ( Parse_ParserPerformTopOp( dd, pStackFn, Oper2 ) == NULL )
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): Unknown operation\n" );
+ free( pFormula );
+ return NULL;
+ }
+ Parse_StackOpPush( pStackOp, Oper1 ); // push the last operation back
+ }
+ else
+ { // if Oper2 precedence is lower, push them back and done
+ Parse_StackOpPush( pStackOp, Oper2 );
+ Parse_StackOpPush( pStackOp, Oper1 );
+ break;
+ }
+ }
+ }
+
+ if ( Flag != PARSE_FLAG_ERROR )
+ {
+ if ( !Parse_StackFnIsEmpty(pStackFn) )
+ {
+ bFunc = Parse_StackFnPop(pStackFn);
+ if ( Parse_StackFnIsEmpty(pStackFn) )
+ if ( Parse_StackOpIsEmpty(pStackOp) )
+ {
+ Parse_StackFnFree(pStackFn);
+ Parse_StackOpFree(pStackOp);
+ Cudd_Deref( bFunc );
+ free( pFormula );
+ return bFunc;
+ }
+ else
+ fprintf( pOutput, "Parse_FormulaParser(): Something is left in the operation stack\n" );
+ else
+ fprintf( pOutput, "Parse_FormulaParser(): Something is left in the function stack\n" );
+ }
+ else
+ fprintf( pOutput, "Parse_FormulaParser(): The input string is empty\n" );
+ }
+ free( pFormula );
+ return NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs the operation on the top entries in the stack.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Parse_ParserPerformTopOp( DdManager * dd, Parse_StackFn_t * pStackFn, int Oper )
+{
+ DdNode * bArg1, * bArg2, * bFunc;
+ // perform the given operation
+ bArg2 = Parse_StackFnPop( pStackFn );
+ bArg1 = Parse_StackFnPop( pStackFn );
+ if ( Oper == PARSE_OPER_AND )
+ bFunc = Cudd_bddAnd( dd, bArg1, bArg2 );
+ else if ( Oper == PARSE_OPER_XOR )
+ bFunc = Cudd_bddXor( dd, bArg1, bArg2 );
+ else if ( Oper == PARSE_OPER_OR )
+ bFunc = Cudd_bddOr( dd, bArg1, bArg2 );
+ else if ( Oper == PARSE_OPER_EQU )
+ bFunc = Cudd_bddXnor( dd, bArg1, bArg2 );
+ else if ( Oper == PARSE_OPER_FLR )
+ bFunc = Cudd_bddOr( dd, Cudd_Not(bArg1), bArg2 );
+ else if ( Oper == PARSE_OPER_FLL )
+ bFunc = Cudd_bddOr( dd, Cudd_Not(bArg2), bArg1 );
+ else
+ return NULL;
+ Cudd_Ref( bFunc );
+ Cudd_RecursiveDeref( dd, bArg1 );
+ Cudd_RecursiveDeref( dd, bArg2 );
+ Parse_StackFnPush( pStackFn, bFunc );
+ return bFunc;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
diff --git a/src/bdd/parse/parseInt.h b/src/bdd/parse/parseInt.h
new file mode 100644
index 00000000..6e6c49b0
--- /dev/null
+++ b/src/bdd/parse/parseInt.h
@@ -0,0 +1,73 @@
+/**CFile****************************************************************
+
+ FileName [parseInt.h]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Parsing symbolic Boolean formulas into BDDs.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - September 8, 2003.]
+
+ Revision [$Id: parseInt.h,v 1.0 2003/09/08 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __PARSE_INT_H__
+#define __PARSE_INT_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+
+#include <stdio.h>
+#include "cuddInt.h"
+#include "extra.h"
+#include "parse.h"
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+typedef int bool;
+
+typedef struct ParseStackFnStruct Parse_StackFn_t; // the function stack
+typedef struct ParseStackOpStruct Parse_StackOp_t; // the operation stack
+
+////////////////////////////////////////////////////////////////////////
+/// GLOBAL VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== parseStack.c =============================================================*/
+extern Parse_StackFn_t * Parse_StackFnStart ( int nDepth );
+extern bool Parse_StackFnIsEmpty( Parse_StackFn_t * p );
+extern void Parse_StackFnPush ( Parse_StackFn_t * p, DdNode * bFunc );
+extern DdNode * Parse_StackFnPop ( Parse_StackFn_t * p );
+extern void Parse_StackFnFree ( Parse_StackFn_t * p );
+
+extern Parse_StackOp_t * Parse_StackOpStart ( int nDepth );
+extern bool Parse_StackOpIsEmpty( Parse_StackOp_t * p );
+extern void Parse_StackOpPush ( Parse_StackOp_t * p, int Oper );
+extern int Parse_StackOpPop ( Parse_StackOp_t * p );
+extern void Parse_StackOpFree ( Parse_StackOp_t * p );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+#endif
diff --git a/src/bdd/parse/parseStack.c b/src/bdd/parse/parseStack.c
new file mode 100644
index 00000000..8329070e
--- /dev/null
+++ b/src/bdd/parse/parseStack.c
@@ -0,0 +1,243 @@
+/**CFile****************************************************************
+
+ FileName [parseStack.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Stacks used by the formula parser.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - August 18, 2003.]
+
+ Revision [$Id: parseStack.c,v 1.0 2003/02/01 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "parseInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+struct ParseStackFnStruct
+{
+ DdNode ** pData; // the array of elements
+ int Top; // the index
+ int Size; // the stack size
+};
+
+struct ParseStackOpStruct
+{
+ int * pData; // the array of elements
+ int Top; // the index
+ int Size; // the stack size
+};
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Starts the stack.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Parse_StackFn_t * Parse_StackFnStart( int nDepth )
+{
+ Parse_StackFn_t * p;
+ p = ALLOC( Parse_StackFn_t, 1 );
+ memset( p, 0, sizeof(Parse_StackFn_t) );
+ p->pData = ALLOC( DdNode *, nDepth );
+ p->Size = nDepth;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks whether the stack is empty.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Parse_StackFnIsEmpty( Parse_StackFn_t * p )
+{
+ return (bool)(p->Top == 0);
+}
+
+/**Function*************************************************************
+
+ Synopsis [Pushes an entry into the stack.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Parse_StackFnPush( Parse_StackFn_t * p, DdNode * bFunc )
+{
+ if ( p->Top >= p->Size )
+ {
+ printf( "Parse_StackFnPush(): Stack size is too small!\n" );
+ return;
+ }
+ p->pData[ p->Top++ ] = bFunc;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Pops an entry out of the stack.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Parse_StackFnPop( Parse_StackFn_t * p )
+{
+ if ( p->Top == 0 )
+ {
+ printf( "Parse_StackFnPush(): Trying to extract data from the empty stack!\n" );
+ return NULL;
+ }
+ return p->pData[ --p->Top ];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Deletes the stack.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Parse_StackFnFree( Parse_StackFn_t * p )
+{
+ FREE( p->pData );
+ FREE( p );
+}
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Starts the stack.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Parse_StackOp_t * Parse_StackOpStart( int nDepth )
+{
+ Parse_StackOp_t * p;
+ p = ALLOC( Parse_StackOp_t, 1 );
+ memset( p, 0, sizeof(Parse_StackOp_t) );
+ p->pData = ALLOC( int, nDepth );
+ p->Size = nDepth;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks whether the stack is empty.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Parse_StackOpIsEmpty( Parse_StackOp_t * p )
+{
+ return (bool)(p->Top == 0);
+}
+
+/**Function*************************************************************
+
+ Synopsis [Pushes an entry into the stack.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Parse_StackOpPush( Parse_StackOp_t * p, int Oper )
+{
+ if ( p->Top >= p->Size )
+ {
+ printf( "Parse_StackOpPush(): Stack size is too small!\n" );
+ return;
+ }
+ p->pData[ p->Top++ ] = Oper;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Pops an entry out of the stack.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Parse_StackOpPop( Parse_StackOp_t * p )
+{
+ if ( p->Top == 0 )
+ {
+ printf( "Parse_StackOpPush(): Trying to extract data from the empty stack!\n" );
+ return -1;
+ }
+ return p->pData[ --p->Top ];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Deletes the stack.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Parse_StackOpFree( Parse_StackOp_t * p )
+{
+ FREE( p->pData );
+ FREE( p );
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/bdd/reo/module.make b/src/bdd/reo/module.make
new file mode 100644
index 00000000..703be139
--- /dev/null
+++ b/src/bdd/reo/module.make
@@ -0,0 +1,7 @@
+SRC += bdd\reo\reoApi.c \
+ bdd\reo\reoCore.c \
+ bdd\reo\reoProfile.c \
+ bdd\reo\reoSift.c \
+ bdd\reo\reoSwap.c \
+ bdd\reo\reoTransfer.c \
+ bdd\reo\reoUnits.c
diff --git a/src/bdd/reo/reo.h b/src/bdd/reo/reo.h
new file mode 100644
index 00000000..7e4be855
--- /dev/null
+++ b/src/bdd/reo/reo.h
@@ -0,0 +1,222 @@
+/**CFile****************************************************************
+
+ FileName [reo.h]
+
+ PackageName [REO: A specialized DD reordering engine.]
+
+ Synopsis [External and internal declarations.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - October 15, 2002.]
+
+ Revision [$Id: reo.h,v 1.0 2002/15/10 03:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __REO_H__
+#define __REO_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "extra.h"
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// reordering parameters
+#define REO_REORDER_LIMIT 1.15 // determines the quality/runtime trade-off
+#define REO_QUAL_PAR 3 // the quality [1 = simple lower bound, 2 = strict, larger = heuristic]
+// internal parameters
+#define REO_CONST_LEVEL 30000 // the number of the constant level
+#define REO_TOPREF_UNDEF 30000 // the undefined top reference
+#define REO_CHUNK_SIZE 5000 // the number of units allocated at one time
+#define REO_COST_EPSILON 0.0000001 // difference in cost large enough so that it counted as an error
+#define REO_HIGH_VALUE 10000000 // a large value used to initialize some variables
+// interface parameters
+#define REO_ENABLE 1 // the value of the enable flag
+#define REO_DISABLE 0 // the value of the disable flag
+
+// the types of minimization currently supported
+typedef enum {
+ REO_MINIMIZE_NODES,
+ REO_MINIMIZE_WIDTH, // may not work for BDDs with complemented edges
+ REO_MINIMIZE_APL
+} reo_min_type;
+
+////////////////////////////////////////////////////////////////////////
+/// DATA STRUCTURES ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct _reo_unit reo_unit; // the unit representing one DD node during reordering
+typedef struct _reo_plane reo_plane; // the set of nodes on one level
+typedef struct _reo_hash reo_hash; // the entry in the hash table
+typedef struct _reo_man reo_man; // the reordering manager
+typedef struct _reo_test reo_test; //
+
+struct _reo_unit
+{
+ short lev; // the level of this node at the beginning
+ short TopRef; // the top level from which this node is refed (used to update BDD width)
+ short TopRefNew; // the new top level from which this node is refed (used to update BDD width)
+ short n; // the number of incoming edges (similar to ref count in the BDD)
+ int Sign; // the signature
+
+ reo_unit * pE; // the pointer to the "else" branch
+ reo_unit * pT; // the pointer to the "then" branch
+ reo_unit * Next; // the link to the next one in the list
+ double Weight; // the probability of traversing this node
+};
+
+struct _reo_plane
+{
+ int fSifted; // to mark the sifted variables
+ int statsNodes; // the number of nodes in the current level
+ int statsWidth; // the width on the current level
+ double statsApl; // the sum of node probabilities on this level
+ double statsCost; // the current cost is stored here
+ double statsCostAbove; // the current cost is stored here
+ double statsCostBelow; // the current cost is stored here
+
+ reo_unit * pHead; // the pointer to the beginning of the unit list
+};
+
+struct _reo_hash
+{
+ int Sign; // signature of the current cache operation
+ unsigned Arg1; // the first argument
+ unsigned Arg2; // the second argument
+ unsigned Arg3; // the second argument
+};
+
+struct _reo_man
+{
+ // these paramaters can be set by the API functions
+ int fMinWidth; // the flag to enable reordering for minimum width
+ int fMinApl; // the flag to enable reordering for minimum APL
+ int fVerbose; // the verbosity level
+ int fVerify; // the flag toggling verification
+ int fRemapUp; // the flag to enable remapping
+ int nIters; // the number of interations of sifting to perform
+
+ // parameters given by the user when reordering is called
+ DdManager * dd; // the CUDD BDD manager
+ int * pOrder; // the resulting variable order will be returned here
+
+ // derived parameters
+ int fThisIsAdd; // this flag is one if the function is the ADD
+ int * pSupp; // the support of the given function
+ int nSuppAlloc; // the max allowed number of support variables
+ int nSupp; // the number of support variables
+ int * pOrderInt; // the array storing the internal variable permutation
+ double * pVarCosts; // other arrays
+ int * pLevelOrder; // other arrays
+ reo_unit ** pWidthCofs; // temporary storage for cofactors used during reordering for width
+
+ // parameters related to cost
+ int nNodesBeg;
+ int nNodesCur;
+ int nNodesEnd;
+ int nWidthCur;
+ int nWidthBeg;
+ int nWidthEnd;
+ double nAplCur;
+ double nAplBeg;
+ double nAplEnd;
+
+ // mapping of the function into planes and back
+ int * pMapToPlanes; // the mapping of var indexes into plane levels
+ int * pMapToDdVarsOrig;// the mapping of plane levels into the original indexes
+ int * pMapToDdVarsFinal;// the mapping of plane levels into the final indexes
+
+ // the planes table
+ reo_plane * pPlanes;
+ int nPlanes;
+ reo_unit ** pTops;
+ int nTops;
+ int nTopsAlloc;
+
+ // the hash table
+ reo_hash * HTable; // the table itself
+ int nTableSize; // the size of the hash table
+ int Signature; // the signature counter
+
+ // the referenced node list
+ int nNodesMaxAlloc; // this parameters determins how much memory is allocated
+ DdNode ** pRefNodes;
+ int nRefNodes;
+ int nRefNodesAlloc;
+
+ // unit memory management
+ reo_unit * pUnitFreeList;
+ reo_unit ** pMemChunks;
+ int nMemChunks;
+ int nMemChunksAlloc;
+ int nUnitsUsed;
+
+ // statistic variables
+ int HashSuccess;
+ int HashFailure;
+ int nSwaps; // the number of swaps
+ int nNISwaps; // the number of swaps without interaction
+};
+
+// used to manipulate units
+#define Unit_Regular(u) ((reo_unit *)((unsigned long)(u) & ~01))
+#define Unit_Not(u) ((reo_unit *)((long)(u) ^ 01))
+#define Unit_NotCond(u,c) ((reo_unit *)((long)(u) ^ (c)))
+#define Unit_IsConstant(u) ((int)((u)->lev == REO_CONST_LEVEL))
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// ======================= reoApi.c ========================================
+extern reo_man * Extra_ReorderInit( int nDdVarsMax, int nNodesMax );
+extern void Extra_ReorderQuit( reo_man * p );
+extern void Extra_ReorderSetMinimizationType( reo_man * p, reo_min_type fMinType );
+extern void Extra_ReorderSetRemapping( reo_man * p, int fRemapUp );
+extern void Extra_ReorderSetIterations( reo_man * p, int nIters );
+extern void Extra_ReorderSetVerbosity( reo_man * p, int fVerbose );
+extern void Extra_ReorderSetVerification( reo_man * p, int fVerify );
+extern DdNode * Extra_Reorder( reo_man * p, DdManager * dd, DdNode * Func, int * pOrder );
+extern void Extra_ReorderArray( reo_man * p, DdManager * dd, DdNode * Funcs[], DdNode * FuncsRes[], int nFuncs, int * pOrder );
+// ======================= reoCore.c =======================================
+extern void reoReorderArray( reo_man * p, DdManager * dd, DdNode * Funcs[], DdNode * FuncsRes[], int nFuncs, int * pOrder );
+extern void reoResizeStructures( reo_man * p, int nDdVarsMax, int nNodesMax, int nFuncs );
+// ======================= reoProfile.c ======================================
+extern void reoProfileNodesStart( reo_man * p );
+extern void reoProfileAplStart( reo_man * p );
+extern void reoProfileWidthStart( reo_man * p );
+extern void reoProfileWidthStart2( reo_man * p );
+extern void reoProfileAplPrint( reo_man * p );
+extern void reoProfileNodesPrint( reo_man * p );
+extern void reoProfileWidthPrint( reo_man * p );
+extern void reoProfileWidthVerifyLevel( reo_plane * pPlane, int Level );
+// ======================= reoSift.c =======================================
+extern void reoReorderSift( reo_man * p );
+// ======================= reoSwap.c =======================================
+extern double reoReorderSwapAdjacentVars( reo_man * p, int Level, int fMovingUp );
+// ======================= reoTransfer.c ===================================
+extern reo_unit * reoTransferNodesToUnits_rec( reo_man * p, DdNode * F );
+extern DdNode * reoTransferUnitsToNodes_rec( reo_man * p, reo_unit * pUnit );
+// ======================= reoUnits.c ======================================
+extern reo_unit * reoUnitsGetNextUnit(reo_man * p );
+extern void reoUnitsRecycleUnit( reo_man * p, reo_unit * pUnit );
+extern void reoUnitsRecycleUnitList( reo_man * p, reo_plane * pPlane );
+extern void reoUnitsAddUnitToPlane( reo_plane * pPlane, reo_unit * pUnit );
+extern void reoUnitsStopDispenser( reo_man * p );
+// ======================= reoTest.c =======================================
+extern void Extra_ReorderTest( DdManager * dd, DdNode * Func );
+extern DdNode * Extra_ReorderCudd( DdManager * dd, DdNode * aFunc, int pPermuteReo[] );
+extern int Extra_bddReorderTest( DdManager * dd, DdNode * bF );
+extern int Extra_addReorderTest( DdManager * dd, DdNode * aF );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
diff --git a/src/bdd/reo/reoApi.c b/src/bdd/reo/reoApi.c
new file mode 100644
index 00000000..e833dabd
--- /dev/null
+++ b/src/bdd/reo/reoApi.c
@@ -0,0 +1,289 @@
+/**CFile****************************************************************
+
+ FileName [reoApi.c]
+
+ PackageName [REO: A specialized DD reordering engine.]
+
+ Synopsis [Implementation of API functions.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - October 15, 2002.]
+
+ Revision [$Id: reoApi.c,v 1.0 2002/15/10 03:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "reo.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Initializes the reordering engine.]
+
+ Description [The first argument is the max number of variables in the
+ CUDD DD manager which will be used with the reordering engine
+ (this number of should be the maximum of BDD and ZDD parts).
+ The second argument is the maximum number of BDD nodes in the BDDs
+ to be reordered. These limits are soft. Setting lower limits will later
+ cause the reordering manager to resize internal data structures.
+ However, setting the exact values will make reordering more efficient
+ because resizing will be not necessary.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+reo_man * Extra_ReorderInit( int nDdVarsMax, int nNodesMax )
+{
+ reo_man * p;
+ // allocate and clean the data structure
+ p = ALLOC( reo_man, 1 );
+ memset( p, 0, sizeof(reo_man) );
+ // resize the manager to meet user's needs
+ reoResizeStructures( p, nDdVarsMax, nNodesMax, 100 );
+ // set the defaults
+ p->fMinApl = 0;
+ p->fMinWidth = 0;
+ p->fRemapUp = 0;
+ p->fVerbose = 0;
+ p->fVerify = 0;
+ p->nIters = 1;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Disposes of the reordering engine.]
+
+ Description [Removes all memory associated with the reordering engine.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_ReorderQuit( reo_man * p )
+{
+ free( p->pTops );
+ free( p->pSupp );
+ free( p->pOrderInt );
+ free( p->pWidthCofs );
+ free( p->pMapToPlanes );
+ free( p->pMapToDdVarsOrig );
+ free( p->pMapToDdVarsFinal );
+ free( p->pPlanes );
+ free( p->pVarCosts );
+ free( p->pLevelOrder );
+ free( p->HTable );
+ free( p->pRefNodes );
+ reoUnitsStopDispenser( p );
+ free( p->pMemChunks );
+ free( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the type of DD minimizationl that will be performed.]
+
+ Description [Currently, three different types of minimization are supported.
+ It is possible to minimize the number of BDD nodes. This is a classical type
+ of minimization, which is attempting to reduce the total number of nodes in
+ the (shared) BDD of the given Boolean functions. It is also possible to
+ minimize the BDD width, defined as the sum total of the number of cofactors
+ on each level in the (shared) BDD (note that the number of cofactors on the
+ given level may be larger than the number of nodes appearing on the given level).
+ It is also possible to minimize the average path length in the (shared) BDD
+ defined as the sum of products, for all BDD paths from the top node to any
+ terminal node, of the number of minterms on the path by the number of nodes
+ on the path. The default reordering type is minimization for the number of
+ BDD nodes. Calling this function with REO_MINIMIZE_WIDTH or REO_MINIMIZE_APL
+ as the second argument, changes the default minimization option for all the
+ reorder calls performed afterwards.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_ReorderSetMinimizationType( reo_man * p, reo_min_type fMinType )
+{
+ if ( fMinType == REO_MINIMIZE_NODES )
+ {
+ p->fMinWidth = 0;
+ p->fMinApl = 0;
+ }
+ else if ( fMinType == REO_MINIMIZE_WIDTH )
+ {
+ p->fMinWidth = 1;
+ p->fMinApl = 0;
+ }
+ else if ( fMinType == REO_MINIMIZE_APL )
+ {
+ p->fMinWidth = 0;
+ p->fMinApl = 1;
+ }
+ else
+ {
+ assert( 0 );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the type of remapping performed by the engine.]
+
+ Description [The remapping refers to the way the resulting BDD
+ is expressed using the elementary variables of the CUDD BDD manager.
+ Currently, two types possibilities are supported: remapping and no
+ remapping. Remapping means that the function(s) after reordering
+ depend on the topmost variables in the manager. No remapping means
+ that the function(s) after reordering depend on the same variables
+ as before. Consider the following example. Suppose the initial four
+ variable function depends on variables 2,4,5, and 9 on the CUDD BDD
+ manager, which may be found anywhere in the current variable order.
+ If remapping is set, the function after ordering depends on the
+ topmost variables in the manager, which may or may not be the same
+ as the variables 2,4,5, and 9. If no remapping is set, then the
+ reordered function depend on the same variables 2,4,5, and 9, but
+ the meaning of each variale has changed according to the new ordering.
+ The resulting ordering is returned in the array "pOrder" filled out
+ by the reordering engine in the call to Extra_Reorder(). The default
+ is no remapping.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_ReorderSetRemapping( reo_man * p, int fRemapUp )
+{
+ p->fRemapUp = fRemapUp;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the number of iterations of sifting performed.]
+
+ Description [The default is one iteration. But a higher minimization
+ quality is desired, it is possible to set the number of iterations
+ to any number larger than 1. Convergence is often reached after
+ several iterations, so typically it make no sense to set the number
+ of iterations higher than 3.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_ReorderSetIterations( reo_man * p, int nIters )
+{
+ p->nIters = nIters;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the verification mode.]
+
+ Description [Setting the level to 1 results in verifying the results
+ of variable reordering. Verification is performed by remapping the
+ resulting functions into the original variable order and comparing
+ them with the original functions given by the user. Enabling verification
+ typically leads to 20-30% increase in the total runtime of REO.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_ReorderSetVerification( reo_man * p, int fVerify )
+{
+ p->fVerify = fVerify;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the verbosity level.]
+
+ Description [Setting the level to 1 results in printing statistics
+ before and after the reordering.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_ReorderSetVerbosity( reo_man * p, int fVerbose )
+{
+ p->fVerbose = fVerbose;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs reordering of the function.]
+
+ Description [Returns the DD minimized by variable reordering in the REO
+ engine. Takes the CUDD decision diagram manager (dd) and the function (Func)
+ represented as a BDD or ADD (MTBDD). If the variable array (pOrder) is not NULL,
+ returns the resulting variable permutation. The permutation is such that if the resulting
+ function is permuted by Cudd_(add,bdd)Permute() using pOrder as the permutation
+ array, the initial function (Func) results.
+ Several flag set by other interface functions specify reordering options:
+ - Remappig can be set by Extra_ReorderSetRemapping(). Then the resulting DD after
+ reordering is remapped into the topmost levels of the DD manager. Otherwise,
+ the resulting DD after reordering is mapped using the same variables, on which it
+ originally depended, only (possibly) permuted as a result of reordering.
+ - Minimization type can be set by Extra_ReorderSetMinimizationType(). Note
+ that when the BDD is minimized for the total width of the total APL, the number
+ BDD nodes can increase. The total width is defines as sum total of widths on each
+ level. The width on one level is defined as the number of distinct BDD nodes
+ pointed by the nodes situated above the given level.
+ - The number of iterations of sifting can be set by Extra_ReorderSetIterations().
+ The decision diagram returned by this procedure is not referenced.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Extra_Reorder( reo_man * p, DdManager * dd, DdNode * Func, int * pOrder )
+{
+ DdNode * FuncRes;
+ Extra_ReorderArray( p, dd, &Func, &FuncRes, 1, pOrder );
+ Cudd_Deref( FuncRes );
+ return FuncRes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs reordering of the array of functions.]
+
+ Description [The options are similar to the procedure Extra_Reorder(), except that
+ the user should also provide storage for the resulting DDs, which are returned
+ referenced.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_ReorderArray( reo_man * p, DdManager * dd, DdNode * Funcs[], DdNode * FuncsRes[], int nFuncs, int * pOrder )
+{
+ reoReorderArray( p, dd, Funcs, FuncsRes, nFuncs, pOrder );
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/bdd/reo/reoCore.c b/src/bdd/reo/reoCore.c
new file mode 100644
index 00000000..3782631c
--- /dev/null
+++ b/src/bdd/reo/reoCore.c
@@ -0,0 +1,438 @@
+/**CFile****************************************************************
+
+ FileName [reoCore.c]
+
+ PackageName [REO: A specialized DD reordering engine.]
+
+ Synopsis [Implementation of the core reordering procedure.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - October 15, 2002.]
+
+ Revision [$Id: reoCore.c,v 1.0 2002/15/10 03:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "reo.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+#define CALLOC(type, num) ((type *) calloc((long)(num), (long)sizeof(type)))
+
+static int reoRecursiveDeref( reo_unit * pUnit );
+static int reoCheckZeroRefs( reo_plane * pPlane );
+static int reoCheckLevels( reo_man * p );
+
+double s_AplBefore;
+double s_AplAfter;
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void reoReorderArray( reo_man * p, DdManager * dd, DdNode * Funcs[], DdNode * FuncsRes[], int nFuncs, int * pOrder )
+{
+ int Counter, i;
+
+ // set the initial parameters
+ p->dd = dd;
+ p->pOrder = pOrder;
+ p->nTops = nFuncs;
+ // get the initial number of nodes
+ p->nNodesBeg = Cudd_SharingSize( Funcs, nFuncs );
+ // resize the internal data structures of the manager if necessary
+ reoResizeStructures( p, ddMax(dd->size,dd->sizeZ), p->nNodesBeg, nFuncs );
+ // compute the support
+ p->pSupp = Extra_VectorSupportArray( dd, Funcs, nFuncs, p->pSupp );
+ // get the number of support variables
+ p->nSupp = 0;
+ for ( i = 0; i < dd->size; i++ )
+ p->nSupp += p->pSupp[i];
+
+ // if it is the constant function, no need to reorder
+ if ( p->nSupp == 0 )
+ {
+ for ( i = 0; i < nFuncs; i++ )
+ {
+ FuncsRes[i] = Funcs[i]; Cudd_Ref( FuncsRes[i] );
+ }
+ return;
+ }
+
+ // create the internal variable maps
+ // go through variable levels in the manager
+ Counter = 0;
+ for ( i = 0; i < dd->size; i++ )
+ if ( p->pSupp[ dd->invperm[i] ] )
+ {
+ p->pMapToPlanes[ dd->invperm[i] ] = Counter;
+ p->pMapToDdVarsOrig[Counter] = dd->invperm[i];
+ if ( !p->fRemapUp )
+ p->pMapToDdVarsFinal[Counter] = dd->invperm[i];
+ else
+ p->pMapToDdVarsFinal[Counter] = dd->invperm[Counter];
+ p->pOrderInt[Counter] = Counter;
+ Counter++;
+ }
+
+ // set the initial parameters
+ p->nUnitsUsed = 0;
+ p->nNodesCur = 0;
+ p->fThisIsAdd = 0;
+ p->Signature++;
+ // transfer the function from the CUDD package into REO"s internal data structure
+ for ( i = 0; i < nFuncs; i++ )
+ p->pTops[i] = reoTransferNodesToUnits_rec( p, Funcs[i] );
+ assert( p->nNodesBeg == p->nNodesCur );
+
+ if ( !p->fThisIsAdd && p->fMinWidth )
+ {
+ printf( "An important message from the REO reordering engine:\n" );
+ printf( "The BDD given to the engine for reordering contains complemented edges.\n" );
+ printf( "Currently, such BDDs cannot be reordered for the minimum width.\n" );
+ printf( "Therefore, minimization for the number of BDD nodes is performed.\n" );
+ fflush( stdout );
+ p->fMinApl = 0;
+ p->fMinWidth = 0;
+ }
+
+ if ( p->fMinWidth )
+ reoProfileWidthStart(p);
+ else if ( p->fMinApl )
+ reoProfileAplStart(p);
+ else
+ reoProfileNodesStart(p);
+
+ if ( p->fVerbose )
+ {
+ printf( "INITIAL: " );
+ if ( p->fMinWidth )
+ reoProfileWidthPrint(p);
+ else if ( p->fMinApl )
+ reoProfileAplPrint(p);
+ else
+ reoProfileNodesPrint(p);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+ // performs the reordering
+ p->nSwaps = 0;
+ p->nNISwaps = 0;
+ for ( i = 0; i < p->nIters; i++ )
+ {
+ reoReorderSift( p );
+ // print statistics after each iteration
+ if ( p->fVerbose )
+ {
+ printf( "ITER #%d: ", i+1 );
+ if ( p->fMinWidth )
+ reoProfileWidthPrint(p);
+ else if ( p->fMinApl )
+ reoProfileAplPrint(p);
+ else
+ reoProfileNodesPrint(p);
+ }
+ // if the cost function did not change, stop iterating
+ if ( p->fMinWidth )
+ {
+ p->nWidthEnd = p->nWidthCur;
+ assert( p->nWidthEnd <= p->nWidthBeg );
+ if ( p->nWidthEnd == p->nWidthBeg )
+ break;
+ }
+ else if ( p->fMinApl )
+ {
+ p->nAplEnd = p->nAplCur;
+ assert( p->nAplEnd <= p->nAplBeg );
+ if ( p->nAplEnd == p->nAplBeg )
+ break;
+ }
+ else
+ {
+ p->nNodesEnd = p->nNodesCur;
+ assert( p->nNodesEnd <= p->nNodesBeg );
+ if ( p->nNodesEnd == p->nNodesBeg )
+ break;
+ }
+ }
+ assert( reoCheckLevels( p ) );
+ ///////////////////////////////////////////////////////////////////
+
+s_AplBefore = p->nAplBeg;
+s_AplAfter = p->nAplEnd;
+
+ // set the initial parameters
+ p->nRefNodes = 0;
+ p->nNodesCur = 0;
+ p->Signature++;
+ // transfer the BDDs from REO's internal data structure to CUDD
+ for ( i = 0; i < nFuncs; i++ )
+ {
+ FuncsRes[i] = reoTransferUnitsToNodes_rec( p, p->pTops[i] ); Cudd_Ref( FuncsRes[i] );
+ }
+ // undo the DDs referenced for storing in the cache
+ for ( i = 0; i < p->nRefNodes; i++ )
+ Cudd_RecursiveDeref( dd, p->pRefNodes[i] );
+ // verify zero refs of the terminal nodes
+ for ( i = 0; i < nFuncs; i++ )
+ {
+ assert( reoRecursiveDeref( p->pTops[i] ) );
+ }
+ assert( reoCheckZeroRefs( &(p->pPlanes[p->nSupp]) ) );
+
+ // prepare the variable map to return to the user
+ if ( p->pOrder )
+ {
+ // i is the current level in the planes data structure
+ // p->pOrderInt[i] is the original level in the planes data structure
+ // p->pMapToDdVarsOrig[i] is the variable, into which we remap when we construct the BDD from planes
+ // p->pMapToDdVarsOrig[ p->pOrderInt[i] ] is the original BDD variable corresponding to this level
+ // Therefore, p->pOrder[ p->pMapToDdVarsFinal[i] ] = p->pMapToDdVarsOrig[ p->pOrderInt[i] ]
+ // creates the permutation, which remaps the resulting BDD variable into the original BDD variable
+ for ( i = 0; i < p->nSupp; i++ )
+ p->pOrder[ p->pMapToDdVarsFinal[i] ] = p->pMapToDdVarsOrig[ p->pOrderInt[i] ];
+ }
+
+ if ( p->fVerify )
+ {
+ int fVerification;
+ DdNode * FuncRemapped;
+ int * pOrder;
+
+ if ( p->pOrder == NULL )
+ {
+ pOrder = ALLOC( int, p->nSupp );
+ for ( i = 0; i < p->nSupp; i++ )
+ pOrder[ p->pMapToDdVarsFinal[i] ] = p->pMapToDdVarsOrig[ p->pOrderInt[i] ];
+ }
+ else
+ pOrder = p->pOrder;
+
+ fVerification = 1;
+ for ( i = 0; i < nFuncs; i++ )
+ {
+ // verify the result
+ if ( p->fThisIsAdd )
+ FuncRemapped = Cudd_addPermute( dd, FuncsRes[i], pOrder );
+ else
+ FuncRemapped = Cudd_bddPermute( dd, FuncsRes[i], pOrder );
+ Cudd_Ref( FuncRemapped );
+
+ if ( FuncRemapped != Funcs[i] )
+ {
+ fVerification = 0;
+ printf( "REO: Internal verification has failed!\n" );
+ fflush( stdout );
+ }
+ Cudd_RecursiveDeref( dd, FuncRemapped );
+ }
+ if ( fVerification )
+ printf( "REO: Internal verification is okay!\n" );
+
+ if ( p->pOrder == NULL )
+ free( pOrder );
+ }
+
+ // recycle the data structure
+ for ( i = 0; i <= p->nSupp; i++ )
+ reoUnitsRecycleUnitList( p, p->pPlanes + i );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Resizes the internal manager data structures.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void reoResizeStructures( reo_man * p, int nDdVarsMax, int nNodesMax, int nFuncs )
+{
+ // resize data structures depending on the number of variables in the DD manager
+ if ( p->nSuppAlloc == 0 )
+ {
+ p->pSupp = ALLOC( int, nDdVarsMax + 1 );
+ p->pOrderInt = ALLOC( int, nDdVarsMax + 1 );
+ p->pMapToPlanes = ALLOC( int, nDdVarsMax + 1 );
+ p->pMapToDdVarsOrig = ALLOC( int, nDdVarsMax + 1 );
+ p->pMapToDdVarsFinal = ALLOC( int, nDdVarsMax + 1 );
+ p->pPlanes = CALLOC( reo_plane, nDdVarsMax + 1 );
+ p->pVarCosts = ALLOC( double, nDdVarsMax + 1 );
+ p->pLevelOrder = ALLOC( int, nDdVarsMax + 1 );
+ p->nSuppAlloc = nDdVarsMax + 1;
+ }
+ else if ( p->nSuppAlloc < nDdVarsMax )
+ {
+ free( p->pSupp );
+ free( p->pOrderInt );
+ free( p->pMapToPlanes );
+ free( p->pMapToDdVarsOrig );
+ free( p->pMapToDdVarsFinal );
+ free( p->pPlanes );
+ free( p->pVarCosts );
+ free( p->pLevelOrder );
+
+ p->pSupp = ALLOC( int, nDdVarsMax + 1 );
+ p->pOrderInt = ALLOC( int, nDdVarsMax + 1 );
+ p->pMapToPlanes = ALLOC( int, nDdVarsMax + 1 );
+ p->pMapToDdVarsOrig = ALLOC( int, nDdVarsMax + 1 );
+ p->pMapToDdVarsFinal = ALLOC( int, nDdVarsMax + 1 );
+ p->pPlanes = CALLOC( reo_plane, nDdVarsMax + 1 );
+ p->pVarCosts = ALLOC( double, nDdVarsMax + 1 );
+ p->pLevelOrder = ALLOC( int, nDdVarsMax + 1 );
+ p->nSuppAlloc = nDdVarsMax + 1;
+ }
+
+ // resize the data structures depending on the number of nodes
+ if ( p->nRefNodesAlloc == 0 )
+ {
+ p->nNodesMaxAlloc = nNodesMax;
+ p->nTableSize = 3*nNodesMax + 1;
+ p->nRefNodesAlloc = 3*nNodesMax + 1;
+ p->nMemChunksAlloc = (10*nNodesMax + 1)/REO_CHUNK_SIZE + 1;
+
+ p->HTable = CALLOC( reo_hash, p->nTableSize );
+ p->pRefNodes = ALLOC( DdNode *, p->nRefNodesAlloc );
+ p->pWidthCofs = ALLOC( reo_unit *, p->nRefNodesAlloc );
+ p->pMemChunks = ALLOC( reo_unit *, p->nMemChunksAlloc );
+ }
+ else if ( p->nNodesMaxAlloc < nNodesMax )
+ {
+ void * pTemp;
+ int nMemChunksAllocPrev = p->nMemChunksAlloc;
+
+ p->nNodesMaxAlloc = nNodesMax;
+ p->nTableSize = 3*nNodesMax + 1;
+ p->nRefNodesAlloc = 3*nNodesMax + 1;
+ p->nMemChunksAlloc = (10*nNodesMax + 1)/REO_CHUNK_SIZE + 1;
+
+ free( p->HTable );
+ free( p->pRefNodes );
+ free( p->pWidthCofs );
+ p->HTable = CALLOC( reo_hash, p->nTableSize );
+ p->pRefNodes = ALLOC( DdNode *, p->nRefNodesAlloc );
+ p->pWidthCofs = ALLOC( reo_unit *, p->nRefNodesAlloc );
+ // p->pMemChunks should be reallocated because it contains pointers currently in use
+ pTemp = ALLOC( reo_unit *, p->nMemChunksAlloc );
+ memmove( pTemp, p->pMemChunks, sizeof(reo_unit *) * nMemChunksAllocPrev );
+ free( p->pMemChunks );
+ p->pMemChunks = pTemp;
+ }
+
+ // resize the data structures depending on the number of functions
+ if ( p->nTopsAlloc == 0 )
+ {
+ p->pTops = ALLOC( reo_unit *, nFuncs );
+ p->nTopsAlloc = nFuncs;
+ }
+ else if ( p->nTopsAlloc < nFuncs )
+ {
+ free( p->pTops );
+ p->pTops = ALLOC( reo_unit *, nFuncs );
+ p->nTopsAlloc = nFuncs;
+ }
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Dereferences units the data structure after reordering.]
+
+ Description [This function is only useful for debugging.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int reoRecursiveDeref( reo_unit * pUnit )
+{
+ reo_unit * pUnitR;
+ pUnitR = Unit_Regular(pUnit);
+ pUnitR->n--;
+ if ( Unit_IsConstant(pUnitR) )
+ return 1;
+ if ( pUnitR->n == 0 )
+ {
+ reoRecursiveDeref( pUnitR->pE );
+ reoRecursiveDeref( pUnitR->pT );
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks the zero references for the given plane.]
+
+ Description [This function is only useful for debugging.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int reoCheckZeroRefs( reo_plane * pPlane )
+{
+ reo_unit * pUnit;
+ for ( pUnit = pPlane->pHead; pUnit; pUnit = pUnit->Next )
+ {
+ if ( pUnit->n != 0 )
+ {
+ assert( 0 );
+ }
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks the zero references for the given plane.]
+
+ Description [This function is only useful for debugging.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int reoCheckLevels( reo_man * p )
+{
+ reo_unit * pUnit;
+ int i;
+
+ for ( i = 0; i < p->nSupp; i++ )
+ {
+ // there are some nodes left on each level
+ assert( p->pPlanes[i].statsNodes );
+ for ( pUnit = p->pPlanes[i].pHead; pUnit; pUnit = pUnit->Next )
+ {
+ // the level is properly set
+ assert( pUnit->lev == i );
+ }
+ }
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/bdd/reo/reoProfile.c b/src/bdd/reo/reoProfile.c
new file mode 100644
index 00000000..b38575f0
--- /dev/null
+++ b/src/bdd/reo/reoProfile.c
@@ -0,0 +1,365 @@
+/**CFile****************************************************************
+
+ FileName [reoProfile.c]
+
+ PackageName [REO: A specialized DD reordering engine.]
+
+ Synopsis [Procudures that compute variables profiles (nodes, width, APL).]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - October 15, 2002.]
+
+ Revision [$Id: reoProfile.c,v 1.0 2002/15/10 03:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "reo.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+
+/**Function********************************************************************
+
+ Synopsis [Start the profile for the BDD nodes.]
+
+ Description [TopRef is the first level, on this the given node counts towards
+ the width of the BDDs. (In other words, it is the level of the referencing node plus 1.)]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void reoProfileNodesStart( reo_man * p )
+{
+ int Total, i;
+ Total = 0;
+ for ( i = 0; i <= p->nSupp; i++ )
+ {
+ p->pPlanes[i].statsCost = p->pPlanes[i].statsNodes;
+ Total += p->pPlanes[i].statsNodes;
+ }
+ assert( Total == p->nNodesCur );
+ p->nNodesBeg = p->nNodesCur;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Start the profile for the APL.]
+
+ Description [Computes the total path length. The path length is normalized
+ by dividing it by 2^|supp(f)|. To get the "real" APL, multiply by 2^|supp(f)|.
+ This procedure assumes that Weight field of all nodes has been set to 0.0
+ before the call, except for the weight of the topmost node, which is set to 1.0
+ (1.0 is the probability of traversing the topmost node). This procedure
+ assigns the edge weights. Because of the equal probability of selecting 0 and 1
+ assignment at a node, the edge weights are the same for the node.
+ Instead of storing them, we store the weight of the node, which is the probability
+ of traversing the node (pUnit->Weight) during the top down evalation of the BDD. ]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void reoProfileAplStart( reo_man * p )
+{
+ reo_unit * pER, * pTR;
+ reo_unit * pUnit;
+ double Res, Half;
+ int i;
+
+ // clean the weights of all nodes
+ for ( i = 0; i < p->nSupp; i++ )
+ for ( pUnit = p->pPlanes[i].pHead; pUnit; pUnit = pUnit->Next )
+ pUnit->Weight = 0.0;
+ // to assign the node weights (the probability of visiting each node)
+ // we visit the node after visiting its predecessors
+
+ // set the probability of visits to the top nodes
+ for ( i = 0; i < p->nTops; i++ )
+ Unit_Regular(p->pTops[i])->Weight += 1.0;
+
+ // to compute the path length (the sum of products of edge weight by edge length)
+ // we visit the nodes in any order (the above order will do)
+ Res = 0.0;
+ for ( i = 0; i < p->nSupp; i++ )
+ {
+ p->pPlanes[i].statsCost = 0.0;
+ for ( pUnit = p->pPlanes[i].pHead; pUnit; pUnit = pUnit->Next )
+ {
+ pER = Unit_Regular(pUnit->pE);
+ pTR = Unit_Regular(pUnit->pT);
+ Half = 0.5 * pUnit->Weight;
+ pER->Weight += Half;
+ pTR->Weight += Half;
+ // add to the path length
+ p->pPlanes[i].statsCost += pUnit->Weight;
+ }
+ Res += p->pPlanes[i].statsCost;
+ }
+ p->pPlanes[p->nSupp].statsCost = 0.0;
+ p->nAplBeg = p->nAplCur = Res;
+}
+
+/**Function********************************************************************
+
+ Synopsis [Start the profile for the BDD width. Complexity of the algorithm is O(N + n).]
+
+ Description [TopRef is the first level, on which the given node counts towards
+ the width of the BDDs. (In other words, it is the level of the referencing node plus 1.)]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void reoProfileWidthStart( reo_man * p )
+{
+ reo_unit * pUnit;
+ int * pWidthStart;
+ int * pWidthStop;
+ int v;
+
+ // allocate and clean the storage for starting and stopping levels
+ pWidthStart = ALLOC( int, p->nSupp + 1 );
+ pWidthStop = ALLOC( int, p->nSupp + 1 );
+ memset( pWidthStart, 0, sizeof(int) * (p->nSupp + 1) );
+ memset( pWidthStop, 0, sizeof(int) * (p->nSupp + 1) );
+
+ // go through the non-constant nodes and set the topmost level of their cofactors
+ for ( v = 0; v <= p->nSupp; v++ )
+ for ( pUnit = p->pPlanes[v].pHead; pUnit; pUnit = pUnit->Next )
+ {
+ pUnit->TopRef = REO_TOPREF_UNDEF;
+ pUnit->Sign = 0;
+ }
+
+ // add the topmost level of the width profile
+ for ( v = 0; v < p->nTops; v++ )
+ {
+ pUnit = Unit_Regular(p->pTops[v]);
+ if ( pUnit->TopRef == REO_TOPREF_UNDEF )
+ {
+ // set the starting level
+ pUnit->TopRef = 0;
+ pWidthStart[pUnit->TopRef]++;
+ // set the stopping level
+ if ( pUnit->lev != REO_CONST_LEVEL )
+ pWidthStop[pUnit->lev+1]++;
+ }
+ }
+
+ for ( v = 0; v < p->nSupp; v++ )
+ for ( pUnit = p->pPlanes[v].pHead; pUnit; pUnit = pUnit->Next )
+ {
+ if ( pUnit->pE->TopRef == REO_TOPREF_UNDEF )
+ {
+ // set the starting level
+ pUnit->pE->TopRef = pUnit->lev + 1;
+ pWidthStart[pUnit->pE->TopRef]++;
+ // set the stopping level
+ if ( pUnit->pE->lev != REO_CONST_LEVEL )
+ pWidthStop[pUnit->pE->lev+1]++;
+ }
+ if ( pUnit->pT->TopRef == REO_TOPREF_UNDEF )
+ {
+ // set the starting level
+ pUnit->pT->TopRef = pUnit->lev + 1;
+ pWidthStart[pUnit->pT->TopRef]++;
+ // set the stopping level
+ if ( pUnit->pT->lev != REO_CONST_LEVEL )
+ pWidthStop[pUnit->pT->lev+1]++;
+ }
+ }
+
+ // verify the top reference
+ for ( v = 0; v < p->nSupp; v++ )
+ reoProfileWidthVerifyLevel( p->pPlanes + v, v );
+
+ // derive the profile
+ p->nWidthCur = 0;
+ for ( v = 0; v <= p->nSupp; v++ )
+ {
+ if ( v == 0 )
+ p->pPlanes[v].statsWidth = pWidthStart[v] - pWidthStop[v];
+ else
+ p->pPlanes[v].statsWidth = p->pPlanes[v-1].statsWidth + pWidthStart[v] - pWidthStop[v];
+ p->pPlanes[v].statsCost = p->pPlanes[v].statsWidth;
+ p->nWidthCur += p->pPlanes[v].statsWidth;
+// printf( "Level %2d: Width = %5d. Correct = %d.\n", v, Temp, p->pPlanes[v].statsWidth );
+ }
+ p->nWidthBeg = p->nWidthCur;
+ free( pWidthStart );
+ free( pWidthStop );
+}
+
+/**Function********************************************************************
+
+ Synopsis [Start the profile for the BDD width. Complexity of the algorithm is O(N * n).]
+
+ Description [TopRef is the first level, on which the given node counts towards
+ the width of the BDDs. (In other words, it is the level of the referencing node plus 1.)]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void reoProfileWidthStart2( reo_man * p )
+{
+ reo_unit * pUnit;
+ int i, v;
+
+ // clean the profile
+ for ( i = 0; i <= p->nSupp; i++ )
+ p->pPlanes[i].statsWidth = 0;
+
+ // clean the node structures
+ for ( v = 0; v <= p->nSupp; v++ )
+ for ( pUnit = p->pPlanes[v].pHead; pUnit; pUnit = pUnit->Next )
+ {
+ pUnit->TopRef = REO_TOPREF_UNDEF;
+ pUnit->Sign = 0;
+ }
+
+ // set the topref to the topmost nodes
+ for ( i = 0; i < p->nTops; i++ )
+ Unit_Regular(p->pTops[i])->TopRef = 0;
+
+ // go through the non-constant nodes and set the topmost level of their cofactors
+ for ( i = 0; i < p->nSupp; i++ )
+ for ( pUnit = p->pPlanes[i].pHead; pUnit; pUnit = pUnit->Next )
+ {
+ if ( pUnit->pE->TopRef > i+1 )
+ pUnit->pE->TopRef = i+1;
+ if ( pUnit->pT->TopRef > i+1 )
+ pUnit->pT->TopRef = i+1;
+ }
+
+ // verify the top reference
+ for ( i = 0; i < p->nSupp; i++ )
+ reoProfileWidthVerifyLevel( p->pPlanes + i, i );
+
+ // compute the profile for the internal nodes
+ for ( i = 0; i < p->nSupp; i++ )
+ for ( pUnit = p->pPlanes[i].pHead; pUnit; pUnit = pUnit->Next )
+ for ( v = pUnit->TopRef; v <= pUnit->lev; v++ )
+ p->pPlanes[v].statsWidth++;
+
+ // compute the profile for the constant nodes
+ for ( pUnit = p->pPlanes[p->nSupp].pHead; pUnit; pUnit = pUnit->Next )
+ for ( v = pUnit->TopRef; v <= p->nSupp; v++ )
+ p->pPlanes[v].statsWidth++;
+
+ // get the width cost
+ p->nWidthCur = 0;
+ for ( i = 0; i <= p->nSupp; i++ )
+ {
+ p->pPlanes[i].statsCost = p->pPlanes[i].statsWidth;
+ p->nWidthCur += p->pPlanes[i].statsWidth;
+ }
+ p->nWidthBeg = p->nWidthCur;
+}
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void reoProfileNodesPrint( reo_man * p )
+{
+ printf( "NODES: Total = %6d. Average = %6.2f.\n", p->nNodesCur, p->nNodesCur / (float)p->nSupp );
+}
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void reoProfileAplPrint( reo_man * p )
+{
+ printf( "APL: Total = %8.2f. Average =%6.2f.\n", p->nAplCur, p->nAplCur / (float)p->nSupp );
+}
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void reoProfileWidthPrint( reo_man * p )
+{
+ int WidthMax;
+ int TotalWidth;
+ int i;
+
+ WidthMax = 0;
+ TotalWidth = 0;
+ for ( i = 0; i <= p->nSupp; i++ )
+ {
+// printf( "Level = %2d. Width = %3d.\n", i, p->pProfile[i] );
+ if ( WidthMax < p->pPlanes[i].statsWidth )
+ WidthMax = p->pPlanes[i].statsWidth;
+ TotalWidth += p->pPlanes[i].statsWidth;
+ }
+ assert( p->nWidthCur = TotalWidth );
+ printf( "WIDTH: " );
+ printf( "Maximum = %5d. ", WidthMax );
+ printf( "Total = %7d. ", p->nWidthCur );
+ printf( "Average = %6.2f.\n", TotalWidth / (float)p->nSupp );
+}
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void reoProfileWidthVerifyLevel( reo_plane * pPlane, int Level )
+{
+ reo_unit * pUnit;
+ for ( pUnit = pPlane->pHead; pUnit; pUnit = pUnit->Next )
+ {
+ assert( pUnit->TopRef <= Level );
+ assert( pUnit->pE->TopRef <= Level + 1 );
+ assert( pUnit->pT->TopRef <= Level + 1 );
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/bdd/reo/reoSift.c b/src/bdd/reo/reoSift.c
new file mode 100644
index 00000000..93d82f08
--- /dev/null
+++ b/src/bdd/reo/reoSift.c
@@ -0,0 +1,341 @@
+/**CFile****************************************************************
+
+ FileName [reoSift.c]
+
+ PackageName [REO: A specialized DD reordering engine.]
+
+ Synopsis [Implementation of the sifting algorihtm.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - October 15, 2002.]
+
+ Revision [$Id: reoSift.c,v 1.0 2002/15/10 03:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "reo.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Implements the variable sifting algorithm.]
+
+ Description [Performs a sequence of adjacent variable swaps known as "sifting".
+ Uses the cost functions determined by the flag.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void reoReorderSift( reo_man * p )
+{
+ double CostCurrent; // the cost of the current permutation
+ double CostLimit; // the maximum increase in cost that can be tolerated
+ double CostBest; // the best cost
+ int BestQ; // the best position
+ int VarCurrent; // the current variable to move
+ int q; // denotes the current position of the variable
+ int c; // performs the loops over variables until all of them are sifted
+ int v; // used for other purposes
+
+ assert( p->nSupp > 0 );
+
+ // set the current cost depending on the minimization criteria
+ if ( p->fMinWidth )
+ CostCurrent = p->nWidthCur;
+ else if ( p->fMinApl )
+ CostCurrent = p->nAplCur;
+ else
+ CostCurrent = p->nNodesCur;
+
+ // find the upper bound on tbe cost growth
+ CostLimit = 1 + (int)(REO_REORDER_LIMIT * CostCurrent);
+
+ // perform sifting for each of p->nSupp variables
+ for ( c = 0; c < p->nSupp; c++ )
+ {
+ // select the current variable to be the one with the largest number of nodes that is not sifted yet
+ VarCurrent = -1;
+ CostBest = -1.0;
+ for ( v = 0; v < p->nSupp; v++ )
+ {
+ p->pVarCosts[v] = REO_HIGH_VALUE;
+ if ( !p->pPlanes[v].fSifted )
+ {
+// VarCurrent = v;
+// if ( CostBest < p->pPlanes[v].statsCost )
+ if ( CostBest < p->pPlanes[v].statsNodes )
+ {
+// CostBest = p->pPlanes[v].statsCost;
+ CostBest = p->pPlanes[v].statsNodes;
+ VarCurrent = v;
+ }
+
+ }
+ }
+ assert( VarCurrent != -1 );
+ // mark this variable as sifted
+ p->pPlanes[VarCurrent].fSifted = 1;
+
+ // set the current value
+ p->pVarCosts[VarCurrent] = CostCurrent;
+
+ // set the best cost
+ CostBest = CostCurrent;
+ BestQ = VarCurrent;
+
+ // determine which way to move the variable first (up or down)
+ // the rationale is that if we move the shorter way first
+ // it is more likely that the best position will be found on the longer way
+ // and the reverse movement (to take the best position) will be faster
+ if ( VarCurrent < p->nSupp/2 ) // move up first, then down
+ {
+ // set the total cost on all levels above the current level
+ p->pPlanes[0].statsCostAbove = 0;
+ for ( v = 1; v <= VarCurrent; v++ )
+ p->pPlanes[v].statsCostAbove = p->pPlanes[v-1].statsCostAbove + p->pPlanes[v-1].statsCost;
+ // set the total cost on all levels below the current level
+ p->pPlanes[p->nSupp].statsCostBelow = 0;
+ for ( v = p->nSupp - 1; v >= VarCurrent; v-- )
+ p->pPlanes[v].statsCostBelow = p->pPlanes[v+1].statsCostBelow + p->pPlanes[v+1].statsCost;
+
+ assert( CostCurrent == p->pPlanes[VarCurrent].statsCostAbove +
+ p->pPlanes[VarCurrent].statsCost +
+ p->pPlanes[VarCurrent].statsCostBelow );
+
+ // move up
+ for ( q = VarCurrent-1; q >= 0; q-- )
+ {
+ CostCurrent -= reoReorderSwapAdjacentVars( p, q, 1 );
+ // now q points to the position of this var in the order
+ p->pVarCosts[q] = CostCurrent;
+ // update the lower bound (assuming that for level q+1 it is set correctly)
+ p->pPlanes[q].statsCostBelow = p->pPlanes[q+1].statsCostBelow + p->pPlanes[q+1].statsCost;
+ // check the upper bound
+ if ( CostCurrent >= CostLimit )
+ break;
+ // check the lower bound
+ if ( p->pPlanes[q].statsCostBelow + (REO_QUAL_PAR-1)*p->pPlanes[q].statsCostAbove/REO_QUAL_PAR >= CostBest )
+ break;
+ // update the best cost
+ if ( CostBest > CostCurrent )
+ {
+ CostBest = CostCurrent;
+ BestQ = q;
+ // adjust node limit
+ CostLimit = ddMin( CostLimit, 1 + (int)(REO_REORDER_LIMIT * CostCurrent) );
+ }
+
+ // when we are reordering for width or APL, it may happen that
+ // the number of nodes has grown above certain limit,
+ // in which case we have to resize the data structures
+ if ( p->fMinWidth || p->fMinApl )
+ {
+ if ( p->nNodesCur >= 2 * p->nNodesMaxAlloc )
+ {
+// printf( "Resizing data structures. Old size = %6d. New size = %6d.\n", p->nNodesMaxAlloc, p->nNodesCur );
+ reoResizeStructures( p, 0, p->nNodesCur, 0 );
+ }
+ }
+ }
+ // fix the plane index
+ if ( q == -1 )
+ q++;
+ // now p points to the position of this var in the order
+
+ // move down
+ for ( ; q < p->nSupp-1; )
+ {
+ CostCurrent -= reoReorderSwapAdjacentVars( p, q, 0 );
+ q++; // change q to point to the position of this var in the order
+ // sanity check: the number of nodes on the back pass should be the same
+ if ( p->pVarCosts[q] != REO_HIGH_VALUE && fabs( p->pVarCosts[q] - CostCurrent ) > REO_COST_EPSILON )
+ printf("reoReorderSift(): Error! On the backward move, the costs are different.\n");
+ p->pVarCosts[q] = CostCurrent;
+ // update the lower bound (assuming that for level q-1 it is set correctly)
+ p->pPlanes[q].statsCostAbove = p->pPlanes[q-1].statsCostAbove + p->pPlanes[q-1].statsCost;
+ // check the bounds only if the variable already reached its previous position
+ if ( q >= BestQ )
+ {
+ // check the upper bound
+ if ( CostCurrent >= CostLimit )
+ break;
+ // check the lower bound
+ if ( p->pPlanes[q].statsCostAbove + (REO_QUAL_PAR-1)*p->pPlanes[q].statsCostBelow/REO_QUAL_PAR >= CostBest )
+ break;
+ }
+ // update the best cost
+ if ( CostBest >= CostCurrent )
+ {
+ CostBest = CostCurrent;
+ BestQ = q;
+ // adjust node limit
+ CostLimit = ddMin( CostLimit, 1 + (int)(REO_REORDER_LIMIT * CostCurrent) );
+ }
+
+ // when we are reordering for width or APL, it may happen that
+ // the number of nodes has grown above certain limit,
+ // in which case we have to resize the data structures
+ if ( p->fMinWidth || p->fMinApl )
+ {
+ if ( p->nNodesCur >= 2 * p->nNodesMaxAlloc )
+ {
+// printf( "Resizing data structures. Old size = %6d. New size = %6d.\n", p->nNodesMaxAlloc, p->nNodesCur );
+ reoResizeStructures( p, 0, p->nNodesCur, 0 );
+ }
+ }
+ }
+ // move the variable up from the given position (q) to the best position (BestQ)
+ assert( q >= BestQ );
+ for ( ; q > BestQ; q-- )
+ {
+ CostCurrent -= reoReorderSwapAdjacentVars( p, q-1, 1 );
+ // sanity check: the number of nodes on the back pass should be the same
+ if ( fabs( p->pVarCosts[q-1] - CostCurrent ) > REO_COST_EPSILON )
+ {
+ printf("reoReorderSift(): Error! On the return move, the costs are different.\n" );
+ fflush(stdout);
+ }
+ }
+ }
+ else // move down first, then up
+ {
+ // set the current number of nodes on all levels above the given level
+ p->pPlanes[0].statsCostAbove = 0;
+ for ( v = 1; v <= VarCurrent; v++ )
+ p->pPlanes[v].statsCostAbove = p->pPlanes[v-1].statsCostAbove + p->pPlanes[v-1].statsCost;
+ // set the current number of nodes on all levels below the given level
+ p->pPlanes[p->nSupp].statsCostBelow = 0;
+ for ( v = p->nSupp - 1; v >= VarCurrent; v-- )
+ p->pPlanes[v].statsCostBelow = p->pPlanes[v+1].statsCostBelow + p->pPlanes[v+1].statsCost;
+
+ assert( CostCurrent == p->pPlanes[VarCurrent].statsCostAbove +
+ p->pPlanes[VarCurrent].statsCost +
+ p->pPlanes[VarCurrent].statsCostBelow );
+
+ // move down
+ for ( q = VarCurrent; q < p->nSupp-1; )
+ {
+ CostCurrent -= reoReorderSwapAdjacentVars( p, q, 0 );
+ q++; // change q to point to the position of this var in the order
+ p->pVarCosts[q] = CostCurrent;
+ // update the lower bound (assuming that for level q-1 it is set correctly)
+ p->pPlanes[q].statsCostAbove = p->pPlanes[q-1].statsCostAbove + p->pPlanes[q-1].statsCost;
+ // check the upper bound
+ if ( CostCurrent >= CostLimit )
+ break;
+ // check the lower bound
+ if ( p->pPlanes[q].statsCostAbove + (REO_QUAL_PAR-1)*p->pPlanes[q].statsCostBelow/REO_QUAL_PAR >= CostBest )
+ break;
+ // update the best cost
+ if ( CostBest > CostCurrent )
+ {
+ CostBest = CostCurrent;
+ BestQ = q;
+ // adjust node limit
+ CostLimit = ddMin( CostLimit, 1 + (int)(REO_REORDER_LIMIT * CostCurrent) );
+ }
+
+ // when we are reordering for width or APL, it may happen that
+ // the number of nodes has grown above certain limit,
+ // in which case we have to resize the data structures
+ if ( p->fMinWidth || p->fMinApl )
+ {
+ if ( p->nNodesCur >= 2 * p->nNodesMaxAlloc )
+ {
+// printf( "Resizing data structures. Old size = %6d. New size = %6d.\n", p->nNodesMaxAlloc, p->nNodesCur );
+ reoResizeStructures( p, 0, p->nNodesCur, 0 );
+ }
+ }
+ }
+
+ // move up
+ for ( --q; q >= 0; q-- )
+ {
+ CostCurrent -= reoReorderSwapAdjacentVars( p, q, 1 );
+ // now q points to the position of this var in the order
+ // sanity check: the number of nodes on the back pass should be the same
+ if ( p->pVarCosts[q] != REO_HIGH_VALUE && fabs( p->pVarCosts[q] - CostCurrent ) > REO_COST_EPSILON )
+ printf("reoReorderSift(): Error! On the backward move, the costs are different.\n");
+ p->pVarCosts[q] = CostCurrent;
+ // update the lower bound (assuming that for level q+1 it is set correctly)
+ p->pPlanes[q].statsCostBelow = p->pPlanes[q+1].statsCostBelow + p->pPlanes[q+1].statsCost;
+ // check the bounds only if the variable already reached its previous position
+ if ( q <= BestQ )
+ {
+ // check the upper bound
+ if ( CostCurrent >= CostLimit )
+ break;
+ // check the lower bound
+ if ( p->pPlanes[q].statsCostBelow + (REO_QUAL_PAR-1)*p->pPlanes[q].statsCostAbove/REO_QUAL_PAR >= CostBest )
+ break;
+ }
+ // update the best cost
+ if ( CostBest >= CostCurrent )
+ {
+ CostBest = CostCurrent;
+ BestQ = q;
+ // adjust node limit
+ CostLimit = ddMin( CostLimit, 1 + (int)(REO_REORDER_LIMIT * CostCurrent) );
+ }
+
+ // when we are reordering for width or APL, it may happen that
+ // the number of nodes has grown above certain limit,
+ // in which case we have to resize the data structures
+ if ( p->fMinWidth || p->fMinApl )
+ {
+ if ( p->nNodesCur >= 2 * p->nNodesMaxAlloc )
+ {
+// printf( "Resizing data structures. Old size = %6d. New size = %6d.\n", p->nNodesMaxAlloc, p->nNodesCur );
+ reoResizeStructures( p, 0, p->nNodesCur, 0 );
+ }
+ }
+ }
+ // fix the plane index
+ if ( q == -1 )
+ q++;
+ // now q points to the position of this var in the order
+ // move the variable down from the given position (q) to the best position (BestQ)
+ assert( q <= BestQ );
+ for ( ; q < BestQ; q++ )
+ {
+ CostCurrent -= reoReorderSwapAdjacentVars( p, q, 0 );
+ // sanity check: the number of nodes on the back pass should be the same
+ if ( fabs( p->pVarCosts[q+1] - CostCurrent ) > REO_COST_EPSILON )
+ {
+ printf("reoReorderSift(): Error! On the return move, the costs are different.\n" );
+ fflush(stdout);
+ }
+ }
+ }
+ assert( fabs( CostBest - CostCurrent ) < REO_COST_EPSILON );
+
+ // update the cost
+ if ( p->fMinWidth )
+ p->nWidthCur = (int)CostBest;
+ else if ( p->fMinApl )
+ p->nAplCur = CostCurrent;
+ else
+ p->nNodesCur = (int)CostBest;
+ }
+
+ // remove the sifted attributes if any
+ for ( v = 0; v < p->nSupp; v++ )
+ p->pPlanes[v].fSifted = 0;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/bdd/reo/reoSwap.c b/src/bdd/reo/reoSwap.c
new file mode 100644
index 00000000..cb730d8e
--- /dev/null
+++ b/src/bdd/reo/reoSwap.c
@@ -0,0 +1,898 @@
+/**CFile****************************************************************
+
+ FileName [reoSwap.c]
+
+ PackageName [REO: A specialized DD reordering engine.]
+
+ Synopsis [Implementation of the two-variable swap.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - October 15, 2002.]
+
+ Revision [$Id: reoSwap.c,v 1.0 2002/15/10 03:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "reo.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+#define AddToLinkedList( ppList, pLink ) (((pLink)->Next = *(ppList)), (*(ppList) = (pLink)))
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description [Takes the level (lev0) of the plane, which should be swapped
+ with the next plane. Returns the gain using the current cost function.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+double reoReorderSwapAdjacentVars( reo_man * p, int lev0, int fMovingUp )
+{
+ // the levels in the decision diagram
+ int lev1 = lev0 + 1, lev2 = lev0 + 2;
+ // the new nodes on lev0
+ reo_unit * pLoop, * pUnit;
+ // the new nodes on lev1
+ reo_unit * pNewPlane20, * pNewPlane21, * pNewPlane20R;
+ reo_unit * pUnitE, * pUnitER, * pUnitT;
+ // the nodes below lev1
+ reo_unit * pNew1E, * pNew1T, * pNew2E, * pNew2T;
+ reo_unit * pNew1ER, * pNew2ER;
+ // the old linked lists
+ reo_unit * pListOld0 = p->pPlanes[lev0].pHead;
+ reo_unit * pListOld1 = p->pPlanes[lev1].pHead;
+ // working planes and one more temporary plane
+ reo_unit * pListNew0 = NULL, ** ppListNew0 = &pListNew0;
+ reo_unit * pListNew1 = NULL, ** ppListNew1 = &pListNew1;
+ reo_unit * pListTemp = NULL, ** ppListTemp = &pListTemp;
+ // various integer variables
+ int fComp, fCompT, fFound, nWidthCofs, HKey, fInteract, temp, c;
+ // statistical variables
+ int nNodesUpMovedDown = 0;
+ int nNodesDownMovedUp = 0;
+ int nNodesUnrefRemoved = 0;
+ int nNodesUnrefAdded = 0;
+ int nWidthReduction = 0;
+ double AplWeightTotalLev0;
+ double AplWeightTotalLev1;
+ double AplWeightHalf;
+ double AplWeightPrev;
+ double AplWeightAfter;
+ double nCostGain;
+
+ // set the old lists
+ assert( lev0 >= 0 && lev1 < p->nSupp );
+ pListOld0 = p->pPlanes[lev0].pHead;
+ pListOld1 = p->pPlanes[lev1].pHead;
+
+ // make sure the planes have nodes
+ assert( p->pPlanes[lev0].statsNodes && p->pPlanes[lev1].statsNodes );
+ assert( pListOld0 && pListOld1 );
+
+ if ( p->fMinWidth )
+ {
+ // verify that the width parameters are set correctly
+ reoProfileWidthVerifyLevel( p->pPlanes + lev0, lev0 );
+ reoProfileWidthVerifyLevel( p->pPlanes + lev1, lev1 );
+ // start the storage for cofactors
+ nWidthCofs = 0;
+ }
+ else if ( p->fMinApl )
+ {
+ AplWeightPrev = p->nAplCur;
+ AplWeightAfter = p->nAplCur;
+ AplWeightTotalLev0 = 0.0;
+ AplWeightTotalLev1 = 0.0;
+ }
+
+ // check if the planes interact
+ fInteract = 0; // assume that they do not interact
+ for ( pUnit = pListOld0; pUnit; pUnit = pUnit->Next )
+ {
+ if ( pUnit->pT->lev == lev1 || Unit_Regular(pUnit->pE)->lev == lev1 )
+ {
+ fInteract = 1;
+ break;
+ }
+ // change the level now, this is done for efficiency reasons
+ pUnit->lev = lev1;
+ }
+
+ // set the new signature for hashing
+ p->nSwaps++;
+ if ( !fInteract )
+// if ( 0 )
+ {
+ // perform the swap without interaction
+ p->nNISwaps++;
+
+ // change the levels
+ if ( p->fMinWidth )
+ {
+ // go through the current lower level, which will become upper
+ for ( pUnit = pListOld1; pUnit; pUnit = pUnit->Next )
+ {
+ pUnit->lev = lev0;
+
+ pUnitER = Unit_Regular(pUnit->pE);
+ if ( pUnitER->TopRef > lev0 )
+ {
+ if ( pUnitER->Sign != p->nSwaps )
+ {
+ if ( pUnitER->TopRef == lev2 )
+ {
+ pUnitER->TopRef = lev1;
+ nWidthReduction--;
+ }
+ else
+ {
+ assert( pUnitER->TopRef == lev1 );
+ }
+ pUnitER->Sign = p->nSwaps;
+ }
+ }
+
+ pUnitT = pUnit->pT;
+ if ( pUnitT->TopRef > lev0 )
+ {
+ if ( pUnitT->Sign != p->nSwaps )
+ {
+ if ( pUnitT->TopRef == lev2 )
+ {
+ pUnitT->TopRef = lev1;
+ nWidthReduction--;
+ }
+ else
+ {
+ assert( pUnitT->TopRef == lev1 );
+ }
+ pUnitT->Sign = p->nSwaps;
+ }
+ }
+
+ }
+
+ // go through the current upper level, which will become lower
+ for ( pUnit = pListOld0; pUnit; pUnit = pUnit->Next )
+ {
+ pUnit->lev = lev1;
+
+ pUnitER = Unit_Regular(pUnit->pE);
+ if ( pUnitER->TopRef > lev0 )
+ {
+ if ( pUnitER->Sign != p->nSwaps )
+ {
+ assert( pUnitER->TopRef == lev1 );
+ pUnitER->TopRef = lev2;
+ pUnitER->Sign = p->nSwaps;
+ nWidthReduction++;
+ }
+ }
+
+ pUnitT = pUnit->pT;
+ if ( pUnitT->TopRef > lev0 )
+ {
+ if ( pUnitT->Sign != p->nSwaps )
+ {
+ assert( pUnitT->TopRef == lev1 );
+ pUnitT->TopRef = lev2;
+ pUnitT->Sign = p->nSwaps;
+ nWidthReduction++;
+ }
+ }
+ }
+ }
+ else
+ {
+// for ( pUnit = pListOld0; pUnit; pUnit = pUnit->Next )
+// pUnit->lev = lev1;
+ for ( pUnit = pListOld1; pUnit; pUnit = pUnit->Next )
+ pUnit->lev = lev0;
+ }
+
+ // set the new linked lists, which will be attached to the planes
+ pListNew0 = pListOld1;
+ pListNew1 = pListOld0;
+
+ if ( p->fMinApl )
+ {
+ AplWeightTotalLev0 = p->pPlanes[lev1].statsCost;
+ AplWeightTotalLev1 = p->pPlanes[lev0].statsCost;
+ }
+
+ // set the changes in terms of nodes
+ nNodesUpMovedDown = p->pPlanes[lev0].statsNodes;
+ nNodesDownMovedUp = p->pPlanes[lev1].statsNodes;
+ goto finish;
+ }
+ p->Signature++;
+
+
+ // two-variable swap is done in three easy steps
+ // previously I thought that steps (1) and (2) can be merged into one step
+ // now it is clear that this cannot be done without changing a lot of other stuff...
+
+ // (1) walk through the upper level, find units without cofactors in the lower level
+ // and move them to the new lower level (while adding to the cache)
+ // (2) walk through the uppoer level, and tranform all the remaning nodes
+ // while employing cache for the new lower level
+ // (3) walk through the old lower level, find those nodes whose ref counters are not zero,
+ // and move them to the new uppoer level, free other nodes
+
+ // (1) walk through the upper level, find units without cofactors in the lower level
+ // and move them to the new lower level (while adding to the cache)
+ for ( pLoop = pListOld0; pLoop; )
+ {
+ pUnit = pLoop;
+ pLoop = pLoop->Next;
+
+ pUnitE = pUnit->pE;
+ pUnitER = Unit_Regular(pUnitE);
+ pUnitT = pUnit->pT;
+
+ if ( pUnitER->lev != lev1 && pUnitT->lev != lev1 )
+ {
+ // before after
+ //
+ // <p1>
+ // 0 / \ 1
+ // / \
+ // / \
+ // / \ <p2n>
+ // / \ 0 / \ 1
+ // / \ / \
+ // / \ / \
+ // F0 F1 F0 F1
+
+ // move to plane-2-new
+ // nothing changes in the process (cofactors, ref counter, APL weight)
+ pUnit->lev = lev1;
+ AddToLinkedList( ppListNew1, pUnit );
+ if ( p->fMinApl )
+ AplWeightTotalLev1 += pUnit->Weight;
+
+ // add to cache - find the cell with different signature (not the current one!)
+ for ( HKey = hashKey3(p->Signature, pUnitE, pUnitT, p->nTableSize);
+ p->HTable[HKey].Sign == p->Signature;
+ HKey = (HKey+1) % p->nTableSize );
+ assert( p->HTable[HKey].Sign != p->Signature );
+ p->HTable[HKey].Sign = p->Signature;
+ p->HTable[HKey].Arg1 = (unsigned)pUnitE;
+ p->HTable[HKey].Arg2 = (unsigned)pUnitT;
+ p->HTable[HKey].Arg3 = (unsigned)pUnit;
+
+ nNodesUpMovedDown++;
+
+ if ( p->fMinWidth )
+ {
+ // update the cofactors's top ref
+ if ( pUnitER->TopRef > lev0 ) // the cofactor's top ref level is one of the current two levels
+ {
+ assert( pUnitER->TopRef == lev1 );
+ pUnitER->TopRefNew = lev2;
+ if ( pUnitER->Sign != p->nSwaps )
+ {
+ pUnitER->Sign = p->nSwaps; // set the current signature
+ p->pWidthCofs[ nWidthCofs++ ] = pUnitER;
+ }
+ }
+ if ( pUnitT->TopRef > lev0 ) // the cofactor's top ref level is one of the current two levels
+ {
+ assert( pUnitT->TopRef == lev1 );
+ pUnitT->TopRefNew = lev2;
+ if ( pUnitT->Sign != p->nSwaps )
+ {
+ pUnitT->Sign = p->nSwaps; // set the current signature
+ p->pWidthCofs[ nWidthCofs++ ] = pUnitT;
+ }
+ }
+ }
+ }
+ else
+ {
+ // add to the temporary plane
+ AddToLinkedList( ppListTemp, pUnit );
+ }
+ }
+
+
+ // (2) walk through the uppoer level, and tranform all the remaning nodes
+ // while employing cache for the new lower level
+ for ( pLoop = pListTemp; pLoop; )
+ {
+ pUnit = pLoop;
+ pLoop = pLoop->Next;
+
+ pUnitE = pUnit->pE;
+ pUnitER = Unit_Regular(pUnitE);
+ pUnitT = pUnit->pT;
+ fComp = (int)(pUnitER != pUnitE);
+
+ // count the amount of weight to reduce the APL of the children of this node
+ if ( p->fMinApl )
+ AplWeightHalf = 0.5 * pUnit->Weight;
+
+ // determine what situation is this
+ if ( pUnitER->lev == lev1 && pUnitT->lev == lev1 )
+ {
+ if ( fComp == 0 )
+ {
+ // before after
+ //
+ // <p1> <p1n>
+ // 0 / \ 1 0 / \ 1
+ // / \ / \
+ // / \ / \
+ // <p2> <p2> <p2n> <p2n>
+ // 0 / \ 1 0 / \ 1 0 / \ 1 0 / \ 1
+ // / \ / \ / \ / \
+ // / \ / \ / \ / \
+ // F0 F1 F2 F3 F0 F2 F1 F3
+ // pNew1E pNew1T pNew2E pNew2T
+ //
+ pNew1E = pUnitE->pE; // F0
+ pNew1T = pUnitT->pE; // F2
+
+ pNew2E = pUnitE->pT; // F1
+ pNew2T = pUnitT->pT; // F3
+ }
+ else
+ {
+ // before after
+ //
+ // <p1> <p1n>
+ // 0 . \ 1 0 / \ 1
+ // . \ / \
+ // . \ / \
+ // <p2> <p2> <p2n> <p2n>
+ // 0 / \ 1 0 / \ 1 0 . \ 1 0 . \ 1
+ // / \ / \ . \ . \
+ // / \ / \ . \ . \
+ // F0 F1 F2 F3 F0 F2 F1 F3
+ // pNew1E pNew1T pNew2E pNew2T
+ //
+ pNew1E = Unit_Not(pUnitER->pE); // F0
+ pNew1T = pUnitT->pE; // F2
+
+ pNew2E = Unit_Not(pUnitER->pT); // F1
+ pNew2T = pUnitT->pT; // F3
+ }
+ // subtract ref counters - on the level P2
+ pUnitER->n--;
+ pUnitT->n--;
+
+ // mark the change in the APL weights
+ if ( p->fMinApl )
+ {
+ pUnitER->Weight -= AplWeightHalf;
+ pUnitT->Weight -= AplWeightHalf;
+ AplWeightAfter -= pUnit->Weight;
+ }
+ }
+ else if ( pUnitER->lev == lev1 )
+ {
+ if ( fComp == 0 )
+ {
+ // before after
+ //
+ // <p1> <p1n>
+ // 0 / \ 1 0 / \ 1
+ // / \ / \
+ // / \ / \
+ // <p2> \ <p2n> <p2n>
+ // 0 / \ 1 \ 0 / \ 1 0 / \ 1
+ // / \ \ / \ / \
+ // / \ \ / \ / \
+ // F0 F1 F3 F0 F3 F1 F3
+ // pNew1E pNew1T pNew2E pNew2T
+ //
+ pNew1E = pUnitER->pE; // F0
+ pNew1T = pUnitT; // F3
+
+ pNew2E = pUnitER->pT; // F1
+ pNew2T = pUnitT; // F3
+ }
+ else
+ {
+ // before after
+ //
+ // <p1> <p1n>
+ // 0 . \ 1 0 / \ 1
+ // . \ / \
+ // . \ / \
+ // <p2> \ <p2n> <p2n>
+ // 0 / \ 1 \ 0 . \ 1 0 . \ 1
+ // / \ \ . \ . \
+ // / \ \ . \ . \
+ // F0 F1 F3 F0 F3 F1 F3
+ // pNew1E pNew1T pNew2E pNew2T
+ //
+ pNew1E = Unit_Not(pUnitER->pE); // F0
+ pNew1T = pUnitT; // F3
+
+ pNew2E = Unit_Not(pUnitER->pT); // F1
+ pNew2T = pUnitT; // F3
+ }
+ // subtract ref counter - on the level P2
+ pUnitER->n--;
+ // subtract ref counter - on other levels
+ pUnitT->n--; ///
+
+ // mark the change in the APL weights
+ if ( p->fMinApl )
+ {
+ pUnitER->Weight -= AplWeightHalf;
+ AplWeightAfter -= AplWeightHalf;
+ }
+ }
+ else if ( pUnitT->lev == lev1 )
+ {
+ // before after
+ //
+ // <p1> <p1n>
+ // 0 / \ 1 0 / \ 1
+ // / \ / \
+ // / \ / \
+ // / <p2> <p2n> <p2n>
+ // / 0 / \ 1 0 / \ 1 0 / \ 1
+ // / / \ / \ / \
+ // / / \ / \ / \
+ // F0 F2 F3 F0 F2 F0 F3
+ // pNew1E pNew1T pNew2E pNew2T
+ //
+ pNew1E = pUnitE; // F0
+ pNew1T = pUnitT->pE; // F2
+
+ pNew2E = pUnitE; // F0
+ pNew2T = pUnitT->pT; // F3
+
+ // subtract incoming edge counter - on the level P2
+ pUnitT->n--;
+ // subtract ref counter - on other levels
+ pUnitER->n--; ///
+
+ // mark the change in the APL weights
+ if ( p->fMinApl )
+ {
+ pUnitT->Weight -= AplWeightHalf;
+ AplWeightAfter -= AplWeightHalf;
+ }
+ }
+ else
+ {
+ assert( 0 ); // should never happen
+ }
+
+
+ // consider all the cases except the last one
+ if ( pNew1E == pNew1T )
+ {
+ pNewPlane20 = pNew1T;
+
+ if ( p->fMinWidth )
+ {
+ // update the cofactors's top ref
+ if ( pNew1T->TopRef > lev0 ) // the cofactor's top ref level is one of the current two levels
+ {
+ pNew1T->TopRefNew = lev1;
+ if ( pNew1T->Sign != p->nSwaps )
+ {
+ pNew1T->Sign = p->nSwaps; // set the current signature
+ p->pWidthCofs[ nWidthCofs++ ] = pNew1T;
+ }
+ }
+ }
+ }
+ else
+ {
+ // pNew1T can be complemented
+ fCompT = Cudd_IsComplement(pNew1T);
+ if ( fCompT )
+ {
+ pNew1E = Unit_Not(pNew1E);
+ pNew1T = Unit_Not(pNew1T);
+ }
+
+ // check the hash-table
+ fFound = 0;
+ for ( HKey = hashKey3(p->Signature, pNew1E, pNew1T, p->nTableSize);
+ p->HTable[HKey].Sign == p->Signature;
+ HKey = (HKey+1) % p->nTableSize )
+ if ( p->HTable[HKey].Arg1 == (unsigned)pNew1E && p->HTable[HKey].Arg2 == (unsigned)pNew1T )
+ { // the entry is present
+ // assign this entry
+ pNewPlane20 = (reo_unit *)p->HTable[HKey].Arg3;
+ assert( pNewPlane20->lev == lev1 );
+ fFound = 1;
+ p->HashSuccess++;
+ break;
+ }
+
+ if ( !fFound )
+ { // create the new entry
+ pNewPlane20 = reoUnitsGetNextUnit( p ); // increments the unit counter
+ pNewPlane20->pE = pNew1E;
+ pNewPlane20->pT = pNew1T;
+ pNewPlane20->n = 0; // ref will be added later
+ pNewPlane20->lev = lev1;
+ if ( p->fMinWidth )
+ {
+ pNewPlane20->TopRef = lev1;
+ pNewPlane20->Sign = 0;
+ }
+ // set the weight of this node
+ if ( p->fMinApl )
+ pNewPlane20->Weight = 0.0;
+
+ // increment ref counters of children
+ pNew1ER = Unit_Regular(pNew1E);
+ pNew1ER->n++; //
+ pNew1T->n++; //
+
+ // insert into the data structure
+ AddToLinkedList( ppListNew1, pNewPlane20 );
+
+ // add this entry to cache
+ assert( p->HTable[HKey].Sign != p->Signature );
+ p->HTable[HKey].Sign = p->Signature;
+ p->HTable[HKey].Arg1 = (unsigned)pNew1E;
+ p->HTable[HKey].Arg2 = (unsigned)pNew1T;
+ p->HTable[HKey].Arg3 = (unsigned)pNewPlane20;
+
+ nNodesUnrefAdded++;
+
+ if ( p->fMinWidth )
+ {
+ // update the cofactors's top ref
+ if ( pNew1ER->TopRef > lev0 ) // the cofactor's top ref level is one of the current two levels
+ {
+ if ( pNew1ER->Sign != p->nSwaps )
+ {
+ pNew1ER->TopRefNew = lev2;
+ if ( pNew1ER->Sign != p->nSwaps )
+ {
+ pNew1ER->Sign = p->nSwaps; // set the current signature
+ p->pWidthCofs[ nWidthCofs++ ] = pNew1ER;
+ }
+ }
+ // otherwise the level is already set correctly
+ else
+ {
+ assert( pNew1ER->TopRefNew == lev1 || pNew1ER->TopRefNew == lev2 );
+ }
+ }
+ // update the cofactors's top ref
+ if ( pNew1T->TopRef > lev0 ) // the cofactor's top ref level is one of the current two levels
+ {
+ if ( pNew1T->Sign != p->nSwaps )
+ {
+ pNew1T->TopRefNew = lev2;
+ if ( pNew1T->Sign != p->nSwaps )
+ {
+ pNew1T->Sign = p->nSwaps; // set the current signature
+ p->pWidthCofs[ nWidthCofs++ ] = pNew1T;
+ }
+ }
+ // otherwise the level is already set correctly
+ else
+ {
+ assert( pNew1T->TopRefNew == lev1 || pNew1T->TopRefNew == lev2 );
+ }
+ }
+ }
+ }
+
+ if ( p->fMinApl )
+ {
+ // increment the weight of this node
+ pNewPlane20->Weight += AplWeightHalf;
+ // mark the change in the APL weight
+ AplWeightAfter += AplWeightHalf;
+ // update the total weight of this level
+ AplWeightTotalLev1 += AplWeightHalf;
+ }
+
+ if ( fCompT )
+ pNewPlane20 = Unit_Not(pNewPlane20);
+ }
+
+ if ( pNew2E == pNew2T )
+ {
+ pNewPlane21 = pNew2T;
+
+ if ( p->fMinWidth )
+ {
+ // update the cofactors's top ref
+ if ( pNew2T->TopRef > lev0 ) // the cofactor's top ref level is one of the current two levels
+ {
+ pNew2T->TopRefNew = lev1;
+ if ( pNew2T->Sign != p->nSwaps )
+ {
+ pNew2T->Sign = p->nSwaps; // set the current signature
+ p->pWidthCofs[ nWidthCofs++ ] = pNew2T;
+ }
+ }
+ }
+ }
+ else
+ {
+ assert( !Cudd_IsComplement(pNew2T) );
+
+ // check the hash-table
+ fFound = 0;
+ for ( HKey = hashKey3(p->Signature, pNew2E, pNew2T, p->nTableSize);
+ p->HTable[HKey].Sign == p->Signature;
+ HKey = (HKey+1) % p->nTableSize )
+ if ( p->HTable[HKey].Arg1 == (unsigned)pNew2E && p->HTable[HKey].Arg2 == (unsigned)pNew2T )
+ { // the entry is present
+ // assign this entry
+ pNewPlane21 = (reo_unit *)p->HTable[HKey].Arg3;
+ assert( pNewPlane21->lev == lev1 );
+ fFound = 1;
+ p->HashSuccess++;
+ break;
+ }
+
+ if ( !fFound )
+ { // create the new entry
+ pNewPlane21 = reoUnitsGetNextUnit( p ); // increments the unit counter
+ pNewPlane21->pE = pNew2E;
+ pNewPlane21->pT = pNew2T;
+ pNewPlane21->n = 0; // ref will be added later
+ pNewPlane21->lev = lev1;
+ if ( p->fMinWidth )
+ {
+ pNewPlane21->TopRef = lev1;
+ pNewPlane21->Sign = 0;
+ }
+ // set the weight of this node
+ if ( p->fMinApl )
+ pNewPlane21->Weight = 0.0;
+
+ // increment ref counters of children
+ pNew2ER = Unit_Regular(pNew2E);
+ pNew2ER->n++; //
+ pNew2T->n++; //
+
+ // insert into the data structure
+// reoUnitsAddUnitToPlane( &P2new, pNewPlane21 );
+ AddToLinkedList( ppListNew1, pNewPlane21 );
+
+ // add this entry to cache
+ assert( p->HTable[HKey].Sign != p->Signature );
+ p->HTable[HKey].Sign = p->Signature;
+ p->HTable[HKey].Arg1 = (unsigned)pNew2E;
+ p->HTable[HKey].Arg2 = (unsigned)pNew2T;
+ p->HTable[HKey].Arg3 = (unsigned)pNewPlane21;
+
+ nNodesUnrefAdded++;
+
+
+ if ( p->fMinWidth )
+ {
+ // update the cofactors's top ref
+ if ( pNew2ER->TopRef > lev0 ) // the cofactor's top ref level is one of the current two levels
+ {
+ if ( pNew2ER->Sign != p->nSwaps )
+ {
+ pNew2ER->TopRefNew = lev2;
+ if ( pNew2ER->Sign != p->nSwaps )
+ {
+ pNew2ER->Sign = p->nSwaps; // set the current signature
+ p->pWidthCofs[ nWidthCofs++ ] = pNew2ER;
+ }
+ }
+ // otherwise the level is already set correctly
+ else
+ {
+ assert( pNew2ER->TopRefNew == lev1 || pNew2ER->TopRefNew == lev2 );
+ }
+ }
+ // update the cofactors's top ref
+ if ( pNew2T->TopRef > lev0 ) // the cofactor's top ref level is one of the current two levels
+ {
+ if ( pNew2T->Sign != p->nSwaps )
+ {
+ pNew2T->TopRefNew = lev2;
+ if ( pNew2T->Sign != p->nSwaps )
+ {
+ pNew2T->Sign = p->nSwaps; // set the current signature
+ p->pWidthCofs[ nWidthCofs++ ] = pNew2T;
+ }
+ }
+ // otherwise the level is already set correctly
+ else
+ {
+ assert( pNew2T->TopRefNew == lev1 || pNew2T->TopRefNew == lev2 );
+ }
+ }
+ }
+ }
+
+ if ( p->fMinApl )
+ {
+ // increment the weight of this node
+ pNewPlane21->Weight += AplWeightHalf;
+ // mark the change in the APL weight
+ AplWeightAfter += AplWeightHalf;
+ // update the total weight of this level
+ AplWeightTotalLev1 += AplWeightHalf;
+ }
+ }
+ // in all cases, the node will be added to the plane-1
+ // this should be the same node (pUnit) as was originally there
+ // because it is referenced by the above nodes
+
+ assert( !Cudd_IsComplement(pNewPlane21) );
+ // should be the case; otherwise reordering is not a local operation
+
+ pUnit->pE = pNewPlane20;
+ pUnit->pT = pNewPlane21;
+ assert( pUnit->lev == lev0 );
+ // reference counter remains the same; the APL weight remains the same
+
+ // increment ref counters of children
+ pNewPlane20R = Unit_Regular(pNewPlane20);
+ pNewPlane20R->n++; ///
+ pNewPlane21->n++; ///
+
+ // insert into the data structure
+ AddToLinkedList( ppListNew0, pUnit );
+ if ( p->fMinApl )
+ AplWeightTotalLev0 += pUnit->Weight;
+ }
+
+ // (3) walk through the old lower level, find those nodes whose ref counters are not zero,
+ // and move them to the new uppoer level, free other nodes
+ for ( pLoop = pListOld1; pLoop; )
+ {
+ pUnit = pLoop;
+ pLoop = pLoop->Next;
+ if ( pUnit->n )
+ {
+ assert( !p->fMinApl || pUnit->Weight > 0.0 );
+ // the node should be added to the new level
+ // no need to check the hash table
+ pUnit->lev = lev0;
+ AddToLinkedList( ppListNew0, pUnit );
+ if ( p->fMinApl )
+ AplWeightTotalLev0 += pUnit->Weight;
+
+ nNodesDownMovedUp++;
+
+ if ( p->fMinWidth )
+ {
+ pUnitER = Unit_Regular(pUnit->pE);
+ pUnitT = pUnit->pT;
+
+ // update the cofactors's top ref
+ if ( pUnitER->TopRef > lev0 ) // the cofactor's top ref level is one of the current two levels
+ {
+ pUnitER->TopRefNew = lev1;
+ if ( pUnitER->Sign != p->nSwaps )
+ {
+ pUnitER->Sign = p->nSwaps; // set the current signature
+ p->pWidthCofs[ nWidthCofs++ ] = pUnitER;
+ }
+ }
+ if ( pUnitT->TopRef > lev0 ) // the cofactor's top ref level is one of the current two levels
+ {
+ pUnitT->TopRefNew = lev1;
+ if ( pUnitT->Sign != p->nSwaps )
+ {
+ pUnitT->Sign = p->nSwaps; // set the current signature
+ p->pWidthCofs[ nWidthCofs++ ] = pUnitT;
+ }
+ }
+ }
+ }
+ else
+ {
+ assert( !p->fMinApl || pUnit->Weight == 0.0 );
+ // decrement reference counters of children
+ pUnitER = Unit_Regular(pUnit->pE);
+ pUnitT = pUnit->pT;
+ pUnitER->n--; ///
+ pUnitT->n--; ///
+ // the node should be thrown away
+ reoUnitsRecycleUnit( p, pUnit );
+ nNodesUnrefRemoved++;
+ }
+ }
+
+finish:
+
+ // attach the new levels to the planes
+ p->pPlanes[lev0].pHead = pListNew0;
+ p->pPlanes[lev1].pHead = pListNew1;
+
+ // swap the sift status
+ temp = p->pPlanes[lev0].fSifted;
+ p->pPlanes[lev0].fSifted = p->pPlanes[lev1].fSifted;
+ p->pPlanes[lev1].fSifted = temp;
+
+ // swap variables in the variable map
+ if ( p->pOrderInt )
+ {
+ temp = p->pOrderInt[lev0];
+ p->pOrderInt[lev0] = p->pOrderInt[lev1];
+ p->pOrderInt[lev1] = temp;
+ }
+
+ // adjust the node profile
+ p->pPlanes[lev0].statsNodes -= (nNodesUpMovedDown - nNodesDownMovedUp);
+ p->pPlanes[lev1].statsNodes -= (nNodesDownMovedUp - nNodesUpMovedDown) + nNodesUnrefRemoved - nNodesUnrefAdded;
+ p->nNodesCur -= nNodesUnrefRemoved - nNodesUnrefAdded;
+
+ // adjust the node profile on this level
+ if ( p->fMinWidth )
+ {
+ for ( c = 0; c < nWidthCofs; c++ )
+ {
+ if ( p->pWidthCofs[c]->TopRefNew < p->pWidthCofs[c]->TopRef )
+ {
+ p->pWidthCofs[c]->TopRef = p->pWidthCofs[c]->TopRefNew;
+ nWidthReduction--;
+ }
+ else if ( p->pWidthCofs[c]->TopRefNew > p->pWidthCofs[c]->TopRef )
+ {
+ p->pWidthCofs[c]->TopRef = p->pWidthCofs[c]->TopRefNew;
+ nWidthReduction++;
+ }
+ }
+ // verify that the profile is okay
+ reoProfileWidthVerifyLevel( p->pPlanes + lev0, lev0 );
+ reoProfileWidthVerifyLevel( p->pPlanes + lev1, lev1 );
+
+ // compute the total gain in terms of width
+ nCostGain = (nNodesDownMovedUp - nNodesUpMovedDown + nNodesUnrefRemoved - nNodesUnrefAdded) + nWidthReduction;
+ // adjust the width on this level
+ p->pPlanes[lev1].statsWidth -= (int)nCostGain;
+ // set the cost
+ p->pPlanes[lev1].statsCost = p->pPlanes[lev1].statsWidth;
+ }
+ else if ( p->fMinApl )
+ {
+ // compute the total gain in terms of APL
+ nCostGain = AplWeightPrev - AplWeightAfter;
+ // make sure that the ALP is updated correctly
+// assert( p->pPlanes[lev0].statsCost + p->pPlanes[lev1].statsCost - nCostGain ==
+// AplWeightTotalLev0 + AplWeightTotalLev1 );
+ // adjust the profile
+ p->pPlanes[lev0].statsApl = AplWeightTotalLev0;
+ p->pPlanes[lev1].statsApl = AplWeightTotalLev1;
+ // set the cost
+ p->pPlanes[lev0].statsCost = p->pPlanes[lev0].statsApl;
+ p->pPlanes[lev1].statsCost = p->pPlanes[lev1].statsApl;
+ }
+ else
+ {
+ // compute the total gain in terms of the number of nodes
+ nCostGain = nNodesUnrefRemoved - nNodesUnrefAdded;
+ // adjust the profile (adjusted above)
+ // set the cost
+ p->pPlanes[lev0].statsCost = p->pPlanes[lev0].statsNodes;
+ p->pPlanes[lev1].statsCost = p->pPlanes[lev1].statsNodes;
+ }
+
+ return nCostGain;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/bdd/reo/reoTest.c b/src/bdd/reo/reoTest.c
new file mode 100644
index 00000000..82f3d5f5
--- /dev/null
+++ b/src/bdd/reo/reoTest.c
@@ -0,0 +1,251 @@
+/**CFile****************************************************************
+
+ FileName [reoTest.c]
+
+ PackageName [REO: A specialized DD reordering engine.]
+
+ Synopsis [Various testing procedures (may be outdated).]
+
+ Author [Alan Mishchenko <alanmi@ece.pdx.edu>]
+
+ Affiliation [ECE Department. Portland State University, Portland, Oregon.]
+
+ Date [Ver. 1.0. Started - October 15, 2002.]
+
+ Revision [$Id: reoTest.c,v 1.0 2002/15/10 03:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "reo.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Reorders the DD using REO and CUDD.]
+
+ Description [This function can be used to test the performance of the reordering package.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_ReorderTest( DdManager * dd, DdNode * Func )
+{
+ reo_man * pReo;
+ DdNode * Temp, * Temp1;
+ int pOrder[1000];
+
+ pReo = Extra_ReorderInit( 100, 100 );
+
+//Extra_DumpDot( dd, &Func, 1, "beforReo.dot", 0 );
+ Temp = Extra_Reorder( pReo, dd, Func, pOrder ); Cudd_Ref( Temp );
+//Extra_DumpDot( dd, &Temp, 1, "afterReo.dot", 0 );
+
+ Temp1 = Extra_ReorderCudd(dd, Func, NULL ); Cudd_Ref( Temp1 );
+printf( "Initial = %d. Final = %d. Cudd = %d.\n", Cudd_DagSize(Func), Cudd_DagSize(Temp), Cudd_DagSize(Temp1) );
+ Cudd_RecursiveDeref( dd, Temp1 );
+ Cudd_RecursiveDeref( dd, Temp );
+
+ Extra_ReorderQuit( pReo );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Reorders the DD using REO and CUDD.]
+
+ Description [This function can be used to test the performance of the reordering package.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_ReorderTestArray( DdManager * dd, DdNode * Funcs[], int nFuncs )
+{
+ reo_man * pReo;
+ DdNode * FuncsRes[1000];
+ int pOrder[1000];
+ int i;
+
+ pReo = Extra_ReorderInit( 100, 100 );
+ Extra_ReorderArray( pReo, dd, Funcs, FuncsRes, nFuncs, pOrder );
+ Extra_ReorderQuit( pReo );
+
+printf( "Initial = %d. Final = %d.\n", Cudd_SharingSize(Funcs,nFuncs), Cudd_SharingSize(FuncsRes,nFuncs) );
+
+ for ( i = 0; i < nFuncs; i++ )
+ Cudd_RecursiveDeref( dd, FuncsRes[i] );
+
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reorders the DD using CUDD package.]
+
+ Description [Transfers the DD into a temporary manager in such a way
+ that the level correspondence is preserved. Reorders the manager
+ and transfers the DD back into the original manager using the topmost
+ levels of the manager, in such a way that the ordering of levels is
+ preserved. The resulting permutation is returned in the array
+ given by the user.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Extra_ReorderCudd( DdManager * dd, DdNode * aFunc, int pPermuteReo[] )
+{
+ static DdManager * ddReorder = NULL;
+ static int * Permute = NULL;
+ static int * PermuteReo1 = NULL;
+ static int * PermuteReo2 = NULL;
+ DdNode * aFuncReorder, * aFuncNew;
+ int lev, var;
+
+ // start the reordering manager
+ if ( ddReorder == NULL )
+ {
+ Permute = ALLOC( int, dd->size );
+ PermuteReo1 = ALLOC( int, dd->size );
+ PermuteReo2 = ALLOC( int, dd->size );
+ ddReorder = Cudd_Init( dd->size, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 );
+ Cudd_AutodynDisable(ddReorder);
+ }
+
+ // determine the permutation of variable to make sure that var order in bFunc
+ // will not change when this function is transfered into the new manager
+ for ( lev = 0; lev < dd->size; lev++ )
+ {
+ Permute[ dd->invperm[lev] ] = ddReorder->invperm[lev];
+ PermuteReo1[ ddReorder->invperm[lev] ] = dd->invperm[lev];
+ }
+ // transfer this function into the new manager in such a way that ordering of vars does not change
+ aFuncReorder = Extra_TransferPermute( dd, ddReorder, aFunc, Permute ); Cudd_Ref( aFuncReorder );
+// assert( Cudd_DagSize(aFunc) == Cudd_DagSize(aFuncReorder) );
+
+ // perform the reordering
+printf( "Nodes before = %d.\n", Cudd_DagSize(aFuncReorder) );
+ Cudd_ReduceHeap( ddReorder, CUDD_REORDER_SYMM_SIFT, 1 );
+printf( "Nodes before = %d.\n", Cudd_DagSize(aFuncReorder) );
+
+ // determine the reverse variable permutation
+ for ( lev = 0; lev < dd->size; lev++ )
+ {
+ Permute[ ddReorder->invperm[lev] ] = dd->invperm[lev];
+ PermuteReo2[ dd->invperm[lev] ] = ddReorder->invperm[lev];
+ }
+
+ // transfer this function into the new manager in such a way that ordering of vars does not change
+ aFuncNew = Extra_TransferPermute( ddReorder, dd, aFuncReorder, Permute ); Cudd_Ref( aFuncNew );
+// assert( Cudd_DagSize(aFuncNew) == Cudd_DagSize(aFuncReorder) );
+ Cudd_RecursiveDeref( ddReorder, aFuncReorder );
+
+ // derive the resulting variable ordering
+ if ( pPermuteReo )
+ for ( var = 0; var < dd->size; var++ )
+ pPermuteReo[var] = PermuteReo1[ PermuteReo2[var] ];
+
+ Cudd_Deref( aFuncNew );
+ return aFuncNew;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description [Transfers the BDD into another manager minimizes it and
+ returns the min number of nodes; disposes of the BDD in the new manager.
+ Useful for debugging or comparing the performance of other reordering
+ procedures.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Extra_bddReorderTest( DdManager * dd, DdNode * bF )
+{
+ static DdManager * s_ddmin;
+ DdNode * bFmin;
+ int nNodes;
+// int clk1;
+
+ if ( s_ddmin == NULL )
+ s_ddmin = Cudd_Init( dd->size, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0);
+
+// Cudd_ShuffleHeap( s_ddmin, dd->invperm );
+
+// clk1 = clock();
+ bFmin = Cudd_bddTransfer( dd, s_ddmin, bF ); Cudd_Ref( bFmin );
+ Cudd_ReduceHeap(s_ddmin,CUDD_REORDER_SIFT,1);
+// Cudd_ReduceHeap(s_ddmin,CUDD_REORDER_SYMM_SIFT,1);
+ nNodes = Cudd_DagSize( bFmin );
+ Cudd_RecursiveDeref( s_ddmin, bFmin );
+
+// printf( "Classical variable reordering time = %.2f sec\n", (float)(clock() - clk1)/(float)(CLOCKS_PER_SEC) );
+ return nNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description [Transfers the ADD into another manager minimizes it and
+ returns the min number of nodes; disposes of the BDD in the new manager.
+ Useful for debugging or comparing the performance of other reordering
+ procedures.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Extra_addReorderTest( DdManager * dd, DdNode * aF )
+{
+ static DdManager * s_ddmin;
+ DdNode * bF;
+ DdNode * bFmin;
+ DdNode * aFmin;
+ int nNodesBeg;
+ int nNodesEnd;
+ int clk1;
+
+ if ( s_ddmin == NULL )
+ s_ddmin = Cudd_Init( dd->size, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0);
+
+// Cudd_ShuffleHeap( s_ddmin, dd->invperm );
+
+ clk1 = clock();
+ bF = Cudd_addBddPattern( dd, aF ); Cudd_Ref( bF );
+ bFmin = Cudd_bddTransfer( dd, s_ddmin, bF ); Cudd_Ref( bFmin );
+ Cudd_RecursiveDeref( dd, bF );
+ aFmin = Cudd_BddToAdd( s_ddmin, bFmin ); Cudd_Ref( aFmin );
+ Cudd_RecursiveDeref( s_ddmin, bFmin );
+
+ nNodesBeg = Cudd_DagSize( aFmin );
+ Cudd_ReduceHeap(s_ddmin,CUDD_REORDER_SIFT,1);
+// Cudd_ReduceHeap(s_ddmin,CUDD_REORDER_SYMM_SIFT,1);
+ nNodesEnd = Cudd_DagSize( aFmin );
+ Cudd_RecursiveDeref( s_ddmin, aFmin );
+
+ printf( "Classical reordering of ADDs: Before = %d. After = %d.\n", nNodesBeg, nNodesEnd );
+ printf( "Classical variable reordering time = %.2f sec\n", (float)(clock() - clk1)/(float)(CLOCKS_PER_SEC) );
+ return nNodesEnd;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/bdd/reo/reoTransfer.c b/src/bdd/reo/reoTransfer.c
new file mode 100644
index 00000000..752cd3d7
--- /dev/null
+++ b/src/bdd/reo/reoTransfer.c
@@ -0,0 +1,199 @@
+/**CFile****************************************************************
+
+ FileName [reoTransfer.c]
+
+ PackageName [REO: A specialized DD reordering engine.]
+
+ Synopsis [Transfering a DD from the CUDD manager into REO"s internal data structures and back.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - October 15, 2002.]
+
+ Revision [$Id: reoTransfer.c,v 1.0 2002/15/10 03:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "reo.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Transfers the DD into the internal reordering data structure.]
+
+ Description [It is important that the hash table is lossless.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+reo_unit * reoTransferNodesToUnits_rec( reo_man * p, DdNode * F )
+{
+ DdManager * dd = p->dd;
+ reo_unit * pUnit;
+ int HKey, fComp;
+
+ fComp = Cudd_IsComplement(F);
+ F = Cudd_Regular(F);
+
+ // check the hash-table
+ if ( F->ref != 1 )
+ {
+ // search cache - use linear probing
+ for ( HKey = hashKey2(p->Signature,F,p->nTableSize); p->HTable[HKey].Sign == p->Signature; HKey = (HKey+1) % p->nTableSize )
+ if ( p->HTable[HKey].Arg1 == (unsigned)F )
+ {
+ pUnit = (reo_unit*) p->HTable[HKey].Arg2;
+ assert( pUnit );
+ // increment the edge counter
+ pUnit->n++;
+ return Unit_NotCond( pUnit, fComp );
+ }
+ }
+ // the entry in not found in the cache
+
+ // create a new entry
+ pUnit = reoUnitsGetNextUnit( p );
+ pUnit->n = 1;
+ if ( cuddIsConstant(F) )
+ {
+ pUnit->lev = REO_CONST_LEVEL;
+ pUnit->pE = (reo_unit*)((int)(cuddV(F)));
+ pUnit->pT = NULL;
+ // check if the diagram that is being reordering has complement edges
+ if ( F != dd->one )
+ p->fThisIsAdd = 1;
+ // insert the unit into the corresponding plane
+ reoUnitsAddUnitToPlane( &(p->pPlanes[p->nSupp]), pUnit ); // increments the unit counter
+ }
+ else
+ {
+ pUnit->lev = p->pMapToPlanes[F->index];
+ pUnit->pE = reoTransferNodesToUnits_rec( p, cuddE(F) );
+ pUnit->pT = reoTransferNodesToUnits_rec( p, cuddT(F) );
+ // insert the unit into the corresponding plane
+ reoUnitsAddUnitToPlane( &(p->pPlanes[pUnit->lev]), pUnit ); // increments the unit counter
+ }
+
+ // add to the hash table
+ if ( F->ref != 1 )
+ {
+ // the next free entry is already found - it is pointed to by HKey
+ // while we traversed the diagram, the hash entry to which HKey points,
+ // might have been used. Make sure that its signature is different.
+ for ( ; p->HTable[HKey].Sign == p->Signature; HKey = (HKey+1) % p->nTableSize );
+ p->HTable[HKey].Sign = p->Signature;
+ p->HTable[HKey].Arg1 = (unsigned)F;
+ p->HTable[HKey].Arg2 = (unsigned)pUnit;
+ }
+
+ // increment the counter of nodes
+ p->nNodesCur++;
+ return Unit_NotCond( pUnit, fComp );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates the DD from the internal reordering data structure.]
+
+ Description [It is important that the hash table is lossless.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * reoTransferUnitsToNodes_rec( reo_man * p, reo_unit * pUnit )
+{
+ DdManager * dd = p->dd;
+ DdNode * bRes, * E, * T;
+ int HKey, fComp;
+
+ fComp = Cudd_IsComplement(pUnit);
+ pUnit = Unit_Regular(pUnit);
+
+ // check the hash-table
+ if ( pUnit->n != 1 )
+ {
+ for ( HKey = hashKey2(p->Signature,pUnit,p->nTableSize); p->HTable[HKey].Sign == p->Signature; HKey = (HKey+1) % p->nTableSize )
+ if ( p->HTable[HKey].Arg1 == (unsigned)pUnit )
+ {
+ bRes = (DdNode*) p->HTable[HKey].Arg2;
+ assert( bRes );
+ return Cudd_NotCond( bRes, fComp );
+ }
+ }
+
+ // treat the case of constants
+ if ( Unit_IsConstant(pUnit) )
+ {
+ bRes = cuddUniqueConst( dd, ((double)((int)(pUnit->pE))) );
+ cuddRef( bRes );
+ }
+ else
+ {
+ // split and recur on children of this node
+ E = reoTransferUnitsToNodes_rec( p, pUnit->pE );
+ if ( E == NULL )
+ return NULL;
+ cuddRef(E);
+
+ T = reoTransferUnitsToNodes_rec( p, pUnit->pT );
+ if ( T == NULL )
+ {
+ Cudd_RecursiveDeref(dd, E);
+ return NULL;
+ }
+ cuddRef(T);
+
+ // consider the case when Res0 and Res1 are the same node
+ assert( E != T );
+ assert( !Cudd_IsComplement(T) );
+
+ bRes = cuddUniqueInter( dd, p->pMapToDdVarsFinal[pUnit->lev], T, E );
+ if ( bRes == NULL )
+ {
+ Cudd_RecursiveDeref(dd,E);
+ Cudd_RecursiveDeref(dd,T);
+ return NULL;
+ }
+ cuddRef( bRes );
+ cuddDeref( E );
+ cuddDeref( T );
+ }
+
+ // do not keep the result if the ref count is only 1, since it will not be visited again
+ if ( pUnit->n != 1 )
+ {
+ // while we traversed the diagram, the hash entry to which HKey points,
+ // might have been used. Make sure that its signature is different.
+ for ( ; p->HTable[HKey].Sign == p->Signature; HKey = (HKey+1) % p->nTableSize );
+ p->HTable[HKey].Sign = p->Signature;
+ p->HTable[HKey].Arg1 = (unsigned)pUnit;
+ p->HTable[HKey].Arg2 = (unsigned)bRes;
+
+ // add the DD to the referenced DD list in order to be able to store it in cache
+ p->pRefNodes[p->nRefNodes++] = bRes; Cudd_Ref( bRes );
+ // no need to do this, because the garbage collection will not take bRes away
+ // it is held by the diagram in the making
+ }
+ // increment the counter of nodes
+ p->nNodesCur++;
+ cuddDeref( bRes );
+ return Cudd_NotCond( bRes, fComp );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/bdd/reo/reoUnits.c b/src/bdd/reo/reoUnits.c
new file mode 100644
index 00000000..aa86516e
--- /dev/null
+++ b/src/bdd/reo/reoUnits.c
@@ -0,0 +1,184 @@
+/**CFile****************************************************************
+
+ FileName [reoUnits.c]
+
+ PackageName [REO: A specialized DD reordering engine.]
+
+ Synopsis [Procedures which support internal data structures.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - October 15, 2002.]
+
+ Revision [$Id: reoUnits.c,v 1.0 2002/15/10 03:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "reo.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void reoUnitsAddToFreeUnitList( reo_man * p );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Extract the next unit from the free unit list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+reo_unit * reoUnitsGetNextUnit(reo_man * p )
+{
+ reo_unit * pUnit;
+ // check there are stil units to extract
+ if ( p->pUnitFreeList == NULL )
+ reoUnitsAddToFreeUnitList( p );
+ // extract the next unit from the linked list
+ pUnit = p->pUnitFreeList;
+ p->pUnitFreeList = pUnit->Next;
+ p->nUnitsUsed++;
+ return pUnit;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the unit to the free unit list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void reoUnitsRecycleUnit( reo_man * p, reo_unit * pUnit )
+{
+ pUnit->Next = p->pUnitFreeList;
+ p->pUnitFreeList = pUnit;
+ p->nUnitsUsed--;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the list of units to the free unit list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void reoUnitsRecycleUnitList( reo_man * p, reo_plane * pPlane )
+{
+ reo_unit * pUnit;
+ reo_unit * pTail;
+
+ if ( pPlane->pHead == NULL )
+ return;
+
+ // find the tail
+ for ( pUnit = pPlane->pHead; pUnit; pUnit = pUnit->Next )
+ pTail = pUnit;
+ pTail->Next = p->pUnitFreeList;
+ p->pUnitFreeList = pPlane->pHead;
+ memset( pPlane, 0, sizeof(reo_plane) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Stops the unit dispenser.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void reoUnitsStopDispenser( reo_man * p )
+{
+ int i;
+ for ( i = 0; i < p->nMemChunks; i++ )
+ free( p->pMemChunks[i] );
+// printf("\nThe number of chunks used is %d, each of them %d units\n", p->nMemChunks, REO_CHUNK_SIZE );
+ p->nMemChunks = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Adds one unit to the list of units which constitutes the plane.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void reoUnitsAddUnitToPlane( reo_plane * pPlane, reo_unit * pUnit )
+{
+ if ( pPlane->pHead == NULL )
+ {
+ pPlane->pHead = pUnit;
+ pUnit->Next = NULL;
+ }
+ else
+ {
+ pUnit->Next = pPlane->pHead;
+ pPlane->pHead = pUnit;
+ }
+ pPlane->statsNodes++;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void reoUnitsAddToFreeUnitList( reo_man * p )
+{
+ int c;
+ // check that we still have chunks left
+ if ( p->nMemChunks == p->nMemChunksAlloc )
+ {
+ printf( "reoUnitsAddToFreeUnitList(): Memory manager ran out of memory!\n" );
+ fflush( stdout );
+ return;
+ }
+ // allocate the next chunk
+ assert( p->pUnitFreeList == NULL );
+ p->pUnitFreeList = ALLOC( reo_unit, REO_CHUNK_SIZE );
+ // split chunks into list-connected units
+ for ( c = 0; c < REO_CHUNK_SIZE-1; c++ )
+ (p->pUnitFreeList + c)->Next = p->pUnitFreeList + c + 1;
+ // set the last pointer to NULL
+ (p->pUnitFreeList + REO_CHUNK_SIZE-1)->Next = NULL;
+ // add the chunk to the array of chunks
+ p->pMemChunks[p->nMemChunks++] = p->pUnitFreeList;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/generic.c b/src/generic.c
new file mode 100644
index 00000000..43dd32d8
--- /dev/null
+++ b/src/generic.c
@@ -0,0 +1,47 @@
+/**CFile****************************************************************
+
+ FileName [.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName []
+
+ Synopsis []
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: .c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "__Int.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/generic.h b/src/generic.h
new file mode 100644
index 00000000..860f2465
--- /dev/null
+++ b/src/generic.h
@@ -0,0 +1,51 @@
+/**CFile****************************************************************
+
+ FileName [.h]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName []
+
+ Synopsis [External declarations.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: .h,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __zzz_H__
+#define __zzz_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// BASIC TYPES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== zzz.c ==========================================================*/
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/src/map/fpga/fpga.c b/src/map/fpga/fpga.c
new file mode 100644
index 00000000..6b107498
--- /dev/null
+++ b/src/map/fpga/fpga.c
@@ -0,0 +1,239 @@
+/**CFile****************************************************************
+
+ FileName [fpga.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Command file for the FPGA package.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - August 18, 2004.]
+
+ Revision [$Id: fpga.c,v 1.4 2004/10/28 17:36:07 alanmi Exp $]
+
+***********************************************************************/
+
+#include "fpgaInt.h"
+#include "main.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Fpga_CommandReadLibrary( Abc_Frame_t * pAbc, int argc, char **argv );
+static int Fpga_CommandPrintLibrary( Abc_Frame_t * pAbc, int argc, char **argv );
+
+// the library file format should be as follows:
+/*
+# The area/delay of k-variable LUTs:
+# k area delay
+1 1 1
+2 2 2
+3 4 3
+4 8 4
+5 16 5
+6 32 6
+*/
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Package initialization procedure.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_Init( Abc_Frame_t * pAbc )
+{
+ // set the default library
+ //Fpga_LutLib_t s_LutLib = { "lutlib", 6, {0,1,2,4,8,16,32}, {0,1,2,3,4,5,6} };
+ Fpga_LutLib_t s_LutLib = { "lutlib", 5, {0,1,1,1,1,1}, {0,1,1,1,1,1} };
+ Abc_FrameSetLibLut( pAbc, Fpga_LutLibDup(&s_LutLib) );
+
+ Cmd_CommandAdd( pAbc, "FPGA mapping", "read_lut", Fpga_CommandReadLibrary, 0 );
+ Cmd_CommandAdd( pAbc, "FPGA mapping", "print_lut", Fpga_CommandPrintLibrary, 0 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Package ending procedure.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_End()
+{
+ Fpga_LutLibFree( Abc_FrameReadLibLut(Abc_FrameGetGlobalFrame()) );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Command procedure to read LUT libraries.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_CommandReadLibrary( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ FILE * pFile;
+ FILE * pOut, * pErr;
+ Fpga_LutLib_t * pLib;
+ Abc_Ntk_t * pNet;
+ char * FileName;
+ int fVerbose;
+ int c;
+
+ pNet = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set the defaults
+ fVerbose = 1;
+ util_getopt_reset();
+ while ( (c = util_getopt(argc, argv, "vh")) != EOF )
+ {
+ switch (c)
+ {
+ case 'v':
+ fVerbose ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ break;
+ default:
+ goto usage;
+ }
+ }
+
+
+ if ( argc != util_optind + 1 )
+ {
+ goto usage;
+ }
+
+ // get the input file name
+ FileName = argv[util_optind];
+ if ( (pFile = fopen( FileName, "r" )) == NULL )
+ {
+ fprintf( pErr, "Cannot open input file \"%s\". ", FileName );
+ if ( FileName = Extra_FileGetSimilarName( FileName, ".genlib", ".lib", ".gen", ".g", NULL ) )
+ fprintf( pErr, "Did you mean \"%s\"?", FileName );
+ fprintf( pErr, "\n" );
+ return 1;
+ }
+ fclose( pFile );
+
+ // set the new network
+ pLib = Fpga_LutLibCreate( FileName, fVerbose );
+ if ( pLib == NULL )
+ {
+ fprintf( pErr, "Reading LUT library has failed.\n" );
+ goto usage;
+ }
+ // replace the current library
+ Fpga_LutLibFree( Abc_FrameReadLibLut(Abc_FrameGetGlobalFrame()) );
+ Abc_FrameSetLibLut( Abc_FrameGetGlobalFrame(), pLib );
+ return 0;
+
+usage:
+ fprintf( pErr, "\nusage: read_lut [-vh]\n");
+ fprintf( pErr, "\t read the LUT library from the file\n" );
+ fprintf( pErr, "\t-v : toggles enabling of verbose output [default = %s]\n", (fVerbose? "yes" : "no") );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ fprintf( pErr, "\t \n");
+ fprintf( pErr, "\t File format for a LUT library:\n");
+ fprintf( pErr, "\t (the default library is shown)\n");
+ fprintf( pErr, "\t \n");
+ fprintf( pErr, "\t # The area/delay of k-variable LUTs:\n");
+ fprintf( pErr, "\t # k area delay\n");
+ fprintf( pErr, "\t 1 1 1\n");
+ fprintf( pErr, "\t 2 2 2\n");
+ fprintf( pErr, "\t 3 4 3\n");
+ fprintf( pErr, "\t 4 8 4\n");
+ fprintf( pErr, "\t 5 16 5\n");
+ fprintf( pErr, "\t 6 32 6\n");
+ return 1; /* error exit */
+}
+
+/**Function*************************************************************
+
+ Synopsis [Command procedure to read LUT libraries.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_CommandPrintLibrary( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNet;
+ int fVerbose;
+ int c;
+
+ pNet = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set the defaults
+ fVerbose = 1;
+ util_getopt_reset();
+ while ( (c = util_getopt(argc, argv, "vh")) != EOF )
+ {
+ switch (c)
+ {
+ case 'v':
+ fVerbose ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ break;
+ default:
+ goto usage;
+ }
+ }
+
+
+ if ( argc != util_optind )
+ {
+ goto usage;
+ }
+
+ // set the new network
+ Fpga_LutLibPrint( Abc_FrameReadLibLut(Abc_FrameGetGlobalFrame()) );
+ return 0;
+
+usage:
+ fprintf( pErr, "\nusage: read_print [-vh]\n");
+ fprintf( pErr, "\t print the current LUT library\n" );
+ fprintf( pErr, "\t-v : toggles enabling of verbose output [default = %s]\n", (fVerbose? "yes" : "no") );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1; /* error exit */
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/fpga/fpga.h b/src/map/fpga/fpga.h
new file mode 100644
index 00000000..62a93a75
--- /dev/null
+++ b/src/map/fpga/fpga.h
@@ -0,0 +1,158 @@
+/**CFile****************************************************************
+
+ FileName [fpga.h]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Technology mapping for variable-size-LUT FPGAs.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - August 18, 2004.]
+
+ Revision [$Id: fpga.h,v 1.7 2004/09/30 21:18:09 satrajit Exp $]
+
+***********************************************************************/
+
+#ifndef __FPGA_H__
+#define __FPGA_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+// the maximum size of LUTs used for mapping
+#define FPGA_MAX_LUTSIZE 10
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct Fpga_ManStruct_t_ Fpga_Man_t;
+typedef struct Fpga_NodeStruct_t_ Fpga_Node_t;
+typedef struct Fpga_NodeVecStruct_t_ Fpga_NodeVec_t;
+typedef struct Fpga_CutStruct_t_ Fpga_Cut_t;
+typedef struct Fpga_LutLibStruct_t_ Fpga_LutLib_t;
+
+////////////////////////////////////////////////////////////////////////
+/// GLOBAL VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+#define Fpga_IsComplement(p) (((int)((long) (p) & 01)))
+#define Fpga_Regular(p) ((Fpga_Node_t *)((unsigned)(p) & ~01))
+#define Fpga_Not(p) ((Fpga_Node_t *)((long)(p) ^ 01))
+#define Fpga_NotCond(p,c) ((Fpga_Node_t *)((long)(p) ^ (c)))
+
+#define Fpga_Ref(p)
+#define Fpga_Deref(p)
+#define Fpga_RecursiveDeref(p,c)
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== fpgaCreate.c =============================================================*/
+extern Fpga_Man_t * Fpga_ManCreate( int nInputs, int nOutputs, int fVerbose );
+extern Fpga_Node_t * Fpga_NodeCreate( Fpga_Man_t * p, Fpga_Node_t * p1, Fpga_Node_t * p2 );
+extern void Fpga_ManFree( Fpga_Man_t * pMan );
+extern void Fpga_ManPrintTimeStats( Fpga_Man_t * p );
+
+extern int Fpga_ManReadInputNum( Fpga_Man_t * p );
+extern int Fpga_ManReadOutputNum( Fpga_Man_t * p );
+extern Fpga_Node_t ** Fpga_ManReadInputs ( Fpga_Man_t * p );
+extern Fpga_Node_t ** Fpga_ManReadOutputs( Fpga_Man_t * p );
+extern Fpga_Node_t * Fpga_ManReadConst1 ( Fpga_Man_t * p );
+extern float * Fpga_ManReadInputArrivals( Fpga_Man_t * p );
+extern int Fpga_ManReadVerbose( Fpga_Man_t * p );
+extern float * Fpga_ManReadLutAreas( Fpga_Man_t * p );
+extern void Fpga_ManSetTimeToMap( Fpga_Man_t * p, int Time );
+extern void Fpga_ManSetTimeToNet( Fpga_Man_t * p, int Time );
+extern void Fpga_ManSetTimeTotal( Fpga_Man_t * p, int Time );
+extern void Fpga_ManSetOutputNames( Fpga_Man_t * p, char ** ppNames );
+extern void Fpga_ManSetInputArrivals( Fpga_Man_t * p, float * pArrivals );
+extern void Fpga_ManSetTree( Fpga_Man_t * p, int fTree );
+extern void Fpga_ManSetPower( Fpga_Man_t * p, int fPower );
+extern void Fpga_ManSetAreaRecovery( Fpga_Man_t * p, int fAreaRecovery );
+extern void Fpga_ManSetResyn( Fpga_Man_t * p, int fResynthesis );
+extern void Fpga_ManSetDelayLimit( Fpga_Man_t * p, float DelayLimit );
+extern void Fpga_ManSetAreaLimit( Fpga_Man_t * p, float AreaLimit );
+extern void Fpga_ManSetTimeLimit( Fpga_Man_t * p, float TimeLimit );
+extern void Fpga_ManSetObeyFanoutLimits( Fpga_Man_t * p, int fObeyFanoutLimits );
+extern void Fpga_ManSetNumIterations( Fpga_Man_t * p, int nNumIterations );
+extern int Fpga_ManReadFanoutViolations( Fpga_Man_t * p );
+extern void Fpga_ManSetFanoutViolations( Fpga_Man_t * p, int nVio );
+extern void Fpga_ManSetChoiceNodeNum( Fpga_Man_t * p, int nChoiceNodes );
+extern void Fpga_ManSetChoiceNum( Fpga_Man_t * p, int nChoices );
+extern void Fpga_ManSetVerbose( Fpga_Man_t * p, int fVerbose );
+extern void Fpga_ManSetLatchNum( Fpga_Man_t * p, int nLatches );
+extern void Fpga_ManSetSequential( Fpga_Man_t * p, int fSequential );
+extern void Fpga_ManSetName( Fpga_Man_t * p, char * pFileName );
+
+extern int Fpga_LibReadLutMax( Fpga_LutLib_t * pLib );
+
+extern char * Fpga_NodeReadData0( Fpga_Node_t * p );
+extern Fpga_Node_t * Fpga_NodeReadData1( Fpga_Node_t * p );
+extern int Fpga_NodeReadNum( Fpga_Node_t * p );
+extern int Fpga_NodeReadLevel( Fpga_Node_t * p );
+extern Fpga_Cut_t * Fpga_NodeReadCuts( Fpga_Node_t * p );
+extern Fpga_Cut_t * Fpga_NodeReadCutBest( Fpga_Node_t * p );
+extern Fpga_Node_t * Fpga_NodeReadOne( Fpga_Node_t * p );
+extern Fpga_Node_t * Fpga_NodeReadTwo( Fpga_Node_t * p );
+extern void Fpga_NodeSetLevel( Fpga_Node_t * p, Fpga_Node_t * pNode );
+extern void Fpga_NodeSetData0( Fpga_Node_t * p, char * pData );
+extern void Fpga_NodeSetData1( Fpga_Node_t * p, Fpga_Node_t * pNode );
+extern void Fpga_NodeSetArrival( Fpga_Node_t * p, float Time );
+extern void Fpga_NodeSetNextE( Fpga_Node_t * p, Fpga_Node_t * pNextE );
+extern void Fpga_NodeSetRepr( Fpga_Node_t * p, Fpga_Node_t * pRepr );
+
+extern int Fpga_NodeIsConst( Fpga_Node_t * p );
+extern int Fpga_NodeIsVar( Fpga_Node_t * p );
+extern int Fpga_NodeIsAnd( Fpga_Node_t * p );
+extern int Fpga_NodeComparePhase( Fpga_Node_t * p1, Fpga_Node_t * p2 );
+
+extern int Fpga_CutReadLeavesNum( Fpga_Cut_t * p );
+extern Fpga_Node_t ** Fpga_CutReadLeaves( Fpga_Cut_t * p );
+
+extern Fpga_Node_t * Fpga_NodeAnd( Fpga_Man_t * p, Fpga_Node_t * p1, Fpga_Node_t * p2 );
+extern Fpga_Node_t * Fpga_NodeOr( Fpga_Man_t * p, Fpga_Node_t * p1, Fpga_Node_t * p2 );
+extern Fpga_Node_t * Fpga_NodeExor( Fpga_Man_t * p, Fpga_Node_t * p1, Fpga_Node_t * p2 );
+extern Fpga_Node_t * Fpga_NodeMux( Fpga_Man_t * p, Fpga_Node_t * pNode, Fpga_Node_t * pNodeT, Fpga_Node_t * pNodeE );
+extern void Fpga_NodeSetChoice( Fpga_Man_t * pMan, Fpga_Node_t * pNodeOld, Fpga_Node_t * pNodeNew );
+
+extern void Fpga_ManStats( Fpga_Man_t * p );
+
+/*=== fpgaCore.c =============================================================*/
+extern int Fpga_Mapping( Fpga_Man_t * p );
+/*=== fpgaCut.c ===============================================================*/
+extern void Fpga_MappingCreatePiCuts( Fpga_Man_t * p );
+extern void Fpga_CutsCleanSign( Fpga_Man_t * pMan );
+/*=== fpgaCutUtils.c =============================================================*/
+extern void Fpga_CutCreateFromNode( Fpga_Man_t * p, int iRoot, int * pLeaves, int nLeaves );
+extern void Fpga_MappingSetUsedCuts( Fpga_Man_t * p );
+/*=== fpgaFraig.c =============================================================*/
+extern Fpga_Man_t * Fpga_ManDupFraig( Fraig_Man_t * pManFraig );
+extern Fpga_Man_t * Fpga_ManBalanceFraig( Fraig_Man_t * pManFraig, int * pInputArrivals );
+/*=== fpgaLib.c =============================================================*/
+extern Fpga_LutLib_t * Fpga_LutLibDup( Fpga_LutLib_t * p );
+/*=== fpgaTruth.c =============================================================*/
+extern void * Fpga_TruthsCutBdd( void * dd, Fpga_Cut_t * pCut );
+/*=== fpgaUtil.c =============================================================*/
+extern int Fpga_ManCheckConsistency( Fpga_Man_t * p );
+extern void Fpga_ManCleanData0( Fpga_Man_t * pMan );
+extern Fpga_NodeVec_t * Fpga_CollectNodeTfo( Fpga_Man_t * pMan, Fpga_Node_t * pNode );
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+#endif
diff --git a/src/map/fpga/fpgaCore.c b/src/map/fpga/fpgaCore.c
new file mode 100644
index 00000000..37726542
--- /dev/null
+++ b/src/map/fpga/fpgaCore.c
@@ -0,0 +1,241 @@
+/**CFile****************************************************************
+
+ FileName [fpgaCore.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Technology mapping for variable-size-LUT FPGAs.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - August 18, 2004.]
+
+ Revision [$Id: fpgaCore.c,v 1.7 2004/10/01 23:41:04 satrajit Exp $]
+
+***********************************************************************/
+
+#include "fpgaInt.h"
+//#include "res.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Fpga_MappingPostProcess( Fpga_Man_t * p );
+
+extern void Fpga_Experiment( Fpga_Man_t * p );
+extern void Fpga_MappingCutsSeq( Fpga_Man_t * p );
+extern void Fpga_MappingLValues( Fpga_Man_t * pMan, int fVerbose );
+
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Performs technology mapping for the given object graph.]
+
+ Description [The object graph is stored in the mapping manager.
+ First, all the AND-nodes, which fanout into the POs, are collected
+ in the DFS fashion. Next, three steps are performed: the k-feasible
+ cuts are computed for each node, the truth tables are computed for
+ each cut, and the delay-optimal matches are assigned for each node.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_Mapping( Fpga_Man_t * p )
+{
+ int clk;
+
+ // collect the nodes reachable from POs in the DFS order (including the choices)
+ p->vAnds = Fpga_MappingDfs( p, 1 );
+ Fpga_ManReportChoices( p ); // recomputes levels
+ Fpga_MappingSetChoiceLevels( p );
+
+ if ( p->fSequential )
+ {
+// Fpga_MappingCutsSeq( p );
+ Fpga_MappingCuts( p );
+//clk = clock();
+// Fpga_MappingLValues( p, p->fVerbose );
+//PRT( "Time", clock() - clk );
+ return 0;
+ }
+
+ // compute the cuts of nodes in the DFS order
+ clk = clock();
+ Fpga_MappingCuts( p );
+ p->timeCuts = clock() - clk;
+
+// Fpga_MappingSortByLevel( p, p->vAnds, 1 );
+
+ // derive the truth tables
+ clk = clock();
+// Fpga_MappingTruths( p );
+ p->timeTruth = clock() - clk;
+
+ // match the truth tables to the supergates
+ clk = clock();
+ if ( !Fpga_MappingMatches( p, 1 ) )
+ return 0;
+ p->timeMatch = clock() - clk;
+
+ // perform area recovery
+ if ( p->fAreaRecovery )
+ {
+ clk = clock();
+ if ( !Fpga_MappingPostProcess( p ) )
+ return 0;
+ p->timeRecover = clock() - clk;
+ }
+
+ // perform resynthesis
+// if ( p->fResynthesis )
+// Res_Resynthesize( p, p->DelayLimit, p->AreaLimit, p->TimeLimit, 1 );
+
+ // print the AI-graph used for mapping
+ //Fpga_ManShow( p, "test" );
+ if ( p->fVerbose )
+ Fpga_MappingPrintOutputArrivals( p );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Postprocesses the mapped network for area recovery.]
+
+ Description [This procedure assumes that the mapping is assigned.
+ It iterates the loop, in which the required times are computed and
+ the mapping is updated. It is conceptually similar to the paper:
+ V. Manohararajah, S. D. Brown, Z. G. Vranesic, Heuristics for area
+ minimization in LUT-based FGPA technology mapping. Proc. IWLS '04.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_MappingPostProcess( Fpga_Man_t * p )
+{
+ float aAreaTotalPrev, aAreaTotalCur, aAreaTotalCur2;
+ float aSwitchTotalPrev, aSwitchTotalCur;
+ int Iter, clk;
+
+if ( p->fVerbose )
+{
+printf( "Iteration %dD : Area = %11.1f ", 0, Fpga_MappingArea( p ) );
+PRT( "Time", p->timeMatch );
+}
+
+// aAreaTotalCur = FPGA_FLOAT_LARGE;
+ aAreaTotalCur = Fpga_MappingSetRefsAndArea( p );
+
+ Iter = 1;
+ do {
+clk = clock();
+ // save the previous area flow
+ aAreaTotalPrev = aAreaTotalCur;
+
+ // compute the required times and the fanouts
+ Fpga_TimeComputeRequiredGlobal( p );
+ // remap topologically
+ Fpga_MappingMatches( p, 0 );
+ // get the resulting area
+ aAreaTotalCur = Fpga_MappingArea( p );
+if ( p->fVerbose )
+{
+printf( "Iteration %dF : Area = %11.1f ", Iter++, aAreaTotalCur );
+PRT( "Time", clock() - clk );
+}
+ if ( p->fPower )
+ aSwitchTotalCur = Fpga_MappingPrintSwitching( p );
+ // quit if this iteration reduced area flow by less than 1%
+ } while ( aAreaTotalPrev > 1.02 * aAreaTotalCur );
+
+
+/*
+ // compute the area of each cut
+ aAreaTotalCur = Fpga_MappingSetRefsAndArea( p );
+ // compute the required times and the fanouts
+ Fpga_TimeComputeRequiredGlobal( p );
+ // perform experiment
+ Fpga_Experiment( p );
+*/
+
+
+ // compute the area of each cut
+ aAreaTotalCur = Fpga_MappingSetRefsAndArea( p );
+ aAreaTotalCur2 = Fpga_MappingComputeCutAreas( p );
+ assert( aAreaTotalCur == aAreaTotalCur2 );
+
+
+// aAreaTotalCur = FPGA_FLOAT_LARGE;
+// Iter = 1;
+ do {
+clk = clock();
+ // save the previous area flow
+ aAreaTotalPrev = aAreaTotalCur;
+
+ // compute the required times and the fanouts
+ Fpga_TimeComputeRequiredGlobal( p );
+ // remap topologically
+ Fpga_MappingMatchesArea( p );
+ // get the resulting area
+ aAreaTotalCur = Fpga_MappingArea( p );
+if ( p->fVerbose )
+{
+printf( "Iteration %dA : Area = %11.1f ", Iter++, aAreaTotalCur );
+PRT( "Time", clock() - clk );
+}
+ if ( p->fPower )
+ {
+ aSwitchTotalPrev = aSwitchTotalCur;
+ aSwitchTotalCur = Fpga_MappingPrintSwitching( p );
+ }
+ // quit if this iteration reduced area flow by less than 1%
+ } while ( aAreaTotalPrev > 1.02 * aAreaTotalCur );
+
+
+ if ( p->fPower )
+ {
+ do {
+clk = clock();
+ // save the previous area flow
+ aAreaTotalPrev = aAreaTotalCur;
+
+ // compute the required times and the fanouts
+ Fpga_TimeComputeRequiredGlobal( p );
+ // remap topologically
+ Fpga_MappingMatchesSwitch( p );
+ // get the resulting area
+ aAreaTotalCur = Fpga_MappingArea( p );
+if ( p->fVerbose )
+{
+printf( "Iteration %dS : Area = %11.1f ", Iter++, aAreaTotalCur );
+PRT( "Time", clock() - clk );
+}
+ aSwitchTotalPrev = aSwitchTotalCur;
+ aSwitchTotalCur = Fpga_MappingPrintSwitching( p );
+ // quit if this iteration reduced area flow by less than 1%
+ } while ( aSwitchTotalPrev > 1.01 * aSwitchTotalCur );
+ }
+
+/*
+ // compute the area of each cut
+ aAreaTotalCur = Fpga_MappingSetRefsAndArea( p );
+ // compute the required times and the fanouts
+ Fpga_TimeComputeRequiredGlobal( p );
+ // perform experiment
+ Fpga_Experiment( p );
+*/
+ p->fAreaGlo = aAreaTotalCur;
+ return 1;
+}
+
+
diff --git a/src/map/fpga/fpgaCreate.c b/src/map/fpga/fpgaCreate.c
new file mode 100644
index 00000000..fc6577fa
--- /dev/null
+++ b/src/map/fpga/fpgaCreate.c
@@ -0,0 +1,585 @@
+/**CFile****************************************************************
+
+ FileName [fpgaCreate.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Technology mapping for variable-size-LUT FPGAs.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - August 18, 2004.]
+
+ Revision [$Id: fpgaCreate.c,v 1.8 2004/09/30 21:18:09 satrajit Exp $]
+
+***********************************************************************/
+
+#include "fpgaInt.h"
+#include "main.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Fpga_TableCreate( Fpga_Man_t * p );
+static void Fpga_TableResize( Fpga_Man_t * p );
+static Fpga_Node_t * Fpga_TableLookup( Fpga_Man_t * p, Fpga_Node_t * p1, Fpga_Node_t * p2 );
+
+// hash key for the structural hash table
+static inline unsigned Fpga_HashKey2( Fpga_Node_t * p0, Fpga_Node_t * p1, int TableSize ) { return ((unsigned)(p0) + (unsigned)(p1) * 12582917) % TableSize; }
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Reads parameters of the mapping manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_ManReadInputNum( Fpga_Man_t * p ) { return p->nInputs; }
+int Fpga_ManReadOutputNum( Fpga_Man_t * p ) { return p->nOutputs; }
+Fpga_Node_t ** Fpga_ManReadInputs ( Fpga_Man_t * p ) { return p->pInputs; }
+Fpga_Node_t ** Fpga_ManReadOutputs( Fpga_Man_t * p ) { return p->pOutputs; }
+Fpga_Node_t * Fpga_ManReadConst1 ( Fpga_Man_t * p ) { return p->pConst1; }
+float * Fpga_ManReadInputArrivals( Fpga_Man_t * p ) { return p->pInputArrivals;}
+int Fpga_ManReadVerbose( Fpga_Man_t * p ) { return p->fVerbose; }
+float * Fpga_ManReadLutAreas( Fpga_Man_t * p ) { return p->pLutLib->pLutAreas; }
+void Fpga_ManSetTimeToMap( Fpga_Man_t * p, int Time ) { p->timeToMap = Time; }
+void Fpga_ManSetTimeToNet( Fpga_Man_t * p, int Time ) { p->timeToNet = Time; }
+void Fpga_ManSetTimeTotal( Fpga_Man_t * p, int Time ) { p->timeTotal = Time; }
+void Fpga_ManSetOutputNames( Fpga_Man_t * p, char ** ppNames ) { p->ppOutputNames = ppNames; }
+void Fpga_ManSetInputArrivals( Fpga_Man_t * p, float * pArrivals ) { p->pInputArrivals = pArrivals; }
+void Fpga_ManSetTree( Fpga_Man_t * p, int fTree ) { p->fTree = fTree; }
+void Fpga_ManSetPower( Fpga_Man_t * p, int fPower ) { p->fPower = fPower; }
+void Fpga_ManSetAreaRecovery( Fpga_Man_t * p, int fAreaRecovery ) { p->fAreaRecovery = fAreaRecovery;}
+void Fpga_ManSetResyn( Fpga_Man_t * p, int fResynthesis ) { p->fResynthesis = fResynthesis; }
+void Fpga_ManSetDelayLimit( Fpga_Man_t * p, float DelayLimit ) { p->DelayLimit = DelayLimit; }
+void Fpga_ManSetAreaLimit( Fpga_Man_t * p, float AreaLimit ) { p->AreaLimit = AreaLimit; }
+void Fpga_ManSetTimeLimit( Fpga_Man_t * p, float TimeLimit ) { p->TimeLimit = TimeLimit; }
+void Fpga_ManSetChoiceNodeNum( Fpga_Man_t * p, int nChoiceNodes ) { p->nChoiceNodes = nChoiceNodes; }
+void Fpga_ManSetChoiceNum( Fpga_Man_t * p, int nChoices ) { p->nChoices = nChoices; }
+void Fpga_ManSetVerbose( Fpga_Man_t * p, int fVerbose ) { p->fVerbose = fVerbose; }
+void Fpga_ManSetLatchNum( Fpga_Man_t * p, int nLatches ) { p->nLatches = nLatches; }
+void Fpga_ManSetSequential( Fpga_Man_t * p, int fSequential ) { p->fSequential = fSequential; }
+void Fpga_ManSetName( Fpga_Man_t * p, char * pFileName ) { p->pFileName = pFileName; }
+
+/**Function*************************************************************
+
+ Synopsis [Reads the parameters of the LUT library.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_LibReadLutMax( Fpga_LutLib_t * pLib ) { return pLib->LutMax; }
+
+/**Function*************************************************************
+
+ Synopsis [Reads parameters of the mapping node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Fpga_NodeReadData0( Fpga_Node_t * p ) { return p->pData0; }
+Fpga_Node_t * Fpga_NodeReadData1( Fpga_Node_t * p ) { return p->pLevel; }
+int Fpga_NodeReadNum( Fpga_Node_t * p ) { return p->Num; }
+int Fpga_NodeReadLevel( Fpga_Node_t * p ) { return Fpga_Regular(p)->Level; }
+Fpga_Cut_t * Fpga_NodeReadCuts( Fpga_Node_t * p ) { return p->pCuts; }
+Fpga_Cut_t * Fpga_NodeReadCutBest( Fpga_Node_t * p ) { return p->pCutBest; }
+Fpga_Node_t * Fpga_NodeReadOne( Fpga_Node_t * p ) { return p->p1; }
+Fpga_Node_t * Fpga_NodeReadTwo( Fpga_Node_t * p ) { return p->p2; }
+void Fpga_NodeSetData0( Fpga_Node_t * p, char * pData ) { p->pData0 = pData; }
+void Fpga_NodeSetData1( Fpga_Node_t * p, Fpga_Node_t * pNode ) { p->pLevel = pNode; }
+void Fpga_NodeSetNextE( Fpga_Node_t * p, Fpga_Node_t * pNextE ) { p->pNextE = pNextE; }
+void Fpga_NodeSetRepr( Fpga_Node_t * p, Fpga_Node_t * pRepr ) { p->pRepr = pRepr; }
+
+/**Function*************************************************************
+
+ Synopsis [Checks the type of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_NodeIsConst( Fpga_Node_t * p ) { return (Fpga_Regular(p))->Num == -1; }
+int Fpga_NodeIsVar( Fpga_Node_t * p ) { return (Fpga_Regular(p))->p1 == NULL && (Fpga_Regular(p))->Num >= 0; }
+int Fpga_NodeIsAnd( Fpga_Node_t * p ) { return (Fpga_Regular(p))->p1 != NULL; }
+int Fpga_NodeComparePhase( Fpga_Node_t * p1, Fpga_Node_t * p2 ) { assert( !Fpga_IsComplement(p1) ); assert( !Fpga_IsComplement(p2) ); return p1->fInv ^ p2->fInv; }
+
+/**Function*************************************************************
+
+ Synopsis [Reads parameters from the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_CutReadLeavesNum( Fpga_Cut_t * p ) { return p->nLeaves; }
+Fpga_Node_t ** Fpga_CutReadLeaves( Fpga_Cut_t * p ) { return p->ppLeaves; }
+
+
+/**Function*************************************************************
+
+ Synopsis [Create the mapping manager.]
+
+ Description [The number of inputs and outputs is assumed to be
+ known is advance. It is much simpler to have them fixed upfront.
+ When it comes to representing the object graph in the form of
+ AIG, the resulting manager is similar to the regular AIG manager,
+ except that it does not use reference counting (and therefore
+ does not have garbage collections). It does have table resizing.
+ The data structure is more flexible to represent additional
+ information needed for mapping.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_Man_t * Fpga_ManCreate( int nInputs, int nOutputs, int fVerbose )
+{
+ Fpga_Man_t * p;
+ int i;
+
+ // start the manager
+ p = ALLOC( Fpga_Man_t, 1 );
+ memset( p, 0, sizeof(Fpga_Man_t) );
+ p->pLutLib = Abc_FrameReadLibLut(Abc_FrameGetGlobalFrame());
+ p->nVarsMax = p->pLutLib->LutMax;
+ p->fVerbose = fVerbose;
+ p->fAreaRecovery = 1;
+ p->fTree = 0;
+ p->fRefCount = 1;
+ p->fEpsilon = (float)0.00001;
+
+ Fpga_TableCreate( p );
+//if ( p->fVerbose )
+// printf( "Node = %d (%d) bytes. Cut = %d bytes.\n", sizeof(Fpga_Node_t), FPGA_NUM_BYTES(sizeof(Fpga_Node_t)), sizeof(Fpga_Cut_t) );
+ p->mmNodes = Extra_MmFixedStart( FPGA_NUM_BYTES(sizeof(Fpga_Node_t)) );
+ p->mmCuts = Extra_MmFixedStart( sizeof(Fpga_Cut_t) );
+
+ assert( p->nVarsMax > 0 );
+ Fpga_MappingSetupTruthTables( p->uTruths );
+
+ // make sure the constant node will get index -1
+ p->nNodes = -1;
+ // create the constant node
+ p->pConst1 = Fpga_NodeCreate( p, NULL, NULL );
+ p->vNodesAll = Fpga_NodeVecAlloc( 100 );
+
+ // create the PI nodes
+ p->nInputs = nInputs;
+ p->pInputs = ALLOC( Fpga_Node_t *, nInputs );
+ for ( i = 0; i < nInputs; i++ )
+ p->pInputs[i] = Fpga_NodeCreate( p, NULL, NULL );
+
+ // create the place for the output nodes
+ p->nOutputs = nOutputs;
+ p->pOutputs = ALLOC( Fpga_Node_t *, nOutputs );
+ memset( p->pOutputs, 0, sizeof(Fpga_Node_t *) * nOutputs );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Deallocates the mapping manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_ManFree( Fpga_Man_t * p )
+{
+// Fpga_ManStats( p );
+
+// int i;
+// for ( i = 0; i < p->vNodesAll->nSize; i++ )
+// Fpga_NodeVecFree( p->vNodesAll->pArray[i]->vFanouts );
+// Fpga_NodeVecFree( p->pConst1->vFanouts );
+ if ( p->vAnds )
+ Fpga_NodeVecFree( p->vAnds );
+ if ( p->vNodesAll )
+ Fpga_NodeVecFree( p->vNodesAll );
+ Extra_MmFixedStop( p->mmNodes, 0 );
+ Extra_MmFixedStop( p->mmCuts, 0 );
+ FREE( p->pInputArrivals );
+ FREE( p->pInputs );
+ FREE( p->pOutputs );
+ FREE( p->pBins );
+// FREE( p->ppOutputNames );
+ if ( p->pSimInfo )
+ {
+ FREE( p->pSimInfo[0] );
+ FREE( p->pSimInfo );
+ }
+ FREE( p );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Prints runtime statistics of the mapping manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_ManPrintTimeStats( Fpga_Man_t * p )
+{
+ extern char * pNetName;
+ extern int TotalLuts;
+// FILE * pTable;
+
+
+/*
+ pTable = fopen( "stats.txt", "a+" );
+ fprintf( pTable, "%s ", pNetName );
+ fprintf( pTable, "%.0f ", p->fRequiredGlo );
+// fprintf( pTable, "%.0f ", p->fAreaGlo );//+ (float)nOutputInvs );
+ fprintf( pTable, "%.0f ", (float)TotalLuts );
+ fprintf( pTable, "%4.2f\n", (float)(p->timeTotal-p->timeToMap)/(float)(CLOCKS_PER_SEC) );
+ fclose( pTable );
+*/
+
+// printf( "N-canonical = %d. Matchings = %d. ", p->nCanons, p->nMatches );
+// printf( "Choice nodes = %d. Choices = %d.\n", p->nChoiceNodes, p->nChoices );
+ PRT( "ToMap", p->timeToMap );
+ PRT( "Cuts ", p->timeCuts );
+ PRT( "Match", p->timeMatch );
+ PRT( "Area ", p->timeRecover );
+ PRT( "ToNet", p->timeToNet );
+ PRT( "TOTAL", p->timeTotal );
+ if ( p->time1 ) { PRT( "time1", p->time1 ); }
+ if ( p->time2 ) { PRT( "time2", p->time2 ); }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates a new node.]
+
+ Description [This procedure should be called to create the constant
+ node and the PI nodes first.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_Node_t * Fpga_NodeCreate( Fpga_Man_t * p, Fpga_Node_t * p1, Fpga_Node_t * p2 )
+{
+ Fpga_Node_t * pNode;
+ // create the node
+ pNode = (Fpga_Node_t *)Extra_MmFixedEntryFetch( p->mmNodes );
+ memset( pNode, 0, sizeof(Fpga_Node_t) );
+ // set very large required time
+ pNode->tRequired = FPGA_FLOAT_LARGE;
+ pNode->aEstFanouts = -1;
+ pNode->p1 = p1;
+ pNode->p2 = p2;
+ // set the number of this node
+ pNode->Num = p->nNodes++;
+ // place to store the fanouts
+// pNode->vFanouts = Fpga_NodeVecAlloc( 5 );
+ // store this node in the internal array
+ if ( pNode->Num >= 0 )
+ Fpga_NodeVecPush( p->vNodesAll, pNode );
+ else
+ pNode->fInv = 1;
+ // set the level of this node
+ if ( p1 )
+ {
+ // create the fanout info
+ Fpga_NodeAddFaninFanout( Fpga_Regular(p1), pNode );
+ Fpga_NodeAddFaninFanout( Fpga_Regular(p2), pNode );
+ // compute the level
+ pNode->Level = 1 + FPGA_MAX(Fpga_Regular(p1)->Level, Fpga_Regular(p2)->Level);
+ pNode->fInv = Fpga_NodeIsSimComplement(p1) & Fpga_NodeIsSimComplement(p2);
+ }
+ // reference the inputs (will be used to compute the number of fanouts)
+ if ( p->fRefCount )
+ {
+ if ( p1 ) Fpga_NodeRef(p1);
+ if ( p2 ) Fpga_NodeRef(p2);
+ }
+ return pNode;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Create the unique table of AND gates.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_TableCreate( Fpga_Man_t * pMan )
+{
+ assert( pMan->pBins == NULL );
+ pMan->nBins = Cudd_Prime(50000);
+ pMan->pBins = ALLOC( Fpga_Node_t *, pMan->nBins );
+ memset( pMan->pBins, 0, sizeof(Fpga_Node_t *) * pMan->nBins );
+ pMan->nNodes = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Looks up the AND2 node in the unique table.]
+
+ Description [This procedure implements one-level hashing. All the nodes
+ are hashed by their children. If the node with the same children was already
+ created, it is returned by the call to this procedure. If it does not exist,
+ this procedure creates a new node with these children. ]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_Node_t * Fpga_TableLookup( Fpga_Man_t * pMan, Fpga_Node_t * p1, Fpga_Node_t * p2 )
+{
+ Fpga_Node_t * pEnt;
+ unsigned Key;
+
+ if ( p1 == p2 )
+ return p1;
+ if ( p1 == Fpga_Not(p2) )
+ return Fpga_Not(pMan->pConst1);
+ if ( Fpga_NodeIsConst(p1) )
+ {
+ if ( p1 == pMan->pConst1 )
+ return p2;
+ return Fpga_Not(pMan->pConst1);
+ }
+ if ( Fpga_NodeIsConst(p2) )
+ {
+ if ( p2 == pMan->pConst1 )
+ return p1;
+ return Fpga_Not(pMan->pConst1);
+ }
+
+ if ( Fpga_Regular(p1)->Num > Fpga_Regular(p2)->Num )
+ pEnt = p1, p1 = p2, p2 = pEnt;
+
+ Key = Fpga_HashKey2( p1, p2, pMan->nBins );
+ for ( pEnt = pMan->pBins[Key]; pEnt; pEnt = pEnt->pNext )
+ if ( pEnt->p1 == p1 && pEnt->p2 == p2 )
+ return pEnt;
+ // resize the table
+ if ( pMan->nNodes >= 2 * pMan->nBins )
+ {
+ Fpga_TableResize( pMan );
+ Key = Fpga_HashKey2( p1, p2, pMan->nBins );
+ }
+ // create the new node
+ pEnt = Fpga_NodeCreate( pMan, p1, p2 );
+ // add the node to the corresponding linked list in the table
+ pEnt->pNext = pMan->pBins[Key];
+ pMan->pBins[Key] = pEnt;
+ return pEnt;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Resizes the table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_TableResize( Fpga_Man_t * pMan )
+{
+ Fpga_Node_t ** pBinsNew;
+ Fpga_Node_t * pEnt, * pEnt2;
+ int nBinsNew, Counter, i, clk;
+ unsigned Key;
+
+clk = clock();
+ // get the new table size
+ nBinsNew = Cudd_Prime(2 * pMan->nBins);
+ // allocate a new array
+ pBinsNew = ALLOC( Fpga_Node_t *, nBinsNew );
+ memset( pBinsNew, 0, sizeof(Fpga_Node_t *) * nBinsNew );
+ // rehash the entries from the old table
+ Counter = 0;
+ for ( i = 0; i < pMan->nBins; i++ )
+ for ( pEnt = pMan->pBins[i], pEnt2 = pEnt? pEnt->pNext: NULL; pEnt;
+ pEnt = pEnt2, pEnt2 = pEnt? pEnt->pNext: NULL )
+ {
+ Key = Fpga_HashKey2( pEnt->p1, pEnt->p2, nBinsNew );
+ pEnt->pNext = pBinsNew[Key];
+ pBinsNew[Key] = pEnt;
+ Counter++;
+ }
+ assert( Counter == pMan->nNodes - pMan->nInputs );
+ if ( pMan->fVerbose )
+ {
+// printf( "Increasing the unique table size from %6d to %6d. ", pMan->nBins, nBinsNew );
+// PRT( "Time", clock() - clk );
+ }
+ // replace the table and the parameters
+ free( pMan->pBins );
+ pMan->pBins = pBinsNew;
+ pMan->nBins = nBinsNew;
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Elementary AND operation on the AIG.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_Node_t * Fpga_NodeAnd( Fpga_Man_t * p, Fpga_Node_t * p1, Fpga_Node_t * p2 )
+{
+ Fpga_Node_t * pNode;
+ pNode = Fpga_TableLookup( p, p1, p2 );
+ return pNode;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Elementary OR operation on the AIG.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_Node_t * Fpga_NodeOr( Fpga_Man_t * p, Fpga_Node_t * p1, Fpga_Node_t * p2 )
+{
+ Fpga_Node_t * pNode;
+ pNode = Fpga_Not( Fpga_TableLookup( p, Fpga_Not(p1), Fpga_Not(p2) ) );
+ return pNode;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Elementary EXOR operation on the AIG.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_Node_t * Fpga_NodeExor( Fpga_Man_t * p, Fpga_Node_t * p1, Fpga_Node_t * p2 )
+{
+ return Fpga_NodeMux( p, p1, Fpga_Not(p2), p2 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Elementary MUX operation on the AIG.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_Node_t * Fpga_NodeMux( Fpga_Man_t * p, Fpga_Node_t * pC, Fpga_Node_t * pT, Fpga_Node_t * pE )
+{
+ Fpga_Node_t * pAnd1, * pAnd2, * pRes;
+ pAnd1 = Fpga_TableLookup( p, pC, pT );
+ pAnd2 = Fpga_TableLookup( p, Fpga_Not(pC), pE );
+ pRes = Fpga_NodeOr( p, pAnd1, pAnd2 );
+ return pRes;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Sets the node to be equivalent to the given one.]
+
+ Description [This procedure is a work-around for the equivalence check.
+ Does not verify the equivalence. Use at the user's risk.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_NodeSetChoice( Fpga_Man_t * pMan, Fpga_Node_t * pNodeOld, Fpga_Node_t * pNodeNew )
+{
+ pNodeNew->pNextE = pNodeOld->pNextE;
+ pNodeOld->pNextE = pNodeNew;
+ pNodeNew->pRepr = pNodeOld;
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Prints some interesting stats.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_ManStats( Fpga_Man_t * p )
+{
+ FILE * pTable;
+ pTable = fopen( "stats.txt", "a+" );
+ fprintf( pTable, "%s ", p->pFileName );
+ fprintf( pTable, "%4d ", p->nInputs - p->nLatches );
+ fprintf( pTable, "%4d ", p->nOutputs - p->nLatches );
+ fprintf( pTable, "%4d ", p->nLatches );
+ fprintf( pTable, "%7d ", p->vAnds->nSize );
+ fprintf( pTable, "%7d ", Fpga_CutCountAll(p) );
+ fprintf( pTable, "%2d\n", (int)p->fRequiredGlo );
+ fclose( pTable );
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/map/fpga/fpgaCut.c b/src/map/fpga/fpgaCut.c
new file mode 100644
index 00000000..27079953
--- /dev/null
+++ b/src/map/fpga/fpgaCut.c
@@ -0,0 +1,1150 @@
+/**CFile****************************************************************
+
+ FileName [fpgaCut.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Generic technology mapping engine.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - August 18, 2004.]
+
+ Revision [$Id: fpgaCut.c,v 1.3 2004/07/06 04:55:57 alanmi Exp $]
+
+***********************************************************************/
+
+#include "fpgaInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct Fpga_CutTableStrutct_t Fpga_CutTable_t;
+struct Fpga_CutTableStrutct_t
+{
+ Fpga_Cut_t ** pBins; // the table used for linear probing
+ int nBins; // the size of the table
+ int * pCuts; // the array of cuts currently stored
+ int nCuts; // the number of cuts currently stored
+ Fpga_Cut_t ** pArray; // the temporary array of cuts
+ Fpga_Cut_t ** pCuts1; // the temporary array of cuts
+ Fpga_Cut_t ** pCuts2; // the temporary array of cuts
+};
+
+// the largest number of cuts considered
+#define FPGA_CUTS_MAX_COMPUTE 500
+// the largest number of cuts used
+#define FPGA_CUTS_MAX_USE 200
+
+// primes used to compute the hash key
+static int s_HashPrimes[10] = { 109, 499, 557, 619, 631, 709, 797, 881, 907, 991 };
+
+static int bit_count[256] = {
+ 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
+ 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
+ 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
+ 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
+ 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
+ 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
+ 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
+ 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
+};
+
+#define FPGA_COUNT_ONES(u) (bit_count[(u)&255]+bit_count[((u)>>8)&255]+bit_count[((u)>>16)&255]+bit_count[(u)>>24])
+
+static Fpga_Cut_t * Fpga_CutCompute( Fpga_Man_t * p, Fpga_CutTable_t * pTable, Fpga_Node_t * pNode );
+static void Fpga_CutFilter( Fpga_Man_t * p, Fpga_Node_t * pNode );
+static Fpga_Cut_t * Fpga_CutMergeLists( Fpga_Man_t * p, Fpga_CutTable_t * pTable, Fpga_Cut_t * pList1, Fpga_Cut_t * pList2, int fComp1, int fComp2, int fPivot1, int fPivot2 );
+static int Fpga_CutMergeTwo( Fpga_Cut_t * pCut1, Fpga_Cut_t * pCut2, Fpga_Node_t * ppNodes[], int nNodesMax );
+static Fpga_Cut_t * Fpga_CutUnionLists( Fpga_Cut_t * pList1, Fpga_Cut_t * pList2 );
+static int Fpga_CutBelongsToList( Fpga_Cut_t * pList, Fpga_Node_t * ppNodes[], int nNodes );
+extern Fpga_Cut_t * Fpga_CutAlloc( Fpga_Man_t * p );
+extern int Fpga_CutCountAll( Fpga_Man_t * pMan );
+
+static void Fpga_CutListPrint( Fpga_Man_t * pMan, Fpga_Node_t * pRoot );
+static void Fpga_CutListPrint2( Fpga_Man_t * pMan, Fpga_Node_t * pRoot );
+static void Fpga_CutPrint_( Fpga_Man_t * pMan, Fpga_Cut_t * pCut, Fpga_Node_t * pRoot );
+
+static Fpga_CutTable_t * Fpga_CutTableStart( Fpga_Man_t * pMan );
+static void Fpga_CutTableStop( Fpga_CutTable_t * p );
+static unsigned Fpga_CutTableHash( Fpga_Node_t * ppNodes[], int nNodes );
+static int Fpga_CutTableLookup( Fpga_CutTable_t * p, Fpga_Node_t * ppNodes[], int nNodes );
+static Fpga_Cut_t * Fpga_CutTableConsider( Fpga_Man_t * pMan, Fpga_CutTable_t * p, Fpga_Node_t * ppNodes[], int nNodes );
+static void Fpga_CutTableRestart( Fpga_CutTable_t * p );
+
+static int Fpga_CutSortCutsCompare( Fpga_Cut_t ** pC1, Fpga_Cut_t ** pC2 );
+static Fpga_Cut_t * Fpga_CutSortCuts( Fpga_Man_t * pMan, Fpga_CutTable_t * p, Fpga_Cut_t * pList );
+static int Fpga_CutList2Array( Fpga_Cut_t ** pArray, Fpga_Cut_t * pList );
+static Fpga_Cut_t * Fpga_CutArray2List( Fpga_Cut_t ** pArray, int nCuts );
+
+
+// iterator through all the cuts of the list
+#define Fpga_ListForEachCut( pList, pCut ) \
+ for ( pCut = pList; \
+ pCut; \
+ pCut = pCut->pNext )
+#define Fpga_ListForEachCutSafe( pList, pCut, pCut2 ) \
+ for ( pCut = pList, \
+ pCut2 = pCut? pCut->pNext: NULL; \
+ pCut; \
+ pCut = pCut2, \
+ pCut2 = pCut? pCut->pNext: NULL )
+
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Computes the cuts for each node in the object graph.]
+
+ Description [The cuts are computed in one sweep over the mapping graph.
+ First, the elementary cuts, which include the node itself, are assigned
+ to the PI nodes. The internal nodes are considered in the DFS order.
+ Each node is two-input AND-gate. So to compute the cuts at a node, we
+ need to merge the sets of cuts of its two predecessors. The merged set
+ contains only unique cuts with the number of inputs equal to k or less.
+ Finally, the elementary cut, composed of the node itself, is added to
+ the set of cuts for the node.
+
+ This procedure is pretty fast for 5-feasible cuts, but it dramatically
+ slows down on some "dense" networks when computing 6-feasible cuts.
+ The problem is that there are too many cuts in this case. We should
+ think how to heuristically trim the number of cuts in such cases,
+ to have reasonable runtime.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappingCuts( Fpga_Man_t * p )
+{
+ ProgressBar * pProgress;
+ Fpga_CutTable_t * pTable;
+ Fpga_Node_t * pNode;
+ int nCuts, nNodes, i;
+
+ // set the elementary cuts for the PI variables
+ assert( p->nVarsMax > 1 && p->nVarsMax < 7 );
+ Fpga_MappingCreatePiCuts( p );
+
+ // compute the cuts for the internal nodes
+ nNodes = p->vAnds->nSize;
+ pProgress = Extra_ProgressBarStart( stdout, nNodes );
+ pTable = Fpga_CutTableStart( p );
+ for ( i = 0; i < nNodes; i++ )
+ {
+ Extra_ProgressBarUpdate( pProgress, i, "Cuts ..." );
+ pNode = p->vAnds->pArray[i];
+ if ( !Fpga_NodeIsAnd( pNode ) )
+ continue;
+ Fpga_CutCompute( p, pTable, pNode );
+ }
+ Extra_ProgressBarStop( pProgress );
+ Fpga_CutTableStop( pTable );
+
+ // report the stats
+ if ( p->fVerbose )
+ {
+ nCuts = Fpga_CutCountAll(p);
+ printf( "Nodes = %6d. Total %d-feasible cuts = %d. Cuts per node = %.1f.\n",
+ p->nNodes, p->nVarsMax, nCuts, ((float)nCuts)/p->nNodes );
+ }
+
+ // print the cuts for the first primary output
+// Fpga_CutListPrint( p, Fpga_Regular(p->pOutputs[0]) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs technology mapping for variable-size-LUTs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappingCreatePiCuts( Fpga_Man_t * p )
+{
+ Fpga_Cut_t * pCut;
+ int i;
+
+ // set the elementary cuts for the PI variables
+ for ( i = 0; i < p->nInputs; i++ )
+ {
+ pCut = Fpga_CutAlloc( p );
+ pCut->nLeaves = 1;
+ pCut->ppLeaves[0] = p->pInputs[i];
+ pCut->uSign = (1 << (i%31));
+ p->pInputs[i]->pCuts = pCut;
+ p->pInputs[i]->pCutBest = pCut;
+ // set the input arrival times
+// p->pInputs[i]->pCut[1]->tArrival = p->pInputArrivals[i];
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the cuts for one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_Cut_t * Fpga_CutCompute( Fpga_Man_t * p, Fpga_CutTable_t * pTable, Fpga_Node_t * pNode )
+{
+ Fpga_Node_t * pTemp;
+ Fpga_Cut_t * pList, * pList1, * pList2;
+ Fpga_Cut_t * pCut;
+ int fPivot1 = p->fTree && (Fpga_NodeReadRef(pNode->p1)>2);
+ int fPivot2 = p->fTree && (Fpga_NodeReadRef(pNode->p2)>2);
+
+ // if the cuts are computed return them
+ if ( pNode->pCuts )
+ return pNode->pCuts;
+
+ // compute the cuts for the children
+ pList1 = Fpga_Regular(pNode->p1)->pCuts;
+ pList2 = Fpga_Regular(pNode->p2)->pCuts;
+ // merge the lists
+ pList = Fpga_CutMergeLists( p, pTable, pList1, pList2,
+ Fpga_IsComplement(pNode->p1), Fpga_IsComplement(pNode->p2),
+ fPivot1, fPivot2 );
+ // if there are functionally equivalent nodes, union them with this list
+ assert( pList );
+ // only add to the list of cuts if the node is a representative one
+ if ( pNode->pRepr == NULL )
+ {
+ for ( pTemp = pNode->pNextE; pTemp; pTemp = pTemp->pNextE )
+ {
+ assert( pTemp->pCuts );
+ pList = Fpga_CutUnionLists( pList, pTemp->pCuts );
+ assert( pTemp->pCuts );
+ pList = Fpga_CutSortCuts( p, pTable, pList );
+ }
+ }
+ // add the new cut
+ pCut = Fpga_CutAlloc( p );
+ pCut->nLeaves = 1;
+ pCut->ppLeaves[0] = pNode;
+ pCut->uSign = (1 << (pNode->Num%31));
+ pCut->fLevel = (float)pCut->ppLeaves[0]->Level;
+ // append (it is important that the elementary cut is appended first)
+ pCut->pNext = pList;
+ // set at the node
+ pNode->pCuts = pCut;
+ // remove the dominated cuts
+ Fpga_CutFilter( p, pNode );
+ // set the phase correctly
+ if ( pNode->pRepr && Fpga_NodeComparePhase(pNode, pNode->pRepr) )
+ {
+ Fpga_ListForEachCut( pNode->pCuts, pCut )
+ pCut->Phase = 1;
+ }
+
+
+/*
+ {
+ Fpga_Cut_t * pPrev;
+ int i, Counter = 0;
+ for ( pCut = pNode->pCuts->pNext, pPrev = pNode->pCuts; pCut; pCut = pCut->pNext )
+ {
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ if ( pCut->ppLeaves[i]->Level >= pNode->Level )
+ break;
+ if ( i != pCut->nLeaves )
+ pPrev->pNext = pCut->pNext;
+ else
+ pPrev = pCut;
+ }
+ }
+ {
+ int i, Counter = 0;;
+ for ( pCut = pNode->pCuts->pNext; pCut; pCut = pCut->pNext )
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ Counter += (pCut->ppLeaves[i]->Level >= pNode->Level);
+ if ( Counter )
+ printf( " %d", Counter );
+ }
+*/
+
+ return pCut;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Filter the cuts using dominance.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_CutFilter( Fpga_Man_t * p, Fpga_Node_t * pNode )
+{
+ Fpga_Cut_t * pTemp, * pPrev, * pCut, * pCut2;
+ int i, k, Counter;
+
+ Counter = 0;
+ pPrev = pNode->pCuts;
+ Fpga_ListForEachCutSafe( pNode->pCuts->pNext, pCut, pCut2 )
+ {
+ // go through all the previous cuts up to pCut
+ for ( pTemp = pNode->pCuts->pNext; pTemp != pCut; pTemp = pTemp->pNext )
+ {
+ // check if every node in pTemp is contained in pCut
+ for ( i = 0; i < pTemp->nLeaves; i++ )
+ {
+ for ( k = 0; k < pCut->nLeaves; k++ )
+ if ( pTemp->ppLeaves[i] == pCut->ppLeaves[k] )
+ break;
+ if ( k == pCut->nLeaves ) // node i in pTemp is not contained in pCut
+ break;
+ }
+ if ( i == pTemp->nLeaves ) // every node in pTemp is contained in pCut
+ {
+ Counter++;
+ break;
+ }
+ }
+ if ( pTemp != pCut ) // pTemp contain pCut
+ {
+ pPrev->pNext = pCut->pNext; // skip pCut
+ // recycle pCut
+ Fpga_CutFree( p, pCut );
+ }
+ else
+ pPrev = pCut;
+ }
+// printf( "Dominated = %3d. \n", Counter );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Merges two lists of cuts.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_Cut_t * Fpga_CutMergeLists( Fpga_Man_t * p, Fpga_CutTable_t * pTable,
+ Fpga_Cut_t * pList1, Fpga_Cut_t * pList2, int fComp1, int fComp2, int fPivot1, int fPivot2 )
+{
+ Fpga_Node_t * ppNodes[6];
+ Fpga_Cut_t * pListNew, ** ppListNew, * pLists[7] = { NULL };
+ Fpga_Cut_t * pCut, * pPrev, * pTemp1, * pTemp2;
+ int nNodes, Counter, i;
+ Fpga_Cut_t ** ppArray1, ** ppArray2, ** ppArray3;
+ int nCuts1, nCuts2, nCuts3, k, fComp3;
+
+ ppArray1 = pTable->pCuts1;
+ ppArray2 = pTable->pCuts2;
+ nCuts1 = Fpga_CutList2Array( ppArray1, pList1 );
+ nCuts2 = Fpga_CutList2Array( ppArray2, pList2 );
+ if ( fPivot1 )
+ nCuts1 = 1;
+ if ( fPivot2 )
+ nCuts2 = 1;
+ // swap the lists based on their length
+ if ( nCuts1 > nCuts2 )
+ {
+ ppArray3 = ppArray1;
+ ppArray1 = ppArray2;
+ ppArray2 = ppArray3;
+
+ nCuts3 = nCuts1;
+ nCuts1 = nCuts2;
+ nCuts2 = nCuts3;
+
+ fComp3 = fComp1;
+ fComp1 = fComp2;
+ fComp2 = fComp3;
+ }
+ // pList1 is shorter or equal length compared to pList2
+
+ // prepare the manager for the cut computation
+ Fpga_CutTableRestart( pTable );
+ // go through the cut pairs
+ Counter = 0;
+// for ( pTemp1 = pList1; pTemp1; pTemp1 = fPivot1? NULL: pTemp1->pNext )
+// for ( pTemp2 = pList2; pTemp2; pTemp2 = fPivot2? NULL: pTemp2->pNext )
+ for ( i = 0; i < nCuts1; i++ )
+ {
+ for ( k = 0; k <= i; k++ )
+ {
+ pTemp1 = ppArray1[i];
+ pTemp2 = ppArray2[k];
+
+ if ( pTemp1->nLeaves == p->nVarsMax && pTemp2->nLeaves == p->nVarsMax )
+ {
+ if ( pTemp1->ppLeaves[0] != pTemp2->ppLeaves[0] )
+ continue;
+ if ( pTemp1->ppLeaves[1] != pTemp2->ppLeaves[1] )
+ continue;
+ }
+
+ // check if k-feasible cut exists
+ nNodes = Fpga_CutMergeTwo( pTemp1, pTemp2, ppNodes, p->nVarsMax );
+ if ( nNodes == 0 )
+ continue;
+ // consider the cut for possible addition to the set of new cuts
+ pCut = Fpga_CutTableConsider( p, pTable, ppNodes, nNodes );
+ if ( pCut == NULL )
+ continue;
+ // add data to the cut
+ pCut->pOne = Fpga_CutNotCond( pTemp1, fComp1 );
+ pCut->pTwo = Fpga_CutNotCond( pTemp2, fComp2 );
+ // create the signature
+ pCut->uSign = pTemp1->uSign | pTemp2->uSign;
+ // add it to the corresponding list
+ pCut->pNext = pLists[pCut->nLeaves];
+ pLists[pCut->nLeaves] = pCut;
+ // count this cut and quit if limit is reached
+ Counter++;
+ if ( Counter == FPGA_CUTS_MAX_COMPUTE )
+ goto QUITS;
+ }
+ for ( k = 0; k < i; k++ )
+ {
+ pTemp1 = ppArray1[k];
+ pTemp2 = ppArray2[i];
+
+ if ( pTemp1->nLeaves == p->nVarsMax && pTemp2->nLeaves == p->nVarsMax )
+ {
+ if ( pTemp1->ppLeaves[0] != pTemp2->ppLeaves[0] )
+ continue;
+ if ( pTemp1->ppLeaves[1] != pTemp2->ppLeaves[1] )
+ continue;
+ }
+
+
+ // check if k-feasible cut exists
+ nNodes = Fpga_CutMergeTwo( pTemp1, pTemp2, ppNodes, p->nVarsMax );
+ if ( nNodes == 0 )
+ continue;
+ // consider the cut for possible addition to the set of new cuts
+ pCut = Fpga_CutTableConsider( p, pTable, ppNodes, nNodes );
+ if ( pCut == NULL )
+ continue;
+ // add data to the cut
+ pCut->pOne = Fpga_CutNotCond( pTemp1, fComp1 );
+ pCut->pTwo = Fpga_CutNotCond( pTemp2, fComp2 );
+ // create the signature
+ pCut->uSign = pTemp1->uSign | pTemp2->uSign;
+ // add it to the corresponding list
+ pCut->pNext = pLists[pCut->nLeaves];
+ pLists[pCut->nLeaves] = pCut;
+ // count this cut and quit if limit is reached
+ Counter++;
+ if ( Counter == FPGA_CUTS_MAX_COMPUTE )
+ goto QUITS;
+ }
+ }
+ // consider the rest of them
+ for ( i = nCuts1; i < nCuts2; i++ )
+ for ( k = 0; k < nCuts1; k++ )
+ {
+ pTemp1 = ppArray1[k];
+ pTemp2 = ppArray2[i];
+
+ if ( pTemp1->nLeaves == p->nVarsMax && pTemp2->nLeaves == p->nVarsMax )
+ {
+ if ( pTemp1->ppLeaves[0] != pTemp2->ppLeaves[0] )
+ continue;
+ if ( pTemp1->ppLeaves[1] != pTemp2->ppLeaves[1] )
+ continue;
+ if ( pTemp1->ppLeaves[2] != pTemp2->ppLeaves[2] )
+ continue;
+ }
+
+
+ // check if k-feasible cut exists
+ nNodes = Fpga_CutMergeTwo( pTemp1, pTemp2, ppNodes, p->nVarsMax );
+ if ( nNodes == 0 )
+ continue;
+ // consider the cut for possible addition to the set of new cuts
+ pCut = Fpga_CutTableConsider( p, pTable, ppNodes, nNodes );
+ if ( pCut == NULL )
+ continue;
+ // add data to the cut
+ pCut->pOne = Fpga_CutNotCond( pTemp1, fComp1 );
+ pCut->pTwo = Fpga_CutNotCond( pTemp2, fComp2 );
+ // create the signature
+ pCut->uSign = pTemp1->uSign | pTemp2->uSign;
+ // add it to the corresponding list
+ pCut->pNext = pLists[pCut->nLeaves];
+ pLists[pCut->nLeaves] = pCut;
+ // count this cut and quit if limit is reached
+ Counter++;
+ if ( Counter == FPGA_CUTS_MAX_COMPUTE )
+ goto QUITS;
+ }
+QUITS :
+ // combine all the lists into one
+ pListNew = NULL;
+ ppListNew = &pListNew;
+ for ( i = 1; i <= p->nVarsMax; i++ )
+ {
+ if ( pLists[i] == NULL )
+ continue;
+ // find the last entry
+ for ( pPrev = pLists[i], pCut = pPrev->pNext; pCut;
+ pPrev = pCut, pCut = pCut->pNext );
+ // connect these lists
+ *ppListNew = pLists[i];
+ ppListNew = &pPrev->pNext;
+ }
+ *ppListNew = NULL;
+ // sort the cuts by arrival times and use only the first FPGA_CUTS_MAX_USE
+ pListNew = Fpga_CutSortCuts( p, pTable, pListNew );
+ return pListNew;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Merges two lists of cuts.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_Cut_t * Fpga_CutMergeLists2( Fpga_Man_t * p, Fpga_CutTable_t * pTable,
+ Fpga_Cut_t * pList1, Fpga_Cut_t * pList2, int fComp1, int fComp2, int fPivot1, int fPivot2 )
+{
+ Fpga_Node_t * ppNodes[6];
+ Fpga_Cut_t * pListNew, ** ppListNew, * pLists[7] = { NULL };
+ Fpga_Cut_t * pCut, * pPrev, * pTemp1, * pTemp2;
+ int nNodes, Counter, i;
+
+ // prepare the manager for the cut computation
+ Fpga_CutTableRestart( pTable );
+ // go through the cut pairs
+ Counter = 0;
+ for ( pTemp1 = pList1; pTemp1; pTemp1 = fPivot1? NULL: pTemp1->pNext )
+ for ( pTemp2 = pList2; pTemp2; pTemp2 = fPivot2? NULL: pTemp2->pNext )
+ {
+ // check if k-feasible cut exists
+ nNodes = Fpga_CutMergeTwo( pTemp1, pTemp2, ppNodes, p->nVarsMax );
+ if ( nNodes == 0 )
+ continue;
+ // consider the cut for possible addition to the set of new cuts
+ pCut = Fpga_CutTableConsider( p, pTable, ppNodes, nNodes );
+ if ( pCut == NULL )
+ continue;
+ // add data to the cut
+ pCut->pOne = Fpga_CutNotCond( pTemp1, fComp1 );
+ pCut->pTwo = Fpga_CutNotCond( pTemp2, fComp2 );
+ // add it to the corresponding list
+ pCut->pNext = pLists[pCut->nLeaves];
+ pLists[pCut->nLeaves] = pCut;
+ // count this cut and quit if limit is reached
+ Counter++;
+ if ( Counter == FPGA_CUTS_MAX_COMPUTE )
+ goto QUITS;
+ }
+QUITS :
+ // combine all the lists into one
+ pListNew = NULL;
+ ppListNew = &pListNew;
+ for ( i = 1; i <= p->nVarsMax; i++ )
+ {
+ if ( pLists[i] == NULL )
+ continue;
+ // find the last entry
+ for ( pPrev = pLists[i], pCut = pPrev->pNext; pCut;
+ pPrev = pCut, pCut = pCut->pNext );
+ // connect these lists
+ *ppListNew = pLists[i];
+ ppListNew = &pPrev->pNext;
+ }
+ *ppListNew = NULL;
+ // sort the cuts by arrival times and use only the first FPGA_CUTS_MAX_USE
+ pListNew = Fpga_CutSortCuts( p, pTable, pListNew );
+ return pListNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Merges two cuts.]
+
+ Description [Returns the number of nodes in the resulting cut, or 0 if the
+ cut is infeasible. Returns the resulting nodes in the array ppNodes[].]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_CutMergeTwo( Fpga_Cut_t * pCut1, Fpga_Cut_t * pCut2, Fpga_Node_t * ppNodes[], int nNodesMax )
+{
+ Fpga_Node_t * pNodeTemp;
+ int nTotal, i, k, min, Counter;
+ unsigned uSign;
+
+ // use quick prefiltering
+ uSign = pCut1->uSign | pCut2->uSign;
+ Counter = FPGA_COUNT_ONES(uSign);
+ if ( Counter > nNodesMax )
+ return 0;
+/*
+ // check the special case when at least of the cuts is the largest
+ if ( pCut1->nLeaves == nNodesMax )
+ {
+ if ( pCut2->nLeaves == nNodesMax )
+ {
+ // return 0 if the cuts are different
+ for ( i = 0; i < nNodesMax; i++ )
+ if ( pCut1->ppLeaves[i] != pCut2->ppLeaves[i] )
+ return 0;
+ // return nNodesMax if they are the same
+ for ( i = 0; i < nNodesMax; i++ )
+ ppNodes[i] = pCut1->ppLeaves[i];
+ return nNodesMax;
+ }
+ else if ( pCut2->nLeaves == nNodesMax - 1 )
+ {
+ // return 0 if the cuts are different
+ fMismatch = 0;
+ for ( i = 0; i < nNodesMax; i++ )
+ if ( pCut1->ppLeaves[i] != pCut2->ppLeaves[i - fMismatch] )
+ {
+ if ( fMismatch == 1 )
+ return 0;
+ fMismatch = 1;
+ }
+ // return nNodesMax if they are the same
+ for ( i = 0; i < nNodesMax; i++ )
+ ppNodes[i] = pCut1->ppLeaves[i];
+ return nNodesMax;
+ }
+ }
+ else if ( pCut1->nLeaves == nNodesMax - 1 && pCut2->nLeaves == nNodesMax )
+ {
+ // return 0 if the cuts are different
+ fMismatch = 0;
+ for ( i = 0; i < nNodesMax; i++ )
+ if ( pCut1->ppLeaves[i - fMismatch] != pCut2->ppLeaves[i] )
+ {
+ if ( fMismatch == 1 )
+ return 0;
+ fMismatch = 1;
+ }
+ // return nNodesMax if they are the same
+ for ( i = 0; i < nNodesMax; i++ )
+ ppNodes[i] = pCut2->ppLeaves[i];
+ return nNodesMax;
+ }
+*/
+ // count the number of unique entries in pCut2
+ nTotal = pCut1->nLeaves;
+ for ( i = 0; i < pCut2->nLeaves; i++ )
+ {
+ // try to find this entry among the leaves of pCut1
+ for ( k = 0; k < pCut1->nLeaves; k++ )
+ if ( pCut2->ppLeaves[i] == pCut1->ppLeaves[k] )
+ break;
+ if ( k < pCut1->nLeaves ) // found
+ continue;
+ // we found a new entry to add
+ if ( nTotal == nNodesMax )
+ return 0;
+ ppNodes[nTotal++] = pCut2->ppLeaves[i];
+ }
+ // we know that the feasible cut exists
+
+ // add the starting entries
+ for ( k = 0; k < pCut1->nLeaves; k++ )
+ ppNodes[k] = pCut1->ppLeaves[k];
+
+ // selection-sort the entries
+ for ( i = 0; i < nTotal - 1; i++ )
+ {
+ min = i;
+ for ( k = i+1; k < nTotal; k++ )
+ if ( ppNodes[k] < ppNodes[min] )
+ min = k;
+ pNodeTemp = ppNodes[i];
+ ppNodes[i] = ppNodes[min];
+ ppNodes[min] = pNodeTemp;
+ }
+
+ return nTotal;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the union of the two lists of cuts.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_Cut_t * Fpga_CutUnionLists( Fpga_Cut_t * pList1, Fpga_Cut_t * pList2 )
+{
+ Fpga_Cut_t * pTemp, * pRoot;
+ // find the last cut in the first list
+ pRoot = pList1;
+ Fpga_ListForEachCut( pList1, pTemp )
+ pRoot = pTemp;
+ // attach the non-trival part of the second cut to the end of the first
+ assert( pRoot->pNext == NULL );
+ pRoot->pNext = pList2->pNext;
+ pList2->pNext = NULL;
+ return pList1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Checks whether the given cut belongs to the list.]
+
+ Description [This procedure takes most of the runtime in the cut
+ computation.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_CutBelongsToList( Fpga_Cut_t * pList, Fpga_Node_t * ppNodes[], int nNodes )
+{
+ Fpga_Cut_t * pTemp;
+ int i;
+ for ( pTemp = pList; pTemp; pTemp = pTemp->pNext )
+ {
+ for ( i = 0; i < nNodes; i++ )
+ if ( pTemp->ppLeaves[i] != ppNodes[i] )
+ break;
+ if ( i == nNodes )
+ return 1;
+ }
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Counts all the cuts.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_CutCountAll( Fpga_Man_t * pMan )
+{
+ Fpga_Node_t * pNode;
+ Fpga_Cut_t * pCut;
+ int i, nCuts;
+ // go through all the nodes in the unique table of the manager
+ nCuts = 0;
+ for ( i = 0; i < pMan->nBins; i++ )
+ for ( pNode = pMan->pBins[i]; pNode; pNode = pNode->pNext )
+ for ( pCut = pNode->pCuts; pCut; pCut = pCut->pNext )
+ if ( pCut->nLeaves > 1 ) // skip the elementary cuts
+ nCuts++;
+ return nCuts;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Clean the signatures.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_CutsCleanSign( Fpga_Man_t * pMan )
+{
+ Fpga_Node_t * pNode;
+ Fpga_Cut_t * pCut;
+ int i;
+ for ( i = 0; i < pMan->nBins; i++ )
+ for ( pNode = pMan->pBins[i]; pNode; pNode = pNode->pNext )
+ for ( pCut = pNode->pCuts; pCut; pCut = pCut->pNext )
+ pCut->uSign = 0;
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Prints the cuts in the list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_CutListPrint( Fpga_Man_t * pMan, Fpga_Node_t * pRoot )
+{
+ Fpga_Cut_t * pTemp;
+ int Counter;
+ for ( Counter = 0, pTemp = pRoot->pCuts; pTemp; pTemp = pTemp->pNext, Counter++ )
+ {
+ printf( "%2d : ", Counter + 1 );
+ Fpga_CutPrint_( pMan, pTemp, pRoot );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the cuts in the list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_CutListPrint2( Fpga_Man_t * pMan, Fpga_Node_t * pRoot )
+{
+ Fpga_Cut_t * pTemp;
+ int Counter;
+ for ( Counter = 0, pTemp = pRoot->pCuts; pTemp; pTemp = pTemp->pNext, Counter++ )
+ {
+ printf( "%2d : ", Counter + 1 );
+ Fpga_CutPrint_( pMan, pTemp, pRoot );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_CutPrint_( Fpga_Man_t * pMan, Fpga_Cut_t * pCut, Fpga_Node_t * pRoot )
+{
+ int i;
+ printf( "(%3d) {", pRoot->Num );
+ for ( i = 0; i < pMan->nVarsMax; i++ )
+ if ( pCut->ppLeaves[i] )
+ printf( " %3d", pCut->ppLeaves[i]->Num );
+ printf( " }\n" );
+}
+
+
+
+
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Starts the hash table to canonicize cuts.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_CutTable_t * Fpga_CutTableStart( Fpga_Man_t * pMan )
+{
+ Fpga_CutTable_t * p;
+ // allocate the table
+ p = ALLOC( Fpga_CutTable_t, 1 );
+ memset( p, 0, sizeof(Fpga_CutTable_t) );
+ p->nBins = Cudd_Prime( 10 * FPGA_CUTS_MAX_COMPUTE );
+ p->pBins = ALLOC( Fpga_Cut_t *, p->nBins );
+ memset( p->pBins, 0, sizeof(Fpga_Cut_t *) * p->nBins );
+ p->pCuts = ALLOC( int, 2 * FPGA_CUTS_MAX_COMPUTE );
+ p->pArray = ALLOC( Fpga_Cut_t *, 2 * FPGA_CUTS_MAX_COMPUTE );
+ p->pCuts1 = ALLOC( Fpga_Cut_t *, 2 * FPGA_CUTS_MAX_COMPUTE );
+ p->pCuts2 = ALLOC( Fpga_Cut_t *, 2 * FPGA_CUTS_MAX_COMPUTE );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Stops the hash table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_CutTableStop( Fpga_CutTable_t * p )
+{
+ free( p->pCuts1 );
+ free( p->pCuts2 );
+ free( p->pArray );
+ free( p->pBins );
+ free( p->pCuts );
+ free( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the hash value of the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+unsigned Fpga_CutTableHash( Fpga_Node_t * ppNodes[], int nNodes )
+{
+ unsigned uRes;
+ int i;
+ uRes = 0;
+ for ( i = 0; i < nNodes; i++ )
+ uRes += s_HashPrimes[i] * ppNodes[i]->Num;
+ return uRes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Looks up the table for the available cut.]
+
+ Description [Returns -1 if the same cut is found. Returns the index
+ of the cell where the cut should be added, if it does not exist.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_CutTableLookup( Fpga_CutTable_t * p, Fpga_Node_t * ppNodes[], int nNodes )
+{
+ Fpga_Cut_t * pCut;
+ unsigned Key;
+ int b, i;
+
+ Key = Fpga_CutTableHash(ppNodes, nNodes) % p->nBins;
+ for ( b = Key; p->pBins[b]; b = (b+1) % p->nBins )
+ {
+ pCut = p->pBins[b];
+ if ( pCut->nLeaves != nNodes )
+ continue;
+ for ( i = 0; i < nNodes; i++ )
+ if ( pCut->ppLeaves[i] != ppNodes[i] )
+ break;
+ if ( i == nNodes )
+ return -1;
+ }
+ return b;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Starts the hash table to canonicize cuts.]
+
+ Description [Considers addition of the cut to the hash table.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_Cut_t * Fpga_CutTableConsider( Fpga_Man_t * pMan, Fpga_CutTable_t * p, Fpga_Node_t * ppNodes[], int nNodes )
+{
+ Fpga_Cut_t * pCut;
+ int Place, i;
+ // check the cut
+ Place = Fpga_CutTableLookup( p, ppNodes, nNodes );
+ if ( Place == -1 )
+ return NULL;
+ assert( nNodes > 0 );
+ // create the new cut
+ pCut = Fpga_CutAlloc( pMan );
+ pCut->nLeaves = nNodes;
+ pCut->fLevel = 0.0;
+ for ( i = 0; i < nNodes; i++ )
+ {
+ pCut->ppLeaves[i] = ppNodes[i];
+ pCut->fLevel += ppNodes[i]->Level;
+ }
+ pCut->fLevel /= nNodes;
+ // add the cut to the table
+ assert( p->pBins[Place] == NULL );
+ p->pBins[Place] = pCut;
+ // add the cut to the new list
+ p->pCuts[ p->nCuts++ ] = Place;
+ return pCut;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prepares the table to be used with other cuts.]
+
+ Description [Restarts the table by cleaning the info about cuts stored
+ when the previous node was considered.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_CutTableRestart( Fpga_CutTable_t * p )
+{
+ int i;
+ for ( i = 0; i < p->nCuts; i++ )
+ {
+ assert( p->pBins[ p->pCuts[i] ] );
+ p->pBins[ p->pCuts[i] ] = NULL;
+ }
+ p->nCuts = 0;
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Compares the cuts by the number of leaves and then by delay.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_CutSortCutsCompare( Fpga_Cut_t ** pC1, Fpga_Cut_t ** pC2 )
+{
+ if ( (*pC1)->nLeaves < (*pC2)->nLeaves )
+ return -1;
+ if ( (*pC1)->nLeaves > (*pC2)->nLeaves )
+ return 1;
+/*
+ if ( (*pC1)->fLevel > (*pC2)->fLevel )
+ return -1;
+ if ( (*pC1)->fLevel < (*pC2)->fLevel )
+ return 1;
+*/
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sorts the cuts by average arrival time.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_Cut_t * Fpga_CutSortCuts( Fpga_Man_t * pMan, Fpga_CutTable_t * p, Fpga_Cut_t * pList )
+{
+ Fpga_Cut_t * pListNew;
+ int nCuts, i;
+ // move the cuts from the list into the array
+ nCuts = Fpga_CutList2Array( p->pCuts1, pList );
+ assert( nCuts <= FPGA_CUTS_MAX_COMPUTE );
+ // sort the cuts
+ qsort( (void *)p->pCuts1, nCuts, sizeof(Fpga_Cut_t *),
+ (int (*)(const void *, const void *)) Fpga_CutSortCutsCompare );
+ // move them back into the list
+ if ( nCuts > FPGA_CUTS_MAX_USE - 1 )
+ {
+// printf( "*" );
+ // free the remaining cuts
+ for ( i = FPGA_CUTS_MAX_USE - 1; i < nCuts; i++ )
+ Extra_MmFixedEntryRecycle( pMan->mmCuts, (char *)p->pCuts1[i] );
+ // update the number of cuts
+ nCuts = FPGA_CUTS_MAX_USE - 1;
+ }
+ pListNew = Fpga_CutArray2List( p->pCuts1, nCuts );
+ return pListNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Moves the nodes from the list into the array.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_CutList2Array( Fpga_Cut_t ** pArray, Fpga_Cut_t * pList )
+{
+ int i;
+ for ( i = 0; pList; pList = pList->pNext, i++ )
+ pArray[i] = pList;
+ return i;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Moves the nodes from the array into the list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_Cut_t * Fpga_CutArray2List( Fpga_Cut_t ** pArray, int nCuts )
+{
+ Fpga_Cut_t * pListNew, ** ppListNew;
+ int i;
+ pListNew = NULL;
+ ppListNew = &pListNew;
+ for ( i = 0; i < nCuts; i++ )
+ {
+ // connect these lists
+ *ppListNew = pArray[i];
+ ppListNew = &pArray[i]->pNext;
+//printf( " %d(%.2f)", pArray[i]->nLeaves, pArray[i]->fLevel );
+ }
+//printf( "\n" );
+
+ *ppListNew = NULL;
+ return pListNew;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/map/fpga/fpgaCutUtils.c b/src/map/fpga/fpgaCutUtils.c
new file mode 100644
index 00000000..abe703a2
--- /dev/null
+++ b/src/map/fpga/fpgaCutUtils.c
@@ -0,0 +1,571 @@
+/**CFile****************************************************************
+
+ FileName [fpgaCutUtils.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Generic technology mapping engine.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - August 18, 2004.]
+
+ Revision [$Id: fpgaCutUtils.h,v 1.0 2003/09/08 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "fpgaInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Allocates the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_Cut_t * Fpga_CutAlloc( Fpga_Man_t * p )
+{
+ Fpga_Cut_t * pCut;
+ pCut = (Fpga_Cut_t *)Extra_MmFixedEntryFetch( p->mmCuts );
+ memset( pCut, 0, sizeof(Fpga_Cut_t) );
+ return pCut;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Duplicates the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_Cut_t * Fpga_CutDup( Fpga_Man_t * p, Fpga_Cut_t * pCutOld )
+{
+ Fpga_Cut_t * pCutNew;
+ int i;
+ pCutNew = Fpga_CutAlloc( p );
+ pCutNew->pRoot = pCutOld->pRoot;
+ pCutNew->nLeaves = pCutOld->nLeaves;
+ for ( i = 0; i < pCutOld->nLeaves; i++ )
+ pCutNew->ppLeaves[i] = pCutOld->ppLeaves[i];
+ return pCutNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Deallocates the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_CutFree( Fpga_Man_t * p, Fpga_Cut_t * pCut )
+{
+ if ( pCut )
+ Extra_MmFixedEntryRecycle( p->mmCuts, (char *)pCut );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_CutPrint( Fpga_Man_t * p, Fpga_Node_t * pRoot, Fpga_Cut_t * pCut )
+{
+ int i;
+ printf( "CUT: Delay = %4.2f. Area = %4.2f. Nodes = %d -> {",
+ pCut->tArrival, pCut->aFlow, pRoot->Num );
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ printf( " %d", pCut->ppLeaves[i]->Num );
+ printf( " } \n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_Cut_t * Fpga_CutCreateSimple( Fpga_Man_t * p, Fpga_Node_t * pNode )
+{
+ Fpga_Cut_t * pCut;
+ pCut = Fpga_CutAlloc( p );
+ pCut->pRoot = pNode;
+ pCut->nLeaves = 1;
+ pCut->ppLeaves[0] = pNode;
+ pCut->uSign = FPGA_SEQ_SIGN(pCut->ppLeaves[0]);
+ return pCut;
+}
+
+
+/**function*************************************************************
+
+ synopsis [Computes the exact area associated with the cut.]
+
+ description []
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+float Fpga_CutGetRootArea( Fpga_Man_t * p, Fpga_Cut_t * pCut )
+{
+ return p->pLutLib->pLutAreas[pCut->nLeaves];
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_Cut_t * Fpga_CutListAppend( Fpga_Cut_t * pSetAll, Fpga_Cut_t * pSets )
+{
+ Fpga_Cut_t * pPrev, * pTemp;
+ if ( pSetAll == NULL )
+ return pSets;
+ if ( pSets == NULL )
+ return pSetAll;
+ // find the last one
+ for ( pTemp = pSets; pTemp; pTemp = pTemp->pNext )
+ pPrev = pTemp;
+ // append all the end of the current set
+ assert( pPrev->pNext == NULL );
+ pPrev->pNext = pSetAll;
+ return pSets;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_CutListRecycle( Fpga_Man_t * p, Fpga_Cut_t * pSetList, Fpga_Cut_t * pSave )
+{
+ Fpga_Cut_t * pNext, * pTemp;
+ for ( pTemp = pSetList, pNext = pTemp? pTemp->pNext : NULL;
+ pTemp;
+ pTemp = pNext, pNext = pNext? pNext->pNext : NULL )
+ if ( pTemp != pSave )
+ Extra_MmFixedEntryRecycle( p->mmCuts, (char *)pTemp );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_CutListCount( Fpga_Cut_t * pSets )
+{
+ Fpga_Cut_t * pTemp;
+ int i;
+ for ( i = 0, pTemp = pSets; pTemp; pTemp = pTemp->pNext, i++ );
+ return i;
+}
+
+#if 0
+
+/**function*************************************************************
+
+ synopsis [Removes the fanouts of the cut.]
+
+ description []
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+void Fpga_CutRemoveFanouts( Fpga_Man_t * p, Fpga_Node_t * pNode, Fpga_Cut_t * pCut )
+{
+ Fpga_NodeVec_t * vFanouts;
+ int i, k;
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ {
+ vFanouts = pCut->ppLeaves[i]->vFanouts;
+ for ( k = 0; k < vFanouts->nSize; k++ )
+ if ( vFanouts->pArray[k] == pNode )
+ break;
+ assert( k != vFanouts->nSize );
+ for ( k++; k < vFanouts->nSize; k++ )
+ vFanouts->pArray[k-1] = vFanouts->pArray[k];
+ vFanouts->nSize--;
+ }
+}
+
+/**function*************************************************************
+
+ synopsis [Removes the fanouts of the cut.]
+
+ description []
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+void Fpga_CutInsertFanouts( Fpga_Man_t * p, Fpga_Node_t * pNode, Fpga_Cut_t * pCut )
+{
+ int i;
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ Fpga_NodeVecPush( pCut->ppLeaves[i]->vFanouts, pNode );
+}
+#endif
+
+/**Function*************************************************************
+
+ Synopsis [Computes the arrival time and the area flow of the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_CutGetParameters( Fpga_Man_t * pMan, Fpga_Cut_t * pCut )
+{
+ Fpga_Cut_t * pFaninCut;
+ int i;
+ pCut->tArrival = -FPGA_FLOAT_LARGE;
+ pCut->aFlow = pMan->pLutLib->pLutAreas[pCut->nLeaves];
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ {
+ pFaninCut = pCut->ppLeaves[i]->pCutBest;
+ if ( pCut->tArrival < pFaninCut->tArrival )
+ pCut->tArrival = pFaninCut->tArrival;
+ // if the fanout count is not set, assume it to be 1
+ if ( pCut->ppLeaves[i]->nRefs == 0 )
+ pCut->aFlow += pFaninCut->aFlow;
+ else
+// pCut->aFlow += pFaninCut->aFlow / pCut->ppLeaves[i]->nRefs;
+ pCut->aFlow += pFaninCut->aFlow / pCut->ppLeaves[i]->aEstFanouts;
+ }
+ pCut->tArrival += pMan->pLutLib->pLutDelays[pCut->nLeaves];
+}
+
+
+/**function*************************************************************
+
+ synopsis [Computes the area flow of the cut.]
+
+ description []
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+float Fpga_CutGetAreaFlow( Fpga_Man_t * pMan, Fpga_Cut_t * pCut )
+{
+ Fpga_Cut_t * pCutFanin;
+ int i;
+ pCut->aFlow = pMan->pLutLib->pLutAreas[pCut->nLeaves];
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ {
+ // get the cut implementing this phase of the fanin
+ pCutFanin = pCut->ppLeaves[i]->pCutBest;
+ assert( pCutFanin );
+ pCut->aFlow += pCutFanin->aFlow / pCut->ppLeaves[i]->nRefs;
+ }
+ return pCut->aFlow;
+}
+
+/**function*************************************************************
+
+ synopsis [Computes the exact area associated with the cut.]
+
+ description []
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+float Fpga_CutGetAreaRefed( Fpga_Man_t * pMan, Fpga_Cut_t * pCut )
+{
+ float aResult, aResult2;
+ if ( pCut->nLeaves == 1 )
+ return 0;
+ aResult = Fpga_CutDeref( pMan, NULL, pCut, 0 );
+ aResult2 = Fpga_CutRef( pMan, NULL, pCut, 0 );
+ assert( aResult == aResult2 );
+ return aResult;
+}
+
+/**function*************************************************************
+
+ synopsis [Computes the exact area associated with the cut.]
+
+ description []
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+float Fpga_CutGetAreaDerefed( Fpga_Man_t * pMan, Fpga_Cut_t * pCut )
+{
+ float aResult, aResult2;
+ if ( pCut->nLeaves == 1 )
+ return 0;
+ aResult2 = Fpga_CutRef( pMan, NULL, pCut, 0 );
+ aResult = Fpga_CutDeref( pMan, NULL, pCut, 0 );
+ assert( aResult == aResult2 );
+ return aResult;
+}
+
+/**function*************************************************************
+
+ synopsis [References the cut.]
+
+ description [This procedure is similar to the procedure NodeReclaim.]
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+float Fpga_CutRef( Fpga_Man_t * pMan, Fpga_Node_t * pNode, Fpga_Cut_t * pCut, int fFanouts )
+{
+ Fpga_Node_t * pNodeChild;
+ float aArea;
+ int i;
+
+ // deref the fanouts
+// if ( fFanouts )
+// Fpga_CutInsertFanouts( pMan, pNode, pCut );
+
+ // start the area of this cut
+ aArea = pMan->pLutLib->pLutAreas[pCut->nLeaves];
+ // go through the children
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ {
+ pNodeChild = pCut->ppLeaves[i];
+ assert( pNodeChild->nRefs >= 0 );
+ if ( pNodeChild->nRefs++ > 0 )
+ continue;
+ if ( !Fpga_NodeIsAnd(pNodeChild) )
+ continue;
+ aArea += Fpga_CutRef( pMan, pNodeChild, pNodeChild->pCutBest, fFanouts );
+ }
+ return aArea;
+}
+
+/**function*************************************************************
+
+ synopsis [Dereferences the cut.]
+
+ description [This procedure is similar to the procedure NodeRecusiveDeref.]
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+float Fpga_CutDeref( Fpga_Man_t * pMan, Fpga_Node_t * pNode, Fpga_Cut_t * pCut, int fFanouts )
+{
+ Fpga_Node_t * pNodeChild;
+ float aArea;
+ int i;
+
+ // deref the fanouts
+// if ( fFanouts )
+// Fpga_CutRemoveFanouts( pMan, pNode, pCut );
+
+ // start the area of this cut
+ aArea = pMan->pLutLib->pLutAreas[pCut->nLeaves];
+ // go through the children
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ {
+ pNodeChild = pCut->ppLeaves[i];
+ assert( pNodeChild->nRefs > 0 );
+ if ( --pNodeChild->nRefs > 0 )
+ continue;
+ if ( !Fpga_NodeIsAnd(pNodeChild) )
+ continue;
+ aArea += Fpga_CutDeref( pMan, pNodeChild, pNodeChild->pCutBest, fFanouts );
+ }
+ return aArea;
+}
+
+
+
+/**function*************************************************************
+
+ synopsis [Computes the exact area associated with the cut.]
+
+ description []
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+float Fpga_CutGetSwitchDerefed( Fpga_Man_t * pMan, Fpga_Node_t * pNode, Fpga_Cut_t * pCut )
+{
+ float aResult, aResult2;
+ if ( pCut->nLeaves == 1 )
+ return 0;
+ aResult2 = Fpga_CutRefSwitch( pMan, pNode, pCut, 0 );
+ aResult = Fpga_CutDerefSwitch( pMan, pNode, pCut, 0 );
+// assert( aResult == aResult2 );
+ return aResult;
+}
+
+/**function*************************************************************
+
+ synopsis [References the cut.]
+
+ description [This procedure is similar to the procedure NodeReclaim.]
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+float Fpga_CutRefSwitch( Fpga_Man_t * pMan, Fpga_Node_t * pNode, Fpga_Cut_t * pCut, int fFanouts )
+{
+ Fpga_Node_t * pNodeChild;
+ float aArea;
+ int i;
+
+ // deref the fanouts
+// if ( fFanouts )
+// Fpga_CutInsertFanouts( pMan, pNode, pCut );
+
+ // start the area of this cut
+ aArea = pNode->SwitchProb;
+ // go through the children
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ {
+ pNodeChild = pCut->ppLeaves[i];
+ assert( pNodeChild->nRefs >= 0 );
+ if ( pNodeChild->nRefs++ > 0 )
+ continue;
+ if ( !Fpga_NodeIsAnd(pNodeChild) )
+ {
+ aArea += pNodeChild->SwitchProb;
+ continue;
+ }
+ aArea += Fpga_CutRefSwitch( pMan, pNodeChild, pNodeChild->pCutBest, fFanouts );
+ }
+ return aArea;
+}
+
+/**function*************************************************************
+
+ synopsis [Dereferences the cut.]
+
+ description [This procedure is similar to the procedure NodeRecusiveDeref.]
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+float Fpga_CutDerefSwitch( Fpga_Man_t * pMan, Fpga_Node_t * pNode, Fpga_Cut_t * pCut, int fFanouts )
+{
+ Fpga_Node_t * pNodeChild;
+ float aArea;
+ int i;
+
+ // deref the fanouts
+// if ( fFanouts )
+// Fpga_CutRemoveFanouts( pMan, pNode, pCut );
+
+ // start the area of this cut
+ aArea = pNode->SwitchProb;
+ // go through the children
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ {
+ pNodeChild = pCut->ppLeaves[i];
+ assert( pNodeChild->nRefs > 0 );
+ if ( --pNodeChild->nRefs > 0 )
+ continue;
+ if ( !Fpga_NodeIsAnd(pNodeChild) )
+ {
+ aArea += pNodeChild->SwitchProb;
+ continue;
+ }
+ aArea += Fpga_CutDerefSwitch( pMan, pNodeChild, pNodeChild->pCutBest, fFanouts );
+ }
+ return aArea;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the used cuts to be the currently selected ones.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappingSetUsedCuts( Fpga_Man_t * pMan )
+{
+ int i;
+ for ( i = 0; i < pMan->vNodesAll->nSize; i++ )
+ if ( pMan->vNodesAll->pArray[i]->pCutOld )
+ {
+ pMan->vNodesAll->pArray[i]->pCutBest = pMan->vNodesAll->pArray[i]->pCutOld;
+ pMan->vNodesAll->pArray[i]->pCutOld = NULL;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/fpga/fpgaFanout.c b/src/map/fpga/fpgaFanout.c
new file mode 100644
index 00000000..50809f65
--- /dev/null
+++ b/src/map/fpga/fpgaFanout.c
@@ -0,0 +1,139 @@
+/**CFile****************************************************************
+
+ FileName [fpgaFanout.c]
+
+ PackageName [FRAIG: Functionally reduced AND-INV graphs.]
+
+ Synopsis [Procedures to manipulate fanouts of the FRAIG nodes.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - August 18, 2004.]
+
+ Revision [$Id: fpgaFanout.c,v 1.1 2005/01/23 06:59:41 alanmi Exp $]
+
+***********************************************************************/
+
+#include "fpgaInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+
+/**Function*************************************************************
+
+ Synopsis [Add the fanout to the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_NodeAddFaninFanout( Fpga_Node_t * pFanin, Fpga_Node_t * pFanout )
+{
+ Fpga_Node_t * pPivot;
+
+ // pFanins is a fanin of pFanout
+ assert( !Fpga_IsComplement(pFanin) );
+ assert( !Fpga_IsComplement(pFanout) );
+ assert( Fpga_Regular(pFanout->p1) == pFanin || Fpga_Regular(pFanout->p2) == pFanin );
+
+ pPivot = pFanin->pFanPivot;
+ if ( pPivot == NULL )
+ {
+ pFanin->pFanPivot = pFanout;
+ return;
+ }
+
+ if ( Fpga_Regular(pPivot->p1) == pFanin )
+ {
+ if ( Fpga_Regular(pFanout->p1) == pFanin )
+ {
+ pFanout->pFanFanin1 = pPivot->pFanFanin1;
+ pPivot->pFanFanin1 = pFanout;
+ }
+ else // if ( Fpga_Regular(pFanout->p2) == pFanin )
+ {
+ pFanout->pFanFanin2 = pPivot->pFanFanin1;
+ pPivot->pFanFanin1 = pFanout;
+ }
+ }
+ else // if ( Fpga_Regular(pPivot->p2) == pFanin )
+ {
+ assert( Fpga_Regular(pPivot->p2) == pFanin );
+ if ( Fpga_Regular(pFanout->p1) == pFanin )
+ {
+ pFanout->pFanFanin1 = pPivot->pFanFanin2;
+ pPivot->pFanFanin2 = pFanout;
+ }
+ else // if ( Fpga_Regular(pFanout->p2) == pFanin )
+ {
+ pFanout->pFanFanin2 = pPivot->pFanFanin2;
+ pPivot->pFanFanin2 = pFanout;
+ }
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Add the fanout to the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_NodeRemoveFaninFanout( Fpga_Node_t * pFanin, Fpga_Node_t * pFanoutToRemove )
+{
+ Fpga_Node_t * pFanout, * pFanout2, ** ppFanList;
+ // start the linked list of fanouts
+ ppFanList = &pFanin->pFanPivot;
+ // go through the fanouts
+ Fpga_NodeForEachFanoutSafe( pFanin, pFanout, pFanout2 )
+ {
+ // skip the fanout-to-remove
+ if ( pFanout == pFanoutToRemove )
+ continue;
+ // add useful fanouts to the list
+ *ppFanList = pFanout;
+ ppFanList = Fpga_NodeReadNextFanoutPlace( pFanin, pFanout );
+ }
+ *ppFanList = NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the number of fanouts of a node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_NodeGetFanoutNum( Fpga_Node_t * pNode )
+{
+ Fpga_Node_t * pFanout;
+ int Counter = 0;
+ Fpga_NodeForEachFanout( pNode, pFanout )
+ Counter++;
+ return Counter;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/fpga/fpgaGENERIC.c b/src/map/fpga/fpgaGENERIC.c
new file mode 100644
index 00000000..f272c1b8
--- /dev/null
+++ b/src/map/fpga/fpgaGENERIC.c
@@ -0,0 +1,46 @@
+/**CFile****************************************************************
+
+ FileName [fpga__.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Generic technology mapping engine.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - September 8, 2003.]
+
+ Revision [$Id: fpga__.h,v 1.0 2003/09/08 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "fpgaInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/fpga/fpgaInt.h b/src/map/fpga/fpgaInt.h
new file mode 100644
index 00000000..0fea9ec8
--- /dev/null
+++ b/src/map/fpga/fpgaInt.h
@@ -0,0 +1,395 @@
+/**CFile****************************************************************
+
+ FileName [fpgaInt.h]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Technology mapping for variable-size-LUT FPGAs.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - August 18, 2004.]
+
+ Revision [$Id: fpgaInt.h,v 1.8 2004/09/30 21:18:10 satrajit Exp $]
+
+***********************************************************************/
+
+#ifndef __FPGA_INT_H__
+#define __FPGA_INT_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+//#include "leaks.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "extra.h"
+#include "fraig.h"
+#include "fpga.h"
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+#ifdef _WIN32
+#define inline __inline // compatible with MS VS 6.0
+#endif
+
+// the maximum number of cut leaves (currently does not work for 7)
+#define FPGA_MAX_LEAVES 6
+
+// the bit masks
+#define FPGA_MASK(n) ((~((unsigned)0)) >> (32-(n)))
+#define FPGA_FULL (~((unsigned)0))
+#define FPGA_NO_VAR (-9999.0)
+#define FPGA_NUM_BYTES(n) (((n)/16 + (((n)%16) > 0))*16)
+
+// maximum/minimum operators
+#define FPGA_MIN(a,b) (((a) < (b))? (a) : (b))
+#define FPGA_MAX(a,b) (((a) > (b))? (a) : (b))
+
+// the small and large numbers (min/max float are 1.17e-38/3.40e+38)
+#define FPGA_FLOAT_LARGE ((float)1.0e+20)
+#define FPGA_FLOAT_SMALL ((float)1.0e-20)
+#define FPGA_INT_LARGE (10000000)
+
+// the macro to compute the signature
+#define FPGA_SEQ_SIGN(p) (1 << (((unsigned)p)%31));
+
+// internal macros to work with cuts
+#define Fpga_CutIsComplement(p) (((int)((long) (p) & 01)))
+#define Fpga_CutRegular(p) ((Fpga_Cut_t *)((unsigned)(p) & ~01))
+#define Fpga_CutNot(p) ((Fpga_Cut_t *)((long)(p) ^ 01))
+#define Fpga_CutNotCond(p,c) ((Fpga_Cut_t *)((long)(p) ^ (c)))
+
+// the cut nodes
+#define Fpga_SeqIsComplement( p ) (((int)((long) (p) & 01)))
+#define Fpga_SeqRegular( p ) ((Fpga_Node_t *)((unsigned)(p) & ~015))
+#define Fpga_SeqIndex( p ) ((((unsigned)(p)) >> 1) & 07)
+#define Fpga_SeqIndexCreate( p, Ind ) (((unsigned)(p)) | (1 << (((unsigned)(Ind)) & 07)))
+
+// internal macros for referencing of nodes
+#define Fpga_NodeReadRef(p) ((Fpga_Regular(p))->nRefs)
+#define Fpga_NodeRef(p) ((Fpga_Regular(p))->nRefs++)
+
+// returns the complemented attribute of the node
+#define Fpga_NodeIsSimComplement(p) (Fpga_IsComplement(p)? !(Fpga_Regular(p)->fInv) : (p)->fInv)
+
+// generating random unsigned (#define RAND_MAX 0x7fff)
+#define FPGA_RANDOM_UNSIGNED ((((unsigned)rand()) << 24) ^ (((unsigned)rand()) << 12) ^ ((unsigned)rand()))
+
+// outputs the runtime in seconds
+#define PRT(a,t) printf("%s = ", (a)); printf("%6.2f sec\n", (float)(t)/(float)(CLOCKS_PER_SEC))
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// the mapping manager
+struct Fpga_ManStruct_t_
+{
+ // the mapping graph
+ Fpga_Node_t ** pBins; // the table of nodes hashed by their children
+ int nBins; // the size of the table
+ Fpga_Node_t ** pInputs; // the array of inputs
+ int nInputs; // the number of inputs
+ Fpga_Node_t ** pOutputs; // the array of outputs
+ int nOutputs; // the number of outputs
+ int nNodes; // the total number of nodes
+ Fpga_Node_t * pConst1; // the constant 1 node
+ Fpga_NodeVec_t * vAnds; // the array of pointer to nodes by number
+ Fpga_NodeVec_t * vNodesAll; // the array of pointer to nodes by number
+ int nLatches; // the number of latches in the circuit
+
+ // info about the original circuit
+ char * pFileName; // the file name
+ char ** ppOutputNames; // the primary output names
+ float * pInputArrivals;// the PI arrival times
+
+ // mapping parameters
+ int nVarsMax; // the max number of variables
+ int fTree; // the flag to enable tree mapping
+ int fPower; // the flag to enable power optimization
+ int fAreaRecovery; // the flag to use area flow as the first parameter
+ int fVerbose; // the verbosiness flag
+ int fRefCount; // enables reference counting
+ int fSequential; // use sequential mapping
+ int nTravIds;
+
+ // support of choice nodes
+ int nChoiceNodes; // the number of choice nodes
+ int nChoices; // the number of all choices
+
+ int nCanons;
+ int nMatches;
+
+ // the supergate library
+ Fpga_LutLib_t * pLutLib; // the current LUT library
+ unsigned uTruths[6][2]; // the elementary truth tables
+
+ // the memory managers
+ Extra_MmFixed_t * mmNodes; // the memory manager for nodes
+ Extra_MmFixed_t * mmCuts; // the memory manager for cuts
+
+ // simulation info from the FRAIG manager
+ int nSimRounds; // the number of words in the simulation info
+ unsigned ** pSimInfo; // the simulation info for each PI
+
+ // resynthesis parameters
+ int fResynthesis; // the resynthesis flag
+ float fRequiredGlo; // the global required times
+ float fRequiredShift;// the shift of the required times
+ float fRequiredStart;// the starting global required times
+ float fRequiredGain; // the reduction in delay
+ float fAreaGlo; // the total area
+ float fAreaGain; // the reduction in area
+ float fEpsilon; // the epsilon used to compare floats
+ float fDelayWindow; // the delay window for delay-oriented resynthesis
+ float DelayLimit; // for resynthesis
+ float AreaLimit; // for resynthesis
+ float TimeLimit; // for resynthesis
+
+ // runtime statistics
+ int timeToMap; // time to transfer to the mapping structure
+ int timeCuts; // time to compute k-feasible cuts
+ int timeTruth; // time to compute the truth table for each cut
+ int timeMatch; // time to perform matching for each node
+ int timeRecover; // time to perform area recovery
+ int timeToNet; // time to transfer back to the network
+ int timeTotal; // the total mapping time
+ int time1; // time to transfer to the mapping structure
+ int time2; // time to transfer to the mapping structure
+};
+
+// the LUT library
+struct Fpga_LutLibStruct_t_
+{
+ char * pName; // the name of the LUT library
+ int LutMax; // the maximum LUT size
+ float pLutAreas[FPGA_MAX_LUTSIZE+1]; // the areas of LUTs
+ float pLutDelays[FPGA_MAX_LUTSIZE+1];// the delays of LUTs
+};
+
+// the mapping node
+struct Fpga_NodeStruct_t_
+{
+ // general information about the node
+ Fpga_Node_t * pNext; // the next node in the hash table
+ Fpga_Node_t * pLevel; // the next node in the linked list by level
+ int Num; // the unique number of this node
+ int NumA; // the unique number of this node
+ short Num2; // the temporary number of this node
+ short nRefs; // the number of references (fanouts) of the given node
+ unsigned fMark0 : 1; // the mark used for traversals
+ unsigned fMark1 : 1; // the mark used for traversals
+ unsigned fInv : 1; // the complemented attribute for the equivalent nodes
+ unsigned Value : 2; // the value of the nodes
+ unsigned fUsed : 1; // the flag indicating that the node is used in the mapping
+ unsigned fTemp : 1; // unused
+ unsigned Level :11; // the level of the given node
+ unsigned uData :14; // used to mark the fanins, for which resynthesis was tried
+ int TravId;
+
+ // the successors of this node
+ Fpga_Node_t * p1; // the first child
+ Fpga_Node_t * p2; // the second child
+ Fpga_Node_t * pNextE; // the next functionally equivalent node
+ Fpga_Node_t * pRepr; // the representative of the functionally equivalent class
+// Fpga_NodeVec_t * vFanouts; // the array of fanouts of the node
+
+ // representation of node's fanouts
+ Fpga_Node_t * pFanPivot; // the first fanout of this node
+ Fpga_Node_t * pFanFanin1; // the next fanout of p1
+ Fpga_Node_t * pFanFanin2; // the next fanout of p2
+
+ // the delay information
+ float tRequired; // the best area flow
+ float aEstFanouts; // the fanout estimation
+ float SwitchProb; // the probability of switching
+ int LValue; // the l-value of the node
+ short nLatches1; // the number of latches on the first edge
+ short nLatches2; // the number of latches on the second edge
+
+ // cut information
+ Fpga_Cut_t * pCutBest; // the best mapping
+ Fpga_Cut_t * pCutOld; // the old mapping
+ Fpga_Cut_t * pCuts; // mapping choices for the node (elementary comes first)
+ Fpga_Cut_t * pCutsN; // mapping choices for the node (elementary comes first)
+
+ // misc information
+ char * pData0; // temporary storage for the corresponding network node
+};
+
+// the cuts used for matching
+struct Fpga_CutStruct_t_
+{
+ Fpga_Cut_t * pOne; // the father of this cut
+ Fpga_Cut_t * pTwo; // the mother of this cut
+ Fpga_Node_t * pRoot; // the root of the cut
+ Fpga_Node_t * ppLeaves[FPGA_MAX_LEAVES+1]; // the leaves of this cut
+ float fLevel; // the average level of the fanins
+ unsigned uSign; // signature for quick comparison
+ char fMark; // the mark to denote visited cut
+ char Phase; // the mark to denote complemented cut
+ char nLeaves; // the number of leaves of this cut
+ char nVolume; // the volume of this cut
+ float tArrival; // the arrival time
+ float aFlow; // the area flow of the cut
+ Fpga_Cut_t * pNext; // the pointer to the next cut in the list
+};
+
+// the vector of nodes
+struct Fpga_NodeVecStruct_t_
+{
+ Fpga_Node_t ** pArray; // the array of nodes
+ int nSize; // the number of entries in the array
+ int nCap; // the number of allocated entries
+};
+
+// getting hold of the next fanout of the node
+#define Fpga_NodeReadNextFanout( pNode, pFanout ) \
+ ( ( pFanout == NULL )? NULL : \
+ ((Fpga_Regular((pFanout)->p1) == (pNode))? \
+ (pFanout)->pFanFanin1 : (pFanout)->pFanFanin2) )
+
+// getting hold of the place where the next fanout will be attached
+#define Fpga_NodeReadNextFanoutPlace( pNode, pFanout ) \
+ ( (Fpga_Regular((pFanout)->p1) == (pNode))? \
+ &(pFanout)->pFanFanin1 : &(pFanout)->pFanFanin2 )
+
+// iterator through the fanouts of the node
+#define Fpga_NodeForEachFanout( pNode, pFanout ) \
+ for ( pFanout = (pNode)->pFanPivot; pFanout; \
+ pFanout = Fpga_NodeReadNextFanout(pNode, pFanout) )
+
+// safe iterator through the fanouts of the node
+#define Fpga_NodeForEachFanoutSafe( pNode, pFanout, pFanout2 ) \
+ for ( pFanout = (pNode)->pFanPivot, \
+ pFanout2 = Fpga_NodeReadNextFanout(pNode, pFanout); \
+ pFanout; \
+ pFanout = pFanout2, \
+ pFanout2 = Fpga_NodeReadNextFanout(pNode, pFanout) )
+
+////////////////////////////////////////////////////////////////////////
+/// GLOBAL VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== fpgaCut.c ===============================================================*/
+extern void Fpga_MappingCuts( Fpga_Man_t * p );
+extern void Fpga_MappingCreatePiCuts( Fpga_Man_t * p );
+extern int Fpga_CutCountAll( Fpga_Man_t * pMan );
+/*=== fpgaCutUtils.c ===============================================================*/
+extern Fpga_Cut_t * Fpga_CutAlloc( Fpga_Man_t * p );
+extern Fpga_Cut_t * Fpga_CutDup( Fpga_Man_t * p, Fpga_Cut_t * pCutOld );
+extern void Fpga_CutFree( Fpga_Man_t * p, Fpga_Cut_t * pCut );
+extern void Fpga_CutPrint( Fpga_Man_t * p, Fpga_Node_t * pRoot, Fpga_Cut_t * pCut );
+extern Fpga_Cut_t * Fpga_CutCreateSimple( Fpga_Man_t * p, Fpga_Node_t * pNode );
+extern float Fpga_CutGetRootArea( Fpga_Man_t * p, Fpga_Cut_t * pCut );
+extern Fpga_Cut_t * Fpga_CutListAppend( Fpga_Cut_t * pSetAll, Fpga_Cut_t * pSets );
+extern void Fpga_CutListRecycle( Fpga_Man_t * p, Fpga_Cut_t * pSetList, Fpga_Cut_t * pSave );
+extern int Fpga_CutListCount( Fpga_Cut_t * pSets );
+extern void Fpga_CutRemoveFanouts( Fpga_Man_t * p, Fpga_Node_t * pNode, Fpga_Cut_t * pCut );
+extern void Fpga_CutInsertFanouts( Fpga_Man_t * p, Fpga_Node_t * pNode, Fpga_Cut_t * pCut );
+extern float Fpga_CutGetAreaRefed( Fpga_Man_t * pMan, Fpga_Cut_t * pCut );
+extern float Fpga_CutGetAreaDerefed( Fpga_Man_t * pMan, Fpga_Cut_t * pCut );
+extern float Fpga_CutRef( Fpga_Man_t * pMan, Fpga_Node_t * pNode, Fpga_Cut_t * pCut, int fFanouts );
+extern float Fpga_CutDeref( Fpga_Man_t * pMan, Fpga_Node_t * pNode, Fpga_Cut_t * pCut, int fFanouts );
+extern float Fpga_CutGetSwitchDerefed( Fpga_Man_t * pMan, Fpga_Node_t * pNode, Fpga_Cut_t * pCut );
+extern float Fpga_CutRefSwitch( Fpga_Man_t * pMan, Fpga_Node_t * pNode, Fpga_Cut_t * pCut, int fFanouts );
+extern float Fpga_CutDerefSwitch( Fpga_Man_t * pMan, Fpga_Node_t * pNode, Fpga_Cut_t * pCut, int fFanouts );
+extern float Fpga_CutGetAreaFlow( Fpga_Man_t * pMan, Fpga_Cut_t * pCut );
+extern void Fpga_CutGetParameters( Fpga_Man_t * pMan, Fpga_Cut_t * pCut );
+/*=== fraigFanout.c =============================================================*/
+extern void Fpga_NodeAddFaninFanout( Fpga_Node_t * pFanin, Fpga_Node_t * pFanout );
+extern void Fpga_NodeRemoveFaninFanout( Fpga_Node_t * pFanin, Fpga_Node_t * pFanoutToRemove );
+extern int Fpga_NodeGetFanoutNum( Fpga_Node_t * pNode );
+/*=== fpgaLib.c ============================================================*/
+extern Fpga_LutLib_t * Fpga_LutLibCreate( char * FileName, int fVerbose );
+extern void Fpga_LutLibFree( Fpga_LutLib_t * p );
+extern void Fpga_LutLibPrint( Fpga_LutLib_t * pLutLib );
+extern int Fpga_LutLibDelaysAreDiscrete( Fpga_LutLib_t * pLutLib );
+/*=== fpgaMatch.c ===============================================================*/
+extern int Fpga_MappingMatches( Fpga_Man_t * p, int fDelayOriented );
+extern int Fpga_MappingMatchesArea( Fpga_Man_t * p );
+extern int Fpga_MappingMatchesSwitch( Fpga_Man_t * p );
+/*=== fpgaShow.c =============================================================*/
+extern void Fpga_MappingShow( Fpga_Man_t * pMan, char * pFileName );
+extern void Fpga_MappingShowNodes( Fpga_Man_t * pMan, Fpga_Node_t ** ppRoots, int nRoots, char * pFileName );
+/*=== fpgaTime.c ===============================================================*/
+extern float Fpga_TimeCutComputeArrival( Fpga_Man_t * pMan, Fpga_Cut_t * pCut );
+extern float Fpga_TimeCutComputeArrival_rec( Fpga_Man_t * pMan, Fpga_Cut_t * pCut );
+extern float Fpga_TimeComputeArrivalMax( Fpga_Man_t * p );
+extern void Fpga_TimeComputeRequiredGlobal( Fpga_Man_t * p );
+extern void Fpga_TimeComputeRequired( Fpga_Man_t * p, float fRequired );
+extern void Fpga_TimePropagateRequired( Fpga_Man_t * p, Fpga_NodeVec_t * vNodes );
+/*=== fpgaTruth.c ===============================================================*/
+extern void Fpga_MappingTruths( Fpga_Man_t * pMan );
+/*=== fpgaVec.c =============================================================*/
+extern Fpga_NodeVec_t * Fpga_NodeVecAlloc( int nCap );
+extern void Fpga_NodeVecFree( Fpga_NodeVec_t * p );
+extern Fpga_Node_t ** Fpga_NodeVecReadArray( Fpga_NodeVec_t * p );
+extern int Fpga_NodeVecReadSize( Fpga_NodeVec_t * p );
+extern void Fpga_NodeVecGrow( Fpga_NodeVec_t * p, int nCapMin );
+extern void Fpga_NodeVecShrink( Fpga_NodeVec_t * p, int nSizeNew );
+extern void Fpga_NodeVecClear( Fpga_NodeVec_t * p );
+extern void Fpga_NodeVecPush( Fpga_NodeVec_t * p, Fpga_Node_t * Entry );
+extern int Fpga_NodeVecPushUnique( Fpga_NodeVec_t * p, Fpga_Node_t * Entry );
+extern Fpga_Node_t * Fpga_NodeVecPop( Fpga_NodeVec_t * p );
+extern void Fpga_NodeVecWriteEntry( Fpga_NodeVec_t * p, int i, Fpga_Node_t * Entry );
+extern Fpga_Node_t * Fpga_NodeVecReadEntry( Fpga_NodeVec_t * p, int i );
+extern void Fpga_NodeVecSortByLevel( Fpga_NodeVec_t * p );
+extern void Fpga_SortNodesByArrivalTimes( Fpga_NodeVec_t * p );
+extern void Fpga_NodeVecUnion( Fpga_NodeVec_t * p, Fpga_NodeVec_t * p1, Fpga_NodeVec_t * p2 );
+extern void Fpga_NodeVecPushOrder( Fpga_NodeVec_t * vNodes, Fpga_Node_t * pNode, int fIncreasing );
+extern void Fpga_NodeVecReverse( Fpga_NodeVec_t * vNodes );
+
+/*=== fpgaUtils.c ===============================================================*/
+extern Fpga_NodeVec_t * Fpga_MappingDfs( Fpga_Man_t * pMan, int fCollectEquiv );
+extern Fpga_NodeVec_t * Fpga_MappingDfsNodes( Fpga_Man_t * pMan, Fpga_Node_t ** ppNodes, int nNodes, int fEquiv );
+extern Fpga_NodeVec_t * Fpga_MappingDfsCutsNode( Fpga_Man_t * pMan, Fpga_Node_t * pNode );
+//extern Sat_IntVec_t * Fpga_MappingDfsNodesSat( Fpga_Man_t * pMan, Fpga_Node_t ** ppNodes, int nNodes );
+extern Fpga_NodeVec_t * Fpga_MappingDfsCuts( Fpga_Man_t * pMan );
+extern int Fpga_CountLevels( Fpga_Man_t * pMan );
+extern int Fpga_CountLevelsNodes( Fpga_Man_t * pMan, Fpga_Node_t ** ppRoots, int nRoots );
+extern void Fpga_MappingMarkUsed( Fpga_Man_t * pMan );
+extern float Fpga_MappingGetAreaFlow( Fpga_Man_t * p );
+extern float Fpga_MappingArea( Fpga_Man_t * pMan );
+extern float Fpga_MappingComputeCutAreas( Fpga_Man_t * pMan );
+extern float Fpga_MappingSetRefsAndArea( Fpga_Man_t * pMan );
+extern int Fpga_MappingCountLevels( Fpga_Man_t * pMan );
+extern void Fpga_MappingUnmark( Fpga_Man_t * pMan );
+extern void Fpga_MappingUnmark_rec( Fpga_Node_t * pNode );
+extern void Fpga_MappingMark_rec( Fpga_Node_t * pNode );
+extern void Fpga_MappedMark_rec( Fpga_Node_t * pNode );
+extern void Fpga_MappedUnmark_rec( Fpga_Node_t * pNode );
+extern void Fpga_MappingPrintOutputArrivals( Fpga_Man_t * p );
+extern void Fpga_MappingSetupTruthTables( unsigned uTruths[][2] );
+extern void Fpga_MappingSetupMask( unsigned uMask[], int nVarsMax );
+extern void Fpga_MappingSortByLevel( Fpga_Man_t * pMan, Fpga_NodeVec_t * vNodes, int fIncreasing );
+extern Fpga_NodeVec_t * Fpga_DfsLim( Fpga_Man_t * pMan, Fpga_Node_t * pNode, int nLevels );
+extern Fpga_NodeVec_t * Fpga_MappingLevelize( Fpga_Man_t * pMan, Fpga_NodeVec_t * vNodes );
+extern float Fpga_MappingPrintSwitching( Fpga_Man_t * pMan );
+extern int Fpga_GetMaxLevel( Fpga_Man_t * pMan );
+extern void Fpga_ManReportChoices( Fpga_Man_t * pMan );
+extern void Fpga_MappingSetChoiceLevels( Fpga_Man_t * pMan );
+
+/*=== CUDD package.c ===============================================================*/
+extern unsigned int Cudd_Prime( unsigned int p );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
diff --git a/src/map/fpga/fpgaLib.c b/src/map/fpga/fpgaLib.c
new file mode 100644
index 00000000..9fd8e281
--- /dev/null
+++ b/src/map/fpga/fpgaLib.c
@@ -0,0 +1,183 @@
+/**CFile****************************************************************
+
+ FileName [fpgaLib.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Technology mapping for variable-size-LUT FPGAs.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - August 18, 2004.]
+
+ Revision [$Id: fpgaLib.c,v 1.4 2005/01/23 06:59:41 alanmi Exp $]
+
+***********************************************************************/
+
+#include "fpgaInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Reads the description of LUTs from the LUT library file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_LutLib_t * Fpga_LutLibCreate( char * FileName, int fVerbose )
+{
+ char pBuffer[1000], * pToken;
+ Fpga_LutLib_t * p;
+ FILE * pFile;
+ int i;
+
+ pFile = fopen( FileName, "r" );
+ if ( pFile == NULL )
+ {
+ printf( "Cannot open LUT library file \"%s\".\n", FileName );
+ return NULL;
+ }
+
+ p = ALLOC( Fpga_LutLib_t, 1 );
+ memset( p, 0, sizeof(Fpga_LutLib_t) );
+ p->pName = util_strsav( FileName );
+
+ i = 1;
+ while ( fgets( pBuffer, 1000, pFile ) != NULL )
+ {
+ pToken = strtok( pBuffer, " \t\n" );
+ if ( pToken == NULL )
+ continue;
+ if ( pToken[0] == '#' )
+ continue;
+ if ( i != atoi(pToken) )
+ {
+ printf( "Error in the LUT library file \"%s\".\n", FileName );
+ free( p );
+ return NULL;
+ }
+
+ pToken = strtok( NULL, " \t\n" );
+ p->pLutAreas[i] = (float)atof(pToken);
+
+ pToken = strtok( NULL, " \t\n" );
+ p->pLutDelays[i] = (float)atof(pToken);
+
+ if ( i == FPGA_MAX_LUTSIZE )
+ {
+ printf( "Skipping LUTs of size more than %d.\n", i );
+ break;
+ }
+ i++;
+ }
+ p->LutMax = i-1;
+ if ( p->LutMax > FPGA_MAX_LEAVES )
+ {
+ p->LutMax = FPGA_MAX_LEAVES;
+ printf( "Warning: LUTs with more than %d input will not be used.\n", FPGA_MAX_LEAVES );
+ }
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Duplicates the LUT library.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_LutLib_t * Fpga_LutLibDup( Fpga_LutLib_t * p )
+{
+ Fpga_LutLib_t * pNew;
+ pNew = ALLOC( Fpga_LutLib_t, 1 );
+ *pNew = *p;
+ pNew->pName = util_strsav( pNew->pName );
+ return pNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Frees the LUT library.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_LutLibFree( Fpga_LutLib_t * pLutLib )
+{
+ if ( pLutLib == NULL )
+ return;
+ FREE( pLutLib->pName );
+ FREE( pLutLib );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Prints the LUT library.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_LutLibPrint( Fpga_LutLib_t * pLutLib )
+{
+ int i;
+ printf( "# The area/delay of k-variable LUTs:\n" );
+ printf( "# k area delay\n" );
+ for ( i = 1; i <= pLutLib->LutMax; i++ )
+ printf( "%d %7.2f %7.2f\n", i, pLutLib->pLutAreas[i], pLutLib->pLutDelays[i] );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if the delays are discrete.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_LutLibDelaysAreDiscrete( Fpga_LutLib_t * pLutLib )
+{
+ float Delay;
+ int i;
+ for ( i = 1; i <= pLutLib->LutMax; i++ )
+ {
+ Delay = pLutLib->pLutDelays[i];
+ if ( ((float)((int)Delay)) != Delay )
+ return 0;
+ }
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/fpga/fpgaMatch.c b/src/map/fpga/fpgaMatch.c
new file mode 100644
index 00000000..8668ce4b
--- /dev/null
+++ b/src/map/fpga/fpgaMatch.c
@@ -0,0 +1,729 @@
+/**CFile****************************************************************
+
+ FileName [fpgaMatch.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Technology mapping for variable-size-LUT FPGAs.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - August 18, 2004.]
+
+ Revision [$Id: fpgaMatch.c,v 1.7 2004/09/30 21:18:10 satrajit Exp $]
+
+***********************************************************************/
+
+#include "fpgaInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Fpga_MatchNode( Fpga_Man_t * p, Fpga_Node_t * pNode, int fDelayOriented );
+static int Fpga_MatchNodeArea( Fpga_Man_t * p, Fpga_Node_t * pNode );
+static int Fpga_MatchNodeSwitch( Fpga_Man_t * p, Fpga_Node_t * pNode );
+
+static Fpga_Cut_t * Fpga_MappingAreaWithoutNode( Fpga_Man_t * p, Fpga_Node_t * pFanout, Fpga_Node_t * pNodeNo );
+static int Fpga_MappingMatchesAreaArray( Fpga_Man_t * p, Fpga_NodeVec_t * vNodes );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Finds the best delay assignment of LUTs.]
+
+ Description [This procedure iterates through all the nodes
+ of the object graph reachable from the POs and assigns the best
+ match to each of them. If the flag fDelayOriented is set to 1, it
+ tries to minimize the arrival time and uses the area flow as a
+ tie-breaker. If the flag is set to 0, it considers all the cuts,
+ whose arrival times matches the required time at the node, and
+ minimizes the area flow using the arrival time as a tie-breaker.
+
+ Before this procedure is called, the required times should be set
+ and the fanout counts should be computed. In the first iteration,
+ the required times are set to very large number (by NodeCreate)
+ and the fanout counts are set to the number of fanouts in the AIG.
+ In the following iterations, the required times are set by the
+ backward traversal, while the fanouts are estimated approximately.
+
+ If the arrival times of the PI nodes are given, they should be
+ assigned to the PIs after the cuts are computed and before this
+ procedure is called for the first time.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_MappingMatches( Fpga_Man_t * p, int fDelayOriented )
+{
+ ProgressBar * pProgress;
+ Fpga_Node_t * pNode;
+ int i, nNodes;
+
+ // assign the arrival times of the PIs
+ for ( i = 0; i < p->nInputs; i++ )
+ p->pInputs[i]->pCutBest->tArrival = p->pInputArrivals[i];
+
+ // match LUTs with nodes in the topological order
+ nNodes = p->vAnds->nSize;
+ pProgress = Extra_ProgressBarStart( stdout, nNodes );
+ for ( i = 0; i < nNodes; i++ )
+ {
+ pNode = p->vAnds->pArray[i];
+ if ( !Fpga_NodeIsAnd( pNode ) )
+ continue;
+ // skip a secondary node
+ if ( pNode->pRepr )
+ continue;
+ // match the node
+ Fpga_MatchNode( p, pNode, fDelayOriented );
+ Extra_ProgressBarUpdate( pProgress, i, "Matches ..." );
+ }
+ Extra_ProgressBarStop( pProgress );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the best matching for one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_MatchNode( Fpga_Man_t * p, Fpga_Node_t * pNode, int fDelayOriented )
+{
+ Fpga_Cut_t * pCut, * pCutBestOld;
+ int clk;
+ // make sure that at least one cut other than the trivial is present
+ if ( pNode->pCuts->pNext == NULL )
+ {
+ printf( "\nError: A node in the mapping graph does not have feasible cuts.\n" );
+ return 0;
+ }
+
+ // estimate the fanouts of the node
+ if ( pNode->aEstFanouts < 0 )
+ pNode->aEstFanouts = (float)pNode->nRefs;
+ else
+ pNode->aEstFanouts = (float)((2.0 * pNode->aEstFanouts + pNode->nRefs) / 3.0);
+// pNode->aEstFanouts = (float)pNode->nRefs;
+
+ pCutBestOld = pNode->pCutBest;
+ pNode->pCutBest = NULL;
+ for ( pCut = pNode->pCuts->pNext; pCut; pCut = pCut->pNext )
+ {
+ // compute the arrival time of the cut and its area flow
+clk = clock();
+ Fpga_CutGetParameters( p, pCut );
+//p->time2 += clock() - clk;
+ // drop the cut if it does not meet the required times
+ if ( pCut->tArrival > pNode->tRequired )
+ continue;
+ // if no cut is assigned, use the current one
+ if ( pNode->pCutBest == NULL )
+ {
+ pNode->pCutBest = pCut;
+ continue;
+ }
+ // choose the best cut using one of the two criteria:
+ // (1) delay oriented mapping (first traversal), delay first, area-flow as a tie-breaker
+ // (2) area recovery (subsequent traversals), area-flow first, delay as a tie-breaker
+ if ( (fDelayOriented &&
+ (pNode->pCutBest->tArrival > pCut->tArrival ||
+ pNode->pCutBest->tArrival == pCut->tArrival && pNode->pCutBest->aFlow > pCut->aFlow)) ||
+ (!fDelayOriented &&
+ (pNode->pCutBest->aFlow > pCut->aFlow ||
+ pNode->pCutBest->aFlow == pCut->aFlow && pNode->pCutBest->tArrival > pCut->tArrival)) )
+ {
+ pNode->pCutBest = pCut;
+ }
+ }
+
+ // make sure the match is found
+ if ( pNode->pCutBest == NULL )
+ {
+ if ( pCutBestOld == NULL )
+ {
+// printf( "\nError: Could not match a node in the object graph.\n" );
+ return 0;
+ }
+ pNode->pCutBest = pCutBestOld;
+ }
+ return 1;
+}
+
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Finds the best area assignment of LUTs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_MappingMatchesArea( Fpga_Man_t * p )
+{
+ ProgressBar * pProgress;
+ Fpga_Node_t * pNode;
+ int i, nNodes;
+
+ // assign the arrival times of the PIs
+ for ( i = 0; i < p->nInputs; i++ )
+ p->pInputs[i]->pCutBest->tArrival = p->pInputArrivals[i];
+
+ // match LUTs with nodes in the topological order
+ nNodes = p->vAnds->nSize;
+ pProgress = Extra_ProgressBarStart( stdout, nNodes );
+ for ( i = 0; i < nNodes; i++ )
+ {
+ pNode = p->vAnds->pArray[i];
+ if ( !Fpga_NodeIsAnd( pNode ) )
+ continue;
+ // skip a secondary node
+ if ( pNode->pRepr )
+ continue;
+ // match the node
+ Fpga_MatchNodeArea( p, pNode );
+ Extra_ProgressBarUpdate( pProgress, i, "Matches ..." );
+ }
+ Extra_ProgressBarStop( pProgress );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Finds the best area assignment of LUTs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_MappingMatchesAreaArray( Fpga_Man_t * p, Fpga_NodeVec_t * vNodes )
+{
+ Fpga_Node_t * pNode;
+ int i;
+
+ // match LUTs with nodes in the topological order
+ for ( i = 0; i < vNodes->nSize; i++ )
+ {
+ pNode = vNodes->pArray[i];
+ if ( !Fpga_NodeIsAnd( pNode ) )
+ continue;
+ // skip a secondary node
+ if ( pNode->pRepr )
+ continue;
+ // match the node
+ if ( !Fpga_MatchNodeArea( p, pNode ) )
+ return 0;
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the best matching for one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_MatchNodeArea( Fpga_Man_t * p, Fpga_Node_t * pNode )
+{
+ Fpga_Cut_t * pCut, * pCutBestOld;
+ float aAreaCutBest;
+ int clk;
+ // make sure that at least one cut other than the trivial is present
+ if ( pNode->pCuts->pNext == NULL )
+ {
+ printf( "\nError: A node in the mapping graph does not have feasible cuts.\n" );
+ return 0;
+ }
+
+ // remember the old cut
+ pCutBestOld = pNode->pCutBest;
+ // deref the old cut
+ if ( pNode->nRefs )
+ aAreaCutBest = Fpga_CutDeref( p, pNode, pNode->pCutBest, 0 );
+
+ // search for a better cut
+ pNode->pCutBest = NULL;
+ for ( pCut = pNode->pCuts->pNext; pCut; pCut = pCut->pNext )
+ {
+ // compute the arrival time of the cut and its area flow
+clk = clock();
+ pCut->tArrival = Fpga_TimeCutComputeArrival( p, pCut );
+//p->time2 += clock() - clk;
+ // drop the cut if it does not meet the required times
+ if ( pCut->tArrival > pNode->tRequired )
+ continue;
+ // get the area of this cut
+ pCut->aFlow = Fpga_CutGetAreaDerefed( p, pCut );
+ // if no cut is assigned, use the current one
+ if ( pNode->pCutBest == NULL )
+ {
+ pNode->pCutBest = pCut;
+ continue;
+ }
+ // choose the best cut as follows: exact area first, delay as a tie-breaker
+ if ( pNode->pCutBest->aFlow > pCut->aFlow ||
+ pNode->pCutBest->aFlow == pCut->aFlow && pNode->pCutBest->tArrival > pCut->tArrival )
+ {
+ pNode->pCutBest = pCut;
+ }
+ }
+
+ // make sure the match is found
+ if ( pNode->pCutBest == NULL )
+ {
+ pNode->pCutBest = pCutBestOld;
+ // insert the new cut
+ if ( pNode->nRefs )
+ pNode->pCutBest->aFlow = Fpga_CutRef( p, pNode, pNode->pCutBest, 0 );
+// printf( "\nError: Could not match a node in the object graph.\n" );
+ return 0;
+ }
+
+ // insert the new cut
+ // make sure the area selected is not worse then the original area
+ if ( pNode->nRefs )
+ {
+ pNode->pCutBest->aFlow = Fpga_CutRef( p, pNode, pNode->pCutBest, 0 );
+ assert( pNode->pCutBest->aFlow <= aAreaCutBest );
+// assert( pNode->tRequired < FPGA_FLOAT_LARGE );
+ }
+ return 1;
+}
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Finds the best area assignment of LUTs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_MappingMatchesSwitch( Fpga_Man_t * p )
+{
+ ProgressBar * pProgress;
+ Fpga_Node_t * pNode;
+ int i, nNodes;
+
+ // assign the arrival times of the PIs
+ for ( i = 0; i < p->nInputs; i++ )
+ p->pInputs[i]->pCutBest->tArrival = p->pInputArrivals[i];
+
+ // match LUTs with nodes in the topological order
+ nNodes = p->vAnds->nSize;
+ pProgress = Extra_ProgressBarStart( stdout, nNodes );
+ for ( i = 0; i < nNodes; i++ )
+ {
+ pNode = p->vAnds->pArray[i];
+ if ( !Fpga_NodeIsAnd( pNode ) )
+ continue;
+ // skip a secondary node
+ if ( pNode->pRepr )
+ continue;
+ // match the node
+ Fpga_MatchNodeSwitch( p, pNode );
+ Extra_ProgressBarUpdate( pProgress, i, "Matches ..." );
+ }
+ Extra_ProgressBarStop( pProgress );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the best matching for one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_MatchNodeSwitch( Fpga_Man_t * p, Fpga_Node_t * pNode )
+{
+ Fpga_Cut_t * pCut, * pCutBestOld;
+ float aAreaCutBest;
+ int clk;
+ // make sure that at least one cut other than the trivial is present
+ if ( pNode->pCuts->pNext == NULL )
+ {
+ printf( "\nError: A node in the mapping graph does not have feasible cuts.\n" );
+ return 0;
+ }
+
+ // remember the old cut
+ pCutBestOld = pNode->pCutBest;
+ // deref the old cut
+ if ( pNode->nRefs )
+ aAreaCutBest = Fpga_CutDerefSwitch( p, pNode, pNode->pCutBest, 0 );
+
+ // search for a better cut
+ pNode->pCutBest = NULL;
+ for ( pCut = pNode->pCuts->pNext; pCut; pCut = pCut->pNext )
+ {
+ // compute the arrival time of the cut and its area flow
+clk = clock();
+ pCut->tArrival = Fpga_TimeCutComputeArrival( p, pCut );
+//p->time2 += clock() - clk;
+ // drop the cut if it does not meet the required times
+ if ( pCut->tArrival > pNode->tRequired )
+ continue;
+ // get the area of this cut
+ pCut->aFlow = Fpga_CutGetSwitchDerefed( p, pNode, pCut );
+ // if no cut is assigned, use the current one
+ if ( pNode->pCutBest == NULL )
+ {
+ pNode->pCutBest = pCut;
+ continue;
+ }
+ // choose the best cut as follows: exact area first, delay as a tie-breaker
+ if ( pNode->pCutBest->aFlow > pCut->aFlow ||
+ pNode->pCutBest->aFlow == pCut->aFlow && pNode->pCutBest->tArrival > pCut->tArrival )
+ {
+ pNode->pCutBest = pCut;
+ }
+ }
+
+ // make sure the match is found
+ if ( pNode->pCutBest == NULL )
+ {
+ pNode->pCutBest = pCutBestOld;
+ // insert the new cut
+ if ( pNode->nRefs )
+ pNode->pCutBest->aFlow = Fpga_CutRefSwitch( p, pNode, pNode->pCutBest, 0 );
+// printf( "\nError: Could not match a node in the object graph.\n" );
+ return 0;
+ }
+
+ // insert the new cut
+ // make sure the area selected is not worse then the original area
+ if ( pNode->nRefs )
+ {
+ pNode->pCutBest->aFlow = Fpga_CutRefSwitch( p, pNode, pNode->pCutBest, 0 );
+ assert( pNode->pCutBest->aFlow <= aAreaCutBest );
+// assert( pNode->tRequired < FPGA_FLOAT_LARGE );
+ }
+ return 1;
+}
+
+
+#if 0
+/**function*************************************************************
+
+ synopsis [References the cut.]
+
+ description [This procedure is similar to the procedure NodeReclaim.]
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+void Fpga_Experiment( Fpga_Man_t * p )
+{
+ int Counter[10] = {0};
+ Fpga_Node_t * pNode;
+ int i;
+
+ for ( i = 0; i < p->nOutputs; i++ )
+ {
+ pNode = Fpga_Regular(p->pOutputs[i]);
+ pNode->vFanouts = NULL;
+ }
+
+ for ( i = 0; i < p->vAnds->nSize; i++ )
+ {
+ pNode = p->vAnds->pArray[i];
+ if ( !Fpga_NodeIsAnd( pNode ) )
+ continue;
+ if ( pNode->vFanouts == NULL )
+ continue;
+ if ( pNode->vFanouts->nSize >= 10 )
+ continue;
+ Counter[pNode->vFanouts->nSize]++;
+ }
+
+ printf( "Fanout stats: " );
+ for ( i = 0; i < 10; i++ )
+ printf( " %d=%d", i, Counter[i] );
+ printf( "\n" );
+ printf( "Area before = %4.2f.\n", Fpga_MappingArea(p) );
+
+ for ( i = 0; i < p->vAnds->nSize; i++ )
+ {
+ Fpga_NodeVec_t * vNodesTfo;
+ float AreaBefore;
+
+ pNode = p->vAnds->pArray[i];
+ if ( !Fpga_NodeIsAnd( pNode ) )
+ continue;
+ if ( pNode->vFanouts == NULL )
+ continue;
+ if ( pNode->vFanouts->nSize != 1 && pNode->vFanouts->nSize != 2 && pNode->vFanouts->nSize != 3 )
+ continue;
+
+// assert( pNode->nRefs > 0 );
+ if ( pNode->nRefs == 0 )
+ continue;
+
+ AreaBefore = pNode->pCutBest->aFlow;
+ pNode->pCutBest->aFlow = FPGA_FLOAT_LARGE;
+
+ Fpga_TimeComputeRequiredGlobal( p );
+
+ vNodesTfo = Fpga_CollectNodeTfo( p, pNode );
+ if ( Fpga_MappingMatchesAreaArray( p, vNodesTfo ) == 0 )
+ printf( "attempt failed\n" );
+ else
+ printf( "attempt succeeded\n" );
+ Fpga_NodeVecFree( vNodesTfo );
+
+ pNode->pCutBest->aFlow = AreaBefore;
+// break;
+ }
+ printf( "Area after = %4.2f.\n", Fpga_MappingArea(p) );
+// printf( "AREA GAIN = %4.2f (%.2f %%)\n", GainTotal, 100.0 * GainTotal / Fpga_MappingArea(p) );
+}
+
+
+
+/**function*************************************************************
+
+ synopsis [References the cut.]
+
+ description [This procedure is similar to the procedure NodeReclaim.]
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+void Fpga_Experiment2( Fpga_Man_t * p )
+{
+ int Counter[10] = {0};
+ Fpga_Cut_t * ppCutsNew[10];
+ Fpga_Cut_t * ppCutsOld[10];
+ Fpga_Node_t * pFanout, * pNode;
+ float Gain, Loss, GainTotal, Area1, Area2;
+ int i, k;
+
+ for ( i = 0; i < p->nOutputs; i++ )
+ {
+ pNode = Fpga_Regular(p->pOutputs[i]);
+ pNode->vFanouts = NULL;
+ }
+
+ for ( i = 0; i < p->vAnds->nSize; i++ )
+ {
+ pNode = p->vAnds->pArray[i];
+ if ( !Fpga_NodeIsAnd( pNode ) )
+ continue;
+ if ( pNode->vFanouts == NULL )
+ continue;
+ if ( pNode->vFanouts->nSize >= 10 )
+ continue;
+ Counter[pNode->vFanouts->nSize]++;
+ }
+
+ printf( "Fanout stats: " );
+ for ( i = 0; i < 10; i++ )
+ printf( " %d=%d", i, Counter[i] );
+ printf( "\n" );
+ printf( "Area before = %4.2f.\n", Fpga_MappingArea(p) );
+
+ GainTotal = 0;
+ for ( i = 0; i < p->vAnds->nSize; i++ )
+ {
+ pNode = p->vAnds->pArray[i];
+ if ( !Fpga_NodeIsAnd( pNode ) )
+ continue;
+ if ( pNode->vFanouts == NULL )
+ continue;
+ if ( pNode->vFanouts->nSize != 2 )//&& pNode->vFanouts->nSize != 2 && pNode->vFanouts->nSize != 3 )
+ continue;
+
+ assert( pNode->nRefs > 0 );
+
+ // for all fanouts, find the best cut without this node
+ for ( k = 0; k < pNode->vFanouts->nSize; k++ )
+ {
+ pFanout = pNode->vFanouts->pArray[k];
+ ppCutsOld[k] = pFanout->pCutBest;
+ ppCutsNew[k] = Fpga_MappingAreaWithoutNode( p, pFanout, pNode );
+ if ( ppCutsNew[k] == NULL )
+ break;
+ }
+ if ( k != pNode->vFanouts->nSize )
+ {
+ printf( "Node %4d: Skipped.\n", pNode->Num );
+ continue;
+ }
+
+
+ // compute the area after replacing all the cuts
+ Gain = 0;
+ for ( k = 0; k < pNode->vFanouts->nSize; k++ )
+ {
+ pFanout = pNode->vFanouts->pArray[k];
+ // deref old cut
+ Area1 = Fpga_MatchAreaDeref( p, ppCutsOld[k] );
+ // assign new cut
+ pFanout->pCutBest = ppCutsNew[k];
+ // ref new cut
+ Area2 = Fpga_MatchAreaRef( p, ppCutsNew[k] );
+ // compute the gain
+ Gain += Area1 - Area2;
+ }
+
+ printf( "%d ", pNode->nRefs );
+
+ // undo the whole thing
+ Loss = 0;
+ for ( k = 0; k < pNode->vFanouts->nSize; k++ )
+ {
+ pFanout = pNode->vFanouts->pArray[k];
+ // deref old cut
+ Area1 = Fpga_MatchAreaDeref( p, ppCutsNew[k] );
+ // assign new cut
+ pFanout->pCutBest = ppCutsOld[k];
+ // ref new cut
+ Area2 = Fpga_MatchAreaRef( p, ppCutsOld[k] );
+ // compute the gain
+ Loss += Area2 - Area1;
+ }
+ assert( Gain == Loss );
+
+
+ printf( "Node %4d: Fanouts = %d. Cut area = %4.2f. Gain = %4.2f.\n",
+ pNode->Num, pNode->nRefs, pNode->pCutBest->aFlow, Gain );
+
+ if ( Gain > 0 )
+ GainTotal += Gain;
+ }
+ printf( "Area after = %4.2f.\n", Fpga_MappingArea(p) );
+ printf( "AREA GAIN = %4.2f (%.2f %%)\n", GainTotal, 100.0 * GainTotal / Fpga_MappingArea(p) );
+}
+
+
+/**function*************************************************************
+
+ synopsis [Computes the loss of area when node is not allowed.]
+
+ description [Returning FPGA_FLOAT_LARGE means it does not exist.]
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+Fpga_Cut_t * Fpga_MappingAreaWithoutNode( Fpga_Man_t * p, Fpga_Node_t * pNode, Fpga_Node_t * pNodeNo )
+{
+ Fpga_Cut_t * pCut, * pCutBestOld, * pCutRes;
+ float aAreaCutBest;
+ int i, clk;
+ // make sure that at least one cut other than the trivial is present
+ if ( pNode->pCuts->pNext == NULL )
+ {
+ printf( "\nError: A node in the mapping graph does not have feasible cuts.\n" );
+ return 0;
+ }
+
+ assert( pNode->nRefs > 0 );
+
+ // remember the old cut
+ pCutBestOld = pNode->pCutBest;
+ // deref the old cut
+ aAreaCutBest = Fpga_MatchAreaDeref( p, pNode->pCutBest );
+
+ // search for a better cut
+ pNode->pCutBest = NULL;
+ for ( pCut = pNode->pCuts->pNext; pCut; pCut = pCut->pNext )
+ {
+ // compute the arrival time of the cut and its area flow
+clk = clock();
+ Fpga_MatchCutGetArrTime( p, pCut );
+//p->time2 += clock() - clk;
+ // drop the cut if it does not meet the required times
+ if ( pCut->tArrival > pNode->tRequired )
+ continue;
+
+ // skip the cut if it contains the no-node
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ if ( pCut->ppLeaves[i] == pNodeNo )
+ break;
+ if ( i != pCut->nLeaves )
+ continue;
+
+ // get the area of this cut
+ pCut->aFlow = Fpga_MatchAreaCount( p, pCut );
+ // if no cut is assigned, use the current one
+ if ( pNode->pCutBest == NULL )
+ {
+ pNode->pCutBest = pCut;
+ continue;
+ }
+ // choose the best cut as follows: exact area first, delay as a tie-breaker
+ if ( pNode->pCutBest->aFlow > pCut->aFlow ||
+ pNode->pCutBest->aFlow == pCut->aFlow && pNode->pCutBest->tArrival > pCut->tArrival )
+ {
+ pNode->pCutBest = pCut;
+ }
+ }
+
+ // make sure the match is found
+ if ( pNode->pCutBest == NULL )
+ {
+ pNode->pCutBest = pCutBestOld;
+ // insert the new cut
+ pNode->pCutBest->aFlow = Fpga_MatchAreaRef( p, pNode->pCutBest );
+ return NULL;
+ }
+
+ pCutRes = pNode->pCutBest;
+ pNode->pCutBest = pCutBestOld;
+
+ // insert the new cut
+ pNode->pCutBest->aFlow = Fpga_MatchAreaRef( p, pNode->pCutBest );
+
+ // make sure the area selected is not worse then the original area
+ assert( pNode->pCutBest->aFlow == aAreaCutBest );
+ assert( pNode->tRequired < FPGA_FLOAT_LARGE );
+ return pCutRes;
+}
+
+#endif
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
diff --git a/src/map/fpga/fpgaTime.c b/src/map/fpga/fpgaTime.c
new file mode 100644
index 00000000..df98faa1
--- /dev/null
+++ b/src/map/fpga/fpgaTime.c
@@ -0,0 +1,189 @@
+/**CFile****************************************************************
+
+ FileName [fpgaTime.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Technology mapping for variable-size-LUT FPGAs.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - August 18, 2004.]
+
+ Revision [$Id: fpgaTime.c,v 1.1 2005/01/23 06:59:42 alanmi Exp $]
+
+***********************************************************************/
+
+#include "fpgaInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Computes the arrival times of the cut.]
+
+ Description [Computes the maximum arrival time of the cut leaves and
+ adds the delay of the LUT.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Fpga_TimeCutComputeArrival( Fpga_Man_t * pMan, Fpga_Cut_t * pCut )
+{
+ int i;
+ float tArrival;
+ tArrival = -FPGA_FLOAT_LARGE;
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ if ( tArrival < pCut->ppLeaves[i]->pCutBest->tArrival )
+ tArrival = pCut->ppLeaves[i]->pCutBest->tArrival;
+ tArrival += pMan->pLutLib->pLutDelays[pCut->nLeaves];
+ return tArrival;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the arrival times of the cut recursively.]
+
+ Description [When computing the arrival time for the previously unused
+ cuts, their arrival time may be incorrect because their fanins have
+ incorrect arrival time. This procedure is called to fix this problem.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Fpga_TimeCutComputeArrival_rec( Fpga_Man_t * pMan, Fpga_Cut_t * pCut )
+{
+ int i;
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ if ( pCut->ppLeaves[i]->nRefs == 0 )
+ Fpga_TimeCutComputeArrival_rec( pMan, pCut->ppLeaves[i]->pCutBest );
+ return Fpga_TimeCutComputeArrival( pMan, pCut );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the maximum arrival times.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Fpga_TimeComputeArrivalMax( Fpga_Man_t * p )
+{
+ float fRequired;
+ int i;
+ // get the critical PO arrival time
+ fRequired = -FPGA_FLOAT_LARGE;
+ for ( i = 0; i < p->nOutputs; i++ )
+ {
+ if ( Fpga_NodeIsConst(p->pOutputs[i]) )
+ continue;
+ fRequired = FPGA_MAX( fRequired, Fpga_Regular(p->pOutputs[i])->pCutBest->tArrival );
+ }
+ return fRequired;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the required times of all nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_TimeComputeRequiredGlobal( Fpga_Man_t * p )
+{
+ p->fRequiredGlo = Fpga_TimeComputeArrivalMax( p );
+ Fpga_TimeComputeRequired( p, p->fRequiredGlo );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the required times of all nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_TimeComputeRequired( Fpga_Man_t * p, float fRequired )
+{
+ Fpga_NodeVec_t * vNodes;
+ int i;
+
+ // clean the required times and the fanout counts for all nodes
+ for ( i = 0; i < p->vAnds->nSize; i++ )
+ p->vAnds->pArray[i]->tRequired = FPGA_FLOAT_LARGE;
+
+ // set the required times for the POs
+ for ( i = 0; i < p->nOutputs; i++ )
+ Fpga_Regular(p->pOutputs[i])->tRequired = fRequired;
+
+ // collect nodes reachable from POs in the DFS order through the best cuts
+ vNodes = Fpga_MappingDfsCuts( p );
+ Fpga_TimePropagateRequired( p, vNodes );
+ Fpga_NodeVecFree( vNodes );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the required times of the given nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_TimePropagateRequired( Fpga_Man_t * p, Fpga_NodeVec_t * vNodes )
+{
+ Fpga_Node_t * pNode, * pChild;
+ float fRequired;
+ int i, k;
+
+ // sorts the nodes in the decreasing order of levels
+ Fpga_MappingSortByLevel( p, vNodes, 0 );
+ // go through the nodes in the reverse topological order
+ for ( k = 0; k < vNodes->nSize; k++ )
+ {
+ pNode = vNodes->pArray[k];
+ if ( !Fpga_NodeIsAnd(pNode) )
+ continue;
+ // get the required time for children
+ fRequired = pNode->tRequired - p->pLutLib->pLutDelays[pNode->pCutBest->nLeaves];
+ // update the required time of the children
+ for ( i = 0; i < pNode->pCutBest->nLeaves; i++ )
+ {
+ pChild = pNode->pCutBest->ppLeaves[i];
+ pChild->tRequired = FPGA_MIN( pChild->tRequired, fRequired );
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/fpga/fpgaTruth.c b/src/map/fpga/fpgaTruth.c
new file mode 100644
index 00000000..17c6385c
--- /dev/null
+++ b/src/map/fpga/fpgaTruth.c
@@ -0,0 +1,107 @@
+/**CFile****************************************************************
+
+ FileName [fpgaTruth.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Technology mapping for variable-size-LUT FPGAs.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - August 18, 2004.]
+
+ Revision [$Id: fpgaTruth.c,v 1.4 2005/01/23 06:59:42 alanmi Exp $]
+
+***********************************************************************/
+
+#include "fpgaInt.h"
+#include "cudd.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Recursively derives the truth table for the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Fpga_TruthsCutBdd_rec( DdManager * dd, Fpga_Cut_t * pCut, Fpga_NodeVec_t * vVisited )
+{
+ DdNode * bFunc, * bFunc0, * bFunc1;
+ assert( !Fpga_IsComplement(pCut) );
+ // if the cut is visited, return the result
+ if ( pCut->uSign )
+ return (DdNode *)pCut->uSign;
+ // compute the functions of the children
+ bFunc0 = Fpga_TruthsCutBdd_rec( dd, Fpga_CutRegular(pCut->pOne), vVisited ); Cudd_Ref( bFunc0 );
+ bFunc0 = Cudd_NotCond( bFunc0, Fpga_CutIsComplement(pCut->pOne) );
+ bFunc1 = Fpga_TruthsCutBdd_rec( dd, Fpga_CutRegular(pCut->pTwo), vVisited ); Cudd_Ref( bFunc1 );
+ bFunc1 = Cudd_NotCond( bFunc1, Fpga_CutIsComplement(pCut->pTwo) );
+ // get the function of the cut
+ bFunc = Cudd_bddAnd( dd, bFunc0, bFunc1 ); Cudd_Ref( bFunc );
+ bFunc = Cudd_NotCond( bFunc, pCut->Phase );
+ Cudd_RecursiveDeref( dd, bFunc0 );
+ Cudd_RecursiveDeref( dd, bFunc1 );
+ assert( pCut->uSign == 0 );
+ pCut->uSign = (unsigned)bFunc;
+ // add this cut to the visited list
+ Fpga_NodeVecPush( vVisited, (Fpga_Node_t *)pCut );
+ return bFunc;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Derives the truth table for one cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void * Fpga_TruthsCutBdd( void * dd, Fpga_Cut_t * pCut )
+{
+ Fpga_NodeVec_t * vVisited;
+ DdNode * bFunc;
+ int i;
+ assert( pCut->nLeaves > 1 );
+ // set the leaf variables
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ pCut->ppLeaves[i]->pCuts->uSign = (unsigned)Cudd_bddIthVar( dd, i );
+ // recursively compute the function
+ vVisited = Fpga_NodeVecAlloc( 10 );
+ bFunc = Fpga_TruthsCutBdd_rec( dd, pCut, vVisited ); Cudd_Ref( bFunc );
+ // clean the intermediate BDDs
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ pCut->ppLeaves[i]->pCuts->uSign = 0;
+ for ( i = 0; i < vVisited->nSize; i++ )
+ {
+ pCut = (Fpga_Cut_t *)vVisited->pArray[i];
+ Cudd_RecursiveDeref( dd, (DdNode*)pCut->uSign );
+ pCut->uSign = 0;
+ }
+ Fpga_NodeVecFree( vVisited );
+ Cudd_Deref( bFunc );
+ return bFunc;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/fpga/fpgaUtils.c b/src/map/fpga/fpgaUtils.c
new file mode 100644
index 00000000..a5b2cb32
--- /dev/null
+++ b/src/map/fpga/fpgaUtils.c
@@ -0,0 +1,1289 @@
+/**CFile****************************************************************
+
+ FileName [fpgaUtils.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Technology mapping for variable-size-LUT FPGAs.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - August 18, 2004.]
+
+ Revision [$Id: fpgaUtils.c,v 1.3 2004/07/06 04:55:58 alanmi Exp $]
+
+***********************************************************************/
+
+#include "fpgaInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Fpga_MappingDfs_rec( Fpga_Node_t * pNode, Fpga_NodeVec_t * vNodes, int fCollectEquiv );
+static void Fpga_MappingDfsCuts_rec( Fpga_Node_t * pNode, Fpga_NodeVec_t * vNodes );
+static float Fpga_MappingArea_rec( Fpga_Man_t * pMan, Fpga_Node_t * pNode, Fpga_NodeVec_t * vNodes );
+static int Fpga_MappingCountLevels_rec( Fpga_Node_t * pNode );
+static void Fpga_MappingMarkUsed_rec( Fpga_Node_t * pNode );
+static int Fpga_MappingCompareOutputDelay( int * pOut1, int * pOut2 );
+static float Fpga_MappingSetRefsAndArea_rec( Fpga_Man_t * pMan, Fpga_Node_t * pNode );
+static Fpga_Man_t * s_pMan = NULL;
+
+static void Fpga_DfsLim_rec( Fpga_Node_t * pNode, int Level, Fpga_NodeVec_t * vNodes );
+static int Fpga_CollectNodeTfo_rec( Fpga_Node_t * pNode, Fpga_Node_t * pPivot, Fpga_NodeVec_t * vVisited, Fpga_NodeVec_t * vTfo );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+
+/**Function*************************************************************
+
+ Synopsis [Computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_NodeVec_t * Fpga_MappingDfs( Fpga_Man_t * pMan, int fCollectEquiv )
+{
+ Fpga_NodeVec_t * vNodes;
+ Fpga_Node_t * pNode;
+ int i;
+ // start the array
+ vNodes = Fpga_NodeVecAlloc( 100 );
+ // collect the PIs
+ for ( i = 0; i < pMan->nInputs; i++ )
+ {
+ pNode = pMan->pInputs[i];
+ Fpga_NodeVecPush( vNodes, pNode );
+ pNode->fMark0 = 1;
+ }
+ // perform the traversal
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ Fpga_MappingDfs_rec( Fpga_Regular(pMan->pOutputs[i]), vNodes, fCollectEquiv );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ vNodes->pArray[i]->fMark0 = 0;
+// for ( i = 0; i < pMan->nOutputs; i++ )
+// Fpga_MappingUnmark_rec( Fpga_Regular(pMan->pOutputs[i]) );
+ return vNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappingDfs_rec( Fpga_Node_t * pNode, Fpga_NodeVec_t * vNodes, int fCollectEquiv )
+{
+ assert( !Fpga_IsComplement(pNode) );
+ if ( pNode->fMark0 )
+ return;
+ // visit the transitive fanin
+ if ( Fpga_NodeIsAnd(pNode) )
+ {
+ Fpga_MappingDfs_rec( Fpga_Regular(pNode->p1), vNodes, fCollectEquiv );
+ Fpga_MappingDfs_rec( Fpga_Regular(pNode->p2), vNodes, fCollectEquiv );
+ }
+ // visit the equivalent nodes
+ if ( fCollectEquiv && pNode->pNextE )
+ Fpga_MappingDfs_rec( pNode->pNextE, vNodes, fCollectEquiv );
+ // make sure the node is not visited through the equivalent nodes
+ assert( pNode->fMark0 == 0 );
+ // mark the node as visited
+ pNode->fMark0 = 1;
+ // add the node to the list
+ Fpga_NodeVecPush( vNodes, pNode );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_NodeVec_t * Fpga_MappingDfsNodes( Fpga_Man_t * pMan, Fpga_Node_t ** ppNodes, int nNodes, int fEquiv )
+{
+ Fpga_NodeVec_t * vNodes;
+ int i;
+ // perform the traversal
+ vNodes = Fpga_NodeVecAlloc( 200 );
+ for ( i = 0; i < nNodes; i++ )
+ Fpga_MappingDfs_rec( ppNodes[i], vNodes, fEquiv );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ vNodes->pArray[i]->fMark0 = 0;
+ return vNodes;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Computes the number of logic levels not counting PIs/POs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_CountLevels( Fpga_Man_t * pMan )
+{
+ int i, LevelsMax, LevelsCur;
+ // perform the traversal
+ LevelsMax = -1;
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ {
+ LevelsCur = Fpga_Regular(pMan->pOutputs[i])->Level;
+ if ( LevelsMax < LevelsCur )
+ LevelsMax = LevelsCur;
+ }
+ return LevelsMax;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the number of logic levels not counting PIs/POs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_CountLevelsNodes( Fpga_Man_t * pMan, Fpga_Node_t ** ppRoots, int nRoots )
+{
+ int i, LevelsMax, LevelsCur;
+ // perform the traversal
+ LevelsMax = -1;
+ for ( i = 0; i < nRoots; i++ )
+ {
+ LevelsCur = Fpga_Regular(ppRoots[i])->Level;
+ if ( LevelsMax < LevelsCur )
+ LevelsMax = LevelsCur;
+ }
+ return LevelsMax;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the DFS ordering of the nodes visible in current mapping.]
+
+ Description [The node is visible if it appears as a root of one of the best
+ cuts (that is cuts selected for the current mapping).]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_NodeVec_t * Fpga_MappingDfsCuts( Fpga_Man_t * pMan )
+{
+ Fpga_NodeVec_t * vNodes;
+ int i;
+ // perform the traversal
+ vNodes = Fpga_NodeVecAlloc( 100 );
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ Fpga_MappingDfsCuts_rec( Fpga_Regular(pMan->pOutputs[i]), vNodes );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ vNodes->pArray[i]->fMark0 = 0;
+ return vNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the DFS ordering of the nodes visible in current mapping.]
+
+ Description [The node is visible if it appears as a root of one of the best
+ cuts (that is cuts selected for the current mapping).]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_NodeVec_t * Fpga_MappingDfsCutsNode( Fpga_Man_t * pMan, Fpga_Node_t * pNode )
+{
+ Fpga_NodeVec_t * vNodes;
+ int i;
+ // perform the traversal
+ vNodes = Fpga_NodeVecAlloc( 100 );
+ Fpga_MappingDfsCuts_rec( pNode, vNodes );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ vNodes->pArray[i]->fMark0 = 0;
+ return vNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappingDfsCuts_rec( Fpga_Node_t * pNode, Fpga_NodeVec_t * vNodes )
+{
+ int i;
+ assert( !Fpga_IsComplement(pNode) );
+ if ( !Fpga_NodeIsAnd(pNode) )
+ return;
+ if ( pNode->fMark0 )
+ return;
+ assert( pNode->pCutBest != NULL );
+ // visit the transitive fanin of the selected cut
+ for ( i = 0; i < pNode->pCutBest->nLeaves; i++ )
+ Fpga_MappingDfsCuts_rec( pNode->pCutBest->ppLeaves[i], vNodes );
+ // make sure the node is not visited through the fanin nodes
+ assert( pNode->fMark0 == 0 );
+ // mark the node as visited
+ pNode->fMark0 = 1;
+ // add the node to the list
+ Fpga_NodeVecPush( vNodes, pNode );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Marks the nodes used in the mapping.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappingMarkUsed( Fpga_Man_t * pMan )
+{
+ int i;
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ Fpga_MappingMarkUsed_rec( Fpga_Regular(pMan->pOutputs[i]) );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappingMarkUsed_rec( Fpga_Node_t * pNode )
+{
+ int i;
+ assert( !Fpga_IsComplement(pNode) );
+ if ( pNode->fUsed )
+ return;
+ pNode->fUsed = 1;
+ if ( !Fpga_NodeIsAnd(pNode) )
+ return;
+ assert( pNode->pCutBest != NULL );
+ // visit the transitive fanin of the selected cut
+ for ( i = 0; i < pNode->pCutBest->nLeaves; i++ )
+ Fpga_MappingMarkUsed_rec( pNode->pCutBest->ppLeaves[i] );
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Fpga_MappingGetAreaFlow( Fpga_Man_t * p )
+{
+ float aFlowFlowTotal = 0;
+ int i;
+ for ( i = 0; i < p->nOutputs; i++ )
+ {
+ if ( Fpga_NodeIsConst(p->pOutputs[i]) )
+ continue;
+ aFlowFlowTotal += Fpga_Regular(p->pOutputs[i])->pCutBest->aFlow;
+ }
+ return aFlowFlowTotal;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the area of the current mapping.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Fpga_MappingArea( Fpga_Man_t * pMan )
+{
+ Fpga_NodeVec_t * vNodes;
+ float aTotal;
+ int i;
+ // perform the traversal
+ aTotal = 0;
+ vNodes = Fpga_NodeVecAlloc( 100 );
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ {
+ aTotal += Fpga_MappingArea_rec( pMan, Fpga_Regular(pMan->pOutputs[i]), vNodes );
+ // add the area for single-input nodes (if any) at the POs
+// if ( Fpga_NodeIsVar(pMan->pOutputs[i]) || Fpga_IsComplement(pMan->pOutputs[i]) )
+// aTotal += pMan->pLutLib->pLutAreas[1];
+ }
+ for ( i = 0; i < vNodes->nSize; i++ )
+ vNodes->pArray[i]->fMark0 = 0;
+ Fpga_NodeVecFree( vNodes );
+ return aTotal;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Fpga_MappingArea_rec( Fpga_Man_t * pMan, Fpga_Node_t * pNode, Fpga_NodeVec_t * vNodes )
+{
+ float aArea;
+ int i;
+ assert( !Fpga_IsComplement(pNode) );
+ if ( !Fpga_NodeIsAnd(pNode) )
+ return 0;
+ if ( pNode->fMark0 )
+ return 0;
+ assert( pNode->pCutBest != NULL );
+ // visit the transitive fanin of the selected cut
+ aArea = 0;
+ for ( i = 0; i < pNode->pCutBest->nLeaves; i++ )
+ aArea += Fpga_MappingArea_rec( pMan, pNode->pCutBest->ppLeaves[i], vNodes );
+ // make sure the node is not visited through the fanin nodes
+ assert( pNode->fMark0 == 0 );
+ // mark the node as visited
+ pNode->fMark0 = 1;
+ // add the node to the list
+ aArea += pMan->pLutLib->pLutAreas[pNode->pCutBest->nLeaves];
+ // add the node to the list
+ Fpga_NodeVecPush( vNodes, pNode );
+ return aArea;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Sets the correct reference counts for the mapping.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Fpga_MappingComputeCutAreas( Fpga_Man_t * pMan )
+{
+ Fpga_NodeVec_t * vNodes;
+ Fpga_Node_t * pNode;
+ float Area = 0;
+ int i;
+ // collect nodes reachable from POs in the DFS order through the best cuts
+ vNodes = Fpga_MappingDfsCuts( pMan );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ {
+ pNode = vNodes->pArray[i];
+ pNode->pCutBest->aFlow = Fpga_CutGetAreaRefed( pMan, pNode->pCutBest );
+ Area += pMan->pLutLib->pLutAreas[pNode->pCutBest->nLeaves];
+ }
+ Fpga_NodeVecFree( vNodes );
+ return Area;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the correct reference counts for the mapping.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Fpga_MappingSetRefsAndArea( Fpga_Man_t * pMan )
+{
+ Fpga_Node_t * pNode;
+ float aArea;
+ int i;
+ // clean all references
+ for ( i = 0; i < pMan->vNodesAll->nSize; i++ )
+ pMan->vNodesAll->pArray[i]->nRefs = 0;
+ // collect nodes reachable from POs in the DFS order through the best cuts
+ aArea = 0;
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ {
+ pNode = Fpga_Regular(pMan->pOutputs[i]);
+ if ( pNode == pMan->pConst1 )
+ continue;
+ aArea += Fpga_MappingSetRefsAndArea_rec( pMan, pNode );
+ pNode->nRefs++;
+ }
+ return aArea;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Fpga_MappingSetRefsAndArea_rec( Fpga_Man_t * pMan, Fpga_Node_t * pNode )
+{
+ float aArea;
+ int i;
+ assert( !Fpga_IsComplement(pNode) );
+ if ( pNode->nRefs++ )
+ return 0;
+ if ( !Fpga_NodeIsAnd(pNode) )
+ return 0;
+ assert( pNode->pCutBest != NULL );
+ // visit the transitive fanin of the selected cut
+ aArea = pMan->pLutLib->pLutAreas[pNode->pCutBest->nLeaves];
+ for ( i = 0; i < pNode->pCutBest->nLeaves; i++ )
+ aArea += Fpga_MappingSetRefsAndArea_rec( pMan, pNode->pCutBest->ppLeaves[i] );
+ return aArea;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the number of logic levels not counting PIs/POs.]
+
+ Description []
+
+ SideEffects [Note that this procedure will reassign the levels assigned
+ originally by NodeCreate() because it counts the number of levels with
+ choices differently!]
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_MappingCountLevels( Fpga_Man_t * pMan )
+{
+ int i, LevelsMax, LevelsCur;
+ // perform the traversal
+ LevelsMax = -1;
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ {
+ LevelsCur = Fpga_MappingCountLevels_rec( Fpga_Regular(pMan->pOutputs[i]) );
+ if ( LevelsMax < LevelsCur )
+ LevelsMax = LevelsCur;
+ }
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ Fpga_MappingUnmark_rec( Fpga_Regular(pMan->pOutputs[i]) );
+ return LevelsMax;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively computes the number of logic levels.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_MappingCountLevels_rec( Fpga_Node_t * pNode )
+{
+ int Level1, Level2;
+ assert( !Fpga_IsComplement(pNode) );
+ if ( !Fpga_NodeIsAnd(pNode) )
+ {
+ pNode->Level = 0;
+ return 0;
+ }
+ if ( pNode->fMark0 )
+ return pNode->Level;
+ pNode->fMark0 = 1;
+ // visit the transitive fanin
+ Level1 = Fpga_MappingCountLevels_rec( Fpga_Regular(pNode->p1) );
+ Level2 = Fpga_MappingCountLevels_rec( Fpga_Regular(pNode->p2) );
+ // set the number of levels
+ pNode->Level = 1 + ((Level1>Level2)? Level1: Level2);
+ return pNode->Level;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Unmarks the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappingUnmark( Fpga_Man_t * pMan )
+{
+ int i;
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ Fpga_MappingUnmark_rec( Fpga_Regular(pMan->pOutputs[i]) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively unmarks the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappingUnmark_rec( Fpga_Node_t * pNode )
+{
+ assert( !Fpga_IsComplement(pNode) );
+ if ( pNode->fMark0 == 0 )
+ return;
+ pNode->fMark0 = 0;
+ if ( !Fpga_NodeIsAnd(pNode) )
+ return;
+ Fpga_MappingUnmark_rec( Fpga_Regular(pNode->p1) );
+ Fpga_MappingUnmark_rec( Fpga_Regular(pNode->p2) );
+ // visit the equivalent nodes
+ if ( pNode->pNextE )
+ Fpga_MappingUnmark_rec( pNode->pNextE );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively unmarks the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappingMark_rec( Fpga_Node_t * pNode )
+{
+ assert( !Fpga_IsComplement(pNode) );
+ if ( pNode->fMark0 == 1 )
+ return;
+ pNode->fMark0 = 1;
+ if ( !Fpga_NodeIsAnd(pNode) )
+ return;
+ Fpga_MappingMark_rec( Fpga_Regular(pNode->p1) );
+ Fpga_MappingMark_rec( Fpga_Regular(pNode->p2) );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappedMark_rec( Fpga_Node_t * pNode )
+{
+ int i;
+ assert( !Fpga_IsComplement(pNode) );
+ if ( pNode->fMark0 == 1 )
+ return;
+ pNode->fMark0 = 1;
+ if ( !Fpga_NodeIsAnd(pNode) )
+ return;
+ assert( pNode->pCutBest != NULL );
+ // visit the transitive fanin of the selected cut
+ for ( i = 0; i < pNode->pCutBest->nLeaves; i++ )
+ Fpga_MappedMark_rec( pNode->pCutBest->ppLeaves[i] );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively unmarks the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappedUnmark_rec( Fpga_Node_t * pNode )
+{
+ int i;
+ assert( !Fpga_IsComplement(pNode) );
+ if ( pNode->fMark0 == 0 )
+ return;
+ pNode->fMark0 = 0;
+ if ( !Fpga_NodeIsAnd(pNode) )
+ return;
+ assert( pNode->pCutBest != NULL );
+ // visit the transitive fanin of the selected cut
+ for ( i = 0; i < pNode->pCutBest->nLeaves; i++ )
+ Fpga_MappedUnmark_rec( pNode->pCutBest->ppLeaves[i] );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints a bunch of latest arriving outputs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappingPrintOutputArrivals( Fpga_Man_t * p )
+{
+ Fpga_Node_t * pNode;
+ int fCompl, Limit, i;
+ int * pSorted;
+
+ // sort outputs by arrival time
+ s_pMan = p;
+ pSorted = ALLOC( int, p->nOutputs );
+ for ( i = 0; i < p->nOutputs; i++ )
+ pSorted[i] = i;
+ qsort( (void *)pSorted, p->nOutputs, sizeof(int),
+ (int (*)(const void *, const void *)) Fpga_MappingCompareOutputDelay );
+ assert( Fpga_MappingCompareOutputDelay( pSorted, pSorted + p->nOutputs - 1 ) <= 0 );
+ s_pMan = NULL;
+
+ // print the latest outputs
+ Limit = (p->nOutputs > 5)? 5 : p->nOutputs;
+ for ( i = 0; i < Limit; i++ )
+ {
+ // get the i-th latest output
+ pNode = Fpga_Regular(p->pOutputs[pSorted[i]]);
+ fCompl = Fpga_IsComplement(p->pOutputs[pSorted[i]]);
+ // print out the best arrival time
+ printf( "Output %20s : ", p->ppOutputNames[pSorted[i]] );
+ printf( "Delay = %8.2f ", (double)pNode->pCutBest->tArrival );
+ if ( fCompl )
+ printf( "NEG" );
+ else
+ printf( "POS" );
+ printf( "\n" );
+ }
+ free( pSorted );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares the outputs by their arrival times.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_MappingCompareOutputDelay( int * pOut1, int * pOut2 )
+{
+ Fpga_Node_t * pNode1 = Fpga_Regular(s_pMan->pOutputs[*pOut1]);
+ Fpga_Node_t * pNode2 = Fpga_Regular(s_pMan->pOutputs[*pOut2]);
+ float pTime1 = pNode1->pCutBest? pNode1->pCutBest->tArrival : 0;
+ float pTime2 = pNode2->pCutBest? pNode2->pCutBest->tArrival : 0;
+ if ( pTime1 > pTime2 )
+ return -1;
+ if ( pTime1 < pTime2 )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets up the truth tables.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappingSetupTruthTables( unsigned uTruths[][2] )
+{
+ int m, v;
+ // set up the truth tables
+ for ( m = 0; m < 32; m++ )
+ for ( v = 0; v < 5; v++ )
+ if ( m & (1 << v) )
+ uTruths[v][0] |= (1 << m);
+ // make adjustments for the case of 6 variables
+ for ( v = 0; v < 5; v++ )
+ uTruths[v][1] = uTruths[v][0];
+ uTruths[5][0] = 0;
+ uTruths[5][1] = FPGA_FULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets up the mask.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappingSetupMask( unsigned uMask[], int nVarsMax )
+{
+ if ( nVarsMax == 6 )
+ uMask[0] = uMask[1] = FPGA_FULL;
+ else
+ {
+ uMask[0] = FPGA_MASK(1 << nVarsMax);
+ uMask[1] = 0;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Verify one useful property.]
+
+ Description [This procedure verifies one useful property. After
+ the FRAIG construction with choice nodes is over, each primary node
+ should have fanins that are primary nodes. The primary nodes is the
+ one that does not have pNode->pRepr set to point to another node.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_ManCheckConsistency( Fpga_Man_t * p )
+{
+ Fpga_Node_t * pNode;
+ Fpga_NodeVec_t * pVec;
+ int i;
+ pVec = Fpga_MappingDfs( p, 0 );
+ for ( i = 0; i < pVec->nSize; i++ )
+ {
+ pNode = pVec->pArray[i];
+ if ( Fpga_NodeIsVar(pNode) )
+ {
+ if ( pNode->pRepr )
+ printf( "Primary input %d is a secondary node.\n", pNode->Num );
+ }
+ else if ( Fpga_NodeIsConst(pNode) )
+ {
+ if ( pNode->pRepr )
+ printf( "Constant 1 %d is a secondary node.\n", pNode->Num );
+ }
+ else
+ {
+ if ( pNode->pRepr )
+ printf( "Internal node %d is a secondary node.\n", pNode->Num );
+ if ( Fpga_Regular(pNode->p1)->pRepr )
+ printf( "Internal node %d has first fanin that is a secondary node.\n", pNode->Num );
+ if ( Fpga_Regular(pNode->p2)->pRepr )
+ printf( "Internal node %d has second fanin that is a secondary node.\n", pNode->Num );
+ }
+ }
+ Fpga_NodeVecFree( pVec );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares the supergates by their level.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_CompareNodesByLevelDecreasing( Fpga_Node_t ** ppS1, Fpga_Node_t ** ppS2 )
+{
+ if ( Fpga_Regular(*ppS1)->Level > Fpga_Regular(*ppS2)->Level )
+ return -1;
+ if ( Fpga_Regular(*ppS1)->Level < Fpga_Regular(*ppS2)->Level )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares the supergates by their level.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_CompareNodesByLevelIncreasing( Fpga_Node_t ** ppS1, Fpga_Node_t ** ppS2 )
+{
+ if ( Fpga_Regular(*ppS1)->Level < Fpga_Regular(*ppS2)->Level )
+ return -1;
+ if ( Fpga_Regular(*ppS1)->Level > Fpga_Regular(*ppS2)->Level )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Orders the nodes in the decreasing order of levels.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappingSortByLevel( Fpga_Man_t * pMan, Fpga_NodeVec_t * vNodes, int fIncreasing )
+{
+ if ( fIncreasing )
+ qsort( (void *)vNodes->pArray, vNodes->nSize, sizeof(Fpga_Node_t *),
+ (int (*)(const void *, const void *)) Fpga_CompareNodesByLevelIncreasing );
+ else
+ qsort( (void *)vNodes->pArray, vNodes->nSize, sizeof(Fpga_Node_t *),
+ (int (*)(const void *, const void *)) Fpga_CompareNodesByLevelDecreasing );
+// assert( Fpga_CompareNodesByLevel( vNodes->pArray, vNodes->pArray + vNodes->nSize - 1 ) <= 0 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the limited DFS ordering for one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_NodeVec_t * Fpga_DfsLim( Fpga_Man_t * pMan, Fpga_Node_t * pNode, int nLevels )
+{
+ Fpga_NodeVec_t * vNodes;
+ int i;
+ // perform the traversal
+ vNodes = Fpga_NodeVecAlloc( 100 );
+ Fpga_DfsLim_rec( pNode, nLevels, vNodes );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ vNodes->pArray[i]->fMark0 = 0;
+ return vNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_DfsLim_rec( Fpga_Node_t * pNode, int Level, Fpga_NodeVec_t * vNodes )
+{
+ assert( !Fpga_IsComplement(pNode) );
+ if ( pNode->fMark0 )
+ return;
+ pNode->fMark0 = 1;
+ // visit the transitive fanin
+ Level--;
+ if ( Level > 0 && Fpga_NodeIsAnd(pNode) )
+ {
+ Fpga_DfsLim_rec( Fpga_Regular(pNode->p1), Level, vNodes );
+ Fpga_DfsLim_rec( Fpga_Regular(pNode->p2), Level, vNodes );
+ }
+ // add the node to the list
+ Fpga_NodeVecPush( vNodes, pNode );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the limited DFS ordering for one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_ManCleanData0( Fpga_Man_t * pMan )
+{
+ int i;
+ for ( i = 0; i < pMan->vNodesAll->nSize; i++ )
+ pMan->vNodesAll->pArray[i]->pData0 = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collects the TFO of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_NodeVec_t * Fpga_CollectNodeTfo( Fpga_Man_t * pMan, Fpga_Node_t * pNode )
+{
+ Fpga_NodeVec_t * vVisited, * vTfo;
+ int i;
+ // perform the traversal
+ vVisited = Fpga_NodeVecAlloc( 100 );
+ vTfo = Fpga_NodeVecAlloc( 100 );
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ Fpga_CollectNodeTfo_rec( Fpga_Regular(pMan->pOutputs[i]), pNode, vVisited, vTfo );
+ for ( i = 0; i < vVisited->nSize; i++ )
+ vVisited->pArray[i]->fMark0 = vVisited->pArray[i]->fMark1 = 0;
+ Fpga_NodeVecFree( vVisited );
+ return vTfo;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collects the TFO of the node.]
+
+ Description [Returns 1 if the node should be collected.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_CollectNodeTfo_rec( Fpga_Node_t * pNode, Fpga_Node_t * pPivot, Fpga_NodeVec_t * vVisited, Fpga_NodeVec_t * vTfo )
+{
+ int Ret1, Ret2;
+ assert( !Fpga_IsComplement(pNode) );
+ // skip visited nodes
+ if ( pNode->fMark0 )
+ return pNode->fMark1;
+ pNode->fMark0 = 1;
+ Fpga_NodeVecPush( vVisited, pNode );
+
+ // return the pivot node
+ if ( pNode == pPivot )
+ {
+ pNode->fMark1 = 1;
+ return 1;
+ }
+ if ( pNode->Level < pPivot->Level )
+ {
+ pNode->fMark1 = 0;
+ return 0;
+ }
+ // visit the transitive fanin
+ assert( Fpga_NodeIsAnd(pNode) );
+ Ret1 = Fpga_CollectNodeTfo_rec( Fpga_Regular(pNode->p1), pPivot, vVisited, vTfo );
+ Ret2 = Fpga_CollectNodeTfo_rec( Fpga_Regular(pNode->p2), pPivot, vVisited, vTfo );
+ if ( Ret1 || Ret2 )
+ {
+ pNode->fMark1 = 1;
+ Fpga_NodeVecPush( vTfo, pNode );
+ }
+ else
+ pNode->fMark1 = 0;
+ return pNode->fMark1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Levelizes the nodes accessible from the POs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_NodeVec_t * Fpga_MappingLevelize( Fpga_Man_t * pMan, Fpga_NodeVec_t * vNodes )
+{
+ Fpga_NodeVec_t * vLevels;
+ Fpga_Node_t ** ppNodes;
+ Fpga_Node_t * pNode;
+ int nNodes, nLevelsMax, i;
+
+ // reassign the levels (this may be necessary for networks which choices)
+ ppNodes = vNodes->pArray;
+ nNodes = vNodes->nSize;
+ for ( i = 0; i < nNodes; i++ )
+ {
+ pNode = ppNodes[i];
+ if ( !Fpga_NodeIsAnd(pNode) )
+ {
+ pNode->Level = 0;
+ continue;
+ }
+ pNode->Level = 1 + FPGA_MAX( Fpga_Regular(pNode->p1)->Level, Fpga_Regular(pNode->p2)->Level );
+ }
+
+ // get the max levels
+ nLevelsMax = 0;
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ nLevelsMax = FPGA_MAX( nLevelsMax, (int)Fpga_Regular(pMan->pOutputs[i])->Level );
+ nLevelsMax++;
+
+ // allocate storage for levels
+ vLevels = Fpga_NodeVecAlloc( nLevelsMax );
+ for ( i = 0; i < nLevelsMax; i++ )
+ Fpga_NodeVecPush( vLevels, NULL );
+
+ // go through the nodes and add them to the levels
+ for ( i = 0; i < nNodes; i++ )
+ {
+ pNode = ppNodes[i];
+ pNode->pLevel = NULL;
+ if ( !Fpga_NodeIsAnd(pNode) )
+ continue;
+ // attach the node to this level
+ pNode->pLevel = Fpga_NodeVecReadEntry( vLevels, pNode->Level );
+ Fpga_NodeVecWriteEntry( vLevels, pNode->Level, pNode );
+ }
+ return vLevels;
+}
+/**Function*************************************************************
+
+ Synopsis [Prints the switching activity changes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Fpga_MappingPrintSwitching( Fpga_Man_t * p )
+{
+ Fpga_Node_t * pNode;
+ float SwitchTotal = 0.0;
+ int nNodes = 0;
+ int i;
+ for ( i = 0; i < p->vNodesAll->nSize; i++ )
+ {
+ // skip primary inputs
+ pNode = p->vNodesAll->pArray[i];
+// if ( !Fpga_NodeIsAnd( pNode ) )
+// continue;
+ // skip a secondary node
+ if ( pNode->pRepr )
+ continue;
+ // count the switching nodes
+ if ( pNode->nRefs > 0 )
+ {
+ SwitchTotal += pNode->SwitchProb;
+ nNodes++;
+ }
+ }
+ if ( p->fVerbose )
+ printf( "Total switching = %10.2f. Average switching = %6.4f.\n", SwitchTotal, SwitchTotal/nNodes );
+ return SwitchTotal;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets up the mask.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_GetMaxLevel( Fpga_Man_t * pMan )
+{
+ int nLevelMax, i;
+ nLevelMax = 0;
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ nLevelMax = nLevelMax > (int)Fpga_Regular(pMan->pOutputs[i])->Level?
+ nLevelMax : (int)Fpga_Regular(pMan->pOutputs[i])->Level;
+ return nLevelMax;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Analyses choice nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_MappingUpdateLevel_rec( Fpga_Man_t * pMan, Fpga_Node_t * pNode, int fMaximum )
+{
+ Fpga_Node_t * pTemp;
+ int Level1, Level2, LevelE;
+ assert( !Fpga_IsComplement(pNode) );
+ if ( !Fpga_NodeIsAnd(pNode) )
+ return pNode->Level;
+ // skip the visited node
+ if ( pNode->TravId == pMan->nTravIds )
+ return pNode->Level;
+ pNode->TravId = pMan->nTravIds;
+ // compute levels of the children nodes
+ Level1 = Fpga_MappingUpdateLevel_rec( pMan, Fpga_Regular(pNode->p1), fMaximum );
+ Level2 = Fpga_MappingUpdateLevel_rec( pMan, Fpga_Regular(pNode->p2), fMaximum );
+ pNode->Level = 1 + FPGA_MAX( Level1, Level2 );
+ if ( pNode->pNextE )
+ {
+ LevelE = Fpga_MappingUpdateLevel_rec( pMan, pNode->pNextE, fMaximum );
+ if ( fMaximum )
+ {
+ if ( pNode->Level < (unsigned)LevelE )
+ pNode->Level = LevelE;
+ }
+ else
+ {
+ if ( pNode->Level > (unsigned)LevelE )
+ pNode->Level = LevelE;
+ }
+ // set the level of all equivalent nodes to be the same minimum
+ if ( pNode->pRepr == NULL ) // the primary node
+ for ( pTemp = pNode->pNextE; pTemp; pTemp = pTemp->pNextE )
+ pTemp->Level = pNode->Level;
+ }
+ return pNode->Level;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Resets the levels of the nodes in the choice graph.]
+
+ Description [Makes the level of the choice nodes to be equal to the
+ maximum of the level of the nodes in the equivalence class. This way
+ sorting by level leads to the reverse topological order, which is
+ needed for the required time computation.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappingSetChoiceLevels( Fpga_Man_t * pMan )
+{
+ int i;
+ pMan->nTravIds++;
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ Fpga_MappingUpdateLevel_rec( pMan, Fpga_Regular(pMan->pOutputs[i]), 1 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reports statistics on choice nodes.]
+
+ Description [The number of choice nodes is the number of primary nodes,
+ which has pNextE set to a pointer. The number of choices is the number
+ of entries in the equivalent-node lists of the primary nodes.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_ManReportChoices( Fpga_Man_t * pMan )
+{
+ Fpga_Node_t * pNode, * pTemp;
+ int nChoiceNodes, nChoices;
+ int i, LevelMax1, LevelMax2;
+
+ // report the number of levels
+ LevelMax1 = Fpga_GetMaxLevel( pMan );
+ pMan->nTravIds++;
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ Fpga_MappingUpdateLevel_rec( pMan, Fpga_Regular(pMan->pOutputs[i]), 0 );
+ LevelMax2 = Fpga_GetMaxLevel( pMan );
+
+ // report statistics about choices
+ nChoiceNodes = nChoices = 0;
+ for ( i = 0; i < pMan->vAnds->nSize; i++ )
+ {
+ pNode = pMan->vAnds->pArray[i];
+ if ( pNode->pRepr == NULL && pNode->pNextE != NULL )
+ { // this is a choice node = the primary node that has equivalent nodes
+ nChoiceNodes++;
+ for ( pTemp = pNode; pTemp; pTemp = pTemp->pNextE )
+ nChoices++;
+ }
+ }
+ if ( pMan->fVerbose )
+ {
+ printf( "Maximum level: Original = %d. Reduced due to choices = %d.\n", LevelMax1, LevelMax2 );
+ printf( "Choice stats: Choice nodes = %d. Total choices = %d.\n", nChoiceNodes, nChoices );
+ }
+/*
+ {
+ FILE * pTable;
+ pTable = fopen( "stats_choice.txt", "a+" );
+ fprintf( pTable, "%s ", pMan->pFileName );
+ fprintf( pTable, "%4d ", LevelMax1 );
+ fprintf( pTable, "%4d ", pMan->vAnds->nSize - pMan->nInputs );
+ fprintf( pTable, "%4d ", LevelMax2 );
+ fprintf( pTable, "%7d ", nChoiceNodes );
+ fprintf( pTable, "%7d ", nChoices + nChoiceNodes );
+ fprintf( pTable, "\n" );
+ fclose( pTable );
+ }
+*/
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/fpga/fpgaVec.c b/src/map/fpga/fpgaVec.c
new file mode 100644
index 00000000..a8c6b983
--- /dev/null
+++ b/src/map/fpga/fpgaVec.c
@@ -0,0 +1,408 @@
+/**CFile****************************************************************
+
+ FileName [fpgaVec.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Technology mapping for variable-size-LUT FPGAs.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - August 18, 2004.]
+
+ Revision [$Id: fpgaVec.c,v 1.3 2005/01/23 06:59:42 alanmi Exp $]
+
+***********************************************************************/
+
+#include "fpgaInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Fpga_NodeVecCompareLevels( Fpga_Node_t ** pp1, Fpga_Node_t ** pp2 );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Allocates a vector with the given capacity.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_NodeVec_t * Fpga_NodeVecAlloc( int nCap )
+{
+ Fpga_NodeVec_t * p;
+ p = ALLOC( Fpga_NodeVec_t, 1 );
+ if ( nCap > 0 && nCap < 16 )
+ nCap = 16;
+ p->nSize = 0;
+ p->nCap = nCap;
+ p->pArray = p->nCap? ALLOC( Fpga_Node_t *, p->nCap ) : NULL;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_NodeVecFree( Fpga_NodeVec_t * p )
+{
+ FREE( p->pArray );
+ FREE( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_Node_t ** Fpga_NodeVecReadArray( Fpga_NodeVec_t * p )
+{
+ return p->pArray;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_NodeVecReadSize( Fpga_NodeVec_t * p )
+{
+ return p->nSize;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Resizes the vector to the given capacity.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_NodeVecGrow( Fpga_NodeVec_t * p, int nCapMin )
+{
+ if ( p->nCap >= nCapMin )
+ return;
+ p->pArray = REALLOC( Fpga_Node_t *, p->pArray, nCapMin );
+ p->nCap = nCapMin;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_NodeVecShrink( Fpga_NodeVec_t * p, int nSizeNew )
+{
+ assert( p->nSize >= nSizeNew );
+ p->nSize = nSizeNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_NodeVecClear( Fpga_NodeVec_t * p )
+{
+ p->nSize = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_NodeVecPush( Fpga_NodeVec_t * p, Fpga_Node_t * Entry )
+{
+ if ( p->nSize == p->nCap )
+ {
+ if ( p->nCap < 16 )
+ Fpga_NodeVecGrow( p, 16 );
+ else
+ Fpga_NodeVecGrow( p, 2 * p->nCap );
+ }
+ p->pArray[p->nSize++] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Add the element while ensuring uniqueness.]
+
+ Description [Returns 1 if the element was found, and 0 if it was new. ]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_NodeVecPushUnique( Fpga_NodeVec_t * p, Fpga_Node_t * Entry )
+{
+ int i;
+ for ( i = 0; i < p->nSize; i++ )
+ if ( p->pArray[i] == Entry )
+ return 1;
+ Fpga_NodeVecPush( p, Entry );
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_Node_t * Fpga_NodeVecPop( Fpga_NodeVec_t * p )
+{
+ return p->pArray[--p->nSize];
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_NodeVecWriteEntry( Fpga_NodeVec_t * p, int i, Fpga_Node_t * Entry )
+{
+ assert( i >= 0 && i < p->nSize );
+ p->pArray[i] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_Node_t * Fpga_NodeVecReadEntry( Fpga_NodeVec_t * p, int i )
+{
+ assert( i >= 0 && i < p->nSize );
+ return p->pArray[i];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Comparison procedure for two nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_NodeVecCompareLevels( Fpga_Node_t ** pp1, Fpga_Node_t ** pp2 )
+{
+ int Level1 = Fpga_Regular(*pp1)->Level;
+ int Level2 = Fpga_Regular(*pp2)->Level;
+ if ( Level1 < Level2 )
+ return -1;
+ if ( Level1 > Level2 )
+ return 1;
+ if ( Fpga_Regular(*pp1)->Num < Fpga_Regular(*pp2)->Num )
+ return -1;
+ if ( Fpga_Regular(*pp1)->Num > Fpga_Regular(*pp2)->Num )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sorting the entries by their integer value.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_NodeVecSortByLevel( Fpga_NodeVec_t * p )
+{
+ qsort( (void *)p->pArray, p->nSize, sizeof(Fpga_Node_t *),
+ (int (*)(const void *, const void *)) Fpga_NodeVecCompareLevels );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares the arrival times.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_NodeVecCompareArrivals( Fpga_Node_t ** ppS1, Fpga_Node_t ** ppS2 )
+{
+ if ( (*ppS1)->pCutBest->tArrival < (*ppS2)->pCutBest->tArrival )
+ return -1;
+ if ( (*ppS1)->pCutBest->tArrival > (*ppS2)->pCutBest->tArrival )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Orders the nodes in the increasing order of the arrival times.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_SortNodesByArrivalTimes( Fpga_NodeVec_t * p )
+{
+ qsort( (void *)p->pArray, p->nSize, sizeof(Fpga_Node_t *),
+ (int (*)(const void *, const void *)) Fpga_NodeVecCompareArrivals );
+// assert( Fpga_CompareNodesByLevel( p->pArray, p->pArray + p->nSize - 1 ) <= 0 );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Computes the union of nodes in two arrays.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_NodeVecUnion( Fpga_NodeVec_t * p, Fpga_NodeVec_t * p1, Fpga_NodeVec_t * p2 )
+{
+ int i;
+ Fpga_NodeVecClear( p );
+ for ( i = 0; i < p1->nSize; i++ )
+ Fpga_NodeVecPush( p, p1->pArray[i] );
+ for ( i = 0; i < p2->nSize; i++ )
+ Fpga_NodeVecPush( p, p2->pArray[i] );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Inserts a new node in the order by arrival times.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_NodeVecPushOrder( Fpga_NodeVec_t * vNodes, Fpga_Node_t * pNode, int fIncreasing )
+{
+ Fpga_Node_t * pNode1, * pNode2;
+ int i;
+ Fpga_NodeVecPush( vNodes, pNode );
+ // find the place of the node
+ for ( i = vNodes->nSize-1; i > 0; i-- )
+ {
+ pNode1 = vNodes->pArray[i ];
+ pNode2 = vNodes->pArray[i-1];
+ if ( fIncreasing && pNode1->pCutBest->tArrival >= pNode2->pCutBest->tArrival ||
+ !fIncreasing && pNode1->pCutBest->tArrival <= pNode2->pCutBest->tArrival )
+ break;
+ vNodes->pArray[i ] = pNode2;
+ vNodes->pArray[i-1] = pNode1;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Inserts a new node in the order by arrival times.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_NodeVecReverse( Fpga_NodeVec_t * vNodes )
+{
+ Fpga_Node_t * pNode1, * pNode2;
+ int i;
+ for ( i = 0; i < vNodes->nSize/2; i++ )
+ {
+ pNode1 = vNodes->pArray[i];
+ pNode2 = vNodes->pArray[vNodes->nSize-1-i];
+ vNodes->pArray[i] = pNode2;
+ vNodes->pArray[vNodes->nSize-1-i] = pNode1;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/map/fpga/module.make b/src/map/fpga/module.make
new file mode 100644
index 00000000..409e4b54
--- /dev/null
+++ b/src/map/fpga/module.make
@@ -0,0 +1,12 @@
+SRC += src/map/fpga/fpga.c \
+ src/map/fpga/fpgaCore.c \
+ src/map/fpga/fpgaCreate.c \
+ src/map/fpga/fpgaCut.c \
+ src/map/fpga/fpgaCutUtils.c \
+ src/map/fpga/fpgaFanout.c \
+ src/map/fpga/fpgaLib.c \
+ src/map/fpga/fpgaMatch.c \
+ src/map/fpga/fpgaTime.c \
+ src/map/fpga/fpgaTruth.c \
+ src/map/fpga/fpgaUtils.c \
+ src/map/fpga/fpgaVec.c
diff --git a/src/map/mapper/mapper.c b/src/map/mapper/mapper.c
new file mode 100644
index 00000000..546186a2
--- /dev/null
+++ b/src/map/mapper/mapper.c
@@ -0,0 +1,176 @@
+/**CFile****************************************************************
+
+ FileName [mapper.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Command file for the mapper package.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - June 1, 2004.]
+
+ Revision [$Id: mapper.c,v 1.7 2005/01/23 06:59:42 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+#include "mainInt.h"
+#include "mio.h"
+#include "mapperInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Map_CommandReadLibrary ( Abc_Frame_t * pAbc, int argc, char **argv );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_Init( Abc_Frame_t * pAbc )
+{
+ Cmd_CommandAdd( pAbc, "SC mapping", "read_super", Map_CommandReadLibrary, 0 );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_End()
+{
+// Map_SuperLibFree( s_pSuperLib );
+ Map_SuperLibFree( Abc_FrameReadLibSuper(Abc_FrameGetGlobalFrame()) );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_CommandReadLibrary( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ FILE * pFile;
+ FILE * pOut, * pErr;
+ Map_SuperLib_t * pLib;
+ Abc_Ntk_t * pNet;
+ char * FileName, * ExcludeFile;
+ int fVerbose;
+ int fAlgorithm;
+ int c;
+
+ pNet = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set the defaults
+ fVerbose = 1;
+ fAlgorithm = 1;
+ ExcludeFile = 0;
+ util_getopt_reset();
+ while ( (c = util_getopt(argc, argv, "eovh")) != EOF )
+ {
+ switch (c)
+ {
+ case 'e':
+ ExcludeFile = argv[util_optind];
+ if ( ExcludeFile == 0 )
+ goto usage;
+ util_optind++;
+ break;
+ case 'o':
+ fAlgorithm ^= 1;
+ break;
+ case 'v':
+ fVerbose ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ break;
+ default:
+ goto usage;
+ }
+ }
+
+
+ if ( argc != util_optind + 1 )
+ {
+ goto usage;
+ }
+
+ // get the input file name
+ FileName = argv[util_optind];
+// if ( (pFile = Io_FileOpen( FileName, "open_path", "r" )) == NULL )
+ if ( (pFile = fopen( FileName, "r" )) == NULL )
+ {
+ fprintf( pErr, "Cannot open input file \"%s\". ", FileName );
+ if ( FileName = Extra_FileGetSimilarName( FileName, ".genlib", ".lib", ".gen", ".g", NULL ) )
+ fprintf( pErr, "Did you mean \"%s\"?", FileName );
+ fprintf( pErr, "\n" );
+ return 1;
+ }
+ fclose( pFile );
+
+ // set the new network
+ pLib = Map_SuperLibCreate( FileName, ExcludeFile, fAlgorithm, fVerbose );
+ if ( pLib == NULL )
+ {
+ fprintf( pErr, "Reading supergate library has failed.\n" );
+ goto usage;
+ }
+ // replace the current library
+// Map_SuperLibFree( s_pSuperLib );
+// s_pSuperLib = pLib;
+ Map_SuperLibFree( Abc_FrameReadLibSuper(Abc_FrameGetGlobalFrame()) );
+ Abc_FrameSetLibSuper( Abc_FrameGetGlobalFrame(), pLib );
+ // replace the current genlib library
+// if ( s_pLib ) Mio_LibraryDelete( s_pLib );
+// s_pLib = s_pSuperLib->pGenlib;
+ Mio_LibraryDelete( Abc_FrameReadLibGen(Abc_FrameGetGlobalFrame()) );
+ Abc_FrameSetLibGen( Abc_FrameGetGlobalFrame(), pLib->pGenlib );
+ return 0;
+
+usage:
+ fprintf( pErr, "\nusage: read_super [-ovh]\n");
+ fprintf( pErr, "\t read the supergate library from the file\n" );
+ fprintf( pErr, "\t-e file : file contains list of genlib gates to exclude\n" );
+ fprintf( pErr, "\t-o : toggles the use of old file format [default = %s]\n", (fAlgorithm? "new" : "old") );
+ fprintf( pErr, "\t-v : toggles enabling of verbose output [default = %s]\n", (fVerbose? "yes" : "no") );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1; /* error exit */
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/mapper/mapper.h b/src/map/mapper/mapper.h
new file mode 100644
index 00000000..a6bfccf8
--- /dev/null
+++ b/src/map/mapper/mapper.h
@@ -0,0 +1,181 @@
+/**CFile****************************************************************
+
+ FileName [mapper.h]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Generic technology mapping engine.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - June 1, 2004.]
+
+ Revision [$Id: mapper.h,v 1.11 2005/02/28 05:34:26 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __MAPPER_H__
+#define __MAPPER_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct Map_ManStruct_t_ Map_Man_t;
+typedef struct Map_NodeStruct_t_ Map_Node_t;
+typedef struct Map_NodeVecStruct_t_ Map_NodeVec_t;
+typedef struct Map_CutStruct_t_ Map_Cut_t;
+typedef struct Map_MatchStruct_t_ Map_Match_t;
+typedef struct Map_SuperStruct_t_ Map_Super_t;
+typedef struct Map_SuperLibStruct_t_ Map_SuperLib_t;
+typedef struct Map_HashTableStruct_t_ Map_HashTable_t;
+typedef struct Map_HashEntryStruct_t_ Map_HashEntry_t;
+typedef struct Map_TimeStruct_t_ Map_Time_t;
+
+// the pair of rise/fall time parameters
+struct Map_TimeStruct_t_
+{
+ float Rise;
+ float Fall;
+ float Worst;
+};
+
+////////////////////////////////////////////////////////////////////////
+/// GLOBAL VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+#define Map_IsComplement(p) (((int)((long) (p) & 01)))
+#define Map_Regular(p) ((Map_Node_t *)((unsigned)(p) & ~01))
+#define Map_Not(p) ((Map_Node_t *)((long)(p) ^ 01))
+#define Map_NotCond(p,c) ((Map_Node_t *)((long)(p) ^ (c)))
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== mapperCreate.c =============================================================*/
+extern Map_Man_t * Map_ManCreate( int nInputs, int nOutputs, int fVerbose );
+extern Map_Node_t * Map_NodeCreate( Map_Man_t * p, Map_Node_t * p1, Map_Node_t * p2 );
+extern void Map_ManFree( Map_Man_t * pMan );
+extern void Map_ManPrintTimeStats( Map_Man_t * p );
+extern void Map_ManPrintStatsToFile( char * pName, float Area, float Delay, int Time );
+extern int Map_ManReadInputNum( Map_Man_t * p );
+extern int Map_ManReadOutputNum( Map_Man_t * p );
+extern Map_Node_t ** Map_ManReadInputs ( Map_Man_t * p );
+extern Map_Node_t ** Map_ManReadOutputs( Map_Man_t * p );
+extern Map_Node_t * Map_ManReadConst1 ( Map_Man_t * p );
+extern Map_Time_t * Map_ManReadInputArrivals( Map_Man_t * p );
+extern Mio_Library_t * Map_ManReadGenLib ( Map_Man_t * p );
+extern bool Map_ManReadVerbose( Map_Man_t * p );
+extern void Map_ManSetTimeToMap( Map_Man_t * p, int Time );
+extern void Map_ManSetTimeToNet( Map_Man_t * p, int Time );
+extern void Map_ManSetTimeSweep( Map_Man_t * p, int Time );
+extern void Map_ManSetTimeTotal( Map_Man_t * p, int Time );
+extern void Map_ManSetOutputNames( Map_Man_t * p, char ** ppNames );
+extern void Map_ManSetAreaRecovery( Map_Man_t * p, int fAreaRecovery );
+extern void Map_ManSetDelayTarget( Map_Man_t * p, float DelayTarget );
+extern void Map_ManSetInputArrivals( Map_Man_t * p, Map_Time_t * pArrivals );
+extern void Map_ManSetObeyFanoutLimits( Map_Man_t * p, bool fObeyFanoutLimits );
+extern void Map_ManSetNumIterations( Map_Man_t * p, int nNumIterations );
+extern int Map_ManReadPass( Map_Man_t * p );
+extern void Map_ManSetPass( Map_Man_t * p, int nPass );
+extern int Map_ManReadFanoutViolations( Map_Man_t * p );
+extern void Map_ManSetFanoutViolations( Map_Man_t * p, int nVio );
+extern void Map_ManSetChoiceNodeNum( Map_Man_t * p, int nChoiceNodes );
+extern void Map_ManSetChoiceNum( Map_Man_t * p, int nChoices );
+extern void Map_ManSetVerbose( Map_Man_t * p, int fVerbose );
+
+extern Map_Man_t * Map_NodeReadMan( Map_Node_t * p );
+extern char * Map_NodeReadData( Map_Node_t * p, int fPhase );
+extern int Map_NodeReadNum( Map_Node_t * p );
+extern int Map_NodeReadLevel( Map_Node_t * p );
+extern Map_Cut_t * Map_NodeReadCuts( Map_Node_t * p );
+extern Map_Cut_t * Map_NodeReadCutBest( Map_Node_t * p, int fPhase );
+extern Map_Node_t * Map_NodeReadOne( Map_Node_t * p );
+extern Map_Node_t * Map_NodeReadTwo( Map_Node_t * p );
+extern void Map_NodeSetData( Map_Node_t * p, int fPhase, char * pData );
+extern void Map_NodeSetNextE( Map_Node_t * p, Map_Node_t * pNextE );
+extern void Map_NodeSetRepr( Map_Node_t * p, Map_Node_t * pRepr );
+
+extern int Map_NodeIsConst( Map_Node_t * p );
+extern int Map_NodeIsVar( Map_Node_t * p );
+extern int Map_NodeIsAnd( Map_Node_t * p );
+extern int Map_NodeComparePhase( Map_Node_t * p1, Map_Node_t * p2 );
+
+extern Map_Super_t * Map_CutReadSuperBest( Map_Cut_t * p, int fPhase );
+extern Map_Super_t * Map_CutReadSuper0( Map_Cut_t * p );
+extern Map_Super_t * Map_CutReadSuper1( Map_Cut_t * p );
+extern int Map_CutReadLeavesNum( Map_Cut_t * p );
+extern Map_Node_t ** Map_CutReadLeaves( Map_Cut_t * p );
+extern unsigned Map_CutReadPhaseBest( Map_Cut_t * p, int fPhase );
+extern unsigned Map_CutReadPhase0( Map_Cut_t * p );
+extern unsigned Map_CutReadPhase1( Map_Cut_t * p );
+
+extern char * Map_SuperReadFormula( Map_Super_t * p );
+extern Mio_Gate_t * Map_SuperReadRoot( Map_Super_t * p );
+extern int Map_SuperReadNum( Map_Super_t * p );
+extern Map_Super_t ** Map_SuperReadFanins( Map_Super_t * p );
+extern int Map_SuperReadFaninNum( Map_Super_t * p );
+extern Map_Super_t * Map_SuperReadNext( Map_Super_t * p );
+extern int Map_SuperReadNumPhases( Map_Super_t * p );
+extern unsigned char * Map_SuperReadPhases( Map_Super_t * p );
+extern int Map_SuperReadFanoutLimit( Map_Super_t * p );
+
+extern Mio_Library_t * Map_SuperLibReadGenLib( Map_SuperLib_t * p );
+extern float Map_SuperLibReadAreaInv( Map_SuperLib_t * p );
+extern Map_Time_t Map_SuperLibReadDelayInv( Map_SuperLib_t * p );
+extern int Map_SuperLibReadVarsMax( Map_SuperLib_t * p );
+
+extern Map_Node_t * Map_NodeAnd( Map_Man_t * p, Map_Node_t * p1, Map_Node_t * p2 );
+extern Map_Node_t * Map_NodeOr( Map_Man_t * p, Map_Node_t * p1, Map_Node_t * p2 );
+extern Map_Node_t * Map_NodeExor( Map_Man_t * p, Map_Node_t * p1, Map_Node_t * p2 );
+extern Map_Node_t * Map_NodeMux( Map_Man_t * p, Map_Node_t * pNode, Map_Node_t * pNodeT, Map_Node_t * pNodeE );
+extern void Map_NodeSetChoice( Map_Man_t * pMan, Map_Node_t * pNodeOld, Map_Node_t * pNodeNew );
+
+/*=== resmCanon.c =============================================================*/
+extern int Map_CanonComputeSlow( unsigned uTruths[][2], int nVarsMax, int nVarsReal, unsigned uTruth[], unsigned char * puPhases, unsigned uTruthRes[] );
+/*=== mapperCut.c =============================================================*/
+extern void Map_MappingCreatePiCuts( Map_Man_t * p );
+extern Map_Cut_t * Map_CutAlloc( Map_Man_t * p );
+/*=== mapperCutUtils.c =============================================================*/
+extern void Map_CutCreateFromNode( Map_Man_t * p, Map_Super_t * pSuper, int iRoot, unsigned uPhaseRoot,
+ int * pLeaves, int nLeaves, unsigned uPhaseLeaves );
+/*=== mapperCore.c =============================================================*/
+extern int Map_Mapping( Map_Man_t * p );
+/*=== mapperLib.c =============================================================*/
+extern int Map_SuperLibDeriveFromGenlib( Mio_Library_t * pLib );
+/*=== mapperMntk.c =============================================================*/
+//extern Mntk_Man_t * Map_ConvertMappingToMntk( Map_Man_t * pMan );
+/*=== mapperSuper.c =============================================================*/
+extern char * Map_LibraryReadFormulaStep( char * pFormula, char * pStrings[], int * pnStrings );
+/*=== mapperSweep.c =============================================================*/
+extern void Map_NetworkSweep( Abc_Ntk_t * pNet );
+/*=== mapperTable.c =============================================================*/
+extern Map_Super_t * Map_SuperTableLookupC( Map_SuperLib_t * pLib, unsigned uTruth[] );
+/*=== mapperTime.c =============================================================*/
+/*=== mapperUtil.c =============================================================*/
+extern int Map_ManCheckConsistency( Map_Man_t * p );
+extern st_table * Map_CreateTableGate2Super( Map_Man_t * p );
+extern void Map_ManCleanData( Map_Man_t * p );
+extern void Map_MappingSetupTruthTables( unsigned uTruths[][2] );
+extern void Map_MappingSetupTruthTablesLarge( unsigned uTruths[][32] );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+#endif
diff --git a/src/map/mapper/mapperCanon.c b/src/map/mapper/mapperCanon.c
new file mode 100644
index 00000000..c5186c7e
--- /dev/null
+++ b/src/map/mapper/mapperCanon.c
@@ -0,0 +1,161 @@
+/**CFile****************************************************************
+
+ FileName [mapperCanon.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Generic technology mapping engine.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - June 1, 2004.]
+
+ Revision [$Id: mapperCanon.c,v 1.2 2005/01/23 06:59:42 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mapperInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static unsigned Map_CanonComputePhase( unsigned uTruths[][2], int nVars, unsigned uTruth, unsigned uPhase );
+static void Map_CanonComputePhase6( unsigned uTruths[][2], int nVars, unsigned uTruth[], unsigned uPhase, unsigned uTruthRes[] );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Computes the N-canonical form of the Boolean function.]
+
+ Description [The N-canonical form is defined as the truth table with
+ the minimum integer value. This function exhaustively enumerates
+ through the complete set of 2^N phase assignments.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_CanonComputeSlow( unsigned uTruths[][2], int nVarsMax, int nVarsReal, unsigned uTruth[], unsigned char * puPhases, unsigned uTruthRes[] )
+{
+ unsigned uTruthPerm[2];
+ int nMints, nPhases, m;
+
+ nPhases = 0;
+ nMints = (1 << nVarsReal);
+ if ( nVarsMax < 6 )
+ {
+ uTruthRes[0] = MAP_MASK(32);
+ for ( m = 0; m < nMints; m++ )
+ {
+ uTruthPerm[0] = Map_CanonComputePhase( uTruths, nVarsMax, uTruth[0], m );
+ if ( uTruthRes[0] > uTruthPerm[0] )
+ {
+ uTruthRes[0] = uTruthPerm[0];
+ nPhases = 0;
+ puPhases[nPhases++] = (unsigned char)m;
+ }
+ else if ( uTruthRes[0] == uTruthPerm[0] )
+ {
+ if ( nPhases < 4 ) // the max number of phases in Map_Super_t
+ puPhases[nPhases++] = (unsigned char)m;
+ }
+ }
+ uTruthRes[1] = uTruthRes[0];
+ }
+ else
+ {
+ uTruthRes[0] = MAP_MASK(32);
+ uTruthRes[1] = MAP_MASK(32);
+ for ( m = 0; m < nMints; m++ )
+ {
+ Map_CanonComputePhase6( uTruths, nVarsMax, uTruth, m, uTruthPerm );
+ if ( uTruthRes[1] > uTruthPerm[1] || uTruthRes[1] == uTruthPerm[1] && uTruthRes[0] > uTruthPerm[0] )
+ {
+ uTruthRes[0] = uTruthPerm[0];
+ uTruthRes[1] = uTruthPerm[1];
+ nPhases = 0;
+ puPhases[nPhases++] = (unsigned char)m;
+ }
+ else if ( uTruthRes[1] == uTruthPerm[1] && uTruthRes[0] == uTruthPerm[0] )
+ {
+ if ( nPhases < 4 ) // the max number of phases in Map_Super_t
+ puPhases[nPhases++] = (unsigned char)m;
+ }
+ }
+ }
+ assert( nPhases > 0 );
+// printf( "%d ", nPhases );
+ return nPhases;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs phase transformation for one function of less than 6 variables.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+unsigned Map_CanonComputePhase( unsigned uTruths[][2], int nVars, unsigned uTruth, unsigned uPhase )
+{
+ int v, Shift;
+ for ( v = 0, Shift = 1; v < nVars; v++, Shift <<= 1 )
+ if ( uPhase & Shift )
+ uTruth = (((uTruth & ~uTruths[v][0]) << Shift) | ((uTruth & uTruths[v][0]) >> Shift));
+ return uTruth;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs phase transformation for one function of 6 variables.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_CanonComputePhase6( unsigned uTruths[][2], int nVars, unsigned uTruth[], unsigned uPhase, unsigned uTruthRes[] )
+{
+ unsigned uTemp;
+ int v, Shift;
+
+ // initialize the result
+ uTruthRes[0] = uTruth[0];
+ uTruthRes[1] = uTruth[1];
+ if ( uPhase == 0 )
+ return;
+ // compute the phase
+ for ( v = 0, Shift = 1; v < nVars; v++, Shift <<= 1 )
+ if ( uPhase & Shift )
+ {
+ if ( Shift < 32 )
+ {
+ uTruthRes[0] = (((uTruthRes[0] & ~uTruths[v][0]) << Shift) | ((uTruthRes[0] & uTruths[v][0]) >> Shift));
+ uTruthRes[1] = (((uTruthRes[1] & ~uTruths[v][1]) << Shift) | ((uTruthRes[1] & uTruths[v][1]) >> Shift));
+ }
+ else
+ {
+ uTemp = uTruthRes[0];
+ uTruthRes[0] = uTruthRes[1];
+ uTruthRes[1] = uTemp;
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/mapper/mapperCore.c b/src/map/mapper/mapperCore.c
new file mode 100644
index 00000000..415e4974
--- /dev/null
+++ b/src/map/mapper/mapperCore.c
@@ -0,0 +1,167 @@
+/**CFile****************************************************************
+
+ FileName [mapperCore.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Generic technology mapping engine.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - June 1, 2004.]
+
+ Revision [$Id: mapperCore.c,v 1.7 2004/10/01 23:41:04 satrajit Exp $]
+
+***********************************************************************/
+
+#include "mapperInt.h"
+//#include "resm.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Performs technology mapping for the given object graph.]
+
+ Description [The object graph is stored in the mapping manager.
+ First, the AND nodes that fanout into POs are collected in the DFS order.
+ Two preprocessing steps are performed: the k-feasible cuts are computed
+ for each node and the truth tables are computed for each cut. Next, the
+ delay-optimal matches are assigned for each node, followed by several
+ iterations of area recoveryd: using area flow (global optimization)
+ and using exact area at a node (local optimization).]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_Mapping( Map_Man_t * p )
+{
+ int fUseAreaFlow = 1;
+ int fUseExactArea = 1;
+ int fUseExactAreaWithPhase = 1;
+ int clk;
+
+ //////////////////////////////////////////////////////////////////////
+ // perform pre-mapping computations
+ // collect the nodes reachable from POs in the DFS order (including the choices)
+ p->vAnds = Map_MappingDfs( p, 1 );
+ if ( p->fVerbose )
+ Map_MappingReportChoices( p );
+ Map_MappingSetChoiceLevels( p ); // should always be called before mapping!
+// return 1;
+
+ // compute the cuts of nodes in the DFS order
+ clk = clock();
+ Map_MappingCuts( p );
+ p->timeCuts = clock() - clk;
+ // derive the truth tables
+ clk = clock();
+ Map_MappingTruths( p );
+ p->timeTruth = clock() - clk;
+ //////////////////////////////////////////////////////////////////////
+
+ //////////////////////////////////////////////////////////////////////
+ // compute the minimum-delay mapping
+ clk = clock();
+ p->fMappingMode = 0;
+ if ( !Map_MappingMatches( p ) )
+ return 0;
+ p->timeMatch = clock() - clk;
+ // compute the references and collect the nodes used in the mapping
+ Map_MappingSetRefs( p );
+ p->AreaBase = Map_MappingGetArea( p, p->vMapping );
+if ( p->fVerbose )
+{
+printf( "Delay : FanViols = %5d Flow = %11.1f Area = %11.1f %4.1f %% ",
+ 0, Map_MappingGetAreaFlow(p), p->AreaBase, 0.0 );
+PRT( "Time", p->timeMatch );
+}
+ //////////////////////////////////////////////////////////////////////
+
+ //////////////////////////////////////////////////////////////////////
+ // perform area recovery using area flow
+ clk = clock();
+ if ( fUseAreaFlow )
+ {
+ // compute the required times and the fanouts
+ Map_TimeComputeRequiredGlobal( p );
+ // recover area flow
+ p->fMappingMode = 1;
+ Map_MappingMatches( p );
+ // compute the references and collect the nodes used in the mapping
+ Map_MappingSetRefs( p );
+ p->AreaFinal = Map_MappingGetArea( p, p->vMapping );
+if ( p->fVerbose )
+{
+printf( "AreaFlow : FanViols = %5d Flow = %11.1f Area = %11.1f %4.1f %% ",
+ 0, Map_MappingGetAreaFlow(p), p->AreaFinal,
+ 100.0*(p->AreaBase-p->AreaFinal)/p->AreaBase );
+PRT( "Time", clock() - clk );
+}
+ }
+ p->timeArea += clock() - clk;
+ //////////////////////////////////////////////////////////////////////
+
+ //////////////////////////////////////////////////////////////////////
+ // perform area recovery using exact area
+ clk = clock();
+ if ( fUseExactArea )
+ {
+ // compute the required times and the fanouts
+ Map_TimeComputeRequiredGlobal( p );
+ // recover area flow
+ p->fMappingMode = 2;
+ Map_MappingMatches( p );
+ // compute the references and collect the nodes used in the mapping
+ Map_MappingSetRefs( p );
+ p->AreaFinal = Map_MappingGetArea( p, p->vMapping );
+if ( p->fVerbose )
+{
+printf( "Area : FanViols = %5d Flow = %11.1f Area = %11.1f %4.1f %% ",
+ 0, 0.0, p->AreaFinal,
+ 100.0*(p->AreaBase-p->AreaFinal)/p->AreaBase );
+PRT( "Time", clock() - clk );
+}
+ }
+ p->timeArea += clock() - clk;
+ //////////////////////////////////////////////////////////////////////
+
+ //////////////////////////////////////////////////////////////////////
+ // perform area recovery using exact area
+ clk = clock();
+ if ( fUseExactAreaWithPhase )
+ {
+ // compute the required times and the fanouts
+ Map_TimeComputeRequiredGlobal( p );
+ // recover area flow
+ p->fMappingMode = 3;
+ Map_MappingMatches( p );
+ // compute the references and collect the nodes used in the mapping
+ Map_MappingSetRefs( p );
+ p->AreaFinal = Map_MappingGetArea( p, p->vMapping );
+if ( p->fVerbose )
+{
+printf( "Area : FanViols = %5d Flow = %11.1f Area = %11.1f %4.1f %% ",
+ 0, 0.0, p->AreaFinal,
+ 100.0*(p->AreaBase-p->AreaFinal)/p->AreaBase );
+PRT( "Time", clock() - clk );
+}
+ }
+ p->timeArea += clock() - clk;
+ //////////////////////////////////////////////////////////////////////
+
+ // print the arrival times of the latest outputs
+ if ( p->fVerbose )
+ Map_MappingPrintOutputArrivals( p );
+ return 1;
+}
diff --git a/src/map/mapper/mapperCreate.c b/src/map/mapper/mapperCreate.c
new file mode 100644
index 00000000..61c90d1c
--- /dev/null
+++ b/src/map/mapper/mapperCreate.c
@@ -0,0 +1,592 @@
+/**CFile****************************************************************
+
+ FileName [mapperCreate.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Generic technology mapping engine.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - June 1, 2004.]
+
+ Revision [$Id: mapperCreate.c,v 1.15 2005/02/28 05:34:26 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mapperInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Map_TableCreate( Map_Man_t * p );
+static void Map_TableResize( Map_Man_t * p );
+static Map_Node_t * Map_TableLookup( Map_Man_t * p, Map_Node_t * p1, Map_Node_t * p2 );
+
+// hash key for the structural hash table
+static inline unsigned Map_HashKey2( Map_Node_t * p0, Map_Node_t * p1, int TableSize ) { return ((unsigned)(p0) + (unsigned)(p1) * 12582917) % TableSize; }
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Reads parameters from the mapping manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_ManReadInputNum( Map_Man_t * p ) { return p->nInputs; }
+int Map_ManReadOutputNum( Map_Man_t * p ) { return p->nOutputs; }
+Map_Node_t ** Map_ManReadInputs ( Map_Man_t * p ) { return p->pInputs; }
+Map_Node_t ** Map_ManReadOutputs( Map_Man_t * p ) { return p->pOutputs; }
+Map_Node_t * Map_ManReadConst1 ( Map_Man_t * p ) { return p->pConst1; }
+Map_Time_t * Map_ManReadInputArrivals( Map_Man_t * p ) { return p->pInputArrivals;}
+Mio_Library_t * Map_ManReadGenLib ( Map_Man_t * p ) { return p->pSuperLib->pGenlib; }
+bool Map_ManReadVerbose( Map_Man_t * p ) { return p->fVerbose; }
+void Map_ManSetTimeToMap( Map_Man_t * p, int Time ) { p->timeToMap = Time; }
+void Map_ManSetTimeToNet( Map_Man_t * p, int Time ) { p->timeToNet = Time; }
+void Map_ManSetTimeSweep( Map_Man_t * p, int Time ) { p->timeSweep = Time; }
+void Map_ManSetTimeTotal( Map_Man_t * p, int Time ) { p->timeTotal = Time; }
+void Map_ManSetOutputNames( Map_Man_t * p, char ** ppNames ) { p->ppOutputNames = ppNames; }
+void Map_ManSetAreaRecovery( Map_Man_t * p, int fAreaRecovery ) { p->fAreaRecovery = fAreaRecovery;}
+void Map_ManSetDelayTarget( Map_Man_t * p, float DelayTarget ) { p->DelayTarget = DelayTarget;}
+void Map_ManSetInputArrivals( Map_Man_t * p, Map_Time_t * pArrivals ) { p->pInputArrivals = pArrivals;}
+void Map_ManSetObeyFanoutLimits( Map_Man_t * p, bool fObeyFanoutLimits ) { p->fObeyFanoutLimits = fObeyFanoutLimits; }
+void Map_ManSetNumIterations( Map_Man_t * p, int nIterations ) { p->nIterations = nIterations; }
+int Map_ManReadFanoutViolations( Map_Man_t * p ) { return p->nFanoutViolations; }
+void Map_ManSetFanoutViolations( Map_Man_t * p, int nVio ) { p->nFanoutViolations = nVio; }
+void Map_ManSetChoiceNodeNum( Map_Man_t * p, int nChoiceNodes ) { p->nChoiceNodes = nChoiceNodes; }
+void Map_ManSetChoiceNum( Map_Man_t * p, int nChoices ) { p->nChoices = nChoices; }
+void Map_ManSetVerbose( Map_Man_t * p, int fVerbose ) { p->fVerbose = fVerbose; }
+
+/**Function*************************************************************
+
+ Synopsis [Reads parameters from the mapping node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Man_t * Map_NodeReadMan( Map_Node_t * p ) { return p->p; }
+char * Map_NodeReadData( Map_Node_t * p, int fPhase ) { return fPhase? p->pData1 : p->pData0; }
+int Map_NodeReadNum( Map_Node_t * p ) { return p->Num; }
+int Map_NodeReadLevel( Map_Node_t * p ) { return Map_Regular(p)->Level; }
+Map_Cut_t * Map_NodeReadCuts( Map_Node_t * p ) { return p->pCuts; }
+Map_Cut_t * Map_NodeReadCutBest( Map_Node_t * p, int fPhase ) { return p->pCutBest[fPhase]; }
+Map_Node_t * Map_NodeReadOne( Map_Node_t * p ) { return p->p1; }
+Map_Node_t * Map_NodeReadTwo( Map_Node_t * p ) { return p->p2; }
+void Map_NodeSetData( Map_Node_t * p, int fPhase, char * pData ) { if (fPhase) p->pData1 = pData; else p->pData0 = pData; }
+void Map_NodeSetNextE( Map_Node_t * p, Map_Node_t * pNextE ) { p->pNextE = pNextE; }
+void Map_NodeSetRepr( Map_Node_t * p, Map_Node_t * pRepr ) { p->pRepr = pRepr; }
+
+/**Function*************************************************************
+
+ Synopsis [Checks the type of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_NodeIsConst( Map_Node_t * p ) { return (Map_Regular(p))->Num == -1; }
+int Map_NodeIsVar( Map_Node_t * p ) { return (Map_Regular(p))->p1 == NULL && (Map_Regular(p))->Num >= 0; }
+int Map_NodeIsAnd( Map_Node_t * p ) { return (Map_Regular(p))->p1 != NULL; }
+int Map_NodeComparePhase( Map_Node_t * p1, Map_Node_t * p2 ) { assert( !Map_IsComplement(p1) ); assert( !Map_IsComplement(p2) ); return p1->fInv ^ p2->fInv; }
+
+/**Function*************************************************************
+
+ Synopsis [Reads parameters from the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Super_t * Map_CutReadSuperBest( Map_Cut_t * p, int fPhase ) { return p->M[fPhase].pSuperBest;}
+Map_Super_t * Map_CutReadSuper0( Map_Cut_t * p ) { return p->M[0].pSuperBest;}
+Map_Super_t * Map_CutReadSuper1( Map_Cut_t * p ) { return p->M[1].pSuperBest;}
+int Map_CutReadLeavesNum( Map_Cut_t * p ) { return p->nLeaves; }
+Map_Node_t ** Map_CutReadLeaves( Map_Cut_t * p ) { return p->ppLeaves; }
+unsigned Map_CutReadPhaseBest( Map_Cut_t * p, int fPhase ) { return p->M[fPhase].uPhaseBest;}
+unsigned Map_CutReadPhase0( Map_Cut_t * p ) { return p->M[0].uPhaseBest;}
+unsigned Map_CutReadPhase1( Map_Cut_t * p ) { return p->M[1].uPhaseBest;}
+
+/**Function*************************************************************
+
+ Synopsis [Reads parameters from the supergate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Map_SuperReadFormula( Map_Super_t * p ) { return p->pFormula; }
+Mio_Gate_t * Map_SuperReadRoot( Map_Super_t * p ) { return p->pRoot; }
+int Map_SuperReadNum( Map_Super_t * p ) { return p->Num; }
+Map_Super_t ** Map_SuperReadFanins( Map_Super_t * p ) { return p->pFanins; }
+int Map_SuperReadFaninNum( Map_Super_t * p ) { return p->nFanins; }
+Map_Super_t * Map_SuperReadNext( Map_Super_t * p ) { return p->pNext; }
+int Map_SuperReadNumPhases( Map_Super_t * p ) { return p->nPhases; }
+unsigned char * Map_SuperReadPhases( Map_Super_t * p ) { return p->uPhases; }
+int Map_SuperReadFanoutLimit( Map_Super_t * p ) { return p->nFanLimit;}
+
+Mio_Library_t * Map_SuperLibReadGenLib( Map_SuperLib_t * p ) { return p->pGenlib; }
+float Map_SuperLibReadAreaInv( Map_SuperLib_t * p ) { return p->AreaInv; }
+Map_Time_t Map_SuperLibReadDelayInv( Map_SuperLib_t * p ) { return p->tDelayInv;}
+int Map_SuperLibReadVarsMax( Map_SuperLib_t * p ) { return p->nVarsMax; }
+
+
+/**Function*************************************************************
+
+ Synopsis [Create the mapping manager.]
+
+ Description [The number of inputs and outputs is assumed to be
+ known is advance. It is much simpler to have them fixed upfront.
+ When it comes to representing the object graph in the form of
+ AIG, the resulting manager is similar to the regular AIG manager,
+ except that it does not use reference counting (and therefore
+ does not have garbage collections). It does have table resizing.
+ The data structure is more flexible to represent additional
+ information needed for mapping.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Man_t * Map_ManCreate( int nInputs, int nOutputs, int fVerbose )
+{
+ Map_Man_t * p;
+ int i;
+
+ // derive the supergate library
+ if ( Abc_FrameReadLibSuper(Abc_FrameGetGlobalFrame()) == NULL )
+ {
+ printf( "The supergate library is not specified. Use \"read_library\" or \"read_super\".\n" );
+ return NULL;
+ }
+
+ // start the manager
+ p = ALLOC( Map_Man_t, 1 );
+ memset( p, 0, sizeof(Map_Man_t) );
+ p->pSuperLib = Abc_FrameReadLibSuper(Abc_FrameGetGlobalFrame());
+ p->nVarsMax = p->pSuperLib->nVarsMax;
+ p->fVerbose = fVerbose;
+ p->fEpsilon = (float)0.00001;
+ assert( p->nVarsMax > 0 );
+
+ // start various data structures
+ Map_TableCreate( p );
+ Map_MappingSetupTruthTables( p->uTruths );
+ Map_MappingSetupTruthTablesLarge( p->uTruthsLarge );
+// printf( "Node = %d bytes. Cut = %d bytes. Super = %d bytes.\n", sizeof(Map_Node_t), sizeof(Map_Cut_t), sizeof(Map_Super_t) );
+ p->mmNodes = Extra_MmFixedStart( sizeof(Map_Node_t) );
+ p->mmCuts = Extra_MmFixedStart( sizeof(Map_Cut_t) );
+
+ // make sure the constant node will get index -1
+ p->nNodes = -1;
+ // create the constant node
+ p->pConst1 = Map_NodeCreate( p, NULL, NULL );
+ p->vNodesAll = Map_NodeVecAlloc( 100 );
+ p->vNodesTemp = Map_NodeVecAlloc( 100 );
+ p->vMapping = Map_NodeVecAlloc( 100 );
+ p->vInside = Map_NodeVecAlloc( 100 );
+ p->vFanins = Map_NodeVecAlloc( 100 );
+
+ // create the PI nodes
+ p->nInputs = nInputs;
+ p->pInputs = ALLOC( Map_Node_t *, nInputs );
+ for ( i = 0; i < nInputs; i++ )
+ p->pInputs[i] = Map_NodeCreate( p, NULL, NULL );
+
+ // create the place for the output nodes
+ p->nOutputs = nOutputs;
+ p->pOutputs = ALLOC( Map_Node_t *, nOutputs );
+ memset( p->pOutputs, 0, sizeof(Map_Node_t *) * nOutputs );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Deallocates the mapping manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_ManFree( Map_Man_t * p )
+{
+// int i;
+// for ( i = 0; i < p->vNodesAll->nSize; i++ )
+// Map_NodeVecFree( p->vNodesAll->pArray[i]->vFanouts );
+// Map_NodeVecFree( p->pConst1->vFanouts );
+ if ( p->vInside )
+ Map_NodeVecFree( p->vInside );
+ if ( p->vFanins )
+ Map_NodeVecFree( p->vFanins );
+ if ( p->vAnds )
+ Map_NodeVecFree( p->vAnds );
+ if ( p->vNodesAll )
+ Map_NodeVecFree( p->vNodesAll );
+ if ( p->vNodesTemp )
+ Map_NodeVecFree( p->vNodesTemp );
+ if ( p->vMapping )
+ Map_NodeVecFree( p->vMapping );
+ Extra_MmFixedStop( p->mmNodes, 0 );
+ Extra_MmFixedStop( p->mmCuts, 0 );
+ FREE( p->pInputArrivals );
+ FREE( p->pInputs );
+ FREE( p->pOutputs );
+ FREE( p->pBins );
+// FREE( p->ppOutputNames );
+ if ( p->pSimInfo ) FREE( p->pSimInfo[0] );
+ FREE( p->pSimInfo );
+ FREE( p );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Deallocates the mapping manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_ManPrintTimeStats( Map_Man_t * p )
+{
+ printf( "N-canonical = %d. Matchings = %d. Phases = %d. ", p->nCanons, p->nMatches, p->nPhases );
+ printf( "Choice nodes = %d. Choices = %d.\n", p->nChoiceNodes, p->nChoices );
+ PRT( "ToMap", p->timeToMap );
+ PRT( "Cuts ", p->timeCuts );
+ PRT( "Truth", p->timeTruth );
+ PRT( "Match", p->timeMatch );
+ PRT( "Area ", p->timeArea );
+ PRT( "Sweep", p->timeSweep );
+ PRT( "ToNet", p->timeToNet );
+ PRT( "TOTAL", p->timeTotal );
+ if ( p->time1 ) { PRT( "time1", p->time1 ); }
+ if ( p->time2 ) { PRT( "time2", p->time2 ); }
+ if ( p->time3 ) { PRT( "time3", p->time3 ); }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the mapping stats.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_ManPrintStatsToFile( char * pName, float Area, float Delay, int Time )
+{
+ FILE * pTable;
+ pTable = fopen( "stats.txt", "a+" );
+ fprintf( pTable, "%s ", pName );
+ fprintf( pTable, "%4.2f ", Area );
+ fprintf( pTable, "%4.2f ", Delay );
+ fprintf( pTable, "%4.2f\n", (float)(Time)/(float)(CLOCKS_PER_SEC) );
+ fclose( pTable );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates a new node.]
+
+ Description [This procedure should be called to create the constant
+ node and the PI nodes first.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Node_t * Map_NodeCreate( Map_Man_t * p, Map_Node_t * p1, Map_Node_t * p2 )
+{
+ Map_Node_t * pNode;
+ // create the node
+ pNode = (Map_Node_t *)Extra_MmFixedEntryFetch( p->mmNodes );
+ memset( pNode, 0, sizeof(Map_Node_t) );
+ pNode->tRequired[0].Rise = pNode->tRequired[0].Fall = pNode->tRequired[0].Worst = MAP_FLOAT_LARGE;
+ pNode->tRequired[1].Rise = pNode->tRequired[1].Fall = pNode->tRequired[1].Worst = MAP_FLOAT_LARGE;
+ pNode->p1 = p1;
+ pNode->p2 = p2;
+ pNode->p = p;
+ // set the number of this node
+ pNode->Num = p->nNodes++;
+ // place to store the fanouts
+// pNode->vFanouts = Map_NodeVecAlloc( 5 );
+ // store this node in the internal array
+ if ( pNode->Num >= 0 )
+ Map_NodeVecPush( p->vNodesAll, pNode );
+ else
+ pNode->fInv = 1;
+ // set the level of this node
+ if ( p1 )
+ {
+ // create the fanout info
+ Map_NodeAddFaninFanout( Map_Regular(p1), pNode );
+ Map_NodeAddFaninFanout( Map_Regular(p2), pNode );
+ pNode->Level = 1 + MAP_MAX(Map_Regular(pNode->p1)->Level, Map_Regular(pNode->p2)->Level);
+ pNode->fInv = Map_NodeIsSimComplement(p1) & Map_NodeIsSimComplement(p2);
+ }
+ // reference the inputs (will be used to compute the number of fanouts)
+ if ( p1 ) Map_NodeRef(p1);
+ if ( p2 ) Map_NodeRef(p2);
+
+ pNode->nRefEst[0] = pNode->nRefEst[1] = -1;
+ return pNode;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Create the unique table of AND gates.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_TableCreate( Map_Man_t * pMan )
+{
+ assert( pMan->pBins == NULL );
+ pMan->nBins = Cudd_Prime(5000);
+ pMan->pBins = ALLOC( Map_Node_t *, pMan->nBins );
+ memset( pMan->pBins, 0, sizeof(Map_Node_t *) * pMan->nBins );
+ pMan->nNodes = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Looks up the AND2 node in the unique table.]
+
+ Description [This procedure implements one-level hashing. All the nodes
+ are hashed by their children. If the node with the same children was already
+ created, it is returned by the call to this procedure. If it does not exist,
+ this procedure creates a new node with these children. ]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Node_t * Map_TableLookup( Map_Man_t * pMan, Map_Node_t * p1, Map_Node_t * p2 )
+{
+ Map_Node_t * pEnt;
+ unsigned Key;
+
+ if ( p1 == p2 )
+ return p1;
+ if ( p1 == Map_Not(p2) )
+ return Map_Not(pMan->pConst1);
+ if ( Map_NodeIsConst(p1) )
+ {
+ if ( p1 == pMan->pConst1 )
+ return p2;
+ return Map_Not(pMan->pConst1);
+ }
+ if ( Map_NodeIsConst(p2) )
+ {
+ if ( p2 == pMan->pConst1 )
+ return p1;
+ return Map_Not(pMan->pConst1);
+ }
+
+ if ( Map_Regular(p1)->Num > Map_Regular(p2)->Num )
+ pEnt = p1, p1 = p2, p2 = pEnt;
+
+ Key = Map_HashKey2( p1, p2, pMan->nBins );
+ for ( pEnt = pMan->pBins[Key]; pEnt; pEnt = pEnt->pNext )
+ if ( pEnt->p1 == p1 && pEnt->p2 == p2 )
+ return pEnt;
+ // resize the table
+ if ( pMan->nNodes >= 2 * pMan->nBins )
+ {
+ Map_TableResize( pMan );
+ Key = Map_HashKey2( p1, p2, pMan->nBins );
+ }
+ // create the new node
+ pEnt = Map_NodeCreate( pMan, p1, p2 );
+ // add the node to the corresponding linked list in the table
+ pEnt->pNext = pMan->pBins[Key];
+ pMan->pBins[Key] = pEnt;
+ return pEnt;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Resizes the table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_TableResize( Map_Man_t * pMan )
+{
+ Map_Node_t ** pBinsNew;
+ Map_Node_t * pEnt, * pEnt2;
+ int nBinsNew, Counter, i, clk;
+ unsigned Key;
+
+clk = clock();
+ // get the new table size
+ nBinsNew = Cudd_Prime(2 * pMan->nBins);
+ // allocate a new array
+ pBinsNew = ALLOC( Map_Node_t *, nBinsNew );
+ memset( pBinsNew, 0, sizeof(Map_Node_t *) * nBinsNew );
+ // rehash the entries from the old table
+ Counter = 0;
+ for ( i = 0; i < pMan->nBins; i++ )
+ for ( pEnt = pMan->pBins[i], pEnt2 = pEnt? pEnt->pNext: NULL; pEnt;
+ pEnt = pEnt2, pEnt2 = pEnt? pEnt->pNext: NULL )
+ {
+ Key = Map_HashKey2( pEnt->p1, pEnt->p2, nBinsNew );
+ pEnt->pNext = pBinsNew[Key];
+ pBinsNew[Key] = pEnt;
+ Counter++;
+ }
+ assert( Counter == pMan->nNodes - pMan->nInputs );
+ if ( pMan->fVerbose )
+ {
+// printf( "Increasing the unique table size from %6d to %6d. ", pMan->nBins, nBinsNew );
+// PRT( "Time", clock() - clk );
+ }
+ // replace the table and the parameters
+ free( pMan->pBins );
+ pMan->pBins = pBinsNew;
+ pMan->nBins = nBinsNew;
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Node_t * Map_NodeAnd( Map_Man_t * p, Map_Node_t * p1, Map_Node_t * p2 )
+{
+ Map_Node_t * pNode;
+ pNode = Map_TableLookup( p, p1, p2 );
+ return pNode;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Node_t * Map_NodeOr( Map_Man_t * p, Map_Node_t * p1, Map_Node_t * p2 )
+{
+ Map_Node_t * pNode;
+ pNode = Map_Not( Map_TableLookup( p, Map_Not(p1), Map_Not(p2) ) );
+ return pNode;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Node_t * Map_NodeExor( Map_Man_t * p, Map_Node_t * p1, Map_Node_t * p2 )
+{
+ return Map_NodeMux( p, p1, Map_Not(p2), p2 );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Node_t * Map_NodeMux( Map_Man_t * p, Map_Node_t * pC, Map_Node_t * pT, Map_Node_t * pE )
+{
+ Map_Node_t * pAnd1, * pAnd2, * pRes;
+ pAnd1 = Map_TableLookup( p, pC, pT );
+ pAnd2 = Map_TableLookup( p, Map_Not(pC), pE );
+ pRes = Map_NodeOr( p, pAnd1, pAnd2 );
+ return pRes;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Sets the node to be equivalent to the given one.]
+
+ Description [This procedure is a work-around for the equivalence check.
+ Does not verify the equivalence. Use at the user's risk.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_NodeSetChoice( Map_Man_t * pMan, Map_Node_t * pNodeOld, Map_Node_t * pNodeNew )
+{
+ pNodeNew->pNextE = pNodeOld->pNextE;
+ pNodeOld->pNextE = pNodeNew;
+ pNodeNew->pRepr = pNodeOld;
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/map/mapper/mapperCut.c b/src/map/mapper/mapperCut.c
new file mode 100644
index 00000000..87592365
--- /dev/null
+++ b/src/map/mapper/mapperCut.c
@@ -0,0 +1,1072 @@
+/**CFile****************************************************************
+
+ FileName [mapperCut.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Generic technology mapping engine.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - June 1, 2004.]
+
+ Revision [$Id: mapperCut.c,v 1.12 2005/02/28 05:34:27 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mapperInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// the largest number of cuts considered
+#define MAP_CUTS_MAX_COMPUTE 200
+// the largest number of cuts used
+#define MAP_CUTS_MAX_USE 50
+
+// temporary hash table to store the cuts
+typedef struct Map_CutTableStrutct_t Map_CutTable_t;
+struct Map_CutTableStrutct_t
+{
+ Map_Cut_t ** pBins; // the table used for linear probing
+ int nBins; // the size of the table
+ int * pCuts; // the array of cuts currently stored
+ int nCuts; // the number of cuts currently stored
+ Map_Cut_t ** pArray; // the temporary array of cuts
+ Map_Cut_t ** pCuts1; // the temporary array of cuts
+ Map_Cut_t ** pCuts2; // the temporary array of cuts
+};
+
+// primes used to compute the hash key
+static int s_HashPrimes[10] = { 109, 499, 557, 619, 631, 709, 797, 881, 907, 991 };
+
+static Map_Cut_t * Map_CutCompute( Map_Man_t * p, Map_CutTable_t * pTable, Map_Node_t * pNode );
+static void Map_CutFilter( Map_Man_t * p, Map_Node_t * pNode );
+static Map_Cut_t * Map_CutMergeLists( Map_Man_t * p, Map_CutTable_t * pTable, Map_Cut_t * pList1, Map_Cut_t * pList2, int fComp1, int fComp2 );
+static int Map_CutMergeTwo( Map_Cut_t * pCut1, Map_Cut_t * pCut2, Map_Node_t * ppNodes[], int nNodesMax );
+static Map_Cut_t * Map_CutUnionLists( Map_Cut_t * pList1, Map_Cut_t * pList2 );
+static int Map_CutBelongsToList( Map_Cut_t * pList, Map_Node_t * ppNodes[], int nNodes );
+
+static void Map_CutListPrint( Map_Man_t * pMan, Map_Node_t * pRoot );
+static void Map_CutListPrint2( Map_Man_t * pMan, Map_Node_t * pRoot );
+static void Map_CutPrint_( Map_Man_t * pMan, Map_Cut_t * pCut, Map_Node_t * pRoot );
+
+static Map_CutTable_t * Map_CutTableStart( Map_Man_t * pMan );
+static void Map_CutTableStop( Map_CutTable_t * p );
+static unsigned Map_CutTableHash( Map_Node_t * ppNodes[], int nNodes );
+static int Map_CutTableLookup( Map_CutTable_t * p, Map_Node_t * ppNodes[], int nNodes );
+static Map_Cut_t * Map_CutTableConsider( Map_Man_t * pMan, Map_CutTable_t * p, Map_Node_t * ppNodes[], int nNodes );
+static void Map_CutTableRestart( Map_CutTable_t * p );
+
+static Map_Cut_t * Map_CutSortCuts( Map_Man_t * pMan, Map_CutTable_t * p, Map_Cut_t * pList );
+static int Map_CutList2Array( Map_Cut_t ** pArray, Map_Cut_t * pList );
+static Map_Cut_t * Map_CutArray2List( Map_Cut_t ** pArray, int nCuts );
+
+
+// iterator through all the cuts of the list
+#define Map_ListForEachCut( pList, pCut ) \
+ for ( pCut = pList; \
+ pCut; \
+ pCut = pCut->pNext )
+#define Map_ListForEachCutSafe( pList, pCut, pCut2 ) \
+ for ( pCut = pList, \
+ pCut2 = pCut? pCut->pNext: NULL; \
+ pCut; \
+ pCut = pCut2, \
+ pCut2 = pCut? pCut->pNext: NULL )
+
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Computes the cuts for each node in the object graph.]
+
+ Description [The cuts are computed in one sweep over the mapping graph.
+ First, the elementary cuts, which include the node itself, are assigned
+ to the PI nodes. The internal nodes are considered in the DFS order.
+ Each node is two-input AND-gate. So to compute the cuts at a node, we
+ need to merge the sets of cuts of its two predecessors. The merged set
+ contains only unique cuts with the number of inputs equal to k or less.
+ Finally, the elementary cut, composed of the node itself, is added to
+ the set of cuts for the node.
+
+ This procedure is pretty fast for 5-feasible cuts, but it dramatically
+ slows down on some "dense" networks when computing 6-feasible cuts.
+ The problem is that there are too many cuts in this case. We should
+ think how to heuristically trim the number of cuts in such cases,
+ to have reasonable runtime.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingCuts( Map_Man_t * p )
+{
+ ProgressBar * pProgress;
+ Map_CutTable_t * pTable;
+ Map_Node_t * pNode;
+ Map_Cut_t * pCut;
+ int nCuts, nNodes, i;
+ // set the elementary cuts for the PI variables
+ assert( p->nVarsMax > 1 && p->nVarsMax < 7 );
+ for ( i = 0; i < p->nInputs; i++ )
+ {
+ pCut = Map_CutAlloc( p );
+ pCut->nLeaves = 1;
+ pCut->ppLeaves[0] = p->pInputs[i];
+// pCut->fLevel = (float)pCut->ppLeaves[0]->Level;
+ p->pInputs[i]->pCuts = pCut;
+ p->pInputs[i]->pCutBest[0] = NULL; // negative polarity is not mapped
+ p->pInputs[i]->pCutBest[1] = pCut; // positive polarity is a trivial cut
+ pCut->M[0].AreaFlow = 0.0;
+ pCut->M[1].AreaFlow = 0.0;
+ }
+
+ // compute the cuts for the internal nodes
+ nNodes = p->vAnds->nSize;
+ pProgress = Extra_ProgressBarStart( stdout, nNodes );
+ pTable = Map_CutTableStart( p );
+ for ( i = 0; i < nNodes; i++ )
+ {
+ pNode = p->vAnds->pArray[i];
+ if ( !Map_NodeIsAnd( pNode ) )
+ continue;
+ Map_CutCompute( p, pTable, pNode );
+ Extra_ProgressBarUpdate( pProgress, i, "Cuts ..." );
+ }
+ Extra_ProgressBarStop( pProgress );
+ Map_CutTableStop( pTable );
+
+ // report the stats
+ if ( p->fVerbose )
+ {
+ nCuts = Map_MappingCountAllCuts(p);
+ printf( "Nodes = %6d. Total %d-feasible cuts = %d. Cuts per node = %.1f.\n",
+ p->nNodes, p->nVarsMax, nCuts, ((float)nCuts)/p->nNodes );
+ }
+
+ // print the cuts for the first primary output
+// Map_CutListPrint( p, Map_Regular(p->pOutputs[0]) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs technology mapping for variable-size-LUTs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingCreatePiCuts( Map_Man_t * p )
+{
+ Map_Cut_t * pCut;
+ int i;
+
+ // set the elementary cuts for the PI variables
+ for ( i = 0; i < p->nInputs; i++ )
+ {
+ pCut = Map_CutAlloc( p );
+ pCut->nLeaves = 1;
+ pCut->ppLeaves[0] = p->pInputs[i];
+// pCut->fLevel = (float)pCut->ppLeaves[0]->Level;
+ p->pInputs[i]->pCuts = pCut;
+ p->pInputs[i]->pCutBest[1] = pCut;
+ p->pInputs[i]->pCutBest[0] = pCut;
+ // set the input arrival times
+// p->pInputs[i]->pCut[1]->tArrival = p->pInputArrivals[i];
+
+ // set the input arrival times
+ pCut = p->pInputs[i]->pCutBest[1];
+ pCut->M[1].tArrive = p->pInputArrivals[i];
+ pCut->M[1].tArrive.Worst = MAP_MAX( pCut->M[1].tArrive.Rise, pCut->M[1].tArrive.Fall );
+ // set the arrival times of the negative phases of the PI nodes
+ pCut = p->pInputs[i]->pCutBest[0];
+ pCut->M[0].tArrive.Rise = p->pInputArrivals[i].Fall + p->pSuperLib->tDelayInv.Rise;
+ pCut->M[0].tArrive.Fall = p->pInputArrivals[i].Rise + p->pSuperLib->tDelayInv.Fall;
+ pCut->M[0].tArrive.Worst = MAP_MAX( pCut->M[0].tArrive.Rise, pCut->M[0].tArrive.Fall );
+
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the cuts for one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Cut_t * Map_CutCompute( Map_Man_t * p, Map_CutTable_t * pTable, Map_Node_t * pNode )
+{
+ Map_Node_t * pTemp;
+ Map_Cut_t * pList, * pList1, * pList2;
+ Map_Cut_t * pCut;
+
+ // if the cuts are computed return them
+ if ( pNode->pCuts )
+ return pNode->pCuts;
+
+ // compute the cuts for the children
+ pList1 = Map_Regular(pNode->p1)->pCuts;
+ pList2 = Map_Regular(pNode->p2)->pCuts;
+ // merge the lists
+ pList = Map_CutMergeLists( p, pTable, pList1, pList2,
+ Map_IsComplement(pNode->p1), Map_IsComplement(pNode->p2) );
+ // if there are functionally equivalent nodes, union them with this list
+ assert( pList );
+ // only add to the list of cuts if the node is a representative one
+ if ( pNode->pRepr == NULL )
+ {
+ for ( pTemp = pNode->pNextE; pTemp; pTemp = pTemp->pNextE )
+ {
+ assert( pTemp->pCuts );
+ pList = Map_CutUnionLists( pList, pTemp->pCuts );
+ assert( pTemp->pCuts );
+ pList = Map_CutSortCuts( p, pTable, pList );
+ }
+ }
+ // add the new cut
+ pCut = Map_CutAlloc( p );
+ pCut->nLeaves = 1;
+ pCut->ppLeaves[0] = pNode;
+// pCut->fLevel = (float)pCut->ppLeaves[0]->Level;
+ // append (it is important that the elementary cut is appended first)
+ pCut->pNext = pList;
+ // set at the node
+ pNode->pCuts = pCut;
+ // remove the dominated cuts
+// Map_CutFilter( p, pNode );
+ // set the phase correctly
+ if ( pNode->pRepr && Map_NodeComparePhase(pNode, pNode->pRepr) )
+ {
+ Map_ListForEachCut( pNode->pCuts, pCut )
+ pCut->Phase = 1;
+ }
+/*
+ {
+ int i, Counter = 0;;
+ for ( pCut = pNode->pCuts->pNext; pCut; pCut = pCut->pNext )
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ Counter += (pCut->ppLeaves[i]->Level >= pNode->Level);
+// if ( Counter )
+// printf( " %d", Counter );
+ }
+*/
+ return pCut;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Filter the cuts using dominance.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_CutFilter( Map_Man_t * p, Map_Node_t * pNode )
+{
+ Map_Cut_t * pTemp, * pPrev, * pCut, * pCut2;
+ int i, k, Counter;
+
+ Counter = 0;
+ pPrev = pNode->pCuts;
+ Map_ListForEachCutSafe( pNode->pCuts->pNext, pCut, pCut2 )
+ {
+ // go through all the previous cuts up to pCut
+ for ( pTemp = pNode->pCuts->pNext; pTemp != pCut; pTemp = pTemp->pNext )
+ {
+ // check if every node in pTemp is contained in pCut
+ for ( i = 0; i < pTemp->nLeaves; i++ )
+ {
+ for ( k = 0; k < pCut->nLeaves; k++ )
+ if ( pTemp->ppLeaves[i] == pCut->ppLeaves[k] )
+ break;
+ if ( k == pCut->nLeaves ) // node i in pTemp is not contained in pCut
+ break;
+ }
+ if ( i == pTemp->nLeaves ) // every node in pTemp is contained in pCut
+ {
+ Counter++;
+ break;
+ }
+ }
+ if ( pTemp != pCut ) // pTemp contain pCut
+ {
+ pPrev->pNext = pCut->pNext; // skip pCut
+ // recycle pCut
+ Map_CutFree( p, pCut );
+ }
+ else
+ pPrev = pCut;
+ }
+// printf( "Dominated = %3d. \n", Counter );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Merges two lists of cuts.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Cut_t * Map_CutMergeLists( Map_Man_t * p, Map_CutTable_t * pTable,
+ Map_Cut_t * pList1, Map_Cut_t * pList2, int fComp1, int fComp2 )
+{
+ Map_Node_t * ppNodes[6];
+ Map_Cut_t * pListNew, ** ppListNew, * pLists[7] = { NULL };
+ Map_Cut_t * pCut, * pPrev, * pTemp1, * pTemp2;
+ int nNodes, Counter, i;
+ Map_Cut_t ** ppArray1, ** ppArray2, ** ppArray3;
+ int nCuts1, nCuts2, nCuts3, k, fComp3;
+
+ ppArray1 = pTable->pCuts1;
+ ppArray2 = pTable->pCuts2;
+ nCuts1 = Map_CutList2Array( ppArray1, pList1 );
+ nCuts2 = Map_CutList2Array( ppArray2, pList2 );
+ // swap the lists based on their length
+ if ( nCuts1 > nCuts2 )
+ {
+ ppArray3 = ppArray1;
+ ppArray1 = ppArray2;
+ ppArray2 = ppArray3;
+
+ nCuts3 = nCuts1;
+ nCuts1 = nCuts2;
+ nCuts2 = nCuts3;
+
+ fComp3 = fComp1;
+ fComp1 = fComp2;
+ fComp2 = fComp3;
+ }
+ // pList1 is shorter or equal length compared to pList2
+
+ // prepare the manager for the cut computation
+ Map_CutTableRestart( pTable );
+ // go through the cut pairs
+ Counter = 0;
+// for ( pTemp1 = pList1; pTemp1; pTemp1 = fPivot1? NULL: pTemp1->pNext )
+// for ( pTemp2 = pList2; pTemp2; pTemp2 = fPivot2? NULL: pTemp2->pNext )
+ for ( i = 0; i < nCuts1; i++ )
+ {
+ for ( k = 0; k <= i; k++ )
+ {
+ pTemp1 = ppArray1[i];
+ pTemp2 = ppArray2[k];
+
+ // check if k-feasible cut exists
+ nNodes = Map_CutMergeTwo( pTemp1, pTemp2, ppNodes, p->nVarsMax );
+ if ( nNodes == 0 )
+ continue;
+ // consider the cut for possible addition to the set of new cuts
+ pCut = Map_CutTableConsider( p, pTable, ppNodes, nNodes );
+ if ( pCut == NULL )
+ continue;
+ // add data to the cut
+ pCut->pOne = Map_CutNotCond( pTemp1, fComp1 );
+ pCut->pTwo = Map_CutNotCond( pTemp2, fComp2 );
+ // add it to the corresponding list
+ pCut->pNext = pLists[pCut->nLeaves];
+ pLists[pCut->nLeaves] = pCut;
+ // count this cut and quit if limit is reached
+ Counter++;
+ if ( Counter == MAP_CUTS_MAX_COMPUTE )
+ goto QUITS;
+ }
+ for ( k = 0; k < i; k++ )
+ {
+ pTemp1 = ppArray1[k];
+ pTemp2 = ppArray2[i];
+
+ // check if k-feasible cut exists
+ nNodes = Map_CutMergeTwo( pTemp1, pTemp2, ppNodes, p->nVarsMax );
+ if ( nNodes == 0 )
+ continue;
+ // consider the cut for possible addition to the set of new cuts
+ pCut = Map_CutTableConsider( p, pTable, ppNodes, nNodes );
+ if ( pCut == NULL )
+ continue;
+ // add data to the cut
+ pCut->pOne = Map_CutNotCond( pTemp1, fComp1 );
+ pCut->pTwo = Map_CutNotCond( pTemp2, fComp2 );
+ // add it to the corresponding list
+ pCut->pNext = pLists[pCut->nLeaves];
+ pLists[pCut->nLeaves] = pCut;
+ // count this cut and quit if limit is reached
+ Counter++;
+ if ( Counter == MAP_CUTS_MAX_COMPUTE )
+ goto QUITS;
+ }
+ }
+ // consider the rest of them
+ for ( i = nCuts1; i < nCuts2; i++ )
+ for ( k = 0; k < nCuts1; k++ )
+ {
+ pTemp1 = ppArray1[k];
+ pTemp2 = ppArray2[i];
+
+ // check if k-feasible cut exists
+ nNodes = Map_CutMergeTwo( pTemp1, pTemp2, ppNodes, p->nVarsMax );
+ if ( nNodes == 0 )
+ continue;
+ // consider the cut for possible addition to the set of new cuts
+ pCut = Map_CutTableConsider( p, pTable, ppNodes, nNodes );
+ if ( pCut == NULL )
+ continue;
+ // add data to the cut
+ pCut->pOne = Map_CutNotCond( pTemp1, fComp1 );
+ pCut->pTwo = Map_CutNotCond( pTemp2, fComp2 );
+ // add it to the corresponding list
+ pCut->pNext = pLists[pCut->nLeaves];
+ pLists[pCut->nLeaves] = pCut;
+ // count this cut and quit if limit is reached
+ Counter++;
+ if ( Counter == MAP_CUTS_MAX_COMPUTE )
+ goto QUITS;
+ }
+QUITS :
+ // combine all the lists into one
+ pListNew = NULL;
+ ppListNew = &pListNew;
+ for ( i = 1; i <= p->nVarsMax; i++ )
+ {
+ if ( pLists[i] == NULL )
+ continue;
+ // find the last entry
+ for ( pPrev = pLists[i], pCut = pPrev->pNext; pCut;
+ pPrev = pCut, pCut = pCut->pNext );
+ // connect these lists
+ *ppListNew = pLists[i];
+ ppListNew = &pPrev->pNext;
+ }
+ *ppListNew = NULL;
+ // soft the cuts by arrival times and use only the first MAP_CUTS_MAX_USE
+ pListNew = Map_CutSortCuts( p, pTable, pListNew );
+ return pListNew;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Merges two lists of cuts.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Cut_t * Map_CutMergeLists2( Map_Man_t * p, Map_CutTable_t * pTable,
+ Map_Cut_t * pList1, Map_Cut_t * pList2, int fComp1, int fComp2 )
+{
+ Map_Node_t * ppNodes[6];
+ Map_Cut_t * pListNew, ** ppListNew, * pLists[7] = { NULL };
+ Map_Cut_t * pCut, * pPrev, * pTemp1, * pTemp2;
+ int nNodes, Counter, i;
+
+ // prepare the manager for the cut computation
+ Map_CutTableRestart( pTable );
+ // go through the cut pairs
+ Counter = 0;
+ for ( pTemp1 = pList1; pTemp1; pTemp1 = pTemp1->pNext )
+ for ( pTemp2 = pList2; pTemp2; pTemp2 = pTemp2->pNext )
+ {
+ // check if k-feasible cut exists
+ nNodes = Map_CutMergeTwo( pTemp1, pTemp2, ppNodes, p->nVarsMax );
+ if ( nNodes == 0 )
+ continue;
+ // consider the cut for possible addition to the set of new cuts
+ pCut = Map_CutTableConsider( p, pTable, ppNodes, nNodes );
+ if ( pCut == NULL )
+ continue;
+ // add data to the cut
+ pCut->pOne = Map_CutNotCond( pTemp1, fComp1 );
+ pCut->pTwo = Map_CutNotCond( pTemp2, fComp2 );
+ // add it to the corresponding list
+ pCut->pNext = pLists[pCut->nLeaves];
+ pLists[pCut->nLeaves] = pCut;
+ // count this cut and quit if limit is reached
+ Counter++;
+ if ( Counter == MAP_CUTS_MAX_COMPUTE )
+ goto QUITS;
+ }
+QUITS :
+ // combine all the lists into one
+ pListNew = NULL;
+ ppListNew = &pListNew;
+ for ( i = 1; i <= p->nVarsMax; i++ )
+ {
+ if ( pLists[i] == NULL )
+ continue;
+ // find the last entry
+ for ( pPrev = pLists[i], pCut = pPrev->pNext; pCut;
+ pPrev = pCut, pCut = pCut->pNext );
+ // connect these lists
+ *ppListNew = pLists[i];
+ ppListNew = &pPrev->pNext;
+ }
+ *ppListNew = NULL;
+ // soft the cuts by arrival times and use only the first MAP_CUTS_MAX_USE
+ pListNew = Map_CutSortCuts( p, pTable, pListNew );
+ return pListNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Merges two cuts.]
+
+ Description [Returns the number of nodes in the resulting cut, or 0 if the
+ cut is infeasible. Returns the resulting nodes in the array ppNodes[].]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_CutMergeTwo( Map_Cut_t * pCut1, Map_Cut_t * pCut2, Map_Node_t * ppNodes[], int nNodesMax )
+{
+ Map_Node_t * pNodeTemp;
+ int nTotal, i, k, min, fMismatch;
+
+ // check the special case when at least of the cuts is the largest
+ if ( pCut1->nLeaves == nNodesMax )
+ {
+ if ( pCut2->nLeaves == nNodesMax )
+ {
+ // return 0 if the cuts are different
+ for ( i = 0; i < nNodesMax; i++ )
+ if ( pCut1->ppLeaves[i] != pCut2->ppLeaves[i] )
+ return 0;
+ // return nNodesMax if they are the same
+ for ( i = 0; i < nNodesMax; i++ )
+ ppNodes[i] = pCut1->ppLeaves[i];
+ return nNodesMax;
+ }
+ else if ( pCut2->nLeaves == nNodesMax - 1 )
+ {
+ // return 0 if the cuts are different
+ fMismatch = 0;
+ for ( i = 0; i < nNodesMax; i++ )
+ if ( pCut1->ppLeaves[i] != pCut2->ppLeaves[i - fMismatch] )
+ {
+ if ( fMismatch == 1 )
+ return 0;
+ fMismatch = 1;
+ }
+ // return nNodesMax if they are the same
+ for ( i = 0; i < nNodesMax; i++ )
+ ppNodes[i] = pCut1->ppLeaves[i];
+ return nNodesMax;
+ }
+ }
+ else if ( pCut1->nLeaves == nNodesMax - 1 && pCut2->nLeaves == nNodesMax )
+ {
+ // return 0 if the cuts are different
+ fMismatch = 0;
+ for ( i = 0; i < nNodesMax; i++ )
+ if ( pCut1->ppLeaves[i - fMismatch] != pCut2->ppLeaves[i] )
+ {
+ if ( fMismatch == 1 )
+ return 0;
+ fMismatch = 1;
+ }
+ // return nNodesMax if they are the same
+ for ( i = 0; i < nNodesMax; i++ )
+ ppNodes[i] = pCut2->ppLeaves[i];
+ return nNodesMax;
+ }
+
+ // count the number of unique entries in pCut2
+ nTotal = pCut1->nLeaves;
+ for ( i = 0; i < pCut2->nLeaves; i++ )
+ {
+ // try to find this entry among the leaves of pCut1
+ for ( k = 0; k < pCut1->nLeaves; k++ )
+ if ( pCut2->ppLeaves[i] == pCut1->ppLeaves[k] )
+ break;
+ if ( k < pCut1->nLeaves ) // found
+ continue;
+ // we found a new entry to add
+ if ( nTotal == nNodesMax )
+ return 0;
+ ppNodes[nTotal++] = pCut2->ppLeaves[i];
+ }
+ // we know that the feasible cut exists
+
+ // add the starting entries
+ for ( k = 0; k < pCut1->nLeaves; k++ )
+ ppNodes[k] = pCut1->ppLeaves[k];
+
+ // selection-sort the entries
+ for ( i = 0; i < nTotal - 1; i++ )
+ {
+ min = i;
+ for ( k = i+1; k < nTotal; k++ )
+ if ( ppNodes[k] < ppNodes[min] )
+ min = k;
+ pNodeTemp = ppNodes[i];
+ ppNodes[i] = ppNodes[min];
+ ppNodes[min] = pNodeTemp;
+ }
+
+ return nTotal;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the union of the two lists of cuts.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Cut_t * Map_CutUnionLists( Map_Cut_t * pList1, Map_Cut_t * pList2 )
+{
+ Map_Cut_t * pTemp, * pRoot;
+ // find the last cut in the first list
+ pRoot = pList1;
+ Map_ListForEachCut( pList1, pTemp )
+ pRoot = pTemp;
+ // attach the non-trival part of the second cut to the end of the first
+ assert( pRoot->pNext == NULL );
+ pRoot->pNext = pList2->pNext;
+ pList2->pNext = NULL;
+ return pList1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Checks whether the given cut belongs to the list.]
+
+ Description [This procedure takes most of the runtime in the cut
+ computation.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_CutBelongsToList( Map_Cut_t * pList, Map_Node_t * ppNodes[], int nNodes )
+{
+ Map_Cut_t * pTemp;
+ int i;
+ for ( pTemp = pList; pTemp; pTemp = pTemp->pNext )
+ {
+ for ( i = 0; i < nNodes; i++ )
+ if ( pTemp->ppLeaves[i] != ppNodes[i] )
+ break;
+ if ( i == nNodes )
+ return 1;
+ }
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Counts all the cuts.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_MappingCountAllCuts( Map_Man_t * pMan )
+{
+ Map_Node_t * pNode;
+ Map_Cut_t * pCut;
+ int i, nCuts;
+ nCuts = 0;
+ for ( i = 0; i < pMan->nBins; i++ )
+ for ( pNode = pMan->pBins[i]; pNode; pNode = pNode->pNext )
+ for ( pCut = pNode->pCuts; pCut; pCut = pCut->pNext )
+ if ( pCut->nLeaves > 1 ) // skip the elementary cuts
+ nCuts++;
+ return nCuts;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Prints the cuts in the list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_CutListPrint( Map_Man_t * pMan, Map_Node_t * pRoot )
+{
+ Map_Cut_t * pTemp;
+ int Counter;
+ for ( Counter = 0, pTemp = pRoot->pCuts; pTemp; pTemp = pTemp->pNext, Counter++ )
+ {
+ printf( "%2d : ", Counter + 1 );
+ Map_CutPrint_( pMan, pTemp, pRoot );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the cuts in the list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_CutListPrint2( Map_Man_t * pMan, Map_Node_t * pRoot )
+{
+ Map_Cut_t * pTemp;
+ int Counter;
+ for ( Counter = 0, pTemp = pRoot->pCuts; pTemp; pTemp = pTemp->pNext, Counter++ )
+ {
+ printf( "%2d : ", Counter + 1 );
+ Map_CutPrint_( pMan, pTemp, pRoot );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_CutPrint_( Map_Man_t * pMan, Map_Cut_t * pCut, Map_Node_t * pRoot )
+{
+ int i;
+ printf( "(%3d) {", pRoot->Num );
+ for ( i = 0; i < pMan->nVarsMax; i++ )
+ if ( pCut->ppLeaves[i] )
+ printf( " %3d", pCut->ppLeaves[i]->Num );
+ printf( " }\n" );
+}
+
+
+
+
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Starts the hash table to canonicize cuts.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_CutTable_t * Map_CutTableStart( Map_Man_t * pMan )
+{
+ Map_CutTable_t * p;
+ // allocate the table
+ p = ALLOC( Map_CutTable_t, 1 );
+ memset( p, 0, sizeof(Map_CutTable_t) );
+ p->nBins = Cudd_Prime( 10 * MAP_CUTS_MAX_COMPUTE );
+ p->pBins = ALLOC( Map_Cut_t *, p->nBins );
+ memset( p->pBins, 0, sizeof(Map_Cut_t *) * p->nBins );
+ p->pCuts = ALLOC( int, 2 * MAP_CUTS_MAX_COMPUTE );
+ p->pArray = ALLOC( Map_Cut_t *, 2 * MAP_CUTS_MAX_COMPUTE );
+ p->pCuts1 = ALLOC( Map_Cut_t *, 2 * MAP_CUTS_MAX_COMPUTE );
+ p->pCuts2 = ALLOC( Map_Cut_t *, 2 * MAP_CUTS_MAX_COMPUTE );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Stops the hash table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_CutTableStop( Map_CutTable_t * p )
+{
+ free( p->pCuts1 );
+ free( p->pCuts2 );
+ free( p->pArray );
+ free( p->pBins );
+ free( p->pCuts );
+ free( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the hash value of the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+unsigned Map_CutTableHash( Map_Node_t * ppNodes[], int nNodes )
+{
+ unsigned uRes;
+ int i;
+ uRes = 0;
+ for ( i = 0; i < nNodes; i++ )
+ uRes += s_HashPrimes[i] * ppNodes[i]->Num;
+ return uRes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Looks up the table for the available cut.]
+
+ Description [Returns -1 if the same cut is found. Returns the index
+ of the cell where the cut should be added, if it does not exist.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_CutTableLookup( Map_CutTable_t * p, Map_Node_t * ppNodes[], int nNodes )
+{
+ Map_Cut_t * pCut;
+ unsigned Key;
+ int b, i;
+
+ Key = Map_CutTableHash(ppNodes, nNodes) % p->nBins;
+ for ( b = Key; p->pBins[b]; b = (b+1) % p->nBins )
+ {
+ pCut = p->pBins[b];
+ if ( pCut->nLeaves != nNodes )
+ continue;
+ for ( i = 0; i < nNodes; i++ )
+ if ( pCut->ppLeaves[i] != ppNodes[i] )
+ break;
+ if ( i == nNodes )
+ return -1;
+ }
+ return b;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Starts the hash table to canonicize cuts.]
+
+ Description [Considers addition of the cut to the hash table.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Cut_t * Map_CutTableConsider( Map_Man_t * pMan, Map_CutTable_t * p, Map_Node_t * ppNodes[], int nNodes )
+{
+ Map_Cut_t * pCut;
+ int Place, i;
+// int clk;
+ // check the cut
+ Place = Map_CutTableLookup( p, ppNodes, nNodes );
+ if ( Place == -1 )
+ return NULL;
+ assert( nNodes > 0 );
+ // create the new cut
+//clk = clock();
+ pCut = Map_CutAlloc( pMan );
+//pMan->time1 += clock() - clk;
+ pCut->nLeaves = nNodes;
+// pCut->fLevel = 0;
+ for ( i = 0; i < nNodes; i++ )
+ {
+ pCut->ppLeaves[i] = ppNodes[i];
+// pCut->fLevel += ppNodes[i]->Level;
+ }
+// pCut->fLevel /= nNodes;
+ // add the cut to the table
+ assert( p->pBins[Place] == NULL );
+ p->pBins[Place] = pCut;
+ // add the cut to the new list
+ p->pCuts[ p->nCuts++ ] = Place;
+ return pCut;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prepares the table to be used with other cuts.]
+
+ Description [Restarts the table by cleaning the info about cuts stored
+ when the previous node was considered.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_CutTableRestart( Map_CutTable_t * p )
+{
+ int i;
+ for ( i = 0; i < p->nCuts; i++ )
+ {
+ assert( p->pBins[ p->pCuts[i] ] );
+ p->pBins[ p->pCuts[i] ] = NULL;
+ }
+ p->nCuts = 0;
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Compares the cuts by the number of leaves and then by delay.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_CutSortCutsCompare( Map_Cut_t ** pC1, Map_Cut_t ** pC2 )
+{
+ if ( (*pC1)->nLeaves < (*pC2)->nLeaves )
+ return -1;
+ if ( (*pC1)->nLeaves > (*pC2)->nLeaves )
+ return 1;
+/*
+ if ( (*pC1)->fLevel < (*pC2)->fLevel )
+ return -1;
+ if ( (*pC1)->fLevel > (*pC2)->fLevel )
+ return 1;
+*/
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sorts the cuts by average arrival time.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Cut_t * Map_CutSortCuts( Map_Man_t * pMan, Map_CutTable_t * p, Map_Cut_t * pList )
+{
+ Map_Cut_t * pListNew;
+ int nCuts, i;
+// int clk;
+ // move the cuts from the list into the array
+ nCuts = Map_CutList2Array( p->pCuts1, pList );
+ assert( nCuts <= MAP_CUTS_MAX_COMPUTE );
+ // sort the cuts
+//clk = clock();
+ qsort( (void *)p->pCuts1, nCuts, sizeof(Map_Cut_t *),
+ (int (*)(const void *, const void *)) Map_CutSortCutsCompare );
+//pMan->time2 += clock() - clk;
+ // move them back into the list
+ if ( nCuts > MAP_CUTS_MAX_USE - 1 )
+ {
+ // free the remaining cuts
+ for ( i = MAP_CUTS_MAX_USE - 1; i < nCuts; i++ )
+ Extra_MmFixedEntryRecycle( pMan->mmCuts, (char *)p->pCuts1[i] );
+ // update the number of cuts
+ nCuts = MAP_CUTS_MAX_USE - 1;
+ }
+ pListNew = Map_CutArray2List( p->pCuts1, nCuts );
+ return pListNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Moves the nodes from the list into the array.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_CutList2Array( Map_Cut_t ** pArray, Map_Cut_t * pList )
+{
+ int i;
+ for ( i = 0; pList; pList = pList->pNext, i++ )
+ pArray[i] = pList;
+ return i;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Moves the nodes from the array into the list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Cut_t * Map_CutArray2List( Map_Cut_t ** pArray, int nCuts )
+{
+ Map_Cut_t * pListNew, ** ppListNew;
+ int i;
+ pListNew = NULL;
+ ppListNew = &pListNew;
+ for ( i = 0; i < nCuts; i++ )
+ {
+ // connect these lists
+ *ppListNew = pArray[i];
+ ppListNew = &pArray[i]->pNext;
+//printf( " %d(%.2f)", pArray[i]->nLeaves, pArray[i]->fLevel );
+ }
+//printf( "\n" );
+
+ *ppListNew = NULL;
+ return pListNew;
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/map/mapper/mapperCutUtils.c b/src/map/mapper/mapperCutUtils.c
new file mode 100644
index 00000000..9f572e75
--- /dev/null
+++ b/src/map/mapper/mapperCutUtils.c
@@ -0,0 +1,273 @@
+/**CFile****************************************************************
+
+ FileName [mapperCutUtils.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Generic technology mapping engine.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - June 1, 2004.]
+
+ Revision [$Id: mapperCutUtils.h,v 1.0 2003/09/08 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mapperInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Allocates the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Cut_t * Map_CutAlloc( Map_Man_t * p )
+{
+ Map_Cut_t * pCut;
+ Map_Match_t * pMatch;
+ pCut = (Map_Cut_t *)Extra_MmFixedEntryFetch( p->mmCuts );
+ memset( pCut, 0, sizeof(Map_Cut_t) );
+
+ pMatch = pCut->M;
+ pMatch->AreaFlow = MAP_FLOAT_LARGE; // unassigned
+ pMatch->tArrive.Rise = MAP_FLOAT_LARGE; // unassigned
+ pMatch->tArrive.Fall = MAP_FLOAT_LARGE; // unassigned
+ pMatch->tArrive.Worst = MAP_FLOAT_LARGE; // unassigned
+
+ pMatch = pCut->M + 1;
+ pMatch->AreaFlow = MAP_FLOAT_LARGE; // unassigned
+ pMatch->tArrive.Rise = MAP_FLOAT_LARGE; // unassigned
+ pMatch->tArrive.Fall = MAP_FLOAT_LARGE; // unassigned
+ pMatch->tArrive.Worst = MAP_FLOAT_LARGE; // unassigned
+ return pCut;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Deallocates the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_CutFree( Map_Man_t * p, Map_Cut_t * pCut )
+{
+ if ( pCut )
+ Extra_MmFixedEntryRecycle( p->mmCuts, (char *)pCut );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_CutPrint( Map_Man_t * p, Map_Node_t * pRoot, Map_Cut_t * pCut, int fPhase )
+{
+ int i;
+ printf( "CUT: Delay = (%4.2f, %4.2f). Area = %4.2f. Nodes = %d -> {",
+ pCut->M[fPhase].tArrive.Rise, pCut->M[fPhase].tArrive.Fall, pCut->M[fPhase].AreaFlow, pRoot->Num );
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ printf( " %d", pCut->ppLeaves[i]->Num );
+ printf( " } \n" );
+}
+
+
+/**function*************************************************************
+
+ synopsis [Computes the exact area associated with the cut.]
+
+ description []
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+float Map_CutGetRootArea( Map_Cut_t * pCut, int fPhase )
+{
+ assert( pCut->M[fPhase].pSuperBest );
+ return pCut->M[fPhase].pSuperBest->Area;
+}
+
+/**function*************************************************************
+
+ synopsis [Computes the exact area associated with the cut.]
+
+ description []
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+int Map_CutGetLeafPhase( Map_Cut_t * pCut, int fPhase, int iLeaf )
+{
+ assert( pCut->M[fPhase].pSuperBest );
+ return (( pCut->M[fPhase].uPhaseBest & (1<<iLeaf) ) == 0);
+}
+
+/**function*************************************************************
+
+ synopsis [Computes the exact area associated with the cut.]
+
+ description []
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+int Map_NodeGetLeafPhase( Map_Node_t * pNode, int fPhase, int iLeaf )
+{
+ assert( pNode->pCutBest[fPhase]->M[fPhase].pSuperBest );
+ return (( pNode->pCutBest[fPhase]->M[fPhase].uPhaseBest & (1<<iLeaf) ) == 0);
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Cut_t * Map_CutListAppend( Map_Cut_t * pSetAll, Map_Cut_t * pSets )
+{
+ Map_Cut_t * pPrev, * pTemp;
+ if ( pSetAll == NULL )
+ return pSets;
+ if ( pSets == NULL )
+ return pSetAll;
+ // find the last one
+ for ( pTemp = pSets; pTemp; pTemp = pTemp->pNext )
+ pPrev = pTemp;
+ // append all the end of the current set
+ assert( pPrev->pNext == NULL );
+ pPrev->pNext = pSetAll;
+ return pSets;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_CutListRecycle( Map_Man_t * p, Map_Cut_t * pSetList, Map_Cut_t * pSave )
+{
+ Map_Cut_t * pNext, * pTemp;
+ for ( pTemp = pSetList, pNext = pTemp? pTemp->pNext : NULL;
+ pTemp;
+ pTemp = pNext, pNext = pNext? pNext->pNext : NULL )
+ if ( pTemp != pSave )
+ Extra_MmFixedEntryRecycle( p->mmCuts, (char *)pTemp );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_CutListCount( Map_Cut_t * pSets )
+{
+ Map_Cut_t * pTemp;
+ int i;
+ for ( i = 0, pTemp = pSets; pTemp; pTemp = pTemp->pNext, i++ );
+ return i;
+}
+
+#if 0
+
+/**function*************************************************************
+
+ synopsis [Removes the fanouts of the cut.]
+
+ description []
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+void Map_CutRemoveFanouts( Map_Node_t * pNode, Map_Cut_t * pCut, int fPhase )
+{
+ Map_NodeVec_t * vFanouts;
+ int i, k;
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ {
+ vFanouts = pCut->ppLeaves[i]->vFanouts;
+ for ( k = 0; k < vFanouts->nSize; k++ )
+ if ( vFanouts->pArray[k] == pNode )
+ break;
+ assert( k != vFanouts->nSize );
+ for ( k++; k < vFanouts->nSize; k++ )
+ vFanouts->pArray[k-1] = vFanouts->pArray[k];
+ vFanouts->nSize--;
+ }
+}
+
+/**function*************************************************************
+
+ synopsis [Removes the fanouts of the cut.]
+
+ description []
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+void Map_CutInsertFanouts( Map_Node_t * pNode, Map_Cut_t * pCut, int fPhase )
+{
+ int i;
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ Map_NodeVecPush( pCut->ppLeaves[i]->vFanouts, pNode );
+}
+
+#endif
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/mapper/mapperFanout.c b/src/map/mapper/mapperFanout.c
new file mode 100644
index 00000000..7bd92ed9
--- /dev/null
+++ b/src/map/mapper/mapperFanout.c
@@ -0,0 +1,139 @@
+/**CFile****************************************************************
+
+ FileName [mapperFanout.c]
+
+ PackageName [FRAIG: Functionally reduced AND-INV graphs.]
+
+ Synopsis [Procedures to manipulate fanouts of the FRAIG nodes.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - June 1, 2004.]
+
+ Revision [$Id: mapperFanout.c,v 1.5 2005/01/23 06:59:43 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mapperInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+
+/**Function*************************************************************
+
+ Synopsis [Add the fanout to the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_NodeAddFaninFanout( Map_Node_t * pFanin, Map_Node_t * pFanout )
+{
+ Map_Node_t * pPivot;
+
+ // pFanins is a fanin of pFanout
+ assert( !Map_IsComplement(pFanin) );
+ assert( !Map_IsComplement(pFanout) );
+ assert( Map_Regular(pFanout->p1) == pFanin || Map_Regular(pFanout->p2) == pFanin );
+
+ pPivot = pFanin->pFanPivot;
+ if ( pPivot == NULL )
+ {
+ pFanin->pFanPivot = pFanout;
+ return;
+ }
+
+ if ( Map_Regular(pPivot->p1) == pFanin )
+ {
+ if ( Map_Regular(pFanout->p1) == pFanin )
+ {
+ pFanout->pFanFanin1 = pPivot->pFanFanin1;
+ pPivot->pFanFanin1 = pFanout;
+ }
+ else // if ( Map_Regular(pFanout->p2) == pFanin )
+ {
+ pFanout->pFanFanin2 = pPivot->pFanFanin1;
+ pPivot->pFanFanin1 = pFanout;
+ }
+ }
+ else // if ( Map_Regular(pPivot->p2) == pFanin )
+ {
+ assert( Map_Regular(pPivot->p2) == pFanin );
+ if ( Map_Regular(pFanout->p1) == pFanin )
+ {
+ pFanout->pFanFanin1 = pPivot->pFanFanin2;
+ pPivot->pFanFanin2 = pFanout;
+ }
+ else // if ( Map_Regular(pFanout->p2) == pFanin )
+ {
+ pFanout->pFanFanin2 = pPivot->pFanFanin2;
+ pPivot->pFanFanin2 = pFanout;
+ }
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Add the fanout to the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_NodeRemoveFaninFanout( Map_Node_t * pFanin, Map_Node_t * pFanoutToRemove )
+{
+ Map_Node_t * pFanout, * pFanout2, ** ppFanList;
+ // start the linked list of fanouts
+ ppFanList = &pFanin->pFanPivot;
+ // go through the fanouts
+ Map_NodeForEachFanoutSafe( pFanin, pFanout, pFanout2 )
+ {
+ // skip the fanout-to-remove
+ if ( pFanout == pFanoutToRemove )
+ continue;
+ // add useful fanouts to the list
+ *ppFanList = pFanout;
+ ppFanList = Map_NodeReadNextFanoutPlace( pFanin, pFanout );
+ }
+ *ppFanList = NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the number of fanouts of a node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_NodeGetFanoutNum( Map_Node_t * pNode )
+{
+ Map_Node_t * pFanout;
+ int Counter = 0;
+ Map_NodeForEachFanout( pNode, pFanout )
+ Counter++;
+ return Counter;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/mapper/mapperGENERIC.c b/src/map/mapper/mapperGENERIC.c
new file mode 100644
index 00000000..4df5ee51
--- /dev/null
+++ b/src/map/mapper/mapperGENERIC.c
@@ -0,0 +1,46 @@
+/**CFile****************************************************************
+
+ FileName [mapper__.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Generic technology mapping engine.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - September 8, 2003.]
+
+ Revision [$Id: mapper__.h,v 1.0 2003/09/08 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mapperInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/mapper/mapperInt.h b/src/map/mapper/mapperInt.h
new file mode 100644
index 00000000..c5ecce73
--- /dev/null
+++ b/src/map/mapper/mapperInt.h
@@ -0,0 +1,475 @@
+/**CFile****************************************************************
+
+ FileName [mapperInt.h]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Generic technology mapping engine.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - June 1, 2004.]
+
+ Revision [$Id: mapperInt.h,v 1.8 2004/09/30 21:18:10 satrajit Exp $]
+
+***********************************************************************/
+
+#ifndef __MAPPER_INT_H__
+#define __MAPPER_INT_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+//#include "leaks.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <float.h>
+#include "cuddInt.h"
+#include "main.h"
+#include "mio.h"
+#include "mapper.h"
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// the bit masks
+#define MAP_MASK(n) ((~((unsigned)0)) >> (32-(n)))
+#define MAP_FULL (~((unsigned)0))
+#define MAP_NO_VAR (-9999.0)
+
+// maximum/minimum operators
+#define MAP_MIN(a,b) (((a) < (b))? (a) : (b))
+#define MAP_MAX(a,b) (((a) > (b))? (a) : (b))
+
+// the small and large numbers (min/max float are 1.17e-38/3.40e+38)
+#define MAP_FLOAT_LARGE ((float)(FLT_MAX/10))
+#define MAP_FLOAT_SMALL ((float)1.0e-03)
+
+// generating random unsigned (#define RAND_MAX 0x7fff)
+#define MAP_RANDOM_UNSIGNED ((((unsigned)rand()) << 24) ^ (((unsigned)rand()) << 12) ^ ((unsigned)rand()))
+
+// internal macros to work with cuts
+#define Map_CutIsComplement(p) (((int)((long) (p) & 01)))
+#define Map_CutRegular(p) ((Map_Cut_t *)((unsigned)(p) & ~01))
+#define Map_CutNot(p) ((Map_Cut_t *)((long)(p) ^ 01))
+#define Map_CutNotCond(p,c) ((Map_Cut_t *)((long)(p) ^ (c)))
+
+// internal macros for referencing of nodes
+#define Map_NodeReadRef(p) ((Map_Regular(p))->nRefs)
+#define Map_NodeRef(p) ((Map_Regular(p))->nRefs++)
+
+// macros to get hold of the bits in the support info
+#define Map_InfoSetVar(p,i) (p[(i)>>5] |= (1<<((i) & 31)))
+#define Map_InfoRemVar(p,i) (p[(i)>>5] &= ~(1<<((i) & 31)))
+#define Map_InfoFlipVar(p,i) (p[(i)>>5] ^= (1<<((i) & 31)))
+#define Map_InfoReadVar(p,i) ((p[(i)>>5] & (1<<((i) & 31))) > 0)
+
+// returns the complemented attribute of the node
+#define Map_NodeIsSimComplement(p) (Map_IsComplement(p)? !(Map_Regular(p)->fInv) : (p)->fInv)
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// the mapping manager
+struct Map_ManStruct_t_
+{
+ // the mapping graph
+ Map_Node_t ** pBins; // the table of nodes hashed by their children
+ int nBins; // the size of the table
+ Map_Node_t ** pInputs; // the array of inputs
+ int nInputs; // the number of inputs
+ Map_Node_t ** pOutputs; // the array of outputs
+ int nOutputs; // the number of outputs
+ int nNodes; // the total number of nodes
+ Map_Node_t * pConst1; // the constant 1 node
+ Map_NodeVec_t * vAnds; // the array of nodes in the DFS order
+ Map_NodeVec_t * vNodesAll; // the array of all nodes
+ Map_NodeVec_t * vNodesTemp; // the array of all nodes
+ Map_NodeVec_t * vMapping; // the array of internal nodes used in the mapping
+
+ // info about the original circuit
+ char ** ppOutputNames; // the primary output names
+ Map_Time_t * pInputArrivals;// the PI arrival times
+
+ // mapping parameters
+ int nVarsMax; // the max number of variables
+ int fAreaRecovery; // the flag to enable area recovery
+ int fVerbose; // the verbosiness flag
+ int fMappingMode; // set to 1 when doing area
+ float fRequiredGlo; // the global required times
+ float fEpsilon; // the epsilon used to compare floats
+ float AreaBase; // the area after delay-oriented mapping
+ float AreaFinal; // the area after delay-oriented mapping
+ int nIterations; // How many matching passes to do
+ bool fObeyFanoutLimits;// Should mapper try to obey fanout limits or not
+ float DelayTarget; // the required times set by the user
+ int nTravIds; // the traversal counter
+
+ // the supergate library
+ Map_SuperLib_t * pSuperLib; // the current supergate library
+ unsigned uTruths[6][2]; // the elementary truth tables
+ unsigned uTruthsLarge[10][32]; // the elementary truth tables
+ int nCounts[32]; // the counter of minterms
+ int nCountsBest[32];// the counter of minterms
+
+ // simulation info from the FRAIG manager
+ int nSimRounds; // the number of words in the simulation info
+ unsigned ** pSimInfo; // the simulation info for each PI
+
+ // don't-care computation
+ Map_NodeVec_t * vInside; // the array of nodes for SDC computation
+ Map_NodeVec_t * vFanins; // the array of nodes for SDC computation
+
+ // the memory managers
+ Extra_MmFixed_t * mmNodes; // the memory manager for nodes
+ Extra_MmFixed_t * mmCuts; // the memory manager for cuts
+
+ // various statistical variables
+ int nChoiceNodes; // the number of choice nodes
+ int nChoices; // the number of all choices
+ int nCanons; // the number of times N-canonical form was computed
+ int nMatches; // the number of times supergate matching was performed
+ int nPhases; // the number of phases considered during matching
+ int nFanoutViolations; // the number of nodes in mapped circuit violating fanout
+
+ // runtime statistics
+ int timeToMap; // time to transfer to the mapping structure
+ int timeCuts; // time to compute k-feasible cuts
+ int timeTruth; // time to compute the truth table for each cut
+ int timeMatch; // time to perform matching for each node
+ int timeArea; // time to recover area after delay oriented mapping
+ int timeSweep; // time to perform technology dependent sweep
+ int timeToNet; // time to transfer back to the network
+ int timeTotal; // the total mapping time
+ int time1; // time to transfer to the mapping structure
+ int time2; // time to transfer to the mapping structure
+ int time3; // time to transfer to the mapping structure
+};
+
+// the supergate library
+struct Map_SuperLibStruct_t_
+{
+ // general info
+ char * pName; // the name of the supergate library
+ Mio_Library_t * pGenlib; // the generic library
+
+ // other info
+ int nVarsMax; // the max number of variables
+ int nSupersAll; // the total number of supergates
+ int nSupersReal; // the total number of supergates
+ int nLines; // the total number of lines in the supergate file
+ bool fVerbose; // the verbosity flag
+
+ // hash tables
+ Map_Super_t ** ppSupers; // the array of supergates
+ Map_HashTable_t * tTableC; // the table mapping N-canonical forms into supergates
+ Map_HashTable_t * tTable; // the table mapping truth tables into supergates
+
+ // data structures for N-canonical form computation
+ unsigned uTruths[6][2]; // the elementary truth tables
+ unsigned uMask[2]; // the mask for the truth table
+
+ // the invertor
+ Mio_Gate_t * pGateInv; // the pointer to the intertor gate
+ Map_Time_t tDelayInv; // the delay of the inverter
+ float AreaInv; // the area of the inverter
+ Map_Super_t * pSuperInv; // the supergate representing the inverter
+
+ // the memory manager for the internal table
+ Extra_MmFixed_t * mmSupers; // the mamory manager for supergates
+ Extra_MmFixed_t * mmEntries; // the memory manager for the entries
+ Extra_MmFlex_t * mmForms; // the memory manager for formulas
+};
+
+// the mapping node
+struct Map_NodeStruct_t_
+{
+ // general information about the node
+ Map_Man_t * p; // the mapping manager
+ Map_Node_t * pNext; // the next node in the hash table
+ int Num; // the unique number of this node
+ int TravId; // the traversal ID (use to avoid cleaning marks)
+ int nRefs; // the number of references (fanouts) of the given node
+ unsigned fMark0 : 1; // the mark used for traversals
+ unsigned fMark1 : 1; // the mark used for traversals
+ unsigned fUsed : 1; // the mark to mark the node or its fanins
+ unsigned fInv : 1; // the complemented attribute for the equivalent nodes
+ unsigned fInvert: 1; // the flag to denote the use of interter
+ unsigned Level :16; // the level of the given node
+ unsigned NumTemp:10; // the level of the given node
+ int nRefAct[3]; // estimated fanout for current covering phase, neg and pos and sum
+ float nRefEst[3]; // actual fanout for previous covering phase, neg and pos and sum
+
+ // the successors of this node
+ Map_Node_t * p1; // the first child
+ Map_Node_t * p2; // the second child
+ Map_Node_t * pNextE; // the next functionally equivalent node
+ Map_Node_t * pRepr; // the representative of the functionally equivalent class
+// Map_NodeVec_t * vFanouts; // the array of fanouts of the node
+
+ // representation of node's fanouts
+ Map_Node_t * pFanPivot; // the first fanout of this node
+ Map_Node_t * pFanFanin1; // the next fanout of p1
+ Map_Node_t * pFanFanin2; // the next fanout of p2
+
+ unsigned * pSims; // the simulation info
+ float SwitchProb; // the switching probability
+
+ // the delay information
+ Map_Time_t tArrival[2]; // the best arrival time of the neg (0) and pos (1) phases
+ Map_Time_t tRequired[2]; // the required time of the neg (0) and pos (1) phases
+
+ // misc information
+ Map_Cut_t * pCutOld[2]; // the old mapping for neg and pos phase
+ Map_Cut_t * pCutBest[2]; // the best mapping for neg and pos phase
+ Map_Cut_t * pCuts; // mapping choices for the node (elementary comes first)
+ char * pData0; // temporary storage for the corresponding network node
+ char * pData1; // temporary storage for the corresponding network node
+};
+
+// the match of the cut
+struct Map_MatchStruct_t_
+{
+ // information used for matching
+ Map_Super_t * pSupers;
+ unsigned uPhase;
+ // information about the best selected match
+ unsigned uPhaseBest; // the best phase (the EXOR of match's phase and gate's phase)
+ Map_Super_t * pSuperBest; // the best supergate matched
+ // the parameters of the match
+ Map_Time_t tArrive; // the arrival time of this match
+ float AreaFlow; // the area flow or area of this match
+};
+
+// the cuts used for matching
+struct Map_CutStruct_t_
+{
+ Map_Cut_t * pNext; // the pointer to the next cut in the list
+ Map_Cut_t * pOne; // the father of this cut
+ Map_Cut_t * pTwo; // the mother of this cut
+ Map_Node_t * ppLeaves[6]; // the leaves of this cut
+ char nLeaves; // the number of leaves
+ char nVolume; // the volume of this cut
+ char fMark; // the mark to denote visited cut
+ char Phase; // the mark to denote complemented cut
+// float fLevel; // the average level of the fanins
+
+ unsigned uTruthTemp[2]; // the temporary truth table used to derive other cuts
+ unsigned uTruthZero[2]; // the temporary truth table used to derive other cuts
+ unsigned uTruthDc[2]; // the don't-cares (SDCs) computed for this cut
+
+ Map_Match_t M[2]; // the matches for the positive/negative phase
+};
+
+// the supergate internally represented
+struct Map_SuperStruct_t_
+{
+ int Num; // the ID of the supergate
+ unsigned fSuper : 1; // the flag to distinquish a real super from a fake one
+ unsigned fExclude: 1; // the flag if set causes gate to be excluded from being used for mapping
+ unsigned nFanins : 3; // the number of inputs
+ unsigned nGates : 3; // the number of gates inside this supergate
+ unsigned nFanLimit: 4; // the max number of fanout count
+ unsigned nSupers : 16; // the number of supergates in the list
+ unsigned nPhases : 4; // the number of phases for matching with canonical form
+ unsigned char uPhases[4]; // the maximum of 4 phases for matching with canonical form
+ int nUsed; // the number of times the supergate is used
+ Map_Super_t * pFanins[6]; // the fanins of the gate
+ Mio_Gate_t * pRoot; // the root gate
+ unsigned uTruth[2]; // the truth table
+ Map_Time_t tDelaysR[6]; // the pin-to-pin delay constraints for the rise of the output
+ Map_Time_t tDelaysF[6]; // the pin-to-pin delay constraints for the rise of the output
+ Map_Time_t tDelayMax; // the maximum delay
+ float Area; // the area
+ char * pFormula; // the symbolic formula
+ Map_Super_t * pNext; // the pointer to the next super in the list
+};
+
+// the vector of nodes
+struct Map_NodeVecStruct_t_
+{
+ Map_Node_t ** pArray; // the array of nodes
+ int nSize; // the number of entries in the array
+ int nCap; // the number of allocated entries
+};
+
+// the hash table
+struct Map_HashTableStruct_t_
+{
+ Map_HashEntry_t ** pBins; // the table bins
+ int nBins; // the size of the table
+ int nEntries; // the total number of entries in the table
+ Extra_MmFixed_t * mmMan; // the memory manager for entries
+};
+
+// the entry in the hash table
+struct Map_HashEntryStruct_t_
+{
+ unsigned uTruth[2]; // the truth table for 6-var function
+ unsigned uPhase; // the phase to tranform it into the canonical form
+ Map_Super_t * pGates; // the linked list of matching supergates
+ Map_HashEntry_t * pNext; // the next entry in the hash table
+};
+
+// getting hold of the next fanout of the node
+#define Map_NodeReadNextFanout( pNode, pFanout ) \
+ ( ( pFanout == NULL )? NULL : \
+ ((Map_Regular((pFanout)->p1) == (pNode))? \
+ (pFanout)->pFanFanin1 : (pFanout)->pFanFanin2) )
+
+// getting hold of the place where the next fanout will be attached
+#define Map_NodeReadNextFanoutPlace( pNode, pFanout ) \
+ ( (Map_Regular((pFanout)->p1) == (pNode))? \
+ &(pFanout)->pFanFanin1 : &(pFanout)->pFanFanin2 )
+
+// iterator through the fanouts of the node
+#define Map_NodeForEachFanout( pNode, pFanout ) \
+ for ( pFanout = (pNode)->pFanPivot; pFanout; \
+ pFanout = Map_NodeReadNextFanout(pNode, pFanout) )
+
+// safe iterator through the fanouts of the node
+#define Map_NodeForEachFanoutSafe( pNode, pFanout, pFanout2 ) \
+ for ( pFanout = (pNode)->pFanPivot, \
+ pFanout2 = Map_NodeReadNextFanout(pNode, pFanout); \
+ pFanout; \
+ pFanout = pFanout2, \
+ pFanout2 = Map_NodeReadNextFanout(pNode, pFanout) )
+
+////////////////////////////////////////////////////////////////////////
+/// GLOBAL VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== mapperCanon.c =============================================================*/
+/*=== mapperCut.c ===============================================================*/
+extern void Map_MappingCuts( Map_Man_t * p );
+extern int Map_MappingCountAllCuts( Map_Man_t * p );
+/*=== mapperCutDcs.c ===============================================================*/
+extern void Map_ComputeDcs( Map_Man_t * p );
+extern unsigned Map_ComputeIsop_rec( Map_Man_t * p, unsigned uF, unsigned uFD, int iVar, int nVars, int fDir );
+/*=== mapperCutUtils.c ===============================================================*/
+extern Map_Cut_t * Map_CutAlloc( Map_Man_t * p );
+extern void Map_CutFree( Map_Man_t * p, Map_Cut_t * pCut );
+extern void Map_CutPrint( Map_Man_t * p, Map_Node_t * pRoot, Map_Cut_t * pCut, int fPhase );
+extern float Map_CutGetRootArea( Map_Cut_t * pCut, int fPhase );
+extern int Map_CutGetLeafPhase( Map_Cut_t * pCut, int fPhase, int iLeaf );
+extern int Map_NodeGetLeafPhase( Map_Node_t * pNode, int fPhase, int iLeaf );
+extern Map_Cut_t * Map_CutListAppend( Map_Cut_t * pSetAll, Map_Cut_t * pSets );
+extern void Map_CutListRecycle( Map_Man_t * p, Map_Cut_t * pSetList, Map_Cut_t * pSave );
+extern int Map_CutListCount( Map_Cut_t * pSets );
+extern void Map_CutRemoveFanouts( Map_Node_t * pNode, Map_Cut_t * pCut, int fPhase );
+extern void Map_CutInsertFanouts( Map_Node_t * pNode, Map_Cut_t * pCut, int fPhase );
+/*=== mapperFanout.c =============================================================*/
+extern void Map_NodeAddFaninFanout( Map_Node_t * pFanin, Map_Node_t * pFanout );
+extern void Map_NodeRemoveFaninFanout( Map_Node_t * pFanin, Map_Node_t * pFanoutToRemove );
+extern int Map_NodeGetFanoutNum( Map_Node_t * pNode );
+/*=== mapperLib.c ============================================================*/
+extern Map_SuperLib_t * Map_SuperLibCreate( char * pFileName, char * pExcludeFile, bool fAlgorithm, bool fVerbose );
+extern void Map_SuperLibFree( Map_SuperLib_t * p );
+/*=== mapperMatch.c ===============================================================*/
+extern int Map_MappingMatches( Map_Man_t * p );
+extern float Map_MappingCombinePhases( Map_Man_t * p );
+extern void Map_MatchClean( Map_Match_t * pMatch );
+extern int Map_MatchCompare( Map_Man_t * pMan, Map_Match_t * pM1, Map_Match_t * pM2, int fDoingArea );
+/*=== mapperRefs.c =============================================================*/
+extern int Map_NodeReadRefPhaseAct( Map_Node_t * pNode, int fPhase );
+extern float Map_NodeReadRefPhaseEst( Map_Node_t * pNode, int fPhase );
+extern void Map_MappingEstimateRefsInit( Map_Man_t * p );
+extern void Map_MappingEstimateRefs( Map_Man_t * p );
+extern float Map_CutGetAreaFlow( Map_Cut_t * pCut, int fPhase );
+extern float Map_CutGetAreaRefed( Map_Cut_t * pCut, int fPhase );
+extern float Map_CutGetAreaDerefed( Map_Cut_t * pCut, int fPhase );
+extern float Map_CutRef( Map_Cut_t * pCut, int fPhase );
+extern float Map_CutDeref( Map_Cut_t * pCut, int fPhase );
+extern void Map_MappingSetRefs( Map_Man_t * pMan );
+extern float Map_MappingGetArea( Map_Man_t * pMan, Map_NodeVec_t * vMapping );
+/*=== mapperShow.c =============================================================*/
+extern void Map_MappingShow( Map_Man_t * pMan, char * pFileName );
+/*=== mapperTree.c ===============================================================*/
+extern int Map_LibraryReadTree( Map_SuperLib_t * pLib, char * pFileName, char * pExcludeFile );
+extern void Map_LibraryPrintTree( Map_SuperLib_t * pLib );
+/*=== mapperSuper.c ===============================================================*/
+extern int Map_LibraryRead( Map_SuperLib_t * p, char * pFileName );
+extern void Map_LibraryPrintSupergate( Map_Super_t * pGate );
+/*=== mapperTable.c ============================================================*/
+extern Map_HashTable_t * Map_SuperTableCreate( Map_SuperLib_t * pLib );
+extern void Map_SuperTableFree( Map_HashTable_t * p );
+extern int Map_SuperTableInsertC( Map_HashTable_t * pLib, unsigned uTruthC[], Map_Super_t * pGate );
+extern int Map_SuperTableInsert( Map_HashTable_t * pLib, unsigned uTruth[], Map_Super_t * pGate, unsigned uPhase );
+extern Map_Super_t * Map_SuperTableLookup( Map_HashTable_t * p, unsigned uTruth[], unsigned * puPhase );
+extern void Map_SuperTableSortSupergates( Map_HashTable_t * p, int nSupersMax );
+extern void Map_SuperTableSortSupergatesByDelay( Map_HashTable_t * p, int nSupersMax );
+/*=== mapperTime.c =============================================================*/
+extern float Map_TimeCutComputeArrival( Map_Node_t * pNode, Map_Cut_t * pCut, int fPhase, float tWorstCaseLimit );
+extern void Map_TimeCutComputeArrival_rec( Map_Cut_t * pCut, int fPhase );
+extern float Map_TimeComputeArrivalMax( Map_Man_t * p );
+extern void Map_TimeComputeRequiredGlobal( Map_Man_t * p );
+extern void Map_TimeComputeRequired( Map_Man_t * p, float fRequired );
+extern float Map_TimeNodeFanoutDelay( Map_Node_t * pNode, int fPhase );
+extern float Map_TimeCutFanoutDelay( Map_Node_t * pNode, Map_Cut_t * pCut, int fPhase );
+extern float Map_TimeMatchWithInverter( Map_Man_t * p, Map_Match_t * pMatch );
+/*=== mapperTruth.c ===============================================================*/
+extern void Map_MappingTruths( Map_Man_t * pMan );
+extern int Map_TruthsCutDontCare( Map_Man_t * pMan, Map_Cut_t * pCut, unsigned * uTruthDc );
+extern int Map_TruthCountOnes( unsigned * uTruth, int nLeaves );
+extern int Map_TruthDetectTwoFirst( unsigned * uTruth, int nLeaves );
+/*=== mapperUtils.c ===============================================================*/
+extern Map_NodeVec_t * Map_MappingDfs( Map_Man_t * pMan, int fCollectEquiv );
+extern Map_NodeVec_t * Map_MappingDfsNodes( Map_Man_t * pMan, Map_Node_t ** ppNodes, int nNodes, int fEquiv );
+
+extern void Map_MappingDfsMarked1_rec( Map_Node_t * pNode, Map_NodeVec_t * vNodes, int fFirst );
+extern void Map_MappingDfsMarked2_rec( Map_Node_t * pNode, Map_NodeVec_t * vNodes, Map_NodeVec_t * vBoundary, int fFirst );
+
+extern int Map_MappingCountLevels( Map_Man_t * pMan );
+extern void Map_MappingUnmark( Map_Man_t * pMan );
+extern void Map_MappingMark_rec( Map_Node_t * pNode );
+extern void Map_MappingUnmark_rec( Map_Node_t * pNode );
+extern void Map_MappingPrintOutputArrivals( Map_Man_t * p );
+extern void Map_MappingSetupMask( unsigned uMask[], int nVarsMax );
+extern int Map_MappingNodeIsViolator( Map_Node_t * pNode, Map_Cut_t * pCut, int fPosPol );
+extern float Map_MappingGetAreaFlow( Map_Man_t * p );
+extern void Map_MappingSortByLevel( Map_Man_t * pMan, Map_NodeVec_t * vNodes );
+extern int Map_MappingCountDoubles( Map_Man_t * pMan, Map_NodeVec_t * vNodes );
+extern void Map_MappingExpandTruth( unsigned uTruth[2], int nVars );
+extern float Map_MappingPrintSwitching( Map_Man_t * pMan );
+extern void Map_MappingSetPlacementInfo( Map_Man_t * p );
+extern float Map_MappingPrintWirelength( Map_Man_t * p );
+extern void Map_MappingWireReport( Map_Man_t * p );
+extern float Map_MappingComputeDelayWithFanouts( Map_Man_t * p );
+extern int Map_MappingGetMaxLevel( Map_Man_t * pMan );
+extern void Map_MappingSetChoiceLevels( Map_Man_t * pMan );
+extern void Map_MappingReportChoices( Map_Man_t * pMan );
+/*=== mapperVec.c =============================================================*/
+extern Map_NodeVec_t * Map_NodeVecAlloc( int nCap );
+extern void Map_NodeVecFree( Map_NodeVec_t * p );
+extern Map_Node_t ** Map_NodeVecReadArray( Map_NodeVec_t * p );
+extern int Map_NodeVecReadSize( Map_NodeVec_t * p );
+extern void Map_NodeVecGrow( Map_NodeVec_t * p, int nCapMin );
+extern void Map_NodeVecShrink( Map_NodeVec_t * p, int nSizeNew );
+extern void Map_NodeVecClear( Map_NodeVec_t * p );
+extern void Map_NodeVecPush( Map_NodeVec_t * p, Map_Node_t * Entry );
+extern int Map_NodeVecPushUnique( Map_NodeVec_t * p, Map_Node_t * Entry );
+extern Map_Node_t * Map_NodeVecPop( Map_NodeVec_t * p );
+extern void Map_NodeVecRemove( Map_NodeVec_t * p, Map_Node_t * Entry );
+extern void Map_NodeVecWriteEntry( Map_NodeVec_t * p, int i, Map_Node_t * Entry );
+extern Map_Node_t * Map_NodeVecReadEntry( Map_NodeVec_t * p, int i );
+extern void Map_NodeVecSortByLevel( Map_NodeVec_t * p );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
diff --git a/src/map/mapper/mapperLib.c b/src/map/mapper/mapperLib.c
new file mode 100644
index 00000000..5530f8cb
--- /dev/null
+++ b/src/map/mapper/mapperLib.c
@@ -0,0 +1,233 @@
+/**CFile****************************************************************
+
+ FileName [mapperLib.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Generic technology mapping engine.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - June 1, 2004.]
+
+ Revision [$Id: mapperLib.c,v 1.6 2005/01/23 06:59:44 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mapperInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Reads in the supergate library and prepares it for use.]
+
+ Description [The supergates library comes in a .super file. This file
+ contains descriptions of supergates along with some relevant information.
+ This procedure reads the supergate file, canonicizes the supergates,
+ and constructs an additional lookup table, which can be used to map
+ truth tables of the cuts into the pair (phase, supergate). The phase
+ indicates how the current truth table should be phase assigned to
+ match the canonical form of the supergate. The resulting phase is the
+ bitwise EXOR of the phase needed to canonicize the supergate and the
+ phase needed to transform the truth table into its canonical form.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_SuperLib_t * Map_SuperLibCreate( char * pFileName, char * pExcludeFile, bool fAlgorithm, bool fVerbose )
+{
+ Map_SuperLib_t * p;
+ int clk;
+
+ // start the supergate library
+ p = ALLOC( Map_SuperLib_t, 1 );
+ memset( p, 0, sizeof(Map_SuperLib_t) );
+ p->pName = pFileName;
+ p->fVerbose = fVerbose;
+ p->mmSupers = Extra_MmFixedStart( sizeof(Map_Super_t) );
+ p->mmEntries = Extra_MmFixedStart( sizeof(Map_HashEntry_t) );
+ p->mmForms = Extra_MmFlexStart();
+ Map_MappingSetupTruthTables( p->uTruths );
+
+ // start the hash table
+ p->tTableC = Map_SuperTableCreate( p );
+ p->tTable = Map_SuperTableCreate( p );
+
+ // read the supergate library from file
+clk = clock();
+ if ( fAlgorithm )
+ {
+ if ( !Map_LibraryReadTree( p, pFileName, pExcludeFile ) )
+ {
+ Map_SuperLibFree( p );
+ return NULL;
+ }
+ }
+ else
+ {
+ if ( pExcludeFile != 0 )
+ {
+ printf ("Error: Exclude file support not present for old format. Stop.\n");
+ return NULL;
+ }
+ if ( !Map_LibraryRead( p, pFileName ) )
+ {
+ Map_SuperLibFree( p );
+ return NULL;
+ }
+ }
+ assert( p->nVarsMax > 0 );
+
+ // report the stats
+if ( fVerbose ) {
+ printf( "Loaded %d unique %d-input supergates from \"%s\". ",
+ p->nSupersReal, p->nVarsMax, pFileName );
+ PRT( "Time", clock() - clk );
+}
+
+ // assign the interver parameters
+ p->pGateInv = Mio_LibraryReadInv( p->pGenlib );
+ p->tDelayInv.Rise = Mio_LibraryReadDelayInvRise( p->pGenlib );
+ p->tDelayInv.Fall = Mio_LibraryReadDelayInvFall( p->pGenlib );
+ p->tDelayInv.Worst = MAP_MAX( p->tDelayInv.Rise, p->tDelayInv.Fall );
+ p->AreaInv = Mio_LibraryReadAreaInv( p->pGenlib );
+
+ // assign the interver supergate
+ p->pSuperInv = (Map_Super_t *)Extra_MmFixedEntryFetch( p->mmSupers );
+ memset( p->pSuperInv, 0, sizeof(Map_Super_t) );
+ p->pSuperInv->Num = -1;
+ p->pSuperInv->nGates = 1;
+ p->pSuperInv->nFanins = 1;
+ p->pSuperInv->nFanLimit = 10;
+ p->pSuperInv->pFanins[0] = p->ppSupers[0];
+ p->pSuperInv->pRoot = p->pGateInv;
+ p->pSuperInv->Area = p->AreaInv;
+ p->pSuperInv->tDelayMax = p->tDelayInv;
+ p->pSuperInv->tDelaysR[0].Rise = MAP_NO_VAR;
+ p->pSuperInv->tDelaysR[0].Fall = p->tDelayInv.Rise;
+ p->pSuperInv->tDelaysF[0].Rise = p->tDelayInv.Fall;
+ p->pSuperInv->tDelaysF[0].Fall = MAP_NO_VAR;
+ return p;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Deallocates the supergate library.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_SuperLibFree( Map_SuperLib_t * p )
+{
+ if ( p == NULL ) return;
+ if ( p->pGenlib )
+ {
+// if ( s_pLib == p->pGenlib )
+// s_pLib = NULL;
+ if ( Abc_FrameReadLibGen(Abc_FrameGetGlobalFrame()) == p->pGenlib )
+ Abc_FrameSetLibGen(Abc_FrameGetGlobalFrame(), NULL);
+// Mio_LibraryDelete( p->pGenlib );
+ Mio_LibraryDelete( p->pGenlib );
+ }
+ if ( p->tTableC )
+ Map_SuperTableFree( p->tTableC );
+ if ( p->tTable )
+ Map_SuperTableFree( p->tTable );
+ Extra_MmFixedStop( p->mmSupers, 0 );
+ Extra_MmFixedStop( p->mmEntries, 0 );
+ Extra_MmFlexStop( p->mmForms, 0 );
+ FREE( p->ppSupers );
+ FREE( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Derives the library from the genlib library.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_SuperLibDeriveFromGenlib( Mio_Library_t * pLib )
+{
+ Abc_Frame_t * pAbc = Abc_FrameGetGlobalFrame();
+ char * pNameGeneric;
+ char FileNameGenlib[100];
+ char FileNameSuper[100];
+ char CommandSuper[500];
+ char CommandRead[500];
+ FILE * pFile;
+
+ if ( pLib == NULL )
+ return 0;
+
+ // write the current library into the file
+ strcpy( FileNameGenlib, Mio_LibraryReadName(pLib) );
+ pFile = fopen( FileNameGenlib, "w" );
+ Mio_WriteLibrary( pFile, pLib, 0 );
+ fclose( pFile );
+
+ // get the file name with the library
+ pNameGeneric = Extra_FileNameGeneric( Mio_LibraryReadName(pLib) );
+ sprintf( FileNameSuper, "%s.super", pNameGeneric );
+ free( pNameGeneric );
+
+ sprintf( CommandSuper, "super -l 1 -i 5 -d 10000000 -a 10000000 -t 100 %s", FileNameGenlib );
+ if ( Cmd_CommandExecute( pAbc, CommandSuper ) )
+ {
+ fprintf( stdout, "Cannot execute command \"%s\".\n", CommandSuper );
+ return 0;
+ }
+//#ifdef WIN32
+// _unlink( FileNameGenlib );
+//#else
+// unlink( FileNameGenlib );
+//#endif
+
+ sprintf( CommandRead, "read_super %s", FileNameSuper );
+ if ( Cmd_CommandExecute( pAbc, CommandRead ) )
+ {
+#ifdef WIN32
+ _unlink( FileNameSuper );
+#else
+ unlink( FileNameSuper );
+#endif
+ fprintf( stdout, "Cannot execute command \"%s\".\n", CommandRead );
+ return 0;
+ }
+
+/* // don't remove the intermediate file
+#ifdef WIN32
+ _unlink( FileNameSuper );
+#else
+ unlink( FileNameSuper );
+#endif
+*/
+ return 1;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/mapper/mapperMatch.c b/src/map/mapper/mapperMatch.c
new file mode 100644
index 00000000..5b72311c
--- /dev/null
+++ b/src/map/mapper/mapperMatch.c
@@ -0,0 +1,578 @@
+/**CFile****************************************************************
+
+ FileName [mapperMatch.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Generic technology mapping engine.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - June 1, 2004.]
+
+ Revision [$Id: mapperMatch.c,v 1.7 2004/09/30 21:18:10 satrajit Exp $]
+
+***********************************************************************/
+
+#include "mapperInt.h"
+
+/*
+ A potential improvement:
+ When an internal node is not used in the mapping, its required times
+ are set to be +infinity. So when we recover area, we try to find the
+ best match for area and completely disregard the delay for the nodes
+ that are not currently used in the mapping because any match whose
+ arrival times are less than the required times (+infinity) can be used.
+ It may be possible to develop a better approach to recover area for
+ the nodes that are not currently used in the mapping...
+*/
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Map_MatchNodePhase( Map_Man_t * p, Map_Node_t * pNode, int fPhase );
+static int Map_MatchNodeCut( Map_Man_t * p, Map_Node_t * pNode, Map_Cut_t * pCut, int fPhase, float fWorstLimit );
+
+static void Map_MappingSetPiArrivalTimes( Map_Man_t * p );
+static void Map_NodeTryDroppingOnePhase( Map_Man_t * p, Map_Node_t * pNode );
+static void Map_NodeTransferArrivalTimes( Map_Man_t * p, Map_Node_t * pNode );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Computes the best matches of the nodes.]
+
+ Description [Uses parameter p->fMappingMode to decide how to assign
+ the matches for both polarities of the node. While the matches are
+ being assigned, one of them may turn out to be better than the other
+ (in terms of delay, for example). In this case, the worse match can
+ be permanently dropped, and the corresponding pointer set to NULL.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_MappingMatches( Map_Man_t * p )
+{
+ ProgressBar * pProgress;
+ Map_Node_t * pNode;
+ int i;
+
+ assert( p->fMappingMode >= 0 && p->fMappingMode <= 3 );
+
+ // use the externally given PI arrival times
+ if ( p->fMappingMode == 0 )
+ Map_MappingSetPiArrivalTimes( p );
+
+ // estimate the fanouts
+ if ( p->fMappingMode == 0 )
+ Map_MappingEstimateRefsInit( p );
+ else if ( p->fMappingMode == 1 )
+ Map_MappingEstimateRefs( p );
+
+ // the PI cuts are matched in the cut computation package
+ // in the loop below we match the internal nodes
+ pProgress = Extra_ProgressBarStart( stdout, p->vAnds->nSize );
+ for ( i = 0; i < p->vAnds->nSize; i++ )
+ {
+ // skip primary inputs and secondary nodes if mapping with choices
+ pNode = p->vAnds->pArray[i];
+ if ( !Map_NodeIsAnd( pNode ) || pNode->pRepr )
+ continue;
+
+ // make sure that at least one non-trival cut is present
+ if ( pNode->pCuts->pNext == NULL )
+ {
+ printf( "\nError: A node in the mapping graph does not have feasible cuts.\n" );
+ return 0;
+ }
+
+ // match negative phase
+ if ( !Map_MatchNodePhase( p, pNode, 0 ) )
+ return 0;
+ // match positive phase
+ if ( !Map_MatchNodePhase( p, pNode, 1 ) )
+ return 0;
+
+ // make sure that at least one phase is mapped
+ if ( pNode->pCutBest[0] == NULL && pNode->pCutBest[1] == NULL )
+ {
+ printf( "\nError: Could not match both phases of AIG node %d.\n", pNode->Num );
+ printf( "Please make sure that the supergate library has equivalents of AND2 or NAND2.\n" );
+ printf( "If such supergates exist in the library, report a bug.\n" );
+ return 0;
+ }
+
+ // if both phases are assigned, check if one of them can be dropped
+ Map_NodeTryDroppingOnePhase( p, pNode );
+ // set the arrival times of the node using the best cuts
+ Map_NodeTransferArrivalTimes( p, pNode );
+
+ // update the progress bar
+ Extra_ProgressBarUpdate( pProgress, i, "Matches ..." );
+ }
+ Extra_ProgressBarStop( pProgress );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Find the matching of one polarity of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_MatchNodePhase( Map_Man_t * p, Map_Node_t * pNode, int fPhase )
+{
+ Map_Match_t MatchBest, * pMatch;
+ Map_Cut_t * pCut, * pCutBest;
+ float Area1, Area2, fWorstLimit;
+
+ // skip the cuts that have been unassigned during area recovery
+ pCutBest = pNode->pCutBest[fPhase];
+ if ( p->fMappingMode != 0 && pCutBest == NULL )
+ return 1;
+
+ // recompute the arrival times of the current best match
+ // because the arrival times of the fanins may have changed
+ // as a result of remapping fanins in the topological order
+ if ( p->fMappingMode != 0 )
+ {
+ Map_TimeCutComputeArrival( pNode, pCutBest, fPhase, MAP_FLOAT_LARGE );
+ // make sure that the required times are met
+ assert( pCutBest->M[fPhase].tArrive.Rise < pNode->tRequired[fPhase].Rise + p->fEpsilon );
+ assert( pCutBest->M[fPhase].tArrive.Fall < pNode->tRequired[fPhase].Fall + p->fEpsilon );
+ }
+
+ // recompute the exact area of the current best match
+ // because the exact area of the fanins may have changed
+ // as a result of remapping fanins in the topological order
+ if ( p->fMappingMode >= 2 )
+ {
+ pMatch = pCutBest->M + fPhase;
+ if ( pNode->nRefAct[fPhase] > 0 ||
+ (pNode->pCutBest[!fPhase] == NULL && pNode->nRefAct[!fPhase] > 0) )
+ pMatch->AreaFlow = Area1 = Map_CutDeref( pCutBest, fPhase );
+ else
+ pMatch->AreaFlow = Area1 = Map_CutGetAreaDerefed( pCutBest, fPhase );
+ }
+
+ // save the old mapping
+ if ( pCutBest )
+ MatchBest = pCutBest->M[fPhase];
+ else
+ Map_MatchClean( &MatchBest );
+
+ // select the new best cut
+ fWorstLimit = pNode->tRequired[fPhase].Worst;
+ for ( pCut = pNode->pCuts->pNext; pCut; pCut = pCut->pNext )
+ {
+ pMatch = pCut->M + fPhase;
+ if ( pMatch->pSupers == NULL )
+ continue;
+
+ // find the matches for the cut
+ Map_MatchNodeCut( p, pNode, pCut, fPhase, fWorstLimit );
+ if ( pMatch->pSuperBest == NULL || pMatch->tArrive.Worst > fWorstLimit + p->fEpsilon )
+ continue;
+
+ // if the cut can be matched compare the matchings
+ if ( Map_MatchCompare( p, &MatchBest, pMatch, p->fMappingMode ) )
+ {
+ pCutBest = pCut;
+ MatchBest = *pMatch;
+ // if we are mapping for delay, the worst-case limit should be tightened
+ if ( p->fMappingMode == 0 )
+ fWorstLimit = MatchBest.tArrive.Worst;
+ }
+ }
+
+ if ( pCutBest == NULL )
+ return 1;
+
+ // set the new mapping
+ pNode->pCutBest[fPhase] = pCutBest;
+ pCutBest->M[fPhase] = MatchBest;
+
+ // reference the new cut if it used
+ if ( p->fMappingMode >= 2 &&
+ (pNode->nRefAct[fPhase] > 0 ||
+ (pNode->pCutBest[!fPhase] == NULL && pNode->nRefAct[!fPhase] > 0)) )
+ {
+ Area2 = Map_CutRef( pNode->pCutBest[fPhase], fPhase );
+ assert( Area2 < Area1 + p->fEpsilon );
+ }
+
+ // make sure that the requited times are met
+ assert( MatchBest.tArrive.Rise < pNode->tRequired[fPhase].Rise + p->fEpsilon );
+ assert( MatchBest.tArrive.Fall < pNode->tRequired[fPhase].Fall + p->fEpsilon );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Find the best matching of the cut.]
+
+ Description [The parameters: the node (pNode), the cut (pCut), the phase to be matched
+ (fPhase), and the upper bound on the arrival times of the cut (fWorstLimit). This
+ procedure goes through the matching supergates up to the phase assignment, and selects the
+ best supergate, which will be used to map the cut. As a result of calling this procedure
+ the matching information is written into pMatch.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_MatchNodeCut( Map_Man_t * p, Map_Node_t * pNode, Map_Cut_t * pCut, int fPhase, float fWorstLimit )
+{
+ Map_Match_t MatchBest, * pMatch = pCut->M + fPhase;
+ Map_Super_t * pSuper;
+ int i, Counter;
+
+ // save the current match of the cut
+ MatchBest = *pMatch;
+ // go through the supergates
+ for ( pSuper = pMatch->pSupers, Counter = 0; pSuper; pSuper = pSuper->pNext, Counter++ )
+ {
+ p->nMatches++;
+ // this is an attempt to reduce the runtime of matching and area
+ // at the cost of rare and very minor increase in delay
+ // (the supergates are sorted by increasing area)
+ if ( Counter == 30 )
+ break;
+
+ // go through different phases of the given match and supergate
+ pMatch->pSuperBest = pSuper;
+ for ( i = 0; i < (int)pSuper->nPhases; i++ )
+ {
+ p->nPhases++;
+ // find the overall phase of this match
+ pMatch->uPhaseBest = pMatch->uPhase ^ pSuper->uPhases[i];
+ if ( p->fMappingMode == 0 )
+ {
+ // get the arrival time
+ Map_TimeCutComputeArrival( pNode, pCut, fPhase, fWorstLimit );
+ // skip the cut if the arrival times exceed the required times
+ if ( pMatch->tArrive.Worst > fWorstLimit + p->fEpsilon )
+ continue;
+ // get the area (area flow)
+ pMatch->AreaFlow = Map_CutGetAreaFlow( pCut, fPhase );
+ }
+ else
+ {
+ // get the area (area flow)
+ if ( p->fMappingMode >= 2 )
+ pMatch->AreaFlow = Map_CutGetAreaDerefed( pCut, fPhase );
+ else
+ pMatch->AreaFlow = Map_CutGetAreaFlow( pCut, fPhase );
+ // skip if the cut is too large
+ if ( pMatch->AreaFlow > MatchBest.AreaFlow + p->fEpsilon )
+ continue;
+ // get the arrival time
+ Map_TimeCutComputeArrival( pNode, pCut, fPhase, fWorstLimit );
+ // skip the cut if the arrival times exceed the required times
+ if ( pMatch->tArrive.Worst > fWorstLimit + p->fEpsilon )
+ continue;
+ }
+
+ // if the cut is non-trivial, compare it
+ if ( Map_MatchCompare( p, &MatchBest, pMatch, p->fMappingMode ) )
+ {
+ MatchBest = *pMatch;
+ // if we are mapping for delay, the worst-case limit should be reduced
+ if ( p->fMappingMode == 0 )
+ fWorstLimit = MatchBest.tArrive.Worst;
+ }
+ }
+ }
+ // set the best match
+ *pMatch = MatchBest;
+
+ // recompute the arrival time and area (area flow) of this cut
+ if ( pMatch->pSuperBest )
+ {
+ Map_TimeCutComputeArrival( pNode, pCut, fPhase, MAP_FLOAT_LARGE );
+ if ( p->fMappingMode >= 2 )
+ pMatch->AreaFlow = Map_CutGetAreaDerefed( pCut, fPhase );
+ else
+ pMatch->AreaFlow = Map_CutGetAreaFlow( pCut, fPhase );
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Cleans the match.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MatchClean( Map_Match_t * pMatch )
+{
+ memset( pMatch, 0, sizeof(Map_Match_t) );
+ pMatch->AreaFlow = MAP_FLOAT_LARGE; // unassigned
+ pMatch->tArrive.Rise = MAP_FLOAT_LARGE; // unassigned
+ pMatch->tArrive.Fall = MAP_FLOAT_LARGE; // unassigned
+ pMatch->tArrive.Worst = MAP_FLOAT_LARGE; // unassigned
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares two matches.]
+
+ Description [Returns 1 if the second match is better. Otherwise returns 0.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_MatchCompare( Map_Man_t * pMan, Map_Match_t * pM1, Map_Match_t * pM2, int fDoingArea )
+{
+ if ( !fDoingArea )
+ {
+ // compare the arrival times
+ if ( pM1->tArrive.Worst < pM2->tArrive.Worst - pMan->fEpsilon )
+ return 0;
+ if ( pM1->tArrive.Worst > pM2->tArrive.Worst + pMan->fEpsilon )
+ return 1;
+ // compare the areas or area flows
+ if ( pM1->AreaFlow < pM2->AreaFlow - pMan->fEpsilon )
+ return 0;
+ if ( pM1->AreaFlow > pM2->AreaFlow + pMan->fEpsilon )
+ return 1;
+ // compare the fanout limits
+ if ( pM1->pSuperBest->nFanLimit > pM2->pSuperBest->nFanLimit )
+ return 0;
+ if ( pM1->pSuperBest->nFanLimit < pM2->pSuperBest->nFanLimit )
+ return 1;
+ // compare the number of leaves
+ if ( pM1->pSuperBest->nFanins < pM2->pSuperBest->nFanins )
+ return 0;
+ if ( pM1->pSuperBest->nFanins > pM2->pSuperBest->nFanins )
+ return 1;
+ // otherwise prefer the old cut
+ return 0;
+ }
+ else
+ {
+ // compare the areas or area flows
+ if ( pM1->AreaFlow < pM2->AreaFlow - pMan->fEpsilon )
+ return 0;
+ if ( pM1->AreaFlow > pM2->AreaFlow + pMan->fEpsilon )
+ return 1;
+ // compare the arrival times
+ if ( pM1->tArrive.Worst < pM2->tArrive.Worst - pMan->fEpsilon )
+ return 0;
+ if ( pM1->tArrive.Worst > pM2->tArrive.Worst + pMan->fEpsilon )
+ return 1;
+ // compare the fanout limits
+ if ( pM1->pSuperBest->nFanLimit > pM2->pSuperBest->nFanLimit )
+ return 0;
+ if ( pM1->pSuperBest->nFanLimit < pM2->pSuperBest->nFanLimit )
+ return 1;
+ // compare the number of leaves
+ if ( pM1->pSuperBest->nFanins < pM2->pSuperBest->nFanins )
+ return 0;
+ if ( pM1->pSuperBest->nFanins > pM2->pSuperBest->nFanins )
+ return 1;
+ // otherwise prefer the old cut
+ return 0;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the PI arrival times.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingSetPiArrivalTimes( Map_Man_t * p )
+{
+ Map_Node_t * pNode;
+ int i;
+ for ( i = 0; i < p->nInputs; i++ )
+ {
+ pNode = p->pInputs[i];
+ // set the arrival time of the positive phase
+ pNode->tArrival[1] = p->pInputArrivals[i];
+ // set the arrival time of the negative phase
+ pNode->tArrival[0].Rise = pNode->tArrival[1].Fall + p->pSuperLib->tDelayInv.Rise;
+ pNode->tArrival[0].Fall = pNode->tArrival[1].Rise + p->pSuperLib->tDelayInv.Fall;
+ pNode->tArrival[0].Worst = MAP_MAX(pNode->tArrival[0].Rise, pNode->tArrival[0].Fall);
+ }
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Attempts dropping one phase of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_NodeTryDroppingOnePhase( Map_Man_t * p, Map_Node_t * pNode )
+{
+ Map_Match_t * pMatchBest0, * pMatchBest1;
+ float tWorst0Using1, tWorst1Using0;
+ int fUsePhase1, fUsePhase0;
+
+ // nothing to do if one of the phases is already dropped
+ if ( pNode->pCutBest[0] == NULL || pNode->pCutBest[1] == NULL )
+ return;
+
+ // do not drop while recovering area flow
+ if ( p->fMappingMode == 1 )//|| p->fMappingMode == 2 )
+ return;
+
+ // get the pointers to the matches of the best cuts
+ pMatchBest0 = pNode->pCutBest[0]->M + 0;
+ pMatchBest1 = pNode->pCutBest[1]->M + 1;
+
+ // get the worst arrival times of each phase
+ // implemented using the other phase with inverter added
+ tWorst0Using1 = Map_TimeMatchWithInverter( p, pMatchBest1 );
+ tWorst1Using0 = Map_TimeMatchWithInverter( p, pMatchBest0 );
+
+ // consider the case of mapping for delay
+ if ( p->fMappingMode == 0 )
+ {
+ // if the arrival time of a phase is larger than the arrival time
+ // of the opposite phase plus the inverter, drop this phase
+ if ( pMatchBest0->tArrive.Worst > tWorst0Using1 + p->fEpsilon )
+ pNode->pCutBest[0] = NULL;
+ else if ( pMatchBest1->tArrive.Worst > tWorst1Using0 + p->fEpsilon )
+ pNode->pCutBest[1] = NULL;
+ return;
+ }
+
+ // do not perform replacement if one of the phases is unused
+ if ( pNode->nRefAct[0] == 0 || pNode->nRefAct[1] == 0 )
+ return;
+
+ // check if replacement of each phase is possible using required times
+ fUsePhase0 = fUsePhase1 = 0;
+ if ( p->fMappingMode == 2 )
+ {
+ fUsePhase0 = (pNode->tRequired[1].Worst > tWorst1Using0 + 3*p->pSuperLib->tDelayInv.Worst + p->fEpsilon);
+ fUsePhase1 = (pNode->tRequired[0].Worst > tWorst0Using1 + 3*p->pSuperLib->tDelayInv.Worst + p->fEpsilon);
+ }
+ else if ( p->fMappingMode == 3 )
+ {
+ fUsePhase0 = (pNode->tRequired[1].Worst > tWorst1Using0 + p->fEpsilon);
+ fUsePhase1 = (pNode->tRequired[0].Worst > tWorst0Using1 + p->fEpsilon);
+ }
+ if ( !fUsePhase0 && !fUsePhase1 )
+ return;
+
+ // if replacement is possible both ways, use the one that works better
+ if ( fUsePhase0 && fUsePhase1 )
+ {
+ if ( pMatchBest0->AreaFlow < pMatchBest1->AreaFlow )
+ fUsePhase1 = 0;
+ else
+ fUsePhase0 = 0;
+ }
+ // only one phase should be used
+ assert( fUsePhase0 ^ fUsePhase1 );
+
+ // set the corresponding cut to NULL
+ if ( fUsePhase0 )
+ {
+ // deref phase 1 cut if necessary
+ if ( p->fMappingMode >= 2 && pNode->nRefAct[1] > 0 )
+ Map_CutDeref( pNode->pCutBest[1], 1 );
+ // get rid of the cut
+ pNode->pCutBest[1] = NULL;
+ // ref phase 0 cut if necessary
+ if ( p->fMappingMode >= 2 && pNode->nRefAct[0] == 0 )
+ Map_CutRef( pNode->pCutBest[0], 0 );
+ }
+ else
+ {
+ // deref phase 0 cut if necessary
+ if ( p->fMappingMode >= 2 && pNode->nRefAct[0] > 0 )
+ Map_CutDeref( pNode->pCutBest[0], 0 );
+ // get rid of the cut
+ pNode->pCutBest[0] = NULL;
+ // ref phase 1 cut if necessary
+ if ( p->fMappingMode >= 2 && pNode->nRefAct[1] == 0 )
+ Map_CutRef( pNode->pCutBest[1], 1 );
+ }
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Transfers the arrival times from the best cuts to the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_NodeTransferArrivalTimes( Map_Man_t * p, Map_Node_t * pNode )
+{
+ // if both phases are available, set their arrival times
+ if ( pNode->pCutBest[0] && pNode->pCutBest[1] )
+ {
+ pNode->tArrival[0] = pNode->pCutBest[0]->M[0].tArrive;
+ pNode->tArrival[1] = pNode->pCutBest[1]->M[1].tArrive;
+ }
+ // if only one phase is available, compute the arrival time of other phase
+ else if ( pNode->pCutBest[0] )
+ {
+ pNode->tArrival[0] = pNode->pCutBest[0]->M[0].tArrive;
+ pNode->tArrival[1].Rise = pNode->tArrival[0].Fall + p->pSuperLib->tDelayInv.Rise;
+ pNode->tArrival[1].Fall = pNode->tArrival[0].Rise + p->pSuperLib->tDelayInv.Fall;
+ pNode->tArrival[1].Worst = MAP_MAX(pNode->tArrival[1].Rise, pNode->tArrival[1].Fall);
+ }
+ else if ( pNode->pCutBest[1] )
+ {
+ pNode->tArrival[1] = pNode->pCutBest[1]->M[1].tArrive;
+ pNode->tArrival[0].Rise = pNode->tArrival[1].Fall + p->pSuperLib->tDelayInv.Rise;
+ pNode->tArrival[0].Fall = pNode->tArrival[1].Rise + p->pSuperLib->tDelayInv.Fall;
+ pNode->tArrival[0].Worst = MAP_MAX(pNode->tArrival[0].Rise, pNode->tArrival[0].Fall);
+ }
+ else
+ {
+ assert( 0 );
+ }
+
+ assert( pNode->tArrival[0].Rise < pNode->tRequired[0].Rise + p->fEpsilon );
+ assert( pNode->tArrival[0].Fall < pNode->tRequired[0].Fall + p->fEpsilon );
+
+ assert( pNode->tArrival[1].Rise < pNode->tRequired[1].Rise + p->fEpsilon );
+ assert( pNode->tArrival[1].Fall < pNode->tRequired[1].Fall + p->fEpsilon );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
diff --git a/src/map/mapper/mapperRefs.c b/src/map/mapper/mapperRefs.c
new file mode 100644
index 00000000..334e98c7
--- /dev/null
+++ b/src/map/mapper/mapperRefs.c
@@ -0,0 +1,541 @@
+/**CFile****************************************************************
+
+ FileName [mapperRefs.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Generic technology mapping engine.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - June 1, 2004.]
+
+ Revision [$Id: mapperRefs.h,v 1.0 2003/09/08 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mapperInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Map_NodeIncRefPhaseAct( Map_Node_t * pNode, int fPhase );
+static int Map_NodeDecRefPhaseAct( Map_Node_t * pNode, int fPhase );
+static float Map_CutRefDeref( Map_Cut_t * pCut, int fPhase, int fReference );
+static void Map_MappingSetRefs_rec( Map_Man_t * pMan, Map_Node_t * pNode );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Reads the actual reference counter of a phase.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_NodeReadRefPhaseAct( Map_Node_t * pNode, int fPhase )
+{
+ assert( !Map_IsComplement(pNode) );
+ if ( pNode->pCutBest[0] && pNode->pCutBest[1] ) // both assigned
+ return pNode->nRefAct[fPhase];
+ assert( pNode->pCutBest[0] || pNode->pCutBest[1] ); // at least one assigned
+ return pNode->nRefAct[2];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads the estimated reference counter of a phase.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Map_NodeReadRefPhaseEst( Map_Node_t * pNode, int fPhase )
+{
+ assert( !Map_IsComplement(pNode) );
+ if ( pNode->pCutBest[0] && pNode->pCutBest[1] ) // both assigned
+ return pNode->nRefEst[fPhase];
+ assert( pNode->pCutBest[0] || pNode->pCutBest[1] ); // at least one assigned
+// return pNode->nRefEst[0] + pNode->nRefEst[1];
+ return pNode->nRefEst[2];
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Increments the actual reference counter of a phase.]
+
+ Description [Returns the old reference counter.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_NodeIncRefPhaseAct( Map_Node_t * pNode, int fPhase )
+{
+ assert( !Map_IsComplement(pNode) );
+ if ( pNode->pCutBest[0] && pNode->pCutBest[1] ) // both assigned
+ return pNode->nRefAct[fPhase]++;
+ assert( pNode->pCutBest[0] || pNode->pCutBest[1] ); // at least one assigned
+ return pNode->nRefAct[2]++;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Decrements the actual reference counter of a phase.]
+
+ Description [Returns the new reference counter.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_NodeDecRefPhaseAct( Map_Node_t * pNode, int fPhase )
+{
+ assert( !Map_IsComplement(pNode) );
+ if ( pNode->pCutBest[0] && pNode->pCutBest[1] ) // both assigned
+ return --pNode->nRefAct[fPhase];
+ assert( pNode->pCutBest[0] || pNode->pCutBest[1] ); // at least one assigned
+ return --pNode->nRefAct[2];
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Sets the estimated reference counter for the PIs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingEstimateRefsInit( Map_Man_t * p )
+{
+ Map_Node_t * pNode;
+ int i;
+ for ( i = 0; i < p->vAnds->nSize; i++ )
+ {
+ pNode = p->vAnds->pArray[i];
+// pNode->nRefEst[0] = pNode->nRefEst[1] = ((float)pNode->nRefs)*(float)2.0;
+ pNode->nRefEst[0] = pNode->nRefEst[1] = pNode->nRefEst[2] = ((float)pNode->nRefs);
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the estimated reference counter.]
+
+ Description [When this procedure is called for the first time,
+ the reference counter is estimated from the AIG. Otherwise, it is
+ a linear combination of reference counters in the last two iterations.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingEstimateRefs( Map_Man_t * p )
+{
+ Map_Node_t * pNode;
+ int i;
+ for ( i = 0; i < p->vAnds->nSize; i++ )
+ {
+ pNode = p->vAnds->pArray[i];
+// pNode->nRefEst[0] = (float)((2.0 * pNode->nRefEst[0] + 1.0 * pNode->nRefAct[0]) / 3.0);
+// pNode->nRefEst[1] = (float)((2.0 * pNode->nRefEst[1] + 1.0 * pNode->nRefAct[1]) / 3.0);
+// pNode->nRefEst[2] = (float)((2.0 * pNode->nRefEst[2] + 1.0 * pNode->nRefAct[2]) / 3.0);
+ pNode->nRefEst[0] = (float)((3.0 * pNode->nRefEst[0] + 1.0 * pNode->nRefAct[0]) / 4.0);
+ pNode->nRefEst[1] = (float)((3.0 * pNode->nRefEst[1] + 1.0 * pNode->nRefAct[1]) / 4.0);
+ pNode->nRefEst[2] = (float)((3.0 * pNode->nRefEst[2] + 1.0 * pNode->nRefAct[2]) / 4.0);
+ }
+}
+
+
+
+
+
+/**function*************************************************************
+
+ synopsis [Computes the area flow of the cut.]
+
+ description [Computes the area flow of the cut if it is implemented using
+ the best supergate with the best phase.]
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+float Map_CutGetAreaFlow( Map_Cut_t * pCut, int fPhase )
+{
+ Map_Match_t * pM = pCut->M + fPhase;
+ Map_Super_t * pSuper = pM->pSuperBest;
+ unsigned uPhaseTot = pM->uPhaseBest;
+ Map_Cut_t * pCutFanin;
+ float aFlowRes, aFlowFanin, nRefs;
+ int i, fPinPhasePos;
+
+ // start the resulting area flow
+ aFlowRes = pSuper->Area;
+ // iterate through the leaves
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ {
+ // get the phase of this fanin
+ fPinPhasePos = ((uPhaseTot & (1 << i)) == 0);
+ // get the cut implementing this phase of the fanin
+ pCutFanin = pCut->ppLeaves[i]->pCutBest[fPinPhasePos];
+ // if the cut is not available, we have to use the opposite phase
+ if ( pCutFanin == NULL )
+ {
+ fPinPhasePos = !fPinPhasePos;
+ pCutFanin = pCut->ppLeaves[i]->pCutBest[fPinPhasePos];
+ }
+ aFlowFanin = pCutFanin->M[fPinPhasePos].AreaFlow; // ignores the area of the interter
+ // get the fanout count of the cut in the given phase
+ nRefs = Map_NodeReadRefPhaseEst( pCut->ppLeaves[i], fPinPhasePos );
+ // if the node does no fanout, assume fanout count equal to 1
+ if ( nRefs == (float)0.0 )
+ nRefs = (float)1.0;
+ // add the area flow due to the fanin
+ aFlowRes += aFlowFanin / nRefs;
+ }
+ pM->AreaFlow = aFlowRes;
+ return aFlowRes;
+}
+
+
+
+/**function*************************************************************
+
+ synopsis [Computes the exact area associated with the cut.]
+
+ description [Assumes that the cut is referenced.]
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+float Map_CutGetAreaRefed( Map_Cut_t * pCut, int fPhase )
+{
+ float aResult, aResult2;
+ aResult2 = Map_CutRefDeref( pCut, fPhase, 0 ); // dereference
+ aResult = Map_CutRefDeref( pCut, fPhase, 1 ); // reference
+ assert( aResult == aResult2 );
+ return aResult;
+}
+
+/**function*************************************************************
+
+ synopsis [Computes the exact area associated with the cut.]
+
+ description []
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+float Map_CutGetAreaDerefed( Map_Cut_t * pCut, int fPhase )
+{
+ float aResult, aResult2;
+ aResult2 = Map_CutRefDeref( pCut, fPhase, 1 ); // reference
+ aResult = Map_CutRefDeref( pCut, fPhase, 0 ); // dereference
+ assert( aResult == aResult2 );
+ return aResult;
+}
+
+/**function*************************************************************
+
+ synopsis [References the cut.]
+
+ description []
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+float Map_CutRef( Map_Cut_t * pCut, int fPhase )
+{
+ return Map_CutRefDeref( pCut, fPhase, 1 ); // reference
+}
+
+/**function*************************************************************
+
+ synopsis [References the cut.]
+
+ description []
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+float Map_CutDeref( Map_Cut_t * pCut, int fPhase )
+{
+ return Map_CutRefDeref( pCut, fPhase, 0 ); // dereference
+}
+
+/**function*************************************************************
+
+ synopsis [References or dereferences the cut.]
+
+ description [This reference part is similar to Cudd_NodeReclaim().
+ The dereference part is similar to Cudd_RecursiveDeref(). The
+ area of the inverter is not counted.]
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+float Map_CutRefDeref( Map_Cut_t * pCut, int fPhase, int fReference )
+{
+ Map_Node_t * pNodeChild;
+ Map_Cut_t * pCutChild;
+ float aArea;
+ int i, fPhaseChild;
+// int nRefs;
+
+ // consider the elementary variable
+ if ( pCut->nLeaves == 1 )
+ return 0;
+ // start the area of this cut
+ aArea = Map_CutGetRootArea( pCut, fPhase );
+ // go through the children
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ {
+ pNodeChild = pCut->ppLeaves[i];
+ fPhaseChild = Map_CutGetLeafPhase( pCut, fPhase, i );
+ // get the reference counter of the child
+/*
+ // this code does not take inverters into account
+ // the quality of area recovery seems to always be a little worse
+ if ( fReference )
+ nRefs = Map_NodeIncRefPhaseAct( pNodeChild, fPhaseChild );
+ else
+ nRefs = Map_NodeDecRefPhaseAct( pNodeChild, fPhaseChild );
+ assert( nRefs >= 0 );
+ // skip if the child was already reference before
+ if ( nRefs > 0 )
+ continue;
+*/
+
+ if ( fReference )
+ {
+ if ( pNodeChild->pCutBest[0] && pNodeChild->pCutBest[1] ) // both phases are present
+ {
+ // if this phase of the node is referenced, there is no recursive call
+ pNodeChild->nRefAct[2]++;
+ if ( pNodeChild->nRefAct[fPhaseChild]++ > 0 )
+ continue;
+ }
+ else // only one phase is present
+ {
+ // inverter should be added if the phase
+ // (a) has no reference and (b) is implemented using other phase
+ if ( pNodeChild->nRefAct[fPhaseChild]++ == 0 && pNodeChild->pCutBest[fPhaseChild] == NULL )
+ aArea += pNodeChild->p->pSuperLib->AreaInv;
+ // if the node is referenced, there is no recursive call
+ if ( pNodeChild->nRefAct[2]++ > 0 )
+ continue;
+ }
+ }
+ else
+ {
+ if ( pNodeChild->pCutBest[0] && pNodeChild->pCutBest[1] ) // both phases are present
+ {
+ // if this phase of the node is referenced, there is no recursive call
+ --pNodeChild->nRefAct[2];
+ if ( --pNodeChild->nRefAct[fPhaseChild] > 0 )
+ continue;
+ }
+ else // only one phase is present
+ {
+ // inverter should be added if the phase
+ // (a) has no reference and (b) is implemented using other phase
+ if ( --pNodeChild->nRefAct[fPhaseChild] == 0 && pNodeChild->pCutBest[fPhaseChild] == NULL )
+ aArea += pNodeChild->p->pSuperLib->AreaInv;
+ // if the node is referenced, there is no recursive call
+ if ( --pNodeChild->nRefAct[2] > 0 )
+ continue;
+ }
+ assert( pNodeChild->nRefAct[fPhaseChild] >= 0 );
+ }
+
+ // get the child cut
+ pCutChild = pNodeChild->pCutBest[fPhaseChild];
+ // if the child does not have this phase mapped, take the opposite phase
+ if ( pCutChild == NULL )
+ {
+ fPhaseChild = !fPhaseChild;
+ pCutChild = pNodeChild->pCutBest[fPhaseChild];
+ }
+ // reference and compute area recursively
+ aArea += Map_CutRefDeref( pCutChild, fPhaseChild, fReference );
+ }
+ return aArea;
+}
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Computes actual reference counters.]
+
+ Description [Stores all the nodes used in the mapping in the array pMan->vMapping.
+ The nodes are stored in the random order.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingSetRefs( Map_Man_t * pMan )
+{
+ Map_Node_t * pNode;
+ int i, fPhase;
+ // clean all references
+ for ( i = 0; i < pMan->vNodesAll->nSize; i++ )
+ {
+ pNode = pMan->vNodesAll->pArray[i];
+ pNode->nRefAct[0] = 0;
+ pNode->nRefAct[1] = 0;
+ pNode->nRefAct[2] = 0;
+ }
+ // visit nodes reachable from POs in the DFS order through the best cuts
+ pMan->vMapping->nSize = 0;
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ {
+ pNode = pMan->pOutputs[i];
+ fPhase = !Map_IsComplement(pNode);
+ if ( !Map_NodeIsConst(pNode) )
+ Map_MappingSetRefs_rec( pMan, pNode );
+ // reference count the PO node
+// Map_Regular(pNode)->nRefAct[fPhase]++;
+// Map_Regular(pNode)->nRefAct[2]++;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingSetRefs_rec( Map_Man_t * pMan, Map_Node_t * pNode )
+{
+ Map_Cut_t * pCut;
+ Map_Node_t * pNodeR;
+ unsigned uPhase;
+ int i, fPhase, fInvPin;
+
+ // get the regular node and its phase
+ pNodeR = Map_Regular(pNode);
+ fPhase = !Map_IsComplement(pNode);
+
+ // add the node to the list of all visited nodes
+ if ( pNodeR->nRefAct[2]++ == 0 )
+ Map_NodeVecPush( pMan->vMapping, pNodeR );
+
+ // quit if the node was already visited in this phase
+ if ( pNodeR->nRefAct[fPhase]++ )
+ return;
+
+ // quit if this is a PI node
+ if ( Map_NodeIsVar(pNodeR) )
+ return;
+
+ // get the cut implementing this or opposite polarity
+ pCut = pNodeR->pCutBest[fPhase];
+ if ( pCut == NULL )
+ {
+ fPhase = !fPhase;
+ pCut = pNodeR->pCutBest[fPhase];
+ }
+
+ // visit the transitive fanin
+ uPhase = pCut->M[fPhase].uPhaseBest;
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ {
+ fInvPin = ((uPhase & (1 << i)) > 0);
+ Map_MappingSetRefs_rec( pMan, Map_NotCond(pCut->ppLeaves[i], fInvPin) );
+ }
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Computes the array of mapping.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Map_MappingGetArea( Map_Man_t * pMan, Map_NodeVec_t * vMapping )
+{
+ Map_Node_t * pNode;
+ float Area;
+ int i;
+ Area = 0.0;
+ for ( i = 0; i < vMapping->nSize; i++ )
+ {
+ pNode = vMapping->pArray[i];
+ // at least one phase has the best cut assigned
+ assert( pNode->pCutBest[0] != NULL || pNode->pCutBest[1] != NULL );
+ // at least one phase is used in the mapping
+ assert( pNode->nRefAct[0] > 0 || pNode->nRefAct[1] > 0 );
+ // compute the array due to the supergate
+ if ( Map_NodeIsAnd(pNode) )
+ {
+ // count area of the negative phase
+ if ( pNode->pCutBest[0] && (pNode->nRefAct[0] > 0 || pNode->pCutBest[1] == NULL) )
+ Area += pNode->pCutBest[0]->M[0].pSuperBest->Area;
+ // count area of the positive phase
+ if ( pNode->pCutBest[1] && (pNode->nRefAct[1] > 0 || pNode->pCutBest[0] == NULL) )
+ Area += pNode->pCutBest[1]->M[1].pSuperBest->Area;
+ }
+ // count area of the interver if we need to implement one phase with another phase
+ if ( (pNode->pCutBest[0] == NULL && pNode->nRefAct[0] > 0) ||
+ (pNode->pCutBest[1] == NULL && pNode->nRefAct[1] > 0) )
+ Area += pMan->pSuperLib->AreaInv;
+ }
+ // add two inverters for each PO buffer
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ if ( Map_NodeIsVar(pMan->pOutputs[i]) && !Map_IsComplement(pMan->pOutputs[i]) )
+ Area += 2 * pMan->pSuperLib->AreaInv;
+ return Area;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/mapper/mapperSuper.c b/src/map/mapper/mapperSuper.c
new file mode 100644
index 00000000..34b1d8e6
--- /dev/null
+++ b/src/map/mapper/mapperSuper.c
@@ -0,0 +1,449 @@
+/**CFile****************************************************************
+
+ FileName [mapperSuper.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Generic technology mapping engine.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - June 1, 2004.]
+
+ Revision [$Id: mapperSuper.c,v 1.6 2005/01/23 06:59:44 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mapperInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Map_LibraryReadFile( Map_SuperLib_t * pLib, FILE * pFile );
+static Map_Super_t * Map_LibraryReadGate( Map_SuperLib_t * pLib, char * pBuffer, int nVars );
+static int Map_LibraryTruthVerify( Map_SuperLib_t * pLib, Map_Super_t * pGate );
+static void Map_LibraryComputeTruth( Map_SuperLib_t * pLib, char * pFormula, unsigned uTruthRes[] );
+static void Map_LibraryComputeTruth_rec( Map_SuperLib_t * pLib, char * pFormula, unsigned uTruthsIn[][2], unsigned uTruthRes[] );
+static void Map_LibraryPrintClasses( Map_SuperLib_t * p );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Reads the supergate library from file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_LibraryRead( Map_SuperLib_t * pLib, char * pFileName )
+{
+ FILE * pFile;
+ int Status;
+ // read the beginning of the file
+ assert( pLib->pGenlib == NULL );
+ pFile = fopen( pFileName, "r" );
+ if ( pFile == NULL )
+ {
+ printf( "Cannot open input file \"%s\".\n", pFileName );
+ return 0;
+ }
+ Status = Map_LibraryReadFile( pLib, pFile );
+ fclose( pFile );
+// Map_LibraryPrintClasses( pLib );
+ return Status;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Reads the library file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_LibraryReadFile( Map_SuperLib_t * pLib, FILE * pFile )
+{
+ ProgressBar * pProgress;
+ char pBuffer[2000];
+ FILE * pFileGen;
+ Map_Super_t * pGate;
+ char * pTemp, * pLibName;
+ int nCounter, nGatesTotal;
+ unsigned uCanon[2];
+
+ // skip empty and comment lines
+ while ( fgets( pBuffer, 5000, pFile ) != NULL )
+ {
+ // skip leading spaces
+ for ( pTemp = pBuffer; *pTemp == ' ' || *pTemp == '\r' || *pTemp == '\n'; pTemp++ );
+ // skip comment lines and empty lines
+ if ( *pTemp != 0 && *pTemp != '#' )
+ break;
+ }
+
+ // get the genlib file name
+ pLibName = strtok( pTemp, " \t\r\n" );
+ if ( strcmp( pLibName, "GATE" ) == 0 )
+ {
+ printf( "The input file \"%s\" looks like a GENLIB file and not a supergate library file.\n", pLib->pName );
+ return 0;
+ }
+ pFileGen = fopen( pLibName, "r" );
+ if ( pFileGen == NULL )
+ {
+ printf( "Cannot open the GENLIB file \"%s\".\n", pLibName );
+ return 0;
+ }
+ fclose( pFileGen );
+
+ // read the genlib library
+ pLib->pGenlib = Mio_LibraryRead( Abc_FrameGetGlobalFrame(), pLibName, 0, 0 );
+ if ( pLib->pGenlib == NULL )
+ {
+ printf( "Cannot read GENLIB file \"%s\".\n", pLibName );
+ return 0;
+ }
+
+ // read the number of variables
+ fscanf( pFile, "%d\n", &pLib->nVarsMax );
+ if ( pLib->nVarsMax < 2 || pLib->nVarsMax > 10 )
+ {
+ printf( "Suspicious number of variables (%d).\n", pLib->nVarsMax );
+ return 0;
+ }
+
+ // read the number of gates
+ fscanf( pFile, "%d\n", &nGatesTotal );
+ if ( nGatesTotal < 1 || nGatesTotal > 10000000 )
+ {
+ printf( "Suspicious number of gates (%d).\n", nGatesTotal );
+ return 0;
+ }
+
+ // read the lines
+ nCounter = 0;
+ pProgress = Extra_ProgressBarStart( stdout, nGatesTotal );
+ while ( fgets( pBuffer, 5000, pFile ) != NULL )
+ {
+ for ( pTemp = pBuffer; *pTemp == ' ' || *pTemp == '\r' || *pTemp == '\n'; pTemp++ );
+ if ( pTemp[0] == '\0' )
+ continue;
+ // get the gate
+ pGate = Map_LibraryReadGate( pLib, pTemp, pLib->nVarsMax );
+ assert( pGate->Num == nCounter + 1 );
+ // count the number of parantheses in the formula - this is the number of gates
+ for ( pTemp = pGate->pFormula; *pTemp; pTemp++ )
+ pGate->nGates += (*pTemp == '(');
+ // verify the truth table
+ assert( Map_LibraryTruthVerify(pLib, pGate) );
+
+ // find the N-canonical form of this supergate
+ pGate->nPhases = Map_CanonComputeSlow( pLib->uTruths, pLib->nVarsMax, pLib->nVarsMax, pGate->uTruth, pGate->uPhases, uCanon );
+ // add the supergate into the table by its N-canonical table
+ Map_SuperTableInsertC( pLib->tTableC, uCanon, pGate );
+ // update the progress bar
+ Extra_ProgressBarUpdate( pProgress, ++nCounter, NULL );
+ }
+ Extra_ProgressBarStop( pProgress );
+ pLib->nSupersAll = nCounter;
+ if ( nCounter != nGatesTotal )
+ printf( "The number of gates read (%d) is different what the file says (%d).\n", nGatesTotal, nCounter );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Super_t * Map_LibraryReadGate( Map_SuperLib_t * pLib, char * pBuffer, int nVars )
+{
+ Map_Super_t * pGate;
+ char * pTemp;
+ int i;
+
+ // start and clean the gate
+ pGate = (Map_Super_t *)Extra_MmFixedEntryFetch( pLib->mmSupers );
+ memset( pGate, 0, sizeof(Map_Super_t) );
+
+ // read the number
+ pTemp = strtok( pBuffer, " " );
+ pGate->Num = atoi(pTemp);
+
+ // read the signature
+ pTemp = strtok( NULL, " " );
+ if ( pLib->nVarsMax < 6 )
+ {
+ pGate->uTruth[0] = Extra_ReadBinary(pTemp);
+ pGate->uTruth[1] = 0;
+ }
+ else
+ {
+ pGate->uTruth[0] = Extra_ReadBinary(pTemp+32);
+ pTemp[32] = 0;
+ pGate->uTruth[1] = Extra_ReadBinary(pTemp);
+ }
+
+ // read the max delay
+ pTemp = strtok( NULL, " " );
+ pGate->tDelayMax.Rise = (float)atof(pTemp);
+ pGate->tDelayMax.Fall = pGate->tDelayMax.Rise;
+
+ // read the pin-to-pin delay
+ for ( i = 0; i < nVars; i++ )
+ {
+ pTemp = strtok( NULL, " " );
+ pGate->tDelaysR[i].Rise = (float)atof(pTemp);
+ pGate->tDelaysF[i].Fall = pGate->tDelaysR[i].Rise;
+ }
+
+ // read the area
+ pTemp = strtok( NULL, " " );
+ pGate->Area = (float)atof(pTemp);
+
+ // the rest is the gate name
+ pTemp = strtok( NULL, " \r\n" );
+ if ( strlen(pTemp) == 0 )
+ printf( "A gate name is empty.\n" );
+
+ // save the gate name
+ pGate->pFormula = Extra_MmFlexEntryFetch( pLib->mmForms, strlen(pTemp) + 1 );
+ strcpy( pGate->pFormula, pTemp );
+
+ // the rest is the gate name
+ pTemp = strtok( NULL, " \n\0" );
+ if ( pTemp != NULL )
+ printf( "The following trailing symbols found \"%s\".\n", pTemp );
+ return pGate;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs one step of parsing the formula into parts.]
+
+ Description [This function will eventually be replaced when the
+ tree-supergate library representation will become standard.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Map_LibraryReadFormulaStep( char * pFormula, char * pStrings[], int * pnStrings )
+{
+ char * pName, * pPar1, * pPar2, * pCur;
+ int nStrings, CountPars;
+
+ // skip leading spaces
+ for ( pName = pFormula; *pName && *pName == ' '; pName++ );
+ assert( *pName );
+ // find the first opening paranthesis
+ for ( pPar1 = pName; *pPar1 && *pPar1 != '('; pPar1++ );
+ if ( *pPar1 == 0 )
+ {
+ *pnStrings = 0;
+ return pName;
+ }
+ // overwrite it with space
+ assert( *pPar1 == '(' );
+ *pPar1 = 0;
+ // find the corresponding closing paranthesis
+ for ( CountPars = 1, pPar2 = pPar1 + 1; *pPar2 && CountPars; pPar2++ )
+ if ( *pPar2 == '(' )
+ CountPars++;
+ else if ( *pPar2 == ')' )
+ CountPars--;
+ pPar2--;
+ assert( CountPars == 0 );
+ // overwrite it with space
+ assert( *pPar2 == ')' );
+ *pPar2 = 0;
+ // save the intervals between the commas
+ nStrings = 0;
+ pCur = pPar1 + 1;
+ while ( 1 )
+ {
+ // save the current string
+ pStrings[ nStrings++ ] = pCur;
+ // find the beginning of the next string
+ for ( CountPars = 0; *pCur && (CountPars || *pCur != ','); pCur++ )
+ if ( *pCur == '(' )
+ CountPars++;
+ else if ( *pCur == ')' )
+ CountPars--;
+ if ( *pCur == 0 )
+ break;
+ assert( *pCur == ',' );
+ *pCur = 0;
+ pCur++;
+ }
+ // save the results and return
+ *pnStrings = nStrings;
+ return pName;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Verifies the truth table of the supergate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_LibraryTruthVerify( Map_SuperLib_t * pLib, Map_Super_t * pGate )
+{
+ unsigned uTruthRes[2];
+ Map_LibraryComputeTruth( pLib, pGate->pFormula, uTruthRes );
+ if ( uTruthRes[0] != pGate->uTruth[0] || uTruthRes[1] != pGate->uTruth[1] )
+ return 0;
+ return 1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Derives the functionality of the supergate.]
+
+ Description [This procedure is useful for verification the supergate
+ library. The truth table derived by this procedure should be the same
+ as the one contained in the original supergate file.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_LibraryComputeTruth( Map_SuperLib_t * pLib, char * pFormula, unsigned uTruthRes[] )
+{
+ char Buffer[1000];
+ strcpy( Buffer, pFormula );
+ Map_LibraryComputeTruth_rec( pLib, Buffer, pLib->uTruths, uTruthRes );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Derives the functionality of the supergate.]
+
+ Description [This procedure is useful for verification the supergate
+ library. The truth table derived by this procedure should be the same
+ as the one contained in the original supergate file.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_LibraryComputeTruth_rec( Map_SuperLib_t * pLib, char * pFormula, unsigned uTruthsIn[][2], unsigned uTruthRes[] )
+{
+ Mio_Gate_t * pMioGate;
+ char * pGateName, * pStrings[6];
+ unsigned uTruthsFanins[6][2];
+ int nStrings, i;
+
+ // perform one step parsing of the formula
+ // detect the root gate name, the next-step strings, and their number
+ pGateName = Map_LibraryReadFormulaStep( pFormula, pStrings, &nStrings );
+ if ( nStrings == 0 ) // elementary variable
+ {
+ assert( pGateName[0] - 'a' < pLib->nVarsMax );
+ uTruthRes[0] = uTruthsIn[pGateName[0] - 'a'][0];
+ uTruthRes[1] = uTruthsIn[pGateName[0] - 'a'][1];
+ return;
+ }
+ // derive the functionality of the fanins
+ for ( i = 0; i < nStrings; i++ )
+ Map_LibraryComputeTruth_rec( pLib, pStrings[i], uTruthsIn, uTruthsFanins[i] );
+ // get the root supergate
+ pMioGate = Mio_LibraryReadGateByName( pLib->pGenlib, pGateName );
+ if ( pMioGate == NULL )
+ printf( "A supergate contains gate \"%s\" that is not in \"%s\".\n", pGateName, Mio_LibraryReadName(pLib->pGenlib) );
+ // derive the functionality of the output of the supergate
+ Mio_DeriveTruthTable( pMioGate, uTruthsFanins, nStrings, pLib->nVarsMax, uTruthRes );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_LibraryPrintSupergate( Map_Super_t * pGate )
+{
+ printf( "%5d : ", pGate->nUsed );
+ printf( "%5d ", pGate->Num );
+ printf( "A = %5.2f ", pGate->Area );
+ printf( "D = %5.2f ", pGate->tDelayMax );
+ printf( "%s", pGate->pFormula );
+ printf( "\n" );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Prints N-classes of supergates.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_LibraryPrintClasses( Map_SuperLib_t * p )
+{
+/*
+ st_generator * gen;
+ Map_Super_t * pSuper, * pSuper2;
+ unsigned Key, uTruth;
+ int Counter = 0;
+ // copy all the supergates into one array
+ st_foreach_item( p->tSuplib, gen, (char **)&Key, (char **)&pSuper )
+ {
+ for ( pSuper2 = pSuper; pSuper2; pSuper2 = pSuper2->pNext )
+ {
+ uTruth = pSuper2->Phase;
+ Extra_PrintBinary( stdout, &uTruth, 5 );
+ printf( " %5d ", pSuper2->Num );
+ printf( "%s", pSuper2->pFormula );
+ printf( "\n" );
+ }
+ printf( "\n" );
+ if ( ++ Counter == 100 )
+ break;
+ }
+*/
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/mapper/mapperTable.c b/src/map/mapper/mapperTable.c
new file mode 100644
index 00000000..747fe1c8
--- /dev/null
+++ b/src/map/mapper/mapperTable.c
@@ -0,0 +1,402 @@
+/**CFile****************************************************************
+
+ FileName [mapperTable.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Generic technology mapping engine.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - June 1, 2004.]
+
+ Revision [$Id: mapperTable.c,v 1.6 2005/01/23 06:59:44 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mapperInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// the table function for the tables
+#define MAP_TABLE_HASH(u1,u2,nSize) (((u1) + 2003 * (u2)) % nSize)
+
+static void Map_SuperTableResize( Map_HashTable_t * pLib );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Creates the hash table for supergates.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_HashTable_t * Map_SuperTableCreate( Map_SuperLib_t * pLib )
+{
+ Map_HashTable_t * p;
+ // allocate the table
+ p = ALLOC( Map_HashTable_t, 1 );
+ memset( p, 0, sizeof(Map_HashTable_t) );
+ p->mmMan = pLib->mmEntries;
+ // allocate and clean the bins
+ p->nBins = Cudd_Prime(20000);
+ p->pBins = ALLOC( Map_HashEntry_t *, p->nBins );
+ memset( p->pBins, 0, sizeof(Map_HashEntry_t *) * p->nBins );
+ return p;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Deallocates the supergate hash table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_SuperTableFree( Map_HashTable_t * p )
+{
+ FREE( p->pBins );
+ FREE( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Inserts a new entry into the hash table.]
+
+ Description [This function inserts the new gate (pGate), which will be
+ accessible through its canonical form (uTruthC).]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_SuperTableInsertC( Map_HashTable_t * p, unsigned uTruthC[], Map_Super_t * pGate )
+{
+ Map_HashEntry_t * pEnt;
+ unsigned Key;
+ // resize the table
+ if ( p->nEntries >= 2 * p->nBins )
+ Map_SuperTableResize( p );
+ // check if another supergate with the same canonical form exists
+ Key = MAP_TABLE_HASH( uTruthC[0], uTruthC[1], p->nBins );
+ for ( pEnt = p->pBins[Key]; pEnt; pEnt = pEnt->pNext )
+ if ( pEnt->uTruth[0] == uTruthC[0] && pEnt->uTruth[1] == uTruthC[1] )
+ break;
+ // create a new entry if it does not exist
+ if ( pEnt == NULL )
+ {
+ // add the new entry to the table
+ pEnt = (Map_HashEntry_t *)Extra_MmFixedEntryFetch( p->mmMan );
+ memset( pEnt, 0, sizeof(Map_HashEntry_t) );
+ pEnt->uTruth[0] = uTruthC[0];
+ pEnt->uTruth[1] = uTruthC[1];
+ // add the hash table entry to the corresponding linked list in the table
+ pEnt->pNext = p->pBins[Key];
+ p->pBins[Key] = pEnt;
+ p->nEntries++;
+ }
+ // add the supergate to the entry
+ pGate->pNext = pEnt->pGates;
+ pEnt->pGates = pGate;
+ return 0;
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Inserts a new entry into the library.]
+
+ Description [This function inserts the new gate (pGate), which will be
+ accessible through its unfolded function (uTruth).]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_SuperTableInsert( Map_HashTable_t * p, unsigned uTruth[], Map_Super_t * pGate, unsigned uPhase )
+{
+ Map_HashEntry_t * pEnt;
+ unsigned Key;
+ // resize the table
+ if ( p->nEntries >= 2 * p->nBins )
+ Map_SuperTableResize( p );
+ // check if this entry already exists
+ Key = MAP_TABLE_HASH( uTruth[0], uTruth[1], p->nBins );
+ for ( pEnt = p->pBins[Key]; pEnt; pEnt = pEnt->pNext )
+ if ( pEnt->uTruth[0] == uTruth[0] && pEnt->uTruth[1] == uTruth[1] )
+ return 1;
+ // add the new hash table entry to the table
+ pEnt = (Map_HashEntry_t *)Extra_MmFixedEntryFetch( p->mmMan );
+ memset( pEnt, 0, sizeof(Map_HashEntry_t) );
+ pEnt->uTruth[0] = uTruth[0];
+ pEnt->uTruth[1] = uTruth[1];
+ pEnt->pGates = pGate;
+ pEnt->uPhase = uPhase;
+ // add the hash table to the corresponding linked list in the table
+ pEnt->pNext = p->pBins[Key];
+ p->pBins[Key] = pEnt;
+ p->nEntries++;
+/*
+printf( "Adding gate: %10u ", Key );
+Map_LibraryPrintSupergate( pGate );
+Extra_PrintBinary( stdout, uTruth, 32 );
+printf( "\n" );
+*/
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Looks up an entry in the library.]
+
+ Description [This function looks up the function, given by its truth table,
+ and return two things: (1) the linked list of supergates, which can implement
+ the functions of this N-class; (2) the phase, which should be applied to the
+ given function, in order to derive the canonical form of this N-class.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Super_t * Map_SuperTableLookupC( Map_SuperLib_t * p, unsigned uTruth[] )
+{
+ Map_HashEntry_t * pEnt;
+ unsigned Key;
+ Key = MAP_TABLE_HASH( uTruth[0], uTruth[1], p->tTableC->nBins );
+ for ( pEnt = p->tTableC->pBins[Key]; pEnt; pEnt = pEnt->pNext )
+ if ( pEnt->uTruth[0] == uTruth[0] && pEnt->uTruth[1] == uTruth[1] )
+ return pEnt->pGates;
+ return NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Looks up an entry in the library.]
+
+ Description [This function looks up the function, given by its truth table,
+ and return two things: (1) the linked list of supergates, which can implement
+ the functions of this N-class; (2) the phase, which should be applied to the
+ given function, in order to derive the canonical form of this N-class.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Super_t * Map_SuperTableLookup( Map_HashTable_t * p, unsigned uTruth[], unsigned * puPhase )
+{
+ Map_HashEntry_t * pEnt;
+ unsigned Key;
+ Key = MAP_TABLE_HASH( uTruth[0], uTruth[1], p->nBins );
+ for ( pEnt = p->pBins[Key]; pEnt; pEnt = pEnt->pNext )
+ if ( pEnt->uTruth[0] == uTruth[0] && pEnt->uTruth[1] == uTruth[1] )
+ {
+ *puPhase = pEnt->uPhase;
+ return pEnt->pGates;
+ }
+ return NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Resizes the table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_SuperTableResize( Map_HashTable_t * p )
+{
+ Map_HashEntry_t ** pBinsNew;
+ Map_HashEntry_t * pEnt, * pEnt2;
+ int nBinsNew, Counter, i, clk = clock();
+ unsigned Key;
+ // get the new table size
+ nBinsNew = Cudd_Prime(2 * p->nBins);
+ // allocate a new array
+ pBinsNew = ALLOC( Map_HashEntry_t *, nBinsNew );
+ memset( pBinsNew, 0, sizeof(Map_HashEntry_t *) * nBinsNew );
+ // rehash the entries from the old table
+ Counter = 0;
+ for ( i = 0; i < p->nBins; i++ )
+ for ( pEnt = p->pBins[i], pEnt2 = pEnt? pEnt->pNext: NULL; pEnt;
+ pEnt = pEnt2, pEnt2 = pEnt? pEnt->pNext: NULL )
+ {
+ Key = MAP_TABLE_HASH( pEnt->uTruth[0], pEnt->uTruth[1], nBinsNew );
+ pEnt->pNext = pBinsNew[Key];
+ pBinsNew[Key] = pEnt;
+ Counter++;
+ }
+ assert( Counter == p->nEntries );
+ // replace the table and the parameters
+ free( p->pBins );
+ p->pBins = pBinsNew;
+ p->nBins = nBinsNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares the supergates by the number of times they are used.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_SuperTableCompareSupergates( Map_Super_t ** ppS1, Map_Super_t ** ppS2 )
+{
+ if ( (*ppS1)->nUsed > (*ppS2)->nUsed )
+ return -1;
+ if ( (*ppS1)->nUsed < (*ppS2)->nUsed )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares the supergates by the number of times they are used.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_SuperTableCompareGatesInList( Map_Super_t ** ppS1, Map_Super_t ** ppS2 )
+{
+// if ( (*ppS1)->tDelayMax.Rise > (*ppS2)->tDelayMax.Rise )
+ if ( (*ppS1)->Area > (*ppS2)->Area )
+ return -1;
+// if ( (*ppS1)->tDelayMax.Rise < (*ppS2)->tDelayMax.Rise )
+ if ( (*ppS1)->Area < (*ppS2)->Area )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sorts supergates by usefulness and prints out most useful.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_SuperTableSortSupergates( Map_HashTable_t * p, int nSupersMax )
+{
+ Map_HashEntry_t * pEnt;
+ Map_Super_t ** ppSupers;
+ Map_Super_t * pSuper;
+ int nSupers, i;
+
+ // copy all the supergates into one array
+ ppSupers = ALLOC( Map_Super_t *, nSupersMax );
+ nSupers = 0;
+ for ( i = 0; i < p->nBins; i++ )
+ for ( pEnt = p->pBins[i]; pEnt; pEnt = pEnt->pNext )
+ for ( pSuper = pEnt->pGates; pSuper; pSuper = pSuper->pNext )
+ ppSupers[nSupers++] = pSuper;
+
+ // sort by usage
+ qsort( (void *)ppSupers, nSupers, sizeof(int),
+ (int (*)(const void *, const void *)) Map_SuperTableCompareSupergates );
+ assert( Map_SuperTableCompareSupergates( ppSupers, ppSupers + nSupers - 1 ) <= 0 );
+
+ // print out the "top ten"
+// for ( i = 0; i < nSupers; i++ )
+ for ( i = 0; i < 10; i++ )
+ {
+ if ( ppSupers[i]->nUsed == 0 )
+ break;
+ printf( "%5d : ", ppSupers[i]->nUsed );
+ printf( "%5d ", ppSupers[i]->Num );
+ printf( "A = %5.2f ", ppSupers[i]->Area );
+ printf( "D = %5.2f ", ppSupers[i]->tDelayMax.Rise );
+ printf( "%s", ppSupers[i]->pFormula );
+ printf( "\n" );
+ }
+ free( ppSupers );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sorts supergates by max delay for each truth table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_SuperTableSortSupergatesByDelay( Map_HashTable_t * p, int nSupersMax )
+{
+ Map_HashEntry_t * pEnt;
+ Map_Super_t ** ppSupers;
+ Map_Super_t * pSuper;
+ int nSupers, i, k;
+
+ ppSupers = ALLOC( Map_Super_t *, nSupersMax );
+ for ( i = 0; i < p->nBins; i++ )
+ for ( pEnt = p->pBins[i]; pEnt; pEnt = pEnt->pNext )
+ {
+ // collect the gates in this entry
+ nSupers = 0;
+ for ( pSuper = pEnt->pGates; pSuper; pSuper = pSuper->pNext )
+ {
+ // skip supergates, whose root is the AND gate
+// if ( strcmp( Mio_GateReadName(pSuper->pRoot), "and" ) == 0 )
+// continue;
+ ppSupers[nSupers++] = pSuper;
+ }
+ pEnt->pGates = NULL;
+ if ( nSupers == 0 )
+ continue;
+ // sort the gates by delay
+ qsort( (void *)ppSupers, nSupers, sizeof(int),
+ (int (*)(const void *, const void *)) Map_SuperTableCompareGatesInList );
+ assert( Map_SuperTableCompareGatesInList( ppSupers, ppSupers + nSupers - 1 ) <= 0 );
+ // link them in the reverse order
+ for ( k = 0; k < nSupers; k++ )
+ {
+ ppSupers[k]->pNext = pEnt->pGates;
+ pEnt->pGates = ppSupers[k];
+ }
+ // save the number of supergates in the list
+ pEnt->pGates->nSupers = nSupers;
+ }
+ FREE( ppSupers );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/mapper/mapperTime.c b/src/map/mapper/mapperTime.c
new file mode 100644
index 00000000..0ff88b0e
--- /dev/null
+++ b/src/map/mapper/mapperTime.c
@@ -0,0 +1,508 @@
+/**CFile****************************************************************
+
+ FileName [mapperTime.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Generic technology mapping engine.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - June 1, 2004.]
+
+ Revision [$Id: mapperTime.c,v 1.3 2005/03/02 02:35:54 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mapperInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Map_TimePropagateRequired( Map_Man_t * p, Map_NodeVec_t * vNodes );
+static void Map_TimePropagateRequiredPhase( Map_Man_t * p, Map_Node_t * pNode, int fPhase );
+static float Map_MatchComputeReqTimes( Map_Cut_t * pCut, int fPhase, Map_Time_t * ptArrRes );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**function*************************************************************
+
+ synopsis [Computes the exact area associated with the cut.]
+
+ description []
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+float Map_TimeMatchWithInverter( Map_Man_t * p, Map_Match_t * pMatch )
+{
+ Map_Time_t tArrInv;
+ tArrInv.Fall = pMatch->tArrive.Rise + p->pSuperLib->tDelayInv.Fall;
+ tArrInv.Rise = pMatch->tArrive.Fall + p->pSuperLib->tDelayInv.Rise;
+ tArrInv.Worst = MAP_MAX( tArrInv.Rise, tArrInv.Fall );
+ return tArrInv.Worst;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the arrival times of the cut recursively.]
+
+ Description [When computing the arrival time for the previously unused
+ cuts, their arrival time may be incorrect because their fanins have
+ incorrect arrival time. This procedure is called to fix this problem.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_TimeCutComputeArrival_rec( Map_Cut_t * pCut, int fPhase )
+{
+ int i, fPhaseLeaf;
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ {
+ fPhaseLeaf = Map_CutGetLeafPhase( pCut, fPhase, i );
+ if ( pCut->ppLeaves[i]->nRefAct[fPhaseLeaf] > 0 )
+ continue;
+ Map_TimeCutComputeArrival_rec( pCut->ppLeaves[i]->pCutBest[fPhaseLeaf], fPhaseLeaf );
+ }
+ Map_TimeCutComputeArrival( NULL, pCut, fPhase, MAP_FLOAT_LARGE );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the arrival times of the cut.]
+
+ Description [Computes the arrival times of the cut if it is implemented using
+ the given supergate with the given phase. Uses the constraint-type specification
+ of rise/fall arrival times.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Map_TimeCutComputeArrival( Map_Node_t * pNode, Map_Cut_t * pCut, int fPhase, float tWorstLimit )
+{
+ Map_Match_t * pM = pCut->M + fPhase;
+ Map_Super_t * pSuper = pM->pSuperBest;
+ unsigned uPhaseTot = pM->uPhaseBest;
+ Map_Time_t * ptArrRes = &pM->tArrive;
+ Map_Time_t * ptArrIn;
+ bool fPinPhase;
+ float tDelay;
+ int i;
+
+ ptArrRes->Rise = ptArrRes->Fall = 0.0;
+ ptArrRes->Worst = MAP_FLOAT_LARGE;
+ for ( i = pCut->nLeaves - 1; i >= 0; i-- )
+ {
+ // get the phase of the given pin
+ fPinPhase = ((uPhaseTot & (1 << i)) == 0);
+ ptArrIn = pCut->ppLeaves[i]->tArrival + fPinPhase;
+
+ // get the rise of the output due to rise of the inputs
+ if ( pSuper->tDelaysR[i].Rise > 0 )
+ {
+ tDelay = ptArrIn->Rise + pSuper->tDelaysR[i].Rise;
+ if ( tDelay > tWorstLimit )
+ return MAP_FLOAT_LARGE;
+ if ( ptArrRes->Rise < tDelay )
+ ptArrRes->Rise = tDelay;
+ }
+
+ // get the rise of the output due to fall of the inputs
+ if ( pSuper->tDelaysR[i].Fall > 0 )
+ {
+ tDelay = ptArrIn->Fall + pSuper->tDelaysR[i].Fall;
+ if ( tDelay > tWorstLimit )
+ return MAP_FLOAT_LARGE;
+ if ( ptArrRes->Rise < tDelay )
+ ptArrRes->Rise = tDelay;
+ }
+
+ // get the fall of the output due to rise of the inputs
+ if ( pSuper->tDelaysF[i].Rise > 0 )
+ {
+ tDelay = ptArrIn->Rise + pSuper->tDelaysF[i].Rise;
+ if ( tDelay > tWorstLimit )
+ return MAP_FLOAT_LARGE;
+ if ( ptArrRes->Fall < tDelay )
+ ptArrRes->Fall = tDelay;
+ }
+
+ // get the fall of the output due to fall of the inputs
+ if ( pSuper->tDelaysF[i].Fall > 0 )
+ {
+ tDelay = ptArrIn->Fall + pSuper->tDelaysF[i].Fall;
+ if ( tDelay > tWorstLimit )
+ return MAP_FLOAT_LARGE;
+ if ( ptArrRes->Fall < tDelay )
+ ptArrRes->Fall = tDelay;
+ }
+ }
+ // return the worst-case of rise/fall arrival times
+ ptArrRes->Worst = MAP_MAX(ptArrRes->Rise, ptArrRes->Fall);
+ return ptArrRes->Worst;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Computes the maximum arrival times.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Map_TimeComputeArrivalMax( Map_Man_t * p )
+{
+ float tReqMax, tReq;
+ int i, fPhase;
+ // get the critical PO arrival time
+ tReqMax = -MAP_FLOAT_LARGE;
+ for ( i = 0; i < p->nOutputs; i++ )
+ {
+ if ( Map_NodeIsConst(p->pOutputs[i]) )
+ continue;
+ fPhase = !Map_IsComplement(p->pOutputs[i]);
+ tReq = Map_Regular(p->pOutputs[i])->tArrival[fPhase].Worst;
+ tReqMax = MAP_MAX( tReqMax, tReq );
+ }
+ return tReqMax;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the required times of all nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_TimeComputeRequiredGlobal( Map_Man_t * p )
+{
+ p->fRequiredGlo = Map_TimeComputeArrivalMax( p );
+ // update the required times according to the target
+ if ( p->DelayTarget != -1 )
+ {
+ if ( p->fRequiredGlo > p->DelayTarget + p->fEpsilon )
+ {
+ if ( p->fMappingMode == 1 )
+ printf( "Cannot meet the target required times (%4.2f). Continue anyway.\n", p->DelayTarget );
+ }
+ else if ( p->fRequiredGlo < p->DelayTarget - p->fEpsilon )
+ {
+ if ( p->fMappingMode == 1 )
+ printf( "Relaxing the required times from (%4.2f) to the target (%4.2f).\n", p->fRequiredGlo, p->DelayTarget );
+ p->fRequiredGlo = p->DelayTarget;
+ }
+ }
+ Map_TimeComputeRequired( p, p->fRequiredGlo );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the required times of all nodes.]
+
+ Description [This procedure assumes that the nodes used in the mapping
+ are collected in p->vMapping.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_TimeComputeRequired( Map_Man_t * p, float fRequired )
+{
+ Map_Time_t * ptTime;
+ int fPhase, i;
+
+ // clean the required times
+ for ( i = 0; i < p->vAnds->nSize; i++ )
+ {
+ p->vAnds->pArray[i]->tRequired[0].Rise = MAP_FLOAT_LARGE;
+ p->vAnds->pArray[i]->tRequired[0].Fall = MAP_FLOAT_LARGE;
+ p->vAnds->pArray[i]->tRequired[0].Worst = MAP_FLOAT_LARGE;
+ p->vAnds->pArray[i]->tRequired[1].Rise = MAP_FLOAT_LARGE;
+ p->vAnds->pArray[i]->tRequired[1].Fall = MAP_FLOAT_LARGE;
+ p->vAnds->pArray[i]->tRequired[1].Worst = MAP_FLOAT_LARGE;
+ }
+
+ // set the required times for the POs
+ for ( i = 0; i < p->nOutputs; i++ )
+ {
+ fPhase = !Map_IsComplement(p->pOutputs[i]);
+ ptTime = Map_Regular(p->pOutputs[i])->tRequired + fPhase;
+ ptTime->Rise = ptTime->Fall = ptTime->Worst = fRequired;
+ }
+
+ // sorts the nodes in the decreasing order of levels
+ // this puts the nodes in reverse topological order
+ Map_MappingSortByLevel( p, p->vMapping );
+ Map_TimePropagateRequired( p, p->vMapping );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the required times of the given nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_TimePropagateRequired( Map_Man_t * p, Map_NodeVec_t * vNodes )
+{
+ Map_Node_t * pNode;
+ Map_Time_t tReqOutTest, * ptReqOutTest = &tReqOutTest;
+ Map_Time_t * ptReqIn, * ptReqOut;
+ int fPhase, k;
+
+ // go through the nodes in the reverse topological order
+ for ( k = 0; k < vNodes->nSize; k++ )
+ {
+ pNode = vNodes->pArray[k];
+
+ // this computation works for regular nodes only
+ assert( !Map_IsComplement(pNode) );
+ // at least one phase should be mapped
+ assert( pNode->pCutBest[0] != NULL || pNode->pCutBest[1] != NULL );
+ // the node should be used in the currently assigned mapping
+ assert( pNode->nRefAct[0] > 0 || pNode->nRefAct[1] > 0 );
+
+ // if one of the cuts is not given, project the required times from the other cut
+ if ( pNode->pCutBest[0] == NULL || pNode->pCutBest[1] == NULL )
+ {
+// assert( 0 );
+ // get the missing phase
+ fPhase = (pNode->pCutBest[1] == NULL);
+ // check if the missing phase is needed in the mapping
+ if ( pNode->nRefAct[fPhase] > 0 )
+ {
+ // get the pointers to the required times of the missing phase
+ ptReqOut = pNode->tRequired + fPhase;
+// assert( ptReqOut->Fall < MAP_FLOAT_LARGE );
+ // get the pointers to the required times of the present phase
+ ptReqIn = pNode->tRequired + !fPhase;
+ // propagate the required times from the missing phase to the present phase
+ // tArrInv.Fall = pMatch->tArrive.Rise + p->pSuperLib->tDelayInv.Fall;
+ // tArrInv.Rise = pMatch->tArrive.Fall + p->pSuperLib->tDelayInv.Rise;
+ ptReqIn->Fall = MAP_MIN( ptReqIn->Fall, ptReqOut->Rise - p->pSuperLib->tDelayInv.Rise );
+ ptReqIn->Rise = MAP_MIN( ptReqIn->Rise, ptReqOut->Fall - p->pSuperLib->tDelayInv.Fall );
+ }
+ }
+
+ // finalize the worst case computation
+ pNode->tRequired[0].Worst = MAP_MIN( pNode->tRequired[0].Fall, pNode->tRequired[0].Rise );
+ pNode->tRequired[1].Worst = MAP_MIN( pNode->tRequired[1].Fall, pNode->tRequired[1].Rise );
+
+ // skip the PIs
+ if ( !Map_NodeIsAnd(pNode) )
+ continue;
+
+ // propagate required times of different phases of the node
+ // the ordering of phases does not matter since they are mapped independently
+ if ( pNode->pCutBest[0] && pNode->tRequired[0].Worst < MAP_FLOAT_LARGE )
+ Map_TimePropagateRequiredPhase( p, pNode, 0 );
+ if ( pNode->pCutBest[1] && pNode->tRequired[1].Worst < MAP_FLOAT_LARGE )
+ Map_TimePropagateRequiredPhase( p, pNode, 1 );
+ }
+
+ // in the end, we verify the required times
+ // for this, we compute the arrival times of the outputs of each phase
+ // of the supergates using the fanins' required times as the fanins' arrival times
+ // the resulting arrival time of the supergate should be less than the actual required time
+ for ( k = 0; k < vNodes->nSize; k++ )
+ {
+ pNode = vNodes->pArray[k];
+ if ( !Map_NodeIsAnd(pNode) )
+ continue;
+ // verify that the required times are propagated correctly
+// if ( pNode->pCutBest[0] && (pNode->nRefAct[0] > 0 || pNode->pCutBest[1] == NULL) )
+ if ( pNode->pCutBest[0] && pNode->tRequired[0].Worst < MAP_FLOAT_LARGE )
+ {
+ Map_MatchComputeReqTimes( pNode->pCutBest[0], 0, ptReqOutTest );
+ assert( ptReqOutTest->Rise < pNode->tRequired[0].Rise + p->fEpsilon );
+ assert( ptReqOutTest->Fall < pNode->tRequired[0].Fall + p->fEpsilon );
+ }
+// if ( pNode->pCutBest[1] && (pNode->nRefAct[1] > 0 || pNode->pCutBest[0] == NULL) )
+ if ( pNode->pCutBest[1] && pNode->tRequired[1].Worst < MAP_FLOAT_LARGE )
+ {
+ Map_MatchComputeReqTimes( pNode->pCutBest[1], 1, ptReqOutTest );
+ assert( ptReqOutTest->Rise < pNode->tRequired[1].Rise + p->fEpsilon );
+ assert( ptReqOutTest->Fall < pNode->tRequired[1].Fall + p->fEpsilon );
+ }
+ }
+
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the required times of the given nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_TimePropagateRequiredPhase( Map_Man_t * p, Map_Node_t * pNode, int fPhase )
+{
+ Map_Time_t * ptReqIn, * ptReqOut;
+ Map_Cut_t * pCut;
+ Map_Super_t * pSuper;
+ float tNewReqTime;
+ unsigned uPhase;
+ int fPinPhase, i;
+
+ // get the cut to be propagated
+ pCut = pNode->pCutBest[fPhase];
+ assert( pCut != NULL );
+ // get the supergate and its polarity
+ pSuper = pCut->M[fPhase].pSuperBest;
+ uPhase = pCut->M[fPhase].uPhaseBest;
+ // get the required time of the output of the supergate
+ ptReqOut = pNode->tRequired + fPhase;
+ // set the required time of the children
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ {
+ // get the phase of the given pin of the supergate
+ fPinPhase = ((uPhase & (1 << i)) == 0);
+ ptReqIn = pCut->ppLeaves[i]->tRequired + fPinPhase;
+ assert( pCut->ppLeaves[i]->nRefAct[2] > 0 );
+
+ // get the rise of the output due to rise of the inputs
+// if ( ptArrOut->Rise < ptArrIn->Rise + pSuper->tDelaysR[i].Rise )
+// ptArrOut->Rise = ptArrIn->Rise + pSuper->tDelaysR[i].Rise;
+ if ( pSuper->tDelaysR[i].Rise > 0 )
+ {
+ tNewReqTime = ptReqOut->Rise - pSuper->tDelaysR[i].Rise;
+ ptReqIn->Rise = MAP_MIN( ptReqIn->Rise, tNewReqTime );
+ }
+
+ // get the rise of the output due to fall of the inputs
+// if ( ptArrOut->Rise < ptArrIn->Fall + pSuper->tDelaysR[i].Fall )
+// ptArrOut->Rise = ptArrIn->Fall + pSuper->tDelaysR[i].Fall;
+ if ( pSuper->tDelaysR[i].Fall > 0 )
+ {
+ tNewReqTime = ptReqOut->Rise - pSuper->tDelaysR[i].Fall;
+ ptReqIn->Fall = MAP_MIN( ptReqIn->Fall, tNewReqTime );
+ }
+
+ // get the fall of the output due to rise of the inputs
+// if ( ptArrOut->Fall < ptArrIn->Rise + pSuper->tDelaysF[i].Rise )
+// ptArrOut->Fall = ptArrIn->Rise + pSuper->tDelaysF[i].Rise;
+ if ( pSuper->tDelaysF[i].Rise > 0 )
+ {
+ tNewReqTime = ptReqOut->Fall - pSuper->tDelaysF[i].Rise;
+ ptReqIn->Rise = MAP_MIN( ptReqIn->Rise, tNewReqTime );
+ }
+
+ // get the fall of the output due to fall of the inputs
+// if ( ptArrOut->Fall < ptArrIn->Fall + pSuper->tDelaysF[i].Fall )
+// ptArrOut->Fall = ptArrIn->Fall + pSuper->tDelaysF[i].Fall;
+ if ( pSuper->tDelaysF[i].Fall > 0 )
+ {
+ tNewReqTime = ptReqOut->Fall - pSuper->tDelaysF[i].Fall;
+ ptReqIn->Fall = MAP_MIN( ptReqIn->Fall, tNewReqTime );
+ }
+ }
+
+ // compare the required times with the arrival times
+ assert( pNode->tArrival[fPhase].Rise < ptReqOut->Rise + p->fEpsilon );
+ assert( pNode->tArrival[fPhase].Fall < ptReqOut->Fall + p->fEpsilon );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the arrival times of the cut.]
+
+ Description [Computes the arrival times of the cut if it is implemented using
+ the given supergate with the given phase. Uses the constraint-type specification
+ of rise/fall arrival times.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Map_MatchComputeReqTimes( Map_Cut_t * pCut, int fPhase, Map_Time_t * ptArrRes )
+{
+ Map_Time_t * ptArrIn;
+ Map_Super_t * pSuper;
+ unsigned uPhaseTot;
+ int fPinPhase, i;
+ float tDelay;
+
+ // get the supergate and the phase
+ pSuper = pCut->M[fPhase].pSuperBest;
+ uPhaseTot = pCut->M[fPhase].uPhaseBest;
+
+ // propagate the arrival times
+ ptArrRes->Rise = ptArrRes->Fall = -MAP_FLOAT_LARGE;
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ {
+ // get the phase of the given pin
+ fPinPhase = ((uPhaseTot & (1 << i)) == 0);
+ ptArrIn = pCut->ppLeaves[i]->tRequired + fPinPhase;
+// assert( ptArrIn->Worst < MAP_FLOAT_LARGE );
+
+ // get the rise of the output due to rise of the inputs
+ if ( pSuper->tDelaysR[i].Rise > 0 )
+ {
+ tDelay = ptArrIn->Rise + pSuper->tDelaysR[i].Rise;
+ if ( ptArrRes->Rise < tDelay )
+ ptArrRes->Rise = tDelay;
+ }
+
+ // get the rise of the output due to fall of the inputs
+ if ( pSuper->tDelaysR[i].Fall > 0 )
+ {
+ tDelay = ptArrIn->Fall + pSuper->tDelaysR[i].Fall;
+ if ( ptArrRes->Rise < tDelay )
+ ptArrRes->Rise = tDelay;
+ }
+
+ // get the fall of the output due to rise of the inputs
+ if ( pSuper->tDelaysF[i].Rise > 0 )
+ {
+ tDelay = ptArrIn->Rise + pSuper->tDelaysF[i].Rise;
+ if ( ptArrRes->Fall < tDelay )
+ ptArrRes->Fall = tDelay;
+ }
+
+ // get the fall of the output due to fall of the inputs
+ if ( pSuper->tDelaysF[i].Fall > 0 )
+ {
+ tDelay = ptArrIn->Fall + pSuper->tDelaysF[i].Fall;
+ if ( ptArrRes->Fall < tDelay )
+ ptArrRes->Fall = tDelay;
+ }
+ }
+ // return the worst-case of rise/fall arrival times
+ return MAP_MAX(ptArrRes->Rise, ptArrRes->Fall);
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/mapper/mapperTree.c b/src/map/mapper/mapperTree.c
new file mode 100644
index 00000000..61e12748
--- /dev/null
+++ b/src/map/mapper/mapperTree.c
@@ -0,0 +1,804 @@
+/**CFile****************************************************************
+
+ FileName [mapperTree.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Generic technology mapping engine.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - June 1, 2004.]
+
+ Revision [$Id: mapperTree.c,v 1.9 2005/01/23 06:59:45 alanmi Exp $]
+
+***********************************************************************/
+
+#ifdef __linux__
+#include <libgen.h>
+#endif
+
+#include "mapperInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Map_LibraryReadFileTree( Map_SuperLib_t * pLib, FILE * pFile, char *pFileName );
+static Map_Super_t * Map_LibraryReadGateTree( Map_SuperLib_t * pLib, char * pBuffer, int Number, int nVars );
+static int Map_LibraryDeriveGateInfo( Map_SuperLib_t * pLib, st_table * tExcludeGate );
+static void Map_LibraryAddFaninDelays( Map_SuperLib_t * pLib, Map_Super_t * pGate, Map_Super_t * pFanin, Mio_Pin_t * pPin );
+static int Map_LibraryGetMaxSuperPi_rec( Map_Super_t * pGate );
+static unsigned Map_LibraryGetGateSupp_rec( Map_Super_t * pGate );
+
+// fanout limits
+extern const int s_MapFanoutLimits[10] = { 1/*0*/, 10/*1*/, 5/*2*/, 2/*3*/, 1/*4*/, 1/*5*/, 1/*6*/ };
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Reads the supergate library from file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_LibraryReadTree( Map_SuperLib_t * pLib, char * pFileName, char * pExcludeFile )
+{
+ FILE * pFile;
+ int Status, num;
+ Abc_Frame_t * pAbc;
+ st_table * tExcludeGate = 0;
+
+ // read the beginning of the file
+ assert( pLib->pGenlib == NULL );
+// pFile = Io_FileOpen( pFileName, "open_path", "r" );
+ pFile = fopen( pFileName, "r" );
+ if ( pFile == NULL )
+ {
+ printf( "Cannot open input file \"%s\".\n", pFileName );
+ return 0;
+ }
+
+ if ( pExcludeFile )
+ {
+ pAbc = Abc_FrameGetGlobalFrame();
+
+ tExcludeGate = st_init_table(strcmp, st_strhash);
+ if ( (num = Mio_LibraryReadExclude( pAbc, pExcludeFile, tExcludeGate )) == -1 )
+ {
+ st_free_table( tExcludeGate );
+ tExcludeGate = 0;
+ return 0;
+ }
+
+ fprintf ( Abc_FrameReadOut( pAbc ), "Read %d gates from exclude file\n", num );
+ }
+
+ Status = Map_LibraryReadFileTree( pLib, pFile, pFileName );
+ fclose( pFile );
+ if ( Status == 0 )
+ return 0;
+ // prepare the info about the library
+ return Map_LibraryDeriveGateInfo( pLib, tExcludeGate );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Reads the library file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_LibraryReadFileTree( Map_SuperLib_t * pLib, FILE * pFile, char *pFileName )
+{
+ ProgressBar * pProgress;
+ char pBuffer[5000], pLibFile[5000];
+ FILE * pFileGen;
+ Map_Super_t * pGate;
+ char * pTemp = 0, * pLibName;
+ int nCounter, k, i;
+
+ // skip empty and comment lines
+ while ( fgets( pBuffer, 5000, pFile ) != NULL )
+ {
+ // skip leading spaces
+ for ( pTemp = pBuffer; *pTemp == ' ' || *pTemp == '\r' || *pTemp == '\n'; pTemp++ );
+ // skip comment lines and empty lines
+ if ( *pTemp != 0 && *pTemp != '#' )
+ break;
+ }
+
+ // get the genlib file name (base)
+ pLibName = strtok( pTemp, " \t\r\n" );
+
+ if ( strcmp( pLibName, "GATE" ) == 0 )
+ {
+ printf( "The input file \"%s\" looks like a GENLIB file and not a supergate library file.\n", pLib->pName );
+ return 0;
+ }
+
+
+ // now figure out the directory if any in the pFileName
+#ifdef __linux__
+ snprintf( pLibFile, 5000, "%s/%s", dirname(strdup(pFileName)), pLibName );
+#else
+ {
+ char * pStr;
+ strcpy( pLibFile, pFileName );
+ pStr = pLibFile + strlen(pBuffer) - 1;
+ while ( pStr > pLibFile && *pStr != '\\' && *pStr != '/' )
+ pStr--;
+ if ( pStr == pLibFile )
+ strcpy( pLibFile, pLibName );
+ else
+ sprintf( pStr, "/%s", pLibName );
+ }
+#endif
+
+// pFileGen = Io_FileOpen( pLibFile, "open_path", "r" );
+ pFileGen = fopen( pLibFile, "r" );
+ if ( pFileGen == NULL )
+ {
+ printf( "Cannot open the GENLIB file \"%s\".\n", pLibFile );
+ return 0;
+ }
+ fclose( pFileGen );
+
+ // read the genlib library
+ pLib->pGenlib = Mio_LibraryRead( Abc_FrameGetGlobalFrame(), pLibFile, 0, 0 );
+ if ( pLib->pGenlib == NULL )
+ {
+ printf( "Cannot read GENLIB file \"%s\".\n", pLibFile );
+ return 0;
+ }
+
+ // read the number of variables
+ fscanf( pFile, "%d\n", &pLib->nVarsMax );
+ if ( pLib->nVarsMax < 2 || pLib->nVarsMax > 10 )
+ {
+ printf( "Suspicious number of variables (%d).\n", pLib->nVarsMax );
+ return 0;
+ }
+
+ // read the number of gates
+ fscanf( pFile, "%d\n", &pLib->nSupersReal );
+ if ( pLib->nSupersReal < 1 || pLib->nSupersReal > 10000000 )
+ {
+ printf( "Suspicious number of gates (%d).\n", pLib->nSupersReal );
+ return 0;
+ }
+
+ // read the number of lines
+ fscanf( pFile, "%d\n", &pLib->nLines );
+ if ( pLib->nLines < 1 || pLib->nLines > 10000000 )
+ {
+ printf( "Suspicious number of lines (%d).\n", pLib->nLines );
+ return 0;
+ }
+
+ // allocate room for supergate pointers
+ pLib->ppSupers = ALLOC( Map_Super_t *, pLib->nLines + 10000 );
+
+ // create the elementary supergates
+ for ( i = 0; i < pLib->nVarsMax; i++ )
+ {
+ // get a new gate
+ pGate = (Map_Super_t *)Extra_MmFixedEntryFetch( pLib->mmSupers );
+ memset( pGate, 0, sizeof(Map_Super_t) );
+ // assign the elementary variable, the truth table, and the delays
+ pGate->Num = i;
+ // set the truth table
+ pGate->uTruth[0] = pLib->uTruths[i][0];
+ pGate->uTruth[1] = pLib->uTruths[i][1];
+ // set the arrival times of all input to non-existent delay
+ for ( k = 0; k < pLib->nVarsMax; k++ )
+ {
+ pGate->tDelaysR[k].Rise = pGate->tDelaysR[k].Fall = MAP_NO_VAR;
+ pGate->tDelaysF[k].Rise = pGate->tDelaysF[k].Fall = MAP_NO_VAR;
+ }
+ // set an existent arrival time for rise and fall
+ pGate->tDelaysR[i].Rise = 0.0;
+ pGate->tDelaysF[i].Fall = 0.0;
+ // set the gate
+ pLib->ppSupers[i] = pGate;
+ }
+
+ // read the lines
+ nCounter = pLib->nVarsMax;
+ pProgress = Extra_ProgressBarStart( stdout, pLib->nLines );
+ while ( fgets( pBuffer, 5000, pFile ) != NULL )
+ {
+ for ( pTemp = pBuffer; *pTemp == ' ' || *pTemp == '\r' || *pTemp == '\n'; pTemp++ );
+ if ( pTemp[0] == '\0' )
+ continue;
+// if ( pTemp[0] == 'a' || pTemp[2] == 'a' )
+// {
+// pLib->nLines--;
+// continue;
+// }
+
+ // get the gate
+ pGate = Map_LibraryReadGateTree( pLib, pTemp, nCounter, pLib->nVarsMax );
+ if ( pGate == NULL )
+ {
+ Extra_ProgressBarStop( pProgress );
+ return 0;
+ }
+ pLib->ppSupers[nCounter++] = pGate;
+ // later we will derive: truth table, delays, area, number of component gates, etc
+
+ // update the progress bar
+ Extra_ProgressBarUpdate( pProgress, nCounter, NULL );
+ }
+ Extra_ProgressBarStop( pProgress );
+ if ( nCounter != pLib->nLines )
+ printf( "The number of lines read (%d) is different what the file says (%d).\n", nCounter, pLib->nLines );
+ pLib->nSupersAll = nCounter;
+ // count the number of real supergates
+ nCounter = 0;
+ for ( k = 0; k < pLib->nLines; k++ )
+ nCounter += pLib->ppSupers[k]->fSuper;
+ if ( nCounter != pLib->nSupersReal )
+ printf( "The number of gates read (%d) is different what the file says (%d).\n", nCounter, pLib->nSupersReal );
+ pLib->nSupersReal = nCounter;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads one gate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Super_t * Map_LibraryReadGateTree( Map_SuperLib_t * pLib, char * pBuffer, int Number, int nVarsMax )
+{
+ Map_Super_t * pGate;
+ char * pTemp;
+ int i, Num;
+
+ // start and clean the gate
+ pGate = (Map_Super_t *)Extra_MmFixedEntryFetch( pLib->mmSupers );
+ memset( pGate, 0, sizeof(Map_Super_t) );
+
+ // set the gate number
+ pGate->Num = Number;
+
+ // read the mark
+ pTemp = strtok( pBuffer, " " );
+ if ( pTemp[0] == '*' )
+ {
+ pGate->fSuper = 1;
+ pTemp = strtok( NULL, " " );
+ }
+
+ // read the root gate
+ pGate->pRoot = Mio_LibraryReadGateByName( pLib->pGenlib, pTemp );
+ if ( pGate->pRoot == NULL )
+ {
+ printf( "Cannot read the root gate names %s.\n", pTemp );
+ return NULL;
+ }
+ // set the max number of fanouts
+ pGate->nFanLimit = s_MapFanoutLimits[ Mio_GateReadInputs(pGate->pRoot) ];
+
+ // read the pin-to-pin delay
+ for ( i = 0; ( pTemp = strtok( NULL, " \n\0" ) ); i++ )
+ {
+ if ( pTemp[0] == '#' )
+ break;
+ if ( i == nVarsMax )
+ {
+ printf( "There are too many entries on the line.\n" );
+ return NULL;
+ }
+ Num = atoi(pTemp);
+ if ( Num < 0 )
+ {
+ printf( "The number of a child supergate is negative.\n" );
+ return NULL;
+ }
+ if ( Num > pLib->nLines )
+ {
+ printf( "The number of a child supergate (%d) exceeded the number of lines (%d).\n",
+ Num, pLib->nLines );
+ return NULL;
+ }
+ pGate->pFanins[i] = pLib->ppSupers[Num];
+ }
+ pGate->nFanins = i;
+ if ( pGate->nFanins != (unsigned)Mio_GateReadInputs(pGate->pRoot) )
+ {
+ printf( "The number of fanins of a root gate is wrong.\n" );
+ return NULL;
+ }
+
+ // save the gate name, just in case
+ if ( pTemp && pTemp[0] == '#' )
+ {
+ if ( pTemp[1] == 0 )
+ pTemp = strtok( NULL, " \n\0" );
+ else // skip spaces
+ for ( pTemp++; *pTemp == ' '; pTemp++ );
+ // save the formula
+ pGate->pFormula = Extra_MmFlexEntryFetch( pLib->mmForms, strlen(pTemp)+1 );
+ strcpy( pGate->pFormula, pTemp );
+ }
+ // check the rest of the string
+ pTemp = strtok( NULL, " \n\0" );
+ if ( pTemp != NULL )
+ printf( "The following trailing symbols found \"%s\".\n", pTemp );
+ return pGate;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Derives information about the library.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_LibraryDeriveGateInfo( Map_SuperLib_t * pLib, st_table * tExcludeGate )
+{
+ Map_Super_t * pGate, * pFanin;
+ Mio_Pin_t * pPin;
+ unsigned uCanon[2];
+ unsigned uTruths[6][2];
+ int i, k, nRealVars;
+
+ // set all the derivable info related to the supergates
+ for ( i = pLib->nVarsMax; i < (int)pLib->nLines; i++ )
+ {
+ pGate = pLib->ppSupers[i];
+
+ if ( tExcludeGate )
+ {
+ if ( st_is_member( tExcludeGate, Mio_GateReadName( pGate->pRoot ) ) )
+ pGate->fExclude = 1;
+ for ( k = 0; k < (int)pGate->nFanins; k++ )
+ {
+ pFanin = pGate->pFanins[k];
+ if ( pFanin->fExclude )
+ {
+ pGate->fExclude = 1;
+ continue;
+ }
+ }
+ }
+
+ // collect the truth tables of the fanins
+ for ( k = 0; k < (int)pGate->nFanins; k++ )
+ {
+ pFanin = pGate->pFanins[k];
+ uTruths[k][0] = pFanin->uTruth[0];
+ uTruths[k][1] = pFanin->uTruth[1];
+ }
+ // derive the new truth table
+ Mio_DeriveTruthTable( pGate->pRoot, uTruths, pGate->nFanins, 6, pGate->uTruth );
+
+ // set the initial delays of the supergate
+ for ( k = 0; k < pLib->nVarsMax; k++ )
+ {
+ pGate->tDelaysR[k].Rise = pGate->tDelaysR[k].Fall = MAP_NO_VAR;
+ pGate->tDelaysF[k].Rise = pGate->tDelaysF[k].Fall = MAP_NO_VAR;
+ }
+ // get the linked list of pins for the given root gate
+ pPin = Mio_GateReadPins( pGate->pRoot );
+ // update the initial delay of the supergate using info from the corresponding pin
+ for ( k = 0; k < (int)pGate->nFanins; k++, pPin = Mio_PinReadNext(pPin) )
+ {
+ // if there is no corresponding pin, this is a bug, return fail
+ if ( pPin == NULL )
+ {
+ printf( "There are less pins than gate inputs.\n" );
+ return 0;
+ }
+ // update the delay information of k-th fanins info from the corresponding pin
+ Map_LibraryAddFaninDelays( pLib, pGate, pGate->pFanins[k], pPin );
+ }
+ // if there are some pins left, this is a bug, return fail
+ if ( pPin != NULL )
+ {
+ printf( "There are more pins than gate inputs.\n" );
+ return 0;
+ }
+ // find the max delay
+ pGate->tDelayMax.Rise = pGate->tDelayMax.Fall = MAP_NO_VAR;
+ for ( k = 0; k < pLib->nVarsMax; k++ )
+ {
+ // the rise of the output depends on the rise and fall of the output
+ if ( pGate->tDelayMax.Rise < pGate->tDelaysR[k].Rise )
+ pGate->tDelayMax.Rise = pGate->tDelaysR[k].Rise;
+ if ( pGate->tDelayMax.Rise < pGate->tDelaysR[k].Fall )
+ pGate->tDelayMax.Rise = pGate->tDelaysR[k].Fall;
+ // the fall of the output depends on the rise and fall of the output
+ if ( pGate->tDelayMax.Fall < pGate->tDelaysF[k].Rise )
+ pGate->tDelayMax.Fall = pGate->tDelaysF[k].Rise;
+ if ( pGate->tDelayMax.Fall < pGate->tDelaysF[k].Fall )
+ pGate->tDelayMax.Fall = pGate->tDelaysF[k].Fall;
+ }
+
+ // count gates and area of the supergate
+ pGate->nGates = 1;
+ pGate->Area = (float)Mio_GateReadArea(pGate->pRoot);
+ for ( k = 0; k < (int)pGate->nFanins; k++ )
+ {
+ pGate->nGates += pGate->pFanins[k]->nGates;
+ pGate->Area += pGate->pFanins[k]->Area;
+ }
+ // do not add the gate to the table, if this gate is an internal gate
+ // of some supegate and does not correspond to a supergate output
+ if ( ( !pGate->fSuper ) || pGate->fExclude )
+ continue;
+
+ // find the maximum index of a variable in the support of the supergates
+ // this is important for two reasons:
+ // (1) to limit the number of permutations considered for canonicization
+ // (2) to get rid of equivalence phases to speed-up matching
+ nRealVars = Map_LibraryGetMaxSuperPi_rec( pGate ) + 1;
+ assert( nRealVars > 0 && nRealVars <= pLib->nVarsMax );
+ // if there are some problems with this code, try this instead
+// nRealVars = pLib->nVarsMax;
+
+ // find the N-canonical form of this supergate
+ pGate->nPhases = Map_CanonComputeSlow( pLib->uTruths, pLib->nVarsMax, nRealVars, pGate->uTruth, pGate->uPhases, uCanon );
+ // add the supergate into the table by its N-canonical table
+ Map_SuperTableInsertC( pLib->tTableC, uCanon, pGate );
+ }
+ // sort the gates in each line
+ Map_SuperTableSortSupergatesByDelay( pLib->tTableC, pLib->nSupersAll );
+
+ // let the glory be manifest
+// Map_LibraryPrintTree( pLib );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Finds the largest PI number in the support of the supergate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_LibraryGetMaxSuperPi_rec( Map_Super_t * pGate )
+{
+ int i, VarCur, VarMax = 0;
+ if ( pGate->pRoot == NULL )
+ return pGate->Num;
+ for ( i = 0; i < (int)pGate->nFanins; i++ )
+ {
+ VarCur = Map_LibraryGetMaxSuperPi_rec( pGate->pFanins[i] );
+ if ( VarMax < VarCur )
+ VarMax = VarCur;
+ }
+ return VarMax;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Finds the largest PI number in the support of the supergate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+unsigned Map_LibraryGetGateSupp_rec( Map_Super_t * pGate )
+{
+ unsigned uSupport;
+ int i;
+ if ( pGate->pRoot == NULL )
+ return (unsigned)(1 << (pGate->Num));
+ uSupport = 0;
+ for ( i = 0; i < (int)pGate->nFanins; i++ )
+ uSupport |= Map_LibraryGetGateSupp_rec( pGate->pFanins[i] );
+ return uSupport;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Derives the pin-to-pin delay constraints for the supergate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_LibraryAddFaninDelays( Map_SuperLib_t * pLib, Map_Super_t * pGate, Map_Super_t * pFanin, Mio_Pin_t * pPin )
+{
+ Mio_PinPhase_t PinPhase;
+ float tDelayBlockRise, tDelayBlockFall, tDelayPin;
+ bool fMaxDelay = 0;
+ int i;
+
+ // use this node to enable max-delay model
+ if ( fMaxDelay )
+ {
+ float tDelayBlockMax;
+ // get the maximum delay
+ tDelayBlockMax = (float)Mio_PinReadDelayBlockMax(pPin);
+ // go through the supergate inputs
+ for ( i = 0; i < pLib->nVarsMax; i++ )
+ {
+ if ( pFanin->tDelaysR[i].Rise < 0 )
+ continue;
+ tDelayPin = pFanin->tDelaysR[i].Rise + tDelayBlockMax;
+ if ( pGate->tDelaysR[i].Rise < tDelayPin )
+ pGate->tDelaysR[i].Rise = tDelayPin;
+ }
+ // go through the supergate inputs
+ for ( i = 0; i < pLib->nVarsMax; i++ )
+ {
+ if ( pFanin->tDelaysF[i].Fall < 0 )
+ continue;
+ tDelayPin = pFanin->tDelaysF[i].Fall + tDelayBlockMax;
+ if ( pGate->tDelaysF[i].Fall < tDelayPin )
+ pGate->tDelaysF[i].Fall = tDelayPin;
+ }
+ return;
+ }
+
+ // get the interesting parameters of this pin
+ PinPhase = Mio_PinReadPhase(pPin);
+ tDelayBlockRise = (float)Mio_PinReadDelayBlockRise( pPin );
+ tDelayBlockFall = (float)Mio_PinReadDelayBlockFall( pPin );
+
+ // update the rise and fall of the output depending on the phase of the pin
+ if ( PinPhase != MIO_PHASE_INV ) // NONINV phase is present
+ {
+ // the rise of the gate is determined by the rise of the fanin
+ // the fall of the gate is determined by the fall of the fanin
+ for ( i = 0; i < pLib->nVarsMax; i++ )
+ {
+ ////////////////////////////////////////////////////////
+ // consider the rise of the gate
+ ////////////////////////////////////////////////////////
+ // check two types of constraints on the rise of the fanin:
+ // (1) the constraints related to the rise of the PIs
+ // (2) the constraints related to the fall of the PIs
+ if ( pFanin->tDelaysR[i].Rise >= 0 ) // case (1)
+ { // fanin's rise depends on the rise of i-th PI
+ // update the rise of the gate's output
+ if ( pGate->tDelaysR[i].Rise < pFanin->tDelaysR[i].Rise + tDelayBlockRise )
+ pGate->tDelaysR[i].Rise = pFanin->tDelaysR[i].Rise + tDelayBlockRise;
+ }
+ if ( pFanin->tDelaysR[i].Fall >= 0 ) // case (2)
+ { // fanin's rise depends on the fall of i-th PI
+ // update the rise of the gate's output
+ if ( pGate->tDelaysR[i].Fall < pFanin->tDelaysR[i].Fall + tDelayBlockRise )
+ pGate->tDelaysR[i].Fall = pFanin->tDelaysR[i].Fall + tDelayBlockRise;
+ }
+ ////////////////////////////////////////////////////////
+
+ ////////////////////////////////////////////////////////
+ // consider the fall of the gate (similar)
+ ////////////////////////////////////////////////////////
+ // check two types of constraints on the fall of the fanin:
+ // (1) the constraints related to the rise of the PIs
+ // (2) the constraints related to the fall of the PIs
+ if ( pFanin->tDelaysF[i].Rise >= 0 ) // case (1)
+ {
+ if ( pGate->tDelaysF[i].Rise < pFanin->tDelaysF[i].Rise + tDelayBlockFall )
+ pGate->tDelaysF[i].Rise = pFanin->tDelaysF[i].Rise + tDelayBlockFall;
+ }
+ if ( pFanin->tDelaysF[i].Fall >= 0 ) // case (2)
+ {
+ if ( pGate->tDelaysF[i].Fall < pFanin->tDelaysF[i].Fall + tDelayBlockFall )
+ pGate->tDelaysF[i].Fall = pFanin->tDelaysF[i].Fall + tDelayBlockFall;
+ }
+ ////////////////////////////////////////////////////////
+ }
+ }
+ if ( PinPhase != MIO_PHASE_NONINV ) // INV phase is present
+ {
+ // the rise of the gate is determined by the fall of the fanin
+ // the fall of the gate is determined by the rise of the fanin
+ for ( i = 0; i < pLib->nVarsMax; i++ )
+ {
+ ////////////////////////////////////////////////////////
+ // consider the rise of the gate's output
+ ////////////////////////////////////////////////////////
+ // check two types of constraints on the fall of the fanin:
+ // (1) the constraints related to the rise of the PIs
+ // (2) the constraints related to the fall of the PIs
+ if ( pFanin->tDelaysF[i].Rise >= 0 ) // case (1)
+ { // fanin's rise depends on the rise of i-th PI
+ // update the rise of the gate
+ if ( pGate->tDelaysR[i].Rise < pFanin->tDelaysF[i].Rise + tDelayBlockRise )
+ pGate->tDelaysR[i].Rise = pFanin->tDelaysF[i].Rise + tDelayBlockRise;
+ }
+ if ( pFanin->tDelaysF[i].Fall >= 0 ) // case (2)
+ { // fanin's rise depends on the fall of i-th PI
+ // update the rise of the gate
+ if ( pGate->tDelaysR[i].Fall < pFanin->tDelaysF[i].Fall + tDelayBlockRise )
+ pGate->tDelaysR[i].Fall = pFanin->tDelaysF[i].Fall + tDelayBlockRise;
+ }
+ ////////////////////////////////////////////////////////
+
+ ////////////////////////////////////////////////////////
+ // consider the fall of the gate (similar)
+ ////////////////////////////////////////////////////////
+ // check two types of constraints on the rise of the fanin:
+ // (1) the constraints related to the rise of the PIs
+ // (2) the constraints related to the fall of the PIs
+ if ( pFanin->tDelaysR[i].Rise >= 0 ) // case (1)
+ {
+ if ( pGate->tDelaysF[i].Rise < pFanin->tDelaysR[i].Rise + tDelayBlockFall )
+ pGate->tDelaysF[i].Rise = pFanin->tDelaysR[i].Rise + tDelayBlockFall;
+ }
+ if ( pFanin->tDelaysR[i].Fall >= 0 ) // case (2)
+ {
+ if ( pGate->tDelaysF[i].Fall < pFanin->tDelaysR[i].Fall + tDelayBlockFall )
+ pGate->tDelaysF[i].Fall = pFanin->tDelaysR[i].Fall + tDelayBlockFall;
+ }
+ ////////////////////////////////////////////////////////
+ }
+ }
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Performs phase transformation for one function.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+unsigned Map_CalculatePhase( unsigned uTruths[][2], int nVars, unsigned uTruth, unsigned uPhase )
+{
+ int v, Shift;
+ for ( v = 0, Shift = 1; v < nVars; v++, Shift <<= 1 )
+ if ( uPhase & Shift )
+ uTruth = (((uTruth & ~uTruths[v][0]) << Shift) | ((uTruth & uTruths[v][0]) >> Shift));
+ return uTruth;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs phase transformation for one function.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_CalculatePhase6( unsigned uTruths[][2], int nVars, unsigned uTruth[], unsigned uPhase, unsigned uTruthRes[] )
+{
+ unsigned uTemp;
+ int v, Shift;
+
+ // initialize the result
+ uTruthRes[0] = uTruth[0];
+ uTruthRes[1] = uTruth[1];
+ if ( uPhase == 0 )
+ return;
+ // compute the phase
+ for ( v = 0, Shift = 1; v < nVars; v++, Shift <<= 1 )
+ if ( uPhase & Shift )
+ {
+ if ( Shift < 32 )
+ {
+ uTruthRes[0] = (((uTruthRes[0] & ~uTruths[v][0]) << Shift) | ((uTruthRes[0] & uTruths[v][0]) >> Shift));
+ uTruthRes[1] = (((uTruthRes[1] & ~uTruths[v][1]) << Shift) | ((uTruthRes[1] & uTruths[v][1]) >> Shift));
+ }
+ else
+ {
+ uTemp = uTruthRes[0];
+ uTruthRes[0] = uTruthRes[1];
+ uTruthRes[1] = uTemp;
+ }
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the supergate library after deriving parameters.]
+
+ Description [This procedure is very useful to see the library after
+ it has been read into the mapper by "read_super" and all the information
+ about the supergates derived.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_LibraryPrintTree( Map_SuperLib_t * pLib )
+{
+ Map_Super_t * pGate;
+ int i, k;
+
+ // print all the info related to the supergates
+// for ( i = pLib->nVarsMax; i < (int)pLib->nLines; i++ )
+ for ( i = pLib->nVarsMax; i < 20; i++ )
+ {
+ pGate = pLib->ppSupers[i];
+
+ // write the gate's fanin info and formula
+ printf( "%6d ", pGate->Num );
+ printf( "%c ", pGate->fSuper? '*' : ' ' );
+ printf( "%6s", Mio_GateReadName(pGate->pRoot) );
+ for ( k = 0; k < (int)pGate->nFanins; k++ )
+ printf( " %6d", pGate->pFanins[k]->Num );
+ printf( " %s", pGate->pFormula );
+ printf( "\n" );
+
+ // write the gate's derived info
+ Extra_PrintBinary( stdout, pGate->uTruth, 64 );
+ printf( " %3d", pGate->nGates );
+ printf( " %6.2f", pGate->Area );
+ printf( " (%4.2f, %4.2f)", pGate->tDelayMax.Rise, pGate->tDelayMax.Fall );
+ printf( "\n" );
+ for ( k = 0; k < pLib->nVarsMax; k++ )
+ {
+ // print the constraint on the rise of the gate in the form (D1, D2),
+ // where D1 is the constraint related to the rise of the k-th PI
+ // where D2 is the constraint related to the fall of the k-th PI
+ if ( pGate->tDelaysR[k].Rise < 0 && pGate->tDelaysR[k].Fall < 0 )
+ printf( " (----, ----)" );
+ else if ( pGate->tDelaysR[k].Fall < 0 )
+ printf( " (%4.2f, ----)", pGate->tDelaysR[k].Rise );
+ else if ( pGate->tDelaysR[k].Rise < 0 )
+ printf( " (----, %4.2f)", pGate->tDelaysR[k].Fall );
+ else
+ printf( " (%4.2f, %4.2f)", pGate->tDelaysR[k].Rise, pGate->tDelaysR[k].Fall );
+
+ // print the constraint on the fall of the gate in the form (D1, D2),
+ // where D1 is the constraint related to the rise of the k-th PI
+ // where D2 is the constraint related to the fall of the k-th PI
+ if ( pGate->tDelaysF[k].Rise < 0 && pGate->tDelaysF[k].Fall < 0 )
+ printf( " (----, ----)" );
+ else if ( pGate->tDelaysF[k].Fall < 0 )
+ printf( " (%4.2f, ----)", pGate->tDelaysF[k].Rise );
+ else if ( pGate->tDelaysF[k].Rise < 0 )
+ printf( " (----, %4.2f)", pGate->tDelaysF[k].Fall );
+ else
+ printf( " (%4.2f, %4.2f)", pGate->tDelaysF[k].Rise, pGate->tDelaysF[k].Fall );
+ printf( "\n" );
+ }
+ printf( "\n" );
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/mapper/mapperTruth.c b/src/map/mapper/mapperTruth.c
new file mode 100644
index 00000000..9388b42f
--- /dev/null
+++ b/src/map/mapper/mapperTruth.c
@@ -0,0 +1,449 @@
+/**CFile****************************************************************
+
+ FileName [mapperTruth.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Generic technology mapping engine.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - June 1, 2004.]
+
+ Revision [$Id: mapperTruth.c,v 1.8 2005/01/23 06:59:45 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mapperInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+//static void Map_TruthsCutDcs( Map_Man_t * p, Map_Cut_t * pCut, unsigned uTruth[] );
+static void Map_TruthsCut( Map_Man_t * pMan, Map_Cut_t * pCut );
+static void Map_TruthsCut_rec( Map_Cut_t * pCut, unsigned uTruth[] );
+static void Map_TruthsUnmark_rec( Map_Cut_t * pCut );
+
+/*
+static int s_Same = 0;
+static int s_Diff = 0;
+static int s_Same2 = 0;
+static int s_Diff2 = 0;
+static int s_Truth = 0;
+static int s_Isop1 = 0;
+static int s_Isop2 = 0;
+*/
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Derives truth tables for each cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingTruths( Map_Man_t * pMan )
+{
+ ProgressBar * pProgress;
+ Map_Node_t * pNode;
+ Map_Cut_t * pCut;
+ int nNodes, i;
+ // compute the cuts for the POs
+ nNodes = pMan->vAnds->nSize;
+ pProgress = Extra_ProgressBarStart( stdout, nNodes );
+ for ( i = 0; i < nNodes; i++ )
+ {
+ pNode = pMan->vAnds->pArray[i];
+ if ( !Map_NodeIsAnd( pNode ) )
+ continue;
+ assert( pNode->pCuts );
+ assert( pNode->pCuts->nLeaves == 1 );
+
+ // match the simple cut
+ pNode->pCuts->M[0].uPhase = 0;
+ pNode->pCuts->M[0].pSupers = pMan->pSuperLib->pSuperInv;
+ pNode->pCuts->M[0].uPhaseBest = 0;
+ pNode->pCuts->M[0].pSuperBest = pMan->pSuperLib->pSuperInv;
+
+ pNode->pCuts->M[1].uPhase = 0;
+ pNode->pCuts->M[1].pSupers = pMan->pSuperLib->pSuperInv;
+ pNode->pCuts->M[1].uPhaseBest = 1;
+ pNode->pCuts->M[1].pSuperBest = pMan->pSuperLib->pSuperInv;
+
+ // match the rest of the cuts
+ for ( pCut = pNode->pCuts->pNext; pCut; pCut = pCut->pNext )
+ Map_TruthsCut( pMan, pCut );
+ Extra_ProgressBarUpdate( pProgress, i, "Tables ..." );
+ }
+ Extra_ProgressBarStop( pProgress );
+
+// printf( "Same = %6d. Diff = %6d.\n", s_Same, s_Diff );
+// printf( "Same2 = %6d. Diff2 = %6d.\n", s_Same2, s_Diff2 );
+// printf( "Truth = %6d. Isop1 = %6d. Isop2 = %6d.\n", s_Truth, s_Isop1, s_Isop2 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Derives the truth table for one cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_TruthsCut( Map_Man_t * p, Map_Cut_t * pCut )
+{
+ unsigned uTruth[2], uCanon[2];
+ unsigned char uPhases[16];
+ int i;
+
+ // generally speaking, 1-input cut can be matched into a wire!
+ if ( pCut->nLeaves == 1 )
+ return;
+ // set the leaf truth tables
+ for ( i = 0; i < pCut->nLeaves; i++ )
+ {
+ pCut->ppLeaves[i]->pCuts->uTruthTemp[0] = p->uTruths[i][0];
+ pCut->ppLeaves[i]->pCuts->uTruthTemp[1] = p->uTruths[i][1];
+ }
+ // recursively compute the truth table
+ pCut->nVolume = 0;
+ Map_TruthsCut_rec( pCut, uTruth );
+ // recursively unmark the visited cuts
+ Map_TruthsUnmark_rec( pCut );
+
+ // compute the canonical form for the positive phase
+ Map_CanonComputeSlow( p->uTruths, p->nVarsMax, pCut->nLeaves, uTruth, uPhases, uCanon );
+ pCut->M[1].pSupers = Map_SuperTableLookupC( p->pSuperLib, uCanon );
+ pCut->M[1].uPhase = uPhases[0];
+ p->nCanons++;
+
+ // compute the canonical form for the negative phase
+ uTruth[0] = ~uTruth[0];
+ uTruth[1] = ~uTruth[1];
+ Map_CanonComputeSlow( p->uTruths, p->nVarsMax, pCut->nLeaves, uTruth, uPhases, uCanon );
+ pCut->M[0].pSupers = Map_SuperTableLookupC( p->pSuperLib, uCanon );
+ pCut->M[0].uPhase = uPhases[0];
+ p->nCanons++;
+
+ // restore the truth table
+ uTruth[0] = ~uTruth[0];
+ uTruth[1] = ~uTruth[1];
+ // enable don't-care computation
+// Map_TruthsCutDcs( p, pCut, uTruth );
+}
+
+#if 0
+
+/**Function*************************************************************
+
+ Synopsis [Adds several other choices using SDCs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_TruthsCutDcs( Map_Man_t * p, Map_Cut_t * pCut, unsigned uTruth[] )
+{
+ unsigned uIsop1[2], uIsop2[2], uCanon[2];
+ unsigned char uPhases[16];
+
+ // add several other supergate classes derived using don't-cares
+ if ( pCut->uTruthDc[0] )
+ {
+ int nOnes;
+ nOnes = Map_TruthCountOnes( pCut->uTruthDc, pCut->nLeaves );
+ if ( nOnes == 1 )
+ {
+ uTruth[0] ^= pCut->uTruthDc[0];
+ uTruth[1] ^= pCut->uTruthDc[1];
+
+ // compute the canonical form for the positive phase
+ Map_CanonComputeSlow( p->uTruths, p->nVarsMax, pCut->nLeaves, uTruth, uPhases, uCanon );
+ pCut->M[1].pSupers = Map_SuperTableLookupC( p->pSuperLib, uCanon );
+ pCut->M[1].uPhase = uPhases[0];
+ p->nCanons++;
+
+ // compute the canonical form for the negative phase
+ uTruth[0] = ~uTruth[0];
+ uTruth[1] = ~uTruth[1];
+ Map_CanonComputeSlow( p->uTruths, p->nVarsMax, pCut->nLeaves, uTruth, uPhases, uCanon );
+ pCut->M[0].pSupers = Map_SuperTableLookupC( p->pSuperLib, uCanon );
+ pCut->M[0].uPhase = uPhases[0];
+ p->nCanons++;
+ }
+ else if ( nOnes == 2 )
+ {
+ int Num1, Num2, RetValue;
+ RetValue = Map_TruthDetectTwoFirst( pCut->uTruthDc, pCut->nLeaves );
+ Num1 = RetValue & 255;
+ Num2 = (RetValue >> 8) & 255;
+
+ // add the first bit
+ Map_InfoFlipVar( uTruth, Num1 );
+
+ // compute the canonical form for the positive phase
+ Map_CanonComputeSlow( p->uTruths, p->nVarsMax, pCut->nLeaves, uTruth, uPhases, uCanon );
+ pCut->M[1].pSupers = Map_SuperTableLookupC( p->pSuperLib, uCanon );
+ pCut->M[1].uPhase = uPhases[0];
+ p->nCanons++;
+
+ // compute the canonical form for the negative phase
+ uTruth[0] = ~uTruth[0];
+ uTruth[1] = ~uTruth[1];
+ Map_CanonComputeSlow( p->uTruths, p->nVarsMax, pCut->nLeaves, uTruth, uPhases, uCanon );
+ pCut->M[0].pSupers = Map_SuperTableLookupC( p->pSuperLib, uCanon );
+ pCut->M[0].uPhase = uPhases[0];
+ p->nCanons++;
+
+ // add the first bit
+ Map_InfoFlipVar( uTruth, Num2 );
+
+ // compute the canonical form for the positive phase
+ Map_CanonComputeSlow( p->uTruths, p->nVarsMax, pCut->nLeaves, uTruth, uPhases, uCanon );
+ pCut->M[1].pSupers = Map_SuperTableLookupC( p->pSuperLib, uCanon );
+ pCut->M[1].uPhase = uPhases[0];
+ p->nCanons++;
+
+ // compute the canonical form for the negative phase
+ uTruth[0] = ~uTruth[0];
+ uTruth[1] = ~uTruth[1];
+ Map_CanonComputeSlow( p->uTruths, p->nVarsMax, pCut->nLeaves, uTruth, uPhases, uCanon );
+ pCut->M[0].pSupers = Map_SuperTableLookupC( p->pSuperLib, uCanon );
+ pCut->M[0].uPhase = uPhases[0];
+ p->nCanons++;
+
+ // add the first bit
+ Map_InfoFlipVar( uTruth, Num1 );
+
+ // compute the canonical form for the positive phase
+ Map_CanonComputeSlow( p->uTruths, p->nVarsMax, pCut->nLeaves, uTruth, uPhases, uCanon );
+ pCut->M[1].pSupers = Map_SuperTableLookupC( p->pSuperLib, uCanon );
+ pCut->M[1].uPhase = uPhases[0];
+ p->nCanons++;
+
+ // compute the canonical form for the negative phase
+ uTruth[0] = ~uTruth[0];
+ uTruth[1] = ~uTruth[1];
+ Map_CanonComputeSlow( p->uTruths, p->nVarsMax, pCut->nLeaves, uTruth, uPhases, uCanon );
+ pCut->M[0].pSupers = Map_SuperTableLookupC( p->pSuperLib, uCanon );
+ pCut->M[0].uPhase = uPhases[0];
+ p->nCanons++;
+ }
+ else
+ {
+ // compute the ISOPs
+ uIsop1[0] = Map_ComputeIsop_rec( p, uTruth[0] & ~pCut->uTruthDc[0], uTruth[0] | pCut->uTruthDc[0], 0, pCut->nLeaves, 0 );
+ uIsop1[1] = uIsop1[0];
+ if ( uIsop1[0] != uTruth[0] )
+ {
+ // compute the canonical form for the positive phase
+ Map_CanonComputeSlow( p->uTruths, p->nVarsMax, pCut->nLeaves, uIsop1, uPhases, uCanon );
+ pCut->M[1].pSupers = Map_SuperTableLookupC( p->pSuperLib, uCanon );
+ pCut->M[1].uPhase = uPhases[0];
+ p->nCanons++;
+
+ // compute the canonical form for the negative phase
+ uIsop1[0] = ~uIsop1[0];
+ uIsop1[1] = ~uIsop1[1];
+ Map_CanonComputeSlow( p->uTruths, p->nVarsMax, pCut->nLeaves, uIsop1, uPhases, uCanon );
+ pCut->M[0].pSupers = Map_SuperTableLookupC( p->pSuperLib, uCanon );
+ pCut->M[0].uPhase = uPhases[0];
+ p->nCanons++;
+ }
+
+ uIsop2[0] = Map_ComputeIsop_rec( p, uTruth[0] & ~pCut->uTruthDc[0], uTruth[0] | pCut->uTruthDc[0], pCut->nLeaves-1, pCut->nLeaves, 1 );
+ uIsop2[1] = uIsop2[0];
+ if ( uIsop2[0] != uTruth[0] && uIsop2[0] != uIsop1[0] )
+ {
+ // compute the canonical form for the positive phase
+ Map_CanonComputeSlow( p->uTruths, p->nVarsMax, pCut->nLeaves, uIsop2, uPhases, uCanon );
+ pCut->M[1].pSupers = Map_SuperTableLookupC( p->pSuperLib, uCanon );
+ p->nCanons++;
+
+ // compute the canonical form for the negative phase
+ uIsop2[0] = ~uIsop2[0];
+ uIsop2[1] = ~uIsop2[1];
+ Map_CanonComputeSlow( p->uTruths, p->nVarsMax, pCut->nLeaves, uIsop2, uPhases, uCanon );
+ pCut->M[0].pSupers = Map_SuperTableLookupC( p->pSuperLib, uCanon );
+ pCut->M[0].uPhase = uPhases[0];
+ p->nCanons++;
+ }
+ }
+ }
+}
+
+#endif
+
+/**Function*************************************************************
+
+ Synopsis [Recursively derives the truth table for the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_TruthsCut_rec( Map_Cut_t * pCut, unsigned uTruthRes[] )
+{
+ unsigned uTruth1[2], uTruth2[2];
+ // if this is the elementary cut, its truth table is already available
+ if ( pCut->nLeaves == 1 )
+ {
+ uTruthRes[0] = pCut->uTruthTemp[0];
+ uTruthRes[1] = pCut->uTruthTemp[1];
+ return;
+ }
+ // if this node was already visited, return its computed truth table
+ if ( pCut->fMark )
+ {
+ uTruthRes[0] = pCut->uTruthTemp[0];
+ uTruthRes[1] = pCut->uTruthTemp[1];
+ return;
+ }
+ pCut->fMark = 1;
+ pCut->nVolume++;
+
+ assert( !Map_IsComplement(pCut) );
+ Map_TruthsCut_rec( Map_CutRegular(pCut->pOne), uTruth1 );
+ if ( Map_CutIsComplement(pCut->pOne) )
+ {
+ uTruth1[0] = ~uTruth1[0];
+ uTruth1[1] = ~uTruth1[1];
+ }
+ Map_TruthsCut_rec( Map_CutRegular(pCut->pTwo), uTruth2 );
+ if ( Map_CutIsComplement(pCut->pTwo) )
+ {
+ uTruth2[0] = ~uTruth2[0];
+ uTruth2[1] = ~uTruth2[1];
+ }
+ if ( !pCut->Phase )
+ {
+ uTruthRes[0] = pCut->uTruthTemp[0] = uTruth1[0] & uTruth2[0];
+ uTruthRes[1] = pCut->uTruthTemp[1] = uTruth1[1] & uTruth2[1];
+ }
+ else
+ {
+ uTruthRes[0] = pCut->uTruthTemp[0] = ~(uTruth1[0] & uTruth2[0]);
+ uTruthRes[1] = pCut->uTruthTemp[1] = ~(uTruth1[1] & uTruth2[1]);
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively derives the truth table for the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_TruthsUnmark_rec( Map_Cut_t * pCut )
+{
+ if ( pCut->nLeaves == 1 )
+ return;
+ // if this node was already visited, return its computed truth table
+ if ( pCut->fMark == 0 )
+ return;
+ pCut->fMark = 0;
+ Map_TruthsUnmark_rec( Map_CutRegular(pCut->pOne) );
+ Map_TruthsUnmark_rec( Map_CutRegular(pCut->pTwo) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the truth table of the don't-care set.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_TruthsCutDontCare( Map_Man_t * pMan, Map_Cut_t * pCut, unsigned * uTruthDc )
+{
+ if ( pCut->pOne || (pCut->uTruthZero[0] == 0 && pCut->uTruthZero[1] == 0) )
+ return 0;
+ assert( (pCut->uTruthTemp[0] & pCut->uTruthZero[0]) == 0 );
+ assert( (pCut->uTruthTemp[1] & pCut->uTruthZero[1]) == 0 );
+ uTruthDc[0] = ((~0) & (~pCut->uTruthTemp[0]) & (~pCut->uTruthZero[0]));
+ uTruthDc[1] = ((~0) & (~pCut->uTruthTemp[1]) & (~pCut->uTruthZero[1]));
+ if ( uTruthDc[0] == 0 && uTruthDc[1] == 0 )
+ return 0;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Expand the truth table]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_TruthCountOnes( unsigned * uTruth, int nLeaves )
+{
+ int i, nMints, Counter;
+ nMints = (1 << nLeaves);
+ Counter = 0;
+ for ( i = 0; i < nMints; i++ )
+ Counter += Map_InfoReadVar( uTruth, i );
+ return Counter;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Expand the truth table]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_TruthDetectTwoFirst( unsigned * uTruth, int nLeaves )
+{
+ int i, nMints, Num1 = -1, Num2 = -1;
+ nMints = (1 << nLeaves);
+ for ( i = 0; i < nMints; i++ )
+ if ( Map_InfoReadVar( uTruth, i ) )
+ {
+ if ( Num1 == -1 )
+ Num1 = i;
+ else if ( Num2 == -1 )
+ Num2 = i;
+ else
+ break;
+ }
+ assert( Num1 != -1 && Num2 != -1 );
+ return (Num1 << 8) | Num2;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/mapper/mapperUtils.c b/src/map/mapper/mapperUtils.c
new file mode 100644
index 00000000..f8fd1a4c
--- /dev/null
+++ b/src/map/mapper/mapperUtils.c
@@ -0,0 +1,1254 @@
+/**CFile****************************************************************
+
+ FileName [mapperUtils.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Generic technology mapping engine.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - June 1, 2004.]
+
+ Revision [$Id: mapperUtils.c,v 1.8 2004/11/03 22:41:45 satrajit Exp $]
+
+***********************************************************************/
+
+#include "mapperInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Map_MappingDfs_rec( Map_Node_t * pNode, Map_NodeVec_t * vNodes, int fCollectEquiv );
+static int Map_MappingCountLevels_rec( Map_Node_t * pNode );
+static float Map_MappingSetRefsAndArea_rec( Map_Man_t * pMan, Map_Node_t * pNode );
+static float Map_MappingSetRefsAndSwitch_rec( Map_Man_t * pMan, Map_Node_t * pNode );
+static float Map_MappingSetRefsAndWire_rec( Map_Man_t * pMan, Map_Node_t * pNode );
+static void Map_MappingDfsCuts_rec( Map_Node_t * pNode, Map_NodeVec_t * vNodes );
+static float Map_MappingArea_rec( Map_Man_t * pMan, Map_Node_t * pNode, Map_NodeVec_t * vNodes );
+static int Map_MappingCompareOutputDelay( int * pOut1, int * pOut2 );
+static unsigned Map_MappingExpandTruth_rec( unsigned uTruth, int nVars );
+static void Map_MappingGetChoiceLevels( Map_Man_t * pMan, Map_Node_t * p1, Map_Node_t * p2, int * pMin, int * pMax );
+static float Map_MappingGetChoiceVolumes( Map_Man_t * pMan, Map_Node_t * p1, Map_Node_t * p2 );
+static int Map_MappingCountUsedNodes( Map_Man_t * pMan, int fChoices );
+static Map_Man_t * s_pMan = NULL;
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+
+/**Function*************************************************************
+
+ Synopsis [Computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_NodeVec_t * Map_MappingDfs( Map_Man_t * pMan, int fCollectEquiv )
+{
+ Map_NodeVec_t * vNodes;
+ int i;
+ // perform the traversal
+ vNodes = Map_NodeVecAlloc( 100 );
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ Map_MappingDfs_rec( Map_Regular(pMan->pOutputs[i]), vNodes, fCollectEquiv );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ vNodes->pArray[i]->fMark0 = 0;
+// for ( i = 0; i < pMan->nOutputs; i++ )
+// Map_MappingUnmark_rec( Map_Regular(pMan->pOutputs[i]) );
+ return vNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_NodeVec_t * Map_MappingDfsNodes( Map_Man_t * pMan, Map_Node_t ** ppCuts, int nNodes, int fEquiv )
+{
+ Map_NodeVec_t * vNodes;
+ int i;
+ // perform the traversal
+ vNodes = Map_NodeVecAlloc( 200 );
+ for ( i = 0; i < nNodes; i++ )
+ Map_MappingDfs_rec( ppCuts[i], vNodes, fEquiv );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ vNodes->pArray[i]->fMark0 = 0;
+ return vNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingDfs_rec( Map_Node_t * pNode, Map_NodeVec_t * vNodes, int fCollectEquiv )
+{
+ assert( !Map_IsComplement(pNode) );
+ if ( pNode->fMark0 )
+ return;
+ // visit the transitive fanin
+ if ( Map_NodeIsAnd(pNode) )
+ {
+ Map_MappingDfs_rec( Map_Regular(pNode->p1), vNodes, fCollectEquiv );
+ Map_MappingDfs_rec( Map_Regular(pNode->p2), vNodes, fCollectEquiv );
+ }
+ // visit the equivalent nodes
+ if ( fCollectEquiv && pNode->pNextE )
+ Map_MappingDfs_rec( pNode->pNextE, vNodes, fCollectEquiv );
+ // make sure the node is not visited through the equivalent nodes
+ assert( pNode->fMark0 == 0 );
+ // mark the node as visited
+ pNode->fMark0 = 1;
+ // add the node to the list
+ Map_NodeVecPush( vNodes, pNode );
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Recursively computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingDfsMarked1_rec( Map_Node_t * pNode, Map_NodeVec_t * vNodes, int fFirst )
+{
+ assert( !Map_IsComplement(pNode) );
+ if ( pNode->fMark0 )
+ return;
+ // visit the transitive fanin
+ if ( Map_NodeIsAnd(pNode) )
+ {
+ Map_MappingDfsMarked1_rec( Map_Regular(pNode->p1), vNodes, 0 );
+ Map_MappingDfsMarked1_rec( Map_Regular(pNode->p2), vNodes, 0 );
+ }
+ // visit the equivalent nodes
+ if ( !fFirst && pNode->pNextE )
+ Map_MappingDfsMarked1_rec( pNode->pNextE, vNodes, 0 );
+ // make sure the node is not visited through the equivalent nodes
+ assert( pNode->fMark0 == 0 );
+ // mark the node as visited
+ pNode->fMark0 = 1;
+ // add the node to the list
+ Map_NodeVecPush( vNodes, pNode );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingDfsMarked2_rec( Map_Node_t * pNode, Map_NodeVec_t * vNodes, Map_NodeVec_t * vBoundary, int fFirst )
+{
+ assert( !Map_IsComplement(pNode) );
+ if ( pNode->fMark1 )
+ return;
+ if ( pNode->fMark0 || Map_NodeIsVar(pNode) )
+ {
+ pNode->fMark1 = 1;
+ Map_NodeVecPush(vBoundary, pNode);
+ return;
+ }
+ // visit the transitive fanin
+ if ( Map_NodeIsAnd(pNode) )
+ {
+ Map_MappingDfsMarked2_rec( Map_Regular(pNode->p1), vNodes, vBoundary, 0 );
+ Map_MappingDfsMarked2_rec( Map_Regular(pNode->p2), vNodes, vBoundary, 0 );
+ }
+ // visit the equivalent nodes
+ if ( !fFirst && pNode->pNextE )
+ Map_MappingDfsMarked2_rec( pNode->pNextE, vNodes, vBoundary, 0 );
+ // make sure the node is not visited through the equivalent nodes
+ assert( pNode->fMark1 == 0 );
+ // mark the node as visited
+ pNode->fMark1 = 1;
+ // add the node to the list
+ Map_NodeVecPush( vNodes, pNode );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Recursively computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingDfsMarked3_rec( Map_Node_t * pNode, Map_NodeVec_t * vNodes )
+{
+ assert( !Map_IsComplement(pNode) );
+ if ( pNode->fMark0 )
+ return;
+ // visit the transitive fanin
+ if ( Map_NodeIsAnd(pNode) )
+ {
+ Map_MappingDfsMarked3_rec( Map_Regular(pNode->p1), vNodes );
+ Map_MappingDfsMarked3_rec( Map_Regular(pNode->p2), vNodes );
+ }
+ // make sure the node is not visited through the equivalent nodes
+ assert( pNode->fMark0 == 0 );
+ // mark the node as visited
+ pNode->fMark0 = 1;
+ // add the node to the list
+ Map_NodeVecPush( vNodes, pNode );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingDfsMarked4_rec( Map_Node_t * pNode, Map_NodeVec_t * vNodes )
+{
+ assert( !Map_IsComplement(pNode) );
+ if ( pNode->fMark1 )
+ return;
+ // visit the transitive fanin
+ if ( Map_NodeIsAnd(pNode) )
+ {
+ Map_MappingDfsMarked4_rec( Map_Regular(pNode->p1), vNodes );
+ Map_MappingDfsMarked4_rec( Map_Regular(pNode->p2), vNodes );
+ }
+ // make sure the node is not visited through the equivalent nodes
+ assert( pNode->fMark1 == 0 );
+ // mark the node as visited
+ pNode->fMark1 = 1;
+ // add the node to the list
+ Map_NodeVecPush( vNodes, pNode );
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Computes the number of logic levels not counting PIs/POs.]
+
+ Description []
+
+ SideEffects [Note that this procedure will reassign the levels assigned
+ originally by NodeCreate() because it counts the number of levels with
+ choices differently!]
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_MappingCountLevels( Map_Man_t * pMan )
+{
+ int i, LevelsMax, LevelsCur;
+ // perform the traversal
+ LevelsMax = -1;
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ {
+ LevelsCur = Map_MappingCountLevels_rec( Map_Regular(pMan->pOutputs[i]) );
+ if ( LevelsMax < LevelsCur )
+ LevelsMax = LevelsCur;
+ }
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ Map_MappingUnmark_rec( Map_Regular(pMan->pOutputs[i]) );
+ return LevelsMax;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively computes the number of logic levels.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_MappingCountLevels_rec( Map_Node_t * pNode )
+{
+ int Level1, Level2;
+ assert( !Map_IsComplement(pNode) );
+ if ( !Map_NodeIsAnd(pNode) )
+ {
+ pNode->Level = 0;
+ return 0;
+ }
+ if ( pNode->fMark0 )
+ return pNode->Level;
+ pNode->fMark0 = 1;
+ // visit the transitive fanin
+ Level1 = Map_MappingCountLevels_rec( Map_Regular(pNode->p1) );
+ Level2 = Map_MappingCountLevels_rec( Map_Regular(pNode->p2) );
+ // set the number of levels
+ pNode->Level = 1 + ((Level1>Level2)? Level1: Level2);
+ return pNode->Level;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Unmarks the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingUnmark( Map_Man_t * pMan )
+{
+ int i;
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ Map_MappingUnmark_rec( Map_Regular(pMan->pOutputs[i]) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively unmarks the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingUnmark_rec( Map_Node_t * pNode )
+{
+ assert( !Map_IsComplement(pNode) );
+ if ( pNode->fMark0 == 0 )
+ return;
+ pNode->fMark0 = 0;
+ if ( !Map_NodeIsAnd(pNode) )
+ return;
+ Map_MappingUnmark_rec( Map_Regular(pNode->p1) );
+ Map_MappingUnmark_rec( Map_Regular(pNode->p2) );
+ // visit the equivalent nodes
+ if ( pNode->pNextE )
+ Map_MappingUnmark_rec( pNode->pNextE );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingMark_rec( Map_Node_t * pNode )
+{
+ assert( !Map_IsComplement(pNode) );
+ if ( pNode->fMark0 == 1 )
+ return;
+ pNode->fMark0 = 1;
+ if ( !Map_NodeIsAnd(pNode) )
+ return;
+ // visit the transitive fanin of the selected cut
+ Map_MappingMark_rec( Map_Regular(pNode->p1) );
+ Map_MappingMark_rec( Map_Regular(pNode->p2) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints a bunch of latest arriving outputs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingPrintOutputArrivals( Map_Man_t * p )
+{
+ Map_Time_t * pTimes;
+ Map_Node_t * pNode;
+ int fPhase, Limit, i;
+ int nOutputs;
+ int * pSorted;
+
+ // sort outputs by arrival time
+ s_pMan = p;
+ pSorted = ALLOC( int, p->nOutputs );
+ nOutputs = 0;
+ for ( i = 0; i < p->nOutputs; i++ )
+ {
+ if ( Map_NodeIsConst(p->pOutputs[i]) )
+ continue;
+ pSorted[nOutputs++] = i;
+ }
+ qsort( (void *)pSorted, nOutputs, sizeof(int),
+ (int (*)(const void *, const void *)) Map_MappingCompareOutputDelay );
+ assert( Map_MappingCompareOutputDelay( pSorted, pSorted + nOutputs - 1 ) <= 0 );
+ s_pMan = NULL;
+
+ // print the latest outputs
+ Limit = (nOutputs > 5)? 5 : nOutputs;
+ for ( i = 0; i < Limit; i++ )
+ {
+ // get the i-th latest output
+ pNode = Map_Regular(p->pOutputs[pSorted[i]]);
+ fPhase =!Map_IsComplement(p->pOutputs[pSorted[i]]);
+ pTimes = pNode->tArrival + fPhase;
+ // print out the best arrival time
+ printf( "Out %20s : ", p->ppOutputNames[pSorted[i]] );
+ printf( "Delay = (%5.2f, %5.2f) ", (double)pTimes->Rise, (double)pTimes->Fall );
+ printf( "%s", fPhase? "POS" : "NEG" );
+ printf( "\n" );
+ }
+ free( pSorted );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares the outputs by their arrival times.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_MappingCompareOutputDelay( int * pOut1, int * pOut2 )
+{
+ Map_Node_t * pNode1 = Map_Regular(s_pMan->pOutputs[*pOut1]);
+ Map_Node_t * pNode2 = Map_Regular(s_pMan->pOutputs[*pOut2]);
+ int fPhase1 = (pNode1 == s_pMan->pOutputs[*pOut1]);
+ int fPhase2 = (pNode2 == s_pMan->pOutputs[*pOut2]);
+ float Arrival1 = pNode1->tArrival[fPhase1].Worst;
+ float Arrival2 = pNode2->tArrival[fPhase2].Worst;
+ if ( Arrival1 > Arrival2 )
+ return -1;
+ if ( Arrival1 < Arrival2 )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets up the truth tables.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingSetupTruthTables( unsigned uTruths[][2] )
+{
+ int m, v;
+ // set up the truth tables
+ for ( m = 0; m < 32; m++ )
+ for ( v = 0; v < 5; v++ )
+ if ( m & (1 << v) )
+ uTruths[v][0] |= (1 << m);
+ // make adjustments for the case of 6 variables
+ for ( v = 0; v < 5; v++ )
+ uTruths[v][1] = uTruths[v][0];
+ uTruths[5][0] = 0;
+ uTruths[5][1] = MAP_FULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets up the truth tables.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingSetupTruthTablesLarge( unsigned uTruths[][32] )
+{
+ int m, v;
+ // clean everything
+ for ( m = 0; m < 32; m++ )
+ for ( v = 0; v < 10; v++ )
+ uTruths[v][m] = 0;
+ // set up the truth tables
+ for ( m = 0; m < 32; m++ )
+ for ( v = 0; v < 5; v++ )
+ if ( m & (1 << v) )
+ {
+ uTruths[v][0] |= (1 << m);
+ uTruths[v+5][m] = MAP_FULL;
+ }
+ // extend this info for the rest of the first 5 variables
+ for ( m = 0; m < 32; m++ )
+ for ( v = 0; v < 5; v++ )
+ uTruths[v][m] = uTruths[v][0];
+/*
+ // verify
+ for ( m = 0; m < 1024; m++, printf("\n") )
+ for ( v = 0; v < 10; v++ )
+ if ( Map_InfoReadVar( uTruths[v], m ) )
+ printf( "1" );
+ else
+ printf( "0" );
+*/
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets up the mask.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingSetupMask( unsigned uMask[], int nVarsMax )
+{
+ if ( nVarsMax == 6 )
+ uMask[0] = uMask[1] = MAP_FULL;
+ else
+ {
+ uMask[0] = MAP_MASK(1 << nVarsMax);
+ uMask[1] = 0;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Verify one useful property.]
+
+ Description [This procedure verifies one useful property. After
+ the FRAIG construction with choice nodes is over, each primary node
+ should have fanins that are primary nodes. The primary nodes is the
+ one that does not have pNode->pRepr set to point to another node.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_ManCheckConsistency( Map_Man_t * p )
+{
+ Map_Node_t * pNode;
+ Map_NodeVec_t * pVec;
+ int i;
+ pVec = Map_MappingDfs( p, 0 );
+ for ( i = 0; i < pVec->nSize; i++ )
+ {
+ pNode = pVec->pArray[i];
+ if ( Map_NodeIsVar(pNode) )
+ {
+ if ( pNode->pRepr )
+ printf( "Primary input %d is a secondary node.\n", pNode->Num );
+ }
+ else if ( Map_NodeIsConst(pNode) )
+ {
+ if ( pNode->pRepr )
+ printf( "Constant 1 %d is a secondary node.\n", pNode->Num );
+ }
+ else
+ {
+ if ( pNode->pRepr )
+ printf( "Internal node %d is a secondary node.\n", pNode->Num );
+ if ( Map_Regular(pNode->p1)->pRepr )
+ printf( "Internal node %d has first fanin that is a secondary node.\n", pNode->Num );
+ if ( Map_Regular(pNode->p2)->pRepr )
+ printf( "Internal node %d has second fanin that is a secondary node.\n", pNode->Num );
+ }
+ }
+ Map_NodeVecFree( pVec );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if current mapping of the node violates fanout limits.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_MappingNodeIsViolator( Map_Node_t * pNode, Map_Cut_t * pCut, int fPosPol )
+{
+ return pNode->nRefAct[fPosPol] > (int)pCut->M[fPosPol].pSuperBest->nFanLimit;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the total are flow of the network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Map_MappingGetAreaFlow( Map_Man_t * p )
+{
+ Map_Node_t * pNode;
+ Map_Cut_t * pCut;
+ float aFlowFlowTotal = 0;
+ int fPosPol, i;
+ for ( i = 0; i < p->nOutputs; i++ )
+ {
+ pNode = Map_Regular(p->pOutputs[i]);
+ if ( !Map_NodeIsAnd(pNode) )
+ continue;
+ fPosPol = !Map_IsComplement(p->pOutputs[i]);
+ pCut = pNode->pCutBest[fPosPol];
+ if ( pCut == NULL )
+ {
+ fPosPol = !fPosPol;
+ pCut = pNode->pCutBest[fPosPol];
+ }
+ aFlowFlowTotal += pNode->pCutBest[fPosPol]->M[fPosPol].AreaFlow;
+ }
+ return aFlowFlowTotal;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Compares the supergates by their level.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_CompareNodesByLevel( Map_Node_t ** ppS1, Map_Node_t ** ppS2 )
+{
+ Map_Node_t * pN1 = Map_Regular(*ppS1);
+ Map_Node_t * pN2 = Map_Regular(*ppS2);
+ if ( pN1->Level > pN2->Level )
+ return -1;
+ if ( pN1->Level < pN2->Level )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Orders the nodes in the decreasing order of levels.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingSortByLevel( Map_Man_t * pMan, Map_NodeVec_t * vNodes )
+{
+ qsort( (void *)vNodes->pArray, vNodes->nSize, sizeof(Map_Node_t *),
+ (int (*)(const void *, const void *)) Map_CompareNodesByLevel );
+// assert( Map_CompareNodesByLevel( vNodes->pArray, vNodes->pArray + vNodes->nSize - 1 ) <= 0 );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Compares the supergates by their pointer.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_CompareNodesByPointer( Map_Node_t ** ppS1, Map_Node_t ** ppS2 )
+{
+ if ( *ppS1 < *ppS2 )
+ return -1;
+ if ( *ppS1 > *ppS2 )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Counts how many AIG nodes are mapped in both polarities.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_MappingCountDoubles( Map_Man_t * pMan, Map_NodeVec_t * vNodes )
+{
+ Map_Node_t * pNode;
+ int Counter, i;
+ // count the number of equal adjacent nodes
+ Counter = 0;
+ for ( i = 0; i < vNodes->nSize; i++ )
+ {
+ pNode = vNodes->pArray[i];
+ if ( !Map_NodeIsAnd(pNode) )
+ continue;
+ if ( (pNode->nRefAct[0] && pNode->pCutBest[0]) &&
+ (pNode->nRefAct[1] && pNode->pCutBest[1]) )
+ Counter++;
+ }
+ return Counter;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+st_table * Map_CreateTableGate2Super( Map_Man_t * pMan )
+{
+ Map_Super_t * pSuper;
+ st_table * tTable;
+ int i, nInputs, v;
+ tTable = st_init_table(strcmp, st_strhash);
+ for ( i = 0; i < pMan->pSuperLib->nSupersAll; i++ )
+ {
+ pSuper = pMan->pSuperLib->ppSupers[i];
+ if ( pSuper->nGates == 1 )
+ {
+ // skip different versions of the same root gate
+ nInputs = Mio_GateReadInputs(pSuper->pRoot);
+ for ( v = 0; v < nInputs; v++ )
+ if ( pSuper->pFanins[v]->Num != nInputs - 1 - v )
+ break;
+ if ( v != nInputs )
+ continue;
+// printf( "%s\n", Mio_GateReadName(pSuper->pRoot) );
+ if ( st_insert( tTable, (char *)pSuper->pRoot, (char *)pSuper ) )
+ {
+ assert( 0 );
+ }
+ }
+ }
+ return tTable;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Get the FRAIG node with phase.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_ManCleanData( Map_Man_t * p )
+{
+ int i;
+ for ( i = 0; i < p->vNodesAll->nSize; i++ )
+ p->vNodesAll->pArray[i]->pData0 = p->vNodesAll->pArray[i]->pData1 = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Expand the truth table]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingExpandTruth( unsigned uTruth[2], int nVars )
+{
+ assert( nVars < 7 );
+ if ( nVars == 6 )
+ return;
+ if ( nVars < 5 )
+ {
+ uTruth[0] &= MAP_MASK( (1<<nVars) );
+ uTruth[0] = Map_MappingExpandTruth_rec( uTruth[0], nVars );
+ }
+ uTruth[1] = uTruth[0];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Expand the truth table]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+unsigned Map_MappingExpandTruth_rec( unsigned uTruth, int nVars )
+{
+ assert( nVars < 6 );
+ if ( nVars == 5 )
+ return uTruth;
+ return Map_MappingExpandTruth_rec( uTruth | (uTruth << (1 << nVars)), nVars + 1 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compute the arrival times.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Map_MappingComputeDelayWithFanouts( Map_Man_t * p )
+{
+ Map_Node_t * pNode;
+ float Result;
+ int i;
+ for ( i = 0; i < p->vAnds->nSize; i++ )
+ {
+ // skip primary inputs
+ pNode = p->vAnds->pArray[i];
+ if ( !Map_NodeIsAnd( pNode ) )
+ continue;
+ // skip a secondary node
+ if ( pNode->pRepr )
+ continue;
+ // count the switching nodes
+ if ( pNode->nRefAct[0] > 0 )
+ Map_TimeCutComputeArrival( pNode, pNode->pCutBest[0], 0, MAP_FLOAT_LARGE );
+ if ( pNode->nRefAct[1] > 0 )
+ Map_TimeCutComputeArrival( pNode, pNode->pCutBest[1], 1, MAP_FLOAT_LARGE );
+ }
+ Result = Map_TimeComputeArrivalMax(p);
+ printf( "Max arrival times with fanouts = %10.2f.\n", Result );
+ return Result;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Sets up the mask.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_MappingGetMaxLevel( Map_Man_t * pMan )
+{
+ int nLevelMax, i;
+ nLevelMax = 0;
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ nLevelMax = ((unsigned)nLevelMax) > Map_Regular(pMan->pOutputs[i])->Level?
+ nLevelMax : Map_Regular(pMan->pOutputs[i])->Level;
+ return nLevelMax;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Analyses choice nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_MappingUpdateLevel_rec( Map_Man_t * pMan, Map_Node_t * pNode, int fMaximum )
+{
+ Map_Node_t * pTemp;
+ int Level1, Level2, LevelE;
+ assert( !Map_IsComplement(pNode) );
+ if ( !Map_NodeIsAnd(pNode) )
+ return pNode->Level;
+ // skip the visited node
+ if ( pNode->TravId == pMan->nTravIds )
+ return pNode->Level;
+ pNode->TravId = pMan->nTravIds;
+ // compute levels of the children nodes
+ Level1 = Map_MappingUpdateLevel_rec( pMan, Map_Regular(pNode->p1), fMaximum );
+ Level2 = Map_MappingUpdateLevel_rec( pMan, Map_Regular(pNode->p2), fMaximum );
+ pNode->Level = 1 + MAP_MAX( Level1, Level2 );
+ if ( pNode->pNextE )
+ {
+ LevelE = Map_MappingUpdateLevel_rec( pMan, pNode->pNextE, fMaximum );
+ if ( fMaximum )
+ {
+ if ( pNode->Level < (unsigned)LevelE )
+ pNode->Level = LevelE;
+ }
+ else
+ {
+ if ( pNode->Level > (unsigned)LevelE )
+ pNode->Level = LevelE;
+ }
+ // set the level of all equivalent nodes to be the same minimum
+ if ( pNode->pRepr == NULL ) // the primary node
+ for ( pTemp = pNode->pNextE; pTemp; pTemp = pTemp->pNextE )
+ pTemp->Level = pNode->Level;
+ }
+ return pNode->Level;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Resets the levels of the nodes in the choice graph.]
+
+ Description [Makes the level of the choice nodes to be equal to the
+ maximum of the level of the nodes in the equivalence class. This way
+ sorting by level leads to the reverse topological order, which is
+ needed for the required time computation.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingSetChoiceLevels( Map_Man_t * pMan )
+{
+ int i;
+ pMan->nTravIds++;
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ Map_MappingUpdateLevel_rec( pMan, Map_Regular(pMan->pOutputs[i]), 1 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reports statistics on choice nodes.]
+
+ Description [The number of choice nodes is the number of primary nodes,
+ which has pNextE set to a pointer. The number of choices is the number
+ of entries in the equivalent-node lists of the primary nodes.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingReportChoices( Map_Man_t * pMan )
+{
+ Map_Node_t * pNode, * pTemp;
+ int nChoiceNodes, nChoices;
+ int i, LevelMax1, LevelMax2;
+
+ // report the number of levels
+ LevelMax1 = Map_MappingGetMaxLevel( pMan );
+ pMan->nTravIds++;
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ Map_MappingUpdateLevel_rec( pMan, Map_Regular(pMan->pOutputs[i]), 0 );
+ LevelMax2 = Map_MappingGetMaxLevel( pMan );
+
+ // report statistics about choices
+ nChoiceNodes = nChoices = 0;
+ for ( i = 0; i < pMan->vAnds->nSize; i++ )
+ {
+ pNode = pMan->vAnds->pArray[i];
+ if ( pNode->pRepr == NULL && pNode->pNextE != NULL )
+ { // this is a choice node = the primary node that has equivalent nodes
+ nChoiceNodes++;
+ for ( pTemp = pNode; pTemp; pTemp = pTemp->pNextE )
+ nChoices++;
+ }
+ }
+ printf( "Maximum level: Original = %d. Reduced due to choices = %d.\n", LevelMax1, LevelMax2 );
+ printf( "Choice stats: Choice nodes = %d. Total choices = %d.\n", nChoiceNodes, nChoices );
+}
+
+/*
+void Map_MappingReportChoices( Map_Man_t * pMan )
+{
+ Map_Node_t * pNode, * pTemp;
+ int nChoiceNodes, nChoices;
+ int i, LevelMax1, LevelMax2;
+ int DiffMaxTotal, DiffMinTotal, Min, Max;
+ int CounterByMin[300]={0}, CounterByMax[300]={0};
+
+ // report the number of levels
+ LevelMax1 = Map_MappingGetMaxLevel( pMan );
+ pMan->nTravIds++;
+ for ( i = 0; i < pMan->nOutputs; i++ )
+// Map_MappingUpdateLevel_rec( pMan, Map_Regular(pMan->pOutputs[i]), 0 );
+ Map_MappingUpdateLevel_rec( pMan, Map_Regular(pMan->pOutputs[i]), 1 );
+ LevelMax2 = Map_MappingGetMaxLevel( pMan );
+
+ // report statistics about choices
+ nChoiceNodes = nChoices = 0;
+ DiffMaxTotal = DiffMinTotal = 0;
+ for ( i = 0; i < pMan->vAnds->nSize; i++ )
+ {
+ pNode = pMan->vAnds->pArray[i];
+ if ( pNode->pRepr == NULL && pNode->pNextE != NULL )
+ { // this is a choice node = the primary node that has equivalent nodes
+ nChoiceNodes++;
+ for ( pTemp = pNode; pTemp; pTemp = pTemp->pNextE )
+ nChoices++;
+ // call to compare the levels
+ Map_MappingGetChoiceLevels( pMan, pNode, pNode->pNextE, &Min, &Max );
+ assert( Min < (int)pNode->Level );
+ assert( Max < (int)pNode->Level );
+ DiffMinTotal += pNode->Level - Max;
+ DiffMaxTotal += pNode->Level - Min;
+
+ CounterByMin[pNode->Level - Max]++;
+ CounterByMax[pNode->Level - Min]++;
+
+ }
+ }
+ printf( "Maximum level: Original = %d. Reduced due to choices = %d.\n", LevelMax1, LevelMax2 );
+ printf( "Choice stats: Choice nodes = %d. Total choices = %d.\n", nChoiceNodes, nChoices );
+ printf( "Choice depth: Minimum = %4.2f. Maximum = %4.2f.\n",
+ ((float)DiffMinTotal)/nChoiceNodes, ((float)DiffMaxTotal)/nChoiceNodes );
+
+ {
+ FILE * pTable;
+ pTable = fopen( "statsc.txt", "a+" );
+ fprintf( pTable, "%6d ", pMan->vAnds->nSize );
+ fprintf( pTable, "%5d ", LevelMax2 );
+ fprintf( pTable, "%5d ", nChoiceNodes );
+ fprintf( pTable, "%5d ", nChoices );
+ fprintf( pTable, "%5.2f ", ((float)DiffMinTotal)/nChoiceNodes );
+ fprintf( pTable, "%5.2f ", ((float)DiffMaxTotal)/nChoiceNodes );
+// fprintf( pTable, "%4.2f\n", (float)(Time)/(float)(CLOCKS_PER_SEC) );
+ fprintf( pTable, "\n" );
+ fclose( pTable );
+ }
+
+
+ printf( "Distribution by min/max levels:\n" );
+ for ( i = 0; i < LevelMax2; i++ )
+ printf( "%3d : %5d %5d\n", i, CounterByMin[i], CounterByMax[i] );
+ printf( "\n" );
+}
+*/
+
+/*
+void Map_MappingReportChoices( Map_Man_t * pMan )
+{
+ Map_Node_t * pNode, * pTemp;
+ int nChoiceNodes, nChoices;
+ int i, LevelMax1, LevelMax2;
+ int CounterByVol[1000]={0};
+ float VolumeAve, Volume;
+
+ // report the number of levels
+ LevelMax1 = Map_MappingGetMaxLevel( pMan );
+ pMan->nTravIds++;
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ Map_MappingUpdateLevel_rec( pMan, Map_Regular(pMan->pOutputs[i]), 0 );
+// Map_MappingUpdateLevel_rec( pMan, Map_Regular(pMan->pOutputs[i]), 1 );
+ LevelMax2 = Map_MappingGetMaxLevel( pMan );
+
+ // report statistics about choices
+ nChoiceNodes = nChoices = 0;
+ VolumeAve = 0.0;
+ for ( i = 0; i < pMan->vAnds->nSize; i++ )
+ {
+ pNode = pMan->vAnds->pArray[i];
+ if ( pNode->pRepr == NULL && pNode->pNextE != NULL )
+ { // this is a choice node = the primary node that has equivalent nodes
+ nChoiceNodes++;
+ for ( pTemp = pNode; pTemp; pTemp = pTemp->pNextE )
+ nChoices++;
+ Volume = Map_MappingGetChoiceVolumes( pMan, pNode, pNode->pNextE );
+ VolumeAve += Volume;
+ assert( Volume < 1000 );
+ CounterByVol[(int)Volume]++;
+ }
+ }
+ printf( "Maximum level: Original = %d. Reduced due to choices = %d.\n", LevelMax1, LevelMax2 );
+ printf( "Choice stats: Choice nodes = %d. Total choices = %d.\n", nChoiceNodes, nChoices );
+ printf( "Average volume = %5.4f.\n", VolumeAve/nChoiceNodes );
+*/
+/*
+ {
+ FILE * pTable;
+ pTable = fopen( "statsv.txt", "a+" );
+ fprintf( pTable, "%6d ", Map_MappingCountUsedNodes(pMan,1) );
+ fprintf( pTable, "%6d ", Map_MappingCountUsedNodes(pMan,0) );
+ fprintf( pTable, "%5d ", LevelMax1 );
+ fprintf( pTable, " " );
+ fprintf( pTable, "%5d ", nChoiceNodes );
+ fprintf( pTable, "%5d ", nChoices );
+ fprintf( pTable, " " );
+ fprintf( pTable, "%5.4f ", VolumeAve/nChoiceNodes );
+ fprintf( pTable, "\n" );
+ fclose( pTable );
+ }
+ printf( "Distribution by volume:\n" );
+ for ( i = 0; i < 1000; i++ )
+ if ( CounterByVol[i] > 0 )
+ printf( "%3d : %5d\n", i, CounterByVol[i] );
+ printf( "\n" );
+*/
+/*
+}
+*/
+
+/**Function*************************************************************
+
+ Synopsis [Computes the maximum and minimum levels of the choice nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_MappingGetChoiceLevels( Map_Man_t * pMan, Map_Node_t * p1, Map_Node_t * p2, int * pMin, int * pMax )
+{
+ Map_NodeVec_t * vNodes;
+ Map_NodeVec_t * vBoundary;
+ Map_Node_t * pNode;
+ int i, Min, Max;
+
+ vNodes = Map_NodeVecAlloc( 100 );
+ vBoundary = Map_NodeVecAlloc( 100 );
+ Map_MappingDfsMarked1_rec( p1, vNodes, 1 );
+ Map_MappingDfsMarked2_rec( p2, vNodes, vBoundary, 1 );
+ // clean the marks
+ Min = 100000;
+ Max = -100000;
+ for ( i = 0; i < vBoundary->nSize; i++ )
+ {
+ pNode = vBoundary->pArray[i];
+ if ( Min > (int)pNode->Level )
+ Min = pNode->Level;
+ if ( Max < (int)pNode->Level )
+ Max = pNode->Level;
+ }
+ Map_NodeVecFree( vBoundary );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ {
+ pNode = vNodes->pArray[i];
+ pNode->fMark0 = pNode->fMark1 = 0;
+ }
+ Map_NodeVecFree( vNodes );
+ *pMin = Min;
+ *pMax = Max;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Map_MappingGetChoiceVolumes( Map_Man_t * pMan, Map_Node_t * p1, Map_Node_t * p2 )
+{
+ Map_NodeVec_t * vNodes;
+ Map_Node_t * pNode;
+ int i, nVolumeTotal, nVolumeUnique;
+
+ vNodes = Map_NodeVecAlloc( 100 );
+ Map_MappingDfsMarked3_rec( p1, vNodes );
+ Map_MappingDfsMarked4_rec( p2, vNodes );
+ // clean the marks
+ nVolumeTotal = nVolumeUnique = 0;
+ for ( i = 0; i < vNodes->nSize; i++ )
+ {
+ pNode = vNodes->pArray[i];
+ if ( !Map_NodeIsAnd(pNode) )
+ continue;
+ nVolumeTotal++;
+ if ( pNode->fMark0 ^ pNode->fMark1 )
+ nVolumeUnique++;
+ pNode->fMark0 = pNode->fMark1 = 0;
+ }
+ Map_NodeVecFree( vNodes );
+// return ((float)nVolumeUnique)/nVolumeTotal;
+ return (float)nVolumeUnique;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Computes the maximum and minimum levels of the choice nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_MappingCountUsedNodes( Map_Man_t * pMan, int fChoices )
+{
+ Map_NodeVec_t * vNodes;
+ int Result;
+ vNodes = Map_MappingDfs( pMan, fChoices );
+ Result = vNodes->nSize;
+ Map_NodeVecFree( vNodes );
+ return Result;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/mapper/mapperVec.c b/src/map/mapper/mapperVec.c
new file mode 100644
index 00000000..e3ab4b7f
--- /dev/null
+++ b/src/map/mapper/mapperVec.c
@@ -0,0 +1,318 @@
+/**CFile****************************************************************
+
+ FileName [mapperVec.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Generic technology mapping engine.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - June 1, 2004.]
+
+ Revision [$Id: mapperVec.c,v 1.3 2005/01/23 06:59:45 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mapperInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Map_NodeVecCompareLevels( Map_Node_t ** pp1, Map_Node_t ** pp2 );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Allocates a vector with the given capacity.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_NodeVec_t * Map_NodeVecAlloc( int nCap )
+{
+ Map_NodeVec_t * p;
+ p = ALLOC( Map_NodeVec_t, 1 );
+ if ( nCap > 0 && nCap < 16 )
+ nCap = 16;
+ p->nSize = 0;
+ p->nCap = nCap;
+ p->pArray = p->nCap? ALLOC( Map_Node_t *, p->nCap ) : NULL;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_NodeVecFree( Map_NodeVec_t * p )
+{
+ FREE( p->pArray );
+ FREE( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Node_t ** Map_NodeVecReadArray( Map_NodeVec_t * p )
+{
+ return p->pArray;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_NodeVecReadSize( Map_NodeVec_t * p )
+{
+ return p->nSize;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Resizes the vector to the given capacity.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_NodeVecGrow( Map_NodeVec_t * p, int nCapMin )
+{
+ if ( p->nCap >= nCapMin )
+ return;
+ p->pArray = REALLOC( Map_Node_t *, p->pArray, nCapMin );
+ p->nCap = nCapMin;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_NodeVecShrink( Map_NodeVec_t * p, int nSizeNew )
+{
+ assert( p->nSize >= nSizeNew );
+ p->nSize = nSizeNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_NodeVecClear( Map_NodeVec_t * p )
+{
+ p->nSize = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_NodeVecPush( Map_NodeVec_t * p, Map_Node_t * Entry )
+{
+ if ( p->nSize == p->nCap )
+ {
+ if ( p->nCap < 16 )
+ Map_NodeVecGrow( p, 16 );
+ else
+ Map_NodeVecGrow( p, 2 * p->nCap );
+ }
+ p->pArray[p->nSize++] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Add the element while ensuring uniqueness.]
+
+ Description [Returns 1 if the element was found, and 0 if it was new. ]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_NodeVecPushUnique( Map_NodeVec_t * p, Map_Node_t * Entry )
+{
+ int i;
+ for ( i = 0; i < p->nSize; i++ )
+ if ( p->pArray[i] == Entry )
+ return 1;
+ Map_NodeVecPush( p, Entry );
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Node_t * Map_NodeVecPop( Map_NodeVec_t * p )
+{
+ return p->pArray[--p->nSize];
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_NodeVecRemove( Map_NodeVec_t * p, Map_Node_t * Entry )
+{
+ int i;
+ for ( i = 0; i < p->nSize; i++ )
+ if ( p->pArray[i] == Entry )
+ break;
+ assert( i < p->nSize );
+ for ( i++; i < p->nSize; i++ )
+ p->pArray[i-1] = p->pArray[i];
+ p->nSize--;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_NodeVecWriteEntry( Map_NodeVec_t * p, int i, Map_Node_t * Entry )
+{
+ assert( i >= 0 && i < p->nSize );
+ p->pArray[i] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Map_Node_t * Map_NodeVecReadEntry( Map_NodeVec_t * p, int i )
+{
+ assert( i >= 0 && i < p->nSize );
+ return p->pArray[i];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sorting the entries by their integer value.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Map_NodeVecSortByLevel( Map_NodeVec_t * p )
+{
+ qsort( (void *)p->pArray, p->nSize, sizeof(Map_Node_t *),
+ (int (*)(const void *, const void *)) Map_NodeVecCompareLevels );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Comparison procedure for two clauses.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Map_NodeVecCompareLevels( Map_Node_t ** pp1, Map_Node_t ** pp2 )
+{
+ int Level1 = Map_Regular(*pp1)->Level;
+ int Level2 = Map_Regular(*pp2)->Level;
+ if ( Level1 < Level2 )
+ return -1;
+ if ( Level1 > Level2 )
+ return 1;
+ if ( Map_Regular(*pp1)->Num < Map_Regular(*pp2)->Num )
+ return -1;
+ if ( Map_Regular(*pp1)->Num > Map_Regular(*pp2)->Num )
+ return 1;
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/map/mapper/module.make b/src/map/mapper/module.make
new file mode 100644
index 00000000..1d3b8867
--- /dev/null
+++ b/src/map/mapper/module.make
@@ -0,0 +1,17 @@
+SRC += src/map/mapper/mapper.c \
+ src/map/mapper/mapperCanon.c \
+ src/map/mapper/mapperCore.c \
+ src/map/mapper/mapperCreate.c \
+ src/map/mapper/mapperCut.c \
+ src/map/mapper/mapperCutUtils.c \
+ src/map/mapper/mapperFanout.c \
+ src/map/mapper/mapperLib.c \
+ src/map/mapper/mapperMatch.c \
+ src/map/mapper/mapperRefs.c \
+ src/map/mapper/mapperSuper.c \
+ src/map/mapper/mapperTable.c \
+ src/map/mapper/mapperTime.c \
+ src/map/mapper/mapperTree.c \
+ src/map/mapper/mapperTruth.c \
+ src/map/mapper/mapperUtils.c \
+ src/map/mapper/mapperVec.c
diff --git a/src/map/mio/mio.c b/src/map/mio/mio.c
new file mode 100644
index 00000000..a01aeaa9
--- /dev/null
+++ b/src/map/mio/mio.c
@@ -0,0 +1,269 @@
+/**CFile****************************************************************
+
+ FileName [mio.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [File reading/writing for technology mapping.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - August 18, 2003.]
+
+ Revision [$Id: mio.c,v 1.4 2004/08/05 18:34:51 satrajit Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+#include "mvc.h"
+#include "mainInt.h"
+#include "mioInt.h"
+#include "mapper.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Mio_CommandReadLibrary( Abc_Frame_t * pAbc, int argc, char **argv );
+static int Mio_CommandPrintLibrary( Abc_Frame_t * pAbc, int argc, char **argv );
+
+// internal version of GENLIB library
+static char * pMcncGenlib[25] = {
+ "GATE inv1 1 O=!a; PIN * INV 1 999 0.9 0.0 0.9 0.0\n",
+ "GATE inv2 2 O=!a; PIN * INV 2 999 1.0 0.0 1.0 0.0\n",
+ "GATE inv3 3 O=!a; PIN * INV 3 999 1.1 0.0 1.1 0.0\n",
+ "GATE inv4 4 O=!a; PIN * INV 4 999 1.2 0.0 1.2 0.0\n",
+ "GATE nand2 2 O=!(a*b); PIN * INV 1 999 1.0 0.0 1.0 0.0\n",
+ "GATE nand3 3 O=!(a*b*c); PIN * INV 1 999 1.1 0.0 1.1 0.0\n",
+ "GATE nand4 4 O=!(a*b*c*d); PIN * INV 1 999 1.4 0.0 1.4 0.0\n",
+ "GATE nor2 2 O=!(a+b); PIN * INV 1 999 1.4 0.0 1.4 0.0\n",
+ "GATE nor3 3 O=!(a+b+c); PIN * INV 1 999 2.4 0.0 2.4 0.0\n",
+ "GATE nor4 4 O=!(a+b+c+d); PIN * INV 1 999 3.8 0.0 3.8 0.0\n",
+ "GATE xora 5 O=a*!b+!a*b; PIN * UNKNOWN 2 999 1.9 0.0 1.9 0.0\n",
+ "GATE xorb 5 O=!(a*b+!a*!b); PIN * UNKNOWN 2 999 1.9 0.0 1.9 0.0\n",
+ "GATE xnora 5 O=a*b+!a*!b; PIN * UNKNOWN 2 999 2.1 0.0 2.1 0.0\n",
+ "GATE xnorb 5 O=!(!a*b+a*!b); PIN * UNKNOWN 2 999 2.1 0.0 2.1 0.0\n",
+ "GATE aoi21 3 O=!(a*b+c); PIN * INV 1 999 1.6 0.0 1.6 0.0\n",
+ "GATE aoi22 4 O=!(a*b+c*d); PIN * INV 1 999 2.0 0.0 2.0 0.0\n",
+ "GATE oai21 3 O=!((a+b)*c); PIN * INV 1 999 1.6 0.0 1.6 0.0\n",
+ "GATE oai22 4 O=!((a+b)*(c+d)); PIN * INV 1 999 2.0 0.0 2.0 0.0\n",
+ "GATE buf 1 O=a; PIN * NONINV 1 999 1.0 0.0 1.0 0.0\n",
+ "GATE zero 0 O=CONST0;\n",
+ "GATE one 0 O=CONST1;\n"
+};
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mio_Init( Abc_Frame_t * pAbc )
+{
+ char * pFileTemp = "mcnc_temp.genlib";
+ Mio_Library_t * pLibGen;
+ FILE * pFile;
+ int i;
+
+ // write genlib into file
+ pFile = fopen( pFileTemp, "w" );
+ for ( i = 0; pMcncGenlib[i]; i++ )
+ fputs( pMcncGenlib[i], pFile );
+ fclose( pFile );
+ // read genlib from file
+ pLibGen = Mio_LibraryRead( pAbc, pFileTemp, NULL, 0 );
+ Abc_FrameSetLibGen( pAbc, pLibGen );
+#ifdef WIN32
+ _unlink( pFileTemp );
+#else
+ unlink( pFileTemp );
+#endif
+
+ Cmd_CommandAdd( pAbc, "SC mapping", "read_library", Mio_CommandReadLibrary, 0 );
+ Cmd_CommandAdd( pAbc, "SC mapping", "print_library", Mio_CommandPrintLibrary, 0 );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mio_End()
+{
+// Mio_LibraryDelete( s_pLib );
+ Mio_LibraryDelete( Abc_FrameReadLibGen(Abc_FrameGetGlobalFrame()) );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mio_CommandReadLibrary( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ FILE * pFile;
+ FILE * pOut, * pErr;
+ Mio_Library_t * pLib;
+ Abc_Ntk_t * pNet;
+ char * FileName;
+ int fVerbose;
+ int c;
+
+ pNet = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set the defaults
+ fVerbose = 1;
+ util_getopt_reset();
+ while ( (c = util_getopt(argc, argv, "vh")) != EOF )
+ {
+ switch (c)
+ {
+ case 'v':
+ fVerbose ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ break;
+ default:
+ goto usage;
+ }
+ }
+
+
+ if ( argc != util_optind + 1 )
+ {
+ goto usage;
+ }
+
+ // get the input file name
+ FileName = argv[util_optind];
+ if ( (pFile = fopen( FileName, "r" )) == NULL )
+ {
+ fprintf( pErr, "Cannot open input file \"%s\". ", FileName );
+ if ( (FileName = Extra_FileGetSimilarName( FileName, ".genlib", ".lib", ".gen", ".g", NULL )) )
+ fprintf( pErr, "Did you mean \"%s\"?", FileName );
+ fprintf( pErr, "\n" );
+ return 1;
+ }
+ fclose( pFile );
+
+ // set the new network
+ pLib = Mio_LibraryRead( pAbc, FileName, 0, fVerbose );
+ if ( pLib == NULL )
+ {
+ fprintf( pErr, "Reading GENLIB library has failed.\n" );
+ return 1;
+ }
+ // free the current superlib because it depends on the old Mio library
+ if ( Abc_FrameReadLibSuper(Abc_FrameGetGlobalFrame()) )
+ {
+ extern void Map_SuperLibFree( Map_SuperLib_t * p );
+// Map_SuperLibFree( s_pSuperLib );
+// s_pSuperLib = NULL;
+ Map_SuperLibFree( Abc_FrameReadLibSuper(Abc_FrameGetGlobalFrame()) );
+ Abc_FrameSetLibSuper(Abc_FrameGetGlobalFrame(), NULL);
+ }
+
+ // replace the current library
+// Mio_LibraryDelete( s_pLib );
+// s_pLib = pLib;
+ Mio_LibraryDelete( Abc_FrameReadLibGen(Abc_FrameGetGlobalFrame()) );
+ Abc_FrameSetLibGen( Abc_FrameGetGlobalFrame(), pLib );
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: read_library [-vh]\n");
+ fprintf( pErr, "\t read the library from a genlib file\n" );
+ fprintf( pErr, "\t-h : enable verbose output\n");
+ return 1; /* error exit */
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Command procedure to read LUT libraries.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mio_CommandPrintLibrary( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ FILE * pOut, * pErr;
+ Abc_Ntk_t * pNet;
+ int fVerbose;
+ int c;
+
+ pNet = Abc_FrameReadNet(pAbc);
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set the defaults
+ fVerbose = 1;
+ util_getopt_reset();
+ while ( (c = util_getopt(argc, argv, "vh")) != EOF )
+ {
+ switch (c)
+ {
+ case 'v':
+ fVerbose ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ break;
+ default:
+ goto usage;
+ }
+ }
+
+
+ if ( argc != util_optind )
+ {
+ goto usage;
+ }
+
+ // set the new network
+ Mio_WriteLibrary( stdout, Abc_FrameReadLibGen(Abc_FrameGetGlobalFrame()), 0 );
+ return 0;
+
+usage:
+ fprintf( pErr, "\nusage: print_library [-vh]\n");
+ fprintf( pErr, "\t print the current genlib library\n" );
+ fprintf( pErr, "\t-v : toggles enabling of verbose output [default = %s]\n", (fVerbose? "yes" : "no") );
+ fprintf( pErr, "\t-h : print the command usage\n");
+ return 1; /* error exit */
+}
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/mio/mio.h b/src/map/mio/mio.h
new file mode 100644
index 00000000..3347bba8
--- /dev/null
+++ b/src/map/mio/mio.h
@@ -0,0 +1,136 @@
+/**CFile****************************************************************
+
+ FileName [mio.h]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [File reading/writing for technology mapping.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - September 8, 2003.]
+
+ Revision [$Id: mio.h,v 1.6 2004/08/09 22:16:31 satrajit Exp $]
+
+***********************************************************************/
+
+#ifndef __MIO_H__
+#define __MIO_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+typedef enum { MIO_PHASE_UNKNOWN, MIO_PHASE_INV, MIO_PHASE_NONINV } Mio_PinPhase_t;
+
+typedef struct Mio_LibraryStruct_t_ Mio_Library_t;
+typedef struct Mio_GateStruct_t_ Mio_Gate_t;
+typedef struct Mio_PinStruct_t_ Mio_Pin_t;
+
+////////////////////////////////////////////////////////////////////////
+/// GLOBAL VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+#define Mio_LibraryForEachGate( Lib, Gate ) \
+ for ( Gate = Mio_LibraryReadGates(Lib); \
+ Gate; \
+ Gate = Mio_GateReadNext(Gate) )
+#define Mio_LibraryForEachGateSafe( Lib, Gate, Gate2 ) \
+ for ( Gate = Mio_LibraryReadGates(Lib), \
+ Gate2 = (Gate? Mio_GateReadNext(Gate): NULL); \
+ Gate; \
+ Gate = Gate2, \
+ Gate2 = (Gate? Mio_GateReadNext(Gate): NULL) )
+
+#define Mio_GateForEachPin( Gate, Pin ) \
+ for ( Pin = Mio_GateReadPins(Gate); \
+ Pin; \
+ Pin = Mio_PinReadNext(Pin) )
+#define Mio_GateForEachPinSafe( Gate, Pin, Pin2 ) \
+ for ( Pin = Mio_GateReadPins(Gate), \
+ Pin2 = (Pin? Mio_PinReadNext(Pin): NULL); \
+ Pin; \
+ Pin = Pin2, \
+ Pin2 = (Pin? Mio_PinReadNext(Pin): NULL) )
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== mioApi.c =============================================================*/
+extern char * Mio_LibraryReadName ( Mio_Library_t * pLib );
+extern int Mio_LibraryReadGateNum ( Mio_Library_t * pLib );
+extern Mio_Gate_t * Mio_LibraryReadGates ( Mio_Library_t * pLib );
+extern DdManager * Mio_LibraryReadDd ( Mio_Library_t * pLib );
+extern Mio_Gate_t * Mio_LibraryReadGateByName ( Mio_Library_t * pLib, char * pName );
+extern char * Mio_LibraryReadSopByName ( Mio_Library_t * pLib, char * pName );
+extern Mio_Gate_t * Mio_LibraryReadConst0 ( Mio_Library_t * pLib );
+extern Mio_Gate_t * Mio_LibraryReadConst1 ( Mio_Library_t * pLib );
+extern Mio_Gate_t * Mio_LibraryReadNand2 ( Mio_Library_t * pLib );
+extern Mio_Gate_t * Mio_LibraryReadBuf ( Mio_Library_t * pLib );
+extern Mio_Gate_t * Mio_LibraryReadInv ( Mio_Library_t * pLib );
+extern float Mio_LibraryReadDelayInvRise( Mio_Library_t * pLib );
+extern float Mio_LibraryReadDelayInvFall( Mio_Library_t * pLib );
+extern float Mio_LibraryReadDelayInvMax( Mio_Library_t * pLib );
+extern float Mio_LibraryReadDelayNand2Rise( Mio_Library_t * pLib );
+extern float Mio_LibraryReadDelayNand2Fall( Mio_Library_t * pLib );
+extern float Mio_LibraryReadDelayNand2Max( Mio_Library_t * pLib );
+extern float Mio_LibraryReadAreaInv ( Mio_Library_t * pLib );
+extern float Mio_LibraryReadAreaNand2 ( Mio_Library_t * pLib );
+extern char * Mio_GateReadName ( Mio_Gate_t * pGate );
+extern char * Mio_GateReadOutName ( Mio_Gate_t * pGate );
+extern double Mio_GateReadArea ( Mio_Gate_t * pGate );
+extern char * Mio_GateReadForm ( Mio_Gate_t * pGate );
+extern Mio_Pin_t * Mio_GateReadPins ( Mio_Gate_t * pGate );
+extern Mio_Library_t * Mio_GateReadLib ( Mio_Gate_t * pGate );
+extern Mio_Gate_t * Mio_GateReadNext ( Mio_Gate_t * pGate );
+extern int Mio_GateReadInputs ( Mio_Gate_t * pGate );
+extern double Mio_GateReadDelayMax ( Mio_Gate_t * pGate );
+extern char * Mio_GateReadSop ( Mio_Gate_t * pGate );
+extern DdNode * Mio_GateReadFunc ( Mio_Gate_t * pGate );
+extern char * Mio_PinReadName ( Mio_Pin_t * pPin );
+extern Mio_PinPhase_t Mio_PinReadPhase ( Mio_Pin_t * pPin );
+extern double Mio_PinReadInputLoad ( Mio_Pin_t * pPin );
+extern double Mio_PinReadMaxLoad ( Mio_Pin_t * pPin );
+extern double Mio_PinReadDelayBlockRise ( Mio_Pin_t * pPin );
+extern double Mio_PinReadDelayFanoutRise( Mio_Pin_t * pPin );
+extern double Mio_PinReadDelayBlockFall ( Mio_Pin_t * pPin );
+extern double Mio_PinReadDelayFanoutFall( Mio_Pin_t * pPin );
+extern double Mio_PinReadDelayBlockMax ( Mio_Pin_t * pPin );
+extern Mio_Pin_t * Mio_PinReadNext ( Mio_Pin_t * pPin );
+/*=== mioRead.c =============================================================*/
+extern Mio_Library_t * Mio_LibraryRead( Abc_Frame_t * pAbc, char * FileName, char * ExcludeFile, int fVerbose );
+extern int Mio_LibraryReadExclude( Abc_Frame_t * pAbc, char * ExcludeFile, st_table * tExcludeGate );
+/*=== mioFunc.c =============================================================*/
+extern int Mio_LibraryParseFormulas( Mio_Library_t * pLib );
+/*=== mioUtils.c =============================================================*/
+extern void Mio_LibraryDelete( Mio_Library_t * pLib );
+extern void Mio_GateDelete( Mio_Gate_t * pGate );
+extern void Mio_PinDelete( Mio_Pin_t * pPin );
+extern Mio_Pin_t * Mio_PinDup( Mio_Pin_t * pPin );
+extern void Mio_WriteLibrary( FILE * pFile, Mio_Library_t * pLib, int fPrintSops );
+extern Mio_Gate_t ** Mio_CollectRoots( Mio_Library_t * pLib, int nInputs, float tDelay, bool fSkipInv, int * pnGates );
+extern void Mio_DeriveTruthTable( Mio_Gate_t * pGate, unsigned uTruthsIn[][2], int nSigns, int nInputs, unsigned uTruthRes[] );
+extern void Mio_DeriveGateDelays( Mio_Gate_t * pGate,
+ float ** ptPinDelays, int nPins, int nInputs, float tDelayZero,
+ float * ptDelaysRes, float * ptPinDelayMax );
+extern Mio_Gate_t * Mio_GateCreatePseudo( int nInputs );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+#endif
diff --git a/src/map/mio/mioApi.c b/src/map/mio/mioApi.c
new file mode 100644
index 00000000..50d60fe9
--- /dev/null
+++ b/src/map/mio/mioApi.c
@@ -0,0 +1,145 @@
+/**CFile****************************************************************
+
+ FileName [mioApi.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [File reading/writing for technology mapping.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - September 8, 2003.]
+
+ Revision [$Id: mioApi.c,v 1.4 2004/06/28 14:20:25 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mioInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Mio_LibraryReadName ( Mio_Library_t * pLib ) { return pLib->pName; }
+int Mio_LibraryReadGateNum ( Mio_Library_t * pLib ) { return pLib->nGates; }
+Mio_Gate_t * Mio_LibraryReadGates ( Mio_Library_t * pLib ) { return pLib->pGates; }
+DdManager * Mio_LibraryReadDd ( Mio_Library_t * pLib ) { return pLib->dd; }
+Mio_Gate_t * Mio_LibraryReadBuf ( Mio_Library_t * pLib ) { return pLib->pGateBuf; }
+Mio_Gate_t * Mio_LibraryReadInv ( Mio_Library_t * pLib ) { return pLib->pGateInv; }
+Mio_Gate_t * Mio_LibraryReadConst0 ( Mio_Library_t * pLib ) { return pLib->pGate0; }
+Mio_Gate_t * Mio_LibraryReadConst1 ( Mio_Library_t * pLib ) { return pLib->pGate1; }
+Mio_Gate_t * Mio_LibraryReadNand2 ( Mio_Library_t * pLib ) { return pLib->pGateNand2; }
+float Mio_LibraryReadDelayInvRise ( Mio_Library_t * pLib ) { return (float)pLib->pGateInv->pPins->dDelayBlockRise; }
+float Mio_LibraryReadDelayInvFall ( Mio_Library_t * pLib ) { return (float)pLib->pGateInv->pPins->dDelayBlockFall; }
+float Mio_LibraryReadDelayInvMax ( Mio_Library_t * pLib ) { return (float)pLib->pGateInv->pPins->dDelayBlockMax; }
+float Mio_LibraryReadDelayNand2Rise( Mio_Library_t * pLib ) { return (float)pLib->pGateNand2->pPins->dDelayBlockRise; }
+float Mio_LibraryReadDelayNand2Fall( Mio_Library_t * pLib ) { return (float)pLib->pGateNand2->pPins->dDelayBlockFall; }
+float Mio_LibraryReadDelayNand2Max ( Mio_Library_t * pLib ) { return (float)pLib->pGateNand2->pPins->dDelayBlockMax; }
+float Mio_LibraryReadAreaInv ( Mio_Library_t * pLib ) { return (float)pLib->pGateInv->dArea; }
+float Mio_LibraryReadAreaNand2 ( Mio_Library_t * pLib ) { return (float)pLib->pGateNand2->dArea; }
+
+/**Function*************************************************************
+
+ Synopsis [Read Mvc of the gate by name.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mio_Gate_t * Mio_LibraryReadGateByName( Mio_Library_t * pLib, char * pName )
+{
+ Mio_Gate_t * pGate;
+ if ( st_lookup( pLib->tName2Gate, pName, (char **)&pGate ) )
+ return pGate;
+ return NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Read Mvc of the gate by name.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Mio_LibraryReadSopByName( Mio_Library_t * pLib, char * pName )
+{
+ Mio_Gate_t * pGate;
+ if ( st_lookup( pLib->tName2Gate, pName, (char **)&pGate ) )
+ return pGate->pSop;
+ return NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Mio_GateReadName ( Mio_Gate_t * pGate ) { return pGate->pName; }
+char * Mio_GateReadOutName ( Mio_Gate_t * pGate ) { return pGate->pOutName; }
+double Mio_GateReadArea ( Mio_Gate_t * pGate ) { return pGate->dArea; }
+char * Mio_GateReadForm ( Mio_Gate_t * pGate ) { return pGate->pForm; }
+Mio_Pin_t * Mio_GateReadPins ( Mio_Gate_t * pGate ) { return pGate->pPins; }
+Mio_Library_t * Mio_GateReadLib ( Mio_Gate_t * pGate ) { return pGate->pLib; }
+Mio_Gate_t * Mio_GateReadNext ( Mio_Gate_t * pGate ) { return pGate->pNext; }
+int Mio_GateReadInputs ( Mio_Gate_t * pGate ) { return pGate->nInputs; }
+double Mio_GateReadDelayMax( Mio_Gate_t * pGate ) { return pGate->dDelayMax; }
+char * Mio_GateReadSop ( Mio_Gate_t * pGate ) { return pGate->pSop; }
+DdNode * Mio_GateReadFunc ( Mio_Gate_t * pGate ) { return pGate->bFunc; }
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Mio_PinReadName ( Mio_Pin_t * pPin ) { return pPin->pName; }
+Mio_PinPhase_t Mio_PinReadPhase ( Mio_Pin_t * pPin ) { return pPin->Phase; }
+double Mio_PinReadInputLoad ( Mio_Pin_t * pPin ) { return pPin->dLoadInput; }
+double Mio_PinReadMaxLoad ( Mio_Pin_t * pPin ) { return pPin->dLoadMax; }
+double Mio_PinReadDelayBlockRise ( Mio_Pin_t * pPin ) { return pPin->dDelayBlockRise; }
+double Mio_PinReadDelayFanoutRise( Mio_Pin_t * pPin ) { return pPin->dDelayFanoutRise;}
+double Mio_PinReadDelayBlockFall ( Mio_Pin_t * pPin ) { return pPin->dDelayBlockFall; }
+double Mio_PinReadDelayFanoutFall( Mio_Pin_t * pPin ) { return pPin->dDelayFanoutFall;}
+double Mio_PinReadDelayBlockMax ( Mio_Pin_t * pPin ) { return pPin->dDelayBlockMax; }
+Mio_Pin_t * Mio_PinReadNext ( Mio_Pin_t * pPin ) { return pPin->pNext; }
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/mio/mioFunc.c b/src/map/mio/mioFunc.c
new file mode 100644
index 00000000..88a7c89c
--- /dev/null
+++ b/src/map/mio/mioFunc.c
@@ -0,0 +1,268 @@
+/**CFile****************************************************************
+
+ FileName [mioFunc.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [File reading/writing for technology mapping.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - September 8, 2003.]
+
+ Revision [$Id: mioFunc.c,v 1.4 2004/06/28 14:20:25 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mioInt.h"
+#include "parse.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// these symbols (and no other) can appear in the formulas
+#define MIO_SYMB_AND '*'
+#define MIO_SYMB_OR '+'
+#define MIO_SYMB_NOT '!'
+#define MIO_SYMB_AFTNOT '\''
+#define MIO_SYMB_OPEN '('
+#define MIO_SYMB_CLOSE ')'
+
+static int Mio_GateParseFormula( Mio_Gate_t * pGate );
+static int Mio_GateCollectNames( char * pFormula, char * pPinNames[] );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Deriving the functionality of the gates.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mio_LibraryParseFormulas( Mio_Library_t * pLib )
+{
+ Mio_Gate_t * pGate;
+
+ // count the gates
+ pLib->nGates = 0;
+ Mio_LibraryForEachGate( pLib, pGate )
+ pLib->nGates++;
+
+ // start a temporary BDD manager
+ pLib->dd = Cudd_Init( 20, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 );
+ // introduce ZDD variables
+ Cudd_zddVarsFromBddVars( pLib->dd, 2 );
+
+ // for each gate, derive its function
+ Mio_LibraryForEachGate( pLib, pGate )
+ if ( Mio_GateParseFormula( pGate ) )
+ return 1;
+ return 0;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Deriving the functionality of the gates.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mio_GateParseFormula( Mio_Gate_t * pGate )
+{
+ DdManager * dd = pGate->pLib->dd;
+ char * pPinNames[100];
+ char * pPinNamesCopy[100];
+ Mio_Pin_t * pPin, ** ppPin;
+ int nPins, iPin, i;
+
+ // set the maximum delay of the gate; count pins
+ pGate->dDelayMax = 0.0;
+ nPins = 0;
+ Mio_GateForEachPin( pGate, pPin )
+ {
+ // set the maximum delay of the gate
+ if ( pGate->dDelayMax < pPin->dDelayBlockMax )
+ pGate->dDelayMax = pPin->dDelayBlockMax;
+ // count the pin
+ nPins++;
+ }
+
+ // check for the gate with const function
+ if ( nPins == 0 )
+ {
+ if ( strcmp( pGate->pForm, MIO_STRING_CONST0 ) == 0 )
+ {
+ pGate->bFunc = b0;
+ pGate->pSop = Abc_SopRegister( pGate->pLib->pMmFlex, " 0\n" );
+ pGate->pLib->pGate0 = pGate;
+ }
+ else if ( strcmp( pGate->pForm, MIO_STRING_CONST1 ) == 0 )
+ {
+ pGate->bFunc = b1;
+ pGate->pSop = Abc_SopRegister( pGate->pLib->pMmFlex, " 1\n" );
+ pGate->pLib->pGate1 = pGate;
+ }
+ else
+ {
+ printf( "Cannot parse formula \"%s\" of gate \"%s\".\n", pGate->pForm, pGate->pName );
+ return 1;
+ }
+ Cudd_Ref( pGate->bFunc );
+ return 0;
+ }
+
+ // collect the names as they appear in the formula
+ nPins = Mio_GateCollectNames( pGate->pForm, pPinNames );
+ if ( nPins == 0 )
+ {
+ printf( "Cannot read formula \"%s\" of gate \"%s\".\n", pGate->pForm, pGate->pName );
+ return 1;
+ }
+
+ // set the number of inputs
+ pGate->nInputs = nPins;
+
+ // consider the case when all the pins have identical pin info
+ if ( strcmp( pGate->pPins->pName, "*" ) == 0 )
+ {
+ // get the topmost (generic) pin
+ pPin = pGate->pPins;
+ FREE( pPin->pName );
+
+ // create individual pins from the generic pin
+ ppPin = &pPin->pNext;
+ for ( i = 1; i < nPins; i++ )
+ {
+ // get the new pin
+ *ppPin = Mio_PinDup( pPin );
+ // set its name
+ (*ppPin)->pName = pPinNames[i];
+ // prepare the next place in the list
+ ppPin = &((*ppPin)->pNext);
+ }
+ *ppPin = NULL;
+
+ // set the name of the topmost pin
+ pPin->pName = pPinNames[0];
+ }
+ else
+ {
+ // reorder the variable names to appear the save way as the pins
+ iPin = 0;
+ Mio_GateForEachPin( pGate, pPin )
+ {
+ // find the pin with the name pPin->pName
+ for ( i = 0; i < nPins; i++ )
+ {
+ if ( pPinNames[i] && strcmp( pPinNames[i], pPin->pName ) == 0 )
+ {
+ // free pPinNames[i] because it is already available as pPin->pName
+ // setting pPinNames[i] to NULL is useful to make sure that
+ // this name is not assigned to two pins in the list
+ FREE( pPinNames[i] );
+ pPinNamesCopy[iPin++] = pPin->pName;
+ break;
+ }
+ if ( i == nPins )
+ {
+ printf( "Cannot find pin name \"%s\" in the formula \"%s\" of gate \"%s\".\n",
+ pPin->pName, pGate->pForm, pGate->pName );
+ return 1;
+ }
+ }
+ }
+
+ // check for the remaining names
+ for ( i = 0; i < nPins; i++ )
+ if ( pPinNames[i] )
+ {
+ printf( "Name \"%s\" appears in the formula \"%s\" of gate \"%s\" but there is no such pin.\n",
+ pPinNames[i], pGate->pForm, pGate->pName );
+ return 1;
+ }
+
+ // copy the names back
+ memcpy( pPinNames, pPinNamesCopy, nPins * sizeof(char *) );
+ }
+
+ // expand the manager if necessary
+ if ( dd->size < nPins )
+ {
+ Cudd_Quit( dd );
+ dd = Cudd_Init( nPins + 10, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 );
+ Cudd_zddVarsFromBddVars( dd, 2 );
+ }
+
+ // derive the formula as the BDD
+ pGate->bFunc = Parse_FormulaParser( stdout, pGate->pForm, nPins, 0, pPinNames, dd, dd->vars );
+ Cudd_Ref( pGate->bFunc );
+
+ // derive the cover (SOP)
+ pGate->pSop = Abc_ConvertBddToSop( pGate->pLib->pMmFlex, dd, pGate->bFunc, nPins, pGate->pLib->vCube, -1 );
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collect the pin names in the formula.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mio_GateCollectNames( char * pFormula, char * pPinNames[] )
+{
+ char Buffer[1000];
+ char * pTemp;
+ int nPins, i;
+
+ // save the formula as it was
+ strcpy( Buffer, pFormula );
+
+ // remove the non-name symbols
+ for ( pTemp = Buffer; *pTemp; pTemp++ )
+ if ( *pTemp == MIO_SYMB_AND || *pTemp == MIO_SYMB_OR || *pTemp == MIO_SYMB_NOT
+ || *pTemp == MIO_SYMB_OPEN || *pTemp == MIO_SYMB_CLOSE || *pTemp == MIO_SYMB_AFTNOT )
+ *pTemp = ' ';
+
+ // save the names
+ nPins = 0;
+ pTemp = strtok( Buffer, " " );
+ while ( pTemp )
+ {
+ for ( i = 0; i < nPins; i++ )
+ if ( strcmp( pTemp, pPinNames[i] ) == 0 )
+ break;
+ if ( i == nPins )
+ { // cannot find this name; save it
+ pPinNames[nPins++] = util_strsav(pTemp);
+ }
+ // get the next name
+ pTemp = strtok( NULL, " " );
+ }
+ return nPins;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/mio/mioGENERIC.c b/src/map/mio/mioGENERIC.c
new file mode 100644
index 00000000..6a40bc52
--- /dev/null
+++ b/src/map/mio/mioGENERIC.c
@@ -0,0 +1,46 @@
+/**CFile****************************************************************
+
+ FileName [mio___.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [File reading/writing for technology mapping.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - September 8, 2003.]
+
+ Revision [$Id: mio___.h,v 1.0 2003/09/08 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mioInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/mio/mioInt.h b/src/map/mio/mioInt.h
new file mode 100644
index 00000000..105e3d8d
--- /dev/null
+++ b/src/map/mio/mioInt.h
@@ -0,0 +1,124 @@
+/**CFile****************************************************************
+
+ FileName [mioInt.h]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [File reading/writing for technology mapping.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - September 8, 2003.]
+
+ Revision [$Id: mioInt.h,v 1.4 2004/06/28 14:20:25 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __MIO_INT_H__
+#define __MIO_INT_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+#include "abc.h"
+#include "mvc.h"
+#include "main.h"
+#include "mio.h"
+#include "extra.h"
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+#define MIO_STRING_GATE "GATE"
+#define MIO_STRING_PIN "PIN"
+#define MIO_STRING_NONINV "NONINV"
+#define MIO_STRING_INV "INV"
+#define MIO_STRING_UNKNOWN "UNKNOWN"
+
+#define MIO_STRING_CONST0 "CONST0"
+#define MIO_STRING_CONST1 "CONST1"
+
+// the bit masks
+#define MIO_MASK(n) ((~((unsigned)0)) >> (32-(n)))
+#define MIO_FULL (~((unsigned)0))
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+struct Mio_LibraryStruct_t_
+{
+ char * pName; // the name of the library
+ int nGates; // the number of the gates
+ Mio_Gate_t * pGates; // the linked list of all gates in no particular order
+ Mio_Gate_t * pGate0; // the constant zero gate
+ Mio_Gate_t * pGate1; // the constant one gate
+ Mio_Gate_t * pGateBuf; // the buffer
+ Mio_Gate_t * pGateInv; // the inverter
+ Mio_Gate_t * pGateNand2; // the NAND2 gate
+ st_table * tName2Gate; // the mapping of gate names into their pointer
+ DdManager * dd; // the nanager storing functions of gates
+ Extra_MmFlex_t * pMmFlex; // the memory manaqer for SOPs
+ Vec_Str_t * vCube; // temporary cube
+};
+
+struct Mio_GateStruct_t_
+{
+ // information derived from the genlib file
+ char * pName; // the name of the gate
+ double dArea; // the area of the gate
+ char * pForm; // the formula describing functionality of the gate
+ Mio_Pin_t * pPins; // the linked list of all pins (one pin if info is the same)
+ char * pOutName; // the name of the output pin
+ // the library to which this gate belongs
+ Mio_Library_t * pLib;
+ // the next gate in the list
+ Mio_Gate_t * pNext;
+
+ // the derived information
+ int nInputs; // the number of inputs
+ double dDelayMax; // the maximum delay
+ DdNode * bFunc; // the functionality
+ char * pSop;
+};
+
+struct Mio_PinStruct_t_
+{
+ char * pName;
+ Mio_PinPhase_t Phase;
+ double dLoadInput;
+ double dLoadMax;
+ double dDelayBlockRise;
+ double dDelayFanoutRise;
+ double dDelayBlockFall;
+ double dDelayFanoutFall;
+ double dDelayBlockMax;
+ Mio_Pin_t * pNext;
+};
+
+
+////////////////////////////////////////////////////////////////////////
+/// GLOBAL VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== mio.c =============================================================*/
+/*=== mioRead.c =============================================================*/
+/*=== mioUtils.c =============================================================*/
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
diff --git a/src/map/mio/mioRead.c b/src/map/mio/mioRead.c
new file mode 100644
index 00000000..098cdb50
--- /dev/null
+++ b/src/map/mio/mioRead.c
@@ -0,0 +1,572 @@
+/**CFile****************************************************************
+
+ FileName [mioRead.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [File reading/writing for technology mapping.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - September 8, 2003.]
+
+ Revision [$Id: mioRead.c,v 1.9 2004/10/19 06:40:16 satrajit Exp $]
+
+***********************************************************************/
+
+#include "mioInt.h"
+#include "ioInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static Mio_Library_t * Mio_LibraryReadOne( Abc_Frame_t * pAbc, char * FileName, bool fExtendedFormat, st_table * tExcludeGate, int fVerbose );
+static int Mio_LibraryReadInternal( Mio_Library_t * pLib, char * pBuffer, bool fExtendedFormat, st_table * tExcludeGate, int fVerbose );
+static Mio_Gate_t * Mio_LibraryReadGate( char ** ppToken, bool fExtendedFormat );
+static Mio_Pin_t * Mio_LibraryReadPin( char ** ppToken, bool fExtendedFormat );
+static char * chomp( char *s );
+static void Mio_LibraryDetectSpecialGates( Mio_Library_t * pLib );
+static void Io_ReadFileRemoveComments( char * pBuffer, int * pnDots, int * pnLines );
+
+#ifdef WIN32
+extern int isspace( int c ); // to silence the warning in VS
+#endif
+
+/**Function*************************************************************
+
+ Synopsis [Read the genlib type of library.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mio_Library_t * Mio_LibraryRead( Abc_Frame_t * pAbc, char * FileName, char * ExcludeFile, int fVerbose )
+{
+ Mio_Library_t * pLib;
+ int num;
+
+ st_table * tExcludeGate = 0;
+
+ if ( ExcludeFile )
+ {
+ tExcludeGate = st_init_table(strcmp, st_strhash);
+ if ( (num = Mio_LibraryReadExclude( pAbc, ExcludeFile, tExcludeGate )) == -1 )
+ {
+ st_free_table( tExcludeGate );
+ tExcludeGate = 0;
+ return 0;
+ }
+
+ fprintf ( Abc_FrameReadOut( pAbc ), "Read %d gates from exclude file\n", num );
+ }
+
+ pLib = Mio_LibraryReadOne( pAbc, FileName, 0, tExcludeGate, fVerbose ); // try normal format first ..
+ if ( pLib == NULL )
+ {
+ pLib = Mio_LibraryReadOne( pAbc, FileName, 1, tExcludeGate, fVerbose ); // .. otherwise try extended format
+ if ( pLib != NULL )
+ printf ( "Warning: Read extended GENLIB format but ignoring extensions\n" );
+ }
+
+ return pLib;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Read the genlib type of library.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mio_Library_t * Mio_LibraryReadOne( Abc_Frame_t * pAbc, char * FileName, bool fExtendedFormat, st_table * tExcludeGate, int fVerbose )
+{
+ Mio_Library_t * pLib;
+ char * pBuffer = 0;
+
+ // allocate the genlib structure
+ pLib = ALLOC( Mio_Library_t, 1 );
+ memset( pLib, 0, sizeof(Mio_Library_t) );
+ pLib->pName = util_strsav( FileName );
+ pLib->tName2Gate = st_init_table(strcmp, st_strhash);
+ pLib->pMmFlex = Extra_MmFlexStart();
+ pLib->vCube = Vec_StrAlloc( 100 );
+
+ // read the file and clean comments
+ // pBuffer = Io_ReadFileFileContents( FileName, NULL );
+ // we don't use above function but actually do the same thing explicitly
+ // to handle open_path expansion correctly
+
+ {
+ FILE * pFile;
+ int nFileSize;
+
+ // open the BLIF file for binary reading
+// pFile = Io_FileOpen( FileName, "open_path", "rb" );
+ pFile = fopen( FileName, "rb" );
+ // if we got this far, file should be okay otherwise would
+ // have been detected by caller
+ assert ( pFile != NULL );
+ // get the file size, in bytes
+ fseek( pFile, 0, SEEK_END );
+ nFileSize = ftell( pFile );
+ // move the file current reading position to the beginning
+ rewind( pFile );
+ // load the contents of the file into memory
+ pBuffer = ALLOC( char, nFileSize + 10 );
+ fread( pBuffer, nFileSize, 1, pFile );
+ // terminate the string with '\0'
+ pBuffer[ nFileSize ] = '\0';
+ strcat( pBuffer, "\n.end\n" );
+ // close file
+ fclose( pFile );
+ }
+
+ Io_ReadFileRemoveComments( pBuffer, NULL, NULL );
+
+ // parse the contents of the file
+ if ( Mio_LibraryReadInternal( pLib, pBuffer, fExtendedFormat, tExcludeGate, fVerbose ) )
+ {
+ Mio_LibraryDelete( pLib );
+ free( pBuffer );
+ return NULL;
+ }
+ free( pBuffer );
+
+ // derive the functinality of gates
+ if ( Mio_LibraryParseFormulas( pLib ) )
+ {
+ printf( "Mio_LibraryRead: Had problems parsing formulas.\n" );
+ Mio_LibraryDelete( pLib );
+ return NULL;
+ }
+
+ // detect INV and NAND2
+ Mio_LibraryDetectSpecialGates( pLib );
+//Mio_WriteLibrary( stdout, pLib );
+ return pLib;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Read the genlib type of library.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mio_LibraryReadInternal( Mio_Library_t * pLib, char * pBuffer, bool fExtendedFormat, st_table * tExcludeGate, int fVerbose )
+{
+ Mio_Gate_t * pGate, ** ppGate;
+ char * pToken;
+ int nGates = 0;
+ int nDel = 0;
+
+ // start the linked list of gates
+ pLib->pGates = NULL;
+ ppGate = &pLib->pGates;
+
+ // read gates one by one
+ pToken = strtok( pBuffer, " \t\r\n" );
+ while ( pToken && strcmp( pToken, MIO_STRING_GATE ) == 0 )
+ {
+ // derive the next gate
+ pGate = Mio_LibraryReadGate( &pToken, fExtendedFormat );
+ if ( pGate == NULL )
+ return 1;
+
+ // set the library
+ pGate->pLib = pLib;
+
+ // printf ("Processing: '%s'\n", pGate->pName);
+
+ if ( tExcludeGate && st_is_member( tExcludeGate, pGate->pName ) )
+ {
+ //printf ("Excluding: '%s'\n", pGate->pName);
+ Mio_GateDelete( pGate );
+ nDel++;
+ }
+ else
+ {
+ // add this gate to the list
+ *ppGate = pGate;
+ ppGate = &pGate->pNext;
+ nGates++;
+
+ // remember this gate by name
+ if ( !st_is_member( pLib->tName2Gate, pGate->pName ) )
+ st_insert( pLib->tName2Gate, pGate->pName, (char *)pGate );
+ else
+ printf( "The gate with name \"%s\" appears more than once.\n", pGate->pName );
+ }
+ }
+ if ( fVerbose )
+ printf( "The number of gates read = %d.\n", nGates );
+
+ // check what is the last word read
+ if ( pToken && strcmp( pToken, ".end" ) != 0 )
+ return 1;
+
+ if ( nDel != 0 )
+ printf( "Actually excluded %d cells\n", nDel );
+
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Read the genlib type of gate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mio_Gate_t * Mio_LibraryReadGate( char ** ppToken, bool fExtendedFormat )
+{
+ Mio_Gate_t * pGate;
+ Mio_Pin_t * pPin, ** ppPin;
+ char * pToken = *ppToken;
+
+ // allocate the gate structure
+ pGate = ALLOC( Mio_Gate_t, 1 );
+ memset( pGate, 0, sizeof(Mio_Gate_t) );
+
+ // read the name
+ pToken = strtok( NULL, " \t\r\n" );
+ pGate->pName = util_strsav( pToken );
+
+ // read the area
+ pToken = strtok( NULL, " \t\r\n" );
+ pGate->dArea = atof( pToken );
+
+ // read the formula
+
+ // first the output name
+ pToken = strtok( NULL, "=" );
+ pGate->pOutName = chomp( pToken );
+
+ // then rest of the expression
+ pToken = strtok( NULL, ";" );
+ pGate->pForm = util_strsav( pToken );
+
+ // read the pin info
+ // start the linked list of pins
+ pGate->pPins = NULL;
+ ppPin = &pGate->pPins;
+
+ // read gates one by one
+ pToken = strtok( NULL, " \t\r\n" );
+ while ( pToken && strcmp( pToken, MIO_STRING_PIN ) == 0 )
+ {
+ // derive the next gate
+ pPin = Mio_LibraryReadPin( &pToken, fExtendedFormat );
+ if ( pPin == NULL )
+ {
+ Mio_GateDelete( pGate );
+ *ppToken = pToken;
+ return NULL;
+ }
+ // add this pin to the list
+ *ppPin = pPin;
+ ppPin = &pPin->pNext;
+ // get the next token
+ pToken = strtok( NULL, " \t\r\n" );
+ }
+
+ *ppToken = pToken;
+ return pGate;
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Read the genlib type of pin.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mio_Pin_t * Mio_LibraryReadPin( char ** ppToken, bool fExtendedFormat )
+{
+ Mio_Pin_t * pPin;
+ char * pToken = *ppToken;
+
+ // allocate the gate structure
+ pPin = ALLOC( Mio_Pin_t, 1 );
+ memset( pPin, 0, sizeof(Mio_Pin_t) );
+
+ // read the name
+ pToken = strtok( NULL, " \t\r\n" );
+ pPin->pName = util_strsav( pToken );
+
+ // read the pin phase
+ pToken = strtok( NULL, " \t\r\n" );
+ if ( strcmp( pToken, MIO_STRING_UNKNOWN ) == 0 )
+ pPin->Phase = MIO_PHASE_UNKNOWN;
+ else if ( strcmp( pToken, MIO_STRING_INV ) == 0 )
+ pPin->Phase = MIO_PHASE_INV;
+ else if ( strcmp( pToken, MIO_STRING_NONINV ) == 0 )
+ pPin->Phase = MIO_PHASE_NONINV;
+ else
+ {
+ printf( "Cannot read pin phase specification\n" );
+ Mio_PinDelete( pPin );
+ *ppToken = pToken;
+ return NULL;
+ }
+
+ pToken = strtok( NULL, " \t\r\n" );
+ pPin->dLoadInput = atof( pToken );
+
+ pToken = strtok( NULL, " \t\r\n" );
+ pPin->dLoadMax = atof( pToken );
+
+ pToken = strtok( NULL, " \t\r\n" );
+ pPin->dDelayBlockRise = atof( pToken );
+
+ pToken = strtok( NULL, " \t\r\n" );
+ pPin->dDelayFanoutRise = atof( pToken );
+
+ pToken = strtok( NULL, " \t\r\n" );
+ pPin->dDelayBlockFall = atof( pToken );
+
+ pToken = strtok( NULL, " \t\r\n" );
+ pPin->dDelayFanoutFall = atof( pToken );
+
+ if ( fExtendedFormat )
+ {
+ /* In extended format, the field after dDelayFanoutRise
+ * is to be ignored
+ **/
+
+ pPin->dDelayBlockFall = pPin->dDelayFanoutFall;
+
+ pToken = strtok( NULL, " \t" );
+ pPin->dDelayFanoutFall = atof( pToken );
+
+ /* last field is ignored */
+ pToken = strtok( NULL, " \t\r\n" );
+ }
+
+ if ( pPin->dDelayBlockRise > pPin->dDelayBlockFall )
+ pPin->dDelayBlockMax = pPin->dDelayBlockRise;
+ else
+ pPin->dDelayBlockMax = pPin->dDelayBlockFall;
+
+ *ppToken = pToken;
+ return pPin;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Duplicates string and returns it with leading and
+ trailing spaces removed.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char *chomp( char *s )
+{
+ char *b = ALLOC(char, strlen(s)+1), *c = b;
+ while (*s && isspace(*s))
+ ++s;
+ while (*s && !isspace(*s))
+ *c++ = *s++;
+ *c = 0;
+ return b;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Duplicates string and returns it with leading and
+ trailing spaces removed.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mio_LibraryDetectSpecialGates( Mio_Library_t * pLib )
+{
+ Mio_Gate_t * pGate;
+ DdNode * bFuncBuf, * bFuncInv, * bFuncNand2;
+
+ bFuncBuf = pLib->dd->vars[0]; Cudd_Ref( bFuncBuf );
+ bFuncInv = Cudd_Not( pLib->dd->vars[0] ); Cudd_Ref( bFuncInv );
+ bFuncNand2 = Cudd_bddNand( pLib->dd, pLib->dd->vars[0], pLib->dd->vars[1] ); Cudd_Ref( bFuncNand2 );
+
+ Mio_LibraryForEachGate( pLib, pGate )
+ if ( pLib->pGateBuf == NULL && pGate->bFunc == bFuncBuf )
+ {
+ pLib->pGateBuf = pGate;
+ break;
+ }
+ if ( pLib->pGateBuf == NULL )
+ {
+ printf( "Warnings: GENLIB library reader cannot detect the buffer gate.\n" );
+ printf( "Some parts of the supergate-based technology mapper may not work correctly.\n" );
+ }
+
+ Mio_LibraryForEachGate( pLib, pGate )
+ if ( pLib->pGateInv == NULL && pGate->bFunc == bFuncInv )
+ {
+ pLib->pGateInv = pGate;
+ break;
+ }
+ if ( pLib->pGateInv == NULL )
+ {
+ printf( "Warnings: GENLIB library reader cannot detect the invertor gate.\n" );
+ printf( "Some parts of the supergate-based technology mapper may not work correctly.\n" );
+ }
+
+ Mio_LibraryForEachGate( pLib, pGate )
+ if ( pLib->pGateNand2 == NULL && pGate->bFunc == bFuncNand2 )
+ {
+ pLib->pGateNand2 = pGate;
+ break;
+ }
+ if ( pLib->pGateNand2 == NULL )
+ {
+ printf( "Warnings: GENLIB library reader cannot detect the NAND2 gate.\n" );
+ printf( "Some parts of the supergate-based technology mapper may not work correctly.\n" );
+ }
+
+ Cudd_RecursiveDeref( pLib->dd, bFuncInv );
+ Cudd_RecursiveDeref( pLib->dd, bFuncNand2 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [populate hash table of gates to be exlcuded from genlib]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mio_LibraryReadExclude( Abc_Frame_t * pAbc, char * ExcludeFile, st_table * tExcludeGate )
+{
+ int nDel = 0;
+ FILE *pEx;
+ char buffer[128];
+
+ assert ( tExcludeGate );
+
+ if ( ExcludeFile )
+ {
+ pEx = fopen( ExcludeFile, "r" );
+
+ if ( pEx == NULL )
+ {
+ fprintf ( Abc_FrameReadErr( pAbc ), "Error: Could not open exclude file %s. Stop.\n", ExcludeFile );
+ return -1;
+ }
+
+ while (1 == fscanf( pEx, "%127s", buffer ))
+ {
+ //printf ("Read: '%s'\n", buffer );
+ st_insert( tExcludeGate, util_strsav( buffer ), (char *)0 );
+ nDel++;
+ }
+
+ fclose( pEx );
+ }
+
+ return nDel;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Eliminates comments from the input file.]
+
+ Description [As a byproduct, this procedure also counts the number
+ lines and dot-statements in the input file. This also joins non-comment
+ lines that are joined with a backspace '\']
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Io_ReadFileRemoveComments( char * pBuffer, int * pnDots, int * pnLines )
+{
+ char * pCur;
+ int nDots, nLines;
+ // scan through the buffer and eliminate comments
+ // (in the BLIF file, comments are lines starting with "#")
+ nDots = nLines = 0;
+ for ( pCur = pBuffer; *pCur; pCur++ )
+ {
+ // if this is the beginning of comment
+ // clean it with spaces until the new line statement
+ if ( *pCur == '#' )
+ while ( *pCur != '\n' )
+ *pCur++ = ' ';
+
+ // count the number of new lines and dots
+ if ( *pCur == '\n' ) {
+ if (*(pCur-1)=='\r') {
+ // DOS(R) file support
+ if (*(pCur-2)!='\\') nLines++;
+ else {
+ // rewind to backslash and overwrite with a space
+ *(pCur-2) = ' ';
+ *(pCur-1) = ' ';
+ *pCur = ' ';
+ }
+ } else {
+ // UNIX(TM) file support
+ if (*(pCur-1)!='\\') nLines++;
+ else {
+ // rewind to backslash and overwrite with a space
+ *(pCur-1) = ' ';
+ *pCur = ' ';
+ }
+ }
+ }
+ else if ( *pCur == '.' )
+ nDots++;
+ }
+ if ( pnDots )
+ *pnDots = nDots;
+ if ( pnLines )
+ *pnLines = nLines;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/mio/mioUtils.c b/src/map/mio/mioUtils.c
new file mode 100644
index 00000000..aa373783
--- /dev/null
+++ b/src/map/mio/mioUtils.c
@@ -0,0 +1,531 @@
+/**CFile****************************************************************
+
+ FileName [mioUtils.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [File reading/writing for technology mapping.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - September 8, 2003.]
+
+ Revision [$Id: mioUtils.c,v 1.6 2004/09/03 18:02:20 satrajit Exp $]
+
+***********************************************************************/
+
+#include "mioInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Mio_WriteGate( FILE * pFile, Mio_Gate_t * pGate, int fPrintSops );
+static void Mio_WritePin( FILE * pFile, Mio_Pin_t * pPin );
+static int Mio_DelayCompare( Mio_Gate_t ** ppG1, Mio_Gate_t ** ppG2 );
+static void Mio_DeriveTruthTable_rec( DdNode * bFunc, unsigned uTruthsIn[][2], unsigned uTruthRes[] );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mio_LibraryDelete( Mio_Library_t * pLib )
+{
+ Mio_Gate_t * pGate, * pGate2;
+ if ( pLib == NULL )
+ return;
+ // free the bindings of nodes to gates from this library for all networks
+// Mv_FrameFreeNetworkBindings( Mv_FrameGetGlobalFrame() );
+ // free the library
+ FREE( pLib->pName );
+ Mio_LibraryForEachGateSafe( pLib, pGate, pGate2 )
+ Mio_GateDelete( pGate );
+ Extra_MmFlexStop( pLib->pMmFlex, 0 );
+ Vec_StrFree( pLib->vCube );
+ if ( pLib->tName2Gate )
+ st_free_table( pLib->tName2Gate );
+ if ( pLib->dd )
+ Cudd_Quit( pLib->dd );
+ free( pLib );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mio_GateDelete( Mio_Gate_t * pGate )
+{
+ Mio_Pin_t * pPin, * pPin2;
+ FREE( pGate->pOutName );
+ FREE( pGate->pName );
+ FREE( pGate->pForm );
+ if ( pGate->bFunc )
+ Cudd_RecursiveDeref( pGate->pLib->dd, pGate->bFunc );
+ Mio_GateForEachPinSafe( pGate, pPin, pPin2 )
+ Mio_PinDelete( pPin );
+ free( pGate );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mio_PinDelete( Mio_Pin_t * pPin )
+{
+ FREE( pPin->pName );
+ free( pPin );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mio_Pin_t * Mio_PinDup( Mio_Pin_t * pPin )
+{
+ Mio_Pin_t * pPinNew;
+
+ pPinNew = ALLOC( Mio_Pin_t, 1 );
+ *pPinNew = *pPin;
+ pPinNew->pName = (pPinNew->pName ? util_strsav(pPinNew->pName) : NULL);
+ pPinNew->pNext = NULL;
+
+ return pPinNew;
+}
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mio_WriteLibrary( FILE * pFile, Mio_Library_t * pLib, int fPrintSops )
+{
+ Mio_Gate_t * pGate;
+
+ fprintf( pFile, "# The genlib library \"%s\".\n", pLib->pName );
+ Mio_LibraryForEachGate( pLib, pGate )
+ Mio_WriteGate( pFile, pGate, fPrintSops );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mio_WriteGate( FILE * pFile, Mio_Gate_t * pGate, int fPrintSops )
+{
+ Mio_Pin_t * pPin;
+
+ fprintf( pFile, "GATE " );
+ fprintf( pFile, "%12s ", pGate->pName );
+ fprintf( pFile, "%10.2f ", pGate->dArea );
+ fprintf( pFile, "O=%s;\n", pGate->pForm );
+ // print the pins
+ if ( fPrintSops )
+ fprintf( pFile, "%s", pGate->pSop? pGate->pSop : "unspecified\n" );
+// Extra_bddPrint( pGate->pLib->dd, pGate->bFunc );
+// fprintf( pFile, "\n" );
+ Mio_GateForEachPin( pGate, pPin )
+ Mio_WritePin( pFile, pPin );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mio_WritePin( FILE * pFile, Mio_Pin_t * pPin )
+{
+ char * pPhaseNames[10] = { "UNKNOWN", "INV", "NONINV" };
+ fprintf( pFile, " PIN " );
+ fprintf( pFile, "%9s ", pPin->pName );
+ fprintf( pFile, "%10s ", pPhaseNames[pPin->Phase] );
+ fprintf( pFile, "%6d ", (int)pPin->dLoadInput );
+ fprintf( pFile, "%6d ", (int)pPin->dLoadMax );
+ fprintf( pFile, "%6.2f ", pPin->dDelayBlockRise );
+ fprintf( pFile, "%6.2f ", pPin->dDelayFanoutRise );
+ fprintf( pFile, "%6.2f ", pPin->dDelayBlockFall );
+ fprintf( pFile, "%6.2f", pPin->dDelayFanoutFall );
+ fprintf( pFile, "\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collects the set of root gates.]
+
+ Description [Only collects the gates with unique functionality,
+ which have fewer inputs and shorter delay than the given limits.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mio_Gate_t ** Mio_CollectRoots( Mio_Library_t * pLib, int nInputs, float tDelay, bool fSkipInv, int * pnGates )
+{
+ Mio_Gate_t * pGate;
+ Mio_Gate_t ** ppGates;
+ /* st_table * tFuncs; */
+ /* st_generator * gen; */
+ DdNode * bFunc;
+ DdManager * dd;
+ int nGates, iGate;
+
+ dd = Mio_LibraryReadDd( pLib );
+ nGates = Mio_LibraryReadGateNum( pLib );
+
+ /*
+
+ // for each functionality select one gate; skip constants and buffers
+ tFuncs = st_init_table( st_ptrcmp, st_ptrhash );
+ Mio_LibraryForEachGate( pLib, pGate )
+ {
+ bFunc = Mio_GateReadFunc(pGate);
+ if ( pGate->nInputs > nInputs )
+ continue;
+ if ( pGate->dDelayMax > (double)tDelay )
+ continue;
+ if ( bFunc == b0 || bFunc == b1 )
+ continue;
+ if ( bFunc == dd->vars[0] )
+ continue;
+ if ( bFunc == Cudd_Not(dd->vars[0]) && fSkipInv )
+ continue;
+ if ( st_is_member( tFuncs, (char *)bFunc ) )
+ continue;
+ st_insert( tFuncs, (char *)bFunc, (char *)pGate );
+ }
+
+ // collect the gates into the array
+ ppGates = ALLOC( Mio_Gate_t *, nGates );
+ iGate = 0;
+ st_foreach_item( tFuncs, gen, (char **)&bFunc, (char **)&pGate )
+ ppGates[ iGate++ ] = pGate;
+ assert( iGate <= nGates );
+ st_free_table( tFuncs );
+
+ */
+
+ ppGates = ALLOC( Mio_Gate_t *, nGates );
+ iGate = 0;
+ Mio_LibraryForEachGate( pLib, pGate )
+ {
+ bFunc = Mio_GateReadFunc(pGate);
+ if ( pGate->nInputs > nInputs )
+ continue;
+ if ( pGate->dDelayMax > (double)tDelay )
+ continue;
+ if ( bFunc == b0 || bFunc == b1 )
+ continue;
+ if ( bFunc == dd->vars[0] )
+ continue;
+ if ( bFunc == Cudd_Not(dd->vars[0]) && fSkipInv )
+ continue;
+
+ assert( iGate < nGates );
+ ppGates[ iGate++ ] = pGate;
+ }
+
+ if ( iGate > 0 )
+ {
+ // sort the gates by delay
+ qsort( (void *)ppGates, iGate, sizeof(Mio_Gate_t *),
+ (int (*)(const void *, const void *)) Mio_DelayCompare );
+ assert( Mio_DelayCompare( ppGates, ppGates + iGate - 1 ) <= 0 );
+ }
+
+ if ( pnGates )
+ *pnGates = iGate;
+ return ppGates;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares the max delay of two gates.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mio_DelayCompare( Mio_Gate_t ** ppG1, Mio_Gate_t ** ppG2 )
+{
+ if ( (*ppG1)->dDelayMax < (*ppG2)->dDelayMax )
+ return -1;
+ if ( (*ppG1)->dDelayMax > (*ppG2)->dDelayMax )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Derives the truth table of the gate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mio_DeriveTruthTable( Mio_Gate_t * pGate, unsigned uTruthsIn[][2], int nSigns, int nInputs, unsigned uTruthRes[] )
+{
+ Mio_DeriveTruthTable_rec( pGate->bFunc, uTruthsIn, uTruthRes );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively derives the truth table of the gate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mio_DeriveTruthTable_rec( DdNode * bFunc, unsigned uTruthsIn[][2], unsigned uTruthRes[] )
+{
+ unsigned uTruthsCof0[2];
+ unsigned uTruthsCof1[2];
+
+ // complement the resulting truth table, if the function is complemented
+ if ( Cudd_IsComplement(bFunc) )
+ {
+ Mio_DeriveTruthTable_rec( Cudd_Not(bFunc), uTruthsIn, uTruthRes );
+ uTruthRes[0] = ~uTruthRes[0];
+ uTruthRes[1] = ~uTruthRes[1];
+ return;
+ }
+
+ // if the function is constant 1, return the constant 1 truth table
+ if ( bFunc->index == CUDD_CONST_INDEX )
+ {
+ uTruthRes[0] = MIO_FULL;
+ uTruthRes[1] = MIO_FULL;
+ return;
+ }
+
+ // solve the problem for both cofactors
+ Mio_DeriveTruthTable_rec( cuddE(bFunc), uTruthsIn, uTruthsCof0 );
+ Mio_DeriveTruthTable_rec( cuddT(bFunc), uTruthsIn, uTruthsCof1 );
+
+ // derive the resulting truth table using the input truth tables
+ uTruthRes[0] = (uTruthsCof0[0] & ~uTruthsIn[bFunc->index][0]) |
+ (uTruthsCof1[0] & uTruthsIn[bFunc->index][0]);
+ uTruthRes[1] = (uTruthsCof0[1] & ~uTruthsIn[bFunc->index][1]) |
+ (uTruthsCof1[1] & uTruthsIn[bFunc->index][1]);
+}
+
+/**Function*************************************************************
+
+ Synopsis [Derives the truth table of the root of the gate.]
+
+ Description [Given the truth tables of the leaves of the gate,
+ this procedure derives the truth table of the root.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mio_DeriveTruthTable2( Mio_Gate_t * pGate, unsigned uTruthsIn[][2], int nTruths, int nInputs, unsigned uTruthRes[] )
+{
+ unsigned uSignCube[2];
+ int i, nFanins;
+ char * pCube;
+
+ // make sure that the number of input truth tables in equal to the number of gate inputs
+ assert( pGate->nInputs == nTruths );
+ assert( nInputs < 7 );
+
+ nFanins = Abc_SopGetVarNum( pGate->pSop );
+ assert( nFanins == nInputs );
+
+ // clean the resulting truth table
+ uTruthRes[0] = 0;
+ uTruthRes[1] = 0;
+ if ( nInputs < 6 )
+ {
+// for ( c = 0; *(pCube = pGate->pSop + c * (nFanins + 3)); c++ )
+ Abc_SopForEachCube( pGate->pSop, nFanins, pCube )
+ {
+ // add the clause
+ uSignCube[0] = MIO_FULL;
+ for ( i = 0; i < nFanins; i++ )
+ {
+ if ( pCube[i] == '0' )
+ uSignCube[0] &= ~uTruthsIn[i][0];
+ else if ( pCube[i] == '1' )
+ uSignCube[0] &= uTruthsIn[i][0];
+ }
+ }
+ if ( nInputs < 5 )
+ uTruthRes[0] &= MIO_MASK(1<<nInputs);
+ }
+ else
+ {
+ // consider the case when two unsigneds should be used
+// for ( c = 0; *(pCube = pGate->pSop + c * (nFanins + 3)); c++ )
+ Abc_SopForEachCube( pGate->pSop, nFanins, pCube )
+ {
+ uSignCube[0] = MIO_FULL;
+ uSignCube[1] = MIO_FULL;
+ for ( i = 0; i < nFanins; i++ )
+ {
+ if ( pCube[i] == '0' )
+ {
+ uSignCube[0] &= ~uTruthsIn[i][0];
+ uSignCube[1] &= ~uTruthsIn[i][1];
+ }
+ else if ( pCube[i] == '1' )
+ {
+ uSignCube[0] &= uTruthsIn[i][0];
+ uSignCube[1] &= uTruthsIn[i][1];
+ }
+ }
+ uTruthRes[0] |= uSignCube[0];
+ uTruthRes[1] |= uSignCube[1];
+ }
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Derives the area and delay of the root of the gate.]
+
+ Description [Array of the resulting delays should be initialized
+ to the (negative) SUPER_NO_VAR value.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mio_DeriveGateDelays( Mio_Gate_t * pGate,
+ float ** ptPinDelays, int nPins, int nInputs, float tDelayZero,
+ float * ptDelaysRes, float * ptPinDelayMax )
+{
+ Mio_Pin_t * pPin;
+ float Delay, DelayMax;
+ int i, k;
+ assert( pGate->nInputs == nPins );
+ // set all the delays to the unused delay
+ for ( i = 0; i < nInputs; i++ )
+ ptDelaysRes[i] = tDelayZero;
+ // compute the delays for each input and the max delay at the same time
+ DelayMax = 0;
+ for ( i = 0; i < nInputs; i++ )
+ {
+ for ( k = 0, pPin = pGate->pPins; pPin; pPin = pPin->pNext, k++ )
+ {
+ if ( ptPinDelays[k][i] < 0 )
+ continue;
+ Delay = ptPinDelays[k][i] + (float)pPin->dDelayBlockMax;
+ if ( ptDelaysRes[i] < Delay )
+ ptDelaysRes[i] = Delay;
+ }
+ if ( k != nPins )
+ {
+ printf ("DEBUG: problem gate is %s\n", Mio_GateReadName( pGate ));
+ }
+ assert( k == nPins );
+ if ( DelayMax < ptDelaysRes[i] )
+ DelayMax = ptDelaysRes[i];
+ }
+ *ptPinDelayMax = DelayMax;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Creates a pseudo-gate.]
+
+ Description [The pseudo-gate is a N-input gate with all info set to 0.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mio_Gate_t * Mio_GateCreatePseudo( int nInputs )
+{
+ Mio_Gate_t * pGate;
+ Mio_Pin_t * pPin;
+ int i;
+ // allocate the gate structure
+ pGate = ALLOC( Mio_Gate_t, 1 );
+ memset( pGate, 0, sizeof(Mio_Gate_t) );
+ pGate->nInputs = nInputs;
+ // create pins
+ for ( i = 0; i < nInputs; i++ )
+ {
+ pPin = ALLOC( Mio_Pin_t, 1 );
+ memset( pPin, 0, sizeof(Mio_Pin_t) );
+ pPin->pNext = pGate->pPins;
+ pGate->pPins = pPin;
+ }
+ return pGate;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/mio/module.make b/src/map/mio/module.make
new file mode 100644
index 00000000..26a4561c
--- /dev/null
+++ b/src/map/mio/module.make
@@ -0,0 +1,5 @@
+SRC += src/map/mio/mio.c \
+ src/map/mio/mioApi.c \
+ src/map/mio/mioFunc.c \
+ src/map/mio/mioRead.c \
+ src/map/mio/mioUtils.c
diff --git a/src/map/super/module.make b/src/map/super/module.make
new file mode 100644
index 00000000..19ce8228
--- /dev/null
+++ b/src/map/super/module.make
@@ -0,0 +1,4 @@
+SRC += src/map/super/super.c \
+ src/map/super/superAnd.c \
+ src/map/super/superGate.c \
+ src/map/super/superWrite.c
diff --git a/src/map/super/super.c b/src/map/super/super.c
new file mode 100644
index 00000000..ffb432d5
--- /dev/null
+++ b/src/map/super/super.c
@@ -0,0 +1,319 @@
+/**CFile****************************************************************
+
+ FileName [super.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Pre-computation of supergates.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - August 18, 2003.]
+
+ Revision [$Id: super.c,v 1.6 2004/10/30 20:51:11 satrajit Exp $]
+
+***********************************************************************/
+
+#include "superInt.h"
+#include "mainInt.h"
+#include "mio.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Super_CommandSupergates ( Abc_Frame_t * pAbc, int argc, char **argv );
+static int Super_CommandSupergatesAnd( Abc_Frame_t * pAbc, int argc, char **argv );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Super_Init( Abc_Frame_t * pAbc )
+{
+ Cmd_CommandAdd( pAbc, "SC mapping", "super", Super_CommandSupergates, 0 );
+ Cmd_CommandAdd( pAbc, "SC mapping", "super2", Super_CommandSupergatesAnd, 0 );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Super_End()
+{
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Super_CommandSupergatesAnd( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ FILE * pOut, * pErr;
+ int nVarsMax, nLevels;
+ int fVerbose;
+ int c;
+
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set the defaults
+ nVarsMax = 4;
+ nLevels = 3;
+ fVerbose = 0;
+ util_getopt_reset();
+ while ( (c = util_getopt(argc, argv, "ilvh")) != EOF )
+ {
+ switch (c)
+ {
+ case 'i':
+ nVarsMax = atoi(argv[util_optind]);
+ util_optind++;
+ if ( nVarsMax < 0 )
+ goto usage;
+ break;
+ case 'l':
+ nLevels = atoi(argv[util_optind]);
+ util_optind++;
+ if ( nLevels < 0 )
+ goto usage;
+ break;
+ case 'v':
+ fVerbose ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ break;
+ default:
+ goto usage;
+ }
+ }
+
+ Super2_Precompute( nVarsMax, nLevels, fVerbose );
+
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: super2 [-i num] [-l num] [-vh]\n");
+ fprintf( pErr, "\t precomputes the supergates composed of AND2s and INVs\n" );
+ fprintf( pErr, "\t-i num : the max number of inputs to the supergate [default = %d]\n", nVarsMax );
+ fprintf( pErr, "\t-l num : the max number of logic levels of gates [default = %d]\n", nLevels );
+ fprintf( pErr, "\t-v : enable verbose output\n");
+ fprintf( pErr, "\t-h : print the help message\n");
+ return 1; /* error exit */
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Super_CommandSupergates( Abc_Frame_t * pAbc, int argc, char **argv )
+{
+ FILE * pFile;
+ FILE * pOut, * pErr;
+ Mio_Library_t * pLib;
+ char * FileName, * ExcludeFile;
+ float DelayLimit;
+ float AreaLimit;
+ bool fSkipInvs;
+ bool fWriteOldFormat;
+ int nVarsMax, nLevels, TimeLimit;
+ int fVerbose;
+ int c;
+
+ pOut = Abc_FrameReadOut(pAbc);
+ pErr = Abc_FrameReadErr(pAbc);
+
+ // set the defaults
+ nVarsMax = 5;
+ nLevels = 3;
+ DelayLimit = 3.5;
+ AreaLimit = 9;
+ TimeLimit = 10;
+ fSkipInvs = 1;
+ fVerbose = 0;
+ fWriteOldFormat = 0;
+ ExcludeFile = 0;
+
+ util_getopt_reset();
+ while ( (c = util_getopt(argc, argv, "eiltdasovh")) != EOF )
+ {
+ switch (c)
+ {
+ case 'e':
+ ExcludeFile = argv[util_optind];
+ if ( ExcludeFile == 0 )
+ goto usage;
+ util_optind++;
+ break;
+ case 'i':
+ nVarsMax = atoi(argv[util_optind]);
+ util_optind++;
+ if ( nVarsMax < 0 )
+ goto usage;
+ break;
+ case 'l':
+ nLevels = atoi(argv[util_optind]);
+ util_optind++;
+ if ( nLevels < 0 )
+ goto usage;
+ break;
+ case 't':
+ TimeLimit = atoi(argv[util_optind]);
+ util_optind++;
+ if ( TimeLimit < 0 )
+ goto usage;
+ break;
+ case 'd':
+ DelayLimit = (float)atof(argv[util_optind]);
+ util_optind++;
+ if ( DelayLimit <= 0.0 )
+ goto usage;
+ break;
+ case 'a':
+ AreaLimit = (float)atof(argv[util_optind]);
+ util_optind++;
+ if ( AreaLimit <= 0.0 )
+ goto usage;
+ break;
+ case 's':
+ fSkipInvs ^= 1;
+ break;
+ case 'o':
+ fWriteOldFormat ^= 1;
+ break;
+ case 'v':
+ fVerbose ^= 1;
+ break;
+ case 'h':
+ goto usage;
+ break;
+ default:
+ goto usage;
+ }
+ }
+
+
+ if ( argc != util_optind + 1 )
+ {
+ fprintf( pErr, "The GENLIB library file should be given on the command line.\n" );
+ goto usage;
+ }
+
+ if ( nVarsMax < 2 || nVarsMax > 6 )
+ {
+ fprintf( pErr, "The max number of variables (%d) should be more than 1 and less than 7.\n", nVarsMax );
+ goto usage;
+ }
+
+ // get the input file name
+ FileName = argv[util_optind];
+// if ( (pFile = Io_FileOpen( FileName, "open_path", "r" )) == NULL )
+ if ( (pFile = fopen( FileName, "r" )) == NULL )
+ {
+ fprintf( pErr, "Cannot open input file \"%s\". ", FileName );
+ if (( FileName = Extra_FileGetSimilarName( FileName, ".genlib", ".lib", ".gen", ".g", NULL ) ))
+ fprintf( pErr, "Did you mean \"%s\"?", FileName );
+ fprintf( pErr, "\n" );
+ return 1;
+ }
+ fclose( pFile );
+
+ // set the new network
+ pLib = Mio_LibraryRead( pAbc, FileName, ExcludeFile, fVerbose );
+ if ( pLib == NULL )
+ {
+ fprintf( pErr, "Reading library has failed.\n" );
+ goto usage;
+ }
+
+ // compute the gates
+ Super_Precompute( pLib, nVarsMax, nLevels, DelayLimit, AreaLimit, TimeLimit, fSkipInvs, fWriteOldFormat, fVerbose );
+
+ // delete the library
+ Mio_LibraryDelete( pLib );
+ return 0;
+
+usage:
+ fprintf( pErr, "usage: super [-i num] [-l num] [-d float] [-a float] [-t num] [-sovh] <genlib_file>\n");
+ fprintf( pErr, "\t precomputes the supergates for the given GENLIB library\n" );
+ fprintf( pErr, "\t-i num : the max number of supergate inputs [default = %d]\n", nVarsMax );
+ fprintf( pErr, "\t-l num : the max number of levels of gates [default = %d]\n", nLevels );
+ fprintf( pErr, "\t-d float : the max delay of the supergates [default = %.2f]\n", DelayLimit );
+ fprintf( pErr, "\t-a float : the max area of the supergates [default = %.2f]\n", AreaLimit );
+ fprintf( pErr, "\t-t num : the approximate runtime limit in seconds [default = %d]\n", TimeLimit );
+ fprintf( pErr, "\t-s : toggle the use of inverters at the inputs [default = %s]\n", (fSkipInvs? "no": "yes") );
+ fprintf( pErr, "\t-o : toggle dumping the supergate library in old format [default = %s]\n", (fWriteOldFormat? "yes": "no") );
+ fprintf( pErr, "\t-e file : file contains list of genlib gates to exclude\n" );
+ fprintf( pErr, "\t-v : enable verbose output [default = %s]\n", (fVerbose? "yes" : "no") );
+ fprintf( pErr, "\t-h : print the help message\n");
+ fprintf( pErr, "\n");
+ fprintf( pErr, "\tHere is a piece of advice on precomputing supergate libraries:\n");
+ fprintf( pErr, "\t\n");
+ fprintf( pErr, "\tStart with the number of inputs equal to 5 (-i 5), the number of \n");
+ fprintf( pErr, "\tlevels equal to 3 (-l 3), the delay equal to 2-3 delays of inverter, \n");
+ fprintf( pErr, "\tthe area equal to 3-4 areas of two input NAND, and runtime limit equal \n");
+ fprintf( pErr, "\tto 10 seconds (-t 10). Run precomputation and learn from the result.\n");
+ fprintf( pErr, "\tDetermine what parameter is most constraining and try to increase \n");
+ fprintf( pErr, "\tthe value of that parameter. The goal is to have a well-balanced\n");
+ fprintf( pErr, "\tset of constraints and the resulting supergate library containing\n");
+ fprintf( pErr, "\tapproximately 100K-200K supergates. Typically, it is better to increase\n");
+ fprintf( pErr, "\tdelay limit rather than area limit, because having large-area supergates\n");
+ fprintf( pErr, "\tmay result in a considerable increase in area.\n");
+ fprintf( pErr, "\t\n");
+ fprintf( pErr, "\tNote that a good supergate library for experiments typically can be \n");
+ fprintf( pErr, "\tprecomputed in 30 sec. Increasing the runtime limit makes sense when\n");
+ fprintf( pErr, "\tother parameters are well-balanced and it is needed to enumerate more\n");
+ fprintf( pErr, "\tchoices to have a good result. In the end, to compute the final library\n");
+ fprintf( pErr, "\tthe runtime can be set to 300 sec to ensure the ultimate quality.\n");
+ fprintf( pErr, "\tIn some cases, the runtime has to be reduced if the supergate library\n");
+ fprintf( pErr, "\tcontains too many supergates (> 500K).\n");
+ fprintf( pErr, "\t\n");
+ fprintf( pErr, "\tWhen precomputing libraries of 6 inputs (-i 6), start with even more \n");
+ fprintf( pErr, "\trestricted parameters and gradually increase them until the goal is met.\n");
+ fprintf( pErr, "\t\n");
+ return 1; /* error exit */
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/super/super.h b/src/map/super/super.h
new file mode 100644
index 00000000..ce2b7433
--- /dev/null
+++ b/src/map/super/super.h
@@ -0,0 +1,51 @@
+/**CFile****************************************************************
+
+ FileName [super.h]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Pre-computation of supergates (delay-limited gate combinations).]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - September 8, 2003.]
+
+ Revision [$Id: super.h,v 1.3 2004/06/28 14:20:25 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __SUPER_H__
+#define __SUPER_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// GLOBAL VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== superCore.c =============================================================*/
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+#endif
diff --git a/src/map/super/superAnd.c b/src/map/super/superAnd.c
new file mode 100644
index 00000000..e90fc76d
--- /dev/null
+++ b/src/map/super/superAnd.c
@@ -0,0 +1,696 @@
+/**CFile****************************************************************
+
+ FileName [superAnd.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Pre-computation of supergates.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - September 8, 2003.]
+
+ Revision [$Id: superAnd.c,v 1.3 2004/06/28 14:20:25 alanmi Exp $]
+
+***********************************************************************/
+
+#include "superInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// the bit masks
+#define SUPER_MASK(n) ((~((unsigned)0)) >> (32-n))
+#define SUPER_FULL (~((unsigned)0))
+
+// data structure for AND2 subgraph precomputation
+typedef struct Super2_ManStruct_t_ Super2_Man_t; // manager
+typedef struct Super2_LibStruct_t_ Super2_Lib_t; // library
+typedef struct Super2_GateStruct_t_ Super2_Gate_t; // supergate
+
+struct Super2_ManStruct_t_
+{
+ Extra_MmFixed_t * pMem; // memory manager for all supergates
+ stmm_table * tTable; // mapping of truth tables into gates
+ int nTried; // the total number of tried
+};
+
+struct Super2_LibStruct_t_
+{
+ int i; // used to iterate through the table
+ int k; // used to iterate through the table
+ int nInputs; // the number of inputs
+ int nMints; // the number of minterms
+ int nLevels; // the number of logic levels
+ int nGates; // the number of gates in the library
+ int nGatesAlloc; // the number of allocated places
+ Super2_Gate_t ** pGates; // the gates themselves
+ unsigned uMaskBit; // the mask used to determine the compl bit
+};
+
+struct Super2_GateStruct_t_
+{
+ unsigned uTruth; // the truth table of this supergate
+ Super2_Gate_t * pOne; // the left wing
+ Super2_Gate_t * pTwo; // the right wing
+ Super2_Gate_t * pNext; // the next gate in the table
+};
+
+
+// manipulation of complemented attributes
+#define Super2_IsComplement(p) (((int)((long) (p) & 01)))
+#define Super2_Regular(p) ((Super2_Gate_t *)((unsigned)(p) & ~01))
+#define Super2_Not(p) ((Super2_Gate_t *)((long)(p) ^ 01))
+#define Super2_NotCond(p,c) ((Super2_Gate_t *)((long)(p) ^ (c)))
+
+// iterating through the gates in the library
+#define Super2_LibForEachGate( Lib, Gate ) \
+ for ( Lib->i = 0; \
+ Lib->i < Lib->nGates && (Gate = Lib->pGates[Lib->i]); \
+ Lib->i++ )
+#define Super2_LibForEachGate2( Lib, Gate2 ) \
+ for ( Lib->k = 0; \
+ Lib->k < Lib->i && (Gate2 = Lib->pGates[Lib->k]); \
+ Lib->k++ )
+
+// static functions
+static Super2_Man_t * Super2_ManStart();
+static void Super2_ManStop( Super2_Man_t * pMan );
+static Super2_Lib_t * Super2_LibStart();
+static Super2_Lib_t * Super2_LibDup( Super2_Lib_t * pLib );
+static void Super2_LibStop( Super2_Lib_t * pLib );
+static void Super2_LibAddGate( Super2_Lib_t * pLib, Super2_Gate_t * pGate );
+static Super2_Lib_t * Super2_LibFirst( Super2_Man_t * pMan, int nInputs );
+static Super2_Lib_t * Super2_LibCompute( Super2_Man_t * pMan, Super2_Lib_t * pLib );
+
+static void Super2_LibWrite( Super2_Lib_t * pLib );
+static void Super2_LibWriteGate( FILE * pFile, Super2_Lib_t * pLib, Super2_Gate_t * pGate );
+static char * Super2_LibWriteGate_rec( Super2_Gate_t * pGate, int fInv, int Level );
+static int Super2_LibWriteCompare( char * pStr1, char * pStr2 );
+static int Super2_LibCompareGates( Super2_Gate_t ** ppG1, Super2_Gate_t ** ppG2 );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Precomputes the library of AND2 gates.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Super2_Precompute( int nInputs, int nLevels, int fVerbose )
+{
+ Super2_Man_t * pMan;
+ Super2_Lib_t * pLibCur, * pLibNext;
+ int Level;
+ int clk;
+
+ assert( nInputs < 6 );
+
+ // start the manager
+ pMan = Super2_ManStart();
+
+ // get the starting supergates
+ pLibCur = Super2_LibFirst( pMan, nInputs );
+
+ // perform the computation of supergates
+printf( "Computing supergates for %d inputs and %d levels:\n", nInputs, nLevels );
+ for ( Level = 1; Level <= nLevels; Level++ )
+ {
+clk = clock();
+ pLibNext = Super2_LibCompute( pMan, pLibCur );
+ pLibNext->nLevels = Level;
+ Super2_LibStop( pLibCur );
+ pLibCur = pLibNext;
+printf( "Level %d: Tried = %7d. Computed = %7d. ", Level, pMan->nTried, pLibCur->nGates );
+PRT( "Runtime", clock() - clk );
+fflush( stdout );
+ }
+
+printf( "Writing the output file...\n" );
+fflush( stdout );
+ // write them into a file
+ Super2_LibWrite( pLibCur );
+ Super2_LibStop( pLibCur );
+
+ // stop the manager
+ Super2_ManStop( pMan );
+}
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Starts the manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Super2_Man_t * Super2_ManStart()
+{
+ Super2_Man_t * pMan;
+ pMan = ALLOC( Super2_Man_t, 1 );
+ memset( pMan, 0, sizeof(Super2_Man_t) );
+ pMan->pMem = Extra_MmFixedStart( sizeof(Super2_Gate_t) );
+ pMan->tTable = stmm_init_table( st_ptrcmp, st_ptrhash );
+ return pMan;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Stops the manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Super2_ManStop( Super2_Man_t * pMan )
+{
+ Extra_MmFixedStop( pMan->pMem, 0 );
+ stmm_free_table( pMan->tTable );
+ free( pMan );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Starts the library.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Super2_Lib_t * Super2_LibStart()
+{
+ Super2_Lib_t * pLib;
+ pLib = ALLOC( Super2_Lib_t, 1 );
+ memset( pLib, 0, sizeof(Super2_Lib_t) );
+ return pLib;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Duplicates the library.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Super2_Lib_t * Super2_LibDup( Super2_Lib_t * pLib )
+{
+ Super2_Lib_t * pLibNew;
+ pLibNew = Super2_LibStart();
+ pLibNew->nInputs = pLib->nInputs;
+ pLibNew->nMints = pLib->nMints;
+ pLibNew->nLevels = pLib->nLevels;
+ pLibNew->nGates = pLib->nGates;
+ pLibNew->uMaskBit = pLib->uMaskBit;
+ pLibNew->nGatesAlloc = 1000 + pLib->nGatesAlloc;
+ pLibNew->pGates = ALLOC( Super2_Gate_t *, pLibNew->nGatesAlloc );
+ memcpy( pLibNew->pGates, pLib->pGates, pLibNew->nGates * sizeof(Super2_Gate_t *) );
+ return pLibNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Add gate to the library.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Super2_LibAddGate( Super2_Lib_t * pLib, Super2_Gate_t * pGate )
+{
+ if ( pLib->nGates == pLib->nGatesAlloc )
+ {
+ pLib->pGates = REALLOC( Super2_Gate_t *, pLib->pGates, 3 * pLib->nGatesAlloc );
+ pLib->nGatesAlloc *= 3;
+ }
+ pLib->pGates[ pLib->nGates++ ] = pGate;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Stops the library.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Super2_LibStop( Super2_Lib_t * pLib )
+{
+ free( pLib->pGates );
+ free( pLib );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Derives the starting supergates.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Super2_Lib_t * Super2_LibFirst( Super2_Man_t * pMan, int nInputs )
+{
+ Super2_Lib_t * pLib;
+ int v, m;
+
+ // start the library
+ pLib = Super2_LibStart();
+
+ // create the starting supergates
+ pLib->nInputs = nInputs;
+ pLib->nMints = (1 << nInputs);
+ pLib->nLevels = 0;
+ pLib->nGates = nInputs + 1;
+ pLib->nGatesAlloc = nInputs + 1;
+ pLib->uMaskBit = (1 << (pLib->nMints-1));
+ pLib->pGates = ALLOC( Super2_Gate_t *, nInputs + 1 );
+ // add the constant 0
+ pLib->pGates[0] = (Super2_Gate_t *)Extra_MmFixedEntryFetch( pMan->pMem );
+ memset( pLib->pGates[0], 0, sizeof(Super2_Gate_t) );
+ // add the elementary gates
+ for ( v = 0; v < nInputs; v++ )
+ {
+ pLib->pGates[v+1] = (Super2_Gate_t *)Extra_MmFixedEntryFetch( pMan->pMem );
+ memset( pLib->pGates[v+1], 0, sizeof(Super2_Gate_t) );
+ pLib->pGates[v+1]->pTwo = (Super2_Gate_t *)v;
+ }
+
+ // set up their truth tables
+ for ( m = 0; m < pLib->nMints; m++ )
+ for ( v = 0; v < nInputs; v++ )
+ if ( m & (1 << v) )
+ pLib->pGates[v+1]->uTruth |= (1 << m);
+ return pLib;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Precomputes one level of supergates.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Super2_Lib_t * Super2_LibCompute( Super2_Man_t * pMan, Super2_Lib_t * pLib )
+{
+ Super2_Lib_t * pLibNew;
+ Super2_Gate_t * pGate1, * pGate2, * pGateNew;
+ Super2_Gate_t ** ppGate;
+ unsigned Mask = SUPER_MASK(pLib->nMints);
+ unsigned uTruth, uTruthR, uTruth1, uTruth2, uTruth1c, uTruth2c;
+
+ // start the new library
+ pLibNew = Super2_LibDup( pLib );
+
+ // reset the hash table
+ stmm_free_table( pMan->tTable );
+ pMan->tTable = stmm_init_table( st_ptrcmp, st_ptrhash );
+ // set the starting things into the hash table
+ Super2_LibForEachGate( pLibNew, pGate1 )
+ {
+ uTruthR = ((pGate1->uTruth & pLibNew->uMaskBit)? Mask & ~pGate1->uTruth : pGate1->uTruth);
+
+ if ( stmm_lookup( pMan->tTable, (char *)uTruthR, (char **)&pGate2 ) )
+ {
+ printf( "New gate:\n" );
+ Super2_LibWriteGate( stdout, pLibNew, pGate1 );
+ printf( "Gate in the table:\n" );
+ Super2_LibWriteGate( stdout, pLibNew, pGate2 );
+ assert( 0 );
+ }
+ stmm_insert( pMan->tTable, (char *)uTruthR, (char *)pGate1 );
+ }
+
+
+ // set the number of gates tried
+ pMan->nTried = pLibNew->nGates;
+
+ // go through the gate pairs
+ Super2_LibForEachGate( pLib, pGate1 )
+ {
+ if ( pLib->i && pLib->i % 300 == 0 )
+ {
+ printf( "Tried %5d first gates...\n", pLib->i );
+ fflush( stdout );
+ }
+
+ Super2_LibForEachGate2( pLib, pGate2 )
+ {
+ uTruth1 = pGate1->uTruth;
+ uTruth2 = pGate2->uTruth;
+ uTruth1c = Mask & ~uTruth1;
+ uTruth2c = Mask & ~uTruth2;
+
+ // none complemented
+ uTruth = uTruth1 & uTruth2;
+ uTruthR = ((uTruth & pLibNew->uMaskBit)? Mask & ~uTruth : uTruth);
+
+ if ( !stmm_find_or_add( pMan->tTable, (char *)uTruthR, (char ***)&ppGate ) )
+ {
+ pGateNew = (Super2_Gate_t *)Extra_MmFixedEntryFetch( pMan->pMem );
+ pGateNew->pOne = pGate1;
+ pGateNew->pTwo = pGate2;
+ pGateNew->uTruth = uTruth;
+ *ppGate = pGateNew;
+ Super2_LibAddGate( pLibNew, pGateNew );
+ }
+
+ // one complemented
+ uTruth = uTruth1c & uTruth2;
+ uTruthR = ((uTruth & pLibNew->uMaskBit)? Mask & ~uTruth : uTruth);
+
+ if ( !stmm_find_or_add( pMan->tTable, (char *)uTruthR, (char ***)&ppGate ) )
+ {
+ pGateNew = (Super2_Gate_t *)Extra_MmFixedEntryFetch( pMan->pMem );
+ pGateNew->pOne = Super2_Not(pGate1);
+ pGateNew->pTwo = pGate2;
+ pGateNew->uTruth = uTruth;
+ *ppGate = pGateNew;
+ Super2_LibAddGate( pLibNew, pGateNew );
+ }
+
+ // another complemented
+ uTruth = uTruth1 & uTruth2c;
+ uTruthR = ((uTruth & pLibNew->uMaskBit)? Mask & ~uTruth : uTruth);
+
+ if ( !stmm_find_or_add( pMan->tTable, (char *)uTruthR, (char ***)&ppGate ) )
+ {
+ pGateNew = (Super2_Gate_t *)Extra_MmFixedEntryFetch( pMan->pMem );
+ pGateNew->pOne = pGate1;
+ pGateNew->pTwo = Super2_Not(pGate2);
+ pGateNew->uTruth = uTruth;
+ *ppGate = pGateNew;
+ Super2_LibAddGate( pLibNew, pGateNew );
+ }
+
+ // both complemented
+ uTruth = uTruth1c & uTruth2c;
+ uTruthR = ((uTruth & pLibNew->uMaskBit)? Mask & ~uTruth : uTruth);
+
+ if ( !stmm_find_or_add( pMan->tTable, (char *)uTruthR, (char ***)&ppGate ) )
+ {
+ pGateNew = (Super2_Gate_t *)Extra_MmFixedEntryFetch( pMan->pMem );
+ pGateNew->pOne = Super2_Not(pGate1);
+ pGateNew->pTwo = Super2_Not(pGate2);
+ pGateNew->uTruth = uTruth;
+ *ppGate = pGateNew;
+ Super2_LibAddGate( pLibNew, pGateNew );
+ }
+
+ pMan->nTried += 4;
+ }
+ }
+ return pLibNew;
+}
+
+
+static unsigned s_uMaskBit;
+static unsigned s_uMaskAll;
+
+/**Function*************************************************************
+
+ Synopsis [Writes the library into the file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Super2_LibWrite( Super2_Lib_t * pLib )
+{
+ Super2_Gate_t * pGate;
+ FILE * pFile;
+ char FileName[100];
+ int clk;
+
+ if ( pLib->nLevels > 5 )
+ {
+ printf( "Cannot write file for %d levels.\n", pLib->nLevels );
+ return;
+ }
+
+clk = clock();
+ // sort the supergates by truth table
+ s_uMaskBit = pLib->uMaskBit;
+ s_uMaskAll = SUPER_MASK(pLib->nMints);
+ qsort( (void *)pLib->pGates, pLib->nGates, sizeof(Super2_Gate_t *),
+ (int (*)(const void *, const void *)) Super2_LibCompareGates );
+ assert( Super2_LibCompareGates( pLib->pGates, pLib->pGates + pLib->nGates - 1 ) < 0 );
+PRT( "Sorting", clock() - clk );
+
+
+ // start the file
+ sprintf( FileName, "superI%dL%d", pLib->nInputs, pLib->nLevels );
+ pFile = fopen( FileName, "w" );
+ fprintf( pFile, "# AND2/INV supergates derived on %s.\n", Extra_TimeStamp() );
+ fprintf( pFile, "# Command line: \"super2 -i %d -l %d\".\n", pLib->nInputs, pLib->nLevels );
+ fprintf( pFile, "# The number of inputs = %6d.\n", pLib->nInputs );
+ fprintf( pFile, "# The number of levels = %6d.\n", pLib->nLevels );
+ fprintf( pFile, "# The number of supergates = %6d.\n", pLib->nGates );
+ fprintf( pFile, "# The total functions = %6d.\n", (1<<(pLib->nMints-1)) );
+ fprintf( pFile, "\n" );
+ fprintf( pFile, "%6d\n", pLib->nGates );
+
+ // print the gates
+ Super2_LibForEachGate( pLib, pGate )
+ Super2_LibWriteGate( pFile, pLib, pGate );
+ fclose( pFile );
+
+ printf( "The supergates are written into file \"%s\" ", FileName );
+ printf( "(%0.2f Mb).\n", ((double)Extra_FileSize(FileName))/(1<<20) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Writes the gate into the file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Super2_LibCompareGates( Super2_Gate_t ** ppG1, Super2_Gate_t ** ppG2 )
+{
+ Super2_Gate_t * pG1 = *ppG1;
+ Super2_Gate_t * pG2 = *ppG2;
+ unsigned uTruth1, uTruth2;
+
+ uTruth1 = (pG1->uTruth & s_uMaskBit)? s_uMaskAll & ~pG1->uTruth : pG1->uTruth;
+ uTruth2 = (pG2->uTruth & s_uMaskBit)? s_uMaskAll & ~pG2->uTruth : pG2->uTruth;
+
+ if ( uTruth1 < uTruth2 )
+ return -1;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Writes the gate into the file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Super2_LibWriteGate( FILE * pFile, Super2_Lib_t * pLib, Super2_Gate_t * pGate )
+{
+// unsigned uTruthR;
+ unsigned uTruth;
+ int fInv;
+
+ // check whether the gate need complementation
+ fInv = (int)(pGate->uTruth & pLib->uMaskBit);
+ uTruth = (fInv? ~pGate->uTruth : pGate->uTruth);
+/*
+ // reverse the truth table
+ uTruthR = 0;
+ for ( m = 0; m < pLib->nMints; m++ )
+ if ( uTruth & (1 << m) )
+ uTruthR |= (1 << (pLib->nMints-1-m));
+*/
+ // write the truth table
+ Extra_PrintBinary( pFile, &uTruth, pLib->nMints );
+ fprintf( pFile, " " );
+ // write the symbolic expression
+ fprintf( pFile, "%s", Super2_LibWriteGate_rec( pGate, fInv, pLib->nLevels ) );
+ fprintf( pFile, "\n" );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Recursively writes the gate into the file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Super2_LibWriteGate_rec( Super2_Gate_t * pGate, int fInv, int Level )
+{
+ static char Buff01[ 3], Buff02[ 3]; // Max0 = 1
+ static char Buff11[ 6], Buff12[ 6]; // Max1 = 2*Max0 + 2 = 4
+ static char Buff21[ 12], Buff22[ 12]; // Max2 = 2*Max1 + 2 = 10
+ static char Buff31[ 25], Buff32[ 25]; // Max3 = 2*Max2 + 2 = 22
+ static char Buff41[ 50], Buff42[ 50]; // Max4 = 2*Max3 + 2 = 46
+ static char Buff51[100], Buff52[100]; // Max5 = 2*Max4 + 2 = 94
+ static char * pBuffs1[6] = { Buff01, Buff11, Buff21, Buff31, Buff41, Buff51 };
+ static char * pBuffs2[6] = { Buff02, Buff12, Buff22, Buff32, Buff42, Buff52 };
+ char * pBranch;
+ char * pBuffer1 = pBuffs1[Level];
+ char * pBuffer2 = pBuffs2[Level];
+ Super2_Gate_t * pGateNext1, * pGateNext2;
+ int fInvNext1, fInvNext2;
+ int RetValue;
+
+ // consider the last level
+ assert( Level >= 0 );
+ if ( pGate->pOne == NULL )
+ {
+ if ( pGate->uTruth == 0 )
+ {
+ pBuffer1[0] = (fInv? '1': '0');
+ pBuffer1[1] = '$';
+ pBuffer1[2] = 0;
+ }
+ else
+ {
+ pBuffer1[0] = (fInv? 'A' + ((int)pGate->pTwo): 'a' + ((int)pGate->pTwo));
+ pBuffer1[1] = 0;
+ }
+ return pBuffer1;
+ }
+ assert( Level > 0 );
+
+
+ // get the left branch
+ pGateNext1 = Super2_Regular(pGate->pOne);
+ fInvNext1 = Super2_IsComplement(pGate->pOne);
+ pBranch = Super2_LibWriteGate_rec(pGateNext1, fInvNext1, Level - 1);
+ // copy into Buffer1
+ strcpy( pBuffer1, pBranch );
+
+ // get the right branch
+ pGateNext2 = Super2_Regular(pGate->pTwo);
+ fInvNext2 = Super2_IsComplement(pGate->pTwo);
+ pBranch = Super2_LibWriteGate_rec(pGateNext2, fInvNext2, Level - 1);
+
+ // consider the case when comparison is not necessary
+ if ( fInvNext1 ^ fInvNext2 )
+ {
+ if ( fInvNext1 > fInvNext2 )
+ sprintf( pBuffer2, "%c%s%s%c", (fInv? '<': '('), pBuffer1, pBranch, (fInv? '>': ')') );
+ else
+ sprintf( pBuffer2, "%c%s%s%c", (fInv? '<': '('), pBranch, pBuffer1, (fInv? '>': ')') );
+ }
+ else
+ {
+ // compare the two branches
+ RetValue = Super2_LibWriteCompare( pBuffer1, pBranch );
+ if ( RetValue == 1 )
+ sprintf( pBuffer2, "%c%s%s%c", (fInv? '<': '('), pBuffer1, pBranch, (fInv? '>': ')') );
+ else // if ( RetValue == -1 )
+ {
+ sprintf( pBuffer2, "%c%s%s%c", (fInv? '<': '('), pBranch, pBuffer1, (fInv? '>': ')') );
+ if ( RetValue == 0 )
+ printf( "Strange!\n" );
+ }
+ }
+ return pBuffer2;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares the two branches of the tree.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Super2_LibWriteCompare( char * pStr1, char * pStr2 )
+{
+ while ( 1 )
+ {
+ // skip extra symbols
+ while ( *pStr1 && *pStr1 < 'A' )
+ pStr1++;
+ while ( *pStr2 && *pStr2 < 'A' )
+ pStr2++;
+
+ // check if any one is finished
+ if ( *pStr1 == 0 || *pStr2 == 0 )
+ {
+ if ( *pStr2 )
+ return 1;
+ return -1;
+ }
+
+ // compare
+ if ( *pStr1 == *pStr2 )
+ {
+ pStr1++;
+ pStr2++;
+ }
+ else
+ {
+ if ( *pStr1 < *pStr2 )
+ return 1;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/super/superGENERIC.c b/src/map/super/superGENERIC.c
new file mode 100644
index 00000000..4c7b67ca
--- /dev/null
+++ b/src/map/super/superGENERIC.c
@@ -0,0 +1,46 @@
+/**CFile****************************************************************
+
+ FileName [super__.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Pre-computation of supergates.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - September 8, 2003.]
+
+ Revision [$Id: super__.h,v 1.0 2003/09/08 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "superInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/map/super/superGate.c b/src/map/super/superGate.c
new file mode 100644
index 00000000..d0cd0ad7
--- /dev/null
+++ b/src/map/super/superGate.c
@@ -0,0 +1,1324 @@
+/**CFile****************************************************************
+
+ FileName [superGate.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Pre-computation of supergates.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - September 8, 2003.]
+
+ Revision [$Id: superGate.c,v 1.7 2004/08/03 00:11:40 satrajit Exp $]
+
+***********************************************************************/
+
+#include "superInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// the bit masks
+#define SUPER_MASK(n) ((~((unsigned)0)) >> (32-(n)))
+#define SUPER_FULL (~((unsigned)0))
+#define SUPER_NO_VAR (-9999.0)
+#define SUPER_EPSILON (0.001)
+
+// data structure for supergate precomputation
+typedef struct Super_ManStruct_t_ Super_Man_t; // manager
+typedef struct Super_GateStruct_t_ Super_Gate_t; // supergate
+
+struct Super_ManStruct_t_
+{
+ // parameters
+ char * pName; // the original genlib file name
+ int nVarsMax; // the number of inputs
+ int nMints; // the number of minterms
+ int nLevels; // the number of logic levels
+ float tDelayMax; // the max delay of the supergates in the library
+ float tAreaMax; // the max area of the supergates in the library
+ int fSkipInv; // the flag says about skipping inverters
+ int fWriteOldFormat; // in addition, writes the file in the old format
+ int fVerbose;
+
+ // supergates
+ Super_Gate_t * pInputs[10]; // the input supergates
+ int nGates; // the number of gates in the library
+ Super_Gate_t ** pGates; // the gates themselves
+ stmm_table * tTable; // mapping of truth tables into gates
+
+ // memory managers
+ Extra_MmFixed_t * pMem; // memory manager for the supergates
+ Extra_MmFlex_t * pMemFlex; // memory manager for the fanin arrays
+
+ // statistics
+ int nTried; // the total number of tried
+ int nAdded; // the number of entries added
+ int nRemoved; // the number of entries removed
+ int nUnique; // the number of unique gates
+ int nLookups; // the number of hash table lookups
+ int nAliases; // the number of hash table lookups thrown away due to aliasing
+
+ // runtime
+ int Time; // the runtime of the generation procedure
+ int TimeLimit; // the runtime limit (in seconds)
+ int TimeSec; // the time passed (in seconds)
+ int TimeStop; // the time to stop computation (in miliseconds)
+ int TimePrint; // the time to print message
+};
+
+struct Super_GateStruct_t_
+{
+ Mio_Gate_t * pRoot; // the root gate for this supergate
+ unsigned fVar : 1; // the flag signaling the elementary variable
+ unsigned fSuper : 1; // the flag signaling the elementary variable
+ unsigned nFanins : 6; // the number of fanin gates
+ unsigned Number : 24; // the number assigned in the process
+ unsigned uTruth[2]; // the truth table of this supergate
+ Super_Gate_t * pFanins[6]; // the fanins of the gate
+ float Area; // the area of this gate
+ float ptDelays[6]; // the pin-to-pin delays for all inputs
+ float tDelayMax; // the maximum delay
+ Super_Gate_t * pNext; // the next gate in the table
+};
+
+
+// iterating through the gates in the library
+#define Super_ManForEachGate( GateArray, Limit, Index, Gate ) \
+ for ( Index = 0; \
+ Index < Limit && (Gate = GateArray[Index]); \
+ Index++ )
+
+// static functions
+static Super_Man_t * Super_ManStart();
+static void Super_ManStop( Super_Man_t * pMan );
+
+static void Super_AddGateToTable( Super_Man_t * pMan, Super_Gate_t * pGate );
+static void Super_First( Super_Man_t * pMan, int nVarsMax );
+static Super_Man_t * Super_Compute( Super_Man_t * pMan, Mio_Gate_t ** ppGates, int nGates, bool fSkipInv );
+static Super_Gate_t * Super_CreateGateNew( Super_Man_t * pMan, Mio_Gate_t * pRoot, Super_Gate_t ** pSupers, int nSupers, unsigned uTruth[], float Area, float tPinDelaysRes[], float tDelayMax, int nPins );
+static bool Super_CompareGates( Super_Man_t * pMan, unsigned uTruth[], float Area, float tPinDelaysRes[], int nPins );
+static int Super_DelayCompare( Super_Gate_t ** ppG1, Super_Gate_t ** ppG2 );
+static int Super_AreaCompare( Super_Gate_t ** ppG1, Super_Gate_t ** ppG2 );
+static void Super_TranferGatesToArray( Super_Man_t * pMan );
+static int Super_CheckTimeout( ProgressBar * pPro, Super_Man_t * pMan );
+
+static void Super_Write( Super_Man_t * pMan );
+static int Super_WriteCompare( Super_Gate_t ** ppG1, Super_Gate_t ** ppG2 );
+static void Super_WriteFileHeader( Super_Man_t * pMan, FILE * pFile );
+
+static void Super_WriteLibrary( Super_Man_t * pMan );
+static void Super_WriteLibraryGate( FILE * pFile, Super_Man_t * pMan, Super_Gate_t * pGate, int Num );
+static char * Super_WriteLibraryGateName( Super_Gate_t * pGate );
+static void Super_WriteLibraryGateName_rec( Super_Gate_t * pGate, char * pBuffer );
+
+static void Super_WriteLibraryTree( Super_Man_t * pMan );
+static void Super_WriteLibraryTree_rec( FILE * pFile, Super_Man_t * pMan, Super_Gate_t * pSuper, int * pCounter );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Precomputes the library of supergates.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Super_Precompute( Mio_Library_t * pLibGen, int nVarsMax, int nLevels, float tDelayMax, float tAreaMax, int TimeLimit, bool fSkipInv, bool fWriteOldFormat, int fVerbose )
+{
+ Super_Man_t * pMan;
+ Mio_Gate_t ** ppGates;
+ int nGates, Level, clk, clockStart;
+
+ assert( nVarsMax < 7 );
+
+ // get the root gates
+ ppGates = Mio_CollectRoots( pLibGen, nVarsMax, tDelayMax, 0, &nGates );
+
+ // start the manager
+ pMan = Super_ManStart();
+ pMan->pName = Mio_LibraryReadName(pLibGen);
+ pMan->fSkipInv = fSkipInv;
+ pMan->tDelayMax = tDelayMax;
+ pMan->tAreaMax = tAreaMax;
+ pMan->TimeLimit = TimeLimit; // in seconds
+ pMan->TimeStop = TimeLimit * CLOCKS_PER_SEC + clock(); // in CPU ticks
+ pMan->fWriteOldFormat = fWriteOldFormat;
+ pMan->fVerbose = fVerbose;
+
+ if ( nGates == 0 )
+ {
+ fprintf( stderr, "Error: No genlib gates satisfy the limits criteria. Stop.\n");
+ fprintf( stderr, "Limits: max delay = %.2f, max area = %.2f, time limit = %d sec.\n",
+ pMan->tDelayMax, pMan->tAreaMax, pMan->TimeLimit );
+
+ // stop the manager
+ Super_ManStop( pMan );
+ free( ppGates );
+
+ return;
+ }
+
+ // get the starting supergates
+ Super_First( pMan, nVarsMax );
+
+ // perform the computation of supergates
+ clockStart = clock();
+if ( fVerbose )
+{
+ printf( "Computing supergates with %d inputs and %d levels.\n",
+ pMan->nVarsMax, nLevels );
+ printf( "Limits: max delay = %.2f, max area = %.2f, time limit = %d sec.\n",
+ pMan->tDelayMax, pMan->tAreaMax, pMan->TimeLimit );
+}
+
+ for ( Level = 1; Level <= nLevels; Level++ )
+ {
+ if ( clock() > pMan->TimeStop )
+ break;
+clk = clock();
+ Super_Compute( pMan, ppGates, nGates, fSkipInv );
+ pMan->nLevels = Level;
+if ( fVerbose )
+{
+ printf( "Lev %d: Try =%12d. Add =%6d. Rem =%5d. Save =%6d. Lookups =%12d. Aliases =%12d. ",
+ Level, pMan->nTried, pMan->nAdded, pMan->nRemoved, pMan->nAdded - pMan->nRemoved, pMan->nLookups, pMan->nAliases );
+PRT( "Time", clock() - clk );
+fflush( stdout );
+}
+ }
+ pMan->Time = clock() - clockStart;
+
+if ( fVerbose )
+{
+printf( "Writing the output file...\n" );
+fflush( stdout );
+}
+ // write them into a file
+ Super_Write( pMan );
+
+ // stop the manager
+ Super_ManStop( pMan );
+ free( ppGates );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Derives the starting supergates.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Super_First( Super_Man_t * pMan, int nVarsMax )
+{
+ Super_Gate_t * pSuper;
+ int nMintLimit, nVarLimit;
+ int v, m;
+ // set the parameters
+ pMan->nVarsMax = nVarsMax;
+ pMan->nMints = (1 << nVarsMax);
+ pMan->nLevels = 0;
+ // allocate room for the gates
+ pMan->nGates = nVarsMax;
+ pMan->pGates = ALLOC( Super_Gate_t *, nVarsMax + 2 );
+ // create the gates corresponding to the elementary variables
+ for ( v = 0; v < nVarsMax; v++ )
+ {
+ // get a new gate
+ pSuper = (Super_Gate_t *)Extra_MmFixedEntryFetch( pMan->pMem );
+ memset( pSuper, 0, sizeof(Super_Gate_t) );
+ // assign the elementary variable, the truth table, and the delays
+ pSuper->fVar = 1;
+ pSuper->Number = v;
+ for ( m = 0; m < nVarsMax; m++ )
+ pSuper->ptDelays[m] = SUPER_NO_VAR;
+ pSuper->ptDelays[v] = 0.0;
+ // set the gate
+ pMan->pGates[v] = pSuper;
+ Super_AddGateToTable( pMan, pSuper );
+ pMan->pInputs[v] = pSuper;
+ }
+ // set up their truth tables
+ nVarLimit = (nVarsMax >= 5)? 5 : nVarsMax;
+ nMintLimit = (1 << nVarLimit);
+ for ( m = 0; m < nMintLimit; m++ )
+ for ( v = 0; v < nVarLimit; v++ )
+ if ( m & (1 << v) )
+ pMan->pGates[v]->uTruth[0] |= (1 << m);
+ // make adjustments for the case of 6 variables
+ if ( nVarsMax == 6 )
+ {
+ for ( v = 0; v < 5; v++ )
+ pMan->pGates[v]->uTruth[1] = pMan->pGates[v]->uTruth[0];
+ pMan->pGates[5]->uTruth[0] = 0;
+ pMan->pGates[5]->uTruth[1] = ~((unsigned)0);
+ }
+ else
+ {
+ for ( v = 0; v < nVarsMax; v++ )
+ pMan->pGates[v]->uTruth[1] = 0;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Precomputes one level of supergates.]
+
+ Description [This procedure computes the set of supergates that can be
+ derived from the given set of root gates (from GENLIB library) by composing
+ the root gates with the currently available supergates. This procedure is
+ smart in the sense that it tries to avoid useless emuration by imposing
+ tight bounds by area and delay. Only the supergates and are guaranteed to
+ have smaller area and delay are enumereated. See comments below for details.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Super_Man_t * Super_Compute( Super_Man_t * pMan, Mio_Gate_t ** ppGates, int nGates, bool fSkipInv )
+{
+ Super_Gate_t * pSupers[6], * pGate0, * pGate1, * pGate2, * pGate3, * pGate4, * pGate5, * pGateNew;
+ float tPinDelaysRes[6], * ptPinDelays[6], tPinDelayMax, tDelayMio;
+ float Area, Area0, Area1, Area2, Area3, Area4, AreaMio;
+ unsigned uTruth[2], uTruths[6][2];
+ int i0, i1, i2, i3, i4, i5;
+ Super_Gate_t ** ppGatesLimit;
+ int nFanins, nGatesLimit, k, s, t;
+ ProgressBar * pProgress;
+ int fTimeOut;
+ int fPrune = 1; // Shall we prune?
+ int iPruneLimit = 3; // Each of the gates plugged into the root gate will have
+ // less than these many fanins
+ int iPruneLimitRoot = 4; // The root gate may have only less than these many fanins
+
+ // put the gates from the unique table into the array
+ // the gates from the array will be used to compose other gates
+ // the gates in tbe table are used to check uniqueness of collected gates
+ Super_TranferGatesToArray( pMan );
+
+ // sort the gates in the increasing order of maximum delay
+ if ( pMan->nGates > 10000 )
+ {
+ printf( "Sorting array of %d supergates...\r", pMan->nGates );
+ fflush( stdout );
+ }
+ qsort( (void *)pMan->pGates, pMan->nGates, sizeof(Super_Gate_t *),
+ (int (*)(const void *, const void *)) Super_DelayCompare );
+ assert( Super_DelayCompare( pMan->pGates, pMan->pGates + pMan->nGates - 1 ) <= 0 );
+ if ( pMan->nGates > 10000 )
+ {
+ printf( " \r" );
+ }
+
+ pProgress = Extra_ProgressBarStart( stdout, pMan->TimeLimit );
+ pMan->TimePrint = clock() + CLOCKS_PER_SEC;
+ ppGatesLimit = ALLOC( Super_Gate_t *, pMan->nGates );
+ // go through the root gates
+ // the root gates are sorted in the increasing gelay
+ fTimeOut = 0;
+ for ( k = 0; k < nGates; k++ )
+ {
+ if ( fTimeOut ) break;
+
+ if ( fPrune )
+ {
+ if ( pMan->nLevels >= 1 ) // First level gates have been computed
+ {
+ if ( Mio_GateReadInputs(ppGates[k]) >= iPruneLimitRoot )
+ continue;
+ }
+ }
+
+ // select the subset of gates to be considered with this root gate
+ // all the gates past this point will lead to delay larger than the limit
+ tDelayMio = (float)Mio_GateReadDelayMax(ppGates[k]);
+ for ( s = 0, t = 0; s < pMan->nGates; s++ )
+ {
+ if ( fPrune && ( pMan->nLevels >= 1 ) && ( ((int)pMan->pGates[s]->nFanins) >= iPruneLimit ))
+ continue;
+
+ ppGatesLimit[t] = pMan->pGates[s];
+ if ( ppGatesLimit[t++]->tDelayMax + tDelayMio > pMan->tDelayMax )
+ break;
+ }
+ nGatesLimit = t;
+
+ if ( pMan->fVerbose )
+ {
+ printf ("Trying %d choices for %d inputs\n", t, Mio_GateReadInputs(ppGates[k]) );
+ }
+
+ // resort part of this range by area
+ // now we can prune the search by going up in the list until we reach the limit on area
+ // all the gates beyond this point can be skipped because their area can be only larger
+ if ( nGatesLimit > 10000 )
+ printf( "Sorting array of %d supergates...\r", nGatesLimit );
+ qsort( (void *)ppGatesLimit, nGatesLimit, sizeof(Super_Gate_t *),
+ (int (*)(const void *, const void *)) Super_AreaCompare );
+ assert( Super_AreaCompare( ppGatesLimit, ppGatesLimit + nGatesLimit - 1 ) <= 0 );
+ if ( nGatesLimit > 10000 )
+ printf( " \r" );
+
+ // consider the combinations of gates with the root gate on top
+ AreaMio = (float)Mio_GateReadArea(ppGates[k]);
+ nFanins = Mio_GateReadInputs(ppGates[k]);
+ switch ( nFanins )
+ {
+ case 0: // should not happen
+ assert( 0 );
+ break;
+ case 1: // interter root
+ Super_ManForEachGate( ppGatesLimit, nGatesLimit, i0, pGate0 )
+ {
+ if ( fTimeOut ) break;
+ fTimeOut = Super_CheckTimeout( pProgress, pMan );
+ // skip the inverter as the root gate before the elementary variable
+ // as a result, the supergates will not have inverters on the input side
+ // but inverters still may occur at the output of or inside complex supergates
+ if ( fSkipInv && pGate0->tDelayMax == 0 )
+ continue;
+ // compute area
+ Area = AreaMio + pGate0->Area;
+ if ( Area > pMan->tAreaMax )
+ break;
+
+ pSupers[0] = pGate0; uTruths[0][0] = pGate0->uTruth[0]; uTruths[0][1] = pGate0->uTruth[1]; ptPinDelays[0] = pGate0->ptDelays;
+ Mio_DeriveGateDelays( ppGates[k], ptPinDelays, nFanins, pMan->nVarsMax, SUPER_NO_VAR, tPinDelaysRes, &tPinDelayMax );
+ Mio_DeriveTruthTable( ppGates[k], uTruths, nFanins, pMan->nVarsMax, uTruth );
+ if ( !Super_CompareGates( pMan, uTruth, Area, tPinDelaysRes, pMan->nVarsMax ) )
+ continue;
+ // create a new gate
+ pGateNew = Super_CreateGateNew( pMan, ppGates[k], pSupers, nFanins, uTruth, Area, tPinDelaysRes, tPinDelayMax, pMan->nVarsMax );
+ Super_AddGateToTable( pMan, pGateNew );
+ }
+ break;
+ case 2: // two-input root gate
+ Super_ManForEachGate( ppGatesLimit, nGatesLimit, i0, pGate0 )
+ {
+ Area0 = AreaMio + pGate0->Area;
+ if ( Area0 > pMan->tAreaMax )
+ break;
+ pSupers[0] = pGate0; uTruths[0][0] = pGate0->uTruth[0]; uTruths[0][1] = pGate0->uTruth[1]; ptPinDelays[0] = pGate0->ptDelays;
+ Super_ManForEachGate( ppGatesLimit, nGatesLimit, i1, pGate1 )
+ if ( i1 != i0 )
+ {
+ if ( fTimeOut ) goto done;
+ fTimeOut = Super_CheckTimeout( pProgress, pMan );
+ // compute area
+ Area = Area0 + pGate1->Area;
+ if ( Area > pMan->tAreaMax )
+ break;
+
+ pSupers[1] = pGate1; uTruths[1][0] = pGate1->uTruth[0]; uTruths[1][1] = pGate1->uTruth[1]; ptPinDelays[1] = pGate1->ptDelays;
+ Mio_DeriveGateDelays( ppGates[k], ptPinDelays, nFanins, pMan->nVarsMax, SUPER_NO_VAR, tPinDelaysRes, &tPinDelayMax );
+ Mio_DeriveTruthTable( ppGates[k], uTruths, nFanins, pMan->nVarsMax, uTruth );
+ if ( !Super_CompareGates( pMan, uTruth, Area, tPinDelaysRes, pMan->nVarsMax ) )
+ continue;
+ // create a new gate
+ pGateNew = Super_CreateGateNew( pMan, ppGates[k], pSupers, nFanins, uTruth, Area, tPinDelaysRes, tPinDelayMax, pMan->nVarsMax );
+ Super_AddGateToTable( pMan, pGateNew );
+ }
+ }
+ break;
+ case 3: // three-input root gate
+ Super_ManForEachGate( ppGatesLimit, nGatesLimit, i0, pGate0 )
+ {
+ Area0 = AreaMio + pGate0->Area;
+ if ( Area0 > pMan->tAreaMax )
+ break;
+ pSupers[0] = pGate0; uTruths[0][0] = pGate0->uTruth[0]; uTruths[0][1] = pGate0->uTruth[1]; ptPinDelays[0] = pGate0->ptDelays;
+
+ Super_ManForEachGate( ppGatesLimit, nGatesLimit, i1, pGate1 )
+ if ( i1 != i0 )
+ {
+ Area1 = Area0 + pGate1->Area;
+ if ( Area1 > pMan->tAreaMax )
+ break;
+ pSupers[1] = pGate1; uTruths[1][0] = pGate1->uTruth[0]; uTruths[1][1] = pGate1->uTruth[1]; ptPinDelays[1] = pGate1->ptDelays;
+
+ Super_ManForEachGate( ppGatesLimit, nGatesLimit, i2, pGate2 )
+ if ( i2 != i0 && i2 != i1 )
+ {
+ if ( fTimeOut ) goto done;
+ fTimeOut = Super_CheckTimeout( pProgress, pMan );
+ // compute area
+ Area = Area1 + pGate2->Area;
+ if ( Area > pMan->tAreaMax )
+ break;
+ pSupers[2] = pGate2; uTruths[2][0] = pGate2->uTruth[0]; uTruths[2][1] = pGate2->uTruth[1]; ptPinDelays[2] = pGate2->ptDelays;
+
+ Mio_DeriveGateDelays( ppGates[k], ptPinDelays, nFanins, pMan->nVarsMax, SUPER_NO_VAR, tPinDelaysRes, &tPinDelayMax );
+ Mio_DeriveTruthTable( ppGates[k], uTruths, nFanins, pMan->nVarsMax, uTruth );
+ if ( !Super_CompareGates( pMan, uTruth, Area, tPinDelaysRes, pMan->nVarsMax ) )
+ continue;
+ // create a new gate
+ pGateNew = Super_CreateGateNew( pMan, ppGates[k], pSupers, nFanins, uTruth, Area, tPinDelaysRes, tPinDelayMax, pMan->nVarsMax );
+ Super_AddGateToTable( pMan, pGateNew );
+ }
+ }
+ }
+ break;
+ case 4: // four-input root gate
+ Super_ManForEachGate( ppGatesLimit, nGatesLimit, i0, pGate0 )
+ {
+ Area0 = AreaMio + pGate0->Area;
+ if ( Area0 > pMan->tAreaMax )
+ break;
+ pSupers[0] = pGate0; uTruths[0][0] = pGate0->uTruth[0]; uTruths[0][1] = pGate0->uTruth[1]; ptPinDelays[0] = pGate0->ptDelays;
+
+ Super_ManForEachGate( ppGatesLimit, nGatesLimit, i1, pGate1 )
+ if ( i1 != i0 )
+ {
+ Area1 = Area0 + pGate1->Area;
+ if ( Area1 > pMan->tAreaMax )
+ break;
+ pSupers[1] = pGate1; uTruths[1][0] = pGate1->uTruth[0]; uTruths[1][1] = pGate1->uTruth[1]; ptPinDelays[1] = pGate1->ptDelays;
+
+ Super_ManForEachGate( ppGatesLimit, nGatesLimit, i2, pGate2 )
+ if ( i2 != i0 && i2 != i1 )
+ {
+ Area2 = Area1 + pGate2->Area;
+ if ( Area2 > pMan->tAreaMax )
+ break;
+ pSupers[2] = pGate2; uTruths[2][0] = pGate2->uTruth[0]; uTruths[2][1] = pGate2->uTruth[1]; ptPinDelays[2] = pGate2->ptDelays;
+
+ Super_ManForEachGate( ppGatesLimit, nGatesLimit, i3, pGate3 )
+ if ( i3 != i0 && i3 != i1 && i3 != i2 )
+ {
+ if ( fTimeOut ) goto done;
+ fTimeOut = Super_CheckTimeout( pProgress, pMan );
+ // compute area
+ Area = Area2 + pGate3->Area;
+ if ( Area > pMan->tAreaMax )
+ break;
+ pSupers[3] = pGate3; uTruths[3][0] = pGate3->uTruth[0]; uTruths[3][1] = pGate3->uTruth[1]; ptPinDelays[3] = pGate3->ptDelays;
+
+ Mio_DeriveGateDelays( ppGates[k], ptPinDelays, nFanins, pMan->nVarsMax, SUPER_NO_VAR, tPinDelaysRes, &tPinDelayMax );
+ Mio_DeriveTruthTable( ppGates[k], uTruths, nFanins, pMan->nVarsMax, uTruth );
+ if ( !Super_CompareGates( pMan, uTruth, Area, tPinDelaysRes, pMan->nVarsMax ) )
+ continue;
+ // create a new gate
+ pGateNew = Super_CreateGateNew( pMan, ppGates[k], pSupers, nFanins, uTruth, Area, tPinDelaysRes, tPinDelayMax, pMan->nVarsMax );
+ Super_AddGateToTable( pMan, pGateNew );
+ }
+ }
+ }
+ }
+ break;
+ case 5: // five-input root gate
+ Super_ManForEachGate( ppGatesLimit, nGatesLimit, i0, pGate0 )
+ {
+ Area0 = AreaMio + pGate0->Area;
+ if ( Area0 > pMan->tAreaMax )
+ break;
+ pSupers[0] = pGate0; uTruths[0][0] = pGate0->uTruth[0]; uTruths[0][1] = pGate0->uTruth[1]; ptPinDelays[0] = pGate0->ptDelays;
+
+ Super_ManForEachGate( ppGatesLimit, nGatesLimit, i1, pGate1 )
+ if ( i1 != i0 )
+ {
+ Area1 = Area0 + pGate1->Area;
+ if ( Area1 > pMan->tAreaMax )
+ break;
+ pSupers[1] = pGate1; uTruths[1][0] = pGate1->uTruth[0]; uTruths[1][1] = pGate1->uTruth[1]; ptPinDelays[1] = pGate1->ptDelays;
+
+ Super_ManForEachGate( ppGatesLimit, nGatesLimit, i2, pGate2 )
+ if ( i2 != i0 && i2 != i1 )
+ {
+ Area2 = Area1 + pGate2->Area;
+ if ( Area2 > pMan->tAreaMax )
+ break;
+ pSupers[2] = pGate2; uTruths[2][0] = pGate2->uTruth[0]; uTruths[2][1] = pGate2->uTruth[1]; ptPinDelays[2] = pGate2->ptDelays;
+
+ Super_ManForEachGate( ppGatesLimit, nGatesLimit, i3, pGate3 )
+ if ( i3 != i0 && i3 != i1 && i3 != i2 )
+ {
+ Area3 = Area2 + pGate3->Area;
+ if ( Area3 > pMan->tAreaMax )
+ break;
+ pSupers[3] = pGate3; uTruths[3][0] = pGate3->uTruth[0]; uTruths[3][1] = pGate3->uTruth[1]; ptPinDelays[3] = pGate3->ptDelays;
+
+ Super_ManForEachGate( ppGatesLimit, nGatesLimit, i4, pGate4 )
+ if ( i4 != i0 && i4 != i1 && i4 != i2 && i4 != i3 )
+ {
+ if ( fTimeOut ) goto done;
+ fTimeOut = Super_CheckTimeout( pProgress, pMan );
+ // compute area
+ Area = Area3 + pGate4->Area;
+ if ( Area > pMan->tAreaMax )
+ break;
+ pSupers[4] = pGate4; uTruths[4][0] = pGate4->uTruth[0]; uTruths[4][1] = pGate4->uTruth[1]; ptPinDelays[4] = pGate4->ptDelays;
+
+ Mio_DeriveGateDelays( ppGates[k], ptPinDelays, nFanins, pMan->nVarsMax, SUPER_NO_VAR, tPinDelaysRes, &tPinDelayMax );
+ Mio_DeriveTruthTable( ppGates[k], uTruths, nFanins, pMan->nVarsMax, uTruth );
+ if ( !Super_CompareGates( pMan, uTruth, Area, tPinDelaysRes, pMan->nVarsMax ) )
+ continue;
+ // create a new gate
+ pGateNew = Super_CreateGateNew( pMan, ppGates[k], pSupers, nFanins, uTruth, Area, tPinDelaysRes, tPinDelayMax, pMan->nVarsMax );
+ Super_AddGateToTable( pMan, pGateNew );
+ }
+ }
+ }
+ }
+ }
+ break;
+ case 6: // six-input root gate
+ Super_ManForEachGate( ppGatesLimit, nGatesLimit, i0, pGate0 )
+ {
+ Area0 = AreaMio + pGate0->Area;
+ if ( Area0 > pMan->tAreaMax )
+ break;
+ pSupers[0] = pGate0; uTruths[0][0] = pGate0->uTruth[0]; uTruths[0][1] = pGate0->uTruth[1]; ptPinDelays[0] = pGate0->ptDelays;
+
+ Super_ManForEachGate( ppGatesLimit, nGatesLimit, i1, pGate1 )
+ if ( i1 != i0 )
+ {
+ Area1 = Area0 + pGate1->Area;
+ if ( Area1 > pMan->tAreaMax )
+ break;
+ pSupers[1] = pGate1; uTruths[1][0] = pGate1->uTruth[0]; uTruths[1][1] = pGate1->uTruth[1]; ptPinDelays[1] = pGate1->ptDelays;
+
+ Super_ManForEachGate( ppGatesLimit, nGatesLimit, i2, pGate2 )
+ if ( i2 != i0 && i2 != i1 )
+ {
+ Area2 = Area1 + pGate2->Area;
+ if ( Area2 > pMan->tAreaMax )
+ break;
+ pSupers[2] = pGate2; uTruths[2][0] = pGate2->uTruth[0]; uTruths[2][1] = pGate2->uTruth[1]; ptPinDelays[2] = pGate2->ptDelays;
+
+ Super_ManForEachGate( ppGatesLimit, nGatesLimit, i3, pGate3 )
+ if ( i3 != i0 && i3 != i1 && i3 != i2 )
+ {
+ Area3 = Area2 + pGate3->Area;
+ if ( Area3 > pMan->tAreaMax )
+ break;
+ pSupers[3] = pGate3; uTruths[3][0] = pGate3->uTruth[0]; uTruths[3][1] = pGate3->uTruth[1]; ptPinDelays[3] = pGate3->ptDelays;
+
+ Super_ManForEachGate( ppGatesLimit, nGatesLimit, i4, pGate4 )
+ if ( i4 != i0 && i4 != i1 && i4 != i2 && i4 != i3 )
+ {
+ if ( fTimeOut ) break;
+ fTimeOut = Super_CheckTimeout( pProgress, pMan );
+ // compute area
+ Area4 = Area3 + pGate4->Area;
+ if ( Area > pMan->tAreaMax )
+ break;
+ pSupers[4] = pGate4; uTruths[4][0] = pGate4->uTruth[0]; uTruths[4][1] = pGate4->uTruth[1]; ptPinDelays[4] = pGate4->ptDelays;
+
+ Super_ManForEachGate( ppGatesLimit, nGatesLimit, i5, pGate5 )
+ if ( i5 != i0 && i5 != i1 && i5 != i2 && i5 != i3 && i5 != i4 )
+ {
+ if ( fTimeOut ) goto done;
+ fTimeOut = Super_CheckTimeout( pProgress, pMan );
+ // compute area
+ Area = Area4 + pGate5->Area;
+ if ( Area > pMan->tAreaMax )
+ break;
+ pSupers[5] = pGate5; uTruths[5][0] = pGate5->uTruth[0]; uTruths[5][1] = pGate5->uTruth[1]; ptPinDelays[5] = pGate5->ptDelays;
+
+ Mio_DeriveGateDelays( ppGates[k], ptPinDelays, nFanins, pMan->nVarsMax, SUPER_NO_VAR, tPinDelaysRes, &tPinDelayMax );
+ Mio_DeriveTruthTable( ppGates[k], uTruths, nFanins, pMan->nVarsMax, uTruth );
+ if ( !Super_CompareGates( pMan, uTruth, Area, tPinDelaysRes, pMan->nVarsMax ) )
+ continue;
+ // create a new gate
+ pGateNew = Super_CreateGateNew( pMan, ppGates[k], pSupers, nFanins, uTruth, Area, tPinDelaysRes, tPinDelayMax, pMan->nVarsMax );
+ Super_AddGateToTable( pMan, pGateNew );
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ default :
+ assert( 0 );
+ break;
+ }
+ }
+done:
+ Extra_ProgressBarStop( pProgress );
+ free( ppGatesLimit );
+ return pMan;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Transfers gates from table into the array.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Super_CheckTimeout( ProgressBar * pPro, Super_Man_t * pMan )
+{
+ int TimeNow = clock();
+ if ( TimeNow > pMan->TimePrint )
+ {
+ Extra_ProgressBarUpdate( pPro, ++pMan->TimeSec, NULL );
+ pMan->TimePrint = clock() + CLOCKS_PER_SEC;
+ }
+ if ( TimeNow > pMan->TimeStop )
+ {
+ printf ("Timeout!\n");
+ return 1;
+ }
+ pMan->nTried++;
+ return 0;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Transfers gates from table into the array.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Super_TranferGatesToArray( Super_Man_t * pMan )
+{
+ stmm_generator * gen;
+ Super_Gate_t * pGate, * pList;
+ unsigned Key;
+
+ // put the gates fron the table into the array
+ free( pMan->pGates );
+ pMan->pGates = ALLOC( Super_Gate_t *, pMan->nAdded );
+ pMan->nGates = 0;
+ stmm_foreach_item( pMan->tTable, gen, (char **)&Key, (char **)&pList )
+ {
+ for ( pGate = pList; pGate; pGate = pGate->pNext )
+ pMan->pGates[ pMan->nGates++ ] = pGate;
+ }
+// assert( pMan->nGates == pMan->nAdded - pMan->nRemoved );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Adds one supergate into the unique table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Super_AddGateToTable( Super_Man_t * pMan, Super_Gate_t * pGate )
+{
+ Super_Gate_t ** ppList;
+ unsigned Key;
+// Key = pGate->uTruth[0] + 2003 * pGate->uTruth[1];
+ Key = pGate->uTruth[0] ^ pGate->uTruth[1];
+ if ( !stmm_find_or_add( pMan->tTable, (char *)Key, (char ***)&ppList ) )
+ *ppList = NULL;
+ pGate->pNext = *ppList;
+ *ppList = pGate;
+ pMan->nAdded++;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Check the manager's unique table for comparable gates.]
+
+ Description [Returns 0 if the gate is dominated by others. Returns 1
+ if the gate is new or is better than the available ones. In this case,
+ cleans the table by removing the gates that are worse than the given one.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Super_CompareGates( Super_Man_t * pMan, unsigned uTruth[], float Area, float tPinDelaysRes[], int nPins )
+{
+ Super_Gate_t ** ppList, * pPrev, * pGate, * pGate2;
+ int i, fNewIsBetter, fGateIsBetter;
+ unsigned Key;
+
+ // skip constant functions
+ if ( pMan->nVarsMax < 6 )
+ {
+ if ( uTruth[0] == 0 || ~uTruth[0] == 0 )
+ return 0;
+ }
+ else
+ {
+ if ( ( uTruth[0] == 0 && uTruth[1] == 0 ) || ( ~uTruth[0] == 0 && ~uTruth[1] == 0 ) )
+ return 0;
+ }
+
+ // get hold of the place where the entry is stored
+// Key = uTruth[0] + 2003 * uTruth[1];
+ Key = uTruth[0] ^ uTruth[1];
+ if ( !stmm_find( pMan->tTable, (char *)Key, (char ***)&ppList ) )
+ return 1;
+ // the entry with this truth table is found
+ pPrev = NULL;
+ for ( pGate = *ppList, pGate2 = pGate? pGate->pNext: NULL; pGate;
+ pGate = pGate2, pGate2 = pGate? pGate->pNext: NULL )
+ {
+ pMan->nLookups++;
+ if ( pGate->uTruth[0] != uTruth[0] || pGate->uTruth[1] != uTruth[1] )
+ {
+ pMan->nAliases++;
+ continue;
+ }
+ fGateIsBetter = 0;
+ fNewIsBetter = 0;
+ if ( pGate->Area + SUPER_EPSILON < Area )
+ fGateIsBetter = 1;
+ else if ( pGate->Area > Area + SUPER_EPSILON )
+ fNewIsBetter = 1;
+ for ( i = 0; i < nPins; i++ )
+ {
+ if ( pGate->ptDelays[i] == SUPER_NO_VAR || tPinDelaysRes[i] == SUPER_NO_VAR )
+ continue;
+ if ( pGate->ptDelays[i] + SUPER_EPSILON < tPinDelaysRes[i] )
+ fGateIsBetter = 1;
+ else if ( pGate->ptDelays[i] > tPinDelaysRes[i] + SUPER_EPSILON )
+ fNewIsBetter = 1;
+ if ( fGateIsBetter && fNewIsBetter )
+ break;
+ }
+ // consider 4 cases
+ if ( fGateIsBetter && fNewIsBetter ) // Pareto points; save both
+ pPrev = pGate;
+ else if ( fNewIsBetter ) // gate is worse; remove the gate
+ {
+ if ( pPrev == NULL )
+ *ppList = pGate->pNext;
+ else
+ pPrev->pNext = pGate->pNext;
+ Extra_MmFixedEntryRecycle( pMan->pMem, (char *)pGate );
+ pMan->nRemoved++;
+ }
+ else if ( fGateIsBetter ) // new is worse, already dominated no need to see others
+ return 0;
+ else // if ( !fGateIsBetter && !fNewIsBetter ) // they are identical, no need to see others
+ return 0;
+ }
+ return 1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Create a new supergate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Super_Gate_t * Super_CreateGateNew( Super_Man_t * pMan, Mio_Gate_t * pRoot, Super_Gate_t ** pSupers, int nSupers,
+ unsigned uTruth[], float Area, float tPinDelaysRes[], float tDelayMax, int nPins )
+{
+ Super_Gate_t * pSuper;
+ pSuper = (Super_Gate_t *)Extra_MmFixedEntryFetch( pMan->pMem );
+ memset( pSuper, 0, sizeof(Super_Gate_t) );
+ pSuper->pRoot = pRoot;
+ pSuper->uTruth[0] = uTruth[0];
+ pSuper->uTruth[1] = uTruth[1];
+ memcpy( pSuper->ptDelays, tPinDelaysRes, sizeof(float) * nPins );
+ pSuper->Area = Area;
+ pSuper->nFanins = nSupers;
+ memcpy( pSuper->pFanins, pSupers, sizeof(Super_Gate_t *) * nSupers );
+ pSuper->pNext = NULL;
+ pSuper->tDelayMax = tDelayMax;
+ return pSuper;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Starts the manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Super_Man_t * Super_ManStart()
+{
+ Super_Man_t * pMan;
+ pMan = ALLOC( Super_Man_t, 1 );
+ memset( pMan, 0, sizeof(Super_Man_t) );
+ pMan->pMem = Extra_MmFixedStart( sizeof(Super_Gate_t) );
+ pMan->tTable = stmm_init_table( st_ptrcmp, st_ptrhash );
+ return pMan;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Stops the manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Super_ManStop( Super_Man_t * pMan )
+{
+ Extra_MmFixedStop( pMan->pMem, 0 );
+ if ( pMan->tTable ) stmm_free_table( pMan->tTable );
+ FREE( pMan->pGates );
+ free( pMan );
+}
+
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Writes the supergate library into the file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Super_Write( Super_Man_t * pMan )
+{
+ Super_Gate_t * pGateRoot, * pGate;
+ stmm_generator * gen;
+ int fZeroFound, clk, v;
+ unsigned Key;
+
+ if ( pMan->nGates < 1 )
+ {
+ printf( "The generated library is empty. No output file written.\n" );
+ return;
+ }
+
+ // Filters the supergates by removing those that have fewer inputs than
+ // the given limit, provided that the inputs are not consequtive.
+ // For example, NAND2(a,c) is removed, but NAND2(a,b) is left,
+ // because a and b are consequtive.
+ FREE( pMan->pGates );
+ pMan->pGates = ALLOC( Super_Gate_t *, pMan->nAdded );
+ pMan->nGates = 0;
+ stmm_foreach_item( pMan->tTable, gen, (char **)&Key, (char **)&pGateRoot )
+ {
+ for ( pGate = pGateRoot; pGate; pGate = pGate->pNext )
+ {
+ // skip the elementary variables
+ if ( pGate->pRoot == NULL )
+ continue;
+ // skip the non-consequtive gates
+ fZeroFound = 0;
+ for ( v = 0; v < pMan->nVarsMax; v++ )
+ if ( pGate->ptDelays[v] < SUPER_NO_VAR + SUPER_EPSILON )
+ fZeroFound = 1;
+ else if ( fZeroFound )
+ break;
+ if ( v < pMan->nVarsMax )
+ continue;
+ // save the unique gate
+ pMan->pGates[ pMan->nGates++ ] = pGate;
+ }
+ }
+
+clk = clock();
+ // sort the supergates by truth table
+ qsort( (void *)pMan->pGates, pMan->nGates, sizeof(Super_Gate_t *),
+ (int (*)(const void *, const void *)) Super_WriteCompare );
+ assert( Super_WriteCompare( pMan->pGates, pMan->pGates + pMan->nGates - 1 ) <= 0 );
+if ( pMan->fVerbose )
+{
+PRT( "Sorting", clock() - clk );
+}
+
+
+ // write library in the old format
+clk = clock();
+ if ( pMan->fWriteOldFormat )
+ Super_WriteLibrary( pMan );
+if ( pMan->fVerbose )
+{
+PRT( "Writing old format", clock() - clk );
+}
+
+ // write the tree-like structure of supergates
+clk = clock();
+ Super_WriteLibraryTree( pMan );
+if ( pMan->fVerbose )
+{
+PRT( "Writing new format", clock() - clk );
+}
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Writes the file header.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Super_WriteFileHeader( Super_Man_t * pMan, FILE * pFile )
+{
+ fprintf( pFile, "#\n" );
+ fprintf( pFile, "# Supergate library derived for \"%s\" on %s.\n", pMan->pName, Extra_TimeStamp() );
+ fprintf( pFile, "#\n" );
+ fprintf( pFile, "# Command line: \"super -i %d -l %d -d %.2f -a %.2f -t %d %s %s\".\n",
+ pMan->nVarsMax, pMan->nLevels, pMan->tDelayMax, pMan->tAreaMax, pMan->TimeLimit, (pMan->fSkipInv? "" : "-s"), pMan->pName );
+ fprintf( pFile, "#\n" );
+ fprintf( pFile, "# The number of inputs = %10d.\n", pMan->nVarsMax );
+ fprintf( pFile, "# The number of levels = %10d.\n", pMan->nLevels );
+ fprintf( pFile, "# The maximum delay = %10.2f.\n", pMan->tDelayMax );
+ fprintf( pFile, "# The maximum area = %10.2f.\n", pMan->tAreaMax );
+ fprintf( pFile, "# The maximum runtime (sec) = %10d.\n", pMan->TimeLimit );
+ fprintf( pFile, "#\n" );
+ fprintf( pFile, "# The number of attempts = %10d.\n", pMan->nTried );
+ fprintf( pFile, "# The number of supergates = %10d.\n", pMan->nGates );
+ fprintf( pFile, "# The number of functions = %10d.\n", pMan->nUnique );
+ fprintf( pFile, "# The total functions = %.0f (2^%d).\n", pow(2,pMan->nMints), pMan->nMints );
+ fprintf( pFile, "#\n" );
+ fprintf( pFile, "# Generation time (sec) = %10.2f.\n", (float)(pMan->Time)/(float)(CLOCKS_PER_SEC) );
+ fprintf( pFile, "#\n" );
+ fprintf( pFile, "%s\n", pMan->pName );
+ fprintf( pFile, "%d\n", pMan->nVarsMax );
+ fprintf( pFile, "%d\n", pMan->nGates );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares the truth tables of two gates.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Super_WriteCompare( Super_Gate_t ** ppG1, Super_Gate_t ** ppG2 )
+{
+ unsigned * pTruth1 = (*ppG1)->uTruth;
+ unsigned * pTruth2 = (*ppG2)->uTruth;
+ if ( pTruth1[1] < pTruth2[1] )
+ return -1;
+ if ( pTruth1[1] > pTruth2[1] )
+ return 1;
+ if ( pTruth1[0] < pTruth2[0] )
+ return -1;
+ if ( pTruth1[0] > pTruth2[0] )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares the max delay of two gates.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Super_DelayCompare( Super_Gate_t ** ppG1, Super_Gate_t ** ppG2 )
+{
+ if ( (*ppG1)->tDelayMax < (*ppG2)->tDelayMax )
+ return -1;
+ if ( (*ppG1)->tDelayMax > (*ppG2)->tDelayMax )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares the area of two gates.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Super_AreaCompare( Super_Gate_t ** ppG1, Super_Gate_t ** ppG2 )
+{
+ if ( (*ppG1)->Area < (*ppG2)->Area )
+ return -1;
+ if ( (*ppG1)->Area > (*ppG2)->Area )
+ return 1;
+ return 0;
+}
+
+
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Writes the gates into the file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Super_WriteLibrary( Super_Man_t * pMan )
+{
+ Super_Gate_t * pGate, * pGateNext;
+ FILE * pFile;
+ char FileName[100];
+ char * pNameGeneric;
+ int i, Counter;
+
+ // get the file name
+ pNameGeneric = Extra_FileNameGeneric( pMan->pName );
+ sprintf( FileName, "%s.super_old", pNameGeneric );
+ free( pNameGeneric );
+
+ // count the number of unique functions
+ pMan->nUnique = 1;
+ Super_ManForEachGate( pMan->pGates, pMan->nGates, i, pGate )
+ {
+ if ( i == pMan->nGates - 1 )
+ break;
+ // print the newline if this gate is different from the following one
+ pGateNext = pMan->pGates[i+1];
+ if ( pGateNext->uTruth[0] != pGate->uTruth[0] || pGateNext->uTruth[1] != pGate->uTruth[1] )
+ pMan->nUnique++;
+ }
+
+ // start the file
+ pFile = fopen( FileName, "w" );
+ Super_WriteFileHeader( pMan, pFile );
+
+ // print the gates
+ Counter = 0;
+ Super_ManForEachGate( pMan->pGates, pMan->nGates, i, pGate )
+ {
+ Super_WriteLibraryGate( pFile, pMan, pGate, ++Counter );
+ if ( i == pMan->nGates - 1 )
+ break;
+ // print the newline if this gate is different from the following one
+ pGateNext = pMan->pGates[i+1];
+ if ( pGateNext->uTruth[0] != pGate->uTruth[0] || pGateNext->uTruth[1] != pGate->uTruth[1] )
+ fprintf( pFile, "\n" );
+ }
+ assert( Counter == pMan->nGates );
+ fclose( pFile );
+
+if ( pMan->fVerbose )
+{
+ printf( "The supergates are written using old format \"%s\" ", FileName );
+ printf( "(%0.3f Mb).\n", ((double)Extra_FileSize(FileName))/(1<<20) );
+}
+}
+
+/**Function*************************************************************
+
+ Synopsis [Writes the supergate into the file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Super_WriteLibraryGate( FILE * pFile, Super_Man_t * pMan, Super_Gate_t * pGate, int Num )
+{
+ int i;
+ fprintf( pFile, "%04d ", Num ); // the number
+ Extra_PrintBinary( pFile, pGate->uTruth, pMan->nMints ); // the truth table
+ fprintf( pFile, " %5.2f", pGate->tDelayMax ); // the max delay
+ fprintf( pFile, " " );
+ for ( i = 0; i < pMan->nVarsMax; i++ ) // the pin-to-pin delays
+ fprintf( pFile, " %5.2f", pGate->ptDelays[i]==SUPER_NO_VAR? 0.0 : pGate->ptDelays[i] );
+ fprintf( pFile, " %5.2f", pGate->Area ); // the area
+ fprintf( pFile, " " );
+ fprintf( pFile, "%s", Super_WriteLibraryGateName(pGate) ); // the symbolic expression
+ fprintf( pFile, "\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively generates symbolic name of the supergate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Super_WriteLibraryGateName( Super_Gate_t * pGate )
+{
+ static char Buffer[2000];
+ Buffer[0] = 0;
+ Super_WriteLibraryGateName_rec( pGate, Buffer );
+ return Buffer;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively generates symbolic name of the supergate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Super_WriteLibraryGateName_rec( Super_Gate_t * pGate, char * pBuffer )
+{
+ char Buffer[10];
+ int i;
+
+ if ( pGate->pRoot == NULL )
+ {
+ sprintf( Buffer, "%c", 'a' + pGate->Number );
+ strcat( pBuffer, Buffer );
+ return;
+ }
+ strcat( pBuffer, Mio_GateReadName(pGate->pRoot) );
+ strcat( pBuffer, "(" );
+ for ( i = 0; i < (int)pGate->nFanins; i++ )
+ {
+ if ( i )
+ strcat( pBuffer, "," );
+ Super_WriteLibraryGateName_rec( pGate->pFanins[i], pBuffer );
+ }
+ strcat( pBuffer, ")" );
+}
+
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Recursively writes the gates.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Super_WriteLibraryTree( Super_Man_t * pMan )
+{
+ Super_Gate_t * pSuper;
+ FILE * pFile;
+ char FileName[100];
+ char * pNameGeneric;
+ int i, Counter;
+ int posStart;
+
+ // get the file name
+ pNameGeneric = Extra_FileNameGeneric( pMan->pName );
+ sprintf( FileName, "%s.super", pNameGeneric );
+ free( pNameGeneric );
+
+ // write the elementary variables
+ pFile = fopen( FileName, "w" );
+ Super_WriteFileHeader( pMan, pFile );
+ // write the place holder for the number of lines
+ posStart = ftell( pFile );
+ fprintf( pFile, " \n" );
+ // mark the real supergates
+ Super_ManForEachGate( pMan->pGates, pMan->nGates, i, pSuper )
+ pSuper->fSuper = 1;
+ // write the supergates
+ Counter = pMan->nVarsMax;
+ Super_ManForEachGate( pMan->pGates, pMan->nGates, i, pSuper )
+ Super_WriteLibraryTree_rec( pFile, pMan, pSuper, &Counter );
+ fclose( pFile );
+ // write the number of lines
+ pFile = fopen( FileName, "rb+" );
+ fseek( pFile, posStart, SEEK_SET );
+ fprintf( pFile, "%d", Counter );
+ fclose( pFile );
+
+if ( pMan->fVerbose )
+{
+ printf( "The supergates are written using new format \"%s\" ", FileName );
+ printf( "(%0.3f Mb).\n", ((double)Extra_FileSize(FileName))/(1<<20) );
+}
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively writes the gate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Super_WriteLibraryTree_rec( FILE * pFile, Super_Man_t * pMan, Super_Gate_t * pSuper, int * pCounter )
+{
+ int nFanins, i;
+ // skip an elementary variable and a gate that was already written
+ if ( pSuper->fVar || pSuper->Number > 0 )
+ return;
+ // write the fanins
+ nFanins = Mio_GateReadInputs(pSuper->pRoot);
+ for ( i = 0; i < nFanins; i++ )
+ Super_WriteLibraryTree_rec( pFile, pMan, pSuper->pFanins[i], pCounter );
+ // finally write the gate
+ pSuper->Number = (*pCounter)++;
+ fprintf( pFile, "%s", pSuper->fSuper? "* " : "" );
+ fprintf( pFile, "%s", Mio_GateReadName(pSuper->pRoot) );
+ for ( i = 0; i < nFanins; i++ )
+ fprintf( pFile, " %d", pSuper->pFanins[i]->Number );
+ // write the formula
+ // this step is optional, the resulting library will work in any case
+ // however, it may be helpful to for debugging to compare the same library
+ // written in the old format and written in the new format with formulas
+// fprintf( pFile, " # %s", Super_WriteLibraryGateName( pSuper ) );
+ fprintf( pFile, "\n" );
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/map/super/superInt.h b/src/map/super/superInt.h
new file mode 100644
index 00000000..686c8739
--- /dev/null
+++ b/src/map/super/superInt.h
@@ -0,0 +1,62 @@
+/**CFile****************************************************************
+
+ FileName [superInt.h]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Pre-computation of supergates.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - September 8, 2003.]
+
+ Revision [$Id: superInt.h,v 1.4 2004/07/06 04:55:59 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __super_INT_H__
+#define __super_INT_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+#include "abc.h"
+#include "mainInt.h"
+#include "mvc.h"
+#include "mio.h"
+#include "stmm.h"
+#include "super.h"
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// GLOBAL VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== superAnd.c =============================================================*/
+extern void Super2_Precompute( int nInputs, int nLevels, int fVerbose );
+/*=== superGate.c =============================================================*/
+extern void Super_Precompute( Mio_Library_t * pLibGen, int nInputs, int nLevels, float tDelayMax, float tAreaMax, int TimeLimit, bool fSkipInv, bool fWriteOldFormat, int fVerbose );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
diff --git a/src/map/super/superWrite.c b/src/map/super/superWrite.c
new file mode 100644
index 00000000..a0e85604
--- /dev/null
+++ b/src/map/super/superWrite.c
@@ -0,0 +1,76 @@
+/**CFile****************************************************************
+
+ FileName [superWrite.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Pre-computation of supergates.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - September 8, 2003.]
+
+ Revision [$Id: superWrite.c,v 1.1 2004/04/03 01:36:45 alanmi Exp $]
+
+***********************************************************************/
+
+#include "superInt.h"
+
+/*
+ One record in the supergate library file consists of:
+
+ <gate_number> <truth_table> <delay_max> <pin-to-pin-delays> <area> <gate_formula>
+
+ <gate_number> is a zero-based integer
+ <truth_table> is a string of 2^n bits representing the value of the function for each minterm
+ <delay_max> is the maximum delay of the gate
+ <pin-to-pin-delays> is the array of n double values
+ <area> is a floating point value
+ <gate_formula> is the string representing the gate in the following format:
+ GATENAME1( GATENAME2( a, c ), GATENAME3( a, d ), ... )
+ The gate names (GATENAME1, etc) are the names as they appear in the .genlib library.
+ The primary inputs of the gates are denoted by lowercase chars 'a', 'b', etc.
+ The parantheses are mandatory for each gate, except for the wire.
+ The wire name can be omitted, so that "a" can be used instead of "**wire**( a )".
+ The spaces are optional in any position of this string.
+
+
+ The supergates are generated exhaustively from all gate combinations that
+ have the max delay lower than the delay given by the user, or until the specified time
+ limit is reached.
+
+ The supergates are stored in supergate classes by their functionality.
+ Among the gates with the equivalent functionaly only those are dropped, which are
+ dominated by at least one other gate in the class in terms of both delay and area.
+ For the definition of gate dominance see pliGenCheckDominance().
+*/
+
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/misc/extra/extra.h b/src/misc/extra/extra.h
new file mode 100644
index 00000000..ec4023b0
--- /dev/null
+++ b/src/misc/extra/extra.h
@@ -0,0 +1,220 @@
+/**CFile****************************************************************
+
+ FileName [extra.h]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [extra]
+
+ Synopsis [Various reusable software utilities.]
+
+ Description [This library contains a number of operators and
+ traversal routines developed to extend the functionality of
+ CUDD v.2.3.x, by Fabio Somenzi (http://vlsi.colorado.edu/~fabio/)
+ To compile your code with the library, #include "extra.h"
+ in your source files and link your project to CUDD and this
+ library. Use the library at your own risk and with caution.
+ Note that debugging of some operators still continues.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: extra.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __EXTRA_H__
+#define __EXTRA_H__
+
+#ifdef _WIN32
+#define inline __inline // compatible with MS VS 6.0
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Nested includes */
+/*---------------------------------------------------------------------------*/
+
+#include <string.h>
+#include <time.h>
+#include "util.h"
+#include "st.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/* constants of the manager */
+#define b0 Cudd_Not((dd)->one)
+#define b1 (dd)->one
+#define z0 (dd)->zero
+#define z1 (dd)->one
+#define a0 (dd)->zero
+#define a1 (dd)->one
+
+// hash key macros
+#define hashKey1(a,TSIZE) \
+((unsigned)(a) % TSIZE)
+
+#define hashKey2(a,b,TSIZE) \
+(((unsigned)(a) + (unsigned)(b) * DD_P1) % TSIZE)
+
+#define hashKey3(a,b,c,TSIZE) \
+(((((unsigned)(a) + (unsigned)(b)) * DD_P1 + (unsigned)(c)) * DD_P2 ) % TSIZE)
+
+#define hashKey4(a,b,c,d,TSIZE) \
+((((((unsigned)(a) + (unsigned)(b)) * DD_P1 + (unsigned)(c)) * DD_P2 + \
+ (unsigned)(d)) * DD_P3) % TSIZE)
+
+#define hashKey5(a,b,c,d,e,TSIZE) \
+(((((((unsigned)(a) + (unsigned)(b)) * DD_P1 + (unsigned)(c)) * DD_P2 + \
+ (unsigned)(d)) * DD_P3 + (unsigned)(e)) * DD_P1) % TSIZE)
+
+/*===========================================================================*/
+/* Various Utilities */
+/*===========================================================================*/
+
+/*=== extraUtilBdd.c ========================================================*/
+extern DdNode * Extra_TransferPermute( DdManager * ddSource, DdManager * ddDestination, DdNode * f, int * Permute );
+extern DdNode * Extra_TransferLevelByLevel( DdManager * ddSource, DdManager * ddDestination, DdNode * f );
+extern DdNode * Extra_bddRemapUp( DdManager * dd, DdNode * bF );
+extern DdNode * Extra_bddMove( DdManager * dd, DdNode * bF, int fShiftUp );
+extern DdNode * extraBddMove( DdManager * dd, DdNode * bF, DdNode * bFlag );
+extern void Extra_StopManager( DdManager * dd );
+extern void Extra_bddPrint( DdManager * dd, DdNode * F );
+extern void extraDecomposeCover( DdManager* dd, DdNode* zC, DdNode** zC0, DdNode** zC1, DdNode** zC2 );
+extern int Extra_bddSuppSize( DdManager * dd, DdNode * bSupp );
+extern int Extra_bddSuppContainVar( DdManager * dd, DdNode * bS, DdNode * bVar );
+extern int Extra_bddSuppOverlapping( DdManager * dd, DdNode * S1, DdNode * S2 );
+extern int Extra_bddSuppDifferentVars( DdManager * dd, DdNode * S1, DdNode * S2, int DiffMax );
+extern int Extra_bddSuppCheckContainment( DdManager * dd, DdNode * bL, DdNode * bH, DdNode ** bLarge, DdNode ** bSmall );
+extern int * Extra_SupportArray( DdManager * dd, DdNode * F, int * support );
+extern int * Extra_VectorSupportArray( DdManager * dd, DdNode ** F, int n, int * support );
+extern DdNode * Extra_bddFindOneCube( DdManager * dd, DdNode * bF );
+extern DdNode * Extra_bddGetOneCube( DdManager * dd, DdNode * bFunc );
+
+/*=== extraUtilFile.c ========================================================*/
+
+extern char * Extra_FileGetSimilarName( char * pFileNameWrong, char * pS1, char * pS2, char * pS3, char * pS4, char * pS5 );
+extern int Extra_FileNameCheckExtension( char * FileName, char * Extension );
+extern char * Extra_FileNameAppend( char * pBase, char * pSuffix );
+extern char * Extra_FileNameGeneric( char * FileName );
+extern int Extra_FileSize( char * pFileName );
+extern char * Extra_FileRead( FILE * pFile );
+extern char * Extra_TimeStamp();
+extern char * Extra_StringAppend( char * pStrGiven, char * pStrAdd );
+extern unsigned Extra_ReadBinary( char * Buffer );
+extern void Extra_PrintBinary( FILE * pFile, unsigned Sign[], int nBits );
+extern void Extra_PrintSymbols( FILE * pFile, char Char, int nTimes, int fPrintNewLine );
+
+/*=== extraUtilReader.c ========================================================*/
+
+typedef struct Extra_FileReader_t_ Extra_FileReader_t;
+extern Extra_FileReader_t * Extra_FileReaderAlloc( char * pFileName,
+ char * pCharsComment, char * pCharsStop, char * pCharsClean );
+extern void Extra_FileReaderFree( Extra_FileReader_t * p );
+extern char * Extra_FileReaderGetFileName( Extra_FileReader_t * p );
+extern int Extra_FileReaderGetFileSize( Extra_FileReader_t * p );
+extern int Extra_FileReaderGetCurPosition( Extra_FileReader_t * p );
+extern void * Extra_FileReaderGetTokens( Extra_FileReader_t * p );
+extern int Extra_FileReaderGetLineNumber( Extra_FileReader_t * p, int iToken );
+
+/*=== extraUtilMemory.c ========================================================*/
+
+typedef struct Extra_MmFixed_t_ Extra_MmFixed_t;
+typedef struct Extra_MmFlex_t_ Extra_MmFlex_t;
+typedef struct Extra_MmStep_t_ Extra_MmStep_t;
+
+// fixed-size-block memory manager
+extern Extra_MmFixed_t * Extra_MmFixedStart( int nEntrySize );
+extern void Extra_MmFixedStop( Extra_MmFixed_t * p, int fVerbose );
+extern char * Extra_MmFixedEntryFetch( Extra_MmFixed_t * p );
+extern void Extra_MmFixedEntryRecycle( Extra_MmFixed_t * p, char * pEntry );
+extern void Extra_MmFixedRestart( Extra_MmFixed_t * p );
+extern int Extra_MmFixedReadMemUsage( Extra_MmFixed_t * p );
+// flexible-size-block memory manager
+extern Extra_MmFlex_t * Extra_MmFlexStart();
+extern void Extra_MmFlexStop( Extra_MmFlex_t * p, int fVerbose );
+extern char * Extra_MmFlexEntryFetch( Extra_MmFlex_t * p, int nBytes );
+extern int Extra_MmFlexReadMemUsage( Extra_MmFlex_t * p );
+// hierarchical memory manager
+extern Extra_MmStep_t * Extra_MmStepStart( int nSteps );
+extern void Extra_MmStepStop( Extra_MmStep_t * p, int fVerbose );
+extern char * Extra_MmStepEntryFetch( Extra_MmStep_t * p, int nBytes );
+extern void Extra_MmStepEntryRecycle( Extra_MmStep_t * p, char * pEntry, int nBytes );
+extern int Extra_MmStepReadMemUsage( Extra_MmStep_t * p );
+
+/*=== extraUtilMisc.c ========================================================*/
+
+/* finds the smallest integer larger of equal than the logarithm. */
+extern int Extra_Base2Log( unsigned Num );
+extern int Extra_Base2LogDouble( double Num );
+extern int Extra_Base10Log( unsigned Num );
+/* returns the power of two as a double */
+extern double Extra_Power2( int Num );
+extern int Extra_Power3( int Num );
+/* the number of combinations of k elements out of n */
+extern int Extra_NumCombinations( int k, int n );
+extern int * Extra_DeriveRadixCode( int Number, int Radix, int nDigits );
+/* the factorial of number */
+extern int Extra_Factorial( int n );
+/* the permutation of the given number of elements */
+extern char ** Extra_Permutations( int n );
+extern unsigned int Cudd_PrimeCopy( unsigned int p );
+
+/*=== extraUtilProgress.c ================================================================*/
+
+typedef struct ProgressBarStruct ProgressBar;
+
+extern ProgressBar * Extra_ProgressBarStart( FILE * pFile, int nItemsTotal );
+extern void Extra_ProgressBarStop( ProgressBar * p );
+extern void Extra_ProgressBarUpdate_int( ProgressBar * p, int nItemsCur, char * pString );
+
+static inline void Extra_ProgressBarUpdate( ProgressBar * p, int nItemsCur, char * pString )
+{ if ( nItemsCur < *((int*)p) ) return; Extra_ProgressBarUpdate_int(p, nItemsCur, pString); }
+
+/*=== extraUtilIntVec.c ================================================================*/
+
+typedef struct Extra_IntVec_t_ Extra_IntVec_t;
+extern Extra_IntVec_t * Extra_IntVecAlloc( int nCap );
+extern Extra_IntVec_t * Extra_IntVecAllocArray( int * pArray, int nSize );
+extern Extra_IntVec_t * Extra_IntVecAllocArrayCopy( int * pArray, int nSize );
+extern Extra_IntVec_t * Extra_IntVecDup( Extra_IntVec_t * pVec );
+extern Extra_IntVec_t * Extra_IntVecDupArray( Extra_IntVec_t * pVec );
+extern void Extra_IntVecFree( Extra_IntVec_t * p );
+extern void Extra_IntVecFill( Extra_IntVec_t * p, int nSize, int Entry );
+extern int * Extra_IntVecReleaseArray( Extra_IntVec_t * p );
+extern int * Extra_IntVecReadArray( Extra_IntVec_t * p );
+extern int Extra_IntVecReadSize( Extra_IntVec_t * p );
+extern int Extra_IntVecReadEntry( Extra_IntVec_t * p, int i );
+extern int Extra_IntVecReadEntryLast( Extra_IntVec_t * p );
+extern void Extra_IntVecWriteEntry( Extra_IntVec_t * p, int i, int Entry );
+extern void Extra_IntVecGrow( Extra_IntVec_t * p, int nCapMin );
+extern void Extra_IntVecShrink( Extra_IntVec_t * p, int nSizeNew );
+extern void Extra_IntVecClear( Extra_IntVec_t * p );
+extern void Extra_IntVecPush( Extra_IntVec_t * p, int Entry );
+extern int Extra_IntVecPop( Extra_IntVec_t * p );
+extern void Extra_IntVecSort( Extra_IntVec_t * p );
+
+/**AutomaticEnd***************************************************************/
+
+#endif /* __EXTRA_H__ */
diff --git a/src/misc/extra/extraUtilBdd.c b/src/misc/extra/extraUtilBdd.c
new file mode 100644
index 00000000..32fdca2c
--- /dev/null
+++ b/src/misc/extra/extraUtilBdd.c
@@ -0,0 +1,1018 @@
+/**CFile****************************************************************
+
+ FileName [extraUtilBdd.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [extra]
+
+ Synopsis [DD-based utilities.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: extraUtilBdd.c,v 1.0 2003/09/01 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "extra.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+// file "extraDdTransfer.c"
+static DdNode * extraTransferPermuteRecur( DdManager * ddS, DdManager * ddD, DdNode * f, st_table * table, int * Permute );
+static DdNode * extraTransferPermute( DdManager * ddS, DdManager * ddD, DdNode * f, int * Permute );
+
+// file "cuddUtils.c"
+static void ddSupportStep ARGS((DdNode *f, int *support));
+static void ddClearFlag ARGS((DdNode *f));
+
+/**AutomaticEnd***************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Convert a {A,B}DD from a manager to another with variable remapping.]
+
+ Description [Convert a {A,B}DD from a manager to another one. The orders of the
+ variables in the two managers may be different. Returns a
+ pointer to the {A,B}DD in the destination manager if successful; NULL
+ otherwise. The i-th entry in the array Permute tells what is the index
+ of the i-th variable from the old manager in the new manager.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode * Extra_TransferPermute( DdManager * ddSource, DdManager * ddDestination, DdNode * f, int * Permute )
+{
+ DdNode * bRes;
+ do
+ {
+ ddDestination->reordered = 0;
+ bRes = extraTransferPermute( ddSource, ddDestination, f, Permute );
+ }
+ while ( ddDestination->reordered == 1 );
+ return ( bRes );
+
+} /* end of Extra_TransferPermute */
+
+/**Function********************************************************************
+
+ Synopsis [Transfers the BDD from one manager into another level by level.]
+
+ Description [Transfers the BDD from one manager into another while
+ preserving the correspondence between variables level by level.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode * Extra_TransferLevelByLevel( DdManager * ddSource, DdManager * ddDestination, DdNode * f )
+{
+ DdNode * bRes;
+ int * pPermute;
+ int nMin, nMax, i;
+
+ nMin = ddMin(ddSource->size, ddDestination->size);
+ nMax = ddMax(ddSource->size, ddDestination->size);
+ pPermute = ALLOC( int, nMax );
+ // set up the variable permutation
+ for ( i = 0; i < nMin; i++ )
+ pPermute[ ddSource->invperm[i] ] = ddDestination->invperm[i];
+ if ( ddSource->size > ddDestination->size )
+ {
+ for ( ; i < nMax; i++ )
+ pPermute[ ddSource->invperm[i] ] = -1;
+ }
+ bRes = Extra_TransferPermute( ddSource, ddDestination, f, pPermute );
+ FREE( pPermute );
+ return bRes;
+}
+
+/**Function********************************************************************
+
+ Synopsis [Remaps the function to depend on the topmost variables on the manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode * Extra_bddRemapUp(
+ DdManager * dd,
+ DdNode * bF )
+{
+ int * pPermute;
+ DdNode * bSupp, * bTemp, * bRes;
+ int Counter;
+
+ pPermute = ALLOC( int, dd->size );
+
+ // get support
+ bSupp = Cudd_Support( dd, bF ); Cudd_Ref( bSupp );
+
+ // create the variable map
+ // to remap the DD into the upper part of the manager
+ Counter = 0;
+ for ( bTemp = bSupp; bTemp != dd->one; bTemp = cuddT(bTemp) )
+ pPermute[bTemp->index] = dd->invperm[Counter++];
+
+ // transfer the BDD and remap it
+ bRes = Cudd_bddPermute( dd, bF, pPermute ); Cudd_Ref( bRes );
+
+ // remove support
+ Cudd_RecursiveDeref( dd, bSupp );
+
+ // return
+ Cudd_Deref( bRes );
+ free( pPermute );
+ return bRes;
+}
+
+/**Function********************************************************************
+
+ Synopsis [Moves the BDD by the given number of variables up or down.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso [Extra_bddShift]
+
+******************************************************************************/
+DdNode * Extra_bddMove(
+ DdManager * dd, /* the DD manager */
+ DdNode * bF,
+ int nVars)
+{
+ DdNode * res;
+ DdNode * bVars;
+ if ( nVars == 0 )
+ return bF;
+ if ( Cudd_IsConstant(bF) )
+ return bF;
+ assert( nVars <= dd->size );
+ if ( nVars > 0 )
+ bVars = dd->vars[nVars];
+ else
+ bVars = Cudd_Not(dd->vars[-nVars]);
+
+ do {
+ dd->reordered = 0;
+ res = extraBddMove( dd, bF, bVars );
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Extra_bddMove */
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_StopManager( DdManager * dd )
+{
+ int RetValue;
+ // check for remaining references in the package
+ RetValue = Cudd_CheckZeroRef( dd );
+ if ( RetValue > 0 )
+ printf( "\nThe number of referenced nodes = %d\n\n", RetValue );
+// Cudd_PrintInfo( dd, stdout );
+ Cudd_Quit( dd );
+}
+
+/**Function********************************************************************
+
+ Synopsis [Outputs the BDD in a readable format.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void Extra_bddPrint( DdManager * dd, DdNode * F )
+{
+ DdGen * Gen;
+ int * Cube;
+ CUDD_VALUE_TYPE Value;
+ int nVars = dd->size;
+ int fFirstCube = 1;
+ int i;
+
+ if ( F == NULL )
+ {
+ printf("NULL");
+ return;
+ }
+ if ( F == b0 )
+ {
+ printf("Constant 0");
+ return;
+ }
+ if ( F == b1 )
+ {
+ printf("Constant 1");
+ return;
+ }
+
+ Cudd_ForeachCube( dd, F, Gen, Cube, Value )
+ {
+ if ( fFirstCube )
+ fFirstCube = 0;
+ else
+// Output << " + ";
+ printf( " + " );
+
+ for ( i = 0; i < nVars; i++ )
+ if ( Cube[i] == 0 )
+ printf( "[%d]'", i );
+// printf( "%c'", (char)('a'+i) );
+ else if ( Cube[i] == 1 )
+ printf( "[%d]", i );
+// printf( "%c", (char)('a'+i) );
+ }
+
+// printf("\n");
+}
+/**Function********************************************************************
+
+ Synopsis [Returns the size of the support.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int Extra_bddSuppSize( DdManager * dd, DdNode * bSupp )
+{
+ int Counter = 0;
+ while ( bSupp != b1 )
+ {
+ assert( !Cudd_IsComplement(bSupp) );
+ assert( cuddE(bSupp) == b0 );
+
+ bSupp = cuddT(bSupp);
+ Counter++;
+ }
+ return Counter;
+}
+
+/**Function********************************************************************
+
+ Synopsis [Returns 1 if the support contains the given BDD variable.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int Extra_bddSuppContainVar( DdManager * dd, DdNode * bS, DdNode * bVar )
+{
+ for( ; bS != b1; bS = cuddT(bS) )
+ if ( bS->index == bVar->index )
+ return 1;
+ return 0;
+}
+
+/**Function********************************************************************
+
+ Synopsis [Returns 1 if two supports represented as BDD cubes are overlapping.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int Extra_bddSuppOverlapping( DdManager * dd, DdNode * S1, DdNode * S2 )
+{
+ while ( S1->index != CUDD_CONST_INDEX && S2->index != CUDD_CONST_INDEX )
+ {
+ // if the top vars are the same, they intersect
+ if ( S1->index == S2->index )
+ return 1;
+ // if the top vars are different, skip the one, which is higher
+ if ( dd->perm[S1->index] < dd->perm[S2->index] )
+ S1 = cuddT(S1);
+ else
+ S2 = cuddT(S2);
+ }
+ return 0;
+}
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of different vars in two supports.]
+
+ Description [Counts the number of variables that appear in one support and
+ does not appear in other support. If the number exceeds DiffMax, returns DiffMax.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int Extra_bddSuppDifferentVars( DdManager * dd, DdNode * S1, DdNode * S2, int DiffMax )
+{
+ int Result = 0;
+ while ( S1->index != CUDD_CONST_INDEX && S2->index != CUDD_CONST_INDEX )
+ {
+ // if the top vars are the same, this var is the same
+ if ( S1->index == S2->index )
+ {
+ S1 = cuddT(S1);
+ S2 = cuddT(S2);
+ continue;
+ }
+ // the top var is different
+ Result++;
+
+ if ( Result >= DiffMax )
+ return DiffMax;
+
+ // if the top vars are different, skip the one, which is higher
+ if ( dd->perm[S1->index] < dd->perm[S2->index] )
+ S1 = cuddT(S1);
+ else
+ S2 = cuddT(S2);
+ }
+
+ // consider the remaining variables
+ if ( S1->index != CUDD_CONST_INDEX )
+ Result += Extra_bddSuppSize(dd,S1);
+ else if ( S2->index != CUDD_CONST_INDEX )
+ Result += Extra_bddSuppSize(dd,S2);
+
+ if ( Result >= DiffMax )
+ return DiffMax;
+ return Result;
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks the support containment.]
+
+ Description [This function returns 1 if one support is contained in another.
+ In this case, bLarge (bSmall) is assigned to point to the larger (smaller) support.
+ If the supports are identical, return 0 and does not assign the supports!]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int Extra_bddSuppCheckContainment( DdManager * dd, DdNode * bL, DdNode * bH, DdNode ** bLarge, DdNode ** bSmall )
+{
+ DdNode * bSL = bL;
+ DdNode * bSH = bH;
+ int fLcontainsH = 1;
+ int fHcontainsL = 1;
+ int TopVar;
+
+ if ( bSL == bSH )
+ return 0;
+
+ while ( bSL != b1 || bSH != b1 )
+ {
+ if ( bSL == b1 )
+ { // Low component has no vars; High components has some vars
+ fLcontainsH = 0;
+ if ( fHcontainsL == 0 )
+ return 0;
+ else
+ break;
+ }
+
+ if ( bSH == b1 )
+ { // similarly
+ fHcontainsL = 0;
+ if ( fLcontainsH == 0 )
+ return 0;
+ else
+ break;
+ }
+
+ // determine the topmost var of the supports by comparing their levels
+ if ( dd->perm[bSL->index] < dd->perm[bSH->index] )
+ TopVar = bSL->index;
+ else
+ TopVar = bSH->index;
+
+ if ( TopVar == bSL->index && TopVar == bSH->index )
+ { // they are on the same level
+ // it does not tell us anything about their containment
+ // skip this var
+ bSL = cuddT(bSL);
+ bSH = cuddT(bSH);
+ }
+ else if ( TopVar == bSL->index ) // and TopVar != bSH->index
+ { // Low components is higher and contains more vars
+ // it is not possible that High component contains Low
+ fHcontainsL = 0;
+ // skip this var
+ bSL = cuddT(bSL);
+ }
+ else // if ( TopVar == bSH->index ) // and TopVar != bSL->index
+ { // similarly
+ fLcontainsH = 0;
+ // skip this var
+ bSH = cuddT(bSH);
+ }
+
+ // check the stopping condition
+ if ( !fHcontainsL && !fLcontainsH )
+ return 0;
+ }
+ // only one of them can be true at the same time
+ assert( !fHcontainsL || !fLcontainsH );
+ if ( fHcontainsL )
+ {
+ *bLarge = bH;
+ *bSmall = bL;
+ }
+ else // fLcontainsH
+ {
+ *bLarge = bL;
+ *bSmall = bH;
+ }
+ return 1;
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds variables on which the DD depends and returns them as am array.]
+
+ Description [Finds the variables on which the DD depends. Returns an array
+ with entries set to 1 for those variables that belong to the support;
+ NULL otherwise. The array is allocated by the user and should have at least
+ as many entries as the maximum number of variables in BDD and ZDD parts of
+ the manager.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Support Cudd_VectorSupport Cudd_ClassifySupport]
+
+******************************************************************************/
+int *
+Extra_SupportArray(
+ DdManager * dd, /* manager */
+ DdNode * f, /* DD whose support is sought */
+ int * support ) /* array allocated by the user */
+{
+ int i, size;
+
+ /* Initialize support array for ddSupportStep. */
+ size = ddMax(dd->size, dd->sizeZ);
+ 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 Extra_SupportArray */
+
+/**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]
+
+******************************************************************************/
+int *
+Extra_VectorSupportArray(
+ DdManager * dd, /* manager */
+ DdNode ** F, /* array of DDs whose support is sought */
+ int n, /* size of the array */
+ int * support ) /* array allocated by the user */
+{
+ int i, size;
+
+ /* Allocate and initialize support array for ddSupportStep. */
+ size = ddMax( dd->size, dd->sizeZ );
+ 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;
+}
+
+/**Function********************************************************************
+
+ Synopsis [Find any cube belonging to the on-set of the function.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode * Extra_bddFindOneCube( DdManager * dd, DdNode * bF )
+{
+ char * s_Temp;
+ DdNode * bCube, * bTemp;
+ int v;
+
+ // get the vector of variables in the cube
+ s_Temp = ALLOC( char, dd->size );
+ Cudd_bddPickOneCube( dd, bF, s_Temp );
+
+ // start the cube
+ bCube = b1; Cudd_Ref( bCube );
+ for ( v = 0; v < dd->size; v++ )
+ if ( s_Temp[v] == 0 )
+ {
+// Cube &= !s_XVars[v];
+ bCube = Cudd_bddAnd( dd, bTemp = bCube, Cudd_Not(dd->vars[v]) ); Cudd_Ref( bCube );
+ Cudd_RecursiveDeref( dd, bTemp );
+ }
+ else if ( s_Temp[v] == 1 )
+ {
+// Cube &= s_XVars[v];
+ bCube = Cudd_bddAnd( dd, bTemp = bCube, dd->vars[v] ); Cudd_Ref( bCube );
+ Cudd_RecursiveDeref( dd, bTemp );
+ }
+ Cudd_Deref(bCube);
+ free( s_Temp );
+ return bCube;
+}
+
+/**Function********************************************************************
+
+ Synopsis [Returns one cube contained in the given BDD.]
+
+ Description [This function returns the cube with the smallest
+ bits-to-integer value.]
+
+ SideEffects []
+
+******************************************************************************/
+DdNode * Extra_bddGetOneCube( DdManager * dd, DdNode * bFunc )
+{
+ DdNode * bFuncR, * bFunc0, * bFunc1;
+ DdNode * bRes0, * bRes1, * bRes;
+
+ bFuncR = Cudd_Regular(bFunc);
+ if ( cuddIsConstant(bFuncR) )
+ return bFunc;
+
+ // cofactor
+ if ( Cudd_IsComplement(bFunc) )
+ {
+ bFunc0 = Cudd_Not( cuddE(bFuncR) );
+ bFunc1 = Cudd_Not( cuddT(bFuncR) );
+ }
+ else
+ {
+ bFunc0 = cuddE(bFuncR);
+ bFunc1 = cuddT(bFuncR);
+ }
+
+ // try to find the cube with the negative literal
+ bRes0 = Extra_bddGetOneCube( dd, bFunc0 ); Cudd_Ref( bRes0 );
+
+ if ( bRes0 != b0 )
+ {
+ bRes = Cudd_bddAnd( dd, bRes0, Cudd_Not(dd->vars[bFuncR->index]) ); Cudd_Ref( bRes );
+ Cudd_RecursiveDeref( dd, bRes0 );
+ }
+ else
+ {
+ Cudd_RecursiveDeref( dd, bRes0 );
+ // try to find the cube with the positive literal
+ bRes1 = Extra_bddGetOneCube( dd, bFunc1 ); Cudd_Ref( bRes1 );
+ assert( bRes1 != b0 );
+ bRes = Cudd_bddAnd( dd, bRes1, dd->vars[bFuncR->index] ); Cudd_Ref( bRes );
+ Cudd_RecursiveDeref( dd, bRes1 );
+ }
+
+ Cudd_Deref( bRes );
+ return bRes;
+}
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Performs the reordering-sensitive step of Extra_bddMove().]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode * extraBddMove(
+ DdManager * dd, /* the DD manager */
+ DdNode * bF,
+ DdNode * bDist)
+{
+ DdNode * bRes;
+
+ if ( Cudd_IsConstant(bF) )
+ return bF;
+
+ if ( bRes = cuddCacheLookup2(dd, extraBddMove, bF, bDist) )
+ return bRes;
+ else
+ {
+ DdNode * bRes0, * bRes1;
+ DdNode * bF0, * bF1;
+ DdNode * bFR = Cudd_Regular(bF);
+ int VarNew;
+
+ if ( Cudd_IsComplement(bDist) )
+ VarNew = bFR->index - Cudd_Not(bDist)->index;
+ else
+ VarNew = bFR->index + bDist->index;
+ assert( VarNew < dd->size );
+
+ // cofactor the functions
+ if ( bFR != bF ) // bFunc is complemented
+ {
+ bF0 = Cudd_Not( cuddE(bFR) );
+ bF1 = Cudd_Not( cuddT(bFR) );
+ }
+ else
+ {
+ bF0 = cuddE(bFR);
+ bF1 = cuddT(bFR);
+ }
+
+ bRes0 = extraBddMove( dd, bF0, bDist );
+ if ( bRes0 == NULL )
+ return NULL;
+ cuddRef( bRes0 );
+
+ bRes1 = extraBddMove( dd, bF1, bDist );
+ if ( bRes1 == NULL )
+ {
+ Cudd_RecursiveDeref( dd, bRes0 );
+ return NULL;
+ }
+ cuddRef( bRes1 );
+
+ /* only bRes0 and bRes1 are referenced at this point */
+ bRes = cuddBddIteRecur( dd, dd->vars[VarNew], bRes1, bRes0 );
+ if ( bRes == NULL )
+ {
+ Cudd_RecursiveDeref( dd, bRes0 );
+ Cudd_RecursiveDeref( dd, bRes1 );
+ return NULL;
+ }
+ cuddRef( bRes );
+ Cudd_RecursiveDeref( dd, bRes0 );
+ Cudd_RecursiveDeref( dd, bRes1 );
+
+ /* insert the result into cache */
+ cuddCacheInsert2( dd, extraBddMove, bF, bDist, bRes );
+ cuddDeref( bRes );
+ return bRes;
+ }
+} /* end of extraBddMove */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds three cofactors of the cover w.r.t. to the topmost variable.]
+
+ Description [Finds three cofactors of the cover w.r.t. to the topmost variable.
+ Does not check the cover for being a constant. Assumes that ZDD variables encoding
+ positive and negative polarities are adjacent in the variable order. Is different
+ from cuddZddGetCofactors3() in that it does not compute the cofactors w.r.t. the
+ given variable but takes the cofactors with respent to the topmost variable.
+ This function is more efficient when used in recursive procedures because it does
+ not require referencing of the resulting cofactors (compare cuddZddProduct()
+ and extraZddPrimeProduct()).]
+
+ SideEffects [None]
+
+ SeeAlso [cuddZddGetCofactors3]
+
+******************************************************************************/
+void
+extraDecomposeCover(
+ DdManager* dd, /* the manager */
+ DdNode* zC, /* the cover */
+ DdNode** zC0, /* the pointer to the negative var cofactor */
+ DdNode** zC1, /* the pointer to the positive var cofactor */
+ DdNode** zC2 ) /* the pointer to the cofactor without var */
+{
+ if ( (zC->index & 1) == 0 )
+ { /* the top variable is present in positive polarity and maybe in negative */
+
+ DdNode *Temp = cuddE( zC );
+ *zC1 = cuddT( zC );
+ if ( cuddIZ(dd,Temp->index) == cuddIZ(dd,zC->index) + 1 )
+ { /* Temp is not a terminal node
+ * top var is present in negative polarity */
+ *zC2 = cuddE( Temp );
+ *zC0 = cuddT( Temp );
+ }
+ else
+ { /* top var is not present in negative polarity */
+ *zC2 = Temp;
+ *zC0 = dd->zero;
+ }
+ }
+ else
+ { /* the top variable is present only in negative */
+ *zC1 = dd->zero;
+ *zC2 = cuddE( zC );
+ *zC0 = cuddT( zC );
+ }
+} /* extraDecomposeCover */
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static Functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Convert a BDD from a manager to another one.]
+
+ Description [Convert a BDD from a manager to another one. Returns a
+ pointer to the BDD in the destination manager if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Extra_TransferPermute]
+
+******************************************************************************/
+DdNode * extraTransferPermute( DdManager * ddS, DdManager * ddD, DdNode * f, int * Permute )
+{
+ DdNode *res;
+ st_table *table = NULL;
+ st_generator *gen = NULL;
+ DdNode *key, *value;
+
+ table = st_init_table( st_ptrcmp, st_ptrhash );
+ if ( table == NULL )
+ goto failure;
+ res = extraTransferPermuteRecur( ddS, ddD, f, table, Permute );
+ if ( res != NULL )
+ cuddRef( res );
+
+ /* Dereference all elements in the table and dispose of the table.
+ ** This must be done also if res is NULL to avoid leaks in case of
+ ** reordering. */
+ gen = st_init_gen( table );
+ if ( gen == NULL )
+ goto failure;
+ while ( st_gen( gen, ( char ** ) &key, ( char ** ) &value ) )
+ {
+ Cudd_RecursiveDeref( ddD, value );
+ }
+ st_free_gen( gen );
+ gen = NULL;
+ st_free_table( table );
+ table = NULL;
+
+ if ( res != NULL )
+ cuddDeref( res );
+ return ( res );
+
+ failure:
+ if ( table != NULL )
+ st_free_table( table );
+ if ( gen != NULL )
+ st_free_gen( gen );
+ return ( NULL );
+
+} /* end of extraTransferPermute */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Extra_TransferPermute.]
+
+ Description [Performs the recursive step of Extra_TransferPermute.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [extraTransferPermute]
+
+******************************************************************************/
+static DdNode *
+extraTransferPermuteRecur(
+ DdManager * ddS,
+ DdManager * ddD,
+ DdNode * f,
+ st_table * table,
+ int * Permute )
+{
+ DdNode *ft, *fe, *t, *e, *var, *res;
+ DdNode *one, *zero;
+ int index;
+ int comple = 0;
+
+ statLine( ddD );
+ one = DD_ONE( ddD );
+ comple = Cudd_IsComplement( f );
+
+ /* Trivial cases. */
+ if ( Cudd_IsConstant( f ) )
+ return ( Cudd_NotCond( one, comple ) );
+
+
+ /* Make canonical to increase the utilization of the cache. */
+ f = Cudd_NotCond( f, comple );
+ /* Now f is a regular pointer to a non-constant node. */
+
+ /* Check the cache. */
+ if ( st_lookup( table, ( char * ) f, ( char ** ) &res ) )
+ return ( Cudd_NotCond( res, comple ) );
+
+ /* Recursive step. */
+ if ( Permute )
+ index = Permute[f->index];
+ else
+ index = f->index;
+
+ ft = cuddT( f );
+ fe = cuddE( f );
+
+ t = extraTransferPermuteRecur( ddS, ddD, ft, table, Permute );
+ if ( t == NULL )
+ {
+ return ( NULL );
+ }
+ cuddRef( t );
+
+ e = extraTransferPermuteRecur( ddS, ddD, fe, table, Permute );
+ if ( e == NULL )
+ {
+ Cudd_RecursiveDeref( ddD, t );
+ return ( NULL );
+ }
+ cuddRef( e );
+
+ zero = Cudd_Not(ddD->one);
+ var = cuddUniqueInter( ddD, index, one, zero );
+ if ( var == NULL )
+ {
+ Cudd_RecursiveDeref( ddD, t );
+ Cudd_RecursiveDeref( ddD, e );
+ return ( NULL );
+ }
+ res = cuddBddIteRecur( ddD, var, t, e );
+
+ if ( res == NULL )
+ {
+ Cudd_RecursiveDeref( ddD, t );
+ Cudd_RecursiveDeref( ddD, e );
+ return ( NULL );
+ }
+ cuddRef( res );
+ Cudd_RecursiveDeref( ddD, t );
+ Cudd_RecursiveDeref( ddD, e );
+
+ if ( st_add_direct( table, ( char * ) f, ( char * ) res ) ==
+ ST_OUT_OF_MEM )
+ {
+ Cudd_RecursiveDeref( ddD, res );
+ return ( NULL );
+ }
+ return ( Cudd_NotCond( res, comple ) );
+
+} /* end of extraTransferPermuteRecur */
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_Support.]
+
+ Description [Performs the recursive step of Cudd_Support. Performs a
+ DFS from f. The support is accumulated in supp as a side effect. Uses
+ the LSB of the then pointer as visited flag.]
+
+ SideEffects [None]
+
+ SeeAlso [ddClearFlag]
+
+******************************************************************************/
+static void
+ddSupportStep(
+ DdNode * f,
+ int * support)
+{
+ if (cuddIsConstant(f) || Cudd_IsComplement(f->next)) {
+ return;
+ }
+
+ support[f->index] = 1;
+ ddSupportStep(cuddT(f),support);
+ ddSupportStep(Cudd_Regular(cuddE(f)),support);
+ /* Mark as visited. */
+ f->next = Cudd_Not(f->next);
+ return;
+
+} /* end of ddSupportStep */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs a DFS from f, clearing the LSB of the next
+ pointers.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [ddSupportStep ddDagInt]
+
+******************************************************************************/
+static void
+ddClearFlag(
+ DdNode * f)
+{
+ if (!Cudd_IsComplement(f->next)) {
+ return;
+ }
+ /* Clear visited flag. */
+ f->next = Cudd_Regular(f->next);
+ if (cuddIsConstant(f)) {
+ return;
+ }
+ ddClearFlag(cuddT(f));
+ ddClearFlag(Cudd_Regular(cuddE(f)));
+ return;
+
+} /* end of ddClearFlag */
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/misc/extra/extraUtilFile.c b/src/misc/extra/extraUtilFile.c
new file mode 100644
index 00000000..faf27dc8
--- /dev/null
+++ b/src/misc/extra/extraUtilFile.c
@@ -0,0 +1,382 @@
+/**CFile****************************************************************
+
+ FileName [extraUtilFile.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [extra]
+
+ Synopsis [File management utilities.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: extraUtilFile.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "extra.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function*************************************************************
+
+ Synopsis [Tries to find a file name with a different extension.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Extra_FileGetSimilarName( char * pFileNameWrong, char * pS1, char * pS2, char * pS3, char * pS4, char * pS5 )
+{
+ FILE * pFile;
+ char * pFileNameOther;
+ char * pFileGen;
+
+ if ( pS1 == NULL )
+ return NULL;
+
+ // get the generic file name
+ pFileGen = Extra_FileNameGeneric( pFileNameWrong );
+ pFileNameOther = Extra_FileNameAppend( pFileGen, pS1 );
+ pFile = fopen( pFileNameOther, "r" );
+ if ( pFile == NULL && pS2 )
+ { // try one more
+ pFileNameOther = Extra_FileNameAppend( pFileGen, pS2 );
+ pFile = fopen( pFileNameOther, "r" );
+ if ( pFile == NULL && pS3 )
+ { // try one more
+ pFileNameOther = Extra_FileNameAppend( pFileGen, pS3 );
+ pFile = fopen( pFileNameOther, "r" );
+ if ( pFile == NULL && pS4 )
+ { // try one more
+ pFileNameOther = Extra_FileNameAppend( pFileGen, pS4 );
+ pFile = fopen( pFileNameOther, "r" );
+ if ( pFile == NULL && pS5 )
+ { // try one more
+ pFileNameOther = Extra_FileNameAppend( pFileGen, pS5 );
+ pFile = fopen( pFileNameOther, "r" );
+ }
+ }
+ }
+ }
+ FREE( pFileGen );
+ if ( pFile )
+ {
+ fclose( pFile );
+ return pFileNameOther;
+ }
+ // did not find :(
+ return NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Extra_FileNameCheckExtension( char * FileName, char * Extension )
+{
+ char * pDot;
+ // find "dot" if it is present in the file name
+// pDot = strstr( FileName, "." );
+ for ( pDot = FileName + strlen(FileName)-1; pDot >= FileName; pDot-- )
+ if ( *pDot == '.' )
+ break;
+ if ( *pDot != '.' )
+ return 0;
+ // check the extension
+ if ( pDot && strcmp( pDot+1, Extension ) == 0 )
+ return 1;
+ else
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the composite name of the file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Extra_FileNameAppend( char * pBase, char * pSuffix )
+{
+ static char Buffer[500];
+ sprintf( Buffer, "%s%s", pBase, pSuffix );
+ return Buffer;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Extra_FileNameGeneric( char * FileName )
+{
+ char * pDot;
+ char * pUnd;
+ char * pRes;
+
+ // find the generic name of the file
+ pRes = util_strsav( FileName );
+ // find the pointer to the "." symbol in the file name
+// pUnd = strstr( FileName, "_" );
+ pUnd = NULL;
+ pDot = strstr( FileName, "." );
+ if ( pUnd )
+ pRes[pUnd - FileName] = 0;
+ else if ( pDot )
+ pRes[pDot - FileName] = 0;
+ return pRes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the file size.]
+
+ Description [The file should be closed.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Extra_FileSize( char * pFileName )
+{
+ FILE * pFile;
+ int nFileSize;
+ pFile = fopen( pFileName, "r" );
+ if ( pFile == NULL )
+ {
+ printf( "Extra_FileSize(): The file is unavailable (absent or open).\n" );
+ return 0;
+ }
+ fseek( pFile, 0, SEEK_END );
+ nFileSize = ftell( pFile );
+ fclose( pFile );
+ return nFileSize;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Read the file into the internal buffer.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Extra_FileRead( FILE * pFile )
+{
+ int nFileSize;
+ char * pBuffer;
+ // get the file size, in bytes
+ fseek( pFile, 0, SEEK_END );
+ nFileSize = ftell( pFile );
+ // move the file current reading position to the beginning
+ rewind( pFile );
+ // load the contents of the file into memory
+ pBuffer = ALLOC( char, nFileSize + 3 );
+ fread( pBuffer, nFileSize, 1, pFile );
+ // terminate the string with '\0'
+ pBuffer[ nFileSize + 0] = '\n';
+ pBuffer[ nFileSize + 1] = '\0';
+ return pBuffer;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the time stamp.]
+
+ Description [The file should be closed.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Extra_TimeStamp()
+{
+ static char Buffer[100];
+ time_t ltime;
+ char * TimeStamp;
+ // get the current time
+ time( &ltime );
+ TimeStamp = asctime( localtime( &ltime ) );
+ TimeStamp[ strlen(TimeStamp) - 1 ] = 0;
+ strcpy( Buffer, TimeStamp );
+ return Buffer;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+unsigned Extra_ReadBinary( char * Buffer )
+{
+ unsigned Result;
+ int i;
+
+ Result = 0;
+ for ( i = 0; Buffer[i]; i++ )
+ if ( Buffer[i] == '0' || Buffer[i] == '1' )
+ Result = Result * 2 + Buffer[i] - '0';
+ else
+ {
+ assert( 0 );
+ }
+ return Result;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the bit string.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_PrintBinary( FILE * pFile, unsigned Sign[], int nBits )
+{
+ int Remainder, nWords;
+ int w, i;
+
+ Remainder = (nBits%(sizeof(unsigned)*8));
+ nWords = (nBits/(sizeof(unsigned)*8)) + (Remainder>0);
+
+ for ( w = nWords-1; w >= 0; w-- )
+ for ( i = ((w == nWords-1 && Remainder)? Remainder-1: 31); i >= 0; i-- )
+ fprintf( pFile, "%c", '0' + (int)((Sign[w] & (1<<i)) > 0) );
+
+// fprintf( pFile, "\n" );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Returns the composite name of the file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_PrintSymbols( FILE * pFile, char Char, int nTimes, int fPrintNewLine )
+{
+ int i;
+ for ( i = 0; i < nTimes; i++ )
+ printf( "%c", Char );
+ if ( fPrintNewLine )
+ printf( "\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Appends the string.]
+
+ Description [Assumes that the given string (pStrGiven) has been allocated
+ before using malloc(). The additional string has not been allocated.
+ Allocs more root, appends the additional part, frees the old given string.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Extra_StringAppend( char * pStrGiven, char * pStrAdd )
+{
+ char * pTemp;
+ if ( pStrGiven )
+ {
+ pTemp = ALLOC( char, strlen(pStrGiven) + strlen(pStrAdd) + 2 );
+ sprintf( pTemp, "%s%s", pStrGiven, pStrAdd );
+ free( pStrGiven );
+ }
+ else
+ pTemp = util_strsav( pStrAdd );
+ return pTemp;
+}
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static Functions */
+/*---------------------------------------------------------------------------*/
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/misc/extra/extraUtilMemory.c b/src/misc/extra/extraUtilMemory.c
new file mode 100644
index 00000000..af1128ac
--- /dev/null
+++ b/src/misc/extra/extraUtilMemory.c
@@ -0,0 +1,564 @@
+/**CFile****************************************************************
+
+ FileName [extraUtilMemory.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [extra]
+
+ Synopsis [Memory managers.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: extraUtilMemory.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "extra.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+struct Extra_MmFixed_t_
+{
+ // information about individual entries
+ int nEntrySize; // the size of one entry
+ int nEntriesAlloc; // the total number of entries allocated
+ int nEntriesUsed; // the number of entries in use
+ int nEntriesMax; // the max number of entries in use
+ char * pEntriesFree; // the linked list of free entries
+
+ // this is where the memory is stored
+ int nChunkSize; // the size of one chunk
+ int nChunksAlloc; // the maximum number of memory chunks
+ int nChunks; // the current number of memory chunks
+ char ** pChunks; // the allocated memory
+
+ // statistics
+ int nMemoryUsed; // memory used in the allocated entries
+ int nMemoryAlloc; // memory allocated
+};
+
+struct Extra_MmFlex_t_
+{
+ // information about individual entries
+ int nEntriesUsed; // the number of entries allocated
+ char * pCurrent; // the current pointer to free memory
+ char * pEnd; // the first entry outside the free memory
+
+ // this is where the memory is stored
+ int nChunkSize; // the size of one chunk
+ int nChunksAlloc; // the maximum number of memory chunks
+ int nChunks; // the current number of memory chunks
+ char ** pChunks; // the allocated memory
+
+ // statistics
+ int nMemoryUsed; // memory used in the allocated entries
+ int nMemoryAlloc; // memory allocated
+};
+
+
+struct Extra_MmStep_t_
+{
+ int nMems; // the number of fixed memory managers employed
+ Extra_MmFixed_t ** pMems; // memory managers: 2^1 words, 2^2 words, etc
+ int nMapSize; // the size of the memory array
+ Extra_MmFixed_t ** pMap; // maps the number of bytes into its memory manager
+};
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function*************************************************************
+
+ Synopsis [Allocates memory pieces of fixed size.]
+
+ Description [The size of the chunk is computed as the minimum of
+ 1024 entries and 64K. Can only work with entry size at least 4 byte long.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Extra_MmFixed_t * Extra_MmFixedStart( int nEntrySize )
+{
+ Extra_MmFixed_t * p;
+
+ p = ALLOC( Extra_MmFixed_t, 1 );
+ memset( p, 0, sizeof(Extra_MmFixed_t) );
+
+ p->nEntrySize = nEntrySize;
+ p->nEntriesAlloc = 0;
+ p->nEntriesUsed = 0;
+ p->pEntriesFree = NULL;
+
+ if ( nEntrySize * (1 << 10) < (1<<16) )
+ p->nChunkSize = (1 << 10);
+ else
+ p->nChunkSize = (1<<16) / nEntrySize;
+ if ( p->nChunkSize < 8 )
+ p->nChunkSize = 8;
+
+ p->nChunksAlloc = 64;
+ p->nChunks = 0;
+ p->pChunks = ALLOC( char *, p->nChunksAlloc );
+
+ p->nMemoryUsed = 0;
+ p->nMemoryAlloc = 0;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_MmFixedStop( Extra_MmFixed_t * p, int fVerbose )
+{
+ int i;
+ if ( p == NULL )
+ return;
+ if ( fVerbose )
+ {
+ printf( "Fixed memory manager: Entry = %5d. Chunk = %5d. Chunks used = %5d.\n",
+ p->nEntrySize, p->nChunkSize, p->nChunks );
+ printf( " Entries used = %8d. Entries peak = %8d. Memory used = %8d. Memory alloc = %8d.\n",
+ p->nEntriesUsed, p->nEntriesMax, p->nEntrySize * p->nEntriesUsed, p->nMemoryAlloc );
+ }
+ for ( i = 0; i < p->nChunks; i++ )
+ free( p->pChunks[i] );
+ free( p->pChunks );
+ free( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Extra_MmFixedEntryFetch( Extra_MmFixed_t * p )
+{
+ char * pTemp;
+ int i;
+
+ // check if there are still free entries
+ if ( p->nEntriesUsed == p->nEntriesAlloc )
+ { // need to allocate more entries
+ assert( p->pEntriesFree == NULL );
+ if ( p->nChunks == p->nChunksAlloc )
+ {
+ p->nChunksAlloc *= 2;
+ p->pChunks = REALLOC( char *, p->pChunks, p->nChunksAlloc );
+ }
+ p->pEntriesFree = ALLOC( char, p->nEntrySize * p->nChunkSize );
+ p->nMemoryAlloc += p->nEntrySize * p->nChunkSize;
+ // transform these entries into a linked list
+ pTemp = p->pEntriesFree;
+ for ( i = 1; i < p->nChunkSize; i++ )
+ {
+ *((char **)pTemp) = pTemp + p->nEntrySize;
+ pTemp += p->nEntrySize;
+ }
+ // set the last link
+ *((char **)pTemp) = NULL;
+ // add the chunk to the chunk storage
+ p->pChunks[ p->nChunks++ ] = p->pEntriesFree;
+ // add to the number of entries allocated
+ p->nEntriesAlloc += p->nChunkSize;
+ }
+ // incrememt the counter of used entries
+ p->nEntriesUsed++;
+ if ( p->nEntriesMax < p->nEntriesUsed )
+ p->nEntriesMax = p->nEntriesUsed;
+ // return the first entry in the free entry list
+ pTemp = p->pEntriesFree;
+ p->pEntriesFree = *((char **)pTemp);
+ return pTemp;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_MmFixedEntryRecycle( Extra_MmFixed_t * p, char * pEntry )
+{
+ // decrement the counter of used entries
+ p->nEntriesUsed--;
+ // add the entry to the linked list of free entries
+ *((char **)pEntry) = p->pEntriesFree;
+ p->pEntriesFree = pEntry;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description [Relocates all the memory except the first chunk.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_MmFixedRestart( Extra_MmFixed_t * p )
+{
+ int i;
+ char * pTemp;
+
+ // delocate all chunks except the first one
+ for ( i = 1; i < p->nChunks; i++ )
+ free( p->pChunks[i] );
+ p->nChunks = 1;
+ // transform these entries into a linked list
+ pTemp = p->pChunks[0];
+ for ( i = 1; i < p->nChunkSize; i++ )
+ {
+ *((char **)pTemp) = pTemp + p->nEntrySize;
+ pTemp += p->nEntrySize;
+ }
+ // set the last link
+ *((char **)pTemp) = NULL;
+ // set the free entry list
+ p->pEntriesFree = p->pChunks[0];
+ // set the correct statistics
+ p->nMemoryAlloc = p->nEntrySize * p->nChunkSize;
+ p->nMemoryUsed = 0;
+ p->nEntriesAlloc = p->nChunkSize;
+ p->nEntriesUsed = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Extra_MmFixedReadMemUsage( Extra_MmFixed_t * p )
+{
+ return p->nMemoryAlloc;
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Allocates entries of flexible size.]
+
+ Description [Can only work with entry size at least 4 byte long.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Extra_MmFlex_t * Extra_MmFlexStart()
+{
+ Extra_MmFlex_t * p;
+
+ p = ALLOC( Extra_MmFlex_t, 1 );
+ memset( p, 0, sizeof(Extra_MmFlex_t) );
+
+ p->nEntriesUsed = 0;
+ p->pCurrent = NULL;
+ p->pEnd = NULL;
+
+ p->nChunkSize = (1 << 12);
+ p->nChunksAlloc = 64;
+ p->nChunks = 0;
+ p->pChunks = ALLOC( char *, p->nChunksAlloc );
+
+ p->nMemoryUsed = 0;
+ p->nMemoryAlloc = 0;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_MmFlexStop( Extra_MmFlex_t * p, int fVerbose )
+{
+ int i;
+ if ( p == NULL )
+ return;
+ if ( fVerbose )
+ {
+ printf( "Flexible memory manager: Chunk size = %d. Chunks used = %d.\n",
+ p->nChunkSize, p->nChunks );
+ printf( " Entries used = %d. Memory used = %d. Memory alloc = %d.\n",
+ p->nEntriesUsed, p->nMemoryUsed, p->nMemoryAlloc );
+ }
+ for ( i = 0; i < p->nChunks; i++ )
+ free( p->pChunks[i] );
+ free( p->pChunks );
+ free( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Extra_MmFlexEntryFetch( Extra_MmFlex_t * p, int nBytes )
+{
+ char * pTemp;
+ // check if there are still free entries
+ if ( p->pCurrent == NULL || p->pCurrent + nBytes > p->pEnd )
+ { // need to allocate more entries
+ if ( p->nChunks == p->nChunksAlloc )
+ {
+ p->nChunksAlloc *= 2;
+ p->pChunks = REALLOC( char *, p->pChunks, p->nChunksAlloc );
+ }
+ if ( nBytes > p->nChunkSize )
+ {
+ // resize the chunk size if more memory is requested than it can give
+ // (ideally, this should never happen)
+ p->nChunkSize = 2 * nBytes;
+ }
+ p->pCurrent = ALLOC( char, p->nChunkSize );
+ p->pEnd = p->pCurrent + p->nChunkSize;
+ p->nMemoryAlloc += p->nChunkSize;
+ // add the chunk to the chunk storage
+ p->pChunks[ p->nChunks++ ] = p->pCurrent;
+ }
+ assert( p->pCurrent + nBytes <= p->pEnd );
+ // increment the counter of used entries
+ p->nEntriesUsed++;
+ // keep track of the memory used
+ p->nMemoryUsed += nBytes;
+ // return the next entry
+ pTemp = p->pCurrent;
+ p->pCurrent += nBytes;
+ return pTemp;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Extra_MmFlexReadMemUsage( Extra_MmFlex_t * p )
+{
+ return p->nMemoryAlloc;
+}
+
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Starts the hierarchical memory manager.]
+
+ Description [This manager can allocate entries of any size.
+ Iternally they are mapped into the entries with the number of bytes
+ equal to the power of 2. The smallest entry size is 8 bytes. The
+ next one is 16 bytes etc. So, if the user requests 6 bytes, he gets
+ 8 byte entry. If we asks for 25 bytes, he gets 32 byte entry etc.
+ The input parameters "nSteps" says how many fixed memory managers
+ are employed internally. Calling this procedure with nSteps equal
+ to 10 results in 10 hierarchically arranged internal memory managers,
+ which can allocate up to 4096 (1Kb) entries. Requests for larger
+ entries are handed over to malloc() and then free()ed.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Extra_MmStep_t * Extra_MmStepStart( int nSteps )
+{
+ Extra_MmStep_t * p;
+ int i, k;
+ p = ALLOC( Extra_MmStep_t, 1 );
+ p->nMems = nSteps;
+ // start the fixed memory managers
+ p->pMems = ALLOC( Extra_MmFixed_t *, p->nMems );
+ for ( i = 0; i < p->nMems; i++ )
+ p->pMems[i] = Extra_MmFixedStart( (8<<i) );
+ // set up the mapping of the required memory size into the corresponding manager
+ p->nMapSize = (4<<p->nMems);
+ p->pMap = ALLOC( Extra_MmFixed_t *, p->nMapSize+1 );
+ p->pMap[0] = NULL;
+ for ( k = 1; k <= 4; k++ )
+ p->pMap[k] = p->pMems[0];
+ for ( i = 0; i < p->nMems; i++ )
+ for ( k = (4<<i)+1; k <= (8<<i); k++ )
+ p->pMap[k] = p->pMems[i];
+//for ( i = 1; i < 100; i ++ )
+//printf( "%10d: size = %10d\n", i, p->pMap[i]->nEntrySize );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Stops the memory manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_MmStepStop( Extra_MmStep_t * p, int fVerbose )
+{
+ int i;
+ for ( i = 0; i < p->nMems; i++ )
+ Extra_MmFixedStop( p->pMems[i], fVerbose );
+ free( p->pMems );
+ free( p->pMap );
+ free( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates the entry.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Extra_MmStepEntryFetch( Extra_MmStep_t * p, int nBytes )
+{
+ if ( nBytes == 0 )
+ return NULL;
+ if ( nBytes > p->nMapSize )
+ {
+// printf( "Allocating %d bytes.\n", nBytes );
+ return ALLOC( char, nBytes );
+ }
+ return Extra_MmFixedEntryFetch( p->pMap[nBytes] );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Recycles the entry.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_MmStepEntryRecycle( Extra_MmStep_t * p, char * pEntry, int nBytes )
+{
+ if ( nBytes == 0 )
+ return;
+ if ( nBytes > p->nMapSize )
+ {
+ free( pEntry );
+ return;
+ }
+ Extra_MmFixedEntryRecycle( p->pMap[nBytes], pEntry );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Extra_MmStepReadMemUsage( Extra_MmStep_t * p )
+{
+ int i, nMemTotal = 0;
+ for ( i = 0; i < p->nMems; i++ )
+ nMemTotal += p->pMems[i]->nMemoryAlloc;
+ return nMemTotal;
+}
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/misc/extra/extraUtilMisc.c b/src/misc/extra/extraUtilMisc.c
new file mode 100644
index 00000000..41c76018
--- /dev/null
+++ b/src/misc/extra/extraUtilMisc.c
@@ -0,0 +1,380 @@
+/**CFile****************************************************************
+
+ FileName [extraUtilMisc.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [extra]
+
+ Synopsis [Misc procedures.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: extraUtilMisc.c,v 1.0 2003/09/01 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "extra.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticEnd***************************************************************/
+
+static void Extra_Permutations_rec( char ** pRes, int nFact, int n, char Array[] );
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the smallest integer larger of equal than the logarithm.]
+
+ Description [Returns [Log2(Num)].]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int Extra_Base2Log( unsigned Num )
+{
+ int Res;
+ assert( Num >= 0 );
+ if ( Num == 0 ) return 0;
+ if ( Num == 1 ) return 1;
+ for ( Res = 0, Num--; Num; Num >>= 1, Res++ );
+ return Res;
+} /* end of Extra_Base2Log */
+
+/**Function********************************************************************
+
+ Synopsis [Finds the smallest integer larger of equal than the logarithm.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int Extra_Base2LogDouble( double Num )
+{
+ double Res;
+ int ResInt;
+
+ Res = log(Num)/log(2.0);
+ ResInt = (int)Res;
+ if ( ResInt == Res )
+ return ResInt;
+ else
+ return ResInt+1;
+}
+
+/**Function********************************************************************
+
+ Synopsis [Finds the smallest integer larger of equal than the logarithm.]
+
+ Description [Returns [Log10(Num)].]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int Extra_Base10Log( unsigned Num )
+{
+ int Res;
+ assert( Num >= 0 );
+ if ( Num == 0 ) return 0;
+ if ( Num == 1 ) return 1;
+ for ( Res = 0, Num--; Num; Num /= 10, Res++ );
+ return Res;
+} /* end of Extra_Base2Log */
+
+/**Function********************************************************************
+
+ Synopsis [Returns the power of two as a double.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+double Extra_Power2( int Degree )
+{
+ double Res;
+ assert( Degree >= 0 );
+ if ( Degree < 32 )
+ return (double)(01<<Degree);
+ for ( Res = 1.0; Degree; Res *= 2.0, Degree-- );
+ return Res;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Extra_Power3( int Num )
+{
+ int i;
+ int Res;
+ Res = 1;
+ for ( i = 0; i < Num; i++ )
+ Res *= 3;
+ return Res;
+}
+
+/**Function********************************************************************
+
+ Synopsis [Finds the number of combinations of k elements out of n.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int Extra_NumCombinations( int k, int n )
+{
+ int i, Res = 1;
+ for ( i = 1; i <= k; i++ )
+ Res = Res * (n-i+1) / i;
+ return Res;
+} /* end of Extra_NumCombinations */
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int * Extra_DeriveRadixCode( int Number, int Radix, int nDigits )
+{
+ static int Code[100];
+ int i;
+ assert( nDigits < 100 );
+ for ( i = 0; i < nDigits; i++ )
+ {
+ Code[i] = Number % Radix;
+ Number = Number / Radix;
+ }
+ assert( Number == 0 );
+ return Code;
+}
+
+/**Function********************************************************************
+
+ Synopsis [Computes the factorial.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int Extra_Factorial( int n )
+{
+ int i, Res = 1;
+ for ( i = 1; i <= n; i++ )
+ Res *= i;
+ return Res;
+}
+
+/**Function********************************************************************
+
+ Synopsis [Computes the set of all permutations.]
+
+ Description [The number of permutations in the array is n!. The number of
+ entries in each permutation is n. Therefore, the resulting array is a
+ two-dimentional array of the size: n! x n. To free the resulting array,
+ call free() on the pointer returned by this procedure.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+char ** Extra_Permutations( int n )
+{
+ char Array[50];
+ char ** pRes;
+ char * pBuffer;
+ int nFact, i;
+ // allocate all memory at once
+ nFact = Extra_Factorial( n );
+ pBuffer = ALLOC( char, nFact * sizeof(char *) + nFact * n * sizeof(char) );
+ // split the chunk
+ pRes = (char **)pBuffer;
+ for ( i = 0; i < nFact; i++ )
+ pRes[i] = pBuffer + nFact * sizeof(char *) + i * n * sizeof(char);
+ // fill in the permutations
+ for ( i = 0; i < n; i++ )
+ Array[i] = i;
+ Extra_Permutations_rec( pRes, nFact, n, Array );
+ // print the permutations
+/*
+ {
+ int i, k;
+ for ( i = 0; i < nFact; i++ )
+ {
+ printf( "{" );
+ for ( k = 0; k < n; k++ )
+ printf( " %d", pRes[i][k] );
+ printf( " }\n" );
+ }
+ }
+*/
+ return pRes;
+}
+
+/**Function********************************************************************
+
+ Synopsis [Fills in the array of permutations.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void Extra_Permutations_rec( char ** pRes, int nFact, int n, char Array[] )
+{
+ char ** pNext;
+ int nFactNext;
+ int iTemp, iCur, iLast, p;
+
+ if ( n == 1 )
+ {
+ pRes[0][0] = Array[0];
+ return;
+ }
+
+ // get the next factorial
+ nFactNext = nFact / n;
+ // get the last entry
+ iLast = n - 1;
+
+ for ( iCur = 0; iCur < n; iCur++ )
+ {
+ // swap Cur and Last
+ iTemp = Array[iCur];
+ Array[iCur] = Array[iLast];
+ Array[iLast] = iTemp;
+
+ // get the pointer to the current section
+ pNext = pRes + (n - 1 - iCur) * nFactNext;
+
+ // set the last entry
+ for ( p = 0; p < nFactNext; p++ )
+ pNext[p][iLast] = Array[iLast];
+
+ // call recursively for this part
+ Extra_Permutations_rec( pNext, nFactNext, n - 1, Array );
+
+ // swap them back
+ iTemp = Array[iCur];
+ Array[iCur] = Array[iLast];
+ Array[iLast] = iTemp;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the smallest prime larger than the number.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+unsigned int Cudd_PrimeCopy( unsigned int p)
+{
+ int i,pn;
+
+ p--;
+ do {
+ p++;
+ if (p&1) {
+ pn = 1;
+ i = 3;
+ while ((unsigned) (i * i) <= p) {
+ if (p % i == 0) {
+ pn = 0;
+ break;
+ }
+ i += 2;
+ }
+ } else {
+ pn = 0;
+ }
+ } while (!pn);
+ return(p);
+
+} /* end of Cudd_Prime */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static Functions */
+/*---------------------------------------------------------------------------*/
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/misc/extra/extraUtilProgress.c b/src/misc/extra/extraUtilProgress.c
new file mode 100644
index 00000000..7b0efb5c
--- /dev/null
+++ b/src/misc/extra/extraUtilProgress.c
@@ -0,0 +1,164 @@
+/**CFile****************************************************************
+
+ FileName [extraUtilProgress.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [extra]
+
+ Synopsis [Progress bar.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: extraUtilProgress.c,v 1.0 2003/02/01 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "stdio.h"
+#include "extra.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+struct ProgressBarStruct
+{
+ int nItemsNext; // the number of items for the next update of the progress bar
+ int nItemsTotal; // the total number of items
+ int posTotal; // the total number of positions
+ int posCur; // the current position
+ FILE * pFile; // the output stream
+};
+
+static void Extra_ProgressBarShow( ProgressBar * p, char * pString );
+static void Extra_ProgressBarClean( ProgressBar * p );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Starts the progress bar.]
+
+ Description [The first parameter is the output stream (pFile), where
+ the progress is printed. The current printing position should be the
+ first one on the given line. The second parameters is the total
+ number of items that correspond to 100% position of the progress bar.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+ProgressBar * Extra_ProgressBarStart( FILE * pFile, int nItemsTotal )
+{
+ ProgressBar * p;
+ p = ALLOC( ProgressBar, 1 );
+ memset( p, 0, sizeof(ProgressBar) );
+ p->pFile = pFile;
+ p->nItemsTotal = nItemsTotal;
+ p->posTotal = 78;
+ p->posCur = 1;
+ p->nItemsNext = (int)((float)p->nItemsTotal/p->posTotal)*(p->posCur+5)+2;
+ Extra_ProgressBarShow( p, NULL );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Updates the progress bar.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_ProgressBarUpdate_int( ProgressBar * p, int nItemsCur, char * pString )
+{
+ if ( nItemsCur < p->nItemsNext )
+ return;
+ if ( nItemsCur > p->nItemsTotal )
+ nItemsCur = p->nItemsTotal;
+ p->posCur = (int)((float)nItemsCur * p->posTotal / p->nItemsTotal);
+ p->nItemsNext = (int)((float)p->nItemsTotal/p->posTotal)*(p->posCur+10)+1;
+ if ( p->posCur == 0 )
+ p->posCur = 1;
+ Extra_ProgressBarShow( p, pString );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Stops the progress bar.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_ProgressBarStop( ProgressBar * p )
+{
+ Extra_ProgressBarClean( p );
+ FREE( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the progress bar of the given size.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_ProgressBarShow( ProgressBar * p, char * pString )
+{
+ int i;
+ if ( pString )
+ fprintf( p->pFile, "%s ", pString );
+ for ( i = (pString? strlen(pString) + 1 : 0); i < p->posCur; i++ )
+ fprintf( p->pFile, "-" );
+ if ( i == p->posCur )
+ fprintf( p->pFile, ">" );
+ for ( i++ ; i <= p->posTotal; i++ )
+ fprintf( p->pFile, " " );
+ fprintf( p->pFile, "\r" );
+ fflush( stdout );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Cleans the progress bar before quitting.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_ProgressBarClean( ProgressBar * p )
+{
+ int i;
+ for ( i = 0; i <= p->posTotal; i++ )
+ fprintf( p->pFile, " " );
+ fprintf( p->pFile, "\r" );
+ fflush( stdout );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/misc/extra/extraUtilReader.c b/src/misc/extra/extraUtilReader.c
new file mode 100644
index 00000000..2dc597bf
--- /dev/null
+++ b/src/misc/extra/extraUtilReader.c
@@ -0,0 +1,367 @@
+/**CFile****************************************************************
+
+ FileName [extraUtilReader.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [extra]
+
+ Synopsis [File reading utilities.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: extraUtilReader.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "stdio.h"
+#include "extra.h"
+#include "vec.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+#define EXTRA_BUFFER_SIZE 1048576 // 1M - size of the data chunk stored in memory
+#define EXTRA_OFFSET_SIZE 4096 // 4K - load new data when less than this is left
+
+#define EXTRA_MINIMUM(a,b) (((a) < (b))? (a) : (b))
+
+struct Extra_FileReader_t_
+{
+ // the input file
+ char * pFileName; // the input file name
+ FILE * pFile; // the input file pointer
+ int nFileSize; // the total number of bytes in the file
+ int nFileRead; // the number of bytes currently read from file
+ // info about processing different types of input chars
+ char pCharMap[256]; // the character map
+ // temporary storage for data
+ char * pBuffer; // the buffer
+ int nBufferSize; // the size of the buffer
+ char * pBufferCur; // the current reading position
+ char * pBufferEnd; // the first position not used by currently loaded data
+ char * pBufferStop; // the position where loading new data will be done
+ // tokens given to the user
+ Vec_Ptr_t * vTokens; // the vector of tokens returned to the user
+ Vec_Int_t * vLines; // the vector of line numbers for each token
+ int nLineCounter; // the counter of lines processed
+ // status of the parser
+ int fStop; // this flag goes high when the end of file is reached
+};
+
+// character types
+typedef enum {
+ EXTRA_CHAR_COMMENT, // a character that begins the comment
+ EXTRA_CHAR_NORMAL, // a regular character
+ EXTRA_CHAR_STOP, // a character that delimits a series of tokens
+ EXTRA_CHAR_CLEAN // a character that should be cleaned
+} Extra_CharType_t;
+
+// the static functions
+static void * Extra_FileReaderGetTokens_int( Extra_FileReader_t * p );
+static void Extra_FileReaderReload( Extra_FileReader_t * p );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Starts the file reader.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Extra_FileReader_t * Extra_FileReaderAlloc( char * pFileName,
+ char * pCharsComment, char * pCharsStop, char * pCharsClean )
+{
+ Extra_FileReader_t * p;
+ FILE * pFile;
+ char * pChar;
+ int nCharsToRead;
+ // check if the file can be opened
+ pFile = fopen( pFileName, "rb" );
+ if ( pFile == NULL )
+ {
+ printf( "Extra_FileReaderAlloc(): Cannot open input file \"%s\".\n", pFileName );
+ return NULL;
+ }
+ // start the file reader
+ p = ALLOC( Extra_FileReader_t, 1 );
+ memset( p, 0, sizeof(Extra_FileReader_t) );
+ p->pFileName = pFileName;
+ p->pFile = pFile;
+ // set the character map
+ memset( p->pCharMap, EXTRA_CHAR_NORMAL, 256 );
+ for ( pChar = pCharsComment; *pChar; pChar++ )
+ p->pCharMap[(unsigned char)*pChar] = EXTRA_CHAR_COMMENT;
+ for ( pChar = pCharsStop; *pChar; pChar++ )
+ p->pCharMap[(unsigned char)*pChar] = EXTRA_CHAR_STOP;
+ for ( pChar = pCharsClean; *pChar; pChar++ )
+ p->pCharMap[(unsigned char)*pChar] = EXTRA_CHAR_CLEAN;
+ // get the file size, in bytes
+ fseek( pFile, 0, SEEK_END );
+ p->nFileSize = ftell( pFile );
+ rewind( pFile );
+ // allocate the buffer
+ p->pBuffer = ALLOC( char, EXTRA_BUFFER_SIZE+1 );
+ p->nBufferSize = EXTRA_BUFFER_SIZE;
+ p->pBufferCur = p->pBuffer;
+ // determine how many chars to read
+ nCharsToRead = EXTRA_MINIMUM(p->nFileSize, EXTRA_BUFFER_SIZE);
+ // load the first part into the buffer
+ fread( p->pBuffer, nCharsToRead, 1, p->pFile );
+ p->nFileRead = nCharsToRead;
+ // set the ponters to the end and the stopping point
+ p->pBufferEnd = p->pBuffer + nCharsToRead;
+ p->pBufferStop = (p->nFileRead == p->nFileSize)? p->pBufferEnd : p->pBuffer + EXTRA_BUFFER_SIZE - EXTRA_OFFSET_SIZE;
+ // start the arrays
+ p->vTokens = Vec_PtrAlloc( 100 );
+ p->vLines = Vec_IntAlloc( 100 );
+ p->nLineCounter = 1; // 1-based line counting
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Stops the file reader.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_FileReaderFree( Extra_FileReader_t * p )
+{
+ if ( p->pFile )
+ fclose( p->pFile );
+ FREE( p->pBuffer );
+ Vec_PtrFree( p->vTokens );
+ Vec_IntFree( p->vLines );
+ free( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the file size.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Extra_FileReaderGetFileName( Extra_FileReader_t * p )
+{
+ return p->pFileName;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the file size.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Extra_FileReaderGetFileSize( Extra_FileReader_t * p )
+{
+ return p->nFileSize;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the current reading position.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Extra_FileReaderGetCurPosition( Extra_FileReader_t * p )
+{
+ return p->nFileRead - (p->pBufferEnd - p->pBufferCur);
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the line number for the given token.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Extra_FileReaderGetLineNumber( Extra_FileReader_t * p, int iToken )
+{
+ assert( iToken >= 0 && iToken < p->vTokens->nSize );
+ return p->vLines->pArray[iToken];
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Returns the next set of tokens.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void * Extra_FileReaderGetTokens( Extra_FileReader_t * p )
+{
+ Vec_Ptr_t * vTokens;
+ while ( vTokens = Extra_FileReaderGetTokens_int( p ) )
+ if ( vTokens->nSize > 0 )
+ break;
+ return vTokens;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the next set of tokens.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void * Extra_FileReaderGetTokens_int( Extra_FileReader_t * p )
+{
+ char * pChar;
+ int fTokenStarted, MapValue;
+ if ( p->fStop )
+ return NULL;
+ // reset the token info
+ p->vTokens->nSize = 0;
+ p->vLines->nSize = 0;
+ fTokenStarted = 0;
+ // check if the new data should to be loaded
+ if ( p->pBufferCur > p->pBufferStop )
+ Extra_FileReaderReload( p );
+ // process the string starting from the current position
+ for ( pChar = p->pBufferCur; pChar < p->pBufferEnd; pChar++ )
+ {
+ // count the lines
+ if ( *pChar == '\n' )
+ p->nLineCounter++;
+ // switch depending on the character
+ MapValue = p->pCharMap[*pChar];
+ switch ( MapValue )
+ {
+ case EXTRA_CHAR_COMMENT:
+ if ( *pChar != '/' || *(pChar+1) == '/' )
+ { // dealing with the need to have // as a comment
+ // if the token was being written, stop it
+ if ( fTokenStarted )
+ fTokenStarted = 0;
+ // eraze the comment till the end of line
+ while ( *pChar != '\n' )
+ {
+ *pChar++ = 0;
+ if ( pChar == p->pBufferEnd )
+ { // this failure is due to the fact the comment continued
+ // through EXTRA_OFFSET_SIZE chars till the end of the buffer
+ printf( "Extra_FileReader failed to parse the file \"%s\".\n", p->pFileName );
+ return NULL;
+ }
+ }
+ pChar--;
+ break;
+ }
+ // otherwise it is a normal character
+ case EXTRA_CHAR_NORMAL:
+ if ( !fTokenStarted )
+ {
+ Vec_PtrPush( p->vTokens, pChar );
+ Vec_IntPush( p->vLines, p->nLineCounter );
+ fTokenStarted = 1;
+ }
+ break;
+ case EXTRA_CHAR_STOP:
+ if ( fTokenStarted )
+ fTokenStarted = 0;
+ *pChar = 0;
+ // prepare before leaving
+ p->pBufferCur = pChar + 1;
+ return p->vTokens;
+ case EXTRA_CHAR_CLEAN:
+ if ( fTokenStarted )
+ fTokenStarted = 0;
+ *pChar = 0;
+ break;
+ default:
+ assert( 0 );
+ }
+ }
+ // the file is finished or the last part continued
+ // through EXTRA_OFFSET_SIZE chars till the end of the buffer
+ if ( p->pBufferStop == p->pBufferEnd ) // end of file
+ {
+ p->fStop = 1;
+ return p->vTokens;
+ }
+ printf( "Extra_FileReader failed to parse the file \"%s\".\n", p->pFileName );
+ return NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Loads new data into the file reader.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_FileReaderReload( Extra_FileReader_t * p )
+{
+ int nCharsUsed, nCharsToRead;
+ assert( !p->fStop );
+ assert( p->pBufferCur > p->pBufferStop );
+ assert( p->pBufferCur < p->pBufferEnd );
+ // figure out how many chars are still not processed
+ nCharsUsed = p->pBufferEnd - p->pBufferCur;
+ // move the remaining data to the beginning of the buffer
+ memmove( p->pBuffer, p->pBufferCur, nCharsUsed );
+ p->pBufferCur = p->pBuffer;
+ // determine how many chars we will read
+ nCharsToRead = EXTRA_MINIMUM( p->nBufferSize - nCharsUsed, p->nFileSize - p->nFileRead );
+ // read the chars
+ fread( p->pBuffer + nCharsUsed, nCharsToRead, 1, p->pFile );
+ p->nFileRead += nCharsToRead;
+ // set the ponters to the end and the stopping point
+ p->pBufferEnd = p->pBuffer + nCharsUsed + nCharsToRead;
+ p->pBufferStop = (p->nFileRead == p->nFileSize)? p->pBufferEnd : p->pBuffer + EXTRA_BUFFER_SIZE - EXTRA_OFFSET_SIZE;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/misc/extra/module.make b/src/misc/extra/module.make
new file mode 100644
index 00000000..0c7d36a2
--- /dev/null
+++ b/src/misc/extra/module.make
@@ -0,0 +1,6 @@
+SRC += src/misc/extra/extraUtilBdd.c \
+ src/misc/extra/extraUtilFile.c \
+ src/misc/extra/extraUtilMemory.c \
+ src/misc/extra/extraUtilMisc.c \
+ src/misc/extra/extraUtilProgress.c \
+ src/misc/extra/extraUtilReader.c
diff --git a/src/misc/st/module.make b/src/misc/st/module.make
new file mode 100644
index 00000000..33e442c0
--- /dev/null
+++ b/src/misc/st/module.make
@@ -0,0 +1,2 @@
+SRC += src/misc/st/st.c \
+ src/misc/st/stmm.c
diff --git a/src/misc/st/st.c b/src/misc/st/st.c
new file mode 100644
index 00000000..13e9bd6a
--- /dev/null
+++ b/src/misc/st/st.c
@@ -0,0 +1,606 @@
+/*
+ * Revision Control Information
+ *
+ * /projects/hsis/CVS/utilities/st/st.c,v
+ * serdar
+ * 1.1
+ * 1993/07/29 01:00:13
+ *
+ */
+#include <stdio.h>
+#include "util.h"
+#include "st.h"
+
+#define ST_NUMCMP(x,y) ((x) != (y))
+#define ST_NUMHASH(x,size) (ABS((long)x)%(size))
+#define ST_PTRHASH(x,size) ((int)((unsigned long)(x)>>2)%size)
+#define EQUAL(func, x, y) \
+ ((((func) == st_numcmp) || ((func) == st_ptrcmp)) ?\
+ (ST_NUMCMP((x),(y)) == 0) : ((*func)((x), (y)) == 0))
+
+
+#define do_hash(key, table)\
+ ((table->hash == st_ptrhash) ? ST_PTRHASH((key),(table)->num_bins) :\
+ (table->hash == st_numhash) ? ST_NUMHASH((key), (table)->num_bins) :\
+ (*table->hash)((key), (table)->num_bins))
+
+static int rehash();
+int st_numhash(), st_ptrhash(), st_numcmp(), st_ptrcmp();
+
+st_table *
+st_init_table_with_params(compare, hash, size, density, grow_factor,
+ reorder_flag)
+int (*compare)();
+int (*hash)();
+int size;
+int density;
+double grow_factor;
+int reorder_flag;
+{
+ int i;
+ st_table *new;
+
+ new = ALLOC(st_table, 1);
+ if (new == NIL(st_table)) {
+ return NIL(st_table);
+ }
+ new->compare = compare;
+ new->hash = hash;
+ new->num_entries = 0;
+ new->max_density = density;
+ new->grow_factor = grow_factor;
+ new->reorder_flag = reorder_flag;
+ if (size <= 0) {
+ size = 1;
+ }
+ new->num_bins = size;
+ new->bins = ALLOC(st_table_entry *, size);
+ if (new->bins == NIL(st_table_entry *)) {
+ FREE(new);
+ return NIL(st_table);
+ }
+ for(i = 0; i < size; i++) {
+ new->bins[i] = 0;
+ }
+ return new;
+}
+
+st_table *
+st_init_table(compare, hash)
+int (*compare)();
+int (*hash)();
+{
+ return st_init_table_with_params(compare, hash, ST_DEFAULT_INIT_TABLE_SIZE,
+ ST_DEFAULT_MAX_DENSITY,
+ ST_DEFAULT_GROW_FACTOR,
+ ST_DEFAULT_REORDER_FLAG);
+}
+
+void
+st_free_table(table)
+st_table *table;
+{
+ register st_table_entry *ptr, *next;
+ int i;
+
+ for(i = 0; i < table->num_bins ; i++) {
+ ptr = table->bins[i];
+ while (ptr != NIL(st_table_entry)) {
+ next = ptr->next;
+ FREE(ptr);
+ ptr = next;
+ }
+ }
+ FREE(table->bins);
+ FREE(table);
+}
+
+#define PTR_NOT_EQUAL(table, ptr, user_key)\
+(ptr != NIL(st_table_entry) && !EQUAL(table->compare, user_key, (ptr)->key))
+
+#define FIND_ENTRY(table, hash_val, key, ptr, last) \
+ (last) = &(table)->bins[hash_val];\
+ (ptr) = *(last);\
+ while (PTR_NOT_EQUAL((table), (ptr), (key))) {\
+ (last) = &(ptr)->next; (ptr) = *(last);\
+ }\
+ if ((ptr) != NIL(st_table_entry) && (table)->reorder_flag) {\
+ *(last) = (ptr)->next;\
+ (ptr)->next = (table)->bins[hash_val];\
+ (table)->bins[hash_val] = (ptr);\
+ }
+
+int
+st_lookup(table, key, value)
+st_table *table;
+register char *key;
+char **value;
+{
+ int hash_val;
+ register st_table_entry *ptr, **last;
+
+ hash_val = do_hash(key, table);
+
+ FIND_ENTRY(table, hash_val, key, ptr, last);
+
+ if (ptr == NIL(st_table_entry)) {
+ return 0;
+ } else {
+ if (value != NIL(char *)) {
+ *value = ptr->record;
+ }
+ return 1;
+ }
+}
+
+int
+st_lookup_int(table, key, value)
+st_table *table;
+register char *key;
+int *value;
+{
+ int hash_val;
+ register st_table_entry *ptr, **last;
+
+ hash_val = do_hash(key, table);
+
+ FIND_ENTRY(table, hash_val, key, ptr, last);
+
+ if (ptr == NIL(st_table_entry)) {
+ return 0;
+ } else {
+ if (value != NIL(int)) {
+ *value = (long) ptr->record;
+ }
+ return 1;
+ }
+}
+
+/* This macro does not check if memory allocation fails. Use at you own risk */
+#define ADD_DIRECT(table, key, value, hash_val, new)\
+{\
+ if (table->num_entries/table->num_bins >= table->max_density) {\
+ rehash(table);\
+ hash_val = do_hash(key,table);\
+ }\
+ \
+ new = ALLOC(st_table_entry, 1);\
+ \
+ new->key = key;\
+ new->record = value;\
+ new->next = table->bins[hash_val];\
+ table->bins[hash_val] = new;\
+ table->num_entries++;\
+}
+
+int
+st_insert(table, key, value)
+register st_table *table;
+register char *key;
+char *value;
+{
+ int hash_val;
+ st_table_entry *new;
+ register st_table_entry *ptr, **last;
+
+ hash_val = do_hash(key, table);
+
+ FIND_ENTRY(table, hash_val, key, ptr, last);
+
+ if (ptr == NIL(st_table_entry)) {
+ if (table->num_entries/table->num_bins >= table->max_density) {
+ if (rehash(table) == ST_OUT_OF_MEM) {
+ return ST_OUT_OF_MEM;
+ }
+ hash_val = do_hash(key, table);
+ }
+ new = ALLOC(st_table_entry, 1);
+ if (new == NIL(st_table_entry)) {
+ return ST_OUT_OF_MEM;
+ }
+ new->key = key;
+ new->record = value;
+ new->next = table->bins[hash_val];
+ table->bins[hash_val] = new;
+ table->num_entries++;
+ return 0;
+ } else {
+ ptr->record = value;
+ return 1;
+ }
+}
+
+int
+st_add_direct(table, key, value)
+st_table *table;
+char *key;
+char *value;
+{
+ int hash_val;
+ st_table_entry *new;
+
+ hash_val = do_hash(key, table);
+ if (table->num_entries / table->num_bins >= table->max_density) {
+ if (rehash(table) == ST_OUT_OF_MEM) {
+ return ST_OUT_OF_MEM;
+ }
+ }
+ hash_val = do_hash(key, table);
+ new = ALLOC(st_table_entry, 1);
+ if (new == NIL(st_table_entry)) {
+ return ST_OUT_OF_MEM;
+ }
+ new->key = key;
+ new->record = value;
+ new->next = table->bins[hash_val];
+ table->bins[hash_val] = new;
+ table->num_entries++;
+ return 1;
+}
+
+int
+st_find_or_add(table, key, slot)
+st_table *table;
+char *key;
+char ***slot;
+{
+ int hash_val;
+ st_table_entry *new, *ptr, **last;
+
+ hash_val = do_hash(key, table);
+
+ FIND_ENTRY(table, hash_val, key, ptr, last);
+
+ if (ptr == NIL(st_table_entry)) {
+ if (table->num_entries / table->num_bins >= table->max_density) {
+ if (rehash(table) == ST_OUT_OF_MEM) {
+ return ST_OUT_OF_MEM;
+ }
+ hash_val = do_hash(key, table);
+ }
+ new = ALLOC(st_table_entry, 1);
+ if (new == NIL(st_table_entry)) {
+ return ST_OUT_OF_MEM;
+ }
+ new->key = key;
+ new->record = (char *) 0;
+ new->next = table->bins[hash_val];
+ table->bins[hash_val] = new;
+ table->num_entries++;
+ if (slot != NIL(char **)) *slot = &new->record;
+ return 0;
+ } else {
+ if (slot != NIL(char **)) *slot = &ptr->record;
+ return 1;
+ }
+}
+
+int
+st_find(table, key, slot)
+st_table *table;
+char *key;
+char ***slot;
+{
+ int hash_val;
+ st_table_entry *ptr, **last;
+
+ hash_val = do_hash(key, table);
+
+ FIND_ENTRY(table, hash_val, key, ptr, last);
+
+ if (ptr == NIL(st_table_entry)) {
+ return 0;
+ } else {
+ if (slot != NIL(char **)) {
+ *slot = &ptr->record;
+ }
+ return 1;
+ }
+}
+
+static int
+rehash(table)
+register st_table *table;
+{
+ register st_table_entry *ptr, *next, **old_bins;
+ int i, old_num_bins, hash_val, old_num_entries;
+
+ /* save old values */
+ old_bins = table->bins;
+ old_num_bins = table->num_bins;
+ old_num_entries = table->num_entries;
+
+ /* rehash */
+ table->num_bins = (int)(table->grow_factor * old_num_bins);
+ if (table->num_bins % 2 == 0) {
+ table->num_bins += 1;
+ }
+ table->num_entries = 0;
+ table->bins = ALLOC(st_table_entry *, table->num_bins);
+ if (table->bins == NIL(st_table_entry *)) {
+ table->bins = old_bins;
+ table->num_bins = old_num_bins;
+ table->num_entries = old_num_entries;
+ return ST_OUT_OF_MEM;
+ }
+ /* initialize */
+ for (i = 0; i < table->num_bins; i++) {
+ table->bins[i] = 0;
+ }
+
+ /* copy data over */
+ for (i = 0; i < old_num_bins; i++) {
+ ptr = old_bins[i];
+ while (ptr != NIL(st_table_entry)) {
+ next = ptr->next;
+ hash_val = do_hash(ptr->key, table);
+ ptr->next = table->bins[hash_val];
+ table->bins[hash_val] = ptr;
+ table->num_entries++;
+ ptr = next;
+ }
+ }
+ FREE(old_bins);
+
+ return 1;
+}
+
+st_table *
+st_copy(old_table)
+st_table *old_table;
+{
+ st_table *new_table;
+ st_table_entry *ptr, *newptr, *next, *new;
+ int i, j, num_bins = old_table->num_bins;
+
+ new_table = ALLOC(st_table, 1);
+ if (new_table == NIL(st_table)) {
+ return NIL(st_table);
+ }
+
+ *new_table = *old_table;
+ new_table->bins = ALLOC(st_table_entry *, num_bins);
+ if (new_table->bins == NIL(st_table_entry *)) {
+ FREE(new_table);
+ return NIL(st_table);
+ }
+ for(i = 0; i < num_bins ; i++) {
+ new_table->bins[i] = NIL(st_table_entry);
+ ptr = old_table->bins[i];
+ while (ptr != NIL(st_table_entry)) {
+ new = ALLOC(st_table_entry, 1);
+ if (new == NIL(st_table_entry)) {
+ for (j = 0; j <= i; j++) {
+ newptr = new_table->bins[j];
+ while (newptr != NIL(st_table_entry)) {
+ next = newptr->next;
+ FREE(newptr);
+ newptr = next;
+ }
+ }
+ FREE(new_table->bins);
+ FREE(new_table);
+ return NIL(st_table);
+ }
+ *new = *ptr;
+ new->next = new_table->bins[i];
+ new_table->bins[i] = new;
+ ptr = ptr->next;
+ }
+ }
+ return new_table;
+}
+
+int
+st_delete(table, keyp, value)
+register st_table *table;
+register char **keyp;
+char **value;
+{
+ int hash_val;
+ char *key = *keyp;
+ register st_table_entry *ptr, **last;
+
+ hash_val = do_hash(key, table);
+
+ FIND_ENTRY(table, hash_val, key, ptr ,last);
+
+ if (ptr == NIL(st_table_entry)) {
+ return 0;
+ }
+
+ *last = ptr->next;
+ if (value != NIL(char *)) *value = ptr->record;
+ *keyp = ptr->key;
+ FREE(ptr);
+ table->num_entries--;
+ return 1;
+}
+
+int
+st_delete_int(table, keyp, value)
+register st_table *table;
+register long *keyp;
+char **value;
+{
+ int hash_val;
+ char *key = (char *) *keyp;
+ register st_table_entry *ptr, **last;
+
+ hash_val = do_hash(key, table);
+
+ FIND_ENTRY(table, hash_val, key, ptr ,last);
+
+ if (ptr == NIL(st_table_entry)) {
+ return 0;
+ }
+
+ *last = ptr->next;
+ if (value != NIL(char *)) *value = ptr->record;
+ *keyp = (long) ptr->key;
+ FREE(ptr);
+ table->num_entries--;
+ return 1;
+}
+
+int
+st_foreach(table, func, arg)
+st_table *table;
+enum st_retval (*func)();
+char *arg;
+{
+ st_table_entry *ptr, **last;
+ enum st_retval retval;
+ int i;
+
+ for(i = 0; i < table->num_bins; i++) {
+ last = &table->bins[i]; ptr = *last;
+ while (ptr != NIL(st_table_entry)) {
+ retval = (*func)(ptr->key, ptr->record, arg);
+ switch (retval) {
+ case ST_CONTINUE:
+ last = &ptr->next; ptr = *last;
+ break;
+ case ST_STOP:
+ return 0;
+ case ST_DELETE:
+ *last = ptr->next;
+ table->num_entries--; /* cstevens@ic */
+ FREE(ptr);
+ ptr = *last;
+ }
+ }
+ }
+ return 1;
+}
+
+int
+st_strhash(string, modulus)
+register char *string;
+int modulus;
+{
+ register int val = 0;
+ register int c;
+
+ while ((c = *string++) != '\0') {
+ val = val*997 + c;
+ }
+
+ return ((val < 0) ? -val : val)%modulus;
+}
+
+int
+st_numhash(x, size)
+char *x;
+int size;
+{
+ return ST_NUMHASH(x, size);
+}
+
+int
+st_ptrhash(x, size)
+char *x;
+int size;
+{
+ return ST_PTRHASH(x, size);
+}
+
+int
+st_numcmp(x, y)
+char *x;
+char *y;
+{
+ return ST_NUMCMP(x, y);
+}
+
+int
+st_ptrcmp(x, y)
+char *x;
+char *y;
+{
+ return ST_NUMCMP(x, y);
+}
+
+st_generator *
+st_init_gen(table)
+st_table *table;
+{
+ st_generator *gen;
+
+ gen = ALLOC(st_generator, 1);
+ if (gen == NIL(st_generator)) {
+ return NIL(st_generator);
+ }
+ gen->table = table;
+ gen->entry = NIL(st_table_entry);
+ gen->index = 0;
+ return gen;
+}
+
+
+int
+st_gen(gen, key_p, value_p)
+st_generator *gen;
+char **key_p;
+char **value_p;
+{
+ register int i;
+
+ if (gen->entry == NIL(st_table_entry)) {
+ /* try to find next entry */
+ for(i = gen->index; i < gen->table->num_bins; i++) {
+ if (gen->table->bins[i] != NIL(st_table_entry)) {
+ gen->index = i+1;
+ gen->entry = gen->table->bins[i];
+ break;
+ }
+ }
+ if (gen->entry == NIL(st_table_entry)) {
+ return 0; /* that's all folks ! */
+ }
+ }
+ *key_p = gen->entry->key;
+ if (value_p != 0) {
+ *value_p = gen->entry->record;
+ }
+ gen->entry = gen->entry->next;
+ return 1;
+}
+
+
+int
+st_gen_int(gen, key_p, value_p)
+st_generator *gen;
+char **key_p;
+long *value_p;
+{
+ register int i;
+
+ if (gen->entry == NIL(st_table_entry)) {
+ /* try to find next entry */
+ for(i = gen->index; i < gen->table->num_bins; i++) {
+ if (gen->table->bins[i] != NIL(st_table_entry)) {
+ gen->index = i+1;
+ gen->entry = gen->table->bins[i];
+ break;
+ }
+ }
+ if (gen->entry == NIL(st_table_entry)) {
+ return 0; /* that's all folks ! */
+ }
+ }
+ *key_p = gen->entry->key;
+ if (value_p != NIL(long)) {
+ *value_p = (long) gen->entry->record;
+ }
+ gen->entry = gen->entry->next;
+ return 1;
+}
+
+
+void
+st_free_gen(gen)
+st_generator *gen;
+{
+ FREE(gen);
+}
diff --git a/src/misc/st/st.h b/src/misc/st/st.h
new file mode 100644
index 00000000..c51873e9
--- /dev/null
+++ b/src/misc/st/st.h
@@ -0,0 +1,88 @@
+/*
+ * Revision Control Information
+ *
+ * /projects/hsis/CVS/utilities/st/st.h,v
+ * serdar
+ * 1.1
+ * 1993/07/29 01:00:21
+ *
+ */
+/* LINTLIBRARY */
+
+/* /projects/hsis/CVS/utilities/st/st.h,v 1.1 1993/07/29 01:00:21 serdar Exp */
+
+#ifndef ST_INCLUDED
+#define ST_INCLUDED
+
+typedef struct st_table_entry st_table_entry;
+struct st_table_entry {
+ char *key;
+ char *record;
+ st_table_entry *next;
+};
+
+typedef struct st_table st_table;
+struct st_table {
+ int (*compare)();
+ int (*hash)();
+ int num_bins;
+ int num_entries;
+ int max_density;
+ int reorder_flag;
+ double grow_factor;
+ st_table_entry **bins;
+};
+
+typedef struct st_generator st_generator;
+struct st_generator {
+ st_table *table;
+ st_table_entry *entry;
+ int index;
+};
+
+#define st_is_member(table,key) st_lookup(table,key,(char **) 0)
+#define st_count(table) ((table)->num_entries)
+
+enum st_retval {ST_CONTINUE, ST_STOP, ST_DELETE};
+
+typedef enum st_retval (*ST_PFSR)();
+typedef int (*ST_PFI)();
+
+EXTERN st_table *st_init_table_with_params ARGS((ST_PFI, ST_PFI, int, int, double, int));
+EXTERN st_table *st_init_table ARGS((ST_PFI, ST_PFI));
+EXTERN void st_free_table ARGS((st_table *));
+EXTERN int st_lookup ARGS((st_table *, char *, char **));
+EXTERN int st_lookup_int ARGS((st_table *, char *, int *));
+EXTERN int st_insert ARGS((st_table *, char *, char *));
+EXTERN int st_add_direct ARGS((st_table *, char *, char *));
+EXTERN int st_find_or_add ARGS((st_table *, char *, char ***));
+EXTERN int st_find ARGS((st_table *, char *, char ***));
+EXTERN st_table *st_copy ARGS((st_table *));
+EXTERN int st_delete ARGS((st_table *, char **, char **));
+EXTERN int st_delete_int ARGS((st_table *, long *, char **));
+EXTERN int st_foreach ARGS((st_table *, ST_PFSR, char *));
+EXTERN int st_strhash ARGS((char *, int));
+EXTERN int st_numhash ARGS((char *, int));
+EXTERN int st_ptrhash ARGS((char *, int));
+EXTERN int st_numcmp ARGS((char *, char *));
+EXTERN int st_ptrcmp ARGS((char *, char *));
+EXTERN st_generator *st_init_gen ARGS((st_table *));
+EXTERN int st_gen ARGS((st_generator *, char **, char **));
+EXTERN int st_gen_int ARGS((st_generator *, char **, long *));
+EXTERN void st_free_gen ARGS((st_generator *));
+
+
+#define ST_DEFAULT_MAX_DENSITY 5
+#define ST_DEFAULT_INIT_TABLE_SIZE 11
+#define ST_DEFAULT_GROW_FACTOR 2.0
+#define ST_DEFAULT_REORDER_FLAG 0
+
+#define st_foreach_item(table, gen, key, value) \
+ for(gen=st_init_gen(table); st_gen(gen,key,value) || (st_free_gen(gen),0);)
+
+#define st_foreach_item_int(table, gen, key, value) \
+ for(gen=st_init_gen(table); st_gen_int(gen,key,value) || (st_free_gen(gen),0);)
+
+#define ST_OUT_OF_MEM -10000
+
+#endif /* ST_INCLUDED */
diff --git a/src/misc/st/stmm.c b/src/misc/st/stmm.c
new file mode 100644
index 00000000..b75b0134
--- /dev/null
+++ b/src/misc/st/stmm.c
@@ -0,0 +1,683 @@
+/*
+ * Revision Control Information
+ *
+ * /projects/hsis/CVS/utilities/st/st.c,v
+ * serdar
+ * 1.1
+ * 1993/07/29 01:00:13
+ *
+ */
+#include <stdio.h>
+#include "util.h"
+#include "stmm.h"
+
+#define STMM_NUMCMP(x,y) ((x) != (y))
+#define STMM_NUMHASH(x,size) (ABS((long)x)%(size))
+#define STMM_PTRHASH(x,size) ((int)((unsigned long)(x)>>2)%size)
+#define EQUAL(func, x, y) \
+ ((((func) == stmm_numcmp) || ((func) == stmm_ptrcmp)) ?\
+ (STMM_NUMCMP((x),(y)) == 0) : ((*func)((x), (y)) == 0))
+
+
+#define do_hash(key, table)\
+ ((table->hash == stmm_ptrhash) ? STMM_PTRHASH((key),(table)->num_bins) :\
+ (table->hash == stmm_numhash) ? STMM_NUMHASH((key), (table)->num_bins) :\
+ (*table->hash)((key), (table)->num_bins))
+
+static int rehash ();
+int stmm_numhash (), stmm_ptrhash (), stmm_numcmp (), stmm_ptrcmp ();
+
+stmm_table *
+stmm_init_table_with_params (compare, hash, size, density, grow_factor,
+ reorder_flag)
+ int (*compare) ();
+ int (*hash) ();
+ int size;
+ int density;
+ double grow_factor;
+ int reorder_flag;
+{
+ int i;
+ stmm_table *new;
+
+ new = ALLOC (stmm_table, 1);
+ if (new == NIL (stmm_table)) {
+ return NIL (stmm_table);
+ }
+ new->compare = compare;
+ new->hash = hash;
+ new->num_entries = 0;
+ new->max_density = density;
+ new->grow_factor = grow_factor;
+ new->reorder_flag = reorder_flag;
+ if (size <= 0) {
+ size = 1;
+ }
+ new->num_bins = size;
+ new->bins = ALLOC (stmm_table_entry *, size);
+ if (new->bins == NIL (stmm_table_entry *)) {
+ FREE (new);
+ return NIL (stmm_table);
+ }
+ for (i = 0; i < size; i++) {
+ new->bins[i] = 0;
+ }
+
+ // added by alanmi
+ new->pMemMan = Extra_MmFixedStart(sizeof (stmm_table_entry));
+ return new;
+}
+
+stmm_table *
+stmm_init_table (compare, hash)
+ int (*compare) ();
+ int (*hash) ();
+{
+ return stmm_init_table_with_params (compare, hash,
+ STMM_DEFAULT_INIT_TABLE_SIZE,
+ STMM_DEFAULT_MAX_DENSITY,
+ STMM_DEFAULT_GROW_FACTOR,
+ STMM_DEFAULT_REORDER_FLAG);
+}
+
+void
+stmm_free_table (table)
+ stmm_table *table;
+{
+/*
+ register stmm_table_entry *ptr, *next;
+ int i;
+ for ( i = 0; i < table->num_bins; i++ )
+ {
+ ptr = table->bins[i];
+ while ( ptr != NIL( stmm_table_entry ) )
+ {
+ next = ptr->next;
+ FREE( ptr );
+ ptr = next;
+ }
+ }
+*/
+ // no need to deallocate entries because they are in the memory manager now
+ // added by alanmi
+ if ( table->pMemMan )
+ Extra_MmFixedStop (table->pMemMan, 0);
+ FREE (table->bins);
+ FREE (table);
+}
+
+// this function recycles all the bins
+void
+stmm_clean (table)
+ stmm_table *table;
+{
+ int i;
+ // clean the bins
+ for (i = 0; i < table->num_bins; i++)
+ table->bins[i] = NULL;
+ // reset the parameters
+ table->num_entries = 0;
+ // restart the memory manager
+ Extra_MmFixedRestart (table->pMemMan);
+}
+
+
+#define PTR_NOT_EQUAL(table, ptr, user_key)\
+(ptr != NIL(stmm_table_entry) && !EQUAL(table->compare, user_key, (ptr)->key))
+
+#define FIND_ENTRY(table, hash_val, key, ptr, last) \
+ (last) = &(table)->bins[hash_val];\
+ (ptr) = *(last);\
+ while (PTR_NOT_EQUAL((table), (ptr), (key))) {\
+ (last) = &(ptr)->next; (ptr) = *(last);\
+ }\
+ if ((ptr) != NIL(stmm_table_entry) && (table)->reorder_flag) {\
+ *(last) = (ptr)->next;\
+ (ptr)->next = (table)->bins[hash_val];\
+ (table)->bins[hash_val] = (ptr);\
+ }
+
+int
+stmm_lookup (table, key, value)
+ stmm_table *table;
+ register char *key;
+ char **value;
+{
+ int hash_val;
+ register stmm_table_entry *ptr, **last;
+
+ hash_val = do_hash (key, table);
+
+ FIND_ENTRY (table, hash_val, key, ptr, last);
+
+ if (ptr == NIL (stmm_table_entry)) {
+ return 0;
+ }
+ else {
+ if (value != NIL (char *))
+ {
+ *value = ptr->record;
+ }
+ return 1;
+ }
+}
+
+int
+stmm_lookup_int (table, key, value)
+ stmm_table *table;
+ register char *key;
+ int *value;
+{
+ int hash_val;
+ register stmm_table_entry *ptr, **last;
+
+ hash_val = do_hash (key, table);
+
+ FIND_ENTRY (table, hash_val, key, ptr, last);
+
+ if (ptr == NIL (stmm_table_entry)) {
+ return 0;
+ }
+ else {
+ if (value != NIL (int))
+ {
+ *value = (long) ptr->record;
+ }
+ return 1;
+ }
+}
+
+// This macro contained a line
+// new = ALLOC(stmm_table_entry, 1);
+// which was modified by alanmi
+
+
+/* This macro does not check if memory allocation fails. Use at you own risk */
+#define ADD_DIRECT(table, key, value, hash_val, new)\
+{\
+ if (table->num_entries/table->num_bins >= table->max_density) {\
+ rehash(table);\
+ hash_val = do_hash(key,table);\
+ }\
+ \
+ new = (stmm_table_entry *)Extra_MmFixedEntryFetch( table->pMemMan );\
+ \
+ new->key = key;\
+ new->record = value;\
+ new->next = table->bins[hash_val];\
+ table->bins[hash_val] = new;\
+ table->num_entries++;\
+}
+
+int
+stmm_insert (table, key, value)
+ register stmm_table *table;
+ register char *key;
+ char *value;
+{
+ int hash_val;
+ stmm_table_entry *new;
+ register stmm_table_entry *ptr, **last;
+
+ hash_val = do_hash (key, table);
+
+ FIND_ENTRY (table, hash_val, key, ptr, last);
+
+ if (ptr == NIL (stmm_table_entry)) {
+ if (table->num_entries / table->num_bins >= table->max_density) {
+ if (rehash (table) == STMM_OUT_OF_MEM) {
+ return STMM_OUT_OF_MEM;
+ }
+ hash_val = do_hash (key, table);
+ }
+
+// new = ALLOC( stmm_table_entry, 1 );
+ new = (stmm_table_entry *) Extra_MmFixedEntryFetch (table->pMemMan);
+ if (new == NIL (stmm_table_entry)) {
+ return STMM_OUT_OF_MEM;
+ }
+
+ new->key = key;
+ new->record = value;
+ new->next = table->bins[hash_val];
+ table->bins[hash_val] = new;
+ table->num_entries++;
+ return 0;
+ }
+ else {
+ ptr->record = value;
+ return 1;
+ }
+}
+
+int
+stmm_add_direct (table, key, value)
+ stmm_table *table;
+ char *key;
+ char *value;
+{
+ int hash_val;
+ stmm_table_entry *new;
+
+ hash_val = do_hash (key, table);
+ if (table->num_entries / table->num_bins >= table->max_density) {
+ if (rehash (table) == STMM_OUT_OF_MEM) {
+ return STMM_OUT_OF_MEM;
+ }
+ }
+ hash_val = do_hash (key, table);
+
+// new = ALLOC( stmm_table_entry, 1 );
+ new = (stmm_table_entry *) Extra_MmFixedEntryFetch (table->pMemMan);
+ if (new == NIL (stmm_table_entry)) {
+ return STMM_OUT_OF_MEM;
+ }
+
+ new->key = key;
+ new->record = value;
+ new->next = table->bins[hash_val];
+ table->bins[hash_val] = new;
+ table->num_entries++;
+ return 1;
+}
+
+int
+stmm_find_or_add (table, key, slot)
+ stmm_table *table;
+ char *key;
+ char ***slot;
+{
+ int hash_val;
+ stmm_table_entry *new, *ptr, **last;
+
+ hash_val = do_hash (key, table);
+
+ FIND_ENTRY (table, hash_val, key, ptr, last);
+
+ if (ptr == NIL (stmm_table_entry)) {
+ if (table->num_entries / table->num_bins >= table->max_density) {
+ if (rehash (table) == STMM_OUT_OF_MEM) {
+ return STMM_OUT_OF_MEM;
+ }
+ hash_val = do_hash (key, table);
+ }
+
+ // new = ALLOC( stmm_table_entry, 1 );
+ new = (stmm_table_entry *) Extra_MmFixedEntryFetch (table->pMemMan);
+ if (new == NIL (stmm_table_entry)) {
+ return STMM_OUT_OF_MEM;
+ }
+
+ new->key = key;
+ new->record = (char *) 0;
+ new->next = table->bins[hash_val];
+ table->bins[hash_val] = new;
+ table->num_entries++;
+ if (slot != NIL (char **))
+ *slot = &new->record;
+ return 0;
+ }
+ else {
+ if (slot != NIL (char **))
+ *slot = &ptr->record;
+ return 1;
+ }
+}
+
+int
+stmm_find (table, key, slot)
+ stmm_table *table;
+ char *key;
+ char ***slot;
+{
+ int hash_val;
+ stmm_table_entry *ptr, **last;
+
+ hash_val = do_hash (key, table);
+
+ FIND_ENTRY (table, hash_val, key, ptr, last);
+
+ if (ptr == NIL (stmm_table_entry)) {
+ return 0;
+ }
+ else {
+ if (slot != NIL (char **))
+ {
+ *slot = &ptr->record;
+ }
+ return 1;
+ }
+}
+
+static int
+rehash (table)
+ register stmm_table *table;
+{
+ register stmm_table_entry *ptr, *next, **old_bins;
+ int i, old_num_bins, hash_val, old_num_entries;
+
+ /* save old values */
+ old_bins = table->bins;
+ old_num_bins = table->num_bins;
+ old_num_entries = table->num_entries;
+
+ /* rehash */
+ table->num_bins = (int) (table->grow_factor * old_num_bins);
+ if (table->num_bins % 2 == 0) {
+ table->num_bins += 1;
+ }
+ table->num_entries = 0;
+ table->bins = ALLOC (stmm_table_entry *, table->num_bins);
+ if (table->bins == NIL (stmm_table_entry *)) {
+ table->bins = old_bins;
+ table->num_bins = old_num_bins;
+ table->num_entries = old_num_entries;
+ return STMM_OUT_OF_MEM;
+ }
+ /* initialize */
+ for (i = 0; i < table->num_bins; i++) {
+ table->bins[i] = 0;
+ }
+
+ /* copy data over */
+ for (i = 0; i < old_num_bins; i++) {
+ ptr = old_bins[i];
+ while (ptr != NIL (stmm_table_entry)) {
+ next = ptr->next;
+ hash_val = do_hash (ptr->key, table);
+ ptr->next = table->bins[hash_val];
+ table->bins[hash_val] = ptr;
+ table->num_entries++;
+ ptr = next;
+ }
+ }
+ FREE (old_bins);
+
+ return 1;
+}
+
+stmm_table *
+stmm_copy (old_table)
+ stmm_table *old_table;
+{
+ stmm_table *new_table;
+ stmm_table_entry *ptr, /* *newptr, *next, */ *new;
+ int i, /*j, */ num_bins = old_table->num_bins;
+
+ new_table = ALLOC (stmm_table, 1);
+ if (new_table == NIL (stmm_table)) {
+ return NIL (stmm_table);
+ }
+
+ *new_table = *old_table;
+ new_table->bins = ALLOC (stmm_table_entry *, num_bins);
+ if (new_table->bins == NIL (stmm_table_entry *)) {
+ FREE (new_table);
+ return NIL (stmm_table);
+ }
+
+ // allocate the memory manager for the new table
+ new_table->pMemMan =
+ Extra_MmFixedStart (sizeof (stmm_table_entry));
+
+ for (i = 0; i < num_bins; i++) {
+ new_table->bins[i] = NIL (stmm_table_entry);
+ ptr = old_table->bins[i];
+ while (ptr != NIL (stmm_table_entry)) {
+// new = ALLOC( stmm_table_entry, 1 );
+ new =
+ (stmm_table_entry *) Extra_MmFixedEntryFetch (new_table->
+ pMemMan);
+
+ if (new == NIL (stmm_table_entry)) {
+/*
+ for ( j = 0; j <= i; j++ )
+ {
+ newptr = new_table->bins[j];
+ while ( newptr != NIL( stmm_table_entry ) )
+ {
+ next = newptr->next;
+ FREE( newptr );
+ newptr = next;
+ }
+ }
+*/
+ Extra_MmFixedStop (new_table->pMemMan, 0);
+
+ FREE (new_table->bins);
+ FREE (new_table);
+ return NIL (stmm_table);
+ }
+ *new = *ptr;
+ new->next = new_table->bins[i];
+ new_table->bins[i] = new;
+ ptr = ptr->next;
+ }
+ }
+ return new_table;
+}
+
+int
+stmm_delete (table, keyp, value)
+ register stmm_table *table;
+ register char **keyp;
+ char **value;
+{
+ int hash_val;
+ char *key = *keyp;
+ register stmm_table_entry *ptr, **last;
+
+ hash_val = do_hash (key, table);
+
+ FIND_ENTRY (table, hash_val, key, ptr, last);
+
+ if (ptr == NIL (stmm_table_entry)) {
+ return 0;
+ }
+
+ *last = ptr->next;
+ if (value != NIL (char *))
+ *value = ptr->record;
+ *keyp = ptr->key;
+// FREE( ptr );
+ Extra_MmFixedEntryRecycle (table->pMemMan, (char *) ptr);
+
+ table->num_entries--;
+ return 1;
+}
+
+int
+stmm_delete_int (table, keyp, value)
+ register stmm_table *table;
+ register long *keyp;
+ char **value;
+{
+ int hash_val;
+ char *key = (char *) *keyp;
+ register stmm_table_entry *ptr, **last;
+
+ hash_val = do_hash (key, table);
+
+ FIND_ENTRY (table, hash_val, key, ptr, last);
+
+ if (ptr == NIL (stmm_table_entry)) {
+ return 0;
+ }
+
+ *last = ptr->next;
+ if (value != NIL (char *))
+ *value = ptr->record;
+ *keyp = (long) ptr->key;
+// FREE( ptr );
+ Extra_MmFixedEntryRecycle (table->pMemMan, (char *) ptr);
+
+ table->num_entries--;
+ return 1;
+}
+
+int
+stmm_foreach (table, func, arg)
+ stmm_table *table;
+ enum stmm_retval (*func) ();
+ char *arg;
+{
+ stmm_table_entry *ptr, **last;
+ enum stmm_retval retval;
+ int i;
+
+ for (i = 0; i < table->num_bins; i++) {
+ last = &table->bins[i];
+ ptr = *last;
+ while (ptr != NIL (stmm_table_entry)) {
+ retval = (*func) (ptr->key, ptr->record, arg);
+ switch (retval) {
+ case STMM_CONTINUE:
+ last = &ptr->next;
+ ptr = *last;
+ break;
+ case STMM_STOP:
+ return 0;
+ case STMM_DELETE:
+ *last = ptr->next;
+ table->num_entries--; /* cstevens@ic */
+// FREE( ptr );
+ Extra_MmFixedEntryRecycle (table->pMemMan, (char *) ptr);
+
+ ptr = *last;
+ }
+ }
+ }
+ return 1;
+}
+
+int
+stmm_strhash (string, modulus)
+ register char *string;
+ int modulus;
+{
+ register int val = 0;
+ register int c;
+
+ while ((c = *string++) != '\0') {
+ val = val * 997 + c;
+ }
+
+ return ((val < 0) ? -val : val) % modulus;
+}
+
+int
+stmm_numhash (x, size)
+ char *x;
+ int size;
+{
+ return STMM_NUMHASH (x, size);
+}
+
+int
+stmm_ptrhash (x, size)
+ char *x;
+ int size;
+{
+ return STMM_PTRHASH (x, size);
+}
+
+int
+stmm_numcmp (x, y)
+ char *x;
+ char *y;
+{
+ return STMM_NUMCMP (x, y);
+}
+
+int
+stmm_ptrcmp (x, y)
+ char *x;
+ char *y;
+{
+ return STMM_NUMCMP (x, y);
+}
+
+stmm_generator *
+stmm_init_gen (table)
+ stmm_table *table;
+{
+ stmm_generator *gen;
+
+ gen = ALLOC (stmm_generator, 1);
+ if (gen == NIL (stmm_generator)) {
+ return NIL (stmm_generator);
+ }
+ gen->table = table;
+ gen->entry = NIL (stmm_table_entry);
+ gen->index = 0;
+ return gen;
+}
+
+
+int
+stmm_gen (gen, key_p, value_p)
+ stmm_generator *gen;
+ char **key_p;
+ char **value_p;
+{
+ register int i;
+
+ if (gen->entry == NIL (stmm_table_entry)) {
+ /* try to find next entry */
+ for (i = gen->index; i < gen->table->num_bins; i++) {
+ if (gen->table->bins[i] != NIL (stmm_table_entry)) {
+ gen->index = i + 1;
+ gen->entry = gen->table->bins[i];
+ break;
+ }
+ }
+ if (gen->entry == NIL (stmm_table_entry)) {
+ return 0; /* that's all folks ! */
+ }
+ }
+ *key_p = gen->entry->key;
+ if (value_p != 0) {
+ *value_p = gen->entry->record;
+ }
+ gen->entry = gen->entry->next;
+ return 1;
+}
+
+
+int
+stmm_gen_int (gen, key_p, value_p)
+ stmm_generator *gen;
+ char **key_p;
+ long *value_p;
+{
+ register int i;
+
+ if (gen->entry == NIL (stmm_table_entry)) {
+ /* try to find next entry */
+ for (i = gen->index; i < gen->table->num_bins; i++) {
+ if (gen->table->bins[i] != NIL (stmm_table_entry)) {
+ gen->index = i + 1;
+ gen->entry = gen->table->bins[i];
+ break;
+ }
+ }
+ if (gen->entry == NIL (stmm_table_entry)) {
+ return 0; /* that's all folks ! */
+ }
+ }
+ *key_p = gen->entry->key;
+ if (value_p != NIL (long))
+ {
+ *value_p = (long) gen->entry->record;
+ }
+ gen->entry = gen->entry->next;
+ return 1;
+}
+
+
+void
+stmm_free_gen (gen)
+ stmm_generator *gen;
+{
+ FREE (gen);
+}
diff --git a/src/misc/st/stmm.h b/src/misc/st/stmm.h
new file mode 100644
index 00000000..1fe3dfd2
--- /dev/null
+++ b/src/misc/st/stmm.h
@@ -0,0 +1,119 @@
+/*
+ * Revision Control Information
+ *
+ * /projects/hsis/CVS/utilities/st/st.h,v
+ * serdar
+ * 1.1
+ * 1993/07/29 01:00:21
+ *
+ */
+/* LINTLIBRARY */
+
+/* /projects/hsis/CVS/utilities/st/st.h,v 1.1 1993/07/29 01:00:21 serdar Exp */
+
+#ifndef STMM_INCLUDED
+#define STMM_INCLUDED
+
+#include "extra.h"
+
+typedef struct stmm_table_entry stmm_table_entry;
+typedef struct stmm_table stmm_table;
+typedef struct stmm_generator stmm_generator;
+
+struct stmm_table_entry
+{
+ char *key;
+ char *record;
+ stmm_table_entry *next;
+};
+
+struct stmm_table
+{
+ int (*compare) ();
+ int (*hash) ();
+ int num_bins;
+ int num_entries;
+ int max_density;
+ int reorder_flag;
+ double grow_factor;
+ stmm_table_entry **bins;
+ // memory manager to improve runtime and prevent memory fragmentation
+ // added by alanmi - January 16, 2003
+ Extra_MmFixed_t *pMemMan;
+};
+
+struct stmm_generator
+{
+ stmm_table *table;
+ stmm_table_entry *entry;
+ int index;
+};
+
+#define stmm_is_member(table,key) stmm_lookup(table,key,(char **) 0)
+#define stmm_count(table) ((table)->num_entries)
+
+enum stmm_retval
+{ STMM_CONTINUE, STMM_STOP, STMM_DELETE };
+
+typedef enum stmm_retval (*STMM_PFSR) ();
+typedef int (*STMM_PFI) ();
+
+EXTERN stmm_table *stmm_init_table_with_params
+ARGS ((STMM_PFI, STMM_PFI, int, int, double, int));
+EXTERN stmm_table *stmm_init_table ARGS ((STMM_PFI, STMM_PFI));
+EXTERN void stmm_free_table ARGS ((stmm_table *));
+EXTERN int stmm_lookup ARGS ((stmm_table *, char *, char **));
+EXTERN int stmm_lookup_int ARGS ((stmm_table *, char *, int *));
+EXTERN int stmm_insert ARGS ((stmm_table *, char *, char *));
+EXTERN int stmm_add_direct ARGS ((stmm_table *, char *, char *));
+EXTERN int stmm_find_or_add ARGS ((stmm_table *, char *, char ***));
+EXTERN int stmm_find ARGS ((stmm_table *, char *, char ***));
+EXTERN stmm_table *stmm_copy ARGS ((stmm_table *));
+EXTERN int stmm_delete ARGS ((stmm_table *, char **, char **));
+EXTERN int stmm_delete_int ARGS ((stmm_table *, long *, char **));
+EXTERN int stmm_foreach ARGS ((stmm_table *, STMM_PFSR, char *));
+EXTERN int stmm_strhash ARGS ((char *, int));
+EXTERN int stmm_numhash ARGS ((char *, int));
+EXTERN int stmm_ptrhash ARGS ((char *, int));
+EXTERN int stmm_numcmp ARGS ((char *, char *));
+EXTERN int stmm_ptrcmp ARGS ((char *, char *));
+EXTERN stmm_generator *stmm_init_gen ARGS ((stmm_table *));
+EXTERN int stmm_gen ARGS ((stmm_generator *, char **, char **));
+EXTERN int stmm_gen_int ARGS ((stmm_generator *, char **, long *));
+EXTERN void stmm_free_gen ARGS ((stmm_generator *));
+// additional functions
+EXTERN void stmm_clean ARGS ((stmm_table *));
+
+
+
+#define STMM_DEFAULT_MAX_DENSITY 5
+#define STMM_DEFAULT_INIT_TABLE_SIZE 11
+#define STMM_DEFAULT_GROW_FACTOR 2.0
+#define STMM_DEFAULT_REORDER_FLAG 0
+
+// added by Zhihong: no need for memory allocation
+#define stmm_foreach_item2(tb, /* stmm_generator */gen, key, value) \
+ for(gen.table=(tb), gen.entry=NIL(stmm_table_entry), gen.index=0; \
+ stmm_gen(&(gen),key,value);)
+
+#define stmm_foreach_item(table, gen, key, value) \
+ for(gen=stmm_init_gen(table); stmm_gen(gen,key,value) || (stmm_free_gen(gen),0);)
+
+#define stmm_foreach_item_int(table, gen, key, value) \
+ for(gen=stmm_init_gen(table); stmm_gen_int(gen,key,value) || (stmm_free_gen(gen),0);)
+
+#define STMM_OUT_OF_MEM -10000
+
+/*
+
+// consider adding these other other similar definitions
+#define st_table stmm_table
+#define st_insert stmm_insert
+#define st_delete stmm_delete
+#define st_lookup stmm_lookup
+#define st_init_table stmm_init_table
+#define st_free_table stmm_free_table
+
+*/
+
+#endif /* STMM_INCLUDED */
diff --git a/src/misc/util/cpu_stats.c b/src/misc/util/cpu_stats.c
new file mode 100644
index 00000000..aa2d18ef
--- /dev/null
+++ b/src/misc/util/cpu_stats.c
@@ -0,0 +1,122 @@
+/*
+ * Revision Control Information
+ *
+ * /projects/hsis/CVS/utilities/util/cpu_stats.c,v
+ * rajeev
+ * 1.4
+ * 1995/08/08 22:41:17
+ *
+ */
+/* LINTLIBRARY */
+
+#include <stdio.h>
+#include "util.h"
+
+
+#include <sys/types.h>
+//#include <sys/time.h>
+#ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+#endif
+
+#if defined(_IBMR2)
+#define etext _etext
+#define edata _edata
+#define end _end
+#endif
+
+#ifndef __CYGWIN32__
+extern int end, etext, edata;
+#endif
+
+void
+util_print_cpu_stats(fp)
+FILE *fp;
+{
+ (void) fprintf(fp, "Usage statistics not available\n");
+}
+
+#if 0
+
+void
+util_print_cpu_stats(fp)
+FILE *fp;
+{
+#if HAVE_SYS_RESOURCE_H && !defined(__CYGWIN32__)
+ struct rusage rusage;
+#ifdef RLIMIT_DATA
+ struct rlimit rlp;
+#endif
+ int text, data, vm_limit, vm_soft_limit;
+ double user, system, scale;
+ char hostname[257];
+ int vm_text, vm_init_data, vm_uninit_data, vm_sbrk_data;
+
+ /* Get the hostname */
+ (void) gethostname(hostname, 256);
+ hostname[256] = '\0'; /* just in case */
+
+ /* Get the virtual memory sizes */
+ vm_text = ((int) (&etext)) / 1024.0 + 0.5;
+ vm_init_data = ((int) (&edata) - (int) (&etext)) / 1024.0 + 0.5;
+ vm_uninit_data = ((int) (&end) - (int) (&edata)) / 1024.0 + 0.5;
+ vm_sbrk_data = (sizeof(char) * ((char *) sbrk(0) - (char *) (&end))) / 1024.0 + 0.5;
+
+ /* Get virtual memory limits */
+#ifdef RLIMIT_DATA /* In HP-UX, with cc, this constant does not exist */
+ (void) getrlimit(RLIMIT_DATA, &rlp);
+ vm_limit = rlp.rlim_max / 1024.0 + 0.5;
+ vm_soft_limit = rlp.rlim_cur / 1024.0 + 0.5;
+#else
+ vm_limit = -1;
+ vm_soft_limit = -1;
+#endif
+
+ /* Get usage stats */
+ (void) getrusage(RUSAGE_SELF, &rusage);
+ user = rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec/1.0e6;
+ system = rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec/1.0e6;
+ scale = (user + system)*100.0;
+ if (scale == 0.0) scale = 0.001;
+
+ (void) fprintf(fp, "Runtime Statistics\n");
+ (void) fprintf(fp, "------------------\n");
+ (void) fprintf(fp, "Machine name: %s\n", hostname);
+ (void) fprintf(fp, "User time %6.1f seconds\n", user);
+ (void) fprintf(fp, "System time %6.1f seconds\n\n", system);
+
+ text = rusage.ru_ixrss / scale + 0.5;
+ data = (rusage.ru_idrss + rusage.ru_isrss) / scale + 0.5;
+ (void) fprintf(fp, "Average resident text size = %5dK\n", text);
+ (void) fprintf(fp, "Average resident data+stack size = %5dK\n", data);
+ (void) fprintf(fp, "Maximum resident size = %5ldK\n\n",
+ rusage.ru_maxrss/2);
+ (void) fprintf(fp, "Virtual text size = %5dK\n",
+ vm_text);
+ (void) fprintf(fp, "Virtual data size = %5dK\n",
+ vm_init_data + vm_uninit_data + vm_sbrk_data);
+ (void) fprintf(fp, " data size initialized = %5dK\n",
+ vm_init_data);
+ (void) fprintf(fp, " data size uninitialized = %5dK\n",
+ vm_uninit_data);
+ (void) fprintf(fp, " data size sbrk = %5dK\n",
+ vm_sbrk_data);
+ /* In some platforms, this constant does not exist */
+#ifdef RLIMIT_DATA
+ (void) fprintf(fp, "Virtual memory limit = %5dK (%dK)\n\n",
+ vm_soft_limit, vm_limit);
+#endif
+ (void) fprintf(fp, "Major page faults = %ld\n", rusage.ru_majflt);
+ (void) fprintf(fp, "Minor page faults = %ld\n", rusage.ru_minflt);
+ (void) fprintf(fp, "Swaps = %ld\n", rusage.ru_nswap);
+ (void) fprintf(fp, "Input blocks = %ld\n", rusage.ru_inblock);
+ (void) fprintf(fp, "Output blocks = %ld\n", rusage.ru_oublock);
+ (void) fprintf(fp, "Context switch (voluntary) = %ld\n", rusage.ru_nvcsw);
+ (void) fprintf(fp, "Context switch (involuntary) = %ld\n", rusage.ru_nivcsw);
+#else /* Do not have sys/resource.h */
+ (void) fprintf(fp, "Usage statistics not available\n");
+#endif
+}
+
+#endif
+
diff --git a/src/misc/util/cpu_time.c b/src/misc/util/cpu_time.c
new file mode 100644
index 00000000..d264bdc9
--- /dev/null
+++ b/src/misc/util/cpu_time.c
@@ -0,0 +1,128 @@
+/**CFile***********************************************************************
+
+ FileName [ cpu_time.c ]
+
+ PackageName [ util ]
+
+ Synopsis [ System time calls ]
+
+ Description [ The problem is that all unix systems have a different notion
+ of how fast time goes (i.e., the units returned by). This
+ returns a consistent result. ]
+
+ Author [ Stephen Edwards <sedwards@eecs.berkeley.edu> and others ]
+
+ Copyright [Copyright (c) 1994-1996 The Regents of the Univ. of California.
+ All rights reserved.
+
+ Permission is hereby granted, without written agreement and without license
+ or royalty fees, to use, copy, modify, and distribute this software and its
+ documentation for any purpose, provided that the above copyright notice and
+ the following two paragraphs appear in all copies of this software.
+
+ IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
+ "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE
+ MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.]
+
+******************************************************************************/
+
+#include "util.h"
+
+#if HAVE_SYS_TYPES_H
+# include<sys/types.h>
+#endif
+
+#if HAVE_SYS_TIMES_H
+# include<sys/times.h>
+#endif
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticEnd***************************************************************/
+
+/**Function********************************************************************
+
+ Synopsis [ Return elapsed time in milliseconds ]
+
+ Description [ Return a long which represents the elapsed time in
+ milliseconds since some constant reference. <P>
+
+ There are two possibilities:
+ <OL>
+ <LI> The system is non-POSIX compliant, so unistd.h
+ and hence sysconf() can't tell us the clock tick
+ speed. At this point, we have to resort to
+ using the user-settable CLOCK_RESOLUTION definition
+ to get the right speed
+ <LI> The system is POSIX-compliant. unistd.h gives
+ us sysconf(), which tells us the clock rate.
+ </OL>
+ ]
+
+ SideEffects [ none ]
+
+******************************************************************************/
+
+/*
+long
+util_cpu_time()
+{
+ long t = 0;
+
+#if HAVE_SYSCONF == 1
+
+ // Code for POSIX systems
+
+ struct tms buffer;
+ long nticks; // number of clock ticks per second
+
+ nticks = sysconf(_SC_CLK_TCK);
+ times(&buffer);
+ t = buffer.tms_utime * (1000.0/nticks);
+
+#else
+# ifndef vms
+
+ // Code for non-POSIX systems
+
+ struct tms buffer;
+
+ time(&buffer);
+ t = buffer.tms_utime * 1000.0 / CLOCK_RESOLUTION;
+
+# else
+
+ // Code for VMS (?)
+
+ struct {int p1, p2, p3, p4;} buffer;
+ static long ref_time;
+ times(&buffer);
+ t = buffer.p1 * 10;
+ if (ref_time == 0)
+ ref_time = t;
+ t = t - ref_time;
+
+# endif // vms
+#endif // _POSIX_VERSION
+
+ return t;
+}
+*/
+
+
+long
+util_cpu_time()
+{
+ return clock();
+}
diff --git a/src/misc/util/datalimit.c b/src/misc/util/datalimit.c
new file mode 100644
index 00000000..96c2ce95
--- /dev/null
+++ b/src/misc/util/datalimit.c
@@ -0,0 +1,95 @@
+/**CFile************************************************************************
+
+ FileName [datalimit.c]
+
+ PackageName [util]
+
+ Synopsis [Routine to obtain the maximum data size available to a program. The
+ routine is based on "getrlimit". If the system does not have this function,
+ the default value RLIMIT_DATA_DEFAULT is assumed. This function provides an
+ informative value, it does not restrict the size of the program in any way.]
+
+ Author [Fabio Somenzi <fabio@colorado.edu>]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+
+static char rcsid[] UNUSED = "$Id: datalimit.c,v 1.1.1.1 2003/02/24 22:24:04 wjiang Exp $";
+
+#if HAVE_SYS_RESOURCE_H
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/resource.h>
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Structure declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef RLIMIT_DATA_DEFAULT
+#define RLIMIT_DATA_DEFAULT 67108864 /* assume 64MB by default */
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticEnd***************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Function that computes the data limit of the process.]
+
+ SideEffects []
+
+******************************************************************************/
+int
+getSoftDataLimit()
+{
+#if HAVE_SYS_RESOURCE_H && HAVE_GETRLIMIT && defined(RLIMIT_DATA)
+ struct rlimit rl;
+ int result;
+
+ result = getrlimit(RLIMIT_DATA, &rl);
+ if (result != 0 || rl.rlim_cur == RLIM_INFINITY)
+ return(RLIMIT_DATA_DEFAULT);
+ else
+ return(rl.rlim_cur);
+#else
+ return(RLIMIT_DATA_DEFAULT);
+#endif
+
+} /* end of getSoftDataLimit */
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
diff --git a/src/misc/util/getopt.c b/src/misc/util/getopt.c
new file mode 100644
index 00000000..778c34d6
--- /dev/null
+++ b/src/misc/util/getopt.c
@@ -0,0 +1,84 @@
+/*
+ * Revision Control Information
+ *
+ * /projects/hsis/CVS/utilities/util/getopt.c,v
+ * rajeev
+ * 1.3
+ * 1995/08/08 22:41:22
+ *
+ */
+/* LINTLIBRARY */
+
+#include <stdio.h>
+#include "util.h"
+
+
+/* File : getopt.c
+ * Author : Henry Spencer, University of Toronto
+ * Updated: 28 April 1984
+ *
+ * Changes: (R Rudell)
+ * changed index() to strchr();
+ * added getopt_reset() to reset the getopt argument parsing
+ *
+ * Purpose: get option letter from argv.
+ */
+
+char *util_optarg; /* Global argument pointer. */
+int util_optind = 0; /* Global argv index. */
+static char *scan;
+
+
+void
+util_getopt_reset()
+{
+ util_optarg = 0;
+ util_optind = 0;
+ scan = 0;
+}
+
+
+
+int
+util_getopt(argc, argv, optstring)
+int argc;
+char *argv[];
+char *optstring;
+{
+ register int c;
+ register char *place;
+
+ util_optarg = NIL(char);
+
+ if (scan == NIL(char) || *scan == '\0') {
+ if (util_optind == 0) util_optind++;
+ if (util_optind >= argc) return EOF;
+ place = argv[util_optind];
+ if (place[0] != '-' || place[1] == '\0') return EOF;
+ util_optind++;
+ if (place[1] == '-' && place[2] == '\0') return EOF;
+ scan = place+1;
+ }
+
+ c = *scan++;
+ place = strchr(optstring, c);
+ if (place == NIL(char) || c == ':') {
+ (void) fprintf(stderr, "%s: unknown option %c\n", argv[0], c);
+ return '?';
+ }
+ if (*++place == ':') {
+ if (*scan != '\0') {
+ util_optarg = scan;
+ scan = NIL(char);
+ } else {
+ if (util_optind >= argc) {
+ (void) fprintf(stderr, "%s: %c requires an argument\n",
+ argv[0], c);
+ return '?';
+ }
+ util_optarg = argv[util_optind];
+ util_optind++;
+ }
+ }
+ return c;
+}
diff --git a/src/misc/util/leaks.h b/src/misc/util/leaks.h
new file mode 100644
index 00000000..daa628b1
--- /dev/null
+++ b/src/misc/util/leaks.h
@@ -0,0 +1,30 @@
+///////////////////////////////////////////////////////////////////////
+// This file is used to detect memory leaks using Visual Studio 6.0
+// The idea comes from the following webpage:
+// http://www.michaelmoser.org/memory.htm
+//////////////////////////////////////
+
+#ifndef __LEAKS_H__
+#define __LEAKS_H__
+
+#ifdef _DEBUG
+#define _CRTDBG_MAP_ALLOC // include Microsoft memory leak detection procedures
+//#define _INC_MALLOC // exclude standard memory alloc procedures
+
+#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
+#define calloc(c, s) _calloc_dbg(c, s, _NORMAL_BLOCK, __FILE__, __LINE__)
+#define realloc(p, s) _realloc_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__)
+//#define _expand(p, s) _expand_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__)
+//#define free(p) _free_dbg(p, _NORMAL_BLOCK)
+//#define _msize(p) _msize_dbg(p, _NORMAL_BLOCK)
+
+//#include <stdlib.h>
+#include <stdlib_hack.h>
+#include <crtdbg.h>
+#endif
+
+#endif
+
+//////////////////////////////////////
+
+
diff --git a/src/misc/util/module.make b/src/misc/util/module.make
new file mode 100644
index 00000000..06eba7e4
--- /dev/null
+++ b/src/misc/util/module.make
@@ -0,0 +1,8 @@
+SRC += src/misc/util/cpu_stats.c \
+ src/misc/util/cpu_time.c \
+ src/misc/util/datalimit.c \
+ src/misc/util/getopt.c \
+ src/misc/util/pathsearch.c \
+ src/misc/util/safe_mem.c \
+ src/misc/util/strsav.c \
+ src/misc/util/texpand.c
diff --git a/src/misc/util/pathsearch.c b/src/misc/util/pathsearch.c
new file mode 100644
index 00000000..d4d845eb
--- /dev/null
+++ b/src/misc/util/pathsearch.c
@@ -0,0 +1,131 @@
+/*
+ * Revision Control Information
+ *
+ * /projects/hsis/CVS/utilities/util/pathsearch.c,v
+ * rajeev
+ * 1.3
+ * 1995/08/08 22:41:24
+ *
+ */
+/* LINTLIBRARY */
+
+#if HAVE_SYS_FILE_H
+# include <sys/file.h>
+#endif
+
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+
+#include "util.h"
+
+/**Function********************************************************************
+
+ Synopsis [ Check that a given file is present and accessible ]
+
+ SideEffects [none]
+******************************************************************************/
+static int
+check_file(filename, mode)
+char *filename;
+char *mode;
+{
+#if defined(HAVE_SYS_STAT_H)
+ struct stat stat_rec;
+ int access_char = mode[0];
+ int access_mode = R_OK;
+
+ /* First check that the file is a regular file. */
+
+ if (stat(filename,&stat_rec) == 0
+ && (stat_rec.st_mode&S_IFMT) == S_IFREG) {
+ if (access_char == 'w') {
+ access_mode = W_OK;
+ } else if (access_char == 'x') {
+ access_mode = X_OK;
+ }
+ return access(filename,access_mode) == 0;
+ }
+ return 0;
+
+#else
+
+ FILE *fp;
+ int got_file;
+
+ if (strcmp(mode, "x") == 0) {
+ mode = "r";
+ }
+ fp = fopen(filename, mode);
+ got_file = (fp != 0);
+ if (fp != 0) {
+ (void) fclose(fp);
+ }
+ return got_file;
+
+#endif
+}
+
+/**Function********************************************************************
+
+ Synopsis [ Search for a program in all possible paths ]
+
+ SideEffects [none]
+
+******************************************************************************/
+char *
+util_path_search(prog)
+char *prog;
+{
+#ifdef HAVE_GETENV
+ return util_file_search(prog, getenv("PATH"), "x");
+#else
+ return util_file_search(prog, NIL(char), "x");
+#endif
+}
+
+char *
+util_file_search(file, path, mode)
+char *file; /* file we're looking for */
+char *path; /* search path, colon separated */
+char *mode; /* "r", "w", or "x" */
+{
+ int quit;
+ char *buffer, *filename, *save_path, *cp;
+
+ if (path == 0 || strcmp(path, "") == 0) {
+ path = "."; /* just look in the current directory */
+ }
+
+ save_path = path = util_strsav(path);
+ quit = 0;
+ do {
+ cp = strchr(path, ':');
+ if (cp != 0) {
+ *cp = '\0';
+ } else {
+ quit = 1;
+ }
+
+ /* cons up the filename out of the path and file name */
+ if (strcmp(path, ".") == 0) {
+ buffer = util_strsav(file);
+ } else {
+ buffer = ALLOC(char, strlen(path) + strlen(file) + 4);
+ (void) sprintf(buffer, "%s/%s", path, file);
+ }
+ filename = util_tilde_expand(buffer);
+ FREE(buffer);
+
+ /* see if we can access it */
+ if (check_file(filename, mode)) {
+ FREE(save_path);
+ return filename;
+ }
+ FREE(filename);
+ path = ++cp;
+ } while (! quit);
+
+ FREE(save_path);
+ return 0;
+}
diff --git a/src/misc/util/safe_mem.c b/src/misc/util/safe_mem.c
new file mode 100644
index 00000000..5a8a5de8
--- /dev/null
+++ b/src/misc/util/safe_mem.c
@@ -0,0 +1,104 @@
+/*
+ * Revision Control Information
+ *
+ * /projects/hsis/CVS/utilities/util/safe_mem.c,v
+ * rajeev
+ * 1.3
+ * 1995/08/08 22:41:29
+ *
+ */
+/* LINTLIBRARY */
+
+#include "util.h"
+
+/*
+ * These are interface routines to be placed between a program and the
+ * system memory allocator.
+ *
+ * It forces well-defined semantics for several 'borderline' cases:
+ *
+ * malloc() of a 0 size object is guaranteed to return something
+ * which is not 0, and can safely be freed (but not dereferenced)
+ * free() accepts (silently) an 0 pointer
+ * realloc of a 0 pointer is allowed, and is equiv. to malloc()
+ * For the IBM/PC it forces no object > 64K; note that the size argument
+ * to malloc/realloc is a 'long' to catch this condition
+ *
+ * The function pointer MMoutOfMemory() contains a vector to handle a
+ * 'out-of-memory' error (which, by default, points at a simple wrap-up
+ * and exit routine).
+ */
+
+extern char *MMalloc();
+extern void MMout_of_memory();
+extern char *MMrealloc();
+
+
+void (*MMoutOfMemory)() = MMout_of_memory;
+
+
+/* MMout_of_memory -- out of memory for lazy people, flush and exit */
+void
+MMout_of_memory(size)
+long size;
+{
+ (void) fflush(stdout);
+ (void) fprintf(stderr, "\nout of memory allocating %u bytes\n",
+ (unsigned) size);
+ assert( 0 );
+ exit(1);
+}
+
+
+char *
+MMalloc(size)
+long size;
+{
+ char *p;
+
+#ifdef IBMPC
+ if (size > 65000L) {
+ if (MMoutOfMemory != (void (*)()) 0 ) (*MMoutOfMemory)(size);
+ return NIL(char);
+ }
+#endif
+ if (size == 0) size = sizeof(long);
+ if ((p = (char *) malloc((unsigned) size)) == NIL(char)) {
+ if (MMoutOfMemory != (void (*)()) 0 ) (*MMoutOfMemory)(size);
+ return NIL(char);
+ }
+ return p;
+}
+
+
+char *
+MMrealloc(obj, size)
+char *obj;
+long size;
+{
+ char *p;
+
+#ifdef IBMPC
+ if (size > 65000L) {
+ if (MMoutOfMemory != (void (*)()) 0 ) (*MMoutOfMemory)(size);
+ return NIL(char);
+ }
+#endif
+ if (obj == NIL(char)) return MMalloc(size);
+ if (size <= 0) size = sizeof(long);
+ if ((p = (char *) realloc(obj, (unsigned) size)) == NIL(char)) {
+ if (MMoutOfMemory != (void (*)()) 0 ) (*MMoutOfMemory)(size);
+ return NIL(char);
+ }
+ return p;
+}
+
+
+void
+MMfree(obj)
+char *obj;
+{
+ if (obj != 0) {
+ free(obj);
+ }
+}
diff --git a/src/misc/util/stdlib_hack.h b/src/misc/util/stdlib_hack.h
new file mode 100644
index 00000000..2ddf73d1
--- /dev/null
+++ b/src/misc/util/stdlib_hack.h
@@ -0,0 +1,4 @@
+
+#include <stdlib.h>
+
+
diff --git a/src/misc/util/strsav.c b/src/misc/util/strsav.c
new file mode 100644
index 00000000..8da1f0c9
--- /dev/null
+++ b/src/misc/util/strsav.c
@@ -0,0 +1,157 @@
+/*
+ * Revision Control Information
+ *
+ * /projects/hsis/CVS/utilities/util/strsav.c,v
+ * shiple
+ * 1.4
+ * 1995/08/30 17:37:58
+ *
+ */
+/* LINTLIBRARY */
+
+#include <stdio.h>
+#include "util.h"
+
+
+/*
+ * util_strsav -- save a copy of a string
+ */
+char *
+util_strsav(s)
+char *s;
+{
+ if(s == NIL(char)) { /* added 7/95, for robustness */
+ return s;
+ }
+ else {
+ return strcpy(ALLOC(char, strlen(s)+1), s);
+ }
+}
+
+/*
+ * util_inttostr -- converts an integer into a string
+ */
+char *
+util_inttostr(i)
+ int i;
+{
+ unsigned int mod, len;
+ char *s;
+
+ if (i == 0)
+ len = 1;
+ else {
+ if (i < 0) {
+ len = 1;
+ mod = -i;
+ }
+ else {
+ len = 0;
+ mod = i;
+ }
+ len += (unsigned)floor(log10(mod)) + 1;
+ }
+
+ s = ALLOC(char, len + 1);
+ sprintf(s, "%d", i);
+
+ return s;
+}
+
+/*
+ * util_strcat3 -- Creates a new string which is the concatenation of 3
+ * strings. It is the responsibility of the caller to free this string
+ * using FREE.
+ */
+char *
+util_strcat3(
+ char * str1,
+ char * str2,
+ char * str3)
+{
+ char *str = ALLOC(char, strlen(str1) + strlen(str2) + strlen(str3) + 1);
+
+ (void) strcpy(str, str1);
+ (void) strcat(str, str2);
+ (void) strcat(str, str3);
+
+ return (str);
+}
+
+/*
+ * util_strcat4 -- Creates a new string which is the concatenation of 4
+ * strings. It is the responsibility of the caller to free this string
+ * using FREE.
+ */
+char *
+util_strcat4(
+ char * str1,
+ char * str2,
+ char * str3,
+ char * str4)
+{
+ char *str = ALLOC(char, strlen(str1) + strlen(str2) + strlen(str3) +
+ strlen(str4) + 1);
+
+ (void) strcpy(str, str1);
+ (void) strcat(str, str2);
+ (void) strcat(str, str3);
+ (void) strcat(str, str4);
+
+ return (str);
+}
+
+
+#if !HAVE_STRSTR
+/**Function********************************************************************
+
+ Synopsis [required]
+
+ Description [optional]
+
+ SideEffects [required]
+
+ SeeAlso [optional]
+
+******************************************************************************/
+char *
+strstr(
+ const char * s,
+ const char * pat)
+{
+ int len;
+
+ len = strlen(pat);
+ for (; *s != '\0'; ++s)
+ if (*s == *pat && memcmp(s, pat, len) == 0) {
+ return (char *)s; /* UGH */
+ }
+ return NULL;
+}
+#endif /* !HAVE_STRSTR */
+
+#if !HAVE_STRCHR
+/**Function********************************************************************
+
+ Synopsis [required]
+
+ Description [optional]
+
+ SideEffects [required]
+
+ SeeAlso [optional]
+
+******************************************************************************/
+char *
+strchr(const char * s,
+ int c)
+{
+ for (; *s != '\0'; s++) {
+ if (*s == c) {
+ return (char *)s;
+ }
+ }
+ return NULL;
+
+}
+#endif /* !HAVE_STRCHR */
diff --git a/src/misc/util/texpand.c b/src/misc/util/texpand.c
new file mode 100644
index 00000000..37f71cbd
--- /dev/null
+++ b/src/misc/util/texpand.c
@@ -0,0 +1,66 @@
+/*
+ * Revision Control Information
+ *
+ * /projects/hsis/CVS/utilities/util/texpand.c,v
+ * rajeev
+ * 1.3
+ * 1995/08/08 22:41:36
+ *
+ */
+
+#include "util.h"
+
+#if HAVE_PWD_H
+# include <pwd.h>
+#endif
+
+
+char *
+util_tilde_expand(fname)
+char *fname;
+{
+#if HAVE_PWD_H
+ struct passwd *userRecord;
+ char username[256], *filename, *dir;
+ register int i, j;
+
+ filename = ALLOC(char, strlen(fname) + 256);
+
+ /* Clear the return string */
+ i = 0;
+ filename[0] = '\0';
+
+ /* Tilde? */
+ if (fname[0] == '~') {
+ j = 0;
+ i = 1;
+ while ((fname[i] != '\0') && (fname[i] != '/')) {
+ username[j++] = fname[i++];
+ }
+ username[j] = '\0';
+ dir = (char *)0;
+ if (username[0] == '\0') {
+ /* ~/ resolves to home directory of current user */
+ userRecord = getpwuid(getuid());
+ if (userRecord) dir = userRecord->pw_dir;
+ } else {
+ /* Special check for ~octtools */
+ if (!strcmp(username,"octtools"))
+ dir = getenv("OCTTOOLS");
+ /* ~user/ resolves to home directory of 'user' */
+ if (!dir) {
+ userRecord = getpwnam(username);
+ if (userRecord) dir = userRecord->pw_dir;
+ }
+ }
+ if (dir) (void) strcat(filename, dir);
+ else i = 0; /* leave fname as-is */
+ } /* if tilde */
+
+ /* Concantenate remaining portion of file name */
+ (void) strcat(filename, fname + i);
+ return filename;
+#else
+ return util_strsav(fname);
+#endif
+}
diff --git a/src/misc/util/util.h b/src/misc/util/util.h
new file mode 100644
index 00000000..0b147347
--- /dev/null
+++ b/src/misc/util/util.h
@@ -0,0 +1,331 @@
+/**CHeaderFile*****************************************************************
+
+ FileName [ util.h ]
+
+ PackageName [ util ]
+
+ Synopsis [ Very low-level utilities ]
+
+ Description [ Includes file access, pipes, forks, time, and temporary file
+ access. ]
+
+ Author [ Stephen Edwards <sedwards@eecs.berkeley.edu> and many others]
+
+ Copyright [Copyright (c) 1994-1996 The Regents of the Univ. of California.
+ All rights reserved.
+
+ Permission is hereby granted, without written agreement and without license
+ or royalty fees, to use, copy, modify, and distribute this software and its
+ documentation for any purpose, provided that the above copyright notice and
+ the following two paragraphs appear in all copies of this software.
+
+ IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
+ "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE
+ MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.]
+
+ Revision [$Id: util.h,v 1.11 1998/05/04 02:05:08 hsv Exp $]
+
+******************************************************************************/
+
+#ifndef _UTIL
+#define _UTIL
+
+////////////////////////////////////////////
+#include "leaks.h"
+////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+//////////////// added by alanmi, November 22, 2001 ////////////////
+//#include <ctype.h>
+#include <time.h>
+#include <signal.h>
+
+#ifndef SIGALRM
+#define SIGALRM SIGINT
+#endif
+
+#ifndef SIGSTOP
+#define SIGSTOP SIGINT
+#endif
+
+#ifndef SIGXCPU
+#define SIGXCPU SIGINT
+#endif
+
+#ifndef SIGUSR1
+#define SIGUSR1 SIGINT
+#endif
+
+#ifndef SIGKILL
+#define SIGKILL SIGINT
+#endif
+
+#ifndef HUGE
+#define HUGE HUGE_VAL
+#endif
+
+#if defined(__STDC__)
+#define SIGNAL_FN void
+#endif
+
+#define alarm(n) ((void)0)
+#define kill(a,b) ((void)0)
+
+#define random rand
+#define srandom srand
+////////////////////////////////////////////////////////////////////
+
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#if HAVE_VARARGS_H
+///////////////////////////////////////
+#undef __STDC__
+# include <varargs.h>
+#define __STDC__ 1
+////////////////// alanmi Feb 03, 2001
+#endif
+
+#ifndef STDC_HEADERS
+#define STDC_HEADERS 1
+#endif
+
+#ifndef HAVE_STRCHR
+#define HAVE_STRCHR 1
+#endif
+
+#ifndef HAVE_GETENV
+#define HAVE_GETENV 1
+#endif
+
+#if STDC_HEADERS
+//# include <stdlib.h>
+# include <string.h>
+#else
+# ifdef HAVE_STRCHR
+char * strchr();
+int strcmp();
+# else
+# define strchr index
+# endif
+# ifdef HAVE_GETENV
+char * getenv();
+# endif
+#endif /* STDC_HEADERS */
+
+#if HAVE_ERRNO_H
+# include <errno.h>
+#endif
+
+/*
+ * Ensure we have reasonable assert() and fail() functions
+ */
+
+#ifndef HAVE_ASSERT_H
+#define HAVE_ASSERT_H 1
+#endif
+
+#if HAVE_ASSERT_H
+# include <assert.h>
+#else
+# ifdef NDEBUG
+# define assert(ex) ;
+# else
+# define assert(ex) {\
+ if (! (ex)) {\
+ (void) fprintf(stderr,\
+ "Assertion failed: file %s, line %d\n\"%s\"\n",\
+ __FILE__, __LINE__, "ex");\
+ (void) fflush(stdout);\
+ abort();\
+ }\
+}
+# endif
+#endif
+
+#define fail(why) {\
+ (void) fprintf(stderr, "Fatal error: file %s, line %d\n%s\n",\
+ __FILE__, __LINE__, why);\
+ (void) fflush(stdout);\
+ abort();\
+}
+
+/*
+ * Support for ANSI function prototypes in non-ANSI compilers
+ *
+ * Usage:
+ * extern int foo ARGS((char *, double))
+ */
+
+#ifndef ARGS
+# ifdef __STDC__
+# define ARGS(args) args
+# else
+# define ARGS(args) ()
+# endif
+#endif
+
+#ifndef NULLARGS
+# ifdef __STDC__
+# define NULLARGS (void)
+# else
+# define NULLARGS ()
+# endif
+#endif
+
+/*
+ * A little support for C++ compilers
+ */
+
+#ifdef __cplusplus
+# define EXTERN extern "C"
+#else
+# define EXTERN extern
+#endif
+
+/*
+ * Support to define unused varibles
+ */
+#if (__GNUC__ >2 || __GNUC_MINOR__ >=7) && !defined(UNUSED)
+#define UNUSED __attribute__ ((unused))
+#else
+#define UNUSED
+#endif
+
+/*
+ * A neater way to define zero pointers
+ *
+ * Usage:
+ * int * fred;
+ * fred = NIL(int);
+ */
+
+#define NIL(type) ((type *) 0)
+
+/*
+ * Left over from SIS and Octtools:
+ */
+
+//#define USE_MM
+// uncommented this line,
+// because to detect memory leaks, we need to work with malloc(), etc directly
+#define USE_MM
+
+
+
+#ifdef USE_MM
+/*
+ * assumes the memory manager is libmm.a (a deprecated (?) Octtools library)
+ * - allows malloc(0) or realloc(obj, 0)
+ * - catches out of memory (and calls MMout_of_memory())
+ * - catch free(0) and realloc(0, size) in the macros
+ */
+# define ALLOC(type, num) \
+ ((type *) malloc(sizeof(type) * (num)))
+# define REALLOC(type, obj, num) \
+ (obj) ? ((type *) realloc((char *) obj, sizeof(type) * (num))) : \
+ ((type *) malloc(sizeof(type) * (num)))
+# define FREE(obj) \
+ ((obj) ? (free((char *) (obj)), (obj) = 0) : 0)
+#else
+/*
+ * enforce strict semantics on the memory allocator
+ */
+# define ALLOC(type, num) \
+ ((type *) MMalloc((long) sizeof(type) * (long) (num)))
+# define REALLOC(type, obj, num) \
+ ((type *) MMrealloc((char *) (obj), (long) sizeof(type) * (long) (num)))
+# define FREE(obj) \
+ ((obj) ? (free((void *) (obj)), (obj) = 0) : 0)
+EXTERN void MMout_of_memory ARGS((long));
+EXTERN char *MMalloc ARGS((long));
+EXTERN char *MMrealloc ARGS((char *, long));
+EXTERN void MMfree ARGS((char *));
+#endif
+
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+#ifndef ABS
+# define ABS(a) ((a) < 0 ? -(a) : (a))
+#endif
+
+#ifndef MAX
+# define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef MIN
+# define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#define ptime() util_cpu_time()
+#define print_time(t) util_print_time(t)
+
+#ifndef HUGE_VAL
+# ifndef HUGE
+# define HUGE 8.9884656743115790e+307
+# endif
+# define HUGE_VAL HUGE
+#endif
+
+#ifndef MAXINT
+# define MAXINT (1 << 30)
+#endif
+
+EXTERN void util_print_cpu_stats ARGS((FILE *));
+EXTERN long util_cpu_time ARGS((void));
+EXTERN void util_getopt_reset ARGS((void));
+EXTERN int util_getopt ARGS((int, char **, char *));
+EXTERN char *util_path_search ARGS((char *));
+EXTERN char *util_file_search ARGS((char *, char *, char *));
+EXTERN char *util_print_time ARGS((long));
+EXTERN int util_save_image ARGS((char *, char *));
+EXTERN char *util_strsav ARGS((char *));
+EXTERN char *util_inttostr ARGS((int));
+EXTERN char *util_strcat3 ARGS((char *, char *, char *));
+EXTERN char *util_strcat4 ARGS((char *, char *, char *, char *));
+EXTERN int util_do_nothing ARGS((void));
+EXTERN char *util_tilde_expand ARGS((char *));
+EXTERN char *util_tempnam ARGS((char *, char *));
+EXTERN FILE *util_tmpfile ARGS((void));
+EXTERN void util_srandom ARGS((long));
+EXTERN long util_random ARGS(());
+EXTERN int getSoftDataLimit ARGS(());
+
+/*
+ * Global variables for util_getopt()
+ */
+
+extern int util_optind;
+extern char *util_optarg;
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Function prototypes */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticEnd***************************************************************/
+
+#endif /* _UTIL */
diff --git a/src/misc/vec/module.make b/src/misc/vec/module.make
new file mode 100644
index 00000000..d6d908e7
--- /dev/null
+++ b/src/misc/vec/module.make
@@ -0,0 +1 @@
+SRC +=
diff --git a/src/misc/vec/vec.h b/src/misc/vec/vec.h
new file mode 100644
index 00000000..34b0bfa2
--- /dev/null
+++ b/src/misc/vec/vec.h
@@ -0,0 +1,58 @@
+/**CFile****************************************************************
+
+ FileName [vec.h]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Resizable arrays.]
+
+ Synopsis [External declarations.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: vec.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __VEC_H__
+#define __VEC_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+#ifdef _WIN32
+#define inline __inline // compatible with MS VS 6.0
+#endif
+
+#include "vecFan.h"
+#include "vecInt.h"
+#include "vecPtr.h"
+#include "vecStr.h"
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// BASIC TYPES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/src/misc/vec/vecFan.h b/src/misc/vec/vecFan.h
new file mode 100644
index 00000000..7bfded4a
--- /dev/null
+++ b/src/misc/vec/vecFan.h
@@ -0,0 +1,361 @@
+/**CFile****************************************************************
+
+ FileName [vecFan.h]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Resizable arrays.]
+
+ Synopsis [Resizable arrays of integers (fanins/fanouts) with memory management.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: vecFan.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __VEC_FAN_H__
+#define __VEC_FAN_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include "extra.h"
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// BASIC TYPES ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct Abc_Fan_t_ Abc_Fan_t;
+struct Abc_Fan_t_ // 1 word
+{
+ unsigned iFan : 21; // the ID of the object
+ unsigned nLats : 3; // the number of latches (up to 7)
+ unsigned Inits : 7; // the initial values of the latches
+ unsigned fCompl : 1; // the complemented attribute
+};
+
+typedef struct Vec_Fan_t_ Vec_Fan_t;
+struct Vec_Fan_t_
+{
+ int nSize;
+ int nCap;
+ Abc_Fan_t * pArray;
+};
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Converts an integer into the simple fanin structure.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Abc_Fan_t Vec_Int2Fan( int iFan )
+{
+ return *((Abc_Fan_t *)&iFan);
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Abc_Fan_t * Vec_FanArray( Vec_Fan_t * p )
+{
+ return p->pArray;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Vec_FanSize( Vec_Fan_t * p )
+{
+ return p->nSize;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Abc_Fan_t Vec_FanEntry( Vec_Fan_t * p, int i )
+{
+ assert( i >= 0 && i < p->nSize );
+ return p->pArray[i];
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_FanWriteEntry( Vec_Fan_t * p, int i, Abc_Fan_t Entry )
+{
+ assert( i >= 0 && i < p->nSize );
+ p->pArray[i] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Abc_Fan_t Vec_FanEntryLast( Vec_Fan_t * p )
+{
+ return p->pArray[p->nSize-1];
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_FanShrink( Vec_Fan_t * p, int nSizeNew )
+{
+ assert( p->nSize >= nSizeNew );
+ p->nSize = nSizeNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_FanClear( Vec_Fan_t * p )
+{
+ p->nSize = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_FanPush( Extra_MmStep_t * pMemMan, Vec_Fan_t * p, Abc_Fan_t Entry )
+{
+ if ( p->nSize == p->nCap )
+ {
+ Abc_Fan_t * pArray;
+ int i;
+
+ if ( p->nSize == 0 )
+ p->nCap = 1;
+ pArray = (Abc_Fan_t *)Extra_MmStepEntryFetch( pMemMan, p->nCap * 8 );
+// pArray = ALLOC( int, p->nCap * 2 );
+ if ( p->pArray )
+ {
+ for ( i = 0; i < p->nSize; i++ )
+ pArray[i] = p->pArray[i];
+ Extra_MmStepEntryRecycle( pMemMan, (char *)p->pArray, p->nCap * 4 );
+// free( p->pArray );
+ }
+ p->nCap *= 2;
+ p->pArray = pArray;
+ }
+ p->pArray[p->nSize++] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the last entry and removes it from the list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Abc_Fan_t Vec_FanPop( Vec_Fan_t * p )
+{
+ assert( p->nSize > 0 );
+ return p->pArray[--p->nSize];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Find entry.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Vec_FanFindEntry( Vec_Fan_t * p, unsigned iFan )
+{
+ int i;
+ for ( i = 0; i < p->nSize; i++ )
+ if ( p->pArray[i].iFan == iFan )
+ return i;
+ return -1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Deletes entry.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Vec_FanDeleteEntry( Vec_Fan_t * p, unsigned iFan )
+{
+ int i, k, fFound = 0;
+ for ( i = k = 0; i < p->nSize; i++ )
+ {
+ if ( p->pArray[i].iFan == iFan )
+ fFound = 1;
+ else
+ p->pArray[k++] = p->pArray[i];
+ }
+ p->nSize = k;
+ return fFound;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Comparison procedure for two integers.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Vec_FanSortCompare1( int * pp1, int * pp2 )
+{
+ // for some reason commenting out lines (as shown) led to crashing of the release version
+ if ( *pp1 < *pp2 )
+ return -1;
+ if ( *pp1 > *pp2 ) //
+ return 1;
+ return 0; //
+}
+
+/**Function*************************************************************
+
+ Synopsis [Comparison procedure for two integers.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Vec_FanSortCompare2( int * pp1, int * pp2 )
+{
+ // for some reason commenting out lines (as shown) led to crashing of the release version
+ if ( *pp1 > *pp2 )
+ return -1;
+ if ( *pp1 < *pp2 ) //
+ return 1;
+ return 0; //
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sorting the entries by their integer value.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_FanSort( Vec_Fan_t * p, int fReverse )
+{
+ if ( fReverse )
+ qsort( (void *)p->pArray, p->nSize, sizeof(int),
+ (int (*)(const void *, const void *)) Vec_FanSortCompare2 );
+ else
+ qsort( (void *)p->pArray, p->nSize, sizeof(int),
+ (int (*)(const void *, const void *)) Vec_FanSortCompare1 );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/src/misc/vec/vecInt.h b/src/misc/vec/vecInt.h
new file mode 100644
index 00000000..8cca2b29
--- /dev/null
+++ b/src/misc/vec/vecInt.h
@@ -0,0 +1,496 @@
+/**CFile****************************************************************
+
+ FileName [vecInt.h]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Resizable arrays.]
+
+ Synopsis [Resizable arrays of integers.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: vecInt.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __VEC_INT_H__
+#define __VEC_INT_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include "extra.h"
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// BASIC TYPES ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct Vec_Int_t_ Vec_Int_t;
+struct Vec_Int_t_
+{
+ int nSize;
+ int nCap;
+ int * pArray;
+};
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Allocates a vector with the given capacity.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Vec_Int_t * Vec_IntAlloc( int nCap )
+{
+ Vec_Int_t * p;
+ p = ALLOC( Vec_Int_t, 1 );
+ if ( nCap > 0 && nCap < 16 )
+ nCap = 16;
+ p->nSize = 0;
+ p->nCap = nCap;
+ p->pArray = p->nCap? ALLOC( int, p->nCap ) : NULL;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates the vector from an integer array of the given size.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Vec_Int_t * Vec_IntAllocArray( int * pArray, int nSize )
+{
+ Vec_Int_t * p;
+ p = ALLOC( Vec_Int_t, 1 );
+ p->nSize = nSize;
+ p->nCap = nSize;
+ p->pArray = pArray;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates the vector from an integer array of the given size.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Vec_Int_t * Vec_IntAllocArrayCopy( int * pArray, int nSize )
+{
+ Vec_Int_t * p;
+ p = ALLOC( Vec_Int_t, 1 );
+ p->nSize = nSize;
+ p->nCap = nSize;
+ p->pArray = ALLOC( int, nSize );
+ memcpy( p->pArray, pArray, sizeof(int) * nSize );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Duplicates the integer array.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Vec_Int_t * Vec_IntDup( Vec_Int_t * pVec )
+{
+ Vec_Int_t * p;
+ p = ALLOC( Vec_Int_t, 1 );
+ p->nSize = pVec->nSize;
+ p->nCap = pVec->nCap;
+ p->pArray = p->nCap? ALLOC( int, p->nCap ) : NULL;
+ memcpy( p->pArray, pVec->pArray, sizeof(int) * pVec->nSize );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Transfers the array into another vector.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Vec_Int_t * Vec_IntDupArray( Vec_Int_t * pVec )
+{
+ Vec_Int_t * p;
+ p = ALLOC( Vec_Int_t, 1 );
+ p->nSize = pVec->nSize;
+ p->nCap = pVec->nCap;
+ p->pArray = pVec->pArray;
+ pVec->nSize = 0;
+ pVec->nCap = 0;
+ pVec->pArray = NULL;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_IntFree( Vec_Int_t * p )
+{
+ FREE( p->pArray );
+ FREE( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int * Vec_IntReleaseArray( Vec_Int_t * p )
+{
+ int * pArray = p->pArray;
+ p->nCap = 0;
+ p->nSize = 0;
+ p->pArray = NULL;
+ return pArray;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int * Vec_IntArray( Vec_Int_t * p )
+{
+ return p->pArray;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Vec_IntSize( Vec_Int_t * p )
+{
+ return p->nSize;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Vec_IntEntry( Vec_Int_t * p, int i )
+{
+ assert( i >= 0 && i < p->nSize );
+ return p->pArray[i];
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_IntWriteEntry( Vec_Int_t * p, int i, int Entry )
+{
+ assert( i >= 0 && i < p->nSize );
+ p->pArray[i] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Vec_IntEntryLast( Vec_Int_t * p )
+{
+ return p->pArray[p->nSize-1];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Resizes the vector to the given capacity.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_IntGrow( Vec_Int_t * p, int nCapMin )
+{
+ if ( p->nCap >= nCapMin )
+ return;
+ p->pArray = REALLOC( int, p->pArray, nCapMin );
+ p->nCap = nCapMin;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Fills the vector with given number of entries.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_IntFill( Vec_Int_t * p, int nSize, int Entry )
+{
+ int i;
+ Vec_IntGrow( p, nSize );
+ p->nSize = nSize;
+ for ( i = 0; i < p->nSize; i++ )
+ p->pArray[i] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_IntShrink( Vec_Int_t * p, int nSizeNew )
+{
+ assert( p->nSize >= nSizeNew );
+ p->nSize = nSizeNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_IntClear( Vec_Int_t * p )
+{
+ p->nSize = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_IntPush( Vec_Int_t * p, int Entry )
+{
+ if ( p->nSize == p->nCap )
+ {
+ if ( p->nCap < 16 )
+ Vec_IntGrow( p, 16 );
+ else
+ Vec_IntGrow( p, 2 * p->nCap );
+ }
+ p->pArray[p->nSize++] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_IntPushOrder( Vec_Int_t * p, int Entry )
+{
+ int i;
+ if ( p->nSize == p->nCap )
+ {
+ if ( p->nCap < 16 )
+ Vec_IntGrow( p, 16 );
+ else
+ Vec_IntGrow( p, 2 * p->nCap );
+ }
+ p->nSize++;
+ for ( i = p->nSize-2; i >= 0; i-- )
+ if ( p->pArray[i] > Entry )
+ p->pArray[i+1] = p->pArray[i];
+ else
+ break;
+ p->pArray[i+1] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the last entry and removes it from the list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Vec_IntPop( Vec_Int_t * p )
+{
+ assert( p->nSize > 0 );
+ return p->pArray[--p->nSize];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Comparison procedure for two integers.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Vec_IntSortCompare1( int * pp1, int * pp2 )
+{
+ // for some reason commenting out lines (as shown) led to crashing of the release version
+ if ( *pp1 < *pp2 )
+ return -1;
+ if ( *pp1 > *pp2 ) //
+ return 1;
+ return 0; //
+}
+
+/**Function*************************************************************
+
+ Synopsis [Comparison procedure for two integers.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Vec_IntSortCompare2( int * pp1, int * pp2 )
+{
+ // for some reason commenting out lines (as shown) led to crashing of the release version
+ if ( *pp1 > *pp2 )
+ return -1;
+ if ( *pp1 < *pp2 ) //
+ return 1;
+ return 0; //
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sorting the entries by their integer value.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_IntSort( Vec_Int_t * p, int fReverse )
+{
+ if ( fReverse )
+ qsort( (void *)p->pArray, p->nSize, sizeof(int),
+ (int (*)(const void *, const void *)) Vec_IntSortCompare2 );
+ else
+ qsort( (void *)p->pArray, p->nSize, sizeof(int),
+ (int (*)(const void *, const void *)) Vec_IntSortCompare1 );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/src/misc/vec/vecPtr.h b/src/misc/vec/vecPtr.h
new file mode 100644
index 00000000..0ba1bdc5
--- /dev/null
+++ b/src/misc/vec/vecPtr.h
@@ -0,0 +1,461 @@
+/**CFile****************************************************************
+
+ FileName [vecPtr.h]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Resizable arrays.]
+
+ Synopsis [Resizable arrays of generic pointers.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: vecPtr.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __VEC_PTR_H__
+#define __VEC_PTR_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include "extra.h"
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// BASIC TYPES ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct Vec_Ptr_t_ Vec_Ptr_t;
+struct Vec_Ptr_t_
+{
+ int nSize;
+ int nCap;
+ void ** pArray;
+};
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Allocates a vector with the given capacity.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Vec_Ptr_t * Vec_PtrAlloc( int nCap )
+{
+ Vec_Ptr_t * p;
+ p = ALLOC( Vec_Ptr_t, 1 );
+ if ( nCap > 0 && nCap < 8 )
+ nCap = 8;
+ p->nSize = 0;
+ p->nCap = nCap;
+ p->pArray = p->nCap? ALLOC( void *, p->nCap ) : NULL;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates the vector from an integer array of the given size.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Vec_Ptr_t * Vec_PtrAllocArray( void ** pArray, int nSize )
+{
+ Vec_Ptr_t * p;
+ p = ALLOC( Vec_Ptr_t, 1 );
+ p->nSize = nSize;
+ p->nCap = nSize;
+ p->pArray = pArray;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates the vector from an integer array of the given size.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Vec_Ptr_t * Vec_PtrAllocArrayCopy( void ** pArray, int nSize )
+{
+ Vec_Ptr_t * p;
+ p = ALLOC( Vec_Ptr_t, 1 );
+ p->nSize = nSize;
+ p->nCap = nSize;
+ p->pArray = ALLOC( void *, nSize );
+ memcpy( p->pArray, pArray, sizeof(void *) * nSize );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Duplicates the integer array.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Vec_Ptr_t * Vec_PtrDup( Vec_Ptr_t * pVec )
+{
+ Vec_Ptr_t * p;
+ p = ALLOC( Vec_Ptr_t, 1 );
+ p->nSize = pVec->nSize;
+ p->nCap = pVec->nCap;
+ p->pArray = p->nCap? ALLOC( void *, p->nCap ) : NULL;
+ memcpy( p->pArray, pVec->pArray, sizeof(void *) * pVec->nSize );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Transfers the array into another vector.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Vec_Ptr_t * Vec_PtrDupArray( Vec_Ptr_t * pVec )
+{
+ Vec_Ptr_t * p;
+ p = ALLOC( Vec_Ptr_t, 1 );
+ p->nSize = pVec->nSize;
+ p->nCap = pVec->nCap;
+ p->pArray = pVec->pArray;
+ pVec->nSize = 0;
+ pVec->nCap = 0;
+ pVec->pArray = NULL;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_PtrFree( Vec_Ptr_t * p )
+{
+ FREE( p->pArray );
+ FREE( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void ** Vec_PtrReleaseArray( Vec_Ptr_t * p )
+{
+ void ** pArray = p->pArray;
+ p->nCap = 0;
+ p->nSize = 0;
+ p->pArray = NULL;
+ return pArray;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void ** Vec_PtrArray( Vec_Ptr_t * p )
+{
+ return p->pArray;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Vec_PtrSize( Vec_Ptr_t * p )
+{
+ return p->nSize;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void * Vec_PtrEntry( Vec_Ptr_t * p, int i )
+{
+ assert( i >= 0 && i < p->nSize );
+ return p->pArray[i];
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_PtrWriteEntry( Vec_Ptr_t * p, int i, void * Entry )
+{
+ assert( i >= 0 && i < p->nSize );
+ p->pArray[i] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void * Vec_PtrEntryLast( Vec_Ptr_t * p )
+{
+ return p->pArray[p->nSize-1];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Resizes the vector to the given capacity.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_PtrGrow( Vec_Ptr_t * p, int nCapMin )
+{
+ if ( p->nCap >= nCapMin )
+ return;
+ p->pArray = REALLOC( void *, p->pArray, nCapMin );
+ p->nCap = nCapMin;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Fills the vector with given number of entries.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_PtrFill( Vec_Ptr_t * p, int nSize, void * Entry )
+{
+ int i;
+ Vec_PtrGrow( p, nSize );
+ p->nSize = nSize;
+ for ( i = 0; i < p->nSize; i++ )
+ p->pArray[i] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_PtrShrink( Vec_Ptr_t * p, int nSizeNew )
+{
+ assert( p->nSize >= nSizeNew );
+ p->nSize = nSizeNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_PtrClear( Vec_Ptr_t * p )
+{
+ p->nSize = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_PtrPush( Vec_Ptr_t * p, void * Entry )
+{
+ if ( p->nSize == p->nCap )
+ {
+ if ( p->nCap < 16 )
+ Vec_PtrGrow( p, 16 );
+ else
+ Vec_PtrGrow( p, 2 * p->nCap );
+ }
+ p->pArray[p->nSize++] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Vec_PtrPushUnique( Vec_Ptr_t * p, void * Entry )
+{
+ int i;
+ for ( i = 0; i < p->nSize; i++ )
+ if ( p->pArray[i] == Entry )
+ return 1;
+ Vec_PtrPush( p, Entry );
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the last entry and removes it from the list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void * Vec_PtrPop( Vec_Ptr_t * p )
+{
+ assert( p->nSize > 0 );
+ return p->pArray[--p->nSize];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Moves the first nItems to the end.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_PtrReorder( Vec_Ptr_t * p, int nItems )
+{
+ assert( nItems < p->nSize );
+ Vec_PtrGrow( p, nItems + p->nSize );
+ memmove( (char **)p->pArray + p->nSize, p->pArray, nItems * sizeof(void*) );
+ memmove( p->pArray, (char **)p->pArray + nItems, p->nSize * sizeof(void*) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sorting the entries by their integer value.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_PtrSort( Vec_Ptr_t * p, int (*Vec_PtrSortCompare)() )
+{
+ qsort( (void *)p->pArray, p->nSize, sizeof(void *),
+ (int (*)(const void *, const void *)) Vec_PtrSortCompare );
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/src/misc/vec/vecStr.h b/src/misc/vec/vecStr.h
new file mode 100644
index 00000000..367304d4
--- /dev/null
+++ b/src/misc/vec/vecStr.h
@@ -0,0 +1,466 @@
+/**CFile****************************************************************
+
+ FileName [vecStr.h]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Resizable arrays.]
+
+ Synopsis [Resizable arrays of characters.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: vecStr.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __VEC_STR_H__
+#define __VEC_STR_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include "extra.h"
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// BASIC TYPES ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct Vec_Str_t_ Vec_Str_t;
+struct Vec_Str_t_
+{
+ int nSize;
+ int nCap;
+ char * pArray;
+};
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Allocates a vector with the given capacity.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Vec_Str_t * Vec_StrAlloc( int nCap )
+{
+ Vec_Str_t * p;
+ p = ALLOC( Vec_Str_t, 1 );
+ if ( nCap > 0 && nCap < 16 )
+ nCap = 16;
+ p->nSize = 0;
+ p->nCap = nCap;
+ p->pArray = p->nCap? ALLOC( char, p->nCap ) : NULL;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates the vector from an integer array of the given size.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Vec_Str_t * Vec_StrAllocArray( char * pArray, int nSize )
+{
+ Vec_Str_t * p;
+ p = ALLOC( Vec_Str_t, 1 );
+ p->nSize = nSize;
+ p->nCap = nSize;
+ p->pArray = pArray;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates the vector from an integer array of the given size.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Vec_Str_t * Vec_StrAllocArrayCopy( char * pArray, int nSize )
+{
+ Vec_Str_t * p;
+ p = ALLOC( Vec_Str_t, 1 );
+ p->nSize = nSize;
+ p->nCap = nSize;
+ p->pArray = ALLOC( char, nSize );
+ memcpy( p->pArray, pArray, sizeof(char) * nSize );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Duplicates the integer array.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Vec_Str_t * Vec_StrDup( Vec_Str_t * pVec )
+{
+ Vec_Str_t * p;
+ p = ALLOC( Vec_Str_t, 1 );
+ p->nSize = pVec->nSize;
+ p->nCap = pVec->nCap;
+ p->pArray = p->nCap? ALLOC( char, p->nCap ) : NULL;
+ memcpy( p->pArray, pVec->pArray, sizeof(char) * pVec->nSize );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Transfers the array into another vector.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Vec_Str_t * Vec_StrDupArray( Vec_Str_t * pVec )
+{
+ Vec_Str_t * p;
+ p = ALLOC( Vec_Str_t, 1 );
+ p->nSize = pVec->nSize;
+ p->nCap = pVec->nCap;
+ p->pArray = pVec->pArray;
+ pVec->nSize = 0;
+ pVec->nCap = 0;
+ pVec->pArray = NULL;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_StrFree( Vec_Str_t * p )
+{
+ FREE( p->pArray );
+ FREE( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline char * Vec_StrReleaseArray( Vec_Str_t * p )
+{
+ char * pArray = p->pArray;
+ p->nCap = 0;
+ p->nSize = 0;
+ p->pArray = NULL;
+ return pArray;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline char * Vec_StrArray( Vec_Str_t * p )
+{
+ return p->pArray;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Vec_StrSize( Vec_Str_t * p )
+{
+ return p->nSize;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline char Vec_StrEntry( Vec_Str_t * p, int i )
+{
+ assert( i >= 0 && i < p->nSize );
+ return p->pArray[i];
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_StrWriteEntry( Vec_Str_t * p, int i, char Entry )
+{
+ assert( i >= 0 && i < p->nSize );
+ p->pArray[i] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline char Vec_StrEntryLast( Vec_Str_t * p )
+{
+ return p->pArray[p->nSize-1];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Resizes the vector to the given capacity.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_StrGrow( Vec_Str_t * p, int nCapMin )
+{
+ if ( p->nCap >= nCapMin )
+ return;
+ p->pArray = REALLOC( char, p->pArray, nCapMin );
+ p->nCap = nCapMin;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Fills the vector with given number of entries.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_StrFill( Vec_Str_t * p, int nSize, char Entry )
+{
+ int i;
+ Vec_StrGrow( p, nSize );
+ p->nSize = nSize;
+ for ( i = 0; i < p->nSize; i++ )
+ p->pArray[i] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_StrShrink( Vec_Str_t * p, int nSizeNew )
+{
+ assert( p->nSize >= nSizeNew );
+ p->nSize = nSizeNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_StrClear( Vec_Str_t * p )
+{
+ p->nSize = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_StrPush( Vec_Str_t * p, char Entry )
+{
+ if ( p->nSize == p->nCap )
+ {
+ if ( p->nCap < 16 )
+ Vec_StrGrow( p, 16 );
+ else
+ Vec_StrGrow( p, 2 * p->nCap );
+ }
+ p->pArray[p->nSize++] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the last entry and removes it from the list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline char Vec_StrPop( Vec_Str_t * p )
+{
+ assert( p->nSize > 0 );
+ return p->pArray[--p->nSize];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Comparison procedure for two clauses.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Vec_StrSortCompare1( char * pp1, char * pp2 )
+{
+ // for some reason commenting out lines (as shown) led to crashing of the release version
+ if ( *pp1 < *pp2 )
+ return -1;
+ if ( *pp1 > *pp2 ) //
+ return 1;
+ return 0; //
+}
+
+/**Function*************************************************************
+
+ Synopsis [Comparison procedure for two clauses.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Vec_StrSortCompare2( char * pp1, char * pp2 )
+{
+ // for some reason commenting out lines (as shown) led to crashing of the release version
+ if ( *pp1 > *pp2 )
+ return -1;
+ if ( *pp1 < *pp2 ) //
+ return 1;
+ return 0; //
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sorting the entries by their integer value.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_StrSort( Vec_Str_t * p, int fReverse )
+{
+ if ( fReverse )
+ qsort( (void *)p->pArray, p->nSize, sizeof(int),
+ (int (*)(const void *, const void *)) Vec_StrSortCompare2 );
+ else
+ qsort( (void *)p->pArray, p->nSize, sizeof(int),
+ (int (*)(const void *, const void *)) Vec_StrSortCompare1 );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/src/opt/module.make b/src/opt/module.make
new file mode 100644
index 00000000..d6d908e7
--- /dev/null
+++ b/src/opt/module.make
@@ -0,0 +1 @@
+SRC +=
diff --git a/src/sat/asat/added.c b/src/sat/asat/added.c
new file mode 100644
index 00000000..d7f5b104
--- /dev/null
+++ b/src/sat/asat/added.c
@@ -0,0 +1,126 @@
+/**CFile****************************************************************
+
+ FileName [added.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [C-language MiniSat solver.]
+
+ Synopsis [Additional SAT solver procedures.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: added.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include <stdio.h>
+#include <assert.h>
+#include "solver.h"
+#include "extra.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+struct clause_t
+{
+ int size_learnt;
+ lit lits[0];
+};
+
+static inline int clause_size (clause* c) { return c->size_learnt >> 1; }
+static inline lit* clause_begin (clause* c) { return c->lits; }
+
+static inline int lit_var(lit l) { return l >> 1; }
+static inline int lit_sign(lit l) { return (l & 1); }
+
+static void Asat_ClauseWriteDimacs( FILE * pFile, clause * pC, bool fIncrement );
+
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Write the clauses in the solver into a file in DIMACS format.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Asat_SolverWriteDimacs( solver * p, char * pFileName )
+{
+ FILE * pFile;
+ void ** pClauses;
+ int nClauses, i;
+
+ // count the number of clauses
+ nClauses = p->clauses.size + p->learnts.size;
+ for ( i = 0; i < p->size; i++ )
+ if ( p->levels[i] == 0 && p->assigns[i] != l_Undef )
+ nClauses++;
+
+ // start the file
+ pFile = fopen( pFileName, "wb" );
+ fprintf( pFile, "c CNF generated by ABC on %s\n", Extra_TimeStamp() );
+ fprintf( pFile, "p cnf %d %d\n", p->size, nClauses );
+
+ // write the original clauses
+ nClauses = p->clauses.size;
+ pClauses = p->clauses.ptr;
+ for ( i = 0; i < nClauses; i++ )
+ Asat_ClauseWriteDimacs( pFile, pClauses[i], 1 );
+
+ // write the learned clauses
+ nClauses = p->learnts.size;
+ pClauses = p->learnts.ptr;
+ for ( i = 0; i < nClauses; i++ )
+ Asat_ClauseWriteDimacs( pFile, pClauses[i], 1 );
+
+ // write zero-level assertions
+ for ( i = 0; i < p->size; i++ )
+ if ( p->levels[i] == 0 && p->assigns[i] != l_Undef )
+ fprintf( pFile, "%s%d 0\n", (p->assigns[i] == l_False)? "-": "", i + 1 );
+
+ fprintf( pFile, "\n" );
+ fclose( pFile );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Writes the given clause in a file in DIMACS format.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Asat_ClauseWriteDimacs( FILE * pFile, clause * pC, bool fIncrement )
+{
+ lit * pLits = clause_begin(pC);
+ int nLits = clause_size(pC);
+ int i;
+
+ for ( i = 0; i < nLits; i++ )
+ fprintf( pFile, "%s%d ", (lit_sign(pLits[i])? "-": ""), lit_var(pLits[i]) + (int)(fIncrement>0) );
+ if ( fIncrement )
+ fprintf( pFile, "0" );
+ fprintf( pFile, "\n" );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sat/asat/main.c b/src/sat/asat/main.c
new file mode 100644
index 00000000..cbad5ba1
--- /dev/null
+++ b/src/sat/asat/main.c
@@ -0,0 +1,195 @@
+/**************************************************************************************************
+MiniSat -- Copyright (c) 2005, Niklas Sorensson
+http://www.cs.chalmers.se/Cs/Research/FormalMethods/MiniSat/
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+**************************************************************************************************/
+// Modified to compile with MS Visual Studio 6.0 by Alan Mishchenko
+
+#include "solver.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+//#include <unistd.h>
+//#include <signal.h>
+//#include <zlib.h>
+//#include <sys/time.h>
+//#include <sys/resource.h>
+
+//=================================================================================================
+// Helpers:
+
+
+// Reads an input stream to end-of-file and returns the result as a 'char*' terminated by '\0'
+// (dynamic allocation in case 'in' is standard input).
+//
+char* readFile(FILE * in)
+{
+ char* data = malloc(65536);
+ int cap = 65536;
+ int size = 0;
+
+ while (!feof(in)){
+ if (size == cap){
+ cap *= 2;
+ data = realloc(data, cap); }
+ size += fread(&data[size], 1, 65536, in);
+ }
+ data = realloc(data, size+1);
+ data[size] = '\0';
+
+ return data;
+}
+
+//static inline double cpuTime(void) {
+// struct rusage ru;
+// getrusage(RUSAGE_SELF, &ru);
+// return (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec / 1000000; }
+
+
+//=================================================================================================
+// DIMACS Parser:
+
+
+static inline void skipWhitespace(char** in) {
+ while ((**in >= 9 && **in <= 13) || **in == 32)
+ (*in)++; }
+
+static inline void skipLine(char** in) {
+ for (;;){
+ if (**in == 0) return;
+ if (**in == '\n') { (*in)++; return; }
+ (*in)++; } }
+
+static inline int parseInt(char** in) {
+ int val = 0;
+ int _neg = 0;
+ skipWhitespace(in);
+ if (**in == '-') _neg = 1, (*in)++;
+ else if (**in == '+') (*in)++;
+ if (**in < '0' || **in > '9') fprintf(stderr, "PARSE ERROR! Unexpected char: %c\n", **in), exit(1);
+ while (**in >= '0' && **in <= '9')
+ val = val*10 + (**in - '0'),
+ (*in)++;
+ return _neg ? -val : val; }
+
+static void readClause(char** in, solver* s, vec* lits) {
+ int parsed_lit, var;
+ vec_resize(lits,0);
+ for (;;){
+ parsed_lit = parseInt(in);
+ if (parsed_lit == 0) break;
+ var = abs(parsed_lit)-1;
+ vec_push(lits, (void*)(parsed_lit > 0 ? toLit(var) : neg(toLit(var))));
+ }
+}
+
+static lbool parse_DIMACS_main(char* in, solver* s) {
+ vec lits;
+ vec_new(&lits);
+
+ for (;;){
+ skipWhitespace(&in);
+ if (*in == 0)
+ break;
+ else if (*in == 'c' || *in == 'p')
+ skipLine(&in);
+ else{
+ lit* begin;
+ readClause(&in, s, &lits);
+ begin = (lit*)vec_begin(&lits);
+ if (solver_addclause(s, begin, begin+vec_size(&lits)) == l_False){
+ vec_delete(&lits);
+ return l_False;
+ }
+ }
+ }
+ vec_delete(&lits);
+ return solver_simplify(s);
+}
+
+
+// Inserts problem into solver. Returns FALSE upon immediate conflict.
+//
+static lbool parse_DIMACS(FILE * in, solver* s) {
+ char* text = readFile(in);
+ lbool ret = parse_DIMACS_main(text, s);
+ free(text);
+ return ret; }
+
+
+//=================================================================================================
+
+
+void printStats(stats* stats, int cpu_time)
+{
+ double Time = (float)(cpu_time)/(float)(CLOCKS_PER_SEC);
+ printf("restarts : %12d\n", stats->starts);
+ printf("conflicts : %12.0f (%9.0f / sec )\n", (double)stats->conflicts , (double)stats->conflicts /Time);
+ printf("decisions : %12.0f (%9.0f / sec )\n", (double)stats->decisions , (double)stats->decisions /Time);
+ printf("propagations : %12.0f (%9.0f / sec )\n", (double)stats->propagations, (double)stats->propagations/Time);
+ printf("inspects : %12.0f (%9.0f / sec )\n", (double)stats->inspects , (double)stats->inspects /Time);
+ printf("conflict literals : %12.0f (%9.2f %% deleted )\n", (double)stats->tot_literals, (double)(stats->max_literals - stats->tot_literals) * 100.0 / (double)stats->max_literals);
+ printf("CPU time : %12.2f sec\n", Time);
+}
+
+//solver* slv;
+//static void SIGINT_handler(int signum) {
+// printf("\n"); printf("*** INTERRUPTED ***\n");
+// printStats(&slv->stats, cpuTime());
+// printf("\n"); printf("*** INTERRUPTED ***\n");
+// exit(0); }
+
+
+//=================================================================================================
+
+
+int main(int argc, char** argv)
+{
+ solver* s = solver_new();
+ lbool st;
+ FILE * in;
+ int clk = clock();
+
+ if (argc != 2)
+ fprintf(stderr, "ERROR! Not enough command line arguments.\n"),
+ exit(1);
+
+ in = fopen(argv[1], "rb");
+ if (in == NULL)
+ fprintf(stderr, "ERROR! Could not open file: %s\n", argc == 1 ? "<stdin>" : argv[1]),
+ exit(1);
+ st = parse_DIMACS(in, s);
+ fclose(in);
+
+ if (st == l_False){
+ solver_delete(s);
+ printf("Trivial problem\nUNSATISFIABLE\n");
+ exit(20);
+ }
+
+ s->verbosity = 1;
+// slv = s;
+// signal(SIGINT,SIGINT_handler);
+ st = solver_solve(s,0,0);
+ printStats(&s->stats, clock() - clk);
+ printf("\n");
+ printf(st == l_True ? "SATISFIABLE\n" : "UNSATISFIABLE\n");
+
+ solver_delete(s);
+ return 0;
+}
diff --git a/src/sat/asat/module.make b/src/sat/asat/module.make
new file mode 100644
index 00000000..882176fa
--- /dev/null
+++ b/src/sat/asat/module.make
@@ -0,0 +1,2 @@
+SRC += src/sat/asat/added.c \
+ src/sat/asat/solver.c
diff --git a/src/sat/asat/solver.c b/src/sat/asat/solver.c
new file mode 100644
index 00000000..c9dadcb4
--- /dev/null
+++ b/src/sat/asat/solver.c
@@ -0,0 +1,1167 @@
+/**************************************************************************************************
+MiniSat -- Copyright (c) 2005, Niklas Sorensson
+http://www.cs.chalmers.se/Cs/Research/FormalMethods/MiniSat/
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+**************************************************************************************************/
+// Modified to compile with MS Visual Studio 6.0 by Alan Mishchenko
+
+#include <stdio.h>
+#include <assert.h>
+#include <math.h>
+
+#include "solver.h"
+
+//=================================================================================================
+// Simple (var/literal) helpers:
+
+static inline int lit_var(lit l) { return l >> 1; }
+static inline int lit_sign(lit l) { return (l & 1); }
+
+//=================================================================================================
+// Debug:
+
+//#define VERBOSEDEBUG
+
+// For derivation output (verbosity level 2)
+#define L_IND "%-*d"
+#define L_ind solver_dlevel(s)*3+3,solver_dlevel(s)
+#define L_LIT "%sx%d"
+#define L_lit(p) lit_sign(p)?"~":"", (lit_var(p))
+
+// Just like 'assert()' but expression will be evaluated in the release version as well.
+static inline void check(int expr) { assert(expr); }
+
+static void printlits(lit* begin, lit* end)
+{
+ int i;
+ for (i = 0; i < end - begin; i++)
+ printf(L_LIT" ",L_lit(begin[i]));
+}
+
+//=================================================================================================
+// Random numbers:
+
+
+// Returns a random float 0 <= x < 1. Seed must never be 0.
+static inline double drand(double* seed) {
+ int q;
+ *seed *= 1389796;
+ q = (int)(*seed / 2147483647);
+ *seed -= (double)q * 2147483647;
+ return *seed / 2147483647; }
+
+
+// Returns a random integer 0 <= x < size. Seed must never be 0.
+static inline int irand(double* seed, int size) {
+ return (int)(drand(seed) * size); }
+
+
+//=================================================================================================
+// Predeclarations:
+
+void sort(void** array, int size, int(*comp)(const void *, const void *));
+
+//=================================================================================================
+// Clause datatype + minor functions:
+
+struct clause_t
+{
+ int size_learnt;
+ lit lits[0];
+};
+
+static inline int clause_size (clause* c) { return c->size_learnt >> 1; }
+static inline lit* clause_begin (clause* c) { return c->lits; }
+static inline int clause_learnt (clause* c) { return c->size_learnt & 1; }
+static inline float clause_activity (clause* c) { return *((float*)&c->lits[c->size_learnt>>1]); }
+static inline void clause_setactivity(clause* c, float a) { *((float*)&c->lits[c->size_learnt>>1]) = a; }
+
+//=================================================================================================
+// Encode literals in clause pointers:
+
+clause* clause_from_lit (lit l) { return (clause*)(l + l + 1); }
+bool clause_is_lit (clause* c) { return ((unsigned int)c & 1); }
+lit clause_read_lit (clause* c) { return (lit)((unsigned int)c >> 1); }
+
+//=================================================================================================
+// Simple helpers:
+
+static inline int solver_dlevel(solver* s) { return vec_size(&s->trail_lim); }
+static inline vec* solver_read_wlist (solver* s, lit l){ return &s->wlists[l]; }
+static inline void vec_remove(vec* v, void* e)
+{
+ void** ws = vec_begin(v);
+ int j = 0;
+
+ for (; ws[j] != e ; j++);
+ assert(j < vec_size(v));
+ for (; j < vec_size(v)-1; j++) ws[j] = ws[j+1];
+ vec_resize(v,vec_size(v)-1);
+}
+
+//=================================================================================================
+// Variable order functions:
+
+static inline void order_update(solver* s, int v) // updateorder
+{
+ int* orderpos = s->orderpos;
+ double* activity = s->activity;
+ int* heap = (int*)vec_begin(&s->order);
+ int i = orderpos[v];
+ int x = heap[i];
+ int parent = (i - 1) / 2;
+
+ assert(s->orderpos[v] != -1);
+
+ while (i != 0 && activity[x] > activity[heap[parent]]){
+ heap[i] = heap[parent];
+ orderpos[heap[i]] = i;
+ i = parent;
+ parent = (i - 1) / 2;
+ }
+ heap[i] = x;
+ orderpos[x] = i;
+}
+
+static inline void order_assigned(solver* s, int v)
+{
+}
+
+static inline void order_unassigned(solver* s, int v) // undoorder
+{
+ int* orderpos = s->orderpos;
+ if (orderpos[v] == -1){
+ orderpos[v] = vec_size(&s->order);
+ vec_push(&s->order,(void*)v);
+ order_update(s,v);
+ }
+}
+
+static int order_select(solver* s, float random_var_freq) // selectvar
+{
+ int* heap;
+ double* activity;
+ int* orderpos;
+
+ lbool* values = s->assigns;
+
+ // Random decision:
+ if (drand(&s->random_seed) < random_var_freq){
+ int next = irand(&s->random_seed,s->size);
+ assert(next >= 0 && next < s->size);
+ if (values[next] == l_Undef)
+ return next;
+ }
+
+ // Activity based decision:
+
+ heap = (int*)vec_begin(&s->order);
+ activity = s->activity;
+ orderpos = s->orderpos;
+
+
+ while (vec_size(&s->order) > 0){
+ int next = heap[0];
+ int size = vec_size(&s->order)-1;
+ int x = heap[size];
+
+ vec_resize(&s->order,size);
+
+ orderpos[next] = -1;
+
+ if (size > 0){
+ double act = activity[x];
+
+ int i = 0;
+ int child = 1;
+
+
+ while (child < size){
+ if (child+1 < size && activity[heap[child]] < activity[heap[child+1]])
+ child++;
+
+ assert(child < size);
+
+ if (act >= activity[heap[child]])
+ break;
+
+ heap[i] = heap[child];
+ orderpos[heap[i]] = i;
+ i = child;
+ child = 2 * child + 1;
+ }
+ heap[i] = x;
+ orderpos[heap[i]] = i;
+ }
+
+ if (values[next] == l_Undef)
+ return next;
+ }
+
+ return var_Undef;
+}
+
+//=================================================================================================
+// Activity functions:
+
+static inline void act_var_rescale(solver* s) {
+ double* activity = s->activity;
+ int i;
+ for (i = 0; i < s->size; i++)
+ activity[i] *= 1e-100;
+ s->var_inc *= 1e-100;
+}
+
+static inline void act_var_bump(solver* s, int v) {
+ double* activity = s->activity;
+ if ((activity[v] += s->var_inc) > 1e100)
+ act_var_rescale(s);
+
+ //printf("bump %d %f\n", v-1, activity[v]);
+
+ if (s->orderpos[v] != -1)
+ order_update(s,v);
+
+}
+
+static inline void act_var_decay(solver* s) { s->var_inc *= s->var_decay; }
+
+static inline void act_clause_rescale(solver* s) {
+ clause** cs = (clause**)vec_begin(&s->learnts);
+ int i;
+ for (i = 0; i < vec_size(&s->learnts); i++){
+ float a = clause_activity(cs[i]);
+ clause_setactivity(cs[i], a * (float)1e-20);
+ }
+ s->cla_inc *= (float)1e-20;
+}
+
+
+static inline void act_clause_bump(solver* s, clause *c) {
+ float a = clause_activity(c) + s->cla_inc;
+ clause_setactivity(c,a);
+ if (a > 1e20) act_clause_rescale(s);
+}
+
+static inline void act_clause_decay(solver* s) { s->cla_inc *= s->cla_decay; }
+
+
+//=================================================================================================
+// Clause functions:
+
+/* pre: size > 1 && no variable occurs twice
+ */
+static clause* clause_new(solver* s, lit* begin, lit* end, int learnt)
+{
+ int size;
+ clause* c;
+ int i;
+
+ assert(end - begin > 1);
+ assert(learnt >= 0 && learnt < 2);
+ size = end - begin;
+ c = (clause*)malloc(sizeof(clause) + sizeof(lit) * size + learnt * sizeof(float));
+ c->size_learnt = (size << 1) | learnt;
+ assert(((unsigned int)c & 1) == 0);
+
+ for (i = 0; i < size; i++)
+ c->lits[i] = begin[i];
+
+ if (learnt)
+ *((float*)&c->lits[size]) = 0.0;
+
+ assert(begin[0] >= 0);
+ assert(begin[0] < s->size*2);
+ assert(begin[1] >= 0);
+ assert(begin[1] < s->size*2);
+
+ assert(neg(begin[0]) < s->size*2);
+ assert(neg(begin[1]) < s->size*2);
+
+ //vec_push(solver_read_wlist(s,neg(begin[0])),(void*)c);
+ //vec_push(solver_read_wlist(s,neg(begin[1])),(void*)c);
+
+ vec_push(solver_read_wlist(s,neg(begin[0])),(void*)(size > 2 ? c : clause_from_lit(begin[1])));
+ vec_push(solver_read_wlist(s,neg(begin[1])),(void*)(size > 2 ? c : clause_from_lit(begin[0])));
+
+ return c;
+}
+
+
+static void clause_remove(solver* s, clause* c)
+{
+ lit* lits = clause_begin(c);
+ assert(neg(lits[0]) < s->size*2);
+ assert(neg(lits[1]) < s->size*2);
+
+ //vec_remove(solver_read_wlist(s,neg(lits[0])),(void*)c);
+ //vec_remove(solver_read_wlist(s,neg(lits[1])),(void*)c);
+
+ assert(lits[0] < s->size*2);
+ vec_remove(solver_read_wlist(s,neg(lits[0])),(void*)(clause_size(c) > 2 ? c : clause_from_lit(lits[1])));
+ vec_remove(solver_read_wlist(s,neg(lits[1])),(void*)(clause_size(c) > 2 ? c : clause_from_lit(lits[0])));
+
+ if (clause_learnt(c)){
+ s->stats.learnts--;
+ s->stats.learnts_literals -= clause_size(c);
+ }else{
+ s->stats.clauses--;
+ s->stats.clauses_literals -= clause_size(c);
+ }
+
+ free(c);
+}
+
+
+static lbool clause_simplify(solver* s, clause* c)
+{
+ lit* lits = clause_begin(c);
+ lbool* values = s->assigns;
+ int i;
+
+ assert(solver_dlevel(s) == 0);
+
+ for (i = 0; i < clause_size(c); i++){
+ lbool sig = !lit_sign(lits[i]); sig += sig - 1;
+ if (values[lit_var(lits[i])] == sig)
+ return l_True;
+ }
+ return l_False;
+}
+
+//=================================================================================================
+// Minor (solver) functions:
+
+static void solver_setnvars(solver* s,int n)
+{
+ int var;
+ if (s->cap < n){
+
+ while (s->cap < n) s->cap = s->cap*2+1;
+
+ s->wlists = (vec*) realloc(s->wlists, sizeof(vec)*s->cap*2);
+ s->activity = (double*) realloc(s->activity, sizeof(double)*s->cap);
+ s->assigns = (lbool*) realloc(s->assigns, sizeof(lbool)*s->cap);
+ s->orderpos = (int*) realloc(s->orderpos, sizeof(int)*s->cap);
+ s->reasons = (clause**)realloc(s->reasons, sizeof(clause*)*s->cap);
+ s->levels = (int*) realloc(s->levels, sizeof(int)*s->cap);
+ s->tags = (lbool*) realloc(s->tags, sizeof(lbool)*s->cap);
+ s->trail = (lit*) realloc(s->trail, sizeof(lit)*s->cap);
+ }
+
+ for (var = s->size; var < n; var++){
+ vec_new(&s->wlists[2*var]);
+ vec_new(&s->wlists[2*var+1]);
+ s->activity [var] = 0;
+ s->assigns [var] = l_Undef;
+ s->orderpos [var] = var;
+ s->reasons [var] = (clause*)0;
+ s->levels [var] = 0;
+ s->tags [var] = l_Undef;
+
+ assert(vec_size(&s->order) == var);
+ vec_push(&s->order,(void*)var);
+ order_update(s,var);
+ }
+
+ s->size = n > s->size ? n : s->size;
+}
+
+
+static inline bool enqueue(solver* s, lit l, clause* from)
+{
+ lbool* values = s->assigns;
+ int v = lit_var(l);
+ lbool val = values[v];
+#ifdef VERBOSEDEBUG
+ printf(L_IND"enqueue("L_LIT")\n", L_ind, L_lit(l));
+#endif
+
+ lbool sig = !lit_sign(l); sig += sig - 1;
+ if (val != l_Undef){
+ return val == sig;
+ }else{
+ // New fact -- store it.
+#ifdef VERBOSEDEBUG
+ printf(L_IND"bind("L_LIT")\n", L_ind, L_lit(l));
+#endif
+ int* levels = s->levels;
+ clause** reasons = s->reasons;
+
+ values [v] = sig;
+ levels [v] = solver_dlevel(s);
+ reasons[v] = from;
+ s->trail[s->qtail++] = l;
+
+ order_assigned(s, v);
+ return true;
+ }
+}
+
+
+static inline void assume(solver* s, lit l){
+ assert(s->qtail == s->qhead);
+ assert(s->assigns[lit_var(l)] == l_Undef);
+#ifdef VERBOSEDEBUG
+ printf(L_IND"assume("L_LIT")\n", L_ind, L_lit(l));
+#endif
+ vec_push(&s->trail_lim,(void*)s->qtail);
+ enqueue(s,l,(clause*)0);
+}
+
+
+static inline void solver_canceluntil(solver* s, int level) {
+ lit* trail;
+ lbool* values;
+ clause** reasons;
+ int bound;
+ int c;
+
+ if (solver_dlevel(s) <= level)
+ return;
+
+ trail = s->trail;
+ values = s->assigns;
+ reasons = s->reasons;
+ bound = ((int*)vec_begin(&s->trail_lim))[level];
+
+ for (c = s->qtail-1; c >= bound; c--) {
+ int x = lit_var(trail[c]);
+ values [x] = l_Undef;
+ reasons[x] = (clause*)0;
+ }
+
+ for (c = s->qhead-1; c >= bound; c--)
+ order_unassigned(s,lit_var(trail[c]));
+
+ s->qhead = s->qtail = bound;
+ vec_resize(&s->trail_lim,level);
+}
+
+static void solver_record(solver* s, vec* cls)
+{
+ lit* begin = (lit*)vec_begin(cls);
+ lit* end = begin + vec_size(cls);
+ clause* c = (vec_size(cls) > 1) ? clause_new(s,begin,end,1) : (clause*)0;
+ enqueue(s,*begin,c);
+
+ assert(vec_size(cls) > 0);
+
+ if (c != 0) {
+ vec_push(&s->learnts,(void*)c);
+ act_clause_bump(s,c);
+ s->stats.learnts++;
+ s->stats.learnts_literals += vec_size(cls);
+ }
+}
+
+
+static double solver_progress(solver* s)
+{
+ lbool* values = s->assigns;
+ int* levels = s->levels;
+ int i;
+
+ double progress = 0;
+ double F = 1.0 / s->size;
+ for (i = 0; i < s->size; i++)
+ if (values[i] != l_Undef)
+ progress += pow(F, levels[i]);
+ return progress / s->size;
+}
+
+//=================================================================================================
+// Major methods:
+
+static bool solver_lit_removable(solver* s, lit l, int minl)
+{
+ lbool* tags = s->tags;
+ clause** reasons = s->reasons;
+ int* levels = s->levels;
+ int top = vec_size(&s->tagged);
+
+ assert(lit_var(l) >= 0 && lit_var(l) < s->size);
+ assert(reasons[lit_var(l)] != 0);
+ vec_resize(&s->stack,0);
+ vec_push(&s->stack,(void*)lit_var(l));
+
+ while (vec_size(&s->stack) > 0){
+ clause* c;
+ int v = (int)vec_begin(&s->stack)[vec_size(&s->stack)-1];
+ assert(v >= 0 && v < s->size);
+ vec_resize(&s->stack,vec_size(&s->stack)-1);
+ assert(reasons[v] != 0);
+ c = reasons[v];
+
+ if (clause_is_lit(c)){
+ int v = lit_var(clause_read_lit(c));
+ if (tags[v] == l_Undef && levels[v] != 0){
+ if (reasons[v] != 0 && ((1 << (levels[v] & 31)) & minl)){
+ vec_push(&s->stack,(void*)v);
+ tags[v] = l_True;
+ vec_push(&s->tagged,(void*)v);
+ }else{
+ int* tagged = (int*)vec_begin(&s->tagged);
+ int j;
+ for (j = top; j < vec_size(&s->tagged); j++)
+ tags[tagged[j]] = l_Undef;
+ vec_resize(&s->tagged,top);
+ return false;
+ }
+ }
+ }else{
+ lit* lits = clause_begin(c);
+ int i, j;
+
+ for (i = 1; i < clause_size(c); i++){
+ int v = lit_var(lits[i]);
+ if (tags[v] == l_Undef && levels[v] != 0){
+ if (reasons[v] != 0 && ((1 << (levels[v] & 31)) & minl)){
+
+ vec_push(&s->stack,(void*)lit_var(lits[i]));
+ tags[v] = l_True;
+ vec_push(&s->tagged,(void*)v);
+ }else{
+ int* tagged = (int*)vec_begin(&s->tagged);
+ for (j = top; j < vec_size(&s->tagged); j++)
+ tags[tagged[j]] = l_Undef;
+ vec_resize(&s->tagged,top);
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+static void solver_analyze(solver* s, clause* c, vec* learnt)
+{
+ lit* trail = s->trail;
+ lbool* tags = s->tags;
+ clause** reasons = s->reasons;
+ int* levels = s->levels;
+ int cnt = 0;
+ lit p = lit_Undef;
+ int ind = s->qtail-1;
+ lit* lits;
+ int i, j, minl;
+ int* tagged;
+
+ vec_push(learnt,(void*)lit_Undef);
+
+ do{
+ assert(c != 0);
+
+ if (clause_is_lit(c)){
+ lit q = clause_read_lit(c);
+ assert(lit_var(q) >= 0 && lit_var(q) < s->size);
+ if (tags[lit_var(q)] == l_Undef && levels[lit_var(q)] > 0){
+ tags[lit_var(q)] = l_True;
+ vec_push(&s->tagged,(void*)lit_var(q));
+ act_var_bump(s,lit_var(q));
+ if (levels[lit_var(q)] == solver_dlevel(s))
+ cnt++;
+ else
+ vec_push(learnt,(void*)q);
+ }
+ }else{
+
+ if (clause_learnt(c))
+ act_clause_bump(s,c);
+
+ lits = clause_begin(c);
+ //printlits(lits,lits+clause_size(c)); printf("\n");
+ for (j = (p == lit_Undef ? 0 : 1); j < clause_size(c); j++){
+ lit q = lits[j];
+ assert(lit_var(q) >= 0 && lit_var(q) < s->size);
+ if (tags[lit_var(q)] == l_Undef && levels[lit_var(q)] > 0){
+ tags[lit_var(q)] = l_True;
+ vec_push(&s->tagged,(void*)lit_var(q));
+ act_var_bump(s,lit_var(q));
+ if (levels[lit_var(q)] == solver_dlevel(s))
+ cnt++;
+ else
+ vec_push(learnt,(void*)q);
+ }
+ }
+ }
+
+ while (tags[lit_var(trail[ind--])] == l_Undef);
+
+ p = trail[ind+1];
+ c = reasons[lit_var(p)];
+ cnt--;
+
+ }while (cnt > 0);
+
+ *(lit*)vec_begin(learnt) = neg(p);
+
+ lits = (lit*)vec_begin(learnt);
+ minl = 0;
+ for (i = 1; i < vec_size(learnt); i++){
+ int lev = levels[lit_var(lits[i])];
+ minl |= 1 << (lev & 31);
+ }
+
+ // simplify (full)
+ for (i = j = 1; i < vec_size(learnt); i++){
+ if (reasons[lit_var(lits[i])] == 0 || !solver_lit_removable(s,lits[i],minl))
+ lits[j++] = lits[i];
+ }
+
+ // update size of learnt + statistics
+ s->stats.max_literals += vec_size(learnt);
+ vec_resize(learnt,j);
+ s->stats.tot_literals += j;
+
+ // clear tags
+ tagged = (int*)vec_begin(&s->tagged);
+ for (i = 0; i < vec_size(&s->tagged); i++)
+ tags[tagged[i]] = l_Undef;
+ vec_resize(&s->tagged,0);
+
+#ifdef DEBUG
+ for (i = 0; i < s->size; i++)
+ assert(tags[i] == l_Undef);
+#endif
+
+#ifdef VERBOSEDEBUG
+ printf(L_IND"Learnt {", L_ind);
+ for (i = 0; i < vec_size(learnt); i++) printf(" "L_LIT, L_lit(lits[i]));
+#endif
+ if (vec_size(learnt) > 1){
+ int max_i = 1;
+ int max = levels[lit_var(lits[1])];
+ lit tmp;
+
+ for (i = 2; i < vec_size(learnt); i++)
+ if (levels[lit_var(lits[i])] > max){
+ max = levels[lit_var(lits[i])];
+ max_i = i;
+ }
+
+ tmp = lits[1];
+ lits[1] = lits[max_i];
+ lits[max_i] = tmp;
+ }
+#ifdef VERBOSEDEBUG
+ {
+ int lev = vec_size(learnt) > 1 ? levels[lit_var(lits[1])] : 0;
+ printf(" } at level %d\n", lev);
+ }
+#endif
+}
+
+
+clause* solver_propagate(solver* s)
+{
+ lbool* values = s->assigns;
+ clause* confl = (clause*)0;
+ lit* lits;
+
+ //printf("solver_propagate\n");
+ while (confl == 0 && s->qtail - s->qhead > 0){
+ lit p = s->trail[s->qhead++];
+ vec* ws = solver_read_wlist(s,p);
+ clause **begin = (clause**)vec_begin(ws);
+ clause **end = begin + vec_size(ws);
+ clause **i, **j;
+
+ s->stats.propagations++;
+ s->simpdb_props--;
+
+ //printf("checking lit %d: "L_LIT"\n", vec_size(ws), L_lit(p));
+ for (i = j = begin; i < end; ){
+ if (clause_is_lit(*i)){
+ *j++ = *i;
+ if (!enqueue(s,clause_read_lit(*i),clause_from_lit(p))){
+ confl = s->binary;
+ (clause_begin(confl))[1] = neg(p);
+ (clause_begin(confl))[0] = clause_read_lit(*i++);
+
+ // Copy the remaining watches:
+ while (i < end)
+ *j++ = *i++;
+ }
+ }else{
+ lit false_lit;
+ lbool sig;
+
+ lits = clause_begin(*i);
+
+ // Make sure the false literal is data[1]:
+ false_lit = neg(p);
+ if (lits[0] == false_lit){
+ lits[0] = lits[1];
+ lits[1] = false_lit;
+ }
+ assert(lits[1] == false_lit);
+ //printf("checking clause: "); printlits(lits, lits+clause_size(*i)); printf("\n");
+
+ // If 0th watch is true, then clause is already satisfied.
+ sig = !lit_sign(lits[0]); sig += sig - 1;
+ if (values[lit_var(lits[0])] == sig){
+ *j++ = *i;
+ }else{
+ // Look for new watch:
+ lit* stop = lits + clause_size(*i);
+ lit* k;
+ for (k = lits + 2; k < stop; k++){
+ lbool sig = lit_sign(*k); sig += sig - 1;
+ if (values[lit_var(*k)] != sig){
+ lits[1] = *k;
+ *k = false_lit;
+ vec_push(solver_read_wlist(s,neg(lits[1])),*i);
+ goto next; }
+ }
+
+ *j++ = *i;
+ // Clause is unit under assignment:
+ if (!enqueue(s,lits[0], *i)){
+ confl = *i++;
+ // Copy the remaining watches:
+ while (i < end)
+ *j++ = *i++;
+ }
+ }
+ }
+ next:
+ i++;
+ }
+
+ s->stats.inspects += j - (clause**)vec_begin(ws);
+ vec_resize(ws,j - (clause**)vec_begin(ws));
+ }
+
+ return confl;
+}
+
+static inline int clause_cmp (const void* x, const void* y) {
+ return clause_size((clause*)x) > 2 && (clause_size((clause*)y) == 2 || clause_activity((clause*)x) < clause_activity((clause*)y)) ? -1 : 1; }
+
+void solver_reducedb(solver* s)
+{
+ int i, j;
+ double extra_lim = s->cla_inc / vec_size(&s->learnts); // Remove any clause below this activity
+ clause** learnts = (clause**)vec_begin(&s->learnts);
+ clause** reasons = s->reasons;
+
+ sort(vec_begin(&s->learnts), vec_size(&s->learnts), &clause_cmp);
+
+ for (i = j = 0; i < vec_size(&s->learnts) / 2; i++){
+ if (clause_size(learnts[i]) > 2 && reasons[lit_var(*clause_begin(learnts[i]))] != learnts[i])
+ clause_remove(s,learnts[i]);
+ else
+ learnts[j++] = learnts[i];
+ }
+ for (; i < vec_size(&s->learnts); i++){
+ if (clause_size(learnts[i]) > 2 && reasons[lit_var(*clause_begin(learnts[i]))] != learnts[i] && clause_activity(learnts[i]) < extra_lim)
+ clause_remove(s,learnts[i]);
+ else
+ learnts[j++] = learnts[i];
+ }
+
+ //printf("reducedb deleted %d\n", vec_size(&s->learnts) - j);
+
+
+ vec_resize(&s->learnts,j);
+}
+
+static lbool solver_search(solver* s, int nof_conflicts, int nof_learnts)
+{
+ int* levels = s->levels;
+ double var_decay = 0.95;
+ double clause_decay = 0.999;
+ double random_var_freq = 0.02;
+
+ int conflictC = 0;
+ vec learnt_clause;
+
+ assert(s->root_level == solver_dlevel(s));
+
+ s->stats.starts++;
+ s->var_decay = (float)(1 / var_decay );
+ s->cla_decay = (float)(1 / clause_decay);
+ vec_resize(&s->model,0);
+ vec_new(&learnt_clause);
+
+ for (;;){
+ clause* confl = solver_propagate(s);
+ if (confl != 0){
+ // CONFLICT
+ int blevel;
+
+#ifdef VERBOSEDEBUG
+ printf(L_IND"**CONFLICT**\n", L_ind);
+#endif
+ s->stats.conflicts++; conflictC++;
+ if (solver_dlevel(s) == s->root_level){
+ vec_delete(&learnt_clause);
+ return l_False;
+ }
+
+ vec_resize(&learnt_clause,0);
+ solver_analyze(s, confl, &learnt_clause);
+ blevel = vec_size(&learnt_clause) > 1 ? levels[lit_var(((lit*)vec_begin(&learnt_clause))[1])] : s->root_level;
+ solver_canceluntil(s,blevel);
+ solver_record(s,&learnt_clause);
+ act_var_decay(s);
+ act_clause_decay(s);
+
+ }else{
+ // NO CONFLICT
+ int next;
+
+ if (nof_conflicts >= 0 && conflictC >= nof_conflicts){
+ // Reached bound on number of conflicts:
+ s->progress_estimate = solver_progress(s);
+ solver_canceluntil(s,s->root_level);
+ vec_delete(&learnt_clause);
+ return l_Undef; }
+
+ if (solver_dlevel(s) == 0)
+ // Simplify the set of problem clauses:
+ solver_simplify(s);
+
+ if (nof_learnts >= 0 && vec_size(&s->learnts) - s->qtail >= nof_learnts)
+ // Reduce the set of learnt clauses:
+ solver_reducedb(s);
+
+ // New variable decision:
+ s->stats.decisions++;
+ next = order_select(s,(float)random_var_freq);
+
+ if (next == var_Undef){
+ // Model found:
+ lbool* values = s->assigns;
+ int i;
+ for (i = 0; i < s->size; i++) vec_push(&s->model,(void*)((int)values[i]));
+ solver_canceluntil(s,s->root_level);
+ vec_delete(&learnt_clause);
+ return l_True;
+ }
+
+ assume(s,neg(toLit(next)));
+ }
+ }
+
+ return l_Undef; // cannot happen
+}
+
+//=================================================================================================
+// External solver functions:
+
+solver* solver_new(void)
+{
+ solver* s = (solver*)malloc(sizeof(solver));
+
+ // initialize vectors
+ vec_new(&s->clauses);
+ vec_new(&s->learnts);
+ vec_new(&s->order);
+ vec_new(&s->trail_lim);
+ vec_new(&s->tagged);
+ vec_new(&s->stack);
+ vec_new(&s->model);
+
+ // initialize arrays
+ s->wlists = 0;
+ s->activity = 0;
+ s->assigns = 0;
+ s->orderpos = 0;
+ s->reasons = 0;
+ s->levels = 0;
+ s->tags = 0;
+ s->trail = 0;
+
+
+ // initialize other vars
+ s->size = 0;
+ s->cap = 0;
+ s->qhead = 0;
+ s->qtail = 0;
+ s->cla_inc = 1;
+ s->cla_decay = 1;
+ s->var_inc = 1;
+ s->var_decay = 1;
+ s->root_level = 0;
+ s->simpdb_assigns = 0;
+ s->simpdb_props = 0;
+ s->random_seed = 91648253;
+ s->progress_estimate = 0;
+ s->binary = (clause*)malloc(sizeof(clause) + sizeof(lit)*2);
+ s->binary->size_learnt = (2 << 1);
+ s->verbosity = 0;
+
+ s->stats.starts = 0;
+ s->stats.decisions = 0;
+ s->stats.propagations = 0;
+ s->stats.inspects = 0;
+ s->stats.conflicts = 0;
+ s->stats.clauses = 0;
+ s->stats.clauses_literals = 0;
+ s->stats.learnts = 0;
+ s->stats.learnts_literals = 0;
+ s->stats.max_literals = 0;
+ s->stats.tot_literals = 0;
+
+ return s;
+}
+
+
+void solver_delete(solver* s)
+{
+ int i;
+ for (i = 0; i < vec_size(&s->clauses); i++)
+ free(vec_begin(&s->clauses)[i]);
+
+ for (i = 0; i < vec_size(&s->learnts); i++)
+ free(vec_begin(&s->learnts)[i]);
+
+ // delete vectors
+ vec_delete(&s->clauses);
+ vec_delete(&s->learnts);
+ vec_delete(&s->order);
+ vec_delete(&s->trail_lim);
+ vec_delete(&s->tagged);
+ vec_delete(&s->stack);
+ vec_delete(&s->model);
+ free(s->binary);
+
+ // delete arrays
+ if (s->wlists != 0){
+ int i;
+ for (i = 0; i < s->size*2; i++)
+ vec_delete(&s->wlists[i]);
+
+ // if one is different from null, all are
+ free(s->wlists);
+ free(s->activity );
+ free(s->assigns );
+ free(s->orderpos );
+ free(s->reasons );
+ free(s->levels );
+ free(s->trail );
+ free(s->tags );
+ }
+
+ free(s);
+}
+
+
+bool solver_addclause(solver* s, lit* begin, lit* end)
+{
+ lit *i,*j;
+ int maxvar;
+ lbool* values;
+ lit last;
+
+ if (begin == end) return false;
+
+ //printlits(begin,end); printf("\n");
+ // insertion sort
+ maxvar = lit_var(*begin);
+ for (i = begin + 1; i < end; i++){
+ lit l = *i;
+ maxvar = lit_var(l) > maxvar ? lit_var(l) : maxvar;
+ for (j = i; j > begin && *(j-1) > l; j--)
+ *j = *(j-1);
+ *j = l;
+ }
+ solver_setnvars(s,maxvar+1);
+
+ //printlits(begin,end); printf("\n");
+ values = s->assigns;
+
+ // delete duplicates
+ last = lit_Undef;
+ for (i = j = begin; i < end; i++){
+ //printf("lit: "L_LIT", value = %d\n", L_lit(*i), (lit_sign(*i) ? -values[lit_var(*i)] : values[lit_var(*i)]));
+ lbool sig = !lit_sign(*i); sig += sig - 1;
+ if (*i == neg(last) || sig == values[lit_var(*i)])
+ return true; // tautology
+ else if (*i != last && values[lit_var(*i)] == l_Undef)
+ last = *j++ = *i;
+ }
+
+ //printf("final: "); printlits(begin,j); printf("\n");
+
+ if (j == begin) // empty clause
+ return false;
+ else if (j - begin == 1) // unit clause
+ return enqueue(s,*begin,(clause*)0);
+
+ // create new clause
+ vec_push(&s->clauses,clause_new(s,begin,j,0));
+
+
+ s->stats.clauses++;
+ s->stats.clauses_literals += j - begin;
+
+ return true;
+}
+
+
+bool solver_simplify(solver* s)
+{
+ clause** reasons;
+ int type;
+
+ assert(solver_dlevel(s) == 0);
+
+ if (solver_propagate(s) != 0)
+ return false;
+
+ if (s->qhead == s->simpdb_assigns || s->simpdb_props > 0)
+ return true;
+
+ reasons = s->reasons;
+ for (type = 0; type < 2; type++){
+ vec* cs = type ? &s->learnts : &s->clauses;
+ clause** cls = (clause**)vec_begin(cs);
+
+ int i, j;
+ for (j = i = 0; i < vec_size(cs); i++){
+ if (reasons[lit_var(*clause_begin(cls[i]))] != cls[i] &&
+ clause_simplify(s,cls[i]) == l_True)
+ clause_remove(s,cls[i]);
+ else
+ cls[j++] = cls[i];
+ }
+ vec_resize(cs,j);
+ }
+
+ s->simpdb_assigns = s->qhead;
+ // (shouldn't depend on 'stats' really, but it will do for now)
+ s->simpdb_props = (int)(s->stats.clauses_literals + s->stats.learnts_literals);
+
+ return true;
+}
+
+
+bool solver_solve(solver* s, lit* begin, lit* end)
+{
+ double nof_conflicts = 100;
+ double nof_learnts = solver_nclauses(s) / 3;
+ lbool status = l_Undef;
+ lbool* values = s->assigns;
+ lit* i;
+
+ for (i = begin; i < end; i++)
+ if ((lit_sign(*i) ? -values[lit_var(*i)] : values[lit_var(*i)]) == l_False || (assume(s,*i), solver_propagate(s) != 0)){
+ solver_canceluntil(s,0);
+ return false; }
+
+ s->root_level = solver_dlevel(s);
+
+ if (s->verbosity >= 1){
+ printf("==================================[MINISAT]===================================\n");
+ printf("| Conflicts | ORIGINAL | LEARNT | Progress |\n");
+ printf("| | Clauses Literals | Limit Clauses Literals Lit/Cl | |\n");
+ printf("==============================================================================\n");
+ }
+
+ while (status == l_Undef){
+ double Ratio = (s->stats.learnts == 0)? 0.0 :
+ s->stats.learnts_literals / (double)s->stats.learnts;
+
+ if (s->verbosity >= 1){
+ printf("| %9.0f | %7.0f %8.0f | %7.0f %7.0f %8.0f %7.1f | %6.3f %% |\n",
+ (double)s->stats.conflicts,
+ (double)s->stats.clauses,
+ (double)s->stats.clauses_literals,
+ (double)nof_learnts,
+ (double)s->stats.learnts,
+ (double)s->stats.learnts_literals,
+ Ratio,
+ s->progress_estimate*100);
+ fflush(stdout);
+ }
+ status = solver_search(s,(int)nof_conflicts, (int)nof_learnts);
+ nof_conflicts *= 1.5;
+ nof_learnts *= 1.1;
+ }
+ if (s->verbosity >= 1)
+ printf("==============================================================================\n");
+
+ solver_canceluntil(s,0);
+ return status != l_False;
+}
+
+
+int solver_nvars(solver* s)
+{
+ return s->size;
+}
+
+
+int solver_nclauses(solver* s)
+{
+ return vec_size(&s->clauses);
+}
+
+//=================================================================================================
+// Sorting functions (sigh):
+
+static inline void selectionsort(void** array, int size, int(*comp)(const void *, const void *))
+{
+ int i, j, best_i;
+ void* tmp;
+
+ for (i = 0; i < size-1; i++){
+ best_i = i;
+ for (j = i+1; j < size; j++){
+ if (comp(array[j], array[best_i]) < 0)
+ best_i = j;
+ }
+ tmp = array[i]; array[i] = array[best_i]; array[best_i] = tmp;
+ }
+}
+
+
+static void sortrnd(void** array, int size, int(*comp)(const void *, const void *), double* seed)
+{
+ if (size <= 15)
+ selectionsort(array, size, comp);
+
+ else{
+ void* pivot = array[irand(seed, size)];
+ void* tmp;
+ int i = -1;
+ int j = size;
+
+ for(;;){
+ do i++; while(comp(array[i], pivot)<0);
+ do j--; while(comp(pivot, array[j])<0);
+
+ if (i >= j) break;
+
+ tmp = array[i]; array[i] = array[j]; array[j] = tmp;
+ }
+
+ sortrnd(array , i , comp, seed);
+ sortrnd(&array[i], size-i, comp, seed);
+ }
+}
+
+void sort(void** array, int size, int(*comp)(const void *, const void *))
+{
+ double seed = 91648253;
+ sortrnd(array,size,comp,&seed);
+}
diff --git a/src/sat/asat/solver.h b/src/sat/asat/solver.h
new file mode 100644
index 00000000..e04d5780
--- /dev/null
+++ b/src/sat/asat/solver.h
@@ -0,0 +1,137 @@
+/**************************************************************************************************
+MiniSat -- Copyright (c) 2005, Niklas Sorensson
+http://www.cs.chalmers.se/Cs/Research/FormalMethods/MiniSat/
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+**************************************************************************************************/
+// Modified to compile with MS Visual Studio 6.0 by Alan Mishchenko
+
+#ifndef solver_h
+#define solver_h
+
+#ifdef _WIN32
+#define inline __inline // compatible with MS VS 6.0
+#endif
+
+#include "solver_vec.h"
+
+//=================================================================================================
+// Simple types:
+
+//typedef int bool;
+#ifndef bool
+#define bool int
+#endif
+
+static const bool true = 1;
+static const bool false = 0;
+
+typedef int lit;
+typedef char lbool;
+
+#ifdef _WIN32
+typedef signed __int64 uint64; // compatible with MS VS 6.0
+#else
+typedef unsigned long long uint64;
+#endif
+
+static const int var_Undef = -1;
+static const lit lit_Undef = -2;
+
+static const lbool l_Undef = 0;
+static const lbool l_True = 1;
+static const lbool l_False = -1;
+
+static inline lit neg (lit l) { return l ^ 1; }
+static inline lit toLit (int v) { return v + v; }
+
+//=================================================================================================
+// Public interface:
+
+struct solver_t;
+typedef struct solver_t solver;
+
+extern solver* solver_new(void);
+extern void solver_delete(solver* s);
+
+extern bool solver_addclause(solver* s, lit* begin, lit* end);
+extern bool solver_simplify(solver* s);
+extern bool solver_solve(solver* s, lit* begin, lit* end);
+
+extern int solver_nvars(solver* s);
+extern int solver_nclauses(solver* s);
+
+// additional procedures
+extern void Asat_SolverWriteDimacs( solver * pSat, char * pFileName );
+
+struct stats_t
+{
+ uint64 starts, decisions, propagations, inspects, conflicts;
+ uint64 clauses, clauses_literals, learnts, learnts_literals, max_literals, tot_literals;
+};
+typedef struct stats_t stats;
+
+//=================================================================================================
+// Solver representation:
+
+struct clause_t;
+typedef struct clause_t clause;
+
+struct solver_t
+{
+ int size; // nof variables
+ int cap; // size of varmaps
+ int qhead; // Head index of queue.
+ int qtail; // Tail index of queue.
+
+ // clauses
+ vec clauses; // List of problem constraints. (contains: clause*)
+ vec learnts; // List of learnt clauses. (contains: clause*)
+
+ // activities
+ double var_inc; // Amount to bump next variable with.
+ double var_decay; // INVERSE decay factor for variable activity: stores 1/decay.
+ float cla_inc; // Amount to bump next clause with.
+ float cla_decay; // INVERSE decay factor for clause activity: stores 1/decay.
+
+ vec* wlists; //
+ double* activity; // A heuristic measurement of the activity of a variable.
+ lbool* assigns; // Current values of variables.
+ int* orderpos; // Index in variable order.
+ clause** reasons; //
+ int* levels; //
+ lit* trail;
+
+ clause* binary; // A temporary binary clause
+ lbool* tags; //
+ vec tagged; // (contains: var)
+ vec stack; // (contains: var)
+
+ vec order; // Variable order. (heap) (contains: var)
+ vec trail_lim; // Separator indices for different decision levels in 'trail'. (contains: int)
+ vec model; // If problem is solved, this vector contains the model (contains: lbool).
+
+ int root_level; // Level of first proper decision.
+ int simpdb_assigns;// Number of top-level assignments at last 'simplifyDB()'.
+ int simpdb_props; // Number of propagations before next 'simplifyDB()'.
+ double random_seed;
+ double progress_estimate;
+ int verbosity; // Verbosity level. 0=silent, 1=some progress report, 2=everything
+
+ stats stats;
+};
+
+#endif
diff --git a/src/sat/asat/solver_vec.h b/src/sat/asat/solver_vec.h
new file mode 100644
index 00000000..fae313d0
--- /dev/null
+++ b/src/sat/asat/solver_vec.h
@@ -0,0 +1,53 @@
+/**************************************************************************************************
+MiniSat -- Copyright (c) 2005, Niklas Sorensson
+http://www.cs.chalmers.se/Cs/Research/FormalMethods/MiniSat/
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+**************************************************************************************************/
+// Modified to compile with MS Visual Studio 6.0 by Alan Mishchenko
+
+#ifndef vec_h
+#define vec_h
+
+#include <stdlib.h>
+
+struct vec_t {
+ int size;
+ int cap;
+ void** ptr;
+};
+typedef struct vec_t vec;
+
+static inline void vec_new (vec* v) {
+ v->size = 0;
+ v->cap = 4;
+ v->ptr = (void**)malloc(sizeof(void*)*v->cap);
+}
+
+static inline void vec_delete (vec* v) { free(v->ptr); }
+static inline void** vec_begin (vec* v) { return v->ptr; }
+static inline int vec_size (vec* v) { return v->size; }
+static inline void vec_resize (vec* v, int k) { v->size = k; } // only safe to shrink !!
+static inline void vec_push (vec* v, void* e)
+{
+ if (v->size == v->cap) {
+ int newsize = v->cap * 2+1;
+ v->ptr = (void**)realloc(v->ptr,sizeof(void*)*newsize);
+ v->cap = newsize; }
+ v->ptr[v->size++] = e;
+}
+
+#endif
diff --git a/src/sat/fraig/fraig.h b/src/sat/fraig/fraig.h
new file mode 100644
index 00000000..53a46584
--- /dev/null
+++ b/src/sat/fraig/fraig.h
@@ -0,0 +1,194 @@
+/**CFile****************************************************************
+
+ FileName [fraig.h]
+
+ PackageName [FRAIG: Functionally reduced AND-INV graphs.]
+
+ Synopsis [External declarations of the FRAIG package.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - October 1, 2004]
+
+ Revision [$Id: fraig.h,v 1.18 2005/07/08 01:01:30 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __FRAIG_H__
+#define __FRAIG_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct Fraig_ManStruct_t_ Fraig_Man_t;
+typedef struct Fraig_NodeStruct_t_ Fraig_Node_t;
+typedef struct Fraig_NodeVecStruct_t_ Fraig_NodeVec_t;
+typedef struct Fraig_HashTableStruct_t_ Fraig_HashTable_t;
+typedef struct Fraig_ParamsStruct_t_ Fraig_Params_t;
+
+struct Fraig_ParamsStruct_t_
+{
+ int nPatsRand; // the number of words of random simulation info
+ int nPatsDyna; // the number of words of dynamic simulation info
+ int nBTLimit; // the max number of backtracks to perform
+ int fFuncRed; // performs only one level hashing
+ int fFeedBack; // enables solver feedback
+ int fDist1Pats; // enables distance-1 patterns
+ int fDoSparse; // performs equiv tests for sparse functions
+ int fChoicing; // enables recording structural choices
+ int fTryProve; // tries to solve the final miter
+ int fVerbose; // the verbosiness flag
+ int fVerboseP; // the verbosiness flag (for proof reporting)
+};
+
+////////////////////////////////////////////////////////////////////////
+/// GLOBAL VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// macros working with complemented attributes of the nodes
+#define Fraig_IsComplement(p) (((int)((long) (p) & 01)))
+#define Fraig_Regular(p) ((Fraig_Node_t *)((unsigned)(p) & ~01))
+#define Fraig_Not(p) ((Fraig_Node_t *)((long)(p) ^ 01))
+#define Fraig_NotCond(p,c) ((Fraig_Node_t *)((long)(p) ^ (c)))
+
+// these are currently not used
+#define Fraig_Ref(p)
+#define Fraig_Deref(p)
+#define Fraig_RecursiveDeref(p,c)
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== fraigApi.c =============================================================*/
+extern Fraig_NodeVec_t * Fraig_ManReadVecInputs( Fraig_Man_t * p );
+extern Fraig_NodeVec_t * Fraig_ManReadVecOutputs( Fraig_Man_t * p );
+extern Fraig_NodeVec_t * Fraig_ManReadVecNodes( Fraig_Man_t * p );
+extern Fraig_Node_t ** Fraig_ManReadInputs ( Fraig_Man_t * p );
+extern Fraig_Node_t ** Fraig_ManReadOutputs( Fraig_Man_t * p );
+extern Fraig_Node_t ** Fraig_ManReadNodes( Fraig_Man_t * p );
+extern int Fraig_ManReadInputNum ( Fraig_Man_t * p );
+extern int Fraig_ManReadOutputNum( Fraig_Man_t * p );
+extern int Fraig_ManReadNodeNum( Fraig_Man_t * p );
+extern Fraig_Node_t * Fraig_ManReadConst1 ( Fraig_Man_t * p );
+extern Fraig_Node_t * Fraig_ManReadIthVar( Fraig_Man_t * p, int i );
+extern Fraig_Node_t * Fraig_ManReadIthNode( Fraig_Man_t * p, int i );
+extern char ** Fraig_ManReadInputNames( Fraig_Man_t * p );
+extern char ** Fraig_ManReadOutputNames( Fraig_Man_t * p );
+extern char * Fraig_ManReadVarsInt( Fraig_Man_t * p );
+extern char * Fraig_ManReadSat( Fraig_Man_t * p );
+extern int Fraig_ManReadFuncRed( Fraig_Man_t * p );
+extern int Fraig_ManReadFeedBack( Fraig_Man_t * p );
+extern int Fraig_ManReadDoSparse( Fraig_Man_t * p );
+extern int Fraig_ManReadChoicing( Fraig_Man_t * p );
+extern int Fraig_ManReadVerbose( Fraig_Man_t * p );
+
+extern void Fraig_ManSetFuncRed( Fraig_Man_t * p, int fFuncRed );
+extern void Fraig_ManSetFeedBack( Fraig_Man_t * p, int fFeedBack );
+extern void Fraig_ManSetDoSparse( Fraig_Man_t * p, int fDoSparse );
+extern void Fraig_ManSetChoicing( Fraig_Man_t * p, int fChoicing );
+extern void Fraig_ManSetTryProve( Fraig_Man_t * p, int fTryProve );
+extern void Fraig_ManSetVerbose( Fraig_Man_t * p, int fVerbose );
+extern void Fraig_ManSetTimeToGraph( Fraig_Man_t * p, int Time );
+extern void Fraig_ManSetTimeToNet( Fraig_Man_t * p, int Time );
+extern void Fraig_ManSetTimeTotal( Fraig_Man_t * p, int Time );
+extern void Fraig_ManSetOutputNames( Fraig_Man_t * p, char ** ppNames );
+extern void Fraig_ManSetInputNames( Fraig_Man_t * p, char ** ppNames );
+extern void Fraig_ManSetPo( Fraig_Man_t * p, Fraig_Node_t * pNode );
+
+extern Fraig_Node_t * Fraig_NodeReadData0( Fraig_Node_t * p );
+extern Fraig_Node_t * Fraig_NodeReadData1( Fraig_Node_t * p );
+extern int Fraig_NodeReadNum( Fraig_Node_t * p );
+extern Fraig_Node_t * Fraig_NodeReadOne( Fraig_Node_t * p );
+extern Fraig_Node_t * Fraig_NodeReadTwo( Fraig_Node_t * p );
+extern Fraig_Node_t * Fraig_NodeReadNextE( Fraig_Node_t * p );
+extern Fraig_Node_t * Fraig_NodeReadRepr( Fraig_Node_t * p );
+extern int Fraig_NodeReadNumRefs( Fraig_Node_t * p );
+extern int Fraig_NodeReadNumFanouts( Fraig_Node_t * p );
+extern int Fraig_NodeReadSimInv( Fraig_Node_t * p );
+extern int Fraig_NodeReadNumOnes( Fraig_Node_t * p );
+
+extern void Fraig_NodeSetData0( Fraig_Node_t * p, Fraig_Node_t * pData );
+extern void Fraig_NodeSetData1( Fraig_Node_t * p, Fraig_Node_t * pData );
+
+extern int Fraig_NodeIsConst( Fraig_Node_t * p );
+extern int Fraig_NodeIsVar( Fraig_Node_t * p );
+extern int Fraig_NodeIsAnd( Fraig_Node_t * p );
+extern int Fraig_NodeComparePhase( Fraig_Node_t * p1, Fraig_Node_t * p2 );
+
+extern Fraig_Node_t * Fraig_NodeOr( Fraig_Man_t * p, Fraig_Node_t * p1, Fraig_Node_t * p2 );
+extern Fraig_Node_t * Fraig_NodeAnd( Fraig_Man_t * p, Fraig_Node_t * p1, Fraig_Node_t * p2 );
+extern Fraig_Node_t * Fraig_NodeOr( Fraig_Man_t * p, Fraig_Node_t * p1, Fraig_Node_t * p2 );
+extern Fraig_Node_t * Fraig_NodeExor( Fraig_Man_t * p, Fraig_Node_t * p1, Fraig_Node_t * p2 );
+extern Fraig_Node_t * Fraig_NodeMux( Fraig_Man_t * p, Fraig_Node_t * pNode, Fraig_Node_t * pNodeT, Fraig_Node_t * pNodeE );
+extern void Fraig_NodeSetChoice( Fraig_Man_t * pMan, Fraig_Node_t * pNodeOld, Fraig_Node_t * pNodeNew );
+
+/*=== fraigMan.c =============================================================*/
+extern void Fraig_ParamsSetDefault( Fraig_Params_t * pParams );
+extern Fraig_Man_t * Fraig_ManCreate( Fraig_Params_t * pParams );
+extern void Fraig_ManFree( Fraig_Man_t * pMan );
+extern void Fraig_ManPrintStats( Fraig_Man_t * p );
+
+/*=== fraigDfs.c =============================================================*/
+extern Fraig_NodeVec_t * Fraig_Dfs( Fraig_Man_t * pMan, int fEquiv );
+extern Fraig_NodeVec_t * Fraig_DfsOne( Fraig_Man_t * pMan, Fraig_Node_t * pNode, int fEquiv );
+extern Fraig_NodeVec_t * Fraig_DfsNodes( Fraig_Man_t * pMan, Fraig_Node_t ** ppNodes, int nNodes, int fEquiv );
+extern Fraig_NodeVec_t * Fraig_DfsReverse( Fraig_Man_t * pMan );
+extern int Fraig_CountNodes( Fraig_Man_t * pMan, int fEquiv );
+extern int Fraig_CheckTfi( Fraig_Man_t * pMan, Fraig_Node_t * pOld, Fraig_Node_t * pNew );
+extern int Fraig_CountLevels( Fraig_Man_t * pMan );
+
+/*=== fraigSat.c =============================================================*/
+extern int Fraig_NodesAreEqual( Fraig_Man_t * p, Fraig_Node_t * pNode1, Fraig_Node_t * pNode2, int nBTLimit );
+extern int Fraig_NodeIsEquivalent( Fraig_Man_t * p, Fraig_Node_t * pOld, Fraig_Node_t * pNew, int nBTLimit );
+extern void Fraig_ManProveMiter( Fraig_Man_t * p );
+
+/*=== fraigVec.c ===============================================================*/
+extern Fraig_NodeVec_t * Fraig_NodeVecAlloc( int nCap );
+extern void Fraig_NodeVecFree( Fraig_NodeVec_t * p );
+extern Fraig_NodeVec_t * Fraig_NodeVecDup( Fraig_NodeVec_t * p );
+extern Fraig_Node_t ** Fraig_NodeVecReadArray( Fraig_NodeVec_t * p );
+extern int Fraig_NodeVecReadSize( Fraig_NodeVec_t * p );
+extern void Fraig_NodeVecGrow( Fraig_NodeVec_t * p, int nCapMin );
+extern void Fraig_NodeVecShrink( Fraig_NodeVec_t * p, int nSizeNew );
+extern void Fraig_NodeVecClear( Fraig_NodeVec_t * p );
+extern void Fraig_NodeVecPush( Fraig_NodeVec_t * p, Fraig_Node_t * Entry );
+extern int Fraig_NodeVecPushUnique( Fraig_NodeVec_t * p, Fraig_Node_t * Entry );
+extern void Fraig_NodeVecPushOrder( Fraig_NodeVec_t * p, Fraig_Node_t * pNode );
+extern int Fraig_NodeVecPushUniqueOrder( Fraig_NodeVec_t * p, Fraig_Node_t * pNode );
+extern void Fraig_NodeVecPushOrderByLevel( Fraig_NodeVec_t * p, Fraig_Node_t * pNode );
+extern int Fraig_NodeVecPushUniqueOrderByLevel( Fraig_NodeVec_t * p, Fraig_Node_t * pNode );
+extern Fraig_Node_t * Fraig_NodeVecPop( Fraig_NodeVec_t * p );
+extern void Fraig_NodeVecRemove( Fraig_NodeVec_t * p, Fraig_Node_t * Entry );
+extern void Fraig_NodeVecWriteEntry( Fraig_NodeVec_t * p, int i, Fraig_Node_t * Entry );
+extern Fraig_Node_t * Fraig_NodeVecReadEntry( Fraig_NodeVec_t * p, int i );
+extern void Fraig_NodeVecSortByLevel( Fraig_NodeVec_t * p, int fIncreasing );
+extern void Fraig_NodeVecSortByNumber( Fraig_NodeVec_t * p );
+
+/*=== fraigUtil.c ===============================================================*/
+extern void Fraig_ManMarkRealFanouts( Fraig_Man_t * p );
+extern int Fraig_ManCheckConsistency( Fraig_Man_t * p );
+extern int Fraig_GetMaxLevel( Fraig_Man_t * pMan );
+extern void Fraig_ManReportChoices( Fraig_Man_t * pMan );
+extern void Fraig_MappingSetChoiceLevels( Fraig_Man_t * pMan, int fMaximum );
+extern Fraig_NodeVec_t * Fraig_CollectSupergate( Fraig_Node_t * pNode, int fStopAtMux );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+#endif
diff --git a/src/sat/fraig/fraigApi.c b/src/sat/fraig/fraigApi.c
new file mode 100644
index 00000000..d60c7168
--- /dev/null
+++ b/src/sat/fraig/fraigApi.c
@@ -0,0 +1,280 @@
+/**CFile****************************************************************
+
+ FileName [fraigAccess.c]
+
+ PackageName [FRAIG: Functionally reduced AND-INV graphs.]
+
+ Synopsis [Access APIs for the FRAIG manager and node.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - October 1, 2004]
+
+ Revision [$Id: fraigApi.c,v 1.2 2005/07/08 01:01:30 alanmi Exp $]
+
+***********************************************************************/
+
+#include "fraigInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Access functions to read the data members of the manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_NodeVec_t * Fraig_ManReadVecInputs( Fraig_Man_t * p ) { return p->vInputs; }
+Fraig_NodeVec_t * Fraig_ManReadVecOutputs( Fraig_Man_t * p ) { return p->vOutputs; }
+Fraig_NodeVec_t * Fraig_ManReadVecNodes( Fraig_Man_t * p ) { return p->vNodes; }
+Fraig_Node_t ** Fraig_ManReadInputs ( Fraig_Man_t * p ) { return p->vInputs->pArray; }
+Fraig_Node_t ** Fraig_ManReadOutputs( Fraig_Man_t * p ) { return p->vOutputs->pArray; }
+Fraig_Node_t ** Fraig_ManReadNodes( Fraig_Man_t * p ) { return p->vNodes->pArray; }
+int Fraig_ManReadInputNum ( Fraig_Man_t * p ) { return p->vInputs->nSize; }
+int Fraig_ManReadOutputNum( Fraig_Man_t * p ) { return p->vOutputs->nSize; }
+int Fraig_ManReadNodeNum( Fraig_Man_t * p ) { return p->vNodes->nSize; }
+Fraig_Node_t * Fraig_ManReadConst1 ( Fraig_Man_t * p ) { return p->pConst1; }
+Fraig_Node_t * Fraig_ManReadIthNode( Fraig_Man_t * p, int i ) { assert ( i < p->vNodes->nSize ); return p->vNodes->pArray[i]; }
+char ** Fraig_ManReadInputNames( Fraig_Man_t * p ) { return p->ppInputNames; }
+char ** Fraig_ManReadOutputNames( Fraig_Man_t * p ) { return p->ppOutputNames; }
+char * Fraig_ManReadVarsInt( Fraig_Man_t * p ) { return (char *)p->vVarsInt; }
+char * Fraig_ManReadSat( Fraig_Man_t * p ) { return (char *)p->pSat; }
+int Fraig_ManReadFuncRed( Fraig_Man_t * p ) { return p->fFuncRed; }
+int Fraig_ManReadFeedBack( Fraig_Man_t * p ) { return p->fFeedBack; }
+int Fraig_ManReadDoSparse( Fraig_Man_t * p ) { return p->fDoSparse; }
+int Fraig_ManReadChoicing( Fraig_Man_t * p ) { return p->fChoicing; }
+int Fraig_ManReadVerbose( Fraig_Man_t * p ) { return p->fVerbose; }
+
+/**Function*************************************************************
+
+ Synopsis [Access functions to set the data members of the manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_ManSetFuncRed( Fraig_Man_t * p, int fFuncRed ) { p->fFuncRed = fFuncRed; }
+void Fraig_ManSetFeedBack( Fraig_Man_t * p, int fFeedBack ) { p->fFeedBack = fFeedBack; }
+void Fraig_ManSetDoSparse( Fraig_Man_t * p, int fDoSparse ) { p->fDoSparse = fDoSparse; }
+void Fraig_ManSetChoicing( Fraig_Man_t * p, int fChoicing ) { p->fChoicing = fChoicing; }
+void Fraig_ManSetTryProve( Fraig_Man_t * p, int fTryProve ) { p->fTryProve = fTryProve; }
+void Fraig_ManSetVerbose( Fraig_Man_t * p, int fVerbose ) { p->fVerbose = fVerbose; }
+void Fraig_ManSetTimeToGraph( Fraig_Man_t * p, int Time ) { p->timeToAig = Time; }
+void Fraig_ManSetTimeToNet( Fraig_Man_t * p, int Time ) { p->timeToNet = Time; }
+void Fraig_ManSetTimeTotal( Fraig_Man_t * p, int Time ) { p->timeTotal = Time; }
+void Fraig_ManSetOutputNames( Fraig_Man_t * p, char ** ppNames ) { p->ppOutputNames = ppNames; }
+void Fraig_ManSetInputNames( Fraig_Man_t * p, char ** ppNames ) { p->ppInputNames = ppNames; }
+
+/**Function*************************************************************
+
+ Synopsis [Access functions to read the data members of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_Node_t * Fraig_NodeReadData0( Fraig_Node_t * p ) { return p->pData0; }
+Fraig_Node_t * Fraig_NodeReadData1( Fraig_Node_t * p ) { return p->pData1; }
+int Fraig_NodeReadNum( Fraig_Node_t * p ) { return p->Num; }
+Fraig_Node_t * Fraig_NodeReadOne( Fraig_Node_t * p ) { assert (!Fraig_IsComplement(p)); return p->p1; }
+Fraig_Node_t * Fraig_NodeReadTwo( Fraig_Node_t * p ) { assert (!Fraig_IsComplement(p)); return p->p2; }
+Fraig_Node_t * Fraig_NodeReadNextE( Fraig_Node_t * p ) { return p->pNextE; }
+Fraig_Node_t * Fraig_NodeReadRepr( Fraig_Node_t * p ) { return p->pRepr; }
+int Fraig_NodeReadNumRefs( Fraig_Node_t * p ) { return p->nRefs; }
+int Fraig_NodeReadNumFanouts( Fraig_Node_t * p ) { return p->nFanouts; }
+int Fraig_NodeReadSimInv( Fraig_Node_t * p ) { return p->fInv; }
+int Fraig_NodeReadNumOnes( Fraig_Node_t * p ) { return p->nOnes; }
+
+/**Function*************************************************************
+
+ Synopsis [Access functions to set the data members of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_NodeSetData0( Fraig_Node_t * p, Fraig_Node_t * pData ) { p->pData0 = pData; }
+void Fraig_NodeSetData1( Fraig_Node_t * p, Fraig_Node_t * pData ) { p->pData1 = pData; }
+
+/**Function*************************************************************
+
+ Synopsis [Checks the type of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_NodeIsConst( Fraig_Node_t * p ) { return (Fraig_Regular(p))->Num == 0; }
+int Fraig_NodeIsVar( Fraig_Node_t * p ) { return (Fraig_Regular(p))->NumPi >= 0; }
+int Fraig_NodeIsAnd( Fraig_Node_t * p ) { return (Fraig_Regular(p))->NumPi < 0 && (Fraig_Regular(p))->Num > 0; }
+int Fraig_NodeComparePhase( Fraig_Node_t * p1, Fraig_Node_t * p2 ) { assert( !Fraig_IsComplement(p1) ); assert( !Fraig_IsComplement(p2) ); return p1->fInv ^ p2->fInv; }
+
+/**Function*************************************************************
+
+ Synopsis [Returns a new primary input node.]
+
+ Description [If the node with this number does not exist,
+ create a new PI node with this number.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_Node_t * Fraig_ManReadIthVar( Fraig_Man_t * p, int i )
+{
+ int k;
+ if ( i < 0 )
+ {
+ printf( "Requesting a PI with a negative number\n" );
+ return NULL;
+ }
+ // create the PIs to fill in the interval
+ if ( i >= p->vInputs->nSize )
+ for ( k = p->vInputs->nSize; k <= i; k++ )
+ Fraig_NodeCreatePi( p );
+ return p->vInputs->pArray[i];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates a new node.]
+
+ Description [This procedure should be called to create the constant
+ node and the PI nodes first.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_ManSetPo( Fraig_Man_t * p, Fraig_Node_t * pNode )
+{
+// assert( pNode->fNodePo == 0 );
+ // internal node may be a PO two times
+ pNode->fNodePo = 1;
+ Fraig_NodeVecPush( p->vOutputs, pNode );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Perfoms the AND operation with functional hashing.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_Node_t * Fraig_NodeAnd( Fraig_Man_t * p, Fraig_Node_t * p1, Fraig_Node_t * p2 )
+{
+ return Fraig_NodeAndCanon( p, p1, p2 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Perfoms the OR operation with functional hashing.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_Node_t * Fraig_NodeOr( Fraig_Man_t * p, Fraig_Node_t * p1, Fraig_Node_t * p2 )
+{
+ return Fraig_Not( Fraig_NodeAndCanon( p, Fraig_Not(p1), Fraig_Not(p2) ) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Perfoms the EXOR operation with functional hashing.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_Node_t * Fraig_NodeExor( Fraig_Man_t * p, Fraig_Node_t * p1, Fraig_Node_t * p2 )
+{
+ return Fraig_NodeMux( p, p1, Fraig_Not(p2), p2 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Perfoms the MUX operation with functional hashing.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_Node_t * Fraig_NodeMux( Fraig_Man_t * p, Fraig_Node_t * pC, Fraig_Node_t * pT, Fraig_Node_t * pE )
+{
+ Fraig_Node_t * pAnd1, * pAnd2, * pRes;
+ pAnd1 = Fraig_NodeAndCanon( p, pC, pT ); Fraig_Ref( pAnd1 );
+ pAnd2 = Fraig_NodeAndCanon( p, Fraig_Not(pC), pE ); Fraig_Ref( pAnd2 );
+ pRes = Fraig_NodeOr( p, pAnd1, pAnd2 );
+ Fraig_RecursiveDeref( p, pAnd1 );
+ Fraig_RecursiveDeref( p, pAnd2 );
+ Fraig_Deref( pRes );
+ return pRes;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Sets the node to be equivalent to the given one.]
+
+ Description [This procedure is a work-around for the equivalence check.
+ Does not verify the equivalence. Use at the user's risk.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_NodeSetChoice( Fraig_Man_t * pMan, Fraig_Node_t * pNodeOld, Fraig_Node_t * pNodeNew )
+{
+// assert( pMan->fChoicing );
+ pNodeNew->pNextE = pNodeOld->pNextE;
+ pNodeOld->pNextE = pNodeNew;
+ pNodeNew->pRepr = pNodeOld;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sat/fraig/fraigCanon.c b/src/sat/fraig/fraigCanon.c
new file mode 100644
index 00000000..ae20531d
--- /dev/null
+++ b/src/sat/fraig/fraigCanon.c
@@ -0,0 +1,216 @@
+/**CFile****************************************************************
+
+ FileName [fraigAnd.c]
+
+ PackageName [FRAIG: Functionally reduced AND-INV graphs.]
+
+ Synopsis [AND-node creation and elementary AND-operation.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - October 1, 2004]
+
+ Revision [$Id: fraigCanon.c,v 1.4 2005/07/08 01:01:31 alanmi Exp $]
+
+***********************************************************************/
+
+#include <limits.h>
+#include "fraigInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [The internal AND operation for the two FRAIG nodes.]
+
+ Description [This procedure is the core of the FRAIG package, because
+ it performs the two-step canonicization of FRAIG nodes. The first step
+ involves the lookup in the structural hash table (which hashes two ANDs
+ into a node that has them as fanins, if such a node exists). If the node
+ is not found in the structural hash table, an attempt is made to find a
+ functionally equivalent node in another hash table (which hashes the
+ simulation info into the nodes, which has this simulation info). Some
+ tricks used on the way are described in the comments to the code and
+ in the paper "FRAIGs: Functionally reduced AND-INV graphs".]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_Node_t * Fraig_NodeAndCanon( Fraig_Man_t * pMan, Fraig_Node_t * p1, Fraig_Node_t * p2 )
+{
+ Fraig_Node_t * pNodeNew, * pNodeOld, * pNodeRepr;
+ int RetValue;
+
+ // check for trivial cases
+ if ( p1 == p2 )
+ return p1;
+ if ( p1 == Fraig_Not(p2) )
+ return Fraig_Not(pMan->pConst1);
+ if ( Fraig_NodeIsConst(p1) )
+ {
+ if ( p1 == pMan->pConst1 )
+ return p2;
+ return Fraig_Not(pMan->pConst1);
+ }
+ if ( Fraig_NodeIsConst(p2) )
+ {
+ if ( p2 == pMan->pConst1 )
+ return p1;
+ return Fraig_Not(pMan->pConst1);
+ }
+
+ // check for less trivial cases
+ if ( Fraig_IsComplement(p1) )
+ {
+ if ( RetValue = Fraig_NodeIsInSupergate( Fraig_Regular(p1), p2 ) )
+ {
+ if ( RetValue == -1 )
+ pMan->nImplies0++;
+ else
+ pMan->nImplies1++;
+
+ if ( RetValue == -1 )
+ return p2;
+ }
+ }
+ else
+ {
+ if ( RetValue = Fraig_NodeIsInSupergate( p1, p2 ) )
+ {
+ if ( RetValue == 1 )
+ pMan->nSimplifies1++;
+ else
+ pMan->nSimplifies0++;
+
+ if ( RetValue == 1 )
+ return p1;
+ return Fraig_Not(pMan->pConst1);
+ }
+ }
+
+ if ( Fraig_IsComplement(p2) )
+ {
+ if ( RetValue = Fraig_NodeIsInSupergate( Fraig_Regular(p2), p1 ) )
+ {
+ if ( RetValue == -1 )
+ pMan->nImplies0++;
+ else
+ pMan->nImplies1++;
+
+ if ( RetValue == -1 )
+ return p1;
+ }
+ }
+ else
+ {
+ if ( RetValue = Fraig_NodeIsInSupergate( p2, p1 ) )
+ {
+ if ( RetValue == 1 )
+ pMan->nSimplifies1++;
+ else
+ pMan->nSimplifies0++;
+
+ if ( RetValue == 1 )
+ return p2;
+ return Fraig_Not(pMan->pConst1);
+ }
+ }
+
+ // perform level-one structural hashing
+ if ( Fraig_HashTableLookupS( pMan, p1, p2, &pNodeNew ) ) // the node with these children is found
+ {
+ // if the existent node is part of the cone of unused logic
+ // (that is logic feeding the node which is equivalent to the given node)
+ // return the canonical representative of this node
+ // determine the phase of the given node, with respect to its canonical form
+ pNodeRepr = Fraig_Regular(pNodeNew)->pRepr;
+ if ( pMan->fFuncRed && pNodeRepr )
+ return Fraig_NotCond( pNodeRepr, Fraig_IsComplement(pNodeNew) ^ Fraig_NodeComparePhase(Fraig_Regular(pNodeNew), pNodeRepr) );
+ // otherwise, the node is itself a canonical representative, return it
+ return pNodeNew;
+ }
+ // the same node is not found, but the new one is created
+
+ // if one level hashing is requested (without functionality hashing), return
+ if ( !pMan->fFuncRed )
+ return pNodeNew;
+
+ // check if the new node is unique using the simulation info
+ if ( pNodeNew->nOnes == 0 || pNodeNew->nOnes == (unsigned)pMan->nWordsRand * 32 )
+ {
+ pMan->nSatZeros++;
+ if ( !pMan->fDoSparse ) // if we do not do sparse functions, skip
+ return pNodeNew;
+ // check the sparse function simulation hash table
+ pNodeOld = Fraig_HashTableLookupF0( pMan, pNodeNew );
+ if ( pNodeOld == NULL ) // the node is unique (it is added to the table)
+ return pNodeNew;
+ }
+ else
+ {
+ // check the simulation hash table
+ pNodeOld = Fraig_HashTableLookupF( pMan, pNodeNew );
+ if ( pNodeOld == NULL ) // the node is unique
+ return pNodeNew;
+ }
+ assert( pNodeOld->pRepr == 0 );
+ // there is another node which looks the same according to simulation
+
+ // use SAT to resolve the ambiguity
+ if ( Fraig_NodeIsEquivalent( pMan, pNodeOld, pNodeNew, pMan->nBTLimit ) )
+ {
+ // set the node to be equivalent with this node
+ // to prevent loops, only set if the old node is not in the TFI of the new node
+ // the loop may happen in the following case: suppose
+ // NodeC = AND(NodeA, NodeB) and at the same time NodeA => NodeB
+ // in this case, NodeA and NodeC are functionally equivalent
+ // however, NodeA is a fanin of node NodeC (this leads to the loop)
+ // add the node to the list of equivalent nodes or dereference it
+ if ( pMan->fChoicing && !Fraig_CheckTfi( pMan, pNodeOld, pNodeNew ) )
+ {
+ // if the old node is not in the TFI of the new node and choicing
+ // is enabled, add the new node to the list of equivalent ones
+ pNodeNew->pNextE = pNodeOld->pNextE;
+ pNodeOld->pNextE = pNodeNew;
+ }
+ // set the canonical representative of this node
+ pNodeNew->pRepr = pNodeOld;
+ // return the equivalent node
+ return Fraig_NotCond( pNodeOld, Fraig_NodeComparePhase(pNodeOld, pNodeNew) );
+ }
+
+ // now we add another member to this simulation class
+ if ( pNodeNew->nOnes == 0 || pNodeNew->nOnes == (unsigned)pMan->nWordsRand * 32 )
+ {
+ Fraig_Node_t * pNodeTemp;
+ assert( pMan->fDoSparse );
+ pNodeTemp = Fraig_HashTableLookupF0( pMan, pNodeNew );
+// assert( pNodeTemp == NULL );
+// Fraig_HashTableInsertF0( pMan, pNodeNew );
+ }
+ else
+ {
+ pNodeNew->pNextD = pNodeOld->pNextD;
+ pNodeOld->pNextD = pNodeNew;
+ }
+ // return the new node
+ assert( pNodeNew->pRepr == 0 );
+ return pNodeNew;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sat/fraig/fraigFanout.c b/src/sat/fraig/fraigFanout.c
new file mode 100644
index 00000000..b44bacd7
--- /dev/null
+++ b/src/sat/fraig/fraigFanout.c
@@ -0,0 +1,175 @@
+/**CFile****************************************************************
+
+ FileName [fraigFanout.c]
+
+ PackageName [FRAIG: Functionally reduced AND-INV graphs.]
+
+ Synopsis [Procedures to manipulate fanouts of the FRAIG nodes.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - October 1, 2004]
+
+ Revision [$Id: fraigFanout.c,v 1.5 2005/07/08 01:01:31 alanmi Exp $]
+
+***********************************************************************/
+
+#include "fraigInt.h"
+
+#ifdef FRAIG_ENABLE_FANOUTS
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Add the fanout to the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_NodeAddFaninFanout( Fraig_Node_t * pFanin, Fraig_Node_t * pFanout )
+{
+ Fraig_Node_t * pPivot;
+
+ // pFanins is a fanin of pFanout
+ assert( !Fraig_IsComplement(pFanin) );
+ assert( !Fraig_IsComplement(pFanout) );
+ assert( Fraig_Regular(pFanout->p1) == pFanin || Fraig_Regular(pFanout->p2) == pFanin );
+
+ pPivot = pFanin->pFanPivot;
+ if ( pPivot == NULL )
+ {
+ pFanin->pFanPivot = pFanout;
+ return;
+ }
+
+ if ( Fraig_Regular(pPivot->p1) == pFanin )
+ {
+ if ( Fraig_Regular(pFanout->p1) == pFanin )
+ {
+ pFanout->pFanFanin1 = pPivot->pFanFanin1;
+ pPivot->pFanFanin1 = pFanout;
+ }
+ else // if ( Fraig_Regular(pFanout->p2) == pFanin )
+ {
+ pFanout->pFanFanin2 = pPivot->pFanFanin1;
+ pPivot->pFanFanin1 = pFanout;
+ }
+ }
+ else // if ( Fraig_Regular(pPivot->p2) == pFanin )
+ {
+ assert( Fraig_Regular(pPivot->p2) == pFanin );
+ if ( Fraig_Regular(pFanout->p1) == pFanin )
+ {
+ pFanout->pFanFanin1 = pPivot->pFanFanin2;
+ pPivot->pFanFanin2 = pFanout;
+ }
+ else // if ( Fraig_Regular(pFanout->p2) == pFanin )
+ {
+ pFanout->pFanFanin2 = pPivot->pFanFanin2;
+ pPivot->pFanFanin2 = pFanout;
+ }
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Add the fanout to the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_NodeRemoveFaninFanout( Fraig_Node_t * pFanin, Fraig_Node_t * pFanoutToRemove )
+{
+ Fraig_Node_t * pFanout, * pFanout2, ** ppFanList;
+ // start the linked list of fanouts
+ ppFanList = &pFanin->pFanPivot;
+ // go through the fanouts
+ Fraig_NodeForEachFanoutSafe( pFanin, pFanout, pFanout2 )
+ {
+ // skip the fanout-to-remove
+ if ( pFanout == pFanoutToRemove )
+ continue;
+ // add useful fanouts to the list
+ *ppFanList = pFanout;
+ ppFanList = Fraig_NodeReadNextFanoutPlace( pFanin, pFanout );
+ }
+ *ppFanList = NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Transfers fanout to a different node.]
+
+ Description [Assumes that the other node currently has no fanouts.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_NodeTransferFanout( Fraig_Node_t * pNodeFrom, Fraig_Node_t * pNodeTo )
+{
+ Fraig_Node_t * pFanout;
+ assert( pNodeTo->pFanPivot == NULL );
+ assert( pNodeTo->pFanFanin1 == NULL );
+ assert( pNodeTo->pFanFanin2 == NULL );
+ // go through the fanouts and update their fanins
+ Fraig_NodeForEachFanout( pNodeFrom, pFanout )
+ {
+ if ( Fraig_Regular(pFanout->p1) == pNodeFrom )
+ pFanout->p1 = Fraig_NotCond( pNodeTo, Fraig_IsComplement(pFanout->p1) );
+ else if ( Fraig_Regular(pFanout->p2) == pNodeFrom )
+ pFanout->p2 = Fraig_NotCond( pNodeTo, Fraig_IsComplement(pFanout->p2) );
+ }
+ // move the pointers
+ pNodeTo->pFanPivot = pNodeFrom->pFanPivot;
+ pNodeTo->pFanFanin1 = pNodeFrom->pFanFanin1;
+ pNodeTo->pFanFanin2 = pNodeFrom->pFanFanin2;
+ pNodeFrom->pFanPivot = NULL;
+ pNodeFrom->pFanFanin1 = NULL;
+ pNodeFrom->pFanFanin2 = NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the number of fanouts of a node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_NodeGetFanoutNum( Fraig_Node_t * pNode )
+{
+ Fraig_Node_t * pFanout;
+ int Counter = 0;
+ Fraig_NodeForEachFanout( pNode, pFanout )
+ Counter++;
+ return Counter;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/src/sat/fraig/fraigFeed.c b/src/sat/fraig/fraigFeed.c
new file mode 100644
index 00000000..0a950aba
--- /dev/null
+++ b/src/sat/fraig/fraigFeed.c
@@ -0,0 +1,772 @@
+/**CFile****************************************************************
+
+ FileName [fraigFeed.c]
+
+ PackageName [FRAIG: Functionally reduced AND-INV graphs.]
+
+ Synopsis [Procedures to support the solver feedback.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - October 1, 2004]
+
+ Revision [$Id: fraigFeed.c,v 1.8 2005/07/08 01:01:31 alanmi Exp $]
+
+***********************************************************************/
+
+#include "fraigInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Fraig_FeedBackPrepare( Fraig_Man_t * p, int * pModel, Msat_IntVec_t * vVars );
+static int Fraig_FeedBackInsert( Fraig_Man_t * p, int nVarsPi );
+static void Fraig_FeedBackVerify( Fraig_Man_t * p, Fraig_Node_t * pOld, Fraig_Node_t * pNew );
+
+static void Fraig_FeedBackCovering( Fraig_Man_t * p, Msat_IntVec_t * vPats );
+static Fraig_NodeVec_t * Fraig_FeedBackCoveringStart( Fraig_Man_t * pMan );
+static int Fraig_GetSmallestColumn( int * pHits, int nHits );
+static int Fraig_GetHittingPattern( unsigned * pSims, int nWords );
+static void Fraig_CancelCoveredColumns( Fraig_NodeVec_t * vColumns, int * pHits, int iPat );
+static void Fraig_FeedBackCheckTable( Fraig_Man_t * p );
+static void Fraig_FeedBackCheckTableF0( Fraig_Man_t * p );
+static void Fraig_ReallocateSimulationInfo( Fraig_Man_t * p );
+
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Initializes the feedback information.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_FeedBackInit( Fraig_Man_t * p )
+{
+ p->vCones = Fraig_NodeVecAlloc( 500 );
+ p->vPatsReal = Msat_IntVecAlloc( 1000 );
+ p->pSimsReal = (unsigned *)Fraig_MemFixedEntryFetch( p->mmSims );
+ memset( p->pSimsReal, 0, sizeof(unsigned) * p->nWordsDyna );
+ p->pSimsTemp = (unsigned *)Fraig_MemFixedEntryFetch( p->mmSims );
+ p->pSimsDiff = (unsigned *)Fraig_MemFixedEntryFetch( p->mmSims );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Processes the feedback from teh solver.]
+
+ Description [Array pModel gives the value of each variable in the SAT
+ solver. Array vVars is the array of integer numbers of variables
+ involves in this conflict.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_FeedBack( Fraig_Man_t * p, int * pModel, Msat_IntVec_t * vVars, Fraig_Node_t * pOld, Fraig_Node_t * pNew )
+{
+ int nVarsPi, nWords;
+ int i, clk = clock();
+
+ // get the number of PI vars in the feedback (also sets the PI values)
+ nVarsPi = Fraig_FeedBackPrepare( p, pModel, vVars );
+
+ // set the PI values
+ nWords = Fraig_FeedBackInsert( p, nVarsPi );
+ assert( p->iWordStart + nWords <= p->nWordsDyna );
+
+ // resimulates the words from p->iWordStart to iWordStop
+ for ( i = 1; i < p->vNodes->nSize; i++ )
+ if ( Fraig_NodeIsAnd(p->vNodes->pArray[i]) )
+ Fraig_NodeSimulate( p->vNodes->pArray[i], p->iWordStart, p->iWordStart + nWords, 0 );
+
+ if ( p->fDoSparse )
+ Fraig_TableRehashF0( p, 0 );
+
+ if ( !p->fChoicing )
+ Fraig_FeedBackVerify( p, pOld, pNew );
+
+ // if there is no room left, compress the patterns
+ if ( p->iWordStart + nWords == p->nWordsDyna )
+ p->iWordStart = Fraig_FeedBackCompress( p );
+ else // otherwise, update the starting word
+ p->iWordStart += nWords;
+
+p->timeFeed += clock() - clk;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Get the number and values of the PI variables.]
+
+ Description [Returns the number of PI variables involved in this feedback.
+ Fills in the internal presence and value data for the primary inputs.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_FeedBackPrepare( Fraig_Man_t * p, int * pModel, Msat_IntVec_t * vVars )
+{
+ Fraig_Node_t * pNode;
+ int i, nVars, nVarsPis, * pVars;
+
+ // clean the presence flag for all PIs
+ for ( i = 0; i < p->vInputs->nSize; i++ )
+ {
+ pNode = p->vInputs->pArray[i];
+ pNode->fFeedUse = 0;
+ }
+
+ // get the variables involved in the feedback
+ nVars = Msat_IntVecReadSize(vVars);
+ pVars = Msat_IntVecReadArray(vVars);
+
+ // set the values for the present variables
+ nVarsPis = 0;
+ for ( i = 0; i < nVars; i++ )
+ {
+ pNode = p->vNodes->pArray[ pVars[i] ];
+ if ( !Fraig_NodeIsVar(pNode) )
+ continue;
+ // set its value
+ pNode->fFeedUse = 1;
+ pNode->fFeedVal = !MSAT_LITSIGN(pModel[pVars[i]]);
+ nVarsPis++;
+ }
+ return nVarsPis;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Inserts the new simulation patterns.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_FeedBackInsert( Fraig_Man_t * p, int nVarsPi )
+{
+ Fraig_Node_t * pNode;
+ int nWords, iPatFlip, nPatFlipLimit, i, w;
+ int fUseNoPats = 0;
+ int fUse2Pats = 0;
+
+ // get the number of words
+ if ( fUse2Pats )
+ nWords = FRAIG_NUM_WORDS( 2 * nVarsPi + 1 );
+ else if ( fUseNoPats )
+ nWords = 1;
+ else
+ nWords = FRAIG_NUM_WORDS( nVarsPi + 1 );
+ // update the number of words if they do not fit into the simulation info
+ if ( nWords > p->nWordsDyna - p->iWordStart )
+ nWords = p->nWordsDyna - p->iWordStart;
+ // determine the bound on the flipping bit
+ nPatFlipLimit = nWords * 32 - 2;
+
+ // mark the real pattern
+ Msat_IntVecPush( p->vPatsReal, p->iWordStart * 32 );
+ // record the real pattern
+ Fraig_BitStringSetBit( p->pSimsReal, p->iWordStart * 32 );
+
+ // set the values at the PIs
+ iPatFlip = 1;
+ for ( i = 0; i < p->vInputs->nSize; i++ )
+ {
+ pNode = p->vInputs->pArray[i];
+ for ( w = p->iWordStart; w < p->iWordStart + nWords; w++ )
+ if ( !pNode->fFeedUse )
+ pNode->puSimD[w] = FRAIG_RANDOM_UNSIGNED;
+ else if ( pNode->fFeedVal )
+ pNode->puSimD[w] = FRAIG_FULL;
+ else // if ( !pNode->fFeedVal )
+ pNode->puSimD[w] = 0;
+
+ if ( fUse2Pats )
+ {
+ // flip two patterns
+ if ( pNode->fFeedUse && 2 * iPatFlip < nPatFlipLimit )
+ {
+ Fraig_BitStringXorBit( pNode->puSimD + p->iWordStart, 2 * iPatFlip - 1 );
+ Fraig_BitStringXorBit( pNode->puSimD + p->iWordStart, 2 * iPatFlip );
+ Fraig_BitStringXorBit( pNode->puSimD + p->iWordStart, 2 * iPatFlip + 1 );
+ iPatFlip++;
+ }
+ }
+ else if ( fUseNoPats )
+ {
+ }
+ else
+ {
+ // flip the diagonal
+ if ( pNode->fFeedUse && iPatFlip < nPatFlipLimit )
+ {
+ Fraig_BitStringXorBit( pNode->puSimD + p->iWordStart, iPatFlip );
+ iPatFlip++;
+ // Extra_PrintBinary( stdout, &pNode->puSimD, 45 ); printf( "\n" );
+ }
+ }
+ // clean the use mask
+ pNode->fFeedUse = 0;
+
+ // add the info to the D hash value of the PIs
+ for ( w = p->iWordStart; w < p->iWordStart + nWords; w++ )
+ pNode->uHashD ^= pNode->puSimD[w] * s_FraigPrimes[w];
+
+ }
+ return nWords;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Checks that the SAT solver pattern indeed distinquishes the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_FeedBackVerify( Fraig_Man_t * p, Fraig_Node_t * pOld, Fraig_Node_t * pNew )
+{
+ int fValue1, fValue2, iPat;
+ iPat = Msat_IntVecReadEntry( p->vPatsReal, Msat_IntVecReadSize(p->vPatsReal)-1 );
+ fValue1 = (Fraig_BitStringHasBit( pOld->puSimD, iPat ));
+ fValue2 = (Fraig_BitStringHasBit( pNew->puSimD, iPat ));
+/*
+Fraig_PrintNode( p, pOld );
+printf( "\n" );
+Fraig_PrintNode( p, pNew );
+printf( "\n" );
+*/
+// assert( fValue1 != fValue2 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compress the simulation patterns.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_FeedBackCompress( Fraig_Man_t * p )
+{
+ unsigned * pSims;
+ unsigned uHash;
+ int i, w, t, nPats, * pPats;
+ int fPerformChecks = (p->nBTLimit == -1);
+
+ // solve the covering problem
+ if ( fPerformChecks )
+ {
+ Fraig_FeedBackCheckTable( p );
+ if ( p->fDoSparse )
+ Fraig_FeedBackCheckTableF0( p );
+ }
+
+ // solve the covering problem
+ Fraig_FeedBackCovering( p, p->vPatsReal );
+
+
+ // get the number of additional patterns
+ nPats = Msat_IntVecReadSize( p->vPatsReal );
+ pPats = Msat_IntVecReadArray( p->vPatsReal );
+ // get the new starting word
+ p->iWordStart = FRAIG_NUM_WORDS( p->iPatsPerm + nPats );
+
+ // set the simulation info for the PIs
+ for ( i = 0; i < p->vInputs->nSize; i++ )
+ {
+ // get hold of the simulation info for this PI
+ pSims = p->vInputs->pArray[i]->puSimD;
+ // clean the storage for the new patterns
+ for ( w = p->iWordPerm; w < p->iWordStart; w++ )
+ p->pSimsTemp[w] = 0;
+ // set the patterns
+ for ( t = 0; t < nPats; t++ )
+ if ( Fraig_BitStringHasBit( pSims, pPats[t] ) )
+ {
+ // check if this pattern falls into temporary storage
+ if ( p->iPatsPerm + t < p->iWordPerm * 32 )
+ Fraig_BitStringSetBit( pSims, p->iPatsPerm + t );
+ else
+ Fraig_BitStringSetBit( p->pSimsTemp, p->iPatsPerm + t );
+ }
+ // copy the pattern
+ for ( w = p->iWordPerm; w < p->iWordStart; w++ )
+ pSims[w] = p->pSimsTemp[w];
+ // recompute the hashing info
+ uHash = 0;
+ for ( w = 0; w < p->iWordStart; w++ )
+ uHash ^= pSims[w] * s_FraigPrimes[w];
+ p->vInputs->pArray[i]->uHashD = uHash;
+ }
+
+ // update info about the permanently stored patterns
+ p->iWordPerm = p->iWordStart;
+ p->iPatsPerm += nPats;
+ assert( p->iWordPerm == FRAIG_NUM_WORDS( p->iPatsPerm ) );
+
+ // resimulate and recompute the hash values
+ for ( i = 1; i < p->vNodes->nSize; i++ )
+ if ( Fraig_NodeIsAnd(p->vNodes->pArray[i]) )
+ {
+ p->vNodes->pArray[i]->uHashD = 0;
+ Fraig_NodeSimulate( p->vNodes->pArray[i], 0, p->iWordPerm, 0 );
+ }
+
+ // double-check that the nodes are still distinguished
+ if ( fPerformChecks )
+ Fraig_FeedBackCheckTable( p );
+
+ // rehash the values in the F0 table
+ if ( p->fDoSparse )
+ {
+ Fraig_TableRehashF0( p, 0 );
+ if ( fPerformChecks )
+ Fraig_FeedBackCheckTableF0( p );
+ }
+
+ // check if we need to resize the simulation info
+ // if less than FRAIG_WORDS_STORE words are left, reallocate simulation info
+ if ( p->iWordPerm + FRAIG_WORDS_STORE > p->nWordsDyna )
+ Fraig_ReallocateSimulationInfo( p );
+
+ // set the real patterns
+ Msat_IntVecClear( p->vPatsReal );
+ memset( p->pSimsReal, 0, sizeof(unsigned)*p->nWordsDyna );
+ for ( w = 0; w < p->iWordPerm; w++ )
+ p->pSimsReal[w] = FRAIG_FULL;
+ if ( p->iPatsPerm % 32 > 0 )
+ p->pSimsReal[p->iWordPerm-1] = FRAIG_MASK( p->iPatsPerm % 32 );
+// printf( "The number of permanent words = %d.\n", p->iWordPerm );
+ return p->iWordStart;
+}
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Checks the correctness of the functional simulation table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_FeedBackCovering( Fraig_Man_t * p, Msat_IntVec_t * vPats )
+{
+ Fraig_NodeVec_t * vColumns;
+ unsigned * pSims;
+ int * pHits, iPat, iCol, i;
+ int nOnesTotal, nSolStarting;
+ int fVeryVerbose = 0;
+
+ // collect the pairs to be distinguished
+ vColumns = Fraig_FeedBackCoveringStart( p );
+ // collect the number of 1s in each simulation vector
+ nOnesTotal = 0;
+ pHits = ALLOC( int, vColumns->nSize );
+ for ( i = 0; i < vColumns->nSize; i++ )
+ {
+ pSims = (unsigned *)vColumns->pArray[i];
+ pHits[i] = Fraig_BitStringCountOnes( pSims, p->iWordStart );
+ nOnesTotal += pHits[i];
+// assert( pHits[i] > 0 );
+ }
+
+ // go through the patterns
+ nSolStarting = Msat_IntVecReadSize(vPats);
+ while ( (iCol = Fraig_GetSmallestColumn( pHits, vColumns->nSize )) != -1 )
+ {
+ // find the pattern, which hits this column
+ iPat = Fraig_GetHittingPattern( (unsigned *)vColumns->pArray[iCol], p->iWordStart );
+ // cancel the columns covered by this pattern
+ Fraig_CancelCoveredColumns( vColumns, pHits, iPat );
+ // save the pattern
+ Msat_IntVecPush( vPats, iPat );
+ }
+
+ // free the set of columns
+ for ( i = 0; i < vColumns->nSize; i++ )
+ Fraig_MemFixedEntryRecycle( p->mmSims, (char *)vColumns->pArray[i] );
+
+ // print stats related to the covering problem
+ if ( p->fVerbose && fVeryVerbose )
+ {
+ printf( "%3d\\%3d\\%3d ", p->nWordsRand, p->nWordsDyna, p->iWordPerm );
+ printf( "Col (pairs) = %5d. ", vColumns->nSize );
+ printf( "Row (pats) = %5d. ", p->iWordStart * 32 );
+ printf( "Dns = %6.2f %%. ", vColumns->nSize==0? 0.0 : 100.0 * nOnesTotal / vColumns->nSize / p->iWordStart / 32 );
+ printf( "Sol = %3d (%3d). ", Msat_IntVecReadSize(vPats), nSolStarting );
+ printf( "\n" );
+ }
+ Fraig_NodeVecFree( vColumns );
+ free( pHits );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Checks the correctness of the functional simulation table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_NodeVec_t * Fraig_FeedBackCoveringStart( Fraig_Man_t * p )
+{
+ Fraig_NodeVec_t * vColumns;
+ Fraig_HashTable_t * pT = p->pTableF;
+ Fraig_Node_t * pEntF, * pEntD;
+ unsigned * pSims;
+ unsigned * pUnsigned1, * pUnsigned2;
+ int i, k, m, w;//, nOnes;
+
+ // start the set of columns
+ vColumns = Fraig_NodeVecAlloc( 100 );
+
+ // go through the pairs of nodes to be distinguished
+ for ( i = 0; i < pT->nBins; i++ )
+ Fraig_TableBinForEachEntryF( pT->pBins[i], pEntF )
+ {
+ p->vCones->nSize = 0;
+ Fraig_TableBinForEachEntryD( pEntF, pEntD )
+ Fraig_NodeVecPush( p->vCones, pEntD );
+ if ( p->vCones->nSize == 1 )
+ continue;
+
+ for ( k = 0; k < p->vCones->nSize; k++ )
+ for ( m = k+1; m < p->vCones->nSize; m++ )
+ {
+ if ( !Fraig_CompareSimInfoUnderMask( p->vCones->pArray[k], p->vCones->pArray[m], p->iWordStart, 0, p->pSimsReal ) )
+ continue;
+
+ // primary simulation patterns (counter-examples) cannot distinguish this pair
+ // get memory to store the feasible simulation patterns
+ pSims = (unsigned *)Fraig_MemFixedEntryFetch( p->mmSims );
+ // find the pattern that distinguish this column, exept the primary ones
+ pUnsigned1 = p->vCones->pArray[k]->puSimD;
+ pUnsigned2 = p->vCones->pArray[m]->puSimD;
+ for ( w = 0; w < p->iWordStart; w++ )
+ pSims[w] = (pUnsigned1[w] ^ pUnsigned2[w]) & ~p->pSimsReal[w];
+ // store the pattern
+ Fraig_NodeVecPush( vColumns, (Fraig_Node_t *)pSims );
+// nOnes = Fraig_BitStringCountOnes(pSims, p->iWordStart);
+// assert( nOnes > 0 );
+ }
+ }
+
+ // if the flag is not set, do not consider sparse nodes in p->pTableF0
+ if ( !p->fDoSparse )
+ return vColumns;
+
+ // recalculate their hash values based on p->pSimsReal
+ pT = p->pTableF0;
+ for ( i = 0; i < pT->nBins; i++ )
+ Fraig_TableBinForEachEntryF( pT->pBins[i], pEntF )
+ {
+ pSims = pEntF->puSimD;
+ pEntF->uHashD = 0;
+ for ( w = 0; w < p->iWordStart; w++ )
+ pEntF->uHashD ^= (pSims[w] & p->pSimsReal[w]) * s_FraigPrimes[w];
+ }
+
+ // rehash the table using these values
+ Fraig_TableRehashF0( p, 1 );
+
+ // collect the classes of equivalent node pairs
+ for ( i = 0; i < pT->nBins; i++ )
+ Fraig_TableBinForEachEntryF( pT->pBins[i], pEntF )
+ {
+ p->vCones->nSize = 0;
+ Fraig_TableBinForEachEntryD( pEntF, pEntD )
+ Fraig_NodeVecPush( p->vCones, pEntD );
+ if ( p->vCones->nSize == 1 )
+ continue;
+
+ // primary simulation patterns (counter-examples) cannot distinguish all these pairs
+ for ( k = 0; k < p->vCones->nSize; k++ )
+ for ( m = k+1; m < p->vCones->nSize; m++ )
+ {
+ // get memory to store the feasible simulation patterns
+ pSims = (unsigned *)Fraig_MemFixedEntryFetch( p->mmSims );
+ // find the patterns that are not distinquished
+ pUnsigned1 = p->vCones->pArray[k]->puSimD;
+ pUnsigned2 = p->vCones->pArray[m]->puSimD;
+ for ( w = 0; w < p->iWordStart; w++ )
+ pSims[w] = (pUnsigned1[w] ^ pUnsigned2[w]) & ~p->pSimsReal[w];
+ // store the pattern
+ Fraig_NodeVecPush( vColumns, (Fraig_Node_t *)pSims );
+// nOnes = Fraig_BitStringCountOnes(pSims, p->iWordStart);
+// assert( nOnes > 0 );
+ }
+ }
+ return vColumns;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Selects the column, which has the smallest number of hits.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_GetSmallestColumn( int * pHits, int nHits )
+{
+ int i, iColMin = -1, nHitsMin = 1000000;
+ for ( i = 0; i < nHits; i++ )
+ {
+ // skip covered columns
+ if ( pHits[i] == 0 )
+ continue;
+ // take the column if it can only be covered by one pattern
+ if ( pHits[i] == 1 )
+ return i;
+ // find the column, which requires the smallest number of patterns
+ if ( nHitsMin > pHits[i] )
+ {
+ nHitsMin = pHits[i];
+ iColMin = i;
+ }
+ }
+ return iColMin;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Select the pattern, which hits this column.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_GetHittingPattern( unsigned * pSims, int nWords )
+{
+ int i, b;
+ for ( i = 0; i < nWords; i++ )
+ {
+ if ( pSims[i] == 0 )
+ continue;
+ for ( b = 0; b < 32; b++ )
+ if ( pSims[i] & (1 << b) )
+ return i * 32 + b;
+ }
+ return -1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Cancel covered patterns.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_CancelCoveredColumns( Fraig_NodeVec_t * vColumns, int * pHits, int iPat )
+{
+ unsigned * pSims;
+ int i;
+ for ( i = 0; i < vColumns->nSize; i++ )
+ {
+ pSims = (unsigned *)vColumns->pArray[i];
+ if ( Fraig_BitStringHasBit( pSims, iPat ) )
+ pHits[i] = 0;
+ }
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Checks the correctness of the functional simulation table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_FeedBackCheckTable( Fraig_Man_t * p )
+{
+ Fraig_HashTable_t * pT = p->pTableF;
+ Fraig_Node_t * pEntF, * pEntD;
+ int i, k, m, nPairs;
+ int clk = clock();
+
+ nPairs = 0;
+ for ( i = 0; i < pT->nBins; i++ )
+ Fraig_TableBinForEachEntryF( pT->pBins[i], pEntF )
+ {
+ p->vCones->nSize = 0;
+ Fraig_TableBinForEachEntryD( pEntF, pEntD )
+ Fraig_NodeVecPush( p->vCones, pEntD );
+ if ( p->vCones->nSize == 1 )
+ continue;
+ for ( k = 0; k < p->vCones->nSize; k++ )
+ for ( m = k+1; m < p->vCones->nSize; m++ )
+ {
+ if ( Fraig_CompareSimInfo( p->vCones->pArray[k], p->vCones->pArray[m], p->iWordStart, 0 ) )
+ printf( "Nodes %d and %d have the same D simulation info.\n",
+ p->vCones->pArray[k]->Num, p->vCones->pArray[m]->Num );
+ nPairs++;
+ }
+ }
+// printf( "\nThe total of %d node pairs have been verified.\n", nPairs );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks the correctness of the functional simulation table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_FeedBackCheckTableF0( Fraig_Man_t * p )
+{
+ Fraig_HashTable_t * pT = p->pTableF0;
+ Fraig_Node_t * pEntF;
+ int i, k, m, nPairs;
+
+ nPairs = 0;
+ for ( i = 0; i < pT->nBins; i++ )
+ {
+ p->vCones->nSize = 0;
+ Fraig_TableBinForEachEntryF( pT->pBins[i], pEntF )
+ Fraig_NodeVecPush( p->vCones, pEntF );
+ if ( p->vCones->nSize == 1 )
+ continue;
+ for ( k = 0; k < p->vCones->nSize; k++ )
+ for ( m = k+1; m < p->vCones->nSize; m++ )
+ {
+ if ( Fraig_CompareSimInfo( p->vCones->pArray[k], p->vCones->pArray[m], p->iWordStart, 0 ) )
+ printf( "Nodes %d and %d have the same D simulation info.\n",
+ p->vCones->pArray[k]->Num, p->vCones->pArray[m]->Num );
+ nPairs++;
+ }
+ }
+// printf( "\nThe total of %d node pairs have been verified.\n", nPairs );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Doubles the size of simulation info.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_ReallocateSimulationInfo( Fraig_Man_t * p )
+{
+ Fraig_MemFixed_t * mmSimsNew; // new memory manager for simulation info
+ Fraig_Node_t * pNode;
+ unsigned * pSimsNew;
+ unsigned uSignOld;
+ int i;
+
+ // allocate a new memory manager
+ p->nWordsDyna *= 2;
+ mmSimsNew = Fraig_MemFixedStart( sizeof(unsigned) * (p->nWordsRand + p->nWordsDyna) );
+
+ // set the new data for the constant node
+ pNode = p->pConst1;
+ pNode->puSimR = (unsigned *)Fraig_MemFixedEntryFetch( mmSimsNew );
+ pNode->puSimD = pNode->puSimR + p->nWordsRand;
+ memset( pNode->puSimR, 0, sizeof(unsigned) * p->nWordsRand );
+ memset( pNode->puSimD, 0, sizeof(unsigned) * p->nWordsDyna );
+
+ // copy the simulation info of the PIs
+ for ( i = 0; i < p->vInputs->nSize; i++ )
+ {
+ pNode = p->vInputs->pArray[i];
+ // copy the simulation info
+ pSimsNew = (unsigned *)Fraig_MemFixedEntryFetch( mmSimsNew );
+ memmove( pSimsNew, pNode->puSimR, sizeof(unsigned) * (p->nWordsRand + p->iWordStart) );
+ // attach the new info
+ pNode->puSimR = pSimsNew;
+ pNode->puSimD = pNode->puSimR + p->nWordsRand;
+ // signatures remain without changes
+ }
+
+ // replace the manager to free up some memory
+ Fraig_MemFixedStop( p->mmSims, 0 );
+ p->mmSims = mmSimsNew;
+
+ // resimulate the internal nodes (this should lead to the same signatures)
+ for ( i = 1; i < p->vNodes->nSize; i++ )
+ {
+ pNode = p->vNodes->pArray[i];
+ if ( !Fraig_NodeIsAnd(pNode) )
+ continue;
+ // allocate memory for the simulation info
+ pNode->puSimR = (unsigned *)Fraig_MemFixedEntryFetch( mmSimsNew );
+ pNode->puSimD = pNode->puSimR + p->nWordsRand;
+ // derive random simulation info
+ uSignOld = pNode->uHashR;
+ pNode->uHashR = 0;
+ Fraig_NodeSimulate( pNode, 0, p->nWordsRand, 1 );
+ assert( uSignOld == pNode->uHashR );
+ // derive dynamic simulation info
+ uSignOld = pNode->uHashD;
+ pNode->uHashD = 0;
+ Fraig_NodeSimulate( pNode, 0, p->iWordStart, 0 );
+ assert( uSignOld == pNode->uHashD );
+ }
+
+ // realloc temporary storage
+ p->pSimsReal = (unsigned *)Fraig_MemFixedEntryFetch( mmSimsNew );
+ memset( p->pSimsReal, 0, sizeof(unsigned) * p->nWordsDyna );
+ p->pSimsTemp = (unsigned *)Fraig_MemFixedEntryFetch( mmSimsNew );
+ p->pSimsDiff = (unsigned *)Fraig_MemFixedEntryFetch( mmSimsNew );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sat/fraig/fraigInt.h b/src/sat/fraig/fraigInt.h
new file mode 100644
index 00000000..1139bdc0
--- /dev/null
+++ b/src/sat/fraig/fraigInt.h
@@ -0,0 +1,442 @@
+/**CFile****************************************************************
+
+ FileName [fraigInt.h]
+
+ PackageName [FRAIG: Functionally reduced AND-INV graphs.]
+
+ Synopsis [Internal declarations of the FRAIG package.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - October 1, 2004]
+
+ Revision [$Id: fraigInt.h,v 1.15 2005/07/08 01:01:31 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __FRAIG_INT_H__
+#define __FRAIG_INT_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+//#include "leaks.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <time.h>
+
+#include "fraig.h"
+#include "msat.h"
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+/*
+ The AIG node policy:
+ - Each node has its main number (pNode->Num)
+ This is the number of this node in the array of all nodes and its SAT variable number
+ - The PI nodes are stored along with other nodes
+ Additionally, PI nodes have a PI number, by which they are stored in the PI node array
+ - The constant node is has number 0 and is also stored in the array
+*/
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// enable this macro to support the fanouts
+#define FRAIG_ENABLE_FANOUTS
+#define FRAIG_PATTERNS_RANDOM 2048 // should not be less than 128 and more than 32768 (2^15)
+#define FRAIG_PATTERNS_DYNAMIC 2048 // should not be less than 256 and more than 32768 (2^15)
+#define FRAIG_MAX_PRIMES 1024 // the maximum number of primes used for hashing
+
+// this parameter determines when simulation info is extended
+// it will be extended when the free storage in the dynamic simulation
+// info is less or equal to this number of words (FRAIG_WORDS_STORE)
+// this is done because if the free storage for dynamic simulation info
+// is not sufficient, computation becomes inefficient
+#define FRAIG_WORDS_STORE 5
+
+// the bit masks
+#define FRAIG_MASK(n) ((~((unsigned)0)) >> (32-(n)))
+#define FRAIG_FULL (~((unsigned)0))
+#define FRAIG_NUM_WORDS(n) ((n)/32 + (((n)%32) > 0))
+
+// maximum/minimum operators
+#define FRAIG_MIN(a,b) (((a) < (b))? (a) : (b))
+#define FRAIG_MAX(a,b) (((a) > (b))? (a) : (b))
+
+// generating random unsigned (#define RAND_MAX 0x7fff)
+#define FRAIG_RANDOM_UNSIGNED ((((unsigned)rand()) << 24) ^ (((unsigned)rand()) << 12) ^ ((unsigned)rand()))
+
+// macros to get hold of the bits in a bit string
+#define Fraig_BitStringSetBit(p,i) ((p)[(i)>>5] |= (1<<((i) & 31)))
+#define Fraig_BitStringXorBit(p,i) ((p)[(i)>>5] ^= (1<<((i) & 31)))
+#define Fraig_BitStringHasBit(p,i) (((p)[(i)>>5] & (1<<((i) & 31))) > 0)
+
+// macros to get hold of the bits in the support info
+//#define Fraig_NodeSetVarStr(p,i) (Fraig_Regular(p)->pSuppStr[((i)%FRAIG_SUPP_SIGN)>>5] |= (1<<(((i)%FRAIG_SUPP_SIGN) & 31)))
+//#define Fraig_NodeHasVarStr(p,i) ((Fraig_Regular(p)->pSuppStr[((i)%FRAIG_SUPP_SIGN)>>5] & (1<<(((i)%FRAIG_SUPP_SIGN) & 31))) > 0)
+#define Fraig_NodeSetVarStr(p,i) Fraig_BitStringSetBit(Fraig_Regular(p)->pSuppStr,i)
+#define Fraig_NodeHasVarStr(p,i) Fraig_BitStringHasBit(Fraig_Regular(p)->pSuppStr,i)
+
+// copied from "util.h" for standaloneness
+#ifndef ALLOC
+# define ALLOC(type, num) \
+ ((type *) malloc(sizeof(type) * (num)))
+#endif
+
+#ifndef REALLOC
+# define REALLOC(type, obj, num) \
+ (obj) ? ((type *) realloc((char *) obj, sizeof(type) * (num))) : \
+ ((type *) malloc(sizeof(type) * (num)))
+#endif
+
+#ifndef FREE
+# define FREE(obj) \
+ ((obj) ? (free((char *) (obj)), (obj) = 0) : 0)
+#endif
+
+// copied from "extra.h" for stand-aloneness
+#define Fraig_PrintTime(a,t) printf( "%s = ", (a) ); printf( "%6.2f sec\n", (float)(t)/(float)(CLOCKS_PER_SEC) )
+
+#define Fraig_HashKey2(a,b,TSIZE) (((unsigned)(a) + (unsigned)(b) * 12582917) % TSIZE)
+//#define Fraig_HashKey2(a,b,TSIZE) (( ((unsigned)(a)->Num * 19) ^ ((unsigned)(b)->Num * 1999) ) % TSIZE)
+//#define Fraig_HashKey2(a,b,TSIZE) ( ((unsigned)((a)->Num + (b)->Num) * ((a)->Num + (b)->Num + 1) / 2) % TSIZE)
+// the other two hash functions give bad distribution of hash chain lengths (not clear why)
+
+#ifndef PRT
+#define PRT(a,t) printf( "%s = ", (a) ); printf( "%6.2f sec\n", (float)(t)/(float)(CLOCKS_PER_SEC) )
+#endif
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct Fraig_MemFixed_t_ Fraig_MemFixed_t;
+
+// the mapping manager
+struct Fraig_ManStruct_t_
+{
+ // the AIG nodes
+ Fraig_NodeVec_t * vInputs; // the array of primary inputs
+ Fraig_NodeVec_t * vNodes; // the array of all nodes, including primary inputs
+ Fraig_NodeVec_t * vOutputs; // the array of primary outputs (some internal nodes)
+ Fraig_Node_t * pConst1; // the pointer to the constant node (vNodes->pArray[0])
+
+ // info about the original circuit
+ char ** ppInputNames; // the primary input names
+ char ** ppOutputNames; // the primary output names
+
+ // various hash-tables
+ Fraig_HashTable_t * pTableS; // hashing by structure
+ Fraig_HashTable_t * pTableF; // hashing by simulation info
+ Fraig_HashTable_t * pTableF0; // hashing by simulation info (sparse functions)
+
+ // parameters
+ int nWordsRand; // the number of words of random simulation info
+ int nWordsDyna; // the number of words of dynamic simulation info
+ int nBTLimit; // the max number of backtracks to perform
+ int fFuncRed; // performs only one level hashing
+ int fFeedBack; // enables solver feedback
+ int fDist1Pats; // enables solver feedback
+ int fDoSparse; // performs equiv tests for sparse functions
+ int fChoicing; // enables recording structural choices
+ int fTryProve; // tries to solve the final miter
+ int fVerbose; // the verbosiness flag
+ int fVerboseP; // the verbosiness flag
+
+ int nTravIds; // the traversal counter
+ int nTravIds2; // the traversal counter
+
+ // info related to the solver feedback
+ int iWordStart; // the first word to use for simulation
+ int iWordPerm; // the number of words stored permanently
+ int iPatsPerm; // the number of patterns stored permanently
+ Fraig_NodeVec_t * vCones; // the temporary array of internal variables
+ Msat_IntVec_t * vPatsReal; // the array of real pattern numbers
+ unsigned * pSimsReal; // used for simulation patterns
+ unsigned * pSimsDiff; // used for simulation patterns
+ unsigned * pSimsTemp; // used for simulation patterns
+
+ // the support information
+ int nSuppWords;
+ unsigned ** pSuppS;
+ unsigned ** pSuppF;
+
+ // the memory managers
+ Fraig_MemFixed_t * mmNodes; // the memory manager for nodes
+ Fraig_MemFixed_t * mmSims; // the memory manager for simulation info
+
+ // solving the SAT problem
+ Msat_Solver_t * pSat; // the SAT solver
+ Msat_IntVec_t * vProj; // the temporary array of projection vars
+ int nSatNums; // the counter of SAT variables
+ // these arrays belong to the solver
+ Msat_IntVec_t * vVarsInt; // the temporary array of variables
+ Msat_ClauseVec_t * vAdjacents; // the temporary storage for connectivity
+ Msat_IntVec_t * vVarsUsed; // the array marking vars appearing in the cone
+
+ // various statistic variables
+ int nSatCalls; // the number of times equivalence checking was called
+ int nSatProof; // the number of times a proof was found
+ int nSatCounter; // the number of times a counter example was found
+ int nSatFails; // the number of times the SAT solver failed to complete
+
+ int nSatCallsImp; // the number of times equivalence checking was called
+ int nSatProofImp; // the number of times a proof was found
+ int nSatCounterImp;// the number of times a counter example was found
+ int nSatFailsImp; // the number of times the SAT solver failed to complete
+
+ int nSatZeros; // the number of times the simulation vector is zero
+ int nSatSupps; // the number of times the support info was useful
+ int nRefErrors; // the number of ref counting errors
+ int nImplies; // the number of implication cases
+ int nSatImpls; // the number of implication SAT calls
+ int nVarsClauses; // the number of variables with clauses
+ int nSimplifies0;
+ int nSimplifies1;
+ int nImplies0;
+ int nImplies1;
+
+ // runtime statistics
+ int timeToAig; // time to transfer to the mapping structure
+ int timeSims; // time to compute k-feasible cuts
+ int timeTrav; // time to traverse the network
+ int timeFeed; // time for solver feedback (recording and resimulating)
+ int timeImply; // time to analyze implications
+ int timeSat; // time to compute the truth table for each cut
+ int timeToNet; // time to transfer back to the network
+ int timeTotal; // the total mapping time
+ int time1; // time to perform one task
+ int time2; // time to perform another task
+ int time3; // time to perform another task
+ int time4; // time to perform another task
+};
+
+// the mapping node
+struct Fraig_NodeStruct_t_
+{
+ // various numbers associated with the node
+ int Num; // the unique number (SAT var number) of this node
+ int NumPi; // if the node is a PI, this is its variable number
+ int Level; // the level of the node
+ int nRefs; // the number of references of the node
+ int TravId; // the traversal ID (use to avoid cleaning marks)
+ int TravId2; // the traversal ID (use to avoid cleaning marks)
+
+ // general information about the node
+ unsigned fInv : 1; // the mark to show that simulation info is complemented
+ unsigned fNodePo : 1; // the mark used for primary outputs
+ unsigned fClauses : 1; // the clauses for this node are loaded
+ unsigned fMark0 : 1; // the mark used for traversals
+ unsigned fMark1 : 1; // the mark used for traversals
+ unsigned fMark2 : 1; // the mark used for traversals
+ unsigned fFeedUse : 1; // the presence of the variable in the feedback
+ unsigned fFeedVal : 1; // the value of the variable in the feedback
+ unsigned nFanouts : 2; // the indicator of fanouts (none, one, or many)
+ unsigned nOnes : 22; // the number of 1's in the random sim info
+
+ // the children of the node
+ Fraig_Node_t * p1; // the first child
+ Fraig_Node_t * p2; // the second child
+ Fraig_NodeVec_t * vFanins; // the fanins of the supergate rooted at this node
+// Fraig_NodeVec_t * vFanouts; // the fanouts of the supergate rooted at this node
+
+ // various linked lists
+ Fraig_Node_t * pNextS; // the next node in the structural hash table
+ Fraig_Node_t * pNextF; // the next node in the functional (simulation) hash table
+ Fraig_Node_t * pNextD; // the next node in the list of nodes based on dynamic simulation
+ Fraig_Node_t * pNextE; // the next structural choice (functionally-equivalent node)
+ Fraig_Node_t * pRepr; // the canonical functional representative of the node
+
+ // simulation data
+// Fraig_Sims_t * pSimsR; // the random simulation info
+// Fraig_Sims_t * pSimsD; // the systematic simulation info
+ unsigned uHashR; // the hash value for random information
+ unsigned uHashD; // the hash value for dynamic information
+ unsigned * puSimR; // the simulation information (random)
+ unsigned * puSimD; // the simulation information (dynamic)
+
+ // misc information
+ Fraig_Node_t * pData0; // temporary storage for the corresponding network node
+ Fraig_Node_t * pData1; // temporary storage for the corresponding network node
+
+#ifdef FRAIG_ENABLE_FANOUTS
+ // representation of node's fanouts
+ Fraig_Node_t * pFanPivot; // the first fanout of this node
+ Fraig_Node_t * pFanFanin1; // the next fanout of p1
+ Fraig_Node_t * pFanFanin2; // the next fanout of p2
+#endif
+};
+
+// the vector of nodes
+struct Fraig_NodeVecStruct_t_
+{
+ Fraig_Node_t ** pArray; // the array of nodes
+ int nSize; // the number of entries in the array
+ int nCap; // the number of allocated entries
+};
+
+// the hash table
+struct Fraig_HashTableStruct_t_
+{
+ Fraig_Node_t ** pBins; // the table bins
+ int nBins; // the size of the table
+ int nEntries; // the total number of entries in the table
+};
+
+// getting hold of the next fanout of the node
+#define Fraig_NodeReadNextFanout( pNode, pFanout ) \
+ ( ( pFanout == NULL )? NULL : \
+ ((Fraig_Regular((pFanout)->p1) == (pNode))? \
+ (pFanout)->pFanFanin1 : (pFanout)->pFanFanin2) )
+// getting hold of the place where the next fanout will be attached
+#define Fraig_NodeReadNextFanoutPlace( pNode, pFanout ) \
+ ( (Fraig_Regular((pFanout)->p1) == (pNode))? \
+ &(pFanout)->pFanFanin1 : &(pFanout)->pFanFanin2 )
+// iterator through the fanouts of the node
+#define Fraig_NodeForEachFanout( pNode, pFanout ) \
+ for ( pFanout = (pNode)->pFanPivot; pFanout; \
+ pFanout = Fraig_NodeReadNextFanout(pNode, pFanout) )
+// safe iterator through the fanouts of the node
+#define Fraig_NodeForEachFanoutSafe( pNode, pFanout, pFanout2 ) \
+ for ( pFanout = (pNode)->pFanPivot, \
+ pFanout2 = Fraig_NodeReadNextFanout(pNode, pFanout); \
+ pFanout; \
+ pFanout = pFanout2, \
+ pFanout2 = Fraig_NodeReadNextFanout(pNode, pFanout) )
+
+// iterators through the entries in the linked lists of nodes
+// the list of nodes in the structural hash table
+#define Fraig_TableBinForEachEntryS( pBin, pEnt ) \
+ for ( pEnt = pBin; \
+ pEnt; \
+ pEnt = pEnt->pNextS )
+#define Fraig_TableBinForEachEntrySafeS( pBin, pEnt, pEnt2 ) \
+ for ( pEnt = pBin, \
+ pEnt2 = pEnt? pEnt->pNextS: NULL; \
+ pEnt; \
+ pEnt = pEnt2, \
+ pEnt2 = pEnt? pEnt->pNextS: NULL )
+// the list of nodes in the functional (simulation) hash table
+#define Fraig_TableBinForEachEntryF( pBin, pEnt ) \
+ for ( pEnt = pBin; \
+ pEnt; \
+ pEnt = pEnt->pNextF )
+#define Fraig_TableBinForEachEntrySafeF( pBin, pEnt, pEnt2 ) \
+ for ( pEnt = pBin, \
+ pEnt2 = pEnt? pEnt->pNextF: NULL; \
+ pEnt; \
+ pEnt = pEnt2, \
+ pEnt2 = pEnt? pEnt->pNextF: NULL )
+// the list of nodes with the same simulation and different functionality
+#define Fraig_TableBinForEachEntryD( pBin, pEnt ) \
+ for ( pEnt = pBin; \
+ pEnt; \
+ pEnt = pEnt->pNextD )
+#define Fraig_TableBinForEachEntrySafeD( pBin, pEnt, pEnt2 ) \
+ for ( pEnt = pBin, \
+ pEnt2 = pEnt? pEnt->pNextD: NULL; \
+ pEnt; \
+ pEnt = pEnt2, \
+ pEnt2 = pEnt? pEnt->pNextD: NULL )
+// the list of nodes with the same functionality
+#define Fraig_TableBinForEachEntryE( pBin, pEnt ) \
+ for ( pEnt = pBin; \
+ pEnt; \
+ pEnt = pEnt->pNextE )
+#define Fraig_TableBinForEachEntrySafeE( pBin, pEnt, pEnt2 ) \
+ for ( pEnt = pBin, \
+ pEnt2 = pEnt? pEnt->pNextE: NULL; \
+ pEnt; \
+ pEnt = pEnt2, \
+ pEnt2 = pEnt? pEnt->pNextE: NULL )
+
+////////////////////////////////////////////////////////////////////////
+/// GLOBAL VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== fraigCanon.c =============================================================*/
+extern Fraig_Node_t * Fraig_NodeAndCanon( Fraig_Man_t * pMan, Fraig_Node_t * p1, Fraig_Node_t * p2 );
+/*=== fraigFanout.c =============================================================*/
+extern void Fraig_NodeAddFaninFanout( Fraig_Node_t * pFanin, Fraig_Node_t * pFanout );
+extern void Fraig_NodeRemoveFaninFanout( Fraig_Node_t * pFanin, Fraig_Node_t * pFanoutToRemove );
+extern int Fraig_NodeGetFanoutNum( Fraig_Node_t * pNode );
+/*=== fraigFeed.c =============================================================*/
+extern void Fraig_FeedBackInit( Fraig_Man_t * p );
+extern void Fraig_FeedBack( Fraig_Man_t * p, int * pModel, Msat_IntVec_t * vVars, Fraig_Node_t * pOld, Fraig_Node_t * pNew );
+extern void Fraig_FeedBackTest( Fraig_Man_t * p );
+extern int Fraig_FeedBackCompress( Fraig_Man_t * p );
+/*=== fraigMem.c =============================================================*/
+extern Fraig_MemFixed_t * Fraig_MemFixedStart( int nEntrySize );
+extern void Fraig_MemFixedStop( Fraig_MemFixed_t * p, int fVerbose );
+extern char * Fraig_MemFixedEntryFetch( Fraig_MemFixed_t * p );
+extern void Fraig_MemFixedEntryRecycle( Fraig_MemFixed_t * p, char * pEntry );
+extern void Fraig_MemFixedRestart( Fraig_MemFixed_t * p );
+extern int Fraig_MemFixedReadMemUsage( Fraig_MemFixed_t * p );
+/*=== fraigNode.c =============================================================*/
+extern Fraig_Node_t * Fraig_NodeCreateConst( Fraig_Man_t * p );
+extern Fraig_Node_t * Fraig_NodeCreatePi( Fraig_Man_t * p );
+extern Fraig_Node_t * Fraig_NodeCreate( Fraig_Man_t * p, Fraig_Node_t * p1, Fraig_Node_t * p2 );
+extern void Fraig_NodeSimulate( Fraig_Node_t * pNode, int iWordStart, int iWordStop, int fUseRand );
+/*=== fraigPrime.c =============================================================*/
+extern int s_FraigPrimes[FRAIG_MAX_PRIMES];
+extern unsigned int Cudd_PrimeFraig( unsigned int p );
+/*=== fraigSat.c ===============================================================*/
+extern int Fraig_NodeIsImplication( Fraig_Man_t * p, Fraig_Node_t * pOld, Fraig_Node_t * pNew, int nBTLimit );
+/*=== fraigTable.c =============================================================*/
+extern Fraig_HashTable_t * Fraig_HashTableCreate( int nSize );
+extern void Fraig_HashTableFree( Fraig_HashTable_t * p );
+extern int Fraig_HashTableLookupS( Fraig_Man_t * pMan, Fraig_Node_t * p1, Fraig_Node_t * p2, Fraig_Node_t ** ppNodeRes );
+extern Fraig_Node_t * Fraig_HashTableLookupF( Fraig_Man_t * pMan, Fraig_Node_t * pNode );
+extern Fraig_Node_t * Fraig_HashTableLookupF0( Fraig_Man_t * pMan, Fraig_Node_t * pNode );
+extern void Fraig_HashTableInsertF0( Fraig_Man_t * pMan, Fraig_Node_t * pNode );
+extern int Fraig_CompareSimInfo( Fraig_Node_t * pNode1, Fraig_Node_t * pNode2, int iWordLast, int fUseRand );
+extern int Fraig_CompareSimInfoUnderMask( Fraig_Node_t * pNode1, Fraig_Node_t * pNode2, int iWordLast, int fUseRand, unsigned * puMask );
+extern void Fraig_CollectXors( Fraig_Node_t * pNode1, Fraig_Node_t * pNode2, int iWordLast, int fUseRand, unsigned * puMask );
+extern void Fraig_TablePrintStatsS( Fraig_Man_t * pMan );
+extern void Fraig_TablePrintStatsF( Fraig_Man_t * pMan );
+extern void Fraig_TablePrintStatsF0( Fraig_Man_t * pMan );
+extern int Fraig_TableRehashF0( Fraig_Man_t * pMan, int fLinkEquiv );
+/*=== fraigUtil.c ===============================================================*/
+extern int Fraig_NodeCountPis( Msat_IntVec_t * vVars, int nVarsPi );
+extern int Fraig_NodeCountSuppVars( Fraig_Man_t * p, Fraig_Node_t * pNode, int fSuppStr );
+extern int Fraig_NodesCompareSupps( Fraig_Man_t * p, Fraig_Node_t * pOld, Fraig_Node_t * pNew );
+extern void Fraig_ManIncrementTravId( Fraig_Man_t * pMan );
+extern void Fraig_NodeSetTravIdCurrent( Fraig_Man_t * pMan, Fraig_Node_t * pNode );
+extern int Fraig_NodeIsTravIdCurrent( Fraig_Man_t * pMan, Fraig_Node_t * pNode );
+extern int Fraig_NodeIsTravIdPrevious( Fraig_Man_t * pMan, Fraig_Node_t * pNode );
+extern int Fraig_NodeAndSimpleCase_rec( Fraig_Node_t * pOld, Fraig_Node_t * pNew );
+extern int Fraig_NodeIsExorType( Fraig_Node_t * pNode );
+extern void Fraig_ManSelectBestChoice( Fraig_Man_t * p );
+extern int Fraig_BitStringCountOnes( unsigned * pString, int nWords );
+extern void Fraig_PrintBinary( FILE * pFile, unsigned * pSign, int nBits );
+extern int Fraig_NodeIsExorType( Fraig_Node_t * pNode );
+extern int Fraig_NodeIsExor( Fraig_Node_t * pNode );
+extern int Fraig_NodeIsMuxType( Fraig_Node_t * pNode );
+extern Fraig_Node_t * Fraig_NodeRecognizeMux( Fraig_Node_t * pNode, Fraig_Node_t ** ppNodeT, Fraig_Node_t ** ppNodeE );
+extern int Fraig_ManCountExors( Fraig_Man_t * pMan );
+extern int Fraig_ManCountMuxes( Fraig_Man_t * pMan );
+extern int Fraig_NodeSimsContained( Fraig_Man_t * pMan, Fraig_Node_t * pNode1, Fraig_Node_t * pNode2 );
+extern int Fraig_NodeIsInSupergate( Fraig_Node_t * pOld, Fraig_Node_t * pNew );
+extern Fraig_NodeVec_t * Fraig_CollectSupergate( Fraig_Node_t * pNode, int fStopAtMux );
+extern int Fraig_CountPis( Fraig_Man_t * p, Msat_IntVec_t * vVarNums );
+/*=== fraigVec.c ===============================================================*/
+extern void Fraig_NodeVecSortByRefCount( Fraig_NodeVec_t * p );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
diff --git a/src/sat/fraig/fraigMan.c b/src/sat/fraig/fraigMan.c
new file mode 100644
index 00000000..d41f5d0b
--- /dev/null
+++ b/src/sat/fraig/fraigMan.c
@@ -0,0 +1,237 @@
+/**CFile****************************************************************
+
+ FileName [fraigMan.c]
+
+ PackageName [FRAIG: Functionally reduced AND-INV graphs.]
+
+ Synopsis [Implementation of the FRAIG manager.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - October 1, 2004]
+
+ Revision [$Id: fraigMan.c,v 1.11 2005/07/08 01:01:31 alanmi Exp $]
+
+***********************************************************************/
+
+#include "fraigInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+int timeSelect;
+int timeAssign;
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Sets the default parameters of the package.]
+
+ Description [This set of parameters is tuned for equivalence checking.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_ParamsSetDefault( Fraig_Params_t * pParams )
+{
+ pParams->nPatsRand = FRAIG_PATTERNS_RANDOM; // the number of words of random simulation info
+ pParams->nPatsDyna = FRAIG_PATTERNS_DYNAMIC; // the number of words of dynamic simulation info
+ pParams->nBTLimit = 99; // the max number of backtracks to perform
+ pParams->fFuncRed = 1; // performs only one level hashing
+ pParams->fFeedBack = 1; // enables solver feedback
+ pParams->fDist1Pats = 1; // enables distance-1 patterns
+ pParams->fDoSparse = 0; // performs equiv tests for sparse functions
+ pParams->fChoicing = 0; // enables recording structural choices
+ pParams->fTryProve = 1; // tries to solve the final miter
+ pParams->fVerbose = 0; // the verbosiness flag
+ pParams->fVerboseP = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates the new FRAIG manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_Man_t * Fraig_ManCreate( Fraig_Params_t * pParams )
+{
+ Fraig_Params_t Params;
+ Fraig_Man_t * p;
+
+ // set the random seed for simulation
+ srand( 0xFEEDDEAF );
+
+ // set parameters for equivalence checking
+ if ( pParams == NULL )
+ Fraig_ParamsSetDefault( pParams = &Params );
+ // adjust the amount of simulation info
+ if ( pParams->nPatsRand < 128 )
+ pParams->nPatsRand = 128;
+ if ( pParams->nPatsRand > 32768 )
+ pParams->nPatsRand = 32768;
+ if ( pParams->nPatsDyna < 128 )
+ pParams->nPatsDyna = 128;
+ if ( pParams->nPatsDyna > 32768 )
+ pParams->nPatsDyna = 32768;
+ // if reduction is not performed, allocate minimum simulation info
+ if ( !pParams->fFuncRed )
+ pParams->nPatsRand = pParams->nPatsDyna = 128;
+
+ // start the manager
+ p = ALLOC( Fraig_Man_t, 1 );
+ memset( p, 0, sizeof(Fraig_Man_t) );
+
+ // set the default parameters
+ p->nWordsRand = FRAIG_NUM_WORDS( pParams->nPatsRand ); // the number of words of random simulation info
+ p->nWordsDyna = FRAIG_NUM_WORDS( pParams->nPatsDyna ); // the number of patterns for dynamic simulation info
+ p->nBTLimit = pParams->nBTLimit; // -1 means infinite backtrack limit
+ p->fFuncRed = pParams->fFuncRed; // enables functional reduction (otherwise, only one-level hashing is performed)
+ p->fFeedBack = pParams->fFeedBack; // enables solver feedback (the use of counter-examples in simulation)
+ p->fDist1Pats = pParams->fDist1Pats; // enables solver feedback (the use of counter-examples in simulation)
+ p->fDoSparse = pParams->fDoSparse; // performs equivalence checking for sparse functions (whose sim-info is 0)
+ p->fChoicing = pParams->fChoicing; // disable accumulation of structural choices (keeps only the first choice)
+ p->fTryProve = pParams->fTryProve; // disable accumulation of structural choices (keeps only the first choice)
+ p->fVerbose = pParams->fVerbose; // disable verbose output
+ p->fVerboseP = pParams->fVerboseP; // disable verbose output
+
+ // start memory managers
+ p->mmNodes = Fraig_MemFixedStart( sizeof(Fraig_Node_t) );
+ p->mmSims = Fraig_MemFixedStart( sizeof(unsigned) * (p->nWordsRand + p->nWordsDyna) );
+ // allocate node arrays
+ p->vInputs = Fraig_NodeVecAlloc( 1000 ); // the array of primary inputs
+ p->vOutputs = Fraig_NodeVecAlloc( 1000 ); // the array of primary outputs
+ p->vNodes = Fraig_NodeVecAlloc( 1000 ); // the array of internal nodes
+ // start the tables
+ p->pTableS = Fraig_HashTableCreate( 1000 ); // hashing by structure
+ p->pTableF = Fraig_HashTableCreate( 1000 ); // hashing by function
+ p->pTableF0 = Fraig_HashTableCreate( 1000 ); // hashing by function (for sparse functions)
+ // create the constant node
+ p->pConst1 = Fraig_NodeCreateConst( p );
+ // initialize SAT solver feedback data structures
+ Fraig_FeedBackInit( p );
+ // initialize other variables
+ p->vProj = Msat_IntVecAlloc( 10 );
+ p->nTravIds = 1;
+ p->nTravIds2 = 1;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Deallocates the mapping manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_ManFree( Fraig_Man_t * p )
+{
+ int i;
+ if ( p->fVerbose )
+ {
+ if ( p->fChoicing ) Fraig_ManReportChoices( p );
+ Fraig_ManPrintStats( p );
+// Fraig_TablePrintStatsS( p );
+// Fraig_TablePrintStatsF( p );
+// Fraig_TablePrintStatsF0( p );
+ }
+
+ for ( i = 0; i < p->vNodes->nSize; i++ )
+ if ( p->vNodes->pArray[i]->vFanins )
+ {
+ Fraig_NodeVecFree( p->vNodes->pArray[i]->vFanins );
+ p->vNodes->pArray[i]->vFanins = NULL;
+ }
+
+ if ( p->vInputs ) Fraig_NodeVecFree( p->vInputs );
+ if ( p->vNodes ) Fraig_NodeVecFree( p->vNodes );
+ if ( p->vOutputs ) Fraig_NodeVecFree( p->vOutputs );
+
+ if ( p->pTableS ) Fraig_HashTableFree( p->pTableS );
+ if ( p->pTableF ) Fraig_HashTableFree( p->pTableF );
+ if ( p->pTableF0 ) Fraig_HashTableFree( p->pTableF0 );
+
+ if ( p->pSat ) Msat_SolverFree( p->pSat );
+ if ( p->vProj ) Msat_IntVecFree( p->vProj );
+ if ( p->vCones ) Fraig_NodeVecFree( p->vCones );
+ if ( p->vPatsReal ) Msat_IntVecFree( p->vPatsReal );
+
+ Fraig_MemFixedStop( p->mmNodes, 0 );
+ Fraig_MemFixedStop( p->mmSims, 0 );
+
+ if ( p->pSuppS )
+ {
+ FREE( p->pSuppS[0] );
+ FREE( p->pSuppS );
+ }
+ if ( p->pSuppF )
+ {
+ FREE( p->pSuppF[0] );
+ FREE( p->pSuppF );
+ }
+
+ FREE( p->ppOutputNames );
+ FREE( p->ppInputNames );
+ FREE( p );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Deallocates the mapping manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_ManPrintStats( Fraig_Man_t * p )
+{
+ double nMemory;
+ int clk = clock();
+ nMemory = ((double)(p->vInputs->nSize + p->vNodes->nSize) *
+ (sizeof(Fraig_Node_t) + sizeof(unsigned)*(p->nWordsRand + p->nWordsDyna) /*+ p->nSuppWords*sizeof(unsigned)*/))/(1<<20);
+ printf( "Words: Random = %d. Dynamic = %d. Used = %d. Memory = %0.2f Mb.\n",
+ p->nWordsRand, p->nWordsDyna, p->iWordPerm, nMemory );
+ printf( "Proof = %d. Counter-example = %d. Fail = %d. Zero = %d.\n",
+ p->nSatProof, p->nSatCounter, p->nSatFails, p->nSatZeros );
+ printf( "Nodes: Final = %d. Total = %d. Mux = %d. (Exor = %d.) ClaVars = %d.\n",
+ Fraig_CountNodes(p,0), p->vNodes->nSize, Fraig_ManCountMuxes(p), Fraig_ManCountExors(p), p->nVarsClauses );
+ if ( p->pSat ) Msat_SolverPrintStats( p->pSat );
+ Fraig_PrintTime( "AIG simulation ", p->timeSims );
+ Fraig_PrintTime( "AIG traversal ", p->timeTrav );
+ Fraig_PrintTime( "Solver feedback ", p->timeFeed );
+ Fraig_PrintTime( "SAT solving ", p->timeSat );
+ Fraig_PrintTime( "Network update ", p->timeToNet );
+ Fraig_PrintTime( "TOTAL RUNTIME ", p->timeTotal );
+ if ( p->time1 > 0 ) { Fraig_PrintTime( "time1", p->time1 ); }
+ if ( p->time2 > 0 ) { Fraig_PrintTime( "time2", p->time2 ); }
+ if ( p->time3 > 0 ) { Fraig_PrintTime( "time3", p->time3 ); }
+ if ( p->time4 > 0 ) { Fraig_PrintTime( "time4", p->time4 ); }
+// PRT( "Selection ", timeSelect );
+// PRT( "Assignment", timeAssign );
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/sat/fraig/fraigMem.c b/src/sat/fraig/fraigMem.c
new file mode 100644
index 00000000..dbf42da4
--- /dev/null
+++ b/src/sat/fraig/fraigMem.c
@@ -0,0 +1,246 @@
+/**CFile****************************************************************
+
+ FileName [fraigMem.c]
+
+ PackageName [FRAIG: Functionally reduced AND-INV graphs.]
+
+ Synopsis [Fixed-size-entry memory manager for the FRAIG package.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - October 1, 2004]
+
+ Revision [$Id: fraigMem.c,v 1.4 2005/07/08 01:01:31 alanmi Exp $]
+
+***********************************************************************/
+
+#include "fraigInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+struct Fraig_MemFixed_t_
+{
+ // information about individual entries
+ int nEntrySize; // the size of one entry
+ int nEntriesAlloc; // the total number of entries allocated
+ int nEntriesUsed; // the number of entries in use
+ int nEntriesMax; // the max number of entries in use
+ char * pEntriesFree; // the linked list of free entries
+
+ // this is where the memory is stored
+ int nChunkSize; // the size of one chunk
+ int nChunksAlloc; // the maximum number of memory chunks
+ int nChunks; // the current number of memory chunks
+ char ** pChunks; // the allocated memory
+
+ // statistics
+ int nMemoryUsed; // memory used in the allocated entries
+ int nMemoryAlloc; // memory allocated
+};
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Starts the internal memory manager.]
+
+ Description [Can only work with entry size at least 4 byte long.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_MemFixed_t * Fraig_MemFixedStart( int nEntrySize )
+{
+ Fraig_MemFixed_t * p;
+
+ p = ALLOC( Fraig_MemFixed_t, 1 );
+ memset( p, 0, sizeof(Fraig_MemFixed_t) );
+
+ p->nEntrySize = nEntrySize;
+ p->nEntriesAlloc = 0;
+ p->nEntriesUsed = 0;
+ p->pEntriesFree = NULL;
+
+ if ( nEntrySize * (1 << 10) < (1<<16) )
+ p->nChunkSize = (1 << 10);
+ else
+ p->nChunkSize = (1<<16) / nEntrySize;
+ if ( p->nChunkSize < 8 )
+ p->nChunkSize = 8;
+
+ p->nChunksAlloc = 64;
+ p->nChunks = 0;
+ p->pChunks = ALLOC( char *, p->nChunksAlloc );
+
+ p->nMemoryUsed = 0;
+ p->nMemoryAlloc = 0;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Stops the internal memory manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_MemFixedStop( Fraig_MemFixed_t * p, int fVerbose )
+{
+ int i;
+ if ( p == NULL )
+ return;
+ if ( fVerbose )
+ {
+ printf( "Fixed memory manager: Entry = %5d. Chunk = %5d. Chunks used = %5d.\n",
+ p->nEntrySize, p->nChunkSize, p->nChunks );
+ printf( " Entries used = %8d. Entries peak = %8d. Memory used = %8d. Memory alloc = %8d.\n",
+ p->nEntriesUsed, p->nEntriesMax, p->nEntrySize * p->nEntriesUsed, p->nMemoryAlloc );
+ }
+ for ( i = 0; i < p->nChunks; i++ )
+ free( p->pChunks[i] );
+ free( p->pChunks );
+ free( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Extracts one entry from the memory manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Fraig_MemFixedEntryFetch( Fraig_MemFixed_t * p )
+{
+ char * pTemp;
+ int i;
+
+ // check if there are still free entries
+ if ( p->nEntriesUsed == p->nEntriesAlloc )
+ { // need to allocate more entries
+ assert( p->pEntriesFree == NULL );
+ if ( p->nChunks == p->nChunksAlloc )
+ {
+ p->nChunksAlloc *= 2;
+ p->pChunks = REALLOC( char *, p->pChunks, p->nChunksAlloc );
+ }
+ p->pEntriesFree = ALLOC( char, p->nEntrySize * p->nChunkSize );
+ p->nMemoryAlloc += p->nEntrySize * p->nChunkSize;
+ // transform these entries into a linked list
+ pTemp = p->pEntriesFree;
+ for ( i = 1; i < p->nChunkSize; i++ )
+ {
+ *((char **)pTemp) = pTemp + p->nEntrySize;
+ pTemp += p->nEntrySize;
+ }
+ // set the last link
+ *((char **)pTemp) = NULL;
+ // add the chunk to the chunk storage
+ p->pChunks[ p->nChunks++ ] = p->pEntriesFree;
+ // add to the number of entries allocated
+ p->nEntriesAlloc += p->nChunkSize;
+ }
+ // incrememt the counter of used entries
+ p->nEntriesUsed++;
+ if ( p->nEntriesMax < p->nEntriesUsed )
+ p->nEntriesMax = p->nEntriesUsed;
+ // return the first entry in the free entry list
+ pTemp = p->pEntriesFree;
+ p->pEntriesFree = *((char **)pTemp);
+ return pTemp;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns one entry into the memory manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_MemFixedEntryRecycle( Fraig_MemFixed_t * p, char * pEntry )
+{
+ // decrement the counter of used entries
+ p->nEntriesUsed--;
+ // add the entry to the linked list of free entries
+ *((char **)pEntry) = p->pEntriesFree;
+ p->pEntriesFree = pEntry;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Frees all associated memory and resets the manager.]
+
+ Description [Relocates all the memory except the first chunk.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_MemFixedRestart( Fraig_MemFixed_t * p )
+{
+ int i;
+ char * pTemp;
+
+ // delocate all chunks except the first one
+ for ( i = 1; i < p->nChunks; i++ )
+ free( p->pChunks[i] );
+ p->nChunks = 1;
+ // transform these entries into a linked list
+ pTemp = p->pChunks[0];
+ for ( i = 1; i < p->nChunkSize; i++ )
+ {
+ *((char **)pTemp) = pTemp + p->nEntrySize;
+ pTemp += p->nEntrySize;
+ }
+ // set the last link
+ *((char **)pTemp) = NULL;
+ // set the free entry list
+ p->pEntriesFree = p->pChunks[0];
+ // set the correct statistics
+ p->nMemoryAlloc = p->nEntrySize * p->nChunkSize;
+ p->nMemoryUsed = 0;
+ p->nEntriesAlloc = p->nChunkSize;
+ p->nEntriesUsed = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reports the memory usage.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_MemFixedReadMemUsage( Fraig_MemFixed_t * p )
+{
+ return p->nMemoryAlloc;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sat/fraig/fraigNode.c b/src/sat/fraig/fraigNode.c
new file mode 100644
index 00000000..9da9b88c
--- /dev/null
+++ b/src/sat/fraig/fraigNode.c
@@ -0,0 +1,308 @@
+/**CFile****************************************************************
+
+ FileName [fraigNode.c]
+
+ PackageName [FRAIG: Functionally reduced AND-INV graphs.]
+
+ Synopsis [Implementation of the FRAIG node.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - October 1, 2004]
+
+ Revision [$Id: fraigNode.c,v 1.3 2005/07/08 01:01:32 alanmi Exp $]
+
+***********************************************************************/
+
+#include "fraigInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// returns the complemented attribute of the node
+#define Fraig_NodeIsSimComplement(p) (Fraig_IsComplement(p)? !(Fraig_Regular(p)->fInv) : (p)->fInv)
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Creates the constant 1 node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_Node_t * Fraig_NodeCreateConst( Fraig_Man_t * p )
+{
+ Fraig_Node_t * pNode;
+
+ // create the node
+ pNode = (Fraig_Node_t *)Fraig_MemFixedEntryFetch( p->mmNodes );
+ memset( pNode, 0, sizeof(Fraig_Node_t) );
+
+ // assign the number and add to the array of nodes
+ pNode->Num = p->vNodes->nSize;
+ Fraig_NodeVecPush( p->vNodes, pNode );
+ pNode->NumPi = -1; // this is not a PI, so its number is -1
+ pNode->Level = 0; // just like a PI, it has 0 level
+ pNode->nRefs = 1; // it is a persistent node, which comes referenced
+ pNode->fInv = 1; // the simulation info is complemented
+
+ // create the simulation info
+ pNode->puSimR = (unsigned *)Fraig_MemFixedEntryFetch( p->mmSims );
+ pNode->puSimD = pNode->puSimR + p->nWordsRand;
+ memset( pNode->puSimR, 0, sizeof(unsigned) * p->nWordsRand );
+ memset( pNode->puSimD, 0, sizeof(unsigned) * p->nWordsDyna );
+
+ // count the number of ones in the simulation vector
+ pNode->nOnes = p->nWordsRand * sizeof(unsigned) * 8;
+
+ // insert it into the hash table
+ Fraig_HashTableLookupF0( p, pNode );
+ return pNode;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates a primary input node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_Node_t * Fraig_NodeCreatePi( Fraig_Man_t * p )
+{
+ Fraig_Node_t * pNode, * pNodeRes;
+ int i, clk;
+
+ // create the node
+ pNode = (Fraig_Node_t *)Fraig_MemFixedEntryFetch( p->mmNodes );
+ memset( pNode, 0, sizeof(Fraig_Node_t) );
+ pNode->puSimR = (unsigned *)Fraig_MemFixedEntryFetch( p->mmSims );
+ pNode->puSimD = pNode->puSimR + p->nWordsRand;
+ memset( pNode->puSimD, 0, sizeof(unsigned) * p->nWordsDyna );
+
+ // assign the number and add to the array of nodes
+ pNode->Num = p->vNodes->nSize;
+ Fraig_NodeVecPush( p->vNodes, pNode );
+
+ // assign the PI number and add to the array of primary inputs
+ pNode->NumPi = p->vInputs->nSize;
+ Fraig_NodeVecPush( p->vInputs, pNode );
+
+ pNode->Level = 0; // PI has 0 level
+ pNode->nRefs = 1; // it is a persistent node, which comes referenced
+ pNode->fInv = 0; // the simulation info of the PI is not complemented
+
+ // derive the simulation info for the new node
+clk = clock();
+ // set the random simulation info for the primary input
+ pNode->uHashR = 0;
+ for ( i = 0; i < p->nWordsRand; i++ )
+ {
+ // generate the simulation info
+ pNode->puSimR[i] = FRAIG_RANDOM_UNSIGNED;
+ // compute the hash key
+ pNode->uHashR ^= pNode->puSimR[i] * s_FraigPrimes[i];
+ }
+ // count the number of ones in the simulation vector
+ pNode->nOnes = Fraig_BitStringCountOnes( pNode->puSimR, p->nWordsRand );
+
+ // set the systematic simulation info for the primary input
+ pNode->uHashD = 0;
+ for ( i = 0; i < p->iWordStart; i++ )
+ {
+ // generate the simulation info
+ pNode->puSimD[i] = FRAIG_RANDOM_UNSIGNED;
+ // compute the hash key
+ pNode->uHashD ^= pNode->puSimD[i] * s_FraigPrimes[i];
+ }
+p->timeSims += clock() - clk;
+
+ // insert it into the hash table
+ pNodeRes = Fraig_HashTableLookupF( p, pNode );
+ assert( pNodeRes == NULL );
+ // add to the runtime of simulation
+ return pNode;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates a new node.]
+
+ Description [This procedure should be called to create the constant
+ node and the PI nodes first.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_Node_t * Fraig_NodeCreate( Fraig_Man_t * p, Fraig_Node_t * p1, Fraig_Node_t * p2 )
+{
+ Fraig_Node_t * pNode;
+ int clk;
+
+ // create the node
+ pNode = (Fraig_Node_t *)Fraig_MemFixedEntryFetch( p->mmNodes );
+ memset( pNode, 0, sizeof(Fraig_Node_t) );
+
+ // assign the children
+ pNode->p1 = p1; Fraig_Ref(p1); Fraig_Regular(p1)->nRefs++;
+ pNode->p2 = p2; Fraig_Ref(p2); Fraig_Regular(p2)->nRefs++;
+
+ // assign the number and add to the array of nodes
+ pNode->Num = p->vNodes->nSize;
+ Fraig_NodeVecPush( p->vNodes, pNode );
+
+ // assign the PI number
+ pNode->NumPi = -1;
+
+ // compute the level of this node
+ pNode->Level = 1 + FRAIG_MAX(Fraig_Regular(p1)->Level, Fraig_Regular(p2)->Level);
+ pNode->fInv = Fraig_NodeIsSimComplement(p1) & Fraig_NodeIsSimComplement(p2);
+
+ // derive the simulation info
+clk = clock();
+ // allocate memory for the simulation info
+ pNode->puSimR = (unsigned *)Fraig_MemFixedEntryFetch( p->mmSims );
+ pNode->puSimD = pNode->puSimR + p->nWordsRand;
+ // derive random simulation info
+ pNode->uHashR = 0;
+ Fraig_NodeSimulate( pNode, 0, p->nWordsRand, 1 );
+ // derive dynamic simulation info
+ pNode->uHashD = 0;
+ Fraig_NodeSimulate( pNode, 0, p->iWordStart, 0 );
+ // count the number of ones in the random simulation info
+ pNode->nOnes = Fraig_BitStringCountOnes( pNode->puSimR, p->nWordsRand );
+ if ( pNode->fInv )
+ pNode->nOnes = p->nWordsRand * 32 - pNode->nOnes;
+ // add to the runtime of simulation
+p->timeSims += clock() - clk;
+
+#ifdef FRAIG_ENABLE_FANOUTS
+ // create the fanout info
+ Fraig_NodeAddFaninFanout( Fraig_Regular(p1), pNode );
+ Fraig_NodeAddFaninFanout( Fraig_Regular(p2), pNode );
+#endif
+ return pNode;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Simulates the node.]
+
+ Description [Simulates the random or dynamic simulation info through
+ the node. Uses phases of the children to determine their real simulation
+ info. Uses phase of the node to determine the way its simulation info
+ is stored. The resulting info is guaranteed to be 0 for the first pattern.]
+
+ SideEffects [This procedure modified the hash value of the simulation info.]
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_NodeSimulate( Fraig_Node_t * pNode, int iWordStart, int iWordStop, int fUseRand )
+{
+ unsigned * pSims, * pSims1, * pSims2;
+ unsigned uHash;
+ int fCompl, fCompl1, fCompl2, i;
+
+ assert( !Fraig_IsComplement(pNode) );
+
+ // get hold of the simulation information
+ pSims = fUseRand? pNode->puSimR : pNode->puSimD;
+ pSims1 = fUseRand? Fraig_Regular(pNode->p1)->puSimR : Fraig_Regular(pNode->p1)->puSimD;
+ pSims2 = fUseRand? Fraig_Regular(pNode->p2)->puSimR : Fraig_Regular(pNode->p2)->puSimD;
+
+ // get complemented attributes of the children using their random info
+ fCompl = pNode->fInv;
+ fCompl1 = Fraig_NodeIsSimComplement(pNode->p1);
+ fCompl2 = Fraig_NodeIsSimComplement(pNode->p2);
+
+ // simulate
+ uHash = 0;
+ if ( fCompl1 && fCompl2 )
+ {
+ if ( fCompl )
+ for ( i = iWordStart; i < iWordStop; i++ )
+ {
+ pSims[i] = (pSims1[i] | pSims2[i]);
+ uHash ^= pSims[i] * s_FraigPrimes[i];
+ }
+ else
+ for ( i = iWordStart; i < iWordStop; i++ )
+ {
+ pSims[i] = ~(pSims1[i] | pSims2[i]);
+ uHash ^= pSims[i] * s_FraigPrimes[i];
+ }
+ }
+ else if ( fCompl1 && !fCompl2 )
+ {
+ if ( fCompl )
+ for ( i = iWordStart; i < iWordStop; i++ )
+ {
+ pSims[i] = (pSims1[i] | ~pSims2[i]);
+ uHash ^= pSims[i] * s_FraigPrimes[i];
+ }
+ else
+ for ( i = iWordStart; i < iWordStop; i++ )
+ {
+ pSims[i] = (~pSims1[i] & pSims2[i]);
+ uHash ^= pSims[i] * s_FraigPrimes[i];
+ }
+ }
+ else if ( !fCompl1 && fCompl2 )
+ {
+ if ( fCompl )
+ for ( i = iWordStart; i < iWordStop; i++ )
+ {
+ pSims[i] = (~pSims1[i] | pSims2[i]);
+ uHash ^= pSims[i] * s_FraigPrimes[i];
+ }
+ else
+ for ( i = iWordStart; i < iWordStop; i++ )
+ {
+ pSims[i] = (pSims1[i] & ~pSims2[i]);
+ uHash ^= pSims[i] * s_FraigPrimes[i];
+ }
+ }
+ else // if ( !fCompl1 && !fCompl2 )
+ {
+ if ( fCompl )
+ for ( i = iWordStart; i < iWordStop; i++ )
+ {
+ pSims[i] = ~(pSims1[i] & pSims2[i]);
+ uHash ^= pSims[i] * s_FraigPrimes[i];
+ }
+ else
+ for ( i = iWordStart; i < iWordStop; i++ )
+ {
+ pSims[i] = (pSims1[i] & pSims2[i]);
+ uHash ^= pSims[i] * s_FraigPrimes[i];
+ }
+ }
+
+ if ( fUseRand )
+ pNode->uHashR ^= uHash;
+ else
+ pNode->uHashD ^= uHash;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/sat/fraig/fraigPrime.c b/src/sat/fraig/fraigPrime.c
new file mode 100644
index 00000000..0f37a586
--- /dev/null
+++ b/src/sat/fraig/fraigPrime.c
@@ -0,0 +1,142 @@
+/**CFile****************************************************************
+
+ FileName [fraigPrime.c]
+
+ PackageName [FRAIG: Functionally reduced AND-INV graphs.]
+
+ Synopsis [The table of the first 1000 primes.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - October 1, 2004]
+
+ Revision [$Id: fraigPrime.c,v 1.4 2005/07/08 01:01:32 alanmi Exp $]
+
+***********************************************************************/
+
+#include "fraigInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// The 1,000 smallest prime numbers used to compute the hash value
+// http://www.math.utah.edu/~alfeld/math/primelist.html
+int s_FraigPrimes[FRAIG_MAX_PRIMES] = { 2, 3, 5,
+7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
+101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191,
+193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283,
+293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401,
+409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509,
+521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631,
+641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751,
+757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877,
+881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997,
+1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091,
+1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193,
+1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291,
+1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423,
+1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493,
+1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601,
+1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699,
+1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811,
+1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931,
+1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029,
+2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137,
+2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267,
+2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357,
+2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459,
+2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593,
+2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693,
+2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791,
+2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903,
+2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023,
+3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167,
+3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271,
+3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373,
+3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511,
+3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607,
+3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709,
+3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833,
+3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931,
+3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057,
+4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177,
+4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283,
+4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423,
+4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547,
+4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657,
+4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789,
+4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931,
+4933, 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011,
+5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147,
+5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279,
+5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413,
+5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507,
+5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647,
+5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743,
+5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857,
+5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, 5987, 6007,
+6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121,
+6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247,
+6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343,
+6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473,
+6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607,
+6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733,
+6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, 6857,
+6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971,
+6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103,
+7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229,
+7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369,
+7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, 7507, 7517,
+7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603,
+7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723,
+7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873,
+7877, 7879, 7883, 7901, 7907, 7919 };
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function********************************************************************
+
+ Synopsis [Returns the next prime &gt;= p.]
+
+ Description [Copied from CUDD, for stand-aloneness.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+unsigned int Cudd_PrimeFraig( unsigned int p)
+{
+ int i,pn;
+
+ p--;
+ do {
+ p++;
+ if (p&1) {
+ pn = 1;
+ i = 3;
+ while ((unsigned) (i * i) <= p) {
+ if (p % i == 0) {
+ pn = 0;
+ break;
+ }
+ i += 2;
+ }
+ } else {
+ pn = 0;
+ }
+ } while (!pn);
+ return(p);
+
+} /* end of Cudd_Prime */
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sat/fraig/fraigSat.c b/src/sat/fraig/fraigSat.c
new file mode 100644
index 00000000..ba22cfad
--- /dev/null
+++ b/src/sat/fraig/fraigSat.c
@@ -0,0 +1,1085 @@
+/**CFile****************************************************************
+
+ FileName [fraigSat.c]
+
+ PackageName [FRAIG: Functionally reduced AND-INV graphs.]
+
+ Synopsis [Proving functional equivalence using SAT.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - October 1, 2004]
+
+ Revision [$Id: fraigSat.c,v 1.10 2005/07/08 01:01:32 alanmi Exp $]
+
+***********************************************************************/
+
+#include "fraigInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Fraig_OrderVariables( Fraig_Man_t * pMan, Fraig_Node_t * pOld, Fraig_Node_t * pNew );
+static void Fraig_SetupAdjacent( Fraig_Man_t * pMan, Msat_IntVec_t * vConeVars );
+static void Fraig_SetupAdjacentMark( Fraig_Man_t * pMan, Msat_IntVec_t * vConeVars );
+static void Fraig_PrepareCones( Fraig_Man_t * pMan, Fraig_Node_t * pOld, Fraig_Node_t * pNew );
+static void Fraig_PrepareCones_rec( Fraig_Man_t * pMan, Fraig_Node_t * pNode );
+
+static void Fraig_SupergateAddClauses( Fraig_Man_t * pMan, Fraig_Node_t * pNode, Fraig_NodeVec_t * vSuper );
+static void Fraig_SupergateAddClausesExor( Fraig_Man_t * pMan, Fraig_Node_t * pNode );
+static void Fraig_SupergateAddClausesMux( Fraig_Man_t * pMan, Fraig_Node_t * pNode );
+//static void Fraig_DetectFanoutFreeCone( Fraig_Man_t * pMan, Fraig_Node_t * pNode );
+static void Fraig_DetectFanoutFreeConeMux( Fraig_Man_t * pMan, Fraig_Node_t * pNode );
+
+extern void * Msat_ClauseVecReadEntry( void * p, int i );
+
+// The lesson learned seems to be that variable should be in reverse topological order
+// from the output of the miter. The ordering of adjacency lists is very important.
+// The best way seems to be fanins followed by fanouts. Slight changes to this order
+// leads to big degradation in quality.
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Checks equivalence of two nodes.]
+
+ Description [Returns 1 iff the nodes are equivalent.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_NodesAreEqual( Fraig_Man_t * p, Fraig_Node_t * pNode1, Fraig_Node_t * pNode2, int nBTLimit )
+{
+ if ( pNode1 == pNode2 )
+ return 1;
+ if ( pNode1 == Fraig_Not(pNode2) )
+ return 0;
+ return Fraig_NodeIsEquivalent( p, Fraig_Regular(pNode1), Fraig_Regular(pNode2), nBTLimit );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Tries to prove the final miter.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_ManProveMiter( Fraig_Man_t * p )
+{
+ Fraig_Node_t * pNode;
+ int i, clk;
+
+ if ( !p->fTryProve )
+ return;
+
+ clk = clock();
+ // consider all outputs of the multi-output miter
+ for ( i = 0; i < p->vOutputs->nSize; i++ )
+ {
+ pNode = Fraig_Regular(p->vOutputs->pArray[i]);
+ // skip already constant nodes
+ if ( pNode == p->pConst1 )
+ continue;
+ // skip nodes that are different according to simulation
+ if ( !Fraig_CompareSimInfo( pNode, p->pConst1, p->nWordsRand, 1 ) )
+ continue;
+ if ( Fraig_NodeIsEquivalent( p, p->pConst1, pNode, -1 ) )
+ {
+ if ( Fraig_IsComplement(p->vOutputs->pArray[i]) )
+ p->vOutputs->pArray[i] = Fraig_Not(p->pConst1);
+ else
+ p->vOutputs->pArray[i] = p->pConst1;
+ }
+ }
+ if ( p->fVerboseP )
+ {
+ PRT( "Final miter proof time", clock() - clk );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks whether two nodes are functinally equivalent.]
+
+ Description [The flag (fComp) tells whether the nodes to be checked
+ are in the opposite polarity. The second flag (fSkipZeros) tells whether
+ the checking should be performed if the simulation vectors are zeros.
+ Returns 1 if the nodes are equivalent; 0 othewise.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_NodeIsEquivalent( Fraig_Man_t * p, Fraig_Node_t * pOld, Fraig_Node_t * pNew, int nBTLimit )
+{
+ int RetValue, RetValue1, i, fComp, clk;
+ int fVerbose = 0;
+
+ // make sure the nodes are not complemented
+ assert( !Fraig_IsComplement(pNew) );
+ assert( !Fraig_IsComplement(pOld) );
+ assert( pNew != pOld );
+
+ p->nSatCalls++;
+
+ // make sure the solver is allocated and has enough variables
+ if ( p->pSat == NULL )
+ {
+ extern int timeSelect;
+ extern int timeAssign;
+ // allocate data for SAT solving
+ p->pSat = Msat_SolverAlloc( 500, 1, 1, 1, 1, 0 );
+ p->vVarsInt = Msat_SolverReadConeVars( p->pSat );
+ p->vAdjacents = Msat_SolverReadAdjacents( p->pSat );
+ p->vVarsUsed = Msat_SolverReadVarsUsed( p->pSat );
+ timeSelect = 0;
+ timeAssign = 0;
+ }
+ // make sure the SAT solver has enough variables
+ for ( i = Msat_SolverReadVarNum(p->pSat); i < p->vNodes->nSize; i++ )
+ Msat_SolverAddVar( p->pSat );
+
+
+
+/*
+ {
+ Fraig_Node_t * ppNodes[2] = { pOld, pNew };
+ extern void Fraig_MappingShowNodes( Fraig_Man_t * pMan, Fraig_Node_t ** ppRoots, int nRoots, char * pFileName );
+ Fraig_MappingShowNodes( p, ppNodes, 2, "temp_aig" );
+ }
+*/
+
+
+ // get the logic cone
+clk = clock();
+ Fraig_OrderVariables( p, pOld, pNew );
+// Fraig_PrepareCones( p, pOld, pNew );
+p->timeTrav += clock() - clk;
+
+if ( fVerbose )
+ printf( "%d(%d) - ", Fraig_CountPis(p,p->vVarsInt), Msat_IntVecReadSize(p->vVarsInt) );
+
+
+ // get the complemented attribute
+ fComp = Fraig_NodeComparePhase( pOld, pNew );
+//Msat_SolverPrintClauses( p->pSat );
+
+ ////////////////////////////////////////////
+ // prepare the solver to run incrementally on these variables
+//clk = clock();
+ Msat_SolverPrepare( p->pSat, p->vVarsInt );
+//p->time3 += clock() - clk;
+
+ // solve under assumptions
+ // A = 1; B = 0 OR A = 1; B = 1
+ Msat_IntVecClear( p->vProj );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pOld->Num, 0) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pNew->Num, !fComp) );
+ // run the solver
+clk = clock();
+ RetValue1 = Msat_SolverSolve( p->pSat, p->vProj, nBTLimit );
+p->timeSat += clock() - clk;
+
+ if ( RetValue1 == MSAT_FALSE )
+ {
+//p->time1 += clock() - clk;
+
+if ( fVerbose )
+{
+ printf( "unsat %d ", Msat_SolverReadBackTracks(p->pSat) );
+PRT( "time", clock() - clk );
+}
+
+ // add the clause
+ Msat_IntVecClear( p->vProj );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pOld->Num, 1) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pNew->Num, fComp) );
+ RetValue = Msat_SolverAddClause( p->pSat, p->vProj );
+ assert( RetValue );
+ // continue solving the other implication
+ }
+ else if ( RetValue1 == MSAT_TRUE )
+ {
+//p->time2 += clock() - clk;
+
+if ( fVerbose )
+{
+ printf( "sat %d ", Msat_SolverReadBackTracks(p->pSat) );
+PRT( "time", clock() - clk );
+}
+
+ // record the counter example
+ Fraig_FeedBack( p, Msat_SolverReadModelArray(p->pSat), p->vVarsInt, pOld, pNew );
+ p->nSatCounter++;
+ return 0;
+ }
+ else // if ( RetValue1 == MSAT_UNKNOWN )
+ {
+p->time3 += clock() - clk;
+ p->nSatFails++;
+ return 0;
+ }
+
+ // if the old node was constant 0, we already know the answer
+ if ( pOld == p->pConst1 )
+ return 1;
+
+ ////////////////////////////////////////////
+ // prepare the solver to run incrementally
+//clk = clock();
+ Msat_SolverPrepare( p->pSat, p->vVarsInt );
+//p->time3 += clock() - clk;
+ // solve under assumptions
+ // A = 0; B = 1 OR A = 0; B = 0
+ Msat_IntVecClear( p->vProj );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pOld->Num, 1) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pNew->Num, fComp) );
+ // run the solver
+clk = clock();
+ RetValue1 = Msat_SolverSolve( p->pSat, p->vProj, nBTLimit );
+p->timeSat += clock() - clk;
+ if ( RetValue1 == MSAT_FALSE )
+ {
+//p->time1 += clock() - clk;
+
+if ( fVerbose )
+{
+ printf( "unsat %d ", Msat_SolverReadBackTracks(p->pSat) );
+PRT( "time", clock() - clk );
+}
+
+ // add the clause
+ Msat_IntVecClear( p->vProj );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pOld->Num, 0) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pNew->Num, !fComp) );
+ RetValue = Msat_SolverAddClause( p->pSat, p->vProj );
+ assert( RetValue );
+ // continue solving the other implication
+ }
+ else if ( RetValue1 == MSAT_TRUE )
+ {
+//p->time2 += clock() - clk;
+
+if ( fVerbose )
+{
+ printf( "sat %d ", Msat_SolverReadBackTracks(p->pSat) );
+PRT( "time", clock() - clk );
+}
+
+ // record the counter example
+ Fraig_FeedBack( p, Msat_SolverReadModelArray(p->pSat), p->vVarsInt, pOld, pNew );
+ p->nSatCounter++;
+ return 0;
+ }
+ else // if ( RetValue1 == MSAT_UNKNOWN )
+ {
+p->time3 += clock() - clk;
+ p->nSatFails++;
+ return 0;
+ }
+
+ // return SAT proof
+ p->nSatProof++;
+ return 1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Checks whether pOld => pNew.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_NodeIsImplication( Fraig_Man_t * p, Fraig_Node_t * pOld, Fraig_Node_t * pNew, int nBTLimit )
+{
+ int RetValue, RetValue1, i, fComp, clk;
+ int fVerbose = 0;
+
+ // make sure the nodes are not complemented
+ assert( !Fraig_IsComplement(pNew) );
+ assert( !Fraig_IsComplement(pOld) );
+ assert( pNew != pOld );
+
+ p->nSatCallsImp++;
+
+ // make sure the solver is allocated and has enough variables
+ if ( p->pSat == NULL )
+ {
+ extern int timeSelect;
+ extern int timeAssign;
+ // allocate data for SAT solving
+ p->pSat = Msat_SolverAlloc( 500, 1, 1, 1, 1, 0 );
+ p->vVarsInt = Msat_SolverReadConeVars( p->pSat );
+ p->vAdjacents = Msat_SolverReadAdjacents( p->pSat );
+ p->vVarsUsed = Msat_SolverReadVarsUsed( p->pSat );
+ timeSelect = 0;
+ timeAssign = 0;
+ }
+ // make sure the SAT solver has enough variables
+ for ( i = Msat_SolverReadVarNum(p->pSat); i < p->vNodes->nSize; i++ )
+ Msat_SolverAddVar( p->pSat );
+
+
+/*
+ {
+ Fraig_Node_t * ppNodes[2] = { pOld, pNew };
+ extern void Fraig_MappingShowNodes( Fraig_Man_t * pMan, Fraig_Node_t ** ppRoots, int nRoots, char * pFileName );
+ Fraig_MappingShowNodes( p, ppNodes, 2, "temp_aig" );
+ }
+*/
+
+
+ // get the logic cone
+clk = clock();
+ Fraig_OrderVariables( p, pOld, pNew );
+// Fraig_PrepareCones( p, pOld, pNew );
+p->timeTrav += clock() - clk;
+
+if ( fVerbose )
+ printf( "%d(%d) - ", Fraig_CountPis(p,p->vVarsInt), Msat_IntVecReadSize(p->vVarsInt) );
+
+
+ // get the complemented attribute
+ fComp = Fraig_NodeComparePhase( pOld, pNew );
+//Msat_SolverPrintClauses( p->pSat );
+
+ ////////////////////////////////////////////
+ // prepare the solver to run incrementally on these variables
+//clk = clock();
+ Msat_SolverPrepare( p->pSat, p->vVarsInt );
+//p->time3 += clock() - clk;
+
+ // solve under assumptions
+ // A = 1; B = 0 OR A = 1; B = 1
+ Msat_IntVecClear( p->vProj );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pOld->Num, 0) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pNew->Num, !fComp) );
+ // run the solver
+clk = clock();
+ RetValue1 = Msat_SolverSolve( p->pSat, p->vProj, nBTLimit );
+p->timeSat += clock() - clk;
+
+ if ( RetValue1 == MSAT_FALSE )
+ {
+//p->time1 += clock() - clk;
+
+if ( fVerbose )
+{
+ printf( "unsat %d ", Msat_SolverReadBackTracks(p->pSat) );
+PRT( "time", clock() - clk );
+}
+
+ // add the clause
+ Msat_IntVecClear( p->vProj );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pOld->Num, 1) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pNew->Num, fComp) );
+ RetValue = Msat_SolverAddClause( p->pSat, p->vProj );
+ assert( RetValue );
+// p->nSatProofImp++;
+ return 1;
+ }
+ else if ( RetValue1 == MSAT_TRUE )
+ {
+//p->time2 += clock() - clk;
+
+if ( fVerbose )
+{
+ printf( "sat %d ", Msat_SolverReadBackTracks(p->pSat) );
+PRT( "time", clock() - clk );
+}
+ // record the counter example
+// Fraig_FeedBack( p, Msat_SolverReadModelArray(p->pSat), p->vVarsInt, pOld, pNew );
+// p->nSatCounterImp++;
+ return 0;
+ }
+ else // if ( RetValue1 == MSAT_UNKNOWN )
+ {
+p->time3 += clock() - clk;
+ p->nSatFailsImp++;
+ return 0;
+ }
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Prepares the SAT solver to run on the two nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_PrepareCones( Fraig_Man_t * pMan, Fraig_Node_t * pOld, Fraig_Node_t * pNew )
+{
+// Msat_IntVec_t * vAdjs;
+// int * pVars, nVars, i, k;
+ int nVarsAlloc;
+
+ assert( pOld != pNew );
+ assert( !Fraig_IsComplement(pOld) );
+ assert( !Fraig_IsComplement(pNew) );
+ // clean the variables
+ nVarsAlloc = Msat_IntVecReadSize(pMan->vVarsUsed);
+ Msat_IntVecFill( pMan->vVarsUsed, nVarsAlloc, 0 );
+ Msat_IntVecClear( pMan->vVarsInt );
+
+ pMan->nTravIds++;
+ Fraig_PrepareCones_rec( pMan, pNew );
+ Fraig_PrepareCones_rec( pMan, pOld );
+
+/*
+ nVars = Msat_IntVecReadSize( pMan->vVarsInt );
+ pVars = Msat_IntVecReadArray( pMan->vVarsInt );
+ for ( i = 0; i < nVars; i++ )
+ {
+ // process its connections
+ vAdjs = (Msat_IntVec_t *)Msat_ClauseVecReadEntry( pMan->vAdjacents, pVars[i] );
+ printf( "%d=%d { ", pVars[i], Msat_IntVecReadSize(vAdjs) );
+ for ( k = 0; k < Msat_IntVecReadSize(vAdjs); k++ )
+ printf( "%d ", Msat_IntVecReadEntry(vAdjs,k) );
+ printf( "}\n" );
+
+ }
+ i = 0;
+*/
+}
+
+/**Function*************************************************************
+
+ Synopsis [Traverses the cone, collects the numbers and adds the clauses.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_PrepareCones_rec( Fraig_Man_t * pMan, Fraig_Node_t * pNode )
+{
+ Fraig_Node_t * pFanin;
+ Msat_IntVec_t * vAdjs;
+ int fUseMuxes = 1, i;
+ int fItIsTime;
+
+ // skip if the node is aleady visited
+ assert( !Fraig_IsComplement(pNode) );
+ if ( pNode->TravId == pMan->nTravIds )
+ return;
+ pNode->TravId = pMan->nTravIds;
+
+ // collect the node's number (closer to reverse topological order)
+ Msat_IntVecPush( pMan->vVarsInt, pNode->Num );
+ Msat_IntVecWriteEntry( pMan->vVarsUsed, pNode->Num, 1 );
+ if ( !Fraig_NodeIsAnd( pNode ) )
+ return;
+
+ // if the node does not have fanins, create them
+ fItIsTime = 0;
+ if ( pNode->vFanins == NULL )
+ {
+ fItIsTime = 1;
+ // create the fanins of the supergate
+ assert( pNode->fClauses == 0 );
+ if ( fUseMuxes && Fraig_NodeIsMuxType(pNode) )
+ {
+ pNode->vFanins = Fraig_NodeVecAlloc( 4 );
+ Fraig_NodeVecPushUnique( pNode->vFanins, Fraig_Regular(Fraig_Regular(pNode->p1)->p1) );
+ Fraig_NodeVecPushUnique( pNode->vFanins, Fraig_Regular(Fraig_Regular(pNode->p1)->p2) );
+ Fraig_NodeVecPushUnique( pNode->vFanins, Fraig_Regular(Fraig_Regular(pNode->p2)->p1) );
+ Fraig_NodeVecPushUnique( pNode->vFanins, Fraig_Regular(Fraig_Regular(pNode->p2)->p2) );
+ Fraig_SupergateAddClausesMux( pMan, pNode );
+ }
+ else
+ {
+ pNode->vFanins = Fraig_CollectSupergate( pNode, fUseMuxes );
+ Fraig_SupergateAddClauses( pMan, pNode, pNode->vFanins );
+ }
+ assert( pNode->vFanins->nSize > 1 );
+ pNode->fClauses = 1;
+ pMan->nVarsClauses++;
+
+ // add fanins
+ vAdjs = (Msat_IntVec_t *)Msat_ClauseVecReadEntry( pMan->vAdjacents, pNode->Num );
+ assert( Msat_IntVecReadSize( vAdjs ) == 0 );
+ for ( i = 0; i < pNode->vFanins->nSize; i++ )
+ {
+ pFanin = Fraig_Regular(pNode->vFanins->pArray[i]);
+ Msat_IntVecPush( vAdjs, pFanin->Num );
+ }
+ }
+
+ // recursively visit the fanins
+ for ( i = 0; i < pNode->vFanins->nSize; i++ )
+ Fraig_PrepareCones_rec( pMan, Fraig_Regular(pNode->vFanins->pArray[i]) );
+
+ if ( fItIsTime )
+ {
+ // recursively visit the fanins
+ for ( i = 0; i < pNode->vFanins->nSize; i++ )
+ {
+ pFanin = Fraig_Regular(pNode->vFanins->pArray[i]);
+ vAdjs = (Msat_IntVec_t *)Msat_ClauseVecReadEntry( pMan->vAdjacents, pFanin->Num );
+ Msat_IntVecPush( vAdjs, pNode->Num );
+ }
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collect variables using their proximity from the nodes.]
+
+ Description [This procedure creates a variable order based on collecting
+ first the nodes that are the closest to the given two target nodes.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_OrderVariables( Fraig_Man_t * pMan, Fraig_Node_t * pOld, Fraig_Node_t * pNew )
+{
+ Fraig_Node_t * pNode, * pFanin;
+ int i, k, Number, fUseMuxes = 1;
+ int nVarsAlloc;
+
+ assert( pOld != pNew );
+ assert( !Fraig_IsComplement(pOld) );
+ assert( !Fraig_IsComplement(pNew) );
+
+ pMan->nTravIds++;
+
+ // clean the variables
+ nVarsAlloc = Msat_IntVecReadSize(pMan->vVarsUsed);
+ Msat_IntVecFill( pMan->vVarsUsed, nVarsAlloc, 0 );
+ Msat_IntVecClear( pMan->vVarsInt );
+
+ // add the first node
+ Msat_IntVecPush( pMan->vVarsInt, pOld->Num );
+ Msat_IntVecWriteEntry( pMan->vVarsUsed, pOld->Num, 1 );
+ pOld->TravId = pMan->nTravIds;
+
+ // add the second node
+ Msat_IntVecPush( pMan->vVarsInt, pNew->Num );
+ Msat_IntVecWriteEntry( pMan->vVarsUsed, pNew->Num, 1 );
+ pNew->TravId = pMan->nTravIds;
+
+ // create the variable order
+ for ( i = 0; i < Msat_IntVecReadSize(pMan->vVarsInt); i++ )
+ {
+ // get the new node on the frontier
+ Number = Msat_IntVecReadEntry(pMan->vVarsInt, i);
+ pNode = pMan->vNodes->pArray[Number];
+ if ( !Fraig_NodeIsAnd(pNode) )
+ continue;
+
+ // if the node does not have fanins, create them
+ if ( pNode->vFanins == NULL )
+ {
+ // create the fanins of the supergate
+ assert( pNode->fClauses == 0 );
+ // detecting a fanout-free cone (experiment only)
+// Fraig_DetectFanoutFreeCone( pMan, pNode );
+
+ if ( fUseMuxes && Fraig_NodeIsMuxType(pNode) )
+ {
+ pNode->vFanins = Fraig_NodeVecAlloc( 4 );
+ Fraig_NodeVecPushUnique( pNode->vFanins, Fraig_Regular(Fraig_Regular(pNode->p1)->p1) );
+ Fraig_NodeVecPushUnique( pNode->vFanins, Fraig_Regular(Fraig_Regular(pNode->p1)->p2) );
+ Fraig_NodeVecPushUnique( pNode->vFanins, Fraig_Regular(Fraig_Regular(pNode->p2)->p1) );
+ Fraig_NodeVecPushUnique( pNode->vFanins, Fraig_Regular(Fraig_Regular(pNode->p2)->p2) );
+ Fraig_SupergateAddClausesMux( pMan, pNode );
+// Fraig_DetectFanoutFreeConeMux( pMan, pNode );
+ }
+ else
+ {
+ pNode->vFanins = Fraig_CollectSupergate( pNode, fUseMuxes );
+ Fraig_SupergateAddClauses( pMan, pNode, pNode->vFanins );
+ }
+ assert( pNode->vFanins->nSize > 1 );
+ pNode->fClauses = 1;
+ pMan->nVarsClauses++;
+
+ pNode->fMark2 = 1; // goes together with Fraig_SetupAdjacentMark()
+ }
+
+ // explore the implication fanins of pNode
+ for ( k = 0; k < pNode->vFanins->nSize; k++ )
+ {
+ pFanin = Fraig_Regular(pNode->vFanins->pArray[k]);
+ if ( pFanin->TravId == pMan->nTravIds ) // already collected
+ continue;
+ // collect and mark
+ Msat_IntVecPush( pMan->vVarsInt, pFanin->Num );
+ Msat_IntVecWriteEntry( pMan->vVarsUsed, pFanin->Num, 1 );
+ pFanin->TravId = pMan->nTravIds;
+ }
+ }
+
+ // set up the adjacent variable information
+// Fraig_SetupAdjacent( pMan, pMan->vVarsInt );
+ Fraig_SetupAdjacentMark( pMan, pMan->vVarsInt );
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Set up the adjacent variable information.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_SetupAdjacent( Fraig_Man_t * pMan, Msat_IntVec_t * vConeVars )
+{
+ Fraig_Node_t * pNode, * pFanin;
+ Msat_IntVec_t * vAdjs;
+ int * pVars, nVars, i, k;
+
+ // clean the adjacents for the variables
+ nVars = Msat_IntVecReadSize( vConeVars );
+ pVars = Msat_IntVecReadArray( vConeVars );
+ for ( i = 0; i < nVars; i++ )
+ {
+ // process its connections
+ vAdjs = (Msat_IntVec_t *)Msat_ClauseVecReadEntry( pMan->vAdjacents, pVars[i] );
+ Msat_IntVecClear( vAdjs );
+
+ pNode = pMan->vNodes->pArray[pVars[i]];
+ if ( !Fraig_NodeIsAnd(pNode) )
+ continue;
+
+ // add fanins
+ vAdjs = (Msat_IntVec_t *)Msat_ClauseVecReadEntry( pMan->vAdjacents, pVars[i] );
+ for ( k = 0; k < pNode->vFanins->nSize; k++ )
+// for ( k = pNode->vFanins->nSize - 1; k >= 0; k-- )
+ {
+ pFanin = Fraig_Regular(pNode->vFanins->pArray[k]);
+ Msat_IntVecPush( vAdjs, pFanin->Num );
+// Msat_IntVecPushUniqueOrder( vAdjs, pFanin->Num );
+ }
+ }
+ // add the fanouts
+ for ( i = 0; i < nVars; i++ )
+ {
+ pNode = pMan->vNodes->pArray[pVars[i]];
+ if ( !Fraig_NodeIsAnd(pNode) )
+ continue;
+
+ // add the edges
+ for ( k = 0; k < pNode->vFanins->nSize; k++ )
+// for ( k = pNode->vFanins->nSize - 1; k >= 0; k-- )
+ {
+ pFanin = Fraig_Regular(pNode->vFanins->pArray[k]);
+ vAdjs = (Msat_IntVec_t *)Msat_ClauseVecReadEntry( pMan->vAdjacents, pFanin->Num );
+ Msat_IntVecPush( vAdjs, pNode->Num );
+// Msat_IntVecPushUniqueOrder( vAdjs, pFanin->Num );
+ }
+ }
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Set up the adjacent variable information.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_SetupAdjacentMark( Fraig_Man_t * pMan, Msat_IntVec_t * vConeVars )
+{
+ Fraig_Node_t * pNode, * pFanin;
+ Msat_IntVec_t * vAdjs;
+ int * pVars, nVars, i, k;
+
+ // clean the adjacents for the variables
+ nVars = Msat_IntVecReadSize( vConeVars );
+ pVars = Msat_IntVecReadArray( vConeVars );
+ for ( i = 0; i < nVars; i++ )
+ {
+ pNode = pMan->vNodes->pArray[pVars[i]];
+ if ( pNode->fMark2 == 0 )
+ continue;
+// pNode->fMark2 = 0;
+
+ // process its connections
+// vAdjs = (Msat_IntVec_t *)Msat_ClauseVecReadEntry( pMan->vAdjacents, pVars[i] );
+// Msat_IntVecClear( vAdjs );
+
+ if ( !Fraig_NodeIsAnd(pNode) )
+ continue;
+
+ // add fanins
+ vAdjs = (Msat_IntVec_t *)Msat_ClauseVecReadEntry( pMan->vAdjacents, pVars[i] );
+ for ( k = 0; k < pNode->vFanins->nSize; k++ )
+// for ( k = pNode->vFanins->nSize - 1; k >= 0; k-- )
+ {
+ pFanin = Fraig_Regular(pNode->vFanins->pArray[k]);
+ Msat_IntVecPush( vAdjs, pFanin->Num );
+// Msat_IntVecPushUniqueOrder( vAdjs, pFanin->Num );
+ }
+ }
+ // add the fanouts
+ for ( i = 0; i < nVars; i++ )
+ {
+ pNode = pMan->vNodes->pArray[pVars[i]];
+ if ( pNode->fMark2 == 0 )
+ continue;
+ pNode->fMark2 = 0;
+
+ if ( !Fraig_NodeIsAnd(pNode) )
+ continue;
+
+ // add the edges
+ for ( k = 0; k < pNode->vFanins->nSize; k++ )
+// for ( k = pNode->vFanins->nSize - 1; k >= 0; k-- )
+ {
+ pFanin = Fraig_Regular(pNode->vFanins->pArray[k]);
+ vAdjs = (Msat_IntVec_t *)Msat_ClauseVecReadEntry( pMan->vAdjacents, pFanin->Num );
+ Msat_IntVecPush( vAdjs, pNode->Num );
+// Msat_IntVecPushUniqueOrder( vAdjs, pFanin->Num );
+ }
+ }
+}
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Adds clauses to the solver.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_SupergateAddClauses( Fraig_Man_t * p, Fraig_Node_t * pNode, Fraig_NodeVec_t * vSuper )
+{
+ int fComp1, RetValue, nVars, Var, Var1, i;
+
+ assert( Fraig_NodeIsAnd( pNode ) );
+ nVars = Msat_SolverReadVarNum(p->pSat);
+
+ Var = pNode->Num;
+ assert( Var < nVars );
+ for ( i = 0; i < vSuper->nSize; i++ )
+ {
+ // get the predecessor nodes
+ // get the complemented attributes of the nodes
+ fComp1 = Fraig_IsComplement(vSuper->pArray[i]);
+ // determine the variable numbers
+ Var1 = Fraig_Regular(vSuper->pArray[i])->Num;
+ // check that the variables are in the SAT manager
+ assert( Var1 < nVars );
+
+ // suppose the AND-gate is A * B = C
+ // add !A => !C or A + !C
+ // fprintf( pFile, "%d %d 0%c", Var1, -Var, 10 );
+ Msat_IntVecClear( p->vProj );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(Var1, fComp1) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(Var, 1) );
+ RetValue = Msat_SolverAddClause( p->pSat, p->vProj );
+ assert( RetValue );
+ }
+
+ // add A & B => C or !A + !B + C
+// fprintf( pFile, "%d %d %d 0%c", -Var1, -Var2, Var, 10 );
+ Msat_IntVecClear( p->vProj );
+ for ( i = 0; i < vSuper->nSize; i++ )
+ {
+ // get the predecessor nodes
+ // get the complemented attributes of the nodes
+ fComp1 = Fraig_IsComplement(vSuper->pArray[i]);
+ // determine the variable numbers
+ Var1 = Fraig_Regular(vSuper->pArray[i])->Num;
+
+ // add this variable to the array
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(Var1, !fComp1) );
+ }
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(Var, 0) );
+ RetValue = Msat_SolverAddClause( p->pSat, p->vProj );
+ assert( RetValue );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Adds clauses to the solver.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_SupergateAddClausesExor( Fraig_Man_t * p, Fraig_Node_t * pNode )
+{
+ Fraig_Node_t * pNode1, * pNode2;
+ int fComp, RetValue;
+
+ assert( !Fraig_IsComplement( pNode ) );
+ assert( Fraig_NodeIsExorType( pNode ) );
+ // get nodes
+ pNode1 = Fraig_Regular(Fraig_Regular(pNode->p1)->p1);
+ pNode2 = Fraig_Regular(Fraig_Regular(pNode->p1)->p2);
+ // get the complemented attribute of the EXOR/NEXOR gate
+ fComp = Fraig_NodeIsExor( pNode ); // 1 if EXOR, 0 if NEXOR
+
+ // create four clauses
+ Msat_IntVecClear( p->vProj );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pNode->Num, fComp) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pNode1->Num, fComp) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pNode2->Num, fComp) );
+ RetValue = Msat_SolverAddClause( p->pSat, p->vProj );
+ assert( RetValue );
+ Msat_IntVecClear( p->vProj );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pNode->Num, fComp) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pNode1->Num, !fComp) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pNode2->Num, !fComp) );
+ RetValue = Msat_SolverAddClause( p->pSat, p->vProj );
+ assert( RetValue );
+ Msat_IntVecClear( p->vProj );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pNode->Num, !fComp) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pNode1->Num, fComp) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pNode2->Num, !fComp) );
+ RetValue = Msat_SolverAddClause( p->pSat, p->vProj );
+ assert( RetValue );
+ Msat_IntVecClear( p->vProj );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pNode->Num, !fComp) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pNode1->Num, !fComp) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(pNode2->Num, fComp) );
+ RetValue = Msat_SolverAddClause( p->pSat, p->vProj );
+ assert( RetValue );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Adds clauses to the solver.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_SupergateAddClausesMux( Fraig_Man_t * p, Fraig_Node_t * pNode )
+{
+ Fraig_Node_t * pNodeI, * pNodeT, * pNodeE;
+ int RetValue, VarF, VarI, VarT, VarE, fCompT, fCompE;
+
+ assert( !Fraig_IsComplement( pNode ) );
+ assert( Fraig_NodeIsMuxType( pNode ) );
+ // get nodes (I = if, T = then, E = else)
+ pNodeI = Fraig_NodeRecognizeMux( pNode, &pNodeT, &pNodeE );
+ // get the variable numbers
+ VarF = pNode->Num;
+ VarI = pNodeI->Num;
+ VarT = Fraig_Regular(pNodeT)->Num;
+ VarE = Fraig_Regular(pNodeE)->Num;
+ // get the complementation flags
+ fCompT = Fraig_IsComplement(pNodeT);
+ fCompE = Fraig_IsComplement(pNodeE);
+
+ // f = ITE(i, t, e)
+
+ // i' + t' + f
+ // i' + t + f'
+ // i + e' + f
+ // i + e + f'
+
+ // create four clauses
+ Msat_IntVecClear( p->vProj );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(VarI, 1) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(VarT, 1^fCompT) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(VarF, 0) );
+ RetValue = Msat_SolverAddClause( p->pSat, p->vProj );
+ assert( RetValue );
+ Msat_IntVecClear( p->vProj );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(VarI, 1) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(VarT, 0^fCompT) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(VarF, 1) );
+ RetValue = Msat_SolverAddClause( p->pSat, p->vProj );
+ assert( RetValue );
+ Msat_IntVecClear( p->vProj );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(VarI, 0) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(VarE, 1^fCompE) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(VarF, 0) );
+ RetValue = Msat_SolverAddClause( p->pSat, p->vProj );
+ assert( RetValue );
+ Msat_IntVecClear( p->vProj );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(VarI, 0) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(VarE, 0^fCompE) );
+ Msat_IntVecPush( p->vProj, MSAT_VAR2LIT(VarF, 1) );
+ RetValue = Msat_SolverAddClause( p->pSat, p->vProj );
+ assert( RetValue );
+}
+
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Returns the array of nodes to be combined into one multi-input AND-gate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_DetectFanoutFreeCone_rec( Fraig_Node_t * pNode, Fraig_NodeVec_t * vSuper, Fraig_NodeVec_t * vInside, int fFirst )
+{
+ // make the pointer regular
+ pNode = Fraig_Regular(pNode);
+ // if the new node is complemented or a PI, another gate begins
+ if ( (!fFirst && pNode->nRefs > 1) || Fraig_NodeIsVar(pNode) )
+ {
+ Fraig_NodeVecPushUnique( vSuper, pNode );
+ return;
+ }
+ // go through the branches
+ Fraig_DetectFanoutFreeCone_rec( pNode->p1, vSuper, vInside, 0 );
+ Fraig_DetectFanoutFreeCone_rec( pNode->p2, vSuper, vInside, 0 );
+ // add the node
+ Fraig_NodeVecPushUnique( vInside, pNode );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the array of nodes to be combined into one multi-input AND-gate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+/*
+void Fraig_DetectFanoutFreeCone( Fraig_Man_t * pMan, Fraig_Node_t * pNode )
+{
+ Fraig_NodeVec_t * vFanins;
+ Fraig_NodeVec_t * vInside;
+ int nCubes;
+ extern int Fraig_CutSopCountCubes( Fraig_Man_t * pMan, Fraig_NodeVec_t * vFanins, Fraig_NodeVec_t * vInside );
+
+ vFanins = Fraig_NodeVecAlloc( 8 );
+ vInside = Fraig_NodeVecAlloc( 8 );
+
+ Fraig_DetectFanoutFreeCone_rec( pNode, vFanins, vInside, 1 );
+ assert( vInside->pArray[vInside->nSize-1] == pNode );
+
+ nCubes = Fraig_CutSopCountCubes( pMan, vFanins, vInside );
+
+printf( "%d(%d)", vFanins->nSize, nCubes );
+ Fraig_NodeVecFree( vFanins );
+ Fraig_NodeVecFree( vInside );
+}
+*/
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Returns the array of nodes to be combined into one multi-input AND-gate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_DetectFanoutFreeConeMux_rec( Fraig_Node_t * pNode, Fraig_NodeVec_t * vSuper, Fraig_NodeVec_t * vInside, int fFirst )
+{
+ // make the pointer regular
+ pNode = Fraig_Regular(pNode);
+ // if the new node is complemented or a PI, another gate begins
+ if ( (!fFirst && pNode->nRefs > 1) || Fraig_NodeIsVar(pNode) || !Fraig_NodeIsMuxType(pNode) )
+ {
+ Fraig_NodeVecPushUnique( vSuper, pNode );
+ return;
+ }
+ // go through the branches
+ Fraig_DetectFanoutFreeConeMux_rec( Fraig_Regular(pNode->p1)->p1, vSuper, vInside, 0 );
+ Fraig_DetectFanoutFreeConeMux_rec( Fraig_Regular(pNode->p1)->p2, vSuper, vInside, 0 );
+ Fraig_DetectFanoutFreeConeMux_rec( Fraig_Regular(pNode->p2)->p1, vSuper, vInside, 0 );
+ Fraig_DetectFanoutFreeConeMux_rec( Fraig_Regular(pNode->p2)->p2, vSuper, vInside, 0 );
+ // add the node
+ Fraig_NodeVecPushUnique( vInside, pNode );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the array of nodes to be combined into one multi-input AND-gate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_DetectFanoutFreeConeMux( Fraig_Man_t * pMan, Fraig_Node_t * pNode )
+{
+ Fraig_NodeVec_t * vFanins;
+ Fraig_NodeVec_t * vInside;
+ int nCubes;
+ extern int Fraig_CutSopCountCubes( Fraig_Man_t * pMan, Fraig_NodeVec_t * vFanins, Fraig_NodeVec_t * vInside );
+
+ vFanins = Fraig_NodeVecAlloc( 8 );
+ vInside = Fraig_NodeVecAlloc( 8 );
+
+ Fraig_DetectFanoutFreeConeMux_rec( pNode, vFanins, vInside, 1 );
+ assert( vInside->pArray[vInside->nSize-1] == pNode );
+
+// nCubes = Fraig_CutSopCountCubes( pMan, vFanins, vInside );
+ nCubes = 0;
+
+printf( "%d(%d)", vFanins->nSize, nCubes );
+ Fraig_NodeVecFree( vFanins );
+ Fraig_NodeVecFree( vInside );
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sat/fraig/fraigTable.c b/src/sat/fraig/fraigTable.c
new file mode 100644
index 00000000..5318c41e
--- /dev/null
+++ b/src/sat/fraig/fraigTable.c
@@ -0,0 +1,596 @@
+/**CFile****************************************************************
+
+ FileName [fraigTable.c]
+
+ PackageName [FRAIG: Functionally reduced AND-INV graphs.]
+
+ Synopsis [Structural and functional hash tables.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - October 1, 2004]
+
+ Revision [$Id: fraigTable.c,v 1.7 2005/07/08 01:01:34 alanmi Exp $]
+
+***********************************************************************/
+
+#include "fraigInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Fraig_TableResizeS( Fraig_HashTable_t * p );
+static void Fraig_TableResizeF( Fraig_HashTable_t * p, int fUseSimR );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Allocates the hash table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_HashTable_t * Fraig_HashTableCreate( int nSize )
+{
+ Fraig_HashTable_t * p;
+ // allocate the table
+ p = ALLOC( Fraig_HashTable_t, 1 );
+ memset( p, 0, sizeof(Fraig_HashTable_t) );
+ // allocate and clean the bins
+ p->nBins = Cudd_PrimeFraig(nSize);
+ p->pBins = ALLOC( Fraig_Node_t *, p->nBins );
+ memset( p->pBins, 0, sizeof(Fraig_Node_t *) * p->nBins );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Deallocates the supergate hash table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_HashTableFree( Fraig_HashTable_t * p )
+{
+ FREE( p->pBins );
+ FREE( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Looks up an entry in the structural hash table.]
+
+ Description [If the entry with the same children does not exists,
+ creates it, inserts it into the table, and returns 0. If the entry
+ with the same children exists, finds it, and return 1. In both cases,
+ the new/old entry is returned in ppNodeRes.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_HashTableLookupS( Fraig_Man_t * pMan, Fraig_Node_t * p1, Fraig_Node_t * p2, Fraig_Node_t ** ppNodeRes )
+{
+ Fraig_HashTable_t * p = pMan->pTableS;
+ Fraig_Node_t * pEnt;
+ unsigned Key;
+
+ // order the arguments
+ if ( Fraig_Regular(p1)->Num > Fraig_Regular(p2)->Num )
+ pEnt = p1, p1 = p2, p2 = pEnt;
+
+ Key = Fraig_HashKey2( p1, p2, p->nBins );
+ Fraig_TableBinForEachEntryS( p->pBins[Key], pEnt )
+ if ( pEnt->p1 == p1 && pEnt->p2 == p2 )
+ {
+ *ppNodeRes = pEnt;
+ return 1;
+ }
+ // check if it is a good time for table resizing
+ if ( p->nEntries >= 2 * p->nBins )
+ {
+ Fraig_TableResizeS( p );
+ Key = Fraig_HashKey2( p1, p2, p->nBins );
+ }
+ // create the new node
+ pEnt = Fraig_NodeCreate( pMan, p1, p2 );
+ // add the node to the corresponding linked list in the table
+ pEnt->pNextS = p->pBins[Key];
+ p->pBins[Key] = pEnt;
+ *ppNodeRes = pEnt;
+ p->nEntries++;
+ return 0;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Insert the entry in the functional hash table.]
+
+ Description [If the entry with the same key exists, return it right away.
+ If the entry with the same key does not exists, inserts it and returns NULL. ]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_Node_t * Fraig_HashTableLookupF( Fraig_Man_t * pMan, Fraig_Node_t * pNode )
+{
+ Fraig_HashTable_t * p = pMan->pTableF;
+ Fraig_Node_t * pEnt, * pEntD;
+ unsigned Key;
+
+ // go through the hash table entries
+ Key = pNode->uHashR % p->nBins;
+ Fraig_TableBinForEachEntryF( p->pBins[Key], pEnt )
+ {
+ // if their simulation info differs, skip
+ if ( !Fraig_CompareSimInfo( pNode, pEnt, pMan->nWordsRand, 1 ) )
+ continue;
+ // equivalent up to the complement
+ Fraig_TableBinForEachEntryD( pEnt, pEntD )
+ {
+ // if their simulation info differs, skip
+ if ( !Fraig_CompareSimInfo( pNode, pEntD, pMan->iWordStart, 0 ) )
+ continue;
+ // found a simulation-equivalent node
+ return pEntD;
+ }
+ // did not find a simulation equivalent node
+ // add the node to the corresponding linked list
+ pNode->pNextD = pEnt->pNextD;
+ pEnt->pNextD = pNode;
+ // return NULL, because there is no functional equivalence in this case
+ return NULL;
+ }
+
+ // check if it is a good time for table resizing
+ if ( p->nEntries >= 2 * p->nBins )
+ {
+ Fraig_TableResizeF( p, 1 );
+ Key = pNode->uHashR % p->nBins;
+ }
+
+ // add the node to the corresponding linked list in the table
+ pNode->pNextF = p->pBins[Key];
+ p->pBins[Key] = pNode;
+ p->nEntries++;
+ // return NULL, because there is no functional equivalence in this case
+ return NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Insert the entry in the functional hash table.]
+
+ Description [If the entry with the same key exists, return it right away.
+ If the entry with the same key does not exists, inserts it and returns NULL. ]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_Node_t * Fraig_HashTableLookupF0( Fraig_Man_t * pMan, Fraig_Node_t * pNode )
+{
+ Fraig_HashTable_t * p = pMan->pTableF0;
+ Fraig_Node_t * pEnt;
+ unsigned Key;
+
+ // go through the hash table entries
+ Key = pNode->uHashD % p->nBins;
+ Fraig_TableBinForEachEntryF( p->pBins[Key], pEnt )
+ {
+ // if their simulation info differs, skip
+ if ( !Fraig_CompareSimInfo( pNode, pEnt, pMan->iWordStart, 0 ) )
+ continue;
+ // found a simulation-equivalent node
+ return pEnt;
+ }
+
+ // check if it is a good time for table resizing
+ if ( p->nEntries >= 2 * p->nBins )
+ {
+ Fraig_TableResizeF( p, 0 );
+ Key = pNode->uHashD % p->nBins;
+ }
+
+ // add the node to the corresponding linked list in the table
+ pNode->pNextF = p->pBins[Key];
+ p->pBins[Key] = pNode;
+ p->nEntries++;
+ // return NULL, because there is no functional equivalence in this case
+ return NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Insert the entry in the functional hash table.]
+
+ Description [Unconditionally add the node to the corresponding
+ linked list in the table.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_HashTableInsertF0( Fraig_Man_t * pMan, Fraig_Node_t * pNode )
+{
+ Fraig_HashTable_t * p = pMan->pTableF0;
+ unsigned Key = pNode->uHashD % p->nBins;
+
+ pNode->pNextF = p->pBins[Key];
+ p->pBins[Key] = pNode;
+ p->nEntries++;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Resizes the table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_TableResizeS( Fraig_HashTable_t * p )
+{
+ Fraig_Node_t ** pBinsNew;
+ Fraig_Node_t * pEnt, * pEnt2;
+ int nBinsNew, Counter, i, clk;
+ unsigned Key;
+
+clk = clock();
+ // get the new table size
+ nBinsNew = Cudd_PrimeFraig(2 * p->nBins);
+ // allocate a new array
+ pBinsNew = ALLOC( Fraig_Node_t *, nBinsNew );
+ memset( pBinsNew, 0, sizeof(Fraig_Node_t *) * nBinsNew );
+ // rehash the entries from the old table
+ Counter = 0;
+ for ( i = 0; i < p->nBins; i++ )
+ Fraig_TableBinForEachEntrySafeS( p->pBins[i], pEnt, pEnt2 )
+ {
+ Key = Fraig_HashKey2( pEnt->p1, pEnt->p2, nBinsNew );
+ pEnt->pNextS = pBinsNew[Key];
+ pBinsNew[Key] = pEnt;
+ Counter++;
+ }
+ assert( Counter == p->nEntries );
+// printf( "Increasing the structural table size from %6d to %6d. ", p->nBins, nBinsNew );
+// PRT( "Time", clock() - clk );
+ // replace the table and the parameters
+ free( p->pBins );
+ p->pBins = pBinsNew;
+ p->nBins = nBinsNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Resizes the table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_TableResizeF( Fraig_HashTable_t * p, int fUseSimR )
+{
+ Fraig_Node_t ** pBinsNew;
+ Fraig_Node_t * pEnt, * pEnt2;
+ int nBinsNew, Counter, i, clk;
+ unsigned Key;
+
+clk = clock();
+ // get the new table size
+ nBinsNew = Cudd_PrimeFraig(2 * p->nBins);
+ // allocate a new array
+ pBinsNew = ALLOC( Fraig_Node_t *, nBinsNew );
+ memset( pBinsNew, 0, sizeof(Fraig_Node_t *) * nBinsNew );
+ // rehash the entries from the old table
+ Counter = 0;
+ for ( i = 0; i < p->nBins; i++ )
+ Fraig_TableBinForEachEntrySafeF( p->pBins[i], pEnt, pEnt2 )
+ {
+ if ( fUseSimR )
+ Key = pEnt->uHashR % nBinsNew;
+ else
+ Key = pEnt->uHashD % nBinsNew;
+ pEnt->pNextF = pBinsNew[Key];
+ pBinsNew[Key] = pEnt;
+ Counter++;
+ }
+ assert( Counter == p->nEntries );
+// printf( "Increasing the functional table size from %6d to %6d. ", p->nBins, nBinsNew );
+// PRT( "Time", clock() - clk );
+ // replace the table and the parameters
+ free( p->pBins );
+ p->pBins = pBinsNew;
+ p->nBins = nBinsNew;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Compares two pieces of simulation info.]
+
+ Description [Returns 1 if they are equal.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_CompareSimInfo( Fraig_Node_t * pNode1, Fraig_Node_t * pNode2, int iWordLast, int fUseRand )
+{
+ int i;
+ assert( !Fraig_IsComplement(pNode1) );
+ assert( !Fraig_IsComplement(pNode2) );
+ if ( fUseRand )
+ {
+ // if their signatures differ, skip
+ if ( pNode1->uHashR != pNode2->uHashR )
+ return 0;
+ // check the simulation info
+ for ( i = 0; i < iWordLast; i++ )
+ if ( pNode1->puSimR[i] != pNode2->puSimR[i] )
+ return 0;
+ }
+ else
+ {
+ // if their signatures differ, skip
+ if ( pNode1->uHashD != pNode2->uHashD )
+ return 0;
+ // check the simulation info
+ for ( i = 0; i < iWordLast; i++ )
+ if ( pNode1->puSimD[i] != pNode2->puSimD[i] )
+ return 0;
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares two pieces of simulation info.]
+
+ Description [Returns 1 if they are equal.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_CompareSimInfoUnderMask( Fraig_Node_t * pNode1, Fraig_Node_t * pNode2, int iWordLast, int fUseRand, unsigned * puMask )
+{
+ unsigned * pSims1, * pSims2;
+ int i;
+ assert( !Fraig_IsComplement(pNode1) );
+ assert( !Fraig_IsComplement(pNode2) );
+ // get hold of simulation info
+ pSims1 = fUseRand? pNode1->puSimR : pNode1->puSimD;
+ pSims2 = fUseRand? pNode2->puSimR : pNode2->puSimD;
+ // check the simulation info
+ for ( i = 0; i < iWordLast; i++ )
+ if ( (pSims1[i] & puMask[i]) != (pSims2[i] & puMask[i]) )
+ return 0;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares two pieces of simulation info.]
+
+ Description [Returns 1 if they are equal.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_CollectXors( Fraig_Node_t * pNode1, Fraig_Node_t * pNode2, int iWordLast, int fUseRand, unsigned * puMask )
+{
+ unsigned * pSims1, * pSims2;
+ int i;
+ assert( !Fraig_IsComplement(pNode1) );
+ assert( !Fraig_IsComplement(pNode2) );
+ // get hold of simulation info
+ pSims1 = fUseRand? pNode1->puSimR : pNode1->puSimD;
+ pSims2 = fUseRand? pNode2->puSimR : pNode2->puSimD;
+ // check the simulation info
+ for ( i = 0; i < iWordLast; i++ )
+ puMask[i] = ( pSims1[i] ^ pSims2[i] );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Prints stats of the structural table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_TablePrintStatsS( Fraig_Man_t * pMan )
+{
+ Fraig_HashTable_t * pT = pMan->pTableS;
+ Fraig_Node_t * pNode;
+ int i, Counter;
+
+ printf( "Structural table. Table size = %d. Number of entries = %d.\n", pT->nBins, pT->nEntries );
+ for ( i = 0; i < pT->nBins; i++ )
+ {
+ Counter = 0;
+ Fraig_TableBinForEachEntryS( pT->pBins[i], pNode )
+ Counter++;
+ if ( Counter > 1 )
+ {
+ printf( "%d ", Counter );
+ if ( Counter > 50 )
+ printf( "{%d} ", i );
+ }
+ }
+ printf( "\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints stats of the structural table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_TablePrintStatsF( Fraig_Man_t * pMan )
+{
+ Fraig_HashTable_t * pT = pMan->pTableF;
+ Fraig_Node_t * pNode;
+ int i, Counter;
+
+ printf( "Functional table. Table size = %d. Number of entries = %d.\n", pT->nBins, pT->nEntries );
+ for ( i = 0; i < pT->nBins; i++ )
+ {
+ Counter = 0;
+ Fraig_TableBinForEachEntryF( pT->pBins[i], pNode )
+ Counter++;
+ if ( Counter > 1 )
+ printf( "{%d} ", Counter );
+ }
+ printf( "\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints stats of the structural table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_TablePrintStatsF0( Fraig_Man_t * pMan )
+{
+ Fraig_HashTable_t * pT = pMan->pTableF0;
+ Fraig_Node_t * pNode;
+ int i, Counter;
+
+ printf( "Zero-node table. Table size = %d. Number of entries = %d.\n", pT->nBins, pT->nEntries );
+ for ( i = 0; i < pT->nBins; i++ )
+ {
+ Counter = 0;
+ Fraig_TableBinForEachEntryF( pT->pBins[i], pNode )
+ Counter++;
+ if ( Counter == 0 )
+ continue;
+/*
+ printf( "\nBin = %4d : Number of entries = %4d\n", i, Counter );
+ Fraig_TableBinForEachEntryF( pT->pBins[i], pNode )
+ printf( "Node %5d. Hash = %10d.\n", pNode->Num, pNode->uHashD );
+*/
+ }
+ printf( "\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Rehashes the table after the simulation info has changed.]
+
+ Description [Assumes that the hash values have been updated after performing
+ additional simulation. Rehashes the table using the new hash values.
+ Uses pNextF to link the entries in the bins. Uses pNextD to link the entries
+ with identical hash values. Returns 1 if the identical entries have been found.
+ Note that identical hash values may mean that the simulation data is different.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_TableRehashF0( Fraig_Man_t * pMan, int fLinkEquiv )
+{
+ Fraig_HashTable_t * pT = pMan->pTableF0;
+ Fraig_Node_t ** pBinsNew;
+ Fraig_Node_t * pEntF, * pEntF2, * pEnt, * pEntD2, * pEntN;
+ int ReturnValue, Counter, i;
+ unsigned Key;
+
+ // allocate a new array of bins
+ pBinsNew = ALLOC( Fraig_Node_t *, pT->nBins );
+ memset( pBinsNew, 0, sizeof(Fraig_Node_t *) * pT->nBins );
+
+ // rehash the entries in the table
+ // go through all the nodes in the F-lists (and possible in D-lists, if used)
+ Counter = 0;
+ ReturnValue = 0;
+ for ( i = 0; i < pT->nBins; i++ )
+ Fraig_TableBinForEachEntrySafeF( pT->pBins[i], pEntF, pEntF2 )
+ Fraig_TableBinForEachEntrySafeD( pEntF, pEnt, pEntD2 )
+ {
+ // decide where to put entry pEnt
+ Key = pEnt->uHashD % pT->nBins;
+ if ( fLinkEquiv )
+ {
+ // go through the entries in the new bin
+ Fraig_TableBinForEachEntryF( pBinsNew[Key], pEntN )
+ {
+ // if they have different values skip
+ if ( pEnt->uHashD != pEntN->uHashD )
+ continue;
+ // they have the same hash value, add pEnt to the D-list pEnt3
+ pEnt->pNextD = pEntN->pNextD;
+ pEntN->pNextD = pEnt;
+ ReturnValue = 1;
+ Counter++;
+ break;
+ }
+ if ( pEntN != NULL ) // already linked
+ continue;
+ // we did not find equal entry
+ }
+ // link the new entry
+ pEnt->pNextF = pBinsNew[Key];
+ pBinsNew[Key] = pEnt;
+ pEnt->pNextD = NULL;
+ Counter++;
+ }
+ assert( Counter == pT->nEntries );
+ // replace the table and the parameters
+ free( pT->pBins );
+ pT->pBins = pBinsNew;
+ return ReturnValue;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sat/fraig/fraigUtil.c b/src/sat/fraig/fraigUtil.c
new file mode 100644
index 00000000..6b7431f2
--- /dev/null
+++ b/src/sat/fraig/fraigUtil.c
@@ -0,0 +1,969 @@
+/**CFile****************************************************************
+
+ FileName [fraigUtil.c]
+
+ PackageName [FRAIG: Functionally reduced AND-INV graphs.]
+
+ Synopsis [Various utilities.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - October 1, 2004]
+
+ Revision [$Id: fraigUtil.c,v 1.15 2005/07/08 01:01:34 alanmi Exp $]
+
+***********************************************************************/
+
+#include "fraigInt.h"
+#include <limits.h>
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int bit_count[256] = {
+ 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
+ 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
+ 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
+ 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
+ 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
+ 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
+ 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
+ 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
+};
+
+static void Fraig_Dfs_rec( Fraig_Man_t * pMan, Fraig_Node_t * pNode, Fraig_NodeVec_t * vNodes, int fEquiv );
+static int Fraig_CheckTfi_rec( Fraig_Man_t * pMan, Fraig_Node_t * pNode, Fraig_Node_t * pOld );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_NodeVec_t * Fraig_Dfs( Fraig_Man_t * pMan, int fEquiv )
+{
+ Fraig_NodeVec_t * vNodes;
+ int i;
+ pMan->nTravIds++;
+ vNodes = Fraig_NodeVecAlloc( 100 );
+ for ( i = 0; i < pMan->vOutputs->nSize; i++ )
+ Fraig_Dfs_rec( pMan, Fraig_Regular(pMan->vOutputs->pArray[i]), vNodes, fEquiv );
+ return vNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_NodeVec_t * Fraig_DfsOne( Fraig_Man_t * pMan, Fraig_Node_t * pNode, int fEquiv )
+{
+ Fraig_NodeVec_t * vNodes;
+ pMan->nTravIds++;
+ vNodes = Fraig_NodeVecAlloc( 100 );
+ Fraig_Dfs_rec( pMan, Fraig_Regular(pNode), vNodes, fEquiv );
+ return vNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_NodeVec_t * Fraig_DfsNodes( Fraig_Man_t * pMan, Fraig_Node_t ** ppNodes, int nNodes, int fEquiv )
+{
+ Fraig_NodeVec_t * vNodes;
+ int i;
+ pMan->nTravIds++;
+ vNodes = Fraig_NodeVecAlloc( 100 );
+ for ( i = 0; i < nNodes; i++ )
+ Fraig_Dfs_rec( pMan, Fraig_Regular(ppNodes[i]), vNodes, fEquiv );
+ return vNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_Dfs_rec( Fraig_Man_t * pMan, Fraig_Node_t * pNode, Fraig_NodeVec_t * vNodes, int fEquiv )
+{
+ assert( !Fraig_IsComplement(pNode) );
+ // skip the visited node
+ if ( pNode->TravId == pMan->nTravIds )
+ return;
+ pNode->TravId = pMan->nTravIds;
+ // visit the transitive fanin
+ if ( Fraig_NodeIsAnd(pNode) )
+ {
+ Fraig_Dfs_rec( pMan, Fraig_Regular(pNode->p1), vNodes, fEquiv );
+ Fraig_Dfs_rec( pMan, Fraig_Regular(pNode->p2), vNodes, fEquiv );
+ }
+ if ( fEquiv && pNode->pNextE )
+ Fraig_Dfs_rec( pMan, pNode->pNextE, vNodes, fEquiv );
+ // save the node
+ Fraig_NodeVecPush( vNodes, pNode );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_CountNodes( Fraig_Man_t * pMan, int fEquiv )
+{
+ Fraig_NodeVec_t * vNodes;
+ int RetValue;
+ vNodes = Fraig_Dfs( pMan, fEquiv );
+ RetValue = vNodes->nSize;
+ Fraig_NodeVecFree( vNodes );
+ return RetValue;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if pOld is in the TFI of pNew.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_CheckTfi( Fraig_Man_t * pMan, Fraig_Node_t * pOld, Fraig_Node_t * pNew )
+{
+ assert( !Fraig_IsComplement(pOld) );
+ assert( !Fraig_IsComplement(pNew) );
+ pMan->nTravIds++;
+ return Fraig_CheckTfi_rec( pMan, pNew, pOld );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if pOld is in the TFI of pNew.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_CheckTfi_rec( Fraig_Man_t * pMan, Fraig_Node_t * pNode, Fraig_Node_t * pOld )
+{
+ // check the trivial cases
+ if ( pNode == NULL )
+ return 0;
+ if ( pNode->Num < pOld->Num && !pMan->fChoicing )
+ return 0;
+ if ( pNode == pOld )
+ return 1;
+ // skip the visited node
+ if ( pNode->TravId == pMan->nTravIds )
+ return 0;
+ pNode->TravId = pMan->nTravIds;
+ // check the children
+ if ( Fraig_CheckTfi_rec( pMan, Fraig_Regular(pNode->p1), pOld ) )
+ return 1;
+ if ( Fraig_CheckTfi_rec( pMan, Fraig_Regular(pNode->p2), pOld ) )
+ return 1;
+ // check equivalent nodes
+ return Fraig_CheckTfi_rec( pMan, pNode->pNextE, pOld );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if pOld is in the TFI of pNew.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_CheckTfi2( Fraig_Man_t * pMan, Fraig_Node_t * pOld, Fraig_Node_t * pNew )
+{
+ Fraig_NodeVec_t * vNodes;
+ int RetValue;
+ vNodes = Fraig_DfsOne( pMan, pNew, 1 );
+ RetValue = (pOld->TravId == pMan->nTravIds);
+ Fraig_NodeVecFree( vNodes );
+ return RetValue;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the number of fanouts (none, one, or many).]
+
+ Description [This procedure collects the nodes reachable from
+ the POs of the AIG and sets the type of fanout counter (none, one,
+ or many) for each node. This procedure is useful to determine
+ fanout-free cones of AND-nodes, which is helpful for rebalancing
+ the AIG (see procedure Fraig_ManRebalance, or something like that).]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_ManMarkRealFanouts( Fraig_Man_t * p )
+{
+ Fraig_NodeVec_t * vNodes;
+ Fraig_Node_t * pNodeR;
+ int i;
+ // collect the nodes reachable
+ vNodes = Fraig_Dfs( p, 0 );
+ // clean the fanouts field
+ for ( i = 0; i < vNodes->nSize; i++ )
+ {
+ vNodes->pArray[i]->nFanouts = 0;
+ vNodes->pArray[i]->pData0 = NULL;
+ }
+ // mark reachable nodes by setting the two-bit counter pNode->nFans
+ for ( i = 0; i < vNodes->nSize; i++ )
+ {
+ pNodeR = Fraig_Regular(vNodes->pArray[i]->p1);
+ if ( pNodeR && ++pNodeR->nFanouts == 3 )
+ pNodeR->nFanouts = 2;
+ pNodeR = Fraig_Regular(vNodes->pArray[i]->p2);
+ if ( pNodeR && ++pNodeR->nFanouts == 3 )
+ pNodeR->nFanouts = 2;
+ }
+ Fraig_NodeVecFree( vNodes );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates the constant 1 node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_BitStringCountOnes( unsigned * pString, int nWords )
+{
+ unsigned char * pSuppBytes = (unsigned char *)pString;
+ int i, nOnes, nBytes = sizeof(unsigned) * nWords;
+ // count the number of ones in the simulation vector
+ for ( i = nOnes = 0; i < nBytes; i++ )
+ nOnes += bit_count[pSuppBytes[i]];
+ return nOnes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Verify one useful property.]
+
+ Description [This procedure verifies one useful property. After
+ the FRAIG construction with choice nodes is over, each primary node
+ should have fanins that are primary nodes. The primary nodes is the
+ one that does not have pNode->pRepr set to point to another node.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_ManCheckConsistency( Fraig_Man_t * p )
+{
+ Fraig_Node_t * pNode;
+ Fraig_NodeVec_t * pVec;
+ int i;
+ pVec = Fraig_Dfs( p, 0 );
+ for ( i = 0; i < pVec->nSize; i++ )
+ {
+ pNode = pVec->pArray[i];
+ if ( Fraig_NodeIsVar(pNode) )
+ {
+ if ( pNode->pRepr )
+ printf( "Primary input %d is a secondary node.\n", pNode->Num );
+ }
+ else if ( Fraig_NodeIsConst(pNode) )
+ {
+ if ( pNode->pRepr )
+ printf( "Constant 1 %d is a secondary node.\n", pNode->Num );
+ }
+ else
+ {
+ if ( pNode->pRepr )
+ printf( "Internal node %d is a secondary node.\n", pNode->Num );
+ if ( Fraig_Regular(pNode->p1)->pRepr )
+ printf( "Internal node %d has first fanin %d that is a secondary node.\n",
+ pNode->Num, Fraig_Regular(pNode->p1)->Num );
+ if ( Fraig_Regular(pNode->p2)->pRepr )
+ printf( "Internal node %d has second fanin %d that is a secondary node.\n",
+ pNode->Num, Fraig_Regular(pNode->p2)->Num );
+ }
+ }
+ Fraig_NodeVecFree( pVec );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_PrintNode( Fraig_Man_t * p, Fraig_Node_t * pNode )
+{
+ Fraig_NodeVec_t * vNodes;
+ Fraig_Node_t * pTemp;
+ int fCompl1, fCompl2, i;
+
+ vNodes = Fraig_DfsOne( p, pNode, 0 );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ {
+ pTemp = vNodes->pArray[i];
+ if ( Fraig_NodeIsVar(pTemp) )
+ {
+ printf( "%3d : PI ", pTemp->Num );
+ Fraig_PrintBinary( stdout, (unsigned *)&pTemp->puSimR, 20 );
+ printf( " " );
+ Fraig_PrintBinary( stdout, (unsigned *)&pTemp->puSimD, 20 );
+ printf( " %d\n", pTemp->fInv );
+ continue;
+ }
+
+ fCompl1 = Fraig_IsComplement(pTemp->p1);
+ fCompl2 = Fraig_IsComplement(pTemp->p2);
+ printf( "%3d : %c%3d %c%3d ", pTemp->Num,
+ (fCompl1? '-':'+'), Fraig_Regular(pTemp->p1)->Num,
+ (fCompl2? '-':'+'), Fraig_Regular(pTemp->p2)->Num );
+ Fraig_PrintBinary( stdout, (unsigned *)&pTemp->puSimR, 20 );
+ printf( " " );
+ Fraig_PrintBinary( stdout, (unsigned *)&pTemp->puSimD, 20 );
+ printf( " %d\n", pTemp->fInv );
+ }
+ Fraig_NodeVecFree( vNodes );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the bit string.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_PrintBinary( FILE * pFile, unsigned * pSign, int nBits )
+{
+ int Remainder, nWords;
+ int w, i;
+
+ Remainder = (nBits%(sizeof(unsigned)*8));
+ nWords = (nBits/(sizeof(unsigned)*8)) + (Remainder>0);
+
+ for ( w = nWords-1; w >= 0; w-- )
+ for ( i = ((w == nWords-1 && Remainder)? Remainder-1: 31); i >= 0; i-- )
+ fprintf( pFile, "%c", '0' + (int)((pSign[w] & (1<<i)) > 0) );
+
+// fprintf( pFile, "\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets up the mask.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_GetMaxLevel( Fraig_Man_t * pMan )
+{
+ int nLevelMax, i;
+ nLevelMax = 0;
+ for ( i = 0; i < pMan->vOutputs->nSize; i++ )
+ nLevelMax = nLevelMax > Fraig_Regular(pMan->vOutputs->pArray[i])->Level?
+ nLevelMax : Fraig_Regular(pMan->vOutputs->pArray[i])->Level;
+ return nLevelMax;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Analyses choice nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_MappingUpdateLevel_rec( Fraig_Man_t * pMan, Fraig_Node_t * pNode, int fMaximum )
+{
+ Fraig_Node_t * pTemp;
+ int Level1, Level2, LevelE;
+ assert( !Fraig_IsComplement(pNode) );
+ if ( !Fraig_NodeIsAnd(pNode) )
+ return pNode->Level;
+ // skip the visited node
+ if ( pNode->TravId == pMan->nTravIds )
+ return pNode->Level;
+ pNode->TravId = pMan->nTravIds;
+ // compute levels of the children nodes
+ Level1 = Fraig_MappingUpdateLevel_rec( pMan, Fraig_Regular(pNode->p1), fMaximum );
+ Level2 = Fraig_MappingUpdateLevel_rec( pMan, Fraig_Regular(pNode->p2), fMaximum );
+ pNode->Level = 1 + FRAIG_MAX( Level1, Level2 );
+ if ( pNode->pNextE )
+ {
+ LevelE = Fraig_MappingUpdateLevel_rec( pMan, pNode->pNextE, fMaximum );
+ if ( fMaximum )
+ {
+ if ( pNode->Level < LevelE )
+ pNode->Level = LevelE;
+ }
+ else
+ {
+ if ( pNode->Level > LevelE )
+ pNode->Level = LevelE;
+ }
+ // set the level of all equivalent nodes to be the same minimum
+ if ( pNode->pRepr == NULL ) // the primary node
+ for ( pTemp = pNode->pNextE; pTemp; pTemp = pTemp->pNextE )
+ pTemp->Level = pNode->Level;
+ }
+ return pNode->Level;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Resets the levels of the nodes in the choice graph.]
+
+ Description [Makes the level of the choice nodes to be equal to the
+ maximum of the level of the nodes in the equivalence class. This way
+ sorting by level leads to the reverse topological order, which is
+ needed for the required time computation.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_MappingSetChoiceLevels( Fraig_Man_t * pMan, int fMaximum )
+{
+ int i;
+ pMan->nTravIds++;
+ for ( i = 0; i < pMan->vOutputs->nSize; i++ )
+ Fraig_MappingUpdateLevel_rec( pMan, Fraig_Regular(pMan->vOutputs->pArray[i]), fMaximum );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reports statistics on choice nodes.]
+
+ Description [The number of choice nodes is the number of primary nodes,
+ which has pNextE set to a pointer. The number of choices is the number
+ of entries in the equivalent-node lists of the primary nodes.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_ManReportChoices( Fraig_Man_t * pMan )
+{
+ Fraig_Node_t * pNode, * pTemp;
+ int nChoiceNodes, nChoices;
+ int i, LevelMax1, LevelMax2;
+
+ // report the number of levels
+ LevelMax1 = Fraig_GetMaxLevel( pMan );
+ Fraig_MappingSetChoiceLevels( pMan, 0 );
+ LevelMax2 = Fraig_GetMaxLevel( pMan );
+
+ // report statistics about choices
+ nChoiceNodes = nChoices = 0;
+ for ( i = 0; i < pMan->vNodes->nSize; i++ )
+ {
+ pNode = pMan->vNodes->pArray[i];
+ if ( pNode->pRepr == NULL && pNode->pNextE != NULL )
+ { // this is a choice node = the primary node that has equivalent nodes
+ nChoiceNodes++;
+ for ( pTemp = pNode; pTemp; pTemp = pTemp->pNextE )
+ nChoices++;
+ }
+ }
+ printf( "Maximum level: Original = %d. Reduced due to choices = %d.\n", LevelMax1, LevelMax2 );
+ printf( "Choice stats: Choice nodes = %d. Total choices = %d.\n", nChoiceNodes, nChoices );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if the node is the root of EXOR/NEXOR gate.]
+
+ Description [The node can be complemented.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_NodeIsExorType( Fraig_Node_t * pNode )
+{
+ Fraig_Node_t * pNode1, * pNode2;
+ // make the node regular (it does not matter for EXOR/NEXOR)
+ pNode = Fraig_Regular(pNode);
+ // if the node or its children are not ANDs or not compl, this cannot be EXOR type
+ if ( !Fraig_NodeIsAnd(pNode) )
+ return 0;
+ if ( !Fraig_NodeIsAnd(pNode->p1) || !Fraig_IsComplement(pNode->p1) )
+ return 0;
+ if ( !Fraig_NodeIsAnd(pNode->p2) || !Fraig_IsComplement(pNode->p2) )
+ return 0;
+
+ // get children
+ pNode1 = Fraig_Regular(pNode->p1);
+ pNode2 = Fraig_Regular(pNode->p2);
+ assert( pNode1->Num < pNode2->Num );
+
+ // compare grandchildren
+ return pNode1->p1 == Fraig_Not(pNode2->p1) && pNode1->p2 == Fraig_Not(pNode2->p2);
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if the node is the root of MUX or EXOR/NEXOR.]
+
+ Description [The node can be complemented.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_NodeIsMuxType( Fraig_Node_t * pNode )
+{
+ Fraig_Node_t * pNode1, * pNode2;
+
+ // make the node regular (it does not matter for EXOR/NEXOR)
+ pNode = Fraig_Regular(pNode);
+ // if the node or its children are not ANDs or not compl, this cannot be EXOR type
+ if ( !Fraig_NodeIsAnd(pNode) )
+ return 0;
+ if ( !Fraig_NodeIsAnd(pNode->p1) || !Fraig_IsComplement(pNode->p1) )
+ return 0;
+ if ( !Fraig_NodeIsAnd(pNode->p2) || !Fraig_IsComplement(pNode->p2) )
+ return 0;
+
+ // get children
+ pNode1 = Fraig_Regular(pNode->p1);
+ pNode2 = Fraig_Regular(pNode->p2);
+ assert( pNode1->Num < pNode2->Num );
+
+ // compare grandchildren
+ // node is an EXOR/NEXOR
+ if ( pNode1->p1 == Fraig_Not(pNode2->p1) && pNode1->p2 == Fraig_Not(pNode2->p2) )
+ return 1;
+
+ // otherwise the node is MUX iff it has a pair of equal grandchildren
+ return pNode1->p1 == Fraig_Not(pNode2->p1) ||
+ pNode1->p1 == Fraig_Not(pNode2->p2) ||
+ pNode1->p2 == Fraig_Not(pNode2->p1) ||
+ pNode1->p2 == Fraig_Not(pNode2->p2);
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if the node is EXOR, 0 if it is NEXOR.]
+
+ Description [The node should be EXOR type and not complemented.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_NodeIsExor( Fraig_Node_t * pNode )
+{
+ Fraig_Node_t * pNode1;
+ assert( !Fraig_IsComplement(pNode) );
+ assert( Fraig_NodeIsExorType(pNode) );
+ assert( Fraig_IsComplement(pNode->p1) );
+ // get children
+ pNode1 = Fraig_Regular(pNode->p1);
+ return Fraig_IsComplement(pNode1->p1) == Fraig_IsComplement(pNode1->p2);
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recognizes what nodes are control and data inputs of a MUX.]
+
+ Description [If the node is a MUX, returns the control variable C.
+ Assigns nodes T and E to be the then and else variables of the MUX.
+ Node C is never complemented. Nodes T and E can be complemented.
+ This function also recognizes EXOR/NEXOR gates as MUXes.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_Node_t * Fraig_NodeRecognizeMux( Fraig_Node_t * pNode, Fraig_Node_t ** ppNodeT, Fraig_Node_t ** ppNodeE )
+{
+ Fraig_Node_t * pNode1, * pNode2;
+ assert( !Fraig_IsComplement(pNode) );
+ assert( Fraig_NodeIsMuxType(pNode) );
+ // get children
+ pNode1 = Fraig_Regular(pNode->p1);
+ pNode2 = Fraig_Regular(pNode->p2);
+ // find the control variable
+ if ( pNode1->p1 == Fraig_Not(pNode2->p1) )
+ {
+ if ( Fraig_IsComplement(pNode1->p1) )
+ { // pNode2->p1 is positive phase of C
+ *ppNodeT = Fraig_Not(pNode2->p2);
+ *ppNodeE = Fraig_Not(pNode1->p2);
+ return pNode2->p1;
+ }
+ else
+ { // pNode1->p1 is positive phase of C
+ *ppNodeT = Fraig_Not(pNode1->p2);
+ *ppNodeE = Fraig_Not(pNode2->p2);
+ return pNode1->p1;
+ }
+ }
+ else if ( pNode1->p1 == Fraig_Not(pNode2->p2) )
+ {
+ if ( Fraig_IsComplement(pNode1->p1) )
+ { // pNode2->p2 is positive phase of C
+ *ppNodeT = Fraig_Not(pNode2->p1);
+ *ppNodeE = Fraig_Not(pNode1->p2);
+ return pNode2->p2;
+ }
+ else
+ { // pNode1->p1 is positive phase of C
+ *ppNodeT = Fraig_Not(pNode1->p2);
+ *ppNodeE = Fraig_Not(pNode2->p1);
+ return pNode1->p1;
+ }
+ }
+ else if ( pNode1->p2 == Fraig_Not(pNode2->p1) )
+ {
+ if ( Fraig_IsComplement(pNode1->p2) )
+ { // pNode2->p1 is positive phase of C
+ *ppNodeT = Fraig_Not(pNode2->p2);
+ *ppNodeE = Fraig_Not(pNode1->p1);
+ return pNode2->p1;
+ }
+ else
+ { // pNode1->p2 is positive phase of C
+ *ppNodeT = Fraig_Not(pNode1->p1);
+ *ppNodeE = Fraig_Not(pNode2->p2);
+ return pNode1->p2;
+ }
+ }
+ else if ( pNode1->p2 == Fraig_Not(pNode2->p2) )
+ {
+ if ( Fraig_IsComplement(pNode1->p2) )
+ { // pNode2->p2 is positive phase of C
+ *ppNodeT = Fraig_Not(pNode2->p1);
+ *ppNodeE = Fraig_Not(pNode1->p1);
+ return pNode2->p2;
+ }
+ else
+ { // pNode1->p2 is positive phase of C
+ *ppNodeT = Fraig_Not(pNode1->p1);
+ *ppNodeE = Fraig_Not(pNode2->p1);
+ return pNode1->p2;
+ }
+ }
+ assert( 0 ); // this is not MUX
+ return NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Counts the number of EXOR type nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_ManCountExors( Fraig_Man_t * pMan )
+{
+ int i, nExors;
+ nExors = 0;
+ for ( i = 0; i < pMan->vNodes->nSize; i++ )
+ nExors += Fraig_NodeIsExorType( pMan->vNodes->pArray[i] );
+ return nExors;
+
+}
+
+/**Function*************************************************************
+
+ Synopsis [Counts the number of EXOR type nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_ManCountMuxes( Fraig_Man_t * pMan )
+{
+ int i, nMuxes;
+ nMuxes = 0;
+ for ( i = 0; i < pMan->vNodes->nSize; i++ )
+ nMuxes += Fraig_NodeIsMuxType( pMan->vNodes->pArray[i] );
+ return nMuxes;
+
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if siminfo of Node1 is contained in siminfo of Node2.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_NodeSimsContained( Fraig_Man_t * pMan, Fraig_Node_t * pNode1, Fraig_Node_t * pNode2 )
+{
+ unsigned * pUnsigned1, * pUnsigned2;
+ int i;
+
+ // compare random siminfo
+ pUnsigned1 = pNode1->puSimR;
+ pUnsigned2 = pNode2->puSimR;
+ for ( i = 0; i < pMan->nWordsRand; i++ )
+ if ( pUnsigned1[i] & ~pUnsigned2[i] )
+ return 0;
+
+ // compare systematic siminfo
+ pUnsigned1 = pNode1->puSimD;
+ pUnsigned2 = pNode2->puSimD;
+ for ( i = 0; i < pMan->iWordStart; i++ )
+ if ( pUnsigned1[i] & ~pUnsigned2[i] )
+ return 0;
+
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Count the number of PI variables.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_CountPis( Fraig_Man_t * p, Msat_IntVec_t * vVarNums )
+{
+ int * pVars, nVars, i, Counter;
+
+ nVars = Msat_IntVecReadSize(vVarNums);
+ pVars = Msat_IntVecReadArray(vVarNums);
+ Counter = 0;
+ for ( i = 0; i < nVars; i++ )
+ Counter += Fraig_NodeIsVar( p->vNodes->pArray[pVars[i]] );
+ return Counter;
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Counts the number of EXOR type nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_ManPrintRefs( Fraig_Man_t * pMan )
+{
+ Fraig_NodeVec_t * vPivots;
+ Fraig_Node_t * pNode, * pNode2;
+ int i, k, Counter, nProved;
+ int clk;
+
+ vPivots = Fraig_NodeVecAlloc( 1000 );
+ for ( i = 0; i < pMan->vNodes->nSize; i++ )
+ {
+ pNode = pMan->vNodes->pArray[i];
+
+ if ( pNode->nOnes == 0 || pNode->nOnes == (unsigned)pMan->nWordsRand * 32 )
+ continue;
+
+ if ( pNode->nRefs > 5 )
+ {
+ Fraig_NodeVecPush( vPivots, pNode );
+// printf( "Node %6d : nRefs = %2d Level = %3d.\n", pNode->Num, pNode->nRefs, pNode->Level );
+ }
+ }
+ printf( "Total nodes = %d. Referenced nodes = %d.\n", pMan->vNodes->nSize, vPivots->nSize );
+
+clk = clock();
+ // count implications
+ Counter = nProved = 0;
+ for ( i = 0; i < vPivots->nSize; i++ )
+ for ( k = i+1; k < vPivots->nSize; k++ )
+ {
+ pNode = vPivots->pArray[i];
+ pNode2 = vPivots->pArray[k];
+ if ( Fraig_NodeSimsContained( pMan, pNode, pNode2 ) )
+ {
+ if ( Fraig_NodeIsImplication( pMan, pNode, pNode2, -1 ) )
+ nProved++;
+ Counter++;
+ }
+ else if ( Fraig_NodeSimsContained( pMan, pNode2, pNode ) )
+ {
+ if ( Fraig_NodeIsImplication( pMan, pNode2, pNode, -1 ) )
+ nProved++;
+ Counter++;
+ }
+ }
+ printf( "Number of candidate pairs = %d. Proved = %d.\n", Counter, nProved );
+PRT( "Time", clock() - clk );
+ return 0;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Checks if pNew exists among the implication fanins of pOld.]
+
+ Description [If pNew is an implication fanin of pOld, returns 1.
+ If Fraig_Not(pNew) is an implication fanin of pOld, return -1.
+ Otherwise returns 0.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_NodeIsInSupergate( Fraig_Node_t * pOld, Fraig_Node_t * pNew )
+{
+ int RetValue1, RetValue2;
+ if ( Fraig_Regular(pOld) == Fraig_Regular(pNew) )
+ return (pOld == pNew)? 1 : -1;
+ if ( Fraig_IsComplement(pOld) || Fraig_NodeIsVar(pOld) )
+ return 0;
+ RetValue1 = Fraig_NodeIsInSupergate( pOld->p1, pNew );
+ RetValue2 = Fraig_NodeIsInSupergate( pOld->p2, pNew );
+ if ( RetValue1 == -1 || RetValue2 == -1 )
+ return -1;
+ if ( RetValue1 == 1 || RetValue2 == 1 )
+ return 1;
+ return 0;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Returns the array of nodes to be combined into one multi-input AND-gate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_CollectSupergate_rec( Fraig_Node_t * pNode, Fraig_NodeVec_t * vSuper, int fFirst, int fStopAtMux )
+{
+ // if the new node is complemented or a PI, another gate begins
+// if ( Fraig_IsComplement(pNode) || Fraig_NodeIsVar(pNode) || Fraig_NodeIsMuxType(pNode) )
+ if ( (!fFirst && Fraig_Regular(pNode)->nRefs > 1) ||
+ Fraig_IsComplement(pNode) || Fraig_NodeIsVar(pNode) ||
+ (fStopAtMux && Fraig_NodeIsMuxType(pNode)) )
+ {
+ Fraig_NodeVecPushUnique( vSuper, pNode );
+ return;
+ }
+ // go through the branches
+ Fraig_CollectSupergate_rec( pNode->p1, vSuper, 0, fStopAtMux );
+ Fraig_CollectSupergate_rec( pNode->p2, vSuper, 0, fStopAtMux );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the array of nodes to be combined into one multi-input AND-gate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_NodeVec_t * Fraig_CollectSupergate( Fraig_Node_t * pNode, int fStopAtMux )
+{
+ Fraig_NodeVec_t * vSuper;
+ vSuper = Fraig_NodeVecAlloc( 8 );
+ Fraig_CollectSupergate_rec( pNode, vSuper, 1, fStopAtMux );
+ return vSuper;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sat/fraig/fraigVec.c b/src/sat/fraig/fraigVec.c
new file mode 100644
index 00000000..2e2603b0
--- /dev/null
+++ b/src/sat/fraig/fraigVec.c
@@ -0,0 +1,545 @@
+/**CFile****************************************************************
+
+ FileName [fraigVec.c]
+
+ PackageName [FRAIG: Functionally reduced AND-INV graphs.]
+
+ Synopsis [Vector of FRAIG nodes.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - October 1, 2004]
+
+ Revision [$Id: fraigVec.c,v 1.7 2005/07/08 01:01:34 alanmi Exp $]
+
+***********************************************************************/
+
+#include "fraigInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Allocates a vector with the given capacity.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_NodeVec_t * Fraig_NodeVecAlloc( int nCap )
+{
+ Fraig_NodeVec_t * p;
+ p = ALLOC( Fraig_NodeVec_t, 1 );
+ if ( nCap > 0 && nCap < 8 )
+ nCap = 8;
+ p->nSize = 0;
+ p->nCap = nCap;
+ p->pArray = p->nCap? ALLOC( Fraig_Node_t *, p->nCap ) : NULL;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_NodeVecFree( Fraig_NodeVec_t * p )
+{
+ FREE( p->pArray );
+ FREE( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Duplicates the integer array.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_NodeVec_t * Fraig_NodeVecDup( Fraig_NodeVec_t * pVec )
+{
+ Fraig_NodeVec_t * p;
+ p = ALLOC( Fraig_NodeVec_t, 1 );
+ p->nSize = pVec->nSize;
+ p->nCap = pVec->nCap;
+ p->pArray = p->nCap? ALLOC( Fraig_Node_t *, p->nCap ) : NULL;
+ memcpy( p->pArray, pVec->pArray, sizeof(Fraig_Node_t *) * pVec->nSize );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_Node_t ** Fraig_NodeVecReadArray( Fraig_NodeVec_t * p )
+{
+ return p->pArray;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_NodeVecReadSize( Fraig_NodeVec_t * p )
+{
+ return p->nSize;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Resizes the vector to the given capacity.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_NodeVecGrow( Fraig_NodeVec_t * p, int nCapMin )
+{
+ if ( p->nCap >= nCapMin )
+ return;
+ p->pArray = REALLOC( Fraig_Node_t *, p->pArray, nCapMin );
+ p->nCap = nCapMin;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_NodeVecShrink( Fraig_NodeVec_t * p, int nSizeNew )
+{
+ assert( p->nSize >= nSizeNew );
+ p->nSize = nSizeNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_NodeVecClear( Fraig_NodeVec_t * p )
+{
+ p->nSize = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_NodeVecPush( Fraig_NodeVec_t * p, Fraig_Node_t * Entry )
+{
+ if ( p->nSize == p->nCap )
+ {
+ if ( p->nCap < 16 )
+ Fraig_NodeVecGrow( p, 16 );
+ else
+ Fraig_NodeVecGrow( p, 2 * p->nCap );
+ }
+ p->pArray[p->nSize++] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Add the element while ensuring uniqueness.]
+
+ Description [Returns 1 if the element was found, and 0 if it was new. ]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_NodeVecPushUnique( Fraig_NodeVec_t * p, Fraig_Node_t * Entry )
+{
+ int i;
+ for ( i = 0; i < p->nSize; i++ )
+ if ( p->pArray[i] == Entry )
+ return 1;
+ Fraig_NodeVecPush( p, Entry );
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Inserts a new node in the order by arrival times.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_NodeVecPushOrder( Fraig_NodeVec_t * p, Fraig_Node_t * pNode )
+{
+ Fraig_Node_t * pNode1, * pNode2;
+ int i;
+ Fraig_NodeVecPush( p, pNode );
+ // find the p of the node
+ for ( i = p->nSize-1; i > 0; i-- )
+ {
+ pNode1 = p->pArray[i ];
+ pNode2 = p->pArray[i-1];
+ if ( pNode1 >= pNode2 )
+ break;
+ p->pArray[i ] = pNode2;
+ p->pArray[i-1] = pNode1;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Add the element while ensuring uniqueness in the order.]
+
+ Description [Returns 1 if the element was found, and 0 if it was new. ]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_NodeVecPushUniqueOrder( Fraig_NodeVec_t * p, Fraig_Node_t * pNode )
+{
+ int i;
+ for ( i = 0; i < p->nSize; i++ )
+ if ( p->pArray[i] == pNode )
+ return 1;
+ Fraig_NodeVecPushOrder( p, pNode );
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Inserts a new node in the order by arrival times.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_NodeVecPushOrderByLevel( Fraig_NodeVec_t * p, Fraig_Node_t * pNode )
+{
+ Fraig_Node_t * pNode1, * pNode2;
+ int i;
+ Fraig_NodeVecPush( p, pNode );
+ // find the p of the node
+ for ( i = p->nSize-1; i > 0; i-- )
+ {
+ pNode1 = p->pArray[i ];
+ pNode2 = p->pArray[i-1];
+ if ( Fraig_Regular(pNode1)->Level <= Fraig_Regular(pNode2)->Level )
+ break;
+ p->pArray[i ] = pNode2;
+ p->pArray[i-1] = pNode1;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Add the element while ensuring uniqueness in the order.]
+
+ Description [Returns 1 if the element was found, and 0 if it was new. ]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_NodeVecPushUniqueOrderByLevel( Fraig_NodeVec_t * p, Fraig_Node_t * pNode )
+{
+ int i;
+ for ( i = 0; i < p->nSize; i++ )
+ if ( p->pArray[i] == pNode )
+ return 1;
+ Fraig_NodeVecPushOrderByLevel( p, pNode );
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_Node_t * Fraig_NodeVecPop( Fraig_NodeVec_t * p )
+{
+ return p->pArray[--p->nSize];
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_NodeVecRemove( Fraig_NodeVec_t * p, Fraig_Node_t * Entry )
+{
+ int i;
+ for ( i = 0; i < p->nSize; i++ )
+ if ( p->pArray[i] == Entry )
+ break;
+ assert( i < p->nSize );
+ for ( i++; i < p->nSize; i++ )
+ p->pArray[i-1] = p->pArray[i];
+ p->nSize--;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_NodeVecWriteEntry( Fraig_NodeVec_t * p, int i, Fraig_Node_t * Entry )
+{
+ assert( i >= 0 && i < p->nSize );
+ p->pArray[i] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fraig_Node_t * Fraig_NodeVecReadEntry( Fraig_NodeVec_t * p, int i )
+{
+ assert( i >= 0 && i < p->nSize );
+ return p->pArray[i];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Comparison procedure for two clauses.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_NodeVecCompareLevelsIncreasing( Fraig_Node_t ** pp1, Fraig_Node_t ** pp2 )
+{
+ int Level1 = Fraig_Regular(*pp1)->Level;
+ int Level2 = Fraig_Regular(*pp2)->Level;
+ if ( Level1 < Level2 )
+ return -1;
+ if ( Level1 > Level2 )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Comparison procedure for two clauses.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_NodeVecCompareLevelsDecreasing( Fraig_Node_t ** pp1, Fraig_Node_t ** pp2 )
+{
+ int Level1 = Fraig_Regular(*pp1)->Level;
+ int Level2 = Fraig_Regular(*pp2)->Level;
+ if ( Level1 > Level2 )
+ return -1;
+ if ( Level1 < Level2 )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Comparison procedure for two clauses.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_NodeVecCompareNumbers( Fraig_Node_t ** pp1, Fraig_Node_t ** pp2 )
+{
+ int Num1 = Fraig_Regular(*pp1)->Num;
+ int Num2 = Fraig_Regular(*pp2)->Num;
+ if ( Num1 < Num2 )
+ return -1;
+ if ( Num1 > Num2 )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Comparison procedure for two clauses.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fraig_NodeVecCompareRefCounts( Fraig_Node_t ** pp1, Fraig_Node_t ** pp2 )
+{
+ int nRefs1 = Fraig_Regular(*pp1)->nRefs;
+ int nRefs2 = Fraig_Regular(*pp2)->nRefs;
+
+ if ( nRefs1 < nRefs2 )
+ return -1;
+ if ( nRefs1 > nRefs2 )
+ return 1;
+
+ nRefs1 = Fraig_Regular(*pp1)->Level;
+ nRefs2 = Fraig_Regular(*pp2)->Level;
+
+ if ( nRefs1 < nRefs2 )
+ return -1;
+ if ( nRefs1 > nRefs2 )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sorting the entries by their integer value.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_NodeVecSortByLevel( Fraig_NodeVec_t * p, int fIncreasing )
+{
+ if ( fIncreasing )
+ qsort( (void *)p->pArray, p->nSize, sizeof(Fraig_Node_t *),
+ (int (*)(const void *, const void *)) Fraig_NodeVecCompareLevelsIncreasing );
+ else
+ qsort( (void *)p->pArray, p->nSize, sizeof(Fraig_Node_t *),
+ (int (*)(const void *, const void *)) Fraig_NodeVecCompareLevelsDecreasing );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sorting the entries by their integer value.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_NodeVecSortByNumber( Fraig_NodeVec_t * p )
+{
+ qsort( (void *)p->pArray, p->nSize, sizeof(Fraig_Node_t *),
+ (int (*)(const void *, const void *)) Fraig_NodeVecCompareNumbers );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sorting the entries by their integer value.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fraig_NodeVecSortByRefCount( Fraig_NodeVec_t * p )
+{
+ qsort( (void *)p->pArray, p->nSize, sizeof(Fraig_Node_t *),
+ (int (*)(const void *, const void *)) Fraig_NodeVecCompareRefCounts );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/sat/fraig/module.make b/src/sat/fraig/module.make
new file mode 100644
index 00000000..cc6eb9d3
--- /dev/null
+++ b/src/sat/fraig/module.make
@@ -0,0 +1,12 @@
+SRC += src/sat/fraig/fraigApi.c \
+ src/sat/fraig/fraigCanon.c \
+ src/sat/fraig/fraigFanout.c \
+ src/sat/fraig/fraigFeed.c \
+ src/sat/fraig/fraigMan.c \
+ src/sat/fraig/fraigMem.c \
+ src/sat/fraig/fraigNode.c \
+ src/sat/fraig/fraigPrime.c \
+ src/sat/fraig/fraigSat.c \
+ src/sat/fraig/fraigTable.c \
+ src/sat/fraig/fraigUtil.c \
+ src/sat/fraig/fraigVec.c
diff --git a/src/sat/msat/module.make b/src/sat/msat/module.make
new file mode 100644
index 00000000..0dadfbe1
--- /dev/null
+++ b/src/sat/msat/module.make
@@ -0,0 +1,13 @@
+SRC += src/sat/msat/msatActivity.c \
+ src/sat/msat/msatClause.c \
+ src/sat/msat/msatClauseVec.c \
+ src/sat/msat/msatMem.c \
+ src/sat/msat/msatOrderJ.c \
+ src/sat/msat/msatQueue.c \
+ src/sat/msat/msatRead.c \
+ src/sat/msat/msatSolverApi.c \
+ src/sat/msat/msatSolverCore.c \
+ src/sat/msat/msatSolverIo.c \
+ src/sat/msat/msatSolverSearch.c \
+ src/sat/msat/msatSort.c \
+ src/sat/msat/msatVec.c
diff --git a/src/sat/msat/msat.h b/src/sat/msat/msat.h
new file mode 100644
index 00000000..21ddcb81
--- /dev/null
+++ b/src/sat/msat/msat.h
@@ -0,0 +1,160 @@
+/**CFile****************************************************************
+
+ FileName [msat.h]
+
+ PackageName [A C version of SAT solver MINISAT, originally developed
+ in C++ by Niklas Een and Niklas Sorensson, Chalmers University of
+ Technology, Sweden: http://www.cs.chalmers.se/~een/Satzoo.]
+
+ Synopsis [External definitions of the solver.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - January 1, 2004.]
+
+ Revision [$Id: msat.h,v 1.6 2004/05/12 06:30:20 satrajit Exp $]
+
+***********************************************************************/
+
+#ifndef __MSAT_H__
+#define __MSAT_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+#ifdef bool
+#undef bool
+#endif
+
+#ifndef __MVTYPES_H__
+typedef int bool;
+#endif
+
+typedef struct Msat_Solver_t_ Msat_Solver_t;
+
+// the vector of intergers and of clauses
+typedef struct Msat_IntVec_t_ Msat_IntVec_t;
+typedef struct Msat_ClauseVec_t_ Msat_ClauseVec_t;
+typedef struct Msat_VarHeap_t_ Msat_VarHeap_t;
+
+// the return value of the solver
+typedef enum { MSAT_FALSE = -1, MSAT_UNKNOWN = 0, MSAT_TRUE = 1 } Msat_Type_t;
+
+// representation of variables and literals
+// the literal (l) is the variable (v) and the sign (s)
+// s = 0 the variable is positive
+// s = 1 the variable is negative
+#define MSAT_VAR2LIT(v,s) (2*(v)+(s))
+#define MSAT_LITNOT(l) ((l)^1)
+#define MSAT_LITSIGN(l) ((l)&1)
+#define MSAT_LIT2VAR(l) ((l)>>1)
+
+////////////////////////////////////////////////////////////////////////
+/// GLOBAL VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== satRead.c ============================================================*/
+extern bool Msat_SolverParseDimacs( FILE * pFile, Msat_Solver_t ** p, int fVerbose );
+/*=== satSolver.c ===========================================================*/
+// adding vars, clauses, simplifying the database, and solving
+extern bool Msat_SolverAddVar( Msat_Solver_t * p );
+extern bool Msat_SolverAddClause( Msat_Solver_t * p, Msat_IntVec_t * pLits );
+extern bool Msat_SolverSimplifyDB( Msat_Solver_t * p );
+extern bool Msat_SolverSolve( Msat_Solver_t * p, Msat_IntVec_t * pVecAssumps, int nBackTrackLimit );
+// printing stats, assignments, and clauses
+extern void Msat_SolverPrintStats( Msat_Solver_t * p );
+extern void Msat_SolverPrintAssignment( Msat_Solver_t * p );
+extern void Msat_SolverPrintClauses( Msat_Solver_t * p );
+extern void Msat_SolverWriteDimacs( Msat_Solver_t * p, char * pFileName );
+// access to the solver internal data
+extern int Msat_SolverReadVarNum( Msat_Solver_t * p );
+extern int Msat_SolverReadVarAllocNum( Msat_Solver_t * p );
+extern int * Msat_SolverReadAssignsArray( Msat_Solver_t * p );
+extern int * Msat_SolverReadModelArray( Msat_Solver_t * p );
+extern unsigned Msat_SolverReadTruth( Msat_Solver_t * p );
+extern int Msat_SolverReadBackTracks( Msat_Solver_t * p );
+extern void Msat_SolverSetVerbosity( Msat_Solver_t * p, int fVerbose );
+extern void Msat_SolverSetProofWriting( Msat_Solver_t * p, int fProof );
+extern void Msat_SolverSetVarTypeA( Msat_Solver_t * p, int Var );
+extern void Msat_SolverSetVarMap( Msat_Solver_t * p, Msat_IntVec_t * vVarMap );
+extern void Msat_SolverMarkLastClauseTypeA( Msat_Solver_t * p );
+extern void Msat_SolverMarkClausesStart( Msat_Solver_t * p );
+// returns the solution after incremental solving
+extern int Msat_SolverReadSolutions( Msat_Solver_t * p );
+extern int * Msat_SolverReadSolutionsArray( Msat_Solver_t * p );
+extern Msat_ClauseVec_t * Msat_SolverReadAdjacents( Msat_Solver_t * p );
+extern Msat_IntVec_t * Msat_SolverReadConeVars( Msat_Solver_t * p );
+extern Msat_IntVec_t * Msat_SolverReadVarsUsed( Msat_Solver_t * p );
+/*=== satSolverSearch.c ===========================================================*/
+extern void Msat_SolverRemoveLearned( Msat_Solver_t * p );
+extern void Msat_SolverRemoveMarked( Msat_Solver_t * p );
+/*=== satSolverApi.c ===========================================================*/
+// allocation, cleaning, and freeing the solver
+extern Msat_Solver_t * Msat_SolverAlloc( int nVars, double dClaInc, double dClaDecay, double dVarInc, double dVarDecay, bool fVerbose );
+extern void Msat_SolverResize( Msat_Solver_t * pMan, int nVarsAlloc );
+extern void Msat_SolverClean( Msat_Solver_t * p, int nVars );
+extern void Msat_SolverPrepare( Msat_Solver_t * pSat, Msat_IntVec_t * vVars );
+extern void Msat_SolverFree( Msat_Solver_t * p );
+/*=== satVec.c ===========================================================*/
+extern Msat_IntVec_t * Msat_IntVecAlloc( int nCap );
+extern Msat_IntVec_t * Msat_IntVecAllocArray( int * pArray, int nSize );
+extern Msat_IntVec_t * Msat_IntVecAllocArrayCopy( int * pArray, int nSize );
+extern Msat_IntVec_t * Msat_IntVecDup( Msat_IntVec_t * pVec );
+extern Msat_IntVec_t * Msat_IntVecDupArray( Msat_IntVec_t * pVec );
+extern void Msat_IntVecFree( Msat_IntVec_t * p );
+extern void Msat_IntVecFill( Msat_IntVec_t * p, int nSize, int Entry );
+extern int * Msat_IntVecReleaseArray( Msat_IntVec_t * p );
+extern int * Msat_IntVecReadArray( Msat_IntVec_t * p );
+extern int Msat_IntVecReadSize( Msat_IntVec_t * p );
+extern int Msat_IntVecReadEntry( Msat_IntVec_t * p, int i );
+extern int Msat_IntVecReadEntryLast( Msat_IntVec_t * p );
+extern void Msat_IntVecWriteEntry( Msat_IntVec_t * p, int i, int Entry );
+extern void Msat_IntVecGrow( Msat_IntVec_t * p, int nCapMin );
+extern void Msat_IntVecShrink( Msat_IntVec_t * p, int nSizeNew );
+extern void Msat_IntVecClear( Msat_IntVec_t * p );
+extern void Msat_IntVecPush( Msat_IntVec_t * p, int Entry );
+extern int Msat_IntVecPushUnique( Msat_IntVec_t * p, int Entry );
+extern void Msat_IntVecPushUniqueOrder( Msat_IntVec_t * p, int Entry, int fIncrease );
+extern int Msat_IntVecPop( Msat_IntVec_t * p );
+extern void Msat_IntVecSort( Msat_IntVec_t * p, int fReverse );
+/*=== satHeap.c ===========================================================*/
+extern Msat_VarHeap_t * Msat_VarHeapAlloc();
+extern void Msat_VarHeapSetActivity( Msat_VarHeap_t * p, double * pActivity );
+extern void Msat_VarHeapStart( Msat_VarHeap_t * p, int * pVars, int nVars, int nVarsAlloc );
+extern void Msat_VarHeapGrow( Msat_VarHeap_t * p, int nSize );
+extern void Msat_VarHeapStop( Msat_VarHeap_t * p );
+extern void Msat_VarHeapPrint( FILE * pFile, Msat_VarHeap_t * p );
+extern void Msat_VarHeapCheck( Msat_VarHeap_t * p );
+extern void Msat_VarHeapCheckOne( Msat_VarHeap_t * p, int iVar );
+extern int Msat_VarHeapContainsVar( Msat_VarHeap_t * p, int iVar );
+extern void Msat_VarHeapInsert( Msat_VarHeap_t * p, int iVar );
+extern void Msat_VarHeapUpdate( Msat_VarHeap_t * p, int iVar );
+extern void Msat_VarHeapDelete( Msat_VarHeap_t * p, int iVar );
+extern double Msat_VarHeapReadMaxWeight( Msat_VarHeap_t * p );
+extern int Msat_VarHeapCountNodes( Msat_VarHeap_t * p, double WeightLimit );
+extern int Msat_VarHeapReadMax( Msat_VarHeap_t * p );
+extern int Msat_VarHeapGetMax( Msat_VarHeap_t * p );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+#endif
diff --git a/src/sat/msat/msatActivity.c b/src/sat/msat/msatActivity.c
new file mode 100644
index 00000000..c9a518ce
--- /dev/null
+++ b/src/sat/msat/msatActivity.c
@@ -0,0 +1,158 @@
+/**CFile****************************************************************
+
+ FileName [msatActivity.c]
+
+ PackageName [A C version of SAT solver MINISAT, originally developed
+ in C++ by Niklas Een and Niklas Sorensson, Chalmers University of
+ Technology, Sweden: http://www.cs.chalmers.se/~een/Satzoo.]
+
+ Synopsis [Procedures controlling activity of variables and clauses.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - January 1, 2004.]
+
+ Revision [$Id: msatActivity.c,v 1.0 2004/01/01 1:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "msatInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverVarBumpActivity( Msat_Solver_t * p, Msat_Lit_t Lit )
+{
+ Msat_Var_t Var;
+ if ( p->dVarDecay < 0 ) // (negative decay means static variable order -- don't bump)
+ return;
+ Var = MSAT_LIT2VAR(Lit);
+ if ( (p->pdActivity[Var] += p->dVarInc) > 1e100 )
+ Msat_SolverVarRescaleActivity( p );
+ Msat_OrderUpdate( p->pOrder, Var );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverVarDecayActivity( Msat_Solver_t * p )
+{
+ if ( p->dVarDecay >= 0 )
+ p->dVarInc *= p->dVarDecay;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Divide all variable activities by 1e100.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverVarRescaleActivity( Msat_Solver_t * p )
+{
+ int i;
+ for ( i = 0; i < p->nVars; i++ )
+ p->pdActivity[i] *= 1e-100;
+ p->dVarInc *= 1e-100;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverClaBumpActivity( Msat_Solver_t * p, Msat_Clause_t * pC )
+{
+ float Activ;
+ Activ = Msat_ClauseReadActivity(pC);
+ if ( Activ + p->dClaInc > 1e20 )
+ {
+ Msat_SolverClaRescaleActivity( p );
+ Activ = Msat_ClauseReadActivity( pC );
+ }
+ Msat_ClauseWriteActivity( pC, Activ + (float)p->dClaInc );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverClaDecayActivity( Msat_Solver_t * p )
+{
+ p->dClaInc *= p->dClaDecay;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Divide all constraint activities by 1e20.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverClaRescaleActivity( Msat_Solver_t * p )
+{
+ Msat_Clause_t ** pLearned;
+ int nLearned, i;
+ float Activ;
+ nLearned = Msat_ClauseVecReadSize( p->vLearned );
+ pLearned = Msat_ClauseVecReadArray( p->vLearned );
+ for ( i = 0; i < nLearned; i++ )
+ {
+ Activ = Msat_ClauseReadActivity( pLearned[i] );
+ Msat_ClauseWriteActivity( pLearned[i], Activ * (float)1e-20 );
+ }
+ p->dClaInc *= 1e-20;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sat/msat/msatClause.c b/src/sat/msat/msatClause.c
new file mode 100644
index 00000000..dc39bee6
--- /dev/null
+++ b/src/sat/msat/msatClause.c
@@ -0,0 +1,524 @@
+/**CFile****************************************************************
+
+ FileName [msatClause.c]
+
+ PackageName [A C version of SAT solver MINISAT, originally developed
+ in C++ by Niklas Een and Niklas Sorensson, Chalmers University of
+ Technology, Sweden: http://www.cs.chalmers.se/~een/Satzoo.]
+
+ Synopsis [Procedures working with SAT clauses.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - January 1, 2004.]
+
+ Revision [$Id: msatClause.c,v 1.0 2004/01/01 1:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "msatInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+struct Msat_Clause_t_
+{
+ int Num; // unique number of the clause
+ unsigned fLearned : 1; // 1 if the clause is learned
+ unsigned fMark : 1; // used to mark visited clauses during proof recording
+ unsigned fTypeA : 1; // used to mark clauses belonging to A for interpolant computation
+ unsigned nSize : 14; // the number of literals in the clause
+ unsigned nSizeAlloc : 15; // the number of bytes allocated for the clause
+ Msat_Lit_t pData[0];
+};
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Creates a new clause.]
+
+ Description [Returns FALSE if top-level conflict detected (must be handled);
+ TRUE otherwise. 'pClause_out' may be set to NULL if clause is already
+ satisfied by the top-level assignment.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Msat_ClauseCreate( Msat_Solver_t * p, Msat_IntVec_t * vLits, bool fLearned, Msat_Clause_t ** pClause_out )
+{
+ int * pAssigns = Msat_SolverReadAssignsArray(p);
+ Msat_ClauseVec_t ** pvWatched;
+ Msat_Clause_t * pC;
+ int * pLits;
+ int nLits, i, j;
+ int nBytes;
+ Msat_Var_t Var;
+ bool Sign;
+
+ *pClause_out = NULL;
+
+ nLits = Msat_IntVecReadSize(vLits);
+ pLits = Msat_IntVecReadArray(vLits);
+
+ if ( !fLearned )
+ {
+ int * pSeen = Msat_SolverReadSeenArray( p );
+ int nSeenId;
+ assert( Msat_SolverReadDecisionLevel(p) == 0 );
+ // sorting literals makes the code trace-equivalent
+ // with to the original C++ solver
+ Msat_IntVecSort( vLits, 0 );
+ // increment the counter of seen twice
+ nSeenId = Msat_SolverIncrementSeenId( p );
+ nSeenId = Msat_SolverIncrementSeenId( p );
+ // nSeenId - 1 stands for negative
+ // nSeenId stands for positive
+ // Remove false literals
+ for ( i = j = 0; i < nLits; i++ ) {
+ // get the corresponding variable
+ Var = MSAT_LIT2VAR(pLits[i]);
+ Sign = MSAT_LITSIGN(pLits[i]); // Sign=0 for positive
+ // check if we already saw this variable in the this clause
+ if ( pSeen[Var] >= nSeenId - 1 )
+ {
+ if ( (pSeen[Var] != nSeenId) == Sign ) // the same lit
+ continue;
+ return 1; // two opposite polarity lits -- don't add the clause
+ }
+ // mark the variable as seen
+ pSeen[Var] = nSeenId - !Sign;
+
+ // analize the value of this literal
+ if ( pAssigns[Var] != MSAT_VAR_UNASSIGNED )
+ {
+ if ( pAssigns[Var] == pLits[i] )
+ return 1; // the clause is always true -- don't add anything
+ // the literal has no impact - skip it
+ continue;
+ }
+ // otherwise, add this literal to the clause
+ pLits[j++] = pLits[i];
+ }
+ Msat_IntVecShrink( vLits, j );
+ nLits = j;
+/*
+ // the problem with this code is that performance is very
+ // sensitive to the ordering of adjacency lits
+ // the best ordering requires fanins first, next fanouts
+ // this ordering is more convenient to make from FRAIG
+
+ // create the adjacency information
+ if ( nLits > 2 )
+ {
+ Msat_Var_t VarI, VarJ;
+ Msat_IntVec_t * pAdjI, * pAdjJ;
+
+ for ( i = 0; i < nLits; i++ )
+ {
+ VarI = MSAT_LIT2VAR(pLits[i]);
+ pAdjI = (Msat_IntVec_t *)p->vAdjacents->pArray[VarI];
+
+ for ( j = i+1; j < nLits; j++ )
+ {
+ VarJ = MSAT_LIT2VAR(pLits[j]);
+ pAdjJ = (Msat_IntVec_t *)p->vAdjacents->pArray[VarJ];
+
+ Msat_IntVecPushUniqueOrder( pAdjI, VarJ, 1 );
+ Msat_IntVecPushUniqueOrder( pAdjJ, VarI, 1 );
+ }
+ }
+ }
+*/
+ }
+ // 'vLits' is now the (possibly) reduced vector of literals.
+ if ( nLits == 0 )
+ return 0;
+ if ( nLits == 1 )
+ return Msat_SolverEnqueue( p, pLits[0], NULL );
+
+ // Allocate clause:
+// nBytes = sizeof(unsigned)*(nLits + 1 + (int)fLearned);
+ nBytes = sizeof(unsigned)*(nLits + 2 + (int)fLearned);
+#ifdef USE_SYSTEM_MEMORY_MANAGEMENT
+ pC = (Msat_Clause_t *)ALLOC( char, nBytes );
+#else
+ pC = (Msat_Clause_t *)Msat_MmStepEntryFetch( Msat_SolverReadMem(p), nBytes );
+#endif
+ pC->Num = p->nClauses++;
+ pC->fTypeA = 0;
+ pC->fMark = 0;
+ pC->fLearned = fLearned;
+ pC->nSize = nLits;
+ pC->nSizeAlloc = nBytes;
+ memcpy( pC->pData, pLits, sizeof(int)*nLits );
+
+ // For learnt clauses only:
+ if ( fLearned )
+ {
+ int * pLevel = Msat_SolverReadDecisionLevelArray( p );
+ int iLevelMax, iLevelCur, iLitMax;
+
+ // Put the second watch on the literal with highest decision level:
+ iLitMax = 1;
+ iLevelMax = pLevel[ MSAT_LIT2VAR(pLits[1]) ];
+ for ( i = 2; i < nLits; i++ )
+ {
+ iLevelCur = pLevel[ MSAT_LIT2VAR(pLits[i]) ];
+ assert( iLevelCur != -1 );
+ if ( iLevelMax < iLevelCur )
+ // this is very strange - shouldn't it be???
+ // if ( iLevelMax > iLevelCur )
+ iLevelMax = iLevelCur, iLitMax = i;
+ }
+ pC->pData[1] = pLits[iLitMax];
+ pC->pData[iLitMax] = pLits[1];
+
+ // Bumping:
+ // (newly learnt clauses should be considered active)
+ Msat_ClauseWriteActivity( pC, 0.0 );
+ Msat_SolverClaBumpActivity( p, pC );
+// if ( nLits < 20 )
+ for ( i = 0; i < nLits; i++ )
+ {
+ Msat_SolverVarBumpActivity( p, pLits[i] );
+// Msat_SolverVarBumpActivity( p, pLits[i] );
+ }
+ }
+
+ // Store clause:
+ pvWatched = Msat_SolverReadWatchedArray( p );
+ Msat_ClauseVecPush( pvWatched[ MSAT_LITNOT(pC->pData[0]) ], pC );
+ Msat_ClauseVecPush( pvWatched[ MSAT_LITNOT(pC->pData[1]) ], pC );
+ *pClause_out = pC;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Deallocates the clause.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_ClauseFree( Msat_Solver_t * p, Msat_Clause_t * pC, bool fRemoveWatched )
+{
+ if ( fRemoveWatched )
+ {
+ Msat_Lit_t Lit;
+ Msat_ClauseVec_t ** pvWatched;
+ pvWatched = Msat_SolverReadWatchedArray( p );
+ Lit = MSAT_LITNOT( pC->pData[0] );
+ Msat_ClauseRemoveWatch( pvWatched[Lit], pC );
+ Lit = MSAT_LITNOT( pC->pData[1] );
+ Msat_ClauseRemoveWatch( pvWatched[Lit], pC );
+ }
+
+#ifdef USE_SYSTEM_MEMORY_MANAGEMENT
+ free( pC );
+#else
+ Msat_MmStepEntryRecycle( Msat_SolverReadMem(p), (char *)pC, pC->nSizeAlloc );
+#endif
+
+}
+
+/**Function*************************************************************
+
+ Synopsis [Access the data field of the clause.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Msat_ClauseReadLearned( Msat_Clause_t * pC ) { return pC->fLearned; }
+int Msat_ClauseReadSize( Msat_Clause_t * pC ) { return pC->nSize; }
+int * Msat_ClauseReadLits( Msat_Clause_t * pC ) { return pC->pData; }
+bool Msat_ClauseReadMark( Msat_Clause_t * pC ) { return pC->fMark; }
+int Msat_ClauseReadNum( Msat_Clause_t * pC ) { return pC->Num; }
+bool Msat_ClauseReadTypeA( Msat_Clause_t * pC ) { return pC->fTypeA; }
+
+void Msat_ClauseSetMark( Msat_Clause_t * pC, bool fMark ) { pC->fMark = fMark; }
+void Msat_ClauseSetNum( Msat_Clause_t * pC, int Num ) { pC->Num = Num; }
+void Msat_ClauseSetTypeA( Msat_Clause_t * pC, bool fTypeA ) { pC->fTypeA = fTypeA; }
+
+/**Function*************************************************************
+
+ Synopsis [Checks whether the learned clause is locked.]
+
+ Description [The clause may be locked if it is the reason of a
+ recent conflict. Such clause cannot be removed from the database.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Msat_ClauseIsLocked( Msat_Solver_t * p, Msat_Clause_t * pC )
+{
+ Msat_Clause_t ** pReasons = Msat_SolverReadReasonArray( p );
+ return (bool)(pReasons[MSAT_LIT2VAR(pC->pData[0])] == pC);
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads the activity of the given clause.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Msat_ClauseReadActivity( Msat_Clause_t * pC )
+{
+ return *((float *)(pC->pData + pC->nSize));
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the activity of the clause.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_ClauseWriteActivity( Msat_Clause_t * pC, float Num )
+{
+ *((float *)(pC->pData + pC->nSize)) = Num;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Propages the assignment.]
+
+ Description [The literal that has become true (Lit) is given to this
+ procedure. The array of current variable assignments is given for
+ efficiency. The output literal (pLit_out) can be the second watched
+ literal (if TRUE is returned) or the conflict literal (if FALSE is
+ returned). This messy interface is used to improve performance.
+ This procedure accounts for ~50% of the runtime of the solver.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Msat_ClausePropagate( Msat_Clause_t * pC, Msat_Lit_t Lit, int * pAssigns, Msat_Lit_t * pLit_out )
+{
+ // make sure the false literal is pC->pData[1]
+ Msat_Lit_t LitF = MSAT_LITNOT(Lit);
+ if ( pC->pData[0] == LitF )
+ pC->pData[0] = pC->pData[1], pC->pData[1] = LitF;
+ assert( pC->pData[1] == LitF );
+ // if the 0-th watch is true, clause is already satisfied
+ if ( pAssigns[MSAT_LIT2VAR(pC->pData[0])] == pC->pData[0] )
+ return 1;
+ // look for a new watch
+ if ( pC->nSize > 2 )
+ {
+ int i;
+ for ( i = 2; i < (int)pC->nSize; i++ )
+ if ( pAssigns[MSAT_LIT2VAR(pC->pData[i])] != MSAT_LITNOT(pC->pData[i]) )
+ {
+ pC->pData[1] = pC->pData[i], pC->pData[i] = LitF;
+ *pLit_out = MSAT_LITNOT(pC->pData[1]);
+ return 1;
+ }
+ }
+ // clause is unit under assignment
+ *pLit_out = pC->pData[0];
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Simplifies the clause.]
+
+ Description [Assumes everything has been propagated! (esp. watches
+ in clauses are NOT unsatisfied)]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Msat_ClauseSimplify( Msat_Clause_t * pC, int * pAssigns )
+{
+ Msat_Var_t Var;
+ int i, j;
+ for ( i = j = 0; i < (int)pC->nSize; i++ )
+ {
+ Var = MSAT_LIT2VAR(pC->pData[i]);
+ if ( pAssigns[Var] == MSAT_VAR_UNASSIGNED )
+ {
+ pC->pData[j++] = pC->pData[i];
+ continue;
+ }
+ if ( pAssigns[Var] == pC->pData[i] )
+ return 1;
+ // otherwise, the value of the literal is false
+ // make sure, this literal is not watched
+ assert( i >= 2 );
+ }
+ // if the size has changed, update it and move activity
+ if ( j < (int)pC->nSize )
+ {
+ float Activ = Msat_ClauseReadActivity(pC);
+ pC->nSize = j;
+ Msat_ClauseWriteActivity(pC, Activ);
+ }
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes reason of conflict in the given clause.]
+
+ Description [If the literal is unassigned, finds the reason by
+ complementing literals in the given cluase (pC). If the literal is
+ assigned, makes sure that this literal is the first one in the clause
+ and computes the complement of all other literals in the clause.
+ Returns the reason in the given array (vLits_out). If the clause is
+ learned, bumps its activity.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_ClauseCalcReason( Msat_Solver_t * p, Msat_Clause_t * pC, Msat_Lit_t Lit, Msat_IntVec_t * vLits_out )
+{
+ int i;
+ // clear the reason
+ Msat_IntVecClear( vLits_out );
+ assert( Lit == MSAT_LIT_UNASSIGNED || Lit == pC->pData[0] );
+ for ( i = (Lit != MSAT_LIT_UNASSIGNED); i < (int)pC->nSize; i++ )
+ {
+ assert( Msat_SolverReadAssignsArray(p)[MSAT_LIT2VAR(pC->pData[i])] == MSAT_LITNOT(pC->pData[i]) );
+ Msat_IntVecPush( vLits_out, MSAT_LITNOT(pC->pData[i]) );
+ }
+ if ( pC->fLearned )
+ Msat_SolverClaBumpActivity( p, pC );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Removes the given clause from the watched list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_ClauseRemoveWatch( Msat_ClauseVec_t * vClauses, Msat_Clause_t * pC )
+{
+ Msat_Clause_t ** pClauses;
+ int nClauses, i;
+ nClauses = Msat_ClauseVecReadSize( vClauses );
+ pClauses = Msat_ClauseVecReadArray( vClauses );
+ for ( i = 0; pClauses[i] != pC; i++ )
+ assert( i < nClauses );
+ for ( ; i < nClauses - 1; i++ )
+ pClauses[i] = pClauses[i+1];
+ Msat_ClauseVecPop( vClauses );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the given clause.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_ClausePrint( Msat_Clause_t * pC )
+{
+ int i;
+ if ( pC == NULL )
+ printf( "NULL pointer" );
+ else
+ {
+ if ( pC->fLearned )
+ printf( "Act = %.4f ", Msat_ClauseReadActivity(pC) );
+ for ( i = 0; i < (int)pC->nSize; i++ )
+ printf( " %s%d", ((pC->pData[i]&1)? "-": ""), pC->pData[i]/2 + 1 );
+ }
+ printf( "\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Writes the given clause in a file in DIMACS format.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_ClauseWriteDimacs( FILE * pFile, Msat_Clause_t * pC, bool fIncrement )
+{
+ int i;
+ for ( i = 0; i < (int)pC->nSize; i++ )
+ fprintf( pFile, "%s%d ", ((pC->pData[i]&1)? "-": ""), pC->pData[i]/2 + (int)(fIncrement>0) );
+ if ( fIncrement )
+ fprintf( pFile, "0" );
+ fprintf( pFile, "\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the given clause.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_ClausePrintSymbols( Msat_Clause_t * pC )
+{
+ int i;
+ if ( pC == NULL )
+ printf( "NULL pointer" );
+ else
+ {
+// if ( pC->fLearned )
+// printf( "Act = %.4f ", Msat_ClauseReadActivity(pC) );
+ for ( i = 0; i < (int)pC->nSize; i++ )
+ printf(" "L_LIT, L_lit(pC->pData[i]));
+ }
+ printf( "\n" );
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sat/msat/msatClauseVec.c b/src/sat/msat/msatClauseVec.c
new file mode 100644
index 00000000..7c24619f
--- /dev/null
+++ b/src/sat/msat/msatClauseVec.c
@@ -0,0 +1,232 @@
+/**CFile****************************************************************
+
+ FileName [msatClauseVec.c]
+
+ PackageName [A C version of SAT solver MINISAT, originally developed
+ in C++ by Niklas Een and Niklas Sorensson, Chalmers University of
+ Technology, Sweden: http://www.cs.chalmers.se/~een/Satzoo.]
+
+ Synopsis [Procedures working with arrays of SAT clauses.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - January 1, 2004.]
+
+ Revision [$Id: msatClauseVec.c,v 1.0 2004/01/01 1:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "msatInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Allocates a vector with the given capacity.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_ClauseVec_t * Msat_ClauseVecAlloc( int nCap )
+{
+ Msat_ClauseVec_t * p;
+ p = ALLOC( Msat_ClauseVec_t, 1 );
+ if ( nCap > 0 && nCap < 16 )
+ nCap = 16;
+ p->nSize = 0;
+ p->nCap = nCap;
+ p->pArray = p->nCap? ALLOC( Msat_Clause_t *, p->nCap ) : NULL;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_ClauseVecFree( Msat_ClauseVec_t * p )
+{
+ FREE( p->pArray );
+ FREE( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_Clause_t ** Msat_ClauseVecReadArray( Msat_ClauseVec_t * p )
+{
+ return p->pArray;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Msat_ClauseVecReadSize( Msat_ClauseVec_t * p )
+{
+ return p->nSize;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Resizes the vector to the given capacity.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_ClauseVecGrow( Msat_ClauseVec_t * p, int nCapMin )
+{
+ if ( p->nCap >= nCapMin )
+ return;
+ p->pArray = REALLOC( Msat_Clause_t *, p->pArray, nCapMin );
+ p->nCap = nCapMin;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_ClauseVecShrink( Msat_ClauseVec_t * p, int nSizeNew )
+{
+ assert( p->nSize >= nSizeNew );
+ p->nSize = nSizeNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_ClauseVecClear( Msat_ClauseVec_t * p )
+{
+ p->nSize = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_ClauseVecPush( Msat_ClauseVec_t * p, Msat_Clause_t * Entry )
+{
+ if ( p->nSize == p->nCap )
+ {
+ if ( p->nCap < 16 )
+ Msat_ClauseVecGrow( p, 16 );
+ else
+ Msat_ClauseVecGrow( p, 2 * p->nCap );
+ }
+ p->pArray[p->nSize++] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_Clause_t * Msat_ClauseVecPop( Msat_ClauseVec_t * p )
+{
+ return p->pArray[--p->nSize];
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_ClauseVecWriteEntry( Msat_ClauseVec_t * p, int i, Msat_Clause_t * Entry )
+{
+ assert( i >= 0 && i < p->nSize );
+ p->pArray[i] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_Clause_t * Msat_ClauseVecReadEntry( Msat_ClauseVec_t * p, int i )
+{
+ assert( i >= 0 && i < p->nSize );
+ return p->pArray[i];
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sat/msat/msatInt.h b/src/sat/msat/msatInt.h
new file mode 100644
index 00000000..037616f6
--- /dev/null
+++ b/src/sat/msat/msatInt.h
@@ -0,0 +1,304 @@
+/**CFile****************************************************************
+
+ FileName [msatInt.c]
+
+ PackageName [A C version of SAT solver MINISAT, originally developed
+ in C++ by Niklas Een and Niklas Sorensson, Chalmers University of
+ Technology, Sweden: http://www.cs.chalmers.se/~een/Satzoo.]
+
+ Synopsis [Internal definitions of the solver.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - January 1, 2004.]
+
+ Revision [$Id: msatInt.c,v 1.0 2004/01/01 1:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __MSAT_INT_H__
+#define __MSAT_INT_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+//#include "leaks.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <time.h>
+#include <math.h>
+#include "msat.h"
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+#ifdef _MSC_VER
+typedef __int64 int64;
+#else
+typedef long long int64;
+#endif
+
+// outputs the runtime in seconds
+#define PRT(a,t) \
+ printf( "%s = ", (a) ); printf( "%6.2f sec\n", (float)(t)/(float)(CLOCKS_PER_SEC) )
+
+// memory management macros
+#define ALLOC(type, num) \
+ ((type *) malloc(sizeof(type) * (num)))
+#define REALLOC(type, obj, num) \
+ (obj) ? ((type *) realloc((char *) obj, sizeof(type) * (num))) : \
+ ((type *) malloc(sizeof(type) * (num)))
+#define FREE(obj) \
+ ((obj) ? (free((char *) (obj)), (obj) = 0) : 0)
+
+// By default, custom memory management is used
+// which guarantees constant time allocation/deallocation
+// for SAT clauses and other frequently modified objects.
+// For debugging, it is possible use system memory management
+// directly. In which case, uncomment the macro below.
+//#define USE_SYSTEM_MEMORY_MANAGEMENT
+
+// internal data structures
+typedef struct Msat_Clause_t_ Msat_Clause_t;
+typedef struct Msat_Queue_t_ Msat_Queue_t;
+typedef struct Msat_Order_t_ Msat_Order_t;
+// memory managers (duplicated from Extra for stand-aloneness)
+typedef struct Msat_MmFixed_t_ Msat_MmFixed_t;
+typedef struct Msat_MmFlex_t_ Msat_MmFlex_t;
+typedef struct Msat_MmStep_t_ Msat_MmStep_t;
+// variables and literals
+typedef int Msat_Lit_t;
+typedef int Msat_Var_t;
+// the type of return value
+#define MSAT_VAR_UNASSIGNED (-1)
+#define MSAT_LIT_UNASSIGNED (-2)
+#define MSAT_ORDER_UNKNOWN (-3)
+
+// printing the search tree
+#define L_IND "%-*d"
+#define L_ind Msat_SolverReadDecisionLevel(p)*3+3,Msat_SolverReadDecisionLevel(p)
+#define L_LIT "%s%d"
+#define L_lit(Lit) MSAT_LITSIGN(Lit)?"-":"", MSAT_LIT2VAR(Lit)+1
+
+typedef struct Msat_SolverStats_t_ Msat_SolverStats_t;
+struct Msat_SolverStats_t_
+{
+ int64 nStarts; // the number of restarts
+ int64 nDecisions; // the number of decisions
+ int64 nPropagations; // the number of implications
+ int64 nInspects; // the number of times clauses are vising while watching them
+ int64 nConflicts; // the number of conflicts
+ int64 nSuccesses; // the number of sat assignments found
+};
+
+typedef struct Msat_SearchParams_t_ Msat_SearchParams_t;
+struct Msat_SearchParams_t_
+{
+ double dVarDecay;
+ double dClaDecay;
+};
+
+// sat solver data structure visible through all the internal files
+struct Msat_Solver_t_
+{
+ int nClauses; // the total number of clauses
+ int nClausesStart; // the number of clauses before adding
+ Msat_ClauseVec_t * vClauses; // problem clauses
+ Msat_ClauseVec_t * vLearned; // learned clauses
+ double dClaInc; // Amount to bump next clause with.
+ double dClaDecay; // INVERSE decay factor for clause activity: stores 1/decay.
+
+ double * pdActivity; // A heuristic measurement of the activity of a variable.
+ double dVarInc; // Amount to bump next variable with.
+ double dVarDecay; // INVERSE decay factor for variable activity: stores 1/decay. Use negative value for static variable order.
+ Msat_Order_t * pOrder; // Keeps track of the decision variable order.
+
+ Msat_ClauseVec_t ** pvWatched; // 'pvWatched[lit]' is a list of constraints watching 'lit' (will go there if literal becomes true).
+ Msat_Queue_t * pQueue; // Propagation queue.
+
+ int nVars; // the current number of variables
+ int nVarsAlloc; // the maximum allowed number of variables
+ int * pAssigns; // The current assignments (literals or MSAT_VAR_UNKOWN)
+ int * pModel; // The satisfying assignment
+ Msat_IntVec_t * vTrail; // List of assignments made.
+ Msat_IntVec_t * vTrailLim; // Separator indices for different decision levels in 'trail'.
+ Msat_Clause_t ** pReasons; // 'reason[var]' is the clause that implied the variables current value, or 'NULL' if none.
+ int * pLevel; // 'level[var]' is the decision level at which assignment was made.
+ int nLevelRoot; // Level of first proper decision.
+
+ double dRandSeed; // For the internal random number generator (makes solver deterministic over different platforms).
+
+ bool fVerbose; // the verbosity flag
+ double dProgress; // Set by 'search()'.
+
+ // the variable cone and variable connectivity
+ Msat_IntVec_t * vConeVars;
+ Msat_IntVec_t * vVarsUsed;
+ Msat_ClauseVec_t * vAdjacents;
+
+ // internal data used during conflict analysis
+ int * pSeen; // time when a lit was seen for the last time
+ int nSeenId; // the id of current seeing
+ Msat_IntVec_t * vReason; // the temporary array of literals
+ Msat_IntVec_t * vTemp; // the temporary array of literals
+
+ // the memory manager
+ Msat_MmStep_t * pMem;
+
+ // statistics
+ Msat_SolverStats_t Stats;
+ int nTwoLits;
+ int nTwoLitsL;
+ int nClausesInit;
+ int nClausesAlloc;
+ int nClausesAllocL;
+ int nBackTracks;
+};
+
+struct Msat_ClauseVec_t_
+{
+ Msat_Clause_t ** pArray;
+ int nSize;
+ int nCap;
+};
+
+struct Msat_IntVec_t_
+{
+ int * pArray;
+ int nSize;
+ int nCap;
+};
+
+////////////////////////////////////////////////////////////////////////
+/// GLOBAL VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== satActivity.c ===========================================================*/
+extern void Msat_SolverVarDecayActivity( Msat_Solver_t * p );
+extern void Msat_SolverVarRescaleActivity( Msat_Solver_t * p );
+extern void Msat_SolverClaDecayActivity( Msat_Solver_t * p );
+extern void Msat_SolverClaRescaleActivity( Msat_Solver_t * p );
+/*=== satSolverApi.c ===========================================================*/
+extern Msat_Clause_t * Msat_SolverReadClause( Msat_Solver_t * p, int Num );
+/*=== satSolver.c ===========================================================*/
+extern int Msat_SolverReadDecisionLevel( Msat_Solver_t * p );
+extern int * Msat_SolverReadDecisionLevelArray( Msat_Solver_t * p );
+extern Msat_Clause_t ** Msat_SolverReadReasonArray( Msat_Solver_t * p );
+extern Msat_Type_t Msat_SolverReadVarValue( Msat_Solver_t * p, Msat_Var_t Var );
+extern Msat_ClauseVec_t * Msat_SolverReadLearned( Msat_Solver_t * p );
+extern Msat_ClauseVec_t ** Msat_SolverReadWatchedArray( Msat_Solver_t * p );
+extern int * Msat_SolverReadSeenArray( Msat_Solver_t * p );
+extern int Msat_SolverIncrementSeenId( Msat_Solver_t * p );
+extern Msat_MmStep_t * Msat_SolverReadMem( Msat_Solver_t * p );
+extern void Msat_SolverClausesIncrement( Msat_Solver_t * p );
+extern void Msat_SolverClausesDecrement( Msat_Solver_t * p );
+extern void Msat_SolverClausesIncrementL( Msat_Solver_t * p );
+extern void Msat_SolverClausesDecrementL( Msat_Solver_t * p );
+extern void Msat_SolverVarBumpActivity( Msat_Solver_t * p, Msat_Lit_t Lit );
+extern void Msat_SolverClaBumpActivity( Msat_Solver_t * p, Msat_Clause_t * pC );
+extern bool Msat_SolverEnqueue( Msat_Solver_t * p, Msat_Lit_t Lit, Msat_Clause_t * pC );
+extern double Msat_SolverProgressEstimate( Msat_Solver_t * p );
+/*=== satSolverSearch.c ===========================================================*/
+extern bool Msat_SolverAssume( Msat_Solver_t * p, Msat_Lit_t Lit );
+extern Msat_Clause_t * Msat_SolverPropagate( Msat_Solver_t * p );
+extern void Msat_SolverCancelUntil( Msat_Solver_t * p, int Level );
+extern Msat_Type_t Msat_SolverSearch( Msat_Solver_t * p, int nConfLimit, int nLearnedLimit, int nBackTrackLimit, Msat_SearchParams_t * pPars );
+/*=== satQueue.c ===========================================================*/
+extern Msat_Queue_t * Msat_QueueAlloc( int nVars );
+extern void Msat_QueueFree( Msat_Queue_t * p );
+extern int Msat_QueueReadSize( Msat_Queue_t * p );
+extern void Msat_QueueInsert( Msat_Queue_t * p, int Lit );
+extern int Msat_QueueExtract( Msat_Queue_t * p );
+extern void Msat_QueueClear( Msat_Queue_t * p );
+/*=== satOrder.c ===========================================================*/
+extern Msat_Order_t * Msat_OrderAlloc( Msat_Solver_t * pSat );
+extern void Msat_OrderSetBounds( Msat_Order_t * p, int nVarsMax );
+extern void Msat_OrderClean( Msat_Order_t * p, Msat_IntVec_t * vCone );
+extern int Msat_OrderCheck( Msat_Order_t * p );
+extern void Msat_OrderFree( Msat_Order_t * p );
+extern int Msat_OrderVarSelect( Msat_Order_t * p );
+extern void Msat_OrderVarAssigned( Msat_Order_t * p, int Var );
+extern void Msat_OrderVarUnassigned( Msat_Order_t * p, int Var );
+extern void Msat_OrderUpdate( Msat_Order_t * p, int Var );
+/*=== satClause.c ===========================================================*/
+extern bool Msat_ClauseCreate( Msat_Solver_t * p, Msat_IntVec_t * vLits, bool fLearnt, Msat_Clause_t ** pClause_out );
+extern Msat_Clause_t * Msat_ClauseCreateFake( Msat_Solver_t * p, Msat_IntVec_t * vLits );
+extern Msat_Clause_t * Msat_ClauseCreateFakeLit( Msat_Solver_t * p, Msat_Lit_t Lit );
+extern bool Msat_ClauseReadLearned( Msat_Clause_t * pC );
+extern int Msat_ClauseReadSize( Msat_Clause_t * pC );
+extern int * Msat_ClauseReadLits( Msat_Clause_t * pC );
+extern bool Msat_ClauseReadMark( Msat_Clause_t * pC );
+extern void Msat_ClauseSetMark( Msat_Clause_t * pC, bool fMark );
+extern int Msat_ClauseReadNum( Msat_Clause_t * pC );
+extern void Msat_ClauseSetNum( Msat_Clause_t * pC, int Num );
+extern bool Msat_ClauseReadTypeA( Msat_Clause_t * pC );
+extern void Msat_ClauseSetTypeA( Msat_Clause_t * pC, bool fTypeA );
+extern bool Msat_ClauseIsLocked( Msat_Solver_t * p, Msat_Clause_t * pC );
+extern float Msat_ClauseReadActivity( Msat_Clause_t * pC );
+extern void Msat_ClauseWriteActivity( Msat_Clause_t * pC, float Num );
+extern void Msat_ClauseFree( Msat_Solver_t * p, Msat_Clause_t * pC, bool fRemoveWatched );
+extern bool Msat_ClausePropagate( Msat_Clause_t * pC, Msat_Lit_t Lit, int * pAssigns, Msat_Lit_t * pLit_out );
+extern bool Msat_ClauseSimplify( Msat_Clause_t * pC, int * pAssigns );
+extern void Msat_ClauseCalcReason( Msat_Solver_t * p, Msat_Clause_t * pC, Msat_Lit_t Lit, Msat_IntVec_t * vLits_out );
+extern void Msat_ClauseRemoveWatch( Msat_ClauseVec_t * vClauses, Msat_Clause_t * pC );
+extern void Msat_ClausePrint( Msat_Clause_t * pC );
+extern void Msat_ClausePrintSymbols( Msat_Clause_t * pC );
+extern void Msat_ClauseWriteDimacs( FILE * pFile, Msat_Clause_t * pC, bool fIncrement );
+extern unsigned Msat_ClauseComputeTruth( Msat_Solver_t * p, Msat_Clause_t * pC );
+/*=== satSort.c ===========================================================*/
+extern void Msat_SolverSortDB( Msat_Solver_t * p );
+/*=== satClauseVec.c ===========================================================*/
+extern Msat_ClauseVec_t * Msat_ClauseVecAlloc( int nCap );
+extern void Msat_ClauseVecFree( Msat_ClauseVec_t * p );
+extern Msat_Clause_t ** Msat_ClauseVecReadArray( Msat_ClauseVec_t * p );
+extern int Msat_ClauseVecReadSize( Msat_ClauseVec_t * p );
+extern void Msat_ClauseVecGrow( Msat_ClauseVec_t * p, int nCapMin );
+extern void Msat_ClauseVecShrink( Msat_ClauseVec_t * p, int nSizeNew );
+extern void Msat_ClauseVecClear( Msat_ClauseVec_t * p );
+extern void Msat_ClauseVecPush( Msat_ClauseVec_t * p, Msat_Clause_t * Entry );
+extern Msat_Clause_t * Msat_ClauseVecPop( Msat_ClauseVec_t * p );
+extern void Msat_ClauseVecWriteEntry( Msat_ClauseVec_t * p, int i, Msat_Clause_t * Entry );
+extern Msat_Clause_t * Msat_ClauseVecReadEntry( Msat_ClauseVec_t * p, int i );
+
+/*=== satMem.c ===========================================================*/
+// fixed-size-block memory manager
+extern Msat_MmFixed_t * Msat_MmFixedStart( int nEntrySize );
+extern void Msat_MmFixedStop( Msat_MmFixed_t * p, int fVerbose );
+extern char * Msat_MmFixedEntryFetch( Msat_MmFixed_t * p );
+extern void Msat_MmFixedEntryRecycle( Msat_MmFixed_t * p, char * pEntry );
+extern void Msat_MmFixedRestart( Msat_MmFixed_t * p );
+extern int Msat_MmFixedReadMemUsage( Msat_MmFixed_t * p );
+// flexible-size-block memory manager
+extern Msat_MmFlex_t * Msat_MmFlexStart();
+extern void Msat_MmFlexStop( Msat_MmFlex_t * p, int fVerbose );
+extern char * Msat_MmFlexEntryFetch( Msat_MmFlex_t * p, int nBytes );
+extern int Msat_MmFlexReadMemUsage( Msat_MmFlex_t * p );
+// hierarchical memory manager
+extern Msat_MmStep_t * Msat_MmStepStart( int nSteps );
+extern void Msat_MmStepStop( Msat_MmStep_t * p, int fVerbose );
+extern char * Msat_MmStepEntryFetch( Msat_MmStep_t * p, int nBytes );
+extern void Msat_MmStepEntryRecycle( Msat_MmStep_t * p, char * pEntry, int nBytes );
+extern int Msat_MmStepReadMemUsage( Msat_MmStep_t * p );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+#endif
diff --git a/src/sat/msat/msatMem.c b/src/sat/msat/msatMem.c
new file mode 100644
index 00000000..2d178094
--- /dev/null
+++ b/src/sat/msat/msatMem.c
@@ -0,0 +1,529 @@
+/**CFile****************************************************************
+
+ FileName [msatMem.c]
+
+ PackageName [A C version of SAT solver MINISAT, originally developed
+ in C++ by Niklas Een and Niklas Sorensson, Chalmers University of
+ Technology, Sweden: http://www.cs.chalmers.se/~een/Satzoo.]
+
+ Synopsis [Memory managers borrowed from Extra.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - January 1, 2004.]
+
+ Revision [$Id: msatMem.c,v 1.0 2004/01/01 1:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "msatInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+struct Msat_MmFixed_t_
+{
+ // information about individual entries
+ int nEntrySize; // the size of one entry
+ int nEntriesAlloc; // the total number of entries allocated
+ int nEntriesUsed; // the number of entries in use
+ int nEntriesMax; // the max number of entries in use
+ char * pEntriesFree; // the linked list of free entries
+
+ // this is where the memory is stored
+ int nChunkSize; // the size of one chunk
+ int nChunksAlloc; // the maximum number of memory chunks
+ int nChunks; // the current number of memory chunks
+ char ** pChunks; // the allocated memory
+
+ // statistics
+ int nMemoryUsed; // memory used in the allocated entries
+ int nMemoryAlloc; // memory allocated
+};
+
+struct Msat_MmFlex_t_
+{
+ // information about individual entries
+ int nEntriesUsed; // the number of entries allocated
+ char * pCurrent; // the current pointer to free memory
+ char * pEnd; // the first entry outside the free memory
+
+ // this is where the memory is stored
+ int nChunkSize; // the size of one chunk
+ int nChunksAlloc; // the maximum number of memory chunks
+ int nChunks; // the current number of memory chunks
+ char ** pChunks; // the allocated memory
+
+ // statistics
+ int nMemoryUsed; // memory used in the allocated entries
+ int nMemoryAlloc; // memory allocated
+};
+
+
+struct Msat_MmStep_t_
+{
+ int nMems; // the number of fixed memory managers employed
+ Msat_MmFixed_t ** pMems; // memory managers: 2^1 words, 2^2 words, etc
+ int nMapSize; // the size of the memory array
+ Msat_MmFixed_t ** pMap; // maps the number of bytes into its memory manager
+};
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Allocates memory pieces of fixed size.]
+
+ Description [The size of the chunk is computed as the minimum of
+ 1024 entries and 64K. Can only work with entry size at least 4 byte long.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_MmFixed_t * Msat_MmFixedStart( int nEntrySize )
+{
+ Msat_MmFixed_t * p;
+
+ p = ALLOC( Msat_MmFixed_t, 1 );
+ memset( p, 0, sizeof(Msat_MmFixed_t) );
+
+ p->nEntrySize = nEntrySize;
+ p->nEntriesAlloc = 0;
+ p->nEntriesUsed = 0;
+ p->pEntriesFree = NULL;
+
+ if ( nEntrySize * (1 << 10) < (1<<16) )
+ p->nChunkSize = (1 << 10);
+ else
+ p->nChunkSize = (1<<16) / nEntrySize;
+ if ( p->nChunkSize < 8 )
+ p->nChunkSize = 8;
+
+ p->nChunksAlloc = 64;
+ p->nChunks = 0;
+ p->pChunks = ALLOC( char *, p->nChunksAlloc );
+
+ p->nMemoryUsed = 0;
+ p->nMemoryAlloc = 0;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_MmFixedStop( Msat_MmFixed_t * p, int fVerbose )
+{
+ int i;
+ if ( p == NULL )
+ return;
+ if ( fVerbose )
+ {
+ printf( "Fixed memory manager: Entry = %5d. Chunk = %5d. Chunks used = %5d.\n",
+ p->nEntrySize, p->nChunkSize, p->nChunks );
+ printf( " Entries used = %8d. Entries peak = %8d. Memory used = %8d. Memory alloc = %8d.\n",
+ p->nEntriesUsed, p->nEntriesMax, p->nEntrySize * p->nEntriesUsed, p->nMemoryAlloc );
+ }
+ for ( i = 0; i < p->nChunks; i++ )
+ free( p->pChunks[i] );
+ free( p->pChunks );
+ free( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Msat_MmFixedEntryFetch( Msat_MmFixed_t * p )
+{
+ char * pTemp;
+ int i;
+
+ // check if there are still free entries
+ if ( p->nEntriesUsed == p->nEntriesAlloc )
+ { // need to allocate more entries
+ assert( p->pEntriesFree == NULL );
+ if ( p->nChunks == p->nChunksAlloc )
+ {
+ p->nChunksAlloc *= 2;
+ p->pChunks = REALLOC( char *, p->pChunks, p->nChunksAlloc );
+ }
+ p->pEntriesFree = ALLOC( char, p->nEntrySize * p->nChunkSize );
+ p->nMemoryAlloc += p->nEntrySize * p->nChunkSize;
+ // transform these entries into a linked list
+ pTemp = p->pEntriesFree;
+ for ( i = 1; i < p->nChunkSize; i++ )
+ {
+ *((char **)pTemp) = pTemp + p->nEntrySize;
+ pTemp += p->nEntrySize;
+ }
+ // set the last link
+ *((char **)pTemp) = NULL;
+ // add the chunk to the chunk storage
+ p->pChunks[ p->nChunks++ ] = p->pEntriesFree;
+ // add to the number of entries allocated
+ p->nEntriesAlloc += p->nChunkSize;
+ }
+ // incrememt the counter of used entries
+ p->nEntriesUsed++;
+ if ( p->nEntriesMax < p->nEntriesUsed )
+ p->nEntriesMax = p->nEntriesUsed;
+ // return the first entry in the free entry list
+ pTemp = p->pEntriesFree;
+ p->pEntriesFree = *((char **)pTemp);
+ return pTemp;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_MmFixedEntryRecycle( Msat_MmFixed_t * p, char * pEntry )
+{
+ // decrement the counter of used entries
+ p->nEntriesUsed--;
+ // add the entry to the linked list of free entries
+ *((char **)pEntry) = p->pEntriesFree;
+ p->pEntriesFree = pEntry;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description [Relocates all the memory except the first chunk.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_MmFixedRestart( Msat_MmFixed_t * p )
+{
+ int i;
+ char * pTemp;
+
+ // delocate all chunks except the first one
+ for ( i = 1; i < p->nChunks; i++ )
+ free( p->pChunks[i] );
+ p->nChunks = 1;
+ // transform these entries into a linked list
+ pTemp = p->pChunks[0];
+ for ( i = 1; i < p->nChunkSize; i++ )
+ {
+ *((char **)pTemp) = pTemp + p->nEntrySize;
+ pTemp += p->nEntrySize;
+ }
+ // set the last link
+ *((char **)pTemp) = NULL;
+ // set the free entry list
+ p->pEntriesFree = p->pChunks[0];
+ // set the correct statistics
+ p->nMemoryAlloc = p->nEntrySize * p->nChunkSize;
+ p->nMemoryUsed = 0;
+ p->nEntriesAlloc = p->nChunkSize;
+ p->nEntriesUsed = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Msat_MmFixedReadMemUsage( Msat_MmFixed_t * p )
+{
+ return p->nMemoryAlloc;
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Allocates entries of flexible size.]
+
+ Description [Can only work with entry size at least 4 byte long.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_MmFlex_t * Msat_MmFlexStart()
+{
+ Msat_MmFlex_t * p;
+
+ p = ALLOC( Msat_MmFlex_t, 1 );
+ memset( p, 0, sizeof(Msat_MmFlex_t) );
+
+ p->nEntriesUsed = 0;
+ p->pCurrent = NULL;
+ p->pEnd = NULL;
+
+ p->nChunkSize = (1 << 12);
+ p->nChunksAlloc = 64;
+ p->nChunks = 0;
+ p->pChunks = ALLOC( char *, p->nChunksAlloc );
+
+ p->nMemoryUsed = 0;
+ p->nMemoryAlloc = 0;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_MmFlexStop( Msat_MmFlex_t * p, int fVerbose )
+{
+ int i;
+ if ( p == NULL )
+ return;
+ if ( fVerbose )
+ {
+ printf( "Flexible memory manager: Chunk size = %d. Chunks used = %d.\n",
+ p->nChunkSize, p->nChunks );
+ printf( " Entries used = %d. Memory used = %d. Memory alloc = %d.\n",
+ p->nEntriesUsed, p->nMemoryUsed, p->nMemoryAlloc );
+ }
+ for ( i = 0; i < p->nChunks; i++ )
+ free( p->pChunks[i] );
+ free( p->pChunks );
+ free( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Msat_MmFlexEntryFetch( Msat_MmFlex_t * p, int nBytes )
+{
+ char * pTemp;
+ // check if there are still free entries
+ if ( p->pCurrent == NULL || p->pCurrent + nBytes > p->pEnd )
+ { // need to allocate more entries
+ if ( p->nChunks == p->nChunksAlloc )
+ {
+ p->nChunksAlloc *= 2;
+ p->pChunks = REALLOC( char *, p->pChunks, p->nChunksAlloc );
+ }
+ if ( nBytes > p->nChunkSize )
+ {
+ // resize the chunk size if more memory is requested than it can give
+ // (ideally, this should never happen)
+ p->nChunkSize = 2 * nBytes;
+ }
+ p->pCurrent = ALLOC( char, p->nChunkSize );
+ p->pEnd = p->pCurrent + p->nChunkSize;
+ p->nMemoryAlloc += p->nChunkSize;
+ // add the chunk to the chunk storage
+ p->pChunks[ p->nChunks++ ] = p->pCurrent;
+ }
+ assert( p->pCurrent + nBytes <= p->pEnd );
+ // increment the counter of used entries
+ p->nEntriesUsed++;
+ // keep track of the memory used
+ p->nMemoryUsed += nBytes;
+ // return the next entry
+ pTemp = p->pCurrent;
+ p->pCurrent += nBytes;
+ return pTemp;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Msat_MmFlexReadMemUsage( Msat_MmFlex_t * p )
+{
+ return p->nMemoryAlloc;
+}
+
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Starts the hierarchical memory manager.]
+
+ Description [This manager can allocate entries of any size.
+ Iternally they are mapped into the entries with the number of bytes
+ equal to the power of 2. The smallest entry size is 8 bytes. The
+ next one is 16 bytes etc. So, if the user requests 6 bytes, he gets
+ 8 byte entry. If we asks for 25 bytes, he gets 32 byte entry etc.
+ The input parameters "nSteps" says how many fixed memory managers
+ are employed internally. Calling this procedure with nSteps equal
+ to 10 results in 10 hierarchically arranged internal memory managers,
+ which can allocate up to 4096 (1Kb) entries. Requests for larger
+ entries are handed over to malloc() and then free()ed.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_MmStep_t * Msat_MmStepStart( int nSteps )
+{
+ Msat_MmStep_t * p;
+ int i, k;
+ p = ALLOC( Msat_MmStep_t, 1 );
+ p->nMems = nSteps;
+ // start the fixed memory managers
+ p->pMems = ALLOC( Msat_MmFixed_t *, p->nMems );
+ for ( i = 0; i < p->nMems; i++ )
+ p->pMems[i] = Msat_MmFixedStart( (8<<i) );
+ // set up the mapping of the required memory size into the corresponding manager
+ p->nMapSize = (4<<p->nMems);
+ p->pMap = ALLOC( Msat_MmFixed_t *, p->nMapSize+1 );
+ p->pMap[0] = NULL;
+ for ( k = 1; k <= 4; k++ )
+ p->pMap[k] = p->pMems[0];
+ for ( i = 0; i < p->nMems; i++ )
+ for ( k = (4<<i)+1; k <= (8<<i); k++ )
+ p->pMap[k] = p->pMems[i];
+//for ( i = 1; i < 100; i ++ )
+//printf( "%10d: size = %10d\n", i, p->pMap[i]->nEntrySize );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Stops the memory manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_MmStepStop( Msat_MmStep_t * p, int fVerbose )
+{
+ int i;
+ for ( i = 0; i < p->nMems; i++ )
+ Msat_MmFixedStop( p->pMems[i], fVerbose );
+ free( p->pMems );
+ free( p->pMap );
+ free( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates the entry.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Msat_MmStepEntryFetch( Msat_MmStep_t * p, int nBytes )
+{
+ if ( nBytes == 0 )
+ return NULL;
+ if ( nBytes > p->nMapSize )
+ {
+// printf( "Allocating %d bytes.\n", nBytes );
+ return ALLOC( char, nBytes );
+ }
+ return Msat_MmFixedEntryFetch( p->pMap[nBytes] );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Recycles the entry.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_MmStepEntryRecycle( Msat_MmStep_t * p, char * pEntry, int nBytes )
+{
+ if ( nBytes == 0 )
+ return;
+ if ( nBytes > p->nMapSize )
+ {
+ free( pEntry );
+ return;
+ }
+ Msat_MmFixedEntryRecycle( p->pMap[nBytes], pEntry );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Msat_MmStepReadMemUsage( Msat_MmStep_t * p )
+{
+ int i, nMemTotal = 0;
+ for ( i = 0; i < p->nMems; i++ )
+ nMemTotal += p->pMems[i]->nMemoryAlloc;
+ return nMemTotal;
+}
diff --git a/src/sat/msat/msatOrderH.c b/src/sat/msat/msatOrderH.c
new file mode 100644
index 00000000..ca034233
--- /dev/null
+++ b/src/sat/msat/msatOrderH.c
@@ -0,0 +1,405 @@
+/**CFile****************************************************************
+
+ FileName [msatOrder.c]
+
+ PackageName [A C version of SAT solver MINISAT, originally developed
+ in C++ by Niklas Een and Niklas Sorensson, Chalmers University of
+ Technology, Sweden: http://www.cs.chalmers.se/~een/Satzoo.]
+
+ Synopsis [The manager of variable assignment.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - January 1, 2004.]
+
+ Revision [$Id: msatOrder.c,v 1.0 2005/05/30 1:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "msatInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// the variable package data structure
+struct Msat_Order_t_
+{
+ Msat_Solver_t * pSat; // the SAT solver
+ Msat_IntVec_t * vIndex; // the heap
+ Msat_IntVec_t * vHeap; // the mapping of var num into its heap num
+};
+
+//The solver can communicate to the variable order the following parts:
+//- the array of current assignments (pSat->pAssigns)
+//- the array of variable activities (pSat->pdActivity)
+//- the array of variables currently in the cone (pSat->vConeVars)
+//- the array of arrays of variables adjucent to each(pSat->vAdjacents)
+
+#define HLEFT(i) ((i)<<1)
+#define HRIGHT(i) (((i)<<1)+1)
+#define HPARENT(i) ((i)>>1)
+#define HCOMPARE(p, i, j) ((p)->pSat->pdActivity[i] > (p)->pSat->pdActivity[j])
+#define HHEAP(p, i) ((p)->vHeap->pArray[i])
+#define HSIZE(p) ((p)->vHeap->nSize)
+#define HOKAY(p, i) ((i) >= 0 && (i) < (p)->vIndex->nSize)
+#define HINHEAP(p, i) (HOKAY(p, i) && (p)->vIndex->pArray[i] != 0)
+#define HEMPTY(p) (HSIZE(p) == 1)
+
+static int Msat_HeapCheck_rec( Msat_Order_t * p, int i );
+static int Msat_HeapGetTop( Msat_Order_t * p );
+static void Msat_HeapInsert( Msat_Order_t * p, int n );
+static void Msat_HeapIncrease( Msat_Order_t * p, int n );
+static void Msat_HeapPercolateUp( Msat_Order_t * p, int i );
+static void Msat_HeapPercolateDown( Msat_Order_t * p, int i );
+
+extern int timeSelect;
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Allocates the ordering structure.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_Order_t * Msat_OrderAlloc( Msat_Solver_t * pSat )
+{
+ Msat_Order_t * p;
+ p = ALLOC( Msat_Order_t, 1 );
+ memset( p, 0, sizeof(Msat_Order_t) );
+ p->pSat = pSat;
+ p->vIndex = Msat_IntVecAlloc( 0 );
+ p->vHeap = Msat_IntVecAlloc( 0 );
+ Msat_OrderSetBounds( p, pSat->nVarsAlloc );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the bound of the ordering structure.]
+
+ Description [Should be called whenever the SAT solver is resized.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_OrderSetBounds( Msat_Order_t * p, int nVarsMax )
+{
+ Msat_IntVecGrow( p->vIndex, nVarsMax );
+ Msat_IntVecGrow( p->vHeap, nVarsMax + 1 );
+ p->vIndex->nSize = nVarsMax;
+ p->vHeap->nSize = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Cleans the ordering structure.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_OrderClean( Msat_Order_t * p, Msat_IntVec_t * vCone )
+{
+ int i;
+ for ( i = 0; i < p->vIndex->nSize; i++ )
+ p->vIndex->pArray[i] = 0;
+ for ( i = 0; i < vCone->nSize; i++ )
+ {
+ assert( i+1 < p->vHeap->nCap );
+ p->vHeap->pArray[i+1] = vCone->pArray[i];
+
+ assert( vCone->pArray[i] < p->vIndex->nSize );
+ p->vIndex->pArray[vCone->pArray[i]] = i+1;
+ }
+ p->vHeap->nSize = vCone->nSize + 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks that the J-boundary is okay.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Msat_OrderCheck( Msat_Order_t * p )
+{
+ return Msat_HeapCheck_rec( p, 1 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Frees the ordering structure.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_OrderFree( Msat_Order_t * p )
+{
+ Msat_IntVecFree( p->vHeap );
+ Msat_IntVecFree( p->vIndex );
+ free( p );
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Selects the next variable to assign.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Msat_OrderVarSelect( Msat_Order_t * p )
+{
+ // Activity based decision:
+// while (!heap.empty()){
+// Var next = heap.getmin();
+// if (toLbool(assigns[next]) == l_Undef)
+// return next;
+// }
+// return var_Undef;
+
+ int Var;
+ int clk = clock();
+
+ while ( !HEMPTY(p) )
+ {
+ Var = Msat_HeapGetTop(p);
+ if ( (p)->pSat->pAssigns[Var] == MSAT_VAR_UNASSIGNED )
+ {
+//assert( Msat_OrderCheck(p) );
+timeSelect += clock() - clk;
+ return Var;
+ }
+ }
+ return MSAT_ORDER_UNKNOWN;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Updates J-boundary when the variable is assigned.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_OrderVarAssigned( Msat_Order_t * p, int Var )
+{
+}
+
+/**Function*************************************************************
+
+ Synopsis [Updates the order after a variable is unassigned.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_OrderVarUnassigned( Msat_Order_t * p, int Var )
+{
+// if (!heap.inHeap(x))
+// heap.insert(x);
+
+ int clk = clock();
+ if ( !HINHEAP(p,Var) )
+ Msat_HeapInsert( p, Var );
+timeSelect += clock() - clk;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Updates the order after a variable changed weight.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_OrderUpdate( Msat_Order_t * p, int Var )
+{
+// if (heap.inHeap(x))
+// heap.increase(x);
+
+ int clk = clock();
+ if ( HINHEAP(p,Var) )
+ Msat_HeapIncrease( p, Var );
+timeSelect += clock() - clk;
+}
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Checks the heap property recursively.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Msat_HeapCheck_rec( Msat_Order_t * p, int i )
+{
+ return i >= HSIZE(p) ||
+ ( HPARENT(i) == 0 || !HCOMPARE(p, HHEAP(p, i), HHEAP(p, HPARENT(i))) ) &&
+ Msat_HeapCheck_rec( p, HLEFT(i) ) && Msat_HeapCheck_rec( p, HRIGHT(i) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Retrieves the minimum element.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Msat_HeapGetTop( Msat_Order_t * p )
+{
+ int Result, NewTop;
+ Result = HHEAP(p, 1);
+ NewTop = Msat_IntVecPop( p->vHeap );
+ p->vHeap->pArray[1] = NewTop;
+ p->vIndex->pArray[NewTop] = 1;
+ p->vIndex->pArray[Result] = 0;
+ if ( p->vHeap->nSize > 1 )
+ Msat_HeapPercolateDown( p, 1 );
+ return Result;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Inserts the new element.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_HeapInsert( Msat_Order_t * p, int n )
+{
+ assert( HOKAY(p, n) );
+ p->vIndex->pArray[n] = HSIZE(p);
+ Msat_IntVecPush( p->vHeap, n );
+ Msat_HeapPercolateUp( p, p->vIndex->pArray[n] );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Inserts the new element.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_HeapIncrease( Msat_Order_t * p, int n )
+{
+ Msat_HeapPercolateUp( p, p->vIndex->pArray[n] );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Moves the entry up.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_HeapPercolateUp( Msat_Order_t * p, int i )
+{
+ int x = HHEAP(p, i);
+ while ( HPARENT(i) != 0 && HCOMPARE(p, x, HHEAP(p, HPARENT(i))) )
+ {
+ p->vHeap->pArray[i] = HHEAP(p, HPARENT(i));
+ p->vIndex->pArray[HHEAP(p, i)] = i;
+ i = HPARENT(i);
+ }
+ p->vHeap->pArray[i] = x;
+ p->vIndex->pArray[x] = i;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Moves the entry down.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_HeapPercolateDown( Msat_Order_t * p, int i )
+{
+ int x = HHEAP(p, i);
+ int Child;
+ while ( HLEFT(i) < HSIZE(p) )
+ {
+ if ( HRIGHT(i) < HSIZE(p) && HCOMPARE(p, HHEAP(p, HRIGHT(i)), HHEAP(p, HLEFT(i))) )
+ Child = HRIGHT(i);
+ else
+ Child = HLEFT(i);
+ if ( !HCOMPARE(p, HHEAP(p, Child), x) )
+ break;
+ p->vHeap->pArray[i] = HHEAP(p, Child);
+ p->vIndex->pArray[HHEAP(p, i)] = i;
+ i = Child;
+ }
+ p->vHeap->pArray[i] = x;
+ p->vIndex->pArray[x] = i;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sat/msat/msatOrderJ.c b/src/sat/msat/msatOrderJ.c
new file mode 100644
index 00000000..6067b40f
--- /dev/null
+++ b/src/sat/msat/msatOrderJ.c
@@ -0,0 +1,466 @@
+/**CFile****************************************************************
+
+ FileName [msatOrder.c]
+
+ PackageName [A C version of SAT solver MINISAT, originally developed
+ in C++ by Niklas Een and Niklas Sorensson, Chalmers University of
+ Technology, Sweden: http://www.cs.chalmers.se/~een/Satzoo.]
+
+ Synopsis [The manager of variable assignment.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - January 1, 2004.]
+
+ Revision [$Id: msatOrder.c,v 1.0 2005/05/30 1:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "msatInt.h"
+
+/*
+The J-boundary (justification boundary) is defined as a set of unassigned
+variables belonging to the cone of interest, such that for each of them,
+there exist an adjacent assigned variable in the cone of interest.
+*/
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct Msat_OrderVar_t_ Msat_OrderVar_t;
+typedef struct Msat_OrderRing_t_ Msat_OrderRing_t;
+
+// the variable data structure
+struct Msat_OrderVar_t_
+{
+ Msat_OrderVar_t * pNext;
+ Msat_OrderVar_t * pPrev;
+ int Num;
+};
+
+// the ring of variables data structure (J-boundary)
+struct Msat_OrderRing_t_
+{
+ Msat_OrderVar_t * pRoot;
+ int nItems;
+};
+
+// the variable package data structure
+struct Msat_Order_t_
+{
+ Msat_Solver_t * pSat; // the SAT solver
+ Msat_OrderVar_t * pVars; // the storage for variables
+ int nVarsAlloc; // the number of variables allocated
+ Msat_OrderRing_t rVars; // the J-boundary as a ring of variables
+};
+
+//The solver can communicate to the variable order the following parts:
+//- the array of current assignments (pSat->pAssigns)
+//- the array of variable activities (pSat->pdActivity)
+//- the array of variables currently in the cone (pSat->vConeVars)
+//- the array of arrays of variables adjucent to each(pSat->vAdjacents)
+
+#define Msat_OrderVarIsInBoundary( p, i ) ((p)->pVars[i].pNext)
+#define Msat_OrderVarIsAssigned( p, i ) ((p)->pSat->pAssigns[i] != MSAT_VAR_UNASSIGNED)
+#define Msat_OrderVarIsUsedInCone( p, i ) ((p)->pSat->vVarsUsed->pArray[i])
+
+// iterator through the entries in J-boundary
+#define Msat_OrderRingForEachEntry( pRing, pVar, pNext ) \
+ for ( pVar = pRing, \
+ pNext = pVar? pVar->pNext : NULL; \
+ pVar; \
+ pVar = (pNext != pRing)? pNext : NULL, \
+ pNext = pVar? pVar->pNext : NULL )
+
+static void Msat_OrderRingAddLast( Msat_OrderRing_t * pRing, Msat_OrderVar_t * pVar );
+static void Msat_OrderRingRemove( Msat_OrderRing_t * pRing, Msat_OrderVar_t * pVar );
+
+extern int timeSelect;
+extern int timeAssign;
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Allocates the ordering structure.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_Order_t * Msat_OrderAlloc( Msat_Solver_t * pSat )
+{
+ Msat_Order_t * p;
+ p = ALLOC( Msat_Order_t, 1 );
+ memset( p, 0, sizeof(Msat_Order_t) );
+ p->pSat = pSat;
+ Msat_OrderSetBounds( p, pSat->nVarsAlloc );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the bound of the ordering structure.]
+
+ Description [Should be called whenever the SAT solver is resized.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_OrderSetBounds( Msat_Order_t * p, int nVarsMax )
+{
+ int i;
+ // add variables if they are missing
+ if ( p->nVarsAlloc < nVarsMax )
+ {
+ p->pVars = REALLOC( Msat_OrderVar_t, p->pVars, nVarsMax );
+ for ( i = p->nVarsAlloc; i < nVarsMax; i++ )
+ {
+ p->pVars[i].pNext = p->pVars[i].pPrev = NULL;
+ p->pVars[i].Num = i;
+ }
+ p->nVarsAlloc = nVarsMax;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Cleans the ordering structure.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_OrderClean( Msat_Order_t * p, Msat_IntVec_t * vCone )
+{
+ Msat_OrderVar_t * pVar, * pNext;
+ // quickly undo the ring
+ Msat_OrderRingForEachEntry( p->rVars.pRoot, pVar, pNext )
+ pVar->pNext = pVar->pPrev = NULL;
+ p->rVars.pRoot = NULL;
+ p->rVars.nItems = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks that the J-boundary is okay.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Msat_OrderCheck( Msat_Order_t * p )
+{
+ Msat_OrderVar_t * pVar, * pNext;
+ Msat_IntVec_t * vRound;
+ int * pRound, nRound;
+ int * pVars, nVars, i;
+
+ // go through all the variables in the boundary
+ Msat_OrderRingForEachEntry( p->rVars.pRoot, pVar, pNext )
+ {
+ assert( !Msat_OrderVarIsAssigned(p, pVar->Num) );
+ // go though all the variables in the neighborhood
+ // and check that it is true that there is least one assigned
+ vRound = (Msat_IntVec_t *)Msat_ClauseVecReadEntry( p->pSat->vAdjacents, pVar->Num );
+ nRound = Msat_IntVecReadSize( vRound );
+ pRound = Msat_IntVecReadArray( vRound );
+ for ( i = 0; i < nRound; i++ )
+ {
+ if ( !Msat_OrderVarIsUsedInCone(p, pRound[i]) )
+ continue;
+ if ( Msat_OrderVarIsAssigned(p, pRound[i]) )
+ break;
+ }
+ assert( i != nRound );
+ if ( i != nRound )
+ return 0;
+ }
+
+ // we may also check other unassigned variables in the cone
+ // to make sure that if they are not in J-boundary,
+ // then they do not have an assigned neighbor
+ nVars = Msat_IntVecReadSize( p->pSat->vConeVars );
+ pVars = Msat_IntVecReadArray( p->pSat->vConeVars );
+ for ( i = 0; i < nVars; i++ )
+ {
+ assert( Msat_OrderVarIsUsedInCone(p, pVars[i]) );
+ // skip assigned vars, vars in the boundary, and vars not used in the cone
+ if ( Msat_OrderVarIsAssigned(p, pVars[i]) ||
+ Msat_OrderVarIsInBoundary(p, pVars[i]) )
+ continue;
+ // make sure, it does not have assigned neighbors
+ vRound = (Msat_IntVec_t *)Msat_ClauseVecReadEntry( p->pSat->vAdjacents, pVars[i] );
+ nRound = Msat_IntVecReadSize( vRound );
+ pRound = Msat_IntVecReadArray( vRound );
+ for ( i = 0; i < nRound; i++ )
+ {
+ if ( !Msat_OrderVarIsUsedInCone(p, pRound[i]) )
+ continue;
+ if ( Msat_OrderVarIsAssigned(p, pRound[i]) )
+ break;
+ }
+ assert( i == nRound );
+ if ( i == nRound )
+ return 0;
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Frees the ordering structure.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_OrderFree( Msat_Order_t * p )
+{
+ free( p->pVars );
+ free( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Selects the next variable to assign.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Msat_OrderVarSelect( Msat_Order_t * p )
+{
+ Msat_OrderVar_t * pVar, * pNext, * pVarBest;
+ double * pdActs = p->pSat->pdActivity;
+ double dfActBest;
+ int clk = clock();
+
+ pVarBest = NULL;
+ dfActBest = -1.0;
+ Msat_OrderRingForEachEntry( p->rVars.pRoot, pVar, pNext )
+ {
+ if ( dfActBest < pdActs[pVar->Num] )
+ {
+ dfActBest = pdActs[pVar->Num];
+ pVarBest = pVar;
+ }
+ }
+timeSelect += clock() - clk;
+timeAssign += clock() - clk;
+
+//if ( pVarBest && pVarBest->Num % 1000 == 0 )
+//printf( "%d ", p->rVars.nItems );
+
+ if ( pVarBest )
+ {
+ assert( Msat_OrderVarIsUsedInCone(p, pVarBest->Num) );
+ return pVarBest->Num;
+ }
+ return MSAT_ORDER_UNKNOWN;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Updates J-boundary when the variable is assigned.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_OrderVarAssigned( Msat_Order_t * p, int Var )
+{
+ Msat_IntVec_t * vRound;
+ int i, clk = clock();
+
+ // make sure the variable is in the boundary
+ assert( Var < p->nVarsAlloc );
+ // if it is not in the boundary (initial decision, random decision), do not remove
+ if ( Msat_OrderVarIsInBoundary( p, Var ) )
+ Msat_OrderRingRemove( &p->rVars, &p->pVars[Var] );
+ // add to the boundary those neighbors that are (1) unassigned, (2) not in boundary
+ // because for them we know that there is a variable (Var) which is assigned
+ vRound = (Msat_IntVec_t *)p->pSat->vAdjacents->pArray[Var];
+ for ( i = 0; i < vRound->nSize; i++ )
+ {
+ if ( !Msat_OrderVarIsUsedInCone(p, vRound->pArray[i]) )
+ continue;
+ if ( Msat_OrderVarIsAssigned(p, vRound->pArray[i]) )
+ continue;
+ if ( Msat_OrderVarIsInBoundary(p, vRound->pArray[i]) )
+ continue;
+ Msat_OrderRingAddLast( &p->rVars, &p->pVars[vRound->pArray[i]] );
+ }
+timeSelect += clock() - clk;
+// Msat_OrderCheck( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Updates the order after a variable is unassigned.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_OrderVarUnassigned( Msat_Order_t * p, int Var )
+{
+ Msat_IntVec_t * vRound, * vRound2;
+ int i, k, clk = clock();
+
+ // make sure the variable is not in the boundary
+ assert( Var < p->nVarsAlloc );
+ assert( !Msat_OrderVarIsInBoundary( p, Var ) );
+ // go through its neigbors - if one of them is assigned add this var
+ // add to the boundary those neighbors that are not there already
+ // this will also get rid of variable outside of the current cone
+ // because they are unassigned in Msat_SolverPrepare()
+ vRound = (Msat_IntVec_t *)p->pSat->vAdjacents->pArray[Var];
+ for ( i = 0; i < vRound->nSize; i++ )
+ if ( Msat_OrderVarIsAssigned(p, vRound->pArray[i]) )
+ break;
+ if ( i != vRound->nSize )
+ Msat_OrderRingAddLast( &p->rVars, &p->pVars[Var] );
+
+ // unassigning a variable may lead to its adjacents dropping from the boundary
+ for ( i = 0; i < vRound->nSize; i++ )
+ if ( Msat_OrderVarIsInBoundary(p, vRound->pArray[i]) )
+ { // the neighbor is in the J-boundary (and unassigned)
+ assert( !Msat_OrderVarIsAssigned(p, vRound->pArray[i]) );
+ vRound2 = (Msat_IntVec_t *)p->pSat->vAdjacents->pArray[vRound->pArray[i]];
+ // go through its neighbors and determine if there is at least one assigned
+ for ( k = 0; k < vRound2->nSize; k++ )
+ if ( Msat_OrderVarIsAssigned(p, vRound2->pArray[k]) )
+ break;
+ if ( k == vRound2->nSize ) // there is no assigned vars, delete this one
+ Msat_OrderRingRemove( &p->rVars, &p->pVars[vRound->pArray[i]] );
+ }
+timeSelect += clock() - clk;
+// Msat_OrderCheck( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Updates the order after a variable changed weight.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_OrderUpdate( Msat_Order_t * p, int Var )
+{
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Adds node to the end of the ring.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_OrderRingAddLast( Msat_OrderRing_t * pRing, Msat_OrderVar_t * pVar )
+{
+//printf( "adding %d\n", pVar->Num );
+ // check that the node is not in a ring
+ assert( pVar->pPrev == NULL );
+ assert( pVar->pNext == NULL );
+ // if the ring is empty, make the node point to itself
+ pRing->nItems++;
+ if ( pRing->pRoot == NULL )
+ {
+ pRing->pRoot = pVar;
+ pVar->pPrev = pVar;
+ pVar->pNext = pVar;
+ return;
+ }
+ // if the ring is not empty, add it as the last entry
+ pVar->pPrev = pRing->pRoot->pPrev;
+ pVar->pNext = pRing->pRoot;
+ pVar->pPrev->pNext = pVar;
+ pVar->pNext->pPrev = pVar;
+
+ // move the root so that it points to the new entry
+// pRing->pRoot = pRing->pRoot->pPrev;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Removes the node from the ring.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_OrderRingRemove( Msat_OrderRing_t * pRing, Msat_OrderVar_t * pVar )
+{
+//printf( "removing %d\n", pVar->Num );
+ // check that the var is in a ring
+ assert( pVar->pPrev );
+ assert( pVar->pNext );
+ pRing->nItems--;
+ if ( pRing->nItems == 0 )
+ {
+ assert( pRing->pRoot == pVar );
+ pVar->pPrev = NULL;
+ pVar->pNext = NULL;
+ pRing->pRoot = NULL;
+ return;
+ }
+ // move the root if needed
+ if ( pRing->pRoot == pVar )
+ pRing->pRoot = pVar->pNext;
+ // move the root to the next entry after pVar
+ // this way all the additions to the list will be traversed first
+// pRing->pRoot = pVar->pNext;
+ // delete the node
+ pVar->pPrev->pNext = pVar->pNext;
+ pVar->pNext->pPrev = pVar->pPrev;
+ pVar->pPrev = NULL;
+ pVar->pNext = NULL;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sat/msat/msatQueue.c b/src/sat/msat/msatQueue.c
new file mode 100644
index 00000000..c12cc75d
--- /dev/null
+++ b/src/sat/msat/msatQueue.c
@@ -0,0 +1,157 @@
+/**CFile****************************************************************
+
+ FileName [msatQueue.c]
+
+ PackageName [A C version of SAT solver MINISAT, originally developed
+ in C++ by Niklas Een and Niklas Sorensson, Chalmers University of
+ Technology, Sweden: http://www.cs.chalmers.se/~een/Satzoo.]
+
+ Synopsis [The manager of the assignment propagation queue.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - January 1, 2004.]
+
+ Revision [$Id: msatQueue.c,v 1.0 2004/01/01 1:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "msatInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+struct Msat_Queue_t_
+{
+ int nVars;
+ int * pVars;
+ int iFirst;
+ int iLast;
+};
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Allocates the variable propagation queue.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_Queue_t * Msat_QueueAlloc( int nVars )
+{
+ Msat_Queue_t * p;
+ p = ALLOC( Msat_Queue_t, 1 );
+ memset( p, 0, sizeof(Msat_Queue_t) );
+ p->nVars = nVars;
+ p->pVars = ALLOC( int, nVars );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Deallocate the variable propagation queue.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_QueueFree( Msat_Queue_t * p )
+{
+ free( p->pVars );
+ free( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads the queue size.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Msat_QueueReadSize( Msat_Queue_t * p )
+{
+ return p->iLast - p->iFirst;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Insert an entry into the queue.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_QueueInsert( Msat_Queue_t * p, int Lit )
+{
+ if ( p->iLast == p->nVars )
+ {
+ int i;
+ assert( 0 );
+ for ( i = 0; i < p->iLast; i++ )
+ printf( "entry = %2d lit = %2d var = %2d \n", i, p->pVars[i], p->pVars[i]/2 );
+ }
+ assert( p->iLast < p->nVars );
+ p->pVars[p->iLast++] = Lit;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Extracts an entry from the queue.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Msat_QueueExtract( Msat_Queue_t * p )
+{
+ if ( p->iFirst == p->iLast )
+ return -1;
+ return p->pVars[p->iFirst++];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Resets the queue.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_QueueClear( Msat_Queue_t * p )
+{
+ p->iFirst = 0;
+ p->iLast = 0;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sat/msat/msatRead.c b/src/sat/msat/msatRead.c
new file mode 100644
index 00000000..b8e585a4
--- /dev/null
+++ b/src/sat/msat/msatRead.c
@@ -0,0 +1,268 @@
+/**CFile****************************************************************
+
+ FileName [msatRead.c]
+
+ PackageName [A C version of SAT solver MINISAT, originally developed
+ in C++ by Niklas Een and Niklas Sorensson, Chalmers University of
+ Technology, Sweden: http://www.cs.chalmers.se/~een/Satzoo.]
+
+ Synopsis [The reader of the CNF formula in DIMACS format.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - January 1, 2004.]
+
+ Revision [$Id: msatRead.c,v 1.0 2004/01/01 1:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "msatInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static char * Msat_FileRead( FILE * pFile );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Read the file into the internal buffer.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Msat_FileRead( FILE * pFile )
+{
+ int nFileSize;
+ char * pBuffer;
+ // get the file size, in bytes
+ fseek( pFile, 0, SEEK_END );
+ nFileSize = ftell( pFile );
+ // move the file current reading position to the beginning
+ rewind( pFile );
+ // load the contents of the file into memory
+ pBuffer = ALLOC( char, nFileSize + 3 );
+ fread( pBuffer, nFileSize, 1, pFile );
+ // terminate the string with '\0'
+ pBuffer[ nFileSize + 0] = '\n';
+ pBuffer[ nFileSize + 1] = '\0';
+ return pBuffer;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static void Msat_ReadWhitespace( char ** pIn )
+{
+ while ((**pIn >= 9 && **pIn <= 13) || **pIn == 32)
+ (*pIn)++;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static void Msat_ReadNotWhitespace( char ** pIn )
+{
+ while ( !((**pIn >= 9 && **pIn <= 13) || **pIn == 32) )
+ (*pIn)++;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static void skipLine( char ** pIn )
+{
+ while ( 1 )
+ {
+ if (**pIn == 0)
+ return;
+ if (**pIn == '\n')
+ {
+ (*pIn)++;
+ return;
+ }
+ (*pIn)++;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static int Msat_ReadInt( char ** pIn )
+{
+ int val = 0;
+ bool neg = 0;
+
+ Msat_ReadWhitespace( pIn );
+ if ( **pIn == '-' )
+ neg = 1,
+ (*pIn)++;
+ else if ( **pIn == '+' )
+ (*pIn)++;
+ if ( **pIn < '0' || **pIn > '9' )
+ fprintf(stderr, "PARSE ERROR! Unexpected char: %c\n", **pIn),
+ exit(1);
+ while ( **pIn >= '0' && **pIn <= '9' )
+ val = val*10 + (**pIn - '0'),
+ (*pIn)++;
+ return neg ? -val : val;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static void Msat_ReadClause( char ** pIn, Msat_Solver_t * p, Msat_IntVec_t * pLits )
+{
+ int nVars = Msat_SolverReadVarNum( p );
+ int parsed_lit, var, sign;
+
+ Msat_IntVecClear( pLits );
+ while ( 1 )
+ {
+ parsed_lit = Msat_ReadInt(pIn);
+ if ( parsed_lit == 0 )
+ break;
+ var = abs(parsed_lit) - 1;
+ sign = (parsed_lit > 0);
+ if ( var >= nVars )
+ {
+ printf( "Variable %d is larger than the number of allocated variables (%d).\n", var+1, nVars );
+ exit(1);
+ }
+ Msat_IntVecPush( pLits, MSAT_VAR2LIT(var, !sign) );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static bool Msat_ReadDimacs( char * pText, Msat_Solver_t ** pS, bool fVerbose )
+{
+ Msat_Solver_t * p;
+ Msat_IntVec_t * pLits;
+ char * pIn = pText;
+ int nVars, nClas;
+ while ( 1 )
+ {
+ Msat_ReadWhitespace( &pIn );
+ if ( *pIn == 0 )
+ break;
+ else if ( *pIn == 'c' )
+ skipLine( &pIn );
+ else if ( *pIn == 'p' )
+ {
+ pIn++;
+ Msat_ReadWhitespace( &pIn );
+ Msat_ReadNotWhitespace( &pIn );
+
+ nVars = Msat_ReadInt( &pIn );
+ nClas = Msat_ReadInt( &pIn );
+ skipLine( &pIn );
+ // start the solver
+ p = Msat_SolverAlloc( nVars, 1, 1, 1, 1, 0 );
+ Msat_SolverClean( p, nVars );
+ Msat_SolverSetVerbosity( p, fVerbose );
+ // allocate the vector
+ pLits = Msat_IntVecAlloc( nVars );
+ }
+ else
+ {
+ if ( p == NULL )
+ {
+ printf( "There is no parameter line.\n" );
+ exit(1);
+ }
+ Msat_ReadClause( &pIn, p, pLits );
+ if ( !Msat_SolverAddClause( p, pLits ) )
+ return 0;
+ }
+ }
+ Msat_IntVecFree( pLits );
+ *pS = p;
+ return Msat_SolverSimplifyDB( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Starts the solver and reads the DIMAC file.]
+
+ Description [Returns FALSE upon immediate conflict.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Msat_SolverParseDimacs( FILE * pFile, Msat_Solver_t ** p, int fVerbose )
+{
+ char * pText;
+ bool Value;
+ pText = Msat_FileRead( pFile );
+ Value = Msat_ReadDimacs( pText, p, fVerbose );
+ free( pText );
+ return Value;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sat/msat/msatSolverApi.c b/src/sat/msat/msatSolverApi.c
new file mode 100644
index 00000000..ba506993
--- /dev/null
+++ b/src/sat/msat/msatSolverApi.c
@@ -0,0 +1,488 @@
+/**CFile****************************************************************
+
+ FileName [msatSolverApi.c]
+
+ PackageName [A C version of SAT solver MINISAT, originally developed
+ in C++ by Niklas Een and Niklas Sorensson, Chalmers University of
+ Technology, Sweden: http://www.cs.chalmers.se/~een/Satzoo.]
+
+ Synopsis [APIs of the SAT solver.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - January 1, 2004.]
+
+ Revision [$Id: msatSolverApi.c,v 1.0 2004/01/01 1:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "msatInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Msat_SolverSetupTruthTables( unsigned uTruths[][2] );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Simple SAT solver APIs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Msat_SolverReadVarNum( Msat_Solver_t * p ) { return p->nVars; }
+int Msat_SolverReadVarAllocNum( Msat_Solver_t * p ) { return p->nVarsAlloc;}
+int Msat_SolverReadDecisionLevel( Msat_Solver_t * p ) { return Msat_IntVecReadSize(p->vTrailLim); }
+int * Msat_SolverReadDecisionLevelArray( Msat_Solver_t * p ) { return p->pLevel; }
+Msat_Clause_t ** Msat_SolverReadReasonArray( Msat_Solver_t * p ) { return p->pReasons; }
+Msat_Lit_t Msat_SolverReadVarValue( Msat_Solver_t * p, Msat_Var_t Var ) { return p->pAssigns[Var]; }
+Msat_ClauseVec_t * Msat_SolverReadLearned( Msat_Solver_t * p ) { return p->vLearned; }
+Msat_ClauseVec_t ** Msat_SolverReadWatchedArray( Msat_Solver_t * p ) { return p->pvWatched; }
+int * Msat_SolverReadAssignsArray( Msat_Solver_t * p ) { return p->pAssigns; }
+int * Msat_SolverReadModelArray( Msat_Solver_t * p ) { return p->pModel; }
+int Msat_SolverReadBackTracks( Msat_Solver_t * p ) { return p->nBackTracks; }
+Msat_MmStep_t * Msat_SolverReadMem( Msat_Solver_t * p ) { return p->pMem; }
+int * Msat_SolverReadSeenArray( Msat_Solver_t * p ) { return p->pSeen; }
+int Msat_SolverIncrementSeenId( Msat_Solver_t * p ) { return ++p->nSeenId; }
+void Msat_SolverSetVerbosity( Msat_Solver_t * p, int fVerbose ) { p->fVerbose = fVerbose; }
+void Msat_SolverClausesIncrement( Msat_Solver_t * p ) { p->nClausesAlloc++; }
+void Msat_SolverClausesDecrement( Msat_Solver_t * p ) { p->nClausesAlloc--; }
+void Msat_SolverClausesIncrementL( Msat_Solver_t * p ) { p->nClausesAllocL++; }
+void Msat_SolverClausesDecrementL( Msat_Solver_t * p ) { p->nClausesAllocL--; }
+void Msat_SolverMarkLastClauseTypeA( Msat_Solver_t * p ) { Msat_ClauseSetTypeA( Msat_ClauseVecReadEntry( p->vClauses, Msat_ClauseVecReadSize(p->vClauses)-1 ), 1 ); }
+void Msat_SolverMarkClausesStart( Msat_Solver_t * p ) { p->nClausesStart = Msat_ClauseVecReadSize(p->vClauses); }
+
+/**Function*************************************************************
+
+ Synopsis [Reads the clause with the given number.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_Clause_t * Msat_SolverReadClause( Msat_Solver_t * p, int Num )
+{
+ int nClausesP;
+ assert( Num < p->nClauses );
+ nClausesP = Msat_ClauseVecReadSize( p->vClauses );
+ if ( Num < nClausesP )
+ return Msat_ClauseVecReadEntry( p->vClauses, Num );
+ return Msat_ClauseVecReadEntry( p->vLearned, Num - nClausesP );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads the clause with the given number.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_ClauseVec_t * Msat_SolverReadAdjacents( Msat_Solver_t * p )
+{
+ return p->vAdjacents;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads the clause with the given number.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_IntVec_t * Msat_SolverReadConeVars( Msat_Solver_t * p )
+{
+ return p->vConeVars;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads the clause with the given number.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_IntVec_t * Msat_SolverReadVarsUsed( Msat_Solver_t * p )
+{
+ return p->vVarsUsed;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Allocates the solver.]
+
+ Description [After the solver is allocated, the procedure
+ Msat_SolverClean() should be called to set the number of variables.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_Solver_t * Msat_SolverAlloc( int nVarsAlloc,
+ double dClaInc, double dClaDecay,
+ double dVarInc, double dVarDecay,
+ bool fVerbose )
+{
+ Msat_Solver_t * p;
+ int i;
+
+ assert(sizeof(Msat_Lit_t) == sizeof(unsigned));
+ assert(sizeof(float) == sizeof(unsigned));
+
+ p = ALLOC( Msat_Solver_t, 1 );
+ memset( p, 0, sizeof(Msat_Solver_t) );
+
+ p->nVarsAlloc = nVarsAlloc;
+ p->nVars = 0;
+
+ p->nClauses = 0;
+ p->vClauses = Msat_ClauseVecAlloc( 512 );
+ p->vLearned = Msat_ClauseVecAlloc( 512 );
+
+ p->dClaInc = dClaInc;
+ p->dClaDecay = dClaDecay;
+ p->dVarInc = dVarInc;
+ p->dVarDecay = dVarDecay;
+
+ p->pdActivity = ALLOC( double, p->nVarsAlloc );
+ for ( i = 0; i < p->nVarsAlloc; i++ )
+ p->pdActivity[i] = 0;
+
+ p->pAssigns = ALLOC( int, p->nVarsAlloc );
+ p->pModel = ALLOC( int, p->nVarsAlloc );
+ for ( i = 0; i < p->nVarsAlloc; i++ )
+ p->pAssigns[i] = MSAT_VAR_UNASSIGNED;
+// p->pOrder = Msat_OrderAlloc( p->pAssigns, p->pdActivity, p->nVarsAlloc );
+ p->pOrder = Msat_OrderAlloc( p );
+
+ p->pvWatched = ALLOC( Msat_ClauseVec_t *, 2 * p->nVarsAlloc );
+ for ( i = 0; i < 2 * p->nVarsAlloc; i++ )
+ p->pvWatched[i] = Msat_ClauseVecAlloc( 16 );
+ p->pQueue = Msat_QueueAlloc( p->nVarsAlloc );
+
+ p->vTrail = Msat_IntVecAlloc( p->nVarsAlloc );
+ p->vTrailLim = Msat_IntVecAlloc( p->nVarsAlloc );
+ p->pReasons = ALLOC( Msat_Clause_t *, p->nVarsAlloc );
+ memset( p->pReasons, 0, sizeof(Msat_Clause_t *) * p->nVarsAlloc );
+ p->pLevel = ALLOC( int, p->nVarsAlloc );
+ for ( i = 0; i < p->nVarsAlloc; i++ )
+ p->pLevel[i] = -1;
+ p->dRandSeed = 91648253;
+ p->fVerbose = fVerbose;
+ p->dProgress = 0.0;
+// p->pModel = Msat_IntVecAlloc( p->nVarsAlloc );
+ p->pMem = Msat_MmStepStart( 10 );
+
+ p->vConeVars = Msat_IntVecAlloc( p->nVarsAlloc );
+ p->vAdjacents = Msat_ClauseVecAlloc( p->nVarsAlloc );
+ for ( i = 0; i < p->nVarsAlloc; i++ )
+ Msat_ClauseVecPush( p->vAdjacents, (Msat_Clause_t *)Msat_IntVecAlloc(5) );
+ p->vVarsUsed = Msat_IntVecAlloc( p->nVarsAlloc );
+ Msat_IntVecFill( p->vVarsUsed, p->nVarsAlloc, 1 );
+
+
+ p->pSeen = ALLOC( int, p->nVarsAlloc );
+ memset( p->pSeen, 0, sizeof(int) * p->nVarsAlloc );
+ p->nSeenId = 1;
+ p->vReason = Msat_IntVecAlloc( p->nVarsAlloc );
+ p->vTemp = Msat_IntVecAlloc( p->nVarsAlloc );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Resizes the solver.]
+
+ Description [Assumes that the solver contains some clauses, and that
+ it is currently between the calls. Resizes the solver to accomodate
+ more variables.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverResize( Msat_Solver_t * p, int nVarsAlloc )
+{
+ int nVarsAllocOld, i;
+
+ nVarsAllocOld = p->nVarsAlloc;
+ p->nVarsAlloc = nVarsAlloc;
+
+ p->pdActivity = REALLOC( double, p->pdActivity, p->nVarsAlloc );
+ for ( i = nVarsAllocOld; i < p->nVarsAlloc; i++ )
+ p->pdActivity[i] = 0;
+
+ p->pAssigns = REALLOC( int, p->pAssigns, p->nVarsAlloc );
+ p->pModel = REALLOC( int, p->pModel, p->nVarsAlloc );
+ for ( i = nVarsAllocOld; i < p->nVarsAlloc; i++ )
+ p->pAssigns[i] = MSAT_VAR_UNASSIGNED;
+
+// Msat_OrderRealloc( p->pOrder, p->pAssigns, p->pdActivity, p->nVarsAlloc );
+ Msat_OrderSetBounds( p->pOrder, p->nVarsAlloc );
+
+ p->pvWatched = REALLOC( Msat_ClauseVec_t *, p->pvWatched, 2 * p->nVarsAlloc );
+ for ( i = 2 * nVarsAllocOld; i < 2 * p->nVarsAlloc; i++ )
+ p->pvWatched[i] = Msat_ClauseVecAlloc( 16 );
+
+ Msat_QueueFree( p->pQueue );
+ p->pQueue = Msat_QueueAlloc( p->nVarsAlloc );
+
+ p->pReasons = REALLOC( Msat_Clause_t *, p->pReasons, p->nVarsAlloc );
+ p->pLevel = REALLOC( int, p->pLevel, p->nVarsAlloc );
+ for ( i = nVarsAllocOld; i < p->nVarsAlloc; i++ )
+ {
+ p->pReasons[i] = NULL;
+ p->pLevel[i] = -1;
+ }
+
+ p->pSeen = REALLOC( int, p->pSeen, p->nVarsAlloc );
+ for ( i = nVarsAllocOld; i < p->nVarsAlloc; i++ )
+ p->pSeen[i] = 0;
+
+ Msat_IntVecGrow( p->vTrail, p->nVarsAlloc );
+ Msat_IntVecGrow( p->vTrailLim, p->nVarsAlloc );
+
+ // make sure the array of adjucents has room to store the variable numbers
+ for ( i = Msat_ClauseVecReadSize(p->vAdjacents); i < p->nVarsAlloc; i++ )
+ Msat_ClauseVecPush( p->vAdjacents, (Msat_Clause_t *)Msat_IntVecAlloc(5) );
+ Msat_IntVecFill( p->vVarsUsed, p->nVarsAlloc, 1 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prepares the solver.]
+
+ Description [Cleans the solver assuming that the problem will involve
+ the given number of variables (nVars). This procedure is useful
+ for many small (incremental) SAT problems, to prevent the solver
+ from being reallocated each time.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverClean( Msat_Solver_t * p, int nVars )
+{
+ int i;
+ // free the clauses
+ int nClauses;
+ Msat_Clause_t ** pClauses;
+
+ assert( p->nVarsAlloc >= nVars );
+ p->nVars = nVars;
+ p->nClauses = 0;
+
+ nClauses = Msat_ClauseVecReadSize( p->vClauses );
+ pClauses = Msat_ClauseVecReadArray( p->vClauses );
+ for ( i = 0; i < nClauses; i++ )
+ Msat_ClauseFree( p, pClauses[i], 0 );
+// Msat_ClauseVecFree( p->vClauses );
+ Msat_ClauseVecClear( p->vClauses );
+
+ nClauses = Msat_ClauseVecReadSize( p->vLearned );
+ pClauses = Msat_ClauseVecReadArray( p->vLearned );
+ for ( i = 0; i < nClauses; i++ )
+ Msat_ClauseFree( p, pClauses[i], 0 );
+// Msat_ClauseVecFree( p->vLearned );
+ Msat_ClauseVecClear( p->vLearned );
+
+// FREE( p->pdActivity );
+ for ( i = 0; i < p->nVars; i++ )
+ p->pdActivity[i] = 0;
+
+// Msat_OrderFree( p->pOrder );
+// Msat_OrderClean( p->pOrder, p->nVars, NULL );
+ Msat_OrderSetBounds( p->pOrder, p->nVars );
+
+ for ( i = 0; i < 2 * p->nVars; i++ )
+// Msat_ClauseVecFree( p->pvWatched[i] );
+ Msat_ClauseVecClear( p->pvWatched[i] );
+// FREE( p->pvWatched );
+// Msat_QueueFree( p->pQueue );
+ Msat_QueueClear( p->pQueue );
+
+// FREE( p->pAssigns );
+ for ( i = 0; i < p->nVars; i++ )
+ p->pAssigns[i] = MSAT_VAR_UNASSIGNED;
+// Msat_IntVecFree( p->vTrail );
+ Msat_IntVecClear( p->vTrail );
+// Msat_IntVecFree( p->vTrailLim );
+ Msat_IntVecClear( p->vTrailLim );
+// FREE( p->pReasons );
+ memset( p->pReasons, 0, sizeof(Msat_Clause_t *) * p->nVars );
+// FREE( p->pLevel );
+ for ( i = 0; i < p->nVars; i++ )
+ p->pLevel[i] = -1;
+// Msat_IntVecFree( p->pModel );
+// Msat_MmStepStop( p->pMem, 0 );
+ p->dRandSeed = 91648253;
+ p->dProgress = 0.0;
+
+// FREE( p->pSeen );
+ memset( p->pSeen, 0, sizeof(int) * p->nVars );
+ p->nSeenId = 1;
+// Msat_IntVecFree( p->vReason );
+ Msat_IntVecClear( p->vReason );
+// Msat_IntVecFree( p->vTemp );
+ Msat_IntVecClear( p->vTemp );
+// printf(" The number of clauses remaining = %d (%d).\n", p->nClausesAlloc, p->nClausesAllocL );
+// FREE( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Frees the solver.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverFree( Msat_Solver_t * p )
+{
+ int i;
+
+ // free the clauses
+ int nClauses;
+ Msat_Clause_t ** pClauses;
+//printf( "clauses = %d. learned = %d.\n", Msat_ClauseVecReadSize( p->vClauses ),
+// Msat_ClauseVecReadSize( p->vLearned ) );
+
+ nClauses = Msat_ClauseVecReadSize( p->vClauses );
+ pClauses = Msat_ClauseVecReadArray( p->vClauses );
+ for ( i = 0; i < nClauses; i++ )
+ Msat_ClauseFree( p, pClauses[i], 0 );
+ Msat_ClauseVecFree( p->vClauses );
+
+ nClauses = Msat_ClauseVecReadSize( p->vLearned );
+ pClauses = Msat_ClauseVecReadArray( p->vLearned );
+ for ( i = 0; i < nClauses; i++ )
+ Msat_ClauseFree( p, pClauses[i], 0 );
+ Msat_ClauseVecFree( p->vLearned );
+
+ FREE( p->pdActivity );
+ Msat_OrderFree( p->pOrder );
+
+ for ( i = 0; i < 2 * p->nVarsAlloc; i++ )
+ Msat_ClauseVecFree( p->pvWatched[i] );
+ FREE( p->pvWatched );
+ Msat_QueueFree( p->pQueue );
+
+ FREE( p->pAssigns );
+ FREE( p->pModel );
+ Msat_IntVecFree( p->vTrail );
+ Msat_IntVecFree( p->vTrailLim );
+ FREE( p->pReasons );
+ FREE( p->pLevel );
+
+ Msat_MmStepStop( p->pMem, 0 );
+
+ nClauses = Msat_ClauseVecReadSize( p->vAdjacents );
+ pClauses = Msat_ClauseVecReadArray( p->vAdjacents );
+ for ( i = 0; i < nClauses; i++ )
+ Msat_IntVecFree( (Msat_IntVec_t *)pClauses[i] );
+ Msat_ClauseVecFree( p->vAdjacents );
+ Msat_IntVecFree( p->vConeVars );
+ Msat_IntVecFree( p->vVarsUsed );
+
+ FREE( p->pSeen );
+ Msat_IntVecFree( p->vReason );
+ Msat_IntVecFree( p->vTemp );
+ FREE( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prepares the solver to run on a subset of variables.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverPrepare( Msat_Solver_t * p, Msat_IntVec_t * vVars )
+{
+
+ int i;
+ // undo the previous data
+ for ( i = 0; i < p->nVarsAlloc; i++ )
+ {
+ p->pAssigns[i] = MSAT_VAR_UNASSIGNED;
+ p->pReasons[i] = NULL;
+ p->pLevel[i] = -1;
+ p->pdActivity[i] = 0.0;
+ }
+
+ // set the new variable order
+ Msat_OrderClean( p->pOrder, vVars );
+
+ Msat_QueueClear( p->pQueue );
+ Msat_IntVecClear( p->vTrail );
+ Msat_IntVecClear( p->vTrailLim );
+ p->dProgress = 0.0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets up the truth tables.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverSetupTruthTables( unsigned uTruths[][2] )
+{
+ int m, v;
+ // set up the truth tables
+ for ( m = 0; m < 32; m++ )
+ for ( v = 0; v < 5; v++ )
+ if ( m & (1 << v) )
+ uTruths[v][0] |= (1 << m);
+ // make adjustments for the case of 6 variables
+ for ( v = 0; v < 5; v++ )
+ uTruths[v][1] = uTruths[v][0];
+ uTruths[5][0] = 0;
+ uTruths[5][1] = ~((unsigned)0);
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sat/msat/msatSolverCore.c b/src/sat/msat/msatSolverCore.c
new file mode 100644
index 00000000..b8d9f328
--- /dev/null
+++ b/src/sat/msat/msatSolverCore.c
@@ -0,0 +1,187 @@
+/**CFile****************************************************************
+
+ FileName [msatSolverCore.c]
+
+ PackageName [A C version of SAT solver MINISAT, originally developed
+ in C++ by Niklas Een and Niklas Sorensson, Chalmers University of
+ Technology, Sweden: http://www.cs.chalmers.se/~een/Satzoo.]
+
+ Synopsis [The SAT solver core procedures.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - January 1, 2004.]
+
+ Revision [$Id: msatSolverCore.c,v 1.2 2004/05/12 03:37:40 satrajit Exp $]
+
+***********************************************************************/
+
+#include "msatInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Adds one variable to the solver.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Msat_SolverAddVar( Msat_Solver_t * p )
+{
+ if ( p->nVars == p->nVarsAlloc )
+ Msat_SolverResize( p, 2 * p->nVarsAlloc );
+ p->nVars++;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Adds one clause to the solver's clause database.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Msat_SolverAddClause( Msat_Solver_t * p, Msat_IntVec_t * vLits )
+{
+ Msat_Clause_t * pC;
+ bool Value;
+ Value = Msat_ClauseCreate( p, vLits, 0, &pC );
+ if ( pC != NULL )
+ Msat_ClauseVecPush( p->vClauses, pC );
+// else if ( p->fProof )
+// Msat_ClauseCreateFake( p, vLits );
+ return Value;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns search-space coverage. Not extremely reliable.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+double Msat_SolverProgressEstimate( Msat_Solver_t * p )
+{
+ double dProgress = 0.0;
+ double dF = 1.0 / p->nVars;
+ int i;
+ for ( i = 0; i < p->nVars; i++ )
+ if ( p->pAssigns[i] != MSAT_VAR_UNASSIGNED )
+ dProgress += pow( dF, p->pLevel[i] );
+ return dProgress / p->nVars;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints statistics about the solver.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverPrintStats( Msat_Solver_t * p )
+{
+ printf("C solver (%d vars; %d clauses; %d learned):\n",
+ p->nVars, Msat_ClauseVecReadSize(p->vClauses), Msat_ClauseVecReadSize(p->vLearned) );
+ printf("starts : %lld\n", p->Stats.nStarts);
+ printf("conflicts : %lld\n", p->Stats.nConflicts);
+ printf("decisions : %lld\n", p->Stats.nDecisions);
+ printf("propagations : %lld\n", p->Stats.nPropagations);
+ printf("inspects : %lld\n", p->Stats.nInspects);
+}
+
+/**Function*************************************************************
+
+ Synopsis [Top-level solve.]
+
+ Description [If using assumptions (non-empty 'assumps' vector), you must
+ call 'simplifyDB()' first to see that no top-level conflict is present
+ (which would put the solver in an undefined state. If the last argument
+ is given (vProj), the solver enumerates through the satisfying solutions,
+ which are projected on the variables listed in this array. Note that the
+ variables in the array may be complemented, in which case the derived
+ assignment for the variable is complemented.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Msat_SolverSolve( Msat_Solver_t * p, Msat_IntVec_t * vAssumps, int nBackTrackLimit )
+{
+ Msat_SearchParams_t Params = { 0.95, 0.999 };
+ double nConflictsLimit, nLearnedLimit;
+ Msat_Type_t Status;
+ int64 nConflictsOld = p->Stats.nConflicts;
+ int64 nDecisionsOld = p->Stats.nDecisions;
+
+ if ( vAssumps )
+ {
+ int * pAssumps, nAssumps, i;
+
+ assert( Msat_IntVecReadSize(p->vTrailLim) == 0 );
+
+ nAssumps = Msat_IntVecReadSize( vAssumps );
+ pAssumps = Msat_IntVecReadArray( vAssumps );
+ for ( i = 0; i < nAssumps; i++ )
+ {
+ if ( !Msat_SolverAssume(p, pAssumps[i]) || Msat_SolverPropagate(p) )
+ {
+ Msat_QueueClear( p->pQueue );
+ Msat_SolverCancelUntil( p, 0 );
+ return MSAT_FALSE;
+ }
+ }
+ }
+ p->nLevelRoot = Msat_SolverReadDecisionLevel(p);
+ p->nClausesInit = Msat_ClauseVecReadSize( p->vClauses );
+ nConflictsLimit = 100;
+ nLearnedLimit = Msat_ClauseVecReadSize(p->vClauses) / 3;
+ Status = MSAT_UNKNOWN;
+ p->nBackTracks = (int)p->Stats.nConflicts;
+ while ( Status == MSAT_UNKNOWN )
+ {
+ if ( p->fVerbose )
+ printf("Solving -- conflicts=%d learnts=%d progress=%.4f %%\n",
+ (int)nConflictsLimit, (int)nLearnedLimit, p->dProgress*100);
+ Status = Msat_SolverSearch( p, (int)nConflictsLimit, (int)nLearnedLimit, nBackTrackLimit, &Params );
+ nConflictsLimit *= 1.5;
+ nLearnedLimit *= 1.1;
+ // if the limit on the number of backtracks is given, quit the restart loop
+ if ( nBackTrackLimit > 0 )
+ break;
+ }
+ Msat_SolverCancelUntil( p, 0 );
+ p->nBackTracks = (int)p->Stats.nConflicts - p->nBackTracks;
+ return Status;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sat/msat/msatSolverIo.c b/src/sat/msat/msatSolverIo.c
new file mode 100644
index 00000000..f17595a7
--- /dev/null
+++ b/src/sat/msat/msatSolverIo.c
@@ -0,0 +1,177 @@
+/**CFile****************************************************************
+
+ FileName [msatSolverIo.c]
+
+ PackageName [A C version of SAT solver MINISAT, originally developed
+ in C++ by Niklas Een and Niklas Sorensson, Chalmers University of
+ Technology, Sweden: http://www.cs.chalmers.se/~een/Satzoo.]
+
+ Synopsis [Input/output of CNFs.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - January 1, 2004.]
+
+ Revision [$Id: msatSolverIo.c,v 1.0 2004/01/01 1:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "msatInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static char * Msat_TimeStamp();
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverPrintAssignment( Msat_Solver_t * p )
+{
+ int i;
+ printf( "Current assignments are: \n" );
+ for ( i = 0; i < p->nVars; i++ )
+ printf( "%d", i % 10 );
+ printf( "\n" );
+ for ( i = 0; i < p->nVars; i++ )
+ if ( p->pAssigns[i] == MSAT_VAR_UNASSIGNED )
+ printf( "." );
+ else
+ {
+ assert( i == MSAT_LIT2VAR(p->pAssigns[i]) );
+ if ( MSAT_LITSIGN(p->pAssigns[i]) )
+ printf( "0" );
+ else
+ printf( "1" );
+ }
+ printf( "\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverPrintClauses( Msat_Solver_t * p )
+{
+ Msat_Clause_t ** pClauses;
+ int nClauses, i;
+
+ printf( "Original clauses: \n" );
+ nClauses = Msat_ClauseVecReadSize( p->vClauses );
+ pClauses = Msat_ClauseVecReadArray( p->vClauses );
+ for ( i = 0; i < nClauses; i++ )
+ {
+ printf( "%3d: ", i );
+ Msat_ClausePrint( pClauses[i] );
+ }
+
+ printf( "Learned clauses: \n" );
+ nClauses = Msat_ClauseVecReadSize( p->vLearned );
+ pClauses = Msat_ClauseVecReadArray( p->vLearned );
+ for ( i = 0; i < nClauses; i++ )
+ {
+ printf( "%3d: ", i );
+ Msat_ClausePrint( pClauses[i] );
+ }
+
+ printf( "Variable activity: \n" );
+ for ( i = 0; i < p->nVars; i++ )
+ printf( "%3d : %.4f\n", i, p->pdActivity[i] );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverWriteDimacs( Msat_Solver_t * p, char * pFileName )
+{
+ FILE * pFile;
+ Msat_Clause_t ** pClauses;
+ int nClauses, i;
+
+ nClauses = Msat_ClauseVecReadSize(p->vClauses) + Msat_ClauseVecReadSize(p->vLearned);
+ for ( i = 0; i < p->nVars; i++ )
+ nClauses += ( p->pLevel[i] == 0 );
+
+ pFile = fopen( pFileName, "wb" );
+ fprintf( pFile, "c Produced by Msat_SolverWriteDimacs() on %s\n", Msat_TimeStamp() );
+ fprintf( pFile, "p cnf %d %d\n", p->nVars, nClauses );
+
+ nClauses = Msat_ClauseVecReadSize( p->vClauses );
+ pClauses = Msat_ClauseVecReadArray( p->vClauses );
+ for ( i = 0; i < nClauses; i++ )
+ Msat_ClauseWriteDimacs( pFile, pClauses[i], 1 );
+
+ nClauses = Msat_ClauseVecReadSize( p->vLearned );
+ pClauses = Msat_ClauseVecReadArray( p->vLearned );
+ for ( i = 0; i < nClauses; i++ )
+ Msat_ClauseWriteDimacs( pFile, pClauses[i], 1 );
+
+ // write zero-level assertions
+ for ( i = 0; i < p->nVars; i++ )
+ if ( p->pLevel[i] == 0 )
+ fprintf( pFile, "%s%d 0\n", ((p->pAssigns[i]&1)? "-": ""), i + 1 );
+
+ fprintf( pFile, "\n" );
+ fclose( pFile );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Returns the time stamp.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+char * Msat_TimeStamp()
+{
+ static char Buffer[100];
+ time_t ltime;
+ char * TimeStamp;
+ // get the current time
+ time( &ltime );
+ TimeStamp = asctime( localtime( &ltime ) );
+ TimeStamp[ strlen(TimeStamp) - 1 ] = 0;
+ strcpy( Buffer, TimeStamp );
+ return Buffer;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sat/msat/msatSolverSearch.c b/src/sat/msat/msatSolverSearch.c
new file mode 100644
index 00000000..13a0c403
--- /dev/null
+++ b/src/sat/msat/msatSolverSearch.c
@@ -0,0 +1,623 @@
+/**CFile****************************************************************
+
+ FileName [msatSolverSearch.c]
+
+ PackageName [A C version of SAT solver MINISAT, originally developed
+ in C++ by Niklas Een and Niklas Sorensson, Chalmers University of
+ Technology, Sweden: http://www.cs.chalmers.se/~een/Satzoo.]
+
+ Synopsis [The search part of the solver.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - January 1, 2004.]
+
+ Revision [$Id: msatSolverSearch.c,v 1.0 2004/01/01 1:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "msatInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Msat_SolverUndoOne( Msat_Solver_t * p );
+static void Msat_SolverCancel( Msat_Solver_t * p );
+static Msat_Clause_t * Msat_SolverRecord( Msat_Solver_t * p, Msat_IntVec_t * vLits );
+static void Msat_SolverAnalyze( Msat_Solver_t * p, Msat_Clause_t * pC, Msat_IntVec_t * vLits_out, int * pLevel_out );
+static void Msat_SolverReduceDB( Msat_Solver_t * p );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Makes the next assumption (Lit).]
+
+ Description [Returns FALSE if immediate conflict.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Msat_SolverAssume( Msat_Solver_t * p, Msat_Lit_t Lit )
+{
+ assert( Msat_QueueReadSize(p->pQueue) == 0 );
+ if ( p->fVerbose )
+ printf(L_IND"assume("L_LIT")\n", L_ind, L_lit(Lit));
+ Msat_IntVecPush( p->vTrailLim, Msat_IntVecReadSize(p->vTrail) );
+// assert( Msat_IntVecReadSize(p->vTrailLim) <= Msat_IntVecReadSize(p->vTrail) + 1 );
+// assert( Msat_IntVecReadSize( p->vTrailLim ) < p->nVars );
+ return Msat_SolverEnqueue( p, Lit, NULL );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reverts one variable binding on the trail.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverUndoOne( Msat_Solver_t * p )
+{
+ Msat_Lit_t Lit;
+ Msat_Var_t Var;
+ Lit = Msat_IntVecPop( p->vTrail );
+ Var = MSAT_LIT2VAR(Lit);
+ p->pAssigns[Var] = MSAT_VAR_UNASSIGNED;
+ p->pReasons[Var] = NULL;
+ p->pLevel[Var] = -1;
+// Msat_OrderUndo( p->pOrder, Var );
+ Msat_OrderVarUnassigned( p->pOrder, Var );
+
+ if ( p->fVerbose )
+ printf(L_IND"unbind("L_LIT")\n", L_ind, L_lit(Lit));
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reverts to the state before last Msat_SolverAssume().]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverCancel( Msat_Solver_t * p )
+{
+ int c;
+ assert( Msat_QueueReadSize(p->pQueue) == 0 );
+ if ( p->fVerbose )
+ {
+ if ( Msat_IntVecReadSize(p->vTrail) != Msat_IntVecReadEntryLast(p->vTrailLim) )
+ {
+ Msat_Lit_t Lit;
+ Lit = Msat_IntVecReadEntry( p->vTrail, Msat_IntVecReadEntryLast(p->vTrailLim) );
+ printf(L_IND"cancel("L_LIT")\n", L_ind, L_lit(Lit));
+ }
+ }
+ for ( c = Msat_IntVecReadSize(p->vTrail) - Msat_IntVecPop( p->vTrailLim ); c != 0; c-- )
+ Msat_SolverUndoOne( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reverts to the state at given level.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverCancelUntil( Msat_Solver_t * p, int Level )
+{
+ while ( Msat_IntVecReadSize(p->vTrailLim) > Level )
+ Msat_SolverCancel(p);
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Record a clause and drive backtracking.]
+
+ Description [vLits[0] must contain the asserting literal.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_Clause_t * Msat_SolverRecord( Msat_Solver_t * p, Msat_IntVec_t * vLits )
+{
+ Msat_Clause_t * pC;
+ int Value;
+ assert( Msat_IntVecReadSize(vLits) != 0 );
+ Value = Msat_ClauseCreate( p, vLits, 1, &pC );
+ assert( Value );
+ Value = Msat_SolverEnqueue( p, Msat_IntVecReadEntry(vLits,0), pC );
+ assert( Value );
+ if ( pC )
+ Msat_ClauseVecPush( p->vLearned, pC );
+ return pC;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Enqueues one variable assignment.]
+
+ Description [Puts a new fact on the propagation queue and immediately
+ updates the variable value. Should a conflict arise, FALSE is returned.
+ Otherwise returns TRUE.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Msat_SolverEnqueue( Msat_Solver_t * p, Msat_Lit_t Lit, Msat_Clause_t * pC )
+{
+ Msat_Var_t Var = MSAT_LIT2VAR(Lit);
+
+ // skip literals that are not in the current cone
+ if ( !Msat_IntVecReadEntry( p->vVarsUsed, Var ) )
+ return 1;
+
+// assert( Msat_QueueReadSize(p->pQueue) == Msat_IntVecReadSize(p->vTrail) );
+ // if the literal is assigned
+ // return 1 if the assignment is consistent
+ // return 0 if the assignment is inconsistent (conflict)
+ if ( p->pAssigns[Var] != MSAT_VAR_UNASSIGNED )
+ return p->pAssigns[Var] == Lit;
+ // new fact - store it
+ if ( p->fVerbose )
+ {
+// printf(L_IND"bind("L_LIT")\n", L_ind, L_lit(Lit));
+ printf(L_IND"bind("L_LIT") ", L_ind, L_lit(Lit));
+ Msat_ClausePrintSymbols( pC );
+ }
+ p->pAssigns[Var] = Lit;
+ p->pLevel[Var] = Msat_IntVecReadSize(p->vTrailLim);
+// p->pReasons[Var] = p->pLevel[Var]? pC: NULL;
+ p->pReasons[Var] = pC;
+ Msat_IntVecPush( p->vTrail, Lit );
+ Msat_QueueInsert( p->pQueue, Lit );
+
+ Msat_OrderVarAssigned( p->pOrder, Var );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Propagates the assignments in the queue.]
+
+ Description [Propagates all enqueued facts. If a conflict arises,
+ the conflicting clause is returned, otherwise NULL.]
+
+ SideEffects [The propagation queue is empty, even if there was a conflict.]
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_Clause_t * Msat_SolverPropagate( Msat_Solver_t * p )
+{
+ Msat_ClauseVec_t ** pvWatched = p->pvWatched;
+ Msat_Clause_t ** pClauses;
+ Msat_Clause_t * pConflict;
+ Msat_Lit_t Lit, Lit_out;
+ int i, j, nClauses;
+
+ // propagate all the literals in the queue
+ while ( (Lit = Msat_QueueExtract( p->pQueue )) >= 0 )
+ {
+ p->Stats.nPropagations++;
+ // get the clauses watched by this literal
+ nClauses = Msat_ClauseVecReadSize( pvWatched[Lit] );
+ pClauses = Msat_ClauseVecReadArray( pvWatched[Lit] );
+ // go through the watched clauses and decide what to do with them
+ for ( i = j = 0; i < nClauses; i++ )
+ {
+ p->Stats.nInspects++;
+ // clear the returned literal
+ Lit_out = -1;
+ // propagate the clause
+ if ( !Msat_ClausePropagate( pClauses[i], Lit, p->pAssigns, &Lit_out ) )
+ { // the clause is unit
+ // "Lit_out" contains the new assignment to be enqueued
+ if ( Msat_SolverEnqueue( p, Lit_out, pClauses[i] ) )
+ { // consistent assignment
+ // no changes to the implication queue; the watch is the same too
+ pClauses[j++] = pClauses[i];
+ continue;
+ }
+ // remember the reason of conflict (will be returned)
+ pConflict = pClauses[i];
+ // leave the remaning clauses in the same watched list
+ for ( ; i < nClauses; i++ )
+ pClauses[j++] = pClauses[i];
+ Msat_ClauseVecShrink( pvWatched[Lit], j );
+ // clear the propagation queue
+ Msat_QueueClear( p->pQueue );
+ return pConflict;
+ }
+ // the clause is not unit
+ // in this case "Lit_out" contains the new watch if it has changed
+ if ( Lit_out >= 0 )
+ Msat_ClauseVecPush( pvWatched[Lit_out], pClauses[i] );
+ else // the watch did not change
+ pClauses[j++] = pClauses[i];
+ }
+ Msat_ClauseVecShrink( pvWatched[Lit], j );
+ }
+ return NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Simplifies the data base.]
+
+ Description [Simplify all constraints according to the current top-level
+ assigment (redundant constraints may be removed altogether).]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Msat_SolverSimplifyDB( Msat_Solver_t * p )
+{
+ Msat_ClauseVec_t * vClauses;
+ Msat_Clause_t ** pClauses;
+ int nClauses, Type, i, j;
+ int * pAssigns;
+ int Counter;
+
+ assert( Msat_SolverReadDecisionLevel(p) == 0 );
+ if ( Msat_SolverPropagate(p) != NULL )
+ return 0;
+//Msat_SolverPrintClauses( p );
+//Msat_SolverPrintAssignment( p );
+//printf( "Simplification\n" );
+
+ // simplify and reassign clause numbers
+ Counter = 0;
+ pAssigns = Msat_SolverReadAssignsArray( p );
+ for ( Type = 0; Type < 2; Type++ )
+ {
+ vClauses = Type? p->vLearned : p->vClauses;
+ nClauses = Msat_ClauseVecReadSize( vClauses );
+ pClauses = Msat_ClauseVecReadArray( vClauses );
+ for ( i = j = 0; i < nClauses; i++ )
+ if ( Msat_ClauseSimplify( pClauses[i], pAssigns ) )
+ Msat_ClauseFree( p, pClauses[i], 1 );
+ else
+ {
+ pClauses[j++] = pClauses[i];
+ Msat_ClauseSetNum( pClauses[i], Counter++ );
+ }
+ Msat_ClauseVecShrink( vClauses, j );
+ }
+ p->nClauses = Counter;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Cleans the clause databased from the useless learnt clauses.]
+
+ Description [Removes half of the learnt clauses, minus the clauses locked
+ by the current assignment. Locked clauses are clauses that are reason
+ to a some assignment.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverReduceDB( Msat_Solver_t * p )
+{
+ Msat_Clause_t ** pLearned;
+ int nLearned, i, j;
+ double dExtraLim = p->dClaInc / Msat_ClauseVecReadSize(p->vLearned);
+ // Remove any clause below this activity
+
+ // sort the learned clauses in the increasing order of activity
+ Msat_SolverSortDB( p );
+
+ // discard the first half the clauses (the less active ones)
+ nLearned = Msat_ClauseVecReadSize( p->vLearned );
+ pLearned = Msat_ClauseVecReadArray( p->vLearned );
+ for ( i = j = 0; i < nLearned / 2; i++ )
+ if ( !Msat_ClauseIsLocked( p, pLearned[i]) )
+ Msat_ClauseFree( p, pLearned[i], 1 );
+ else
+ pLearned[j++] = pLearned[i];
+ // filter the more active clauses and leave those above the limit
+ for ( ; i < nLearned; i++ )
+ if ( !Msat_ClauseIsLocked( p, pLearned[i] ) &&
+ Msat_ClauseReadActivity(pLearned[i]) < dExtraLim )
+ Msat_ClauseFree( p, pLearned[i], 1 );
+ else
+ pLearned[j++] = pLearned[i];
+ Msat_ClauseVecShrink( p->vLearned, j );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Removes the learned clauses.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverRemoveLearned( Msat_Solver_t * p )
+{
+ Msat_Clause_t ** pLearned;
+ int nLearned, i;
+
+ // discard the learned clauses
+ nLearned = Msat_ClauseVecReadSize( p->vLearned );
+ pLearned = Msat_ClauseVecReadArray( p->vLearned );
+ for ( i = 0; i < nLearned; i++ )
+ {
+ assert( !Msat_ClauseIsLocked( p, pLearned[i]) );
+
+ Msat_ClauseFree( p, pLearned[i], 1 );
+ }
+ Msat_ClauseVecShrink( p->vLearned, 0 );
+ p->nClauses = Msat_ClauseVecReadSize(p->vClauses);
+
+ for ( i = 0; i < p->nVarsAlloc; i++ )
+ p->pReasons[i] = NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Removes the recently added clauses.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverRemoveMarked( Msat_Solver_t * p )
+{
+ Msat_Clause_t ** pLearned, ** pClauses;
+ int nLearned, nClauses, i;
+
+ // discard the learned clauses
+ nClauses = Msat_ClauseVecReadSize( p->vClauses );
+ pClauses = Msat_ClauseVecReadArray( p->vClauses );
+ for ( i = p->nClausesStart; i < nClauses; i++ )
+ {
+// assert( !Msat_ClauseIsLocked( p, pClauses[i]) );
+ Msat_ClauseFree( p, pClauses[i], 1 );
+ }
+ Msat_ClauseVecShrink( p->vClauses, p->nClausesStart );
+
+ // discard the learned clauses
+ nLearned = Msat_ClauseVecReadSize( p->vLearned );
+ pLearned = Msat_ClauseVecReadArray( p->vLearned );
+ for ( i = 0; i < nLearned; i++ )
+ {
+// assert( !Msat_ClauseIsLocked( p, pLearned[i]) );
+ Msat_ClauseFree( p, pLearned[i], 1 );
+ }
+ Msat_ClauseVecShrink( p->vLearned, 0 );
+ p->nClauses = Msat_ClauseVecReadSize(p->vClauses);
+/*
+ // undo the previous data
+ for ( i = 0; i < p->nVarsAlloc; i++ )
+ {
+ p->pAssigns[i] = MSAT_VAR_UNASSIGNED;
+ p->pReasons[i] = NULL;
+ p->pLevel[i] = -1;
+ p->pdActivity[i] = 0.0;
+ }
+ Msat_OrderClean( p->pOrder, p->nVars, NULL );
+ Msat_QueueClear( p->pQueue );
+*/
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Analyze conflict and produce a reason clause.]
+
+ Description [Current decision level must be greater than root level.]
+
+ SideEffects [vLits_out[0] is the asserting literal at level pLevel_out.]
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverAnalyze( Msat_Solver_t * p, Msat_Clause_t * pC, Msat_IntVec_t * vLits_out, int * pLevel_out )
+{
+ Msat_Lit_t LitQ, Lit = MSAT_LIT_UNASSIGNED;
+ Msat_Var_t VarQ, Var;
+ int * pReasonArray, nReasonSize;
+ int j, pathC = 0, nLevelCur = Msat_IntVecReadSize(p->vTrailLim);
+ int iStep = Msat_IntVecReadSize(p->vTrail) - 1;
+
+ // increment the seen counter
+ p->nSeenId++;
+ // empty the vector array
+ Msat_IntVecClear( vLits_out );
+ Msat_IntVecPush( vLits_out, -1 ); // (leave room for the asserting literal)
+ *pLevel_out = 0;
+ do {
+ assert( pC != NULL ); // (otherwise should be UIP)
+ // get the reason of conflict
+ Msat_ClauseCalcReason( p, pC, Lit, p->vReason );
+ nReasonSize = Msat_IntVecReadSize( p->vReason );
+ pReasonArray = Msat_IntVecReadArray( p->vReason );
+ for ( j = 0; j < nReasonSize; j++ ) {
+ LitQ = pReasonArray[j];
+ VarQ = MSAT_LIT2VAR(LitQ);
+ if ( p->pSeen[VarQ] != p->nSeenId ) {
+ p->pSeen[VarQ] = p->nSeenId;
+
+ // added to better fine-tune the search
+ Msat_SolverVarBumpActivity( p, LitQ );
+
+ // skip all the literals on this decision level
+ if ( p->pLevel[VarQ] == nLevelCur )
+ pathC++;
+ else if ( p->pLevel[VarQ] > 0 ) {
+ // add the literals on other decision levels but
+ // exclude variables from decision level 0
+ Msat_IntVecPush( vLits_out, MSAT_LITNOT(LitQ) );
+ if ( *pLevel_out < p->pLevel[VarQ] )
+ *pLevel_out = p->pLevel[VarQ];
+ }
+ }
+ }
+ // Select next clause to look at:
+ do {
+// Lit = Msat_IntVecReadEntryLast(p->vTrail);
+ Lit = Msat_IntVecReadEntry( p->vTrail, iStep-- );
+ Var = MSAT_LIT2VAR(Lit);
+ pC = p->pReasons[Var];
+// Msat_SolverUndoOne( p );
+ } while ( p->pSeen[Var] != p->nSeenId );
+ pathC--;
+ } while ( pathC > 0 );
+ // we do not unbind the variables above
+ // this will be done after conflict analysis
+
+ Msat_IntVecWriteEntry( vLits_out, 0, MSAT_LITNOT(Lit) );
+ if ( p->fVerbose )
+ {
+ printf( L_IND"Learnt {", L_ind );
+ nReasonSize = Msat_IntVecReadSize( vLits_out );
+ pReasonArray = Msat_IntVecReadArray( vLits_out );
+ for ( j = 0; j < nReasonSize; j++ )
+ printf(" "L_LIT, L_lit(pReasonArray[j]));
+ printf(" } at level %d\n", *pLevel_out);
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [The search procedure called between the restarts.]
+
+ Description [Search for a satisfying solution as long as the number of
+ conflicts does not exceed the limit (nConfLimit) while keeping the number
+ of learnt clauses below the provided limit (nLearnedLimit). NOTE! Use
+ negative value for nConfLimit or nLearnedLimit to indicate infinity.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_Type_t Msat_SolverSearch( Msat_Solver_t * p, int nConfLimit, int nLearnedLimit, int nBackTrackLimit, Msat_SearchParams_t * pPars )
+{
+ Msat_Clause_t * pConf;
+ Msat_Var_t Var;
+ int nLevelBack, nConfs, nAssigns, Value;
+
+ assert( Msat_SolverReadDecisionLevel(p) == p->nLevelRoot );
+ p->Stats.nStarts++;
+ p->dVarDecay = 1 / pPars->dVarDecay;
+ p->dClaDecay = 1 / pPars->dClaDecay;
+
+ nConfs = 0;
+ while ( 1 )
+ {
+ pConf = Msat_SolverPropagate( p );
+ if ( pConf != NULL ){
+ // CONFLICT
+ if ( p->fVerbose )
+ {
+// printf(L_IND"**CONFLICT**\n", L_ind);
+ printf(L_IND"**CONFLICT** ", L_ind);
+ Msat_ClausePrintSymbols( pConf );
+ }
+ // count conflicts
+ p->Stats.nConflicts++;
+ nConfs++;
+
+ // if top level, return UNSAT
+ if ( Msat_SolverReadDecisionLevel(p) == p->nLevelRoot )
+ return MSAT_FALSE;
+
+ // perform conflict analysis
+ Msat_SolverAnalyze( p, pConf, p->vTemp, &nLevelBack );
+ Msat_SolverCancelUntil( p, (p->nLevelRoot > nLevelBack)? p->nLevelRoot : nLevelBack );
+ Msat_SolverRecord( p, p->vTemp );
+
+ // it is important that recording is done after cancelling
+ // because canceling cleans the queue while recording adds to it
+ Msat_SolverVarDecayActivity( p );
+ Msat_SolverClaDecayActivity( p );
+
+ }
+ else{
+ // NO CONFLICT
+ if ( Msat_IntVecReadSize(p->vTrailLim) == 0 ) {
+ // Simplify the set of problem clauses:
+// Value = Msat_SolverSimplifyDB(p);
+// assert( Value );
+ }
+ nAssigns = Msat_IntVecReadSize( p->vTrail );
+ if ( nLearnedLimit >= 0 && Msat_ClauseVecReadSize(p->vLearned) >= nLearnedLimit + nAssigns ) {
+ // Reduce the set of learnt clauses:
+ Msat_SolverReduceDB(p);
+ }
+
+ Var = Msat_OrderVarSelect( p->pOrder );
+ if ( Var == MSAT_ORDER_UNKNOWN ) {
+ // Model found and stored in p->pAssigns
+ memcpy( p->pModel, p->pAssigns, sizeof(int) * p->nVars );
+ Msat_QueueClear( p->pQueue );
+ Msat_SolverCancelUntil( p, p->nLevelRoot );
+ return MSAT_TRUE;
+ }
+ if ( nConfLimit > 0 && nConfs > nConfLimit ) {
+ // Reached bound on number of conflicts:
+ p->dProgress = Msat_SolverProgressEstimate( p );
+ Msat_QueueClear( p->pQueue );
+ Msat_SolverCancelUntil( p, p->nLevelRoot );
+ return MSAT_UNKNOWN;
+ }
+ else if ( nBackTrackLimit > 0 && nConfs > nBackTrackLimit ) {
+ // Reached bound on number of conflicts:
+ Msat_QueueClear( p->pQueue );
+ Msat_SolverCancelUntil( p, p->nLevelRoot );
+ return MSAT_UNKNOWN;
+ }
+ else{
+ // New variable decision:
+ p->Stats.nDecisions++;
+ assert( Var != MSAT_ORDER_UNKNOWN && Var >= 0 && Var < p->nVars );
+ Value = Msat_SolverAssume(p, MSAT_VAR2LIT(Var,0) );
+ assert( Value );
+ }
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sat/msat/msatSort.c b/src/sat/msat/msatSort.c
new file mode 100644
index 00000000..2198d303
--- /dev/null
+++ b/src/sat/msat/msatSort.c
@@ -0,0 +1,173 @@
+/**CFile****************************************************************
+
+ FileName [msatSort.c]
+
+ PackageName [A C version of SAT solver MINISAT, originally developed
+ in C++ by Niklas Een and Niklas Sorensson, Chalmers University of
+ Technology, Sweden: http://www.cs.chalmers.se/~een/Satzoo.]
+
+ Synopsis [Sorting clauses.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - January 1, 2004.]
+
+ Revision [$Id: msatSort.c,v 1.0 2004/01/01 1:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "msatInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Msat_SolverSortCompare( Msat_Clause_t ** ppC1, Msat_Clause_t ** ppC2 );
+
+// Returns a random float 0 <= x < 1. Seed must never be 0.
+static double drand(double seed) {
+ int q;
+ seed *= 1389796;
+ q = (int)(seed / 2147483647);
+ seed -= (double)q * 2147483647;
+ return seed / 2147483647; }
+
+// Returns a random integer 0 <= x < size. Seed must never be 0.
+static int irand(double seed, int size) {
+ return (int)(drand(seed) * size); }
+
+static void Msat_SolverSort( Msat_Clause_t ** array, int size, double seed );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Msat_SolverSort the learned clauses in the increasing order of activity.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverSortDB( Msat_Solver_t * p )
+{
+ Msat_ClauseVec_t * pVecClauses;
+ Msat_Clause_t ** pLearned;
+ int nLearned;
+ // read the parameters
+ pVecClauses = Msat_SolverReadLearned( p );
+ nLearned = Msat_ClauseVecReadSize( pVecClauses );
+ pLearned = Msat_ClauseVecReadArray( pVecClauses );
+ // Msat_SolverSort the array
+// qMsat_SolverSort( (void *)pLearned, nLearned, sizeof(Msat_Clause_t *),
+// (int (*)(const void *, const void *)) Msat_SolverSortCompare );
+// printf( "Msat_SolverSorting.\n" );
+ Msat_SolverSort( pLearned, nLearned, 91648253 );
+/*
+ if ( nLearned > 2 )
+ {
+ printf( "Clause 1: %0.20f\n", Msat_ClauseReadActivity(pLearned[0]) );
+ printf( "Clause 2: %0.20f\n", Msat_ClauseReadActivity(pLearned[1]) );
+ printf( "Clause 3: %0.20f\n", Msat_ClauseReadActivity(pLearned[2]) );
+ }
+*/
+}
+
+/**Function*************************************************************
+
+ Synopsis [Comparison procedure for two clauses.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Msat_SolverSortCompare( Msat_Clause_t ** ppC1, Msat_Clause_t ** ppC2 )
+{
+ float Value1 = Msat_ClauseReadActivity( *ppC1 );
+ float Value2 = Msat_ClauseReadActivity( *ppC2 );
+ if ( Value1 < Value2 )
+ return -1;
+ if ( Value1 > Value2 )
+ return 1;
+ return 0;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Selection sort for small array size.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverSortSelection( Msat_Clause_t ** array, int size )
+{
+ Msat_Clause_t * tmp;
+ int i, j, best_i;
+ for ( i = 0; i < size-1; i++ )
+ {
+ best_i = i;
+ for (j = i+1; j < size; j++)
+ {
+ if ( Msat_ClauseReadActivity(array[j]) < Msat_ClauseReadActivity(array[best_i]) )
+ best_i = j;
+ }
+ tmp = array[i]; array[i] = array[best_i]; array[best_i] = tmp;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [The original MiniSat sorting procedure.]
+
+ Description [This procedure is used to preserve trace-equivalence
+ with the orignal C++ implemenation of the solver.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_SolverSort( Msat_Clause_t ** array, int size, double seed )
+{
+ if (size <= 15)
+ Msat_SolverSortSelection( array, size );
+ else
+ {
+ Msat_Clause_t * pivot = array[irand(seed, size)];
+ Msat_Clause_t * tmp;
+ int i = -1;
+ int j = size;
+
+ for(;;)
+ {
+ do i++; while( Msat_ClauseReadActivity(array[i]) < Msat_ClauseReadActivity(pivot) );
+ do j--; while( Msat_ClauseReadActivity(pivot) < Msat_ClauseReadActivity(array[j]) );
+
+ if ( i >= j ) break;
+
+ tmp = array[i]; array[i] = array[j]; array[j] = tmp;
+ }
+ Msat_SolverSort(array , i , seed);
+ Msat_SolverSort(&array[i], size-i, seed);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sat/msat/msatVec.c b/src/sat/msat/msatVec.c
new file mode 100644
index 00000000..951969cf
--- /dev/null
+++ b/src/sat/msat/msatVec.c
@@ -0,0 +1,495 @@
+/**CFile****************************************************************
+
+ FileName [msatVec.c]
+
+ PackageName [A C version of SAT solver MINISAT, originally developed
+ in C++ by Niklas Een and Niklas Sorensson, Chalmers University of
+ Technology, Sweden: http://www.cs.chalmers.se/~een/Satzoo.]
+
+ Synopsis [Integer vector borrowed from Extra.]
+
+ Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - January 1, 2004.]
+
+ Revision [$Id: msatVec.c,v 1.0 2004/01/01 1:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "msatInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Msat_IntVecSortCompare1( int * pp1, int * pp2 );
+static int Msat_IntVecSortCompare2( int * pp1, int * pp2 );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Allocates a vector with the given capacity.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_IntVec_t * Msat_IntVecAlloc( int nCap )
+{
+ Msat_IntVec_t * p;
+ p = ALLOC( Msat_IntVec_t, 1 );
+ if ( nCap > 0 && nCap < 16 )
+ nCap = 16;
+ p->nSize = 0;
+ p->nCap = nCap;
+ p->pArray = p->nCap? ALLOC( int, p->nCap ) : NULL;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates the vector from an integer array of the given size.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_IntVec_t * Msat_IntVecAllocArray( int * pArray, int nSize )
+{
+ Msat_IntVec_t * p;
+ p = ALLOC( Msat_IntVec_t, 1 );
+ p->nSize = nSize;
+ p->nCap = nSize;
+ p->pArray = pArray;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates the vector from an integer array of the given size.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_IntVec_t * Msat_IntVecAllocArrayCopy( int * pArray, int nSize )
+{
+ Msat_IntVec_t * p;
+ p = ALLOC( Msat_IntVec_t, 1 );
+ p->nSize = nSize;
+ p->nCap = nSize;
+ p->pArray = ALLOC( int, nSize );
+ memcpy( p->pArray, pArray, sizeof(int) * nSize );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Duplicates the integer array.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_IntVec_t * Msat_IntVecDup( Msat_IntVec_t * pVec )
+{
+ Msat_IntVec_t * p;
+ p = ALLOC( Msat_IntVec_t, 1 );
+ p->nSize = pVec->nSize;
+ p->nCap = pVec->nCap;
+ p->pArray = p->nCap? ALLOC( int, p->nCap ) : NULL;
+ memcpy( p->pArray, pVec->pArray, sizeof(int) * pVec->nSize );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Transfers the array into another vector.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Msat_IntVec_t * Msat_IntVecDupArray( Msat_IntVec_t * pVec )
+{
+ Msat_IntVec_t * p;
+ p = ALLOC( Msat_IntVec_t, 1 );
+ p->nSize = pVec->nSize;
+ p->nCap = pVec->nCap;
+ p->pArray = pVec->pArray;
+ pVec->nSize = 0;
+ pVec->nCap = 0;
+ pVec->pArray = NULL;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_IntVecFree( Msat_IntVec_t * p )
+{
+ FREE( p->pArray );
+ FREE( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Fills the vector with given number of entries.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_IntVecFill( Msat_IntVec_t * p, int nSize, int Entry )
+{
+ int i;
+ Msat_IntVecGrow( p, nSize );
+ p->nSize = nSize;
+ for ( i = 0; i < p->nSize; i++ )
+ p->pArray[i] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int * Msat_IntVecReleaseArray( Msat_IntVec_t * p )
+{
+ int * pArray = p->pArray;
+ p->nCap = 0;
+ p->nSize = 0;
+ p->pArray = NULL;
+ return pArray;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int * Msat_IntVecReadArray( Msat_IntVec_t * p )
+{
+ return p->pArray;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Msat_IntVecReadSize( Msat_IntVec_t * p )
+{
+ return p->nSize;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Msat_IntVecReadEntry( Msat_IntVec_t * p, int i )
+{
+ assert( i >= 0 && i < p->nSize );
+ return p->pArray[i];
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_IntVecWriteEntry( Msat_IntVec_t * p, int i, int Entry )
+{
+ assert( i >= 0 && i < p->nSize );
+ p->pArray[i] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Msat_IntVecReadEntryLast( Msat_IntVec_t * p )
+{
+ return p->pArray[p->nSize-1];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Resizes the vector to the given capacity.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_IntVecGrow( Msat_IntVec_t * p, int nCapMin )
+{
+ if ( p->nCap >= nCapMin )
+ return;
+ p->pArray = REALLOC( int, p->pArray, nCapMin );
+ p->nCap = nCapMin;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_IntVecShrink( Msat_IntVec_t * p, int nSizeNew )
+{
+ assert( p->nSize >= nSizeNew );
+ p->nSize = nSizeNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_IntVecClear( Msat_IntVec_t * p )
+{
+ p->nSize = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_IntVecPush( Msat_IntVec_t * p, int Entry )
+{
+ if ( p->nSize == p->nCap )
+ {
+ if ( p->nCap < 16 )
+ Msat_IntVecGrow( p, 16 );
+ else
+ Msat_IntVecGrow( p, 2 * p->nCap );
+ }
+ p->pArray[p->nSize++] = Entry;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Add the element while ensuring uniqueness.]
+
+ Description [Returns 1 if the element was found, and 0 if it was new. ]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Msat_IntVecPushUnique( Msat_IntVec_t * p, int Entry )
+{
+ int i;
+ for ( i = 0; i < p->nSize; i++ )
+ if ( p->pArray[i] == Entry )
+ return 1;
+ Msat_IntVecPush( p, Entry );
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Inserts the element while sorting in the increasing order.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_IntVecPushUniqueOrder( Msat_IntVec_t * p, int Entry, int fIncrease )
+{
+ int Entry1, Entry2;
+ int i;
+ Msat_IntVecPushUnique( p, Entry );
+ // find the p of the node
+ for ( i = p->nSize-1; i > 0; i-- )
+ {
+ Entry1 = p->pArray[i ];
+ Entry2 = p->pArray[i-1];
+ if ( fIncrease && Entry1 >= Entry2 ||
+ !fIncrease && Entry1 <= Entry2 )
+ break;
+ p->pArray[i ] = Entry2;
+ p->pArray[i-1] = Entry1;
+ }
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Returns the last entry and removes it from the list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Msat_IntVecPop( Msat_IntVec_t * p )
+{
+ assert( p->nSize > 0 );
+ return p->pArray[--p->nSize];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sorting the entries by their integer value.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Msat_IntVecSort( Msat_IntVec_t * p, int fReverse )
+{
+ if ( fReverse )
+ qsort( (void *)p->pArray, p->nSize, sizeof(int),
+ (int (*)(const void *, const void *)) Msat_IntVecSortCompare2 );
+ else
+ qsort( (void *)p->pArray, p->nSize, sizeof(int),
+ (int (*)(const void *, const void *)) Msat_IntVecSortCompare1 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Comparison procedure for two clauses.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Msat_IntVecSortCompare1( int * pp1, int * pp2 )
+{
+ // for some reason commenting out lines (as shown) led to crashing of the release version
+ if ( *pp1 < *pp2 )
+ return -1;
+ if ( *pp1 > *pp2 ) //
+ return 1;
+ return 0; //
+}
+
+/**Function*************************************************************
+
+ Synopsis [Comparison procedure for two clauses.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Msat_IntVecSortCompare2( int * pp1, int * pp2 )
+{
+ // for some reason commenting out lines (as shown) led to crashing of the release version
+ if ( *pp1 > *pp2 )
+ return -1;
+ if ( *pp1 < *pp2 ) //
+ return 1;
+ return 0; //
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/seq/module.make b/src/seq/module.make
new file mode 100644
index 00000000..d6d908e7
--- /dev/null
+++ b/src/seq/module.make
@@ -0,0 +1 @@
+SRC +=
diff --git a/src/sop/ft/ft.h b/src/sop/ft/ft.h
new file mode 100644
index 00000000..81e1a2dc
--- /dev/null
+++ b/src/sop/ft/ft.h
@@ -0,0 +1,105 @@
+/**CFile****************************************************************
+
+ FileName [ft.h]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Data structure for algebraic factoring.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - February 1, 2003.]
+
+ Revision [$Id: ft.h,v 1.1 2003/05/22 19:20:04 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __FT_H__
+#define __FT_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct Ft_Node_t_ Ft_Node_t;
+struct Ft_Node_t_
+{
+ // the first child
+ unsigned fCompl0 : 1; // complemented attribute
+ unsigned iFanin0 : 11; // fanin number
+ // the second child
+ unsigned fCompl1 : 1; // complemented attribute
+ unsigned iFanin1 : 11; // fanin number (1-based)
+ // other info
+ unsigned fIntern : 1; // marks any node that is not an elementary var
+ unsigned fConst : 1; // marks the constant 1 function
+ unsigned fCompl : 1; // marks the complement of topmost node
+ // printing info
+ unsigned fNodeOr : 1; // marks the original OR node
+ unsigned fEdge0 : 1; // marks the original complemented edge
+ unsigned fEdge1 : 1; // marks the original complemented edge
+ // some bits are unused
+};
+
+/*
+ The factored form of a SOP is an array (Vec_Int_t) of entries Ft_Node_t.
+ If the SOP has n input variables (some of them may not be in the true support)
+ the first n entries of the factored form array have 0s. This representation
+ makes it each to translate the factored form into an AIG.
+
+ The node structure contains fanins of the node and their complemented attributes
+ (using AIG semantics). The elementary variable (buffer or interver) are
+ represented as a node with the same fanins. For example: x' = AND( x', x' ).
+ The constant node cannot be represented. Constant functions should be detected
+ before calling the factoring procedure.
+*/
+
+// working with complemented attributes of objects
+static inline bool Ptr_IsComplement( void * p ) { return (bool)(((unsigned)p) & 01); }
+static inline void * Ptr_Regular( void * p ) { return (void *)((unsigned)(p) & ~01); }
+static inline void * Ptr_Not( void * p ) { return (void *)((unsigned)(p) ^ 01); }
+static inline void * Ptr_NotCond( void * p, int c ) { return (void *)((unsigned)(p) ^ (c)); }
+
+static inline Ft_Node_t * Ft_NodeRead( Vec_Int_t * vForm, int i ) { return (Ft_Node_t *)vForm->pArray + i; }
+static inline Ft_Node_t * Ft_NodeReadLast( Vec_Int_t * vForm ) { return (Ft_Node_t *)vForm->pArray + vForm->nSize - 1; }
+static inline Ft_Node_t * Ft_NodeFanin0( Vec_Int_t * vForm, Ft_Node_t * pNode ) { assert( pNode->fIntern ); return (Ft_Node_t *)vForm->pArray + pNode->iFanin0; }
+static inline Ft_Node_t * Ft_NodeFanin1( Vec_Int_t * vForm, Ft_Node_t * pNode ) { assert( pNode->fIntern ); return (Ft_Node_t *)vForm->pArray + pNode->iFanin1; }
+
+static inline Ft_Node_t Ft_Int2Node( int Num ) { return *((Ft_Node_t *)&Num); }
+static inline int Ft_Node2Int( Ft_Node_t Node ) { return *((int *)&Node); }
+static inline void Ft_NodeClean( Ft_Node_t * pNode ) { *((int *)pNode) = 0; }
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== ftFactor.c =====================================================*/
+extern void Ft_FactorStartMan();
+extern void Ft_FactorStopMan();
+extern Vec_Int_t * Ft_Factor( char * pSop );
+extern int Ft_FactorGetNumNodes( Vec_Int_t * vForm );
+extern int Ft_FactorGetNumVars( Vec_Int_t * vForm );
+/*=== ftPrint.c =====================================================*/
+extern void Ft_FactorPrint( FILE * pFile, Vec_Int_t * vForm, char * pNamesIn[], char * pNameOut );
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/src/sop/ft/ftFactor.c b/src/sop/ft/ftFactor.c
new file mode 100644
index 00000000..04779fe0
--- /dev/null
+++ b/src/sop/ft/ftFactor.c
@@ -0,0 +1,842 @@
+/**CFile****************************************************************
+
+ FileName [ftFactor.c]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Procedures for algebraic factoring.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - February 1, 2003.]
+
+ Revision [$Id: ftFactor.c,v 1.3 2003/09/01 04:56:43 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+#include "mvc.h"
+#include "ft.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// the types of nodes in FFs
+enum { FT_NODE_NONE, FT_NODE_AND, FT_NODE_OR, FT_NODE_INV, FT_NODE_LEAF, FT_NODE_0, FT_NODE_1 };
+
+static Ft_Node_t * Ft_Factor_rec( Vec_Int_t * vForm, Mvc_Cover_t * pCover );
+static Ft_Node_t * Ft_FactorLF_rec( Vec_Int_t * vForm, Mvc_Cover_t * pCover, Mvc_Cover_t * pSimple );
+
+static Ft_Node_t * Ft_FactorTrivial( Vec_Int_t * vForm, Mvc_Cover_t * pCover );
+static Ft_Node_t * Ft_FactorTrivialCube( Vec_Int_t * vForm, Mvc_Cover_t * pCover, Mvc_Cube_t * pCube );
+static Ft_Node_t * Ft_FactorTrivialTree_rec( Vec_Int_t * vForm, Ft_Node_t ** ppNodes, int nNodes, int fAnd );
+static Ft_Node_t * Ft_FactorTrivialCascade( Vec_Int_t * vForm, Mvc_Cover_t * pCover );
+static Ft_Node_t * Ft_FactorTrivialCubeCascade( Vec_Int_t * vForm, Mvc_Cover_t * pCover, Mvc_Cube_t * pCube );
+
+static Ft_Node_t * Ft_FactorNodeCreate( Vec_Int_t * vForm, int Type, Ft_Node_t * pNode1, Ft_Node_t * pNode2 );
+static Ft_Node_t * Ft_FactorLeafCreate( Vec_Int_t * vForm, int iLit );
+static void Ft_FactorFinalize( Vec_Int_t * vForm, Ft_Node_t * pNode, int nVars );
+static void Ft_FactorComplement( Vec_Int_t * vForm );
+static Vec_Int_t * Ft_FactorConst( int fConst1 );
+
+// temporary procedures that work with the covers
+static Mvc_Cover_t * Ft_ConvertSopToMvc( char * pSop );
+static int Ft_FactorVerify( char * pSop, Vec_Int_t * vForm );
+
+// temporary managers
+static Mvc_Manager_t * pMem = NULL;
+static DdManager * dd = NULL;
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Factors the cover.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Vec_Int_t * Ft_Factor( char * pSop )
+{
+ Vec_Int_t * vForm;
+ Ft_Node_t * pNode;
+ Mvc_Cover_t * pCover;
+ int nVars = Abc_SopGetVarNum( pSop );
+
+ // derive the cover from the SOP representation
+ pCover = Ft_ConvertSopToMvc( pSop );
+
+ // make sure the cover is CCS free (should be done before CST)
+ Mvc_CoverContain( pCover );
+ // check for trivial functions
+ if ( Mvc_CoverIsEmpty(pCover) )
+ {
+ Mvc_CoverFree( pCover );
+ return Ft_FactorConst( 0 );
+ }
+ if ( Mvc_CoverIsTautology(pCover) )
+ {
+ Mvc_CoverFree( pCover );
+ return Ft_FactorConst( 1 );
+ }
+
+ // perform CST
+ Mvc_CoverInverse( pCover ); // CST
+
+ // start the factored form
+ vForm = Vec_IntAlloc( 1000 );
+ Vec_IntFill( vForm, nVars, 0 );
+ // factor the cover
+ pNode = Ft_Factor_rec( vForm, pCover );
+ // finalize the factored form
+ Ft_FactorFinalize( vForm, pNode, nVars );
+ // check if the cover was originally complented
+ if ( Abc_SopGetPhase(pSop) == 0 )
+ Ft_FactorComplement( vForm );
+
+ // verify the factored form
+// if ( !Ft_FactorVerify( pSop, vForm ) )
+// printf( "Verification has failed.\n" );
+
+// Mvc_CoverInverse( pCover ); // undo CST
+ Mvc_CoverFree( pCover );
+ return vForm;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Internal recursive factoring procedure.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ft_Node_t * Ft_Factor_rec( Vec_Int_t * vForm, Mvc_Cover_t * pCover )
+{
+ Mvc_Cover_t * pDiv, * pQuo, * pRem, * pCom;
+ Ft_Node_t * pNodeDiv, * pNodeQuo, * pNodeRem;
+ Ft_Node_t * pNodeAnd, * pNode;
+
+ // make sure the cover contains some cubes
+ assert( Mvc_CoverReadCubeNum(pCover) );
+
+ // get the divisor
+ pDiv = Mvc_CoverDivisor( pCover );
+ if ( pDiv == NULL )
+ return Ft_FactorTrivial( vForm, pCover );
+
+ // divide the cover by the divisor
+ Mvc_CoverDivideInternal( pCover, pDiv, &pQuo, &pRem );
+ assert( Mvc_CoverReadCubeNum(pQuo) );
+
+ Mvc_CoverFree( pDiv );
+ Mvc_CoverFree( pRem );
+
+ // check the trivial case
+ if ( Mvc_CoverReadCubeNum(pQuo) == 1 )
+ {
+ pNode = Ft_FactorLF_rec( vForm, pCover, pQuo );
+ Mvc_CoverFree( pQuo );
+ return pNode;
+ }
+
+ // make the quotient cube free
+ Mvc_CoverMakeCubeFree( pQuo );
+
+ // divide the cover by the quotient
+ Mvc_CoverDivideInternal( pCover, pQuo, &pDiv, &pRem );
+
+ // check the trivial case
+ if ( Mvc_CoverIsCubeFree( pDiv ) )
+ {
+ pNodeDiv = Ft_Factor_rec( vForm, pDiv );
+ pNodeQuo = Ft_Factor_rec( vForm, pQuo );
+ Mvc_CoverFree( pDiv );
+ Mvc_CoverFree( pQuo );
+ pNodeAnd = Ft_FactorNodeCreate( vForm, FT_NODE_AND, pNodeDiv, pNodeQuo );
+ if ( Mvc_CoverReadCubeNum(pRem) == 0 )
+ {
+ Mvc_CoverFree( pRem );
+ return pNodeAnd;
+ }
+ else
+ {
+ pNodeRem = Ft_Factor_rec( vForm, pRem );
+ Mvc_CoverFree( pRem );
+ return Ft_FactorNodeCreate( vForm, FT_NODE_OR, pNodeAnd, pNodeRem );
+ }
+ }
+
+ // get the common cube
+ pCom = Mvc_CoverCommonCubeCover( pDiv );
+ Mvc_CoverFree( pDiv );
+ Mvc_CoverFree( pQuo );
+ Mvc_CoverFree( pRem );
+
+ // solve the simple problem
+ pNode = Ft_FactorLF_rec( vForm, pCover, pCom );
+ Mvc_CoverFree( pCom );
+ return pNode;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Internal recursive factoring procedure for the leaf case.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ft_Node_t * Ft_FactorLF_rec( Vec_Int_t * vForm, Mvc_Cover_t * pCover, Mvc_Cover_t * pSimple )
+{
+ Mvc_Cover_t * pDiv, * pQuo, * pRem;
+ Ft_Node_t * pNodeDiv, * pNodeQuo, * pNodeRem;
+ Ft_Node_t * pNodeAnd;
+
+ // get the most often occurring literal
+ pDiv = Mvc_CoverBestLiteralCover( pCover, pSimple );
+ // divide the cover by the literal
+ Mvc_CoverDivideByLiteral( pCover, pDiv, &pQuo, &pRem );
+ // get the node pointer for the literal
+ pNodeDiv = Ft_FactorTrivialCube( vForm, pDiv, Mvc_CoverReadCubeHead(pDiv) );
+ Mvc_CoverFree( pDiv );
+ // factor the quotient and remainder
+ pNodeQuo = Ft_Factor_rec( vForm, pQuo );
+ Mvc_CoverFree( pQuo );
+ pNodeAnd = Ft_FactorNodeCreate( vForm, FT_NODE_AND, pNodeDiv, pNodeQuo );
+ if ( Mvc_CoverReadCubeNum(pRem) == 0 )
+ {
+ Mvc_CoverFree( pRem );
+ return pNodeAnd;
+ }
+ else
+ {
+ pNodeRem = Ft_Factor_rec( vForm, pRem );
+ Mvc_CoverFree( pRem );
+ return Ft_FactorNodeCreate( vForm, FT_NODE_OR, pNodeAnd, pNodeRem );
+ }
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Factoring the cover, which has no algebraic divisors.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ft_Node_t * Ft_FactorTrivial( Vec_Int_t * vForm, Mvc_Cover_t * pCover )
+{
+ Ft_Node_t ** ppNodes;
+ Ft_Node_t * pNode;
+ Mvc_Cube_t * pCube;
+ int i, nNodes;
+
+ // create space to put the cubes
+ nNodes = Mvc_CoverReadCubeNum(pCover);
+ assert( nNodes > 0 );
+ ppNodes = ALLOC( Ft_Node_t *, nNodes );
+ // create the factored form for each cube
+ i = 0;
+ Mvc_CoverForEachCube( pCover, pCube )
+ ppNodes[i++] = Ft_FactorTrivialCube( vForm, pCover, pCube );
+ assert( i == nNodes );
+ // balance the factored forms
+ pNode = Ft_FactorTrivialTree_rec( vForm, ppNodes, nNodes, 0 );
+ free( ppNodes );
+ return pNode;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Factoring the cube.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ft_Node_t * Ft_FactorTrivialCube( Vec_Int_t * vForm, Mvc_Cover_t * pCover, Mvc_Cube_t * pCube )
+{
+ Ft_Node_t ** ppNodes;
+ Ft_Node_t * pNode;
+ int iBit, Value, i;
+
+ // create space to put each literal
+ ppNodes = ALLOC( Ft_Node_t *, pCover->nBits );
+ // create the factored form for each literal
+ i = 0;
+ Mvc_CubeForEachBit( pCover, pCube, iBit, Value )
+ {
+ if ( Value )
+ ppNodes[i++] = Ft_FactorLeafCreate( vForm, iBit );
+ }
+ assert( i > 0 && i < pCover->nBits );
+ // balance the factored forms
+ pNode = Ft_FactorTrivialTree_rec( vForm, ppNodes, i, 1 );
+ free( ppNodes );
+ return pNode;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Create the well-balanced tree of nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ft_Node_t * Ft_FactorTrivialTree_rec( Vec_Int_t * vForm, Ft_Node_t ** ppNodes, int nNodes, int fAnd )
+{
+ Ft_Node_t * pNode1, * pNode2;
+ int nNodes1, nNodes2;
+
+ if ( nNodes == 1 )
+ return ppNodes[0];
+
+ // split the nodes into two parts
+ nNodes1 = nNodes/2;
+ nNodes2 = nNodes - nNodes1;
+
+ // recursively construct the tree for the parts
+ pNode1 = Ft_FactorTrivialTree_rec( vForm, ppNodes, nNodes1, fAnd );
+ pNode2 = Ft_FactorTrivialTree_rec( vForm, ppNodes + nNodes1, nNodes2, fAnd );
+
+ return Ft_FactorNodeCreate( vForm, fAnd? FT_NODE_AND : FT_NODE_OR, pNode1, pNode2 );
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Factoring the cover, which has no algebraic divisors.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ft_Node_t * Ft_FactorTrivialCascade( Vec_Int_t * vForm, Mvc_Cover_t * pCover )
+{
+ Ft_Node_t * pNode;
+ Mvc_Cube_t * pCube;
+
+ // iterate through the cubes
+ pNode = NULL;
+ Mvc_CoverForEachCube( pCover, pCube )
+ {
+ if ( pNode == NULL )
+ pNode = Ft_FactorTrivialCube( vForm, pCover, pCube );
+ else
+ pNode = Ft_FactorNodeCreate( vForm, FT_NODE_OR, pNode, Ft_FactorTrivialCubeCascade( vForm, pCover, pCube ) );
+ }
+ assert( pNode ); // if this assertion fails, the input cover is not SCC-free
+ return pNode;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Factoring the cube.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ft_Node_t * Ft_FactorTrivialCubeCascade( Vec_Int_t * vForm, Mvc_Cover_t * pCover, Mvc_Cube_t * pCube )
+{
+ Ft_Node_t * pNode;
+ int iBit, Value;
+
+ // iterate through the literals
+ pNode = NULL;
+ Mvc_CubeForEachBit( pCover, pCube, iBit, Value )
+ {
+ if ( Value )
+ {
+ if ( pNode == NULL )
+ pNode = Ft_FactorLeafCreate( vForm, iBit );
+ else
+ pNode = Ft_FactorNodeCreate( vForm, FT_NODE_AND, pNode, Ft_FactorLeafCreate( vForm, iBit ) );
+ }
+ }
+ assert( pNode ); // if this assertion fails, the input cover is not SCC-free
+ return pNode;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ft_Node_t * Ft_FactorNodeCreate( Vec_Int_t * vForm, int Type, Ft_Node_t * pNode1, Ft_Node_t * pNode2 )
+{
+ Ft_Node_t * pNode;
+ // get the new node
+ Vec_IntPush( vForm, 0 );
+ pNode = Ft_NodeReadLast( vForm );
+ // set the inputs and other info
+ pNode->iFanin0 = (Ft_Node_t *)Ptr_Regular(pNode1) - (Ft_Node_t *)vForm->pArray;
+ pNode->iFanin1 = (Ft_Node_t *)Ptr_Regular(pNode2) - (Ft_Node_t *)vForm->pArray;
+ assert( pNode->iFanin0 < (unsigned)vForm->nSize );
+ assert( pNode->iFanin1 < (unsigned)vForm->nSize );
+ pNode->fIntern = 1;
+ pNode->fCompl = 0;
+ pNode->fConst = 0;
+ pNode->fEdge0 = Ptr_IsComplement(pNode1);
+ pNode->fEdge1 = Ptr_IsComplement(pNode2);
+ // consider specific gates
+ if ( Type == FT_NODE_OR )
+ {
+ pNode->fCompl0 = !Ptr_IsComplement(pNode1);
+ pNode->fCompl1 = !Ptr_IsComplement(pNode2);
+ pNode->fNodeOr = 1;
+ return Ptr_Not( pNode );
+ }
+ if ( Type == FT_NODE_AND )
+ {
+ pNode->fCompl0 = Ptr_IsComplement(pNode1);
+ pNode->fCompl1 = Ptr_IsComplement(pNode2);
+ pNode->fNodeOr = 0;
+ return pNode;
+ }
+ assert( 0 );
+ return NULL;
+
+/*
+ Vec_Int_t * vForm;
+ assert( pNode1 && pNode2 );
+ pNode = MEM_ALLOC( vForm->pMem, void, 1 );
+ memset( pNode, 0, sizeof(void) );
+ pNode->Type = Type;
+ pNode->pOne = pNode1;
+ pNode->pTwo = pNode2;
+ // update FF statistics
+ if ( pNode->Type == FT_NODE_LEAF )
+ vForm->nNodes++;
+ return pNode;
+*/
+}
+
+/**Function*************************************************************
+
+ Synopsis [Factoring the cube.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ft_Node_t * Ft_FactorLeafCreate( Vec_Int_t * vForm, int iLit )
+{
+ return Ptr_NotCond( Ft_NodeRead(vForm, iLit/2), iLit%2 ); // using CST
+
+/*
+ Vm_VarMap_t * pVm;
+ int * pValuesFirst, * pValues;
+ int nValuesIn, nVarsIn;
+ Vec_Int_t * vForm;
+ int iVar;
+ pVm = vForm->pVm;
+ pValues = Vm_VarMapReadValuesArray(pVm);
+ pValuesFirst = Vm_VarMapReadValuesFirstArray(pVm);
+ nValuesIn = Vm_VarMapReadValuesInNum(pVm);
+ nVarsIn = Vm_VarMapReadVarsInNum(pVm);
+ assert( iLit < nValuesIn );
+ for ( iVar = 0; iVar < nVarsIn; iVar++ )
+ if ( iLit < pValuesFirst[iVar] + pValues[iVar] )
+ break;
+ assert( iVar < nVarsIn );
+ pNode = Ft_FactorNodeCreate( vForm, FT_NODE_LEAF, NULL, NULL );
+ pNode->VarNum = iVar;
+ pNode->nValues = pValues[iVar];
+ pNode->uData = FT_MV_MASK(pNode->nValues) ^ (1 << (iLit - pValuesFirst[iVar]));
+ return pNode;
+*/
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Adds a single-variable literal if necessary.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ft_FactorFinalize( Vec_Int_t * vForm, Ft_Node_t * pRoot, int nVars )
+{
+ Ft_Node_t * pRootR = Ptr_Regular(pRoot);
+ int iNode = pRootR - (Ft_Node_t *)vForm->pArray;
+ Ft_Node_t * pNode;
+ if ( iNode >= nVars )
+ {
+ // set the complemented attribute
+ pRootR->fCompl = Ptr_IsComplement(pRoot);
+ return;
+ }
+ // create a new node
+ Vec_IntPush( vForm, 0 );
+ pNode = Ft_NodeReadLast( vForm );
+ pNode->iFanin0 = iNode;
+ pNode->iFanin1 = iNode;
+ pNode->fIntern = 1;
+ pNode->fCompl = Ptr_IsComplement(pRoot);
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the number of variables in the factored form.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ft_FactorGetNumVars( Vec_Int_t * vForm )
+{
+ int i;
+ for ( i = 0; i < vForm->nSize; i++ )
+ if ( vForm->pArray[i] )
+ break;
+ return i;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the number of variables in the factored form.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ft_FactorGetNumNodes( Vec_Int_t * vForm )
+{
+ Ft_Node_t * pNode;
+ int i;
+ pNode = Ft_NodeReadLast(vForm);
+ if ( pNode->fConst )
+ return 0;
+ if ( !pNode->fConst && pNode->iFanin0 == pNode->iFanin1 ) // literal
+ return 1;
+ for ( i = 0; i < vForm->nSize; i++ )
+ if ( vForm->pArray[i] )
+ break;
+ return vForm->nSize - i + 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Complements the factored form.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ft_FactorComplement( Vec_Int_t * vForm )
+{
+ Ft_Node_t * pNode;
+ int nVars = Ft_FactorGetNumVars( vForm );
+ assert( nVars >= 0 );
+ pNode = Ft_NodeReadLast(vForm);
+ pNode->fCompl ^= 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates a constant 0 or 1 factored form.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Vec_Int_t * Ft_FactorConst( int fConst1 )
+{
+ Vec_Int_t * vForm;
+ Ft_Node_t * pNode;
+ // create the constant node
+ vForm = Vec_IntAlloc( 1 );
+ Vec_IntPush( vForm, 0 );
+ pNode = Ft_NodeReadLast( vForm );
+ pNode->fIntern = 1;
+ pNode->fConst = 1;
+ pNode->fCompl = !fConst1;
+ return vForm;
+}
+
+
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Start the MVC manager used in the factoring package.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ft_FactorStartMan()
+{
+ assert( pMem == NULL );
+ pMem = Mvc_ManagerStart();
+ dd = Cudd_Init( 0, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Stops the MVC maanager used in the factoring package.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ft_FactorStopMan()
+{
+ assert( pMem );
+ Mvc_ManagerFree( pMem );
+ Cudd_Quit( dd );
+ pMem = NULL;
+ dd = NULL;
+}
+
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Converts SOP into MVC.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cover_t * Ft_ConvertSopToMvc( char * pSop )
+{
+ Mvc_Cover_t * pMvc;
+ Mvc_Cube_t * pMvcCube;
+ char * pCube;
+ int nVars, Value, v;
+
+ // start the cover
+ nVars = Abc_SopGetVarNum(pSop);
+ pMvc = Mvc_CoverAlloc( pMem, nVars * 2 );
+ // check the logic function of the node
+ Abc_SopForEachCube( pSop, nVars, pCube )
+ {
+ // create and add the cube
+ pMvcCube = Mvc_CubeAlloc( pMvc );
+ Mvc_CoverAddCubeTail( pMvc, pMvcCube );
+ // fill in the literals
+ Mvc_CubeBitFill( pMvcCube );
+ Abc_CubeForEachVar( pCube, Value, v )
+ {
+ if ( Value == '0' )
+ Mvc_CubeBitRemove( pMvcCube, v * 2 + 1 );
+ else if ( Value == '1' )
+ Mvc_CubeBitRemove( pMvcCube, v * 2 );
+ }
+ }
+//Mvc_CoverPrint( pMvc );
+ return pMvc;
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Converts SOP into BDD.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Ft_ConvertSopToBdd( DdManager * dd, char * pSop )
+{
+ DdNode * bSum, * bCube, * bTemp, * bVar;
+ char * pCube;
+ int nVars, Value, v;
+ // start the cover
+ nVars = Abc_SopGetVarNum(pSop);
+ // check the logic function of the node
+ bSum = Cudd_ReadLogicZero(dd); Cudd_Ref( bSum );
+ Abc_SopForEachCube( pSop, nVars, pCube )
+ {
+ bCube = Cudd_ReadOne(dd); Cudd_Ref( bCube );
+ Abc_CubeForEachVar( pCube, Value, v )
+ {
+ if ( Value == '0' )
+ bVar = Cudd_Not( Cudd_bddIthVar( dd, v ) );
+ else if ( Value == '1' )
+ bVar = Cudd_bddIthVar( dd, v );
+ else
+ continue;
+ bCube = Cudd_bddAnd( dd, bTemp = bCube, bVar ); Cudd_Ref( bCube );
+ Cudd_RecursiveDeref( dd, bTemp );
+ }
+ bSum = Cudd_bddOr( dd, bTemp = bSum, bCube ); Cudd_Ref( bSum );
+ Cudd_RecursiveDeref( dd, bTemp );
+ Cudd_RecursiveDeref( dd, bCube );
+ }
+ // complement the result if necessary
+ bSum = Cudd_NotCond( bSum, !Abc_SopGetPhase(pSop) );
+ Cudd_Deref( bSum );
+ return bSum;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Converts SOP into BDD.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Ft_ConvertFormToBdd( DdManager * dd, Vec_Int_t * vForm )
+{
+ Vec_Ptr_t * vFuncs;
+ DdNode * bFunc, * bFunc0, * bFunc1;
+ Ft_Node_t * pNode;
+ int i, nVars;
+
+ // sanity checks
+ nVars = Ft_FactorGetNumVars( vForm );
+ assert( nVars >= 0 );
+ assert( vForm->nSize > nVars );
+
+ // check for constant function
+ pNode = Ft_NodeRead( vForm, 0 );
+ if ( pNode->fConst )
+ return Cudd_NotCond( dd->one, pNode->fCompl );
+
+ // start the array of elementary variables
+ vFuncs = Vec_PtrAlloc( 20 );
+ for ( i = 0; i < nVars; i++ )
+ Vec_PtrPush( vFuncs, Cudd_bddIthVar(dd, i) );
+
+ // compute the functions of other nodes
+ for ( i = nVars; i < vForm->nSize; i++ )
+ {
+ pNode = Ft_NodeRead( vForm, i );
+ bFunc0 = Cudd_NotCond( vFuncs->pArray[pNode->iFanin0], pNode->fCompl0 );
+ bFunc1 = Cudd_NotCond( vFuncs->pArray[pNode->iFanin1], pNode->fCompl1 );
+ bFunc = Cudd_bddAnd( dd, bFunc0, bFunc1 ); Cudd_Ref( bFunc );
+ Vec_PtrPush( vFuncs, bFunc );
+ }
+ assert( vForm->nSize = vFuncs->nSize );
+
+ // deref the intermediate results
+ for ( i = nVars; i < vForm->nSize-1; i++ )
+ Cudd_RecursiveDeref( dd, (DdNode *)vFuncs->pArray[i] );
+ Vec_PtrFree( vFuncs );
+
+ // complement the result if necessary
+ pNode = Ft_NodeReadLast( vForm );
+ bFunc = Cudd_NotCond( bFunc, pNode->fCompl );
+
+ // return the result
+ Cudd_Deref( bFunc );
+ return bFunc;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Verifies that the factoring is correct.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ft_FactorVerify( char * pSop, Vec_Int_t * vForm )
+{
+ DdNode * bFunc1, * bFunc2;
+ int RetValue;
+ bFunc1 = Ft_ConvertSopToBdd( dd, pSop ); Cudd_Ref( bFunc1 );
+ bFunc2 = Ft_ConvertFormToBdd( dd, vForm ); Cudd_Ref( bFunc2 );
+//Extra_bddPrint( dd, bFunc1 ); printf("\n");
+//Extra_bddPrint( dd, bFunc2 ); printf("\n");
+ RetValue = (bFunc1 == bFunc2);
+ Cudd_RecursiveDeref( dd, bFunc1 );
+ Cudd_RecursiveDeref( dd, bFunc2 );
+ return RetValue;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sop/ft/ftPrint.c b/src/sop/ft/ftPrint.c
new file mode 100644
index 00000000..e08ceaae
--- /dev/null
+++ b/src/sop/ft/ftPrint.c
@@ -0,0 +1,255 @@
+/**CFile****************************************************************
+
+ FileName [ftPrint.c]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Procedures to print the factored tree.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - February 1, 2003.]
+
+ Revision [$Id: ftPrint.c,v 1.1 2003/05/22 19:20:05 alanmi Exp $]
+
+***********************************************************************/
+
+#include "abc.h"
+#include "ft.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Ft_FactorPrint_rec( FILE * pFile, Vec_Int_t * vForm, Ft_Node_t * pNode, int fCompl, char * pNamesIn[], int * pPos, int LitSizeMax );
+static int Ft_FactorPrintGetLeafName( FILE * pFile, Vec_Int_t * vForm, Ft_Node_t * pNode, int fCompl, char * pNamesIn[] );
+static void Ft_FactorPrintUpdatePos( FILE * pFile, int * pPos, int LitSizeMax );
+static int Ft_FactorPrintOutputName( FILE * pFile, char * pNameOut, int fCompl );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ft_FactorPrint( FILE * pFile, Vec_Int_t * vForm, char * pNamesIn[], char * pNameOut )
+{
+ Ft_Node_t * pNode;
+ char Buffer[5];
+ int Pos, i, LitSizeMax, LitSizeCur, nVars;
+ int fMadeupNames;
+
+ // sanity checks
+ nVars = Ft_FactorGetNumVars( vForm );
+ assert( nVars >= 0 );
+ assert( vForm->nSize > nVars );
+
+ // create the names if not given by the user
+ fMadeupNames = 0;
+ if ( pNamesIn == NULL )
+ {
+ fMadeupNames = 1;
+ pNamesIn = ALLOC( char *, nVars );
+ for ( i = 0; i < nVars; i++ )
+ {
+ if ( nVars < 26 )
+ {
+ Buffer[0] = 'a' + i;
+ Buffer[1] = 0;
+ }
+ else
+ {
+ Buffer[0] = 'a' + i%26;
+ Buffer[1] = '0' + i/26;
+ Buffer[2] = 0;
+ }
+ pNamesIn[i] = util_strsav( Buffer );
+ }
+ }
+
+ // get the size of the longest literal
+ LitSizeMax = 0;
+ for ( i = 0; i < nVars; i++ )
+ {
+ LitSizeCur = strlen(pNamesIn[i]);
+ if ( LitSizeMax < LitSizeCur )
+ LitSizeMax = LitSizeCur;
+ }
+ if ( LitSizeMax > 50 )
+ LitSizeMax = 20;
+
+ // print the output name
+ pNode = Ft_NodeReadLast(vForm);
+ if ( !pNode->fConst && pNode->iFanin0 == pNode->iFanin1 ) // literal
+ {
+ Pos = Ft_FactorPrintOutputName( pFile, pNameOut, 0 );
+ Ft_FactorPrintGetLeafName( pFile, vForm, Ft_NodeFanin0(vForm,pNode), pNode->fCompl, pNamesIn );
+ }
+ else // constant or non-trivial form
+ {
+ Pos = Ft_FactorPrintOutputName( pFile, pNameOut, pNode->fCompl );
+ Ft_FactorPrint_rec( pFile, vForm, pNode, 0, pNamesIn, &Pos, LitSizeMax );
+ }
+ fprintf( pFile, "\n" );
+
+ if ( fMadeupNames )
+ {
+ for ( i = 0; i < nVars; i++ )
+ free( pNamesIn[i] );
+ free( pNamesIn );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ft_FactorPrint_rec( FILE * pFile, Vec_Int_t * vForm, Ft_Node_t * pNode, int fCompl, char * pNamesIn[], int * pPos, int LitSizeMax )
+{
+ Ft_Node_t * pNode0, * pNode1;
+
+ if ( pNode->fConst ) // FT_NODE_0 )
+ {
+ if ( fCompl )
+ fprintf( pFile, "Constant 0" );
+ else
+ fprintf( pFile, "Constant 1" );
+ return;
+ }
+ if ( !pNode->fIntern ) // FT_NODE_LEAF )
+ {
+ (*pPos) += Ft_FactorPrintGetLeafName( pFile, vForm, pNode, fCompl, pNamesIn );
+ return;
+ }
+
+ pNode0 = Ft_NodeFanin0( vForm, pNode );
+ pNode1 = Ft_NodeFanin1( vForm, pNode );
+ if ( !pNode->fNodeOr ) // FT_NODE_AND )
+ {
+ if ( !pNode0->fNodeOr ) // != FT_NODE_OR )
+ Ft_FactorPrint_rec( pFile, vForm, pNode0, pNode->fEdge0, pNamesIn, pPos, LitSizeMax );
+ else
+ {
+ fprintf( pFile, "(" );
+ (*pPos)++;
+ Ft_FactorPrint_rec( pFile, vForm, pNode0, pNode->fEdge0, pNamesIn, pPos, LitSizeMax );
+ fprintf( pFile, ")" );
+ (*pPos)++;
+ }
+ fprintf( pFile, " " );
+ (*pPos)++;
+
+ Ft_FactorPrintUpdatePos( pFile, pPos, LitSizeMax );
+
+ if ( !pNode1->fNodeOr ) // != FT_NODE_OR )
+ Ft_FactorPrint_rec( pFile, vForm, pNode1, pNode->fEdge1, pNamesIn, pPos, LitSizeMax );
+ else
+ {
+ fprintf( pFile, "(" );
+ (*pPos)++;
+ Ft_FactorPrint_rec( pFile, vForm, pNode1, pNode->fEdge1, pNamesIn, pPos, LitSizeMax );
+ fprintf( pFile, ")" );
+ (*pPos)++;
+ }
+ return;
+ }
+ if ( pNode->fNodeOr ) // FT_NODE_OR )
+ {
+ Ft_FactorPrint_rec( pFile, vForm, pNode0, pNode->fEdge0, pNamesIn, pPos, LitSizeMax );
+ fprintf( pFile, " + " );
+ (*pPos) += 3;
+
+ Ft_FactorPrintUpdatePos( pFile, pPos, LitSizeMax );
+
+ Ft_FactorPrint_rec( pFile, vForm, pNode1, pNode->fEdge1, pNamesIn, pPos, LitSizeMax );
+ return;
+ }
+ assert( 0 );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ft_FactorPrintGetLeafName( FILE * pFile, Vec_Int_t * vForm, Ft_Node_t * pNode, int fCompl, char * pNamesIn[] )
+{
+ static char Buffer[100];
+ int iVar;
+ assert( !Ptr_IsComplement(pNode) );
+ iVar = (Ft_Node_t *)pNode - (Ft_Node_t *)vForm->pArray;
+ sprintf( Buffer, "%s%s", pNamesIn[iVar], fCompl? "\'" : "" );
+ fprintf( pFile, "%s", Buffer );
+ return strlen( Buffer );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ft_FactorPrintUpdatePos( FILE * pFile, int * pPos, int LitSizeMax )
+{
+ int i;
+ if ( *pPos + LitSizeMax < 77 )
+ return;
+ fprintf( pFile, "\n" );
+ for ( i = 0; i < 10; i++ )
+ fprintf( pFile, " " );
+ *pPos = 10;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Starts the printout for a factored form or cover.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ft_FactorPrintOutputName( FILE * pFile, char * pNameOut, int fCompl )
+{
+ if ( pNameOut == NULL )
+ return 0;
+ fprintf( pFile, "%6s%s = ", pNameOut, fCompl? "\'" : " " );
+ return 10;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sop/ft/module.make b/src/sop/ft/module.make
new file mode 100644
index 00000000..37e78ce6
--- /dev/null
+++ b/src/sop/ft/module.make
@@ -0,0 +1,2 @@
+SRC += src/sop/ft/ftFactor.c \
+ src/sop/ft/ftPrint.c
diff --git a/src/sop/mvc/module.make b/src/sop/mvc/module.make
new file mode 100644
index 00000000..bdb5c5cf
--- /dev/null
+++ b/src/sop/mvc/module.make
@@ -0,0 +1,16 @@
+SRC += src/sop/mvc/mvc.c \
+ src/sop/mvc/mvcApi.c \
+ src/sop/mvc/mvcCompare.c \
+ src/sop/mvc/mvcContain.c \
+ src/sop/mvc/mvcCover.c \
+ src/sop/mvc/mvcCube.c \
+ src/sop/mvc/mvcDivide.c \
+ src/sop/mvc/mvcDivisor.c \
+ src/sop/mvc/mvcList.c \
+ src/sop/mvc/mvcLits.c \
+ src/sop/mvc/mvcMan.c \
+ src/sop/mvc/mvcOpAlg.c \
+ src/sop/mvc/mvcOpBool.c \
+ src/sop/mvc/mvcPrint.c \
+ src/sop/mvc/mvcSort.c \
+ src/sop/mvc/mvcUtils.c
diff --git a/src/sop/mvc/mvc.c b/src/sop/mvc/mvc.c
new file mode 100644
index 00000000..9430276c
--- /dev/null
+++ b/src/sop/mvc/mvc.c
@@ -0,0 +1,46 @@
+/**CFile****************************************************************
+
+ FileName [mvc.c]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis []
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - February 1, 2003.]
+
+ Revision [$Id: mvc.c,v 1.3 2003/03/19 19:50:26 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mvc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sop/mvc/mvc.h b/src/sop/mvc/mvc.h
new file mode 100644
index 00000000..ee8c31be
--- /dev/null
+++ b/src/sop/mvc/mvc.h
@@ -0,0 +1,733 @@
+/**CFile****************************************************************
+
+ FileName [mvc.h]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Data structure for MV cube/cover manipulation.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - February 1, 2003.]
+
+ Revision [$Id: mvc.h,v 1.10 2003/05/02 23:23:59 wjiang Exp $]
+
+***********************************************************************/
+
+#ifndef __MVC_H__
+#define __MVC_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include "util.h"
+#include "extra.h"
+//#include "vm.h"
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+// this is the only part of Mvc package, which should be modified
+// when compiling the package for other platforms
+
+// these parameters can be computed but setting them manually makes it faster
+#define BITS_PER_WORD 32 // sizeof(Mvc_CubeWord_t) * 8
+#define BITS_PER_WORD_MINUS 31 // the same minus 1
+#define BITS_PER_WORD_LOG 5 // log2(sizeof(Mvc_CubeWord_t) * 8)
+#define BITS_DISJOINT ((Mvc_CubeWord_t)0x55555555) // the mask of the type "01010101"
+#define BITS_FULL ((Mvc_CubeWord_t)0xffffffff) // the mask of the type "11111111"
+
+// uncomment this macro to switch to standard memory management
+//#define USE_SYSTEM_MEMORY_MANAGEMENT
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// cube/list/cover/data
+typedef unsigned long Mvc_CubeWord_t;
+typedef struct MvcCubeStruct Mvc_Cube_t;
+typedef struct MvcListStruct Mvc_List_t;
+typedef struct MvcCoverStruct Mvc_Cover_t;
+typedef struct MvcDataStruct Mvc_Data_t;
+typedef struct MvcManagerStruct Mvc_Manager_t;
+
+// the cube data structure
+struct MvcCubeStruct
+{
+ Mvc_Cube_t * pNext; // the next cube in the linked list
+ unsigned iLast : 8; // the index of the last word
+ unsigned nUnused : 6; // the number of unused bits in the last word
+ unsigned fPrime : 1; // marks the prime cube
+ unsigned fEssen : 1; // marks the essential cube
+ unsigned nOnes : 16; // the number of 1's in the bit data
+ Mvc_CubeWord_t pData[1]; // the first Mvc_CubeWord_t filled with bit data
+};
+
+// the single-linked list of cubes in the cover
+struct MvcListStruct
+{
+ Mvc_Cube_t * pHead; // the first cube in the list
+ Mvc_Cube_t * pTail; // the last cube in the list
+ int nItems; // the number of cubes in the list
+};
+
+// the cover data structure
+struct MvcCoverStruct
+{
+ char nWords; // the number of machine words
+ char nUnused; // the number of unused bits in the last word
+ short nBits; // the number of used data bits in the cube
+ Mvc_List_t lCubes; // the single-linked list of cubes
+ Mvc_Cube_t ** pCubes; // the array of cubes (for sorting)
+ int nCubesAlloc; // the size of allocated storage
+ int * pLits; // the counter of lit occurrances in cubes
+ Mvc_Cube_t * pMask; // the multipurpose mask
+ Mvc_Manager_t * pMem; // the memory manager
+};
+
+// data structure to store information about MV variables
+struct MvcDataStruct
+{
+ Mvc_Manager_t * pMan; // the memory manager
+// Vm_VarMap_t * pVm; // the MV variable data
+ int nBinVars; // the number of binary variables
+ Mvc_Cube_t * pMaskBin; // the mask to select the binary bits only
+ Mvc_Cube_t ** ppMasks; // the mask to select each MV variable
+ Mvc_Cube_t * ppTemp[3]; // the temporary cubes
+};
+
+// the manager of covers and cubes (as of today, only managing memory)
+struct MvcManagerStruct
+{
+ Extra_MmFixed_t * pManC; // the manager for covers
+ Extra_MmFixed_t * pMan1; // the manager for 1-word cubes
+ Extra_MmFixed_t * pMan2; // the manager for 2-word cubes
+ Extra_MmFixed_t * pMan4; // the manager for 3-word cubes
+};
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// reading data from the header of the cube
+#define Mvc_CubeReadNext(Cube) ((Cube)->pNext)
+#define Mvc_CubeReadNextP(Cube) (&(Cube)->pNext)
+#define Mvc_CubeReadLast(Cube) ((Cube)->iLast)
+#define Mvc_CubeReadSize(Cube) ((Cube)->nOnes)
+// setting data to the header of the cube
+#define Mvc_CubeSetNext(Cube,Next) ((Cube)->pNext = (Next))
+#define Mvc_CubeSetLast(Cube,Last) ((Cube)->iLast = (Last))
+#define Mvc_CubeSetSize(Cube,Size) ((Cube)->nOnes = (Size))
+// checking the number of words
+
+#define Mvc_Cube1Words(Cube) ((Cube)->iLast == 0)
+#define Mvc_Cube2Words(Cube) ((Cube)->iLast == 1)
+#define Mvc_CubeNWords(Cube) ((Cube)->iLast > 1)
+// getting one data bit
+#define Mvc_CubeWhichWord(Bit) ((Bit) >> BITS_PER_WORD_LOG)
+#define Mvc_CubeWhichBit(Bit) ((Bit) & BITS_PER_WORD_MINUS)
+// accessing individual bits
+#define Mvc_CubeBitValue(Cube, Bit) (((Cube)->pData[Mvc_CubeWhichWord(Bit)] & (((Mvc_CubeWord_t)1)<<(Mvc_CubeWhichBit(Bit)))) > 0)
+#define Mvc_CubeBitInsert(Cube, Bit) ((Cube)->pData[Mvc_CubeWhichWord(Bit)] |= (((Mvc_CubeWord_t)1)<<(Mvc_CubeWhichBit(Bit))))
+#define Mvc_CubeBitRemove(Cube, Bit) ((Cube)->pData[Mvc_CubeWhichWord(Bit)] &= ~(((Mvc_CubeWord_t)1)<<(Mvc_CubeWhichBit(Bit))))
+// accessing values of the binary variables
+#define Mvc_CubeVarValue(Cube, Var) (((Cube)->pData[Mvc_CubeWhichWord(2*(Var))] >> (Mvc_CubeWhichBit(2*(Var)))) & ((Mvc_CubeWord_t)3))
+
+// various macros
+
+// cleaning the data bits of the cube
+#define Mvc_Cube1BitClean( Cube )\
+ ((Cube)->pData[0] = 0)
+#define Mvc_Cube2BitClean( Cube )\
+ (((Cube)->pData[0] = 0),\
+ ((Cube)->pData[1] = 0))
+#define Mvc_CubeNBitClean( Cube )\
+{\
+ int _i_;\
+ for( _i_ = (Cube)->iLast; _i_ >= 0; _i_--)\
+ (Cube)->pData[_i_] = 0;\
+}
+
+// cleaning the unused part of the lat word
+#define Mvc_CubeBitCleanUnused( Cube )\
+ ((Cube)->pData[(Cube)->iLast] &= (BITS_FULL >> (Cube)->nUnused))
+
+// filling the used data bits with 1's
+#define Mvc_Cube1BitFill( Cube )\
+ (Cube)->pData[0] = (BITS_FULL >> (Cube)->nUnused);
+#define Mvc_Cube2BitFill( Cube )\
+ (((Cube)->pData[0] = BITS_FULL),\
+ ((Cube)->pData[1] = (BITS_FULL >> (Cube)->nUnused)))
+#define Mvc_CubeNBitFill( Cube )\
+{\
+ int _i_;\
+ (Cube)->pData[(Cube)->iLast] = (BITS_FULL >> (Cube)->nUnused);\
+ for( _i_ = (Cube)->iLast - 1; _i_ >= 0; _i_-- )\
+ (Cube)->pData[_i_] = BITS_FULL;\
+}
+
+// complementing the data bits
+#define Mvc_Cube1BitNot( Cube )\
+ ((Cube)->pData[0] ^= (BITS_FULL >> (Cube)->nUnused))
+#define Mvc_Cube2BitNot( Cube )\
+ (((Cube)->pData[0] ^= BITS_FULL),\
+ ((Cube)->pData[1] ^= (BITS_FULL >> (Cube)->nUnused)))
+#define Mvc_CubeNBitNot( Cube )\
+{\
+ int _i_;\
+ (Cube)->pData[(Cube)->iLast] ^= (BITS_FULL >> (Cube)->nUnused);\
+ for( _i_ = (Cube)->iLast - 1; _i_ >= 0; _i_-- )\
+ (Cube)->pData[_i_] ^= BITS_FULL;\
+}
+
+#define Mvc_Cube1BitCopy( Cube1, Cube2 )\
+ (((Cube1)->pData[0]) = ((Cube2)->pData[0]))
+#define Mvc_Cube2BitCopy( Cube1, Cube2 )\
+ ((((Cube1)->pData[0]) = ((Cube2)->pData[0])),\
+ (((Cube1)->pData[1])= ((Cube2)->pData[1])))
+#define Mvc_CubeNBitCopy( Cube1, Cube2 )\
+{\
+ int _i_;\
+ for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\
+ ((Cube1)->pData[_i_]) = ((Cube2)->pData[_i_]);\
+}
+
+#define Mvc_Cube1BitOr( CubeR, Cube1, Cube2 )\
+ (((CubeR)->pData[0]) = ((Cube1)->pData[0] | (Cube2)->pData[0]))
+#define Mvc_Cube2BitOr( CubeR, Cube1, Cube2 )\
+ ((((CubeR)->pData[0]) = ((Cube1)->pData[0] | (Cube2)->pData[0])),\
+ (((CubeR)->pData[1]) = ((Cube1)->pData[1] | (Cube2)->pData[1])))
+#define Mvc_CubeNBitOr( CubeR, Cube1, Cube2 )\
+{\
+ int _i_;\
+ for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\
+ (((CubeR)->pData[_i_]) = ((Cube1)->pData[_i_] | (Cube2)->pData[_i_]));\
+}
+
+#define Mvc_Cube1BitExor( CubeR, Cube1, Cube2 )\
+ (((CubeR)->pData[0]) = ((Cube1)->pData[0] ^ (Cube2)->pData[0]))
+#define Mvc_Cube2BitExor( CubeR, Cube1, Cube2 )\
+ ((((CubeR)->pData[0]) = ((Cube1)->pData[0] ^ (Cube2)->pData[0])),\
+ (((CubeR)->pData[1]) = ((Cube1)->pData[1] ^ (Cube2)->pData[1])))
+#define Mvc_CubeNBitExor( CubeR, Cube1, Cube2 )\
+{\
+ int _i_;\
+ for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\
+ (((CubeR)->pData[_i_]) = ((Cube1)->pData[_i_] ^ (Cube2)->pData[_i_]));\
+}
+
+#define Mvc_Cube1BitAnd( CubeR, Cube1, Cube2 )\
+ (((CubeR)->pData[0]) = ((Cube1)->pData[0] & (Cube2)->pData[0]))
+#define Mvc_Cube2BitAnd( CubeR, Cube1, Cube2 )\
+ ((((CubeR)->pData[0]) = ((Cube1)->pData[0] & (Cube2)->pData[0])),\
+ (((CubeR)->pData[1]) = ((Cube1)->pData[1] & (Cube2)->pData[1])))
+#define Mvc_CubeNBitAnd( CubeR, Cube1, Cube2 )\
+{\
+ int _i_;\
+ for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\
+ (((CubeR)->pData[_i_]) = ((Cube1)->pData[_i_] & (Cube2)->pData[_i_]));\
+}
+
+#define Mvc_Cube1BitSharp( CubeR, Cube1, Cube2 )\
+ (((CubeR)->pData[0]) = ((Cube1)->pData[0] & ~((Cube2)->pData[0])))
+#define Mvc_Cube2BitSharp( CubeR, Cube1, Cube2 )\
+ ((((CubeR)->pData[0]) = ((Cube1)->pData[0] & ~((Cube2)->pData[0]))),\
+ (((CubeR)->pData[1]) = ((Cube1)->pData[1] & ~((Cube2)->pData[1]))))
+#define Mvc_CubeNBitSharp( CubeR, Cube1, Cube2 )\
+{\
+ int _i_;\
+ for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\
+ (((CubeR)->pData[_i_]) = ((Cube1)->pData[_i_] & ~(Cube2)->pData[_i_]));\
+}
+
+#define Mvc_Cube1BitEmpty( Res, Cube )\
+ (Res = ((Cube)->pData[0] == 0))
+#define Mvc_Cube2BitEmpty( Res, Cube )\
+ (Res = ((Cube)->pData[0] == 0 && (Cube)->pData[1] == 0))
+#define Mvc_CubeNBitEmpty( Res, Cube )\
+{\
+ int _i_; Res = 1;\
+ for (_i_ = (Cube)->iLast; _i_ >= 0; _i_--)\
+ if ( (Cube)->pData[_i_] )\
+ { Res = 0; break; }\
+}
+
+#define Mvc_Cube1BitEqual( Res, Cube1, Cube2 )\
+ (Res = (((Cube1)->pData[0]) == ((Cube2)->pData[0])))
+#define Mvc_Cube2BitEqual( Res, Cube1, Cube2 )\
+ (Res = ((((Cube1)->pData[0]) == ((Cube2)->pData[0])) &&\
+ (((Cube1)->pData[1]) == ((Cube2)->pData[1]))))
+#define Mvc_CubeNBitEqual( Res, Cube1, Cube2 )\
+{\
+ int _i_; Res = 1;\
+ for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\
+ if (((Cube1)->pData[_i_]) != ((Cube2)->pData[_i_]))\
+ { Res = 0; break; }\
+}
+
+#define Mvc_Cube1BitLess( Res, Cube1, Cube2 )\
+ (Res = (((Cube1)->pData[0]) < ((Cube2)->pData[0])))
+#define Mvc_Cube2BitLess( Res, Cube1, Cube2 )\
+ (Res = ((((Cube1)->pData[0]) < ((Cube2)->pData[0])) ||\
+ ((((Cube1)->pData[0]) == ((Cube2)->pData[0])) && (((Cube1)->pData[1]) < ((Cube2)->pData[1])))))
+#define Mvc_CubeNBitLess( Res, Cube1, Cube2 )\
+{\
+ int _i_; Res = 1;\
+ for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\
+ if (((Cube1)->pData[_i_]) >= ((Cube2)->pData[_i_]))\
+ { Res = 0; break; }\
+}
+
+#define Mvc_Cube1BitMore( Res, Cube1, Cube2 )\
+ (Res = (((Cube1)->pData[0]) > ((Cube2)->pData[0])))
+#define Mvc_Cube2BitMore( Res, Cube1, Cube2 )\
+ (Res = ((((Cube1)->pData[0]) > ((Cube2)->pData[0])) ||\
+ ((((Cube1)->pData[0]) == ((Cube2)->pData[0])) && (((Cube1)->pData[1]) > ((Cube2)->pData[1])))))
+#define Mvc_CubeNBitMore( Res, Cube1, Cube2 )\
+{\
+ int _i_; Res = 1;\
+ for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\
+ if (((Cube1)->pData[_i_]) <= ((Cube2)->pData[_i_]))\
+ { Res = 0; break; }\
+}
+
+#define Mvc_Cube1BitNotImpl( Res, Cube1, Cube2 )\
+ (Res = (((Cube1)->pData[0]) & ~((Cube2)->pData[0])))
+#define Mvc_Cube2BitNotImpl( Res, Cube1, Cube2 )\
+ (Res = ((((Cube1)->pData[0]) & ~((Cube2)->pData[0])) ||\
+ (((Cube1)->pData[1]) & ~((Cube2)->pData[1]))))
+#define Mvc_CubeNBitNotImpl( Res, Cube1, Cube2 )\
+{\
+ int _i_; Res = 0;\
+ for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\
+ if (((Cube1)->pData[_i_]) & ~((Cube2)->pData[_i_]))\
+ { Res = 1; break; }\
+}
+
+#define Mvc_Cube1BitDisjoint( Res, Cube1, Cube2 )\
+ (Res = ((((Cube1)->pData[0]) & ((Cube2)->pData[0])) == 0 ))
+#define Mvc_Cube2BitDisjoint( Res, Cube1, Cube2 )\
+ (Res = (((((Cube1)->pData[0]) & ((Cube2)->pData[0])) == 0 ) &&\
+ ((((Cube1)->pData[1]) & ((Cube2)->pData[1])) == 0 )))
+#define Mvc_CubeNBitDisjoint( Res, Cube1, Cube2 )\
+{\
+ int _i_; Res = 1;\
+ for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\
+ if (((Cube1)->pData[_i_]) & ((Cube2)->pData[_i_]))\
+ { Res = 0; break; }\
+}
+
+#define Mvc_Cube1BitEqualUnderMask( Res, Cube1, Cube2, Mask )\
+ (Res = ((((Cube1)->pData[0]) & ((Mask)->pData[0])) == (((Cube2)->pData[0]) & ((Mask)->pData[0]))))
+#define Mvc_Cube2BitEqualUnderMask( Res, Cube1, Cube2, Mask )\
+ (Res = (((((Cube1)->pData[0]) & ((Mask)->pData[0])) == (((Cube2)->pData[0]) & ((Mask)->pData[0]))) &&\
+ ((((Cube1)->pData[1]) & ((Mask)->pData[1])) == (((Cube2)->pData[1]) & ((Mask)->pData[1])))))
+#define Mvc_CubeNBitEqualUnderMask( Res, Cube1, Cube2, Mask )\
+{\
+ int _i_; Res = 1;\
+ for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\
+ if ((((Cube1)->pData[_i_]) & ((Mask)->pData[_i_])) != (((Cube2)->pData[_i_]) & ((Mask)->pData[_i_])))\
+ { Res = 0; break; }\
+}
+
+#define Mvc_Cube1BitEqualOutsideMask( Res, Cube1, Cube2, Mask )\
+ (Res = ((((Cube1)->pData[0]) | ((Mask)->pData[0])) == (((Cube2)->pData[0]) | ((Mask)->pData[0]))))
+#define Mvc_Cube2BitEqualOutsideMask( Res, Cube1, Cube2, Mask )\
+ (Res = (((((Cube1)->pData[0]) | ((Mask)->pData[0])) == (((Cube2)->pData[0]) | ((Mask)->pData[0]))) &&\
+ ((((Cube1)->pData[1]) | ((Mask)->pData[1])) == (((Cube2)->pData[1]) | ((Mask)->pData[1])))))
+#define Mvc_CubeNBitEqualOutsideMask( Res, Cube1, Cube2, Mask )\
+{\
+ int _i_; Res = 1;\
+ for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\
+ if ((((Cube1)->pData[_i_]) | ((Mask)->pData[_i_])) != (((Cube2)->pData[_i_]) | ((Mask)->pData[_i_])))\
+ { Res = 0; break; }\
+}
+
+#define Mvc_Cube1BitIntersectUnderMask( Res, Cube1, Cube2, Mask)\
+ (Res = ((((Cube1)->pData[0]) & ((Cube2)->pData[0]) & ((Mask)->pData[0])) > 0))
+#define Mvc_Cube2BitIntersectUnderMask( Res, Cube1, Cube2, Mask)\
+ (Res = (((((Cube1)->pData[0]) & ((Cube2)->pData[0]) & ((Mask)->pData[0])) > 0) ||\
+ ((((Cube1)->pData[1]) & ((Cube2)->pData[1]) & ((Mask)->pData[1])) > 0)))
+#define Mvc_CubeNBitIntersectUnderMask( Res, Cube1, Cube2, Mask)\
+{\
+ int _i_; Res = 0;\
+ for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\
+ if (((Cube1)->pData[_i_]) & ((Cube2)->pData[_i_]) & ((Mask)->pData[_i_]))\
+ { Res = 1; break; }\
+}
+
+#define Mvc_Cube1BitNotImplUnderMask( Res, Cube1, Cube2, Mask )\
+ (Res = (((Mask)->pData[0]) & ((Cube1)->pData[0]) & ~((Cube2)->pData[0])))
+#define Mvc_Cube2BitNotImplUnderMask( Res, Cube1, Cube2, Mask )\
+ (Res = ((((Mask)->pData[0]) & ((Cube1)->pData[0]) & ~((Cube2)->pData[0])) ||\
+ (((Mask)->pData[1]) & ((Cube1)->pData[1]) & ~((Cube2)->pData[1]))))
+#define Mvc_CubeNBitNotImplUnderMask( Res, Cube1, Cube2, Mask )\
+{\
+ int _i_; Res = 0;\
+ for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\
+ if (((Mask)->pData[_i_]) & ((Cube1)->pData[_i_]) & ~((Cube2)->pData[_i_]))\
+ { Res = 1; break; }\
+}
+
+// the following macros make no assumption about the cube's bitset size
+#define Mvc_CubeBitClean( Cube )\
+ if ( Mvc_Cube1Words(Cube) ) { Mvc_Cube1BitClean( Cube ); }\
+ else if ( Mvc_Cube2Words(Cube) ) { Mvc_Cube2BitClean( Cube ); }\
+ else { Mvc_CubeNBitClean( Cube ); }
+#define Mvc_CubeBitFill( Cube )\
+ if ( Mvc_Cube1Words(Cube) ) { Mvc_Cube1BitFill( Cube ); }\
+ else if ( Mvc_Cube2Words(Cube) ) { Mvc_Cube2BitFill( Cube ); }\
+ else { Mvc_CubeNBitFill( Cube ); }
+#define Mvc_CubeBitNot( Cube )\
+ if ( Mvc_Cube1Words(Cube) ) { Mvc_Cube1BitNot( Cube ); }\
+ else if ( Mvc_Cube2Words(Cube) ) { Mvc_Cube2BitNot( Cube ); }\
+ else { Mvc_CubeNBitNot( Cube ); }
+#define Mvc_CubeBitCopy( Cube1, Cube2 )\
+ if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitCopy( Cube1, Cube2 ); }\
+ else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitCopy( Cube1, Cube2 ); }\
+ else { Mvc_CubeNBitCopy( Cube1, Cube2 ); }
+#define Mvc_CubeBitOr( CubeR, Cube1, Cube2 )\
+ if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitOr( CubeR, Cube1, Cube2 ); }\
+ else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitOr( CubeR, Cube1, Cube2 ); }\
+ else { Mvc_CubeNBitOr( CubeR, Cube1, Cube2 ); }
+#define Mvc_CubeBitExor( CubeR, Cube1, Cube2 )\
+ if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitExor( CubeR, Cube1, Cube2 ); }\
+ else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitExor( CubeR, Cube1, Cube2 ); }\
+ else { Mvc_CubeNBitExor( CubeR, Cube1, Cube2 ); }
+#define Mvc_CubeBitAnd( CubeR, Cube1, Cube2 )\
+ if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitAnd( CubeR, Cube1, Cube2 ); }\
+ else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitAnd( CubeR, Cube1, Cube2 ); }\
+ else { Mvc_CubeNBitAnd( CubeR, Cube1, Cube2 ); }
+#define Mvc_CubeBitSharp( CubeR, Cube1, Cube2 )\
+ if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitSharp( CubeR, Cube1, Cube2 ); }\
+ else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitSharp( CubeR, Cube1, Cube2 ); }\
+ else { Mvc_CubeNBitSharp( CubeR, Cube1, Cube2 ); }
+#define Mvc_CubeBitEmpty( Res, Cube )\
+ if ( Mvc_Cube1Words(Cube) ) { Mvc_Cube1BitEmpty( Res, Cube ); }\
+ else if ( Mvc_Cube2Words(Cube) ) { Mvc_Cube2BitEmpty( Res, Cube ); }\
+ else { Mvc_CubeNBitEmpty( Res, Cube ); }
+#define Mvc_CubeBitEqual( Res, Cube1, Cube2 )\
+ if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitEqual( Res, Cube1, Cube2 ); }\
+ else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitEqual( Res, Cube1, Cube2 ); }\
+ else { Mvc_CubeNBitEqual( Res, Cube1, Cube2 ); }
+#define Mvc_CubeBitLess( Res, Cube1, Cube2 )\
+ if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitLess( Res, Cube1, Cube2 ); }\
+ else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitLess( Res, Cube1, Cube2 ); }\
+ else { Mvc_CubeNBitLess( Res, Cube1, Cube2 ); }
+#define Mvc_CubeBitMore( Res, Cube1, Cube2 )\
+ if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitMore( Res, Cube1, Cube2 ); }\
+ else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitMore( Res, Cube1, Cube2 ); }\
+ else { Mvc_CubeNBitMore( Res, Cube1, Cube2 ); }
+#define Mvc_CubeBitNotImpl( Res, Cube1, Cube2 )\
+ if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitNotImpl( Res, Cube1, Cube2 ); }\
+ else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitNotImpl( Res, Cube1, Cube2 ); }\
+ else { Mvc_CubeNBitNotImpl( Res, Cube1, Cube2 ); }
+#define Mvc_CubeBitDisjoint( Res, Cube1, Cube2 )\
+ if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitDisjoint( Res, Cube1, Cube2 ); }\
+ else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitDisjoint( Res, Cube1, Cube2 ); }\
+ else { Mvc_CubeNBitDisjoint( Res, Cube1, Cube2 ); }
+#define Mvc_CubeBitEqualUnderMask( Res, Cube1, Cube2, Mask )\
+ if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitEqualUnderMask( Res, Cube1, Cube2, Mask ); }\
+ else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitEqualUnderMask( Res, Cube1, Cube2, Mask ); }\
+ else { Mvc_CubeNBitEqualUnderMask( Res, Cube1, Cube2, Mask ); }
+#define Mvc_CubeBitEqualOutsideMask( Res, Cube1, Cube2, Mask )\
+ if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitEqualOutsideMask( Res, Cube1, Cube2, Mask ); }\
+ else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitEqualOutsideMask( Res, Cube1, Cube2, Mask ); }\
+ else { Mvc_CubeNBitEqualOutsideMask( Res, Cube1, Cube2, Mask ); }
+#define Mvc_CubeBitIntersectUnderMask( Res, Cube1, Cube2, Mask )\
+ if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitIntersectUnderMask( Res, Cube1, Cube2, Mask ); }\
+ else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitIntersectUnderMask( Res, Cube1, Cube2, Mask ); }\
+ else { Mvc_CubeNBitIntersectUnderMask( Res, Cube1, Cube2, Mask ); }
+#define Mvc_CubeBitNotImplUnderMask( Res, Cube1, Cube2, Mask )\
+ if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitNotImplUnderMask( Res, Cube1, Cube2, Mask ); }\
+ else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitNotImplUnderMask( Res, Cube1, Cube2, Mask ); }\
+ else { Mvc_CubeNBitNotImplUnderMask( Res, Cube1, Cube2, Mask ); }
+
+
+// managing linked lists
+#define Mvc_ListAddCubeHead( pList, pCube )\
+ {\
+ if ( pList->pHead == NULL )\
+ {\
+ Mvc_CubeSetNext( pCube, NULL );\
+ pList->pHead = pCube;\
+ pList->pTail = pCube;\
+ }\
+ else\
+ {\
+ Mvc_CubeSetNext( pCube, pList->pHead );\
+ pList->pHead = pCube;\
+ }\
+ pList->nItems++;\
+ }
+#define Mvc_ListAddCubeTail( pList, pCube )\
+ {\
+ if ( pList->pHead == NULL )\
+ pList->pHead = pCube;\
+ else\
+ Mvc_CubeSetNext( pList->pTail, pCube );\
+ pList->pTail = pCube;\
+ Mvc_CubeSetNext( pCube, NULL );\
+ pList->nItems++;\
+ }
+#define Mvc_ListDeleteCube( pList, pPrev, pCube )\
+{\
+ if ( pPrev == NULL )\
+ pList->pHead = pCube->pNext;\
+ else\
+ pPrev->pNext = pCube->pNext;\
+ if ( pList->pTail == pCube )\
+ {\
+ assert( pCube->pNext == NULL );\
+ pList->pTail = pPrev;\
+ }\
+ pList->nItems--;\
+}
+
+// managing linked lists inside the cover
+#define Mvc_CoverAddCubeHead( pCover, pCube )\
+{\
+ Mvc_List_t * pList = &pCover->lCubes;\
+ Mvc_ListAddCubeHead( pList, pCube );\
+}
+#define Mvc_CoverAddCubeTail( pCover, pCube )\
+{\
+ Mvc_List_t * pList = &pCover->lCubes;\
+ Mvc_ListAddCubeTail( pList, pCube );\
+}
+#define Mvc_CoverDeleteCube( pCover, pPrev, pCube )\
+{\
+ Mvc_List_t * pList = &pCover->lCubes;\
+ Mvc_ListDeleteCube( pList, pPrev, pCube );\
+}
+
+
+
+
+
+
+// iterator through the cubes in the cube list
+#define Mvc_ListForEachCube( List, Cube )\
+ for ( Cube = List->pHead;\
+ Cube;\
+ Cube = Cube->pNext )
+#define Mvc_ListForEachCubeSafe( List, Cube, Cube2 )\
+ for ( Cube = List->pHead, Cube2 = (Cube? Cube->pNext: NULL);\
+ Cube;\
+ Cube = Cube2, Cube2 = (Cube? Cube->pNext: NULL) )
+
+// iterator through cubes in the cover
+#define Mvc_CoverForEachCube( Cover, Cube )\
+ for ( Cube = (Cover)->lCubes.pHead;\
+ Cube;\
+ Cube = Cube->pNext )
+#define Mvc_CoverForEachCubeWithIndex( Cover, Cube, Index )\
+ for ( Index = 0, Cube = (Cover)->lCubes.pHead;\
+ Cube;\
+ Index++, Cube = Cube->pNext )
+#define Mvc_CoverForEachCubeSafe( Cover, Cube, Cube2 )\
+ for ( Cube = (Cover)->lCubes.pHead, Cube2 = (Cube? Cube->pNext: NULL);\
+ Cube;\
+ Cube = Cube2, Cube2 = (Cube? Cube->pNext: NULL) )
+
+// iterator which starts from the given cube
+#define Mvc_CoverForEachCubeStart( Start, Cube )\
+ for ( Cube = Start;\
+ Cube;\
+ Cube = Cube->pNext )
+#define Mvc_CoverForEachCubeStartSafe( Start, Cube, Cube2 )\
+ for ( Cube = Start, Cube2 = (Cube? Cube->pNext: NULL);\
+ Cube;\
+ Cube = Cube2, Cube2 = (Cube? Cube->pNext: NULL) )
+
+
+// iterator through literals of the cube
+#define Mvc_CubeForEachBit( Cover, Cube, iBit, Value )\
+ for ( iBit = 0;\
+ iBit < Cover->nBits && ((Value = Mvc_CubeBitValue(Cube,iBit))>=0);\
+ iBit++ )
+// iterator through values of binary variables
+#define Mvc_CubeForEachVarValue( Cover, Cube, iVar, Value )\
+ for ( iVar = 0;\
+ iVar < Cover->nBits/2 && (Value = Mvc_CubeVarValue(Cube,iVar));\
+ iVar++ )
+
+
+// macros which work with memory
+// MEM_ALLOC: allocate the given number (Size) of items of type (Type)
+// MEM_FREE: deallocate the pointer (Pointer) to the given number (Size) of items of type (Type)
+#define MEM_ALLOC( Manager, Type, Size ) ((Type *)malloc( (Size) * sizeof(Type) ))
+#define MEM_FREE( Manager, Type, Size, Pointer ) if ( Pointer ) { free(Pointer); Pointer = NULL; }
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== mvcApi.c ====================================================*/
+extern int Mvc_CoverReadWordNum( Mvc_Cover_t * pCover );
+extern int Mvc_CoverReadBitNum( Mvc_Cover_t * pCover );
+extern int Mvc_CoverReadCubeNum( Mvc_Cover_t * pCover );
+extern Mvc_Cube_t * Mvc_CoverReadCubeHead( Mvc_Cover_t * pCover );
+extern Mvc_Cube_t * Mvc_CoverReadCubeTail( Mvc_Cover_t * pCover );
+extern Mvc_List_t * Mvc_CoverReadCubeList( Mvc_Cover_t * pCover );
+extern int Mvc_ListReadCubeNum( Mvc_List_t * pList );
+extern Mvc_Cube_t * Mvc_ListReadCubeHead( Mvc_List_t * pList );
+extern Mvc_Cube_t * Mvc_ListReadCubeTail( Mvc_List_t * pList );
+extern void Mvc_CoverSetCubeNum( Mvc_Cover_t * pCover,int nItems );
+extern void Mvc_CoverSetCubeHead( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube );
+extern void Mvc_CoverSetCubeTail( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube );
+extern void Mvc_CoverSetCubeList( Mvc_Cover_t * pCover, Mvc_List_t * pList );
+extern int Mvc_CoverIsEmpty( Mvc_Cover_t * pCover );
+extern int Mvc_CoverIsTautology( Mvc_Cover_t * pCover );
+extern int Mvc_CoverIsBinaryBuffer( Mvc_Cover_t * pCover );
+extern void Mvc_CoverMakeEmpty( Mvc_Cover_t * pCover );
+extern void Mvc_CoverMakeTautology( Mvc_Cover_t * pCover );
+extern Mvc_Cover_t * Mvc_CoverCreateEmpty( Mvc_Cover_t * pCover );
+extern Mvc_Cover_t * Mvc_CoverCreateTautology( Mvc_Cover_t * pCover );
+/*=== mvcCover.c ====================================================*/
+extern Mvc_Cover_t * Mvc_CoverAlloc( Mvc_Manager_t * pMem, int nBits );
+extern Mvc_Cover_t * Mvc_CoverCreateConst( Mvc_Manager_t * pMem, int nBits, int Phase );
+extern Mvc_Cover_t * Mvc_CoverClone( Mvc_Cover_t * pCover );
+extern Mvc_Cover_t * Mvc_CoverDup( Mvc_Cover_t * pCover );
+extern void Mvc_CoverFree( Mvc_Cover_t * pCover );
+extern void Mvc_CoverAllocateMask( Mvc_Cover_t * pCover );
+extern void Mvc_CoverAllocateArrayLits( Mvc_Cover_t * pCover );
+extern void Mvc_CoverAllocateArrayCubes( Mvc_Cover_t * pCover );
+extern void Mvc_CoverDeallocateMask( Mvc_Cover_t * pCover );
+extern void Mvc_CoverDeallocateArrayLits( Mvc_Cover_t * pCover );
+/*=== mvcCube.c ====================================================*/
+extern Mvc_Cube_t * Mvc_CubeAlloc( Mvc_Cover_t * pCover );
+extern Mvc_Cube_t * Mvc_CubeDup( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube );
+extern void Mvc_CubeFree( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube );
+extern void Mvc_CubeBitRemoveDcs( Mvc_Cube_t * pCube );
+/*=== mvcCompare.c ====================================================*/
+extern int Mvc_CubeCompareInt( Mvc_Cube_t * pC1, Mvc_Cube_t * pC2, Mvc_Cube_t * pMask );
+extern int Mvc_CubeCompareSizeAndInt( Mvc_Cube_t * pC1, Mvc_Cube_t * pC2, Mvc_Cube_t * pMask );
+extern int Mvc_CubeCompareIntUnderMask( Mvc_Cube_t * pC1, Mvc_Cube_t * pC2, Mvc_Cube_t * pMask );
+extern int Mvc_CubeCompareIntOutsideMask( Mvc_Cube_t * pC1, Mvc_Cube_t * pC2, Mvc_Cube_t * pMask );
+extern int Mvc_CubeCompareIntOutsideAndUnderMask( Mvc_Cube_t * pC1, Mvc_Cube_t * pC2, Mvc_Cube_t * pMask );
+/*=== mvcDd.c ====================================================*/
+/*
+extern DdNode * Mvc_CoverConvertToBdd( DdManager * dd, Mvc_Cover_t * pCover );
+extern DdNode * Mvc_CoverConvertToZdd( DdManager * dd, Mvc_Cover_t * pCover );
+extern DdNode * Mvc_CoverConvertToZdd2( DdManager * dd, Mvc_Cover_t * pCover );
+extern DdNode * Mvc_CubeConvertToBdd( DdManager * dd, Mvc_Cube_t * pCube );
+extern DdNode * Mvc_CubeConvertToZdd( DdManager * dd, Mvc_Cube_t * pCube );
+extern DdNode * Mvc_CubeConvertToZdd2( DdManager * dd, Mvc_Cube_t * pCube );
+*/
+/*=== mvcDivisor.c ====================================================*/
+extern Mvc_Cover_t * Mvc_CoverDivisor( Mvc_Cover_t * pCover );
+/*=== mvcDivide.c ====================================================*/
+extern void Mvc_CoverDivide( Mvc_Cover_t * pCover, Mvc_Cover_t * pDiv, Mvc_Cover_t ** ppQuo, Mvc_Cover_t ** ppRem );
+extern void Mvc_CoverDivideInternal( Mvc_Cover_t * pCover, Mvc_Cover_t * pDiv, Mvc_Cover_t ** ppQuo, Mvc_Cover_t ** ppRem );
+extern void Mvc_CoverDivideByLiteral( Mvc_Cover_t * pCover, Mvc_Cover_t * pDiv, Mvc_Cover_t ** ppQuo, Mvc_Cover_t ** ppRem );
+extern void Mvc_CoverDivideByCube( Mvc_Cover_t * pCover, Mvc_Cover_t * pDiv, Mvc_Cover_t ** ppQuo, Mvc_Cover_t ** ppRem );
+extern void Mvc_CoverDivideByLiteralQuo( Mvc_Cover_t * pCover, int iLit );
+/*=== mvcList.c ====================================================*/
+// these functions are available as macros
+extern void Mvc_ListAddCubeHead_( Mvc_List_t * pList, Mvc_Cube_t * pCube );
+extern void Mvc_ListAddCubeTail_( Mvc_List_t * pList, Mvc_Cube_t * pCube );
+extern void Mvc_ListDeleteCube_( Mvc_List_t * pList, Mvc_Cube_t * pPrev, Mvc_Cube_t * pCube );
+extern void Mvc_CoverAddCubeHead_( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube );
+extern void Mvc_CoverAddCubeTail_( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube );
+extern void Mvc_CoverDeleteCube_( Mvc_Cover_t * pCover, Mvc_Cube_t * pPrev, Mvc_Cube_t * pCube );
+extern void Mvc_CoverAddDupCubeHead( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube );
+extern void Mvc_CoverAddDupCubeTail( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube );
+// other functions
+extern void Mvc_CoverAddLiteralsOfCube( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube );
+extern void Mvc_CoverDeleteLiteralsOfCube( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube );
+extern void Mvc_CoverList2Array( Mvc_Cover_t * pCover );
+extern void Mvc_CoverArray2List( Mvc_Cover_t * pCover );
+extern Mvc_Cube_t * Mvc_ListGetTailFromHead( Mvc_Cube_t * pHead );
+/*=== mvcPrint.c ====================================================*/
+extern void Mvc_CoverPrint( Mvc_Cover_t * pCover );
+extern void Mvc_CubePrint( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube );
+extern void Mvc_CoverPrintMv( Mvc_Data_t * pData, Mvc_Cover_t * pCover );
+extern void Mvc_CubePrintMv( Mvc_Data_t * pData, Mvc_Cover_t * pCover, Mvc_Cube_t * pCube );
+/*=== mvcSort.c ====================================================*/
+extern void Mvc_CoverSort( Mvc_Cover_t * pCover, Mvc_Cube_t * pMask, int (* pCompareFunc)(Mvc_Cube_t *, Mvc_Cube_t *, Mvc_Cube_t *) );
+/*=== mvcUtils.c ====================================================*/
+extern void Mvc_CoverSupport( Mvc_Cover_t * pCover, Mvc_Cube_t * pSupp );
+extern int Mvc_CoverSupportSizeBinary( Mvc_Cover_t * pCover );
+extern int Mvc_CoverSupportVarBelongs( Mvc_Cover_t * pCover, int iVar );
+extern void Mvc_CoverCommonCube( Mvc_Cover_t * pCover, Mvc_Cube_t * pComCube );
+extern int Mvc_CoverIsCubeFree( Mvc_Cover_t * pCover );
+extern void Mvc_CoverMakeCubeFree( Mvc_Cover_t * pCover );
+extern Mvc_Cover_t * Mvc_CoverCommonCubeCover( Mvc_Cover_t * pCover );
+extern int Mvc_CoverCheckSuppContainment( Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 );
+extern int Mvc_CoverSetCubeSizes( Mvc_Cover_t * pCover );
+extern int Mvc_CoverGetCubeSize( Mvc_Cube_t * pCube );
+extern int Mvc_CoverCountCubePairDiffs( Mvc_Cover_t * pCover, unsigned char pDiffs[] );
+extern Mvc_Cover_t * Mvc_CoverRemap( Mvc_Cover_t * pCover, int * pVarsRem, int nVarsRem );
+extern void Mvc_CoverInverse( Mvc_Cover_t * pCover );
+extern Mvc_Cover_t * Mvc_CoverRemoveDontCareLits( Mvc_Cover_t * pCover );
+extern Mvc_Cover_t * Mvc_CoverCofactor( Mvc_Cover_t * pCover, int iValue, int iValueOther );
+extern Mvc_Cover_t * Mvc_CoverFlipVar( Mvc_Cover_t * pCover, int iValue0, int iValue1 );
+extern Mvc_Cover_t * Mvc_CoverUnivQuantify( Mvc_Cover_t * p, int iValueA0, int iValueA1, int iValueB0, int iValueB1 );
+extern Mvc_Cover_t ** Mvc_CoverCofactors( Mvc_Data_t * pData, Mvc_Cover_t * pCover, int iVar );
+extern int Mvr_CoverCountLitsWithValue( Mvc_Data_t * pData, Mvc_Cover_t * pCover, int iVar, int iValue );
+//extern Mvc_Cover_t * Mvc_CoverCreateExpanded( Mvc_Cover_t * pCover, Vm_VarMap_t * pVmNew );
+extern Mvc_Cover_t * Mvc_CoverTranspose( Mvc_Cover_t * pCover );
+extern int Mvc_UtilsCheckUnusedZeros( Mvc_Cover_t * pCover );
+/*=== mvcLits.c ====================================================*/
+extern int Mvc_CoverAnyLiteral( Mvc_Cover_t * pCover, Mvc_Cube_t * pMask );
+extern int Mvc_CoverBestLiteral( Mvc_Cover_t * pCover, Mvc_Cube_t * pMask );
+extern int Mvc_CoverWorstLiteral( Mvc_Cover_t * pCover, Mvc_Cube_t * pMask );
+extern Mvc_Cover_t * Mvc_CoverBestLiteralCover( Mvc_Cover_t * pCover, Mvc_Cover_t * pSimple );
+extern int Mvc_CoverFirstCubeFirstLit( Mvc_Cover_t * pCover );
+extern int Mvc_CoverCountLiterals( Mvc_Cover_t * pCover );
+extern int Mvc_CoverIsOneLiteral( Mvc_Cover_t * pCover );
+/*=== mvcOpAlg.c ====================================================*/
+extern Mvc_Cover_t * Mvc_CoverAlgebraicMultiply( Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 );
+extern Mvc_Cover_t * Mvc_CoverAlgebraicSubtract( Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 );
+extern int Mvc_CoverAlgebraicEqual( Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 );
+/*=== mvcOpBool.c ====================================================*/
+extern Mvc_Cover_t * Mvc_CoverBooleanOr( Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 );
+extern Mvc_Cover_t * Mvc_CoverBooleanAnd( Mvc_Data_t * p, Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 );
+extern int Mvc_CoverBooleanEqual( Mvc_Data_t * p, Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 );
+
+/*=== mvcContain.c ====================================================*/
+extern int Mvc_CoverContain( Mvc_Cover_t * pCover );
+/*=== mvcTau.c ====================================================*/
+extern int Mvc_CoverTautology( Mvc_Data_t * p, Mvc_Cover_t * pCover );
+/*=== mvcCompl.c ====================================================*/
+extern Mvc_Cover_t * Mvc_CoverComplement( Mvc_Data_t * p, Mvc_Cover_t * pCover );
+/*=== mvcSharp.c ====================================================*/
+extern Mvc_Cover_t * Mvc_CoverSharp( Mvc_Data_t * p, Mvc_Cover_t * pA, Mvc_Cover_t * pB );
+extern int Mvc_CoverDist0Cubes( Mvc_Data_t * pData, Mvc_Cube_t * pA, Mvc_Cube_t * pB );
+extern void Mvc_CoverIntersectCubes( Mvc_Data_t * pData, Mvc_Cover_t * pC1, Mvc_Cover_t * pC2 );
+extern int Mvc_CoverIsIntersecting( Mvc_Data_t * pData, Mvc_Cover_t * pC1, Mvc_Cover_t * pC2 );
+extern void Mvc_CoverAppendCubes( Mvc_Cover_t * pC1, Mvc_Cover_t * pC2 );
+extern void Mvc_CoverCopyAndAppendCubes( Mvc_Cover_t * pC1, Mvc_Cover_t * pC2 );
+extern void Mvc_CoverRemoveCubes( Mvc_Cover_t * pC );
+
+/*=== mvcReshape.c ====================================================*/
+extern void Mvc_CoverMinimizeByReshape( Mvc_Data_t * pData, Mvc_Cover_t * pCover );
+
+/*=== mvcMerge.c ====================================================*/
+extern void Mvc_CoverDist1Merge( Mvc_Data_t * p, Mvc_Cover_t * pCover );
+
+/*=== mvcData.c ====================================================*/
+//extern Mvc_Data_t * Mvc_CoverDataAlloc( Vm_VarMap_t * pVm, Mvc_Cover_t * pCover );
+//extern void Mvc_CoverDataFree( Mvc_Data_t * p, Mvc_Cover_t * pCover );
+
+/*=== mvcMan.c ====================================================*/
+extern void Mvc_ManagerFree( Mvc_Manager_t * p );
+extern Mvc_Manager_t * Mvc_ManagerStart();
+extern Mvc_Manager_t * Mvc_ManagerAllocCover();
+extern Mvc_Manager_t * Mvc_ManagerAllocCube( int nWords );
+extern Mvc_Manager_t * Mvc_ManagerFreeCover( Mvc_Cover_t * pCover );
+extern Mvc_Manager_t * Mvc_ManagerFreeCube( Mvc_Cover_t * pCube, int nWords );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/src/sop/mvc/mvcApi.c b/src/sop/mvc/mvcApi.c
new file mode 100644
index 00000000..1f51a235
--- /dev/null
+++ b/src/sop/mvc/mvcApi.c
@@ -0,0 +1,233 @@
+/**CFile****************************************************************
+
+ FileName [mvcApi.c]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis []
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - February 1, 2003.]
+
+ Revision [$Id: mvcApi.c,v 1.4 2003/04/03 06:31:48 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mvc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CoverReadWordNum( Mvc_Cover_t * pCover ) { return pCover->nWords; }
+int Mvc_CoverReadBitNum( Mvc_Cover_t * pCover ) { return pCover->nBits; }
+int Mvc_CoverReadCubeNum( Mvc_Cover_t * pCover ) { return pCover->lCubes.nItems; }
+Mvc_Cube_t * Mvc_CoverReadCubeHead( Mvc_Cover_t * pCover ) { return pCover->lCubes.pHead; }
+Mvc_Cube_t * Mvc_CoverReadCubeTail( Mvc_Cover_t * pCover ) { return pCover->lCubes.pTail; }
+Mvc_List_t * Mvc_CoverReadCubeList( Mvc_Cover_t * pCover ) { return &pCover->lCubes; }
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_ListReadCubeNum( Mvc_List_t * pList ) { return pList->nItems; }
+Mvc_Cube_t * Mvc_ListReadCubeHead( Mvc_List_t * pList ) { return pList->pHead; }
+Mvc_Cube_t * Mvc_ListReadCubeTail( Mvc_List_t * pList ) { return pList->pTail; }
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverSetCubeNum( Mvc_Cover_t * pCover,int nItems ) { pCover->lCubes.nItems = nItems; }
+void Mvc_CoverSetCubeHead( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ) { pCover->lCubes.pHead = pCube; }
+void Mvc_CoverSetCubeTail( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ) { pCover->lCubes.pTail = pCube; }
+void Mvc_CoverSetCubeList( Mvc_Cover_t * pCover, Mvc_List_t * pList ) { pCover->lCubes = *pList; }
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CoverIsEmpty( Mvc_Cover_t * pCover )
+{
+ return Mvc_CoverReadCubeNum(pCover) == 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CoverIsTautology( Mvc_Cover_t * pCover )
+{
+ Mvc_Cube_t * pCube;
+ int iBit, Value;
+
+ if ( Mvc_CoverReadCubeNum(pCover) != 1 )
+ return 0;
+
+ pCube = Mvc_CoverReadCubeHead( pCover );
+ Mvc_CubeForEachBit( pCover, pCube, iBit, Value )
+ if ( Value == 0 )
+ return 0;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if the cover is a binary buffer.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CoverIsBinaryBuffer( Mvc_Cover_t * pCover )
+{
+ Mvc_Cube_t * pCube;
+ if ( pCover->nBits != 2 )
+ return 0;
+ if ( Mvc_CoverReadCubeNum(pCover) != 1 )
+ return 0;
+ pCube = pCover->lCubes.pHead;
+ if ( Mvc_CubeBitValue(pCube, 0) == 0 && Mvc_CubeBitValue(pCube, 1) == 1 )
+ return 1;
+ return 0;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverMakeEmpty( Mvc_Cover_t * pCover )
+{
+ Mvc_Cube_t * pCube, * pCube2;
+ Mvc_CoverForEachCubeSafe( pCover, pCube, pCube2 )
+ Mvc_CubeFree( pCover, pCube );
+ pCover->lCubes.nItems = 0;
+ pCover->lCubes.pHead = NULL;
+ pCover->lCubes.pTail = NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverMakeTautology( Mvc_Cover_t * pCover )
+{
+ Mvc_Cube_t * pCubeNew;
+ Mvc_CoverMakeEmpty( pCover );
+ pCubeNew = Mvc_CubeAlloc( pCover );
+ Mvc_CubeBitFill( pCubeNew );
+ Mvc_CoverAddCubeTail( pCover, pCubeNew );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cover_t * Mvc_CoverCreateEmpty( Mvc_Cover_t * pCover )
+{
+ Mvc_Cover_t * pCoverNew;
+ pCoverNew = Mvc_CoverAlloc( pCover->pMem, pCover->nBits );
+ return pCoverNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cover_t * Mvc_CoverCreateTautology( Mvc_Cover_t * pCover )
+{
+ Mvc_Cube_t * pCubeNew;
+ Mvc_Cover_t * pCoverNew;
+ pCoverNew = Mvc_CoverAlloc( pCover->pMem, pCover->nBits );
+ pCubeNew = Mvc_CubeAlloc( pCoverNew );
+ Mvc_CubeBitFill( pCubeNew );
+ Mvc_CoverAddCubeTail( pCoverNew, pCubeNew );
+ return pCoverNew;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sop/mvc/mvcCompare.c b/src/sop/mvc/mvcCompare.c
new file mode 100644
index 00000000..c7999d40
--- /dev/null
+++ b/src/sop/mvc/mvcCompare.c
@@ -0,0 +1,369 @@
+/**CFile****************************************************************
+
+ FileName [mvcCompare.c]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Various cube comparison functions.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - February 1, 2003.]
+
+ Revision [$Id: mvcCompare.c,v 1.5 2003/04/03 23:25:41 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mvc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Compares two cubes according to their integer value.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CubeCompareInt( Mvc_Cube_t * pC1, Mvc_Cube_t * pC2, Mvc_Cube_t * pMask )
+{
+ if ( Mvc_Cube1Words(pC1) )
+ {
+ if ( pC1->pData[0] < pC2->pData[0] )
+ return -1;
+ if ( pC1->pData[0] > pC2->pData[0] )
+ return 1;
+ return 0;
+ }
+ else if ( Mvc_Cube2Words(pC1) )
+ {
+ if ( pC1->pData[1] < pC2->pData[1] )
+ return -1;
+ if ( pC1->pData[1] > pC2->pData[1] )
+ return 1;
+ if ( pC1->pData[0] < pC2->pData[0] )
+ return -1;
+ if ( pC1->pData[0] > pC2->pData[0] )
+ return 1;
+ return 0;
+ }
+ else
+ {
+ int i = Mvc_CubeReadLast(pC1);
+ for(; i >= 0; i--)
+ {
+ if ( pC1->pData[i] < pC2->pData[i] )
+ return -1;
+ if ( pC1->pData[i] > pC2->pData[i] )
+ return 1;
+ }
+ return 0;
+ }
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Compares the cubes (1) by size, (2) by integer value.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CubeCompareSizeAndInt( Mvc_Cube_t * pC1, Mvc_Cube_t * pC2, Mvc_Cube_t * pMask )
+{
+ // compare the cubes by size
+ if ( Mvc_CubeReadSize( pC1 ) < Mvc_CubeReadSize( pC2 ) )
+ return 1;
+ if ( Mvc_CubeReadSize( pC1 ) > Mvc_CubeReadSize( pC2 ) )
+ return -1;
+ // the cubes have the same size
+
+ // compare the cubes as integers
+ if ( Mvc_Cube1Words( pC1 ) )
+ {
+ if ( pC1->pData[0] < pC2->pData[0] )
+ return -1;
+ if ( pC1->pData[0] > pC2->pData[0] )
+ return 1;
+ return 0;
+ }
+ else if ( Mvc_Cube2Words( pC1 ) )
+ {
+ if ( pC1->pData[1] < pC2->pData[1] )
+ return -1;
+ if ( pC1->pData[1] > pC2->pData[1] )
+ return 1;
+ if ( pC1->pData[0] < pC2->pData[0] )
+ return -1;
+ if ( pC1->pData[0] > pC2->pData[0] )
+ return 1;
+ return 0;
+ }
+ else
+ {
+ int i = Mvc_CubeReadLast( pC1 );
+ for(; i >= 0; i--)
+ {
+ if ( pC1->pData[i] < pC2->pData[i] )
+ return -1;
+ if ( pC1->pData[i] > pC2->pData[i] )
+ return 1;
+ }
+ return 0;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares two cubes under the mask.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CubeCompareIntUnderMask( Mvc_Cube_t * pC1, Mvc_Cube_t * pC2, Mvc_Cube_t * pMask )
+{
+ unsigned uBits1, uBits2;
+
+ // compare the cubes under the mask
+ if ( Mvc_Cube1Words(pC1) )
+ {
+ uBits1 = pC1->pData[0] & pMask->pData[0];
+ uBits2 = pC2->pData[0] & pMask->pData[0];
+ if ( uBits1 < uBits2 )
+ return -1;
+ if ( uBits1 > uBits2 )
+ return 1;
+ // cubes are equal
+ return 0;
+ }
+ else if ( Mvc_Cube2Words(pC1) )
+ {
+ uBits1 = pC1->pData[1] & pMask->pData[1];
+ uBits2 = pC2->pData[1] & pMask->pData[1];
+ if ( uBits1 < uBits2 )
+ return -1;
+ if ( uBits1 > uBits2 )
+ return 1;
+ uBits1 = pC1->pData[0] & pMask->pData[0];
+ uBits2 = pC2->pData[0] & pMask->pData[0];
+ if ( uBits1 < uBits2 )
+ return -1;
+ if ( uBits1 > uBits2 )
+ return 1;
+ return 0;
+ }
+ else
+ {
+ int i = Mvc_CubeReadLast(pC1);
+ for(; i >= 0; i--)
+ {
+ uBits1 = pC1->pData[i] & pMask->pData[i];
+ uBits2 = pC2->pData[i] & pMask->pData[i];
+ if ( uBits1 < uBits2 )
+ return -1;
+ if ( uBits1 > uBits2 )
+ return 1;
+ }
+ return 0;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares two cubes under the mask.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CubeCompareIntOutsideMask( Mvc_Cube_t * pC1, Mvc_Cube_t * pC2, Mvc_Cube_t * pMask )
+{
+ unsigned uBits1, uBits2;
+
+ // compare the cubes under the mask
+ if ( Mvc_Cube1Words(pC1) )
+ {
+ uBits1 = pC1->pData[0] | pMask->pData[0];
+ uBits2 = pC2->pData[0] | pMask->pData[0];
+ if ( uBits1 < uBits2 )
+ return -1;
+ if ( uBits1 > uBits2 )
+ return 1;
+ // cubes are equal
+ return 0;
+ }
+ else if ( Mvc_Cube2Words(pC1) )
+ {
+ uBits1 = pC1->pData[1] | pMask->pData[1];
+ uBits2 = pC2->pData[1] | pMask->pData[1];
+ if ( uBits1 < uBits2 )
+ return -1;
+ if ( uBits1 > uBits2 )
+ return 1;
+ uBits1 = pC1->pData[0] | pMask->pData[0];
+ uBits2 = pC2->pData[0] | pMask->pData[0];
+ if ( uBits1 < uBits2 )
+ return -1;
+ if ( uBits1 > uBits2 )
+ return 1;
+ return 0;
+ }
+ else
+ {
+ int i = Mvc_CubeReadLast(pC1);
+ for(; i >= 0; i--)
+ {
+ uBits1 = pC1->pData[i] | pMask->pData[i];
+ uBits2 = pC2->pData[i] | pMask->pData[i];
+ if ( uBits1 < uBits2 )
+ return -1;
+ if ( uBits1 > uBits2 )
+ return 1;
+ }
+ return 0;
+ }
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Compares the cubes (1) outside the mask, (2) under the mask.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CubeCompareIntOutsideAndUnderMask( Mvc_Cube_t * pC1, Mvc_Cube_t * pC2, Mvc_Cube_t * pMask )
+{
+ unsigned uBits1, uBits2;
+
+ if ( Mvc_Cube1Words(pC1) )
+ {
+ // compare the cubes outside the mask
+ uBits1 = pC1->pData[0] & ~(pMask->pData[0]);
+ uBits2 = pC2->pData[0] & ~(pMask->pData[0]);
+ if ( uBits1 < uBits2 )
+ return -1;
+ if ( uBits1 > uBits2 )
+ return 1;
+
+ // compare the cubes under the mask
+ uBits1 = pC1->pData[0] & pMask->pData[0];
+ uBits2 = pC2->pData[0] & pMask->pData[0];
+ if ( uBits1 < uBits2 )
+ return -1;
+ if ( uBits1 > uBits2 )
+ return 1;
+ // cubes are equal
+ // should never happen
+ assert( 0 );
+ return 0;
+ }
+ else if ( Mvc_Cube2Words(pC1) )
+ {
+ // compare the cubes outside the mask
+ uBits1 = pC1->pData[1] & ~(pMask->pData[1]);
+ uBits2 = pC2->pData[1] & ~(pMask->pData[1]);
+ if ( uBits1 < uBits2 )
+ return -1;
+ if ( uBits1 > uBits2 )
+ return 1;
+
+ uBits1 = pC1->pData[0] & ~(pMask->pData[0]);
+ uBits2 = pC2->pData[0] & ~(pMask->pData[0]);
+ if ( uBits1 < uBits2 )
+ return -1;
+ if ( uBits1 > uBits2 )
+ return 1;
+
+ // compare the cubes under the mask
+ uBits1 = pC1->pData[1] & pMask->pData[1];
+ uBits2 = pC2->pData[1] & pMask->pData[1];
+ if ( uBits1 < uBits2 )
+ return -1;
+ if ( uBits1 > uBits2 )
+ return 1;
+
+ uBits1 = pC1->pData[0] & pMask->pData[0];
+ uBits2 = pC2->pData[0] & pMask->pData[0];
+ if ( uBits1 < uBits2 )
+ return -1;
+ if ( uBits1 > uBits2 )
+ return 1;
+
+ // cubes are equal
+ // should never happen
+ assert( 0 );
+ return 0;
+ }
+ else
+ {
+ int i;
+
+ // compare the cubes outside the mask
+ for( i = Mvc_CubeReadLast(pC1); i >= 0; i-- )
+ {
+ uBits1 = pC1->pData[i] & ~(pMask->pData[i]);
+ uBits2 = pC2->pData[i] & ~(pMask->pData[i]);
+ if ( uBits1 < uBits2 )
+ return -1;
+ if ( uBits1 > uBits2 )
+ return 1;
+ }
+ // compare the cubes under the mask
+ for( i = Mvc_CubeReadLast(pC1); i >= 0; i-- )
+ {
+ uBits1 = pC1->pData[i] & pMask->pData[i];
+ uBits2 = pC2->pData[i] & pMask->pData[i];
+ if ( uBits1 < uBits2 )
+ return -1;
+ if ( uBits1 > uBits2 )
+ return 1;
+ }
+/*
+ {
+ Mvc_Cover_t * pCover;
+ pCover = Mvc_CoverAlloc( NULL, 96 );
+ Mvc_CubePrint( pCover, pC1 );
+ Mvc_CubePrint( pCover, pC2 );
+ Mvc_CubePrint( pCover, pMask );
+ }
+*/
+ // cubes are equal
+ // should never happen
+ assert( 0 );
+ return 0;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sop/mvc/mvcContain.c b/src/sop/mvc/mvcContain.c
new file mode 100644
index 00000000..37b933b8
--- /dev/null
+++ b/src/sop/mvc/mvcContain.c
@@ -0,0 +1,173 @@
+/**CFile****************************************************************
+
+ FileName [mvcContain.c]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Making the cover single-cube containment free.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - February 1, 2003.]
+
+ Revision [$Id: mvcContain.c,v 1.4 2003/04/03 23:25:42 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mvc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Mvc_CoverRemoveDuplicates( Mvc_Cover_t * pCover );
+static void Mvc_CoverRemoveContained( Mvc_Cover_t * pCover );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+
+/**Function*************************************************************
+
+ Synopsis [Removes the contained cubes.]
+
+ Description [Returns 1 if the cover has been changed.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CoverContain( Mvc_Cover_t * pCover )
+{
+ int nCubes;
+ nCubes = Mvc_CoverReadCubeNum( pCover );
+ if ( nCubes < 2 )
+ return 0;
+ Mvc_CoverSetCubeSizes(pCover);
+ Mvc_CoverSort( pCover, NULL, Mvc_CubeCompareSizeAndInt );
+ Mvc_CoverRemoveDuplicates( pCover );
+ if ( nCubes > 1 )
+ Mvc_CoverRemoveContained( pCover );
+ return (nCubes != Mvc_CoverReadCubeNum(pCover));
+}
+
+/**Function*************************************************************
+
+ Synopsis [Removes adjacent duplicated cubes from the cube list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverRemoveDuplicates( Mvc_Cover_t * pCover )
+{
+ Mvc_Cube_t * pPrev, * pCube, * pCube2;
+ int fEqual;
+
+ // set the first cube of the cover
+ pPrev = Mvc_CoverReadCubeHead(pCover);
+ // go through all the cubes after this one
+ Mvc_CoverForEachCubeStartSafe( Mvc_CubeReadNext(pPrev), pCube, pCube2 )
+ {
+ // compare the current cube with the prev cube
+ Mvc_CubeBitEqual( fEqual, pPrev, pCube );
+ if ( fEqual )
+ { // they are equal - remove the current cube
+ Mvc_CoverDeleteCube( pCover, pPrev, pCube );
+ Mvc_CubeFree( pCover, pCube );
+ // don't change the previous cube cube
+ }
+ else
+ { // they are not equal - update the previous cube
+ pPrev = pCube;
+ }
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Removes contained cubes from the sorted cube list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverRemoveContained( Mvc_Cover_t * pCover )
+{
+ Mvc_Cube_t * pCubeBeg, * pCubeEnd, * pCubeLarge;
+ Mvc_Cube_t * pCube, * pCube2, * pPrev;
+ unsigned sizeCur;
+ int Result;
+
+ // since the cubes are sorted by size, it is sufficient
+ // to compare each cube with other cubes that have larger sizes
+ // if the given cube implies a larger cube, the larger cube is removed
+ pCubeBeg = Mvc_CoverReadCubeHead(pCover);
+ do
+ {
+ // get the current cube size
+ sizeCur = Mvc_CubeReadSize(pCubeBeg);
+
+ // initialize the end of the given size group
+ pCubeEnd = pCubeBeg;
+ // find the beginning of the next size group
+ Mvc_CoverForEachCubeStart( Mvc_CubeReadNext(pCubeBeg), pCube )
+ {
+ if ( sizeCur == Mvc_CubeReadSize(pCube) )
+ pCubeEnd = pCube;
+ else // pCube is the first cube in the new size group
+ break;
+ }
+ // if we could not find the next size group
+ // the containment check is finished
+ if ( pCube == NULL )
+ break;
+ // otherwise, pCubeBeg/pCubeEnd are the first/last cubes of the group
+
+ // go through all the cubes between pCubeBeg and pCubeEnd, inclusive,
+ // and for each of them, try removing cubes after pCubeEnd
+ Mvc_CoverForEachCubeStart( pCubeBeg, pCubeLarge )
+ {
+ pPrev = pCubeEnd;
+ Mvc_CoverForEachCubeStartSafe( Mvc_CubeReadNext(pCubeEnd), pCube, pCube2 )
+ {
+ // check containment
+ Mvc_CubeBitNotImpl( Result, pCube, pCubeLarge );
+ if ( !Result )
+ { // pCubeLarge implies pCube - remove pCube
+ Mvc_CoverDeleteCube( pCover, pPrev, pCube );
+ Mvc_CubeFree( pCover, pCube );
+ // don't update the previous cube
+ }
+ else
+ { // update the previous cube
+ pPrev = pCube;
+ }
+ }
+ // quit, if the main cube was the last one of this size
+ if ( pCubeLarge == pCubeEnd )
+ break;
+ }
+
+ // set the beginning of the next group
+ pCubeBeg = Mvc_CubeReadNext(pCubeEnd);
+ }
+ while ( pCubeBeg );
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sop/mvc/mvcCover.c b/src/sop/mvc/mvcCover.c
new file mode 100644
index 00000000..bd9c4412
--- /dev/null
+++ b/src/sop/mvc/mvcCover.c
@@ -0,0 +1,251 @@
+/**CFile****************************************************************
+
+ FileName [mvcCover.c]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Basic procedures to manipulate unate cube covers.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - February 1, 2003.]
+
+ Revision [$Id: mvcCover.c,v 1.5 2003/04/09 18:02:05 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mvc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cover_t * Mvc_CoverAlloc( Mvc_Manager_t * pMem, int nBits )
+{
+ Mvc_Cover_t * p;
+ int nBitsInUnsigned;
+
+ nBitsInUnsigned = 8 * sizeof(Mvc_CubeWord_t);
+#ifdef USE_SYSTEM_MEMORY_MANAGEMENT
+ p = (Mvc_Cover_t *)malloc( sizeof(Mvc_Cover_t) );
+#else
+ p = (Mvc_Cover_t *)Extra_MmFixedEntryFetch( pMem->pManC );
+#endif
+ p->pMem = pMem;
+ p->nBits = nBits;
+ p->nWords = nBits / nBitsInUnsigned + (int)(nBits % nBitsInUnsigned > 0);
+ p->nUnused = p->nWords * nBitsInUnsigned - p->nBits;
+ p->lCubes.nItems = 0;
+ p->lCubes.pHead = NULL;
+ p->lCubes.pTail = NULL;
+ p->nCubesAlloc = 0;
+ p->pCubes = NULL;
+ p->pMask = NULL;
+ p->pLits = NULL;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cover_t * Mvc_CoverClone( Mvc_Cover_t * p )
+{
+ Mvc_Cover_t * pCover;
+#ifdef USE_SYSTEM_MEMORY_MANAGEMENT
+ pCover = (Mvc_Cover_t *)malloc( sizeof(Mvc_Cover_t) );
+#else
+ pCover = (Mvc_Cover_t *)Extra_MmFixedEntryFetch( p->pMem->pManC );
+#endif
+ pCover->pMem = p->pMem;
+ pCover->nBits = p->nBits;
+ pCover->nWords = p->nWords;
+ pCover->nUnused = p->nUnused;
+ pCover->lCubes.nItems = 0;
+ pCover->lCubes.pHead = NULL;
+ pCover->lCubes.pTail = NULL;
+ pCover->nCubesAlloc = 0;
+ pCover->pCubes = NULL;
+ pCover->pMask = NULL;
+ pCover->pLits = NULL;
+ return pCover;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cover_t * Mvc_CoverDup( Mvc_Cover_t * p )
+{
+ Mvc_Cover_t * pCover;
+ Mvc_Cube_t * pCube, * pCubeCopy;
+ // clone the cover
+ pCover = Mvc_CoverClone( p );
+ // copy the cube list
+ Mvc_CoverForEachCube( p, pCube )
+ {
+ pCubeCopy = Mvc_CubeDup( p, pCube );
+ Mvc_CoverAddCubeTail( pCover, pCubeCopy );
+ }
+ return pCover;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverFree( Mvc_Cover_t * p )
+{
+ Mvc_Cube_t * pCube, * pCube2;
+ // recycle cube list
+ Mvc_CoverForEachCubeSafe( p, pCube, pCube2 )
+ Mvc_CubeFree( p, pCube );
+ // recycle other pointers
+ Mvc_CubeFree( p, p->pMask );
+ MEM_FREE( p->pMem, Mvc_Cube_t *, p->nCubesAlloc, p->pCubes );
+ MEM_FREE( p->pMem, int, p->nBits, p->pLits );
+
+#ifdef USE_SYSTEM_MEMORY_MANAGEMENT
+ free( p );
+#else
+ Extra_MmFixedEntryRecycle( p->pMem->pManC, (char *)p );
+#endif
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverAllocateMask( Mvc_Cover_t * pCover )
+{
+ if ( pCover->pMask == NULL )
+ pCover->pMask = Mvc_CubeAlloc( pCover );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverAllocateArrayLits( Mvc_Cover_t * pCover )
+{
+ if ( pCover->pLits == NULL )
+ pCover->pLits = MEM_ALLOC( pCover->pMem, int, pCover->nBits );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverAllocateArrayCubes( Mvc_Cover_t * pCover )
+{
+ if ( pCover->nCubesAlloc < pCover->lCubes.nItems )
+ {
+ if ( pCover->nCubesAlloc > 0 )
+ MEM_FREE( pCover->pMem, Mvc_Cube_t *, pCover->nCubesAlloc, pCover->pCubes );
+ pCover->nCubesAlloc = pCover->lCubes.nItems;
+ pCover->pCubes = MEM_ALLOC( pCover->pMem, Mvc_Cube_t *, pCover->nCubesAlloc );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverDeallocateMask( Mvc_Cover_t * pCover )
+{
+ Mvc_CubeFree( pCover, pCover->pMask );
+ pCover->pMask = NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverDeallocateArrayLits( Mvc_Cover_t * pCover )
+{
+ if ( pCover->pLits )
+ {
+ MEM_FREE( pCover->pMem, int, pCover->nBits, pCover->pLits );
+ pCover->pLits = NULL;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sop/mvc/mvcCube.c b/src/sop/mvc/mvcCube.c
new file mode 100644
index 00000000..d02fa270
--- /dev/null
+++ b/src/sop/mvc/mvcCube.c
@@ -0,0 +1,175 @@
+/**CFile****************************************************************
+
+ FileName [mvcCube.c]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Manipulating unate cubes.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - February 1, 2003.]
+
+ Revision [$Id: mvcCube.c,v 1.4 2003/04/03 06:31:49 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mvc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cube_t * Mvc_CubeAlloc( Mvc_Cover_t * pCover )
+{
+ Mvc_Cube_t * pCube;
+
+ assert( pCover->nWords >= 0 );
+ // allocate the cube
+#ifdef USE_SYSTEM_MEMORY_MANAGEMENT
+ if ( pCover->nWords == 0 )
+ pCube = (Mvc_Cube_t *)malloc( sizeof(Mvc_Cube_t) );
+ else
+ pCube = (Mvc_Cube_t *)malloc( sizeof(Mvc_Cube_t) + sizeof(Mvc_CubeWord_t) * (pCover->nWords - 1) );
+#else
+ switch( pCover->nWords )
+ {
+ case 0:
+ case 1:
+ pCube = (Mvc_Cube_t *)Extra_MmFixedEntryFetch( pCover->pMem->pMan1 );
+ break;
+ case 2:
+ pCube = (Mvc_Cube_t *)Extra_MmFixedEntryFetch( pCover->pMem->pMan2 );
+ break;
+ case 3:
+ case 4:
+ pCube = (Mvc_Cube_t *)Extra_MmFixedEntryFetch( pCover->pMem->pMan4 );
+ break;
+ default:
+ pCube = (Mvc_Cube_t *)malloc( sizeof(Mvc_Cube_t) + sizeof(Mvc_CubeWord_t) * (pCover->nWords - 1) );
+ break;
+ }
+#endif
+ // set the parameters charactering this cube
+ if ( pCover->nWords == 0 )
+ pCube->iLast = pCover->nWords;
+ else
+ pCube->iLast = pCover->nWords - 1;
+ pCube->nUnused = pCover->nUnused;
+ return pCube;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cube_t * Mvc_CubeDup( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube )
+{
+ Mvc_Cube_t * pCubeCopy;
+ pCubeCopy = Mvc_CubeAlloc( pCover );
+ Mvc_CubeBitCopy( pCubeCopy, pCube );
+ return pCubeCopy;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CubeFree( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube )
+{
+ if ( pCube == NULL )
+ return;
+
+ // verify the parameters charactering this cube
+ assert( pCube->iLast == 0 || ((int)pCube->iLast) == pCover->nWords - 1 );
+ assert( ((int)pCube->nUnused) == pCover->nUnused );
+
+ // deallocate the cube
+#ifdef USE_SYSTEM_MEMORY_MANAGEMENT
+ free( pCube );
+#else
+ switch( pCover->nWords )
+ {
+ case 0:
+ case 1:
+ Extra_MmFixedEntryRecycle( pCover->pMem->pMan1, (char *)pCube );
+ break;
+ case 2:
+ Extra_MmFixedEntryRecycle( pCover->pMem->pMan2, (char *)pCube );
+ break;
+ case 3:
+ case 4:
+ Extra_MmFixedEntryRecycle( pCover->pMem->pMan4, (char *)pCube );
+ break;
+ default:
+ free( pCube );
+ break;
+ }
+#endif
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Removes the don't-care variable from the cube.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CubeBitRemoveDcs( Mvc_Cube_t * pCube )
+{
+ unsigned Mask;
+ int i;
+ for ( i = Mvc_CubeReadLast(pCube); i >= 0; i-- )
+ {
+ // detect those variables that are different (not DCs)
+ Mask = (pCube->pData[i] ^ (pCube->pData[i] >> 1)) & BITS_DISJOINT;
+ // create the mask of all that are different
+ Mask |= (Mask << 1);
+ // remove other bits from the set
+ pCube->pData[i] &= Mask;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sop/mvc/mvcDivide.c b/src/sop/mvc/mvcDivide.c
new file mode 100644
index 00000000..6aa3d58d
--- /dev/null
+++ b/src/sop/mvc/mvcDivide.c
@@ -0,0 +1,436 @@
+/**CFile****************************************************************
+
+ FileName [mvcDivide.c]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Procedures for algebraic division.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - February 1, 2003.]
+
+ Revision [$Id: mvcDivide.c,v 1.5 2003/04/26 20:41:36 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mvc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Mvc_CoverVerifyDivision( Mvc_Cover_t * pCover, Mvc_Cover_t * pDiv, Mvc_Cover_t * pQuo, Mvc_Cover_t * pRem );
+
+int s_fVerbose = 0;
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverDivide( Mvc_Cover_t * pCover, Mvc_Cover_t * pDiv, Mvc_Cover_t ** ppQuo, Mvc_Cover_t ** ppRem )
+{
+ // check the number of cubes
+ if ( Mvc_CoverReadCubeNum( pCover ) < Mvc_CoverReadCubeNum( pDiv ) )
+ {
+ *ppQuo = NULL;
+ *ppRem = NULL;
+ return;
+ }
+
+ // make sure that support of pCover contains that of pDiv
+ if ( !Mvc_CoverCheckSuppContainment( pCover, pDiv ) )
+ {
+ *ppQuo = NULL;
+ *ppRem = NULL;
+ return;
+ }
+
+ // perform the general division
+ Mvc_CoverDivideInternal( pCover, pDiv, ppQuo, ppRem );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Merge the cubes inside the groups.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverDivideInternal( Mvc_Cover_t * pCover, Mvc_Cover_t * pDiv, Mvc_Cover_t ** ppQuo, Mvc_Cover_t ** ppRem )
+{
+ Mvc_Cover_t * pQuo, * pRem;
+ Mvc_Cube_t * pCubeC, * pCubeD, * pCubeCopy;
+ Mvc_Cube_t * pCube1, * pCube2;
+ int * pGroups, nGroups; // the cube groups
+ int nCubesC, nCubesD, nMerges, iCubeC, iCubeD, iMerge;
+ int fSkipG, GroupSize, g, c, RetValue;
+ int nCubes;
+
+ // get cover sizes
+ nCubesD = Mvc_CoverReadCubeNum( pDiv );
+ nCubesC = Mvc_CoverReadCubeNum( pCover );
+
+ // check trivial cases
+ if ( nCubesD == 1 )
+ {
+ if ( Mvc_CoverIsOneLiteral( pDiv ) )
+ Mvc_CoverDivideByLiteral( pCover, pDiv, ppQuo, ppRem );
+ else
+ Mvc_CoverDivideByCube( pCover, pDiv, ppQuo, ppRem );
+ return;
+ }
+
+ // create the divisor and the remainder
+ pQuo = Mvc_CoverAlloc( pCover->pMem, pCover->nBits );
+ pRem = Mvc_CoverAlloc( pCover->pMem, pCover->nBits );
+
+ // get the support of the divisor
+ Mvc_CoverAllocateMask( pDiv );
+ Mvc_CoverSupport( pDiv, pDiv->pMask );
+
+ // sort the cubes of the divisor
+ Mvc_CoverSort( pDiv, NULL, Mvc_CubeCompareInt );
+ // sort the cubes of the cover
+ Mvc_CoverSort( pCover, pDiv->pMask, Mvc_CubeCompareIntOutsideAndUnderMask );
+
+ // allocate storage for cube groups
+ pGroups = MEM_ALLOC( pCover->pMem, int, nCubesC + 1 );
+
+ // mask contains variables in the support of Div
+ // split the cubes into groups using the mask
+ Mvc_CoverList2Array( pCover );
+ Mvc_CoverList2Array( pDiv );
+ pGroups[0] = 0;
+ nGroups = 1;
+ for ( c = 1; c < nCubesC; c++ )
+ {
+ // get the cubes
+ pCube1 = pCover->pCubes[c-1];
+ pCube2 = pCover->pCubes[c ];
+ // compare the cubes
+ Mvc_CubeBitEqualOutsideMask( RetValue, pCube1, pCube2, pDiv->pMask );
+ if ( !RetValue )
+ pGroups[nGroups++] = c;
+ }
+ // finish off the last group
+ pGroups[nGroups] = nCubesC;
+
+ // consider each group separately and decide
+ // whether it can produce a quotient cube
+ nCubes = 0;
+ for ( g = 0; g < nGroups; g++ )
+ {
+ // if the group has less than nCubesD cubes,
+ // there is no way it can produce the quotient cube
+ // copy the cubes to the remainder
+ GroupSize = pGroups[g+1] - pGroups[g];
+ if ( GroupSize < nCubesD )
+ {
+ for ( c = pGroups[g]; c < pGroups[g+1]; c++ )
+ {
+ pCubeCopy = Mvc_CubeDup( pRem, pCover->pCubes[c] );
+ Mvc_CoverAddCubeTail( pRem, pCubeCopy );
+ nCubes++;
+ }
+ continue;
+ }
+
+ // mark the cubes as those that should be added to the remainder
+ for ( c = pGroups[g]; c < pGroups[g+1]; c++ )
+ Mvc_CubeSetSize( pCover->pCubes[c], 1 );
+
+ // go through the cubes in the group and at the same time
+ // go through the cubes in the divisor
+ iCubeD = 0;
+ iCubeC = 0;
+ pCubeD = pDiv->pCubes[iCubeD++];
+ pCubeC = pCover->pCubes[pGroups[g]+iCubeC++];
+ fSkipG = 0;
+ nMerges = 0;
+
+ while ( 1 )
+ {
+ // compare the topmost cubes in F and in D
+ RetValue = Mvc_CubeCompareIntUnderMask( pCubeC, pCubeD, pDiv->pMask );
+ // cube are ordered in increasing order of their int value
+ if ( RetValue == -1 ) // pCubeC is above pCubeD
+ { // cube in C should be added to the remainder
+ // check that there is enough cubes in the group
+ if ( GroupSize - iCubeC < nCubesD - nMerges )
+ {
+ fSkipG = 1;
+ break;
+ }
+ // get the next cube in the cover
+ pCubeC = pCover->pCubes[pGroups[g]+iCubeC++];
+ continue;
+ }
+ if ( RetValue == 1 ) // pCubeD is above pCubeC
+ { // given cube in D does not have a corresponding cube in the cover
+ fSkipG = 1;
+ break;
+ }
+ // mark the cube as the one that should NOT be added to the remainder
+ Mvc_CubeSetSize( pCubeC, 0 );
+ // remember this merged cube
+ iMerge = iCubeC-1;
+ nMerges++;
+
+ // stop if we considered the last cube of the group
+ if ( iCubeD == nCubesD )
+ break;
+
+ // advance the cube of the divisor
+ assert( iCubeD < nCubesD );
+ pCubeD = pDiv->pCubes[iCubeD++];
+
+ // advance the cube of the group
+ assert( pGroups[g]+iCubeC < nCubesC );
+ pCubeC = pCover->pCubes[pGroups[g]+iCubeC++];
+ }
+
+ if ( fSkipG )
+ {
+ // the group has failed, add all the cubes to the remainder
+ for ( c = pGroups[g]; c < pGroups[g+1]; c++ )
+ {
+ pCubeCopy = Mvc_CubeDup( pRem, pCover->pCubes[c] );
+ Mvc_CoverAddCubeTail( pRem, pCubeCopy );
+ nCubes++;
+ }
+ continue;
+ }
+
+ // the group has worked, add left-over cubes to the remainder
+ for ( c = pGroups[g]; c < pGroups[g+1]; c++ )
+ {
+ pCubeC = pCover->pCubes[c];
+ if ( Mvc_CubeReadSize(pCubeC) )
+ {
+ pCubeCopy = Mvc_CubeDup( pRem, pCubeC );
+ Mvc_CoverAddCubeTail( pRem, pCubeCopy );
+ nCubes++;
+ }
+ }
+
+ // create the quotient cube
+ pCube1 = Mvc_CubeAlloc( pQuo );
+ Mvc_CubeBitSharp( pCube1, pCover->pCubes[pGroups[g]+iMerge], pDiv->pMask );
+ // add the cube to the quotient
+ Mvc_CoverAddCubeTail( pQuo, pCube1 );
+ nCubes += nCubesD;
+ }
+ assert( nCubes == nCubesC );
+
+ // deallocate the memory
+ MEM_FREE( pCover->pMem, int, nCubesC + 1, pGroups );
+
+ // return the results
+ *ppRem = pRem;
+ *ppQuo = pQuo;
+// Mvc_CoverVerifyDivision( pCover, pDiv, pQuo, pRem );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Divides the cover by a cube.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverDivideByCube( Mvc_Cover_t * pCover, Mvc_Cover_t * pDiv, Mvc_Cover_t ** ppQuo, Mvc_Cover_t ** ppRem )
+{
+ Mvc_Cover_t * pQuo, * pRem;
+ Mvc_Cube_t * pCubeC, * pCubeD, * pCubeCopy;
+ int CompResult;
+
+ // get the only cube of D
+ assert( Mvc_CoverReadCubeNum(pDiv) == 1 );
+
+ // start the quotient and the remainder
+ pQuo = Mvc_CoverAlloc( pCover->pMem, pCover->nBits );
+ pRem = Mvc_CoverAlloc( pCover->pMem, pCover->nBits );
+
+ // get the first and only cube of the divisor
+ pCubeD = Mvc_CoverReadCubeHead( pDiv );
+
+ // iterate through the cubes in the cover
+ Mvc_CoverForEachCube( pCover, pCubeC )
+ {
+ // check the containment of literals from pCubeD in pCube
+ Mvc_Cube2BitNotImpl( CompResult, pCubeD, pCubeC );
+ if ( !CompResult )
+ { // this cube belongs to the quotient
+ // alloc the cube
+ pCubeCopy = Mvc_CubeAlloc( pQuo );
+ // clean the support of D
+ Mvc_CubeBitSharp( pCubeCopy, pCubeC, pCubeD );
+ // add the cube to the quotient
+ Mvc_CoverAddCubeTail( pQuo, pCubeCopy );
+ }
+ else
+ {
+ // copy the cube
+ pCubeCopy = Mvc_CubeDup( pRem, pCubeC );
+ // add the cube to the remainder
+ Mvc_CoverAddCubeTail( pRem, pCubeCopy );
+ }
+ }
+ // return the results
+ *ppRem = pRem;
+ *ppQuo = pQuo;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Divides the cover by a literal.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverDivideByLiteral( Mvc_Cover_t * pCover, Mvc_Cover_t * pDiv, Mvc_Cover_t ** ppQuo, Mvc_Cover_t ** ppRem )
+{
+ Mvc_Cover_t * pQuo, * pRem;
+ Mvc_Cube_t * pCubeC, * pCubeCopy;
+ int iLit;
+
+ // get the only cube of D
+ assert( Mvc_CoverReadCubeNum(pDiv) == 1 );
+
+ // start the quotient and the remainder
+ pQuo = Mvc_CoverAlloc( pCover->pMem, pCover->nBits );
+ pRem = Mvc_CoverAlloc( pCover->pMem, pCover->nBits );
+
+ // get the first and only literal in the divisor cube
+ iLit = Mvc_CoverFirstCubeFirstLit( pDiv );
+
+ // iterate through the cubes in the cover
+ Mvc_CoverForEachCube( pCover, pCubeC )
+ {
+ // copy the cube
+ pCubeCopy = Mvc_CubeDup( pCover, pCubeC );
+ // add the cube to the quotient or to the remainder depending on the literal
+ if ( Mvc_CubeBitValue( pCubeCopy, iLit ) )
+ { // remove the literal
+ Mvc_CubeBitRemove( pCubeCopy, iLit );
+ // add the cube ot the quotient
+ Mvc_CoverAddCubeTail( pQuo, pCubeCopy );
+ }
+ else
+ { // add the cube ot the remainder
+ Mvc_CoverAddCubeTail( pRem, pCubeCopy );
+ }
+ }
+ // return the results
+ *ppRem = pRem;
+ *ppQuo = pQuo;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Derives the quotient of division by literal.]
+
+ Description [Reduces the cover to be the equal to the result of
+ division of the given cover by the literal.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverDivideByLiteralQuo( Mvc_Cover_t * pCover, int iLit )
+{
+ Mvc_Cube_t * pCube, * pCube2, * pPrev;
+ // delete those cubes that do not have this literal
+ // remove this literal from other cubes
+ pPrev = NULL;
+ Mvc_CoverForEachCubeSafe( pCover, pCube, pCube2 )
+ {
+ if ( Mvc_CubeBitValue( pCube, iLit ) == 0 )
+ { // delete the cube from the cover
+ Mvc_CoverDeleteCube( pCover, pPrev, pCube );
+ Mvc_CubeFree( pCover, pCube );
+ // don't update the previous cube
+ }
+ else
+ { // delete this literal from the cube
+ Mvc_CubeBitRemove( pCube, iLit );
+ // update the previous cube
+ pPrev = pCube;
+ }
+ }
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Verifies that the result of algebraic division is correct.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverVerifyDivision( Mvc_Cover_t * pCover, Mvc_Cover_t * pDiv, Mvc_Cover_t * pQuo, Mvc_Cover_t * pRem )
+{
+ Mvc_Cover_t * pProd;
+ Mvc_Cover_t * pDiff;
+
+ pProd = Mvc_CoverAlgebraicMultiply( pDiv, pQuo );
+ pDiff = Mvc_CoverAlgebraicSubtract( pCover, pProd );
+
+ if ( Mvc_CoverAlgebraicEqual( pDiff, pRem ) )
+ printf( "Verification OKAY!\n" );
+ else
+ {
+ printf( "Verification FAILED!\n" );
+ printf( "pCover:\n" );
+ Mvc_CoverPrint( pCover );
+ printf( "pDiv:\n" );
+ Mvc_CoverPrint( pDiv );
+ printf( "pRem:\n" );
+ Mvc_CoverPrint( pRem );
+ printf( "pQuo:\n" );
+ Mvc_CoverPrint( pQuo );
+ }
+
+ Mvc_CoverFree( pProd );
+ Mvc_CoverFree( pDiff );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sop/mvc/mvcDivisor.c b/src/sop/mvc/mvcDivisor.c
new file mode 100644
index 00000000..e92c3a65
--- /dev/null
+++ b/src/sop/mvc/mvcDivisor.c
@@ -0,0 +1,90 @@
+/**CFile****************************************************************
+
+ FileName [mvcDivisor.c]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Procedures for compute the quick divisor.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - February 1, 2003.]
+
+ Revision [$Id: mvcDivisor.c,v 1.1 2003/04/03 15:34:08 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mvc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Mvc_CoverDivisorZeroKernel( Mvc_Cover_t * pCover );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Returns the quick divisor of the cover.]
+
+ Description [Returns NULL, if there is not divisor other than
+ trivial.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cover_t * Mvc_CoverDivisor( Mvc_Cover_t * pCover )
+{
+ Mvc_Cover_t * pKernel;
+ if ( Mvc_CoverReadCubeNum(pCover) <= 1 )
+ return NULL;
+ // allocate the literal array and count literals
+ if ( Mvc_CoverAnyLiteral( pCover, NULL ) == -1 )
+ return NULL;
+ // duplicate the cover
+ pKernel = Mvc_CoverDup(pCover);
+ // perform the kerneling
+ Mvc_CoverDivisorZeroKernel( pKernel );
+ assert( Mvc_CoverReadCubeNum(pKernel) );
+ return pKernel;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes a level-zero kernel.]
+
+ Description [Modifies the cover to contain one level-zero kernel.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverDivisorZeroKernel( Mvc_Cover_t * pCover )
+{
+ int iLit;
+ // find any literal that occurs at least two times
+// iLit = Mvc_CoverAnyLiteral( pCover, NULL );
+ iLit = Mvc_CoverWorstLiteral( pCover, NULL );
+// iLit = Mvc_CoverBestLiteral( pCover, NULL );
+ if ( iLit == -1 )
+ return;
+ // derive the cube-free quotient
+ Mvc_CoverDivideByLiteralQuo( pCover, iLit ); // the same cover
+ Mvc_CoverMakeCubeFree( pCover ); // the same cover
+ // call recursively
+ Mvc_CoverDivisorZeroKernel( pCover ); // the same cover
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sop/mvc/mvcList.c b/src/sop/mvc/mvcList.c
new file mode 100644
index 00000000..678ae9fd
--- /dev/null
+++ b/src/sop/mvc/mvcList.c
@@ -0,0 +1,362 @@
+/**CFile****************************************************************
+
+ FileName [mvcList.c]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Manipulating list of cubes in the cover.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - February 1, 2003.]
+
+ Revision [$Id: mvcList.c,v 1.4 2003/04/03 06:31:50 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mvc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_ListAddCubeHead_( Mvc_List_t * pList, Mvc_Cube_t * pCube )
+{
+ if ( pList->pHead == NULL )
+ {
+ Mvc_CubeSetNext( pCube, NULL );
+ pList->pHead = pCube;
+ pList->pTail = pCube;
+ }
+ else
+ {
+ Mvc_CubeSetNext( pCube, pList->pHead );
+ pList->pHead = pCube;
+ }
+ pList->nItems++;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_ListAddCubeTail_( Mvc_List_t * pList, Mvc_Cube_t * pCube )
+{
+ if ( pList->pHead == NULL )
+ pList->pHead = pCube;
+ else
+ Mvc_CubeSetNext( pList->pTail, pCube );
+ pList->pTail = pCube;
+ Mvc_CubeSetNext( pCube, NULL );
+ pList->nItems++;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_ListDeleteCube_( Mvc_List_t * pList, Mvc_Cube_t * pPrev, Mvc_Cube_t * pCube )
+{
+ if ( pPrev == NULL ) // deleting the head cube
+ pList->pHead = Mvc_CubeReadNext(pCube);
+ else
+ pPrev->pNext = pCube->pNext;
+ if ( pList->pTail == pCube ) // deleting the tail cube
+ {
+ assert( Mvc_CubeReadNext(pCube) == NULL );
+ pList->pTail = pPrev;
+ }
+ pList->nItems--;
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverAddCubeHead_( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube )
+{
+ Mvc_List_t * pList = &pCover->lCubes;
+ if ( pList->pHead == NULL )
+ {
+ Mvc_CubeSetNext( pCube, NULL );
+ pList->pHead = pCube;
+ pList->pTail = pCube;
+ }
+ else
+ {
+ Mvc_CubeSetNext( pCube, pList->pHead );
+ pList->pHead = pCube;
+ }
+ pList->nItems++;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverAddCubeTail_( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube )
+{
+ Mvc_List_t * pList = &pCover->lCubes;
+
+ if ( pList->pHead == NULL )
+ pList->pHead = pCube;
+ else
+ Mvc_CubeSetNext( pList->pTail, pCube );
+ pList->pTail = pCube;
+ Mvc_CubeSetNext( pCube, NULL );
+ pList->nItems++;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverDeleteCube_( Mvc_Cover_t * pCover, Mvc_Cube_t * pPrev, Mvc_Cube_t * pCube )
+{
+ Mvc_List_t * pList = &pCover->lCubes;
+
+ if ( pPrev == NULL ) // deleting the head cube
+ pList->pHead = Mvc_CubeReadNext(pCube);
+ else
+ pPrev->pNext = pCube->pNext;
+ if ( pList->pTail == pCube ) // deleting the tail cube
+ {
+ assert( Mvc_CubeReadNext(pCube) == NULL );
+ pList->pTail = pPrev;
+ }
+ pList->nItems--;
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverAddDupCubeHead( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube )
+{
+ Mvc_Cube_t * pCubeNew;
+ pCubeNew = Mvc_CubeAlloc( pCover );
+ Mvc_CubeBitCopy( pCubeNew, pCube );
+ Mvc_CoverAddCubeHead( pCover, pCubeNew );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverAddDupCubeTail( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube )
+{
+ Mvc_Cube_t * pCubeNew;
+ // copy the cube as part of this cover
+ pCubeNew = Mvc_CubeAlloc( pCover );
+ Mvc_CubeBitCopy( pCubeNew, pCube );
+ // clean the last bits of the new cube
+// pCubeNew->pData[pCubeNew->iLast] &= (BITS_FULL >> pCubeNew->nUnused);
+ // add the cube at the end
+ Mvc_CoverAddCubeTail( pCover, pCubeNew );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverAddLiteralsOfCube( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube )
+{
+// int iBit, Value;
+// assert( pCover->pLits );
+// Mvc_CubeForEachBit( pCover, pCube, iBit, Value )
+// if ( Value )
+// pCover->pLits[iBit] += Value;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverDeleteLiteralsOfCube( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube )
+{
+// int iBit, Value;
+// assert( pCover->pLits );
+// Mvc_CubeForEachBit( pCover, pCube, iBit, Value )
+// if ( Value )
+// pCover->pLits[iBit] -= Value;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Transfers the cubes from the list into the array.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverList2Array( Mvc_Cover_t * pCover )
+{
+ Mvc_Cube_t * pCube;
+ int Counter;
+ // resize storage if necessary
+ Mvc_CoverAllocateArrayCubes( pCover );
+ // iterate through the cubes
+ Counter = 0;
+ Mvc_CoverForEachCube( pCover, pCube )
+ pCover->pCubes[ Counter++ ] = pCube;
+ assert( Counter == Mvc_CoverReadCubeNum(pCover) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Transfers the cubes from the array into list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverArray2List( Mvc_Cover_t * pCover )
+{
+ Mvc_Cube_t * pCube;
+ int nCubes, i;
+
+ assert( pCover->pCubes );
+
+ nCubes = Mvc_CoverReadCubeNum(pCover);
+ if ( nCubes == 0 )
+ return;
+ if ( nCubes == 1 )
+ {
+ pCube = pCover->pCubes[0];
+ pCube->pNext = NULL;
+ pCover->lCubes.pHead = pCover->lCubes.pTail = pCube;
+ return;
+ }
+ // set up the first cube
+ pCube = pCover->pCubes[0];
+ pCover->lCubes.pHead = pCube;
+ // set up the last cube
+ pCube = pCover->pCubes[nCubes-1];
+ pCube->pNext = NULL;
+ pCover->lCubes.pTail = pCube;
+
+ // link all cubes starting from the first one
+ for ( i = 0; i < nCubes - 1; i++ )
+ pCover->pCubes[i]->pNext = pCover->pCubes[i+1];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the tail of the linked list given by the head.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cube_t * Mvc_ListGetTailFromHead( Mvc_Cube_t * pHead )
+{
+ Mvc_Cube_t * pCube, * pTail;
+ for ( pTail = pCube = pHead;
+ pCube;
+ pTail = pCube, pCube = Mvc_CubeReadNext(pCube) );
+ return pTail;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sop/mvc/mvcLits.c b/src/sop/mvc/mvcLits.c
new file mode 100644
index 00000000..98211719
--- /dev/null
+++ b/src/sop/mvc/mvcLits.c
@@ -0,0 +1,345 @@
+/**CFile****************************************************************
+
+ FileName [mvcLits.c]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Literal counting/updating procedures.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - February 1, 2003.]
+
+ Revision [$Id: mvcLits.c,v 1.4 2003/04/03 06:31:50 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mvc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Find the any literal that occurs more than once.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CoverAnyLiteral( Mvc_Cover_t * pCover, Mvc_Cube_t * pMask )
+{
+ Mvc_Cube_t * pCube;
+ int nWord, nBit, i;
+ int nLitsCur;
+ int fUseFirst = 0;
+
+ // go through each literal
+ if ( fUseFirst )
+ {
+ for ( i = 0; i < pCover->nBits; i++ )
+ if ( !pMask || Mvc_CubeBitValue(pMask,i) )
+ {
+ // get the word and bit of this literal
+ nWord = Mvc_CubeWhichWord(i);
+ nBit = Mvc_CubeWhichBit(i);
+ // go through all the cubes
+ nLitsCur = 0;
+ Mvc_CoverForEachCube( pCover, pCube )
+ if ( pCube->pData[nWord] & (1<<nBit) )
+ {
+ nLitsCur++;
+ if ( nLitsCur > 1 )
+ return i;
+ }
+ }
+ }
+ else
+ {
+ for ( i = pCover->nBits - 1; i >=0; i-- )
+ if ( !pMask || Mvc_CubeBitValue(pMask,i) )
+ {
+ // get the word and bit of this literal
+ nWord = Mvc_CubeWhichWord(i);
+ nBit = Mvc_CubeWhichBit(i);
+ // go through all the cubes
+ nLitsCur = 0;
+ Mvc_CoverForEachCube( pCover, pCube )
+ if ( pCube->pData[nWord] & (1<<nBit) )
+ {
+ nLitsCur++;
+ if ( nLitsCur > 1 )
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Find the most often occurring literal.]
+
+ Description [Find the most often occurring literal among those
+ that occur more than once.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CoverBestLiteral( Mvc_Cover_t * pCover, Mvc_Cube_t * pMask )
+{
+ Mvc_Cube_t * pCube;
+ int nWord, nBit;
+ int i, iMax, nLitsMax, nLitsCur;
+ int fUseFirst = 1;
+
+ // go through each literal
+ iMax = -1;
+ nLitsMax = -1;
+ for ( i = 0; i < pCover->nBits; i++ )
+ if ( !pMask || Mvc_CubeBitValue(pMask,i) )
+ {
+ // get the word and bit of this literal
+ nWord = Mvc_CubeWhichWord(i);
+ nBit = Mvc_CubeWhichBit(i);
+ // go through all the cubes
+ nLitsCur = 0;
+ Mvc_CoverForEachCube( pCover, pCube )
+ if ( pCube->pData[nWord] & (1<<nBit) )
+ nLitsCur++;
+
+ // check if this is the best literal
+ if ( fUseFirst )
+ {
+ if ( nLitsMax < nLitsCur )
+ {
+ nLitsMax = nLitsCur;
+ iMax = i;
+ }
+ }
+ else
+ {
+ if ( nLitsMax <= nLitsCur )
+ {
+ nLitsMax = nLitsCur;
+ iMax = i;
+ }
+ }
+ }
+
+ if ( nLitsMax > 1 )
+ return iMax;
+ return -1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Find the most often occurring literal.]
+
+ Description [Find the most often occurring literal among those
+ that occur more than once.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CoverWorstLiteral( Mvc_Cover_t * pCover, Mvc_Cube_t * pMask )
+{
+ Mvc_Cube_t * pCube;
+ int nWord, nBit;
+ int i, iMin, nLitsMin, nLitsCur;
+ int fUseFirst = 1;
+
+ // go through each literal
+ iMin = -1;
+ nLitsMin = 1000000;
+ for ( i = 0; i < pCover->nBits; i++ )
+ if ( !pMask || Mvc_CubeBitValue(pMask,i) )
+ {
+ // get the word and bit of this literal
+ nWord = Mvc_CubeWhichWord(i);
+ nBit = Mvc_CubeWhichBit(i);
+ // go through all the cubes
+ nLitsCur = 0;
+ Mvc_CoverForEachCube( pCover, pCube )
+ if ( pCube->pData[nWord] & (1<<nBit) )
+ nLitsCur++;
+
+ // skip the literal that does not occur or occurs once
+ if ( nLitsCur < 2 )
+ continue;
+
+ // check if this is the best literal
+ if ( fUseFirst )
+ {
+ if ( nLitsMin > nLitsCur )
+ {
+ nLitsMin = nLitsCur;
+ iMin = i;
+ }
+ }
+ else
+ {
+ if ( nLitsMin >= nLitsCur )
+ {
+ nLitsMin = nLitsCur;
+ iMin = i;
+ }
+ }
+ }
+
+ if ( nLitsMin < 1000000 )
+ return iMin;
+ return -1;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cover_t * Mvc_CoverBestLiteralCover( Mvc_Cover_t * pCover, Mvc_Cover_t * pSimple )
+{
+ Mvc_Cover_t * pCoverNew;
+ Mvc_Cube_t * pCubeNew;
+ Mvc_Cube_t * pCubeS;
+ int iLitBest;
+
+ // create the new cover
+ pCoverNew = Mvc_CoverClone( pCover );
+ // get the new cube
+ pCubeNew = Mvc_CubeAlloc( pCoverNew );
+ // clean the cube
+ Mvc_CubeBitClean( pCubeNew );
+
+ // get the first cube of pSimple
+ assert( Mvc_CoverReadCubeNum(pSimple) == 1 );
+ pCubeS = Mvc_CoverReadCubeHead( pSimple );
+ // find the best literal among those of pCubeS
+ iLitBest = Mvc_CoverBestLiteral( pCover, pCubeS );
+
+ // insert this literal into the cube
+ Mvc_CubeBitInsert( pCubeNew, iLitBest );
+ // add the cube to the cover
+ Mvc_CoverAddCubeTail( pCoverNew, pCubeNew );
+ return pCoverNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CoverFirstCubeFirstLit( Mvc_Cover_t * pCover )
+{
+ Mvc_Cube_t * pCube;
+ int iBit, Value;
+
+ // get the first cube
+ pCube = Mvc_CoverReadCubeHead( pCover );
+ // get the first literal
+ Mvc_CubeForEachBit( pCover, pCube, iBit, Value )
+ if ( Value )
+ return iBit;
+ return -1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the number of literals in the cover.]
+
+ Description [Allocates storage for literal counters and fills it up
+ using the current information.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CoverCountLiterals( Mvc_Cover_t * pCover )
+{
+ Mvc_Cube_t * pCube;
+ int nWord, nBit;
+ int i, CounterTot, CounterCur;
+
+ // allocate/clean the storage for literals
+// Mvc_CoverAllocateArrayLits( pCover );
+// memset( pCover->pLits, 0, pCover->nBits * sizeof(int) );
+ // go through each literal
+ CounterTot = 0;
+ for ( i = 0; i < pCover->nBits; i++ )
+ {
+ // get the word and bit of this literal
+ nWord = Mvc_CubeWhichWord(i);
+ nBit = Mvc_CubeWhichBit(i);
+ // go through all the cubes
+ CounterCur = 0;
+ Mvc_CoverForEachCube( pCover, pCube )
+ if ( pCube->pData[nWord] & (1<<nBit) )
+ CounterCur++;
+ CounterTot += CounterCur;
+ }
+ return CounterTot;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the number of literals in the cover.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CoverIsOneLiteral( Mvc_Cover_t * pCover )
+{
+ Mvc_Cube_t * pCube;
+ int iBit, Counter, Value;
+ if ( Mvc_CoverReadCubeNum(pCover) != 1 )
+ return 0;
+ pCube = Mvc_CoverReadCubeHead(pCover);
+ // count literals
+ Counter = 0;
+ Mvc_CubeForEachBit( pCover, pCube, iBit, Value )
+ {
+ if ( Value )
+ {
+ if ( Counter++ )
+ return 0;
+ }
+ }
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sop/mvc/mvcMan.c b/src/sop/mvc/mvcMan.c
new file mode 100644
index 00000000..f2943e0c
--- /dev/null
+++ b/src/sop/mvc/mvcMan.c
@@ -0,0 +1,77 @@
+/**CFile****************************************************************
+
+ FileName [mvcMan.c]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Procedures working with the MVC memory manager.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - February 1, 2003.]
+
+ Revision [$Id: mvcMan.c,v 1.3 2003/03/19 19:50:26 alanmi Exp $]
+
+***********************************************************************/
+
+#include <string.h>
+#include "mvc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Manager_t * Mvc_ManagerStart()
+{
+ Mvc_Manager_t * p;
+ p = ALLOC( Mvc_Manager_t, 1 );
+ memset( p, 0, sizeof(Mvc_Manager_t) );
+ p->pMan1 = Extra_MmFixedStart( sizeof(Mvc_Cube_t) );
+ p->pMan2 = Extra_MmFixedStart( sizeof(Mvc_Cube_t) + sizeof(Mvc_CubeWord_t) );
+ p->pMan4 = Extra_MmFixedStart( sizeof(Mvc_Cube_t) + 3 * sizeof(Mvc_CubeWord_t) );
+ p->pManC = Extra_MmFixedStart( sizeof(Mvc_Cover_t) );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_ManagerFree( Mvc_Manager_t * p )
+{
+ Extra_MmFixedStop( p->pMan1, 0 );
+ Extra_MmFixedStop( p->pMan2, 0 );
+ Extra_MmFixedStop( p->pMan4, 0 );
+ Extra_MmFixedStop( p->pManC, 0 );
+ free( p );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sop/mvc/mvcOpAlg.c b/src/sop/mvc/mvcOpAlg.c
new file mode 100644
index 00000000..befccb70
--- /dev/null
+++ b/src/sop/mvc/mvcOpAlg.c
@@ -0,0 +1,163 @@
+/**CFile****************************************************************
+
+ FileName [mvcOperAlg.c]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Miscellaneous operations on covers.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - February 1, 2003.]
+
+ Revision [$Id: mvcOpAlg.c,v 1.4 2003/04/26 20:41:36 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mvc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Multiplies two disjoint-support covers.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cover_t * Mvc_CoverAlgebraicMultiply( Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 )
+{
+ Mvc_Cover_t * pCover;
+ Mvc_Cube_t * pCube1, * pCube2, * pCube;
+ int CompResult;
+
+ // covers should be the same base
+ assert( pCover1->nBits == pCover2->nBits );
+ // make sure that supports do not overlap
+ Mvc_CoverAllocateMask( pCover1 );
+ Mvc_CoverAllocateMask( pCover2 );
+ Mvc_CoverSupport( pCover1, pCover1->pMask );
+ Mvc_CoverSupport( pCover2, pCover2->pMask );
+ // check if the cubes are bit-wise disjoint
+ Mvc_CubeBitDisjoint( CompResult, pCover1->pMask, pCover2->pMask );
+ if ( !CompResult )
+ printf( "Mvc_CoverMultiply(): Cover supports are not disjoint!\n" );
+
+ // iterate through the cubes
+ pCover = Mvc_CoverClone( pCover1 );
+ Mvc_CoverForEachCube( pCover1, pCube1 )
+ Mvc_CoverForEachCube( pCover2, pCube2 )
+ {
+ // create the product cube
+ pCube = Mvc_CubeAlloc( pCover );
+ // set the product cube equal to the product of the two cubes
+ Mvc_CubeBitOr( pCube, pCube1, pCube2 );
+ // add the cube to the cover
+ Mvc_CoverAddCubeTail( pCover, pCube );
+ }
+ return pCover;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Subtracts the second cover from the first.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cover_t * Mvc_CoverAlgebraicSubtract( Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 )
+{
+ Mvc_Cover_t * pCover;
+ Mvc_Cube_t * pCube1, * pCube2, * pCube;
+ int fFound;
+ int CompResult;
+
+ // covers should be the same base
+ assert( pCover1->nBits == pCover2->nBits );
+
+ // iterate through the cubes
+ pCover = Mvc_CoverClone( pCover1 );
+ Mvc_CoverForEachCube( pCover1, pCube1 )
+ {
+ fFound = 0;
+ Mvc_CoverForEachCube( pCover2, pCube2 )
+ {
+ Mvc_CubeBitEqual( CompResult, pCube1, pCube2 );
+ if ( CompResult )
+ {
+ fFound = 1;
+ break;
+ }
+ }
+ if ( !fFound )
+ {
+ // create the copy of the cube
+ pCube = Mvc_CubeDup( pCover, pCube1 );
+ // add the cube copy to the cover
+ Mvc_CoverAddCubeTail( pCover, pCube );
+ }
+ }
+ return pCover;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CoverAlgebraicEqual( Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 )
+{
+ Mvc_Cube_t * pCube1, * pCube2;
+ int fFound;
+ int CompResult;
+
+ // covers should be the same base
+ assert( pCover1->nBits == pCover2->nBits );
+ // iterate through the cubes
+ Mvc_CoverForEachCube( pCover1, pCube1 )
+ {
+ fFound = 0;
+ Mvc_CoverForEachCube( pCover2, pCube2 )
+ {
+ Mvc_CubeBitEqual( CompResult, pCube1, pCube2 );
+ if ( CompResult )
+ {
+ fFound = 1;
+ break;
+ }
+ }
+ if ( !fFound )
+ return 0;
+ }
+ return 1;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sop/mvc/mvcOpBool.c b/src/sop/mvc/mvcOpBool.c
new file mode 100644
index 00000000..57b1a968
--- /dev/null
+++ b/src/sop/mvc/mvcOpBool.c
@@ -0,0 +1,151 @@
+/**CFile****************************************************************
+
+ FileName [mvcProc.c]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Various boolean procedures working with covers.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - February 1, 2003.]
+
+ Revision [$Id: mvcOpBool.c,v 1.4 2003/04/16 01:55:37 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mvc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cover_t * Mvc_CoverBooleanOr( Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 )
+{
+ Mvc_Cover_t * pCover;
+ Mvc_Cube_t * pCube, * pCubeCopy;
+ // make sure the covers are compatible
+ assert( pCover1->nBits == pCover2->nBits );
+ // clone the cover
+ pCover = Mvc_CoverClone( pCover1 );
+ // create the cubes by making pair-wise products
+ // of cubes in pCover1 and pCover2
+ Mvc_CoverForEachCube( pCover1, pCube )
+ {
+ pCubeCopy = Mvc_CubeDup( pCover, pCube );
+ Mvc_CoverAddCubeTail( pCover, pCubeCopy );
+ }
+ Mvc_CoverForEachCube( pCover2, pCube )
+ {
+ pCubeCopy = Mvc_CubeDup( pCover, pCube );
+ Mvc_CoverAddCubeTail( pCover, pCubeCopy );
+ }
+ return pCover;
+}
+
+#if 0
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cover_t * Mvc_CoverBooleanAnd( Mvc_Data_t * p, Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 )
+{
+ Mvc_Cover_t * pCover;
+ Mvc_Cube_t * pCube1, * pCube2, * pCubeCopy;
+ // make sure the covers are compatible
+ assert( pCover1->nBits == pCover2->nBits );
+ // clone the cover
+ pCover = Mvc_CoverClone( pCover1 );
+ // create the cubes by making pair-wise products
+ // of cubes in pCover1 and pCover2
+ Mvc_CoverForEachCube( pCover1, pCube1 )
+ {
+ Mvc_CoverForEachCube( pCover2, pCube2 )
+ {
+ if ( Mvc_CoverDist0Cubes( p, pCube1, pCube2 ) )
+ {
+ pCubeCopy = Mvc_CubeAlloc( pCover );
+ Mvc_CubeBitAnd( pCubeCopy, pCube1, pCube2 );
+ Mvc_CoverAddCubeTail( pCover, pCubeCopy );
+ }
+ }
+ // if the number of cubes in the new cover is too large
+ // try compressing them
+ if ( Mvc_CoverReadCubeNum( pCover ) > 500 )
+ Mvc_CoverContain( pCover );
+ }
+ return pCover;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if the two covers are equal.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CoverBooleanEqual( Mvc_Data_t * p, Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 )
+{
+ Mvc_Cover_t * pSharp;
+
+ pSharp = Mvc_CoverSharp( p, pCover1, pCover2 );
+ if ( Mvc_CoverReadCubeNum( pSharp ) )
+ {
+Mvc_CoverContain( pSharp );
+printf( "Sharp \n" );
+Mvc_CoverPrint( pSharp );
+ Mvc_CoverFree( pSharp );
+ return 0;
+ }
+ Mvc_CoverFree( pSharp );
+
+ pSharp = Mvc_CoverSharp( p, pCover2, pCover1 );
+ if ( Mvc_CoverReadCubeNum( pSharp ) )
+ {
+Mvc_CoverContain( pSharp );
+printf( "Sharp \n" );
+Mvc_CoverPrint( pSharp );
+ Mvc_CoverFree( pSharp );
+ return 0;
+ }
+ Mvc_CoverFree( pSharp );
+
+ return 1;
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sop/mvc/mvcPrint.c b/src/sop/mvc/mvcPrint.c
new file mode 100644
index 00000000..3a31235b
--- /dev/null
+++ b/src/sop/mvc/mvcPrint.c
@@ -0,0 +1,220 @@
+/**CFile****************************************************************
+
+ FileName [mvcPrint.c]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Printing cubes and covers.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - February 1, 2003.]
+
+ Revision [$Id: mvcPrint.c,v 1.6 2003/04/09 18:02:06 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mvc.h"
+//#include "vm.h"
+//#include "vmInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Mvc_CubePrintBinary( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverPrint( Mvc_Cover_t * pCover )
+{
+ Mvc_Cube_t * pCube;
+ int i;
+ // print general statistics
+ printf( "The cover contains %d cubes (%d bits and %d words)\n",
+ pCover->lCubes.nItems, pCover->nBits, pCover->nWords );
+ // iterate through the cubes
+ Mvc_CoverForEachCube( pCover, pCube )
+ Mvc_CubePrint( pCover, pCube );
+
+ if ( pCover->pLits )
+ {
+ for ( i = 0; i < pCover->nBits; i++ )
+ printf( " %d", pCover->pLits[i] );
+ printf( "\n" );
+ }
+ printf( "End of cover printout\n" );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CubePrint( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube )
+{
+ int iBit, Value;
+ // iterate through the literals
+// printf( "Size = %2d ", Mvc_CubeReadSize(pCube) );
+ Mvc_CubeForEachBit( pCover, pCube, iBit, Value )
+ printf( "%c", '0' + Value );
+ printf( "\n" );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverPrintBinary( Mvc_Cover_t * pCover )
+{
+ Mvc_Cube_t * pCube;
+ int i;
+ // print general statistics
+ printf( "The cover contains %d cubes (%d bits and %d words)\n",
+ pCover->lCubes.nItems, pCover->nBits, pCover->nWords );
+ // iterate through the cubes
+ Mvc_CoverForEachCube( pCover, pCube )
+ Mvc_CubePrintBinary( pCover, pCube );
+
+ if ( pCover->pLits )
+ {
+ for ( i = 0; i < pCover->nBits; i++ )
+ printf( " %d", pCover->pLits[i] );
+ printf( "\n" );
+ }
+ printf( "End of cover printout\n" );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CubePrintBinary( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube )
+{
+ int iVar, Value;
+ // iterate through the literals
+// printf( "Size = %2d ", Mvc_CubeReadSize(pCube) );
+ Mvc_CubeForEachVarValue( pCover, pCube, iVar, Value )
+ {
+ assert( Value != 0 );
+ if ( Value == 3 )
+ printf( "-" );
+ else if ( Value == 1 )
+ printf( "0" );
+ else
+ printf( "1" );
+ }
+ printf( "\n" );
+}
+
+#if 0
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverPrintMv( Mvc_Data_t * pData, Mvc_Cover_t * pCover )
+{
+ Mvc_Cube_t * pCube;
+ int i;
+ // print general statistics
+ printf( "The cover contains %d cubes (%d bits and %d words)\n",
+ pCover->lCubes.nItems, pCover->nBits, pCover->nWords );
+ // iterate through the cubes
+ Mvc_CoverForEachCube( pCover, pCube )
+ Mvc_CubePrintMv( pData, pCover, pCube );
+
+ if ( pCover->pLits )
+ {
+ for ( i = 0; i < pCover->nBits; i++ )
+ printf( " %d", pCover->pLits[i] );
+ printf( "\n" );
+ }
+ printf( "End of cover printout\n" );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CubePrintMv( Mvc_Data_t * pData, Mvc_Cover_t * pCover, Mvc_Cube_t * pCube )
+{
+ int iLit, iVar;
+ // iterate through the literals
+ printf( "Size = %2d ", Mvc_CubeReadSize(pCube) );
+ iVar = 0;
+ for ( iLit = 0; iLit < pData->pVm->nValuesIn; iLit++ )
+ {
+ if ( iLit == pData->pVm->pValuesFirst[iVar+1] )
+ {
+ printf( " " );
+ iVar++;
+ }
+ if ( Mvc_CubeBitValue( pCube, iLit ) )
+ printf( "%c", '0' + iLit - pData->pVm->pValuesFirst[iVar] );
+ else
+ printf( "-" );
+ }
+ printf( "\n" );
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sop/mvc/mvcSort.c b/src/sop/mvc/mvcSort.c
new file mode 100644
index 00000000..1126b22a
--- /dev/null
+++ b/src/sop/mvc/mvcSort.c
@@ -0,0 +1,141 @@
+/**CFile****************************************************************
+
+ FileName [mvcSort.c]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Sorting cubes in the cover with the mask.]
+
+ Author [MVSIS Group]
+
+ Affiliation [uC Berkeley]
+
+ Date [Ver. 1.0. Started - February 1, 2003.]
+
+ Revision [$Id: mvcSort.c,v 1.5 2003/04/27 01:03:45 wjiang Exp $]
+
+***********************************************************************/
+
+#include "mvc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+
+Mvc_Cube_t * Mvc_CoverSort_rec( Mvc_Cube_t * pList, int nItems, Mvc_Cube_t * pMask, int (* pCompareFunc)(Mvc_Cube_t *, Mvc_Cube_t *, Mvc_Cube_t *) );
+Mvc_Cube_t * Mvc_CoverSortMerge( Mvc_Cube_t * pList1, Mvc_Cube_t * pList2, Mvc_Cube_t * pMask, int (* pCompareFunc)(Mvc_Cube_t *, Mvc_Cube_t *, Mvc_Cube_t *) );
+
+////////////////////////////////////////////////////////////////////////
+/// FuNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Sorts cubes using the given cost function.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverSort( Mvc_Cover_t * pCover, Mvc_Cube_t * pMask, int (* pCompareFunc)(Mvc_Cube_t *, Mvc_Cube_t *, Mvc_Cube_t *) )
+{
+ Mvc_Cube_t * pHead;
+ int nCubes;
+ // one cube does not need sorting
+ nCubes = Mvc_CoverReadCubeNum(pCover);
+ if ( nCubes <= 1 )
+ return;
+ // sort the cubes
+ pHead = Mvc_CoverSort_rec( Mvc_CoverReadCubeHead(pCover), nCubes, pMask, pCompareFunc );
+ // insert the sorted list into the cover
+ Mvc_CoverSetCubeHead( pCover, pHead );
+ Mvc_CoverSetCubeTail( pCover, Mvc_ListGetTailFromHead(pHead) );
+ // make sure that the list is sorted in the increasing order
+ assert( pCompareFunc( Mvc_CoverReadCubeHead(pCover), Mvc_CoverReadCubeTail(pCover), pMask ) <= 0 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursive part of Mvc_CoverSort()]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cube_t * Mvc_CoverSort_rec( Mvc_Cube_t * pList, int nItems, Mvc_Cube_t * pMask, int (* pCompareFunc)(Mvc_Cube_t *, Mvc_Cube_t *, Mvc_Cube_t *) )
+{
+ Mvc_Cube_t * pList1, * pList2;
+ int nItems1, nItems2, i;
+
+ // trivial case
+ if ( nItems == 1 )
+ {
+ Mvc_CubeSetNext( pList, NULL );
+ return pList;
+ }
+
+ // select the new sizes
+ nItems1 = nItems/2;
+ nItems2 = nItems - nItems1;
+
+ // set the new beginnings
+ pList1 = pList2 = pList;
+ for ( i = 0; i < nItems1; i++ )
+ pList2 = Mvc_CubeReadNext( pList2 );
+
+ // solve recursively
+ pList1 = Mvc_CoverSort_rec( pList1, nItems1, pMask, pCompareFunc );
+ pList2 = Mvc_CoverSort_rec( pList2, nItems2, pMask, pCompareFunc );
+
+ // merge
+ return Mvc_CoverSortMerge( pList1, pList2, pMask, pCompareFunc );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Merges two NULL-terminated linked lists.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cube_t * Mvc_CoverSortMerge( Mvc_Cube_t * pList1, Mvc_Cube_t * pList2, Mvc_Cube_t * pMask, int (* pCompareFunc)(Mvc_Cube_t *, Mvc_Cube_t *, Mvc_Cube_t *) )
+{
+ Mvc_Cube_t * pList = NULL, ** ppTail = &pList;
+ Mvc_Cube_t * pCube;
+ while ( pList1 && pList2 )
+ {
+ if ( pCompareFunc( pList1, pList2, pMask ) < 0 )
+ {
+ pCube = pList1;
+ pList1 = Mvc_CubeReadNext(pList1);
+ }
+ else
+ {
+ pCube = pList2;
+ pList2 = Mvc_CubeReadNext(pList2);
+ }
+ *ppTail = pCube;
+ ppTail = Mvc_CubeReadNextP(pCube);
+ }
+ *ppTail = pList1? pList1: pList2;
+ return pList;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/sop/mvc/mvcUtils.c b/src/sop/mvc/mvcUtils.c
new file mode 100644
index 00000000..3fb57276
--- /dev/null
+++ b/src/sop/mvc/mvcUtils.c
@@ -0,0 +1,868 @@
+/**CFile****************************************************************
+
+ FileName [mvcUtils.c]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Various cover handling utilities.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - February 1, 2003.]
+
+ Revision [$Id: mvcUtils.c,v 1.7 2003/04/26 20:41:36 alanmi Exp $]
+
+***********************************************************************/
+
+#include "mvc.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int bit_count[256] = {
+ 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
+ 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
+ 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
+ 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
+ 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
+ 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
+ 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
+ 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
+};
+
+
+static void Mvc_CoverCopyColumn( Mvc_Cover_t * pCoverOld, Mvc_Cover_t * pCoverNew, int iColOld, int iColNew );
+
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverSupport( Mvc_Cover_t * pCover, Mvc_Cube_t * pSupp )
+{
+ Mvc_Cube_t * pCube;
+ // clean the support
+ Mvc_CubeBitClean( pSupp );
+ // collect the support
+ Mvc_CoverForEachCube( pCover, pCube )
+ Mvc_CubeBitOr( pSupp, pSupp, pCube );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverSupportAnd( Mvc_Cover_t * pCover, Mvc_Cube_t * pSupp )
+{
+ Mvc_Cube_t * pCube;
+ // clean the support
+ Mvc_CubeBitFill( pSupp );
+ // collect the support
+ Mvc_CoverForEachCube( pCover, pCube )
+ Mvc_CubeBitAnd( pSupp, pSupp, pCube );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CoverSupportSizeBinary( Mvc_Cover_t * pCover )
+{
+ Mvc_Cube_t * pSupp;
+ int Counter, i, v0, v1;
+ // compute the support
+ pSupp = Mvc_CubeAlloc( pCover );
+ Mvc_CoverSupportAnd( pCover, pSupp );
+ Counter = pCover->nBits/2;
+ for ( i = 0; i < pCover->nBits/2; i++ )
+ {
+ v0 = Mvc_CubeBitValue( pSupp, 2*i );
+ v1 = Mvc_CubeBitValue( pSupp, 2*i+1 );
+ if ( v0 && v1 )
+ Counter--;
+ }
+ Mvc_CubeFree( pCover, pSupp );
+ return Counter;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CoverSupportVarBelongs( Mvc_Cover_t * pCover, int iVar )
+{
+ Mvc_Cube_t * pSupp;
+ int RetValue, v0, v1;
+ // compute the support
+ pSupp = Mvc_CubeAlloc( pCover );
+ Mvc_CoverSupportAnd( pCover, pSupp );
+ v0 = Mvc_CubeBitValue( pSupp, 2*iVar );
+ v1 = Mvc_CubeBitValue( pSupp, 2*iVar+1 );
+ RetValue = (int)( !v0 || !v1 );
+ Mvc_CubeFree( pCover, pSupp );
+ return RetValue;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverCommonCube( Mvc_Cover_t * pCover, Mvc_Cube_t * pComCube )
+{
+ Mvc_Cube_t * pCube;
+ // clean the support
+ Mvc_CubeBitFill( pComCube );
+ // collect the support
+ Mvc_CoverForEachCube( pCover, pCube )
+ Mvc_CubeBitAnd( pComCube, pComCube, pCube );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CoverIsCubeFree( Mvc_Cover_t * pCover )
+{
+ int Result;
+ // get the common cube
+ Mvc_CoverAllocateMask( pCover );
+ Mvc_CoverCommonCube( pCover, pCover->pMask );
+ // check whether the common cube is empty
+ Mvc_CubeBitEmpty( Result, pCover->pMask );
+ return Result;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverMakeCubeFree( Mvc_Cover_t * pCover )
+{
+ Mvc_Cube_t * pCube;
+ // get the common cube
+ Mvc_CoverAllocateMask( pCover );
+ Mvc_CoverCommonCube( pCover, pCover->pMask );
+ // remove this cube from the cubes in the cover
+ Mvc_CoverForEachCube( pCover, pCube )
+ Mvc_CubeBitSharp( pCube, pCube, pCover->pMask );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cover_t * Mvc_CoverCommonCubeCover( Mvc_Cover_t * pCover )
+{
+ Mvc_Cover_t * pRes;
+ Mvc_Cube_t * pCube;
+ // create the new cover
+ pRes = Mvc_CoverClone( pCover );
+ // get the new cube
+ pCube = Mvc_CubeAlloc( pRes );
+ // get the common cube
+ Mvc_CoverCommonCube( pCover, pCube );
+ // add the cube to the cover
+ Mvc_CoverAddCubeTail( pRes, pCube );
+ return pRes;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if the support of cover2 is contained in the support of cover1.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CoverCheckSuppContainment( Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 )
+{
+ int Result;
+ assert( pCover1->nBits == pCover2->nBits );
+ // set the supports
+ Mvc_CoverAllocateMask( pCover1 );
+ Mvc_CoverSupport( pCover1, pCover1->pMask );
+ Mvc_CoverAllocateMask( pCover2 );
+ Mvc_CoverSupport( pCover2, pCover2->pMask );
+ // check the containment
+ Mvc_CubeBitNotImpl( Result, pCover2->pMask, pCover1->pMask );
+ return !Result;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Counts the cube sizes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CoverSetCubeSizes( Mvc_Cover_t * pCover )
+{
+ Mvc_Cube_t * pCube;
+ unsigned char * pByte, * pByteStart, * pByteStop;
+ int nBytes, nOnes;
+
+ // get the number of unsigned chars in the cube's bit strings
+ nBytes = pCover->nBits / (8 * sizeof(unsigned char)) + (int)(pCover->nBits % (8 * sizeof(unsigned char)) > 0);
+ // iterate through the cubes
+ Mvc_CoverForEachCube( pCover, pCube )
+ {
+ // clean the counter of ones
+ nOnes = 0;
+ // set the starting and stopping positions
+ pByteStart = (unsigned char *)pCube->pData;
+ pByteStop = pByteStart + nBytes;
+ // iterate through the positions
+ for ( pByte = pByteStart; pByte < pByteStop; pByte++ )
+ nOnes += bit_count[*pByte];
+ // set the nOnes
+ Mvc_CubeSetSize( pCube, nOnes );
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Counts the cube sizes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CoverGetCubeSize( Mvc_Cube_t * pCube )
+{
+ unsigned char * pByte, * pByteStart, * pByteStop;
+ int nOnes, nBytes, nBits;
+ // get the number of unsigned chars in the cube's bit strings
+ nBits = (pCube->iLast + 1) * sizeof(Mvc_CubeWord_t) * 8 - pCube->nUnused;
+ nBytes = nBits / (8 * sizeof(unsigned char)) + (int)(nBits % (8 * sizeof(unsigned char)) > 0);
+ // clean the counter of ones
+ nOnes = 0;
+ // set the starting and stopping positions
+ pByteStart = (unsigned char *)pCube->pData;
+ pByteStop = pByteStart + nBytes;
+ // iterate through the positions
+ for ( pByte = pByteStart; pByte < pByteStop; pByte++ )
+ nOnes += bit_count[*pByte];
+ return nOnes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Counts the differences in each cube pair in the cover.]
+
+ Description [Takes the cover (pCover) and the array where the
+ diff counters go (pDiffs). The array pDiffs should have as many
+ entries as there are different pairs of cubes in the cover: n(n-1)/2.
+ Fills out the array pDiffs with the following info: For each cube
+ pair, included in the array is the number of literals in both cubes
+ after they are made cube free.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_CoverCountCubePairDiffs( Mvc_Cover_t * pCover, unsigned char pDiffs[] )
+{
+ Mvc_Cube_t * pCube1;
+ Mvc_Cube_t * pCube2;
+ Mvc_Cube_t * pMask;
+ unsigned char * pByte, * pByteStart, * pByteStop;
+ int nBytes, nOnes;
+ int nCubePairs;
+
+ // allocate a temporary mask
+ pMask = Mvc_CubeAlloc( pCover );
+ // get the number of unsigned chars in the cube's bit strings
+ nBytes = pCover->nBits / (8 * sizeof(unsigned char)) + (int)(pCover->nBits % (8 * sizeof(unsigned char)) > 0);
+ // iterate through the cubes
+ nCubePairs = 0;
+ Mvc_CoverForEachCube( pCover, pCube1 )
+ {
+ Mvc_CoverForEachCubeStart( Mvc_CubeReadNext(pCube1), pCube2 )
+ {
+ // find the bit-wise exor of cubes
+ Mvc_CubeBitExor( pMask, pCube1, pCube2 );
+ // set the starting and stopping positions
+ pByteStart = (unsigned char *)pMask->pData;
+ pByteStop = pByteStart + nBytes;
+ // clean the counter of ones
+ nOnes = 0;
+ // iterate through the positions
+ for ( pByte = pByteStart; pByte < pByteStop; pByte++ )
+ nOnes += bit_count[*pByte];
+ // set the nOnes
+ pDiffs[nCubePairs++] = nOnes;
+ }
+ }
+ // deallocate the mask
+ Mvc_CubeFree( pCover, pMask );
+ return 1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Creates a new cover containing some literals of the old cover.]
+
+ Description [Creates the new cover containing the given number (nVarsRem)
+ literals of the old cover. All the bits of the new cover are initialized
+ to "1". The selected bits from the old cover are copied on top. The numbers
+ of the selected bits to copy are given in the array pVarsRem. The i-set
+ entry in this array is the index of the bit in the old cover which goes
+ to the i-th place in the new cover. If the i-th entry in pVarsRem is -1,
+ it means that the i-th bit does not change (remains composed of all 1's).
+ This is a useful feature to speed up remapping covers, which are known
+ to depend only on a subset of input variables.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cover_t * Mvc_CoverRemap( Mvc_Cover_t * p, int * pVarsRem, int nVarsRem )
+{
+ Mvc_Cover_t * pCover;
+ Mvc_Cube_t * pCube, * pCubeCopy;
+ int i;
+ // clone the cover
+ pCover = Mvc_CoverAlloc( p->pMem, nVarsRem );
+ // copy the cube list
+ Mvc_CoverForEachCube( p, pCube )
+ {
+ pCubeCopy = Mvc_CubeAlloc( pCover );
+ //Mvc_CubeBitClean( pCubeCopy ); //changed by wjiang
+ Mvc_CubeBitFill( pCubeCopy ); //changed by wjiang
+ Mvc_CoverAddCubeTail( pCover, pCubeCopy );
+ }
+ // copy the corresponding columns
+ for ( i = 0; i < nVarsRem; i++ )
+ {
+ if (pVarsRem[i] < 0)
+ continue; //added by wjiang
+ assert( pVarsRem[i] >= 0 && pVarsRem[i] < p->nBits );
+ Mvc_CoverCopyColumn( p, pCover, pVarsRem[i], i );
+ }
+ return pCover;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Copies a column from the old cover to the new cover.]
+
+ Description [Copies the column (iColOld) of the old cover (pCoverOld)
+ into the column (iColNew) of the new cover (pCoverNew). Assumes that
+ the number of cubes is the same in both covers. Makes no assuptions
+ about the current contents of the column in the new cover.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverCopyColumn( Mvc_Cover_t * pCoverOld, Mvc_Cover_t * pCoverNew,
+ int iColOld, int iColNew )
+{
+ Mvc_Cube_t * pCubeOld, * pCubeNew;
+ int iWordOld, iWordNew, iBitOld, iBitNew;
+
+ assert( Mvc_CoverReadCubeNum(pCoverOld) == Mvc_CoverReadCubeNum(pCoverNew) );
+
+ // get the place of the old and new columns
+ iWordOld = Mvc_CubeWhichWord(iColOld);
+ iBitOld = Mvc_CubeWhichBit(iColOld);
+ iWordNew = Mvc_CubeWhichWord(iColNew);
+ iBitNew = Mvc_CubeWhichBit(iColNew);
+
+ // go through the cubes of both covers
+ pCubeNew = Mvc_CoverReadCubeHead(pCoverNew);
+ Mvc_CoverForEachCube( pCoverOld, pCubeOld )
+ {
+ if ( pCubeOld->pData[iWordOld] & (1<<iBitOld) )
+ pCubeNew->pData[iWordNew] |= (1<<iBitNew);
+ else
+ pCubeNew->pData[iWordNew] &= ~(1<<iBitNew); // added by wjiang
+ pCubeNew = Mvc_CubeReadNext( pCubeNew );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Mvc_CoverInverse( Mvc_Cover_t * pCover )
+{
+ Mvc_Cube_t * pCube;
+ // complement the cubes
+ Mvc_CoverForEachCube( pCover, pCube )
+ Mvc_CubeBitNot( pCube );
+}
+
+/**Function*************************************************************
+
+ Synopsis [This function dups the cover and removes DC literals from cubes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cover_t * Mvc_CoverRemoveDontCareLits( Mvc_Cover_t * pCover )
+{
+ Mvc_Cover_t * pCoverNew;
+ Mvc_Cube_t * pCube;
+
+ pCoverNew = Mvc_CoverDup( pCover );
+ Mvc_CoverForEachCube( pCoverNew, pCube )
+ Mvc_CubeBitRemoveDcs( pCube );
+ return pCoverNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the cofactor w.r.t. to a binary var.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cover_t * Mvc_CoverCofactor( Mvc_Cover_t * p, int iValue, int iValueOther )
+{
+ Mvc_Cover_t * pCover;
+ Mvc_Cube_t * pCube, * pCubeCopy;
+ // clone the cover
+ pCover = Mvc_CoverClone( p );
+ // copy the cube list
+ Mvc_CoverForEachCube( p, pCube )
+ if ( Mvc_CubeBitValue( pCube, iValue ) )
+ {
+ pCubeCopy = Mvc_CubeDup( pCover, pCube );
+ Mvc_CoverAddCubeTail( pCover, pCubeCopy );
+ Mvc_CubeBitInsert( pCubeCopy, iValueOther );
+ }
+ return pCover;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the cover, in which the binary var is complemented.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cover_t * Mvc_CoverFlipVar( Mvc_Cover_t * p, int iValue0, int iValue1 )
+{
+ Mvc_Cover_t * pCover;
+ Mvc_Cube_t * pCube, * pCubeCopy;
+ int Value0, Value1, Temp;
+
+ assert( iValue0 + 1 == iValue1 ); // should be adjacent
+
+ // clone the cover
+ pCover = Mvc_CoverClone( p );
+ // copy the cube list
+ Mvc_CoverForEachCube( p, pCube )
+ {
+ pCubeCopy = Mvc_CubeDup( pCover, pCube );
+ Mvc_CoverAddCubeTail( pCover, pCubeCopy );
+
+ // get the bits
+ Value0 = Mvc_CubeBitValue( pCubeCopy, iValue0 );
+ Value1 = Mvc_CubeBitValue( pCubeCopy, iValue1 );
+
+ // if both bits are one, nothing to swap
+ if ( Value0 && Value1 )
+ continue;
+ // cannot be both zero because they belong to the same var
+ assert( Value0 || Value1 );
+
+ // swap the bits
+ Temp = Value0;
+ Value0 = Value1;
+ Value1 = Temp;
+
+ // set the bits after the swap
+ if ( Value0 )
+ Mvc_CubeBitInsert( pCubeCopy, iValue0 );
+ else
+ Mvc_CubeBitRemove( pCubeCopy, iValue0 );
+
+ if ( Value1 )
+ Mvc_CubeBitInsert( pCubeCopy, iValue1 );
+ else
+ Mvc_CubeBitRemove( pCubeCopy, iValue1 );
+ }
+ return pCover;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the cover derived by universal quantification.]
+
+ Description [Returns the cover computed by universal quantification
+ as follows: CoverNew = Univ(B) [Cover & (A==B)]. Removes the second
+ binary var from the support (given by values iValueB0 and iValueB1).
+ Leaves the first binary variable (given by values iValueA0 and iValueA1)
+ in the support.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cover_t * Mvc_CoverUnivQuantify( Mvc_Cover_t * p,
+ int iValueA0, int iValueA1, int iValueB0, int iValueB1 )
+{
+ Mvc_Cover_t * pCover;
+ Mvc_Cube_t * pCube, * pCubeCopy;
+ int ValueA0, ValueA1, ValueB0, ValueB1;
+
+ // clone the cover
+ pCover = Mvc_CoverClone( p );
+ // copy the cube list
+ Mvc_CoverForEachCube( p, pCube )
+ {
+ // get the bits
+ ValueA0 = Mvc_CubeBitValue( pCube, iValueA0 );
+ ValueA1 = Mvc_CubeBitValue( pCube, iValueA1 );
+ ValueB0 = Mvc_CubeBitValue( pCube, iValueB0 );
+ ValueB1 = Mvc_CubeBitValue( pCube, iValueB1 );
+
+ // cannot be both zero because they belong to the same var
+ assert( ValueA0 || ValueA1 );
+ assert( ValueB0 || ValueB1 );
+
+ // if the values of this var are different, do not add the cube
+ if ( ValueA0 != ValueB0 && ValueA1 != ValueB1 )
+ continue;
+
+ // create the cube
+ pCubeCopy = Mvc_CubeDup( pCover, pCube );
+ Mvc_CoverAddCubeTail( pCover, pCubeCopy );
+
+ // insert 1's into for the first var, if both have this value
+ if ( ValueA0 && ValueB0 )
+ Mvc_CubeBitInsert( pCubeCopy, iValueA0 );
+ else
+ Mvc_CubeBitRemove( pCubeCopy, iValueA0 );
+
+ if ( ValueA1 && ValueB1 )
+ Mvc_CubeBitInsert( pCubeCopy, iValueA1 );
+ else
+ Mvc_CubeBitRemove( pCubeCopy, iValueA1 );
+
+ // insert 1's into for the second var (the cover does not depend on it)
+ Mvc_CubeBitInsert( pCubeCopy, iValueB0 );
+ Mvc_CubeBitInsert( pCubeCopy, iValueB1 );
+ }
+ return pCover;
+}
+
+#if 0
+
+/**Function*************************************************************
+
+ Synopsis [Derives the cofactors of the cover.]
+
+ Description [Derives the cofactors w.r.t. a variable and also cubes
+ that do not depend on this variable.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cover_t ** Mvc_CoverCofactors( Mvc_Data_t * pData, Mvc_Cover_t * pCover, int iVar )
+{
+ Mvc_Cover_t ** ppCofs;
+ Mvc_Cube_t * pCube, * pCubeNew;
+ int i, nValues, iValueFirst, Res;
+
+ // start the covers for cofactors
+ iValueFirst = Vm_VarMapReadValuesFirst(pData->pVm, iVar);
+ nValues = Vm_VarMapReadValues(pData->pVm, iVar);
+ ppCofs = ALLOC( Mvc_Cover_t *, nValues + 1 );
+ for ( i = 0; i <= nValues; i++ )
+ ppCofs[i] = Mvc_CoverClone( pCover );
+
+ // go through the cubes
+ Mvc_CoverForEachCube( pCover, pCube )
+ {
+ // if the literal if a full literal, add it to last "cofactor"
+ Mvc_CubeBitEqualUnderMask( Res, pCube, pData->ppMasks[iVar], pData->ppMasks[iVar] );
+ if ( Res )
+ {
+ pCubeNew = Mvc_CubeDup(pCover, pCube);
+ Mvc_CoverAddCubeTail( ppCofs[nValues], pCubeNew );
+ continue;
+ }
+
+ // otherwise, add it to separate values
+ for ( i = 0; i < nValues; i++ )
+ if ( Mvc_CubeBitValue( pCube, iValueFirst + i ) )
+ {
+ pCubeNew = Mvc_CubeDup(pCover, pCube);
+ Mvc_CubeBitOr( pCubeNew, pCubeNew, pData->ppMasks[iVar] );
+ Mvc_CoverAddCubeTail( ppCofs[i], pCubeNew );
+ }
+ }
+ return ppCofs;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Count the cubes with non-trivial literals with the given value.]
+
+ Description [The data and the cover are given (pData, pCover). Also given
+ are the variable number and the number of a value of this variable.
+ This procedure returns the number of cubes having a non-trivial literal
+ of this variable that have the given value present.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvr_CoverCountLitsWithValue( Mvc_Data_t * pData, Mvc_Cover_t * pCover, int iVar, int iValue )
+{
+ Mvc_Cube_t * pCube;
+ int iValueFirst, Res, Counter;
+
+ Counter = 0;
+ iValueFirst = Vm_VarMapReadValuesFirst( pData->pVm, iVar );
+ Mvc_CoverForEachCube( pCover, pCube )
+ {
+ // check if the given literal is the full literal
+ Mvc_CubeBitEqualUnderMask( Res, pCube, pData->ppMasks[iVar], pData->ppMasks[iVar] );
+ if ( Res )
+ continue;
+ // this literal is not a full literal; check if it has this value
+ Counter += Mvc_CubeBitValue( pCube, iValueFirst + iValue );
+ }
+ return Counter;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates the expanded cover.]
+
+ Description [The original cover is expanded by adding some variables.
+ These variables are the additional variables in pVmNew, compared to
+ pCvr->pVm. The resulting cover is the same as the original one, except
+ that it contains the additional variables present as full literals
+ in every cube.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cover_t * Mvc_CoverCreateExpanded( Mvc_Cover_t * pCover, Vm_VarMap_t * pVmNew )
+{
+ Mvc_Cover_t * pCoverNew;
+ Mvc_Cube_t * pCube, * pCubeNew;
+ int i, iLast, iLastNew;
+
+ // create the new cover
+ pCoverNew = Mvc_CoverAlloc( pCover->pMem, Vm_VarMapReadValuesInNum(pVmNew) );
+
+ // get the cube composed of extra bits
+ Mvc_CoverAllocateMask( pCoverNew );
+ Mvc_CubeBitClean( pCoverNew->pMask );
+ for ( i = pCover->nBits; i < pCoverNew->nBits; i++ )
+ Mvc_CubeBitInsert( pCoverNew->pMask, i );
+
+ // get the indexes of the last words in both covers
+ iLast = pCover->nWords? pCover->nWords - 1: 0;
+ iLastNew = pCoverNew->nWords? pCoverNew->nWords - 1: 0;
+
+ // create the cubes of the new cover
+ Mvc_CoverForEachCube( pCover, pCube )
+ {
+ pCubeNew = Mvc_CubeAlloc( pCoverNew );
+ Mvc_CubeBitClean( pCubeNew );
+ // copy the bits (cannot immediately use Mvc_CubeBitCopy,
+ // because covers have different numbers of bits)
+ Mvc_CubeSetLast( pCubeNew, iLast );
+ Mvc_CubeBitCopy( pCubeNew, pCube );
+ Mvc_CubeSetLast( pCubeNew, iLastNew );
+ // add the extra bits
+ Mvc_CubeBitOr( pCubeNew, pCubeNew, pCoverNew->pMask );
+ // add the cube to the new cover
+ Mvc_CoverAddCubeTail( pCoverNew, pCubeNew );
+ }
+ return pCoverNew;
+}
+
+#endif
+
+/**Function*************************************************************
+
+ Synopsis [Transposes the cube cover.]
+
+ Description [Returns the cube cover that looks like a transposed
+ matrix, compared to the matrix derived from the original cover.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Mvc_Cover_t * Mvc_CoverTranspose( Mvc_Cover_t * pCover )
+{
+ Mvc_Cover_t * pRes;
+ Mvc_Cube_t * pCubeRes, * pCube;
+ int nWord, nBit, i, iCube;
+
+ pRes = Mvc_CoverAlloc( pCover->pMem, Mvc_CoverReadCubeNum(pCover) );
+ for ( i = 0; i < pCover->nBits; i++ )
+ {
+ // get the word and bit of this literal
+ nWord = Mvc_CubeWhichWord(i);
+ nBit = Mvc_CubeWhichBit(i);
+ // get the transposed cube
+ pCubeRes = Mvc_CubeAlloc( pRes );
+ Mvc_CubeBitClean( pCubeRes );
+ iCube = 0;
+ Mvc_CoverForEachCube( pCover, pCube )
+ {
+ if ( pCube->pData[nWord] & (1<<nBit) )
+ Mvc_CubeBitInsert( pCubeRes, iCube );
+ iCube++;
+ }
+ Mvc_CoverAddCubeTail( pRes, pCubeRes );
+ }
+ return pRes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks that the cubes of the cover have 0's in unused bits.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Mvc_UtilsCheckUnusedZeros( Mvc_Cover_t * pCover )
+{
+ unsigned Unsigned;
+ Mvc_Cube_t * pCube;
+ int nCubes;
+
+ nCubes = 0;
+ Mvc_CoverForEachCube( pCover, pCube )
+ {
+ if ( pCube->nUnused == 0 )
+ continue;
+
+ Unsigned = ( pCube->pData[pCube->iLast] &
+ (BITS_FULL << (32-pCube->nUnused)) );
+ if( Unsigned )
+ {
+ printf( "Cube %2d out of %2d contains dirty bits.\n", nCubes,
+ Mvc_CoverReadCubeNum(pCover) );
+ }
+ nCubes++;
+ }
+ return 1;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+