PPL  0.12.1
Generator_System.cc
Go to the documentation of this file.
00001 /* Generator_System class implementation (non-inline functions).
00002    Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
00003    Copyright (C) 2010-2012 BUGSENG srl (http://bugseng.com)
00004 
00005 This file is part of the Parma Polyhedra Library (PPL).
00006 
00007 The PPL is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 The PPL is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with this program; if not, write to the Free Software Foundation,
00019 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
00020 
00021 For the most up-to-date information see the Parma Polyhedra Library
00022 site: http://bugseng.com/products/ppl/ . */
00023 
00024 #include "ppl-config.h"
00025 #include "Generator_System.defs.hh"
00026 #include "Generator_System.inlines.hh"
00027 #include "Constraint.defs.hh"
00028 #include "Scalar_Products.defs.hh"
00029 #include "assert.hh"
00030 #include <string>
00031 #include <vector>
00032 #include <iostream>
00033 #include <stdexcept>
00034 
00035 namespace PPL = Parma_Polyhedra_Library;
00036 
00037 bool
00038 PPL::Generator_System::
00039 adjust_topology_and_space_dimension(const Topology new_topology,
00040                                     const dimension_type new_space_dim) {
00041   PPL_ASSERT(space_dimension() <= new_space_dim);
00042 
00043   const dimension_type old_space_dim = space_dimension();
00044   const Topology old_topology = topology();
00045   dimension_type cols_to_be_added = new_space_dim - old_space_dim;
00046 
00047   // Dealing with empty generator systems first.
00048   if (has_no_rows()) {
00049     if (num_columns() == 0)
00050       if (new_topology == NECESSARILY_CLOSED) {
00051         add_zero_columns(cols_to_be_added + 1);
00052         set_necessarily_closed();
00053       }
00054       else {
00055         add_zero_columns(cols_to_be_added + 2);
00056         set_not_necessarily_closed();
00057       }
00058     else
00059       // Here `num_columns() > 0'.
00060       if (old_topology != new_topology)
00061         if (new_topology == NECESSARILY_CLOSED) {
00062           switch (cols_to_be_added) {
00063           case 0:
00064             remove_trailing_columns(1);
00065             break;
00066           case 1:
00067             // Nothing to do.
00068             break;
00069           default:
00070             add_zero_columns(cols_to_be_added - 1);
00071           }
00072           set_necessarily_closed();
00073         }
00074         else {
00075           // Here old_topology == NECESSARILY_CLOSED
00076           //  and new_topology == NOT_NECESSARILY_CLOSED.
00077           add_zero_columns(cols_to_be_added + 1);
00078           set_not_necessarily_closed();
00079         }
00080       else
00081         // Here topologies agree.
00082         if (cols_to_be_added > 0)
00083           add_zero_columns(cols_to_be_added);
00084     PPL_ASSERT(OK());
00085     return true;
00086   }
00087 
00088   // Here the generator system is not empty.
00089   if (cols_to_be_added > 0)
00090     if (old_topology != new_topology)
00091       if (new_topology == NECESSARILY_CLOSED) {
00092         // A NOT_NECESSARILY_CLOSED generator system
00093         // can be converted to a NECESSARILY_CLOSED one
00094         // only if it does not contain closure points.
00095         // This check has to be performed under the user viewpoint.
00096         if (has_closure_points())
00097           return false;
00098         // For a correct implementation, we have to remove those
00099         // closure points that were matching a point (i.e., those
00100         // that are in the generator system, but are invisible to
00101         // the user).
00102         Generator_System& gs = *this;
00103         dimension_type num_closure_points = 0;
00104         dimension_type gs_end = gs.num_rows();
00105         for (dimension_type i = 0; i < gs_end; ) {
00106           // All the closure points seen so far have consecutive
00107           // indices starting from `i'.
00108           if (num_closure_points > 0) {
00109             // Let next generator have index `i'.
00110             using std::swap;
00111             swap(gs[i], gs[i+num_closure_points]);
00112           }
00113           if (gs[i].is_closure_point()) {
00114             ++num_closure_points;
00115             --gs_end;
00116           }
00117           else
00118             ++i;
00119         }
00120         // We may have identified some closure points.
00121         if (num_closure_points > 0) {
00122           PPL_ASSERT(num_closure_points == num_rows() - gs_end);
00123           remove_trailing_rows(num_closure_points);
00124         }
00125         // Remove the epsilon column, re-normalize and, after that,
00126         // add the missing dimensions. This ensures that
00127         // non-zero epsilon coefficients will be cleared.
00128         remove_trailing_columns(1);
00129         set_necessarily_closed();
00130         normalize();
00131         add_zero_columns(cols_to_be_added);
00132       }
00133       else {
00134         // A NECESSARILY_CLOSED generator system is converted to
00135         // a NOT_NECESSARILY_CLOSED one by adding a further column
00136         // and setting the epsilon coordinate of all points to 1.
00137         // Note: normalization is preserved.
00138         add_zero_columns(cols_to_be_added + 1);
00139         Generator_System& gs = *this;
00140         const dimension_type eps_index = new_space_dim + 1;
00141         for (dimension_type i = num_rows(); i-- > 0; )
00142           gs[i][eps_index] = gs[i][0];
00143         set_not_necessarily_closed();
00144       }
00145     else {
00146       // Topologies agree: first add the required zero columns ...
00147       add_zero_columns(cols_to_be_added);
00148       // ... and, if needed, move the epsilon coefficients
00149       // to the new last column.
00150       if (old_topology == NOT_NECESSARILY_CLOSED)
00151         swap_columns(old_space_dim + 1, new_space_dim + 1);
00152     }
00153   else
00154     // Here `cols_to_be_added == 0'.
00155     if (old_topology != new_topology) {
00156       if (new_topology == NECESSARILY_CLOSED) {
00157         // A NOT_NECESSARILY_CLOSED generator system
00158         // can be converted in to a NECESSARILY_CLOSED one
00159         // only if it does not contain closure points.
00160         if (has_closure_points())
00161           return false;
00162         // We just remove the column of the epsilon coefficients.
00163         remove_trailing_columns(1);
00164         set_necessarily_closed();
00165       }
00166       else {
00167         // Add the column of the epsilon coefficients
00168         // and set the epsilon coordinate of all points to 1.
00169         // Note: normalization is preserved.
00170         add_zero_columns(1);
00171         Generator_System& gs = *this;
00172         const dimension_type eps_index = new_space_dim + 1;
00173         for (dimension_type i = num_rows(); i-- > 0; )
00174           gs[i][eps_index] = gs[i][0];
00175         set_not_necessarily_closed();
00176       }
00177     }
00178   // We successfully adjusted dimensions and topology.
00179   PPL_ASSERT(OK());
00180   return true;
00181 }
00182 
00183 // TODO: would be worth to avoid adding closure points
00184 // that already are in the system of generators?
00185 // To do this efficiently we could sort the system and
00186 // perform insertions keeping its sortedness.
00187 void
00188 PPL::Generator_System::add_corresponding_closure_points() {
00189   PPL_ASSERT(!is_necessarily_closed());
00190   // NOTE: we always add (pending) rows at the end of the generator system.
00191   // Updating `index_first_pending', if needed, is done by the caller.
00192   Generator_System& gs = *this;
00193   const dimension_type n_rows = gs.num_rows();
00194   const dimension_type eps_index = gs.num_columns() - 1;
00195   for (dimension_type i = n_rows; i-- > 0; ) {
00196     const Generator& g = gs[i];
00197     if (g[eps_index] > 0) {
00198       // `g' is a point: adding the closure point.
00199       Generator cp = g;
00200       cp[eps_index] = 0;
00201       // Enforcing normalization.
00202       cp.normalize();
00203       gs.add_pending_row(cp);
00204     }
00205   }
00206   PPL_ASSERT(OK());
00207 }
00208 
00209 
00210 // TODO: would be worth to avoid adding points
00211 // that already are in the system of generators?
00212 // To do this efficiently we could sort the system and
00213 // perform insertions keeping its sortedness.
00214 void
00215 PPL::Generator_System::add_corresponding_points() {
00216   PPL_ASSERT(!is_necessarily_closed());
00217   // NOTE: we always add (pending) rows at the end of the generator system.
00218   // Updating `index_first_pending', if needed, is done by the caller.
00219   Generator_System& gs = *this;
00220   const dimension_type n_rows = gs.num_rows();
00221   const dimension_type eps_index = gs.num_columns() - 1;
00222   for (dimension_type i = 0; i < n_rows; i++) {
00223     const Generator& g = gs[i];
00224     if (!g.is_line_or_ray() && g[eps_index] == 0) {
00225       // `g' is a closure point: adding the point.
00226       // Note: normalization is preserved.
00227       Generator p = g;
00228       p[eps_index] = p[0];
00229       gs.add_pending_row(p);
00230     }
00231   }
00232   PPL_ASSERT(OK());
00233 }
00234 
00235 bool
00236 PPL::Generator_System::has_closure_points() const {
00237   if (is_necessarily_closed())
00238     return false;
00239   // Adopt the point of view of the user.
00240   for (Generator_System::const_iterator i = begin(),
00241          this_end = end(); i != this_end; ++i)
00242     if (i->is_closure_point())
00243       return true;
00244   return false;
00245 }
00246 
00247 bool
00248 PPL::Generator_System::has_points() const {
00249   const Generator_System& gs = *this;
00250   // Avoiding the repeated tests on topology.
00251   if (is_necessarily_closed())
00252     for (dimension_type i = num_rows(); i-- > 0; ) {
00253       if (!gs[i].is_line_or_ray())
00254         return true;
00255     }
00256   else {
00257     // !is_necessarily_closed()
00258     const dimension_type eps_index = gs.num_columns() - 1;
00259     for (dimension_type i = num_rows(); i-- > 0; )
00260     if (gs[i][eps_index] != 0)
00261       return true;
00262   }
00263   return false;
00264 }
00265 
00266 void
00267 PPL::Generator_System::const_iterator::skip_forward() {
00268   const Linear_System::const_iterator gsp_end = gsp->end();
00269   if (i != gsp_end) {
00270     Linear_System::const_iterator i_next = i;
00271     ++i_next;
00272     if (i_next != gsp_end) {
00273       const Generator& cp = static_cast<const Generator&>(*i);
00274       const Generator& p = static_cast<const Generator&>(*i_next);
00275       if (cp.is_closure_point()
00276           && p.is_point()
00277           && cp.is_matching_closure_point(p))
00278         i = i_next;
00279     }
00280   }
00281 }
00282 
00283 void
00284 PPL::Generator_System::insert(const Generator& g) {
00285   // We are sure that the matrix has no pending rows
00286   // and that the new row is not a pending generator.
00287   PPL_ASSERT(num_pending_rows() == 0);
00288   if (topology() == g.topology())
00289     Linear_System::insert(g);
00290   else
00291     // `*this' and `g' have different topologies.
00292     if (is_necessarily_closed()) {
00293       // Padding the matrix with the column
00294       // corresponding to the epsilon coefficients:
00295       // all points must have epsilon coordinate equal to 1
00296       // (i.e., the epsilon coefficient is equal to the divisor);
00297       // rays and lines must have epsilon coefficient equal to 0.
00298       // Note: normalization is preserved.
00299       const dimension_type eps_index = num_columns();
00300       add_zero_columns(1);
00301       Generator_System& gs = *this;
00302       for (dimension_type i = num_rows(); i-- > 0; ) {
00303         Generator& gen = gs[i];
00304         if (!gen.is_line_or_ray())
00305           gen[eps_index] = gen[0];
00306       }
00307       set_not_necessarily_closed();
00308       // Inserting the new generator.
00309       Linear_System::insert(g);
00310     }
00311     else {
00312       // The generator system is NOT necessarily closed:
00313       // copy the generator, adding the missing dimensions
00314       // and the epsilon coefficient.
00315       const dimension_type new_size = 2 + std::max(g.space_dimension(),
00316                                                    space_dimension());
00317       Generator tmp_g(g, new_size);
00318       // If it was a point, set the epsilon coordinate to 1
00319       // (i.e., set the coefficient equal to the divisor).
00320       // Note: normalization is preserved.
00321       if (!tmp_g.is_line_or_ray())
00322         tmp_g[new_size - 1] = tmp_g[0];
00323       tmp_g.set_not_necessarily_closed();
00324       // Inserting the new generator.
00325       Linear_System::insert(tmp_g);
00326     }
00327   PPL_ASSERT(OK());
00328 }
00329 
00330 void
00331 PPL::Generator_System::insert_pending(const Generator& g) {
00332   if (topology() == g.topology())
00333     Linear_System::insert_pending(g);
00334   else
00335     // `*this' and `g' have different topologies.
00336     if (is_necessarily_closed()) {
00337       // Padding the matrix with the column
00338       // corresponding to the epsilon coefficients:
00339       // all points must have epsilon coordinate equal to 1
00340       // (i.e., the epsilon coefficient is equal to the divisor);
00341       // rays and lines must have epsilon coefficient equal to 0.
00342       // Note: normalization is preserved.
00343       const dimension_type eps_index = num_columns();
00344       add_zero_columns(1);
00345       Generator_System& gs = *this;
00346       for (dimension_type i = num_rows(); i-- > 0; ) {
00347         Generator& gen = gs[i];
00348         if (!gen.is_line_or_ray())
00349           gen[eps_index] = gen[0];
00350       }
00351       set_not_necessarily_closed();
00352       // Inserting the new generator.
00353       Linear_System::insert_pending(g);
00354     }
00355     else {
00356       // The generator system is NOT necessarily closed:
00357       // copy the generator, adding the missing dimensions
00358       // and the epsilon coefficient.
00359       const dimension_type new_size = 2 + std::max(g.space_dimension(),
00360                                                    space_dimension());
00361       Generator tmp_g(g, new_size);
00362       // If it was a point, set the epsilon coordinate to 1
00363       // (i.e., set the coefficient equal to the divisor).
00364       // Note: normalization is preserved.
00365       if (!tmp_g.is_line_or_ray())
00366         tmp_g[new_size - 1] = tmp_g[0];
00367       tmp_g.set_not_necessarily_closed();
00368       // Inserting the new generator.
00369       Linear_System::insert_pending(tmp_g);
00370     }
00371   PPL_ASSERT(OK());
00372 }
00373 
00374 PPL::dimension_type
00375 PPL::Generator_System::num_lines() const {
00376   // We are sure that this method is applied only to a matrix
00377   // that does not contain pending rows.
00378   PPL_ASSERT(num_pending_rows() == 0);
00379   const Generator_System& gs = *this;
00380   dimension_type n = 0;
00381   // If the Linear_System happens to be sorted, take advantage of the fact
00382   // that lines are at the top of the system.
00383   if (is_sorted()) {
00384     dimension_type nrows = num_rows();
00385     for (dimension_type i = 0; i < nrows && gs[i].is_line(); ++i)
00386       ++n;
00387   }
00388   else
00389     for (dimension_type i = num_rows(); i-- > 0 ; )
00390       if (gs[i].is_line())
00391         ++n;
00392   return n;
00393 }
00394 
00395 PPL::dimension_type
00396 PPL::Generator_System::num_rays() const {
00397   // We are sure that this method is applied only to a matrix
00398   // that does not contain pending rows.
00399   PPL_ASSERT(num_pending_rows() == 0);
00400   const Generator_System& gs = *this;
00401   dimension_type n = 0;
00402   // If the Linear_System happens to be sorted, take advantage of the fact
00403   // that rays and points are at the bottom of the system and
00404   // rays have the inhomogeneous term equal to zero.
00405   if (is_sorted()) {
00406     for (dimension_type i = num_rows(); i != 0 && gs[--i].is_ray_or_point(); )
00407       if (gs[i].is_line_or_ray())
00408         ++n;
00409   }
00410   else
00411     for (dimension_type i = num_rows(); i-- > 0 ; )
00412       if (gs[i].is_ray())
00413         ++n;
00414   return n;
00415 }
00416 
00417 PPL::Poly_Con_Relation
00418 PPL::Generator_System::relation_with(const Constraint& c) const {
00419   // Note: this method is not public and it is the responsibility
00420   // of the caller to actually test for dimension compatibility.
00421   // We simply assert it.
00422   PPL_ASSERT(space_dimension() >= c.space_dimension());
00423   // Number of generators: the case of an empty polyhedron
00424   // has already been filtered out by the caller.
00425   const dimension_type n_rows = num_rows();
00426   PPL_ASSERT(n_rows > 0);
00427   const Generator_System& gs = *this;
00428 
00429   // `result' will keep the relation holding between the generators
00430   // we have seen so far and the constraint `c'.
00431   Poly_Con_Relation result = Poly_Con_Relation::saturates();
00432 
00433   switch (c.type()) {
00434 
00435   case Constraint::EQUALITY:
00436     {
00437       // The hyperplane defined by the equality `c' is included
00438       // in the set of points satisfying `c' (it is the same set!).
00439       result = result && Poly_Con_Relation::is_included();
00440       // The following integer variable will hold the scalar product sign
00441       // of either the first point or the first non-saturating ray we find.
00442       // If it is equal to 2, then it means that we haven't found such
00443       // a generator yet.
00444       int first_point_or_nonsaturating_ray_sign = 2;
00445 
00446       for (dimension_type i = n_rows; i-- > 0; ) {
00447         const Generator& g = gs[i];
00448         const int sp_sign = Scalar_Products::sign(c, g);
00449         // Checking whether the generator saturates the equality.
00450         // If that is the case, then we have to do something only if
00451         // the generator is a point.
00452         if (sp_sign == 0) {
00453           if (g.is_point()) {
00454             if (first_point_or_nonsaturating_ray_sign == 2)
00455               // It is the first time that we find a point and
00456               // we have not found a non-saturating ray yet.
00457               first_point_or_nonsaturating_ray_sign = 0;
00458             else
00459               // We already found a point or a non-saturating ray.
00460               if (first_point_or_nonsaturating_ray_sign != 0)
00461                 return Poly_Con_Relation::strictly_intersects();
00462           }
00463         }
00464         else
00465           // Here we know that sp_sign != 0.
00466           switch (g.type()) {
00467 
00468           case Generator::LINE:
00469             // If a line does not saturate `c', then there is a strict
00470             // intersection between the points satisfying `c'
00471             // and the points generated by `gs'.
00472             return Poly_Con_Relation::strictly_intersects();
00473 
00474           case Generator::RAY:
00475             if (first_point_or_nonsaturating_ray_sign == 2) {
00476               // It is the first time that we have a non-saturating ray
00477               // and we have not found any point yet.
00478               first_point_or_nonsaturating_ray_sign = sp_sign;
00479               result = Poly_Con_Relation::is_disjoint();
00480             }
00481             else
00482               // We already found a point or a non-saturating ray.
00483               if (sp_sign != first_point_or_nonsaturating_ray_sign)
00484                 return Poly_Con_Relation::strictly_intersects();
00485             break;
00486 
00487           case Generator::POINT:
00488           case Generator::CLOSURE_POINT:
00489             // NOTE: a non-saturating closure point is treated as
00490             // a normal point.
00491             if (first_point_or_nonsaturating_ray_sign == 2) {
00492               // It is the first time that we find a point and
00493               // we have not found a non-saturating ray yet.
00494               first_point_or_nonsaturating_ray_sign = sp_sign;
00495               result = Poly_Con_Relation::is_disjoint();
00496             }
00497             else
00498               // We already found a point or a non-saturating ray.
00499               if (sp_sign != first_point_or_nonsaturating_ray_sign)
00500                 return Poly_Con_Relation::strictly_intersects();
00501             break;
00502           }
00503       }
00504     }
00505     break;
00506 
00507   case Constraint::NONSTRICT_INEQUALITY:
00508     {
00509       // The hyperplane implicitly defined by the non-strict inequality `c'
00510       // is included in the set of points satisfying `c'.
00511       result = result && Poly_Con_Relation::is_included();
00512       // The following Boolean variable will be set to `false'
00513       // as soon as either we find (any) point or we find a
00514       // non-saturating ray.
00515       bool first_point_or_nonsaturating_ray = true;
00516 
00517       for (dimension_type i = n_rows; i-- > 0; ) {
00518         const Generator& g = gs[i];
00519         const int sp_sign = Scalar_Products::sign(c, g);
00520         // Checking whether the generator saturates the non-strict
00521         // inequality. If that is the case, then we have to do something
00522         // only if the generator is a point.
00523         if (sp_sign == 0) {
00524           if (g.is_point()) {
00525             if (first_point_or_nonsaturating_ray)
00526               // It is the first time that we have a point and
00527               // we have not found a non-saturating ray yet.
00528               first_point_or_nonsaturating_ray = false;
00529             else
00530               // We already found a point or a non-saturating ray before.
00531               if (result == Poly_Con_Relation::is_disjoint())
00532                 // Since g saturates c, we have a strict intersection if
00533                 // none of the generators seen so far are included in `c'.
00534                 return Poly_Con_Relation::strictly_intersects();
00535           }
00536         }
00537         else
00538           // Here we know that sp_sign != 0.
00539           switch (g.type()) {
00540 
00541           case Generator::LINE:
00542             // If a line does not saturate `c', then there is a strict
00543             // intersection between the points satisfying `c' and
00544             // the points generated by `gs'.
00545             return Poly_Con_Relation::strictly_intersects();
00546 
00547           case Generator::RAY:
00548             if (first_point_or_nonsaturating_ray) {
00549               // It is the first time that we have a non-saturating ray
00550               // and we have not found any point yet.
00551               first_point_or_nonsaturating_ray = false;
00552               result = (sp_sign > 0)
00553                 ? Poly_Con_Relation::is_included()
00554                 : Poly_Con_Relation::is_disjoint();
00555             }
00556             else {
00557               // We already found a point or a non-saturating ray.
00558               if ((sp_sign > 0
00559                    && result == Poly_Con_Relation::is_disjoint())
00560                   || (sp_sign < 0
00561                       && result.implies(Poly_Con_Relation::is_included())))
00562                 // We have a strict intersection if either:
00563                 // - `g' satisfies `c' but none of the generators seen
00564                 //    so far are included in `c'; or
00565                 // - `g' does not satisfy `c' and all the generators
00566                 //    seen so far are included in `c'.
00567                 return Poly_Con_Relation::strictly_intersects();
00568               if (sp_sign > 0)
00569                 // Here all the generators seen so far either saturate
00570                 // or are included in `c'.
00571                 // Since `g' does not saturate `c' ...
00572                 result = Poly_Con_Relation::is_included();
00573             }
00574             break;
00575 
00576           case Generator::POINT:
00577           case Generator::CLOSURE_POINT:
00578             // NOTE: a non-saturating closure point is treated as
00579             // a normal point.
00580             if (first_point_or_nonsaturating_ray) {
00581               // It is the first time that we have a point and
00582               // we have not found a non-saturating ray yet.
00583               // - If point `g' saturates `c', then all the generators
00584               //   seen so far saturate `c'.
00585               // - If point `g' is included (but does not saturate) `c',
00586               //   then all the generators seen so far are included in `c'.
00587               // - If point `g' does not satisfy `c', then all the
00588               //   generators seen so far are disjoint from `c'.
00589               first_point_or_nonsaturating_ray = false;
00590               if (sp_sign > 0)
00591                 result = Poly_Con_Relation::is_included();
00592               else if (sp_sign < 0)
00593                 result = Poly_Con_Relation::is_disjoint();
00594             }
00595             else {
00596               // We already found a point or a non-saturating ray before.
00597               if ((sp_sign > 0
00598                    && result == Poly_Con_Relation::is_disjoint())
00599                   || (sp_sign < 0
00600                       && result.implies(Poly_Con_Relation::is_included())))
00601                 // We have a strict intersection if either:
00602                 // - `g' satisfies or saturates `c' but none of the
00603                 //    generators seen so far are included in `c'; or
00604                 // - `g' does not satisfy `c' and all the generators
00605                 //    seen so far are included in `c'.
00606                 return Poly_Con_Relation::strictly_intersects();
00607               if (sp_sign > 0)
00608                 // Here all the generators seen so far either saturate
00609                 // or are included in `c'.
00610                 // Since `g' does not saturate `c' ...
00611                 result = Poly_Con_Relation::is_included();
00612             }
00613             break;
00614           }
00615       }
00616     }
00617     break;
00618 
00619   case Constraint::STRICT_INEQUALITY:
00620     {
00621       // The hyperplane implicitly defined by the strict inequality `c'
00622       // is disjoint from the set of points satisfying `c'.
00623       result = result && Poly_Con_Relation::is_disjoint();
00624       // The following Boolean variable will be set to `false'
00625       // as soon as either we find (any) point or we find a
00626       // non-saturating ray.
00627       bool first_point_or_nonsaturating_ray = true;
00628       for (dimension_type i = n_rows; i-- > 0; ) {
00629         const Generator& g = gs[i];
00630         // Using the reduced scalar product operator to avoid
00631         // both topology and num_columns mismatches.
00632         const int sp_sign = Scalar_Products::reduced_sign(c, g);
00633         // Checking whether the generator saturates the strict inequality.
00634         // If that is the case, then we have to do something
00635         // only if the generator is a point.
00636         if (sp_sign == 0) {
00637           if (g.is_point()) {
00638             if (first_point_or_nonsaturating_ray)
00639               // It is the first time that we have a point and
00640               // we have not found a non-saturating ray yet.
00641               first_point_or_nonsaturating_ray = false;
00642             else
00643               // We already found a point or a non-saturating ray before.
00644               if (result == Poly_Con_Relation::is_included())
00645                 return Poly_Con_Relation::strictly_intersects();
00646           }
00647         }
00648         else
00649           // Here we know that sp_sign != 0.
00650           switch (g.type()) {
00651 
00652           case Generator::LINE:
00653             // If a line does not saturate `c', then there is a strict
00654             // intersection between the points satisfying `c' and the points
00655             // generated by `gs'.
00656             return Poly_Con_Relation::strictly_intersects();
00657 
00658           case Generator::RAY:
00659             if (first_point_or_nonsaturating_ray) {
00660               // It is the first time that we have a non-saturating ray
00661               // and we have not found any point yet.
00662               first_point_or_nonsaturating_ray = false;
00663               result = (sp_sign > 0)
00664                 ? Poly_Con_Relation::is_included()
00665                 : Poly_Con_Relation::is_disjoint();
00666             }
00667             else {
00668               // We already found a point or a non-saturating ray before.
00669               if ((sp_sign > 0
00670                    && result.implies(Poly_Con_Relation::is_disjoint()))
00671                   ||
00672                   (sp_sign <= 0
00673                    && result == Poly_Con_Relation::is_included()))
00674                 return Poly_Con_Relation::strictly_intersects();
00675               if (sp_sign < 0)
00676                 // Here all the generators seen so far either saturate
00677                 // or are disjoint from `c'.
00678                 // Since `g' does not saturate `c' ...
00679                 result = Poly_Con_Relation::is_disjoint();
00680             }
00681             break;
00682 
00683           case Generator::POINT:
00684           case Generator::CLOSURE_POINT:
00685             if (first_point_or_nonsaturating_ray) {
00686               // It is the first time that we have a point and
00687               // we have not found a non-saturating ray yet.
00688               // - If point `g' saturates `c', then all the generators
00689               //   seen so far saturate `c'.
00690               // - If point `g' is included in (but does not saturate) `c',
00691               //   then all the generators seen so far are included in `c'.
00692               // - If point `g' strictly violates `c', then all the
00693               //   generators seen so far are disjoint from `c'.
00694               first_point_or_nonsaturating_ray = false;
00695               if (sp_sign > 0)
00696                 result = Poly_Con_Relation::is_included();
00697               else if (sp_sign < 0)
00698                 result = Poly_Con_Relation::is_disjoint();
00699             }
00700             else {
00701               // We already found a point or a non-saturating ray before.
00702               if ((sp_sign > 0
00703                    && result.implies(Poly_Con_Relation::is_disjoint()))
00704                   ||
00705                   (sp_sign <= 0
00706                    && result == Poly_Con_Relation::is_included()))
00707                 return Poly_Con_Relation::strictly_intersects();
00708               if (sp_sign < 0)
00709                 // Here all the generators seen so far either saturate
00710                 // or are disjoint from `c'.
00711                 // Since `g' does not saturate `c' ...
00712                 result = Poly_Con_Relation::is_disjoint();
00713             }
00714             break;
00715           }
00716       }
00717     }
00718     break;
00719   }
00720   // We have seen all generators.
00721   return result;
00722 }
00723 
00724 
00725 bool
00726 PPL::Generator_System::satisfied_by_all_generators(const Constraint& c) const {
00727   PPL_ASSERT(c.space_dimension() <= space_dimension());
00728 
00729   // Setting `sps' to the appropriate scalar product sign operator.
00730   // This also avoids problems when having _legal_ topology mismatches
00731   // (which could also cause a mismatch in the number of columns).
00732   Topology_Adjusted_Scalar_Product_Sign sps(c);
00733 
00734   const Generator_System& gs = *this;
00735   switch (c.type()) {
00736   case Constraint::EQUALITY:
00737     // Equalities must be saturated by all generators.
00738     for (dimension_type i = gs.num_rows(); i-- > 0; )
00739       if (sps(c, gs[i]) != 0)
00740         return false;
00741     break;
00742   case Constraint::NONSTRICT_INEQUALITY:
00743     // Non-strict inequalities must be saturated by lines and
00744     // satisfied by all the other generators.
00745     for (dimension_type i = gs.num_rows(); i-- > 0; ) {
00746       const Generator& g = gs[i];
00747       const int sp_sign = sps(c, g);
00748       if (g.is_line()) {
00749         if (sp_sign != 0)
00750           return false;
00751       }
00752       else
00753         // `g' is a ray, point or closure point.
00754         if (sp_sign < 0)
00755           return false;
00756     }
00757     break;
00758   case Constraint::STRICT_INEQUALITY:
00759     // Strict inequalities must be saturated by lines,
00760     // satisfied by all generators, and must not be saturated by points.
00761     for (dimension_type i = gs.num_rows(); i-- > 0; ) {
00762       const Generator& g = gs[i];
00763       const int sp_sign = sps(c, g);
00764       switch (g.type()) {
00765       case Generator::POINT:
00766         if (sp_sign <= 0)
00767           return false;
00768         break;
00769       case Generator::LINE:
00770         if (sp_sign != 0)
00771           return false;
00772         break;
00773       default:
00774         // `g' is a ray or closure point.
00775         if (sp_sign < 0)
00776           return false;
00777         break;
00778       }
00779     }
00780     break;
00781   }
00782   // If we reach this point, `c' is satisfied by all generators.
00783   return true;
00784 }
00785 
00786 
00787 void
00788 PPL::Generator_System
00789 ::affine_image(dimension_type v,
00790                const Linear_Expression& expr,
00791                Coefficient_traits::const_reference denominator) {
00792   Generator_System& x = *this;
00793   // `v' is the index of a column corresponding to
00794   // a "user" variable (i.e., it cannot be the inhomogeneous term,
00795   // nor the epsilon dimension of NNC polyhedra).
00796   PPL_ASSERT(v > 0 && v <= x.space_dimension());
00797   PPL_ASSERT(expr.space_dimension() <= x.space_dimension());
00798   PPL_ASSERT(denominator > 0);
00799 
00800   const dimension_type n_columns = x.num_columns();
00801   const dimension_type n_rows = x.num_rows();
00802 
00803   // Compute the numerator of the affine transformation and assign it
00804   // to the column of `*this' indexed by `v'.
00805   PPL_DIRTY_TEMP_COEFFICIENT(numerator);
00806   for (dimension_type i = n_rows; i-- > 0; ) {
00807     Generator& row = x[i];
00808     Scalar_Products::assign(numerator, expr, row);
00809     using std::swap;
00810     swap(numerator, row[v]);
00811   }
00812 
00813   if (denominator != 1) {
00814     // Since we want integer elements in the matrix,
00815     // we multiply by `denominator' all the columns of `*this'
00816     // having an index different from `v'.
00817     for (dimension_type i = n_rows; i-- > 0; ) {
00818       Generator& row = x[i];
00819       for (dimension_type j = n_columns; j-- > 0; )
00820         if (j != v)
00821           row[j] *= denominator;
00822     }
00823   }
00824 
00825   // If the mapping is not invertible we may have transformed
00826   // valid lines and rays into the origin of the space.
00827   const bool not_invertible = (v > expr.space_dimension() || expr[v] == 0);
00828   if (not_invertible)
00829     x.remove_invalid_lines_and_rays();
00830 
00831   // Strong normalization also resets the sortedness flag.
00832   x.strong_normalize();
00833 }
00834 
00835 void
00836 PPL::Generator_System::ascii_dump(std::ostream& s) const {
00837   const Generator_System& x = *this;
00838   const dimension_type x_num_rows = x.num_rows();
00839   const dimension_type x_num_columns = x.num_columns();
00840   s << "topology " << (is_necessarily_closed()
00841                        ? "NECESSARILY_CLOSED"
00842                        : "NOT_NECESSARILY_CLOSED")
00843     << "\n"
00844     << x_num_rows << " x " << x_num_columns << ' '
00845     << (x.is_sorted() ? "(sorted)" : "(not_sorted)")
00846     << "\n"
00847     << "index_first_pending " << x.first_pending_row()
00848     << "\n";
00849   for (dimension_type i = 0; i < x_num_rows; ++i) {
00850     const Generator& g = x[i];
00851     for (dimension_type j = 0; j < x_num_columns; ++j)
00852       s << g[j] << ' ';
00853     switch (g.type()) {
00854     case Generator::LINE:
00855       s << "L";
00856       break;
00857     case Generator::RAY:
00858       s << "R";
00859       break;
00860     case Generator::POINT:
00861       s << "P";
00862       break;
00863     case Generator::CLOSURE_POINT:
00864       s << "C";
00865       break;
00866     }
00867     s << "\n";
00868   }
00869 }
00870 
00871 PPL_OUTPUT_DEFINITIONS(Generator_System)
00872 
00873 bool
00874 PPL::Generator_System::ascii_load(std::istream& s) {
00875   std::string str;
00876   if (!(s >> str) || str != "topology")
00877     return false;
00878   if (!(s >> str))
00879     return false;
00880   if (str == "NECESSARILY_CLOSED")
00881     set_necessarily_closed();
00882   else {
00883     if (str != "NOT_NECESSARILY_CLOSED")
00884       return false;
00885     set_not_necessarily_closed();
00886   }
00887 
00888   dimension_type nrows;
00889   dimension_type ncols;
00890   if (!(s >> nrows))
00891     return false;
00892   if (!(s >> str) || str != "x")
00893     return false;
00894   if (!(s >> ncols))
00895       return false;
00896   resize_no_copy(nrows, ncols);
00897 
00898   if (!(s >> str) || (str != "(sorted)" && str != "(not_sorted)"))
00899     return false;
00900   set_sorted(str == "(sorted)");
00901   dimension_type index;
00902   if (!(s >> str) || str != "index_first_pending")
00903     return false;
00904   if (!(s >> index))
00905     return false;
00906   set_index_first_pending_row(index);
00907 
00908   Generator_System& x = *this;
00909   for (dimension_type i = 0; i < x.num_rows(); ++i) {
00910     for (dimension_type j = 0; j < x.num_columns(); ++j)
00911       if (!(s >> x[i][j]))
00912         return false;
00913 
00914     if (!(s >> str))
00915       return false;
00916     if (str == "L")
00917       x[i].set_is_line();
00918     else if (str == "R" || str == "P" || str == "C")
00919       x[i].set_is_ray_or_point();
00920     else
00921       return false;
00922 
00923     // Checking for equality of actual and declared types.
00924     switch (x[i].type()) {
00925     case Generator::LINE:
00926       if (str == "L")
00927         continue;
00928       break;
00929     case Generator::RAY:
00930       if (str == "R")
00931         continue;
00932       break;
00933     case Generator::POINT:
00934       if (str == "P")
00935         continue;
00936       break;
00937     case Generator::CLOSURE_POINT:
00938       if (str == "C")
00939         continue;
00940       break;
00941     }
00942     // Reaching this point means that the input was illegal.
00943     return false;
00944   }
00945 
00946   // Check invariants.
00947   PPL_ASSERT(OK());
00948   return true;
00949 }
00950 
00951 void
00952 PPL::Generator_System::remove_invalid_lines_and_rays() {
00953   // The origin of the vector space cannot be a valid line/ray.
00954   // NOTE: the following swaps will mix generators without even trying
00955   // to preserve sortedness: as a matter of fact, it will almost always
00956   // be the case that the input generator system is NOT sorted.
00957   using std::swap;
00958   Generator_System& gs = *this;
00959   const dimension_type old_n_rows = gs.num_rows();
00960   dimension_type n_rows = old_n_rows;
00961   if (num_pending_rows() == 0) {
00962     for (dimension_type i = n_rows; i-- > 0; ) {
00963       Generator& g = gs[i];
00964       if (g.is_line_or_ray() && g.all_homogeneous_terms_are_zero()) {
00965         // An invalid line/ray has been found.
00966         --n_rows;
00967         swap(g, gs[n_rows]);
00968         gs.set_sorted(false);
00969       }
00970     }
00971     set_index_first_pending_row(n_rows);
00972   }
00973   else {
00974     // If the matrix has some pending rows, we can not
00975     // swap the "normal" rows with the pending rows. So
00976     // we must put at the end of the "normal" rows
00977     // the invalid "normal" rows, put them at the end
00978     // of the matrix, find the invalid rows in the pending
00979     // part and then erase the invalid rows that now
00980     // are in the bottom part of the matrix.
00981     PPL_ASSERT(num_pending_rows() > 0);
00982     dimension_type first_pending = first_pending_row();
00983     for (dimension_type i = first_pending; i-- > 0; ) {
00984       Generator& g = gs[i];
00985       if (g.is_line_or_ray() && g.all_homogeneous_terms_are_zero()) {
00986         // An invalid line/ray has been found.
00987         --first_pending;
00988         swap(g, gs[first_pending]);
00989         gs.set_sorted(false);
00990       }
00991     }
00992     const dimension_type num_invalid_rows
00993       = first_pending_row() - first_pending;
00994     set_index_first_pending_row(first_pending);
00995     for (dimension_type i = 0; i < num_invalid_rows; ++i)
00996       swap(gs[n_rows - i], gs[first_pending + i]);
00997     n_rows -= num_invalid_rows;
00998     for (dimension_type i = n_rows; i-- > first_pending; ) {
00999       Generator& g = gs[i];
01000       if (g.is_line_or_ray() && g.all_homogeneous_terms_are_zero()) {
01001         // An invalid line/ray has been found.
01002         --n_rows;
01003         swap(g, gs[n_rows]);
01004         gs.set_sorted(false);
01005       }
01006     }
01007   }
01008   gs.remove_trailing_rows(old_n_rows - n_rows);
01009 }
01010 
01011 const PPL::Generator_System* PPL::Generator_System::zero_dim_univ_p = 0;
01012 
01013 void
01014 PPL::Generator_System::initialize() {
01015   PPL_ASSERT(zero_dim_univ_p == 0);
01016   zero_dim_univ_p
01017     = new Generator_System(Generator::zero_dim_point());
01018 }
01019 
01020 void
01021 PPL::Generator_System::finalize() {
01022   PPL_ASSERT(zero_dim_univ_p != 0);
01023   delete zero_dim_univ_p;
01024   zero_dim_univ_p = 0;
01025 }
01026 
01027 bool
01028 PPL::Generator_System::OK() const {
01029   // A Generator_System must be a valid Linear_System; do not check for
01030   // strong normalization, since this will be done when
01031   // checking each individual generator.
01032   if (!Linear_System::OK(false))
01033     return false;
01034 
01035   // Checking each generator in the system.
01036   const Generator_System& x = *this;
01037   for (dimension_type i = num_rows(); i-- > 0; )
01038     if (!x[i].OK())
01039       return false;
01040 
01041   // All checks passed.
01042   return true;
01043 }
01044 
01046 std::ostream&
01047 PPL::IO_Operators::operator<<(std::ostream& s, const Generator_System& gs) {
01048   Generator_System::const_iterator i = gs.begin();
01049   const Generator_System::const_iterator gs_end = gs.end();
01050   if (i == gs_end)
01051     return s << "false";
01052   while (true) {
01053     s << *i++;
01054     if (i == gs_end)
01055       return s;
01056     s << ", ";
01057   }
01058 }