Generated on Mon Aug 25 11:35:43 2008 for Gecode by doxygen 1.5.6

formula.cc

Go to the documentation of this file.
00001 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
00002 /*
00003  *  Main authors:
00004  *     Guido Tack <tack@gecode.org>
00005  *
00006  *  Copyright:
00007  *     Guido Tack, 2006
00008  *
00009  *  Last modified:
00010  *     $Date: 2008-08-07 16:04:08 +0200 (Thu, 07 Aug 2008) $ by $Author: tack $
00011  *     $Revision: 7536 $
00012  *
00013  *  This file is part of Gecode, the generic constraint
00014  *  development environment:
00015  *     http://www.gecode.org
00016  *
00017  *  Permission is hereby granted, free of charge, to any person obtaining
00018  *  a copy of this software and associated documentation files (the
00019  *  "Software"), to deal in the Software without restriction, including
00020  *  without limitation the rights to use, copy, modify, merge, publish,
00021  *  distribute, sublicense, and/or sell copies of the Software, and to
00022  *  permit persons to whom the Software is furnished to do so, subject to
00023  *  the following conditions:
00024  *
00025  *  The above copyright notice and this permission notice shall be
00026  *  included in all copies or substantial portions of the Software.
00027  *
00028  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00029  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00030  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00031  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00032  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00033  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00034  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00035  *
00036  */
00037 
00038 #include "gecode/set/projectors.hh"
00039 
00040 #include "gecode/support/buddy/bdd.h"
00041 #include <set>
00042 
00043 using namespace Gecode::Set;
00044 
00045 namespace Gecode {
00046 
00050   class Formula::Node {
00051   private:
00053     unsigned int use;
00055     Node *left, *right;
00057     int signLeft, signRight;
00059     int x;
00061     Operator r;
00063     void fv(std::set<int>& s);
00064   public:
00066     Node(const int x);
00068     Node(Node* n0, int s0, Operator r, Node* n1, int s1);
00069     
00071     void increment(void);
00073     bool decrement(void);
00074 
00076     std::set<int> fv(void);
00078     bdd toBdd(void);
00079     
00081     static void* operator new(size_t size);
00083     static void  operator delete(void* p,size_t size);
00084   };
00085 
00086   /*
00087    * Operations for nodes
00088    *
00089    */
00090 
00091   forceinline void*
00092   Formula::Node::operator new(size_t size) {
00093     return Memory::malloc(size);
00094   }
00095 
00096   forceinline void
00097   Formula::Node::operator delete(void* p, size_t) {
00098     Memory::free(p);
00099   }
00100 
00101 
00102   forceinline void
00103   Formula::Node::increment(void) { 
00104     ++use; 
00105   }
00106 
00107   forceinline
00108   Formula::Node::Node(const int x) :
00109     use(1),
00110     left(NULL), right(NULL), signLeft(0), signRight(0), x(x) {}
00111 
00112   forceinline
00113   Formula::Node::Node(Node* l, int sL, Operator o, Node* r, int sR) :
00114     use(1),
00115     left(l), right(r), signLeft(sL), signRight(sR), r(o) {
00116     if (left != NULL)
00117       left->increment();
00118     if (right != NULL)
00119       right->increment();
00120   }
00121 
00122   bool
00123   Formula::Node::decrement(void) {
00124     if (--use == 0) {
00125       if (left != NULL && left->decrement())
00126               delete left;
00127       if (right != NULL && right->decrement())
00128               delete right;
00129       return true;
00130     }
00131     return false;
00132   }
00133 
00134   void
00135   Formula::Node::fv(std::set<int>& s) {
00136     if (left==NULL)
00137       s.insert(x);
00138     else {
00139       left->fv(s);
00140       right->fv(s);
00141     }
00142   }
00143   
00144   inline
00145   std::set<int>
00146   Formula::Node::fv(void) {
00147     std::set<int> s;
00148     fv(s);
00149     return s;
00150   }
00151 
00152   bdd
00153   Formula::Node::toBdd(void) {
00154     if (left==NULL) {
00155       return bdd_ithvar(x);
00156     } else {
00157       bdd bl = left->toBdd(); bdd br = right->toBdd();
00158       if (signLeft == -1)
00159         bl = !bl;
00160       if (signRight == -1)
00161         br = !br;
00162       
00163       switch (r) {
00164       case OR:
00165         return bl | br;
00166       case AND:
00167         return bl & br;
00168       case IMPL:
00169         return bl >> br;
00170       case EQUIV:
00171         return (bl >> br) & (br >> bl);
00172       default:
00173         assert(false);
00174         return bdd_false();
00175       }
00176     }
00177   }
00178 
00179   /*
00180    * Operations for formulas
00181    *
00182    */
00183   
00184   Formula::Formula(int v) : ax(new Node(v)), sign(1) {}
00185 
00186   Formula::Formula(const Formula& f, int sf,
00187                    Operator r,
00188                    const Formula& g, int sg)
00189     : ax(new Node(f.ax,f.sign*sf,r,g.ax,g.sign*sg)), sign(1) {}
00190 
00191   Formula::Formula(const Formula& f, int sign)
00192     : ax(f.ax), sign(f.sign*sign) {
00193     if (ax != NULL)
00194       ax->increment();
00195   }
00196 
00197   Formula::Formula(const Formula& f)
00198     : ax(f.ax), sign(f.sign) {
00199     if (ax != NULL)
00200       ax->increment();
00201   }
00202 
00203   const Formula&
00204   Formula::operator=(const Formula& f) {
00205     if (this != &f) {
00206       if ((ax != NULL) && ax->decrement())
00207         delete ax;
00208       ax = f.ax;
00209       sign = f.sign;
00210       if (ax != NULL)
00211         ax->increment();
00212     }
00213     return *this;
00214   }
00215 
00216   Formula::~Formula(void) {
00217     if ((ax != NULL) && ax->decrement())
00218       delete ax;
00219   }
00220 
00221   namespace {
00222 
00224     SetExpr bddToSetExpr(const bdd& b) {
00225       if (b == bdd_true())
00226         return SetExpr(SetExpr(), -1);
00227       else if (b == bdd_false())
00228         return SetExpr();
00229 
00230       SetExpr right = bddToSetExpr(bdd_high(b));
00231       SetExpr left = bddToSetExpr(bdd_low(b));
00232 
00233       SetExpr selfRight, selfLeft;
00234 
00235       int var = bdd_var(b);
00236 
00237       if (bdd_high(b) == bdd_true()) {
00238         selfRight = SetExpr(var);
00239         selfLeft = left;
00240       } else if (bdd_low(b) == bdd_true()) {
00241         selfLeft = SetExpr(SetExpr(var), -1);
00242         selfRight = right;
00243       } else {
00244         selfRight = SetExpr(var) && right;
00245         selfLeft = SetExpr(SetExpr(var), -1) && left;
00246       }
00247 
00248       if (bdd_high(b) == bdd_false())
00249         return selfLeft;
00250       if (bdd_low(b) == bdd_false())
00251         return selfRight;
00252     
00253       return selfLeft || selfRight;
00254     }
00255 
00256   }
00257 
00258   ProjectorSet
00259   Formula::projectors(void) {
00260 
00261     // Empty formla, empty projector set
00262     if (ax == NULL)
00263       return ProjectorSet(0);
00264 
00265     // Get free variables from formula
00266     std::set<int> s = ax->fv();
00267     int maxVar=0;
00268     for (std::set<int>::const_iterator i=s.begin(); i != s.end(); ++i) {
00269       maxVar = std::max(maxVar, *i);
00270     }
00271 
00272     bool bddWasRunning = true;
00273     // Initialize buddy
00274     if (!bdd_isrunning()) {
00275       bddWasRunning = false;
00276       bdd_init(1000, 1000);
00277     }
00278     if (bdd_varnum() < maxVar+1)
00279       bdd_setvarnum(maxVar+1);
00280 
00281     // First, transform the formula into a bdd
00282     bdd f = ax->toBdd();
00283 
00284     ProjectorSet p(s.size());
00285 
00286     // Now extract the projectors for each variable
00287     for (std::set<int>::const_iterator i=s.begin(); i != s.end(); ++i) {
00288       bdd x = bdd_ithvar(*i);
00289 
00290       // Compute bdd for psi -> x
00291       bdd psi1 = bdd_exist((! bdd_exist( ((!x) & f), x)) & f, x);
00292       //      bdd_reorder(BDD_REORDER_WIN3ITE);
00293       SetExpr glbExpr = bddToSetExpr(psi1);
00294 
00295       // Compute bdd for x -> psi
00296       bdd psi2 = bdd_exist( x & f, x);
00297       //      bdd_reorder(BDD_REORDER_WIN3ITE);
00298       SetExpr lubExpr = bddToSetExpr(psi2);
00299 
00300       Projector proj(*i, glbExpr, lubExpr);
00301       p.add(proj);
00302     }
00303 
00304     if (!bddWasRunning)
00305       bdd_done();
00306 
00307     return p;
00308   }
00309 
00310 }
00311 
00312 // STATISTICS: set-prop