bddBdd.cpp

Go to the documentation of this file.
00001 /*
00002  * CrocoPat is a tool for relational programming.
00003  * This file is part of CrocoPat. 
00004  *
00005  * Copyright (C) 2002-2008  Dirk Beyer
00006  *
00007  * CrocoPat is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * CrocoPat is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public License
00018  * along with CrocoPat; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020  *
00021  * Please find the GNU Lesser General Public License in file
00022  * License_LGPL.txt or at http://www.gnu.org/licenses/lgpl.txt
00023  *
00024  * Author:
00025  * Dirk Beyer (firstname.lastname@sfu.ca)
00026  * Simon Fraser University
00027  *
00028  * With contributions of: Andreas Noack, Michael Vogel
00029  */
00030 
00031 #include "bddBdd.h"
00032 
00033 #include <vector>
00034 #include <iostream>
00035 #include <set>
00036 
00037 #include <climits>
00038 
00039 bddNode* bddBdd::mNodes = 0;
00040 unsigned bddBdd::mMaxNodeNr;
00041 unsigned bddBdd::mFree;
00042 
00043 multiset<unsigned> bddBdd::mExtRefs;
00044 
00045 unsigned* bddBdd::mUniqueHash = 0;
00046 unsigned bddBdd::mUniqueHBitNr;
00047 bddBinEntry* bddBdd::mBinCache = 0;
00048 unsigned bddBdd::mBinCBitNr;
00049 bddStatEntry* bddBdd::mStatCache = 0;
00050 unsigned bddBdd::mStatCBitNr;
00051 
00053 unsigned bddBdd::mRenameCnt = 0;
00054 
00057 inline void 
00058 bddBdd::normalize(unsigned& p1, unsigned& p2) 
00059 {
00060   if (p1 > p2) {
00061     unsigned tmp = p1;
00062     p1 = p2;
00063     p2 = tmp;
00064   }
00065 }
00066 
00068 inline unsigned 
00069 bddBdd::hash (unsigned i, unsigned hashBitNr) 
00070 {
00071   unsigned mask = (1u << hashBitNr) - 1;
00072   return i & mask;
00073 }
00074 
00075 inline unsigned 
00076 bddBdd::hash(unsigned i, unsigned j, unsigned k, unsigned hashBitNr) 
00077 {
00078   unsigned mask = (1u << hashBitNr) - 1;
00079   j ^= 0x55555555;   // XOR.
00080   return (i + 
00081     (j<<(hashBitNr>>1)) + (j>>(hashBitNr>>1)) +
00082     (k<<(hashBitNr>>2)) + (k>>(hashBitNr>>2))) & mask;
00083 }
00084 
00085 /*
00087 inline unsigned 
00088 bddBdd::hash(unsigned i, unsigned j, unsigned hashBitNr) {
00089   unsigned mask = (1u << hashBitNr) - 1;
00090   return (i + 
00091     ((j ^ 0x55555555)<<(hashBitNr>>1)) +
00092     (j<<(hashBitNr>>2)) + (j>>(hashBitNr>>2))) & mask;
00093 }
00094 
00095 inline unsigned 
00096 bddBdd::hash(unsigned i, unsigned j, unsigned hashBitNr) {
00097   return ((i * 17765507 + j) * 9243337) >> (32-hashBitNr);
00098 }
00099 
00100 inline unsigned 
00101 bddBdd::hash(unsigned i, unsigned j, unsigned k, unsigned hashBitNr) {
00102   return (((i * 14099753 + j) * 9243337 + k) * 3901787) >> (32-hashBitNr);
00103 }
00104 */
00105 
00107 void 
00108 bddBdd::mark(unsigned pRoot) 
00109 {
00110   if(!mNodes[pRoot].mark) 
00111   {
00112     mNodes[pRoot].mark = 1;
00113     mark(mNodes[pRoot].low);
00114     mark(mNodes[pRoot].high); 
00115   }
00116 }
00117 
00120 void 
00121 bddBdd::unMark(unsigned pRoot) 
00122 {
00123   if(mNodes[pRoot].mark && pRoot != 0 && pRoot != 1)
00124   {
00125     mNodes[pRoot].mark = 0;
00126     unMark(mNodes[pRoot].low);
00127     unMark(mNodes[pRoot].high);
00128   }
00129 }
00130 
00134 void 
00135 bddBdd::gc() 
00136 {
00137   // Mark all live nodes.
00138   for(multiset<unsigned>::iterator lIt = mExtRefs.begin();
00139       lIt != mExtRefs.end();
00140       lIt++)
00141   {
00142     mark(*lIt);
00143   }
00144   
00145   // Clear hash and caches.
00146   memset(mUniqueHash, 0, (1u << mUniqueHBitNr) * sizeof(unsigned));
00147   memset(mStatCache, 0, (1u << mStatCBitNr) * sizeof(bddStatEntry));
00148   memset(mBinCache, 0, (1u << mBinCBitNr) * sizeof(bddBinEntry));
00149 
00150   mFree = 0;
00151   for(unsigned lCnt = mMaxNodeNr-1; lCnt >= 2; --lCnt) 
00152   {
00153     if(!mNodes[lCnt].mark) 
00154     { 
00155       // Free dead nodes.
00156       mNodes[lCnt].low = mFree;
00157       mFree = lCnt;
00158     } 
00159     else 
00160     {                
00161       mNodes[lCnt].mark = 0;
00162       // Insert live nodes into mUniqueHash.
00163       unsigned lHashIndex = hash(
00164         mNodes[lCnt].var, mNodes[lCnt].low, mNodes[lCnt].high, mUniqueHBitNr);
00165       mNodes[lCnt].next = mUniqueHash[lHashIndex];
00166       mUniqueHash[lHashIndex] = lCnt;
00167     }
00168   }
00169 }
00170 
00171 
00175 unsigned 
00176 bddBdd::insert(unsigned pVar, unsigned pLow, unsigned pHigh) 
00177 {
00178   unsigned lHashIndex;
00179   unsigned lResult;
00180 
00181   // BDD-reduction of nodes with equal high- and low-child.
00182   if(pHigh == pLow) 
00183   {
00184     return pLow;
00185   }
00186 
00187   // Search mUniqueHash.
00188   lHashIndex = hash(pVar, pLow, pHigh, mUniqueHBitNr);
00189   lResult = mUniqueHash[lHashIndex];  
00190   while(lResult) 
00191   {
00192     if(   mNodes[lResult].var == pVar 
00193        && mNodes[lResult].low == pLow
00194        && mNodes[lResult].high == pHigh) 
00195     {
00196       return lResult;
00197     }
00198     lResult = mNodes[lResult].next;
00199   }
00200 
00201   // Create new node.
00202   if(mFree == 0)
00203   {
00204     throw "Error: BDD package out of memory\n";
00205   }
00206 
00207   lResult = mFree;
00208   mFree = mNodes[lResult].low;
00209   mNodes[lResult].var = pVar;
00210   mNodes[lResult].low = pLow;
00211   mNodes[lResult].high = pHigh;
00212   mNodes[lResult].next = mUniqueHash[lHashIndex];
00213   mUniqueHash[lHashIndex] = lResult;
00214 
00215   return lResult;
00216 }
00217 
00220 bool 
00221 bddBdd::testVars_(unsigned pRoot, 
00222                   unsigned pVarIdFirst, 
00223                   unsigned pVarIdLast)
00224 {
00225   // Note: Terminal nodes are always marked.
00226   if(mNodes[pRoot].mark)
00227   {
00228     return false;
00229   }
00230   mNodes[pRoot].mark = 1;
00231 
00232   // Node after forbidden range.
00233   if(mNodes[pRoot].var > pVarIdLast)
00234   {
00235     return false;
00236   }
00237   
00238   // Node within forbidden range.
00239   if(    mNodes[pRoot].var <= pVarIdLast 
00240      &&  mNodes[pRoot].var >= pVarIdFirst )
00241   {
00242     return true;
00243   }
00244 
00245   // Process node in front of forbidden range.
00246   if( testVars_(mNodes[pRoot].low,  pVarIdFirst, pVarIdLast) )
00247   {
00248     return true;
00249   }
00250 
00251   return testVars_(mNodes[pRoot].high,  pVarIdFirst, pVarIdLast);
00252 }
00253 
00257 double 
00258 bddBdd::getTupleNr_(unsigned pRoot, unsigned pVar, unsigned pMaxVar)
00259 {
00260   // Terminal case.
00261   if(pVar > pMaxVar)
00262   {
00263     return (pRoot == 0 ? 0.0 : 1.0);
00264   }
00265 
00266   // pVar <= pMaxVar.
00267 
00268   // Reduced node?
00269   if(pVar < mNodes[pRoot].var)
00270   {
00271     return 2 * getTupleNr_(pRoot, pVar + 1, pMaxVar);
00272   }
00273 
00274   // Forbid nodes with variable id less than 'pVar'.
00275   assert(pVar == mNodes[pRoot].var);
00276 
00277   // Now pVar == mNodes[pRoot].var holds.
00278   // Result in cache?
00279   unsigned lCacheIndex = hash(pRoot, mStatCBitNr);
00280   if(mStatCache[lCacheIndex].root == pRoot)
00281   {
00282     return mStatCache[lCacheIndex].result;
00283   }
00284 
00285   mStatCache[lCacheIndex].result 
00286     = getTupleNr_(mNodes[pRoot].low, pVar + 1, pMaxVar)
00287     + getTupleNr_(mNodes[pRoot].high, pVar + 1, pMaxVar);
00288   mStatCache[lCacheIndex].root = pRoot;
00289 
00290   return mStatCache[lCacheIndex].result;
00291 }
00292 
00294 unsigned 
00295 bddBdd::getTuple_(unsigned pRoot, unsigned pVar, unsigned pMaxVar)
00296 {
00297   // Terminal case.
00298   if(pVar > pMaxVar)
00299   {
00300     return 0;
00301   }
00302 
00303   // pVar <= pMaxVar.
00304 
00305   // Reduced node?
00306   if(pVar < mNodes[pRoot].var)
00307   {
00308     return getTuple_(pRoot, pVar + 1, pMaxVar);
00309   }
00310 
00311   if(pVar > mNodes[pRoot].var)
00312   {
00313     if (mNodes[pRoot].low != 0) {
00314       return getTuple_(mNodes[pRoot].low, pVar, pMaxVar);
00315     } else { 
00316       return getTuple_(mNodes[pRoot].high, pVar, pMaxVar);
00317     } 
00318   }
00319 
00320   // pVar == mNodes[pRoot].var.
00321 
00322   if (mNodes[pRoot].low != 0) {
00323     return getTuple_(mNodes[pRoot].low, pVar + 1, pMaxVar);
00324   } else { 
00325     return getTuple_(mNodes[pRoot].high, pVar + 1, pMaxVar)
00326       + (1 << (pMaxVar - pVar));
00327   } 
00328 }
00329 
00332 unsigned 
00333 bddBdd::getNodeNr_(unsigned pRoot) 
00334 {
00335   // Note: Terminal nodes are always marked.
00336   if(mNodes[pRoot].mark)
00337   {
00338     return 0;
00339   }
00340   mNodes[pRoot].mark = 1;
00341 
00342   return getNodeNr_(mNodes[pRoot].low) + getNodeNr_(mNodes[pRoot].high) + 1;
00343 }
00344 
00346 void 
00347 bddBdd::getNodesPerVarId_(unsigned pRoot, 
00348                           map<unsigned, unsigned>& pBddNodesPerVar)
00349 {
00350   // Note: Terminal nodes are always marked.
00351   if( !mNodes[pRoot].mark )
00352   {
00353     mNodes[pRoot].mark = 1;
00354     if ( pBddNodesPerVar.find(mNodes[pRoot].var) != pBddNodesPerVar.end() ) {
00355       ++ pBddNodesPerVar[mNodes[pRoot].var];
00356     } else {
00357       pBddNodesPerVar[mNodes[pRoot].var] = 1;
00358     }
00359     getNodesPerVarId_(mNodes[pRoot].low,  pBddNodesPerVar); 
00360     getNodesPerVarId_(mNodes[pRoot].high, pBddNodesPerVar);
00361   }
00362 }
00363 
00365 void 
00366 bddBdd::getGraph_(unsigned pRoot, 
00367                   multimap<unsigned,bddGraphNode>& pGraph)
00368 {
00369   // Note: Terminal nodes are always marked.
00370   if( !mNodes[pRoot].mark )
00371   {
00372     mNodes[pRoot].mark = 1;
00373 
00374     bddGraphNode node;
00375     node.id   = pRoot;
00376     node.var  = mNodes[pRoot].var;
00377     node.low  = mNodes[pRoot].low;
00378     node.high = mNodes[pRoot].high;
00379     pGraph.insert( pair<unsigned,bddGraphNode>(node.var, node) );
00380 
00381     getGraph_(mNodes[pRoot].low,  pGraph); 
00382     getGraph_(mNodes[pRoot].high, pGraph);
00383   }
00384 }
00385 
00387 void 
00388 bddBdd::print_(ostream& pS, unsigned pRoot)
00389 {
00390   if(pRoot == 1) 
00391   {
00392     cout << 'T';
00393   }
00394   else 
00395   {
00396     if(pRoot == 0)
00397     {
00398       cout << 'F';
00399     }
00400     else 
00401     {
00402       cout << '(';
00403       print_(pS, mNodes[pRoot].low);
00404       cout << ' ' << mNodes[pRoot].var << ' ';
00405       print_(pS, mNodes[pRoot].high);
00406       cout << ')';
00407     }
00408   }
00409 }
00410 
00412 bool 
00413 bddBdd::setContains_(unsigned pRoot1, unsigned pRoot2) 
00414 {
00415   unsigned lCacheIndex;
00416   unsigned lResult;
00417 
00418   // Terminal cases.
00419   if(pRoot1 == 1)
00420   {
00421     return true;
00422   }
00423   if(pRoot2 == 0)
00424   {
00425     return true;
00426   }
00427   if(pRoot1 == pRoot2)
00428   {
00429     return true;
00430   }
00431   if(pRoot1 == 0) // Assumes pRoot2 != 0.
00432   {
00433     return false;
00434   }
00435   if(pRoot2 == 1) // Assumes pRoot1 != 1.
00436   {
00437     return false;
00438   }
00439   
00440   // Result in Cache?
00441   lCacheIndex = hash(mSetContains, pRoot1, pRoot2, mBinCBitNr);
00442   if(mBinCache[lCacheIndex].op == mSetContains
00443     && mBinCache[lCacheIndex].root1 == pRoot1
00444     && mBinCache[lCacheIndex].root2 == pRoot2) 
00445   {
00446     return mBinCache[lCacheIndex].result;
00447   }
00448 
00449   // Compute result.
00450   if(mNodes[pRoot1].var < mNodes[pRoot2].var)
00451   {
00452     lResult = setContains_(mNodes[pRoot1].low, pRoot2)
00453       && setContains_(mNodes[pRoot1].high, pRoot2);
00454   }
00455   else 
00456   {
00457     if(mNodes[pRoot1].var == mNodes[pRoot2].var)
00458     {
00459       lResult = setContains_(mNodes[pRoot1].low, mNodes[pRoot2].low)
00460         && setContains_(mNodes[pRoot1].high, mNodes[pRoot2].high);
00461     }
00462     else 
00463     {
00464       lResult = setContains_(pRoot1, mNodes[pRoot2].low)
00465         && setContains_(pRoot1, mNodes[pRoot2].high);
00466     }
00467   }
00468 
00469   // Write result into cache.
00470   mBinCache[lCacheIndex].result = lResult;
00471   mBinCache[lCacheIndex].op = mSetContains;
00472   mBinCache[lCacheIndex].root1 = pRoot1;
00473   mBinCache[lCacheIndex].root2 = pRoot2;
00474 
00475   return lResult;
00476 }
00477 
00478 unsigned 
00479 bddBdd::complement_(unsigned pRoot) 
00480 {
00481   unsigned lCacheIndex;
00482   unsigned lResult;
00483 
00484   if(pRoot == 0)
00485   {
00486     return 1;
00487   }
00488   if(pRoot == 1)
00489   {
00490     return 0;
00491   }
00492 
00493   lCacheIndex = hash(mComplement, pRoot, pRoot, mBinCBitNr);
00494   if(mBinCache[lCacheIndex].op == mComplement
00495     && mBinCache[lCacheIndex].root1 == pRoot) 
00496   {
00497     return mBinCache[lCacheIndex].result;
00498   }
00499 
00500   lResult = insert(mNodes[pRoot].var,
00501                    complement_(mNodes[pRoot].low), 
00502                    complement_(mNodes[pRoot].high));
00503 
00504   mBinCache[lCacheIndex].result = lResult;
00505   mBinCache[lCacheIndex].op = mComplement;
00506   mBinCache[lCacheIndex].root1 = pRoot;
00507 
00508   return lResult;
00509 }
00510 
00511 unsigned 
00512 bddBdd::unite_(unsigned pRoot1, unsigned pRoot2) 
00513 {
00514   if(pRoot1 == 1) 
00515   {
00516     return 1;
00517   }
00518   if(pRoot2 == 1) 
00519   {
00520     return 1;
00521   }
00522   if(pRoot1 == 0)
00523   {
00524     return pRoot2;
00525   }
00526   if(pRoot2 == 0)
00527   {
00528     return pRoot1;
00529   }
00530   if(pRoot1 == pRoot2)
00531   {
00532     return pRoot1;
00533   }
00534 
00535   normalize(pRoot1, pRoot2);
00536   unsigned lResult;
00537   unsigned lCacheIndex = hash(mUnite, pRoot1, pRoot2, mBinCBitNr);
00538   if (mBinCache[lCacheIndex].op == mUnite
00539     && mBinCache[lCacheIndex].root1 == pRoot1
00540     && mBinCache[lCacheIndex].root2 == pRoot2) 
00541   {
00542     return mBinCache[lCacheIndex].result;
00543   }
00544 
00545   if(mNodes[pRoot1].var < mNodes[pRoot2].var)
00546   {
00547     lResult = insert(mNodes[pRoot1].var,
00548                      unite_(mNodes[pRoot1].low, pRoot2), 
00549                      unite_(mNodes[pRoot1].high, pRoot2));
00550   }
00551   else 
00552   {
00553     if(mNodes[pRoot1].var == mNodes[pRoot2].var)
00554     {
00555       lResult = insert(mNodes[pRoot1].var,
00556                        unite_(mNodes[pRoot1].low, mNodes[pRoot2].low), 
00557                        unite_(mNodes[pRoot1].high, mNodes[pRoot2].high));
00558     }
00559     else 
00560     {
00561       lResult = insert(mNodes[pRoot2].var,
00562                        unite_(pRoot1, mNodes[pRoot2].low), 
00563                        unite_(pRoot1, mNodes[pRoot2].high));
00564     }
00565   }
00566 
00567   mBinCache[lCacheIndex].result = lResult;
00568   mBinCache[lCacheIndex].op = mUnite;
00569   mBinCache[lCacheIndex].root1 = pRoot1;
00570   mBinCache[lCacheIndex].root2 = pRoot2;
00571 
00572   return lResult;
00573 }
00574 
00575 unsigned 
00576 bddBdd::intersect_(unsigned pRoot1, unsigned pRoot2) 
00577 {
00578   if(pRoot1 == 0) 
00579   {
00580     return 0;
00581   }
00582   if(pRoot2 == 0) 
00583   {
00584     return 0;
00585   }
00586   if(pRoot1 == 1) 
00587   {
00588     return pRoot2;
00589   }
00590   if(pRoot2 == 1) 
00591   {
00592     return pRoot1;
00593   }
00594   if(pRoot1 == pRoot2)
00595   {
00596     return pRoot1;
00597   }
00598 
00599   normalize(pRoot1, pRoot2);
00600   unsigned lResult;
00601   unsigned lCacheIndex = hash(mIntersect, pRoot1, pRoot2, mBinCBitNr);
00602   if(mBinCache[lCacheIndex].op == mIntersect
00603     && mBinCache[lCacheIndex].root1 == pRoot1
00604     && mBinCache[lCacheIndex].root2 == pRoot2) 
00605   {
00606     return mBinCache[lCacheIndex].result;
00607   }
00608 
00609   if(mNodes[pRoot1].var < mNodes[pRoot2].var) 
00610   {
00611     lResult = insert(mNodes[pRoot1].var,
00612                      intersect_(mNodes[pRoot1].low, pRoot2), 
00613                      intersect_(mNodes[pRoot1].high, pRoot2));
00614   }
00615   else 
00616   {
00617     if(mNodes[pRoot1].var == mNodes[pRoot2].var)
00618     {
00619       lResult = insert(mNodes[pRoot1].var,
00620                        intersect_(mNodes[pRoot1].low, mNodes[pRoot2].low), 
00621                        intersect_(mNodes[pRoot1].high, mNodes[pRoot2].high));
00622     }
00623     else 
00624     {
00625       lResult = insert(mNodes[pRoot2].var,
00626                        intersect_(pRoot1, mNodes[pRoot2].low), 
00627                        intersect_(pRoot1, mNodes[pRoot2].high));
00628     }
00629   }
00630 
00631   mBinCache[lCacheIndex].result = lResult;
00632   mBinCache[lCacheIndex].op = mIntersect;
00633   mBinCache[lCacheIndex].root1 = pRoot1;
00634   mBinCache[lCacheIndex].root2 = pRoot2;
00635 
00636   return lResult;
00637 }
00638 
00639 unsigned 
00640 bddBdd::exists_(unsigned pRoot, unsigned pVar)
00641 {
00642   unsigned lCacheIndex;
00643   unsigned lResult;
00644 
00645   if(mNodes[pRoot].var < pVar)
00646   {
00647     lCacheIndex = hash(mExists, pRoot, pVar, mBinCBitNr);
00648     if(mBinCache[lCacheIndex].op == mExists
00649        && mBinCache[lCacheIndex].root1 == pRoot
00650        && mBinCache[lCacheIndex].root2 == pVar) 
00651     {
00652       return mBinCache[lCacheIndex].result;
00653     }
00654 
00655     lResult = insert(mNodes[pRoot].var,
00656                      exists_(mNodes[pRoot].low, pVar), 
00657                      exists_(mNodes[pRoot].high, pVar));
00658 
00659     mBinCache[lCacheIndex].result = lResult;
00660     mBinCache[lCacheIndex].op = mExists;
00661     mBinCache[lCacheIndex].root1 = pRoot;
00662     mBinCache[lCacheIndex].root2 = pVar;
00663   }
00664   else 
00665   { 
00666     if(mNodes[pRoot].var == pVar)
00667     {
00668       lResult = unite_(mNodes[pRoot].low, mNodes[pRoot].high);
00669     }
00670     else
00671     {
00672       lResult = pRoot;
00673     }
00674   }
00675 
00676   return lResult;
00677 }
00678 
00681 unsigned 
00682 bddBdd::renameVars_ (unsigned pRoot, 
00683                      unsigned pFirst, 
00684                      unsigned pLast, 
00685                      int      pOffset) 
00686 {
00687   if(pRoot == 0 || pRoot == 1)
00688   {
00689     return pRoot;
00690   }
00691 
00692   if(mNodes[pRoot].var > pLast)
00693   {
00694     // Process variable ids after pLast.
00695     return pRoot;
00696   }
00697 
00698   // The variable (mRenameCnt) is set by renameVars(), 
00699   //   such that its value is unique in each execution of renameVars().
00700   // Lookup cache.
00701   unsigned lCacheIndex = hash(mRenameVars, pRoot, mRenameCnt, mBinCBitNr);
00702   if(mBinCache[lCacheIndex].op == mRenameVars
00703     && mBinCache[lCacheIndex].root1 == pRoot
00704     && mBinCache[lCacheIndex].root2 == mRenameCnt) 
00705   {
00706     return mBinCache[lCacheIndex].result;
00707   }
00708 
00709   unsigned lResult;
00710   if(mNodes[pRoot].var < pFirst)
00711   {
00712     // Process variable ids in front of pFirst.
00713     lResult = insert(mNodes[pRoot].var,
00714                      renameVars_(mNodes[pRoot].low,  pFirst, pLast, pOffset),
00715                      renameVars_(mNodes[pRoot].high, pFirst, pLast, pOffset));
00716   }
00717   else
00718   {
00719     // Rename node pRoot.
00720     lResult = insert(mNodes[pRoot].var + pOffset,
00721                      renameVars_(mNodes[pRoot].low, pFirst, pLast, pOffset),
00722                      renameVars_(mNodes[pRoot].high, pFirst, pLast, pOffset));
00723   }
00724   
00725 
00726   // Write result into cache.
00727   mBinCache[lCacheIndex].result = lResult;
00728   mBinCache[lCacheIndex].op = mRenameVars;
00729   mBinCache[lCacheIndex].root1 = pRoot;
00730   mBinCache[lCacheIndex].root2 = mRenameCnt;
00731 
00732   return lResult;
00733 }
00734 
00742 void 
00743 bddBdd::init (unsigned pMaxNodeNr, 
00744               unsigned pUniqueHBitNr, 
00745               unsigned pBinCBitNr, 
00746               unsigned pStatCBitNr) {
00747 
00748   // Allocate memory.
00749   mMaxNodeNr = pMaxNodeNr+2;
00750   mNodes = new bddNode[mMaxNodeNr];
00751 
00752   mUniqueHBitNr = pUniqueHBitNr;
00753   mUniqueHash = new unsigned[1u << mUniqueHBitNr];
00754 
00755   mBinCBitNr = pBinCBitNr;
00756   mBinCache = new bddBinEntry[1u << mBinCBitNr];
00757   mStatCBitNr = pStatCBitNr;
00758   mStatCache = new bddStatEntry[1u << mStatCBitNr];
00759 
00760   if(!mNodes || !mUniqueHash || !mBinCache  || !mStatCache) 
00761   {
00762     cerr << "Error: "
00763          << "Not enough memory for initialization of BDD package." << endl;
00764     exit(EXIT_FAILURE);
00765   }
00766 
00767   // Initialise arrays.
00768   memset(mNodes, 0, mMaxNodeNr * sizeof(bddNode));
00769   memset(mUniqueHash, 0, (1u << mUniqueHBitNr) * sizeof(unsigned));
00770   memset(mBinCache, 0, (1u << mBinCBitNr) * sizeof(bddBinEntry));
00771   memset(mStatCache, 0, (1u << mStatCBitNr) * sizeof(bddStatEntry));
00772 
00773   // Initialise terminal nodes.
00774   mNodes[0].var = (unsigned)-1;
00775   mNodes[0].mark = 1;
00776   mNodes[1].var = (unsigned)-1;
00777   mNodes[1].mark = 1;
00778 
00779   // Initialise mFree list of unused nodes.
00780   mFree = 2;
00781   for(unsigned lCnt = 2; lCnt < mMaxNodeNr-1; lCnt++)
00782   {
00783     mNodes[lCnt].low = lCnt+1;
00784   }
00785 }
00786 
00788 void 
00789 bddBdd::done () {
00790   delete mNodes;
00791   delete mUniqueHash;
00792   delete mBinCache;
00793   delete mStatCache;
00794 }
00795 
00797 unsigned 
00798 bddBdd::getReachNodeNr()
00799 {
00800   unsigned lResult;
00801 
00802   lResult = 0;
00803   for(multiset<unsigned>::iterator lIt = mExtRefs.begin();
00804       lIt != mExtRefs.end(); 
00805       ++lIt)
00806   {
00807     lResult += getNodeNr_(*lIt);
00808   }
00809 
00810   for(multiset<unsigned>::iterator lIt = mExtRefs.begin();
00811       lIt != mExtRefs.end(); 
00812       ++lIt)
00813   {
00814     unMark(*lIt);
00815   }
00816 
00817   return lResult;
00818 }
00819 
00821 unsigned 
00822 bddBdd::getExtRefNr()
00823 {
00824   return mExtRefs.size();
00825 }
00826 
00828 void 
00829 bddBdd::analyseUniqueHash() 
00830 {
00831   vector<unsigned> lListLenCnts;
00832   unsigned lListLen;
00833   unsigned lUniqueElem;
00834 
00835   for(unsigned lCnt = 0; lCnt < (1u << mUniqueHBitNr); lCnt++) 
00836   {
00837     lListLen = 0;
00838     lUniqueElem = mUniqueHash[lCnt];
00839     while(lUniqueElem) 
00840     {
00841       lUniqueElem = mNodes[lUniqueElem].next;
00842       ++lListLen;
00843     }
00844     ++lListLenCnts[lListLen];
00845   }
00846 
00847   cout << "Size of uniqueHash: " << (1u << mUniqueHBitNr) << '\n';
00848   cout << "n | number of lists of length n in uniqueHash:\n";
00849   for(unsigned lCnt = 0; lCnt < lListLenCnts.size(); lCnt++)
00850     cout << lCnt << ' ' << lListLenCnts[lCnt] << '\n';
00851 }
00852 
00854 bddBdd::bddBdd(unsigned pVarId, bool pValue) 
00855 {
00856   try 
00857   {
00858     mRoot = bddBdd::bddBdd_(pVarId, pValue);
00859   }
00860   catch(...) 
00861   {
00862     bddBdd::gc();
00863     try
00864     {
00865       mRoot = bddBdd::bddBdd_(pVarId, pValue);
00866     }
00867     catch(...)
00868     {
00869       cerr << "Error: BDD package out of memory." << endl;
00870       exit(EXIT_FAILURE);
00871     }
00872   }
00873   incRef();
00874 }
00875 
00877 unsigned 
00878 bddBdd::bddBdd_(unsigned pVarId, bool pValue) 
00879 {
00880   if (pValue) 
00881   {
00882     return insert(pVarId, 0, 1);
00883   }
00884   else
00885   {
00886     return insert(pVarId, 1, 0);
00887   }
00888 }
00889 
00892 bddBdd::bddBdd(unsigned pVarId, unsigned pBitNr, unsigned pValue)
00893 {
00894   try 
00895   {
00896     mRoot = bddBdd::bddBdd_(pVarId, pBitNr, pValue);
00897   }
00898   catch(...) 
00899   {
00900     bddBdd::gc();
00901     try
00902     {
00903       mRoot = bddBdd::bddBdd_(pVarId, pBitNr, pValue);
00904     }
00905     catch(...)
00906     {
00907       cerr << "Error: BDD package out of memory." << endl;
00908       exit(EXIT_FAILURE);
00909     }
00910   }
00911   incRef();
00912 }
00913 
00916 unsigned 
00917 bddBdd::bddBdd_(unsigned pVarId, unsigned pBitNr, unsigned pValue)
00918 {
00919   unsigned result = 1;
00920 
00921   // For all bits of the binary encoding of 'pValue'.
00922   for (unsigned lIt = 0; 
00923        lIt < pBitNr;
00924        ++lIt)
00925   {
00926     unsigned lPosition = pVarId + (pBitNr - lIt - 1);
00927     if ( (pValue & (1<<lIt)) > 0 )
00928     {
00929       result = insert(lPosition, 0, result);
00930     }
00931     else
00932     {
00933       result = insert(lPosition, result, 0);
00934     }
00935   }
00936   return result;
00937 }
00938 
00940 bddBdd::bddBdd(unsigned pVarId1, unsigned pVarId2)
00941 {
00942   try 
00943   {
00944     mRoot = bddBdd::bddBdd_(pVarId1, pVarId2);
00945   }
00946   catch(...) 
00947   {
00948     bddBdd::gc();
00949     try
00950     {
00951       mRoot = bddBdd::bddBdd_(pVarId1, pVarId2);
00952     }
00953     catch(...)
00954     {
00955       cerr << "Error: BDD package out of memory." << endl;
00956       exit(EXIT_FAILURE);
00957     }
00958   }
00959   incRef();
00960 }
00961   
00963 unsigned 
00964 bddBdd::bddBdd_(unsigned pVarId1, unsigned pVarId2)
00965 {
00966   unsigned topVarId    = pVarId1;
00967   unsigned bottomVarId = pVarId2;
00968   if(pVarId1 > pVarId2)
00969   {
00970     topVarId    = pVarId2;
00971     bottomVarId = pVarId1;
00972   }
00973   return insert(topVarId,
00974                 insert(bottomVarId, 1, 0),
00975                 insert(bottomVarId, 0, 1)
00976                 );
00977 }
00978   
00979 bddBdd& 
00980 bddBdd::operator=(const bddBdd& pBdd) 
00981 {
00982   decRef();
00983   mRoot = pBdd.mRoot;
00984   incRef();
00985   return *this;
00986 }
00987 
00990 bddBdd
00991 bddBdd::mkLessEqual(unsigned pVarId, unsigned pBitNr, unsigned pValue)
00992 {
00993   // pValue < 2^pBitNr.
00994   assert(pValue < (unsigned)(1<<pBitNr));
00995 
00996   unsigned lRoot;
00997   try 
00998   {
00999     lRoot = bddBdd::mkLessEqual_(pVarId, pBitNr, pValue);
01000   }
01001   catch(...) 
01002   {
01003     bddBdd::gc();
01004     try
01005     {
01006       lRoot = bddBdd::mkLessEqual_(pVarId, pBitNr, pValue);
01007     }
01008     catch(...)
01009     {
01010       cerr << "Error: BDD package out of memory." << endl;
01011       exit(EXIT_FAILURE);
01012     }
01013   }
01014   return bddBdd(lRoot);
01015 }
01016 
01019 unsigned 
01020 bddBdd::mkLessEqual_(unsigned pVarId, unsigned pBitNr, unsigned pValue)
01021 {
01022   unsigned result = 1;
01023 
01024   // For all bits of the binary encoding of 'pValue'.
01025   for (unsigned lIt = 0; 
01026        lIt < pBitNr;
01027        ++lIt)
01028   {
01029     unsigned lPosition = pVarId + (pBitNr - lIt - 1);
01030     if ( (pValue & (1<<lIt)) > 0 )
01031     {
01032       result = insert(lPosition, 1, result);
01033     }
01034     else
01035     {
01036       result = insert(lPosition, result, 0);
01037     }
01038   }
01039   return result;
01040 }
01041 
01043 unsigned 
01044 bddBdd::getNodeNr() const
01045 {
01046   unsigned lResult = getNodeNr_(mRoot);
01047   unMark(mRoot);  
01048   return lResult;
01049 }
01050 
01052 unsigned 
01053 bddBdd::getFreeNodeNr() const
01054 {
01055   // Includes garbage collection to get real values.
01056   bddBdd::gc();
01057 
01058   unsigned result = 0;
01059   unsigned lFreePos = mFree;
01060 
01061   while( lFreePos != 0 )
01062   {
01063     ++result;
01064     lFreePos = mNodes[lFreePos].low;
01065   }
01066   return result;
01067 }
01068 
01069 
01071 void 
01072 bddBdd::complement() 
01073 {
01074   unsigned lResult;
01075   try 
01076   {
01077     lResult = bddBdd::complement_(mRoot);
01078   }
01079   catch(...) 
01080   {
01081     // Out of free nodes in nodes array. Collect Garbage and try again.
01082     bddBdd::gc();
01083     try
01084     {
01085       lResult = bddBdd::complement_(mRoot);
01086     }
01087     catch(...)
01088     {
01089       cerr << "Error: BDD package out of memory." << endl;
01090       exit(EXIT_FAILURE);
01091     }
01092   }
01093   decRef();
01094   mRoot = lResult;
01095   incRef();
01096 }
01097 
01099 void 
01100 bddBdd::unite(const bddBdd& pBdd) 
01101 {
01102   unsigned lResult;
01103   try 
01104   {
01105     lResult = bddBdd::unite_(mRoot, pBdd.mRoot);
01106   }
01107   catch(...) 
01108   {
01109     bddBdd::gc();
01110     try
01111     {
01112       lResult = bddBdd::unite_(mRoot, pBdd.mRoot);
01113     }
01114     catch(...)
01115     {
01116       cerr << "Error: BDD package out of memory." << endl;
01117       exit(EXIT_FAILURE);
01118     }
01119   }
01120   decRef();
01121   mRoot = lResult;
01122   incRef();
01123 }
01124 
01126 void 
01127 bddBdd::intersect(const bddBdd& pBdd) 
01128 {
01129   unsigned lResult;
01130   try 
01131   {
01132     lResult = bddBdd::intersect_(mRoot, pBdd.mRoot);
01133   }
01134   catch(...) 
01135   {
01136     bddBdd::gc();
01137     try
01138     {
01139       lResult = bddBdd::intersect_(mRoot, pBdd.mRoot);
01140     }
01141     catch(...)
01142     {
01143       cerr << "Error: BDD package out of memory." << endl;
01144       exit(EXIT_FAILURE);
01145     }
01146   }
01147   decRef();
01148   mRoot = lResult;
01149   incRef();
01150 }
01151 
01153 void 
01154 bddBdd::exists(unsigned pVar) 
01155 {
01156   unsigned lResult;
01157   try 
01158   {
01159     lResult = bddBdd::exists_(mRoot, pVar);
01160   }
01161   catch(...) 
01162   {
01163     bddBdd::gc();
01164     try
01165     {
01166       lResult = bddBdd::exists_(mRoot, pVar);
01167     }
01168     catch(...)
01169     {
01170       cerr << "Error: BDD package out of memory." << endl;
01171       exit(EXIT_FAILURE);
01172     }
01173   }
01174   decRef();
01175   mRoot = lResult;
01176   incRef();
01177 }
01178 
01181 void 
01182 bddBdd::renameVars(unsigned pFirst, unsigned pLast, int pOffset)
01183 {
01184   unsigned lResult;
01185   try 
01186   {
01187     lResult = bddBdd::renameVars_(mRoot, pFirst, pLast, pOffset);
01188   }
01189   catch(...) 
01190   {
01191     bddBdd::gc();
01192     try
01193     {
01194       lResult = bddBdd::renameVars_(mRoot, pFirst, pLast, pOffset);
01195     }
01196     catch(...)
01197     {
01198       cerr << "Error: BDD package out of memory." << endl;
01199       exit(EXIT_FAILURE);
01200     }
01201   }
01202   decRef();
01203   mRoot = lResult;
01204   incRef();
01205 
01206   // Create a fresh, unique cache entry operand for the next call. 
01207   if (mRenameCnt < UINT_MAX) {
01208     ++mRenameCnt;
01209   } else {
01210     mRenameCnt = 0;
01211     bddBdd::gc();
01212   }
01213 }
01214 

Generated on Fri Jun 6 22:21:09 2008 for CrocoPat by  doxygen 1.5.1