PPL  0.12.1
Octagonal_Shape.templates.hh
Go to the documentation of this file.
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.