bddRelation.h

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 #ifndef _bddRelation_h_
00032 #define _bddRelation_h_
00033 
00034 #include "bddBdd.h"
00035 #include "bddSymTab.h"
00036 #include "relDataType.h"
00037 
00039 extern string unsigned2string(unsigned pUnsigned);
00040 
00054 class bddRelation : public relDataType
00055 {
00056 
00057 private: // Private static methods.
00058 
00060   static bddRelation
00061   mkEqualPure(const bddSymTab* pSymTab,
00062               unsigned pVarId, 
00063               reprNUMBER pConst)
00064   {
00065     return bddRelation(pSymTab,  
00066                        bddBdd(pVarId, pSymTab->getBitNr(), pConst) );
00067   }
00068 
00069 public: // Public static methods.
00070 
00076   static bddRelation
00077   mkEqual(const bddSymTab* pSymTab,
00078           unsigned pVarId, 
00079           reprNUMBER pConst)
00080   {
00081     // Standard operation.
00082     assert(pConst < pSymTab->getUniverseSize());
00083 
00084     bddRelation result = mkEqualPure(pSymTab, pVarId, pConst);
00085 
00086     if( pConst+1 == pSymTab->getUniverseSize() )  // '+' because we use unsigned.
00087     {
00088       // If (pConst) is the value (pSymTab->getUniverseSize()-1)
00089       //   i.e., the maximal value,
00090       //   then (result) must contain all values greater than or equal to 
00091       //   (pSymTab->getUniverseSize()-1), i.e. from the interval 
00092       //   [ pSymTab->getUniverseSize()-1, 2^(pSymTab->getBitNr())-1 ].
00093       // We just need to add the values outside the 'valid range'.
00094       bddRelation lTmp = mkRange(pSymTab, pVarId);
00095       lTmp.complement();
00096       result.unite(lTmp);
00097     }
00098     return result;
00099   }
00100 
00103   static bddRelation
00104   mkRange(const bddSymTab* pSymTab,
00105           unsigned pVarId)
00106   {
00107     return bddRelation(pSymTab, 
00108                        bddBdd::mkLessEqual(pVarId,
00109                                            pSymTab->getBitNr(),
00110                                            pSymTab->getUniverseSize() - 1 ) 
00111                        );
00112   }
00113 
00115   static bddRelation
00116   mkEqual(const bddSymTab* pSymTab,
00117           const string& pVar1, 
00118           const string& pVar2)
00119   {
00120     bddRelation result(pSymTab, false);
00121     unsigned lVarId1 = pSymTab->getAttributePos(pVar1);
00122     unsigned lVarId2 = pSymTab->getAttributePos(pVar2);
00123 
00124     for(reprNUMBER lValueIt = 0;
00125         lValueIt < pSymTab->getUniverseSize();
00126         ++lValueIt)
00127     {
00128       bddRelation lValuePair = mkEqual(pSymTab, lVarId1, lValueIt);
00129       lValuePair.intersect(    mkEqual(pSymTab, lVarId2, lValueIt));
00130       result.unite(lValuePair);
00131     }
00132     return result;
00133   }
00134 
00137   static bddRelation
00138   mkLess(const bddSymTab* pSymTab,
00139          const string& pVar1, 
00140          const string& pVar2)
00141   {
00142     bddRelation result(pSymTab, false);
00143     unsigned lVarId1 = pSymTab->getAttributePos(pVar1);
00144     unsigned lVarId2 = pSymTab->getAttributePos(pVar2);
00145     assert(lVarId1 <= lVarId2);
00146 
00147     bddRelation lVar2Values(pSymTab, false);
00148     for(int lValueIt = pSymTab->getUniverseSize()-1;
00149         lValueIt > 0 ;
00150         --lValueIt)
00151     {
00152       // Construct set {lValueIt, ..., getUniverseSize()-1}
00153       lVar2Values.unite( mkEqual(pSymTab, lVarId2, lValueIt) );
00154 
00155       // Construct relation {lValueIt-1 < lValueIt, ..., lValueIt-1 < pSymTab->getUniverseSize()-1}.
00156       bddRelation lRel(lVar2Values);
00157       lRel.intersect( mkEqual(pSymTab, lVarId1, lValueIt-1) );
00158       result.unite(lRel);
00159     }
00160     return result;
00161   }
00162 
00165   static bddRelation
00166   mkAttributeValue(const bddSymTab* pSymTab,
00167                    const string& pAttributeName, 
00168                    const string& pAttributeValue)
00169   {
00170     return mkEqual(pSymTab, 
00171                    pSymTab->getAttributePos(pAttributeName), 
00172                    pSymTab->getValueNum(pAttributeValue));
00173   }
00174   
00175 private: // Attributes.
00176 
00178   const bddSymTab* mSymTab;
00180   bddBdd mBdd;
00181 
00182 public: // Attributes.
00183 
00189   int mArity;
00190 
00191 public: // Constructors and destructor.
00192   
00193   bddRelation(const bddSymTab* pSymTab, bool full)
00194     : mSymTab(pSymTab),
00195       mBdd(full),
00196       mArity(-1)
00197   {}
00198   // Use the standard copy constructor. 
00199   // Use the standard destructor.
00200   // Use the standard operator '='.
00201 
00202 private:
00203 
00204   bddRelation(const bddSymTab* pSymTab, const bddBdd& pBdd)
00205     : mSymTab(pSymTab),
00206       mBdd(pBdd),
00207       mArity(-1)
00208   {}
00210   bddRelation(void*);
00212   void operator,(const bddRelation&);
00213 
00214 private: // Service methods.
00215 
00218   void
00219   renameSafe(unsigned pVarIdOld, unsigned pVarIdNew, unsigned pBitNr) 
00220   {
00221     // Walk through all BDD variables.
00222 
00223     // For all bits of the binary encoding of both attributes.
00224     if( pVarIdOld > pVarIdNew )
00225     {
00226       for (unsigned lIt = 0; 
00227            lIt < pBitNr;
00228            ++lIt)
00229       {
00230         unsigned lPosOld = pVarIdOld + lIt;     
00231         unsigned lPosNew = pVarIdNew + lIt;     
00232         
00233         mBdd.intersect(bddBdd(lPosOld, lPosNew));
00234         mBdd.exists(lPosOld);
00235       }
00236     }
00237     else
00238     {
00239       for (int lIt = pBitNr-1; 
00240            lIt >= 0;
00241            --lIt)
00242       {
00243         unsigned lPosOld = pVarIdOld + lIt;     
00244         unsigned lPosNew = pVarIdNew + lIt;     
00245         
00246         mBdd.intersect(bddBdd(lPosOld, lPosNew));
00247         mBdd.exists(lPosOld);
00248       }
00249     }
00250   }
00251 
00252 
00253 public: // Service methods.
00254 
00257   double
00258   getTupleNr(const set<string>& pFree) const
00259   {
00260     if (pFree.size() == 0) {
00261       return isEmpty() ? 0 : 1;
00262     }
00263 
00264     map<unsigned,string> lVarOrd = mSymTab->computeVariableOrder(pFree);
00265     unsigned lFirstVar = lVarOrd.begin()->first;
00266     unsigned lLastVar  = (--lVarOrd.end())->first;
00267     assert(lFirstVar <= lLastVar);
00268 
00269     // First exclude out-of-range bit vectors 
00270     //   (see comment at top of the class).
00271     bddRelation lTmp = *this;
00272     { // For all attributes in the given range.
00273       for (unsigned lVarId = lFirstVar;  
00274            lVarId <= lLastVar;  
00275            lVarId += mSymTab->getBitNr() ) 
00276       {
00277         bddRelation lRange(mSymTab, false);
00278         if (lVarOrd.find(lVarId) == lVarOrd.end()) {
00279           lRange.unite(mkEqualPure(mSymTab, lVarId, 0));
00280         } else {
00281           lRange.unite(mkRange(mSymTab, lVarId));
00282         }
00283         lTmp.intersect(lRange);
00284       }
00285     }
00286 
00287     // No nodes allowed in front of the first variable id.
00288     assert( !lTmp.mBdd.testVars(0, lFirstVar - 1) );
00289     return lTmp.mBdd.getTupleNr(lFirstVar, lLastVar + mSymTab->getBitNr() - 1);
00290   }
00291 
00294   string
00295   getElement(unsigned pVarId)
00296   {
00297     unsigned lNumValue = mBdd.getTuple(pVarId, pVarId + mSymTab->getBitNr()-1);
00298     return mSymTab->getAttributeValue(lNumValue);
00299   }
00300 
00301 
00302 public: // Operations.
00303 
00304   bool
00305   setEqual(const bddRelation& p) const {
00306     return mBdd.setEqual( p.mBdd );
00307   }
00308 
00310   bool
00311   setContains(const bddRelation& p) const {
00312     return mBdd.setContains( p.mBdd );
00313   }
00314   
00315   bool
00316   isEmpty() const {
00317     return mBdd.isEmpty();
00318   }
00319   
00320   void
00321   complement() {
00322     mBdd.complement();
00323   }
00324 
00325   void
00326   unite(const bddRelation& p) {
00327     mBdd.unite(p.mBdd);
00328   }
00329 
00330   void
00331   intersect(const bddRelation& p) {
00332     mBdd.intersect(p.mBdd);
00333   }
00334 
00336   void
00337   exists(const string pAttribute) {
00338     unsigned lVarId = mSymTab->getAttributePos(pAttribute);
00339     // Existential quantification of 'mSymTab->getBitNr()' bits,
00340     //   beginning at 'lVarId', i.e., for all bits of the encoding of 'pAttribute'.
00341     for (int i = mSymTab->getBitNr() - 1;  i >= 0;  --i)
00342     {
00343       mBdd.exists(lVarId + i);
00344     }
00345   }
00346 
00349   bool
00350   testVars(string pVarFirst, string pVarLast)
00351   {
00352     unsigned lVarIdFirst = mSymTab->getAttributePos(pVarFirst);
00353     unsigned lVarIdLast  = mSymTab->getAttributePos(pVarLast) + mSymTab->getBitNr()-1;
00354     assert(lVarIdFirst <= lVarIdLast);
00355     return mBdd.testVars(lVarIdFirst, lVarIdLast);
00356   }
00357 
00359   void
00360   rename(const string pAttributeOld, const string pAttributeNew) {
00361     unsigned lVarIdOld = mSymTab->getAttributePos(pAttributeOld);
00362     unsigned lVarIdNew = mSymTab->getAttributePos(pAttributeNew);
00363 
00364     // Renaming of attributes. 
00365 
00366     // For direct renaming:
00367     // Forbidden range of variable ids for renaming [min, max].
00368     // Case 1) pVarIdOld < pVarIdNew
00369     unsigned lVarIdFirst = lVarIdOld + mSymTab->getBitNr();
00370     unsigned lVarIdLast  = lVarIdNew + mSymTab->getBitNr()-1;
00371     // Case 2) pVarIdOld > pVarIdNew
00372     if( lVarIdOld > lVarIdNew )
00373     {
00374       lVarIdFirst = lVarIdNew;
00375       lVarIdLast  = lVarIdOld - 1;
00376     }
00377 
00378     // Check if there is any BDD node of a varId between the variables
00379     //   or of a varId of the new variable.
00380     if( mBdd.testVars(lVarIdFirst, lVarIdLast) )
00381     {
00382       // Safe variant, without preconditions.
00383       renameSafe(lVarIdOld, lVarIdNew, mSymTab->getBitNr());
00384     }
00385     else
00386     {
00387       // Direct variant, 
00388       //   with the precondition that no BDD node exists between the variables.
00389       // Parameters: First varId to rename.
00390       //             Last varId to rename.
00391       //             Offset, i.e. distance to new.
00392       mBdd.renameVars(lVarIdOld,
00393                       lVarIdOld + (mSymTab->getBitNr() - 1),
00394                       lVarIdNew - lVarIdOld
00395                       );
00396     }
00397   }
00398 
00399 
00400 public: // IO.
00401 
00402   void
00403   printBddInfo(ostream& pS) const {
00404     // Includes garbage collection to get real values.
00405     unsigned lFreeNodes = mBdd.getFreeNodeNr();
00406     unsigned lMaxNodes  = mBdd.getMaxNodeNr();
00407 
00408     // Infos about BDD package.
00409     pS << "Number of BDD nodes: " << mBdd.getNodeNr() << endl
00410        << "Percentage of free nodes in BDD package: " 
00411        << lFreeNodes << " / " << lMaxNodes << " = " 
00412        << (unsigned)(((double)lFreeNodes / (double)lMaxNodes) * 100) 
00413        << " %" << endl;
00414   }
00415 
00418   void
00419   printNodesPerVarId(ostream& pS, const set<string>& pFree) const {
00420     map<unsigned, string>   lVarOrd = mSymTab->computeVariableOrder(pFree);
00421     map<unsigned, unsigned> lBddNodesPerVar = mBdd.getNodesPerVarId();
00422     if (lVarOrd.empty() || lBddNodesPerVar.empty()) {  // BDD has only terminal nodes.
00423       pS << 0 << endl;
00424       return;
00425     }
00426 
00427     // Print the number of BDD nodes for all var ids 
00428     //   in the range [lPos, lLastId].
00429     // Invariant: BDD contains nodes only for user attributes,
00430     //   more precise, nodes with var ids >= lPos and <= lLastId.
00431     unsigned lPos = lVarOrd.begin()->first;
00432     unsigned lLastId = (--lVarOrd.end())->first + mSymTab->getBitNr() - 1;
00433     assert( lBddNodesPerVar.begin()->first >= lPos );
00434     assert( (--lBddNodesPerVar.end())->first <= lLastId );
00435 
00436     while (lPos <= lLastId) { 
00437       unsigned lPosFirst = (lPos / mSymTab->getBitNr()) * mSymTab->getBitNr();
00438       // Print name.
00439       if (lVarOrd.find(lPosFirst) != lVarOrd.end()) {
00440         pS << lVarOrd[lPosFirst] << '_' << lPos - lPosFirst 
00441            << '(' << lPos << ')' 
00442            << endl;
00443       }
00444       // Print value.
00445       if ( lBddNodesPerVar.find(lPos) != lBddNodesPerVar.end() ) {
00446         pS << lBddNodesPerVar[lPos] << endl;
00447       } else {
00448         pS << 0 << endl;
00449       }
00450       ++lPos;
00451     }
00452   }
00453 
00456   void 
00457   printRelation(ostream& pS, 
00458                 const string pTuple,
00459                 vector<string> pAttributeList) const 
00460   {
00461     // Empty relation?
00462     if( isEmpty() ) {
00463       return;
00464     }
00465 
00466     // End of Recursion.
00467     if( pAttributeList.empty() ) {
00468       pS << pTuple << endl;
00469       return;
00470     }
00471 
00472     // Proceed next attribute (i.e. column in relation) in given list.
00473     // Use a copy of this relation.
00474     bddRelation lRel(*this);
00475     
00476     // Output of the values of the first attribute in (pTermList),
00477     //   i.e. the given ordering is regarded.
00478     unsigned lVarId = mSymTab->getAttributePos( * pAttributeList.begin() );
00479     pAttributeList.erase(pAttributeList.begin());
00480 
00481     // For all values of the current attribute.
00482     while (!lRel.isEmpty()) {
00483       // Get next value of the attribute.
00484       unsigned lNumValue = lRel.mBdd.getTuple(lVarId, 
00485                                               lVarId + mSymTab->getBitNr()-1);
00486 
00487       // Compute cofactor for current value in (lTmpRel).
00488       bddRelation lTmpRel(lRel);
00489       lTmpRel.intersect( mkEqual(mSymTab, lVarId, lNumValue) );
00490       // Print value.
00491       string lStringValue( mSymTab->getAttributeValue(lNumValue) );
00492       if( mSymTab->isQuoted(lStringValue) )
00493       {
00494         lStringValue = '"' + lStringValue + '"';
00495       }
00496       // Recursive call for the next attribute.
00497       lTmpRel.printRelation(pS, pTuple + lStringValue + '\t', pAttributeList);
00498       
00499       // Delete printed tuples.
00500       lTmpRel.complement();  
00501       lRel.intersect( lTmpRel );
00502     }
00503   }
00504 
00506   void
00507   printGraph(ostream& pS, const set<string>& pFree) const {
00508     // BDD contains nodes only for user attributes.
00509     map<unsigned,string> lVarOrd = mSymTab->computeVariableOrder(pFree);
00510 
00511     bool need1Terminal = true;
00512     bool need0Terminal = true;
00513     if (setEqual(bddRelation(mSymTab, true))) {  // Full set.
00514       need0Terminal = false;
00515     }
00516     if (setEqual(bddRelation(mSymTab, false))) { // Empty set.
00517       need1Terminal = false;
00518     }
00519 
00520     // Maps var ids to nodes.
00521     multimap<unsigned,bddGraphNode> lGraph;
00522     mBdd.getGraph(lGraph);
00523 
00524     string lEdgeStyle = " [arrowsize=\"1.0\",fontname=\"Helvetica\",fontsize=\"8\",";
00525     string lNodeStyle = " [fontname=\"Helvetica\",fontsize=\"16\",height=\"0.3\",width=\"0.5\",color=black,style=unfilled,";
00526 
00527     pS << "digraph BDD {" << endl;
00528     pS << "size=\"7.5,10\";" << endl << endl;
00529 
00530     // Nodes.
00531     if (lGraph.size() > 0) {
00532       pS << "{ rank=same;" << endl;
00533     }
00534     multimap<unsigned,bddGraphNode>::const_iterator lItPrev = lGraph.begin();
00535     for (multimap<unsigned,bddGraphNode>::const_iterator lIt = lGraph.begin();
00536          lIt != lGraph.end();
00537          ++lIt) {
00538 
00539       if (lIt->first != lItPrev->first) {
00540         pS << "}" << endl << endl 
00541            << "{ rank=same;" << endl;
00542       }
00543       lItPrev = lIt;
00544 
00545       pS << lIt->second.id << lNodeStyle;
00546       unsigned lPos = lIt->second.var;
00547       unsigned lPosFirst = (lPos / mSymTab->getBitNr()) * mSymTab->getBitNr();
00548       assert(lVarOrd.find(lPosFirst) != lVarOrd.end());
00549       pS << "label=\"" << lVarOrd[lPosFirst] << '_' << lPos - lPosFirst << "\"];" << endl;
00550     }
00551     if (lGraph.size() > 0) {
00552       pS << "}" << endl << endl;
00553     }
00554 
00555     // Terminal nodes.
00556     pS << endl
00557        << "{ rank=same;" << endl;
00558     if (need1Terminal) {
00559       pS << 1 << lNodeStyle << "shape=box,label=\"1\"];" << endl << endl;
00560     }
00561     if (need0Terminal) {
00562       pS << 0 << lNodeStyle << "shape=box,label=\"0\"];" << endl << endl;
00563     }
00564     pS << "}" << endl << endl << endl;
00565 
00566     // Edges.
00567     for (multimap<unsigned,bddGraphNode>::const_iterator lIt = lGraph.begin();
00568          lIt != lGraph.end();
00569          ++lIt) {
00570       // Low-edge.
00571       pS << lIt->second.id << " -> " << lIt->second.low 
00572          << lEdgeStyle << "label=\"0\"," << "style=dotted]" << endl;
00573       // High-edge.
00574       pS << lIt->second.id << " -> " << lIt->second.high
00575          << lEdgeStyle << "label=\"1\"," << "style=solid]" << endl;
00576       pS << endl;
00577     }
00578 
00579     pS << "}" << endl;
00580   }
00581 
00583   void
00584   printBDT(ostream& pS) const {
00585     mBdd.print(pS);
00586   }
00587 
00590   bddRelation 
00591   getTupleOf(const map<unsigned, string>& pAttributeList) const 
00592   {
00593     assert(!isEmpty());
00594     // Compute cofactor for the (lexicographically) first value at each attribute.
00595     bddRelation lRel(*this);
00596     for(map<unsigned, string>::const_iterator lIt = pAttributeList.begin();
00597         lIt != pAttributeList.end();
00598         ++lIt)
00599     {
00600       unsigned lVarId = mSymTab->getAttributePos( lIt->second );
00601       // Consider one single value of attribute (*lIt),
00602       //   i.e., the given ordering in (pAttributeList) is regarded (just for efficiency).
00603       unsigned lNumValue = lRel.mBdd.getTuple(lVarId, 
00604                                               lVarId + mSymTab->getBitNr()-1);
00605       lRel.intersect( mkEqual(mSymTab, lVarId, lNumValue) );
00606     }
00607     return lRel;
00608   }
00609 
00610 };
00611 
00612 class bddRelationConst : public bddRelation
00613 {
00614 public:
00615   bddRelationConst(bddRelation pRel)
00616     : bddRelation(pRel)
00617   {}
00618 };
00619 
00620 #endif // _bddRelation_h_

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