From 888e5bed5d7f56a5d86d91a6e8e88f3e5a3454dc Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Fri, 29 Jul 2005 08:01:00 -0700 Subject: Version abc50729 --- Makefile | 62 + abc.dsp | 1314 +++++++++++ abc.dsw | 29 + abc.opt | Bin 0 -> 52736 bytes abc.plg | 962 ++++++++ abc.rc | 26 + depends.sh | 13 + src/base/abc/abc.c | 2158 ++++++++++++++++++ src/base/abc/abc.h | 557 +++++ src/base/abc/abcAig.c | 321 +++ src/base/abc/abcAttach.c | 396 ++++ src/base/abc/abcCheck.c | 848 +++++++ src/base/abc/abcCollapse.c | 271 +++ src/base/abc/abcCreate.c | 1121 +++++++++ src/base/abc/abcDfs.c | 446 ++++ src/base/abc/abcDsd.c | 48 + src/base/abc/abcFanio.c | 196 ++ src/base/abc/abcFpga.c | 247 ++ src/base/abc/abcFraig.c | 585 +++++ src/base/abc/abcFunc.c | 419 ++++ src/base/abc/abcInt.h | 46 + src/base/abc/abcLatch.c | 260 +++ src/base/abc/abcMap.c | 439 ++++ src/base/abc/abcMinBase.c | 167 ++ src/base/abc/abcMiter.c | 502 ++++ src/base/abc/abcNames.c | 406 ++++ src/base/abc/abcNetlist.c | 93 + src/base/abc/abcPrint.c | 288 +++ src/base/abc/abcRefs.c | 133 ++ src/base/abc/abcRenode.c | 605 +++++ src/base/abc/abcSat.c | 252 +++ src/base/abc/abcSop.c | 461 ++++ src/base/abc/abcStrash.c | 541 +++++ src/base/abc/abcSweep.c | 434 ++++ src/base/abc/abcTiming.c | 631 ++++++ src/base/abc/abcUtil.c | 780 +++++++ src/base/abc/abcVerify.c | 310 +++ src/base/abc/module.make | 28 + src/base/cmd/cmd.c | 1498 ++++++++++++ src/base/cmd/cmd.h | 65 + src/base/cmd/cmdAlias.c | 120 + src/base/cmd/cmdApi.c | 104 + src/base/cmd/cmdFlag.c | 112 + src/base/cmd/cmdHist.c | 55 + src/base/cmd/cmdInt.h | 82 + src/base/cmd/cmdUtils.c | 598 +++++ src/base/cmd/module.make | 6 + src/base/io/io.c | 766 +++++++ src/base/io/io.h | 74 + src/base/io/ioInt.h | 49 + src/base/io/ioRead.c | 74 + src/base/io/ioReadBench.c | 227 ++ src/base/io/ioReadBlif.c | 642 ++++++ src/base/io/ioReadVerilog.c | 888 ++++++++ src/base/io/ioWriteBench.c | 224 ++ src/base/io/ioWriteBlif.c | 344 +++ src/base/io/ioWriteBlifLogic.c | 402 ++++ src/base/io/ioWriteCnf.c | 76 + src/base/io/ioWriteGate.c | 263 +++ src/base/io/module.make | 10 + src/base/main/main.c | 267 +++ src/base/main/main.h | 109 + src/base/main/mainFrame.c | 417 ++++ src/base/main/mainInit.c | 96 + src/base/main/mainInt.h | 107 + src/base/main/mainUtils.c | 218 ++ src/base/main/module.make | 4 + src/bdd/cudd/cuBdd.make | 41 + src/bdd/cudd/cudd.h | 959 ++++++++ src/bdd/cudd/cudd.make | 42 + src/bdd/cudd/cuddAPI.c | 4409 ++++++++++++++++++++++++++++++++++++ src/bdd/cudd/cuddAddAbs.c | 566 +++++ src/bdd/cudd/cuddAddApply.c | 917 ++++++++ src/bdd/cudd/cuddAddFind.c | 283 +++ src/bdd/cudd/cuddAddInv.c | 172 ++ src/bdd/cudd/cuddAddIte.c | 613 +++++ src/bdd/cudd/cuddAddNeg.c | 262 +++ src/bdd/cudd/cuddAddWalsh.c | 364 +++ src/bdd/cudd/cuddAndAbs.c | 306 +++ src/bdd/cudd/cuddAnneal.c | 788 +++++++ src/bdd/cudd/cuddApa.c | 930 ++++++++ src/bdd/cudd/cuddApprox.c | 2192 ++++++++++++++++++ src/bdd/cudd/cuddBddAbs.c | 689 ++++++ src/bdd/cudd/cuddBddCorr.c | 481 ++++ src/bdd/cudd/cuddBddIte.c | 1254 ++++++++++ src/bdd/cudd/cuddBridge.c | 981 ++++++++ src/bdd/cudd/cuddCache.c | 1023 +++++++++ src/bdd/cudd/cuddCheck.c | 851 +++++++ src/bdd/cudd/cuddClip.c | 531 +++++ src/bdd/cudd/cuddCof.c | 300 +++ src/bdd/cudd/cuddCompose.c | 1722 ++++++++++++++ src/bdd/cudd/cuddDecomp.c | 2150 ++++++++++++++++++ src/bdd/cudd/cuddEssent.c | 279 +++ src/bdd/cudd/cuddExact.c | 1004 ++++++++ src/bdd/cudd/cuddExport.c | 1289 +++++++++++ src/bdd/cudd/cuddGenCof.c | 1968 ++++++++++++++++ src/bdd/cudd/cuddGenetic.c | 921 ++++++++ src/bdd/cudd/cuddGroup.c | 2142 ++++++++++++++++++ src/bdd/cudd/cuddHarwell.c | 541 +++++ src/bdd/cudd/cuddInit.c | 283 +++ src/bdd/cudd/cuddInt.h | 1133 +++++++++ src/bdd/cudd/cuddInteract.c | 402 ++++ src/bdd/cudd/cuddLCache.c | 1428 ++++++++++++ src/bdd/cudd/cuddLevelQ.c | 533 +++++ src/bdd/cudd/cuddLinear.c | 1333 +++++++++++ src/bdd/cudd/cuddLiteral.c | 237 ++ src/bdd/cudd/cuddMatMult.c | 680 ++++++ src/bdd/cudd/cuddPriority.c | 1475 ++++++++++++ src/bdd/cudd/cuddRead.c | 490 ++++ src/bdd/cudd/cuddRef.c | 781 +++++++ src/bdd/cudd/cuddReorder.c | 2090 +++++++++++++++++ src/bdd/cudd/cuddSat.c | 1305 +++++++++++ src/bdd/cudd/cuddSign.c | 292 +++ src/bdd/cudd/cuddSolve.c | 339 +++ src/bdd/cudd/cuddSplit.c | 657 ++++++ src/bdd/cudd/cuddSubsetHB.c | 1311 +++++++++++ src/bdd/cudd/cuddSubsetSP.c | 1624 +++++++++++++ src/bdd/cudd/cuddSymmetry.c | 1668 ++++++++++++++ src/bdd/cudd/cuddTable.c | 3141 +++++++++++++++++++++++++ src/bdd/cudd/cuddUtil.c | 3633 +++++++++++++++++++++++++++++ src/bdd/cudd/cuddWindow.c | 997 ++++++++ src/bdd/cudd/cuddZddCount.c | 324 +++ src/bdd/cudd/cuddZddFuncs.c | 1603 +++++++++++++ src/bdd/cudd/cuddZddGroup.c | 1317 +++++++++++ src/bdd/cudd/cuddZddIsop.c | 885 ++++++++ src/bdd/cudd/cuddZddLin.c | 939 ++++++++ src/bdd/cudd/cuddZddMisc.c | 252 +++ src/bdd/cudd/cuddZddPort.c | 354 +++ src/bdd/cudd/cuddZddReord.c | 1633 +++++++++++++ src/bdd/cudd/cuddZddSetop.c | 1137 ++++++++++ src/bdd/cudd/cuddZddSymm.c | 1677 ++++++++++++++ src/bdd/cudd/cuddZddUtil.c | 1021 +++++++++ src/bdd/cudd/module.make | 61 + src/bdd/cudd/r7x8.1.mat | 53 + src/bdd/cudd/testcudd.c | 988 ++++++++ src/bdd/dsd/dsd.h | 115 + src/bdd/dsd/dsdApi.c | 95 + src/bdd/dsd/dsdCheck.c | 314 +++ src/bdd/dsd/dsdInt.h | 88 + src/bdd/dsd/dsdLocal.c | 337 +++ src/bdd/dsd/dsdMan.c | 113 + src/bdd/dsd/dsdProc.c | 1607 +++++++++++++ src/bdd/dsd/dsdTree.c | 838 +++++++ src/bdd/dsd/module.make | 6 + src/bdd/epd/epd.c | 1314 +++++++++++ src/bdd/epd/epd.h | 160 ++ src/bdd/epd/module.make | 1 + src/bdd/mtr/module.make | 2 + src/bdd/mtr/mtr.h | 173 ++ src/bdd/mtr/mtrBasic.c | 426 ++++ src/bdd/mtr/mtrGroup.c | 690 ++++++ src/bdd/mtr/mtrInt.h | 65 + src/bdd/parse/module.make | 2 + src/bdd/parse/parse.h | 53 + src/bdd/parse/parseCore.c | 504 +++++ src/bdd/parse/parseInt.h | 73 + src/bdd/parse/parseStack.c | 243 ++ src/bdd/reo/module.make | 7 + src/bdd/reo/reo.h | 222 ++ src/bdd/reo/reoApi.c | 289 +++ src/bdd/reo/reoCore.c | 438 ++++ src/bdd/reo/reoProfile.c | 365 +++ src/bdd/reo/reoSift.c | 341 +++ src/bdd/reo/reoSwap.c | 898 ++++++++ src/bdd/reo/reoTest.c | 251 ++ src/bdd/reo/reoTransfer.c | 199 ++ src/bdd/reo/reoUnits.c | 184 ++ src/generic.c | 47 + src/generic.h | 51 + src/map/fpga/fpga.c | 239 ++ src/map/fpga/fpga.h | 158 ++ src/map/fpga/fpgaCore.c | 241 ++ src/map/fpga/fpgaCreate.c | 585 +++++ src/map/fpga/fpgaCut.c | 1150 ++++++++++ src/map/fpga/fpgaCutUtils.c | 571 +++++ src/map/fpga/fpgaFanout.c | 139 ++ src/map/fpga/fpgaGENERIC.c | 46 + src/map/fpga/fpgaInt.h | 395 ++++ src/map/fpga/fpgaLib.c | 183 ++ src/map/fpga/fpgaMatch.c | 729 ++++++ src/map/fpga/fpgaTime.c | 189 ++ src/map/fpga/fpgaTruth.c | 107 + src/map/fpga/fpgaUtils.c | 1289 +++++++++++ src/map/fpga/fpgaVec.c | 408 ++++ src/map/fpga/module.make | 12 + src/map/mapper/mapper.c | 176 ++ src/map/mapper/mapper.h | 181 ++ src/map/mapper/mapperCanon.c | 161 ++ src/map/mapper/mapperCore.c | 167 ++ src/map/mapper/mapperCreate.c | 592 +++++ src/map/mapper/mapperCut.c | 1072 +++++++++ src/map/mapper/mapperCutUtils.c | 273 +++ src/map/mapper/mapperFanout.c | 139 ++ src/map/mapper/mapperGENERIC.c | 46 + src/map/mapper/mapperInt.h | 475 ++++ src/map/mapper/mapperLib.c | 233 ++ src/map/mapper/mapperMatch.c | 578 +++++ src/map/mapper/mapperRefs.c | 541 +++++ src/map/mapper/mapperSuper.c | 449 ++++ src/map/mapper/mapperTable.c | 402 ++++ src/map/mapper/mapperTime.c | 508 +++++ src/map/mapper/mapperTree.c | 804 +++++++ src/map/mapper/mapperTruth.c | 449 ++++ src/map/mapper/mapperUtils.c | 1254 ++++++++++ src/map/mapper/mapperVec.c | 318 +++ src/map/mapper/module.make | 17 + src/map/mio/mio.c | 269 +++ src/map/mio/mio.h | 136 ++ src/map/mio/mioApi.c | 145 ++ src/map/mio/mioFunc.c | 268 +++ src/map/mio/mioGENERIC.c | 46 + src/map/mio/mioInt.h | 124 + src/map/mio/mioRead.c | 572 +++++ src/map/mio/mioUtils.c | 531 +++++ src/map/mio/module.make | 5 + src/map/super/module.make | 4 + src/map/super/super.c | 319 +++ src/map/super/super.h | 51 + src/map/super/superAnd.c | 696 ++++++ src/map/super/superGENERIC.c | 46 + src/map/super/superGate.c | 1324 +++++++++++ src/map/super/superInt.h | 62 + src/map/super/superWrite.c | 76 + src/misc/extra/extra.h | 220 ++ src/misc/extra/extraUtilBdd.c | 1018 +++++++++ src/misc/extra/extraUtilFile.c | 382 ++++ src/misc/extra/extraUtilMemory.c | 564 +++++ src/misc/extra/extraUtilMisc.c | 380 ++++ src/misc/extra/extraUtilProgress.c | 164 ++ src/misc/extra/extraUtilReader.c | 367 +++ src/misc/extra/module.make | 6 + src/misc/st/module.make | 2 + src/misc/st/st.c | 606 +++++ src/misc/st/st.h | 88 + src/misc/st/stmm.c | 683 ++++++ src/misc/st/stmm.h | 119 + src/misc/util/cpu_stats.c | 122 + src/misc/util/cpu_time.c | 128 ++ src/misc/util/datalimit.c | 95 + src/misc/util/getopt.c | 84 + src/misc/util/leaks.h | 30 + src/misc/util/module.make | 8 + src/misc/util/pathsearch.c | 131 ++ src/misc/util/safe_mem.c | 104 + src/misc/util/stdlib_hack.h | 4 + src/misc/util/strsav.c | 157 ++ src/misc/util/texpand.c | 66 + src/misc/util/util.h | 331 +++ src/misc/vec/module.make | 1 + src/misc/vec/vec.h | 58 + src/misc/vec/vecFan.h | 361 +++ src/misc/vec/vecInt.h | 496 ++++ src/misc/vec/vecPtr.h | 461 ++++ src/misc/vec/vecStr.h | 466 ++++ src/opt/module.make | 1 + src/sat/asat/added.c | 126 ++ src/sat/asat/main.c | 195 ++ src/sat/asat/module.make | 2 + src/sat/asat/solver.c | 1167 ++++++++++ src/sat/asat/solver.h | 137 ++ src/sat/asat/solver_vec.h | 53 + src/sat/fraig/fraig.h | 194 ++ src/sat/fraig/fraigApi.c | 280 +++ src/sat/fraig/fraigCanon.c | 216 ++ src/sat/fraig/fraigFanout.c | 175 ++ src/sat/fraig/fraigFeed.c | 772 +++++++ src/sat/fraig/fraigInt.h | 442 ++++ src/sat/fraig/fraigMan.c | 237 ++ src/sat/fraig/fraigMem.c | 246 ++ src/sat/fraig/fraigNode.c | 308 +++ src/sat/fraig/fraigPrime.c | 142 ++ src/sat/fraig/fraigSat.c | 1085 +++++++++ src/sat/fraig/fraigTable.c | 596 +++++ src/sat/fraig/fraigUtil.c | 969 ++++++++ src/sat/fraig/fraigVec.c | 545 +++++ src/sat/fraig/module.make | 12 + src/sat/msat/module.make | 13 + src/sat/msat/msat.h | 160 ++ src/sat/msat/msatActivity.c | 158 ++ src/sat/msat/msatClause.c | 524 +++++ src/sat/msat/msatClauseVec.c | 232 ++ src/sat/msat/msatInt.h | 304 +++ src/sat/msat/msatMem.c | 529 +++++ src/sat/msat/msatOrderH.c | 405 ++++ src/sat/msat/msatOrderJ.c | 466 ++++ src/sat/msat/msatQueue.c | 157 ++ src/sat/msat/msatRead.c | 268 +++ src/sat/msat/msatSolverApi.c | 488 ++++ src/sat/msat/msatSolverCore.c | 187 ++ src/sat/msat/msatSolverIo.c | 177 ++ src/sat/msat/msatSolverSearch.c | 623 +++++ src/sat/msat/msatSort.c | 173 ++ src/sat/msat/msatVec.c | 495 ++++ src/seq/module.make | 1 + src/sop/ft/ft.h | 105 + src/sop/ft/ftFactor.c | 842 +++++++ src/sop/ft/ftPrint.c | 255 +++ src/sop/ft/module.make | 2 + src/sop/mvc/module.make | 16 + src/sop/mvc/mvc.c | 46 + src/sop/mvc/mvc.h | 733 ++++++ src/sop/mvc/mvcApi.c | 233 ++ src/sop/mvc/mvcCompare.c | 369 +++ src/sop/mvc/mvcContain.c | 173 ++ src/sop/mvc/mvcCover.c | 251 ++ src/sop/mvc/mvcCube.c | 175 ++ src/sop/mvc/mvcDivide.c | 436 ++++ src/sop/mvc/mvcDivisor.c | 90 + src/sop/mvc/mvcList.c | 362 +++ src/sop/mvc/mvcLits.c | 345 +++ src/sop/mvc/mvcMan.c | 77 + src/sop/mvc/mvcOpAlg.c | 163 ++ src/sop/mvc/mvcOpBool.c | 151 ++ src/sop/mvc/mvcPrint.c | 220 ++ src/sop/mvc/mvcSort.c | 141 ++ src/sop/mvc/mvcUtils.c | 868 +++++++ 316 files changed, 150814 insertions(+) create mode 100644 Makefile create mode 100644 abc.dsp create mode 100644 abc.dsw create mode 100644 abc.opt create mode 100644 abc.plg create mode 100644 abc.rc create mode 100755 depends.sh create mode 100644 src/base/abc/abc.c create mode 100644 src/base/abc/abc.h create mode 100644 src/base/abc/abcAig.c create mode 100644 src/base/abc/abcAttach.c create mode 100644 src/base/abc/abcCheck.c create mode 100644 src/base/abc/abcCollapse.c create mode 100644 src/base/abc/abcCreate.c create mode 100644 src/base/abc/abcDfs.c create mode 100644 src/base/abc/abcDsd.c create mode 100644 src/base/abc/abcFanio.c create mode 100644 src/base/abc/abcFpga.c create mode 100644 src/base/abc/abcFraig.c create mode 100644 src/base/abc/abcFunc.c create mode 100644 src/base/abc/abcInt.h create mode 100644 src/base/abc/abcLatch.c create mode 100644 src/base/abc/abcMap.c create mode 100644 src/base/abc/abcMinBase.c create mode 100644 src/base/abc/abcMiter.c create mode 100644 src/base/abc/abcNames.c create mode 100644 src/base/abc/abcNetlist.c create mode 100644 src/base/abc/abcPrint.c create mode 100644 src/base/abc/abcRefs.c create mode 100644 src/base/abc/abcRenode.c create mode 100644 src/base/abc/abcSat.c create mode 100644 src/base/abc/abcSop.c create mode 100644 src/base/abc/abcStrash.c create mode 100644 src/base/abc/abcSweep.c create mode 100644 src/base/abc/abcTiming.c create mode 100644 src/base/abc/abcUtil.c create mode 100644 src/base/abc/abcVerify.c create mode 100644 src/base/abc/module.make create mode 100644 src/base/cmd/cmd.c create mode 100644 src/base/cmd/cmd.h create mode 100644 src/base/cmd/cmdAlias.c create mode 100644 src/base/cmd/cmdApi.c create mode 100644 src/base/cmd/cmdFlag.c create mode 100644 src/base/cmd/cmdHist.c create mode 100644 src/base/cmd/cmdInt.h create mode 100644 src/base/cmd/cmdUtils.c create mode 100644 src/base/cmd/module.make create mode 100644 src/base/io/io.c create mode 100644 src/base/io/io.h create mode 100644 src/base/io/ioInt.h create mode 100644 src/base/io/ioRead.c create mode 100644 src/base/io/ioReadBench.c create mode 100644 src/base/io/ioReadBlif.c create mode 100644 src/base/io/ioReadVerilog.c create mode 100644 src/base/io/ioWriteBench.c create mode 100644 src/base/io/ioWriteBlif.c create mode 100644 src/base/io/ioWriteBlifLogic.c create mode 100644 src/base/io/ioWriteCnf.c create mode 100644 src/base/io/ioWriteGate.c create mode 100644 src/base/io/module.make create mode 100644 src/base/main/main.c create mode 100644 src/base/main/main.h create mode 100644 src/base/main/mainFrame.c create mode 100644 src/base/main/mainInit.c create mode 100644 src/base/main/mainInt.h create mode 100644 src/base/main/mainUtils.c create mode 100644 src/base/main/module.make create mode 100644 src/bdd/cudd/cuBdd.make create mode 100644 src/bdd/cudd/cudd.h create mode 100644 src/bdd/cudd/cudd.make create mode 100644 src/bdd/cudd/cuddAPI.c create mode 100644 src/bdd/cudd/cuddAddAbs.c create mode 100644 src/bdd/cudd/cuddAddApply.c create mode 100644 src/bdd/cudd/cuddAddFind.c create mode 100644 src/bdd/cudd/cuddAddInv.c create mode 100644 src/bdd/cudd/cuddAddIte.c create mode 100644 src/bdd/cudd/cuddAddNeg.c create mode 100644 src/bdd/cudd/cuddAddWalsh.c create mode 100644 src/bdd/cudd/cuddAndAbs.c create mode 100644 src/bdd/cudd/cuddAnneal.c create mode 100644 src/bdd/cudd/cuddApa.c create mode 100644 src/bdd/cudd/cuddApprox.c create mode 100644 src/bdd/cudd/cuddBddAbs.c create mode 100644 src/bdd/cudd/cuddBddCorr.c create mode 100644 src/bdd/cudd/cuddBddIte.c create mode 100644 src/bdd/cudd/cuddBridge.c create mode 100644 src/bdd/cudd/cuddCache.c create mode 100644 src/bdd/cudd/cuddCheck.c create mode 100644 src/bdd/cudd/cuddClip.c create mode 100644 src/bdd/cudd/cuddCof.c create mode 100644 src/bdd/cudd/cuddCompose.c create mode 100644 src/bdd/cudd/cuddDecomp.c create mode 100644 src/bdd/cudd/cuddEssent.c create mode 100644 src/bdd/cudd/cuddExact.c create mode 100644 src/bdd/cudd/cuddExport.c create mode 100644 src/bdd/cudd/cuddGenCof.c create mode 100644 src/bdd/cudd/cuddGenetic.c create mode 100644 src/bdd/cudd/cuddGroup.c create mode 100644 src/bdd/cudd/cuddHarwell.c create mode 100644 src/bdd/cudd/cuddInit.c create mode 100644 src/bdd/cudd/cuddInt.h create mode 100644 src/bdd/cudd/cuddInteract.c create mode 100644 src/bdd/cudd/cuddLCache.c create mode 100644 src/bdd/cudd/cuddLevelQ.c create mode 100644 src/bdd/cudd/cuddLinear.c create mode 100644 src/bdd/cudd/cuddLiteral.c create mode 100644 src/bdd/cudd/cuddMatMult.c create mode 100644 src/bdd/cudd/cuddPriority.c create mode 100644 src/bdd/cudd/cuddRead.c create mode 100644 src/bdd/cudd/cuddRef.c create mode 100644 src/bdd/cudd/cuddReorder.c create mode 100644 src/bdd/cudd/cuddSat.c create mode 100644 src/bdd/cudd/cuddSign.c create mode 100644 src/bdd/cudd/cuddSolve.c create mode 100644 src/bdd/cudd/cuddSplit.c create mode 100644 src/bdd/cudd/cuddSubsetHB.c create mode 100644 src/bdd/cudd/cuddSubsetSP.c create mode 100644 src/bdd/cudd/cuddSymmetry.c create mode 100644 src/bdd/cudd/cuddTable.c create mode 100644 src/bdd/cudd/cuddUtil.c create mode 100644 src/bdd/cudd/cuddWindow.c create mode 100644 src/bdd/cudd/cuddZddCount.c create mode 100644 src/bdd/cudd/cuddZddFuncs.c create mode 100644 src/bdd/cudd/cuddZddGroup.c create mode 100644 src/bdd/cudd/cuddZddIsop.c create mode 100644 src/bdd/cudd/cuddZddLin.c create mode 100644 src/bdd/cudd/cuddZddMisc.c create mode 100644 src/bdd/cudd/cuddZddPort.c create mode 100644 src/bdd/cudd/cuddZddReord.c create mode 100644 src/bdd/cudd/cuddZddSetop.c create mode 100644 src/bdd/cudd/cuddZddSymm.c create mode 100644 src/bdd/cudd/cuddZddUtil.c create mode 100644 src/bdd/cudd/module.make create mode 100644 src/bdd/cudd/r7x8.1.mat create mode 100644 src/bdd/cudd/testcudd.c create mode 100644 src/bdd/dsd/dsd.h create mode 100644 src/bdd/dsd/dsdApi.c create mode 100644 src/bdd/dsd/dsdCheck.c create mode 100644 src/bdd/dsd/dsdInt.h create mode 100644 src/bdd/dsd/dsdLocal.c create mode 100644 src/bdd/dsd/dsdMan.c create mode 100644 src/bdd/dsd/dsdProc.c create mode 100644 src/bdd/dsd/dsdTree.c create mode 100644 src/bdd/dsd/module.make create mode 100644 src/bdd/epd/epd.c create mode 100644 src/bdd/epd/epd.h create mode 100644 src/bdd/epd/module.make create mode 100644 src/bdd/mtr/module.make create mode 100644 src/bdd/mtr/mtr.h create mode 100644 src/bdd/mtr/mtrBasic.c create mode 100644 src/bdd/mtr/mtrGroup.c create mode 100644 src/bdd/mtr/mtrInt.h create mode 100644 src/bdd/parse/module.make create mode 100644 src/bdd/parse/parse.h create mode 100644 src/bdd/parse/parseCore.c create mode 100644 src/bdd/parse/parseInt.h create mode 100644 src/bdd/parse/parseStack.c create mode 100644 src/bdd/reo/module.make create mode 100644 src/bdd/reo/reo.h create mode 100644 src/bdd/reo/reoApi.c create mode 100644 src/bdd/reo/reoCore.c create mode 100644 src/bdd/reo/reoProfile.c create mode 100644 src/bdd/reo/reoSift.c create mode 100644 src/bdd/reo/reoSwap.c create mode 100644 src/bdd/reo/reoTest.c create mode 100644 src/bdd/reo/reoTransfer.c create mode 100644 src/bdd/reo/reoUnits.c create mode 100644 src/generic.c create mode 100644 src/generic.h create mode 100644 src/map/fpga/fpga.c create mode 100644 src/map/fpga/fpga.h create mode 100644 src/map/fpga/fpgaCore.c create mode 100644 src/map/fpga/fpgaCreate.c create mode 100644 src/map/fpga/fpgaCut.c create mode 100644 src/map/fpga/fpgaCutUtils.c create mode 100644 src/map/fpga/fpgaFanout.c create mode 100644 src/map/fpga/fpgaGENERIC.c create mode 100644 src/map/fpga/fpgaInt.h create mode 100644 src/map/fpga/fpgaLib.c create mode 100644 src/map/fpga/fpgaMatch.c create mode 100644 src/map/fpga/fpgaTime.c create mode 100644 src/map/fpga/fpgaTruth.c create mode 100644 src/map/fpga/fpgaUtils.c create mode 100644 src/map/fpga/fpgaVec.c create mode 100644 src/map/fpga/module.make create mode 100644 src/map/mapper/mapper.c create mode 100644 src/map/mapper/mapper.h create mode 100644 src/map/mapper/mapperCanon.c create mode 100644 src/map/mapper/mapperCore.c create mode 100644 src/map/mapper/mapperCreate.c create mode 100644 src/map/mapper/mapperCut.c create mode 100644 src/map/mapper/mapperCutUtils.c create mode 100644 src/map/mapper/mapperFanout.c create mode 100644 src/map/mapper/mapperGENERIC.c create mode 100644 src/map/mapper/mapperInt.h create mode 100644 src/map/mapper/mapperLib.c create mode 100644 src/map/mapper/mapperMatch.c create mode 100644 src/map/mapper/mapperRefs.c create mode 100644 src/map/mapper/mapperSuper.c create mode 100644 src/map/mapper/mapperTable.c create mode 100644 src/map/mapper/mapperTime.c create mode 100644 src/map/mapper/mapperTree.c create mode 100644 src/map/mapper/mapperTruth.c create mode 100644 src/map/mapper/mapperUtils.c create mode 100644 src/map/mapper/mapperVec.c create mode 100644 src/map/mapper/module.make create mode 100644 src/map/mio/mio.c create mode 100644 src/map/mio/mio.h create mode 100644 src/map/mio/mioApi.c create mode 100644 src/map/mio/mioFunc.c create mode 100644 src/map/mio/mioGENERIC.c create mode 100644 src/map/mio/mioInt.h create mode 100644 src/map/mio/mioRead.c create mode 100644 src/map/mio/mioUtils.c create mode 100644 src/map/mio/module.make create mode 100644 src/map/super/module.make create mode 100644 src/map/super/super.c create mode 100644 src/map/super/super.h create mode 100644 src/map/super/superAnd.c create mode 100644 src/map/super/superGENERIC.c create mode 100644 src/map/super/superGate.c create mode 100644 src/map/super/superInt.h create mode 100644 src/map/super/superWrite.c create mode 100644 src/misc/extra/extra.h create mode 100644 src/misc/extra/extraUtilBdd.c create mode 100644 src/misc/extra/extraUtilFile.c create mode 100644 src/misc/extra/extraUtilMemory.c create mode 100644 src/misc/extra/extraUtilMisc.c create mode 100644 src/misc/extra/extraUtilProgress.c create mode 100644 src/misc/extra/extraUtilReader.c create mode 100644 src/misc/extra/module.make create mode 100644 src/misc/st/module.make create mode 100644 src/misc/st/st.c create mode 100644 src/misc/st/st.h create mode 100644 src/misc/st/stmm.c create mode 100644 src/misc/st/stmm.h create mode 100644 src/misc/util/cpu_stats.c create mode 100644 src/misc/util/cpu_time.c create mode 100644 src/misc/util/datalimit.c create mode 100644 src/misc/util/getopt.c create mode 100644 src/misc/util/leaks.h create mode 100644 src/misc/util/module.make create mode 100644 src/misc/util/pathsearch.c create mode 100644 src/misc/util/safe_mem.c create mode 100644 src/misc/util/stdlib_hack.h create mode 100644 src/misc/util/strsav.c create mode 100644 src/misc/util/texpand.c create mode 100644 src/misc/util/util.h create mode 100644 src/misc/vec/module.make create mode 100644 src/misc/vec/vec.h create mode 100644 src/misc/vec/vecFan.h create mode 100644 src/misc/vec/vecInt.h create mode 100644 src/misc/vec/vecPtr.h create mode 100644 src/misc/vec/vecStr.h create mode 100644 src/opt/module.make create mode 100644 src/sat/asat/added.c create mode 100644 src/sat/asat/main.c create mode 100644 src/sat/asat/module.make create mode 100644 src/sat/asat/solver.c create mode 100644 src/sat/asat/solver.h create mode 100644 src/sat/asat/solver_vec.h create mode 100644 src/sat/fraig/fraig.h create mode 100644 src/sat/fraig/fraigApi.c create mode 100644 src/sat/fraig/fraigCanon.c create mode 100644 src/sat/fraig/fraigFanout.c create mode 100644 src/sat/fraig/fraigFeed.c create mode 100644 src/sat/fraig/fraigInt.h create mode 100644 src/sat/fraig/fraigMan.c create mode 100644 src/sat/fraig/fraigMem.c create mode 100644 src/sat/fraig/fraigNode.c create mode 100644 src/sat/fraig/fraigPrime.c create mode 100644 src/sat/fraig/fraigSat.c create mode 100644 src/sat/fraig/fraigTable.c create mode 100644 src/sat/fraig/fraigUtil.c create mode 100644 src/sat/fraig/fraigVec.c create mode 100644 src/sat/fraig/module.make create mode 100644 src/sat/msat/module.make create mode 100644 src/sat/msat/msat.h create mode 100644 src/sat/msat/msatActivity.c create mode 100644 src/sat/msat/msatClause.c create mode 100644 src/sat/msat/msatClauseVec.c create mode 100644 src/sat/msat/msatInt.h create mode 100644 src/sat/msat/msatMem.c create mode 100644 src/sat/msat/msatOrderH.c create mode 100644 src/sat/msat/msatOrderJ.c create mode 100644 src/sat/msat/msatQueue.c create mode 100644 src/sat/msat/msatRead.c create mode 100644 src/sat/msat/msatSolverApi.c create mode 100644 src/sat/msat/msatSolverCore.c create mode 100644 src/sat/msat/msatSolverIo.c create mode 100644 src/sat/msat/msatSolverSearch.c create mode 100644 src/sat/msat/msatSort.c create mode 100644 src/sat/msat/msatVec.c create mode 100644 src/seq/module.make create mode 100644 src/sop/ft/ft.h create mode 100644 src/sop/ft/ftFactor.c create mode 100644 src/sop/ft/ftPrint.c create mode 100644 src/sop/ft/module.make create mode 100644 src/sop/mvc/module.make create mode 100644 src/sop/mvc/mvc.c create mode 100644 src/sop/mvc/mvc.h create mode 100644 src/sop/mvc/mvcApi.c create mode 100644 src/sop/mvc/mvcCompare.c create mode 100644 src/sop/mvc/mvcContain.c create mode 100644 src/sop/mvc/mvcCover.c create mode 100644 src/sop/mvc/mvcCube.c create mode 100644 src/sop/mvc/mvcDivide.c create mode 100644 src/sop/mvc/mvcDivisor.c create mode 100644 src/sop/mvc/mvcList.c create mode 100644 src/sop/mvc/mvcLits.c create mode 100644 src/sop/mvc/mvcMan.c create mode 100644 src/sop/mvc/mvcOpAlg.c create mode 100644 src/sop/mvc/mvcOpBool.c create mode 100644 src/sop/mvc/mvcPrint.c create mode 100644 src/sop/mvc/mvcSort.c create mode 100644 src/sop/mvc/mvcUtils.c 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 Binary files /dev/null and b/abc.opt 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 @@ + + +
+

