RelationOpsPaired.hpp

Go to the documentation of this file.
00001 #ifndef RELATION_OPS_PAIRED_HPP
00002 #define RELATION_OPS_PAIRED_HPP
00003 
00004 #include <algorithm>
00005 #include <iterator>
00006 #include <cassert>
00007 #include <utility>
00008 #include <map>
00009 #include <set>
00010 
00011 #define relations std_set_relations
00012 #include "RelationOps.hpp"
00013 #undef relations
00014 #define relations buddy_relations
00015 #include "RelationOpsBuddy.hpp"
00016 #undef relations
00017 
00018 namespace wali {
00019   namespace relations {
00020     namespace wsr = wali::std_set_relations;
00021     namespace wbr = wali::buddy_relations;
00022 
00023     typedef wsr::RelationTypedefs<unsigned long>::BinaryRelation wsrbr;
00024     typedef wbr::RelationTypedefs<unsigned long>::BinaryRelation wbrbr;
00025 
00026     extern int count;
00027     inline
00028     void counter(char* vals, int size) {
00029       int numDontCares = 0;
00030       for (int i=0; i<size; ++i) {
00031         if (vals[i] < 0) {
00032           ++numDontCares;
00033         }
00034       }
00035 
00036       //for (int i=0; i<size; ++i) {
00037       //    std::cout << (vals[i] < 0 ? 'X' : ('0' + vals[i]));
00038       //}
00039       //std::cout << "\n";
00040             
00041       count += 1 << numDontCares;
00042     }
00043 
00044     inline
00045     int bdd_rel_size(::bdd b, int factor) {
00046       count = 0;
00047       //std::cout << "Call to allsat:\n";
00048       bdd_allsat(b, counter);
00049 
00050       assert(bdd_satcount(b) == count);
00051       return count/factor;
00052     }
00053         
00054     /// Wraps a bdd in a nice friendly package
00055     struct BinaryRelation {
00056       wsrbr set;
00057       wbrbr bdd;
00058 
00059       BinaryRelation(unsigned int largest)
00060         : bdd(largest)
00061       {}
00062 
00063       BinaryRelation()
00064       {}
00065 
00066       bool insert(unsigned int leftVal, unsigned int rightVal)
00067       {
00068         return insert(std::make_pair(leftVal, rightVal));
00069       }
00070             
00071       bool insert(std::pair<unsigned int, unsigned int> pair)
00072       {
00073         assert(check());
00074         bool added1 = set.insert(pair).second;
00075         bool added2 = bdd.insert(pair);
00076         assert(check());
00077         assert(added1 == added2);
00078         return added1;
00079       }
00080             
00081       bool empty() const
00082       {
00083         assert(set.empty() == bdd.empty());
00084         return set.empty();
00085       }
00086             
00087       bool operator== (BinaryRelation const & other) const {
00088         assert( (set == other.set) == (bdd == other.bdd) );
00089         return bdd == other.bdd;
00090       }
00091 
00092       ::bdd getBdd() const {
00093         return bdd.getBdd();
00094       }
00095 
00096       int bddSize() const {
00097         return bdd_rel_size(bdd.getBdd(), 256);
00098       }
00099 
00100       int setSize() const {
00101         return set.size();
00102       }
00103 
00104       bool check() const {
00105         return bddSize() == setSize();
00106       }
00107     };
00108 
00109     struct TernaryRelation {
00110       wsr::RelationTypedefs<unsigned long>::TernaryRelation set;
00111       wbr::RelationTypedefs<unsigned long>::TernaryRelation bdd;
00112 
00113       TernaryRelation(unsigned int largest)
00114         : bdd(largest)
00115       {}
00116 
00117       TernaryRelation()
00118       {}
00119 
00120       bool insert(unsigned int leftVal, unsigned int middleVal, unsigned int rightVal)
00121       {
00122         bool added1 = set.insert(Triple<unsigned long,unsigned long,unsigned long>(leftVal, middleVal, rightVal));
00123         bool added2 = bdd.insert(Triple<unsigned,unsigned,unsigned>(leftVal, middleVal, rightVal));
00124         assert(added1 == added2);
00125         return added1;
00126       }
00127 
00128       bool insert(Triple<unsigned, unsigned, unsigned> triple)
00129       {
00130         return insert(triple.first, triple.second, triple.third);
00131       }
00132 
00133       bool insert(Triple<unsigned long, unsigned long, unsigned long> triple)
00134       {
00135         return insert(triple.first, triple.second, triple.third);
00136       }
00137 
00138       bool check() const {
00139         return bdd_rel_size(bdd.getBdd(), 16) == set.size();
00140       }
00141     };
00142 
00143         
00144     /// This can be used in client code to hide the actual relation types
00145     template<typename State>
00146     struct RelationTypedefs
00147     {
00148       typedef wali::relations::BinaryRelation BinaryRelation;
00149       typedef wali::relations::TernaryRelation TernaryRelation;
00150     };
00151 
00152         
00153     using wbr::buddyInit;
00154         
00155     // inline
00156     // void buddyInit()
00157     // {
00158     //     if (!bdd_isrunning()) {
00159     //         const int million = 1000000;
00160     //         int rc = bdd_init( 50*million, 100000 );
00161     //         if( rc < 0 ) {
00162     //             std::cerr << "[ERROR] " << bdd_errstring(rc) << std::endl;
00163     //             assert( 0 );
00164     //             exit(10);
00165     //         }
00166     //         // Default is 50,000 (1 Mb),memory is cheap, so use 100,000
00167     //         bdd_setmaxincrease(100000);
00168     //     }
00169     // }
00170 
00171 
00172     /// Composes two binary relations
00173     ///
00174     /// { (x,z) | (x,y) \in r1,  (y,z) \in r2}
00175     ///
00176     /// Parameters:
00177     ///   out_result: The relational composition of r1 and r2
00178     ///   r1:         relation 1
00179     ///   r2:         relation 2
00180     inline void
00181     compose(BinaryRelation & out_result,
00182             BinaryRelation const & r1,
00183             BinaryRelation const & r2)
00184     {
00185       wsr::compose<unsigned long>(out_result.set, r1.set, r2.set);
00186       wbr::compose(out_result.bdd, r1.bdd, r2.bdd);
00187       assert(out_result.check());
00188     }
00189 
00190         
00191     /// Projects out the symbol in the internal and call relation
00192     ///
00193     /// {(source, target) | (source, alpha, target) \in delta}
00194     ///
00195     /// Parameters:
00196     ///   out_result: The relation delta restricted to alpha
00197     ///   delta:      Internals or calls relation
00198     ///   alpha:      Alphabet symbol to select and project
00199     template<typename OutRelation, typename State, typename Symbol>
00200     void
00201     project_symbol_3_set(OutRelation & out_result,
00202                          std::set<Triple<State, Symbol, State> > const & delta,
00203                          Symbol alpha)
00204     {
00205       wsr::project_symbol_3<OutRelation, State, Symbol>(out_result, delta, alpha);
00206     }
00207 
00208         
00209     template<typename OutRelation, typename State, typename Symbol>
00210     void
00211     project_symbol_3(OutRelation & out_result,
00212                      std::set<Triple<State, Symbol, State> > const & delta,
00213                      Symbol alpha)
00214     {
00215       wsr::project_symbol_3<wsrbr, State, Symbol>(out_result.set, delta, alpha);
00216       wbr::project_symbol_3<wbrbr, State, Symbol>(out_result.bdd, delta, alpha);
00217       assert(out_result.check());
00218     }
00219 
00220 
00221     /// Performs the sort of merge required for NWA return edges
00222     ///
00223     /// {(q, q') | (q,q1) \in r_call, (q1,q2) \in r_exit, (q2,q1,q') \in delta}
00224     ///
00225     /// Parameters:
00226     ///   out_result: The relational composition of R1 and R2
00227     ///   r_exit:     The relation at the exit node
00228     ///   r_call:     The relation at the call node
00229     ///   delta_r:    The return transition relation with the alphabet
00230     ///               symbol projected out
00231     inline void
00232     merge(BinaryRelation & out_result,
00233           BinaryRelation const & r_exit,
00234           BinaryRelation const & r_call,
00235           TernaryRelation const & delta_r)
00236     {
00237       assert(out_result.check());
00238       assert(r_exit.check());
00239       assert(r_call.check());
00240       assert(delta_r.check());
00241       wsr::merge<unsigned long>(out_result.set, r_exit.set, r_call.set, delta_r.set);
00242       wbr::merge(out_result.bdd, r_exit.bdd, r_call.bdd, delta_r.bdd);
00243       //std::cout << out_result.bdd.getBdd() << "\n";
00244       assert(out_result.check());
00245     }
00246 
00247 
00248     /// Projects out the symbol in the return relation
00249     ///
00250     /// {(source, pred, target) | (source, pred, alpha, target) \in delta}
00251     ///
00252     /// Parameters:
00253     ///   out_result: The ternary relation delta restricted to alpha
00254     ///   delta:      Return relation
00255     ///   alpha:      Alphabet symbol to select and project
00256     template<typename State, typename Symbol>
00257     void
00258     project_symbol_4(TernaryRelation & out_result,
00259                      std::set<Quad<State, State, Symbol, State> > const & delta,
00260                      Symbol alpha)
00261     {
00262       assert(out_result.check());
00263       wsr::project_symbol_4<State, Symbol>(out_result.set, delta, alpha);
00264       wbr::project_symbol_4<State, Symbol>(out_result.bdd, delta, alpha);
00265       assert(out_result.check());
00266     }
00267 
00268 
00269     template<typename State>
00270     State biggest(State s1, State s2, State s3)
00271     {
00272       return std::max(s1, std::max(s2, s3));
00273     }
00274 
00275     /// Constructs the transitive closure of an algorithm.
00276     ///
00277     /// TODO: Right now we break the abstraction and assume State is a
00278     /// (reasonably small) integer.
00279     ///
00280     /// { (p, q) | p R* q} or however you want to denote it
00281     ///
00282     /// Parameters:
00283     ///   out_result: The transitive closure of r
00284     ///   r:          The source relation
00285     template<typename Relation>
00286     void
00287     transitive_closure(Relation & out_result,
00288                        Relation const & r)
00289     {
00290       typedef typename Relation::const_iterator Iterator;
00291       typedef typename Relation::value_type::first_type State;
00292 
00293 #ifndef NDEBUG
00294       const bool domain_and_codomain_are_the_same =
00295         boost::is_same<typename Relation::value_type::first_type,
00296         typename Relation::value_type::second_type>::value;
00297       BOOST_STATIC_ASSERT(domain_and_codomain_are_the_same);
00298 #endif
00299 
00300       // Find the largest state
00301       State largest_state = State();
00302       for(Iterator edge = r.begin(); edge != r.end(); ++edge)
00303       {
00304         largest_state = biggest(largest_state, edge->first, edge->second);
00305       }
00306 
00307       largest_state = largest_state + 1;
00308 
00309       assert(largest_state < 2000); // reasonable based on my examples
00310       // I think
00311       
00312       // Set up the path matrix
00313       std::vector<std::deque<bool> > matrix(largest_state);
00314       for(size_t i = 0; i<matrix.size(); ++i)
00315       {
00316         matrix[i].resize(largest_state);
00317       }
00318 
00319       for(size_t source=0; source<largest_state; ++source)
00320       {
00321         matrix[source][source] = 1;
00322       }
00323        
00324       for(Iterator edge = r.begin(); edge != r.end(); ++edge)
00325       {
00326         matrix[edge->first][edge->second] = 1;
00327       }
00328 
00329       // Now perform Floyd-Warshall alg. From Wikipedia:
00330       //
00331       //  /* Assume a function edgeCost(i,j) which returns the cost of
00332       //     the edge from i to j (infinity if there is none).  Also
00333       //     assume that n is the number of vertices and
00334       //     edgeCost(i,i) = 0
00335       //   */
00336       //
00337       //  int path[][];
00338       //
00339       //  /* A 2-dimensional matrix. At each step in the algorithm,
00340       //     path[i][j] is the shortest path from i to j using
00341       //     intermediate vertices (1..k-1).  Each path[i][j] is
00342       //     initialized to edgeCost(i,j) or infinity if there is no
00343       //     edge between i and j.
00344       //   */
00345       //
00346       //   procedure FloydWarshall ()
00347       //      for k := 1 to n
00348       //         for i := 1 to n
00349       //            for j := 1 to n
00350       //               path[i][j] = min ( path[i][j], path[i][k]+path[k][j] );
00351 
00352       for(size_t k = 0; k < largest_state; ++k)
00353         for(size_t i = 0; i < largest_state; ++i)
00354           for(size_t j = 0; j < largest_state; ++j)
00355             matrix[i][j] = matrix[i][j] || (matrix[i][k] && matrix[k][j]);
00356 
00357 
00358       // Now go through and convert back to the multimap view
00359       for(size_t source=0; source<largest_state; ++source)
00360       {
00361         for(size_t target=0; target<largest_state; ++target)
00362         {
00363           if(matrix[source][target])
00364           {
00365             out_result.insert(std::make_pair(source,target));
00366           }
00367         }
00368       } // done with 
00369     }
00370 
00371 
00372     /// Returns the intersection of two binary relations on states
00373     ///
00374     /// Parameters:
00375     ///   out_result: The intersection of r1 and r2
00376     ///   r1:         One binary relation on states
00377     ///   r2:         Another binary relation on states
00378     inline void
00379     intersect(BinaryRelation & out_result,
00380               BinaryRelation const & r1,
00381               BinaryRelation const & r2)
00382     {
00383       wsr::intersect(out_result.set, r1.set, r2.set);
00384       wbr::intersect(out_result.bdd, r1.bdd, r2.bdd);
00385       assert(out_result.check());
00386     }
00387 
00388 
00389     /// Returns the union of two binary relations on states
00390     ///
00391     /// Parameters:
00392     ///   out_result: The union of r1 and r2
00393     ///   r1:         One binary relation on states
00394     ///   r2:         Another binary relation on states
00395     inline void
00396     union_(BinaryRelation & out_result,
00397            BinaryRelation const & r1,
00398            BinaryRelation const & r2)
00399     {
00400       assert(r1.check());
00401       assert(r2.check());
00402       wsr::union_(out_result.set, r1.set, r2.set);
00403       wbr::union_(out_result.bdd, r1.bdd, r2.bdd);
00404       assert(out_result.check());
00405     }
00406 
00407 
00408 
00409     template<typename T>
00410     class VectorSet {
00411       typedef std::vector<T> Items;
00412       Items items;
00413 
00414     public:
00415       typedef typename Items::iterator iterator;
00416       typedef typename Items::const_iterator const_iterator;
00417            
00418       void insert(T const & item)  {
00419         if (find(item) == end()) {
00420           items.push_back(item);
00421         }
00422       }
00423 
00424       iterator find(T const & item) { return std::find(items.begin(), items.end(), item); }
00425       const_iterator find(T const & item) const { return std::find(items.begin(), items.end(), item); }
00426 
00427       bool empty() const { return items.empty(); }
00428 
00429       iterator begin() { return items.begin(); }
00430       const_iterator begin() const { return items.begin(); }
00431 
00432       iterator end() { return items.end(); }
00433       const_iterator end() const { return items.end(); }
00434 
00435       void erase(iterator i) { items.erase(i); }
00436       void erase(const_iterator i) { items.erase(i); }
00437     };
00438         
00439   } // namespace relations
00440 } // namespace wali
00441 
00442 // Yo, Emacs!
00443 // Local Variables:
00444 //   c-file-style: "ellemtel"
00445 //   c-basic-offset: 2
00446 // End:
00447 
00448 #endif