PPL  0.12.1
Polyhedron_public.cc
Go to the documentation of this file.
00001 /* Polyhedron class implementation (non-inline public 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 #include "ppl-config.h"
00025 #include "Polyhedron.defs.hh"
00026 #include "C_Polyhedron.defs.hh"
00027 #include "NNC_Polyhedron.defs.hh"
00028 #include "Scalar_Products.defs.hh"
00029 #include "MIP_Problem.defs.hh"
00030 #include "wrap_assign.hh"
00031 #include "assert.hh"
00032 #include <cstdlib>
00033 #include <iostream>
00034 
00035 #ifndef ENSURE_SORTEDNESS
00036 #define ENSURE_SORTEDNESS 0
00037 #endif
00038 
00039 namespace PPL = Parma_Polyhedra_Library;
00040 
00041 PPL::dimension_type* PPL::Polyhedron::simplify_num_saturators_p = 0;
00042 
00043 size_t PPL::Polyhedron::simplify_num_saturators_size = 0;
00044 
00045 void
00046 PPL::Polyhedron::initialize() {
00047   PPL_ASSERT(simplify_num_saturators_p == 0);
00048   PPL_ASSERT(simplify_num_saturators_size == 0);
00049   simplify_num_saturators_p = new dimension_type[simplify_num_saturators_size];
00050 }
00051 
00052 void
00053 PPL::Polyhedron::finalize() {
00054   delete [] simplify_num_saturators_p;
00055   simplify_num_saturators_p = 0;
00056   simplify_num_saturators_size = 0;
00057 }
00058 
00059 PPL::dimension_type
00060 PPL::Polyhedron::affine_dimension() const {
00061   if (is_empty())
00062     return 0;
00063 
00064   const Constraint_System& cs = minimized_constraints();
00065   dimension_type d = space_dim;
00066   for (Constraint_System::const_iterator i = cs.begin(),
00067          cs_end = cs.end(); i != cs_end; ++i)
00068     if (i->is_equality())
00069       --d;
00070   return d;
00071 }
00072 
00073 const PPL::Constraint_System&
00074 PPL::Polyhedron::constraints() const {
00075   if (marked_empty()) {
00076     // We want `con_sys' to only contain the unsatisfiable constraint
00077     // of the appropriate dimension.
00078     if (con_sys.has_no_rows()) {
00079       // The 0-dim unsatisfiable constraint is extended to
00080       // the appropriate dimension and then stored in `con_sys'.
00081       Constraint_System unsat_cs = Constraint_System::zero_dim_empty();
00082       unsat_cs.adjust_topology_and_space_dimension(topology(), space_dim);
00083       const_cast<Constraint_System&>(con_sys).m_swap(unsat_cs);
00084     }
00085     else {
00086       // Checking that `con_sys' contains the right thing.
00087       PPL_ASSERT(con_sys.space_dimension() == space_dim);
00088       PPL_ASSERT(con_sys.num_rows() == 1);
00089       PPL_ASSERT(con_sys[0].is_inconsistent());
00090     }
00091     return con_sys;
00092   }
00093 
00094   if (space_dim == 0) {
00095     // Zero-dimensional universe.
00096     PPL_ASSERT(con_sys.num_rows() == 0 && con_sys.num_columns() == 0);
00097     return con_sys;
00098   }
00099 
00100   // If the polyhedron has pending generators, we process them to obtain
00101   // the constraints. No processing is needed if the polyhedron has
00102   // pending constraints.
00103   if (has_pending_generators())
00104     process_pending_generators();
00105   else if (!constraints_are_up_to_date())
00106     update_constraints();
00107 
00108   // TODO: reconsider whether to really sort constraints at this stage.
00109 #if ENSURE_SORTEDNESS
00110   // We insist in returning a sorted system of constraints,
00111   // but sorting is useless if there are pending constraints.
00112   if (!has_pending_constraints())
00113     obtain_sorted_constraints();
00114 #endif
00115   return con_sys;
00116 }
00117 
00118 const PPL::Constraint_System&
00119 PPL::Polyhedron::minimized_constraints() const {
00120   // `minimize()' or `strongly_minimize_constraints()'
00121   // will process any pending constraints or generators.
00122   if (is_necessarily_closed())
00123     minimize();
00124   else
00125     strongly_minimize_constraints();
00126   return constraints();
00127 }
00128 
00129 const PPL::Generator_System&
00130 PPL::Polyhedron::generators() const {
00131   if (marked_empty()) {
00132     PPL_ASSERT(gen_sys.has_no_rows());
00133     // We want `gen_sys' to have the appropriate space dimension,
00134     // even though it is an empty generator system.
00135     if (gen_sys.space_dimension() != space_dim) {
00136       Generator_System gs;
00137       gs.adjust_topology_and_space_dimension(topology(), space_dim);
00138       const_cast<Generator_System&>(gen_sys).m_swap(gs);
00139     }
00140     return gen_sys;
00141   }
00142 
00143   if (space_dim == 0) {
00144     PPL_ASSERT(gen_sys.num_rows() == 0 && gen_sys.num_columns() == 0);
00145     return Generator_System::zero_dim_univ();
00146   }
00147 
00148   // If the polyhedron has pending constraints, we process them to obtain
00149   // the generators (we may discover that the polyhedron is empty).
00150   // No processing is needed if the polyhedron has pending generators.
00151   if ((has_pending_constraints() && !process_pending_constraints())
00152       || (!generators_are_up_to_date() && !update_generators())) {
00153     // We have just discovered that `*this' is empty.
00154     PPL_ASSERT(gen_sys.has_no_rows());
00155     // We want `gen_sys' to have the appropriate space dimension,
00156     // even though it is an empty generator system.
00157     if (gen_sys.space_dimension() != space_dim) {
00158       Generator_System gs;
00159       gs.adjust_topology_and_space_dimension(topology(), space_dim);
00160       const_cast<Generator_System&>(gen_sys).m_swap(gs);
00161     }
00162     return gen_sys;
00163   }
00164 
00165   // TODO: reconsider whether to really sort generators at this stage.
00166 #if ENSURE_SORTEDNESS
00167   // We insist in returning a sorted system of generators,
00168   // but sorting is useless if there are pending generators.
00169   if (!has_pending_generators())
00170     obtain_sorted_generators();
00171 #else
00172   // In the case of an NNC polyhedron, if the generator system is fully
00173   // minimized (i.e., minimized and with no pending generator), then
00174   // return a sorted system of generators: this is needed so that the
00175   // const_iterator could correctly filter out the matched closure points.
00176   if (!is_necessarily_closed()
00177       && generators_are_minimized() && !has_pending_generators())
00178     obtain_sorted_generators();
00179 #endif
00180   return gen_sys;
00181 }
00182 
00183 const PPL::Generator_System&
00184 PPL::Polyhedron::minimized_generators() const {
00185   // `minimize()' or `strongly_minimize_generators()'
00186   // will process any pending constraints or generators.
00187   if (is_necessarily_closed())
00188     minimize();
00189   else
00190     strongly_minimize_generators();
00191   // Note: calling generators() on a strongly minimized NNC generator
00192   // system will also ensure sortedness, which is required to correctly
00193   // filter away the matched closure points.
00194   return generators();
00195 }
00196 
00197 PPL::Poly_Con_Relation
00198 PPL::Polyhedron::relation_with(const Constraint& c) const {
00199   // Dimension-compatibility check.
00200   if (space_dim < c.space_dimension())
00201     throw_dimension_incompatible("relation_with(c)", "c", c);
00202 
00203   if (marked_empty())
00204     return Poly_Con_Relation::saturates()
00205       && Poly_Con_Relation::is_included()
00206       && Poly_Con_Relation::is_disjoint();
00207 
00208   if (space_dim == 0) {
00209     if (c.is_inconsistent())
00210       if (c.is_strict_inequality() && c.inhomogeneous_term() == 0)
00211         // The constraint 0 > 0 implicitly defines the hyperplane 0 = 0;
00212         // thus, the zero-dimensional point also saturates it.
00213         return Poly_Con_Relation::saturates()
00214           && Poly_Con_Relation::is_disjoint();
00215       else
00216         return Poly_Con_Relation::is_disjoint();
00217     else if (c.is_equality() || c.inhomogeneous_term() == 0)
00218       return Poly_Con_Relation::saturates()
00219         && Poly_Con_Relation::is_included();
00220     else
00221       // The zero-dimensional point saturates
00222       // neither the positivity constraint 1 >= 0,
00223       // nor the strict positivity constraint 1 > 0.
00224       return Poly_Con_Relation::is_included();
00225   }
00226 
00227   if ((has_pending_constraints() && !process_pending_constraints())
00228       || (!generators_are_up_to_date() && !update_generators()))
00229     // The polyhedron is empty.
00230     return Poly_Con_Relation::saturates()
00231       && Poly_Con_Relation::is_included()
00232       && Poly_Con_Relation::is_disjoint();
00233 
00234   return gen_sys.relation_with(c);
00235 }
00236 
00237 PPL::Poly_Gen_Relation
00238 PPL::Polyhedron::relation_with(const Generator& g) const {
00239   // Dimension-compatibility check.
00240   if (space_dim < g.space_dimension())
00241     throw_dimension_incompatible("relation_with(g)", "g", g);
00242 
00243   // The empty polyhedron cannot subsume a generator.
00244   if (marked_empty())
00245     return Poly_Gen_Relation::nothing();
00246 
00247   // A universe polyhedron in a zero-dimensional space subsumes
00248   // all the generators of a zero-dimensional space.
00249   if (space_dim == 0)
00250     return Poly_Gen_Relation::subsumes();
00251 
00252   if (has_pending_generators())
00253     process_pending_generators();
00254   else if (!constraints_are_up_to_date())
00255     update_constraints();
00256 
00257   return
00258     con_sys.satisfies_all_constraints(g)
00259     ? Poly_Gen_Relation::subsumes()
00260     : Poly_Gen_Relation::nothing();
00261 }
00262 
00263 PPL::Poly_Con_Relation
00264 PPL::Polyhedron::relation_with(const Congruence& cg) const {
00265   dimension_type cg_space_dim = cg.space_dimension();
00266   // Dimension-compatibility check.
00267   if (space_dim < cg_space_dim)
00268     throw_dimension_incompatible("relation_with(cg)", "cg", cg);
00269 
00270   if (cg.is_equality()) {
00271     const Constraint c(cg);
00272     return relation_with(c);
00273   }
00274 
00275   if (marked_empty())
00276     return Poly_Con_Relation::saturates()
00277       && Poly_Con_Relation::is_included()
00278       && Poly_Con_Relation::is_disjoint();
00279 
00280   if (space_dim == 0) {
00281     if (cg.is_inconsistent())
00282       return Poly_Con_Relation::is_disjoint();
00283     else
00284       return Poly_Con_Relation::saturates()
00285         && Poly_Con_Relation::is_included();
00286   }
00287 
00288   if ((has_pending_constraints() && !process_pending_constraints())
00289       || (!generators_are_up_to_date() && !update_generators()))
00290     // The polyhedron is empty.
00291     return Poly_Con_Relation::saturates()
00292       && Poly_Con_Relation::is_included()
00293       && Poly_Con_Relation::is_disjoint();
00294 
00295   // Build the equality corresponding to the congruence (ignoring the modulus).
00296   Linear_Expression expr = Linear_Expression(cg);
00297   Constraint c(expr == 0);
00298 
00299   // The polyhedron is non-empty so that there exists a point.
00300   // For an arbitrary generator point, compute the scalar product with
00301   // the equality.
00302   PPL_DIRTY_TEMP_COEFFICIENT(sp_point);
00303   for (Generator_System::const_iterator gs_i = gen_sys.begin(),
00304          gs_end = gen_sys.end(); gs_i != gs_end; ++gs_i) {
00305     if (gs_i->is_point()) {
00306       Scalar_Products::assign(sp_point, c, *gs_i);
00307       expr -= sp_point;
00308       break;
00309     }
00310   }
00311 
00312   // Find two hyperplanes that satisfy the congruence and are near to
00313   // the generating point (so that the point lies on or between these
00314   // two hyperplanes).
00315   // Then use the relations between the polyhedron and the halfspaces
00316   // corresponding to the hyperplanes to determine the result.
00317 
00318   // Compute the distance from the point to an hyperplane.
00319   const Coefficient& modulus = cg.modulus();
00320   PPL_DIRTY_TEMP_COEFFICIENT(signed_distance);
00321   signed_distance = sp_point % modulus;
00322   if (signed_distance == 0)
00323     // The point is lying on the hyperplane.
00324     return relation_with(expr == 0);
00325   else
00326     // The point is not lying on the hyperplane.
00327     expr += signed_distance;
00328 
00329   // Build first halfspace constraint.
00330   const bool positive = (signed_distance > 0);
00331   Constraint first_halfspace = positive ? (expr >= 0) : (expr <= 0);
00332 
00333   Poly_Con_Relation first_rels = relation_with(first_halfspace);
00334   PPL_ASSERT(!first_rels.implies(Poly_Con_Relation::saturates())
00335              && !first_rels.implies(Poly_Con_Relation::is_disjoint()));
00336   if (first_rels.implies(Poly_Con_Relation::strictly_intersects()))
00337     return Poly_Con_Relation::strictly_intersects();
00338 
00339   // Build second halfspace.
00340   if (positive)
00341     expr -= modulus;
00342   else
00343     expr += modulus;
00344   Constraint second_halfspace = positive ? (expr <= 0) : (expr >= 0);
00345 
00346   PPL_ASSERT(first_rels == Poly_Con_Relation::is_included());
00347   Poly_Con_Relation second_rels = relation_with(second_halfspace);
00348   PPL_ASSERT(!second_rels.implies(Poly_Con_Relation::saturates())
00349              && !second_rels.implies(Poly_Con_Relation::is_disjoint()));
00350   if (second_rels.implies(Poly_Con_Relation::strictly_intersects()))
00351     return Poly_Con_Relation::strictly_intersects();
00352 
00353   PPL_ASSERT(second_rels == Poly_Con_Relation::is_included());
00354   return Poly_Con_Relation::is_disjoint();
00355 }
00356 
00357 bool
00358 PPL::Polyhedron::is_universe() const {
00359   if (marked_empty())
00360     return false;
00361 
00362   if (space_dim == 0)
00363     return true;
00364 
00365   if (!has_pending_generators() && constraints_are_up_to_date()) {
00366     // Search for a constraint that is not a tautology.
00367     for (dimension_type i = con_sys.num_rows(); i-- > 0; )
00368       if (!con_sys[i].is_tautological())
00369         return false;
00370     // All the constraints are tautologies.
00371     return true;
00372   }
00373 
00374   PPL_ASSERT(!has_pending_constraints() && generators_are_up_to_date());
00375 
00376   // Try a fast-fail test.
00377   dimension_type num_lines = 0;
00378   dimension_type num_rays = 0;
00379   const dimension_type first_pending = gen_sys.first_pending_row();
00380   for (dimension_type i = first_pending; i-- > 0; )
00381     switch (gen_sys[i].type()) {
00382     case Generator::RAY:
00383       ++num_rays;
00384       break;
00385     case Generator::LINE:
00386       ++num_lines;
00387       break;
00388     default:
00389       break;
00390     }
00391 
00392   if (has_pending_generators()) {
00393     // The non-pending part of `gen_sys' was minimized:
00394     // a success-first test is possible in this case.
00395     PPL_ASSERT(generators_are_minimized());
00396     if (num_lines == space_dim) {
00397       PPL_ASSERT(num_rays == 0);
00398       return true;
00399     }
00400     PPL_ASSERT(num_lines < space_dim);
00401     // Now scan the pending generators.
00402     dimension_type num_pending_lines = 0;
00403     dimension_type num_pending_rays = 0;
00404     const dimension_type gs_num_rows = gen_sys.num_rows();
00405     for (dimension_type i = first_pending; i < gs_num_rows; ++i)
00406       switch (gen_sys[i].type()) {
00407       case Generator::RAY:
00408         ++num_pending_rays;
00409         break;
00410       case Generator::LINE:
00411         ++num_pending_lines;
00412         break;
00413       default:
00414         break;
00415       }
00416     // If no pending rays and lines were found,
00417     // then it is not the universe polyhedron.
00418     if (num_pending_rays == 0 && num_pending_lines == 0)
00419       return false;
00420     // Factor away the lines already seen (to be on the safe side,
00421     // we assume they are all linearly independent).
00422     if (num_lines + num_pending_lines < space_dim) {
00423       const dimension_type num_dims_missing
00424         = space_dim - (num_lines + num_pending_lines);
00425       // In order to span an n dimensional space (where n = num_dims_missing),
00426       // at least n+1 rays are needed.
00427       if (num_rays + num_pending_rays <= num_dims_missing)
00428         return false;
00429     }
00430   }
00431   else {
00432     // There is nothing pending.
00433     if (generators_are_minimized()) {
00434       // The exact test is possible.
00435       PPL_ASSERT(num_rays == 0 || num_lines < space_dim);
00436       return num_lines == space_dim;
00437     }
00438     else
00439       // Only the fast-fail test can be computed: in order to span
00440       // an n dimensional space (where n = space_dim - num_lines),
00441       // at least n+1 rays are needed.
00442       if (num_lines < space_dim && num_lines + num_rays <= space_dim)
00443         return false;
00444   }
00445 
00446   // We need the polyhedron in minimal form.
00447   if (has_pending_generators())
00448     process_pending_generators();
00449   else if (!constraints_are_minimized())
00450     minimize();
00451   if (is_necessarily_closed())
00452     return con_sys.num_rows() == 1
00453       && con_sys[0].is_inequality()
00454       && con_sys[0].is_tautological();
00455   else {
00456     // NNC polyhedron.
00457     if (con_sys.num_rows() != 2
00458         || con_sys[0].is_equality()
00459         || con_sys[1].is_equality())
00460       return false;
00461     else {
00462       // If the system of constraints contains two rows that
00463       // are not equalities, we are sure that they are
00464       // epsilon constraints: in this case we know that
00465       // the polyhedron is universe.
00466 #ifndef NDEBUG
00467       obtain_sorted_constraints();
00468       const Constraint& eps_leq_one = con_sys[0];
00469       const Constraint& eps_geq_zero = con_sys[1];
00470       const dimension_type eps_index = con_sys.num_columns() - 1;
00471       PPL_ASSERT(eps_leq_one[0] > 0 && eps_leq_one[eps_index] < 0
00472              && eps_geq_zero[0] == 0 && eps_geq_zero[eps_index] > 0);
00473       for (dimension_type i = 1; i < eps_index; ++i)
00474         PPL_ASSERT(eps_leq_one[i] == 0 && eps_geq_zero[i] == 0);
00475 #endif
00476       return true;
00477     }
00478   }
00479 }
00480 
00481 bool
00482 PPL::Polyhedron::is_bounded() const {
00483   // A zero-dimensional or empty polyhedron is bounded.
00484   if (space_dim == 0
00485       || marked_empty()
00486       || (has_pending_constraints() && !process_pending_constraints())
00487       || (!generators_are_up_to_date() && !update_generators()))
00488     return true;
00489 
00490   // If the system of generators contains any line or a ray,
00491   // then the polyhedron is unbounded.
00492   for (dimension_type i = gen_sys.num_rows(); i-- > 0; )
00493     if (gen_sys[i].is_line_or_ray())
00494       return false;
00495 
00496   // The system of generators is composed only by
00497   // points and closure points: the polyhedron is bounded.
00498   return true;
00499 }
00500 
00501 bool
00502 PPL::Polyhedron::is_topologically_closed() const {
00503   // Necessarily closed polyhedra are trivially closed.
00504   if (is_necessarily_closed())
00505     return true;
00506   // Any empty or zero-dimensional polyhedron is closed.
00507   if (marked_empty()
00508       || space_dim == 0
00509       || (has_something_pending() && !process_pending()))
00510     return true;
00511 
00512   // At this point there are no pending constraints or generators.
00513   PPL_ASSERT(!has_something_pending());
00514 
00515   if (generators_are_minimized()) {
00516     // A polyhedron is closed if and only if all of its (non-redundant)
00517     // closure points are matched by a corresponding point.
00518     const dimension_type n_rows = gen_sys.num_rows();
00519     const dimension_type n_lines = gen_sys.num_lines();
00520     for (dimension_type i = n_rows; i-- > n_lines; ) {
00521       const Generator& gen_sys_i = gen_sys[i];
00522       if (gen_sys_i.is_closure_point()) {
00523         bool gen_sys_i_has_no_matching_point = true;
00524         for (dimension_type j = n_rows; j-- > n_lines; ) {
00525           const Generator& gen_sys_j = gen_sys[j];
00526           if (i != j
00527               && gen_sys_j.is_point()
00528               && gen_sys_i.is_matching_closure_point(gen_sys_j)) {
00529             gen_sys_i_has_no_matching_point = false;
00530             break;
00531           }
00532         }
00533         if (gen_sys_i_has_no_matching_point)
00534           return false;
00535       }
00536     }
00537     // All closure points are matched.
00538     return true;
00539   }
00540 
00541   // A polyhedron is closed if, after strong minimization
00542   // of its constraint system, it has no strict inequalities.
00543   strongly_minimize_constraints();
00544   return marked_empty() || !con_sys.has_strict_inequalities();
00545 }
00546 
00547 bool
00548 PPL::Polyhedron::contains_integer_point() const {
00549   // Any empty polyhedron does not contain integer points.
00550   if (marked_empty())
00551     return false;
00552 
00553   // A zero-dimensional, universe polyhedron has, by convention, an
00554   // integer point.
00555   if (space_dim == 0)
00556     return true;
00557 
00558   // CHECKME: do we really want to call conversion to check for emptiness?
00559   if (has_pending_constraints() && !process_pending())
00560     // Empty again.
00561     return false;
00562 
00563   // FIXME: do also exploit info regarding rays and lines, if possible.
00564   // Is any integer point already available?
00565   PPL_ASSERT(!has_pending_constraints());
00566   if (generators_are_up_to_date())
00567     for (dimension_type i = gen_sys.num_rows(); i-- > 0; )
00568       if (gen_sys[i].is_point() && gen_sys[i].divisor() == 1)
00569         return true;
00570 
00571   const Constraint_System& cs = constraints();
00572 #if 0 // TEMPORARILY DISABLED.
00573   MIP_Problem mip(space_dim,
00574                   cs.begin(), cs.end(),
00575                   Variables_Set(Variable(0), Variable(space_dim-1)));
00576 #else
00577   // FIXME: temporary workaround, to be removed as soon as the MIP
00578   // problem class will correctly and precisely handle
00579   // ((strict) in-) equality constraints having all integer variables.
00580   MIP_Problem mip(space_dim);
00581   mip.add_to_integer_space_dimensions(Variables_Set(Variable(0),
00582                                                     Variable(space_dim-1)));
00583   PPL_DIRTY_TEMP_COEFFICIENT(homogeneous_gcd);
00584   PPL_DIRTY_TEMP_COEFFICIENT(gcd);
00585   PPL_DIRTY_TEMP(mpq_class, rational_inhomogeneous);
00586   PPL_DIRTY_TEMP_COEFFICIENT(tightened_inhomogeneous);
00587   for (Constraint_System::const_iterator cs_i = cs.begin(),
00588          cs_end = cs.end(); cs_i != cs_end; ++cs_i) {
00589     const Constraint& c = *cs_i;
00590     const Constraint::Type c_type = c.type();
00591     const Coefficient& inhomogeneous = c.inhomogeneous_term();
00592     if (c_type == Constraint::STRICT_INEQUALITY) {
00593       // CHECKME: should we change the behavior of Linear_Expression(c) ?
00594       // Compute the GCD of the coefficients of c
00595       // (disregarding the inhomogeneous term and the epsilon dimension).
00596       homogeneous_gcd = 0;
00597       for (dimension_type i = space_dim; i-- > 0; )
00598         gcd_assign(homogeneous_gcd,
00599                    homogeneous_gcd, c.coefficient(Variable(i)));
00600       if (homogeneous_gcd == 0) {
00601         // NOTE: since tautological constraints are already filtered away
00602         // by iterators, here we must have an inconsistent constraint.
00603         PPL_ASSERT(c.is_inconsistent());
00604         return false;
00605       }
00606       Linear_Expression le;
00607       for (dimension_type i = space_dim; i-- > 0; )
00608         le += (c.coefficient(Variable(i)) / homogeneous_gcd) * Variable(i);
00609       // Add the integer part of `inhomogeneous'.
00610       le += (inhomogeneous / homogeneous_gcd);
00611       // Further tighten the constraint if the inhomogeneous term
00612       // was integer, i.e., if `homogeneous_gcd' divides `inhomogeneous'.
00613       gcd_assign(gcd, homogeneous_gcd, inhomogeneous);
00614       if (gcd == homogeneous_gcd)
00615         le -= 1;
00616       mip.add_constraint(le >= 0);
00617     }
00618     else {
00619       // Equality or non-strict inequality.
00620       // If possible, avoid useless gcd computations.
00621       if (inhomogeneous == 0)
00622         // The inhomogeneous term cannot be tightened.
00623         mip.add_constraint(c);
00624       else {
00625         // Compute the GCD of the coefficients of c
00626         // (disregarding the inhomogeneous term)
00627         // to see whether or not the inhomogeneous term can be tightened.
00628         homogeneous_gcd = 0;
00629         for (dimension_type i = space_dim; i-- > 0; )
00630           gcd_assign(homogeneous_gcd,
00631                      homogeneous_gcd, c.coefficient(Variable(i)));
00632         if (homogeneous_gcd == 0) {
00633           // NOTE: since tautological constraints are already filtered away
00634           // by iterators, here we must have an inconsistent constraint.
00635           PPL_ASSERT(c.is_inconsistent());
00636           return false;
00637         }
00638         else if (homogeneous_gcd == 1)
00639           // The normalized inhomogeneous term is integer:
00640           // add the constraint as-is.
00641           mip.add_constraint(c);
00642         else {
00643           PPL_ASSERT(homogeneous_gcd > 1);
00644           // Here the normalized inhomogeneous term is rational:
00645           // the constraint has to be tightened.
00646 #ifndef NDEBUG
00647           // `homogeneous_gcd' does not divide `inhomogeneous'.
00648           // FIXME: add a divisibility test for Coefficient.
00649           gcd_assign(gcd, homogeneous_gcd, inhomogeneous);
00650           PPL_ASSERT(gcd == 1);
00651 #endif
00652           if (c.type() == Constraint::EQUALITY)
00653             return false;
00654           // Extract the homogeneous part of the constraint.
00655           Linear_Expression le = Linear_Expression(c);
00656           le -= inhomogeneous;
00657           // Tighten the inhomogeneous term.
00658           assign_r(rational_inhomogeneous.get_num(),
00659                    inhomogeneous, ROUND_NOT_NEEDED);
00660           assign_r(rational_inhomogeneous.get_den(),
00661                    homogeneous_gcd, ROUND_NOT_NEEDED);
00662           // Note: canonicalization is not needed (as gcd == 1).
00663           PPL_ASSERT(is_canonical(rational_inhomogeneous));
00664           assign_r(tightened_inhomogeneous,
00665                    rational_inhomogeneous, ROUND_DOWN);
00666           tightened_inhomogeneous *= homogeneous_gcd;
00667           le += tightened_inhomogeneous;
00668           mip.add_constraint(le >= 0);
00669         }
00670       }
00671     }
00672   }
00673 #endif // TEMPORARY WORKAROUND.
00674   return mip.is_satisfiable();
00675 }
00676 
00677 bool
00678 PPL::Polyhedron::constrains(const Variable var) const {
00679   // `var' should be one of the dimensions of the polyhedron.
00680   const dimension_type var_space_dim = var.space_dimension();
00681   if (space_dim < var_space_dim)
00682     throw_dimension_incompatible("constrains(v)", "v", var);
00683 
00684   // An empty polyhedron constrains all variables.
00685   if (marked_empty())
00686     return true;
00687 
00688   if (generators_are_up_to_date() && !has_pending_constraints()) {
00689     // Since generators are up-to-date and there are no pending
00690     // constraints, the generator system (since it is well formed)
00691     // contains a point.  Hence the polyhedron is not empty.
00692     if (constraints_are_up_to_date() && !has_pending_generators())
00693       // Here a variable is constrained if and only if it is
00694       // syntactically constrained.
00695       goto syntactic_check;
00696 
00697     if (generators_are_minimized()) {
00698       // Try a quick, incomplete check for the universe polyhedron:
00699       // a universe polyhedron constrains no variable.
00700       // Count the number of non-pending
00701       // (hence, linearly independent) lines.
00702       dimension_type num_lines = 0;
00703       const dimension_type first_pending = gen_sys.first_pending_row();
00704       for (dimension_type i = first_pending; i-- > 0; )
00705         if (gen_sys[i].is_line())
00706           ++num_lines;
00707 
00708       if (num_lines == space_dim)
00709         return false;
00710     }
00711 
00712     // Scan generators: perhaps we will find a generator equivalent to
00713     // line(var) or a pair of generators equivalent to ray(-var) and
00714     // ray(var).
00715     bool have_positive_ray = false;
00716     bool have_negative_ray = false;
00717     const dimension_type var_id = var.id();
00718     for (dimension_type i = gen_sys.num_rows(); i-- > 0; ) {
00719       const Generator& gen_sys_i = gen_sys[i];
00720       if (gen_sys_i.is_line_or_ray()) {
00721         const Linear_Row& row = gen_sys_i;
00722         const int sign = sgn(row.coefficient(var_id));
00723         if (sign != 0) {
00724           for (dimension_type j = space_dim+1; --j > 0; )
00725             if (j != var_id && row[j] != 0)
00726               goto next;
00727           if (gen_sys_i.is_line())
00728             return true;
00729           if (sign > 0)
00730             if (have_negative_ray)
00731               return true;
00732             else
00733               have_positive_ray = true;
00734           else if (have_positive_ray)
00735             return true;
00736           else
00737             have_negative_ray = true;
00738         }
00739       }
00740     next:
00741       ;
00742     }
00743 
00744     // We are still here: at least we know that, since generators are
00745     // up-to-date and there are no pending constraints, then the
00746     // generator system (since it is well formed) contains a point.
00747     // Hence the polyhedron is not empty.
00748     if (has_pending_generators())
00749       process_pending_generators();
00750     else if (!constraints_are_up_to_date())
00751       update_constraints();
00752     goto syntactic_check;
00753   }
00754 
00755   // We must minimize to detect emptiness and obtain constraints.
00756   if (!minimize())
00757     return true;
00758 
00759  syntactic_check:
00760   for (dimension_type i = con_sys.num_rows(); i-- > 0; )
00761     if (con_sys[i].coefficient(var) != 0)
00762       return true;
00763   return false;
00764 }
00765 
00766 bool
00767 PPL::Polyhedron::OK(bool check_not_empty) const {
00768 #ifndef NDEBUG
00769   using std::endl;
00770   using std::cerr;
00771 #endif
00772 
00773   // The expected number of columns in the constraint and generator
00774   // systems, if they are not empty.
00775   const dimension_type poly_num_columns
00776     = space_dim + (is_necessarily_closed() ? 1U : 2U);
00777 
00778   // Check whether the topologies of `con_sys' and `gen_sys' agree.
00779   if (con_sys.topology() != gen_sys.topology()) {
00780 #ifndef NDEBUG
00781     cerr << "Constraints and generators have different topologies!"
00782          << endl;
00783 #endif
00784     goto bomb;
00785   }
00786 
00787   // Check whether the saturation matrices are well-formed.
00788   if (!sat_c.OK())
00789     goto bomb;
00790   if (!sat_g.OK())
00791     goto bomb;
00792 
00793   // Check whether the status information is legal.
00794   if (!status.OK())
00795     goto bomb;
00796 
00797   if (marked_empty()) {
00798     if (check_not_empty) {
00799       // The caller does not want the polyhedron to be empty.
00800 #ifndef NDEBUG
00801       cerr << "Empty polyhedron!" << endl;
00802 #endif
00803       goto bomb;
00804     }
00805 
00806     // An empty polyhedron is allowed if the system of constraints
00807     // either has no rows or only contains an unsatisfiable constraint
00808     // and if it has no pending constraints or generators.
00809     if (has_something_pending()) {
00810 #ifndef NDEBUG
00811       cerr << "The polyhedron is empty, "
00812            << "but it has something pending" << endl;
00813 #endif
00814       goto bomb;
00815     }
00816     if (con_sys.has_no_rows())
00817       return true;
00818     else {
00819       if (con_sys.space_dimension() != space_dim) {
00820 #ifndef NDEBUG
00821         cerr << "The polyhedron is in a space of dimension "
00822              << space_dim
00823              << " while the system of constraints is in a space of dimension "
00824              << con_sys.space_dimension()
00825              << endl;
00826 #endif
00827         goto bomb;
00828       }
00829       if (con_sys.num_rows() != 1) {
00830 #ifndef NDEBUG
00831         cerr << "The system of constraints for an empty polyhedron "
00832              << "has more then one row"
00833              << endl;
00834 #endif
00835         goto bomb;
00836       }
00837       if (!con_sys[0].is_inconsistent()) {
00838 #ifndef NDEBUG
00839         cerr << "Empty polyhedron with a satisfiable system of constraints"
00840              << endl;
00841 #endif
00842         goto bomb;
00843       }
00844       // Here we have only one, inconsistent constraint.
00845       return true;
00846     }
00847   }
00848 
00849   // A zero-dimensional, non-empty polyhedron is legal only if the
00850   // system of constraint `con_sys' and the system of generators
00851   // `gen_sys' have no rows.
00852   if (space_dim == 0) {
00853     if (has_something_pending()) {
00854 #ifndef NDEBUG
00855       cerr << "Zero-dimensional polyhedron with something pending"
00856            << endl;
00857 #endif
00858       goto bomb;
00859     }
00860     if (!con_sys.has_no_rows() || !gen_sys.has_no_rows()) {
00861 #ifndef NDEBUG
00862       cerr << "Zero-dimensional polyhedron with a non-empty"
00863            << endl
00864            << "system of constraints or generators."
00865            << endl;
00866 #endif
00867       goto bomb;
00868     }
00869     return true;
00870   }
00871 
00872   // A polyhedron is defined by a system of constraints
00873   // or a system of generators: at least one of them must be up to date.
00874   if (!constraints_are_up_to_date() && !generators_are_up_to_date()) {
00875 #ifndef NDEBUG
00876     cerr << "Polyhedron not empty, not zero-dimensional"
00877          << endl
00878          << "and with neither constraints nor generators up-to-date!"
00879          << endl;
00880 #endif
00881     goto bomb;
00882   }
00883 
00884   // Here we check if the size of the matrices is consistent.
00885   // Let us suppose that all the matrices are up-to-date; this means:
00886   // `con_sys' : number of constraints x poly_num_columns
00887   // `gen_sys' : number of generators  x poly_num_columns
00888   // `sat_c'   : number of generators  x number of constraints
00889   // `sat_g'   : number of constraints x number of generators.
00890   if (constraints_are_up_to_date()) {
00891     if (con_sys.num_columns() != poly_num_columns) {
00892 #ifndef NDEBUG
00893       cerr << "Incompatible size! (con_sys and space_dim)"
00894            << endl;
00895 #endif
00896       goto bomb;
00897     }
00898     if (sat_c_is_up_to_date())
00899       if (con_sys.first_pending_row() != sat_c.num_columns()) {
00900 #ifndef NDEBUG
00901         cerr << "Incompatible size! (con_sys and sat_c)"
00902              << endl;
00903 #endif
00904         goto bomb;
00905       }
00906     if (sat_g_is_up_to_date())
00907       if (con_sys.first_pending_row() != sat_g.num_rows()) {
00908 #ifndef NDEBUG
00909         cerr << "Incompatible size! (con_sys and sat_g)"
00910              << endl;
00911 #endif
00912         goto bomb;
00913       }
00914     if (generators_are_up_to_date())
00915       if (con_sys.num_columns() != gen_sys.num_columns()) {
00916 #ifndef NDEBUG
00917         cerr << "Incompatible size! (con_sys and gen_sys)"
00918              << endl;
00919 #endif
00920         goto bomb;
00921       }
00922   }
00923 
00924   if (generators_are_up_to_date()) {
00925     if (gen_sys.num_columns() != poly_num_columns) {
00926 #ifndef NDEBUG
00927       cerr << "Incompatible size! (gen_sys and space_dim)"
00928            << endl;
00929 #endif
00930       goto bomb;
00931     }
00932     if (sat_c_is_up_to_date())
00933       if (gen_sys.first_pending_row() != sat_c.num_rows()) {
00934 #ifndef NDEBUG
00935         cerr << "Incompatible size! (gen_sys and sat_c)"
00936              << endl;
00937 #endif
00938         goto bomb;
00939       }
00940     if (sat_g_is_up_to_date())
00941       if (gen_sys.first_pending_row() != sat_g.num_columns()) {
00942 #ifndef NDEBUG
00943         cerr << "Incompatible size! (gen_sys and sat_g)"
00944              << endl;
00945 #endif
00946         goto bomb;
00947       }
00948 
00949     // Check if the system of generators is well-formed.
00950     if (!gen_sys.OK())
00951       goto bomb;
00952 
00953     if (gen_sys.first_pending_row() == 0) {
00954 #ifndef NDEBUG
00955       cerr << "Up-to-date generator system with all rows pending!"
00956            << endl;
00957 #endif
00958       goto bomb;
00959     }
00960 
00961     // A non-empty system of generators describing a polyhedron
00962     // is valid if and only if it contains a point.
00963     if (!gen_sys.has_no_rows() && !gen_sys.has_points()) {
00964 #ifndef NDEBUG
00965       cerr << "Non-empty generator system declared up-to-date "
00966            << "has no points!"
00967            << endl;
00968 #endif
00969       goto bomb;
00970     }
00971 
00972 #if 0 // To be activated when Status keeps strong minimization flags.
00973     //=================================================
00974     // TODO: this test is wrong in the general case.
00975     // However, such an invariant does hold for a
00976     // strongly-minimized Generator_System.
00977     // We will activate this test as soon as the Status
00978     // flags will be able to remember if a system is
00979     // strongly minimized.
00980 
00981     // Checking that the number of closure points is always
00982     // greater than the number of points.
00983     if (!is_necessarily_closed()) {
00984       dimension_type num_points = 0;
00985       dimension_type num_closure_points = 0;
00986       dimension_type eps_index = gen_sys.num_columns() - 1;
00987       for (dimension_type i = gen_sys.num_rows(); i-- > 0; )
00988         if (!gen_sys[i].is_line_or_ray())
00989           if (gen_sys[i][eps_index] > 0)
00990             ++num_points;
00991           else
00992             ++num_closure_points;
00993       if (num_points > num_closure_points) {
00994 #ifndef NDEBUG
00995         cerr << "# POINTS > # CLOSURE_POINTS" << endl;
00996 #endif
00997         goto bomb;
00998       }
00999     }
01000     //=================================================
01001 #endif
01002 
01003     if (generators_are_minimized()) {
01004       // If the system of generators is minimized, the number of
01005       // lines, rays and points of the polyhedron must be the same as
01006       // of a temporary, minimized one. If this does not happen then
01007       // the polyhedron is not OK.
01008       Constraint_System new_con_sys(topology());
01009       Generator_System gs_without_pending = gen_sys;
01010       gs_without_pending.remove_trailing_rows(gs_without_pending.num_rows()
01011                                               - gen_sys.first_pending_row());
01012       gs_without_pending.unset_pending_rows();
01013       Generator_System copy_of_gen_sys = gs_without_pending;
01014       Bit_Matrix new_sat_c;
01015       minimize(false, copy_of_gen_sys, new_con_sys, new_sat_c);
01016       const dimension_type copy_num_lines = copy_of_gen_sys.num_lines();
01017       if (gs_without_pending.num_rows() != copy_of_gen_sys.num_rows()
01018           || gs_without_pending.num_lines() != copy_num_lines
01019           || gs_without_pending.num_rays() != copy_of_gen_sys.num_rays()) {
01020 #ifndef NDEBUG
01021         cerr << "Generators are declared minimized, but they are not!\n"
01022              << "Here is the minimized form of the generators:\n";
01023         copy_of_gen_sys.ascii_dump(cerr);
01024         cerr << endl;
01025 #endif
01026         goto bomb;
01027       }
01028 
01029       // CHECKME : the following observation is not formally true
01030       //           for a NNC_Polyhedron. But it may be true for its
01031       //           representation ...
01032 
01033       // If the corresponding polyhedral cone is _pointed_, then
01034       // a minimal system of generators is unique up to positive scaling.
01035       // We thus verify if the cone is pointed (i.e., there are no lines)
01036       // and, after normalizing and sorting a copy of the system `gen_sys'
01037       // of the polyhedron (we use a copy not to modify the polyhedron's
01038       // system) and the system `copy_of_gen_sys' that has been just
01039       // minimized, we check if the two matrices are identical.  If
01040       // they are different it means that the generators of the
01041       // polyhedron are declared minimized, but they are not.
01042       if (copy_num_lines == 0) {
01043         copy_of_gen_sys.strong_normalize();
01044         copy_of_gen_sys.sort_rows();
01045         gs_without_pending.strong_normalize();
01046         gs_without_pending.sort_rows();
01047         if (copy_of_gen_sys != gs_without_pending) {
01048 #ifndef NDEBUG
01049           cerr << "Generators are declared minimized, but they are not!\n"
01050                << "(we are in the case:\n"
01051                << "dimension of lineality space equal to 0)\n"
01052                << "Here is the minimized form of the generators:\n";
01053           copy_of_gen_sys.ascii_dump(cerr);
01054           cerr << endl;
01055 #endif
01056             goto bomb;
01057         }
01058       }
01059     }
01060   }
01061 
01062   if (constraints_are_up_to_date()) {
01063     // Check if the system of constraints is well-formed.
01064     if (!con_sys.OK())
01065       goto bomb;
01066 
01067     if (con_sys.first_pending_row() == 0) {
01068 #ifndef NDEBUG
01069       cerr << "Up-to-date constraint system with all rows pending!"
01070            << endl;
01071 #endif
01072       goto bomb;
01073     }
01074 
01075     // A non-empty system of constraints describing a polyhedron
01076     // must contain a constraint with a non-zero inhomogeneous term;
01077     // such a constraint corresponds to (a combination of other
01078     // constraints with):
01079     // -* the positivity constraint, for necessarily closed polyhedra;
01080     // -* the epsilon <= 1 constraint, for NNC polyhedra.
01081     bool no_positivity_constraint = true;
01082     for (dimension_type i = con_sys.num_rows(); i-- > 0; )
01083       if (con_sys[i].inhomogeneous_term() != 0) {
01084         no_positivity_constraint = false;
01085         break;
01086       }
01087     if (no_positivity_constraint) {
01088 #ifndef NDEBUG
01089       cerr << "Non-empty constraint system has no positivity constraint"
01090            << endl;
01091 #endif
01092       goto bomb;
01093     }
01094 
01095     if (!is_necessarily_closed()) {
01096       // A non-empty system of constraints describing a NNC polyhedron
01097       // must also contain a (combination of) the constraint epsilon >= 0,
01098       // i.e., a constraint with a positive epsilon coefficient.
01099       bool no_epsilon_geq_zero = true;
01100       const dimension_type eps_index = con_sys.num_columns() - 1;
01101       for (dimension_type i = con_sys.num_rows(); i-- > 0; )
01102         if (con_sys[i][eps_index] > 0) {
01103           no_epsilon_geq_zero = false;
01104           break;
01105         }
01106       if (no_epsilon_geq_zero) {
01107 #ifndef NDEBUG
01108         cerr << "Non-empty constraint system for NNC polyhedron "
01109              << "has no epsilon >= 0 constraint"
01110              << endl;
01111 #endif
01112         goto bomb;
01113       }
01114     }
01115 
01116     Constraint_System cs_without_pending = con_sys;
01117     cs_without_pending.remove_trailing_rows(cs_without_pending.num_rows()
01118                                             - con_sys.first_pending_row());
01119     cs_without_pending.unset_pending_rows();
01120     Constraint_System copy_of_con_sys = cs_without_pending;
01121     bool empty = false;
01122     if (check_not_empty || constraints_are_minimized()) {
01123       Generator_System new_gen_sys(topology());
01124       Bit_Matrix new_sat_g;
01125       empty = minimize(true, copy_of_con_sys, new_gen_sys, new_sat_g);
01126     }
01127 
01128     if (empty && check_not_empty) {
01129 #ifndef NDEBUG
01130       cerr << "Unsatisfiable system of constraints!"
01131            << endl;
01132 #endif
01133       goto bomb;
01134     }
01135 
01136     if (constraints_are_minimized()) {
01137       // If the constraints are minimized, the number of equalities
01138       // and of inequalities of the system of the polyhedron must be
01139       // the same of the temporary minimized one.
01140       // If it does not happen, the polyhedron is not OK.
01141       if (cs_without_pending.num_rows() != copy_of_con_sys.num_rows()
01142           || cs_without_pending.num_equalities()
01143           != copy_of_con_sys.num_equalities()) {
01144 #ifndef NDEBUG
01145         cerr << "Constraints are declared minimized, but they are not!\n"
01146              << "Here is the minimized form of the constraints:\n";
01147         copy_of_con_sys.ascii_dump(cerr);
01148         cerr << endl;
01149 #endif
01150         goto bomb;
01151       }
01152       // The system `copy_of_con_sys' has the form that is obtained
01153       // after applying methods gauss() and back_substitute().
01154       // A system of constraints can be minimal even if it does not
01155       // have this form. So, to verify if the polyhedron is correct,
01156       // we copy the system `con_sys' in a temporary one and then
01157       // modify it using method simplify() (which calls both gauss()
01158       // and back_substitute()).
01159       // If the temporary system and `copy_of_con_sys' are different,
01160       // the polyhedron is not OK.
01161       copy_of_con_sys.strong_normalize();
01162       copy_of_con_sys.sort_rows();
01163       cs_without_pending.simplify();
01164       cs_without_pending.strong_normalize();
01165       cs_without_pending.sort_rows();
01166       if (cs_without_pending != copy_of_con_sys) {
01167 #ifndef NDEBUG
01168         cerr << "Constraints are declared minimized, but they are not!\n"
01169              << "Here is the minimized form of the constraints:\n";
01170         copy_of_con_sys.ascii_dump(cerr);
01171         cerr << endl;
01172 #endif
01173         goto bomb;
01174       }
01175     }
01176   }
01177 
01178   if (sat_c_is_up_to_date())
01179     for (dimension_type i = sat_c.num_rows(); i-- > 0; ) {
01180       const Generator tmp_gen = gen_sys[i];
01181       const Bit_Row tmp_sat = sat_c[i];
01182       for (dimension_type j = sat_c.num_columns(); j-- > 0; ) {
01183         const bool sat_j = (Scalar_Products::sign(con_sys[j], tmp_gen) == 0);
01184         if (sat_j == tmp_sat[j]) {
01185 #ifndef NDEBUG
01186           cerr << "sat_c is declared up-to-date, but it is not!"
01187                << endl;
01188 #endif
01189           goto bomb;
01190         }
01191       }
01192     }
01193 
01194   if (sat_g_is_up_to_date())
01195     for (dimension_type i = sat_g.num_rows(); i-- > 0; ) {
01196       const Constraint tmp_con = con_sys[i];
01197       const Bit_Row tmp_sat = sat_g[i];
01198       for (dimension_type j = sat_g.num_columns(); j-- > 0; ) {
01199         const bool sat_j = (Scalar_Products::sign(tmp_con, gen_sys[j]) == 0);
01200         if (sat_j == tmp_sat[j]) {
01201 #ifndef NDEBUG
01202           cerr << "sat_g is declared up-to-date, but it is not!"
01203                << endl;
01204 #endif
01205           goto bomb;
01206         }
01207       }
01208     }
01209 
01210   if (has_pending_constraints()) {
01211     if (con_sys.num_pending_rows() == 0) {
01212 #ifndef NDEBUG
01213       cerr << "The polyhedron is declared to have pending constraints, "
01214            << "but con_sys has no pending rows!"
01215            << endl;
01216 #endif
01217       goto bomb;
01218     }
01219   }
01220 
01221   if (has_pending_generators()) {
01222     if (gen_sys.num_pending_rows() == 0) {
01223 #ifndef NDEBUG
01224       cerr << "The polyhedron is declared to have pending generators, "
01225            << "but gen_sys has no pending rows!"
01226            << endl;
01227 #endif
01228       goto bomb;
01229     }
01230   }
01231 
01232   return true;
01233 
01234  bomb:
01235 #ifndef NDEBUG
01236   cerr << "Here is the guilty polyhedron:"
01237        << endl;
01238   ascii_dump(cerr);
01239 #endif
01240   return false;
01241 }
01242 
01243 void
01244 PPL::Polyhedron::add_constraint(const Constraint& c) {
01245   // Topology-compatibility check.
01246   if (c.is_strict_inequality() && is_necessarily_closed()) {
01247     // Trivially true/false strict inequalities are legal.
01248     if (c.is_tautological())
01249       return;
01250     if (c.is_inconsistent()) {
01251       set_empty();
01252       return;
01253     }
01254     // Here c is a non-trivial strict inequality.
01255     throw_topology_incompatible("add_constraint(c)", "c", c);
01256   }
01257 
01258   // Dimension-compatibility check:
01259   // the dimension of `c' can not be greater than space_dim.
01260   if (space_dim < c.space_dimension())
01261     throw_dimension_incompatible("add_constraint(c)", "c", c);
01262 
01263   if (!marked_empty())
01264     refine_no_check(c);
01265 }
01266 
01267 void
01268 PPL::Polyhedron::add_congruence(const Congruence& cg) {
01269   // Dimension-compatibility check:
01270   // the dimension of `cg' can not be greater than space_dim.
01271   if (space_dim < cg.space_dimension())
01272     throw_dimension_incompatible("add_congruence(cg)", "cg", cg);
01273 
01274   // Handle the case of proper congruences first.
01275   if (cg.is_proper_congruence()) {
01276     if (cg.is_tautological())
01277       return;
01278     if (cg.is_inconsistent()) {
01279       set_empty();
01280       return;
01281     }
01282     // Non-trivial and proper congruences are not allowed.
01283     throw_invalid_argument("add_congruence(cg)",
01284                            "cg is a non-trivial, proper congruence");
01285   }
01286 
01287   PPL_ASSERT(cg.is_equality());
01288   // Handle empty and 0-dim cases first.
01289   if (marked_empty())
01290     return;
01291   if (space_dim == 0) {
01292     if (cg.is_inconsistent())
01293       set_empty();
01294     return;
01295   }
01296 
01297   // Add the equality.
01298   Linear_Expression le(cg);
01299   Constraint c(le, Constraint::EQUALITY, NECESSARILY_CLOSED);
01300   // Enforce normalization.
01301   c.strong_normalize();
01302   refine_no_check(c);
01303 }
01304 
01305 void
01306 PPL::Polyhedron::add_generator(const Generator& g) {
01307   // Topology-compatibility check.
01308   if (g.is_closure_point() && is_necessarily_closed())
01309     throw_topology_incompatible("add_generator(g)", "g", g);
01310   // Dimension-compatibility check:
01311   // the dimension of `g' can not be greater than space_dim.
01312   const dimension_type g_space_dim = g.space_dimension();
01313   if (space_dim < g_space_dim)
01314     throw_dimension_incompatible("add_generator(g)", "g", g);
01315 
01316   // Dealing with a zero-dimensional space polyhedron first.
01317   if (space_dim == 0) {
01318     // It is not possible to create 0-dim rays or lines.
01319     PPL_ASSERT(g.is_point() || g.is_closure_point());
01320     // Closure points can only be inserted in non-empty polyhedra.
01321     if (marked_empty()) {
01322       if (g.type() != Generator::POINT)
01323         throw_invalid_generator("add_generator(g)", "g");
01324       else
01325         set_zero_dim_univ();
01326     }
01327     PPL_ASSERT_HEAVY(OK());
01328     return;
01329   }
01330 
01331   if (marked_empty()
01332       || (has_pending_constraints() && !process_pending_constraints())
01333       || (!generators_are_up_to_date() && !update_generators())) {
01334     // Here the polyhedron is empty:
01335     // the specification says we can only insert a point.
01336     if (!g.is_point())
01337       throw_invalid_generator("add_generator(g)", "g");
01338     if (g.is_necessarily_closed() || !is_necessarily_closed()) {
01339       gen_sys.insert(g);
01340       // Since `gen_sys' was empty, after inserting `g' we have to resize
01341       // the system of generators to have the right dimension.
01342       gen_sys.adjust_topology_and_space_dimension(topology(), space_dim);
01343       if (!is_necessarily_closed()) {
01344         // In the NNC topology, each point has to be matched by
01345         // a corresponding closure point:
01346         // turn the just inserted point into the corresponding
01347         // (normalized) closure point.
01348         Generator& cp = gen_sys[gen_sys.num_rows() - 1];
01349         cp[space_dim + 1] = 0;
01350         cp.normalize();
01351         // Re-insert the point (which is already normalized).
01352         gen_sys.insert(g);
01353       }
01354     }
01355     else {
01356       // Note: here we have a _legal_ topology mismatch,
01357       // because `g' is NOT a closure point (it is a point!)
01358       // However, by barely invoking `gen_sys.insert(g)' we would
01359       // cause a change in the topology of `gen_sys', which is wrong.
01360       // Thus, we insert a "topology corrected" copy of `g'.
01361       const Linear_Expression nc_expr = Linear_Expression(g);
01362       gen_sys.insert(Generator::point(nc_expr, g.divisor()));
01363       // Since `gen_sys' was empty, after inserting `g' we have to resize
01364       // the system of generators to have the right dimension.
01365       gen_sys.adjust_topology_and_space_dimension(topology(), space_dim);
01366     }
01367     // No longer empty, generators up-to-date and minimized.
01368     clear_empty();
01369     set_generators_minimized();
01370   }
01371   else {
01372     PPL_ASSERT(generators_are_up_to_date());
01373     const bool has_pending = can_have_something_pending();
01374     if (g.is_necessarily_closed() || !is_necessarily_closed()) {
01375       // Since `gen_sys' is not empty, the topology and space dimension
01376       // of the inserted generator are automatically adjusted.
01377       if (has_pending)
01378         gen_sys.insert_pending(g);
01379       else
01380         gen_sys.insert(g);
01381       if (!is_necessarily_closed() && g.is_point()) {
01382         // In the NNC topology, each point has to be matched by
01383         // a corresponding closure point:
01384         // turn the just inserted point into the corresponding
01385         // (normalized) closure point.
01386         Generator& cp = gen_sys[gen_sys.num_rows() - 1];
01387         cp[space_dim + 1] = 0;
01388         cp.normalize();
01389         // Re-insert the point (which is already normalized).
01390         if (has_pending)
01391           gen_sys.insert_pending(g);
01392         else
01393           gen_sys.insert(g);
01394       }
01395     }
01396     else {
01397       PPL_ASSERT(!g.is_closure_point());
01398       // Note: here we have a _legal_ topology mismatch, because
01399       // `g' is NOT a closure point.
01400       // However, by barely invoking `gen_sys.insert(g)' we would
01401       // cause a change in the topology of `gen_sys', which is wrong.
01402       // Thus, we insert a "topology corrected" copy of `g'.
01403       const Linear_Expression nc_expr = Linear_Expression(g);
01404       switch (g.type()) {
01405       case Generator::LINE:
01406         if (has_pending)
01407           gen_sys.insert_pending(Generator::line(nc_expr));
01408         else
01409           gen_sys.insert(Generator::line(nc_expr));
01410         break;
01411       case Generator::RAY:
01412         if (has_pending)
01413           gen_sys.insert_pending(Generator::ray(nc_expr));
01414         else
01415           gen_sys.insert(Generator::ray(nc_expr));
01416         break;
01417       case Generator::POINT:
01418         if (has_pending)
01419           gen_sys.insert_pending(Generator::point(nc_expr, g.divisor()));
01420         else
01421           gen_sys.insert(Generator::point(nc_expr, g.divisor()));
01422         break;
01423       case Generator::CLOSURE_POINT:
01424         PPL_UNREACHABLE;
01425         break;
01426       }
01427     }
01428 
01429     if (has_pending)
01430       set_generators_pending();
01431     else {
01432       // After adding the new generator,
01433       // constraints are no longer up-to-date.
01434       clear_generators_minimized();
01435       clear_constraints_up_to_date();
01436     }
01437   }
01438   PPL_ASSERT_HEAVY(OK());
01439 }
01440 
01441 void
01442 PPL::Polyhedron::add_recycled_constraints(Constraint_System& cs) {
01443   // Topology compatibility check.
01444   if (is_necessarily_closed() && cs.has_strict_inequalities()) {
01445     // We check if _all_ strict inequalities in cs are trivially false.
01446     // (The iterators already filter away trivially true constraints.)
01447     for (Constraint_System::const_iterator i = cs.begin(),
01448            i_end = cs.end(); i != i_end; ++i) {
01449       if (i->is_strict_inequality()
01450           && !i->is_inconsistent())
01451         throw_topology_incompatible("add_recycled_constraints(cs)",
01452                                     "cs", cs);
01453     }
01454     // If we reach this point, all strict inequalities were inconsistent.
01455     set_empty();
01456     return;
01457   }
01458 
01459   // Dimension-compatibility check:
01460   // the dimension of `cs' can not be greater than space_dim.
01461   const dimension_type cs_space_dim = cs.space_dimension();
01462   if (space_dim < cs_space_dim)
01463     throw_dimension_incompatible("add_recycled_constraints(cs)", "cs", cs);
01464 
01465   // Adding no constraints is a no-op.
01466   if (cs.has_no_rows())
01467     return;
01468 
01469   if (space_dim == 0) {
01470     // In a 0-dimensional space the constraints are
01471     // tautologies (e.g., 0 == 0 or 1 >= 0 or 1 > 0) or
01472     // inconsistent (e.g., 1 == 0 or -1 >= 0 or 0 > 0).
01473     // In a system of constraints `begin()' and `end()' are equal
01474     // if and only if the system only contains tautologies.
01475     if (cs.begin() != cs.end())
01476       // There is a constraint, it must be inconsistent,
01477       // the polyhedron is empty.
01478       status.set_empty();
01479     return;
01480   }
01481 
01482   if (marked_empty())
01483     return;
01484 
01485   // The constraints (possibly with pending rows) are required.
01486   if (has_pending_generators())
01487     process_pending_generators();
01488   else if (!constraints_are_up_to_date())
01489     update_constraints();
01490 
01491   // Adjust `cs' to the right topology and space dimension.
01492   // NOTE: we already checked for topology compatibility.
01493   cs.adjust_topology_and_space_dimension(topology(), space_dim);
01494 
01495   const bool adding_pending = can_have_something_pending();
01496 
01497   // Here we do not require `con_sys' to be sorted.
01498   // also, we _swap_ (instead of copying) the coefficients of `cs'
01499   // (which is not a const).
01500   const dimension_type old_num_rows = con_sys.num_rows();
01501   const dimension_type cs_num_rows = cs.num_rows();
01502   const dimension_type cs_num_columns = cs.num_columns();
01503   con_sys.add_zero_rows(cs_num_rows,
01504                         Linear_Row::Flags(topology(),
01505                                           Linear_Row::RAY_OR_POINT_OR_INEQUALITY));
01506   for (dimension_type i = cs_num_rows; i-- > 0; ) {
01507     // NOTE: we cannot directly swap the rows, since they might have
01508     // different capacities (besides possibly having different sizes):
01509     // thus, we steal one coefficient at a time.
01510     Constraint& new_c = con_sys[old_num_rows + i];
01511     Constraint& old_c = cs[i];
01512     if (old_c.is_equality())
01513       new_c.set_is_equality();
01514     using std::swap;
01515     for (dimension_type j = cs_num_columns; j-- > 0; )
01516       swap(new_c[j], old_c[j]);
01517   }
01518 
01519   if (adding_pending)
01520     set_constraints_pending();
01521   else {
01522     // The newly added ones are not pending constraints.
01523     con_sys.unset_pending_rows();
01524     // They have been simply appended.
01525     con_sys.set_sorted(false);
01526     // Constraints are not minimized and generators are not up-to-date.
01527     clear_constraints_minimized();
01528     clear_generators_up_to_date();
01529   }
01530   // Note: the constraint system may have become unsatisfiable, thus
01531   // we do not check for satisfiability.
01532   PPL_ASSERT_HEAVY(OK());
01533 }
01534 
01535 void
01536 PPL::Polyhedron::add_constraints(const Constraint_System& cs) {
01537   // TODO: this is just an executable specification.
01538   Constraint_System cs_copy = cs;
01539   add_recycled_constraints(cs_copy);
01540 }
01541 
01542 void
01543 PPL::Polyhedron::add_recycled_generators(Generator_System& gs) {
01544   // Topology compatibility check.
01545   if (is_necessarily_closed() && gs.has_closure_points())
01546     throw_topology_incompatible("add_recycled_generators(gs)", "gs", gs);
01547   // Dimension-compatibility check:
01548   // the dimension of `gs' can not be greater than space_dim.
01549   const dimension_type gs_space_dim = gs.space_dimension();
01550   if (space_dim < gs_space_dim)
01551     throw_dimension_incompatible("add_recycled_generators(gs)", "gs", gs);
01552 
01553   // Adding no generators is a no-op.
01554   if (gs.has_no_rows())
01555     return;
01556 
01557   // Adding valid generators to a zero-dimensional polyhedron
01558   // transform it in the zero-dimensional universe polyhedron.
01559   if (space_dim == 0) {
01560     if (marked_empty() && !gs.has_points())
01561       throw_invalid_generators("add_recycled_generators(gs)", "gs");
01562     set_zero_dim_univ();
01563     PPL_ASSERT_HEAVY(OK(true));
01564     return;
01565   }
01566 
01567   // Adjust `gs' to the right topology and dimensions.
01568   // NOTE: we already checked for topology compatibility.
01569   gs.adjust_topology_and_space_dimension(topology(), space_dim);
01570   // For NNC polyhedra, each point must be matched by
01571   // the corresponding closure point.
01572   if (!is_necessarily_closed())
01573     gs.add_corresponding_closure_points();
01574 
01575   // The generators (possibly with pending rows) are required.
01576   if ((has_pending_constraints() && !process_pending_constraints())
01577       || (!generators_are_up_to_date() && !minimize())) {
01578     // We have just discovered that `*this' is empty.
01579     // So `gs' must contain at least one point.
01580     if (!gs.has_points())
01581       throw_invalid_generators("add_recycled_generators(gs)", "gs");
01582     // The polyhedron is no longer empty and generators are up-to-date.
01583     using std::swap;
01584     swap(gen_sys, gs);
01585     if (gen_sys.num_pending_rows() > 0) {
01586       // Even though `gs' has pending generators, since the constraints
01587       // of the polyhedron are not up-to-date, the polyhedron cannot
01588       // have pending generators. By integrating the pending part
01589       // of `gen_sys' we may loose sortedness.
01590       gen_sys.unset_pending_rows();
01591       gen_sys.set_sorted(false);
01592     }
01593     set_generators_up_to_date();
01594     clear_empty();
01595     PPL_ASSERT_HEAVY(OK());
01596     return;
01597   }
01598 
01599   const bool adding_pending = can_have_something_pending();
01600 
01601   // Here we do not require `gen_sys' to be sorted.
01602   // also, we _swap_ (instead of copying) the coefficients of `gs'
01603   // (which is not a const).
01604   const dimension_type old_num_rows = gen_sys.num_rows();
01605   const dimension_type gs_num_rows = gs.num_rows();
01606   const dimension_type gs_num_columns = gs.num_columns();
01607   gen_sys.add_zero_rows(gs_num_rows,
01608                         Linear_Row::Flags(topology(),
01609                                           Linear_Row::RAY_OR_POINT_OR_INEQUALITY));
01610   for (dimension_type i = gs_num_rows; i-- > 0; ) {
01611     // NOTE: we cannot directly swap the rows, since they might have
01612     // different capacities (besides possibly having different sizes):
01613     // thus, we steal one coefficient at a time.
01614     Generator& new_g = gen_sys[old_num_rows + i];
01615     Generator& old_g = gs[i];
01616     if (old_g.is_line())
01617       new_g.set_is_line();
01618     using std::swap;
01619     for (dimension_type j = gs_num_columns; j-- > 0; )
01620       swap(new_g[j], old_g[j]);
01621   }
01622 
01623   if (adding_pending)
01624     set_generators_pending();
01625   else {
01626     // The newly added ones are not pending generators.
01627     gen_sys.unset_pending_rows();
01628     // They have been simply appended.
01629     gen_sys.set_sorted(false);
01630     // Constraints are not up-to-date and generators are not minimized.
01631     clear_constraints_up_to_date();
01632     clear_generators_minimized();
01633   }
01634   PPL_ASSERT_HEAVY(OK(true));
01635 }
01636 
01637 void
01638 PPL::Polyhedron::add_generators(const Generator_System& gs) {
01639   // TODO: this is just an executable specification.
01640   Generator_System gs_copy = gs;
01641   add_recycled_generators(gs_copy);
01642 }
01643 
01644 void
01645 PPL::Polyhedron::add_congruences(const Congruence_System& cgs) {
01646   // Dimension-compatibility check.
01647   if (space_dim < cgs.space_dimension())
01648     throw_dimension_incompatible("add_congruences(cgs)", "cgs", cgs);
01649 
01650   Constraint_System cs;
01651   bool inserted = false;
01652   for (Congruence_System::const_iterator i = cgs.begin(),
01653          cgs_end = cgs.end(); i != cgs_end; ++i) {
01654     const Congruence& cg = *i;
01655     if (cg.is_equality()) {
01656       Linear_Expression le(cg);
01657       Constraint c(le, Constraint::EQUALITY, NECESSARILY_CLOSED);
01658       // Enforce normalization.
01659       c.strong_normalize();
01660       // TODO: Consider stealing the row in c when adding it to cs.
01661       cs.insert(c);
01662       inserted = true;
01663     }
01664     else {
01665       PPL_ASSERT(cg.is_proper_congruence());
01666       if (cg.is_inconsistent()) {
01667         set_empty();
01668         return;
01669       }
01670       if (!cg.is_tautological())
01671         throw_invalid_argument("add_congruences(cgs)",
01672                                "cgs has a non-trivial, proper congruence");
01673     }
01674   }
01675   // Only add cs if it contains something.
01676   if (inserted)
01677     add_recycled_constraints(cs);
01678 }
01679 
01680 void
01681 PPL::Polyhedron::refine_with_constraint(const Constraint& c) {
01682   // Dimension-compatibility check.
01683   if (space_dim < c.space_dimension())
01684     throw_dimension_incompatible("refine_with_constraint(c)", "c", c);
01685   // If the polyhedron is known to be empty, do nothing.
01686   if (!marked_empty())
01687     refine_no_check(c);
01688 }
01689 
01690 void
01691 PPL::Polyhedron::refine_with_congruence(const Congruence& cg) {
01692   // Dimension-compatibility check.
01693   if (space_dim < cg.space_dimension())
01694     throw_dimension_incompatible("refine_with_congruence(cg)", "cg", cg);
01695 
01696   // If the polyhedron is known to be empty, do nothing.
01697   if (marked_empty())
01698     return;
01699 
01700   // Dealing with a zero-dimensional space polyhedron first.
01701   if (space_dim == 0) {
01702     if (!cg.is_tautological())
01703       set_empty();
01704     return;
01705   }
01706 
01707   if (cg.is_equality()) {
01708     Linear_Expression le(cg);
01709     Constraint c(le, Constraint::EQUALITY, NECESSARILY_CLOSED);
01710     // Enforce normalization.
01711     c.strong_normalize();
01712     refine_no_check(c);
01713   }
01714 }
01715 
01716 void
01717 PPL::Polyhedron::refine_with_constraints(const Constraint_System& cs) {
01718   // TODO: this is just an executable specification.
01719 
01720   // Dimension-compatibility check.
01721   const dimension_type cs_space_dim = cs.space_dimension();
01722   if (space_dim < cs_space_dim)
01723     throw_dimension_incompatible("refine_with_constraints(cs)a",
01724                                  "cs", cs);
01725 
01726   // Adding no constraints is a no-op.
01727   if (cs.has_no_rows())
01728     return;
01729 
01730   if (space_dim == 0) {
01731     // In a 0-dimensional space the constraints are
01732     // tautologies (e.g., 0 == 0 or 1 >= 0 or 1 > 0) or
01733     // inconsistent (e.g., 1 == 0 or -1 >= 0 or 0 > 0).
01734     // In a system of constraints `begin()' and `end()' are equal
01735     // if and only if the system only contains tautologies.
01736     if (cs.begin() != cs.end())
01737       // There is a constraint, it must be inconsistent,
01738       // the polyhedron is empty.
01739       status.set_empty();
01740     return;
01741   }
01742 
01743   if (marked_empty())
01744     return;
01745 
01746   // The constraints (possibly with pending rows) are required.
01747   if (has_pending_generators())
01748     process_pending_generators();
01749   else if (!constraints_are_up_to_date())
01750     update_constraints();
01751 
01752   const bool adding_pending = can_have_something_pending();
01753   for (dimension_type i = cs.num_rows(); i-- > 0; ) {
01754     const Constraint& c = cs[i];
01755 
01756     if (c.is_necessarily_closed() || !is_necessarily_closed())
01757       // Since `con_sys' is not empty, the topology and space dimension
01758       // of the inserted constraint are automatically adjusted.
01759       if (adding_pending)
01760         con_sys.insert_pending(c);
01761       else
01762         con_sys.insert(c);
01763     else {
01764       // Here we know that *this is necessarily closed so even if c is
01765       // topologically closed, by barely invoking `con_sys.insert(c)' we
01766       // would cause a change in the topology of `con_sys', which is
01767       // wrong.  Thus, we insert a topology closed and "topology
01768       // corrected" version of `c'.
01769       Linear_Expression nc_expr = Linear_Expression(c);
01770       if (c.is_equality())
01771         if (adding_pending)
01772           con_sys.insert_pending(nc_expr == 0);
01773         else
01774           con_sys.insert(nc_expr == 0);
01775       else
01776         if (adding_pending)
01777           con_sys.insert_pending(nc_expr >= 0);
01778         else
01779           con_sys.insert(nc_expr >= 0);
01780     }
01781   }
01782 
01783   if (adding_pending)
01784     set_constraints_pending();
01785   else {
01786     // Constraints are not minimized and generators are not up-to-date.
01787     clear_constraints_minimized();
01788     clear_generators_up_to_date();
01789   }
01790 
01791   // Note: the constraint system may have become unsatisfiable, thus
01792   // we do not check for satisfiability.
01793   PPL_ASSERT_HEAVY(OK());
01794 }
01795 
01796 void
01797 PPL::Polyhedron::refine_with_congruences(const Congruence_System& cgs) {
01798   // Dimension-compatibility check.
01799   if (space_dim < cgs.space_dimension())
01800     throw_dimension_incompatible("refine_with_congruences(cgs)", "cgs", cgs);
01801 
01802   Constraint_System cs;
01803   bool inserted = false;
01804   for (Congruence_System::const_iterator i = cgs.begin(),
01805          cgs_end = cgs.end(); i != cgs_end; ++i) {
01806     if (i->is_equality()) {
01807       Linear_Expression le(*i);
01808       Constraint c(le, Constraint::EQUALITY, NECESSARILY_CLOSED);
01809       // Enforce normalization.
01810       c.strong_normalize();
01811       // TODO: Consider stealing the row in c when adding it to cs.
01812       cs.insert(c);
01813       inserted = true;
01814     }
01815     else if (i->is_inconsistent()) {
01816       set_empty();
01817       return;
01818     }
01819   }
01820   // Only add cgs if congruences were inserted into cgs, as the
01821   // dimension of cs must be at most that of the polyhedron.
01822   if (inserted)
01823     add_recycled_constraints(cs);
01824 }
01825 
01826 void
01827 PPL::Polyhedron::unconstrain(const Variable var) {
01828   // Dimension-compatibility check.
01829   if (space_dim < var.space_dimension())
01830     throw_dimension_incompatible("unconstrain(var)", var.space_dimension());
01831 
01832   // Do something only if the polyhedron is non-empty.
01833   if (marked_empty()
01834       || (has_pending_constraints() && !process_pending_constraints())
01835       || (!generators_are_up_to_date() && !update_generators()))
01836     // Empty: do nothing.
01837     return;
01838 
01839   PPL_ASSERT(generators_are_up_to_date());
01840   // Since `gen_sys' is not empty, the topology and space dimension
01841   // of the inserted generator are automatically adjusted.
01842   if (can_have_something_pending()) {
01843     gen_sys.insert_pending(Generator::line(var));
01844     set_generators_pending();
01845   }
01846   else {
01847     gen_sys.insert(Generator::line(var));
01848     // After adding the new generator,
01849     // constraints are no longer up-to-date.
01850     clear_generators_minimized();
01851     clear_constraints_up_to_date();
01852   }
01853   PPL_ASSERT_HEAVY(OK(true));
01854 }
01855 
01856 void
01857 PPL::Polyhedron::unconstrain(const Variables_Set& vars) {
01858   // The cylindrification with respect to no dimensions is a no-op.
01859   // This case also captures the only legal cylindrification
01860   // of a polyhedron in a 0-dim space.
01861   if (vars.empty())
01862     return;
01863 
01864   // Dimension-compatibility check.
01865   const dimension_type min_space_dim = vars.space_dimension();
01866   if (space_dim < min_space_dim)
01867     throw_dimension_incompatible("unconstrain(vs)", min_space_dim);
01868 
01869   // Do something only if the polyhedron is non-empty.
01870   if (marked_empty()
01871       || (has_pending_constraints() && !process_pending_constraints())
01872       || (!generators_are_up_to_date() && !update_generators()))
01873     // Empty: do nothing.
01874     return;
01875 
01876   PPL_ASSERT(generators_are_up_to_date());
01877   // Since `gen_sys' is not empty, the topology and space dimension
01878   // of the inserted generators are automatically adjusted.
01879   Variables_Set::const_iterator vsi = vars.begin();
01880   Variables_Set::const_iterator vsi_end = vars.end();
01881   if (can_have_something_pending()) {
01882     for ( ; vsi != vsi_end; ++vsi)
01883       gen_sys.insert_pending(Generator::line(Variable(*vsi)));
01884     set_generators_pending();
01885   }
01886   else {
01887     for ( ; vsi != vsi_end; ++vsi)
01888       gen_sys.insert(Generator::line(Variable(*vsi)));
01889     // After adding the new generators,
01890     // constraints are no longer up-to-date.
01891     clear_generators_minimized();
01892     clear_constraints_up_to_date();
01893   }
01894   PPL_ASSERT_HEAVY(OK(true));
01895 }
01896 
01897 void
01898 PPL::Polyhedron::intersection_assign(const Polyhedron& y) {
01899   Polyhedron& x = *this;
01900   // Topology compatibility check.
01901   if (x.topology() != y.topology())
01902     throw_topology_incompatible("intersection_assign(y)", "y", y);
01903   // Dimension-compatibility check.
01904   if (x.space_dim != y.space_dim)
01905     throw_dimension_incompatible("intersection_assign(y)", "y", y);
01906 
01907   // If one of the two polyhedra is empty, the intersection is empty.
01908   if (x.marked_empty())
01909     return;
01910   if (y.marked_empty()) {
01911     x.set_empty();
01912     return;
01913   }
01914 
01915   // If both polyhedra are zero-dimensional,
01916   // then at this point they are necessarily non-empty,
01917   // so that their intersection is non-empty too.
01918   if (x.space_dim == 0)
01919     return;
01920 
01921   // Both systems of constraints have to be up-to-date,
01922   // possibly having pending constraints.
01923   if (x.has_pending_generators())
01924     x.process_pending_generators();
01925   else if (!x.constraints_are_up_to_date())
01926     x.update_constraints();
01927 
01928   if (y.has_pending_generators())
01929     y.process_pending_generators();
01930   else if (!y.constraints_are_up_to_date())
01931     y.update_constraints();
01932 
01933   // Here both systems are up-to-date and possibly have pending constraints
01934   // (but they cannot have pending generators).
01935   PPL_ASSERT(!x.has_pending_generators() && x.constraints_are_up_to_date());
01936   PPL_ASSERT(!y.has_pending_generators() && y.constraints_are_up_to_date());
01937 
01938   // If `x' can support pending constraints,
01939   // the constraints of `y' are added as pending constraints of `x'.
01940   if (x.can_have_something_pending()) {
01941     x.con_sys.add_pending_rows(y.con_sys);
01942     x.set_constraints_pending();
01943   }
01944   else {
01945     // `x' cannot support pending constraints.
01946     // If both constraint systems are (fully) sorted, then we can
01947     // merge them; otherwise we simply add the second to the first.
01948     if (x.con_sys.is_sorted()
01949         && y.con_sys.is_sorted() && !y.has_pending_constraints())
01950       x.con_sys.merge_rows_assign(y.con_sys);
01951     else
01952       x.con_sys.add_rows(y.con_sys);
01953     // Generators are no longer up-to-date and constraints are no
01954     // longer minimized.
01955     x.clear_generators_up_to_date();
01956     x.clear_constraints_minimized();
01957   }
01958   PPL_ASSERT_HEAVY(x.OK() && y.OK());
01959 }
01960 
01961 namespace {
01962 
01963 struct Ruled_Out_Pair {
01964   PPL::dimension_type constraint_index;
01965   PPL::dimension_type num_ruled_out;
01966 };
01967 
01968 struct Ruled_Out_Less_Than {
01969   bool operator()(const Ruled_Out_Pair& x,
01970                   const Ruled_Out_Pair& y) const {
01971     return x.num_ruled_out > y.num_ruled_out;
01972   }
01973 };
01974 
01975 bool
01976 add_to_system_and_check_independence(PPL::Linear_System& eq_sys,
01977                                      const PPL::Linear_Row& eq) {
01978   // Check if eq is linearly independent from eq_sys.
01979   PPL_ASSERT(eq.is_line_or_equality());
01980   eq_sys.insert(eq);
01981   const PPL::dimension_type eq_sys_num_rows = eq_sys.num_rows();
01982   const PPL::dimension_type rank = eq_sys.gauss(eq_sys_num_rows);
01983   if (rank == eq_sys_num_rows)
01984     // eq is linearly independent from eq_sys.
01985     return true;
01986   else {
01987     // eq is not linearly independent from eq_sys.
01988     PPL_ASSERT(rank == eq_sys_num_rows - 1);
01989     eq_sys.remove_trailing_rows(1);
01990     return false;
01991   }
01992 }
01993 
01994 /*
01995   Modifies the vector of pointers \p ineqs_p, setting to 0 those entries
01996   that point to redundant inequalities or masked equalities.
01997   The redundancy test is based on saturation matrix \p sat and
01998   on knowing that there exists \p rank non-redundant equalities
01999   (they are implicit, i.e., not explicitly listed in \p ineqs_p).
02000 */
02001 void
02002 drop_redundant_inequalities(std::vector<const PPL::Constraint*>& ineqs_p,
02003                             const PPL::Topology topology,
02004                             const PPL::Bit_Matrix& sat,
02005                             const PPL::dimension_type rank) {
02006   using namespace Parma_Polyhedra_Library;
02007   const dimension_type num_rows = ineqs_p.size();
02008   PPL_ASSERT(num_rows > 0);
02009   // `rank' is the rank of the (implicit) system of equalities.
02010   const dimension_type space_dim = ineqs_p[0]->space_dimension();
02011   PPL_ASSERT(space_dim > 0 && space_dim >= rank);
02012   const dimension_type num_coefficients
02013     = space_dim + ((topology == NECESSARILY_CLOSED) ? 0U : 1U);
02014   const dimension_type min_sat = num_coefficients - rank;
02015   const dimension_type num_cols_sat = sat.num_columns();
02016 
02017   // Perform quick redundancy test based on the number of saturators.
02018   for (dimension_type i = num_rows; i-- > 0; ) {
02019     if (sat[i].empty())
02020       // Masked equalities are redundant.
02021       ineqs_p[i] = 0;
02022     else {
02023       const dimension_type num_sat = num_cols_sat - sat[i].count_ones();
02024       if (num_sat < min_sat)
02025         ineqs_p[i] = 0;
02026     }
02027   }
02028 
02029   // Re-examine remaining inequalities.
02030   // Iteration index `i' is _intentionally_ increasing.
02031   for (dimension_type i = 0; i < num_rows; ++i) {
02032     if (ineqs_p[i] != 0) {
02033       for (dimension_type j = 0; j < num_rows; ++j) {
02034         bool strict_subset;
02035         if (ineqs_p[j] != 0 && i != j
02036             && subset_or_equal(sat[j], sat[i], strict_subset)) {
02037           if (strict_subset) {
02038             ineqs_p[i] = 0;
02039             break;
02040           }
02041           else
02042             // Here `sat[j] == sat[i]'.
02043             ineqs_p[j] = 0;
02044         }
02045       }
02046     }
02047   }
02048 }
02049 
02050 } // namespace
02051 
02052 bool
02053 PPL::Polyhedron::simplify_using_context_assign(const Polyhedron& y) {
02054   Polyhedron& x = *this;
02055   // Topology compatibility check.
02056   if (x.topology() != y.topology())
02057     throw_topology_incompatible("simplify_using_context_assign(y)", "y", y);
02058   // Dimension-compatibility check.
02059   if (x.space_dim != y.space_dim)
02060     throw_dimension_incompatible("simplify_using_context_assign(y)", "y", y);
02061 
02062   // Filter away the zero-dimensional case.
02063   if (x.space_dim == 0) {
02064     if (y.is_empty()) {
02065       x.set_zero_dim_univ();
02066       return false;
02067     }
02068     else
02069       return !x.is_empty();
02070   }
02071 
02072   // If `y' is empty, the biggest enlargement for `x' is the universe.
02073   if (!y.minimize()) {
02074     Polyhedron ph(x.topology(), x.space_dim, UNIVERSE);
02075     m_swap(ph);
02076     return false;
02077   }
02078 
02079   // If `x' is empty, the intersection is empty.
02080   if (!x.minimize()) {
02081     // Search for a constraint of `y' that is not a tautology.
02082     PPL_ASSERT(!y.has_pending_generators() && y.constraints_are_up_to_date());
02083     for (dimension_type i = y.con_sys.num_rows(); i-- > 0; ) {
02084       const Constraint& y_con_sys_i = y.con_sys[i];
02085       if (!y_con_sys_i.is_tautological()) {
02086         // Found: we obtain a constraint `c' contradicting the one we
02087         // found, and assign to `x' the polyhedron `ph' with `c' as
02088         // the only constraint.
02089         Polyhedron ph(x.topology(), x.space_dim, UNIVERSE);
02090         Linear_Expression le(y_con_sys_i);
02091         switch (y_con_sys_i.type()) {
02092         case Constraint::EQUALITY:
02093           ph.refine_no_check(le == 1);
02094           break;
02095         case Constraint::NONSTRICT_INEQUALITY:
02096           ph.refine_no_check(le <= -1);
02097           break;
02098         case Constraint::STRICT_INEQUALITY:
02099           ph.refine_no_check(le == 0);
02100           break;
02101         }
02102         m_swap(ph);
02103         PPL_ASSERT_HEAVY(OK());
02104         return false;
02105       }
02106     }
02107     // `y' is the universe: `x' cannot be enlarged.
02108     return false;
02109   }
02110 
02111   PPL_ASSERT(x.constraints_are_minimized()
02112          && !x.has_something_pending()
02113          && y.generators_are_minimized()
02114          && !y.has_something_pending());
02115   const Constraint_System& x_cs = x.con_sys;
02116   const dimension_type x_cs_num_rows = x_cs.num_rows();
02117   const Generator_System& y_gs = y.gen_sys;
02118 
02119   // Record into `redundant_by_y' the info about which constraints of
02120   // `x' are redundant in the context `y'.  Count the number of
02121   // redundancies found.
02122   std::vector<bool> redundant_by_y(x_cs_num_rows, false);
02123   dimension_type num_redundant_by_y = 0;
02124   for (dimension_type i = 0; i < x_cs_num_rows; ++i)
02125     if (y_gs.satisfied_by_all_generators(x_cs[i])) {
02126       redundant_by_y[i] = true;
02127       ++num_redundant_by_y;
02128     }
02129 
02130   Constraint_System result_cs;
02131 
02132   if (num_redundant_by_y < x_cs_num_rows) {
02133     // Some constraints were not identified as redundant (yet?).
02134     const Constraint_System& y_cs = y.con_sys;
02135     const dimension_type y_cs_num_rows = y_cs.num_rows();
02136     // Compute into `z' the minimized intersection of `x' and `y'.
02137     const bool x_first = (x_cs_num_rows > y_cs_num_rows);
02138     Polyhedron z(x_first ? x : y);
02139     if (x_first)
02140       z.add_constraints(y_cs);
02141     else {
02142       // Only copy (and then recycle) the non-redundant constraints.
02143       Constraint_System tmp_cs;
02144       for (dimension_type i = 0; i < x_cs_num_rows; ++i) {
02145         if (!redundant_by_y[i])
02146           tmp_cs.insert(x_cs[i]);
02147       }
02148       z.add_recycled_constraints(tmp_cs);
02149     }
02150     if (!z.minimize()) {
02151       // The objective function is the default, zero.
02152       // We do not care about minimization or maximization, since
02153       // we are only interested in satisfiability.
02154       MIP_Problem lp;
02155       if (x.is_necessarily_closed()) {
02156         lp.add_space_dimensions_and_embed(x.space_dim);
02157         lp.add_constraints(y_cs);
02158       }
02159       else {
02160         // KLUDGE: temporarily mark `y_cs' if it was necessarily
02161         // closed, so that we can interpret the epsilon dimension as a
02162         // standard dimension. Be careful to reset the topology of `cs'
02163         // even on exceptional execution path.
02164         const_cast<Constraint_System&>(y_cs).set_necessarily_closed();
02165         try {
02166           lp.add_space_dimensions_and_embed(x.space_dim+1);
02167           lp.add_constraints(y_cs);
02168           const_cast<Constraint_System&>(y_cs).set_not_necessarily_closed();
02169         }
02170         catch (...) {
02171           const_cast<Constraint_System&>(y_cs).set_not_necessarily_closed();
02172           throw;
02173         }
02174       }
02175       // We apply the following heuristics here: constraints of `x' that
02176       // are not made redundant by `y' are added to `lp' depending on
02177       // the number of generators of `y' they rule out (the more generators
02178       // they rule out, the sooner they are added).  Of course, as soon
02179       // as `lp' becomes unsatisfiable, we stop adding.
02180       std::vector<Ruled_Out_Pair>
02181         ruled_out_vec(x_cs_num_rows - num_redundant_by_y);
02182       for (dimension_type i = 0, j = 0; i < x_cs_num_rows; ++i) {
02183         if (!redundant_by_y[i]) {
02184           const Constraint& c = x_cs[i];
02185           Topology_Adjusted_Scalar_Product_Sign sps(c);
02186           dimension_type num_ruled_out_generators = 0;
02187           for (Generator_System::const_iterator k = y_gs.begin(),
02188                  y_gs_end = y_gs.end(); k != y_gs_end; ++k) {
02189             const Generator& g = *k;
02190             const int sp_sign = sps(g, c);
02191             if (x.is_necessarily_closed()) {
02192               if (g.is_line()) {
02193                 // Lines must saturate the constraint.
02194                 if (sp_sign != 0)
02195                   goto ruled_out;
02196               }
02197               else {
02198                 // `g' is either a ray, a point or a closure point.
02199                 if (c.is_inequality()) {
02200                   // `c' is a non-strict inequality.
02201                   if (sp_sign < 0)
02202                     goto ruled_out;
02203                 }
02204                 else
02205                   // `c' is an equality.
02206                   if (sp_sign != 0)
02207                     goto ruled_out;
02208               }
02209             }
02210             else
02211               // The topology is not necessarily closed.
02212               switch (g.type()) {
02213               case Generator::LINE:
02214                 // Lines must saturate the constraint.
02215                 if (sp_sign != 0)
02216                   goto ruled_out;
02217                 break;
02218               case Generator::POINT:
02219                 // Have to perform the special test when dealing with
02220                 // a strict inequality.
02221                 switch (c.type()) {
02222                 case Constraint::EQUALITY:
02223                   if (sp_sign != 0)
02224                     goto ruled_out;
02225                   break;
02226                 case Constraint::NONSTRICT_INEQUALITY:
02227                   if (sp_sign < 0)
02228                     goto ruled_out;
02229                   break;
02230                 case Constraint::STRICT_INEQUALITY:
02231                   if (sp_sign <= 0)
02232                     goto ruled_out;
02233                   break;
02234                 }
02235                 break;
02236               case Generator::RAY:
02237                 // Intentionally fall through.
02238               case Generator::CLOSURE_POINT:
02239                 if (c.is_inequality()) {
02240                   // Constraint `c' is either a strict or a non-strict
02241                   // inequality.
02242                   if (sp_sign < 0)
02243                     goto ruled_out;
02244                 }
02245                 else
02246                   // Constraint `c' is an equality.
02247                   if (sp_sign != 0)
02248                     goto ruled_out;
02249                 break;
02250               }
02251 
02252             // If we reach this point, `g' satisfies `c'.
02253             continue;
02254           ruled_out:
02255             ++num_ruled_out_generators;
02256           }
02257           ruled_out_vec[j].constraint_index = i;
02258           ruled_out_vec[j].num_ruled_out = num_ruled_out_generators;
02259           ++j;
02260         }
02261       }
02262       std::sort(ruled_out_vec.begin(), ruled_out_vec.end(),
02263                 Ruled_Out_Less_Than());
02264 
02265       for (std::vector<Ruled_Out_Pair>::const_iterator
02266              j = ruled_out_vec.begin(),
02267              ruled_out_vec_end = ruled_out_vec.end();
02268            j != ruled_out_vec_end;
02269            ++j) {
02270         const Constraint& c = x_cs[j->constraint_index];
02271         result_cs.insert(c);
02272         lp.add_constraint(c);
02273         MIP_Problem_Status status = lp.solve();
02274         if (status == UNFEASIBLE_MIP_PROBLEM) {
02275           Polyhedron result_ph(x.topology(), x.space_dim, UNIVERSE);
02276           result_ph.add_constraints(result_cs);
02277           x.m_swap(result_ph);
02278           PPL_ASSERT_HEAVY(x.OK());
02279           return false;
02280         }
02281       }
02282       // Cannot exit from here.
02283       PPL_UNREACHABLE;
02284     }
02285     else {
02286       // Here `z' is not empty and minimized.
02287       PPL_ASSERT(z.constraints_are_minimized()
02288              && z.generators_are_minimized()
02289              && !z.has_something_pending());
02290       const Constraint_System& z_cs = z.con_sys;
02291       const Generator_System& z_gs = z.gen_sys;
02292       const dimension_type z_gs_num_rows = z_gs.num_rows();
02293 
02294       // Compute the number of equalities in x_cs, y_cs and z_cs
02295       // (exploiting minimal form knowledge).
02296       dimension_type x_cs_num_eq = 0;
02297       while (x_cs[x_cs_num_eq].is_equality())
02298         ++x_cs_num_eq;
02299       dimension_type y_cs_num_eq = 0;
02300       while (y_cs[y_cs_num_eq].is_equality())
02301         ++y_cs_num_eq;
02302       dimension_type z_cs_num_eq = 0;
02303       while (z_cs[z_cs_num_eq].is_equality())
02304         ++z_cs_num_eq;
02305       PPL_ASSERT(x_cs_num_eq <= z_cs_num_eq && y_cs_num_eq <= z_cs_num_eq);
02306 
02307       // Identify non-redundant equalities.
02308       Constraint_System non_redundant_eq;
02309       dimension_type num_non_redundant_eq = 0;
02310       const dimension_type needed_non_redundant_eq = z_cs_num_eq - y_cs_num_eq;
02311       Linear_System eqs(x.topology());
02312       if (needed_non_redundant_eq > 0) {
02313         // Populate eqs with the equalities from y.
02314         for (dimension_type i = 0; i < y_cs_num_eq; ++i)
02315           eqs.insert(y_cs[i]);
02316         // Try to find another `needed_non_redundant_eq' linear independent
02317         // equalities among those from x.
02318         for (dimension_type i = 0; i < x_cs_num_eq; ++i) {
02319           const Constraint& x_cs_i = x_cs[i];
02320           if (add_to_system_and_check_independence(eqs, x_cs_i)) {
02321             // x_cs_i is linear independent.
02322             non_redundant_eq.insert(x_cs_i);
02323             ++num_non_redundant_eq;
02324             if (num_non_redundant_eq == needed_non_redundant_eq)
02325               // Already found all the needed equalities.
02326               break;
02327           }
02328         }
02329         // NOTE: if num_non_redundant_eq < needed_non_redundant_eq
02330         // then we haven't found all the needed equalities yet:
02331         // this means that some inequalities from x actually holds
02332         // as "masked" equalities in the context of y.
02333         PPL_ASSERT(eqs.num_rows() <= z_cs_num_eq);
02334         PPL_ASSERT(num_non_redundant_eq <= needed_non_redundant_eq);
02335         PPL_ASSERT(z_cs_num_eq - eqs.num_rows()
02336                == needed_non_redundant_eq - num_non_redundant_eq);
02337       }
02338 
02339       // Identify non-redundant inequalities.
02340       // Avoid useless copies (no modifications are needed).
02341       std::vector<const Constraint*> non_redundant_ineq_p;
02342       // Fill non_redundant_ineq_p with (pointers to) inequalities
02343       // from y_cs ...
02344       for (dimension_type i = y_cs_num_eq; i < y_cs_num_rows; ++i)
02345         non_redundant_ineq_p.push_back(&y_cs[i]);
02346       // ... and (pointers to) non-redundant inequalities from x_cs.
02347       for (dimension_type i = x_cs_num_eq; i < x_cs_num_rows; ++i)
02348         if (!redundant_by_y[i])
02349           non_redundant_ineq_p.push_back(&x_cs[i]);
02350 
02351       const dimension_type non_redundant_ineq_p_size
02352         = non_redundant_ineq_p.size();
02353       const dimension_type y_cs_num_ineq = y_cs_num_rows - y_cs_num_eq;
02354 
02355       // Compute saturation info.
02356       const dimension_type sat_num_rows = non_redundant_ineq_p_size;
02357       Bit_Matrix sat(sat_num_rows, z_gs_num_rows);
02358       for (dimension_type i = sat_num_rows; i-- > 0; ) {
02359         const Constraint& non_redundant_ineq_i = *(non_redundant_ineq_p[i]);
02360         Bit_Row& sat_i = sat[i];
02361         for (dimension_type j = z_gs_num_rows; j-- > 0; )
02362           if (Scalar_Products::sign(non_redundant_ineq_i, z_gs[j]) != 0)
02363             sat_i.set(j);
02364         if (sat_i.empty() && num_non_redundant_eq < needed_non_redundant_eq) {
02365           // `non_redundant_ineq_i' is actually masking an equality
02366           // and we are still looking for some masked inequalities.
02367           // Iteration goes downwards, so the inequality comes from x_cs.
02368           PPL_ASSERT(i >= y_cs_num_ineq);
02369           // Check if the equality is independent in eqs.
02370           Linear_Row masked_eq = Linear_Row(non_redundant_ineq_i);
02371           masked_eq.set_is_line_or_equality();
02372           masked_eq.sign_normalize();
02373           if (add_to_system_and_check_independence(eqs, masked_eq)) {
02374             // It is independent: add the _inequality_ to non_redundant_eq.
02375             non_redundant_eq.insert(non_redundant_ineq_i);
02376             ++num_non_redundant_eq;
02377           }
02378         }
02379       }
02380       // Here we have already found all the needed (masked) equalities.
02381       PPL_ASSERT(num_non_redundant_eq == needed_non_redundant_eq);
02382 
02383       drop_redundant_inequalities(non_redundant_ineq_p, x.topology(),
02384                                   sat, z_cs_num_eq);
02385 
02386       // Place the non-redundant (masked) equalities into result_cs.
02387       result_cs.m_swap(non_redundant_eq);
02388       // Add to result_cs the non-redundant inequalities from x_cs,
02389       // i.e., those having indices no smaller than y_cs_num_ineq.
02390       for (dimension_type i = y_cs_num_ineq;
02391            i < non_redundant_ineq_p_size;
02392            ++i)
02393         if (non_redundant_ineq_p[i] != 0)
02394           result_cs.insert(*non_redundant_ineq_p[i]);
02395     }
02396   }
02397 
02398   Polyhedron result_ph(x.topology(), x.space_dim, UNIVERSE);
02399   result_ph.add_recycled_constraints(result_cs);
02400   x.m_swap(result_ph);
02401   PPL_ASSERT_HEAVY(x.OK());
02402   return true;
02403 }
02404 
02405 void
02406 PPL::Polyhedron::poly_hull_assign(const Polyhedron& y) {
02407   Polyhedron& x = *this;
02408   // Topology compatibility check.
02409   if (x.topology() != y.topology())
02410     throw_topology_incompatible("poly_hull_assign(y)", "y", y);
02411   // Dimension-compatibility check.
02412   if (x.space_dim != y.space_dim)
02413     throw_dimension_incompatible("poly_hull_assign(y)", "y", y);
02414 
02415   // The poly-hull of a polyhedron `p' with an empty polyhedron is `p'.
02416   if (y.marked_empty())
02417     return;
02418   if (x.marked_empty()) {
02419     x = y;
02420     return;
02421   }
02422 
02423   // If both polyhedra are zero-dimensional,
02424   // then at this point they are necessarily universe polyhedra,
02425   // so that their poly-hull is the universe polyhedron too.
02426   if (x.space_dim == 0)
02427     return;
02428 
02429   // Both systems of generators have to be up-to-date,
02430   // possibly having pending generators.
02431   if ((x.has_pending_constraints() && !x.process_pending_constraints())
02432       || (!x.generators_are_up_to_date() && !x.update_generators())) {
02433     // Discovered `x' empty when updating generators.
02434     x = y;
02435     return;
02436   }
02437   if ((y.has_pending_constraints() && !y.process_pending_constraints())
02438       || (!y.generators_are_up_to_date() && !y.update_generators()))
02439     // Discovered `y' empty when updating generators.
02440     return;
02441 
02442   // Here both systems are up-to-date and possibly have pending generators
02443   // (but they cannot have pending constraints).
02444   PPL_ASSERT(!x.has_pending_constraints() && x.generators_are_up_to_date());
02445   PPL_ASSERT(!y.has_pending_constraints() && y.generators_are_up_to_date());
02446 
02447   // If `x' can support pending generators,
02448   // the generators of `y' are added as pending generators of `x'.
02449   if (x.can_have_something_pending()) {
02450     x.gen_sys.add_pending_rows(y.gen_sys);
02451     x.set_generators_pending();
02452   }
02453   else {
02454     // `x' cannot support pending generators.
02455     // If both generator systems are (fully) sorted, then we can merge
02456     // them; otherwise we simply add the second to the first.
02457     if (x.gen_sys.is_sorted()
02458         && y.gen_sys.is_sorted() && !y.has_pending_generators())
02459       x.gen_sys.merge_rows_assign(y.gen_sys);
02460     else
02461       x.gen_sys.add_rows(y.gen_sys);
02462     // Constraints are no longer up-to-date
02463     // and generators are no longer minimized.
02464     x.clear_constraints_up_to_date();
02465     x.clear_generators_minimized();
02466   }
02467   // At this point both `x' and `y' are not empty.
02468   PPL_ASSERT_HEAVY(x.OK(true) && y.OK(true));
02469 }
02470 
02471 void
02472 PPL::Polyhedron::poly_difference_assign(const Polyhedron& y) {
02473   Polyhedron& x = *this;
02474   // Topology compatibility check.
02475   if (x.topology() != y.topology())
02476     throw_topology_incompatible("poly_difference_assign(y)", "y", y);
02477   // Dimension-compatibility check.
02478   if (x.space_dim != y.space_dim)
02479     throw_dimension_incompatible("poly_difference_assign(y)", "y", y);
02480 
02481   // The difference of a polyhedron `p' and an empty polyhedron is `p'.
02482   if (y.marked_empty())
02483     return;
02484   // The difference of an empty polyhedron and of a polyhedron `p' is empty.
02485   if (x.marked_empty())
02486     return;
02487 
02488   // If both polyhedra are zero-dimensional,
02489   // then at this point they are necessarily universe polyhedra,
02490   // so that their difference is empty.
02491   if (x.space_dim == 0) {
02492     x.set_empty();
02493     return;
02494   }
02495 
02496   // TODO: This is just an executable specification.
02497   //       Have to find a more efficient method.
02498 
02499   if (y.contains(x)) {
02500     x.set_empty();
02501     return;
02502   }
02503 
02504   // Being lazy here is only harmful.
02505   // `minimize()' will process any pending constraints or generators.
02506   if (!y.minimize())
02507     return;
02508   x.minimize();
02509 
02510   Polyhedron new_polyhedron(topology(), x.space_dim, EMPTY);
02511 
02512   const Constraint_System& y_cs = y.constraints();
02513   for (Constraint_System::const_iterator i = y_cs.begin(),
02514          y_cs_end = y_cs.end(); i != y_cs_end; ++i) {
02515     const Constraint& c = *i;
02516     PPL_ASSERT(!c.is_tautological());
02517     PPL_ASSERT(!c.is_inconsistent());
02518     // If the polyhedron `x' is included in the polyhedron defined by
02519     // `c', then `c' can be skipped, as adding its complement to `x'
02520     // would result in the empty polyhedron.  Moreover, if we operate
02521     // on C-polyhedra and `c' is a non-strict inequality, c _must_ be
02522     // skipped for otherwise we would obtain a result that is less
02523     // precise than the poly-difference.
02524     if (x.relation_with(c).implies(Poly_Con_Relation::is_included()))
02525       continue;
02526     Polyhedron z = x;
02527     const Linear_Expression e = Linear_Expression(c);
02528     switch (c.type()) {
02529     case Constraint::NONSTRICT_INEQUALITY:
02530       if (is_necessarily_closed())
02531         z.refine_no_check(e <= 0);
02532       else
02533         z.refine_no_check(e < 0);
02534       break;
02535     case Constraint::STRICT_INEQUALITY:
02536       z.refine_no_check(e <= 0);
02537       break;
02538     case Constraint::EQUALITY:
02539       if (is_necessarily_closed())
02540         // We have already filtered out the case
02541         // when `x' is included in `y': the result is `x'.
02542         return;
02543       else {
02544         Polyhedron w = x;
02545         w.refine_no_check(e < 0);
02546         new_polyhedron.poly_hull_assign(w);
02547         z.refine_no_check(e > 0);
02548       }
02549       break;
02550     }
02551     new_polyhedron.poly_hull_assign(z);
02552   }
02553   *this = new_polyhedron;
02554 
02555   PPL_ASSERT_HEAVY(OK());
02556 }
02557 
02558 void
02559 PPL::Polyhedron::
02560 affine_image(const Variable var,
02561              const Linear_Expression& expr,
02562              Coefficient_traits::const_reference denominator) {
02563   // The denominator cannot be zero.
02564   if (denominator == 0)
02565     throw_invalid_argument("affine_image(v, e, d)", "d == 0");
02566 
02567   // Dimension-compatibility checks.
02568   // The dimension of `expr' should not be greater than the dimension
02569   // of `*this'.
02570   if (space_dim < expr.space_dimension())
02571     throw_dimension_incompatible("affine_image(v, e, d)", "e", expr);
02572   // `var' should be one of the dimensions of the polyhedron.
02573   const dimension_type var_space_dim = var.space_dimension();
02574   if (space_dim < var_space_dim)
02575     throw_dimension_incompatible("affine_image(v, e, d)", "v", var);
02576 
02577   if (marked_empty())
02578     return;
02579 
02580   if (expr.coefficient(var) != 0) {
02581     // The transformation is invertible:
02582     // minimality and saturators are preserved, so that
02583     // pending rows, if present, are correctly handled.
02584     if (generators_are_up_to_date()) {
02585       // Generator_System::affine_image() requires the third argument
02586       // to be a positive Coefficient.
02587       if (denominator > 0)
02588         gen_sys.affine_image(var_space_dim, expr, denominator);
02589       else
02590         gen_sys.affine_image(var_space_dim, -expr, -denominator);
02591     }
02592     if (constraints_are_up_to_date()) {
02593       // To build the inverse transformation,
02594       // after copying and negating `expr',
02595       // we exchange the roles of `expr[var_space_dim]' and `denominator'.
02596       Linear_Expression inverse;
02597       if (expr[var_space_dim] > 0) {
02598         inverse = -expr;
02599         inverse[var_space_dim] = denominator;
02600         con_sys.affine_preimage(var_space_dim, inverse, expr[var_space_dim]);
02601       }
02602       else {
02603         // The new denominator is negative: we negate everything once
02604         // more, as Constraint_System::affine_preimage() requires the
02605         // third argument to be positive.
02606         inverse = expr;
02607         inverse[var_space_dim] = denominator;
02608         neg_assign(inverse[var_space_dim]);
02609         con_sys.affine_preimage(var_space_dim, inverse, -expr[var_space_dim]);
02610       }
02611     }
02612   }
02613   else {
02614     // The transformation is not invertible.
02615     // We need an up-to-date system of generators.
02616     if (has_something_pending())
02617       remove_pending_to_obtain_generators();
02618     else if (!generators_are_up_to_date())
02619       minimize();
02620     if (!marked_empty()) {
02621       // Generator_System::affine_image() requires the third argument
02622       // to be a positive Coefficient.
02623       if (denominator > 0)
02624         gen_sys.affine_image(var_space_dim, expr, denominator);
02625       else
02626         gen_sys.affine_image(var_space_dim, -expr, -denominator);
02627 
02628       clear_constraints_up_to_date();
02629       clear_generators_minimized();
02630       clear_sat_c_up_to_date();
02631       clear_sat_g_up_to_date();
02632     }
02633   }
02634   PPL_ASSERT_HEAVY(OK());
02635 }
02636 
02637 
02638 void
02639 PPL::Polyhedron::
02640 affine_preimage(const Variable var,
02641                 const Linear_Expression& expr,
02642                 Coefficient_traits::const_reference denominator) {
02643   // The denominator cannot be zero.
02644   if (denominator == 0)
02645     throw_invalid_argument("affine_preimage(v, e, d)", "d == 0");
02646 
02647   // Dimension-compatibility checks.
02648   // The dimension of `expr' should not be greater than the dimension
02649   // of `*this'.
02650   if (space_dim < expr.space_dimension())
02651     throw_dimension_incompatible("affine_preimage(v, e, d)", "e", expr);
02652   // `var' should be one of the dimensions of the polyhedron.
02653   const dimension_type var_space_dim = var.space_dimension();
02654   if (space_dim < var_space_dim)
02655     throw_dimension_incompatible("affine_preimage(v, e, d)", "v", var);
02656 
02657   if (marked_empty())
02658     return;
02659 
02660   if (expr.coefficient(var) != 0) {
02661     // The transformation is invertible:
02662     // minimality and saturators are preserved.
02663     if (constraints_are_up_to_date()) {
02664       // Constraint_System::affine_preimage() requires the third argument
02665       // to be a positive Coefficient.
02666       if (denominator > 0)
02667         con_sys.affine_preimage(var_space_dim, expr, denominator);
02668       else
02669         con_sys.affine_preimage(var_space_dim, -expr, -denominator);
02670     }
02671     if (generators_are_up_to_date()) {
02672       // To build the inverse transformation,
02673       // after copying and negating `expr',
02674       // we exchange the roles of `expr[var_space_dim]' and `denominator'.
02675       Linear_Expression inverse;
02676       if (expr[var_space_dim] > 0) {
02677         inverse = -expr;
02678         inverse[var_space_dim] = denominator;
02679         gen_sys.affine_image(var_space_dim, inverse, expr[var_space_dim]);
02680       }
02681       else {
02682         // The new denominator is negative:
02683         // we negate everything once more, as Generator_System::affine_image()
02684         // requires the third argument to be positive.
02685         inverse = expr;
02686         inverse[var_space_dim] = denominator;
02687         neg_assign(inverse[var_space_dim]);
02688         gen_sys.affine_image(var_space_dim, inverse, -expr[var_space_dim]);
02689       }
02690     }
02691   }
02692   else {
02693     // The transformation is not invertible.
02694     // We need an up-to-date system of constraints.
02695     if (has_something_pending())
02696       remove_pending_to_obtain_constraints();
02697     else if (!constraints_are_up_to_date())
02698       minimize();
02699     // Constraint_System::affine_preimage() requires the third argument
02700     // to be a positive Coefficient.
02701     if (denominator > 0)
02702       con_sys.affine_preimage(var_space_dim, expr, denominator);
02703     else
02704       con_sys.affine_preimage(var_space_dim, -expr, -denominator);
02705     // Generators, minimality and saturators are no longer valid.
02706     clear_generators_up_to_date();
02707     clear_constraints_minimized();
02708     clear_sat_c_up_to_date();
02709     clear_sat_g_up_to_date();
02710   }
02711   PPL_ASSERT_HEAVY(OK());
02712 }
02713 
02714 void
02715 PPL::Polyhedron::
02716 bounded_affine_image(const Variable var,
02717                      const Linear_Expression& lb_expr,
02718                      const Linear_Expression& ub_expr,
02719                      Coefficient_traits::const_reference denominator) {
02720   // The denominator cannot be zero.
02721   if (denominator == 0)
02722     throw_invalid_argument("bounded_affine_image(v, lb, ub, d)", "d == 0");
02723 
02724   // Dimension-compatibility checks.
02725   // `var' should be one of the dimensions of the polyhedron.
02726   const dimension_type var_space_dim = var.space_dimension();
02727   if (space_dim < var_space_dim)
02728     throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
02729                                  "v", var);
02730   // The dimension of `lb_expr' and `ub_expr' should not be
02731   // greater than the dimension of `*this'.
02732   const dimension_type lb_space_dim = lb_expr.space_dimension();
02733   if (space_dim < lb_space_dim)
02734     throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
02735                                  "lb", lb_expr);
02736   const dimension_type ub_space_dim = ub_expr.space_dimension();
02737   if (space_dim < ub_space_dim)
02738     throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
02739                                  "ub", ub_expr);
02740 
02741   // Any image of an empty polyhedron is empty.
02742   if (marked_empty())
02743     return;
02744 
02745   // Check whether `var' occurs in `lb_expr' and/or `ub_expr'.
02746   if (lb_expr.coefficient(var) == 0) {
02747     // Here `var' may only occur in `ub_expr'.
02748     generalized_affine_image(var,
02749                              LESS_OR_EQUAL,
02750                              ub_expr,
02751                              denominator);
02752     if (denominator > 0)
02753       refine_no_check(lb_expr <= denominator*var);
02754     else
02755       refine_no_check(denominator*var <= lb_expr);
02756   }
02757   else if (ub_expr.coefficient(var) == 0) {
02758     // Here `var' only occurs in `lb_expr'.
02759     generalized_affine_image(var,
02760                              GREATER_OR_EQUAL,
02761                              lb_expr,
02762                              denominator);
02763     if (denominator > 0)
02764       refine_no_check(denominator*var <= ub_expr);
02765     else
02766       refine_no_check(ub_expr <= denominator*var);
02767   }
02768   else {
02769     // Here `var' occurs in both `lb_expr' and `ub_expr'.
02770     // To ease the computation, we add an additional dimension.
02771     const Variable new_var(space_dim);
02772     add_space_dimensions_and_embed(1);
02773     // Constrain the new dimension to be equal to `ub_expr'.
02774     refine_no_check(denominator*new_var == ub_expr);
02775     // Apply the affine lower bound.
02776     generalized_affine_image(var,
02777                              GREATER_OR_EQUAL,
02778                              lb_expr,
02779                              denominator);
02780     if (!marked_empty())
02781       // Now apply the affine upper bound, as recorded in `new_var'.
02782       refine_no_check(new_var >= var);
02783     // Remove the temporarily added dimension.
02784     remove_higher_space_dimensions(space_dim-1);
02785   }
02786   PPL_ASSERT_HEAVY(OK());
02787 }
02788 
02789 void
02790 PPL::Polyhedron::
02791 bounded_affine_preimage(const Variable var,
02792                         const Linear_Expression& lb_expr,
02793                         const Linear_Expression& ub_expr,
02794                         Coefficient_traits::const_reference denominator) {
02795   // The denominator cannot be zero.
02796   if (denominator == 0)
02797     throw_invalid_argument("bounded_affine_preimage(v, lb, ub, d)", "d == 0");
02798 
02799   // Dimension-compatibility checks.
02800   // `var' should be one of the dimensions of the polyhedron.
02801   const dimension_type var_space_dim = var.space_dimension();
02802   if (space_dim < var_space_dim)
02803     throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
02804                                  "v", var);
02805   // The dimension of `lb_expr' and `ub_expr' should not be
02806   // greater than the dimension of `*this'.
02807   const dimension_type lb_space_dim = lb_expr.space_dimension();
02808   if (space_dim < lb_space_dim)
02809     throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
02810                                  "lb", lb_expr);
02811   const dimension_type ub_space_dim = ub_expr.space_dimension();
02812   if (space_dim < ub_space_dim)
02813     throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
02814                                  "ub", ub_expr);
02815 
02816   // Any preimage of an empty polyhedron is empty.
02817   if (marked_empty())
02818     return;
02819 
02820   // Check whether `var' occurs in neither `lb_expr' nor `ub_expr'.
02821   if (lb_expr.coefficient(var) == 0 && ub_expr.coefficient(var) == 0) {
02822     if (denominator > 0) {
02823       refine_no_check(lb_expr <= denominator*var);
02824       refine_no_check(denominator*var <= ub_expr);
02825     }
02826     else {
02827       refine_no_check(ub_expr <= denominator*var);
02828       refine_no_check(denominator*var <= lb_expr);
02829     }
02830     unconstrain(var);
02831   }
02832   else {
02833     // Here `var' occurs in `lb_expr' or `ub_expr'.
02834     // To ease the computation, add an additional dimension.
02835     const Variable new_var(space_dim);
02836     add_space_dimensions_and_embed(1);
02837     // Swap dimensions `var' and `new_var'.
02838     std::vector<dimension_type> swapping_cycle;
02839     swapping_cycle.push_back(var_space_dim);
02840     swapping_cycle.push_back(space_dim);
02841     swapping_cycle.push_back(0);
02842     if (constraints_are_up_to_date())
02843       con_sys.permute_columns(swapping_cycle);
02844     if (generators_are_up_to_date())
02845       gen_sys.permute_columns(swapping_cycle);
02846     // Constrain the new dimension as dictated by `lb_expr' and `ub_expr'.
02847     // (we force minimization because we will need the generators).
02848     if (denominator > 0) {
02849       refine_no_check(lb_expr <= denominator*new_var);
02850       refine_no_check(denominator*new_var <= ub_expr);
02851     }
02852     else {
02853       refine_no_check(ub_expr <= denominator*new_var);
02854       refine_no_check(denominator*new_var <= lb_expr);
02855     }
02856     // Remove the temporarily added dimension.
02857     remove_higher_space_dimensions(space_dim-1);
02858   }
02859   PPL_ASSERT_HEAVY(OK());
02860 }
02861 
02862 void
02863 PPL::Polyhedron::
02864 generalized_affine_image(const Variable var,
02865                          const Relation_Symbol relsym,
02866                          const Linear_Expression& expr,
02867                          Coefficient_traits::const_reference denominator) {
02868   // The denominator cannot be zero.
02869   if (denominator == 0)
02870     throw_invalid_argument("generalized_affine_image(v, r, e, d)", "d == 0");
02871 
02872   // Dimension-compatibility checks.
02873   // The dimension of `expr' should not be greater than the dimension
02874   // of `*this'.
02875   if (space_dim < expr.space_dimension())
02876     throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
02877                                  "e", expr);
02878   // `var' should be one of the dimensions of the polyhedron.
02879   const dimension_type var_space_dim = var.space_dimension();
02880   if (space_dim < var_space_dim)
02881     throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
02882                                  "v", var);
02883 
02884   // Strict relation symbols are only admitted for NNC polyhedra.
02885   if (is_necessarily_closed()
02886       && (relsym == LESS_THAN || relsym == GREATER_THAN))
02887     throw_invalid_argument("generalized_affine_image(v, r, e, d)",
02888                            "r is a strict relation symbol");
02889   // The relation symbol cannot be a disequality.
02890   if (relsym == NOT_EQUAL)
02891     throw_invalid_argument("generalized_affine_image(v, r, e, d)",
02892                            "r is the disequality relation symbol");
02893 
02894   // First compute the affine image.
02895   affine_image(var, expr, denominator);
02896 
02897   if (relsym == EQUAL)
02898     // The affine relation is indeed an affine function.
02899     return;
02900 
02901   // Any image of an empty polyhedron is empty.
02902   // Note: DO check for emptiness here, as we will later add a ray.
02903   if (is_empty())
02904     return;
02905 
02906   switch (relsym) {
02907   case LESS_OR_EQUAL:
02908     add_generator(ray(-var));
02909     break;
02910   case GREATER_OR_EQUAL:
02911     add_generator(ray(var));
02912     break;
02913   case LESS_THAN:
02914   // Intentionally fall through.
02915   case GREATER_THAN:
02916     {
02917       // The relation symbol is strict.
02918       PPL_ASSERT(!is_necessarily_closed());
02919       // While adding the ray, we minimize the generators
02920       // in order to avoid adding too many redundant generators later.
02921       add_generator(ray((relsym == GREATER_THAN) ? var : -var));
02922       minimize();
02923       // We split each point of the generator system into two generators:
02924       // a closure point, having the same coordinates of the given point,
02925       // and another point, having the same coordinates for all but the
02926       // `var' dimension, which is displaced along the direction of the
02927       // newly introduced ray.
02928       const dimension_type eps_index = space_dim + 1;
02929       for (dimension_type i =  gen_sys.num_rows(); i-- > 0; )
02930         if (gen_sys[i].is_point()) {
02931           // Add a `var'-displaced copy of `gen_sys[i]' to the generator system.
02932           gen_sys.add_row(gen_sys[i]);
02933           if (relsym == GREATER_THAN)
02934             ++gen_sys[gen_sys.num_rows()-1][var_space_dim];
02935           else
02936             --gen_sys[gen_sys.num_rows()-1][var_space_dim];
02937           // Transform `gen_sys[i]' into a closure point.
02938           gen_sys[i][eps_index] = 0;
02939         }
02940       clear_constraints_up_to_date();
02941       clear_generators_minimized();
02942       gen_sys.set_sorted(false);
02943       clear_sat_c_up_to_date();
02944       clear_sat_g_up_to_date();
02945     }
02946     break;
02947   default:
02948     // The EQUAL and NOT_EQUAL cases have been already dealt with.
02949     PPL_UNREACHABLE;
02950     break;
02951   }
02952   PPL_ASSERT_HEAVY(OK());
02953 }
02954 
02955 void
02956 PPL::Polyhedron::
02957 generalized_affine_preimage(const Variable var,
02958                             const Relation_Symbol relsym,
02959                             const Linear_Expression& expr,
02960                             Coefficient_traits::const_reference denominator) {
02961   // The denominator cannot be zero.
02962   if (denominator == 0)
02963     throw_invalid_argument("generalized_affine_preimage(v, r, e, d)",
02964                            "d == 0");
02965 
02966   // Dimension-compatibility checks.
02967   // The dimension of `expr' should not be greater than the dimension
02968   // of `*this'.
02969   if (space_dim < expr.space_dimension())
02970     throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
02971                                  "e", expr);
02972   // `var' should be one of the dimensions of the polyhedron.
02973   const dimension_type var_space_dim = var.space_dimension();
02974   if (space_dim < var_space_dim)
02975     throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
02976                                  "v", var);
02977 
02978   // Strict relation symbols are only admitted for NNC polyhedra.
02979   if (is_necessarily_closed()
02980       && (relsym == LESS_THAN || relsym == GREATER_THAN))
02981     throw_invalid_argument("generalized_affine_preimage(v, r, e, d)",
02982                            "r is a strict relation symbol");
02983   // The relation symbol cannot be a disequality.
02984   if (relsym == NOT_EQUAL)
02985     throw_invalid_argument("generalized_affine_preimage(v, r, e, d)",
02986                            "r is the disequality relation symbol");
02987 
02988   // Check whether the affine relation is indeed an affine function.
02989   if (relsym == EQUAL) {
02990     affine_preimage(var, expr, denominator);
02991     return;
02992   }
02993 
02994   // Compute the reversed relation symbol to simplify later coding.
02995   Relation_Symbol reversed_relsym;
02996   switch (relsym) {
02997   case LESS_THAN:
02998     reversed_relsym = GREATER_THAN;
02999     break;
03000   case LESS_OR_EQUAL:
03001     reversed_relsym = GREATER_OR_EQUAL;
03002     break;
03003   case GREATER_OR_EQUAL:
03004     reversed_relsym = LESS_OR_EQUAL;
03005     break;
03006   case GREATER_THAN:
03007     reversed_relsym = LESS_THAN;
03008     break;
03009   default:
03010     // The EQUAL and NOT_EQUAL cases have been already dealt with.
03011     PPL_UNREACHABLE;
03012     return;
03013   }
03014 
03015   // Check whether the preimage of this affine relation can be easily
03016   // computed as the image of its inverse relation.
03017   const Coefficient& var_coefficient = expr.coefficient(var);
03018   if (var_coefficient != 0) {
03019     Linear_Expression inverse_expr
03020       = expr - (denominator + var_coefficient) * var;
03021     PPL_DIRTY_TEMP_COEFFICIENT(inverse_denominator);
03022     neg_assign(inverse_denominator, var_coefficient);
03023     Relation_Symbol inverse_relsym
03024       = (sgn(denominator) == sgn(inverse_denominator))
03025       ? relsym : reversed_relsym;
03026     generalized_affine_image(var, inverse_relsym, inverse_expr,
03027                              inverse_denominator);
03028     return;
03029   }
03030 
03031   // Here `var_coefficient == 0', so that the preimage cannot
03032   // be easily computed by inverting the affine relation.
03033   // Shrink the polyhedron by adding the constraint induced
03034   // by the affine relation.
03035   const Relation_Symbol corrected_relsym
03036     = (denominator > 0) ? relsym : reversed_relsym;
03037   switch (corrected_relsym) {
03038   case LESS_THAN:
03039     refine_no_check(denominator*var < expr);
03040     break;
03041   case LESS_OR_EQUAL:
03042     refine_no_check(denominator*var <= expr);
03043     break;
03044   case GREATER_OR_EQUAL:
03045     refine_no_check(denominator*var >= expr);
03046     break;
03047   case GREATER_THAN:
03048     refine_no_check(denominator*var > expr);
03049     break;
03050   default:
03051     // The EQUAL and NOT_EQUAL cases have been already dealt with.
03052     PPL_UNREACHABLE;
03053     break;
03054   }
03055   unconstrain(var);
03056   PPL_ASSERT_HEAVY(OK());
03057 }
03058 
03059 void
03060 PPL::Polyhedron::generalized_affine_image(const Linear_Expression& lhs,
03061                                           const Relation_Symbol relsym,
03062                                           const Linear_Expression& rhs) {
03063   // Dimension-compatibility checks.
03064   // The dimension of `lhs' should not be greater than the dimension
03065   // of `*this'.
03066   dimension_type lhs_space_dim = lhs.space_dimension();
03067   if (space_dim < lhs_space_dim)
03068     throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
03069                                  "e1", lhs);
03070   // The dimension of `rhs' should not be greater than the dimension
03071   // of `*this'.
03072   const dimension_type rhs_space_dim = rhs.space_dimension();
03073   if (space_dim < rhs_space_dim)
03074     throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
03075                                  "e2", rhs);
03076 
03077   // Strict relation symbols are only admitted for NNC polyhedra.
03078   if (is_necessarily_closed()
03079       && (relsym == LESS_THAN || relsym == GREATER_THAN))
03080     throw_invalid_argument("generalized_affine_image(e1, r, e2)",
03081                            "r is a strict relation symbol");
03082   // The relation symbol cannot be a disequality.
03083   if (relsym == NOT_EQUAL)
03084     throw_invalid_argument("generalized_affine_image(e1, r, e2)",
03085                            "r is the disequality relation symbol");
03086 
03087   // Any image of an empty polyhedron is empty.
03088   if (marked_empty())
03089     return;
03090 
03091   // Compute the actual space dimension of `lhs',
03092   // i.e., the highest dimension having a non-zero coefficient in `lhs'.
03093   for ( ; lhs_space_dim > 0; lhs_space_dim--)
03094     if (lhs.coefficient(Variable(lhs_space_dim - 1)) != 0)
03095       break;
03096   // If all variables have a zero coefficient, then `lhs' is a constant:
03097   // we can simply add the constraint `lhs relsym rhs'.
03098   if (lhs_space_dim == 0) {
03099     switch (relsym) {
03100     case LESS_THAN:
03101       refine_no_check(lhs < rhs);
03102       break;
03103     case LESS_OR_EQUAL:
03104       refine_no_check(lhs <= rhs);
03105       break;
03106     case EQUAL:
03107       refine_no_check(lhs == rhs);
03108       break;
03109     case GREATER_OR_EQUAL:
03110       refine_no_check(lhs >= rhs);
03111       break;
03112     case GREATER_THAN:
03113       refine_no_check(lhs > rhs);
03114       break;
03115     case NOT_EQUAL:
03116       // The NOT_EQUAL case has been already dealt with.
03117       PPL_UNREACHABLE;
03118       break;
03119     }
03120     return;
03121   }
03122 
03123   // Gather in `new_lines' the collections of all the lines having
03124   // the direction of variables occurring in `lhs'.
03125   // While at it, check whether or not there exists a variable
03126   // occurring in both `lhs' and `rhs'.
03127   Generator_System new_lines;
03128   bool lhs_vars_intersects_rhs_vars = false;
03129   for (dimension_type i = lhs_space_dim; i-- > 0; )
03130     if (lhs.coefficient(Variable(i)) != 0) {
03131       new_lines.insert(line(Variable(i)));
03132       if (rhs.coefficient(Variable(i)) != 0)
03133         lhs_vars_intersects_rhs_vars = true;
03134     }
03135 
03136   if (lhs_vars_intersects_rhs_vars) {
03137     // Some variables in `lhs' also occur in `rhs'.
03138     // To ease the computation, we add an additional dimension.
03139     const Variable new_var(space_dim);
03140     add_space_dimensions_and_embed(1);
03141 
03142     // Constrain the new dimension to be equal to the right hand side.
03143     // (check for emptiness because we will add lines).
03144     refine_no_check(new_var == rhs);
03145     if (!is_empty()) {
03146       // Existentially quantify the variables in the left hand side.
03147       add_recycled_generators(new_lines);
03148 
03149       // Constrain the new dimension so that it is related to
03150       // the left hand side as dictated by `relsym'
03151       // (we force minimization because we will need the generators).
03152       switch (relsym) {
03153       case LESS_THAN:
03154         refine_no_check(lhs < new_var);
03155         break;
03156       case LESS_OR_EQUAL:
03157         refine_no_check(lhs <= new_var);
03158         break;
03159       case EQUAL:
03160         refine_no_check(lhs == new_var);
03161         break;
03162       case GREATER_OR_EQUAL:
03163         refine_no_check(lhs >= new_var);
03164         break;
03165       case GREATER_THAN:
03166         refine_no_check(lhs > new_var);
03167         break;
03168       case NOT_EQUAL:
03169         // The NOT_EQUAL case has been already dealt with.
03170         PPL_UNREACHABLE;
03171         break;
03172       }
03173     }
03174     // Remove the temporarily added dimension.
03175     remove_higher_space_dimensions(space_dim-1);
03176   }
03177   else {
03178     // `lhs' and `rhs' variables are disjoint:
03179     // there is no need to add a further dimension.
03180 
03181     // Any image of an empty polyhedron is empty.
03182     // Note: DO check for emptiness here, as we will add lines.
03183     if (is_empty())
03184       return;
03185 
03186     // Existentially quantify the variables in the left hand side.
03187     add_recycled_generators(new_lines);
03188 
03189     // Constrain the left hand side expression so that it is related to
03190     // the right hand side expression as dictated by `relsym'.
03191     switch (relsym) {
03192     case LESS_THAN:
03193       refine_no_check(lhs < rhs);
03194       break;
03195     case LESS_OR_EQUAL:
03196       refine_no_check(lhs <= rhs);
03197       break;
03198     case EQUAL:
03199       refine_no_check(lhs == rhs);
03200       break;
03201     case GREATER_OR_EQUAL:
03202       refine_no_check(lhs >= rhs);
03203       break;
03204     case GREATER_THAN:
03205       refine_no_check(lhs > rhs);
03206       break;
03207     case NOT_EQUAL:
03208       // The NOT_EQUAL case has been already dealt with.
03209       PPL_UNREACHABLE;
03210       break;
03211     }
03212   }
03213   PPL_ASSERT_HEAVY(OK());
03214 }
03215 
03216 void
03217 PPL::Polyhedron::generalized_affine_preimage(const Linear_Expression& lhs,
03218                                              const Relation_Symbol relsym,
03219                                              const Linear_Expression& rhs) {
03220   // Dimension-compatibility checks.
03221   // The dimension of `lhs' should not be greater than the dimension
03222   // of `*this'.
03223   dimension_type lhs_space_dim = lhs.space_dimension();
03224   if (space_dim < lhs_space_dim)
03225     throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2)",
03226                                  "e1", lhs);
03227   // The dimension of `rhs' should not be greater than the dimension
03228   // of `*this'.
03229   const dimension_type rhs_space_dim = rhs.space_dimension();
03230   if (space_dim < rhs_space_dim)
03231     throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2)",
03232                                  "e2", rhs);
03233 
03234   // Strict relation symbols are only admitted for NNC polyhedra.
03235   if (is_necessarily_closed()
03236       && (relsym == LESS_THAN || relsym == GREATER_THAN))
03237     throw_invalid_argument("generalized_affine_preimage(e1, r, e2)",
03238                            "r is a strict relation symbol");
03239   // The relation symbol cannot be a disequality.
03240   if (relsym == NOT_EQUAL)
03241     throw_invalid_argument("generalized_affine_preimage(e1, r, e2)",
03242                            "r is the disequality relation symbol");
03243 
03244   // Any preimage of an empty polyhedron is empty.
03245   if (marked_empty())
03246     return;
03247 
03248   // Compute the actual space dimension of `lhs',
03249   // i.e., the highest dimension having a non-zero coefficient in `lhs'.
03250   for ( ; lhs_space_dim > 0; lhs_space_dim--)
03251     if (lhs.coefficient(Variable(lhs_space_dim - 1)) != 0)
03252       break;
03253 
03254   // If all variables have a zero coefficient, then `lhs' is a constant:
03255   // in this case, preimage and image happen to be the same.
03256   if (lhs_space_dim == 0) {
03257     generalized_affine_image(lhs, relsym, rhs);
03258     return;
03259   }
03260 
03261   // Gather in `new_lines' the collections of all the lines having
03262   // the direction of variables occurring in `lhs'.
03263   // While at it, check whether or not there exists a variable
03264   // occurring in both `lhs' and `rhs'.
03265   Generator_System new_lines;
03266   bool lhs_vars_intersects_rhs_vars = false;
03267   for (dimension_type i = lhs_space_dim; i-- > 0; )
03268     if (lhs.coefficient(Variable(i)) != 0) {
03269       new_lines.insert(line(Variable(i)));
03270       if (rhs.coefficient(Variable(i)) != 0)
03271         lhs_vars_intersects_rhs_vars = true;
03272     }
03273 
03274   if (lhs_vars_intersects_rhs_vars) {
03275     // Some variables in `lhs' also occur in `rhs'.
03276     // To ease the computation, we add an additional dimension.
03277     const Variable new_var(space_dim);
03278     add_space_dimensions_and_embed(1);
03279 
03280     // Constrain the new dimension to be equal to `lhs'
03281     // (also check for emptiness because we have to add lines).
03282     refine_no_check(new_var == lhs);
03283     if (!is_empty()) {
03284       // Existentially quantify the variables in the left hand side.
03285       add_recycled_generators(new_lines);
03286 
03287       // Constrain the new dimension so that it is related to
03288       // the right hand side as dictated by `relsym'.
03289       switch (relsym) {
03290       case LESS_THAN:
03291         refine_no_check(new_var < rhs);
03292         break;
03293       case LESS_OR_EQUAL:
03294         refine_no_check(new_var <= rhs);
03295         break;
03296       case EQUAL:
03297         refine_no_check(new_var == rhs);
03298         break;
03299       case GREATER_OR_EQUAL:
03300         refine_no_check(new_var >= rhs);
03301         break;
03302       case GREATER_THAN:
03303         refine_no_check(new_var > rhs);
03304         break;
03305       case NOT_EQUAL:
03306         // The NOT_EQUAL case has been already dealt with.
03307         PPL_UNREACHABLE;
03308         break;
03309       }
03310     }
03311     // Remove the temporarily added dimension.
03312     remove_higher_space_dimensions(space_dim-1);
03313   }
03314   else {
03315     // `lhs' and `rhs' variables are disjoint:
03316     // there is no need to add a further dimension.
03317 
03318     // Constrain the left hand side expression so that it is related to
03319     // the right hand side expression as dictated by `relsym'.
03320     switch (relsym) {
03321     case LESS_THAN:
03322       refine_no_check(lhs < rhs);
03323       break;
03324     case LESS_OR_EQUAL:
03325       refine_no_check(lhs <= rhs);
03326       break;
03327     case EQUAL:
03328       refine_no_check(lhs == rhs);
03329       break;
03330     case GREATER_OR_EQUAL:
03331       refine_no_check(lhs >= rhs);
03332       break;
03333     case GREATER_THAN:
03334       refine_no_check(lhs > rhs);
03335       break;
03336     case NOT_EQUAL:
03337       // The NOT_EQUAL case has been already dealt with.
03338       PPL_UNREACHABLE;
03339       break;
03340     }
03341     // Any image of an empty polyhedron is empty.
03342     // Note: DO check for emptiness here, as we will add lines.
03343     if (is_empty())
03344       return;
03345     // Existentially quantify all the variables occurring in `lhs'.
03346     add_recycled_generators(new_lines);
03347   }
03348   PPL_ASSERT_HEAVY(OK());
03349 }
03350 
03351 void
03352 PPL::Polyhedron::time_elapse_assign(const Polyhedron& y) {
03353   Polyhedron& x = *this;
03354   // Topology compatibility check.
03355   if (x.topology() != y.topology())
03356     throw_topology_incompatible("time_elapse_assign(y)", "y", y);
03357   // Dimension-compatibility checks.
03358   if (x.space_dim != y.space_dim)
03359     throw_dimension_incompatible("time_elapse_assign(y)", "y", y);
03360 
03361   // Dealing with the zero-dimensional case.
03362   if (x.space_dim == 0) {
03363     if (y.marked_empty())
03364       x.set_empty();
03365     return;
03366   }
03367 
03368   // If either one of `x' or `y' is empty, the result is empty too.
03369   if (x.marked_empty() || y.marked_empty()
03370       || (x.has_pending_constraints() && !x.process_pending_constraints())
03371       || (!x.generators_are_up_to_date() && !x.update_generators())
03372       || (y.has_pending_constraints() && !y.process_pending_constraints())
03373       || (!y.generators_are_up_to_date() && !y.update_generators())) {
03374     x.set_empty();
03375     return;
03376   }
03377 
03378   // At this point both generator systems are up-to-date,
03379   // possibly containing pending generators.
03380   Generator_System gs = y.gen_sys;
03381   const dimension_type old_gs_num_rows = gs.num_rows();
03382   dimension_type gs_num_rows = old_gs_num_rows;
03383 
03384   if (!x.is_necessarily_closed()) {
03385     // `x' and `y' are NNC polyhedra.
03386     for (dimension_type i = gs_num_rows; i-- > 0; )
03387       switch (gs[i].type()) {
03388       case Generator::POINT:
03389         // The points of `gs' can be erased,
03390         // since their role can be played by closure points.
03391         --gs_num_rows;
03392         using std::swap;
03393         swap(gs[i], gs[gs_num_rows]);
03394         break;
03395       case Generator::CLOSURE_POINT:
03396         {
03397           Generator& cp = gs[i];
03398           // If it is the origin, erase it.
03399           if (cp.all_homogeneous_terms_are_zero()) {
03400             --gs_num_rows;
03401             using std::swap;
03402             swap(cp, gs[gs_num_rows]);
03403           }
03404           // Otherwise, transform the closure point into a ray.
03405           else {
03406             cp[0] = 0;
03407             // Enforce normalization.
03408             cp.normalize();
03409           }
03410         }
03411         break;
03412       case Generator::RAY:
03413       case Generator::LINE:
03414         // For rays and lines, nothing to be done.
03415         break;
03416       }
03417   }
03418   else {
03419     // `x' and `y' are C polyhedra.
03420     for (dimension_type i = gs_num_rows; i-- > 0; ) {
03421       // For rays and lines, nothing to be done.
03422       if (gs[i].is_point()) {
03423         Generator& p = gs[i];
03424         // If it is the origin, erase it.
03425         if (p.all_homogeneous_terms_are_zero()) {
03426           --gs_num_rows;
03427           using std::swap;
03428           swap(p, gs[gs_num_rows]);
03429         }
03430         // Otherwise, transform the point into a ray.
03431         else {
03432           p[0] = 0;
03433           // Enforce normalization.
03434           p.normalize();
03435         }
03436       }
03437     }
03438   }
03439   // If it was present, erase the origin point or closure point,
03440   // which cannot be transformed into a valid ray or line.
03441   // For NNC polyhedra, also erase all the points of `gs',
03442   // whose role can be played by the closure points.
03443   // These have been previously moved to the end of `gs'.
03444   gs.remove_trailing_rows(old_gs_num_rows - gs_num_rows);
03445   gs.unset_pending_rows();
03446 
03447   // `gs' may now have no rows.
03448   // Namely, this happens when `y' was the singleton polyhedron
03449   // having the origin as the one and only point.
03450   // In such a case, the resulting polyhedron is equal to `x'.
03451   if (gs_num_rows == 0)
03452     return;
03453 
03454   // If the polyhedron can have something pending, we add `gs'
03455   // to `gen_sys' as pending rows
03456   if (x.can_have_something_pending()) {
03457     x.gen_sys.add_pending_rows(gs);
03458     x.set_generators_pending();
03459   }
03460   // Otherwise, the two systems are merged.
03461   // `Linear_System::merge_rows_assign()' requires both systems to be sorted.
03462   else {
03463     if (!x.gen_sys.is_sorted())
03464       x.gen_sys.sort_rows();
03465     gs.sort_rows();
03466     x.gen_sys.merge_rows_assign(gs);
03467     // Only the system of generators is up-to-date.
03468     x.clear_constraints_up_to_date();
03469     x.clear_generators_minimized();
03470   }
03471   PPL_ASSERT_HEAVY(x.OK(true) && y.OK(true));
03472 }
03473 
03474 bool
03475 PPL::Polyhedron::frequency(const Linear_Expression& expr,
03476                            Coefficient& freq_n, Coefficient& freq_d,
03477                            Coefficient& val_n, Coefficient& val_d) const {
03478   // The dimension of `expr' must be at most the dimension of *this.
03479   if (space_dim < expr.space_dimension())
03480     throw_dimension_incompatible("frequency(e, ...)", "e", expr);
03481 
03482   // If the `expr' has a constant value, then the frequency
03483   // `freq_n' is 0. Otherwise the values for \p expr are not discrete
03484   // and we return false.
03485 
03486   // Space dimension is 0: if empty, then return false;
03487   // otherwise the frequency is 1 and the value is 0.
03488   if (space_dim == 0) {
03489     if (is_empty())
03490       return false;
03491     freq_n = 0;
03492     freq_d = 1;
03493     val_n = expr.inhomogeneous_term();
03494     val_d = 1;
03495     return true;
03496   }
03497 
03498   // For an empty polyhedron, we simply return false.
03499   if (marked_empty()
03500       || (has_pending_constraints() && !process_pending_constraints())
03501       || (!generators_are_up_to_date() && !update_generators()))
03502     return false;
03503 
03504   // The polyhedron has updated, possibly pending generators.
03505   // The following loop will iterate through the generator
03506   // to see if `expr' has a constant value.
03507   PPL_DIRTY_TEMP(mpq_class, value);
03508 
03509   // True if we have no other candidate value to compare with.
03510   bool first_candidate = true;
03511 
03512   PPL_DIRTY_TEMP_COEFFICIENT(sp);
03513   PPL_DIRTY_TEMP(mpq_class, candidate);
03514   for (dimension_type i = gen_sys.num_rows(); i-- > 0; ) {
03515     const Generator& gen_sys_i = gen_sys[i];
03516     Scalar_Products::homogeneous_assign(sp, expr, gen_sys_i);
03517     // Lines and rays in `*this' can cause `expr' to be non-constant.
03518     if (gen_sys_i.is_line_or_ray()) {
03519       const int sp_sign = sgn(sp);
03520       if (sp_sign != 0)
03521         // `expr' is unbounded in `*this'.
03522         return false;
03523     }
03524     else {
03525       // We have a point or a closure point.
03526       PPL_ASSERT(gen_sys_i.is_point() || gen_sys_i.is_closure_point());
03527       // Notice that we are ignoring the constant term in `expr' here.
03528       // We will add it to the value if there is a constant value.
03529       assign_r(candidate.get_num(), sp, ROUND_NOT_NEEDED);
03530       assign_r(candidate.get_den(), gen_sys_i[0], ROUND_NOT_NEEDED);
03531       candidate.canonicalize();
03532       if (first_candidate) {
03533         // We have a (new) candidate value.
03534         first_candidate = false;
03535         value = candidate;
03536       }
03537       else if (candidate != value)
03538         return false;
03539     }
03540   }
03541 
03542   // Add in the constant term in `expr'.
03543   PPL_DIRTY_TEMP(mpz_class, n);
03544   assign_r(n, expr.inhomogeneous_term(), ROUND_NOT_NEEDED);
03545   value += n;
03546   // FIXME: avoid these temporaries, if possible.
03547   // This can be done adding an `assign' function working on native
03548   // and checked or an operator= that have on one side a checked and
03549   // on the other a native or checked.
03550   // The reason why now we can't use operator= is the fact that we
03551   // still can have Coefficient defined to mpz_class (and not
03552   // Checked_Number<mpz_class>).
03553   val_n = Coefficient(value.get_num());
03554   val_d = Coefficient(value.get_den());
03555 
03556   freq_n = 0;
03557   freq_d = 1;
03558   return true;
03559 }
03560 
03561 void
03562 PPL::Polyhedron::topological_closure_assign() {
03563   // Necessarily closed polyhedra are trivially closed.
03564   if (is_necessarily_closed())
03565     return;
03566   // Any empty or zero-dimensional polyhedron is closed.
03567   if (marked_empty() || space_dim == 0)
03568     return;
03569 
03570   // The computation can be done using constraints or generators.
03571   // If we use constraints, we will change them, so that having pending
03572   // constraints would be useless. If we use generators, we add generators,
03573   // so that having pending generators still makes sense.
03574 
03575   // Process any pending constraints.
03576   if (has_pending_constraints() && !process_pending_constraints())
03577     return;
03578 
03579   // Use constraints only if they are available and
03580   // there are no pending generators.
03581   if (!has_pending_generators() && constraints_are_up_to_date()) {
03582     const dimension_type eps_index = space_dim + 1;
03583     bool changed = false;
03584     // Transform all strict inequalities into non-strict ones.
03585     for (dimension_type i = con_sys.num_rows(); i-- > 0; ) {
03586       Constraint& c = con_sys[i];
03587       if (c[eps_index] < 0 && !c.is_tautological()) {
03588         c[eps_index] = 0;
03589         // Enforce normalization.
03590         c.normalize();
03591         changed = true;
03592       }
03593     }
03594     if (changed) {
03595       con_sys.insert(Constraint::epsilon_leq_one());
03596       con_sys.set_sorted(false);
03597       // After changing the system of constraints, the generators
03598       // are no longer up-to-date and the constraints are no longer
03599       // minimized.
03600       clear_generators_up_to_date();
03601       clear_constraints_minimized();
03602     }
03603   }
03604   else {
03605     // Here we use generators, possibly keeping constraints.
03606     PPL_ASSERT(generators_are_up_to_date());
03607     // Add the corresponding point to each closure point.
03608     gen_sys.add_corresponding_points();
03609     if (can_have_something_pending())
03610       set_generators_pending();
03611     else {
03612       // We cannot have pending generators; this also implies
03613       // that generators may have lost their sortedness.
03614       gen_sys.unset_pending_rows();
03615       gen_sys.set_sorted(false);
03616       // Constraints are not up-to-date and generators are not minimized.
03617       clear_constraints_up_to_date();
03618       clear_generators_minimized();
03619     }
03620   }
03621   PPL_ASSERT_HEAVY(OK());
03622 }
03623 
03625 bool
03626 PPL::operator==(const Polyhedron& x, const Polyhedron& y) {
03627   // If the two polyhedra are topology-incompatible or dimension-incompatible,
03628   // then they cannot be the same polyhedron.
03629   if (x.topology() != y.topology() || x.space_dim != y.space_dim)
03630     return false;
03631 
03632   if (x.marked_empty())
03633     return y.is_empty();
03634   else if (y.marked_empty())
03635     return x.is_empty();
03636   else if (x.space_dim == 0)
03637     return true;
03638 
03639   switch (x.quick_equivalence_test(y)) {
03640   case Polyhedron::TVB_TRUE:
03641     return true;
03642 
03643   case Polyhedron::TVB_FALSE:
03644     return false;
03645 
03646   default:
03647     if (x.is_included_in(y))
03648       if (x.marked_empty())
03649         return y.is_empty();
03650       else
03651         return y.is_included_in(x);
03652     else
03653       return false;
03654   }
03655 }
03656 
03657 bool
03658 PPL::Polyhedron::contains(const Polyhedron& y) const {
03659   const Polyhedron& x = *this;
03660 
03661   // Topology compatibility check.
03662   if (x.topology() != y.topology())
03663     throw_topology_incompatible("contains(y)", "y", y);
03664 
03665   // Dimension-compatibility check.
03666   if (x.space_dim != y.space_dim)
03667     throw_dimension_incompatible("contains(y)", "y", y);
03668 
03669   if (y.marked_empty())
03670     return true;
03671   else if (x.marked_empty())
03672     return y.is_empty();
03673   else if (y.space_dim == 0)
03674     return true;
03675   else if (x.quick_equivalence_test(y) == Polyhedron::TVB_TRUE)
03676     return true;
03677   else
03678     return y.is_included_in(x);
03679 }
03680 
03681 bool
03682 PPL::Polyhedron::is_disjoint_from(const Polyhedron& y) const {
03683   Polyhedron z = *this;
03684   z.intersection_assign(y);
03685   return z.is_empty();
03686 }
03687 
03688 void
03689 PPL::Polyhedron::ascii_dump(std::ostream& s) const {
03690   s << "space_dim " << space_dim << "\n";
03691   status.ascii_dump(s);
03692   s << "\ncon_sys ("
03693     << (constraints_are_up_to_date() ? "" : "not_")
03694     << "up-to-date)"
03695     << "\n";
03696   con_sys.ascii_dump(s);
03697   s << "\ngen_sys ("
03698     << (generators_are_up_to_date() ? "" : "not_")
03699     << "up-to-date)"
03700     << "\n";
03701   gen_sys.ascii_dump(s);
03702   s << "\nsat_c\n";
03703   sat_c.ascii_dump(s);
03704   s << "\nsat_g\n";
03705   sat_g.ascii_dump(s);
03706   s << "\n";
03707 }
03708 
03709 PPL_OUTPUT_DEFINITIONS(Polyhedron)
03710 
03711 bool
03712 PPL::Polyhedron::ascii_load(std::istream& s) {
03713   std::string str;
03714 
03715   if (!(s >> str) || str != "space_dim")
03716     return false;
03717 
03718   if (!(s >> space_dim))
03719     return false;
03720 
03721   if (!status.ascii_load(s))
03722     return false;
03723 
03724   if (!(s >> str) || str != "con_sys")
03725     return false;
03726 
03727   if (!(s >> str) || (str != "(not_up-to-date)" && str != "(up-to-date)"))
03728     return false;
03729 
03730   if (!con_sys.ascii_load(s))
03731     return false;
03732 
03733   if (!(s >> str) || str != "gen_sys")
03734     return false;
03735 
03736   if (!(s >> str) || (str != "(not_up-to-date)" && str != "(up-to-date)"))
03737     return false;
03738 
03739   if (!gen_sys.ascii_load(s))
03740     return false;
03741 
03742   if (!(s >> str) || str != "sat_c")
03743     return false;
03744 
03745   if (!sat_c.ascii_load(s))
03746     return false;
03747 
03748   if (!(s >> str) || str != "sat_g")
03749     return false;
03750 
03751   if (!sat_g.ascii_load(s))
03752     return false;
03753 
03754   // Check invariants.
03755   PPL_ASSERT_HEAVY(OK());
03756   return true;
03757 }
03758 
03759 PPL::memory_size_type
03760 PPL::Polyhedron::external_memory_in_bytes() const {
03761   return
03762     con_sys.external_memory_in_bytes()
03763     + gen_sys.external_memory_in_bytes()
03764     + sat_c.external_memory_in_bytes()
03765     + sat_g.external_memory_in_bytes();
03766 }
03767 
03768 void
03769 PPL::Polyhedron::wrap_assign(const Variables_Set& vars,
03770                              Bounded_Integer_Type_Width w,
03771                              Bounded_Integer_Type_Representation r,
03772                              Bounded_Integer_Type_Overflow o,
03773                              const Constraint_System* cs_p,
03774                              unsigned complexity_threshold,
03775                              bool wrap_individually) {
03776   if (is_necessarily_closed())
03777     Implementation::wrap_assign(static_cast<C_Polyhedron&>(*this),
03778                                 vars, w, r, o, cs_p,
03779                                 complexity_threshold, wrap_individually,
03780                                 "C_Polyhedron");
03781   else
03782     Implementation::wrap_assign(static_cast<NNC_Polyhedron&>(*this),
03783                                 vars, w, r, o, cs_p,
03784                                 complexity_threshold, wrap_individually,
03785                                 "NNC_Polyhedron");
03786 }
03787 
03789 std::ostream&
03790 PPL::IO_Operators::operator<<(std::ostream& s, const Polyhedron& ph) {
03791   if (ph.is_empty())
03792     s << "false";
03793   else
03794     s << ph.minimized_constraints();
03795   return s;
03796 }