Build Log

+

+--------------------Configuration: abc - Win32 Release-------------------- +

+

Command Lines

+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" +

Output Window

+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... +

Output Window

+ + + +

Results

+abc.exe - 0 error(s), 19 warning(s) +
+ + 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] \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] \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] \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] \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 +#include +#include +#include +#include + +#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<= 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 \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 \n" ); + fprintf( pAbc->Err, " set the current network to be one of the previous networks\n" ); + fprintf( pAbc->Err, " : 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 + +// these structures are defined in 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] \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, " : 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] \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, " : 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 // 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] \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] \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] \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] \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] \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] \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] \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] \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] \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 ' */ + 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 +#include + +// 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. +
    +
  • To turn on the gathering of statistics, define DD_STATS. +
  • To link with mis, define DD_MIS. +
+ 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 + node is a constant node, the result is unpredictable.] + + SideEffects [none] + + SeeAlso [Cudd_E Cudd_V] + +******************************************************************************/ +#define Cudd_T(node) ((Cudd_Regular(node))->type.kids.T) + + +/**Macro*********************************************************************** + + Synopsis [Returns the else child of an internal node.] + + Description [Returns the else child of an internal node. If + node is a constant node, the result is unpredictable.] + + SideEffects [none] + + SeeAlso [Cudd_T Cudd_V] + +******************************************************************************/ +#define Cudd_E(node) ((Cudd_Regular(node))->type.kids.E) + + +/**Macro*********************************************************************** + + Synopsis [Returns the value of a constant node.] + + Description [Returns the value of a constant node. If + node is an internal node, the result is unpredictable.] + + SideEffects [none] + + SeeAlso [Cudd_T Cudd_E] + +******************************************************************************/ +#define Cudd_V(node) ((Cudd_Regular(node))->type.value) + + +/**Macro*********************************************************************** + + Synopsis [Returns the current position in the order of variable + index.] + + Description [Returns the current position in the order of variable + index. This macro is obsolete and is kept for compatibility. New + applications should use Cudd_ReadPerm instead.] + + SideEffects [none] + + SeeAlso [Cudd_ReadPerm] + +******************************************************************************/ +#define Cudd_ReadIndex(dd,index) (Cudd_ReadPerm(dd,index)) + + +/**Macro*********************************************************************** + + Synopsis [Iterates over the cubes of a decision diagram.] + + Description [Iterates over the cubes of a decision diagram f. +
    +
  • DdManager *manager; +
  • DdNode *f; +
  • DdGen *gen; +
  • int *cube; +
  • CUDD_VALUE_TYPE value; +
+ 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.

+ 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. +

    +
  • DdManager *manager; +
  • DdNode *f; +
  • DdGen *gen; +
  • DdNode *node; +
+ 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.

+ 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. +

    +
  • DdManager *manager; +
  • DdNode *f; +
  • DdGen *gen; +
  • int *path; +
+ 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.

+ 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: +

    +
  • Cudd_addNewVar() +
  • Cudd_addNewVarAtLevel() +
  • Cudd_bddNewVar() +
  • Cudd_bddNewVarAtLevel() +
  • Cudd_addIthVar() +
  • Cudd_bddIthVar() +
  • Cudd_zddIthVar() +
  • Cudd_zddVarsFromBddVars() +
  • Cudd_addConst() +
  • Cudd_IsNonConstant() +
  • Cudd_AutodynEnable() +
  • Cudd_AutodynDisable() +
  • Cudd_ReorderingStatus() +
  • Cudd_AutodynEnableZdd() +
  • Cudd_AutodynDisableZdd() +
  • Cudd_ReorderingStatusZdd() +
  • Cudd_zddRealignmentEnabled() +
  • Cudd_zddRealignEnable() +
  • Cudd_zddRealignDisable() +
  • Cudd_bddRealignmentEnabled() +
  • Cudd_bddRealignEnable() +
  • Cudd_bddRealignDisable() +
  • Cudd_ReadOne() +
  • Cudd_ReadZddOne() +
  • Cudd_ReadZero() +
  • Cudd_ReadLogicZero() +
  • Cudd_ReadPlusInfinity() +
  • Cudd_ReadMinusInfinity() +
  • Cudd_ReadBackground() +
  • Cudd_SetBackground() +
  • Cudd_ReadCacheSlots() +
  • Cudd_ReadCacheUsedSlots() +
  • Cudd_ReadCacheLookUps() +
  • Cudd_ReadCacheHits() +
  • Cudd_ReadMinHit() +
  • Cudd_SetMinHit() +
  • Cudd_ReadLooseUpTo() +
  • Cudd_SetLooseUpTo() +
  • Cudd_ReadMaxCache() +
  • Cudd_ReadMaxCacheHard() +
  • Cudd_SetMaxCacheHard() +
  • Cudd_ReadSize() +
  • Cudd_ReadSlots() +
  • Cudd_ReadUsedSlots() +
  • Cudd_ExpectedUsedSlots() +
  • Cudd_ReadKeys() +
  • Cudd_ReadDead() +
  • Cudd_ReadMinDead() +
  • Cudd_ReadReorderings() +
  • Cudd_ReadReorderingTime() +
  • Cudd_ReadGarbageCollections() +
  • Cudd_ReadGarbageCollectionTime() +
  • Cudd_ReadNodesFreed() +
  • Cudd_ReadNodesDropped() +
  • Cudd_ReadUniqueLookUps() +
  • Cudd_ReadUniqueLinks() +
  • Cudd_ReadSiftMaxVar() +
  • Cudd_SetSiftMaxVar() +
  • Cudd_ReadMaxGrowth() +
  • Cudd_SetMaxGrowth() +
  • Cudd_ReadMaxGrowthAlternate() +
  • Cudd_SetMaxGrowthAlternate() +
  • Cudd_ReadReorderingCycle() +
  • Cudd_SetReorderingCycle() +
  • Cudd_ReadTree() +
  • Cudd_SetTree() +
  • Cudd_FreeTree() +
  • Cudd_ReadZddTree() +
  • Cudd_SetZddTree() +
  • Cudd_FreeZddTree() +
  • Cudd_NodeReadIndex() +
  • Cudd_ReadPerm() +
  • Cudd_ReadInvPerm() +
  • Cudd_ReadVars() +
  • Cudd_ReadEpsilon() +
  • Cudd_SetEpsilon() +
  • Cudd_ReadGroupCheck() +
  • Cudd_SetGroupcheck() +
  • Cudd_GarbageCollectionEnabled() +
  • Cudd_EnableGarbageCollection() +
  • Cudd_DisableGarbageCollection() +
  • Cudd_DeadAreCounted() +
  • Cudd_TurnOnCountDead() +
  • Cudd_TurnOffCountDead() +
  • Cudd_ReadRecomb() +
  • Cudd_SetRecomb() +
  • Cudd_ReadSymmviolation() +
  • Cudd_SetSymmviolation() +
  • Cudd_ReadArcviolation() +
  • Cudd_SetArcviolation() +
  • Cudd_ReadPopulationSize() +
  • Cudd_SetPopulationSize() +
  • Cudd_ReadNumberXovers() +
  • Cudd_SetNumberXovers() +
  • Cudd_ReadMemoryInUse() +
  • Cudd_PrintInfo() +
  • Cudd_ReadPeakNodeCount() +
  • Cudd_ReadPeakLiveNodeCount() +
  • Cudd_ReadNodeCount() +
  • Cudd_zddReadNodeCount() +
  • Cudd_AddHook() +
  • Cudd_RemoveHook() +
  • Cudd_IsInHook() +
  • Cudd_StdPreReordHook() +
  • Cudd_StdPostReordHook() +
  • Cudd_EnableReorderingReporting() +
  • Cudd_DisableReorderingReporting() +
  • Cudd_ReorderingReporting() +
  • Cudd_ReadErrorCode() +
  • Cudd_ClearErrorCode() +
  • Cudd_ReadStdout() +
  • Cudd_SetStdout() +
  • Cudd_ReadStderr() +
  • Cudd_SetStderr() +
  • Cudd_ReadNextReordering() +
  • Cudd_SetNextReordering() +
  • Cudd_ReadSwapSteps() +
  • Cudd_ReadMaxLive() +
  • Cudd_SetMaxLive() +
  • Cudd_ReadMaxMemory() +
  • Cudd_SetMaxMemory() +
  • Cudd_bddBindVar() +
  • Cudd_bddUnbindVar() +
  • Cudd_bddVarIsBound() +
  • Cudd_bddSetPiVar() +
  • Cudd_bddSetPsVar() +
  • Cudd_bddSetNsVar() +
  • Cudd_bddIsPiVar() +
  • Cudd_bddIsPsVar() +
  • Cudd_bddIsNsVar() +
  • Cudd_bddSetPairIndex() +
  • Cudd_bddReadPairIndex() +
  • Cudd_bddSetVarToBeGrouped() +
  • Cudd_bddSetVarHardGroup() +
  • Cudd_bddResetVarToBeGrouped() +
  • Cudd_bddIsVarToBeGrouped() +
  • Cudd_bddSetVarToBeUngrouped() +
  • Cudd_bddIsVarToBeUngrouped() +
  • Cudd_bddIsVarHardGroup() +
