|
PPL
0.12.1
|
00001 /* Box class implementation: non-inline template functions. 00002 Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it> 00003 Copyright (C) 2010-2012 BUGSENG srl (http://bugseng.com) 00004 00005 This file is part of the Parma Polyhedra Library (PPL). 00006 00007 The PPL is free software; you can redistribute it and/or modify it 00008 under the terms of the GNU General Public License as published by the 00009 Free Software Foundation; either version 3 of the License, or (at your 00010 option) any later version. 00011 00012 The PPL is distributed in the hope that it will be useful, but WITHOUT 00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 00015 for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program; if not, write to the Free Software Foundation, 00019 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA. 00020 00021 For the most up-to-date information see the Parma Polyhedra Library 00022 site: http://bugseng.com/products/ppl/ . */ 00023 00024 #ifndef PPL_Box_templates_hh 00025 #define PPL_Box_templates_hh 1 00026 00027 #include "Variables_Set.defs.hh" 00028 #include "Constraint_System.defs.hh" 00029 #include "Constraint_System.inlines.hh" 00030 #include "Generator_System.defs.hh" 00031 #include "Generator_System.inlines.hh" 00032 #include "Poly_Con_Relation.defs.hh" 00033 #include "Poly_Gen_Relation.defs.hh" 00034 #include "Polyhedron.defs.hh" 00035 #include "Grid.defs.hh" 00036 #include "Interval.defs.hh" 00037 #include "Linear_Form.defs.hh" 00038 #include "BD_Shape.defs.hh" 00039 #include "Octagonal_Shape.defs.hh" 00040 #include "MIP_Problem.defs.hh" 00041 #include "Rational_Interval.hh" 00042 #include <vector> 00043 #include <map> 00044 #include <iostream> 00045 00046 namespace Parma_Polyhedra_Library { 00047 00048 template <typename ITV> 00049 inline 00050 Box<ITV>::Box(dimension_type num_dimensions, Degenerate_Element kind) 00051 : seq(check_space_dimension_overflow(num_dimensions, 00052 max_space_dimension(), 00053 "PPL::Box::", 00054 "Box(n, k)", 00055 "n exceeds the maximum " 00056 "allowed space dimension")), 00057 status() { 00058 // In a box that is marked empty the intervals are completely 00059 // meaningless: we exploit this by avoiding their initialization. 00060 if (kind == UNIVERSE) { 00061 for (dimension_type i = num_dimensions; i-- > 0; ) 00062 seq[i].assign(UNIVERSE); 00063 set_empty_up_to_date(); 00064 } 00065 else 00066 set_empty(); 00067 PPL_ASSERT(OK()); 00068 } 00069 00070 template <typename ITV> 00071 inline 00072 Box<ITV>::Box(const Constraint_System& cs) 00073 : seq(check_space_dimension_overflow(cs.space_dimension(), 00074 max_space_dimension(), 00075 "PPL::Box::", 00076 "Box(cs)", 00077 "cs exceeds the maximum " 00078 "allowed space dimension")), 00079 status() { 00080 // FIXME: check whether we can avoid the double initialization. 00081 for (dimension_type i = cs.space_dimension(); i-- > 0; ) 00082 seq[i].assign(UNIVERSE); 00083 add_constraints_no_check(cs); 00084 } 00085 00086 template <typename ITV> 00087 inline 00088 Box<ITV>::Box(const Congruence_System& cgs) 00089 : seq(check_space_dimension_overflow(cgs.space_dimension(), 00090 max_space_dimension(), 00091 "PPL::Box::", 00092 "Box(cgs)", 00093 "cgs exceeds the maximum " 00094 "allowed space dimension")), 00095 status() { 00096 // FIXME: check whether we can avoid the double initialization. 00097 for (dimension_type i = cgs.space_dimension(); i-- > 0; ) 00098 seq[i].assign(UNIVERSE); 00099 add_congruences_no_check(cgs); 00100 } 00101 00102 template <typename ITV> 00103 template <typename Other_ITV> 00104 inline 00105 Box<ITV>::Box(const Box<Other_ITV>& y, Complexity_Class) 00106 : seq(y.space_dimension()), 00107 // FIXME: why the following does not work? 00108 // status(y.status) { 00109 status() { 00110 // FIXME: remove when the above is fixed. 00111 if (y.marked_empty()) 00112 set_empty(); 00113 00114 if (!y.marked_empty()) 00115 for (dimension_type k = y.space_dimension(); k-- > 0; ) 00116 seq[k].assign(y.seq[k]); 00117 PPL_ASSERT(OK()); 00118 } 00119 00120 template <typename ITV> 00121 Box<ITV>::Box(const Generator_System& gs) 00122 : seq(check_space_dimension_overflow(gs.space_dimension(), 00123 max_space_dimension(), 00124 "PPL::Box::", 00125 "Box(gs)", 00126 "gs exceeds the maximum " 00127 "allowed space dimension")), 00128 status() { 00129 const Generator_System::const_iterator gs_begin = gs.begin(); 00130 const Generator_System::const_iterator gs_end = gs.end(); 00131 if (gs_begin == gs_end) { 00132 // An empty generator system defines the empty box. 00133 set_empty(); 00134 return; 00135 } 00136 00137 // The empty flag will be meaningful, whatever happens from now on. 00138 set_empty_up_to_date(); 00139 00140 const dimension_type space_dim = space_dimension(); 00141 PPL_DIRTY_TEMP(mpq_class, q); 00142 bool point_seen = false; 00143 // Going through all the points. 00144 for (Generator_System::const_iterator 00145 gs_i = gs_begin; gs_i != gs_end; ++gs_i) { 00146 const Generator& g = *gs_i; 00147 if (g.is_point()) { 00148 const Coefficient& d = g.divisor(); 00149 if (point_seen) { 00150 // This is not the first point: `seq' already contains valid values. 00151 for (dimension_type i = space_dim; i-- > 0; ) { 00152 assign_r(q.get_num(), g.coefficient(Variable(i)), ROUND_NOT_NEEDED); 00153 assign_r(q.get_den(), d, ROUND_NOT_NEEDED); 00154 q.canonicalize(); 00155 PPL_DIRTY_TEMP(ITV, iq); 00156 iq.build(i_constraint(EQUAL, q)); 00157 seq[i].join_assign(iq); 00158 } 00159 } 00160 else { 00161 // This is the first point seen: initialize `seq'. 00162 point_seen = true; 00163 for (dimension_type i = space_dim; i-- > 0; ) { 00164 assign_r(q.get_num(), g.coefficient(Variable(i)), ROUND_NOT_NEEDED); 00165 assign_r(q.get_den(), d, ROUND_NOT_NEEDED); 00166 q.canonicalize(); 00167 seq[i].build(i_constraint(EQUAL, q)); 00168 } 00169 } 00170 } 00171 } 00172 00173 if (!point_seen) 00174 // The generator system is not empty, but contains no points. 00175 throw std::invalid_argument("PPL::Box<ITV>::Box(gs):\n" 00176 "the non-empty generator system gs " 00177 "contains no points."); 00178 00179 // Going through all the lines, rays and closure points. 00180 ITV q_interval; 00181 for (Generator_System::const_iterator gs_i = gs_begin; 00182 gs_i != gs_end; ++gs_i) { 00183 const Generator& g = *gs_i; 00184 switch (g.type()) { 00185 case Generator::LINE: 00186 for (dimension_type i = space_dim; i-- > 0; ) 00187 if (g.coefficient(Variable(i)) != 0) 00188 seq[i].assign(UNIVERSE); 00189 break; 00190 case Generator::RAY: 00191 for (dimension_type i = space_dim; i-- > 0; ) 00192 switch (sgn(g.coefficient(Variable(i)))) { 00193 case 1: 00194 seq[i].upper_extend(); 00195 break; 00196 case -1: 00197 seq[i].lower_extend(); 00198 break; 00199 default: 00200 break; 00201 } 00202 break; 00203 case Generator::CLOSURE_POINT: 00204 { 00205 const Coefficient& d = g.divisor(); 00206 for (dimension_type i = space_dim; i-- > 0; ) { 00207 assign_r(q.get_num(), g.coefficient(Variable(i)), ROUND_NOT_NEEDED); 00208 assign_r(q.get_den(), d, ROUND_NOT_NEEDED); 00209 q.canonicalize(); 00210 ITV& seq_i = seq[i]; 00211 seq_i.lower_extend(i_constraint(GREATER_THAN, q)); 00212 seq_i.upper_extend(i_constraint(LESS_THAN, q)); 00213 } 00214 } 00215 break; 00216 default: 00217 // Points already dealt with. 00218 break; 00219 } 00220 } 00221 PPL_ASSERT(OK()); 00222 } 00223 00224 template <typename ITV> 00225 template <typename T> 00226 Box<ITV>::Box(const BD_Shape<T>& bds, Complexity_Class) 00227 : seq(check_space_dimension_overflow(bds.space_dimension(), 00228 max_space_dimension(), 00229 "PPL::Box::", 00230 "Box(bds)", 00231 "bds exceeds the maximum " 00232 "allowed space dimension")), 00233 status() { 00234 // Expose all the interval constraints. 00235 bds.shortest_path_closure_assign(); 00236 if (bds.marked_empty()) { 00237 set_empty(); 00238 PPL_ASSERT(OK()); 00239 return; 00240 } 00241 00242 // The empty flag will be meaningful, whatever happens from now on. 00243 set_empty_up_to_date(); 00244 00245 const dimension_type space_dim = space_dimension(); 00246 if (space_dim == 0) { 00247 PPL_ASSERT(OK()); 00248 return; 00249 } 00250 00251 typedef typename BD_Shape<T>::coefficient_type Coeff; 00252 PPL_DIRTY_TEMP(Coeff, tmp); 00253 const DB_Row<Coeff>& dbm_0 = bds.dbm[0]; 00254 for (dimension_type i = space_dim; i-- > 0; ) { 00255 I_Constraint<Coeff> lower; 00256 I_Constraint<Coeff> upper; 00257 ITV& seq_i = seq[i]; 00258 00259 // Set the upper bound. 00260 const Coeff& u = dbm_0[i+1]; 00261 if (!is_plus_infinity(u)) 00262 upper.set(LESS_OR_EQUAL, u, true); 00263 00264 // Set the lower bound. 00265 const Coeff& negated_l = bds.dbm[i+1][0]; 00266 if (!is_plus_infinity(negated_l)) { 00267 neg_assign_r(tmp, negated_l, ROUND_DOWN); 00268 lower.set(GREATER_OR_EQUAL, tmp); 00269 } 00270 00271 seq_i.build(lower, upper); 00272 } 00273 PPL_ASSERT(OK()); 00274 } 00275 00276 template <typename ITV> 00277 template <typename T> 00278 Box<ITV>::Box(const Octagonal_Shape<T>& oct, Complexity_Class) 00279 : seq(check_space_dimension_overflow(oct.space_dimension(), 00280 max_space_dimension(), 00281 "PPL::Box::", 00282 "Box(oct)", 00283 "oct exceeds the maximum " 00284 "allowed space dimension")), 00285 status() { 00286 // Expose all the interval constraints. 00287 oct.strong_closure_assign(); 00288 if (oct.marked_empty()) { 00289 set_empty(); 00290 return; 00291 } 00292 00293 // The empty flag will be meaningful, whatever happens from now on. 00294 set_empty_up_to_date(); 00295 00296 const dimension_type space_dim = space_dimension(); 00297 if (space_dim == 0) 00298 return; 00299 00300 PPL_DIRTY_TEMP(mpq_class, lower_bound); 00301 PPL_DIRTY_TEMP(mpq_class, upper_bound); 00302 for (dimension_type i = space_dim; i-- > 0; ) { 00303 typedef typename Octagonal_Shape<T>::coefficient_type Coeff; 00304 I_Constraint<mpq_class> lower; 00305 I_Constraint<mpq_class> upper; 00306 ITV& seq_i = seq[i]; 00307 const dimension_type ii = 2*i; 00308 const dimension_type cii = ii + 1; 00309 00310 // Set the upper bound. 00311 const Coeff& twice_ub = oct.matrix[cii][ii]; 00312 if (!is_plus_infinity(twice_ub)) { 00313 assign_r(upper_bound, twice_ub, ROUND_NOT_NEEDED); 00314 div_2exp_assign_r(upper_bound, upper_bound, 1, ROUND_NOT_NEEDED); 00315 upper.set(LESS_OR_EQUAL, upper_bound); 00316 } 00317 00318 // Set the lower bound. 00319 const Coeff& twice_lb = oct.matrix[ii][cii]; 00320 if (!is_plus_infinity(twice_lb)) { 00321 assign_r(lower_bound, twice_lb, ROUND_NOT_NEEDED); 00322 neg_assign_r(lower_bound, lower_bound, ROUND_NOT_NEEDED); 00323 div_2exp_assign_r(lower_bound, lower_bound, 1, ROUND_NOT_NEEDED); 00324 lower.set(GREATER_OR_EQUAL, lower_bound); 00325 } 00326 seq_i.build(lower, upper); 00327 } 00328 } 00329 00330 template <typename ITV> 00331 Box<ITV>::Box(const Polyhedron& ph, Complexity_Class complexity) 00332 : seq(check_space_dimension_overflow(ph.space_dimension(), 00333 max_space_dimension(), 00334 "PPL::Box::", 00335 "Box(ph)", 00336 "ph exceeds the maximum " 00337 "allowed space dimension")), 00338 status() { 00339 // The empty flag will be meaningful, whatever happens from now on. 00340 set_empty_up_to_date(); 00341 00342 // We do not need to bother about `complexity' if: 00343 // a) the polyhedron is already marked empty; or ... 00344 if (ph.marked_empty()) { 00345 set_empty(); 00346 return; 00347 } 00348 00349 // b) the polyhedron is zero-dimensional; or ... 00350 const dimension_type space_dim = ph.space_dimension(); 00351 if (space_dim == 0) 00352 return; 00353 00354 // c) the polyhedron is already described by a generator system. 00355 if (ph.generators_are_up_to_date() && !ph.has_pending_constraints()) { 00356 Box tmp(ph.generators()); 00357 m_swap(tmp); 00358 return; 00359 } 00360 00361 // Here generators are not up-to-date or there are pending constraints. 00362 PPL_ASSERT(ph.constraints_are_up_to_date()); 00363 00364 if (complexity == POLYNOMIAL_COMPLEXITY) { 00365 // FIXME: is there a way to avoid this initialization? 00366 for (dimension_type i = space_dim; i-- > 0; ) 00367 seq[i].assign(UNIVERSE); 00368 // Get a simplified version of the constraints. 00369 Constraint_System cs = ph.simplified_constraints(); 00370 // Propagate easy-to-find bounds from the constraints, 00371 // allowing for a limited number of iterations. 00372 // FIXME: 20 is just a wild guess. 00373 const dimension_type max_iterations = 20; 00374 propagate_constraints_no_check(cs, max_iterations); 00375 } 00376 else if (complexity == SIMPLEX_COMPLEXITY) { 00377 MIP_Problem lp(space_dim); 00378 const Constraint_System& ph_cs = ph.constraints(); 00379 if (!ph_cs.has_strict_inequalities()) 00380 lp.add_constraints(ph_cs); 00381 else 00382 // Adding to `lp' a topologically closed version of `ph_cs'. 00383 for (Constraint_System::const_iterator i = ph_cs.begin(), 00384 ph_cs_end = ph_cs.end(); i != ph_cs_end; ++i) { 00385 const Constraint& c = *i; 00386 if (c.is_strict_inequality()) 00387 lp.add_constraint(Linear_Expression(c) >= 0); 00388 else 00389 lp.add_constraint(c); 00390 } 00391 // Check for unsatisfiability. 00392 if (!lp.is_satisfiable()) { 00393 set_empty(); 00394 return; 00395 } 00396 // Get all the bounds for the space dimensions. 00397 Generator g(point()); 00398 PPL_DIRTY_TEMP(mpq_class, lower_bound); 00399 PPL_DIRTY_TEMP(mpq_class, upper_bound); 00400 PPL_DIRTY_TEMP(Coefficient, bound_numer); 00401 PPL_DIRTY_TEMP(Coefficient, bound_denom); 00402 for (dimension_type i = space_dim; i-- > 0; ) { 00403 I_Constraint<mpq_class> lower; 00404 I_Constraint<mpq_class> upper; 00405 ITV& seq_i = seq[i]; 00406 lp.set_objective_function(Variable(i)); 00407 // Evaluate upper bound. 00408 lp.set_optimization_mode(MAXIMIZATION); 00409 if (lp.solve() == OPTIMIZED_MIP_PROBLEM) { 00410 g = lp.optimizing_point(); 00411 lp.evaluate_objective_function(g, bound_numer, bound_denom); 00412 assign_r(upper_bound.get_num(), bound_numer, ROUND_NOT_NEEDED); 00413 assign_r(upper_bound.get_den(), bound_denom, ROUND_NOT_NEEDED); 00414 PPL_ASSERT(is_canonical(upper_bound)); 00415 upper.set(LESS_OR_EQUAL, upper_bound); 00416 } 00417 // Evaluate optimal lower bound. 00418 lp.set_optimization_mode(MINIMIZATION); 00419 if (lp.solve() == OPTIMIZED_MIP_PROBLEM) { 00420 g = lp.optimizing_point(); 00421 lp.evaluate_objective_function(g, bound_numer, bound_denom); 00422 assign_r(lower_bound.get_num(), bound_numer, ROUND_NOT_NEEDED); 00423 assign_r(lower_bound.get_den(), bound_denom, ROUND_NOT_NEEDED); 00424 PPL_ASSERT(is_canonical(lower_bound)); 00425 lower.set(GREATER_OR_EQUAL, lower_bound); 00426 } 00427 seq_i.build(lower, upper); 00428 } 00429 } 00430 else { 00431 PPL_ASSERT(complexity == ANY_COMPLEXITY); 00432 if (ph.is_empty()) 00433 set_empty(); 00434 else { 00435 Box tmp(ph.generators()); 00436 m_swap(tmp); 00437 } 00438 } 00439 } 00440 00441 template <typename ITV> 00442 Box<ITV>::Box(const Grid& gr, Complexity_Class) 00443 : seq(check_space_dimension_overflow(gr.space_dimension(), 00444 max_space_dimension(), 00445 "PPL::Box::", 00446 "Box(gr)", 00447 "gr exceeds the maximum " 00448 "allowed space dimension")), 00449 status() { 00450 00451 if (gr.marked_empty()) { 00452 set_empty(); 00453 return; 00454 } 00455 00456 // The empty flag will be meaningful, whatever happens from now on. 00457 set_empty_up_to_date(); 00458 00459 const dimension_type space_dim = gr.space_dimension(); 00460 00461 if (space_dim == 0) 00462 return; 00463 00464 if (!gr.generators_are_up_to_date() && !gr.update_generators()) { 00465 // Updating found the grid empty. 00466 set_empty(); 00467 return; 00468 } 00469 00470 PPL_ASSERT(!gr.gen_sys.empty()); 00471 00472 // For each dimension that is bounded by the grid, set both bounds 00473 // of the interval to the value of the associated coefficient in a 00474 // generator point. 00475 PPL_DIRTY_TEMP(mpq_class, bound); 00476 PPL_DIRTY_TEMP(Coefficient, bound_numer); 00477 PPL_DIRTY_TEMP(Coefficient, bound_denom); 00478 for (dimension_type i = space_dim; i-- > 0; ) { 00479 ITV& seq_i = seq[i]; 00480 Variable var(i); 00481 bool max; 00482 if (gr.maximize(var, bound_numer, bound_denom, max)) { 00483 assign_r(bound.get_num(), bound_numer, ROUND_NOT_NEEDED); 00484 assign_r(bound.get_den(), bound_denom, ROUND_NOT_NEEDED); 00485 bound.canonicalize(); 00486 seq_i.build(i_constraint(EQUAL, bound)); 00487 } 00488 else 00489 seq_i.assign(UNIVERSE); 00490 } 00491 } 00492 00493 template <typename ITV> 00494 template <typename D1, typename D2, typename R> 00495 Box<ITV>::Box(const Partially_Reduced_Product<D1, D2, R>& dp, 00496 Complexity_Class complexity) 00497 : seq(), status() { 00498 check_space_dimension_overflow(dp.space_dimension(), 00499 max_space_dimension(), 00500 "PPL::Box::", 00501 "Box(dp)", 00502 "dp exceeds the maximum " 00503 "allowed space dimension"); 00504 Box tmp1(dp.domain1(), complexity); 00505 Box tmp2(dp.domain2(), complexity); 00506 tmp1.intersection_assign(tmp2); 00507 m_swap(tmp1); 00508 } 00509 00510 template <typename ITV> 00511 inline void 00512 Box<ITV>::add_space_dimensions_and_embed(const dimension_type m) { 00513 // Adding no dimensions is a no-op. 00514 if (m == 0) 00515 return; 00516 check_space_dimension_overflow(m, max_space_dimension() - space_dimension(), 00517 "PPL::Box::", 00518 "add_space_dimensions_and_embed(m)", 00519 "adding m new space dimensions exceeds " 00520 "the maximum allowed space dimension"); 00521 // To embed an n-dimension space box in a (n+m)-dimension space, 00522 // we just add `m' new universe elements to the sequence. 00523 seq.insert(seq.end(), m, ITV(UNIVERSE)); 00524 PPL_ASSERT(OK()); 00525 } 00526 00527 template <typename ITV> 00528 inline void 00529 Box<ITV>::add_space_dimensions_and_project(const dimension_type m) { 00530 // Adding no dimensions is a no-op. 00531 if (m == 0) 00532 return; 00533 check_space_dimension_overflow(m, max_space_dimension() - space_dimension(), 00534 "PPL::Box::", 00535 "add_space_dimensions_and_project(m)", 00536 "adding m new space dimensions exceeds " 00537 "the maximum allowed space dimension"); 00538 // Add `m' new zero elements to the sequence. 00539 seq.insert(seq.end(), m, ITV(0)); 00540 PPL_ASSERT(OK()); 00541 } 00542 00543 template <typename ITV> 00544 bool 00545 operator==(const Box<ITV>& x, const Box<ITV>& y) { 00546 const dimension_type x_space_dim = x.space_dimension(); 00547 if (x_space_dim != y.space_dimension()) 00548 return false; 00549 00550 if (x.is_empty()) 00551 return y.is_empty(); 00552 00553 if (y.is_empty()) 00554 return x.is_empty(); 00555 00556 for (dimension_type k = x_space_dim; k-- > 0; ) 00557 if (x.seq[k] != y.seq[k]) 00558 return false; 00559 return true; 00560 } 00561 00562 template <typename ITV> 00563 bool 00564 Box<ITV>::bounds(const Linear_Expression& expr, const bool from_above) const { 00565 // `expr' should be dimension-compatible with `*this'. 00566 const dimension_type expr_space_dim = expr.space_dimension(); 00567 const dimension_type space_dim = space_dimension(); 00568 if (space_dim < expr_space_dim) 00569 throw_dimension_incompatible((from_above 00570 ? "bounds_from_above(e)" 00571 : "bounds_from_below(e)"), "e", expr); 00572 // A zero-dimensional or empty Box bounds everything. 00573 if (space_dim == 0 || is_empty()) 00574 return true; 00575 00576 const int from_above_sign = from_above ? 1 : -1; 00577 for (dimension_type i = expr_space_dim; i-- > 0; ) 00578 switch (sgn(expr.coefficient(Variable(i))) * from_above_sign) { 00579 case 1: 00580 if (seq[i].upper_is_boundary_infinity()) 00581 return false; 00582 break; 00583 case 0: 00584 // Nothing to do. 00585 break; 00586 case -1: 00587 if (seq[i].lower_is_boundary_infinity()) 00588 return false; 00589 break; 00590 } 00591 return true; 00592 } 00593 00594 template <typename ITV> 00595 Poly_Con_Relation 00596 interval_relation(const ITV& i, 00597 const Constraint::Type constraint_type, 00598 Coefficient_traits::const_reference numer, 00599 Coefficient_traits::const_reference denom) { 00600 00601 if (i.is_universe()) 00602 return Poly_Con_Relation::strictly_intersects(); 00603 00604 PPL_DIRTY_TEMP(mpq_class, bound); 00605 assign_r(bound.get_num(), numer, ROUND_NOT_NEEDED); 00606 assign_r(bound.get_den(), denom, ROUND_NOT_NEEDED); 00607 bound.canonicalize(); 00608 neg_assign_r(bound, bound, ROUND_NOT_NEEDED); 00609 const bool is_lower_bound = (denom > 0); 00610 00611 PPL_DIRTY_TEMP(mpq_class, bound_diff); 00612 if (constraint_type == Constraint::EQUALITY) { 00613 if (i.lower_is_boundary_infinity()) { 00614 PPL_ASSERT(!i.upper_is_boundary_infinity()); 00615 assign_r(bound_diff, i.upper(), ROUND_NOT_NEEDED); 00616 sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED); 00617 switch (sgn(bound_diff)) { 00618 case 1: 00619 return Poly_Con_Relation::strictly_intersects(); 00620 case 0: 00621 return i.upper_is_open() 00622 ? Poly_Con_Relation::is_disjoint() 00623 : Poly_Con_Relation::strictly_intersects(); 00624 case -1: 00625 return Poly_Con_Relation::is_disjoint(); 00626 } 00627 } 00628 else { 00629 assign_r(bound_diff, i.lower(), ROUND_NOT_NEEDED); 00630 sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED); 00631 switch (sgn(bound_diff)) { 00632 case 1: 00633 return Poly_Con_Relation::is_disjoint(); 00634 case 0: 00635 if (i.lower_is_open()) 00636 return Poly_Con_Relation::is_disjoint(); 00637 if (i.is_singleton()) 00638 return Poly_Con_Relation::is_included() 00639 && Poly_Con_Relation::saturates(); 00640 return Poly_Con_Relation::strictly_intersects(); 00641 case -1: 00642 if (i.upper_is_boundary_infinity()) 00643 return Poly_Con_Relation::strictly_intersects(); 00644 else { 00645 assign_r(bound_diff, i.upper(), ROUND_NOT_NEEDED); 00646 sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED); 00647 switch (sgn(bound_diff)) { 00648 case 1: 00649 return Poly_Con_Relation::strictly_intersects(); 00650 case 0: 00651 if (i.upper_is_open()) 00652 return Poly_Con_Relation::is_disjoint(); 00653 else 00654 return Poly_Con_Relation::strictly_intersects(); 00655 case -1: 00656 return Poly_Con_Relation::is_disjoint(); 00657 } 00658 } 00659 } 00660 } 00661 } 00662 00663 PPL_ASSERT(constraint_type != Constraint::EQUALITY); 00664 if (is_lower_bound) { 00665 if (i.lower_is_boundary_infinity()) { 00666 PPL_ASSERT(!i.upper_is_boundary_infinity()); 00667 assign_r(bound_diff, i.upper(), ROUND_NOT_NEEDED); 00668 sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED); 00669 switch (sgn(bound_diff)) { 00670 case 1: 00671 return Poly_Con_Relation::strictly_intersects(); 00672 case 0: 00673 if (constraint_type == Constraint::STRICT_INEQUALITY 00674 || i.upper_is_open()) 00675 return Poly_Con_Relation::is_disjoint(); 00676 else 00677 return Poly_Con_Relation::strictly_intersects(); 00678 case -1: 00679 return Poly_Con_Relation::is_disjoint(); 00680 } 00681 } 00682 else { 00683 assign_r(bound_diff, i.lower(), ROUND_NOT_NEEDED); 00684 sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED); 00685 switch (sgn(bound_diff)) { 00686 case 1: 00687 return Poly_Con_Relation::is_included(); 00688 case 0: 00689 if (constraint_type == Constraint::NONSTRICT_INEQUALITY 00690 || i.lower_is_open()) { 00691 Poly_Con_Relation result = Poly_Con_Relation::is_included(); 00692 if (i.is_singleton()) 00693 result = result && Poly_Con_Relation::saturates(); 00694 return result; 00695 } 00696 else { 00697 PPL_ASSERT(constraint_type == Constraint::STRICT_INEQUALITY 00698 && !i.lower_is_open()); 00699 if (i.is_singleton()) 00700 return Poly_Con_Relation::is_disjoint() 00701 && Poly_Con_Relation::saturates(); 00702 else 00703 return Poly_Con_Relation::strictly_intersects(); 00704 } 00705 case -1: 00706 if (i.upper_is_boundary_infinity()) 00707 return Poly_Con_Relation::strictly_intersects(); 00708 else { 00709 assign_r(bound_diff, i.upper(), ROUND_NOT_NEEDED); 00710 sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED); 00711 switch (sgn(bound_diff)) { 00712 case 1: 00713 return Poly_Con_Relation::strictly_intersects(); 00714 case 0: 00715 if (constraint_type == Constraint::STRICT_INEQUALITY 00716 || i.upper_is_open()) 00717 return Poly_Con_Relation::is_disjoint(); 00718 else 00719 return Poly_Con_Relation::strictly_intersects(); 00720 case -1: 00721 return Poly_Con_Relation::is_disjoint(); 00722 } 00723 } 00724 } 00725 } 00726 } 00727 else { 00728 // `c' is an upper bound. 00729 if (i.upper_is_boundary_infinity()) 00730 return Poly_Con_Relation::strictly_intersects(); 00731 else { 00732 assign_r(bound_diff, i.upper(), ROUND_NOT_NEEDED); 00733 sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED); 00734 switch (sgn(bound_diff)) { 00735 case -1: 00736 return Poly_Con_Relation::is_included(); 00737 case 0: 00738 if (constraint_type == Constraint::NONSTRICT_INEQUALITY 00739 || i.upper_is_open()) { 00740 Poly_Con_Relation result = Poly_Con_Relation::is_included(); 00741 if (i.is_singleton()) 00742 result = result && Poly_Con_Relation::saturates(); 00743 return result; 00744 } 00745 else { 00746 PPL_ASSERT(constraint_type == Constraint::STRICT_INEQUALITY 00747 && !i.upper_is_open()); 00748 if (i.is_singleton()) 00749 return Poly_Con_Relation::is_disjoint() 00750 && Poly_Con_Relation::saturates(); 00751 else 00752 return Poly_Con_Relation::strictly_intersects(); 00753 } 00754 case 1: 00755 if (i.lower_is_boundary_infinity()) 00756 return Poly_Con_Relation::strictly_intersects(); 00757 else { 00758 assign_r(bound_diff, i.lower(), ROUND_NOT_NEEDED); 00759 sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED); 00760 switch (sgn(bound_diff)) { 00761 case -1: 00762 return Poly_Con_Relation::strictly_intersects(); 00763 case 0: 00764 if (constraint_type == Constraint::STRICT_INEQUALITY 00765 || i.lower_is_open()) 00766 return Poly_Con_Relation::is_disjoint(); 00767 else 00768 return Poly_Con_Relation::strictly_intersects(); 00769 case 1: 00770 return Poly_Con_Relation::is_disjoint(); 00771 } 00772 } 00773 } 00774 } 00775 } 00776 00777 // Quiet a compiler warning: this program point is unreachable. 00778 PPL_UNREACHABLE; 00779 return Poly_Con_Relation::nothing(); 00780 } 00781 00782 template <typename ITV> 00783 Poly_Con_Relation 00784 Box<ITV>::relation_with(const Congruence& cg) const { 00785 const dimension_type cg_space_dim = cg.space_dimension(); 00786 const dimension_type space_dim = space_dimension(); 00787 00788 // Dimension-compatibility check. 00789 if (cg_space_dim > space_dim) 00790 throw_dimension_incompatible("relation_with(cg)", cg); 00791 00792 if (is_empty()) 00793 return Poly_Con_Relation::saturates() 00794 && Poly_Con_Relation::is_included() 00795 && Poly_Con_Relation::is_disjoint(); 00796 00797 if (space_dim == 0) { 00798 if (cg.is_inconsistent()) 00799 return Poly_Con_Relation::is_disjoint(); 00800 else 00801 return Poly_Con_Relation::saturates() 00802 && Poly_Con_Relation::is_included(); 00803 } 00804 00805 if (cg.is_equality()) { 00806 const Constraint c(cg); 00807 return relation_with(c); 00808 } 00809 00810 PPL_DIRTY_TEMP(Rational_Interval, r); 00811 PPL_DIRTY_TEMP(Rational_Interval, t); 00812 PPL_DIRTY_TEMP(mpq_class, m); 00813 r = 0; 00814 for (dimension_type i = cg.space_dimension(); i-- > 0; ) { 00815 const Coefficient& cg_i = cg.coefficient(Variable(i)); 00816 if (sgn(cg_i) != 0) { 00817 assign_r(m, cg_i, ROUND_NOT_NEEDED); 00818 // FIXME: an add_mul_assign() method would come handy here. 00819 t.build(seq[i].lower_constraint(), seq[i].upper_constraint()); 00820 t *= m; 00821 r += t; 00822 } 00823 } 00824 00825 if (r.lower_is_boundary_infinity() || r.upper_is_boundary_infinity()) 00826 return Poly_Con_Relation::strictly_intersects(); 00827 00828 00829 // Find the value that satisfies the congruence and is 00830 // nearest to the lower bound such that the point lies on or above it. 00831 00832 PPL_DIRTY_TEMP_COEFFICIENT(lower); 00833 PPL_DIRTY_TEMP_COEFFICIENT(mod); 00834 PPL_DIRTY_TEMP_COEFFICIENT(v); 00835 mod = cg.modulus(); 00836 v = cg.inhomogeneous_term() % mod; 00837 assign_r(lower, r.lower(), ROUND_DOWN); 00838 v -= ((lower / mod) * mod); 00839 if (v + lower > 0) 00840 v -= mod; 00841 return interval_relation(r, Constraint::EQUALITY, v); 00842 } 00843 00844 template <typename ITV> 00845 Poly_Con_Relation 00846 Box<ITV>::relation_with(const Constraint& c) const { 00847 const dimension_type c_space_dim = c.space_dimension(); 00848 const dimension_type space_dim = space_dimension(); 00849 00850 // Dimension-compatibility check. 00851 if (c_space_dim > space_dim) 00852 throw_dimension_incompatible("relation_with(c)", c); 00853 00854 if (is_empty()) 00855 return Poly_Con_Relation::saturates() 00856 && Poly_Con_Relation::is_included() 00857 && Poly_Con_Relation::is_disjoint(); 00858 00859 if (space_dim == 0) { 00860 if ((c.is_equality() && c.inhomogeneous_term() != 0) 00861 || (c.is_inequality() && c.inhomogeneous_term() < 0)) 00862 return Poly_Con_Relation::is_disjoint(); 00863 else if (c.is_strict_inequality() && c.inhomogeneous_term() == 0) 00864 // The constraint 0 > 0 implicitly defines the hyperplane 0 = 0; 00865 // thus, the zero-dimensional point also saturates it. 00866 return Poly_Con_Relation::saturates() 00867 && Poly_Con_Relation::is_disjoint(); 00868 else if (c.is_equality() || c.inhomogeneous_term() == 0) 00869 return Poly_Con_Relation::saturates() 00870 && Poly_Con_Relation::is_included(); 00871 else 00872 // The zero-dimensional point saturates 00873 // neither the positivity constraint 1 >= 0, 00874 // nor the strict positivity constraint 1 > 0. 00875 return Poly_Con_Relation::is_included(); 00876 } 00877 00878 dimension_type c_num_vars = 0; 00879 dimension_type c_only_var = 0; 00880 00881 if (extract_interval_constraint(c, c_space_dim, c_num_vars, c_only_var)) 00882 if (c_num_vars == 0) 00883 // c is a trivial constraint. 00884 switch (sgn(c.inhomogeneous_term())) { 00885 case -1: 00886 return Poly_Con_Relation::is_disjoint(); 00887 case 0: 00888 if (c.is_strict_inequality()) 00889 return Poly_Con_Relation::saturates() 00890 && Poly_Con_Relation::is_disjoint(); 00891 else 00892 return Poly_Con_Relation::saturates() 00893 && Poly_Con_Relation::is_included(); 00894 case 1: 00895 return Poly_Con_Relation::is_included(); 00896 } 00897 else { 00898 // c is an interval constraint. 00899 return interval_relation(seq[c_only_var], 00900 c.type(), 00901 c.inhomogeneous_term(), 00902 c.coefficient(Variable(c_only_var))); 00903 } 00904 else { 00905 // Deal with a non-trivial and non-interval constraint. 00906 PPL_DIRTY_TEMP(Rational_Interval, r); 00907 PPL_DIRTY_TEMP(Rational_Interval, t); 00908 PPL_DIRTY_TEMP(mpq_class, m); 00909 r = 0; 00910 for (dimension_type i = c.space_dimension(); i-- > 0; ) { 00911 const Coefficient& c_i = c.coefficient(Variable(i)); 00912 if (sgn(c_i) != 0) { 00913 assign_r(m, c_i, ROUND_NOT_NEEDED); 00914 // FIXME: an add_mul_assign() method would come handy here. 00915 t.build(seq[i].lower_constraint(), seq[i].upper_constraint()); 00916 t *= m; 00917 r += t; 00918 } 00919 } 00920 return interval_relation(r, 00921 c.type(), 00922 c.inhomogeneous_term()); 00923 } 00924 00925 // Quiet a compiler warning: this program point is unreachable. 00926 PPL_UNREACHABLE; 00927 return Poly_Con_Relation::nothing(); 00928 } 00929 00930 template <typename ITV> 00931 Poly_Gen_Relation 00932 Box<ITV>::relation_with(const Generator& g) const { 00933 const dimension_type space_dim = space_dimension(); 00934 const dimension_type g_space_dim = g.space_dimension(); 00935 00936 // Dimension-compatibility check. 00937 if (space_dim < g_space_dim) 00938 throw_dimension_incompatible("relation_with(g)", g); 00939 00940 // The empty box cannot subsume a generator. 00941 if (is_empty()) 00942 return Poly_Gen_Relation::nothing(); 00943 00944 // A universe box in a zero-dimensional space subsumes 00945 // all the generators of a zero-dimensional space. 00946 if (space_dim == 0) 00947 return Poly_Gen_Relation::subsumes(); 00948 00949 if (g.is_line_or_ray()) { 00950 if (g.is_line()) { 00951 for (dimension_type i = g_space_dim; i-- > 0; ) 00952 if (g.coefficient(Variable(i)) != 0 && !seq[i].is_universe()) 00953 return Poly_Gen_Relation::nothing(); 00954 return Poly_Gen_Relation::subsumes(); 00955 } 00956 else { 00957 PPL_ASSERT(g.is_ray()); 00958 for (dimension_type i = g_space_dim; i-- > 0; ) 00959 switch (sgn(g.coefficient(Variable(i)))) { 00960 case 1: 00961 if (!seq[i].upper_is_boundary_infinity()) 00962 return Poly_Gen_Relation::nothing(); 00963 break; 00964 case 0: 00965 break; 00966 case -1: 00967 if (!seq[i].lower_is_boundary_infinity()) 00968 return Poly_Gen_Relation::nothing(); 00969 break; 00970 } 00971 return Poly_Gen_Relation::subsumes(); 00972 } 00973 } 00974 00975 // Here `g' is a point or closure point. 00976 const Coefficient& g_divisor = g.divisor(); 00977 PPL_DIRTY_TEMP(mpq_class, g_coord); 00978 PPL_DIRTY_TEMP(mpq_class, bound); 00979 for (dimension_type i = g_space_dim; i-- > 0; ) { 00980 const ITV& seq_i = seq[i]; 00981 if (seq_i.is_universe()) 00982 continue; 00983 assign_r(g_coord.get_num(), g.coefficient(Variable(i)), ROUND_NOT_NEEDED); 00984 assign_r(g_coord.get_den(), g_divisor, ROUND_NOT_NEEDED); 00985 g_coord.canonicalize(); 00986 // Check lower bound. 00987 if (!seq_i.lower_is_boundary_infinity()) { 00988 assign_r(bound, seq_i.lower(), ROUND_NOT_NEEDED); 00989 if (g_coord <= bound) { 00990 if (seq_i.lower_is_open()) { 00991 if (g.is_point() || g_coord != bound) 00992 return Poly_Gen_Relation::nothing(); 00993 } 00994 else if (g_coord != bound) 00995 return Poly_Gen_Relation::nothing(); 00996 } 00997 } 00998 // Check upper bound. 00999 if (!seq_i.upper_is_boundary_infinity()) { 01000 assign_r(bound, seq_i.upper(), ROUND_NOT_NEEDED); 01001 if (g_coord >= bound) { 01002 if (seq_i.upper_is_open()) { 01003 if (g.is_point() || g_coord != bound) 01004 return Poly_Gen_Relation::nothing(); 01005 } 01006 else if (g_coord != bound) 01007 return Poly_Gen_Relation::nothing(); 01008 } 01009 } 01010 } 01011 return Poly_Gen_Relation::subsumes(); 01012 } 01013 01014 01015 template <typename ITV> 01016 bool 01017 Box<ITV>::max_min(const Linear_Expression& expr, 01018 const bool maximize, 01019 Coefficient& ext_n, Coefficient& ext_d, 01020 bool& included) const { 01021 // `expr' should be dimension-compatible with `*this'. 01022 const dimension_type space_dim = space_dimension(); 01023 const dimension_type expr_space_dim = expr.space_dimension(); 01024 if (space_dim < expr_space_dim) 01025 throw_dimension_incompatible((maximize 01026 ? "maximize(e, ...)" 01027 : "minimize(e, ...)"), "e", expr); 01028 // Deal with zero-dim Box first. 01029 if (space_dim == 0) { 01030 if (marked_empty()) 01031 return false; 01032 else { 01033 ext_n = expr.inhomogeneous_term(); 01034 ext_d = 1; 01035 included = true; 01036 return true; 01037 } 01038 } 01039 01040 // For an empty Box we simply return false. 01041 if (is_empty()) 01042 return false; 01043 01044 PPL_DIRTY_TEMP(mpq_class, result); 01045 assign_r(result, expr.inhomogeneous_term(), ROUND_NOT_NEEDED); 01046 bool is_included = true; 01047 const int maximize_sign = maximize ? 1 : -1; 01048 PPL_DIRTY_TEMP(mpq_class, bound_i); 01049 PPL_DIRTY_TEMP(mpq_class, expr_i); 01050 for (dimension_type i = expr_space_dim; i-- > 0; ) { 01051 const ITV& seq_i = seq[i]; 01052 assign_r(expr_i, expr.coefficient(Variable(i)), ROUND_NOT_NEEDED); 01053 switch (sgn(expr_i) * maximize_sign) { 01054 case 1: 01055 if (seq_i.upper_is_boundary_infinity()) 01056 return false; 01057 assign_r(bound_i, seq_i.upper(), ROUND_NOT_NEEDED); 01058 add_mul_assign_r(result, bound_i, expr_i, ROUND_NOT_NEEDED); 01059 if (seq_i.upper_is_open()) 01060 is_included = false; 01061 break; 01062 case 0: 01063 // Nothing to do. 01064 break; 01065 case -1: 01066 if (seq_i.lower_is_boundary_infinity()) 01067 return false; 01068 assign_r(bound_i, seq_i.lower(), ROUND_NOT_NEEDED); 01069 add_mul_assign_r(result, bound_i, expr_i, ROUND_NOT_NEEDED); 01070 if (seq_i.lower_is_open()) 01071 is_included = false; 01072 break; 01073 } 01074 } 01075 // Extract output info. 01076 PPL_ASSERT(is_canonical(result)); 01077 ext_n = result.get_num(); 01078 ext_d = result.get_den(); 01079 included = is_included; 01080 return true; 01081 } 01082 01083 template <typename ITV> 01084 bool 01085 Box<ITV>::max_min(const Linear_Expression& expr, 01086 const bool maximize, 01087 Coefficient& ext_n, Coefficient& ext_d, 01088 bool& included, 01089 Generator& g) const { 01090 if (!max_min(expr, maximize, ext_n, ext_d, included)) 01091 return false; 01092 01093 // Compute generator `g'. 01094 Linear_Expression g_expr; 01095 PPL_DIRTY_TEMP(Coefficient, g_divisor); 01096 g_divisor = 1; 01097 const int maximize_sign = maximize ? 1 : -1; 01098 PPL_DIRTY_TEMP(mpq_class, g_coord); 01099 PPL_DIRTY_TEMP(Coefficient, numer); 01100 PPL_DIRTY_TEMP(Coefficient, denom); 01101 PPL_DIRTY_TEMP(Coefficient, lcm); 01102 PPL_DIRTY_TEMP(Coefficient, factor); 01103 for (dimension_type i = space_dimension(); i-- > 0; ) { 01104 const ITV& seq_i = seq[i]; 01105 switch (sgn(expr.coefficient(Variable(i))) * maximize_sign) { 01106 case 1: 01107 assign_r(g_coord, seq_i.upper(), ROUND_NOT_NEEDED); 01108 break; 01109 case 0: 01110 // If 0 belongs to the interval, choose it 01111 // (and directly proceed to the next iteration). 01112 // FIXME: name qualification issue. 01113 if (seq_i.contains(0)) 01114 continue; 01115 if (!seq_i.lower_is_boundary_infinity()) 01116 if (seq_i.lower_is_open()) 01117 if (!seq_i.upper_is_boundary_infinity()) 01118 if (seq_i.upper_is_open()) { 01119 // Bounded and open interval: compute middle point. 01120 assign_r(g_coord, seq_i.lower(), ROUND_NOT_NEEDED); 01121 PPL_DIRTY_TEMP(mpq_class, q_seq_i_upper); 01122 assign_r(q_seq_i_upper, seq_i.upper(), ROUND_NOT_NEEDED); 01123 g_coord += q_seq_i_upper; 01124 g_coord /= 2; 01125 } 01126 else 01127 // The upper bound is in the interval. 01128 assign_r(g_coord, seq_i.upper(), ROUND_NOT_NEEDED); 01129 else { 01130 // Lower is open, upper is unbounded. 01131 assign_r(g_coord, seq_i.lower(), ROUND_NOT_NEEDED); 01132 ++g_coord; 01133 } 01134 else 01135 // The lower bound is in the interval. 01136 assign_r(g_coord, seq_i.lower(), ROUND_NOT_NEEDED); 01137 else { 01138 // Lower is unbounded, hence upper is bounded 01139 // (since we know that 0 does not belong to the interval). 01140 PPL_ASSERT(!seq_i.upper_is_boundary_infinity()); 01141 assign_r(g_coord, seq_i.upper(), ROUND_NOT_NEEDED); 01142 if (seq_i.upper_is_open()) 01143 --g_coord; 01144 } 01145 break; 01146 case -1: 01147 assign_r(g_coord, seq_i.lower(), ROUND_NOT_NEEDED); 01148 break; 01149 } 01150 // Add g_coord * Variable(i) to the generator. 01151 assign_r(denom, g_coord.get_den(), ROUND_NOT_NEEDED); 01152 lcm_assign(lcm, g_divisor, denom); 01153 exact_div_assign(factor, lcm, g_divisor); 01154 g_expr *= factor; 01155 exact_div_assign(factor, lcm, denom); 01156 assign_r(numer, g_coord.get_num(), ROUND_NOT_NEEDED); 01157 numer *= factor; 01158 g_expr += numer * Variable(i); 01159 g_divisor = lcm; 01160 } 01161 g = Generator::point(g_expr, g_divisor); 01162 return true; 01163 } 01164 01165 template <typename ITV> 01166 bool 01167 Box<ITV>::contains(const Box& y) const { 01168 const Box& x = *this; 01169 // Dimension-compatibility check. 01170 if (x.space_dimension() != y.space_dimension()) 01171 x.throw_dimension_incompatible("contains(y)", y); 01172 01173 // If `y' is empty, then `x' contains `y'. 01174 if (y.is_empty()) 01175 return true; 01176 01177 // If `x' is empty, then `x' cannot contain `y'. 01178 if (x.is_empty()) 01179 return false; 01180 01181 for (dimension_type k = x.seq.size(); k-- > 0; ) 01182 // FIXME: fix this name qualification issue. 01183 if (!x.seq[k].contains(y.seq[k])) 01184 return false; 01185 return true; 01186 } 01187 01188 template <typename ITV> 01189 bool 01190 Box<ITV>::is_disjoint_from(const Box& y) const { 01191 const Box& x = *this; 01192 // Dimension-compatibility check. 01193 if (x.space_dimension() != y.space_dimension()) 01194 x.throw_dimension_incompatible("is_disjoint_from(y)", y); 01195 01196 // If any of `x' or `y' is marked empty, then they are disjoint. 01197 // Note: no need to use `is_empty', as the following loop is anyway correct. 01198 if (x.marked_empty() || y.marked_empty()) 01199 return true; 01200 01201 for (dimension_type k = x.seq.size(); k-- > 0; ) 01202 // FIXME: fix this name qualification issue. 01203 if (x.seq[k].is_disjoint_from(y.seq[k])) 01204 return true; 01205 return false; 01206 } 01207 01208 template <typename ITV> 01209 inline bool 01210 Box<ITV>::upper_bound_assign_if_exact(const Box& y) { 01211 Box& x = *this; 01212 01213 // Dimension-compatibility check. 01214 if (x.space_dimension() != y.space_dimension()) 01215 x.throw_dimension_incompatible("upper_bound_assign_if_exact(y)", y); 01216 01217 // The lub of a box with an empty box is equal to the first box. 01218 if (y.is_empty()) 01219 return true; 01220 if (x.is_empty()) { 01221 x = y; 01222 return true; 01223 } 01224 01225 bool x_j_does_not_contain_y_j = false; 01226 bool y_j_does_not_contain_x_j = false; 01227 01228 for (dimension_type i = x.seq.size(); i-- > 0; ) { 01229 const ITV& x_seq_i = x.seq[i]; 01230 const ITV& y_seq_i = y.seq[i]; 01231 01232 if (!x_seq_i.can_be_exactly_joined_to(y_seq_i)) 01233 return false; 01234 01235 // Note: the use of `y_i_does_not_contain_x_i' is needed 01236 // because we want to temporarily preserve the old value 01237 // of `y_j_does_not_contain_x_j'. 01238 bool y_i_does_not_contain_x_i = !y_seq_i.contains(x_seq_i); 01239 if (y_i_does_not_contain_x_i && x_j_does_not_contain_y_j) 01240 return false; 01241 if (!x_seq_i.contains(y_seq_i)) { 01242 if (y_j_does_not_contain_x_j) 01243 return false; 01244 else 01245 x_j_does_not_contain_y_j = true; 01246 } 01247 if (y_i_does_not_contain_x_i) 01248 y_j_does_not_contain_x_j = true; 01249 } 01250 01251 // The upper bound is exact: compute it into *this. 01252 for (dimension_type k = x.seq.size(); k-- > 0; ) 01253 x.seq[k].join_assign(y.seq[k]); 01254 return true; 01255 } 01256 01257 template <typename ITV> 01258 bool 01259 Box<ITV>::OK() const { 01260 if (status.test_empty_up_to_date() && !status.test_empty()) { 01261 Box tmp = *this; 01262 tmp.reset_empty_up_to_date(); 01263 if (tmp.check_empty()) { 01264 #ifndef NDEBUG 01265 std::cerr << "The box is empty, but it is marked as non-empty." 01266 << std::endl; 01267 #endif // NDEBUG 01268 return false; 01269 } 01270 } 01271 01272 // A box that is not marked empty must have meaningful intervals. 01273 if (!marked_empty()) { 01274 for (dimension_type k = seq.size(); k-- > 0; ) 01275 if (!seq[k].OK()) 01276 return false; 01277 } 01278 01279 return true; 01280 } 01281 01282 template <typename ITV> 01283 dimension_type 01284 Box<ITV>::affine_dimension() const { 01285 dimension_type d = space_dimension(); 01286 // A zero-space-dim box always has affine dimension zero. 01287 if (d == 0) 01288 return 0; 01289 01290 // An empty box has affine dimension zero. 01291 if (is_empty()) 01292 return 0; 01293 01294 for (dimension_type k = d; k-- > 0; ) 01295 if (seq[k].is_singleton()) 01296 --d; 01297 01298 return d; 01299 } 01300 01301 template <typename ITV> 01302 bool 01303 Box<ITV>::check_empty() const { 01304 PPL_ASSERT(!marked_empty()); 01305 Box<ITV>& x = const_cast<Box<ITV>&>(*this); 01306 for (dimension_type k = seq.size(); k-- > 0; ) 01307 if (seq[k].is_empty()) { 01308 x.set_empty(); 01309 return true; 01310 } 01311 x.set_nonempty(); 01312 return false; 01313 } 01314 01315 template <typename ITV> 01316 bool 01317 Box<ITV>::is_universe() const { 01318 if (marked_empty()) 01319 return false; 01320 for (dimension_type k = seq.size(); k-- > 0; ) 01321 if (!seq[k].is_universe()) 01322 return false; 01323 return true; 01324 } 01325 01326 template <typename ITV> 01327 bool 01328 Box<ITV>::is_topologically_closed() const { 01329 if (ITV::is_always_topologically_closed() || is_empty()) 01330 return true; 01331 01332 for (dimension_type k = seq.size(); k-- > 0; ) 01333 if (!seq[k].is_topologically_closed()) 01334 return false; 01335 return true; 01336 } 01337 01338 template <typename ITV> 01339 bool 01340 Box<ITV>::is_discrete() const { 01341 if (is_empty()) 01342 return true; 01343 for (dimension_type k = seq.size(); k-- > 0; ) 01344 if (!seq[k].is_singleton()) 01345 return false; 01346 return true; 01347 } 01348 01349 template <typename ITV> 01350 bool 01351 Box<ITV>::is_bounded() const { 01352 if (is_empty()) 01353 return true; 01354 for (dimension_type k = seq.size(); k-- > 0; ) 01355 if (!seq[k].is_bounded()) 01356 return false; 01357 return true; 01358 } 01359 01360 template <typename ITV> 01361 bool 01362 Box<ITV>::contains_integer_point() const { 01363 if (marked_empty()) 01364 return false; 01365 for (dimension_type k = seq.size(); k-- > 0; ) 01366 if (!seq[k].contains_integer_point()) 01367 return false; 01368 return true; 01369 } 01370 01371 template <typename ITV> 01372 bool 01373 Box<ITV>::frequency(const Linear_Expression& expr, 01374 Coefficient& freq_n, Coefficient& freq_d, 01375 Coefficient& val_n, Coefficient& val_d) const { 01376 dimension_type space_dim = space_dimension(); 01377 // The dimension of `expr' must be at most the dimension of *this. 01378 if (space_dim < expr.space_dimension()) 01379 throw_dimension_incompatible("frequency(e, ...)", "e", expr); 01380 01381 // Check if `expr' has a constant value. 01382 // If it is constant, set the frequency `freq_n' to 0 01383 // and return true. Otherwise the values for \p expr 01384 // are not discrete so return false. 01385 01386 // Space dimension is 0: if empty, then return false; 01387 // otherwise the frequency is 0 and the value is the inhomogeneous term. 01388 if (space_dim == 0) { 01389 if (is_empty()) 01390 return false; 01391 freq_n = 0; 01392 freq_d = 1; 01393 val_n = expr.inhomogeneous_term(); 01394 val_d = 1; 01395 return true; 01396 } 01397 01398 // For an empty Box, we simply return false. 01399 if (is_empty()) 01400 return false; 01401 01402 // The Box has at least 1 dimension and is not empty. 01403 PPL_DIRTY_TEMP_COEFFICIENT(coeff); 01404 PPL_DIRTY_TEMP_COEFFICIENT(numer); 01405 PPL_DIRTY_TEMP_COEFFICIENT(denom); 01406 PPL_DIRTY_TEMP(mpq_class, tmp); 01407 Linear_Expression le = expr; 01408 01409 PPL_DIRTY_TEMP_COEFFICIENT(val_denom); 01410 val_denom = 1; 01411 01412 for (dimension_type i = space_dim; i-- > 0; ) { 01413 const Variable v(i); 01414 coeff = le.coefficient(v); 01415 if (coeff == 0) { 01416 continue; 01417 } 01418 01419 const ITV& seq_i = seq[i]; 01420 // Check if `v' is constant in the BD shape. 01421 if (seq_i.is_singleton()) { 01422 // If `v' is constant, replace it in `le' by the value. 01423 assign_r(tmp, seq_i.lower(), ROUND_NOT_NEEDED); 01424 numer = tmp.get_num(); 01425 denom = tmp.get_den(); 01426 le -= coeff*v; 01427 le *= denom; 01428 le += numer*coeff; 01429 val_denom *= denom; 01430 continue; 01431 } 01432 // The expression `expr' is not constant. 01433 return false; 01434 } 01435 01436 // The expression `expr' is constant. 01437 freq_n = 0; 01438 freq_d = 1; 01439 01440 // Reduce `val_n' and `val_d'. 01441 normalize2(le.inhomogeneous_term(), val_denom, val_n, val_d); 01442 return true; 01443 } 01444 01445 template <typename ITV> 01446 bool 01447 Box<ITV>::constrains(Variable var) const { 01448 // `var' should be one of the dimensions of the polyhedron. 01449 const dimension_type var_space_dim = var.space_dimension(); 01450 if (space_dimension() < var_space_dim) 01451 throw_dimension_incompatible("constrains(v)", "v", var); 01452 01453 if (marked_empty() || !seq[var_space_dim-1].is_universe()) 01454 return true; 01455 // Now force an emptiness check. 01456 return is_empty(); 01457 } 01458 01459 template <typename ITV> 01460 void 01461 Box<ITV>::unconstrain(const Variables_Set& vars) { 01462 // The cylindrification with respect to no dimensions is a no-op. 01463 // This case also captures the only legal cylindrification 01464 // of a box in a 0-dim space. 01465 if (vars.empty()) 01466 return; 01467 01468 // Dimension-compatibility check. 01469 const dimension_type min_space_dim = vars.space_dimension(); 01470 if (space_dimension() < min_space_dim) 01471 throw_dimension_incompatible("unconstrain(vs)", min_space_dim); 01472 01473 // If the box is already empty, there is nothing left to do. 01474 if (marked_empty()) 01475 return; 01476 01477 // Here the box might still be empty (but we haven't detected it yet): 01478 // check emptiness of the interval for each of the variables in 01479 // `vars' before cylindrification. 01480 for (Variables_Set::const_iterator vsi = vars.begin(), 01481 vsi_end = vars.end(); vsi != vsi_end; ++vsi) { 01482 ITV& seq_vsi = seq[*vsi]; 01483 if (!seq_vsi.is_empty()) 01484 seq_vsi.assign(UNIVERSE); 01485 else { 01486 set_empty(); 01487 break; 01488 } 01489 } 01490 PPL_ASSERT(OK()); 01491 } 01492 01493 template <typename ITV> 01494 void 01495 Box<ITV>::topological_closure_assign() { 01496 if (ITV::is_always_topologically_closed() || is_empty()) 01497 return; 01498 01499 for (dimension_type k = seq.size(); k-- > 0; ) 01500 seq[k].topological_closure_assign(); 01501 } 01502 01503 template <typename ITV> 01504 void 01505 Box<ITV>::wrap_assign(const Variables_Set& vars, 01506 Bounded_Integer_Type_Width w, 01507 Bounded_Integer_Type_Representation r, 01508 Bounded_Integer_Type_Overflow o, 01509 const Constraint_System* cs_p, 01510 unsigned complexity_threshold, 01511 bool wrap_individually) { 01512 #if 0 // Generic implementation commented out. 01513 Implementation::wrap_assign(*this, 01514 vars, w, r, o, cs_p, 01515 complexity_threshold, wrap_individually, 01516 "Box"); 01517 #else // Specialized implementation. 01518 PPL_USED(wrap_individually); 01519 PPL_USED(complexity_threshold); 01520 Box& x = *this; 01521 01522 // Dimension-compatibility check for `*cs_p', if any. 01523 const dimension_type vars_space_dim = vars.space_dimension(); 01524 if (cs_p != 0 && cs_p->space_dimension() > vars_space_dim) { 01525 std::ostringstream s; 01526 s << "PPL::Box<ITV>::wrap_assign(vars, w, r, o, cs_p, ...):" 01527 << std::endl 01528 << "vars.space_dimension() == " << vars_space_dim 01529 << ", cs_p->space_dimension() == " << cs_p->space_dimension() << "."; 01530 throw std::invalid_argument(s.str()); 01531 } 01532 01533 // Wrapping no variable only requires refining with *cs_p, if any. 01534 if (vars.empty()) { 01535 if (cs_p != 0) 01536 refine_with_constraints(*cs_p); 01537 return; 01538 } 01539 01540 // Dimension-compatibility check for `vars'. 01541 const dimension_type space_dim = x.space_dimension(); 01542 if (space_dim < vars_space_dim) { 01543 std::ostringstream s; 01544 s << "PPL::Box<ITV>::wrap_assign(vars, ...):" 01545 << std::endl 01546 << "this->space_dimension() == " << space_dim 01547 << ", required space dimension == " << vars_space_dim << "."; 01548 throw std::invalid_argument(s.str()); 01549 } 01550 01551 // Wrapping an empty polyhedron is a no-op. 01552 if (x.is_empty()) 01553 return; 01554 01555 // FIXME: temporarily (ab-) using Coefficient. 01556 // Set `min_value' and `max_value' to the minimum and maximum values 01557 // a variable of width `w' and signedness `s' can take. 01558 PPL_DIRTY_TEMP_COEFFICIENT(min_value); 01559 PPL_DIRTY_TEMP_COEFFICIENT(max_value); 01560 if (r == UNSIGNED) { 01561 min_value = 0; 01562 mul_2exp_assign(max_value, Coefficient_one(), w); 01563 --max_value; 01564 } 01565 else { 01566 PPL_ASSERT(r == SIGNED_2_COMPLEMENT); 01567 mul_2exp_assign(max_value, Coefficient_one(), w-1); 01568 neg_assign(min_value, max_value); 01569 --max_value; 01570 } 01571 01572 // FIXME: Build the (integer) quadrant interval. 01573 PPL_DIRTY_TEMP(ITV, integer_quadrant_itv); 01574 PPL_DIRTY_TEMP(ITV, rational_quadrant_itv); 01575 { 01576 I_Constraint<Coefficient> lower = i_constraint(GREATER_OR_EQUAL, min_value); 01577 I_Constraint<Coefficient> upper = i_constraint(LESS_OR_EQUAL, max_value); 01578 integer_quadrant_itv.build(lower, upper); 01579 // The rational quadrant is only needed if overflow is undefined. 01580 if (o == OVERFLOW_UNDEFINED) { 01581 ++max_value; 01582 upper = i_constraint(LESS_THAN, max_value); 01583 rational_quadrant_itv.build(lower, upper); 01584 } 01585 } 01586 01587 const Variables_Set::const_iterator vs_end = vars.end(); 01588 01589 if (cs_p == 0) { 01590 // No constraint refinement is needed here. 01591 switch (o) { 01592 case OVERFLOW_WRAPS: 01593 for (Variables_Set::const_iterator i = vars.begin(); i != vs_end; ++i) 01594 x.seq[*i].wrap_assign(w, r, integer_quadrant_itv); 01595 reset_empty_up_to_date(); 01596 break; 01597 case OVERFLOW_UNDEFINED: 01598 for (Variables_Set::const_iterator i = vars.begin(); i != vs_end; ++i) { 01599 ITV& x_seq_v = x.seq[*i]; 01600 if (!rational_quadrant_itv.contains(x_seq_v)) { 01601 x_seq_v.assign(integer_quadrant_itv); 01602 } 01603 } 01604 break; 01605 case OVERFLOW_IMPOSSIBLE: 01606 for (Variables_Set::const_iterator i = vars.begin(); i != vs_end; ++i) 01607 x.seq[*i].intersect_assign(integer_quadrant_itv); 01608 reset_empty_up_to_date(); 01609 break; 01610 } 01611 PPL_ASSERT(x.OK()); 01612 return; 01613 } 01614 01615 PPL_ASSERT(cs_p != 0); 01616 const Constraint_System& cs = *cs_p; 01617 const dimension_type cs_space_dim = cs.space_dimension(); 01618 // A map associating interval constraints to variable indexes. 01619 typedef std::map<dimension_type, std::vector<const Constraint*> > map_type; 01620 map_type var_cs_map; 01621 for (Constraint_System::const_iterator i = cs.begin(), 01622 i_end = cs.end(); i != i_end; ++i) { 01623 const Constraint& c = *i; 01624 dimension_type c_num_vars = 0; 01625 dimension_type c_only_var = 0; 01626 if (extract_interval_constraint(c, cs_space_dim, 01627 c_num_vars, c_only_var)) { 01628 if (c_num_vars == 1) { 01629 // An interval constraint on variable index `c_only_var'. 01630 PPL_ASSERT(c_only_var < space_dim); 01631 // We do care about c if c_only_var is going to be wrapped. 01632 if (vars.find(c_only_var) != vs_end) 01633 var_cs_map[c_only_var].push_back(&c); 01634 } 01635 else { 01636 PPL_ASSERT(c_num_vars == 0); 01637 // Note: tautologies have been filtered out by iterators. 01638 PPL_ASSERT(c.is_inconsistent()); 01639 x.set_empty(); 01640 return; 01641 } 01642 } 01643 } 01644 01645 PPL_DIRTY_TEMP(ITV, refinement_itv); 01646 const map_type::const_iterator var_cs_map_end = var_cs_map.end(); 01647 // Loop through the variable indexes in `vars'. 01648 for (Variables_Set::const_iterator i = vars.begin(); i != vs_end; ++i) { 01649 const dimension_type v = *i; 01650 refinement_itv = integer_quadrant_itv; 01651 // Look for the refinement constraints for space dimension index `v'. 01652 map_type::const_iterator var_cs_map_iter = var_cs_map.find(v); 01653 if (var_cs_map_iter != var_cs_map_end) { 01654 // Refine interval for variable `v'. 01655 const map_type::mapped_type& var_cs = var_cs_map_iter->second; 01656 for (dimension_type j = var_cs.size(); j-- > 0; ) { 01657 const Constraint& c = *var_cs[j]; 01658 refine_interval_no_check(refinement_itv, 01659 c.type(), 01660 c.inhomogeneous_term(), 01661 c.coefficient(Variable(v))); 01662 } 01663 } 01664 // Wrap space dimension index `v'. 01665 ITV& x_seq_v = x.seq[v]; 01666 switch (o) { 01667 case OVERFLOW_WRAPS: 01668 x_seq_v.wrap_assign(w, r, refinement_itv); 01669 break; 01670 case OVERFLOW_UNDEFINED: 01671 if (!rational_quadrant_itv.contains(x_seq_v)) 01672 x_seq_v.assign(UNIVERSE); 01673 break; 01674 case OVERFLOW_IMPOSSIBLE: 01675 x_seq_v.intersect_assign(refinement_itv); 01676 break; 01677 } 01678 } 01679 PPL_ASSERT(x.OK()); 01680 #endif 01681 } 01682 01683 template <typename ITV> 01684 void 01685 Box<ITV>::drop_some_non_integer_points(Complexity_Class) { 01686 if (std::numeric_limits<typename ITV::boundary_type>::is_integer 01687 && !ITV::info_type::store_open) 01688 return; 01689 01690 if (marked_empty()) 01691 return; 01692 01693 for (dimension_type k = seq.size(); k-- > 0; ) 01694 seq[k].drop_some_non_integer_points(); 01695 01696 PPL_ASSERT(OK()); 01697 } 01698 01699 template <typename ITV> 01700 void 01701 Box<ITV>::drop_some_non_integer_points(const Variables_Set& vars, 01702 Complexity_Class) { 01703 // Dimension-compatibility check. 01704 const dimension_type min_space_dim = vars.space_dimension(); 01705 if (space_dimension() < min_space_dim) 01706 throw_dimension_incompatible("drop_some_non_integer_points(vs, cmpl)", 01707 min_space_dim); 01708 01709 if (std::numeric_limits<typename ITV::boundary_type>::is_integer 01710 && !ITV::info_type::store_open) 01711 return; 01712 01713 if (marked_empty()) 01714 return; 01715 01716 for (Variables_Set::const_iterator v_i = vars.begin(), 01717 v_end = vars.end(); v_i != v_end; ++v_i) 01718 seq[*v_i].drop_some_non_integer_points(); 01719 01720 PPL_ASSERT(OK()); 01721 } 01722 01723 template <typename ITV> 01724 void 01725 Box<ITV>::intersection_assign(const Box& y) { 01726 Box& x = *this; 01727 const dimension_type space_dim = space_dimension(); 01728 01729 // Dimension-compatibility check. 01730 if (space_dim != y.space_dimension()) 01731 x.throw_dimension_incompatible("intersection_assign(y)", y); 01732 01733 // If one of the two boxes is empty, the intersection is empty. 01734 if (x.marked_empty()) 01735 return; 01736 if (y.marked_empty()) { 01737 x.set_empty(); 01738 return; 01739 } 01740 01741 // If both boxes are zero-dimensional, then at this point they are 01742 // necessarily non-empty, so that their intersection is non-empty too. 01743 if (space_dim == 0) 01744 return; 01745 01746 // FIXME: here we may conditionally exploit a capability of the 01747 // underlying interval to eagerly detect empty results. 01748 reset_empty_up_to_date(); 01749 01750 for (dimension_type k = space_dim; k-- > 0; ) 01751 x.seq[k].intersect_assign(y.seq[k]); 01752 01753 PPL_ASSERT(x.OK()); 01754 } 01755 01756 template <typename ITV> 01757 void 01758 Box<ITV>::upper_bound_assign(const Box& y) { 01759 Box& x = *this; 01760 01761 // Dimension-compatibility check. 01762 if (x.space_dimension() != y.space_dimension()) 01763 x.throw_dimension_incompatible("upper_bound_assign(y)", y); 01764 01765 // The lub of a box with an empty box is equal to the first box. 01766 if (y.is_empty()) 01767 return; 01768 if (x.is_empty()) { 01769 x = y; 01770 return; 01771 } 01772 01773 for (dimension_type k = x.seq.size(); k-- > 0; ) 01774 x.seq[k].join_assign(y.seq[k]); 01775 01776 PPL_ASSERT(x.OK()); 01777 } 01778 01779 template <typename ITV> 01780 void 01781 Box<ITV>::concatenate_assign(const Box& y) { 01782 Box& x = *this; 01783 const dimension_type x_space_dim = x.space_dimension(); 01784 const dimension_type y_space_dim = y.space_dimension(); 01785 01786 // If `y' is marked empty, the result will be empty too. 01787 if (y.marked_empty()) 01788 x.set_empty(); 01789 01790 // If `y' is a 0-dim space box, there is nothing left to do. 01791 if (y_space_dim == 0) 01792 return; 01793 // The resulting space dimension must be at most the maximum. 01794 check_space_dimension_overflow(y.space_dimension(), 01795 max_space_dimension() - space_dimension(), 01796 "PPL::Box::", 01797 "concatenate_assign(y)", 01798 "concatenation exceeds the maximum " 01799 "allowed space dimension"); 01800 // Here `y_space_dim > 0', so that a non-trivial concatenation will occur: 01801 // make sure that reallocation will occur once at most. 01802 x.seq.reserve(x_space_dim + y_space_dim); 01803 01804 // If `x' is marked empty, then it is sufficient to adjust 01805 // the dimension of the vector space. 01806 if (x.marked_empty()) { 01807 x.seq.insert(x.seq.end(), y_space_dim, ITV(EMPTY)); 01808 PPL_ASSERT(x.OK()); 01809 return; 01810 } 01811 01812 // Here neither `x' nor `y' are marked empty: concatenate them. 01813 std::copy(y.seq.begin(), y.seq.end(), 01814 std::back_insert_iterator<Sequence>(x.seq)); 01815 // Update the `empty_up_to_date' flag. 01816 if (!y.status.test_empty_up_to_date()) 01817 reset_empty_up_to_date(); 01818 01819 PPL_ASSERT(x.OK()); 01820 } 01821 01822 template <typename ITV> 01823 void 01824 Box<ITV>::difference_assign(const Box& y) { 01825 const dimension_type space_dim = space_dimension(); 01826 01827 // Dimension-compatibility check. 01828 if (space_dim != y.space_dimension()) 01829 throw_dimension_incompatible("difference_assign(y)", y); 01830 01831 Box& x = *this; 01832 if (x.is_empty() || y.is_empty()) 01833 return; 01834 01835 switch (space_dim) { 01836 case 0: 01837 // If `x' is zero-dimensional, then at this point both `x' and `y' 01838 // are the universe box, so that their difference is empty. 01839 x.set_empty(); 01840 break; 01841 01842 case 1: 01843 x.seq[0].difference_assign(y.seq[0]); 01844 if (x.seq[0].is_empty()) 01845 x.set_empty(); 01846 break; 01847 01848 default: 01849 { 01850 dimension_type index_non_contained = space_dim; 01851 dimension_type number_non_contained = 0; 01852 for (dimension_type i = space_dim; i-- > 0; ) 01853 if (!y.seq[i].contains(x.seq[i])) { 01854 if (++number_non_contained == 1) 01855 index_non_contained = i; 01856 else 01857 break; 01858 } 01859 01860 switch (number_non_contained) { 01861 case 0: 01862 // `y' covers `x': the difference is empty. 01863 x.set_empty(); 01864 break; 01865 case 1: 01866 x.seq[index_non_contained] 01867 .difference_assign(y.seq[index_non_contained]); 01868 if (x.seq[index_non_contained].is_empty()) 01869 x.set_empty(); 01870 break; 01871 default: 01872 // Nothing to do: the difference is `x'. 01873 break; 01874 } 01875 } 01876 break; 01877 } 01878 PPL_ASSERT(OK()); 01879 } 01880 01881 template <typename ITV> 01882 bool 01883 Box<ITV>::simplify_using_context_assign(const Box& y) { 01884 Box& x = *this; 01885 const dimension_type num_dims = x.space_dimension(); 01886 // Dimension-compatibility check. 01887 if (num_dims != y.space_dimension()) 01888 x.throw_dimension_incompatible("simplify_using_context_assign(y)", y); 01889 01890 // Filter away the zero-dimensional case. 01891 if (num_dims == 0) { 01892 if (y.marked_empty()) { 01893 x.set_nonempty(); 01894 return false; 01895 } 01896 else 01897 return !x.marked_empty(); 01898 } 01899 01900 // Filter away the case when `y' is empty. 01901 if (y.is_empty()) { 01902 for (dimension_type i = num_dims; i-- > 0; ) 01903 x.seq[i].assign(UNIVERSE); 01904 x.set_nonempty(); 01905 return false; 01906 } 01907 01908 if (x.is_empty()) { 01909 // Find in `y' a non-universe interval, if any. 01910 for (dimension_type i = 0; i < num_dims; ++i) { 01911 if (y.seq[i].is_universe()) 01912 x.seq[i].assign(UNIVERSE); 01913 else { 01914 // Set x.seq[i] so as to contradict y.seq[i], if possible. 01915 ITV& seq_i = x.seq[i]; 01916 seq_i.empty_intersection_assign(y.seq[i]); 01917 if (seq_i.is_empty()) { 01918 // We were not able to assign to `seq_i' a non-empty interval: 01919 // reset `seq_i' to the universe interval and keep searching. 01920 seq_i.assign(UNIVERSE); 01921 continue; 01922 } 01923 // We assigned to `seq_i' a non-empty interval: 01924 // set the other intervals to universe and return. 01925 for (++i; i < num_dims; ++i) 01926 x.seq[i].assign(UNIVERSE); 01927 x.set_nonempty(); 01928 PPL_ASSERT(x.OK()); 01929 return false; 01930 } 01931 } 01932 // All intervals in `y' are universe or could not be contradicted: 01933 // simplification can leave the empty box `x' as is. 01934 PPL_ASSERT(x.OK() && x.is_empty()); 01935 return false; 01936 } 01937 01938 // Loop index `i' is intentionally going upwards. 01939 for (dimension_type i = 0; i < num_dims; ++i) { 01940 if (!x.seq[i].simplify_using_context_assign(y.seq[i])) { 01941 PPL_ASSERT(!x.seq[i].is_empty()); 01942 // The intersection of `x' and `y' is empty due to the i-th interval: 01943 // reset other intervals to UNIVERSE. 01944 for (dimension_type j = num_dims; j-- > i; ) 01945 x.seq[j].assign(UNIVERSE); 01946 for (dimension_type j = i; j-- > 0; ) 01947 x.seq[j].assign(UNIVERSE); 01948 PPL_ASSERT(x.OK()); 01949 return false; 01950 } 01951 } 01952 PPL_ASSERT(x.OK()); 01953 return true; 01954 } 01955 01956 template <typename ITV> 01957 void 01958 Box<ITV>::time_elapse_assign(const Box& y) { 01959 Box& x = *this; 01960 const dimension_type x_space_dim = x.space_dimension(); 01961 01962 // Dimension-compatibility check. 01963 if (x_space_dim != y.space_dimension()) 01964 x.throw_dimension_incompatible("time_elapse_assign(y)", y); 01965 01966 // Dealing with the zero-dimensional case. 01967 if (x_space_dim == 0) { 01968 if (y.marked_empty()) 01969 x.set_empty(); 01970 return; 01971 } 01972 01973 // If either one of `x' or `y' is empty, the result is empty too. 01974 // Note: if possible, avoid cost of checking for emptiness. 01975 if (x.marked_empty() || y.marked_empty() 01976 || x.is_empty() || y.is_empty()) { 01977 x.set_empty(); 01978 return; 01979 } 01980 01981 for (dimension_type i = x_space_dim; i-- > 0; ) { 01982 ITV& x_seq_i = x.seq[i]; 01983 const ITV& y_seq_i = y.seq[i]; 01984 if (!x_seq_i.lower_is_boundary_infinity()) 01985 if (y_seq_i.lower_is_boundary_infinity() || y_seq_i.lower() < 0) 01986 x_seq_i.lower_extend(); 01987 if (!x_seq_i.upper_is_boundary_infinity()) 01988 if (y_seq_i.upper_is_boundary_infinity() || y_seq_i.upper() > 0) 01989 x_seq_i.upper_extend(); 01990 } 01991 PPL_ASSERT(x.OK()); 01992 } 01993 01994 template <typename ITV> 01995 inline void 01996 Box<ITV>::remove_space_dimensions(const Variables_Set& vars) { 01997 // The removal of no dimensions from any box is a no-op. 01998 // Note that this case also captures the only legal removal of 01999 // space dimensions from a box in a zero-dimensional space. 02000 if (vars.empty()) { 02001 PPL_ASSERT(OK()); 02002 return; 02003 } 02004 02005 const dimension_type old_space_dim = space_dimension(); 02006 02007 // Dimension-compatibility check. 02008 const dimension_type vsi_space_dim = vars.space_dimension(); 02009 if (old_space_dim < vsi_space_dim) 02010 throw_dimension_incompatible("remove_space_dimensions(vs)", 02011 vsi_space_dim); 02012 02013 const dimension_type new_space_dim = old_space_dim - vars.size(); 02014 02015 // If the box is empty (this must be detected), then resizing is all 02016 // what is needed. If it is not empty and we are removing _all_ the 02017 // dimensions then, again, resizing suffices. 02018 if (is_empty() || new_space_dim == 0) { 02019 seq.resize(new_space_dim); 02020 PPL_ASSERT(OK()); 02021 return; 02022 } 02023 02024 // For each variable to be removed, we fill the corresponding interval 02025 // by shifting left those intervals that will not be removed. 02026 Variables_Set::const_iterator vsi = vars.begin(); 02027 Variables_Set::const_iterator vsi_end = vars.end(); 02028 dimension_type dst = *vsi; 02029 dimension_type src = dst + 1; 02030 for (++vsi; vsi != vsi_end; ++vsi) { 02031 const dimension_type vsi_next = *vsi; 02032 // All intervals in between are moved to the left. 02033 while (src < vsi_next) 02034 swap(seq[dst++], seq[src++]); 02035 ++src; 02036 } 02037 // Moving the remaining intervals. 02038 while (src < old_space_dim) 02039 swap(seq[dst++], seq[src++]); 02040 02041 PPL_ASSERT(dst == new_space_dim); 02042 seq.resize(new_space_dim); 02043 02044 PPL_ASSERT(OK()); 02045 } 02046 02047 template <typename ITV> 02048 void 02049 Box<ITV>::remove_higher_space_dimensions(const dimension_type new_dimension) { 02050 // Dimension-compatibility check: the variable having 02051 // maximum index is the one occurring last in the set. 02052 const dimension_type space_dim = space_dimension(); 02053 if (new_dimension > space_dim) 02054 throw_dimension_incompatible("remove_higher_space_dimensions(nd)", 02055 new_dimension); 02056 02057 // The removal of no dimensions from any box is a no-op. 02058 // Note that this case also captures the only legal removal of 02059 // dimensions from a zero-dim space box. 02060 if (new_dimension == space_dim) { 02061 PPL_ASSERT(OK()); 02062 return; 02063 } 02064 02065 seq.resize(new_dimension); 02066 PPL_ASSERT(OK()); 02067 } 02068 02069 template <typename ITV> 02070 template <typename Partial_Function> 02071 void 02072 Box<ITV>::map_space_dimensions(const Partial_Function& pfunc) { 02073 const dimension_type space_dim = space_dimension(); 02074 if (space_dim == 0) 02075 return; 02076 02077 if (pfunc.has_empty_codomain()) { 02078 // All dimensions vanish: the box becomes zero_dimensional. 02079 remove_higher_space_dimensions(0); 02080 return; 02081 } 02082 02083 const dimension_type new_space_dim = pfunc.max_in_codomain() + 1; 02084 // If the box is empty, then simply adjust the space dimension. 02085 if (is_empty()) { 02086 remove_higher_space_dimensions(new_space_dim); 02087 return; 02088 } 02089 02090 // We create a new Box with the new space dimension. 02091 Box<ITV> tmp(new_space_dim); 02092 // Map the intervals, exchanging the indexes. 02093 for (dimension_type i = 0; i < space_dim; ++i) { 02094 dimension_type new_i; 02095 if (pfunc.maps(i, new_i)) 02096 swap(seq[i], tmp.seq[new_i]); 02097 } 02098 m_swap(tmp); 02099 PPL_ASSERT(OK()); 02100 } 02101 02102 template <typename ITV> 02103 void 02104 Box<ITV>::fold_space_dimensions(const Variables_Set& vars, 02105 const Variable dest) { 02106 const dimension_type space_dim = space_dimension(); 02107 // `dest' should be one of the dimensions of the box. 02108 if (dest.space_dimension() > space_dim) 02109 throw_dimension_incompatible("fold_space_dimensions(vs, v)", "v", dest); 02110 02111 // The folding of no dimensions is a no-op. 02112 if (vars.empty()) 02113 return; 02114 02115 // All variables in `vars' should be dimensions of the box. 02116 if (vars.space_dimension() > space_dim) 02117 throw_dimension_incompatible("fold_space_dimensions(vs, v)", 02118 vars.space_dimension()); 02119 02120 // Moreover, `dest.id()' should not occur in `vars'. 02121 if (vars.find(dest.id()) != vars.end()) 02122 throw_invalid_argument("fold_space_dimensions(vs, v)", 02123 "v should not occur in vs"); 02124 02125 // Note: the check for emptiness is needed for correctness. 02126 if (!is_empty()) { 02127 // Join the interval corresponding to variable `dest' with the intervals 02128 // corresponding to the variables in `vars'. 02129 ITV& seq_v = seq[dest.id()]; 02130 for (Variables_Set::const_iterator i = vars.begin(), 02131 vs_end = vars.end(); i != vs_end; ++i) 02132 seq_v.join_assign(seq[*i]); 02133 } 02134 remove_space_dimensions(vars); 02135 } 02136 02137 template <typename ITV> 02138 void 02139 Box<ITV>::add_constraint_no_check(const Constraint& c) { 02140 const dimension_type c_space_dim = c.space_dimension(); 02141 PPL_ASSERT(c_space_dim <= space_dimension()); 02142 02143 dimension_type c_num_vars = 0; 02144 dimension_type c_only_var = 0; 02145 // Throw an exception if c is not an interval constraints. 02146 if (!extract_interval_constraint(c, c_space_dim, c_num_vars, c_only_var)) 02147 throw_invalid_argument("add_constraint(c)", 02148 "c is not an interval constraint"); 02149 02150 // Throw an exception if c is a nontrivial strict constraint 02151 // and ITV does not support open boundaries. 02152 if (c.is_strict_inequality() && c_num_vars != 0 02153 && ITV::is_always_topologically_closed()) 02154 throw_invalid_argument("add_constraint(c)", 02155 "c is a nontrivial strict constraint"); 02156 02157 // Avoid doing useless work if the box is known to be empty. 02158 if (marked_empty()) 02159 return; 02160 02161 const Coefficient& n = c.inhomogeneous_term(); 02162 if (c_num_vars == 0) { 02163 // Dealing with a trivial constraint. 02164 if (n < 0 02165 || (c.is_equality() && n != 0) 02166 || (c.is_strict_inequality() && n == 0)) 02167 set_empty(); 02168 return; 02169 } 02170 02171 PPL_ASSERT(c_num_vars == 1); 02172 const Coefficient& d = c.coefficient(Variable(c_only_var)); 02173 add_interval_constraint_no_check(c_only_var, c.type(), n, d); 02174 } 02175 02176 template <typename ITV> 02177 void 02178 Box<ITV>::add_constraints_no_check(const Constraint_System& cs) { 02179 PPL_ASSERT(cs.space_dimension() <= space_dimension()); 02180 // Note: even when the box is known to be empty, we need to go 02181 // through all the constraints to fulfill the method's contract 02182 // for what concerns exception throwing. 02183 for (Constraint_System::const_iterator i = cs.begin(), 02184 cs_end = cs.end(); i != cs_end; ++i) 02185 add_constraint_no_check(*i); 02186 PPL_ASSERT(OK()); 02187 } 02188 02189 template <typename ITV> 02190 void 02191 Box<ITV>::add_congruence_no_check(const Congruence& cg) { 02192 const dimension_type cg_space_dim = cg.space_dimension(); 02193 PPL_ASSERT(cg_space_dim <= space_dimension()); 02194 02195 // Set aside the case of proper congruences. 02196 if (cg.is_proper_congruence()) { 02197 if (cg.is_inconsistent()) { 02198 set_empty(); 02199 return; 02200 } 02201 else if (cg.is_tautological()) 02202 return; 02203 else 02204 throw_invalid_argument("add_congruence(cg)", 02205 "cg is a nontrivial proper congruence"); 02206 } 02207 02208 PPL_ASSERT(cg.is_equality()); 02209 dimension_type cg_num_vars = 0; 02210 dimension_type cg_only_var = 0; 02211 // Throw an exception if c is not an interval congruence. 02212 if (!extract_interval_congruence(cg, cg_space_dim, cg_num_vars, cg_only_var)) 02213 throw_invalid_argument("add_congruence(cg)", 02214 "cg is not an interval congruence"); 02215 02216 // Avoid doing useless work if the box is known to be empty. 02217 if (marked_empty()) 02218 return; 02219 02220 const Coefficient& n = cg.inhomogeneous_term(); 02221 if (cg_num_vars == 0) { 02222 // Dealing with a trivial equality congruence. 02223 if (n != 0) 02224 set_empty(); 02225 return; 02226 } 02227 02228 PPL_ASSERT(cg_num_vars == 1); 02229 const Coefficient& d = cg.coefficient(Variable(cg_only_var)); 02230 add_interval_constraint_no_check(cg_only_var, Constraint::EQUALITY, n, d); 02231 } 02232 02233 template <typename ITV> 02234 void 02235 Box<ITV>::add_congruences_no_check(const Congruence_System& cgs) { 02236 PPL_ASSERT(cgs.space_dimension() <= space_dimension()); 02237 // Note: even when the box is known to be empty, we need to go 02238 // through all the congruences to fulfill the method's contract 02239 // for what concerns exception throwing. 02240 for (Congruence_System::const_iterator i = cgs.begin(), 02241 cgs_end = cgs.end(); i != cgs_end; ++i) 02242 add_congruence_no_check(*i); 02243 PPL_ASSERT(OK()); 02244 } 02245 02246 template <typename ITV> 02247 void 02248 Box<ITV>::refine_no_check(const Constraint& c) { 02249 const dimension_type c_space_dim = c.space_dimension(); 02250 PPL_ASSERT(c.space_dimension() <= space_dimension()); 02251 PPL_ASSERT(!marked_empty()); 02252 02253 dimension_type c_num_vars = 0; 02254 dimension_type c_only_var = 0; 02255 // Non-interval constraints are approximated. 02256 if (!extract_interval_constraint(c, c_space_dim, c_num_vars, c_only_var)) { 02257 propagate_constraint_no_check(c); 02258 return; 02259 } 02260 02261 const Coefficient& n = c.inhomogeneous_term(); 02262 if (c_num_vars == 0) { 02263 // Dealing with a trivial constraint. 02264 if (n < 0 02265 || (c.is_equality() && n != 0) 02266 || (c.is_strict_inequality() && n == 0)) 02267 set_empty(); 02268 return; 02269 } 02270 02271 PPL_ASSERT(c_num_vars == 1); 02272 const Coefficient& d = c.coefficient(Variable(c_only_var)); 02273 add_interval_constraint_no_check(c_only_var, c.type(), n, d); 02274 } 02275 02276 template <typename ITV> 02277 void 02278 Box<ITV>::refine_no_check(const Constraint_System& cs) { 02279 PPL_ASSERT(cs.space_dimension() <= space_dimension()); 02280 for (Constraint_System::const_iterator i = cs.begin(), 02281 cs_end = cs.end(); !marked_empty() && i != cs_end; ++i) 02282 refine_no_check(*i); 02283 PPL_ASSERT(OK()); 02284 } 02285 02286 template <typename ITV> 02287 void 02288 Box<ITV>::refine_no_check(const Congruence& cg) { 02289 PPL_ASSERT(!marked_empty()); 02290 02291 PPL_ASSERT(cg.space_dimension() <= space_dimension()); 02292 02293 if (cg.is_proper_congruence()) { 02294 // A proper congruences is also an interval constraint 02295 // if and only if it is trivial. 02296 if (cg.is_inconsistent()) 02297 set_empty(); 02298 return; 02299 } 02300 02301 PPL_ASSERT(cg.is_equality()); 02302 Constraint c(cg); 02303 refine_no_check(c); 02304 } 02305 02306 template <typename ITV> 02307 void 02308 Box<ITV>::refine_no_check(const Congruence_System& cgs) { 02309 PPL_ASSERT(cgs.space_dimension() <= space_dimension()); 02310 for (Congruence_System::const_iterator i = cgs.begin(), 02311 cgs_end = cgs.end(); !marked_empty() && i != cgs_end; ++i) 02312 refine_no_check(*i); 02313 PPL_ASSERT(OK()); 02314 } 02315 02316 #if 1 // Alternative implementations for propagate_constraint_no_check. 02317 namespace Implementation { 02318 02319 namespace Boxes { 02320 02321 inline bool 02322 propagate_constraint_check_result(Result r, Ternary& open) { 02323 r = result_relation_class(r); 02324 switch (r) { 02325 case V_GT_MINUS_INFINITY: 02326 case V_LT_PLUS_INFINITY: 02327 return true; 02328 case V_LT: 02329 case V_GT: 02330 open = T_YES; 02331 return false; 02332 case V_LE: 02333 case V_GE: 02334 if (open == T_NO) 02335 open = T_MAYBE; 02336 return false; 02337 case V_EQ: 02338 return false; 02339 default: 02340 PPL_UNREACHABLE; 02341 return true; 02342 } 02343 } 02344 02345 } // namespace Boxes 02346 02347 } // namespace Implementation 02348 02349 02350 template <typename ITV> 02351 void 02352 Box<ITV>::propagate_constraint_no_check(const Constraint& c) { 02353 using namespace Implementation::Boxes; 02354 02355 PPL_ASSERT(c.space_dimension() <= space_dimension()); 02356 02357 typedef 02358 typename Select_Temp_Boundary_Type<typename ITV::boundary_type>::type 02359 Temp_Boundary_Type; 02360 02361 const dimension_type c_space_dim = c.space_dimension(); 02362 const Constraint::Type c_type = c.type(); 02363 const Coefficient& c_inhomogeneous_term = c.inhomogeneous_term(); 02364 02365 // Find a space dimension having a non-zero coefficient (if any). 02366 dimension_type last_k = c_space_dim; 02367 for (dimension_type k = c_space_dim; k-- > 0; ) { 02368 if (c.coefficient(Variable(k)) != 0) { 02369 last_k = k; 02370 break; 02371 } 02372 } 02373 if (last_k == c_space_dim) { 02374 // Constraint c is trivial: check if it is inconsistent. 02375 if (c_inhomogeneous_term < 0 02376 || (c_inhomogeneous_term == 0 02377 && c_type != Constraint::NONSTRICT_INEQUALITY)) 02378 set_empty(); 02379 return; 02380 } 02381 02382 // Here constraint c is non-trivial. 02383 PPL_ASSERT(last_k < c_space_dim); 02384 Temp_Boundary_Type t_bound; 02385 Temp_Boundary_Type t_a; 02386 Temp_Boundary_Type t_x; 02387 Ternary open; 02388 for (dimension_type k = last_k+1; k-- > 0; ) { 02389 const Coefficient& a_k = c.coefficient(Variable(k)); 02390 int sgn_a_k = sgn(a_k); 02391 if (sgn_a_k == 0) 02392 continue; 02393 Result r; 02394 if (sgn_a_k > 0) { 02395 open = (c_type == Constraint::STRICT_INEQUALITY) ? T_YES : T_NO; 02396 if (open == T_NO) 02397 maybe_reset_fpu_inexact<Temp_Boundary_Type>(); 02398 r = assign_r(t_bound, c_inhomogeneous_term, ROUND_UP); 02399 if (propagate_constraint_check_result(r, open)) 02400 goto maybe_refine_upper_1; 02401 r = neg_assign_r(t_bound, t_bound, ROUND_DOWN); 02402 if (propagate_constraint_check_result(r, open)) 02403 goto maybe_refine_upper_1; 02404 for (dimension_type i = last_k+1; i-- > 0; ) { 02405 if (i == k) 02406 continue; 02407 const Coefficient& a_i = c.coefficient(Variable(i)); 02408 int sgn_a_i = sgn(a_i); 02409 if (sgn_a_i == 0) 02410 continue; 02411 ITV& x_i = seq[i]; 02412 if (sgn_a_i < 0) { 02413 if (x_i.lower_is_boundary_infinity()) 02414 goto maybe_refine_upper_1; 02415 r = assign_r(t_a, a_i, ROUND_DOWN); 02416 if (propagate_constraint_check_result(r, open)) 02417 goto maybe_refine_upper_1; 02418 r = assign_r(t_x, x_i.lower(), ROUND_DOWN); 02419 if (propagate_constraint_check_result(r, open)) 02420 goto maybe_refine_upper_1; 02421 if (x_i.lower_is_open()) 02422 open = T_YES; 02423 r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_DOWN); 02424 if (propagate_constraint_check_result(r, open)) 02425 goto maybe_refine_upper_1; 02426 } 02427 else { 02428 PPL_ASSERT(sgn_a_i > 0); 02429 if (x_i.upper_is_boundary_infinity()) 02430 goto maybe_refine_upper_1; 02431 r = assign_r(t_a, a_i, ROUND_UP); 02432 if (propagate_constraint_check_result(r, open)) 02433 goto maybe_refine_upper_1; 02434 r = assign_r(t_x, x_i.upper(), ROUND_UP); 02435 if (propagate_constraint_check_result(r, open)) 02436 goto maybe_refine_upper_1; 02437 if (x_i.upper_is_open()) 02438 open = T_YES; 02439 r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_DOWN); 02440 if (propagate_constraint_check_result(r, open)) 02441 goto maybe_refine_upper_1; 02442 } 02443 } 02444 r = assign_r(t_a, a_k, ROUND_UP); 02445 if (propagate_constraint_check_result(r, open)) 02446 goto maybe_refine_upper_1; 02447 r = div_assign_r(t_bound, t_bound, t_a, ROUND_DOWN); 02448 if (propagate_constraint_check_result(r, open)) 02449 goto maybe_refine_upper_1; 02450 02451 // Refine the lower bound of `seq[k]' with `t_bound'. 02452 if (open == T_MAYBE 02453 && maybe_check_fpu_inexact<Temp_Boundary_Type>() == 1) 02454 open = T_YES; 02455 { 02456 Relation_Symbol rel = (open == T_YES) ? GREATER_THAN : GREATER_OR_EQUAL; 02457 seq[k].add_constraint(i_constraint(rel, t_bound)); 02458 } 02459 reset_empty_up_to_date(); 02460 maybe_refine_upper_1: 02461 if (c_type != Constraint::EQUALITY) 02462 continue; 02463 open = T_NO; 02464 maybe_reset_fpu_inexact<Temp_Boundary_Type>(); 02465 r = assign_r(t_bound, c_inhomogeneous_term, ROUND_DOWN); 02466 if (propagate_constraint_check_result(r, open)) 02467 goto next_k; 02468 r = neg_assign_r(t_bound, t_bound, ROUND_UP); 02469 if (propagate_constraint_check_result(r, open)) 02470 goto next_k; 02471 for (dimension_type i = c_space_dim; i-- > 0; ) { 02472 if (i == k) 02473 continue; 02474 const Coefficient& a_i = c.coefficient(Variable(i)); 02475 int sgn_a_i = sgn(a_i); 02476 if (sgn_a_i == 0) 02477 continue; 02478 ITV& x_i = seq[i]; 02479 if (sgn_a_i < 0) { 02480 if (x_i.upper_is_boundary_infinity()) 02481 goto next_k; 02482 r = assign_r(t_a, a_i, ROUND_UP); 02483 if (propagate_constraint_check_result(r, open)) 02484 goto next_k; 02485 r = assign_r(t_x, x_i.upper(), ROUND_UP); 02486 if (propagate_constraint_check_result(r, open)) 02487 goto next_k; 02488 if (x_i.upper_is_open()) 02489 open = T_YES; 02490 r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_UP); 02491 if (propagate_constraint_check_result(r, open)) 02492 goto next_k; 02493 } 02494 else { 02495 PPL_ASSERT(sgn_a_i > 0); 02496 if (x_i.lower_is_boundary_infinity()) 02497 goto next_k; 02498 r = assign_r(t_a, a_i, ROUND_DOWN); 02499 if (propagate_constraint_check_result(r, open)) 02500 goto next_k; 02501 r = assign_r(t_x, x_i.lower(), ROUND_DOWN); 02502 if (propagate_constraint_check_result(r, open)) 02503 goto next_k; 02504 if (x_i.lower_is_open()) 02505 open = T_YES; 02506 r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_UP); 02507 if (propagate_constraint_check_result(r, open)) 02508 goto next_k; 02509 } 02510 } 02511 r = assign_r(t_a, a_k, ROUND_DOWN); 02512 if (propagate_constraint_check_result(r, open)) 02513 goto next_k; 02514 r = div_assign_r(t_bound, t_bound, t_a, ROUND_UP); 02515 if (propagate_constraint_check_result(r, open)) 02516 goto next_k; 02517 02518 // Refine the upper bound of seq[k] with t_bound. 02519 if (open == T_MAYBE 02520 && maybe_check_fpu_inexact<Temp_Boundary_Type>() == 1) 02521 open = T_YES; 02522 Relation_Symbol rel = (open == T_YES) ? LESS_THAN : LESS_OR_EQUAL; 02523 seq[k].add_constraint(i_constraint(rel, t_bound)); 02524 reset_empty_up_to_date(); 02525 } 02526 else { 02527 PPL_ASSERT(sgn_a_k < 0); 02528 open = (c_type == Constraint::STRICT_INEQUALITY) ? T_YES : T_NO; 02529 if (open == T_NO) 02530 maybe_reset_fpu_inexact<Temp_Boundary_Type>(); 02531 r = assign_r(t_bound, c_inhomogeneous_term, ROUND_UP); 02532 if (propagate_constraint_check_result(r, open)) 02533 goto maybe_refine_upper_2; 02534 r = neg_assign_r(t_bound, t_bound, ROUND_DOWN); 02535 if (propagate_constraint_check_result(r, open)) 02536 goto maybe_refine_upper_2; 02537 for (dimension_type i = c_space_dim; i-- > 0; ) { 02538 if (i == k) 02539 continue; 02540 const Coefficient& a_i = c.coefficient(Variable(i)); 02541 int sgn_a_i = sgn(a_i); 02542 if (sgn_a_i == 0) 02543 continue; 02544 ITV& x_i = seq[i]; 02545 if (sgn_a_i < 0) { 02546 if (x_i.lower_is_boundary_infinity()) 02547 goto maybe_refine_upper_2; 02548 r = assign_r(t_a, a_i, ROUND_DOWN); 02549 if (propagate_constraint_check_result(r, open)) 02550 goto maybe_refine_upper_2; 02551 r = assign_r(t_x, x_i.lower(), ROUND_DOWN); 02552 if (propagate_constraint_check_result(r, open)) 02553 goto maybe_refine_upper_2; 02554 if (x_i.lower_is_open()) 02555 open = T_YES; 02556 r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_UP); 02557 if (propagate_constraint_check_result(r, open)) 02558 goto maybe_refine_upper_2; 02559 } 02560 else { 02561 PPL_ASSERT(sgn_a_i > 0); 02562 if (x_i.upper_is_boundary_infinity()) 02563 goto maybe_refine_upper_2; 02564 r = assign_r(t_a, a_i, ROUND_UP); 02565 if (propagate_constraint_check_result(r, open)) 02566 goto maybe_refine_upper_2; 02567 r = assign_r(t_x, x_i.upper(), ROUND_UP); 02568 if (propagate_constraint_check_result(r, open)) 02569 goto maybe_refine_upper_2; 02570 if (x_i.upper_is_open()) 02571 open = T_YES; 02572 r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_DOWN); 02573 if (propagate_constraint_check_result(r, open)) 02574 goto maybe_refine_upper_2; 02575 } 02576 } 02577 r = assign_r(t_a, a_k, ROUND_UP); 02578 if (propagate_constraint_check_result(r, open)) 02579 goto maybe_refine_upper_2; 02580 r = div_assign_r(t_bound, t_bound, t_a, ROUND_UP); 02581 if (propagate_constraint_check_result(r, open)) 02582 goto maybe_refine_upper_2; 02583 02584 // Refine the upper bound of seq[k] with t_bound. 02585 if (open == T_MAYBE 02586 && maybe_check_fpu_inexact<Temp_Boundary_Type>() == 1) 02587 open = T_YES; 02588 { 02589 Relation_Symbol rel = (open == T_YES) ? LESS_THAN : LESS_OR_EQUAL; 02590 seq[k].add_constraint(i_constraint(rel, t_bound)); 02591 } 02592 reset_empty_up_to_date(); 02593 maybe_refine_upper_2: 02594 if (c_type != Constraint::EQUALITY) 02595 continue; 02596 open = T_NO; 02597 maybe_reset_fpu_inexact<Temp_Boundary_Type>(); 02598 r = assign_r(t_bound, c_inhomogeneous_term, ROUND_DOWN); 02599 if (propagate_constraint_check_result(r, open)) 02600 goto next_k; 02601 r = neg_assign_r(t_bound, t_bound, ROUND_UP); 02602 if (propagate_constraint_check_result(r, open)) 02603 goto next_k; 02604 for (dimension_type i = c_space_dim; i-- > 0; ) { 02605 if (i == k) 02606 continue; 02607 const Coefficient& a_i = c.coefficient(Variable(i)); 02608 int sgn_a_i = sgn(a_i); 02609 if (sgn_a_i == 0) 02610 continue; 02611 ITV& x_i = seq[i]; 02612 if (sgn_a_i < 0) { 02613 if (x_i.upper_is_boundary_infinity()) 02614 goto next_k; 02615 r = assign_r(t_a, a_i, ROUND_UP); 02616 if (propagate_constraint_check_result(r, open)) 02617 goto next_k; 02618 r = assign_r(t_x, x_i.upper(), ROUND_UP); 02619 if (propagate_constraint_check_result(r, open)) 02620 goto next_k; 02621 if (x_i.upper_is_open()) 02622 open = T_YES; 02623 r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_UP); 02624 if (propagate_constraint_check_result(r, open)) 02625 goto next_k; 02626 } 02627 else { 02628 PPL_ASSERT(sgn_a_i > 0); 02629 if (x_i.lower_is_boundary_infinity()) 02630 goto next_k; 02631 r = assign_r(t_a, a_i, ROUND_DOWN); 02632 if (propagate_constraint_check_result(r, open)) 02633 goto next_k; 02634 r = assign_r(t_x, x_i.lower(), ROUND_DOWN); 02635 if (propagate_constraint_check_result(r, open)) 02636 goto next_k; 02637 if (x_i.lower_is_open()) 02638 open = T_YES; 02639 r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_UP); 02640 if (propagate_constraint_check_result(r, open)) 02641 goto next_k; 02642 } 02643 } 02644 r = assign_r(t_a, a_k, ROUND_DOWN); 02645 if (propagate_constraint_check_result(r, open)) 02646 goto next_k; 02647 r = div_assign_r(t_bound, t_bound, t_a, ROUND_DOWN); 02648 if (propagate_constraint_check_result(r, open)) 02649 goto next_k; 02650 02651 // Refine the lower bound of seq[k] with t_bound. 02652 if (open == T_MAYBE 02653 && maybe_check_fpu_inexact<Temp_Boundary_Type>() == 1) 02654 open = T_YES; 02655 Relation_Symbol rel = (open == T_YES) ? GREATER_THAN : GREATER_OR_EQUAL; 02656 seq[k].add_constraint(i_constraint(rel, t_bound)); 02657 reset_empty_up_to_date(); 02658 } 02659 next_k: 02660 ; 02661 } 02662 } 02663 02664 #else // Alternative implementations for propagate_constraint_no_check. 02665 02666 template <typename ITV> 02667 void 02668 Box<ITV>::propagate_constraint_no_check(const Constraint& c) { 02669 PPL_ASSERT(c.space_dimension() <= space_dimension()); 02670 02671 dimension_type c_space_dim = c.space_dimension(); 02672 ITV k[c_space_dim]; 02673 ITV p[c_space_dim]; 02674 for (dimension_type i = c_space_dim; i-- > 0; ) { 02675 k[i] = c.coefficient(Variable(i)); 02676 ITV& p_i = p[i]; 02677 p_i = seq[i]; 02678 p_i.mul_assign(p_i, k[i]); 02679 } 02680 const Coefficient& inhomogeneous_term = c.inhomogeneous_term(); 02681 for (dimension_type i = c_space_dim; i-- > 0; ) { 02682 int sgn_coefficient_i = sgn(c.coefficient(Variable(i))); 02683 if (sgn_coefficient_i == 0) 02684 continue; 02685 ITV q(inhomogeneous_term); 02686 for (dimension_type j = c_space_dim; j-- > 0; ) { 02687 if (i == j) 02688 continue; 02689 q.add_assign(q, p[j]); 02690 } 02691 q.div_assign(q, k[i]); 02692 q.neg_assign(q); 02693 Relation_Symbol rel; 02694 switch (c.type()) { 02695 case Constraint::EQUALITY: 02696 rel = EQUAL; 02697 break; 02698 case Constraint::NONSTRICT_INEQUALITY: 02699 rel = (sgn_coefficient_i > 0) ? GREATER_OR_EQUAL : LESS_OR_EQUAL; 02700 break; 02701 case Constraint::STRICT_INEQUALITY: 02702 rel = (sgn_coefficient_i > 0) ? GREATER_THAN : LESS_THAN; 02703 break; 02704 } 02705 seq[i].add_constraint(i_constraint(rel, q)); 02706 // FIXME: could/should we exploit the return value of add_constraint 02707 // in case it is available? 02708 // FIXME: should we instead be lazy and do not even bother about 02709 // the possibility the interval becomes empty apart from setting 02710 // empty_up_to_date = false? 02711 if (seq[i].is_empty()) { 02712 set_empty(); 02713 break; 02714 } 02715 } 02716 02717 PPL_ASSERT(OK()); 02718 } 02719 02720 #endif // Alternative implementations for propagate_constraint_no_check. 02721 02722 template <typename ITV> 02723 void 02724 Box<ITV> 02725 ::propagate_constraints_no_check(const Constraint_System& cs, 02726 const dimension_type max_iterations) { 02727 const dimension_type space_dim = space_dimension(); 02728 PPL_ASSERT(cs.space_dimension() <= space_dim); 02729 02730 const Constraint_System::const_iterator cs_begin = cs.begin(); 02731 const Constraint_System::const_iterator cs_end = cs.end(); 02732 const dimension_type propagation_weight 02733 = Implementation::num_constraints(cs) * space_dim; 02734 02735 Sequence copy; 02736 bool changed; 02737 dimension_type num_iterations = 0; 02738 do { 02739 WEIGHT_BEGIN(); 02740 ++num_iterations; 02741 copy = seq; 02742 for (Constraint_System::const_iterator i = cs_begin; i != cs_end; ++i) 02743 propagate_constraint_no_check(*i); 02744 02745 WEIGHT_ADD_MUL(40, propagation_weight); 02746 // Check if the client has requested abandoning all expensive 02747 // computations. If so, the exception specified by the client 02748 // is thrown now. 02749 maybe_abandon(); 02750 02751 // NOTE: if max_iterations == 0 (i.e., no iteration limit is set) 02752 // the following test will anyway trigger on wrap around. 02753 if (num_iterations == max_iterations) 02754 break; 02755 02756 changed = (copy != seq); 02757 } while (changed); 02758 } 02759 02760 template <typename ITV> 02761 void 02762 Box<ITV>::affine_image(const Variable var, 02763 const Linear_Expression& expr, 02764 Coefficient_traits::const_reference denominator) { 02765 // The denominator cannot be zero. 02766 if (denominator == 0) 02767 throw_invalid_argument("affine_image(v, e, d)", "d == 0"); 02768 02769 // Dimension-compatibility checks. 02770 const dimension_type space_dim = space_dimension(); 02771 const dimension_type expr_space_dim = expr.space_dimension(); 02772 if (space_dim < expr_space_dim) 02773 throw_dimension_incompatible("affine_image(v, e, d)", "e", expr); 02774 // `var' should be one of the dimensions of the polyhedron. 02775 const dimension_type var_space_dim = var.space_dimension(); 02776 if (space_dim < var_space_dim) 02777 throw_dimension_incompatible("affine_image(v, e, d)", "v", var); 02778 02779 if (is_empty()) 02780 return; 02781 02782 Tmp_Interval_Type expr_value, temp0, temp1; 02783 expr_value.assign(expr.inhomogeneous_term()); 02784 for (dimension_type i = expr_space_dim; i-- > 0; ) { 02785 const Coefficient& coeff = expr.coefficient(Variable(i)); 02786 if (coeff != 0) { 02787 temp0.assign(coeff); 02788 temp1.assign(seq[i]); 02789 temp0.mul_assign(temp0, temp1); 02790 expr_value.add_assign(expr_value, temp0); 02791 } 02792 } 02793 if (denominator != 1) { 02794 temp0.assign(denominator); 02795 expr_value.div_assign(expr_value, temp0); 02796 } 02797 seq[var.id()].assign(expr_value); 02798 02799 PPL_ASSERT(OK()); 02800 } 02801 02802 template <typename ITV> 02803 void 02804 Box<ITV>::affine_form_image(const Variable var, 02805 const Linear_Form<ITV>& lf) { 02806 02807 // Check that ITV has a floating point boundary type. 02808 PPL_COMPILE_TIME_CHECK(!std::numeric_limits<typename ITV::boundary_type> 02809 ::is_exact, "Box<ITV>::affine_form_image(Variable, Linear_Form):" 02810 "ITV has not a floating point boundary type."); 02811 02812 // Dimension-compatibility checks. 02813 const dimension_type space_dim = space_dimension(); 02814 const dimension_type lf_space_dim = lf.space_dimension(); 02815 if (space_dim < lf_space_dim) 02816 throw_dimension_incompatible("affine_form_image(var, lf)", "lf", lf); 02817 // `var' should be one of the dimensions of the polyhedron. 02818 const dimension_type var_space_dim = var.space_dimension(); 02819 if (space_dim < var_space_dim) 02820 throw_dimension_incompatible("affine_form_image(var, lf)", "var", var); 02821 02822 if (is_empty()) 02823 return; 02824 02825 // Intervalization of 'lf'. 02826 ITV result = lf.inhomogeneous_term(); 02827 for (dimension_type i = 0; i < lf_space_dim; ++i) { 02828 ITV current_addend = lf.coefficient(Variable(i)); 02829 const ITV& curr_int = seq[i]; 02830 current_addend *= curr_int; 02831 result += current_addend; 02832 } 02833 02834 seq[var.id()].assign(result); 02835 PPL_ASSERT(OK()); 02836 } 02837 02838 template <typename ITV> 02839 void 02840 Box<ITV>::affine_preimage(const Variable var, 02841 const Linear_Expression& expr, 02842 Coefficient_traits::const_reference 02843 denominator) { 02844 // The denominator cannot be zero. 02845 if (denominator == 0) 02846 throw_invalid_argument("affine_preimage(v, e, d)", "d == 0"); 02847 02848 // Dimension-compatibility checks. 02849 const dimension_type x_space_dim = space_dimension(); 02850 const dimension_type expr_space_dim = expr.space_dimension(); 02851 if (x_space_dim < expr_space_dim) 02852 throw_dimension_incompatible("affine_preimage(v, e, d)", "e", expr); 02853 // `var' should be one of the dimensions of the polyhedron. 02854 const dimension_type var_space_dim = var.space_dimension(); 02855 if (x_space_dim < var_space_dim) 02856 throw_dimension_incompatible("affine_preimage(v, e, d)", "v", var); 02857 02858 if (is_empty()) 02859 return; 02860 02861 const Coefficient& expr_v = expr.coefficient(var); 02862 const bool invertible = (expr_v != 0); 02863 if (!invertible) { 02864 Tmp_Interval_Type expr_value, temp0, temp1; 02865 expr_value.assign(expr.inhomogeneous_term()); 02866 for (dimension_type i = expr_space_dim; i-- > 0; ) { 02867 const Coefficient& coeff = expr.coefficient(Variable(i)); 02868 if (coeff != 0) { 02869 temp0.assign(coeff); 02870 temp1.assign(seq[i]); 02871 temp0.mul_assign(temp0, temp1); 02872 expr_value.add_assign(expr_value, temp0); 02873 } 02874 } 02875 if (denominator != 1) { 02876 temp0.assign(denominator); 02877 expr_value.div_assign(expr_value, temp0); 02878 } 02879 ITV& x_seq_v = seq[var.id()]; 02880 expr_value.intersect_assign(x_seq_v); 02881 if (expr_value.is_empty()) 02882 set_empty(); 02883 else 02884 x_seq_v.assign(UNIVERSE); 02885 } 02886 else { 02887 // The affine transformation is invertible. 02888 // CHECKME: for efficiency, would it be meaningful to avoid 02889 // the computation of inverse by partially evaluating the call 02890 // to affine_image? 02891 Linear_Expression inverse; 02892 inverse -= expr; 02893 inverse += (expr_v + denominator) * var; 02894 affine_image(var, inverse, expr_v); 02895 } 02896 PPL_ASSERT(OK()); 02897 } 02898 02899 template <typename ITV> 02900 void 02901 Box<ITV> 02902 ::bounded_affine_image(const Variable var, 02903 const Linear_Expression& lb_expr, 02904 const Linear_Expression& ub_expr, 02905 Coefficient_traits::const_reference denominator) { 02906 // The denominator cannot be zero. 02907 if (denominator == 0) 02908 throw_invalid_argument("bounded_affine_image(v, lb, ub, d)", "d == 0"); 02909 02910 // Dimension-compatibility checks. 02911 const dimension_type space_dim = space_dimension(); 02912 // The dimension of `lb_expr' and `ub_expr' should not be 02913 // greater than the dimension of `*this'. 02914 const dimension_type lb_space_dim = lb_expr.space_dimension(); 02915 if (space_dim < lb_space_dim) 02916 throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)", 02917 "lb", lb_expr); 02918 const dimension_type ub_space_dim = ub_expr.space_dimension(); 02919 if (space_dim < ub_space_dim) 02920 throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)", 02921 "ub", ub_expr); 02922 // `var' should be one of the dimensions of the box. 02923 const dimension_type var_space_dim = var.space_dimension(); 02924 if (space_dim < var_space_dim) 02925 throw_dimension_incompatible("affine_image(v, e, d)", "v", var); 02926 02927 // Any image of an empty box is empty. 02928 if (is_empty()) 02929 return; 02930 02931 // Add the constraint implied by the `lb_expr' and `ub_expr'. 02932 if (denominator > 0) 02933 refine_with_constraint(lb_expr <= ub_expr); 02934 else 02935 refine_with_constraint(lb_expr >= ub_expr); 02936 02937 // Check whether `var' occurs in `lb_expr' and/or `ub_expr'. 02938 if (lb_expr.coefficient(var) == 0) { 02939 // Here `var' can only occur in `ub_expr'. 02940 generalized_affine_image(var, 02941 LESS_OR_EQUAL, 02942 ub_expr, 02943 denominator); 02944 if (denominator > 0) 02945 refine_with_constraint(lb_expr <= denominator*var); 02946 else 02947 refine_with_constraint(denominator*var <= lb_expr); 02948 } 02949 else if (ub_expr.coefficient(var) == 0) { 02950 // Here `var' can only occur in `lb_expr'. 02951 generalized_affine_image(var, 02952 GREATER_OR_EQUAL, 02953 lb_expr, 02954 denominator); 02955 if (denominator > 0) 02956 refine_with_constraint(denominator*var <= ub_expr); 02957 else 02958 refine_with_constraint(ub_expr <= denominator*var); 02959 } 02960 else { 02961 // Here `var' occurs in both `lb_expr' and `ub_expr'. As boxes 02962 // can only use the non-relational constraints, we find the 02963 // maximum/minimum values `ub_expr' and `lb_expr' obtain with the 02964 // box and use these instead of the `ub-expr' and `lb-expr'. 02965 PPL_DIRTY_TEMP(Coefficient, max_numer); 02966 PPL_DIRTY_TEMP(Coefficient, max_denom); 02967 bool max_included; 02968 PPL_DIRTY_TEMP(Coefficient, min_numer); 02969 PPL_DIRTY_TEMP(Coefficient, min_denom); 02970 bool min_included; 02971 ITV& seq_v = seq[var.id()]; 02972 if (maximize(ub_expr, max_numer, max_denom, max_included)) { 02973 if (minimize(lb_expr, min_numer, min_denom, min_included)) { 02974 // The `ub_expr' has a maximum value and the `lb_expr' 02975 // has a minimum value for the box. 02976 // Set the bounds for `var' using the minimum for `lb_expr'. 02977 min_denom *= denominator; 02978 PPL_DIRTY_TEMP(mpq_class, q1); 02979 PPL_DIRTY_TEMP(mpq_class, q2); 02980 assign_r(q1.get_num(), min_numer, ROUND_NOT_NEEDED); 02981 assign_r(q1.get_den(), min_denom, ROUND_NOT_NEEDED); 02982 q1.canonicalize(); 02983 // Now make the maximum of lb_expr the upper bound. If the 02984 // maximum is not at a box point, then inequality is strict. 02985 max_denom *= denominator; 02986 assign_r(q2.get_num(), max_numer, ROUND_NOT_NEEDED); 02987 assign_r(q2.get_den(), max_denom, ROUND_NOT_NEEDED); 02988 q2.canonicalize(); 02989 02990 if (denominator > 0) { 02991 Relation_Symbol gr = min_included ? GREATER_OR_EQUAL : GREATER_THAN; 02992 Relation_Symbol lr = max_included ? LESS_OR_EQUAL : LESS_THAN; 02993 seq_v.build(i_constraint(gr, q1), i_constraint(lr, q2)); 02994 } 02995 else { 02996 Relation_Symbol gr = max_included ? GREATER_OR_EQUAL : GREATER_THAN; 02997 Relation_Symbol lr = min_included ? LESS_OR_EQUAL : LESS_THAN; 02998 seq_v.build(i_constraint(gr, q2), i_constraint(lr, q1)); 02999 } 03000 } 03001 else { 03002 // The `ub_expr' has a maximum value but the `lb_expr' 03003 // has no minimum value for the box. 03004 // Set the bounds for `var' using the maximum for `lb_expr'. 03005 PPL_DIRTY_TEMP(mpq_class, q); 03006 max_denom *= denominator; 03007 assign_r(q.get_num(), max_numer, ROUND_NOT_NEEDED); 03008 assign_r(q.get_den(), max_denom, ROUND_NOT_NEEDED); 03009 q.canonicalize(); 03010 Relation_Symbol rel = (denominator > 0) 03011 ? (max_included ? LESS_OR_EQUAL : LESS_THAN) 03012 : (max_included ? GREATER_OR_EQUAL : GREATER_THAN); 03013 seq_v.build(i_constraint(rel, q)); 03014 } 03015 } 03016 else if (minimize(lb_expr, min_numer, min_denom, min_included)) { 03017 // The `ub_expr' has no maximum value but the `lb_expr' 03018 // has a minimum value for the box. 03019 // Set the bounds for `var' using the minimum for `lb_expr'. 03020 min_denom *= denominator; 03021 PPL_DIRTY_TEMP(mpq_class, q); 03022 assign_r(q.get_num(), min_numer, ROUND_NOT_NEEDED); 03023 assign_r(q.get_den(), min_denom, ROUND_NOT_NEEDED); 03024 q.canonicalize(); 03025 03026 Relation_Symbol rel = (denominator > 0) 03027 ? (min_included ? GREATER_OR_EQUAL : GREATER_THAN) 03028 : (min_included ? LESS_OR_EQUAL : LESS_THAN); 03029 seq_v.build(i_constraint(rel, q)); 03030 } 03031 else { 03032 // The `ub_expr' has no maximum value and the `lb_expr' 03033 // has no minimum value for the box. 03034 // So we set the bounds to be unbounded. 03035 seq_v.assign(UNIVERSE); 03036 } 03037 } 03038 PPL_ASSERT(OK()); 03039 } 03040 03041 template <typename ITV> 03042 void 03043 Box<ITV> 03044 ::bounded_affine_preimage(const Variable var, 03045 const Linear_Expression& lb_expr, 03046 const Linear_Expression& ub_expr, 03047 Coefficient_traits::const_reference denominator) { 03048 // The denominator cannot be zero. 03049 const dimension_type space_dim = space_dimension(); 03050 if (denominator == 0) 03051 throw_invalid_argument("bounded_affine_preimage(v, lb, ub, d)", "d == 0"); 03052 03053 // Dimension-compatibility checks. 03054 // `var' should be one of the dimensions of the polyhedron. 03055 const dimension_type var_space_dim = var.space_dimension(); 03056 if (space_dim < var_space_dim) 03057 throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)", 03058 "v", var); 03059 // The dimension of `lb_expr' and `ub_expr' should not be 03060 // greater than the dimension of `*this'. 03061 const dimension_type lb_space_dim = lb_expr.space_dimension(); 03062 if (space_dim < lb_space_dim) 03063 throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)", 03064 "lb", lb_expr); 03065 const dimension_type ub_space_dim = ub_expr.space_dimension(); 03066 if (space_dim < ub_space_dim) 03067 throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)", 03068 "ub", ub_expr); 03069 03070 // Any preimage of an empty polyhedron is empty. 03071 if (marked_empty()) 03072 return; 03073 03074 const bool negative_denom = (denominator < 0); 03075 const Coefficient& lb_var_coeff = lb_expr.coefficient(var); 03076 const Coefficient& ub_var_coeff = ub_expr.coefficient(var); 03077 03078 // If the implied constraint between `ub_expr and `lb_expr' is 03079 // independent of `var', then impose it now. 03080 if (lb_var_coeff == ub_var_coeff) { 03081 if (negative_denom) 03082 refine_with_constraint(lb_expr >= ub_expr); 03083 else 03084 refine_with_constraint(lb_expr <= ub_expr); 03085 } 03086 03087 ITV& seq_var = seq[var.id()]; 03088 if (!seq_var.is_universe()) { 03089 // We want to work with a positive denominator, 03090 // so the sign and its (unsigned) value are separated. 03091 PPL_DIRTY_TEMP_COEFFICIENT(pos_denominator); 03092 pos_denominator = denominator; 03093 if (negative_denom) 03094 neg_assign(pos_denominator, pos_denominator); 03095 // Store all the information about the upper and lower bounds 03096 // for `var' before making this interval unbounded. 03097 bool open_lower = seq_var.lower_is_open(); 03098 bool unbounded_lower = seq_var.lower_is_boundary_infinity(); 03099 PPL_DIRTY_TEMP(mpq_class, q_seq_var_lower); 03100 PPL_DIRTY_TEMP(Coefficient, numer_lower); 03101 PPL_DIRTY_TEMP(Coefficient, denom_lower); 03102 if (!unbounded_lower) { 03103 assign_r(q_seq_var_lower, seq_var.lower(), ROUND_NOT_NEEDED); 03104 assign_r(numer_lower, q_seq_var_lower.get_num(), ROUND_NOT_NEEDED); 03105 assign_r(denom_lower, q_seq_var_lower.get_den(), ROUND_NOT_NEEDED); 03106 if (negative_denom) 03107 neg_assign(denom_lower, denom_lower); 03108 numer_lower *= pos_denominator; 03109 seq_var.lower_extend(); 03110 } 03111 bool open_upper = seq_var.upper_is_open(); 03112 bool unbounded_upper = seq_var.upper_is_boundary_infinity(); 03113 PPL_DIRTY_TEMP(mpq_class, q_seq_var_upper); 03114 PPL_DIRTY_TEMP(Coefficient, numer_upper); 03115 PPL_DIRTY_TEMP(Coefficient, denom_upper); 03116 if (!unbounded_upper) { 03117 assign_r(q_seq_var_upper, seq_var.upper(), ROUND_NOT_NEEDED); 03118 assign_r(numer_upper, q_seq_var_upper.get_num(), ROUND_NOT_NEEDED); 03119 assign_r(denom_upper, q_seq_var_upper.get_den(), ROUND_NOT_NEEDED); 03120 if (negative_denom) 03121 neg_assign(denom_upper, denom_upper); 03122 numer_upper *= pos_denominator; 03123 seq_var.upper_extend(); 03124 } 03125 03126 if (!unbounded_lower) { 03127 // `lb_expr' is revised by removing the `var' component, 03128 // multiplying by `-' denominator of the lower bound for `var', 03129 // and adding the lower bound for `var' to the inhomogeneous term. 03130 Linear_Expression revised_lb_expr(ub_expr); 03131 revised_lb_expr -= ub_var_coeff * var; 03132 PPL_DIRTY_TEMP(Coefficient, d); 03133 neg_assign(d, denom_lower); 03134 revised_lb_expr *= d; 03135 revised_lb_expr += numer_lower; 03136 03137 // Find the minimum value for the revised lower bound expression 03138 // and use this to refine the appropriate bound. 03139 bool included; 03140 PPL_DIRTY_TEMP(Coefficient, denom); 03141 if (minimize(revised_lb_expr, numer_lower, denom, included)) { 03142 denom_lower *= (denom * ub_var_coeff); 03143 PPL_DIRTY_TEMP(mpq_class, q); 03144 assign_r(q.get_num(), numer_lower, ROUND_NOT_NEEDED); 03145 assign_r(q.get_den(), denom_lower, ROUND_NOT_NEEDED); 03146 q.canonicalize(); 03147 if (!included) 03148 open_lower = true; 03149 Relation_Symbol rel; 03150 if ((ub_var_coeff >= 0) ? !negative_denom : negative_denom) 03151 rel = open_lower ? GREATER_THAN : GREATER_OR_EQUAL; 03152 else 03153 rel = open_lower ? LESS_THAN : LESS_OR_EQUAL; 03154 seq_var.add_constraint(i_constraint(rel, q)); 03155 if (seq_var.is_empty()) { 03156 set_empty(); 03157 return; 03158 } 03159 } 03160 } 03161 03162 if (!unbounded_upper) { 03163 // `ub_expr' is revised by removing the `var' component, 03164 // multiplying by `-' denominator of the upper bound for `var', 03165 // and adding the upper bound for `var' to the inhomogeneous term. 03166 Linear_Expression revised_ub_expr(lb_expr); 03167 revised_ub_expr -= lb_var_coeff * var; 03168 PPL_DIRTY_TEMP(Coefficient, d); 03169 neg_assign(d, denom_upper); 03170 revised_ub_expr *= d; 03171 revised_ub_expr += numer_upper; 03172 03173 // Find the maximum value for the revised upper bound expression 03174 // and use this to refine the appropriate bound. 03175 bool included; 03176 PPL_DIRTY_TEMP(Coefficient, denom); 03177 if (maximize(revised_ub_expr, numer_upper, denom, included)) { 03178 denom_upper *= (denom * lb_var_coeff); 03179 PPL_DIRTY_TEMP(mpq_class, q); 03180 assign_r(q.get_num(), numer_upper, ROUND_NOT_NEEDED); 03181 assign_r(q.get_den(), denom_upper, ROUND_NOT_NEEDED); 03182 q.canonicalize(); 03183 if (!included) 03184 open_upper = true; 03185 Relation_Symbol rel; 03186 if ((lb_var_coeff >= 0) ? !negative_denom : negative_denom) 03187 rel = open_upper ? LESS_THAN : LESS_OR_EQUAL; 03188 else 03189 rel = open_upper ? GREATER_THAN : GREATER_OR_EQUAL; 03190 seq_var.add_constraint(i_constraint(rel, q)); 03191 if (seq_var.is_empty()) { 03192 set_empty(); 03193 return; 03194 } 03195 } 03196 } 03197 } 03198 03199 // If the implied constraint between `ub_expr and `lb_expr' is 03200 // dependent on `var', then impose on the new box. 03201 if (lb_var_coeff != ub_var_coeff) { 03202 if (denominator > 0) 03203 refine_with_constraint(lb_expr <= ub_expr); 03204 else 03205 refine_with_constraint(lb_expr >= ub_expr); 03206 } 03207 03208 PPL_ASSERT(OK()); 03209 } 03210 03211 template <typename ITV> 03212 void 03213 Box<ITV> 03214 ::generalized_affine_image(const Variable var, 03215 const Relation_Symbol relsym, 03216 const Linear_Expression& expr, 03217 Coefficient_traits::const_reference denominator) { 03218 // The denominator cannot be zero. 03219 if (denominator == 0) 03220 throw_invalid_argument("generalized_affine_image(v, r, e, d)", "d == 0"); 03221 03222 // Dimension-compatibility checks. 03223 const dimension_type space_dim = space_dimension(); 03224 // The dimension of `expr' should not be greater than the dimension 03225 // of `*this'. 03226 if (space_dim < expr.space_dimension()) 03227 throw_dimension_incompatible("generalized_affine_image(v, r, e, d)", 03228 "e", expr); 03229 // `var' should be one of the dimensions of the box. 03230 const dimension_type var_space_dim = var.space_dimension(); 03231 if (space_dim < var_space_dim) 03232 throw_dimension_incompatible("generalized_affine_image(v, r, e, d)", 03233 "v", var); 03234 03235 // The relation symbol cannot be a disequality. 03236 if (relsym == NOT_EQUAL) 03237 throw_invalid_argument("generalized_affine_image(v, r, e, d)", 03238 "r is the disequality relation symbol"); 03239 03240 // First compute the affine image. 03241 affine_image(var, expr, denominator); 03242 03243 if (relsym == EQUAL) 03244 // The affine relation is indeed an affine function. 03245 return; 03246 03247 // Any image of an empty box is empty. 03248 if (is_empty()) 03249 return; 03250 03251 ITV& seq_var = seq[var.id()]; 03252 switch (relsym) { 03253 case LESS_OR_EQUAL: 03254 seq_var.lower_extend(); 03255 break; 03256 case LESS_THAN: 03257 seq_var.lower_extend(); 03258 if (!seq_var.upper_is_boundary_infinity()) 03259 seq_var.remove_sup(); 03260 break; 03261 case GREATER_OR_EQUAL: 03262 seq_var.upper_extend(); 03263 break; 03264 case GREATER_THAN: 03265 seq_var.upper_extend(); 03266 if (!seq_var.lower_is_boundary_infinity()) 03267 seq_var.remove_inf(); 03268 break; 03269 default: 03270 // The EQUAL and NOT_EQUAL cases have been already dealt with. 03271 PPL_UNREACHABLE; 03272 break; 03273 } 03274 PPL_ASSERT(OK()); 03275 } 03276 03277 template <typename ITV> 03278 void 03279 Box<ITV> 03280 ::generalized_affine_preimage(const Variable var, 03281 const Relation_Symbol relsym, 03282 const Linear_Expression& expr, 03283 Coefficient_traits::const_reference denominator) 03284 { 03285 // The denominator cannot be zero. 03286 if (denominator == 0) 03287 throw_invalid_argument("generalized_affine_preimage(v, r, e, d)", 03288 "d == 0"); 03289 03290 // Dimension-compatibility checks. 03291 const dimension_type space_dim = space_dimension(); 03292 // The dimension of `expr' should not be greater than the dimension 03293 // of `*this'. 03294 if (space_dim < expr.space_dimension()) 03295 throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)", 03296 "e", expr); 03297 // `var' should be one of the dimensions of the box. 03298 const dimension_type var_space_dim = var.space_dimension(); 03299 if (space_dim < var_space_dim) 03300 throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)", 03301 "v", var); 03302 // The relation symbol cannot be a disequality. 03303 if (relsym == NOT_EQUAL) 03304 throw_invalid_argument("generalized_affine_preimage(v, r, e, d)", 03305 "r is the disequality relation symbol"); 03306 03307 // Check whether the affine relation is indeed an affine function. 03308 if (relsym == EQUAL) { 03309 affine_preimage(var, expr, denominator); 03310 return; 03311 } 03312 03313 // Compute the reversed relation symbol to simplify later coding. 03314 Relation_Symbol reversed_relsym; 03315 switch (relsym) { 03316 case LESS_THAN: 03317 reversed_relsym = GREATER_THAN; 03318 break; 03319 case LESS_OR_EQUAL: 03320 reversed_relsym = GREATER_OR_EQUAL; 03321 break; 03322 case GREATER_OR_EQUAL: 03323 reversed_relsym = LESS_OR_EQUAL; 03324 break; 03325 case GREATER_THAN: 03326 reversed_relsym = LESS_THAN; 03327 break; 03328 default: 03329 // The EQUAL and NOT_EQUAL cases have been already dealt with. 03330 PPL_UNREACHABLE; 03331 break; 03332 } 03333 03334 // Check whether the preimage of this affine relation can be easily 03335 // computed as the image of its inverse relation. 03336 const Coefficient& var_coefficient = expr.coefficient(var); 03337 if (var_coefficient != 0) { 03338 Linear_Expression inverse_expr 03339 = expr - (denominator + var_coefficient) * var; 03340 PPL_DIRTY_TEMP_COEFFICIENT(inverse_denominator); 03341 neg_assign(inverse_denominator, var_coefficient); 03342 Relation_Symbol inverse_relsym 03343 = (sgn(denominator) == sgn(inverse_denominator)) 03344 ? relsym 03345 : reversed_relsym; 03346 generalized_affine_image(var, inverse_relsym, inverse_expr, 03347 inverse_denominator); 03348 return; 03349 } 03350 03351 // Here `var_coefficient == 0', so that the preimage cannot 03352 // be easily computed by inverting the affine relation. 03353 // Shrink the box by adding the constraint induced 03354 // by the affine relation. 03355 // First, compute the maximum and minimum value reached by 03356 // `denominator*var' on the box as we need to use non-relational 03357 // expressions. 03358 PPL_DIRTY_TEMP(Coefficient, max_numer); 03359 PPL_DIRTY_TEMP(Coefficient, max_denom); 03360 bool max_included; 03361 bool bound_above = maximize(denominator*var, max_numer, max_denom, max_included); 03362 PPL_DIRTY_TEMP(Coefficient, min_numer); 03363 PPL_DIRTY_TEMP(Coefficient, min_denom); 03364 bool min_included; 03365 bool bound_below = minimize(denominator*var, min_numer, min_denom, min_included); 03366 // Use the correct relation symbol 03367 const Relation_Symbol corrected_relsym 03368 = (denominator > 0) ? relsym : reversed_relsym; 03369 // Revise the expression to take into account the denominator of the 03370 // maximum/minimum value for `var'. 03371 PPL_DIRTY_TEMP(Linear_Expression, revised_expr); 03372 dimension_type dim = space_dim; 03373 PPL_DIRTY_TEMP_COEFFICIENT(d); 03374 if (corrected_relsym == LESS_THAN || corrected_relsym == LESS_OR_EQUAL) { 03375 if (bound_below) { 03376 for ( ; dim > 0; dim--) { 03377 d = min_denom * expr.coefficient(Variable(dim - 1)); 03378 revised_expr += d * Variable(dim - 1); 03379 } 03380 } 03381 } 03382 else { 03383 if (bound_above) { 03384 for ( ; dim > 0; dim--) { 03385 d = max_denom * expr.coefficient(Variable(dim - 1)); 03386 revised_expr += d * Variable(dim - 1); 03387 } 03388 } 03389 } 03390 03391 switch (corrected_relsym) { 03392 case LESS_THAN: 03393 if (bound_below) 03394 refine_with_constraint(min_numer < revised_expr); 03395 break; 03396 case LESS_OR_EQUAL: 03397 if (bound_below) 03398 (min_included) 03399 ? refine_with_constraint(min_numer <= revised_expr) 03400 : refine_with_constraint(min_numer < revised_expr); 03401 break; 03402 case GREATER_OR_EQUAL: 03403 if (bound_above) 03404 (max_included) 03405 ? refine_with_constraint(max_numer >= revised_expr) 03406 : refine_with_constraint(max_numer > revised_expr); 03407 break; 03408 case GREATER_THAN: 03409 if (bound_above) 03410 refine_with_constraint(max_numer > revised_expr); 03411 break; 03412 default: 03413 // The EQUAL and NOT_EQUAL cases have been already dealt with. 03414 PPL_UNREACHABLE; 03415 break; 03416 } 03417 // If the shrunk box is empty, its preimage is empty too. 03418 if (is_empty()) 03419 return; 03420 ITV& seq_v = seq[var.id()]; 03421 seq_v.assign(UNIVERSE); 03422 PPL_ASSERT(OK()); 03423 } 03424 03425 template <typename ITV> 03426 void 03427 Box<ITV> 03428 ::generalized_affine_image(const Linear_Expression& lhs, 03429 const Relation_Symbol relsym, 03430 const Linear_Expression& rhs) { 03431 // Dimension-compatibility checks. 03432 // The dimension of `lhs' should not be greater than the dimension 03433 // of `*this'. 03434 dimension_type lhs_space_dim = lhs.space_dimension(); 03435 const dimension_type space_dim = space_dimension(); 03436 if (space_dim < lhs_space_dim) 03437 throw_dimension_incompatible("generalized_affine_image(e1, r, e2)", 03438 "e1", lhs); 03439 // The dimension of `rhs' should not be greater than the dimension 03440 // of `*this'. 03441 const dimension_type rhs_space_dim = rhs.space_dimension(); 03442 if (space_dim < rhs_space_dim) 03443 throw_dimension_incompatible("generalized_affine_image(e1, r, e2)", 03444 "e2", rhs); 03445 03446 // The relation symbol cannot be a disequality. 03447 if (relsym == NOT_EQUAL) 03448 throw_invalid_argument("generalized_affine_image(e1, r, e2)", 03449 "r is the disequality relation symbol"); 03450 03451 // Any image of an empty box is empty. 03452 if (marked_empty()) 03453 return; 03454 03455 // Compute the maximum and minimum value reached by the rhs on the box. 03456 PPL_DIRTY_TEMP(Coefficient, max_numer); 03457 PPL_DIRTY_TEMP(Coefficient, max_denom); 03458 bool max_included; 03459 bool max_rhs = maximize(rhs, max_numer, max_denom, max_included); 03460 PPL_DIRTY_TEMP(Coefficient, min_numer); 03461 PPL_DIRTY_TEMP(Coefficient, min_denom); 03462 bool min_included; 03463 bool min_rhs = minimize(rhs, min_numer, min_denom, min_included); 03464 03465 // Check whether there is 0, 1 or more than one variable in the lhs 03466 // and record the variable with the highest dimension; set the box 03467 // intervals to be unbounded for all other dimensions with non-zero 03468 // coefficients in the lhs. 03469 bool has_var = false; 03470 bool has_more_than_one_var = false; 03471 // Initialization is just to avoid an annoying warning. 03472 dimension_type has_var_id = 0; 03473 for ( ; lhs_space_dim > 0; --lhs_space_dim) 03474 if (lhs.coefficient(Variable(lhs_space_dim - 1)) != 0) { 03475 if (has_var) { 03476 ITV& seq_i = seq[lhs_space_dim - 1]; 03477 seq_i.assign(UNIVERSE); 03478 has_more_than_one_var = true; 03479 } 03480 else { 03481 has_var = true; 03482 has_var_id = lhs_space_dim - 1; 03483 } 03484 } 03485 03486 if (has_more_than_one_var) { 03487 // There is more than one dimension with non-zero coefficient, so 03488 // we cannot have any information about the dimensions in the lhs. 03489 // Since all but the highest dimension with non-zero coefficient 03490 // in the lhs have been set unbounded, it remains to set the 03491 // highest dimension in the lhs unbounded. 03492 ITV& seq_var = seq[has_var_id]; 03493 seq_var.assign(UNIVERSE); 03494 PPL_ASSERT(OK()); 03495 return; 03496 } 03497 03498 if (has_var) { 03499 // There is exactly one dimension with non-zero coefficient. 03500 ITV& seq_var = seq[has_var_id]; 03501 03502 // Compute the new bounds for this dimension defined by the rhs 03503 // expression. 03504 const Coefficient& inhomo = lhs.inhomogeneous_term(); 03505 const Coefficient& coeff = lhs.coefficient(Variable(has_var_id)); 03506 PPL_DIRTY_TEMP(mpq_class, q_max); 03507 PPL_DIRTY_TEMP(mpq_class, q_min); 03508 if (max_rhs) { 03509 max_numer -= inhomo * max_denom; 03510 max_denom *= coeff; 03511 assign_r(q_max.get_num(), max_numer, ROUND_NOT_NEEDED); 03512 assign_r(q_max.get_den(), max_denom, ROUND_NOT_NEEDED); 03513 q_max.canonicalize(); 03514 } 03515 if (min_rhs) { 03516 min_numer -= inhomo * min_denom; 03517 min_denom *= coeff; 03518 assign_r(q_min.get_num(), min_numer, ROUND_NOT_NEEDED); 03519 assign_r(q_min.get_den(), min_denom, ROUND_NOT_NEEDED); 03520 q_min.canonicalize(); 03521 } 03522 03523 // The choice as to which bounds should be set depends on the sign 03524 // of the coefficient of the dimension `has_var_id' in the lhs. 03525 if (coeff > 0) 03526 // The coefficient of the dimension in the lhs is positive. 03527 switch (relsym) { 03528 case LESS_OR_EQUAL: 03529 if (max_rhs) { 03530 Relation_Symbol rel = max_included ? LESS_OR_EQUAL : LESS_THAN; 03531 seq_var.build(i_constraint(rel, q_max)); 03532 } 03533 else 03534 seq_var.assign(UNIVERSE); 03535 break; 03536 case LESS_THAN: 03537 if (max_rhs) 03538 seq_var.build(i_constraint(LESS_THAN, q_max)); 03539 else 03540 seq_var.assign(UNIVERSE); 03541 break; 03542 case EQUAL: 03543 { 03544 I_Constraint<mpq_class> l; 03545 I_Constraint<mpq_class> u; 03546 if (max_rhs) 03547 u.set(max_included ? LESS_OR_EQUAL : LESS_THAN, q_max); 03548 if (min_rhs) 03549 l.set(min_included ? GREATER_OR_EQUAL : GREATER_THAN, q_min); 03550 seq_var.build(l, u); 03551 break; 03552 } 03553 case GREATER_OR_EQUAL: 03554 if (min_rhs) { 03555 Relation_Symbol rel = min_included ? GREATER_OR_EQUAL : GREATER_THAN; 03556 seq_var.build(i_constraint(rel, q_min)); 03557 } 03558 else 03559 seq_var.assign(UNIVERSE); 03560 break; 03561 case GREATER_THAN: 03562 if (min_rhs) 03563 seq_var.build(i_constraint(GREATER_THAN, q_min)); 03564 else 03565 seq_var.assign(UNIVERSE); 03566 break; 03567 default: 03568 // The NOT_EQUAL case has been already dealt with. 03569 PPL_UNREACHABLE; 03570 break; 03571 } 03572 else 03573 // The coefficient of the dimension in the lhs is negative. 03574 switch (relsym) { 03575 case GREATER_OR_EQUAL: 03576 if (min_rhs) { 03577 Relation_Symbol rel = min_included ? LESS_OR_EQUAL : LESS_THAN; 03578 seq_var.build(i_constraint(rel, q_min)); 03579 } 03580 else 03581 seq_var.assign(UNIVERSE); 03582 break; 03583 case GREATER_THAN: 03584 if (min_rhs) 03585 seq_var.build(i_constraint(LESS_THAN, q_min)); 03586 else 03587 seq_var.assign(UNIVERSE); 03588 break; 03589 case EQUAL: 03590 { 03591 I_Constraint<mpq_class> l; 03592 I_Constraint<mpq_class> u; 03593 if (max_rhs) 03594 l.set(max_included ? GREATER_OR_EQUAL : GREATER_THAN, q_max); 03595 if (min_rhs) 03596 u.set(min_included ? LESS_OR_EQUAL : LESS_THAN, q_min); 03597 seq_var.build(l, u); 03598 break; 03599 } 03600 case LESS_OR_EQUAL: 03601 if (max_rhs) { 03602 Relation_Symbol rel = max_included ? GREATER_OR_EQUAL : GREATER_THAN; 03603 seq_var.build(i_constraint(rel, q_max)); 03604 } 03605 else 03606 seq_var.assign(UNIVERSE); 03607 break; 03608 case LESS_THAN: 03609 if (max_rhs) 03610 seq_var.build(i_constraint(GREATER_THAN, q_max)); 03611 else 03612 seq_var.assign(UNIVERSE); 03613 break; 03614 default: 03615 // The NOT_EQUAL case has been already dealt with. 03616 PPL_UNREACHABLE; 03617 break; 03618 } 03619 } 03620 03621 else { 03622 // The lhs is a constant value, so we just need to add the 03623 // appropriate constraint. 03624 const Coefficient& inhomo = lhs.inhomogeneous_term(); 03625 switch (relsym) { 03626 case LESS_THAN: 03627 refine_with_constraint(inhomo < rhs); 03628 break; 03629 case LESS_OR_EQUAL: 03630 refine_with_constraint(inhomo <= rhs); 03631 break; 03632 case EQUAL: 03633 refine_with_constraint(inhomo == rhs); 03634 break; 03635 case GREATER_OR_EQUAL: 03636 refine_with_constraint(inhomo >= rhs); 03637 break; 03638 case GREATER_THAN: 03639 refine_with_constraint(inhomo > rhs); 03640 break; 03641 default: 03642 // The NOT_EQUAL case has been already dealt with. 03643 PPL_UNREACHABLE; 03644 break; 03645 } 03646 } 03647 PPL_ASSERT(OK()); 03648 } 03649 03650 template <typename ITV> 03651 void 03652 Box<ITV>::generalized_affine_preimage(const Linear_Expression& lhs, 03653 const Relation_Symbol relsym, 03654 const Linear_Expression& rhs) { 03655 // Dimension-compatibility checks. 03656 // The dimension of `lhs' should not be greater than the dimension 03657 // of `*this'. 03658 dimension_type lhs_space_dim = lhs.space_dimension(); 03659 const dimension_type space_dim = space_dimension(); 03660 if (space_dim < lhs_space_dim) 03661 throw_dimension_incompatible("generalized_affine_image(e1, r, e2)", 03662 "e1", lhs); 03663 // The dimension of `rhs' should not be greater than the dimension 03664 // of `*this'. 03665 const dimension_type rhs_space_dim = rhs.space_dimension(); 03666 if (space_dim < rhs_space_dim) 03667 throw_dimension_incompatible("generalized_affine_image(e1, r, e2)", 03668 "e2", rhs); 03669 03670 // The relation symbol cannot be a disequality. 03671 if (relsym == NOT_EQUAL) 03672 throw_invalid_argument("generalized_affine_image(e1, r, e2)", 03673 "r is the disequality relation symbol"); 03674 03675 // Any image of an empty box is empty. 03676 if (marked_empty()) 03677 return; 03678 03679 // For any dimension occurring in the lhs, swap and change the sign 03680 // of this component for the rhs and lhs. Then use these in a call 03681 // to generalized_affine_image/3. 03682 Linear_Expression revised_lhs = lhs; 03683 Linear_Expression revised_rhs = rhs; 03684 for (dimension_type d = lhs_space_dim; d-- > 0; ) { 03685 const Variable var(d); 03686 if (lhs.coefficient(var) != 0) { 03687 PPL_DIRTY_TEMP(Coefficient, temp); 03688 temp = rhs.coefficient(var) + lhs.coefficient(var); 03689 revised_rhs -= temp * var; 03690 revised_lhs -= temp * var; 03691 } 03692 } 03693 generalized_affine_image(revised_lhs, relsym, revised_rhs); 03694 PPL_ASSERT(OK()); 03695 } 03696 03697 template <typename ITV> 03698 template <typename T, typename Iterator> 03699 typename Enable_If<Is_Same<T, Box<ITV> >::value 03700 && Is_Same_Or_Derived<Interval_Base, ITV>::value, 03701 void>::type 03702 Box<ITV>::CC76_widening_assign(const T& y, Iterator first, Iterator last) { 03703 if (y.is_empty()) 03704 return; 03705 03706 for (dimension_type i = seq.size(); i-- > 0; ) 03707 seq[i].CC76_widening_assign(y.seq[i], first, last); 03708 03709 PPL_ASSERT(OK()); 03710 } 03711 03712 template <typename ITV> 03713 template <typename T> 03714 typename Enable_If<Is_Same<T, Box<ITV> >::value 03715 && Is_Same_Or_Derived<Interval_Base, ITV>::value, 03716 void>::type 03717 Box<ITV>::CC76_widening_assign(const T& y, unsigned* tp) { 03718 static typename ITV::boundary_type stop_points[] = { 03719 typename ITV::boundary_type(-2), 03720 typename ITV::boundary_type(-1), 03721 typename ITV::boundary_type(0), 03722 typename ITV::boundary_type(1), 03723 typename ITV::boundary_type(2) 03724 }; 03725 03726 Box& x = *this; 03727 // If there are tokens available, work on a temporary copy. 03728 if (tp != 0 && *tp > 0) { 03729 Box<ITV> x_tmp(x); 03730 x_tmp.CC76_widening_assign(y, 0); 03731 // If the widening was not precise, use one of the available tokens. 03732 if (!x.contains(x_tmp)) 03733 --(*tp); 03734 return; 03735 } 03736 x.CC76_widening_assign(y, 03737 stop_points, 03738 stop_points 03739 + sizeof(stop_points)/sizeof(stop_points[0])); 03740 } 03741 03742 template <typename ITV> 03743 void 03744 Box<ITV>::get_limiting_box(const Constraint_System& cs, 03745 Box& limiting_box) const { 03746 const dimension_type cs_space_dim = cs.space_dimension(); 03747 // Private method: the caller has to ensure the following. 03748 PPL_ASSERT(cs_space_dim <= space_dimension()); 03749 03750 for (Constraint_System::const_iterator cs_i = cs.begin(), 03751 cs_end = cs.end(); cs_i != cs_end; ++cs_i) { 03752 const Constraint& c = *cs_i; 03753 dimension_type c_num_vars = 0; 03754 dimension_type c_only_var = 0; 03755 // Constraints that are not interval constraints are ignored. 03756 if (!extract_interval_constraint(c, cs_space_dim, c_num_vars, c_only_var)) 03757 continue; 03758 // Trivial constraints are ignored. 03759 if (c_num_vars != 0) { 03760 // c is a non-trivial interval constraint. 03761 // add interval constraint to limiting box 03762 const Coefficient& n = c.inhomogeneous_term(); 03763 const Coefficient& d = c.coefficient(Variable(c_only_var)); 03764 if (interval_relation(seq[c_only_var], c.type(), n, d) 03765 == Poly_Con_Relation::is_included()) 03766 limiting_box.add_interval_constraint_no_check(c_only_var, c.type(), 03767 n, d); 03768 } 03769 } 03770 } 03771 03772 template <typename ITV> 03773 void 03774 Box<ITV>::limited_CC76_extrapolation_assign(const Box& y, 03775 const Constraint_System& cs, 03776 unsigned* tp) { 03777 Box& x = *this; 03778 const dimension_type space_dim = x.space_dimension(); 03779 03780 // Dimension-compatibility check. 03781 if (space_dim != y.space_dimension()) 03782 throw_dimension_incompatible("limited_CC76_extrapolation_assign(y, cs)", 03783 y); 03784 // `cs' must be dimension-compatible with the two boxes. 03785 const dimension_type cs_space_dim = cs.space_dimension(); 03786 if (space_dim < cs_space_dim) 03787 throw_constraint_incompatible("limited_CC76_extrapolation_assign(y, cs)"); 03788 03789 // The limited CC76-extrapolation between two boxes in a 03790 // zero-dimensional space is also a zero-dimensional box 03791 if (space_dim == 0) 03792 return; 03793 03794 // Assume `y' is contained in or equal to `*this'. 03795 PPL_EXPECT_HEAVY(copy_contains(*this, y)); 03796 03797 // If `*this' is empty, since `*this' contains `y', `y' is empty too. 03798 if (marked_empty()) 03799 return; 03800 // If `y' is empty, we return. 03801 if (y.marked_empty()) 03802 return; 03803 03804 // Build a limiting box using all the constraints in cs 03805 // that are satisfied by *this. 03806 Box limiting_box(space_dim, UNIVERSE); 03807 get_limiting_box(cs, limiting_box); 03808 03809 x.CC76_widening_assign(y, tp); 03810 03811 // Intersect the widened box with the limiting box. 03812 intersection_assign(limiting_box); 03813 } 03814 03815 template <typename ITV> 03816 template <typename T> 03817 typename Enable_If<Is_Same<T, Box<ITV> >::value 03818 && Is_Same_Or_Derived<Interval_Base, ITV>::value, 03819 void>::type 03820 Box<ITV>::CC76_narrowing_assign(const T& y) { 03821 const dimension_type space_dim = space_dimension(); 03822 03823 // Dimension-compatibility check. 03824 if (space_dim != y.space_dimension()) 03825 throw_dimension_incompatible("CC76_narrowing_assign(y)", y); 03826 03827 // Assume `*this' is contained in or equal to `y'. 03828 PPL_EXPECT_HEAVY(copy_contains(y, *this)); 03829 03830 // If both boxes are zero-dimensional, 03831 // since `y' contains `*this', we simply return `*this'. 03832 if (space_dim == 0) 03833 return; 03834 03835 // If `y' is empty, since `y' contains `this', `*this' is empty too. 03836 if (y.is_empty()) 03837 return; 03838 // If `*this' is empty, we return. 03839 if (is_empty()) 03840 return; 03841 03842 // Replace each constraint in `*this' by the corresponding constraint 03843 // in `y' if the corresponding inhomogeneous terms are both finite. 03844 for (dimension_type i = space_dim; i-- > 0; ) { 03845 ITV& x_i = seq[i]; 03846 const ITV& y_i = y.seq[i]; 03847 if (!x_i.lower_is_boundary_infinity() 03848 && !y_i.lower_is_boundary_infinity() 03849 && x_i.lower() != y_i.lower()) 03850 x_i.lower() = y_i.lower(); 03851 if (!x_i.upper_is_boundary_infinity() 03852 && !y_i.upper_is_boundary_infinity() 03853 && x_i.upper() != y_i.upper()) 03854 x_i.upper() = y_i.upper(); 03855 } 03856 PPL_ASSERT(OK()); 03857 } 03858 03859 template <typename ITV> 03860 Constraint_System 03861 Box<ITV>::constraints() const { 03862 const dimension_type space_dim = space_dimension(); 03863 if (space_dim == 0) { 03864 if (marked_empty()) 03865 return Constraint_System::zero_dim_empty(); 03866 else 03867 return Constraint_System(); 03868 } 03869 03870 if (marked_empty()) { 03871 Constraint_System cs; 03872 cs.insert(0*Variable(space_dim-1) <= -1); 03873 return cs; 03874 } 03875 03876 Constraint_System cs; 03877 // KLUDGE: in the future `cs' will be constructed of the right dimension. 03878 // For the time being, we force the dimension with the following line. 03879 cs.insert(0*Variable(space_dim-1) <= 0); 03880 03881 for (dimension_type k = 0; k < space_dim; ++k) { 03882 const Variable v_k = Variable(k); 03883 PPL_DIRTY_TEMP(Coefficient, n); 03884 PPL_DIRTY_TEMP(Coefficient, d); 03885 bool closed = false; 03886 if (has_lower_bound(v_k, n, d, closed)) { 03887 if (closed) 03888 cs.insert(d * v_k >= n); 03889 else 03890 cs.insert(d * v_k > n); 03891 } 03892 if (has_upper_bound(v_k, n, d, closed)) { 03893 if (closed) 03894 cs.insert(d * v_k <= n); 03895 else 03896 cs.insert(d * v_k < n); 03897 } 03898 } 03899 return cs; 03900 } 03901 03902 template <typename ITV> 03903 Constraint_System 03904 Box<ITV>::minimized_constraints() const { 03905 const dimension_type space_dim = space_dimension(); 03906 if (space_dim == 0) { 03907 if (marked_empty()) 03908 return Constraint_System::zero_dim_empty(); 03909 else 03910 return Constraint_System(); 03911 } 03912 03913 // Make sure emptiness is detected. 03914 if (is_empty()) { 03915 Constraint_System cs; 03916 cs.insert(0*Variable(space_dim-1) <= -1); 03917 return cs; 03918 } 03919 03920 Constraint_System cs; 03921 // KLUDGE: in the future `cs' will be constructed of the right dimension. 03922 // For the time being, we force the dimension with the following line. 03923 cs.insert(0*Variable(space_dim-1) <= 0); 03924 03925 for (dimension_type k = 0; k < space_dim; ++k) { 03926 const Variable v_k = Variable(k); 03927 PPL_DIRTY_TEMP(Coefficient, n); 03928 PPL_DIRTY_TEMP(Coefficient, d); 03929 bool closed = false; 03930 if (has_lower_bound(v_k, n, d, closed)) { 03931 if (closed) 03932 // Make sure equality constraints are detected. 03933 if (seq[k].is_singleton()) { 03934 cs.insert(d * v_k == n); 03935 continue; 03936 } 03937 else 03938 cs.insert(d * v_k >= n); 03939 else 03940 cs.insert(d * v_k > n); 03941 } 03942 if (has_upper_bound(v_k, n, d, closed)) { 03943 if (closed) 03944 cs.insert(d * v_k <= n); 03945 else 03946 cs.insert(d * v_k < n); 03947 } 03948 } 03949 return cs; 03950 } 03951 03952 template <typename ITV> 03953 Congruence_System 03954 Box<ITV>::congruences() const { 03955 const dimension_type space_dim = space_dimension(); 03956 if (space_dim == 0) { 03957 if (marked_empty()) 03958 return Congruence_System::zero_dim_empty(); 03959 else 03960 return Congruence_System(); 03961 } 03962 03963 // Make sure emptiness is detected. 03964 if (is_empty()) { 03965 Congruence_System cgs; 03966 cgs.insert((0*Variable(space_dim-1) %= -1) / 0); 03967 return cgs; 03968 } 03969 03970 Congruence_System cgs; 03971 // KLUDGE: in the future `cgs' will be constructed of the right dimension. 03972 // For the time being, we force the dimension with the following line. 03973 cgs.insert(0*Variable(space_dim-1) %= 0); 03974 03975 for (dimension_type k = 0; k < space_dim; ++k) { 03976 const Variable v_k = Variable(k); 03977 PPL_DIRTY_TEMP(Coefficient, n); 03978 PPL_DIRTY_TEMP(Coefficient, d); 03979 bool closed = false; 03980 if (has_lower_bound(v_k, n, d, closed) && closed) 03981 // Make sure equality congruences are detected. 03982 if (seq[k].is_singleton()) 03983 cgs.insert((d * v_k %= n) / 0); 03984 } 03985 return cgs; 03986 } 03987 03988 template <typename ITV> 03989 memory_size_type 03990 Box<ITV>::external_memory_in_bytes() const { 03991 memory_size_type n = seq.capacity() * sizeof(ITV); 03992 for (dimension_type k = seq.size(); k-- > 0; ) 03993 n += seq[k].external_memory_in_bytes(); 03994 return n; 03995 } 03996 03998 template <typename ITV> 03999 std::ostream& 04000 IO_Operators::operator<<(std::ostream& s, const Box<ITV>& box) { 04001 if (box.is_empty()) 04002 s << "false"; 04003 else if (box.is_universe()) 04004 s << "true"; 04005 else 04006 for (dimension_type k = 0, 04007 space_dim = box.space_dimension(); k < space_dim; ) { 04008 s << Variable(k) << " in " << box[k]; 04009 ++k; 04010 if (k < space_dim) 04011 s << ", "; 04012 else 04013 break; 04014 } 04015 return s; 04016 } 04017 04018 template <typename ITV> 04019 void 04020 Box<ITV>::ascii_dump(std::ostream& s) const { 04021 const char separator = ' '; 04022 status.ascii_dump(s); 04023 const dimension_type space_dim = space_dimension(); 04024 s << "space_dim" << separator << space_dim; 04025 s << "\n"; 04026 for (dimension_type i = 0; i < space_dim; ++i) 04027 seq[i].ascii_dump(s); 04028 } 04029 04030 PPL_OUTPUT_TEMPLATE_DEFINITIONS(ITV, Box<ITV>) 04031 04032 template <typename ITV> 04033 bool 04034 Box<ITV>::ascii_load(std::istream& s) { 04035 if (!status.ascii_load(s)) 04036 return false; 04037 04038 std::string str; 04039 dimension_type space_dim; 04040 if (!(s >> str) || str != "space_dim") 04041 return false; 04042 if (!(s >> space_dim)) 04043 return false; 04044 04045 seq.clear(); 04046 ITV seq_i; 04047 for (dimension_type i = 0; i < space_dim; ++i) { 04048 if (seq_i.ascii_load(s)) 04049 seq.push_back(seq_i); 04050 else 04051 return false; 04052 } 04053 04054 // Check invariants. 04055 PPL_ASSERT(OK()); 04056 return true; 04057 } 04058 04059 template <typename ITV> 04060 void 04061 Box<ITV>::throw_dimension_incompatible(const char* method, 04062 const Box& y) const { 04063 std::ostringstream s; 04064 s << "PPL::Box::" << method << ":" << std::endl 04065 << "this->space_dimension() == " << this->space_dimension() 04066 << ", y->space_dimension() == " << y.space_dimension() << "."; 04067 throw std::invalid_argument(s.str()); 04068 } 04069 04070 template <typename ITV> 04071 void 04072 Box<ITV> 04073 ::throw_dimension_incompatible(const char* method, 04074 dimension_type required_dim) const { 04075 std::ostringstream s; 04076 s << "PPL::Box::" << method << ":" << std::endl 04077 << "this->space_dimension() == " << space_dimension() 04078 << ", required dimension == " << required_dim << "."; 04079 throw std::invalid_argument(s.str()); 04080 } 04081 04082 template <typename ITV> 04083 void 04084 Box<ITV>::throw_dimension_incompatible(const char* method, 04085 const Constraint& c) const { 04086 std::ostringstream s; 04087 s << "PPL::Box::" << method << ":" << std::endl 04088 << "this->space_dimension() == " << space_dimension() 04089 << ", c->space_dimension == " << c.space_dimension() << "."; 04090 throw std::invalid_argument(s.str()); 04091 } 04092 04093 template <typename ITV> 04094 void 04095 Box<ITV>::throw_dimension_incompatible(const char* method, 04096 const Congruence& cg) const { 04097 std::ostringstream s; 04098 s << "PPL::Box::" << method << ":" << std::endl 04099 << "this->space_dimension() == " << space_dimension() 04100 << ", cg->space_dimension == " << cg.space_dimension() << "."; 04101 throw std::invalid_argument(s.str()); 04102 } 04103 04104 template <typename ITV> 04105 void 04106 Box<ITV>::throw_dimension_incompatible(const char* method, 04107 const Constraint_System& cs) const { 04108 std::ostringstream s; 04109 s << "PPL::Box::" << method << ":" << std::endl 04110 << "this->space_dimension() == " << space_dimension() 04111 << ", cs->space_dimension == " << cs.space_dimension() << "."; 04112 throw std::invalid_argument(s.str()); 04113 } 04114 04115 template <typename ITV> 04116 void 04117 Box<ITV>::throw_dimension_incompatible(const char* method, 04118 const Congruence_System& cgs) const { 04119 std::ostringstream s; 04120 s << "PPL::Box::" << method << ":" << std::endl 04121 << "this->space_dimension() == " << space_dimension() 04122 << ", cgs->space_dimension == " << cgs.space_dimension() << "."; 04123 throw std::invalid_argument(s.str()); 04124 } 04125 04126 template <typename ITV> 04127 void 04128 Box<ITV>::throw_dimension_incompatible(const char* method, 04129 const Generator& g) const { 04130 std::ostringstream s; 04131 s << "PPL::Box::" << method << ":" << std::endl 04132 << "this->space_dimension() == " << space_dimension() 04133 << ", g->space_dimension == " << g.space_dimension() << "."; 04134 throw std::invalid_argument(s.str()); 04135 } 04136 04137 template <typename ITV> 04138 void 04139 Box<ITV>::throw_constraint_incompatible(const char* method) { 04140 std::ostringstream s; 04141 s << "PPL::Box::" << method << ":" << std::endl 04142 << "the constraint is incompatible."; 04143 throw std::invalid_argument(s.str()); 04144 } 04145 04146 template <typename ITV> 04147 void 04148 Box<ITV>::throw_expression_too_complex(const char* method, 04149 const Linear_Expression& le) { 04150 using namespace IO_Operators; 04151 std::ostringstream s; 04152 s << "PPL::Box::" << method << ":" << std::endl 04153 << le << " is too complex."; 04154 throw std::invalid_argument(s.str()); 04155 } 04156 04157 template <typename ITV> 04158 void 04159 Box<ITV>::throw_dimension_incompatible(const char* method, 04160 const char* le_name, 04161 const Linear_Expression& le) const { 04162 std::ostringstream s; 04163 s << "PPL::Box::" << method << ":" << std::endl 04164 << "this->space_dimension() == " << space_dimension() 04165 << ", " << le_name << "->space_dimension() == " 04166 << le.space_dimension() << "."; 04167 throw std::invalid_argument(s.str()); 04168 } 04169 04170 template <typename ITV> 04171 template <typename C> 04172 void 04173 Box<ITV>::throw_dimension_incompatible(const char* method, 04174 const char* lf_name, 04175 const Linear_Form<C>& lf) const { 04176 std::ostringstream s; 04177 s << "PPL::Box::" << method << ":\n" 04178 << "this->space_dimension() == " << space_dimension() 04179 << ", " << lf_name << "->space_dimension() == " 04180 << lf.space_dimension() << "."; 04181 throw std::invalid_argument(s.str()); 04182 } 04183 04184 template <typename ITV> 04185 void 04186 Box<ITV>::throw_invalid_argument(const char* method, const char* reason) { 04187 std::ostringstream s; 04188 s << "PPL::Box::" << method << ":" << std::endl 04189 << reason; 04190 throw std::invalid_argument(s.str()); 04191 } 04192 04193 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS 04194 04195 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS) 04196 template <typename Specialization, 04197 typename Temp, typename To, typename ITV> 04198 bool 04199 l_m_distance_assign(Checked_Number<To, Extended_Number_Policy>& r, 04200 const Box<ITV>& x, const Box<ITV>& y, 04201 const Rounding_Dir dir, 04202 Temp& tmp0, Temp& tmp1, Temp& tmp2) { 04203 const dimension_type x_space_dim = x.space_dimension(); 04204 // Dimension-compatibility check. 04205 if (x_space_dim != y.space_dimension()) 04206 return false; 04207 04208 // Zero-dim boxes are equal if and only if they are both empty or universe. 04209 if (x_space_dim == 0) { 04210 if (x.marked_empty() == y.marked_empty()) 04211 assign_r(r, 0, ROUND_NOT_NEEDED); 04212 else 04213 assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED); 04214 return true; 04215 } 04216 04217 // The distance computation requires a check for emptiness. 04218 (void) x.is_empty(); 04219 (void) y.is_empty(); 04220 // If one of two boxes is empty, then they are equal if and only if 04221 // the other box is empty too. 04222 if (x.marked_empty() || y.marked_empty()) { 04223 if (x.marked_empty() == y.marked_empty()) { 04224 assign_r(r, 0, ROUND_NOT_NEEDED); 04225 return true; 04226 } 04227 else 04228 goto pinf; 04229 } 04230 04231 assign_r(tmp0, 0, ROUND_NOT_NEEDED); 04232 for (dimension_type i = x_space_dim; i-- > 0; ) { 04233 const ITV& x_i = x.seq[i]; 04234 const ITV& y_i = y.seq[i]; 04235 // Dealing with the lower bounds. 04236 if (x_i.lower_is_boundary_infinity()) { 04237 if (!y_i.lower_is_boundary_infinity()) 04238 goto pinf; 04239 } 04240 else if (y_i.lower_is_boundary_infinity()) 04241 goto pinf; 04242 else { 04243 const Temp* tmp1p; 04244 const Temp* tmp2p; 04245 if (x_i.lower() > y_i.lower()) { 04246 maybe_assign(tmp1p, tmp1, x_i.lower(), dir); 04247 maybe_assign(tmp2p, tmp2, y_i.lower(), inverse(dir)); 04248 } 04249 else { 04250 maybe_assign(tmp1p, tmp1, y_i.lower(), dir); 04251 maybe_assign(tmp2p, tmp2, x_i.lower(), inverse(dir)); 04252 } 04253 sub_assign_r(tmp1, *tmp1p, *tmp2p, dir); 04254 PPL_ASSERT(sgn(tmp1) >= 0); 04255 Specialization::combine(tmp0, tmp1, dir); 04256 } 04257 // Dealing with the lower bounds. 04258 if (x_i.upper_is_boundary_infinity()) 04259 if (y_i.upper_is_boundary_infinity()) 04260 continue; 04261 else 04262 goto pinf; 04263 else if (y_i.upper_is_boundary_infinity()) 04264 goto pinf; 04265 else { 04266 const Temp* tmp1p; 04267 const Temp* tmp2p; 04268 if (x_i.upper() > y_i.upper()) { 04269 maybe_assign(tmp1p, tmp1, x_i.upper(), dir); 04270 maybe_assign(tmp2p, tmp2, y_i.upper(), inverse(dir)); 04271 } 04272 else { 04273 maybe_assign(tmp1p, tmp1, y_i.upper(), dir); 04274 maybe_assign(tmp2p, tmp2, x_i.upper(), inverse(dir)); 04275 } 04276 sub_assign_r(tmp1, *tmp1p, *tmp2p, dir); 04277 PPL_ASSERT(sgn(tmp1) >= 0); 04278 Specialization::combine(tmp0, tmp1, dir); 04279 } 04280 } 04281 Specialization::finalize(tmp0, dir); 04282 assign_r(r, tmp0, dir); 04283 return true; 04284 04285 pinf: 04286 assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED); 04287 return true; 04288 } 04289 04290 } // namespace Parma_Polyhedra_Library 04291 04292 #endif // !defined(PPL_Box_templates_hh)