|
PPL
0.12.1
|
00001 /* Pointset_Powerset class implementation: non-inline template functions. 00002 Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it> 00003 Copyright (C) 2010-2012 BUGSENG srl (http://bugseng.com) 00004 00005 This file is part of the Parma Polyhedra Library (PPL). 00006 00007 The PPL is free software; you can redistribute it and/or modify it 00008 under the terms of the GNU General Public License as published by the 00009 Free Software Foundation; either version 3 of the License, or (at your 00010 option) any later version. 00011 00012 The PPL is distributed in the hope that it will be useful, but WITHOUT 00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 00015 for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program; if not, write to the Free Software Foundation, 00019 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA. 00020 00021 For the most up-to-date information see the Parma Polyhedra Library 00022 site: http://bugseng.com/products/ppl/ . */ 00023 00024 #ifndef PPL_Pointset_Powerset_templates_hh 00025 #define PPL_Pointset_Powerset_templates_hh 1 00026 00027 #include "Constraint.defs.hh" 00028 #include "Constraint_System.defs.hh" 00029 #include "Constraint_System.inlines.hh" 00030 #include "C_Polyhedron.defs.hh" 00031 #include "NNC_Polyhedron.defs.hh" 00032 #include "Variables_Set.defs.hh" 00033 #include <algorithm> 00034 #include <deque> 00035 #include <string> 00036 #include <iostream> 00037 #include <sstream> 00038 #include <stdexcept> 00039 00040 namespace Parma_Polyhedra_Library { 00041 00042 template <typename PSET> 00043 void 00044 Pointset_Powerset<PSET>::add_disjunct(const PSET& ph) { 00045 Pointset_Powerset& x = *this; 00046 if (x.space_dimension() != ph.space_dimension()) { 00047 std::ostringstream s; 00048 s << "PPL::Pointset_Powerset<PSET>::add_disjunct(ph):\n" 00049 << "this->space_dimension() == " << x.space_dimension() << ", " 00050 << "ph.space_dimension() == " << ph.space_dimension() << "."; 00051 throw std::invalid_argument(s.str()); 00052 } 00053 x.sequence.push_back(Determinate<PSET>(ph)); 00054 x.reduced = false; 00055 PPL_ASSERT_HEAVY(x.OK()); 00056 } 00057 00058 template <> 00059 template <typename QH> 00060 Pointset_Powerset<NNC_Polyhedron> 00061 ::Pointset_Powerset(const Pointset_Powerset<QH>& y, 00062 Complexity_Class complexity) 00063 : Base(), space_dim(y.space_dimension()) { 00064 Pointset_Powerset& x = *this; 00065 for (typename Pointset_Powerset<QH>::const_iterator i = y.begin(), 00066 y_end = y.end(); i != y_end; ++i) 00067 x.sequence.push_back(Determinate<NNC_Polyhedron> 00068 (NNC_Polyhedron(i->pointset(), complexity))); 00069 00070 // FIXME: If the domain elements can be represented _exactly_ as NNC 00071 // polyhedra, then having x.reduced = y.reduced is correct. This is 00072 // the case if the domains are both linear and convex which holds 00073 // for all the currently supported instantiations except for 00074 // Grids; for this reason the Grid specialization has a 00075 // separate implementation. For any non-linear or non-convex 00076 // domains (e.g., a domain of Intervals with restrictions or a 00077 // domain of circles) that may be supported in the future, the 00078 // assignment x.reduced = y.reduced will be a bug. 00079 x.reduced = y.reduced; 00080 00081 PPL_ASSERT_HEAVY(x.OK()); 00082 } 00083 00084 template <typename PSET> 00085 template <typename QH> 00086 Pointset_Powerset<PSET> 00087 ::Pointset_Powerset(const Pointset_Powerset<QH>& y, 00088 Complexity_Class complexity) 00089 : Base(), space_dim(y.space_dimension()) { 00090 Pointset_Powerset& x = *this; 00091 for (typename Pointset_Powerset<QH>::const_iterator i = y.begin(), 00092 y_end = y.end(); i != y_end; ++i) 00093 x.sequence.push_back(Determinate<PSET>(PSET(i->pointset(), complexity))); 00094 // Note: this might be non-reduced even when `y' is known to be 00095 // omega-reduced, because the constructor of PSET may have made 00096 // different QH elements to become comparable. 00097 x.reduced = false; 00098 PPL_ASSERT_HEAVY(x.OK()); 00099 } 00100 00101 template <typename PSET> 00102 void 00103 Pointset_Powerset<PSET>::concatenate_assign(const Pointset_Powerset& y) { 00104 Pointset_Powerset& x = *this; 00105 // Ensure omega-reduction here, since what follows has quadratic complexity. 00106 x.omega_reduce(); 00107 y.omega_reduce(); 00108 Pointset_Powerset<PSET> new_x(x.space_dim + y.space_dim, EMPTY); 00109 for (const_iterator xi = x.begin(), x_end = x.end(), 00110 y_begin = y.begin(), y_end = y.end(); xi != x_end; ) { 00111 for (const_iterator yi = y_begin; yi != y_end; ++yi) { 00112 Det_PSET zi = *xi; 00113 zi.concatenate_assign(*yi); 00114 PPL_ASSERT_HEAVY(!zi.is_bottom()); 00115 new_x.sequence.push_back(zi); 00116 } 00117 ++xi; 00118 if ((abandon_expensive_computations != 0) 00119 && (xi != x_end) && (y_begin != y_end)) { 00120 // Hurry up! 00121 PSET x_ph = xi->pointset(); 00122 for (++xi; xi != x_end; ++xi) 00123 x_ph.upper_bound_assign(xi->pointset()); 00124 const_iterator yi = y_begin; 00125 PSET y_ph = yi->pointset(); 00126 for (++yi; yi != y_end; ++yi) 00127 y_ph.upper_bound_assign(yi->pointset()); 00128 x_ph.concatenate_assign(y_ph); 00129 swap(x, new_x); 00130 x.add_disjunct(x_ph); 00131 PPL_ASSERT_HEAVY(x.OK()); 00132 return; 00133 } 00134 } 00135 swap(x, new_x); 00136 PPL_ASSERT_HEAVY(x.OK()); 00137 } 00138 00139 template <typename PSET> 00140 void 00141 Pointset_Powerset<PSET>::add_constraint(const Constraint& c) { 00142 Pointset_Powerset& x = *this; 00143 for (Sequence_iterator si = x.sequence.begin(), 00144 s_end = x.sequence.end(); si != s_end; ++si) 00145 si->pointset().add_constraint(c); 00146 x.reduced = false; 00147 PPL_ASSERT_HEAVY(x.OK()); 00148 } 00149 00150 template <typename PSET> 00151 void 00152 Pointset_Powerset<PSET>::refine_with_constraint(const Constraint& c) { 00153 Pointset_Powerset& x = *this; 00154 for (Sequence_iterator si = x.sequence.begin(), 00155 s_end = x.sequence.end(); si != s_end; ++si) 00156 si->pointset().refine_with_constraint(c); 00157 x.reduced = false; 00158 PPL_ASSERT_HEAVY(x.OK()); 00159 } 00160 00161 template <typename PSET> 00162 void 00163 Pointset_Powerset<PSET>::add_constraints(const Constraint_System& cs) { 00164 Pointset_Powerset& x = *this; 00165 for (Sequence_iterator si = x.sequence.begin(), 00166 s_end = x.sequence.end(); si != s_end; ++si) 00167 si->pointset().add_constraints(cs); 00168 x.reduced = false; 00169 PPL_ASSERT_HEAVY(x.OK()); 00170 } 00171 00172 template <typename PSET> 00173 void 00174 Pointset_Powerset<PSET>::refine_with_constraints(const Constraint_System& cs) { 00175 Pointset_Powerset& x = *this; 00176 for (Sequence_iterator si = x.sequence.begin(), 00177 s_end = x.sequence.end(); si != s_end; ++si) 00178 si->pointset().refine_with_constraints(cs); 00179 x.reduced = false; 00180 PPL_ASSERT_HEAVY(x.OK()); 00181 } 00182 00183 template <typename PSET> 00184 void 00185 Pointset_Powerset<PSET>::add_congruence(const Congruence& cg) { 00186 Pointset_Powerset& x = *this; 00187 for (Sequence_iterator si = x.sequence.begin(), 00188 s_end = x.sequence.end(); si != s_end; ++si) 00189 si->pointset().add_congruence(cg); 00190 x.reduced = false; 00191 PPL_ASSERT_HEAVY(x.OK()); 00192 } 00193 00194 template <typename PSET> 00195 void 00196 Pointset_Powerset<PSET>::refine_with_congruence(const Congruence& cg) { 00197 Pointset_Powerset& x = *this; 00198 for (Sequence_iterator si = x.sequence.begin(), 00199 s_end = x.sequence.end(); si != s_end; ++si) 00200 si->pointset().refine_with_congruence(cg); 00201 x.reduced = false; 00202 PPL_ASSERT_HEAVY(x.OK()); 00203 } 00204 00205 template <typename PSET> 00206 void 00207 Pointset_Powerset<PSET>::add_congruences(const Congruence_System& cgs) { 00208 Pointset_Powerset& x = *this; 00209 for (Sequence_iterator si = x.sequence.begin(), 00210 s_end = x.sequence.end(); si != s_end; ++si) 00211 si->pointset().add_congruences(cgs); 00212 x.reduced = false; 00213 PPL_ASSERT_HEAVY(x.OK()); 00214 } 00215 00216 template <typename PSET> 00217 void 00218 Pointset_Powerset<PSET>::refine_with_congruences(const Congruence_System& cgs) { 00219 Pointset_Powerset& x = *this; 00220 for (Sequence_iterator si = x.sequence.begin(), 00221 s_end = x.sequence.end(); si != s_end; ++si) 00222 si->pointset().refine_with_congruences(cgs); 00223 x.reduced = false; 00224 PPL_ASSERT_HEAVY(x.OK()); 00225 } 00226 00227 template <typename PSET> 00228 void 00229 Pointset_Powerset<PSET>::unconstrain(const Variable var) { 00230 Pointset_Powerset& x = *this; 00231 for (Sequence_iterator si = x.sequence.begin(), 00232 s_end = x.sequence.end(); si != s_end; ++si) { 00233 si->pointset().unconstrain(var); 00234 x.reduced = false; 00235 } 00236 PPL_ASSERT_HEAVY(x.OK()); 00237 } 00238 00239 template <typename PSET> 00240 void 00241 Pointset_Powerset<PSET>::unconstrain(const Variables_Set& vars) { 00242 Pointset_Powerset& x = *this; 00243 for (Sequence_iterator si = x.sequence.begin(), 00244 s_end = x.sequence.end(); si != s_end; ++si) { 00245 si->pointset().unconstrain(vars); 00246 x.reduced = false; 00247 } 00248 PPL_ASSERT_HEAVY(x.OK()); 00249 } 00250 00251 template <typename PSET> 00252 void 00253 Pointset_Powerset<PSET>::add_space_dimensions_and_embed(dimension_type m) { 00254 Pointset_Powerset& x = *this; 00255 for (Sequence_iterator si = x.sequence.begin(), 00256 s_end = x.sequence.end(); si != s_end; ++si) 00257 si->pointset().add_space_dimensions_and_embed(m); 00258 x.space_dim += m; 00259 PPL_ASSERT_HEAVY(x.OK()); 00260 } 00261 00262 template <typename PSET> 00263 void 00264 Pointset_Powerset<PSET>::add_space_dimensions_and_project(dimension_type m) { 00265 Pointset_Powerset& x = *this; 00266 for (Sequence_iterator si = x.sequence.begin(), 00267 s_end = x.sequence.end(); si != s_end; ++si) 00268 si->pointset().add_space_dimensions_and_project(m); 00269 x.space_dim += m; 00270 PPL_ASSERT_HEAVY(x.OK()); 00271 } 00272 00273 template <typename PSET> 00274 void 00275 Pointset_Powerset<PSET>::remove_space_dimensions(const Variables_Set& vars) { 00276 Pointset_Powerset& x = *this; 00277 Variables_Set::size_type num_removed = vars.size(); 00278 if (num_removed > 0) { 00279 for (Sequence_iterator si = x.sequence.begin(), 00280 s_end = x.sequence.end(); si != s_end; ++si) { 00281 si->pointset().remove_space_dimensions(vars); 00282 x.reduced = false; 00283 } 00284 x.space_dim -= num_removed; 00285 PPL_ASSERT_HEAVY(x.OK()); 00286 } 00287 } 00288 00289 template <typename PSET> 00290 void 00291 Pointset_Powerset<PSET> 00292 ::remove_higher_space_dimensions(dimension_type new_dimension) { 00293 Pointset_Powerset& x = *this; 00294 if (new_dimension < x.space_dim) { 00295 for (Sequence_iterator si = x.sequence.begin(), 00296 s_end = x.sequence.end(); si != s_end; ++si) { 00297 si->pointset().remove_higher_space_dimensions(new_dimension); 00298 x.reduced = false; 00299 } 00300 x.space_dim = new_dimension; 00301 PPL_ASSERT_HEAVY(x.OK()); 00302 } 00303 } 00304 00305 template <typename PSET> 00306 template <typename Partial_Function> 00307 void 00308 Pointset_Powerset<PSET>::map_space_dimensions(const Partial_Function& pfunc) { 00309 Pointset_Powerset& x = *this; 00310 if (x.is_bottom()) { 00311 dimension_type n = 0; 00312 for (dimension_type i = x.space_dim; i-- > 0; ) { 00313 dimension_type new_i; 00314 if (pfunc.maps(i, new_i)) 00315 ++n; 00316 } 00317 x.space_dim = n; 00318 } 00319 else { 00320 Sequence_iterator s_begin = x.sequence.begin(); 00321 for (Sequence_iterator si = s_begin, 00322 s_end = x.sequence.end(); si != s_end; ++si) 00323 si->pointset().map_space_dimensions(pfunc); 00324 x.space_dim = s_begin->pointset().space_dimension(); 00325 x.reduced = false; 00326 } 00327 PPL_ASSERT_HEAVY(x.OK()); 00328 } 00329 00330 template <typename PSET> 00331 void 00332 Pointset_Powerset<PSET>::expand_space_dimension(Variable var, 00333 dimension_type m) { 00334 Pointset_Powerset& x = *this; 00335 for (Sequence_iterator si = x.sequence.begin(), 00336 s_end = x.sequence.end(); si != s_end; ++si) 00337 si->pointset().expand_space_dimension(var, m); 00338 x.space_dim += m; 00339 PPL_ASSERT_HEAVY(x.OK()); 00340 } 00341 00342 template <typename PSET> 00343 void 00344 Pointset_Powerset<PSET>::fold_space_dimensions(const Variables_Set& vars, 00345 Variable dest) { 00346 Pointset_Powerset& x = *this; 00347 Variables_Set::size_type num_folded = vars.size(); 00348 if (num_folded > 0) { 00349 for (Sequence_iterator si = x.sequence.begin(), 00350 s_end = x.sequence.end(); si != s_end; ++si) 00351 si->pointset().fold_space_dimensions(vars, dest); 00352 } 00353 x.space_dim -= num_folded; 00354 PPL_ASSERT_HEAVY(x.OK()); 00355 } 00356 00357 template <typename PSET> 00358 void 00359 Pointset_Powerset<PSET>::affine_image(Variable var, 00360 const Linear_Expression& expr, 00361 Coefficient_traits::const_reference 00362 denominator) { 00363 Pointset_Powerset& x = *this; 00364 for (Sequence_iterator si = x.sequence.begin(), 00365 s_end = x.sequence.end(); si != s_end; ++si) { 00366 si->pointset().affine_image(var, expr, denominator); 00367 // Note that the underlying domain can apply conservative approximation: 00368 // that is why it would not be correct to make the loss of reduction 00369 // conditional on `var' and `expr'. 00370 x.reduced = false; 00371 } 00372 PPL_ASSERT_HEAVY(x.OK()); 00373 } 00374 00375 template <typename PSET> 00376 void 00377 Pointset_Powerset<PSET>::affine_preimage(Variable var, 00378 const Linear_Expression& expr, 00379 Coefficient_traits::const_reference 00380 denominator) { 00381 Pointset_Powerset& x = *this; 00382 for (Sequence_iterator si = x.sequence.begin(), 00383 s_end = x.sequence.end(); si != s_end; ++si) { 00384 si->pointset().affine_preimage(var, expr, denominator); 00385 // Note that the underlying domain can apply conservative approximation: 00386 // that is why it would not be correct to make the loss of reduction 00387 // conditional on `var' and `expr'. 00388 x.reduced = false; 00389 } 00390 PPL_ASSERT_HEAVY(x.OK()); 00391 } 00392 00393 00394 template <typename PSET> 00395 void 00396 Pointset_Powerset<PSET> 00397 ::generalized_affine_image(const Linear_Expression& lhs, 00398 const Relation_Symbol relsym, 00399 const Linear_Expression& rhs) { 00400 Pointset_Powerset& x = *this; 00401 for (Sequence_iterator si = x.sequence.begin(), 00402 s_end = x.sequence.end(); si != s_end; ++si) { 00403 si->pointset().generalized_affine_image(lhs, relsym, rhs); 00404 x.reduced = false; 00405 } 00406 PPL_ASSERT_HEAVY(x.OK()); 00407 } 00408 00409 template <typename PSET> 00410 void 00411 Pointset_Powerset<PSET> 00412 ::generalized_affine_preimage(const Linear_Expression& lhs, 00413 const Relation_Symbol relsym, 00414 const Linear_Expression& rhs) { 00415 Pointset_Powerset& x = *this; 00416 for (Sequence_iterator si = x.sequence.begin(), 00417 s_end = x.sequence.end(); si != s_end; ++si) { 00418 si->pointset().generalized_affine_preimage(lhs, relsym, rhs); 00419 x.reduced = false; 00420 } 00421 PPL_ASSERT_HEAVY(x.OK()); 00422 } 00423 00424 template <typename PSET> 00425 void 00426 Pointset_Powerset<PSET> 00427 ::generalized_affine_image(Variable var, 00428 const Relation_Symbol relsym, 00429 const Linear_Expression& expr, 00430 Coefficient_traits::const_reference denominator) { 00431 Pointset_Powerset& x = *this; 00432 for (Sequence_iterator si = x.sequence.begin(), 00433 s_end = x.sequence.end(); si != s_end; ++si) { 00434 si->pointset().generalized_affine_image(var, relsym, expr, denominator); 00435 x.reduced = false; 00436 } 00437 PPL_ASSERT_HEAVY(x.OK()); 00438 } 00439 00440 template <typename PSET> 00441 void 00442 Pointset_Powerset<PSET> 00443 ::generalized_affine_preimage(Variable var, 00444 const Relation_Symbol relsym, 00445 const Linear_Expression& expr, 00446 Coefficient_traits::const_reference 00447 denominator) { 00448 Pointset_Powerset& x = *this; 00449 for (Sequence_iterator si = x.sequence.begin(), 00450 s_end = x.sequence.end(); si != s_end; ++si) { 00451 si->pointset().generalized_affine_preimage(var, relsym, expr, denominator); 00452 x.reduced = false; 00453 } 00454 PPL_ASSERT_HEAVY(x.OK()); 00455 } 00456 00457 00458 template <typename PSET> 00459 void 00460 Pointset_Powerset<PSET> 00461 ::bounded_affine_image(Variable var, 00462 const Linear_Expression& lb_expr, 00463 const Linear_Expression& ub_expr, 00464 Coefficient_traits::const_reference denominator) { 00465 Pointset_Powerset& x = *this; 00466 for (Sequence_iterator si = x.sequence.begin(), 00467 s_end = x.sequence.end(); si != s_end; ++si) { 00468 si->pointset().bounded_affine_image(var, lb_expr, ub_expr, denominator); 00469 x.reduced = false; 00470 } 00471 PPL_ASSERT_HEAVY(x.OK()); 00472 } 00473 00474 template <typename PSET> 00475 void 00476 Pointset_Powerset<PSET> 00477 ::bounded_affine_preimage(Variable var, 00478 const Linear_Expression& lb_expr, 00479 const Linear_Expression& ub_expr, 00480 Coefficient_traits::const_reference denominator) { 00481 Pointset_Powerset& x = *this; 00482 for (Sequence_iterator si = x.sequence.begin(), 00483 s_end = x.sequence.end(); si != s_end; ++si) { 00484 si->pointset().bounded_affine_preimage(var, lb_expr, ub_expr, 00485 denominator); 00486 x.reduced = false; 00487 } 00488 PPL_ASSERT_HEAVY(x.OK()); 00489 } 00490 00491 template <typename PSET> 00492 dimension_type 00493 Pointset_Powerset<PSET>::affine_dimension() const { 00494 // The affine dimension of the powerset is the affine dimension of 00495 // the smallest vector space in which it can be embedded. 00496 const Pointset_Powerset& x = *this; 00497 C_Polyhedron x_ph(space_dim, EMPTY); 00498 00499 for (Sequence_const_iterator si = x.sequence.begin(), 00500 s_end = x.sequence.end(); si != s_end; ++si) { 00501 PSET pi(si->pointset()); 00502 if (!pi.is_empty()) { 00503 C_Polyhedron phi(space_dim); 00504 const Constraint_System& cs = pi.minimized_constraints(); 00505 for (Constraint_System::const_iterator i = cs.begin(), 00506 cs_end = cs.end(); i != cs_end; ++i) { 00507 const Constraint& c = *i; 00508 if (c.is_equality()) 00509 phi.add_constraint(c); 00510 } 00511 x_ph.poly_hull_assign(phi); 00512 } 00513 } 00514 00515 return x_ph.affine_dimension(); 00516 } 00517 00518 template <typename PSET> 00519 bool 00520 Pointset_Powerset<PSET>::is_universe() const { 00521 const Pointset_Powerset& x = *this; 00522 // Exploit omega-reduction, if already computed. 00523 if (x.is_omega_reduced()) 00524 return x.size() == 1 && x.begin()->pointset().is_universe(); 00525 00526 // A powerset is universe iff one of its disjuncts is. 00527 for (const_iterator x_i = x.begin(), x_end = x.end(); x_i != x_end; ++x_i) 00528 if (x_i->pointset().is_universe()) { 00529 // Speculative omega-reduction, if it is worth. 00530 if (x.size() > 1) { 00531 Pointset_Powerset<PSET> universe(x.space_dimension(), UNIVERSE); 00532 Pointset_Powerset& xx = const_cast<Pointset_Powerset&>(x); 00533 swap(xx, universe); 00534 } 00535 return true; 00536 } 00537 return false; 00538 } 00539 00540 template <typename PSET> 00541 bool 00542 Pointset_Powerset<PSET>::is_empty() const { 00543 const Pointset_Powerset& x = *this; 00544 for (Sequence_const_iterator si = x.sequence.begin(), 00545 s_end = x.sequence.end(); si != s_end; ++si) 00546 if (!si->pointset().is_empty()) 00547 return false; 00548 return true; 00549 } 00550 00551 template <typename PSET> 00552 bool 00553 Pointset_Powerset<PSET>::is_discrete() const { 00554 const Pointset_Powerset& x = *this; 00555 for (Sequence_const_iterator si = x.sequence.begin(), 00556 s_end = x.sequence.end(); si != s_end; ++si) 00557 if (!si->pointset().is_discrete()) 00558 return false; 00559 return true; 00560 } 00561 00562 template <typename PSET> 00563 bool 00564 Pointset_Powerset<PSET>::is_topologically_closed() const { 00565 const Pointset_Powerset& x = *this; 00566 // The powerset must be omega-reduced before checking 00567 // topological closure. 00568 x.omega_reduce(); 00569 for (Sequence_const_iterator si = x.sequence.begin(), 00570 s_end = x.sequence.end(); si != s_end; ++si) 00571 if (!si->pointset().is_topologically_closed()) 00572 return false; 00573 return true; 00574 } 00575 00576 template <typename PSET> 00577 bool 00578 Pointset_Powerset<PSET>::is_bounded() const { 00579 const Pointset_Powerset& x = *this; 00580 for (Sequence_const_iterator si = x.sequence.begin(), 00581 s_end = x.sequence.end(); si != s_end; ++si) 00582 if (!si->pointset().is_bounded()) 00583 return false; 00584 return true; 00585 } 00586 00587 template <typename PSET> 00588 bool 00589 Pointset_Powerset<PSET>::constrains(Variable var) const { 00590 const Pointset_Powerset& x = *this; 00591 // `var' should be one of the dimensions of the powerset. 00592 const dimension_type var_space_dim = var.space_dimension(); 00593 if (x.space_dimension() < var_space_dim) { 00594 std::ostringstream s; 00595 s << "PPL::Pointset_Powerset<PSET>::constrains(v):\n" 00596 << "this->space_dimension() == " << x.space_dimension() << ", " 00597 << "v.space_dimension() == " << var_space_dim << "."; 00598 throw std::invalid_argument(s.str()); 00599 } 00600 // omega_reduction needed, since a redundant disjunct may constrain var. 00601 x.omega_reduce(); 00602 // An empty powerset constrains all variables. 00603 if (x.is_empty()) 00604 return true; 00605 for (const_iterator x_i = x.begin(), x_end = x.end(); x_i != x_end; ++x_i) 00606 if (x_i->pointset().constrains(var)) 00607 return true; 00608 return false; 00609 } 00610 00611 template <typename PSET> 00612 bool 00613 Pointset_Powerset<PSET>::is_disjoint_from(const Pointset_Powerset& y) const { 00614 const Pointset_Powerset& x = *this; 00615 for (Sequence_const_iterator si = x.sequence.begin(), 00616 x_s_end = x.sequence.end(); si != x_s_end; ++si) { 00617 const PSET& pi = si->pointset(); 00618 for (Sequence_const_iterator sj = y.sequence.begin(), 00619 y_s_end = y.sequence.end(); sj != y_s_end; ++sj) { 00620 const PSET& pj = sj->pointset(); 00621 if (!pi.is_disjoint_from(pj)) 00622 return false; 00623 } 00624 } 00625 return true; 00626 } 00627 00628 template <typename PSET> 00629 void 00630 Pointset_Powerset<PSET> 00631 ::drop_some_non_integer_points(const Variables_Set& vars, 00632 Complexity_Class complexity) { 00633 Pointset_Powerset& x = *this; 00634 for (Sequence_iterator si = x.sequence.begin(), 00635 s_end = x.sequence.end(); si != s_end; ++si) 00636 si->pointset().drop_some_non_integer_points(vars, complexity); 00637 x.reduced = false; 00638 PPL_ASSERT_HEAVY(x.OK()); 00639 } 00640 00641 template <typename PSET> 00642 void 00643 Pointset_Powerset<PSET> 00644 ::drop_some_non_integer_points(Complexity_Class complexity) { 00645 Pointset_Powerset& x = *this; 00646 for (Sequence_iterator si = x.sequence.begin(), 00647 s_end = x.sequence.end(); si != s_end; ++si) 00648 si->pointset().drop_some_non_integer_points(complexity); 00649 x.reduced = false; 00650 PPL_ASSERT_HEAVY(x.OK()); 00651 } 00652 00653 template <typename PSET> 00654 void 00655 Pointset_Powerset<PSET>::topological_closure_assign() { 00656 Pointset_Powerset& x = *this; 00657 for (Sequence_iterator si = x.sequence.begin(), 00658 s_end = x.sequence.end(); si != s_end; ++si) 00659 si->pointset().topological_closure_assign(); 00660 PPL_ASSERT_HEAVY(x.OK()); 00661 } 00662 00663 template <typename PSET> 00664 bool 00665 Pointset_Powerset<PSET> 00666 ::intersection_preserving_enlarge_element(PSET& dest) const { 00667 // FIXME: this is just an executable specification. 00668 const Pointset_Powerset& context = *this; 00669 PPL_ASSERT(context.space_dimension() == dest.space_dimension()); 00670 bool nonempty_intersection = false; 00671 // TODO: maybe use a *sorted* constraint system? 00672 PSET enlarged(context.space_dimension(), UNIVERSE); 00673 for (Sequence_const_iterator si = context.sequence.begin(), 00674 s_end = context.sequence.end(); si != s_end; ++si) { 00675 PSET context_i(si->pointset()); 00676 context_i.intersection_assign(enlarged); 00677 PSET enlarged_i(dest); 00678 if (enlarged_i.simplify_using_context_assign(context_i)) 00679 nonempty_intersection = true; 00680 // TODO: merge the sorted constraints of `enlarged' and `enlarged_i'? 00681 enlarged.intersection_assign(enlarged_i); 00682 } 00683 swap(dest, enlarged); 00684 return nonempty_intersection; 00685 } 00686 00687 template <typename PSET> 00688 bool 00689 Pointset_Powerset<PSET> 00690 ::simplify_using_context_assign(const Pointset_Powerset& y) { 00691 Pointset_Powerset& x = *this; 00692 00693 // Omega reduction is required. 00694 // TODO: check whether it would be more efficient to Omega-reduce x 00695 // during the simplification process: when examining *si, we check 00696 // if it has been made redundant by any of the elements preceding it 00697 // (which have been already simplified). 00698 x.omega_reduce(); 00699 if (x.is_empty()) 00700 return false; 00701 y.omega_reduce(); 00702 if (y.is_empty()) { 00703 x = y; 00704 return false; 00705 } 00706 00707 if (y.size() == 1) { 00708 // More efficient, special handling of the singleton context case. 00709 const PSET& y_i = y.sequence.begin()->pointset(); 00710 for (Sequence_iterator si = x.sequence.begin(), 00711 s_end = x.sequence.end(); si != s_end; ) { 00712 PSET& x_i = si->pointset(); 00713 if (x_i.simplify_using_context_assign(y_i)) 00714 ++si; 00715 else 00716 // Intersection is empty: drop the disjunct. 00717 si = x.sequence.erase(si); 00718 } 00719 } 00720 else { 00721 // The context is not a singleton. 00722 for (Sequence_iterator si = x.sequence.begin(), 00723 s_end = x.sequence.end(); si != s_end; ) { 00724 if (y.intersection_preserving_enlarge_element(si->pointset())) 00725 ++si; 00726 else 00727 // Intersection with `*si' is empty: drop the disjunct. 00728 si = x.sequence.erase(si); 00729 } 00730 } 00731 x.reduced = false; 00732 PPL_ASSERT_HEAVY(x.OK()); 00733 return !x.sequence.empty(); 00734 } 00735 00736 template <typename PSET> 00737 bool 00738 Pointset_Powerset<PSET>::contains(const Pointset_Powerset& y) const { 00739 const Pointset_Powerset& x = *this; 00740 for (Sequence_const_iterator si = y.sequence.begin(), 00741 y_s_end = y.sequence.end(); si != y_s_end; ++si) { 00742 const PSET& pi = si->pointset(); 00743 bool pi_is_contained = false; 00744 for (Sequence_const_iterator sj = x.sequence.begin(), 00745 x_s_end = x.sequence.end(); 00746 (sj != x_s_end && !pi_is_contained); 00747 ++sj) { 00748 const PSET& pj = sj->pointset(); 00749 if (pj.contains(pi)) 00750 pi_is_contained = true; 00751 } 00752 if (!pi_is_contained) 00753 return false; 00754 } 00755 return true; 00756 } 00757 00758 template <typename PSET> 00759 bool 00760 Pointset_Powerset<PSET>::strictly_contains(const Pointset_Powerset& y) const { 00761 /* omega reduction ensures that a disjunct of y cannot be strictly 00762 contained in one disjunct and also contained but not strictly 00763 contained in another disjunct of *this */ 00764 const Pointset_Powerset& x = *this; 00765 x.omega_reduce(); 00766 for (Sequence_const_iterator si = y.sequence.begin(), 00767 y_s_end = y.sequence.end(); si != y_s_end; ++si) { 00768 const PSET& pi = si->pointset(); 00769 bool pi_is_strictly_contained = false; 00770 for (Sequence_const_iterator sj = x.sequence.begin(), 00771 x_s_end = x.sequence.end(); 00772 (sj != x_s_end && !pi_is_strictly_contained); ++sj) { 00773 const PSET& pj = sj->pointset(); 00774 if (pj.strictly_contains(pi)) 00775 pi_is_strictly_contained = true; 00776 } 00777 if (!pi_is_strictly_contained) 00778 return false; 00779 } 00780 return true; 00781 } 00782 00783 template <typename PSET> 00784 Poly_Con_Relation 00785 Pointset_Powerset<PSET>::relation_with(const Congruence& cg) const { 00786 const Pointset_Powerset& x = *this; 00787 00788 /* *this is included in cg if every disjunct is included in cg */ 00789 bool is_included = true; 00790 /* *this is disjoint with cg if every disjunct is disjoint with cg */ 00791 bool is_disjoint = true; 00792 /* *this strictly_intersects with cg if some disjunct strictly 00793 intersects with cg */ 00794 bool is_strictly_intersecting = false; 00795 /* *this saturates cg if some disjunct saturates cg and 00796 every disjunct is either disjoint from cg or saturates cg */ 00797 bool saturates_once = false; 00798 bool may_saturate = true; 00799 for (Sequence_const_iterator si = x.sequence.begin(), 00800 s_end = x.sequence.end(); si != s_end; ++si) { 00801 Poly_Con_Relation relation_i = si->pointset().relation_with(cg); 00802 if (!relation_i.implies(Poly_Con_Relation::is_included())) 00803 is_included = false; 00804 if (!relation_i.implies(Poly_Con_Relation::is_disjoint())) 00805 is_disjoint = false; 00806 if (relation_i.implies(Poly_Con_Relation::strictly_intersects())) 00807 is_strictly_intersecting = true; 00808 if (relation_i.implies(Poly_Con_Relation::saturates())) 00809 saturates_once = true; 00810 else if (!relation_i.implies(Poly_Con_Relation::is_disjoint())) 00811 may_saturate = false; 00812 } 00813 00814 Poly_Con_Relation result = Poly_Con_Relation::nothing(); 00815 if (is_included) 00816 result = result && Poly_Con_Relation::is_included(); 00817 if (is_disjoint) 00818 result = result && Poly_Con_Relation::is_disjoint(); 00819 if (is_strictly_intersecting) 00820 result = result && Poly_Con_Relation::strictly_intersects(); 00821 if (saturates_once && may_saturate) 00822 result = result && Poly_Con_Relation::saturates(); 00823 00824 return result; 00825 } 00826 00827 template <typename PSET> 00828 Poly_Con_Relation 00829 Pointset_Powerset<PSET>::relation_with(const Constraint& c) const { 00830 const Pointset_Powerset& x = *this; 00831 00832 /* *this is included in c if every disjunct is included in c */ 00833 bool is_included = true; 00834 /* *this is disjoint with c if every disjunct is disjoint with c */ 00835 bool is_disjoint = true; 00836 /* *this strictly_intersects with c if some disjunct strictly 00837 intersects with c */ 00838 bool is_strictly_intersecting = false; 00839 /* *this saturates c if some disjunct saturates c and 00840 every disjunct is either disjoint from c or saturates c */ 00841 bool saturates_once = false; 00842 bool may_saturate = true; 00843 for (Sequence_const_iterator si = x.sequence.begin(), 00844 s_end = x.sequence.end(); si != s_end; ++si) { 00845 Poly_Con_Relation relation_i = si->pointset().relation_with(c); 00846 if (!relation_i.implies(Poly_Con_Relation::is_included())) 00847 is_included = false; 00848 if (!relation_i.implies(Poly_Con_Relation::is_disjoint())) 00849 is_disjoint = false; 00850 if (relation_i.implies(Poly_Con_Relation::strictly_intersects())) 00851 is_strictly_intersecting = true; 00852 if (relation_i.implies(Poly_Con_Relation::saturates())) 00853 saturates_once = true; 00854 else if (!relation_i.implies(Poly_Con_Relation::is_disjoint())) 00855 may_saturate = false; 00856 } 00857 00858 Poly_Con_Relation result = Poly_Con_Relation::nothing(); 00859 if (is_included) 00860 result = result && Poly_Con_Relation::is_included(); 00861 if (is_disjoint) 00862 result = result && Poly_Con_Relation::is_disjoint(); 00863 if (is_strictly_intersecting) 00864 result = result && Poly_Con_Relation::strictly_intersects(); 00865 if (saturates_once && may_saturate) 00866 result = result && Poly_Con_Relation::saturates(); 00867 00868 return result; 00869 } 00870 00871 template <typename PSET> 00872 Poly_Gen_Relation 00873 Pointset_Powerset<PSET>::relation_with(const Generator& g) const { 00874 const Pointset_Powerset& x = *this; 00875 00876 for (Sequence_const_iterator si = x.sequence.begin(), 00877 s_end = x.sequence.end(); si != s_end; ++si) { 00878 Poly_Gen_Relation relation_i = si->pointset().relation_with(g); 00879 if (relation_i.implies(Poly_Gen_Relation::subsumes())) 00880 return Poly_Gen_Relation::subsumes(); 00881 } 00882 00883 return Poly_Gen_Relation::nothing(); 00884 } 00885 00886 template <typename PSET> 00887 bool 00888 Pointset_Powerset<PSET> 00889 ::bounds_from_above(const Linear_Expression& expr) const { 00890 const Pointset_Powerset& x = *this; 00891 x.omega_reduce(); 00892 for (Sequence_const_iterator si = x.sequence.begin(), 00893 s_end = x.sequence.end(); si != s_end; ++si) 00894 if (!si->pointset().bounds_from_above(expr)) 00895 return false; 00896 return true; 00897 } 00898 00899 template <typename PSET> 00900 bool 00901 Pointset_Powerset<PSET> 00902 ::bounds_from_below(const Linear_Expression& expr) const { 00903 const Pointset_Powerset& x = *this; 00904 x.omega_reduce(); 00905 for (Sequence_const_iterator si = x.sequence.begin(), 00906 s_end = x.sequence.end(); si != s_end; ++si) 00907 if (!si->pointset().bounds_from_below(expr)) 00908 return false; 00909 return true; 00910 } 00911 00912 template <typename PSET> 00913 bool 00914 Pointset_Powerset<PSET>::maximize(const Linear_Expression& expr, 00915 Coefficient& sup_n, 00916 Coefficient& sup_d, 00917 bool& maximum) const { 00918 const Pointset_Powerset& x = *this; 00919 x.omega_reduce(); 00920 if (x.is_empty()) 00921 return false; 00922 00923 bool first = true; 00924 00925 PPL_DIRTY_TEMP_COEFFICIENT(best_sup_n); 00926 PPL_DIRTY_TEMP_COEFFICIENT(best_sup_d); 00927 best_sup_n = 0; 00928 best_sup_d = 1; 00929 bool best_max = false; 00930 00931 PPL_DIRTY_TEMP_COEFFICIENT(iter_sup_n); 00932 PPL_DIRTY_TEMP_COEFFICIENT(iter_sup_d); 00933 iter_sup_n = 0; 00934 iter_sup_d = 1; 00935 bool iter_max = false; 00936 00937 PPL_DIRTY_TEMP_COEFFICIENT(tmp); 00938 00939 for (Sequence_const_iterator si = x.sequence.begin(), 00940 s_end = x.sequence.end(); si != s_end; ++si) { 00941 if (!si->pointset().maximize(expr, iter_sup_n, iter_sup_d, iter_max)) 00942 return false; 00943 else 00944 if (first) { 00945 first = false; 00946 best_sup_n = iter_sup_n; 00947 best_sup_d = iter_sup_d; 00948 best_max = iter_max; 00949 } 00950 else { 00951 tmp = (best_sup_n * iter_sup_d) - (iter_sup_n * best_sup_d); 00952 if (tmp < 0) { 00953 best_sup_n = iter_sup_n; 00954 best_sup_d = iter_sup_d; 00955 best_max = iter_max; 00956 } 00957 else if (tmp == 0) 00958 best_max = (best_max || iter_max); 00959 } 00960 } 00961 sup_n = best_sup_n; 00962 sup_d = best_sup_d; 00963 maximum = best_max; 00964 return true; 00965 } 00966 00967 template <typename PSET> 00968 bool 00969 Pointset_Powerset<PSET>::maximize(const Linear_Expression& expr, 00970 Coefficient& sup_n, 00971 Coefficient& sup_d, 00972 bool& maximum, 00973 Generator& g) const { 00974 const Pointset_Powerset& x = *this; 00975 x.omega_reduce(); 00976 if (x.is_empty()) 00977 return false; 00978 00979 bool first = true; 00980 00981 PPL_DIRTY_TEMP_COEFFICIENT(best_sup_n); 00982 PPL_DIRTY_TEMP_COEFFICIENT(best_sup_d); 00983 best_sup_n = 0; 00984 best_sup_d = 1; 00985 bool best_max = false; 00986 Generator best_g = point(); 00987 00988 PPL_DIRTY_TEMP_COEFFICIENT(iter_sup_n); 00989 PPL_DIRTY_TEMP_COEFFICIENT(iter_sup_d); 00990 iter_sup_n = 0; 00991 iter_sup_d = 1; 00992 bool iter_max = false; 00993 Generator iter_g = point(); 00994 00995 PPL_DIRTY_TEMP_COEFFICIENT(tmp); 00996 00997 for (Sequence_const_iterator si = x.sequence.begin(), 00998 s_end = x.sequence.end(); si != s_end; ++si) { 00999 if (!si->pointset().maximize(expr, 01000 iter_sup_n, iter_sup_d, iter_max, iter_g)) 01001 return false; 01002 else 01003 if (first) { 01004 first = false; 01005 best_sup_n = iter_sup_n; 01006 best_sup_d = iter_sup_d; 01007 best_max = iter_max; 01008 best_g = iter_g; 01009 } 01010 else { 01011 tmp = (best_sup_n * iter_sup_d) - (iter_sup_n * best_sup_d); 01012 if (tmp < 0) { 01013 best_sup_n = iter_sup_n; 01014 best_sup_d = iter_sup_d; 01015 best_max = iter_max; 01016 best_g = iter_g; 01017 } 01018 else if (tmp == 0) { 01019 best_max = (best_max || iter_max); 01020 best_g = iter_g; 01021 } 01022 } 01023 } 01024 sup_n = best_sup_n; 01025 sup_d = best_sup_d; 01026 maximum = best_max; 01027 g = best_g; 01028 return true; 01029 } 01030 01031 template <typename PSET> 01032 bool 01033 Pointset_Powerset<PSET>::minimize(const Linear_Expression& expr, 01034 Coefficient& inf_n, 01035 Coefficient& inf_d, 01036 bool& minimum) const { 01037 const Pointset_Powerset& x = *this; 01038 x.omega_reduce(); 01039 if (x.is_empty()) 01040 return false; 01041 01042 bool first = true; 01043 01044 PPL_DIRTY_TEMP_COEFFICIENT(best_inf_n); 01045 PPL_DIRTY_TEMP_COEFFICIENT(best_inf_d); 01046 best_inf_n = 0; 01047 best_inf_d = 1; 01048 bool best_min = false; 01049 01050 PPL_DIRTY_TEMP_COEFFICIENT(iter_inf_n); 01051 PPL_DIRTY_TEMP_COEFFICIENT(iter_inf_d); 01052 iter_inf_n = 0; 01053 iter_inf_d = 1; 01054 bool iter_min = false; 01055 01056 PPL_DIRTY_TEMP_COEFFICIENT(tmp); 01057 01058 for (Sequence_const_iterator si = x.sequence.begin(), 01059 s_end = x.sequence.end(); si != s_end; ++si) { 01060 if (!si->pointset().minimize(expr, iter_inf_n, iter_inf_d, iter_min)) 01061 return false; 01062 else 01063 if (first) { 01064 first = false; 01065 best_inf_n = iter_inf_n; 01066 best_inf_d = iter_inf_d; 01067 best_min = iter_min; 01068 } 01069 else { 01070 tmp = (best_inf_n * iter_inf_d) - (iter_inf_n * best_inf_d); 01071 if (tmp > 0) { 01072 best_inf_n = iter_inf_n; 01073 best_inf_d = iter_inf_d; 01074 best_min = iter_min; 01075 } 01076 else if (tmp == 0) 01077 best_min = (best_min || iter_min); 01078 } 01079 } 01080 inf_n = best_inf_n; 01081 inf_d = best_inf_d; 01082 minimum = best_min; 01083 return true; 01084 } 01085 01086 template <typename PSET> 01087 bool 01088 Pointset_Powerset<PSET>::minimize(const Linear_Expression& expr, 01089 Coefficient& inf_n, 01090 Coefficient& inf_d, 01091 bool& minimum, 01092 Generator& g) const { 01093 const Pointset_Powerset& x = *this; 01094 x.omega_reduce(); 01095 if (x.is_empty()) 01096 return false; 01097 01098 bool first = true; 01099 01100 PPL_DIRTY_TEMP_COEFFICIENT(best_inf_n); 01101 PPL_DIRTY_TEMP_COEFFICIENT(best_inf_d); 01102 best_inf_n = 0; 01103 best_inf_d = 1; 01104 bool best_min = false; 01105 Generator best_g = point(); 01106 01107 PPL_DIRTY_TEMP_COEFFICIENT(iter_inf_n); 01108 PPL_DIRTY_TEMP_COEFFICIENT(iter_inf_d); 01109 iter_inf_n = 0; 01110 iter_inf_d = 1; 01111 bool iter_min = false; 01112 Generator iter_g = point(); 01113 01114 PPL_DIRTY_TEMP_COEFFICIENT(tmp); 01115 01116 for (Sequence_const_iterator si = x.sequence.begin(), 01117 s_end = x.sequence.end(); si != s_end; ++si) { 01118 if (!si->pointset().minimize(expr, 01119 iter_inf_n, iter_inf_d, iter_min, iter_g)) 01120 return false; 01121 else 01122 if (first) { 01123 first = false; 01124 best_inf_n = iter_inf_n; 01125 best_inf_d = iter_inf_d; 01126 best_min = iter_min; 01127 best_g = iter_g; 01128 } 01129 else { 01130 tmp = (best_inf_n * iter_inf_d) - (iter_inf_n * best_inf_d); 01131 if (tmp > 0) { 01132 best_inf_n = iter_inf_n; 01133 best_inf_d = iter_inf_d; 01134 best_min = iter_min; 01135 best_g = iter_g; 01136 } 01137 else if (tmp == 0) { 01138 best_min = (best_min || iter_min); 01139 best_g = iter_g; 01140 } 01141 } 01142 } 01143 inf_n = best_inf_n; 01144 inf_d = best_inf_d; 01145 minimum = best_min; 01146 g = best_g; 01147 return true; 01148 } 01149 01150 template <typename PSET> 01151 bool 01152 Pointset_Powerset<PSET>::contains_integer_point() const { 01153 const Pointset_Powerset& x = *this; 01154 for (Sequence_const_iterator si = x.sequence.begin(), 01155 s_end = x.sequence.end(); si != s_end; ++si) 01156 if (si->pointset().contains_integer_point()) 01157 return true; 01158 return false; 01159 } 01160 01161 template <typename PSET> 01162 void 01163 Pointset_Powerset<PSET>::wrap_assign(const Variables_Set& vars, 01164 Bounded_Integer_Type_Width w, 01165 Bounded_Integer_Type_Representation r, 01166 Bounded_Integer_Type_Overflow o, 01167 const Constraint_System* cs_p, 01168 unsigned complexity_threshold, 01169 bool wrap_individually) { 01170 Pointset_Powerset& x = *this; 01171 for (Sequence_iterator si = x.sequence.begin(), 01172 s_end = x.sequence.end(); si != s_end; ++si) 01173 si->pointset().wrap_assign(vars, w, r, o, cs_p, 01174 complexity_threshold, wrap_individually); 01175 x.reduced = false; 01176 PPL_ASSERT_HEAVY(x.OK()); 01177 } 01178 01179 template <typename PSET> 01180 void 01181 Pointset_Powerset<PSET>::pairwise_reduce() { 01182 Pointset_Powerset& x = *this; 01183 // It is wise to omega-reduce before pairwise-reducing. 01184 x.omega_reduce(); 01185 01186 size_type n = x.size(); 01187 size_type deleted; 01188 do { 01189 Pointset_Powerset new_x(x.space_dim, EMPTY); 01190 std::deque<bool> marked(n, false); 01191 deleted = 0; 01192 Sequence_iterator s_begin = x.sequence.begin(); 01193 Sequence_iterator s_end = x.sequence.end(); 01194 unsigned si_index = 0; 01195 for (Sequence_iterator si = s_begin; si != s_end; ++si, ++si_index) { 01196 if (marked[si_index]) 01197 continue; 01198 PSET& pi = si->pointset(); 01199 Sequence_const_iterator sj = si; 01200 unsigned sj_index = si_index; 01201 for (++sj, ++sj_index; sj != s_end; ++sj, ++sj_index) { 01202 if (marked[sj_index]) 01203 continue; 01204 const PSET& pj = sj->pointset(); 01205 if (pi.upper_bound_assign_if_exact(pj)) { 01206 marked[si_index] = true; 01207 marked[sj_index] = true; 01208 new_x.add_non_bottom_disjunct_preserve_reduction(pi); 01209 ++deleted; 01210 goto next; 01211 } 01212 } 01213 next: 01214 ; 01215 } 01216 iterator new_x_begin = new_x.begin(); 01217 iterator new_x_end = new_x.end(); 01218 unsigned xi_index = 0; 01219 for (const_iterator xi = x.begin(), 01220 x_end = x.end(); xi != x_end; ++xi, ++xi_index) 01221 if (!marked[xi_index]) 01222 new_x_begin 01223 = new_x.add_non_bottom_disjunct_preserve_reduction(*xi, 01224 new_x_begin, 01225 new_x_end); 01226 using std::swap; 01227 swap(x.sequence, new_x.sequence); 01228 n -= deleted; 01229 } while (deleted > 0); 01230 PPL_ASSERT_HEAVY(x.OK()); 01231 } 01232 01233 template <typename PSET> 01234 template <typename Widening> 01235 void 01236 Pointset_Powerset<PSET>:: 01237 BGP99_heuristics_assign(const Pointset_Powerset& y, Widening widen_fun) { 01238 // `x' is the current iteration value. 01239 Pointset_Powerset& x = *this; 01240 01241 #ifndef NDEBUG 01242 { 01243 // We assume that `y' entails `x'. 01244 const Pointset_Powerset<PSET> x_copy = x; 01245 const Pointset_Powerset<PSET> y_copy = y; 01246 PPL_ASSERT_HEAVY(y_copy.definitely_entails(x_copy)); 01247 } 01248 #endif 01249 01250 size_type n = x.size(); 01251 Pointset_Powerset new_x(x.space_dim, EMPTY); 01252 std::deque<bool> marked(n, false); 01253 const_iterator x_begin = x.begin(); 01254 const_iterator x_end = x.end(); 01255 unsigned i_index = 0; 01256 for (const_iterator i = x_begin, 01257 y_begin = y.begin(), y_end = y.end(); i != x_end; ++i, ++i_index) 01258 for (const_iterator j = y_begin; j != y_end; ++j) { 01259 const PSET& pi = i->pointset(); 01260 const PSET& pj = j->pointset(); 01261 if (pi.contains(pj)) { 01262 PSET pi_copy = pi; 01263 widen_fun(pi_copy, pj); 01264 new_x.add_non_bottom_disjunct_preserve_reduction(pi_copy); 01265 marked[i_index] = true; 01266 } 01267 } 01268 iterator new_x_begin = new_x.begin(); 01269 iterator new_x_end = new_x.end(); 01270 i_index = 0; 01271 for (const_iterator i = x_begin; i != x_end; ++i, ++i_index) 01272 if (!marked[i_index]) 01273 new_x_begin 01274 = new_x.add_non_bottom_disjunct_preserve_reduction(*i, 01275 new_x_begin, 01276 new_x_end); 01277 using std::swap; 01278 swap(x.sequence, new_x.sequence); 01279 PPL_ASSERT_HEAVY(x.OK()); 01280 PPL_ASSERT(x.is_omega_reduced()); 01281 } 01282 01283 template <typename PSET> 01284 template <typename Widening> 01285 void 01286 Pointset_Powerset<PSET>:: 01287 BGP99_extrapolation_assign(const Pointset_Powerset& y, 01288 Widening widen_fun, 01289 unsigned max_disjuncts) { 01290 // `x' is the current iteration value. 01291 Pointset_Powerset& x = *this; 01292 01293 #ifndef NDEBUG 01294 { 01295 // We assume that `y' entails `x'. 01296 const Pointset_Powerset<PSET> x_copy = x; 01297 const Pointset_Powerset<PSET> y_copy = y; 01298 PPL_ASSERT_HEAVY(y_copy.definitely_entails(x_copy)); 01299 } 01300 #endif 01301 01302 x.pairwise_reduce(); 01303 if (max_disjuncts != 0) 01304 x.collapse(max_disjuncts); 01305 x.BGP99_heuristics_assign(y, widen_fun); 01306 } 01307 01308 template <typename PSET> 01309 template <typename Cert> 01310 void 01311 Pointset_Powerset<PSET>:: 01312 collect_certificates(std::map<Cert, size_type, 01313 typename Cert::Compare>& cert_ms) const { 01314 const Pointset_Powerset& x = *this; 01315 PPL_ASSERT(x.is_omega_reduced()); 01316 PPL_ASSERT(cert_ms.size() == 0); 01317 for (const_iterator i = x.begin(), end = x.end(); i != end; i++) { 01318 Cert ph_cert(i->pointset()); 01319 ++cert_ms[ph_cert]; 01320 } 01321 } 01322 01323 template <typename PSET> 01324 template <typename Cert> 01325 bool 01326 Pointset_Powerset<PSET>:: 01327 is_cert_multiset_stabilizing(const std::map<Cert, size_type, 01328 typename Cert::Compare>& y_cert_ms) const { 01329 typedef std::map<Cert, size_type, typename Cert::Compare> Cert_Multiset; 01330 Cert_Multiset x_cert_ms; 01331 collect_certificates(x_cert_ms); 01332 typename Cert_Multiset::const_iterator 01333 xi = x_cert_ms.begin(), 01334 x_cert_ms_end = x_cert_ms.end(), 01335 yi = y_cert_ms.begin(), 01336 y_cert_ms_end = y_cert_ms.end(); 01337 while (xi != x_cert_ms_end && yi != y_cert_ms_end) { 01338 const Cert& xi_cert = xi->first; 01339 const Cert& yi_cert = yi->first; 01340 switch (xi_cert.compare(yi_cert)) { 01341 case 0: 01342 // xi_cert == yi_cert: check the number of multiset occurrences. 01343 { 01344 const size_type& xi_count = xi->second; 01345 const size_type& yi_count = yi->second; 01346 if (xi_count == yi_count) { 01347 // Same number of occurrences: compare the next pair. 01348 ++xi; 01349 ++yi; 01350 } 01351 else 01352 // Different number of occurrences: can decide ordering. 01353 return xi_count < yi_count; 01354 break; 01355 } 01356 case 1: 01357 // xi_cert > yi_cert: it is not stabilizing. 01358 return false; 01359 01360 case -1: 01361 // xi_cert < yi_cert: it is stabilizing. 01362 return true; 01363 } 01364 } 01365 // Here xi == x_cert_ms_end or yi == y_cert_ms_end. 01366 // Stabilization is achieved if `y_cert_ms' still has other elements. 01367 return yi != y_cert_ms_end; 01368 } 01369 01370 template <typename PSET> 01371 template <typename Cert, typename Widening> 01372 void 01373 Pointset_Powerset<PSET>::BHZ03_widening_assign(const Pointset_Powerset& y, 01374 Widening widen_fun) { 01375 // `x' is the current iteration value. 01376 Pointset_Powerset& x = *this; 01377 01378 #ifndef NDEBUG 01379 { 01380 // We assume that `y' entails `x'. 01381 const Pointset_Powerset<PSET> x_copy = x; 01382 const Pointset_Powerset<PSET> y_copy = y; 01383 PPL_ASSERT_HEAVY(y_copy.definitely_entails(x_copy)); 01384 } 01385 #endif 01386 01387 // First widening technique: do nothing. 01388 01389 // If `y' is the empty collection, do nothing. 01390 PPL_ASSERT(x.size() > 0); 01391 if (y.size() == 0) 01392 return; 01393 01394 // Compute the poly-hull of `x'. 01395 PSET x_hull(x.space_dim, EMPTY); 01396 for (const_iterator i = x.begin(), x_end = x.end(); i != x_end; ++i) 01397 x_hull.upper_bound_assign(i->pointset()); 01398 01399 // Compute the poly-hull of `y'. 01400 PSET y_hull(y.space_dim, EMPTY); 01401 for (const_iterator i = y.begin(), y_end = y.end(); i != y_end; ++i) 01402 y_hull.upper_bound_assign(i->pointset()); 01403 // Compute the certificate for `y_hull'. 01404 const Cert y_hull_cert(y_hull); 01405 01406 // If the hull is stabilizing, do nothing. 01407 int hull_stabilization = y_hull_cert.compare(x_hull); 01408 if (hull_stabilization == 1) 01409 return; 01410 01411 // Multiset ordering is only useful when `y' is not a singleton. 01412 const bool y_is_not_a_singleton = y.size() > 1; 01413 01414 // The multiset certificate for `y': 01415 // we want to be lazy about its computation. 01416 typedef std::map<Cert, size_type, typename Cert::Compare> Cert_Multiset; 01417 Cert_Multiset y_cert_ms; 01418 bool y_cert_ms_computed = false; 01419 01420 if (hull_stabilization == 0 && y_is_not_a_singleton) { 01421 // Collect the multiset certificate for `y'. 01422 y.collect_certificates(y_cert_ms); 01423 y_cert_ms_computed = true; 01424 // If multiset ordering is stabilizing, do nothing. 01425 if (x.is_cert_multiset_stabilizing(y_cert_ms)) 01426 return; 01427 } 01428 01429 // Second widening technique: try the BGP99 powerset heuristics. 01430 Pointset_Powerset<PSET> bgp99_heuristics = x; 01431 bgp99_heuristics.BGP99_heuristics_assign(y, widen_fun); 01432 01433 // Compute the poly-hull of `bgp99_heuristics'. 01434 PSET bgp99_heuristics_hull(x.space_dim, EMPTY); 01435 for (const_iterator i = bgp99_heuristics.begin(), 01436 b_h_end = bgp99_heuristics.end(); i != b_h_end; ++i) 01437 bgp99_heuristics_hull.upper_bound_assign(i->pointset()); 01438 01439 // Check for stabilization and, if successful, 01440 // commit to the result of the extrapolation. 01441 hull_stabilization = y_hull_cert.compare(bgp99_heuristics_hull); 01442 if (hull_stabilization == 1) { 01443 // The poly-hull is stabilizing. 01444 swap(x, bgp99_heuristics); 01445 return; 01446 } 01447 else if (hull_stabilization == 0 && y_is_not_a_singleton) { 01448 // If not already done, compute multiset certificate for `y'. 01449 if (!y_cert_ms_computed) { 01450 y.collect_certificates(y_cert_ms); 01451 y_cert_ms_computed = true; 01452 } 01453 if (bgp99_heuristics.is_cert_multiset_stabilizing(y_cert_ms)) { 01454 swap(x, bgp99_heuristics); 01455 return; 01456 } 01457 // Third widening technique: pairwise-reduction on `bgp99_heuristics'. 01458 // Note that pairwise-reduction does not affect the computation 01459 // of the poly-hulls, so that we only have to check the multiset 01460 // certificate relation. 01461 Pointset_Powerset<PSET> reduced_bgp99_heuristics(bgp99_heuristics); 01462 reduced_bgp99_heuristics.pairwise_reduce(); 01463 if (reduced_bgp99_heuristics.is_cert_multiset_stabilizing(y_cert_ms)) { 01464 swap(x, reduced_bgp99_heuristics); 01465 return; 01466 } 01467 } 01468 01469 // Fourth widening technique: this is applicable only when 01470 // `y_hull' is a proper subset of `bgp99_heuristics_hull'. 01471 if (bgp99_heuristics_hull.strictly_contains(y_hull)) { 01472 // Compute (y_hull \widen bgp99_heuristics_hull). 01473 PSET ph = bgp99_heuristics_hull; 01474 widen_fun(ph, y_hull); 01475 // Compute the difference between `ph' and `bgp99_heuristics_hull'. 01476 ph.difference_assign(bgp99_heuristics_hull); 01477 x.add_disjunct(ph); 01478 return; 01479 } 01480 01481 // Fall back to the computation of the poly-hull. 01482 Pointset_Powerset<PSET> x_hull_singleton(x.space_dim, EMPTY); 01483 x_hull_singleton.add_disjunct(x_hull); 01484 swap(x, x_hull_singleton); 01485 } 01486 01487 template <typename PSET> 01488 void 01489 Pointset_Powerset<PSET>::ascii_dump(std::ostream& s) const { 01490 const Pointset_Powerset& x = *this; 01491 s << "size " << x.size() 01492 << "\nspace_dim " << x.space_dim 01493 << "\n"; 01494 for (const_iterator xi = x.begin(), x_end = x.end(); xi != x_end; ++xi) 01495 xi->pointset().ascii_dump(s); 01496 } 01497 01498 PPL_OUTPUT_TEMPLATE_DEFINITIONS(PSET, Pointset_Powerset<PSET>) 01499 01500 template <typename PSET> 01501 bool 01502 Pointset_Powerset<PSET>::ascii_load(std::istream& s) { 01503 Pointset_Powerset& x = *this; 01504 std::string str; 01505 01506 if (!(s >> str) || str != "size") 01507 return false; 01508 01509 size_type sz; 01510 01511 if (!(s >> sz)) 01512 return false; 01513 01514 if (!(s >> str) || str != "space_dim") 01515 return false; 01516 01517 if (!(s >> x.space_dim)) 01518 return false; 01519 01520 Pointset_Powerset new_x(x.space_dim, EMPTY); 01521 while (sz-- > 0) { 01522 PSET ph; 01523 if (!ph.ascii_load(s)) 01524 return false; 01525 new_x.add_disjunct(ph); 01526 } 01527 swap(x, new_x); 01528 01529 // Check invariants. 01530 PPL_ASSERT_HEAVY(x.OK()); 01531 return true; 01532 } 01533 01534 template <typename PSET> 01535 bool 01536 Pointset_Powerset<PSET>::OK() const { 01537 const Pointset_Powerset& x = *this; 01538 for (const_iterator xi = x.begin(), x_end = x.end(); xi != x_end; ++xi) { 01539 const PSET& pi = xi->pointset(); 01540 if (pi.space_dimension() != x.space_dim) { 01541 #ifndef NDEBUG 01542 std::cerr << "Space dimension mismatch: is " << pi.space_dimension() 01543 << " in an element of the sequence,\nshould be " 01544 << x.space_dim << "." 01545 << std::endl; 01546 #endif 01547 return false; 01548 } 01549 } 01550 return x.Base::OK(); 01551 } 01552 01553 namespace Implementation { 01554 01555 namespace Pointset_Powersets { 01556 01557 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS 01558 01559 01564 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS) 01565 template <typename PSET> 01566 void 01567 linear_partition_aux(const Constraint& c, 01568 PSET& pset, 01569 Pointset_Powerset<NNC_Polyhedron>& r) { 01570 Linear_Expression le(c); 01571 const Constraint& neg_c = c.is_strict_inequality() ? (le <= 0) : (le < 0); 01572 NNC_Polyhedron nnc_ph_pset(pset); 01573 nnc_ph_pset.add_constraint(neg_c); 01574 if (!nnc_ph_pset.is_empty()) 01575 r.add_disjunct(nnc_ph_pset); 01576 pset.add_constraint(c); 01577 } 01578 01579 } // namespace Pointset_Powersets 01580 01581 } // namespace Implementation 01582 01583 01585 template <typename PSET> 01586 std::pair<PSET, Pointset_Powerset<NNC_Polyhedron> > 01587 linear_partition(const PSET& p, const PSET& q) { 01588 using Implementation::Pointset_Powersets::linear_partition_aux; 01589 01590 Pointset_Powerset<NNC_Polyhedron> r(p.space_dimension(), EMPTY); 01591 PSET pset = q; 01592 const Constraint_System& p_constraints = p.constraints(); 01593 for (Constraint_System::const_iterator i = p_constraints.begin(), 01594 p_constraints_end = p_constraints.end(); 01595 i != p_constraints_end; 01596 ++i) { 01597 const Constraint& c = *i; 01598 if (c.is_equality()) { 01599 Linear_Expression le(c); 01600 linear_partition_aux(le <= 0, pset, r); 01601 linear_partition_aux(le >= 0, pset, r); 01602 } 01603 else 01604 linear_partition_aux(c, pset, r); 01605 } 01606 return std::make_pair(pset, r); 01607 } 01608 01609 } // namespace Parma_Polyhedra_Library 01610 01611 #endif // !defined(PPL_Pointset_Powerset_templates_hh)