|
PPL
0.12.1
|
00001 /* Polyhedron class implementation 00002 (non-inline private or protected 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 "Scalar_Products.defs.hh" 00028 #include "Linear_Form.defs.hh" 00029 #include "C_Integer.hh" 00030 #include "assert.hh" 00031 #include <string> 00032 #include <iostream> 00033 #include <sstream> 00034 #include <stdexcept> 00035 00036 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS 00037 00046 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS) 00047 #define BE_LAZY 1 00048 00049 namespace PPL = Parma_Polyhedra_Library; 00050 00051 PPL::Polyhedron::Polyhedron(const Topology topol, 00052 const dimension_type num_dimensions, 00053 const Degenerate_Element kind) 00054 : con_sys(topol), 00055 gen_sys(topol), 00056 sat_c(), 00057 sat_g() { 00058 // Protecting against space dimension overflow is up to the caller. 00059 PPL_ASSERT(num_dimensions <= max_space_dimension()); 00060 00061 if (kind == EMPTY) 00062 status.set_empty(); 00063 else if (num_dimensions > 0) { 00064 con_sys.add_low_level_constraints(); 00065 con_sys.adjust_topology_and_space_dimension(topol, num_dimensions); 00066 set_constraints_minimized(); 00067 } 00068 space_dim = num_dimensions; 00069 PPL_ASSERT_HEAVY(OK()); 00070 } 00071 00072 PPL::Polyhedron::Polyhedron(const Polyhedron& y, Complexity_Class) 00073 : con_sys(y.topology()), 00074 gen_sys(y.topology()), 00075 status(y.status), 00076 space_dim(y.space_dim) { 00077 // Being a protected method, we simply assert that topologies do match. 00078 PPL_ASSERT(topology() == y.topology()); 00079 if (y.constraints_are_up_to_date()) 00080 con_sys.assign_with_pending(y.con_sys); 00081 if (y.generators_are_up_to_date()) 00082 gen_sys.assign_with_pending(y.gen_sys); 00083 if (y.sat_c_is_up_to_date()) 00084 sat_c = y.sat_c; 00085 if (y.sat_g_is_up_to_date()) 00086 sat_g = y.sat_g; 00087 } 00088 00089 PPL::Polyhedron::Polyhedron(const Topology topol, const Constraint_System& cs) 00090 : con_sys(topol), 00091 gen_sys(topol), 00092 sat_c(), 00093 sat_g() { 00094 // Protecting against space dimension overflow is up to the caller. 00095 PPL_ASSERT(cs.space_dimension() <= max_space_dimension()); 00096 00097 // TODO: this implementation is just an executable specification. 00098 Constraint_System cs_copy = cs; 00099 00100 // Try to adapt `cs_copy' to the required topology. 00101 const dimension_type cs_copy_space_dim = cs_copy.space_dimension(); 00102 if (!cs_copy.adjust_topology_and_space_dimension(topol, cs_copy_space_dim)) 00103 throw_topology_incompatible((topol == NECESSARILY_CLOSED) 00104 ? "C_Polyhedron(cs)" 00105 : "NNC_Polyhedron(cs)", "cs", cs_copy); 00106 00107 // Set the space dimension. 00108 space_dim = cs_copy_space_dim; 00109 00110 if (space_dim > 0) { 00111 // Stealing the rows from `cs_copy'. 00112 using std::swap; 00113 swap(con_sys, cs_copy); 00114 if (con_sys.num_pending_rows() > 0) { 00115 // Even though `cs_copy' has pending constraints, since the 00116 // generators of the polyhedron are not up-to-date, the 00117 // polyhedron cannot have pending constraints. By integrating 00118 // the pending part of `con_sys' we may loose sortedness. 00119 con_sys.unset_pending_rows(); 00120 con_sys.set_sorted(false); 00121 } 00122 con_sys.add_low_level_constraints(); 00123 set_constraints_up_to_date(); 00124 } 00125 else { 00126 // Here `space_dim == 0'. 00127 if (cs_copy.num_columns() > 0) 00128 // See if an inconsistent constraint has been passed. 00129 for (dimension_type i = cs_copy.num_rows(); i-- > 0; ) 00130 if (cs_copy[i].is_inconsistent()) { 00131 // Inconsistent constraint found: the polyhedron is empty. 00132 set_empty(); 00133 break; 00134 } 00135 } 00136 PPL_ASSERT_HEAVY(OK()); 00137 } 00138 00139 PPL::Polyhedron::Polyhedron(const Topology topol, 00140 Constraint_System& cs, 00141 Recycle_Input) 00142 : con_sys(topol), 00143 gen_sys(topol), 00144 sat_c(), 00145 sat_g() { 00146 // Protecting against space dimension overflow is up to the caller. 00147 PPL_ASSERT(cs.space_dimension() <= max_space_dimension()); 00148 00149 // Try to adapt `cs' to the required topology. 00150 const dimension_type cs_space_dim = cs.space_dimension(); 00151 if (!cs.adjust_topology_and_space_dimension(topol, cs_space_dim)) 00152 throw_topology_incompatible((topol == NECESSARILY_CLOSED) 00153 ? "C_Polyhedron(cs, recycle)" 00154 : "NNC_Polyhedron(cs, recycle)", "cs", cs); 00155 00156 // Set the space dimension. 00157 space_dim = cs_space_dim; 00158 00159 if (space_dim > 0) { 00160 // Stealing the rows from `cs'. 00161 using std::swap; 00162 swap(con_sys, cs); 00163 if (con_sys.num_pending_rows() > 0) { 00164 // Even though `cs' has pending constraints, since the generators 00165 // of the polyhedron are not up-to-date, the polyhedron cannot 00166 // have pending constraints. By integrating the pending part 00167 // of `con_sys' we may loose sortedness. 00168 con_sys.unset_pending_rows(); 00169 con_sys.set_sorted(false); 00170 } 00171 con_sys.add_low_level_constraints(); 00172 set_constraints_up_to_date(); 00173 } 00174 else { 00175 // Here `space_dim == 0'. 00176 if (cs.num_columns() > 0) 00177 // See if an inconsistent constraint has been passed. 00178 for (dimension_type i = cs.num_rows(); i-- > 0; ) 00179 if (cs[i].is_inconsistent()) { 00180 // Inconsistent constraint found: the polyhedron is empty. 00181 set_empty(); 00182 break; 00183 } 00184 } 00185 PPL_ASSERT_HEAVY(OK()); 00186 } 00187 00188 PPL::Polyhedron::Polyhedron(const Topology topol, const Generator_System& gs) 00189 : con_sys(topol), 00190 gen_sys(topol), 00191 sat_c(), 00192 sat_g() { 00193 // Protecting against space dimension overflow is up to the caller. 00194 PPL_ASSERT(gs.space_dimension() <= max_space_dimension()); 00195 00196 // An empty set of generators defines the empty polyhedron. 00197 if (gs.has_no_rows()) { 00198 space_dim = gs.space_dimension(); 00199 status.set_empty(); 00200 PPL_ASSERT_HEAVY(OK()); 00201 return; 00202 } 00203 00204 // Non-empty valid generator systems have a supporting point, at least. 00205 if (!gs.has_points()) 00206 throw_invalid_generators((topol == NECESSARILY_CLOSED) 00207 ? "C_Polyhedron(gs)" 00208 : "NNC_Polyhedron(gs)", "gs"); 00209 00210 // TODO: this implementation is just an executable specification. 00211 Generator_System gs_copy = gs; 00212 00213 const dimension_type gs_copy_space_dim = gs_copy.space_dimension(); 00214 // Try to adapt `gs_copy' to the required topology. 00215 if (!gs_copy.adjust_topology_and_space_dimension(topol, gs_copy_space_dim)) 00216 throw_topology_incompatible((topol == NECESSARILY_CLOSED) 00217 ? "C_Polyhedron(gs)" 00218 : "NNC_Polyhedron(gs)", "gs", gs_copy); 00219 00220 if (gs_copy_space_dim > 0) { 00221 // Stealing the rows from `gs_copy'. 00222 using std::swap; 00223 swap(gen_sys, gs_copy); 00224 // In a generator system describing a NNC polyhedron, 00225 // for each point we must also have the corresponding closure point. 00226 if (topol == NOT_NECESSARILY_CLOSED) 00227 gen_sys.add_corresponding_closure_points(); 00228 if (gen_sys.num_pending_rows() > 0) { 00229 // Even though `gs_copy' has pending generators, since the 00230 // constraints of the polyhedron are not up-to-date, the 00231 // polyhedron cannot have pending generators. By integrating the 00232 // pending part of `gen_sys' we may loose sortedness. 00233 gen_sys.unset_pending_rows(); 00234 gen_sys.set_sorted(false); 00235 } 00236 // Generators are now up-to-date. 00237 set_generators_up_to_date(); 00238 00239 // Set the space dimension. 00240 space_dim = gs_copy_space_dim; 00241 PPL_ASSERT_HEAVY(OK()); 00242 return; 00243 } 00244 00245 // Here `gs_copy.num_rows > 0' and `gs_copy_space_dim == 0': 00246 // we already checked for both the topology-compatibility 00247 // and the supporting point. 00248 space_dim = 0; 00249 PPL_ASSERT_HEAVY(OK()); 00250 } 00251 00252 PPL::Polyhedron::Polyhedron(const Topology topol, 00253 Generator_System& gs, 00254 Recycle_Input) 00255 : con_sys(topol), 00256 gen_sys(topol), 00257 sat_c(), 00258 sat_g() { 00259 // Protecting against space dimension overflow is up to the caller. 00260 PPL_ASSERT(gs.space_dimension() <= max_space_dimension()); 00261 00262 // An empty set of generators defines the empty polyhedron. 00263 if (gs.has_no_rows()) { 00264 space_dim = gs.space_dimension(); 00265 status.set_empty(); 00266 PPL_ASSERT_HEAVY(OK()); 00267 return; 00268 } 00269 00270 // Non-empty valid generator systems have a supporting point, at least. 00271 if (!gs.has_points()) 00272 throw_invalid_generators((topol == NECESSARILY_CLOSED) 00273 ? "C_Polyhedron(gs, recycle)" 00274 : "NNC_Polyhedron(gs, recycle)", "gs"); 00275 00276 const dimension_type gs_space_dim = gs.space_dimension(); 00277 // Try to adapt `gs' to the required topology. 00278 if (!gs.adjust_topology_and_space_dimension(topol, gs_space_dim)) 00279 throw_topology_incompatible((topol == NECESSARILY_CLOSED) 00280 ? "C_Polyhedron(gs, recycle)" 00281 : "NNC_Polyhedron(gs, recycle)", "gs", gs); 00282 00283 if (gs_space_dim > 0) { 00284 // Stealing the rows from `gs'. 00285 using std::swap; 00286 swap(gen_sys, gs); 00287 // In a generator system describing a NNC polyhedron, 00288 // for each point we must also have the corresponding closure point. 00289 if (topol == NOT_NECESSARILY_CLOSED) 00290 gen_sys.add_corresponding_closure_points(); 00291 if (gen_sys.num_pending_rows() > 0) { 00292 // Even though `gs' has pending generators, since the constraints 00293 // of the polyhedron are not up-to-date, the polyhedron cannot 00294 // have pending generators. By integrating the pending part 00295 // of `gen_sys' we may loose sortedness. 00296 gen_sys.unset_pending_rows(); 00297 gen_sys.set_sorted(false); 00298 } 00299 // Generators are now up-to-date. 00300 set_generators_up_to_date(); 00301 00302 // Set the space dimension. 00303 space_dim = gs_space_dim; 00304 PPL_ASSERT_HEAVY(OK()); 00305 return; 00306 } 00307 00308 // Here `gs.num_rows > 0' and `gs_space_dim == 0': 00309 // we already checked for both the topology-compatibility 00310 // and the supporting point. 00311 space_dim = 0; 00312 PPL_ASSERT_HEAVY(OK()); 00313 } 00314 00315 PPL::Polyhedron& 00316 PPL::Polyhedron::operator=(const Polyhedron& y) { 00317 // Being a protected method, we simply assert that topologies do match. 00318 PPL_ASSERT(topology() == y.topology()); 00319 space_dim = y.space_dim; 00320 if (y.marked_empty()) 00321 set_empty(); 00322 else if (space_dim == 0) 00323 set_zero_dim_univ(); 00324 else { 00325 status = y.status; 00326 if (y.constraints_are_up_to_date()) 00327 con_sys.assign_with_pending(y.con_sys); 00328 if (y.generators_are_up_to_date()) 00329 gen_sys.assign_with_pending(y.gen_sys); 00330 if (y.sat_c_is_up_to_date()) 00331 sat_c = y.sat_c; 00332 if (y.sat_g_is_up_to_date()) 00333 sat_g = y.sat_g; 00334 } 00335 return *this; 00336 } 00337 00338 PPL::Polyhedron::Three_Valued_Boolean 00339 PPL::Polyhedron::quick_equivalence_test(const Polyhedron& y) const { 00340 // Private method: the caller must ensure the following. 00341 PPL_ASSERT(topology() == y.topology()); 00342 PPL_ASSERT(space_dim == y.space_dim); 00343 PPL_ASSERT(!marked_empty() && !y.marked_empty() && space_dim > 0); 00344 00345 const Polyhedron& x = *this; 00346 00347 if (x.is_necessarily_closed()) { 00348 if (!x.has_something_pending() && !y.has_something_pending()) { 00349 bool css_normalized = false; 00350 if (x.constraints_are_minimized() && y.constraints_are_minimized()) { 00351 // Equivalent minimized constraint systems have: 00352 // - the same number of constraints; ... 00353 if (x.con_sys.num_rows() != y.con_sys.num_rows()) 00354 return Polyhedron::TVB_FALSE; 00355 // - the same number of equalities; ... 00356 dimension_type x_num_equalities = x.con_sys.num_equalities(); 00357 if (x_num_equalities != y.con_sys.num_equalities()) 00358 return Polyhedron::TVB_FALSE; 00359 // - if there are no equalities, they have the same constraints. 00360 // Delay this test: try cheaper tests on generators first. 00361 css_normalized = (x_num_equalities == 0); 00362 } 00363 00364 if (x.generators_are_minimized() && y.generators_are_minimized()) { 00365 // Equivalent minimized generator systems have: 00366 // - the same number of generators; ... 00367 if (x.gen_sys.num_rows() != y.gen_sys.num_rows()) 00368 return Polyhedron::TVB_FALSE; 00369 // - the same number of lines; ... 00370 const dimension_type x_num_lines = x.gen_sys.num_lines(); 00371 if (x_num_lines != y.gen_sys.num_lines()) 00372 return Polyhedron::TVB_FALSE; 00373 // - if there are no lines, they have the same generators. 00374 if (x_num_lines == 0) { 00375 // Sort the two systems and check for syntactic identity. 00376 x.obtain_sorted_generators(); 00377 y.obtain_sorted_generators(); 00378 if (x.gen_sys == y.gen_sys) 00379 return Polyhedron::TVB_TRUE; 00380 else 00381 return Polyhedron::TVB_FALSE; 00382 } 00383 } 00384 00385 if (css_normalized) { 00386 // Sort the two systems and check for identity. 00387 x.obtain_sorted_constraints(); 00388 y.obtain_sorted_constraints(); 00389 if (x.con_sys == y.con_sys) 00390 return Polyhedron::TVB_TRUE; 00391 else 00392 return Polyhedron::TVB_FALSE; 00393 } 00394 } 00395 } 00396 return Polyhedron::TVB_DONT_KNOW; 00397 } 00398 00399 bool 00400 PPL::Polyhedron::is_included_in(const Polyhedron& y) const { 00401 // Private method: the caller must ensure the following. 00402 PPL_ASSERT(topology() == y.topology()); 00403 PPL_ASSERT(space_dim == y.space_dim); 00404 PPL_ASSERT(!marked_empty() && !y.marked_empty() && space_dim > 0); 00405 00406 const Polyhedron& x = *this; 00407 00408 // `x' cannot have pending constraints, because we need its generators. 00409 if (x.has_pending_constraints() && !x.process_pending_constraints()) 00410 return true; 00411 // `y' cannot have pending generators, because we need its constraints. 00412 if (y.has_pending_generators()) 00413 y.process_pending_generators(); 00414 00415 #if BE_LAZY 00416 if (!x.generators_are_up_to_date() && !x.update_generators()) 00417 return true; 00418 if (!y.constraints_are_up_to_date()) 00419 y.update_constraints(); 00420 #else 00421 if (!x.generators_are_minimized()) 00422 x.minimize(); 00423 if (!y.constraints_are_minimized()) 00424 y.minimize(); 00425 #endif 00426 00427 PPL_ASSERT_HEAVY(x.OK()); 00428 PPL_ASSERT_HEAVY(y.OK()); 00429 00430 const Generator_System& gs = x.gen_sys; 00431 const Constraint_System& cs = y.con_sys; 00432 00433 if (x.is_necessarily_closed()) 00434 // When working with necessarily closed polyhedra, 00435 // `x' is contained in `y' if and only if all the generators of `x' 00436 // satisfy all the inequalities and saturate all the equalities of `y'. 00437 // This comes from the definition of a polyhedron as the set of 00438 // vectors satisfying a constraint system and the fact that all 00439 // vectors in `x' can be obtained by suitably combining its generators. 00440 for (dimension_type i = cs.num_rows(); i-- > 0; ) { 00441 const Constraint& c = cs[i]; 00442 if (c.is_inequality()) { 00443 for (dimension_type j = gs.num_rows(); j-- > 0; ) { 00444 const Generator& g = gs[j]; 00445 const int sp_sign = Scalar_Products::sign(c, g); 00446 if (g.is_line()) { 00447 if (sp_sign != 0) 00448 return false; 00449 } 00450 else 00451 // `g' is a ray or a point. 00452 if (sp_sign < 0) 00453 return false; 00454 } 00455 } 00456 else { 00457 // `c' is an equality. 00458 for (dimension_type j = gs.num_rows(); j-- > 0; ) 00459 if (Scalar_Products::sign(c, gs[j]) != 0) 00460 return false; 00461 } 00462 } 00463 else { 00464 // Here we have an NNC polyhedron: using the reduced scalar product, 00465 // which ignores the epsilon coefficient. 00466 for (dimension_type i = cs.num_rows(); i-- > 0; ) { 00467 const Constraint& c = cs[i]; 00468 switch (c.type()) { 00469 case Constraint::NONSTRICT_INEQUALITY: 00470 for (dimension_type j = gs.num_rows(); j-- > 0; ) { 00471 const Generator& g = gs[j]; 00472 const int sp_sign = Scalar_Products::reduced_sign(c, g); 00473 if (g.is_line()) { 00474 if (sp_sign != 0) 00475 return false; 00476 } 00477 else 00478 // `g' is a ray or a point or a closure point. 00479 if (sp_sign < 0) 00480 return false; 00481 } 00482 break; 00483 case Constraint::EQUALITY: 00484 for (dimension_type j = gs.num_rows(); j-- > 0; ) 00485 if (Scalar_Products::reduced_sign(c, gs[j]) != 0) 00486 return false; 00487 break; 00488 case Constraint::STRICT_INEQUALITY: 00489 for (dimension_type j = gs.num_rows(); j-- > 0; ) { 00490 const Generator& g = gs[j]; 00491 const int sp_sign = Scalar_Products::reduced_sign(c, g); 00492 switch (g.type()) { 00493 case Generator::POINT: 00494 // If a point violates or saturates a strict inequality 00495 // (when ignoring the epsilon coefficients) then it is 00496 // not included in the polyhedron. 00497 if (sp_sign <= 0) 00498 return false; 00499 break; 00500 case Generator::LINE: 00501 // Lines have to saturate all constraints. 00502 if (sp_sign != 0) 00503 return false; 00504 break; 00505 case Generator::RAY: 00506 // Intentionally fall through. 00507 case Generator::CLOSURE_POINT: 00508 // The generator is a ray or closure point: usual test. 00509 if (sp_sign < 0) 00510 return false; 00511 break; 00512 } 00513 } 00514 break; 00515 } 00516 } 00517 } 00518 00519 // Inclusion holds. 00520 return true; 00521 } 00522 00523 bool 00524 PPL::Polyhedron::bounds(const Linear_Expression& expr, 00525 const bool from_above) const { 00526 // The dimension of `expr' should not be greater than the dimension 00527 // of `*this'. 00528 const dimension_type expr_space_dim = expr.space_dimension(); 00529 if (space_dim < expr_space_dim) 00530 throw_dimension_incompatible((from_above 00531 ? "bounds_from_above(e)" 00532 : "bounds_from_below(e)"), "e", expr); 00533 00534 // A zero-dimensional or empty polyhedron bounds everything. 00535 if (space_dim == 0 00536 || marked_empty() 00537 || (has_pending_constraints() && !process_pending_constraints()) 00538 || (!generators_are_up_to_date() && !update_generators())) 00539 return true; 00540 00541 // The polyhedron has updated, possibly pending generators. 00542 for (dimension_type i = gen_sys.num_rows(); i-- > 0; ) { 00543 const Generator& g = gen_sys[i]; 00544 // Only lines and rays in `*this' can cause `expr' to be unbounded. 00545 if (g.is_line_or_ray()) { 00546 const int sp_sign = Scalar_Products::homogeneous_sign(expr, g); 00547 if (sp_sign != 0 00548 && (g.is_line() 00549 || (from_above && sp_sign > 0) 00550 || (!from_above && sp_sign < 0))) 00551 // `*this' does not bound `expr'. 00552 return false; 00553 } 00554 } 00555 // No sources of unboundedness have been found for `expr' 00556 // in the given direction. 00557 return true; 00558 } 00559 00560 bool 00561 PPL::Polyhedron::max_min(const Linear_Expression& expr, 00562 const bool maximize, 00563 Coefficient& ext_n, Coefficient& ext_d, 00564 bool& included, 00565 Generator& g) const { 00566 // The dimension of `expr' should not be greater than the dimension 00567 // of `*this'. 00568 const dimension_type expr_space_dim = expr.space_dimension(); 00569 if (space_dim < expr_space_dim) 00570 throw_dimension_incompatible((maximize 00571 ? "maximize(e, ...)" 00572 : "minimize(e, ...)"), "e", expr); 00573 00574 // Deal with zero-dim polyhedra first. 00575 if (space_dim == 0) { 00576 if (marked_empty()) 00577 return false; 00578 else { 00579 ext_n = expr.inhomogeneous_term(); 00580 ext_d = 1; 00581 included = true; 00582 g = point(); 00583 return true; 00584 } 00585 } 00586 00587 // For an empty polyhedron we simply return false. 00588 if (marked_empty() 00589 || (has_pending_constraints() && !process_pending_constraints()) 00590 || (!generators_are_up_to_date() && !update_generators())) 00591 return false; 00592 00593 // The polyhedron has updated, possibly pending generators. 00594 // The following loop will iterate through the generator 00595 // to find the extremum. 00596 PPL_DIRTY_TEMP(mpq_class, extremum); 00597 00598 // True if we have no other candidate extremum to compare with. 00599 bool first_candidate = true; 00600 00601 // To store the position of the current candidate extremum. 00602 PPL_UNINITIALIZED(dimension_type, ext_position); 00603 00604 // Whether the current candidate extremum is included or not. 00605 PPL_UNINITIALIZED(bool, ext_included); 00606 00607 PPL_DIRTY_TEMP_COEFFICIENT(sp); 00608 for (dimension_type i = gen_sys.num_rows(); i-- > 0; ) { 00609 const Generator& gen_sys_i = gen_sys[i]; 00610 Scalar_Products::homogeneous_assign(sp, expr, gen_sys_i); 00611 // Lines and rays in `*this' can cause `expr' to be unbounded. 00612 if (gen_sys_i.is_line_or_ray()) { 00613 const int sp_sign = sgn(sp); 00614 if (sp_sign != 0 00615 && (gen_sys_i.is_line() 00616 || (maximize && sp_sign > 0) 00617 || (!maximize && sp_sign < 0))) 00618 // `expr' is unbounded in `*this'. 00619 return false; 00620 } 00621 else { 00622 // We have a point or a closure point. 00623 PPL_ASSERT(gen_sys_i.is_point() || gen_sys_i.is_closure_point()); 00624 // Notice that we are ignoring the constant term in `expr' here. 00625 // We will add it to the extremum as soon as we find it. 00626 PPL_DIRTY_TEMP(mpq_class, candidate); 00627 assign_r(candidate.get_num(), sp, ROUND_NOT_NEEDED); 00628 assign_r(candidate.get_den(), gen_sys_i[0], ROUND_NOT_NEEDED); 00629 candidate.canonicalize(); 00630 const bool g_is_point = gen_sys_i.is_point(); 00631 if (first_candidate 00632 || (maximize 00633 && (candidate > extremum 00634 || (g_is_point 00635 && !ext_included 00636 && candidate == extremum))) 00637 || (!maximize 00638 && (candidate < extremum 00639 || (g_is_point 00640 && !ext_included 00641 && candidate == extremum)))) { 00642 // We have a (new) candidate extremum. 00643 first_candidate = false; 00644 extremum = candidate; 00645 ext_position = i; 00646 ext_included = g_is_point; 00647 } 00648 } 00649 } 00650 00651 // Add in the constant term in `expr'. 00652 PPL_DIRTY_TEMP(mpz_class, n); 00653 assign_r(n, expr.inhomogeneous_term(), ROUND_NOT_NEEDED); 00654 extremum += n; 00655 00656 // The polyhedron is bounded in the right direction and we have 00657 // computed the extremum: write the result into the caller's structures. 00658 PPL_ASSERT(!first_candidate); 00659 // FIXME: avoid these temporaries, if possible. 00660 // This can be done adding an `assign' function working on native 00661 // and checked or an operator= that have on one side a checked and 00662 // on the other a native or checked. 00663 // The reason why now we can't use operator= is the fact that we 00664 // still can have Coefficient defined to mpz_class (and not 00665 // Checked_Number<mpz_class>). 00666 ext_n = Coefficient(extremum.get_num()); 00667 ext_d = Coefficient(extremum.get_den()); 00668 included = ext_included; 00669 g = gen_sys[ext_position]; 00670 00671 return true; 00672 } 00673 00674 void 00675 PPL::Polyhedron::set_zero_dim_univ() { 00676 status.set_zero_dim_univ(); 00677 space_dim = 0; 00678 con_sys.clear(); 00679 gen_sys.clear(); 00680 } 00681 00682 void 00683 PPL::Polyhedron::set_empty() { 00684 status.set_empty(); 00685 // The polyhedron is empty: we can thus throw away everything. 00686 con_sys.clear(); 00687 gen_sys.clear(); 00688 sat_c.clear(); 00689 sat_g.clear(); 00690 } 00691 00692 bool 00693 PPL::Polyhedron::process_pending_constraints() const { 00694 PPL_ASSERT(space_dim > 0 && !marked_empty()); 00695 PPL_ASSERT(has_pending_constraints() && !has_pending_generators()); 00696 00697 Polyhedron& x = const_cast<Polyhedron&>(*this); 00698 00699 // Integrate the pending part of the system of constraints and minimize. 00700 // We need `sat_c' up-to-date and `con_sys' sorted (together with `sat_c'). 00701 if (!x.sat_c_is_up_to_date()) 00702 x.sat_c.transpose_assign(x.sat_g); 00703 if (!x.con_sys.is_sorted()) 00704 x.obtain_sorted_constraints_with_sat_c(); 00705 // We sort in place the pending constraints, erasing those constraints 00706 // that also occur in the non-pending part of `con_sys'. 00707 x.con_sys.sort_pending_and_remove_duplicates(); 00708 if (x.con_sys.num_pending_rows() == 0) { 00709 // All pending constraints were duplicates. 00710 x.clear_pending_constraints(); 00711 PPL_ASSERT_HEAVY(OK(true)); 00712 return true; 00713 } 00714 00715 const bool empty = add_and_minimize(true, x.con_sys, x.gen_sys, x.sat_c); 00716 PPL_ASSERT(x.con_sys.num_pending_rows() == 0); 00717 00718 if (empty) 00719 x.set_empty(); 00720 else { 00721 x.clear_pending_constraints(); 00722 x.clear_sat_g_up_to_date(); 00723 x.set_sat_c_up_to_date(); 00724 } 00725 PPL_ASSERT_HEAVY(OK(!empty)); 00726 return !empty; 00727 } 00728 00729 void 00730 PPL::Polyhedron::process_pending_generators() const { 00731 PPL_ASSERT(space_dim > 0 && !marked_empty()); 00732 PPL_ASSERT(has_pending_generators() && !has_pending_constraints()); 00733 00734 Polyhedron& x = const_cast<Polyhedron&>(*this); 00735 00736 // Integrate the pending part of the system of generators and minimize. 00737 // We need `sat_g' up-to-date and `gen_sys' sorted (together with `sat_g'). 00738 if (!x.sat_g_is_up_to_date()) 00739 x.sat_g.transpose_assign(x.sat_c); 00740 if (!x.gen_sys.is_sorted()) 00741 x.obtain_sorted_generators_with_sat_g(); 00742 // We sort in place the pending generators, erasing those generators 00743 // that also occur in the non-pending part of `gen_sys'. 00744 x.gen_sys.sort_pending_and_remove_duplicates(); 00745 if (x.gen_sys.num_pending_rows() == 0) { 00746 // All pending generators were duplicates. 00747 x.clear_pending_generators(); 00748 PPL_ASSERT_HEAVY(OK(true)); 00749 return; 00750 } 00751 00752 add_and_minimize(false, x.gen_sys, x.con_sys, x.sat_g); 00753 PPL_ASSERT(x.gen_sys.num_pending_rows() == 0); 00754 00755 x.clear_pending_generators(); 00756 x.clear_sat_c_up_to_date(); 00757 x.set_sat_g_up_to_date(); 00758 } 00759 00760 void 00761 PPL::Polyhedron::remove_pending_to_obtain_constraints() const { 00762 PPL_ASSERT(has_something_pending()); 00763 00764 Polyhedron& x = const_cast<Polyhedron&>(*this); 00765 00766 // If the polyhedron has pending constraints, simply unset them. 00767 if (x.has_pending_constraints()) { 00768 // Integrate the pending constraints, which are possibly not sorted. 00769 x.con_sys.unset_pending_rows(); 00770 x.con_sys.set_sorted(false); 00771 x.clear_pending_constraints(); 00772 x.clear_constraints_minimized(); 00773 x.clear_generators_up_to_date(); 00774 } 00775 else { 00776 PPL_ASSERT(x.has_pending_generators()); 00777 // We must process the pending generators and obtain the 00778 // corresponding system of constraints. 00779 x.process_pending_generators(); 00780 } 00781 PPL_ASSERT_HEAVY(OK(true)); 00782 } 00783 00784 bool 00785 PPL::Polyhedron::remove_pending_to_obtain_generators() const { 00786 PPL_ASSERT(has_something_pending()); 00787 00788 Polyhedron& x = const_cast<Polyhedron&>(*this); 00789 00790 // If the polyhedron has pending generators, simply unset them. 00791 if (x.has_pending_generators()) { 00792 // Integrate the pending generators, which are possibly not sorted. 00793 x.gen_sys.unset_pending_rows(); 00794 x.gen_sys.set_sorted(false); 00795 x.clear_pending_generators(); 00796 x.clear_generators_minimized(); 00797 x.clear_constraints_up_to_date(); 00798 PPL_ASSERT_HEAVY(OK(true)); 00799 return true; 00800 } 00801 else { 00802 PPL_ASSERT(x.has_pending_constraints()); 00803 // We must integrate the pending constraints and obtain the 00804 // corresponding system of generators. 00805 return x.process_pending_constraints(); 00806 } 00807 } 00808 00809 void 00810 PPL::Polyhedron::update_constraints() const { 00811 PPL_ASSERT(space_dim > 0); 00812 PPL_ASSERT(!marked_empty()); 00813 PPL_ASSERT(generators_are_up_to_date()); 00814 // We assume the polyhedron has no pending constraints or generators. 00815 PPL_ASSERT(!has_something_pending()); 00816 00817 Polyhedron& x = const_cast<Polyhedron&>(*this); 00818 minimize(false, x.gen_sys, x.con_sys, x.sat_c); 00819 // `sat_c' is the only saturation matrix up-to-date. 00820 x.set_sat_c_up_to_date(); 00821 x.clear_sat_g_up_to_date(); 00822 // The system of constraints and the system of generators 00823 // are minimized. 00824 x.set_constraints_minimized(); 00825 x.set_generators_minimized(); 00826 } 00827 00828 bool 00829 PPL::Polyhedron::update_generators() const { 00830 PPL_ASSERT(space_dim > 0); 00831 PPL_ASSERT(!marked_empty()); 00832 PPL_ASSERT(constraints_are_up_to_date()); 00833 // We assume the polyhedron has no pending constraints or generators. 00834 PPL_ASSERT(!has_something_pending()); 00835 00836 Polyhedron& x = const_cast<Polyhedron&>(*this); 00837 // If the system of constraints is not consistent the 00838 // polyhedron is empty. 00839 const bool empty = minimize(true, x.con_sys, x.gen_sys, x.sat_g); 00840 if (empty) 00841 x.set_empty(); 00842 else { 00843 // `sat_g' is the only saturation matrix up-to-date. 00844 x.set_sat_g_up_to_date(); 00845 x.clear_sat_c_up_to_date(); 00846 // The system of constraints and the system of generators 00847 // are minimized. 00848 x.set_constraints_minimized(); 00849 x.set_generators_minimized(); 00850 } 00851 return !empty; 00852 } 00853 00854 void 00855 PPL::Polyhedron::update_sat_c() const { 00856 PPL_ASSERT(constraints_are_minimized()); 00857 PPL_ASSERT(generators_are_minimized()); 00858 PPL_ASSERT(!sat_c_is_up_to_date()); 00859 00860 // We only consider non-pending rows. 00861 const dimension_type csr = con_sys.first_pending_row(); 00862 const dimension_type gsr = gen_sys.first_pending_row(); 00863 Polyhedron& x = const_cast<Polyhedron&>(*this); 00864 00865 // The columns of `sat_c' represent the constraints and 00866 // its rows represent the generators: resize accordingly. 00867 x.sat_c.resize(gsr, csr); 00868 for (dimension_type i = gsr; i-- > 0; ) 00869 for (dimension_type j = csr; j-- > 0; ) { 00870 const int sp_sign = Scalar_Products::sign(con_sys[j], gen_sys[i]); 00871 // The negativity of this scalar product would mean 00872 // that the generator `gen_sys[i]' violates the constraint 00873 // `con_sys[j]' and it is not possible because both generators 00874 // and constraints are up-to-date. 00875 PPL_ASSERT(sp_sign >= 0); 00876 if (sp_sign > 0) 00877 // `gen_sys[i]' satisfies (without saturate) `con_sys[j]'. 00878 x.sat_c[i].set(j); 00879 else 00880 // `gen_sys[i]' saturates `con_sys[j]'. 00881 x.sat_c[i].clear(j); 00882 } 00883 x.set_sat_c_up_to_date(); 00884 } 00885 00886 void 00887 PPL::Polyhedron::update_sat_g() const { 00888 PPL_ASSERT(constraints_are_minimized()); 00889 PPL_ASSERT(generators_are_minimized()); 00890 PPL_ASSERT(!sat_g_is_up_to_date()); 00891 00892 // We only consider non-pending rows. 00893 const dimension_type csr = con_sys.first_pending_row(); 00894 const dimension_type gsr = gen_sys.first_pending_row(); 00895 Polyhedron& x = const_cast<Polyhedron&>(*this); 00896 00897 // The columns of `sat_g' represent generators and its 00898 // rows represent the constraints: resize accordingly. 00899 x.sat_g.resize(csr, gsr); 00900 for (dimension_type i = csr; i-- > 0; ) 00901 for (dimension_type j = gsr; j-- > 0; ) { 00902 const int sp_sign = Scalar_Products::sign(con_sys[i], gen_sys[j]); 00903 // The negativity of this scalar product would mean 00904 // that the generator `gen_sys[j]' violates the constraint 00905 // `con_sys[i]' and it is not possible because both generators 00906 // and constraints are up-to-date. 00907 PPL_ASSERT(sp_sign >= 0); 00908 if (sp_sign > 0) 00909 // `gen_sys[j]' satisfies (without saturate) `con_sys[i]'. 00910 x.sat_g[i].set(j); 00911 else 00912 // `gen_sys[j]' saturates `con_sys[i]'. 00913 x.sat_g[i].clear(j); 00914 } 00915 x.set_sat_g_up_to_date(); 00916 } 00917 00918 void 00919 PPL::Polyhedron::obtain_sorted_constraints() const { 00920 PPL_ASSERT(constraints_are_up_to_date()); 00921 // `con_sys' will be sorted up to `index_first_pending'. 00922 Polyhedron& x = const_cast<Polyhedron&>(*this); 00923 if (!x.con_sys.is_sorted()) { 00924 if (x.sat_g_is_up_to_date()) { 00925 // Sorting constraints keeping `sat_g' consistent. 00926 x.con_sys.sort_and_remove_with_sat(x.sat_g); 00927 // `sat_c' is not up-to-date anymore. 00928 x.clear_sat_c_up_to_date(); 00929 } 00930 else if (x.sat_c_is_up_to_date()) { 00931 // Using `sat_c' to obtain `sat_g', then it is like previous case. 00932 x.sat_g.transpose_assign(x.sat_c); 00933 x.con_sys.sort_and_remove_with_sat(x.sat_g); 00934 x.set_sat_g_up_to_date(); 00935 x.clear_sat_c_up_to_date(); 00936 } 00937 else 00938 // If neither `sat_g' nor `sat_c' are up-to-date, 00939 // we just sort the constraints. 00940 x.con_sys.sort_rows(); 00941 } 00942 00943 PPL_ASSERT(con_sys.check_sorted()); 00944 } 00945 00946 void 00947 PPL::Polyhedron::obtain_sorted_generators() const { 00948 PPL_ASSERT(generators_are_up_to_date()); 00949 // `gen_sys' will be sorted up to `index_first_pending'. 00950 Polyhedron& x = const_cast<Polyhedron&>(*this); 00951 if (!x.gen_sys.is_sorted()) { 00952 if (x.sat_c_is_up_to_date()) { 00953 // Sorting generators keeping 'sat_c' consistent. 00954 x.gen_sys.sort_and_remove_with_sat(x.sat_c); 00955 // `sat_g' is not up-to-date anymore. 00956 x.clear_sat_g_up_to_date(); 00957 } 00958 else if (x.sat_g_is_up_to_date()) { 00959 // Obtaining `sat_c' from `sat_g' and proceeding like previous case. 00960 x.sat_c.transpose_assign(x.sat_g); 00961 x.gen_sys.sort_and_remove_with_sat(x.sat_c); 00962 x.set_sat_c_up_to_date(); 00963 x.clear_sat_g_up_to_date(); 00964 } 00965 else 00966 // If neither `sat_g' nor `sat_c' are up-to-date, we just sort 00967 // the generators. 00968 x.gen_sys.sort_rows(); 00969 } 00970 00971 PPL_ASSERT(gen_sys.check_sorted()); 00972 } 00973 00974 void 00975 PPL::Polyhedron::obtain_sorted_constraints_with_sat_c() const { 00976 PPL_ASSERT(constraints_are_up_to_date()); 00977 PPL_ASSERT(constraints_are_minimized()); 00978 // `con_sys' will be sorted up to `index_first_pending'. 00979 Polyhedron& x = const_cast<Polyhedron&>(*this); 00980 // At least one of the saturation matrices must be up-to-date. 00981 if (!x.sat_c_is_up_to_date() && !x.sat_g_is_up_to_date()) 00982 x.update_sat_c(); 00983 00984 if (x.con_sys.is_sorted()) { 00985 if (x.sat_c_is_up_to_date()) 00986 // If constraints are already sorted and sat_c is up to 00987 // date there is nothing to do. 00988 return; 00989 } 00990 else { 00991 if (!x.sat_g_is_up_to_date()) { 00992 // If constraints are not sorted and sat_g is not up-to-date 00993 // we obtain sat_g from sat_c (that has to be up-to-date)... 00994 x.sat_g.transpose_assign(x.sat_c); 00995 x.set_sat_g_up_to_date(); 00996 } 00997 // ... and sort it together with constraints. 00998 x.con_sys.sort_and_remove_with_sat(x.sat_g); 00999 } 01000 // Obtaining sat_c from sat_g. 01001 x.sat_c.transpose_assign(x.sat_g); 01002 x.set_sat_c_up_to_date(); 01003 // Constraints are sorted now. 01004 x.con_sys.set_sorted(true); 01005 01006 PPL_ASSERT(con_sys.check_sorted()); 01007 } 01008 01009 void 01010 PPL::Polyhedron::obtain_sorted_generators_with_sat_g() const { 01011 PPL_ASSERT(generators_are_up_to_date()); 01012 // `gen_sys' will be sorted up to `index_first_pending'. 01013 Polyhedron& x = const_cast<Polyhedron&>(*this); 01014 // At least one of the saturation matrices must be up-to-date. 01015 if (!x.sat_c_is_up_to_date() && !x.sat_g_is_up_to_date()) 01016 x.update_sat_g(); 01017 01018 if (x.gen_sys.is_sorted()) { 01019 if (x.sat_g_is_up_to_date()) 01020 // If generators are already sorted and sat_g is up to 01021 // date there is nothing to do. 01022 return; 01023 } 01024 else { 01025 if (!x.sat_c_is_up_to_date()) { 01026 // If generators are not sorted and sat_c is not up-to-date 01027 // we obtain sat_c from sat_g (that has to be up-to-date)... 01028 x.sat_c.transpose_assign(x.sat_g); 01029 x.set_sat_c_up_to_date(); 01030 } 01031 // ... and sort it together with generators. 01032 x.gen_sys.sort_and_remove_with_sat(x.sat_c); 01033 } 01034 // Obtaining sat_g from sat_c. 01035 x.sat_g.transpose_assign(sat_c); 01036 x.set_sat_g_up_to_date(); 01037 // Generators are sorted now. 01038 x.gen_sys.set_sorted(true); 01039 01040 PPL_ASSERT(gen_sys.check_sorted()); 01041 } 01042 01043 bool 01044 PPL::Polyhedron::minimize() const { 01045 // 0-dim space or empty polyhedra are already minimized. 01046 if (marked_empty()) 01047 return false; 01048 if (space_dim == 0) 01049 return true; 01050 01051 // If the polyhedron has something pending, process it. 01052 if (has_something_pending()) { 01053 const bool not_empty = process_pending(); 01054 PPL_ASSERT_HEAVY(OK()); 01055 return not_empty; 01056 } 01057 01058 // Here there are no pending constraints or generators. 01059 // Is the polyhedron already minimized? 01060 if (constraints_are_minimized() && generators_are_minimized()) 01061 return true; 01062 01063 // If constraints or generators are up-to-date, invoking 01064 // update_generators() or update_constraints(), respectively, 01065 // minimizes both constraints and generators. 01066 // If both are up-to-date it does not matter whether we use 01067 // update_generators() or update_constraints(): 01068 // both minimize constraints and generators. 01069 if (constraints_are_up_to_date()) { 01070 // We may discover here that `*this' is empty. 01071 const bool ret = update_generators(); 01072 PPL_ASSERT_HEAVY(OK()); 01073 return ret; 01074 } 01075 else { 01076 PPL_ASSERT(generators_are_up_to_date()); 01077 update_constraints(); 01078 PPL_ASSERT_HEAVY(OK()); 01079 return true; 01080 } 01081 } 01082 01083 bool 01084 PPL::Polyhedron::strongly_minimize_constraints() const { 01085 PPL_ASSERT(!is_necessarily_closed()); 01086 01087 // From the user perspective, the polyhedron will not change. 01088 Polyhedron& x = const_cast<Polyhedron&>(*this); 01089 01090 // We need `con_sys' (weakly) minimized and `gen_sys' up-to-date. 01091 // `minimize()' will process any pending constraints or generators. 01092 if (!minimize()) 01093 return false; 01094 01095 // If the polyhedron `*this' is zero-dimensional 01096 // at this point it must be a universe polyhedron. 01097 if (x.space_dim == 0) 01098 return true; 01099 01100 // We also need `sat_g' up-to-date. 01101 if (!sat_g_is_up_to_date()) { 01102 PPL_ASSERT(sat_c_is_up_to_date()); 01103 x.sat_g.transpose_assign(sat_c); 01104 } 01105 01106 // These Bit_Row's will be later used as masks in order to 01107 // check saturation conditions restricted to particular subsets of 01108 // the generator system. 01109 Bit_Row sat_all_but_rays; 01110 Bit_Row sat_all_but_points; 01111 Bit_Row sat_all_but_closure_points; 01112 01113 const dimension_type gs_rows = gen_sys.num_rows(); 01114 const dimension_type n_lines = gen_sys.num_lines(); 01115 for (dimension_type i = gs_rows; i-- > n_lines; ) 01116 switch (gen_sys[i].type()) { 01117 case Generator::RAY: 01118 sat_all_but_rays.set(i); 01119 break; 01120 case Generator::POINT: 01121 sat_all_but_points.set(i); 01122 break; 01123 case Generator::CLOSURE_POINT: 01124 sat_all_but_closure_points.set(i); 01125 break; 01126 case Generator::LINE: 01127 // Found a line with index i >= n_lines ! 01128 PPL_UNREACHABLE; 01129 break; 01130 } 01131 Bit_Row sat_lines_and_rays(sat_all_but_points, sat_all_but_closure_points); 01132 Bit_Row sat_lines_and_closure_points(sat_all_but_rays, sat_all_but_points); 01133 Bit_Row sat_lines(sat_lines_and_rays, sat_lines_and_closure_points); 01134 01135 // These flags are maintained to later decide if we have to add the 01136 // eps_leq_one constraint and whether or not the constraint system 01137 // was changed. 01138 bool changed = false; 01139 bool found_eps_leq_one = false; 01140 01141 // For all the strict inequalities in `con_sys', check for 01142 // eps-redundancy and eventually move them to the bottom part of the 01143 // system. 01144 Constraint_System& cs = x.con_sys; 01145 Bit_Matrix& sat = x.sat_g; 01146 const dimension_type old_cs_rows = cs.num_rows(); 01147 dimension_type cs_rows = old_cs_rows; 01148 const dimension_type eps_index = cs.num_columns() - 1; 01149 for (dimension_type i = 0; i < cs_rows; ) 01150 if (cs[i].is_strict_inequality()) { 01151 // First, check if it is saturated by no closure points 01152 Bit_Row sat_ci; 01153 sat_ci.union_assign(sat[i], sat_lines_and_closure_points); 01154 if (sat_ci == sat_lines) { 01155 // It is saturated by no closure points. 01156 if (!found_eps_leq_one) { 01157 // Check if it is the eps_leq_one constraint. 01158 const Constraint& c = cs[i]; 01159 bool all_zeroes = true; 01160 for (dimension_type k = eps_index; k-- > 1; ) 01161 if (c[k] != 0) { 01162 all_zeroes = false; 01163 break; 01164 } 01165 if (all_zeroes && (c[0] + c[eps_index] == 0)) { 01166 // We found the eps_leq_one constraint. 01167 found_eps_leq_one = true; 01168 // Consider next constraint. 01169 ++i; 01170 continue; 01171 } 01172 } 01173 // Here `cs[i]' is not the eps_leq_one constraint, 01174 // so it is eps-redundant. 01175 // Move it to the bottom of the constraint system, 01176 // while keeping `sat_g' consistent. 01177 --cs_rows; 01178 using std::swap; 01179 swap(cs[i], cs[cs_rows]); 01180 swap(sat[i], sat[cs_rows]); 01181 // The constraint system is changed. 01182 changed = true; 01183 // Continue by considering next constraint, 01184 // which is already in place due to the swap. 01185 continue; 01186 } 01187 // Now we check if there exists another strict inequality 01188 // constraint having a superset of its saturators, 01189 // when disregarding points. 01190 sat_ci.union_assign(sat[i], sat_all_but_points); 01191 bool eps_redundant = false; 01192 for (dimension_type j = 0; j < cs_rows; ++j) 01193 if (i != j && cs[j].is_strict_inequality() 01194 && subset_or_equal(sat[j], sat_ci)) { 01195 // Constraint `cs[i]' is eps-redundant: 01196 // move it to the bottom of the constraint system, 01197 // while keeping `sat_g' consistent. 01198 --cs_rows; 01199 using std::swap; 01200 swap(cs[i], cs[cs_rows]); 01201 swap(sat[i], sat[cs_rows]); 01202 eps_redundant = true; 01203 // The constraint system is changed. 01204 changed = true; 01205 break; 01206 } 01207 // Continue with next constraint, which is already in place 01208 // due to the swap if we have found an eps-redundant constraint. 01209 if (!eps_redundant) 01210 ++i; 01211 } 01212 else 01213 // `cs[i]' is not a strict inequality: consider next constraint. 01214 ++i; 01215 01216 if (changed) { 01217 // If the constraint system has been changed, we have to erase 01218 // the epsilon-redundant constraints. 01219 PPL_ASSERT(cs_rows < cs.num_rows()); 01220 cs.remove_trailing_rows(old_cs_rows - cs_rows); 01221 // The remaining constraints are not pending. 01222 cs.unset_pending_rows(); 01223 // The constraint system is no longer sorted. 01224 cs.set_sorted(false); 01225 // The generator system is no longer up-to-date. 01226 x.clear_generators_up_to_date(); 01227 01228 // If we haven't found an upper bound for the epsilon dimension, 01229 // then we have to check whether such an upper bound is implied 01230 // by the remaining constraints (exploiting the simplex algorithm). 01231 if (!found_eps_leq_one) { 01232 MIP_Problem lp; 01233 // KLUDGE: temporarily mark the constraint system as if it was 01234 // necessarily closed, so that we can interpret the epsilon 01235 // dimension as a standard dimension. Be careful to reset the 01236 // topology of `cs' even on exceptional execution path. 01237 cs.set_necessarily_closed(); 01238 try { 01239 lp.add_space_dimensions_and_embed(cs.space_dimension()); 01240 lp.add_constraints(cs); 01241 cs.set_not_necessarily_closed(); 01242 } 01243 catch (...) { 01244 cs.set_not_necessarily_closed(); 01245 throw; 01246 } 01247 // The objective function is `epsilon'. 01248 lp.set_objective_function(Variable(x.space_dim)); 01249 lp.set_optimization_mode(MAXIMIZATION); 01250 MIP_Problem_Status status = lp.solve(); 01251 PPL_ASSERT(status != UNFEASIBLE_MIP_PROBLEM); 01252 // If the epsilon dimension is actually unbounded, 01253 // then add the eps_leq_one constraint. 01254 if (status == UNBOUNDED_MIP_PROBLEM) 01255 cs.insert(Constraint::epsilon_leq_one()); 01256 } 01257 } 01258 01259 PPL_ASSERT_HEAVY(OK()); 01260 return true; 01261 } 01262 01263 bool 01264 PPL::Polyhedron::strongly_minimize_generators() const { 01265 PPL_ASSERT(!is_necessarily_closed()); 01266 01267 // From the user perspective, the polyhedron will not change. 01268 Polyhedron& x = const_cast<Polyhedron&>(*this); 01269 01270 // We need `gen_sys' (weakly) minimized and `con_sys' up-to-date. 01271 // `minimize()' will process any pending constraints or generators. 01272 if (!minimize()) 01273 return false; 01274 01275 // If the polyhedron `*this' is zero-dimensional 01276 // at this point it must be a universe polyhedron. 01277 if (x.space_dim == 0) 01278 return true; 01279 01280 // We also need `sat_c' up-to-date. 01281 if (!sat_c_is_up_to_date()) { 01282 PPL_ASSERT(sat_g_is_up_to_date()); 01283 x.sat_c.transpose_assign(sat_g); 01284 } 01285 01286 // This Bit_Row will have all and only the indexes 01287 // of strict inequalities set to 1. 01288 Bit_Row sat_all_but_strict_ineq; 01289 const dimension_type cs_rows = con_sys.num_rows(); 01290 const dimension_type n_equals = con_sys.num_equalities(); 01291 for (dimension_type i = cs_rows; i-- > n_equals; ) 01292 if (con_sys[i].is_strict_inequality()) 01293 sat_all_but_strict_ineq.set(i); 01294 01295 // Will record whether or not we changed the generator system. 01296 bool changed = false; 01297 01298 // For all points in the generator system, check for eps-redundancy 01299 // and eventually move them to the bottom part of the system. 01300 Generator_System& gs = const_cast<Generator_System&>(gen_sys); 01301 Bit_Matrix& sat = const_cast<Bit_Matrix&>(sat_c); 01302 const dimension_type old_gs_rows = gs.num_rows(); 01303 dimension_type gs_rows = old_gs_rows; 01304 const dimension_type n_lines = gs.num_lines(); 01305 const dimension_type eps_index = gs.num_columns() - 1; 01306 for (dimension_type i = n_lines; i < gs_rows; ) 01307 if (gs[i].is_point()) { 01308 // Compute the Bit_Row corresponding to the candidate point 01309 // when strict inequality constraints are ignored. 01310 Bit_Row sat_gs_i(sat[i], sat_all_but_strict_ineq); 01311 // Check if the candidate point is actually eps-redundant: 01312 // namely, if there exists another point that saturates 01313 // all the non-strict inequalities saturated by the candidate. 01314 bool eps_redundant = false; 01315 for (dimension_type j = n_lines; j < gs_rows; ++j) 01316 if (i != j && gs[j].is_point() && subset_or_equal(sat[j], sat_gs_i)) { 01317 // Point `gs[i]' is eps-redundant: 01318 // move it to the bottom of the generator system, 01319 // while keeping `sat_c' consistent. 01320 --gs_rows; 01321 using std::swap; 01322 swap(gs[i], gs[gs_rows]); 01323 swap(sat[i], sat[gs_rows]); 01324 eps_redundant = true; 01325 changed = true; 01326 break; 01327 } 01328 if (!eps_redundant) { 01329 // Let all point encodings have epsilon coordinate 1. 01330 Generator& gs_i = gs[i]; 01331 if (gs_i[eps_index] != gs_i[0]) { 01332 gs_i[eps_index] = gs_i[0]; 01333 // Enforce normalization. 01334 gs_i.normalize(); 01335 changed = true; 01336 } 01337 // Consider next generator. 01338 ++i; 01339 } 01340 } 01341 else 01342 // Consider next generator. 01343 ++i; 01344 01345 // If needed, erase the eps-redundant generators (also updating 01346 // `index_first_pending'). 01347 if (gs_rows < old_gs_rows) { 01348 gs.remove_trailing_rows(old_gs_rows - gs_rows); 01349 gs.unset_pending_rows(); 01350 } 01351 01352 if (changed) { 01353 // The generator system is no longer sorted. 01354 x.gen_sys.set_sorted(false); 01355 // The constraint system is no longer up-to-date. 01356 x.clear_constraints_up_to_date(); 01357 } 01358 01359 PPL_ASSERT_HEAVY(OK()); 01360 return true; 01361 } 01362 01363 void 01364 PPL::Polyhedron::refine_no_check(const Constraint& c) { 01365 PPL_ASSERT(!marked_empty()); 01366 PPL_ASSERT(space_dim >= c.space_dimension()); 01367 01368 // Dealing with a zero-dimensional space polyhedron first. 01369 if (space_dim == 0) { 01370 if (c.is_inconsistent()) 01371 set_empty(); 01372 return; 01373 } 01374 01375 // The constraints (possibly with pending rows) are required. 01376 if (has_pending_generators()) 01377 process_pending_generators(); 01378 else if (!constraints_are_up_to_date()) 01379 update_constraints(); 01380 01381 const bool adding_pending = can_have_something_pending(); 01382 01383 if (c.is_necessarily_closed() || !is_necessarily_closed()) 01384 // Since `con_sys' is not empty, the topology and space dimension 01385 // of the inserted constraint are automatically adjusted. 01386 if (adding_pending) 01387 con_sys.insert_pending(c); 01388 else 01389 con_sys.insert(c); 01390 else { 01391 // Here we know that the system of constraints has at least a row. 01392 // However, by barely invoking `con_sys.insert(c)' we would 01393 // cause a change in the topology of `con_sys', which is wrong. 01394 // Thus, we insert a "topology corrected" copy of `c'. 01395 Linear_Expression nc_expr = Linear_Expression(c); 01396 if (c.is_equality()) 01397 if (adding_pending) 01398 con_sys.insert_pending(nc_expr == 0); 01399 else 01400 con_sys.insert(nc_expr == 0); 01401 else 01402 if (adding_pending) 01403 con_sys.insert_pending(nc_expr >= 0); 01404 else 01405 con_sys.insert(nc_expr >= 0); 01406 } 01407 01408 if (adding_pending) 01409 set_constraints_pending(); 01410 else { 01411 // Constraints are not minimized and generators are not up-to-date. 01412 clear_constraints_minimized(); 01413 clear_generators_up_to_date(); 01414 } 01415 01416 // Note: the constraint system may have become unsatisfiable, thus 01417 // we do not check for satisfiability. 01418 PPL_ASSERT_HEAVY(OK()); 01419 } 01420 01421 bool 01422 PPL::Polyhedron::BHZ09_poly_hull_assign_if_exact(const Polyhedron& y) { 01423 Polyhedron& x = *this; 01424 01425 // Private method: the caller must ensure the following. 01426 PPL_ASSERT(x.topology() == y.topology()); 01427 PPL_ASSERT(x.space_dim == y.space_dim); 01428 01429 // The zero-dim case is trivial. 01430 if (x.space_dim == 0) { 01431 x.upper_bound_assign(y); 01432 return true; 01433 } 01434 01435 // If `x' or `y' are (known to be) empty, the upper bound is exact. 01436 if (x.marked_empty()) { 01437 x = y; 01438 return true; 01439 } 01440 else if (y.is_empty()) 01441 return true; 01442 else if (x.is_empty()) { 01443 x = y; 01444 return true; 01445 } 01446 01447 if (x.is_necessarily_closed()) 01448 return x.BHZ09_C_poly_hull_assign_if_exact(y); 01449 else 01450 return x.BHZ09_NNC_poly_hull_assign_if_exact(y); 01451 } 01452 01453 bool 01454 PPL::Polyhedron::BHZ09_C_poly_hull_assign_if_exact(const Polyhedron& y) { 01455 Polyhedron& x = *this; 01456 // Private method: the caller must ensure the following. 01457 PPL_ASSERT(x.is_necessarily_closed() && y.is_necessarily_closed()); 01458 PPL_ASSERT(x.space_dim > 0 && x.space_dim == y.space_dim); 01459 PPL_ASSERT(!x.is_empty() && !y.is_empty()); 01460 01461 // Minimization is not really required, but it is probably the best 01462 // way of getting constraints, generators and saturation matrices 01463 // up-to-date. Minimization it also removes redundant 01464 // constraints/generators. 01465 (void) x.minimize(); 01466 (void) y.minimize(); 01467 01468 // Handle a special case: for topologically closed polyhedra P and Q, 01469 // if the affine dimension of P is greater than that of Q, then 01470 // their upper bound is exact if and only if P includes Q. 01471 const dimension_type x_affine_dim = x.affine_dimension(); 01472 const dimension_type y_affine_dim = y.affine_dimension(); 01473 if (x_affine_dim > y_affine_dim) 01474 return y.is_included_in(x); 01475 else if (x_affine_dim < y_affine_dim) { 01476 if (x.is_included_in(y)) { 01477 x = y; 01478 return true; 01479 } 01480 else 01481 return false; 01482 } 01483 01484 const Constraint_System& x_cs = x.con_sys; 01485 const Generator_System& x_gs = x.gen_sys; 01486 const Generator_System& y_gs = y.gen_sys; 01487 const dimension_type x_gs_num_rows = x_gs.num_rows(); 01488 const dimension_type y_gs_num_rows = y_gs.num_rows(); 01489 01490 // Step 1: generators of `x' that are redundant in `y', and vice versa. 01491 Bit_Row x_gs_red_in_y; 01492 dimension_type num_x_gs_red_in_y = 0; 01493 for (dimension_type i = x_gs_num_rows; i-- > 0; ) 01494 if (y.relation_with(x_gs[i]).implies(Poly_Gen_Relation::subsumes())) { 01495 x_gs_red_in_y.set(i); 01496 ++num_x_gs_red_in_y; 01497 } 01498 Bit_Row y_gs_red_in_x; 01499 dimension_type num_y_gs_red_in_x = 0; 01500 for (dimension_type i = y_gs_num_rows; i-- > 0; ) 01501 if (x.relation_with(y_gs[i]).implies(Poly_Gen_Relation::subsumes())) { 01502 y_gs_red_in_x.set(i); 01503 ++num_y_gs_red_in_x; 01504 } 01505 01506 // Step 2: filter away special cases. 01507 01508 // Step 2.1: inclusion tests. 01509 if (num_y_gs_red_in_x == y_gs_num_rows) 01510 // `y' is included into `x': upper bound `x' is exact. 01511 return true; 01512 if (num_x_gs_red_in_y == x_gs_num_rows) { 01513 // `x' is included into `y': upper bound `y' is exact. 01514 x = y; 01515 return true; 01516 } 01517 01518 // Step 2.2: if no generator of `x' is redundant for `y', then 01519 // (as by 2.1 there exists a constraint of `x' non-redundant for `y') 01520 // the upper bound is not exact; the same if exchanging `x' and `y'. 01521 if (num_x_gs_red_in_y == 0 || num_y_gs_red_in_x == 0) 01522 return false; 01523 01524 // Step 3: see if `x' has a non-redundant constraint `c_x' that is not 01525 // satisfied by `y' and a non-redundant generator in `y' (see Step 1) 01526 // saturating `c_x'. If so, the upper bound is not exact. 01527 01528 // Make sure the saturation matrix for `x' is up to date. 01529 // Any sat matrix would do: we choose `sat_g' because it matches 01530 // the two nested loops (constraints on rows and generators on columns). 01531 if (!x.sat_g_is_up_to_date()) 01532 x.update_sat_g(); 01533 const Bit_Matrix& x_sat = x.sat_g; 01534 01535 Bit_Row all_ones; 01536 all_ones.set_until(x_gs_num_rows); 01537 Bit_Row row_union; 01538 for (dimension_type i = x_cs.num_rows(); i-- > 0; ) { 01539 const bool included 01540 = y.relation_with(x_cs[i]).implies(Poly_Con_Relation::is_included()); 01541 if (!included) { 01542 row_union.union_assign(x_gs_red_in_y, x_sat[i]); 01543 if (row_union != all_ones) 01544 return false; 01545 } 01546 } 01547 01548 // Here we know that the upper bound is exact: compute it. 01549 for (dimension_type j = y_gs_num_rows; j-- > 0; ) 01550 if (!y_gs_red_in_x[j]) 01551 add_generator(y_gs[j]); 01552 01553 PPL_ASSERT_HEAVY(OK()); 01554 return true; 01555 } 01556 01557 bool 01558 PPL::Polyhedron::BHZ09_NNC_poly_hull_assign_if_exact(const Polyhedron& y) { 01559 const Polyhedron& x = *this; 01560 // Private method: the caller must ensure the following. 01561 PPL_ASSERT(!x.is_necessarily_closed() && !y.is_necessarily_closed()); 01562 PPL_ASSERT(x.space_dim > 0 && x.space_dim == y.space_dim); 01563 PPL_ASSERT(!x.is_empty() && !y.is_empty()); 01564 01565 // Minimization is not really required, but it is probably the best 01566 // way of getting constraints, generators and saturation matrices 01567 // up-to-date. Minimization also removes redundant 01568 // constraints/generators. 01569 (void) x.minimize(); 01570 (void) y.minimize(); 01571 01572 const Generator_System& x_gs = x.gen_sys; 01573 const Generator_System& y_gs = y.gen_sys; 01574 const dimension_type x_gs_num_rows = x_gs.num_rows(); 01575 const dimension_type y_gs_num_rows = y_gs.num_rows(); 01576 01577 // Compute generators of `x' that are non-redundant in `y' ... 01578 Bit_Row x_gs_non_redundant_in_y; 01579 Bit_Row x_points_non_redundant_in_y; 01580 Bit_Row x_closure_points; 01581 dimension_type num_x_gs_non_redundant_in_y = 0; 01582 for (dimension_type i = x_gs_num_rows; i-- > 0; ) { 01583 const Generator& x_gs_i = x_gs[i]; 01584 if (x_gs_i.is_closure_point()) 01585 x_closure_points.set(i); 01586 if (y.relation_with(x_gs[i]).implies(Poly_Gen_Relation::subsumes())) 01587 continue; 01588 x_gs_non_redundant_in_y.set(i); 01589 ++num_x_gs_non_redundant_in_y; 01590 if (x_gs_i.is_point()) 01591 x_points_non_redundant_in_y.set(i); 01592 } 01593 01594 // If `x' is included into `y', the upper bound `y' is exact. 01595 if (num_x_gs_non_redundant_in_y == 0) { 01596 *this = y; 01597 return true; 01598 } 01599 01600 // ... and vice versa, generators of `y' that are non-redundant in `x'. 01601 Bit_Row y_gs_non_redundant_in_x; 01602 Bit_Row y_points_non_redundant_in_x; 01603 Bit_Row y_closure_points; 01604 dimension_type num_y_gs_non_redundant_in_x = 0; 01605 for (dimension_type i = y_gs_num_rows; i-- > 0; ) { 01606 const Generator& y_gs_i = y_gs[i]; 01607 if (y_gs_i.is_closure_point()) 01608 y_closure_points.set(i); 01609 if (x.relation_with(y_gs_i).implies(Poly_Gen_Relation::subsumes())) 01610 continue; 01611 y_gs_non_redundant_in_x.set(i); 01612 ++num_y_gs_non_redundant_in_x; 01613 if (y_gs_i.is_point()) 01614 y_points_non_redundant_in_x.set(i); 01615 } 01616 01617 // If `y' is included into `x', the upper bound `x' is exact. 01618 if (num_y_gs_non_redundant_in_x == 0) 01619 return true; 01620 01621 Bit_Row x_non_points_non_redundant_in_y; 01622 x_non_points_non_redundant_in_y 01623 .difference_assign(x_gs_non_redundant_in_y, 01624 x_points_non_redundant_in_y); 01625 01626 const Constraint_System& x_cs = x.con_sys; 01627 const Constraint_System& y_cs = y.con_sys; 01628 const dimension_type x_cs_num_rows = x_cs.num_rows(); 01629 const dimension_type y_cs_num_rows = y_cs.num_rows(); 01630 01631 // Filter away the points of `x_gs' that would be redundant 01632 // in the topological closure of `y'. 01633 Bit_Row x_points_non_redundant_in_y_closure; 01634 for (dimension_type i = x_points_non_redundant_in_y.first(); 01635 i != C_Integer<unsigned long>::max; 01636 i = x_points_non_redundant_in_y.next(i)) { 01637 const Generator& x_p = x_gs[i]; 01638 PPL_ASSERT(x_p.is_point()); 01639 // NOTE: we cannot use Constraint_System::relation_with() 01640 // as we need to treat strict inequalities as if they were nonstrict. 01641 for (dimension_type j = y_cs_num_rows; j-- > 0; ) { 01642 const Constraint& y_c = y_cs[j]; 01643 const int sp_sign = Scalar_Products::reduced_sign(y_c, x_p); 01644 if (sp_sign < 0 || (y_c.is_equality() && sp_sign > 0)) { 01645 x_points_non_redundant_in_y_closure.set(i); 01646 break; 01647 } 01648 } 01649 } 01650 01651 // Make sure the saturation matrix for `x' is up to date. 01652 // Any sat matrix would do: we choose `sat_g' because it matches 01653 // the two nested loops (constraints on rows and generators on columns). 01654 if (!x.sat_g_is_up_to_date()) 01655 x.update_sat_g(); 01656 const Bit_Matrix& x_sat = x.sat_g; 01657 01658 Bit_Row x_cs_condition_3; 01659 Bit_Row x_gs_condition_3; 01660 Bit_Row all_ones; 01661 all_ones.set_until(x_gs_num_rows); 01662 Bit_Row saturators; 01663 Bit_Row tmp_set; 01664 for (dimension_type i = x_cs_num_rows; i-- > 0; ) { 01665 const Constraint& x_c = x_cs[i]; 01666 // Skip constraint if it is not violated by `y'. 01667 if (y.relation_with(x_c).implies(Poly_Con_Relation::is_included())) 01668 continue; 01669 saturators.difference_assign(all_ones, x_sat[i]); 01670 // Check condition 1. 01671 tmp_set.intersection_assign(x_non_points_non_redundant_in_y, saturators); 01672 if (!tmp_set.empty()) 01673 return false; 01674 if (x_c.is_strict_inequality()) { 01675 // Postpone check for condition 3. 01676 x_cs_condition_3.set(i); 01677 tmp_set.intersection_assign(x_closure_points, saturators); 01678 x_gs_condition_3.union_assign(x_gs_condition_3, tmp_set); 01679 } 01680 else { 01681 // Check condition 2. 01682 tmp_set.intersection_assign(x_points_non_redundant_in_y_closure, 01683 saturators); 01684 if (!tmp_set.empty()) 01685 return false; 01686 } 01687 } 01688 01689 // Now exchange the roles of `x' and `y' 01690 // (the statement of the NNC theorem in BHZ09 is symmetric). 01691 01692 Bit_Row y_non_points_non_redundant_in_x; 01693 y_non_points_non_redundant_in_x 01694 .difference_assign(y_gs_non_redundant_in_x, 01695 y_points_non_redundant_in_x); 01696 01697 // Filter away the points of `y_gs' that would be redundant 01698 // in the topological closure of `x'. 01699 Bit_Row y_points_non_redundant_in_x_closure; 01700 for (dimension_type i = y_points_non_redundant_in_x.first(); 01701 i != C_Integer<unsigned long>::max; 01702 i = y_points_non_redundant_in_x.next(i)) { 01703 const Generator& y_p = y_gs[i]; 01704 PPL_ASSERT(y_p.is_point()); 01705 // NOTE: we cannot use Constraint_System::relation_with() 01706 // as we need to treat strict inequalities as if they were nonstrict. 01707 for (dimension_type j = x_cs_num_rows; j-- > 0; ) { 01708 const Constraint& x_c = x_cs[j]; 01709 const int sp_sign = Scalar_Products::reduced_sign(x_c, y_p); 01710 if (sp_sign < 0 || (x_c.is_equality() && sp_sign > 0)) { 01711 y_points_non_redundant_in_x_closure.set(i); 01712 break; 01713 } 01714 } 01715 } 01716 01717 // Make sure the saturation matrix `sat_g' for `y' is up to date. 01718 if (!y.sat_g_is_up_to_date()) 01719 y.update_sat_g(); 01720 const Bit_Matrix& y_sat = y.sat_g; 01721 01722 Bit_Row y_cs_condition_3; 01723 Bit_Row y_gs_condition_3; 01724 all_ones.clear(); 01725 all_ones.set_until(y_gs_num_rows); 01726 for (dimension_type i = y_cs_num_rows; i-- > 0; ) { 01727 const Constraint& y_c = y_cs[i]; 01728 // Skip constraint if it is not violated by `x'. 01729 if (x.relation_with(y_c).implies(Poly_Con_Relation::is_included())) 01730 continue; 01731 saturators.difference_assign(all_ones, y_sat[i]); 01732 // Check condition 1. 01733 tmp_set.intersection_assign(y_non_points_non_redundant_in_x, saturators); 01734 if (!tmp_set.empty()) 01735 return false; 01736 if (y_c.is_strict_inequality()) { 01737 // Postpone check for condition 3. 01738 y_cs_condition_3.set(i); 01739 tmp_set.intersection_assign(y_closure_points, saturators); 01740 y_gs_condition_3.union_assign(y_gs_condition_3, tmp_set); 01741 } 01742 else { 01743 // Check condition 2. 01744 tmp_set.intersection_assign(y_points_non_redundant_in_x_closure, 01745 saturators); 01746 if (!tmp_set.empty()) 01747 return false; 01748 } 01749 } 01750 01751 // Now considering condition 3. 01752 01753 if (x_cs_condition_3.empty() && y_cs_condition_3.empty()) { 01754 // No test for condition 3 is needed. 01755 // The hull is exact: compute it. 01756 for (dimension_type j = y_gs_num_rows; j-- > 0; ) 01757 if (y_gs_non_redundant_in_x[j]) 01758 add_generator(y_gs[j]); 01759 return true; 01760 } 01761 01762 // We have anyway to compute the upper bound and its constraints too. 01763 Polyhedron ub(x); 01764 for (dimension_type j = y_gs_num_rows; j-- > 0; ) 01765 if (y_gs_non_redundant_in_x[j]) 01766 ub.add_generator(y_gs[j]); 01767 (void) ub.minimize(); 01768 PPL_ASSERT(!ub.is_empty()); 01769 01770 // NOTE: the following computation of x_gs_condition_3_not_in_y 01771 // (resp., y_gs_condition_3_not_in_x) is not required for correctness. 01772 // It is done so as to later apply a speculative test 01773 // (i.e., a non-conclusive but computationally lighter test). 01774 01775 // Filter away from `x_gs_condition_3' those closure points 01776 // that, when considered as points, would belong to `y', 01777 // i.e., those that violate no strict constraint in `y_cs'. 01778 Bit_Row x_gs_condition_3_not_in_y; 01779 for (dimension_type i = y_cs_num_rows; i-- > 0; ) { 01780 const Constraint& y_c = y_cs[i]; 01781 if (y_c.is_strict_inequality()) { 01782 for (dimension_type j = x_gs_condition_3.first(); 01783 j != C_Integer<unsigned long>::max; j = x_gs_condition_3.next(j)) { 01784 const Generator& x_cp = x_gs[j]; 01785 PPL_ASSERT(x_cp.is_closure_point()); 01786 const int sp_sign = Scalar_Products::reduced_sign(y_c, x_cp); 01787 PPL_ASSERT(sp_sign >= 0); 01788 if (sp_sign == 0) { 01789 x_gs_condition_3.clear(j); 01790 x_gs_condition_3_not_in_y.set(j); 01791 } 01792 } 01793 if (x_gs_condition_3.empty()) 01794 break; 01795 } 01796 } 01797 // Symmetrically, filter away from `y_gs_condition_3' those 01798 // closure points that, when considered as points, would belong to `x', 01799 // i.e., those that violate no strict constraint in `x_cs'. 01800 Bit_Row y_gs_condition_3_not_in_x; 01801 for (dimension_type i = x_cs_num_rows; i-- > 0; ) { 01802 if (x_cs[i].is_strict_inequality()) { 01803 const Constraint& x_c = x_cs[i]; 01804 for (dimension_type j = y_gs_condition_3.first(); 01805 j != C_Integer<unsigned long>::max; j = y_gs_condition_3.next(j)) { 01806 const Generator& y_cp = y_gs[j]; 01807 PPL_ASSERT(y_cp.is_closure_point()); 01808 const int sp_sign = Scalar_Products::reduced_sign(x_c, y_cp); 01809 PPL_ASSERT(sp_sign >= 0); 01810 if (sp_sign == 0) { 01811 y_gs_condition_3.clear(j); 01812 y_gs_condition_3_not_in_x.set(j); 01813 } 01814 } 01815 if (y_gs_condition_3.empty()) 01816 break; 01817 } 01818 } 01819 01820 // NOTE: here we apply the speculative test. 01821 // Check if there exists a closure point in `x_gs_condition_3_not_in_y' 01822 // or `y_gs_condition_3_not_in_x' that belongs (as point) to the hull. 01823 // If so, the hull is not exact. 01824 const Constraint_System& ub_cs = ub.constraints(); 01825 for (dimension_type i = ub_cs.num_rows(); i-- > 0; ) { 01826 if (ub_cs[i].is_strict_inequality()) { 01827 const Constraint& ub_c = ub_cs[i]; 01828 for (dimension_type j = x_gs_condition_3_not_in_y.first(); 01829 j != C_Integer<unsigned long>::max; 01830 j = x_gs_condition_3_not_in_y.next(j)) { 01831 const Generator& x_cp = x_gs[j]; 01832 PPL_ASSERT(x_cp.is_closure_point()); 01833 const int sp_sign = Scalar_Products::reduced_sign(ub_c, x_cp); 01834 PPL_ASSERT(sp_sign >= 0); 01835 if (sp_sign == 0) 01836 x_gs_condition_3_not_in_y.clear(j); 01837 } 01838 for (dimension_type j = y_gs_condition_3_not_in_x.first(); 01839 j != C_Integer<unsigned long>::max; 01840 j = y_gs_condition_3_not_in_x.next(j)) { 01841 const Generator& y_cp = y_gs[j]; 01842 PPL_ASSERT(y_cp.is_closure_point()); 01843 const int sp_sign = Scalar_Products::reduced_sign(ub_c, y_cp); 01844 PPL_ASSERT(sp_sign >= 0); 01845 if (sp_sign == 0) 01846 y_gs_condition_3_not_in_x.clear(j); 01847 } 01848 } 01849 } 01850 01851 if (!(x_gs_condition_3_not_in_y.empty() 01852 && y_gs_condition_3_not_in_x.empty())) 01853 // There exist a closure point satisfying condition 3, 01854 // hence the hull is not exact. 01855 return false; 01856 01857 // The speculative test was not successful: 01858 // apply the expensive (but conclusive) test for condition 3. 01859 01860 // Consider strict inequalities in `x' violated by `y'. 01861 for (dimension_type i = x_cs_condition_3.first(); 01862 i != C_Integer<unsigned long>::max; i = x_cs_condition_3.next(i)) { 01863 const Constraint& x_cs_i = x_cs[i]; 01864 PPL_ASSERT(x_cs_i.is_strict_inequality()); 01865 // Build the equality constraint induced by x_cs_i. 01866 Constraint eq_i(Linear_Expression(x_cs_i) == 0); 01867 PPL_ASSERT(!(ub.relation_with(eq_i) 01868 .implies(Poly_Con_Relation::is_disjoint()))); 01869 Polyhedron ub_inters_hyperplane(ub); 01870 ub_inters_hyperplane.add_constraint(eq_i); 01871 Polyhedron y_inters_hyperplane(y); 01872 y_inters_hyperplane.add_constraint(eq_i); 01873 if (!y_inters_hyperplane.contains(ub_inters_hyperplane)) 01874 // The hull is not exact. 01875 return false; 01876 } 01877 01878 // Consider strict inequalities in `y' violated by `x'. 01879 for (dimension_type i = y_cs_condition_3.first(); 01880 i != C_Integer<unsigned long>::max; i = y_cs_condition_3.next(i)) { 01881 const Constraint& y_cs_i = y_cs[i]; 01882 PPL_ASSERT(y_cs_i.is_strict_inequality()); 01883 // Build the equality constraint induced by y_cs_i. 01884 Constraint eq_i(Linear_Expression(y_cs_i) == 0); 01885 PPL_ASSERT(!(ub.relation_with(eq_i) 01886 .implies(Poly_Con_Relation::is_disjoint()))); 01887 Polyhedron ub_inters_hyperplane(ub); 01888 ub_inters_hyperplane.add_constraint(eq_i); 01889 Polyhedron x_inters_hyperplane(x); 01890 x_inters_hyperplane.add_constraint(eq_i); 01891 if (!x_inters_hyperplane.contains(ub_inters_hyperplane)) 01892 // The hull is not exact. 01893 return false; 01894 } 01895 01896 // The hull is exact. 01897 m_swap(ub); 01898 return true; 01899 } 01900 01901 bool 01902 PPL::Polyhedron::BFT00_poly_hull_assign_if_exact(const Polyhedron& y) { 01903 // Declare a const reference to *this (to avoid accidental modifications). 01904 const Polyhedron& x = *this; 01905 // Private method: the caller must ensure the following. 01906 PPL_ASSERT(x.is_necessarily_closed()); 01907 PPL_ASSERT(x.topology() == y.topology()); 01908 PPL_ASSERT(x.space_dim == y.space_dim); 01909 01910 // The zero-dim case is trivial. 01911 if (x.space_dim == 0) { 01912 upper_bound_assign(y); 01913 return true; 01914 } 01915 // If `x' or `y' is (known to be) empty, the convex union is exact. 01916 if (x.marked_empty()) { 01917 *this = y; 01918 return true; 01919 } 01920 else if (y.is_empty()) 01921 return true; 01922 else if (x.is_empty()) { 01923 *this = y; 01924 return true; 01925 } 01926 01927 // Here both `x' and `y' are known to be non-empty. 01928 01929 // Implementation based on Algorithm 8.1 (page 15) in [BemporadFT00TR], 01930 // generalized so as to also allow for unbounded polyhedra. 01931 // The extension to unbounded polyhedra is obtained by mimicking 01932 // what done in Algorithm 8.2 (page 19) with respect to 01933 // Algorithm 6.2 (page 13). 01934 // We also apply a couple of improvements (see steps 2.1, 3.1, 6.1, 7.1) 01935 // so as to quickly handle special cases and avoid the splitting 01936 // of equalities/lines into pairs of inequalities/rays. 01937 01938 (void) x.minimize(); 01939 (void) y.minimize(); 01940 const Constraint_System& x_cs = x.con_sys; 01941 const Constraint_System& y_cs = y.con_sys; 01942 const Generator_System& x_gs = x.gen_sys; 01943 const Generator_System& y_gs = y.gen_sys; 01944 const dimension_type x_gs_num_rows = x_gs.num_rows(); 01945 const dimension_type y_gs_num_rows = y_gs.num_rows(); 01946 01947 // Step 1: generators of `x' that are redundant in `y', and vice versa. 01948 std::vector<bool> x_gs_red_in_y(x_gs_num_rows, false); 01949 dimension_type num_x_gs_red_in_y = 0; 01950 for (dimension_type i = x_gs_num_rows; i-- > 0; ) 01951 if (y.relation_with(x_gs[i]).implies(Poly_Gen_Relation::subsumes())) { 01952 x_gs_red_in_y[i] = true; 01953 ++num_x_gs_red_in_y; 01954 } 01955 std::vector<bool> y_gs_red_in_x(y_gs_num_rows, false); 01956 dimension_type num_y_gs_red_in_x = 0; 01957 for (dimension_type i = y_gs_num_rows; i-- > 0; ) 01958 if (x.relation_with(y_gs[i]).implies(Poly_Gen_Relation::subsumes())) { 01959 y_gs_red_in_x[i] = true; 01960 ++num_y_gs_red_in_x; 01961 } 01962 01963 // Step 2: if no redundant generator has been identified, 01964 // then the union is not convex. CHECKME: why? 01965 if (num_x_gs_red_in_y == 0 && num_y_gs_red_in_x == 0) 01966 return false; 01967 01968 // Step 2.1: while at it, also perform quick inclusion tests. 01969 if (num_y_gs_red_in_x == y_gs_num_rows) 01970 // `y' is included into `x': union is convex. 01971 return true; 01972 if (num_x_gs_red_in_y == x_gs_num_rows) { 01973 // `x' is included into `y': union is convex. 01974 *this = y; 01975 return true; 01976 } 01977 01978 // Here we know that `x' is not included in `y', and vice versa. 01979 01980 // Step 3: constraints of `x' that are satisfied by `y', and vice versa. 01981 const dimension_type x_cs_num_rows = x_cs.num_rows(); 01982 std::vector<bool> x_cs_red_in_y(x_cs_num_rows, false); 01983 for (dimension_type i = x_cs_num_rows; i-- > 0; ) { 01984 const Constraint& x_cs_i = x_cs[i]; 01985 if (y.relation_with(x_cs_i).implies(Poly_Con_Relation::is_included())) 01986 x_cs_red_in_y[i] = true; 01987 else if (x_cs_i.is_equality()) 01988 // Step 3.1: `x' has an equality not satisfied by `y': 01989 // union is not convex (recall that `y' does not contain `x'). 01990 // NOTE: this would be false for NNC polyhedra. 01991 // Example: x = { A == 0 }, y = { 0 < A <= 1 }. 01992 return false; 01993 } 01994 const dimension_type y_cs_num_rows = y_cs.num_rows(); 01995 std::vector<bool> y_cs_red_in_x(y_cs_num_rows, false); 01996 for (dimension_type i = y_cs_num_rows; i-- > 0; ) { 01997 const Constraint& y_cs_i = y_cs[i]; 01998 if (x.relation_with(y_cs_i).implies(Poly_Con_Relation::is_included())) 01999 y_cs_red_in_x[i] = true; 02000 else if (y_cs_i.is_equality()) 02001 // Step 3.1: `y' has an equality not satisfied by `x': 02002 // union is not convex (see explanation above). 02003 return false; 02004 } 02005 02006 // Loop in steps 5-9: for each pair of non-redundant generators, 02007 // compute their "mid-point" and check if it is both in `x' and `y'. 02008 02009 // Note: reasoning at the polyhedral cone level. 02010 // CHECKME, FIXME: Polyhedron is a (deprecated) friend of Generator. 02011 // Here below we systematically exploit such a friendship, so as to 02012 // freely reinterpret a Generator as a Linear_Row and vice versa. 02013 Linear_Row mid_row; 02014 const Generator& mid_g = static_cast<const Generator&>(mid_row); 02015 02016 for (dimension_type i = x_gs_num_rows; i-- > 0; ) { 02017 if (x_gs_red_in_y[i]) 02018 continue; 02019 const Linear_Row& x_row = static_cast<const Linear_Row&>(x_gs[i]); 02020 const dimension_type row_sz = x_row.size(); 02021 const bool x_row_is_line = x_row.is_line_or_equality(); 02022 for (dimension_type j = y_gs_num_rows; j-- > 0; ) { 02023 if (y_gs_red_in_x[j]) 02024 continue; 02025 const Linear_Row& y_row = static_cast<const Linear_Row&>(y_gs[j]); 02026 const bool y_row_is_line = y_row.is_line_or_equality(); 02027 02028 // Step 6: compute mid_row = x_row + y_row. 02029 // NOTE: no need to actually compute the "mid-point", 02030 // since any strictly positive combination would do. 02031 mid_row = x_row; 02032 for (dimension_type k = row_sz; k-- > 0; ) 02033 mid_row[k] += y_row[k]; 02034 // A zero ray is not a well formed generator. 02035 const bool illegal_ray 02036 = (mid_row[0] == 0 && mid_row.all_homogeneous_terms_are_zero()); 02037 // A zero ray cannot be generated from a line: this holds 02038 // because x_row (resp., y_row) is not subsumed by y (resp., x). 02039 PPL_ASSERT(!(illegal_ray && (x_row_is_line || y_row_is_line))); 02040 if (illegal_ray) 02041 continue; 02042 // Normalize mid_row (strongly, if needed). 02043 mid_row.normalize(); 02044 if (x_row_is_line) { 02045 if (y_row_is_line) 02046 // mid_row is a line too: sign normalization is needed. 02047 mid_row.sign_normalize(); 02048 else 02049 // mid_row is a ray/point. 02050 mid_row.set_is_ray_or_point_or_inequality(); 02051 } 02052 PPL_ASSERT(mid_g.OK()); 02053 02054 // Step 7: check if mid_g is in the union of x and y. 02055 if (x.relation_with(mid_g) == Poly_Gen_Relation::nothing() 02056 && y.relation_with(mid_g) == Poly_Gen_Relation::nothing()) 02057 return false; 02058 02059 // If either x_row or y_row is a line, we should use its 02060 // negation to produce another generator to be tested too. 02061 // NOTE: exclusive-or is meant. 02062 if (!x_row_is_line && y_row_is_line) { 02063 // Step 6.1: (re-)compute mid_row = x_row - y_row. 02064 mid_row = x_row; 02065 for (dimension_type k = row_sz; k-- > 0; ) 02066 mid_row[k] -= y_row[k]; 02067 mid_row.normalize(); 02068 // Step 7.1: check if mid_g is in the union of x and y. 02069 if (x.relation_with(mid_g) == Poly_Gen_Relation::nothing() 02070 && y.relation_with(mid_g) == Poly_Gen_Relation::nothing()) 02071 return false; 02072 } 02073 else if (x_row_is_line && !y_row_is_line) { 02074 // Step 6.1: (re-)compute mid_row = - x_row + y_row. 02075 mid_row = y_row; 02076 for (dimension_type k = row_sz; k-- > 0; ) 02077 mid_row[k] -= x_row[k]; 02078 mid_row.normalize(); 02079 // Step 7.1: check if mid_g is in the union of x and y. 02080 if (x.relation_with(mid_g) == Poly_Gen_Relation::nothing() 02081 && y.relation_with(mid_g) == Poly_Gen_Relation::nothing()) 02082 return false; 02083 } 02084 } 02085 } 02086 02087 // Here we know that the union of x and y is convex. 02088 // TODO: exploit knowledge on the cardinality of non-redundant 02089 // constraints/generators to improve the convex-hull computation. 02090 // Using generators allows for exploiting incrementality. 02091 for (dimension_type j = 0; j < y_gs_num_rows; ++j) { 02092 if (!y_gs_red_in_x[j]) 02093 add_generator(y_gs[j]); 02094 } 02095 PPL_ASSERT_HEAVY(OK()); 02096 return true; 02097 } 02098 02099 void 02100 PPL::Polyhedron::drop_some_non_integer_points(const Variables_Set* vars_p, 02101 Complexity_Class complexity) { 02102 // There is nothing to do for an empty set of variables. 02103 if (vars_p != 0 && vars_p->empty()) 02104 return; 02105 02106 // Any empty polyhedron does not contain integer points. 02107 if (marked_empty()) 02108 return; 02109 02110 // A zero-dimensional, universe polyhedron has, by convention, an 02111 // integer point. 02112 if (space_dim == 0) { 02113 set_empty(); 02114 return; 02115 } 02116 02117 // The constraints (possibly with pending rows) are required. 02118 if (has_pending_generators()) { 02119 // Processing of pending generators is exponential in the worst case. 02120 if (complexity != ANY_COMPLEXITY) 02121 return; 02122 else 02123 process_pending_generators(); 02124 } 02125 if (!constraints_are_up_to_date()) { 02126 // Constraints update is exponential in the worst case. 02127 if (complexity != ANY_COMPLEXITY) 02128 return; 02129 else 02130 update_constraints(); 02131 } 02132 // For NNC polyhedra we need to process any pending constraints. 02133 if (!is_necessarily_closed() && has_pending_constraints()) { 02134 if (complexity != ANY_COMPLEXITY) 02135 return; 02136 else if (!process_pending_constraints()) 02137 // We just discovered the polyhedron is empty. 02138 return; 02139 } 02140 02141 PPL_ASSERT(!has_pending_generators() && constraints_are_up_to_date()); 02142 PPL_ASSERT(is_necessarily_closed() || !has_pending_constraints()); 02143 02144 bool changed = false; 02145 const dimension_type eps_index = space_dim + 1; 02146 PPL_DIRTY_TEMP_COEFFICIENT(gcd); 02147 02148 for (dimension_type j = con_sys.num_rows(); j-- > 0; ) { 02149 Constraint& c = con_sys[j]; 02150 if (c.is_tautological()) 02151 goto next_constraint; 02152 02153 if (vars_p != 0) { 02154 for (dimension_type i = space_dim; i-- > 0; ) 02155 if (c[i+1] != 0 && vars_p->find(i) == vars_p->end()) 02156 goto next_constraint; 02157 } 02158 02159 if (!is_necessarily_closed()) { 02160 // Transform all strict inequalities into non-strict ones, 02161 // with the inhomogeneous term incremented by 1. 02162 if (c[eps_index] < 0) { 02163 c[eps_index] = 0; 02164 --c[0]; 02165 // Enforce normalization. 02166 // FIXME: is this really necessary? 02167 c.normalize(); 02168 changed = true; 02169 } 02170 } 02171 02172 { 02173 // Compute the GCD of all the homogeneous terms. 02174 dimension_type i = space_dim+1; 02175 while (i > 1) { 02176 const Coefficient& c_i = c[--i]; 02177 if (const int c_i_sign = sgn(c_i)) { 02178 gcd = c_i; 02179 if (c_i_sign < 0) 02180 neg_assign(gcd); 02181 goto compute_gcd; 02182 } 02183 } 02184 // We reach this point only if all the coefficients were zero. 02185 goto next_constraint; 02186 02187 compute_gcd: 02188 if (gcd == 1) 02189 goto next_constraint; 02190 while (i > 1) { 02191 const Coefficient& c_i = c[--i]; 02192 if (c_i != 0) { 02193 // See the comment in Dense_Row::normalize(). 02194 gcd_assign(gcd, c_i, gcd); 02195 if (gcd == 1) 02196 goto next_constraint; 02197 } 02198 } 02199 PPL_ASSERT(gcd != 1); 02200 PPL_ASSERT(c[0] % gcd != 0); 02201 02202 // If we have an equality, the polyhedron becomes empty. 02203 if (c.is_equality()) { 02204 set_empty(); 02205 return; 02206 } 02207 02208 // Divide the inhomogeneous coefficients by the GCD. 02209 for (dimension_type k = space_dim+1; --k > 0; ) { 02210 Coefficient& c_k = c[k]; 02211 exact_div_assign(c_k, c_k, gcd); 02212 } 02213 Coefficient& c_0 = c[0]; 02214 const int c_0_sign = sgn(c_0); 02215 c_0 /= gcd; 02216 if (c_0_sign < 0) 02217 --c_0; 02218 changed = true; 02219 } 02220 02221 next_constraint: 02222 ; 02223 } 02224 02225 if (changed) { 02226 if (!is_necessarily_closed()) { 02227 con_sys.insert(Constraint::epsilon_leq_one()); 02228 // FIXME: make sure that the following line really can stay here 02229 // and should not be moved below the brace. 02230 con_sys.set_sorted(false); 02231 } 02232 02233 // After changing the system of constraints, the generators 02234 // are no longer up-to-date and the constraints are no longer 02235 // minimized. 02236 clear_generators_up_to_date(); 02237 clear_constraints_minimized(); 02238 } 02239 PPL_ASSERT_HEAVY(OK()); 02240 } 02241 02242 void 02243 PPL::Polyhedron::throw_invalid_argument(const char* method, 02244 const char* reason) const { 02245 std::ostringstream s; 02246 s << "PPL::"; 02247 if (is_necessarily_closed()) 02248 s << "C_"; 02249 else 02250 s << "NNC_"; 02251 s << "Polyhedron::" << method << ":" << std::endl 02252 << reason << "."; 02253 throw std::invalid_argument(s.str()); 02254 } 02255 02256 void 02257 PPL::Polyhedron::throw_topology_incompatible(const char* method, 02258 const char* ph_name, 02259 const Polyhedron& ph) const { 02260 std::ostringstream s; 02261 s << "PPL::"; 02262 if (is_necessarily_closed()) 02263 s << "C_"; 02264 else 02265 s << "NNC_"; 02266 s << "Polyhedron::" << method << ":" << std::endl 02267 << ph_name << " is a "; 02268 if (ph.is_necessarily_closed()) 02269 s << "C_"; 02270 else 02271 s << "NNC_"; 02272 s << "Polyhedron." << std::endl; 02273 throw std::invalid_argument(s.str()); 02274 } 02275 02276 void 02277 PPL::Polyhedron::throw_topology_incompatible(const char* method, 02278 const char* c_name, 02279 const Constraint&) const { 02280 PPL_ASSERT(is_necessarily_closed()); 02281 std::ostringstream s; 02282 s << "PPL::C_Polyhedron::" << method << ":" << std::endl 02283 << c_name << " is a strict inequality."; 02284 throw std::invalid_argument(s.str()); 02285 } 02286 02287 void 02288 PPL::Polyhedron::throw_topology_incompatible(const char* method, 02289 const char* g_name, 02290 const Generator&) const { 02291 PPL_ASSERT(is_necessarily_closed()); 02292 std::ostringstream s; 02293 s << "PPL::C_Polyhedron::" << method << ":" << std::endl 02294 << g_name << " is a closure point."; 02295 throw std::invalid_argument(s.str()); 02296 } 02297 02298 void 02299 PPL::Polyhedron::throw_topology_incompatible(const char* method, 02300 const char* cs_name, 02301 const Constraint_System&) const { 02302 PPL_ASSERT(is_necessarily_closed()); 02303 std::ostringstream s; 02304 s << "PPL::C_Polyhedron::" << method << ":" << std::endl 02305 << cs_name << " contains strict inequalities."; 02306 throw std::invalid_argument(s.str()); 02307 } 02308 02309 void 02310 PPL::Polyhedron::throw_topology_incompatible(const char* method, 02311 const char* gs_name, 02312 const Generator_System&) const { 02313 std::ostringstream s; 02314 s << "PPL::C_Polyhedron::" << method << ":" << std::endl 02315 << gs_name << " contains closure points."; 02316 throw std::invalid_argument(s.str()); 02317 } 02318 02319 void 02320 PPL::Polyhedron::throw_dimension_incompatible(const char* method, 02321 const char* other_name, 02322 dimension_type other_dim) const { 02323 std::ostringstream s; 02324 s << "PPL::" 02325 << (is_necessarily_closed() ? "C_" : "NNC_") 02326 << "Polyhedron::" << method << ":\n" 02327 << "this->space_dimension() == " << space_dimension() << ", " 02328 << other_name << ".space_dimension() == " << other_dim << "."; 02329 throw std::invalid_argument(s.str()); 02330 } 02331 02332 void 02333 PPL::Polyhedron::throw_dimension_incompatible(const char* method, 02334 const char* ph_name, 02335 const Polyhedron& ph) const { 02336 throw_dimension_incompatible(method, ph_name, ph.space_dimension()); 02337 } 02338 02339 void 02340 PPL::Polyhedron 02341 ::throw_dimension_incompatible(const char* method, 02342 const char* le_name, 02343 const Linear_Expression& le) const { 02344 throw_dimension_incompatible(method, le_name, le.space_dimension()); 02345 } 02346 02347 void 02348 PPL::Polyhedron::throw_dimension_incompatible(const char* method, 02349 const char* c_name, 02350 const Constraint& c) const { 02351 throw_dimension_incompatible(method, c_name, c.space_dimension()); 02352 } 02353 02354 void 02355 PPL::Polyhedron::throw_dimension_incompatible(const char* method, 02356 const char* g_name, 02357 const Generator& g) const { 02358 throw_dimension_incompatible(method, g_name, g.space_dimension()); 02359 } 02360 02361 void 02362 PPL::Polyhedron::throw_dimension_incompatible(const char* method, 02363 const char* cg_name, 02364 const Congruence& cg) const { 02365 throw_dimension_incompatible(method, cg_name, cg.space_dimension()); 02366 } 02367 02368 void 02369 PPL::Polyhedron::throw_dimension_incompatible(const char* method, 02370 const char* cs_name, 02371 const Constraint_System& cs) const { 02372 throw_dimension_incompatible(method, cs_name, cs.space_dimension()); 02373 } 02374 02375 void 02376 PPL::Polyhedron 02377 ::throw_dimension_incompatible(const char* method, 02378 const char* gs_name, 02379 const Generator_System& gs) const { 02380 throw_dimension_incompatible(method, gs_name, gs.space_dimension()); 02381 } 02382 02383 void 02384 PPL::Polyhedron 02385 ::throw_dimension_incompatible(const char* method, 02386 const char* cgs_name, 02387 const Congruence_System& cgs) const { 02388 throw_dimension_incompatible(method, cgs_name, cgs.space_dimension()); 02389 } 02390 02391 void 02392 PPL::Polyhedron::throw_dimension_incompatible(const char* method, 02393 const char* var_name, 02394 const Variable var) const { 02395 std::ostringstream s; 02396 s << "PPL::"; 02397 if (is_necessarily_closed()) 02398 s << "C_"; 02399 else 02400 s << "NNC_"; 02401 s << "Polyhedron::" << method << ":" << std::endl 02402 << "this->space_dimension() == " << space_dimension() << ", " 02403 << var_name << ".space_dimension() == " << var.space_dimension() << "."; 02404 throw std::invalid_argument(s.str()); 02405 } 02406 02407 void 02408 PPL::Polyhedron:: 02409 throw_dimension_incompatible(const char* method, 02410 dimension_type required_space_dim) const { 02411 std::ostringstream s; 02412 s << "PPL::"; 02413 if (is_necessarily_closed()) 02414 s << "C_"; 02415 else 02416 s << "NNC_"; 02417 s << "Polyhedron::" << method << ":" << std::endl 02418 << "this->space_dimension() == " << space_dimension() 02419 << ", required space dimension == " << required_space_dim << "."; 02420 throw std::invalid_argument(s.str()); 02421 } 02422 02423 PPL::dimension_type 02424 PPL::Polyhedron::check_space_dimension_overflow(const dimension_type dim, 02425 const dimension_type max, 02426 const Topology topol, 02427 const char* method, 02428 const char* reason) { 02429 const char* domain = (topol == NECESSARILY_CLOSED) 02430 ? "PPL::C_Polyhedron::" : "PPL::NNC_Polyhedron::"; 02431 return PPL::check_space_dimension_overflow(dim, max, domain, method, reason); 02432 } 02433 02434 PPL::dimension_type 02435 PPL::Polyhedron::check_space_dimension_overflow(const dimension_type dim, 02436 const Topology topol, 02437 const char* method, 02438 const char* reason) { 02439 return check_space_dimension_overflow(dim, Polyhedron::max_space_dimension(), 02440 topol, method, reason); 02441 } 02442 02443 void 02444 PPL::Polyhedron::throw_invalid_generator(const char* method, 02445 const char* g_name) const { 02446 std::ostringstream s; 02447 s << "PPL::"; 02448 if (is_necessarily_closed()) 02449 s << "C_"; 02450 else 02451 s << "NNC_"; 02452 s << "Polyhedron::" << method << ":" << std::endl 02453 << "*this is an empty polyhedron and " 02454 << g_name << " is not a point."; 02455 throw std::invalid_argument(s.str()); 02456 } 02457 02458 void 02459 PPL::Polyhedron::throw_invalid_generators(const char* method, 02460 const char* gs_name) const { 02461 std::ostringstream s; 02462 s << "PPL::"; 02463 if (is_necessarily_closed()) 02464 s << "C_"; 02465 else 02466 s << "NNC_"; 02467 s << "Polyhedron::" << method << ":" << std::endl 02468 << "*this is an empty polyhedron and" << std::endl 02469 << "the non-empty generator system " << gs_name << " contains no points."; 02470 throw std::invalid_argument(s.str()); 02471 }