|
PPL
0.12.1
|
00001 /* BD_Shape 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_BD_Shape_templates_hh 00025 #define PPL_BD_Shape_templates_hh 1 00026 00027 #include "Generator_System.defs.hh" 00028 #include "Generator_System.inlines.hh" 00029 #include "Congruence_System.inlines.hh" 00030 #include "Congruence_System.defs.hh" 00031 #include "Interval.defs.hh" 00032 #include "Linear_Form.defs.hh" 00033 #include "Poly_Con_Relation.defs.hh" 00034 #include "Poly_Gen_Relation.defs.hh" 00035 #include "MIP_Problem.defs.hh" 00036 #include "Variables_Set.defs.hh" 00037 #include "Bit_Row.defs.hh" 00038 #include "Temp.defs.hh" 00039 #include "assert.hh" 00040 #include <vector> 00041 #include <deque> 00042 #include <iostream> 00043 #include <sstream> 00044 #include <stdexcept> 00045 #include <algorithm> 00046 00047 namespace Parma_Polyhedra_Library { 00048 00049 template <typename T> 00050 BD_Shape<T>::BD_Shape(const Congruence_System& cgs) 00051 : dbm(cgs.space_dimension() + 1), 00052 status(), 00053 redundancy_dbm() { 00054 add_congruences(cgs); 00055 } 00056 00057 template <typename T> 00058 BD_Shape<T>::BD_Shape(const Generator_System& gs) 00059 : dbm(gs.space_dimension() + 1), status(), redundancy_dbm() { 00060 const Generator_System::const_iterator gs_begin = gs.begin(); 00061 const Generator_System::const_iterator gs_end = gs.end(); 00062 if (gs_begin == gs_end) { 00063 // An empty generator system defines the empty BD shape. 00064 set_empty(); 00065 return; 00066 } 00067 00068 const dimension_type space_dim = space_dimension(); 00069 DB_Row<N>& dbm_0 = dbm[0]; 00070 PPL_DIRTY_TEMP(N, tmp); 00071 00072 bool dbm_initialized = false; 00073 bool point_seen = false; 00074 // Going through all the points and closure points. 00075 for (Generator_System::const_iterator gs_i = gs_begin; 00076 gs_i != gs_end; ++gs_i) { 00077 const Generator& g = *gs_i; 00078 switch (g.type()) { 00079 case Generator::POINT: 00080 point_seen = true; 00081 // Intentionally fall through. 00082 case Generator::CLOSURE_POINT: 00083 if (!dbm_initialized) { 00084 // When handling the first (closure) point, we initialize the DBM. 00085 dbm_initialized = true; 00086 const Coefficient& d = g.divisor(); 00087 for (dimension_type i = space_dim; i > 0; --i) { 00088 const Coefficient& g_i = g.coefficient(Variable(i-1)); 00089 DB_Row<N>& dbm_i = dbm[i]; 00090 for (dimension_type j = space_dim; j > 0; --j) 00091 if (i != j) 00092 div_round_up(dbm_i[j], g.coefficient(Variable(j-1)) - g_i, d); 00093 div_round_up(dbm_i[0], -g_i, d); 00094 } 00095 for (dimension_type j = space_dim; j > 0; --j) 00096 div_round_up(dbm_0[j], g.coefficient(Variable(j-1)), d); 00097 // Note: no need to initialize the first element of the main diagonal. 00098 } 00099 else { 00100 // This is not the first point: the DBM already contains 00101 // valid values and we must compute maxima. 00102 const Coefficient& d = g.divisor(); 00103 for (dimension_type i = space_dim; i > 0; --i) { 00104 const Coefficient& g_i = g.coefficient(Variable(i-1)); 00105 DB_Row<N>& dbm_i = dbm[i]; 00106 // The loop correctly handles the case when i == j. 00107 for (dimension_type j = space_dim; j > 0; --j) { 00108 div_round_up(tmp, g.coefficient(Variable(j-1)) - g_i, d); 00109 max_assign(dbm_i[j], tmp); 00110 } 00111 div_round_up(tmp, -g_i, d); 00112 max_assign(dbm_i[0], tmp); 00113 } 00114 for (dimension_type j = space_dim; j > 0; --j) { 00115 div_round_up(tmp, g.coefficient(Variable(j-1)), d); 00116 max_assign(dbm_0[j], tmp); 00117 } 00118 } 00119 break; 00120 default: 00121 // Lines and rays temporarily ignored. 00122 break; 00123 } 00124 } 00125 00126 if (!point_seen) 00127 // The generator system is not empty, but contains no points. 00128 throw_invalid_argument("BD_Shape(gs)", 00129 "the non-empty generator system gs " 00130 "contains no points."); 00131 00132 // Going through all the lines and rays. 00133 for (Generator_System::const_iterator gs_i = gs_begin; 00134 gs_i != gs_end; ++gs_i) { 00135 const Generator& g = *gs_i; 00136 switch (g.type()) { 00137 case Generator::LINE: 00138 for (dimension_type i = space_dim; i > 0; --i) { 00139 const Coefficient& g_i = g.coefficient(Variable(i-1)); 00140 DB_Row<N>& dbm_i = dbm[i]; 00141 // The loop correctly handles the case when i == j. 00142 for (dimension_type j = space_dim; j > 0; --j) 00143 if (g_i != g.coefficient(Variable(j-1))) 00144 assign_r(dbm_i[j], PLUS_INFINITY, ROUND_NOT_NEEDED); 00145 if (g_i != 0) 00146 assign_r(dbm_i[0], PLUS_INFINITY, ROUND_NOT_NEEDED); 00147 } 00148 for (dimension_type j = space_dim; j > 0; --j) 00149 if (g.coefficient(Variable(j-1)) != 0) 00150 assign_r(dbm_0[j], PLUS_INFINITY, ROUND_NOT_NEEDED); 00151 break; 00152 case Generator::RAY: 00153 for (dimension_type i = space_dim; i > 0; --i) { 00154 const Coefficient& g_i = g.coefficient(Variable(i-1)); 00155 DB_Row<N>& dbm_i = dbm[i]; 00156 // The loop correctly handles the case when i == j. 00157 for (dimension_type j = space_dim; j > 0; --j) 00158 if (g_i < g.coefficient(Variable(j-1))) 00159 assign_r(dbm_i[j], PLUS_INFINITY, ROUND_NOT_NEEDED); 00160 if (g_i < 0) 00161 assign_r(dbm_i[0], PLUS_INFINITY, ROUND_NOT_NEEDED); 00162 } 00163 for (dimension_type j = space_dim; j > 0; --j) 00164 if (g.coefficient(Variable(j-1)) > 0) 00165 assign_r(dbm_0[j], PLUS_INFINITY, ROUND_NOT_NEEDED); 00166 break; 00167 default: 00168 // Points and closure points already dealt with. 00169 break; 00170 } 00171 } 00172 set_shortest_path_closed(); 00173 PPL_ASSERT(OK()); 00174 } 00175 00176 template <typename T> 00177 BD_Shape<T>::BD_Shape(const Polyhedron& ph, const Complexity_Class complexity) 00178 : dbm(), status(), redundancy_dbm() { 00179 const dimension_type num_dimensions = ph.space_dimension(); 00180 00181 if (ph.marked_empty()) { 00182 *this = BD_Shape<T>(num_dimensions, EMPTY); 00183 return; 00184 } 00185 00186 if (num_dimensions == 0) { 00187 *this = BD_Shape<T>(num_dimensions, UNIVERSE); 00188 return; 00189 } 00190 00191 // Build from generators when we do not care about complexity 00192 // or when the process has polynomial complexity. 00193 if (complexity == ANY_COMPLEXITY 00194 || (!ph.has_pending_constraints() && ph.generators_are_up_to_date())) { 00195 *this = BD_Shape<T>(ph.generators()); 00196 return; 00197 } 00198 00199 // We cannot afford exponential complexity, we do not have a complete set 00200 // of generators for the polyhedron, and the polyhedron is not trivially 00201 // empty or zero-dimensional. Constraints, however, are up to date. 00202 PPL_ASSERT(ph.constraints_are_up_to_date()); 00203 00204 if (!ph.has_something_pending() && ph.constraints_are_minimized()) { 00205 // If the constraint system of the polyhedron is minimized, 00206 // the test `is_universe()' has polynomial complexity. 00207 if (ph.is_universe()) { 00208 *this = BD_Shape<T>(num_dimensions, UNIVERSE); 00209 return; 00210 } 00211 } 00212 00213 // See if there is at least one inconsistent constraint in `ph.con_sys'. 00214 for (Constraint_System::const_iterator i = ph.con_sys.begin(), 00215 cs_end = ph.con_sys.end(); i != cs_end; ++i) 00216 if (i->is_inconsistent()) { 00217 *this = BD_Shape<T>(num_dimensions, EMPTY); 00218 return; 00219 } 00220 00221 // If `complexity' allows it, use simplex to derive the exact (modulo 00222 // the fact that our BDSs are topologically closed) variable bounds. 00223 if (complexity == SIMPLEX_COMPLEXITY) { 00224 MIP_Problem lp(num_dimensions); 00225 lp.set_optimization_mode(MAXIMIZATION); 00226 00227 const Constraint_System& ph_cs = ph.constraints(); 00228 if (!ph_cs.has_strict_inequalities()) 00229 lp.add_constraints(ph_cs); 00230 else 00231 // Adding to `lp' a topologically closed version of `ph_cs'. 00232 for (Constraint_System::const_iterator i = ph_cs.begin(), 00233 ph_cs_end = ph_cs.end(); i != ph_cs_end; ++i) { 00234 const Constraint& c = *i; 00235 if (c.is_strict_inequality()) 00236 lp.add_constraint(Linear_Expression(c) >= 0); 00237 else 00238 lp.add_constraint(c); 00239 } 00240 00241 // Check for unsatisfiability. 00242 if (!lp.is_satisfiable()) { 00243 *this = BD_Shape<T>(num_dimensions, EMPTY); 00244 return; 00245 } 00246 00247 // Start with a universe BDS that will be refined by the simplex. 00248 *this = BD_Shape<T>(num_dimensions, UNIVERSE); 00249 // Get all the upper bounds. 00250 Generator g(point()); 00251 PPL_DIRTY_TEMP_COEFFICIENT(numer); 00252 PPL_DIRTY_TEMP_COEFFICIENT(denom); 00253 for (dimension_type i = 1; i <= num_dimensions; ++i) { 00254 Variable x(i-1); 00255 // Evaluate optimal upper bound for `x <= ub'. 00256 lp.set_objective_function(x); 00257 if (lp.solve() == OPTIMIZED_MIP_PROBLEM) { 00258 g = lp.optimizing_point(); 00259 lp.evaluate_objective_function(g, numer, denom); 00260 div_round_up(dbm[0][i], numer, denom); 00261 } 00262 // Evaluate optimal upper bound for `x - y <= ub'. 00263 for (dimension_type j = 1; j <= num_dimensions; ++j) { 00264 if (i == j) 00265 continue; 00266 Variable y(j-1); 00267 lp.set_objective_function(x - y); 00268 if (lp.solve() == OPTIMIZED_MIP_PROBLEM) { 00269 g = lp.optimizing_point(); 00270 lp.evaluate_objective_function(g, numer, denom); 00271 div_round_up(dbm[j][i], numer, denom); 00272 } 00273 } 00274 // Evaluate optimal upper bound for `-x <= ub'. 00275 lp.set_objective_function(-x); 00276 if (lp.solve() == OPTIMIZED_MIP_PROBLEM) { 00277 g = lp.optimizing_point(); 00278 lp.evaluate_objective_function(g, numer, denom); 00279 div_round_up(dbm[i][0], numer, denom); 00280 } 00281 } 00282 set_shortest_path_closed(); 00283 PPL_ASSERT(OK()); 00284 return; 00285 } 00286 00287 // Extract easy-to-find bounds from constraints. 00288 PPL_ASSERT(complexity == POLYNOMIAL_COMPLEXITY); 00289 *this = BD_Shape<T>(num_dimensions, UNIVERSE); 00290 refine_with_constraints(ph.constraints()); 00291 } 00292 00293 template <typename T> 00294 dimension_type 00295 BD_Shape<T>::affine_dimension() const { 00296 const dimension_type space_dim = space_dimension(); 00297 // A zero-space-dim shape always has affine dimension zero. 00298 if (space_dim == 0) 00299 return 0; 00300 00301 // Shortest-path closure is necessary to detect emptiness 00302 // and all (possibly implicit) equalities. 00303 shortest_path_closure_assign(); 00304 if (marked_empty()) 00305 return 0; 00306 00307 // The vector `predecessor' is used to represent equivalence classes: 00308 // `predecessor[i] == i' if and only if `i' is the leader of its 00309 // equivalence class (i.e., the minimum index in the class). 00310 std::vector<dimension_type> predecessor; 00311 compute_predecessors(predecessor); 00312 00313 // Due to the fictitious variable `0', the affine dimension is one 00314 // less the number of equivalence classes. 00315 dimension_type affine_dim = 0; 00316 // Note: disregard the first equivalence class. 00317 for (dimension_type i = 1; i <= space_dim; ++i) 00318 if (predecessor[i] == i) 00319 ++affine_dim; 00320 00321 return affine_dim; 00322 } 00323 00324 template <typename T> 00325 Congruence_System 00326 BD_Shape<T>::minimized_congruences() const { 00327 // Shortest-path closure is necessary to detect emptiness 00328 // and all (possibly implicit) equalities. 00329 shortest_path_closure_assign(); 00330 00331 const dimension_type space_dim = space_dimension(); 00332 Congruence_System cgs; 00333 if (space_dim == 0) { 00334 if (marked_empty()) 00335 cgs = Congruence_System::zero_dim_empty(); 00336 } 00337 else if (marked_empty()) 00338 cgs.insert((0*Variable(space_dim-1) %= 1) / 0); 00339 else { 00340 // KLUDGE: in the future `cgs' will be constructed of the right dimension. 00341 // For the time being, we force the dimension with the following line. 00342 cgs.insert(0*Variable(space_dim-1) == 0); 00343 00344 PPL_DIRTY_TEMP_COEFFICIENT(numer); 00345 PPL_DIRTY_TEMP_COEFFICIENT(denom); 00346 00347 // Compute leader information. 00348 std::vector<dimension_type> leaders; 00349 compute_leaders(leaders); 00350 00351 // Go through the non-leaders to generate equality constraints. 00352 const DB_Row<N>& dbm_0 = dbm[0]; 00353 for (dimension_type i = 1; i <= space_dim; ++i) { 00354 const dimension_type leader = leaders[i]; 00355 if (i != leader) { 00356 // Generate the constraint relating `i' and its leader. 00357 if (leader == 0) { 00358 // A unary equality has to be generated. 00359 PPL_ASSERT(!is_plus_infinity(dbm_0[i])); 00360 numer_denom(dbm_0[i], numer, denom); 00361 cgs.insert(denom*Variable(i-1) == numer); 00362 } 00363 else { 00364 // A binary equality has to be generated. 00365 PPL_ASSERT(!is_plus_infinity(dbm[i][leader])); 00366 numer_denom(dbm[i][leader], numer, denom); 00367 cgs.insert(denom*Variable(leader-1) - denom*Variable(i-1) == numer); 00368 } 00369 } 00370 } 00371 } 00372 return cgs; 00373 } 00374 00375 template <typename T> 00376 void 00377 BD_Shape<T>::add_constraint(const Constraint& c) { 00378 const dimension_type c_space_dim = c.space_dimension(); 00379 // Dimension-compatibility check. 00380 if (c_space_dim > space_dimension()) 00381 throw_dimension_incompatible("add_constraint(c)", c); 00382 00383 // Get rid of strict inequalities. 00384 if (c.is_strict_inequality()) { 00385 if (c.is_inconsistent()) { 00386 set_empty(); 00387 return; 00388 } 00389 if (c.is_tautological()) 00390 return; 00391 // Nontrivial strict inequalities are not allowed. 00392 throw_invalid_argument("add_constraint(c)", 00393 "strict inequalities are not allowed"); 00394 } 00395 00396 dimension_type num_vars = 0; 00397 dimension_type i = 0; 00398 dimension_type j = 0; 00399 PPL_DIRTY_TEMP_COEFFICIENT(coeff); 00400 // Constraints that are not bounded differences are not allowed. 00401 if (!extract_bounded_difference(c, c_space_dim, num_vars, i, j, coeff)) 00402 throw_invalid_argument("add_constraint(c)", 00403 "c is not a bounded difference constraint"); 00404 00405 const Coefficient& inhomo = c.inhomogeneous_term(); 00406 if (num_vars == 0) { 00407 // Dealing with a trivial constraint (not a strict inequality). 00408 if (inhomo < 0 00409 || (inhomo != 0 && c.is_equality())) 00410 set_empty(); 00411 return; 00412 } 00413 00414 // Select the cell to be modified for the "<=" part of the constraint, 00415 // and set `coeff' to the absolute value of itself. 00416 const bool negative = (coeff < 0); 00417 if (negative) 00418 neg_assign(coeff); 00419 00420 bool changed = false; 00421 N& x = negative ? dbm[i][j] : dbm[j][i]; 00422 // Compute the bound for `x', rounding towards plus infinity. 00423 PPL_DIRTY_TEMP(N, d); 00424 div_round_up(d, inhomo, coeff); 00425 if (x > d) { 00426 x = d; 00427 changed = true; 00428 } 00429 00430 if (c.is_equality()) { 00431 N& y = negative ? dbm[j][i] : dbm[i][j]; 00432 // Also compute the bound for `y', rounding towards plus infinity. 00433 PPL_DIRTY_TEMP_COEFFICIENT(minus_c_term); 00434 neg_assign(minus_c_term, inhomo); 00435 div_round_up(d, minus_c_term, coeff); 00436 if (y > d) { 00437 y = d; 00438 changed = true; 00439 } 00440 } 00441 00442 // In general, adding a constraint does not preserve the shortest-path 00443 // closure or reduction of the bounded difference shape. 00444 if (changed && marked_shortest_path_closed()) 00445 reset_shortest_path_closed(); 00446 PPL_ASSERT(OK()); 00447 } 00448 00449 template <typename T> 00450 void 00451 BD_Shape<T>::add_congruence(const Congruence& cg) { 00452 const dimension_type cg_space_dim = cg.space_dimension(); 00453 // Dimension-compatibility check: 00454 // the dimension of `cg' can not be greater than space_dim. 00455 if (space_dimension() < cg_space_dim) 00456 throw_dimension_incompatible("add_congruence(cg)", cg); 00457 00458 // Handle the case of proper congruences first. 00459 if (cg.is_proper_congruence()) { 00460 if (cg.is_tautological()) 00461 return; 00462 if (cg.is_inconsistent()) { 00463 set_empty(); 00464 return; 00465 } 00466 // Non-trivial and proper congruences are not allowed. 00467 throw_invalid_argument("add_congruence(cg)", 00468 "cg is a non-trivial, proper congruence"); 00469 } 00470 00471 PPL_ASSERT(cg.is_equality()); 00472 Constraint c(cg); 00473 add_constraint(c); 00474 } 00475 00476 template <typename T> 00477 void 00478 BD_Shape<T>::refine_no_check(const Constraint& c) { 00479 PPL_ASSERT(!marked_empty()); 00480 const dimension_type c_space_dim = c.space_dimension(); 00481 PPL_ASSERT(c_space_dim <= space_dimension()); 00482 00483 dimension_type num_vars = 0; 00484 dimension_type i = 0; 00485 dimension_type j = 0; 00486 PPL_DIRTY_TEMP_COEFFICIENT(coeff); 00487 // Constraints that are not bounded differences are ignored. 00488 if (!extract_bounded_difference(c, c_space_dim, num_vars, i, j, coeff)) 00489 return; 00490 00491 const Coefficient& inhomo = c.inhomogeneous_term(); 00492 if (num_vars == 0) { 00493 // Dealing with a trivial constraint (might be a strict inequality). 00494 if (inhomo < 0 00495 || (c.is_equality() && inhomo != 0) 00496 || (c.is_strict_inequality() && inhomo == 0)) 00497 set_empty(); 00498 return; 00499 } 00500 00501 // Select the cell to be modified for the "<=" part of the constraint, 00502 // and set `coeff' to the absolute value of itself. 00503 const bool negative = (coeff < 0); 00504 N& x = negative ? dbm[i][j] : dbm[j][i]; 00505 N& y = negative ? dbm[j][i] : dbm[i][j]; 00506 if (negative) 00507 neg_assign(coeff); 00508 00509 bool changed = false; 00510 // Compute the bound for `x', rounding towards plus infinity. 00511 PPL_DIRTY_TEMP(N, d); 00512 div_round_up(d, inhomo, coeff); 00513 if (x > d) { 00514 x = d; 00515 changed = true; 00516 } 00517 00518 if (c.is_equality()) { 00519 // Also compute the bound for `y', rounding towards plus infinity. 00520 PPL_DIRTY_TEMP_COEFFICIENT(minus_c_term); 00521 neg_assign(minus_c_term, inhomo); 00522 div_round_up(d, minus_c_term, coeff); 00523 if (y > d) { 00524 y = d; 00525 changed = true; 00526 } 00527 } 00528 00529 // In general, adding a constraint does not preserve the shortest-path 00530 // closure or reduction of the bounded difference shape. 00531 if (changed && marked_shortest_path_closed()) 00532 reset_shortest_path_closed(); 00533 PPL_ASSERT(OK()); 00534 } 00535 00536 template <typename T> 00537 void 00538 BD_Shape<T>::concatenate_assign(const BD_Shape& y) { 00539 BD_Shape& x = *this; 00540 00541 const dimension_type x_space_dim = x.space_dimension(); 00542 const dimension_type y_space_dim = y.space_dimension(); 00543 00544 // If `y' is an empty 0-dim space bounded difference shape, 00545 // let `*this' become empty. 00546 if (y_space_dim == 0 && y.marked_empty()) { 00547 set_empty(); 00548 return; 00549 } 00550 00551 // If `x' is an empty 0-dim space BDS, then it is sufficient to adjust 00552 // the dimension of the vector space. 00553 if (x_space_dim == 0 && marked_empty()) { 00554 dbm.grow(y_space_dim + 1); 00555 PPL_ASSERT(OK()); 00556 return; 00557 } 00558 // First we increase the space dimension of `x' by adding 00559 // `y.space_dimension()' new dimensions. 00560 // The matrix for the new system of constraints is obtained 00561 // by leaving the old system of constraints in the upper left-hand side 00562 // and placing the constraints of `y' in the lower right-hand side, 00563 // except the constraints as `y(i) >= cost' or `y(i) <= cost', that are 00564 // placed in the right position on the new matrix. 00565 add_space_dimensions_and_embed(y_space_dim); 00566 const dimension_type new_space_dim = x_space_dim + y_space_dim; 00567 for (dimension_type i = x_space_dim + 1; i <= new_space_dim; ++i) { 00568 DB_Row<N>& dbm_i = dbm[i]; 00569 dbm_i[0] = y.dbm[i - x_space_dim][0]; 00570 dbm[0][i] = y.dbm[0][i - x_space_dim]; 00571 for (dimension_type j = x_space_dim + 1; j <= new_space_dim; ++j) 00572 dbm_i[j] = y.dbm[i - x_space_dim][j - x_space_dim]; 00573 } 00574 00575 if (marked_shortest_path_closed()) 00576 reset_shortest_path_closed(); 00577 PPL_ASSERT(OK()); 00578 } 00579 00580 template <typename T> 00581 bool 00582 BD_Shape<T>::contains(const BD_Shape& y) const { 00583 const BD_Shape<T>& x = *this; 00584 const dimension_type x_space_dim = x.space_dimension(); 00585 00586 // Dimension-compatibility check. 00587 if (x_space_dim != y.space_dimension()) 00588 throw_dimension_incompatible("contains(y)", y); 00589 00590 // The zero-dimensional universe shape contains any other 00591 // dimension-compatible shape. 00592 // The zero-dimensional empty shape only contains another 00593 // zero-dimensional empty shape. 00594 if (x_space_dim == 0) { 00595 if (!marked_empty()) 00596 return true; 00597 else 00598 return y.marked_empty(); 00599 } 00600 00601 /* 00602 The `y' bounded difference shape must be closed. As an example, 00603 consider the case where in `*this' we have the constraints 00604 00605 x1 - x2 <= 1, 00606 x1 <= 3, 00607 x2 <= 2, 00608 00609 and in `y' the constraints are 00610 00611 x1 - x2 <= 0, 00612 x2 <= 1. 00613 00614 Without closure the (erroneous) analysis of the inhomogeneous terms 00615 would conclude containment does not hold. Closing `y' results into 00616 the "discovery" of the implicit constraint 00617 00618 x1 <= 1, 00619 00620 at which point the inhomogeneous terms can be examined to determine 00621 that containment does hold. 00622 */ 00623 y.shortest_path_closure_assign(); 00624 00625 // An empty shape is contained in any other dimension-compatible shapes. 00626 if (y.marked_empty()) 00627 return true; 00628 00629 // `*this' contains `y' if and only if every cell of `dbm' 00630 // is greater than or equal to the correspondent one of `y.dbm'. 00631 for (dimension_type i = x_space_dim + 1; i-- > 0; ) { 00632 const DB_Row<N>& x_dbm_i = x.dbm[i]; 00633 const DB_Row<N>& y_dbm_i = y.dbm[i]; 00634 for (dimension_type j = x_space_dim + 1; j-- > 0; ) 00635 if (x_dbm_i[j] < y_dbm_i[j]) 00636 return false; 00637 } 00638 return true; 00639 } 00640 00641 template <typename T> 00642 bool 00643 BD_Shape<T>::is_disjoint_from(const BD_Shape& y) const { 00644 const dimension_type space_dim = space_dimension(); 00645 // Dimension-compatibility check. 00646 if (space_dim != y.space_dimension()) 00647 throw_dimension_incompatible("is_disjoint_from(y)", y); 00648 00649 // If one of the two bounded difference shape is empty, 00650 // then the two bounded difference shape are disjoint. 00651 shortest_path_closure_assign(); 00652 if (marked_empty()) 00653 return true; 00654 y.shortest_path_closure_assign(); 00655 if (y.marked_empty()) 00656 return true; 00657 00658 // Two BDSs are disjoint when their intersection is empty. 00659 // That is if and only if there exists at least a bounded difference 00660 // such that the upper bound of the bounded difference in the first 00661 // BD_Shape is strictly less than the lower bound of 00662 // the corresponding bounded difference in the second BD_Shape 00663 // or vice versa. 00664 // For example: let be 00665 // in `*this': -a_j_i <= v_j - v_i <= a_i_j; 00666 // and in `y': -b_j_i <= v_j - v_i <= b_i_j; 00667 // `*this' and `y' are disjoint if 00668 // 1.) a_i_j < -b_j_i or 00669 // 2.) b_i_j < -a_j_i. 00670 PPL_DIRTY_TEMP(N, tmp); 00671 for (dimension_type i = space_dim+1; i-- > 0; ) { 00672 const DB_Row<N>& x_i = dbm[i]; 00673 for (dimension_type j = space_dim+1; j-- > 0; ) { 00674 neg_assign_r(tmp, y.dbm[j][i], ROUND_UP); 00675 if (x_i[j] < tmp) 00676 return true; 00677 } 00678 } 00679 00680 return false; 00681 } 00682 00683 template <typename T> 00684 bool 00685 BD_Shape<T>::is_universe() const { 00686 if (marked_empty()) 00687 return false; 00688 00689 const dimension_type space_dim = space_dimension(); 00690 // If the BDS is non-empty and zero-dimensional, 00691 // then it is necessarily the universe BDS. 00692 if (space_dim == 0) 00693 return true; 00694 00695 // A bounded difference shape defining the universe BDS can only 00696 // contain trivial constraints. 00697 for (dimension_type i = space_dim + 1; i-- > 0; ) { 00698 const DB_Row<N>& dbm_i = dbm[i]; 00699 for (dimension_type j = space_dim + 1; j-- > 0; ) 00700 if (!is_plus_infinity(dbm_i[j])) 00701 return false; 00702 } 00703 return true; 00704 } 00705 00706 template <typename T> 00707 bool 00708 BD_Shape<T>::is_bounded() const { 00709 shortest_path_closure_assign(); 00710 const dimension_type space_dim = space_dimension(); 00711 // A zero-dimensional or empty BDS is bounded. 00712 if (marked_empty() || space_dim == 0) 00713 return true; 00714 00715 // A bounded difference shape defining the bounded BDS never can 00716 // contain trivial constraints. 00717 for (dimension_type i = space_dim + 1; i-- > 0; ) { 00718 const DB_Row<N>& dbm_i = dbm[i]; 00719 for (dimension_type j = space_dim + 1; j-- > 0; ) 00720 if (i != j) 00721 if (is_plus_infinity(dbm_i[j])) 00722 return false; 00723 } 00724 00725 return true; 00726 } 00727 00728 template <typename T> 00729 bool 00730 BD_Shape<T>::contains_integer_point() const { 00731 // Force shortest-path closure. 00732 if (is_empty()) 00733 return false; 00734 00735 const dimension_type space_dim = space_dimension(); 00736 if (space_dim == 0) 00737 return true; 00738 00739 // A non-empty BD_Shape defined by integer constraints 00740 // necessarily contains an integer point. 00741 if (std::numeric_limits<T>::is_integer) 00742 return true; 00743 00744 // Build an integer BD_Shape z with bounds at least as tight as 00745 // those in *this and then recheck for emptiness. 00746 BD_Shape<mpz_class> bds_z(space_dim); 00747 typedef BD_Shape<mpz_class>::N Z; 00748 bds_z.reset_shortest_path_closed(); 00749 PPL_DIRTY_TEMP(N, tmp); 00750 bool all_integers = true; 00751 for (dimension_type i = space_dim + 1; i-- > 0; ) { 00752 DB_Row<Z>& z_i = bds_z.dbm[i]; 00753 const DB_Row<N>& dbm_i = dbm[i]; 00754 for (dimension_type j = space_dim + 1; j-- > 0; ) { 00755 const N& dbm_i_j = dbm_i[j]; 00756 if (is_plus_infinity(dbm_i_j)) 00757 continue; 00758 if (is_integer(dbm_i_j)) 00759 assign_r(z_i[j], dbm_i_j, ROUND_NOT_NEEDED); 00760 else { 00761 all_integers = false; 00762 Z& z_i_j = z_i[j]; 00763 // Copy dbm_i_j into z_i_j, but rounding downwards. 00764 neg_assign_r(tmp, dbm_i_j, ROUND_NOT_NEEDED); 00765 assign_r(z_i_j, tmp, ROUND_UP); 00766 neg_assign_r(z_i_j, z_i_j, ROUND_NOT_NEEDED); 00767 } 00768 } 00769 } 00770 return all_integers || !bds_z.is_empty(); 00771 } 00772 00773 template <typename T> 00774 bool 00775 BD_Shape<T>::frequency(const Linear_Expression& expr, 00776 Coefficient& freq_n, Coefficient& freq_d, 00777 Coefficient& val_n, Coefficient& val_d) const { 00778 dimension_type space_dim = space_dimension(); 00779 // The dimension of `expr' must be at most the dimension of *this. 00780 if (space_dim < expr.space_dimension()) 00781 throw_dimension_incompatible("frequency(e, ...)", "e", expr); 00782 00783 // Check if `expr' has a constant value. 00784 // If it is constant, set the frequency `freq_n' to 0 00785 // and return true. Otherwise the values for \p expr 00786 // are not discrete so return false. 00787 00788 // Space dimension is 0: if empty, then return false; 00789 // otherwise the frequency is 0 and the value is the inhomogeneous term. 00790 if (space_dim == 0) { 00791 if (is_empty()) 00792 return false; 00793 freq_n = 0; 00794 freq_d = 1; 00795 val_n = expr.inhomogeneous_term(); 00796 val_d = 1; 00797 return true; 00798 } 00799 00800 shortest_path_closure_assign(); 00801 // For an empty BD shape, we simply return false. 00802 if (marked_empty()) 00803 return false; 00804 00805 // The BD shape has at least 1 dimension and is not empty. 00806 PPL_DIRTY_TEMP_COEFFICIENT(coeff); 00807 PPL_DIRTY_TEMP_COEFFICIENT(numer); 00808 PPL_DIRTY_TEMP_COEFFICIENT(denom); 00809 PPL_DIRTY_TEMP(N, tmp); 00810 Linear_Expression le = expr; 00811 // Boolean to keep track of a variable `v' in expression `le'. 00812 // If we can replace `v' by an expression using variables other 00813 // than `v' and are already in `le', then this is set to true. 00814 bool constant_v = false; 00815 00816 PPL_DIRTY_TEMP_COEFFICIENT(val_denom); 00817 val_denom = 1; 00818 00819 for (dimension_type i = dbm.num_rows(); i-- > 1; ) { 00820 constant_v = false; 00821 const Variable v(i-1); 00822 coeff = le.coefficient(v); 00823 if (coeff == 0) { 00824 constant_v = true; 00825 continue; 00826 } 00827 00828 const DB_Row<N>& dbm_i = dbm[i]; 00829 // Check if `v' is constant in the BD shape. 00830 assign_r(tmp, dbm_i[0], ROUND_NOT_NEEDED); 00831 if (is_additive_inverse(dbm[0][i], tmp)) { 00832 // If `v' is constant, replace it in `le' by the value. 00833 numer_denom(tmp, numer, denom); 00834 le -= coeff*v; 00835 le *= denom; 00836 le -= numer*coeff; 00837 val_denom *= denom; 00838 constant_v = true; 00839 continue; 00840 } 00841 // Check the bounded differences with the other dimensions that 00842 // have non-zero coefficient in `le'. 00843 else { 00844 PPL_ASSERT(!constant_v); 00845 for (dimension_type j = i; j-- > 1; ) { 00846 const Variable vj(j-1); 00847 if (le.coefficient(vj) == 0) 00848 // The coefficient in `le' is 0, so do nothing. 00849 continue; 00850 assign_r(tmp, dbm_i[j], ROUND_NOT_NEEDED); 00851 if (is_additive_inverse(dbm[j][i], tmp)) { 00852 // The coefficient for `vj' in `le' is not 0 00853 // and the difference with `v' in the BD shape is constant. 00854 // So apply this equality to eliminate `v' in `le'. 00855 numer_denom(tmp, numer, denom); 00856 le -= coeff*v - coeff*vj; 00857 le *= denom; 00858 le -= numer*coeff; 00859 val_denom *= denom; 00860 constant_v = true; 00861 break; 00862 } 00863 } 00864 if (!constant_v) 00865 // The expression `expr' is not constant. 00866 return false; 00867 } 00868 } 00869 if (!constant_v) 00870 // The expression `expr' is not constant. 00871 return false; 00872 00873 // The expression `expr' is constant. 00874 freq_n = 0; 00875 freq_d = 1; 00876 00877 // Reduce `val_n' and `val_d'. 00878 normalize2(le.inhomogeneous_term(), val_denom, val_n, val_d); 00879 return true; 00880 } 00881 00882 template <typename T> 00883 bool 00884 BD_Shape<T>::constrains(const Variable var) const { 00885 // `var' should be one of the dimensions of the BD shape. 00886 const dimension_type var_space_dim = var.space_dimension(); 00887 if (space_dimension() < var_space_dim) 00888 throw_dimension_incompatible("constrains(v)", "v", var); 00889 00890 shortest_path_closure_assign(); 00891 // A BD shape known to be empty constrains all variables. 00892 // (Note: do not force emptiness check _yet_) 00893 if (marked_empty()) 00894 return true; 00895 00896 // Check whether `var' is syntactically constrained. 00897 const DB_Row<N>& dbm_v = dbm[var_space_dim]; 00898 for (dimension_type i = dbm.num_rows(); i-- > 0; ) { 00899 if (!is_plus_infinity(dbm_v[i]) 00900 || !is_plus_infinity(dbm[i][var_space_dim])) 00901 return true; 00902 } 00903 00904 // `var' is not syntactically constrained: 00905 // now force an emptiness check. 00906 return is_empty(); 00907 } 00908 00909 template <typename T> 00910 void 00911 BD_Shape<T> 00912 ::compute_predecessors(std::vector<dimension_type>& predecessor) const { 00913 PPL_ASSERT(!marked_empty() && marked_shortest_path_closed()); 00914 PPL_ASSERT(predecessor.size() == 0); 00915 // Variables are ordered according to their index. 00916 // The vector `predecessor' is used to indicate which variable 00917 // immediately precedes a given one in the corresponding equivalence class. 00918 // The `leader' of an equivalence class is the element having minimum 00919 // index: leaders are their own predecessors. 00920 const dimension_type predecessor_size = dbm.num_rows(); 00921 // Initially, each variable is leader of its own zero-equivalence class. 00922 predecessor.reserve(predecessor_size); 00923 for (dimension_type i = 0; i < predecessor_size; ++i) 00924 predecessor.push_back(i); 00925 // Now compute actual predecessors. 00926 for (dimension_type i = predecessor_size; i-- > 1; ) 00927 if (i == predecessor[i]) { 00928 const DB_Row<N>& dbm_i = dbm[i]; 00929 for (dimension_type j = i; j-- > 0; ) 00930 if (j == predecessor[j] 00931 && is_additive_inverse(dbm[j][i], dbm_i[j])) { 00932 // Choose as predecessor the variable having the smaller index. 00933 predecessor[i] = j; 00934 break; 00935 } 00936 } 00937 } 00938 00939 template <typename T> 00940 void 00941 BD_Shape<T>::compute_leaders(std::vector<dimension_type>& leaders) const { 00942 PPL_ASSERT(!marked_empty() && marked_shortest_path_closed()); 00943 PPL_ASSERT(leaders.size() == 0); 00944 // Compute predecessor information. 00945 compute_predecessors(leaders); 00946 // Flatten the predecessor chains so as to obtain leaders. 00947 PPL_ASSERT(leaders[0] == 0); 00948 for (dimension_type i = 1, l_size = leaders.size(); i != l_size; ++i) { 00949 const dimension_type leaders_i = leaders[i]; 00950 PPL_ASSERT(leaders_i <= i); 00951 if (leaders_i != i) { 00952 const dimension_type leaders_leaders_i = leaders[leaders_i]; 00953 PPL_ASSERT(leaders_leaders_i == leaders[leaders_leaders_i]); 00954 leaders[i] = leaders_leaders_i; 00955 } 00956 } 00957 } 00958 00959 template <typename T> 00960 bool 00961 BD_Shape<T>::is_shortest_path_reduced() const { 00962 // If the BDS is empty, it is also reduced. 00963 if (marked_empty()) 00964 return true; 00965 00966 const dimension_type space_dim = space_dimension(); 00967 // Zero-dimensional BDSs are necessarily reduced. 00968 if (space_dim == 0) 00969 return true; 00970 00971 // A shortest-path reduced dbm is just a dbm with an indication of 00972 // those constraints that are redundant. If there is no indication 00973 // of the redundant constraints, then it cannot be reduced. 00974 if (!marked_shortest_path_reduced()) 00975 return false; 00976 00977 const BD_Shape x_copy = *this; 00978 x_copy.shortest_path_closure_assign(); 00979 // If we just discovered emptiness, it cannot be reduced. 00980 if (x_copy.marked_empty()) 00981 return false; 00982 00983 // The vector `leader' is used to indicate which variables are equivalent. 00984 std::vector<dimension_type> leader(space_dim + 1); 00985 00986 // We store the leader. 00987 for (dimension_type i = space_dim + 1; i-- > 0; ) 00988 leader[i] = i; 00989 00990 // Step 1: we store really the leader with the corrected value. 00991 // We search for the equivalent or zero-equivalent variables. 00992 // The variable(i-1) and variable(j-1) are equivalent if and only if 00993 // m_i_j == -(m_j_i). 00994 for (dimension_type i = 0; i < space_dim; ++i) { 00995 const DB_Row<N>& x_copy_dbm_i = x_copy.dbm[i]; 00996 for (dimension_type j = i + 1; j <= space_dim; ++j) 00997 if (is_additive_inverse(x_copy.dbm[j][i], x_copy_dbm_i[j])) 00998 // Two equivalent variables have got the same leader 00999 // (the smaller variable). 01000 leader[j] = leader[i]; 01001 } 01002 01003 // Step 2: we check if there are redundant constraints in the zero_cycle 01004 // free bounded difference shape, considering only the leaders. 01005 // A constraint `c' is redundant, when there are two constraints such that 01006 // their sum is the same constraint with the inhomogeneous term 01007 // less than or equal to the `c' one. 01008 PPL_DIRTY_TEMP(N, c); 01009 for (dimension_type k = 0; k <= space_dim; ++k) 01010 if (leader[k] == k) { 01011 const DB_Row<N>& x_k = x_copy.dbm[k]; 01012 for (dimension_type i = 0; i <= space_dim; ++i) 01013 if (leader[i] == i) { 01014 const DB_Row<N>& x_i = x_copy.dbm[i]; 01015 const Bit_Row& redundancy_i = redundancy_dbm[i]; 01016 const N& x_i_k = x_i[k]; 01017 for (dimension_type j = 0; j <= space_dim; ++j) 01018 if (leader[j] == j) { 01019 const N& x_i_j = x_i[j]; 01020 if (!is_plus_infinity(x_i_j)) { 01021 add_assign_r(c, x_i_k, x_k[j], ROUND_UP); 01022 if (x_i_j >= c && !redundancy_i[j]) 01023 return false; 01024 } 01025 } 01026 } 01027 } 01028 01029 // The vector `var_conn' is used to check if there is a single cycle 01030 // that connected all zero-equivalent variables between them. 01031 // The value `space_dim + 1' is used to indicate that the equivalence 01032 // class contains a single variable. 01033 std::vector<dimension_type> var_conn(space_dim + 1); 01034 for (dimension_type i = space_dim + 1; i-- > 0; ) 01035 var_conn[i] = space_dim + 1; 01036 01037 // Step 3: we store really the `var_conn' with the right value, putting 01038 // the variable with the selected variable is connected: 01039 // we check the row of each variable: 01040 // a- each leader could be connected with only zero-equivalent one, 01041 // b- each non-leader with only another zero-equivalent one. 01042 for (dimension_type i = 0; i <= space_dim; ++i) { 01043 // It count with how many variables the selected variable is 01044 // connected. 01045 dimension_type t = 0; 01046 dimension_type leader_i = leader[i]; 01047 // Case a: leader. 01048 if (leader_i == i) { 01049 for (dimension_type j = 0; j <= space_dim; ++j) { 01050 dimension_type leader_j = leader[j]; 01051 // Only the connectedness with equivalent variables 01052 // is considered. 01053 if (j != leader_j) 01054 if (!redundancy_dbm[i][j]) { 01055 if (t == 1) 01056 // Two non-leaders cannot be connected with the same leader. 01057 return false; 01058 else 01059 if (leader_j != i) 01060 // The variables are not in the same equivalence class. 01061 return false; 01062 else { 01063 ++t; 01064 var_conn[i] = j; 01065 } 01066 } 01067 } 01068 } 01069 // Case b: non-leader. 01070 else { 01071 for (dimension_type j = 0; j <= space_dim; ++j) { 01072 if (!redundancy_dbm[i][j]) { 01073 dimension_type leader_j = leader[j]; 01074 if (leader_i != leader_j) 01075 // The variables are not in the same equivalence class. 01076 return false; 01077 else { 01078 if (t == 1) 01079 // The variables cannot be connected with the same leader. 01080 return false; 01081 else { 01082 ++t; 01083 var_conn[i] = j; 01084 } 01085 } 01086 // A non-leader must be connected with 01087 // another variable. 01088 if (t == 0) 01089 return false; 01090 } 01091 } 01092 } 01093 } 01094 01095 // The vector `just_checked' is used to check if 01096 // a variable is already checked. 01097 std::vector<bool> just_checked(space_dim + 1); 01098 for (dimension_type i = space_dim + 1; i-- > 0; ) 01099 just_checked[i] = false; 01100 01101 // Step 4: we check if there are single cycles that 01102 // connected all the zero-equivalent variables between them. 01103 for (dimension_type i = 0; i <= space_dim; ++i) { 01104 // We do not re-check the already considered single cycles. 01105 if (!just_checked[i]) { 01106 dimension_type v_con = var_conn[i]; 01107 // We consider only the equivalence classes with 01108 // 2 or plus variables. 01109 if (v_con != space_dim + 1) { 01110 // There is a single cycle if taken a variable, 01111 // we return to this same variable. 01112 while (v_con != i) { 01113 just_checked[v_con] = true; 01114 v_con = var_conn[v_con]; 01115 // If we re-pass to an already considered variable, 01116 // then we haven't a single cycle. 01117 if (just_checked[v_con]) 01118 return false; 01119 } 01120 } 01121 } 01122 just_checked[i] = true; 01123 } 01124 01125 // The system bounded differences is just reduced. 01126 return true; 01127 } 01128 01129 template <typename T> 01130 bool 01131 BD_Shape<T>::bounds(const Linear_Expression& expr, 01132 const bool from_above) const { 01133 // The dimension of `expr' should not be greater than the dimension 01134 // of `*this'. 01135 const dimension_type expr_space_dim = expr.space_dimension(); 01136 const dimension_type space_dim = space_dimension(); 01137 if (space_dim < expr_space_dim) 01138 throw_dimension_incompatible((from_above 01139 ? "bounds_from_above(e)" 01140 : "bounds_from_below(e)"), "e", expr); 01141 01142 shortest_path_closure_assign(); 01143 // A zero-dimensional or empty BDS bounds everything. 01144 if (space_dim == 0 || marked_empty()) 01145 return true; 01146 01147 // The constraint `c' is used to check if `expr' is a difference 01148 // bounded and, in this case, to select the cell. 01149 const Constraint& c = from_above ? expr <= 0 : expr >= 0; 01150 const dimension_type c_space_dim = c.space_dimension(); 01151 dimension_type num_vars = 0; 01152 dimension_type i = 0; 01153 dimension_type j = 0; 01154 PPL_DIRTY_TEMP_COEFFICIENT(coeff); 01155 // Check if `c' is a BD constraint. 01156 if (extract_bounded_difference(c, c_space_dim, num_vars, i, j, coeff)) { 01157 if (num_vars == 0) 01158 // Dealing with a trivial constraint. 01159 return true; 01160 // Select the cell to be checked. 01161 const N& x = (coeff < 0) ? dbm[i][j] : dbm[j][i]; 01162 return !is_plus_infinity(x); 01163 } 01164 else { 01165 // Not a DB constraint: use the MIP solver. 01166 Optimization_Mode mode_bounds 01167 = from_above ? MAXIMIZATION : MINIMIZATION; 01168 MIP_Problem mip(space_dim, constraints(), expr, mode_bounds); 01169 // Problem is known to be feasible. 01170 return mip.solve() == OPTIMIZED_MIP_PROBLEM; 01171 } 01172 } 01173 01174 template <typename T> 01175 bool 01176 BD_Shape<T>::max_min(const Linear_Expression& expr, 01177 const bool maximize, 01178 Coefficient& ext_n, Coefficient& ext_d, 01179 bool& included) const { 01180 // The dimension of `expr' should not be greater than the dimension 01181 // of `*this'. 01182 const dimension_type space_dim = space_dimension(); 01183 const dimension_type expr_space_dim = expr.space_dimension(); 01184 if (space_dim < expr_space_dim) 01185 throw_dimension_incompatible((maximize 01186 ? "maximize(e, ...)" 01187 : "minimize(e, ...)"), "e", expr); 01188 // Deal with zero-dim BDS first. 01189 if (space_dim == 0) { 01190 if (marked_empty()) 01191 return false; 01192 else { 01193 ext_n = expr.inhomogeneous_term(); 01194 ext_d = 1; 01195 included = true; 01196 return true; 01197 } 01198 } 01199 01200 shortest_path_closure_assign(); 01201 // For an empty BDS we simply return false. 01202 if (marked_empty()) 01203 return false; 01204 01205 // The constraint `c' is used to check if `expr' is a difference 01206 // bounded and, in this case, to select the cell. 01207 const Constraint& c = maximize ? expr <= 0 : expr >= 0; 01208 const dimension_type c_space_dim = c.space_dimension(); 01209 dimension_type num_vars = 0; 01210 dimension_type i = 0; 01211 dimension_type j = 0; 01212 PPL_DIRTY_TEMP_COEFFICIENT(coeff); 01213 // Check if `c' is a BD constraint. 01214 if (!extract_bounded_difference(c, c_space_dim, num_vars, i, j, coeff)) { 01215 Optimization_Mode mode_max_min 01216 = maximize ? MAXIMIZATION : MINIMIZATION; 01217 MIP_Problem mip(space_dim, constraints(), expr, mode_max_min); 01218 if (mip.solve() == OPTIMIZED_MIP_PROBLEM) { 01219 mip.optimal_value(ext_n, ext_d); 01220 included = true; 01221 return true; 01222 } 01223 else 01224 // Here`expr' is unbounded in `*this'. 01225 return false; 01226 } 01227 else { 01228 // Here `expr' is a bounded difference. 01229 if (num_vars == 0) { 01230 // Dealing with a trivial expression. 01231 ext_n = expr.inhomogeneous_term(); 01232 ext_d = 1; 01233 included = true; 01234 return true; 01235 } 01236 01237 // Select the cell to be checked. 01238 const N& x = (coeff < 0) ? dbm[i][j] : dbm[j][i]; 01239 if (!is_plus_infinity(x)) { 01240 // Compute the maximize/minimize of `expr'. 01241 PPL_DIRTY_TEMP(N, d); 01242 const Coefficient& b = expr.inhomogeneous_term(); 01243 PPL_DIRTY_TEMP_COEFFICIENT(minus_b); 01244 neg_assign(minus_b, b); 01245 const Coefficient& sc_b = maximize ? b : minus_b; 01246 assign_r(d, sc_b, ROUND_UP); 01247 // Set `coeff_expr' to the absolute value of coefficient of 01248 // a variable in `expr'. 01249 PPL_DIRTY_TEMP(N, coeff_expr); 01250 const Coefficient& coeff_i = expr.coefficient(Variable(i-1)); 01251 const int sign_i = sgn(coeff_i); 01252 if (sign_i > 0) 01253 assign_r(coeff_expr, coeff_i, ROUND_UP); 01254 else { 01255 PPL_DIRTY_TEMP_COEFFICIENT(minus_coeff_i); 01256 neg_assign(minus_coeff_i, coeff_i); 01257 assign_r(coeff_expr, minus_coeff_i, ROUND_UP); 01258 } 01259 // Approximating the maximum/minimum of `expr'. 01260 add_mul_assign_r(d, coeff_expr, x, ROUND_UP); 01261 numer_denom(d, ext_n, ext_d); 01262 if (!maximize) 01263 neg_assign(ext_n); 01264 included = true; 01265 return true; 01266 } 01267 01268 // `expr' is unbounded. 01269 return false; 01270 } 01271 } 01272 01273 template <typename T> 01274 bool 01275 BD_Shape<T>::max_min(const Linear_Expression& expr, 01276 const bool maximize, 01277 Coefficient& ext_n, Coefficient& ext_d, 01278 bool& included, 01279 Generator& g) const { 01280 // The dimension of `expr' should not be greater than the dimension 01281 // of `*this'. 01282 const dimension_type space_dim = space_dimension(); 01283 const dimension_type expr_space_dim = expr.space_dimension(); 01284 if (space_dim < expr_space_dim) 01285 throw_dimension_incompatible((maximize 01286 ? "maximize(e, ...)" 01287 : "minimize(e, ...)"), "e", expr); 01288 // Deal with zero-dim BDS first. 01289 if (space_dim == 0) { 01290 if (marked_empty()) 01291 return false; 01292 else { 01293 ext_n = expr.inhomogeneous_term(); 01294 ext_d = 1; 01295 included = true; 01296 g = point(); 01297 return true; 01298 } 01299 } 01300 01301 shortest_path_closure_assign(); 01302 // For an empty BDS we simply return false. 01303 if (marked_empty()) 01304 return false; 01305 01306 Optimization_Mode mode_max_min 01307 = maximize ? MAXIMIZATION : MINIMIZATION; 01308 MIP_Problem mip(space_dim, constraints(), expr, mode_max_min); 01309 if (mip.solve() == OPTIMIZED_MIP_PROBLEM) { 01310 g = mip.optimizing_point(); 01311 mip.evaluate_objective_function(g, ext_n, ext_d); 01312 included = true; 01313 return true; 01314 } 01315 // Here `expr' is unbounded in `*this'. 01316 return false; 01317 } 01318 01319 template <typename T> 01320 Poly_Con_Relation 01321 BD_Shape<T>::relation_with(const Congruence& cg) const { 01322 const dimension_type space_dim = space_dimension(); 01323 01324 // Dimension-compatibility check. 01325 if (cg.space_dimension() > space_dim) 01326 throw_dimension_incompatible("relation_with(cg)", cg); 01327 01328 // If the congruence is an equality, find the relation with 01329 // the equivalent equality constraint. 01330 if (cg.is_equality()) { 01331 Constraint c(cg); 01332 return relation_with(c); 01333 } 01334 01335 shortest_path_closure_assign(); 01336 01337 if (marked_empty()) 01338 return Poly_Con_Relation::saturates() 01339 && Poly_Con_Relation::is_included() 01340 && Poly_Con_Relation::is_disjoint(); 01341 01342 if (space_dim == 0) { 01343 if (cg.is_inconsistent()) 01344 return Poly_Con_Relation::is_disjoint(); 01345 else 01346 return Poly_Con_Relation::saturates() 01347 && Poly_Con_Relation::is_included(); 01348 } 01349 01350 // Find the lower bound for a hyperplane with direction 01351 // defined by the congruence. 01352 Linear_Expression le = Linear_Expression(cg); 01353 PPL_DIRTY_TEMP_COEFFICIENT(min_numer); 01354 PPL_DIRTY_TEMP_COEFFICIENT(min_denom); 01355 bool min_included; 01356 bool bounded_below = minimize(le, min_numer, min_denom, min_included); 01357 01358 // If there is no lower bound, then some of the hyperplanes defined by 01359 // the congruence will strictly intersect the shape. 01360 if (!bounded_below) 01361 return Poly_Con_Relation::strictly_intersects(); 01362 01363 // TODO: Consider adding a max_and_min() method, performing both 01364 // maximization and minimization so as to possibly exploit 01365 // incrementality of the MIP solver. 01366 01367 // Find the upper bound for a hyperplane with direction 01368 // defined by the congruence. 01369 PPL_DIRTY_TEMP_COEFFICIENT(max_numer); 01370 PPL_DIRTY_TEMP_COEFFICIENT(max_denom); 01371 bool max_included; 01372 bool bounded_above = maximize(le, max_numer, max_denom, max_included); 01373 01374 // If there is no upper bound, then some of the hyperplanes defined by 01375 // the congruence will strictly intersect the shape. 01376 if (!bounded_above) 01377 return Poly_Con_Relation::strictly_intersects(); 01378 01379 PPL_DIRTY_TEMP_COEFFICIENT(signed_distance); 01380 01381 // Find the position value for the hyperplane that satisfies the congruence 01382 // and is above the lower bound for the shape. 01383 PPL_DIRTY_TEMP_COEFFICIENT(min_value); 01384 min_value = min_numer / min_denom; 01385 const Coefficient& modulus = cg.modulus(); 01386 signed_distance = min_value % modulus; 01387 min_value -= signed_distance; 01388 if (min_value * min_denom < min_numer) 01389 min_value += modulus; 01390 01391 // Find the position value for the hyperplane that satisfies the congruence 01392 // and is below the upper bound for the shape. 01393 PPL_DIRTY_TEMP_COEFFICIENT(max_value); 01394 max_value = max_numer / max_denom; 01395 signed_distance = max_value % modulus; 01396 max_value += signed_distance; 01397 if (max_value * max_denom > max_numer) 01398 max_value -= modulus; 01399 01400 // If the upper bound value is less than the lower bound value, 01401 // then there is an empty intersection with the congruence; 01402 // otherwise it will strictly intersect. 01403 if (max_value < min_value) 01404 return Poly_Con_Relation::is_disjoint(); 01405 else 01406 return Poly_Con_Relation::strictly_intersects(); 01407 } 01408 01409 01410 template <typename T> 01411 Poly_Con_Relation 01412 BD_Shape<T>::relation_with(const Constraint& c) const { 01413 const dimension_type c_space_dim = c.space_dimension(); 01414 const dimension_type space_dim = space_dimension(); 01415 01416 // Dimension-compatibility check. 01417 if (c_space_dim > space_dim) 01418 throw_dimension_incompatible("relation_with(c)", c); 01419 01420 shortest_path_closure_assign(); 01421 01422 if (marked_empty()) 01423 return Poly_Con_Relation::saturates() 01424 && Poly_Con_Relation::is_included() 01425 && Poly_Con_Relation::is_disjoint(); 01426 01427 if (space_dim == 0) { 01428 if ((c.is_equality() && c.inhomogeneous_term() != 0) 01429 || (c.is_inequality() && c.inhomogeneous_term() < 0)) 01430 return Poly_Con_Relation::is_disjoint(); 01431 else if (c.is_strict_inequality() && c.inhomogeneous_term() == 0) 01432 // The constraint 0 > 0 implicitly defines the hyperplane 0 = 0; 01433 // thus, the zero-dimensional point also saturates it. 01434 return Poly_Con_Relation::saturates() 01435 && Poly_Con_Relation::is_disjoint(); 01436 else if (c.is_equality() || c.inhomogeneous_term() == 0) 01437 return Poly_Con_Relation::saturates() 01438 && Poly_Con_Relation::is_included(); 01439 else 01440 // The zero-dimensional point saturates 01441 // neither the positivity constraint 1 >= 0, 01442 // nor the strict positivity constraint 1 > 0. 01443 return Poly_Con_Relation::is_included(); 01444 } 01445 01446 dimension_type num_vars = 0; 01447 dimension_type i = 0; 01448 dimension_type j = 0; 01449 PPL_DIRTY_TEMP_COEFFICIENT(coeff); 01450 if (!extract_bounded_difference(c, c_space_dim, num_vars, i, j, coeff)) { 01451 // Constraints that are not bounded differences. 01452 // Use maximize() and minimize() to do much of the work. 01453 01454 // Find the linear expression for the constraint and use that to 01455 // find if the expression is bounded from above or below and if it 01456 // is, find the maximum and minimum values. 01457 Linear_Expression le; 01458 for (dimension_type k = c_space_dim; k-- > 0; ) { 01459 Variable v_k(k); 01460 le += c.coefficient(v_k) * v_k; 01461 } 01462 PPL_DIRTY_TEMP(Coefficient, max_numer); 01463 PPL_DIRTY_TEMP(Coefficient, max_denom); 01464 bool max_included; 01465 PPL_DIRTY_TEMP(Coefficient, min_numer); 01466 PPL_DIRTY_TEMP(Coefficient, min_denom); 01467 bool min_included; 01468 bool bounded_above = maximize(le, max_numer, max_denom, max_included); 01469 bool bounded_below = minimize(le, min_numer, min_denom, min_included); 01470 if (!bounded_above) { 01471 if (!bounded_below) 01472 return Poly_Con_Relation::strictly_intersects(); 01473 min_numer += c.inhomogeneous_term() * min_denom; 01474 switch (sgn(min_numer)) { 01475 case 1: 01476 if (c.is_equality()) 01477 return Poly_Con_Relation::is_disjoint(); 01478 return Poly_Con_Relation::is_included(); 01479 case 0: 01480 if (c.is_strict_inequality() || c.is_equality()) 01481 return Poly_Con_Relation::strictly_intersects(); 01482 return Poly_Con_Relation::is_included(); 01483 case -1: 01484 return Poly_Con_Relation::strictly_intersects(); 01485 } 01486 } 01487 if (!bounded_below) { 01488 max_numer += c.inhomogeneous_term() * max_denom; 01489 switch (sgn(max_numer)) { 01490 case 1: 01491 return Poly_Con_Relation::strictly_intersects(); 01492 case 0: 01493 if (c.is_strict_inequality()) 01494 return Poly_Con_Relation::is_disjoint(); 01495 return Poly_Con_Relation::strictly_intersects(); 01496 case -1: 01497 return Poly_Con_Relation::is_disjoint(); 01498 } 01499 } 01500 else { 01501 max_numer += c.inhomogeneous_term() * max_denom; 01502 min_numer += c.inhomogeneous_term() * min_denom; 01503 switch (sgn(max_numer)) { 01504 case 1: 01505 switch (sgn(min_numer)) { 01506 case 1: 01507 if (c.is_equality()) 01508 return Poly_Con_Relation::is_disjoint(); 01509 return Poly_Con_Relation::is_included(); 01510 case 0: 01511 if (c.is_equality()) 01512 return Poly_Con_Relation::strictly_intersects(); 01513 if (c.is_strict_inequality()) 01514 return Poly_Con_Relation::strictly_intersects(); 01515 return Poly_Con_Relation::is_included(); 01516 case -1: 01517 return Poly_Con_Relation::strictly_intersects(); 01518 } 01519 PPL_UNREACHABLE; 01520 break; 01521 case 0: 01522 if (min_numer == 0) { 01523 if (c.is_strict_inequality()) 01524 return Poly_Con_Relation::is_disjoint() 01525 && Poly_Con_Relation::saturates(); 01526 return Poly_Con_Relation::is_included() 01527 && Poly_Con_Relation::saturates(); 01528 } 01529 if (c.is_strict_inequality()) 01530 return Poly_Con_Relation::is_disjoint(); 01531 return Poly_Con_Relation::strictly_intersects(); 01532 case -1: 01533 return Poly_Con_Relation::is_disjoint(); 01534 } 01535 } 01536 } 01537 01538 // Constraints that are bounded differences. 01539 if (num_vars == 0) { 01540 // Dealing with a trivial constraint. 01541 switch (sgn(c.inhomogeneous_term())) { 01542 case -1: 01543 return Poly_Con_Relation::is_disjoint(); 01544 case 0: 01545 if (c.is_strict_inequality()) 01546 return Poly_Con_Relation::saturates() 01547 && Poly_Con_Relation::is_disjoint(); 01548 else 01549 return Poly_Con_Relation::saturates() 01550 && Poly_Con_Relation::is_included(); 01551 case 1: 01552 if (c.is_equality()) 01553 return Poly_Con_Relation::is_disjoint(); 01554 else 01555 return Poly_Con_Relation::is_included(); 01556 } 01557 } 01558 01559 // Select the cell to be checked for the "<=" part of the constraint, 01560 // and set `coeff' to the absolute value of itself. 01561 const bool negative = (coeff < 0); 01562 const N& x = negative ? dbm[i][j] : dbm[j][i]; 01563 const N& y = negative ? dbm[j][i] : dbm[i][j]; 01564 if (negative) 01565 neg_assign(coeff); 01566 // Deduce the relation/s of the constraint `c' of the form 01567 // `coeff*v - coeff*u </<=/== c.inhomogeneous_term()' 01568 // with the respectively constraints in `*this' 01569 // `-y <= v - u <= x'. 01570 // Let `d == c.inhomogeneous_term()/coeff' 01571 // and `d1 == -c.inhomogeneous_term()/coeff'. 01572 // The following variables of mpq_class type are used to be precise 01573 // when the bds is defined by integer constraints. 01574 PPL_DIRTY_TEMP(mpq_class, q_x); 01575 PPL_DIRTY_TEMP(mpq_class, q_y); 01576 PPL_DIRTY_TEMP(mpq_class, d); 01577 PPL_DIRTY_TEMP(mpq_class, d1); 01578 PPL_DIRTY_TEMP(mpq_class, c_denom); 01579 PPL_DIRTY_TEMP(mpq_class, q_denom); 01580 assign_r(c_denom, coeff, ROUND_NOT_NEEDED); 01581 assign_r(d, c.inhomogeneous_term(), ROUND_NOT_NEEDED); 01582 neg_assign_r(d1, d, ROUND_NOT_NEEDED); 01583 div_assign_r(d, d, c_denom, ROUND_NOT_NEEDED); 01584 div_assign_r(d1, d1, c_denom, ROUND_NOT_NEEDED); 01585 01586 if (is_plus_infinity(x)) { 01587 if (!is_plus_infinity(y)) { 01588 // `*this' is in the following form: 01589 // `-y <= v - u'. 01590 // In this case `*this' is disjoint from `c' if 01591 // `-y > d' (`-y >= d' if c is a strict equality), i.e. if 01592 // `y < d1' (`y <= d1' if c is a strict equality). 01593 PPL_DIRTY_TEMP_COEFFICIENT(numer); 01594 PPL_DIRTY_TEMP_COEFFICIENT(denom); 01595 numer_denom(y, numer, denom); 01596 assign_r(q_denom, denom, ROUND_NOT_NEEDED); 01597 assign_r(q_y, numer, ROUND_NOT_NEEDED); 01598 div_assign_r(q_y, q_y, q_denom, ROUND_NOT_NEEDED); 01599 if (q_y < d1) 01600 return Poly_Con_Relation::is_disjoint(); 01601 if (q_y == d1 && c.is_strict_inequality()) 01602 return Poly_Con_Relation::is_disjoint(); 01603 } 01604 01605 // In all other cases `*this' intersects `c'. 01606 return Poly_Con_Relation::strictly_intersects(); 01607 } 01608 01609 // Here `x' is not plus-infinity. 01610 PPL_DIRTY_TEMP_COEFFICIENT(numer); 01611 PPL_DIRTY_TEMP_COEFFICIENT(denom); 01612 numer_denom(x, numer, denom); 01613 assign_r(q_denom, denom, ROUND_NOT_NEEDED); 01614 assign_r(q_x, numer, ROUND_NOT_NEEDED); 01615 div_assign_r(q_x, q_x, q_denom, ROUND_NOT_NEEDED); 01616 01617 if (!is_plus_infinity(y)) { 01618 numer_denom(y, numer, denom); 01619 assign_r(q_denom, denom, ROUND_NOT_NEEDED); 01620 assign_r(q_y, numer, ROUND_NOT_NEEDED); 01621 div_assign_r(q_y, q_y, q_denom, ROUND_NOT_NEEDED); 01622 if (q_x == d && q_y == d1) { 01623 if (c.is_strict_inequality()) 01624 return Poly_Con_Relation::saturates() 01625 && Poly_Con_Relation::is_disjoint(); 01626 else 01627 return Poly_Con_Relation::saturates() 01628 && Poly_Con_Relation::is_included(); 01629 } 01630 // `*this' is disjoint from `c' when 01631 // `-y > d' (`-y >= d' if c is a strict equality), i.e. if 01632 // `y < d1' (`y <= d1' if c is a strict equality). 01633 if (q_y < d1) 01634 return Poly_Con_Relation::is_disjoint(); 01635 if (q_y == d1 && c.is_strict_inequality()) 01636 return Poly_Con_Relation::is_disjoint(); 01637 } 01638 01639 // Here `y' can be also plus-infinity. 01640 // If `c' is an equality, `*this' is disjoint from `c' if 01641 // `x < d'. 01642 if (d > q_x) { 01643 if (c.is_equality()) 01644 return Poly_Con_Relation::is_disjoint(); 01645 else 01646 return Poly_Con_Relation::is_included(); 01647 } 01648 01649 if (d == q_x && c.is_nonstrict_inequality()) 01650 return Poly_Con_Relation::is_included(); 01651 01652 // In all other cases `*this' intersects `c'. 01653 return Poly_Con_Relation::strictly_intersects(); 01654 } 01655 01656 template <typename T> 01657 Poly_Gen_Relation 01658 BD_Shape<T>::relation_with(const Generator& g) const { 01659 const dimension_type space_dim = space_dimension(); 01660 const dimension_type g_space_dim = g.space_dimension(); 01661 01662 // Dimension-compatibility check. 01663 if (space_dim < g_space_dim) 01664 throw_dimension_incompatible("relation_with(g)", g); 01665 01666 shortest_path_closure_assign(); 01667 // The empty BDS cannot subsume a generator. 01668 if (marked_empty()) 01669 return Poly_Gen_Relation::nothing(); 01670 01671 // A universe BDS in a zero-dimensional space subsumes 01672 // all the generators of a zero-dimensional space. 01673 if (space_dim == 0) 01674 return Poly_Gen_Relation::subsumes(); 01675 01676 const bool is_line = g.is_line(); 01677 const bool is_line_or_ray = g.is_line_or_ray(); 01678 01679 // The relation between the BDS and the given generator is obtained 01680 // checking if the generator satisfies all the constraints in the BDS. 01681 // To check if the generator satisfies all the constraints it's enough 01682 // studying the sign of the scalar product between the generator and 01683 // all the constraints in the BDS. 01684 01685 // Allocation of temporaries done once and for all. 01686 PPL_DIRTY_TEMP_COEFFICIENT(numer); 01687 PPL_DIRTY_TEMP_COEFFICIENT(denom); 01688 PPL_DIRTY_TEMP_COEFFICIENT(product); 01689 // We find in `*this' all the constraints. 01690 for (dimension_type i = 0; i <= space_dim; ++i) { 01691 const Coefficient& g_coeff_y = (i > g_space_dim || i == 0) 01692 ? Coefficient_zero() : g.coefficient(Variable(i-1)); 01693 const DB_Row<N>& dbm_i = dbm[i]; 01694 for (dimension_type j = i + 1; j <= space_dim; ++j) { 01695 const Coefficient& g_coeff_x = (j > g_space_dim) 01696 ? Coefficient_zero() : g.coefficient(Variable(j-1)); 01697 const N& dbm_ij = dbm_i[j]; 01698 const N& dbm_ji = dbm[j][i]; 01699 if (is_additive_inverse(dbm_ji, dbm_ij)) { 01700 // We have one equality constraint: denom*x - denom*y = numer. 01701 // Compute the scalar product. 01702 numer_denom(dbm_ij, numer, denom); 01703 product = 0; 01704 add_mul_assign(product, denom, g_coeff_y); 01705 add_mul_assign(product, -denom, g_coeff_x); 01706 if (!is_line_or_ray) 01707 add_mul_assign(product, numer, g.divisor()); 01708 if (product != 0) 01709 return Poly_Gen_Relation::nothing(); 01710 } 01711 else { 01712 // We have 0, 1 or 2 binary inequality constraint/s. 01713 if (!is_plus_infinity(dbm_ij)) { 01714 // We have the binary inequality constraint: 01715 // denom*x - denom*y <= numer. 01716 // Compute the scalar product. 01717 numer_denom(dbm_ij, numer, denom); 01718 product = 0; 01719 add_mul_assign(product, denom, g_coeff_y); 01720 add_mul_assign(product, -denom, g_coeff_x); 01721 if (!is_line_or_ray) 01722 add_mul_assign(product, numer, g.divisor()); 01723 if (is_line) { 01724 if (product != 0) 01725 // Lines must saturate all constraints. 01726 return Poly_Gen_Relation::nothing(); 01727 } 01728 else 01729 // `g' is either a ray, a point or a closure point. 01730 if (product < 0) 01731 return Poly_Gen_Relation::nothing(); 01732 } 01733 01734 if (!is_plus_infinity(dbm_ji)) { 01735 // We have the binary inequality constraint: denom*y - denom*x <= b. 01736 // Compute the scalar product. 01737 numer_denom(dbm_ji, numer, denom); 01738 product = 0; 01739 add_mul_assign(product, denom, g_coeff_x); 01740 add_mul_assign(product, -denom, g_coeff_y); 01741 if (!is_line_or_ray) 01742 add_mul_assign(product, numer, g.divisor()); 01743 if (is_line) { 01744 if (product != 0) 01745 // Lines must saturate all constraints. 01746 return Poly_Gen_Relation::nothing(); 01747 } 01748 else 01749 // `g' is either a ray, a point or a closure point. 01750 if (product < 0) 01751 return Poly_Gen_Relation::nothing(); 01752 } 01753 } 01754 } 01755 } 01756 01757 // The generator satisfies all the constraints. 01758 return Poly_Gen_Relation::subsumes(); 01759 } 01760 01761 template <typename T> 01762 void 01763 BD_Shape<T>::shortest_path_closure_assign() const { 01764 // Do something only if necessary. 01765 if (marked_empty() || marked_shortest_path_closed()) 01766 return; 01767 const dimension_type num_dimensions = space_dimension(); 01768 // Zero-dimensional BDSs are necessarily shortest-path closed. 01769 if (num_dimensions == 0) 01770 return; 01771 01772 // Even though the BDS will not change, its internal representation 01773 // is going to be modified by the Floyd-Warshall algorithm. 01774 BD_Shape& x = const_cast<BD_Shape<T>&>(*this); 01775 01776 // Fill the main diagonal with zeros. 01777 for (dimension_type h = num_dimensions + 1; h-- > 0; ) { 01778 PPL_ASSERT(is_plus_infinity(x.dbm[h][h])); 01779 assign_r(x.dbm[h][h], 0, ROUND_NOT_NEEDED); 01780 } 01781 01782 PPL_DIRTY_TEMP(N, sum); 01783 for (dimension_type k = num_dimensions + 1; k-- > 0; ) { 01784 const DB_Row<N>& x_dbm_k = x.dbm[k]; 01785 for (dimension_type i = num_dimensions + 1; i-- > 0; ) { 01786 DB_Row<N>& x_dbm_i = x.dbm[i]; 01787 const N& x_dbm_i_k = x_dbm_i[k]; 01788 if (!is_plus_infinity(x_dbm_i_k)) 01789 for (dimension_type j = num_dimensions + 1; j-- > 0; ) { 01790 const N& x_dbm_k_j = x_dbm_k[j]; 01791 if (!is_plus_infinity(x_dbm_k_j)) { 01792 // Rounding upward for correctness. 01793 add_assign_r(sum, x_dbm_i_k, x_dbm_k_j, ROUND_UP); 01794 min_assign(x_dbm_i[j], sum); 01795 } 01796 } 01797 } 01798 } 01799 01800 // Check for emptiness: the BDS is empty if and only if there is a 01801 // negative value on the main diagonal of `dbm'. 01802 for (dimension_type h = num_dimensions + 1; h-- > 0; ) { 01803 N& x_dbm_hh = x.dbm[h][h]; 01804 if (sgn(x_dbm_hh) < 0) { 01805 x.set_empty(); 01806 return; 01807 } 01808 else { 01809 PPL_ASSERT(sgn(x_dbm_hh) == 0); 01810 // Restore PLUS_INFINITY on the main diagonal. 01811 assign_r(x_dbm_hh, PLUS_INFINITY, ROUND_NOT_NEEDED); 01812 } 01813 } 01814 01815 // The BDS is not empty and it is now shortest-path closed. 01816 x.set_shortest_path_closed(); 01817 } 01818 01819 template <typename T> 01820 void 01821 BD_Shape<T>::incremental_shortest_path_closure_assign(Variable var) const { 01822 // Do something only if necessary. 01823 if (marked_empty() || marked_shortest_path_closed()) 01824 return; 01825 const dimension_type num_dimensions = space_dimension(); 01826 PPL_ASSERT(var.id() < num_dimensions); 01827 01828 // Even though the BDS will not change, its internal representation 01829 // is going to be modified by the incremental Floyd-Warshall algorithm. 01830 BD_Shape& x = const_cast<BD_Shape&>(*this); 01831 01832 // Fill the main diagonal with zeros. 01833 for (dimension_type h = num_dimensions + 1; h-- > 0; ) { 01834 PPL_ASSERT(is_plus_infinity(x.dbm[h][h])); 01835 assign_r(x.dbm[h][h], 0, ROUND_NOT_NEEDED); 01836 } 01837 01838 // Using the incremental Floyd-Warshall algorithm. 01839 PPL_DIRTY_TEMP(N, sum); 01840 const dimension_type v = var.id() + 1; 01841 DB_Row<N>& x_v = x.dbm[v]; 01842 // Step 1: Improve all constraints on variable `var'. 01843 for (dimension_type k = num_dimensions + 1; k-- > 0; ) { 01844 DB_Row<N>& x_k = x.dbm[k]; 01845 const N& x_v_k = x_v[k]; 01846 const N& x_k_v = x_k[v]; 01847 const bool x_v_k_finite = !is_plus_infinity(x_v_k); 01848 const bool x_k_v_finite = !is_plus_infinity(x_k_v); 01849 // Specialize inner loop based on finiteness info. 01850 if (x_v_k_finite) { 01851 if (x_k_v_finite) { 01852 // Here both x_v_k and x_k_v are finite. 01853 for (dimension_type i = num_dimensions + 1; i-- > 0; ) { 01854 DB_Row<N>& x_i = x.dbm[i]; 01855 const N& x_i_k = x_i[k]; 01856 if (!is_plus_infinity(x_i_k)) { 01857 add_assign_r(sum, x_i_k, x_k_v, ROUND_UP); 01858 min_assign(x_i[v], sum); 01859 } 01860 const N& x_k_i = x_k[i]; 01861 if (!is_plus_infinity(x_k_i)) { 01862 add_assign_r(sum, x_v_k, x_k_i, ROUND_UP); 01863 min_assign(x_v[i], sum); 01864 } 01865 } 01866 } 01867 else { 01868 // Here x_v_k is finite, but x_k_v is not. 01869 for (dimension_type i = num_dimensions + 1; i-- > 0; ) { 01870 const N& x_k_i = x_k[i]; 01871 if (!is_plus_infinity(x_k_i)) { 01872 add_assign_r(sum, x_v_k, x_k_i, ROUND_UP); 01873 min_assign(x_v[i], sum); 01874 } 01875 } 01876 } 01877 } 01878 else if (x_k_v_finite) { 01879 // Here x_v_k is infinite, but x_k_v is finite. 01880 for (dimension_type i = num_dimensions + 1; i-- > 0; ) { 01881 DB_Row<N>& x_i = x.dbm[i]; 01882 const N& x_i_k = x_i[k]; 01883 if (!is_plus_infinity(x_i_k)) { 01884 add_assign_r(sum, x_i_k, x_k_v, ROUND_UP); 01885 min_assign(x_i[v], sum); 01886 } 01887 } 01888 } 01889 else 01890 // Here both x_v_k and x_k_v are infinite. 01891 continue; 01892 } 01893 01894 // Step 2: improve the other bounds by using the precise bounds 01895 // for the constraints on `var'. 01896 for (dimension_type i = num_dimensions + 1; i-- > 0; ) { 01897 DB_Row<N>& x_i = x.dbm[i]; 01898 const N& x_i_v = x_i[v]; 01899 if (!is_plus_infinity(x_i_v)) { 01900 for (dimension_type j = num_dimensions + 1; j-- > 0; ) { 01901 const N& x_v_j = x_v[j]; 01902 if (!is_plus_infinity(x_v_j)) { 01903 add_assign_r(sum, x_i_v, x_v_j, ROUND_UP); 01904 min_assign(x_i[j], sum); 01905 } 01906 } 01907 } 01908 } 01909 01910 // Check for emptiness: the BDS is empty if and only if there is a 01911 // negative value on the main diagonal of `dbm'. 01912 for (dimension_type h = num_dimensions + 1; h-- > 0; ) { 01913 N& x_dbm_hh = x.dbm[h][h]; 01914 if (sgn(x_dbm_hh) < 0) { 01915 x.set_empty(); 01916 return; 01917 } 01918 else { 01919 PPL_ASSERT(sgn(x_dbm_hh) == 0); 01920 // Restore PLUS_INFINITY on the main diagonal. 01921 assign_r(x_dbm_hh, PLUS_INFINITY, ROUND_NOT_NEEDED); 01922 } 01923 } 01924 01925 // The BDS is not empty and it is now shortest-path closed. 01926 x.set_shortest_path_closed(); 01927 } 01928 01929 template <typename T> 01930 void 01931 BD_Shape<T>::shortest_path_reduction_assign() const { 01932 // Do something only if necessary. 01933 if (marked_shortest_path_reduced()) 01934 return; 01935 01936 const dimension_type space_dim = space_dimension(); 01937 // Zero-dimensional BDSs are necessarily reduced. 01938 if (space_dim == 0) 01939 return; 01940 01941 // First find the tightest constraints for this BDS. 01942 shortest_path_closure_assign(); 01943 01944 // If `*this' is empty, then there is nothing to reduce. 01945 if (marked_empty()) 01946 return; 01947 01948 // Step 1: compute zero-equivalence classes. 01949 // Variables corresponding to indices `i' and `j' are zero-equivalent 01950 // if they lie on a zero-weight loop; since the matrix is shortest-path 01951 // closed, this happens if and only if dbm[i][j] == -dbm[j][i]. 01952 std::vector<dimension_type> predecessor; 01953 compute_predecessors(predecessor); 01954 std::vector<dimension_type> leaders; 01955 compute_leader_indices(predecessor, leaders); 01956 const dimension_type num_leaders = leaders.size(); 01957 01958 Bit_Matrix redundancy(space_dim + 1, space_dim + 1); 01959 // Init all constraints to be redundant. 01960 // TODO: provide an appropriate method to set multiple bits. 01961 Bit_Row& red_0 = redundancy[0]; 01962 for (dimension_type j = space_dim + 1; j-- > 0; ) 01963 red_0.set(j); 01964 for (dimension_type i = space_dim + 1; i-- > 0; ) 01965 redundancy[i] = red_0; 01966 01967 // Step 2: flag non-redundant constraints in the (zero-cycle-free) 01968 // subsystem of bounded differences having only leaders as variables. 01969 PPL_DIRTY_TEMP(N, c); 01970 for (dimension_type l_i = 0; l_i < num_leaders; ++l_i) { 01971 const dimension_type i = leaders[l_i]; 01972 const DB_Row<N>& dbm_i = dbm[i]; 01973 Bit_Row& redundancy_i = redundancy[i]; 01974 for (dimension_type l_j = 0; l_j < num_leaders; ++l_j) { 01975 const dimension_type j = leaders[l_j]; 01976 if (redundancy_i[j]) { 01977 const N& dbm_i_j = dbm_i[j]; 01978 redundancy_i.clear(j); 01979 for (dimension_type l_k = 0; l_k < num_leaders; ++l_k) { 01980 const dimension_type k = leaders[l_k]; 01981 add_assign_r(c, dbm_i[k], dbm[k][j], ROUND_UP); 01982 if (dbm_i_j >= c) { 01983 redundancy_i.set(j); 01984 break; 01985 } 01986 } 01987 } 01988 } 01989 } 01990 01991 // Step 3: flag non-redundant constraints in zero-equivalence classes. 01992 // Each equivalence class must have a single 0-cycle connecting 01993 // all the equivalent variables in increasing order. 01994 std::deque<bool> dealt_with(space_dim + 1, false); 01995 for (dimension_type i = space_dim + 1; i-- > 0; ) 01996 // We only need to deal with non-singleton zero-equivalence classes 01997 // that haven't already been dealt with. 01998 if (i != predecessor[i] && !dealt_with[i]) { 01999 dimension_type j = i; 02000 while (true) { 02001 const dimension_type predecessor_j = predecessor[j]; 02002 if (j == predecessor_j) { 02003 // We finally found the leader of `i'. 02004 PPL_ASSERT(redundancy[i][j]); 02005 redundancy[i].clear(j); 02006 // Here we dealt with `j' (i.e., `predecessor_j'), but it is useless 02007 // to update `dealt_with' because `j' is a leader. 02008 break; 02009 } 02010 // We haven't found the leader of `i' yet. 02011 PPL_ASSERT(redundancy[predecessor_j][j]); 02012 redundancy[predecessor_j].clear(j); 02013 dealt_with[predecessor_j] = true; 02014 j = predecessor_j; 02015 } 02016 } 02017 02018 // Even though shortest-path reduction is not going to change the BDS, 02019 // it might change its internal representation. 02020 BD_Shape<T>& x = const_cast<BD_Shape<T>&>(*this); 02021 using std::swap; 02022 swap(x.redundancy_dbm, redundancy); 02023 x.set_shortest_path_reduced(); 02024 02025 PPL_ASSERT(is_shortest_path_reduced()); 02026 } 02027 02028 template <typename T> 02029 void 02030 BD_Shape<T>::upper_bound_assign(const BD_Shape& y) { 02031 const dimension_type space_dim = space_dimension(); 02032 02033 // Dimension-compatibility check. 02034 if (space_dim != y.space_dimension()) 02035 throw_dimension_incompatible("upper_bound_assign(y)", y); 02036 02037 // The upper bound of a BD shape `bd' with an empty shape is `bd'. 02038 y.shortest_path_closure_assign(); 02039 if (y.marked_empty()) 02040 return; 02041 shortest_path_closure_assign(); 02042 if (marked_empty()) { 02043 *this = y; 02044 return; 02045 } 02046 02047 // The bds-hull consists in constructing `*this' with the maximum 02048 // elements selected from `*this' and `y'. 02049 PPL_ASSERT(space_dim == 0 || marked_shortest_path_closed()); 02050 for (dimension_type i = space_dim + 1; i-- > 0; ) { 02051 DB_Row<N>& dbm_i = dbm[i]; 02052 const DB_Row<N>& y_dbm_i = y.dbm[i]; 02053 for (dimension_type j = space_dim + 1; j-- > 0; ) { 02054 N& dbm_ij = dbm_i[j]; 02055 const N& y_dbm_ij = y_dbm_i[j]; 02056 if (dbm_ij < y_dbm_ij) 02057 dbm_ij = y_dbm_ij; 02058 } 02059 } 02060 // Shortest-path closure is maintained (if it was holding). 02061 // TODO: see whether reduction can be (efficiently!) maintained too. 02062 if (marked_shortest_path_reduced()) 02063 reset_shortest_path_reduced(); 02064 PPL_ASSERT(OK()); 02065 } 02066 02067 template <typename T> 02068 bool 02069 BD_Shape<T>::BFT00_upper_bound_assign_if_exact(const BD_Shape& y) { 02070 // Declare a const reference to *this (to avoid accidental modifications). 02071 const BD_Shape& x = *this; 02072 const dimension_type x_space_dim = x.space_dimension(); 02073 02074 // Private method: the caller must ensure the following. 02075 PPL_ASSERT(x_space_dim == y.space_dimension()); 02076 02077 // The zero-dim case is trivial. 02078 if (x_space_dim == 0) { 02079 upper_bound_assign(y); 02080 return true; 02081 } 02082 // If `x' or `y' is (known to be) empty, the upper bound is exact. 02083 if (x.marked_empty()) { 02084 *this = y; 02085 return true; 02086 } 02087 else if (y.is_empty()) 02088 return true; 02089 else if (x.is_empty()) { 02090 *this = y; 02091 return true; 02092 } 02093 02094 // Here both `x' and `y' are known to be non-empty. 02095 // Implementation based on Algorithm 4.1 (page 6) in [BemporadFT00TR], 02096 // tailored to the special case of BD shapes. 02097 02098 Variable epsilon(x_space_dim); 02099 Linear_Expression zero_expr = 0*epsilon; 02100 Linear_Expression db_expr; 02101 PPL_DIRTY_TEMP_COEFFICIENT(numer); 02102 PPL_DIRTY_TEMP_COEFFICIENT(denom); 02103 02104 // Step 1: compute the constraint system for the envelope env(x,y) 02105 // and put into x_cs_removed and y_cs_removed those non-redundant 02106 // constraints that are not in the constraint system for env(x,y). 02107 // While at it, also add the additional space dimension (epsilon). 02108 Constraint_System env_cs; 02109 Constraint_System x_cs_removed; 02110 Constraint_System y_cs_removed; 02111 x.shortest_path_reduction_assign(); 02112 y.shortest_path_reduction_assign(); 02113 for (dimension_type i = x_space_dim + 1; i-- > 0; ) { 02114 const Bit_Row& x_red_i = x.redundancy_dbm[i]; 02115 const Bit_Row& y_red_i = y.redundancy_dbm[i]; 02116 const DB_Row<N>& x_dbm_i = x.dbm[i]; 02117 const DB_Row<N>& y_dbm_i = y.dbm[i]; 02118 for (dimension_type j = x_space_dim + 1; j-- > 0; ) { 02119 if (x_red_i[j] && y_red_i[j]) 02120 continue; 02121 if (!x_red_i[j]) { 02122 const N& x_dbm_ij = x_dbm_i[j]; 02123 PPL_ASSERT(!is_plus_infinity(x_dbm_ij)); 02124 numer_denom(x_dbm_ij, numer, denom); 02125 // Build skeleton DB constraint (having the right space dimension). 02126 db_expr = zero_expr; 02127 if (i > 0) 02128 db_expr += Variable(i-1); 02129 if (j > 0) 02130 db_expr -= Variable(j-1); 02131 if (denom != 1) 02132 db_expr *= denom; 02133 db_expr += numer; 02134 if (x_dbm_ij >= y_dbm_i[j]) 02135 env_cs.insert(db_expr >= 0); 02136 else { 02137 db_expr += epsilon; 02138 x_cs_removed.insert(db_expr == 0); 02139 } 02140 } 02141 if (!y_red_i[j]) { 02142 const N& y_dbm_ij = y_dbm_i[j]; 02143 const N& x_dbm_ij = x_dbm_i[j]; 02144 PPL_ASSERT(!is_plus_infinity(y_dbm_ij)); 02145 numer_denom(y_dbm_ij, numer, denom); 02146 // Build skeleton DB constraint (having the right space dimension). 02147 db_expr = zero_expr; 02148 if (i > 0) 02149 db_expr += Variable(i-1); 02150 if (j > 0) 02151 db_expr -= Variable(j-1); 02152 if (denom != 1) 02153 db_expr *= denom; 02154 db_expr += numer; 02155 if (y_dbm_ij >= x_dbm_ij) { 02156 // Check if same constraint was added when considering x_dbm_ij. 02157 if (!x_red_i[j] && x_dbm_ij == y_dbm_ij) 02158 continue; 02159 env_cs.insert(db_expr >= 0); 02160 } 02161 else { 02162 db_expr += epsilon; 02163 y_cs_removed.insert(db_expr == 0); 02164 } 02165 } 02166 } 02167 } 02168 02169 if (x_cs_removed.empty()) 02170 // No constraint of x was removed: y is included in x. 02171 return true; 02172 if (y_cs_removed.empty()) { 02173 // No constraint of y was removed: x is included in y. 02174 *this = y; 02175 return true; 02176 } 02177 02178 // In preparation to Step 4: build the common part of LP problems, 02179 // i.e., the constraints corresponding to env(x,y), 02180 // where the additional space dimension (epsilon) has to be maximized. 02181 MIP_Problem env_lp(x_space_dim + 1, env_cs, epsilon, MAXIMIZATION); 02182 // Pre-solve `env_lp' to later exploit incrementality. 02183 env_lp.solve(); 02184 PPL_ASSERT(env_lp.solve() != UNFEASIBLE_MIP_PROBLEM); 02185 02186 // Implementing loop in Steps 3-6. 02187 for (Constraint_System::const_iterator i = x_cs_removed.begin(), 02188 i_end = x_cs_removed.end(); i != i_end; ++i) { 02189 MIP_Problem lp_i(env_lp); 02190 lp_i.add_constraint(*i); 02191 // Pre-solve to exploit incrementality. 02192 if (lp_i.solve() == UNFEASIBLE_MIP_PROBLEM) 02193 continue; 02194 for (Constraint_System::const_iterator j = y_cs_removed.begin(), 02195 j_end = y_cs_removed.end(); j != j_end; ++j) { 02196 MIP_Problem lp_ij(lp_i); 02197 lp_ij.add_constraint(*j); 02198 // Solve and check for a positive optimal value. 02199 switch (lp_ij.solve()) { 02200 case UNFEASIBLE_MIP_PROBLEM: 02201 // CHECKME: is the following actually impossible? 02202 PPL_UNREACHABLE; 02203 return false; 02204 case UNBOUNDED_MIP_PROBLEM: 02205 return false; 02206 case OPTIMIZED_MIP_PROBLEM: 02207 lp_ij.optimal_value(numer, denom); 02208 if (numer > 0) 02209 return false; 02210 break; 02211 } 02212 } 02213 } 02214 02215 // The upper bound of x and y is indeed exact. 02216 upper_bound_assign(y); 02217 PPL_ASSERT(OK()); 02218 return true; 02219 } 02220 02221 template <typename T> 02222 template <bool integer_upper_bound> 02223 bool 02224 BD_Shape<T>::BHZ09_upper_bound_assign_if_exact(const BD_Shape& y) { 02225 PPL_COMPILE_TIME_CHECK(!integer_upper_bound 02226 || std::numeric_limits<T>::is_integer, 02227 "BD_Shape<T>::BHZ09_upper_bound_assign_if_exact(y):" 02228 " instantiating for integer upper bound," 02229 " but T in not an integer datatype."); 02230 02231 // FIXME, CHECKME: what about inexact computations? 02232 // Declare a const reference to *this (to avoid accidental modifications). 02233 const BD_Shape& x = *this; 02234 const dimension_type x_space_dim = x.space_dimension(); 02235 02236 // Private method: the caller must ensure the following. 02237 PPL_ASSERT(x_space_dim == y.space_dimension()); 02238 02239 // The zero-dim case is trivial. 02240 if (x_space_dim == 0) { 02241 upper_bound_assign(y); 02242 return true; 02243 } 02244 // If `x' or `y' is (known to be) empty, the upper bound is exact. 02245 if (x.marked_empty()) { 02246 *this = y; 02247 return true; 02248 } 02249 else if (y.is_empty()) 02250 return true; 02251 else if (x.is_empty()) { 02252 *this = y; 02253 return true; 02254 } 02255 02256 // Here both `x' and `y' are known to be non-empty. 02257 x.shortest_path_reduction_assign(); 02258 y.shortest_path_reduction_assign(); 02259 PPL_ASSERT(x.marked_shortest_path_closed()); 02260 PPL_ASSERT(y.marked_shortest_path_closed()); 02261 // Pre-compute the upper bound of `x' and `y'. 02262 BD_Shape<T> ub(x); 02263 ub.upper_bound_assign(y); 02264 02265 PPL_DIRTY_TEMP(N, lhs); 02266 PPL_DIRTY_TEMP(N, rhs); 02267 PPL_DIRTY_TEMP(N, temp_zero); 02268 assign_r(temp_zero, 0, ROUND_NOT_NEEDED); 02269 PPL_DIRTY_TEMP(N, temp_one); 02270 if (integer_upper_bound) 02271 assign_r(temp_one, 1, ROUND_NOT_NEEDED); 02272 02273 for (dimension_type i = x_space_dim + 1; i-- > 0; ) { 02274 const DB_Row<N>& x_i = x.dbm[i]; 02275 const Bit_Row& x_red_i = x.redundancy_dbm[i]; 02276 const DB_Row<N>& y_i = y.dbm[i]; 02277 const DB_Row<N>& ub_i = ub.dbm[i]; 02278 for (dimension_type j = x_space_dim + 1; j-- > 0; ) { 02279 // Check redundancy of x_i_j. 02280 if (x_red_i[j]) 02281 continue; 02282 // By non-redundancy, we know that i != j. 02283 PPL_ASSERT(i != j); 02284 const N& x_i_j = x_i[j]; 02285 if (x_i_j < y_i[j]) { 02286 for (dimension_type k = x_space_dim + 1; k-- > 0; ) { 02287 const DB_Row<N>& x_k = x.dbm[k]; 02288 const DB_Row<N>& y_k = y.dbm[k]; 02289 const Bit_Row& y_red_k = y.redundancy_dbm[k]; 02290 const DB_Row<N>& ub_k = ub.dbm[k]; 02291 const N& ub_k_j = (k == j) ? temp_zero : ub_k[j]; 02292 for (dimension_type ell = x_space_dim + 1; ell-- > 0; ) { 02293 // Check redundancy of y_k_ell. 02294 if (y_red_k[ell]) 02295 continue; 02296 // By non-redundancy, we know that k != ell. 02297 PPL_ASSERT(k != ell); 02298 const N& y_k_ell = y_k[ell]; 02299 if (y_k_ell < x_k[ell]) { 02300 // The first condition in BHZ09 theorem holds; 02301 // now check for the second condition. 02302 add_assign_r(lhs, x_i_j, y_k_ell, ROUND_UP); 02303 const N& ub_i_ell = (i == ell) ? temp_zero : ub_i[ell]; 02304 add_assign_r(rhs, ub_i_ell, ub_k_j, ROUND_UP); 02305 if (integer_upper_bound) { 02306 // Note: adding 1 rather than 2 (as in Theorem 5.3) 02307 // so as to later test for < rather than <=. 02308 add_assign_r(lhs, lhs, temp_one, ROUND_NOT_NEEDED); 02309 } 02310 // Testing for < in both the rational and integer case. 02311 if (lhs < rhs) 02312 return false; 02313 } 02314 } 02315 } 02316 } 02317 } 02318 } 02319 // The upper bound of x and y is indeed exact. 02320 m_swap(ub); 02321 PPL_ASSERT(OK()); 02322 return true; 02323 } 02324 02325 template <typename T> 02326 void 02327 BD_Shape<T>::difference_assign(const BD_Shape& y) { 02328 const dimension_type space_dim = space_dimension(); 02329 02330 // Dimension-compatibility check. 02331 if (space_dim != y.space_dimension()) 02332 throw_dimension_incompatible("difference_assign(y)", y); 02333 02334 BD_Shape new_bd_shape(space_dim, EMPTY); 02335 02336 BD_Shape& x = *this; 02337 02338 x.shortest_path_closure_assign(); 02339 // The difference of an empty bounded difference shape 02340 // and of a bounded difference shape `p' is empty. 02341 if (x.marked_empty()) 02342 return; 02343 y.shortest_path_closure_assign(); 02344 // The difference of a bounded difference shape `p' 02345 // and an empty bounded difference shape is `p'. 02346 if (y.marked_empty()) 02347 return; 02348 02349 // If both bounded difference shapes are zero-dimensional, 02350 // then at this point they are necessarily universe system of 02351 // bounded differences, so that their difference is empty. 02352 if (space_dim == 0) { 02353 x.set_empty(); 02354 return; 02355 } 02356 02357 // TODO: This is just an executable specification. 02358 // Have to find a more efficient method. 02359 if (y.contains(x)) { 02360 x.set_empty(); 02361 return; 02362 } 02363 02364 // We take a constraint of the system y at the time and we 02365 // consider its complementary. Then we intersect the union 02366 // of these complementary constraints with the system x. 02367 const Constraint_System& y_cs = y.constraints(); 02368 for (Constraint_System::const_iterator i = y_cs.begin(), 02369 y_cs_end = y_cs.end(); i != y_cs_end; ++i) { 02370 const Constraint& c = *i; 02371 // If the bounded difference shape `x' is included 02372 // in the bounded difference shape defined by `c', 02373 // then `c' _must_ be skipped, as adding its complement to `x' 02374 // would result in the empty bounded difference shape, 02375 // and as we would obtain a result that is less precise 02376 // than the bds-difference. 02377 if (x.relation_with(c).implies(Poly_Con_Relation::is_included())) 02378 continue; 02379 BD_Shape z = x; 02380 const Linear_Expression e = Linear_Expression(c); 02381 z.add_constraint(e <= 0); 02382 if (!z.is_empty()) 02383 new_bd_shape.upper_bound_assign(z); 02384 if (c.is_equality()) { 02385 z = x; 02386 z.add_constraint(e >= 0); 02387 if (!z.is_empty()) 02388 new_bd_shape.upper_bound_assign(z); 02389 } 02390 } 02391 *this = new_bd_shape; 02392 PPL_ASSERT(OK()); 02393 } 02394 02395 template <typename T> 02396 bool 02397 BD_Shape<T>::simplify_using_context_assign(const BD_Shape& y) { 02398 BD_Shape& x = *this; 02399 const dimension_type dim = x.space_dimension(); 02400 // Dimension-compatibility check. 02401 if (dim != y.space_dimension()) 02402 throw_dimension_incompatible("simplify_using_context_assign(y)", y); 02403 02404 // Filter away the zero-dimensional case. 02405 if (dim == 0) { 02406 if (y.marked_empty()) { 02407 x.set_zero_dim_univ(); 02408 return false; 02409 } 02410 else 02411 return !x.marked_empty(); 02412 } 02413 02414 // Filter away the case where `x' contains `y' 02415 // (this subsumes the case when `y' is empty). 02416 y.shortest_path_closure_assign(); 02417 if (x.contains(y)) { 02418 BD_Shape<T> res(dim, UNIVERSE); 02419 x.m_swap(res); 02420 return false; 02421 } 02422 02423 // Filter away the case where `x' is empty. 02424 x.shortest_path_closure_assign(); 02425 if (x.marked_empty()) { 02426 // Search for a constraint of `y' that is not a tautology. 02427 dimension_type i; 02428 dimension_type j; 02429 // Prefer unary constraints. 02430 i = 0; 02431 const DB_Row<N>& y_dbm_0 = y.dbm[0]; 02432 for (j = 1; j <= dim; ++j) { 02433 if (!is_plus_infinity(y_dbm_0[j])) 02434 // FIXME: if N is a float or bounded integer type, then 02435 // we also need to check that we are actually able to construct 02436 // a constraint inconsistent with respect to this one. 02437 goto found; 02438 } 02439 j = 0; 02440 for (i = 1; i <= dim; ++i) { 02441 if (!is_plus_infinity(y.dbm[i][0])) 02442 // FIXME: if N is a float or bounded integer type, then 02443 // we also need to check that we are actually able to construct 02444 // a constraint inconsistent with respect to this one. 02445 goto found; 02446 } 02447 // Then search binary constraints. 02448 for (i = 1; i <= dim; ++i) { 02449 const DB_Row<N>& y_dbm_i = y.dbm[i]; 02450 for (j = 1; j <= dim; ++j) 02451 if (!is_plus_infinity(y_dbm_i[j])) 02452 // FIXME: if N is a float or bounded integer type, then 02453 // we also need to check that we are actually able to construct 02454 // a constraint inconsistent with respect to this one. 02455 goto found; 02456 } 02457 // Not found: we were not able to build a constraint contradicting 02458 // one of the constraints in `y': `x' cannot be enlarged. 02459 return false; 02460 02461 found: 02462 // Found: build a new BDS contradicting the constraint found. 02463 PPL_ASSERT(i <= dim && j <= dim && (i > 0 || j > 0)); 02464 BD_Shape<T> res(dim, UNIVERSE); 02465 PPL_DIRTY_TEMP(N, tmp); 02466 assign_r(tmp, 1, ROUND_UP); 02467 add_assign_r(tmp, tmp, y.dbm[i][j], ROUND_UP); 02468 PPL_ASSERT(!is_plus_infinity(tmp)); 02469 // CHECKME: round down is really meant. 02470 neg_assign_r(res.dbm[j][i], tmp, ROUND_DOWN); 02471 x.m_swap(res); 02472 return false; 02473 } 02474 02475 // Here `x' and `y' are not empty and shortest-path closed; 02476 // also, `x' does not contain `y'. 02477 // Let `target' be the intersection of `x' and `y'. 02478 BD_Shape<T> target = x; 02479 target.intersection_assign(y); 02480 const bool bool_result = !target.is_empty(); 02481 02482 // Compute a reduced dbm for `x' and ... 02483 x.shortest_path_reduction_assign(); 02484 // ... count the non-redundant constraints. 02485 dimension_type x_num_non_redundant = (dim+1)*(dim+1); 02486 for (dimension_type i = dim + 1; i-- > 0; ) 02487 x_num_non_redundant -= x.redundancy_dbm[i].count_ones(); 02488 PPL_ASSERT(x_num_non_redundant > 0); 02489 02490 // Let `yy' be a copy of `y': we will keep adding to `yy' 02491 // the non-redundant constraints of `x', 02492 // stopping as soon as `yy' becomes equal to `target'. 02493 BD_Shape<T> yy = y; 02494 02495 // The constraints added to `yy' will be recorded in `res' ... 02496 BD_Shape<T> res(dim, UNIVERSE); 02497 // ... and we will count them too. 02498 dimension_type res_num_non_redundant = 0; 02499 02500 // Compute leader information for `x'. 02501 std::vector<dimension_type> x_leaders; 02502 x.compute_leaders(x_leaders); 02503 02504 // First go through the unary equality constraints. 02505 const DB_Row<N>& x_dbm_0 = x.dbm[0]; 02506 DB_Row<N>& yy_dbm_0 = yy.dbm[0]; 02507 DB_Row<N>& res_dbm_0 = res.dbm[0]; 02508 for (dimension_type j = 1; j <= dim; ++j) { 02509 // Unary equality constraints are encoded in entries dbm_0j and dbm_j0 02510 // provided index j has special variable index 0 as its leader. 02511 if (x_leaders[j] != 0) 02512 continue; 02513 PPL_ASSERT(!is_plus_infinity(x_dbm_0[j])); 02514 if (x_dbm_0[j] < yy_dbm_0[j]) { 02515 res_dbm_0[j] = x_dbm_0[j]; 02516 ++res_num_non_redundant; 02517 // Tighten context `yy' using the newly added constraint. 02518 yy_dbm_0[j] = x_dbm_0[j]; 02519 yy.reset_shortest_path_closed(); 02520 } 02521 PPL_ASSERT(!is_plus_infinity(x.dbm[j][0])); 02522 if (x.dbm[j][0] < yy.dbm[j][0]) { 02523 res.dbm[j][0] = x.dbm[j][0]; 02524 ++res_num_non_redundant; 02525 // Tighten context `yy' using the newly added constraint. 02526 yy.dbm[j][0] = x.dbm[j][0]; 02527 yy.reset_shortest_path_closed(); 02528 } 02529 // Restore shortest-path closure, if it was lost. 02530 if (!yy.marked_shortest_path_closed()) { 02531 Variable var_j(j-1); 02532 yy.incremental_shortest_path_closure_assign(var_j); 02533 if (target.contains(yy)) { 02534 // Target reached: swap `x' and `res' if needed. 02535 if (res_num_non_redundant < x_num_non_redundant) { 02536 res.reset_shortest_path_closed(); 02537 x.m_swap(res); 02538 } 02539 return bool_result; 02540 } 02541 } 02542 } 02543 02544 // Go through the binary equality constraints. 02545 // Note: no need to consider the case i == 1. 02546 for (dimension_type i = 2; i <= dim; ++i) { 02547 const dimension_type j = x_leaders[i]; 02548 if (j == i || j == 0) 02549 continue; 02550 PPL_ASSERT(!is_plus_infinity(x.dbm[i][j])); 02551 if (x.dbm[i][j] < yy.dbm[i][j]) { 02552 res.dbm[i][j] = x.dbm[i][j]; 02553 ++res_num_non_redundant; 02554 // Tighten context `yy' using the newly added constraint. 02555 yy.dbm[i][j] = x.dbm[i][j]; 02556 yy.reset_shortest_path_closed(); 02557 } 02558 PPL_ASSERT(!is_plus_infinity(x.dbm[j][i])); 02559 if (x.dbm[j][i] < yy.dbm[j][i]) { 02560 res.dbm[j][i] = x.dbm[j][i]; 02561 ++res_num_non_redundant; 02562 // Tighten context `yy' using the newly added constraint. 02563 yy.dbm[j][i] = x.dbm[j][i]; 02564 yy.reset_shortest_path_closed(); 02565 } 02566 // Restore shortest-path closure, if it was lost. 02567 if (!yy.marked_shortest_path_closed()) { 02568 Variable var_j(j-1); 02569 yy.incremental_shortest_path_closure_assign(var_j); 02570 if (target.contains(yy)) { 02571 // Target reached: swap `x' and `res' if needed. 02572 if (res_num_non_redundant < x_num_non_redundant) { 02573 res.reset_shortest_path_closed(); 02574 x.m_swap(res); 02575 } 02576 return bool_result; 02577 } 02578 } 02579 } 02580 02581 // Finally go through the (proper) inequality constraints: 02582 // both indices i and j should be leaders. 02583 for (dimension_type i = 0; i <= dim; ++i) { 02584 if (i != x_leaders[i]) 02585 continue; 02586 const DB_Row<N>& x_dbm_i = x.dbm[i]; 02587 const Bit_Row& x_redundancy_dbm_i = x.redundancy_dbm[i]; 02588 DB_Row<N>& yy_dbm_i = yy.dbm[i]; 02589 DB_Row<N>& res_dbm_i = res.dbm[i]; 02590 for (dimension_type j = 0; j <= dim; ++j) { 02591 if (j != x_leaders[j] || x_redundancy_dbm_i[j]) 02592 continue; 02593 N& yy_dbm_ij = yy_dbm_i[j]; 02594 const N& x_dbm_ij = x_dbm_i[j]; 02595 if (x_dbm_ij < yy_dbm_ij) { 02596 res_dbm_i[j] = x_dbm_ij; 02597 ++res_num_non_redundant; 02598 // Tighten context `yy' using the newly added constraint. 02599 yy_dbm_ij = x_dbm_ij; 02600 yy.reset_shortest_path_closed(); 02601 PPL_ASSERT(i > 0 || j > 0); 02602 Variable var(((i > 0) ? i : j) - 1); 02603 yy.incremental_shortest_path_closure_assign(var); 02604 if (target.contains(yy)) { 02605 // Target reached: swap `x' and `res' if needed. 02606 if (res_num_non_redundant < x_num_non_redundant) { 02607 res.reset_shortest_path_closed(); 02608 x.m_swap(res); 02609 } 02610 return bool_result; 02611 } 02612 } 02613 } 02614 } 02615 // This point should be unreachable. 02616 PPL_UNREACHABLE; 02617 return false; 02618 } 02619 02620 template <typename T> 02621 void 02622 BD_Shape<T>::add_space_dimensions_and_embed(const dimension_type m) { 02623 // Adding no dimensions is a no-op. 02624 if (m == 0) 02625 return; 02626 02627 const dimension_type space_dim = space_dimension(); 02628 const dimension_type new_space_dim = space_dim + m; 02629 const bool was_zero_dim_univ = (!marked_empty() && space_dim == 0); 02630 02631 // To embed an n-dimension space BDS in a (n+m)-dimension space, 02632 // we just add `m' rows and columns in the bounded difference shape, 02633 // initialized to PLUS_INFINITY. 02634 dbm.grow(new_space_dim + 1); 02635 02636 // Shortest-path closure is maintained (if it was holding). 02637 // TODO: see whether reduction can be (efficiently!) maintained too. 02638 if (marked_shortest_path_reduced()) 02639 reset_shortest_path_reduced(); 02640 02641 // If `*this' was the zero-dim space universe BDS, 02642 // the we can set the shortest-path closure flag. 02643 if (was_zero_dim_univ) 02644 set_shortest_path_closed(); 02645 02646 PPL_ASSERT(OK()); 02647 } 02648 02649 template <typename T> 02650 void 02651 BD_Shape<T>::add_space_dimensions_and_project(const dimension_type m) { 02652 // Adding no dimensions is a no-op. 02653 if (m == 0) 02654 return; 02655 02656 const dimension_type space_dim = space_dimension(); 02657 02658 // If `*this' was zero-dimensional, then we add `m' rows and columns. 02659 // If it also was non-empty, then we zero all the added elements 02660 // and set the flag for shortest-path closure. 02661 if (space_dim == 0) { 02662 dbm.grow(m + 1); 02663 if (!marked_empty()) { 02664 for (dimension_type i = m + 1; i-- > 0; ) { 02665 DB_Row<N>& dbm_i = dbm[i]; 02666 for (dimension_type j = m + 1; j-- > 0; ) 02667 if (i != j) 02668 assign_r(dbm_i[j], 0, ROUND_NOT_NEEDED); 02669 } 02670 set_shortest_path_closed(); 02671 } 02672 PPL_ASSERT(OK()); 02673 return; 02674 } 02675 02676 // To project an n-dimension space bounded difference shape 02677 // in a (n+m)-dimension space, we add `m' rows and columns. 02678 // In the first row and column of the matrix we add `zero' from 02679 // the (n+1)-th position to the end. 02680 const dimension_type new_space_dim = space_dim + m; 02681 dbm.grow(new_space_dim + 1); 02682 02683 // Bottom of the matrix and first row. 02684 DB_Row<N>& dbm_0 = dbm[0]; 02685 for (dimension_type i = space_dim + 1; i <= new_space_dim; ++i) { 02686 assign_r(dbm[i][0], 0, ROUND_NOT_NEEDED); 02687 assign_r(dbm_0[i], 0, ROUND_NOT_NEEDED); 02688 } 02689 02690 if (marked_shortest_path_closed()) 02691 reset_shortest_path_closed(); 02692 PPL_ASSERT(OK()); 02693 } 02694 02695 template <typename T> 02696 void 02697 BD_Shape<T>::remove_space_dimensions(const Variables_Set& vars) { 02698 // The removal of no dimensions from any BDS is a no-op. 02699 // Note that this case also captures the only legal removal of 02700 // space dimensions from a BDS in a 0-dim space. 02701 if (vars.empty()) { 02702 PPL_ASSERT(OK()); 02703 return; 02704 } 02705 02706 const dimension_type old_space_dim = space_dimension(); 02707 02708 // Dimension-compatibility check. 02709 const dimension_type min_space_dim = vars.space_dimension(); 02710 if (old_space_dim < min_space_dim) 02711 throw_dimension_incompatible("remove_space_dimensions(vs)", min_space_dim); 02712 02713 // Shortest-path closure is necessary to keep precision. 02714 shortest_path_closure_assign(); 02715 02716 // When removing _all_ dimensions from a BDS, we obtain the 02717 // zero-dimensional BDS. 02718 const dimension_type new_space_dim = old_space_dim - vars.size(); 02719 if (new_space_dim == 0) { 02720 dbm.resize_no_copy(1); 02721 if (!marked_empty()) 02722 // We set the zero_dim_univ flag. 02723 set_zero_dim_univ(); 02724 PPL_ASSERT(OK()); 02725 return; 02726 } 02727 02728 // Handle the case of an empty BD_Shape. 02729 if (marked_empty()) { 02730 dbm.resize_no_copy(new_space_dim + 1); 02731 PPL_ASSERT(OK()); 02732 return; 02733 } 02734 02735 // Shortest-path closure is maintained. 02736 // TODO: see whether reduction can be (efficiently!) maintained too. 02737 if (marked_shortest_path_reduced()) 02738 reset_shortest_path_reduced(); 02739 02740 // For each variable to remove, we fill the corresponding column and 02741 // row by shifting respectively left and above those 02742 // columns and rows, that will not be removed. 02743 Variables_Set::const_iterator vsi = vars.begin(); 02744 Variables_Set::const_iterator vsi_end = vars.end(); 02745 dimension_type dst = *vsi + 1; 02746 dimension_type src = dst + 1; 02747 for (++vsi; vsi != vsi_end; ++vsi) { 02748 const dimension_type vsi_next = *vsi + 1; 02749 // All other columns and rows are moved respectively to the left 02750 // and above. 02751 while (src < vsi_next) { 02752 using std::swap; 02753 swap(dbm[dst], dbm[src]); 02754 for (dimension_type i = old_space_dim + 1; i-- > 0; ) { 02755 DB_Row<N>& dbm_i = dbm[i]; 02756 assign_or_swap(dbm_i[dst], dbm_i[src]); 02757 } 02758 ++dst; 02759 ++src; 02760 } 02761 ++src; 02762 } 02763 02764 // Moving the remaining rows and columns. 02765 while (src <= old_space_dim) { 02766 using std::swap; 02767 swap(dbm[dst], dbm[src]); 02768 for (dimension_type i = old_space_dim + 1; i-- > 0; ) { 02769 DB_Row<N>& dbm_i = dbm[i]; 02770 assign_or_swap(dbm_i[dst], dbm_i[src]); 02771 } 02772 ++src; 02773 ++dst; 02774 } 02775 02776 // Update the space dimension. 02777 dbm.resize_no_copy(new_space_dim + 1); 02778 PPL_ASSERT(OK()); 02779 } 02780 02781 template <typename T> 02782 template <typename Partial_Function> 02783 void 02784 BD_Shape<T>::map_space_dimensions(const Partial_Function& pfunc) { 02785 const dimension_type space_dim = space_dimension(); 02786 // TODO: this implementation is just an executable specification. 02787 if (space_dim == 0) 02788 return; 02789 02790 if (pfunc.has_empty_codomain()) { 02791 // All dimensions vanish: the BDS becomes zero_dimensional. 02792 remove_higher_space_dimensions(0); 02793 return; 02794 } 02795 02796 const dimension_type new_space_dim = pfunc.max_in_codomain() + 1; 02797 // If we are going to actually reduce the space dimension, 02798 // then shortest-path closure is required to keep precision. 02799 if (new_space_dim < space_dim) 02800 shortest_path_closure_assign(); 02801 02802 // If the BDS is empty, then it is sufficient to adjust the 02803 // space dimension of the bounded difference shape. 02804 if (marked_empty()) { 02805 remove_higher_space_dimensions(new_space_dim); 02806 return; 02807 } 02808 02809 // Shortest-path closure is maintained (if it was holding). 02810 // TODO: see whether reduction can be (efficiently!) maintained too. 02811 if (marked_shortest_path_reduced()) 02812 reset_shortest_path_reduced(); 02813 02814 // We create a new matrix with the new space dimension. 02815 DB_Matrix<N> x(new_space_dim+1); 02816 // First of all we must map the unary constraints, because 02817 // there is the fictitious variable `zero', that can't be mapped 02818 // at all. 02819 DB_Row<N>& dbm_0 = dbm[0]; 02820 DB_Row<N>& x_0 = x[0]; 02821 for (dimension_type j = 1; j <= space_dim; ++j) { 02822 dimension_type new_j; 02823 if (pfunc.maps(j - 1, new_j)) { 02824 assign_or_swap(x_0[new_j + 1], dbm_0[j]); 02825 assign_or_swap(x[new_j + 1][0], dbm[j][0]); 02826 } 02827 } 02828 // Now we map the binary constraints, exchanging the indexes. 02829 for (dimension_type i = 1; i <= space_dim; ++i) { 02830 dimension_type new_i; 02831 if (pfunc.maps(i - 1, new_i)) { 02832 DB_Row<N>& dbm_i = dbm[i]; 02833 ++new_i; 02834 DB_Row<N>& x_new_i = x[new_i]; 02835 for (dimension_type j = i+1; j <= space_dim; ++j) { 02836 dimension_type new_j; 02837 if (pfunc.maps(j - 1, new_j)) { 02838 ++new_j; 02839 assign_or_swap(x_new_i[new_j], dbm_i[j]); 02840 assign_or_swap(x[new_j][new_i], dbm[j][i]); 02841 } 02842 } 02843 } 02844 } 02845 02846 using std::swap; 02847 swap(dbm, x); 02848 PPL_ASSERT(OK()); 02849 } 02850 02851 template <typename T> 02852 void 02853 BD_Shape<T>::intersection_assign(const BD_Shape& y) { 02854 const dimension_type space_dim = space_dimension(); 02855 02856 // Dimension-compatibility check. 02857 if (space_dim != y.space_dimension()) 02858 throw_dimension_incompatible("intersection_assign(y)", y); 02859 02860 // If one of the two bounded difference shapes is empty, 02861 // the intersection is empty. 02862 if (marked_empty()) 02863 return; 02864 if (y.marked_empty()) { 02865 set_empty(); 02866 return; 02867 } 02868 02869 // If both bounded difference shapes are zero-dimensional, 02870 // then at this point they are necessarily non-empty, 02871 // so that their intersection is non-empty too. 02872 if (space_dim == 0) 02873 return; 02874 02875 // To intersect two bounded difference shapes we compare 02876 // the constraints and we choose the less values. 02877 bool changed = false; 02878 for (dimension_type i = space_dim + 1; i-- > 0; ) { 02879 DB_Row<N>& dbm_i = dbm[i]; 02880 const DB_Row<N>& y_dbm_i = y.dbm[i]; 02881 for (dimension_type j = space_dim + 1; j-- > 0; ) { 02882 N& dbm_ij = dbm_i[j]; 02883 const N& y_dbm_ij = y_dbm_i[j]; 02884 if (dbm_ij > y_dbm_ij) { 02885 dbm_ij = y_dbm_ij; 02886 changed = true; 02887 } 02888 } 02889 } 02890 02891 if (changed && marked_shortest_path_closed()) 02892 reset_shortest_path_closed(); 02893 PPL_ASSERT(OK()); 02894 } 02895 02896 template <typename T> 02897 template <typename Iterator> 02898 void 02899 BD_Shape<T>::CC76_extrapolation_assign(const BD_Shape& y, 02900 Iterator first, Iterator last, 02901 unsigned* tp) { 02902 const dimension_type space_dim = space_dimension(); 02903 02904 // Dimension-compatibility check. 02905 if (space_dim != y.space_dimension()) 02906 throw_dimension_incompatible("CC76_extrapolation_assign(y)", y); 02907 02908 // We assume that `y' is contained in or equal to `*this'. 02909 PPL_EXPECT_HEAVY(copy_contains(*this, y)); 02910 02911 // If both bounded difference shapes are zero-dimensional, 02912 // since `*this' contains `y', we simply return `*this'. 02913 if (space_dim == 0) 02914 return; 02915 02916 shortest_path_closure_assign(); 02917 // If `*this' is empty, since `*this' contains `y', `y' is empty too. 02918 if (marked_empty()) 02919 return; 02920 y.shortest_path_closure_assign(); 02921 // If `y' is empty, we return. 02922 if (y.marked_empty()) 02923 return; 02924 02925 // If there are tokens available, work on a temporary copy. 02926 if (tp != 0 && *tp > 0) { 02927 BD_Shape<T> x_tmp(*this); 02928 x_tmp.CC76_extrapolation_assign(y, first, last, 0); 02929 // If the widening was not precise, use one of the available tokens. 02930 if (!contains(x_tmp)) 02931 --(*tp); 02932 return; 02933 } 02934 02935 // Compare each constraint in `y' to the corresponding one in `*this'. 02936 // The constraint in `*this' is kept as is if it is stronger than or 02937 // equal to the constraint in `y'; otherwise, the inhomogeneous term 02938 // of the constraint in `*this' is further compared with elements taken 02939 // from a sorted container (the stop-points, provided by the user), and 02940 // is replaced by the first entry, if any, which is greater than or equal 02941 // to the inhomogeneous term. If no such entry exists, the constraint 02942 // is removed altogether. 02943 for (dimension_type i = space_dim + 1; i-- > 0; ) { 02944 DB_Row<N>& dbm_i = dbm[i]; 02945 const DB_Row<N>& y_dbm_i = y.dbm[i]; 02946 for (dimension_type j = space_dim + 1; j-- > 0; ) { 02947 N& dbm_ij = dbm_i[j]; 02948 const N& y_dbm_ij = y_dbm_i[j]; 02949 if (y_dbm_ij < dbm_ij) { 02950 Iterator k = std::lower_bound(first, last, dbm_ij); 02951 if (k != last) { 02952 if (dbm_ij < *k) 02953 assign_r(dbm_ij, *k, ROUND_UP); 02954 } 02955 else 02956 assign_r(dbm_ij, PLUS_INFINITY, ROUND_NOT_NEEDED); 02957 } 02958 } 02959 } 02960 reset_shortest_path_closed(); 02961 PPL_ASSERT(OK()); 02962 } 02963 02964 template <typename T> 02965 void 02966 BD_Shape<T>::get_limiting_shape(const Constraint_System& cs, 02967 BD_Shape& limiting_shape) const { 02968 const dimension_type cs_space_dim = cs.space_dimension(); 02969 // Private method: the caller has to ensure the following. 02970 PPL_ASSERT(cs_space_dim <= space_dimension()); 02971 02972 shortest_path_closure_assign(); 02973 bool changed = false; 02974 PPL_DIRTY_TEMP_COEFFICIENT(coeff); 02975 PPL_DIRTY_TEMP_COEFFICIENT(minus_c_term); 02976 PPL_DIRTY_TEMP(N, d); 02977 PPL_DIRTY_TEMP(N, d1); 02978 for (Constraint_System::const_iterator cs_i = cs.begin(), 02979 cs_end = cs.end(); cs_i != cs_end; ++cs_i) { 02980 const Constraint& c = *cs_i; 02981 dimension_type num_vars = 0; 02982 dimension_type i = 0; 02983 dimension_type j = 0; 02984 // Constraints that are not bounded differences are ignored. 02985 if (extract_bounded_difference(c, cs_space_dim, num_vars, i, j, coeff)) { 02986 // Select the cell to be modified for the "<=" part of the constraint, 02987 // and set `coeff' to the absolute value of itself. 02988 const bool negative = (coeff < 0); 02989 const N& x = negative ? dbm[i][j] : dbm[j][i]; 02990 const N& y = negative ? dbm[j][i] : dbm[i][j]; 02991 DB_Matrix<N>& ls_dbm = limiting_shape.dbm; 02992 if (negative) 02993 neg_assign(coeff); 02994 // Compute the bound for `x', rounding towards plus infinity. 02995 div_round_up(d, c.inhomogeneous_term(), coeff); 02996 if (x <= d) { 02997 if (c.is_inequality()) { 02998 N& ls_x = negative ? ls_dbm[i][j] : ls_dbm[j][i]; 02999 if (ls_x > d) { 03000 ls_x = d; 03001 changed = true; 03002 } 03003 } 03004 else { 03005 // Compute the bound for `y', rounding towards plus infinity. 03006 neg_assign(minus_c_term, c.inhomogeneous_term()); 03007 div_round_up(d1, minus_c_term, coeff); 03008 if (y <= d1) { 03009 N& ls_x = negative ? ls_dbm[i][j] : ls_dbm[j][i]; 03010 N& ls_y = negative ? ls_dbm[j][i] : ls_dbm[i][j]; 03011 if ((ls_x >= d && ls_y > d1) || (ls_x > d && ls_y >= d1)) { 03012 ls_x = d; 03013 ls_y = d1; 03014 changed = true; 03015 } 03016 } 03017 } 03018 } 03019 } 03020 } 03021 03022 // In general, adding a constraint does not preserve the shortest-path 03023 // closure of the bounded difference shape. 03024 if (changed && limiting_shape.marked_shortest_path_closed()) 03025 limiting_shape.reset_shortest_path_closed(); 03026 } 03027 03028 template <typename T> 03029 void 03030 BD_Shape<T>::limited_CC76_extrapolation_assign(const BD_Shape& y, 03031 const Constraint_System& cs, 03032 unsigned* tp) { 03033 // Dimension-compatibility check. 03034 const dimension_type space_dim = space_dimension(); 03035 if (space_dim != y.space_dimension()) 03036 throw_dimension_incompatible("limited_CC76_extrapolation_assign(y, cs)", 03037 y); 03038 03039 // `cs' must be dimension-compatible with the two systems 03040 // of bounded differences. 03041 const dimension_type cs_space_dim = cs.space_dimension(); 03042 if (space_dim < cs_space_dim) 03043 throw_invalid_argument("limited_CC76_extrapolation_assign(y, cs)", 03044 "cs is space_dimension incompatible"); 03045 03046 // Strict inequalities not allowed. 03047 if (cs.has_strict_inequalities()) 03048 throw_invalid_argument("limited_CC76_extrapolation_assign(y, cs)", 03049 "cs has strict inequalities"); 03050 03051 // The limited CC76-extrapolation between two systems of bounded 03052 // differences in a zero-dimensional space is a system of bounded 03053 // differences in a zero-dimensional space, too. 03054 if (space_dim == 0) 03055 return; 03056 03057 // We assume that `y' is contained in or equal to `*this'. 03058 PPL_EXPECT_HEAVY(copy_contains(*this, y)); 03059 03060 // If `*this' is empty, since `*this' contains `y', `y' is empty too. 03061 if (marked_empty()) 03062 return; 03063 // If `y' is empty, we return. 03064 if (y.marked_empty()) 03065 return; 03066 03067 BD_Shape<T> limiting_shape(space_dim, UNIVERSE); 03068 get_limiting_shape(cs, limiting_shape); 03069 CC76_extrapolation_assign(y, tp); 03070 intersection_assign(limiting_shape); 03071 } 03072 03073 template <typename T> 03074 void 03075 BD_Shape<T>::BHMZ05_widening_assign(const BD_Shape& y, unsigned* tp) { 03076 const dimension_type space_dim = space_dimension(); 03077 03078 // Dimension-compatibility check. 03079 if (space_dim != y.space_dimension()) 03080 throw_dimension_incompatible("BHMZ05_widening_assign(y)", y); 03081 03082 // We assume that `y' is contained in or equal to `*this'. 03083 PPL_EXPECT_HEAVY(copy_contains(*this, y)); 03084 03085 // Compute the affine dimension of `y'. 03086 const dimension_type y_affine_dim = y.affine_dimension(); 03087 // If the affine dimension of `y' is zero, then either `y' is 03088 // zero-dimensional, or it is empty, or it is a singleton. 03089 // In all cases, due to the inclusion hypothesis, the result is `*this'. 03090 if (y_affine_dim == 0) 03091 return; 03092 03093 // If the affine dimension has changed, due to the inclusion hypothesis, 03094 // the result is `*this'. 03095 const dimension_type x_affine_dim = affine_dimension(); 03096 PPL_ASSERT(x_affine_dim >= y_affine_dim); 03097 if (x_affine_dim != y_affine_dim) 03098 return; 03099 03100 // If there are tokens available, work on a temporary copy. 03101 if (tp != 0 && *tp > 0) { 03102 BD_Shape<T> x_tmp(*this); 03103 x_tmp.BHMZ05_widening_assign(y, 0); 03104 // If the widening was not precise, use one of the available tokens. 03105 if (!contains(x_tmp)) 03106 --(*tp); 03107 return; 03108 } 03109 03110 // Here no token is available. 03111 PPL_ASSERT(marked_shortest_path_closed() && y.marked_shortest_path_closed()); 03112 // Minimize `y'. 03113 y.shortest_path_reduction_assign(); 03114 03115 // Extrapolate unstable bounds, taking into account redundancy in `y'. 03116 for (dimension_type i = space_dim + 1; i-- > 0; ) { 03117 DB_Row<N>& dbm_i = dbm[i]; 03118 const DB_Row<N>& y_dbm_i = y.dbm[i]; 03119 const Bit_Row& y_redundancy_i = y.redundancy_dbm[i]; 03120 for (dimension_type j = space_dim + 1; j-- > 0; ) { 03121 N& dbm_ij = dbm_i[j]; 03122 // Note: in the following line the use of `!=' (as opposed to 03123 // the use of `<' that would seem -but is not- equivalent) is 03124 // intentional. 03125 if (y_redundancy_i[j] || y_dbm_i[j] != dbm_ij) 03126 assign_r(dbm_ij, PLUS_INFINITY, ROUND_NOT_NEEDED); 03127 } 03128 } 03129 // NOTE: this will also reset the shortest-path reduction flag, 03130 // even though the dbm is still in reduced form. However, the 03131 // current implementation invariant requires that any reduced dbm 03132 // is closed too. 03133 reset_shortest_path_closed(); 03134 PPL_ASSERT(OK()); 03135 } 03136 03137 template <typename T> 03138 void 03139 BD_Shape<T>::limited_BHMZ05_extrapolation_assign(const BD_Shape& y, 03140 const Constraint_System& cs, 03141 unsigned* tp) { 03142 // Dimension-compatibility check. 03143 const dimension_type space_dim = space_dimension(); 03144 if (space_dim != y.space_dimension()) 03145 throw_dimension_incompatible("limited_BHMZ05_extrapolation_assign(y, cs)", 03146 y); 03147 // `cs' must be dimension-compatible with the two systems 03148 // of bounded differences. 03149 const dimension_type cs_space_dim = cs.space_dimension(); 03150 if (space_dim < cs_space_dim) 03151 throw_invalid_argument("limited_BHMZ05_extrapolation_assign(y, cs)", 03152 "cs is space-dimension incompatible"); 03153 03154 // Strict inequalities are not allowed. 03155 if (cs.has_strict_inequalities()) 03156 throw_invalid_argument("limited_BHMZ05_extrapolation_assign(y, cs)", 03157 "cs has strict inequalities"); 03158 03159 // The limited BHMZ05-extrapolation between two systems of bounded 03160 // differences in a zero-dimensional space is a system of bounded 03161 // differences in a zero-dimensional space, too. 03162 if (space_dim == 0) 03163 return; 03164 03165 // We assume that `y' is contained in or equal to `*this'. 03166 PPL_EXPECT_HEAVY(copy_contains(*this, y)); 03167 03168 // If `*this' is empty, since `*this' contains `y', `y' is empty too. 03169 if (marked_empty()) 03170 return; 03171 // If `y' is empty, we return. 03172 if (y.marked_empty()) 03173 return; 03174 03175 BD_Shape<T> limiting_shape(space_dim, UNIVERSE); 03176 get_limiting_shape(cs, limiting_shape); 03177 BHMZ05_widening_assign(y, tp); 03178 intersection_assign(limiting_shape); 03179 } 03180 03181 template <typename T> 03182 void 03183 BD_Shape<T>::CC76_narrowing_assign(const BD_Shape& y) { 03184 const dimension_type space_dim = space_dimension(); 03185 03186 // Dimension-compatibility check. 03187 if (space_dim != y.space_dimension()) 03188 throw_dimension_incompatible("CC76_narrowing_assign(y)", y); 03189 03190 // We assume that `*this' is contained in or equal to `y'. 03191 PPL_EXPECT_HEAVY(copy_contains(y, *this)); 03192 03193 // If both bounded difference shapes are zero-dimensional, 03194 // since `y' contains `*this', we simply return `*this'. 03195 if (space_dim == 0) 03196 return; 03197 03198 y.shortest_path_closure_assign(); 03199 // If `y' is empty, since `y' contains `this', `*this' is empty too. 03200 if (y.marked_empty()) 03201 return; 03202 shortest_path_closure_assign(); 03203 // If `*this' is empty, we return. 03204 if (marked_empty()) 03205 return; 03206 03207 // Replace each constraint in `*this' by the corresponding constraint 03208 // in `y' if the corresponding inhomogeneous terms are both finite. 03209 bool changed = false; 03210 for (dimension_type i = space_dim + 1; i-- > 0; ) { 03211 DB_Row<N>& dbm_i = dbm[i]; 03212 const DB_Row<N>& y_dbm_i = y.dbm[i]; 03213 for (dimension_type j = space_dim + 1; j-- > 0; ) { 03214 N& dbm_ij = dbm_i[j]; 03215 const N& y_dbm_ij = y_dbm_i[j]; 03216 if (!is_plus_infinity(dbm_ij) 03217 && !is_plus_infinity(y_dbm_ij) 03218 && dbm_ij != y_dbm_ij) { 03219 dbm_ij = y_dbm_ij; 03220 changed = true; 03221 } 03222 } 03223 } 03224 if (changed && marked_shortest_path_closed()) 03225 reset_shortest_path_closed(); 03226 PPL_ASSERT(OK()); 03227 } 03228 03229 template <typename T> 03230 void 03231 BD_Shape<T> 03232 ::deduce_v_minus_u_bounds(const dimension_type v, 03233 const dimension_type last_v, 03234 const Linear_Expression& sc_expr, 03235 Coefficient_traits::const_reference sc_denom, 03236 const N& ub_v) { 03237 PPL_ASSERT(sc_denom > 0); 03238 PPL_ASSERT(!is_plus_infinity(ub_v)); 03239 // Deduce constraints of the form `v - u', where `u != v'. 03240 // Note: the shortest-path closure is able to deduce the constraint 03241 // `v - u <= ub_v - lb_u'. We can be more precise if variable `u' 03242 // played an active role in the computation of the upper bound for `v', 03243 // i.e., if the corresponding coefficient `q == expr_u/denom' is 03244 // greater than zero. In particular: 03245 // if `q >= 1', then `v - u <= ub_v - ub_u'; 03246 // if `0 < q < 1', then `v - u <= ub_v - (q*ub_u + (1-q)*lb_u)'. 03247 PPL_DIRTY_TEMP(mpq_class, mpq_sc_denom); 03248 assign_r(mpq_sc_denom, sc_denom, ROUND_NOT_NEEDED); 03249 const DB_Row<N>& dbm_0 = dbm[0]; 03250 // Speculative allocation of temporaries to be used in the following loop. 03251 PPL_DIRTY_TEMP(mpq_class, minus_lb_u); 03252 PPL_DIRTY_TEMP(mpq_class, q); 03253 PPL_DIRTY_TEMP(mpq_class, ub_u); 03254 PPL_DIRTY_TEMP(N, up_approx); 03255 // No need to consider indices greater than `last_v'. 03256 for (dimension_type u = last_v; u > 0; --u) 03257 if (u != v) { 03258 const Coefficient& expr_u = sc_expr.coefficient(Variable(u-1)); 03259 if (expr_u > 0) { 03260 if (expr_u >= sc_denom) 03261 // Deducing `v - u <= ub_v - ub_u'. 03262 sub_assign_r(dbm[u][v], ub_v, dbm_0[u], ROUND_UP); 03263 else { 03264 DB_Row<N>& dbm_u = dbm[u]; 03265 const N& dbm_u0 = dbm_u[0]; 03266 if (!is_plus_infinity(dbm_u0)) { 03267 // Let `ub_u' and `lb_u' be the known upper and lower bound 03268 // for `u', respectively. Letting `q = expr_u/sc_denom' be the 03269 // rational coefficient of `u' in `sc_expr/sc_denom', 03270 // the upper bound for `v - u' is computed as 03271 // `ub_v - (q * ub_u + (1-q) * lb_u)', i.e., 03272 // `ub_v + (-lb_u) - q * (ub_u + (-lb_u))'. 03273 assign_r(minus_lb_u, dbm_u0, ROUND_NOT_NEEDED); 03274 assign_r(q, expr_u, ROUND_NOT_NEEDED); 03275 div_assign_r(q, q, mpq_sc_denom, ROUND_NOT_NEEDED); 03276 assign_r(ub_u, dbm_0[u], ROUND_NOT_NEEDED); 03277 // Compute `ub_u - lb_u'. 03278 add_assign_r(ub_u, ub_u, minus_lb_u, ROUND_NOT_NEEDED); 03279 // Compute `(-lb_u) - q * (ub_u - lb_u)'. 03280 sub_mul_assign_r(minus_lb_u, q, ub_u, ROUND_NOT_NEEDED); 03281 assign_r(up_approx, minus_lb_u, ROUND_UP); 03282 // Deducing `v - u <= ub_v - (q * ub_u + (1-q) * lb_u)'. 03283 add_assign_r(dbm_u[v], ub_v, up_approx, ROUND_UP); 03284 } 03285 } 03286 } 03287 } 03288 } 03289 03290 template <typename T> 03291 void 03292 BD_Shape<T> 03293 ::deduce_u_minus_v_bounds(const dimension_type v, 03294 const dimension_type last_v, 03295 const Linear_Expression& sc_expr, 03296 Coefficient_traits::const_reference sc_denom, 03297 const N& minus_lb_v) { 03298 PPL_ASSERT(sc_denom > 0); 03299 PPL_ASSERT(!is_plus_infinity(minus_lb_v)); 03300 // Deduce constraints of the form `u - v', where `u != v'. 03301 // Note: the shortest-path closure is able to deduce the constraint 03302 // `u - v <= ub_u - lb_v'. We can be more precise if variable `u' 03303 // played an active role in the computation of the lower bound for `v', 03304 // i.e., if the corresponding coefficient `q == expr_u/denom' is 03305 // greater than zero. In particular: 03306 // if `q >= 1', then `u - v <= lb_u - lb_v'; 03307 // if `0 < q < 1', then `u - v <= (q*lb_u + (1-q)*ub_u) - lb_v'. 03308 PPL_DIRTY_TEMP(mpq_class, mpq_sc_denom); 03309 assign_r(mpq_sc_denom, sc_denom, ROUND_NOT_NEEDED); 03310 DB_Row<N>& dbm_0 = dbm[0]; 03311 DB_Row<N>& dbm_v = dbm[v]; 03312 // Speculative allocation of temporaries to be used in the following loop. 03313 PPL_DIRTY_TEMP(mpq_class, ub_u); 03314 PPL_DIRTY_TEMP(mpq_class, q); 03315 PPL_DIRTY_TEMP(mpq_class, minus_lb_u); 03316 PPL_DIRTY_TEMP(N, up_approx); 03317 // No need to consider indices greater than `last_v'. 03318 for (dimension_type u = last_v; u > 0; --u) 03319 if (u != v) { 03320 const Coefficient& expr_u = sc_expr.coefficient(Variable(u-1)); 03321 if (expr_u > 0) { 03322 if (expr_u >= sc_denom) 03323 // Deducing `u - v <= lb_u - lb_v', 03324 // i.e., `u - v <= (-lb_v) - (-lb_u)'. 03325 sub_assign_r(dbm_v[u], minus_lb_v, dbm[u][0], ROUND_UP); 03326 else { 03327 const N& dbm_0u = dbm_0[u]; 03328 if (!is_plus_infinity(dbm_0u)) { 03329 // Let `ub_u' and `lb_u' be the known upper and lower bound 03330 // for `u', respectively. Letting `q = expr_u/sc_denom' be the 03331 // rational coefficient of `u' in `sc_expr/sc_denom', 03332 // the upper bound for `u - v' is computed as 03333 // `(q * lb_u + (1-q) * ub_u) - lb_v', i.e., 03334 // `ub_u - q * (ub_u + (-lb_u)) + minus_lb_v'. 03335 assign_r(ub_u, dbm_0u, ROUND_NOT_NEEDED); 03336 assign_r(q, expr_u, ROUND_NOT_NEEDED); 03337 div_assign_r(q, q, mpq_sc_denom, ROUND_NOT_NEEDED); 03338 assign_r(minus_lb_u, dbm[u][0], ROUND_NOT_NEEDED); 03339 // Compute `ub_u - lb_u'. 03340 add_assign_r(minus_lb_u, minus_lb_u, ub_u, ROUND_NOT_NEEDED); 03341 // Compute `ub_u - q * (ub_u - lb_u)'. 03342 sub_mul_assign_r(ub_u, q, minus_lb_u, ROUND_NOT_NEEDED); 03343 assign_r(up_approx, ub_u, ROUND_UP); 03344 // Deducing `u - v <= (q*lb_u + (1-q)*ub_u) - lb_v'. 03345 add_assign_r(dbm_v[u], up_approx, minus_lb_v, ROUND_UP); 03346 } 03347 } 03348 } 03349 } 03350 } 03351 03352 template <typename T> 03353 void 03354 BD_Shape<T>::forget_all_dbm_constraints(const dimension_type v) { 03355 PPL_ASSERT(0 < v && v <= dbm.num_rows()); 03356 DB_Row<N>& dbm_v = dbm[v]; 03357 for (dimension_type i = dbm.num_rows(); i-- > 0; ) { 03358 assign_r(dbm_v[i], PLUS_INFINITY, ROUND_NOT_NEEDED); 03359 assign_r(dbm[i][v], PLUS_INFINITY, ROUND_NOT_NEEDED); 03360 } 03361 } 03362 03363 template <typename T> 03364 void 03365 BD_Shape<T>::forget_binary_dbm_constraints(const dimension_type v) { 03366 PPL_ASSERT(0 < v && v <= dbm.num_rows()); 03367 DB_Row<N>& dbm_v = dbm[v]; 03368 for (dimension_type i = dbm.num_rows()-1; i > 0; --i) { 03369 assign_r(dbm_v[i], PLUS_INFINITY, ROUND_NOT_NEEDED); 03370 assign_r(dbm[i][v], PLUS_INFINITY, ROUND_NOT_NEEDED); 03371 } 03372 } 03373 03374 template <typename T> 03375 void 03376 BD_Shape<T>::unconstrain(const Variable var) { 03377 // Dimension-compatibility check. 03378 const dimension_type var_space_dim = var.space_dimension(); 03379 if (space_dimension() < var_space_dim) 03380 throw_dimension_incompatible("unconstrain(var)", var_space_dim); 03381 03382 // Shortest-path closure is necessary to detect emptiness 03383 // and all (possibly implicit) constraints. 03384 shortest_path_closure_assign(); 03385 03386 // If the shape is empty, this is a no-op. 03387 if (marked_empty()) 03388 return; 03389 03390 forget_all_dbm_constraints(var_space_dim); 03391 // Shortest-path closure is preserved, but not reduction. 03392 reset_shortest_path_reduced(); 03393 PPL_ASSERT(OK()); 03394 } 03395 03396 template <typename T> 03397 void 03398 BD_Shape<T>::unconstrain(const Variables_Set& vars) { 03399 // The cylindrification with respect to no dimensions is a no-op. 03400 // This case captures the only legal cylindrification in a 0-dim space. 03401 if (vars.empty()) 03402 return; 03403 03404 // Dimension-compatibility check. 03405 const dimension_type min_space_dim = vars.space_dimension(); 03406 if (space_dimension() < min_space_dim) 03407 throw_dimension_incompatible("unconstrain(vs)", min_space_dim); 03408 03409 // Shortest-path closure is necessary to detect emptiness 03410 // and all (possibly implicit) constraints. 03411 shortest_path_closure_assign(); 03412 03413 // If the shape is empty, this is a no-op. 03414 if (marked_empty()) 03415 return; 03416 03417 for (Variables_Set::const_iterator vsi = vars.begin(), 03418 vsi_end = vars.end(); vsi != vsi_end; ++vsi) 03419 forget_all_dbm_constraints(*vsi + 1); 03420 // Shortest-path closure is preserved, but not reduction. 03421 reset_shortest_path_reduced(); 03422 PPL_ASSERT(OK()); 03423 } 03424 03425 template <typename T> 03426 void 03427 BD_Shape<T>::refine(const Variable var, 03428 const Relation_Symbol relsym, 03429 const Linear_Expression& expr, 03430 Coefficient_traits::const_reference denominator) { 03431 PPL_ASSERT(denominator != 0); 03432 const dimension_type expr_space_dim = expr.space_dimension(); 03433 PPL_ASSERT(space_dimension() >= expr_space_dim); 03434 const dimension_type v = var.id() + 1; 03435 PPL_ASSERT(v <= space_dimension()); 03436 PPL_ASSERT(expr.coefficient(var) == 0); 03437 PPL_ASSERT(relsym != LESS_THAN && relsym != GREATER_THAN); 03438 03439 const Coefficient& b = expr.inhomogeneous_term(); 03440 // Number of non-zero coefficients in `expr': will be set to 03441 // 0, 1, or 2, the latter value meaning any value greater than 1. 03442 dimension_type t = 0; 03443 // Index of the last non-zero coefficient in `expr', if any. 03444 dimension_type w = 0; 03445 // Get information about the number of non-zero coefficients in `expr'. 03446 for (dimension_type i = expr_space_dim; i-- > 0; ) 03447 if (expr.coefficient(Variable(i)) != 0) { 03448 if (t++ == 1) 03449 break; 03450 else 03451 w = i+1; 03452 } 03453 03454 // Since we are only able to record bounded differences, we can 03455 // precisely deal with the case of a single variable only if its 03456 // coefficient (taking into account the denominator) is 1. 03457 // If this is not the case, we fall back to the general case 03458 // so as to over-approximate the constraint. 03459 if (t == 1 && expr.coefficient(Variable(w-1)) != denominator) 03460 t = 2; 03461 03462 // Now we know the form of `expr': 03463 // - If t == 0, then expr == b, with `b' a constant; 03464 // - If t == 1, then expr == a*w + b, where `w != v' and `a == denominator'; 03465 // - If t == 2, the `expr' is of the general form. 03466 const DB_Row<N>& dbm_0 = dbm[0]; 03467 PPL_DIRTY_TEMP_COEFFICIENT(minus_denom); 03468 neg_assign(minus_denom, denominator); 03469 03470 if (t == 0) { 03471 // Case 1: expr == b. 03472 switch (relsym) { 03473 case EQUAL: 03474 // Add the constraint `var == b/denominator'. 03475 add_dbm_constraint(0, v, b, denominator); 03476 add_dbm_constraint(v, 0, b, minus_denom); 03477 break; 03478 case LESS_OR_EQUAL: 03479 // Add the constraint `var <= b/denominator'. 03480 add_dbm_constraint(0, v, b, denominator); 03481 break; 03482 case GREATER_OR_EQUAL: 03483 // Add the constraint `var >= b/denominator', 03484 // i.e., `-var <= -b/denominator', 03485 add_dbm_constraint(v, 0, b, minus_denom); 03486 break; 03487 default: 03488 // We already dealt with the other cases. 03489 PPL_UNREACHABLE; 03490 break; 03491 } 03492 return; 03493 } 03494 03495 if (t == 1) { 03496 // Case 2: expr == a*w + b, w != v, a == denominator. 03497 PPL_ASSERT(expr.coefficient(Variable(w-1)) == denominator); 03498 PPL_DIRTY_TEMP(N, d); 03499 switch (relsym) { 03500 case EQUAL: 03501 // Add the new constraint `v - w <= b/denominator'. 03502 div_round_up(d, b, denominator); 03503 add_dbm_constraint(w, v, d); 03504 // Add the new constraint `v - w >= b/denominator', 03505 // i.e., `w - v <= -b/denominator'. 03506 div_round_up(d, b, minus_denom); 03507 add_dbm_constraint(v, w, d); 03508 break; 03509 case LESS_OR_EQUAL: 03510 // Add the new constraint `v - w <= b/denominator'. 03511 div_round_up(d, b, denominator); 03512 add_dbm_constraint(w, v, d); 03513 break; 03514 case GREATER_OR_EQUAL: 03515 // Add the new constraint `v - w >= b/denominator', 03516 // i.e., `w - v <= -b/denominator'. 03517 div_round_up(d, b, minus_denom); 03518 add_dbm_constraint(v, w, d); 03519 break; 03520 default: 03521 // We already dealt with the other cases. 03522 PPL_UNREACHABLE; 03523 break; 03524 } 03525 return; 03526 } 03527 03528 // Here t == 2, so that either 03529 // expr == a_1*x_1 + a_2*x_2 + ... + a_n*x_n + b, where n >= 2, or 03530 // expr == a*w + b, w != v and a != denominator. 03531 const bool is_sc = (denominator > 0); 03532 PPL_DIRTY_TEMP_COEFFICIENT(minus_b); 03533 neg_assign(minus_b, b); 03534 const Coefficient& sc_b = is_sc ? b : minus_b; 03535 const Coefficient& minus_sc_b = is_sc ? minus_b : b; 03536 const Coefficient& sc_denom = is_sc ? denominator : minus_denom; 03537 const Coefficient& minus_sc_denom = is_sc ? minus_denom : denominator; 03538 // NOTE: here, for optimization purposes, `minus_expr' is only assigned 03539 // when `denominator' is negative. Do not use it unless you are sure 03540 // it has been correctly assigned. 03541 Linear_Expression minus_expr; 03542 if (!is_sc) 03543 minus_expr = -expr; 03544 const Linear_Expression& sc_expr = is_sc ? expr : minus_expr; 03545 03546 PPL_DIRTY_TEMP(N, sum); 03547 // Indices of the variables that are unbounded in `this->dbm'. 03548 PPL_UNINITIALIZED(dimension_type, pinf_index); 03549 // Number of unbounded variables found. 03550 dimension_type pinf_count = 0; 03551 03552 // Speculative allocation of temporaries that are used in most 03553 // of the computational traces starting from this point (also loops). 03554 PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i); 03555 PPL_DIRTY_TEMP(N, coeff_i); 03556 03557 switch (relsym) { 03558 case EQUAL: 03559 { 03560 PPL_DIRTY_TEMP(N, neg_sum); 03561 // Indices of the variables that are unbounded in `this->dbm'. 03562 PPL_UNINITIALIZED(dimension_type, neg_pinf_index); 03563 // Number of unbounded variables found. 03564 dimension_type neg_pinf_count = 0; 03565 03566 // Compute an upper approximation for `expr' into `sum', 03567 // taking into account the sign of `denominator'. 03568 03569 // Approximate the inhomogeneous term. 03570 assign_r(sum, sc_b, ROUND_UP); 03571 assign_r(neg_sum, minus_sc_b, ROUND_UP); 03572 03573 // Approximate the homogeneous part of `sc_expr'. 03574 // Note: indices above `w' can be disregarded, as they all have 03575 // a zero coefficient in `expr'. 03576 for (dimension_type i = w; i > 0; --i) { 03577 const Coefficient& sc_i = sc_expr.coefficient(Variable(i-1)); 03578 const int sign_i = sgn(sc_i); 03579 if (sign_i == 0) 03580 continue; 03581 if (sign_i > 0) { 03582 assign_r(coeff_i, sc_i, ROUND_UP); 03583 // Approximating `sc_expr'. 03584 if (pinf_count <= 1) { 03585 const N& approx_i = dbm_0[i]; 03586 if (!is_plus_infinity(approx_i)) 03587 add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP); 03588 else { 03589 ++pinf_count; 03590 pinf_index = i; 03591 } 03592 } 03593 // Approximating `-sc_expr'. 03594 if (neg_pinf_count <= 1) { 03595 const N& approx_minus_i = dbm[i][0]; 03596 if (!is_plus_infinity(approx_minus_i)) 03597 add_mul_assign_r(neg_sum, coeff_i, approx_minus_i, ROUND_UP); 03598 else { 03599 ++neg_pinf_count; 03600 neg_pinf_index = i; 03601 } 03602 } 03603 } 03604 else if (sign_i < 0) { 03605 neg_assign(minus_sc_i, sc_i); 03606 // Note: using temporary named `coeff_i' to store -coeff_i. 03607 assign_r(coeff_i, minus_sc_i, ROUND_UP); 03608 // Approximating `sc_expr'. 03609 if (pinf_count <= 1) { 03610 const N& approx_minus_i = dbm[i][0]; 03611 if (!is_plus_infinity(approx_minus_i)) 03612 add_mul_assign_r(sum, coeff_i, approx_minus_i, ROUND_UP); 03613 else { 03614 ++pinf_count; 03615 pinf_index = i; 03616 } 03617 } 03618 // Approximating `-sc_expr'. 03619 if (neg_pinf_count <= 1) { 03620 const N& approx_i = dbm_0[i]; 03621 if (!is_plus_infinity(approx_i)) 03622 add_mul_assign_r(neg_sum, coeff_i, approx_i, ROUND_UP); 03623 else { 03624 ++neg_pinf_count; 03625 neg_pinf_index = i; 03626 } 03627 } 03628 } 03629 } 03630 // Return immediately if no approximation could be computed. 03631 if (pinf_count > 1 && neg_pinf_count > 1) { 03632 PPL_ASSERT(OK()); 03633 return; 03634 } 03635 03636 // In the following, shortest-path closure will be definitely lost. 03637 reset_shortest_path_closed(); 03638 03639 // Before computing quotients, the denominator should be approximated 03640 // towards zero. Since `sc_denom' is known to be positive, this amounts to 03641 // rounding downwards, which is achieved as usual by rounding upwards 03642 // `minus_sc_denom' and negating again the result. 03643 PPL_DIRTY_TEMP(N, down_sc_denom); 03644 assign_r(down_sc_denom, minus_sc_denom, ROUND_UP); 03645 neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP); 03646 03647 // Exploit the upper approximation, if possible. 03648 if (pinf_count <= 1) { 03649 // Compute quotient (if needed). 03650 if (down_sc_denom != 1) 03651 div_assign_r(sum, sum, down_sc_denom, ROUND_UP); 03652 // Add the upper bound constraint, if meaningful. 03653 if (pinf_count == 0) { 03654 // Add the constraint `v <= sum'. 03655 dbm[0][v] = sum; 03656 // Deduce constraints of the form `v - u', where `u != v'. 03657 deduce_v_minus_u_bounds(v, w, sc_expr, sc_denom, sum); 03658 } 03659 else 03660 // Here `pinf_count == 1'. 03661 if (pinf_index != v 03662 && sc_expr.coefficient(Variable(pinf_index-1)) == sc_denom) 03663 // Add the constraint `v - pinf_index <= sum'. 03664 dbm[pinf_index][v] = sum; 03665 } 03666 03667 // Exploit the lower approximation, if possible. 03668 if (neg_pinf_count <= 1) { 03669 // Compute quotient (if needed). 03670 if (down_sc_denom != 1) 03671 div_assign_r(neg_sum, neg_sum, down_sc_denom, ROUND_UP); 03672 // Add the lower bound constraint, if meaningful. 03673 if (neg_pinf_count == 0) { 03674 // Add the constraint `v >= -neg_sum', i.e., `-v <= neg_sum'. 03675 DB_Row<N>& dbm_v = dbm[v]; 03676 dbm_v[0] = neg_sum; 03677 // Deduce constraints of the form `u - v', where `u != v'. 03678 deduce_u_minus_v_bounds(v, w, sc_expr, sc_denom, neg_sum); 03679 } 03680 else 03681 // Here `neg_pinf_count == 1'. 03682 if (neg_pinf_index != v 03683 && sc_expr.coefficient(Variable(neg_pinf_index-1)) == sc_denom) 03684 // Add the constraint `v - neg_pinf_index >= -neg_sum', 03685 // i.e., `neg_pinf_index - v <= neg_sum'. 03686 dbm[v][neg_pinf_index] = neg_sum; 03687 } 03688 } 03689 break; 03690 03691 case LESS_OR_EQUAL: 03692 // Compute an upper approximation for `expr' into `sum', 03693 // taking into account the sign of `denominator'. 03694 03695 // Approximate the inhomogeneous term. 03696 assign_r(sum, sc_b, ROUND_UP); 03697 03698 // Approximate the homogeneous part of `sc_expr'. 03699 // Note: indices above `w' can be disregarded, as they all have 03700 // a zero coefficient in `expr'. 03701 for (dimension_type i = w; i > 0; --i) { 03702 const Coefficient& sc_i = sc_expr.coefficient(Variable(i-1)); 03703 const int sign_i = sgn(sc_i); 03704 if (sign_i == 0) 03705 continue; 03706 // Choose carefully: we are approximating `sc_expr'. 03707 const N& approx_i = (sign_i > 0) ? dbm_0[i] : dbm[i][0]; 03708 if (is_plus_infinity(approx_i)) { 03709 if (++pinf_count > 1) 03710 break; 03711 pinf_index = i; 03712 continue; 03713 } 03714 if (sign_i > 0) 03715 assign_r(coeff_i, sc_i, ROUND_UP); 03716 else { 03717 neg_assign(minus_sc_i, sc_i); 03718 assign_r(coeff_i, minus_sc_i, ROUND_UP); 03719 } 03720 add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP); 03721 } 03722 03723 // Divide by the (sign corrected) denominator (if needed). 03724 if (sc_denom != 1) { 03725 // Before computing the quotient, the denominator should be 03726 // approximated towards zero. Since `sc_denom' is known to be 03727 // positive, this amounts to rounding downwards, which is achieved 03728 // by rounding upwards `minus_sc - denom' and negating again the result. 03729 PPL_DIRTY_TEMP(N, down_sc_denom); 03730 assign_r(down_sc_denom, minus_sc_denom, ROUND_UP); 03731 neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP); 03732 div_assign_r(sum, sum, down_sc_denom, ROUND_UP); 03733 } 03734 03735 if (pinf_count == 0) { 03736 // Add the constraint `v <= sum'. 03737 add_dbm_constraint(0, v, sum); 03738 // Deduce constraints of the form `v - u', where `u != v'. 03739 deduce_v_minus_u_bounds(v, w, sc_expr, sc_denom, sum); 03740 } 03741 else if (pinf_count == 1) 03742 if (expr.coefficient(Variable(pinf_index-1)) == denominator) 03743 // Add the constraint `v - pinf_index <= sum'. 03744 add_dbm_constraint(pinf_index, v, sum); 03745 break; 03746 03747 case GREATER_OR_EQUAL: 03748 // Compute an upper approximation for `-sc_expr' into `sum'. 03749 // Note: approximating `-sc_expr' from above and then negating the 03750 // result is the same as approximating `sc_expr' from below. 03751 03752 // Approximate the inhomogeneous term. 03753 assign_r(sum, minus_sc_b, ROUND_UP); 03754 03755 // Approximate the homogeneous part of `-sc_expr'. 03756 for (dimension_type i = w; i > 0; --i) { 03757 const Coefficient& sc_i = sc_expr.coefficient(Variable(i-1)); 03758 const int sign_i = sgn(sc_i); 03759 if (sign_i == 0) 03760 continue; 03761 // Choose carefully: we are approximating `-sc_expr'. 03762 const N& approx_i = (sign_i > 0) ? dbm[i][0] : dbm_0[i]; 03763 if (is_plus_infinity(approx_i)) { 03764 if (++pinf_count > 1) 03765 break; 03766 pinf_index = i; 03767 continue; 03768 } 03769 if (sign_i > 0) 03770 assign_r(coeff_i, sc_i, ROUND_UP); 03771 else { 03772 neg_assign(minus_sc_i, sc_i); 03773 assign_r(coeff_i, minus_sc_i, ROUND_UP); 03774 } 03775 add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP); 03776 } 03777 03778 // Divide by the (sign corrected) denominator (if needed). 03779 if (sc_denom != 1) { 03780 // Before computing the quotient, the denominator should be 03781 // approximated towards zero. Since `sc_denom' is known to be positive, 03782 // this amounts to rounding downwards, which is achieved by rounding 03783 // upwards `minus_sc_denom' and negating again the result. 03784 PPL_DIRTY_TEMP(N, down_sc_denom); 03785 assign_r(down_sc_denom, minus_sc_denom, ROUND_UP); 03786 neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP); 03787 div_assign_r(sum, sum, down_sc_denom, ROUND_UP); 03788 } 03789 03790 if (pinf_count == 0) { 03791 // Add the constraint `v >= -sum', i.e., `-v <= sum'. 03792 add_dbm_constraint(v, 0, sum); 03793 // Deduce constraints of the form `u - v', where `u != v'. 03794 deduce_u_minus_v_bounds(v, w, sc_expr, sc_denom, sum); 03795 } 03796 else if (pinf_count == 1) 03797 if (pinf_index != v 03798 && expr.coefficient(Variable(pinf_index-1)) == denominator) 03799 // Add the constraint `v - pinf_index >= -sum', 03800 // i.e., `pinf_index - v <= sum'. 03801 add_dbm_constraint(v, pinf_index, sum); 03802 break; 03803 03804 default: 03805 // We already dealt with the other cases. 03806 PPL_UNREACHABLE; 03807 break; 03808 } 03809 03810 PPL_ASSERT(OK()); 03811 } 03812 03813 template <typename T> 03814 void 03815 BD_Shape<T>::affine_image(const Variable var, 03816 const Linear_Expression& expr, 03817 Coefficient_traits::const_reference denominator) { 03818 // The denominator cannot be zero. 03819 if (denominator == 0) 03820 throw_invalid_argument("affine_image(v, e, d)", "d == 0"); 03821 03822 // Dimension-compatibility checks. 03823 // The dimension of `expr' should not be greater than the dimension 03824 // of `*this'. 03825 const dimension_type space_dim = space_dimension(); 03826 const dimension_type expr_space_dim = expr.space_dimension(); 03827 if (space_dim < expr_space_dim) 03828 throw_dimension_incompatible("affine_image(v, e, d)", "e", expr); 03829 03830 // `var' should be one of the dimensions of the shape. 03831 const dimension_type v = var.id() + 1; 03832 if (v > space_dim) 03833 throw_dimension_incompatible("affine_image(v, e, d)", var.id()); 03834 03835 // The image of an empty BDS is empty too. 03836 shortest_path_closure_assign(); 03837 if (marked_empty()) 03838 return; 03839 03840 const Coefficient& b = expr.inhomogeneous_term(); 03841 // Number of non-zero coefficients in `expr': will be set to 03842 // 0, 1, or 2, the latter value meaning any value greater than 1. 03843 dimension_type t = 0; 03844 // Index of the last non-zero coefficient in `expr', if any. 03845 dimension_type w = 0; 03846 // Get information about the number of non-zero coefficients in `expr'. 03847 for (dimension_type i = expr_space_dim; i-- > 0; ) 03848 if (expr.coefficient(Variable(i)) != 0) { 03849 if (t++ == 1) 03850 break; 03851 else 03852 w = i+1; 03853 } 03854 03855 // Now we know the form of `expr': 03856 // - If t == 0, then expr == b, with `b' a constant; 03857 // - If t == 1, then expr == a*w + b, where `w' can be `v' or another 03858 // variable; in this second case we have to check whether `a' is 03859 // equal to `denominator' or `-denominator', since otherwise we have 03860 // to fall back on the general form; 03861 // - If t == 2, the `expr' is of the general form. 03862 PPL_DIRTY_TEMP_COEFFICIENT(minus_denom); 03863 neg_assign(minus_denom, denominator); 03864 03865 if (t == 0) { 03866 // Case 1: expr == b. 03867 // Remove all constraints on `var'. 03868 forget_all_dbm_constraints(v); 03869 // Shortest-path closure is preserved, but not reduction. 03870 if (marked_shortest_path_reduced()) 03871 reset_shortest_path_reduced(); 03872 // Add the constraint `var == b/denominator'. 03873 add_dbm_constraint(0, v, b, denominator); 03874 add_dbm_constraint(v, 0, b, minus_denom); 03875 PPL_ASSERT(OK()); 03876 return; 03877 } 03878 03879 if (t == 1) { 03880 // Value of the one and only non-zero coefficient in `expr'. 03881 const Coefficient& a = expr.coefficient(Variable(w-1)); 03882 if (a == denominator || a == minus_denom) { 03883 // Case 2: expr == a*w + b, with a == +/- denominator. 03884 if (w == v) { 03885 // `expr' is of the form: a*v + b. 03886 if (a == denominator) { 03887 if (b == 0) 03888 // The transformation is the identity function. 03889 return; 03890 else { 03891 // Translate all the constraints on `var', 03892 // adding or subtracting the value `b/denominator'. 03893 PPL_DIRTY_TEMP(N, d); 03894 div_round_up(d, b, denominator); 03895 PPL_DIRTY_TEMP(N, c); 03896 div_round_up(c, b, minus_denom); 03897 DB_Row<N>& dbm_v = dbm[v]; 03898 for (dimension_type i = space_dim + 1; i-- > 0; ) { 03899 N& dbm_vi = dbm_v[i]; 03900 add_assign_r(dbm_vi, dbm_vi, c, ROUND_UP); 03901 N& dbm_iv = dbm[i][v]; 03902 add_assign_r(dbm_iv, dbm_iv, d, ROUND_UP); 03903 } 03904 // Both shortest-path closure and reduction are preserved. 03905 } 03906 } 03907 else { 03908 // Here `a == -denominator'. 03909 // Remove the binary constraints on `var'. 03910 forget_binary_dbm_constraints(v); 03911 // Swap the unary constraints on `var'. 03912 using std::swap; 03913 swap(dbm[v][0], dbm[0][v]); 03914 // Shortest-path closure is not preserved. 03915 reset_shortest_path_closed(); 03916 if (b != 0) { 03917 // Translate the unary constraints on `var', 03918 // adding or subtracting the value `b/denominator'. 03919 PPL_DIRTY_TEMP(N, c); 03920 div_round_up(c, b, minus_denom); 03921 N& dbm_v0 = dbm[v][0]; 03922 add_assign_r(dbm_v0, dbm_v0, c, ROUND_UP); 03923 PPL_DIRTY_TEMP(N, d); 03924 div_round_up(d, b, denominator); 03925 N& dbm_0v = dbm[0][v]; 03926 add_assign_r(dbm_0v, dbm_0v, d, ROUND_UP); 03927 } 03928 } 03929 } 03930 else { 03931 // Here `w != v', so that `expr' is of the form 03932 // +/-denominator * w + b. 03933 // Remove all constraints on `var'. 03934 forget_all_dbm_constraints(v); 03935 // Shortest-path closure is preserved, but not reduction. 03936 if (marked_shortest_path_reduced()) 03937 reset_shortest_path_reduced(); 03938 if (a == denominator) { 03939 // Add the new constraint `v - w == b/denominator'. 03940 add_dbm_constraint(w, v, b, denominator); 03941 add_dbm_constraint(v, w, b, minus_denom); 03942 } 03943 else { 03944 // Here a == -denominator, so that we should be adding 03945 // the constraint `v + w == b/denominator'. 03946 // Approximate it by computing lower and upper bounds for `w'. 03947 const N& dbm_w0 = dbm[w][0]; 03948 if (!is_plus_infinity(dbm_w0)) { 03949 // Add the constraint `v <= b/denominator - lower_w'. 03950 PPL_DIRTY_TEMP(N, d); 03951 div_round_up(d, b, denominator); 03952 add_assign_r(dbm[0][v], d, dbm_w0, ROUND_UP); 03953 reset_shortest_path_closed(); 03954 } 03955 const N& dbm_0w = dbm[0][w]; 03956 if (!is_plus_infinity(dbm_0w)) { 03957 // Add the constraint `v >= b/denominator - upper_w'. 03958 PPL_DIRTY_TEMP(N, c); 03959 div_round_up(c, b, minus_denom); 03960 add_assign_r(dbm[v][0], dbm_0w, c, ROUND_UP); 03961 reset_shortest_path_closed(); 03962 } 03963 } 03964 } 03965 PPL_ASSERT(OK()); 03966 return; 03967 } 03968 } 03969 03970 // General case. 03971 // Either t == 2, so that 03972 // expr == a_1*x_1 + a_2*x_2 + ... + a_n*x_n + b, where n >= 2, 03973 // or t == 1, expr == a*w + b, but a <> +/- denominator. 03974 // We will remove all the constraints on `var' and add back 03975 // constraints providing upper and lower bounds for `var'. 03976 03977 // Compute upper approximations for `expr' and `-expr' 03978 // into `pos_sum' and `neg_sum', respectively, taking into account 03979 // the sign of `denominator'. 03980 // Note: approximating `-expr' from above and then negating the 03981 // result is the same as approximating `expr' from below. 03982 const bool is_sc = (denominator > 0); 03983 PPL_DIRTY_TEMP_COEFFICIENT(minus_b); 03984 neg_assign(minus_b, b); 03985 const Coefficient& sc_b = is_sc ? b : minus_b; 03986 const Coefficient& minus_sc_b = is_sc ? minus_b : b; 03987 const Coefficient& sc_denom = is_sc ? denominator : minus_denom; 03988 const Coefficient& minus_sc_denom = is_sc ? minus_denom : denominator; 03989 // NOTE: here, for optimization purposes, `minus_expr' is only assigned 03990 // when `denominator' is negative. Do not use it unless you are sure 03991 // it has been correctly assigned. 03992 Linear_Expression minus_expr; 03993 if (!is_sc) 03994 minus_expr = -expr; 03995 const Linear_Expression& sc_expr = is_sc ? expr : minus_expr; 03996 03997 PPL_DIRTY_TEMP(N, pos_sum); 03998 PPL_DIRTY_TEMP(N, neg_sum); 03999 // Indices of the variables that are unbounded in `this->dbm'. 04000 PPL_UNINITIALIZED(dimension_type, pos_pinf_index); 04001 PPL_UNINITIALIZED(dimension_type, neg_pinf_index); 04002 // Number of unbounded variables found. 04003 dimension_type pos_pinf_count = 0; 04004 dimension_type neg_pinf_count = 0; 04005 04006 // Approximate the inhomogeneous term. 04007 assign_r(pos_sum, sc_b, ROUND_UP); 04008 assign_r(neg_sum, minus_sc_b, ROUND_UP); 04009 04010 // Approximate the homogeneous part of `sc_expr'. 04011 const DB_Row<N>& dbm_0 = dbm[0]; 04012 // Speculative allocation of temporaries to be used in the following loop. 04013 PPL_DIRTY_TEMP(N, coeff_i); 04014 PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i); 04015 // Note: indices above `w' can be disregarded, as they all have 04016 // a zero coefficient in `sc_expr'. 04017 for (dimension_type i = w; i > 0; --i) { 04018 const Coefficient& sc_i = sc_expr.coefficient(Variable(i-1)); 04019 const int sign_i = sgn(sc_i); 04020 if (sign_i > 0) { 04021 assign_r(coeff_i, sc_i, ROUND_UP); 04022 // Approximating `sc_expr'. 04023 if (pos_pinf_count <= 1) { 04024 const N& up_approx_i = dbm_0[i]; 04025 if (!is_plus_infinity(up_approx_i)) 04026 add_mul_assign_r(pos_sum, coeff_i, up_approx_i, ROUND_UP); 04027 else { 04028 ++pos_pinf_count; 04029 pos_pinf_index = i; 04030 } 04031 } 04032 // Approximating `-sc_expr'. 04033 if (neg_pinf_count <= 1) { 04034 const N& up_approx_minus_i = dbm[i][0]; 04035 if (!is_plus_infinity(up_approx_minus_i)) 04036 add_mul_assign_r(neg_sum, coeff_i, up_approx_minus_i, ROUND_UP); 04037 else { 04038 ++neg_pinf_count; 04039 neg_pinf_index = i; 04040 } 04041 } 04042 } 04043 else if (sign_i < 0) { 04044 neg_assign(minus_sc_i, sc_i); 04045 // Note: using temporary named `coeff_i' to store -coeff_i. 04046 assign_r(coeff_i, minus_sc_i, ROUND_UP); 04047 // Approximating `sc_expr'. 04048 if (pos_pinf_count <= 1) { 04049 const N& up_approx_minus_i = dbm[i][0]; 04050 if (!is_plus_infinity(up_approx_minus_i)) 04051 add_mul_assign_r(pos_sum, coeff_i, up_approx_minus_i, ROUND_UP); 04052 else { 04053 ++pos_pinf_count; 04054 pos_pinf_index = i; 04055 } 04056 } 04057 // Approximating `-sc_expr'. 04058 if (neg_pinf_count <= 1) { 04059 const N& up_approx_i = dbm_0[i]; 04060 if (!is_plus_infinity(up_approx_i)) 04061 add_mul_assign_r(neg_sum, coeff_i, up_approx_i, ROUND_UP); 04062 else { 04063 ++neg_pinf_count; 04064 neg_pinf_index = i; 04065 } 04066 } 04067 } 04068 } 04069 04070 // Remove all constraints on 'v'. 04071 forget_all_dbm_constraints(v); 04072 // Shortest-path closure is maintained, but not reduction. 04073 if (marked_shortest_path_reduced()) 04074 reset_shortest_path_reduced(); 04075 // Return immediately if no approximation could be computed. 04076 if (pos_pinf_count > 1 && neg_pinf_count > 1) { 04077 PPL_ASSERT(OK()); 04078 return; 04079 } 04080 04081 // In the following, shortest-path closure will be definitely lost. 04082 reset_shortest_path_closed(); 04083 04084 // Exploit the upper approximation, if possible. 04085 if (pos_pinf_count <= 1) { 04086 // Compute quotient (if needed). 04087 if (sc_denom != 1) { 04088 // Before computing quotients, the denominator should be approximated 04089 // towards zero. Since `sc_denom' is known to be positive, this amounts to 04090 // rounding downwards, which is achieved as usual by rounding upwards 04091 // `minus_sc_denom' and negating again the result. 04092 PPL_DIRTY_TEMP(N, down_sc_denom); 04093 assign_r(down_sc_denom, minus_sc_denom, ROUND_UP); 04094 neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP); 04095 div_assign_r(pos_sum, pos_sum, down_sc_denom, ROUND_UP); 04096 } 04097 // Add the upper bound constraint, if meaningful. 04098 if (pos_pinf_count == 0) { 04099 // Add the constraint `v <= pos_sum'. 04100 dbm[0][v] = pos_sum; 04101 // Deduce constraints of the form `v - u', where `u != v'. 04102 deduce_v_minus_u_bounds(v, w, sc_expr, sc_denom, pos_sum); 04103 } 04104 else 04105 // Here `pos_pinf_count == 1'. 04106 if (pos_pinf_index != v 04107 && sc_expr.coefficient(Variable(pos_pinf_index-1)) == sc_denom) 04108 // Add the constraint `v - pos_pinf_index <= pos_sum'. 04109 dbm[pos_pinf_index][v] = pos_sum; 04110 } 04111 04112 // Exploit the lower approximation, if possible. 04113 if (neg_pinf_count <= 1) { 04114 // Compute quotient (if needed). 04115 if (sc_denom != 1) { 04116 // Before computing quotients, the denominator should be approximated 04117 // towards zero. Since `sc_denom' is known to be positive, this amounts to 04118 // rounding downwards, which is achieved as usual by rounding upwards 04119 // `minus_sc_denom' and negating again the result. 04120 PPL_DIRTY_TEMP(N, down_sc_denom); 04121 assign_r(down_sc_denom, minus_sc_denom, ROUND_UP); 04122 neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP); 04123 div_assign_r(neg_sum, neg_sum, down_sc_denom, ROUND_UP); 04124 } 04125 // Add the lower bound constraint, if meaningful. 04126 if (neg_pinf_count == 0) { 04127 // Add the constraint `v >= -neg_sum', i.e., `-v <= neg_sum'. 04128 DB_Row<N>& dbm_v = dbm[v]; 04129 dbm_v[0] = neg_sum; 04130 // Deduce constraints of the form `u - v', where `u != v'. 04131 deduce_u_minus_v_bounds(v, w, sc_expr, sc_denom, neg_sum); 04132 } 04133 else 04134 // Here `neg_pinf_count == 1'. 04135 if (neg_pinf_index != v 04136 && sc_expr.coefficient(Variable(neg_pinf_index-1)) == sc_denom) 04137 // Add the constraint `v - neg_pinf_index >= -neg_sum', 04138 // i.e., `neg_pinf_index - v <= neg_sum'. 04139 dbm[v][neg_pinf_index] = neg_sum; 04140 } 04141 04142 PPL_ASSERT(OK()); 04143 } 04144 04145 template <typename T> 04146 template <typename Interval_Info> 04147 void 04148 BD_Shape<T>::affine_form_image(const Variable var, 04149 const Linear_Form< Interval<T, Interval_Info> >& lf) { 04150 04151 // Check that T is a floating point type. 04152 PPL_COMPILE_TIME_CHECK(!std::numeric_limits<T>::is_exact, 04153 "BD_Shape<T>::affine_form_image(Variable, Linear_Form):" 04154 " T not a floating point type."); 04155 04156 // Dimension-compatibility checks. 04157 // The dimension of `lf' should not be greater than the dimension 04158 // of `*this'. 04159 const dimension_type space_dim = space_dimension(); 04160 const dimension_type lf_space_dim = lf.space_dimension(); 04161 if (space_dim < lf_space_dim) 04162 throw_dimension_incompatible("affine_form_image(var_id, l)", "l", lf); 04163 04164 // `var' should be one of the dimensions of the shape. 04165 const dimension_type var_id = var.id() + 1; 04166 if (space_dim < var_id) 04167 throw_dimension_incompatible("affine_form_image(var_id, l)", var.id()); 04168 04169 // The image of an empty BDS is empty too. 04170 shortest_path_closure_assign(); 04171 if (marked_empty()) 04172 return; 04173 04174 // Number of non-zero coefficients in `lf': will be set to 04175 // 0, 1, or 2, the latter value meaning any value greater than 1. 04176 dimension_type t = 0; 04177 // Index of the last non-zero coefficient in `lf', if any. 04178 dimension_type w_id = 0; 04179 // Get information about the number of non-zero coefficients in `lf'. 04180 for (dimension_type i = lf_space_dim; i-- > 0; ) 04181 if (lf.coefficient(Variable(i)) != 0) { 04182 if (t++ == 1) 04183 break; 04184 else 04185 w_id = i + 1; 04186 } 04187 04188 typedef Interval<T, Interval_Info> FP_Interval_Type; 04189 04190 const FP_Interval_Type& b = lf.inhomogeneous_term(); 04191 04192 // Now we know the form of `lf': 04193 // - If t == 0, then lf == b, with `b' a constant; 04194 // - If t == 1, then lf == a*w + b, where `w' can be `v' or another 04195 // variable; 04196 // - If t == 2, the linear form 'lf' is of the general form. 04197 04198 if (t == 0) { 04199 inhomogeneous_affine_form_image(var_id, b); 04200 PPL_ASSERT(OK()); 04201 return; 04202 } 04203 else if (t == 1) { 04204 const FP_Interval_Type& w_coeff = lf.coefficient(Variable(w_id - 1)); 04205 if (w_coeff == 1 || w_coeff == -1) { 04206 one_variable_affine_form_image(var_id, b, w_coeff, w_id, space_dim); 04207 PPL_ASSERT(OK()); 04208 return; 04209 } 04210 } 04211 two_variables_affine_form_image(var_id, lf, space_dim); 04212 PPL_ASSERT(OK()); 04213 } 04214 04215 // Case 1: var = b, where b = [-b_mlb, b_ub] 04216 template <typename T> 04217 template <typename Interval_Info> 04218 void 04219 BD_Shape<T> 04220 ::inhomogeneous_affine_form_image(const dimension_type& var_id, 04221 const Interval<T, Interval_Info>& b) { 04222 PPL_DIRTY_TEMP(N, b_ub); 04223 assign_r(b_ub, b.upper(), ROUND_NOT_NEEDED); 04224 PPL_DIRTY_TEMP(N, b_mlb); 04225 neg_assign_r(b_mlb, b.lower(), ROUND_NOT_NEEDED); 04226 04227 // Remove all constraints on `var'. 04228 forget_all_dbm_constraints(var_id); 04229 // Shortest-path closure is preserved, but not reduction. 04230 if (marked_shortest_path_reduced()) 04231 reset_shortest_path_reduced(); 04232 // Add the constraint `var >= lb && var <= ub'. 04233 add_dbm_constraint(0, var_id, b_ub); 04234 add_dbm_constraint(var_id, 0, b_mlb); 04235 return; 04236 } 04237 04238 // case 2: var = (+/-1) * w + [-b_mlb, b_ub], where `w' can be `var' 04239 // or another variable. 04240 template <typename T> 04241 template <typename Interval_Info> 04242 void BD_Shape<T> 04243 ::one_variable_affine_form_image(const dimension_type& var_id, 04244 const Interval<T, Interval_Info>& b, 04245 const Interval<T, Interval_Info>& w_coeff, 04246 const dimension_type& w_id, 04247 const dimension_type& space_dim) { 04248 04249 PPL_DIRTY_TEMP(N, b_ub); 04250 assign_r(b_ub, b.upper(), ROUND_NOT_NEEDED); 04251 PPL_DIRTY_TEMP(N, b_mlb); 04252 neg_assign_r(b_mlb, b.lower(), ROUND_NOT_NEEDED); 04253 04254 // True if `w_coeff' is in [1, 1]. 04255 bool is_w_coeff_one = (w_coeff == 1); 04256 04257 if (w_id == var_id) { 04258 // True if `b' is in [b_mlb, b_ub] and that is [0, 0]. 04259 bool is_b_zero = (b_mlb == 0 && b_ub == 0); 04260 // Here `lf' is of the form: [+/-1, +/-1] * v + b. 04261 if (is_w_coeff_one) { 04262 if (is_b_zero) 04263 // The transformation is the identity function. 04264 return; 04265 else { 04266 // Translate all the constraints on `var' by adding the value 04267 // `b_ub' or subtracting the value `b_mlb'. 04268 DB_Row<N>& dbm_v = dbm[var_id]; 04269 for (dimension_type i = space_dim + 1; i-- > 0; ) { 04270 N& dbm_vi = dbm_v[i]; 04271 add_assign_r(dbm_vi, dbm_vi, b_mlb, ROUND_UP); 04272 N& dbm_iv = dbm[i][var_id]; 04273 add_assign_r(dbm_iv, dbm_iv, b_ub, ROUND_UP); 04274 } 04275 // Both shortest-path closure and reduction are preserved. 04276 } 04277 } 04278 else { 04279 // Here `w_coeff = [-1, -1]. 04280 // Remove the binary constraints on `var'. 04281 forget_binary_dbm_constraints(var_id); 04282 using std::swap; 04283 swap(dbm[var_id][0], dbm[0][var_id]); 04284 // Shortest-path closure is not preserved. 04285 reset_shortest_path_closed(); 04286 if (!is_b_zero) { 04287 // Translate the unary constraints on `var' by adding the value 04288 // `b_ub' or subtracting the value `b_mlb'. 04289 N& dbm_v0 = dbm[var_id][0]; 04290 add_assign_r(dbm_v0, dbm_v0, b_mlb, ROUND_UP); 04291 N& dbm_0v = dbm[0][var_id]; 04292 add_assign_r(dbm_0v, dbm_0v, b_ub, ROUND_UP); 04293 } 04294 } 04295 } 04296 else { 04297 // Here `w != var', so that `lf' is of the form 04298 // [+/-1, +/-1] * w + b. 04299 // Remove all constraints on `var'. 04300 forget_all_dbm_constraints(var_id); 04301 // Shortest-path closure is preserved, but not reduction. 04302 if (marked_shortest_path_reduced()) 04303 reset_shortest_path_reduced(); 04304 if (is_w_coeff_one) { 04305 // Add the new constraints `var - w >= b_mlb' 04306 // `and var - w <= b_ub'. 04307 add_dbm_constraint(w_id, var_id, b_ub); 04308 add_dbm_constraint(var_id, w_id, b_mlb); 04309 } 04310 else { 04311 // We have to add the constraint `v + w == b', over-approximating it 04312 // by computing lower and upper bounds for `w'. 04313 const N& mlb_w = dbm[w_id][0]; 04314 if (!is_plus_infinity(mlb_w)) { 04315 // Add the constraint `v <= ub - lb_w'. 04316 add_assign_r(dbm[0][var_id], b_ub, mlb_w, ROUND_UP); 04317 reset_shortest_path_closed(); 04318 } 04319 const N& ub_w = dbm[0][w_id]; 04320 if (!is_plus_infinity(ub_w)) { 04321 // Add the constraint `v >= lb - ub_w'. 04322 add_assign_r(dbm[var_id][0], ub_w, b_mlb, ROUND_UP); 04323 reset_shortest_path_closed(); 04324 } 04325 } 04326 } 04327 return; 04328 } 04329 04330 // General case. 04331 // Either t == 2, so that 04332 // lf == i_1*x_1 + i_2*x_2 + ... + i_n*x_n + b, where n >= 2, 04333 // or t == 1, lf == i*w + b, but i <> [+/-1, +/-1]. 04334 template <typename T> 04335 template <typename Interval_Info> 04336 void BD_Shape<T> 04337 ::two_variables_affine_form_image(const dimension_type& var_id, 04338 const Linear_Form< Interval<T, Interval_Info> >& lf, 04339 const dimension_type& space_dim) { 04340 // Shortest-path closure is maintained, but not reduction. 04341 if (marked_shortest_path_reduced()) 04342 reset_shortest_path_reduced(); 04343 04344 reset_shortest_path_closed(); 04345 04346 Linear_Form< Interval<T, Interval_Info> > minus_lf(lf); 04347 minus_lf.negate(); 04348 04349 // Declare temporaries outside the loop. 04350 PPL_DIRTY_TEMP(N, upper_bound); 04351 04352 // Update binary constraints on var FIRST. 04353 for (dimension_type curr_var = 1; curr_var < var_id; ++curr_var) { 04354 Variable current(curr_var - 1); 04355 linear_form_upper_bound(lf - current, upper_bound); 04356 assign_r(dbm[curr_var][var_id], upper_bound, ROUND_NOT_NEEDED); 04357 linear_form_upper_bound(minus_lf + current, upper_bound); 04358 assign_r(dbm[var_id][curr_var], upper_bound, ROUND_NOT_NEEDED); 04359 } 04360 for (dimension_type curr_var = var_id + 1; curr_var <= space_dim; 04361 ++curr_var) { 04362 Variable current(curr_var - 1); 04363 linear_form_upper_bound(lf - current, upper_bound); 04364 assign_r(dbm[curr_var][var_id], upper_bound, ROUND_NOT_NEEDED); 04365 linear_form_upper_bound(minus_lf + current, upper_bound); 04366 assign_r(dbm[var_id][curr_var], upper_bound, ROUND_NOT_NEEDED); 04367 } 04368 // Finally, update unary constraints on var. 04369 PPL_DIRTY_TEMP(N, lf_ub); 04370 linear_form_upper_bound(lf, lf_ub); 04371 PPL_DIRTY_TEMP(N, minus_lf_ub); 04372 linear_form_upper_bound(minus_lf, minus_lf_ub); 04373 assign_r(dbm[0][var_id], lf_ub, ROUND_NOT_NEEDED); 04374 assign_r(dbm[var_id][0], minus_lf_ub, ROUND_NOT_NEEDED); 04375 } 04376 04377 template <typename T> 04378 template <typename Interval_Info> 04379 void BD_Shape<T>::refine_with_linear_form_inequality( 04380 const Linear_Form< Interval<T, Interval_Info> >& left, 04381 const Linear_Form< Interval<T, Interval_Info> >& right) { 04382 // Check that T is a floating point type. 04383 PPL_COMPILE_TIME_CHECK(!std::numeric_limits<T>::is_exact, 04384 "Octagonal_Shape<T>::refine_with_linear_form_inequality:" 04385 " T not a floating point type."); 04386 04387 //We assume that the analyzer will not try to apply an unreachable filter. 04388 PPL_ASSERT(!marked_empty()); 04389 04390 // Dimension-compatibility checks. 04391 // The dimensions of `left' and `right' should not be greater than the 04392 // dimension of `*this'. 04393 const dimension_type left_space_dim = left.space_dimension(); 04394 const dimension_type space_dim = space_dimension(); 04395 if (space_dim < left_space_dim) 04396 throw_dimension_incompatible( 04397 "refine_with_linear_form_inequality(left, right)", "left", left); 04398 04399 const dimension_type right_space_dim = right.space_dimension(); 04400 if (space_dim < right_space_dim) 04401 throw_dimension_incompatible( 04402 "refine_with_linear_form_inequality(left, right)", "right", right); 04403 04404 // Number of non-zero coefficients in `left': will be set to 04405 // 0, 1, or 2, the latter value meaning any value greater than 1. 04406 dimension_type left_t = 0; 04407 // Variable-index of the last non-zero coefficient in `left', if any. 04408 dimension_type left_w_id = 0; 04409 // Number of non-zero coefficients in `right': will be set to 04410 // 0, 1, or 2, the latter value meaning any value greater than 1. 04411 dimension_type right_t = 0; 04412 // Variable-index of the last non-zero coefficient in `right', if any. 04413 dimension_type right_w_id = 0; 04414 04415 typedef Interval<T, Interval_Info> FP_Interval_Type; 04416 04417 // Get information about the number of non-zero coefficients in `left'. 04418 for (dimension_type i = left_space_dim; i-- > 0; ) 04419 if (left.coefficient(Variable(i)) != 0) { 04420 if (left_t++ == 1) 04421 break; 04422 else 04423 left_w_id = i; 04424 } 04425 04426 // Get information about the number of non-zero coefficients in `right'. 04427 for (dimension_type i = right_space_dim; i-- > 0; ) 04428 if (right.coefficient(Variable(i)) != 0) { 04429 if (right_t++ == 1) 04430 break; 04431 else 04432 right_w_id = i; 04433 } 04434 04435 const FP_Interval_Type& left_w_coeff = 04436 left.coefficient(Variable(left_w_id)); 04437 const FP_Interval_Type& right_w_coeff = 04438 right.coefficient(Variable(right_w_id)); 04439 04440 if (left_t == 0) { 04441 if (right_t == 0) { 04442 // The constraint involves constants only. Ignore it: it is up to 04443 // the analyzer to handle it. 04444 PPL_ASSERT(OK()); 04445 return; 04446 } 04447 else if (right_w_coeff == 1 || right_w_coeff == -1) { 04448 left_inhomogeneous_refine(right_t, right_w_id, left, right); 04449 PPL_ASSERT(OK()); 04450 return; 04451 } 04452 } 04453 else if (left_t == 1) { 04454 if (left_w_coeff == 1 || left_w_coeff == -1) { 04455 if (right_t == 0 || (right_w_coeff == 1 || right_w_coeff == -1)) { 04456 left_one_var_refine(left_w_id, right_t, right_w_id, left, right); 04457 PPL_ASSERT(OK()); 04458 return; 04459 } 04460 } 04461 } 04462 04463 // General case. 04464 general_refine(left_w_id, right_w_id, left, right); 04465 PPL_ASSERT(OK()); 04466 } // end of refine_with_linear_form_inequality 04467 04468 template <typename T> 04469 template <typename U> 04470 void 04471 BD_Shape<T> 04472 ::export_interval_constraints(U& dest) const { 04473 const dimension_type space_dim = space_dimension(); 04474 if (space_dim > dest.space_dimension()) 04475 throw std::invalid_argument( 04476 "BD_Shape<T>::export_interval_constraints"); 04477 04478 // Expose all the interval constraints. 04479 shortest_path_closure_assign(); 04480 04481 if (marked_empty()) { 04482 dest.set_empty(); 04483 PPL_ASSERT(OK()); 04484 return; 04485 } 04486 04487 PPL_DIRTY_TEMP(N, tmp); 04488 const DB_Row<N>& dbm_0 = dbm[0]; 04489 for (dimension_type i = space_dim; i-- > 0; ) { 04490 // Set the upper bound. 04491 const N& u = dbm_0[i+1]; 04492 if (!is_plus_infinity(u)) 04493 if (!dest.restrict_upper(i, u.raw_value())) 04494 return; 04495 04496 // Set the lower bound. 04497 const N& negated_l = dbm[i+1][0]; 04498 if (!is_plus_infinity(negated_l)) { 04499 neg_assign_r(tmp, negated_l, ROUND_DOWN); 04500 if (!dest.restrict_lower(i, tmp.raw_value())) 04501 return; 04502 } 04503 } 04504 04505 PPL_ASSERT(OK()); 04506 } 04507 04508 template <typename T> 04509 template <typename Interval_Info> 04510 void 04511 BD_Shape<T>::left_inhomogeneous_refine(const dimension_type& right_t, 04512 const dimension_type& right_w_id, 04513 const Linear_Form< Interval<T, Interval_Info> >& left, 04514 const Linear_Form< Interval<T, Interval_Info> >& right) { 04515 04516 typedef Interval<T, Interval_Info> FP_Interval_Type; 04517 04518 if (right_t == 1) { 04519 // The constraint has the form [a-, a+] <= [b-, b+] + [c-, c+] * x. 04520 // Reduce it to the constraint +/-x <= b+ - a- if [c-, c+] = +/-[1, 1]. 04521 const FP_Interval_Type& right_w_coeff = 04522 right.coefficient(Variable(right_w_id)); 04523 if (right_w_coeff == 1) { 04524 PPL_DIRTY_TEMP(N, b_plus_minus_a_minus); 04525 const FP_Interval_Type& left_a = left.inhomogeneous_term(); 04526 const FP_Interval_Type& right_b = right.inhomogeneous_term(); 04527 sub_assign_r(b_plus_minus_a_minus, right_b.upper(), left_a.lower(), 04528 ROUND_UP); 04529 add_dbm_constraint(right_w_id+1, 0, b_plus_minus_a_minus); 04530 return; 04531 } 04532 04533 if (right_w_coeff == -1) { 04534 PPL_DIRTY_TEMP(N, b_plus_minus_a_minus); 04535 const FP_Interval_Type& left_a = left.inhomogeneous_term(); 04536 const FP_Interval_Type& right_b = right.inhomogeneous_term(); 04537 sub_assign_r(b_plus_minus_a_minus, right_b.upper(), left_a.lower(), 04538 ROUND_UP); 04539 add_dbm_constraint(0, right_w_id+1, b_plus_minus_a_minus); 04540 return; 04541 } 04542 } 04543 } // end of left_inhomogeneous_refine 04544 04545 04546 template <typename T> 04547 template <typename Interval_Info> 04548 void 04549 BD_Shape<T> 04550 ::left_one_var_refine(const dimension_type& left_w_id, 04551 const dimension_type& right_t, 04552 const dimension_type& right_w_id, 04553 const Linear_Form< Interval<T, Interval_Info> >& left, 04554 const Linear_Form< Interval<T, Interval_Info> >& right) { 04555 04556 typedef Interval<T, Interval_Info> FP_Interval_Type; 04557 04558 if (right_t == 0) { 04559 // The constraint has the form [b-, b+] + [c-, c+] * x <= [a-, a+] 04560 // Reduce it to the constraint +/-x <= a+ - b- if [c-, c+] = +/-[1, 1]. 04561 const FP_Interval_Type& left_w_coeff = 04562 left.coefficient(Variable(left_w_id)); 04563 04564 if (left_w_coeff == 1) { 04565 PPL_DIRTY_TEMP(N, a_plus_minus_b_minus); 04566 const FP_Interval_Type& left_b = left.inhomogeneous_term(); 04567 const FP_Interval_Type& right_a = right.inhomogeneous_term(); 04568 sub_assign_r(a_plus_minus_b_minus, right_a.upper(), left_b.lower(), 04569 ROUND_UP); 04570 add_dbm_constraint(0, left_w_id+1, a_plus_minus_b_minus); 04571 return; 04572 } 04573 04574 if (left_w_coeff == -1) { 04575 PPL_DIRTY_TEMP(N, a_plus_minus_b_minus); 04576 const FP_Interval_Type& left_b = left.inhomogeneous_term(); 04577 const FP_Interval_Type& right_a = right.inhomogeneous_term(); 04578 sub_assign_r(a_plus_minus_b_minus, right_a.upper(), left_b.lower(), 04579 ROUND_UP); 04580 add_dbm_constraint(left_w_id+1, 0, a_plus_minus_b_minus); 04581 return; 04582 } 04583 } 04584 else if (right_t == 1) { 04585 // The constraint has the form 04586 // [a-, a+] + [b-, b+] * x <= [c-, c+] + [d-, d+] * y. 04587 // Reduce it to the constraint +/-x +/-y <= c+ - a- 04588 // if [b-, b+] = +/-[1, 1] and [d-, d+] = +/-[1, 1]. 04589 const FP_Interval_Type& left_w_coeff = 04590 left.coefficient(Variable(left_w_id)); 04591 04592 const FP_Interval_Type& right_w_coeff = 04593 right.coefficient(Variable(right_w_id)); 04594 04595 bool is_left_coeff_one = (left_w_coeff == 1); 04596 bool is_left_coeff_minus_one = (left_w_coeff == -1); 04597 bool is_right_coeff_one = (right_w_coeff == 1); 04598 bool is_right_coeff_minus_one = (right_w_coeff == -1); 04599 if (left_w_id == right_w_id) { 04600 if ((is_left_coeff_one && is_right_coeff_one) 04601 || 04602 (is_left_coeff_minus_one && is_right_coeff_minus_one)) { 04603 // Here we have an identity or a constants-only constraint. 04604 return; 04605 } 04606 if (is_left_coeff_one && is_right_coeff_minus_one) { 04607 // We fall back to a previous case. 04608 PPL_DIRTY_TEMP(N, a_plus_minus_b_minus); 04609 const FP_Interval_Type& left_b = left.inhomogeneous_term(); 04610 const FP_Interval_Type& right_a = right.inhomogeneous_term(); 04611 sub_assign_r(a_plus_minus_b_minus, right_a.upper(), left_b.lower(), 04612 ROUND_UP); 04613 div_2exp_assign_r(a_plus_minus_b_minus, a_plus_minus_b_minus, 1, 04614 ROUND_UP); 04615 add_dbm_constraint(0, left_w_id + 1, a_plus_minus_b_minus); 04616 return; 04617 } 04618 if (is_left_coeff_minus_one && is_right_coeff_one) { 04619 // We fall back to a previous case. 04620 PPL_DIRTY_TEMP(N, a_plus_minus_b_minus); 04621 const FP_Interval_Type& left_b = left.inhomogeneous_term(); 04622 const FP_Interval_Type& right_a = right.inhomogeneous_term(); 04623 sub_assign_r(a_plus_minus_b_minus, right_a.upper(), left_b.lower(), 04624 ROUND_UP); 04625 div_2exp_assign_r(a_plus_minus_b_minus, a_plus_minus_b_minus, 1, 04626 ROUND_UP); 04627 add_dbm_constraint(right_w_id + 1, 0, a_plus_minus_b_minus); 04628 return; 04629 } 04630 } 04631 else if (is_left_coeff_minus_one && is_right_coeff_one) { 04632 // over-approximate (if is it possible) the inequality 04633 // -B + [b1, b2] <= A + [a1, a2] by adding the constraints 04634 // -B <= upper_bound(A) + (a2 - b1) and 04635 // -A <= upper_bound(B) + (a2 - b1) 04636 PPL_DIRTY_TEMP(N, a_plus_minus_b_minus); 04637 const FP_Interval_Type& left_b = left.inhomogeneous_term(); 04638 const FP_Interval_Type& right_a = right.inhomogeneous_term(); 04639 sub_assign_r(a_plus_minus_b_minus, right_a.upper(), left_b.lower(), 04640 ROUND_UP); 04641 PPL_DIRTY_TEMP(N, ub); 04642 ub = dbm[0][right_w_id + 1]; 04643 if (!is_plus_infinity(ub)) { 04644 add_assign_r(ub, ub, a_plus_minus_b_minus, ROUND_UP); 04645 add_dbm_constraint(left_w_id + 1, 0, ub); 04646 } 04647 ub = dbm[0][left_w_id + 1]; 04648 if (!is_plus_infinity(ub)) { 04649 add_assign_r(ub, ub, a_plus_minus_b_minus, ROUND_UP); 04650 add_dbm_constraint(right_w_id + 1, 0, ub); 04651 } 04652 return; 04653 } 04654 if (is_left_coeff_one && is_right_coeff_minus_one) { 04655 // over-approximate (if is it possible) the inequality 04656 // B + [b1, b2] <= -A + [a1, a2] by adding the constraints 04657 // B <= upper_bound(-A) + (a2 - b1) and 04658 // A <= upper_bound(-B) + (a2 - b1) 04659 PPL_DIRTY_TEMP(N, a_plus_minus_b_minus); 04660 const FP_Interval_Type& left_b = left.inhomogeneous_term(); 04661 const FP_Interval_Type& right_a = right.inhomogeneous_term(); 04662 sub_assign_r(a_plus_minus_b_minus, right_a.upper(), left_b.lower(), 04663 ROUND_UP); 04664 PPL_DIRTY_TEMP(N, ub); 04665 ub = dbm[right_w_id + 1][0]; 04666 if (!is_plus_infinity(ub)) { 04667 add_assign_r(ub, ub, a_plus_minus_b_minus, ROUND_UP); 04668 add_dbm_constraint(0, left_w_id + 1, ub); 04669 } 04670 ub = dbm[left_w_id + 1][0]; 04671 if (!is_plus_infinity(ub)) { 04672 add_assign_r(ub, ub, a_plus_minus_b_minus, ROUND_UP); 04673 add_dbm_constraint(0, right_w_id + 1, ub); 04674 } 04675 return; 04676 } 04677 if (is_left_coeff_one && is_right_coeff_one) { 04678 PPL_DIRTY_TEMP(N, c_plus_minus_a_minus); 04679 const FP_Interval_Type& left_a = left.inhomogeneous_term(); 04680 const FP_Interval_Type& right_c = right.inhomogeneous_term(); 04681 sub_assign_r(c_plus_minus_a_minus, right_c.upper(), left_a.lower(), 04682 ROUND_UP); 04683 add_dbm_constraint(right_w_id+1, left_w_id+1, c_plus_minus_a_minus); 04684 return; 04685 } 04686 if (is_left_coeff_minus_one && is_right_coeff_minus_one) { 04687 PPL_DIRTY_TEMP(N, c_plus_minus_a_minus); 04688 const FP_Interval_Type& left_a = left.inhomogeneous_term(); 04689 const FP_Interval_Type& right_c = right.inhomogeneous_term(); 04690 sub_assign_r(c_plus_minus_a_minus, right_c.upper(), left_a.lower(), 04691 ROUND_UP); 04692 add_dbm_constraint(left_w_id+1, right_w_id+1, c_plus_minus_a_minus); 04693 return; 04694 } 04695 } 04696 } 04697 04698 template <typename T> 04699 template <typename Interval_Info> 04700 void 04701 BD_Shape<T> 04702 ::general_refine(const dimension_type& left_w_id, 04703 const dimension_type& right_w_id, 04704 const Linear_Form< Interval<T, Interval_Info> >& left, 04705 const Linear_Form< Interval<T, Interval_Info> >& right) { 04706 04707 typedef Interval<T, Interval_Info> FP_Interval_Type; 04708 Linear_Form<FP_Interval_Type> right_minus_left(right); 04709 right_minus_left -= left; 04710 04711 // Declare temporaries outside of the loop. 04712 PPL_DIRTY_TEMP(N, low_coeff); 04713 PPL_DIRTY_TEMP(N, high_coeff); 04714 PPL_DIRTY_TEMP(N, upper_bound); 04715 04716 dimension_type max_w_id = std::max(left_w_id, right_w_id); 04717 04718 for (dimension_type first_v = 0; first_v < max_w_id; ++first_v) { 04719 for (dimension_type second_v = first_v+1; 04720 second_v <= max_w_id; ++second_v) { 04721 const FP_Interval_Type& lfv_coefficient = 04722 left.coefficient(Variable(first_v)); 04723 const FP_Interval_Type& lsv_coefficient = 04724 left.coefficient(Variable(second_v)); 04725 const FP_Interval_Type& rfv_coefficient = 04726 right.coefficient(Variable(first_v)); 04727 const FP_Interval_Type& rsv_coefficient = 04728 right.coefficient(Variable(second_v)); 04729 // We update the constraints only when both variables appear in at 04730 // least one argument. 04731 bool do_update = false; 04732 assign_r(low_coeff, lfv_coefficient.lower(), ROUND_NOT_NEEDED); 04733 assign_r(high_coeff, lfv_coefficient.upper(), ROUND_NOT_NEEDED); 04734 if (low_coeff != 0 || high_coeff != 0) { 04735 assign_r(low_coeff, lsv_coefficient.lower(), ROUND_NOT_NEEDED); 04736 assign_r(high_coeff, lsv_coefficient.upper(), ROUND_NOT_NEEDED); 04737 if (low_coeff != 0 || high_coeff != 0) 04738 do_update = true; 04739 else { 04740 assign_r(low_coeff, rsv_coefficient.lower(), ROUND_NOT_NEEDED); 04741 assign_r(high_coeff, rsv_coefficient.upper(), ROUND_NOT_NEEDED); 04742 if (low_coeff != 0 || high_coeff != 0) 04743 do_update = true; 04744 } 04745 } 04746 else { 04747 assign_r(low_coeff, rfv_coefficient.lower(), ROUND_NOT_NEEDED); 04748 assign_r(high_coeff, rfv_coefficient.upper(), ROUND_NOT_NEEDED); 04749 if (low_coeff != 0 || high_coeff != 0) { 04750 assign_r(low_coeff, lsv_coefficient.lower(), ROUND_NOT_NEEDED); 04751 assign_r(high_coeff, lsv_coefficient.upper(), ROUND_NOT_NEEDED); 04752 if (low_coeff != 0 || high_coeff != 0) 04753 do_update = true; 04754 else { 04755 assign_r(low_coeff, rsv_coefficient.lower(), ROUND_NOT_NEEDED); 04756 assign_r(high_coeff, rsv_coefficient.upper(), ROUND_NOT_NEEDED); 04757 if (low_coeff != 0 || high_coeff != 0) 04758 do_update = true; 04759 } 04760 } 04761 } 04762 04763 if (do_update) { 04764 Variable first(first_v); 04765 Variable second(second_v); 04766 dimension_type n_first_var = first_v +1 ; 04767 dimension_type n_second_var = second_v + 1; 04768 linear_form_upper_bound(right_minus_left - first + second, 04769 upper_bound); 04770 add_dbm_constraint(n_first_var, n_second_var, upper_bound); 04771 linear_form_upper_bound(right_minus_left + first - second, 04772 upper_bound); 04773 add_dbm_constraint(n_second_var, n_first_var, upper_bound); 04774 } 04775 } 04776 } 04777 04778 // Finally, update the unary constraints. 04779 for (dimension_type v = 0; v < max_w_id; ++v) { 04780 const FP_Interval_Type& lv_coefficient = 04781 left.coefficient(Variable(v)); 04782 const FP_Interval_Type& rv_coefficient = 04783 right.coefficient(Variable(v)); 04784 // We update the constraints only if v appears in at least one of the 04785 // two arguments. 04786 bool do_update = false; 04787 assign_r(low_coeff, lv_coefficient.lower(), ROUND_NOT_NEEDED); 04788 assign_r(high_coeff, lv_coefficient.upper(), ROUND_NOT_NEEDED); 04789 if (low_coeff != 0 || high_coeff != 0) 04790 do_update = true; 04791 else { 04792 assign_r(low_coeff, rv_coefficient.lower(), ROUND_NOT_NEEDED); 04793 assign_r(high_coeff, rv_coefficient.upper(), ROUND_NOT_NEEDED); 04794 if (low_coeff != 0 || high_coeff != 0) 04795 do_update = true; 04796 } 04797 04798 if (do_update) { 04799 Variable var(v); 04800 dimension_type n_var = v + 1; 04801 linear_form_upper_bound(right_minus_left + var, upper_bound); 04802 add_dbm_constraint(0, n_var, upper_bound); 04803 linear_form_upper_bound(right_minus_left - var, upper_bound); 04804 add_dbm_constraint(n_var, 0, upper_bound); 04805 } 04806 } 04807 04808 } 04809 04810 template <typename T> 04811 template <typename Interval_Info> 04812 void 04813 BD_Shape<T>:: 04814 linear_form_upper_bound(const Linear_Form< Interval<T, Interval_Info> >& lf, 04815 N& result) const { 04816 04817 // Check that T is a floating point type. 04818 PPL_COMPILE_TIME_CHECK(!std::numeric_limits<T>::is_exact, 04819 "BD_Shape<T>::linear_form_upper_bound:" 04820 " T not a floating point type."); 04821 04822 const dimension_type lf_space_dimension = lf.space_dimension(); 04823 PPL_ASSERT(lf_space_dimension <= space_dimension()); 04824 04825 typedef Interval<T, Interval_Info> FP_Interval_Type; 04826 04827 PPL_DIRTY_TEMP(N, curr_lb); 04828 PPL_DIRTY_TEMP(N, curr_ub); 04829 PPL_DIRTY_TEMP(N, curr_var_ub); 04830 PPL_DIRTY_TEMP(N, curr_minus_var_ub); 04831 04832 PPL_DIRTY_TEMP(N, first_comparison_term); 04833 PPL_DIRTY_TEMP(N, second_comparison_term); 04834 04835 PPL_DIRTY_TEMP(N, negator); 04836 04837 assign_r(result, lf.inhomogeneous_term().upper(), ROUND_NOT_NEEDED); 04838 04839 for (dimension_type curr_var = 0, n_var = 0; curr_var < lf_space_dimension; 04840 ++curr_var) { 04841 n_var = curr_var + 1; 04842 const FP_Interval_Type& curr_coefficient = 04843 lf.coefficient(Variable(curr_var)); 04844 assign_r(curr_lb, curr_coefficient.lower(), ROUND_NOT_NEEDED); 04845 assign_r(curr_ub, curr_coefficient.upper(), ROUND_NOT_NEEDED); 04846 if (curr_lb != 0 || curr_ub != 0) { 04847 assign_r(curr_var_ub, dbm[0][n_var], ROUND_NOT_NEEDED); 04848 neg_assign_r(curr_minus_var_ub, dbm[n_var][0], ROUND_NOT_NEEDED); 04849 // Optimize the most commons cases: curr = +/-[1, 1]. 04850 if (curr_lb == 1 && curr_ub == 1) { 04851 add_assign_r(result, result, std::max(curr_var_ub, curr_minus_var_ub), 04852 ROUND_UP); 04853 } 04854 else if (curr_lb == -1 && curr_ub == -1) { 04855 neg_assign_r(negator, std::min(curr_var_ub, curr_minus_var_ub), 04856 ROUND_NOT_NEEDED); 04857 add_assign_r(result, result, negator, ROUND_UP); 04858 } 04859 else { 04860 // Next addend will be the maximum of four quantities. 04861 assign_r(first_comparison_term, 0, ROUND_NOT_NEEDED); 04862 assign_r(second_comparison_term, 0, ROUND_NOT_NEEDED); 04863 add_mul_assign_r(first_comparison_term, curr_var_ub, curr_ub, 04864 ROUND_UP); 04865 add_mul_assign_r(second_comparison_term, curr_var_ub, curr_lb, 04866 ROUND_UP); 04867 assign_r(first_comparison_term, std::max(first_comparison_term, 04868 second_comparison_term), 04869 ROUND_NOT_NEEDED); 04870 assign_r(second_comparison_term, 0, ROUND_NOT_NEEDED); 04871 add_mul_assign_r(second_comparison_term, curr_minus_var_ub, curr_ub, 04872 ROUND_UP); 04873 assign_r(first_comparison_term, std::max(first_comparison_term, 04874 second_comparison_term), 04875 ROUND_NOT_NEEDED); 04876 assign_r(second_comparison_term, 0, ROUND_NOT_NEEDED); 04877 add_mul_assign_r(second_comparison_term, curr_minus_var_ub, curr_lb, 04878 ROUND_UP); 04879 assign_r(first_comparison_term, std::max(first_comparison_term, 04880 second_comparison_term), 04881 ROUND_NOT_NEEDED); 04882 04883 add_assign_r(result, result, first_comparison_term, ROUND_UP); 04884 } 04885 } 04886 } 04887 } 04888 04889 template <typename T> 04890 void 04891 BD_Shape<T>::affine_preimage(const Variable var, 04892 const Linear_Expression& expr, 04893 Coefficient_traits::const_reference denominator) { 04894 // The denominator cannot be zero. 04895 if (denominator == 0) 04896 throw_invalid_argument("affine_preimage(v, e, d)", "d == 0"); 04897 04898 // Dimension-compatibility checks. 04899 // The dimension of `expr' should not be greater than the dimension 04900 // of `*this'. 04901 const dimension_type space_dim = space_dimension(); 04902 const dimension_type expr_space_dim = expr.space_dimension(); 04903 if (space_dim < expr_space_dim) 04904 throw_dimension_incompatible("affine_preimage(v, e, d)", "e", expr); 04905 04906 // `var' should be one of the dimensions of 04907 // the bounded difference shapes. 04908 const dimension_type v = var.id() + 1; 04909 if (v > space_dim) 04910 throw_dimension_incompatible("affine_preimage(v, e, d)", var.id()); 04911 04912 // The image of an empty BDS is empty too. 04913 shortest_path_closure_assign(); 04914 if (marked_empty()) 04915 return; 04916 04917 const Coefficient& b = expr.inhomogeneous_term(); 04918 // Number of non-zero coefficients in `expr': will be set to 04919 // 0, 1, or 2, the latter value meaning any value greater than 1. 04920 dimension_type t = 0; 04921 // Index of the last non-zero coefficient in `expr', if any. 04922 dimension_type j = 0; 04923 // Get information about the number of non-zero coefficients in `expr'. 04924 for (dimension_type i = expr_space_dim; i-- > 0; ) 04925 if (expr.coefficient(Variable(i)) != 0) { 04926 if (t++ == 1) 04927 break; 04928 else 04929 j = i; 04930 } 04931 04932 // Now we know the form of `expr': 04933 // - If t == 0, then expr = b, with `b' a constant; 04934 // - If t == 1, then expr = a*w + b, where `w' can be `v' or another 04935 // variable; in this second case we have to check whether `a' is 04936 // equal to `denominator' or `-denominator', since otherwise we have 04937 // to fall back on the general form; 04938 // - If t > 1, the `expr' is of the general form. 04939 if (t == 0) { 04940 // Case 1: expr = n; remove all constraints on `var'. 04941 forget_all_dbm_constraints(v); 04942 // Shortest-path closure is preserved, but not reduction. 04943 if (marked_shortest_path_reduced()) 04944 reset_shortest_path_reduced(); 04945 PPL_ASSERT(OK()); 04946 return; 04947 } 04948 04949 if (t == 1) { 04950 // Value of the one and only non-zero coefficient in `expr'. 04951 const Coefficient& a = expr.coefficient(Variable(j)); 04952 if (a == denominator || a == -denominator) { 04953 // Case 2: expr = a*w + b, with a = +/- denominator. 04954 if (j == var.id()) 04955 // Apply affine_image() on the inverse of this transformation. 04956 affine_image(var, denominator*var - b, a); 04957 else { 04958 // `expr == a*w + b', where `w != v'. 04959 // Remove all constraints on `var'. 04960 forget_all_dbm_constraints(v); 04961 // Shortest-path closure is preserved, but not reduction. 04962 if (marked_shortest_path_reduced()) 04963 reset_shortest_path_reduced(); 04964 PPL_ASSERT(OK()); 04965 } 04966 return; 04967 } 04968 } 04969 04970 // General case. 04971 // Either t == 2, so that 04972 // expr = a_1*x_1 + a_2*x_2 + ... + a_n*x_n + b, where n >= 2, 04973 // or t = 1, expr = a*w + b, but a <> +/- denominator. 04974 const Coefficient& expr_v = expr.coefficient(var); 04975 if (expr_v != 0) { 04976 // The transformation is invertible. 04977 Linear_Expression inverse((expr_v + denominator)*var); 04978 inverse -= expr; 04979 affine_image(var, inverse, expr_v); 04980 } 04981 else { 04982 // Transformation not invertible: all constraints on `var' are lost. 04983 forget_all_dbm_constraints(v); 04984 // Shortest-path closure is preserved, but not reduction. 04985 if (marked_shortest_path_reduced()) 04986 reset_shortest_path_reduced(); 04987 } 04988 PPL_ASSERT(OK()); 04989 } 04990 04991 template <typename T> 04992 void 04993 BD_Shape<T> 04994 ::bounded_affine_image(const Variable var, 04995 const Linear_Expression& lb_expr, 04996 const Linear_Expression& ub_expr, 04997 Coefficient_traits::const_reference denominator) { 04998 // The denominator cannot be zero. 04999 if (denominator == 0) 05000 throw_invalid_argument("bounded_affine_image(v, lb, ub, d)", "d == 0"); 05001 05002 // Dimension-compatibility checks. 05003 // `var' should be one of the dimensions of the BD_Shape. 05004 const dimension_type bds_space_dim = space_dimension(); 05005 const dimension_type v = var.id() + 1; 05006 if (v > bds_space_dim) 05007 throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)", 05008 "v", var); 05009 // The dimension of `lb_expr' and `ub_expr' should not be 05010 // greater than the dimension of `*this'. 05011 const dimension_type lb_space_dim = lb_expr.space_dimension(); 05012 if (bds_space_dim < lb_space_dim) 05013 throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)", 05014 "lb", lb_expr); 05015 const dimension_type ub_space_dim = ub_expr.space_dimension(); 05016 if (bds_space_dim < ub_space_dim) 05017 throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)", 05018 "ub", ub_expr); 05019 05020 // Any image of an empty BDS is empty. 05021 shortest_path_closure_assign(); 05022 if (marked_empty()) 05023 return; 05024 05025 const Coefficient& b = ub_expr.inhomogeneous_term(); 05026 // Number of non-zero coefficients in `ub_expr': will be set to 05027 // 0, 1, or 2, the latter value meaning any value greater than 1. 05028 dimension_type t = 0; 05029 // Index of the last non-zero coefficient in `ub_expr', if any. 05030 dimension_type w = 0; 05031 // Get information about the number of non-zero coefficients in `expr'. 05032 for (dimension_type i = ub_space_dim; i-- > 0; ) 05033 if (ub_expr.coefficient(Variable(i)) != 0) { 05034 if (t++ == 1) 05035 break; 05036 else 05037 w = i+1; 05038 } 05039 05040 // Now we know the form of `ub_expr': 05041 // - If t == 0, then ub_expr == b, with `b' a constant; 05042 // - If t == 1, then ub_expr == a*w + b, where `w' can be `v' or another 05043 // variable; in this second case we have to check whether `a' is 05044 // equal to `denominator' or `-denominator', since otherwise we have 05045 // to fall back on the general form; 05046 // - If t == 2, the `ub_expr' is of the general form. 05047 PPL_DIRTY_TEMP_COEFFICIENT(minus_denom); 05048 neg_assign(minus_denom, denominator); 05049 05050 if (t == 0) { 05051 // Case 1: ub_expr == b. 05052 generalized_affine_image(var, 05053 GREATER_OR_EQUAL, 05054 lb_expr, 05055 denominator); 05056 // Add the constraint `var <= b/denominator'. 05057 add_dbm_constraint(0, v, b, denominator); 05058 PPL_ASSERT(OK()); 05059 return; 05060 } 05061 05062 if (t == 1) { 05063 // Value of the one and only non-zero coefficient in `ub_expr'. 05064 const Coefficient& a = ub_expr.coefficient(Variable(w-1)); 05065 if (a == denominator || a == minus_denom) { 05066 // Case 2: expr == a*w + b, with a == +/- denominator. 05067 if (w == v) { 05068 // Here `var' occurs in `ub_expr'. 05069 // To ease the computation, we add an additional dimension. 05070 const Variable new_var(bds_space_dim); 05071 add_space_dimensions_and_embed(1); 05072 // Constrain the new dimension to be equal to `ub_expr'. 05073 affine_image(new_var, ub_expr, denominator); 05074 // NOTE: enforce shortest-path closure for precision. 05075 shortest_path_closure_assign(); 05076 PPL_ASSERT(!marked_empty()); 05077 // Apply the affine lower bound. 05078 generalized_affine_image(var, 05079 GREATER_OR_EQUAL, 05080 lb_expr, 05081 denominator); 05082 // Now apply the affine upper bound, as recorded in `new_var'. 05083 add_constraint(var <= new_var); 05084 // Remove the temporarily added dimension. 05085 remove_higher_space_dimensions(bds_space_dim); 05086 return; 05087 } 05088 else { 05089 // Here `w != v', so that `expr' is of the form 05090 // +/-denominator * w + b. 05091 // Apply the affine lower bound. 05092 generalized_affine_image(var, 05093 GREATER_OR_EQUAL, 05094 lb_expr, 05095 denominator); 05096 if (a == denominator) { 05097 // Add the new constraint `v - w == b/denominator'. 05098 add_dbm_constraint(w, v, b, denominator); 05099 } 05100 else { 05101 // Here a == -denominator, so that we should be adding 05102 // the constraint `v + w == b/denominator'. 05103 // Approximate it by computing lower and upper bounds for `w'. 05104 const N& dbm_w0 = dbm[w][0]; 05105 if (!is_plus_infinity(dbm_w0)) { 05106 // Add the constraint `v <= b/denominator - lower_w'. 05107 PPL_DIRTY_TEMP(N, d); 05108 div_round_up(d, b, denominator); 05109 add_assign_r(dbm[0][v], d, dbm_w0, ROUND_UP); 05110 reset_shortest_path_closed(); 05111 } 05112 } 05113 PPL_ASSERT(OK()); 05114 return; 05115 } 05116 } 05117 } 05118 05119 // General case. 05120 // Either t == 2, so that 05121 // ub_expr == a_1*x_1 + a_2*x_2 + ... + a_n*x_n + b, where n >= 2, 05122 // or t == 1, ub_expr == a*w + b, but a <> +/- denominator. 05123 // We will remove all the constraints on `var' and add back 05124 // constraints providing upper and lower bounds for `var'. 05125 05126 // Compute upper approximations for `ub_expr' into `pos_sum' 05127 // taking into account the sign of `denominator'. 05128 const bool is_sc = (denominator > 0); 05129 PPL_DIRTY_TEMP_COEFFICIENT(minus_b); 05130 neg_assign(minus_b, b); 05131 const Coefficient& sc_b = is_sc ? b : minus_b; 05132 const Coefficient& sc_denom = is_sc ? denominator : minus_denom; 05133 const Coefficient& minus_sc_denom = is_sc ? minus_denom : denominator; 05134 // NOTE: here, for optimization purposes, `minus_expr' is only assigned 05135 // when `denominator' is negative. Do not use it unless you are sure 05136 // it has been correctly assigned. 05137 Linear_Expression minus_expr; 05138 if (!is_sc) 05139 minus_expr = -ub_expr; 05140 const Linear_Expression& sc_expr = is_sc ? ub_expr : minus_expr; 05141 05142 PPL_DIRTY_TEMP(N, pos_sum); 05143 // Index of the variable that are unbounded in `this->dbm'. 05144 PPL_UNINITIALIZED(dimension_type, pos_pinf_index); 05145 // Number of unbounded variables found. 05146 dimension_type pos_pinf_count = 0; 05147 05148 // Approximate the inhomogeneous term. 05149 assign_r(pos_sum, sc_b, ROUND_UP); 05150 05151 // Approximate the homogeneous part of `sc_expr'. 05152 const DB_Row<N>& dbm_0 = dbm[0]; 05153 // Speculative allocation of temporaries to be used in the following loop. 05154 PPL_DIRTY_TEMP(N, coeff_i); 05155 PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i); 05156 // Note: indices above `w' can be disregarded, as they all have 05157 // a zero coefficient in `sc_expr'. 05158 for (dimension_type i = w; i > 0; --i) { 05159 const Coefficient& sc_i = sc_expr.coefficient(Variable(i-1)); 05160 const int sign_i = sgn(sc_i); 05161 if (sign_i > 0) { 05162 assign_r(coeff_i, sc_i, ROUND_UP); 05163 // Approximating `sc_expr'. 05164 if (pos_pinf_count <= 1) { 05165 const N& up_approx_i = dbm_0[i]; 05166 if (!is_plus_infinity(up_approx_i)) 05167 add_mul_assign_r(pos_sum, coeff_i, up_approx_i, ROUND_UP); 05168 else { 05169 ++pos_pinf_count; 05170 pos_pinf_index = i; 05171 } 05172 } 05173 } 05174 else if (sign_i < 0) { 05175 neg_assign(minus_sc_i, sc_i); 05176 // Note: using temporary named `coeff_i' to store -coeff_i. 05177 assign_r(coeff_i, minus_sc_i, ROUND_UP); 05178 // Approximating `sc_expr'. 05179 if (pos_pinf_count <= 1) { 05180 const N& up_approx_minus_i = dbm[i][0]; 05181 if (!is_plus_infinity(up_approx_minus_i)) 05182 add_mul_assign_r(pos_sum, coeff_i, up_approx_minus_i, ROUND_UP); 05183 else { 05184 ++pos_pinf_count; 05185 pos_pinf_index = i; 05186 } 05187 } 05188 } 05189 } 05190 // Apply the affine lower bound. 05191 generalized_affine_image(var, 05192 GREATER_OR_EQUAL, 05193 lb_expr, 05194 denominator); 05195 // Return immediately if no approximation could be computed. 05196 if (pos_pinf_count > 1) { 05197 return; 05198 } 05199 05200 // In the following, shortest-path closure will be definitely lost. 05201 reset_shortest_path_closed(); 05202 05203 // Exploit the upper approximation, if possible. 05204 if (pos_pinf_count <= 1) { 05205 // Compute quotient (if needed). 05206 if (sc_denom != 1) { 05207 // Before computing quotients, the denominator should be approximated 05208 // towards zero. Since `sc_denom' is known to be positive, this amounts to 05209 // rounding downwards, which is achieved as usual by rounding upwards 05210 // `minus_sc_denom' and negating again the result. 05211 PPL_DIRTY_TEMP(N, down_sc_denom); 05212 assign_r(down_sc_denom, minus_sc_denom, ROUND_UP); 05213 neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP); 05214 div_assign_r(pos_sum, pos_sum, down_sc_denom, ROUND_UP); 05215 } 05216 // Add the upper bound constraint, if meaningful. 05217 if (pos_pinf_count == 0) { 05218 // Add the constraint `v <= pos_sum'. 05219 dbm[0][v] = pos_sum; 05220 // Deduce constraints of the form `v - u', where `u != v'. 05221 deduce_v_minus_u_bounds(v, w, sc_expr, sc_denom, pos_sum); 05222 } 05223 else 05224 // Here `pos_pinf_count == 1'. 05225 if (pos_pinf_index != v 05226 && sc_expr.coefficient(Variable(pos_pinf_index-1)) == sc_denom) 05227 // Add the constraint `v - pos_pinf_index <= pos_sum'. 05228 dbm[pos_pinf_index][v] = pos_sum; 05229 } 05230 PPL_ASSERT(OK()); 05231 } 05232 05233 template <typename T> 05234 void 05235 BD_Shape<T> 05236 ::bounded_affine_preimage(const Variable var, 05237 const Linear_Expression& lb_expr, 05238 const Linear_Expression& ub_expr, 05239 Coefficient_traits::const_reference denominator) { 05240 // The denominator cannot be zero. 05241 if (denominator == 0) 05242 throw_invalid_argument("bounded_affine_preimage(v, lb, ub, d)", "d == 0"); 05243 05244 // Dimension-compatibility checks. 05245 // `var' should be one of the dimensions of the BD_Shape. 05246 const dimension_type space_dim = space_dimension(); 05247 const dimension_type v = var.id() + 1; 05248 if (v > space_dim) 05249 throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)", 05250 "v", var); 05251 // The dimension of `lb_expr' and `ub_expr' should not be 05252 // greater than the dimension of `*this'. 05253 const dimension_type lb_space_dim = lb_expr.space_dimension(); 05254 if (space_dim < lb_space_dim) 05255 throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)", 05256 "lb", lb_expr); 05257 const dimension_type ub_space_dim = ub_expr.space_dimension(); 05258 if (space_dim < ub_space_dim) 05259 throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)", 05260 "ub", ub_expr); 05261 05262 // Any preimage of an empty BDS is empty. 05263 shortest_path_closure_assign(); 05264 if (marked_empty()) 05265 return; 05266 05267 if (ub_expr.coefficient(var) == 0) { 05268 refine(var, LESS_OR_EQUAL, ub_expr, denominator); 05269 generalized_affine_preimage(var, GREATER_OR_EQUAL, 05270 lb_expr, denominator); 05271 return; 05272 } 05273 if (lb_expr.coefficient(var) == 0) { 05274 refine(var, GREATER_OR_EQUAL, lb_expr, denominator); 05275 generalized_affine_preimage(var, LESS_OR_EQUAL, 05276 ub_expr, denominator); 05277 return; 05278 } 05279 05280 const Coefficient& lb_expr_v = lb_expr.coefficient(var); 05281 // Here `var' occurs in `lb_expr' and `ub_expr'. 05282 // To ease the computation, we add an additional dimension. 05283 const Variable new_var(space_dim); 05284 add_space_dimensions_and_embed(1); 05285 const Linear_Expression lb_inverse 05286 = lb_expr - (lb_expr_v + denominator)*var; 05287 PPL_DIRTY_TEMP_COEFFICIENT(lb_inverse_denom); 05288 neg_assign(lb_inverse_denom, lb_expr_v); 05289 affine_image(new_var, lb_inverse, lb_inverse_denom); 05290 shortest_path_closure_assign(); 05291 PPL_ASSERT(!marked_empty()); 05292 generalized_affine_preimage(var, LESS_OR_EQUAL, 05293 ub_expr, denominator); 05294 if (sgn(denominator) == sgn(lb_inverse_denom)) 05295 add_constraint(var >= new_var); 05296 else 05297 add_constraint(var <= new_var); 05298 // Remove the temporarily added dimension. 05299 remove_higher_space_dimensions(space_dim); 05300 } 05301 05302 template <typename T> 05303 void 05304 BD_Shape<T>::generalized_affine_image(const Variable var, 05305 const Relation_Symbol relsym, 05306 const Linear_Expression& expr, 05307 Coefficient_traits::const_reference 05308 denominator) { 05309 // The denominator cannot be zero. 05310 if (denominator == 0) 05311 throw_invalid_argument("generalized_affine_image(v, r, e, d)", "d == 0"); 05312 05313 // Dimension-compatibility checks. 05314 // The dimension of `expr' should not be greater than the dimension 05315 // of `*this'. 05316 const dimension_type space_dim = space_dimension(); 05317 const dimension_type expr_space_dim = expr.space_dimension(); 05318 if (space_dim < expr_space_dim) 05319 throw_dimension_incompatible("generalized_affine_image(v, r, e, d)", 05320 "e", expr); 05321 05322 // `var' should be one of the dimensions of the BDS. 05323 const dimension_type v = var.id() + 1; 05324 if (v > space_dim) 05325 throw_dimension_incompatible("generalized_affine_image(v, r, e, d)", 05326 var.id()); 05327 05328 // The relation symbol cannot be a strict relation symbol. 05329 if (relsym == LESS_THAN || relsym == GREATER_THAN) 05330 throw_invalid_argument("generalized_affine_image(v, r, e, d)", 05331 "r is a strict relation symbol"); 05332 // The relation symbol cannot be a disequality. 05333 if (relsym == NOT_EQUAL) 05334 throw_invalid_argument("generalized_affine_image(v, r, e, d)", 05335 "r is the disequality relation symbol"); 05336 05337 if (relsym == EQUAL) { 05338 // The relation symbol is "=": 05339 // this is just an affine image computation. 05340 affine_image(var, expr, denominator); 05341 return; 05342 } 05343 05344 // The image of an empty BDS is empty too. 05345 shortest_path_closure_assign(); 05346 if (marked_empty()) 05347 return; 05348 05349 const Coefficient& b = expr.inhomogeneous_term(); 05350 // Number of non-zero coefficients in `expr': will be set to 05351 // 0, 1, or 2, the latter value meaning any value greater than 1. 05352 dimension_type t = 0; 05353 // Index of the last non-zero coefficient in `expr', if any. 05354 dimension_type w = 0; 05355 // Get information about the number of non-zero coefficients in `expr'. 05356 for (dimension_type i = expr_space_dim; i-- > 0; ) 05357 if (expr.coefficient(Variable(i)) != 0) { 05358 if (t++ == 1) 05359 break; 05360 else 05361 w = i+1; 05362 } 05363 05364 // Now we know the form of `expr': 05365 // - If t == 0, then expr == b, with `b' a constant; 05366 // - If t == 1, then expr == a*w + b, where `w' can be `v' or another 05367 // variable; in this second case we have to check whether `a' is 05368 // equal to `denominator' or `-denominator', since otherwise we have 05369 // to fall back on the general form; 05370 // - If t == 2, the `expr' is of the general form. 05371 DB_Row<N>& dbm_0 = dbm[0]; 05372 DB_Row<N>& dbm_v = dbm[v]; 05373 PPL_DIRTY_TEMP_COEFFICIENT(minus_denom); 05374 neg_assign(minus_denom, denominator); 05375 05376 if (t == 0) { 05377 // Case 1: expr == b. 05378 // Remove all constraints on `var'. 05379 forget_all_dbm_constraints(v); 05380 // Both shortest-path closure and reduction are lost. 05381 reset_shortest_path_closed(); 05382 switch (relsym) { 05383 case LESS_OR_EQUAL: 05384 // Add the constraint `var <= b/denominator'. 05385 add_dbm_constraint(0, v, b, denominator); 05386 break; 05387 case GREATER_OR_EQUAL: 05388 // Add the constraint `var >= b/denominator', 05389 // i.e., `-var <= -b/denominator', 05390 add_dbm_constraint(v, 0, b, minus_denom); 05391 break; 05392 default: 05393 // We already dealt with the other cases. 05394 PPL_UNREACHABLE; 05395 break; 05396 } 05397 PPL_ASSERT(OK()); 05398 return; 05399 } 05400 05401 if (t == 1) { 05402 // Value of the one and only non-zero coefficient in `expr'. 05403 const Coefficient& a = expr.coefficient(Variable(w-1)); 05404 if (a == denominator || a == minus_denom) { 05405 // Case 2: expr == a*w + b, with a == +/- denominator. 05406 PPL_DIRTY_TEMP(N, d); 05407 switch (relsym) { 05408 case LESS_OR_EQUAL: 05409 div_round_up(d, b, denominator); 05410 if (w == v) { 05411 // `expr' is of the form: a*v + b. 05412 // Shortest-path closure and reduction are not preserved. 05413 reset_shortest_path_closed(); 05414 if (a == denominator) { 05415 // Translate each constraint `v - w <= dbm_wv' 05416 // into the constraint `v - w <= dbm_wv + b/denominator'; 05417 // forget each constraint `w - v <= dbm_vw'. 05418 for (dimension_type i = space_dim + 1; i-- > 0; ) { 05419 N& dbm_iv = dbm[i][v]; 05420 add_assign_r(dbm_iv, dbm_iv, d, ROUND_UP); 05421 assign_r(dbm_v[i], PLUS_INFINITY, ROUND_NOT_NEEDED); 05422 } 05423 } 05424 else { 05425 // Here `a == -denominator'. 05426 // Translate the constraint `0 - v <= dbm_v0' 05427 // into the constraint `0 - v <= dbm_v0 + b/denominator'. 05428 N& dbm_v0 = dbm_v[0]; 05429 add_assign_r(dbm_0[v], dbm_v0, d, ROUND_UP); 05430 // Forget all the other constraints on `v'. 05431 assign_r(dbm_v0, PLUS_INFINITY, ROUND_NOT_NEEDED); 05432 forget_binary_dbm_constraints(v); 05433 } 05434 } 05435 else { 05436 // Here `w != v', so that `expr' is of the form 05437 // +/-denominator * w + b, with `w != v'. 05438 // Remove all constraints on `v'. 05439 forget_all_dbm_constraints(v); 05440 // Shortest-path closure is preserved, but not reduction. 05441 if (marked_shortest_path_reduced()) 05442 reset_shortest_path_reduced(); 05443 if (a == denominator) 05444 // Add the new constraint `v - w <= b/denominator'. 05445 add_dbm_constraint(w, v, d); 05446 else { 05447 // Here a == -denominator, so that we should be adding 05448 // the constraint `v <= b/denominator - w'. 05449 // Approximate it by computing a lower bound for `w'. 05450 const N& dbm_w0 = dbm[w][0]; 05451 if (!is_plus_infinity(dbm_w0)) { 05452 // Add the constraint `v <= b/denominator - lb_w'. 05453 add_assign_r(dbm_0[v], d, dbm_w0, ROUND_UP); 05454 // Shortest-path closure is not preserved. 05455 reset_shortest_path_closed(); 05456 } 05457 } 05458 } 05459 break; 05460 05461 case GREATER_OR_EQUAL: 05462 div_round_up(d, b, minus_denom); 05463 if (w == v) { 05464 // `expr' is of the form: a*w + b. 05465 // Shortest-path closure and reduction are not preserved. 05466 reset_shortest_path_closed(); 05467 if (a == denominator) { 05468 // Translate each constraint `w - v <= dbm_vw' 05469 // into the constraint `w - v <= dbm_vw - b/denominator'; 05470 // forget each constraint `v - w <= dbm_wv'. 05471 for (dimension_type i = space_dim + 1; i-- > 0; ) { 05472 N& dbm_vi = dbm_v[i]; 05473 add_assign_r(dbm_vi, dbm_vi, d, ROUND_UP); 05474 assign_r(dbm[i][v], PLUS_INFINITY, ROUND_NOT_NEEDED); 05475 } 05476 } 05477 else { 05478 // Here `a == -denominator'. 05479 // Translate the constraint `0 - v <= dbm_v0' 05480 // into the constraint `0 - v <= dbm_0v - b/denominator'. 05481 N& dbm_0v = dbm_0[v]; 05482 add_assign_r(dbm_v[0], dbm_0v, d, ROUND_UP); 05483 // Forget all the other constraints on `v'. 05484 assign_r(dbm_0v, PLUS_INFINITY, ROUND_NOT_NEEDED); 05485 forget_binary_dbm_constraints(v); 05486 } 05487 } 05488 else { 05489 // Here `w != v', so that `expr' is of the form 05490 // +/-denominator * w + b, with `w != v'. 05491 // Remove all constraints on `v'. 05492 forget_all_dbm_constraints(v); 05493 // Shortest-path closure is preserved, but not reduction. 05494 if (marked_shortest_path_reduced()) 05495 reset_shortest_path_reduced(); 05496 if (a == denominator) 05497 // Add the new constraint `v - w >= b/denominator', 05498 // i.e., `w - v <= -b/denominator'. 05499 add_dbm_constraint(v, w, d); 05500 else { 05501 // Here a == -denominator, so that we should be adding 05502 // the constraint `v >= -w + b/denominator', 05503 // i.e., `-v <= w - b/denominator'. 05504 // Approximate it by computing an upper bound for `w'. 05505 const N& dbm_0w = dbm_0[w]; 05506 if (!is_plus_infinity(dbm_0w)) { 05507 // Add the constraint `-v <= ub_w - b/denominator'. 05508 add_assign_r(dbm_v[0], dbm_0w, d, ROUND_UP); 05509 // Shortest-path closure is not preserved. 05510 reset_shortest_path_closed(); 05511 } 05512 } 05513 } 05514 break; 05515 05516 default: 05517 // We already dealt with the other cases. 05518 PPL_UNREACHABLE; 05519 break; 05520 } 05521 PPL_ASSERT(OK()); 05522 return; 05523 } 05524 } 05525 05526 // General case. 05527 // Either t == 2, so that 05528 // expr == a_1*x_1 + a_2*x_2 + ... + a_n*x_n + b, where n >= 2, 05529 // or t == 1, expr == a*w + b, but a <> +/- denominator. 05530 // We will remove all the constraints on `v' and add back 05531 // a constraint providing an upper or a lower bound for `v' 05532 // (depending on `relsym'). 05533 const bool is_sc = (denominator > 0); 05534 PPL_DIRTY_TEMP_COEFFICIENT(minus_b); 05535 neg_assign(minus_b, b); 05536 const Coefficient& sc_b = is_sc ? b : minus_b; 05537 const Coefficient& minus_sc_b = is_sc ? minus_b : b; 05538 const Coefficient& sc_denom = is_sc ? denominator : minus_denom; 05539 const Coefficient& minus_sc_denom = is_sc ? minus_denom : denominator; 05540 // NOTE: here, for optimization purposes, `minus_expr' is only assigned 05541 // when `denominator' is negative. Do not use it unless you are sure 05542 // it has been correctly assigned. 05543 Linear_Expression minus_expr; 05544 if (!is_sc) 05545 minus_expr = -expr; 05546 const Linear_Expression& sc_expr = is_sc ? expr : minus_expr; 05547 05548 PPL_DIRTY_TEMP(N, sum); 05549 // Index of variable that is unbounded in `this->dbm'. 05550 PPL_UNINITIALIZED(dimension_type, pinf_index); 05551 // Number of unbounded variables found. 05552 dimension_type pinf_count = 0; 05553 05554 // Speculative allocation of temporaries to be used in the following loops. 05555 PPL_DIRTY_TEMP(N, coeff_i); 05556 PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i); 05557 05558 switch (relsym) { 05559 case LESS_OR_EQUAL: 05560 // Compute an upper approximation for `sc_expr' into `sum'. 05561 05562 // Approximate the inhomogeneous term. 05563 assign_r(sum, sc_b, ROUND_UP); 05564 // Approximate the homogeneous part of `sc_expr'. 05565 // Note: indices above `w' can be disregarded, as they all have 05566 // a zero coefficient in `sc_expr'. 05567 for (dimension_type i = w; i > 0; --i) { 05568 const Coefficient& sc_i = sc_expr.coefficient(Variable(i-1)); 05569 const int sign_i = sgn(sc_i); 05570 if (sign_i == 0) 05571 continue; 05572 // Choose carefully: we are approximating `sc_expr'. 05573 const N& approx_i = (sign_i > 0) ? dbm_0[i] : dbm[i][0]; 05574 if (is_plus_infinity(approx_i)) { 05575 if (++pinf_count > 1) 05576 break; 05577 pinf_index = i; 05578 continue; 05579 } 05580 if (sign_i > 0) 05581 assign_r(coeff_i, sc_i, ROUND_UP); 05582 else { 05583 neg_assign(minus_sc_i, sc_i); 05584 assign_r(coeff_i, minus_sc_i, ROUND_UP); 05585 } 05586 add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP); 05587 } 05588 05589 // Remove all constraints on `v'. 05590 forget_all_dbm_constraints(v); 05591 // Shortest-path closure is preserved, but not reduction. 05592 if (marked_shortest_path_reduced()) 05593 reset_shortest_path_reduced(); 05594 // Return immediately if no approximation could be computed. 05595 if (pinf_count > 1) { 05596 PPL_ASSERT(OK()); 05597 return; 05598 } 05599 05600 // Divide by the (sign corrected) denominator (if needed). 05601 if (sc_denom != 1) { 05602 // Before computing the quotient, the denominator should be approximated 05603 // towards zero. Since `sc_denom' is known to be positive, this amounts to 05604 // rounding downwards, which is achieved as usual by rounding upwards 05605 // `minus_sc_denom' and negating again the result. 05606 PPL_DIRTY_TEMP(N, down_sc_denom); 05607 assign_r(down_sc_denom, minus_sc_denom, ROUND_UP); 05608 neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP); 05609 div_assign_r(sum, sum, down_sc_denom, ROUND_UP); 05610 } 05611 05612 if (pinf_count == 0) { 05613 // Add the constraint `v <= sum'. 05614 add_dbm_constraint(0, v, sum); 05615 // Deduce constraints of the form `v - u', where `u != v'. 05616 deduce_v_minus_u_bounds(v, w, sc_expr, sc_denom, sum); 05617 } 05618 else if (pinf_count == 1) 05619 if (pinf_index != v 05620 && expr.coefficient(Variable(pinf_index-1)) == denominator) 05621 // Add the constraint `v - pinf_index <= sum'. 05622 add_dbm_constraint(pinf_index, v, sum); 05623 break; 05624 05625 case GREATER_OR_EQUAL: 05626 // Compute an upper approximation for `-sc_expr' into `sum'. 05627 // Note: approximating `-sc_expr' from above and then negating the 05628 // result is the same as approximating `sc_expr' from below. 05629 05630 // Approximate the inhomogeneous term. 05631 assign_r(sum, minus_sc_b, ROUND_UP); 05632 // Approximate the homogeneous part of `-sc_expr'. 05633 for (dimension_type i = expr_space_dim + 1; i > 0; --i) { 05634 const Coefficient& sc_i = sc_expr.coefficient(Variable(i-1)); 05635 const int sign_i = sgn(sc_i); 05636 if (sign_i == 0) 05637 continue; 05638 // Choose carefully: we are approximating `-sc_expr'. 05639 const N& approx_i = (sign_i > 0) ? dbm[i][0] : dbm_0[i]; 05640 if (is_plus_infinity(approx_i)) { 05641 if (++pinf_count > 1) 05642 break; 05643 pinf_index = i; 05644 continue; 05645 } 05646 if (sign_i > 0) 05647 assign_r(coeff_i, sc_i, ROUND_UP); 05648 else { 05649 neg_assign(minus_sc_i, sc_i); 05650 assign_r(coeff_i, minus_sc_i, ROUND_UP); 05651 } 05652 add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP); 05653 } 05654 05655 // Remove all constraints on `var'. 05656 forget_all_dbm_constraints(v); 05657 // Shortest-path closure is preserved, but not reduction. 05658 if (marked_shortest_path_reduced()) 05659 reset_shortest_path_reduced(); 05660 // Return immediately if no approximation could be computed. 05661 if (pinf_count > 1) { 05662 PPL_ASSERT(OK()); 05663 return; 05664 } 05665 05666 // Divide by the (sign corrected) denominator (if needed). 05667 if (sc_denom != 1) { 05668 // Before computing the quotient, the denominator should be approximated 05669 // towards zero. Since `sc_denom' is known to be positive, this amounts to 05670 // rounding downwards, which is achieved as usual by rounding upwards 05671 // `minus_sc_denom' and negating again the result. 05672 PPL_DIRTY_TEMP(N, down_sc_denom); 05673 assign_r(down_sc_denom, minus_sc_denom, ROUND_UP); 05674 neg_assign_r(down_sc_denom, down_sc_denom, ROUND_UP); 05675 div_assign_r(sum, sum, down_sc_denom, ROUND_UP); 05676 } 05677 05678 if (pinf_count == 0) { 05679 // Add the constraint `v >= -sum', i.e., `-v <= sum'. 05680 add_dbm_constraint(v, 0, sum); 05681 // Deduce constraints of the form `u - v', where `u != v'. 05682 deduce_u_minus_v_bounds(v, w, sc_expr, sc_denom, sum); 05683 } 05684 else if (pinf_count == 1) 05685 if (pinf_index != v 05686 && expr.coefficient(Variable(pinf_index-1)) == denominator) 05687 // Add the constraint `v - pinf_index >= -sum', 05688 // i.e., `pinf_index - v <= sum'. 05689 add_dbm_constraint(v, pinf_index, sum); 05690 break; 05691 05692 default: 05693 // We already dealt with the other cases. 05694 PPL_UNREACHABLE; 05695 break; 05696 } 05697 PPL_ASSERT(OK()); 05698 } 05699 05700 template <typename T> 05701 void 05702 BD_Shape<T>::generalized_affine_image(const Linear_Expression& lhs, 05703 const Relation_Symbol relsym, 05704 const Linear_Expression& rhs) { 05705 // Dimension-compatibility checks. 05706 // The dimension of `lhs' should not be greater than the dimension 05707 // of `*this'. 05708 const dimension_type space_dim = space_dimension(); 05709 const dimension_type lhs_space_dim = lhs.space_dimension(); 05710 if (space_dim < lhs_space_dim) 05711 throw_dimension_incompatible("generalized_affine_image(e1, r, e2)", 05712 "e1", lhs); 05713 05714 // The dimension of `rhs' should not be greater than the dimension 05715 // of `*this'. 05716 const dimension_type rhs_space_dim = rhs.space_dimension(); 05717 if (space_dim < rhs_space_dim) 05718 throw_dimension_incompatible("generalized_affine_image(e1, r, e2)", 05719 "e2", rhs); 05720 05721 // Strict relation symbols are not admitted for BDSs. 05722 if (relsym == LESS_THAN || relsym == GREATER_THAN) 05723 throw_invalid_argument("generalized_affine_image(e1, r, e2)", 05724 "r is a strict relation symbol"); 05725 // The relation symbol cannot be a disequality. 05726 if (relsym == NOT_EQUAL) 05727 throw_invalid_argument("generalized_affine_image(e1, r, e2)", 05728 "r is the disequality relation symbol"); 05729 05730 // The image of an empty BDS is empty. 05731 shortest_path_closure_assign(); 05732 if (marked_empty()) 05733 return; 05734 05735 // Number of non-zero coefficients in `lhs': will be set to 05736 // 0, 1, or 2, the latter value meaning any value greater than 1. 05737 dimension_type t_lhs = 0; 05738 // Index of the last non-zero coefficient in `lhs', if any. 05739 dimension_type j_lhs = 0; 05740 // Compute the number of the non-zero components of `lhs'. 05741 for (dimension_type i = lhs_space_dim; i-- > 0; ) 05742 if (lhs.coefficient(Variable(i)) != 0) { 05743 if (t_lhs++ == 1) 05744 break; 05745 else 05746 j_lhs = i; 05747 } 05748 05749 const Coefficient& b_lhs = lhs.inhomogeneous_term(); 05750 05751 if (t_lhs == 0) { 05752 // `lhs' is a constant. 05753 // In principle, it is sufficient to add the constraint `lhs relsym rhs'. 05754 // Note that this constraint is a bounded difference if `t_rhs <= 1' 05755 // or `t_rhs > 1' and `rhs == a*v - a*w + b_rhs'. If `rhs' is of a 05756 // more general form, it will be simply ignored. 05757 // TODO: if it is not a bounded difference, should we compute 05758 // approximations for this constraint? 05759 switch (relsym) { 05760 case LESS_OR_EQUAL: 05761 refine_no_check(lhs <= rhs); 05762 break; 05763 case EQUAL: 05764 refine_no_check(lhs == rhs); 05765 break; 05766 case GREATER_OR_EQUAL: 05767 refine_no_check(lhs >= rhs); 05768 break; 05769 default: 05770 // We already dealt with the other cases. 05771 PPL_UNREACHABLE; 05772 break; 05773 } 05774 } 05775 else if (t_lhs == 1) { 05776 // Here `lhs == a_lhs * v + b_lhs'. 05777 // Independently from the form of `rhs', we can exploit the 05778 // method computing generalized affine images for a single variable. 05779 Variable v(j_lhs); 05780 // Compute a sign-corrected relation symbol. 05781 const Coefficient& denom = lhs.coefficient(v); 05782 Relation_Symbol new_relsym = relsym; 05783 if (denom < 0) { 05784 if (relsym == LESS_OR_EQUAL) 05785 new_relsym = GREATER_OR_EQUAL; 05786 else if (relsym == GREATER_OR_EQUAL) 05787 new_relsym = LESS_OR_EQUAL; 05788 } 05789 Linear_Expression expr = rhs - b_lhs; 05790 generalized_affine_image(v, new_relsym, expr, denom); 05791 } 05792 else { 05793 // Here `lhs' is of the general form, having at least two variables. 05794 // Compute the set of variables occurring in `lhs'. 05795 bool lhs_vars_intersects_rhs_vars = false; 05796 std::vector<Variable> lhs_vars; 05797 for (dimension_type i = lhs_space_dim; i-- > 0; ) 05798 if (lhs.coefficient(Variable(i)) != 0) { 05799 lhs_vars.push_back(Variable(i)); 05800 if (rhs.coefficient(Variable(i)) != 0) 05801 lhs_vars_intersects_rhs_vars = true; 05802 } 05803 05804 if (!lhs_vars_intersects_rhs_vars) { 05805 // `lhs' and `rhs' variables are disjoint. 05806 // Existentially quantify all variables in the lhs. 05807 for (dimension_type i = lhs_vars.size(); i-- > 0; ) 05808 forget_all_dbm_constraints(lhs_vars[i].id() + 1); 05809 // Constrain the left hand side expression so that it is related to 05810 // the right hand side expression as dictated by `relsym'. 05811 // TODO: if the following constraint is NOT a bounded difference, 05812 // it will be simply ignored. Should we compute approximations for it? 05813 switch (relsym) { 05814 case LESS_OR_EQUAL: 05815 refine_no_check(lhs <= rhs); 05816 break; 05817 case EQUAL: 05818 refine_no_check(lhs == rhs); 05819 break; 05820 case GREATER_OR_EQUAL: 05821 refine_no_check(lhs >= rhs); 05822 break; 05823 default: 05824 // We already dealt with the other cases. 05825 PPL_UNREACHABLE; 05826 break; 05827 } 05828 } 05829 else { 05830 // Some variables in `lhs' also occur in `rhs'. 05831 05832 #if 1 // Simplified computation (see the TODO note below). 05833 05834 for (dimension_type i = lhs_vars.size(); i-- > 0; ) 05835 forget_all_dbm_constraints(lhs_vars[i].id() + 1); 05836 05837 #else // Currently unnecessarily complex computation. 05838 05839 // More accurate computation that is worth doing only if 05840 // the following TODO note is accurately dealt with. 05841 05842 // To ease the computation, we add an additional dimension. 05843 const Variable new_var(space_dim); 05844 add_space_dimensions_and_embed(1); 05845 // Constrain the new dimension to be equal to `rhs'. 05846 // NOTE: calling affine_image() instead of refine_no_check() 05847 // ensures some approximation is tried even when the constraint 05848 // is not a bounded difference. 05849 affine_image(new_var, rhs); 05850 // Existentially quantify all variables in the lhs. 05851 // NOTE: enforce shortest-path closure for precision. 05852 shortest_path_closure_assign(); 05853 PPL_ASSERT(!marked_empty()); 05854 for (dimension_type i = lhs_vars.size(); i-- > 0; ) 05855 forget_all_dbm_constraints(lhs_vars[i].id() + 1); 05856 // Constrain the new dimension so that it is related to 05857 // the left hand side as dictated by `relsym'. 05858 // TODO: each one of the following constraints is definitely NOT 05859 // a bounded differences (since it has 3 variables at least). 05860 // Thus, the method refine_no_check() will simply ignore it. 05861 // Should we compute approximations for this constraint? 05862 switch (relsym) { 05863 case LESS_OR_EQUAL: 05864 refine_no_check(lhs <= new_var); 05865 break; 05866 case EQUAL: 05867 refine_no_check(lhs == new_var); 05868 break; 05869 case GREATER_OR_EQUAL: 05870 refine_no_check(lhs >= new_var); 05871 break; 05872 default: 05873 // We already dealt with the other cases. 05874 PPL_UNREACHABLE; 05875 break; 05876 } 05877 // Remove the temporarily added dimension. 05878 remove_higher_space_dimensions(space_dim-1); 05879 #endif // Currently unnecessarily complex computation. 05880 } 05881 } 05882 05883 PPL_ASSERT(OK()); 05884 } 05885 05886 template <typename T> 05887 void 05888 BD_Shape<T>::generalized_affine_preimage(const Variable var, 05889 const Relation_Symbol relsym, 05890 const Linear_Expression& expr, 05891 Coefficient_traits::const_reference 05892 denominator) { 05893 // The denominator cannot be zero. 05894 if (denominator == 0) 05895 throw_invalid_argument("generalized_affine_preimage(v, r, e, d)", 05896 "d == 0"); 05897 05898 // Dimension-compatibility checks. 05899 // The dimension of `expr' should not be greater than the dimension 05900 // of `*this'. 05901 const dimension_type space_dim = space_dimension(); 05902 const dimension_type expr_space_dim = expr.space_dimension(); 05903 if (space_dim < expr_space_dim) 05904 throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)", 05905 "e", expr); 05906 05907 // `var' should be one of the dimensions of the BDS. 05908 const dimension_type v = var.id() + 1; 05909 if (v > space_dim) 05910 throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)", 05911 var.id()); 05912 05913 // The relation symbol cannot be a strict relation symbol. 05914 if (relsym == LESS_THAN || relsym == GREATER_THAN) 05915 throw_invalid_argument("generalized_affine_preimage(v, r, e, d)", 05916 "r is a strict relation symbol"); 05917 // The relation symbol cannot be a disequality. 05918 if (relsym == NOT_EQUAL) 05919 throw_invalid_argument("generalized_affine_preimage(v, r, e, d)", 05920 "r is the disequality relation symbol"); 05921 05922 if (relsym == EQUAL) { 05923 // The relation symbol is "=": 05924 // this is just an affine preimage computation. 05925 affine_preimage(var, expr, denominator); 05926 return; 05927 } 05928 05929 // The preimage of an empty BDS is empty too. 05930 shortest_path_closure_assign(); 05931 if (marked_empty()) 05932 return; 05933 05934 // Check whether the preimage of this affine relation can be easily 05935 // computed as the image of its inverse relation. 05936 const Coefficient& expr_v = expr.coefficient(var); 05937 if (expr_v != 0) { 05938 const Relation_Symbol reversed_relsym = (relsym == LESS_OR_EQUAL) 05939 ? GREATER_OR_EQUAL : LESS_OR_EQUAL; 05940 const Linear_Expression inverse 05941 = expr - (expr_v + denominator)*var; 05942 PPL_DIRTY_TEMP_COEFFICIENT(inverse_denom); 05943 neg_assign(inverse_denom, expr_v); 05944 const Relation_Symbol inverse_relsym 05945 = (sgn(denominator) == sgn(inverse_denom)) ? relsym : reversed_relsym; 05946 generalized_affine_image(var, inverse_relsym, inverse, inverse_denom); 05947 return; 05948 } 05949 05950 refine(var, relsym, expr, denominator); 05951 // If the shrunk BD_Shape is empty, its preimage is empty too; ... 05952 if (is_empty()) 05953 return; 05954 // ... otherwise, since the relation was not invertible, 05955 // we just forget all constraints on `v'. 05956 forget_all_dbm_constraints(v); 05957 // Shortest-path closure is preserved, but not reduction. 05958 if (marked_shortest_path_reduced()) 05959 reset_shortest_path_reduced(); 05960 PPL_ASSERT(OK()); 05961 } 05962 05963 template <typename T> 05964 void 05965 BD_Shape<T>::generalized_affine_preimage(const Linear_Expression& lhs, 05966 const Relation_Symbol relsym, 05967 const Linear_Expression& rhs) { 05968 // Dimension-compatibility checks. 05969 // The dimension of `lhs' should not be greater than the dimension 05970 // of `*this'. 05971 const dimension_type bds_space_dim = space_dimension(); 05972 const dimension_type lhs_space_dim = lhs.space_dimension(); 05973 if (bds_space_dim < lhs_space_dim) 05974 throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2)", 05975 "e1", lhs); 05976 05977 // The dimension of `rhs' should not be greater than the dimension 05978 // of `*this'. 05979 const dimension_type rhs_space_dim = rhs.space_dimension(); 05980 if (bds_space_dim < rhs_space_dim) 05981 throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2)", 05982 "e2", rhs); 05983 05984 // Strict relation symbols are not admitted for BDSs. 05985 if (relsym == LESS_THAN || relsym == GREATER_THAN) 05986 throw_invalid_argument("generalized_affine_preimage(e1, r, e2)", 05987 "r is a strict relation symbol"); 05988 // The relation symbol cannot be a disequality. 05989 if (relsym == NOT_EQUAL) 05990 throw_invalid_argument("generalized_affine_preimage(e1, r, e2)", 05991 "r is the disequality relation symbol"); 05992 05993 // The preimage of an empty BDS is empty. 05994 shortest_path_closure_assign(); 05995 if (marked_empty()) 05996 return; 05997 05998 // Number of non-zero coefficients in `lhs': will be set to 05999 // 0, 1, or 2, the latter value meaning any value greater than 1. 06000 dimension_type t_lhs = 0; 06001 // Index of the last non-zero coefficient in `lhs', if any. 06002 dimension_type j_lhs = 0; 06003 // Compute the number of the non-zero components of `lhs'. 06004 for (dimension_type i = lhs_space_dim; i-- > 0; ) 06005 if (lhs.coefficient(Variable(i)) != 0) { 06006 if (t_lhs++ == 1) 06007 break; 06008 else 06009 j_lhs = i; 06010 } 06011 06012 const Coefficient& b_lhs = lhs.inhomogeneous_term(); 06013 06014 if (t_lhs == 0) { 06015 // `lhs' is a constant. 06016 // In this case, preimage and image happen to be the same. 06017 generalized_affine_image(lhs, relsym, rhs); 06018 return; 06019 } 06020 else if (t_lhs == 1) { 06021 // Here `lhs == a_lhs * v + b_lhs'. 06022 // Independently from the form of `rhs', we can exploit the 06023 // method computing generalized affine preimages for a single variable. 06024 Variable v(j_lhs); 06025 // Compute a sign-corrected relation symbol. 06026 const Coefficient& denom = lhs.coefficient(v); 06027 Relation_Symbol new_relsym = relsym; 06028 if (denom < 0) { 06029 if (relsym == LESS_OR_EQUAL) 06030 new_relsym = GREATER_OR_EQUAL; 06031 else if (relsym == GREATER_OR_EQUAL) 06032 new_relsym = LESS_OR_EQUAL; 06033 } 06034 Linear_Expression expr = rhs - b_lhs; 06035 generalized_affine_preimage(v, new_relsym, expr, denom); 06036 } 06037 else { 06038 // Here `lhs' is of the general form, having at least two variables. 06039 // Compute the set of variables occurring in `lhs'. 06040 bool lhs_vars_intersects_rhs_vars = false; 06041 std::vector<Variable> lhs_vars; 06042 for (dimension_type i = lhs_space_dim; i-- > 0; ) 06043 if (lhs.coefficient(Variable(i)) != 0) { 06044 lhs_vars.push_back(Variable(i)); 06045 if (rhs.coefficient(Variable(i)) != 0) 06046 lhs_vars_intersects_rhs_vars = true; 06047 } 06048 06049 if (!lhs_vars_intersects_rhs_vars) { 06050 // `lhs' and `rhs' variables are disjoint. 06051 06052 // Constrain the left hand side expression so that it is related to 06053 // the right hand side expression as dictated by `relsym'. 06054 // TODO: if the following constraint is NOT a bounded difference, 06055 // it will be simply ignored. Should we compute approximations for it? 06056 switch (relsym) { 06057 case LESS_OR_EQUAL: 06058 refine_no_check(lhs <= rhs); 06059 break; 06060 case EQUAL: 06061 refine_no_check(lhs == rhs); 06062 break; 06063 case GREATER_OR_EQUAL: 06064 refine_no_check(lhs >= rhs); 06065 break; 06066 default: 06067 // We already dealt with the other cases. 06068 PPL_UNREACHABLE; 06069 break; 06070 } 06071 06072 // If the shrunk BD_Shape is empty, its preimage is empty too; ... 06073 if (is_empty()) 06074 return; 06075 // Existentially quantify all variables in the lhs. 06076 for (dimension_type i = lhs_vars.size(); i-- > 0; ) 06077 forget_all_dbm_constraints(lhs_vars[i].id() + 1); 06078 } 06079 else { 06080 06081 // Some variables in `lhs' also occur in `rhs'. 06082 // To ease the computation, we add an additional dimension. 06083 const Variable new_var(bds_space_dim); 06084 add_space_dimensions_and_embed(1); 06085 // Constrain the new dimension to be equal to `lhs'. 06086 // NOTE: calling affine_image() instead of refine_no_check() 06087 // ensures some approximation is tried even when the constraint 06088 // is not a bounded difference. 06089 affine_image(new_var, lhs); 06090 // Existentiallly quantify all variables in the lhs. 06091 // NOTE: enforce shortest-path closure for precision. 06092 shortest_path_closure_assign(); 06093 PPL_ASSERT(!marked_empty()); 06094 for (dimension_type i = lhs_vars.size(); i-- > 0; ) 06095 forget_all_dbm_constraints(lhs_vars[i].id() + 1); 06096 // Constrain the new dimension so that it is related to 06097 // the left hand side as dictated by `relsym'. 06098 // Note: if `rhs == a_rhs*v + b_rhs' where `a_rhs' is in {0, 1}, 06099 // then one of the following constraints will be added, 06100 // since it is a bounded difference. Else the method 06101 // refine_no_check() will ignore it, because the 06102 // constraint is NOT a bounded difference. 06103 switch (relsym) { 06104 case LESS_OR_EQUAL: 06105 refine_no_check(new_var <= rhs); 06106 break; 06107 case EQUAL: 06108 refine_no_check(new_var == rhs); 06109 break; 06110 case GREATER_OR_EQUAL: 06111 refine_no_check(new_var >= rhs); 06112 break; 06113 default: 06114 // We already dealt with the other cases. 06115 PPL_UNREACHABLE; 06116 break; 06117 } 06118 // Remove the temporarily added dimension. 06119 remove_higher_space_dimensions(bds_space_dim); 06120 } 06121 } 06122 06123 PPL_ASSERT(OK()); 06124 } 06125 06126 template <typename T> 06127 Constraint_System 06128 BD_Shape<T>::constraints() const { 06129 Constraint_System cs; 06130 const dimension_type space_dim = space_dimension(); 06131 if (space_dim == 0) { 06132 if (marked_empty()) 06133 cs = Constraint_System::zero_dim_empty(); 06134 } 06135 else if (marked_empty()) 06136 cs.insert(0*Variable(space_dim-1) <= -1); 06137 else if (marked_shortest_path_reduced()) 06138 // Disregard redundant constraints. 06139 cs = minimized_constraints(); 06140 else { 06141 // KLUDGE: in the future `cs' will be constructed of the right dimension. 06142 // For the time being, we force the dimension with the following line. 06143 cs.insert(0*Variable(space_dim-1) <= 0); 06144 06145 PPL_DIRTY_TEMP_COEFFICIENT(a); 06146 PPL_DIRTY_TEMP_COEFFICIENT(b); 06147 // Go through all the unary constraints in `dbm'. 06148 const DB_Row<N>& dbm_0 = dbm[0]; 06149 for (dimension_type j = 1; j <= space_dim; ++j) { 06150 const Variable x(j-1); 06151 const N& dbm_0j = dbm_0[j]; 06152 const N& dbm_j0 = dbm[j][0]; 06153 if (is_additive_inverse(dbm_j0, dbm_0j)) { 06154 // We have a unary equality constraint. 06155 numer_denom(dbm_0j, b, a); 06156 cs.insert(a*x == b); 06157 } 06158 else { 06159 // We have 0, 1 or 2 unary inequality constraints. 06160 if (!is_plus_infinity(dbm_0j)) { 06161 numer_denom(dbm_0j, b, a); 06162 cs.insert(a*x <= b); 06163 } 06164 if (!is_plus_infinity(dbm_j0)) { 06165 numer_denom(dbm_j0, b, a); 06166 cs.insert(-a*x <= b); 06167 } 06168 } 06169 } 06170 06171 // Go through all the binary constraints in `dbm'. 06172 for (dimension_type i = 1; i <= space_dim; ++i) { 06173 const Variable y(i-1); 06174 const DB_Row<N>& dbm_i = dbm[i]; 06175 for (dimension_type j = i + 1; j <= space_dim; ++j) { 06176 const Variable x(j-1); 06177 const N& dbm_ij = dbm_i[j]; 06178 const N& dbm_ji = dbm[j][i]; 06179 if (is_additive_inverse(dbm_ji, dbm_ij)) { 06180 // We have a binary equality constraint. 06181 numer_denom(dbm_ij, b, a); 06182 cs.insert(a*x - a*y == b); 06183 } 06184 else { 06185 // We have 0, 1 or 2 binary inequality constraints. 06186 if (!is_plus_infinity(dbm_ij)) { 06187 numer_denom(dbm_ij, b, a); 06188 cs.insert(a*x - a*y <= b); 06189 } 06190 if (!is_plus_infinity(dbm_ji)) { 06191 numer_denom(dbm_ji, b, a); 06192 cs.insert(a*y - a*x <= b); 06193 } 06194 } 06195 } 06196 } 06197 } 06198 return cs; 06199 } 06200 06201 template <typename T> 06202 Constraint_System 06203 BD_Shape<T>::minimized_constraints() const { 06204 shortest_path_reduction_assign(); 06205 Constraint_System cs; 06206 const dimension_type space_dim = space_dimension(); 06207 if (space_dim == 0) { 06208 if (marked_empty()) 06209 cs = Constraint_System::zero_dim_empty(); 06210 } 06211 else if (marked_empty()) 06212 cs.insert(0*Variable(space_dim-1) <= -1); 06213 else { 06214 // KLUDGE: in the future `cs' will be constructed of the right dimension. 06215 // For the time being, we force the dimension with the following line. 06216 cs.insert(0*Variable(space_dim-1) <= 0); 06217 06218 PPL_DIRTY_TEMP_COEFFICIENT(numer); 06219 PPL_DIRTY_TEMP_COEFFICIENT(denom); 06220 06221 // Compute leader information. 06222 std::vector<dimension_type> leaders; 06223 compute_leaders(leaders); 06224 std::vector<dimension_type> leader_indices; 06225 compute_leader_indices(leaders, leader_indices); 06226 const dimension_type num_leaders = leader_indices.size(); 06227 06228 // Go through the non-leaders to generate equality constraints. 06229 const DB_Row<N>& dbm_0 = dbm[0]; 06230 for (dimension_type i = 1; i <= space_dim; ++i) { 06231 const dimension_type leader = leaders[i]; 06232 if (i != leader) { 06233 // Generate the constraint relating `i' and its leader. 06234 if (leader == 0) { 06235 // A unary equality has to be generated. 06236 PPL_ASSERT(!is_plus_infinity(dbm_0[i])); 06237 numer_denom(dbm_0[i], numer, denom); 06238 cs.insert(denom*Variable(i-1) == numer); 06239 } 06240 else { 06241 // A binary equality has to be generated. 06242 PPL_ASSERT(!is_plus_infinity(dbm[i][leader])); 06243 numer_denom(dbm[i][leader], numer, denom); 06244 cs.insert(denom*Variable(leader-1) - denom*Variable(i-1) == numer); 06245 } 06246 } 06247 } 06248 06249 // Go through the leaders to generate inequality constraints. 06250 // First generate all the unary inequalities. 06251 const Bit_Row& red_0 = redundancy_dbm[0]; 06252 for (dimension_type l_i = 1; l_i < num_leaders; ++l_i) { 06253 const dimension_type i = leader_indices[l_i]; 06254 if (!red_0[i]) { 06255 numer_denom(dbm_0[i], numer, denom); 06256 cs.insert(denom*Variable(i-1) <= numer); 06257 } 06258 if (!redundancy_dbm[i][0]) { 06259 numer_denom(dbm[i][0], numer, denom); 06260 cs.insert(-denom*Variable(i-1) <= numer); 06261 } 06262 } 06263 // Then generate all the binary inequalities. 06264 for (dimension_type l_i = 1; l_i < num_leaders; ++l_i) { 06265 const dimension_type i = leader_indices[l_i]; 06266 const DB_Row<N>& dbm_i = dbm[i]; 06267 const Bit_Row& red_i = redundancy_dbm[i]; 06268 for (dimension_type l_j = l_i + 1; l_j < num_leaders; ++l_j) { 06269 const dimension_type j = leader_indices[l_j]; 06270 if (!red_i[j]) { 06271 numer_denom(dbm_i[j], numer, denom); 06272 cs.insert(denom*Variable(j-1) - denom*Variable(i-1) <= numer); 06273 } 06274 if (!redundancy_dbm[j][i]) { 06275 numer_denom(dbm[j][i], numer, denom); 06276 cs.insert(denom*Variable(i-1) - denom*Variable(j-1) <= numer); 06277 } 06278 } 06279 } 06280 } 06281 return cs; 06282 } 06283 06284 template <typename T> 06285 void 06286 BD_Shape<T>::expand_space_dimension(Variable var, dimension_type m) { 06287 dimension_type old_dim = space_dimension(); 06288 // `var' should be one of the dimensions of the vector space. 06289 if (var.space_dimension() > old_dim) 06290 throw_dimension_incompatible("expand_space_dimension(v, m)", "v", var); 06291 06292 // The space dimension of the resulting BDS should not 06293 // overflow the maximum allowed space dimension. 06294 if (m > max_space_dimension() - space_dimension()) 06295 throw_invalid_argument("expand_dimension(v, m)", 06296 "adding m new space dimensions exceeds " 06297 "the maximum allowed space dimension"); 06298 06299 // Nothing to do, if no dimensions must be added. 06300 if (m == 0) 06301 return; 06302 06303 // Add the required new dimensions. 06304 add_space_dimensions_and_embed(m); 06305 06306 // For each constraints involving variable `var', we add a 06307 // similar constraint with the new variable substituted for 06308 // variable `var'. 06309 const dimension_type v_id = var.id() + 1; 06310 const DB_Row<N>& dbm_v = dbm[v_id]; 06311 for (dimension_type i = old_dim + 1; i-- > 0; ) { 06312 DB_Row<N>& dbm_i = dbm[i]; 06313 const N& dbm_i_v = dbm[i][v_id]; 06314 const N& dbm_v_i = dbm_v[i]; 06315 for (dimension_type j = old_dim+1; j < old_dim+m+1; ++j) { 06316 dbm_i[j] = dbm_i_v; 06317 dbm[j][i] = dbm_v_i; 06318 } 06319 } 06320 // In general, adding a constraint does not preserve the shortest-path 06321 // closure or reduction of the bounded difference shape. 06322 if (marked_shortest_path_closed()) 06323 reset_shortest_path_closed(); 06324 PPL_ASSERT(OK()); 06325 } 06326 06327 template <typename T> 06328 void 06329 BD_Shape<T>::fold_space_dimensions(const Variables_Set& vars, 06330 Variable dest) { 06331 const dimension_type space_dim = space_dimension(); 06332 // `dest' should be one of the dimensions of the BDS. 06333 if (dest.space_dimension() > space_dim) 06334 throw_dimension_incompatible("fold_space_dimensions(vs, v)", 06335 "v", dest); 06336 06337 // The folding of no dimensions is a no-op. 06338 if (vars.empty()) 06339 return; 06340 06341 // All variables in `vars' should be dimensions of the BDS. 06342 if (vars.space_dimension() > space_dim) 06343 throw_dimension_incompatible("fold_space_dimensions(vs, v)", 06344 vars.space_dimension()); 06345 06346 // Moreover, `dest.id()' should not occur in `vars'. 06347 if (vars.find(dest.id()) != vars.end()) 06348 throw_invalid_argument("fold_space_dimensions(vs, v)", 06349 "v should not occur in vs"); 06350 06351 shortest_path_closure_assign(); 06352 if (!marked_empty()) { 06353 // Recompute the elements of the row and the column corresponding 06354 // to variable `dest' by taking the join of their value with the 06355 // value of the corresponding elements in the row and column of the 06356 // variable `vars'. 06357 const dimension_type v_id = dest.id() + 1; 06358 DB_Row<N>& dbm_v = dbm[v_id]; 06359 for (Variables_Set::const_iterator i = vars.begin(), 06360 vs_end = vars.end(); i != vs_end; ++i) { 06361 const dimension_type to_be_folded_id = *i + 1; 06362 const DB_Row<N>& dbm_to_be_folded_id = dbm[to_be_folded_id]; 06363 for (dimension_type j = space_dim + 1; j-- > 0; ) { 06364 max_assign(dbm[j][v_id], dbm[j][to_be_folded_id]); 06365 max_assign(dbm_v[j], dbm_to_be_folded_id[j]); 06366 } 06367 } 06368 } 06369 remove_space_dimensions(vars); 06370 } 06371 06372 template <typename T> 06373 void 06374 BD_Shape<T>::drop_some_non_integer_points(Complexity_Class) { 06375 if (std::numeric_limits<T>::is_integer) 06376 return; 06377 06378 const dimension_type space_dim = space_dimension(); 06379 shortest_path_closure_assign(); 06380 if (space_dim == 0 || marked_empty()) 06381 return; 06382 06383 for (dimension_type i = space_dim + 1; i-- > 0; ) { 06384 DB_Row<N>& dbm_i = dbm[i]; 06385 for (dimension_type j = space_dim + 1; j-- > 0; ) 06386 if (i != j) 06387 drop_some_non_integer_points_helper(dbm_i[j]); 06388 } 06389 PPL_ASSERT(OK()); 06390 } 06391 06392 template <typename T> 06393 void 06394 BD_Shape<T>::drop_some_non_integer_points(const Variables_Set& vars, 06395 Complexity_Class) { 06396 // Dimension-compatibility check. 06397 const dimension_type space_dim = space_dimension(); 06398 const dimension_type min_space_dim = vars.space_dimension(); 06399 if (space_dim < min_space_dim) 06400 throw_dimension_incompatible("drop_some_non_integer_points(vs, cmpl)", 06401 min_space_dim); 06402 06403 if (std::numeric_limits<T>::is_integer || min_space_dim == 0) 06404 return; 06405 06406 shortest_path_closure_assign(); 06407 if (marked_empty()) 06408 return; 06409 06410 const Variables_Set::const_iterator v_begin = vars.begin(); 06411 const Variables_Set::const_iterator v_end = vars.end(); 06412 PPL_ASSERT(v_begin != v_end); 06413 // Unary constraints on a variable occurring in `vars'. 06414 DB_Row<N>& dbm_0 = dbm[0]; 06415 for (Variables_Set::const_iterator v_i = v_begin; v_i != v_end; ++v_i) { 06416 const dimension_type i = *v_i + 1; 06417 drop_some_non_integer_points_helper(dbm_0[i]); 06418 drop_some_non_integer_points_helper(dbm[i][0]); 06419 } 06420 06421 // Binary constraints where both variables occur in `vars'. 06422 for (Variables_Set::const_iterator v_i = v_begin; v_i != v_end; ++v_i) { 06423 const dimension_type i = *v_i + 1; 06424 DB_Row<N>& dbm_i = dbm[i]; 06425 for (Variables_Set::const_iterator v_j = v_begin; v_j != v_end; ++v_j) { 06426 const dimension_type j = *v_j + 1; 06427 if (i != j) 06428 drop_some_non_integer_points_helper(dbm_i[j]); 06429 } 06430 } 06431 PPL_ASSERT(OK()); 06432 } 06433 06435 template <typename T> 06436 std::ostream& 06437 IO_Operators::operator<<(std::ostream& s, const BD_Shape<T>& bds) { 06438 typedef typename BD_Shape<T>::coefficient_type N; 06439 if (bds.is_universe()) 06440 s << "true"; 06441 else { 06442 // We control empty bounded difference shape. 06443 dimension_type n = bds.space_dimension(); 06444 if (bds.marked_empty()) 06445 s << "false"; 06446 else { 06447 PPL_DIRTY_TEMP(N, v); 06448 bool first = true; 06449 for (dimension_type i = 0; i <= n; ++i) 06450 for (dimension_type j = i + 1; j <= n; ++j) { 06451 const N& c_i_j = bds.dbm[i][j]; 06452 const N& c_j_i = bds.dbm[j][i]; 06453 if (is_additive_inverse(c_j_i, c_i_j)) { 06454 // We will print an equality. 06455 if (first) 06456 first = false; 06457 else 06458 s << ", "; 06459 if (i == 0) { 06460 // We have got a equality constraint with one variable. 06461 s << Variable(j - 1); 06462 s << " = " << c_i_j; 06463 } 06464 else { 06465 // We have got a equality constraint with two variables. 06466 if (sgn(c_i_j) >= 0) { 06467 s << Variable(j - 1); 06468 s << " - "; 06469 s << Variable(i - 1); 06470 s << " = " << c_i_j; 06471 } 06472 else { 06473 s << Variable(i - 1); 06474 s << " - "; 06475 s << Variable(j - 1); 06476 s << " = " << c_j_i; 06477 } 06478 } 06479 } 06480 else { 06481 // We will print a non-strict inequality. 06482 if (!is_plus_infinity(c_j_i)) { 06483 if (first) 06484 first = false; 06485 else 06486 s << ", "; 06487 if (i == 0) { 06488 // We have got a constraint with only one variable. 06489 s << Variable(j - 1); 06490 neg_assign_r(v, c_j_i, ROUND_DOWN); 06491 s << " >= " << v; 06492 } 06493 else { 06494 // We have got a constraint with two variables. 06495 if (sgn(c_j_i) >= 0) { 06496 s << Variable(i - 1); 06497 s << " - "; 06498 s << Variable(j - 1); 06499 s << " <= " << c_j_i; 06500 } 06501 else { 06502 s << Variable(j - 1); 06503 s << " - "; 06504 s << Variable(i - 1); 06505 neg_assign_r(v, c_j_i, ROUND_DOWN); 06506 s << " >= " << v; 06507 } 06508 } 06509 } 06510 if (!is_plus_infinity(c_i_j)) { 06511 if (first) 06512 first = false; 06513 else 06514 s << ", "; 06515 if (i == 0) { 06516 // We have got a constraint with only one variable. 06517 s << Variable(j - 1); 06518 s << " <= " << c_i_j; 06519 } 06520 else { 06521 // We have got a constraint with two variables. 06522 if (sgn(c_i_j) >= 0) { 06523 s << Variable(j - 1); 06524 s << " - "; 06525 s << Variable(i - 1); 06526 s << " <= " << c_i_j; 06527 } 06528 else { 06529 s << Variable(i - 1); 06530 s << " - "; 06531 s << Variable(j - 1); 06532 neg_assign_r(v, c_i_j, ROUND_DOWN); 06533 s << " >= " << v; 06534 } 06535 } 06536 } 06537 } 06538 } 06539 } 06540 } 06541 return s; 06542 } 06543 06544 template <typename T> 06545 void 06546 BD_Shape<T>::ascii_dump(std::ostream& s) const { 06547 status.ascii_dump(s); 06548 s << "\n"; 06549 dbm.ascii_dump(s); 06550 s << "\n"; 06551 redundancy_dbm.ascii_dump(s); 06552 } 06553 06554 PPL_OUTPUT_TEMPLATE_DEFINITIONS(T, BD_Shape<T>) 06555 06556 template <typename T> 06557 bool 06558 BD_Shape<T>::ascii_load(std::istream& s) { 06559 if (!status.ascii_load(s)) 06560 return false; 06561 if (!dbm.ascii_load(s)) 06562 return false; 06563 if (!redundancy_dbm.ascii_load(s)) 06564 return false; 06565 return true; 06566 } 06567 06568 template <typename T> 06569 memory_size_type 06570 BD_Shape<T>::external_memory_in_bytes() const { 06571 return dbm.external_memory_in_bytes() 06572 + redundancy_dbm.external_memory_in_bytes(); 06573 } 06574 06575 template <typename T> 06576 bool 06577 BD_Shape<T>::OK() const { 06578 // Check whether the difference-bound matrix is well-formed. 06579 if (!dbm.OK()) 06580 return false; 06581 06582 // Check whether the status information is legal. 06583 if (!status.OK()) 06584 return false; 06585 06586 // An empty BDS is OK. 06587 if (marked_empty()) 06588 return true; 06589 06590 // MINUS_INFINITY cannot occur at all. 06591 for (dimension_type i = dbm.num_rows(); i-- > 0; ) 06592 for (dimension_type j = dbm.num_rows(); j-- > 0; ) 06593 if (is_minus_infinity(dbm[i][j])) { 06594 #ifndef NDEBUG 06595 using namespace Parma_Polyhedra_Library::IO_Operators; 06596 std::cerr << "BD_Shape::dbm[" << i << "][" << j << "] = " 06597 << dbm[i][j] << "!" 06598 << std::endl; 06599 #endif 06600 return false; 06601 } 06602 06603 // On the main diagonal only PLUS_INFINITY can occur. 06604 for (dimension_type i = dbm.num_rows(); i-- > 0; ) 06605 if (!is_plus_infinity(dbm[i][i])) { 06606 #ifndef NDEBUG 06607 using namespace Parma_Polyhedra_Library::IO_Operators; 06608 std::cerr << "BD_Shape::dbm[" << i << "][" << i << "] = " 06609 << dbm[i][i] << "! (+inf was expected.)" 06610 << std::endl; 06611 #endif 06612 return false; 06613 } 06614 06615 // Check whether the shortest-path closure information is legal. 06616 if (marked_shortest_path_closed()) { 06617 BD_Shape x = *this; 06618 x.reset_shortest_path_closed(); 06619 x.shortest_path_closure_assign(); 06620 if (x.dbm != dbm) { 06621 #ifndef NDEBUG 06622 std::cerr << "BD_Shape is marked as closed but it is not!" 06623 << std::endl; 06624 #endif 06625 return false; 06626 } 06627 } 06628 06629 // The following tests might result in false alarms when using floating 06630 // point coefficients: they are only meaningful if the coefficient type 06631 // base is exact (since otherwise shortest-path closure is approximated). 06632 if (std::numeric_limits<coefficient_type_base>::is_exact) { 06633 06634 // Check whether the shortest-path reduction information is legal. 06635 if (marked_shortest_path_reduced()) { 06636 // A non-redundant constraint cannot be equal to PLUS_INFINITY. 06637 for (dimension_type i = dbm.num_rows(); i-- > 0; ) 06638 for (dimension_type j = dbm.num_rows(); j-- > 0; ) 06639 if (!redundancy_dbm[i][j] && is_plus_infinity(dbm[i][j])) { 06640 #ifndef NDEBUG 06641 using namespace Parma_Polyhedra_Library::IO_Operators; 06642 std::cerr << "BD_Shape::dbm[" << i << "][" << j << "] = " 06643 << dbm[i][j] << " is marked as non-redundant!" 06644 << std::endl; 06645 #endif 06646 return false; 06647 } 06648 06649 BD_Shape x = *this; 06650 x.reset_shortest_path_reduced(); 06651 x.shortest_path_reduction_assign(); 06652 if (x.redundancy_dbm != redundancy_dbm) { 06653 #ifndef NDEBUG 06654 std::cerr << "BD_Shape is marked as reduced but it is not!" 06655 << std::endl; 06656 #endif 06657 return false; 06658 } 06659 } 06660 } 06661 06662 // All checks passed. 06663 return true; 06664 } 06665 06666 template <typename T> 06667 void 06668 BD_Shape<T>::throw_dimension_incompatible(const char* method, 06669 const BD_Shape& y) const { 06670 std::ostringstream s; 06671 s << "PPL::BD_Shape::" << method << ":" << std::endl 06672 << "this->space_dimension() == " << space_dimension() 06673 << ", y->space_dimension() == " << y.space_dimension() << "."; 06674 throw std::invalid_argument(s.str()); 06675 } 06676 06677 template <typename T> 06678 void 06679 BD_Shape<T>::throw_dimension_incompatible(const char* method, 06680 dimension_type required_dim) const { 06681 std::ostringstream s; 06682 s << "PPL::BD_Shape::" << method << ":" << std::endl 06683 << "this->space_dimension() == " << space_dimension() 06684 << ", required dimension == " << required_dim << "."; 06685 throw std::invalid_argument(s.str()); 06686 } 06687 06688 template <typename T> 06689 void 06690 BD_Shape<T>::throw_dimension_incompatible(const char* method, 06691 const Constraint& c) const { 06692 std::ostringstream s; 06693 s << "PPL::BD_Shape::" << method << ":" << std::endl 06694 << "this->space_dimension() == " << space_dimension() 06695 << ", c->space_dimension == " << c.space_dimension() << "."; 06696 throw std::invalid_argument(s.str()); 06697 } 06698 06699 template <typename T> 06700 void 06701 BD_Shape<T>::throw_dimension_incompatible(const char* method, 06702 const Congruence& cg) const { 06703 std::ostringstream s; 06704 s << "PPL::BD_Shape::" << method << ":" << std::endl 06705 << "this->space_dimension() == " << space_dimension() 06706 << ", cg->space_dimension == " << cg.space_dimension() << "."; 06707 throw std::invalid_argument(s.str()); 06708 } 06709 06710 template <typename T> 06711 void 06712 BD_Shape<T>::throw_dimension_incompatible(const char* method, 06713 const Generator& g) const { 06714 std::ostringstream s; 06715 s << "PPL::BD_Shape::" << method << ":" << std::endl 06716 << "this->space_dimension() == " << space_dimension() 06717 << ", g->space_dimension == " << g.space_dimension() << "."; 06718 throw std::invalid_argument(s.str()); 06719 } 06720 06721 template <typename T> 06722 void 06723 BD_Shape<T>::throw_expression_too_complex(const char* method, 06724 const Linear_Expression& le) { 06725 using namespace IO_Operators; 06726 std::ostringstream s; 06727 s << "PPL::BD_Shape::" << method << ":" << std::endl 06728 << le << " is too complex."; 06729 throw std::invalid_argument(s.str()); 06730 } 06731 06732 06733 template <typename T> 06734 void 06735 BD_Shape<T>::throw_dimension_incompatible(const char* method, 06736 const char* le_name, 06737 const Linear_Expression& le) const { 06738 std::ostringstream s; 06739 s << "PPL::BD_Shape::" << method << ":" << std::endl 06740 << "this->space_dimension() == " << space_dimension() 06741 << ", " << le_name << "->space_dimension() == " 06742 << le.space_dimension() << "."; 06743 throw std::invalid_argument(s.str()); 06744 } 06745 06746 template <typename T> 06747 template<typename Interval_Info> 06748 void 06749 BD_Shape<T>::throw_dimension_incompatible(const char* method, 06750 const char* lf_name, 06751 const Linear_Form< Interval<T, 06752 Interval_Info> >& lf) const { 06753 std::ostringstream s; 06754 s << "PPL::BD_Shape::" << method << ":" << std::endl 06755 << "this->space_dimension() == " << space_dimension() 06756 << ", " << lf_name << "->space_dimension() == " 06757 << lf.space_dimension() << "."; 06758 throw std::invalid_argument(s.str()); 06759 } 06760 06761 template <typename T> 06762 void 06763 BD_Shape<T>::throw_invalid_argument(const char* method, const char* reason) { 06764 std::ostringstream s; 06765 s << "PPL::BD_Shape::" << method << ":" << std::endl 06766 << reason << "."; 06767 throw std::invalid_argument(s.str()); 06768 } 06769 06770 } // namespace Parma_Polyhedra_Library 06771 06772 #endif // !defined(PPL_BD_Shape_templates_hh)