RelationOps.hpp

Go to the documentation of this file.
00001 #ifndef RELATION_OPS_HPP
00002 #define RELATION_OPS_HPP
00003 
00004 #include <algorithm>
00005 #include <iterator>
00006 #include <deque>
00007 #include <vector>
00008 #include <map>
00009 #include <set>
00010 
00011 //#include <tr1/unordered_set>
00012 
00013 #include "wali/ref_ptr.hpp"
00014 #include "wali/KeyContainer.hpp"
00015 
00016 namespace wali {
00017   namespace relations {
00018     using std::set;
00019     using std::map;
00020     using std::pair;
00021     using std::make_pair;
00022 
00023 
00024     /// This class represents a ternary relation over the set 'Subject'
00025     template<typename Subject>
00026     class TernaryRelation
00027     {
00028       map<pair<Subject, Subject>, set<Subject> > relation2_1;
00029 
00030       typedef map<pair<Subject, Subject>, set<Subject> > Map;
00031 
00032     public:
00033       /// The iterator for this class
00034       class Iterator
00035       {
00036       public:
00037         typedef Triple<Subject, Subject, Subject> Tuple;
00038 
00039       private:
00040         typedef typename Map::const_iterator MapIter;
00041         typedef typename set<Subject>::const_iterator SetIter;
00042 
00043         // This holds the position in the outer set
00044         MapIter map_iter;
00045         MapIter end_map_iter;
00046 
00047         // This holds the position in the inner set
00048         SetIter set_iter;
00049         SetIter end_set_iter;
00050 
00051         Tuple cur_tuple;
00052 
00053         void set_tuple() {
00054           assert(!at_end());
00055           assert(set_iter != end_set_iter);
00056           assert(end_set_iter == map_iter->second.end());
00057           
00058           cur_tuple.first = map_iter->first.first;
00059           cur_tuple.second = map_iter->first.second;
00060           cur_tuple.third = *set_iter;
00061         }
00062 
00063       public:
00064         /// Initializes the iterator so it will walk over the outer map
00065         /// [start_outer, end_outer).
00066         Iterator(MapIter start_outer, MapIter end_outer) {
00067           map_iter = start_outer;
00068           end_map_iter = end_outer;
00069 
00070           if (map_iter != end_map_iter) {
00071             set_iter = map_iter->second.begin();
00072             end_set_iter = map_iter->second.end();
00073           }
00074         }
00075 
00076         /// Creates an iterator that walks over the given relation
00077         static Iterator begin(Map & relation) {
00078           return Iterator(relation.begin(), relation.end());
00079         }
00080 
00081         static Iterator end(Map & relation) {
00082           return Iterator(relation.end(), relation.end());
00083         }
00084 
00085         /// Returns whether the iterator is at the end of the relation
00086         bool at_end() const {
00087           return (map_iter == end_map_iter);
00088         }
00089 
00090         /// Advance the iterator.
00091         ///
00092         /// This function is void because I strongly disapprove of
00093         /// using '++' (either form) in the midst of another
00094         /// expression anyway. :-)
00095         void operator++() {
00096           assert(!at_end());
00097           assert(set_iter != end_set_iter);
00098           assert(end_set_iter == map_iter->second.end());
00099 
00100           // Advance the innermost iterator. If that brings us to the
00101           // end of the set, then go to the next set. If *that* brings
00102           // us to the end of the map (i.e. we were already on the
00103           // last set), then we're done, otherwise we need to say
00104           // we're working on the new set.
00105           ++set_iter;
00106           if(set_iter == end_set_iter) {
00107             advance_map();
00108           }
00109         }
00110           
00111         /// Avance the iterator
00112         void operator++(int) {
00113           this->operator++();
00114         }
00115 
00116 
00117         /// Return the tuple under the iterator
00118         Tuple const & operator*() const {
00119           assert(!at_end());
00120           set_tuple();
00121           return cur_tuple;
00122         }
00123 
00124         /// Returns the tuple under the iterator
00125         Tuple const * operator->() const {
00126           assert(!at_end());
00127           const_cast<Iterator*>(this)->set_tuple();
00128           return &cur_tuple;
00129         }
00130 
00131         /// Returns if two iterators are th same
00132         bool operator==(Iterator other) const {
00133           // Two iterators are the same if both are pointing to the
00134           // same element of the outer map AND either:
00135           //   1. both point at the same element of the set
00136           //   2. both are at the end of the map
00137           return (map_iter == other.map_iter
00138                   && (map_iter == end_map_iter
00139                       || set_iter == other.set_iter));
00140         }
00141         
00142         /// Returns if two iterators are different
00143         bool operator!=(Iterator other) const {
00144           return !(*this == other);
00145         }
00146 
00147         /// a
00148         void advance_map() {
00149           assert(!at_end());
00150           ++map_iter;
00151           if(map_iter != end_map_iter) {
00152             set_iter = map_iter->second.begin();
00153             end_set_iter = map_iter->second.end();
00154           }
00155         }
00156       };
00157 
00158     public:
00159       typedef Iterator iterator;
00160       typedef Iterator const_iterator;
00161       
00162       bool insert(Triple<Subject, Subject, Subject> const & tuple) {
00163         return relation2_1[make_pair(tuple.first, tuple.second)].insert(tuple.third).second;
00164       }
00165 
00166       iterator begin() { return Iterator::begin(relation2_1); }
00167       const_iterator begin() const { return Iterator::begin(const_cast<Map&>(relation2_1)); }
00168       iterator end() { return Iterator::end(relation2_1); }
00169       const_iterator end() const { return Iterator::end(const_cast<Map&>(relation2_1)); }
00170 
00171       size_t size() const {
00172         int ret = 0;
00173         for(typename Map::const_iterator iter = relation2_1.begin();
00174             iter != relation2_1.end(); ++iter) {
00175           ret += iter->second.size();
00176         }
00177         return ret;
00178       }
00179 
00180       /// Returns an iterator range that runs over all tuples where
00181       /// the first two coordinates match 'key'.
00182       pair<iterator, iterator> equal_range(pair<Subject, Subject> key) const {
00183         // The range starts at the beginning of the set related to key
00184         // and runs to the beginning of the set following that.
00185         typename Map::const_iterator store_iter = relation2_1.find(key);
00186         typename Map::const_iterator next_map = store_iter;
00187 
00188         // Now, if key wasn't actually *in* the map, then we want the range
00189         // to be empty. This is the case right now, since
00190         // store_iter==next_map.
00191         // 
00192         // Otherwise (if we did find 'key', advance 'next_map' to the next set.
00193         if(store_iter != relation2_1.end()) {
00194           ++next_map;
00195         }
00196 
00197         Iterator start(store_iter, next_map);
00198         Iterator finish(next_map, next_map);
00199 
00200         return make_pair(start, finish);
00201       }
00202 
00203       bool operator==(TernaryRelation const & other) const {
00204         return relation2_1 == other.relation2_1;
00205       }
00206     };
00207 
00208 
00209 #if 0
00210     template<typename a, typename b>
00211     struct pairhash {
00212     private:
00213       const std::tr1::hash<a> ah;
00214       const std::tr1::hash<b> bh;
00215     public:
00216       pairhash() : ah(), bh() {}
00217       size_t operator()(const std::pair<a, b> &p) const {
00218         return ah(p.first) ^ bh(p.second);
00219       }
00220     };
00221 #endif
00222 
00223     /// This can be used in client code to hide the actual relation types
00224     template<typename State>
00225     struct RelationTypedefs
00226     {
00227       // typedef std::tr1::unordered_set<pair<State, State>,
00228       //                                 pairhash<State, State> > BinaryRelation;
00229       typedef std::set<pair<State, State> > BinaryRelation;
00230       typedef wali::relations::TernaryRelation<State> TernaryRelation;
00231     };
00232 
00233 
00234     /// Composes two binary relations
00235     ///
00236     /// { (x,z) | (x,y) \in r1,  (y,z) \in r2}
00237     ///
00238     /// Parameters:
00239     ///   out_result: The relational composition of r1 and r2
00240     ///   r1:         relation 1
00241     ///   r2:         relation 2
00242     template<typename State>
00243     void
00244     compose(typename RelationTypedefs<State>::BinaryRelation & out_result,
00245             typename RelationTypedefs<State>::BinaryRelation const & r1,
00246             typename RelationTypedefs<State>::BinaryRelation const & r2)
00247     {
00248       typedef typename RelationTypedefs<State>::BinaryRelation::const_iterator Iterator;
00249 
00250       std::multimap<State, State> r2_map(r2.begin(), r2.end());
00251       typedef typename std::multimap<State, State>::const_iterator BigIterator;
00252 
00253       // Test possibilites for (origin, call_pred) \in r1
00254       for(Iterator r1_iter = r1.begin(); r1_iter != r1.end(); ++r1_iter)
00255       {
00256         State x = r1_iter->first;
00257         State y = r1_iter->second;
00258 
00259         // Test possibilites for (y, z) in r2
00260         pair<BigIterator, BigIterator> range = r2_map.equal_range(y);
00261         for(BigIterator r2_iter = range.first; r2_iter != range.second; ++r2_iter)
00262         {
00263           //if(r2_iter->first == y) {
00264           out_result.insert(make_pair(x, r2_iter->second));
00265           //}
00266         }
00267       }
00268     }
00269 
00270     /// Projects out the symbol in the internal and call relation
00271     ///
00272     /// {(source, target) | (source, alpha, target) \in delta}
00273     ///
00274     /// Parameters:
00275     ///   out_result: The relation delta restricted to alpha
00276     ///   delta:      Internals or calls relation
00277     ///   alpha:      Alphabet symbol to select and project
00278     template<typename OutRelation, typename State, typename Symbol>
00279     void
00280     project_symbol_3(OutRelation & out_result,
00281                      std::set<Triple<State, Symbol, State> > const & delta,
00282                      Symbol alpha)
00283     {
00284       typedef typename std::set<Triple<State, Symbol, State> >::const_iterator Iterator;
00285 
00286       for(Iterator cur_trans = delta.begin(); cur_trans != delta.end(); ++cur_trans)
00287       {
00288         State source = cur_trans->first;
00289         Symbol symb = cur_trans->second;
00290         State target = cur_trans->third;
00291 
00292         if(symb == alpha)
00293         {
00294           out_result.insert(make_pair(source, target));
00295         }
00296       }
00297     }
00298 
00299 
00300     /// Performs the sort of merge required for NWA return edges
00301     ///
00302     /// {(q, q') | (q,q1) \in r_call, (q1,q2) \in r_exit, (q2,q1,q') \in delta}
00303     ///
00304     /// Parameters:
00305     ///   out_result: The relational composition of R1 and R2
00306     ///   r_exit:     The relation at the exit node
00307     ///   r_call:     The relation at the call node
00308     ///   delta_r:    The return transition relation with the alphabet
00309     ///               symbol projected out
00310     template<typename State>
00311     void
00312     merge(typename RelationTypedefs<State>::BinaryRelation & out_result,
00313           typename RelationTypedefs<State>::BinaryRelation const & r_exit,
00314           typename RelationTypedefs<State>::BinaryRelation const & r_call,
00315           typename RelationTypedefs<State>::TernaryRelation const & delta_r)
00316     {
00317       typedef typename RelationTypedefs<State>::BinaryRelation::const_iterator Iterator;
00318 
00319       typename RelationTypedefs<State>::BinaryRelation temp;
00320 
00321       // Test possibilites for (call_pred, exit) in r_exit
00322       for(Iterator exit_iter = r_exit.begin(); exit_iter != r_exit.end(); ++exit_iter)
00323       {
00324         // Test possibilities for (exit, call_pred, return_) in delta
00325         typedef typename RelationTypedefs<State>::TernaryRelation::const_iterator BigIterator;
00326         pair<BigIterator, BigIterator> range =
00327           delta_r.equal_range(make_pair(exit_iter->second, exit_iter->first));
00328         
00329         for(BigIterator ret_trans = range.first; ret_trans != range.second; ++ret_trans) {
00330           if(exit_iter->first == ret_trans->second && exit_iter->second == ret_trans->first) {
00331             temp.insert(make_pair(exit_iter->first, ret_trans->third));
00332           }
00333         }
00334       }
00335 
00336       compose<State>(out_result, r_call, temp);
00337     }
00338 
00339 
00340     /// Projects out the symbol in the return relation
00341     ///
00342     /// {(source, pred, target) | (source, pred, alpha, target) \in delta}
00343     ///
00344     /// Parameters:
00345     ///   out_result: The ternary relation delta restricted to alpha
00346     ///   delta:      Return relation
00347     ///   alpha:      Alphabet symbol to select and project
00348     template<typename State, typename Symbol>
00349     void
00350     project_symbol_4(typename RelationTypedefs<State>::TernaryRelation & out_result,
00351                      std::set<Quad<State, State, Symbol, State> > const & delta,
00352                      Symbol alpha)
00353     {
00354       typedef typename set<Quad<State, State, Symbol, State> >::const_iterator Iterator;
00355 
00356       for(Iterator cur_trans = delta.begin(); cur_trans != delta.end(); ++cur_trans)
00357       {
00358         State source = cur_trans->first;
00359         State pred = cur_trans->second;
00360         Symbol symb = cur_trans->third;
00361         State target = cur_trans->fourth;
00362 
00363         if(symb == alpha)
00364         {
00365           bool added = out_result.insert(Triple<State, State, State>(source, pred, target));
00366           assert(added);
00367         }
00368       }
00369     }
00370 
00371 
00372     template<typename State>
00373     State biggest(State s1, State s2, State s3)
00374     {
00375       return std::max(s1, std::max(s2, s3));
00376     }
00377 
00378     template<typename State>
00379     void
00380     transitive_closure_no_remap(typename RelationTypedefs<State>::BinaryRelation & out_result,
00381                                 typename RelationTypedefs<State>::BinaryRelation const & r)
00382     {
00383       typedef typename RelationTypedefs<State>::BinaryRelation::const_iterator Iterator;
00384 
00385       // Find the largest state
00386       State largest_state = State();
00387       for(Iterator edge = r.begin(); edge != r.end(); ++edge)
00388       {
00389         largest_state = biggest(largest_state, edge->first, edge->second);
00390       }
00391 
00392       largest_state = largest_state + 1;
00393 
00394       //std::cerr << "transitive_closure : " << largest_state << "\n";
00395       assert(largest_state < 4000); // reasonable based on my examples
00396                                     // I think
00397       
00398       // Set up the path matrix
00399       std::vector<std::deque<bool> > matrix(largest_state);
00400       for(size_t i = 0; i<matrix.size(); ++i)
00401       {
00402         matrix[i].resize(largest_state);
00403       }
00404 
00405       // The first key we use is 1, not 0
00406       for(size_t source=1; source<largest_state; ++source)
00407       {
00408         matrix[source][source] = 1;
00409       }
00410        
00411       for(Iterator edge = r.begin(); edge != r.end(); ++edge)
00412       {
00413         matrix[edge->first][edge->second] = 1;
00414       }
00415 
00416       // Now perform Floyd-Warshall alg. From Wikipedia:
00417       //
00418       //  /* Assume a function edgeCost(i,j) which returns the cost of
00419       //     the edge from i to j (infinity if there is none).  Also
00420       //     assume that n is the number of vertices and
00421       //     edgeCost(i,i) = 0
00422       //   */
00423       //
00424       //  int path[][];
00425       //
00426       //  /* A 2-dimensional matrix. At each step in the algorithm,
00427       //     path[i][j] is the shortest path from i to j using
00428       //     intermediate vertices (1..k-1).  Each path[i][j] is
00429       //     initialized to edgeCost(i,j) or infinity if there is no
00430       //     edge between i and j.
00431       //   */
00432       //
00433       //   procedure FloydWarshall ()
00434       //      for k := 1 to n
00435       //         for i := 1 to n
00436       //            for j := 1 to n
00437       //               path[i][j] = min ( path[i][j], path[i][k]+path[k][j] );
00438 
00439       for(size_t k = 0; k < largest_state; ++k)
00440         for(size_t i = 0; i < largest_state; ++i)
00441           for(size_t j = 0; j < largest_state; ++j)
00442             matrix[i][j] = matrix[i][j] || (matrix[i][k] && matrix[k][j]);
00443 
00444 
00445       // Now go through and convert back to the multimap view
00446       for(size_t source=0; source<largest_state; ++source)
00447       {
00448         for(size_t target=0; target<largest_state; ++target)
00449         {
00450           if(matrix[source][target])
00451           {
00452             out_result.insert(make_pair(source,target));
00453           }
00454         }
00455       } // done with 
00456     }
00457     
00458     
00459     /// Constructs the transitive closure of an algorithm.
00460     ///
00461     /// TODO: Right now we break the abstraction and assume State is a
00462     /// (reasonably small) integer.
00463     ///
00464     /// { (p, q) | p R* q} or however you want to denote it
00465     ///
00466     /// Parameters:
00467     ///   out_result: The transitive closure of r
00468     ///   r:          The source relation
00469     template<typename State>
00470     void
00471     transitive_closure(typename RelationTypedefs<State>::BinaryRelation & out_result,
00472                        typename RelationTypedefs<State>::BinaryRelation const & r)
00473     {
00474       // When doing transitive closure of a relation R (from SxS), you make a
00475       // 2-D array of size N-by-N, where N is the number of elements in S,
00476       // then do a triply-nested loop over it.
00477       //
00478       // Because the access in the loop are done so many times, they should
00479       // be fast, so I made them into vectors (well, a vector of deques to
00480       // avoid the vector<bool> problem). But to do things right, you have to
00481       // map Wali Keys to indices in this matrix.
00482       //
00483       // I didn't want to do this before, so I just left the matrix
00484       // (potentially) very sparse. If your NWA's keys were exclusively in
00485       // the range 3000 to 4000, then you'd get a 4000-by-4000 matrix. Of
00486       // course, you only really need a 1000-by-1000 matrix, so multiplying
00487       // the size by 4 meant that it would take 4^3=64 times longer than it
00488       // "should."
00489       //
00490       // This hasn't been a problem for me in the past, but in the unit tests
00491       // we do determinization on NWAs that are created quite far into the
00492       // procedure -- and with all the calls to determinize that were being
00493       // done, doing repeated useless work in transitive_closure() was taking
00494       // the running time from well under a second to half a minute.
00495       //
00496       // So I fixed it for good. I convert the input relation to
00497       // transitive_closure into one that is dense: mapping the Wali keys
00498       // down to a dense range 1...N (these I call "canonical keys"), do the
00499       // transitive closure on that, then map the keys in the resulting
00500       // relation back.
00501 
00502       if (r.empty()) return;
00503       
00504       typedef typename RelationTypedefs<State>::BinaryRelation BinaryRelation;
00505       typedef typename RelationTypedefs<State>::BinaryRelation::const_iterator Iterator;
00506 
00507       // Forward map is input State -> canonical State
00508       std::map<State, State> forward;
00509       std::map<State, State> backward;
00510 
00511       BinaryRelation r_canonical;
00512       State next_canonical = 1;
00513 
00514       //std::cout << "\nNew transitive closure call:\n";
00515 
00516       //////////////////////////////////////////
00517       // Conversion input->canonical
00518       for(Iterator edge_original = r.begin(); edge_original != r.end(); ++edge_original)
00519       {
00520         State src_original = edge_original->first;
00521         State tgt_original = edge_original->second;
00522 
00523         if (forward.find(src_original) == forward.end()) {
00524           //std::cout << "  Mapping input key " << src_original << " to canonical key " << next_canonical << "\n";
00525           // Have not seen src_original yet
00526           forward[src_original] = next_canonical;
00527           backward[next_canonical] = src_original;
00528           ++next_canonical;
00529         }
00530 
00531         if (forward.find(tgt_original) == forward.end()) {
00532           //std::cout << "  Mapping input key " << src_original << " to canonical key " << next_canonical << "\n";
00533           // Have not seen src_original yet
00534           forward[tgt_original] = next_canonical;
00535           backward[next_canonical] = tgt_original;
00536           ++next_canonical;
00537         }
00538 
00539         State src_canonical = forward[src_original];
00540         State tgt_canonical = forward[tgt_original];
00541         
00542         r_canonical.insert(std::make_pair(src_canonical, tgt_canonical));
00543       }
00544 
00545       /////////////////////////////
00546       // Actual transitive closure
00547       BinaryRelation canonical_closure;
00548       transitive_closure_no_remap<State>(canonical_closure, r_canonical);
00549 
00550       /////////////////////////////
00551       // Conversion canonical->input
00552       for(Iterator edge_canonical = canonical_closure.begin();
00553           edge_canonical != canonical_closure.end(); ++edge_canonical)
00554       {
00555         State src_canonical = edge_canonical->first;
00556         State tgt_canonical = edge_canonical->second;
00557 
00558         if (backward.find(src_canonical) == backward.end()) {
00559           std:: cout << "  ERROR: cannot find original key for canonical key " << src_canonical << std::endl;
00560           std:: cout << "         related to canonical key " << tgt_canonical << std::endl;
00561         }
00562 
00563         assert(backward.find(src_canonical) != backward.end());
00564         assert(backward.find(tgt_canonical) != backward.end());
00565 
00566         State src_original = backward[src_canonical];
00567         State tgt_original = backward[tgt_canonical];
00568 
00569         out_result.insert(std::make_pair(src_original, tgt_original));
00570       }      
00571     }
00572 
00573 
00574 
00575     /// Returns the intersection of two binary relations on states
00576     ///
00577     /// Parameters:
00578     ///   out_result: The intersection of r1 and r2
00579     ///   r1:         One binary relation on states
00580     ///   r2:         Another binary relation on states
00581     template<typename Relation>
00582     void
00583     intersect(Relation & out_result,
00584           Relation const & r1,
00585           Relation const & r2)
00586     {
00587       std::set_intersection(r1.begin(), r1.end(),
00588                             r2.begin(), r2.end(),
00589                             std::inserter(out_result, out_result.begin()));
00590     }
00591 
00592 
00593     /// Returns the union of two binary relations on states
00594     ///
00595     /// Parameters:
00596     ///   out_result: The union of r1 and r2
00597     ///   r1:         One binary relation on states
00598     ///   r2:         Another binary relation on states
00599     template<typename Relation>
00600     void
00601     union_(Relation & out_result,
00602            Relation const & r1,
00603            Relation const & r2)
00604     {
00605       std::set_union(r1.begin(), r1.end(),
00606                      r2.begin(), r2.end(),
00607                      std::inserter(out_result, out_result.begin()));
00608     }
00609   } // namespace relations
00610 } // namespace wali
00611 
00612 
00613 // Yo, Emacs!
00614 // Local Variables:
00615 //   c-file-style: "ellemtel"
00616 //   c-basic-offset: 2
00617 // End:
00618 
00619 #endif