+ Static procedures included in this module: +
    +
  • fixVarTree() +
] + + 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 M be the + ratio of the two numbers. For the purpose of realignment, the ZDD + variables from M*i to (M+1)*i-1 are + reagarded as corresponding to BDD variable i. Realignment + is initially disabled.] + + SideEffects [None] + + SeeAlso [Cudd_ReduceHeap Cudd_zddRealignDisable + Cudd_zddRealignmentEnabled Cudd_bddRealignDisable + Cudd_bddRealignmentEnabled] + +******************************************************************************/ +void +Cudd_zddRealignEnable( + DdManager * unique) +{ + unique->realign = 1; + return; + +} /* end of Cudd_zddRealignEnable */ + + +/**Function******************************************************************** + + Synopsis [Disables realignment of ZDD order to BDD order.] + + Description [] + + SideEffects [None] + + SeeAlso [Cudd_zddRealignEnable Cudd_zddRealignmentEnabled + Cudd_bddRealignEnable Cudd_bddRealignmentEnabled] + +******************************************************************************/ +void +Cudd_zddRealignDisable( + DdManager * unique) +{ + unique->realign = 0; + return; + +} /* end of Cudd_zddRealignDisable */ + + +/**Function******************************************************************** + + Synopsis [Tells whether the realignment of BDD order to ZDD order is + enabled.] + + Description [Returns 1 if the realignment of BDD order to ZDD order is + enabled; 0 otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_bddRealignEnable Cudd_bddRealignDisable + Cudd_zddRealignEnable Cudd_zddRealignDisable] + +******************************************************************************/ +int +Cudd_bddRealignmentEnabled( + DdManager * unique) +{ + return(unique->realignZ); + +} /* end of Cudd_bddRealignmentEnabled */ + + +/**Function******************************************************************** + + Synopsis [Enables realignment of BDD order to ZDD order.] + + Description [Enables realignment of the BDD variable order to the + ZDD variable order after the ZDDs have been reordered. The + number of ZDD variables must be a multiple of the number of BDD + variables for realignment to make sense. If this condition is not met, + Cudd_zddReduceHeap will return 0. Let M be the + ratio of the two numbers. For the purpose of realignment, the ZDD + variables from M*i to (M+1)*i-1 are + reagarded as corresponding to BDD variable i. Realignment + is initially disabled.] + + SideEffects [None] + + SeeAlso [Cudd_zddReduceHeap Cudd_bddRealignDisable + Cudd_bddRealignmentEnabled Cudd_zddRealignDisable + Cudd_zddRealignmentEnabled] + +******************************************************************************/ +void +Cudd_bddRealignEnable( + DdManager * unique) +{ + unique->realignZ = 1; + return; + +} /* end of Cudd_bddRealignEnable */ + + +/**Function******************************************************************** + + Synopsis [Disables realignment of ZDD order to BDD order.] + + Description [] + + SideEffects [None] + + SeeAlso [Cudd_bddRealignEnable Cudd_bddRealignmentEnabled + Cudd_zddRealignEnable Cudd_zddRealignmentEnabled] + +******************************************************************************/ +void +Cudd_bddRealignDisable( + DdManager * unique) +{ + unique->realignZ = 0; + return; + +} /* end of Cudd_bddRealignDisable */ + + +/**Function******************************************************************** + + Synopsis [Returns the one constant of the manager.] + + Description [Returns the one constant of the manager. The one + constant is common to ADDs and BDDs.] + + SideEffects [None] + + SeeAlso [Cudd_ReadZero Cudd_ReadLogicZero Cudd_ReadZddOne] + +******************************************************************************/ +DdNode * +Cudd_ReadOne( + DdManager * dd) +{ + return(dd->one); + +} /* end of Cudd_ReadOne */ + + +/**Function******************************************************************** + + Synopsis [Returns the ZDD for the constant 1 function.] + + Description [Returns the ZDD for the constant 1 function. + The representation of the constant 1 function as a ZDD depends on + how many variables it (nominally) depends on. The index of the + topmost variable in the support is given as argument i.] + + SideEffects [None] + + SeeAlso [Cudd_ReadOne] + +******************************************************************************/ +DdNode * +Cudd_ReadZddOne( + DdManager * dd, + int i) +{ + if (i < 0) + return(NULL); + return(i < dd->sizeZ ? dd->univ[i] : DD_ONE(dd)); + +} /* end of Cudd_ReadZddOne */ + + + +/**Function******************************************************************** + + Synopsis [Returns the zero constant of the manager.] + + Description [Returns the zero constant of the manager. The zero + constant is the arithmetic zero, rather than the logic zero. The + latter is the complement of the one constant.] + + SideEffects [None] + + SeeAlso [Cudd_ReadOne Cudd_ReadLogicZero] + +******************************************************************************/ +DdNode * +Cudd_ReadZero( + DdManager * dd) +{ + return(DD_ZERO(dd)); + +} /* end of Cudd_ReadZero */ + + +/**Function******************************************************************** + + Synopsis [Returns the logic zero constant of the manager.] + + Description [Returns the zero constant of the manager. The logic zero + constant is the complement of the one constant, and is distinct from + the arithmetic zero.] + + SideEffects [None] + + SeeAlso [Cudd_ReadOne Cudd_ReadZero] + +******************************************************************************/ +DdNode * +Cudd_ReadLogicZero( + DdManager * dd) +{ + return(Cudd_Not(DD_ONE(dd))); + +} /* end of Cudd_ReadLogicZero */ + + +/**Function******************************************************************** + + Synopsis [Reads the plus-infinity constant from the manager.] + + Description [] + + SideEffects [None] + +******************************************************************************/ +DdNode * +Cudd_ReadPlusInfinity( + DdManager * dd) +{ + return(dd->plusinfinity); + +} /* end of Cudd_ReadPlusInfinity */ + + +/**Function******************************************************************** + + Synopsis [Reads the minus-infinity constant from the manager.] + + Description [] + + SideEffects [None] + +******************************************************************************/ +DdNode * +Cudd_ReadMinusInfinity( + DdManager * dd) +{ + return(dd->minusinfinity); + +} /* end of Cudd_ReadMinusInfinity */ + + +/**Function******************************************************************** + + Synopsis [Reads the background constant of the manager.] + + Description [] + + SideEffects [None] + +******************************************************************************/ +DdNode * +Cudd_ReadBackground( + DdManager * dd) +{ + return(dd->background); + +} /* end of Cudd_ReadBackground */ + + +/**Function******************************************************************** + + Synopsis [Sets the background constant of the manager.] + + Description [Sets the background constant of the manager. It assumes + that the DdNode pointer bck is already referenced.] + + SideEffects [None] + +******************************************************************************/ +void +Cudd_SetBackground( + DdManager * dd, + DdNode * bck) +{ + dd->background = bck; + +} /* end of Cudd_SetBackground */ + + +/**Function******************************************************************** + + Synopsis [Reads the number of slots in the cache.] + + Description [] + + SideEffects [None] + + SeeAlso [Cudd_ReadCacheUsedSlots] + +******************************************************************************/ +unsigned int +Cudd_ReadCacheSlots( + DdManager * dd) +{ + return(dd->cacheSlots); + +} /* end of Cudd_ReadCacheSlots */ + + +/**Function******************************************************************** + + Synopsis [Reads the fraction of used slots in the cache.] + + Description [Reads the fraction of used slots in the cache. The unused + slots are those in which no valid data is stored. Garbage collection, + variable reordering, and cache resizing may cause used slots to become + unused.] + + SideEffects [None] + + SeeAlso [Cudd_ReadCacheSlots] + +******************************************************************************/ +double +Cudd_ReadCacheUsedSlots( + DdManager * dd) +{ + unsigned long used = 0; + int slots = dd->cacheSlots; + DdCache *cache = dd->cache; + int i; + + for (i = 0; i < slots; i++) { + used += cache[i].h != 0; + } + + return((double)used / (double) dd->cacheSlots); + +} /* end of Cudd_ReadCacheUsedSlots */ + + +/**Function******************************************************************** + + Synopsis [Returns the number of cache look-ups.] + + Description [Returns the number of cache look-ups.] + + SideEffects [None] + + SeeAlso [Cudd_ReadCacheHits] + +******************************************************************************/ +double +Cudd_ReadCacheLookUps( + DdManager * dd) +{ + return(dd->cacheHits + dd->cacheMisses + + dd->totCachehits + dd->totCacheMisses); + +} /* end of Cudd_ReadCacheLookUps */ + + +/**Function******************************************************************** + + Synopsis [Returns the number of cache hits.] + + Description [] + + SideEffects [None] + + SeeAlso [Cudd_ReadCacheLookUps] + +******************************************************************************/ +double +Cudd_ReadCacheHits( + DdManager * dd) +{ + return(dd->cacheHits + dd->totCachehits); + +} /* end of Cudd_ReadCacheHits */ + + +/**Function******************************************************************** + + Synopsis [Returns the number of recursive calls.] + + Description [Returns the number of recursive calls if the package is + compiled with DD_COUNT defined.] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +double +Cudd_ReadRecursiveCalls( + DdManager * dd) +{ +#ifdef DD_COUNT + return(dd->recursiveCalls); +#else + return(-1.0); +#endif + +} /* end of Cudd_ReadRecursiveCalls */ + + + +/**Function******************************************************************** + + Synopsis [Reads the hit rate that causes resizinig of the computed + table.] + + Description [] + + SideEffects [None] + + SeeAlso [Cudd_SetMinHit] + +******************************************************************************/ +unsigned int +Cudd_ReadMinHit( + DdManager * dd) +{ + /* Internally, the package manipulates the ratio of hits to + ** misses instead of the ratio of hits to accesses. */ + return((unsigned int) (0.5 + 100 * dd->minHit / (1 + dd->minHit))); + +} /* end of Cudd_ReadMinHit */ + + +/**Function******************************************************************** + + Synopsis [Sets the hit rate that causes resizinig of the computed + table.] + + Description [Sets the minHit parameter of the manager. This + parameter controls the resizing of the computed table. If the hit + rate is larger than the specified value, and the cache is not + already too large, then its size is doubled.] + + SideEffects [None] + + SeeAlso [Cudd_ReadMinHit] + +******************************************************************************/ +void +Cudd_SetMinHit( + DdManager * dd, + unsigned int hr) +{ + /* Internally, the package manipulates the ratio of hits to + ** misses instead of the ratio of hits to accesses. */ + dd->minHit = (double) hr / (100.0 - (double) hr); + +} /* end of Cudd_SetMinHit */ + + +/**Function******************************************************************** + + Synopsis [Reads the looseUpTo parameter of the manager.] + + Description [] + + SideEffects [None] + + SeeAlso [Cudd_SetLooseUpTo Cudd_ReadMinHit Cudd_ReadMinDead] + +******************************************************************************/ +unsigned int +Cudd_ReadLooseUpTo( + DdManager * dd) +{ + return(dd->looseUpTo); + +} /* end of Cudd_ReadLooseUpTo */ + + +/**Function******************************************************************** + + Synopsis [Sets the looseUpTo parameter of the manager.] + + Description [Sets the looseUpTo parameter of the manager. This + parameter of the manager controls the threshold beyond which no fast + growth of the unique table is allowed. The threshold is given as a + number of slots. If the value passed to this function is 0, the + function determines a suitable value based on the available memory.] + + SideEffects [None] + + SeeAlso [Cudd_ReadLooseUpTo Cudd_SetMinHit] + +******************************************************************************/ +void +Cudd_SetLooseUpTo( + DdManager * dd, + unsigned int lut) +{ + if (lut == 0) { + 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 f10 = f01 or + f11 = f00 are tolerable when checking for aggregation + due to extended symmetry. The value should be between 0 and 100. A + small value causes fewer variables to be aggregated. The default + value is 0.] + + SideEffects [None] + + SeeAlso [Cudd_SetSymmviolation] + +******************************************************************************/ +int +Cudd_ReadSymmviolation( + DdManager * dd) +{ + return(dd->symmviolation); + +} /* end of Cudd_ReadSymmviolation */ + + +/**Function******************************************************************** + + Synopsis [Sets the value of the symmviolation parameter used + in group sifting.] + + Description [Sets the value of the symmviolation + parameter. This parameter is used in group sifting to decide how + many violations to the symmetry conditions f10 = f01 or + f11 = f00 are tolerable when checking for aggregation + due to extended symmetry. The value should be between 0 and 100. A + small value causes fewer variables to be aggregated. The default + value is 0.] + + SideEffects [Changes the manager.] + + SeeAlso [Cudd_ReadSymmviolation] + +******************************************************************************/ +void +Cudd_SetSymmviolation( + DdManager * dd, + int symmviolation) +{ + dd->symmviolation = symmviolation; + +} /* end of Cudd_SetSymmviolation */ + + +/**Function******************************************************************** + + Synopsis [Returns the current value of the arcviolation parameter used + in group sifting.] + + Description [Returns the current value of the arcviolation + parameter. This parameter is used in group sifting to decide how + many arcs into y not coming from x are + tolerable when checking for aggregation due to extended + symmetry. The value should be between 0 and 100. A small value + causes fewer variables to be aggregated. The default value is 0.] + + SideEffects [None] + + SeeAlso [Cudd_SetArcviolation] + +******************************************************************************/ +int +Cudd_ReadArcviolation( + DdManager * dd) +{ + return(dd->arcviolation); + +} /* end of Cudd_ReadArcviolation */ + + +/**Function******************************************************************** + + Synopsis [Sets the value of the arcviolation parameter used + in group sifting.] + + Description [Sets the value of the arcviolation + parameter. This parameter is used in group sifting to decide how + many arcs into y not coming from x are + tolerable when checking for aggregation due to extended + symmetry. The value should be between 0 and 100. A small value + causes fewer variables to be aggregated. The default value is 0.] + + SideEffects [None] + + SeeAlso [Cudd_ReadArcviolation] + +******************************************************************************/ +void +Cudd_SetArcviolation( + DdManager * dd, + int arcviolation) +{ + dd->arcviolation = arcviolation; + +} /* end of Cudd_SetArcviolation */ + + +/**Function******************************************************************** + + Synopsis [Reads the current size of the population used by the + genetic algorithm for reordering.] + + Description [Reads the current size of the population used by the + genetic algorithm for variable reordering. A larger population size will + cause the genetic algorithm to take more time, but will generally + produce better results. The default value is 0, in which case the + package uses three times the number of variables as population size, + with a maximum of 120.] + + SideEffects [None] + + SeeAlso [Cudd_SetPopulationSize] + +******************************************************************************/ +int +Cudd_ReadPopulationSize( + DdManager * dd) +{ + return(dd->populationSize); + +} /* end of Cudd_ReadPopulationSize */ + + +/**Function******************************************************************** + + Synopsis [Sets the size of the population used by the + genetic algorithm for reordering.] + + Description [Sets the size of the population used by the + genetic algorithm for variable reordering. A larger population size will + cause the genetic algorithm to take more time, but will generally + produce better results. The default value is 0, in which case the + package uses three times the number of variables as population size, + with a maximum of 120.] + + SideEffects [Changes the manager.] + + SeeAlso [Cudd_ReadPopulationSize] + +******************************************************************************/ +void +Cudd_SetPopulationSize( + DdManager * dd, + int populationSize) +{ + dd->populationSize = populationSize; + +} /* end of Cudd_SetPopulationSize */ + + +/**Function******************************************************************** + + Synopsis [Reads the current number of crossovers used by the + genetic algorithm for reordering.] + + Description [Reads the current number of crossovers used by the + genetic algorithm for variable reordering. A larger number of crossovers will + cause the genetic algorithm to take more time, but will generally + produce better results. The default value is 0, in which case the + package uses three times the number of variables as number of crossovers, + with a maximum of 60.] + + SideEffects [None] + + SeeAlso [Cudd_SetNumberXovers] + +******************************************************************************/ +int +Cudd_ReadNumberXovers( + DdManager * dd) +{ + return(dd->numberXovers); + +} /* end of Cudd_ReadNumberXovers */ + + +/**Function******************************************************************** + + Synopsis [Sets the number of crossovers used by the + genetic algorithm for reordering.] + + Description [Sets the number of crossovers used by the genetic + algorithm for variable reordering. A larger number of crossovers + will cause the genetic algorithm to take more time, but will + generally produce better results. The default value is 0, in which + case the package uses three times the number of variables as number + of crossovers, with a maximum of 60.] + + SideEffects [None] + + SeeAlso [Cudd_ReadNumberXovers] + +******************************************************************************/ +void +Cudd_SetNumberXovers( + DdManager * dd, + int numberXovers) +{ + dd->numberXovers = numberXovers; + +} /* end of Cudd_SetNumberXovers */ + +/**Function******************************************************************** + + Synopsis [Returns the 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: +
    +
  • Cudd_addExistAbstract() +
  • Cudd_addUnivAbstract() +
  • Cudd_addOrAbstract() +
+ Internal procedures included in this module: +
    +
  • cuddAddExistAbstractRecur() +
  • cuddAddUnivAbstractRecur() +
  • cuddAddOrAbstractRecur() +
+ Static procedures included in this module: +
    +
  • addCheckPositiveCube() +
] + + 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: +
    +
  • Cudd_addApply() +
  • 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() +
+ Internal procedures included in this module: +
    +
  • cuddAddApplyRecur() +
  • cuddAddMonadicApplyRecur() +
] + + 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>=g; 0 if f<g.] + + Description [Threshold operator for Apply (f if f >=g; 0 if f<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 > g and 0 otherwise.] + + Description [Returns 1 if f > 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: +
    +
  • Cudd_addFindMax() +
  • Cudd_addFindMin() +
  • Cudd_addIthBit() +
+ Static functions included in this module: +
    +
  • addDoIthBit() +
] + + 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: +
    +
  • Cudd_addScalarInverse() +
+ Internal procedures included in this module: +
    +
  • cuddAddScalarInverseRecur() +
] + + 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: +
    +
  • Cudd_addIte() +
  • Cudd_addIteConstant() +
  • Cudd_addEvalConst() +
  • Cudd_addCmpl() +
  • Cudd_addLeq() +
+ Internal procedures included in this module: +
    +
  • cuddAddIteRecur() +
  • cuddAddCmplRecur() +
+ Static procedures included in this module: +
    +
  • addVarToConst() +
] + + 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: +
    +
  • Cudd_addNegate() +
  • Cudd_addRoundOff() +
+ Internal procedures included in this module: +
    +
  • cuddAddNegateRecur() +
  • cuddAddRoundOffRecur() +
] + + 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: +
    +
  • Cudd_addWalsh() +
  • Cudd_addResidue() +
+ Static procedures included in this module: +
    +
  • addWalshInt() +
] + + 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: +
    +
  • Cudd_bddAndAbstract() +
+ Internal procedures included in this module: +
    +
  • cuddBddAndAbstractRecur() +
] + + 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: +
    +
  • cuddAnnealing() +
+ Static procedures included in this file: +
    +
  • stopping_criterion() +
  • random_generator() +
  • ddExchange() +
  • ddJumpingAux() +
  • ddJumpingUp() +
  • ddJumpingDown() +
  • siftBackwardProb() +
  • copyOrder() +
  • restoreOrder() +
+ ] + + 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: +
    +
  • +
+ Internal procedures included in this module: +
    +
  • () +
+ Static procedures included in this module: +
    +
  • () +
] + + 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 dest.] + + SeeAlso [] + +******************************************************************************/ +void +Cudd_ApaCopy( + int digits, + DdApaNumber source, + DdApaNumber dest) +{ + int i; + + for (i = 0; i < digits; i++) { + dest[i] = source[i]; + } + +} /* end of Cudd_ApaCopy */ + + +/**Function******************************************************************** + + Synopsis [Adds two arbitrary precision integers.] + + Description [Adds two arbitrary precision integers. Returns the + carry out of the most significant digit.] + + SideEffects [The result of the sum is stored in parameter sum.] + + SeeAlso [] + +******************************************************************************/ +DdApaDigit +Cudd_ApaAdd( + int digits, + DdApaNumber a, + DdApaNumber b, + DdApaNumber sum) +{ + int i; + DdApaDoubleDigit partial = 0; + + for (i = digits - 1; i >= 0; i--) { + partial = a[i] + b[i] + DD_MSDIGIT(partial); + sum[i] = (DdApaDigit) DD_LSDIGIT(partial); + } + return(DD_MSDIGIT(partial)); + +} /* end of Cudd_ApaAdd */ + + +/**Function******************************************************************** + + Synopsis [Subtracts two arbitrary precision integers.] + + Description [Subtracts two arbitrary precision integers. Returns the + borrow out of the most significant digit.] + + SideEffects [The result of the subtraction is stored in parameter + diff.] + + SeeAlso [] + +******************************************************************************/ +DdApaDigit +Cudd_ApaSubtract( + int digits, + DdApaNumber a, + DdApaNumber b, + DdApaNumber diff) +{ + int i; + DdApaDoubleDigit partial = DD_APA_BASE; + + for (i = digits - 1; i >= 0; i--) { + partial = 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 quotient.] + + SeeAlso [] + +******************************************************************************/ +DdApaDigit +Cudd_ApaShortDivision( + int digits, + DdApaNumber dividend, + DdApaDigit divisor, + DdApaNumber quotient) +{ + int i; + DdApaDigit remainder; + DdApaDoubleDigit partial; + + remainder = 0; + for (i = 0; i < digits; i++) { + partial = remainder * DD_APA_BASE + dividend[i]; + quotient[i] = (DdApaDigit) (partial/(DdApaDoubleDigit)divisor); + remainder = (DdApaDigit) (partial % divisor); + } + + return(remainder); + +} /* end of Cudd_ApaShortDivision */ + + +/**Function******************************************************************** + + Synopsis [Divides an arbitrary precision integer by an integer.] + + Description [Divides an arbitrary precision integer by a 32-bit + unsigned integer. Returns the remainder of the division. This + procedure relies on the assumption that the number of bits of a + DdApaDigit plus the number of bits of an unsigned int is less the + number of bits of the mantissa of a double. This guarantees that the + product of a DdApaDigit and an unsigned int can be represented + without loss of precision by a double. On machines where this + assumption is not satisfied, this procedure will malfunction.] + + SideEffects [The quotient is returned in parameter quotient.] + + SeeAlso [Cudd_ApaShortDivision] + +******************************************************************************/ +unsigned int +Cudd_ApaIntDivision( + int digits, + DdApaNumber dividend, + unsigned int divisor, + DdApaNumber quotient) +{ + int i; + double partial; + unsigned int remainder = 0; + double ddiv = (double) divisor; + + for (i = 0; i < digits; i++) { + partial = (double) remainder * DD_APA_BASE + dividend[i]; + quotient[i] = (DdApaDigit) (partial / ddiv); + remainder = (unsigned int) (partial - ((double)quotient[i] * ddiv)); + } + + return(remainder); + +} /* end of Cudd_ApaIntDivision */ + + +/**Function******************************************************************** + + Synopsis [Shifts right an arbitrary precision integer by one binary + place.] + + Description [Shifts right an arbitrary precision integer by one + binary place. The most significant binary digit of the result is + taken from parameter in.] + + SideEffects [The result is returned in parameter b.] + + SeeAlso [] + +******************************************************************************/ +void +Cudd_ApaShiftRight( + int digits, + DdApaDigit in, + DdApaNumber a, + DdApaNumber b) +{ + int i; + + for (i = digits - 1; i > 0; i--) { + b[i] = (a[i] >> 1) | ((a[i-1] & 1) << (DD_APA_BITS - 1)); + } + b[0] = (a[0] >> 1) | (in << (DD_APA_BITS - 1)); + +} /* end of Cudd_ApaShiftRight */ + + +/**Function******************************************************************** + + Synopsis [Sets an arbitrary precision integer to a one-digit literal.] + + Description [Sets an arbitrary precision integer to a one-digit literal.] + + SideEffects [The result is returned in parameter number.] + + SeeAlso [] + +******************************************************************************/ +void +Cudd_ApaSetToLiteral( + int digits, + DdApaNumber number, + DdApaDigit literal) +{ + int i; + + for (i = 0; i < digits - 1; i++) + number[i] = 0; + number[digits - 1] = literal; + +} /* end of Cudd_ApaSetToLiteral */ + + +/**Function******************************************************************** + + Synopsis [Sets an arbitrary precision integer to a power of two.] + + Description [Sets an arbitrary precision integer to a power of + two. If the power of two is too large to be represented, the number + is set to 0.] + + SideEffects [The result is returned in parameter number.] + + SeeAlso [] + +******************************************************************************/ +void +Cudd_ApaPowerOfTwo( + int digits, + DdApaNumber number, + int power) +{ + int i; + int index; + + for (i = 0; i < digits; i++) + number[i] = 0; + i = digits - 1 - power / DD_APA_BITS; + if (i < 0) return; + index = power & (DD_APA_BITS - 1); + number[i] = 1 << index; + +} /* end of Cudd_ApaPowerOfTwo */ + + +/**Function******************************************************************** + + Synopsis [Compares two arbitrary precision integers.] + + Description [Compares two arbitrary precision integers. Returns 1 if + the first number is larger; 0 if they are equal; -1 if the second + number is larger.] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +int +Cudd_ApaCompare( + int digitsFirst, + DdApaNumber first, + int digitsSecond, + DdApaNumber second) +{ + int i; + int firstNZ, secondNZ; + + /* Find first non-zero in both numbers. */ + for (firstNZ = 0; firstNZ < digitsFirst; firstNZ++) + if (first[firstNZ] != 0) break; + for (secondNZ = 0; secondNZ < digitsSecond; secondNZ++) + if (second[secondNZ] != 0) break; + if (digitsFirst - firstNZ > digitsSecond - secondNZ) return(1); + else if (digitsFirst - firstNZ < digitsSecond - secondNZ) return(-1); + for (i = 0; i < digitsFirst - firstNZ; i++) { + if (first[firstNZ + i] > second[secondNZ + i]) return(1); + else if (first[firstNZ + i] < second[secondNZ + i]) return(-1); + } + return(0); + +} /* end of Cudd_ApaCompare */ + + +/**Function******************************************************************** + + Synopsis [Compares the ratios of two arbitrary precision integers to two + unsigned ints.] + + Description [Compares the ratios of two arbitrary precision integers + to two unsigned ints. Returns 1 if the first number is larger; 0 if + they are equal; -1 if the second number is larger.] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +int +Cudd_ApaCompareRatios( + int digitsFirst, + DdApaNumber firstNum, + unsigned int firstDen, + int digitsSecond, + DdApaNumber secondNum, + unsigned int secondDen) +{ + int result; + DdApaNumber first, second; + unsigned int firstRem, secondRem; + + first = Cudd_NewApaNumber(digitsFirst); + firstRem = Cudd_ApaIntDivision(digitsFirst,firstNum,firstDen,first); + second = Cudd_NewApaNumber(digitsSecond); + secondRem = Cudd_ApaIntDivision(digitsSecond,secondNum,secondDen,second); + result = Cudd_ApaCompare(digitsFirst,first,digitsSecond,second); + 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 digits.] + + SeeAlso [Cudd_CountMinterm] + +******************************************************************************/ +DdApaNumber +Cudd_ApaCountMinterm( + DdManager * manager, + DdNode * node, + int nvars, + int * digits) +{ + DdApaNumber max, min; + st_table *table; + DdApaNumber i,count; + + background = manager->background; + zero = Cudd_Not(manager->one); + + *digits = Cudd_ApaNumberOfDigits(nvars+1); + max = Cudd_NewApaNumber(*digits); + if (max == NULL) { + return(NULL); + } + Cudd_ApaPowerOfTwo(*digits,max,nvars); + min = Cudd_NewApaNumber(*digits); + if (min == NULL) { + FREE(max); + return(NULL); + } + Cudd_ApaSetToLiteral(*digits,min,0); + table = st_init_table(st_ptrcmp,st_ptrhash); + if (table == NULL) { + FREE(max); + FREE(min); + return(NULL); + } + i = cuddApaCountMintermAux(Cudd_Regular(node),*digits,max,min,table); + if (i == NULL) { + FREE(max); + FREE(min); + st_foreach(table, cuddApaStCountfree, NULL); + st_free_table(table); + return(NULL); + } + count = Cudd_NewApaNumber(*digits); + if (count == NULL) { + FREE(max); + FREE(min); + st_foreach(table, cuddApaStCountfree, NULL); + st_free_table(table); + if (Cudd_Regular(node)->ref == 1) FREE(i); + return(NULL); + } + if (Cudd_IsComplement(node)) { + (void) Cudd_ApaSubtract(*digits,max,i,count); + } else { + Cudd_ApaCopy(*digits,i,count); + } + FREE(max); + FREE(min); + st_foreach(table, cuddApaStCountfree, NULL); + st_free_table(table); + if (Cudd_Regular(node)->ref == 1) FREE(i); + return(count); + +} /* end of Cudd_ApaCountMinterm */ + + +/**Function******************************************************************** + + Synopsis [Prints the number of minterms of a BDD or ADD using + arbitrary precision arithmetic.] + + Description [Prints the number of minterms of a BDD or ADD using + arbitrary precision arithmetic. Returns 1 if successful; 0 otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_ApaPrintMintermExp] + +******************************************************************************/ +int +Cudd_ApaPrintMinterm( + FILE * fp, + DdManager * dd, + DdNode * node, + int nvars) +{ + int digits; + int result; + DdApaNumber count; + + count = Cudd_ApaCountMinterm(dd,node,nvars,&digits); + if (count == NULL) + return(0); + result = Cudd_ApaPrintDecimal(fp,digits,count); + FREE(count); + if (fprintf(fp,"\n") == EOF) { + return(0); + } + return(result); + +} /* end of Cudd_ApaPrintMinterm */ + + +/**Function******************************************************************** + + Synopsis [Prints the number of minterms of a BDD or ADD in exponential + format using arbitrary precision arithmetic.] + + Description [Prints the number of minterms of a BDD or ADD in + exponential format using arbitrary precision arithmetic. Parameter + precision controls the number of signficant digits printed. Returns + 1 if successful; 0 otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_ApaPrintMinterm] + +******************************************************************************/ +int +Cudd_ApaPrintMintermExp( + FILE * fp, + DdManager * dd, + DdNode * node, + int nvars, + int precision) +{ + int digits; + int result; + DdApaNumber count; + + count = Cudd_ApaCountMinterm(dd,node,nvars,&digits); + if (count == NULL) + return(0); + result = Cudd_ApaPrintExponential(fp,digits,count,precision); + FREE(count); + if (fprintf(fp,"\n") == EOF) { + return(0); + } + return(result); + +} /* end of Cudd_ApaPrintMintermExp */ + + +/**Function******************************************************************** + + Synopsis [Prints the density of a BDD or ADD using + arbitrary precision arithmetic.] + + Description [Prints the density of a BDD or ADD using + arbitrary precision arithmetic. Returns 1 if successful; 0 otherwise.] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +int +Cudd_ApaPrintDensity( + FILE * fp, + DdManager * dd, + DdNode * node, + int nvars) +{ + int digits; + int result; + DdApaNumber count,density; + unsigned int size, remainder, fractional; + + count = Cudd_ApaCountMinterm(dd,node,nvars,&digits); + if (count == NULL) + return(0); + size = Cudd_DagSize(node); + density = Cudd_NewApaNumber(digits); + remainder = Cudd_ApaIntDivision(digits,count,size,density); + result = Cudd_ApaPrintDecimal(fp,digits,density); + FREE(count); + FREE(density); + fractional = (unsigned int)((double)remainder / size * 1000000); + if (fprintf(fp,".%u\n", fractional) == EOF) { + return(0); + } + return(result); + +} /* end of Cudd_ApaPrintDensity */ + + +/*---------------------------------------------------------------------------*/ +/* Definition of internal functions */ +/*---------------------------------------------------------------------------*/ + + +/*---------------------------------------------------------------------------*/ +/* Definition of static functions */ +/*---------------------------------------------------------------------------*/ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Cudd_ApaCountMinterm.] + + Description [Performs the recursive step of Cudd_ApaCountMinterm. + It is based on the following identity. Let |f| be the + number of minterms of f. Then: + + |f| = (|f0|+|f1|)/2 + + where f0 and f1 are the two cofactors of f. + Uses the identity |f'| = max - |f|. + The procedure expects the argument "node" to be a regular pointer, and + guarantees this condition is met in the recursive calls. + For efficiency, the result of a call is cached only if the node has + a reference count greater than 1. + Returns the number of minterms of the function rooted at node.] + + SideEffects [None] + +******************************************************************************/ +static DdApaNumber +cuddApaCountMintermAux( + DdNode * node, + int digits, + DdApaNumber max, + DdApaNumber min, + st_table * table) +{ + DdNode *Nt, *Ne; + DdApaNumber mint, mint1, mint2; + DdApaDigit carryout; + + if (cuddIsConstant(node)) { + if (node == background || node == zero) { + return(min); + } else { + return(max); + } + } + if (node->ref > 1 && st_lookup(table, (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: +
    +
  • Cudd_UnderApprox() +
  • Cudd_OverApprox() +
  • Cudd_RemapUnderApprox() +
  • Cudd_RemapOverApprox() +
  • Cudd_BiasedUnderApprox() +
  • Cudd_BiasedOverApprox() +
+ Internal procedures included in this module: +
    +
  • cuddUnderApprox() +
  • cuddRemapUnderApprox() +
  • cuddBiasedUnderApprox() +
+ Static procedures included in this module: +
    +
  • gatherInfoAux() +
  • gatherInfo() +
  • computeSavings() +
  • UAmarkNodes() +
  • UAbuildSubset() +
  • updateRefs() +
  • RAmarkNodes() +
  • BAmarkNodes() +
  • RAbuildSubset() +
+ ] + + 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 +#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: +
    +
  • collect information on each node in the BDD; this is done via DFS. +
  • traverse the BDD in top-down fashion and compute for each node + whether its elimination increases density. +
  • traverse the BDD via DFS and actually perform the elimination. +
+ 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: +
    +
  • collect information on each node in the BDD; this is done via DFS. +
  • traverse the BDD in top-down fashion and compute for each node + whether remapping increases density. +
  • traverse the BDD via DFS and actually perform the elimination. +
+ 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: +
    +
  • collect information on each node in the BDD; this is done via DFS. +
  • traverse the BDD in top-down fashion and compute for each node + whether remapping increases density. +
  • traverse the BDD via DFS and actually perform the elimination. +
+ 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: +
    +
  • Cudd_bddExistAbstract() +
  • Cudd_bddXorExistAbstract() +
  • Cudd_bddUnivAbstract() +
  • Cudd_bddBooleanDiff() +
  • Cudd_bddVarIsDependent() +
+ Internal procedures included in this module: +
    +
  • cuddBddExistAbstractRecur() +
  • cuddBddXorExistAbstractRecur() +
  • cuddBddBooleanDiffRecur() +
+ Static procedures included in this module: +
    +
  • bddCheckPositiveCube() +
+ ] + + 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: +
    +
  • Cudd_bddCorrelation() +
  • Cudd_bddCorrelationWeights() +
+ Static procedures included in this module: +
    +
  • bddCorrelationAux() +
  • bddCorrelationWeightsAux() +
  • CorrelCompare() +
  • CorrelHash() +
  • CorrelCleanUp() +
+ ] + + 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: +
    +
  • Cudd_bddIte() +
  • Cudd_bddIteConstant() +
  • Cudd_bddIntersect() +
  • Cudd_bddAnd() +
  • Cudd_bddOr() +
  • Cudd_bddNand() +
  • Cudd_bddNor() +
  • Cudd_bddXor() +
  • Cudd_bddXnor() +
  • Cudd_bddLeq() +
+ Internal procedures included in this module: +
    +
  • cuddBddIteRecur() +
  • cuddBddIntersectRecur() +
  • cuddBddAndRecur() +
  • cuddBddXorRecur() +
+ Static procedures included in this module: +
    +
  • bddVarToConst() +
  • bddVarToCanonical() +
  • bddVarToCanonicalSimple() +
] + + 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: +
    +
  • Cudd_addBddThreshold() +
  • Cudd_addBddStrictThreshold() +
  • Cudd_addBddInterval() +
  • Cudd_addBddIthBit() +
  • Cudd_BddToAdd() +
  • Cudd_addBddPattern() +
  • Cudd_bddTransfer() +
+ Internal procedures included in this file: +
    +
  • cuddBddTransfer() +
  • cuddAddBddDoPattern() +
+ Static procedures included in this file: +
    +
  • addBddDoThreshold() +
  • addBddDoStrictThreshold() +
  • addBddDoInterval() +
  • addBddDoIthBit() +
  • ddBddToAddRecur() +
  • cuddBddTransferRecur() +
+ ] + + 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: +
    +
  • cuddInitCache() +
  • cuddCacheInsert() +
  • cuddCacheInsert2() +
  • cuddCacheLookup() +
  • cuddCacheLookupZdd() +
  • cuddCacheLookup2() +
  • cuddCacheLookup2Zdd() +
  • cuddConstantLookup() +
  • cuddCacheProfile() +
  • cuddCacheResize() +
  • cuddCacheFlush() +
  • cuddComputeFloorLog2() +
+ Static procedures included in this module: +
    +
] + + 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: +
    +
  • Cudd_DebugCheck() +
  • Cudd_CheckKeys() +
+ Internal procedures included in this module: +
    +
  • cuddHeapProfile() +
  • cuddPrintNode() +
  • cuddPrintVarGroups() +
+ Static procedures included in this module: +
    +
  • debugFindParent() +
+ ] + + 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: +
    +
  • node has illegal index +
  • live node has dead children +
  • node has illegal Then or Else pointers +
  • BDD/ADD node has identical children +
  • ZDD node has zero then child +
  • wrong number of total nodes +
  • wrong number of dead nodes +
  • ref count error at node +
+ 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: +
    +
  • Wrong sizes of subtables. +
  • Wrong number of keys found in unique subtable. +
  • Wrong number of dead found in unique subtable. +
  • Wrong number of keys found in the constant table +
  • Wrong number of dead found in the constant table +
  • Wrong number of total slots found +
  • Wrong number of maximum keys found +
  • Wrong number of total dead found +
+ 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: +
    +
  • total number of tables; +
  • number of tables with live nodes; +
  • table with the largest number of live nodes; +
  • number of nodes in that table. +
+ 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; iout,"%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. +
    +
  • F: MTR_FIXED +
  • N: MTR_NEWNODE +
  • S: MTR_SOFT +
+ 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;jout,"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;jref != 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: +
    +
  • Cudd_bddClippingAnd() +
  • Cudd_bddClippingAndAbstract() +
+ Internal procedures included in this module: +
    +
  • cuddBddClippingAnd() +
  • cuddBddClippingAndAbstract() +
+ Static procedures included in this module: +
    +
  • cuddBddClippingAndRecur() +
  • cuddBddClipAndAbsRecur() +
+ + 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: +
    +
  • Cudd_Cofactor() +
+ Internal procedures included in this module: +
    +
  • cuddGetBranches() +
  • cuddCheckCube() +
  • cuddCofactorRecur() +
+ ] + + 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: +
    +
  • Cudd_bddCompose() +
  • Cudd_addCompose() +
  • Cudd_addPermute() +
  • Cudd_addSwapVariables() +
  • Cudd_bddPermute() +
  • Cudd_bddVarMap() +
  • Cudd_SetVarMap() +
  • Cudd_bddSwapVariables() +
  • Cudd_bddAdjPermuteX() +
  • Cudd_addVectorCompose() +
  • Cudd_addGeneralVectorCompose() +
  • Cudd_addNonSimCompose() +
  • Cudd_bddVectorCompose() +
+ Internal procedures included in this module: +
    +
  • cuddBddComposeRecur() +
  • cuddAddComposeRecur() +
+ Static procedures included in this module: +
    +
  • cuddAddPermuteRecur() +
  • cuddBddPermuteRecur() +
  • cuddBddVarMapRecur() +
  • cuddAddVectorComposeRecur() +
  • cuddAddGeneralVectorComposeRecur() +
  • cuddAddNonSimComposeRecur() +
  • cuddBddVectorComposeRecur() +
  • ddIsIthAddVar() +
  • ddIsIthAddVarPair() +
+ 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.

