PPL  0.12.1
Pointset_Powerset.templates.hh
Go to the documentation of this file.
00001 /* Pointset_Powerset class implementation: non-inline template 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 #ifndef PPL_Pointset_Powerset_templates_hh
00025 #define PPL_Pointset_Powerset_templates_hh 1
00026 
00027 #include "Constraint.defs.hh"
00028 #include "Constraint_System.defs.hh"
00029 #include "Constraint_System.inlines.hh"
00030 #include "C_Polyhedron.defs.hh"
00031 #include "NNC_Polyhedron.defs.hh"
00032 #include "Variables_Set.defs.hh"
00033 #include <algorithm>
00034 #include <deque>
00035 #include <string>
00036 #include <iostream>
00037 #include <sstream>
00038 #include <stdexcept>
00039 
00040 namespace Parma_Polyhedra_Library {
00041 
00042 template <typename PSET>
00043 void
00044 Pointset_Powerset<PSET>::add_disjunct(const PSET& ph) {
00045   Pointset_Powerset& x = *this;
00046   if (x.space_dimension() != ph.space_dimension()) {
00047     std::ostringstream s;
00048     s << "PPL::Pointset_Powerset<PSET>::add_disjunct(ph):\n"
00049       << "this->space_dimension() == " << x.space_dimension() << ", "
00050       << "ph.space_dimension() == " << ph.space_dimension() << ".";
00051     throw std::invalid_argument(s.str());
00052   }
00053   x.sequence.push_back(Determinate<PSET>(ph));
00054   x.reduced = false;
00055   PPL_ASSERT_HEAVY(x.OK());
00056 }
00057 
00058 template <>
00059 template <typename QH>
00060 Pointset_Powerset<NNC_Polyhedron>
00061 ::Pointset_Powerset(const Pointset_Powerset<QH>& y,
00062                     Complexity_Class complexity)
00063   : Base(), space_dim(y.space_dimension()) {
00064   Pointset_Powerset& x = *this;
00065   for (typename Pointset_Powerset<QH>::const_iterator i = y.begin(),
00066          y_end = y.end(); i != y_end; ++i)
00067     x.sequence.push_back(Determinate<NNC_Polyhedron>
00068                          (NNC_Polyhedron(i->pointset(), complexity)));
00069 
00070   // FIXME: If the domain elements can be represented _exactly_ as NNC
00071   // polyhedra, then having x.reduced = y.reduced is correct. This is
00072   // the case if the domains are both linear and convex which holds
00073   // for all the currently supported instantiations except for
00074   // Grids; for this reason the Grid specialization has a
00075   // separate implementation.  For any non-linear or non-convex
00076   // domains (e.g., a domain of Intervals with restrictions or a
00077   // domain of circles) that may be supported in the future, the
00078   // assignment x.reduced = y.reduced will be a bug.
00079   x.reduced = y.reduced;
00080 
00081   PPL_ASSERT_HEAVY(x.OK());
00082 }
00083 
00084 template <typename PSET>
00085 template <typename QH>
00086 Pointset_Powerset<PSET>
00087 ::Pointset_Powerset(const Pointset_Powerset<QH>& y,
00088                     Complexity_Class complexity)
00089   : Base(), space_dim(y.space_dimension()) {
00090   Pointset_Powerset& x = *this;
00091   for (typename Pointset_Powerset<QH>::const_iterator i = y.begin(),
00092          y_end = y.end(); i != y_end; ++i)
00093     x.sequence.push_back(Determinate<PSET>(PSET(i->pointset(), complexity)));
00094   // Note: this might be non-reduced even when `y' is known to be
00095   // omega-reduced, because the constructor of PSET may have made
00096   // different QH elements to become comparable.
00097   x.reduced = false;
00098   PPL_ASSERT_HEAVY(x.OK());
00099 }
00100 
00101 template <typename PSET>
00102 void
00103 Pointset_Powerset<PSET>::concatenate_assign(const Pointset_Powerset& y) {
00104   Pointset_Powerset& x = *this;
00105   // Ensure omega-reduction here, since what follows has quadratic complexity.
00106   x.omega_reduce();
00107   y.omega_reduce();
00108   Pointset_Powerset<PSET> new_x(x.space_dim + y.space_dim, EMPTY);
00109   for (const_iterator xi = x.begin(), x_end = x.end(),
00110          y_begin = y.begin(), y_end = y.end(); xi != x_end; ) {
00111     for (const_iterator yi = y_begin; yi != y_end; ++yi) {
00112       Det_PSET zi = *xi;
00113       zi.concatenate_assign(*yi);
00114       PPL_ASSERT_HEAVY(!zi.is_bottom());
00115       new_x.sequence.push_back(zi);
00116     }
00117     ++xi;
00118     if ((abandon_expensive_computations != 0)
00119         && (xi != x_end) && (y_begin != y_end)) {
00120       // Hurry up!
00121       PSET x_ph = xi->pointset();
00122       for (++xi; xi != x_end; ++xi)
00123         x_ph.upper_bound_assign(xi->pointset());
00124       const_iterator yi = y_begin;
00125       PSET y_ph = yi->pointset();
00126       for (++yi; yi != y_end; ++yi)
00127         y_ph.upper_bound_assign(yi->pointset());
00128       x_ph.concatenate_assign(y_ph);
00129       swap(x, new_x);
00130       x.add_disjunct(x_ph);
00131       PPL_ASSERT_HEAVY(x.OK());
00132       return;
00133     }
00134   }
00135   swap(x, new_x);
00136   PPL_ASSERT_HEAVY(x.OK());
00137 }
00138 
00139 template <typename PSET>
00140 void
00141 Pointset_Powerset<PSET>::add_constraint(const Constraint& c) {
00142   Pointset_Powerset& x = *this;
00143   for (Sequence_iterator si = x.sequence.begin(),
00144          s_end = x.sequence.end(); si != s_end; ++si)
00145     si->pointset().add_constraint(c);
00146   x.reduced = false;
00147   PPL_ASSERT_HEAVY(x.OK());
00148 }
00149 
00150 template <typename PSET>
00151 void
00152 Pointset_Powerset<PSET>::refine_with_constraint(const Constraint& c) {
00153   Pointset_Powerset& x = *this;
00154   for (Sequence_iterator si = x.sequence.begin(),
00155          s_end = x.sequence.end(); si != s_end; ++si)
00156     si->pointset().refine_with_constraint(c);
00157   x.reduced = false;
00158   PPL_ASSERT_HEAVY(x.OK());
00159 }
00160 
00161 template <typename PSET>
00162 void
00163 Pointset_Powerset<PSET>::add_constraints(const Constraint_System& cs) {
00164   Pointset_Powerset& x = *this;
00165   for (Sequence_iterator si = x.sequence.begin(),
00166          s_end = x.sequence.end(); si != s_end; ++si)
00167     si->pointset().add_constraints(cs);
00168   x.reduced = false;
00169   PPL_ASSERT_HEAVY(x.OK());
00170 }
00171 
00172 template <typename PSET>
00173 void
00174 Pointset_Powerset<PSET>::refine_with_constraints(const Constraint_System& cs) {
00175   Pointset_Powerset& x = *this;
00176   for (Sequence_iterator si = x.sequence.begin(),
00177          s_end = x.sequence.end(); si != s_end; ++si)
00178     si->pointset().refine_with_constraints(cs);
00179   x.reduced = false;
00180   PPL_ASSERT_HEAVY(x.OK());
00181 }
00182 
00183 template <typename PSET>
00184 void
00185 Pointset_Powerset<PSET>::add_congruence(const Congruence& cg) {
00186   Pointset_Powerset& x = *this;
00187   for (Sequence_iterator si = x.sequence.begin(),
00188          s_end = x.sequence.end(); si != s_end; ++si)
00189     si->pointset().add_congruence(cg);
00190   x.reduced = false;
00191   PPL_ASSERT_HEAVY(x.OK());
00192 }
00193 
00194 template <typename PSET>
00195 void
00196 Pointset_Powerset<PSET>::refine_with_congruence(const Congruence& cg) {
00197   Pointset_Powerset& x = *this;
00198   for (Sequence_iterator si = x.sequence.begin(),
00199          s_end = x.sequence.end(); si != s_end; ++si)
00200     si->pointset().refine_with_congruence(cg);
00201   x.reduced = false;
00202   PPL_ASSERT_HEAVY(x.OK());
00203 }
00204 
00205 template <typename PSET>
00206 void
00207 Pointset_Powerset<PSET>::add_congruences(const Congruence_System& cgs) {
00208   Pointset_Powerset& x = *this;
00209   for (Sequence_iterator si = x.sequence.begin(),
00210          s_end = x.sequence.end(); si != s_end; ++si)
00211     si->pointset().add_congruences(cgs);
00212   x.reduced = false;
00213   PPL_ASSERT_HEAVY(x.OK());
00214 }
00215 
00216 template <typename PSET>
00217 void
00218 Pointset_Powerset<PSET>::refine_with_congruences(const Congruence_System& cgs) {
00219   Pointset_Powerset& x = *this;
00220   for (Sequence_iterator si = x.sequence.begin(),
00221          s_end = x.sequence.end(); si != s_end; ++si)
00222     si->pointset().refine_with_congruences(cgs);
00223   x.reduced = false;
00224   PPL_ASSERT_HEAVY(x.OK());
00225 }
00226 
00227 template <typename PSET>
00228 void
00229 Pointset_Powerset<PSET>::unconstrain(const Variable var) {
00230   Pointset_Powerset& x = *this;
00231   for (Sequence_iterator si = x.sequence.begin(),
00232          s_end = x.sequence.end(); si != s_end; ++si) {
00233     si->pointset().unconstrain(var);
00234     x.reduced = false;
00235   }
00236   PPL_ASSERT_HEAVY(x.OK());
00237 }
00238 
00239 template <typename PSET>
00240 void
00241 Pointset_Powerset<PSET>::unconstrain(const Variables_Set& vars) {
00242   Pointset_Powerset& x = *this;
00243   for (Sequence_iterator si = x.sequence.begin(),
00244          s_end = x.sequence.end(); si != s_end; ++si) {
00245     si->pointset().unconstrain(vars);
00246     x.reduced = false;
00247   }
00248   PPL_ASSERT_HEAVY(x.OK());
00249 }
00250 
00251 template <typename PSET>
00252 void
00253 Pointset_Powerset<PSET>::add_space_dimensions_and_embed(dimension_type m) {
00254   Pointset_Powerset& x = *this;
00255   for (Sequence_iterator si = x.sequence.begin(),
00256          s_end = x.sequence.end(); si != s_end; ++si)
00257     si->pointset().add_space_dimensions_and_embed(m);
00258   x.space_dim += m;
00259   PPL_ASSERT_HEAVY(x.OK());
00260 }
00261 
00262 template <typename PSET>
00263 void
00264 Pointset_Powerset<PSET>::add_space_dimensions_and_project(dimension_type m) {
00265   Pointset_Powerset& x = *this;
00266   for (Sequence_iterator si = x.sequence.begin(),
00267          s_end = x.sequence.end(); si != s_end; ++si)
00268     si->pointset().add_space_dimensions_and_project(m);
00269   x.space_dim += m;
00270   PPL_ASSERT_HEAVY(x.OK());
00271 }
00272 
00273 template <typename PSET>
00274 void
00275 Pointset_Powerset<PSET>::remove_space_dimensions(const Variables_Set& vars) {
00276   Pointset_Powerset& x = *this;
00277   Variables_Set::size_type num_removed = vars.size();
00278   if (num_removed > 0) {
00279     for (Sequence_iterator si = x.sequence.begin(),
00280            s_end = x.sequence.end(); si != s_end; ++si) {
00281       si->pointset().remove_space_dimensions(vars);
00282       x.reduced = false;
00283     }
00284     x.space_dim -= num_removed;
00285     PPL_ASSERT_HEAVY(x.OK());
00286   }
00287 }
00288 
00289 template <typename PSET>
00290 void
00291 Pointset_Powerset<PSET>
00292 ::remove_higher_space_dimensions(dimension_type new_dimension) {
00293   Pointset_Powerset& x = *this;
00294   if (new_dimension < x.space_dim) {
00295     for (Sequence_iterator si = x.sequence.begin(),
00296            s_end = x.sequence.end(); si != s_end; ++si) {
00297       si->pointset().remove_higher_space_dimensions(new_dimension);
00298       x.reduced = false;
00299     }
00300     x.space_dim = new_dimension;
00301     PPL_ASSERT_HEAVY(x.OK());
00302   }
00303 }
00304 
00305 template <typename PSET>
00306 template <typename Partial_Function>
00307 void
00308 Pointset_Powerset<PSET>::map_space_dimensions(const Partial_Function& pfunc) {
00309   Pointset_Powerset& x = *this;
00310   if (x.is_bottom()) {
00311     dimension_type n = 0;
00312     for (dimension_type i = x.space_dim; i-- > 0; ) {
00313       dimension_type new_i;
00314       if (pfunc.maps(i, new_i))
00315         ++n;
00316     }
00317     x.space_dim = n;
00318   }
00319   else {
00320     Sequence_iterator s_begin = x.sequence.begin();
00321     for (Sequence_iterator si = s_begin,
00322            s_end = x.sequence.end(); si != s_end; ++si)
00323       si->pointset().map_space_dimensions(pfunc);
00324     x.space_dim = s_begin->pointset().space_dimension();
00325     x.reduced = false;
00326   }
00327   PPL_ASSERT_HEAVY(x.OK());
00328 }
00329 
00330 template <typename PSET>
00331 void
00332 Pointset_Powerset<PSET>::expand_space_dimension(Variable var,
00333                                                 dimension_type m) {
00334   Pointset_Powerset& x = *this;
00335   for (Sequence_iterator si = x.sequence.begin(),
00336          s_end = x.sequence.end(); si != s_end; ++si)
00337     si->pointset().expand_space_dimension(var, m);
00338   x.space_dim += m;
00339   PPL_ASSERT_HEAVY(x.OK());
00340 }
00341 
00342 template <typename PSET>
00343 void
00344 Pointset_Powerset<PSET>::fold_space_dimensions(const Variables_Set& vars,
00345                                                Variable dest) {
00346   Pointset_Powerset& x = *this;
00347   Variables_Set::size_type num_folded = vars.size();
00348   if (num_folded > 0) {
00349     for (Sequence_iterator si = x.sequence.begin(),
00350            s_end = x.sequence.end(); si != s_end; ++si)
00351       si->pointset().fold_space_dimensions(vars, dest);
00352   }
00353   x.space_dim -= num_folded;
00354   PPL_ASSERT_HEAVY(x.OK());
00355 }
00356 
00357 template <typename PSET>
00358 void
00359 Pointset_Powerset<PSET>::affine_image(Variable var,
00360                                       const Linear_Expression& expr,
00361                                       Coefficient_traits::const_reference
00362                                       denominator) {
00363   Pointset_Powerset& x = *this;
00364   for (Sequence_iterator si = x.sequence.begin(),
00365          s_end = x.sequence.end(); si != s_end; ++si) {
00366     si->pointset().affine_image(var, expr, denominator);
00367     // Note that the underlying domain can apply conservative approximation:
00368     // that is why it would not be correct to make the loss of reduction
00369     // conditional on `var' and `expr'.
00370     x.reduced = false;
00371   }
00372   PPL_ASSERT_HEAVY(x.OK());
00373 }
00374 
00375 template <typename PSET>
00376 void
00377 Pointset_Powerset<PSET>::affine_preimage(Variable var,
00378                                          const Linear_Expression& expr,
00379                                          Coefficient_traits::const_reference
00380                                          denominator) {
00381   Pointset_Powerset& x = *this;
00382   for (Sequence_iterator si = x.sequence.begin(),
00383          s_end = x.sequence.end(); si != s_end; ++si) {
00384     si->pointset().affine_preimage(var, expr, denominator);
00385     // Note that the underlying domain can apply conservative approximation:
00386     // that is why it would not be correct to make the loss of reduction
00387     // conditional on `var' and `expr'.
00388     x.reduced = false;
00389   }
00390   PPL_ASSERT_HEAVY(x.OK());
00391 }
00392 
00393 
00394 template <typename PSET>
00395 void
00396 Pointset_Powerset<PSET>
00397 ::generalized_affine_image(const Linear_Expression& lhs,
00398                            const Relation_Symbol relsym,
00399                            const Linear_Expression& rhs) {
00400   Pointset_Powerset& x = *this;
00401   for (Sequence_iterator si = x.sequence.begin(),
00402          s_end = x.sequence.end(); si != s_end; ++si) {
00403     si->pointset().generalized_affine_image(lhs, relsym, rhs);
00404     x.reduced = false;
00405   }
00406   PPL_ASSERT_HEAVY(x.OK());
00407 }
00408 
00409 template <typename PSET>
00410 void
00411 Pointset_Powerset<PSET>
00412 ::generalized_affine_preimage(const Linear_Expression& lhs,
00413                               const Relation_Symbol relsym,
00414                               const Linear_Expression& rhs) {
00415   Pointset_Powerset& x = *this;
00416   for (Sequence_iterator si = x.sequence.begin(),
00417          s_end = x.sequence.end(); si != s_end; ++si) {
00418     si->pointset().generalized_affine_preimage(lhs, relsym, rhs);
00419     x.reduced = false;
00420   }
00421   PPL_ASSERT_HEAVY(x.OK());
00422 }
00423 
00424 template <typename PSET>
00425 void
00426 Pointset_Powerset<PSET>
00427 ::generalized_affine_image(Variable var,
00428                            const Relation_Symbol relsym,
00429                            const Linear_Expression& expr,
00430                            Coefficient_traits::const_reference denominator) {
00431   Pointset_Powerset& x = *this;
00432   for (Sequence_iterator si = x.sequence.begin(),
00433          s_end = x.sequence.end(); si != s_end; ++si) {
00434     si->pointset().generalized_affine_image(var, relsym, expr, denominator);
00435     x.reduced = false;
00436   }
00437   PPL_ASSERT_HEAVY(x.OK());
00438 }
00439 
00440 template <typename PSET>
00441 void
00442 Pointset_Powerset<PSET>
00443 ::generalized_affine_preimage(Variable var,
00444                               const Relation_Symbol relsym,
00445                               const Linear_Expression& expr,
00446                               Coefficient_traits::const_reference
00447                               denominator) {
00448   Pointset_Powerset& x = *this;
00449   for (Sequence_iterator si = x.sequence.begin(),
00450          s_end = x.sequence.end(); si != s_end; ++si) {
00451     si->pointset().generalized_affine_preimage(var, relsym, expr, denominator);
00452     x.reduced = false;
00453   }
00454   PPL_ASSERT_HEAVY(x.OK());
00455 }
00456 
00457 
00458 template <typename PSET>
00459 void
00460 Pointset_Powerset<PSET>
00461 ::bounded_affine_image(Variable var,
00462                        const Linear_Expression& lb_expr,
00463                        const Linear_Expression& ub_expr,
00464                        Coefficient_traits::const_reference denominator) {
00465   Pointset_Powerset& x = *this;
00466   for (Sequence_iterator si = x.sequence.begin(),
00467          s_end = x.sequence.end(); si != s_end; ++si) {
00468     si->pointset().bounded_affine_image(var, lb_expr, ub_expr, denominator);
00469     x.reduced = false;
00470   }
00471   PPL_ASSERT_HEAVY(x.OK());
00472 }
00473 
00474 template <typename PSET>
00475 void
00476 Pointset_Powerset<PSET>
00477 ::bounded_affine_preimage(Variable var,
00478                           const Linear_Expression& lb_expr,
00479                           const Linear_Expression& ub_expr,
00480                           Coefficient_traits::const_reference denominator) {
00481   Pointset_Powerset& x = *this;
00482   for (Sequence_iterator si = x.sequence.begin(),
00483          s_end = x.sequence.end(); si != s_end; ++si) {
00484     si->pointset().bounded_affine_preimage(var, lb_expr, ub_expr,
00485                                           denominator);
00486     x.reduced = false;
00487   }
00488   PPL_ASSERT_HEAVY(x.OK());
00489 }
00490 
00491 template <typename PSET>
00492 dimension_type
00493 Pointset_Powerset<PSET>::affine_dimension() const {
00494   // The affine dimension of the powerset is the affine dimension of
00495   // the smallest vector space in which it can be embedded.
00496   const Pointset_Powerset& x = *this;
00497   C_Polyhedron x_ph(space_dim, EMPTY);
00498 
00499   for (Sequence_const_iterator si = x.sequence.begin(),
00500          s_end = x.sequence.end(); si != s_end; ++si) {
00501     PSET pi(si->pointset());
00502     if (!pi.is_empty()) {
00503       C_Polyhedron phi(space_dim);
00504       const Constraint_System& cs = pi.minimized_constraints();
00505       for (Constraint_System::const_iterator i = cs.begin(),
00506              cs_end = cs.end(); i != cs_end; ++i) {
00507         const Constraint& c = *i;
00508         if (c.is_equality())
00509           phi.add_constraint(c);
00510       }
00511       x_ph.poly_hull_assign(phi);
00512     }
00513   }
00514 
00515   return x_ph.affine_dimension();
00516 }
00517 
00518 template <typename PSET>
00519 bool
00520 Pointset_Powerset<PSET>::is_universe() const {
00521   const Pointset_Powerset& x = *this;
00522   // Exploit omega-reduction, if already computed.
00523   if (x.is_omega_reduced())
00524     return x.size() == 1 && x.begin()->pointset().is_universe();
00525 
00526   // A powerset is universe iff one of its disjuncts is.
00527   for (const_iterator x_i = x.begin(), x_end = x.end(); x_i != x_end; ++x_i)
00528     if (x_i->pointset().is_universe()) {
00529       // Speculative omega-reduction, if it is worth.
00530       if (x.size() > 1) {
00531         Pointset_Powerset<PSET> universe(x.space_dimension(), UNIVERSE);
00532         Pointset_Powerset& xx = const_cast<Pointset_Powerset&>(x);
00533         swap(xx, universe);
00534       }
00535       return true;
00536     }
00537   return false;
00538 }
00539 
00540 template <typename PSET>
00541 bool
00542 Pointset_Powerset<PSET>::is_empty() const {
00543   const Pointset_Powerset& x = *this;
00544   for (Sequence_const_iterator si = x.sequence.begin(),
00545          s_end = x.sequence.end(); si != s_end; ++si)
00546     if (!si->pointset().is_empty())
00547       return false;
00548   return true;
00549 }
00550 
00551 template <typename PSET>
00552 bool
00553 Pointset_Powerset<PSET>::is_discrete() const {
00554   const Pointset_Powerset& x = *this;
00555   for (Sequence_const_iterator si = x.sequence.begin(),
00556          s_end = x.sequence.end(); si != s_end; ++si)
00557     if (!si->pointset().is_discrete())
00558       return false;
00559   return true;
00560 }
00561 
00562 template <typename PSET>
00563 bool
00564 Pointset_Powerset<PSET>::is_topologically_closed() const {
00565   const Pointset_Powerset& x = *this;
00566   // The powerset must be omega-reduced before checking
00567   // topological closure.
00568   x.omega_reduce();
00569   for (Sequence_const_iterator si = x.sequence.begin(),
00570          s_end = x.sequence.end(); si != s_end; ++si)
00571     if (!si->pointset().is_topologically_closed())
00572       return false;
00573   return true;
00574 }
00575 
00576 template <typename PSET>
00577 bool
00578 Pointset_Powerset<PSET>::is_bounded() const {
00579   const Pointset_Powerset& x = *this;
00580   for (Sequence_const_iterator si = x.sequence.begin(),
00581          s_end = x.sequence.end(); si != s_end; ++si)
00582     if (!si->pointset().is_bounded())
00583       return false;
00584   return true;
00585 }
00586 
00587 template <typename PSET>
00588 bool
00589 Pointset_Powerset<PSET>::constrains(Variable var) const {
00590   const Pointset_Powerset& x = *this;
00591   // `var' should be one of the dimensions of the powerset.
00592   const dimension_type var_space_dim = var.space_dimension();
00593   if (x.space_dimension() < var_space_dim) {
00594     std::ostringstream s;
00595     s << "PPL::Pointset_Powerset<PSET>::constrains(v):\n"
00596       << "this->space_dimension() == " << x.space_dimension() << ", "
00597       << "v.space_dimension() == " << var_space_dim << ".";
00598     throw std::invalid_argument(s.str());
00599   }
00600   // omega_reduction needed, since a redundant disjunct may constrain var.
00601   x.omega_reduce();
00602   // An empty powerset constrains all variables.
00603   if (x.is_empty())
00604     return true;
00605   for (const_iterator x_i = x.begin(), x_end = x.end(); x_i != x_end; ++x_i)
00606     if (x_i->pointset().constrains(var))
00607       return true;
00608   return false;
00609 }
00610 
00611 template <typename PSET>
00612 bool
00613 Pointset_Powerset<PSET>::is_disjoint_from(const Pointset_Powerset& y) const {
00614   const Pointset_Powerset& x = *this;
00615   for (Sequence_const_iterator si = x.sequence.begin(),
00616          x_s_end = x.sequence.end(); si != x_s_end; ++si) {
00617     const PSET& pi = si->pointset();
00618     for (Sequence_const_iterator sj = y.sequence.begin(),
00619            y_s_end = y.sequence.end(); sj != y_s_end; ++sj) {
00620       const PSET& pj = sj->pointset();
00621       if (!pi.is_disjoint_from(pj))
00622         return false;
00623     }
00624   }
00625   return true;
00626 }
00627 
00628 template <typename PSET>
00629 void
00630 Pointset_Powerset<PSET>
00631 ::drop_some_non_integer_points(const Variables_Set& vars,
00632                                Complexity_Class complexity) {
00633   Pointset_Powerset& x = *this;
00634   for (Sequence_iterator si = x.sequence.begin(),
00635          s_end = x.sequence.end(); si != s_end; ++si)
00636     si->pointset().drop_some_non_integer_points(vars, complexity);
00637   x.reduced = false;
00638   PPL_ASSERT_HEAVY(x.OK());
00639 }
00640 
00641 template <typename PSET>
00642 void
00643 Pointset_Powerset<PSET>
00644 ::drop_some_non_integer_points(Complexity_Class complexity) {
00645   Pointset_Powerset& x = *this;
00646   for (Sequence_iterator si = x.sequence.begin(),
00647          s_end = x.sequence.end(); si != s_end; ++si)
00648     si->pointset().drop_some_non_integer_points(complexity);
00649   x.reduced = false;
00650   PPL_ASSERT_HEAVY(x.OK());
00651 }
00652 
00653 template <typename PSET>
00654 void
00655 Pointset_Powerset<PSET>::topological_closure_assign() {
00656   Pointset_Powerset& x = *this;
00657   for (Sequence_iterator si = x.sequence.begin(),
00658          s_end = x.sequence.end(); si != s_end; ++si)
00659     si->pointset().topological_closure_assign();
00660   PPL_ASSERT_HEAVY(x.OK());
00661 }
00662 
00663 template <typename PSET>
00664 bool
00665 Pointset_Powerset<PSET>
00666 ::intersection_preserving_enlarge_element(PSET& dest) const {
00667   // FIXME: this is just an executable specification.
00668   const Pointset_Powerset& context = *this;
00669   PPL_ASSERT(context.space_dimension() == dest.space_dimension());
00670   bool nonempty_intersection = false;
00671   // TODO: maybe use a *sorted* constraint system?
00672   PSET enlarged(context.space_dimension(), UNIVERSE);
00673   for (Sequence_const_iterator si = context.sequence.begin(),
00674          s_end = context.sequence.end(); si != s_end; ++si) {
00675     PSET context_i(si->pointset());
00676     context_i.intersection_assign(enlarged);
00677     PSET enlarged_i(dest);
00678     if (enlarged_i.simplify_using_context_assign(context_i))
00679       nonempty_intersection = true;
00680     // TODO: merge the sorted constraints of `enlarged' and `enlarged_i'?
00681     enlarged.intersection_assign(enlarged_i);
00682   }
00683   swap(dest, enlarged);
00684   return nonempty_intersection;
00685 }
00686 
00687 template <typename PSET>
00688 bool
00689 Pointset_Powerset<PSET>
00690 ::simplify_using_context_assign(const Pointset_Powerset& y) {
00691   Pointset_Powerset& x = *this;
00692 
00693   // Omega reduction is required.
00694   // TODO: check whether it would be more efficient to Omega-reduce x
00695   // during the simplification process: when examining *si, we check
00696   // if it has been made redundant by any of the elements preceding it
00697   // (which have been already simplified).
00698   x.omega_reduce();
00699   if (x.is_empty())
00700     return false;
00701   y.omega_reduce();
00702   if (y.is_empty()) {
00703     x = y;
00704     return false;
00705   }
00706 
00707   if (y.size() == 1) {
00708     // More efficient, special handling of the singleton context case.
00709     const PSET& y_i = y.sequence.begin()->pointset();
00710     for (Sequence_iterator si = x.sequence.begin(),
00711            s_end = x.sequence.end(); si != s_end; ) {
00712       PSET& x_i = si->pointset();
00713       if (x_i.simplify_using_context_assign(y_i))
00714         ++si;
00715       else
00716         // Intersection is empty: drop the disjunct.
00717         si = x.sequence.erase(si);
00718     }
00719   }
00720   else {
00721     // The context is not a singleton.
00722     for (Sequence_iterator si = x.sequence.begin(),
00723            s_end = x.sequence.end(); si != s_end; ) {
00724       if (y.intersection_preserving_enlarge_element(si->pointset()))
00725         ++si;
00726       else
00727         // Intersection with `*si' is empty: drop the disjunct.
00728         si = x.sequence.erase(si);
00729     }
00730   }
00731   x.reduced = false;
00732   PPL_ASSERT_HEAVY(x.OK());
00733   return !x.sequence.empty();
00734 }
00735 
00736 template <typename PSET>
00737 bool
00738 Pointset_Powerset<PSET>::contains(const Pointset_Powerset& y) const {
00739   const Pointset_Powerset& x = *this;
00740   for (Sequence_const_iterator si = y.sequence.begin(),
00741          y_s_end = y.sequence.end(); si != y_s_end; ++si) {
00742     const PSET& pi = si->pointset();
00743     bool pi_is_contained = false;
00744     for (Sequence_const_iterator sj = x.sequence.begin(),
00745            x_s_end = x.sequence.end();
00746          (sj != x_s_end && !pi_is_contained);
00747          ++sj) {
00748       const PSET& pj = sj->pointset();
00749       if (pj.contains(pi))
00750         pi_is_contained = true;
00751     }
00752     if (!pi_is_contained)
00753       return false;
00754   }
00755   return true;
00756 }
00757 
00758 template <typename PSET>
00759 bool
00760 Pointset_Powerset<PSET>::strictly_contains(const Pointset_Powerset& y) const {
00761   /* omega reduction ensures that a disjunct of y cannot be strictly
00762      contained in one disjunct and also contained but not strictly
00763      contained in another disjunct of *this */
00764   const Pointset_Powerset& x = *this;
00765   x.omega_reduce();
00766   for (Sequence_const_iterator si = y.sequence.begin(),
00767          y_s_end = y.sequence.end(); si != y_s_end; ++si) {
00768     const PSET& pi = si->pointset();
00769     bool pi_is_strictly_contained = false;
00770     for (Sequence_const_iterator sj = x.sequence.begin(),
00771            x_s_end = x.sequence.end();
00772          (sj != x_s_end && !pi_is_strictly_contained); ++sj) {
00773       const PSET& pj = sj->pointset();
00774       if (pj.strictly_contains(pi))
00775         pi_is_strictly_contained = true;
00776     }
00777     if (!pi_is_strictly_contained)
00778       return false;
00779   }
00780   return true;
00781 }
00782 
00783 template <typename PSET>
00784 Poly_Con_Relation
00785 Pointset_Powerset<PSET>::relation_with(const Congruence& cg) const {
00786   const Pointset_Powerset& x = *this;
00787 
00788   /* *this is included in cg if every disjunct is included in cg */
00789   bool is_included = true;
00790   /* *this is disjoint with cg if every disjunct is disjoint with cg */
00791   bool is_disjoint = true;
00792   /* *this strictly_intersects with cg if some disjunct strictly
00793      intersects with cg */
00794   bool is_strictly_intersecting = false;
00795   /* *this saturates cg if some disjunct saturates cg and
00796      every disjunct is either disjoint from cg or saturates cg */
00797   bool saturates_once = false;
00798   bool may_saturate = true;
00799   for (Sequence_const_iterator si = x.sequence.begin(),
00800          s_end = x.sequence.end(); si != s_end; ++si) {
00801     Poly_Con_Relation relation_i = si->pointset().relation_with(cg);
00802     if (!relation_i.implies(Poly_Con_Relation::is_included()))
00803       is_included = false;
00804     if (!relation_i.implies(Poly_Con_Relation::is_disjoint()))
00805       is_disjoint = false;
00806     if (relation_i.implies(Poly_Con_Relation::strictly_intersects()))
00807       is_strictly_intersecting = true;
00808     if (relation_i.implies(Poly_Con_Relation::saturates()))
00809       saturates_once = true;
00810     else if (!relation_i.implies(Poly_Con_Relation::is_disjoint()))
00811       may_saturate = false;
00812   }
00813 
00814   Poly_Con_Relation result = Poly_Con_Relation::nothing();
00815   if (is_included)
00816     result = result && Poly_Con_Relation::is_included();
00817   if (is_disjoint)
00818     result = result && Poly_Con_Relation::is_disjoint();
00819   if (is_strictly_intersecting)
00820     result = result && Poly_Con_Relation::strictly_intersects();
00821   if (saturates_once && may_saturate)
00822     result = result && Poly_Con_Relation::saturates();
00823 
00824   return result;
00825 }
00826 
00827 template <typename PSET>
00828 Poly_Con_Relation
00829 Pointset_Powerset<PSET>::relation_with(const Constraint& c) const {
00830   const Pointset_Powerset& x = *this;
00831 
00832   /* *this is included in c if every disjunct is included in c */
00833   bool is_included = true;
00834   /* *this is disjoint with c if every disjunct is disjoint with c */
00835   bool is_disjoint = true;
00836   /* *this strictly_intersects with c if some disjunct strictly
00837      intersects with c */
00838   bool is_strictly_intersecting = false;
00839   /* *this saturates c if some disjunct saturates c and
00840      every disjunct is either disjoint from c or saturates c */
00841   bool saturates_once = false;
00842   bool may_saturate = true;
00843   for (Sequence_const_iterator si = x.sequence.begin(),
00844          s_end = x.sequence.end(); si != s_end; ++si) {
00845     Poly_Con_Relation relation_i = si->pointset().relation_with(c);
00846     if (!relation_i.implies(Poly_Con_Relation::is_included()))
00847       is_included = false;
00848     if (!relation_i.implies(Poly_Con_Relation::is_disjoint()))
00849       is_disjoint = false;
00850     if (relation_i.implies(Poly_Con_Relation::strictly_intersects()))
00851       is_strictly_intersecting = true;
00852     if (relation_i.implies(Poly_Con_Relation::saturates()))
00853       saturates_once = true;
00854     else if (!relation_i.implies(Poly_Con_Relation::is_disjoint()))
00855       may_saturate = false;
00856   }
00857 
00858   Poly_Con_Relation result = Poly_Con_Relation::nothing();
00859   if (is_included)
00860     result = result && Poly_Con_Relation::is_included();
00861   if (is_disjoint)
00862     result = result && Poly_Con_Relation::is_disjoint();
00863   if (is_strictly_intersecting)
00864     result = result && Poly_Con_Relation::strictly_intersects();
00865   if (saturates_once && may_saturate)
00866     result = result && Poly_Con_Relation::saturates();
00867 
00868   return result;
00869 }
00870 
00871 template <typename PSET>
00872 Poly_Gen_Relation
00873 Pointset_Powerset<PSET>::relation_with(const Generator& g) const {
00874   const Pointset_Powerset& x = *this;
00875 
00876   for (Sequence_const_iterator si = x.sequence.begin(),
00877          s_end = x.sequence.end(); si != s_end; ++si) {
00878     Poly_Gen_Relation relation_i = si->pointset().relation_with(g);
00879     if (relation_i.implies(Poly_Gen_Relation::subsumes()))
00880       return Poly_Gen_Relation::subsumes();
00881   }
00882 
00883   return Poly_Gen_Relation::nothing();
00884 }
00885 
00886 template <typename PSET>
00887 bool
00888 Pointset_Powerset<PSET>
00889 ::bounds_from_above(const Linear_Expression& expr) const {
00890   const Pointset_Powerset& x = *this;
00891   x.omega_reduce();
00892   for (Sequence_const_iterator si = x.sequence.begin(),
00893          s_end = x.sequence.end(); si != s_end; ++si)
00894     if (!si->pointset().bounds_from_above(expr))
00895       return false;
00896   return true;
00897 }
00898 
00899 template <typename PSET>
00900 bool
00901 Pointset_Powerset<PSET>
00902 ::bounds_from_below(const Linear_Expression& expr) const {
00903   const Pointset_Powerset& x = *this;
00904   x.omega_reduce();
00905   for (Sequence_const_iterator si = x.sequence.begin(),
00906          s_end = x.sequence.end(); si != s_end; ++si)
00907     if (!si->pointset().bounds_from_below(expr))
00908       return false;
00909   return true;
00910 }
00911 
00912 template <typename PSET>
00913 bool
00914 Pointset_Powerset<PSET>::maximize(const Linear_Expression& expr,
00915                                   Coefficient& sup_n,
00916                                   Coefficient& sup_d,
00917                                   bool& maximum) const {
00918   const Pointset_Powerset& x = *this;
00919   x.omega_reduce();
00920   if (x.is_empty())
00921     return false;
00922 
00923   bool first = true;
00924 
00925   PPL_DIRTY_TEMP_COEFFICIENT(best_sup_n);
00926   PPL_DIRTY_TEMP_COEFFICIENT(best_sup_d);
00927   best_sup_n = 0;
00928   best_sup_d = 1;
00929   bool best_max = false;
00930 
00931   PPL_DIRTY_TEMP_COEFFICIENT(iter_sup_n);
00932   PPL_DIRTY_TEMP_COEFFICIENT(iter_sup_d);
00933   iter_sup_n = 0;
00934   iter_sup_d = 1;
00935   bool iter_max = false;
00936 
00937   PPL_DIRTY_TEMP_COEFFICIENT(tmp);
00938 
00939   for (Sequence_const_iterator si = x.sequence.begin(),
00940          s_end = x.sequence.end(); si != s_end; ++si) {
00941     if (!si->pointset().maximize(expr, iter_sup_n, iter_sup_d, iter_max))
00942       return false;
00943     else
00944       if (first) {
00945         first = false;
00946         best_sup_n = iter_sup_n;
00947         best_sup_d = iter_sup_d;
00948         best_max = iter_max;
00949       }
00950       else {
00951         tmp = (best_sup_n * iter_sup_d) - (iter_sup_n * best_sup_d);
00952         if (tmp < 0) {
00953           best_sup_n = iter_sup_n;
00954           best_sup_d = iter_sup_d;
00955           best_max = iter_max;
00956         }
00957         else if (tmp == 0)
00958           best_max = (best_max || iter_max);
00959       }
00960   }
00961   sup_n = best_sup_n;
00962   sup_d = best_sup_d;
00963   maximum = best_max;
00964   return true;
00965 }
00966 
00967 template <typename PSET>
00968 bool
00969 Pointset_Powerset<PSET>::maximize(const Linear_Expression& expr,
00970                                   Coefficient& sup_n,
00971                                   Coefficient& sup_d,
00972                                   bool& maximum,
00973                                   Generator& g) const {
00974   const Pointset_Powerset& x = *this;
00975   x.omega_reduce();
00976   if (x.is_empty())
00977     return false;
00978 
00979   bool first = true;
00980 
00981   PPL_DIRTY_TEMP_COEFFICIENT(best_sup_n);
00982   PPL_DIRTY_TEMP_COEFFICIENT(best_sup_d);
00983   best_sup_n = 0;
00984   best_sup_d = 1;
00985   bool best_max = false;
00986   Generator best_g = point();
00987 
00988   PPL_DIRTY_TEMP_COEFFICIENT(iter_sup_n);
00989   PPL_DIRTY_TEMP_COEFFICIENT(iter_sup_d);
00990   iter_sup_n = 0;
00991   iter_sup_d = 1;
00992   bool iter_max = false;
00993   Generator iter_g = point();
00994 
00995   PPL_DIRTY_TEMP_COEFFICIENT(tmp);
00996 
00997   for (Sequence_const_iterator si = x.sequence.begin(),
00998          s_end = x.sequence.end(); si != s_end; ++si) {
00999     if (!si->pointset().maximize(expr,
01000                                  iter_sup_n, iter_sup_d, iter_max, iter_g))
01001       return false;
01002     else
01003       if (first) {
01004         first = false;
01005         best_sup_n = iter_sup_n;
01006         best_sup_d = iter_sup_d;
01007         best_max = iter_max;
01008         best_g = iter_g;
01009       }
01010       else {
01011         tmp = (best_sup_n * iter_sup_d) - (iter_sup_n * best_sup_d);
01012         if (tmp < 0) {
01013           best_sup_n = iter_sup_n;
01014           best_sup_d = iter_sup_d;
01015           best_max = iter_max;
01016           best_g = iter_g;
01017         }
01018         else if (tmp == 0) {
01019           best_max = (best_max || iter_max);
01020           best_g = iter_g;
01021         }
01022       }
01023   }
01024   sup_n = best_sup_n;
01025   sup_d = best_sup_d;
01026   maximum = best_max;
01027   g = best_g;
01028   return true;
01029 }
01030 
01031 template <typename PSET>
01032 bool
01033 Pointset_Powerset<PSET>::minimize(const Linear_Expression& expr,
01034                                   Coefficient& inf_n,
01035                                   Coefficient& inf_d,
01036                                   bool& minimum) const {
01037   const Pointset_Powerset& x = *this;
01038   x.omega_reduce();
01039   if (x.is_empty())
01040     return false;
01041 
01042   bool first = true;
01043 
01044   PPL_DIRTY_TEMP_COEFFICIENT(best_inf_n);
01045   PPL_DIRTY_TEMP_COEFFICIENT(best_inf_d);
01046   best_inf_n = 0;
01047   best_inf_d = 1;
01048   bool best_min = false;
01049 
01050   PPL_DIRTY_TEMP_COEFFICIENT(iter_inf_n);
01051   PPL_DIRTY_TEMP_COEFFICIENT(iter_inf_d);
01052   iter_inf_n = 0;
01053   iter_inf_d = 1;
01054   bool iter_min = false;
01055 
01056   PPL_DIRTY_TEMP_COEFFICIENT(tmp);
01057 
01058   for (Sequence_const_iterator si = x.sequence.begin(),
01059          s_end = x.sequence.end(); si != s_end; ++si) {
01060     if (!si->pointset().minimize(expr, iter_inf_n, iter_inf_d, iter_min))
01061       return false;
01062     else
01063       if (first) {
01064         first = false;
01065         best_inf_n = iter_inf_n;
01066         best_inf_d = iter_inf_d;
01067         best_min = iter_min;
01068       }
01069       else {
01070         tmp = (best_inf_n * iter_inf_d) - (iter_inf_n * best_inf_d);
01071         if (tmp > 0) {
01072           best_inf_n = iter_inf_n;
01073           best_inf_d = iter_inf_d;
01074           best_min = iter_min;
01075         }
01076         else if (tmp == 0)
01077           best_min = (best_min || iter_min);
01078       }
01079   }
01080   inf_n = best_inf_n;
01081   inf_d = best_inf_d;
01082   minimum = best_min;
01083   return true;
01084 }
01085 
01086 template <typename PSET>
01087 bool
01088 Pointset_Powerset<PSET>::minimize(const Linear_Expression& expr,
01089                                   Coefficient& inf_n,
01090                                   Coefficient& inf_d,
01091                                   bool& minimum,
01092                                   Generator& g) const {
01093   const Pointset_Powerset& x = *this;
01094   x.omega_reduce();
01095   if (x.is_empty())
01096     return false;
01097 
01098   bool first = true;
01099 
01100   PPL_DIRTY_TEMP_COEFFICIENT(best_inf_n);
01101   PPL_DIRTY_TEMP_COEFFICIENT(best_inf_d);
01102   best_inf_n = 0;
01103   best_inf_d = 1;
01104   bool best_min = false;
01105   Generator best_g = point();
01106 
01107   PPL_DIRTY_TEMP_COEFFICIENT(iter_inf_n);
01108   PPL_DIRTY_TEMP_COEFFICIENT(iter_inf_d);
01109   iter_inf_n = 0;
01110   iter_inf_d = 1;
01111   bool iter_min = false;
01112   Generator iter_g = point();
01113 
01114   PPL_DIRTY_TEMP_COEFFICIENT(tmp);
01115 
01116   for (Sequence_const_iterator si = x.sequence.begin(),
01117          s_end = x.sequence.end(); si != s_end; ++si) {
01118     if (!si->pointset().minimize(expr,
01119                                  iter_inf_n, iter_inf_d, iter_min, iter_g))
01120       return false;
01121     else
01122       if (first) {
01123         first = false;
01124         best_inf_n = iter_inf_n;
01125         best_inf_d = iter_inf_d;
01126         best_min = iter_min;
01127         best_g = iter_g;
01128       }
01129       else {
01130         tmp = (best_inf_n * iter_inf_d) - (iter_inf_n * best_inf_d);
01131         if (tmp > 0) {
01132           best_inf_n = iter_inf_n;
01133           best_inf_d = iter_inf_d;
01134           best_min = iter_min;
01135           best_g = iter_g;
01136         }
01137         else if (tmp == 0) {
01138           best_min = (best_min || iter_min);
01139           best_g = iter_g;
01140         }
01141       }
01142   }
01143   inf_n = best_inf_n;
01144   inf_d = best_inf_d;
01145   minimum = best_min;
01146   g = best_g;
01147   return true;
01148 }
01149 
01150 template <typename PSET>
01151 bool
01152 Pointset_Powerset<PSET>::contains_integer_point() const {
01153   const Pointset_Powerset& x = *this;
01154   for (Sequence_const_iterator si = x.sequence.begin(),
01155          s_end = x.sequence.end(); si != s_end; ++si)
01156     if (si->pointset().contains_integer_point())
01157       return true;
01158   return false;
01159 }
01160 
01161 template <typename PSET>
01162 void
01163 Pointset_Powerset<PSET>::wrap_assign(const Variables_Set& vars,
01164                                      Bounded_Integer_Type_Width w,
01165                                      Bounded_Integer_Type_Representation r,
01166                                      Bounded_Integer_Type_Overflow o,
01167                                      const Constraint_System* cs_p,
01168                                      unsigned complexity_threshold,
01169                                      bool wrap_individually) {
01170   Pointset_Powerset& x = *this;
01171   for (Sequence_iterator si = x.sequence.begin(),
01172          s_end = x.sequence.end(); si != s_end; ++si)
01173     si->pointset().wrap_assign(vars, w, r, o, cs_p,
01174                                complexity_threshold, wrap_individually);
01175   x.reduced = false;
01176   PPL_ASSERT_HEAVY(x.OK());
01177 }
01178 
01179 template <typename PSET>
01180 void
01181 Pointset_Powerset<PSET>::pairwise_reduce() {
01182   Pointset_Powerset& x = *this;
01183   // It is wise to omega-reduce before pairwise-reducing.
01184   x.omega_reduce();
01185 
01186   size_type n = x.size();
01187   size_type deleted;
01188   do {
01189     Pointset_Powerset new_x(x.space_dim, EMPTY);
01190     std::deque<bool> marked(n, false);
01191     deleted = 0;
01192     Sequence_iterator s_begin = x.sequence.begin();
01193     Sequence_iterator s_end = x.sequence.end();
01194     unsigned si_index = 0;
01195     for (Sequence_iterator si = s_begin; si != s_end; ++si, ++si_index) {
01196       if (marked[si_index])
01197         continue;
01198       PSET& pi = si->pointset();
01199       Sequence_const_iterator sj = si;
01200       unsigned sj_index = si_index;
01201       for (++sj, ++sj_index; sj != s_end; ++sj, ++sj_index) {
01202         if (marked[sj_index])
01203           continue;
01204         const PSET& pj = sj->pointset();
01205         if (pi.upper_bound_assign_if_exact(pj)) {
01206           marked[si_index] = true;
01207           marked[sj_index] = true;
01208           new_x.add_non_bottom_disjunct_preserve_reduction(pi);
01209           ++deleted;
01210           goto next;
01211         }
01212       }
01213     next:
01214       ;
01215     }
01216     iterator new_x_begin = new_x.begin();
01217     iterator new_x_end = new_x.end();
01218     unsigned xi_index = 0;
01219     for (const_iterator xi = x.begin(),
01220            x_end = x.end(); xi != x_end; ++xi, ++xi_index)
01221       if (!marked[xi_index])
01222         new_x_begin
01223           = new_x.add_non_bottom_disjunct_preserve_reduction(*xi,
01224                                                              new_x_begin,
01225                                                              new_x_end);
01226     using std::swap;
01227     swap(x.sequence, new_x.sequence);
01228     n -= deleted;
01229   } while (deleted > 0);
01230   PPL_ASSERT_HEAVY(x.OK());
01231 }
01232 
01233 template <typename PSET>
01234 template <typename Widening>
01235 void
01236 Pointset_Powerset<PSET>::
01237 BGP99_heuristics_assign(const Pointset_Powerset& y, Widening widen_fun) {
01238   // `x' is the current iteration value.
01239   Pointset_Powerset& x = *this;
01240 
01241 #ifndef NDEBUG
01242   {
01243     // We assume that `y' entails `x'.
01244     const Pointset_Powerset<PSET> x_copy = x;
01245     const Pointset_Powerset<PSET> y_copy = y;
01246     PPL_ASSERT_HEAVY(y_copy.definitely_entails(x_copy));
01247   }
01248 #endif
01249 
01250   size_type n = x.size();
01251   Pointset_Powerset new_x(x.space_dim, EMPTY);
01252   std::deque<bool> marked(n, false);
01253   const_iterator x_begin = x.begin();
01254   const_iterator x_end = x.end();
01255   unsigned i_index = 0;
01256   for (const_iterator i = x_begin,
01257          y_begin = y.begin(), y_end = y.end(); i != x_end; ++i, ++i_index)
01258     for (const_iterator j = y_begin; j != y_end; ++j) {
01259       const PSET& pi = i->pointset();
01260       const PSET& pj = j->pointset();
01261       if (pi.contains(pj)) {
01262         PSET pi_copy = pi;
01263         widen_fun(pi_copy, pj);
01264         new_x.add_non_bottom_disjunct_preserve_reduction(pi_copy);
01265         marked[i_index] = true;
01266       }
01267     }
01268   iterator new_x_begin = new_x.begin();
01269   iterator new_x_end = new_x.end();
01270   i_index = 0;
01271   for (const_iterator i = x_begin; i != x_end; ++i, ++i_index)
01272     if (!marked[i_index])
01273       new_x_begin
01274         = new_x.add_non_bottom_disjunct_preserve_reduction(*i,
01275                                                            new_x_begin,
01276                                                            new_x_end);
01277   using std::swap;
01278   swap(x.sequence, new_x.sequence);
01279   PPL_ASSERT_HEAVY(x.OK());
01280   PPL_ASSERT(x.is_omega_reduced());
01281 }
01282 
01283 template <typename PSET>
01284 template <typename Widening>
01285 void
01286 Pointset_Powerset<PSET>::
01287 BGP99_extrapolation_assign(const Pointset_Powerset& y,
01288                            Widening widen_fun,
01289                            unsigned max_disjuncts) {
01290   // `x' is the current iteration value.
01291   Pointset_Powerset& x = *this;
01292 
01293 #ifndef NDEBUG
01294   {
01295     // We assume that `y' entails `x'.
01296     const Pointset_Powerset<PSET> x_copy = x;
01297     const Pointset_Powerset<PSET> y_copy = y;
01298     PPL_ASSERT_HEAVY(y_copy.definitely_entails(x_copy));
01299   }
01300 #endif
01301 
01302   x.pairwise_reduce();
01303   if (max_disjuncts != 0)
01304     x.collapse(max_disjuncts);
01305   x.BGP99_heuristics_assign(y, widen_fun);
01306 }
01307 
01308 template <typename PSET>
01309 template <typename Cert>
01310 void
01311 Pointset_Powerset<PSET>::
01312 collect_certificates(std::map<Cert, size_type,
01313                      typename Cert::Compare>& cert_ms) const {
01314   const Pointset_Powerset& x = *this;
01315   PPL_ASSERT(x.is_omega_reduced());
01316   PPL_ASSERT(cert_ms.size() == 0);
01317   for (const_iterator i = x.begin(), end = x.end(); i != end; i++) {
01318     Cert ph_cert(i->pointset());
01319     ++cert_ms[ph_cert];
01320   }
01321 }
01322 
01323 template <typename PSET>
01324 template <typename Cert>
01325 bool
01326 Pointset_Powerset<PSET>::
01327 is_cert_multiset_stabilizing(const std::map<Cert, size_type,
01328                              typename Cert::Compare>& y_cert_ms) const {
01329   typedef std::map<Cert, size_type, typename Cert::Compare> Cert_Multiset;
01330   Cert_Multiset x_cert_ms;
01331   collect_certificates(x_cert_ms);
01332   typename Cert_Multiset::const_iterator
01333     xi = x_cert_ms.begin(),
01334     x_cert_ms_end = x_cert_ms.end(),
01335     yi = y_cert_ms.begin(),
01336     y_cert_ms_end = y_cert_ms.end();
01337   while (xi != x_cert_ms_end && yi != y_cert_ms_end) {
01338     const Cert& xi_cert = xi->first;
01339     const Cert& yi_cert = yi->first;
01340     switch (xi_cert.compare(yi_cert)) {
01341     case 0:
01342       // xi_cert == yi_cert: check the number of multiset occurrences.
01343       {
01344         const size_type& xi_count = xi->second;
01345         const size_type& yi_count = yi->second;
01346         if (xi_count == yi_count) {
01347           // Same number of occurrences: compare the next pair.
01348           ++xi;
01349           ++yi;
01350         }
01351         else
01352           // Different number of occurrences: can decide ordering.
01353           return xi_count < yi_count;
01354         break;
01355       }
01356     case 1:
01357       // xi_cert > yi_cert: it is not stabilizing.
01358       return false;
01359 
01360     case -1:
01361       // xi_cert < yi_cert: it is stabilizing.
01362       return true;
01363     }
01364   }
01365   // Here xi == x_cert_ms_end or yi == y_cert_ms_end.
01366   // Stabilization is achieved if `y_cert_ms' still has other elements.
01367   return yi != y_cert_ms_end;
01368 }
01369 
01370 template <typename PSET>
01371 template <typename Cert, typename Widening>
01372 void
01373 Pointset_Powerset<PSET>::BHZ03_widening_assign(const Pointset_Powerset& y,
01374                                                Widening widen_fun) {
01375   // `x' is the current iteration value.
01376   Pointset_Powerset& x = *this;
01377 
01378 #ifndef NDEBUG
01379   {
01380     // We assume that `y' entails `x'.
01381     const Pointset_Powerset<PSET> x_copy = x;
01382     const Pointset_Powerset<PSET> y_copy = y;
01383     PPL_ASSERT_HEAVY(y_copy.definitely_entails(x_copy));
01384   }
01385 #endif
01386 
01387   // First widening technique: do nothing.
01388 
01389   // If `y' is the empty collection, do nothing.
01390   PPL_ASSERT(x.size() > 0);
01391   if (y.size() == 0)
01392     return;
01393 
01394   // Compute the poly-hull of `x'.
01395   PSET x_hull(x.space_dim, EMPTY);
01396   for (const_iterator i = x.begin(), x_end = x.end(); i != x_end; ++i)
01397     x_hull.upper_bound_assign(i->pointset());
01398 
01399   // Compute the poly-hull of `y'.
01400   PSET y_hull(y.space_dim, EMPTY);
01401   for (const_iterator i = y.begin(), y_end = y.end(); i != y_end; ++i)
01402     y_hull.upper_bound_assign(i->pointset());
01403   // Compute the certificate for `y_hull'.
01404   const Cert y_hull_cert(y_hull);
01405 
01406   // If the hull is stabilizing, do nothing.
01407   int hull_stabilization = y_hull_cert.compare(x_hull);
01408   if (hull_stabilization == 1)
01409     return;
01410 
01411   // Multiset ordering is only useful when `y' is not a singleton.
01412   const bool y_is_not_a_singleton = y.size() > 1;
01413 
01414   // The multiset certificate for `y':
01415   // we want to be lazy about its computation.
01416   typedef std::map<Cert, size_type, typename Cert::Compare> Cert_Multiset;
01417   Cert_Multiset y_cert_ms;
01418   bool y_cert_ms_computed = false;
01419 
01420   if (hull_stabilization == 0 && y_is_not_a_singleton) {
01421     // Collect the multiset certificate for `y'.
01422     y.collect_certificates(y_cert_ms);
01423     y_cert_ms_computed = true;
01424     // If multiset ordering is stabilizing, do nothing.
01425     if (x.is_cert_multiset_stabilizing(y_cert_ms))
01426       return;
01427   }
01428 
01429   // Second widening technique: try the BGP99 powerset heuristics.
01430   Pointset_Powerset<PSET> bgp99_heuristics = x;
01431   bgp99_heuristics.BGP99_heuristics_assign(y, widen_fun);
01432 
01433   // Compute the poly-hull of `bgp99_heuristics'.
01434   PSET bgp99_heuristics_hull(x.space_dim, EMPTY);
01435   for (const_iterator i = bgp99_heuristics.begin(),
01436          b_h_end = bgp99_heuristics.end(); i != b_h_end; ++i)
01437     bgp99_heuristics_hull.upper_bound_assign(i->pointset());
01438 
01439   // Check for stabilization and, if successful,
01440   // commit to the result of the extrapolation.
01441   hull_stabilization = y_hull_cert.compare(bgp99_heuristics_hull);
01442   if (hull_stabilization == 1) {
01443     // The poly-hull is stabilizing.
01444     swap(x, bgp99_heuristics);
01445     return;
01446   }
01447   else if (hull_stabilization == 0 && y_is_not_a_singleton) {
01448     // If not already done, compute multiset certificate for `y'.
01449     if (!y_cert_ms_computed) {
01450       y.collect_certificates(y_cert_ms);
01451       y_cert_ms_computed = true;
01452     }
01453     if (bgp99_heuristics.is_cert_multiset_stabilizing(y_cert_ms)) {
01454       swap(x, bgp99_heuristics);
01455       return;
01456     }
01457     // Third widening technique: pairwise-reduction on `bgp99_heuristics'.
01458     // Note that pairwise-reduction does not affect the computation
01459     // of the poly-hulls, so that we only have to check the multiset
01460     // certificate relation.
01461     Pointset_Powerset<PSET> reduced_bgp99_heuristics(bgp99_heuristics);
01462     reduced_bgp99_heuristics.pairwise_reduce();
01463     if (reduced_bgp99_heuristics.is_cert_multiset_stabilizing(y_cert_ms)) {
01464       swap(x, reduced_bgp99_heuristics);
01465       return;
01466     }
01467   }
01468 
01469   // Fourth widening technique: this is applicable only when
01470   // `y_hull' is a proper subset of `bgp99_heuristics_hull'.
01471   if (bgp99_heuristics_hull.strictly_contains(y_hull)) {
01472     // Compute (y_hull \widen bgp99_heuristics_hull).
01473     PSET ph = bgp99_heuristics_hull;
01474     widen_fun(ph, y_hull);
01475     // Compute the difference between `ph' and `bgp99_heuristics_hull'.
01476     ph.difference_assign(bgp99_heuristics_hull);
01477     x.add_disjunct(ph);
01478     return;
01479   }
01480 
01481   // Fall back to the computation of the poly-hull.
01482   Pointset_Powerset<PSET> x_hull_singleton(x.space_dim, EMPTY);
01483   x_hull_singleton.add_disjunct(x_hull);
01484   swap(x, x_hull_singleton);
01485 }
01486 
01487 template <typename PSET>
01488 void
01489 Pointset_Powerset<PSET>::ascii_dump(std::ostream& s) const {
01490   const Pointset_Powerset& x = *this;
01491   s << "size " << x.size()
01492     << "\nspace_dim " << x.space_dim
01493     << "\n";
01494   for (const_iterator xi = x.begin(), x_end = x.end(); xi != x_end; ++xi)
01495     xi->pointset().ascii_dump(s);
01496 }
01497 
01498 PPL_OUTPUT_TEMPLATE_DEFINITIONS(PSET, Pointset_Powerset<PSET>)
01499 
01500 template <typename PSET>
01501 bool
01502 Pointset_Powerset<PSET>::ascii_load(std::istream& s) {
01503   Pointset_Powerset& x = *this;
01504   std::string str;
01505 
01506   if (!(s >> str) || str != "size")
01507     return false;
01508 
01509   size_type sz;
01510 
01511   if (!(s >> sz))
01512     return false;
01513 
01514   if (!(s >> str) || str != "space_dim")
01515     return false;
01516 
01517   if (!(s >> x.space_dim))
01518     return false;
01519 
01520   Pointset_Powerset new_x(x.space_dim, EMPTY);
01521   while (sz-- > 0) {
01522     PSET ph;
01523     if (!ph.ascii_load(s))
01524       return false;
01525     new_x.add_disjunct(ph);
01526   }
01527   swap(x, new_x);
01528 
01529   // Check invariants.
01530   PPL_ASSERT_HEAVY(x.OK());
01531   return true;
01532 }
01533 
01534 template <typename PSET>
01535 bool
01536 Pointset_Powerset<PSET>::OK() const {
01537   const Pointset_Powerset& x = *this;
01538   for (const_iterator xi = x.begin(), x_end = x.end(); xi != x_end; ++xi) {
01539     const PSET& pi = xi->pointset();
01540     if (pi.space_dimension() != x.space_dim) {
01541 #ifndef NDEBUG
01542       std::cerr << "Space dimension mismatch: is " << pi.space_dimension()
01543                 << " in an element of the sequence,\nshould be "
01544                 << x.space_dim << "."
01545                 << std::endl;
01546 #endif
01547       return false;
01548     }
01549   }
01550   return x.Base::OK();
01551 }
01552 
01553 namespace Implementation {
01554 
01555 namespace Pointset_Powersets {
01556 
01557 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
01558 
01559 
01564 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
01565 template <typename PSET>
01566 void
01567 linear_partition_aux(const Constraint& c,
01568                      PSET& pset,
01569                      Pointset_Powerset<NNC_Polyhedron>& r) {
01570   Linear_Expression le(c);
01571   const Constraint& neg_c = c.is_strict_inequality() ? (le <= 0) : (le < 0);
01572   NNC_Polyhedron nnc_ph_pset(pset);
01573   nnc_ph_pset.add_constraint(neg_c);
01574   if (!nnc_ph_pset.is_empty())
01575     r.add_disjunct(nnc_ph_pset);
01576   pset.add_constraint(c);
01577 }
01578 
01579 } // namespace Pointset_Powersets
01580 
01581 } // namespace Implementation
01582 
01583 
01585 template <typename PSET>
01586 std::pair<PSET, Pointset_Powerset<NNC_Polyhedron> >
01587 linear_partition(const PSET& p, const PSET& q) {
01588   using Implementation::Pointset_Powersets::linear_partition_aux;
01589 
01590   Pointset_Powerset<NNC_Polyhedron> r(p.space_dimension(), EMPTY);
01591   PSET pset = q;
01592   const Constraint_System& p_constraints = p.constraints();
01593   for (Constraint_System::const_iterator i = p_constraints.begin(),
01594          p_constraints_end = p_constraints.end();
01595        i != p_constraints_end;
01596        ++i) {
01597     const Constraint& c = *i;
01598     if (c.is_equality()) {
01599       Linear_Expression le(c);
01600       linear_partition_aux(le <= 0, pset, r);
01601       linear_partition_aux(le >= 0, pset, r);
01602     }
01603     else
01604       linear_partition_aux(c, pset, r);
01605   }
01606   return std::make_pair(pset, r);
01607 }
01608 
01609 } // namespace Parma_Polyhedra_Library
01610 
01611 #endif // !defined(PPL_Pointset_Powerset_templates_hh)