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