00001 #ifndef RELATION_OPS_BUDDY_HPP
00002 #define RELATION_OPS_BUDDY_HPP
00003
00004 #include <algorithm>
00005 #include <iterator>
00006 #include <cassert>
00007 #include <utility>
00008 #include <map>
00009 #include <set>
00010
00011 #ifndef NDEBUG
00012 #include <boost/type_traits/is_same.hpp>
00013 #include <boost/static_assert.hpp>
00014 #endif
00015 #include <boost/shared_ptr.hpp>
00016
00017 #include <fdd.h>
00018
00019 #include "wali/ref_ptr.hpp"
00020 #include "wali/KeyContainer.hpp"
00021
00022 namespace wali {
00023 namespace relations {
00024 #if 0
00025 (Not used right now, but could be slightly helpful)
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047 inline int floorLog2(unsigned int n) {
00048 assert(n>0);
00049
00050 int log = -1;
00051 while (n > 0) {
00052 n >>= 1;
00053 ++log;
00054 }
00055 return log;
00056 }
00057 #endif
00058
00059 inline
00060 Quad<int, int, int, int>
00061 getFddNumbers(unsigned int largest)
00062 {
00063
00064 static std::map<unsigned int, int> fddMap;
00065
00066 if (fddMap.find(largest) == fddMap.end()) {
00067
00068 int domains[4] = {
00069 largest + 1,
00070 largest + 1,
00071 largest + 1,
00072 largest + 1
00073 };
00074 int base = fdd_extdomain(domains, 4);
00075 fddMap[largest] = base;
00076 }
00077
00078 int base = fddMap[largest];
00079
00080 return Quad<int, int, int, int>(base, base+1, base+2, base+3);
00081 }
00082
00083
00084
00085
00086
00087
00088
00089
00090 struct Component {
00091 int fdd_number;
00092
00093 bool operator== (Component rhs) const {
00094 return fdd_number == rhs.fdd_number;
00095 }
00096
00097 bool operator!= (Component rhs) const {
00098 return fdd_number != rhs.fdd_number;
00099 }
00100 };
00101
00102
00103
00104
00105
00106
00107 class Domain {
00108 public:
00109 Component left, middle, right, extra;
00110
00111 private:
00112 unsigned int _largest;
00113
00114 typedef void(*pairFreer)(bddPair*);
00115 boost::shared_ptr<bddPair> shift_LM_to_MR;
00116 boost::shared_ptr<bddPair> shift_R_to_M;
00117 boost::shared_ptr<bddPair> shift_LR_to_RE;
00118 boost::shared_ptr<bddPair> shift_E_to_M;
00119
00120 public:
00121 Domain(unsigned int largest)
00122 : shift_LM_to_MR(bdd_newpair(), bdd_freepair)
00123 , shift_R_to_M(bdd_newpair(), bdd_freepair)
00124 , shift_LR_to_RE(bdd_newpair(), bdd_freepair)
00125 , shift_E_to_M(bdd_newpair(), bdd_freepair)
00126 {
00127 _largest = largest;
00128
00129 if (largest > 0) {
00130 Quad<int, int, int, int> fdds = getFddNumbers(largest);
00131 left.fdd_number = fdds.first;
00132 middle.fdd_number = fdds.second;
00133 right.fdd_number = fdds.third;
00134 extra.fdd_number = fdds.fourth;
00135
00136 fdd_setpair(shift_LM_to_MR.get(), left.fdd_number, middle.fdd_number);
00137 fdd_setpair(shift_LM_to_MR.get(), middle.fdd_number, right.fdd_number);
00138
00139 fdd_setpair(shift_R_to_M.get(), right.fdd_number, middle.fdd_number);
00140
00141 fdd_setpair(shift_LR_to_RE.get(), left.fdd_number, right.fdd_number);
00142 fdd_setpair(shift_LR_to_RE.get(), right.fdd_number, extra.fdd_number);
00143
00144 fdd_setpair(shift_E_to_M.get(), extra.fdd_number, middle.fdd_number);
00145 }
00146 }
00147
00148 bool operator!= (Domain const & rhs) const {
00149 return !(*this == rhs);
00150 }
00151
00152 bool operator== (Domain const & rhs) const {
00153 if (_largest == rhs._largest) {
00154 assert (left == rhs.left
00155 && middle == rhs.middle
00156 && right == rhs.right
00157 && extra == rhs.extra);
00158 return true;
00159 }
00160 else {
00161 return false;
00162 }
00163 }
00164
00165 bddPair* shift_out_compose() const {
00166 return shift_LM_to_MR.get();
00167 }
00168
00169 bddPair* shift_in_compose() const {
00170 return shift_R_to_M.get();
00171 }
00172
00173 bddPair* shift_out_merge() const {
00174 return shift_LR_to_RE.get();
00175 }
00176
00177 bddPair* shift_in_merge() const {
00178 return shift_E_to_M.get();
00179 }
00180
00181 unsigned int largest() const {
00182 return _largest;
00183 }
00184
00185 private:
00186 friend class BinaryRelation;
00187 friend class TernaryRelation;
00188 };
00189
00190
00191
00192 class BinaryRelation {
00193 public:
00194 Domain domain;
00195 bdd myBdd;
00196
00197 public:
00198 BinaryRelation(unsigned int largest)
00199 : domain(largest)
00200 , myBdd(bddfalse)
00201 {}
00202
00203 BinaryRelation()
00204 : domain(0)
00205 , myBdd(bddfalse)
00206 {}
00207
00208 bool insert(unsigned int leftVal, unsigned int rightVal)
00209 {
00210 assert(leftVal <= domain.largest());
00211 assert(rightVal <= domain.largest());
00212
00213 bdd left_is_leftVal = fdd_ithvar(domain.left.fdd_number, leftVal);
00214 bdd right_is_rightVal = fdd_ithvar(domain.middle.fdd_number, rightVal);
00215
00216 bdd old = myBdd;
00217 myBdd = myBdd | (left_is_leftVal & right_is_rightVal);
00218 return myBdd != old;
00219 }
00220
00221 bool insert(std::pair<unsigned int, unsigned int> pair)
00222 {
00223 return insert(pair.first, pair.second);
00224 }
00225
00226 bool empty() const
00227 {
00228 return myBdd == bddfalse;
00229 }
00230
00231 bdd getBdd() const
00232 {
00233 return myBdd;
00234 }
00235
00236 bool operator== (BinaryRelation const & other) const {
00237 return (myBdd == other.myBdd && domain == other.domain);
00238 }
00239
00240 friend void compose(BinaryRelation &, BinaryRelation const &, BinaryRelation const &);
00241 friend void intersect(BinaryRelation &, BinaryRelation const &, BinaryRelation const &);
00242 friend void union_(BinaryRelation &, BinaryRelation const &, BinaryRelation const &);
00243 friend void merge(BinaryRelation &, BinaryRelation const &, BinaryRelation const &, BinaryRelation const &);
00244 };
00245
00246
00247
00248 class TernaryRelation {
00249 public:
00250 Domain domain;
00251 bdd myBdd;
00252
00253 public:
00254 TernaryRelation(unsigned int largest)
00255 : domain(largest)
00256 , myBdd(bddfalse)
00257 {}
00258
00259 TernaryRelation()
00260 : domain(0)
00261 , myBdd(bddfalse)
00262 {}
00263
00264
00265 bool insert(unsigned int leftVal, unsigned int middleVal, unsigned int rightVal)
00266 {
00267 assert(leftVal <= domain.largest());
00268 assert(middleVal <= domain.largest());
00269 assert(rightVal <= domain.largest());
00270
00271 bdd left_is_leftVal = fdd_ithvar(domain.left.fdd_number, leftVal);
00272 bdd middle_is_middleVal = fdd_ithvar(domain.middle.fdd_number, middleVal);
00273 bdd right_is_rightVal = fdd_ithvar(domain.right.fdd_number, rightVal);
00274
00275 bdd old = myBdd;
00276 myBdd = myBdd | (left_is_leftVal & middle_is_middleVal & right_is_rightVal);
00277 return old != myBdd;
00278 }
00279
00280 bool insert(Triple<unsigned, unsigned, unsigned> triple)
00281 {
00282 return insert(triple.first, triple.second, triple.third);
00283 }
00284
00285 bool insert(Triple<unsigned long, unsigned long, unsigned long> triple)
00286 {
00287 return insert(triple.first, triple.second, triple.third);
00288 }
00289
00290 bdd getBdd() const
00291 {
00292 return myBdd;
00293 }
00294 };
00295
00296
00297
00298 template<typename State>
00299 struct RelationTypedefs
00300 {
00301 typedef wali::relations::BinaryRelation BinaryRelation;
00302 typedef wali::relations::TernaryRelation TernaryRelation;
00303 };
00304
00305
00306 inline
00307 void buddyInit()
00308 {
00309 if (!bdd_isrunning()) {
00310 const int million = 1000000;
00311 int rc = bdd_init( 50*million, 100000 );
00312 if( rc < 0 ) {
00313 std::cerr << "[ERROR] " << bdd_errstring(rc) << std::endl;
00314 assert( 0 );
00315 exit(10);
00316 }
00317
00318 bdd_setmaxincrease(100000);
00319 }
00320 }
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331 inline void
00332 compose(BinaryRelation & out_result,
00333 BinaryRelation const & r1,
00334 BinaryRelation const & r2)
00335 {
00336 if (r1.domain != r2.domain || out_result.domain != r1.domain) {
00337 std::cerr << "Error: compose (Buddy version): relations don't share a domain\n";
00338 exit(20);
00339 }
00340
00341 bdd r1_bdd = r1.myBdd;
00342 bdd r2_shifted = bdd_replace(r2.myBdd, r2.domain.shift_out_compose());
00343 bdd composed = bdd_relprod(r1_bdd, r2_shifted, fdd_ithset(r1.domain.middle.fdd_number));
00344 out_result.myBdd = bdd_replace(composed, out_result.domain.shift_in_compose());
00345 }
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356 template<typename OutRelation, typename State, typename Symbol>
00357 void
00358 project_symbol_3(OutRelation & out_result,
00359 std::set<Triple<State, Symbol, State> > const & delta,
00360 Symbol alpha)
00361 {
00362 typedef typename std::set<Triple<State, Symbol, State> >::const_iterator Iterator;
00363
00364 for(Iterator cur_trans = delta.begin(); cur_trans != delta.end(); ++cur_trans) {
00365 State source = cur_trans->first;
00366 Symbol symb = cur_trans->second;
00367 State target = cur_trans->third;
00368
00369 if(symb == alpha) {
00370 out_result.insert(std::make_pair(source, target));
00371 }
00372 }
00373 }
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386 inline void
00387 merge(BinaryRelation & out_result,
00388 BinaryRelation const & r_exit,
00389 BinaryRelation const & r_call,
00390 TernaryRelation const & delta_r)
00391 {
00392 if (out_result.domain != r_exit.domain
00393 || r_exit.domain != r_call.domain
00394 || r_call.domain != delta_r.domain)
00395 {
00396 std::cerr << "Error: merge (Buddy version): relations don't share a domain\n";
00397 exit(20);
00398 }
00399
00400 bdd r1_bdd = r_call.myBdd;
00401 bdd r2_bdd = bdd_replace(r_exit.myBdd, r_exit.domain.shift_out_compose());
00402 bdd r3_bdd = bdd_replace(delta_r.myBdd, r_call.domain.shift_out_merge());
00403
00404 bdd middle_two = fdd_ithset(r_exit.domain.middle.fdd_number);
00405
00406
00407 bdd composed = bdd_appex(r1_bdd & r2_bdd,
00408 r3_bdd,
00409 bddop_and,
00410 fdd_ithset(r_call.domain.middle.fdd_number));
00411
00412 composed = bdd_exist(composed, fdd_ithset(r_exit.domain.right.fdd_number));
00413
00414 out_result.myBdd = bdd_replace(composed, out_result.domain.shift_in_merge());
00415 }
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426 template<typename State, typename Symbol>
00427 void
00428 project_symbol_4(TernaryRelation & out_result,
00429 std::set<Quad<State, State, Symbol, State> > const & delta,
00430 Symbol alpha)
00431 {
00432 typedef typename std::set<Quad<State, State, Symbol, State> >::const_iterator Iterator;
00433
00434 for(Iterator cur_trans = delta.begin(); cur_trans != delta.end(); ++cur_trans)
00435 {
00436 State source = cur_trans->first;
00437 State pred = cur_trans->second;
00438 Symbol symb = cur_trans->third;
00439 State target = cur_trans->fourth;
00440
00441 if(symb == alpha)
00442 {
00443 bool added = out_result.insert(Triple<State, State, State>(source, pred, target));
00444 assert(added);
00445 }
00446 }
00447 }
00448
00449
00450 template<typename State>
00451 State biggest(State s1, State s2, State s3)
00452 {
00453 return std::max(s1, std::max(s2, s3));
00454 }
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466 template<typename Relation>
00467 void
00468 transitive_closure(Relation & out_result,
00469 Relation const & r)
00470 {
00471 typedef typename Relation::const_iterator Iterator;
00472 typedef typename Relation::value_type::first_type State;
00473
00474 #ifndef NDEBUG
00475 const bool domain_and_codomain_are_the_same =
00476 boost::is_same<typename Relation::value_type::first_type,
00477 typename Relation::value_type::second_type>::value;
00478 BOOST_STATIC_ASSERT(domain_and_codomain_are_the_same);
00479 #endif
00480
00481
00482 State largest_state = State();
00483 for(Iterator edge = r.begin(); edge != r.end(); ++edge)
00484 {
00485 largest_state = biggest(largest_state, edge->first, edge->second);
00486 }
00487
00488 largest_state = largest_state + 1;
00489
00490 assert(largest_state < 4000);
00491
00492
00493
00494 std::vector<std::deque<bool> > matrix(largest_state);
00495 for(size_t i = 0; i<matrix.size(); ++i)
00496 {
00497 matrix[i].resize(largest_state);
00498 }
00499
00500 for(size_t source=0; source<largest_state; ++source)
00501 {
00502 matrix[source][source] = 1;
00503 }
00504
00505 for(Iterator edge = r.begin(); edge != r.end(); ++edge)
00506 {
00507 matrix[edge->first][edge->second] = 1;
00508 }
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533 for(size_t k = 0; k < largest_state; ++k)
00534 for(size_t i = 0; i < largest_state; ++i)
00535 for(size_t j = 0; j < largest_state; ++j)
00536 matrix[i][j] = matrix[i][j] || (matrix[i][k] && matrix[k][j]);
00537
00538
00539
00540 for(size_t source=0; source<largest_state; ++source)
00541 {
00542 for(size_t target=0; target<largest_state; ++target)
00543 {
00544 if(matrix[source][target])
00545 {
00546 out_result.insert(std::make_pair(source,target));
00547 }
00548 }
00549 }
00550 }
00551
00552
00553
00554
00555
00556
00557
00558
00559 inline void
00560 intersect(BinaryRelation & out_result,
00561 BinaryRelation const & r1,
00562 BinaryRelation const & r2)
00563 {
00564 if (r1.domain != r2.domain || out_result.domain != r1.domain) {
00565 std::cerr << "Error: intersect (Buddy version): relations don't share a domain\n";
00566 exit(20);
00567 }
00568
00569 out_result.myBdd = r1.myBdd & r2.myBdd;
00570 }
00571
00572
00573
00574
00575
00576
00577
00578
00579 inline void
00580 union_(BinaryRelation & out_result,
00581 BinaryRelation const & r1,
00582 BinaryRelation const & r2)
00583 {
00584 if (r1.domain != r2.domain || out_result.domain != r1.domain) {
00585 std::cerr << "Error: intersect (Buddy version): relations don't share a domain\n";
00586 exit(20);
00587 }
00588
00589 out_result.myBdd = r1.myBdd | r2.myBdd;
00590 }
00591
00592
00593
00594 template<typename T>
00595 class VectorSet {
00596 std::deque<T> items;
00597
00598 public:
00599 typedef typename std::deque<T>::iterator iterator;
00600 typedef typename std::deque<T>::const_iterator const_iterator;
00601
00602 void insert(T const & item) {
00603 if (find(item) == end()) {
00604 items.push_back(item);
00605 }
00606 }
00607
00608 iterator find(T const & item) { return std::find(items.begin(), items.end(), item); }
00609 const_iterator find(T const & item) const { return std::find(items.begin(), items.end(), item); }
00610
00611 bool empty() const { return items.empty(); }
00612
00613 iterator begin() { return items.begin(); }
00614 const_iterator begin() const { return items.begin(); }
00615
00616 iterator end() { return items.end(); }
00617 const_iterator end() const { return items.end(); }
00618
00619 void erase(iterator i) { items.erase(i); }
00620 void erase(const_iterator i) { items.erase(i); }
00621 };
00622
00623 }
00624 }
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634 #endif