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