PPL  0.12.1
Polyhedron_widenings.cc
Go to the documentation of this file.
00001 /* Polyhedron class implementation
00002    (non-inline widening-related member functions).
00003    Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
00004    Copyright (C) 2010-2012 BUGSENG srl (http://bugseng.com)
00005 
00006 This file is part of the Parma Polyhedra Library (PPL).
00007 
00008 The PPL is free software; you can redistribute it and/or modify it
00009 under the terms of the GNU General Public License as published by the
00010 Free Software Foundation; either version 3 of the License, or (at your
00011 option) any later version.
00012 
00013 The PPL is distributed in the hope that it will be useful, but WITHOUT
00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00015 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016 for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with this program; if not, write to the Free Software Foundation,
00020 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
00021 
00022 For the most up-to-date information see the Parma Polyhedra Library
00023 site: http://bugseng.com/products/ppl/ . */
00024 
00025 #include "ppl-config.h"
00026 #include "Polyhedron.defs.hh"
00027 #include "BHRZ03_Certificate.defs.hh"
00028 #include "Rational_Box.hh"
00029 #include "Scalar_Products.defs.hh"
00030 #include "assert.hh"
00031 #include <iostream>
00032 #include <stdexcept>
00033 #include <deque>
00034 
00035 namespace PPL = Parma_Polyhedra_Library;
00036 
00037 void
00038 PPL::Polyhedron
00039 ::select_CH78_constraints(const Polyhedron& y,
00040                           Constraint_System& cs_selection) const {
00041   // Private method: the caller must ensure the following conditions.
00042   PPL_ASSERT(topology() == y.topology()
00043          && topology() == cs_selection.topology()
00044          && space_dim == y.space_dim);
00045   PPL_ASSERT(!marked_empty()
00046          && !has_pending_constraints()
00047          && generators_are_up_to_date());
00048   PPL_ASSERT(!y.marked_empty()
00049          && !y.has_something_pending()
00050          && y.constraints_are_minimized());
00051 
00052   // A constraint in `y.con_sys' is copied to `cs_selection'
00053   // if it is satisfied by all the generators of `gen_sys'.
00054 
00055   // Note: the loop index `i' goes upward to avoid reversing
00056   // the ordering of the chosen constraints.
00057   for (dimension_type i = 0, end = y.con_sys.num_rows(); i < end; ++i) {
00058     const Constraint& c = y.con_sys[i];
00059     if (gen_sys.satisfied_by_all_generators(c))
00060       cs_selection.insert(c);
00061   }
00062 }
00063 
00064 void
00065 PPL::Polyhedron
00066 ::select_H79_constraints(const Polyhedron& y,
00067                          Constraint_System& cs_selected,
00068                          Constraint_System& cs_not_selected) const {
00069   // Private method: the caller must ensure the following conditions
00070   // (beside the inclusion `y <= x').
00071   PPL_ASSERT(topology() == y.topology()
00072          && topology() == cs_selected.topology()
00073          && topology() == cs_not_selected.topology());
00074   PPL_ASSERT(space_dim == y.space_dim);
00075   PPL_ASSERT(!marked_empty()
00076          && !has_pending_generators()
00077          && constraints_are_up_to_date());
00078   PPL_ASSERT(!y.marked_empty()
00079          && !y.has_something_pending()
00080          && y.constraints_are_minimized()
00081          && y.generators_are_up_to_date());
00082 
00083   // FIXME: this is a workaround for NNC polyhedra.
00084   if (!y.is_necessarily_closed()) {
00085     // Force strong minimization of constraints.
00086     y.strongly_minimize_constraints();
00087     // Recompute generators (without compromising constraint minimization).
00088     y.update_generators();
00089   }
00090 
00091   // Obtain a sorted copy of `y.sat_g'.
00092   if (!y.sat_g_is_up_to_date())
00093     y.update_sat_g();
00094   Bit_Matrix tmp_sat_g = y.sat_g;
00095   // Remove from `tmp_sat_g' the rows corresponding to tautologies
00096   // (i.e., the positivity or epsilon-bounding constraints):
00097   // this is needed in order to widen the polyhedron and not the
00098   // corresponding homogenized polyhedral cone.
00099   const Constraint_System& y_cs = y.con_sys;
00100   const dimension_type old_num_rows = y_cs.num_rows();
00101   dimension_type num_rows = old_num_rows;
00102   for (dimension_type i = 0; i < num_rows; ++i)
00103     if (y_cs[i].is_tautological()) {
00104       using std::swap;
00105       --num_rows;
00106       swap(tmp_sat_g[i], tmp_sat_g[num_rows]);
00107     }
00108   tmp_sat_g.remove_trailing_rows(old_num_rows - num_rows);
00109   tmp_sat_g.sort_rows();
00110 
00111   // A constraint in `con_sys' is copied to `cs_selected'
00112   // if its behavior with respect to `y.gen_sys' is the same
00113   // as that of another constraint in `y.con_sys'.
00114   // otherwise it is copied to `cs_not_selected'.
00115   // Namely, we check whether the saturation row `buffer'
00116   // (built starting from the given constraint and `y.gen_sys')
00117   // is a row of the saturation matrix `tmp_sat_g'.
00118 
00119   // CHECKME: the following comment is only applicable when `y.gen_sys'
00120   // is minimized. In that case, the comment suggests that it would be
00121   // possible to use a fast (but incomplete) redundancy test based on
00122   // the number of saturators in `buffer'.
00123   // NOTE: If the considered constraint of `con_sys' does not
00124   // satisfy the saturation rule (see Section \ref prelims), then
00125   // it will not appear in the resulting constraint system,
00126   // because `tmp_sat_g' is built starting from a minimized polyhedron.
00127 
00128   // The size of `buffer' will reach sat.num_columns() bits.
00129   Bit_Row buffer;
00130   // Note: the loop index `i' goes upward to avoid reversing
00131   // the ordering of the chosen constraints.
00132   for (dimension_type i = 0, end = con_sys.num_rows(); i < end; ++i) {
00133     const Constraint& ci = con_sys[i];
00134     // The saturation row `buffer' is built considering
00135     // the `i'-th constraint of the polyhedron `x' and
00136     // all the generators of the polyhedron `y'.
00137     buffer.clear();
00138     for (dimension_type j = y.gen_sys.num_rows(); j-- > 0; ) {
00139       const int sp_sgn = Scalar_Products::sign(ci, y.gen_sys[j]);
00140       // We are assuming that `y <= x'.
00141       PPL_ASSERT(sp_sgn >= 0
00142              || (!is_necessarily_closed()
00143                  && ci.is_strict_inequality()
00144                  && y.gen_sys[j].is_point()));
00145       if (sp_sgn > 0)
00146         buffer.set(j);
00147     }
00148     // We check whether `buffer' is a row of `tmp_sat_g',
00149     // exploiting its sortedness in order to have faster comparisons.
00150     if (tmp_sat_g.sorted_contains(buffer))
00151       cs_selected.insert(ci);
00152     else
00153       cs_not_selected.insert(ci);
00154   }
00155 }
00156 
00157 void
00158 PPL::Polyhedron::H79_widening_assign(const Polyhedron& y, unsigned* tp) {
00159   Polyhedron& x = *this;
00160   // Topology compatibility check.
00161   const Topology topol = x.topology();
00162   if (topol != y.topology())
00163     throw_topology_incompatible("H79_widening_assign(y)", "y", y);
00164   // Dimension-compatibility check.
00165   if (x.space_dim != y.space_dim)
00166     throw_dimension_incompatible("H79_widening_assign(y)", "y", y);
00167 
00168   // Assume `y' is contained in or equal to `x'.
00169   PPL_EXPECT_HEAVY(copy_contains(x, y));
00170 
00171   // If any argument is zero-dimensional or empty,
00172   // the H79-widening behaves as the identity function.
00173   if (x.space_dim == 0 || x.marked_empty() || y.marked_empty())
00174     return;
00175 
00176   // `y.gen_sys' should be in minimal form and
00177   // `y.sat_g' should be up-to-date.
00178   if (y.is_necessarily_closed()) {
00179     if (!y.minimize())
00180       // `y' is empty: the result is `x'.
00181       return;
00182   }
00183   else {
00184     // Dealing with a NNC polyhedron.
00185     // To obtain a correct reasoning when comparing
00186     // the constraints of `x' with the generators of `y',
00187     // we enforce the inclusion relation holding between
00188     // the two NNC polyhedra `x' and `y' (i.e., `y <= x')
00189     // to also hold for the corresponding eps-representations:
00190     // this is obtained by intersecting the two eps-representations.
00191     Polyhedron& yy = const_cast<Polyhedron&>(y);
00192     yy.intersection_assign(x);
00193     if (yy.is_empty())
00194       // The result is `x'.
00195       return;
00196   }
00197 
00198   // If we only have the generators of `x' and the dimensions of
00199   // the two polyhedra are the same, we can compute the standard
00200   // widening by using the specification in [CousotH78], therefore
00201   // avoiding converting from generators to constraints.
00202   if (x.has_pending_generators() || !x.constraints_are_up_to_date()) {
00203     Constraint_System CH78_cs(topol);
00204     x.select_CH78_constraints(y, CH78_cs);
00205 
00206     if (CH78_cs.num_rows() == y.con_sys.num_rows()) {
00207       // Having selected all the constraints, the result is `y'.
00208       x = y;
00209       return;
00210     }
00211     // Otherwise, check if `x' and `y' have the same dimension.
00212     // Note that `y.con_sys' is minimized and `CH78_cs' has no redundant
00213     // constraints, since it is a subset of the former.
00214     else if (CH78_cs.num_equalities() == y.con_sys.num_equalities()) {
00215       // Let `x' be defined by the constraints in `CH78_cs'.
00216       Polyhedron CH78(topol, x.space_dim, UNIVERSE);
00217       CH78.add_recycled_constraints(CH78_cs);
00218 
00219       // Check whether we are using the widening-with-tokens technique
00220       // and there still are tokens available.
00221       if (tp != 0 && *tp > 0) {
00222         // There are tokens available. If `CH78' is not a subset of `x',
00223         // then it is less precise and we use one of the available tokens.
00224         if (!x.contains(CH78))
00225           --(*tp);
00226       }
00227       else
00228         // No tokens.
00229         x.m_swap(CH78);
00230       PPL_ASSERT_HEAVY(x.OK(true));
00231       return;
00232     }
00233   }
00234 
00235   // As the dimension of `x' is strictly greater than the dimension of `y',
00236   // we have to compute the standard widening by selecting a subset of
00237   // the constraints of `x'.
00238   // `x.con_sys' is just required to be up-to-date, because:
00239   // - if `x.con_sys' is unsatisfiable, then by assumption
00240   //   also `y' is empty, so that the resulting polyhedron is `x';
00241   // - redundant constraints in `x.con_sys' do not affect the result
00242   //   of the widening, because if they are selected they will be
00243   //   redundant even in the result.
00244   if (has_pending_generators())
00245     process_pending_generators();
00246   else if (!x.constraints_are_up_to_date())
00247     x.update_constraints();
00248 
00249   // Copy into `H79_cs' the constraints of `x' that are common to `y',
00250   // according to the definition of the H79 widening.
00251   Constraint_System H79_cs(topol);
00252   Constraint_System x_minus_H79_cs(topol);
00253   x.select_H79_constraints(y, H79_cs, x_minus_H79_cs);
00254 
00255   if (x_minus_H79_cs.has_no_rows())
00256     // We selected all of the constraints of `x',
00257     // thus the result of the widening is `x'.
00258     return;
00259   else {
00260     // We selected a strict subset of the constraints of `x'.
00261     // NOTE: as `x.con_sys' was not necessarily in minimal form,
00262     // this does not imply that the result strictly includes `x'.
00263     // Let `H79' be defined by the constraints in `H79_cs'.
00264     Polyhedron H79(topol, x.space_dim, UNIVERSE);
00265     H79.add_recycled_constraints(H79_cs);
00266 
00267     // Check whether we are using the widening-with-tokens technique
00268     // and there still are tokens available.
00269     if (tp != 0 && *tp > 0) {
00270       // There are tokens available. If `H79' is not a subset of `x',
00271       // then it is less precise and we use one of the available tokens.
00272       if (!x.contains(H79))
00273         --(*tp);
00274     }
00275     else
00276       // No tokens.
00277       x.m_swap(H79);
00278     PPL_ASSERT_HEAVY(x.OK(true));
00279   }
00280 }
00281 
00282 void
00283 PPL::Polyhedron::limited_H79_extrapolation_assign(const Polyhedron& y,
00284                                                   const Constraint_System& cs,
00285                                                   unsigned* tp) {
00286   Polyhedron& x = *this;
00287 
00288   const dimension_type cs_num_rows = cs.num_rows();
00289   // If `cs' is empty, we fall back to ordinary, non-limited widening.
00290   if (cs_num_rows == 0) {
00291     x.H79_widening_assign(y, tp);
00292     return;
00293   }
00294 
00295   // Topology compatibility check.
00296   if (x.is_necessarily_closed()) {
00297     if (!y.is_necessarily_closed())
00298       throw_topology_incompatible("limited_H79_extrapolation_assign(y, cs)",
00299                                   "y", y);
00300     if (cs.has_strict_inequalities())
00301       throw_topology_incompatible("limited_H79_extrapolation_assign(y, cs)",
00302                                   "cs", cs);
00303   }
00304   else if (y.is_necessarily_closed())
00305     throw_topology_incompatible("limited_H79_extrapolation_assign(y, cs)",
00306                                 "y", y);
00307 
00308   // Dimension-compatibility check.
00309   if (x.space_dim != y.space_dim)
00310     throw_dimension_incompatible("limited_H79_extrapolation_assign(y, cs)",
00311                                  "y", y);
00312   // `cs' must be dimension-compatible with the two polyhedra.
00313   const dimension_type cs_space_dim = cs.space_dimension();
00314   if (x.space_dim < cs_space_dim)
00315     throw_dimension_incompatible("limited_H79_extrapolation_assign(y, cs)",
00316                                  "cs", cs);
00317 
00318   // Assume `y' is contained in or equal to `x'.
00319   PPL_EXPECT_HEAVY(copy_contains(x, y));
00320 
00321   if (y.marked_empty())
00322     return;
00323   if (x.marked_empty())
00324     return;
00325 
00326   // The limited H79-widening between two polyhedra in a
00327   // zero-dimensional space is a polyhedron in a zero-dimensional
00328   // space, too.
00329   if (x.space_dim == 0)
00330     return;
00331 
00332   if (!y.minimize())
00333     // We have just discovered that `y' is empty.
00334     return;
00335 
00336   // Update the generators of `x': these are used to select,
00337   // from the constraints in `cs', those that must be added
00338   // to the resulting polyhedron.
00339   if ((x.has_pending_constraints() && !x.process_pending_constraints())
00340       || (!x.generators_are_up_to_date() && !x.update_generators()))
00341     // We have just discovered that `x' is empty.
00342     return;
00343 
00344   Constraint_System new_cs;
00345   // The constraints to be added must be satisfied by all the
00346   // generators of `x'.  We can disregard `y' because `y <= x'.
00347   const Generator_System& x_gen_sys = x.gen_sys;
00348   // Iterate upwards here so as to keep the relative ordering of constraints.
00349   // Not really an issue: just aesthetics.
00350   for (dimension_type i = 0; i < cs_num_rows; ++i) {
00351     const Constraint& c = cs[i];
00352     if (x_gen_sys.satisfied_by_all_generators(c))
00353       new_cs.insert(c);
00354   }
00355   x.H79_widening_assign(y, tp);
00356   x.add_recycled_constraints(new_cs);
00357   PPL_ASSERT_HEAVY(OK());
00358 }
00359 
00360 void
00361 PPL::Polyhedron::bounded_H79_extrapolation_assign(const Polyhedron& y,
00362                                                   const Constraint_System& cs,
00363                                                   unsigned* tp) {
00364   Rational_Box x_box(*this, ANY_COMPLEXITY);
00365   Rational_Box y_box(y, ANY_COMPLEXITY);
00366   x_box.CC76_widening_assign(y_box);
00367   limited_H79_extrapolation_assign(y, cs, tp);
00368   Constraint_System x_box_cs = x_box.constraints();
00369   add_recycled_constraints(x_box_cs);
00370 }
00371 
00372 bool
00373 PPL::Polyhedron
00374 ::BHRZ03_combining_constraints(const Polyhedron& y,
00375                                const BHRZ03_Certificate& y_cert,
00376                                const Polyhedron& H79,
00377                                const Constraint_System& x_minus_H79_cs) {
00378   Polyhedron& x = *this;
00379   // It is assumed that `y <= x <= H79'.
00380   PPL_ASSERT(x.topology() == y.topology()
00381          && x.topology() == H79.topology()
00382          && x.topology() == x_minus_H79_cs.topology());
00383   PPL_ASSERT(x.space_dim == y.space_dim
00384          && x.space_dim == H79.space_dim
00385          && x.space_dim == x_minus_H79_cs.space_dimension());
00386   PPL_ASSERT(!x.marked_empty() && !x.has_something_pending()
00387          && x.constraints_are_minimized() && x.generators_are_minimized());
00388   PPL_ASSERT(!y.marked_empty() && !y.has_something_pending()
00389          && y.constraints_are_minimized() && y.generators_are_minimized());
00390   PPL_ASSERT(!H79.marked_empty() && !H79.has_something_pending()
00391          && H79.constraints_are_minimized() && H79.generators_are_minimized());
00392 
00393   // We will choose from `x_minus_H79_cs' many subsets of constraints,
00394   // that will be collected (one at a time) in `combining_cs'.
00395   // For each group collected, we compute an average constraint,
00396   // that will be stored in `new_cs'.
00397 
00398   // There is no point in applying this technique when `x_minus_H79_cs'
00399   // has one constraint at most (no ``new'' constraint can be computed).
00400   const dimension_type x_minus_H79_cs_num_rows = x_minus_H79_cs.num_rows();
00401   if (x_minus_H79_cs_num_rows <= 1)
00402     return false;
00403 
00404   const Topology topol = x.topology();
00405   Constraint_System combining_cs(topol);
00406   Constraint_System new_cs(topol);
00407 
00408   // Consider the points that belong to both `x.gen_sys' and `y.gen_sys'.
00409   // For NNC polyhedra, the role of points is played by closure points.
00410   const bool closed = x.is_necessarily_closed();
00411   for (dimension_type i = y.gen_sys.num_rows(); i-- > 0; ) {
00412     const Generator& g = y.gen_sys[i];
00413     if ((g.is_point() && closed) || (g.is_closure_point() && !closed)) {
00414       // If in `H79.con_sys' there is already an inequality constraint
00415       // saturating this point, then there is no need to produce another
00416       // constraint.
00417       bool lies_on_the_boundary_of_H79 = false;
00418       const Constraint_System& H79_cs = H79.con_sys;
00419       for (dimension_type j = H79_cs.num_rows(); j-- > 0; ) {
00420         const Constraint& c = H79_cs[j];
00421         if (c.is_inequality() && Scalar_Products::sign(c, g) == 0) {
00422           lies_on_the_boundary_of_H79 = true;
00423           break;
00424         }
00425       }
00426       if (lies_on_the_boundary_of_H79)
00427         continue;
00428 
00429       // Consider all the constraints in `x_minus_H79_cs'
00430       // that are saturated by the point `g'.
00431       combining_cs.clear();
00432       for (dimension_type j = x_minus_H79_cs_num_rows; j-- > 0; ) {
00433         const Constraint& c = x_minus_H79_cs[j];
00434         if (Scalar_Products::sign(c, g) == 0)
00435           combining_cs.insert(c);
00436       }
00437       // Build a new constraint by combining all the chosen constraints.
00438       const dimension_type combining_cs_num_rows = combining_cs.num_rows();
00439       if (combining_cs_num_rows > 0) {
00440         if (combining_cs_num_rows == 1)
00441           // No combination is needed.
00442           new_cs.insert(combining_cs[0]);
00443         else {
00444           Linear_Expression e(0);
00445           bool strict_inequality = false;
00446           for (dimension_type h = combining_cs_num_rows; h-- > 0; ) {
00447             if (combining_cs[h].is_strict_inequality())
00448               strict_inequality = true;
00449             e += Linear_Expression(combining_cs[h]);
00450           }
00451 
00452           if (!e.all_homogeneous_terms_are_zero()) {
00453             if (strict_inequality)
00454               new_cs.insert(e > 0);
00455             else
00456               new_cs.insert(e >= 0);
00457           }
00458         }
00459       }
00460     }
00461   }
00462 
00463   // If none of the collected constraints strictly intersects `H79',
00464   // then the technique was unsuccessful.
00465   bool improves_upon_H79 = false;
00466   const Poly_Con_Relation si = Poly_Con_Relation::strictly_intersects();
00467   for (dimension_type i = new_cs.num_rows(); i-- > 0; )
00468     if (H79.relation_with(new_cs[i]) == si) {
00469       improves_upon_H79 = true;
00470       break;
00471     }
00472   if (!improves_upon_H79)
00473     return false;
00474 
00475   // The resulting polyhedron is obtained by adding the constraints
00476   // in `new_cs' to polyhedron `H79'.
00477   Polyhedron result = H79;
00478   result.add_recycled_constraints(new_cs);
00479   // Force minimization.
00480   result.minimize();
00481 
00482   // Check for stabilization with respect to `y_cert' and improvement
00483   // over `H79'.
00484   if (y_cert.is_stabilizing(result) && !result.contains(H79)) {
00485     // The technique was successful.
00486     x.m_swap(result);
00487     PPL_ASSERT_HEAVY(x.OK(true));
00488     return true;
00489   }
00490   else
00491     // The technique was unsuccessful.
00492     return false;
00493 }
00494 
00495 bool
00496 PPL::Polyhedron::BHRZ03_evolving_points(const Polyhedron& y,
00497                                         const BHRZ03_Certificate& y_cert,
00498                                         const Polyhedron& H79) {
00499   Polyhedron& x = *this;
00500   // It is assumed that `y <= x <= H79'.
00501   PPL_ASSERT(x.topology() == y.topology()
00502          && x.topology() == H79.topology());
00503   PPL_ASSERT(x.space_dim == y.space_dim
00504          && x.space_dim == H79.space_dim);
00505   PPL_ASSERT(!x.marked_empty() && !x.has_something_pending()
00506          && x.constraints_are_minimized() && x.generators_are_minimized());
00507   PPL_ASSERT(!y.marked_empty() && !y.has_something_pending()
00508          && y.constraints_are_minimized() && y.generators_are_minimized());
00509   PPL_ASSERT(!H79.marked_empty() && !H79.has_something_pending()
00510          && H79.constraints_are_minimized() && H79.generators_are_minimized());
00511 
00512   // For each point in `x.gen_sys' that is not in `y',
00513   // this technique tries to identify a set of rays that:
00514   //  - are included in polyhedron `H79';
00515   //  - when added to `y' will subsume the point.
00516   Generator_System candidate_rays;
00517 
00518   const dimension_type x_gen_sys_num_rows = x.gen_sys.num_rows();
00519   const dimension_type y_gen_sys_num_rows = y.gen_sys.num_rows();
00520   const bool closed = x.is_necessarily_closed();
00521   for (dimension_type i = x_gen_sys_num_rows; i-- > 0; ) {
00522     Generator& g1 = x.gen_sys[i];
00523     // For C polyhedra, we choose a point of `x.gen_sys'
00524     // that is not included in `y'.
00525     // In the case of NNC polyhedra, we can restrict attention to
00526     // closure points (considering also points will only add redundancy).
00527     if (((g1.is_point() && closed) || (g1.is_closure_point() && !closed))
00528         && y.relation_with(g1) == Poly_Gen_Relation::nothing()) {
00529       // For each point (resp., closure point) `g2' in `y.gen_sys',
00530       // where `g1' and `g2' are different,
00531       // build the candidate ray `g1 - g2'.
00532       for (dimension_type j = y_gen_sys_num_rows; j-- > 0; ) {
00533         const Generator& g2 = y.gen_sys[j];
00534         if ((g2.is_point() && closed)
00535             || (g2.is_closure_point() && !closed)) {
00536           PPL_ASSERT(compare(g1, g2) != 0);
00537           Generator ray_from_g2_to_g1 = g1;
00538           ray_from_g2_to_g1.linear_combine(g2, 0);
00539           candidate_rays.insert(ray_from_g2_to_g1);
00540         }
00541       }
00542     }
00543   }
00544 
00545   // Be non-intrusive.
00546   Polyhedron result = x;
00547   result.add_recycled_generators(candidate_rays);
00548   result.intersection_assign(H79);
00549   // Force minimization.
00550   result.minimize();
00551 
00552   // Check for stabilization with respect to `y_cert' and improvement
00553   // over `H79'.
00554   if (y_cert.is_stabilizing(result) && !result.contains(H79)) {
00555     // The technique was successful.
00556     x.m_swap(result);
00557     PPL_ASSERT_HEAVY(x.OK(true));
00558     return true;
00559   }
00560   else
00561     // The technique was unsuccessful.
00562     return false;
00563 }
00564 
00565 bool
00566 PPL::Polyhedron::BHRZ03_evolving_rays(const Polyhedron& y,
00567                                       const BHRZ03_Certificate& y_cert,
00568                                       const Polyhedron& H79) {
00569   Polyhedron& x = *this;
00570   // It is assumed that `y <= x <= H79'.
00571   PPL_ASSERT(x.topology() == y.topology()
00572          && x.topology() == H79.topology());
00573   PPL_ASSERT(x.space_dim == y.space_dim
00574          && x.space_dim == H79.space_dim);
00575   PPL_ASSERT(!x.marked_empty() && !x.has_something_pending()
00576          && x.constraints_are_minimized() && x.generators_are_minimized());
00577   PPL_ASSERT(!y.marked_empty() && !y.has_something_pending()
00578          && y.constraints_are_minimized() && y.generators_are_minimized());
00579   PPL_ASSERT(!H79.marked_empty() && !H79.has_something_pending()
00580          && H79.constraints_are_minimized() && H79.generators_are_minimized());
00581 
00582   const dimension_type x_gen_sys_num_rows = x.gen_sys.num_rows();
00583   const dimension_type y_gen_sys_num_rows = y.gen_sys.num_rows();
00584 
00585   // Candidate rays are kept in a temporary generator system.
00586   Generator_System candidate_rays;
00587   PPL_DIRTY_TEMP_COEFFICIENT(tmp);
00588   for (dimension_type i = x_gen_sys_num_rows; i-- > 0; ) {
00589     const Generator& x_g = x.gen_sys[i];
00590     // We choose a ray of `x' that does not belong to `y'.
00591     if (x_g.is_ray() && y.relation_with(x_g) == Poly_Gen_Relation::nothing()) {
00592       for (dimension_type j = y_gen_sys_num_rows; j-- > 0; ) {
00593         const Generator& y_g = y.gen_sys[j];
00594         if (y_g.is_ray()) {
00595           Generator new_ray(x_g);
00596           // Modify `new_ray' according to the evolution of `x_g' with
00597           // respect to `y_g'.
00598           std::deque<bool> considered(x.space_dim + 1);
00599           for (dimension_type k = 1; k < x.space_dim; ++k)
00600             if (!considered[k])
00601               for (dimension_type h = k + 1; h <= x.space_dim; ++h)
00602                 if (!considered[h]) {
00603                   tmp = x_g[k] * y_g[h];
00604                   // The following line optimizes the computation of
00605                   // <CODE> tmp -= x_g[h] * y_g[k]; </CODE>
00606                   sub_mul_assign(tmp, x_g[h], y_g[k]);
00607                   const int clockwise
00608                     = sgn(tmp);
00609                   const int first_or_third_quadrant
00610                     = sgn(x_g[k]) * sgn(x_g[h]);
00611                   switch (clockwise * first_or_third_quadrant) {
00612                   case -1:
00613                     new_ray[k] = 0;
00614                     considered[k] = true;
00615                     break;
00616                   case 1:
00617                     new_ray[h] = 0;
00618                     considered[h] = true;
00619                     break;
00620                   default:
00621                     break;
00622                   }
00623                 }
00624           new_ray.normalize();
00625           candidate_rays.insert(new_ray);
00626         }
00627       }
00628     }
00629   }
00630 
00631   // If there are no candidate rays, we cannot obtain stabilization.
00632   if (candidate_rays.has_no_rows())
00633     return false;
00634 
00635   // Be non-intrusive.
00636   Polyhedron result = x;
00637   result.add_recycled_generators(candidate_rays);
00638   result.intersection_assign(H79);
00639   // Force minimization.
00640   result.minimize();
00641 
00642   // Check for stabilization with respect to `y' and improvement over `H79'.
00643   if (y_cert.is_stabilizing(result) && !result.contains(H79)) {
00644     // The technique was successful.
00645     x.m_swap(result);
00646     PPL_ASSERT_HEAVY(x.OK(true));
00647     return true;
00648   }
00649   else
00650     // The technique was unsuccessful.
00651     return false;
00652 }
00653 
00654 void
00655 PPL::Polyhedron::BHRZ03_widening_assign(const Polyhedron& y, unsigned* tp) {
00656   Polyhedron& x = *this;
00657   // Topology compatibility check.
00658   if (x.topology() != y.topology())
00659     throw_topology_incompatible("BHRZ03_widening_assign(y)", "y", y);
00660   // Dimension-compatibility check.
00661   if (x.space_dim != y.space_dim)
00662     throw_dimension_incompatible("BHRZ03_widening_assign(y)", "y", y);
00663 
00664   // Assume `y' is contained in or equal to `x'.
00665   PPL_EXPECT_HEAVY(copy_contains(x, y));
00666 
00667   // If any argument is zero-dimensional or empty,
00668   // the BHRZ03-widening behaves as the identity function.
00669   if (x.space_dim == 0 || x.marked_empty() || y.marked_empty())
00670     return;
00671 
00672   // `y.con_sys' and `y.gen_sys' should be in minimal form.
00673   if (!y.minimize())
00674     // `y' is empty: the result is `x'.
00675     return;
00676   // `x.con_sys' and `x.gen_sys' should be in minimal form.
00677   x.minimize();
00678 
00679   // Compute certificate info for polyhedron `y'.
00680   BHRZ03_Certificate y_cert(y);
00681 
00682   // If the iteration is stabilizing, the resulting polyhedron is `x'.
00683   // At this point, also check if the two polyhedra are the same
00684   // (exploiting the knowledge that `y <= x').
00685   if (y_cert.is_stabilizing(x) || y.contains(x)) {
00686     PPL_ASSERT_HEAVY(OK());
00687     return;
00688   }
00689 
00690   // Here the iteration is not immediately stabilizing.
00691   // If we are using the widening-with-tokens technique and
00692   // there are tokens available, use one of them and return `x'.
00693   if (tp != 0 && *tp > 0) {
00694     --(*tp);
00695     PPL_ASSERT_HEAVY(OK());
00696     return;
00697   }
00698 
00699   // Copy into `H79_cs' the constraints that are common to `x' and `y',
00700   // according to the definition of the H79 widening.
00701   // The other ones are copied into `x_minus_H79_cs'.
00702   const Topology topol = x.topology();
00703   Constraint_System H79_cs(topol);
00704   Constraint_System x_minus_H79_cs(topol);
00705   x.select_H79_constraints(y, H79_cs, x_minus_H79_cs);
00706 
00707   // We cannot have selected all of the rows, since otherwise
00708   // the iteration should have been immediately stabilizing.
00709   PPL_ASSERT(!x_minus_H79_cs.has_no_rows());
00710   // Be careful to obtain the right space dimension
00711   // (because `H79_cs' may be empty).
00712   Polyhedron H79(topol, x.space_dim, UNIVERSE);
00713   H79.add_recycled_constraints(H79_cs);
00714   // Force minimization.
00715   H79.minimize();
00716 
00717   // NOTE: none of the following widening heuristics is intrusive:
00718   // they will modify `x' only when returning successfully.
00719   if (x.BHRZ03_combining_constraints(y, y_cert, H79, x_minus_H79_cs))
00720     return;
00721 
00722   PPL_ASSERT_HEAVY(H79.OK() && x.OK() && y.OK());
00723 
00724   if (x.BHRZ03_evolving_points(y, y_cert, H79))
00725     return;
00726 
00727   PPL_ASSERT_HEAVY(H79.OK() && x.OK() && y.OK());
00728 
00729   if (x.BHRZ03_evolving_rays(y, y_cert, H79))
00730     return;
00731 
00732   PPL_ASSERT_HEAVY(H79.OK() && x.OK() && y.OK());
00733 
00734   // No previous technique was successful: fall back to the H79 widening.
00735   x.m_swap(H79);
00736   PPL_ASSERT_HEAVY(x.OK(true));
00737 
00738   // The H79 widening is always stabilizing.
00739   PPL_ASSERT(y_cert.is_stabilizing(x));
00740 }
00741 
00742 void
00743 PPL::Polyhedron
00744 ::limited_BHRZ03_extrapolation_assign(const Polyhedron& y,
00745                                       const Constraint_System& cs,
00746                                       unsigned* tp) {
00747   Polyhedron& x = *this;
00748   const dimension_type cs_num_rows = cs.num_rows();
00749   // If `cs' is empty, we fall back to ordinary, non-limited widening.
00750   if (cs_num_rows == 0) {
00751     x.BHRZ03_widening_assign(y, tp);
00752     return;
00753   }
00754 
00755   // Topology compatibility check.
00756   if (x.is_necessarily_closed()) {
00757     if (!y.is_necessarily_closed())
00758       throw_topology_incompatible("limited_BHRZ03_extrapolation_assign(y, cs)",
00759                                   "y", y);
00760     if (cs.has_strict_inequalities())
00761       throw_topology_incompatible("limited_BHRZ03_extrapolation_assign(y, cs)",
00762                                   "cs", cs);
00763   }
00764   else if (y.is_necessarily_closed())
00765     throw_topology_incompatible("limited_BHRZ03_extrapolation_assign(y, cs)",
00766                                 "y", y);
00767 
00768   // Dimension-compatibility check.
00769   if (x.space_dim != y.space_dim)
00770     throw_dimension_incompatible("limited_BHRZ03_extrapolation_assign(y, cs)",
00771                                  "y", y);
00772   // `cs' must be dimension-compatible with the two polyhedra.
00773   const dimension_type cs_space_dim = cs.space_dimension();
00774   if (x.space_dim < cs_space_dim)
00775     throw_dimension_incompatible("limited_BHRZ03_extrapolation_assign(y, cs)",
00776                                  "cs", cs);
00777 
00778   // Assume `y' is contained in or equal to `x'.
00779   PPL_EXPECT_HEAVY(copy_contains(x, y));
00780 
00781   if (y.marked_empty())
00782     return;
00783   if (x.marked_empty())
00784     return;
00785 
00786   // The limited BHRZ03-widening between two polyhedra in a
00787   // zero-dimensional space is a polyhedron in a zero-dimensional
00788   // space, too.
00789   if (x.space_dim == 0)
00790     return;
00791 
00792   if (!y.minimize())
00793     // We have just discovered that `y' is empty.
00794     return;
00795 
00796   // Update the generators of `x': these are used to select,
00797   // from the constraints in `cs', those that must be added
00798   // to the resulting polyhedron.
00799   if ((x.has_pending_constraints() && !x.process_pending_constraints())
00800       || (!x.generators_are_up_to_date() && !x.update_generators()))
00801     // We have just discovered that `x' is empty.
00802     return;
00803 
00804   Constraint_System new_cs;
00805   // The constraints to be added must be satisfied by all the
00806   // generators of `x'. We can disregard `y' because `y <= x'.
00807   const Generator_System& x_gen_sys = x.gen_sys;
00808   // Iterate upwards here so as to keep the relative ordering of constraints.
00809   // Not really an issue: just aesthetics.
00810   for (dimension_type i = 0; i < cs_num_rows; ++i) {
00811     const Constraint& c = cs[i];
00812     if (x_gen_sys.satisfied_by_all_generators(c))
00813       new_cs.insert(c);
00814   }
00815   x.BHRZ03_widening_assign(y, tp);
00816   x.add_recycled_constraints(new_cs);
00817   PPL_ASSERT_HEAVY(OK());
00818 }
00819 
00820 void
00821 PPL::Polyhedron
00822 ::bounded_BHRZ03_extrapolation_assign(const Polyhedron& y,
00823                                       const Constraint_System& cs,
00824                                       unsigned* tp) {
00825   Rational_Box x_box(*this, ANY_COMPLEXITY);
00826   Rational_Box y_box(y, ANY_COMPLEXITY);
00827   x_box.CC76_widening_assign(y_box);
00828   limited_BHRZ03_extrapolation_assign(y, cs, tp);
00829   Constraint_System x_box_cs = x_box.constraints();
00830   add_recycled_constraints(x_box_cs);
00831 }