|
PPL
0.12.1
|
00001 /* Polyhedron class implementation 00002 (non-inline widening-related member functions). 00003 Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it> 00004 Copyright (C) 2010-2012 BUGSENG srl (http://bugseng.com) 00005 00006 This file is part of the Parma Polyhedra Library (PPL). 00007 00008 The PPL is free software; you can redistribute it and/or modify it 00009 under the terms of the GNU General Public License as published by the 00010 Free Software Foundation; either version 3 of the License, or (at your 00011 option) any later version. 00012 00013 The PPL is distributed in the hope that it will be useful, but WITHOUT 00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00015 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 00016 for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with this program; if not, write to the Free Software Foundation, 00020 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA. 00021 00022 For the most up-to-date information see the Parma Polyhedra Library 00023 site: http://bugseng.com/products/ppl/ . */ 00024 00025 #include "ppl-config.h" 00026 #include "Polyhedron.defs.hh" 00027 #include "BHRZ03_Certificate.defs.hh" 00028 #include "Rational_Box.hh" 00029 #include "Scalar_Products.defs.hh" 00030 #include "assert.hh" 00031 #include <iostream> 00032 #include <stdexcept> 00033 #include <deque> 00034 00035 namespace PPL = Parma_Polyhedra_Library; 00036 00037 void 00038 PPL::Polyhedron 00039 ::select_CH78_constraints(const Polyhedron& y, 00040 Constraint_System& cs_selection) const { 00041 // Private method: the caller must ensure the following conditions. 00042 PPL_ASSERT(topology() == y.topology() 00043 && topology() == cs_selection.topology() 00044 && space_dim == y.space_dim); 00045 PPL_ASSERT(!marked_empty() 00046 && !has_pending_constraints() 00047 && generators_are_up_to_date()); 00048 PPL_ASSERT(!y.marked_empty() 00049 && !y.has_something_pending() 00050 && y.constraints_are_minimized()); 00051 00052 // A constraint in `y.con_sys' is copied to `cs_selection' 00053 // if it is satisfied by all the generators of `gen_sys'. 00054 00055 // Note: the loop index `i' goes upward to avoid reversing 00056 // the ordering of the chosen constraints. 00057 for (dimension_type i = 0, end = y.con_sys.num_rows(); i < end; ++i) { 00058 const Constraint& c = y.con_sys[i]; 00059 if (gen_sys.satisfied_by_all_generators(c)) 00060 cs_selection.insert(c); 00061 } 00062 } 00063 00064 void 00065 PPL::Polyhedron 00066 ::select_H79_constraints(const Polyhedron& y, 00067 Constraint_System& cs_selected, 00068 Constraint_System& cs_not_selected) const { 00069 // Private method: the caller must ensure the following conditions 00070 // (beside the inclusion `y <= x'). 00071 PPL_ASSERT(topology() == y.topology() 00072 && topology() == cs_selected.topology() 00073 && topology() == cs_not_selected.topology()); 00074 PPL_ASSERT(space_dim == y.space_dim); 00075 PPL_ASSERT(!marked_empty() 00076 && !has_pending_generators() 00077 && constraints_are_up_to_date()); 00078 PPL_ASSERT(!y.marked_empty() 00079 && !y.has_something_pending() 00080 && y.constraints_are_minimized() 00081 && y.generators_are_up_to_date()); 00082 00083 // FIXME: this is a workaround for NNC polyhedra. 00084 if (!y.is_necessarily_closed()) { 00085 // Force strong minimization of constraints. 00086 y.strongly_minimize_constraints(); 00087 // Recompute generators (without compromising constraint minimization). 00088 y.update_generators(); 00089 } 00090 00091 // Obtain a sorted copy of `y.sat_g'. 00092 if (!y.sat_g_is_up_to_date()) 00093 y.update_sat_g(); 00094 Bit_Matrix tmp_sat_g = y.sat_g; 00095 // Remove from `tmp_sat_g' the rows corresponding to tautologies 00096 // (i.e., the positivity or epsilon-bounding constraints): 00097 // this is needed in order to widen the polyhedron and not the 00098 // corresponding homogenized polyhedral cone. 00099 const Constraint_System& y_cs = y.con_sys; 00100 const dimension_type old_num_rows = y_cs.num_rows(); 00101 dimension_type num_rows = old_num_rows; 00102 for (dimension_type i = 0; i < num_rows; ++i) 00103 if (y_cs[i].is_tautological()) { 00104 using std::swap; 00105 --num_rows; 00106 swap(tmp_sat_g[i], tmp_sat_g[num_rows]); 00107 } 00108 tmp_sat_g.remove_trailing_rows(old_num_rows - num_rows); 00109 tmp_sat_g.sort_rows(); 00110 00111 // A constraint in `con_sys' is copied to `cs_selected' 00112 // if its behavior with respect to `y.gen_sys' is the same 00113 // as that of another constraint in `y.con_sys'. 00114 // otherwise it is copied to `cs_not_selected'. 00115 // Namely, we check whether the saturation row `buffer' 00116 // (built starting from the given constraint and `y.gen_sys') 00117 // is a row of the saturation matrix `tmp_sat_g'. 00118 00119 // CHECKME: the following comment is only applicable when `y.gen_sys' 00120 // is minimized. In that case, the comment suggests that it would be 00121 // possible to use a fast (but incomplete) redundancy test based on 00122 // the number of saturators in `buffer'. 00123 // NOTE: If the considered constraint of `con_sys' does not 00124 // satisfy the saturation rule (see Section \ref prelims), then 00125 // it will not appear in the resulting constraint system, 00126 // because `tmp_sat_g' is built starting from a minimized polyhedron. 00127 00128 // The size of `buffer' will reach sat.num_columns() bits. 00129 Bit_Row buffer; 00130 // Note: the loop index `i' goes upward to avoid reversing 00131 // the ordering of the chosen constraints. 00132 for (dimension_type i = 0, end = con_sys.num_rows(); i < end; ++i) { 00133 const Constraint& ci = con_sys[i]; 00134 // The saturation row `buffer' is built considering 00135 // the `i'-th constraint of the polyhedron `x' and 00136 // all the generators of the polyhedron `y'. 00137 buffer.clear(); 00138 for (dimension_type j = y.gen_sys.num_rows(); j-- > 0; ) { 00139 const int sp_sgn = Scalar_Products::sign(ci, y.gen_sys[j]); 00140 // We are assuming that `y <= x'. 00141 PPL_ASSERT(sp_sgn >= 0 00142 || (!is_necessarily_closed() 00143 && ci.is_strict_inequality() 00144 && y.gen_sys[j].is_point())); 00145 if (sp_sgn > 0) 00146 buffer.set(j); 00147 } 00148 // We check whether `buffer' is a row of `tmp_sat_g', 00149 // exploiting its sortedness in order to have faster comparisons. 00150 if (tmp_sat_g.sorted_contains(buffer)) 00151 cs_selected.insert(ci); 00152 else 00153 cs_not_selected.insert(ci); 00154 } 00155 } 00156 00157 void 00158 PPL::Polyhedron::H79_widening_assign(const Polyhedron& y, unsigned* tp) { 00159 Polyhedron& x = *this; 00160 // Topology compatibility check. 00161 const Topology topol = x.topology(); 00162 if (topol != y.topology()) 00163 throw_topology_incompatible("H79_widening_assign(y)", "y", y); 00164 // Dimension-compatibility check. 00165 if (x.space_dim != y.space_dim) 00166 throw_dimension_incompatible("H79_widening_assign(y)", "y", y); 00167 00168 // Assume `y' is contained in or equal to `x'. 00169 PPL_EXPECT_HEAVY(copy_contains(x, y)); 00170 00171 // If any argument is zero-dimensional or empty, 00172 // the H79-widening behaves as the identity function. 00173 if (x.space_dim == 0 || x.marked_empty() || y.marked_empty()) 00174 return; 00175 00176 // `y.gen_sys' should be in minimal form and 00177 // `y.sat_g' should be up-to-date. 00178 if (y.is_necessarily_closed()) { 00179 if (!y.minimize()) 00180 // `y' is empty: the result is `x'. 00181 return; 00182 } 00183 else { 00184 // Dealing with a NNC polyhedron. 00185 // To obtain a correct reasoning when comparing 00186 // the constraints of `x' with the generators of `y', 00187 // we enforce the inclusion relation holding between 00188 // the two NNC polyhedra `x' and `y' (i.e., `y <= x') 00189 // to also hold for the corresponding eps-representations: 00190 // this is obtained by intersecting the two eps-representations. 00191 Polyhedron& yy = const_cast<Polyhedron&>(y); 00192 yy.intersection_assign(x); 00193 if (yy.is_empty()) 00194 // The result is `x'. 00195 return; 00196 } 00197 00198 // If we only have the generators of `x' and the dimensions of 00199 // the two polyhedra are the same, we can compute the standard 00200 // widening by using the specification in [CousotH78], therefore 00201 // avoiding converting from generators to constraints. 00202 if (x.has_pending_generators() || !x.constraints_are_up_to_date()) { 00203 Constraint_System CH78_cs(topol); 00204 x.select_CH78_constraints(y, CH78_cs); 00205 00206 if (CH78_cs.num_rows() == y.con_sys.num_rows()) { 00207 // Having selected all the constraints, the result is `y'. 00208 x = y; 00209 return; 00210 } 00211 // Otherwise, check if `x' and `y' have the same dimension. 00212 // Note that `y.con_sys' is minimized and `CH78_cs' has no redundant 00213 // constraints, since it is a subset of the former. 00214 else if (CH78_cs.num_equalities() == y.con_sys.num_equalities()) { 00215 // Let `x' be defined by the constraints in `CH78_cs'. 00216 Polyhedron CH78(topol, x.space_dim, UNIVERSE); 00217 CH78.add_recycled_constraints(CH78_cs); 00218 00219 // Check whether we are using the widening-with-tokens technique 00220 // and there still are tokens available. 00221 if (tp != 0 && *tp > 0) { 00222 // There are tokens available. If `CH78' is not a subset of `x', 00223 // then it is less precise and we use one of the available tokens. 00224 if (!x.contains(CH78)) 00225 --(*tp); 00226 } 00227 else 00228 // No tokens. 00229 x.m_swap(CH78); 00230 PPL_ASSERT_HEAVY(x.OK(true)); 00231 return; 00232 } 00233 } 00234 00235 // As the dimension of `x' is strictly greater than the dimension of `y', 00236 // we have to compute the standard widening by selecting a subset of 00237 // the constraints of `x'. 00238 // `x.con_sys' is just required to be up-to-date, because: 00239 // - if `x.con_sys' is unsatisfiable, then by assumption 00240 // also `y' is empty, so that the resulting polyhedron is `x'; 00241 // - redundant constraints in `x.con_sys' do not affect the result 00242 // of the widening, because if they are selected they will be 00243 // redundant even in the result. 00244 if (has_pending_generators()) 00245 process_pending_generators(); 00246 else if (!x.constraints_are_up_to_date()) 00247 x.update_constraints(); 00248 00249 // Copy into `H79_cs' the constraints of `x' that are common to `y', 00250 // according to the definition of the H79 widening. 00251 Constraint_System H79_cs(topol); 00252 Constraint_System x_minus_H79_cs(topol); 00253 x.select_H79_constraints(y, H79_cs, x_minus_H79_cs); 00254 00255 if (x_minus_H79_cs.has_no_rows()) 00256 // We selected all of the constraints of `x', 00257 // thus the result of the widening is `x'. 00258 return; 00259 else { 00260 // We selected a strict subset of the constraints of `x'. 00261 // NOTE: as `x.con_sys' was not necessarily in minimal form, 00262 // this does not imply that the result strictly includes `x'. 00263 // Let `H79' be defined by the constraints in `H79_cs'. 00264 Polyhedron H79(topol, x.space_dim, UNIVERSE); 00265 H79.add_recycled_constraints(H79_cs); 00266 00267 // Check whether we are using the widening-with-tokens technique 00268 // and there still are tokens available. 00269 if (tp != 0 && *tp > 0) { 00270 // There are tokens available. If `H79' is not a subset of `x', 00271 // then it is less precise and we use one of the available tokens. 00272 if (!x.contains(H79)) 00273 --(*tp); 00274 } 00275 else 00276 // No tokens. 00277 x.m_swap(H79); 00278 PPL_ASSERT_HEAVY(x.OK(true)); 00279 } 00280 } 00281 00282 void 00283 PPL::Polyhedron::limited_H79_extrapolation_assign(const Polyhedron& y, 00284 const Constraint_System& cs, 00285 unsigned* tp) { 00286 Polyhedron& x = *this; 00287 00288 const dimension_type cs_num_rows = cs.num_rows(); 00289 // If `cs' is empty, we fall back to ordinary, non-limited widening. 00290 if (cs_num_rows == 0) { 00291 x.H79_widening_assign(y, tp); 00292 return; 00293 } 00294 00295 // Topology compatibility check. 00296 if (x.is_necessarily_closed()) { 00297 if (!y.is_necessarily_closed()) 00298 throw_topology_incompatible("limited_H79_extrapolation_assign(y, cs)", 00299 "y", y); 00300 if (cs.has_strict_inequalities()) 00301 throw_topology_incompatible("limited_H79_extrapolation_assign(y, cs)", 00302 "cs", cs); 00303 } 00304 else if (y.is_necessarily_closed()) 00305 throw_topology_incompatible("limited_H79_extrapolation_assign(y, cs)", 00306 "y", y); 00307 00308 // Dimension-compatibility check. 00309 if (x.space_dim != y.space_dim) 00310 throw_dimension_incompatible("limited_H79_extrapolation_assign(y, cs)", 00311 "y", y); 00312 // `cs' must be dimension-compatible with the two polyhedra. 00313 const dimension_type cs_space_dim = cs.space_dimension(); 00314 if (x.space_dim < cs_space_dim) 00315 throw_dimension_incompatible("limited_H79_extrapolation_assign(y, cs)", 00316 "cs", cs); 00317 00318 // Assume `y' is contained in or equal to `x'. 00319 PPL_EXPECT_HEAVY(copy_contains(x, y)); 00320 00321 if (y.marked_empty()) 00322 return; 00323 if (x.marked_empty()) 00324 return; 00325 00326 // The limited H79-widening between two polyhedra in a 00327 // zero-dimensional space is a polyhedron in a zero-dimensional 00328 // space, too. 00329 if (x.space_dim == 0) 00330 return; 00331 00332 if (!y.minimize()) 00333 // We have just discovered that `y' is empty. 00334 return; 00335 00336 // Update the generators of `x': these are used to select, 00337 // from the constraints in `cs', those that must be added 00338 // to the resulting polyhedron. 00339 if ((x.has_pending_constraints() && !x.process_pending_constraints()) 00340 || (!x.generators_are_up_to_date() && !x.update_generators())) 00341 // We have just discovered that `x' is empty. 00342 return; 00343 00344 Constraint_System new_cs; 00345 // The constraints to be added must be satisfied by all the 00346 // generators of `x'. We can disregard `y' because `y <= x'. 00347 const Generator_System& x_gen_sys = x.gen_sys; 00348 // Iterate upwards here so as to keep the relative ordering of constraints. 00349 // Not really an issue: just aesthetics. 00350 for (dimension_type i = 0; i < cs_num_rows; ++i) { 00351 const Constraint& c = cs[i]; 00352 if (x_gen_sys.satisfied_by_all_generators(c)) 00353 new_cs.insert(c); 00354 } 00355 x.H79_widening_assign(y, tp); 00356 x.add_recycled_constraints(new_cs); 00357 PPL_ASSERT_HEAVY(OK()); 00358 } 00359 00360 void 00361 PPL::Polyhedron::bounded_H79_extrapolation_assign(const Polyhedron& y, 00362 const Constraint_System& cs, 00363 unsigned* tp) { 00364 Rational_Box x_box(*this, ANY_COMPLEXITY); 00365 Rational_Box y_box(y, ANY_COMPLEXITY); 00366 x_box.CC76_widening_assign(y_box); 00367 limited_H79_extrapolation_assign(y, cs, tp); 00368 Constraint_System x_box_cs = x_box.constraints(); 00369 add_recycled_constraints(x_box_cs); 00370 } 00371 00372 bool 00373 PPL::Polyhedron 00374 ::BHRZ03_combining_constraints(const Polyhedron& y, 00375 const BHRZ03_Certificate& y_cert, 00376 const Polyhedron& H79, 00377 const Constraint_System& x_minus_H79_cs) { 00378 Polyhedron& x = *this; 00379 // It is assumed that `y <= x <= H79'. 00380 PPL_ASSERT(x.topology() == y.topology() 00381 && x.topology() == H79.topology() 00382 && x.topology() == x_minus_H79_cs.topology()); 00383 PPL_ASSERT(x.space_dim == y.space_dim 00384 && x.space_dim == H79.space_dim 00385 && x.space_dim == x_minus_H79_cs.space_dimension()); 00386 PPL_ASSERT(!x.marked_empty() && !x.has_something_pending() 00387 && x.constraints_are_minimized() && x.generators_are_minimized()); 00388 PPL_ASSERT(!y.marked_empty() && !y.has_something_pending() 00389 && y.constraints_are_minimized() && y.generators_are_minimized()); 00390 PPL_ASSERT(!H79.marked_empty() && !H79.has_something_pending() 00391 && H79.constraints_are_minimized() && H79.generators_are_minimized()); 00392 00393 // We will choose from `x_minus_H79_cs' many subsets of constraints, 00394 // that will be collected (one at a time) in `combining_cs'. 00395 // For each group collected, we compute an average constraint, 00396 // that will be stored in `new_cs'. 00397 00398 // There is no point in applying this technique when `x_minus_H79_cs' 00399 // has one constraint at most (no ``new'' constraint can be computed). 00400 const dimension_type x_minus_H79_cs_num_rows = x_minus_H79_cs.num_rows(); 00401 if (x_minus_H79_cs_num_rows <= 1) 00402 return false; 00403 00404 const Topology topol = x.topology(); 00405 Constraint_System combining_cs(topol); 00406 Constraint_System new_cs(topol); 00407 00408 // Consider the points that belong to both `x.gen_sys' and `y.gen_sys'. 00409 // For NNC polyhedra, the role of points is played by closure points. 00410 const bool closed = x.is_necessarily_closed(); 00411 for (dimension_type i = y.gen_sys.num_rows(); i-- > 0; ) { 00412 const Generator& g = y.gen_sys[i]; 00413 if ((g.is_point() && closed) || (g.is_closure_point() && !closed)) { 00414 // If in `H79.con_sys' there is already an inequality constraint 00415 // saturating this point, then there is no need to produce another 00416 // constraint. 00417 bool lies_on_the_boundary_of_H79 = false; 00418 const Constraint_System& H79_cs = H79.con_sys; 00419 for (dimension_type j = H79_cs.num_rows(); j-- > 0; ) { 00420 const Constraint& c = H79_cs[j]; 00421 if (c.is_inequality() && Scalar_Products::sign(c, g) == 0) { 00422 lies_on_the_boundary_of_H79 = true; 00423 break; 00424 } 00425 } 00426 if (lies_on_the_boundary_of_H79) 00427 continue; 00428 00429 // Consider all the constraints in `x_minus_H79_cs' 00430 // that are saturated by the point `g'. 00431 combining_cs.clear(); 00432 for (dimension_type j = x_minus_H79_cs_num_rows; j-- > 0; ) { 00433 const Constraint& c = x_minus_H79_cs[j]; 00434 if (Scalar_Products::sign(c, g) == 0) 00435 combining_cs.insert(c); 00436 } 00437 // Build a new constraint by combining all the chosen constraints. 00438 const dimension_type combining_cs_num_rows = combining_cs.num_rows(); 00439 if (combining_cs_num_rows > 0) { 00440 if (combining_cs_num_rows == 1) 00441 // No combination is needed. 00442 new_cs.insert(combining_cs[0]); 00443 else { 00444 Linear_Expression e(0); 00445 bool strict_inequality = false; 00446 for (dimension_type h = combining_cs_num_rows; h-- > 0; ) { 00447 if (combining_cs[h].is_strict_inequality()) 00448 strict_inequality = true; 00449 e += Linear_Expression(combining_cs[h]); 00450 } 00451 00452 if (!e.all_homogeneous_terms_are_zero()) { 00453 if (strict_inequality) 00454 new_cs.insert(e > 0); 00455 else 00456 new_cs.insert(e >= 0); 00457 } 00458 } 00459 } 00460 } 00461 } 00462 00463 // If none of the collected constraints strictly intersects `H79', 00464 // then the technique was unsuccessful. 00465 bool improves_upon_H79 = false; 00466 const Poly_Con_Relation si = Poly_Con_Relation::strictly_intersects(); 00467 for (dimension_type i = new_cs.num_rows(); i-- > 0; ) 00468 if (H79.relation_with(new_cs[i]) == si) { 00469 improves_upon_H79 = true; 00470 break; 00471 } 00472 if (!improves_upon_H79) 00473 return false; 00474 00475 // The resulting polyhedron is obtained by adding the constraints 00476 // in `new_cs' to polyhedron `H79'. 00477 Polyhedron result = H79; 00478 result.add_recycled_constraints(new_cs); 00479 // Force minimization. 00480 result.minimize(); 00481 00482 // Check for stabilization with respect to `y_cert' and improvement 00483 // over `H79'. 00484 if (y_cert.is_stabilizing(result) && !result.contains(H79)) { 00485 // The technique was successful. 00486 x.m_swap(result); 00487 PPL_ASSERT_HEAVY(x.OK(true)); 00488 return true; 00489 } 00490 else 00491 // The technique was unsuccessful. 00492 return false; 00493 } 00494 00495 bool 00496 PPL::Polyhedron::BHRZ03_evolving_points(const Polyhedron& y, 00497 const BHRZ03_Certificate& y_cert, 00498 const Polyhedron& H79) { 00499 Polyhedron& x = *this; 00500 // It is assumed that `y <= x <= H79'. 00501 PPL_ASSERT(x.topology() == y.topology() 00502 && x.topology() == H79.topology()); 00503 PPL_ASSERT(x.space_dim == y.space_dim 00504 && x.space_dim == H79.space_dim); 00505 PPL_ASSERT(!x.marked_empty() && !x.has_something_pending() 00506 && x.constraints_are_minimized() && x.generators_are_minimized()); 00507 PPL_ASSERT(!y.marked_empty() && !y.has_something_pending() 00508 && y.constraints_are_minimized() && y.generators_are_minimized()); 00509 PPL_ASSERT(!H79.marked_empty() && !H79.has_something_pending() 00510 && H79.constraints_are_minimized() && H79.generators_are_minimized()); 00511 00512 // For each point in `x.gen_sys' that is not in `y', 00513 // this technique tries to identify a set of rays that: 00514 // - are included in polyhedron `H79'; 00515 // - when added to `y' will subsume the point. 00516 Generator_System candidate_rays; 00517 00518 const dimension_type x_gen_sys_num_rows = x.gen_sys.num_rows(); 00519 const dimension_type y_gen_sys_num_rows = y.gen_sys.num_rows(); 00520 const bool closed = x.is_necessarily_closed(); 00521 for (dimension_type i = x_gen_sys_num_rows; i-- > 0; ) { 00522 Generator& g1 = x.gen_sys[i]; 00523 // For C polyhedra, we choose a point of `x.gen_sys' 00524 // that is not included in `y'. 00525 // In the case of NNC polyhedra, we can restrict attention to 00526 // closure points (considering also points will only add redundancy). 00527 if (((g1.is_point() && closed) || (g1.is_closure_point() && !closed)) 00528 && y.relation_with(g1) == Poly_Gen_Relation::nothing()) { 00529 // For each point (resp., closure point) `g2' in `y.gen_sys', 00530 // where `g1' and `g2' are different, 00531 // build the candidate ray `g1 - g2'. 00532 for (dimension_type j = y_gen_sys_num_rows; j-- > 0; ) { 00533 const Generator& g2 = y.gen_sys[j]; 00534 if ((g2.is_point() && closed) 00535 || (g2.is_closure_point() && !closed)) { 00536 PPL_ASSERT(compare(g1, g2) != 0); 00537 Generator ray_from_g2_to_g1 = g1; 00538 ray_from_g2_to_g1.linear_combine(g2, 0); 00539 candidate_rays.insert(ray_from_g2_to_g1); 00540 } 00541 } 00542 } 00543 } 00544 00545 // Be non-intrusive. 00546 Polyhedron result = x; 00547 result.add_recycled_generators(candidate_rays); 00548 result.intersection_assign(H79); 00549 // Force minimization. 00550 result.minimize(); 00551 00552 // Check for stabilization with respect to `y_cert' and improvement 00553 // over `H79'. 00554 if (y_cert.is_stabilizing(result) && !result.contains(H79)) { 00555 // The technique was successful. 00556 x.m_swap(result); 00557 PPL_ASSERT_HEAVY(x.OK(true)); 00558 return true; 00559 } 00560 else 00561 // The technique was unsuccessful. 00562 return false; 00563 } 00564 00565 bool 00566 PPL::Polyhedron::BHRZ03_evolving_rays(const Polyhedron& y, 00567 const BHRZ03_Certificate& y_cert, 00568 const Polyhedron& H79) { 00569 Polyhedron& x = *this; 00570 // It is assumed that `y <= x <= H79'. 00571 PPL_ASSERT(x.topology() == y.topology() 00572 && x.topology() == H79.topology()); 00573 PPL_ASSERT(x.space_dim == y.space_dim 00574 && x.space_dim == H79.space_dim); 00575 PPL_ASSERT(!x.marked_empty() && !x.has_something_pending() 00576 && x.constraints_are_minimized() && x.generators_are_minimized()); 00577 PPL_ASSERT(!y.marked_empty() && !y.has_something_pending() 00578 && y.constraints_are_minimized() && y.generators_are_minimized()); 00579 PPL_ASSERT(!H79.marked_empty() && !H79.has_something_pending() 00580 && H79.constraints_are_minimized() && H79.generators_are_minimized()); 00581 00582 const dimension_type x_gen_sys_num_rows = x.gen_sys.num_rows(); 00583 const dimension_type y_gen_sys_num_rows = y.gen_sys.num_rows(); 00584 00585 // Candidate rays are kept in a temporary generator system. 00586 Generator_System candidate_rays; 00587 PPL_DIRTY_TEMP_COEFFICIENT(tmp); 00588 for (dimension_type i = x_gen_sys_num_rows; i-- > 0; ) { 00589 const Generator& x_g = x.gen_sys[i]; 00590 // We choose a ray of `x' that does not belong to `y'. 00591 if (x_g.is_ray() && y.relation_with(x_g) == Poly_Gen_Relation::nothing()) { 00592 for (dimension_type j = y_gen_sys_num_rows; j-- > 0; ) { 00593 const Generator& y_g = y.gen_sys[j]; 00594 if (y_g.is_ray()) { 00595 Generator new_ray(x_g); 00596 // Modify `new_ray' according to the evolution of `x_g' with 00597 // respect to `y_g'. 00598 std::deque<bool> considered(x.space_dim + 1); 00599 for (dimension_type k = 1; k < x.space_dim; ++k) 00600 if (!considered[k]) 00601 for (dimension_type h = k + 1; h <= x.space_dim; ++h) 00602 if (!considered[h]) { 00603 tmp = x_g[k] * y_g[h]; 00604 // The following line optimizes the computation of 00605 // <CODE> tmp -= x_g[h] * y_g[k]; </CODE> 00606 sub_mul_assign(tmp, x_g[h], y_g[k]); 00607 const int clockwise 00608 = sgn(tmp); 00609 const int first_or_third_quadrant 00610 = sgn(x_g[k]) * sgn(x_g[h]); 00611 switch (clockwise * first_or_third_quadrant) { 00612 case -1: 00613 new_ray[k] = 0; 00614 considered[k] = true; 00615 break; 00616 case 1: 00617 new_ray[h] = 0; 00618 considered[h] = true; 00619 break; 00620 default: 00621 break; 00622 } 00623 } 00624 new_ray.normalize(); 00625 candidate_rays.insert(new_ray); 00626 } 00627 } 00628 } 00629 } 00630 00631 // If there are no candidate rays, we cannot obtain stabilization. 00632 if (candidate_rays.has_no_rows()) 00633 return false; 00634 00635 // Be non-intrusive. 00636 Polyhedron result = x; 00637 result.add_recycled_generators(candidate_rays); 00638 result.intersection_assign(H79); 00639 // Force minimization. 00640 result.minimize(); 00641 00642 // Check for stabilization with respect to `y' and improvement over `H79'. 00643 if (y_cert.is_stabilizing(result) && !result.contains(H79)) { 00644 // The technique was successful. 00645 x.m_swap(result); 00646 PPL_ASSERT_HEAVY(x.OK(true)); 00647 return true; 00648 } 00649 else 00650 // The technique was unsuccessful. 00651 return false; 00652 } 00653 00654 void 00655 PPL::Polyhedron::BHRZ03_widening_assign(const Polyhedron& y, unsigned* tp) { 00656 Polyhedron& x = *this; 00657 // Topology compatibility check. 00658 if (x.topology() != y.topology()) 00659 throw_topology_incompatible("BHRZ03_widening_assign(y)", "y", y); 00660 // Dimension-compatibility check. 00661 if (x.space_dim != y.space_dim) 00662 throw_dimension_incompatible("BHRZ03_widening_assign(y)", "y", y); 00663 00664 // Assume `y' is contained in or equal to `x'. 00665 PPL_EXPECT_HEAVY(copy_contains(x, y)); 00666 00667 // If any argument is zero-dimensional or empty, 00668 // the BHRZ03-widening behaves as the identity function. 00669 if (x.space_dim == 0 || x.marked_empty() || y.marked_empty()) 00670 return; 00671 00672 // `y.con_sys' and `y.gen_sys' should be in minimal form. 00673 if (!y.minimize()) 00674 // `y' is empty: the result is `x'. 00675 return; 00676 // `x.con_sys' and `x.gen_sys' should be in minimal form. 00677 x.minimize(); 00678 00679 // Compute certificate info for polyhedron `y'. 00680 BHRZ03_Certificate y_cert(y); 00681 00682 // If the iteration is stabilizing, the resulting polyhedron is `x'. 00683 // At this point, also check if the two polyhedra are the same 00684 // (exploiting the knowledge that `y <= x'). 00685 if (y_cert.is_stabilizing(x) || y.contains(x)) { 00686 PPL_ASSERT_HEAVY(OK()); 00687 return; 00688 } 00689 00690 // Here the iteration is not immediately stabilizing. 00691 // If we are using the widening-with-tokens technique and 00692 // there are tokens available, use one of them and return `x'. 00693 if (tp != 0 && *tp > 0) { 00694 --(*tp); 00695 PPL_ASSERT_HEAVY(OK()); 00696 return; 00697 } 00698 00699 // Copy into `H79_cs' the constraints that are common to `x' and `y', 00700 // according to the definition of the H79 widening. 00701 // The other ones are copied into `x_minus_H79_cs'. 00702 const Topology topol = x.topology(); 00703 Constraint_System H79_cs(topol); 00704 Constraint_System x_minus_H79_cs(topol); 00705 x.select_H79_constraints(y, H79_cs, x_minus_H79_cs); 00706 00707 // We cannot have selected all of the rows, since otherwise 00708 // the iteration should have been immediately stabilizing. 00709 PPL_ASSERT(!x_minus_H79_cs.has_no_rows()); 00710 // Be careful to obtain the right space dimension 00711 // (because `H79_cs' may be empty). 00712 Polyhedron H79(topol, x.space_dim, UNIVERSE); 00713 H79.add_recycled_constraints(H79_cs); 00714 // Force minimization. 00715 H79.minimize(); 00716 00717 // NOTE: none of the following widening heuristics is intrusive: 00718 // they will modify `x' only when returning successfully. 00719 if (x.BHRZ03_combining_constraints(y, y_cert, H79, x_minus_H79_cs)) 00720 return; 00721 00722 PPL_ASSERT_HEAVY(H79.OK() && x.OK() && y.OK()); 00723 00724 if (x.BHRZ03_evolving_points(y, y_cert, H79)) 00725 return; 00726 00727 PPL_ASSERT_HEAVY(H79.OK() && x.OK() && y.OK()); 00728 00729 if (x.BHRZ03_evolving_rays(y, y_cert, H79)) 00730 return; 00731 00732 PPL_ASSERT_HEAVY(H79.OK() && x.OK() && y.OK()); 00733 00734 // No previous technique was successful: fall back to the H79 widening. 00735 x.m_swap(H79); 00736 PPL_ASSERT_HEAVY(x.OK(true)); 00737 00738 // The H79 widening is always stabilizing. 00739 PPL_ASSERT(y_cert.is_stabilizing(x)); 00740 } 00741 00742 void 00743 PPL::Polyhedron 00744 ::limited_BHRZ03_extrapolation_assign(const Polyhedron& y, 00745 const Constraint_System& cs, 00746 unsigned* tp) { 00747 Polyhedron& x = *this; 00748 const dimension_type cs_num_rows = cs.num_rows(); 00749 // If `cs' is empty, we fall back to ordinary, non-limited widening. 00750 if (cs_num_rows == 0) { 00751 x.BHRZ03_widening_assign(y, tp); 00752 return; 00753 } 00754 00755 // Topology compatibility check. 00756 if (x.is_necessarily_closed()) { 00757 if (!y.is_necessarily_closed()) 00758 throw_topology_incompatible("limited_BHRZ03_extrapolation_assign(y, cs)", 00759 "y", y); 00760 if (cs.has_strict_inequalities()) 00761 throw_topology_incompatible("limited_BHRZ03_extrapolation_assign(y, cs)", 00762 "cs", cs); 00763 } 00764 else if (y.is_necessarily_closed()) 00765 throw_topology_incompatible("limited_BHRZ03_extrapolation_assign(y, cs)", 00766 "y", y); 00767 00768 // Dimension-compatibility check. 00769 if (x.space_dim != y.space_dim) 00770 throw_dimension_incompatible("limited_BHRZ03_extrapolation_assign(y, cs)", 00771 "y", y); 00772 // `cs' must be dimension-compatible with the two polyhedra. 00773 const dimension_type cs_space_dim = cs.space_dimension(); 00774 if (x.space_dim < cs_space_dim) 00775 throw_dimension_incompatible("limited_BHRZ03_extrapolation_assign(y, cs)", 00776 "cs", cs); 00777 00778 // Assume `y' is contained in or equal to `x'. 00779 PPL_EXPECT_HEAVY(copy_contains(x, y)); 00780 00781 if (y.marked_empty()) 00782 return; 00783 if (x.marked_empty()) 00784 return; 00785 00786 // The limited BHRZ03-widening between two polyhedra in a 00787 // zero-dimensional space is a polyhedron in a zero-dimensional 00788 // space, too. 00789 if (x.space_dim == 0) 00790 return; 00791 00792 if (!y.minimize()) 00793 // We have just discovered that `y' is empty. 00794 return; 00795 00796 // Update the generators of `x': these are used to select, 00797 // from the constraints in `cs', those that must be added 00798 // to the resulting polyhedron. 00799 if ((x.has_pending_constraints() && !x.process_pending_constraints()) 00800 || (!x.generators_are_up_to_date() && !x.update_generators())) 00801 // We have just discovered that `x' is empty. 00802 return; 00803 00804 Constraint_System new_cs; 00805 // The constraints to be added must be satisfied by all the 00806 // generators of `x'. We can disregard `y' because `y <= x'. 00807 const Generator_System& x_gen_sys = x.gen_sys; 00808 // Iterate upwards here so as to keep the relative ordering of constraints. 00809 // Not really an issue: just aesthetics. 00810 for (dimension_type i = 0; i < cs_num_rows; ++i) { 00811 const Constraint& c = cs[i]; 00812 if (x_gen_sys.satisfied_by_all_generators(c)) 00813 new_cs.insert(c); 00814 } 00815 x.BHRZ03_widening_assign(y, tp); 00816 x.add_recycled_constraints(new_cs); 00817 PPL_ASSERT_HEAVY(OK()); 00818 } 00819 00820 void 00821 PPL::Polyhedron 00822 ::bounded_BHRZ03_extrapolation_assign(const Polyhedron& y, 00823 const Constraint_System& cs, 00824 unsigned* tp) { 00825 Rational_Box x_box(*this, ANY_COMPLEXITY); 00826 Rational_Box y_box(y, ANY_COMPLEXITY); 00827 x_box.CC76_widening_assign(y_box); 00828 limited_BHRZ03_extrapolation_assign(y, cs, tp); 00829 Constraint_System x_box_cs = x_box.constraints(); 00830 add_recycled_constraints(x_box_cs); 00831 }