PPL  0.12.1
Grid_public.cc
Go to the documentation of this file.
00001 /* Grid class implementation (non-inline public functions).
00002    Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
00003    Copyright (C) 2010-2012 BUGSENG srl (http://bugseng.com)
00004 
00005 This file is part of the Parma Polyhedra Library (PPL).
00006 
00007 The PPL is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 The PPL is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with this program; if not, write to the Free Software Foundation,
00019 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
00020 
00021 For the most up-to-date information see the Parma Polyhedra Library
00022 site: http://bugseng.com/products/ppl/ . */
00023 
00024 #include "ppl-config.h"
00025 #include "Grid.defs.hh"
00026 #include "Topology.types.hh"
00027 #include "Scalar_Products.defs.hh"
00028 #include "Polyhedron.defs.hh"
00029 #include "assert.hh"
00030 #include <iostream>
00031 
00032 namespace PPL = Parma_Polyhedra_Library;
00033 
00034 // TODO: In the Grid constructors adapt and use the given system if it
00035 //       is modifiable, instead of using a copy.
00036 
00037 PPL::Grid::Grid(const Grid& y, Complexity_Class)
00038   : con_sys(),
00039     gen_sys(),
00040     status(y.status),
00041     space_dim(y.space_dim),
00042     dim_kinds(y.dim_kinds) {
00043   if (space_dim == 0) {
00044     con_sys = y.con_sys;
00045     gen_sys = y.gen_sys;
00046   }
00047   else {
00048     if (y.congruences_are_up_to_date())
00049       con_sys = y.con_sys;
00050     else
00051       con_sys.increase_space_dimension(space_dim);
00052     if (y.generators_are_up_to_date())
00053       gen_sys = y.gen_sys;
00054     else
00055       gen_sys = Grid_Generator_System(y.space_dim);
00056   }
00057 }
00058 
00059 PPL::Grid::Grid(const Constraint_System& cs)
00060   : con_sys(check_space_dimension_overflow(cs.space_dimension(),
00061                                            max_space_dimension(),
00062                                            "PPL::Grid::",
00063                                            "Grid(cs)",
00064                                            "the space dimension of cs "
00065                                            "exceeds the maximum allowed "
00066                                            "space dimension")),
00067     gen_sys(cs.space_dimension()) {
00068   space_dim = cs.space_dimension();
00069 
00070   if (space_dim == 0) {
00071     // See if an inconsistent constraint has been passed.
00072     for (Constraint_System::const_iterator i = cs.begin(),
00073          cs_end = cs.end(); i != cs_end; ++i)
00074       if (i->is_inconsistent()) {
00075         // Inconsistent constraint found: the grid is empty.
00076         status.set_empty();
00077         // Insert the zero dim false congruence system into `con_sys'.
00078         // `gen_sys' is already in empty form.
00079         con_sys.insert(Congruence::zero_dim_false());
00080         PPL_ASSERT(OK());
00081         return;
00082       }
00083     set_zero_dim_univ();
00084     PPL_ASSERT(OK());
00085     return;
00086   }
00087 
00088   Congruence_System cgs;
00089   cgs.insert(0*Variable(space_dim - 1) %= 1);
00090   for (Constraint_System::const_iterator i = cs.begin(),
00091          cs_end = cs.end(); i != cs_end; ++i)
00092     if (i->is_equality())
00093       cgs.insert(*i);
00094     else
00095       throw_invalid_constraints("Grid(cs)", "cs");
00096   construct(cgs);
00097 }
00098 
00099 PPL::Grid::Grid(Constraint_System& cs, Recycle_Input)
00100   : con_sys(check_space_dimension_overflow(cs.space_dimension(),
00101                                            max_space_dimension(),
00102                                            "PPL::Grid::",
00103                                            "Grid(cs, recycle)",
00104                                            "the space dimension of cs "
00105                                            "exceeds the maximum allowed "
00106                                            "space dimension")),
00107     gen_sys(cs.space_dimension()) {
00108   space_dim = cs.space_dimension();
00109 
00110   if (space_dim == 0) {
00111     // See if an inconsistent constraint has been passed.
00112     for (Constraint_System::const_iterator i = cs.begin(),
00113          cs_end = cs.end(); i != cs_end; ++i)
00114       if (i->is_inconsistent()) {
00115         // Inconsistent constraint found: the grid is empty.
00116         status.set_empty();
00117         // Insert the zero dim false congruence system into `con_sys'.
00118         // `gen_sys' is already in empty form.
00119         con_sys.insert(Congruence::zero_dim_false());
00120         PPL_ASSERT(OK());
00121         return;
00122       }
00123     set_zero_dim_univ();
00124     PPL_ASSERT(OK());
00125     return;
00126   }
00127 
00128   Congruence_System cgs;
00129   cgs.insert(0*Variable(space_dim - 1) %= 1);
00130   for (Constraint_System::const_iterator i = cs.begin(),
00131          cs_end = cs.end(); i != cs_end; ++i)
00132     if (i->is_equality())
00133       cgs.insert(*i);
00134     else
00135       throw_invalid_constraint("Grid(cs)", "cs");
00136   construct(cgs);
00137 }
00138 
00139 PPL::Grid::Grid(const Polyhedron& ph,
00140                 Complexity_Class complexity)
00141   : con_sys(check_space_dimension_overflow(ph.space_dimension(),
00142                                            max_space_dimension(),
00143                                            "PPL::Grid::",
00144                                            "Grid(ph)",
00145                                            "the space dimension of ph "
00146                                            "exceeds the maximum allowed "
00147                                            "space dimension")),
00148     gen_sys(ph.space_dimension()) {
00149   space_dim = ph.space_dimension();
00150 
00151   // A zero-dim polyhedron causes no complexity problems.
00152   if (space_dim == 0) {
00153     if (ph.is_empty())
00154       set_empty();
00155     else
00156       set_zero_dim_univ();
00157     return;
00158   }
00159 
00160   // A polyhedron known to be empty causes no complexity problems.
00161   if (ph.marked_empty()) {
00162     set_empty();
00163     return;
00164   }
00165 
00166   bool use_constraints = ph.constraints_are_minimized()
00167     || !ph.generators_are_up_to_date();
00168 
00169   // Minimize the constraint description if it is needed and
00170   // the complexity allows it.
00171   if (use_constraints && complexity == ANY_COMPLEXITY)
00172     if (!ph.minimize()) {
00173       set_empty();
00174       return;
00175     }
00176 
00177   if (use_constraints) {
00178     // Only the equality constraints need be used.
00179     PPL_ASSERT(ph.constraints_are_up_to_date());
00180     const Constraint_System& cs = ph.constraints();
00181     Congruence_System cgs;
00182     cgs.insert(0*Variable(space_dim - 1) %= 1);
00183     for (Constraint_System::const_iterator i = cs.begin(),
00184            cs_end = cs.end(); i != cs_end; ++i)
00185       if (i->is_equality())
00186         cgs.insert(*i);
00187     construct(cgs);
00188   }
00189   else {
00190     // First find a point or closure point and convert it to a
00191     // grid point and add to the (initially empty) set of grid generators.
00192     PPL_ASSERT(ph.generators_are_up_to_date());
00193     const Generator_System& gs = ph.generators();
00194     Grid_Generator_System ggs(space_dim);
00195     Linear_Expression point_expr;
00196     PPL_DIRTY_TEMP_COEFFICIENT(point_divisor);
00197     for (Generator_System::const_iterator g = gs.begin(),
00198            gs_end = gs.end(); g != gs_end; ++g) {
00199       if (g->is_point() || g->is_closure_point()) {
00200         for (dimension_type i = space_dim; i-- > 0; ) {
00201           const Variable v(i);
00202           point_expr += g->coefficient(v) * v;
00203           point_divisor = g->divisor();
00204         }
00205         ggs.insert(grid_point(point_expr, point_divisor));
00206         break;
00207       }
00208     }
00209     // Add grid lines for all the other generators.
00210     // If the polyhedron's generator is a (closure) point, the grid line must
00211     // have the direction given by a line that joins the grid point already
00212     // inserted and the new point.
00213     PPL_DIRTY_TEMP_COEFFICIENT(coeff);
00214     PPL_DIRTY_TEMP_COEFFICIENT(g_divisor);
00215     for (Generator_System::const_iterator g = gs.begin(),
00216            gs_end = gs.end(); g != gs_end; ++g) {
00217       Linear_Expression e;
00218       if (g->is_point() || g->is_closure_point()) {
00219         g_divisor = g->divisor();
00220         for (dimension_type i = space_dim; i-- > 0; ) {
00221           const Variable v(i);
00222           coeff = point_expr.coefficient(v) * g_divisor;
00223           coeff -= g->coefficient(v) * point_divisor;
00224           e += coeff * v;
00225         }
00226         if (e.all_homogeneous_terms_are_zero())
00227           continue;
00228       }
00229       else
00230         for (dimension_type i = space_dim; i-- > 0; ) {
00231           const Variable v(i);
00232           e += g->coefficient(v) * v;
00233         }
00234       ggs.insert(grid_line(e));
00235     }
00236     construct(ggs);
00237   }
00238   PPL_ASSERT(OK());
00239 }
00240 
00241 PPL::Grid&
00242 PPL::Grid::operator=(const Grid& y) {
00243   space_dim = y.space_dim;
00244   dim_kinds = y.dim_kinds;
00245   if (y.marked_empty())
00246     set_empty();
00247   else if (space_dim == 0)
00248     set_zero_dim_univ();
00249   else {
00250     status = y.status;
00251     if (y.congruences_are_up_to_date())
00252       con_sys = y.con_sys;
00253     if (y.generators_are_up_to_date())
00254       gen_sys = y.gen_sys;
00255   }
00256   return *this;
00257 }
00258 
00259 PPL::dimension_type
00260 PPL::Grid::affine_dimension() const {
00261   if (space_dim == 0 || is_empty())
00262     return 0;
00263 
00264   if (generators_are_up_to_date()) {
00265     if (generators_are_minimized())
00266       return gen_sys.num_rows() - 1;
00267     if (!(congruences_are_up_to_date() && congruences_are_minimized()))
00268       return minimized_grid_generators().num_rows() - 1;
00269   }
00270   else
00271     minimized_congruences();
00272   PPL_ASSERT(congruences_are_minimized());
00273   dimension_type d = space_dim;
00274   for (dimension_type i = con_sys.num_rows(); i-- > 0; )
00275     if (con_sys[i].is_equality())
00276       --d;
00277   return d;
00278 }
00279 
00280 const PPL::Congruence_System&
00281 PPL::Grid::congruences() const {
00282   if (marked_empty())
00283     return con_sys;
00284 
00285   if (space_dim == 0) {
00286     // Zero-dimensional universe.
00287     PPL_ASSERT(con_sys.num_rows() == 0 && con_sys.num_columns() == 2);
00288     return con_sys;
00289   }
00290 
00291   if (!congruences_are_up_to_date())
00292     update_congruences();
00293 
00294   return con_sys;
00295 }
00296 
00297 const PPL::Congruence_System&
00298 PPL::Grid::minimized_congruences() const {
00299   if (congruences_are_up_to_date() && !congruences_are_minimized()) {
00300     // Minimize the congruences.
00301     Grid& gr = const_cast<Grid&>(*this);
00302     if (gr.simplify(gr.con_sys, gr.dim_kinds))
00303       gr.set_empty();
00304     else
00305       gr.set_congruences_minimized();
00306   }
00307   return congruences();
00308 }
00309 
00310 const PPL::Grid_Generator_System&
00311 PPL::Grid::grid_generators() const {
00312   if (space_dim == 0) {
00313     PPL_ASSERT(gen_sys.space_dimension() == 0
00314                && gen_sys.num_rows() == (marked_empty() ? 0U : 1U));
00315     return gen_sys;
00316   }
00317 
00318   if (marked_empty()) {
00319     PPL_ASSERT(gen_sys.has_no_rows());
00320     return gen_sys;
00321   }
00322 
00323   if (!generators_are_up_to_date() && !update_generators()) {
00324     // Updating found the grid empty.
00325     const_cast<Grid&>(*this).set_empty();
00326     return gen_sys;
00327   }
00328 
00329   return gen_sys;
00330 }
00331 
00332 const PPL::Grid_Generator_System&
00333 PPL::Grid::minimized_grid_generators() const {
00334   if (space_dim == 0) {
00335     PPL_ASSERT(gen_sys.space_dimension() == 0
00336                && gen_sys.num_rows() == (marked_empty() ? 0U : 1U));
00337     return gen_sys;
00338   }
00339 
00340   if (marked_empty()) {
00341     PPL_ASSERT(gen_sys.has_no_rows());
00342     return gen_sys;
00343   }
00344 
00345   if (generators_are_up_to_date()) {
00346     if (!generators_are_minimized()) {
00347       // Minimize the generators.
00348       Grid& gr = const_cast<Grid&>(*this);
00349       gr.simplify(gr.gen_sys, gr.dim_kinds);
00350       gr.set_generators_minimized();
00351     }
00352   }
00353   else if (!update_generators()) {
00354     // Updating found the grid empty.
00355     const_cast<Grid&>(*this).set_empty();
00356     return gen_sys;
00357   }
00358 
00359   return gen_sys;
00360 }
00361 
00362 PPL::Poly_Con_Relation
00363 PPL::Grid::relation_with(const Congruence& cg) const {
00364   // Dimension-compatibility check.
00365   if (space_dim < cg.space_dimension())
00366     throw_dimension_incompatible("relation_with(cg)", "cg", cg);
00367 
00368   if (marked_empty())
00369     return Poly_Con_Relation::saturates()
00370       && Poly_Con_Relation::is_included()
00371       && Poly_Con_Relation::is_disjoint();
00372 
00373   if (space_dim == 0) {
00374     if (cg.is_inconsistent())
00375       return Poly_Con_Relation::is_disjoint();
00376     else if (cg.is_equality())
00377       return Poly_Con_Relation::saturates()
00378         && Poly_Con_Relation::is_included();
00379     else if (cg.inhomogeneous_term() % cg.modulus() == 0)
00380       return Poly_Con_Relation::saturates()
00381         && Poly_Con_Relation::is_included();
00382   }
00383 
00384   if (!generators_are_up_to_date() && !update_generators())
00385     // Updating found the grid empty.
00386     return Poly_Con_Relation::saturates()
00387       && Poly_Con_Relation::is_included()
00388       && Poly_Con_Relation::is_disjoint();
00389 
00390   // Return one of the relations
00391   // 'strictly_intersects'   a strict subset of the grid points satisfy cg
00392   // 'is_included'           every grid point satisfies cg
00393   // 'is_disjoint'           cg and the grid occupy separate spaces.
00394 
00395   // There is always a point.
00396 
00397   // Scalar product of the congruence and the first point that
00398   // satisfies the congruence.
00399   PPL_DIRTY_TEMP_COEFFICIENT(point_sp);
00400   point_sp = 0;
00401 
00402   PPL_DIRTY_TEMP_COEFFICIENT(div);
00403   div = cg.modulus();
00404 
00405   PPL_DIRTY_TEMP_COEFFICIENT(sp);
00406 
00407   bool known_to_intersect = false;
00408 
00409   for (Grid_Generator_System::const_iterator i = gen_sys.begin(),
00410          i_end = gen_sys.end(); i != i_end; ++i) {
00411     const Grid_Generator& g = *i;
00412     Scalar_Products::assign(sp, cg, g);
00413 
00414     switch (g.type()) {
00415 
00416     case Grid_Generator::POINT:
00417       if (cg.is_proper_congruence())
00418         sp %= div;
00419       if (sp == 0) {
00420         // The point satisfies the congruence.
00421         if (point_sp == 0)
00422           // Any previous points satisfied the congruence.
00423           known_to_intersect = true;
00424         else
00425           return Poly_Con_Relation::strictly_intersects();
00426       }
00427       else {
00428         if (point_sp == 0) {
00429           if (known_to_intersect)
00430             return Poly_Con_Relation::strictly_intersects();
00431           // Assign `sp' to `point_sp' as `sp' is the scalar product
00432           // of cg and a point g and is non-zero.
00433           point_sp = sp;
00434         }
00435         else {
00436           // A previously considered point p failed to satisfy cg such that
00437           // `point_sp' = `scalar_prod(p, cg)'
00438           // so, if we consider the parameter g-p instead of g, we have
00439           // scalar_prod(g-p, cg) = scalar_prod(g, cg) - scalar_prod(p, cg)
00440           //                      = sp - point_sp
00441           sp -= point_sp;
00442 
00443           if (sp != 0) {
00444             // Find the GCD between sp and the previous GCD.
00445             gcd_assign(div, div, sp);
00446             if (point_sp % div == 0)
00447               // There is a point in the grid satisfying cg.
00448               return Poly_Con_Relation::strictly_intersects();
00449           }
00450         }
00451       }
00452       break;
00453 
00454     case Grid_Generator::PARAMETER:
00455       if (cg.is_proper_congruence())
00456         sp %= (div * g.divisor());
00457       if (sp == 0)
00458         // Parameter g satisfies the cg so the relation depends
00459         // entirely on the other generators.
00460         break;
00461       if (known_to_intersect)
00462         // At least one point satisfies cg.  However, the sum of such
00463         // a point and the parameter g fails to satisfy cg (due to g).
00464         return Poly_Con_Relation::strictly_intersects();
00465       // Find the GCD between sp and the previous GCD.
00466       gcd_assign(div, div, sp);
00467       if (point_sp != 0) {
00468         // At least one of any previously encountered points fails to
00469         // satisfy cg.
00470         if (point_sp % div == 0)
00471           // There is also a grid point that satisfies cg.
00472           return Poly_Con_Relation::strictly_intersects();
00473       }
00474       break;
00475 
00476     case Grid_Generator::LINE:
00477       if (sp == 0)
00478         // Line g satisfies the cg so the relation depends entirely on
00479         // the other generators.
00480         break;
00481 
00482       // Line g intersects the congruence.
00483       //
00484       // There is a point p in the grid.  Suppose <p*cg> = p_sp.  Then
00485       // (-p_sp/sp)*g + p is a point that satisfies cg: <((-p_sp/sp)*g
00486       // + p).cg> = -(p_sp/sp)*sp + p_sp) = 0.  If p does not satisfy
00487       // `cg' and hence is not in the grid defined by `cg', the grid
00488       // `*this' strictly intersects the `cg' grid.  On the other
00489       // hand, if `p' is in the grid defined by `cg' so that p_sp = 0,
00490       // then <p+g.cg> = p_sp + sp != 0; thus `p+g' is a point in
00491       // *this that does not satisfy `cg' and hence `p+g' is a point
00492       // in *this not in the grid defined by `cg'; therefore `*this'
00493       // strictly intersects the `cg' grid.
00494       return Poly_Con_Relation::strictly_intersects();
00495     }
00496   }
00497 
00498   if (point_sp == 0) {
00499     if (cg.is_equality())
00500       // Every generator satisfied the cg.
00501       return Poly_Con_Relation::is_included()
00502         && Poly_Con_Relation::saturates();
00503     else
00504       // Every generator satisfied the cg.
00505       return Poly_Con_Relation::is_included();
00506   }
00507 
00508   PPL_ASSERT(!known_to_intersect);
00509   return Poly_Con_Relation::is_disjoint();
00510 }
00511 
00512 PPL::Poly_Gen_Relation
00513 PPL::Grid::relation_with(const Grid_Generator& g) const {
00514   // Dimension-compatibility check.
00515   if (space_dim < g.space_dimension())
00516     throw_dimension_incompatible("relation_with(g)", "g", g);
00517 
00518   // The empty grid cannot subsume a generator.
00519   if (marked_empty())
00520     return Poly_Gen_Relation::nothing();
00521 
00522   // A universe grid in a zero-dimensional space subsumes all the
00523   // generators of a zero-dimensional space.
00524   if (space_dim == 0)
00525     return Poly_Gen_Relation::subsumes();
00526 
00527   if (!congruences_are_up_to_date())
00528     update_congruences();
00529 
00530   return
00531     con_sys.satisfies_all_congruences(g)
00532     ? Poly_Gen_Relation::subsumes()
00533     : Poly_Gen_Relation::nothing();
00534 }
00535 
00536 PPL::Poly_Gen_Relation
00537 PPL::Grid::relation_with(const Generator& g) const {
00538   dimension_type g_space_dim = g.space_dimension();
00539 
00540   // Dimension-compatibility check.
00541   if (space_dim < g_space_dim)
00542     throw_dimension_incompatible("relation_with(g)", "g", g);
00543 
00544   // The empty grid cannot subsume a generator.
00545   if (marked_empty())
00546     return Poly_Gen_Relation::nothing();
00547 
00548   // A universe grid in a zero-dimensional space subsumes all the
00549   // generators of a zero-dimensional space.
00550   if (space_dim == 0)
00551     return Poly_Gen_Relation::subsumes();
00552 
00553   if (!congruences_are_up_to_date())
00554     update_congruences();
00555 
00556   Linear_Expression expr;
00557   for (dimension_type i = g_space_dim; i-- > 0; ) {
00558     const Variable v(i);
00559     expr += g.coefficient(v) * v;
00560   }
00561   Grid_Generator gg(grid_point());
00562   if (g.is_point() || g.is_closure_point())
00563     // Points and closure points are converted to grid points.
00564     gg = grid_point(expr, g.divisor());
00565   else
00566     // The generator is a ray or line.
00567     // In both cases, we convert it to a grid line
00568     gg = grid_line(expr);
00569 
00570   return
00571     con_sys.satisfies_all_congruences(gg)
00572     ? Poly_Gen_Relation::subsumes()
00573     : Poly_Gen_Relation::nothing();
00574 }
00575 
00576 PPL::Poly_Con_Relation
00577 PPL::Grid::relation_with(const Constraint& c) const {
00578   // Dimension-compatibility check.
00579   if (space_dim < c.space_dimension())
00580     throw_dimension_incompatible("relation_with(c)", "c", c);
00581 
00582   if (c.is_equality()) {
00583     Congruence cg(c);
00584     return relation_with(cg);
00585   }
00586 
00587   if (marked_empty())
00588     return Poly_Con_Relation::saturates()
00589       &&  Poly_Con_Relation::is_included()
00590       && Poly_Con_Relation::is_disjoint();
00591 
00592   if (space_dim == 0) {
00593     if (c.is_inconsistent())
00594       if (c.is_strict_inequality() && c.inhomogeneous_term() == 0)
00595         // The constraint 0 > 0 implicitly defines the hyperplane 0 = 0;
00596         // thus, the zero-dimensional point also saturates it.
00597         return Poly_Con_Relation::saturates()
00598           && Poly_Con_Relation::is_disjoint();
00599       else
00600         return Poly_Con_Relation::is_disjoint();
00601     else if (c.inhomogeneous_term() == 0)
00602       return Poly_Con_Relation::saturates()
00603         && Poly_Con_Relation::is_included();
00604     else
00605       // The zero-dimensional point saturates
00606       // neither the positivity constraint 1 >= 0,
00607       // nor the strict positivity constraint 1 > 0.
00608       return Poly_Con_Relation::is_included();
00609   }
00610 
00611   if (!generators_are_up_to_date() && !update_generators())
00612     // Updating found the grid empty.
00613     return Poly_Con_Relation::saturates()
00614       && Poly_Con_Relation::is_included()
00615       && Poly_Con_Relation::is_disjoint();
00616 
00617   // Return one of the relations
00618   // 'strictly_intersects'   a strict subset of the grid points satisfy c
00619   // 'is_included'           every grid point satisfies c
00620   // 'is_disjoint'           c and the grid occupy separate spaces.
00621 
00622   // There is always a point.
00623 
00624   bool point_is_included = false;
00625   bool point_saturates = false;
00626   const Grid_Generator* first_point = 0;
00627 
00628   for (Grid_Generator_System::const_iterator i = gen_sys.begin(),
00629          i_end = gen_sys.end(); i != i_end; ++i) {
00630     const Grid_Generator& g = *i;
00631     switch (g.type()) {
00632     case Grid_Generator::POINT:
00633       {
00634         if (first_point == 0) {
00635           first_point = &g;
00636           const int sign = Scalar_Products::sign(c, g);
00637           if (sign == 0)
00638             point_saturates = !c.is_strict_inequality();
00639           else if (sign > 0)
00640             point_is_included = !c.is_equality();
00641           break;
00642         }
00643         // Not the first point: convert `g' to be a parameter
00644         // and fall through into the parameter case.
00645         Grid_Generator& gen = const_cast<Grid_Generator&>(g);
00646         const Grid_Generator& point = *first_point;
00647         const Coefficient& p_div = g[0];
00648         if (p_div != Coefficient_one()) {
00649           for (dimension_type j = gen.size() - 1; j-- > 1; )
00650             gen[j] *= p_div;
00651         }
00652         const Coefficient& g_div = gen[0];
00653         if (g_div == Coefficient_one()) {
00654           for (dimension_type j = gen.size() - 1; j-- > 1; )
00655             gen[j] -= point[j];
00656         }
00657         else {
00658           for (dimension_type j = gen.size() - 1; j-- > 1; )
00659             sub_mul_assign(gen[j], g_div, point[j]);
00660         }
00661         gen[0] *= p_div;
00662         gen.strong_normalize();
00663         gen.set_is_parameter();
00664         PPL_ASSERT(gen.OK());
00665       }
00666       // Intentionally fall through.
00667 
00668     case Grid_Generator::PARAMETER:
00669     case Grid_Generator::LINE:
00670       {
00671         const int sign = c.is_strict_inequality()
00672           ? Scalar_Products::reduced_sign(c, g)
00673           : Scalar_Products::sign(c, g);
00674         if (sign != 0)
00675           return Poly_Con_Relation::strictly_intersects();
00676       }
00677       break;
00678     } // switch
00679   }
00680 
00681   // If this program point is reached, then all lines and parameters
00682   // saturate the constraint. Hence, the result is determined by
00683   // the previosly computed relation with the point.
00684   if (point_saturates)
00685     return Poly_Con_Relation::saturates()
00686       && Poly_Con_Relation::is_included();
00687 
00688   if (point_is_included)
00689     return Poly_Con_Relation::is_included();
00690 
00691   return Poly_Con_Relation::is_disjoint();
00692 }
00693 
00694 bool
00695 PPL::Grid::is_empty() const {
00696   if (marked_empty())
00697     return true;
00698   // Try a fast-fail test: if generators are up-to-date then the
00699   // generator system (since it is well formed) contains a point.
00700   if (generators_are_up_to_date())
00701     return false;
00702   if (space_dim == 0)
00703     return false;
00704   if (congruences_are_minimized())
00705     // If the grid was empty it would be marked empty.
00706     return false;
00707   // Minimize the congruences to check if the grid is empty.
00708   Grid& gr = const_cast<Grid&>(*this);
00709   if (gr.simplify(gr.con_sys, gr.dim_kinds)) {
00710     gr.set_empty();
00711     return true;
00712   }
00713   gr.set_congruences_minimized();
00714   return false;
00715 }
00716 
00717 bool
00718 PPL::Grid::is_universe() const {
00719   if (marked_empty())
00720     return false;
00721 
00722   if (space_dim == 0)
00723     return true;
00724 
00725   if (congruences_are_up_to_date()) {
00726     if (congruences_are_minimized())
00727       // The minimized universe congruence system has only one row,
00728       // the integrality congruence.
00729       return con_sys.num_rows() == 1 && con_sys[0].is_tautological();
00730   }
00731   else {
00732     update_congruences();
00733     return con_sys.num_rows() == 1 && con_sys[0].is_tautological();
00734   }
00735 
00736   // Test con_sys's inclusion in a universe generator system.
00737 
00738   // The zero dimension cases are handled above.
00739   Variable var(space_dim - 1);
00740   for (dimension_type i = space_dim; i-- > 0; )
00741     if (!con_sys.satisfies_all_congruences(grid_line(Variable(i) + var)))
00742       return false;
00743   PPL_ASSERT(con_sys.satisfies_all_congruences(grid_point(0*var)));
00744   return true;
00745 }
00746 
00747 bool
00748 PPL::Grid::is_bounded() const {
00749   // A zero-dimensional or empty grid is bounded.
00750   if (space_dim == 0
00751       || marked_empty()
00752       || (!generators_are_up_to_date() && !update_generators()))
00753     return true;
00754 
00755   // TODO: Consider using con_sys when gen_sys is out of date.
00756 
00757   if (gen_sys.num_rows() > 1) {
00758     // Check if all generators are the same point.
00759     const Grid_Generator& first_point = gen_sys[0];
00760     if (first_point.is_line_or_parameter())
00761       return false;
00762     for (dimension_type row = gen_sys.num_rows(); row-- > 0; ) {
00763       const Grid_Generator& gen = gen_sys[row];
00764       if (gen.is_line_or_parameter() || gen != first_point)
00765         return false;
00766     }
00767   }
00768   return true;
00769 }
00770 
00771 bool
00772 PPL::Grid::is_discrete() const {
00773   // A zero-dimensional or empty grid is discrete.
00774   if (space_dim == 0
00775       || marked_empty()
00776       || (!generators_are_up_to_date() && !update_generators()))
00777     return true;
00778 
00779   // Search for lines in the generator system.
00780   for (dimension_type row = gen_sys.num_rows(); row-- > 1; )
00781     if (gen_sys[row].is_line())
00782       return false;
00783 
00784   // The system of generators is composed only by
00785   // points and parameters: the grid is discrete.
00786   return true;
00787 }
00788 
00789 bool
00790 PPL::Grid::is_topologically_closed() const {
00791   return true;
00792 }
00793 
00794 bool
00795 PPL::Grid::contains_integer_point() const {
00796   // Empty grids have no points.
00797   if (marked_empty())
00798     return false;
00799 
00800   // A zero-dimensional, universe grid has, by convention, an
00801   // integer point.
00802   if (space_dim == 0)
00803     return true;
00804 
00805   // A grid has an integer point if its intersection with the integer
00806   // grid is non-empty.
00807   Congruence_System cgs;
00808   for (dimension_type var_index = space_dim; var_index-- > 0; )
00809     cgs.insert(Variable(var_index) %= 0);
00810 
00811   Grid gr = *this;
00812   gr.add_recycled_congruences(cgs);
00813   return !gr.is_empty();
00814 }
00815 
00816 bool
00817 PPL::Grid::constrains(const Variable var) const {
00818   // `var' should be one of the dimensions of the grid.
00819   const dimension_type var_space_dim = var.space_dimension();
00820   if (space_dim < var_space_dim)
00821     throw_dimension_incompatible("constrains(v)", "v", var);
00822 
00823   // An empty grid constrains all variables.
00824   if (marked_empty())
00825     return true;
00826 
00827   if (generators_are_up_to_date()) {
00828     // Since generators are up-to-date, the generator system (since it is
00829     // well formed) contains a point.  Hence the grid is not empty.
00830     if (congruences_are_up_to_date())
00831       // Here a variable is constrained if and only if it is
00832       // syntactically constrained.
00833       goto syntactic_check;
00834 
00835     if (generators_are_minimized()) {
00836       // Try a quick, incomplete check for the universe grid:
00837       // a universe grid constrains no variable.
00838       // Count the number of lines (they are linearly independent).
00839       dimension_type num_lines = 0;
00840       for (dimension_type i = gen_sys.num_rows(); i-- > 0; )
00841         if (gen_sys[i].is_line())
00842           ++num_lines;
00843 
00844       if (num_lines == space_dim)
00845         return false;
00846     }
00847 
00848     // Scan generators: perhaps we will find line(var).
00849     const dimension_type var_id = var.id();
00850     for (dimension_type i = gen_sys.num_rows(); i-- > 0; ) {
00851       const Grid_Generator& g_i = gen_sys[i];
00852       if (g_i.is_line()) {
00853         if (sgn(g_i.coefficient(var)) != 0) {
00854           for (dimension_type j = 0; j < space_dim; ++j)
00855             if (g_i.coefficient(Variable(j)) != 0 && j != var_id)
00856               goto next;
00857           return true;
00858         }
00859       }
00860     next:
00861       ;
00862     }
00863 
00864     // We are still here: at least we know that the grid is not empty.
00865     update_congruences();
00866     goto syntactic_check;
00867   }
00868 
00869   // We must minimize to detect emptiness and obtain constraints.
00870   if (!minimize())
00871     return true;
00872 
00873  syntactic_check:
00874   for (dimension_type i = con_sys.num_rows(); i-- > 0; )
00875     if (con_sys[i].coefficient(var) != 0)
00876       return true;
00877   return false;
00878 }
00879 
00880 bool
00881 PPL::Grid::OK(bool check_not_empty) const {
00882 #ifndef NDEBUG
00883   using std::endl;
00884   using std::cerr;
00885 #endif
00886 
00887   // Check whether the status information is legal.
00888   if (!status.OK())
00889     goto fail;
00890 
00891   if (marked_empty()) {
00892     if (check_not_empty) {
00893       // The caller does not want the grid to be empty.
00894 #ifndef NDEBUG
00895       cerr << "Empty grid!" << endl;
00896 #endif
00897       goto fail;
00898     }
00899 
00900     if (con_sys.space_dimension() != space_dim) {
00901 #ifndef NDEBUG
00902       cerr << "The grid is in a space of dimension " << space_dim
00903            << " while the system of congruences is in a space of dimension "
00904            << con_sys.space_dimension()
00905            << endl;
00906 #endif
00907       goto fail;
00908     }
00909     return true;
00910   }
00911 
00912   // A zero-dimensional universe grid is legal only if the system of
00913   // congruences `con_sys' is empty, and the generator system contains
00914   // one point.
00915   if (space_dim == 0) {
00916     if (con_sys.has_no_rows())
00917       if (gen_sys.num_rows() == 1 && gen_sys[0].is_point())
00918         return true;
00919 #ifndef NDEBUG
00920     cerr << "Zero-dimensional grid should have an empty congruence" << endl
00921          << "system and a generator system of a single point." << endl;
00922 #endif
00923     goto fail;
00924   }
00925 
00926   // A grid is defined by a system of congruences or a system of
00927   // generators.  At least one of them must be up to date.
00928   if (!congruences_are_up_to_date() && !generators_are_up_to_date()) {
00929 #ifndef NDEBUG
00930     cerr << "Grid not empty, not zero-dimensional" << endl
00931          << "and with neither congruences nor generators up-to-date!"
00932          << endl;
00933 #endif
00934     goto fail;
00935   }
00936 
00937   {
00938     // The expected number of columns in the congruence and generator
00939     // systems, if they are not empty.
00940     const dimension_type num_columns = space_dim + 1;
00941 
00942     // Here we check if the size of the matrices is consistent.
00943     // Let us suppose that all the matrices are up-to-date; this means:
00944     // `con_sys' : number of congruences x poly_num_columns
00945     // `gen_sys' : number of generators  x poly_num_columns
00946     if (congruences_are_up_to_date())
00947       if (con_sys.num_columns() != num_columns + 1 /* moduli */) {
00948 #ifndef NDEBUG
00949         cerr << "Incompatible size! (con_sys and space_dim)"
00950              << endl;
00951 #endif
00952         goto fail;
00953       }
00954 
00955     if (generators_are_up_to_date()) {
00956       if (gen_sys.space_dimension() + 1 != num_columns) {
00957 #ifndef NDEBUG
00958         cerr << "Incompatible size! (gen_sys and space_dim)"
00959              << endl;
00960 #endif
00961         goto fail;
00962       }
00963 
00964       // Check if the system of generators is well-formed.
00965       if (!gen_sys.OK())
00966         goto fail;
00967 
00968       // Check each generator in the system.
00969       for (dimension_type i = gen_sys.num_rows(); i-- > 0; ) {
00970         const Grid_Generator& g = gen_sys[i];
00971 
00972         if (g.size() < 1) {
00973 #ifndef NDEBUG
00974           cerr << "Parameter should have coefficients." << endl;
00975 #endif
00976           goto fail;
00977         }
00978       }
00979 
00980       // A non-empty system of generators describing a grid is valid
00981       // if and only if it contains a point.
00982       if (!gen_sys.has_no_rows() && !gen_sys.has_points()) {
00983 #ifndef NDEBUG
00984         cerr << "Non-empty generator system declared up-to-date "
00985              << "has no points!"
00986              << endl;
00987 #endif
00988         goto fail;
00989       }
00990 
00991       if (generators_are_minimized()) {
00992         Grid_Generator_System gs = gen_sys;
00993 
00994         if (dim_kinds.size() != num_columns) {
00995 #ifndef NDEBUG
00996           cerr << "Size of dim_kinds should equal the number of columns."
00997                << endl;
00998 #endif
00999           goto fail;
01000         }
01001 
01002         if (!upper_triangular(gs, dim_kinds)) {
01003 #ifndef NDEBUG
01004           cerr << "Reduced generators should be upper triangular."
01005                << endl;
01006 #endif
01007           goto fail;
01008         }
01009 
01010         // Check that dim_kinds corresponds to the row kinds in gen_sys.
01011         for (dimension_type dim = space_dim,
01012                row = gen_sys.num_rows(); dim > 0; --dim) {
01013           if (dim_kinds[dim] == GEN_VIRTUAL)
01014             goto ok;
01015           if (gen_sys[--row].is_parameter_or_point()
01016               && dim_kinds[dim] == PARAMETER)
01017             goto ok;
01018           PPL_ASSERT(gen_sys[row].is_line());
01019           if (dim_kinds[dim] == LINE)
01020             goto ok;
01021 #ifndef NDEBUG
01022           cerr << "Kinds in dim_kinds should match those in gen_sys."
01023                << endl;
01024 #endif
01025           goto fail;
01026         ok:
01027           PPL_ASSERT(row <= dim);
01028         }
01029 
01030         // A reduced generator system must be the same as a temporary
01031         // reduced copy.
01032         Dimension_Kinds dim_kinds_copy = dim_kinds;
01033         // `gs' is minimized and marked_empty returned false, so `gs'
01034         // should contain rows.
01035         PPL_ASSERT(!gs.has_no_rows());
01036         simplify(gs, dim_kinds_copy);
01037         // gs contained rows before being reduced, so it should
01038         // contain at least a single point afterward.
01039         PPL_ASSERT(!gs.has_no_rows());
01040         for (dimension_type row = gen_sys.num_rows(); row-- > 0; ) {
01041           Grid_Generator& g = gs[row];
01042           const Grid_Generator& g_copy = gen_sys[row];
01043           if (g.is_equal_to(g_copy))
01044             continue;
01045 #ifndef NDEBUG
01046           cerr << "Generators are declared minimized,"
01047             " but they change under reduction.\n"
01048                << "Here is the generator system:\n";
01049           gen_sys.ascii_dump(cerr);
01050           cerr << "and here is the minimized form of the temporary copy:\n";
01051           gs.ascii_dump(cerr);
01052 #endif
01053           goto fail;
01054         }
01055       }
01056 
01057     } // if (congruences_are_up_to_date())
01058   }
01059 
01060   if (congruences_are_up_to_date()) {
01061     // Check if the system of congruences is well-formed.
01062     if (!con_sys.OK())
01063       goto fail;
01064 
01065     Grid tmp_gr = *this;
01066     // Make a copy here, before changing tmp_gr, to check later.
01067     const Congruence_System cs_copy = tmp_gr.con_sys;
01068 
01069     // Clear the generators in tmp_gr.
01070     Grid_Generator_System gs(space_dim);
01071     tmp_gr.gen_sys.m_swap(gs);
01072     tmp_gr.clear_generators_up_to_date();
01073 
01074     if (!tmp_gr.update_generators()) {
01075       if (check_not_empty) {
01076         // Want to know the satisfiability of the congruences.
01077 #ifndef NDEBUG
01078         cerr << "Unsatisfiable system of congruences!"
01079              << endl;
01080 #endif
01081         goto fail;
01082       }
01083       // The grid is empty, all checks are done.
01084       return true;
01085     }
01086 
01087     if (congruences_are_minimized()) {
01088       // A reduced congruence system must be lower triangular.
01089       if (!lower_triangular(con_sys, dim_kinds)) {
01090 #ifndef NDEBUG
01091         cerr << "Reduced congruences should be lower triangular." << endl;
01092 #endif
01093         goto fail;
01094       }
01095 
01096       // If the congruences are minimized, all the elements in the
01097       // congruence system must be the same as those in the temporary,
01098       // minimized system `cs_copy'.
01099       if (!con_sys.is_equal_to(cs_copy)) {
01100 #ifndef NDEBUG
01101         cerr << "Congruences are declared minimized, but they change under reduction!"
01102              << endl
01103              << "Here is the minimized form of the congruence system:"
01104              << endl;
01105         cs_copy.ascii_dump(cerr);
01106         cerr << endl;
01107 #endif
01108         goto fail;
01109       }
01110 
01111       if (dim_kinds.size() != con_sys.num_columns() - 1 /* modulus */) {
01112 #ifndef NDEBUG
01113         cerr << "Size of dim_kinds should equal the number of columns."
01114              << endl;
01115 #endif
01116         goto fail;
01117       }
01118 
01119       // Check that dim_kinds corresponds to the row kinds in con_sys.
01120       for (dimension_type dim = space_dim, row = 0; dim > 0; --dim) {
01121         if (dim_kinds[dim] == CON_VIRTUAL)
01122             continue;
01123         if (con_sys[row++].is_proper_congruence()
01124             && dim_kinds[dim] == PROPER_CONGRUENCE)
01125           continue;
01126         PPL_ASSERT(con_sys[row-1].is_equality());
01127         if (dim_kinds[dim] == EQUALITY)
01128           continue;
01129 #ifndef NDEBUG
01130         cerr << "Kinds in dim_kinds should match those in con_sys." << endl;
01131 #endif
01132         goto fail;
01133       }
01134     }
01135   }
01136 
01137   return true;
01138 
01139  fail:
01140 #ifndef NDEBUG
01141   cerr << "Here is the grid under check:" << endl;
01142   ascii_dump(cerr);
01143 #endif
01144   return false;
01145 }
01146 
01147 void
01148 PPL::Grid::add_constraints(const Constraint_System& cs) {
01149   // The dimension of `cs' must be at most `space_dim'.
01150   if (space_dim < cs.space_dimension())
01151     throw_dimension_incompatible("add_constraints(cs)", "cs", cs);
01152   if (marked_empty())
01153     return;
01154 
01155   for (Constraint_System::const_iterator i = cs.begin(),
01156          cs_end = cs.end(); i != cs_end; ++i) {
01157     add_constraint_no_check(*i);
01158     if (marked_empty())
01159       return;
01160   }
01161 }
01162 
01163 void
01164 PPL::Grid::add_grid_generator(const Grid_Generator& g) {
01165   // The dimension of `g' must be at most space_dim.
01166   const dimension_type g_space_dim = g.space_dimension();
01167   if (space_dim < g_space_dim)
01168     throw_dimension_incompatible("add_grid_generator(g)", "g", g);
01169 
01170   // Deal with zero-dimension case first.
01171   if (space_dim == 0) {
01172     // Points and parameters are the only zero-dimension generators
01173     // that can be created.
01174     if (marked_empty()) {
01175       if (g.is_parameter())
01176         throw_invalid_generator("add_grid_generator(g)", "g");
01177       set_zero_dim_univ();
01178     }
01179     PPL_ASSERT(OK());
01180     return;
01181   }
01182 
01183   if (marked_empty()
01184       || (!generators_are_up_to_date() && !update_generators())) {
01185     // Here the grid is empty: the specification says we can only
01186     // insert a point.
01187     if (g.is_line_or_parameter())
01188       throw_invalid_generator("add_grid_generator(g)", "g");
01189     gen_sys.insert(g);
01190     clear_empty();
01191   }
01192   else {
01193     PPL_ASSERT(generators_are_up_to_date());
01194     gen_sys.insert(g);
01195     if (g.is_parameter_or_point())
01196       normalize_divisors(gen_sys);
01197   }
01198 
01199   // With the added generator, congruences are out of date.
01200   clear_congruences_up_to_date();
01201 
01202   clear_generators_minimized();
01203   set_generators_up_to_date();
01204   PPL_ASSERT(OK());
01205 }
01206 
01207 void
01208 PPL::Grid::add_recycled_congruences(Congruence_System& cgs) {
01209   // Dimension-compatibility check.
01210   const dimension_type cgs_space_dim = cgs.space_dimension();
01211   if (space_dim < cgs_space_dim)
01212     throw_dimension_incompatible("add_recycled_congruences(cgs)", "cgs", cgs);
01213 
01214   if (cgs.has_no_rows())
01215     return;
01216 
01217   if (marked_empty())
01218     return;
01219 
01220   if (space_dim == 0) {
01221     // In a 0-dimensional space the congruences are trivial (e.g., 0
01222     // == 0 or 1 %= 0) or false (e.g., 1 == 0).  In a system of
01223     // congruences `begin()' and `end()' are equal if and only if the
01224     // system contains only trivial congruences.
01225     if (cgs.begin() != cgs.end())
01226       // There is a congruence, it must be false, the grid becomes empty.
01227       set_empty();
01228     return;
01229   }
01230 
01231   // The congruences are required.
01232   if (!congruences_are_up_to_date())
01233     update_congruences();
01234 
01235   // Swap (instead of copying) the coefficients of `cgs' (which is
01236   // writable).
01237   con_sys.recycling_insert(cgs);
01238 
01239   // Congruences may not be minimized and generators are out of date.
01240   clear_congruences_minimized();
01241   clear_generators_up_to_date();
01242   // Note: the congruence system may have become unsatisfiable, thus
01243   // we do not check for satisfiability.
01244   PPL_ASSERT(OK());
01245 }
01246 
01247 void
01248 PPL::Grid::add_recycled_grid_generators(Grid_Generator_System& gs) {
01249   // Dimension-compatibility check.
01250   const dimension_type gs_space_dim = gs.space_dimension();
01251   if (space_dim < gs_space_dim)
01252     throw_dimension_incompatible("add_recycled_grid_generators(gs)", "gs", gs);
01253 
01254   // Adding no generators leaves the grid the same.
01255   if (gs.has_no_rows())
01256     return;
01257 
01258   // Adding valid generators to a zero-dimensional grid transforms it
01259   // to the zero-dimensional universe grid.
01260   if (space_dim == 0) {
01261     if (marked_empty())
01262       set_zero_dim_univ();
01263     else {
01264       PPL_ASSERT(gs.has_points());
01265     }
01266     PPL_ASSERT(OK(true));
01267     return;
01268   }
01269 
01270   if (!marked_empty()) {
01271     // The grid contains at least one point.
01272 
01273     if (!generators_are_up_to_date())
01274       update_generators();
01275     normalize_divisors(gs, gen_sys);
01276 
01277     gen_sys.recycling_insert(gs);
01278 
01279     // Congruences are out of date and generators are not minimized.
01280     clear_congruences_up_to_date();
01281     clear_generators_minimized();
01282 
01283     PPL_ASSERT(OK(true));
01284     return;
01285   }
01286 
01287   // The grid is empty.
01288 
01289   // `gs' must contain at least one point.
01290   if (!gs.has_points())
01291     throw_invalid_generators("add_recycled_grid_generators(gs)", "gs");
01292 
01293   // Adjust `gs' to the right dimension.
01294   gs.insert(parameter(0*Variable(space_dim-1)));
01295 
01296   gen_sys.m_swap(gs);
01297 
01298   normalize_divisors(gen_sys);
01299 
01300   // The grid is no longer empty and generators are up-to-date.
01301   set_generators_up_to_date();
01302   clear_empty();
01303 
01304   PPL_ASSERT(OK());
01305 }
01306 
01307 void
01308 PPL::Grid::add_grid_generators(const Grid_Generator_System& gs) {
01309   // TODO: this is just an executable specification.
01310   Grid_Generator_System gs_copy = gs;
01311   add_recycled_grid_generators(gs_copy);
01312 }
01313 
01314 void
01315 PPL::Grid::refine_with_constraint(const Constraint& c) {
01316   // The dimension of `c' must be at most `space_dim'.
01317   if (space_dim < c.space_dimension())
01318     throw_dimension_incompatible("refine_with_constraint(c)", "c", c);
01319   if (marked_empty())
01320     return;
01321   refine_no_check(c);
01322 }
01323 
01324 void
01325 PPL::Grid::refine_with_constraints(const Constraint_System& cs) {
01326   // The dimension of `cs' must be at most `space_dim'.
01327   if (space_dim < cs.space_dimension())
01328     throw_dimension_incompatible("refine_with_constraints(cs)", "cs", cs);
01329 
01330   for (Constraint_System::const_iterator i = cs.begin(),
01331          cs_end = cs.end(); !marked_empty() && i != cs_end; ++i)
01332     refine_no_check(*i);
01333 }
01334 
01335 void
01336 PPL::Grid::unconstrain(const Variable var) {
01337   // Dimension-compatibility check.
01338   if (space_dim < var.space_dimension())
01339     throw_dimension_incompatible("unconstrain(var)", var.space_dimension());
01340 
01341   // Do something only if the grid is non-empty.
01342   if (marked_empty()
01343       || (!generators_are_up_to_date() && !update_generators()))
01344     // Empty: do nothing.
01345     return;
01346 
01347   PPL_ASSERT(generators_are_up_to_date());
01348   Grid_Generator l = grid_line(var);
01349   gen_sys.recycling_insert(l);
01350   // With the added generator, congruences are out of date.
01351   clear_congruences_up_to_date();
01352   clear_generators_minimized();
01353   PPL_ASSERT(OK());
01354 }
01355 
01356 void
01357 PPL::Grid::unconstrain(const Variables_Set& vars) {
01358   // The cylindrification with respect to no dimensions is a no-op.
01359   // This case also captures the only legal cylindrification
01360   // of a grid in a 0-dim space.
01361   if (vars.empty())
01362     return;
01363 
01364   // Dimension-compatibility check.
01365   const dimension_type min_space_dim = vars.space_dimension();
01366   if (space_dim < min_space_dim)
01367     throw_dimension_incompatible("unconstrain(vs)", min_space_dim);
01368 
01369   // Do something only if the grid is non-empty.
01370   if (marked_empty()
01371       || (!generators_are_up_to_date() && !update_generators()))
01372     // Empty: do nothing.
01373     return;
01374 
01375   PPL_ASSERT(generators_are_up_to_date());
01376   // Since `gen_sys' is not empty, the space dimension of the inserted
01377   // generators are automatically adjusted.
01378   for (Variables_Set::const_iterator vsi = vars.begin(),
01379          vsi_end = vars.end(); vsi != vsi_end; ++vsi) {
01380     Grid_Generator l = grid_line(Variable(*vsi));
01381     gen_sys.recycling_insert(l);
01382   }
01383   // Constraints are no longer up-to-date.
01384   clear_generators_minimized();
01385   clear_congruences_up_to_date();
01386   PPL_ASSERT(OK());
01387 }
01388 
01389 void
01390 PPL::Grid::intersection_assign(const Grid& y) {
01391   Grid& x = *this;
01392   // Dimension-compatibility check.
01393   if (x.space_dim != y.space_dim)
01394     throw_dimension_incompatible("intersection_assign(y)", "y", y);
01395 
01396   // If one of the two grids is empty, the intersection is empty.
01397   if (x.marked_empty())
01398     return;
01399   if (y.marked_empty()) {
01400     x.set_empty();
01401     return;
01402   }
01403 
01404   // If both grids are zero-dimensional, then at this point they are
01405   // necessarily universe, so the intersection is also universe.
01406   if (x.space_dim == 0)
01407     return;
01408 
01409   // The congruences must be up-to-date.
01410   if (!x.congruences_are_up_to_date())
01411     x.update_congruences();
01412   if (!y.congruences_are_up_to_date())
01413     y.update_congruences();
01414 
01415   if (!y.con_sys.has_no_rows()) {
01416     x.con_sys.insert(y.con_sys);
01417     // Grid_Generators may be out of date and congruences may have changed
01418     // from minimal form.
01419     x.clear_generators_up_to_date();
01420     x.clear_congruences_minimized();
01421   }
01422 
01423   PPL_ASSERT(x.OK() && y.OK());
01424 }
01425 
01426 void
01427 PPL::Grid::upper_bound_assign(const Grid& y) {
01428   Grid& x = *this;
01429   // Dimension-compatibility check.
01430   if (x.space_dim != y.space_dim)
01431     throw_dimension_incompatible("upper_bound_assign(y)", "y", y);
01432 
01433   // The join of a grid `gr' with an empty grid is `gr'.
01434   if (y.marked_empty())
01435     return;
01436   if (x.marked_empty()) {
01437     x = y;
01438     return;
01439   }
01440 
01441   // If both grids are zero-dimensional, then they are necessarily
01442   // universe grids, and so is their join.
01443   if (x.space_dim == 0)
01444     return;
01445 
01446   // The generators must be up-to-date.
01447   if (!x.generators_are_up_to_date() && !x.update_generators()) {
01448     // Discovered `x' empty when updating generators.
01449     x = y;
01450     return;
01451   }
01452   if (!y.generators_are_up_to_date() && !y.update_generators())
01453     // Discovered `y' empty when updating generators.
01454     return;
01455 
01456   // Match the divisors of the x and y generator systems.
01457   Grid_Generator_System gs(y.gen_sys);
01458   normalize_divisors(x.gen_sys, gs);
01459   x.gen_sys.recycling_insert(gs);
01460   // Congruences may be out of date and generators may have lost
01461   // minimal form.
01462   x.clear_congruences_up_to_date();
01463   x.clear_generators_minimized();
01464 
01465   // At this point both `x' and `y' are not empty.
01466   PPL_ASSERT(x.OK(true) && y.OK(true));
01467 }
01468 
01469 bool
01470 PPL::Grid::upper_bound_assign_if_exact(const Grid& y) {
01471   Grid& x = *this;
01472 
01473   // Dimension-compatibility check.
01474   if (x.space_dim != y.space_dim)
01475     throw_dimension_incompatible("upper_bound_assign_if_exact(y)", "y", y);
01476 
01477   if (x.marked_empty()
01478       || y.marked_empty()
01479       || x.space_dim == 0
01480       || x.is_included_in(y)
01481       || y.is_included_in(x)) {
01482     upper_bound_assign(y);
01483     return true;
01484   }
01485 
01486   // The above test 'x.is_included_in(y)' will ensure the generators of x
01487   // are up to date.
01488   PPL_ASSERT(generators_are_up_to_date());
01489 
01490   Grid x_copy = x;
01491   x_copy.upper_bound_assign(y);
01492   x_copy.difference_assign(y);
01493   if (x_copy.is_included_in(x)) {
01494     upper_bound_assign(y);
01495     return true;
01496   }
01497 
01498   return false;
01499 }
01500 
01501 void
01502 PPL::Grid::difference_assign(const Grid& y) {
01503   Grid& x = *this;
01504   // Dimension-compatibility check.
01505   if (x.space_dim != y.space_dim)
01506     throw_dimension_incompatible("difference_assign(y)", "y", y);
01507 
01508   if (y.marked_empty() || x.marked_empty())
01509     return;
01510 
01511   // If both grids are zero-dimensional, then they are necessarily
01512   // universe grids, so the result is empty.
01513   if (x.space_dim == 0) {
01514     x.set_empty();
01515     return;
01516   }
01517 
01518   if (y.contains(x)) {
01519     x.set_empty();
01520     return;
01521   }
01522 
01523   Grid new_grid(x.space_dim, EMPTY);
01524 
01525   const Congruence_System& y_cgs = y.congruences();
01526   for (Congruence_System::const_iterator i = y_cgs.begin(),
01527          y_cgs_end = y_cgs.end(); i != y_cgs_end; ++i) {
01528     const Congruence& cg = *i;
01529 
01530     // The 2-complement cg2 of cg = ((e %= 0) / m) is the congruence
01531     // defining the sets of points exactly half-way between successive
01532     // hyperplanes e = km and e = (k+1)m, for any integer k; that is,
01533     // the hyperplanes defined by 2e = (2k + 1)m, for any integer k.
01534     // Thus `cg2' is the congruence ((2e %= m) / 2m).
01535 
01536     // As the grid difference must be a grid, only add the
01537     // 2-complement congruence to x if the resulting grid includes all
01538     // the points in x that did not satisfy `cg'.
01539 
01540     // The 2-complement of cg can be included in the result only if x
01541     // holds points other than those in cg.
01542     if (x.relation_with(cg).implies(Poly_Con_Relation::is_included()))
01543       continue;
01544 
01545     if (cg.is_proper_congruence()) {
01546       const Linear_Expression e = Linear_Expression(cg);
01547       // Congruence cg is ((e %= 0) / m).
01548       const Coefficient& m = cg.modulus();
01549       // If x is included in the grid defined by the congruences cg
01550       // and its 2-complement (i.e. the grid defined by the congruence
01551       // (2e %= 0) / m) then add the 2-complement to the potential
01552       // result.
01553       if (x.relation_with((2*e %= 0) / m)
01554           .implies(Poly_Con_Relation::is_included())) {
01555         Grid z = x;
01556         z.add_congruence_no_check((2*e %= m) / (2*m));
01557         new_grid.upper_bound_assign(z);
01558         continue;
01559       }
01560     }
01561     return;
01562   }
01563 
01564   *this = new_grid;
01565 
01566   PPL_ASSERT(OK());
01567 }
01568 
01569 namespace {
01570 
01571 struct Ruled_Out_Pair {
01572   PPL::dimension_type congruence_index;
01573   PPL::dimension_type num_ruled_out;
01574 };
01575 
01576 struct Ruled_Out_Less_Than {
01577   bool operator()(const Ruled_Out_Pair& x,
01578                   const Ruled_Out_Pair& y) const {
01579     return x.num_ruled_out > y.num_ruled_out;
01580   }
01581 };
01582 
01583 } // namespace
01584 
01585 bool
01586 PPL::Grid::simplify_using_context_assign(const Grid& y) {
01587   Grid& x = *this;
01588   // Dimension-compatibility check.
01589   if (x.space_dim != y.space_dim)
01590     throw_dimension_incompatible("simplify_using_context_assign(y)", "y", y);
01591 
01592   // Filter away the zero-dimensional case.
01593   if (x.space_dim == 0) {
01594     if (y.is_empty()) {
01595       set_zero_dim_univ();
01596       PPL_ASSERT(OK());
01597       return false;
01598     }
01599     else
01600       return !x.is_empty();
01601   }
01602 
01603   // If `y' is empty, the biggest enlargement for `x' is the universe.
01604   if (!y.minimize()) {
01605     Grid gr(x.space_dim, UNIVERSE);
01606     m_swap(gr);
01607     return false;
01608   }
01609 
01610   // If `x' is empty, the intersection is empty.
01611   if (!x.minimize()) {
01612     // Search for a congruence of `y' that is not a tautology.
01613     PPL_ASSERT(y.congruences_are_up_to_date());
01614     Grid gr(x.space_dim, UNIVERSE);
01615     for (dimension_type i = y.con_sys.num_rows(); i-- > 0; ) {
01616       const Congruence& y_con_sys_i = y.con_sys[i];
01617       if (!y_con_sys_i.is_tautological()) {
01618         // Found: we obtain a congruence `c' contradicting the one we
01619         // found, and assign to `x' the grid `gr' with `c' as
01620         // the only congruence.
01621         const Linear_Expression le(y_con_sys_i);
01622         if (y_con_sys_i.is_equality()) {
01623           gr.refine_no_check(le == 1);
01624           break;
01625         }
01626         else {
01627           const Coefficient& y_modulus_i = y_con_sys_i.modulus();
01628           if (y_modulus_i > 1)
01629             gr.refine_no_check(le == 1);
01630           else {
01631             Linear_Expression le2;
01632             for (dimension_type j = le.space_dimension(); j-- > 0; )
01633               le2 += 2 * le.coefficient(Variable(j)) * Variable(j);
01634             le2 += 2 * le.inhomogeneous_term();
01635             gr.refine_no_check(le2 == y_modulus_i);
01636           }
01637           break;
01638         }
01639       }
01640     }
01641     m_swap(gr);
01642     PPL_ASSERT(OK());
01643     return false;
01644   }
01645 
01646   PPL_ASSERT(x.congruences_are_minimized()
01647          && y.generators_are_minimized());
01648 
01649   const Congruence_System& x_cs = x.con_sys;
01650   const dimension_type x_cs_num_rows = x_cs.num_rows();
01651 
01652   // Record into `redundant_by_y' the info about which congruences of
01653   // `x' are redundant in the context `y'.  Count the number of
01654   // redundancies found.
01655   std::vector<bool> redundant_by_y(x_cs_num_rows, false);
01656   dimension_type num_redundant_by_y = 0;
01657   for (dimension_type i = 0; i < x_cs_num_rows; ++i) {
01658     if (y.relation_with(x_cs[i]).implies(Poly_Con_Relation::is_included())) {
01659       redundant_by_y[i] = true;
01660       ++num_redundant_by_y;
01661     }
01662   }
01663 
01664   if (num_redundant_by_y < x_cs_num_rows) {
01665 
01666     // Some congruences were not identified as redundant.
01667 
01668     Congruence_System result_cs;
01669     const Congruence_System& y_cs = y.con_sys;
01670     const dimension_type y_cs_num_rows = y_cs.num_rows();
01671     // Compute into `z' the intersection of `x' and `y'.
01672     const bool x_first = (x_cs_num_rows > y_cs_num_rows);
01673     Grid z(x_first ? x : y);
01674     if (x_first)
01675       z.add_congruences(y_cs);
01676     else {
01677       // Only copy (and then recycle) the non-redundant congruences.
01678       Congruence_System tmp_cs;
01679       for (dimension_type i = 0; i < x_cs_num_rows; ++i) {
01680         if (!redundant_by_y[i])
01681           tmp_cs.insert(x_cs[i]);
01682       }
01683       z.add_recycled_congruences(tmp_cs);
01684     }
01685 
01686     // Congruences are added to `w' until it equals `z'.
01687     // We do not care about minimization or maximization, since
01688     // we are only interested in satisfiability.
01689     Grid w;
01690     w.add_space_dimensions_and_embed(x.space_dim);
01691     // First add the congruences for `y'.
01692     w.add_congruences(y_cs);
01693 
01694     // We apply the following heuristics here: congruences of `x' that
01695     // are not made redundant by `y' are added to `w' depending on
01696     // the number of generators of `y' they rule out (the more generators)
01697     // (they rule out, the sooner they are added).  Of course, as soon
01698     // as `w' becomes empty, we stop adding.
01699     std::vector<Ruled_Out_Pair>
01700       ruled_out_vec(x_cs_num_rows - num_redundant_by_y);
01701 
01702     PPL_DIRTY_TEMP_COEFFICIENT(sp);
01703     PPL_DIRTY_TEMP_COEFFICIENT(div);
01704 
01705     for (dimension_type i = 0, j = 0; i < x_cs_num_rows; ++i) {
01706       if (!redundant_by_y[i]) {
01707         const Congruence& c = x_cs[i];
01708         const Coefficient& modulus = c.modulus();
01709         div = modulus;
01710 
01711         const Grid_Generator_System& y_gs = y.gen_sys;
01712         dimension_type num_ruled_out_generators = 0;
01713         for (Grid_Generator_System::const_iterator k = y_gs.begin(),
01714                y_gs_end = y_gs.end(); k != y_gs_end; ++k) {
01715           const Grid_Generator& g = *k;
01716           // If the generator is not to be ruled out,
01717           // it must saturate the congruence.
01718           Scalar_Products::assign(sp, c, g);
01719           // If `c' is a proper congruence the scalar product must be
01720           // reduced modulo a (possibly scaled) modulus.
01721           if (c.is_proper_congruence()) {
01722             // If `g' is a parameter the congruence modulus must be scaled
01723             // up by the divisor of the generator.
01724             if (g.is_parameter())
01725               sp %= (div * g.divisor());
01726             else
01727               if (g.is_point())
01728                 sp %= div;
01729           }
01730           if (sp == 0)
01731             continue;
01732           ++num_ruled_out_generators;
01733         }
01734         ruled_out_vec[j].congruence_index = i;
01735         ruled_out_vec[j].num_ruled_out = num_ruled_out_generators;
01736         ++j;
01737       }
01738     }
01739     std::sort(ruled_out_vec.begin(), ruled_out_vec.end(),
01740               Ruled_Out_Less_Than());
01741 
01742     bool empty_intersection = (!z.minimize());
01743 
01744     // Add the congruences in the "ruled out" order to `w'
01745     // until the result is the intersection.
01746     for (std::vector<Ruled_Out_Pair>::const_iterator
01747            j = ruled_out_vec.begin(), ruled_out_vec_end = ruled_out_vec.end();
01748          j != ruled_out_vec_end;
01749          ++j) {
01750       const Congruence& c = x_cs[j->congruence_index];
01751       result_cs.insert(c);
01752       w.add_congruence(c);
01753       if ((empty_intersection && w.is_empty())
01754           || (!empty_intersection && w.is_included_in(z))) {
01755         Grid result_gr(x.space_dim, UNIVERSE);
01756         result_gr.add_congruences(result_cs);
01757         x.m_swap(result_gr);
01758         PPL_ASSERT(x.OK());
01759         return !empty_intersection;
01760       }
01761     }
01762     // Cannot exit from here.
01763     PPL_UNREACHABLE;
01764   }
01765 
01766   // All the congruences are redundant so that the simplified grid
01767   // is the universe.
01768   Grid result_gr(x.space_dim, UNIVERSE);
01769   x.m_swap(result_gr);
01770   PPL_ASSERT(x.OK());
01771   return true;
01772 }
01773 
01774 void
01775 PPL::Grid::affine_image(const Variable var,
01776                         const Linear_Expression& expr,
01777                         Coefficient_traits::const_reference denominator) {
01778   // The denominator cannot be zero.
01779   if (denominator == 0)
01780     throw_invalid_argument("affine_image(v, e, d)", "d == 0");
01781 
01782   // Dimension-compatibility checks.
01783   // The dimension of `expr' must be at most the dimension of `*this'.
01784   const dimension_type expr_space_dim = expr.space_dimension();
01785   if (space_dim < expr_space_dim)
01786     throw_dimension_incompatible("affine_image(v, e, d)", "e", expr);
01787   // `var' must be one of the dimensions of the grid.
01788   const dimension_type var_space_dim = var.space_dimension();
01789   if (space_dim < var_space_dim)
01790     throw_dimension_incompatible("affine_image(v, e, d)", "v", var);
01791 
01792   if (marked_empty())
01793     return;
01794 
01795   if (var_space_dim <= expr_space_dim && expr[var_space_dim] != 0) {
01796     // The transformation is invertible.
01797     if (generators_are_up_to_date()) {
01798       // Grid_Generator_System::affine_image() requires the third argument
01799       // to be a positive Coefficient.
01800       if (denominator > 0)
01801         gen_sys.affine_image(var_space_dim, expr, denominator);
01802       else
01803         gen_sys.affine_image(var_space_dim, -expr, -denominator);
01804       clear_generators_minimized();
01805       // Strong normalization in gs::affine_image may have modified
01806       // divisors.
01807       normalize_divisors(gen_sys);
01808     }
01809     if (congruences_are_up_to_date()) {
01810       // To build the inverse transformation,
01811       // after copying and negating `expr',
01812       // we exchange the roles of `expr[var_space_dim]' and `denominator'.
01813       Linear_Expression inverse;
01814       if (expr[var_space_dim] > 0) {
01815         inverse = -expr;
01816         inverse[var_space_dim] = denominator;
01817         con_sys.affine_preimage(var_space_dim, inverse, expr[var_space_dim]);
01818       }
01819       else {
01820         // The new denominator is negative: we negate everything once
01821         // more, as Congruence_System::affine_preimage() requires the
01822         // third argument to be positive.
01823         inverse = expr;
01824         inverse[var_space_dim] = denominator;
01825         neg_assign(inverse[var_space_dim]);
01826         con_sys.affine_preimage(var_space_dim, inverse, -expr[var_space_dim]);
01827       }
01828       clear_congruences_minimized();
01829     }
01830   }
01831   else {
01832     // The transformation is not invertible.
01833     // We need an up-to-date system of generators.
01834     if (!generators_are_up_to_date())
01835       minimize();
01836     if (!marked_empty()) {
01837       // Grid_Generator_System::affine_image() requires the third argument
01838       // to be a positive Coefficient.
01839       if (denominator > 0)
01840         gen_sys.affine_image(var_space_dim, expr, denominator);
01841       else
01842         gen_sys.affine_image(var_space_dim, -expr, -denominator);
01843 
01844       clear_congruences_up_to_date();
01845       clear_generators_minimized();
01846       // Strong normalization in gs::affine_image may have modified
01847       // divisors.
01848       normalize_divisors(gen_sys);
01849     }
01850   }
01851   PPL_ASSERT(OK());
01852 }
01853 
01854 void
01855 PPL::Grid::
01856 affine_preimage(const Variable var,
01857                 const Linear_Expression& expr,
01858                 Coefficient_traits::const_reference denominator) {
01859   // The denominator cannot be zero.
01860   if (denominator == 0)
01861     throw_invalid_argument("affine_preimage(v, e, d)", "d == 0");
01862 
01863   // Dimension-compatibility checks.
01864   // The dimension of `expr' should not be greater than the dimension
01865   // of `*this'.
01866   const dimension_type expr_space_dim = expr.space_dimension();
01867   if (space_dim < expr_space_dim)
01868     throw_dimension_incompatible("affine_preimage(v, e, d)", "e", expr);
01869   // `var' should be one of the dimensions of the grid.
01870   const dimension_type var_space_dim = var.space_dimension();
01871   if (space_dim < var_space_dim)
01872     throw_dimension_incompatible("affine_preimage(v, e, d)", "v", var);
01873 
01874   if (marked_empty())
01875     return;
01876 
01877   if (var_space_dim <= expr_space_dim && expr[var_space_dim] != 0) {
01878     // The transformation is invertible.
01879     if (congruences_are_up_to_date()) {
01880       // Congruence_System::affine_preimage() requires the third argument
01881       // to be a positive Coefficient.
01882       if (denominator > 0)
01883         con_sys.affine_preimage(var_space_dim, expr, denominator);
01884       else
01885         con_sys.affine_preimage(var_space_dim, -expr, -denominator);
01886       clear_congruences_minimized();
01887     }
01888     if (generators_are_up_to_date()) {
01889       // To build the inverse transformation,
01890       // after copying and negating `expr',
01891       // we exchange the roles of `expr[var_space_dim]' and `denominator'.
01892       Linear_Expression inverse;
01893       if (expr[var_space_dim] > 0) {
01894         inverse = -expr;
01895         inverse[var_space_dim] = denominator;
01896         gen_sys.affine_image(var_space_dim, inverse, expr[var_space_dim]);
01897       }
01898       else {
01899         // The new denominator is negative: we negate everything once
01900         // more, as Grid_Generator_System::affine_image() requires the
01901         // third argument to be positive.
01902         inverse = expr;
01903         inverse[var_space_dim] = denominator;
01904         neg_assign(inverse[var_space_dim]);
01905         gen_sys.affine_image(var_space_dim, inverse, -expr[var_space_dim]);
01906       }
01907       clear_generators_minimized();
01908     }
01909   }
01910   else {
01911     // The transformation is not invertible.
01912     // We need an up-to-date system of congruences.
01913     if (!congruences_are_up_to_date())
01914       minimize();
01915     // Congruence_System::affine_preimage() requires the third argument
01916     // to be a positive Coefficient.
01917     if (denominator > 0)
01918       con_sys.affine_preimage(var_space_dim, expr, denominator);
01919     else
01920       con_sys.affine_preimage(var_space_dim, -expr, -denominator);
01921 
01922     clear_generators_up_to_date();
01923     clear_congruences_minimized();
01924   }
01925   PPL_ASSERT(OK());
01926 }
01927 
01928 void
01929 PPL::Grid::
01930 generalized_affine_image(const Variable var,
01931                          const Relation_Symbol relsym,
01932                          const Linear_Expression& expr,
01933                          Coefficient_traits::const_reference denominator,
01934                          Coefficient_traits::const_reference modulus) {
01935   // The denominator cannot be zero.
01936   if (denominator == 0)
01937     throw_invalid_argument("generalized_affine_image(v, r, e, d, m)",
01938                            "d == 0");
01939 
01940   // Dimension-compatibility checks.
01941   // The dimension of `expr' should not be greater than the dimension
01942   // of `*this'.
01943   const dimension_type expr_space_dim = expr.space_dimension();
01944   if (space_dim < expr_space_dim)
01945     throw_dimension_incompatible("generalized_affine_image(v, r, e, d, m)",
01946                                  "e", expr);
01947   // `var' should be one of the dimensions of the grid.
01948   const dimension_type var_space_dim = var.space_dimension();
01949   if (space_dim < var_space_dim)
01950     throw_dimension_incompatible("generalized_affine_image(v, r, e, d, m)",
01951                                  "v", var);
01952   // The relation symbol cannot be a disequality.
01953   if (relsym == NOT_EQUAL)
01954     throw_invalid_argument("generalized_affine_image(v, r, e, d, m)",
01955                            "r is the disequality relation symbol");
01956 
01957   // Any image of an empty grid is empty.
01958   if (marked_empty())
01959     return;
01960 
01961   // If relsym is not EQUAL, then we return a safe approximation
01962   // by adding a line in the direction of var.
01963   if (relsym != EQUAL) {
01964 
01965     if (modulus != 0)
01966       throw_invalid_argument("generalized_affine_image(v, r, e, d, m)",
01967                              "r != EQUAL && m != 0");
01968 
01969     if (!generators_are_up_to_date())
01970       minimize();
01971 
01972     // Any image of an empty grid is empty.
01973     if (marked_empty())
01974       return;
01975 
01976     add_grid_generator(grid_line(var));
01977 
01978     PPL_ASSERT(OK());
01979     return;
01980   }
01981 
01982   PPL_ASSERT(relsym == EQUAL);
01983 
01984   affine_image(var, expr, denominator);
01985 
01986   if (modulus == 0)
01987     return;
01988 
01989   // Modulate dimension `var' according to `modulus'.
01990 
01991   if (!generators_are_up_to_date())
01992     minimize();
01993 
01994   // Test if minimization, possibly in affine_image, found an empty
01995   // grid.
01996   if (marked_empty())
01997     return;
01998 
01999   if (modulus < 0)
02000     gen_sys.insert(parameter(-modulus * var));
02001   else
02002     gen_sys.insert(parameter(modulus * var));
02003 
02004   normalize_divisors(gen_sys);
02005 
02006   clear_generators_minimized();
02007   clear_congruences_up_to_date();
02008 
02009   PPL_ASSERT(OK());
02010 }
02011 
02012 void
02013 PPL::Grid::
02014 generalized_affine_preimage(const Variable var,
02015                             const Relation_Symbol relsym,
02016                             const Linear_Expression& expr,
02017                             Coefficient_traits::const_reference denominator,
02018                             Coefficient_traits::const_reference modulus) {
02019   // The denominator cannot be zero.
02020   if (denominator == 0)
02021     throw_invalid_argument("generalized_affine_preimage(v, r, e, d, m)",
02022                            "d == 0");
02023 
02024   // The dimension of `expr' should be at most the dimension of
02025   // `*this'.
02026   const dimension_type expr_space_dim = expr.space_dimension();
02027   if (space_dim < expr_space_dim)
02028     throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d, m)",
02029                                  "e", expr);
02030   // `var' should be one of the dimensions of the grid.
02031   const dimension_type var_space_dim = var.space_dimension();
02032   if (space_dim < var_space_dim)
02033     throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d, m)",
02034                                  "v", var);
02035   // The relation symbol cannot be a disequality.
02036   if (relsym == NOT_EQUAL)
02037     throw_invalid_argument("generalized_affine_preimage(v, r, e, d, m)",
02038                            "r is the disequality relation symbol");
02039 
02040   // If relsym is not EQUAL, then we return a safe approximation
02041   // by adding a line in the direction of var.
02042   if (relsym != EQUAL) {
02043 
02044     if (modulus != 0)
02045       throw_invalid_argument("generalized_affine_preimage(v, r, e, d, m)",
02046                              "r != EQUAL && m != 0");
02047 
02048     if (!generators_are_up_to_date())
02049       minimize();
02050 
02051     // Any image of an empty grid is empty.
02052     if (marked_empty())
02053       return;
02054 
02055     add_grid_generator(grid_line(var));
02056 
02057     PPL_ASSERT(OK());
02058     return;
02059   }
02060 
02061   PPL_ASSERT(relsym == EQUAL);
02062   // Any image of an empty grid is empty.
02063   if (marked_empty())
02064     return;
02065 
02066   // Check whether the affine relation is an affine function.
02067   if (modulus == 0) {
02068     affine_preimage(var, expr, denominator);
02069     return;
02070   }
02071 
02072   // Check whether the preimage of this affine relation can be easily
02073   // computed as the image of its inverse relation.
02074   const Coefficient& var_coefficient = expr.coefficient(var);
02075   if (var_space_dim <= expr_space_dim && var_coefficient != 0) {
02076     Linear_Expression inverse_expr
02077       = expr - (denominator + var_coefficient) * var;
02078     PPL_DIRTY_TEMP_COEFFICIENT(inverse_denominator);
02079     neg_assign(inverse_denominator, var_coefficient);
02080     if (modulus < 0)
02081       generalized_affine_image(var, EQUAL, inverse_expr, inverse_denominator,
02082                                - modulus);
02083     else
02084       generalized_affine_image(var, EQUAL, inverse_expr, inverse_denominator,
02085                                modulus);
02086     return;
02087   }
02088 
02089   // Here `var_coefficient == 0', so that the preimage cannot be
02090   // easily computed by inverting the affine relation.  Add the
02091   // congruence induced by the affine relation.
02092   {
02093     Congruence cg((denominator*var %= expr) / denominator);
02094     if (modulus < 0)
02095       cg /= -modulus;
02096     else
02097       cg /= modulus;
02098     add_congruence_no_check(cg);
02099   }
02100 
02101   // If the resulting grid is empty, its preimage is empty too.
02102   // Note: DO check for emptiness here, as we will later add a line.
02103   if (is_empty())
02104     return;
02105   add_grid_generator(grid_line(var));
02106   PPL_ASSERT(OK());
02107 }
02108 
02109 void
02110 PPL::Grid::
02111 generalized_affine_image(const Linear_Expression& lhs,
02112                          const Relation_Symbol relsym,
02113                          const Linear_Expression& rhs,
02114                          Coefficient_traits::const_reference modulus) {
02115   // Dimension-compatibility checks.
02116   // The dimension of `lhs' should be at most the dimension of
02117   // `*this'.
02118   dimension_type lhs_space_dim = lhs.space_dimension();
02119   if (space_dim < lhs_space_dim)
02120     throw_dimension_incompatible("generalized_affine_image(e1, r, e2, m)",
02121                                  "e1", lhs);
02122   // The dimension of `rhs' should be at most the dimension of
02123   // `*this'.
02124   const dimension_type rhs_space_dim = rhs.space_dimension();
02125   if (space_dim < rhs_space_dim)
02126     throw_dimension_incompatible("generalized_affine_image(e1, r, e2, m)",
02127                                  "e2", rhs);
02128   // The relation symbol cannot be a disequality.
02129   if (relsym == NOT_EQUAL)
02130     throw_invalid_argument("generalized_affine_image(e1, r, e2, m)",
02131                            "r is the disequality relation symbol");
02132 
02133   // Any image of an empty grid is empty.
02134   if (marked_empty())
02135     return;
02136 
02137   // If relsym is not EQUAL, then we return a safe approximation
02138   // by adding a line in the direction of var.
02139   if (relsym != EQUAL) {
02140 
02141     if (modulus != 0)
02142       throw_invalid_argument("generalized_affine_image(e1, r, e2, m)",
02143                              "r != EQUAL && m != 0");
02144 
02145     if (!generators_are_up_to_date())
02146       minimize();
02147 
02148     // Any image of an empty grid is empty.
02149     if (marked_empty())
02150       return;
02151 
02152     for (dimension_type i = space_dim; i-- > 0; )
02153       if (lhs.coefficient(Variable(i)) != 0)
02154         add_grid_generator(grid_line(Variable(i)));
02155 
02156     PPL_ASSERT(OK());
02157     return;
02158   }
02159 
02160   PPL_ASSERT(relsym == EQUAL);
02161 
02162   PPL_DIRTY_TEMP_COEFFICIENT(tmp_modulus);
02163   tmp_modulus = modulus;
02164   if (tmp_modulus < 0)
02165     neg_assign(tmp_modulus);
02166 
02167   // Compute the actual space dimension of `lhs',
02168   // i.e., the highest dimension having a non-zero coefficient in `lhs'.
02169   do {
02170     if (lhs_space_dim == 0) {
02171       // All variables have zero coefficients, so `lhs' is a constant.
02172       add_congruence_no_check((lhs %= rhs) / tmp_modulus);
02173       return;
02174     }
02175   }
02176   while (lhs.coefficient(Variable(--lhs_space_dim)) == 0);
02177 
02178   // Gather in `new_lines' the collections of all the lines having the
02179   // direction of variables occurring in `lhs'.  While at it, check
02180   // whether there exists a variable occurring in both `lhs' and
02181   // `rhs'.
02182   Grid_Generator_System new_lines;
02183   bool lhs_vars_intersect_rhs_vars = false;
02184   for (dimension_type i = lhs_space_dim + 1; i-- > 0; )
02185     if (lhs.coefficient(Variable(i)) != 0) {
02186       new_lines.insert(grid_line(Variable(i)));
02187       if (rhs.coefficient(Variable(i)) != 0)
02188         lhs_vars_intersect_rhs_vars = true;
02189     }
02190 
02191   if (lhs_vars_intersect_rhs_vars) {
02192     // Some variables in `lhs' also occur in `rhs'.
02193     // To ease the computation, add an additional dimension.
02194     const Variable new_var(space_dim);
02195     add_space_dimensions_and_embed(1);
02196 
02197     // Constrain the new dimension to be equal to the right hand side.
02198     // TODO: Use add_congruence() when it has been updated.
02199     Congruence_System new_cgs1(new_var == rhs);
02200     add_recycled_congruences(new_cgs1);
02201     if (!is_empty()) {
02202       // The grid still contains points.
02203 
02204       // Existentially quantify all the variables occurring in the left
02205       // hand side expression.
02206 
02207       // Adjust `new_lines' to the right dimension.
02208       new_lines.insert(parameter(0*Variable(space_dim-1)));
02209       // Add the lines to `gen_sys' (first make sure they are up-to-date).
02210       update_generators();
02211       gen_sys.recycling_insert(new_lines);
02212       normalize_divisors(gen_sys);
02213       // Update the flags.
02214       clear_congruences_up_to_date();
02215       clear_generators_minimized();
02216 
02217       // Constrain the new dimension so that it is congruent to the left
02218       // hand side expression modulo `modulus'.
02219       // TODO: Use add_congruence() when it has been updated.
02220       Congruence_System new_cgs2((lhs %= new_var) / tmp_modulus);
02221       add_recycled_congruences(new_cgs2);
02222     }
02223 
02224     // Remove the temporarily added dimension.
02225     remove_higher_space_dimensions(space_dim-1);
02226   }
02227   else {
02228     // `lhs' and `rhs' variables are disjoint:
02229     // there is no need to add a further dimension.
02230 
02231     // Only add the lines and congruence if there are points.
02232     if (is_empty())
02233       return;
02234 
02235     // Existentially quantify all the variables occurring in the left hand
02236     // side expression.
02237     add_recycled_grid_generators(new_lines);
02238 
02239     // Constrain the left hand side expression so that it is congruent to
02240     // the right hand side expression modulo `modulus'.
02241     add_congruence_no_check((lhs %= rhs) / tmp_modulus);
02242   }
02243 
02244   PPL_ASSERT(OK());
02245 }
02246 
02247 void
02248 PPL::Grid::
02249 generalized_affine_preimage(const Linear_Expression& lhs,
02250                             const Relation_Symbol relsym,
02251                             const Linear_Expression& rhs,
02252                             Coefficient_traits::const_reference modulus) {
02253   // The dimension of `lhs' must be at most the dimension of `*this'.
02254   dimension_type lhs_space_dim = lhs.space_dimension();
02255   if (space_dim < lhs_space_dim)
02256     throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2, m)",
02257                                  "lhs", lhs);
02258   // The dimension of `rhs' must be at most the dimension of `*this'.
02259   const dimension_type rhs_space_dim = rhs.space_dimension();
02260   if (space_dim < rhs_space_dim)
02261     throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2, m)",
02262                                  "e2", rhs);
02263   // The relation symbol cannot be a disequality.
02264   if (relsym == NOT_EQUAL)
02265     throw_invalid_argument("generalized_affine_preimage(e1, r, e2, m)",
02266                            "r is the disequality relation symbol");
02267 
02268   // Any preimage of an empty grid is empty.
02269   if (marked_empty())
02270     return;
02271 
02272   // If relsym is not EQUAL, then we return a safe approximation
02273   // by adding a line in the direction of var.
02274   if (relsym != EQUAL) {
02275 
02276     if (modulus != 0)
02277       throw_invalid_argument("generalized_affine_preimage(e1, r, e2, m)",
02278                              "r != EQUAL && m != 0");
02279 
02280     if (!generators_are_up_to_date())
02281       minimize();
02282 
02283     // Any image of an empty grid is empty.
02284     if (marked_empty())
02285       return;
02286 
02287     for (dimension_type i = lhs_space_dim + 1; i-- > 0; )
02288       if (lhs.coefficient(Variable(i)) != 0)
02289         add_grid_generator(grid_line(Variable(i)));
02290 
02291     PPL_ASSERT(OK());
02292     return;
02293   }
02294 
02295   PPL_ASSERT(relsym == EQUAL);
02296 
02297   PPL_DIRTY_TEMP_COEFFICIENT(tmp_modulus);
02298   tmp_modulus = modulus;
02299   if (tmp_modulus < 0)
02300     neg_assign(tmp_modulus);
02301 
02302   // Compute the actual space dimension of `lhs',
02303   // i.e., the highest dimension having a non-zero coefficient in `lhs'.
02304   do {
02305     if (lhs_space_dim == 0) {
02306       // All variables have zero coefficients, so `lhs' is a constant.
02307       // In this case, preimage and image happen to be the same.
02308       add_congruence_no_check((lhs %= rhs) / tmp_modulus);
02309       return;
02310     }
02311   }
02312   while (lhs.coefficient(Variable(--lhs_space_dim)) == 0);
02313 
02314   // Gather in `new_lines' the collections of all the lines having
02315   // the direction of variables occurring in `lhs'.
02316   // While at it, check whether or not there exists a variable
02317   // occurring in both `lhs' and `rhs'.
02318   Grid_Generator_System new_lines;
02319   bool lhs_vars_intersect_rhs_vars = false;
02320   for (dimension_type i = lhs_space_dim + 1; i-- > 0; )
02321     if (lhs.coefficient(Variable(i)) != 0) {
02322       new_lines.insert(grid_line(Variable(i)));
02323       if (rhs.coefficient(Variable(i)) != 0)
02324         lhs_vars_intersect_rhs_vars = true;
02325     }
02326 
02327   if (lhs_vars_intersect_rhs_vars) {
02328     // Some variables in `lhs' also occur in `rhs'.
02329     // To ease the computation, add an additional dimension.
02330     const Variable new_var(space_dim);
02331     add_space_dimensions_and_embed(1);
02332 
02333     // Constrain the new dimension to be equal to `lhs'
02334     // TODO: Use add_congruence() when it has been updated.
02335     Congruence_System new_cgs1(new_var == lhs);
02336     add_recycled_congruences(new_cgs1);
02337     if (!is_empty()) {
02338       // The grid still contains points.
02339 
02340       // Existentially quantify all the variables occurring in the left
02341       // hand side
02342 
02343       // Adjust `new_lines' to the right dimension.
02344       new_lines.insert(parameter(0*Variable(space_dim-1)));
02345       // Add the lines to `gen_sys' (first make sure they are up-to-date).
02346       update_generators();
02347       gen_sys.recycling_insert(new_lines);
02348       normalize_divisors(gen_sys);
02349       // Update the flags.
02350       clear_congruences_up_to_date();
02351       clear_generators_minimized();
02352 
02353       // Constrain the new dimension so that it is related to
02354       // the right hand side modulo `modulus'.
02355       // TODO: Use add_congruence() when it has been updated.
02356       Congruence_System new_cgs2((rhs %= new_var) / tmp_modulus);
02357       add_recycled_congruences(new_cgs2);
02358     }
02359 
02360     // Remove the temporarily added dimension.
02361     remove_higher_space_dimensions(space_dim-1);
02362   }
02363   else {
02364     // `lhs' and `rhs' variables are disjoint:
02365     // there is no need to add a further dimension.
02366 
02367     // Constrain the left hand side expression so that it is congruent to
02368     // the right hand side expression modulo `mod'.
02369     add_congruence_no_check((lhs %= rhs) / tmp_modulus);
02370 
02371     // Any image of an empty grid is empty.
02372     if (is_empty())
02373       return;
02374 
02375     // Existentially quantify all the variables occurring in `lhs'.
02376     add_recycled_grid_generators(new_lines);
02377   }
02378   PPL_ASSERT(OK());
02379 }
02380 
02381 void
02382 PPL::Grid::
02383 bounded_affine_image(const Variable var,
02384                      const Linear_Expression& lb_expr,
02385                      const Linear_Expression& ub_expr,
02386                      Coefficient_traits::const_reference denominator) {
02387 
02388   // The denominator cannot be zero.
02389   if (denominator == 0)
02390     throw_invalid_argument("bounded_affine_image(v, lb, ub, d)", "d == 0");
02391 
02392   // Dimension-compatibility checks.
02393   // `var' should be one of the dimensions of the grid.
02394   const dimension_type var_space_dim = var.space_dimension();
02395   if (space_dim < var_space_dim)
02396     throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
02397                                  "v", var);
02398   // The dimension of `lb_expr' and `ub_expr' should not be
02399   // greater than the dimension of `*this'.
02400   const dimension_type lb_space_dim = lb_expr.space_dimension();
02401   if (space_dim < lb_space_dim)
02402     throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
02403                                  "lb", lb_expr);
02404   const dimension_type ub_space_dim = ub_expr.space_dimension();
02405   if (space_dim < ub_space_dim)
02406     throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
02407                                  "ub", ub_expr);
02408 
02409   // Any image of an empty grid is empty.
02410   if (marked_empty())
02411     return;
02412 
02413   // In all other cases, generalized_affine_preimage() must
02414   // just add a line in the direction of var.
02415   generalized_affine_image(var,
02416                            LESS_OR_EQUAL,
02417                            ub_expr,
02418                            denominator);
02419 
02420   PPL_ASSERT(OK());
02421 }
02422 
02423 
02424 void
02425 PPL::Grid::
02426 bounded_affine_preimage(const Variable var,
02427                         const Linear_Expression& lb_expr,
02428                         const Linear_Expression& ub_expr,
02429                         Coefficient_traits::const_reference denominator) {
02430 
02431   // The denominator cannot be zero.
02432   if (denominator == 0)
02433     throw_invalid_argument("bounded_affine_preimage(v, lb, ub, d)", "d == 0");
02434 
02435   // Dimension-compatibility checks.
02436   // `var' should be one of the dimensions of the grid.
02437   const dimension_type var_space_dim = var.space_dimension();
02438   if (space_dim < var_space_dim)
02439     throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
02440                                  "v", var);
02441   // The dimension of `lb_expr' and `ub_expr' should not be
02442   // greater than the dimension of `*this'.
02443   const dimension_type lb_space_dim = lb_expr.space_dimension();
02444   if (space_dim < lb_space_dim)
02445     throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
02446                                  "lb", lb_expr);
02447   const dimension_type ub_space_dim = ub_expr.space_dimension();
02448   if (space_dim < ub_space_dim)
02449     throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
02450                                  "ub", ub_expr);
02451 
02452   // Any preimage of an empty grid is empty.
02453   if (marked_empty())
02454     return;
02455 
02456   // In all other cases, generalized_affine_preimage() must
02457   // just add a line in the direction of var.
02458   generalized_affine_preimage(var,
02459                               LESS_OR_EQUAL,
02460                               ub_expr,
02461                               denominator);
02462 
02463   PPL_ASSERT(OK());
02464 }
02465 
02466 void
02467 PPL::Grid::time_elapse_assign(const Grid& y) {
02468   Grid& x = *this;
02469   // Check dimension-compatibility.
02470   if (x.space_dim != y.space_dim)
02471     throw_dimension_incompatible("time_elapse_assign(y)", "y", y);
02472 
02473   // Deal with the zero-dimensional case.
02474   if (x.space_dim == 0) {
02475     if (y.marked_empty())
02476       x.set_empty();
02477     return;
02478   }
02479 
02480   // If either one of `x' or `y' is empty, the result is empty too.
02481   if (x.marked_empty())
02482     return;
02483   if (y.marked_empty()
02484       || (!x.generators_are_up_to_date() && !x.update_generators())
02485       || (!y.generators_are_up_to_date() && !y.update_generators())) {
02486     x.set_empty();
02487     return;
02488   }
02489 
02490   // At this point both generator systems are up-to-date.
02491   Grid_Generator_System gs = y.gen_sys;
02492   dimension_type gs_num_rows = gs.num_rows();
02493 
02494   normalize_divisors(gs, gen_sys);
02495 
02496   for (dimension_type i = gs_num_rows; i-- > 0; ) {
02497     Grid_Generator& g = gs[i];
02498     if (g.is_point())
02499       // Transform the point into a parameter.
02500       g.set_is_parameter();
02501   }
02502 
02503   if (gs_num_rows == 0)
02504     // `y' was the grid containing a single point at the origin, so
02505     // the result is `x'.
02506     return;
02507 
02508   // Append `gs' to the generators of `x'.
02509 
02510   gen_sys.recycling_insert(gs);
02511 
02512   x.clear_congruences_up_to_date();
02513   x.clear_generators_minimized();
02514 
02515   PPL_ASSERT(x.OK(true) && y.OK(true));
02516 }
02517 
02518 bool
02519 PPL::Grid::frequency(const Linear_Expression& expr,
02520                      Coefficient& freq_n, Coefficient& freq_d,
02521                      Coefficient& val_n, Coefficient& val_d) const {
02522   // The dimension of `expr' must be at most the dimension of *this.
02523   if (space_dim < expr.space_dimension())
02524     throw_dimension_incompatible("frequency(e, ...)", "e", expr);
02525 
02526   // Space dimension is 0: if empty, then return false;
02527   // otherwise the frequency is 1 and the value is 0.
02528   if (space_dim == 0) {
02529     if (is_empty())
02530       return false;
02531     freq_n = 0;
02532     freq_d = 1;
02533     val_n = 0;
02534     val_d = 1;
02535     return true;
02536   }
02537   if (!generators_are_minimized() && !minimize())
02538     // Minimizing found `this' empty.
02539     return false;
02540 
02541   return frequency_no_check(expr, freq_n, freq_d, val_n, val_d);
02542 }
02543 
02545 bool
02546 PPL::operator==(const Grid& x, const Grid& y) {
02547   if (x.space_dim != y.space_dim)
02548     return false;
02549 
02550   if (x.marked_empty())
02551     return y.is_empty();
02552   if (y.marked_empty())
02553     return x.is_empty();
02554   if (x.space_dim == 0)
02555     return true;
02556 
02557   switch (x.quick_equivalence_test(y)) {
02558   case Grid::TVB_TRUE:
02559     return true;
02560 
02561   case Grid::TVB_FALSE:
02562     return false;
02563 
02564   default:
02565     if (x.is_included_in(y)) {
02566       if (x.marked_empty())
02567         return y.is_empty();
02568       return y.is_included_in(x);
02569     }
02570     return false;
02571   }
02572 }
02573 
02574 bool
02575 PPL::Grid::contains(const Grid& y) const {
02576   const Grid& x = *this;
02577 
02578   // Dimension-compatibility check.
02579   if (x.space_dim != y.space_dim)
02580     throw_dimension_incompatible("contains(y)", "y", y);
02581 
02582   if (y.marked_empty())
02583     return true;
02584   if (x.marked_empty())
02585     return y.is_empty();
02586   if (y.space_dim == 0)
02587     return true;
02588   if (x.quick_equivalence_test(y) == Grid::TVB_TRUE)
02589     return true;
02590   return y.is_included_in(x);
02591 }
02592 
02593 bool
02594 PPL::Grid::is_disjoint_from(const Grid& y) const {
02595   // Dimension-compatibility check.
02596   if (space_dim != y.space_dim)
02597     throw_dimension_incompatible("is_disjoint_from(y)", "y", y);
02598   Grid z = *this;
02599   z.intersection_assign(y);
02600   return z.is_empty();
02601 }
02602 
02603 void
02604 PPL::Grid::ascii_dump(std::ostream& s) const {
02605   using std::endl;
02606 
02607   s << "space_dim "
02608     << space_dim
02609     << endl;
02610   status.ascii_dump(s);
02611   s << "con_sys ("
02612     << (congruences_are_up_to_date() ? "" : "not_")
02613     << "up-to-date)"
02614     << endl;
02615   con_sys.ascii_dump(s);
02616   s << "gen_sys ("
02617     << (generators_are_up_to_date() ? "" : "not_")
02618     << "up-to-date)"
02619     << endl;
02620   gen_sys.ascii_dump(s);
02621   s << "dimension_kinds";
02622   if ((generators_are_up_to_date() && generators_are_minimized())
02623       || (congruences_are_up_to_date() && congruences_are_minimized()))
02624     for (Dimension_Kinds::const_iterator i = dim_kinds.begin();
02625          i != dim_kinds.end();
02626          ++i)
02627       s << " " << *i;
02628   s << endl;
02629 }
02630 
02631 PPL_OUTPUT_DEFINITIONS(Grid)
02632 
02633 bool
02634 PPL::Grid::ascii_load(std::istream& s) {
02635   std::string str;
02636 
02637   if (!(s >> str) || str != "space_dim")
02638     return false;
02639 
02640   if (!(s >> space_dim))
02641     return false;
02642 
02643   if (!status.ascii_load(s))
02644     return false;
02645 
02646   if (!(s >> str) || str != "con_sys")
02647     return false;
02648 
02649   if (!(s >> str))
02650     return false;
02651   if (str == "(up-to-date)")
02652     set_congruences_up_to_date();
02653   else if (str != "(not_up-to-date)")
02654     return false;
02655 
02656   if (!con_sys.ascii_load(s))
02657     return false;
02658 
02659   if (!(s >> str) || str != "gen_sys")
02660     return false;
02661 
02662   if (!(s >> str))
02663     return false;
02664   if (str == "(up-to-date)")
02665     set_generators_up_to_date();
02666   else if (str != "(not_up-to-date)")
02667     return false;
02668 
02669   if (!gen_sys.ascii_load(s))
02670     return false;
02671 
02672   if (!(s >> str) || str != "dimension_kinds")
02673     return false;
02674 
02675   if (!marked_empty()
02676       && ((generators_are_up_to_date() && generators_are_minimized())
02677           || (congruences_are_up_to_date() && congruences_are_minimized()))) {
02678     dim_kinds.resize(space_dim + 1);
02679     for (Dimension_Kinds::size_type dim = 0; dim <= space_dim; ++dim) {
02680       short unsigned int dim_kind;
02681       if (!(s >> dim_kind))
02682         return false;
02683       switch(dim_kind) {
02684       case 0: dim_kinds[dim] = PARAMETER; break;
02685       case 1: dim_kinds[dim] = LINE; break;
02686       case 2: dim_kinds[dim] = GEN_VIRTUAL; break;
02687       default: return false;
02688       }
02689     }
02690   }
02691 
02692   // Check invariants.
02693   PPL_ASSERT(OK());
02694   return true;
02695 }
02696 
02697 PPL::memory_size_type
02698 PPL::Grid::external_memory_in_bytes() const {
02699   return
02700     con_sys.external_memory_in_bytes()
02701     + gen_sys.external_memory_in_bytes();
02702 }
02703 
02704 void
02705 PPL::Grid::wrap_assign(const Variables_Set& vars,
02706                        Bounded_Integer_Type_Width w,
02707                        Bounded_Integer_Type_Representation r,
02708                        Bounded_Integer_Type_Overflow o,
02709                        const Constraint_System* cs_p,
02710                        unsigned /* complexity_threshold */,
02711                        bool /* wrap_individually */) {
02712 
02713   // Dimension-compatibility check of `*cs_p', if any.
02714   if (cs_p != 0) {
02715     const dimension_type cs_p_space_dim  = cs_p->space_dimension();
02716     if (cs_p->space_dimension() > space_dim)
02717       throw_dimension_incompatible("wrap_assign(vs, ...)", cs_p_space_dim);
02718   }
02719 
02720   // Wrapping no variable is a no-op.
02721   if (vars.empty())
02722     return;
02723 
02724   // Dimension-compatibility check of `vars'.
02725   const dimension_type min_space_dim = vars.space_dimension();
02726   if (space_dim < min_space_dim)
02727     throw_dimension_incompatible("wrap_assign(vs, ...)", min_space_dim);
02728 
02729   // Wrapping an empty grid is a no-op.
02730   if (marked_empty())
02731     return;
02732   if (!generators_are_minimized() && !minimize())
02733     // Minimizing found `this' empty.
02734     return;
02735 
02736   // Set the wrap frequency for variables of width `w'.
02737   // This is independent of the signedness `s'.
02738   PPL_DIRTY_TEMP_COEFFICIENT(wrap_frequency);
02739   mul_2exp_assign(wrap_frequency, Coefficient_one(), w);
02740   // Set `min_value' and `max_value' to the minimum and maximum values
02741   // a variable of width `w' and signedness `s' can take.
02742   PPL_DIRTY_TEMP_COEFFICIENT(min_value);
02743   PPL_DIRTY_TEMP_COEFFICIENT(max_value);
02744   if (r == UNSIGNED) {
02745     min_value = 0;
02746     mul_2exp_assign(max_value, Coefficient_one(), w);
02747     --max_value;
02748   }
02749   else {
02750     PPL_ASSERT(r == SIGNED_2_COMPLEMENT);
02751     mul_2exp_assign(max_value, Coefficient_one(), w-1);
02752     neg_assign(min_value, max_value);
02753     --max_value;
02754   }
02755 
02756   // Generators are up-to-date and minimized.
02757   const Grid gr = *this;
02758 
02759   // Overflow is impossible or wraps.
02760   if (o == OVERFLOW_IMPOSSIBLE || o == OVERFLOW_WRAPS) {
02761     PPL_DIRTY_TEMP_COEFFICIENT(f_n);
02762     PPL_DIRTY_TEMP_COEFFICIENT(f_d);
02763     PPL_DIRTY_TEMP_COEFFICIENT(v_n);
02764     PPL_DIRTY_TEMP_COEFFICIENT(v_d);
02765     for (Variables_Set::const_iterator i = vars.begin(),
02766            vars_end = vars.end(); i != vars_end; ++i) {
02767       const Variable x(*i);
02768       // Find the frequency and a value for `x' in `gr'.
02769       if (!gr.frequency_no_check(x, f_n, f_d, v_n, v_d))
02770         continue;
02771       if (f_n == 0) {
02772 
02773         // `x' is a constant in `gr'.
02774         if (v_d != 1) {
02775           // The value for `x' is not integral (`frequency_no_check()'
02776           // ensures that `v_n' and `v_d' have no common divisors).
02777           set_empty();
02778           return;
02779         }
02780 
02781         // `x' is a constant and has an integral value.
02782         if ((v_n > max_value) || (v_n < min_value)) {
02783           // The value is outside the range of the bounded integer type.
02784           if (o == OVERFLOW_IMPOSSIBLE) {
02785             // Then `x' has no possible value and hence set empty.
02786             set_empty();
02787             return;
02788           }
02789           PPL_ASSERT(o == OVERFLOW_WRAPS);
02790           // The value v_n for `x' is wrapped modulo the 'wrap_frequency'.
02791           v_n %= wrap_frequency;
02792           // `v_n' is the value closest to 0 and may be negative.
02793           if (r == UNSIGNED && v_n < 0)
02794             v_n += wrap_frequency;
02795           unconstrain(x);
02796           add_constraint(x == v_n);
02797         }
02798         continue;
02799       }
02800 
02801       // `x' is not a constant in `gr'.
02802       PPL_ASSERT(f_n != 0);
02803 
02804       if (f_d % v_d != 0) {
02805         // Then `x' has no integral value and hence `gr' is set empty.
02806         set_empty();
02807         return;
02808       }
02809       if (f_d != 1) {
02810         // `x' has non-integral values, so add the integrality
02811         // congruence for `x'.
02812         add_congruence((x %= 0) / 1);
02813       }
02814       if (o == OVERFLOW_WRAPS && f_n != wrap_frequency)
02815         // We know that `x' is not a constant, so, if overflow wraps,
02816         // `x' may wrap to a value modulo the `wrap_frequency'.
02817         add_grid_generator(parameter(wrap_frequency * x));
02818       else if ((o == OVERFLOW_IMPOSSIBLE && 2*f_n >= wrap_frequency)
02819                || (f_n == wrap_frequency)) {
02820         // In these cases, `x' can only take a unique (ie constant)
02821         // value.
02822         if (r == UNSIGNED && v_n < 0) {
02823           // `v_n' is the value closest to 0 and may be negative.
02824           v_n += f_n;
02825         }
02826         unconstrain(x);
02827         add_constraint(x == v_n);
02828       }
02829       else {
02830         // If overflow is impossible but the grid frequency is less than
02831         // half the wrap frequency, then there is more than one possible
02832         // value for `x' in the range of the bounded integer type,
02833         // so the grid is unchanged.
02834         PPL_ASSERT(o == OVERFLOW_IMPOSSIBLE && 2*f_n < wrap_frequency);
02835       }
02836     }
02837     return;
02838   }
02839 
02840   PPL_ASSERT(o == OVERFLOW_UNDEFINED);
02841   // If overflow is undefined, then all we know is that the variable
02842   // may take any integer within the range of the bounded integer type.
02843   const Grid_Generator& point = gr.gen_sys[0];
02844   const Coefficient& div = point.divisor();
02845   max_value *= div;
02846   min_value *= div;
02847   for (Variables_Set::const_iterator i = vars.begin(),
02848          vars_end = vars.end(); i != vars_end; ++i) {
02849     const Variable x(*i);
02850     if (!gr.bounds_no_check(x)) {
02851       // `x' is not a constant in `gr'.
02852       // We know that `x' is not a constant, so `x' may wrap to any
02853       // value `x + z' where z is an integer.
02854       if (point.coefficient(x) % div != 0) {
02855         // We know that `x' can take non-integral values, so enforce
02856         // integrality.
02857         unconstrain(x);
02858         add_congruence(x %= 0);
02859       }
02860       else
02861         // `x' has at least one integral value.
02862         // `x' may also take other non-integral values,
02863         // but checking could be costly so we ignore this.
02864         add_grid_generator(parameter(x));
02865     }
02866     else {
02867       // `x' is a constant `v' in `gr'.
02868       const Coefficient& coeff_x = point.coefficient(x);
02869       // `x' should be integral.
02870       if (coeff_x % div != 0) {
02871         set_empty();
02872         return;
02873       }
02874       // If the value `v' for `x' is not within the range for the
02875       // bounded integer type, then `x' may wrap to any value `v + z'
02876       // where `z' is an integer; otherwise `x' is unchanged.
02877       if (coeff_x > max_value || coeff_x < min_value) {
02878         add_grid_generator(parameter(x));
02879       }
02880     }
02881   }
02882 }
02883 
02884 void
02885 PPL::Grid::drop_some_non_integer_points(Complexity_Class) {
02886   if (marked_empty() || space_dim == 0)
02887     return;
02888 
02889   // By adding integral congruences for each dimension to the
02890   // congruence system, defining \p *this, the grid will keep only
02891   // those points that have integral coordinates. All points in \p
02892   // *this with non-integral coordinates are removed.
02893   for (dimension_type i = space_dim; i-- > 0; )
02894     add_congruence(Variable(i) %= 0);
02895 
02896   PPL_ASSERT(OK());
02897 }
02898 
02899 void
02900 PPL::Grid::drop_some_non_integer_points(const Variables_Set& vars,
02901                                         Complexity_Class) {
02902   // Dimension-compatibility check.
02903   const dimension_type min_space_dim = vars.space_dimension();
02904   if (space_dimension() < min_space_dim)
02905     throw_dimension_incompatible("drop_some_non_integer_points(vs, cmpl)",
02906                                  min_space_dim);
02907 
02908   if (marked_empty() || min_space_dim == 0)
02909     return;
02910 
02911   // By adding the integral congruences for each dimension in vars to
02912   // the congruence system defining \p *this, the grid will keep only
02913   // those points that have integer coordinates for all the dimensions
02914   // in vars. All points in \p *this with non-integral coordinates for
02915   // the dimensions in vars are removed.
02916   for (Variables_Set::const_iterator i = vars.begin(),
02917          vars_end = vars.end(); i != vars_end; ++i)
02918     add_congruence(Variable(*i) %= 0);
02919 
02920   PPL_ASSERT(OK());
02921 }
02922 
02924 std::ostream&
02925 PPL::IO_Operators::operator<<(std::ostream& s, const Grid& gr) {
02926   if (gr.is_empty())
02927     s << "false";
02928   else if (gr.is_universe())
02929     s << "true";
02930   else
02931     s << gr.minimized_congruences();
02932   return s;
02933 }