+ The DdNode * that is returned is the same ADD as passed in as node, + but in the new order.] + + SideEffects [None] + + SeeAlso [Cudd_addPermute cuddBddPermuteRecur] + +******************************************************************************/ +static DdNode * +cuddAddPermuteRecur( + DdManager * manager /* DD manager */, + DdHashTable * table /* computed table */, + DdNode * node /* ADD to be reordered */, + int * permut /* permutation array */) +{ + DdNode *T,*E; + DdNode *res,*var; + int index; + + statLine(manager); + /* Check for terminal case of constant node. */ + if (cuddIsConstant(node)) { + return(node); + } + + /* If problem already solved, look up answer and return. */ + if (node->ref != 1 && (res = cuddHashTableLookup1(table,node)) != NULL) { +#ifdef DD_DEBUG + addPermuteRecurHits++; +#endif + return(res); + } + + /* Split and recur on children of this node. */ + T = cuddAddPermuteRecur(manager,table,cuddT(node),permut); + if (T == NULL) return(NULL); + cuddRef(T); + E = cuddAddPermuteRecur(manager,table,cuddE(node),permut); + if (E == NULL) { + Cudd_RecursiveDeref(manager, T); + return(NULL); + } + cuddRef(E); + + /* Move variable that should be in this position to this position + ** by creating a single var ADD for that variable, and calling + ** cuddAddIteRecur with the T and E we just created. + */ + index = permut[node->index]; + var = cuddUniqueInter(manager,index,DD_ONE(manager),DD_ZERO(manager)); + if (var == NULL) return(NULL); + cuddRef(var); + res = cuddAddIteRecur(manager,var,T,E); + if (res == NULL) { + Cudd_RecursiveDeref(manager,var); + Cudd_RecursiveDeref(manager, T); + Cudd_RecursiveDeref(manager, E); + return(NULL); + } + cuddRef(res); + Cudd_RecursiveDeref(manager,var); + Cudd_RecursiveDeref(manager, T); + Cudd_RecursiveDeref(manager, E); + + /* Do not keep the result if the reference count is only 1, since + ** it will not be visited again. + */ + if (node->ref != 1) { + ptrint fanout = (ptrint) node->ref; + cuddSatDec(fanout); + if (!cuddHashTableInsert1(table,node,res,fanout)) { + Cudd_RecursiveDeref(manager, res); + return(NULL); + } + } + cuddDeref(res); + return(res); + +} /* end of cuddAddPermuteRecur */ + + +/**Function******************************************************************** + + Synopsis [Implements the recursive step of Cudd_bddPermute.] + + Description [ Recursively puts the BDD in the order given in the array permut. + Checks for trivial cases to terminate recursion, then splits on the + children of this node. Once the solutions for the children are + obtained, it puts into the current position the node from the rest of + the BDD that should be here. Then returns this BDD. + The key here is that the node being visited is NOT put in its proper + place by this instance, but rather is switched when its proper position + is reached in the recursion tree.

+ The DdNode * that is returned is the same BDD as passed in as node, + but in the new order.] + + SideEffects [None] + + SeeAlso [Cudd_bddPermute cuddAddPermuteRecur] + +******************************************************************************/ +static DdNode * +cuddBddPermuteRecur( + DdManager * manager /* DD manager */, + DdHashTable * table /* computed table */, + DdNode * node /* BDD to be reordered */, + int * permut /* permutation array */) +{ + DdNode *N,*T,*E; + DdNode *res; + int index; + + statLine(manager); + N = Cudd_Regular(node); + + /* Check for terminal case of constant node. */ + if (cuddIsConstant(N)) { + return(node); + } + + /* If problem already solved, look up answer and return. */ + if (N->ref != 1 && (res = cuddHashTableLookup1(table,N)) != NULL) { +#ifdef DD_DEBUG + bddPermuteRecurHits++; +#endif + return(Cudd_NotCond(res,N != node)); + } + + /* Split and recur on children of this node. */ + T = cuddBddPermuteRecur(manager,table,cuddT(N),permut); + if (T == NULL) return(NULL); + cuddRef(T); + E = cuddBddPermuteRecur(manager,table,cuddE(N),permut); + if (E == NULL) { + Cudd_IterDerefBdd(manager, T); + return(NULL); + } + cuddRef(E); + + /* Move variable that should be in this position to this position + ** by retrieving the single var BDD for that variable, and calling + ** cuddBddIteRecur with the T and E we just created. + */ + index = permut[N->index]; + res = cuddBddIteRecur(manager,manager->vars[index],T,E); + if (res == NULL) { + Cudd_IterDerefBdd(manager, T); + Cudd_IterDerefBdd(manager, E); + return(NULL); + } + cuddRef(res); + Cudd_IterDerefBdd(manager, T); + Cudd_IterDerefBdd(manager, E); + + /* Do not keep the result if the reference count is only 1, since + ** it will not be visited again. + */ + if (N->ref != 1) { + ptrint fanout = (ptrint) N->ref; + cuddSatDec(fanout); + if (!cuddHashTableInsert1(table,N,res,fanout)) { + Cudd_IterDerefBdd(manager, res); + return(NULL); + } + } + cuddDeref(res); + return(Cudd_NotCond(res,N != node)); + +} /* end of cuddBddPermuteRecur */ + + +/**Function******************************************************************** + + Synopsis [Implements the recursive step of Cudd_bddVarMap.] + + Description [Implements the recursive step of Cudd_bddVarMap. + Returns a pointer to the result if successful; NULL otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_bddVarMap] + +******************************************************************************/ +static DdNode * +cuddBddVarMapRecur( + DdManager *manager /* DD manager */, + DdNode *f /* BDD to be remapped */) +{ + DdNode *F, *T, *E; + DdNode *res; + int index; + + statLine(manager); + F = Cudd_Regular(f); + + /* Check for terminal case of constant node. */ + if (cuddIsConstant(F)) { + return(f); + } + + /* If problem already solved, look up answer and return. */ + if (F->ref != 1 && + (res = cuddCacheLookup1(manager,Cudd_bddVarMap,F)) != NULL) { + return(Cudd_NotCond(res,F != f)); + } + + /* Split and recur on children of this node. */ + T = cuddBddVarMapRecur(manager,cuddT(F)); + if (T == NULL) return(NULL); + cuddRef(T); + E = cuddBddVarMapRecur(manager,cuddE(F)); + if (E == NULL) { + Cudd_IterDerefBdd(manager, T); + return(NULL); + } + cuddRef(E); + + /* Move variable that should be in this position to this position + ** by retrieving the single var BDD for that variable, and calling + ** cuddBddIteRecur with the T and E we just created. + */ + index = manager->map[F->index]; + res = cuddBddIteRecur(manager,manager->vars[index],T,E); + if (res == NULL) { + Cudd_IterDerefBdd(manager, T); + Cudd_IterDerefBdd(manager, E); + return(NULL); + } + cuddRef(res); + Cudd_IterDerefBdd(manager, T); + Cudd_IterDerefBdd(manager, E); + + /* Do not keep the result if the reference count is only 1, since + ** it will not be visited again. + */ + if (F->ref != 1) { + cuddCacheInsert1(manager,Cudd_bddVarMap,F,res); + } + cuddDeref(res); + return(Cudd_NotCond(res,F != f)); + +} /* end of cuddBddVarMapRecur */ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Cudd_addVectorCompose.] + + Description [] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +static DdNode * +cuddAddVectorComposeRecur( + DdManager * dd /* DD manager */, + DdHashTable * table /* computed table */, + DdNode * f /* ADD in which to compose */, + DdNode ** vector /* functions to substitute */, + int deepest /* depth of deepest substitution */) +{ + DdNode *T,*E; + DdNode *res; + + statLine(dd); + /* If we are past the deepest substitution, return f. */ + if (cuddI(dd,f->index) > deepest) { + return(f); + } + + if ((res = cuddHashTableLookup1(table,f)) != NULL) { +#ifdef DD_DEBUG + addVectorComposeHits++; +#endif + return(res); + } + + /* Split and recur on children of this node. */ + T = cuddAddVectorComposeRecur(dd,table,cuddT(f),vector,deepest); + if (T == NULL) return(NULL); + cuddRef(T); + E = cuddAddVectorComposeRecur(dd,table,cuddE(f),vector,deepest); + if (E == NULL) { + Cudd_RecursiveDeref(dd, T); + return(NULL); + } + cuddRef(E); + + /* Retrieve the 0-1 ADD for the current top variable and call + ** cuddAddIteRecur with the T and E we just created. + */ + res = cuddAddIteRecur(dd,vector[f->index],T,E); + if (res == NULL) { + Cudd_RecursiveDeref(dd, T); + Cudd_RecursiveDeref(dd, E); + return(NULL); + } + cuddRef(res); + Cudd_RecursiveDeref(dd, T); + Cudd_RecursiveDeref(dd, E); + + /* Do not keep the result if the reference count is only 1, since + ** it will not be visited again + */ + if (f->ref != 1) { + ptrint fanout = (ptrint) f->ref; + cuddSatDec(fanout); + if (!cuddHashTableInsert1(table,f,res,fanout)) { + Cudd_RecursiveDeref(dd, res); + return(NULL); + } + } + cuddDeref(res); + return(res); + +} /* end of cuddAddVectorComposeRecur */ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Cudd_addGeneralVectorCompose.] + + Description [] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +static DdNode * +cuddAddGeneralVectorComposeRecur( + DdManager * dd /* DD manager */, + DdHashTable * table /* computed table */, + DdNode * f /* ADD in which to compose */, + DdNode ** vectorOn /* functions to substitute for x_i */, + DdNode ** vectorOff /* functions to substitute for x_i' */, + int deepest /* depth of deepest substitution */) +{ + DdNode *T,*E,*t,*e; + DdNode *res; + + /* If we are past the deepest substitution, return f. */ + if (cuddI(dd,f->index) > deepest) { + return(f); + } + + if ((res = cuddHashTableLookup1(table,f)) != NULL) { +#ifdef DD_DEBUG + addGeneralVectorComposeHits++; +#endif + return(res); + } + + /* Split and recur on children of this node. */ + T = cuddAddGeneralVectorComposeRecur(dd,table,cuddT(f), + vectorOn,vectorOff,deepest); + if (T == NULL) return(NULL); + cuddRef(T); + E = cuddAddGeneralVectorComposeRecur(dd,table,cuddE(f), + vectorOn,vectorOff,deepest); + if (E == NULL) { + Cudd_RecursiveDeref(dd, T); + return(NULL); + } + cuddRef(E); + + /* Retrieve the compose ADDs for the current top variable and call + ** cuddAddApplyRecur with the T and E we just created. + */ + t = cuddAddApplyRecur(dd,Cudd_addTimes,vectorOn[f->index],T); + if (t == NULL) { + Cudd_RecursiveDeref(dd,T); + Cudd_RecursiveDeref(dd,E); + return(NULL); + } + cuddRef(t); + e = cuddAddApplyRecur(dd,Cudd_addTimes,vectorOff[f->index],E); + if (e == NULL) { + Cudd_RecursiveDeref(dd,T); + Cudd_RecursiveDeref(dd,E); + Cudd_RecursiveDeref(dd,t); + return(NULL); + } + cuddRef(e); + res = cuddAddApplyRecur(dd,Cudd_addPlus,t,e); + if (res == NULL) { + Cudd_RecursiveDeref(dd,T); + Cudd_RecursiveDeref(dd,E); + Cudd_RecursiveDeref(dd,t); + Cudd_RecursiveDeref(dd,e); + return(NULL); + } + cuddRef(res); + Cudd_RecursiveDeref(dd,T); + Cudd_RecursiveDeref(dd,E); + Cudd_RecursiveDeref(dd,t); + Cudd_RecursiveDeref(dd,e); + + /* Do not keep the result if the reference count is only 1, since + ** it will not be visited again + */ + if (f->ref != 1) { + ptrint fanout = (ptrint) f->ref; + cuddSatDec(fanout); + if (!cuddHashTableInsert1(table,f,res,fanout)) { + Cudd_RecursiveDeref(dd, res); + return(NULL); + } + } + cuddDeref(res); + return(res); + +} /* end of cuddAddGeneralVectorComposeRecur */ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Cudd_addNonSimCompose.] + + Description [] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +static DdNode * +cuddAddNonSimComposeRecur( + DdManager * dd, + DdNode * f, + DdNode ** vector, + DdNode * key, + DdNode * cube, + int lastsub) +{ + DdNode *f1, *f0, *key1, *key0, *cube1, *var; + DdNode *T,*E; + DdNode *r; + unsigned int top, topf, topk, topc; + unsigned int index; + int i; + DdNode **vect1; + DdNode **vect0; + + statLine(dd); + /* If we are past the deepest substitution, return f. */ + if (cube == DD_ONE(dd) || cuddIsConstant(f)) { + return(f); + } + + /* If problem already solved, look up answer and return. */ + r = cuddCacheLookup(dd,DD_ADD_NON_SIM_COMPOSE_TAG,f,key,cube); + if (r != NULL) { + return(r); + } + + /* Find top variable. we just need to look at f, key, and cube, + ** because all the varibles in the gi are in key. + */ + topf = cuddI(dd,f->index); + topk = cuddI(dd,key->index); + top = ddMin(topf,topk); + topc = cuddI(dd,cube->index); + top = ddMin(top,topc); + index = dd->invperm[top]; + + /* Compute the cofactors. */ + if (topf == top) { + f1 = cuddT(f); + f0 = cuddE(f); + } else { + f1 = f0 = f; + } + if (topc == top) { + cube1 = cuddT(cube); + /* We want to eliminate vector[index] from key. Otherwise + ** cache performance is severely affected. Hence we + ** existentially quantify the variable with index "index" from key. + */ + var = Cudd_addIthVar(dd, (int) index); + if (var == NULL) { + return(NULL); + } + cuddRef(var); + key1 = cuddAddExistAbstractRecur(dd, key, var); + if (key1 == NULL) { + Cudd_RecursiveDeref(dd,var); + return(NULL); + } + cuddRef(key1); + Cudd_RecursiveDeref(dd,var); + key0 = key1; + } else { + cube1 = cube; + if (topk == top) { + key1 = cuddT(key); + key0 = cuddE(key); + } else { + key1 = key0 = key; + } + cuddRef(key1); + } + + /* Allocate two new vectors for the cofactors of vector. */ + vect1 = ALLOC(DdNode *,lastsub); + if (vect1 == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + Cudd_RecursiveDeref(dd,key1); + return(NULL); + } + vect0 = ALLOC(DdNode *,lastsub); + if (vect0 == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + Cudd_RecursiveDeref(dd,key1); + FREE(vect1); + return(NULL); + } + + /* Cofactor the gi. Eliminate vect1[index] and vect0[index], because + ** we do not need them. + */ + for (i = 0; i < lastsub; i++) { + DdNode *gi = vector[i]; + if (gi == NULL) { + vect1[i] = vect0[i] = NULL; + } else if (gi->index == index) { + vect1[i] = cuddT(gi); + vect0[i] = cuddE(gi); + } else { + vect1[i] = vect0[i] = gi; + } + } + vect1[index] = vect0[index] = NULL; + + /* Recur on children. */ + T = cuddAddNonSimComposeRecur(dd,f1,vect1,key1,cube1,lastsub); + FREE(vect1); + if (T == NULL) { + Cudd_RecursiveDeref(dd,key1); + FREE(vect0); + return(NULL); + } + cuddRef(T); + E = cuddAddNonSimComposeRecur(dd,f0,vect0,key0,cube1,lastsub); + FREE(vect0); + if (E == NULL) { + Cudd_RecursiveDeref(dd,key1); + Cudd_RecursiveDeref(dd,T); + return(NULL); + } + cuddRef(E); + Cudd_RecursiveDeref(dd,key1); + + /* Retrieve the 0-1 ADD for the current top variable from vector, + ** and call cuddAddIteRecur with the T and E we just created. + */ + r = cuddAddIteRecur(dd,vector[index],T,E); + if (r == NULL) { + Cudd_RecursiveDeref(dd,T); + Cudd_RecursiveDeref(dd,E); + return(NULL); + } + cuddRef(r); + Cudd_RecursiveDeref(dd,T); + Cudd_RecursiveDeref(dd,E); + cuddDeref(r); + + /* Store answer to trim recursion. */ + cuddCacheInsert(dd,DD_ADD_NON_SIM_COMPOSE_TAG,f,key,cube,r); + + return(r); + +} /* end of cuddAddNonSimComposeRecur */ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Cudd_bddVectorCompose.] + + Description [] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +static DdNode * +cuddBddVectorComposeRecur( + DdManager * dd /* DD manager */, + DdHashTable * table /* computed table */, + DdNode * f /* BDD in which to compose */, + DdNode ** vector /* functions to be composed */, + int deepest /* depth of the deepest substitution */) +{ + DdNode *F,*T,*E; + DdNode *res; + + statLine(dd); + F = Cudd_Regular(f); + + /* If we are past the deepest substitution, return f. */ + if (cuddI(dd,F->index) > deepest) { + return(f); + } + + /* If problem already solved, look up answer and return. */ + if ((res = cuddHashTableLookup1(table,F)) != NULL) { +#ifdef DD_DEBUG + bddVectorComposeHits++; +#endif + return(Cudd_NotCond(res,F != f)); + } + + /* Split and recur on children of this node. */ + T = cuddBddVectorComposeRecur(dd,table,cuddT(F),vector, deepest); + if (T == NULL) return(NULL); + cuddRef(T); + E = cuddBddVectorComposeRecur(dd,table,cuddE(F),vector, deepest); + if (E == NULL) { + Cudd_IterDerefBdd(dd, T); + return(NULL); + } + cuddRef(E); + + /* Call cuddBddIteRecur with the BDD that replaces the current top + ** variable and the T and E we just created. + */ + res = cuddBddIteRecur(dd,vector[F->index],T,E); + if (res == NULL) { + Cudd_IterDerefBdd(dd, T); + Cudd_IterDerefBdd(dd, E); + return(NULL); + } + cuddRef(res); + Cudd_IterDerefBdd(dd, T); + Cudd_IterDerefBdd(dd, E); + + /* Do not keep the result if the reference count is only 1, since + ** it will not be visited again. + */ + if (F->ref != 1) { + ptrint fanout = (ptrint) F->ref; + cuddSatDec(fanout); + if (!cuddHashTableInsert1(table,F,res,fanout)) { + Cudd_IterDerefBdd(dd, res); + return(NULL); + } + } + cuddDeref(res); + return(Cudd_NotCond(res,F != f)); + +} /* end of cuddBddVectorComposeRecur */ + + +/**Function******************************************************************** + + Synopsis [Comparison of a function to the i-th ADD variable.] + + Description [Comparison of a function to the i-th ADD variable. Returns 1 if + the function is the i-th ADD variable; 0 otherwise.] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +DD_INLINE +static int +ddIsIthAddVar( + DdManager * dd, + DdNode * f, + unsigned int i) +{ + return(f->index == i && cuddT(f) == DD_ONE(dd) && cuddE(f) == DD_ZERO(dd)); + +} /* end of ddIsIthAddVar */ + + +/**Function******************************************************************** + + Synopsis [Comparison of a pair of functions to the i-th ADD variable.] + + Description [Comparison of a pair of functions to the i-th ADD + variable. Returns 1 if the functions are the i-th ADD variable and its + complement; 0 otherwise.] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +DD_INLINE +static int +ddIsIthAddVarPair( + DdManager * dd, + DdNode * f, + DdNode * g, + unsigned int i) +{ + return(f->index == i && g->index == i && + cuddT(f) == DD_ONE(dd) && cuddE(f) == DD_ZERO(dd) && + cuddT(g) == DD_ZERO(dd) && cuddE(g) == DD_ONE(dd)); + +} /* end of ddIsIthAddVarPair */ 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: +

    +
  • Cudd_bddApproxConjDecomp() +
  • Cudd_bddApproxDisjDecomp() +
  • Cudd_bddIterConjDecomp() +
  • Cudd_bddIterDisjDecomp() +
  • Cudd_bddGenConjDecomp() +
  • Cudd_bddGenDisjDecomp() +
  • Cudd_bddVarConjDecomp() +
  • Cudd_bddVarDisjDecomp() +
+ Static procedures included in this module: +
    +
  • cuddConjunctsAux() +
  • CreateBotDist() +
  • BuildConjuncts() +
  • ConjunctsFree() +
] + + 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 f is the function of the BDD and + x is the variable, the decomposition is + (f+x)(f+x'). The variable is chosen so as to balance + the sizes of the two conjuncts and to keep them small. Returns the + number of conjuncts produced, that is, 2 if successful; 1 if no + meaningful decomposition was found; 0 otherwise.] + + SideEffects [The two factors are returned in an array as side effects. + The array is allocated by this function. It is the caller's responsibility + to free it. On successful completion, the conjuncts are already + referenced. If the function returns 0, the array for the conjuncts is + not allocated. If the function returns 1, the only factor equals the + function to be decomposed.] + + SeeAlso [Cudd_bddVarDisjDecomp Cudd_bddGenConjDecomp + Cudd_bddApproxConjDecomp Cudd_bddIterConjDecomp] + +*****************************************************************************/ +int +Cudd_bddVarConjDecomp( + DdManager * dd /* manager */, + DdNode * f /* function to be decomposed */, + DdNode *** conjuncts /* address of the array of conjuncts */) +{ + int best; + int min; + DdNode *support, *scan, *var, *glocal, *hlocal; + + /* Find best cofactoring variable. */ + support = Cudd_Support(dd,f); + if (support == NULL) return(0); + if (Cudd_IsConstant(support)) { + *conjuncts = ALLOC(DdNode *,1); + if (*conjuncts == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(0); + } + (*conjuncts)[0] = f; + cuddRef((*conjuncts)[0]); + return(1); + } + cuddRef(support); + min = 1000000000; + best = -1; + scan = support; + while (!Cudd_IsConstant(scan)) { + int i = scan->index; + int est1 = Cudd_EstimateCofactor(dd,f,i,1); + int est0 = Cudd_EstimateCofactor(dd,f,i,0); + /* Minimize the size of the larger of the two cofactors. */ + int est = (est1 > est0) ? est1 : est0; + if (est < min) { + min = est; + best = i; + } + scan = cuddT(scan); + } +#ifdef DD_DEBUG + assert(best >= 0 && best < dd->size); +#endif + Cudd_RecursiveDeref(dd,support); + + var = Cudd_bddIthVar(dd,best); + glocal = Cudd_bddOr(dd,f,var); + if (glocal == NULL) { + return(0); + } + cuddRef(glocal); + hlocal = Cudd_bddOr(dd,f,Cudd_Not(var)); + if (hlocal == NULL) { + Cudd_RecursiveDeref(dd,glocal); + return(0); + } + cuddRef(hlocal); + + if (glocal != DD_ONE(dd)) { + if (hlocal != DD_ONE(dd)) { + *conjuncts = ALLOC(DdNode *,2); + if (*conjuncts == NULL) { + Cudd_RecursiveDeref(dd,glocal); + Cudd_RecursiveDeref(dd,hlocal); + dd->errorCode = CUDD_MEMORY_OUT; + return(0); + } + (*conjuncts)[0] = glocal; + (*conjuncts)[1] = hlocal; + return(2); + } else { + Cudd_RecursiveDeref(dd,hlocal); + *conjuncts = ALLOC(DdNode *,1); + if (*conjuncts == NULL) { + Cudd_RecursiveDeref(dd,glocal); + dd->errorCode = CUDD_MEMORY_OUT; + return(0); + } + (*conjuncts)[0] = glocal; + return(1); + } + } else { + Cudd_RecursiveDeref(dd,glocal); + *conjuncts = ALLOC(DdNode *,1); + if (*conjuncts == NULL) { + Cudd_RecursiveDeref(dd,hlocal); + dd->errorCode = CUDD_MEMORY_OUT; + return(0); + } + (*conjuncts)[0] = hlocal; + return(1); + } + +} /* end of Cudd_bddVarConjDecomp */ + + +/**Function******************************************************************** + + Synopsis [Performs two-way disjunctive decomposition of a BDD.] + + Description [Performs two-way disjunctive decomposition of a BDD + according to a variable. If f is the function of the + BDD and x is the variable, the decomposition is + f*x + f*x'. The variable is chosen so as to balance + the sizes of the two disjuncts and to keep them small. Returns the + number of disjuncts produced, that is, 2 if successful; 1 if no + meaningful decomposition was found; 0 otherwise.] + + SideEffects [The two disjuncts are returned in an array as side effects. + The array is allocated by this function. It is the caller's responsibility + to free it. On successful completion, the disjuncts are already + referenced. If the function returns 0, the array for the disjuncts is + not allocated. If the function returns 1, the only factor equals the + function to be decomposed.] + + SeeAlso [Cudd_bddVarConjDecomp Cudd_bddApproxDisjDecomp + Cudd_bddIterDisjDecomp Cudd_bddGenDisjDecomp] + +******************************************************************************/ +int +Cudd_bddVarDisjDecomp( + DdManager * dd /* manager */, + DdNode * f /* function to be decomposed */, + DdNode *** disjuncts /* address of the array of the disjuncts */) +{ + int result, i; + + result = Cudd_bddVarConjDecomp(dd,Cudd_Not(f),disjuncts); + for (i = 0; i < result; i++) { + (*disjuncts)[i] = Cudd_Not((*disjuncts)[i]); + } + return(result); + +} /* end of Cudd_bddVarDisjDecomp */ + + +/*---------------------------------------------------------------------------*/ +/* Definition of internal functions */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Definition of static functions */ +/*---------------------------------------------------------------------------*/ + + +/**Function******************************************************************** + + Synopsis [Get longest distance of node from constant.] + + Description [Get longest distance of node from constant. Returns the + distance of the root from the constant if successful; CUDD_OUT_OF_MEM + otherwise.] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +static NodeStat * +CreateBotDist( + DdNode * node, + st_table * distanceTable) +{ + DdNode *N, *Nv, *Nnv; + int distance, distanceNv, distanceNnv; + NodeStat *nodeStat, *nodeStatNv, *nodeStatNnv; + +#if 0 + if (Cudd_IsConstant(node)) { + return(0); + } +#endif + + /* Return the entry in the table if found. */ + N = Cudd_Regular(node); + if (st_lookup(distanceTable, (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: +
    +
  • Cudd_FindEssential() +
  • Cudd_bddIsVarEssential() +
+ Static procedures included in this module: +
    +
  • ddFindEssentialRecur() +
] + + 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: +
    +
+ Internal procedures included in this module: +
    +
  • cuddExact() +
+ Static procedures included in this module: +
    +
  • getMaxBinomial() +
  • gcd() +
  • getMatrix() +
  • freeMatrix() +
  • getLevelKeys() +
  • ddShuffle() +
  • ddSiftUp() +
  • updateUB() +
  • ddCountRoots() +
  • ddClearGlobal() +
  • computeLB() +
  • updateEntry() +
  • pushDown() +
  • initSymmInfo() +
] + + 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: +
    +
  • size of the lower part of it; +
  • size of the part of the upper part not subjected to reordering; +
  • number of roots in the part of the BDD subjected to reordering; +
  • variable in the support of the roots in the upper part of the + BDD subjected to reordering. +
      ] + + 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: +
        +
      • Cudd_DumpBlif() +
      • Cudd_DumpBlifBody() +
      • Cudd_DumpDot() +
      • Cudd_DumpDaVinci() +
      • Cudd_DumpDDcal() +
      • Cudd_DumpFactoredForm() +
      + Internal procedures included in this module: +
        +
      + Static procedures included in this module: +
        +
      • ddDoDumpBlif() +
      • ddDoDumpDaVinci() +
      • ddDoDumpDDcal() +
      • ddDoDumpFactoredForm() +
      ] + + 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: +
        +
      • solid line: THEN arcs; +
      • dotted line: complement arcs; +
      • dashed line: regular ELSE arcs. +
      + 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: +
        +
      • Cudd_bddConstrain() +
      • Cudd_bddRestrict() +
      • Cudd_addConstrain() +
      • Cudd_bddConstrainDecomp() +
      • Cudd_addRestrict() +
      • Cudd_bddCharToVect() +
      • Cudd_bddLICompaction() +
      • Cudd_bddSqueeze() +
      • Cudd_SubsetCompress() +
      • Cudd_SupersetCompress() +
      + Internal procedures included in this module: +
        +
      • cuddBddConstrainRecur() +
      • cuddBddRestrictRecur() +
      • cuddAddConstrainRecur() +
      • cuddAddRestrictRecur() +
      • cuddBddLICompaction() +
      + Static procedures included in this module: +
        +
      • cuddBddConstrainDecomp() +
      • cuddBddCharToVect() +
      • cuddBddLICMarkEdges() +
      • cuddBddLICBuildResult() +
      • cuddBddSqueeze() +
      + ] + + 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: +
        +
      • f @ 0 = 0 +
      • f @ 1 = f +
      • 0 @ c = 0 +
      • 1 @ c = 1 +
      • f @ f = 1 +
      • f @ f'= 0 +
      + 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: +
        +
      • F @ 0 = 0 +
      • F @ 1 = F +
      • 0 @ c = 0 +
      • 1 @ c = 1 +
      • F @ F = 1 +
      + 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 + f of a function to be minimized and a BDD + c representing the care set, Cudd_bddLICompaction + produces the BDD of a function that agrees with f + wherever c is 1. Safe minimization means that the size + of the result is guaranteed not to exceed the size of + f. This function is based on the DAC97 paper by Hong et + al.. Returns a pointer to the result if successful; NULL + otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_bddRestrict] + +******************************************************************************/ +DdNode * +Cudd_bddLICompaction( + DdManager * dd /* manager */, + DdNode * f /* function to be minimized */, + DdNode * c /* constraint (care set) */) +{ + DdNode *res; + + do { + dd->reordered = 0; + res = cuddBddLICompaction(dd,f,c); + } while (dd->reordered == 1); + return(res); + +} /* end of Cudd_bddLICompaction */ + + +/**Function******************************************************************** + + Synopsis [Finds a small BDD in a function interval.] + + Description [Finds a small BDD in a function interval. Given BDDs + l and u, representing the lower bound and + upper bound of a function interval, Cudd_bddSqueeze produces the BDD + of a function within the interval with a small BDD. Returns a + pointer to the result if successful; NULL otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_bddRestrict Cudd_bddLICompaction] + +******************************************************************************/ +DdNode * +Cudd_bddSqueeze( + DdManager * dd /* manager */, + DdNode * l /* lower bound */, + DdNode * u /* upper bound */) +{ + DdNode *res; + int sizeRes, sizeL, sizeU; + + do { + dd->reordered = 0; + res = cuddBddSqueeze(dd,l,u); + } while (dd->reordered == 1); + if (res == NULL) return(NULL); + /* We now compare the result with the bounds and return the smallest. + ** We first compare to u, so that in case l == 0 and u == 1, we return + ** 0 as in other minimization algorithms. */ + sizeRes = Cudd_DagSize(res); + sizeU = Cudd_DagSize(u); + if (sizeU <= sizeRes) { + cuddRef(res); + Cudd_IterDerefBdd(dd,res); + res = u; + sizeRes = sizeU; + } + sizeL = Cudd_DagSize(l); + if (sizeL <= sizeRes) { + cuddRef(res); + Cudd_IterDerefBdd(dd,res); + res = l; + sizeRes = sizeL; + } + return(res); + +} /* end of Cudd_bddSqueeze */ + + +/**Function******************************************************************** + + Synopsis [Finds a small BDD that agrees with f over + c.] + + Description [Finds a small BDD that agrees with f over + c. Returns a pointer to the result if successful; NULL + otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_bddRestrict Cudd_bddLICompaction Cudd_bddSqueeze] + +******************************************************************************/ +DdNode * +Cudd_bddMinimize( + DdManager * dd, + DdNode * f, + DdNode * c) +{ + DdNode *cplus, *res; + + if (c == Cudd_Not(DD_ONE(dd))) return(c); + if (Cudd_IsConstant(f)) return(f); + if (f == c) return(DD_ONE(dd)); + if (f == Cudd_Not(c)) return(Cudd_Not(DD_ONE(dd))); + + cplus = Cudd_RemapOverApprox(dd,c,0,0,1.0); + if (cplus == NULL) return(NULL); + cuddRef(cplus); + res = Cudd_bddLICompaction(dd,f,cplus); + if (res == NULL) { + Cudd_IterDerefBdd(dd,cplus); + return(NULL); + } + cuddRef(res); + Cudd_IterDerefBdd(dd,cplus); + cuddDeref(res); + return(res); + +} /* end of Cudd_bddMinimize */ + + +/**Function******************************************************************** + + Synopsis [Find a dense subset of BDD f.] + + Description [Finds a dense subset of BDD f. Density is + the ratio of number of minterms to number of nodes. Uses several + techniques in series. It is more expensive than other subsetting + procedures, but often produces better results. See + Cudd_SubsetShortPaths for a description of the threshold and nvars + parameters. Returns a pointer to the result if successful; NULL + otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_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 f.] + + Description [Finds a dense superset of BDD f. Density is + the ratio of number of minterms to number of nodes. Uses several + techniques in series. It is more expensive than other supersetting + procedures, but often produces better results. See + Cudd_SupersetShortPaths for a description of the threshold and nvars + parameters. Returns a pointer to the result if successful; NULL + otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_SubsetCompress Cudd_SupersetRemap Cudd_SupersetShortPaths + Cudd_SupersetHeavyBranch Cudd_bddSqueeze] + +******************************************************************************/ +DdNode * +Cudd_SupersetCompress( + DdManager * dd /* manager */, + DdNode * f /* BDD whose superset is sought */, + int nvars /* number of variables in the support of f */, + int threshold /* maximum number of nodes in the superset */) +{ + DdNode *subset; + + subset = Cudd_SubsetCompress(dd, Cudd_Not(f),nvars,threshold); + + return(Cudd_NotCond(subset, (subset != NULL))); + +} /* end of Cudd_SupersetCompress */ + + +/*---------------------------------------------------------------------------*/ +/* Definition of internal functions */ +/*---------------------------------------------------------------------------*/ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Cudd_bddConstrain.] + + Description [Performs the recursive step of Cudd_bddConstrain. + Returns a pointer to the result if successful; NULL otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_bddConstrain] + +******************************************************************************/ +DdNode * +cuddBddConstrainRecur( + DdManager * dd, + DdNode * f, + DdNode * c) +{ + DdNode *Fv, *Fnv, *Cv, *Cnv, *t, *e, *r; + DdNode *one, *zero; + unsigned int topf, topc; + int index; + int comple = 0; + + statLine(dd); + one = DD_ONE(dd); + zero = Cudd_Not(one); + + /* Trivial cases. */ + if (c == one) return(f); + if (c == zero) return(zero); + if (Cudd_IsConstant(f)) return(f); + if (f == c) return(one); + if (f == Cudd_Not(c)) return(zero); + + /* Make canonical to increase the utilization of the cache. */ + if (Cudd_IsComplement(f)) { + f = Cudd_Not(f); + comple = 1; + } + /* Now f is a regular pointer to a non-constant node; c is also + ** non-constant, but may be complemented. + */ + + /* Check the cache. */ + r = cuddCacheLookup2(dd, Cudd_bddConstrain, f, c); + if (r != NULL) { + return(Cudd_NotCond(r,comple)); + } + + /* Recursive step. */ + topf = dd->perm[f->index]; + topc = dd->perm[Cudd_Regular(c)->index]; + if (topf <= topc) { + index = f->index; + Fv = cuddT(f); Fnv = cuddE(f); + } else { + index = Cudd_Regular(c)->index; + Fv = Fnv = f; + } + if (topc <= topf) { + Cv = cuddT(Cudd_Regular(c)); Cnv = cuddE(Cudd_Regular(c)); + if (Cudd_IsComplement(c)) { + Cv = Cudd_Not(Cv); + Cnv = Cudd_Not(Cnv); + } + } else { + Cv = Cnv = c; + } + + if (!Cudd_IsConstant(Cv)) { + t = cuddBddConstrainRecur(dd, Fv, Cv); + if (t == NULL) + return(NULL); + } else if (Cv == one) { + t = Fv; + } else { /* Cv == zero: return Fnv @ Cnv */ + if (Cnv == one) { + r = Fnv; + } else { + r = cuddBddConstrainRecur(dd, Fnv, Cnv); + if (r == NULL) + return(NULL); + } + return(Cudd_NotCond(r,comple)); + } + cuddRef(t); + + if (!Cudd_IsConstant(Cnv)) { + e = cuddBddConstrainRecur(dd, Fnv, Cnv); + if (e == NULL) { + Cudd_IterDerefBdd(dd, t); + return(NULL); + } + } else if (Cnv == one) { + e = Fnv; + } else { /* Cnv == zero: return Fv @ Cv previously computed */ + cuddDeref(t); + return(Cudd_NotCond(t,comple)); + } + cuddRef(e); + + if (Cudd_IsComplement(t)) { + t = Cudd_Not(t); + e = Cudd_Not(e); + r = (t == e) ? t : cuddUniqueInter(dd, index, t, e); + if (r == NULL) { + Cudd_IterDerefBdd(dd, e); + Cudd_IterDerefBdd(dd, t); + return(NULL); + } + r = Cudd_Not(r); + } else { + r = (t == e) ? t : cuddUniqueInter(dd, index, t, e); + if (r == NULL) { + Cudd_IterDerefBdd(dd, e); + Cudd_IterDerefBdd(dd, t); + return(NULL); + } + } + cuddDeref(t); + cuddDeref(e); + + cuddCacheInsert2(dd, Cudd_bddConstrain, f, c, r); + return(Cudd_NotCond(r,comple)); + +} /* end of cuddBddConstrainRecur */ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Cudd_bddRestrict.] + + Description [Performs the recursive step of Cudd_bddRestrict. + Returns the restricted BDD if successful; otherwise NULL.] + + SideEffects [None] + + SeeAlso [Cudd_bddRestrict] + +******************************************************************************/ +DdNode * +cuddBddRestrictRecur( + DdManager * dd, + DdNode * f, + DdNode * c) +{ + DdNode *Fv, *Fnv, *Cv, *Cnv, *t, *e, *r, *one, *zero; + unsigned int topf, topc; + int index; + int comple = 0; + + statLine(dd); + one = DD_ONE(dd); + zero = Cudd_Not(one); + + /* Trivial cases */ + if (c == one) return(f); + if (c == zero) return(zero); + if (Cudd_IsConstant(f)) return(f); + if (f == c) return(one); + if (f == Cudd_Not(c)) return(zero); + + /* Make canonical to increase the utilization of the cache. */ + if (Cudd_IsComplement(f)) { + f = Cudd_Not(f); + comple = 1; + } + /* Now f is a regular pointer to a non-constant node; c is also + ** non-constant, but may be complemented. + */ + + /* Check the cache. */ + r = cuddCacheLookup2(dd, Cudd_bddRestrict, f, c); + if (r != NULL) { + return(Cudd_NotCond(r,comple)); + } + + topf = dd->perm[f->index]; + topc = dd->perm[Cudd_Regular(c)->index]; + + if (topc < topf) { /* abstract top variable from c */ + DdNode *d, *s1, *s2; + + /* Find complements of cofactors of c. */ + if (Cudd_IsComplement(c)) { + s1 = cuddT(Cudd_Regular(c)); + s2 = cuddE(Cudd_Regular(c)); + } else { + s1 = Cudd_Not(cuddT(c)); + s2 = Cudd_Not(cuddE(c)); + } + /* Take the OR by applying DeMorgan. */ + d = cuddBddAndRecur(dd, s1, s2); + if (d == NULL) return(NULL); + d = Cudd_Not(d); + cuddRef(d); + r = cuddBddRestrictRecur(dd, f, d); + if (r == NULL) { + Cudd_IterDerefBdd(dd, d); + return(NULL); + } + cuddRef(r); + Cudd_IterDerefBdd(dd, d); + cuddCacheInsert2(dd, Cudd_bddRestrict, f, c, r); + cuddDeref(r); + return(Cudd_NotCond(r,comple)); + } + + /* Recursive step. Here topf <= topc. */ + index = f->index; + Fv = cuddT(f); Fnv = cuddE(f); + if (topc == topf) { + Cv = cuddT(Cudd_Regular(c)); Cnv = cuddE(Cudd_Regular(c)); + if (Cudd_IsComplement(c)) { + Cv = Cudd_Not(Cv); + Cnv = Cudd_Not(Cnv); + } + } else { + Cv = Cnv = c; + } + + if (!Cudd_IsConstant(Cv)) { + t = cuddBddRestrictRecur(dd, Fv, Cv); + if (t == NULL) return(NULL); + } else if (Cv == one) { + t = Fv; + } else { /* Cv == zero: return(Fnv @ Cnv) */ + if (Cnv == one) { + r = Fnv; + } else { + r = cuddBddRestrictRecur(dd, Fnv, Cnv); + if (r == NULL) return(NULL); + } + return(Cudd_NotCond(r,comple)); + } + cuddRef(t); + + if (!Cudd_IsConstant(Cnv)) { + e = cuddBddRestrictRecur(dd, Fnv, Cnv); + if (e == NULL) { + Cudd_IterDerefBdd(dd, t); + return(NULL); + } + } else if (Cnv == one) { + e = Fnv; + } else { /* Cnv == zero: return (Fv @ Cv) previously computed */ + cuddDeref(t); + return(Cudd_NotCond(t,comple)); + } + cuddRef(e); + + if (Cudd_IsComplement(t)) { + t = Cudd_Not(t); + e = Cudd_Not(e); + r = (t == e) ? t : cuddUniqueInter(dd, index, t, e); + if (r == NULL) { + Cudd_IterDerefBdd(dd, e); + Cudd_IterDerefBdd(dd, t); + return(NULL); + } + r = Cudd_Not(r); + } else { + r = (t == e) ? t : cuddUniqueInter(dd, index, t, e); + if (r == NULL) { + Cudd_IterDerefBdd(dd, e); + Cudd_IterDerefBdd(dd, t); + return(NULL); + } + } + cuddDeref(t); + cuddDeref(e); + + cuddCacheInsert2(dd, Cudd_bddRestrict, f, c, r); + return(Cudd_NotCond(r,comple)); + +} /* end of cuddBddRestrictRecur */ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Cudd_addConstrain.] + + Description [Performs the recursive step of Cudd_addConstrain. + Returns a pointer to the result if successful; NULL otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_addConstrain] + +******************************************************************************/ +DdNode * +cuddAddConstrainRecur( + DdManager * dd, + DdNode * f, + DdNode * c) +{ + DdNode *Fv, *Fnv, *Cv, *Cnv, *t, *e, *r; + DdNode *one, *zero; + unsigned int topf, topc; + int index; + + statLine(dd); + one = DD_ONE(dd); + zero = DD_ZERO(dd); + + /* Trivial cases. */ + if (c == one) return(f); + if (c == zero) return(zero); + if (Cudd_IsConstant(f)) return(f); + if (f == c) return(one); + + /* Now f and c are non-constant. */ + + /* Check the cache. */ + r = cuddCacheLookup2(dd, Cudd_addConstrain, f, c); + if (r != NULL) { + return(r); + } + + /* Recursive step. */ + topf = dd->perm[f->index]; + topc = dd->perm[c->index]; + if (topf <= topc) { + index = f->index; + Fv = cuddT(f); Fnv = cuddE(f); + } else { + index = c->index; + Fv = Fnv = f; + } + if (topc <= topf) { + Cv = cuddT(c); Cnv = cuddE(c); + } else { + Cv = Cnv = c; + } + + if (!Cudd_IsConstant(Cv)) { + t = cuddAddConstrainRecur(dd, Fv, Cv); + if (t == NULL) + return(NULL); + } else if (Cv == one) { + t = Fv; + } else { /* Cv == zero: return Fnv @ Cnv */ + if (Cnv == one) { + r = Fnv; + } else { + r = cuddAddConstrainRecur(dd, Fnv, Cnv); + if (r == NULL) + return(NULL); + } + return(r); + } + cuddRef(t); + + if (!Cudd_IsConstant(Cnv)) { + e = cuddAddConstrainRecur(dd, Fnv, Cnv); + if (e == NULL) { + Cudd_RecursiveDeref(dd, t); + return(NULL); + } + } else if (Cnv == one) { + e = Fnv; + } else { /* Cnv == zero: return Fv @ Cv previously computed */ + cuddDeref(t); + return(t); + } + cuddRef(e); + + r = (t == e) ? t : cuddUniqueInter(dd, index, t, e); + if (r == NULL) { + Cudd_RecursiveDeref(dd, e); + Cudd_RecursiveDeref(dd, t); + return(NULL); + } + cuddDeref(t); + cuddDeref(e); + + cuddCacheInsert2(dd, Cudd_addConstrain, f, c, r); + return(r); + +} /* end of cuddAddConstrainRecur */ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Cudd_addRestrict.] + + Description [Performs the recursive step of Cudd_addRestrict. + Returns the restricted ADD if successful; otherwise NULL.] + + SideEffects [None] + + SeeAlso [Cudd_addRestrict] + +******************************************************************************/ +DdNode * +cuddAddRestrictRecur( + DdManager * dd, + DdNode * f, + DdNode * c) +{ + DdNode *Fv, *Fnv, *Cv, *Cnv, *t, *e, *r, *one, *zero; + unsigned int topf, topc; + int index; + + statLine(dd); + one = DD_ONE(dd); + zero = DD_ZERO(dd); + + /* Trivial cases */ + if (c == one) return(f); + if (c == zero) return(zero); + if (Cudd_IsConstant(f)) return(f); + if (f == c) return(one); + + /* Now f and c are non-constant. */ + + /* Check the cache. */ + r = cuddCacheLookup2(dd, Cudd_addRestrict, f, c); + if (r != NULL) { + return(r); + } + + topf = dd->perm[f->index]; + topc = dd->perm[c->index]; + + if (topc < topf) { /* abstract top variable from c */ + DdNode *d, *s1, *s2; + + /* Find cofactors of c. */ + s1 = cuddT(c); + s2 = cuddE(c); + /* Take the OR by applying DeMorgan. */ + d = cuddAddApplyRecur(dd, Cudd_addOr, s1, s2); + if (d == NULL) return(NULL); + cuddRef(d); + r = cuddAddRestrictRecur(dd, f, d); + if (r == NULL) { + Cudd_RecursiveDeref(dd, d); + return(NULL); + } + cuddRef(r); + Cudd_RecursiveDeref(dd, d); + cuddCacheInsert2(dd, Cudd_addRestrict, f, c, r); + cuddDeref(r); + return(r); + } + + /* Recursive step. Here topf <= topc. */ + index = f->index; + Fv = cuddT(f); Fnv = cuddE(f); + if (topc == topf) { + Cv = cuddT(c); Cnv = cuddE(c); + } else { + Cv = Cnv = c; + } + + if (!Cudd_IsConstant(Cv)) { + t = cuddAddRestrictRecur(dd, Fv, Cv); + if (t == NULL) return(NULL); + } else if (Cv == one) { + t = Fv; + } else { /* Cv == zero: return(Fnv @ Cnv) */ + if (Cnv == one) { + r = Fnv; + } else { + r = cuddAddRestrictRecur(dd, Fnv, Cnv); + if (r == NULL) return(NULL); + } + return(r); + } + cuddRef(t); + + if (!Cudd_IsConstant(Cnv)) { + e = cuddAddRestrictRecur(dd, Fnv, Cnv); + if (e == NULL) { + Cudd_RecursiveDeref(dd, t); + return(NULL); + } + } else if (Cnv == one) { + e = Fnv; + } else { /* Cnv == zero: return (Fv @ Cv) previously computed */ + cuddDeref(t); + return(t); + } + cuddRef(e); + + r = (t == e) ? t : cuddUniqueInter(dd, index, t, e); + if (r == NULL) { + Cudd_RecursiveDeref(dd, e); + Cudd_RecursiveDeref(dd, t); + return(NULL); + } + cuddDeref(t); + cuddDeref(e); + + cuddCacheInsert2(dd, Cudd_addRestrict, f, c, r); + return(r); + +} /* end of cuddAddRestrictRecur */ + + + +/**Function******************************************************************** + + Synopsis [Performs safe minimization of a BDD.] + + Description [Performs safe minimization of a BDD. Given the BDD + f of a function to be minimized and a BDD + c representing the care set, Cudd_bddLICompaction + produces the BDD of a function that agrees with f + wherever c is 1. Safe minimization means that the size + of the result is guaranteed not to exceed the size of + f. This function is based on the DAC97 paper by Hong et + al.. Returns a pointer to the result if successful; NULL + otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_bddLICompaction] + +******************************************************************************/ +DdNode * +cuddBddLICompaction( + DdManager * dd /* manager */, + DdNode * f /* function to be minimized */, + DdNode * c /* constraint (care set) */) +{ + st_table *marktable, *markcache, *buildcache; + DdNode *res, *zero; + + zero = Cudd_Not(DD_ONE(dd)); + if (c == zero) return(zero); + + /* We need to use local caches for both steps of this operation. + ** The results of the edge marking step are only valid as long as the + ** edge markings themselves are available. However, the edge markings + ** are lost at the end of one invocation of Cudd_bddLICompaction. + ** Hence, the cache entries for the edge marking step must be + ** invalidated at the end of this function. + ** For the result of the building step we argue as follows. The result + ** for a node and a given constrain depends on the BDD in which the node + ** appears. Hence, the same node and constrain may give different results + ** in successive invocations. + */ + marktable = st_init_table(st_ptrcmp,st_ptrhash); + if (marktable == NULL) { + return(NULL); + } + markcache = st_init_table(MarkCacheCompare,MarkCacheHash); + if (markcache == NULL) { + st_free_table(marktable); + return(NULL); + } + if (cuddBddLICMarkEdges(dd,f,c,marktable,markcache) == CUDD_OUT_OF_MEM) { + st_foreach(markcache, MarkCacheCleanUp, NULL); + st_free_table(marktable); + st_free_table(markcache); + return(NULL); + } + st_foreach(markcache, MarkCacheCleanUp, NULL); + st_free_table(markcache); + buildcache = st_init_table(st_ptrcmp,st_ptrhash); + if (buildcache == NULL) { + st_free_table(marktable); + return(NULL); + } + res = cuddBddLICBuildResult(dd,f,buildcache,marktable); + st_free_table(buildcache); + st_free_table(marktable); + return(res); + +} /* end of cuddBddLICompaction */ + + +/*---------------------------------------------------------------------------*/ +/* Definition of static functions */ +/*---------------------------------------------------------------------------*/ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Cudd_bddConstrainDecomp.] + + Description [Performs the recursive step of Cudd_bddConstrainDecomp. + Returns f super (i) if successful; otherwise NULL.] + + SideEffects [None] + + SeeAlso [Cudd_bddConstrainDecomp] + +******************************************************************************/ +static int +cuddBddConstrainDecomp( + DdManager * dd, + DdNode * f, + DdNode ** decomp) +{ + DdNode *F, *fv, *fvn; + DdNode *fAbs; + DdNode *result; + int ok; + + if (Cudd_IsConstant(f)) return(1); + /* Compute complements of cofactors. */ + F = Cudd_Regular(f); + fv = cuddT(F); + fvn = cuddE(F); + if (F == f) { + fv = Cudd_Not(fv); + fvn = Cudd_Not(fvn); + } + /* Compute abstraction of top variable. */ + fAbs = cuddBddAndRecur(dd, fv, fvn); + if (fAbs == NULL) { + return(0); + } + cuddRef(fAbs); + fAbs = Cudd_Not(fAbs); + /* Recursively find the next abstraction and the components of the + ** decomposition. */ + ok = cuddBddConstrainDecomp(dd, fAbs, decomp); + if (ok == 0) { + Cudd_IterDerefBdd(dd,fAbs); + return(0); + } + /* Compute the component of the decomposition corresponding to the + ** top variable and store it in the decomposition array. */ + result = cuddBddConstrainRecur(dd, f, fAbs); + if (result == NULL) { + Cudd_IterDerefBdd(dd,fAbs); + return(0); + } + cuddRef(result); + decomp[F->index] = result; + Cudd_IterDerefBdd(dd, fAbs); + return(1); + +} /* end of cuddBddConstrainDecomp */ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Cudd_bddCharToVect.] + + Description [Performs the recursive step of Cudd_bddCharToVect. + This function maintains the invariant that f is non-zero. + Returns the i-th component of the vector if successful; otherwise NULL.] + + SideEffects [None] + + SeeAlso [Cudd_bddCharToVect] + +******************************************************************************/ +static DdNode * +cuddBddCharToVect( + DdManager * dd, + DdNode * f, + DdNode * x) +{ + unsigned int topf; + unsigned int level; + int comple; + + DdNode *one, *zero, *res, *F, *fT, *fE, *T, *E; + + statLine(dd); + /* Check the cache. */ + res = cuddCacheLookup2(dd, cuddBddCharToVect, f, x); + if (res != NULL) { + return(res); + } + + F = Cudd_Regular(f); + + topf = cuddI(dd,F->index); + level = dd->perm[x->index]; + + if (topf > level) return(x); + + one = DD_ONE(dd); + zero = Cudd_Not(one); + + comple = F != f; + fT = Cudd_NotCond(cuddT(F),comple); + fE = Cudd_NotCond(cuddE(F),comple); + + if (topf == level) { + if (fT == zero) return(zero); + if (fE == zero) return(one); + return(x); + } + + /* Here topf < level. */ + if (fT == zero) return(cuddBddCharToVect(dd, fE, x)); + if (fE == zero) return(cuddBddCharToVect(dd, fT, x)); + + T = cuddBddCharToVect(dd, fT, x); + if (T == NULL) { + return(NULL); + } + cuddRef(T); + E = cuddBddCharToVect(dd, fE, x); + if (E == NULL) { + Cudd_IterDerefBdd(dd,T); + return(NULL); + } + cuddRef(E); + res = cuddBddIteRecur(dd, dd->vars[F->index], T, E); + if (res == NULL) { + Cudd_IterDerefBdd(dd,T); + Cudd_IterDerefBdd(dd,E); + return(NULL); + } + cuddDeref(T); + cuddDeref(E); + cuddCacheInsert2(dd, cuddBddCharToVect, f, x, res); + return(res); + +} /* end of cuddBddCharToVect */ + + +/**Function******************************************************************** + + Synopsis [Performs the edge marking step of Cudd_bddLICompaction.] + + Description [Performs the edge marking step of Cudd_bddLICompaction. + Returns the LUB of the markings of the two outgoing edges of f + if successful; otherwise CUDD_OUT_OF_MEM.] + + SideEffects [None] + + SeeAlso [Cudd_bddLICompaction cuddBddLICBuildResult] + +******************************************************************************/ +static int +cuddBddLICMarkEdges( + DdManager * dd, + DdNode * f, + DdNode * c, + st_table * table, + st_table * cache) +{ + DdNode *Fv, *Fnv, *Cv, *Cnv; + DdNode *one, *zero; + unsigned int topf, topc; + int 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: +
        +
      • cuddGa() +
      + Static procedures included in this module: +
        +
      • make_random() +
      • sift_up() +
      • build_dd() +
      • largest() +
      • rand_int() +
      • array_hash() +
      • array_compare() +
      • find_best() +
      • find_average_fitness() +
      • PMX() +
      • roulette() +
      + + 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: +
        +
      • Cudd_MakeTreeNode() +
      + Internal procedures included in this file: +
        +
      • cuddTreeSifting() +
      + Static procedures included in this module: +
        +
      • ddTreeSiftingAux() +
      • ddCountInternalMtrNodes() +
      • ddReorderChildren() +
      • ddFindNodeHiLo() +
      • ddUniqueCompareGroup() +
      • ddGroupSifting() +
      • ddCreateGroup() +
      • ddGroupSiftingAux() +
      • ddGroupSiftingUp() +
      • ddGroupSiftingDown() +
      • ddGroupMove() +
      • ddGroupMoveBackward() +
      • ddGroupSiftingBackward() +
      • ddMergeGroups() +
      • ddDissolveGroup() +
      • ddNoCheck() +
      • ddSecDiffCheck() +
      • ddExtSymmCheck() +
      • ddVarGroupCheck() +
      • ddSetVarHandled() +
      • ddResetVarHandled() +
      • ddIsVarHandled() +
      ] + + 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: +
        +
      • Cudd_addHarwell() +
      + ] + + 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: +
      + x\[0\] y\[0\] x\[1\] y\[1\] ... +
      + 0 is the most significant bit. On input, nx and ny hold the numbers + of row and column variables already in existence. On output, they + hold the numbers of row and column variables actually used by the + matrix. m and n are set to the numbers of rows and columns of the + matrix. Their values on input are immaterial. Returns 1 on + success; 0 otherwise. The ADD for the sparse matrix is returned in + E, and its reference count is > 0.] + + SideEffects [None] + + SeeAlso [Cudd_addRead Cudd_bddRead] + +******************************************************************************/ +int +Cudd_addHarwell( + FILE * fp /* pointer to the input file */, + DdManager * dd /* DD manager */, + DdNode ** E /* characteristic function of the graph */, + DdNode *** x /* array of row variables */, + DdNode *** y /* array of column variables */, + DdNode *** xn /* array of complemented row variables */, + DdNode *** yn_ /* array of complemented column variables */, + int * nx /* number or row variables */, + int * ny /* number or column variables */, + int * m /* number of rows */, + int * n /* number of columns */, + int bx /* first index of row variables */, + int sx /* step of row variables */, + int by /* first index of column variables */, + int sy /* step of column variables */, + int pr /* verbosity level */) +{ + DdNode *one, *zero; + DdNode *w; + DdNode *cubex, *cubey, *minterm1; + int u, v, err, i, j, nv; + double val; + DdNode **lx, **ly, **lxn, **lyn; /* local copies of x, y, xn, yn_ */ + int lnx, lny; /* local copies of nx and ny */ + char title[73], key[9], mxtype[4], rhstyp[4]; + int totcrd, ptrcrd, indcrd, valcrd, rhscrd, + nrow, ncol, nnzero, neltvl, + nrhs, nrhsix; + int *colptr, *rowind; +#if 0 + int nguess, nexact; + int *rhsptr, *rhsind; +#endif + + if (*nx < 0 || *ny < 0) return(0); + + one = DD_ONE(dd); + zero = DD_ZERO(dd); + + /* Read the header */ + err = fscanf(fp, "%72c %8c", title, key); + if (err == EOF) { + return(0); + } else if (err != 2) { + return(0); + } + title[72] = (char) 0; + key[8] = (char) 0; + + err = fscanf(fp, "%d %d %d %d %d", &totcrd, &ptrcrd, &indcrd, + &valcrd, &rhscrd); + if (err == EOF) { + return(0); + } else if (err != 5) { + return(0); + } + + err = fscanf(fp, "%3s %d %d %d %d", mxtype, &nrow, &ncol, + &nnzero, &neltvl); + if (err == EOF) { + return(0); + } else if (err != 5) { + return(0); + } + + /* Skip FORTRAN formats */ + if (rhscrd == 0) { + err = fscanf(fp, "%*s %*s %*s \n"); + } else { + err = fscanf(fp, "%*s %*s %*s %*s \n"); + } + if (err == EOF) { + return(0); + } else if (err != 0) { + return(0); + } + + /* Print out some stuff if requested to be verbose */ + if (pr>0) { + (void) fprintf(dd->out,"%s: type %s, %d rows, %d columns, %d entries\n", key, + mxtype, nrow, ncol, nnzero); + if (pr>1) (void) fprintf(dd->out,"%s\n", title); + } + + /* Check matrix type */ + if (mxtype[0] != 'R' || mxtype[1] != 'U' || mxtype[2] != 'A') { + (void) fprintf(dd->err,"%s: Illegal matrix type: %s\n", + key, mxtype); + return(0); + } + if (neltvl != 0) return(0); + + /* Read optional 5-th line */ + if (rhscrd != 0) { + err = fscanf(fp, "%3c %d %d", rhstyp, &nrhs, &nrhsix); + if (err == EOF) { + return(0); + } else if (err != 3) { + return(0); + } + rhstyp[3] = (char) 0; + if (rhstyp[0] != 'F') { + (void) fprintf(dd->err, + "%s: Sparse right-hand side not yet supported\n", key); + return(0); + } + if (pr>0) (void) fprintf(dd->out,"%d right-hand side(s)\n", nrhs); + } else { + nrhs = 0; + } + + /* Compute the number of variables */ + + /* row and column numbers start from 0 */ + u = nrow - 1; + for (i=0; u > 0; i++) { + u >>= 1; + } + lnx = i; + if (nrhs == 0) { + v = ncol - 1; + } else { + v = 2* (ddMax(ncol, nrhs) - 1); + } + for (i=0; v > 0; i++) { + v >>= 1; + } + lny = i; + + /* Allocate or reallocate arrays for variables as needed */ + if (*nx == 0) { + if (lnx > 0) { + *x = lx = ALLOC(DdNode *,lnx); + if (lx == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(0); + } + *xn = lxn = ALLOC(DdNode *,lnx); + if (lxn == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(0); + } + } else { + *x = *xn = NULL; + } + } else if (lnx > *nx) { + *x = lx = REALLOC(DdNode *, *x, lnx); + if (lx == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(0); + } + *xn = lxn = REALLOC(DdNode *, *xn, lnx); + if (lxn == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(0); + } + } else { + lx = *x; + lxn = *xn; + } + if (*ny == 0) { + if (lny >0) { + *y = ly = ALLOC(DdNode *,lny); + if (ly == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(0); + } + *yn_ = lyn = ALLOC(DdNode *,lny); + if (lyn == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(0); + } + } else { + *y = *yn_ = NULL; + } + } else if (lny > *ny) { + *y = ly = REALLOC(DdNode *, *y, lny); + if (ly == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(0); + } + *yn_ = lyn = REALLOC(DdNode *, *yn_, lny); + if (lyn == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(0); + } + } else { + ly = *y; + lyn = *yn_; + } + + /* Create new variables as needed */ + for (i= *nx,nv=bx+(*nx)*sx; i < lnx; i++,nv+=sx) { + do { + dd->reordered = 0; + lx[i] = cuddUniqueInter(dd, nv, one, zero); + } while (dd->reordered == 1); + if (lx[i] == NULL) return(0); + cuddRef(lx[i]); + do { + dd->reordered = 0; + lxn[i] = cuddUniqueInter(dd, nv, zero, one); + } while (dd->reordered == 1); + if (lxn[i] == NULL) return(0); + cuddRef(lxn[i]); + } + for (i= *ny,nv=by+(*ny)*sy; i < lny; i++,nv+=sy) { + do { + dd->reordered = 0; + ly[i] = cuddUniqueInter(dd, nv, one, zero); + } while (dd->reordered == 1); + if (ly[i] == NULL) return(0); + cuddRef(ly[i]); + do { + dd->reordered = 0; + lyn[i] = cuddUniqueInter(dd, nv, zero, one); + } while (dd->reordered == 1); + if (lyn[i] == NULL) return(0); + cuddRef(lyn[i]); + } + + /* Update matrix parameters */ + *nx = lnx; + *ny = lny; + *m = nrow; + if (nrhs == 0) { + *n = ncol; + } else { + *n = (1 << (lny - 1)) + nrhs; + } + + /* Read structure data */ + colptr = ALLOC(int, ncol+1); + if (colptr == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(0); + } + rowind = ALLOC(int, nnzero); + if (rowind == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(0); + } + + for (i=0; ierr,"%s: Unexpected colptr[0] (%d)\n", + key,colptr[0]); + FREE(colptr); + FREE(rowind); + return(0); + } + for (i=0; i=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=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=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=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: +
        +
      • Cudd_Init() +
      • Cudd_Quit() +
      + Internal procedures included in this module: +
        +
      • cuddZddInitUniv() +
      • cuddZddFreeUniv() +
      + ] + + 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 +#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 + node is a constant node, the result is unpredictable. + The pointer passed to cuddT must be regular.] + + SideEffects [none] + + SeeAlso [Cudd_T] + +******************************************************************************/ +#define cuddT(node) ((node)->type.kids.T) + + +/**Macro*********************************************************************** + + Synopsis [Returns the else child of an internal node.] + + Description [Returns the else child of an internal node. If + node is a constant node, the result is unpredictable. + The pointer passed to cuddE must be regular.] + + SideEffects [none] + + SeeAlso [Cudd_E] + +******************************************************************************/ +#define cuddE(node) ((node)->type.kids.E) + + +/**Macro*********************************************************************** + + Synopsis [Returns the value of a constant node.] + + Description [Returns the value of a constant node. If + node is an internal node, the result is unpredictable. + The pointer passed to cuddV must be regular.] + + SideEffects [none] + + SeeAlso [Cudd_V] + +******************************************************************************/ +#define cuddV(node) ((node)->type.value) + + +/**Macro*********************************************************************** + + Synopsis [Finds the current position of variable index in the + order.] + + Description [Finds the current position of variable index in the + order. This macro duplicates the functionality of Cudd_ReadPerm, + but it does not check for out-of-bounds indices and it is more + efficient.] + + SideEffects [none] + + SeeAlso [Cudd_ReadPerm] + +******************************************************************************/ +#define cuddI(dd,index) (((index)==CUDD_CONST_INDEX)?(int)(index):(dd)->perm[(index)]) + + +/**Macro*********************************************************************** + + Synopsis [Finds the current position of ZDD variable index in the + order.] + + Description [Finds the current position of ZDD variable index in the + order. This macro duplicates the functionality of Cudd_ReadPermZdd, + but it does not check for out-of-bounds indices and it is more + efficient.] + + SideEffects [none] + + SeeAlso [Cudd_ReadPermZdd] + +******************************************************************************/ +#define cuddIZ(dd,index) (((index)==CUDD_CONST_INDEX)?(int)(index):(dd)->permZ[(index)]) + + +/**Macro*********************************************************************** + + Synopsis [Hash function for the unique table.] + + Description [] + + SideEffects [none] + + SeeAlso [ddCHash ddCHash2] + +******************************************************************************/ +#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4 +#define ddHash(f,g,s) \ +((((unsigned)(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: +
        +
      • cuddSetInteract() +
      • cuddTestInteract() +
      • cuddInitInteract() +
      + Static procedures included in this file: +
        +
      • ddSuppInteract() +
      • ddClearLocal() +
      • ddUpdateInteract() +
      • ddClearGlobal() +
      + 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.

      + 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: +

        +
      • cuddLocalCacheInit() +
      • cuddLocalCacheQuit() +
      • cuddLocalCacheInsert() +
      • cuddLocalCacheLookup() +
      • cuddLocalCacheClearDead() +
      • cuddLocalCacheClearAll() +
      • cuddLocalCacheProfile() +
      • cuddHashTableInit() +
      • cuddHashTableQuit() +
      • cuddHashTableInsert() +
      • cuddHashTableLookup() +
      • cuddHashTableInsert2() +
      • cuddHashTableLookup2() +
      • cuddHashTableInsert3() +
      • cuddHashTableLookup3() +
      + Static procedures included in this module: +
        +
      • cuddLocalCacheResize() +
      • ddLCHash() +
      • cuddLocalCacheAddToList() +
      • cuddLocalCacheRemoveFromList() +
      • cuddHashTableResize() +
      • cuddHashTableAlloc() +
      ] + + 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: +
        +
      • cuddLevelQueueInit() +
      • cuddLevelQueueQuit() +
      • cuddLevelQueueEnqueue() +
      • cuddLevelQueueDequeue() +
      + Static procedures included in this module: +
        +
      • hashLookup() +
      • hashInsert() +
      • hashDelete() +
      • hashResize() +
      + ] + + 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: +
        +
      • cuddLinearAndSifting() +
      + Static procedures included in this module: +
        +
      • ddLinearUniqueCompare() +
      • ddLinearAndSiftingAux() +
      • ddLinearAndSiftingUp() +
      • ddLinearAndSiftingDown() +
      • ddLinearAndSiftingBackward() +
      • ddUndoMoves() +
      • ddUpdateInteractionMatrix() +
      • cuddLinearInPlace() +
      • cuddInitLinear() +
      • cuddResizeLinear() +
      • cuddXorLinear() +
      ] + + 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. +
        +
      1. Order all the variables according to the number of entries + in each unique table. +
      2. 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. +
      3. Select the best permutation. +
      4. Repeat 3 and 4 for all variables. +
      + 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 < + 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: +
        +
      • Cudd_bddLiteralSetIntersection() +
      + Internal procedures included in this file: +
        +
      • cuddBddLiteralSetIntersectionRecur() +
      ] + + 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: +
        +
      • Cudd_addMatrixMultiply() +
      • Cudd_addTimesPlus() +
      • Cudd_addTriangle() +
      • Cudd_addOuterSum() +
      + Static procedures included in this module: +
        +
      • addMMRecur() +
      • addTriangleRecur() +
      • cuddAddOuterSumRecur() +
      ] + + 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: +
        +
      • Cudd_PrioritySelect() +
      • Cudd_Xgty() +
      • Cudd_Xeqy() +
      • Cudd_addXeqy() +
      • Cudd_Dxygtdxz() +
      • Cudd_Dxygtdyz() +
      • Cudd_CProjection() +
      • Cudd_addHamming() +
      • Cudd_MinHammingDist() +
      • Cudd_bddClosestCube() +
      + Internal procedures included in this module: +
        +
      • cuddCProjectionRecur() +
      • cuddBddClosestCube() +
      + Static procedures included in this module: +
        +
      • cuddMinHammingDistRecur() +
      • separateCube() +
      • createResult() +
      + ] + + 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: +
        +
      • When extracting representatives from an equivalence relation, + Cudd_CProjection has the advantage of nor requiring the auxiliary + variables. +
      • 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). +
      + ] + + 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 > y.] + + Description [This function generates a BDD for the function x > y. + Both x and y are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\] and + y\[0\] y\[1\] ... y\[N-1\], with 0 the most significant bit. + The BDD is built bottom-up. + It has 3*N-1 internal nodes, if the variables are ordered as follows: + x\[0\] y\[0\] x\[1\] y\[1\] ... x\[N-1\] y\[N-1\]. + Argument z is not used by Cudd_Xgty: it is included to make it + call-compatible to Cudd_Dxygtdxz and Cudd_Dxygtdyz.] + + SideEffects [None] + + SeeAlso [Cudd_PrioritySelect Cudd_Dxygtdxz Cudd_Dxygtdyz] + +******************************************************************************/ +DdNode * +Cudd_Xgty( + DdManager * dd /* DD manager */, + int N /* number of x and y variables */, + DdNode ** z /* array of z variables: unused */, + DdNode ** x /* array of x variables */, + DdNode ** y /* array of y variables */) +{ + DdNode *u, *v, *w; + int i; + + /* Build bottom part of BDD outside loop. */ + u = Cudd_bddAnd(dd, x[N-1], Cudd_Not(y[N-1])); + if (u == NULL) return(NULL); + cuddRef(u); + + /* Loop to build the rest of the BDD. */ + for (i = N-2; i >= 0; i--) { + v = Cudd_bddAnd(dd, y[i], Cudd_Not(u)); + if (v == NULL) { + Cudd_RecursiveDeref(dd, u); + return(NULL); + } + cuddRef(v); + w = Cudd_bddAnd(dd, Cudd_Not(y[i]), u); + if (w == NULL) { + Cudd_RecursiveDeref(dd, u); + Cudd_RecursiveDeref(dd, v); + return(NULL); + } + cuddRef(w); + Cudd_RecursiveDeref(dd, u); + u = Cudd_bddIte(dd, x[i], Cudd_Not(v), w); + if (u == NULL) { + Cudd_RecursiveDeref(dd, v); + Cudd_RecursiveDeref(dd, w); + return(NULL); + } + cuddRef(u); + Cudd_RecursiveDeref(dd, v); + Cudd_RecursiveDeref(dd, w); + + } + cuddDeref(u); + return(u); + +} /* end of Cudd_Xgty */ + + +/**Function******************************************************************** + + Synopsis [Generates a BDD for the function x==y.] + + Description [This function generates a BDD for the function x==y. + Both x and y are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\] and + y\[0\] y\[1\] ... y\[N-1\], with 0 the most significant bit. + The BDD is built bottom-up. + It has 3*N-1 internal nodes, if the variables are ordered as follows: + x\[0\] y\[0\] x\[1\] y\[1\] ... x\[N-1\] y\[N-1\]. ] + + SideEffects [None] + + SeeAlso [Cudd_addXeqy] + +******************************************************************************/ +DdNode * +Cudd_Xeqy( + DdManager * dd /* DD manager */, + int N /* number of x and y variables */, + DdNode ** x /* array of x variables */, + DdNode ** y /* array of y variables */) +{ + DdNode *u, *v, *w; + int i; + + /* Build bottom part of BDD outside loop. */ + u = Cudd_bddIte(dd, x[N-1], y[N-1], Cudd_Not(y[N-1])); + if (u == NULL) return(NULL); + cuddRef(u); + + /* Loop to build the rest of the BDD. */ + for (i = N-2; i >= 0; i--) { + v = Cudd_bddAnd(dd, y[i], u); + if (v == NULL) { + Cudd_RecursiveDeref(dd, u); + return(NULL); + } + cuddRef(v); + w = Cudd_bddAnd(dd, Cudd_Not(y[i]), u); + if (w == NULL) { + Cudd_RecursiveDeref(dd, u); + Cudd_RecursiveDeref(dd, v); + return(NULL); + } + cuddRef(w); + Cudd_RecursiveDeref(dd, u); + u = Cudd_bddIte(dd, x[i], v, w); + if (u == NULL) { + Cudd_RecursiveDeref(dd, v); + Cudd_RecursiveDeref(dd, w); + return(NULL); + } + cuddRef(u); + Cudd_RecursiveDeref(dd, v); + Cudd_RecursiveDeref(dd, w); + } + cuddDeref(u); + return(u); + +} /* end of Cudd_Xeqy */ + + +/**Function******************************************************************** + + Synopsis [Generates an ADD for the function x==y.] + + Description [This function generates an ADD for the function x==y. + Both x and y are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\] and + y\[0\] y\[1\] ... y\[N-1\], with 0 the most significant bit. + The ADD is built bottom-up. + It has 3*N-1 internal nodes, if the variables are ordered as follows: + x\[0\] y\[0\] x\[1\] y\[1\] ... x\[N-1\] y\[N-1\]. ] + + SideEffects [None] + + SeeAlso [Cudd_Xeqy] + +******************************************************************************/ +DdNode * +Cudd_addXeqy( + DdManager * dd /* DD manager */, + int N /* number of x and y variables */, + DdNode ** x /* array of x variables */, + DdNode ** y /* array of y variables */) +{ + DdNode *one, *zero; + DdNode *u, *v, *w; + int i; + + one = DD_ONE(dd); + zero = DD_ZERO(dd); + + /* Build bottom part of ADD outside loop. */ + v = Cudd_addIte(dd, y[N-1], one, zero); + if (v == NULL) return(NULL); + cuddRef(v); + w = Cudd_addIte(dd, y[N-1], zero, one); + if (w == NULL) { + Cudd_RecursiveDeref(dd, v); + return(NULL); + } + cuddRef(w); + u = Cudd_addIte(dd, x[N-1], v, w); + if (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) > d(x,z).] + + Description [This function generates a BDD for the function d(x,y) + > d(x,z); + x, y, and z are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\], + y\[0\] y\[1\] ... y\[N-1\], and z\[0\] z\[1\] ... z\[N-1\], + with 0 the most significant bit. + The distance d(x,y) is defined as: + \sum_{i=0}^{N-1}(|x_i - y_i| \cdot 2^{N-i-1}). + The BDD is built bottom-up. + It has 7*N-3 internal nodes, if the variables are ordered as follows: + x\[0\] y\[0\] z\[0\] x\[1\] y\[1\] z\[1\] ... x\[N-1\] y\[N-1\] z\[N-1\]. ] + + SideEffects [None] + + SeeAlso [Cudd_PrioritySelect Cudd_Dxygtdyz Cudd_Xgty Cudd_bddAdjPermuteX] + +******************************************************************************/ +DdNode * +Cudd_Dxygtdxz( + DdManager * dd /* DD manager */, + int N /* number of x, y, and z variables */, + DdNode ** x /* array of x variables */, + DdNode ** y /* array of y variables */, + DdNode ** z /* array of z variables */) +{ + DdNode *one, *zero; + DdNode *z1, *z2, *z3, *z4, *y1_, *y2, *x1; + int i; + + one = DD_ONE(dd); + zero = Cudd_Not(one); + + /* Build bottom part of BDD outside loop. */ + y1_ = Cudd_bddIte(dd, y[N-1], one, Cudd_Not(z[N-1])); + if (y1_ == NULL) return(NULL); + cuddRef(y1_); + y2 = Cudd_bddIte(dd, y[N-1], z[N-1], one); + if (y2 == NULL) { + Cudd_RecursiveDeref(dd, y1_); + return(NULL); + } + cuddRef(y2); + x1 = Cudd_bddIte(dd, x[N-1], y1_, y2); + if (x1 == NULL) { + Cudd_RecursiveDeref(dd, y1_); + Cudd_RecursiveDeref(dd, y2); + return(NULL); + } + cuddRef(x1); + Cudd_RecursiveDeref(dd, y1_); + Cudd_RecursiveDeref(dd, y2); + + /* Loop to build the rest of the BDD. */ + for (i = N-2; i >= 0; i--) { + z1 = Cudd_bddIte(dd, z[i], one, Cudd_Not(x1)); + if (z1 == NULL) { + Cudd_RecursiveDeref(dd, x1); + return(NULL); + } + cuddRef(z1); + z2 = Cudd_bddIte(dd, z[i], x1, one); + if (z2 == NULL) { + Cudd_RecursiveDeref(dd, x1); + Cudd_RecursiveDeref(dd, z1); + return(NULL); + } + cuddRef(z2); + z3 = Cudd_bddIte(dd, z[i], one, x1); + if (z3 == NULL) { + Cudd_RecursiveDeref(dd, x1); + Cudd_RecursiveDeref(dd, z1); + Cudd_RecursiveDeref(dd, z2); + return(NULL); + } + cuddRef(z3); + z4 = Cudd_bddIte(dd, z[i], x1, zero); + if (z4 == NULL) { + Cudd_RecursiveDeref(dd, x1); + Cudd_RecursiveDeref(dd, z1); + Cudd_RecursiveDeref(dd, z2); + Cudd_RecursiveDeref(dd, z3); + return(NULL); + } + cuddRef(z4); + Cudd_RecursiveDeref(dd, x1); + y1_ = Cudd_bddIte(dd, y[i], z2, Cudd_Not(z1)); + if (y1_ == NULL) { + Cudd_RecursiveDeref(dd, z1); + Cudd_RecursiveDeref(dd, z2); + Cudd_RecursiveDeref(dd, z3); + Cudd_RecursiveDeref(dd, z4); + return(NULL); + } + cuddRef(y1_); + y2 = Cudd_bddIte(dd, y[i], z4, z3); + if (y2 == NULL) { + Cudd_RecursiveDeref(dd, z1); + Cudd_RecursiveDeref(dd, z2); + Cudd_RecursiveDeref(dd, z3); + Cudd_RecursiveDeref(dd, z4); + Cudd_RecursiveDeref(dd, y1_); + return(NULL); + } + cuddRef(y2); + Cudd_RecursiveDeref(dd, z1); + Cudd_RecursiveDeref(dd, z2); + Cudd_RecursiveDeref(dd, z3); + Cudd_RecursiveDeref(dd, z4); + x1 = Cudd_bddIte(dd, x[i], y1_, y2); + if (x1 == NULL) { + Cudd_RecursiveDeref(dd, y1_); + Cudd_RecursiveDeref(dd, y2); + return(NULL); + } + cuddRef(x1); + Cudd_RecursiveDeref(dd, y1_); + Cudd_RecursiveDeref(dd, y2); + } + cuddDeref(x1); + return(Cudd_Not(x1)); + +} /* end of Cudd_Dxygtdxz */ + + +/**Function******************************************************************** + + Synopsis [Generates a BDD for the function d(x,y) > d(y,z).] + + Description [This function generates a BDD for the function d(x,y) + > d(y,z); + x, y, and z are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\], + y\[0\] y\[1\] ... y\[N-1\], and z\[0\] z\[1\] ... z\[N-1\], + with 0 the most significant bit. + The distance d(x,y) is defined as: + \sum_{i=0}^{N-1}(|x_i - y_i| \cdot 2^{N-i-1}). + The BDD is built bottom-up. + It has 7*N-3 internal nodes, if the variables are ordered as follows: + x\[0\] y\[0\] z\[0\] x\[1\] y\[1\] z\[1\] ... x\[N-1\] y\[N-1\] z\[N-1\]. ] + + SideEffects [None] + + SeeAlso [Cudd_PrioritySelect Cudd_Dxygtdxz Cudd_Xgty Cudd_bddAdjPermuteX] + +******************************************************************************/ +DdNode * +Cudd_Dxygtdyz( + DdManager * dd /* DD manager */, + int N /* number of x, y, and z variables */, + DdNode ** x /* array of x variables */, + DdNode ** y /* array of y variables */, + DdNode ** z /* array of z variables */) +{ + DdNode *one, *zero; + DdNode *z1, *z2, *z3, *z4, *y1_, *y2, *x1; + int i; + + one = DD_ONE(dd); + zero = Cudd_Not(one); + + /* Build bottom part of BDD outside loop. */ + y1_ = Cudd_bddIte(dd, y[N-1], one, z[N-1]); + if (y1_ == NULL) return(NULL); + cuddRef(y1_); + y2 = Cudd_bddIte(dd, y[N-1], z[N-1], zero); + if (y2 == NULL) { + Cudd_RecursiveDeref(dd, y1_); + return(NULL); + } + cuddRef(y2); + x1 = Cudd_bddIte(dd, x[N-1], y1_, Cudd_Not(y2)); + if (x1 == NULL) { + Cudd_RecursiveDeref(dd, y1_); + Cudd_RecursiveDeref(dd, y2); + return(NULL); + } + cuddRef(x1); + Cudd_RecursiveDeref(dd, y1_); + Cudd_RecursiveDeref(dd, y2); + + /* Loop to build the rest of the BDD. */ + for (i = N-2; i >= 0; i--) { + z1 = Cudd_bddIte(dd, z[i], x1, zero); + if (z1 == NULL) { + Cudd_RecursiveDeref(dd, x1); + return(NULL); + } + cuddRef(z1); + z2 = Cudd_bddIte(dd, z[i], x1, one); + if (z2 == NULL) { + Cudd_RecursiveDeref(dd, x1); + Cudd_RecursiveDeref(dd, z1); + return(NULL); + } + cuddRef(z2); + z3 = Cudd_bddIte(dd, z[i], one, x1); + if (z3 == NULL) { + Cudd_RecursiveDeref(dd, x1); + Cudd_RecursiveDeref(dd, z1); + Cudd_RecursiveDeref(dd, z2); + return(NULL); + } + cuddRef(z3); + z4 = Cudd_bddIte(dd, z[i], one, Cudd_Not(x1)); + if (z4 == NULL) { + Cudd_RecursiveDeref(dd, x1); + Cudd_RecursiveDeref(dd, z1); + Cudd_RecursiveDeref(dd, z2); + Cudd_RecursiveDeref(dd, z3); + return(NULL); + } + cuddRef(z4); + Cudd_RecursiveDeref(dd, x1); + y1_ = Cudd_bddIte(dd, y[i], z2, z1); + if (y1_ == NULL) { + Cudd_RecursiveDeref(dd, z1); + Cudd_RecursiveDeref(dd, z2); + Cudd_RecursiveDeref(dd, z3); + Cudd_RecursiveDeref(dd, z4); + return(NULL); + } + cuddRef(y1_); + y2 = Cudd_bddIte(dd, y[i], z4, Cudd_Not(z3)); + if (y2 == NULL) { + Cudd_RecursiveDeref(dd, z1); + Cudd_RecursiveDeref(dd, z2); + Cudd_RecursiveDeref(dd, z3); + Cudd_RecursiveDeref(dd, z4); + Cudd_RecursiveDeref(dd, y1_); + return(NULL); + } + cuddRef(y2); + Cudd_RecursiveDeref(dd, z1); + Cudd_RecursiveDeref(dd, z2); + Cudd_RecursiveDeref(dd, z3); + Cudd_RecursiveDeref(dd, z4); + x1 = Cudd_bddIte(dd, x[i], y1_, Cudd_Not(y2)); + if (x1 == NULL) { + Cudd_RecursiveDeref(dd, y1_); + Cudd_RecursiveDeref(dd, y2); + return(NULL); + } + cuddRef(x1); + Cudd_RecursiveDeref(dd, y1_); + Cudd_RecursiveDeref(dd, y2); + } + cuddDeref(x1); + return(Cudd_Not(x1)); + +} /* end of Cudd_Dxygtdyz */ + + +/**Function******************************************************************** + + Synopsis [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: + + H(f) = min(H(f0)+h0,H(f1)+h1) + + 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: +
        +
      • Cudd_addRead() +
      • Cudd_bddRead() +
      ] + + 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.

      + Cudd_addRead produces an ADD that depends on two sets of variables: x + and y. The x variables (x\[0\] ... x\[nx-1\]) encode the row index and + the y variables (y\[0\] ... y\[ny-1\]) encode the column index. + x\[0\] and y\[0\] are the most significant bits in the indices. + The variables may already exist or may be created by the function. + The index of x\[i\] is bx+i*sx, and the index of y\[i\] is by+i*sy.

      + On input, nx and ny hold the numbers + of row and column variables already in existence. On output, they + hold the numbers of row and column variables actually used by the + matrix. When Cudd_addRead creates the variable arrays, + the index of x\[i\] is bx+i*sx, and the index of y\[i\] is by+i*sy. + When some variables already exist Cudd_addRead expects the indices + of the existing x variables to be bx+i*sx, and the indices of the + existing y variables to be by+i*sy.

      + m and n are set to the numbers of rows and columns of the + matrix. Their values on input are immaterial. + The ADD for the + sparse matrix is returned in E, and its reference count is > 0. + Cudd_addRead returns 1 in case of success; 0 otherwise.] + + SideEffects [nx and ny are set to the numbers of row and column + variables. m and n are set to the numbers of rows and columns. x and y + are possibly extended to represent the array of row and column + variables. Similarly for xn and yn_, which hold on return from + Cudd_addRead the complements of the row and column variables.] + + SeeAlso [Cudd_addHarwell Cudd_bddRead] + +******************************************************************************/ +int +Cudd_addRead( + FILE * fp /* input file pointer */, + DdManager * dd /* DD manager */, + DdNode ** E /* characteristic function of the graph */, + DdNode *** x /* array of row variables */, + DdNode *** y /* array of column variables */, + DdNode *** xn /* array of complemented row variables */, + DdNode *** yn_ /* array of complemented column variables */, + int * nx /* number or row variables */, + int * ny /* number or column variables */, + int * m /* number of rows */, + int * n /* number of columns */, + int bx /* first index of row variables */, + int sx /* step of row variables */, + int by /* first index of column variables */, + int sy /* step of column variables */) +{ + DdNode *one, *zero; + DdNode *w, *neW; + DdNode *minterm1; + int u, v, err, i, nv; + int lnx, lny; + CUDD_VALUE_TYPE val; + DdNode **lx, **ly, **lxn, **lyn; + + one = DD_ONE(dd); + zero = DD_ZERO(dd); + + err = fscanf(fp, "%d %d", &u, &v); + if (err == EOF) { + return(0); + } else if (err != 2) { + return(0); + } + + *m = u; + /* Compute the number of x variables. */ + lx = *x; lxn = *xn; + u--; /* row and column numbers start from 0 */ + for (lnx=0; u > 0; lnx++) { + u >>= 1; + } + /* Here we rely on the fact that REALLOC of a null pointer is + ** translates to an ALLOC. + */ + if (lnx > *nx) { + *x = lx = REALLOC(DdNode *, *x, lnx); + if (lx == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(0); + } + *xn = lxn = REALLOC(DdNode *, *xn, lnx); + if (lxn == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(0); + } + } + + *n = v; + /* Compute the number of y variables. */ + ly = *y; lyn = *yn_; + v--; /* row and column numbers start from 0 */ + for (lny=0; v > 0; lny++) { + v >>= 1; + } + /* Here we rely on the fact that REALLOC of a null pointer is + ** translates to an ALLOC. + */ + if (lny > *ny) { + *y = ly = REALLOC(DdNode *, *y, lny); + if (ly == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(0); + } + *yn_ = lyn = REALLOC(DdNode *, *yn_, lny); + if (lyn == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(0); + } + } + + /* Create all new variables. */ + for (i = *nx, nv = bx + (*nx) * sx; i < lnx; i++, nv += sx) { + do { + dd->reordered = 0; + lx[i] = cuddUniqueInter(dd, nv, one, zero); + } while (dd->reordered == 1); + if (lx[i] == NULL) return(0); + cuddRef(lx[i]); + do { + dd->reordered = 0; + lxn[i] = cuddUniqueInter(dd, nv, zero, one); + } while (dd->reordered == 1); + if (lxn[i] == NULL) return(0); + cuddRef(lxn[i]); + } + for (i = *ny, nv = by + (*ny) * sy; i < lny; i++, nv += sy) { + do { + dd->reordered = 0; + ly[i] = cuddUniqueInter(dd, nv, one, zero); + } while (dd->reordered == 1); + if (ly[i] == NULL) return(0); + cuddRef(ly[i]); + do { + dd->reordered = 0; + lyn[i] = cuddUniqueInter(dd, nv, zero, one); + } while (dd->reordered == 1); + if (lyn[i] == NULL) return(0); + cuddRef(lyn[i]); + } + *nx = lnx; + *ny = lny; + + *E = dd->background; /* this call will never cause reordering */ + cuddRef(*E); + + while (! feof(fp)) { + err = fscanf(fp, "%d %d %lf", &u, &v, &val); + if (err == EOF) { + break; + } else if (err != 3) { + return(0); + } else if (u >= *m || v >= *n || u < 0 || v < 0) { + return(0); + } + + minterm1 = one; cuddRef(minterm1); + + /* Build minterm1 corresponding to this arc */ + for (i = lnx - 1; i>=0; i--) { + if (u & 1) { + w = Cudd_addApply(dd, Cudd_addTimes, minterm1, lx[i]); + } else { + w = Cudd_addApply(dd, Cudd_addTimes, minterm1, lxn[i]); + } + if (w == NULL) { + Cudd_RecursiveDeref(dd, minterm1); + return(0); + } + cuddRef(w); + Cudd_RecursiveDeref(dd, minterm1); + minterm1 = w; + u >>= 1; + } + for (i = lny - 1; i>=0; i--) { + if (v & 1) { + w = Cudd_addApply(dd, Cudd_addTimes, minterm1, ly[i]); + } else { + w = Cudd_addApply(dd, Cudd_addTimes, minterm1, lyn[i]); + } + if (w == NULL) { + Cudd_RecursiveDeref(dd, minterm1); + return(0); + } + cuddRef(w); + Cudd_RecursiveDeref(dd, minterm1); + minterm1 = w; + v >>= 1; + } + /* Create new constant node if necessary. + ** This call will never cause reordering. + */ + neW = cuddUniqueConst(dd, val); + if (neW == NULL) { + Cudd_RecursiveDeref(dd, minterm1); + return(0); + } + cuddRef(neW); + + w = Cudd_addIte(dd, minterm1, neW, *E); + if (w == NULL) { + Cudd_RecursiveDeref(dd, minterm1); + Cudd_RecursiveDeref(dd, neW); + return(0); + } + cuddRef(w); + Cudd_RecursiveDeref(dd, minterm1); + Cudd_RecursiveDeref(dd, neW); + Cudd_RecursiveDeref(dd, *E); + *E = w; + } + return(1); + +} /* end of Cudd_addRead */ + + +/**Function******************************************************************** + + Synopsis [Reads in a graph (without labels) given as a list of arcs.] + + Description [Reads in a graph (without labels) given as an adjacency + matrix. The first line of the input contains the numbers of rows and + columns of the adjacency matrix. The remaining lines contain the arcs + of the graph, one per line. Each arc is described by two integers, + i.e., the row and column number, or the indices of the two endpoints. + Cudd_bddRead produces a BDD that depends on two sets of variables: x + and y. The x variables (x\[0\] ... x\[nx-1\]) encode + the row index and the y variables (y\[0\] ... y\[ny-1\]) encode the + column index. x\[0\] and y\[0\] are the most significant bits in the + indices. + The variables may already exist or may be created by the function. + The index of x\[i\] is bx+i*sx, and the index of y\[i\] is by+i*sy.

      + On input, nx and ny hold the numbers of row and column variables already + in existence. On output, they hold the numbers of row and column + variables actually used by the matrix. When Cudd_bddRead creates the + variable arrays, the index of x\[i\] is bx+i*sx, and the index of + y\[i\] is by+i*sy. When some variables already exist, Cudd_bddRead + expects the indices of the existing x variables to be bx+i*sx, and the + indices of the existing y variables to be by+i*sy.

      + m and n are set to the numbers of rows and columns of the + matrix. Their values on input are immaterial. The BDD for the graph + is returned in E, and its reference count is > 0. Cudd_bddRead returns + 1 in case of success; 0 otherwise.] + + SideEffects [nx and ny are set to the numbers of row and column + variables. m and n are set to the numbers of rows and columns. x and y + are possibly extended to represent the array of row and column + variables.] + + SeeAlso [Cudd_addHarwell Cudd_addRead] + +******************************************************************************/ +int +Cudd_bddRead( + FILE * fp /* input file pointer */, + DdManager * dd /* DD manager */, + DdNode ** E /* characteristic function of the graph */, + DdNode *** x /* array of row variables */, + DdNode *** y /* array of column variables */, + int * nx /* number or row variables */, + int * ny /* number or column variables */, + int * m /* number of rows */, + int * n /* number of columns */, + int bx /* first index of row variables */, + int sx /* step of row variables */, + int by /* first index of column variables */, + int sy /* step of column variables */) +{ + DdNode *one, *zero; + DdNode *w; + DdNode *minterm1; + int u, v, err, i, nv; + int lnx, lny; + DdNode **lx, **ly; + + one = DD_ONE(dd); + zero = Cudd_Not(one); + + err = fscanf(fp, "%d %d", &u, &v); + if (err == EOF) { + return(0); + } else if (err != 2) { + return(0); + } + + *m = u; + /* Compute the number of x variables. */ + lx = *x; + u--; /* row and column numbers start from 0 */ + for (lnx=0; u > 0; lnx++) { + u >>= 1; + } + if (lnx > *nx) { + *x = lx = REALLOC(DdNode *, *x, lnx); + if (lx == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(0); + } + } + + *n = v; + /* Compute the number of y variables. */ + ly = *y; + v--; /* row and column numbers start from 0 */ + for (lny=0; v > 0; lny++) { + v >>= 1; + } + if (lny > *ny) { + *y = ly = REALLOC(DdNode *, *y, lny); + if (ly == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(0); + } + } + + /* Create all new variables. */ + for (i = *nx, nv = bx + (*nx) * sx; i < lnx; i++, nv += sx) { + do { + dd->reordered = 0; + lx[i] = cuddUniqueInter(dd, nv, one, zero); + } while (dd->reordered == 1); + if (lx[i] == NULL) return(0); + cuddRef(lx[i]); + } + for (i = *ny, nv = by + (*ny) * sy; i < lny; i++, nv += sy) { + do { + dd->reordered = 0; + ly[i] = cuddUniqueInter(dd, nv, one, zero); + } while (dd->reordered == 1); + if (ly[i] == NULL) return(0); + cuddRef(ly[i]); + } + *nx = lnx; + *ny = lny; + + *E = zero; /* this call will never cause reordering */ + cuddRef(*E); + + while (! feof(fp)) { + err = fscanf(fp, "%d %d", &u, &v); + if (err == EOF) { + break; + } else if (err != 2) { + return(0); + } else if (u >= *m || v >= *n || u < 0 || v < 0) { + return(0); + } + + minterm1 = one; cuddRef(minterm1); + + /* Build minterm1 corresponding to this arc. */ + for (i = lnx - 1; i>=0; i--) { + if (u & 1) { + w = Cudd_bddAnd(dd, minterm1, lx[i]); + } else { + w = Cudd_bddAnd(dd, minterm1, Cudd_Not(lx[i])); + } + if (w == NULL) { + Cudd_RecursiveDeref(dd, minterm1); + return(0); + } + cuddRef(w); + Cudd_RecursiveDeref(dd,minterm1); + minterm1 = w; + u >>= 1; + } + for (i = lny - 1; i>=0; i--) { + if (v & 1) { + w = Cudd_bddAnd(dd, minterm1, ly[i]); + } else { + w = Cudd_bddAnd(dd, minterm1, Cudd_Not(ly[i])); + } + if (w == NULL) { + Cudd_RecursiveDeref(dd, minterm1); + return(0); + } + cuddRef(w); + Cudd_RecursiveDeref(dd, minterm1); + minterm1 = w; + v >>= 1; + } + + w = Cudd_bddAnd(dd, Cudd_Not(minterm1), Cudd_Not(*E)); + if (w == NULL) { + Cudd_RecursiveDeref(dd, minterm1); + return(0); + } + w = Cudd_Not(w); + cuddRef(w); + Cudd_RecursiveDeref(dd, minterm1); + Cudd_RecursiveDeref(dd, *E); + *E = w; + } + return(1); + +} /* end of Cudd_bddRead */ + +/*---------------------------------------------------------------------------*/ +/* Definition of internal functions */ +/*---------------------------------------------------------------------------*/ + + +/*---------------------------------------------------------------------------*/ +/* Definition of static functions */ +/*---------------------------------------------------------------------------*/ + 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: +

        +
      • Cudd_Ref() +
      • Cudd_RecursiveDeref() +
      • Cudd_IterDerefBdd() +
      • Cudd_DelayedDerefBdd() +
      • Cudd_RecursiveDerefZdd() +
      • Cudd_Deref() +
      • Cudd_CheckZeroRef() +
      + Internal procedures included in this module: +
        +
      • cuddReclaim() +
      • cuddReclaimZdd() +
      • cuddClearDeathRow() +
      • cuddShrinkDeathRow() +
      • cuddIsInDeathRow() +
      • cuddTimesInDeathRow() +
      + ] + + 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: +
        +
      • Cudd_ReduceHeap() +
      • Cudd_ShuffleHeap() +
      + Internal procedures included in this module: +
        +
      • cuddDynamicAllocNode() +
      • cuddSifting() +
      • cuddSwapping() +
      • cuddNextHigh() +
      • cuddNextLow() +
      • cuddSwapInPlace() +
      • cuddBddAlignToZdd() +
      + Static procedures included in this module: +
        +
      • ddUniqueCompare() +
      • ddSwapAny() +
      • ddSiftingAux() +
      • ddSiftingUp() +
      • ddSiftingDown() +
      • ddSiftingBackward() +
      • ddReorderPreprocess() +
      • ddReorderPostprocess() +
      • ddShuffle() +
      • ddSiftUp() +
      • bddFixTree() +
      ] + + 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: +
        +
      • Swapping +
      • Sifting +
      • Symmetric Sifting +
      • Group Sifting +
      • Window Permutation +
      • Simulated Annealing +
      • Genetic Algorithm +
      • Dynamic Programming (exact) +
      + + For sifting, symmetric sifting, group sifting, and window + permutation it is possible to request reordering to convergence.

      + + 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. +

        +
      1. Order all the variables according to the number of entries + in each unique table. +
      2. Sift the variable up and down, remembering each time the + total size of the DD heap. +
      3. Select the best permutation. +
      4. Repeat 3 and 4 for all variables. +
      + 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. +
        +
      1. Select two variables (RANDOM or HEURISTIC). +
      2. Permute these variables. +
      3. If the nodes have decreased accept the permutation. +
      4. Otherwise reconstruct the original heap. +
      5. Loop. +
      + 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 < 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 + M be the ratio of the two numbers. cuddBddAlignToZdd + then considers the ZDD variables from M*i to + (M+1)*i-1 as corresponding to BDD variable + i. This function should be normally called from + Cudd_zddReduceHeap, which clears the cache. Returns 1 in case of + success; 0 otherwise.] + + SideEffects [Changes the BDD variable order for all diagrams and performs + garbage collection of the BDD unique table.] + + SeeAlso [Cudd_ShuffleHeap Cudd_zddReduceHeap] + +******************************************************************************/ +int +cuddBddAlignToZdd( + DdManager * table /* DD manager */) +{ + int *invperm; /* permutation array */ + int M; /* ratio of ZDD variables to BDD variables */ + int i; /* loop index */ + int result; /* return value */ + + /* We assume that a ratio of 0 is OK. */ + if (table->size == 0) + return(1); + + M = table->sizeZ / table->size; + /* Check whether the number of ZDD variables is a multiple of the + ** number of BDD variables. + */ + if (M * table->size != table->sizeZ) + return(0); + /* Create and initialize the inverse permutation array. */ + invperm = ALLOC(int,table->size); + if (invperm == NULL) { + table->errorCode = CUDD_MEMORY_OUT; + return(0); + } + for (i = 0; i < table->sizeZ; i += M) { + int indexZ = table->invpermZ[i]; + int index = indexZ / M; + invperm[i / M] = index; + } + /* Eliminate dead nodes. Do not scan the cache again, because we + ** assume that Cudd_zddReduceHeap has already cleared it. + */ + cuddGarbageCollect(table,0); + + /* Initialize number of isolated projection functions. */ + table->isolated = 0; + for (i = 0; i < table->size; i++) { + if (table->vars[i]->ref == 1) table->isolated++; + } + + /* Initialize the interaction matrix. */ + result = cuddInitInteract(table); + if (result == 0) return(0); + + result = ddShuffle(table, invperm); + FREE(invperm); + /* Free interaction matrix. */ + FREE(table->interact); + /* Fix the BDD variable group tree. */ + bddFixTree(table,table->tree); + return(result); + +} /* end of cuddBddAlignToZdd */ + +/*---------------------------------------------------------------------------*/ +/* Definition of static functions */ +/*---------------------------------------------------------------------------*/ + + +/**Function******************************************************************** + + Synopsis [Comparison function used by qsort.] + + Description [Comparison function used by qsort to order the + variables according to the number of keys in the subtables. + Returns the difference in number of keys between the two + variables being compared.] + + SideEffects [None] + +******************************************************************************/ +static int +ddUniqueCompare( + int * ptrX, + int * ptrY) +{ +#if 0 + if (entry[*ptrY] == entry[*ptrX]) { + return((*ptrX) - (*ptrY)); + } +#endif + return(entry[*ptrY] - entry[*ptrX]); + +} /* end of ddUniqueCompare */ + + +/**Function******************************************************************** + + Synopsis [Swaps any two variables.] + + Description [Swaps any two variables. Returns the set of moves.] + + SideEffects [None] + +******************************************************************************/ +static Move * +ddSwapAny( + DdManager * table, + int x, + int y) +{ + Move *move, *moves; + int xRef,yRef; + int xNext,yNext; + int size; + int limitSize; + int tmp; + + if (x >y) { + tmp = x; x = y; y = tmp; + } + + xRef = x; yRef = y; + + xNext = cuddNextHigh(table,x); + yNext = cuddNextLow(table,y); + moves = NULL; + limitSize = table->keys - table->isolated; + + for (;;) { + if ( xNext == yNext) { + size = cuddSwapInPlace(table,x,xNext); + if (size == 0) goto ddSwapAnyOutOfMem; + move = (Move *) cuddDynamicAllocNode(table); + if (move == NULL) goto ddSwapAnyOutOfMem; + move->x = x; + move->y = xNext; + move->size = size; + move->next = moves; + moves = move; + + size = cuddSwapInPlace(table,yNext,y); + if (size == 0) goto ddSwapAnyOutOfMem; + move = (Move *) cuddDynamicAllocNode(table); + if (move == NULL) goto ddSwapAnyOutOfMem; + move->x = yNext; + move->y = y; + move->size = size; + move->next = moves; + moves = move; + + size = cuddSwapInPlace(table,x,xNext); + if (size == 0) goto ddSwapAnyOutOfMem; + move = (Move *) cuddDynamicAllocNode(table); + if (move == NULL) goto ddSwapAnyOutOfMem; + move->x = x; + move->y = xNext; + move->size = size; + move->next = moves; + moves = move; + + tmp = x; x = y; y = tmp; + + } else if (x == yNext) { + + size = cuddSwapInPlace(table,x,xNext); + if (size == 0) goto ddSwapAnyOutOfMem; + move = (Move *) cuddDynamicAllocNode(table); + if (move == NULL) goto ddSwapAnyOutOfMem; + move->x = x; + move->y = xNext; + move->size = size; + move->next = moves; + moves = move; + + tmp = x; x = y; y = tmp; + + } else { + size = cuddSwapInPlace(table,x,xNext); + if (size == 0) goto ddSwapAnyOutOfMem; + move = (Move *) cuddDynamicAllocNode(table); + if (move == NULL) goto ddSwapAnyOutOfMem; + move->x = x; + move->y = xNext; + move->size = size; + move->next = moves; + moves = move; + + size = cuddSwapInPlace(table,yNext,y); + if (size == 0) goto ddSwapAnyOutOfMem; + move = (Move *) cuddDynamicAllocNode(table); + if (move == NULL) goto ddSwapAnyOutOfMem; + move->x = yNext; + move->y = y; + move->size = size; + move->next = moves; + moves = move; + + x = xNext; + y = yNext; + } + + xNext = cuddNextHigh(table,x); + yNext = cuddNextLow(table,y); + if (xNext > yRef) break; + + if ((double) size > table->maxGrowth * (double) limitSize) break; + if (size < limitSize) limitSize = size; + } + if (yNext>=xRef) { + size = cuddSwapInPlace(table,yNext,y); + if (size == 0) goto ddSwapAnyOutOfMem; + move = (Move *) cuddDynamicAllocNode(table); + if (move == NULL) goto ddSwapAnyOutOfMem; + move->x = yNext; + move->y = y; + move->size = size; + move->next = moves; + moves = move; + } + + return(moves); + +ddSwapAnyOutOfMem: + while (moves != NULL) { + move = moves->next; + 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: +
        +
      • Cudd_Eval() +
      • Cudd_ShortestPath() +
      • Cudd_LargestCube() +
      • Cudd_ShortestLength() +
      • Cudd_Decreasing() +
      • Cudd_Increasing() +
      • Cudd_EquivDC() +
      • Cudd_bddLeqUnless() +
      • Cudd_EqualSupNorm() +
      • Cudd_bddMakePrime() +
      + Internal procedures included in this module: +
        +
      • cuddBddMakePrime() +
      + Static procedures included in this module: +
        +
      • freePathPair() +
      • getShortest() +
      • getPath() +
      • getLargest() +
      • getCube() +
      ] + + 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 pr is positive + the first failure is reported to the standard output.] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +int +Cudd_EqualSupNorm( + DdManager * dd /* manager */, + DdNode * f /* first ADD */, + DdNode * g /* second ADD */, + CUDD_VALUE_TYPE tolerance /* maximum allowed difference */, + int pr /* verbosity level */) +{ + DdNode *fv, *fvn, *gv, *gvn, *r; + unsigned int topf, topg; + + statLine(dd); + /* Check terminal cases. */ + if (f == g) return(1); + if (Cudd_IsConstant(f) && Cudd_IsConstant(g)) { + if (ddEqualVal(cuddV(f),cuddV(g),tolerance)) { + return(1); + } else { + if (pr>0) { + (void) fprintf(dd->out,"Offending nodes:\n"); +#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: +
        +
      • Cudd_CofMinterm(); +
      + Static procedures included in this module: +
        +
      • ddCofMintermAux() +
      + ] + + 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: +
        +
      • Cudd_SolveEqn() +
      • Cudd_VerifySol() +
      + Internal functions included in this module: +
        +
      • cuddSolveEqnRecur() +
      • cuddVerifySol() +
      ] + + 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: +
        +
      • Cudd_SplitSet() +
      + Internal functions included in this module: +
        +
      • cuddSplitSetRecur() + + Static functions included in this module: +
          +
        • selectMintermsFromUniverse() +
        • mintermsFromUniverse() +
        • bddAnnotateMintermCount() +
        ] + + 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 m minterms from a BDD whose + support has n variables at most. The procedure tries + to create as few extra nodes as possible. The function represented + by S depends on at most n of the variables + in xVars. Returns a BDD with m minterms + of the on-set of S if successful; NULL otherwise.] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +DdNode * +Cudd_SplitSet( + DdManager * manager, + DdNode * S, + DdNode ** xVars, + int n, + double m) +{ + DdNode *result; + DdNode *zero, *one; + double max, num; + st_table *mtable; + int *varSeen; + int i,index, size; + + size = manager->size; + one = DD_ONE(manager); + zero = Cudd_Not(one); + + /* Trivial cases. */ + if (m == 0.0) { + return(zero); + } + if (S == zero) { + return(NULL); + } + + max = pow(2.0,(double)n); + if (m > max) + return(NULL); + + do { + manager->reordered = 0; + /* varSeen is used to mark the variables that are encountered + ** while traversing the BDD S. + */ + varSeen = ALLOC(int, size); + if (varSeen == NULL) { + manager->errorCode = CUDD_MEMORY_OUT; + return(NULL); + } + for (i = 0; i < size; i++) { + varSeen[i] = -1; + } + for (i = 0; i < n; i++) { + index = (xVars[i])->index; + varSeen[manager->invperm[index]] = 0; + } + + if (S == one) { + if (m == max) + 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<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 .] + +******************************************************************************/ +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: +
          +
        • Cudd_SubsetHeavyBranch() +
        • Cudd_SupersetHeavyBranch() +
        + Internal procedures included in this module: +
          +
        • cuddSubsetHeavyBranch() +
        + Static procedures included in this module: +
          +
        • ResizeCountMintermPages(); +
        • ResizeNodeDataPages() +
        • ResizeCountNodePages() +
        • SubsetCountMintermAux() +
        • SubsetCountMinterm() +
        • SubsetCountNodesAux() +
        • SubsetCountNodes() +
        • BuildSubsetBdd() +
        + ] + + 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 +#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: +
          +
        • Cudd_SubsetShortPaths() +
        • Cudd_SupersetShortPaths() +
        + Internal procedures included in this module: +
          +
        • cuddSubsetShortPaths() +
        + Static procedures included in this module: +
          +
        • BuildSubsetBdd() +
        • CreatePathTable() +
        • AssessPathLength() +
        • CreateTopDist() +
        • CreateBotDist() +
        • ResizeNodeDistPages() +
        • ResizeQueuePages() +
        • stPathTableDdFree() +
        + ] + + 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: +
          +
        • Cudd_SymmProfile() +
        + Internal procedures included in this module: +
          +
        • cuddSymmCheck() +
        • cuddSymmSifting() +
        • cuddSymmSiftingConv() +
        + Static procedures included in this module: +
          +
        • ddSymmUniqueCompare() +
        • ddSymmSiftingAux() +
        • ddSymmSiftingConvAux() +
        • ddSymmSiftingUp() +
        • ddSymmSiftingDown() +
        • ddSymmGroupMove() +
        • ddSymmGroupMoveBackward() +
        • ddSymmSiftingBackward() +
        • ddSymmSummary() +
        ] + + 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. +
          +
        1. Order all the variables according to the number of entries in + each unique subtable. +
        2. Sift the variable up and down, remembering each time the total + size of the DD heap and grouping variables that are symmetric. +
        3. Select the best permutation. +
        4. Repeat 3 and 4 for all variables. +
        + 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. +
          +
        1. Order all the variables according to the number of entries in + each unique subtable. +
        2. Sift the variable up and down, remembering each time the total + size of the DD heap and grouping variables that are symmetric. +
        3. Select the best permutation. +
        4. Repeat 3 and 4 for all variables. +
        5. Repeat 1-4 until no further improvement. +
        + 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: +
          +
        • Cudd_Prime() +
        + Internal procedures included in this module: +
          +
        • cuddAllocNode() +
        • cuddInitTable() +
        • cuddFreeTable() +
        • cuddGarbageCollect() +
        • cuddGarbageCollectZdd() +
        • cuddZddGetNode() +
        • cuddZddGetNodeIVO() +
        • cuddUniqueInter() +
        • cuddUniqueInterIVO() +
        • cuddUniqueInterZdd() +
        • cuddUniqueConst() +
        • cuddRehash() +
        • cuddShrinkSubtable() +
        • cuddInsertSubtables() +
        • cuddDestroySubtables() +
        • cuddResizeTableZdd() +
        • cuddSlowTableGrowth() +
        + Static procedures included in this module: +
          +
        • ddRehashZdd() +
        • ddResizeTable() +
        • cuddFindParent() +
        • cuddOrderedInsert() +
        • cuddOrderedThread() +
        • cuddRotateLeft() +
        • cuddRotateRight() +
        • cuddDoRebalance() +
        • cuddCheckCollisionOrdering() +
        ] + + 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 >= 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: +
          +
        • Cudd_PrintMinterm() +
        • Cudd_PrintDebug() +
        • Cudd_DagSize() +
        • Cudd_EstimateCofactor() +
        • Cudd_EstimateCofactorSimple() +
        • Cudd_SharingSize() +
        • Cudd_CountMinterm() +
        • Cudd_EpdCountMinterm() +
        • Cudd_CountPath() +
        • Cudd_CountPathsToNonZero() +
        • Cudd_Support() +
        • Cudd_SupportIndex() +
        • Cudd_SupportSize() +
        • Cudd_VectorSupport() +
        • Cudd_VectorSupportIndex() +
        • Cudd_VectorSupportSize() +
        • Cudd_ClassifySupport() +
        • Cudd_CountLeaves() +
        • Cudd_bddPickOneCube() +
        • Cudd_bddPickOneMinterm() +
        • Cudd_bddPickArbitraryMinterms() +
        • Cudd_SubsetWithMaskVars() +
        • Cudd_FirstCube() +
        • Cudd_NextCube() +
        • Cudd_bddComputeCube() +
        • Cudd_addComputeCube() +
        • Cudd_FirstNode() +
        • Cudd_NextNode() +
        • Cudd_GenFree() +
        • Cudd_IsGenEmpty() +
        • Cudd_IndicesToCube() +
        • Cudd_PrintVersion() +
        • Cudd_AverageDistance() +
        • Cudd_Random() +
        • Cudd_Srandom() +
        • Cudd_Density() +
        + Internal procedures included in this module: +
          +
        • cuddP() +
        • cuddStCountfree() +
        • cuddCollectNodes() +
        + Static procedures included in this module: +
          +
        • dp2() +
        • ddPrintMintermAux() +
        • ddDagInt() +
        • ddCountMintermAux() +
        • ddEpdCountMintermAux() +
        • ddCountPathAux() +
        • ddSupportStep() +
        • ddClearFlag() +
        • ddLeavesInt() +
        • ddPickArbitraryMinterms() +
        • ddPickRepresentativeCube() +
        • ddEpdFree() +
        ] + + 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 > 0. Specifically: +
          +
        • pr = 0 : prints nothing +
        • pr = 1 : prints counts of nodes and minterms +
        • pr = 2 : prints counts + disjoint sum of product +
        • pr = 3 : prints counts + list of nodes +
        • pr > 3 : prints counts + disjoint sum of product + list of nodes +
        + 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 + f and g, depending on whther they appear + in both DDs, only in f, or only in g. + Returns 1 if successful; 0 otherwise.] + + SideEffects [The cubes of the three classes of variables are + returned as side effects.] + + SeeAlso [Cudd_Support Cudd_VectorSupport] + +******************************************************************************/ +int +Cudd_ClassifySupport( + DdManager * dd /* manager */, + DdNode * f /* first DD */, + DdNode * g /* second DD */, + DdNode ** common /* cube of shared variables */, + DdNode ** onlyF /* cube of variables only in f */, + DdNode ** onlyG /* cube of variables only in g */) +{ + int *supportF, *supportG; + 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 vars. The array + vars should contain at least all variables in the + support of f; if this condition is not met the minterm + built by this procedure may not be contained in + f. Builds a BDD for the minterm and returns a pointer + to it if successful; NULL otherwise. There are three reasons why the + procedure may fail: +
          +
        • It may run out of memory; +
        • the function f may be the constant 0; +
        • the minterm may not be contained in f. +
        ] + + 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 vars */) +{ + char *string; + int i, size; + int *indices; + int result; + DdNode *old, *neW; + + size = dd->size; + string = ALLOC(char, size); + if (string == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(NULL); + } + indices = ALLOC(int,n); + if (indices == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + FREE(string); + return(NULL); + } + + for (i = 0; i < n; i++) { + indices[i] = vars[i]->index; + } + + result = Cudd_bddPickOneCube(dd,f,string); + if (result == 0) { + FREE(string); + FREE(indices); + return(NULL); + } + + /* Randomize choice for don't cares. */ + for (i = 0; i < n; i++) { + if (string[indices[i]] == 2) + string[indices[i]] = (char) ((Cudd_Random() & 0x20) >> 5); + } + + /* Build result BDD. */ + old = Cudd_ReadOne(dd); + cuddRef(old); + + for (i = n-1; i >= 0; i--) { + neW = Cudd_bddAnd(dd,old,Cudd_NotCond(vars[i],string[indices[i]]==0)); + if (neW == NULL) { + FREE(string); + FREE(indices); + Cudd_RecursiveDeref(dd,old); + return(NULL); + } + cuddRef(neW); + Cudd_RecursiveDeref(dd,old); + old = neW; + } + +#ifdef DD_DEBUG + /* Test. */ + if (Cudd_bddLeq(dd,old,f)) { + cuddDeref(old); + } else { + Cudd_RecursiveDeref(dd,old); + old = NULL; + } +#else + cuddDeref(old); +#endif + + FREE(string); + FREE(indices); + return(old); + +} /* end of Cudd_bddPickOneMinterm */ + + +/**Function******************************************************************** + + Synopsis [Picks k on-set minterms evenly distributed from given DD.] + + Description [Picks k on-set minterms evenly distributed from given DD. + The minterms are in terms of vars. The array + vars should contain at least all variables in the + support of f; if this condition is not met the minterms + built by this procedure may not be contained in + f. Builds an array of BDDs for the minterms and returns a + pointer to it if successful; NULL otherwise. There are three reasons + why the procedure may fail: +
          +
        • It may run out of memory; +
        • the function f may be the constant 0; +
        • the minterms may not be contained in f. +
        ] + + 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 vars */, + int k /* number of minterms to find */) +{ + char **string; + int i, j, l, size; + int *indices; + int result; + DdNode **old, *neW; + double minterms; + char *saveString; + int saveFlag, savePoint, isSame; + + minterms = Cudd_CountMinterm(dd,f,n); + if ((double)k > minterms) { + return(NULL); + } + + size = dd->size; + string = ALLOC(char *, k); + if (string == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(NULL); + } + for (i = 0; i < k; i++) { + string[i] = ALLOC(char, size + 1); + if (string[i] == NULL) { + for (j = 0; j < i; j++) + FREE(string[i]); + FREE(string); + dd->errorCode = CUDD_MEMORY_OUT; + return(NULL); + } + for (j = 0; j < size; j++) string[i][j] = '2'; + string[i][size] = '\0'; + } + indices = ALLOC(int,n); + if (indices == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + for (i = 0; i < k; i++) + FREE(string[i]); + FREE(string); + return(NULL); + } + + for (i = 0; i < n; i++) { + indices[i] = vars[i]->index; + } + + result = ddPickArbitraryMinterms(dd,f,n,k,string); + if (result == 0) { + for (i = 0; i < k; i++) + FREE(string[i]); + FREE(string); + FREE(indices); + return(NULL); + } + + old = ALLOC(DdNode *, k); + if (old == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + for (i = 0; i < k; i++) + FREE(string[i]); + FREE(string); + FREE(indices); + return(NULL); + } + saveString = ALLOC(char, size + 1); + if (saveString == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + for (i = 0; i < k; i++) + FREE(string[i]); + FREE(string); + FREE(indices); + FREE(old); + return(NULL); + } + saveFlag = 0; + + /* Build result BDD array. */ + for (i = 0; i < k; i++) { + isSame = 0; + if (!saveFlag) { + for (j = i + 1; j < k; j++) { + if (strcmp(string[i], string[j]) == 0) { + savePoint = i; + strcpy(saveString, string[i]); + saveFlag = 1; + break; + } + } + } else { + if (strcmp(string[i], saveString) == 0) { + isSame = 1; + } else { + saveFlag = 0; + for (j = i + 1; j < k; j++) { + if (strcmp(string[i], string[j]) == 0) { + savePoint = i; + strcpy(saveString, string[i]); + saveFlag = 1; + break; + } + } + } + } + /* Randomize choice for don't cares. */ + for (j = 0; j < n; j++) { + if (string[i][indices[j]] == '2') + string[i][indices[j]] = (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 vars */, + DdNode ** maskVars /* array of variables */, + int mvars /* size of maskVars */) +{ + double *weight; + char *string; + int i, size; + int *indices, *mask; + int result; + DdNode *zero, *cube, *newCube, *subset; + DdNode *cof; + + DdNode *support; + support = Cudd_Support(dd,f); + cuddRef(support); + Cudd_RecursiveDeref(dd,support); + + zero = Cudd_Not(dd->one); + size = dd->size; + + weight = ALLOC(double,size); + if (weight == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(NULL); + } + for (i = 0; i < size; i++) { + weight[i] = 0.0; + } + for (i = 0; i < mvars; i++) { + cof = Cudd_Cofactor(dd, f, maskVars[i]); + cuddRef(cof); + weight[i] = Cudd_CountMinterm(dd, cof, nvars); + Cudd_RecursiveDeref(dd,cof); + + cof = Cudd_Cofactor(dd, f, Cudd_Not(maskVars[i])); + cuddRef(cof); + weight[i] -= Cudd_CountMinterm(dd, cof, nvars); + Cudd_RecursiveDeref(dd,cof); + } + + string = ALLOC(char, size + 1); + if (string == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + 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.

        + A cube is represented as an array of literals, which are integers in + {0, 1, 2}; 0 represents a complemented literal, 1 represents an + uncomplemented literal, and 2 stands for don't care. The enumeration + produces a disjoint cover of the function associated with the diagram. + The size of the array equals the number of variables in the manager at + the time Cudd_FirstCube is called.

        + For each cube, a value is also returned. This value is always 1 for a + BDD, while it may be different from 1 for an ADD. + For BDDs, the offset is the set of cubes whose value is the logical zero. + For ADDs, the offset is the set of cubes whose value is the + background value. The cubes of the offset are not enumerated.] + + SideEffects [The first cube and its value are returned as side effects.] + + SeeAlso [Cudd_ForeachCube Cudd_NextCube Cudd_GenFree Cudd_IsGenEmpty + Cudd_FirstNode] + +******************************************************************************/ +DdGen * +Cudd_FirstCube( + DdManager * dd, + DdNode * f, + int ** cube, + CUDD_VALUE_TYPE * value) +{ + DdGen *gen; + DdNode *top, *treg, *next, *nreg, *prev, *preg; + int i; + int nvars; + + /* Sanity Check. */ + if (dd == NULL || f == NULL) return(NULL); + + /* Allocate generator an initialize it. */ + gen = ALLOC(DdGen,1); + if (gen == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(NULL); + } + + gen->manager = dd; + gen->type = CUDD_GEN_CUBES; + gen->status = CUDD_GEN_EMPTY; + gen->gen.cubes.cube = NULL; + gen->gen.cubes.value = DD_ZERO_VAL; + gen->stack.sp = 0; + gen->stack.stack = NULL; + gen->node = NULL; + + nvars = dd->size; + gen->gen.cubes.cube = ALLOC(int,nvars); + if (gen->gen.cubes.cube == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + FREE(gen); + return(NULL); + } + for (i = 0; i < nvars; i++) gen->gen.cubes.cube[i] = 2; + + /* The maximum stack depth is one plus the number of variables. + ** because a path may have nodes at all levels, including the + ** constant level. + */ + gen->stack.stack = ALLOC(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: +

        + |f| = (|f0|+|f1|)/2 + + 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: + + |f| = |f0|+|f1| + + 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: + + |f| = (|f0|+|f1|)/2 + + 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: + + |f| = |f0|+|f1| + + 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: +
          +
        • cuddWindowReorder() +
        + Static procedures included in this module: +
          +
        • ddWindow2() +
        • ddWindowConv2() +
        • ddPermuteWindow3() +
        • ddWindow3() +
        • ddWindowConv3() +
        • ddPermuteWindow4() +
        • ddWindow4() +
        • ddWindowConv4() +
        ] + + 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; xkeys - table->isolated; + do { + newevent = 0; + for (x=0; x= 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 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 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: +
          +
        • Cudd_zddCount(); +
        • Cudd_zddCountDouble(); +
        + Internal procedures included in this module: +
          +
        + Static procedures included in this module: +
          +
        • cuddZddCountStep(); +
        • cuddZddCountDoubleStep(); +
        • st_zdd_count_dbl_free() +
        • st_zdd_countfree() +
        + ] + + 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: +
          +
        • Cudd_zddProduct(); +
        • Cudd_zddUnateProduct(); +
        • Cudd_zddWeakDiv(); +
        • Cudd_zddWeakDivF(); +
        • Cudd_zddDivide(); +
        • Cudd_zddDivideF(); +
        • Cudd_zddComplement(); +
        + Internal procedures included in this module: +
          +
        • cuddZddProduct(); +
        • cuddZddUnateProduct(); +
        • cuddZddWeakDiv(); +
        • cuddZddWeakDivF(); +
        • cuddZddDivide(); +
        • cuddZddDivideF(); +
        • cuddZddGetCofactors3() +
        • cuddZddGetCofactors2() +
        • cuddZddComplement(); +
        • cuddZddGetPosVarIndex(); +
        • cuddZddGetNegVarIndex(); +
        • cuddZddGetPosVarLevel(); +
        • cuddZddGetNegVarLevel(); +
        + Static procedures included in this module: +
          +
        + ] + + 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: +
          +
        • Cudd_MakeZddTreeNode() +
        + Internal procedures included in this file: +
          +
        • cuddZddTreeSifting() +
        + Static procedures included in this module: +
          +
        • zddTreeSiftingAux() +
        • zddCountInternalMtrNodes() +
        • zddReorderChildren() +
        • zddFindNodeHiLo() +
        • zddUniqueCompareGroup() +
        • zddGroupSifting() +
        • zddGroupSiftingAux() +
        • zddGroupSiftingUp() +
        • zddGroupSiftingDown() +
        • zddGroupMove() +
        • zddGroupMoveBackward() +
        • zddGroupSiftingBackward() +
        • zddMergeGroups() +
        ] + + 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: +
          +
        • Cudd_bddIsop() +
        • Cudd_zddIsop() +
        • Cudd_MakeBddFromZddCover() +
        + Internal procedures included in this module: +
          +
        • cuddBddIsop() +
        • cuddZddIsop() +
        • cuddMakeBddFromZddCover() +
        + Static procedures included in this module: +
          +
        + ] + + 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 i should have indices 2i and + 2i+1. The result of this procedure depends on the + variable order. If successful, Cudd_zddIsop returns the BDD for + the function chosen from the interval. The ZDD representing the + irredundant cover is returned as a side effect in zdd_I. In case of + failure, NULL is returned.] + + SideEffects [zdd_I holds the pointer to the ZDD for the ISOP on + successful return.] + + SeeAlso [Cudd_bddIsop Cudd_zddVarsFromBddVars] + +******************************************************************************/ +DdNode * +Cudd_zddIsop( + DdManager * dd, + DdNode * L, + DdNode * U, + DdNode ** zdd_I) +{ + DdNode *res; + int autoDynZ; + + autoDynZ = dd->autoDynZ; + dd->autoDynZ = 0; + + do { + dd->reordered = 0; + res = cuddZddIsop(dd, L, U, zdd_I); + } while (dd->reordered == 1); + dd->autoDynZ = autoDynZ; + return(res); + +} /* end of Cudd_zddIsop */ + + +/**Function******************************************************************** + + Synopsis [Computes a BDD in the interval between L and U with a + simple sum-of-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: +
          +
        • cuddZddLinearSifting() +
        + Static procedures included in this module: +
          +
        • cuddZddLinearInPlace() +
        • cuddZddLinerAux() +
        • cuddZddLinearUp() +
        • cuddZddLinearDown() +
        • cuddZddLinearBackward() +
        • cuddZddUndoMoves() +
        + ] + + 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. +
          +
        1. Order all the variables according to the number of entries + in each unique table. +
        2. Sift the variable up and down and applies the XOR transformation, + remembering each time the total size of the DD heap. +
        3. Select the best permutation. +
        4. Repeat 3 and 4 for all variables. +
        + 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 < 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: +
          +
        • Cudd_zddDagSize() +
        • Cudd_zddCountMinterm() +
        • Cudd_zddPrintSubtable() +
        + Internal procedures included in this module: +
          +
        + Static procedures included in this module: +
          +
        • cuddZddDagInt() +
        + ] + + 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 +#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 + node. This procedure takes a parameter + path that specifies how many variables are in the + support of the function. If the procedure runs out of memory, it + returns (double) CUDD_OUT_OF_MEM.] + + SideEffects [None] + + SeeAlso [Cudd_zddCountDouble] + +******************************************************************************/ +double +Cudd_zddCountMinterm( + DdManager * zdd, + DdNode * node, + int path) +{ + double dc_var, minterms; + + dc_var = (double)((double)(zdd->sizeZ) - (double)path); + minterms = Cudd_zddCountDouble(zdd, node) / pow(2.0, dc_var); + return(minterms); + +} /* end of Cudd_zddCountMinterm */ + + +/**Function******************************************************************** + + Synopsis [Prints the ZDD table.] + + Description [Prints the ZDD table for debugging purposes.] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +void +Cudd_zddPrintSubtable( + DdManager * table) +{ + int i, j; + DdNode *z1, *z1_next, *base; + DdSubtable *ZSubTable; + + base = table->one; + for (i = table->sizeZ - 1; i >= 0; i--) { + ZSubTable = &(table->subtableZ[i]); + printf("subtable[%d]:\n", i); + for (j = ZSubTable->slots - 1; j >= 0; j--) { + z1 = ZSubTable->nodelist[j]; + while (z1 != NIL(DdNode)) { + (void) fprintf(table->out, +#if SIZEOF_VOID_P == 8 + "ID = 0x%lx\tindex = %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: +
          +
        • Cudd_zddPortFromBdd() +
        • Cudd_zddPortToBdd() +
        + Internal procedures included in this module: +
          +
        + Static procedures included in this module: +
          +
        • zddPortFromBddStep() +
        • zddPortToBddStep() +
        + ] + + 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: +
          +
        • Cudd_zddReduceHeap() +
        • Cudd_zddShuffleHeap() +
        + Internal procedures included in this module: +
          +
        • cuddZddAlignToBdd() +
        • cuddZddNextHigh() +
        • cuddZddNextLow() +
        • cuddZddUniqueCompare() +
        • cuddZddSwapInPlace() +
        • cuddZddSwapping() +
        • cuddZddSifting() +
        + Static procedures included in this module: +
          +
        • zddSwapAny() +
        • cuddZddSiftingAux() +
        • cuddZddSiftingUp() +
        • cuddZddSiftingDown() +
        • cuddZddSiftingBackward() +
        • zddReorderPreprocess() +
        • zddReorderPostprocess() +
        • zddShuffle() +
        • zddSiftUp() +
        + ] + + 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: +
          +
        • Swapping +
        • Sifting +
        • Symmetric Sifting +
        + + For sifting and symmetric sifting it is possible to request reordering + to convergence.

        + + 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 + M be the ratio of the two numbers. cuddZddAlignToBdd + then considers the ZDD variables from M*i to + (M+1)*i-1 as corresponding to BDD variable + i. This function should be normally called from + Cudd_ReduceHeap, which clears the cache. Returns 1 in case of + success; 0 otherwise.] + + SideEffects [Changes the ZDD variable order for all diagrams and performs + garbage collection of the ZDD unique table.] + + SeeAlso [Cudd_zddShuffleHeap Cudd_ReduceHeap] + +******************************************************************************/ +int +cuddZddAlignToBdd( + DdManager * table /* DD manager */) +{ + int *invpermZ; /* permutation array */ + int M; /* ratio of ZDD variables to BDD variables */ + int i,j; /* loop indices */ + int result; /* return value */ + + /* We assume that a ratio of 0 is OK. */ + if (table->sizeZ == 0) + return(1); + + empty = table->zero; + M = table->sizeZ / table->size; + /* Check whether the number of ZDD variables is a multiple of the + ** number of BDD variables. + */ + if (M * table->size != table->sizeZ) + return(0); + /* Create and initialize the inverse permutation array. */ + invpermZ = ALLOC(int,table->sizeZ); + if (invpermZ == NULL) { + table->errorCode = CUDD_MEMORY_OUT; + return(0); + } + for (i = 0; i < table->size; i++) { + int index = table->invperm[i]; + int indexZ = index * M; + int levelZ = table->permZ[indexZ]; + levelZ = (levelZ / M) * M; + for (j = 0; j < M; j++) { + invpermZ[M * i + j] = table->invpermZ[levelZ + j]; + } + } + /* Eliminate dead nodes. Do not scan the cache again, because we + ** assume that Cudd_ReduceHeap has already cleared it. + */ + 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 < 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. +

          +
        1. Select two variables (RANDOM or HEURISTIC). +
        2. Permute these variables. +
        3. If the nodes have decreased accept the permutation. +
        4. Otherwise reconstruct the original heap. +
        5. Loop. +
        + 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. +
          +
        1. Order all the variables according to the number of entries + in each unique table. +
        2. Sift the variable up and down, remembering each time the + total size of the DD heap. +
        3. Select the best permutation. +
        4. Repeat 3 and 4 for all variables. +
        + 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: +
          +
        • Cudd_zddIte() +
        • Cudd_zddUnion() +
        • Cudd_zddIntersect() +
        • Cudd_zddDiff() +
        • Cudd_zddDiffConst() +
        • Cudd_zddSubset1() +
        • Cudd_zddSubset0() +
        • Cudd_zddChange() +
        + Internal procedures included in this module: +
          +
        • cuddZddIte() +
        • cuddZddUnion() +
        • cuddZddIntersect() +
        • cuddZddDiff() +
        • cuddZddChangeAux() +
        • cuddZddSubset1() +
        • cuddZddSubset0() +
        + Static procedures included in this module: +
          +
        • zdd_subset1_aux() +
        • zdd_subset0_aux() +
        • zddVarToConst() +
        + ] + + 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: +
          +
        • Cudd_zddSymmProfile() +
        + Internal procedures included in this module: +
          +
        • cuddZddSymmCheck() +
        • cuddZddSymmSifting() +
        • cuddZddSymmSiftingConv() +
        + Static procedures included in this module: +
          +
        • cuddZddUniqueCompare() +
        • cuddZddSymmSiftingAux() +
        • cuddZddSymmSiftingConvAux() +
        • cuddZddSymmSifting_up() +
        • cuddZddSymmSifting_down() +
        • zdd_group_move() +
        • cuddZddSymmSiftingBackward() +
        • zdd_group_move_backward() +
        + ] + + 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. +
          +
        1. Order all the variables according to the number of entries in + each unique subtable. +
        2. Sift the variable up and down, remembering each time the total + size of the ZDD heap and grouping variables that are symmetric. +
        3. Select the best permutation. +
        4. Repeat 3 and 4 for all variables. +
        + 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. +
          +
        1. Order all the variables according to the number of entries in + each unique subtable. +
        2. Sift the variable up and down, remembering each time the total + size of the ZDD heap and grouping variables that are symmetric. +
        3. Select the best permutation. +
        4. Repeat 3 and 4 for all variables. +
        5. Repeat 1-4 until no further improvement. +
        + 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: +
          +
        • Cudd_zddPrintMinterm() +
        • Cudd_zddPrintCover() +
        • Cudd_zddPrintDebug() +
        • Cudd_zddDumpDot() +
        + Internal procedures included in this module: +
          +
        • cuddZddP() +
        + Static procedures included in this module: +
          +
        • zp2() +
        • zdd_print_minterm_aux() +
        + ] + + 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 > 0. Specifically: +
          +
        • pr = 0 : prints nothing +
        • pr = 1 : prints counts of nodes and minterms +
        • pr = 2 : prints counts + disjoint sum of products +
        • pr = 3 : prints counts + list of nodes +
        • pr > 3 : prints counts + disjoint sum of products + list of nodes +
        + 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.

        + A path is represented as an array of literals, which are integers in + {0, 1, 2}; 0 represents an else arc out of a node, 1 represents a then arc + out of a node, and 2 stands for the absence of a node. + The size of the array equals the number of variables in the manager at + the time Cudd_zddFirstCube is called.

        + The paths that end in the empty terminal are not enumerated.] + + SideEffects [The first path is returned as a side effect.] + + SeeAlso [Cudd_zddForeachPath Cudd_zddNextPath Cudd_GenFree + Cudd_IsGenEmpty] + +******************************************************************************/ +DdGen * +Cudd_zddFirstPath( + DdManager * zdd, + DdNode * f, + int ** path) +{ + DdGen *gen; + DdNode *top, *next, *prev; + int i; + int nvars; + + /* Sanity Check. */ + if (zdd == NULL || f == NULL) return(NULL); + + /* Allocate generator an initialize it. */ + gen = ALLOC(DdGen,1); + if (gen == NULL) { + zdd->errorCode = CUDD_MEMORY_OUT; + return(NULL); + } + + gen->manager = zdd; + gen->type = CUDD_GEN_ZDD_PATHS; + gen->status = CUDD_GEN_EMPTY; + gen->gen.cubes.cube = NULL; + gen->gen.cubes.value = DD_ZERO_VAL; + gen->stack.sp = 0; + gen->stack.stack = NULL; + gen->node = NULL; + + nvars = zdd->sizeZ; + gen->gen.cubes.cube = ALLOC(int,nvars); + if (gen->gen.cubes.cube == NULL) { + zdd->errorCode = CUDD_MEMORY_OUT; + FREE(gen); + return(NULL); + } + for (i = 0; i < nvars; i++) gen->gen.cubes.cube[i] = 2; + + /* The maximum stack depth is one plus the number of variables. + ** because a path may have nodes at all levels, including the + ** constant level. + */ + gen->stack.stack = ALLOC(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: +

          +
        • solid line: THEN arcs; +
        • dashed line: ELSE arcs. +
        + 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; iinvperm[i]); + } + (void) printf("\n"); + (void) printf("Inverse Permutation:"); + for (i=0; iperm[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 +#include +#include +#include +#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.

        + 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: +

          +
        • Mtr_AllocNode() +
        • Mtr_DeallocNode() +
        • Mtr_InitTree() +
        • Mtr_FreeTree() +
        • Mtr_CopyTree() +
        • Mtr_MakeFirstChild() +
        • Mtr_MakeLastChild() +
        • Mtr_CreateFirstChild() +
        • Mtr_CreateLastChild() +
        • Mtr_MakeNextSibling() +
        • Mtr_PrintTree() +
        + ] + + 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: +
          +
        • Mtr_InitGroupTree() +
        • Mtr_MakeGroup() +
        • Mtr_DissolveGroup() +
        • Mtr_FindGroup() +
        • Mtr_SwapGroups() +
        • Mtr_PrintGroups() +
        • Mtr_ReadGroups() +
        + Static procedures included in this module: +
          +
        • mtrShiftHL +
        + ] + + 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. +
          +
        • F: MTR_FIXED +
        • N: MTR_NEWNODE +
        • S: MTR_SOFT +
        + 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: + + low size flags. + + Low and size are (short) integers. Flags is a string composed of the + following characters (with associated translation): +
          +
        • D: MTR_DEFAULT +
        • F: MTR_FIXED +
        • N: MTR_NEWNODE +
        • S: MTR_SOFT +
        • T: MTR_TERMINAL +
        + 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 +#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 +#include +#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 + // + // + // 0 / \ 1 + // / \ + // / \ + // / \ + // / \ 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 + // + // + // 0 / \ 1 0 / \ 1 + // / \ / \ + // / \ / \ + // + // 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 + // + // + // 0 . \ 1 0 / \ 1 + // . \ / \ + // . \ / \ + // + // 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 + // + // + // 0 / \ 1 0 / \ 1 + // / \ / \ + // / \ / \ + // \ + // 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 + // + // + // 0 . \ 1 0 / \ 1 + // . \ / \ + // . \ / \ + // \ + // 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 + // + // + // 0 / \ 1 0 / \ 1 + // / \ / \ + // / \ / \ + // / + // / 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 ] + + 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 ] + + 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 +#include +#include +#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<pCutBest[fPhase]->M[fPhase].pSuperBest ); + return (( pNode->pCutBest[fPhase]->M[fPhase].uPhaseBest & (1<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 ] + + 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 +#include +#include +#include +#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 +#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<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<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] \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: + + + + is a zero-based integer + is a string of 2^n bits representing the value of the function for each minterm + is the maximum delay of the gate + is the array of n double values + is a floating point value + 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 +#include +#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( <ime ); + TimeStamp = asctime( localtime( <ime ) ); + 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< 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<nMapSize = (4<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<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<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 +#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 +#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 +#include "util.h" + + +#include +//#include +#ifdef HAVE_SYS_RESOURCE_H +# include +#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 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 +#endif + +#if HAVE_SYS_TIMES_H +# include +#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.

        + + There are two possibilities: +

          +
        1. 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 +
        2. The system is POSIX-compliant. unistd.h gives + us sysconf(), which tells us the clock rate. +
        + ] + + 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 ] + + 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 +#endif +#include +#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 +#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 +#include +#include +#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 +#endif + +#if HAVE_SYS_STAT_H +# include +#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 + + 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 +#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 +#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 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 +#include +#include + +//////////////// added by alanmi, November 22, 2001 //////////////// +//#include +#include +#include + +#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 +#endif + +#if HAVE_SYS_TYPES_H +# include +#endif + +#if HAVE_VARARGS_H +/////////////////////////////////////// +#undef __STDC__ +# include +#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 +# include +#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 +#endif + +/* + * Ensure we have reasonable assert() and fail() functions + */ + +#ifndef HAVE_ASSERT_H +#define HAVE_ASSERT_H 1 +#endif + +#if HAVE_ASSERT_H +# include +#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 +#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 +#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 +#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 +#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 +#include +#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 +#include +#include +//#include +//#include +//#include +//#include +//#include + +//================================================================================================= +// 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 ? "" : 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 +#include +#include + +#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 + +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 ] + + 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 ] + + 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 ] + + 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 +#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 ] + + 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 ] + + 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 ] + + 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 +#include +#include +#include +#include + +#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 ] + + 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 ] + + 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 ] + + 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 ] + + 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 >= 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 ] + + 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 ] + + 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 ] + + 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 + +//////////////////////////////////////////////////////////////////////// +/// 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< 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 ] + + 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 ] + + 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 ] + + 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 ] + + 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 ] + + 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 ] + + 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 +#include +#include +#include +#include +#include +#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 ] + + 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<nMapSize = (4<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<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 ] + + 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 ] + + 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 ] + + 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 ] + + 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 ] + + 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 ] + + 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 ] + + 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( <ime ); + TimeStamp = asctime( localtime( <ime ) ); + 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 ] + + 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 ] + + 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 ] + + 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 +#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< 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< 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< 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< 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< +#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<pData[iWordNew] |= (1<pData[iWordNew] &= ~(1<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<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 /// +//////////////////////////////////////////////////////////////////////// + + -- cgit v1.2.3