PPL  0.12.1
Polyhedron_nonpublic.cc
Go to the documentation of this file.
00001 /* Polyhedron class implementation
00002    (non-inline private or protected functions).
00003    Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
00004    Copyright (C) 2010-2012 BUGSENG srl (http://bugseng.com)
00005 
00006 This file is part of the Parma Polyhedra Library (PPL).
00007 
00008 The PPL is free software; you can redistribute it and/or modify it
00009 under the terms of the GNU General Public License as published by the
00010 Free Software Foundation; either version 3 of the License, or (at your
00011 option) any later version.
00012 
00013 The PPL is distributed in the hope that it will be useful, but WITHOUT
00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00015 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016 for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with this program; if not, write to the Free Software Foundation,
00020 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
00021 
00022 For the most up-to-date information see the Parma Polyhedra Library
00023 site: http://bugseng.com/products/ppl/ . */
00024 
00025 #include "ppl-config.h"
00026 #include "Polyhedron.defs.hh"
00027 #include "Scalar_Products.defs.hh"
00028 #include "Linear_Form.defs.hh"
00029 #include "C_Integer.hh"
00030 #include "assert.hh"
00031 #include <string>
00032 #include <iostream>
00033 #include <sstream>
00034 #include <stdexcept>
00035 
00036 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
00037 
00046 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
00047 #define BE_LAZY 1
00048 
00049 namespace PPL = Parma_Polyhedra_Library;
00050 
00051 PPL::Polyhedron::Polyhedron(const Topology topol,
00052                             const dimension_type num_dimensions,
00053                             const Degenerate_Element kind)
00054   : con_sys(topol),
00055     gen_sys(topol),
00056     sat_c(),
00057     sat_g() {
00058   // Protecting against space dimension overflow is up to the caller.
00059   PPL_ASSERT(num_dimensions <= max_space_dimension());
00060 
00061   if (kind == EMPTY)
00062     status.set_empty();
00063   else if (num_dimensions > 0) {
00064     con_sys.add_low_level_constraints();
00065     con_sys.adjust_topology_and_space_dimension(topol, num_dimensions);
00066     set_constraints_minimized();
00067   }
00068   space_dim = num_dimensions;
00069   PPL_ASSERT_HEAVY(OK());
00070 }
00071 
00072 PPL::Polyhedron::Polyhedron(const Polyhedron& y, Complexity_Class)
00073   : con_sys(y.topology()),
00074     gen_sys(y.topology()),
00075     status(y.status),
00076     space_dim(y.space_dim) {
00077   // Being a protected method, we simply assert that topologies do match.
00078   PPL_ASSERT(topology() == y.topology());
00079   if (y.constraints_are_up_to_date())
00080     con_sys.assign_with_pending(y.con_sys);
00081   if (y.generators_are_up_to_date())
00082     gen_sys.assign_with_pending(y.gen_sys);
00083   if (y.sat_c_is_up_to_date())
00084     sat_c = y.sat_c;
00085   if (y.sat_g_is_up_to_date())
00086     sat_g = y.sat_g;
00087 }
00088 
00089 PPL::Polyhedron::Polyhedron(const Topology topol, const Constraint_System& cs)
00090   : con_sys(topol),
00091     gen_sys(topol),
00092     sat_c(),
00093     sat_g() {
00094   // Protecting against space dimension overflow is up to the caller.
00095   PPL_ASSERT(cs.space_dimension() <= max_space_dimension());
00096 
00097   // TODO: this implementation is just an executable specification.
00098   Constraint_System cs_copy = cs;
00099 
00100   // Try to adapt `cs_copy' to the required topology.
00101   const dimension_type cs_copy_space_dim = cs_copy.space_dimension();
00102   if (!cs_copy.adjust_topology_and_space_dimension(topol, cs_copy_space_dim))
00103     throw_topology_incompatible((topol == NECESSARILY_CLOSED)
00104                                 ? "C_Polyhedron(cs)"
00105                                 : "NNC_Polyhedron(cs)", "cs", cs_copy);
00106 
00107   // Set the space dimension.
00108   space_dim = cs_copy_space_dim;
00109 
00110   if (space_dim > 0) {
00111     // Stealing the rows from `cs_copy'.
00112     using std::swap;
00113     swap(con_sys, cs_copy);
00114     if (con_sys.num_pending_rows() > 0) {
00115       // Even though `cs_copy' has pending constraints, since the
00116       // generators of the polyhedron are not up-to-date, the
00117       // polyhedron cannot have pending constraints. By integrating
00118       // the pending part of `con_sys' we may loose sortedness.
00119       con_sys.unset_pending_rows();
00120       con_sys.set_sorted(false);
00121     }
00122     con_sys.add_low_level_constraints();
00123     set_constraints_up_to_date();
00124   }
00125   else {
00126     // Here `space_dim == 0'.
00127     if (cs_copy.num_columns() > 0)
00128       // See if an inconsistent constraint has been passed.
00129       for (dimension_type i = cs_copy.num_rows(); i-- > 0; )
00130         if (cs_copy[i].is_inconsistent()) {
00131           // Inconsistent constraint found: the polyhedron is empty.
00132           set_empty();
00133           break;
00134         }
00135   }
00136   PPL_ASSERT_HEAVY(OK());
00137 }
00138 
00139 PPL::Polyhedron::Polyhedron(const Topology topol,
00140                             Constraint_System& cs,
00141                             Recycle_Input)
00142   : con_sys(topol),
00143     gen_sys(topol),
00144     sat_c(),
00145     sat_g() {
00146   // Protecting against space dimension overflow is up to the caller.
00147   PPL_ASSERT(cs.space_dimension() <= max_space_dimension());
00148 
00149   // Try to adapt `cs' to the required topology.
00150   const dimension_type cs_space_dim = cs.space_dimension();
00151   if (!cs.adjust_topology_and_space_dimension(topol, cs_space_dim))
00152     throw_topology_incompatible((topol == NECESSARILY_CLOSED)
00153                                 ? "C_Polyhedron(cs, recycle)"
00154                                 : "NNC_Polyhedron(cs, recycle)", "cs", cs);
00155 
00156   // Set the space dimension.
00157   space_dim = cs_space_dim;
00158 
00159   if (space_dim > 0) {
00160     // Stealing the rows from `cs'.
00161     using std::swap;
00162     swap(con_sys, cs);
00163     if (con_sys.num_pending_rows() > 0) {
00164       // Even though `cs' has pending constraints, since the generators
00165       // of the polyhedron are not up-to-date, the polyhedron cannot
00166       // have pending constraints. By integrating the pending part
00167       // of `con_sys' we may loose sortedness.
00168       con_sys.unset_pending_rows();
00169       con_sys.set_sorted(false);
00170     }
00171     con_sys.add_low_level_constraints();
00172     set_constraints_up_to_date();
00173   }
00174   else {
00175     // Here `space_dim == 0'.
00176     if (cs.num_columns() > 0)
00177       // See if an inconsistent constraint has been passed.
00178       for (dimension_type i = cs.num_rows(); i-- > 0; )
00179         if (cs[i].is_inconsistent()) {
00180           // Inconsistent constraint found: the polyhedron is empty.
00181           set_empty();
00182           break;
00183         }
00184   }
00185   PPL_ASSERT_HEAVY(OK());
00186 }
00187 
00188 PPL::Polyhedron::Polyhedron(const Topology topol, const Generator_System& gs)
00189   : con_sys(topol),
00190     gen_sys(topol),
00191     sat_c(),
00192     sat_g() {
00193   // Protecting against space dimension overflow is up to the caller.
00194   PPL_ASSERT(gs.space_dimension() <= max_space_dimension());
00195 
00196   // An empty set of generators defines the empty polyhedron.
00197   if (gs.has_no_rows()) {
00198     space_dim = gs.space_dimension();
00199     status.set_empty();
00200     PPL_ASSERT_HEAVY(OK());
00201     return;
00202   }
00203 
00204   // Non-empty valid generator systems have a supporting point, at least.
00205   if (!gs.has_points())
00206     throw_invalid_generators((topol == NECESSARILY_CLOSED)
00207                              ? "C_Polyhedron(gs)"
00208                              : "NNC_Polyhedron(gs)", "gs");
00209 
00210   // TODO: this implementation is just an executable specification.
00211   Generator_System gs_copy = gs;
00212 
00213   const dimension_type gs_copy_space_dim = gs_copy.space_dimension();
00214   // Try to adapt `gs_copy' to the required topology.
00215   if (!gs_copy.adjust_topology_and_space_dimension(topol, gs_copy_space_dim))
00216     throw_topology_incompatible((topol == NECESSARILY_CLOSED)
00217                                 ? "C_Polyhedron(gs)"
00218                                 : "NNC_Polyhedron(gs)", "gs", gs_copy);
00219 
00220   if (gs_copy_space_dim > 0) {
00221     // Stealing the rows from `gs_copy'.
00222     using std::swap;
00223     swap(gen_sys, gs_copy);
00224     // In a generator system describing a NNC polyhedron,
00225     // for each point we must also have the corresponding closure point.
00226     if (topol == NOT_NECESSARILY_CLOSED)
00227       gen_sys.add_corresponding_closure_points();
00228     if (gen_sys.num_pending_rows() > 0) {
00229       // Even though `gs_copy' has pending generators, since the
00230       // constraints of the polyhedron are not up-to-date, the
00231       // polyhedron cannot have pending generators. By integrating the
00232       // pending part of `gen_sys' we may loose sortedness.
00233       gen_sys.unset_pending_rows();
00234       gen_sys.set_sorted(false);
00235     }
00236     // Generators are now up-to-date.
00237     set_generators_up_to_date();
00238 
00239     // Set the space dimension.
00240     space_dim = gs_copy_space_dim;
00241     PPL_ASSERT_HEAVY(OK());
00242     return;
00243   }
00244 
00245   // Here `gs_copy.num_rows > 0' and `gs_copy_space_dim == 0':
00246   // we already checked for both the topology-compatibility
00247   // and the supporting point.
00248   space_dim = 0;
00249   PPL_ASSERT_HEAVY(OK());
00250 }
00251 
00252 PPL::Polyhedron::Polyhedron(const Topology topol,
00253                             Generator_System& gs,
00254                             Recycle_Input)
00255   : con_sys(topol),
00256     gen_sys(topol),
00257     sat_c(),
00258     sat_g() {
00259   // Protecting against space dimension overflow is up to the caller.
00260   PPL_ASSERT(gs.space_dimension() <= max_space_dimension());
00261 
00262   // An empty set of generators defines the empty polyhedron.
00263   if (gs.has_no_rows()) {
00264     space_dim = gs.space_dimension();
00265     status.set_empty();
00266     PPL_ASSERT_HEAVY(OK());
00267     return;
00268   }
00269 
00270   // Non-empty valid generator systems have a supporting point, at least.
00271   if (!gs.has_points())
00272     throw_invalid_generators((topol == NECESSARILY_CLOSED)
00273                              ? "C_Polyhedron(gs, recycle)"
00274                              : "NNC_Polyhedron(gs, recycle)", "gs");
00275 
00276   const dimension_type gs_space_dim = gs.space_dimension();
00277   // Try to adapt `gs' to the required topology.
00278   if (!gs.adjust_topology_and_space_dimension(topol, gs_space_dim))
00279     throw_topology_incompatible((topol == NECESSARILY_CLOSED)
00280                                 ? "C_Polyhedron(gs, recycle)"
00281                                 : "NNC_Polyhedron(gs, recycle)", "gs", gs);
00282 
00283   if (gs_space_dim > 0) {
00284     // Stealing the rows from `gs'.
00285     using std::swap;
00286     swap(gen_sys, gs);
00287     // In a generator system describing a NNC polyhedron,
00288     // for each point we must also have the corresponding closure point.
00289     if (topol == NOT_NECESSARILY_CLOSED)
00290       gen_sys.add_corresponding_closure_points();
00291     if (gen_sys.num_pending_rows() > 0) {
00292       // Even though `gs' has pending generators, since the constraints
00293       // of the polyhedron are not up-to-date, the polyhedron cannot
00294       // have pending generators. By integrating the pending part
00295       // of `gen_sys' we may loose sortedness.
00296       gen_sys.unset_pending_rows();
00297       gen_sys.set_sorted(false);
00298     }
00299     // Generators are now up-to-date.
00300     set_generators_up_to_date();
00301 
00302     // Set the space dimension.
00303     space_dim = gs_space_dim;
00304     PPL_ASSERT_HEAVY(OK());
00305     return;
00306   }
00307 
00308   // Here `gs.num_rows > 0' and `gs_space_dim == 0':
00309   // we already checked for both the topology-compatibility
00310   // and the supporting point.
00311   space_dim = 0;
00312   PPL_ASSERT_HEAVY(OK());
00313 }
00314 
00315 PPL::Polyhedron&
00316 PPL::Polyhedron::operator=(const Polyhedron& y) {
00317   // Being a protected method, we simply assert that topologies do match.
00318   PPL_ASSERT(topology() == y.topology());
00319   space_dim = y.space_dim;
00320   if (y.marked_empty())
00321     set_empty();
00322   else if (space_dim == 0)
00323     set_zero_dim_univ();
00324   else {
00325     status = y.status;
00326     if (y.constraints_are_up_to_date())
00327       con_sys.assign_with_pending(y.con_sys);
00328     if (y.generators_are_up_to_date())
00329       gen_sys.assign_with_pending(y.gen_sys);
00330     if (y.sat_c_is_up_to_date())
00331       sat_c = y.sat_c;
00332     if (y.sat_g_is_up_to_date())
00333       sat_g = y.sat_g;
00334   }
00335   return *this;
00336 }
00337 
00338 PPL::Polyhedron::Three_Valued_Boolean
00339 PPL::Polyhedron::quick_equivalence_test(const Polyhedron& y) const {
00340   // Private method: the caller must ensure the following.
00341   PPL_ASSERT(topology() == y.topology());
00342   PPL_ASSERT(space_dim == y.space_dim);
00343   PPL_ASSERT(!marked_empty() && !y.marked_empty() && space_dim > 0);
00344 
00345   const Polyhedron& x = *this;
00346 
00347   if (x.is_necessarily_closed()) {
00348     if (!x.has_something_pending() && !y.has_something_pending()) {
00349       bool css_normalized = false;
00350       if (x.constraints_are_minimized() && y.constraints_are_minimized()) {
00351         // Equivalent minimized constraint systems have:
00352         //  - the same number of constraints; ...
00353         if (x.con_sys.num_rows() != y.con_sys.num_rows())
00354           return Polyhedron::TVB_FALSE;
00355         //  - the same number of equalities; ...
00356         dimension_type x_num_equalities = x.con_sys.num_equalities();
00357         if (x_num_equalities != y.con_sys.num_equalities())
00358           return Polyhedron::TVB_FALSE;
00359         //  - if there are no equalities, they have the same constraints.
00360         //    Delay this test: try cheaper tests on generators first.
00361         css_normalized = (x_num_equalities == 0);
00362       }
00363 
00364       if (x.generators_are_minimized() && y.generators_are_minimized()) {
00365         // Equivalent minimized generator systems have:
00366         //  - the same number of generators; ...
00367         if (x.gen_sys.num_rows() != y.gen_sys.num_rows())
00368           return Polyhedron::TVB_FALSE;
00369         //  - the same number of lines; ...
00370         const dimension_type x_num_lines = x.gen_sys.num_lines();
00371         if (x_num_lines != y.gen_sys.num_lines())
00372           return Polyhedron::TVB_FALSE;
00373         //  - if there are no lines, they have the same generators.
00374         if (x_num_lines == 0) {
00375           // Sort the two systems and check for syntactic identity.
00376           x.obtain_sorted_generators();
00377           y.obtain_sorted_generators();
00378           if (x.gen_sys == y.gen_sys)
00379             return Polyhedron::TVB_TRUE;
00380           else
00381             return Polyhedron::TVB_FALSE;
00382         }
00383       }
00384 
00385       if (css_normalized) {
00386         // Sort the two systems and check for identity.
00387         x.obtain_sorted_constraints();
00388         y.obtain_sorted_constraints();
00389         if (x.con_sys == y.con_sys)
00390             return Polyhedron::TVB_TRUE;
00391           else
00392             return Polyhedron::TVB_FALSE;
00393       }
00394     }
00395   }
00396   return Polyhedron::TVB_DONT_KNOW;
00397 }
00398 
00399 bool
00400 PPL::Polyhedron::is_included_in(const Polyhedron& y) const {
00401   // Private method: the caller must ensure the following.
00402   PPL_ASSERT(topology() == y.topology());
00403   PPL_ASSERT(space_dim == y.space_dim);
00404   PPL_ASSERT(!marked_empty() && !y.marked_empty() && space_dim > 0);
00405 
00406   const Polyhedron& x = *this;
00407 
00408   // `x' cannot have pending constraints, because we need its generators.
00409   if (x.has_pending_constraints() && !x.process_pending_constraints())
00410     return true;
00411   // `y' cannot have pending generators, because we need its constraints.
00412   if (y.has_pending_generators())
00413     y.process_pending_generators();
00414 
00415 #if BE_LAZY
00416   if (!x.generators_are_up_to_date() && !x.update_generators())
00417     return true;
00418   if (!y.constraints_are_up_to_date())
00419     y.update_constraints();
00420 #else
00421   if (!x.generators_are_minimized())
00422     x.minimize();
00423   if (!y.constraints_are_minimized())
00424     y.minimize();
00425 #endif
00426 
00427   PPL_ASSERT_HEAVY(x.OK());
00428   PPL_ASSERT_HEAVY(y.OK());
00429 
00430   const Generator_System& gs = x.gen_sys;
00431   const Constraint_System& cs = y.con_sys;
00432 
00433   if (x.is_necessarily_closed())
00434     // When working with necessarily closed polyhedra,
00435     // `x' is contained in `y' if and only if all the generators of `x'
00436     // satisfy all the inequalities and saturate all the equalities of `y'.
00437     // This comes from the definition of a polyhedron as the set of
00438     // vectors satisfying a constraint system and the fact that all
00439     // vectors in `x' can be obtained by suitably combining its generators.
00440     for (dimension_type i = cs.num_rows(); i-- > 0; ) {
00441       const Constraint& c = cs[i];
00442       if (c.is_inequality()) {
00443         for (dimension_type j = gs.num_rows(); j-- > 0; ) {
00444           const Generator& g = gs[j];
00445           const int sp_sign = Scalar_Products::sign(c, g);
00446           if (g.is_line()) {
00447             if (sp_sign != 0)
00448               return false;
00449           }
00450           else
00451             // `g' is a ray or a point.
00452             if (sp_sign < 0)
00453               return false;
00454         }
00455       }
00456       else {
00457         // `c' is an equality.
00458         for (dimension_type j = gs.num_rows(); j-- > 0; )
00459           if (Scalar_Products::sign(c, gs[j]) != 0)
00460             return false;
00461       }
00462     }
00463   else {
00464     // Here we have an NNC polyhedron: using the reduced scalar product,
00465     // which ignores the epsilon coefficient.
00466     for (dimension_type i = cs.num_rows(); i-- > 0; ) {
00467       const Constraint& c = cs[i];
00468       switch (c.type()) {
00469       case Constraint::NONSTRICT_INEQUALITY:
00470         for (dimension_type j = gs.num_rows(); j-- > 0; ) {
00471           const Generator& g = gs[j];
00472           const int sp_sign = Scalar_Products::reduced_sign(c, g);
00473           if (g.is_line()) {
00474             if (sp_sign != 0)
00475               return false;
00476           }
00477           else
00478             // `g' is a ray or a point or a closure point.
00479             if (sp_sign < 0)
00480               return false;
00481         }
00482         break;
00483       case Constraint::EQUALITY:
00484         for (dimension_type j = gs.num_rows(); j-- > 0; )
00485           if (Scalar_Products::reduced_sign(c, gs[j]) != 0)
00486             return false;
00487         break;
00488       case Constraint::STRICT_INEQUALITY:
00489         for (dimension_type j = gs.num_rows(); j-- > 0; ) {
00490           const Generator& g = gs[j];
00491           const int sp_sign = Scalar_Products::reduced_sign(c, g);
00492           switch (g.type()) {
00493           case Generator::POINT:
00494             // If a point violates or saturates a strict inequality
00495             // (when ignoring the epsilon coefficients) then it is
00496             // not included in the polyhedron.
00497             if (sp_sign <= 0)
00498               return false;
00499             break;
00500           case Generator::LINE:
00501             // Lines have to saturate all constraints.
00502             if (sp_sign != 0)
00503               return false;
00504             break;
00505           case Generator::RAY:
00506             // Intentionally fall through.
00507           case Generator::CLOSURE_POINT:
00508             // The generator is a ray or closure point: usual test.
00509             if (sp_sign < 0)
00510               return false;
00511             break;
00512           }
00513         }
00514         break;
00515       }
00516     }
00517   }
00518 
00519   // Inclusion holds.
00520   return true;
00521 }
00522 
00523 bool
00524 PPL::Polyhedron::bounds(const Linear_Expression& expr,
00525                         const bool from_above) const {
00526   // The dimension of `expr' should not be greater than the dimension
00527   // of `*this'.
00528   const dimension_type expr_space_dim = expr.space_dimension();
00529   if (space_dim < expr_space_dim)
00530     throw_dimension_incompatible((from_above
00531                                   ? "bounds_from_above(e)"
00532                                   : "bounds_from_below(e)"), "e", expr);
00533 
00534   // A zero-dimensional or empty polyhedron bounds everything.
00535   if (space_dim == 0
00536       || marked_empty()
00537       || (has_pending_constraints() && !process_pending_constraints())
00538       || (!generators_are_up_to_date() && !update_generators()))
00539     return true;
00540 
00541   // The polyhedron has updated, possibly pending generators.
00542   for (dimension_type i = gen_sys.num_rows(); i-- > 0; ) {
00543     const Generator& g = gen_sys[i];
00544     // Only lines and rays in `*this' can cause `expr' to be unbounded.
00545     if (g.is_line_or_ray()) {
00546       const int sp_sign = Scalar_Products::homogeneous_sign(expr, g);
00547       if (sp_sign != 0
00548           && (g.is_line()
00549               || (from_above && sp_sign > 0)
00550               || (!from_above && sp_sign < 0)))
00551         // `*this' does not bound `expr'.
00552         return false;
00553     }
00554   }
00555   // No sources of unboundedness have been found for `expr'
00556   // in the given direction.
00557   return true;
00558 }
00559 
00560 bool
00561 PPL::Polyhedron::max_min(const Linear_Expression& expr,
00562                          const bool maximize,
00563                          Coefficient& ext_n, Coefficient& ext_d,
00564                          bool& included,
00565                          Generator& g) const {
00566   // The dimension of `expr' should not be greater than the dimension
00567   // of `*this'.
00568   const dimension_type expr_space_dim = expr.space_dimension();
00569   if (space_dim < expr_space_dim)
00570     throw_dimension_incompatible((maximize
00571                                   ? "maximize(e, ...)"
00572                                   : "minimize(e, ...)"), "e", expr);
00573 
00574   // Deal with zero-dim polyhedra first.
00575   if (space_dim == 0) {
00576     if (marked_empty())
00577       return false;
00578     else {
00579       ext_n = expr.inhomogeneous_term();
00580       ext_d = 1;
00581       included = true;
00582       g = point();
00583       return true;
00584     }
00585   }
00586 
00587   // For an empty polyhedron we simply return false.
00588   if (marked_empty()
00589       || (has_pending_constraints() && !process_pending_constraints())
00590       || (!generators_are_up_to_date() && !update_generators()))
00591     return false;
00592 
00593   // The polyhedron has updated, possibly pending generators.
00594   // The following loop will iterate through the generator
00595   // to find the extremum.
00596   PPL_DIRTY_TEMP(mpq_class, extremum);
00597 
00598   // True if we have no other candidate extremum to compare with.
00599   bool first_candidate = true;
00600 
00601   // To store the position of the current candidate extremum.
00602   PPL_UNINITIALIZED(dimension_type, ext_position);
00603 
00604   // Whether the current candidate extremum is included or not.
00605   PPL_UNINITIALIZED(bool, ext_included);
00606 
00607   PPL_DIRTY_TEMP_COEFFICIENT(sp);
00608   for (dimension_type i = gen_sys.num_rows(); i-- > 0; ) {
00609     const Generator& gen_sys_i = gen_sys[i];
00610     Scalar_Products::homogeneous_assign(sp, expr, gen_sys_i);
00611     // Lines and rays in `*this' can cause `expr' to be unbounded.
00612     if (gen_sys_i.is_line_or_ray()) {
00613       const int sp_sign = sgn(sp);
00614       if (sp_sign != 0
00615           && (gen_sys_i.is_line()
00616               || (maximize && sp_sign > 0)
00617               || (!maximize && sp_sign < 0)))
00618         // `expr' is unbounded in `*this'.
00619         return false;
00620     }
00621     else {
00622       // We have a point or a closure point.
00623       PPL_ASSERT(gen_sys_i.is_point() || gen_sys_i.is_closure_point());
00624       // Notice that we are ignoring the constant term in `expr' here.
00625       // We will add it to the extremum as soon as we find it.
00626       PPL_DIRTY_TEMP(mpq_class, candidate);
00627       assign_r(candidate.get_num(), sp, ROUND_NOT_NEEDED);
00628       assign_r(candidate.get_den(), gen_sys_i[0], ROUND_NOT_NEEDED);
00629       candidate.canonicalize();
00630       const bool g_is_point = gen_sys_i.is_point();
00631       if (first_candidate
00632           || (maximize
00633               && (candidate > extremum
00634                   || (g_is_point
00635                       && !ext_included
00636                       && candidate == extremum)))
00637           || (!maximize
00638               && (candidate < extremum
00639                   || (g_is_point
00640                       && !ext_included
00641                       && candidate == extremum)))) {
00642         // We have a (new) candidate extremum.
00643         first_candidate = false;
00644         extremum = candidate;
00645         ext_position = i;
00646         ext_included = g_is_point;
00647       }
00648     }
00649   }
00650 
00651   // Add in the constant term in `expr'.
00652   PPL_DIRTY_TEMP(mpz_class, n);
00653   assign_r(n, expr.inhomogeneous_term(), ROUND_NOT_NEEDED);
00654   extremum += n;
00655 
00656   // The polyhedron is bounded in the right direction and we have
00657   // computed the extremum: write the result into the caller's structures.
00658   PPL_ASSERT(!first_candidate);
00659   // FIXME: avoid these temporaries, if possible.
00660   // This can be done adding an `assign' function working on native
00661   // and checked or an operator= that have on one side a checked and
00662   // on the other a native or checked.
00663   // The reason why now we can't use operator= is the fact that we
00664   // still can have Coefficient defined to mpz_class (and not
00665   // Checked_Number<mpz_class>).
00666   ext_n = Coefficient(extremum.get_num());
00667   ext_d = Coefficient(extremum.get_den());
00668   included = ext_included;
00669   g = gen_sys[ext_position];
00670 
00671   return true;
00672 }
00673 
00674 void
00675 PPL::Polyhedron::set_zero_dim_univ() {
00676   status.set_zero_dim_univ();
00677   space_dim = 0;
00678   con_sys.clear();
00679   gen_sys.clear();
00680 }
00681 
00682 void
00683 PPL::Polyhedron::set_empty() {
00684   status.set_empty();
00685   // The polyhedron is empty: we can thus throw away everything.
00686   con_sys.clear();
00687   gen_sys.clear();
00688   sat_c.clear();
00689   sat_g.clear();
00690 }
00691 
00692 bool
00693 PPL::Polyhedron::process_pending_constraints() const {
00694   PPL_ASSERT(space_dim > 0 && !marked_empty());
00695   PPL_ASSERT(has_pending_constraints() && !has_pending_generators());
00696 
00697   Polyhedron& x = const_cast<Polyhedron&>(*this);
00698 
00699   // Integrate the pending part of the system of constraints and minimize.
00700   // We need `sat_c' up-to-date and `con_sys' sorted (together with `sat_c').
00701   if (!x.sat_c_is_up_to_date())
00702     x.sat_c.transpose_assign(x.sat_g);
00703   if (!x.con_sys.is_sorted())
00704     x.obtain_sorted_constraints_with_sat_c();
00705   // We sort in place the pending constraints, erasing those constraints
00706   // that also occur in the non-pending part of `con_sys'.
00707   x.con_sys.sort_pending_and_remove_duplicates();
00708   if (x.con_sys.num_pending_rows() == 0) {
00709     // All pending constraints were duplicates.
00710     x.clear_pending_constraints();
00711     PPL_ASSERT_HEAVY(OK(true));
00712     return true;
00713   }
00714 
00715   const bool empty = add_and_minimize(true, x.con_sys, x.gen_sys, x.sat_c);
00716   PPL_ASSERT(x.con_sys.num_pending_rows() == 0);
00717 
00718   if (empty)
00719     x.set_empty();
00720   else {
00721     x.clear_pending_constraints();
00722     x.clear_sat_g_up_to_date();
00723     x.set_sat_c_up_to_date();
00724   }
00725   PPL_ASSERT_HEAVY(OK(!empty));
00726   return !empty;
00727 }
00728 
00729 void
00730 PPL::Polyhedron::process_pending_generators() const {
00731   PPL_ASSERT(space_dim > 0 && !marked_empty());
00732   PPL_ASSERT(has_pending_generators() && !has_pending_constraints());
00733 
00734   Polyhedron& x = const_cast<Polyhedron&>(*this);
00735 
00736   // Integrate the pending part of the system of generators and minimize.
00737   // We need `sat_g' up-to-date and `gen_sys' sorted (together with `sat_g').
00738   if (!x.sat_g_is_up_to_date())
00739     x.sat_g.transpose_assign(x.sat_c);
00740   if (!x.gen_sys.is_sorted())
00741     x.obtain_sorted_generators_with_sat_g();
00742   // We sort in place the pending generators, erasing those generators
00743   // that also occur in the non-pending part of `gen_sys'.
00744   x.gen_sys.sort_pending_and_remove_duplicates();
00745   if (x.gen_sys.num_pending_rows() == 0) {
00746     // All pending generators were duplicates.
00747     x.clear_pending_generators();
00748     PPL_ASSERT_HEAVY(OK(true));
00749     return;
00750   }
00751 
00752   add_and_minimize(false, x.gen_sys, x.con_sys, x.sat_g);
00753   PPL_ASSERT(x.gen_sys.num_pending_rows() == 0);
00754 
00755   x.clear_pending_generators();
00756   x.clear_sat_c_up_to_date();
00757   x.set_sat_g_up_to_date();
00758 }
00759 
00760 void
00761 PPL::Polyhedron::remove_pending_to_obtain_constraints() const {
00762   PPL_ASSERT(has_something_pending());
00763 
00764   Polyhedron& x = const_cast<Polyhedron&>(*this);
00765 
00766   // If the polyhedron has pending constraints, simply unset them.
00767   if (x.has_pending_constraints()) {
00768     // Integrate the pending constraints, which are possibly not sorted.
00769     x.con_sys.unset_pending_rows();
00770     x.con_sys.set_sorted(false);
00771     x.clear_pending_constraints();
00772     x.clear_constraints_minimized();
00773     x.clear_generators_up_to_date();
00774   }
00775   else {
00776     PPL_ASSERT(x.has_pending_generators());
00777     // We must process the pending generators and obtain the
00778     // corresponding system of constraints.
00779     x.process_pending_generators();
00780   }
00781   PPL_ASSERT_HEAVY(OK(true));
00782 }
00783 
00784 bool
00785 PPL::Polyhedron::remove_pending_to_obtain_generators() const {
00786   PPL_ASSERT(has_something_pending());
00787 
00788   Polyhedron& x = const_cast<Polyhedron&>(*this);
00789 
00790   // If the polyhedron has pending generators, simply unset them.
00791   if (x.has_pending_generators()) {
00792     // Integrate the pending generators, which are possibly not sorted.
00793     x.gen_sys.unset_pending_rows();
00794     x.gen_sys.set_sorted(false);
00795     x.clear_pending_generators();
00796     x.clear_generators_minimized();
00797     x.clear_constraints_up_to_date();
00798     PPL_ASSERT_HEAVY(OK(true));
00799     return true;
00800   }
00801   else {
00802     PPL_ASSERT(x.has_pending_constraints());
00803     // We must integrate the pending constraints and obtain the
00804     // corresponding system of generators.
00805     return x.process_pending_constraints();
00806   }
00807 }
00808 
00809 void
00810 PPL::Polyhedron::update_constraints() const {
00811   PPL_ASSERT(space_dim > 0);
00812   PPL_ASSERT(!marked_empty());
00813   PPL_ASSERT(generators_are_up_to_date());
00814   // We assume the polyhedron has no pending constraints or generators.
00815   PPL_ASSERT(!has_something_pending());
00816 
00817   Polyhedron& x = const_cast<Polyhedron&>(*this);
00818   minimize(false, x.gen_sys, x.con_sys, x.sat_c);
00819   // `sat_c' is the only saturation matrix up-to-date.
00820   x.set_sat_c_up_to_date();
00821   x.clear_sat_g_up_to_date();
00822   // The system of constraints and the system of generators
00823   // are minimized.
00824   x.set_constraints_minimized();
00825   x.set_generators_minimized();
00826 }
00827 
00828 bool
00829 PPL::Polyhedron::update_generators() const {
00830   PPL_ASSERT(space_dim > 0);
00831   PPL_ASSERT(!marked_empty());
00832   PPL_ASSERT(constraints_are_up_to_date());
00833   // We assume the polyhedron has no pending constraints or generators.
00834   PPL_ASSERT(!has_something_pending());
00835 
00836   Polyhedron& x = const_cast<Polyhedron&>(*this);
00837   // If the system of constraints is not consistent the
00838   // polyhedron is empty.
00839   const bool empty = minimize(true, x.con_sys, x.gen_sys, x.sat_g);
00840   if (empty)
00841     x.set_empty();
00842   else {
00843     // `sat_g' is the only saturation matrix up-to-date.
00844     x.set_sat_g_up_to_date();
00845     x.clear_sat_c_up_to_date();
00846     // The system of constraints and the system of generators
00847     // are minimized.
00848     x.set_constraints_minimized();
00849     x.set_generators_minimized();
00850   }
00851   return !empty;
00852 }
00853 
00854 void
00855 PPL::Polyhedron::update_sat_c() const {
00856   PPL_ASSERT(constraints_are_minimized());
00857   PPL_ASSERT(generators_are_minimized());
00858   PPL_ASSERT(!sat_c_is_up_to_date());
00859 
00860   // We only consider non-pending rows.
00861   const dimension_type csr = con_sys.first_pending_row();
00862   const dimension_type gsr = gen_sys.first_pending_row();
00863   Polyhedron& x = const_cast<Polyhedron&>(*this);
00864 
00865   // The columns of `sat_c' represent the constraints and
00866   // its rows represent the generators: resize accordingly.
00867   x.sat_c.resize(gsr, csr);
00868   for (dimension_type i = gsr; i-- > 0; )
00869     for (dimension_type j = csr; j-- > 0; ) {
00870       const int sp_sign = Scalar_Products::sign(con_sys[j], gen_sys[i]);
00871       // The negativity of this scalar product would mean
00872       // that the generator `gen_sys[i]' violates the constraint
00873       // `con_sys[j]' and it is not possible because both generators
00874       // and constraints are up-to-date.
00875       PPL_ASSERT(sp_sign >= 0);
00876       if (sp_sign > 0)
00877         // `gen_sys[i]' satisfies (without saturate) `con_sys[j]'.
00878         x.sat_c[i].set(j);
00879       else
00880         // `gen_sys[i]' saturates `con_sys[j]'.
00881         x.sat_c[i].clear(j);
00882     }
00883   x.set_sat_c_up_to_date();
00884 }
00885 
00886 void
00887 PPL::Polyhedron::update_sat_g() const {
00888   PPL_ASSERT(constraints_are_minimized());
00889   PPL_ASSERT(generators_are_minimized());
00890   PPL_ASSERT(!sat_g_is_up_to_date());
00891 
00892   // We only consider non-pending rows.
00893   const dimension_type csr = con_sys.first_pending_row();
00894   const dimension_type gsr = gen_sys.first_pending_row();
00895   Polyhedron& x = const_cast<Polyhedron&>(*this);
00896 
00897   // The columns of `sat_g' represent generators and its
00898   // rows represent the constraints: resize accordingly.
00899   x.sat_g.resize(csr, gsr);
00900   for (dimension_type i = csr; i-- > 0; )
00901     for (dimension_type j = gsr; j-- > 0; ) {
00902       const int sp_sign = Scalar_Products::sign(con_sys[i], gen_sys[j]);
00903       // The negativity of this scalar product would mean
00904       // that the generator `gen_sys[j]' violates the constraint
00905       // `con_sys[i]' and it is not possible because both generators
00906       // and constraints are up-to-date.
00907       PPL_ASSERT(sp_sign >= 0);
00908       if (sp_sign > 0)
00909         // `gen_sys[j]' satisfies (without saturate) `con_sys[i]'.
00910         x.sat_g[i].set(j);
00911       else
00912         // `gen_sys[j]' saturates `con_sys[i]'.
00913         x.sat_g[i].clear(j);
00914     }
00915   x.set_sat_g_up_to_date();
00916 }
00917 
00918 void
00919 PPL::Polyhedron::obtain_sorted_constraints() const {
00920   PPL_ASSERT(constraints_are_up_to_date());
00921   // `con_sys' will be sorted up to `index_first_pending'.
00922   Polyhedron& x = const_cast<Polyhedron&>(*this);
00923   if (!x.con_sys.is_sorted()) {
00924     if (x.sat_g_is_up_to_date()) {
00925       // Sorting constraints keeping `sat_g' consistent.
00926       x.con_sys.sort_and_remove_with_sat(x.sat_g);
00927       // `sat_c' is not up-to-date anymore.
00928       x.clear_sat_c_up_to_date();
00929     }
00930     else if (x.sat_c_is_up_to_date()) {
00931       // Using `sat_c' to obtain `sat_g', then it is like previous case.
00932       x.sat_g.transpose_assign(x.sat_c);
00933       x.con_sys.sort_and_remove_with_sat(x.sat_g);
00934       x.set_sat_g_up_to_date();
00935       x.clear_sat_c_up_to_date();
00936     }
00937     else
00938       // If neither `sat_g' nor `sat_c' are up-to-date,
00939       // we just sort the constraints.
00940       x.con_sys.sort_rows();
00941   }
00942 
00943   PPL_ASSERT(con_sys.check_sorted());
00944 }
00945 
00946 void
00947 PPL::Polyhedron::obtain_sorted_generators() const {
00948   PPL_ASSERT(generators_are_up_to_date());
00949   // `gen_sys' will be sorted up to `index_first_pending'.
00950   Polyhedron& x = const_cast<Polyhedron&>(*this);
00951   if (!x.gen_sys.is_sorted()) {
00952     if (x.sat_c_is_up_to_date()) {
00953       // Sorting generators keeping 'sat_c' consistent.
00954       x.gen_sys.sort_and_remove_with_sat(x.sat_c);
00955       // `sat_g' is not up-to-date anymore.
00956       x.clear_sat_g_up_to_date();
00957     }
00958     else if (x.sat_g_is_up_to_date()) {
00959       // Obtaining `sat_c' from `sat_g' and proceeding like previous case.
00960       x.sat_c.transpose_assign(x.sat_g);
00961       x.gen_sys.sort_and_remove_with_sat(x.sat_c);
00962       x.set_sat_c_up_to_date();
00963       x.clear_sat_g_up_to_date();
00964     }
00965     else
00966       // If neither `sat_g' nor `sat_c' are up-to-date, we just sort
00967       // the generators.
00968       x.gen_sys.sort_rows();
00969   }
00970 
00971   PPL_ASSERT(gen_sys.check_sorted());
00972 }
00973 
00974 void
00975 PPL::Polyhedron::obtain_sorted_constraints_with_sat_c() const {
00976   PPL_ASSERT(constraints_are_up_to_date());
00977   PPL_ASSERT(constraints_are_minimized());
00978   // `con_sys' will be sorted up to `index_first_pending'.
00979   Polyhedron& x = const_cast<Polyhedron&>(*this);
00980   // At least one of the saturation matrices must be up-to-date.
00981   if (!x.sat_c_is_up_to_date() && !x.sat_g_is_up_to_date())
00982     x.update_sat_c();
00983 
00984   if (x.con_sys.is_sorted()) {
00985     if (x.sat_c_is_up_to_date())
00986       // If constraints are already sorted and sat_c is up to
00987       // date there is nothing to do.
00988       return;
00989   }
00990   else {
00991     if (!x.sat_g_is_up_to_date()) {
00992       // If constraints are not sorted and sat_g is not up-to-date
00993       // we obtain sat_g from sat_c (that has to be up-to-date)...
00994       x.sat_g.transpose_assign(x.sat_c);
00995       x.set_sat_g_up_to_date();
00996     }
00997     // ... and sort it together with constraints.
00998     x.con_sys.sort_and_remove_with_sat(x.sat_g);
00999   }
01000   // Obtaining sat_c from sat_g.
01001   x.sat_c.transpose_assign(x.sat_g);
01002   x.set_sat_c_up_to_date();
01003   // Constraints are sorted now.
01004   x.con_sys.set_sorted(true);
01005 
01006   PPL_ASSERT(con_sys.check_sorted());
01007 }
01008 
01009 void
01010 PPL::Polyhedron::obtain_sorted_generators_with_sat_g() const {
01011   PPL_ASSERT(generators_are_up_to_date());
01012   // `gen_sys' will be sorted up to `index_first_pending'.
01013   Polyhedron& x = const_cast<Polyhedron&>(*this);
01014   // At least one of the saturation matrices must be up-to-date.
01015   if (!x.sat_c_is_up_to_date() && !x.sat_g_is_up_to_date())
01016     x.update_sat_g();
01017 
01018   if (x.gen_sys.is_sorted()) {
01019     if (x.sat_g_is_up_to_date())
01020       // If generators are already sorted and sat_g is up to
01021       // date there is nothing to do.
01022       return;
01023   }
01024   else {
01025     if (!x.sat_c_is_up_to_date()) {
01026       // If generators are not sorted and sat_c is not up-to-date
01027       // we obtain sat_c from sat_g (that has to be up-to-date)...
01028       x.sat_c.transpose_assign(x.sat_g);
01029       x.set_sat_c_up_to_date();
01030     }
01031     // ... and sort it together with generators.
01032     x.gen_sys.sort_and_remove_with_sat(x.sat_c);
01033   }
01034   // Obtaining sat_g from sat_c.
01035   x.sat_g.transpose_assign(sat_c);
01036   x.set_sat_g_up_to_date();
01037   // Generators are sorted now.
01038   x.gen_sys.set_sorted(true);
01039 
01040   PPL_ASSERT(gen_sys.check_sorted());
01041 }
01042 
01043 bool
01044 PPL::Polyhedron::minimize() const {
01045   // 0-dim space or empty polyhedra are already minimized.
01046   if (marked_empty())
01047     return false;
01048   if (space_dim == 0)
01049     return true;
01050 
01051   // If the polyhedron has something pending, process it.
01052   if (has_something_pending()) {
01053     const bool not_empty = process_pending();
01054     PPL_ASSERT_HEAVY(OK());
01055     return not_empty;
01056   }
01057 
01058   // Here there are no pending constraints or generators.
01059   // Is the polyhedron already minimized?
01060   if (constraints_are_minimized() && generators_are_minimized())
01061     return true;
01062 
01063   // If constraints or generators are up-to-date, invoking
01064   // update_generators() or update_constraints(), respectively,
01065   // minimizes both constraints and generators.
01066   // If both are up-to-date it does not matter whether we use
01067   // update_generators() or update_constraints():
01068   // both minimize constraints and generators.
01069   if (constraints_are_up_to_date()) {
01070     // We may discover here that `*this' is empty.
01071     const bool ret = update_generators();
01072     PPL_ASSERT_HEAVY(OK());
01073     return ret;
01074   }
01075   else {
01076     PPL_ASSERT(generators_are_up_to_date());
01077     update_constraints();
01078     PPL_ASSERT_HEAVY(OK());
01079     return true;
01080   }
01081 }
01082 
01083 bool
01084 PPL::Polyhedron::strongly_minimize_constraints() const {
01085   PPL_ASSERT(!is_necessarily_closed());
01086 
01087   // From the user perspective, the polyhedron will not change.
01088   Polyhedron& x = const_cast<Polyhedron&>(*this);
01089 
01090   // We need `con_sys' (weakly) minimized and `gen_sys' up-to-date.
01091   // `minimize()' will process any pending constraints or generators.
01092   if (!minimize())
01093     return false;
01094 
01095   // If the polyhedron `*this' is zero-dimensional
01096   // at this point it must be a universe polyhedron.
01097   if (x.space_dim == 0)
01098     return true;
01099 
01100   // We also need `sat_g' up-to-date.
01101   if (!sat_g_is_up_to_date()) {
01102     PPL_ASSERT(sat_c_is_up_to_date());
01103     x.sat_g.transpose_assign(sat_c);
01104   }
01105 
01106   // These Bit_Row's will be later used as masks in order to
01107   // check saturation conditions restricted to particular subsets of
01108   // the generator system.
01109   Bit_Row sat_all_but_rays;
01110   Bit_Row sat_all_but_points;
01111   Bit_Row sat_all_but_closure_points;
01112 
01113   const dimension_type gs_rows = gen_sys.num_rows();
01114   const dimension_type n_lines = gen_sys.num_lines();
01115   for (dimension_type i = gs_rows; i-- > n_lines; )
01116     switch (gen_sys[i].type()) {
01117     case Generator::RAY:
01118       sat_all_but_rays.set(i);
01119       break;
01120     case Generator::POINT:
01121       sat_all_but_points.set(i);
01122       break;
01123     case Generator::CLOSURE_POINT:
01124       sat_all_but_closure_points.set(i);
01125       break;
01126     case Generator::LINE:
01127       // Found a line with index i >= n_lines !
01128       PPL_UNREACHABLE;
01129       break;
01130     }
01131   Bit_Row sat_lines_and_rays(sat_all_but_points, sat_all_but_closure_points);
01132   Bit_Row sat_lines_and_closure_points(sat_all_but_rays, sat_all_but_points);
01133   Bit_Row sat_lines(sat_lines_and_rays, sat_lines_and_closure_points);
01134 
01135   // These flags are maintained to later decide if we have to add the
01136   // eps_leq_one constraint and whether or not the constraint system
01137   // was changed.
01138   bool changed = false;
01139   bool found_eps_leq_one = false;
01140 
01141   // For all the strict inequalities in `con_sys', check for
01142   // eps-redundancy and eventually move them to the bottom part of the
01143   // system.
01144   Constraint_System& cs = x.con_sys;
01145   Bit_Matrix& sat = x.sat_g;
01146   const dimension_type old_cs_rows = cs.num_rows();
01147   dimension_type cs_rows = old_cs_rows;
01148   const dimension_type eps_index = cs.num_columns() - 1;
01149   for (dimension_type i = 0; i < cs_rows; )
01150     if (cs[i].is_strict_inequality()) {
01151       // First, check if it is saturated by no closure points
01152       Bit_Row sat_ci;
01153       sat_ci.union_assign(sat[i], sat_lines_and_closure_points);
01154       if (sat_ci == sat_lines) {
01155         // It is saturated by no closure points.
01156         if (!found_eps_leq_one) {
01157           // Check if it is the eps_leq_one constraint.
01158           const Constraint& c = cs[i];
01159           bool all_zeroes = true;
01160           for (dimension_type k = eps_index; k-- > 1; )
01161             if (c[k] != 0) {
01162               all_zeroes = false;
01163               break;
01164             }
01165           if (all_zeroes && (c[0] + c[eps_index] == 0)) {
01166             // We found the eps_leq_one constraint.
01167             found_eps_leq_one = true;
01168             // Consider next constraint.
01169             ++i;
01170             continue;
01171           }
01172         }
01173         // Here `cs[i]' is not the eps_leq_one constraint,
01174         // so it is eps-redundant.
01175         // Move it to the bottom of the constraint system,
01176         // while keeping `sat_g' consistent.
01177         --cs_rows;
01178         using std::swap;
01179         swap(cs[i], cs[cs_rows]);
01180         swap(sat[i], sat[cs_rows]);
01181         // The constraint system is changed.
01182         changed = true;
01183         // Continue by considering next constraint,
01184         // which is already in place due to the swap.
01185         continue;
01186       }
01187       // Now we check if there exists another strict inequality
01188       // constraint having a superset of its saturators,
01189       // when disregarding points.
01190       sat_ci.union_assign(sat[i], sat_all_but_points);
01191       bool eps_redundant = false;
01192       for (dimension_type j = 0; j < cs_rows; ++j)
01193         if (i != j && cs[j].is_strict_inequality()
01194             && subset_or_equal(sat[j], sat_ci)) {
01195           // Constraint `cs[i]' is eps-redundant:
01196           // move it to the bottom of the constraint system,
01197           // while keeping `sat_g' consistent.
01198           --cs_rows;
01199           using std::swap;
01200           swap(cs[i], cs[cs_rows]);
01201           swap(sat[i], sat[cs_rows]);
01202           eps_redundant = true;
01203           // The constraint system is changed.
01204           changed = true;
01205           break;
01206         }
01207       // Continue with next constraint, which is already in place
01208       // due to the swap if we have found an eps-redundant constraint.
01209       if (!eps_redundant)
01210         ++i;
01211     }
01212     else
01213       // `cs[i]' is not a strict inequality: consider next constraint.
01214       ++i;
01215 
01216   if (changed) {
01217     // If the constraint system has been changed, we have to erase
01218     // the epsilon-redundant constraints.
01219     PPL_ASSERT(cs_rows < cs.num_rows());
01220     cs.remove_trailing_rows(old_cs_rows - cs_rows);
01221     // The remaining constraints are not pending.
01222     cs.unset_pending_rows();
01223     // The constraint system is no longer sorted.
01224     cs.set_sorted(false);
01225     // The generator system is no longer up-to-date.
01226     x.clear_generators_up_to_date();
01227 
01228     // If we haven't found an upper bound for the epsilon dimension,
01229     // then we have to check whether such an upper bound is implied
01230     // by the remaining constraints (exploiting the simplex algorithm).
01231     if (!found_eps_leq_one) {
01232       MIP_Problem lp;
01233       // KLUDGE: temporarily mark the constraint system as if it was
01234       // necessarily closed, so that we can interpret the epsilon
01235       // dimension as a standard dimension. Be careful to reset the
01236       // topology of `cs' even on exceptional execution path.
01237       cs.set_necessarily_closed();
01238       try {
01239         lp.add_space_dimensions_and_embed(cs.space_dimension());
01240         lp.add_constraints(cs);
01241         cs.set_not_necessarily_closed();
01242       }
01243       catch (...) {
01244         cs.set_not_necessarily_closed();
01245         throw;
01246       }
01247       // The objective function is `epsilon'.
01248       lp.set_objective_function(Variable(x.space_dim));
01249       lp.set_optimization_mode(MAXIMIZATION);
01250       MIP_Problem_Status status = lp.solve();
01251       PPL_ASSERT(status != UNFEASIBLE_MIP_PROBLEM);
01252       // If the epsilon dimension is actually unbounded,
01253       // then add the eps_leq_one constraint.
01254       if (status == UNBOUNDED_MIP_PROBLEM)
01255         cs.insert(Constraint::epsilon_leq_one());
01256     }
01257   }
01258 
01259   PPL_ASSERT_HEAVY(OK());
01260   return true;
01261 }
01262 
01263 bool
01264 PPL::Polyhedron::strongly_minimize_generators() const {
01265   PPL_ASSERT(!is_necessarily_closed());
01266 
01267   // From the user perspective, the polyhedron will not change.
01268   Polyhedron& x = const_cast<Polyhedron&>(*this);
01269 
01270   // We need `gen_sys' (weakly) minimized and `con_sys' up-to-date.
01271   // `minimize()' will process any pending constraints or generators.
01272   if (!minimize())
01273     return false;
01274 
01275   // If the polyhedron `*this' is zero-dimensional
01276   // at this point it must be a universe polyhedron.
01277   if (x.space_dim == 0)
01278     return true;
01279 
01280   // We also need `sat_c' up-to-date.
01281   if (!sat_c_is_up_to_date()) {
01282     PPL_ASSERT(sat_g_is_up_to_date());
01283     x.sat_c.transpose_assign(sat_g);
01284   }
01285 
01286   // This Bit_Row will have all and only the indexes
01287   // of strict inequalities set to 1.
01288   Bit_Row sat_all_but_strict_ineq;
01289   const dimension_type cs_rows = con_sys.num_rows();
01290   const dimension_type n_equals = con_sys.num_equalities();
01291   for (dimension_type i = cs_rows; i-- > n_equals; )
01292     if (con_sys[i].is_strict_inequality())
01293       sat_all_but_strict_ineq.set(i);
01294 
01295   // Will record whether or not we changed the generator system.
01296   bool changed = false;
01297 
01298   // For all points in the generator system, check for eps-redundancy
01299   // and eventually move them to the bottom part of the system.
01300   Generator_System& gs = const_cast<Generator_System&>(gen_sys);
01301   Bit_Matrix& sat = const_cast<Bit_Matrix&>(sat_c);
01302   const dimension_type old_gs_rows = gs.num_rows();
01303   dimension_type gs_rows = old_gs_rows;
01304   const dimension_type n_lines = gs.num_lines();
01305   const dimension_type eps_index = gs.num_columns() - 1;
01306   for (dimension_type i = n_lines; i < gs_rows; )
01307     if (gs[i].is_point()) {
01308       // Compute the Bit_Row corresponding to the candidate point
01309       // when strict inequality constraints are ignored.
01310       Bit_Row sat_gs_i(sat[i], sat_all_but_strict_ineq);
01311       // Check if the candidate point is actually eps-redundant:
01312       // namely, if there exists another point that saturates
01313       // all the non-strict inequalities saturated by the candidate.
01314       bool eps_redundant = false;
01315       for (dimension_type j = n_lines; j < gs_rows; ++j)
01316         if (i != j && gs[j].is_point() && subset_or_equal(sat[j], sat_gs_i)) {
01317           // Point `gs[i]' is eps-redundant:
01318           // move it to the bottom of the generator system,
01319           // while keeping `sat_c' consistent.
01320           --gs_rows;
01321           using std::swap;
01322           swap(gs[i], gs[gs_rows]);
01323           swap(sat[i], sat[gs_rows]);
01324           eps_redundant = true;
01325           changed = true;
01326           break;
01327         }
01328       if (!eps_redundant) {
01329         // Let all point encodings have epsilon coordinate 1.
01330         Generator& gs_i = gs[i];
01331         if (gs_i[eps_index] != gs_i[0]) {
01332           gs_i[eps_index] = gs_i[0];
01333           // Enforce normalization.
01334           gs_i.normalize();
01335           changed = true;
01336         }
01337         // Consider next generator.
01338         ++i;
01339       }
01340     }
01341     else
01342       // Consider next generator.
01343       ++i;
01344 
01345   // If needed, erase the eps-redundant generators (also updating
01346   // `index_first_pending').
01347   if (gs_rows < old_gs_rows) {
01348     gs.remove_trailing_rows(old_gs_rows - gs_rows);
01349     gs.unset_pending_rows();
01350   }
01351 
01352   if (changed) {
01353     // The generator system is no longer sorted.
01354     x.gen_sys.set_sorted(false);
01355     // The constraint system is no longer up-to-date.
01356     x.clear_constraints_up_to_date();
01357   }
01358 
01359   PPL_ASSERT_HEAVY(OK());
01360   return true;
01361 }
01362 
01363 void
01364 PPL::Polyhedron::refine_no_check(const Constraint& c) {
01365   PPL_ASSERT(!marked_empty());
01366   PPL_ASSERT(space_dim >= c.space_dimension());
01367 
01368   // Dealing with a zero-dimensional space polyhedron first.
01369   if (space_dim == 0) {
01370     if (c.is_inconsistent())
01371       set_empty();
01372     return;
01373   }
01374 
01375   // The constraints (possibly with pending rows) are required.
01376   if (has_pending_generators())
01377     process_pending_generators();
01378   else if (!constraints_are_up_to_date())
01379     update_constraints();
01380 
01381   const bool adding_pending = can_have_something_pending();
01382 
01383   if (c.is_necessarily_closed() || !is_necessarily_closed())
01384     // Since `con_sys' is not empty, the topology and space dimension
01385     // of the inserted constraint are automatically adjusted.
01386     if (adding_pending)
01387       con_sys.insert_pending(c);
01388     else
01389       con_sys.insert(c);
01390   else {
01391     // Here we know that the system of constraints has at least a row.
01392     // However, by barely invoking `con_sys.insert(c)' we would
01393     // cause a change in the topology of `con_sys', which is wrong.
01394     // Thus, we insert a "topology corrected" copy of `c'.
01395     Linear_Expression nc_expr = Linear_Expression(c);
01396     if (c.is_equality())
01397       if (adding_pending)
01398         con_sys.insert_pending(nc_expr == 0);
01399       else
01400         con_sys.insert(nc_expr == 0);
01401     else
01402       if (adding_pending)
01403         con_sys.insert_pending(nc_expr >= 0);
01404       else
01405         con_sys.insert(nc_expr >= 0);
01406   }
01407 
01408   if (adding_pending)
01409     set_constraints_pending();
01410   else {
01411     // Constraints are not minimized and generators are not up-to-date.
01412     clear_constraints_minimized();
01413     clear_generators_up_to_date();
01414   }
01415 
01416   // Note: the constraint system may have become unsatisfiable, thus
01417   // we do not check for satisfiability.
01418   PPL_ASSERT_HEAVY(OK());
01419 }
01420 
01421 bool
01422 PPL::Polyhedron::BHZ09_poly_hull_assign_if_exact(const Polyhedron& y) {
01423   Polyhedron& x = *this;
01424 
01425   // Private method: the caller must ensure the following.
01426   PPL_ASSERT(x.topology() == y.topology());
01427   PPL_ASSERT(x.space_dim == y.space_dim);
01428 
01429   // The zero-dim case is trivial.
01430   if (x.space_dim == 0) {
01431     x.upper_bound_assign(y);
01432     return true;
01433   }
01434 
01435   // If `x' or `y' are (known to be) empty, the upper bound is exact.
01436   if (x.marked_empty()) {
01437     x = y;
01438     return true;
01439   }
01440   else if (y.is_empty())
01441     return true;
01442   else if (x.is_empty()) {
01443     x = y;
01444     return true;
01445   }
01446 
01447   if (x.is_necessarily_closed())
01448     return x.BHZ09_C_poly_hull_assign_if_exact(y);
01449   else
01450     return x.BHZ09_NNC_poly_hull_assign_if_exact(y);
01451 }
01452 
01453 bool
01454 PPL::Polyhedron::BHZ09_C_poly_hull_assign_if_exact(const Polyhedron& y) {
01455   Polyhedron& x = *this;
01456   // Private method: the caller must ensure the following.
01457   PPL_ASSERT(x.is_necessarily_closed() && y.is_necessarily_closed());
01458   PPL_ASSERT(x.space_dim > 0 && x.space_dim == y.space_dim);
01459   PPL_ASSERT(!x.is_empty() && !y.is_empty());
01460 
01461   // Minimization is not really required, but it is probably the best
01462   // way of getting constraints, generators and saturation matrices
01463   // up-to-date.  Minimization it also removes redundant
01464   // constraints/generators.
01465   (void) x.minimize();
01466   (void) y.minimize();
01467 
01468   // Handle a special case: for topologically closed polyhedra P and Q,
01469   // if the affine dimension of P is greater than that of Q, then
01470   // their upper bound is exact if and only if P includes Q.
01471   const dimension_type x_affine_dim = x.affine_dimension();
01472   const dimension_type y_affine_dim = y.affine_dimension();
01473   if (x_affine_dim > y_affine_dim)
01474     return y.is_included_in(x);
01475   else if (x_affine_dim < y_affine_dim) {
01476     if (x.is_included_in(y)) {
01477       x = y;
01478       return true;
01479     }
01480     else
01481       return false;
01482   }
01483 
01484   const Constraint_System& x_cs = x.con_sys;
01485   const Generator_System& x_gs = x.gen_sys;
01486   const Generator_System& y_gs = y.gen_sys;
01487   const dimension_type x_gs_num_rows = x_gs.num_rows();
01488   const dimension_type y_gs_num_rows = y_gs.num_rows();
01489 
01490   // Step 1: generators of `x' that are redundant in `y', and vice versa.
01491   Bit_Row x_gs_red_in_y;
01492   dimension_type num_x_gs_red_in_y = 0;
01493   for (dimension_type i = x_gs_num_rows; i-- > 0; )
01494     if (y.relation_with(x_gs[i]).implies(Poly_Gen_Relation::subsumes())) {
01495       x_gs_red_in_y.set(i);
01496       ++num_x_gs_red_in_y;
01497     }
01498   Bit_Row y_gs_red_in_x;
01499   dimension_type num_y_gs_red_in_x = 0;
01500   for (dimension_type i = y_gs_num_rows; i-- > 0; )
01501     if (x.relation_with(y_gs[i]).implies(Poly_Gen_Relation::subsumes())) {
01502       y_gs_red_in_x.set(i);
01503       ++num_y_gs_red_in_x;
01504     }
01505 
01506   // Step 2: filter away special cases.
01507 
01508   // Step 2.1: inclusion tests.
01509   if (num_y_gs_red_in_x == y_gs_num_rows)
01510     // `y' is included into `x': upper bound `x' is exact.
01511     return true;
01512   if (num_x_gs_red_in_y == x_gs_num_rows) {
01513     // `x' is included into `y': upper bound `y' is exact.
01514     x = y;
01515     return true;
01516   }
01517 
01518   // Step 2.2: if no generator of `x' is redundant for `y', then
01519   // (as by 2.1 there exists a constraint of `x' non-redundant for `y')
01520   // the upper bound is not exact; the same if exchanging `x' and `y'.
01521   if (num_x_gs_red_in_y == 0 || num_y_gs_red_in_x == 0)
01522     return false;
01523 
01524   // Step 3: see if `x' has a non-redundant constraint `c_x' that is not
01525   // satisfied by `y' and a non-redundant generator in `y' (see Step 1)
01526   // saturating `c_x'. If so, the upper bound is not exact.
01527 
01528   // Make sure the saturation matrix for `x' is up to date.
01529   // Any sat matrix would do: we choose `sat_g' because it matches
01530   // the two nested loops (constraints on rows and generators on columns).
01531   if (!x.sat_g_is_up_to_date())
01532     x.update_sat_g();
01533   const Bit_Matrix& x_sat = x.sat_g;
01534 
01535   Bit_Row all_ones;
01536   all_ones.set_until(x_gs_num_rows);
01537   Bit_Row row_union;
01538   for (dimension_type i = x_cs.num_rows(); i-- > 0; ) {
01539     const bool included
01540       = y.relation_with(x_cs[i]).implies(Poly_Con_Relation::is_included());
01541     if (!included) {
01542       row_union.union_assign(x_gs_red_in_y, x_sat[i]);
01543       if (row_union != all_ones)
01544         return false;
01545     }
01546   }
01547 
01548   // Here we know that the upper bound is exact: compute it.
01549   for (dimension_type j = y_gs_num_rows; j-- > 0; )
01550     if (!y_gs_red_in_x[j])
01551       add_generator(y_gs[j]);
01552 
01553   PPL_ASSERT_HEAVY(OK());
01554   return true;
01555 }
01556 
01557 bool
01558 PPL::Polyhedron::BHZ09_NNC_poly_hull_assign_if_exact(const Polyhedron& y) {
01559   const Polyhedron& x = *this;
01560   // Private method: the caller must ensure the following.
01561   PPL_ASSERT(!x.is_necessarily_closed() && !y.is_necessarily_closed());
01562   PPL_ASSERT(x.space_dim > 0 && x.space_dim == y.space_dim);
01563   PPL_ASSERT(!x.is_empty() && !y.is_empty());
01564 
01565   // Minimization is not really required, but it is probably the best
01566   // way of getting constraints, generators and saturation matrices
01567   // up-to-date.  Minimization also removes redundant
01568   // constraints/generators.
01569   (void) x.minimize();
01570   (void) y.minimize();
01571 
01572   const Generator_System& x_gs = x.gen_sys;
01573   const Generator_System& y_gs = y.gen_sys;
01574   const dimension_type x_gs_num_rows = x_gs.num_rows();
01575   const dimension_type y_gs_num_rows = y_gs.num_rows();
01576 
01577   // Compute generators of `x' that are non-redundant in `y' ...
01578   Bit_Row x_gs_non_redundant_in_y;
01579   Bit_Row x_points_non_redundant_in_y;
01580   Bit_Row x_closure_points;
01581   dimension_type num_x_gs_non_redundant_in_y = 0;
01582   for (dimension_type i = x_gs_num_rows; i-- > 0; ) {
01583     const Generator& x_gs_i = x_gs[i];
01584     if (x_gs_i.is_closure_point())
01585       x_closure_points.set(i);
01586     if (y.relation_with(x_gs[i]).implies(Poly_Gen_Relation::subsumes()))
01587       continue;
01588     x_gs_non_redundant_in_y.set(i);
01589     ++num_x_gs_non_redundant_in_y;
01590     if (x_gs_i.is_point())
01591       x_points_non_redundant_in_y.set(i);
01592   }
01593 
01594   // If `x' is included into `y', the upper bound `y' is exact.
01595   if (num_x_gs_non_redundant_in_y == 0) {
01596     *this = y;
01597     return true;
01598   }
01599 
01600   // ... and vice versa, generators of `y' that are non-redundant in `x'.
01601   Bit_Row y_gs_non_redundant_in_x;
01602   Bit_Row y_points_non_redundant_in_x;
01603   Bit_Row y_closure_points;
01604   dimension_type num_y_gs_non_redundant_in_x = 0;
01605   for (dimension_type i = y_gs_num_rows; i-- > 0; ) {
01606     const Generator& y_gs_i = y_gs[i];
01607     if (y_gs_i.is_closure_point())
01608       y_closure_points.set(i);
01609     if (x.relation_with(y_gs_i).implies(Poly_Gen_Relation::subsumes()))
01610       continue;
01611     y_gs_non_redundant_in_x.set(i);
01612     ++num_y_gs_non_redundant_in_x;
01613     if (y_gs_i.is_point())
01614       y_points_non_redundant_in_x.set(i);
01615   }
01616 
01617   // If `y' is included into `x', the upper bound `x' is exact.
01618   if (num_y_gs_non_redundant_in_x == 0)
01619     return true;
01620 
01621   Bit_Row x_non_points_non_redundant_in_y;
01622   x_non_points_non_redundant_in_y
01623     .difference_assign(x_gs_non_redundant_in_y,
01624                        x_points_non_redundant_in_y);
01625 
01626   const Constraint_System& x_cs = x.con_sys;
01627   const Constraint_System& y_cs = y.con_sys;
01628   const dimension_type x_cs_num_rows = x_cs.num_rows();
01629   const dimension_type y_cs_num_rows = y_cs.num_rows();
01630 
01631   // Filter away the points of `x_gs' that would be redundant
01632   // in the topological closure of `y'.
01633   Bit_Row x_points_non_redundant_in_y_closure;
01634   for (dimension_type i = x_points_non_redundant_in_y.first();
01635        i != C_Integer<unsigned long>::max;
01636        i = x_points_non_redundant_in_y.next(i)) {
01637     const Generator& x_p = x_gs[i];
01638     PPL_ASSERT(x_p.is_point());
01639     // NOTE: we cannot use Constraint_System::relation_with()
01640     // as we need to treat strict inequalities as if they were nonstrict.
01641     for (dimension_type j = y_cs_num_rows; j-- > 0; ) {
01642       const Constraint& y_c = y_cs[j];
01643       const int sp_sign = Scalar_Products::reduced_sign(y_c, x_p);
01644       if (sp_sign < 0 || (y_c.is_equality() && sp_sign > 0)) {
01645         x_points_non_redundant_in_y_closure.set(i);
01646         break;
01647       }
01648     }
01649   }
01650 
01651   // Make sure the saturation matrix for `x' is up to date.
01652   // Any sat matrix would do: we choose `sat_g' because it matches
01653   // the two nested loops (constraints on rows and generators on columns).
01654   if (!x.sat_g_is_up_to_date())
01655     x.update_sat_g();
01656   const Bit_Matrix& x_sat = x.sat_g;
01657 
01658   Bit_Row x_cs_condition_3;
01659   Bit_Row x_gs_condition_3;
01660   Bit_Row all_ones;
01661   all_ones.set_until(x_gs_num_rows);
01662   Bit_Row saturators;
01663   Bit_Row tmp_set;
01664   for (dimension_type i = x_cs_num_rows; i-- > 0; ) {
01665     const Constraint& x_c = x_cs[i];
01666     // Skip constraint if it is not violated by `y'.
01667     if (y.relation_with(x_c).implies(Poly_Con_Relation::is_included()))
01668       continue;
01669     saturators.difference_assign(all_ones, x_sat[i]);
01670     // Check condition 1.
01671     tmp_set.intersection_assign(x_non_points_non_redundant_in_y, saturators);
01672     if (!tmp_set.empty())
01673       return false;
01674     if (x_c.is_strict_inequality()) {
01675       // Postpone check for condition 3.
01676       x_cs_condition_3.set(i);
01677       tmp_set.intersection_assign(x_closure_points, saturators);
01678       x_gs_condition_3.union_assign(x_gs_condition_3, tmp_set);
01679     }
01680     else {
01681       // Check condition 2.
01682       tmp_set.intersection_assign(x_points_non_redundant_in_y_closure,
01683                                   saturators);
01684       if (!tmp_set.empty())
01685         return false;
01686     }
01687   }
01688 
01689   // Now exchange the roles of `x' and `y'
01690   // (the statement of the NNC theorem in BHZ09 is symmetric).
01691 
01692   Bit_Row y_non_points_non_redundant_in_x;
01693   y_non_points_non_redundant_in_x
01694     .difference_assign(y_gs_non_redundant_in_x,
01695                        y_points_non_redundant_in_x);
01696 
01697   // Filter away the points of `y_gs' that would be redundant
01698   // in the topological closure of `x'.
01699   Bit_Row y_points_non_redundant_in_x_closure;
01700   for (dimension_type i = y_points_non_redundant_in_x.first();
01701        i != C_Integer<unsigned long>::max;
01702        i = y_points_non_redundant_in_x.next(i)) {
01703     const Generator& y_p = y_gs[i];
01704     PPL_ASSERT(y_p.is_point());
01705     // NOTE: we cannot use Constraint_System::relation_with()
01706     // as we need to treat strict inequalities as if they were nonstrict.
01707     for (dimension_type j = x_cs_num_rows; j-- > 0; ) {
01708       const Constraint& x_c = x_cs[j];
01709       const int sp_sign = Scalar_Products::reduced_sign(x_c, y_p);
01710       if (sp_sign < 0 || (x_c.is_equality() && sp_sign > 0)) {
01711         y_points_non_redundant_in_x_closure.set(i);
01712         break;
01713       }
01714     }
01715   }
01716 
01717   // Make sure the saturation matrix `sat_g' for `y' is up to date.
01718   if (!y.sat_g_is_up_to_date())
01719     y.update_sat_g();
01720   const Bit_Matrix& y_sat = y.sat_g;
01721 
01722   Bit_Row y_cs_condition_3;
01723   Bit_Row y_gs_condition_3;
01724   all_ones.clear();
01725   all_ones.set_until(y_gs_num_rows);
01726   for (dimension_type i = y_cs_num_rows; i-- > 0; ) {
01727     const Constraint& y_c = y_cs[i];
01728     // Skip constraint if it is not violated by `x'.
01729     if (x.relation_with(y_c).implies(Poly_Con_Relation::is_included()))
01730       continue;
01731     saturators.difference_assign(all_ones, y_sat[i]);
01732     // Check condition 1.
01733     tmp_set.intersection_assign(y_non_points_non_redundant_in_x, saturators);
01734     if (!tmp_set.empty())
01735       return false;
01736     if (y_c.is_strict_inequality()) {
01737       // Postpone check for condition 3.
01738       y_cs_condition_3.set(i);
01739       tmp_set.intersection_assign(y_closure_points, saturators);
01740       y_gs_condition_3.union_assign(y_gs_condition_3, tmp_set);
01741     }
01742     else {
01743       // Check condition 2.
01744       tmp_set.intersection_assign(y_points_non_redundant_in_x_closure,
01745                                   saturators);
01746       if (!tmp_set.empty())
01747         return false;
01748     }
01749   }
01750 
01751   // Now considering condition 3.
01752 
01753   if (x_cs_condition_3.empty() && y_cs_condition_3.empty()) {
01754     // No test for condition 3 is needed.
01755     // The hull is exact: compute it.
01756     for (dimension_type j = y_gs_num_rows; j-- > 0; )
01757       if (y_gs_non_redundant_in_x[j])
01758         add_generator(y_gs[j]);
01759     return true;
01760   }
01761 
01762   // We have anyway to compute the upper bound and its constraints too.
01763   Polyhedron ub(x);
01764   for (dimension_type j = y_gs_num_rows; j-- > 0; )
01765     if (y_gs_non_redundant_in_x[j])
01766       ub.add_generator(y_gs[j]);
01767   (void) ub.minimize();
01768   PPL_ASSERT(!ub.is_empty());
01769 
01770   // NOTE: the following computation of x_gs_condition_3_not_in_y
01771   // (resp., y_gs_condition_3_not_in_x) is not required for correctness.
01772   // It is done so as to later apply a speculative test
01773   // (i.e., a non-conclusive but computationally lighter test).
01774 
01775   // Filter away from `x_gs_condition_3' those closure points
01776   // that, when considered as points, would belong to `y',
01777   // i.e., those that violate no strict constraint in `y_cs'.
01778   Bit_Row x_gs_condition_3_not_in_y;
01779   for (dimension_type i = y_cs_num_rows; i-- > 0; ) {
01780     const Constraint& y_c = y_cs[i];
01781     if (y_c.is_strict_inequality()) {
01782       for (dimension_type j = x_gs_condition_3.first();
01783            j != C_Integer<unsigned long>::max; j = x_gs_condition_3.next(j)) {
01784         const Generator& x_cp = x_gs[j];
01785         PPL_ASSERT(x_cp.is_closure_point());
01786         const int sp_sign = Scalar_Products::reduced_sign(y_c, x_cp);
01787         PPL_ASSERT(sp_sign >= 0);
01788         if (sp_sign == 0) {
01789           x_gs_condition_3.clear(j);
01790           x_gs_condition_3_not_in_y.set(j);
01791         }
01792       }
01793       if (x_gs_condition_3.empty())
01794         break;
01795     }
01796   }
01797   // Symmetrically, filter away from `y_gs_condition_3' those
01798   // closure points that, when considered as points, would belong to `x',
01799   // i.e., those that violate no strict constraint in `x_cs'.
01800   Bit_Row y_gs_condition_3_not_in_x;
01801   for (dimension_type i = x_cs_num_rows; i-- > 0; ) {
01802     if (x_cs[i].is_strict_inequality()) {
01803       const Constraint& x_c = x_cs[i];
01804       for (dimension_type j = y_gs_condition_3.first();
01805            j != C_Integer<unsigned long>::max; j = y_gs_condition_3.next(j)) {
01806         const Generator& y_cp = y_gs[j];
01807         PPL_ASSERT(y_cp.is_closure_point());
01808         const int sp_sign = Scalar_Products::reduced_sign(x_c, y_cp);
01809         PPL_ASSERT(sp_sign >= 0);
01810         if (sp_sign == 0) {
01811           y_gs_condition_3.clear(j);
01812           y_gs_condition_3_not_in_x.set(j);
01813         }
01814       }
01815       if (y_gs_condition_3.empty())
01816         break;
01817     }
01818   }
01819 
01820   // NOTE: here we apply the speculative test.
01821   // Check if there exists a closure point in `x_gs_condition_3_not_in_y'
01822   // or `y_gs_condition_3_not_in_x' that belongs (as point) to the hull.
01823   // If so, the hull is not exact.
01824   const Constraint_System& ub_cs = ub.constraints();
01825   for (dimension_type i = ub_cs.num_rows(); i-- > 0; ) {
01826     if (ub_cs[i].is_strict_inequality()) {
01827       const Constraint& ub_c = ub_cs[i];
01828       for (dimension_type j = x_gs_condition_3_not_in_y.first();
01829            j != C_Integer<unsigned long>::max;
01830            j = x_gs_condition_3_not_in_y.next(j)) {
01831         const Generator& x_cp = x_gs[j];
01832         PPL_ASSERT(x_cp.is_closure_point());
01833         const int sp_sign = Scalar_Products::reduced_sign(ub_c, x_cp);
01834         PPL_ASSERT(sp_sign >= 0);
01835         if (sp_sign == 0)
01836           x_gs_condition_3_not_in_y.clear(j);
01837       }
01838       for (dimension_type j = y_gs_condition_3_not_in_x.first();
01839            j != C_Integer<unsigned long>::max;
01840            j = y_gs_condition_3_not_in_x.next(j)) {
01841         const Generator& y_cp = y_gs[j];
01842         PPL_ASSERT(y_cp.is_closure_point());
01843         const int sp_sign = Scalar_Products::reduced_sign(ub_c, y_cp);
01844         PPL_ASSERT(sp_sign >= 0);
01845         if (sp_sign == 0)
01846           y_gs_condition_3_not_in_x.clear(j);
01847       }
01848     }
01849   }
01850 
01851   if (!(x_gs_condition_3_not_in_y.empty()
01852         && y_gs_condition_3_not_in_x.empty()))
01853     // There exist a closure point satisfying condition 3,
01854     // hence the hull is not exact.
01855     return false;
01856 
01857   // The speculative test was not successful:
01858   // apply the expensive (but conclusive) test for condition 3.
01859 
01860   // Consider strict inequalities in `x' violated by `y'.
01861   for (dimension_type i = x_cs_condition_3.first();
01862        i != C_Integer<unsigned long>::max; i = x_cs_condition_3.next(i)) {
01863     const Constraint& x_cs_i = x_cs[i];
01864     PPL_ASSERT(x_cs_i.is_strict_inequality());
01865     // Build the equality constraint induced by x_cs_i.
01866     Constraint eq_i(Linear_Expression(x_cs_i) == 0);
01867     PPL_ASSERT(!(ub.relation_with(eq_i)
01868                  .implies(Poly_Con_Relation::is_disjoint())));
01869     Polyhedron ub_inters_hyperplane(ub);
01870     ub_inters_hyperplane.add_constraint(eq_i);
01871     Polyhedron y_inters_hyperplane(y);
01872     y_inters_hyperplane.add_constraint(eq_i);
01873     if (!y_inters_hyperplane.contains(ub_inters_hyperplane))
01874       // The hull is not exact.
01875       return false;
01876   }
01877 
01878   // Consider strict inequalities in `y' violated by `x'.
01879   for (dimension_type i = y_cs_condition_3.first();
01880        i != C_Integer<unsigned long>::max; i = y_cs_condition_3.next(i)) {
01881     const Constraint& y_cs_i = y_cs[i];
01882     PPL_ASSERT(y_cs_i.is_strict_inequality());
01883     // Build the equality constraint induced by y_cs_i.
01884     Constraint eq_i(Linear_Expression(y_cs_i) == 0);
01885     PPL_ASSERT(!(ub.relation_with(eq_i)
01886                  .implies(Poly_Con_Relation::is_disjoint())));
01887     Polyhedron ub_inters_hyperplane(ub);
01888     ub_inters_hyperplane.add_constraint(eq_i);
01889     Polyhedron x_inters_hyperplane(x);
01890     x_inters_hyperplane.add_constraint(eq_i);
01891     if (!x_inters_hyperplane.contains(ub_inters_hyperplane))
01892       // The hull is not exact.
01893       return false;
01894   }
01895 
01896   // The hull is exact.
01897   m_swap(ub);
01898   return true;
01899 }
01900 
01901 bool
01902 PPL::Polyhedron::BFT00_poly_hull_assign_if_exact(const Polyhedron& y) {
01903   // Declare a const reference to *this (to avoid accidental modifications).
01904   const Polyhedron& x = *this;
01905   // Private method: the caller must ensure the following.
01906   PPL_ASSERT(x.is_necessarily_closed());
01907   PPL_ASSERT(x.topology() == y.topology());
01908   PPL_ASSERT(x.space_dim == y.space_dim);
01909 
01910   // The zero-dim case is trivial.
01911   if (x.space_dim == 0) {
01912     upper_bound_assign(y);
01913     return true;
01914   }
01915   // If `x' or `y' is (known to be) empty, the convex union is exact.
01916   if (x.marked_empty()) {
01917     *this = y;
01918     return true;
01919   }
01920   else if (y.is_empty())
01921     return true;
01922   else if (x.is_empty()) {
01923     *this = y;
01924     return true;
01925   }
01926 
01927   // Here both `x' and `y' are known to be non-empty.
01928 
01929   // Implementation based on Algorithm 8.1 (page 15) in [BemporadFT00TR],
01930   // generalized so as to also allow for unbounded polyhedra.
01931   // The extension to unbounded polyhedra is obtained by mimicking
01932   // what done in Algorithm 8.2 (page 19) with respect to
01933   // Algorithm 6.2 (page 13).
01934   // We also apply a couple of improvements (see steps 2.1, 3.1, 6.1, 7.1)
01935   // so as to quickly handle special cases and avoid the splitting
01936   // of equalities/lines into pairs of inequalities/rays.
01937 
01938   (void) x.minimize();
01939   (void) y.minimize();
01940   const Constraint_System& x_cs = x.con_sys;
01941   const Constraint_System& y_cs = y.con_sys;
01942   const Generator_System& x_gs = x.gen_sys;
01943   const Generator_System& y_gs = y.gen_sys;
01944   const dimension_type x_gs_num_rows = x_gs.num_rows();
01945   const dimension_type y_gs_num_rows = y_gs.num_rows();
01946 
01947   // Step 1: generators of `x' that are redundant in `y', and vice versa.
01948   std::vector<bool> x_gs_red_in_y(x_gs_num_rows, false);
01949   dimension_type num_x_gs_red_in_y = 0;
01950   for (dimension_type i = x_gs_num_rows; i-- > 0; )
01951     if (y.relation_with(x_gs[i]).implies(Poly_Gen_Relation::subsumes())) {
01952       x_gs_red_in_y[i] = true;
01953       ++num_x_gs_red_in_y;
01954     }
01955   std::vector<bool> y_gs_red_in_x(y_gs_num_rows, false);
01956   dimension_type num_y_gs_red_in_x = 0;
01957   for (dimension_type i = y_gs_num_rows; i-- > 0; )
01958     if (x.relation_with(y_gs[i]).implies(Poly_Gen_Relation::subsumes())) {
01959       y_gs_red_in_x[i] = true;
01960       ++num_y_gs_red_in_x;
01961     }
01962 
01963   // Step 2: if no redundant generator has been identified,
01964   // then the union is not convex. CHECKME: why?
01965   if (num_x_gs_red_in_y == 0 && num_y_gs_red_in_x == 0)
01966     return false;
01967 
01968   // Step 2.1: while at it, also perform quick inclusion tests.
01969   if (num_y_gs_red_in_x == y_gs_num_rows)
01970     // `y' is included into `x': union is convex.
01971     return true;
01972   if (num_x_gs_red_in_y == x_gs_num_rows) {
01973     // `x' is included into `y': union is convex.
01974     *this = y;
01975     return true;
01976   }
01977 
01978   // Here we know that `x' is not included in `y', and vice versa.
01979 
01980   // Step 3: constraints of `x' that are satisfied by `y', and vice versa.
01981   const dimension_type x_cs_num_rows = x_cs.num_rows();
01982   std::vector<bool> x_cs_red_in_y(x_cs_num_rows, false);
01983   for (dimension_type i = x_cs_num_rows; i-- > 0; ) {
01984     const Constraint& x_cs_i = x_cs[i];
01985     if (y.relation_with(x_cs_i).implies(Poly_Con_Relation::is_included()))
01986       x_cs_red_in_y[i] = true;
01987     else if (x_cs_i.is_equality())
01988       // Step 3.1: `x' has an equality not satisfied by `y':
01989       // union is not convex (recall that `y' does not contain `x').
01990       // NOTE: this would be false for NNC polyhedra.
01991       // Example: x = { A == 0 }, y = { 0 < A <= 1 }.
01992       return false;
01993   }
01994   const dimension_type y_cs_num_rows = y_cs.num_rows();
01995   std::vector<bool> y_cs_red_in_x(y_cs_num_rows, false);
01996   for (dimension_type i = y_cs_num_rows; i-- > 0; ) {
01997     const Constraint& y_cs_i = y_cs[i];
01998     if (x.relation_with(y_cs_i).implies(Poly_Con_Relation::is_included()))
01999       y_cs_red_in_x[i] = true;
02000     else if (y_cs_i.is_equality())
02001       // Step 3.1: `y' has an equality not satisfied by `x':
02002       // union is not convex (see explanation above).
02003       return false;
02004   }
02005 
02006   // Loop in steps 5-9: for each pair of non-redundant generators,
02007   // compute their "mid-point" and check if it is both in `x' and `y'.
02008 
02009   // Note: reasoning at the polyhedral cone level.
02010   // CHECKME, FIXME: Polyhedron is a (deprecated) friend of Generator.
02011   // Here below we systematically exploit such a friendship, so as to
02012   // freely reinterpret a Generator as a Linear_Row and vice versa.
02013   Linear_Row mid_row;
02014   const Generator& mid_g = static_cast<const Generator&>(mid_row);
02015 
02016   for (dimension_type i = x_gs_num_rows; i-- > 0; ) {
02017     if (x_gs_red_in_y[i])
02018       continue;
02019     const Linear_Row& x_row = static_cast<const Linear_Row&>(x_gs[i]);
02020     const dimension_type row_sz = x_row.size();
02021     const bool x_row_is_line = x_row.is_line_or_equality();
02022     for (dimension_type j = y_gs_num_rows; j-- > 0; ) {
02023       if (y_gs_red_in_x[j])
02024         continue;
02025       const Linear_Row& y_row = static_cast<const Linear_Row&>(y_gs[j]);
02026       const bool y_row_is_line = y_row.is_line_or_equality();
02027 
02028       // Step 6: compute mid_row = x_row + y_row.
02029       // NOTE: no need to actually compute the "mid-point",
02030       // since any strictly positive combination would do.
02031       mid_row = x_row;
02032       for (dimension_type k = row_sz; k-- > 0; )
02033         mid_row[k] += y_row[k];
02034       // A zero ray is not a well formed generator.
02035       const bool illegal_ray
02036         = (mid_row[0] == 0 && mid_row.all_homogeneous_terms_are_zero());
02037       // A zero ray cannot be generated from a line: this holds
02038       // because x_row (resp., y_row) is not subsumed by y (resp., x).
02039       PPL_ASSERT(!(illegal_ray && (x_row_is_line || y_row_is_line)));
02040       if (illegal_ray)
02041         continue;
02042       // Normalize mid_row (strongly, if needed).
02043       mid_row.normalize();
02044       if (x_row_is_line) {
02045         if (y_row_is_line)
02046           // mid_row is a line too: sign normalization is needed.
02047           mid_row.sign_normalize();
02048         else
02049           // mid_row is a ray/point.
02050           mid_row.set_is_ray_or_point_or_inequality();
02051       }
02052       PPL_ASSERT(mid_g.OK());
02053 
02054       // Step 7: check if mid_g is in the union of x and y.
02055       if (x.relation_with(mid_g) == Poly_Gen_Relation::nothing()
02056           && y.relation_with(mid_g) == Poly_Gen_Relation::nothing())
02057         return false;
02058 
02059       // If either x_row or y_row is a line, we should use its
02060       // negation to produce another generator to be tested too.
02061       // NOTE: exclusive-or is meant.
02062       if (!x_row_is_line && y_row_is_line) {
02063         // Step 6.1: (re-)compute mid_row = x_row - y_row.
02064         mid_row = x_row;
02065         for (dimension_type k = row_sz; k-- > 0; )
02066           mid_row[k] -= y_row[k];
02067         mid_row.normalize();
02068         // Step 7.1: check if mid_g is in the union of x and y.
02069         if (x.relation_with(mid_g) == Poly_Gen_Relation::nothing()
02070             && y.relation_with(mid_g) == Poly_Gen_Relation::nothing())
02071           return false;
02072       }
02073       else if (x_row_is_line && !y_row_is_line) {
02074         // Step 6.1: (re-)compute mid_row = - x_row + y_row.
02075         mid_row = y_row;
02076         for (dimension_type k = row_sz; k-- > 0; )
02077           mid_row[k] -= x_row[k];
02078         mid_row.normalize();
02079         // Step 7.1: check if mid_g is in the union of x and y.
02080         if (x.relation_with(mid_g) == Poly_Gen_Relation::nothing()
02081             && y.relation_with(mid_g) == Poly_Gen_Relation::nothing())
02082           return false;
02083       }
02084     }
02085   }
02086 
02087   // Here we know that the union of x and y is convex.
02088   // TODO: exploit knowledge on the cardinality of non-redundant
02089   // constraints/generators to improve the convex-hull computation.
02090   // Using generators allows for exploiting incrementality.
02091   for (dimension_type j = 0; j < y_gs_num_rows; ++j) {
02092     if (!y_gs_red_in_x[j])
02093       add_generator(y_gs[j]);
02094   }
02095   PPL_ASSERT_HEAVY(OK());
02096   return true;
02097 }
02098 
02099 void
02100 PPL::Polyhedron::drop_some_non_integer_points(const Variables_Set* vars_p,
02101                                               Complexity_Class complexity) {
02102   // There is nothing to do for an empty set of variables.
02103   if (vars_p != 0 && vars_p->empty())
02104     return;
02105 
02106   // Any empty polyhedron does not contain integer points.
02107   if (marked_empty())
02108     return;
02109 
02110   // A zero-dimensional, universe polyhedron has, by convention, an
02111   // integer point.
02112   if (space_dim == 0) {
02113     set_empty();
02114     return;
02115   }
02116 
02117   // The constraints (possibly with pending rows) are required.
02118   if (has_pending_generators()) {
02119     // Processing of pending generators is exponential in the worst case.
02120     if (complexity != ANY_COMPLEXITY)
02121       return;
02122     else
02123       process_pending_generators();
02124   }
02125   if (!constraints_are_up_to_date()) {
02126     // Constraints update is exponential in the worst case.
02127     if (complexity != ANY_COMPLEXITY)
02128       return;
02129     else
02130       update_constraints();
02131   }
02132   // For NNC polyhedra we need to process any pending constraints.
02133   if (!is_necessarily_closed() && has_pending_constraints()) {
02134     if (complexity != ANY_COMPLEXITY)
02135       return;
02136     else if (!process_pending_constraints())
02137       // We just discovered the polyhedron is empty.
02138       return;
02139   }
02140 
02141   PPL_ASSERT(!has_pending_generators() && constraints_are_up_to_date());
02142   PPL_ASSERT(is_necessarily_closed() || !has_pending_constraints());
02143 
02144   bool changed = false;
02145   const dimension_type eps_index = space_dim + 1;
02146   PPL_DIRTY_TEMP_COEFFICIENT(gcd);
02147 
02148   for (dimension_type j = con_sys.num_rows(); j-- > 0; ) {
02149     Constraint& c = con_sys[j];
02150     if (c.is_tautological())
02151       goto next_constraint;
02152 
02153     if (vars_p != 0) {
02154       for (dimension_type i = space_dim; i-- > 0; )
02155         if (c[i+1] != 0 && vars_p->find(i) == vars_p->end())
02156           goto next_constraint;
02157     }
02158 
02159     if (!is_necessarily_closed()) {
02160       // Transform all strict inequalities into non-strict ones,
02161       // with the inhomogeneous term incremented by 1.
02162       if (c[eps_index] < 0) {
02163         c[eps_index] = 0;
02164         --c[0];
02165         // Enforce normalization.
02166         // FIXME: is this really necessary?
02167         c.normalize();
02168         changed = true;
02169       }
02170     }
02171 
02172     {
02173       // Compute the GCD of all the homogeneous terms.
02174       dimension_type i = space_dim+1;
02175       while (i > 1) {
02176         const Coefficient& c_i = c[--i];
02177         if (const int c_i_sign = sgn(c_i)) {
02178           gcd = c_i;
02179           if (c_i_sign < 0)
02180             neg_assign(gcd);
02181           goto compute_gcd;
02182         }
02183       }
02184       // We reach this point only if all the coefficients were zero.
02185       goto next_constraint;
02186 
02187     compute_gcd:
02188       if (gcd == 1)
02189         goto next_constraint;
02190       while (i > 1) {
02191         const Coefficient& c_i = c[--i];
02192         if (c_i != 0) {
02193           // See the comment in Dense_Row::normalize().
02194           gcd_assign(gcd, c_i, gcd);
02195           if (gcd == 1)
02196             goto next_constraint;
02197         }
02198       }
02199       PPL_ASSERT(gcd != 1);
02200       PPL_ASSERT(c[0] % gcd != 0);
02201 
02202       // If we have an equality, the polyhedron becomes empty.
02203       if (c.is_equality()) {
02204         set_empty();
02205         return;
02206       }
02207 
02208       // Divide the inhomogeneous coefficients by the GCD.
02209       for (dimension_type k = space_dim+1; --k > 0; ) {
02210         Coefficient& c_k = c[k];
02211         exact_div_assign(c_k, c_k, gcd);
02212       }
02213       Coefficient& c_0 = c[0];
02214       const int c_0_sign = sgn(c_0);
02215       c_0 /= gcd;
02216       if (c_0_sign < 0)
02217         --c_0;
02218       changed = true;
02219     }
02220 
02221   next_constraint:
02222     ;
02223   }
02224 
02225   if (changed) {
02226     if (!is_necessarily_closed()) {
02227       con_sys.insert(Constraint::epsilon_leq_one());
02228       // FIXME: make sure that the following line really can stay here
02229       // and should not be moved below the brace.
02230       con_sys.set_sorted(false);
02231     }
02232 
02233     // After changing the system of constraints, the generators
02234     // are no longer up-to-date and the constraints are no longer
02235     // minimized.
02236     clear_generators_up_to_date();
02237     clear_constraints_minimized();
02238   }
02239   PPL_ASSERT_HEAVY(OK());
02240 }
02241 
02242 void
02243 PPL::Polyhedron::throw_invalid_argument(const char* method,
02244                                         const char* reason) const {
02245   std::ostringstream s;
02246   s << "PPL::";
02247   if (is_necessarily_closed())
02248     s << "C_";
02249   else
02250     s << "NNC_";
02251   s << "Polyhedron::" << method << ":" << std::endl
02252     << reason << ".";
02253   throw std::invalid_argument(s.str());
02254 }
02255 
02256 void
02257 PPL::Polyhedron::throw_topology_incompatible(const char* method,
02258                                              const char* ph_name,
02259                                              const Polyhedron& ph) const {
02260   std::ostringstream s;
02261   s << "PPL::";
02262   if (is_necessarily_closed())
02263     s << "C_";
02264   else
02265     s << "NNC_";
02266   s << "Polyhedron::" << method << ":" << std::endl
02267     << ph_name << " is a ";
02268   if (ph.is_necessarily_closed())
02269     s << "C_";
02270   else
02271     s << "NNC_";
02272   s << "Polyhedron." << std::endl;
02273   throw std::invalid_argument(s.str());
02274 }
02275 
02276 void
02277 PPL::Polyhedron::throw_topology_incompatible(const char* method,
02278                                              const char* c_name,
02279                                              const Constraint&) const {
02280   PPL_ASSERT(is_necessarily_closed());
02281   std::ostringstream s;
02282   s << "PPL::C_Polyhedron::" << method << ":" << std::endl
02283     << c_name << " is a strict inequality.";
02284   throw std::invalid_argument(s.str());
02285 }
02286 
02287 void
02288 PPL::Polyhedron::throw_topology_incompatible(const char* method,
02289                                              const char* g_name,
02290                                              const Generator&) const {
02291   PPL_ASSERT(is_necessarily_closed());
02292   std::ostringstream s;
02293   s << "PPL::C_Polyhedron::" << method << ":" << std::endl
02294     << g_name << " is a closure point.";
02295   throw std::invalid_argument(s.str());
02296 }
02297 
02298 void
02299 PPL::Polyhedron::throw_topology_incompatible(const char* method,
02300                                              const char* cs_name,
02301                                              const Constraint_System&) const {
02302   PPL_ASSERT(is_necessarily_closed());
02303   std::ostringstream s;
02304   s << "PPL::C_Polyhedron::" << method << ":" << std::endl
02305     << cs_name << " contains strict inequalities.";
02306   throw std::invalid_argument(s.str());
02307 }
02308 
02309 void
02310 PPL::Polyhedron::throw_topology_incompatible(const char* method,
02311                                              const char* gs_name,
02312                                              const Generator_System&) const {
02313   std::ostringstream s;
02314   s << "PPL::C_Polyhedron::" << method << ":" << std::endl
02315     << gs_name << " contains closure points.";
02316   throw std::invalid_argument(s.str());
02317 }
02318 
02319 void
02320 PPL::Polyhedron::throw_dimension_incompatible(const char* method,
02321                                               const char* other_name,
02322                                               dimension_type other_dim) const {
02323   std::ostringstream s;
02324   s << "PPL::"
02325     << (is_necessarily_closed() ? "C_" : "NNC_")
02326     << "Polyhedron::" << method << ":\n"
02327     << "this->space_dimension() == " << space_dimension() << ", "
02328     << other_name << ".space_dimension() == " << other_dim << ".";
02329   throw std::invalid_argument(s.str());
02330 }
02331 
02332 void
02333 PPL::Polyhedron::throw_dimension_incompatible(const char* method,
02334                                               const char* ph_name,
02335                                               const Polyhedron& ph) const {
02336   throw_dimension_incompatible(method, ph_name, ph.space_dimension());
02337 }
02338 
02339 void
02340 PPL::Polyhedron
02341 ::throw_dimension_incompatible(const char* method,
02342                                const char* le_name,
02343                                const Linear_Expression& le) const {
02344   throw_dimension_incompatible(method, le_name, le.space_dimension());
02345 }
02346 
02347 void
02348 PPL::Polyhedron::throw_dimension_incompatible(const char* method,
02349                                               const char* c_name,
02350                                               const Constraint& c) const {
02351   throw_dimension_incompatible(method, c_name, c.space_dimension());
02352 }
02353 
02354 void
02355 PPL::Polyhedron::throw_dimension_incompatible(const char* method,
02356                                               const char* g_name,
02357                                               const Generator& g) const {
02358   throw_dimension_incompatible(method, g_name, g.space_dimension());
02359 }
02360 
02361 void
02362 PPL::Polyhedron::throw_dimension_incompatible(const char* method,
02363                                               const char* cg_name,
02364                                               const Congruence& cg) const {
02365   throw_dimension_incompatible(method, cg_name, cg.space_dimension());
02366 }
02367 
02368 void
02369 PPL::Polyhedron::throw_dimension_incompatible(const char* method,
02370                                               const char* cs_name,
02371                                               const Constraint_System& cs) const {
02372   throw_dimension_incompatible(method, cs_name, cs.space_dimension());
02373 }
02374 
02375 void
02376 PPL::Polyhedron
02377 ::throw_dimension_incompatible(const char* method,
02378                                const char* gs_name,
02379                                const Generator_System& gs) const {
02380   throw_dimension_incompatible(method, gs_name, gs.space_dimension());
02381 }
02382 
02383 void
02384 PPL::Polyhedron
02385 ::throw_dimension_incompatible(const char* method,
02386                                const char* cgs_name,
02387                                const Congruence_System& cgs) const {
02388   throw_dimension_incompatible(method, cgs_name, cgs.space_dimension());
02389 }
02390 
02391 void
02392 PPL::Polyhedron::throw_dimension_incompatible(const char* method,
02393                                               const char* var_name,
02394                                               const Variable var) const {
02395   std::ostringstream s;
02396   s << "PPL::";
02397   if (is_necessarily_closed())
02398     s << "C_";
02399   else
02400     s << "NNC_";
02401   s << "Polyhedron::" << method << ":" << std::endl
02402     << "this->space_dimension() == " << space_dimension() << ", "
02403     << var_name << ".space_dimension() == " << var.space_dimension() << ".";
02404   throw std::invalid_argument(s.str());
02405 }
02406 
02407 void
02408 PPL::Polyhedron::
02409 throw_dimension_incompatible(const char* method,
02410                              dimension_type required_space_dim) const {
02411   std::ostringstream s;
02412   s << "PPL::";
02413   if (is_necessarily_closed())
02414     s << "C_";
02415   else
02416     s << "NNC_";
02417   s << "Polyhedron::" << method << ":" << std::endl
02418     << "this->space_dimension() == " << space_dimension()
02419     << ", required space dimension == " << required_space_dim << ".";
02420   throw std::invalid_argument(s.str());
02421 }
02422 
02423 PPL::dimension_type
02424 PPL::Polyhedron::check_space_dimension_overflow(const dimension_type dim,
02425                                                 const dimension_type max,
02426                                                 const Topology topol,
02427                                                 const char* method,
02428                                                 const char* reason) {
02429   const char* domain = (topol == NECESSARILY_CLOSED)
02430     ? "PPL::C_Polyhedron::" : "PPL::NNC_Polyhedron::";
02431   return PPL::check_space_dimension_overflow(dim, max, domain, method, reason);
02432 }
02433 
02434 PPL::dimension_type
02435 PPL::Polyhedron::check_space_dimension_overflow(const dimension_type dim,
02436                                                 const Topology topol,
02437                                                 const char* method,
02438                                                 const char* reason) {
02439   return check_space_dimension_overflow(dim, Polyhedron::max_space_dimension(),
02440                                         topol, method, reason);
02441 }
02442 
02443 void
02444 PPL::Polyhedron::throw_invalid_generator(const char* method,
02445                                          const char* g_name) const {
02446   std::ostringstream s;
02447   s << "PPL::";
02448   if (is_necessarily_closed())
02449     s << "C_";
02450   else
02451     s << "NNC_";
02452   s << "Polyhedron::" << method << ":" << std::endl
02453     << "*this is an empty polyhedron and "
02454     << g_name << " is not a point.";
02455   throw std::invalid_argument(s.str());
02456 }
02457 
02458 void
02459 PPL::Polyhedron::throw_invalid_generators(const char* method,
02460                                           const char* gs_name) const {
02461   std::ostringstream s;
02462   s << "PPL::";
02463   if (is_necessarily_closed())
02464     s << "C_";
02465   else
02466     s << "NNC_";
02467   s << "Polyhedron::" << method << ":" << std::endl
02468     << "*this is an empty polyhedron and" << std::endl
02469     << "the non-empty generator system " << gs_name << " contains no points.";
02470   throw std::invalid_argument(s.str());
02471 }