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