Parma_Polyhedra_Library::Polyhedron Class Reference
[C++ Language Interface]

The base class for convex polyhedra. More...

#include <Polyhedron.defs.hh>

Inheritance diagram for Parma_Polyhedra_Library::Polyhedron:

Inheritance graph
[legend]
Collaboration diagram for Parma_Polyhedra_Library::Polyhedron:

Collaboration graph
[legend]

List of all members.

Exception Throwers

void throw_runtime_error (const char *method) const
void throw_invalid_argument (const char *method, const char *reason) const
void throw_topology_incompatible (const char *method, const char *ph_name, const Polyhedron &ph) const
void throw_topology_incompatible (const char *method, const char *c_name, const Constraint &c) const
void throw_topology_incompatible (const char *method, const char *g_name, const Generator &g) const
void throw_topology_incompatible (const char *method, const char *cs_name, const Constraint_System &cs) const
void throw_topology_incompatible (const char *method, const char *gs_name, const Generator_System &gs) const
void throw_dimension_incompatible (const char *method, const char *other_name, dimension_type other_dim) const
void throw_dimension_incompatible (const char *method, const char *ph_name, const Polyhedron &ph) const
void throw_dimension_incompatible (const char *method, const char *e_name, const Linear_Expression &e) const
void throw_dimension_incompatible (const char *method, const char *c_name, const Constraint &c) const
void throw_dimension_incompatible (const char *method, const char *g_name, const Generator &g) const
void throw_dimension_incompatible (const char *method, const char *cg_name, const Congruence &cg) const
void throw_dimension_incompatible (const char *method, const char *cs_name, const Constraint_System &cs) const
void throw_dimension_incompatible (const char *method, const char *gs_name, const Generator_System &gs) const
void throw_dimension_incompatible (const char *method, const char *cgs_name, const Congruence_System &cgs) const
void throw_dimension_incompatible (const char *method, const char *var_name, const Variable var) const
void throw_dimension_incompatible (const char *method, dimension_type required_space_dim) const
void throw_invalid_generator (const char *method, const char *g_name) const
void throw_invalid_generators (const char *method, const char *gs_name) const
static void throw_space_dimension_overflow (Topology topol, const char *method, const char *reason)

Public Member Functions

Member Functions that Do Not Modify the Polyhedron
dimension_type space_dimension () const
 Returns the dimension of the vector space enclosing *this.
dimension_type affine_dimension () const
 Returns $0$, if *this is empty; otherwise, returns the affine dimension of *this.
const Constraint_Systemconstraints () const
 Returns the system of constraints.
const Constraint_Systemminimized_constraints () const
 Returns the system of constraints, with no redundant constraint.
const Generator_Systemgenerators () const
 Returns the system of generators.
const Generator_Systemminimized_generators () const
 Returns the system of generators, with no redundant generator.
Poly_Con_Relation relation_with (const Constraint &c) const
 Returns the relations holding between the polyhedron *this and the constraint c.
Poly_Gen_Relation relation_with (const Generator &g) const
 Returns the relations holding between the polyhedron *this and the generator g.
bool is_empty () const
 Returns true if and only if *this is an empty polyhedron.
bool is_universe () const
 Returns true if and only if *this is a universe polyhedron.
bool is_topologically_closed () const
 Returns true if and only if *this is a topologically closed subset of the vector space.
bool is_disjoint_from (const Polyhedron &y) const
 Returns true if and only if *this and y are disjoint.
bool is_bounded () const
 Returns true if and only if *this is a bounded polyhedron.
bool bounds_from_above (const Linear_Expression &expr) const
 Returns true if and only if expr is bounded from above in *this.
bool bounds_from_below (const Linear_Expression &expr) const
 Returns true if and only if expr is bounded from below in *this.
bool maximize (const Linear_Expression &expr, Coefficient &sup_n, Coefficient &sup_d, bool &maximum) const
 Returns true if and only if *this is not empty and expr is bounded from above in *this, in which case the supremum value is computed.
bool maximize (const Linear_Expression &expr, Coefficient &sup_n, Coefficient &sup_d, bool &maximum, Generator &point) const
 Returns true if and only if *this is not empty and expr is bounded from above in *this, in which case the supremum value and a point where expr reaches it are computed.
bool minimize (const Linear_Expression &expr, Coefficient &inf_n, Coefficient &inf_d, bool &minimum) const
 Returns true if and only if *this is not empty and expr is bounded from below in *this, in which case the infimum value is computed.
bool minimize (const Linear_Expression &expr, Coefficient &inf_n, Coefficient &inf_d, bool &minimum, Generator &point) const
 Returns true if and only if *this is not empty and expr is bounded from below in *this, in which case the infimum value and a point where expr reaches it are computed.
bool contains (const Polyhedron &y) const
 Returns true if and only if *this contains y.
bool strictly_contains (const Polyhedron &y) const
 Returns true if and only if *this strictly contains y.
template<typename Box>
void shrink_bounding_box (Box &box, Complexity_Class complexity=ANY_COMPLEXITY) const
 Uses *this to shrink a generic, interval-based bounding box. Assigns to box the intersection of box with the smallest bounding box containing *this.
bool OK (bool check_not_empty=false) const
 Checks if all the invariants are satisfied.
Space Dimension Preserving Member Functions that May Modify the Polyhedron
void add_constraint (const Constraint &c)
 Adds a copy of constraint c to the system of constraints of *this (without minimizing the result).
bool add_constraint_and_minimize (const Constraint &c)
 Adds a copy of constraint c to the system of constraints of *this, minimizing the result.
void add_generator (const Generator &g)
 Adds a copy of generator g to the system of generators of *this (without minimizing the result).
bool add_generator_and_minimize (const Generator &g)
 Adds a copy of generator g to the system of generators of *this, minimizing the result.
void add_congruence (const Congruence &cg)
 Adds a copy of congruence cg to the system of congruences of this (without minimizing the result).
void add_constraints (const Constraint_System &cs)
 Adds a copy of the constraints in cs to the system of constraints of *this (without minimizing the result).
void add_recycled_constraints (Constraint_System &cs)
 Adds the constraints in cs to the system of constraints of *this (without minimizing the result).
bool add_constraints_and_minimize (const Constraint_System &cs)
 Adds a copy of the constraints in cs to the system of constraints of *this, minimizing the result.
bool add_recycled_constraints_and_minimize (Constraint_System &cs)
 Adds the constraints in cs to the system of constraints of *this, minimizing the result.
void add_generators (const Generator_System &gs)
 Adds a copy of the generators in gs to the system of generators of *this (without minimizing the result).
void add_recycled_generators (Generator_System &gs)
 Adds the generators in gs to the system of generators of *this (without minimizing the result).
bool add_generators_and_minimize (const Generator_System &gs)
 Adds a copy of the generators in gs to the system of generators of *this, minimizing the result.
bool add_recycled_generators_and_minimize (Generator_System &gs)
 Adds the generators in gs to the system of generators of *this, minimizing the result.
void add_congruences (const Congruence_System &cgs)
 Adds to *this constraints equivalent to the congruences in cgs (without minimizing the result).
void intersection_assign (const Polyhedron &y)
 Assigns to *this the intersection of *this and y. The result is not guaranteed to be minimized.
bool intersection_assign_and_minimize (const Polyhedron &y)
 Assigns to *this the intersection of *this and y, minimizing the result.
void poly_hull_assign (const Polyhedron &y)
 Assigns to *this the poly-hull of *this and y. The result is not guaranteed to be minimized.
bool poly_hull_assign_and_minimize (const Polyhedron &y)
 Assigns to *this the poly-hull of *this and y, minimizing the result.
void upper_bound_assign (const Polyhedron &y)
 Same as poly_hull_assign(y).
void poly_difference_assign (const Polyhedron &y)
 Assigns to *this the poly-difference of *this and y. The result is not guaranteed to be minimized.
void difference_assign (const Polyhedron &y)
 Same as poly_difference_assign(y).
void affine_image (Variable var, const Linear_Expression &expr, Coefficient_traits::const_reference denominator=Coefficient_one())
 Assigns to *this the affine image of *this under the function mapping variable var to the affine expression specified by expr and denominator.
void affine_preimage (Variable var, const Linear_Expression &expr, Coefficient_traits::const_reference denominator=Coefficient_one())
 Assigns to *this the affine preimage of *this under the function mapping variable var to the affine expression specified by expr and denominator.
void generalized_affine_image (Variable var, const Relation_Symbol relsym, const Linear_Expression &expr, Coefficient_traits::const_reference denominator=Coefficient_one())
 Assigns to *this the image of *this with respect to the generalized affine relation $\mathrm{var}' \relsym \frac{\mathrm{expr}}{\mathrm{denominator}}$, where $\mathord{\relsym}$ is the relation symbol encoded by relsym.
void generalized_affine_preimage (Variable var, const Relation_Symbol relsym, const Linear_Expression &expr, Coefficient_traits::const_reference denominator=Coefficient_one())
 Assigns to *this the preimage of *this with respect to the generalized affine relation $\mathrm{var}' \relsym \frac{\mathrm{expr}}{\mathrm{denominator}}$, where $\mathord{\relsym}$ is the relation symbol encoded by relsym.
void generalized_affine_image (const Linear_Expression &lhs, const Relation_Symbol relsym, const Linear_Expression &rhs)
 Assigns to *this the image of *this with respect to the generalized affine relation $\mathrm{lhs}' \relsym \mathrm{rhs}$, where $\mathord{\relsym}$ is the relation symbol encoded by relsym.
void generalized_affine_preimage (const Linear_Expression &lhs, const Relation_Symbol relsym, const Linear_Expression &rhs)
 Assigns to *this the preimage of *this with respect to the generalized affine relation $\mathrm{lhs}' \relsym \mathrm{rhs}$, where $\mathord{\relsym}$ is the relation symbol encoded by relsym.
void bounded_affine_image (Variable var, const Linear_Expression &lb_expr, const Linear_Expression &ub_expr, Coefficient_traits::const_reference denominator=Coefficient_one())
 Assigns to *this the image of *this with respect to the bounded affine relation $\frac{\mathrm{lb\_expr}}{\mathrm{denominator}} \leq \mathrm{var}' \leq \frac{\mathrm{ub\_expr}}{\mathrm{denominator}}$.
void bounded_affine_preimage (Variable var, const Linear_Expression &lb_expr, const Linear_Expression &ub_expr, Coefficient_traits::const_reference denominator=Coefficient_one())
 Assigns to *this the preimage of *this with respect to the bounded affine relation $\frac{\mathrm{lb\_expr}}{\mathrm{denominator}} \leq \mathrm{var}' \leq \frac{\mathrm{ub\_expr}}{\mathrm{denominator}}$.
void time_elapse_assign (const Polyhedron &y)
 Assigns to *this the result of computing the time-elapse between *this and y.
void topological_closure_assign ()
 Assigns to *this its topological closure.
void BHRZ03_widening_assign (const Polyhedron &y, unsigned *tp=0)
 Assigns to *this the result of computing the BHRZ03-widening between *this and y.
void limited_BHRZ03_extrapolation_assign (const Polyhedron &y, const Constraint_System &cs, unsigned *tp=0)
 Improves the result of the BHRZ03-widening computation by also enforcing those constraints in cs that are satisfied by all the points of *this.
void bounded_BHRZ03_extrapolation_assign (const Polyhedron &y, const Constraint_System &cs, unsigned *tp=0)
 Improves the result of the BHRZ03-widening computation by also enforcing those constraints in cs that are satisfied by all the points of *this, plus all the constraints of the form $\pm x \leq r$ and $\pm x < r$, with $r \in \Qset$, that are satisfied by all the points of *this.
void H79_widening_assign (const Polyhedron &y, unsigned *tp=0)
 Assigns to *this the result of computing the H79-widening between *this and y.
void limited_H79_extrapolation_assign (const Polyhedron &y, const Constraint_System &cs, unsigned *tp=0)
 Improves the result of the H79-widening computation by also enforcing those constraints in cs that are satisfied by all the points of *this.
void bounded_H79_extrapolation_assign (const Polyhedron &y, const Constraint_System &cs, unsigned *tp=0)
 Improves the result of the H79-widening computation by also enforcing those constraints in cs that are satisfied by all the points of *this, plus all the constraints of the form $\pm x \leq r$ and $\pm x < r$, with $r \in \Qset$, that are satisfied by all the points of *this.
Member Functions that May Modify the Dimension of the Vector Space
void add_space_dimensions_and_embed (dimension_type m)
 Adds m new space dimensions and embeds the old polyhedron in the new vector space.
void add_space_dimensions_and_project (dimension_type m)
 Adds m new space dimensions to the polyhedron and does not embed it in the new vector space.
void concatenate_assign (const Polyhedron &y)
 Assigns to *this the concatenation of *this and y, taken in this order.
void remove_space_dimensions (const Variables_Set &to_be_removed)
 Removes all the specified dimensions from the vector space.
void remove_higher_space_dimensions (dimension_type new_dimension)
 Removes the higher dimensions of the vector space so that the resulting space will have dimension new_dimension.
template<typename Partial_Function>
void map_space_dimensions (const Partial_Function &pfunc)
 Remaps the dimensions of the vector space according to a partial function.
void expand_space_dimension (Variable var, dimension_type m)
 Creates m copies of the space dimension corresponding to var.
void fold_space_dimensions (const Variables_Set &to_be_folded, Variable var)
 Folds the space dimensions in to_be_folded into var.
Miscellaneous Member Functions
 ~Polyhedron ()
 Destructor.
void swap (Polyhedron &y)
 Swaps *this with polyhedron y. (*this and y can be dimension-incompatible.).
void ascii_dump () const
 Writes to std::cerr an ASCII representation of *this.
void ascii_dump (std::ostream &s) const
 Writes to s an ASCII representation of *this.
void print () const
 Prints *this to std::cerr using operator<<.
bool ascii_load (std::istream &s)
 Loads from s an ASCII representation (as produced by ascii_dump) and sets *this accordingly. Returns true if successful, false otherwise.
memory_size_type total_memory_in_bytes () const
 Returns the total size in bytes of the memory occupied by *this.
memory_size_type external_memory_in_bytes () const
 Returns the size in bytes of the memory managed by *this.

Static Public Member Functions

static dimension_type max_space_dimension ()
 Returns the maximum space dimension all kinds of Polyhedron can handle.

Protected Member Functions

 Polyhedron (Topology topol, dimension_type num_dimensions, Degenerate_Element kind)
 Builds a polyhedron having the specified properties.
 Polyhedron (const Polyhedron &y)
 Ordinary copy-constructor.
 Polyhedron (Topology topol, const Constraint_System &cs)
 Builds a polyhedron from a system of constraints.
 Polyhedron (Topology topol, Constraint_System &cs)
 Builds a polyhedron recycling a system of constraints.
 Polyhedron (Topology topol, const Generator_System &gs)
 Builds a polyhedron from a system of generators.
 Polyhedron (Topology topol, Generator_System &gs)
 Builds a polyhedron recycling a system of generators.
template<typename Box>
 Polyhedron (Topology topol, const Box &box)
 Builds a polyhedron out of a generic, interval-based bounding box.
Polyhedronoperator= (const Polyhedron &y)
 The assignment operator. (*this and y can be dimension-incompatible.).

Private Types

enum  Three_Valued_Boolean { TVB_TRUE, TVB_FALSE, TVB_DONT_KNOW }

Private Member Functions

Topology topology () const
 Returns the topological kind of the polyhedron.
bool is_necessarily_closed () const
 Returns true if and only if the polyhedron is necessarily closed.
Three_Valued_Boolean quick_equivalence_test (const Polyhedron &y) const
 Polynomial but incomplete equivalence test between polyhedra.
bool is_included_in (const Polyhedron &y) const
 Returns true if and only if *this is included in y.
bool bounds (const Linear_Expression &expr, bool from_above) const
 Checks if and how expr is bounded in *this.
bool max_min (const Linear_Expression &expr, const bool maximize, Coefficient &ext_n, Coefficient &ext_d, bool &included, Generator &point) const
 Maximizes or minimizes expr subject to *this.
Private Verifiers: Verify if Individual Flags are Set
bool marked_empty () const
 Returns true if the polyhedron is known to be empty.
bool constraints_are_up_to_date () const
 Returns true if the system of constraints is up-to-date.
bool generators_are_up_to_date () const
 Returns true if the system of generators is up-to-date.
bool constraints_are_minimized () const
 Returns true if the system of constraints is minimized.
bool generators_are_minimized () const
 Returns true if the system of generators is minimized.
bool has_pending_constraints () const
 Returns true if there are pending constraints.
bool has_pending_generators () const
 Returns true if there are pending generators.
bool has_something_pending () const
 Returns true if there are either pending constraints or pending generators.
bool can_have_something_pending () const
 Returns true if the polyhedron can have something pending.
bool sat_c_is_up_to_date () const
 Returns true if the saturation matrix sat_c is up-to-date.
bool sat_g_is_up_to_date () const
 Returns true if the saturation matrix sat_g is up-to-date.
State Flag Setters: Set Only the Specified Flags
void set_zero_dim_univ ()
 Sets status to express that the polyhedron is the universe 0-dimension vector space, clearing all corresponding matrices.
void set_empty ()
 Sets status to express that the polyhedron is empty, clearing all corresponding matrices.
void set_constraints_up_to_date ()
 Sets status to express that constraints are up-to-date.
void set_generators_up_to_date ()
 Sets status to express that generators are up-to-date.
void set_constraints_minimized ()
 Sets status to express that constraints are minimized.
void set_generators_minimized ()
 Sets status to express that generators are minimized.
void set_constraints_pending ()
 Sets status to express that constraints are pending.
void set_generators_pending ()
 Sets status to express that generators are pending.
void set_sat_c_up_to_date ()
 Sets status to express that sat_c is up-to-date.
void set_sat_g_up_to_date ()
 Sets status to express that sat_g is up-to-date.
State Flag Cleaners: Clear Only the Specified Flag
void clear_empty ()
 Clears the status flag indicating that the polyhedron is empty.
void clear_constraints_up_to_date ()
 Sets status to express that constraints are no longer up-to-date.
void clear_generators_up_to_date ()
 Sets status to express that generators are no longer up-to-date.
void clear_constraints_minimized ()
 Sets status to express that constraints are no longer minimized.
void clear_generators_minimized ()
 Sets status to express that generators are no longer minimized.
void clear_pending_constraints ()
 Sets status to express that there are no longer pending constraints.
void clear_pending_generators ()
 Sets status to express that there are no longer pending generators.
void clear_sat_c_up_to_date ()
 Sets status to express that sat_c is no longer up-to-date.
void clear_sat_g_up_to_date ()
 Sets status to express that sat_g is no longer up-to-date.
The Handling of Pending Rows
bool process_pending () const
 Processes the pending rows of either description of the polyhedron and obtains a minimized polyhedron.
bool process_pending_constraints () const
 Processes the pending constraints and obtains a minimized polyhedron.
void process_pending_generators () const
 Processes the pending generators and obtains a minimized polyhedron.
void remove_pending_to_obtain_constraints () const
 Lazily integrates the pending descriptions of the polyhedron to obtain a constraint system without pending rows.
bool remove_pending_to_obtain_generators () const
 Lazily integrates the pending descriptions of the polyhedron to obtain a generator system without pending rows.
Updating and Sorting Matrices
void update_constraints () const
 Updates constraints starting from generators and minimizes them.
bool update_generators () const
 Updates generators starting from constraints and minimizes them.
void update_sat_c () const
 Updates sat_c using the updated constraints and generators.
void update_sat_g () const
 Updates sat_g using the updated constraints and generators.
void obtain_sorted_constraints () const
 Sorts the matrix of constraints keeping status consistency.
void obtain_sorted_generators () const
 Sorts the matrix of generators keeping status consistency.
void obtain_sorted_constraints_with_sat_c () const
 Sorts the matrix of constraints and updates sat_c.
void obtain_sorted_generators_with_sat_g () const
 Sorts the matrix of generators and updates sat_g.
Weak and Strong Minimization of Descriptions
bool minimize () const
 Applies (weak) minimization to both the constraints and generators.
bool strongly_minimize_constraints () const
 Applies strong minimization to the constraints of an NNC polyhedron.
bool strongly_minimize_generators () const
 Applies strong minimization to the generators of an NNC polyhedron.
Widening- and Extrapolation-Related Functions
void select_CH78_constraints (const Polyhedron &y, Constraint_System &cs_selected) const
 Copies to cs_selection the constraints of y corresponding to the definition of the CH78-widening of *this and y.
void select_H79_constraints (const Polyhedron &y, Constraint_System &cs_selected, Constraint_System &cs_not_selected) const
 Splits the constraints of `x' into two subsets, depending on whether or not they are selected to compute the H79-widening of *this and y.
bool BHRZ03_combining_constraints (const Polyhedron &y, const BHRZ03_Certificate &y_cert, const Polyhedron &H79, const Constraint_System &x_minus_H79_con_sys)
bool BHRZ03_evolving_points (const Polyhedron &y, const BHRZ03_Certificate &y_cert, const Polyhedron &H79)
bool BHRZ03_evolving_rays (const Polyhedron &y, const BHRZ03_Certificate &y_cert, const Polyhedron &H79)

Static Private Member Functions

static void add_space_dimensions (Linear_System &mat1, Linear_System &mat2, Saturation_Matrix &sat1, Saturation_Matrix &sat2, dimension_type add_dim)
 Adds new space dimensions to the given matrices.
Minimization-Related Static Member Functions
static bool minimize (bool con_to_gen, Linear_System &source, Linear_System &dest, Saturation_Matrix &sat)
 Builds and simplifies constraints from generators (or vice versa).
static bool add_and_minimize (bool con_to_gen, Linear_System &source1, Linear_System &dest, Saturation_Matrix &sat, const Linear_System &source2)
 Adds given constraints and builds minimized corresponding generators or vice versa.
static bool add_and_minimize (bool con_to_gen, Linear_System &source, Linear_System &dest, Saturation_Matrix &sat)
 Adds given constraints and builds minimized corresponding generators or vice versa. The given constraints are in source.
static dimension_type conversion (Linear_System &source, dimension_type start, Linear_System &dest, Saturation_Matrix &sat, dimension_type num_lines_or_equalities)
 Performs the conversion from constraints to generators and vice versa.
static int simplify (Linear_System &mat, Saturation_Matrix &sat)
 Uses Gauss' elimination method to simplify the result of conversion().

Private Attributes

Constraint_System con_sys
 The system of constraints.
Generator_System gen_sys
 The system of generators.
Saturation_Matrix sat_c
 The saturation matrix having constraints on its columns.
Saturation_Matrix sat_g
 The saturation matrix having generators on its columns.
Status status
 The status flags to keep track of the polyhedron's internal state.
dimension_type space_dim
 The number of dimensions of the enclosing vector space.

Friends

class Parma_Polyhedra_Library::BD_Shape
class Parma_Polyhedra_Library::BHRZ03_Certificate
class Parma_Polyhedra_Library::H79_Certificate
bool operator== (const Polyhedron &x, const Polyhedron &y)

Related Functions

(Note that these are not member functions.)

std::ostream & operator<< (std::ostream &s, const Polyhedron &ph)
 Output operator.
bool operator!= (const Polyhedron &x, const Polyhedron &y)
 Returns true if and only if x and y are different polyhedra.
void swap (Parma_Polyhedra_Library::Polyhedron &x, Parma_Polyhedra_Library::Polyhedron &y)
 Specializes std::swap.
template<typename PH>
bool poly_hull_assign_if_exact (PH &p, const PH &q)
 If the poly-hull of p and q is exact it is assigned to p and true is returned, otherwise false is returned.

Classes

class  Status
 A conjunctive assertion about a polyhedron. More...


Detailed Description

The base class for convex polyhedra.

An object of the class Polyhedron represents a convex polyhedron in the vector space $\Rset^n$.

A polyhedron can be specified as either a finite system of constraints or a finite system of generators (see Section Representations of Convex Polyhedra) and it is always possible to obtain either representation. That is, if we know the system of constraints, we can obtain from this the system of generators that define the same polyhedron and vice versa. These systems can contain redundant members: in this case we say that they are not in the minimal form. Most operators on polyhedra are provided with two implementations: one of these, denoted <operator-name>_and_minimize, also enforces the minimization of the representations, and returns the Boolean value false whenever the resulting polyhedron turns out to be empty.

Two key attributes of any polyhedron are its topological kind (recording whether it is a C_Polyhedron or an NNC_Polyhedron object) and its space dimension (the dimension $n \in \Nset$ of the enclosing vector space):

Note that four different polyhedra can be defined on the zero-dimension space: the empty polyhedron, either closed or NNC, and the universe polyhedron $R^0$, again either closed or NNC.

In all the examples it is assumed that variables x and y are defined (where they are used) as follows:
  Variable x(0);
  Variable y(1);
Example 1
The following code builds a polyhedron corresponding to a square in $\Rset^2$, given as a system of constraints:
  Constraint_System cs;
  cs.insert(x >= 0);
  cs.insert(x <= 3);
  cs.insert(y >= 0);
  cs.insert(y <= 3);
  C_Polyhedron ph(cs);
The following code builds the same polyhedron as above, but starting from a system of generators specifying the four vertices of the square:
  Generator_System gs;
  gs.insert(point(0*x + 0*y));
  gs.insert(point(0*x + 3*y));
  gs.insert(point(3*x + 0*y));
  gs.insert(point(3*x + 3*y));
  C_Polyhedron ph(gs);
Example 2
The following code builds an unbounded polyhedron corresponding to a half-strip in $\Rset^2$, given as a system of constraints:
  Constraint_System cs;
  cs.insert(x >= 0);
  cs.insert(x - y <= 0);
  cs.insert(x - y + 1 >= 0);
  C_Polyhedron ph(cs);
The following code builds the same polyhedron as above, but starting from the system of generators specifying the two vertices of the polyhedron and one ray:
  Generator_System gs;
  gs.insert(point(0*x + 0*y));
  gs.insert(point(0*x + y));
  gs.insert(ray(x - y));
  C_Polyhedron ph(gs);
Example 3
The following code builds the polyhedron corresponding to a half-plane by adding a single constraint to the universe polyhedron in $\Rset^2$:
  C_Polyhedron ph(2);
  ph.add_constraint(y >= 0);
The following code builds the same polyhedron as above, but starting from the empty polyhedron in the space $\Rset^2$ and inserting the appropriate generators (a point, a ray and a line).
  C_Polyhedron ph(2, EMPTY);
  ph.add_generator(point(0*x + 0*y));
  ph.add_generator(ray(y));
  ph.add_generator(line(x));
Note that, although the above polyhedron has no vertices, we must add one point, because otherwise the result of the Minkowski's sum would be an empty polyhedron. To avoid subtle errors related to the minimization process, it is required that the first generator inserted in an empty polyhedron is a point (otherwise, an exception is thrown).
Example 4
The following code shows the use of the function add_space_dimensions_and_embed:
  C_Polyhedron ph(1);
  ph.add_constraint(x == 2);
  ph.add_space_dimensions_and_embed(1);
We build the universe polyhedron in the 1-dimension space $\Rset$. Then we add a single equality constraint, thus obtaining the polyhedron corresponding to the singleton set $\{ 2 \} \sseq \Rset$. After the last line of code, the resulting polyhedron is

\[ \bigl\{\, (2, y)^\transpose \in \Rset^2 \bigm| y \in \Rset \,\bigr\}. \]

Example 5
The following code shows the use of the function add_space_dimensions_and_project:
  C_Polyhedron ph(1);
  ph.add_constraint(x == 2);
  ph.add_space_dimensions_and_project(1);
The first two lines of code are the same as in Example 4 for add_space_dimensions_and_embed. After the last line of code, the resulting polyhedron is the singleton set $\bigl\{ (2, 0)^\transpose \bigr\} \sseq \Rset^2$.
Example 6
The following code shows the use of the function affine_image:
  C_Polyhedron ph(2, EMPTY);
  ph.add_generator(point(0*x + 0*y));
  ph.add_generator(point(0*x + 3*y));
  ph.add_generator(point(3*x + 0*y));
  ph.add_generator(point(3*x + 3*y));
  Linear_Expression expr = x + 4;
  ph.affine_image(x, expr);
In this example the starting polyhedron is a square in $\Rset^2$, the considered variable is $x$ and the affine expression is $x+4$. The resulting polyhedron is the same square translated to the right. Moreover, if the affine transformation for the same variable x is $x+y$:
  Linear_Expression expr = x + y;
the resulting polyhedron is a parallelogram with the height equal to the side of the square and the oblique sides parallel to the line $x-y$. Instead, if we do not use an invertible transformation for the same variable; for example, the affine expression $y$:
  Linear_Expression expr = y;
the resulting polyhedron is a diagonal of the square.
Example 7
The following code shows the use of the function affine_preimage:
  C_Polyhedron ph(2);
  ph.add_constraint(x >= 0);
  ph.add_constraint(x <= 3);
  ph.add_constraint(y >= 0);
  ph.add_constraint(y <= 3);
  Linear_Expression expr = x + 4;
  ph.affine_preimage(x, expr);
In this example the starting polyhedron, var and the affine expression and the denominator are the same as in Example 6, while the resulting polyhedron is again the same square, but translated to the left. Moreover, if the affine transformation for x is $x+y$
  Linear_Expression expr = x + y;
the resulting polyhedron is a parallelogram with the height equal to the side of the square and the oblique sides parallel to the line $x+y$. Instead, if we do not use an invertible transformation for the same variable x, for example, the affine expression $y$:
  Linear_Expression expr = y;
the resulting polyhedron is a line that corresponds to the $y$ axis.
Example 8
For this example we use also the variables:
  Variable z(2);
  Variable w(3);
The following code shows the use of the function remove_space_dimensions:
  Generator_System gs;
  gs.insert(point(3*x + y +0*z + 2*w));
  C_Polyhedron ph(gs);
  Variables_Set to_be_removed;
  to_be_removed.insert(y);
  to_be_removed.insert(z);
  ph.remove_space_dimensions(to_be_removed);
The starting polyhedron is the singleton set $\bigl\{ (3, 1, 0, 2)^\transpose \bigr\} \sseq \Rset^4$, while the resulting polyhedron is $\bigl\{ (3, 2)^\transpose \bigr\} \sseq \Rset^2$. Be careful when removing space dimensions incrementally: since dimensions are automatically renamed after each application of the remove_space_dimensions operator, unexpected results can be obtained. For instance, by using the following code we would obtain a different result:
  set<Variable> to_be_removed1;
  to_be_removed1.insert(y);
  ph.remove_space_dimensions(to_be_removed1);
  set<Variable> to_be_removed2;
  to_be_removed2.insert(z);
  ph.remove_space_dimensions(to_be_removed2);
In this case, the result is the polyhedron $\bigl\{(3, 0)^\transpose \bigr\} \sseq \Rset^2$: when removing the set of dimensions to_be_removed2 we are actually removing variable $w$ of the original polyhedron. For the same reason, the operator remove_space_dimensions is not idempotent: removing twice the same non-empty set of dimensions is never the same as removing them just once.

Definition at line 351 of file Polyhedron.defs.hh.


Member Enumeration Documentation

Enumerator:
TVB_TRUE 
TVB_FALSE 
TVB_DONT_KNOW 

Definition at line 2387 of file Polyhedron.defs.hh.

02393      {


Constructor & Destructor Documentation

Parma_Polyhedra_Library::Polyhedron::Polyhedron ( Topology  topol,
dimension_type  num_dimensions,
Degenerate_Element  kind 
) [protected]

Builds a polyhedron having the specified properties.

Parameters:
topol The topology of the polyhedron;
num_dimensions The number of dimensions of the vector space enclosing the polyhedron;
kind Specifies whether the universe or the empty polyhedron has to be built.

Definition at line 49 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Constraint_System::add_low_level_constraints(), Parma_Polyhedra_Library::Constraint_System::adjust_topology_and_space_dimension(), con_sys, Parma_Polyhedra_Library::EMPTY, max_space_dimension(), OK(), set_constraints_minimized(), Parma_Polyhedra_Library::Polyhedron::Status::set_empty(), space_dim, and status.

00052   : con_sys(topol),
00053     gen_sys(topol),
00054     sat_c(),
00055     sat_g() {
00056   // Protecting against space dimension overflow is up to the caller.
00057   assert(num_dimensions <= max_space_dimension());
00058 
00059   if (kind == EMPTY)
00060     status.set_empty();
00061   else if (num_dimensions > 0) {
00062     con_sys.add_low_level_constraints();
00063     con_sys.adjust_topology_and_space_dimension(topol, num_dimensions);
00064     set_constraints_minimized();
00065   }
00066   space_dim = num_dimensions;
00067   assert(OK());
00068 }

Parma_Polyhedra_Library::Polyhedron::Polyhedron ( const Polyhedron y  )  [protected]

Ordinary copy-constructor.

Definition at line 70 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Linear_System::assign_with_pending(), con_sys, constraints_are_up_to_date(), gen_sys, generators_are_up_to_date(), sat_c, sat_c_is_up_to_date(), sat_g, sat_g_is_up_to_date(), and topology().

00071   : con_sys(y.topology()),
00072     gen_sys(y.topology()),
00073     status(y.status),
00074     space_dim(y.space_dim) {
00075   // Being a protected method, we simply assert that topologies do match.
00076   assert(topology() == y.topology());
00077   if (y.constraints_are_up_to_date())
00078     con_sys.assign_with_pending(y.con_sys);
00079   if (y.generators_are_up_to_date())
00080     gen_sys.assign_with_pending(y.gen_sys);
00081   if (y.sat_c_is_up_to_date())
00082     sat_c = y.sat_c;
00083   if (y.sat_g_is_up_to_date())
00084     sat_g = y.sat_g;
00085 }

Parma_Polyhedra_Library::Polyhedron::Polyhedron ( Topology  topol,
const Constraint_System cs 
) [protected]

Builds a polyhedron from a system of constraints.

The polyhedron inherits the space dimension of the constraint system.

Parameters:
topol The topology of the polyhedron;
cs The system of constraints defining the polyhedron.
Exceptions:
std::invalid_argument Thrown if the topology of cs is incompatible with topol.

Definition at line 87 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Constraint_System::add_low_level_constraints(), con_sys, max_space_dimension(), Parma_Polyhedra_Library::NECESSARILY_CLOSED, Parma_Polyhedra_Library::Linear_System::num_pending_rows(), OK(), set_constraints_up_to_date(), set_empty(), Parma_Polyhedra_Library::Linear_System::set_sorted(), space_dim, Parma_Polyhedra_Library::Constraint_System::space_dimension(), throw_topology_incompatible(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

00088   : con_sys(topol),
00089     gen_sys(topol),
00090     sat_c(),
00091     sat_g() {
00092   // Protecting against space dimension overflow is up to the caller.
00093   assert(ccs.space_dimension() <= max_space_dimension());
00094 
00095   // TODO: this implementation is just an executable specification.
00096   Constraint_System cs = ccs;
00097 
00098   // Try to adapt `cs' to the required topology.
00099   const dimension_type cs_space_dim = cs.space_dimension();
00100   if (!cs.adjust_topology_and_space_dimension(topol, cs_space_dim))
00101     throw_topology_incompatible((topol == NECESSARILY_CLOSED)
00102                                 ? "C_Polyhedron(cs)"
00103                                 : "NNC_Polyhedron(cs)", "cs", cs);
00104 
00105   // Set the space dimension.
00106   space_dim = cs_space_dim;
00107 
00108   if (space_dim > 0) {
00109     // Stealing the rows from `cs'.
00110     std::swap(con_sys, cs);
00111     if (con_sys.num_pending_rows() > 0) {
00112       // Even though `cs' has pending constraints, since the generators
00113       // of the polyhedron are not up-to-date, the polyhedron cannot
00114       // have pending constraints. By integrating the pending part
00115       // of `con_sys' we may loose sortedness.
00116       con_sys.unset_pending_rows();
00117       con_sys.set_sorted(false);
00118     }
00119     con_sys.add_low_level_constraints();
00120     set_constraints_up_to_date();
00121   }
00122   else {
00123     // Here `space_dim == 0'.
00124     if (cs.num_columns() > 0)
00125       // See if an inconsistent constraint has been passed.
00126       for (dimension_type i = cs.num_rows(); i-- > 0; )
00127         if (cs[i].is_inconsistent()) {
00128           // Inconsistent constraint found: the polyhedron is empty.
00129           set_empty();
00130           break;
00131         }
00132   }
00133   assert(OK());
00134 }

Parma_Polyhedra_Library::Polyhedron::Polyhedron ( Topology  topol,
Constraint_System cs 
) [protected]

Builds a polyhedron recycling a system of constraints.

The polyhedron inherits the space dimension of the constraint system.

Parameters:
topol The topology of the polyhedron;
cs The system of constraints defining the polyhedron. It is not declared const because its data-structures will be recycled to build the polyhedron.
Exceptions:
std::invalid_argument Thrown if the topology of cs is incompatible with topol.

Definition at line 136 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Constraint_System::add_low_level_constraints(), Parma_Polyhedra_Library::Constraint_System::adjust_topology_and_space_dimension(), con_sys, max_space_dimension(), Parma_Polyhedra_Library::NECESSARILY_CLOSED, Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Linear_System::num_pending_rows(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), set_constraints_up_to_date(), set_empty(), Parma_Polyhedra_Library::Linear_System::set_sorted(), space_dim, Parma_Polyhedra_Library::Constraint_System::space_dimension(), throw_topology_incompatible(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

00137   : con_sys(topol),
00138     gen_sys(topol),
00139     sat_c(),
00140     sat_g() {
00141   // Protecting against space dimension overflow is up to the caller.
00142   assert(cs.space_dimension() <= max_space_dimension());
00143 
00144   // Try to adapt `cs' to the required topology.
00145   const dimension_type cs_space_dim = cs.space_dimension();
00146   if (!cs.adjust_topology_and_space_dimension(topol, cs_space_dim))
00147     throw_topology_incompatible((topol == NECESSARILY_CLOSED)
00148                                 ? "C_Polyhedron(cs)"
00149                                 : "NNC_Polyhedron(cs)", "cs", cs);
00150 
00151   // Set the space dimension.
00152   space_dim = cs_space_dim;
00153 
00154   if (space_dim > 0) {
00155     // Stealing the rows from `cs'.
00156     std::swap(con_sys, cs);
00157     if (con_sys.num_pending_rows() > 0) {
00158       // Even though `cs' has pending constraints, since the generators
00159       // of the polyhedron are not up-to-date, the polyhedron cannot
00160       // have pending constraints. By integrating the pending part
00161       // of `con_sys' we may loose sortedness.
00162       con_sys.unset_pending_rows();
00163       con_sys.set_sorted(false);
00164     }
00165     con_sys.add_low_level_constraints();
00166     set_constraints_up_to_date();
00167   }
00168   else {
00169     // Here `space_dim == 0'.
00170     if (cs.num_columns() > 0)
00171       // See if an inconsistent constraint has been passed.
00172       for (dimension_type i = cs.num_rows(); i-- > 0; )
00173         if (cs[i].is_inconsistent()) {
00174           // Inconsistent constraint found: the polyhedron is empty.
00175           set_empty();
00176           break;
00177         }
00178   }
00179   assert(OK());
00180 }

Parma_Polyhedra_Library::Polyhedron::Polyhedron ( Topology  topol,
const Generator_System gs 
) [protected]

Builds a polyhedron from a system of generators.

The polyhedron inherits the space dimension of the generator system.

Parameters:
topol The topology of the polyhedron;
gs The system of generators defining the polyhedron.
Exceptions:
std::invalid_argument Thrown if the topology of gs is incompatible with topol, or if the system of generators is not empty but has no points.

Definition at line 182 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Generator_System::add_corresponding_closure_points(), gen_sys, max_space_dimension(), Parma_Polyhedra_Library::NECESSARILY_CLOSED, Parma_Polyhedra_Library::NOT_NECESSARILY_CLOSED, Parma_Polyhedra_Library::Linear_System::num_pending_rows(), OK(), Parma_Polyhedra_Library::Polyhedron::Status::set_empty(), set_generators_up_to_date(), Parma_Polyhedra_Library::Linear_System::set_sorted(), space_dim, Parma_Polyhedra_Library::Generator_System::space_dimension(), status, throw_invalid_generators(), throw_topology_incompatible(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

00183   : con_sys(topol),
00184     gen_sys(topol),
00185     sat_c(),
00186     sat_g() {
00187   // Protecting against space dimension overflow is up to the caller.
00188   assert(cgs.space_dimension() <= max_space_dimension());
00189 
00190   // TODO: this implementation is just an executable specification.
00191   Generator_System gs = cgs;
00192 
00193   // An empty set of generators defines the empty polyhedron.
00194   if (gs.num_rows() == 0) {
00195     space_dim = gs.space_dimension();
00196     status.set_empty();
00197     assert(OK());
00198     return;
00199   }
00200 
00201   // Non-empty valid generator systems have a supporting point, at least.
00202   if (!gs.has_points())
00203     throw_invalid_generators((topol == NECESSARILY_CLOSED)
00204                              ? "C_Polyhedron(gs)"
00205                              : "NNC_Polyhedron(gs)", "gs");
00206 
00207   const dimension_type gs_space_dim = gs.space_dimension();
00208   // Try to adapt `gs' to the required topology.
00209   if (!gs.adjust_topology_and_space_dimension(topol, gs_space_dim))
00210     throw_topology_incompatible((topol == NECESSARILY_CLOSED)
00211                                 ? "C_Polyhedron(gs)"
00212                                 : "NNC_Polyhedron(gs)", "gs", gs);
00213 
00214   if (gs_space_dim > 0) {
00215     // Stealing the rows from `gs'.
00216     std::swap(gen_sys, gs);
00217     // In a generator system describing a NNC polyhedron,
00218     // for each point we must also have the corresponding closure point.
00219     if (topol == NOT_NECESSARILY_CLOSED)
00220       gen_sys.add_corresponding_closure_points();
00221     if (gen_sys.num_pending_rows() > 0) {
00222       // Even though `gs' has pending generators, since the constraints
00223       // of the polyhedron are not up-to-date, the polyhedron cannot
00224       // have pending generators. By integrating the pending part
00225       // of `gen_sys' we may loose sortedness.
00226       gen_sys.unset_pending_rows();
00227       gen_sys.set_sorted(false);
00228     }
00229     // Generators are now up-to-date.
00230     set_generators_up_to_date();
00231 
00232     // Set the space dimension.
00233     space_dim = gs_space_dim;
00234     assert(OK());
00235     return;
00236   }
00237 
00238   // Here `gs.num_rows > 0' and `gs_space_dim == 0':
00239   // we already checked for both the topology-compatibility
00240   // and the supporting point.
00241   space_dim = 0;
00242   assert(OK());
00243 }

Parma_Polyhedra_Library::Polyhedron::Polyhedron ( Topology  topol,
Generator_System gs 
) [protected]

Builds a polyhedron recycling a system of generators.

The polyhedron inherits the space dimension of the generator system.

Parameters:
topol The topology of the polyhedron;
gs The system of generators defining the polyhedron. It is not declared const because its data-structures will be recycled to build the polyhedron.
Exceptions:
std::invalid_argument Thrown if the topology of gs is incompatible with topol, or if the system of generators is not empty but has no points.

Definition at line 245 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Generator_System::add_corresponding_closure_points(), Parma_Polyhedra_Library::Generator_System::adjust_topology_and_space_dimension(), gen_sys, Parma_Polyhedra_Library::Generator_System::has_points(), max_space_dimension(), Parma_Polyhedra_Library::NECESSARILY_CLOSED, Parma_Polyhedra_Library::NOT_NECESSARILY_CLOSED, Parma_Polyhedra_Library::Linear_System::num_pending_rows(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), Parma_Polyhedra_Library::Polyhedron::Status::set_empty(), set_generators_up_to_date(), Parma_Polyhedra_Library::Linear_System::set_sorted(), space_dim, Parma_Polyhedra_Library::Generator_System::space_dimension(), status, throw_invalid_generators(), throw_topology_incompatible(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

00246   : con_sys(topol),
00247     gen_sys(topol),
00248     sat_c(),
00249     sat_g() {
00250   // Protecting against space dimension overflow is up to the caller.
00251   assert(gs.space_dimension() <= max_space_dimension());
00252 
00253   // An empty set of generators defines the empty polyhedron.
00254   if (gs.num_rows() == 0) {
00255     space_dim = gs.space_dimension();
00256     status.set_empty();
00257     assert(OK());
00258     return;
00259   }
00260 
00261   // Non-empty valid generator systems have a supporting point, at least.
00262   if (!gs.has_points())
00263     throw_invalid_generators((topol == NECESSARILY_CLOSED)
00264                              ? "C_Polyhedron(gs)"
00265                              : "NNC_Polyhedron(gs)", "gs");
00266 
00267   const dimension_type gs_space_dim = gs.space_dimension();
00268   // Try to adapt `gs' to the required topology.
00269   if (!gs.adjust_topology_and_space_dimension(topol, gs_space_dim))
00270     throw_topology_incompatible((topol == NECESSARILY_CLOSED)
00271                                 ? "C_Polyhedron(gs)"
00272                                 : "NNC_Polyhedron(gs)", "gs", gs);
00273 
00274   if (gs_space_dim > 0) {
00275     // Stealing the rows from `gs'.
00276     std::swap(gen_sys, gs);
00277     // In a generator system describing a NNC polyhedron,
00278     // for each point we must also have the corresponding closure point.
00279     if (topol == NOT_NECESSARILY_CLOSED)
00280       gen_sys.add_corresponding_closure_points();
00281     if (gen_sys.num_pending_rows() > 0) {
00282       // Even though `gs' has pending generators, since the constraints
00283       // of the polyhedron are not up-to-date, the polyhedron cannot
00284       // have pending generators. By integrating the pending part
00285       // of `gen_sys' we may loose sortedness.
00286       gen_sys.unset_pending_rows();
00287       gen_sys.set_sorted(false);
00288     }
00289     // Generators are now up-to-date.
00290     set_generators_up_to_date();
00291 
00292     // Set the space dimension.
00293     space_dim = gs_space_dim;
00294     assert(OK());
00295     return;
00296   }
00297 
00298   // Here `gs.num_rows > 0' and `gs_space_dim == 0':
00299   // we already checked for both the topology-compatibility
00300   // and the supporting point.
00301   space_dim = 0;
00302   assert(OK());
00303 }

template<typename Box>
Parma_Polyhedra_Library::Polyhedron::Polyhedron ( Topology  topol,
const Box &  box 
) [inline, protected]

Builds a polyhedron out of a generic, interval-based bounding box.

Parameters:
topol The topology of the polyhedron;
box The bounding box representing the polyhedron to be built.
Exceptions:
std::invalid_argument Thrown if box has intervals that are incompatible with topol.
The template class Box must provide the following methods. returns the dimension of the vector space enclosing the polyhedron represented by the bounding box.
      bool is_empty() const
returns true if and only if the bounding box describes the empty set. The is_empty() method will always be called before the methods below. However, if is_empty() returns true, none of the functions below will be called.
      bool get_lower_bound(dimension_type k, bool closed,
                           Coefficient& n, Coefficient& d) const
Let $I$ the interval corresponding to the k-th space dimension. If $I$ is not bounded from below, simply return false. Otherwise, set closed, n and d as follows: closed is set to true if the the lower boundary of $I$ is closed and is set to false otherwise; n and d are assigned the integers $n$ and $d$ such that the canonical fraction $n/d$ corresponds to the greatest lower bound of $I$. The fraction $n/d$ is in canonical form if and only if $n$ and $d$ have no common factors and $d$ is positive, $0/1$ being the unique representation for zero.
      bool get_upper_bound(dimension_type k, bool closed,
                           Coefficient& n, Coefficient& d) const
Let $I$ the interval corresponding to the k-th space dimension. If $I$ is not bounded from above, simply return false. Otherwise, set closed, n and d as follows: closed is set to true if the the upper boundary of $I$ is closed and is set to false otherwise; n and d are assigned the integers $n$ and $d$ such that the canonical fraction $n/d$ corresponds to the least upper bound of $I$.

Definition at line 35 of file Polyhedron.templates.hh.

References Parma_Polyhedra_Library::Constraint_System::add_low_level_constraints(), con_sys, Parma_Polyhedra_Library::Matrix::erase_to_end(), Parma_Polyhedra_Library::Constraint_System::insert(), Parma_Polyhedra_Library::NECESSARILY_CLOSED, Parma_Polyhedra_Library::Matrix::num_rows(), OK(), set_constraints_up_to_date(), set_empty(), Parma_Polyhedra_Library::Linear_System::set_index_first_pending_row(), Parma_Polyhedra_Library::Linear_System::set_sorted(), set_zero_dim_univ(), space_dim, Parma_Polyhedra_Library::Constraint_System::swap(), and throw_invalid_argument().

00036   : con_sys(topol),
00037     gen_sys(topol),
00038     sat_c(),
00039     sat_g() {
00040   // Initialize the space dimension as indicated by the box.
00041   space_dim = box.space_dimension();
00042 
00043   // Check for emptiness.
00044   if (box.is_empty()) {
00045     set_empty();
00046     return;
00047   }
00048 
00049   // Zero-dim universe polyhedron.
00050   if (space_dim == 0) {
00051     set_zero_dim_univ();
00052     return;
00053   }
00054 
00055   // Insert a dummy constraint of the highest dimension to avoid the
00056   // need of resizing the matrix of constraints later;
00057   // this constraint will be removed at the end.
00058   con_sys.insert(Variable(space_dim - 1) >= 0);
00059 
00060   for (dimension_type k = space_dim; k-- > 0; ) {
00061     // See if we have a valid lower bound.
00062     bool l_closed = false;
00063     Coefficient l_n, l_d;
00064     bool l_bounded = box.get_lower_bound(k, l_closed, l_n, l_d);
00065     if (l_bounded && topol == NECESSARILY_CLOSED && !l_closed)
00066       throw_invalid_argument("C_Polyhedron(const Box& box):",
00067                              " box has an open lower bound");
00068     // See if we have a valid upper bound.
00069     bool u_closed = false;
00070     Coefficient u_n, u_d;
00071     bool u_bounded = box.get_upper_bound(k, u_closed, u_n, u_d);
00072     if (u_bounded && topol == NECESSARILY_CLOSED && !u_closed)
00073       throw_invalid_argument("C_Polyhedron(const Box& box):",
00074                              " box has an open upper bound");
00075 
00076     // See if we have an implicit equality constraint.
00077     if (l_bounded && u_bounded
00078         && l_closed && u_closed
00079         && l_n == u_n && l_d == u_d) {
00080       // Add the constraint `l_d*v_k == l_n'.
00081       con_sys.insert(l_d * Variable(k) == l_n);
00082     }
00083     else {
00084       // Check if a lower bound constraint is required.
00085       if (l_bounded) {
00086        if (l_closed)
00087          // Add the constraint `l_d*v_k >= l_n'.
00088          con_sys.insert(l_d * Variable(k) >= l_n);
00089        else
00090          // Add the constraint `l_d*v_k > l_n'.
00091          con_sys.insert(l_d * Variable(k) > l_n);
00092       }
00093       // Check if an upper bound constraint is required.
00094       if (u_bounded) {
00095        if (u_closed)
00096          // Add the constraint `u_d*v_k <= u_n'.
00097          con_sys.insert(u_d * Variable(k) <= u_n);
00098        else
00099          // Add the constraint `u_d*v_k < u_n'.
00100          con_sys.insert(u_d * Variable(k) < u_n);
00101       }
00102     }
00103   }
00104 
00105   // Adding the low-level constraints.
00106   con_sys.add_low_level_constraints();
00107   // Now removing the dummy constraint inserted before.
00108   dimension_type n_rows = con_sys.num_rows() - 1;
00109   con_sys[0].swap(con_sys[n_rows]);
00110   con_sys.set_sorted(false);
00111   // NOTE: here there are no pending constraints.
00112   con_sys.set_index_first_pending_row(n_rows);
00113   con_sys.erase_to_end(n_rows);
00114 
00115   // Constraints are up-to-date.
00116   set_constraints_up_to_date();
00117   assert(OK());
00118 }

Parma_Polyhedra_Library::Polyhedron::~Polyhedron (  )  [inline]

Destructor.

Definition at line 81 of file Polyhedron.inlines.hh.

00081                         {
00082 }


Member Function Documentation

dimension_type Parma_Polyhedra_Library::Polyhedron::max_space_dimension (  )  [inline, static]

Returns the maximum space dimension all kinds of Polyhedron can handle.

Definition at line 40 of file Polyhedron.inlines.hh.

References Parma_Polyhedra_Library::Generator_System::max_space_dimension(), and Parma_Polyhedra_Library::Constraint_System::max_space_dimension().

Referenced by add_space_dimensions_and_embed(), add_space_dimensions_and_project(), concatenate_assign(), expand_space_dimension(), and Polyhedron().

00040                                 {
00041   using std::min;
00042   // One dimension is reserved to have a value of type dimension_type
00043   // that does not represent a legal dimension.
00044   return min(std::numeric_limits<dimension_type>::max() - 1,
00045              min(Constraint_System::max_space_dimension(),
00046                  Generator_System::max_space_dimension()
00047                  )
00048              );
00049 }

PPL::Polyhedron & Parma_Polyhedra_Library::Polyhedron::operator= ( const Polyhedron y  )  [protected]

The assignment operator. (*this and y can be dimension-incompatible.).

Definition at line 306 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Linear_System::assign_with_pending(), con_sys, constraints_are_up_to_date(), gen_sys, generators_are_up_to_date(), marked_empty(), sat_c, sat_c_is_up_to_date(), sat_g, sat_g_is_up_to_date(), set_empty(), set_zero_dim_univ(), space_dim, status, and topology().

Referenced by Parma_Polyhedra_Library::NNC_Polyhedron::operator=(), and Parma_Polyhedra_Library::C_Polyhedron::operator=().

00306                                             {
00307   // Being a protected method, we simply assert that topologies do match.
00308   assert(topology() == y.topology());
00309   space_dim = y.space_dim;
00310   if (y.marked_empty())
00311     set_empty();
00312   else if (space_dim == 0)
00313     set_zero_dim_univ();
00314   else {
00315     status = y.status;
00316     if (y.constraints_are_up_to_date())
00317       con_sys.assign_with_pending(y.con_sys);
00318     if (y.generators_are_up_to_date())
00319       gen_sys.assign_with_pending(y.gen_sys);
00320     if (y.sat_c_is_up_to_date())
00321       sat_c = y.sat_c;
00322     if (y.sat_g_is_up_to_date())
00323       sat_g = y.sat_g;
00324   }
00325   return *this;
00326 }

dimension_type Parma_Polyhedra_Library::Polyhedron::space_dimension (  )  const [inline]

PPL::dimension_type Parma_Polyhedra_Library::Polyhedron::affine_dimension (  )  const

Returns $0$, if *this is empty; otherwise, returns the affine dimension of *this.

Definition at line 38 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::Constraint_System::begin(), Parma_Polyhedra_Library::Constraint_System::end(), is_empty(), minimized_constraints(), and space_dim.

Referenced by ppl_Polyhedron_affine_dimension().

00038                                       {
00039   if (is_empty())
00040     return 0;
00041 
00042   const Constraint_System& cs = minimized_constraints();
00043   dimension_type d = space_dim;
00044   for (Constraint_System::const_iterator i = cs.begin(),
00045          cs_end = cs.end(); i != cs_end; ++i)
00046     if (i->is_equality())
00047       --d;
00048   return d;
00049 }

const PPL::Constraint_System & Parma_Polyhedra_Library::Polyhedron::constraints (  )  const

Returns the system of constraints.

Definition at line 52 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::Constraint_System::adjust_topology_and_space_dimension(), con_sys, constraints_are_up_to_date(), has_pending_constraints(), has_pending_generators(), marked_empty(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), obtain_sorted_constraints(), process_pending_generators(), space_dim, Parma_Polyhedra_Library::Constraint_System::space_dimension(), swap(), topology(), update_constraints(), and Parma_Polyhedra_Library::Constraint_System::zero_dim_empty().

Referenced by Parma_Polyhedra_Library::BD_Shape< T >::BD_Shape(), Parma_Polyhedra_Library::C_Polyhedron::C_Polyhedron(), concatenate_assign(), expand_space_dimension(), minimized_constraints(), Parma_Polyhedra_Library::NNC_Polyhedron::NNC_Polyhedron(), poly_difference_assign(), ppl_Polyhedron_constraints(), and ppl_Polyhedron_get_constraints().

00052                                  {
00053   if (marked_empty()) {
00054     // We want `con_sys' to only contain the unsatisfiable constraint
00055     // of the appropriate dimension.
00056     if (con_sys.num_rows() == 0) {
00057       // The 0-dim unsatisfiable constraint is extended to
00058       // the appropriate dimension and then stored in `con_sys'.
00059       Constraint_System unsat_cs = Constraint_System::zero_dim_empty();
00060       unsat_cs.adjust_topology_and_space_dimension(topology(), space_dim);
00061       const_cast<Constraint_System&>(con_sys).swap(unsat_cs);
00062     }
00063     else {
00064       // Checking that `con_sys' contains the right thing.
00065       assert(con_sys.space_dimension() == space_dim);
00066       assert(con_sys.num_rows() == 1);
00067       assert(con_sys[0].is_inconsistent());
00068     }
00069     return con_sys;
00070   }
00071 
00072   if (space_dim == 0) {
00073     // zero-dimensional universe.
00074     assert(con_sys.num_columns() == 0 && con_sys.num_rows() == 0);
00075     return con_sys;
00076   }
00077 
00078   // If the polyhedron has pending generators, we process them to obtain
00079   // the constraints. No processing is needed if the polyhedron has
00080   // pending constraints.
00081   if (has_pending_generators())
00082     process_pending_generators();
00083   else if (!constraints_are_up_to_date())
00084     update_constraints();
00085 
00086   // TODO: reconsider whether to really sort constraints at this stage.
00087 #if ENSURE_SORTEDNESS
00088   // We insist in returning a sorted system of constraints,
00089   // but sorting is useless if there are pending constraints.
00090   if (!has_pending_constraints())
00091     obtain_sorted_constraints();
00092 #endif
00093   return con_sys;
00094 }

const PPL::Constraint_System & Parma_Polyhedra_Library::Polyhedron::minimized_constraints (  )  const

Returns the system of constraints, with no redundant constraint.

Definition at line 97 of file Polyhedron_public.cc.

References constraints(), is_necessarily_closed(), minimize(), and strongly_minimize_constraints().

Referenced by affine_dimension(), Parma_Polyhedra_Library::BHRZ03_Certificate::BHRZ03_Certificate(), Parma_Polyhedra_Library::H79_Certificate::compare(), Parma_Polyhedra_Library::BHRZ03_Certificate::compare(), Parma_Polyhedra_Library::H79_Certificate::H79_Certificate(), operator<<(), ppl_Polyhedron_get_minimized_constraints(), and ppl_Polyhedron_minimized_constraints().

00097                                            {
00098   // `minimize()' or `strongly_minimize_constraints()'
00099   // will process any pending constraints or generators.
00100   if (is_necessarily_closed())
00101     minimize();
00102   else
00103     strongly_minimize_constraints();
00104   return constraints();
00105 }

const PPL::Generator_System & Parma_Polyhedra_Library::Polyhedron::generators (  )  const

Returns the system of generators.

Definition at line 108 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::Generator_System::adjust_topology_and_space_dimension(), gen_sys, generators_are_minimized(), generators_are_up_to_date(), has_pending_constraints(), has_pending_generators(), is_necessarily_closed(), marked_empty(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), obtain_sorted_generators(), process_pending_constraints(), space_dim, Parma_Polyhedra_Library::Generator_System::space_dimension(), swap(), topology(), update_generators(), and zero_dim_univ.

Referenced by Parma_Polyhedra_Library::BD_Shape< T >::BD_Shape(), map_space_dimensions(), minimized_generators(), ppl_Polyhedron_generators(), and ppl_Polyhedron_get_generators().

00108                                 {
00109   if (marked_empty()) {
00110     assert(gen_sys.num_rows() == 0);
00111     // We want `gen_sys' to have the appropriate space dimension,
00112     // even though it is an empty generator system.
00113     if (gen_sys.space_dimension() != space_dim) {
00114       Generator_System gs;
00115       gs.adjust_topology_and_space_dimension(topology(), space_dim);
00116       const_cast<Generator_System&>(gen_sys).swap(gs);
00117     }
00118     return gen_sys;
00119   }
00120 
00121   if (space_dim == 0) {
00122     assert(gen_sys.num_columns() == 0 && gen_sys.num_rows() == 0);
00123     return Generator_System::zero_dim_univ();
00124   }
00125 
00126   // If the polyhedron has pending constraints, we process them to obtain
00127   // the generators (we may discover that the polyhedron is empty).
00128   // No processing is needed if the polyhedron has pending generators.
00129   if ((has_pending_constraints() && !process_pending_constraints())
00130       || (!generators_are_up_to_date() && !update_generators())) {
00131     // We have just discovered that `*this' is empty.
00132     assert(gen_sys.num_rows() == 0);
00133     // We want `gen_sys' to have the appropriate space dimension,
00134     // even though it is an empty generator system.
00135     if (gen_sys.space_dimension() != space_dim) {
00136       Generator_System gs;
00137       gs.adjust_topology_and_space_dimension(topology(), space_dim);
00138       const_cast<Generator_System&>(gen_sys).swap(gs);
00139     }
00140     return gen_sys;
00141   }
00142 
00143   // TODO: reconsider whether to really sort generators at this stage.
00144 #if ENSURE_SORTEDNESS
00145   // We insist in returning a sorted system of generators,
00146   // but sorting is useless if there are pending generators.
00147   if (!has_pending_generators())
00148     obtain_sorted_generators();
00149 #else
00150   // In the case of an NNC polyhedron, if the generator system is fully
00151   // minimized (i.e., minimized and with no pending generator), then
00152   // return a sorted system of generators: this is needed so that the
00153   // const_iterator could correctly filter out the matched closure points.
00154   if (!is_necessarily_closed()
00155       && generators_are_minimized() && !has_pending_generators())
00156     obtain_sorted_generators();
00157 #endif
00158   return gen_sys;
00159 }

const PPL::Generator_System & Parma_Polyhedra_Library::Polyhedron::minimized_generators (  )  const

Returns the system of generators, with no redundant generator.

Definition at line 162 of file Polyhedron_public.cc.

References generators(), is_necessarily_closed(), minimize(), and strongly_minimize_generators().

Referenced by Parma_Polyhedra_Library::BHRZ03_Certificate::BHRZ03_Certificate(), Parma_Polyhedra_Library::BHRZ03_Certificate::compare(), ppl_Polyhedron_get_minimized_generators(), and ppl_Polyhedron_minimized_generators().

00162                                           {
00163   // `minimize()' or `strongly_minimize_generators()'
00164   // will process any pending constraints or generators.
00165   if (is_necessarily_closed())
00166     minimize();
00167   else
00168     strongly_minimize_generators();
00169   // Note: calling generators() on a strongly minimized NNC generator
00170   // system will also ensure sortedness, which is required to correctly
00171   // filter away the matched closure points.
00172   return generators();
00173 }

PPL::Poly_Con_Relation Parma_Polyhedra_Library::Polyhedron::relation_with ( const Constraint c  )  const

Returns the relations holding between the polyhedron *this and the constraint c.

Exceptions:
std::invalid_argument Thrown if *this and constraint c are dimension-incompatible.

Definition at line 176 of file Polyhedron_public.cc.

References gen_sys, generators_are_up_to_date(), has_pending_constraints(), Parma_Polyhedra_Library::Constraint::inhomogeneous_term(), Parma_Polyhedra_Library::Poly_Con_Relation::is_disjoint(), Parma_Polyhedra_Library::Constraint::is_equality(), Parma_Polyhedra_Library::Poly_Con_Relation::is_included(), Parma_Polyhedra_Library::Constraint::is_inconsistent(), Parma_Polyhedra_Library::Constraint::is_strict_inequality(), marked_empty(), process_pending_constraints(), Parma_Polyhedra_Library::Generator_System::relation_with(), Parma_Polyhedra_Library::Poly_Con_Relation::saturates(), space_dim, Parma_Polyhedra_Library::Constraint::space_dimension(), throw_dimension_incompatible(), and update_generators().

Referenced by BHRZ03_combining_constraints(), BHRZ03_evolving_points(), BHRZ03_evolving_rays(), poly_difference_assign(), ppl_Polyhedron_relation_with_constraint(), ppl_Polyhedron_relation_with_Constraint(), ppl_Polyhedron_relation_with_generator(), and ppl_Polyhedron_relation_with_Generator().

00176                                                       {
00177   // Dimension-compatibility check.
00178   if (space_dim < c.space_dimension())
00179     throw_dimension_incompatible("relation_with(c)", "c", c);
00180 
00181   if (marked_empty())
00182     return Poly_Con_Relation::saturates()
00183       && Poly_Con_Relation::is_included()
00184       && Poly_Con_Relation::is_disjoint();
00185 
00186   if (space_dim == 0)
00187     if (c.is_inconsistent())
00188       if (c.is_strict_inequality() && c.inhomogeneous_term() == 0)
00189         // The constraint 0 > 0 implicitly defines the hyperplane 0 = 0;
00190         // thus, the zero-dimensional point also saturates it.
00191         return Poly_Con_Relation::saturates()
00192           && Poly_Con_Relation::is_disjoint();
00193       else
00194         return Poly_Con_Relation::is_disjoint();
00195     else if (c.is_equality() || c.inhomogeneous_term() == 0)
00196       return Poly_Con_Relation::saturates()
00197         && Poly_Con_Relation::is_included();
00198     else
00199       // The zero-dimensional point saturates
00200       // neither the positivity constraint 1 >= 0,
00201       // nor the strict positivity constraint 1 > 0.
00202       return Poly_Con_Relation::is_included();
00203 
00204   if ((has_pending_constraints() && !process_pending_constraints())
00205       || (!generators_are_up_to_date() && !update_generators()))
00206     // The polyhedron is empty.
00207     return Poly_Con_Relation::saturates()
00208       && Poly_Con_Relation::is_included()
00209       && Poly_Con_Relation::is_disjoint();
00210 
00211   return gen_sys.relation_with(c);
00212 }

PPL::Poly_Gen_Relation Parma_Polyhedra_Library::Polyhedron::relation_with ( const Generator g  )  const

Returns the relations holding between the polyhedron *this and the generator g.

Exceptions:
std::invalid_argument Thrown if *this and generator g are dimension-incompatible.

Definition at line 215 of file Polyhedron_public.cc.

References con_sys, constraints_are_up_to_date(), has_pending_generators(), marked_empty(), Parma_Polyhedra_Library::Poly_Gen_Relation::nothing(), process_pending_generators(), Parma_Polyhedra_Library::Constraint_System::satisfies_all_constraints(), space_dim, Parma_Polyhedra_Library::Generator::space_dimension(), Parma_Polyhedra_Library::Poly_Gen_Relation::subsumes(), throw_dimension_incompatible(), and update_constraints().

00215                                                      {
00216   // Dimension-compatibility check.
00217   if (space_dim < g.space_dimension())
00218     throw_dimension_incompatible("relation_with(g)", "g", g);
00219 
00220   // The empty polyhedron cannot subsume a generator.
00221   if (marked_empty())
00222     return Poly_Gen_Relation::nothing();
00223 
00224   // A universe polyhedron in a zero-dimensional space subsumes
00225   // all the generators of a zero-dimensional space.
00226   if (space_dim == 0)
00227     return Poly_Gen_Relation::subsumes();
00228 
00229   if (has_pending_generators())
00230     process_pending_generators();
00231   else if (!constraints_are_up_to_date())
00232     update_constraints();
00233 
00234   return
00235     con_sys.satisfies_all_constraints(g)
00236     ? Poly_Gen_Relation::subsumes()
00237     : Poly_Gen_Relation::nothing();
00238 }

bool Parma_Polyhedra_Library::Polyhedron::is_empty (  )  const [inline]

Returns true if and only if *this is an empty polyhedron.

Definition at line 279 of file Polyhedron.inlines.hh.

References generators_are_up_to_date(), has_pending_constraints(), marked_empty(), and minimize().

Referenced by affine_dimension(), bounded_affine_preimage(), contains(), generalized_affine_image(), generalized_affine_preimage(), is_disjoint_from(), operator<<(), ppl_Polyhedron_is_empty(), and shrink_bounding_box().

00279                            {
00280   if (marked_empty())
00281     return true;
00282   // Try a fast-fail test: if generators are up-to-date and
00283   // there are no pending constraints, then the generator system
00284   // (since it is well formed) contains a point.
00285   if (generators_are_up_to_date() && !has_pending_constraints())
00286     return false;
00287   return !minimize();
00288 }

bool Parma_Polyhedra_Library::Polyhedron::is_universe (  )  const

Returns true if and only if *this is a universe polyhedron.

Definition at line 241 of file Polyhedron_public.cc.

References con_sys, constraints_are_minimized(), constraints_are_up_to_date(), Parma_Polyhedra_Library::Linear_System::first_pending_row(), gen_sys, generators_are_minimized(), generators_are_up_to_date(), has_pending_constraints(), has_pending_generators(), is_necessarily_closed(), Parma_Polyhedra_Library::Generator::LINE, marked_empty(), minimize(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), obtain_sorted_constraints(), process_pending_generators(), Parma_Polyhedra_Library::Generator::RAY, and space_dim.

Referenced by Parma_Polyhedra_Library::BD_Shape< T >::BD_Shape(), ppl_Polyhedron_is_universe(), and shrink_bounding_box().

00241                                  {
00242   if (marked_empty())
00243     return false;
00244 
00245   if (space_dim == 0)
00246     return true;
00247 
00248   if (!has_pending_generators() && constraints_are_up_to_date()) {
00249     // Search for a constraint that is not a tautology.
00250     for (dimension_type i = con_sys.num_rows(); i-- > 0; )
00251       if (!con_sys[i].is_tautological())
00252         return false;
00253     // All the constraints are tautologies.
00254     return true;
00255   }
00256 
00257   assert(!has_pending_constraints() && generators_are_up_to_date());
00258 
00259   // Try a fast-fail test.
00260   dimension_type num_lines = 0;
00261   dimension_type num_rays = 0;
00262   const dimension_type first_pending = gen_sys.first_pending_row();
00263   for (dimension_type i = first_pending; i-- > 0; )
00264     switch (gen_sys[i].type()) {
00265     case Generator::RAY:
00266       ++num_rays;
00267       break;
00268     case Generator::LINE:
00269       ++num_lines;
00270       break;
00271     default:
00272       break;
00273     }
00274 
00275   if (has_pending_generators()) {
00276     // The non-pending part of `gen_sys' was minimized:
00277     // a success-first test is possible in this case.
00278     assert(generators_are_minimized());
00279     if (num_lines == space_dim) {
00280       assert(num_rays == 0);
00281       return true;
00282     }
00283     assert(num_lines < space_dim);
00284     // Now scan the pending generators.
00285     dimension_type num_pending_lines = 0;
00286     dimension_type num_pending_rays = 0;
00287     const dimension_type gs_num_rows = gen_sys.num_rows();
00288     for (dimension_type i = first_pending; i < gs_num_rows; ++i)
00289       switch (gen_sys[i].type()) {
00290       case Generator::RAY:
00291         ++num_pending_rays;
00292         break;
00293       case Generator::LINE:
00294         ++num_pending_lines;
00295         break;
00296       default:
00297         break;
00298       }
00299     // If no pending rays and lines were found,
00300     // then it is not the universe polyhedron.
00301     if (num_pending_rays == 0 && num_pending_lines == 0)
00302       return false;
00303     // Factor away the lines already seen (to be on the safe side,
00304     // we assume they are all linearly independent).
00305     if (num_lines + num_pending_lines < space_dim) {
00306       const dimension_type num_dims_missing
00307         = space_dim - (num_lines + num_pending_lines);
00308       // In order to span an n dimensional space (where n = num_dims_missing),
00309       // at least n+1 rays are needed.
00310       if (num_rays + num_pending_rays <= num_dims_missing)
00311         return false;
00312     }
00313   }
00314   else {
00315     // There is nothing pending.
00316     if (generators_are_minimized()) {
00317       // The exact test is possible.
00318       assert(num_rays == 0 || num_lines < space_dim);
00319       return num_lines == space_dim;
00320     }
00321     else
00322       // Only the fast-fail test can be computed: in order to span
00323       // an n dimensional space (where n = space_dim - num_lines),
00324       // at least n+1 rays are needed.
00325       if (num_lines < space_dim && num_lines + num_rays <= space_dim)
00326         return false;
00327   }
00328 
00329   // We need the polyhedron in minimal form.
00330   if (has_pending_generators())
00331     process_pending_generators();
00332   else if (!constraints_are_minimized())
00333     minimize();
00334   if (is_necessarily_closed())
00335     return (con_sys.num_rows() == 1
00336             && con_sys[0].is_inequality()
00337             && con_sys[0].is_tautological());
00338   else {
00339     // NNC polyhedron.
00340     if (con_sys.num_rows() != 2
00341         || con_sys[0].is_equality()
00342         || con_sys[1].is_equality())
00343       return false;
00344     else {
00345       // If the system of constraints contains two rows that
00346       // are not equalities, we are sure that they are
00347       // epsilon constraints: in this case we know that
00348       // the polyhedron is universe.
00349 #ifndef NDEBUG
00350       obtain_sorted_constraints();
00351       const Constraint& eps_leq_one = con_sys[0];
00352       const Constraint& eps_geq_zero = con_sys[1];
00353       const dimension_type eps_index = con_sys.num_columns() - 1;
00354       assert(eps_leq_one[0] > 0 && eps_leq_one[eps_index] < 0
00355              && eps_geq_zero[0] == 0 && eps_geq_zero[eps_index] > 0);
00356       for (dimension_type i = 1; i < eps_index; ++i)
00357         assert(eps_leq_one[i] == 0 && eps_geq_zero[i] == 0);
00358 #endif
00359       return true;
00360     }
00361   }
00362 }

bool Parma_Polyhedra_Library::Polyhedron::is_topologically_closed (  )  const

Returns true if and only if *this is a topologically closed subset of the vector space.

Definition at line 385 of file Polyhedron_public.cc.

References con_sys, gen_sys, generators_are_minimized(), has_something_pending(), Parma_Polyhedra_Library::Constraint_System::has_strict_inequalities(), Parma_Polyhedra_Library::Generator::is_closure_point(), Parma_Polyhedra_Library::Generator::is_matching_closure_point(), is_necessarily_closed(), Parma_Polyhedra_Library::Generator::is_point(), marked_empty(), Parma_Polyhedra_Library::Generator_System::num_lines(), Parma_Polyhedra_Library::Matrix::num_rows(), process_pending(), space_dim, and strongly_minimize_constraints().

Referenced by ppl_Polyhedron_is_topologically_closed().

00385                                              {
00386   // Necessarily closed polyhedra are trivially closed.
00387   if (is_necessarily_closed())
00388     return true;
00389   // Any empty or zero-dimensional polyhedron is closed.
00390   if (marked_empty()
00391       || space_dim == 0
00392       || (has_something_pending() && !process_pending()))
00393      return true;
00394 
00395   // At this point there are no pending constraints or generators.
00396   assert(!has_something_pending());
00397 
00398   if (generators_are_minimized()) {
00399     // A polyhedron is closed if and only if all of its (non-redundant)
00400     // closure points are matched by a corresponding point.
00401     const dimension_type n_rows = gen_sys.num_rows();
00402     const dimension_type n_lines = gen_sys.num_lines();
00403     for (dimension_type i = n_rows; i-- > n_lines; ) {
00404       const Generator& gi = gen_sys[i];
00405       if (gi.is_closure_point()) {
00406         bool gi_has_no_matching_point = true;
00407         for (dimension_type j = n_rows; j-- > n_lines; ) {
00408           const Generator& gj = gen_sys[j];
00409           if (i != j
00410               && gj.is_point()
00411               && gi.is_matching_closure_point(gj)) {
00412             gi_has_no_matching_point = false;
00413             break;
00414           }
00415         }
00416         if (gi_has_no_matching_point)
00417           return false;
00418       }
00419     }
00420     // All closure points are matched.
00421     return true;
00422   }
00423 
00424   // A polyhedron is closed if, after strong minimization
00425   // of its constraint system, it has no strict inequalities.
00426   strongly_minimize_constraints();
00427   return marked_empty() || !con_sys.has_strict_inequalities();
00428 }

bool Parma_Polyhedra_Library::Polyhedron::is_disjoint_from ( const Polyhedron y  )  const

Returns true if and only if *this and y are disjoint.

Exceptions:
std::invalid_argument Thrown if x and y are topology-incompatible or dimension-incompatible.

Definition at line 2871 of file Polyhedron_public.cc.

References intersection_assign_and_minimize(), and is_empty().

Referenced by Parma_Polyhedra_Library::Polyhedra_Powerset< PH >::check_containment(), and ppl_Polyhedron_is_disjoint_from_Polyhedron().

02871                                                          {
02872   Polyhedron z = *this;
02873   z.intersection_assign_and_minimize(y);
02874   return z.is_empty();
02875 }

bool Parma_Polyhedra_Library::Polyhedron::is_bounded (  )  const

Returns true if and only if *this is a bounded polyhedron.

Definition at line 365 of file Polyhedron_public.cc.

References gen_sys, generators_are_up_to_date(), has_pending_constraints(), marked_empty(), Parma_Polyhedra_Library::Matrix::num_rows(), process_pending_constraints(), space_dim, and update_generators().

Referenced by ppl_Polyhedron_is_bounded().

00365                                 {
00366   // A zero-dimensional or empty polyhedron is bounded.
00367   if (space_dim == 0
00368       || marked_empty()
00369       || (has_pending_constraints() && !process_pending_constraints())
00370       || (!generators_are_up_to_date() && !update_generators()))
00371     return true;
00372 
00373   // If the system of generators contains any line or a ray,
00374   // then the polyhedron is unbounded.
00375   for (dimension_type i = gen_sys.num_rows(); i-- > 0; )
00376     if (gen_sys[i].is_line_or_ray())
00377       return false;
00378 
00379   // The system of generators is composed only by
00380   // points and closure points: the polyhedron is bounded.
00381   return true;
00382 }

bool Parma_Polyhedra_Library::Polyhedron::bounds_from_above ( const Linear_Expression expr  )  const [inline]

Returns true if and only if expr is bounded from above in *this.

Exceptions:
std::invalid_argument Thrown if expr and *this are dimension-incompatible.

Definition at line 291 of file Polyhedron.inlines.hh.

References bounds().

Referenced by ppl_Polyhedron_bounds_from_above().

00291                                                                  {
00292   return bounds(expr, true);
00293 }

bool Parma_Polyhedra_Library::Polyhedron::bounds_from_below ( const Linear_Expression expr  )  const [inline]

Returns true if and only if expr is bounded from below in *this.

Exceptions:
std::invalid_argument Thrown if expr and *this are dimension-incompatible.

Definition at line 296 of file Polyhedron.inlines.hh.

References bounds().

Referenced by ppl_Polyhedron_bounds_from_below().

00296                                                                  {
00297   return bounds(expr, false);
00298 }

bool Parma_Polyhedra_Library::Polyhedron::maximize ( const Linear_Expression expr,
Coefficient sup_n,
Coefficient sup_d,
bool &  maximum 
) const [inline]

Returns true if and only if *this is not empty and expr is bounded from above in *this, in which case the supremum value is computed.

Parameters:
expr The linear expression to be maximized subject to *this;
sup_n The numerator of the supremum value;
sup_d The denominator of the supremum value;
maximum true if and only if the supremum is also the maximum value.
Exceptions:
std::invalid_argument Thrown if expr and *this are dimension-incompatible.
If *this is empty or expr is not bounded from above, false is returned and sup_n, sup_d and maximum are left untouched.

Definition at line 301 of file Polyhedron.inlines.hh.

References max_min().

Referenced by ppl_Polyhedron_maximize(), and ppl_Polyhedron_maximize_with_point().

00303                                           {
00304   Generator g(point());
00305   return max_min(expr, true, sup_n, sup_d, maximum, g);
00306 }

bool Parma_Polyhedra_Library::Polyhedron::maximize ( const Linear_Expression expr,
Coefficient sup_n,
Coefficient sup_d,
bool &  maximum,
Generator point 
) const [inline]

Returns true if and only if *this is not empty and expr is bounded from above in *this, in which case the supremum value and a point where expr reaches it are computed.

Parameters:
expr The linear expression to be maximized subject to *this;
sup_n The numerator of the supremum value;
sup_d The denominator of the supremum value;
maximum true if and only if the supremum is also the maximum value;
point When maximization succeeds, will be assigned the point or closure point where expr reaches its supremum value.
Exceptions:
std::invalid_argument Thrown if expr and *this are dimension-incompatible.
If *this is empty or expr is not bounded from above, false is returned and sup_n, sup_d, maximum and point are left untouched.

Definition at line 309 of file Polyhedron.inlines.hh.

References max_min().

00311                                          {
00312   return max_min(expr, true, sup_n, sup_d, maximum, g);
00313 }

bool Parma_Polyhedra_Library::Polyhedron::minimize ( const Linear_Expression expr,
Coefficient inf_n,
Coefficient inf_d,
bool &  minimum 
) const [inline]

Returns true if and only if *this is not empty and expr is bounded from below in *this, in which case the infimum value is computed.

Parameters:
expr The linear expression to be minimized subject to *this;
inf_n The numerator of the infimum value;
inf_d The denominator of the infimum value;
minimum true if and only if the infimum is also the minimum value.
Exceptions:
std::invalid_argument Thrown if expr and *this are dimension-incompatible.
If *this is empty or expr is not bounded from below, false is returned and inf_n, inf_d and minimum are left untouched.

Definition at line 316 of file Polyhedron.inlines.hh.

References max_min().

Referenced by Parma_Polyhedra_Library::BHRZ03_Certificate::BHRZ03_Certificate(), BHRZ03_widening_assign(), Parma_Polyhedra_Library::H79_Certificate::compare(), Parma_Polyhedra_Library::BHRZ03_Certificate::compare(), Parma_Polyhedra_Library::H79_Certificate::H79_Certificate(), H79_widening_assign(), intersection_assign_and_minimize(), is_included_in(), limited_BHRZ03_extrapolation_assign(), limited_H79_extrapolation_assign(), poly_difference_assign(), poly_hull_assign_and_minimize(), ppl_Polyhedron_minimize(), and ppl_Polyhedron_minimize_with_point().

00318                                           {
00319   Generator g(point());
00320   return max_min(expr, false, inf_n, inf_d, minimum, g);
00321 }

bool Parma_Polyhedra_Library::Polyhedron::minimize ( const Linear_Expression expr,
Coefficient inf_n,
Coefficient inf_d,
bool &  minimum,
Generator point 
) const [inline]

Returns true if and only if *this is not empty and expr is bounded from below in *this, in which case the infimum value and a point where expr reaches it are computed.

Parameters:
expr The linear expression to be minimized subject to *this;
inf_n The numerator of the infimum value;
inf_d The denominator of the infimum value;
minimum true if and only if the infimum is also the minimum value;
point When minimization succeeds, will be assigned a point or closure point where expr reaches its infimum value.
Exceptions:
std::invalid_argument Thrown if expr and *this are dimension-incompatible.
If *this is empty or expr is not bounded from below, false is returned and inf_n, inf_d, minimum and point are left untouched.

Definition at line 324 of file Polyhedron.inlines.hh.

References max_min().

00326                                          {
00327   return max_min(expr, false, inf_n, inf_d, minimum, g);
00328 }

bool Parma_Polyhedra_Library::Polyhedron::contains ( const Polyhedron y  )  const

Returns true if and only if *this contains y.

Exceptions:
std::invalid_argument Thrown if *this and y are topology-incompatible or dimension-incompatible.

Definition at line 2847 of file Polyhedron_public.cc.

References is_empty(), is_included_in(), marked_empty(), quick_equivalence_test(), space_dim, throw_dimension_incompatible(), throw_topology_incompatible(), topology(), and TVB_TRUE.

Referenced by BHRZ03_combining_constraints(), BHRZ03_evolving_points(), BHRZ03_evolving_rays(), BHRZ03_widening_assign(), Parma_Polyhedra_Library::Polyhedra_Powerset< PH >::check_containment(), H79_widening_assign(), limited_BHRZ03_extrapolation_assign(), limited_H79_extrapolation_assign(), poly_difference_assign(), poly_hull_assign_if_exact(), ppl_Polyhedron_contains_Polyhedron(), and strictly_contains().

02847                                                  {
02848   const Polyhedron& x = *this;
02849 
02850   // Topology compatibility check.
02851   if (x.topology() != y.topology())
02852     throw_topology_incompatible("contains(y)", "y", y);
02853 
02854   // Dimension-compatibility check.
02855   if (x.space_dim != y.space_dim)
02856     throw_dimension_incompatible("contains(y)", "y", y);
02857 
02858   if (y.marked_empty())
02859     return true;
02860   else if (x.marked_empty())
02861     return y.is_empty();
02862   else if (y.space_dim == 0)
02863     return true;
02864   else if (x.quick_equivalence_test(y) == Polyhedron::TVB_TRUE)
02865     return true;
02866   else
02867     return y.is_included_in(x);
02868 }

bool Parma_Polyhedra_Library::Polyhedron::strictly_contains ( const Polyhedron y  )  const [inline]

Returns true if and only if *this strictly contains y.

Exceptions:
std::invalid_argument Thrown if *this and y are topology-incompatible or dimension-incompatible.

Definition at line 337 of file Polyhedron.inlines.hh.

References contains().

Referenced by ppl_Polyhedron_strictly_contains_Polyhedron().

00337                                                        {
00338   const Polyhedron& x = *this;
00339   return x.contains(y) && !y.contains(x);
00340 }

template<typename Box>
void Parma_Polyhedra_Library::Polyhedron::shrink_bounding_box ( Box &  box,
Complexity_Class  complexity = ANY_COMPLEXITY 
) const [inline]

Uses *this to shrink a generic, interval-based bounding box. Assigns to box the intersection of box with the smallest bounding box containing *this.

Parameters:
box The bounding box to be shrunk;
complexity The complexity class of the algorithm to be used.
If the polyhedron *this or box is empty, then the empty box is returned.

If *this and box are non-empty, then, for each space dimension $k$ with variable $\mathrm{var}$, let $u$ be the upper and $l$ the lower bound of the smallest interval containing *this.

If $l$ is infinite, then box is unaltered; if $l$ is finite, then the box interval for space dimension $k$ is (destructively) intersected with $[l, +\mathrm{infty})$ if a point of *this satisfies $\mathrm{var} == l$ and with $(l, +\mathrm{infty})$ otherwise.

Similarly, if $u$ is infinite, then box is unaltered; if $u$ is finite, then the box interval for space dimension $k$ is (destructively) intersected with $(-\mathrm{infty}, u]$ if a point of *this satisfies $\mathrm{var} == u$ and with $(-\mathrm{infty}, u)$ otherwise.

The template class Box must provide the following methods, whose return values, if any, are simply ignored.

causes the box to become empty, i.e., to represent the empty set.
      raise_lower_bound(dimension_type k, bool closed,
                        Coefficient_traits::const_reference n,
                        Coefficient_traits::const_reference d)
intersects the interval corresponding to the k-th space dimension with $[n/d, +\infty)$ if closed is true, with $(n/d, +\infty)$ if closed is false.
      lower_upper_bound(dimension_type k, bool closed,
                        Coefficient_traits::const_reference n,
                        Coefficient_traits::const_reference d)
intersects the interval corresponding to the k-th space dimension with $(-\infty, n/d]$ if closed is true, with $(-\infty, n/d)$ if closed is false.

The function raise_lower_bound(k, closed, n, d) will be called at most once for each possible value for k and for all such calls the fraction $n/d$ will be in canonical form, that is, $n$ and $d$ have no common factors and $d$ is positive, $0/1$ being the unique representation for zero. The same guarantee is offered for the function lower_upper_bound(k, closed, n, d).

Definition at line 122 of file Polyhedron.templates.hh.

References Parma_Polyhedra_Library::ANY_COMPLEXITY, Parma_Polyhedra_Library::assign_r(), Parma_Polyhedra_Library::Generator_System::begin(), Parma_Polyhedra_Library::Constraint_System::begin(), Parma_Polyhedra_Library::Boundary::bound(), Parma_Polyhedra_Library::UBoundary::CLOSED, Parma_Polyhedra_Library::LBoundary::CLOSED, Parma_Polyhedra_Library::Generator::CLOSURE_POINT, Parma_Polyhedra_Library::Generator::coefficient(), Parma_Polyhedra_Library::Constraint::coefficient(), con_sys, constraints_are_minimized(), constraints_are_up_to_date(), Parma_Polyhedra_Library::Generator::divisor(), Parma_Polyhedra_Library::Generator_System::end(), Parma_Polyhedra_Library::Constraint_System::end(), Parma_Polyhedra_Library::Constraint::EQUALITY, gen_sys, generators_are_up_to_date(), has_pending_constraints(), has_something_pending(), Parma_Polyhedra_Library::Constraint::inhomogeneous_term(), Parma_Polyhedra_Library::Boundary::is_closed(), is_empty(), Parma_Polyhedra_Library::Constraint::is_inconsistent(), Parma_Polyhedra_Library::is_minus_infinity(), is_necessarily_closed(), Parma_Polyhedra_Library::is_plus_infinity(), Parma_Polyhedra_Library::LP_Problem::is_satisfiable(), is_universe(), Parma_Polyhedra_Library::Generator::LINE, marked_empty(), Parma_Polyhedra_Library::MINUS_INFINITY, Parma_Polyhedra_Library::Constraint::NONSTRICT_INEQUALITY, Parma_Polyhedra_Library::Linear_System::num_pending_rows(), Parma_Polyhedra_Library::Matrix::num_rows(), Parma_Polyhedra_Library::UBoundary::OPEN, Parma_Polyhedra_Library::LBoundary::OPEN, Parma_Polyhedra_Library::PLUS_INFINITY, Parma_Polyhedra_Library::Generator::POINT, process_pending(), Parma_Polyhedra_Library::raw_value(), Parma_Polyhedra_Library::Generator::RAY, Parma_Polyhedra_Library::SIMPLEX_COMPLEXITY, Parma_Polyhedra_Library::Constraint_System::simplify(), space_dim, Parma_Polyhedra_Library::Constraint::STRICT_INEQUALITY, TEMP_INTEGER, Parma_Polyhedra_Library::Generator::type(), Parma_Polyhedra_Library::Constraint::type(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

Referenced by bounded_BHRZ03_extrapolation_assign(), bounded_H79_extrapolation_assign(), ppl_Polyhedron_get_bounding_box(), and ppl_Polyhedron_shrink_bounding_box().

00122                                                                            {
00123   bool reduce_complexity = (complexity != ANY_COMPLEXITY);
00124   if (!reduce_complexity
00125       || (!has_something_pending() && constraints_are_minimized())) {
00126     // If the constraint system is minimized, the test `is_universe()'
00127     // is not exponential.
00128     if (is_universe())
00129       return;
00130   }
00131   if (reduce_complexity) {
00132     if (marked_empty()
00133         || (generators_are_up_to_date() && gen_sys.num_rows() == 0)) {
00134       box.set_empty();
00135       return;
00136     }
00137     else if (constraints_are_up_to_date()) {
00138       // See if there is at least one inconsistent constraint in `con_sys'.
00139       for (Constraint_System::const_iterator i = con_sys.begin(),
00140              cs_end = con_sys.end(); i != cs_end; ++i)
00141         if (i->is_inconsistent()) {
00142           box.set_empty();
00143           return;
00144         }
00145       // If `complexity' allows it, use the LP_Problem solver to determine
00146       // whether or not the polyhedron is empty.
00147       if (complexity == SIMPLEX_COMPLEXITY
00148           // TODO: find a workaround for NNC polyhedra.
00149           && is_necessarily_closed()) {
00150         LP_Problem lp(con_sys);
00151         if (!lp.is_satisfiable()) {
00152           box.set_empty();
00153           return;
00154         }
00155       }
00156     }
00157   }
00158   else
00159     // The flag `reduce_complexity' is `false'.
00160     // Note that the test `is_empty()' is exponential in the worst case.
00161     if (is_empty()) {
00162       box.set_empty();
00163       return;
00164     }
00165 
00166   if (space_dim == 0)
00167     return;
00168 
00169   // The following vectors will store the lower and upper bound
00170   // for each dimension.
00171   // Lower bounds are initialized to open plus infinity.
00172   std::vector<LBoundary>
00173     lower_bound(space_dim,
00174                 LBoundary(ERational(PLUS_INFINITY), LBoundary::OPEN));
00175   // Upper bounds are initialized to open minus infinity.
00176   std::vector<UBoundary>
00177     upper_bound(space_dim,
00178                 UBoundary(ERational(MINUS_INFINITY), UBoundary::OPEN));
00179 
00180   if (!reduce_complexity && has_something_pending())
00181     process_pending();
00182 
00183   // TODO: use simplex to derive variable bounds, if the complexity
00184   // is SIMPLEX_COMPLEXITY.
00185 
00186   if (reduce_complexity &&
00187        (!generators_are_up_to_date() || has_pending_constraints())) {
00188     // Extract easy-to-find bounds from constraints.
00189     assert(constraints_are_up_to_date());
00190 
00191     // We must copy `con_sys' to a temporary matrix,
00192     // as we need to simplify all of the matrix
00193     // (not just the non-pending part of it).
00194     Constraint_System cs(con_sys);
00195     if (cs.num_pending_rows() > 0)
00196       cs.unset_pending_rows();
00197     if (has_pending_constraints() || !constraints_are_minimized())
00198       cs.simplify();
00199 
00200     const Constraint_System::const_iterator cs_begin = cs.begin();
00201     const Constraint_System::const_iterator cs_end = cs.end();
00202 
00203     for (Constraint_System::const_iterator i = cs_begin; i != cs_end; ++i) {
00204       dimension_type varid = space_dim;
00205       const Constraint& c = *i;
00206       // After `simplify()' some constraints may have become inconsistent.
00207       if (c.is_inconsistent()) {
00208         box.set_empty();
00209         return;
00210       }
00211       for (dimension_type j = space_dim; j-- > 0; ) {
00212         // We look for constraints of the form `Variable(j) == k',
00213         // `Variable(j) >= k', and `Variable(j) > k'.
00214         if (c.coefficient(Variable(j)) != 0)
00215           if (varid != space_dim) {
00216             varid = space_dim;
00217             break;
00218           }
00219           else
00220             varid = j;
00221       }
00222       if (varid != space_dim) {
00223         Coefficient_traits::const_reference d = c.coefficient(Variable(varid));
00224         Coefficient_traits::const_reference n = c.inhomogeneous_term();
00225         // The constraint `c' is of the form
00226         // `Variable(varid) + n / d rel 0', where
00227         // `rel' is either the relation `==', `>=', or `>'.
00228         // For the purpose of shrinking intervals, this is
00229         // (morally) turned into `Variable(varid) rel -n/d'.
00230         mpq_class q;
00231         assign_r(q.get_num(), n, ROUND_NOT_NEEDED);
00232         assign_r(q.get_den(), d, ROUND_NOT_NEEDED);
00233         q.canonicalize();
00234         // Turn `n/d' into `-n/d'.
00235         q = -q;
00236         const ERational r(q, ROUND_NOT_NEEDED);
00237         const Constraint::Type c_type = c.type();
00238         switch (c_type) {
00239         case Constraint::EQUALITY:
00240           lower_bound[varid] = LBoundary(r, LBoundary::CLOSED);
00241           upper_bound[varid] = UBoundary(r, UBoundary::CLOSED);
00242           break;
00243         case Constraint::NONSTRICT_INEQUALITY:
00244         case Constraint::STRICT_INEQUALITY:
00245           if (d > 0)
00246           // If `d' is strictly positive, we have a constraint of the
00247           // form `Variable(varid) >= k' or `Variable(varid) > k'.
00248             lower_bound[varid]
00249               = LBoundary(r, (c_type == Constraint::NONSTRICT_INEQUALITY
00250                               ? LBoundary::CLOSED
00251                               : LBoundary::OPEN));
00252           else {
00253             // Otherwise, we are sure that `d' is strictly negative
00254             // and, in this case, we have a constraint of the form
00255             // `Variable(varid) <= k' or `Variable(varid) < k'.
00256             assert(d < 0);
00257             upper_bound[varid]
00258               = UBoundary(r, (c_type == Constraint::NONSTRICT_INEQUALITY
00259                               ? UBoundary::CLOSED
00260                               : UBoundary::OPEN));
00261           }
00262           break;
00263         }
00264       }
00265     }
00266   }
00267   else {
00268     // We are in the case where either the generators are up-to-date
00269     // or reduced complexity is not required.
00270     // Get the generators for *this.
00271 
00272     // We have not to copy `gen_sys', because in this case
00273     // we only read the generators.
00274     const Generator_System& gs = gen_sys;
00275 
00276     // We first need to identify those axes that are unbounded below
00277     // and/or above.
00278     for (Generator_System::const_iterator i = gs.begin(),
00279            gs_end = gs.end(); i != gs_end; ++i) {
00280       // Note: using an iterator, we read also the pending part of the matrix.
00281       const Generator& g = *i;
00282       Generator::Type g_type = g.type();
00283       switch (g_type) {
00284       case Generator::LINE:
00285         // Any axes `j' in which the coefficient is non-zero is unbounded
00286         // both below and above.
00287         for (dimension_type j = space_dim; j-- > 0; )
00288           if (g.coefficient(Variable(j)) != 0) {
00289             lower_bound[j] = LBoundary(ERational(MINUS_INFINITY),
00290                                        LBoundary::OPEN);
00291             upper_bound[j] = UBoundary(ERational(PLUS_INFINITY),
00292                                        UBoundary::OPEN);
00293           }
00294         break;
00295       case Generator::RAY:
00296         // Axes in which the coefficient is negative are unbounded below.
00297         // Axes in which the coefficient is positive are unbounded above.
00298         for (dimension_type j = space_dim; j-- > 0; ) {
00299           int sign = sgn(g.coefficient(Variable(j)));
00300           if (sign < 0)
00301             lower_bound[j] = LBoundary(ERational(MINUS_INFINITY),
00302                                        LBoundary::OPEN);
00303           else if (sign > 0)
00304             upper_bound[j] = UBoundary(ERational(PLUS_INFINITY),
00305                                        UBoundary::OPEN);
00306         }
00307         break;
00308       case Generator::POINT:
00309       case Generator::CLOSURE_POINT:
00310         {
00311           Coefficient_traits::const_reference d = g.divisor();
00312           for (dimension_type j = space_dim; j-- > 0; ) {
00313             Coefficient_traits::const_reference n = g.coefficient(Variable(j));
00314             mpq_class q;
00315             assign_r(q.get_num(), n, ROUND_NOT_NEEDED);
00316             assign_r(q.get_den(), d, ROUND_NOT_NEEDED);
00317             q.canonicalize();
00318             const ERational r(q, ROUND_NOT_NEEDED);
00319             LBoundary lb(r,(g_type == Generator::CLOSURE_POINT
00320                             ? LBoundary::OPEN
00321                             : LBoundary::CLOSED));
00322             if (lb < lower_bound[j])
00323               lower_bound[j] = lb;
00324             UBoundary ub(r, (g_type == Generator::CLOSURE_POINT
00325                              ? UBoundary::OPEN
00326                              : UBoundary::CLOSED));
00327             if (ub > upper_bound[j])
00328               upper_bound[j] = ub;
00329           }
00330         }
00331         break;
00332       }
00333     }
00334   }
00335 
00336   TEMP_INTEGER(n);
00337   TEMP_INTEGER(d);
00338 
00339   // Now shrink the bounded axes.
00340   for (dimension_type j = space_dim; j-- > 0; ) {
00341     // Lower bound.
00342     const LBoundary& lb = lower_bound[j];
00343     const ERational& lr = lb.bound();
00344     if (!is_plus_infinity(lr) && !is_minus_infinity(lr)) {
00345       n = raw_value(lr).get_num();
00346       d = raw_value(lr).get_den();
00347       box.raise_lower_bound(j, lb.is_closed(), n, d);
00348     }
00349 
00350     // Upper bound.
00351     const UBoundary& ub = upper_bound[j];
00352     const ERational& ur = ub.bound();
00353     if (!is_plus_infinity(ur) && !is_minus_infinity(ur)) {
00354       n = raw_value(ur).get_num();
00355       d = raw_value(ur).get_den();
00356       box.lower_upper_bound(j, ub.is_closed(), n, d);
00357     }
00358   }
00359 }

bool Parma_Polyhedra_Library::Polyhedron::OK ( bool  check_not_empty = false  )  const

Checks if all the invariants are satisfied.

Returns:
true if and only if *this satisfies all the invariants and either check_not_empty is false or *this is not empty.
Parameters:
check_not_empty true if and only if, in addition to checking the invariants, *this must be checked to be not empty.
The check is performed so as to intrude as little as possible. If the library has been compiled with run-time assertions enabled, error messages are written on std::cerr in case invariants are violated. This is useful for the purpose of debugging the library.

Definition at line 431 of file Polyhedron_public.cc.

References ascii_dump(), Parma_Polyhedra_Library::Constraint_System::ascii_dump(), Parma_Polyhedra_Library::Generator_System::ascii_dump(), con_sys, constraints_are_minimized(), constraints_are_up_to_date(), Parma_Polyhedra_Library::Matrix::erase_to_end(), Parma_Polyhedra_Library::Linear_System::first_pending_row(), gen_sys, generators_are_minimized(), generators_are_up_to_date(), has_pending_constraints(), has_pending_generators(), Parma_Polyhedra_Library::Generator_System::has_points(), has_something_pending(), is_necessarily_closed(), marked_empty(), minimize(), Parma_Polyhedra_Library::Saturation_Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Constraint_System::num_equalities(), Parma_Polyhedra_Library::Generator_System::num_lines(), Parma_Polyhedra_Library::Linear_System::num_pending_rows(), Parma_Polyhedra_Library::Generator_System::num_rays(), Parma_Polyhedra_Library::Saturation_Matrix::num_rows(), Parma_Polyhedra_Library::Matrix::num_rows(), Parma_Polyhedra_Library::Constraint_System::OK(), Parma_Polyhedra_Library::Generator_System::OK(), Parma_Polyhedra_Library::Polyhedron::Status::OK(), Parma_Polyhedra_Library::Saturation_Matrix::OK(), sat_c, sat_c_is_up_to_date(), sat_g, sat_g_is_up_to_date(), Parma_Polyhedra_Library::Scalar_Products::sign(), Parma_Polyhedra_Library::Constraint_System::simplify(), Parma_Polyhedra_Library::Linear_System::sort_rows(), space_dim, Parma_Polyhedra_Library::Constraint_System::space_dimension(), status, Parma_Polyhedra_Library::Linear_System::strong_normalize(), topology(), Parma_Polyhedra_Library::Linear_System::topology(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

Referenced by add_constraint(), add_generator(), add_recycled_constraints(), add_recycled_constraints_and_minimize(), add_recycled_generators(), add_recycled_generators_and_minimize(), add_space_dimensions_and_embed(), add_space_dimensions_and_project(), affine_image(), affine_preimage(), ascii_load(), BHRZ03_combining_constraints(), BHRZ03_evolving_points(), BHRZ03_evolving_rays(), BHRZ03_widening_assign(), bounded_affine_image(), bounded_affine_preimage(), Parma_Polyhedra_Library::C_Polyhedron::C_Polyhedron(), concatenate_assign(), expand_space_dimension(), fold_space_dimensions(), generalized_affine_image(), generalized_affine_preimage(), H79_widening_assign(), intersection_assign(), intersection_assign_and_minimize(), is_included_in(), limited_BHRZ03_extrapolation_assign(), limited_H79_extrapolation_assign(), map_space_dimensions(), minimize(), Parma_Polyhedra_Library::NNC_Polyhedron::NNC_Polyhedron(), poly_difference_assign(), poly_hull_assign(), poly_hull_assign_and_minimize(), Polyhedron(), ppl_Polyhedron_OK(), process_pending_constraints(), process_pending_generators(), remove_higher_space_dimensions(), remove_pending_to_obtain_constraints(), remove_pending_to_obtain_generators(), remove_space_dimensions(), strongly_minimize_constraints(), strongly_minimize_generators(), time_elapse_assign(), and topological_closure_assign().

00431                                             {
00432 #ifndef NDEBUG
00433   using std::endl;
00434   using std::cerr;
00435 #endif
00436 
00437   // The expected number of columns in the constraint and generator
00438   // systems, if they are not empty.
00439   const dimension_type poly_num_columns
00440     = space_dim + (is_necessarily_closed() ? 1 : 2);
00441 
00442   // Check whether the topologies of `con_sys' and `gen_sys' agree.
00443   if (con_sys.topology() != gen_sys.topology()) {
00444 #ifndef NDEBUG
00445     cerr << "Constraints and generators have different topologies!"
00446          << endl;
00447 #endif
00448     goto bomb;
00449   }
00450 
00451   // Check whether the saturation matrices are well-formed.
00452   if (!sat_c.OK())
00453     goto bomb;
00454   if (!sat_g.OK())
00455     goto bomb;
00456 
00457   // Check whether the status information is legal.
00458   if (!status.OK())
00459     goto bomb;
00460 
00461   if (marked_empty()) {
00462     if (check_not_empty) {
00463       // The caller does not want the polyhedron to be empty.
00464 #ifndef NDEBUG
00465       cerr << "Empty polyhedron!" << endl;
00466 #endif
00467       goto bomb;
00468     }
00469 
00470     // An empty polyhedron is allowed if the system of constraints
00471     // either has no rows or only contains an unsatisfiable constraint
00472     // and if it has no pending constraints or generators.
00473     if (has_something_pending()) {
00474 #ifndef NDEBUG
00475       cerr << "The polyhedron is empty, "
00476            << "but it has something pending" << endl;
00477 #endif
00478       goto bomb;
00479     }
00480     if (con_sys.num_rows() == 0)
00481       return true;
00482     else {
00483       if (con_sys.space_dimension() != space_dim) {
00484 #ifndef NDEBUG
00485         cerr << "The polyhedron is in a space of dimension "
00486              << space_dim
00487              << " while the system of constraints is in a space of dimension "
00488              << con_sys.space_dimension()
00489              << endl;
00490 #endif
00491         goto bomb;
00492       }
00493       if (con_sys.num_rows() != 1) {
00494 #ifndef NDEBUG
00495         cerr << "The system of constraints for an empty polyhedron "
00496              << "has more then one row"
00497              << endl;
00498 #endif
00499         goto bomb;
00500       }
00501       if (!con_sys[0].is_inconsistent()) {
00502 #ifndef NDEBUG
00503         cerr << "Empty polyhedron with a satisfiable system of constraints"
00504              << endl;
00505 #endif
00506         goto bomb;
00507       }
00508       // Here we have only one, inconsistent constraint.
00509       return true;
00510     }
00511   }
00512 
00513   // A zero-dimensional, non-empty polyhedron is legal only if the
00514   // system of constraint `con_sys' and the system of generators
00515   // `gen_sys' have no rows.
00516   if (space_dim == 0) {
00517     if (has_something_pending()) {
00518 #ifndef NDEBUG
00519       cerr << "Zero-dimensional polyhedron with something pending"
00520            << endl;
00521 #endif
00522       goto bomb;
00523     }
00524     if (con_sys.num_rows() != 0 || gen_sys.num_rows() != 0) {
00525 #ifndef NDEBUG
00526       cerr << "Zero-dimensional polyhedron with a non-empty"
00527            << endl
00528            << "system of constraints or generators."
00529            << endl;
00530 #endif
00531       goto bomb;
00532     }
00533     return true;
00534   }
00535 
00536   // A polyhedron is defined by a system of constraints
00537   // or a system of generators: at least one of them must be up to date.
00538   if (!constraints_are_up_to_date() && !generators_are_up_to_date()) {
00539 #ifndef NDEBUG
00540     cerr << "Polyhedron not empty, not zero-dimensional"
00541          << endl
00542          << "and with neither constraints nor generators up-to-date!"
00543          << endl;
00544 #endif
00545     goto bomb;
00546   }
00547 
00548   // Here we check if the size of the matrices is consistent.
00549   // Let us suppose that all the matrices are up-to-date; this means:
00550   // `con_sys' : number of constraints x poly_num_columns
00551   // `gen_sys' : number of generators  x poly_num_columns
00552   // `sat_c'   : number of generators  x number of constraints
00553   // `sat_g'   : number of constraints x number of generators.
00554   if (constraints_are_up_to_date()) {
00555     if (con_sys.num_columns() != poly_num_columns) {
00556 #ifndef NDEBUG
00557       cerr << "Incompatible size! (con_sys and space_dim)"
00558            << endl;
00559 #endif
00560       goto bomb;
00561     }
00562     if (sat_c_is_up_to_date())
00563       if (con_sys.first_pending_row() != sat_c.num_columns()) {
00564 #ifndef NDEBUG
00565         cerr << "Incompatible size! (con_sys and sat_c)"
00566              << endl;
00567 #endif
00568         goto bomb;
00569       }
00570     if (sat_g_is_up_to_date())
00571       if (con_sys.first_pending_row() != sat_g.num_rows()) {
00572 #ifndef NDEBUG
00573         cerr << "Incompatible size! (con_sys and sat_g)"
00574              << endl;
00575 #endif
00576         goto bomb;
00577       }
00578     if (generators_are_up_to_date())
00579       if (con_sys.num_columns() != gen_sys.num_columns()) {
00580 #ifndef NDEBUG
00581         cerr << "Incompatible size! (con_sys and gen_sys)"
00582              << endl;
00583 #endif
00584         goto bomb;
00585       }
00586   }
00587 
00588   if (generators_are_up_to_date()) {
00589     if (gen_sys.num_columns() != poly_num_columns) {
00590 #ifndef NDEBUG
00591       cerr << "Incompatible size! (gen_sys and space_dim)"
00592            << endl;
00593 #endif
00594       goto bomb;
00595     }
00596     if (sat_c_is_up_to_date())
00597       if (gen_sys.first_pending_row() != sat_c.num_rows()) {
00598 #ifndef NDEBUG
00599         cerr << "Incompatible size! (gen_sys and sat_c)"
00600              << endl;
00601 #endif
00602         goto bomb;
00603       }
00604     if (sat_g_is_up_to_date())
00605       if (gen_sys.first_pending_row() != sat_g.num_columns()) {
00606 #ifndef NDEBUG
00607         cerr << "Incompatible size! (gen_sys and sat_g)"
00608              << endl;
00609 #endif
00610         goto bomb;
00611       }
00612 
00613     // Check if the system of generators is well-formed.
00614     if (!gen_sys.OK())
00615       goto bomb;
00616 
00617     if (gen_sys.first_pending_row() == 0) {
00618 #ifndef NDEBUG
00619       cerr << "Up-to-date generator system with all rows pending!"
00620            << endl;
00621 #endif
00622       goto bomb;
00623     }
00624 
00625     // A non-empty system of generators describing a polyhedron
00626     // is valid if and only if it contains a point.
00627     if (gen_sys.num_rows() > 0 && !gen_sys.has_points()) {
00628 #ifndef NDEBUG
00629       cerr << "Non-empty generator system declared up-to-date "
00630            << "has no points!"
00631            << endl;
00632 #endif
00633       goto bomb;
00634     }
00635 
00636 #if 0
00637     //=================================================
00638     // TODO: this test is wrong in the general case.
00639     // However, such an invariant does hold for a
00640     // strongly-minimized Generator_System.
00641     // We will activate this test as soon as the Status
00642     // flags will be able to remember if a system is
00643     // strongly minimized.
00644 
00645     // Checking that the number of closure points is always
00646     // greater than the number of points.
00647     if (!is_necessarily_closed()) {
00648       dimension_type num_points = 0;
00649       dimension_type num_closure_points = 0;
00650       dimension_type eps_index = gen_sys.num_columns() - 1;
00651       for (dimension_type i = gen_sys.num_rows(); i-- > 0; )
00652         if (!gen_sys[i].is_line_or_ray())
00653           if (gen_sys[i][eps_index] > 0)
00654             ++num_points;
00655           else
00656             ++num_closure_points;
00657       if (num_points > num_closure_points) {
00658 #ifndef NDEBUG
00659         cerr << "# POINTS > # CLOSURE_POINTS" << endl;
00660 #endif
00661         goto bomb;
00662       }
00663     }
00664     //=================================================
00665 #endif
00666 
00667     if (generators_are_minimized()) {
00668       // If the system of generators is minimized, the number of
00669       // lines, rays and points of the polyhedron must be the same as
00670       // of a temporary, minimized one. If this does not happen then
00671       // the polyhedron is not OK.
00672       Constraint_System new_con_sys(topology());
00673       Generator_System gs_without_pending = gen_sys;
00674       gs_without_pending.erase_to_end(gen_sys.first_pending_row());
00675       gs_without_pending.unset_pending_rows();
00676       Generator_System copy_of_gen_sys = gs_without_pending;
00677       Saturation_Matrix new_sat_c;
00678       minimize(false, copy_of_gen_sys, new_con_sys, new_sat_c);
00679       const dimension_type copy_num_lines = copy_of_gen_sys.num_lines();
00680       if (gs_without_pending.num_rows() != copy_of_gen_sys.num_rows()
00681           || gs_without_pending.num_lines() != copy_num_lines
00682           || gs_without_pending.num_rays() != copy_of_gen_sys.num_rays()) {
00683 #ifndef NDEBUG
00684         cerr << "Generators are declared minimized, but they are not!\n"
00685              << "Here is the minimized form of the generators:\n";
00686         copy_of_gen_sys.ascii_dump(cerr);
00687         cerr << endl;
00688 #endif
00689         goto bomb;
00690       }
00691 
00692       // CHECKME : the following observation is not formally true
00693       //           for a NNC_Polyhedron. But it may be true for its
00694       //           representation ...
00695 
00696       // If the corresponding polyhedral cone is _pointed_, then
00697       // a minimal system of generators is unique up to positive scaling.
00698       // We thus verify if the cone is pointed (i.e., there are no lines)
00699       // and, after normalizing and sorting a copy of the system `gen_sys'
00700       // of the polyhedron (we use a copy not to modify the polyhedron's
00701       // system) and the system `copy_of_gen_sys' that has been just
00702       // minimized, we check if the two matrices are identical.  If
00703       // they are different it means that the generators of the
00704       // polyhedron are declared minimized, but they are not.
00705       if (copy_num_lines == 0) {
00706         copy_of_gen_sys.strong_normalize();
00707         copy_of_gen_sys.sort_rows();
00708         gs_without_pending.strong_normalize();
00709         gs_without_pending.sort_rows();
00710         if (copy_of_gen_sys != gs_without_pending) {
00711 #ifndef NDEBUG
00712           cerr << "Generators are declared minimized, but they are not!\n"
00713                << "(we are in the case:\n"
00714                << "dimension of lineality space equal to 0)\n"
00715                << "Here is the minimized form of the generators:\n";
00716           copy_of_gen_sys.ascii_dump(cerr);
00717           cerr << endl;
00718 #endif
00719             goto bomb;
00720         }
00721       }
00722     }
00723   }
00724 
00725   if (constraints_are_up_to_date()) {
00726     // Check if the system of constraints is well-formed.
00727     if (!con_sys.OK())
00728       goto bomb;
00729 
00730     if (con_sys.first_pending_row() == 0) {
00731 #ifndef NDEBUG
00732       cerr << "Up-to-date constraint system with all rows pending!"
00733            << endl;
00734 #endif
00735       goto bomb;
00736     }
00737 
00738     // A non-empty system of constraints describing a polyhedron
00739     // must contain a constraint with a non-zero inhomogeneous term;
00740     // such a constraint corresponds to (a combination of other
00741     // constraints with):
00742     // -* the positivity constraint, for necessarily closed polyhedra;
00743     // -* the epsilon <= 1 constraint, for NNC polyhedra.
00744     bool no_positivity_constraint = true;
00745     for (dimension_type i = con_sys.num_rows(); i-- > 0; )
00746       if (con_sys[i].inhomogeneous_term() != 0) {
00747         no_positivity_constraint = false;
00748         break;
00749       }
00750     if (no_positivity_constraint) {
00751 #ifndef NDEBUG
00752       cerr << "Non-empty constraint system has no positivity constraint"
00753            << endl;
00754 #endif
00755       goto bomb;
00756     }
00757 
00758     if (!is_necessarily_closed()) {
00759       // A non-empty system of constraints describing a NNC polyhedron
00760       // must also contain a (combination of) the constraint epsilon >= 0,
00761       // i.e., a constraint with a positive epsilon coefficient.
00762       bool no_epsilon_geq_zero = true;
00763       const dimension_type eps_index = con_sys.num_columns() - 1;
00764       for (dimension_type i = con_sys.num_rows(); i-- > 0; )
00765         if (con_sys[i][eps_index] > 0) {
00766           no_epsilon_geq_zero = false;
00767           break;
00768         }
00769       if (no_epsilon_geq_zero) {
00770 #ifndef NDEBUG
00771         cerr << "Non-empty constraint system for NNC polyhedron "
00772              << "has no epsilon >= 0 constraint"
00773              << endl;
00774 #endif
00775         goto bomb;
00776       }
00777     }
00778 
00779     Constraint_System cs_without_pending = con_sys;
00780     cs_without_pending.erase_to_end(con_sys.first_pending_row());
00781     cs_without_pending.unset_pending_rows();
00782     Constraint_System copy_of_con_sys = cs_without_pending;
00783     Generator_System new_gen_sys(topology());
00784     Saturation_Matrix new_sat_g;
00785 
00786     if (minimize(true, copy_of_con_sys, new_gen_sys, new_sat_g)) {
00787       if (check_not_empty) {
00788         // Want to know the satisfiability of the constraints.
00789 #ifndef NDEBUG
00790         cerr << "Unsatisfiable system of constraints!"
00791              << endl;
00792 #endif
00793         goto bomb;
00794       }
00795       // The polyhedron is empty, there is nothing else to check.
00796       return true;
00797     }
00798 
00799     if (constraints_are_minimized()) {
00800       // If the constraints are minimized, the number of equalities
00801       // and of inequalities of the system of the polyhedron must be
00802       // the same of the temporary minimized one.
00803       // If it does not happen, the polyhedron is not OK.
00804       if (cs_without_pending.num_rows() != copy_of_con_sys.num_rows()
00805           || cs_without_pending.num_equalities()
00806           != copy_of_con_sys.num_equalities()) {
00807 #ifndef NDEBUG
00808         cerr << "Constraints are declared minimized, but they are not!\n"
00809              << "Here is the minimized form of the constraints:\n";
00810         copy_of_con_sys.ascii_dump(cerr);
00811         cerr << endl;
00812 #endif
00813         goto bomb;
00814       }
00815       // The system `copy_of_con_sys' has the form that is obtained
00816       // after applying methods gauss() and back_substitute().
00817       // A system of constraints can be minimal even if it does not
00818       // have this form. So, to verify if the polyhedron is correct,
00819       // we copy the system `con_sys' in a temporary one and then
00820       // modify it using method simplify() (which calls both gauss()
00821       // and back_substitute()).
00822       // If the temporary system and `copy_of_con_sys' are different,
00823       // the polyhedron is not OK.
00824       copy_of_con_sys.strong_normalize();
00825       copy_of_con_sys.sort_rows();
00826       cs_without_pending.simplify();
00827       cs_without_pending.strong_normalize();
00828       cs_without_pending.sort_rows();
00829       if (cs_without_pending != copy_of_con_sys) {
00830 #ifndef NDEBUG
00831         cerr << "Constraints are declared minimized, but they are not!\n"
00832              << "Here is the minimized form of the constraints:\n";
00833         copy_of_con_sys.ascii_dump(cerr);
00834         cerr << endl;
00835 #endif
00836         goto bomb;
00837       }
00838     }
00839   }
00840 
00841   if (sat_c_is_up_to_date())
00842     for (dimension_type i = sat_c.num_rows(); i-- > 0; ) {
00843       const Generator tmp_gen = gen_sys[i];
00844       const Saturation_Row tmp_sat = sat_c[i];
00845       for (dimension_type j = sat_c.num_columns(); j-- > 0; )
00846         if (Scalar_Products::sign(con_sys[j], tmp_gen) != tmp_sat[j]) {
00847 #ifndef NDEBUG
00848           cerr << "sat_c is declared up-to-date, but it is not!"
00849                << endl;
00850 #endif
00851           goto bomb;
00852         }
00853     }
00854 
00855   if (sat_g_is_up_to_date())
00856     for (dimension_type i = sat_g.num_rows(); i-- > 0; ) {
00857       const Constraint tmp_con = con_sys[i];
00858       const Saturation_Row tmp_sat = sat_g[i];
00859       for (dimension_type j = sat_g.num_columns(); j-- > 0; )
00860         if (Scalar_Products::sign(tmp_con, gen_sys[j]) != tmp_sat[j]) {
00861 #ifndef NDEBUG
00862           cerr << "sat_g is declared up-to-date, but it is not!"
00863                << endl;
00864 #endif
00865           goto bomb;
00866         }
00867     }
00868 
00869   if (has_pending_constraints()) {
00870     if (con_sys.num_pending_rows() == 0) {
00871 #ifndef NDEBUG
00872       cerr << "The polyhedron is declared to have pending constraints, "
00873            << "but con_sys has no pending rows!"
00874            << endl;
00875 #endif
00876       goto bomb;
00877     }
00878   }
00879 
00880   if (has_pending_generators()) {
00881     if (gen_sys.num_pending_rows() == 0) {
00882 #ifndef NDEBUG
00883       cerr << "The polyhedron is declared to have pending generators, "
00884            << "but gen_sys has no pending rows!"
00885            << endl;
00886 #endif
00887       goto bomb;
00888     }
00889   }
00890 
00891   return true;
00892 
00893  bomb:
00894 #ifndef NDEBUG
00895   cerr << "Here is the guilty polyhedron:"
00896        << endl;
00897   ascii_dump(cerr);
00898 #endif
00899   return false;
00900 }

void Parma_Polyhedra_Library::Polyhedron::add_constraint ( const Constraint c  ) 

Adds a copy of constraint c to the system of constraints of *this (without minimizing the result).

Exceptions:
std::invalid_argument Thrown if *this and constraint c are topology-incompatible or dimension-incompatible.

Definition at line 903 of file Polyhedron_public.cc.

References can_have_something_pending(), clear_constraints_minimized(), clear_generators_up_to_date(), con_sys, constraints_are_up_to_date(), has_pending_generators(), Parma_Polyhedra_Library::Constraint_System::insert(), Parma_Polyhedra_Library::Constraint_System::insert_pending(), Parma_Polyhedra_Library::Constraint::is_equality(), Parma_Polyhedra_Library::Linear_Row::is_necessarily_closed(), is_necessarily_closed(), Parma_Polyhedra_Library::Constraint::is_strict_inequality(), Parma_Polyhedra_Library::Constraint::is_tautological(), marked_empty(), OK(), process_pending_generators(), set_constraints_pending(), set_empty(), space_dim, Parma_Polyhedra_Library::Constraint::space_dimension(), throw_dimension_incompatible(), throw_topology_incompatible(), and update_constraints().

Referenced by add_congruence(), bounded_affine_image(), bounded_affine_preimage(), Parma_Polyhedra_Library::C_Polyhedron::C_Polyhedron(), generalized_affine_image(), generalized_affine_preimage(), poly_difference_assign(), and ppl_Polyhedron_add_constraint().

00903                                                  {
00904   // Topology-compatibility check.
00905   if (c.is_strict_inequality() && is_necessarily_closed())
00906     throw_topology_incompatible("add_constraint(c)", "c", c);
00907   // Dimension-compatibility check:
00908   // the dimension of `c' can not be greater than space_dim.
00909   if (space_dim < c.space_dimension())
00910     throw_dimension_incompatible("add_constraint(c)", "c", c);
00911 
00912   // Adding a new constraint to an empty polyhedron
00913   // results in an empty polyhedron.
00914   if (marked_empty())
00915     return;
00916 
00917   // Dealing with a zero-dimensional space polyhedron first.
00918   if (space_dim == 0) {
00919     if (!c.is_tautological())
00920       set_empty();
00921     return;
00922   }
00923 
00924   // The constraints (possibly with pending rows) are required.
00925   if (has_pending_generators())
00926     process_pending_generators();
00927   else if (!constraints_are_up_to_date())
00928     update_constraints();
00929 
00930   const bool adding_pending = can_have_something_pending();
00931 
00932   // Here we know that the system of constraints has at least a row.
00933   if (c.is_necessarily_closed() || !is_necessarily_closed())
00934     // Since `con_sys' is not empty, the topology and space dimension
00935     // of the inserted constraint are automatically adjusted.
00936     if (adding_pending)
00937       con_sys.insert_pending(c);
00938     else
00939       con_sys.insert(c);
00940   else {
00941     // Note: here we have a _legal_ topology mismatch, because
00942     // `c' is NOT a strict inequality.
00943     // However, by barely invoking `con_sys.insert(c)' we would
00944     // cause a change in the topology of `con_sys', which is wrong.
00945     // Thus, we insert a "topology corrected" copy of `c'.
00946     Linear_Expression nc_expr = Linear_Expression(c);
00947     if (c.is_equality())
00948       if (adding_pending)
00949         con_sys.insert_pending(nc_expr == 0);
00950       else
00951         con_sys.insert(nc_expr == 0);
00952     else
00953       if (adding_pending)
00954         con_sys.insert_pending(nc_expr >= 0);
00955       else
00956         con_sys.insert(nc_expr >= 0);
00957   }
00958 
00959   if (adding_pending)
00960     set_constraints_pending();
00961   else {
00962     // Constraints are not minimized and generators are not up-to-date.
00963     clear_constraints_minimized();
00964     clear_generators_up_to_date();
00965   }
00966   // Note: the constraint system may have become unsatisfiable, thus
00967   // we do not check for satisfiability.
00968   assert(OK());
00969 }

bool Parma_Polyhedra_Library::Polyhedron::add_constraint_and_minimize ( const Constraint c  ) 

Adds a copy of constraint c to the system of constraints of *this, minimizing the result.

Returns:
false if and only if the result is empty.
Exceptions:
std::invalid_argument Thrown if *this and constraint c are topology-incompatible or dimension-incompatible.

Definition at line 998 of file Polyhedron_public.cc.

References add_recycled_constraints_and_minimize().

Referenced by bounded_affine_image(), generalized_affine_image(), generalized_affine_preimage(), Parma_Polyhedra_Library::Polyhedra_Powerset< PH >::linear_partition_aux(), and ppl_Polyhedron_add_constraint_and_minimize().

00998                                                               {
00999   // TODO: this is just an executable specification.
01000   Constraint_System cs(c);
01001   return add_recycled_constraints_and_minimize(cs);
01002 }

void Parma_Polyhedra_Library::Polyhedron::add_generator ( const Generator g  ) 

Adds a copy of generator g to the system of generators of *this (without minimizing the result).

Exceptions:
std::invalid_argument Thrown if *this and generator g are topology-incompatible or dimension-incompatible, or if *this is an empty polyhedron and g is not a point.

Definition at line 1005 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::Generator_System::adjust_topology_and_space_dimension(), can_have_something_pending(), clear_constraints_up_to_date(), clear_empty(), clear_generators_minimized(), Parma_Polyhedra_Library::Generator::divisor(), gen_sys, generators_are_up_to_date(), has_pending_constraints(), Parma_Polyhedra_Library::Generator_System::insert(), Parma_Polyhedra_Library::Generator_System::insert_pending(), Parma_Polyhedra_Library::Generator::is_closure_point(), Parma_Polyhedra_Library::Linear_Row::is_necessarily_closed(), is_necessarily_closed(), Parma_Polyhedra_Library::Generator::is_point(), Parma_Polyhedra_Library::Generator::line(), Parma_Polyhedra_Library::Generator::LINE, marked_empty(), Parma_Polyhedra_Library::Row::normalize(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), Parma_Polyhedra_Library::Generator::point(), Parma_Polyhedra_Library::Generator::POINT, process_pending_constraints(), Parma_Polyhedra_Library::Generator::ray(), Parma_Polyhedra_Library::Generator::RAY, set_generators_minimized(), set_generators_pending(), Parma_Polyhedra_Library::Polyhedron::Status::set_zero_dim_univ(), space_dim, Parma_Polyhedra_Library::Generator::space_dimension(), status, throw_dimension_incompatible(), throw_invalid_generator(), throw_runtime_error(), throw_topology_incompatible(), topology(), Parma_Polyhedra_Library::Generator::type(), and update_generators().

Referenced by bounded_affine_preimage(), generalized_affine_image(), generalized_affine_preimage(), and ppl_Polyhedron_add_generator().

01005                                                {
01006   // Topology-compatibility check.
01007   if (g.is_closure_point() && is_necessarily_closed())
01008     throw_topology_incompatible("add_generator(g)", "g", g);
01009   // Dimension-compatibility check:
01010   // the dimension of `g' can not be greater than space_dim.
01011   const dimension_type g_space_dim = g.space_dimension();
01012   if (space_dim < g_space_dim)
01013     throw_dimension_incompatible("add_generator(g)", "g", g);
01014 
01015   // Dealing with a zero-dimensional space polyhedron first.
01016   if (space_dim == 0) {
01017     // It is not possible to create 0-dim rays or lines.
01018     assert(g.is_point() || g.is_closure_point());
01019     // Closure points can only be inserted in non-empty polyhedra.
01020     if (marked_empty())
01021       if (g.type() != Generator::POINT)
01022         throw_invalid_generator("add_generator(g)", "g");
01023       else
01024         status.set_zero_dim_univ();
01025     assert(OK());
01026     return;
01027   }
01028 
01029   if (marked_empty()
01030       || (has_pending_constraints() && !process_pending_constraints())
01031       || (!generators_are_up_to_date() && !update_generators())) {
01032     // Here the polyhedron is empty:
01033     // the specification says we can only insert a point.
01034     if (!g.is_point())
01035       throw_invalid_generator("add_generator(g)", "g");
01036     if (g.is_necessarily_closed() || !is_necessarily_closed()) {
01037       gen_sys.insert(g);
01038       // Since `gen_sys' was empty, after inserting `g' we have to resize
01039       // the system of generators to have the right dimension.
01040       gen_sys.adjust_topology_and_space_dimension(topology(), space_dim);
01041       if (!is_necessarily_closed()) {
01042         // In the NNC topology, each point has to be matched by
01043         // a corresponding closure point:
01044         // turn the just inserted point into the corresponding
01045         // (normalized) closure point.
01046         Generator& cp = gen_sys[gen_sys.num_rows() - 1];
01047         cp[space_dim + 1] = 0;
01048         cp.normalize();
01049         // Re-insert the point (which is already normalized).
01050         gen_sys.insert(g);
01051       }
01052     }
01053     else {
01054       // Note: here we have a _legal_ topology mismatch,
01055       // because `g' is NOT a closure point (it is a point!)
01056       // However, by barely invoking `gen_sys.insert(g)' we would
01057       // cause a change in the topology of `gen_sys', which is wrong.
01058       // Thus, we insert a "topology corrected" copy of `g'.
01059       const Linear_Expression nc_expr = Linear_Expression(g);
01060       gen_sys.insert(Generator::point(nc_expr, g.divisor()));
01061       // Since `gen_sys' was empty, after inserting `g' we have to resize
01062       // the system of generators to have the right dimension.
01063       gen_sys.adjust_topology_and_space_dimension(topology(), space_dim);
01064     }
01065     // No longer empty, generators up-to-date and minimized.
01066     clear_empty();
01067     set_generators_minimized();
01068   }
01069   else {
01070     assert(generators_are_up_to_date());
01071     const bool has_pending = can_have_something_pending();
01072     if (g.is_necessarily_closed() || !is_necessarily_closed()) {
01073       // Since `gen_sys' is not empty, the topology and space dimension
01074       // of the inserted generator are automatically adjusted.
01075       if (has_pending)
01076         gen_sys.insert_pending(g);
01077       else
01078         gen_sys.insert(g);
01079       if (!is_necessarily_closed() && g.is_point()) {
01080         // In the NNC topology, each point has to be matched by
01081         // a corresponding closure point:
01082         // turn the just inserted point into the corresponding
01083         // (normalized) closure point.
01084         Generator& cp = gen_sys[gen_sys.num_rows() - 1];
01085         cp[space_dim + 1] = 0;
01086         cp.normalize();
01087         // Re-insert the point (which is already normalized).
01088         if (has_pending)
01089           gen_sys.insert_pending(g);
01090         else
01091           gen_sys.insert(g);
01092       }
01093     }
01094     else {
01095       assert(!g.is_closure_point());
01096       // Note: here we have a _legal_ topology mismatch, because
01097       // `g' is NOT a closure point.
01098       // However, by barely invoking `gen_sys.insert(g)' we would
01099       // cause a change in the topology of `gen_sys', which is wrong.
01100       // Thus, we insert a "topology corrected" copy of `g'.
01101       const Linear_Expression nc_expr = Linear_Expression(g);
01102       switch (g.type()) {
01103       case Generator::LINE:
01104         if (has_pending)
01105           gen_sys.insert_pending(Generator::line(nc_expr));
01106         else
01107           gen_sys.insert(Generator::line(nc_expr));
01108         break;
01109       case Generator::RAY:
01110         if (has_pending)
01111           gen_sys.insert_pending(Generator::ray(nc_expr));
01112         else
01113           gen_sys.insert(Generator::ray(nc_expr));
01114         break;
01115       case Generator::POINT:
01116         if (has_pending)
01117           gen_sys.insert_pending(Generator::point(nc_expr, g.divisor()));
01118         else
01119           gen_sys.insert(Generator::point(nc_expr, g.divisor()));
01120         break;
01121       default:
01122         throw_runtime_error("add_generator(const Generator& g)");
01123       }
01124     }
01125 
01126     if (has_pending)
01127       set_generators_pending();
01128     else {
01129       // After adding the new generator,
01130       // constraints are no longer up-to-date.
01131       clear_generators_minimized();
01132       clear_constraints_up_to_date();
01133     }
01134   }
01135   assert(OK());
01136 }

bool Parma_Polyhedra_Library::Polyhedron::add_generator_and_minimize ( const Generator g  ) 

Adds a copy of generator g to the system of generators of *this, minimizing the result.

Returns:
false if and only if the result is empty.
Exceptions:
std::invalid_argument Thrown if *this and generator g are topology-incompatible or dimension-incompatible, or if *this is an empty polyhedron and g is not a point.

Definition at line 1139 of file Polyhedron_public.cc.

References add_recycled_generators_and_minimize().

Referenced by generalized_affine_image(), and ppl_Polyhedron_add_generator_and_minimize().

01139                                                             {
01140   // TODO: this is just an executable specification.
01141   Generator_System gs(g);
01142   return add_recycled_generators_and_minimize(gs);
01143 }

void Parma_Polyhedra_Library::Polyhedron::add_congruence ( const Congruence cg  ) 

Adds a copy of congruence cg to the system of congruences of this (without minimizing the result).

Exceptions:
std::invalid_argument Thrown if *this and congruence cg are topology-incompatible or dimension-incompatible.

Definition at line 972 of file Polyhedron_public.cc.

References add_constraint(), Parma_Polyhedra_Library::Constraint::EQUALITY, Parma_Polyhedra_Library::Congruence::is_equality(), Parma_Polyhedra_Library::Congruence::is_trivial_true(), marked_empty(), Parma_Polyhedra_Library::NECESSARILY_CLOSED, set_empty(), space_dim, Parma_Polyhedra_Library::Congruence::space_dimension(), and throw_dimension_incompatible().

00972                                                   {
00973   // Dimension-compatibility check:
00974   // the dimension of `cg' can not be greater than space_dim.
00975   if (space_dim < cg.space_dimension())
00976     throw_dimension_incompatible("add_congruence(cg)", "cg", cg);
00977 
00978   // Adding a new congruence to an empty polyhedron results in an
00979   // empty polyhedron.
00980   if (marked_empty())
00981     return;
00982 
00983   // Dealing with a zero-dimensional space polyhedron first.
00984   if (space_dim == 0) {
00985     if (!cg.is_trivial_true())
00986       set_empty();
00987     return;
00988   }
00989 
00990   if (cg.is_equality()) {
00991     Linear_Expression le(cg);
00992     Constraint c(le, Constraint::EQUALITY, NECESSARILY_CLOSED);
00993     add_constraint(c);
00994   }
00995 }

void Parma_Polyhedra_Library::Polyhedron::add_constraints ( const Constraint_System cs  ) 

Adds a copy of the constraints in cs to the system of constraints of *this (without minimizing the result).

Parameters:
cs Contains the constraints that will be added to the system of constraints of *this.
Exceptions:
std::invalid_argument Thrown if *this and cs are topology-incompatible or dimension-incompatible.

Definition at line 1226 of file Polyhedron_public.cc.

References add_recycled_constraints().

Referenced by bounded_BHRZ03_extrapolation_assign(), bounded_H79_extrapolation_assign(), expand_space_dimension(), limited_BHRZ03_extrapolation_assign(), limited_H79_extrapolation_assign(), Parma_Polyhedra_Library::NNC_Polyhedron::NNC_Polyhedron(), and ppl_Polyhedron_add_constraints().

01226                                                           {
01227   // TODO: this is just an executable specification.
01228   Constraint_System cs_copy = cs;
01229   add_recycled_constraints(cs_copy);
01230 }

void Parma_Polyhedra_Library::Polyhedron::add_recycled_constraints ( Constraint_System cs  ) 

Adds the constraints in cs to the system of constraints of *this (without minimizing the result).

Parameters:
cs The constraint system that will be recycled, adding its constraints to the system of constraints of *this.
Exceptions:
std::invalid_argument Thrown if *this and cs are topology-incompatible or dimension-incompatible.
Warning:
The only assumption that can be made on cs upon successful or exceptional return is that it can be safely destroyed.

Definition at line 1146 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::Matrix::add_zero_rows(), Parma_Polyhedra_Library::Constraint_System::adjust_topology_and_space_dimension(), Parma_Polyhedra_Library::Constraint_System::begin(), can_have_something_pending(), clear_constraints_minimized(), clear_generators_up_to_date(), con_sys, constraints_are_up_to_date(), Parma_Polyhedra_Library::Constraint_System::end(), has_pending_generators(), Parma_Polyhedra_Library::Constraint_System::has_strict_inequalities(), Parma_Polyhedra_Library::Constraint::is_equality(), is_necessarily_closed(), marked_empty(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), process_pending_generators(), Parma_Polyhedra_Library::Linear_Row::RAY_OR_POINT_OR_INEQUALITY, set_constraints_pending(), Parma_Polyhedra_Library::Polyhedron::Status::set_empty(), Parma_Polyhedra_Library::Constraint::set_is_equality(), Parma_Polyhedra_Library::Linear_System::set_sorted(), space_dim, Parma_Polyhedra_Library::Constraint_System::space_dimension(), status, throw_dimension_incompatible(), throw_topology_incompatible(), topology(), Parma_Polyhedra_Library::Linear_System::unset_pending_rows(), and update_constraints().

Referenced by add_congruences(), add_constraints(), H79_widening_assign(), and ppl_Polyhedron_add_recycled_constraints().

01146                                                              {
01147   // Topology compatibility check.
01148   if (is_necessarily_closed() && cs.has_strict_inequalities())
01149     throw_topology_incompatible("add_constraints(cs)", "cs", cs);
01150   // Dimension-compatibility check:
01151   // the dimension of `cs' can not be greater than space_dim.
01152   const dimension_type cs_space_dim = cs.space_dimension();
01153   if (space_dim < cs_space_dim)
01154     throw_dimension_incompatible("add_recycled_constraints(cs)", "cs", cs);
01155 
01156   // Adding no constraints is a no-op.
01157   if (cs.num_rows() == 0)
01158     return;
01159 
01160   if (space_dim == 0) {
01161     // In a 0-dimensional space the constraints are
01162     // tautologies (e.g., 0 == 0 or 1 >= 0 or 1 > 0) or
01163     // inconsistent (e.g., 1 == 0 or -1 >= 0 or 0 > 0).
01164     // In a system of constraints `begin()' and `end()' are equal
01165     // if and only if the system only contains tautologies.
01166     if (cs.begin() != cs.end())
01167       // There is a constraint, it must be inconsistent,
01168       // the polyhedron is empty.
01169       status.set_empty();
01170     return;
01171   }
01172 
01173   if (marked_empty())
01174     return;
01175 
01176   // The constraints (possibly with pending rows) are required.
01177   if (has_pending_generators())
01178     process_pending_generators();
01179   else if (!constraints_are_up_to_date())
01180     update_constraints();
01181 
01182   // Adjust `cs' to the right topology and space dimension.
01183   // NOTE: we already checked for topology compatibility.
01184   cs.adjust_topology_and_space_dimension(topology(), space_dim);
01185 
01186   const bool adding_pending = can_have_something_pending();
01187 
01188   // Here we do not require `con_sys' to be sorted.
01189   // also, we _swap_ (instead of copying) the coefficients of `cs'
01190   // (which is not a const).
01191   const dimension_type old_num_rows = con_sys.num_rows();
01192   const dimension_type cs_num_rows = cs.num_rows();
01193   const dimension_type cs_num_columns = cs.num_columns();
01194   con_sys.add_zero_rows(cs_num_rows,
01195                         Linear_Row::Flags(topology(),
01196                                           Linear_Row::RAY_OR_POINT_OR_INEQUALITY));
01197   for (dimension_type i = cs_num_rows; i-- > 0; ) {
01198     // NOTE: we cannot directly swap the rows, since they might have
01199     // different capacities (besides possibly having different sizes):
01200     // thus, we steal one coefficient at a time.
01201     Constraint& new_c = con_sys[old_num_rows + i];
01202     Constraint& old_c = cs[i];
01203     if (old_c.is_equality())
01204       new_c.set_is_equality();
01205     for (dimension_type j = cs_num_columns; j-- > 0; )
01206       std::swap(new_c[j], old_c[j]);
01207   }
01208 
01209   if (adding_pending)
01210     set_constraints_pending();
01211   else {
01212     // The newly added ones are not pending constraints.
01213     con_sys.unset_pending_rows();
01214     // They have been simply appended.
01215     con_sys.set_sorted(false);
01216     // Constraints are not minimized and generators are not up-to-date.
01217     clear_constraints_minimized();
01218     clear_generators_up_to_date();
01219   }
01220   // Note: the constraint system may have become unsatisfiable, thus
01221   // we do not check for satisfiability.
01222   assert(OK());
01223 }

bool Parma_Polyhedra_Library::Polyhedron::add_constraints_and_minimize ( const Constraint_System cs  ) 

Adds a copy of the constraints in cs to the system of constraints of *this, minimizing the result.

Returns:
false if and only if the result is empty.
Parameters:
cs Contains the constraints that will be added to the system of constraints of *this.
Exceptions:
std::invalid_argument Thrown if *this and cs are topology-incompatible or dimension-incompatible.

Definition at line 1299 of file Polyhedron_public.cc.

References add_recycled_constraints_and_minimize().

Referenced by ppl_Polyhedron_add_constraints_and_minimize().

01299                                                                        {
01300   // TODO: this is just an executable specification.
01301   Constraint_System cs_copy = cs;
01302   return add_recycled_constraints_and_minimize(cs_copy);
01303 }

bool Parma_Polyhedra_Library::Polyhedron::add_recycled_constraints_and_minimize ( Constraint_System cs  ) 

Adds the constraints in cs to the system of constraints of *this, minimizing the result.

Returns:
false if and only if the result is empty.
Parameters:
cs The constraint system that will be recycled, adding its constraints to the system of constraints of *this.
Exceptions:
std::invalid_argument Thrown if *this and cs are topology-incompatible or dimension-incompatible.
Warning:
The only assumption that can be made on cs upon successful or exceptional return is that it can be safely destroyed.

Definition at line 1233 of file Polyhedron_public.cc.

References add_and_minimize(), Parma_Polyhedra_Library::Constraint_System::adjust_topology_and_space_dimension(), Parma_Polyhedra_Library::Constraint_System::begin(), clear_sat_g_up_to_date(), con_sys, empty, Parma_Polyhedra_Library::Constraint_System::end(), gen_sys, Parma_Polyhedra_Library::Constraint_System::has_strict_inequalities(), is_necessarily_closed(), Parma_Polyhedra_Library::Linear_System::is_sorted(), minimize(), Parma_Polyhedra_Library::Linear_System::num_pending_rows(), Parma_Polyhedra_Library::Matrix::num_rows(), obtain_sorted_constraints_with_sat_c(), OK(), sat_c, set_empty(), Parma_Polyhedra_Library::Polyhedron::Status::set_empty(), set_sat_c_up_to_date(), Parma_Polyhedra_Library::Linear_System::sort_rows(), space_dim, Parma_Polyhedra_Library::Constraint_System::space_dimension(), status, throw_dimension_incompatible(), throw_topology_incompatible(), topology(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

Referenced by add_constraint_and_minimize(), add_constraints_and_minimize(), BHRZ03_combining_constraints(), and ppl_Polyhedron_add_recycled_constraints_and_minimize().

01233                                                                           {
01234   // Topology-compatibility check.
01235   if (is_necessarily_closed() && cs.has_strict_inequalities())
01236     throw_topology_incompatible("add_recycled_constraints_and_minimize(cs)",
01237                                 "cs", cs);
01238   // Dimension-compatibility check:
01239   // the dimension of `cs' can not be greater than space_dim.
01240   const dimension_type cs_space_dim = cs.space_dimension();
01241   if (space_dim < cs_space_dim)
01242     throw_dimension_incompatible("add_recycled_constraints_and_minimize(cs)",
01243                                  "cs", cs);
01244 
01245   // Adding no constraints: just minimize.
01246   if (cs.num_rows() == 0)
01247     return minimize();
01248 
01249   // Dealing with zero-dimensional space polyhedra first.
01250   if (space_dim == 0) {
01251     // In a 0-dimensional space the constraints are
01252     // tautologies (e.g., 0 == 0 or 1 >= 0 or 1 > 0) or
01253     // inconsistent (e.g., 1 == 0 or -1 >= 0 or 0 > 0).
01254     // In a system of constraints `begin()' and `end()' are equal
01255     // if and only if the system only contains tautologies.
01256     if (cs.begin() == cs.end())
01257       return true;
01258     // There is a constraint, it must be inconsistent,
01259     // the polyhedron is empty.
01260     status.set_empty();
01261     return false;
01262   }
01263 
01264   // The polyhedron must be minimized and have sorted constraints.
01265   // `minimize()' will process any pending constraints or generators.
01266   if (!minimize())
01267     // We have just discovered that `x' is empty.
01268     return false;
01269   // Fully sort the system of constraints for `x'.
01270   obtain_sorted_constraints_with_sat_c();
01271 
01272   // Fully sort the system of constraints to be added
01273   // (before adjusting dimensions in order to save time).
01274   if (cs.num_pending_rows() > 0) {
01275     cs.unset_pending_rows();
01276     cs.sort_rows();
01277   }
01278   else if (!cs.is_sorted())
01279     cs.sort_rows();
01280   // Adjust `cs' to the right topology and space dimension.
01281   // NOTE: we already checked for topology compatibility.
01282   cs.adjust_topology_and_space_dimension(topology(), space_dim);
01283 
01284   const bool empty = add_and_minimize(true, con_sys, gen_sys, sat_c, cs);
01285 
01286   if (empty)
01287     set_empty();
01288   else {
01289     // `sat_c' is up-to-date, while `sat_g' is no longer up-to-date.
01290     set_sat_c_up_to_date();
01291     clear_sat_g_up_to_date();
01292   }
01293   assert(OK());
01294 
01295   return !empty;
01296 }

void Parma_Polyhedra_Library::Polyhedron::add_generators ( const Generator_System gs  ) 

Adds a copy of the generators in gs to the system of generators of *this (without minimizing the result).

Parameters:
gs Contains the generators that will be added to the system of generators of *this.
Exceptions:
std::invalid_argument Thrown if *this and gs are topology-incompatible or dimension-incompatible, or if *this is empty and the system of generators gs is not empty, but has no points.

Definition at line 1399 of file Polyhedron_public.cc.

References add_recycled_generators().

Referenced by ppl_Polyhedron_add_generators().

01399                                                         {
01400   // TODO: this is just an executable specification.
01401   Generator_System gs_copy = gs;
01402   add_recycled_generators(gs_copy);
01403 }

void Parma_Polyhedra_Library::Polyhedron::add_recycled_generators ( Generator_System gs  ) 

Adds the generators in gs to the system of generators of *this (without minimizing the result).

Parameters:
gs The generator system that will be recycled, adding its generators to the system of generators of *this.
Exceptions:
std::invalid_argument Thrown if *this and gs are topology-incompatible or dimension-incompatible, or if *this is empty and the system of generators gs is not empty, but has no points.
Warning:
The only assumption that can be made on gs upon successful or exceptional return is that it can be safely destroyed.

Definition at line 1306 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::Generator_System::add_corresponding_closure_points(), Parma_Polyhedra_Library::Matrix::add_zero_rows(), Parma_Polyhedra_Library::Generator_System::adjust_topology_and_space_dimension(), can_have_something_pending(), clear_constraints_up_to_date(), clear_empty(), clear_generators_minimized(), gen_sys, generators_are_up_to_date(), Parma_Polyhedra_Library::Generator_System::has_closure_points(), has_pending_constraints(), Parma_Polyhedra_Library::Generator_System::has_points(), Parma_Polyhedra_Library::Generator::is_line(), is_necessarily_closed(), marked_empty(), minimize(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Linear_System::num_pending_rows(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), process_pending_constraints(), Parma_Polyhedra_Library::Linear_Row::RAY_OR_POINT_OR_INEQUALITY, set_generators_pending(), set_generators_up_to_date(), Parma_Polyhedra_Library::Generator::set_is_line(), Parma_Polyhedra_Library::Linear_System::set_sorted(), Parma_Polyhedra_Library::Polyhedron::Status::set_zero_dim_univ(), space_dim, Parma_Polyhedra_Library::Generator_System::space_dimension(), status, throw_dimension_incompatible(), throw_invalid_generators(), throw_topology_incompatible(), topology(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

Referenced by add_generators(), generalized_affine_preimage(), and ppl_Polyhedron_add_recycled_generators().

01306                                                            {
01307   // Topology compatibility check.
01308   if (is_necessarily_closed() && gs.has_closure_points())
01309     throw_topology_incompatible("add_recycled_generators(gs)", "gs", gs);
01310   // Dimension-compatibility check:
01311   // the dimension of `gs' can not be greater than space_dim.
01312   const dimension_type gs_space_dim = gs.space_dimension();
01313   if (space_dim < gs_space_dim)
01314     throw_dimension_incompatible("add_recycled_generators(gs)", "gs", gs);
01315 
01316   // Adding no generators is a no-op.
01317   if (gs.num_rows() == 0)
01318     return;
01319 
01320   // Adding valid generators to a zero-dimensional polyhedron
01321   // transform it in the zero-dimensional universe polyhedron.
01322   if (space_dim == 0) {
01323     if (marked_empty() && !gs.has_points())
01324       throw_invalid_generators("add_recycled_generators(gs)", "gs");
01325     status.set_zero_dim_univ();
01326     assert(OK(true));
01327     return;
01328   }
01329 
01330   // Adjust `gs' to the right topology and dimensions.
01331   // NOTE: we already checked for topology compatibility.
01332   gs.adjust_topology_and_space_dimension(topology(), space_dim);
01333   // For NNC polyhedra, each point must be matched by
01334   // the corresponding closure point.
01335   if (!is_necessarily_closed())
01336     gs.add_corresponding_closure_points();
01337 
01338   // The generators (possibly with pending rows) are required.
01339   if ((has_pending_constraints() && !process_pending_constraints())
01340       || (!generators_are_up_to_date() && !minimize())) {
01341     // We have just discovered that `*this' is empty.
01342     // So `gs' must contain at least one point.
01343     if (!gs.has_points())
01344       throw_invalid_generators("add_recycled_generators(gs)", "gs");
01345     // The polyhedron is no longer empty and generators are up-to-date.
01346     std::swap(gen_sys, gs);
01347     if (gen_sys.num_pending_rows() > 0) {
01348       // Even though `gs' has pending generators, since the constraints
01349       // of the polyhedron are not up-to-date, the polyhedron cannot
01350       // have pending generators. By integrating the pending part
01351       // of `gen_sys' we may loose sortedness.
01352       gen_sys.unset_pending_rows();
01353       gen_sys.set_sorted(false);
01354     }
01355     set_generators_up_to_date();
01356     clear_empty();
01357     assert(OK());
01358     return;
01359   }
01360 
01361   const bool adding_pending = can_have_something_pending();
01362 
01363   // Here we do not require `gen_sys' to be sorted.
01364   // also, we _swap_ (instead of copying) the coefficients of `gs'
01365   // (which is not a const).
01366   const dimension_type old_num_rows = gen_sys.num_rows();
01367   const dimension_type gs_num_rows = gs.num_rows();
01368   const dimension_type gs_num_columns = gs.num_columns();
01369   gen_sys.add_zero_rows(gs_num_rows,
01370                         Linear_Row::Flags(topology(),
01371                                           Linear_Row::RAY_OR_POINT_OR_INEQUALITY));
01372   for (dimension_type i = gs_num_rows; i-- > 0; ) {
01373     // NOTE: we cannot directly swap the rows, since they might have
01374     // different capacities (besides possibly having different sizes):
01375     // thus, we steal one coefficient at a time.
01376     Generator& new_g = gen_sys[old_num_rows + i];
01377     Generator& old_g = gs[i];
01378     if (old_g.is_line())
01379       new_g.set_is_line();
01380     for (dimension_type j = gs_num_columns; j-- > 0; )
01381       std::swap(new_g[j], old_g[j]);
01382   }
01383 
01384   if (adding_pending)
01385     set_generators_pending();
01386   else {
01387     // The newly added ones are not pending generators.
01388     gen_sys.unset_pending_rows();
01389     // They have been simply appended.
01390     gen_sys.set_sorted(false);
01391     // Constraints are not up-to-date and generators are not minimized.
01392     clear_constraints_up_to_date();
01393     clear_generators_minimized();
01394   }
01395   assert(OK(true));
01396 }

bool Parma_Polyhedra_Library::Polyhedron::add_generators_and_minimize ( const Generator_System gs  ) 

Adds a copy of the generators in gs to the system of generators of *this, minimizing the result.

Returns:
false if and only if the result is empty.
Parameters:
gs Contains the generators that will be added to the system of generators of *this.
Exceptions:
std::invalid_argument Thrown if *this and gs are topology-incompatible or dimension-incompatible, or if *this is empty and the the system of generators gs is not empty, but has no points.

Definition at line 1480 of file Polyhedron_public.cc.

References add_recycled_generators_and_minimize().

Referenced by ppl_Polyhedron_add_generators_and_minimize().

01480                                                                      {
01481   // TODO: this is just an executable specification.
01482   Generator_System gs_copy = gs;
01483   return add_recycled_generators_and_minimize(gs_copy);
01484 }

bool Parma_Polyhedra_Library::Polyhedron::add_recycled_generators_and_minimize ( Generator_System gs  ) 

Adds the generators in gs to the system of generators of *this, minimizing the result.

Returns:
false if and only if the result is empty.
Parameters:
gs The generator system that will be recycled, adding its generators to the system of generators of *this.
Exceptions:
std::invalid_argument Thrown if *this and gs are topology-incompatible or dimension-incompatible, or if *this is empty and the the system of generators gs is not empty, but has no points.
Warning:
The only assumption that can be made on gs upon successful or exceptional return is that it can be safely destroyed.

Definition at line 1406 of file Polyhedron_public.cc.

References add_and_minimize(), Parma_Polyhedra_Library::Generator_System::add_corresponding_closure_points(), Parma_Polyhedra_Library::Generator_System::adjust_topology_and_space_dimension(), clear_empty(), clear_sat_c_up_to_date(), con_sys, gen_sys, Parma_Polyhedra_Library::Generator_System::has_closure_points(), Parma_Polyhedra_Library::Generator_System::has_points(), is_necessarily_closed(), Parma_Polyhedra_Library::Linear_System::is_sorted(), marked_empty(), minimize(), Parma_Polyhedra_Library::Linear_System::num_pending_rows(), Parma_Polyhedra_Library::Matrix::num_rows(), obtain_sorted_generators_with_sat_g(), OK(), sat_g, set_generators_up_to_date(), Parma_Polyhedra_Library::Polyhedron::Status::set_zero_dim_univ(), Parma_Polyhedra_Library::Linear_System::sort_rows(), space_dim, Parma_Polyhedra_Library::Generator_System::space_dimension(), status, throw_dimension_incompatible(), throw_invalid_generators(), throw_topology_incompatible(), topology(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

Referenced by add_generator_and_minimize(), add_generators_and_minimize(), BHRZ03_evolving_points(), BHRZ03_evolving_rays(), generalized_affine_image(), generalized_affine_preimage(), and ppl_Polyhedron_add_recycled_generators_and_minimize().

01406                                                                         {
01407   // Topology compatibility check.
01408   if (is_necessarily_closed() && gs.has_closure_points())
01409     throw_topology_incompatible("add_recycled_generators_and_minimize(gs)",
01410                                 "gs", gs);
01411   // Dimension-compatibility check:
01412   // the dimension of `gs' can not be greater than space_dim.
01413   const dimension_type gs_space_dim = gs.space_dimension();
01414   if (space_dim < gs_space_dim)
01415     throw_dimension_incompatible("add_recycled_generators_and_minimize(gs)",
01416                                  "gs", gs);
01417 
01418   // Adding no generators is equivalent to just requiring minimization.
01419   if (gs.num_rows() == 0)
01420     return minimize();
01421 
01422   // Adding valid generators to a zero-dimensional polyhedron
01423   // transform it in the zero-dimensional universe polyhedron.
01424   if (space_dim == 0) {
01425     if (marked_empty() && !gs.has_points())
01426       throw_invalid_generators("add_recycled_generators_and_minimize(gs)",
01427                                "gs");
01428     status.set_zero_dim_univ();
01429     assert(OK(true));
01430     return true;
01431   }
01432 
01433   // Adjust `gs' to the right topology.
01434   // NOTE: we already checked for topology compatibility;
01435   // also, we do NOT adjust dimensions now, so that we will
01436   // spend less time to sort rows.
01437   gs.adjust_topology_and_space_dimension(topology(), gs_space_dim);
01438 
01439   // For NNC polyhedra, each point must be matched by
01440   // the corresponding closure point.
01441   if (!is_necessarily_closed())
01442     gs.add_corresponding_closure_points();
01443 
01444   // `gs' has to be fully sorted, thus it cannot have pending rows.
01445   if (gs.num_pending_rows() > 0) {
01446     gs.unset_pending_rows();
01447     gs.sort_rows();
01448   }
01449   else if (!gs.is_sorted())
01450     gs.sort_rows();
01451 
01452   // Now adjusting dimensions (topology already adjusted).
01453   // NOTE: sortedness is preserved.
01454   gs.adjust_topology_and_space_dimension(topology(), space_dim);
01455 
01456   if (minimize()) {
01457     obtain_sorted_generators_with_sat_g();
01458     // This call to `add_and_minimize(...)' cannot return `false'.
01459     add_and_minimize(false, gen_sys, con_sys, sat_g, gs);
01460     clear_sat_c_up_to_date();
01461   }
01462   else {
01463     // The polyhedron was empty: check if `gs' contains a point.
01464     if (!gs.has_points())
01465       throw_invalid_generators("add_recycled_generators_and_minimize(gs)",
01466                                "gs");
01467     // `gs' has a point: the polyhedron is no longer empty
01468     // and generators are up-to-date.
01469     std::swap(gen_sys, gs);
01470     clear_empty();
01471     set_generators_up_to_date();
01472     // This call to `minimize()' cannot return `false'.
01473     minimize();
01474   }
01475   assert(OK(true));
01476   return true;
01477 }

void Parma_Polyhedra_Library::Polyhedron::add_congruences ( const Congruence_System cgs  ) 

Adds to *this constraints equivalent to the congruences in cgs (without minimizing the result).

Parameters:
cgs Contains the congruences that will be added to the system of constraints of *this.
Exceptions:
std::invalid_argument Thrown if *this and cgs are topology-incompatible or dimension-incompatible.

Definition at line 1487 of file Polyhedron_public.cc.

References add_recycled_constraints(), Parma_Polyhedra_Library::Congruence_System::begin(), Parma_Polyhedra_Library::Congruence_System::end(), Parma_Polyhedra_Library::Constraint::EQUALITY, Parma_Polyhedra_Library::Constraint_System::insert(), Parma_Polyhedra_Library::NECESSARILY_CLOSED, space_dim, Parma_Polyhedra_Library::Congruence_System::space_dimension(), and throw_dimension_incompatible().

Referenced by Parma_Polyhedra_Library::C_Polyhedron::C_Polyhedron(), and Parma_Polyhedra_Library::NNC_Polyhedron::NNC_Polyhedron().

01487                                                            {
01488   // Dimension-compatibility check:
01489   // the dimension of `cgs' can not be greater than space_dim.
01490   if (space_dim < cgs.space_dimension())
01491     throw_dimension_incompatible("add_congruences(cgs)", "cgs", cgs);
01492 
01493   Constraint_System cs;
01494   bool inserted = false;
01495   for (Congruence_System::const_iterator i = cgs.begin(),
01496          cgs_end = cgs.end(); i != cgs_end; ++i)
01497     if (i->is_equality()) {
01498       Linear_Expression le(*i);
01499       Constraint c(le, Constraint::EQUALITY, NECESSARILY_CLOSED);
01500       // FIXME: Steal the row in c when adding it to cs.
01501       cs.insert(c);
01502       inserted = true;
01503     }
01504   // Only add cgs if congruences were inserted into cgs, as the
01505   // dimension of cs must be at most that of the polyhedron.
01506   if (inserted)
01507     add_recycled_constraints(cs);
01508 }

void Parma_Polyhedra_Library::Polyhedron::intersection_assign ( const Polyhedron y  ) 

Assigns to *this the intersection of *this and y. The result is not guaranteed to be minimized.

Exceptions:
std::invalid_argument Thrown if *this and y are topology-incompatible or dimension-incompatible.

Definition at line 1511 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::Linear_System::add_pending_rows(), Parma_Polyhedra_Library::Linear_System::add_rows(), can_have_something_pending(), clear_constraints_minimized(), clear_generators_up_to_date(), con_sys, constraints_are_up_to_date(), has_pending_constraints(), has_pending_generators(), Parma_Polyhedra_Library::Linear_System::is_sorted(), marked_empty(), Parma_Polyhedra_Library::Linear_System::merge_rows_assign(), OK(), process_pending_generators(), set_constraints_pending(), set_empty(), space_dim, throw_dimension_incompatible(), throw_topology_incompatible(), topology(), and update_constraints().

Referenced by ppl_Polyhedron_intersection_assign().

01511                                                       {
01512   Polyhedron& x = *this;
01513   // Topology compatibility check.
01514   if (x.topology() != y.topology())
01515     throw_topology_incompatible("intersection_assign(y)", "y", y);
01516   // Dimension-compatibility check.
01517   if (x.space_dim != y.space_dim)
01518     throw_dimension_incompatible("intersection_assign(y)", "y", y);
01519 
01520   // If one of the two polyhedra is empty, the intersection is empty.
01521   if (x.marked_empty())
01522     return;
01523   if (y.marked_empty()) {
01524     x.set_empty();
01525     return;
01526   }
01527 
01528   // If both polyhedra are zero-dimensional,
01529   // then at this point they are necessarily non-empty,
01530   // so that their intersection is non-empty too.
01531   if (x.space_dim == 0)
01532     return;
01533 
01534   // Both systems of constraints have to be up-to-date,
01535   // possibly having pending constraints.
01536   if (x.has_pending_generators())
01537     x.process_pending_generators();
01538   else if (!x.constraints_are_up_to_date())
01539     x.update_constraints();
01540 
01541   if (y.has_pending_generators())
01542     y.process_pending_generators();
01543   else if (!y.constraints_are_up_to_date())
01544     y.update_constraints();
01545 
01546   // Here both systems are up-to-date and possibly have pending constraints
01547   // (but they cannot have pending generators).
01548   assert(!x.has_pending_generators() && x.constraints_are_up_to_date());
01549   assert(!y.has_pending_generators() && y.constraints_are_up_to_date());
01550 
01551   // If `x' can support pending constraints,
01552   // the constraints of `y' are added as pending constraints of `x'.
01553   if (x.can_have_something_pending()) {
01554     x.con_sys.add_pending_rows(y.con_sys);
01555     x.set_constraints_pending();
01556   }
01557   else {
01558     // `x' cannot support pending constraints.
01559     // If both constraint systems are (fully) sorted, then we can
01560     // merge them; otherwise we simply add the second to the first.
01561     if (x.con_sys.is_sorted()
01562         && y.con_sys.is_sorted() && !y.has_pending_constraints())
01563       x.con_sys.merge_rows_assign(y.con_sys);
01564     else
01565       x.con_sys.add_rows(y.con_sys);
01566     // Generators are no longer up-to-date and constraints are no
01567     // longer minimized.
01568     x.clear_generators_up_to_date();
01569     x.clear_constraints_minimized();
01570   }
01571   assert(x.OK() && y.OK());
01572 }

bool Parma_Polyhedra_Library::Polyhedron::intersection_assign_and_minimize ( const Polyhedron y  ) 

Assigns to *this the intersection of *this and y, minimizing the result.

Returns:
false if and only if the result is empty.
Exceptions:
std::invalid_argument Thrown if *this and y are topology-incompatible or dimension-incompatible.

Definition at line 1575 of file Polyhedron_public.cc.

References add_and_minimize(), Parma_Polyhedra_Library::Linear_System::add_pending_rows(), clear_pending_constraints(), clear_sat_g_up_to_date(), con_sys, constraints_are_up_to_date(), empty, gen_sys, has_pending_generators(), marked_empty(), minimize(), Parma_Polyhedra_Library::Linear_System::num_pending_rows(), obtain_sorted_constraints(), obtain_sorted_constraints_with_sat_c(), OK(), process_pending_generators(), sat_c, set_empty(), set_sat_c_up_to_date(), Parma_Polyhedra_Library::Linear_System::sort_pending_and_remove_duplicates(), space_dim, throw_dimension_incompatible(), throw_topology_incompatible(), topology(), and update_constraints().

Referenced by BHRZ03_evolving_points(), BHRZ03_evolving_rays(), BHRZ03_widening_assign(), H79_widening_assign(), is_disjoint_from(), and ppl_Polyhedron_intersection_assign_and_minimize().

01575                                                                    {
01576   Polyhedron& x = *this;
01577   // Topology compatibility check.
01578   if (x.topology() != y.topology())
01579     throw_topology_incompatible("intersection_assign_and_minimize(y)",
01580                                 "y", y);
01581   // Dimension-compatibility check.
01582   if (x.space_dim != y.space_dim)
01583     throw_dimension_incompatible("intersection_assign_and_minimize(y)",
01584                                  "y", y);
01585 
01586   // If one of the two polyhedra is empty, the intersection is empty.
01587   if (x.marked_empty())
01588     return false;
01589   if (y.marked_empty()) {
01590     x.set_empty();
01591     return false;
01592   }
01593 
01594   // If both polyhedra are zero-dimensional,
01595   // then at this point they are necessarily non-empty,
01596   // so that their intersection is non-empty too.
01597   if (x.space_dim == 0)
01598     return true;
01599 
01600   // `x' must be minimized and have sorted constraints.
01601   // `minimize()' will process any pending constraints or generators.
01602   if (!x.minimize())
01603     // We have just discovered that `x' is empty.
01604     return false;
01605   x.obtain_sorted_constraints_with_sat_c();
01606 
01607   // `y' must have updated, possibly pending constraints.
01608   if (y.has_pending_generators())
01609     y.process_pending_generators();
01610   else if (!y.constraints_are_up_to_date())
01611     y.update_constraints();
01612 
01613   bool empty;
01614   if (y.con_sys.num_pending_rows() > 0) {
01615     // Integrate `y.con_sys' as pending constraints of `x',
01616     // sort them in place and then call `add_and_minimize()'.
01617     x.con_sys.add_pending_rows(y.con_sys);
01618     x.con_sys.sort_pending_and_remove_duplicates();
01619     if (x.con_sys.num_pending_rows() == 0) {
01620       // All pending constraints were duplicates.
01621       x.clear_pending_constraints();
01622       assert(OK(true));
01623       return true;
01624     }
01625     empty = add_and_minimize(true, x.con_sys, x.gen_sys, x.sat_c);
01626   }
01627   else {
01628     y.obtain_sorted_constraints();
01629     empty = add_and_minimize(true, x.con_sys, x.gen_sys, x.sat_c, y.con_sys);
01630   }
01631 
01632   if (empty)
01633     x.set_empty();
01634   else {
01635     // On exit of the function `intersection_assign_and_minimize()'
01636     // the polyhedron is up-to-date and `sat_c' is meaningful.
01637     x.set_sat_c_up_to_date();
01638     x.clear_sat_g_up_to_date();
01639   }
01640   assert(x.OK(!empty));
01641   return !empty;
01642 }

void Parma_Polyhedra_Library::Polyhedron::poly_hull_assign ( const Polyhedron y  ) 

Assigns to *this the poly-hull of *this and y. The result is not guaranteed to be minimized.

Exceptions:
std::invalid_argument Thrown if *this and y are topology-incompatible or dimension-incompatible.

Definition at line 1645 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::Linear_System::add_pending_rows(), Parma_Polyhedra_Library::Linear_System::add_rows(), can_have_something_pending(), clear_constraints_up_to_date(), clear_generators_minimized(), gen_sys, generators_are_up_to_date(), has_pending_constraints(), has_pending_generators(), Parma_Polyhedra_Library::Linear_System::is_sorted(), marked_empty(), Parma_Polyhedra_Library::Linear_System::merge_rows_assign(), OK(), process_pending_constraints(), set_generators_pending(), space_dim, throw_dimension_incompatible(), throw_topology_incompatible(), topology(), and update_generators().

Referenced by fold_space_dimensions(), poly_difference_assign(), ppl_Polyhedron_poly_hull_assign(), and upper_bound_assign().

01645                                                    {
01646   Polyhedron& x = *this;
01647   // Topology compatibility check.
01648   if (x.topology() != y.topology())
01649     throw_topology_incompatible("poly_hull_assign(y)", "y", y);
01650   // Dimension-compatibility check.
01651   if (x.space_dim != y.space_dim)
01652     throw_dimension_incompatible("poly_hull_assign(y)", "y", y);
01653 
01654   // The poly-hull of a polyhedron `p' with an empty polyhedron is `p'.
01655   if (y.marked_empty())
01656     return;
01657   if (x.marked_empty()) {
01658     x = y;
01659     return;
01660   }
01661 
01662   // If both polyhedra are zero-dimensional,
01663   // then at this point they are necessarily universe polyhedra,
01664   // so that their poly-hull is the universe polyhedron too.
01665   if (x.space_dim == 0)
01666     return;
01667 
01668   // Both systems of generators have to be up-to-date,
01669   // possibly having pending generators.
01670   if ((x.has_pending_constraints() && !x.process_pending_constraints())
01671       || (!x.generators_are_up_to_date() && !x.update_generators())) {
01672     // Discovered `x' empty when updating generators.
01673     x = y;
01674     return;
01675   }
01676   if ((y.has_pending_constraints() && !y.process_pending_constraints())
01677       || (!y.generators_are_up_to_date() && !y.update_generators()))
01678     // Discovered `y' empty when updating generators.
01679     return;
01680 
01681   // Here both systems are up-to-date and possibly have pending generators
01682   // (but they cannot have pending constraints).
01683   assert(!x.has_pending_constraints() && x.generators_are_up_to_date());
01684   assert(!y.has_pending_constraints() && y.generators_are_up_to_date());
01685 
01686   // If `x' can support pending generators,
01687   // the generators of `y' are added as pending generators of `x'.
01688   if (x.can_have_something_pending()) {
01689     x.gen_sys.add_pending_rows(y.gen_sys);
01690     x.set_generators_pending();
01691   }
01692   else {
01693     // `x' cannot support pending generators.
01694     // If both generator systems are (fully) sorted, then we can merge
01695     // them; otherwise we simply add the second to the first.
01696     if (x.gen_sys.is_sorted()
01697         && y.gen_sys.is_sorted() && !y.has_pending_generators())
01698       x.gen_sys.merge_rows_assign(y.gen_sys);
01699     else
01700       x.gen_sys.add_rows(y.gen_sys);
01701     // Constraints are no longer up-to-date
01702     // and generators are no longer minimized.
01703     x.clear_constraints_up_to_date();
01704     x.clear_generators_minimized();
01705   }
01706   // At this point both `x' and `y' are not empty.
01707   assert(x.OK(true) && y.OK(true));
01708 }

bool Parma_Polyhedra_Library::Polyhedron::poly_hull_assign_and_minimize ( const Polyhedron y  ) 

Assigns to *this the poly-hull of *this and y, minimizing the result.

Returns:
false if and only if the result is empty.
Exceptions:
std::invalid_argument Thrown if *this and y are topology-incompatible or dimension-incompatible.

Definition at line 1711 of file Polyhedron_public.cc.

References add_and_minimize(), Parma_Polyhedra_Library::Linear_System::add_pending_rows(), clear_pending_generators(), clear_sat_c_up_to_date(), con_sys, gen_sys, generators_are_up_to_date(), has_pending_constraints(), marked_empty(), minimize(), Parma_Polyhedra_Library::Linear_System::num_pending_rows(), obtain_sorted_generators(), obtain_sorted_generators_with_sat_g(), OK(), process_pending_constraints(), sat_g, Parma_Polyhedra_Library::Linear_System::sort_pending_and_remove_duplicates(), space_dim, throw_dimension_incompatible(), throw_topology_incompatible(), topology(), and update_generators().

Referenced by ppl_Polyhedron_poly_hull_assign_and_minimize().

01711                                                                 {
01712   Polyhedron& x = *this;
01713   // Topology compatibility check.
01714   if (x.topology() != y.topology())
01715     throw_topology_incompatible("poly_hull_assign_and_minimize(y)", "y", y);
01716   // Dimension-compatibility check.
01717   if (x.space_dim != y.space_dim)
01718     throw_dimension_incompatible("poly_hull_assign_and_minimize(y)", "y", y);
01719 
01720   // The poly-hull of a polyhedron `p' with an empty polyhedron is `p'.
01721   if (y.marked_empty())
01722     return minimize();
01723   if (x.marked_empty()) {
01724     x = y;
01725     return minimize();
01726   }
01727 
01728   // If both polyhedra are zero-dimensional,
01729   // then at this point they are necessarily universe polyhedra,
01730   // so that their poly-hull is the universe polyhedron too.
01731   if (x.space_dim == 0)
01732     return true;
01733 
01734   // `x' must have minimized constraints and generators.
01735   // `minimize()' will process any pending constraints or generators.
01736   if (!x.minimize()) {
01737     // We have just discovered that `x' is empty.
01738     x = y;
01739     return minimize();
01740   }
01741   // x must have `sat_g' up-to-date and sorted generators.
01742   x.obtain_sorted_generators_with_sat_g();
01743 
01744   // `y' must have updated, possibly pending generators.
01745   if ((y.has_pending_constraints() && !y.process_pending_constraints())
01746       || (!y.generators_are_up_to_date() && !y.update_generators()))
01747     // We have just discovered that `y' is empty
01748     // (and we know that `x' is not empty).
01749     return true;
01750 
01751   if (y.gen_sys.num_pending_rows() > 0) {
01752     // Integrate `y.gen_sys' as pending generators of `x',
01753     // sort them in place and then call `add_and_minimize()'.
01754     x.gen_sys.add_pending_rows(y.gen_sys);
01755     x.gen_sys.sort_pending_and_remove_duplicates();
01756     if (x.gen_sys.num_pending_rows() == 0) {
01757       // All pending generators were duplicates.
01758       x.clear_pending_generators();
01759       assert(OK(true) && y.OK());
01760       return true;
01761     }
01762     add_and_minimize(false, x.gen_sys, x.con_sys, x.sat_g);
01763   }
01764   else {
01765     y.obtain_sorted_generators();
01766     add_and_minimize(false, x.gen_sys, x.con_sys, x.sat_g, y.gen_sys);
01767   }
01768   x.clear_sat_c_up_to_date();
01769 
01770   assert(x.OK(true) && y.OK());
01771   return true;
01772 }

void Parma_Polyhedra_Library::Polyhedron::upper_bound_assign ( const Polyhedron y  )  [inline]

Same as poly_hull_assign(y).

Definition at line 71 of file Polyhedron.inlines.hh.

References poly_hull_assign().

00071                                                   {
00072   poly_hull_assign(y);
00073 }

void Parma_Polyhedra_Library::Polyhedron::poly_difference_assign ( const Polyhedron y  ) 

Assigns to *this the poly-difference of *this and y. The result is not guaranteed to be minimized.

Exceptions:
std::invalid_argument Thrown if *this and y are topology-incompatible or dimension-incompatible.

Definition at line 1775 of file Polyhedron_public.cc.

References add_constraint(), Parma_Polyhedra_Library::Constraint_System::begin(), constraints(), contains(), Parma_Polyhedra_Library::EMPTY, Parma_Polyhedra_Library::Constraint_System::end(), Parma_Polyhedra_Library::Constraint::EQUALITY, Parma_Polyhedra_Library::Poly_Con_Relation::implies(), Parma_Polyhedra_Library::Poly_Con_Relation::is_included(), Parma_Polyhedra_Library::Constraint::is_inconsistent(), is_necessarily_closed(), Parma_Polyhedra_Library::Constraint::is_tautological(), marked_empty(), minimize(), Parma_Polyhedra_Library::Constraint::NONSTRICT_INEQUALITY, OK(), poly_hull_assign(), relation_with(), set_empty(), space_dim, Parma_Polyhedra_Library::Constraint::STRICT_INEQUALITY, throw_dimension_incompatible(), throw_topology_incompatible(), topology(), and Parma_Polyhedra_Library::Constraint::type().

Referenced by difference_assign(), and ppl_Polyhedron_poly_difference_assign().

01775                                                          {
01776   Polyhedron& x = *this;
01777   // Topology compatibility check.
01778   if (x.topology() != y.topology())
01779     throw_topology_incompatible("poly_difference_assign(y)", "y", y);
01780   // Dimension-compatibility check.
01781   if (x.space_dim != y.space_dim)
01782     throw_dimension_incompatible("poly_difference_assign(y)", "y", y);
01783 
01784   // The difference of a polyhedron `p' and an empty polyhedron is `p'.
01785   if (y.marked_empty())
01786     return;
01787   // The difference of an empty polyhedron and of a polyhedron `p' is empty.
01788   if (x.marked_empty())
01789     return;
01790 
01791   // If both polyhedra are zero-dimensional,
01792   // then at this point they are necessarily universe polyhedra,
01793   // so that their difference is empty.
01794   if (x.space_dim == 0) {
01795     x.set_empty();
01796     return;
01797   }
01798 
01799   // TODO: This is just an executable specification.
01800   //       Have to find a more efficient method.
01801 
01802   if (y.contains(x)) {
01803     x.set_empty();
01804     return;
01805   }
01806 
01807   Polyhedron new_polyhedron(topology(), x.space_dim, EMPTY);
01808 
01809   // Being lazy here is only harmful.
01810   // `minimize()' will process any pending constraints or generators.
01811   x.minimize();
01812   y.minimize();
01813 
01814   const Constraint_System& y_cs = y.constraints();
01815   for (Constraint_System::const_iterator i = y_cs.begin(),
01816          y_cs_end = y_cs.end(); i != y_cs_end; ++i) {
01817     const Constraint& c = *i;
01818     assert(!c.is_tautological());
01819     assert(!c.is_inconsistent());
01820     // If the polyhedron `x' is included in the polyhedron defined by
01821     // `c', then `c' can be skipped, as adding its complement to `x'
01822     // would result in the empty polyhedron.  Moreover, if we operate
01823     // on C-polyhedra and `c' is a non-strict inequality, c _must_ be
01824     // skipped for otherwise we would obtain a result that is less
01825     // precise than the poly-difference.
01826     if (x.relation_with(c).implies(Poly_Con_Relation::is_included()))
01827       continue;
01828     Polyhedron z = x;
01829     const Linear_Expression e = Linear_Expression(c);
01830     switch (c.type()) {
01831     case Constraint::NONSTRICT_INEQUALITY:
01832       if (is_necessarily_closed())
01833         z.add_constraint(e <= 0);
01834       else
01835         z.add_constraint(e < 0);
01836       break;
01837     case Constraint::STRICT_INEQUALITY:
01838       z.add_constraint(e <= 0);
01839       break;
01840     case Constraint::EQUALITY:
01841       if (is_necessarily_closed())
01842         // We have already filtered out the case
01843         // when `x' is included in `y': the result is `x'.
01844         return;
01845       else {
01846         Polyhedron w = x;
01847         w.add_constraint(e < 0);
01848         new_polyhedron.poly_hull_assign(w);
01849         z.add_constraint(e > 0);
01850       }
01851       break;
01852     }
01853     new_polyhedron.poly_hull_assign(z);
01854   }
01855   *this = new_polyhedron;
01856 
01857   assert(OK());
01858 }

void Parma_Polyhedra_Library::Polyhedron::difference_assign ( const Polyhedron y  )  [inline]

Same as poly_difference_assign(y).

Definition at line 76 of file Polyhedron.inlines.hh.

References poly_difference_assign().

00076                                                  {
00077   poly_difference_assign(y);
00078 }

void Parma_Polyhedra_Library::Polyhedron::affine_image ( Variable  var,
const Linear_Expression expr,
Coefficient_traits::const_reference  denominator = Coefficient_one() 
)

Assigns to *this the affine image of *this under the function mapping variable var to the affine expression specified by expr and denominator.

Parameters:
var The variable to which the affine expression is assigned;
expr The numerator of the affine expression;
denominator The denominator of the affine expression (optional argument with default value 1.)
Exceptions:
std::invalid_argument Thrown if denominator is zero or if expr and *this are dimension-incompatible or if var is not a space dimension of *this.
When considering the generators of a polyhedron, the affine transformation

\[ \frac{\sum_{i=0}^{n-1} a_i x_i + b}{\mathrm{denominator}} \]

is assigned to var where expr is $\sum_{i=0}^{n-1} a_i x_i + b$ ($b$ is the inhomogeneous term).

If constraints are up-to-date, it uses the specialized function affine_preimage() (for the system of constraints) and inverse transformation to reach the same result. To obtain the inverse transformation we use the following observation.

Observation:

  1. The affine transformation is invertible if the coefficient of var in this transformation (i.e., $a_\mathrm{var}$) is different from zero.
  2. If the transformation is invertible, then we can write

    \[ \mathrm{denominator} * {x'}_\mathrm{var} = \sum_{i = 0}^{n - 1} a_i x_i + b = a_\mathrm{var} x_\mathrm{var} + \sum_{i \neq var} a_i x_i + b, \]

    so that the inverse transformation is

    \[ a_\mathrm{var} x_\mathrm{var} = \mathrm{denominator} * {x'}_\mathrm{var} - \sum_{i \neq j} a_i x_i - b. \]

Then, if the transformation is invertible, all the entities that were up-to-date remain up-to-date. Otherwise only generators remain up-to-date.

In other words, if $R$ is a $m_1 \times n$ matrix representing the rays of the polyhedron, $V$ is a $m_2 \times n$ matrix representing the points of the polyhedron and

\[ P = \bigl\{\, \vect{x} = (x_0, \ldots, x_{n-1})^\mathrm{T} \bigm| \vect{x} = \vect{\lambda} R + \vect{\mu} V, \vect{\lambda} \in \Rset^{m_1}_+, \vect{\mu} \in \Rset^{m_2}_+, \sum_{i = 0}^{m_2 - 1} \mu_i = 1 \,\bigr\} \]

and $T$ is the affine transformation to apply to $P$, then the resulting polyhedron is

\[ P' = \bigl\{\, (x_0, \ldots, T(x_0, \ldots, x_{n-1}), \ldots, x_{n-1})^\mathrm{T} \bigm| (x_0, \ldots, x_{n-1})^\mathrm{T} \in P \,\bigr\}. \]

Affine transformations are, for example:

  • translations
  • rotations
  • symmetries.

Definition at line 1862 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::Generator_System::affine_image(), Parma_Polyhedra_Library::Constraint_System::affine_preimage(), clear_constraints_up_to_date(), clear_generators_minimized(), clear_sat_c_up_to_date(), clear_sat_g_up_to_date(), Parma_Polyhedra_Library::Linear_Expression::coefficient(), con_sys, constraints_are_up_to_date(), gen_sys, generators_are_up_to_date(), has_something_pending(), marked_empty(), minimize(), Parma_Polyhedra_Library::neg_assign(), OK(), remove_pending_to_obtain_generators(), space_dim, Parma_Polyhedra_Library::Variable::space_dimension(), Parma_Polyhedra_Library::Linear_Expression::space_dimension(), throw_dimension_incompatible(), and throw_invalid_argument().

Referenced by fold_space_dimensions(), generalized_affine_image(), and ppl_Polyhedron_affine_image().

01864                                                             {
01865   // The denominator cannot be zero.
01866   if (denominator == 0)
01867     throw_invalid_argument("affine_image(v, e, d)", "d == 0");
01868 
01869   // Dimension-compatibility checks.
01870   // The dimension of `expr' should not be greater than the dimension
01871   // of `*this'.
01872   if (space_dim < expr.space_dimension())
01873     throw_dimension_incompatible("affine_image(v, e, d)", "e", expr);
01874   // `var' should be one of the dimensions of the polyhedron.
01875   const dimension_type var_space_dim = var.space_dimension();
01876   if (space_dim < var_space_dim)
01877     throw_dimension_incompatible("affine_image(v, e, d)", "v", var);
01878 
01879   if (marked_empty())
01880     return;
01881 
01882   if (expr.coefficient(var) != 0) {
01883     // The transformation is invertible:
01884     // minimality and saturators are preserved, so that
01885     // pending rows, if present, are correctly handled.
01886     if (generators_are_up_to_date()) {
01887       // Generator_System::affine_image() requires the third argument
01888       // to be a positive Coefficient.
01889       if (denominator > 0)
01890         gen_sys.affine_image(var_space_dim, expr, denominator);
01891       else
01892         gen_sys.affine_image(var_space_dim, -expr, -denominator);
01893     }
01894     if (constraints_are_up_to_date()) {
01895       // To build the inverse transformation,
01896       // after copying and negating `expr',
01897       // we exchange the roles of `expr[var_space_dim]' and `denominator'.
01898       Linear_Expression inverse;
01899       if (expr[var_space_dim] > 0) {
01900         inverse = -expr;
01901         inverse[var_space_dim] = denominator;
01902         con_sys.affine_preimage(var_space_dim, inverse, expr[var_space_dim]);
01903       }
01904       else {
01905         // The new denominator is negative: we negate everything once
01906         // more, as Constraint_System::affine_preimage() requires the
01907         // third argument to be positive.
01908         inverse = expr;
01909         inverse[var_space_dim] = denominator;
01910         neg_assign(inverse[var_space_dim]);
01911         con_sys.affine_preimage(var_space_dim, inverse, -expr[var_space_dim]);
01912       }
01913     }
01914   }
01915   else {
01916     // The transformation is not invertible.
01917     // We need an up-to-date system of generators.
01918     if (has_something_pending())
01919       remove_pending_to_obtain_generators();
01920     else if (!generators_are_up_to_date())
01921       minimize();
01922     if (!marked_empty()) {
01923       // Generator_System::affine_image() requires the third argument
01924       // to be a positive Coefficient.
01925       if (denominator > 0)
01926         gen_sys.affine_image(var_space_dim, expr, denominator);
01927       else
01928         gen_sys.affine_image(var_space_dim, -expr, -denominator);
01929 
01930       clear_constraints_up_to_date();
01931       clear_generators_minimized();
01932       clear_sat_c_up_to_date();
01933       clear_sat_g_up_to_date();
01934     }
01935   }
01936   assert(OK());
01937 }

void Parma_Polyhedra_Library::Polyhedron::affine_preimage ( Variable  var,
const Linear_Expression expr,
Coefficient_traits::const_reference  denominator = Coefficient_one() 
)

Assigns to *this the affine preimage of *this under the function mapping variable var to the affine expression specified by expr and denominator.

Parameters:
var The variable to which the affine expression is substituted;
expr The numerator of the affine expression;
denominator The denominator of the affine expression (optional argument with default value 1.)
Exceptions:
std::invalid_argument Thrown if denominator is zero or if expr and *this are dimension-incompatible or if var is not a space dimension of *this.
When considering constraints of a polyhedron, the affine transformation

\[ \frac{\sum_{i=0}^{n-1} a_i x_i + b}{denominator}, \]

is assigned to var where expr is $\sum_{i=0}^{n-1} a_i x_i + b$ ($b$ is the inhomogeneous term).

If generators are up-to-date, then the specialized function affine_image() is used (for the system of generators) and inverse transformation to reach the same result. To obtain the inverse transformation, we use the following observation.

Observation:

  1. The affine transformation is invertible if the coefficient of var in this transformation (i.e. $a_\mathrm{var}$) is different from zero.
  2. If the transformation is invertible, then we can write

    \[ \mathrm{denominator} * {x'}_\mathrm{var} = \sum_{i = 0}^{n - 1} a_i x_i + b = a_\mathrm{var} x_\mathrm{var} + \sum_{i \neq \mathrm{var}} a_i x_i + b, \]

    , the inverse transformation is

    \[ a_\mathrm{var} x_\mathrm{var} = \mathrm{denominator} * {x'}_\mathrm{var} - \sum_{i \neq j} a_i x_i - b. \]

    .

Then, if the transformation is invertible, all the entities that were up-to-date remain up-to-date. Otherwise only constraints remain up-to-date.

In other words, if $A$ is a $m \times n$ matrix representing the constraints of the polyhedron, $T$ is the affine transformation to apply to $P$ and

\[ P = \bigl\{\, \vect{x} = (x_0, \ldots, x_{n-1})^\mathrm{T} \bigm| A\vect{x} \geq \vect{0} \,\bigr\}. \]

The resulting polyhedron is

\[ P' = \bigl\{\, \vect{x} = (x_0, \ldots, x_{n-1}))^\mathrm{T} \bigm| A'\vect{x} \geq \vect{0} \,\bigr\}, \]

where $A'$ is defined as follows:

\[ {a'}_{ij} = \begin{cases} a_{ij} * \mathrm{denominator} + a_{i\mathrm{var}}*\mathrm{expr}[j] \quad \mathrm{for } j \neq \mathrm{var}; \\ \mathrm{expr}[\mathrm{var}] * a_{i\mathrm{var}}, \quad \text{for } j = \mathrm{var}. \end{cases} \]

Definition at line 1942 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::Generator_System::affine_image(), Parma_Polyhedra_Library::Constraint_System::affine_preimage(), clear_constraints_minimized(), clear_generators_up_to_date(), clear_sat_c_up_to_date(), clear_sat_g_up_to_date(), Parma_Polyhedra_Library::Linear_Expression::coefficient(), con_sys, constraints_are_up_to_date(), gen_sys, generators_are_up_to_date(), has_something_pending(), marked_empty(), minimize(), Parma_Polyhedra_Library::neg_assign(), OK(), remove_pending_to_obtain_constraints(), space_dim, Parma_Polyhedra_Library::Variable::space_dimension(), Parma_Polyhedra_Library::Linear_Expression::space_dimension(), throw_dimension_incompatible(), and throw_invalid_argument().

Referenced by generalized_affine_preimage(), and ppl_Polyhedron_affine_preimage().

01944                                                                {
01945   // The denominator cannot be zero.
01946   if (denominator == 0)
01947     throw_invalid_argument("affine_preimage(v, e, d)", "d == 0");
01948 
01949   // Dimension-compatibility checks.
01950   // The dimension of `expr' should not be greater than the dimension
01951   // of `*this'.
01952   if (space_dim < expr.space_dimension())
01953     throw_dimension_incompatible("affine_preimage(v, e, d)", "e", expr);
01954   // `var' should be one of the dimensions of the polyhedron.
01955   const dimension_type var_space_dim = var.space_dimension();
01956   if (space_dim < var_space_dim)
01957     throw_dimension_incompatible("affine_preimage(v, e, d)", "v", var);
01958 
01959   if (marked_empty())
01960     return;
01961 
01962   if (expr.coefficient(var) != 0) {
01963     // The transformation is invertible:
01964     // minimality and saturators are preserved.
01965     if (constraints_are_up_to_date()) {
01966       // Constraint_System::affine_preimage() requires the third argument
01967       // to be a positive Coefficient.
01968       if (denominator > 0)
01969         con_sys.affine_preimage(var_space_dim, expr, denominator);
01970       else
01971         con_sys.affine_preimage(var_space_dim, -expr, -denominator);
01972     }
01973     if (generators_are_up_to_date()) {
01974       // To build the inverse transformation,
01975       // after copying and negating `expr',
01976       // we exchange the roles of `expr[var_space_dim]' and `denominator'.
01977       Linear_Expression inverse;
01978       if (expr[var_space_dim] > 0) {
01979         inverse = -expr;
01980         inverse[var_space_dim] = denominator;
01981         gen_sys.affine_image(var_space_dim, inverse, expr[var_space_dim]);
01982       }
01983       else {
01984         // The new denominator is negative:
01985         // we negate everything once more, as Generator_System::affine_image()
01986         // requires the third argument to be positive.
01987         inverse = expr;
01988         inverse[var_space_dim] = denominator;
01989         neg_assign(inverse[var_space_dim]);
01990         gen_sys.affine_image(var_space_dim, inverse, -expr[var_space_dim]);
01991       }
01992     }
01993   }
01994   else {
01995     // The transformation is not invertible.
01996     // We need an up-to-date system of constraints.
01997     if (has_something_pending())
01998       remove_pending_to_obtain_constraints();
01999     else if (!constraints_are_up_to_date())
02000       minimize();
02001     // Constraint_System::affine_preimage() requires the third argument
02002     // to be a positive Coefficient.
02003     if (denominator > 0)
02004       con_sys.affine_preimage(var_space_dim, expr, denominator);
02005     else
02006       con_sys.affine_preimage(var_space_dim, -expr, -denominator);
02007     // Generators, minimality and saturators are no longer valid.
02008     clear_generators_up_to_date();
02009     clear_constraints_minimized();
02010     clear_sat_c_up_to_date();
02011     clear_sat_g_up_to_date();
02012   }
02013   assert(OK());
02014 }

void Parma_Polyhedra_Library::Polyhedron::generalized_affine_image ( Variable  var,
const Relation_Symbol  relsym,
const Linear_Expression expr,
Coefficient_traits::const_reference  denominator = Coefficient_one() 
)

Assigns to *this the image of *this with respect to the generalized affine relation $\mathrm{var}' \relsym \frac{\mathrm{expr}}{\mathrm{denominator}}$, where $\mathord{\relsym}$ is the relation symbol encoded by relsym.

Parameters:
var The left hand side variable of the generalized affine relation;
relsym The relation symbol;
expr The numerator of the right hand side affine expression;
denominator The denominator of the right hand side affine expression (optional argument with default value 1.)
Exceptions:
std::invalid_argument Thrown if denominator is zero or if expr and *this are dimension-incompatible or if var is not a space dimension of *this or if *this is a C_Polyhedron and relsym is a strict relation symbol.

Definition at line 2174 of file Polyhedron_public.cc.

References add_generator(), add_generator_and_minimize(), Parma_Polyhedra_Library::Linear_System::add_row(), affine_image(), clear_constraints_up_to_date(), clear_generators_minimized(), clear_sat_c_up_to_date(), clear_sat_g_up_to_date(), Parma_Polyhedra_Library::EQUAL, gen_sys, Parma_Polyhedra_Library::GREATER_THAN, Parma_Polyhedra_Library::GREATER_THAN_OR_EQUAL, is_empty(), is_necessarily_closed(), Parma_Polyhedra_Library::LESS_THAN, Parma_Polyhedra_Library::LESS_THAN_OR_EQUAL, Parma_Polyhedra_Library::Matrix::num_rows(), OK(), Parma_Polyhedra_Library::Linear_System::set_sorted(), space_dim, Parma_Polyhedra_Library::Variable::space_dimension(), Parma_Polyhedra_Library::Linear_Expression::space_dimension(), throw_dimension_incompatible(), and throw_invalid_argument().

Referenced by bounded_affine_image(), generalized_affine_preimage(), ppl_Polyhedron_generalized_affine_image(), and ppl_Polyhedron_generalized_affine_image_lhs_rhs().

02177                                                                         {
02178   // The denominator cannot be zero.
02179   if (denominator == 0)
02180     throw_invalid_argument("generalized_affine_image(v, r, e, d)", "d == 0");
02181 
02182   // Dimension-compatibility checks.
02183   // The dimension of `expr' should not be greater than the dimension
02184   // of `*this'.
02185   if (space_dim < expr.space_dimension())
02186     throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
02187                                  "e", expr);
02188   // `var' should be one of the dimensions of the polyhedron.
02189   const dimension_type var_space_dim = var.space_dimension();
02190   if (space_dim < var_space_dim)
02191     throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
02192                                  "v", var);
02193 
02194   // Strict relation symbols are only admitted for NNC polyhedra.
02195   if (is_necessarily_closed()
02196       && (relsym == LESS_THAN || relsym == GREATER_THAN))
02197     throw_invalid_argument("generalized_affine_image(v, r, e, d)",
02198                            "r is a strict relation symbol");
02199 
02200   // First compute the affine image.
02201   affine_image(var, expr, denominator);
02202 
02203   if (relsym == EQUAL)
02204     // The affine relation is indeed an affine function.
02205     return;
02206 
02207   // Any image of an empty polyhedron is empty.
02208   // Note: DO check for emptyness here, as we will later add a ray.
02209   if (is_empty())
02210     return;
02211 
02212   switch (relsym) {
02213   case LESS_THAN_OR_EQUAL:
02214     add_generator(ray(-var));
02215     break;
02216   case GREATER_THAN_OR_EQUAL:
02217     add_generator(ray(var));
02218     break;
02219   case LESS_THAN:
02220   // Intentionally fall through.
02221   case GREATER_THAN:
02222     {
02223       // The relation symbol is strict.
02224       assert(!is_necessarily_closed());
02225       // While adding the ray, we minimize the generators
02226       // in order to avoid adding too many redundant generators later.
02227       add_generator_and_minimize(ray(relsym == GREATER_THAN ? var : -var));
02228       // We split each point of the generator system into two generators:
02229       // a closure point, having the same coordinates of the given point,
02230       // and another point, having the same coordinates for all but the
02231       // `var' dimension, which is displaced along the direction of the
02232       // newly introduced ray.
02233       const dimension_type eps_index = space_dim + 1;
02234       for (dimension_type i =  gen_sys.num_rows(); i-- > 0; )
02235         if (gen_sys[i].is_point()) {
02236           Generator& g = gen_sys[i];
02237           // Add a `var'-displaced copy of `g' to the generator system.
02238           gen_sys.add_row(g);
02239           if (relsym == GREATER_THAN)
02240             ++gen_sys[gen_sys.num_rows()-1][var_space_dim];
02241           else
02242             --gen_sys[gen_sys.num_rows()-1][var_space_dim];
02243           // Transform `g' into a closure point.
02244           g[eps_index] = 0;
02245         }
02246       clear_constraints_up_to_date();
02247       clear_generators_minimized();
02248       gen_sys.set_sorted(false);
02249       clear_sat_c_up_to_date();
02250       clear_sat_g_up_to_date();
02251     }
02252     break;
02253   case EQUAL:
02254     // This case was already dealt with before.
02255     throw std::runtime_error("PPL internal error");
02256   }
02257   assert(OK());
02258 }

void Parma_Polyhedra_Library::Polyhedron::generalized_affine_preimage ( Variable  var,
const Relation_Symbol  relsym,
const Linear_Expression expr,
Coefficient_traits::const_reference  denominator = Coefficient_one() 
)

Assigns to *this the preimage of *this with respect to the generalized affine relation $\mathrm{var}' \relsym \frac{\mathrm{expr}}{\mathrm{denominator}}$, where $\mathord{\relsym}$ is the relation symbol encoded by relsym.

Parameters:
var The left hand side variable of the generalized affine relation;
relsym The relation symbol;
expr The numerator of the right hand side affine expression;
denominator The denominator of the right hand side affine expression (optional argument with default value 1.)
Exceptions:
std::invalid_argument Thrown if denominator is zero or if expr and *this are dimension-incompatible or if var is not a space dimension of *this or if *this is a C_Polyhedron and relsym is a strict relation symbol.

Definition at line 2262 of file Polyhedron_public.cc.

References add_constraint(), add_generator(), affine_preimage(), Parma_Polyhedra_Library::Linear_Expression::coefficient(), Parma_Polyhedra_Library::EQUAL, generalized_affine_image(), Parma_Polyhedra_Library::GREATER_THAN, Parma_Polyhedra_Library::GREATER_THAN_OR_EQUAL, is_empty(), is_necessarily_closed(), Parma_Polyhedra_Library::LESS_THAN, Parma_Polyhedra_Library::LESS_THAN_OR_EQUAL, OK(), space_dim, Parma_Polyhedra_Library::Variable::space_dimension(), Parma_Polyhedra_Library::Linear_Expression::space_dimension(), throw_dimension_incompatible(), and throw_invalid_argument().

Referenced by ppl_Polyhedron_generalized_affine_preimage(), and ppl_Polyhedron_generalized_affine_preimage_lhs_rhs().

02265                                                                            {
02266   // The denominator cannot be zero.
02267   if (denominator == 0)
02268     throw_invalid_argument("generalized_affine_preimage(v, r, e, d)",
02269                            "d == 0");
02270 
02271   // Dimension-compatibility checks.
02272   // The dimension of `expr' should not be greater than the dimension
02273   // of `*this'.
02274   if (space_dim < expr.space_dimension())
02275     throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
02276                                  "e", expr);
02277   // `var' should be one of the dimensions of the polyhedron.
02278   const dimension_type var_space_dim = var.space_dimension();
02279   if (space_dim < var_space_dim)
02280     throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
02281                                  "v", var);
02282 
02283   // Strict relation symbols are only admitted for NNC polyhedra.
02284   if (is_necessarily_closed()
02285       && (relsym == LESS_THAN || relsym == GREATER_THAN))
02286     throw_invalid_argument("generalized_affine_preimage(v, r, e, d)",
02287                            "r is a strict relation symbol");
02288 
02289   // Check whether the affine relation is indeed an affine function.
02290   if (relsym == EQUAL) {
02291     affine_preimage(var, expr, denominator);
02292     return;
02293   }
02294 
02295   // Compute the reversed relation symbol to simplify later coding.
02296   Relation_Symbol reversed_relsym;
02297   switch (relsym) {
02298   case LESS_THAN:
02299     reversed_relsym = GREATER_THAN;
02300     break;
02301   case LESS_THAN_OR_EQUAL:
02302     reversed_relsym = GREATER_THAN_OR_EQUAL;
02303     break;
02304   case GREATER_THAN_OR_EQUAL:
02305     reversed_relsym = LESS_THAN_OR_EQUAL;
02306     break;
02307   case GREATER_THAN:
02308     reversed_relsym = LESS_THAN;
02309     break;
02310   default:
02311     // The EQUAL case has been already dealt with.
02312     throw std::runtime_error("PPL internal error");
02313     break;
02314   }
02315 
02316   // Check whether the preimage of this affine relation can be easily
02317   // computed as the image of its inverse relation.
02318   const Coefficient& var_coefficient = expr.coefficient(var);
02319   if (var_coefficient != 0) {
02320     Linear_Expression inverse_expr
02321       = expr - (denominator + var_coefficient) * var;
02322     Coefficient inverse_denominator = - var_coefficient;
02323     Relation_Symbol inverse_relsym
02324       = (sgn(denominator) == sgn(inverse_denominator))
02325       ? relsym : reversed_relsym;
02326     generalized_affine_image(var, inverse_relsym, inverse_expr,
02327                              inverse_denominator);
02328     return;
02329   }
02330 
02331   // Here `var_coefficient == 0', so that the preimage cannot
02332   // be easily computed by inverting the affine relation.
02333   // Shrink the polyhedron by adding the constraint induced
02334   // by the affine relation.
02335   const Relation_Symbol corrected_relsym
02336     = (denominator > 0) ? relsym : reversed_relsym;
02337   switch (corrected_relsym) {
02338   case LESS_THAN:
02339     add_constraint(denominator*var < expr);
02340     break;
02341   case LESS_THAN_OR_EQUAL:
02342     add_constraint(denominator*var <= expr);
02343     break;
02344   case GREATER_THAN_OR_EQUAL:
02345     add_constraint(denominator*var >= expr);
02346     break;
02347   case GREATER_THAN:
02348     add_constraint(denominator*var > expr);
02349     break;
02350   case EQUAL:
02351     // We already dealt with this case.
02352     throw std::runtime_error("PPL internal error");
02353     break;
02354   }
02355   // If the shrunk polyhedron is empty, its preimage is empty too.
02356   // Note: DO check for emptyness here, as we will later add a line.
02357   if (is_empty())
02358     return;
02359   add_generator(line(var));
02360   assert(OK());
02361 }

void Parma_Polyhedra_Library::Polyhedron::generalized_affine_image ( const Linear_Expression lhs,
const Relation_Symbol  relsym,
const Linear_Expression rhs 
)

Assigns to *this the image of *this with respect to the generalized affine relation $\mathrm{lhs}' \relsym \mathrm{rhs}$, where $\mathord{\relsym}$ is the relation symbol encoded by relsym.

Parameters:
lhs The left hand side affine expression;
relsym The relation symbol;
rhs The right hand side affine expression.
Exceptions:
std::invalid_argument Thrown if *this is dimension-incompatible with lhs or rhs or if *this is a C_Polyhedron and relsym is a strict relation symbol.

Definition at line 2364 of file Polyhedron_public.cc.

References add_constraint(), add_constraint_and_minimize(), add_recycled_generators_and_minimize(), add_space_dimensions_and_embed(), Parma_Polyhedra_Library::Linear_Expression::coefficient(), Parma_Polyhedra_Library::EQUAL, Parma_Polyhedra_Library::GREATER_THAN, Parma_Polyhedra_Library::GREATER_THAN_OR_EQUAL, Parma_Polyhedra_Library::Generator_System::insert(), is_empty(), is_necessarily_closed(), Parma_Polyhedra_Library::LESS_THAN, Parma_Polyhedra_Library::LESS_THAN_OR_EQUAL, marked_empty(), OK(), remove_higher_space_dimensions(), space_dim, Parma_Polyhedra_Library::Linear_Expression::space_dimension(), throw_dimension_incompatible(), and throw_invalid_argument().

02366                                                                         {
02367   // Dimension-compatibility checks.
02368   // The dimension of `lhs' should not be greater than the dimension
02369   // of `*this'.
02370   dimension_type lhs_space_dim = lhs.space_dimension();
02371   if (space_dim < lhs_space_dim)
02372     throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
02373                                  "e1", lhs);
02374   // The dimension of `rhs' should not be greater than the dimension
02375   // of `*this'.
02376   const dimension_type rhs_space_dim = rhs.space_dimension();
02377   if (space_dim < rhs_space_dim)
02378     throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
02379                                  "e2", rhs);
02380 
02381   // Strict relation symbols are only admitted for NNC polyhedra.
02382   if (is_necessarily_closed()
02383       && (relsym == LESS_THAN || relsym == GREATER_THAN))
02384     throw_invalid_argument("generalized_affine_image(e1, r, e2)",
02385                            "r is a strict relation symbol");
02386 
02387   // Any image of an empty polyhedron is empty.
02388   if (marked_empty())
02389     return;
02390 
02391   // Compute the actual space dimension of `lhs',
02392   // i.e., the highest dimension having a non-zero coefficient in `lhs'.
02393   for ( ; lhs_space_dim > 0; lhs_space_dim--)
02394     if (lhs.coefficient(Variable(lhs_space_dim - 1)) != 0)
02395       break;
02396   // If all variables have a zero coefficient, then `lhs' is a constant:
02397   // we can simply add the constraint `lhs relsym rhs'.
02398   if (lhs_space_dim == 0) {
02399     switch (relsym) {
02400     case LESS_THAN:
02401       add_constraint(lhs < rhs);
02402       break;
02403     case LESS_THAN_OR_EQUAL:
02404       add_constraint(lhs <= rhs);
02405       break;
02406     case EQUAL:
02407       add_constraint(lhs == rhs);
02408       break;
02409     case GREATER_THAN_OR_EQUAL:
02410       add_constraint(lhs >= rhs);
02411       break;
02412     case GREATER_THAN:
02413       add_constraint(lhs > rhs);
02414       break;
02415     }
02416     return;
02417   }
02418 
02419   // Gather in `new_lines' the collections of all the lines having
02420   // the direction of variables occurring in `lhs'.
02421   // While at it, check whether or not there exists a variable
02422   // occurring in both `lhs' and `rhs'.
02423   Generator_System new_lines;
02424   bool lhs_vars_intersects_rhs_vars = false;
02425   for (dimension_type i = lhs_space_dim; i-- > 0; )
02426     if (lhs.coefficient(Variable(i)) != 0) {
02427       new_lines.insert(line(Variable(i)));
02428       if (rhs.coefficient(Variable(i)) != 0)
02429         lhs_vars_intersects_rhs_vars = true;
02430     }
02431 
02432   if (lhs_vars_intersects_rhs_vars) {
02433     // Some variables in `lhs' also occur in `rhs'.
02434     // To ease the computation, we add an additional dimension.
02435     const Variable new_var = Variable(space_dim);
02436     add_space_dimensions_and_embed(1);
02437 
02438     // Constrain the new dimension to be equal to the right hand side.
02439     // (check for emptiness because we will add lines).
02440     if (add_constraint_and_minimize(new_var == rhs)) {
02441       // Cylindrificate on all the variables occurring in the left hand side
02442       // (we force minimization because we will need the constraints).
02443       add_recycled_generators_and_minimize(new_lines);
02444 
02445       // Constrain the new dimension so that it is related to
02446       // the left hand side as dictated by `relsym'
02447       // (we force minimization because we will need the generators).
02448       switch (relsym) {
02449       case LESS_THAN:
02450         add_constraint_and_minimize(lhs < new_var);
02451         break;
02452       case LESS_THAN_OR_EQUAL:
02453         add_constraint_and_minimize(lhs <= new_var);
02454         break;
02455       case EQUAL:
02456         add_constraint_and_minimize(lhs == new_var);
02457         break;
02458       case GREATER_THAN_OR_EQUAL:
02459         add_constraint_and_minimize(lhs >= new_var);
02460         break;
02461       case GREATER_THAN:
02462         add_constraint_and_minimize(lhs > new_var);
02463         break;
02464       }
02465     }
02466     // Remove the temporarily added dimension.
02467     remove_higher_space_dimensions(space_dim-1);
02468   }
02469   else {
02470     // `lhs' and `rhs' variables are disjoint:
02471     // there is no need to add a further dimension.
02472 
02473     // Any image of an empty polyhedron is empty.
02474     // Note: DO check for emptyness here, as we will add lines.
02475     if (is_empty())
02476       return;
02477 
02478     // Cylindrificate on all the variables occurring in the left hand side
02479     // (we force minimization because we will need the constraints).
02480     add_recycled_generators_and_minimize(new_lines);
02481 
02482     // Constrain the left hand side expression so that it is related to
02483     // the right hand side expression as dictated by `relsym'.
02484     switch (relsym) {
02485     case LESS_THAN:
02486       add_constraint(lhs < rhs);
02487       break;
02488     case LESS_THAN_OR_EQUAL:
02489       add_constraint(lhs <= rhs);
02490       break;
02491     case EQUAL:
02492       add_constraint(lhs == rhs);
02493       break;
02494     case GREATER_THAN_OR_EQUAL:
02495       add_constraint(lhs >= rhs);
02496       break;
02497     case GREATER_THAN:
02498       add_constraint(lhs > rhs);
02499       break;
02500     }
02501   }
02502   assert(OK());
02503 }

void Parma_Polyhedra_Library::Polyhedron::generalized_affine_preimage ( const Linear_Expression lhs,
const Relation_Symbol  relsym,
const Linear_Expression rhs 
)

Assigns to *this the preimage of *this with respect to the generalized affine relation $\mathrm{lhs}' \relsym \mathrm{rhs}$, where $\mathord{\relsym}$ is the relation symbol encoded by relsym.

Parameters:
lhs The left hand side affine expression;
relsym The relation symbol;
rhs The right hand side affine expression.
Exceptions:
std::invalid_argument Thrown if *this is dimension-incompatible with lhs or rhs or if *this is a C_Polyhedron and relsym is a strict relation symbol.

Definition at line 2506 of file Polyhedron_public.cc.

References add_constraint(), add_constraint_and_minimize(), add_recycled_generators(), add_recycled_generators_and_minimize(), add_space_dimensions_and_embed(), Parma_Polyhedra_Library::Linear_Expression::coefficient(), Parma_Polyhedra_Library::EQUAL, generalized_affine_image(), Parma_Polyhedra_Library::GREATER_THAN, Parma_Polyhedra_Library::GREATER_THAN_OR_EQUAL, Parma_Polyhedra_Library::Generator_System::insert(), is_empty(), is_necessarily_closed(), Parma_Polyhedra_Library::LESS_THAN, Parma_Polyhedra_Library::LESS_THAN_OR_EQUAL, marked_empty(), OK(), remove_higher_space_dimensions(), space_dim, Parma_Polyhedra_Library::Linear_Expression::space_dimension(), throw_dimension_incompatible(), and throw_invalid_argument().

02508                                                                            {
02509   // Dimension-compatibility checks.
02510   // The dimension of `lhs' should not be greater than the dimension
02511   // of `*this'.
02512   dimension_type lhs_space_dim = lhs.space_dimension();
02513   if (space_dim < lhs_space_dim)
02514     throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2)",
02515                                  "e1", lhs);
02516   // The dimension of `rhs' should not be greater than the dimension
02517   // of `*this'.
02518   const dimension_type rhs_space_dim = rhs.space_dimension();
02519   if (space_dim < rhs_space_dim)
02520     throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2)",
02521                                  "e2", rhs);
02522 
02523   // Strict relation symbols are only admitted for NNC polyhedra.
02524   if (is_necessarily_closed()
02525       && (relsym == LESS_THAN || relsym == GREATER_THAN))
02526     throw_invalid_argument("generalized_affine_preimage(e1, r, e2)",
02527                            "r is a strict relation symbol");
02528 
02529   // Any preimage of an empty polyhedron is empty.
02530   if (marked_empty())
02531     return;
02532 
02533   // Compute the actual space dimension of `lhs',
02534   // i.e., the highest dimension having a non-zero coefficient in `lhs'.
02535   for ( ; lhs_space_dim > 0; lhs_space_dim--)
02536     if (lhs.coefficient(Variable(lhs_space_dim - 1)) != 0)
02537       break;
02538 
02539   // If all variables have a zero coefficient, then `lhs' is a constant:
02540   // in this case, preimage and image happen to be the same.
02541   if (lhs_space_dim == 0) {
02542     generalized_affine_image(lhs, relsym, rhs);
02543     return;
02544   }
02545 
02546   // Gather in `new_lines' the collections of all the lines having
02547   // the direction of variables occurring in `lhs'.
02548   // While at it, check whether or not there exists a variable
02549   // occurring in both `lhs' and `rhs'.
02550   Generator_System new_lines;
02551   bool lhs_vars_intersects_rhs_vars = false;
02552   for (dimension_type i = lhs_space_dim; i-- > 0; )
02553     if (lhs.coefficient(Variable(i)) != 0) {
02554       new_lines.insert(line(Variable(i)));
02555       if (rhs.coefficient(Variable(i)) != 0)
02556         lhs_vars_intersects_rhs_vars = true;
02557     }
02558 
02559   if (lhs_vars_intersects_rhs_vars) {
02560     // Some variables in `lhs' also occur in `rhs'.
02561     // To ease the computation, we add an additional dimension.
02562     const Variable new_var = Variable(space_dim);
02563     add_space_dimensions_and_embed(1);
02564 
02565     // Constrain the new dimension to be equal to `lhs'
02566     // (also check for emptiness because we have to add lines).
02567     if (add_constraint_and_minimize(new_var == lhs)) {
02568       // Cylindrificate on all the variables occurring in the left hand side
02569       // (we force minimization because we will need the constraints).
02570       add_recycled_generators_and_minimize(new_lines);
02571 
02572       // Constrain the new dimension so that it is related to
02573       // the right hand side as dictated by `relsym'
02574       // (we force minimization because we will need the generators).
02575       switch (relsym) {
02576       case LESS_THAN:
02577         add_constraint_and_minimize(new_var < rhs);
02578         break;
02579       case LESS_THAN_OR_EQUAL:
02580         add_constraint_and_minimize(new_var <= rhs);
02581         break;
02582       case EQUAL:
02583         add_constraint_and_minimize(new_var == rhs);
02584         break;
02585       case GREATER_THAN_OR_EQUAL:
02586         add_constraint_and_minimize(new_var >= rhs);
02587         break;
02588       case GREATER_THAN:
02589         add_constraint_and_minimize(new_var > rhs);
02590         break;
02591       }
02592     }
02593     // Remove the temporarily added dimension.
02594     remove_higher_space_dimensions(space_dim-1);
02595   }
02596   else {
02597     // `lhs' and `rhs' variables are disjoint:
02598     // there is no need to add a further dimension.
02599 
02600     // Constrain the left hand side expression so that it is related to
02601     // the right hand side expression as dictated by `relsym'.
02602     switch (relsym) {
02603     case LESS_THAN:
02604       add_constraint(lhs < rhs);
02605       break;
02606     case LESS_THAN_OR_EQUAL:
02607       add_constraint(lhs <= rhs);
02608       break;
02609     case EQUAL:
02610       add_constraint(lhs == rhs);
02611       break;
02612     case GREATER_THAN_OR_EQUAL:
02613       add_constraint(lhs >= rhs);
02614       break;
02615     case GREATER_THAN:
02616       add_constraint(lhs > rhs);
02617       break;
02618     }
02619     // Any image of an empty polyhedron is empty.
02620     // Note: DO check for emptyness here, as we will add lines.
02621     if (is_empty())
02622       return;
02623     // Cylindrificate on all the variables occurring in `lhs'.
02624     add_recycled_generators(new_lines);
02625   }
02626   assert(OK());
02627 }

void Parma_Polyhedra_Library::Polyhedron::bounded_affine_image ( Variable  var,
const Linear_Expression lb_expr,
const Linear_Expression ub_expr,
Coefficient_traits::const_reference  denominator = Coefficient_one() 
)

Assigns to *this the image of *this with respect to the bounded affine relation $\frac{\mathrm{lb\_expr}}{\mathrm{denominator}} \leq \mathrm{var}' \leq \frac{\mathrm{ub\_expr}}{\mathrm{denominator}}$.

Parameters:
var The variable updated by the affine relation;
lb_expr The numerator of the lower bounding affine expression;
ub_expr The numerator of the upper bounding affine expression;
denominator The (common) denominator for the lower and upper bounding affine expressions (optional argument with default value 1.)
Exceptions:
std::invalid_argument Thrown if denominator is zero or if lb_expr (resp., ub_expr) and *this are dimension-incompatible or if var is not a space dimension of *this.

Definition at line 2018 of file Polyhedron_public.cc.

References add_constraint(), add_constraint_and_minimize(), add_space_dimensions_and_embed(), Parma_Polyhedra_Library::Linear_Expression::coefficient(), generalized_affine_image(), Parma_Polyhedra_Library::GREATER_THAN_OR_EQUAL, Parma_Polyhedra_Library::LESS_THAN_OR_EQUAL, marked_empty(), OK(), remove_higher_space_dimensions(), space_dim, Parma_Polyhedra_Library::Linear_Expression::space_dimension(), Parma_Polyhedra_Library::Variable::space_dimension(), throw_dimension_incompatible(), and throw_invalid_argument().

Referenced by ppl_Polyhedron_bounded_affine_image().

02021                                                                     {
02022   // The denominator cannot be zero.
02023   if (denominator == 0)
02024     throw_invalid_argument("bounded_affine_image(v, lb, ub, d)", "d == 0");
02025 
02026   // Dimension-compatibility checks.
02027   // `var' should be one of the dimensions of the polyhedron.
02028   const dimension_type var_space_dim = var.space_dimension();
02029   if (space_dim < var_space_dim)
02030     throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
02031                                  "v", var);
02032   // The dimension of `lb_expr' and `ub_expr' should not be
02033   // greater than the dimension of `*this'.
02034   const dimension_type lb_space_dim = lb_expr.space_dimension();
02035   if (space_dim < lb_space_dim)
02036     throw_dimension_incompatible("bounded_affine_image(v, lb, ub)",
02037                                  "lb", lb_expr);
02038   const dimension_type ub_space_dim = ub_expr.space_dimension();
02039   if (space_dim < ub_space_dim)
02040     throw_dimension_incompatible("bounded_affine_image(v, lb, ub)",
02041                                  "ub", ub_expr);
02042 
02043   // Any image of an empty polyhedron is empty.
02044   if (marked_empty())
02045     return;
02046 
02047   // Check whether `var' occurs in `lb_expr' and/or `ub_expr'.
02048   if (lb_expr.coefficient(var) == 0) {
02049     // Here `var' may only occur in `ub_expr'.
02050     generalized_affine_image(var,
02051                              LESS_THAN_OR_EQUAL,
02052                              ub_expr,
02053                              denominator);
02054     if (denominator > 0)
02055       add_constraint(lb_expr <= denominator*var);
02056     else
02057       add_constraint(denominator*var <= lb_expr);
02058   }
02059   else if (ub_expr.coefficient(var) == 0) {
02060     // Here `var' only occurs in `lb_expr'.
02061     generalized_affine_image(var,
02062                              GREATER_THAN_OR_EQUAL,
02063                              lb_expr,
02064                              denominator);
02065     if (denominator > 0)
02066       add_constraint(denominator*var <= ub_expr);
02067     else
02068       add_constraint(ub_expr <= denominator*var);
02069   }
02070   else {
02071     // Here `var' occurs in both `lb_expr' and `ub_expr'.
02072     // To ease the computation, we add an additional dimension.
02073     const Variable new_var = Variable(space_dim);
02074     add_space_dimensions_and_embed(1);
02075     // Constrain the new dimension to be equal to `ub_expr'.
02076     // (we force minimization because we will need the generators).
02077     add_constraint_and_minimize(denominator*new_var == ub_expr);
02078     // Apply the affine lower bound.
02079     generalized_affine_image(var,
02080                              GREATER_THAN_OR_EQUAL,
02081                              lb_expr,
02082                              denominator);
02083     // Now apply the affine upper bound, as recorded in `new_var'
02084     // (we force minimization because we will need the generators).
02085     if (denominator > 0)
02086       add_constraint_and_minimize(var <= new_var);
02087     else
02088       add_constraint_and_minimize(new_var <= var);
02089     // Remove the temporarily added dimension.
02090     remove_higher_space_dimensions(space_dim-1);
02091   }
02092   assert(OK());
02093 }

void Parma_Polyhedra_Library::Polyhedron::bounded_affine_preimage ( Variable  var,
const Linear_Expression lb_expr,
const Linear_Expression ub_expr,
Coefficient_traits::const_reference  denominator = Coefficient_one() 
)

Assigns to *this the preimage of *this with respect to the bounded affine relation $\frac{\mathrm{lb\_expr}}{\mathrm{denominator}} \leq \mathrm{var}' \leq \frac{\mathrm{ub\_expr}}{\mathrm{denominator}}$.

Parameters:
var The variable updated by the affine relation;
lb_expr The numerator of the lower bounding affine expression;
ub_expr The numerator of the upper bounding affine expression;
denominator The (common) denominator for the lower and upper bounding affine expressions (optional argument with default value 1.)
Exceptions:
std::invalid_argument Thrown if denominator is zero or if lb_expr (resp., ub_expr) and *this are dimension-incompatible or if var is not a space dimension of *this.

Definition at line 2097 of file Polyhedron_public.cc.

References add_constraint(), add_generator(), add_space_dimensions_and_embed(), Parma_Polyhedra_Library::Linear_Expression::coefficient(), con_sys, constraints_are_up_to_date(), gen_sys, generators_are_up_to_date(), is_empty(), marked_empty(), OK(), Parma_Polyhedra_Library::Linear_System::permute_columns(), remove_higher_space_dimensions(), space_dim, Parma_Polyhedra_Library::Linear_Expression::space_dimension(), Parma_Polyhedra_Library::Variable::space_dimension(), throw_dimension_incompatible(), and throw_invalid_argument().

Referenced by ppl_Polyhedron_bounded_affine_preimage().

02100                                                                        {
02101   // The denominator cannot be zero.
02102   if (denominator == 0)
02103     throw_invalid_argument("bounded_affine_preimage(v, lb, ub, d)", "d == 0");
02104 
02105   // Dimension-compatibility checks.
02106   // `var' should be one of the dimensions of the polyhedron.
02107   const dimension_type var_space_dim = var.space_dimension();
02108   if (space_dim < var_space_dim)
02109     throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
02110                                  "v", var);
02111   // The dimension of `lb_expr' and `ub_expr' should not be
02112   // greater than the dimension of `*this'.
02113   const dimension_type lb_space_dim = lb_expr.space_dimension();
02114   if (space_dim < lb_space_dim)
02115     throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub)",
02116                                  "lb", lb_expr);
02117   const dimension_type ub_space_dim = ub_expr.space_dimension();
02118   if (space_dim < ub_space_dim)
02119     throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub)",
02120                                  "ub", ub_expr);
02121 
02122   // Any preimage of an empty polyhedron is empty.
02123   if (marked_empty())
02124     return;
02125 
02126   // Check whether `var' occurs in neither `lb_expr' nor `ub_expr'.
02127   if (lb_expr.coefficient(var) == 0 && ub_expr.coefficient(var) == 0) {
02128     if (denominator > 0) {
02129       add_constraint(lb_expr <= denominator*var);
02130       add_constraint(denominator*var <= ub_expr);
02131     }
02132     else {
02133       add_constraint(ub_expr <= denominator*var);
02134       add_constraint(denominator*var <= lb_expr);
02135     }
02136     // Any image of an empty polyhedron is empty.
02137     // Note: DO check for emptyness here, as we will later add a line.
02138     if (is_empty())
02139       return;
02140     add_generator(line(var));
02141   }
02142   else {
02143     // Here `var' occurs in `lb_expr' or `ub_expr'.
02144     // To ease the computation, add an additional dimension.
02145     const Variable new_var = Variable(space_dim);
02146     add_space_dimensions_and_embed(1);
02147     // Swap dimensions `var' and `new_var'.
02148     std::vector<dimension_type> swapping_cycle;
02149     swapping_cycle.push_back(var_space_dim);
02150     swapping_cycle.push_back(space_dim);
02151     swapping_cycle.push_back(0);
02152     if (constraints_are_up_to_date())
02153       con_sys.permute_columns(swapping_cycle);
02154     if (generators_are_up_to_date())
02155       gen_sys.permute_columns(swapping_cycle);
02156     // Constrain the new dimension as dictated by `lb_expr' and `ub_expr'.
02157     // (we force minimization because we will need the generators).
02158     if (denominator > 0) {
02159       add_constraint(lb_expr <= denominator*new_var);
02160       add_constraint(denominator*new_var <= ub_expr);
02161     }
02162     else {
02163       add_constraint(ub_expr <= denominator*new_var);
02164       add_constraint(denominator*new_var <= lb_expr);
02165     }
02166     // Remove the temporarily added dimension.
02167     remove_higher_space_dimensions(space_dim-1);
02168   }
02169   assert(OK());
02170 }

void Parma_Polyhedra_Library::Polyhedron::time_elapse_assign ( const Polyhedron y  ) 

Assigns to *this the result of computing the time-elapse between *this and y.

Exceptions:
std::invalid_argument Thrown if *this and y are topology-incompatible or dimension-incompatible.

Definition at line 2630 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::Linear_System::add_pending_rows(), Parma_Polyhedra_Library::Linear_Row::all_homogeneous_terms_are_zero(), can_have_something_pending(), clear_constraints_up_to_date(), clear_generators_minimized(), Parma_Polyhedra_Library::Generator::CLOSURE_POINT, Parma_Polyhedra_Library::Matrix::erase_to_end(), gen_sys, generators_are_up_to_date(), has_pending_constraints(), is_necessarily_closed(), Parma_Polyhedra_Library::Linear_System::is_sorted(), marked_empty(), Parma_Polyhedra_Library::Linear_System::merge_rows_assign(), Parma_Polyhedra_Library::Row::normalize(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), Parma_Polyhedra_Library::Generator::POINT, process_pending_constraints(), set_empty(), set_generators_pending(), Parma_Polyhedra_Library::Linear_System::sort_rows(), space_dim, throw_dimension_incompatible(), throw_topology_incompatible(), topology(), Parma_Polyhedra_Library::Linear_System::unset_pending_rows(), and update_generators().

Referenced by ppl_Polyhedron_time_elapse_assign(), and Parma_Polyhedra_Library::BD_Shape< T >::time_elapse_assign().

02630                                                      {
02631   Polyhedron& x = *this;
02632   // Topology compatibility check.
02633   if (x.topology() != y.topology())
02634     throw_topology_incompatible("time_elapse_assign(y)", "y", y);
02635   // Dimension-compatibility checks.
02636   if (x.space_dim != y.space_dim)
02637     throw_dimension_incompatible("time_elapse_assign(y)", "y", y);
02638 
02639   // Dealing with the zero-dimensional case.
02640   if (x.space_dim == 0) {
02641     if (y.marked_empty())
02642       x.set_empty();
02643     return;
02644   }
02645 
02646   // If either one of `x' or `y' is empty, the result is empty too.
02647   if (x.marked_empty() || y.marked_empty()
02648       || (x.has_pending_constraints() && !x.process_pending_constraints())
02649       || (!x.generators_are_up_to_date() && !x.update_generators())
02650       || (y.has_pending_constraints() && !y.process_pending_constraints())
02651       || (!y.generators_are_up_to_date() && !y.update_generators())) {
02652     x.set_empty();
02653     return;
02654   }
02655 
02656   // At this point both generator systems are up-to-date,
02657   // possibly containing pending generators.
02658   Generator_System gs = y.gen_sys;
02659   dimension_type gs_num_rows = gs.num_rows();
02660 
02661   if (!x.is_necessarily_closed())
02662     // `x' and `y' are NNC polyhedra.
02663     for (dimension_type i = gs_num_rows; i-- > 0; )
02664       switch (gs[i].type()) {
02665       case Generator::POINT:
02666         // The points of `gs' can be erased,
02667         // since their role can be played by closure points.
02668         --gs_num_rows;
02669         std::swap(gs[i], gs[gs_num_rows]);
02670         break;
02671       case Generator::CLOSURE_POINT:
02672         {
02673           Generator& cp = gs[i];
02674           // If it is the origin, erase it.
02675           if (cp.all_homogeneous_terms_are_zero()) {
02676             --gs_num_rows;
02677             std::swap(cp, gs[gs_num_rows]);
02678           }
02679           // Otherwise, transform the closure point into a ray.
02680           else {
02681             cp[0] = 0;
02682             // Enforce normalization.
02683             cp.normalize();
02684           }
02685         }
02686         break;
02687       default:
02688         // For rays and lines, nothing to be done.
02689         break;
02690       }
02691   else
02692     // `x' and `y' are C polyhedra.
02693     for (dimension_type i = gs_num_rows; i-- > 0; )
02694       switch (gs[i].type()) {
02695       case Generator::POINT:
02696         {
02697           Generator& p = gs[i];
02698           // If it is the origin, erase it.
02699           if (p.all_homogeneous_terms_are_zero()) {
02700             --gs_num_rows;
02701             std::swap(p, gs[gs_num_rows]);
02702           }
02703           // Otherwise, transform the point into a ray.
02704           else {
02705             p[0] = 0;
02706             // Enforce normalization.
02707             p.normalize();
02708           }
02709         }
02710         break;
02711       default:
02712         // For rays and lines, nothing to be done.
02713         break;
02714       }
02715   // If it was present, erase the origin point or closure point,
02716   // which cannot be transformed into a valid ray or line.
02717   // For NNC polyhedra, also erase all the points of `gs',
02718   // whose role can be played by the closure points.
02719   // These have been previously moved to the end of `gs'.
02720   gs.erase_to_end(gs_num_rows);
02721   gs.unset_pending_rows();
02722 
02723   // `gs' may now have no rows.
02724   // Namely, this happens when `y' was the singleton polyhedron
02725   // having the origin as the one and only point.
02726   // In such a case, the resulting polyhedron is equal to `x'.
02727   if (gs_num_rows == 0)
02728     return;
02729 
02730   // If the polyhedron can have something pending, we add `gs'
02731   // to `gen_sys' as pending rows
02732   if (x.can_have_something_pending()) {
02733     x.gen_sys.add_pending_rows(gs);
02734     x.set_generators_pending();
02735   }
02736   // Otherwise, the two systems are merged.
02737   // `Linear_System::merge_rows_assign()' requires both systems to be sorted.
02738   else {
02739     if (!x.gen_sys.is_sorted())
02740       x.gen_sys.sort_rows();
02741     gs.sort_rows();
02742     x.gen_sys.merge_rows_assign(gs);
02743     // Only the system of generators is up-to-date.
02744     x.clear_constraints_up_to_date();
02745     x.clear_generators_minimized();
02746   }
02747   assert(x.OK(true) && y.OK(true));
02748 }

void Parma_Polyhedra_Library::Polyhedron::topological_closure_assign (  ) 

Assigns to *this its topological closure.

Definition at line 2751 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::Generator_System::add_corresponding_points(), can_have_something_pending(), clear_constraints_minimized(), clear_constraints_up_to_date(), clear_generators_minimized(), clear_generators_up_to_date(), con_sys, constraints_are_up_to_date(), Parma_Polyhedra_Library::Constraint::epsilon_leq_one(), gen_sys, generators_are_up_to_date(), has_pending_constraints(), has_pending_generators(), Parma_Polyhedra_Library::Constraint_System::insert(), is_necessarily_closed(), Parma_Polyhedra_Library::Constraint::is_tautological(), marked_empty(), Parma_Polyhedra_Library::Row::normalize(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), process_pending_constraints(), set_generators_pending(), Parma_Polyhedra_Library::Linear_System::set_sorted(), space_dim, and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

Referenced by ppl_Polyhedron_topological_closure_assign().

02751                                           {
02752   // Necessarily closed polyhedra are trivially closed.
02753   if (is_necessarily_closed())
02754     return;
02755   // Any empty or zero-dimensional polyhedron is closed.
02756   if (marked_empty() || space_dim == 0)
02757     return;
02758 
02759   // The computation can be done using constraints or generators.
02760   // If we use constraints, we will change them, so that having pending
02761   // constraints would be useless. If we use generators, we add generators,
02762   // so that having pending generators still makes sense.
02763 
02764   // Process any pending constraints.
02765   if (has_pending_constraints() && !process_pending_constraints())
02766     return;
02767 
02768   // Use constraints only if they are available and
02769   // there are no pending generators.
02770   if (!has_pending_generators() && constraints_are_up_to_date()) {
02771     const dimension_type eps_index = space_dim + 1;
02772     bool changed = false;
02773     // Transform all strict inequalities into non-strict ones.
02774     for (dimension_type i = con_sys.num_rows(); i-- > 0; ) {
02775       Constraint& c = con_sys[i];
02776       if (c[eps_index] < 0 && !c.is_tautological()) {
02777         c[eps_index] = 0;
02778         // Enforce normalization.
02779         c.normalize();
02780         changed = true;
02781       }
02782     }
02783     if (changed) {
02784       con_sys.insert(Constraint::epsilon_leq_one());
02785       con_sys.set_sorted(false);
02786       // After changing the system of constraints, the generators
02787       // are no longer up-to-date and the constraints are no longer
02788       // minimized.
02789       clear_generators_up_to_date();
02790       clear_constraints_minimized();
02791     }
02792   }
02793   else {
02794     // Here we use generators, possibly keeping constraints.
02795     assert(generators_are_up_to_date());
02796     // Add the corresponding point to each closure point.
02797     gen_sys.add_corresponding_points();
02798     if (can_have_something_pending())
02799       set_generators_pending();
02800     else {
02801       // We cannot have pending generators; this also implies
02802       // that generators may have lost their sortedness.
02803       gen_sys.unset_pending_rows();
02804       gen_sys.set_sorted(false);
02805       // Constraints are not up-to-date and generators are not minimized.
02806       clear_constraints_up_to_date();
02807       clear_generators_minimized();
02808     }
02809   }
02810   assert(OK());
02811 }

void Parma_Polyhedra_Library::Polyhedron::BHRZ03_widening_assign ( const Polyhedron y,
unsigned *  tp = 0 
)

Assigns to *this the result of computing the BHRZ03-widening between *this and y.

Parameters:
y A polyhedron that must be contained in *this;
tp An optional pointer to an unsigned variable storing the number of available tokens (to be used when applying the widening with tokens delay technique).
Exceptions:
std::invalid_argument Thrown if *this and y are topology-incompatible or dimension-incompatible.

Definition at line 653 of file Polyhedron_widenings.cc.

References BHRZ03_combining_constraints(), BHRZ03_evolving_points(), BHRZ03_evolving_rays(), contains(), intersection_assign_and_minimize(), is_necessarily_closed(), Parma_Polyhedra_Library::BHRZ03_Certificate::is_stabilizing(), marked_empty(), minimize(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), select_H79_constraints(), space_dim, throw_dimension_incompatible(), throw_topology_incompatible(), topology(), and Parma_Polyhedra_Library::UNIVERSE.

Referenced by limited_BHRZ03_extrapolation_assign(), and ppl_Polyhedron_BHRZ03_widening_assign_with_tokens().

00653                                                                        {
00654   Polyhedron& x = *this;
00655   // Topology compatibility check.
00656   if (x.topology() != y.topology())
00657     throw_topology_incompatible("BHRZ03_widening_assign(y)", "y", y);
00658   // Dimension-compatibility check.
00659   if (x.space_dim != y.space_dim)
00660     throw_dimension_incompatible("BHRZ03_widening_assign(y)", "y", y);
00661 
00662 #ifndef NDEBUG
00663   {
00664     // We assume that y is contained in or equal to x.
00665     const Polyhedron x_copy = x;
00666     const Polyhedron y_copy = y;
00667     assert(x_copy.contains(y_copy));
00668   }
00669 #endif
00670 
00671   // If any argument is zero-dimensional or empty,
00672   // the BHRZ03-widening behaves as the identity function.
00673   if (x.space_dim == 0 || x.marked_empty() || y.marked_empty())
00674     return;
00675 
00676   // `x.con_sys' and `x.gen_sys' should be in minimal form.
00677   x.minimize();
00678 
00679   // `y.con_sys' and `y.gen_sys' should be in minimal form.
00680   if (y.is_necessarily_closed()) {
00681     if (!y.minimize())
00682       // `y' is empty: the result is `x'.
00683       return;
00684   }
00685   else {
00686     // Dealing with a NNC polyhedron.
00687     // To obtain a correct reasoning when comparing
00688     // the constraints of `x' with the generators of `y',
00689     // we enforce the inclusion relation holding between
00690     // the two NNC polyhedra `x' and `y' (i.e., `y <= x')
00691     // to also hold for the corresponding eps-representations:
00692     // this is obtained by intersecting the two eps-representations.
00693     Polyhedron& yy = const_cast<Polyhedron&>(y);
00694     if (!yy.intersection_assign_and_minimize(x))
00695       // `y' is empty: the result is `x'.
00696       return;
00697   }
00698 
00699   // Compute certificate info for polyhedron `y'.
00700   BHRZ03_Certificate y_cert(y);
00701 
00702   // If the iteration is stabilizing, the resulting polyhedron is `x'.
00703   // At this point, also check if the two polyhedra are the same
00704   // (exploiting the knowledge that `y <= x').
00705   if (y_cert.is_stabilizing(x) || y.contains(x)) {
00706     assert(OK());
00707     return;
00708   }
00709 
00710   // Here the iteration is not immediately stabilizing.
00711   // If we are using the widening-with-tokens technique and
00712   // there are tokens available, use one of them and return `x'.
00713   if (tp != 0 && *tp > 0) {
00714     --(*tp);
00715     assert(OK());
00716     return;
00717   }
00718 
00719   // Copy into `H79_cs' the constraints that are common to `x' and `y',
00720   // according to the definition of the H79 widening.
00721   // The other ones are copied into `x_minus_H79_cs'.
00722   const Topology tpl = x.topology();
00723   Constraint_System H79_cs(tpl);
00724   Constraint_System x_minus_H79_cs(tpl);
00725   x.select_H79_constraints(y, H79_cs, x_minus_H79_cs);
00726 
00727   // We cannot have selected all of the rows, since otherwise
00728   // the iteration should have been immediately stabilizing.
00729   assert(x_minus_H79_cs.num_rows() > 0);
00730   // Be careful to obtain the right space dimension
00731   // (because `H79_cs' may be empty).
00732   Polyhedron H79(tpl, x.space_dim, UNIVERSE);
00733   H79.add_recycled_constraints_and_minimize(H79_cs);
00734 
00735   // NOTE: none of the following widening heuristics is intrusive:
00736   // they will modify `x' only when returning successfully.
00737   if (x.BHRZ03_combining_constraints(y, y_cert, H79, x_minus_H79_cs))
00738     return;
00739 
00740   assert(H79.OK() && x.OK() && y.OK());
00741 
00742   if (x.BHRZ03_evolving_points(y, y_cert, H79))
00743     return;
00744 
00745   assert(H79.OK() && x.OK() && y.OK());
00746 
00747   if (x.BHRZ03_evolving_rays(y, y_cert, H79))
00748     return;
00749 
00750   assert(H79.OK() && x.OK() && y.OK());
00751 
00752   // No previous technique was successful: fall back to the H79 widening.
00753   std::swap(x, H79);
00754   assert(x.OK(true));
00755 
00756 #ifndef NDEBUG
00757   // The H79 widening is always stabilizing.
00758   x.minimize();
00759   assert(y_cert.is_stabilizing(x));
00760 #endif
00761 }

void Parma_Polyhedra_Library::Polyhedron::limited_BHRZ03_extrapolation_assign ( const Polyhedron y,
const Constraint_System cs,
unsigned *  tp = 0 
)

Improves the result of the BHRZ03-widening computation by also enforcing those constraints in cs that are satisfied by all the points of *this.

Parameters:
y A polyhedron that must be contained in *this;
cs The system of constraints used to improve the widened polyhedron;
tp An optional pointer to an unsigned variable storing the number of available tokens (to be used when applying the widening with tokens delay technique).
Exceptions:
std::invalid_argument Thrown if *this, y and cs are topology-incompatible or dimension-incompatible.

Definition at line 765 of file Polyhedron_widenings.cc.

References add_constraints(), BHRZ03_widening_assign(), contains(), gen_sys, generators_are_up_to_date(), has_pending_constraints(), Parma_Polyhedra_Library::Constraint_System::has_strict_inequalities(), Parma_Polyhedra_Library::Constraint_System::insert(), is_necessarily_closed(), marked_empty(), minimize(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), process_pending_constraints(), Parma_Polyhedra_Library::Generator_System::satisfied_by_all_generators(), space_dim, Parma_Polyhedra_Library::Constraint_System::space_dimension(), throw_dimension_incompatible(), throw_topology_incompatible(), and update_generators().

Referenced by bounded_BHRZ03_extrapolation_assign(), and ppl_Polyhedron_limited_BHRZ03_extrapolation_assign_with_tokens().

00767                                                     {
00768   Polyhedron& x = *this;
00769   const dimension_type cs_num_rows = cs.num_rows();
00770   // If `cs' is empty, we fall back to ordinary, non-limited widening.
00771   if (cs_num_rows == 0) {
00772     x.BHRZ03_widening_assign(y, tp);
00773     return;
00774   }
00775 
00776   // Topology compatibility check.
00777   if (x.is_necessarily_closed()) {
00778     if (!y.is_necessarily_closed())
00779       throw_topology_incompatible("limited_BHRZ03_extrapolation_assign(y, cs)",
00780                                   "y", y);
00781     if (cs.has_strict_inequalities())
00782       throw_topology_incompatible("limited_BHRZ03_extrapolation_assign(y, cs)",
00783                                   "cs", cs);
00784   }
00785   else if (y.is_necessarily_closed())
00786     throw_topology_incompatible("limited_BHRZ03_extrapolation_assign(y, cs)",
00787                                 "y", y);
00788 
00789   // Dimension-compatibility check.
00790   if (x.space_dim != y.space_dim)
00791     throw_dimension_incompatible("limited_BHRZ03_extrapolation_assign(y, cs)",
00792                                  "y", y);
00793   // `cs' must be dimension-compatible with the two polyhedra.
00794   const dimension_type cs_space_dim = cs.space_dimension();
00795   if (x.space_dim < cs_space_dim)
00796     throw_dimension_incompatible("limited_BHRZ03_extrapolation_assign(y, cs)",
00797                                  "cs", cs);
00798 
00799 #ifndef NDEBUG
00800   {
00801     // We assume that y is contained in or equal to x.
00802     const Polyhedron x_copy = x;
00803     const Polyhedron y_copy = y;
00804     assert(x_copy.contains(y_copy));
00805   }
00806 #endif
00807 
00808   if (y.marked_empty())
00809     return;
00810   if (x.marked_empty())
00811     return;
00812 
00813   // The limited BHRZ03-widening between two polyhedra in a
00814   // zero-dimensional space is a polyhedron in a zero-dimensional
00815   // space, too.
00816   if (x.space_dim == 0)
00817     return;
00818 
00819   if (!y.minimize())
00820     // We have just discovered that `y' is empty.
00821     return;
00822 
00823   // Update the generators of `x': these are used to select,
00824   // from the constraints in `cs', those that must be added
00825   // to the resulting polyhedron.
00826   if ((x.has_pending_constraints() && !x.process_pending_constraints())
00827       || (!x.generators_are_up_to_date() && !x.update_generators()))
00828     // We have just discovered that `x' is empty.
00829     return;
00830 
00831   Constraint_System new_cs;
00832   // The constraints to be added must be satisfied by all the
00833   // generators of `x'. We can disregard `y' because `y <= x'.
00834   const Generator_System& x_gen_sys = x.gen_sys;
00835   // Iterate upwards here so as to keep the relative ordering of constraints.
00836   // Not really an issue: just aesthetics.
00837   for (dimension_type i = 0; i < cs_num_rows; ++i) {
00838     const Constraint& c = cs[i];
00839     if (x_gen_sys.satisfied_by_all_generators(c))
00840       new_cs.insert(c);
00841   }
00842   x.BHRZ03_widening_assign(y, tp);
00843   x.add_constraints(new_cs);
00844   assert(OK());
00845 }

void Parma_Polyhedra_Library::Polyhedron::bounded_BHRZ03_extrapolation_assign ( const Polyhedron y,
const Constraint_System cs,
unsigned *  tp = 0 
)

Improves the result of the BHRZ03-widening computation by also enforcing those constraints in cs that are satisfied by all the points of *this, plus all the constraints of the form $\pm x \leq r$ and $\pm x < r$, with $r \in \Qset$, that are satisfied by all the points of *this.

Parameters:
y A polyhedron that must be contained in *this;
cs The system of constraints used to improve the widened polyhedron;
tp An optional pointer to an unsigned variable storing the number of available tokens (to be used when applying the widening with tokens delay technique).
Exceptions:
std::invalid_argument Thrown if *this, y and cs are topology-incompatible or dimension-incompatible.

Definition at line 849 of file Polyhedron_widenings.cc.

References add_constraints(), Parma_Polyhedra_Library::ANY_COMPLEXITY, Parma_Polyhedra_Library::Bounding_Box::CC76_widening_assign(), Parma_Polyhedra_Library::Bounding_Box::constraints(), limited_BHRZ03_extrapolation_assign(), shrink_bounding_box(), space_dim, and space_dimension().

Referenced by ppl_Polyhedron_bounded_BHRZ03_extrapolation_assign_with_tokens().

00851                                                     {
00852   const dimension_type space_dim = space_dimension();
00853   Bounding_Box x_box(space_dim);
00854   Bounding_Box y_box(space_dim);
00855   shrink_bounding_box(x_box, ANY_COMPLEXITY);
00856   y.shrink_bounding_box(y_box, ANY_COMPLEXITY);
00857   x_box.CC76_widening_assign(y_box);
00858   limited_BHRZ03_extrapolation_assign(y, cs, tp);
00859   // TODO: see if some copies can be avoided.
00860   // add_recycled_constraints(x_box.constraints());
00861   add_constraints(x_box.constraints());
00862 }

void Parma_Polyhedra_Library::Polyhedron::H79_widening_assign ( const Polyhedron y,
unsigned *  tp = 0 
)

Assigns to *this the result of computing the H79-widening between *this and y.

Parameters:
y A polyhedron that must be contained in *this;
tp An optional pointer to an unsigned variable storing the number of available tokens (to be used when applying the widening with tokens delay technique).
Exceptions:
std::invalid_argument Thrown if *this and y are topology-incompatible or dimension-incompatible.

Definition at line 146 of file Polyhedron_widenings.cc.

References add_recycled_constraints(), con_sys, constraints_are_up_to_date(), contains(), has_pending_generators(), intersection_assign_and_minimize(), is_necessarily_closed(), marked_empty(), minimize(), Parma_Polyhedra_Library::Constraint_System::num_equalities(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), process_pending_generators(), select_CH78_constraints(), select_H79_constraints(), space_dim, throw_dimension_incompatible(), throw_topology_incompatible(), topology(), Parma_Polyhedra_Library::UNIVERSE, and update_constraints().

Referenced by Parma_Polyhedra_Library::BD_Shape< T >::H79_widening_assign(), limited_H79_extrapolation_assign(), and ppl_Polyhedron_H79_widening_assign_with_tokens().

00146                                                                     {
00147   Polyhedron& x = *this;
00148   // Topology compatibility check.
00149   const Topology tpl = x.topology();
00150   if (tpl != y.topology())
00151     throw_topology_incompatible("H79_widening_assign(y)", "y", y);
00152   // Dimension-compatibility check.
00153   if (x.space_dim != y.space_dim)
00154     throw_dimension_incompatible("H79_widening_assign(y)", "y", y);
00155 
00156 #ifndef NDEBUG
00157   {
00158     // We assume that y is contained in or equal to x.
00159     const Polyhedron x_copy = x;
00160     const Polyhedron y_copy = y;
00161     assert(x_copy.contains(y_copy));
00162   }
00163 #endif
00164 
00165   // If any argument is zero-dimensional or empty,
00166   // the H79-widening behaves as the identity function.
00167   if (x.space_dim == 0 || x.marked_empty() || y.marked_empty())
00168     return;
00169 
00170   // `y.gen_sys' should be in minimal form and
00171   // `y.sat_g' should be up-to-date.
00172   if (y.is_necessarily_closed()) {
00173     if (!y.minimize())
00174       // `y' is empty: the result is `x'.
00175       return;
00176   }
00177   else {
00178     // Dealing with a NNC polyhedron.
00179     // To obtain a correct reasoning when comparing
00180     // the constraints of `x' with the generators of `y',
00181     // we enforce the inclusion relation holding between
00182     // the two NNC polyhedra `x' and `y' (i.e., `y <= x')
00183     // to also hold for the corresponding eps-representations:
00184     // this is obtained by intersecting the two eps-representations.
00185     Polyhedron& yy = const_cast<Polyhedron&>(y);
00186     if (!yy.intersection_assign_and_minimize(x))
00187       // `y' is empty: the result is `x'.
00188       return;
00189   }
00190 
00191   // If we only have the generators of `x' and the dimensions of
00192   // the two polyhedra are the same, we can compute the standard
00193   // widening by using the specification in CousotH78, therefore
00194   // avoiding converting from generators to constraints.
00195   if (x.has_pending_generators() || !x.constraints_are_up_to_date()) {
00196     Constraint_System CH78_cs(tpl);
00197     x.select_CH78_constraints(y, CH78_cs);
00198 
00199     if (CH78_cs.num_rows() == y.con_sys.num_rows()) {
00200       // Having selected all the constraints, the result is `y'.
00201       x = y;
00202       return;
00203     }
00204     // Otherwise, check if `x' and `y' have the same dimension.
00205     // Note that `y.con_sys' is minimized and `CH78_cs' has no redundant
00206     // constraints, since it is a subset of the former.
00207     else if (CH78_cs.num_equalities() == y.con_sys.num_equalities()) {
00208       // Let `x' be defined by the constraints in `CH78_cs'.
00209       Polyhedron CH78(tpl, x.space_dim, UNIVERSE);
00210       CH78.add_recycled_constraints(CH78_cs);
00211 
00212       // Check whether we are using the widening-with-tokens technique
00213       // and there still are tokens available.
00214       if (tp != 0 && *tp > 0) {
00215         // There are tokens available. If `CH78' is not a subset of `x',
00216         // then it is less precise and we use one of the available tokens.
00217         if (!x.contains(CH78))
00218           --(*tp);
00219       }
00220       else
00221         // No tokens.
00222         std::swap(x, CH78);
00223       assert(x.OK(true));
00224       return;
00225     }
00226   }
00227 
00228   // As the dimension of `x' is strictly greater than the dimension of `y',
00229   // we have to compute the standard widening by selecting a subset of
00230   // the constraints of `x'.
00231   // `x.con_sys' is just required to be up-to-date, because:
00232   // - if `x.con_sys' is unsatisfiable, then by assumption
00233   //   also `y' is empty, so that the resulting polyhedron is `x';
00234   // - redundant constraints in `x.con_sys' do not affect the result
00235   //   of the widening, because if they are selected they will be
00236   //   redundant even in the result.
00237   if (has_pending_generators())
00238     process_pending_generators();
00239   else if (!x.constraints_are_up_to_date())
00240     x.update_constraints();
00241 
00242   // Copy into `H79_cs' the constraints of `x' that are common to `y',
00243   // according to the definition of the H79 widening.
00244   Constraint_System H79_cs(tpl);
00245   Constraint_System x_minus_H79_cs(tpl);
00246   x.select_H79_constraints(y, H79_cs, x_minus_H79_cs);
00247 
00248   if (x_minus_H79_cs.num_rows() == 0)
00249     // We selected all of the constraints of `x',
00250     // thus the result of the widening is `x'.
00251     return;
00252   else {
00253     // We selected a strict subset of the constraints of `x'.
00254     // NOTE: as `x.con_sys' was not necessarily in minimal form,
00255     // this does not imply that the result strictly includes `x'.
00256     // Let `H79' be defined by the constraints in `H79_cs'.
00257     Polyhedron H79(tpl, x.space_dim, UNIVERSE);
00258     H79.add_recycled_constraints(H79_cs);
00259 
00260     // Check whether we are using the widening-with-tokens technique
00261     // and there still are tokens available.
00262     if (tp != 0 && *tp > 0) {
00263       // There are tokens available. If `H79' is not a subset of `x',
00264       // then it is less precise and we use one of the available tokens.
00265       if (!x.contains(H79))
00266         --(*tp);
00267     }
00268     else
00269       // No tokens.
00270       std::swap(x, H79);
00271     assert(x.OK(true));
00272   }
00273 }

void Parma_Polyhedra_Library::Polyhedron::limited_H79_extrapolation_assign ( const Polyhedron y,
const Constraint_System cs,
unsigned *  tp = 0 
)

Improves the result of the H79-widening computation by also enforcing those constraints in cs that are satisfied by all the points of *this.

Parameters:
y A polyhedron that must be contained in *this;
cs The system of constraints used to improve the widened polyhedron;
tp An optional pointer to an unsigned variable storing the number of available tokens (to be used when applying the widening with tokens delay technique).
Exceptions:
std::invalid_argument Thrown if *this, y and cs are topology-incompatible or dimension-incompatible.

Definition at line 276 of file Polyhedron_widenings.cc.

References add_constraints(), contains(), gen_sys, generators_are_up_to_date(), H79_widening_assign(), has_pending_constraints(), Parma_Polyhedra_Library::Constraint_System::has_strict_inequalities(), Parma_Polyhedra_Library::Constraint_System::insert(), is_necessarily_closed(), marked_empty(), minimize(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), process_pending_constraints(), Parma_Polyhedra_Library::Generator_System::satisfied_by_all_generators(), space_dim, Parma_Polyhedra_Library::Constraint_System::space_dimension(), throw_dimension_incompatible(), throw_topology_incompatible(), and update_generators().

Referenced by bounded_H79_extrapolation_assign(), Parma_Polyhedra_Library::BD_Shape< T >::limited_H79_extrapolation_assign(), and ppl_Polyhedron_limited_H79_extrapolation_assign_with_tokens().

00278                                                                 {
00279   Polyhedron& x = *this;
00280 
00281   const dimension_type cs_num_rows = cs.num_rows();
00282   // If `cs' is empty, we fall back to ordinary, non-limited widening.
00283   if (cs_num_rows == 0) {
00284     x.H79_widening_assign(y, tp);
00285     return;
00286   }
00287 
00288   // Topology compatibility check.
00289   if (x.is_necessarily_closed()) {
00290     if (!y.is_necessarily_closed())
00291       throw_topology_incompatible("limited_H79_extrapolation_assign(y, cs)",
00292                                   "y", y);
00293     if (cs.has_strict_inequalities())
00294       throw_topology_incompatible("limited_H79_extrapolation_assign(y, cs)",
00295                                   "cs", cs);
00296   }
00297   else if (y.is_necessarily_closed())
00298     throw_topology_incompatible("limited_H79_extrapolation_assign(y, cs)",
00299                                 "y", y);
00300 
00301   // Dimension-compatibility check.
00302   if (x.space_dim != y.space_dim)
00303     throw_dimension_incompatible("limited_H79_extrapolation_assign(y, cs)",
00304                                  "y", y);
00305   // `cs' must be dimension-compatible with the two polyhedra.
00306   const dimension_type cs_space_dim = cs.space_dimension();
00307   if (x.space_dim < cs_space_dim)
00308     throw_dimension_incompatible("limited_H79_extrapolation_assign(y, cs)",
00309                                  "cs", cs);
00310 
00311 #ifndef NDEBUG
00312   {
00313     // We assume that y is contained in or equal to x.
00314     const Polyhedron x_copy = x;
00315     const Polyhedron y_copy = y;
00316     assert(x_copy.contains(y_copy));
00317   }
00318 #endif
00319 
00320   if (y.marked_empty())
00321     return;
00322   if (x.marked_empty())
00323     return;
00324 
00325   // The limited H79-widening between two polyhedra in a
00326   // zero-dimensional space is a polyhedron in a zero-dimensional
00327   // space, too.
00328   if (x.space_dim == 0)
00329     return;
00330 
00331   if (!y.minimize())
00332     // We have just discovered that `y' is empty.
00333     return;
00334 
00335   // Update the generators of `x': these are used to select,
00336   // from the constraints in `cs', those that must be added
00337   // to the resulting polyhedron.
00338   if ((x.has_pending_constraints() && !x.process_pending_constraints())
00339       || (!x.generators_are_up_to_date() && !x.update_generators()))
00340     // We have just discovered that `x' is empty.
00341     return;
00342 
00343   Constraint_System new_cs;
00344   // The constraints to be added must be satisfied by all the
00345   // generators of `x'.  We can disregard `y' because `y <= x'.
00346   const Generator_System& x_gen_sys = x.gen_sys;
00347   // Iterate upwards here so as to keep the relative ordering of constraints.
00348   // Not really an issue: just aesthetics.
00349   for (dimension_type i = 0; i < cs_num_rows; ++i) {
00350     const Constraint& c = cs[i];
00351     if (x_gen_sys.satisfied_by_all_generators(c))
00352       new_cs.insert(c);
00353   }
00354   x.H79_widening_assign(y, tp);
00355   x.add_constraints(new_cs);
00356   assert(OK());
00357 }

void Parma_Polyhedra_Library::Polyhedron::bounded_H79_extrapolation_assign ( const Polyhedron y,
const Constraint_System cs,
unsigned *  tp = 0 
)

Improves the result of the H79-widening computation by also enforcing those constraints in cs that are satisfied by all the points of *this, plus all the constraints of the form $\pm x \leq r$ and $\pm x < r$, with $r \in \Qset$, that are satisfied by all the points of *this.

Parameters:
y A polyhedron that must be contained in *this;
cs The system of constraints used to improve the widened polyhedron;
tp An optional pointer to an unsigned variable storing the number of available tokens (to be used when applying the widening with tokens delay technique).
Exceptions:
std::invalid_argument Thrown if *this, y and cs are topology-incompatible or dimension-incompatible.

Definition at line 360 of file Polyhedron_widenings.cc.

References add_constraints(), Parma_Polyhedra_Library::ANY_COMPLEXITY, Parma_Polyhedra_Library::Bounding_Box::CC76_widening_assign(), Parma_Polyhedra_Library::Bounding_Box::constraints(), limited_H79_extrapolation_assign(), shrink_bounding_box(), space_dim, and space_dimension().

Referenced by ppl_Polyhedron_bounded_H79_extrapolation_assign_with_tokens().

00362                                                                 {
00363   const dimension_type space_dim = space_dimension();
00364   Bounding_Box x_box(space_dim);
00365   Bounding_Box y_box(space_dim);
00366   shrink_bounding_box(x_box, ANY_COMPLEXITY);
00367   y.shrink_bounding_box(y_box, ANY_COMPLEXITY);
00368   x_box.CC76_widening_assign(y_box);
00369   limited_H79_extrapolation_assign(y, cs, tp);
00370   // TODO: see if some copies can be avoided.
00371   // add_recycled_constraints(x_box.constraints());
00372   add_constraints(x_box.constraints());
00373 }

void Parma_Polyhedra_Library::Polyhedron::add_space_dimensions_and_embed ( dimension_type  m  ) 

Adds m new space dimensions and embeds the old polyhedron in the new vector space.

Parameters:
m The number of dimensions to add.
Exceptions:
std::length_error Thrown if adding m new space dimensions would cause the vector space to exceed dimension max_space_dimension().
The new space dimensions will be those having the highest indexes in the new polyhedron, which is characterized by a system of constraints in which the variables running through the new dimensions are not constrained. For instance, when starting from the polyhedron $\cP \sseq \Rset^2$ and adding a third space dimension, the result will be the polyhedron

\[ \bigl\{\, (x, y, z)^\transpose \in \Rset^3 \bigm| (x, y)^\transpose \in \cP \,\bigr\}. \]

Definition at line 90 of file Polyhedron_chdims.cc.

References Parma_Polyhedra_Library::Linear_System::add_rows_and_columns(), add_space_dimensions(), Parma_Polyhedra_Library::Matrix::add_zero_columns(), Parma_Polyhedra_Library::Constraint_System::clear(), con_sys, constraints_are_up_to_date(), gen_sys, generators_are_up_to_date(), is_necessarily_closed(), Parma_Polyhedra_Library::Linear_System::is_sorted(), marked_empty(), max_space_dimension(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), sat_c, sat_c_is_up_to_date(), sat_g, space_dim, space_dimension(), status, swap(), Parma_Polyhedra_Library::Matrix::swap_columns(), Parma_Polyhedra_Library::Polyhedron::Status::test_zero_dim_univ(), throw_space_dimension_overflow(), topology(), Parma_Polyhedra_Library::UNIVERSE, Parma_Polyhedra_Library::Linear_System::unset_pending_rows(), and update_sat_c().

Referenced by bounded_affine_image(), bounded_affine_preimage(), expand_space_dimension(), generalized_affine_image(), generalized_affine_preimage(), and ppl_Polyhedron_add_space_dimensions_and_embed().

00090                                                               {
00091   // The space dimension of the resulting polyhedron should not
00092   // overflow the maximum allowed space dimension.
00093   if (m > max_space_dimension() - space_dimension())
00094     throw_space_dimension_overflow(topology(),
00095                                    "add_space_dimensions_and_embed(m)",
00096                                    "adding m new space dimensions exceeds "
00097                                    "the maximum allowed space dimension");
00098 
00099   // Adding no dimensions to any polyhedron is a no-op.
00100   if (m == 0)
00101     return;
00102 
00103   // Adding dimensions to an empty polyhedron is obtained by adjusting
00104   // `space_dim' and clearing `con_sys' (since it can contain the
00105   // unsatisfiable constraint system of the wrong dimension).
00106   if (marked_empty()) {
00107     space_dim += m;
00108     con_sys.clear();
00109     return;
00110   }
00111 
00112   // The case of a zero-dimensional space polyhedron.
00113   if (space_dim == 0) {
00114     // Since it is not empty, it has to be the universe polyhedron.
00115     assert(status.test_zero_dim_univ());
00116     // We swap `*this' with a newly created
00117     // universe polyhedron of dimension `m'.
00118     Polyhedron ph(topology(), m, UNIVERSE);
00119     swap(ph);
00120     return;
00121   }
00122 
00123   // To embed an n-dimension space polyhedron in a (n+m)-dimension space,
00124   // we just add `m' zero-columns to the rows in the system of constraints;
00125   // in contrast, the system of generators needs additional rows,
00126   // corresponding to the vectors of the canonical basis
00127   // for the added dimensions. That is, for each new dimension `x[k]'
00128   // we add the line having that direction. This is done by invoking
00129   // the function add_space_dimensions() giving the system of generators
00130   // as the second argument.
00131   if (constraints_are_up_to_date())
00132     if (generators_are_up_to_date()) {
00133       // `sat_c' must be up to date for add_space_dimensions(...).
00134       if (!sat_c_is_up_to_date())
00135         update_sat_c();
00136       // Adds rows and/or columns to both matrices.
00137       // `add_space_dimensions' correctly handles pending constraints
00138       // or generators.
00139       add_space_dimensions(con_sys, gen_sys, sat_c, sat_g, m);
00140     }
00141     else {
00142       // Only constraints are up-to-date: no need to modify the generators.
00143       con_sys.add_zero_columns(m);
00144       // If the polyhedron is not necessarily closed,
00145       // move the epsilon coefficients to the last column.
00146       if (!is_necessarily_closed())
00147         con_sys.swap_columns(space_dim + 1, space_dim + 1 + m);
00148     }
00149   else {
00150     // Only generators are up-to-date: no need to modify the constraints.
00151     assert(generators_are_up_to_date());
00152     gen_sys.add_rows_and_columns(m);
00153     // The polyhedron does not support pending generators.
00154     gen_sys.unset_pending_rows();
00155     // If the polyhedron is not necessarily closed,
00156     // move the epsilon coefficients to the last column.
00157     if (!is_necessarily_closed()) {
00158       // Try to preserve sortedness of `gen_sys'.
00159       if (!gen_sys.is_sorted())
00160         gen_sys.swap_columns(space_dim + 1, space_dim + 1 + m);
00161       else {
00162         dimension_type old_eps_index = space_dim + 1;
00163         dimension_type new_eps_index = old_eps_index + m;
00164         for (dimension_type i = gen_sys.num_rows(); i-- > m; ) {
00165           Generator& r = gen_sys[i];
00166           std::swap(r[old_eps_index], r[new_eps_index]);
00167         }
00168         // The upper-right corner of `gen_sys' contains the J matrix:
00169         // swap coefficients to preserve sortedness.
00170         for (dimension_type i = m; i-- > 0; ++old_eps_index) {
00171           Generator& r = gen_sys[i];
00172           std::swap(r[old_eps_index], r[old_eps_index + 1]);
00173         }
00174       }
00175     }
00176   }
00177   // Update the space dimension.
00178   space_dim += m;
00179 
00180   // Note: we do not check for satisfiability, because the system of
00181   // constraints may be unsatisfiable.
00182   assert(OK());
00183 }

void Parma_Polyhedra_Library::Polyhedron::add_space_dimensions_and_project ( dimension_type  m  ) 

Adds m new space dimensions to the polyhedron and does not embed it in the new vector space.

Parameters:
m The number of space dimensions to add.
Exceptions:
std::length_error Thrown if adding m new space dimensions would cause the vector space to exceed dimension max_space_dimension().
The new space dimensions will be those having the highest indexes in the new polyhedron, which is characterized by a system of constraints in which the variables running through the new dimensions are all constrained to be equal to 0. For instance, when starting from the polyhedron $\cP \sseq \Rset^2$ and adding a third space dimension, the result will be the polyhedron

\[ \bigl\{\, (x, y, 0)^\transpose \in \Rset^3 \bigm| (x, y)^\transpose \in \cP \,\bigr\}. \]

Definition at line 186 of file Polyhedron_chdims.cc.

References Parma_Polyhedra_Library::Linear_System::add_rows_and_columns(), add_space_dimensions(), Parma_Polyhedra_Library::Matrix::add_zero_columns(), Parma_Polyhedra_Library::Generator_System::adjust_topology_and_space_dimension(), Parma_Polyhedra_Library::Constraint_System::clear(), con_sys, constraints_are_up_to_date(), gen_sys, generators_are_up_to_date(), Parma_Polyhedra_Library::Generator_System::insert(), is_necessarily_closed(), Parma_Polyhedra_Library::Linear_System::is_sorted(), marked_empty(), max_space_dimension(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), sat_c, sat_g, sat_g_is_up_to_date(), set_generators_minimized(), space_dim, space_dimension(), status, Parma_Polyhedra_Library::Matrix::swap_columns(), Parma_Polyhedra_Library::Polyhedron::Status::test_zero_dim_univ(), throw_space_dimension_overflow(), topology(), Parma_Polyhedra_Library::Linear_System::unset_pending_rows(), update_sat_g(), Parma_Polyhedra_Library::Generator::zero_dim_closure_point(), and Parma_Polyhedra_Library::Generator::zero_dim_point().

Referenced by ppl_Polyhedron_add_space_dimensions_and_project().

00186                                                                 {
00187   // The space dimension of the resulting polyhedron should not
00188   // overflow the maximum allowed space dimension.
00189   if (m > max_space_dimension() - space_dimension())
00190     throw_space_dimension_overflow(topology(),
00191                                    "add_space_dimensions_and_project(m)",
00192                                    "adding m new space dimensions exceeds "
00193                                    "the maximum allowed space dimension");
00194 
00195   // Adding no dimensions to any polyhedron is a no-op.
00196   if (m == 0)
00197     return;
00198 
00199   // Adding dimensions to an empty polyhedron is obtained
00200   // by merely adjusting `space_dim'.
00201   if (marked_empty()) {
00202     space_dim += m;
00203     con_sys.clear();
00204     return;
00205   }
00206 
00207   if (space_dim == 0) {
00208     assert(status.test_zero_dim_univ() && gen_sys.num_rows() == 0);
00209     // The system of generators for this polyhedron has only
00210     // the origin as a point.
00211     // In an NNC polyhedron, all points have to be accompanied
00212     // by the corresponding closure points
00213     // (this time, dimensions are automatically adjusted).
00214     if (!is_necessarily_closed())
00215       gen_sys.insert(Generator::zero_dim_closure_point());
00216     gen_sys.insert(Generator::zero_dim_point());
00217     gen_sys.adjust_topology_and_space_dimension(topology(), m);
00218     set_generators_minimized();
00219     space_dim = m;
00220     assert(OK());
00221     return;
00222   }
00223 
00224   // To project an n-dimension space polyhedron in a (n+m)-dimension space,
00225   // we just add to the system of generators `m' zero-columns;
00226   // In contrast, in the system of constraints, new rows are needed
00227   // in order to avoid embedding the old polyhedron in the new space.
00228   // Thus, for each new dimensions `x[k]', we add the constraint
00229   // x[k] = 0; this is done by invoking the function add_space_dimensions()
00230   // giving the system of constraints as the second argument.
00231   if (constraints_are_up_to_date())
00232     if (generators_are_up_to_date()) {
00233       // `sat_g' must be up to date for add_space_dimensions(...).
00234       if (!sat_g_is_up_to_date())
00235         update_sat_g();
00236       // Adds rows and/or columns to both matrices.
00237       // `add_space_dimensions' correctly handles pending constraints
00238       // or generators.
00239       add_space_dimensions(gen_sys, con_sys, sat_g, sat_c, m);
00240     }
00241     else {
00242       // Only constraints are up-to-date: no need to modify the generators.
00243       con_sys.add_rows_and_columns(m);
00244       // The polyhedron does not support pending constraints.
00245       con_sys.unset_pending_rows();
00246       // If the polyhedron is not necessarily closed,
00247       // move the epsilon coefficients to the last column.
00248       if (!is_necessarily_closed()) {
00249         // Try to preserve sortedness of `con_sys'.
00250         if (!con_sys.is_sorted())
00251           con_sys.swap_columns(space_dim + 1, space_dim + 1 + m);
00252         else {
00253           dimension_type old_eps_index = space_dim + 1;
00254           dimension_type new_eps_index = old_eps_index + m;
00255           for (dimension_type i = con_sys.num_rows(); i-- > m; ) {
00256             Constraint& r = con_sys[i];
00257             std::swap(r[old_eps_index], r[new_eps_index]);
00258           }
00259           // The upper-right corner of `con_sys' contains the J matrix:
00260           // swap coefficients to preserve sortedness.
00261           for (dimension_type i = m; i-- > 0; ++old_eps_index) {
00262             Constraint& r = con_sys[i];
00263             std::swap(r[old_eps_index], r[old_eps_index + 1]);
00264           }
00265         }
00266       }
00267     }
00268   else {
00269     // Only generators are up-to-date: no need to modify the constraints.
00270     assert(generators_are_up_to_date());
00271     gen_sys.add_zero_columns(m);
00272     // If the polyhedron is not necessarily closed,
00273     // move the epsilon coefficients to the last column.
00274     if (!is_necessarily_closed())
00275       gen_sys.swap_columns(space_dim + 1, space_dim + 1 + m);
00276   }
00277   // Now we update the space dimension.
00278   space_dim += m;
00279 
00280   // Note: we do not check for satisfiability, because the system of
00281   // constraints may be unsatisfiable.
00282   assert(OK());
00283 }

void Parma_Polyhedra_Library::Polyhedron::concatenate_assign ( const Polyhedron y  ) 

Assigns to *this the concatenation of *this and y, taken in this order.

Exceptions:
std::invalid_argument Thrown if *this and y are topology-incompatible.
std::length_error Thrown if the concatenation would cause the vector space to exceed dimension max_space_dimension().

Definition at line 286 of file Polyhedron_chdims.cc.

References Parma_Polyhedra_Library::Linear_System::add_rows_and_columns(), Parma_Polyhedra_Library::Matrix::add_zero_rows_and_columns(), can_have_something_pending(), clear_constraints_minimized(), clear_generators_up_to_date(), clear_sat_c_up_to_date(), clear_sat_g_up_to_date(), con_sys, constraints(), constraints_are_up_to_date(), gen_sys, has_pending_generators(), Parma_Polyhedra_Library::Constraint::is_equality(), is_necessarily_closed(), marked_empty(), max_space_dimension(), Parma_Polyhedra_Library::Saturation_Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Saturation_Matrix::num_rows(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), process_pending_generators(), Parma_Polyhedra_Library::Linear_Row::RAY_OR_POINT_OR_INEQUALITY, Parma_Polyhedra_Library::Saturation_Matrix::resize(), sat_c, sat_c_is_up_to_date(), sat_g, set_constraints_pending(), set_empty(), Parma_Polyhedra_Library::Constraint::set_is_equality(), set_sat_c_up_to_date(), Parma_Polyhedra_Library::Linear_System::set_sorted(), Parma_Polyhedra_Library::Linear_System::sort_rows(), space_dim, space_dimension(), Parma_Polyhedra_Library::Matrix::swap_columns(), throw_space_dimension_overflow(), throw_topology_incompatible(), topology(), Parma_Polyhedra_Library::Saturation_Matrix::transpose_assign(), Parma_Polyhedra_Library::Linear_System::unset_pending_rows(), and update_constraints().

Referenced by ppl_Polyhedron_concatenate_assign().

00286                                                      {
00287   if (topology() != y.topology())
00288     throw_topology_incompatible("concatenate_assign(y)", "y", y);
00289 
00290   // The space dimension of the resulting polyhedron should not
00291   // overflow the maximum allowed space dimension.
00292   if (y.space_dim > max_space_dimension() - space_dimension())
00293     throw_space_dimension_overflow(topology(),
00294                                    "concatenate_assign(y)",
00295                                    "concatenation exceeds the maximum "
00296                                    "allowed space dimension");
00297 
00298   const dimension_type added_columns = y.space_dim;
00299 
00300   // If `*this' or `y' are empty polyhedra, it is sufficient to adjust
00301   // the dimension of the space.
00302   if (marked_empty() || y.marked_empty()) {
00303     space_dim += added_columns;
00304     set_empty();
00305     return;
00306   }
00307 
00308   // If `y' is a non-empty 0-dim space polyhedron, the result is `*this'.
00309   if (added_columns == 0)
00310     return;
00311 
00312   // If `*this' is a non-empty 0-dim space polyhedron, the result is `y'.
00313   if (space_dim == 0) {
00314     *this = y;
00315     return;
00316   }
00317 
00318   // TODO: this implementation is just an executable specification.
00319   Constraint_System cs = y.constraints();
00320 
00321   // The constraints of `x' (possibly with pending rows) are required.
00322   if (has_pending_generators())
00323     process_pending_generators();
00324   else if (!constraints_are_up_to_date())
00325     update_constraints();
00326 
00327   // The matrix for the new system of constraints is obtained
00328   // by leaving the old system of constraints in the upper left-hand side
00329   // and placing the constraints of `cs' in the lower right-hand side.
00330   // NOTE: here topologies agree, whereas dimensions may not agree.
00331   dimension_type old_num_rows = con_sys.num_rows();
00332   dimension_type old_num_columns = con_sys.num_columns();
00333   dimension_type added_rows = cs.num_rows();
00334 
00335   // We already dealt with the cases of an empty or zero-dim `y' polyhedron;
00336   // also, `cs' contains the low-level constraints, at least.
00337   assert(added_rows > 0 && added_columns > 0);
00338 
00339   con_sys.add_zero_rows_and_columns(added_rows, added_columns,
00340                                     Linear_Row::Flags(topology(),
00341                                                       Linear_Row::RAY_OR_POINT_OR_INEQUALITY));
00342   // Move the epsilon coefficient to the last column, if needed.
00343   if (!is_necessarily_closed())
00344     con_sys.swap_columns(old_num_columns - 1,
00345                          old_num_columns - 1 + added_columns);
00346   dimension_type cs_num_columns = cs.num_columns();
00347   // Steal the constraints from `cs' and put them in `con_sys'
00348   // using the right displacement for coefficients.
00349   for (dimension_type i = added_rows; i-- > 0; ) {
00350     Constraint& c_old = cs[i];
00351     Constraint& c_new = con_sys[old_num_rows + i];
00352     // Method `add_zero_rows_and_columns', by default, added
00353     // inequalities.
00354     if (c_old.is_equality())
00355       c_new.set_is_equality();
00356     // The inhomogeneous term is not displaced.
00357     std::swap(c_new[0], c_old[0]);
00358     // All homogeneous terms (included the epsilon coefficient,
00359     // if present) are displaced by `space_dim' columns.
00360     for (dimension_type j = 1; j < cs_num_columns; ++j)
00361       std::swap(c_old[j], c_new[space_dim + j]);
00362   }
00363 
00364   if (can_have_something_pending()) {
00365     // If `*this' can support pending constraints, then, since we have
00366     // resized the system of constraints, we must also add to the generator
00367     // system those lines corresponding to the newly added dimensions,
00368     // because the non-pending parts of `con_sys' and `gen_sys' must still
00369     // be a DD pair in minimal form.
00370     gen_sys.add_rows_and_columns(added_columns);
00371     gen_sys.set_sorted(false);
00372     if (!is_necessarily_closed())
00373       gen_sys.swap_columns(old_num_columns - 1,
00374                            old_num_columns - 1 + added_columns);
00375     // The added lines are not pending.
00376     gen_sys.unset_pending_rows();
00377     // Since we added new lines at the beginning of `x.gen_sys',
00378     // we also have to adjust the saturation matrix `sat_c'.
00379     // FIXME: if `sat_c' is not up-to-date, couldn't we directly update
00380     // `sat_g' by resizing it and shifting its columns?
00381     if (!sat_c_is_up_to_date()) {
00382       sat_c.transpose_assign(sat_g);
00383       set_sat_c_up_to_date();
00384     }
00385     clear_sat_g_up_to_date();
00386     sat_c.resize(sat_c.num_rows() + added_columns, sat_c.num_columns());
00387     // The old saturation rows are copied at the end of the matrix.
00388     // The newly introduced lines saturate all the non-pending constraints,
00389     // thus their saturation rows are made of zeroes.
00390     for (dimension_type i = sat_c.num_rows() - added_columns; i-- > 0; )
00391       std::swap(sat_c[i], sat_c[i+added_columns]);
00392     // Since `added_rows > 0', we now have pending constraints.
00393     set_constraints_pending();
00394   }
00395   else {
00396     // The polyhedron cannot have pending constraints.
00397     con_sys.unset_pending_rows();
00398 #if BE_LAZY
00399     con_sys.set_sorted(false);
00400 #else
00401     con_sys.sort_rows();
00402 #endif
00403     clear_constraints_minimized();
00404     clear_generators_up_to_date();
00405     clear_sat_g_up_to_date();
00406     clear_sat_c_up_to_date();
00407   }
00408   // Update space dimension.
00409   space_dim += added_columns;
00410 
00411   // The system of constraints may be unsatisfiable,
00412   // thus we do not check for satisfiability.
00413   assert(OK());
00414 }

void Parma_Polyhedra_Library::Polyhedron::remove_space_dimensions ( const Variables_Set to_be_removed  ) 

Removes all the specified dimensions from the vector space.

Parameters:
to_be_removed The set of Variable objects corresponding to the space dimensions to be removed.
Exceptions:
std::invalid_argument Thrown if *this is dimension-incompatible with one of the Variable objects contained in to_be_removed.

Definition at line 417 of file Polyhedron_chdims.cc.

References Parma_Polyhedra_Library::Constraint_System::clear(), clear_constraints_up_to_date(), clear_generators_minimized(), con_sys, gen_sys, generators_are_up_to_date(), has_something_pending(), marked_empty(), Parma_Polyhedra_Library::Matrix::num_columns(), OK(), Parma_Polyhedra_Library::Generator_System::remove_invalid_lines_and_rays(), remove_pending_to_obtain_generators(), Parma_Polyhedra_Library::Linear_System::remove_trailing_columns(), set_zero_dim_univ(), space_dim, throw_dimension_incompatible(), and update_generators().

Referenced by fold_space_dimensions(), and ppl_Polyhedron_remove_space_dimensions().

00417                                                                          {
00418   // The removal of no dimensions from any polyhedron is a no-op.
00419   // Note that this case also captures the only legal removal of
00420   // dimensions from a polyhedron in a 0-dim space.
00421   if (to_be_removed.empty()) {
00422     assert(OK());
00423     return;
00424   }
00425 
00426   // Dimension-compatibility check: the variable having
00427   // maximum space dimension is the one occurring last in the set.
00428   const dimension_type
00429     min_space_dim = to_be_removed.rbegin()->space_dimension();
00430   if (space_dim < min_space_dim)
00431     throw_dimension_incompatible("remove_space_dimensions(vs)", min_space_dim);
00432 
00433   const dimension_type new_space_dim = space_dim - to_be_removed.size();
00434 
00435   // We need updated generators; note that keeping pending generators
00436   // is useless because the constraints will be dropped anyway.
00437   if (marked_empty()
00438       || (has_something_pending() && !remove_pending_to_obtain_generators())
00439       || (!generators_are_up_to_date() && !update_generators())) {
00440     // Removing dimensions from the empty polyhedron:
00441     // we clear `con_sys' since it could have contained the
00442     // unsatisfiable constraint of the wrong dimension.
00443     con_sys.clear();
00444     // Update the space dimension.
00445     space_dim = new_space_dim;
00446     assert(OK());
00447     return;
00448   }
00449 
00450   // When removing _all_ dimensions from a non-empty polyhedron,
00451   // we obtain the zero-dimensional universe polyhedron.
00452   if (new_space_dim == 0) {
00453     set_zero_dim_univ();
00454     return;
00455   }
00456 
00457   // For each variable to be removed, we fill the corresponding column
00458   // by shifting left those columns that will not be removed.
00459   Variables_Set::const_iterator tbr = to_be_removed.begin();
00460   Variables_Set::const_iterator tbr_end = to_be_removed.end();
00461   dimension_type dst_col = tbr->space_dimension();
00462   dimension_type src_col = dst_col + 1;
00463   for (++tbr; tbr != tbr_end; ++tbr) {
00464     dimension_type tbr_col = tbr->space_dimension();
00465     // All columns in between are moved to the left.
00466     while (src_col < tbr_col)
00467       gen_sys.Matrix::swap_columns(dst_col++, src_col++);
00468     ++src_col;
00469   }
00470   // Moving the remaining columns.
00471   const dimension_type gen_sys_num_columns = gen_sys.num_columns();
00472   while (src_col < gen_sys_num_columns)
00473     gen_sys.Matrix::swap_columns(dst_col++, src_col++);
00474 
00475   // The number of remaining columns is `dst_col'.
00476   // Note that resizing also calls `set_sorted(false)'.
00477   gen_sys.remove_trailing_columns(gen_sys_num_columns - dst_col);
00478   // We may have invalid lines and rays now.
00479   gen_sys.remove_invalid_lines_and_rays();
00480 
00481   // Constraints are not up-to-date and generators are not minimized.
00482   clear_constraints_up_to_date();
00483   clear_generators_minimized();
00484 
00485   // Update the space dimension.
00486   space_dim = new_space_dim;
00487 
00488   assert(OK(true));
00489 }

void Parma_Polyhedra_Library::Polyhedron::remove_higher_space_dimensions ( dimension_type  new_dimension  ) 

Removes the higher dimensions of the vector space so that the resulting space will have dimension new_dimension.

Exceptions:
std::invalid_argument Thrown if new_dimensions is greater than the space dimension of *this.

Definition at line 492 of file Polyhedron_chdims.cc.

References Parma_Polyhedra_Library::Constraint_System::clear(), clear_constraints_up_to_date(), clear_generators_minimized(), con_sys, gen_sys, generators_are_up_to_date(), has_something_pending(), is_necessarily_closed(), marked_empty(), Parma_Polyhedra_Library::Matrix::num_columns(), OK(), Parma_Polyhedra_Library::Generator_System::remove_invalid_lines_and_rays(), remove_pending_to_obtain_generators(), Parma_Polyhedra_Library::Linear_System::remove_trailing_columns(), set_zero_dim_univ(), space_dim, Parma_Polyhedra_Library::Matrix::swap_columns(), throw_dimension_incompatible(), and update_generators().

Referenced by bounded_affine_image(), bounded_affine_preimage(), generalized_affine_image(), generalized_affine_preimage(), and ppl_Polyhedron_remove_higher_space_dimensions().

00492                                                                           {
00493   // Dimension-compatibility check.
00494   if (new_dimension > space_dim)
00495     throw_dimension_incompatible("remove_higher_space_dimensions(nd)",
00496                                  new_dimension);
00497 
00498   // The removal of no dimensions from any polyhedron is a no-op.
00499   // Note that this case also captures the only legal removal of
00500   // dimensions from a polyhedron in a 0-dim space.
00501   if (new_dimension == space_dim) {
00502     assert(OK());
00503     return;
00504   }
00505 
00506   // We need updated generators; note that keeping pending generators
00507   // is useless because constraints will be dropped anyway.
00508   if (marked_empty()
00509       || (has_something_pending() && !remove_pending_to_obtain_generators())
00510       || (!generators_are_up_to_date() && !update_generators())) {
00511     // Removing dimensions from the empty polyhedron:
00512     // just updates the space dimension.
00513     space_dim = new_dimension;
00514     con_sys.clear();
00515     assert(OK());
00516     return;
00517   }
00518 
00519   if (new_dimension == 0) {
00520     // Removing all dimensions from a non-empty polyhedron:
00521     // just return the zero-dimensional universe polyhedron.
00522     set_zero_dim_univ();
00523     return;
00524   }
00525 
00526   dimension_type new_num_cols = new_dimension + 1;
00527   if (!is_necessarily_closed()) {
00528     // The polyhedron is not necessarily closed: move the column
00529     // of the epsilon coefficients to its new place.
00530     gen_sys.swap_columns(gen_sys.num_columns() - 1, new_num_cols);
00531     // The number of remaining columns is `new_dimension + 2'.
00532     ++new_num_cols;
00533   }
00534   // Note that resizing also calls `set_sorted(false)'.
00535   gen_sys.remove_trailing_columns(space_dim - new_dimension);
00536   // We may have invalid lines and rays now.
00537   gen_sys.remove_invalid_lines_and_rays();
00538 
00539   // Constraints are not up-to-date and generators are not minimized.
00540   clear_constraints_up_to_date();
00541   clear_generators_minimized();
00542 
00543   // Update the space dimension.
00544   space_dim = new_dimension;
00545 
00546   assert(OK(true));
00547 }

template<typename Partial_Function>
void Parma_Polyhedra_Library::Polyhedron::map_space_dimensions ( const Partial_Function &  pfunc  )  [inline]

Remaps the dimensions of the vector space according to a partial function.

Parameters:
pfunc The partial function specifying the destiny of each space dimension.
The template class Partial_Function must provide the following methods.
      bool has_empty_codomain() const
returns true if and only if the represented partial function has an empty codomain (i.e., it is always undefined). The has_empty_codomain() method will always be called before the methods below. However, if has_empty_codomain() returns true, none of the functions below will be called.
      dimension_type max_in_codomain() const
returns the maximum value that belongs to the codomain of the partial function. The max_in_codomain() method is called at most once.
      bool maps(dimension_type i, dimension_type& j) const
Let $f$ be the represented function and $k$ be the value of i. If $f$ is defined in $k$, then $f(k)$ is assigned to j and true is returned. If $f$ is undefined in $k$, then false is returned. This method is called at most $n$ times, where $n$ is the dimension of the vector space enclosing the polyhedron.

The result is undefined if pfunc does not encode a partial function with the properties described in the specification of the mapping operator.

Definition at line 363 of file Polyhedron.templates.hh.

References Parma_Polyhedra_Library::Generator_System::begin(), Parma_Polyhedra_Library::Constraint_System::clear(), Parma_Polyhedra_Library::Generator::CLOSURE_POINT, Parma_Polyhedra_Library::Generator::coefficient(), con_sys, constraints_are_up_to_date(), Parma_Polyhedra_Library::Generator::divisor(), Parma_Polyhedra_Library::EMPTY, Parma_Polyhedra_Library::Generator_System::end(), gen_sys, generators(), generators_are_up_to_date(), has_pending_constraints(), Parma_Polyhedra_Library::Generator_System::insert(), Parma_Polyhedra_Library::Generator::LINE, marked_empty(), Parma_Polyhedra_Library::not_a_dimension(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), Parma_Polyhedra_Library::Linear_System::permute_columns(), Parma_Polyhedra_Library::Generator::POINT, Parma_Polyhedra_Library::Generator::RAY, remove_pending_to_obtain_generators(), set_zero_dim_univ(), space_dim, throw_invalid_argument(), topology(), Parma_Polyhedra_Library::Generator::type(), and update_generators().

Referenced by ppl_Polyhedron_map_space_dimensions().

00363                                                               {
00364   if (space_dim == 0)
00365     return;
00366 
00367   if (pfunc.has_empty_codomain()) {
00368     // All dimensions vanish: the polyhedron becomes zero_dimensional.
00369     if (marked_empty()
00370         || (has_pending_constraints()
00371             && !remove_pending_to_obtain_generators())
00372         || (!generators_are_up_to_date() && !update_generators())) {
00373       // Removing all dimensions from the empty polyhedron.
00374       space_dim = 0;
00375       con_sys.clear();
00376     }
00377     else
00378       // Removing all dimensions from a non-empty polyhedron.
00379       set_zero_dim_univ();
00380 
00381     assert(OK());
00382     return;
00383   }
00384 
00385   const dimension_type new_space_dimension = pfunc.max_in_codomain() + 1;
00386 
00387   if (new_space_dimension == space_dim) {
00388     // The partial function `pfunc' is indeed total and thus specifies
00389     // a permutation, that is, a renaming of the dimensions.  For
00390     // maximum efficiency, we will simply permute the columns of the
00391     // constraint system and/or the generator system.
00392 
00393     // We first compute suitable permutation cycles for the columns of
00394     // the `con_sys' and `gen_sys' matrices.  We will represent them
00395     // with a linear array, using 0 as a terminator for each cycle
00396     // (notice that the columns with index 0 of `con_sys' and
00397     // `gen_sys' represent the inhomogeneous terms, and thus are
00398     // unaffected by the permutation of dimensions).
00399     // Cycles of length 1 will be omitted so that, in the worst case,
00400     // we will have `space_dim' elements organized in `space_dim/2'
00401     // cycles, which means we will have at most `space_dim/2'
00402     // terminators.
00403     std::vector<dimension_type> cycles;
00404     cycles.reserve(space_dim + space_dim/2);
00405 
00406     // Used to mark elements as soon as they are inserted in a cycle.
00407     std::deque<bool> visited(space_dim);
00408 
00409     for (dimension_type i = space_dim; i-- > 0; ) {
00410       if (!visited[i]) {
00411         dimension_type j = i;
00412         do {
00413           visited[j] = true;
00414           // The following initialization is only to make the compiler happy.
00415           dimension_type k = 0;
00416           if (!pfunc.maps(j, k))
00417             throw_invalid_argument("map_space_dimensions(pfunc)",
00418                                    " pfunc is inconsistent");
00419           if (k == j)
00420             // Cycle of length 1: skip it.
00421             goto skip;
00422 
00423           cycles.push_back(j+1);
00424           // Go along the cycle.
00425           j = k;
00426         } while (!visited[j]);
00427         // End of cycle: mark it.
00428         cycles.push_back(0);
00429       skip:
00430         ;
00431       }
00432     }
00433 
00434     // If `cycles' is empty then `pfunc' is the identity.
00435     if (cycles.empty())
00436       return;
00437 
00438     // Permute all that is up-to-date.  Notice that the contents of
00439     // the saturation matrices is unaffected by the permutation of
00440     // columns: they remain valid, if they were so.
00441     if (constraints_are_up_to_date())
00442       con_sys.permute_columns(cycles);
00443 
00444     if (generators_are_up_to_date())
00445       gen_sys.permute_columns(cycles);
00446 
00447     assert(OK());
00448     return;
00449   }
00450 
00451   // If control gets here, then `pfunc' is not a permutation and some
00452   // dimensions must be projected away.
00453 
00454   // If there are pending constraints, using `generators()' we process them.
00455   const Generator_System& old_gensys = generators();
00456 
00457   if (old_gensys.num_rows() == 0) {
00458     // The polyhedron is empty.
00459     Polyhedron new_polyhedron(topology(), new_space_dimension, EMPTY);
00460     std::swap(*this, new_polyhedron);
00461     assert(OK());
00462     return;
00463   }
00464 
00465   // Make a local copy of the partial function.
00466   std::vector<dimension_type> pfunc_maps(space_dim, not_a_dimension());
00467   for (dimension_type j = space_dim; j-- > 0; ) {
00468     dimension_type pfunc_j;
00469     if (pfunc.maps(j, pfunc_j))
00470       pfunc_maps[j] = pfunc_j;
00471   }
00472 
00473   Generator_System new_gensys;
00474   for (Generator_System::const_iterator i = old_gensys.begin(),
00475          old_gensys_end = old_gensys.end(); i != old_gensys_end; ++i) {
00476     const Generator& old_g = *i;
00477     Linear_Expression e(0 * Variable(new_space_dimension-1));
00478     bool all_zeroes = true;
00479     for (dimension_type j = space_dim; j-- > 0; ) {
00480       if (old_g.coefficient(Variable(j)) != 0
00481           && pfunc_maps[j] != not_a_dimension()) {
00482         e += Variable(pfunc_maps[j]) * old_g.coefficient(Variable(j));
00483         all_zeroes = false;
00484       }
00485     }
00486     switch (old_g.type()) {
00487     case Generator::LINE:
00488       if (!all_zeroes)
00489         new_gensys.insert(line(e));
00490       break;
00491     case Generator::RAY:
00492       if (!all_zeroes)
00493         new_gensys.insert(ray(e));
00494       break;
00495     case Generator::POINT:
00496       // A point in the origin has all zero homogeneous coefficients.
00497       new_gensys.insert(point(e, old_g.divisor()));
00498       break;
00499     case Generator::CLOSURE_POINT:
00500       // A closure point in the origin has all zero homogeneous coefficients.
00501       new_gensys.insert(closure_point(e, old_g.divisor()));
00502       break;
00503     }
00504   }
00505   Polyhedron new_polyhedron(topology(), new_gensys);
00506   std::swap(*this, new_polyhedron);
00507   assert(OK(true));
00508 }

void Parma_Polyhedra_Library::Polyhedron::expand_space_dimension ( Variable  var,
dimension_type  m 
)

Creates m copies of the space dimension corresponding to var.

Parameters:
var The variable corresponding to the space dimension to be replicated;
m The number of replicas to be created.
Exceptions:
std::invalid_argument Thrown if var does not correspond to a dimension of the vector space.
std::length_error Thrown if adding m new space dimensions would cause the vector space to exceed dimension max_space_dimension().
If *this has space dimension $n$, with $n > 0$, and var has space dimension $k \leq n$, then the $k$-th space dimension is expanded to m new space dimensions $n$, $n+1$, $\dots$, $n+m-1$.

Definition at line 550 of file Polyhedron_chdims.cc.

References add_constraints(), add_space_dimensions_and_embed(), Parma_Polyhedra_Library::Constraint_System::begin(), Parma_Polyhedra_Library::Constraint::coefficient(), constraints(), Parma_Polyhedra_Library::Constraint_System::end(), Parma_Polyhedra_Library::Variable::id(), Parma_Polyhedra_Library::Constraint::inhomogeneous_term(), Parma_Polyhedra_Library::Constraint_System::insert(), Parma_Polyhedra_Library::Constraint::is_equality(), Parma_Polyhedra_Library::Constraint::is_nonstrict_inequality(), max_space_dimension(), OK(), space_dim, space_dimension(), Parma_Polyhedra_Library::Variable::space_dimension(), throw_dimension_incompatible(), throw_space_dimension_overflow(), and topology().

Referenced by ppl_Polyhedron_expand_space_dimension().

00550                                                                     {
00551   // TODO: this implementation is _really_ an executable specification.
00552 
00553   // `var' should be one of the dimensions of the vector space.
00554   if (var.space_dimension() > space_dim)
00555     throw_dimension_incompatible("expand_space_dimension(v, m)", "v", var);
00556 
00557   // The space dimension of the resulting polyhedron should not
00558   // overflow the maximum allowed space dimension.
00559   if (m > max_space_dimension() - space_dimension())
00560     throw_space_dimension_overflow(topology(),
00561                                    "expand_dimension(v, m)",
00562                                    "adding m new space dimensions exceeds "
00563                                    "the maximum allowed space dimension");
00564 
00565   // Nothing to do, if no dimensions must be added.
00566   if (m == 0)
00567     return;
00568 
00569   // Keep track of the dimension before adding the new ones.
00570   dimension_type old_dim = space_dim;
00571 
00572   // Add the required new dimensions.
00573   add_space_dimensions_and_embed(m);
00574 
00575   const dimension_type src_d = var.id();
00576   const Constraint_System& cs = constraints();
00577   Constraint_System new_constraints;
00578   for (Constraint_System::const_iterator i = cs.begin(),
00579          cs_end = cs.end(); i != cs_end; ++i) {
00580     const Constraint& c = *i;
00581 
00582     // If `c' does not constrain `var', skip it.
00583     if (c.coefficient(var) == 0)
00584       continue;
00585 
00586     // Each relevant constraint results in `m' new constraints.
00587     for (dimension_type dst_d = old_dim; dst_d < old_dim+m; ++dst_d) {
00588       Linear_Expression e;
00589       for (dimension_type j = old_dim; j-- > 0; )
00590         e +=
00591           c.coefficient(Variable(j))
00592           * (j == src_d ? Variable(dst_d) : Variable(j));
00593       e += c.inhomogeneous_term();
00594       new_constraints.insert(c.is_equality()
00595                              ? (e == 0)
00596                              : (c.is_nonstrict_inequality()
00597                                 ? (e >= 0)
00598                                 : (e > 0)));
00599     }
00600   }
00601   add_constraints(new_constraints);
00602   assert(OK());
00603 }

void Parma_Polyhedra_Library::Polyhedron::fold_space_dimensions ( const Variables_Set to_be_folded,
Variable  var 
)

Folds the space dimensions in to_be_folded into var.

Parameters:
to_be_folded The set of Variable objects corresponding to the space dimensions to be folded;
var The variable corresponding to the space dimension that is the destination of the folding operation.
Exceptions:
std::invalid_argument Thrown if *this is dimension-incompatible with var or with one of the Variable objects contained in to_be_folded. Also thrown if var is contained in to_be_folded.
If *this has space dimension $n$, with $n > 0$, var has space dimension $k \leq n$, to_be_folded is a set of variables whose maximum space dimension is also less than or equal to $n$, and var is not a member of to_be_folded, then the space dimensions corresponding to variables in to_be_folded are folded into the $k$-th space dimension.

Definition at line 606 of file Polyhedron_chdims.cc.

References affine_image(), OK(), poly_hull_assign(), remove_space_dimensions(), space_dim, Parma_Polyhedra_Library::Variable::space_dimension(), throw_dimension_incompatible(), and throw_invalid_argument().

Referenced by ppl_Polyhedron_fold_space_dimensions().

00607                                                      {
00608   // TODO: this implementation is _really_ an executable specification.
00609 
00610   // `var' should be one of the dimensions of the polyhedron.
00611   if (var.space_dimension() > space_dim)
00612     throw_dimension_incompatible("fold_space_dimensions(tbf, v)", "v", var);
00613 
00614   // The folding of no dimensions is a no-op.
00615   if (to_be_folded.empty())
00616     return;
00617 
00618   // All variables in `to_be_folded' should be dimensions of the polyhedron.
00619   if (to_be_folded.rbegin()->space_dimension() > space_dim)
00620     throw_dimension_incompatible("fold_space_dimensions(tbf, v)",
00621                                  "*tbf.rbegin()",
00622                                  *to_be_folded.rbegin());
00623 
00624   // Moreover, `var' should not occur in `to_be_folded'.
00625   if (to_be_folded.find(var) != to_be_folded.end())
00626     throw_invalid_argument("fold_space_dimensions(tbf, v)",
00627                            "v should not occur in tbf");
00628 
00629   for (Variables_Set::const_iterator i = to_be_folded.begin(),
00630          tbf_end = to_be_folded.end(); i != tbf_end; ++i) {
00631     Polyhedron copy = *this;
00632     copy.affine_image(var, Linear_Expression(*i));
00633     poly_hull_assign(copy);
00634   }
00635   remove_space_dimensions(to_be_folded);
00636   assert(OK());
00637 }

void Parma_Polyhedra_Library::Polyhedron::swap ( Polyhedron y  )  [inline]

Swaps *this with polyhedron y. (*this and y can be dimension-incompatible.).

Exceptions:
std::invalid_argument Thrown if x and y are topology-incompatible.

Definition at line 85 of file Polyhedron.inlines.hh.

References con_sys, gen_sys, sat_c, sat_g, space_dim, status, throw_topology_incompatible(), and topology().

Referenced by add_space_dimensions_and_embed(), constraints(), generators(), Parma_Polyhedra_Library::NNC_Polyhedron::operator=(), Parma_Polyhedra_Library::C_Polyhedron::operator=(), ppl_Polyhedron_swap(), and swap().

00085                               {
00086   if (topology() != y.topology())
00087     throw_topology_incompatible("swap(y)", "y", y);
00088   std::swap(con_sys, y.con_sys);
00089   std::swap(gen_sys, y.gen_sys);
00090   std::swap(sat_c, y.sat_c);
00091   std::swap(sat_g, y.sat_g);
00092   std::swap(status, y.status);
00093   std::swap(space_dim, y.space_dim);
00094 }

void Parma_Polyhedra_Library::Polyhedron::ascii_dump (  )  const

Writes to std::cerr an ASCII representation of *this.

Referenced by OK().

void Parma_Polyhedra_Library::Polyhedron::ascii_dump ( std::ostream &  s  )  const

Writes to s an ASCII representation of *this.

Definition at line 2878 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::Saturation_Matrix::ascii_dump(), Parma_Polyhedra_Library::Generator_System::ascii_dump(), Parma_Polyhedra_Library::Constraint_System::ascii_dump(), Parma_Polyhedra_Library::Polyhedron::Status::ascii_dump(), con_sys, constraints_are_up_to_date(), gen_sys, generators_are_up_to_date(), sat_c, sat_g, space_dim, and status.

02878                                              {
02879   s << "space_dim " << space_dim << "\n";
02880   status.ascii_dump(s);
02881   s << "\ncon_sys ("
02882     << (constraints_are_up_to_date() ? "" : "not_")
02883     << "up-to-date)"
02884     << "\n";
02885   con_sys.ascii_dump(s);
02886   s << "\ngen_sys ("
02887     << (generators_are_up_to_date() ? "" : "not_")
02888     << "up-to-date)"
02889     << "\n";
02890   gen_sys.ascii_dump(s);
02891   s << "\nsat_c\n";
02892   sat_c.ascii_dump(s);
02893   s << "\nsat_g\n";
02894   sat_g.ascii_dump(s);
02895   s << "\n";
02896 }

void Parma_Polyhedra_Library::Polyhedron::print (  )  const

Prints *this to std::cerr using operator<<.

bool Parma_Polyhedra_Library::Polyhedron::ascii_load ( std::istream &  s  ) 

Loads from s an ASCII representation (as produced by ascii_dump) and sets *this accordingly. Returns true if successful, false otherwise.

Definition at line 2901 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::Saturation_Matrix::ascii_load(), Parma_Polyhedra_Library::Generator_System::ascii_load(), Parma_Polyhedra_Library::Constraint_System::ascii_load(), Parma_Polyhedra_Library::Polyhedron::Status::ascii_load(), con_sys, gen_sys, OK(), sat_c, sat_g, space_dim, and status.

02901                                        {
02902   std::string str;
02903 
02904   if (!(s >> str) || str != "space_dim")
02905     return false;
02906 
02907   if (!(s >> space_dim))
02908     return false;
02909 
02910   if (!status.ascii_load(s))
02911     return false;
02912 
02913   if (!(s >> str) || str != "con_sys")
02914     return false;
02915 
02916   if (!(s >> str) || (str != "(not_up-to-date)" && str != "(up-to-date)"))
02917     return false;
02918 
02919   if (!con_sys.ascii_load(s))
02920     return false;
02921 
02922   if (!(s >> str) || str != "gen_sys")
02923     return false;
02924 
02925   if (!(s >> str) || (str != "(not_up-to-date)" && str != "(up-to-date)"))
02926     return false;
02927 
02928   if (!gen_sys.ascii_load(s))
02929     return false;
02930 
02931   if (!(s >> str) || str != "sat_c")
02932     return false;
02933 
02934   if (!sat_c.ascii_load(s))
02935     return false;
02936 
02937   if (!(s >> str) || str != "sat_g")
02938     return false;
02939 
02940   if (!sat_g.ascii_load(s))
02941     return false;
02942 
02943   // Check for well-formedness.
02944   assert(OK());
02945   return true;
02946 }

memory_size_type Parma_Polyhedra_Library::Polyhedron::total_memory_in_bytes (  )  const [inline]

Returns the total size in bytes of the memory occupied by *this.

Definition at line 35 of file Polyhedron.inlines.hh.

References external_memory_in_bytes().

00035                                         {
00036   return sizeof(*this) + external_memory_in_bytes();
00037 }

PPL::memory_size_type Parma_Polyhedra_Library::Polyhedron::external_memory_in_bytes (  )  const

Returns the size in bytes of the memory managed by *this.

Definition at line 2949 of file Polyhedron_public.cc.

References con_sys, Parma_Polyhedra_Library::Saturation_Matrix::external_memory_in_bytes(), Parma_Polyhedra_Library::Generator_System::external_memory_in_bytes(), Parma_Polyhedra_Library::Constraint_System::external_memory_in_bytes(), gen_sys, sat_c, and sat_g.

Referenced by total_memory_in_bytes().

02949                                               {
02950   return
02951     con_sys.external_memory_in_bytes()
02952     + gen_sys.external_memory_in_bytes()
02953     + sat_c.external_memory_in_bytes()
02954     + sat_g.external_memory_in_bytes();
02955 }

Topology Parma_Polyhedra_Library::Polyhedron::topology (  )  const [inline, private]

bool Parma_Polyhedra_Library::Polyhedron::is_necessarily_closed (  )  const [inline, private]

Returns true if and only if the polyhedron is necessarily closed.

Definition at line 59 of file Polyhedron.inlines.hh.

References con_sys, and Parma_Polyhedra_Library::Linear_System::is_necessarily_closed().

Referenced by add_constraint(), add_generator(), add_recycled_constraints(), add_recycled_constraints_and_minimize(), add_recycled_generators(), add_recycled_generators_and_minimize(), add_space_dimensions_and_embed(), add_space_dimensions_and_project(), Parma_Polyhedra_Library::BHRZ03_Certificate::BHRZ03_Certificate(), BHRZ03_combining_constraints(), BHRZ03_evolving_points(), BHRZ03_widening_assign(), Parma_Polyhedra_Library::H79_Certificate::compare(), Parma_Polyhedra_Library::BHRZ03_Certificate::compare(), concatenate_assign(), generalized_affine_image(), generalized_affine_preimage(), generators(), Parma_Polyhedra_Library::H79_Certificate::H79_Certificate(), H79_widening_assign(), is_topologically_closed(), is_universe(), limited_BHRZ03_extrapolation_assign(), limited_H79_extrapolation_assign(), minimized_constraints(), minimized_generators(), OK(), poly_difference_assign(), remove_higher_space_dimensions(), shrink_bounding_box(), strongly_minimize_constraints(), strongly_minimize_generators(), throw_dimension_incompatible(), throw_invalid_argument(), throw_invalid_generator(), throw_invalid_generators(), throw_runtime_error(), throw_topology_incompatible(), time_elapse_assign(), and topological_closure_assign().

00059                                         {
00060   // We can check either one of the two matrices.
00061   // (`con_sys' is slightly better, since it is placed at offset 0.)
00062   return con_sys.is_necessarily_closed();
00063 }

bool Parma_Polyhedra_Library::Polyhedron::marked_empty (  )  const [inline, private]

Returns true if the polyhedron is known to be empty.

The return value false does not necessarily implies that *this is non-empty.

Definition at line 108 of file Polyhedron.inlines.hh.

References status, and Parma_Polyhedra_Library::Polyhedron::Status::test_empty().

Referenced by add_congruence(), add_constraint(), add_generator(), add_recycled_constraints(), add_recycled_generators(), add_recycled_generators_and_minimize(), add_space_dimensions_and_embed(), add_space_dimensions_and_project(), affine_image(), affine_preimage(), Parma_Polyhedra_Library::BD_Shape< T >::BD_Shape(), Parma_Polyhedra_Library::BHRZ03_Certificate::BHRZ03_Certificate(), BHRZ03_combining_constraints(), BHRZ03_evolving_points(), BHRZ03_evolving_rays(), BHRZ03_widening_assign(), bounded_affine_image(), bounded_affine_preimage(), bounds(), Parma_Polyhedra_Library::H79_Certificate::compare(), Parma_Polyhedra_Library::BHRZ03_Certificate::compare(), concatenate_assign(), constraints(), contains(), generalized_affine_image(), generalized_affine_preimage(), generators(), Parma_Polyhedra_Library::H79_Certificate::H79_Certificate(), H79_widening_assign(), intersection_assign(), intersection_assign_and_minimize(), is_bounded(), is_empty(), is_included_in(), is_topologically_closed(), is_universe(), limited_BHRZ03_extrapolation_assign(), limited_H79_extrapolation_assign(), map_space_dimensions(), max_min(), minimize(), OK(), operator=(), poly_difference_assign(), poly_hull_assign(), poly_hull_assign_and_minimize(), process_pending(), process_pending_constraints(), process_pending_generators(), quick_equivalence_test(), relation_with(), remove_higher_space_dimensions(), remove_space_dimensions(), select_CH78_constraints(), select_H79_constraints(), shrink_bounding_box(), time_elapse_assign(), topological_closure_assign(), update_constraints(), and update_generators().

00108                                {
00109   return status.test_empty();
00110 }

bool Parma_Polyhedra_Library::Polyhedron::constraints_are_up_to_date (  )  const [inline, private]

bool Parma_Polyhedra_Library::Polyhedron::generators_are_up_to_date (  )  const [inline, private]

bool Parma_Polyhedra_Library::Polyhedron::constraints_are_minimized (  )  const [inline, private]

bool Parma_Polyhedra_Library::Polyhedron::generators_are_minimized (  )  const [inline, private]

Returns true if the system of generators is minimized.

Note that only weak minimization is entailed, so that an NNC polyhedron may still have $\epsilon$-redundant generators.

Definition at line 128 of file Polyhedron.inlines.hh.

References status, and Parma_Polyhedra_Library::Polyhedron::Status::test_g_minimized().

Referenced by BHRZ03_combining_constraints(), BHRZ03_evolving_points(), BHRZ03_evolving_rays(), can_have_something_pending(), generators(), is_topologically_closed(), is_universe(), minimize(), OK(), quick_equivalence_test(), update_sat_c(), and update_sat_g().

00128                                            {
00129   return status.test_g_minimized();
00130 }

bool Parma_Polyhedra_Library::Polyhedron::has_pending_constraints (  )  const [inline, private]

bool Parma_Polyhedra_Library::Polyhedron::has_pending_generators (  )  const [inline, private]

bool Parma_Polyhedra_Library::Polyhedron::has_something_pending (  )  const [inline, private]

bool Parma_Polyhedra_Library::Polyhedron::can_have_something_pending (  )  const [inline, private]

bool Parma_Polyhedra_Library::Polyhedron::sat_c_is_up_to_date (  )  const [inline, private]

bool Parma_Polyhedra_Library::Polyhedron::sat_g_is_up_to_date (  )  const [inline, private]

void Parma_Polyhedra_Library::Polyhedron::set_zero_dim_univ (  )  [private]

Sets status to express that the polyhedron is the universe 0-dimension vector space, clearing all corresponding matrices.

Definition at line 647 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Generator_System::clear(), Parma_Polyhedra_Library::Constraint_System::clear(), con_sys, gen_sys, Parma_Polyhedra_Library::Polyhedron::Status::set_zero_dim_univ(), space_dim, and status.

Referenced by map_space_dimensions(), operator=(), Polyhedron(), remove_higher_space_dimensions(), and remove_space_dimensions().

00647                                  {
00648   status.set_zero_dim_univ();
00649   space_dim = 0;
00650   con_sys.clear();
00651   gen_sys.clear();
00652 }

void Parma_Polyhedra_Library::Polyhedron::set_empty (  )  [private]

void Parma_Polyhedra_Library::Polyhedron::set_constraints_up_to_date (  )  [inline, private]

Sets status to express that constraints are up-to-date.

Definition at line 165 of file Polyhedron.inlines.hh.

References Parma_Polyhedra_Library::Polyhedron::Status::set_c_up_to_date(), and status.

Referenced by Polyhedron(), and set_constraints_minimized().

00165                                        {
00166   status.set_c_up_to_date();
00167 }

void Parma_Polyhedra_Library::Polyhedron::set_generators_up_to_date (  )  [inline, private]

Sets status to express that generators are up-to-date.

Definition at line 170 of file Polyhedron.inlines.hh.

References Parma_Polyhedra_Library::Polyhedron::Status::set_g_up_to_date(), and status.

Referenced by add_recycled_generators(), add_recycled_generators_and_minimize(), Polyhedron(), and set_generators_minimized().

00170                                       {
00171   status.set_g_up_to_date();
00172 }

void Parma_Polyhedra_Library::Polyhedron::set_constraints_minimized (  )  [inline, private]

Sets status to express that constraints are minimized.

Definition at line 175 of file Polyhedron.inlines.hh.

References Parma_Polyhedra_Library::Polyhedron::Status::set_c_minimized(), set_constraints_up_to_date(), and status.

Referenced by Polyhedron(), update_constraints(), and update_generators().

00175                                       {
00176   set_constraints_up_to_date();
00177   status.set_c_minimized();
00178 }

void Parma_Polyhedra_Library::Polyhedron::set_generators_minimized (  )  [inline, private]

Sets status to express that generators are minimized.

Definition at line 181 of file Polyhedron.inlines.hh.

References Parma_Polyhedra_Library::Polyhedron::Status::set_g_minimized(), set_generators_up_to_date(), and status.

Referenced by add_generator(), add_space_dimensions_and_project(), update_constraints(), and update_generators().

00181                                      {
00182   set_generators_up_to_date();
00183   status.set_g_minimized();
00184 }

void Parma_Polyhedra_Library::Polyhedron::set_constraints_pending (  )  [inline, private]

Sets status to express that constraints are pending.

Definition at line 187 of file Polyhedron.inlines.hh.

References Parma_Polyhedra_Library::Polyhedron::Status::set_c_pending(), and status.

Referenced by add_constraint(), add_recycled_constraints(), concatenate_assign(), and intersection_assign().

00187                                     {
00188   status.set_c_pending();
00189 }

void Parma_Polyhedra_Library::Polyhedron::set_generators_pending (  )  [inline, private]

Sets status to express that generators are pending.

Definition at line 192 of file Polyhedron.inlines.hh.

References Parma_Polyhedra_Library::Polyhedron::Status::set_g_pending(), and status.

Referenced by add_generator(), add_recycled_generators(), poly_hull_assign(), time_elapse_assign(), and topological_closure_assign().

00192                                    {
00193   status.set_g_pending();
00194 }

void Parma_Polyhedra_Library::Polyhedron::set_sat_c_up_to_date (  )  [inline, private]

void Parma_Polyhedra_Library::Polyhedron::set_sat_g_up_to_date (  )  [inline, private]

void Parma_Polyhedra_Library::Polyhedron::clear_empty (  )  [inline, private]

Clears the status flag indicating that the polyhedron is empty.

Definition at line 207 of file Polyhedron.inlines.hh.

References Parma_Polyhedra_Library::Polyhedron::Status::reset_empty(), and status.

Referenced by add_generator(), add_recycled_generators(), and add_recycled_generators_and_minimize().

00207                         {
00208   status.reset_empty();
00209 }

void Parma_Polyhedra_Library::Polyhedron::clear_constraints_up_to_date (  )  [inline, private]

void Parma_Polyhedra_Library::Polyhedron::clear_generators_up_to_date (  )  [inline, private]

Sets status to express that generators are no longer up-to-date.

This also implies that they are neither minimized and both saturation matrices are no longer meaningful.

Definition at line 254 of file Polyhedron.inlines.hh.

References clear_generators_minimized(), clear_pending_generators(), clear_sat_c_up_to_date(), clear_sat_g_up_to_date(), Parma_Polyhedra_Library::Polyhedron::Status::reset_g_up_to_date(), and status.

Referenced by add_constraint(), add_recycled_constraints(), affine_preimage(), concatenate_assign(), intersection_assign(), remove_pending_to_obtain_constraints(), strongly_minimize_constraints(), and topological_closure_assign().

00254                                         {
00255   clear_pending_generators();
00256   clear_generators_minimized();
00257   clear_sat_c_up_to_date();
00258   clear_sat_g_up_to_date();
00259   status.reset_g_up_to_date();
00260   // Can get rid of gen_sys here.
00261 }

void Parma_Polyhedra_Library::Polyhedron::clear_constraints_minimized (  )  [inline, private]

void Parma_Polyhedra_Library::Polyhedron::clear_generators_minimized (  )  [inline, private]

void Parma_Polyhedra_Library::Polyhedron::clear_pending_constraints (  )  [inline, private]

Sets status to express that there are no longer pending constraints.

Definition at line 222 of file Polyhedron.inlines.hh.

References Parma_Polyhedra_Library::Polyhedron::Status::reset_c_pending(), and status.

Referenced by clear_constraints_up_to_date(), intersection_assign_and_minimize(), process_pending_constraints(), and remove_pending_to_obtain_constraints().

00222                                       {
00223   status.reset_c_pending();
00224 }

void Parma_Polyhedra_Library::Polyhedron::clear_pending_generators (  )  [inline, private]

Sets status to express that there are no longer pending generators.

Definition at line 227 of file Polyhedron.inlines.hh.

References Parma_Polyhedra_Library::Polyhedron::Status::reset_g_pending(), and status.

Referenced by clear_generators_up_to_date(), poly_hull_assign_and_minimize(), process_pending_generators(), and remove_pending_to_obtain_generators().

00227                                      {
00228   status.reset_g_pending();
00229 }

void Parma_Polyhedra_Library::Polyhedron::clear_sat_c_up_to_date (  )  [inline, private]

void Parma_Polyhedra_Library::Polyhedron::clear_sat_g_up_to_date (  )  [inline, private]

bool Parma_Polyhedra_Library::Polyhedron::process_pending (  )  const [inline, private]

Processes the pending rows of either description of the polyhedron and obtains a minimized polyhedron.

Returns:
false if and only if *this turns out to be an empty polyhedron.
It is assumed that the polyhedron does have some constraints or generators pending.

Definition at line 264 of file Polyhedron.inlines.hh.

References has_pending_constraints(), has_pending_generators(), has_something_pending(), marked_empty(), process_pending_constraints(), process_pending_generators(), and space_dim.

Referenced by is_topologically_closed(), minimize(), and shrink_bounding_box().

00264                                   {
00265   assert(space_dim > 0 && !marked_empty());
00266   assert(has_something_pending());
00267 
00268   Polyhedron& x = const_cast<Polyhedron&>(*this);
00269 
00270   if (x.has_pending_constraints())
00271     return x.process_pending_constraints();
00272 
00273   assert(x.has_pending_generators());
00274   x.process_pending_generators();
00275   return true;
00276 }

bool Parma_Polyhedra_Library::Polyhedron::process_pending_constraints (  )  const [private]

Processes the pending constraints and obtains a minimized polyhedron.

Returns:
false if and only if *this turns out to be an empty polyhedron.
It is assumed that the polyhedron does have some pending constraints.

Definition at line 665 of file Polyhedron_nonpublic.cc.

References add_and_minimize(), clear_pending_constraints(), clear_sat_g_up_to_date(), con_sys, empty, gen_sys, has_pending_constraints(), has_pending_generators(), Parma_Polyhedra_Library::Linear_System::is_sorted(), marked_empty(), Parma_Polyhedra_Library::Linear_System::num_pending_rows(), obtain_sorted_constraints_with_sat_c(), OK(), sat_c, sat_c_is_up_to_date(), sat_g, set_empty(), set_sat_c_up_to_date(), Parma_Polyhedra_Library::Linear_System::sort_pending_and_remove_duplicates(), space_dim, and Parma_Polyhedra_Library::Saturation_Matrix::transpose_assign().

Referenced by add_generator(), add_recycled_generators(), bounds(), generators(), is_bounded(), limited_BHRZ03_extrapolation_assign(), limited_H79_extrapolation_assign(), max_min(), poly_hull_assign(), poly_hull_assign_and_minimize(), process_pending(), relation_with(), remove_pending_to_obtain_generators(), time_elapse_assign(), and topological_closure_assign().

00665                                                  {
00666   assert(space_dim > 0 && !marked_empty());
00667   assert(has_pending_constraints() && !has_pending_generators());
00668 
00669   Polyhedron& x = const_cast<Polyhedron&>(*this);
00670 
00671   // Integrate the pending part of the system of constraints and minimize.
00672   // We need `sat_c' up-to-date and `con_sys' sorted (together with `sat_c').
00673   if (!x.sat_c_is_up_to_date())
00674     x.sat_c.transpose_assign(x.sat_g);
00675   if (!x.con_sys.is_sorted())
00676     x.obtain_sorted_constraints_with_sat_c();
00677   // We sort in place the pending constraints, erasing those constraints
00678   // that also occur in the non-pending part of `con_sys'.
00679   x.con_sys.sort_pending_and_remove_duplicates();
00680   if (x.con_sys.num_pending_rows() == 0) {
00681     // All pending constraints were duplicates.
00682     x.clear_pending_constraints();
00683     assert(OK(true));
00684     return true;
00685   }
00686 
00687   const bool empty = add_and_minimize(true, x.con_sys, x.gen_sys, x.sat_c);
00688   assert(x.con_sys.num_pending_rows() == 0);
00689 
00690   if (empty)
00691     x.set_empty();
00692   else {
00693     x.clear_pending_constraints();
00694     x.clear_sat_g_up_to_date();
00695     x.set_sat_c_up_to_date();
00696   }
00697   assert(OK(!empty));
00698   return !empty;
00699 }

void Parma_Polyhedra_Library::Polyhedron::process_pending_generators (  )  const [private]

Processes the pending generators and obtains a minimized polyhedron.

It is assumed that the polyhedron does have some pending generators.

Definition at line 702 of file Polyhedron_nonpublic.cc.

References add_and_minimize(), clear_pending_generators(), clear_sat_c_up_to_date(), con_sys, gen_sys, has_pending_constraints(), has_pending_generators(), Parma_Polyhedra_Library::Linear_System::is_sorted(), marked_empty(), Parma_Polyhedra_Library::Linear_System::num_pending_rows(), obtain_sorted_generators_with_sat_g(), OK(), sat_c, sat_g, sat_g_is_up_to_date(), set_sat_g_up_to_date(), Parma_Polyhedra_Library::Linear_System::sort_pending_and_remove_duplicates(), space_dim, and Parma_Polyhedra_Library::Saturation_Matrix::transpose_assign().

Referenced by add_constraint(), add_recycled_constraints(), concatenate_assign(), constraints(), H79_widening_assign(), intersection_assign(), intersection_assign_and_minimize(), is_included_in(), is_universe(), process_pending(), relation_with(), and remove_pending_to_obtain_constraints().

00702                                                 {
00703   assert(space_dim > 0 && !marked_empty());
00704   assert(has_pending_generators() && !has_pending_constraints());
00705 
00706   Polyhedron& x = const_cast<Polyhedron&>(*this);
00707 
00708   // Integrate the pending part of the system of generators and minimize.
00709   // We need `sat_g' up-to-date and `gen_sys' sorted (together with `sat_g').
00710   if (!x.sat_g_is_up_to_date())
00711     x.sat_g.transpose_assign(x.sat_c);
00712   if (!x.gen_sys.is_sorted())
00713     x.obtain_sorted_generators_with_sat_g();
00714   // We sort in place the pending generators, erasing those generators
00715   // that also occur in the non-pending part of `gen_sys'.
00716   x.gen_sys.sort_pending_and_remove_duplicates();
00717   if (x.gen_sys.num_pending_rows() == 0) {
00718     // All pending generators were duplicates.
00719     x.clear_pending_generators();
00720     assert(OK(true));
00721     return;
00722   }
00723 
00724   add_and_minimize(false, x.gen_sys, x.con_sys, x.sat_g);
00725   assert(x.gen_sys.num_pending_rows() == 0);
00726 
00727   x.clear_pending_generators();
00728   x.clear_sat_c_up_to_date();
00729   x.set_sat_g_up_to_date();
00730 }

void Parma_Polyhedra_Library::Polyhedron::remove_pending_to_obtain_constraints (  )  const [private]

Lazily integrates the pending descriptions of the polyhedron to obtain a constraint system without pending rows.

It is assumed that the polyhedron does have some constraints or generators pending.

Definition at line 733 of file Polyhedron_nonpublic.cc.

References clear_constraints_minimized(), clear_generators_up_to_date(), clear_pending_constraints(), con_sys, has_pending_constraints(), has_pending_generators(), has_something_pending(), OK(), process_pending_generators(), Parma_Polyhedra_Library::Linear_System::set_sorted(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

Referenced by affine_preimage().

00733                                                           {
00734   assert(has_something_pending());
00735 
00736   Polyhedron& x = const_cast<Polyhedron&>(*this);
00737 
00738   // If the polyhedron has pending constraints, simply unset them.
00739   if (x.has_pending_constraints()) {
00740     // Integrate the pending constraints, which are possibly not sorted.
00741     x.con_sys.unset_pending_rows();
00742     x.con_sys.set_sorted(false);
00743     x.clear_pending_constraints();
00744     x.clear_constraints_minimized();
00745     x.clear_generators_up_to_date();
00746   }
00747   else {
00748     assert(x.has_pending_generators());
00749     // We must process the pending generators and obtain the
00750     // corresponding system of constraints.
00751     x.process_pending_generators();
00752   }
00753   assert(OK(true));
00754 }

bool Parma_Polyhedra_Library::Polyhedron::remove_pending_to_obtain_generators (  )  const [private]

Lazily integrates the pending descriptions of the polyhedron to obtain a generator system without pending rows.

Returns:
false if and only if *this turns out to be an empty polyhedron.
It is assumed that the polyhedron does have some constraints or generators pending.

Definition at line 757 of file Polyhedron_nonpublic.cc.

References clear_constraints_up_to_date(), clear_generators_minimized(), clear_pending_generators(), gen_sys, has_pending_constraints(), has_pending_generators(), has_something_pending(), OK(), process_pending_constraints(), Parma_Polyhedra_Library::Linear_System::set_sorted(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

Referenced by affine_image(), map_space_dimensions(), remove_higher_space_dimensions(), and remove_space_dimensions().

00757                                                          {
00758   assert(has_something_pending());
00759 
00760   Polyhedron& x = const_cast<Polyhedron&>(*this);
00761 
00762   // If the polyhedron has pending generators, simply unset them.
00763   if (x.has_pending_generators()) {
00764     // Integrate the pending generators, which are possibly not sorted.
00765     x.gen_sys.unset_pending_rows();
00766     x.gen_sys.set_sorted(false);
00767     x.clear_pending_generators();
00768     x.clear_generators_minimized();
00769     x.clear_constraints_up_to_date();
00770     assert(OK(true));
00771     return true;
00772   }
00773   else {
00774     assert(x.has_pending_constraints());
00775     // We must integrate the pending constraints and obtain the
00776     // corresponding system of generators.
00777     return x.process_pending_constraints();
00778   }
00779 }

void Parma_Polyhedra_Library::Polyhedron::update_constraints (  )  const [private]

Updates constraints starting from generators and minimizes them.

The resulting system of constraints is only partially sorted: the equalities are in the upper part of the matrix, while the inequalities in the lower part.

Definition at line 782 of file Polyhedron_nonpublic.cc.

References clear_sat_g_up_to_date(), con_sys, gen_sys, generators_are_up_to_date(), has_something_pending(), marked_empty(), minimize(), sat_c, set_constraints_minimized(), set_generators_minimized(), set_sat_c_up_to_date(), and space_dim.

Referenced by add_constraint(), add_recycled_constraints(), concatenate_assign(), constraints(), H79_widening_assign(), intersection_assign(), intersection_assign_and_minimize(), is_included_in(), minimize(), and relation_with().

00782                                         {
00783   assert(space_dim > 0);
00784   assert(!marked_empty());
00785   assert(generators_are_up_to_date());
00786   // We assume the polyhedron has no pending constraints or generators.
00787   assert(!has_something_pending());
00788 
00789   Polyhedron& x = const_cast<Polyhedron&>(*this);
00790   minimize(false, x.gen_sys, x.con_sys, x.sat_c);
00791   // `sat_c' is the only saturation matrix up-to-date.
00792   x.set_sat_c_up_to_date();
00793   x.clear_sat_g_up_to_date();
00794   // The system of constraints and the system of generators
00795   // are minimized.
00796   x.set_constraints_minimized();
00797   x.set_generators_minimized();
00798 }

bool Parma_Polyhedra_Library::Polyhedron::update_generators (  )  const [private]

Updates generators starting from constraints and minimizes them.

Returns:
false if and only if *this turns out to be an empty polyhedron.
The resulting system of generators is only partially sorted: the lines are in the upper part of the matrix, while rays and points are in the lower part. It is illegal to call this method when the Status field already declares the polyhedron to be empty.

Definition at line 801 of file Polyhedron_nonpublic.cc.

References clear_sat_c_up_to_date(), con_sys, constraints_are_up_to_date(), empty, gen_sys, has_something_pending(), marked_empty(), minimize(), sat_g, set_constraints_minimized(), set_empty(), set_generators_minimized(), set_sat_g_up_to_date(), and space_dim.

Referenced by add_generator(), bounds(), generators(), is_bounded(), limited_BHRZ03_extrapolation_assign(), limited_H79_extrapolation_assign(), map_space_dimensions(), max_min(), minimize(), poly_hull_assign(), poly_hull_assign_and_minimize(), relation_with(), remove_higher_space_dimensions(), remove_space_dimensions(), and time_elapse_assign().

00801                                        {
00802   assert(space_dim > 0);
00803   assert(!marked_empty());
00804   assert(constraints_are_up_to_date());
00805   // We assume the polyhedron has no pending constraints or generators.
00806   assert(!has_something_pending());
00807 
00808   Polyhedron& x = const_cast<Polyhedron&>(*this);
00809   // If the system of constraints is not consistent the
00810   // polyhedron is empty.
00811   const bool empty = minimize(true, x.con_sys, x.gen_sys, x.sat_g);
00812   if (empty)
00813     x.set_empty();
00814   else {
00815     // `sat_g' is the only saturation matrix up-to-date.
00816     x.set_sat_g_up_to_date();
00817     x.clear_sat_c_up_to_date();
00818     // The system of constraints and the system of generators
00819     // are minimized.
00820     x.set_constraints_minimized();
00821     x.set_generators_minimized();
00822   }
00823   return !empty;
00824 }

void Parma_Polyhedra_Library::Polyhedron::update_sat_c (  )  const [private]

Updates sat_c using the updated constraints and generators.

It is assumed that constraints and generators are up-to-date and minimized and that the Status field does not already flag sat_c to be up-to-date. The values of the saturation matrix are computed as follows:

\[ \begin{cases} sat\_c[i][j] = 0, \quad \text{if } G[i] \cdot C^\mathrm{T}[j] = 0; \\ sat\_c[i][j] = 1, \quad \text{if } G[i] \cdot C^\mathrm{T}[j] > 0. \end{cases} \]

Definition at line 827 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Saturation_Matrix::clear(), con_sys, constraints_are_minimized(), Parma_Polyhedra_Library::Linear_System::first_pending_row(), gen_sys, generators_are_minimized(), Parma_Polyhedra_Library::Saturation_Matrix::resize(), sat_c, sat_c_is_up_to_date(), set_sat_c_up_to_date(), and Parma_Polyhedra_Library::Scalar_Products::sign().

Referenced by add_space_dimensions_and_embed(), and obtain_sorted_constraints_with_sat_c().

00827                                   {
00828   assert(constraints_are_minimized());
00829   assert(generators_are_minimized());
00830   assert(!sat_c_is_up_to_date());
00831 
00832   // We only consider non-pending rows.
00833   const dimension_type csr = con_sys.first_pending_row();
00834   const dimension_type gsr = gen_sys.first_pending_row();
00835   Polyhedron& x = const_cast<Polyhedron&>(*this);
00836 
00837   // The columns of `sat_c' represent the constraints and
00838   // its rows represent the generators: resize accordingly.
00839   x.sat_c.resize(gsr, csr);
00840   for (dimension_type i = gsr; i-- > 0; )
00841     for (dimension_type j = csr; j-- > 0; ) {
00842       const int sp_sign = Scalar_Products::sign(con_sys[j], gen_sys[i]);
00843       // The negativity of this scalar product would mean
00844       // that the generator `gen_sys[i]' violates the constraint
00845       // `con_sys[j]' and it is not possible because both generators
00846       // and constraints are up-to-date.
00847       assert(sp_sign >= 0);
00848       if (sp_sign > 0)
00849         // `gen_sys[i]' satisfies (without saturate) `con_sys[j]'.
00850         x.sat_c[i].set(j);
00851       else
00852         // `gen_sys[i]' saturates `con_sys[j]'.
00853         x.sat_c[i].clear(j);
00854     }
00855   x.set_sat_c_up_to_date();
00856 }

void Parma_Polyhedra_Library::Polyhedron::update_sat_g (  )  const [private]

Updates sat_g using the updated constraints and generators.

It is assumed that constraints and generators are up-to-date and minimized and that the Status field does not already flag sat_g to be up-to-date. The values of the saturation matrix are computed as follows:

\[ \begin{cases} sat\_g[i][j] = 0, \quad \text{if } C[i] \cdot G^\mathrm{T}[j] = 0; \\ sat\_g[i][j] = 1, \quad \text{if } C[i] \cdot G^\mathrm{T}[j] > 0. \end{cases} \]

Definition at line 859 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Saturation_Matrix::clear(), con_sys, constraints_are_minimized(), Parma_Polyhedra_Library::Linear_System::first_pending_row(), gen_sys, generators_are_minimized(), Parma_Polyhedra_Library::Saturation_Matrix::resize(), sat_g, sat_g_is_up_to_date(), set_sat_g_up_to_date(), and Parma_Polyhedra_Library::Scalar_Products::sign().

Referenced by add_space_dimensions_and_project(), obtain_sorted_generators_with_sat_g(), and select_H79_constraints().

00859                                   {
00860   assert(constraints_are_minimized());
00861   assert(generators_are_minimized());
00862   assert(!sat_g_is_up_to_date());
00863 
00864   // We only consider non-pending rows.
00865   const dimension_type csr = con_sys.first_pending_row();
00866   const dimension_type gsr = gen_sys.first_pending_row();
00867   Polyhedron& x = const_cast<Polyhedron&>(*this);
00868 
00869   // The columns of `sat_g' represent generators and its
00870   // rows represent the constraints: resize accordingly.
00871   x.sat_g.resize(csr, gsr);
00872   for (dimension_type i = csr; i-- > 0; )
00873     for (dimension_type j = gsr; j-- > 0; ) {
00874       const int sp_sign = Scalar_Products::sign(con_sys[i], gen_sys[j]);
00875       // The negativity of this scalar product would mean
00876       // that the generator `gen_sys[j]' violates the constraint
00877       // `con_sys[i]' and it is not possible because both generators
00878       // and constraints are up-to-date.
00879       assert(sp_sign >= 0);
00880       if (sp_sign > 0)
00881         // `gen_sys[j]' satisfies (without saturate) `con_sys[i]'.
00882         x.sat_g[i].set(j);
00883       else
00884         // `gen_sys[j]' saturates `con_sys[i]'.
00885         x.sat_g[i].clear(j);
00886     }
00887   x.set_sat_g_up_to_date();
00888 }

void Parma_Polyhedra_Library::Polyhedron::obtain_sorted_constraints (  )  const [private]

Sorts the matrix of constraints keeping status consistency.

It is assumed that constraints are up-to-date. If at least one of the saturation matrices is up-to-date, then sat_g is kept consistent with the sorted matrix of constraints. The method is declared const because reordering the constraints does not modify the polyhedron from a logical point of view.

Definition at line 891 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Linear_System::check_sorted(), clear_sat_c_up_to_date(), con_sys, constraints_are_up_to_date(), Parma_Polyhedra_Library::Linear_System::is_sorted(), sat_c, sat_c_is_up_to_date(), sat_g, sat_g_is_up_to_date(), set_sat_g_up_to_date(), Parma_Polyhedra_Library::Linear_System::sort_and_remove_with_sat(), Parma_Polyhedra_Library::Linear_System::sort_rows(), and Parma_Polyhedra_Library::Saturation_Matrix::transpose_assign().

Referenced by constraints(), intersection_assign_and_minimize(), is_universe(), and quick_equivalence_test().

00891                                                {
00892   assert(constraints_are_up_to_date());
00893   // `con_sys' will be sorted up to `index_first_pending'.
00894   Polyhedron& x = const_cast<Polyhedron&>(*this);
00895   if (!x.con_sys.is_sorted())
00896     if (x.sat_g_is_up_to_date()) {
00897       // Sorting constraints keeping `sat_g' consistent.
00898       x.con_sys.sort_and_remove_with_sat(x.sat_g);
00899       // `sat_c' is not up-to-date anymore.
00900       x.clear_sat_c_up_to_date();
00901     }
00902     else if (x.sat_c_is_up_to_date()) {
00903       // Using `sat_c' to obtain `sat_g', then it is like previous case.
00904       x.sat_g.transpose_assign(x.sat_c);
00905       x.con_sys.sort_and_remove_with_sat(x.sat_g);
00906       x.set_sat_g_up_to_date();
00907       x.clear_sat_c_up_to_date();
00908     }
00909     else
00910       // If neither `sat_g' nor `sat_c' are up-to-date,
00911       // we just sort the constraints.
00912       x.con_sys.sort_rows();
00913 
00914   assert(con_sys.check_sorted());
00915 }

void Parma_Polyhedra_Library::Polyhedron::obtain_sorted_generators (  )  const [private]

Sorts the matrix of generators keeping status consistency.

It is assumed that generators are up-to-date. If at least one of the saturation matrices is up-to-date, then sat_c is kept consistent with the sorted matrix of generators. The method is declared const because reordering the generators does not modify the polyhedron from a logical point of view.

Definition at line 918 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Linear_System::check_sorted(), clear_sat_g_up_to_date(), gen_sys, generators_are_up_to_date(), Parma_Polyhedra_Library::Linear_System::is_sorted(), sat_c, sat_c_is_up_to_date(), sat_g, sat_g_is_up_to_date(), set_sat_c_up_to_date(), Parma_Polyhedra_Library::Linear_System::sort_and_remove_with_sat(), Parma_Polyhedra_Library::Linear_System::sort_rows(), and Parma_Polyhedra_Library::Saturation_Matrix::transpose_assign().

Referenced by generators(), poly_hull_assign_and_minimize(), and quick_equivalence_test().

00918                                               {
00919   assert(generators_are_up_to_date());
00920   // `gen_sys' will be sorted up to `index_first_pending'.
00921   Polyhedron& x = const_cast<Polyhedron&>(*this);
00922   if (!x.gen_sys.is_sorted())
00923     if (x.sat_c_is_up_to_date()) {
00924       // Sorting generators keeping 'sat_c' consistent.
00925       x.gen_sys.sort_and_remove_with_sat(x.sat_c);
00926       // `sat_g' is not up-to-date anymore.
00927       x.clear_sat_g_up_to_date();
00928     }
00929     else if (x.sat_g_is_up_to_date()) {
00930       // Obtaining `sat_c' from `sat_g' and proceeding like previous case.
00931       x.sat_c.transpose_assign(x.sat_g);
00932       x.gen_sys.sort_and_remove_with_sat(x.sat_c);
00933       x.set_sat_c_up_to_date();
00934       x.clear_sat_g_up_to_date();
00935     }
00936     else
00937       // If neither `sat_g' nor `sat_c' are up-to-date, we just sort
00938       // the generators.
00939       x.gen_sys.sort_rows();
00940 
00941   assert(gen_sys.check_sorted());
00942 }

void Parma_Polyhedra_Library::Polyhedron::obtain_sorted_constraints_with_sat_c (  )  const [private]

Sorts the matrix of constraints and updates sat_c.

It is assumed that both constraints and generators are up-to-date and minimized. The method is declared const because reordering the constraints does not modify the polyhedron from a logical point of view.

Definition at line 945 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Linear_System::check_sorted(), con_sys, constraints_are_minimized(), constraints_are_up_to_date(), Parma_Polyhedra_Library::Linear_System::is_sorted(), sat_c, sat_c_is_up_to_date(), sat_g, sat_g_is_up_to_date(), set_sat_c_up_to_date(), set_sat_g_up_to_date(), Parma_Polyhedra_Library::Linear_System::set_sorted(), Parma_Polyhedra_Library::Linear_System::sort_and_remove_with_sat(), Parma_Polyhedra_Library::Saturation_Matrix::transpose_assign(), and update_sat_c().

Referenced by add_recycled_constraints_and_minimize(), intersection_assign_and_minimize(), and process_pending_constraints().

00945                                                           {
00946   assert(constraints_are_up_to_date());
00947   assert(constraints_are_minimized());
00948   // `con_sys' will be sorted up to `index_first_pending'.
00949   Polyhedron& x = const_cast<Polyhedron&>(*this);
00950   // At least one of the saturation matrices must be up-to-date.
00951   if (!x.sat_c_is_up_to_date() && !x.sat_g_is_up_to_date())
00952     x.update_sat_c();
00953 
00954   if (x.con_sys.is_sorted()) {
00955     if (x.sat_c_is_up_to_date())
00956       // If constraints are already sorted and sat_c is up to
00957       // date there is nothing to do.
00958       return;
00959   }
00960   else {
00961     if (!x.sat_g_is_up_to_date()) {
00962       // If constraints are not sorted and sat_g is not up-to-date
00963       // we obtain sat_g from sat_c (that has to be up-to-date)...
00964       x.sat_g.transpose_assign(x.sat_c);
00965       x.set_sat_g_up_to_date();
00966     }
00967     // ... and sort it together with constraints.
00968     x.con_sys.sort_and_remove_with_sat(x.sat_g);
00969   }
00970   // Obtaining sat_c from sat_g.
00971   x.sat_c.transpose_assign(x.sat_g);
00972   x.set_sat_c_up_to_date();
00973   // Constraints are sorted now.
00974   x.con_sys.set_sorted(true);
00975 
00976   assert(con_sys.check_sorted());
00977 }

void Parma_Polyhedra_Library::Polyhedron::obtain_sorted_generators_with_sat_g (  )  const [private]

Sorts the matrix of generators and updates sat_g.

It is assumed that both constraints and generators are up-to-date and minimized. The method is declared const because reordering the generators does not modify the polyhedron from a logical point of view.

Definition at line 980 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Linear_System::check_sorted(), gen_sys, generators_are_up_to_date(), Parma_Polyhedra_Library::Linear_System::is_sorted(), sat_c, sat_c_is_up_to_date(), sat_g, sat_g_is_up_to_date(), set_sat_c_up_to_date(), set_sat_g_up_to_date(), Parma_Polyhedra_Library::Linear_System::set_sorted(), Parma_Polyhedra_Library::Linear_System::sort_and_remove_with_sat(), Parma_Polyhedra_Library::Saturation_Matrix::transpose_assign(), and update_sat_g().

Referenced by add_recycled_generators_and_minimize(), poly_hull_assign_and_minimize(), and process_pending_generators().

00980                                                          {
00981   assert(generators_are_up_to_date());
00982   // `gen_sys' will be sorted up to `index_first_pending'.
00983   Polyhedron& x = const_cast<Polyhedron&>(*this);
00984   // At least one of the saturation matrices must be up-to-date.
00985   if (!x.sat_c_is_up_to_date() && !x.sat_g_is_up_to_date())
00986     x.update_sat_g();
00987 
00988   if (x.gen_sys.is_sorted()) {
00989     if (x.sat_g_is_up_to_date())
00990       // If generators are already sorted and sat_g is up to
00991       // date there is nothing to do.
00992       return;
00993   }
00994   else {
00995     if (!x.sat_c_is_up_to_date()) {
00996       // If generators are not sorted and sat_c is not up-to-date
00997       // we obtain sat_c from sat_g (that has to be up-to-date)...
00998       x.sat_c.transpose_assign(x.sat_g);
00999       x.set_sat_c_up_to_date();
01000     }
01001     // ... and sort it together with generators.
01002     x.gen_sys.sort_and_remove_with_sat(x.sat_c);
01003   }
01004   // Obtaining sat_g from sat_c.
01005   x.sat_g.transpose_assign(sat_c);
01006   x.set_sat_g_up_to_date();
01007   // Generators are sorted now.
01008   x.gen_sys.set_sorted(true);
01009 
01010   assert(gen_sys.check_sorted());
01011 }

bool Parma_Polyhedra_Library::Polyhedron::minimize (  )  const [private]

Applies (weak) minimization to both the constraints and generators.

Returns:
false if and only if *this turns out to be an empty polyhedron.
Minimization is not attempted if the Status field already declares both systems to be minimized.

Definition at line 1014 of file Polyhedron_nonpublic.cc.

References constraints_are_minimized(), constraints_are_up_to_date(), generators_are_minimized(), generators_are_up_to_date(), has_something_pending(), marked_empty(), OK(), process_pending(), space_dim, update_constraints(), and update_generators().

Referenced by add_recycled_constraints_and_minimize(), add_recycled_generators(), add_recycled_generators_and_minimize(), affine_image(), affine_preimage(), is_empty(), is_universe(), minimized_constraints(), minimized_generators(), OK(), poly_hull_assign_and_minimize(), strongly_minimize_constraints(), strongly_minimize_generators(), update_constraints(), and update_generators().

01014                               {
01015   // 0-dim space or empty polyhedra are already minimized.
01016   if (marked_empty())
01017     return false;
01018   if (space_dim == 0)
01019     return true;
01020 
01021   // If the polyhedron has something pending, process it.
01022   if (has_something_pending()) {
01023     const bool not_empty = process_pending();
01024     assert(OK());
01025     return not_empty;
01026   }
01027 
01028   // Here there are no pending constraints or generators.
01029   // Is the polyhedron already minimized?
01030   if (constraints_are_minimized() && generators_are_minimized())
01031     return true;
01032 
01033   // If constraints or generators are up-to-date, invoking
01034   // update_generators() or update_constraints(), respectively,
01035   // minimizes both constraints and generators.
01036   // If both are up-to-date it does not matter whether we use
01037   // update_generators() or update_constraints():
01038   // both minimize constraints and generators.
01039   if (constraints_are_up_to_date()) {
01040     // We may discover here that `*this' is empty.
01041     const bool ret = update_generators();
01042     assert(OK());
01043     return ret;
01044   }
01045   else {
01046     assert(generators_are_up_to_date());
01047     update_constraints();
01048     assert(OK());
01049     return true;
01050   }
01051 }

bool Parma_Polyhedra_Library::Polyhedron::strongly_minimize_constraints (  )  const [private]

Applies strong minimization to the constraints of an NNC polyhedron.

Returns:
false if and only if *this turns out to be an empty polyhedron.

Definition at line 1054 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::LP_Problem::add_constraints(), Parma_Polyhedra_Library::Saturation_Row::clear(), clear_generators_up_to_date(), Parma_Polyhedra_Library::Generator::CLOSURE_POINT, con_sys, Parma_Polyhedra_Library::Constraint::epsilon_leq_one(), Parma_Polyhedra_Library::Matrix::erase_to_end(), gen_sys, Parma_Polyhedra_Library::Constraint_System::insert(), is_necessarily_closed(), Parma_Polyhedra_Library::MAXIMIZATION, minimize(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Generator_System::num_lines(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), Parma_Polyhedra_Library::Generator::POINT, Parma_Polyhedra_Library::Generator::RAY, sat_c, sat_c_is_up_to_date(), sat_g, sat_g_is_up_to_date(), Parma_Polyhedra_Library::Saturation_Row::set(), Parma_Polyhedra_Library::Linear_System::set_necessarily_closed(), Parma_Polyhedra_Library::Linear_System::set_not_necessarily_closed(), Parma_Polyhedra_Library::LP_Problem::set_objective_function(), Parma_Polyhedra_Library::LP_Problem::set_optimization_mode(), Parma_Polyhedra_Library::Linear_System::set_sorted(), Parma_Polyhedra_Library::LP_Problem::solve(), space_dim, status, Parma_Polyhedra_Library::Saturation_Matrix::transpose_assign(), Parma_Polyhedra_Library::UNBOUNDED_LP_PROBLEM, Parma_Polyhedra_Library::UNFEASIBLE_LP_PROBLEM, and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

Referenced by is_topologically_closed(), and minimized_constraints().

01054                                                    {
01055   assert(!is_necessarily_closed());
01056 
01057   // From the user perspective, the polyhedron will not change.
01058   Polyhedron& x = const_cast<Polyhedron&>(*this);
01059 
01060   // We need `con_sys' (weakly) minimized and `gen_sys' up-to-date.
01061   // `minimize()' will process any pending constraints or generators.
01062   if (!minimize())
01063     return false;
01064 
01065   // If the polyhedron `*this' is zero-dimensional
01066   // at this point it must be a universe polyhedron.
01067   if (x.space_dim == 0)
01068     return true;
01069 
01070   // We also need `sat_g' up-to-date.
01071   if (!sat_g_is_up_to_date()) {
01072     assert(sat_c_is_up_to_date());
01073     x.sat_g.transpose_assign(sat_c);
01074   }
01075 
01076   // These Saturation_Row's will be later used as masks in order to
01077   // check saturation conditions restricted to particular subsets of
01078   // the generator system.
01079   Saturation_Row sat_all_but_rays;
01080   Saturation_Row sat_all_but_points;
01081   Saturation_Row sat_all_but_closure_points;
01082 
01083   const dimension_type gs_rows = gen_sys.num_rows();
01084   const dimension_type n_lines = gen_sys.num_lines();
01085   for (dimension_type i = gs_rows; i-- > n_lines; )
01086     switch (gen_sys[i].type()) {
01087     case Generator::RAY:
01088       sat_all_but_rays.set(i);
01089       break;
01090     case Generator::POINT:
01091       sat_all_but_points.set(i);
01092       break;
01093     case Generator::CLOSURE_POINT:
01094       sat_all_but_closure_points.set(i);
01095       break;
01096     default:
01097       // Found a line with index i >= n_lines.
01098       throw std::runtime_error("PPL internal error: "
01099                                "strongly_minimize_constraints.");
01100     }
01101   Saturation_Row sat_lines_and_rays;
01102   set_union(sat_all_but_points, sat_all_but_closure_points,
01103             sat_lines_and_rays);
01104   Saturation_Row sat_lines_and_closure_points;
01105   set_union(sat_all_but_rays, sat_all_but_points,
01106             sat_lines_and_closure_points);
01107   Saturation_Row sat_lines;
01108   set_union(sat_lines_and_rays, sat_lines_and_closure_points,
01109             sat_lines);
01110 
01111   // These flags are maintained to later decide if we have to add the
01112   // eps_leq_one constraint and whether or not the constraint system
01113   // was changed.
01114   bool changed = false;
01115   bool found_eps_leq_one = false;
01116 
01117   // For all the strict inequalities in `con_sys', check for
01118   // eps-redundancy and eventually move them to the bottom part of the
01119   // system.
01120   Constraint_System& cs = x.con_sys;
01121   Saturation_Matrix& sat = x.sat_g;
01122   dimension_type cs_rows = cs.num_rows();
01123   const dimension_type eps_index = cs.num_columns() - 1;
01124   for (dimension_type i = 0; i < cs_rows; )
01125     if (cs[i].is_strict_inequality()) {
01126       // First, check if it is saturated by no closure points
01127       Saturation_Row sat_ci;
01128       set_union(sat[i], sat_lines_and_closure_points, sat_ci);
01129       if (sat_ci == sat_lines) {
01130         // It is saturated by no closure points.
01131         if (!found_eps_leq_one) {
01132           // Check if it is the eps_leq_one constraint.
01133           const Constraint& c = cs[i];
01134           bool all_zeroes = true;
01135           for (dimension_type k = eps_index; k-- > 1; )
01136             if (c[k] != 0) {
01137               all_zeroes = false;
01138               break;
01139             }
01140           if (all_zeroes && (c[0] + c[eps_index] == 0)) {
01141             // We found the eps_leq_one constraint.
01142             found_eps_leq_one = true;
01143             // Consider next constraint.
01144             ++i;
01145             continue;
01146           }
01147         }
01148         // Here `cs[i]' is not the eps_leq_one constraint,
01149         // so it is eps-redundant.
01150         // Move it to the bottom of the constraint system,
01151         // while keeping `sat_g' consistent.
01152         --cs_rows;
01153         std::swap(cs[i], cs[cs_rows]);
01154         std::swap(sat[i], sat[cs_rows]);
01155         // The constraint system is changed.
01156         changed = true;
01157         // Continue by considering next constraint,
01158         // which is already in place due to the swap.
01159         continue;
01160       }
01161       // Now we check if there exists another strict inequality
01162       // constraint having a superset of its saturators,
01163       // when disregarding points.
01164       sat_ci.clear();
01165       set_union(sat[i], sat_all_but_points, sat_ci);
01166       bool eps_redundant = false;
01167       for (dimension_type j = 0; j < cs_rows; ++j)
01168         if (i != j && cs[j].is_strict_inequality()
01169             && subset_or_equal(sat[j], sat_ci)) {
01170           // Constraint `cs[i]' is eps-redundant:
01171           // move it to the bottom of the constraint system,
01172           // while keeping `sat_g' consistent.
01173           --cs_rows;
01174           std::swap(cs[i], cs[cs_rows]);
01175           std::swap(sat[i], sat[cs_rows]);
01176           eps_redundant = true;
01177           // The constraint system is changed.
01178           changed = true;
01179           break;
01180         }
01181       // Continue with next constraint, which is already in place
01182       // due to the swap if we have found an eps-redundant constraint.
01183       if (!eps_redundant)
01184         ++i;
01185     }
01186     else
01187       // `cs[i]' is not a strict inequality: consider next constraint.
01188       ++i;
01189 
01190   if (changed) {
01191     // If the constraint system has been changed, we have to erase
01192     // the epsilon-redundant constraints.
01193     assert(cs_rows < cs.num_rows());
01194     cs.erase_to_end(cs_rows);
01195     // The remaining constraints are not pending.
01196     cs.unset_pending_rows();
01197     // The constraint system is no longer sorted.
01198     cs.set_sorted(false);
01199     // The generator system is no longer up-to-date.
01200     x.clear_generators_up_to_date();
01201 
01202     // If we haven't found an upper bound for the epsilon dimension,
01203     // then we have to check whether such an upper bound is implied
01204     // by the remaining constraints (exploiting teh simplex algorithm).
01205     if (!found_eps_leq_one) {
01206       LP_Problem lp;
01207       // KLUDGE: temporarily mark the constraint system as if it was
01208       // necessarily closed, so that we can interpret the epsilon
01209       // dimension as a standard dimension. Be careful to reset the
01210       // topology of `cs' even on exceptional execution path.
01211       cs.set_necessarily_closed();
01212       try {
01213         lp.add_constraints(cs);
01214         cs.set_not_necessarily_closed();
01215       }
01216       catch (...) {
01217         cs.set_not_necessarily_closed();
01218         throw;
01219       }
01220       // The objective function is `epsilon'.
01221       lp.set_objective_function(Variable(x.space_dim));
01222       lp.set_optimization_mode(MAXIMIZATION);
01223       LP_Problem_Status status = lp.solve();
01224       assert(status != UNFEASIBLE_LP_PROBLEM);
01225       // If the epsilon dimension is actually unbounded,
01226       // then add the eps_leq_one constraint.
01227       if (status == UNBOUNDED_LP_PROBLEM)
01228         cs.insert(Constraint::epsilon_leq_one());
01229     }
01230   }
01231 
01232   assert(OK());
01233   return true;
01234 }

bool Parma_Polyhedra_Library::Polyhedron::strongly_minimize_generators (  )  const [private]

Applies strong minimization to the generators of an NNC polyhedron.

Returns:
false if and only if *this turns out to be an empty polyhedron.

Definition at line 1237 of file Polyhedron_nonpublic.cc.

References clear_constraints_up_to_date(), con_sys, Parma_Polyhedra_Library::Matrix::erase_to_end(), gen_sys, is_necessarily_closed(), minimize(), Parma_Polyhedra_Library::Row::normalize(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Constraint_System::num_equalities(), Parma_Polyhedra_Library::Generator_System::num_lines(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), sat_c, sat_c_is_up_to_date(), sat_g, sat_g_is_up_to_date(), Parma_Polyhedra_Library::Saturation_Row::set(), Parma_Polyhedra_Library::Linear_System::set_sorted(), space_dim, Parma_Polyhedra_Library::Saturation_Matrix::transpose_assign(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

Referenced by minimized_generators().

01237                                                   {
01238   assert(!is_necessarily_closed());
01239 
01240   // From the user perspective, the polyhedron will not change.
01241   Polyhedron& x = const_cast<Polyhedron&>(*this);
01242 
01243   // We need `gen_sys' (weakly) minimized and `con_sys' up-to-date.
01244   // `minimize()' will process any pending constraints or generators.
01245   if (!minimize())
01246     return false;
01247 
01248   // If the polyhedron `*this' is zero-dimensional
01249   // at this point it must be a universe polyhedron.
01250   if (x.space_dim == 0)
01251     return true;
01252 
01253   // We also need `sat_c' up-to-date.
01254   if (!sat_c_is_up_to_date()) {
01255     assert(sat_g_is_up_to_date());
01256     x.sat_c.transpose_assign(sat_g);
01257   }
01258 
01259   // This Saturation_Row will have all and only the indexes
01260   // of strict inequalities set to 1.
01261   Saturation_Row sat_all_but_strict_ineq;
01262   const dimension_type cs_rows = con_sys.num_rows();
01263   const dimension_type n_equals = con_sys.num_equalities();
01264   for (dimension_type i = cs_rows; i-- > n_equals; )
01265     if (con_sys[i].is_strict_inequality())
01266       sat_all_but_strict_ineq.set(i);
01267 
01268   // Will record whether or not we changed the generator system.
01269   bool changed = false;
01270 
01271   // For all points in the generator system, check for eps-redundancy
01272   // and eventually move them to the bottom part of the system.
01273   Generator_System& gs = const_cast<Generator_System&>(gen_sys);
01274   Saturation_Matrix& sat = const_cast<Saturation_Matrix&>(sat_c);
01275   dimension_type gs_rows = gs.num_rows();
01276   const dimension_type n_lines = gs.num_lines();
01277   const dimension_type eps_index = gs.num_columns() - 1;
01278   for (dimension_type i = n_lines; i < gs_rows; )
01279     if (gs[i].is_point()) {
01280       // Compute the Saturation_Row corresponding to the candidate point
01281       // when strict inequality constraints are ignored.
01282       Saturation_Row sat_gi;
01283       set_union(sat[i], sat_all_but_strict_ineq, sat_gi);
01284       // Check if the candidate point is actually eps-redundant:
01285       // namely, if there exists another point that saturates
01286       // all the non-strict inequalities saturated by the candidate.
01287       bool eps_redundant = false;
01288       for (dimension_type j = n_lines; j < gs_rows; ++j)
01289         if (i != j && gs[j].is_point() && subset_or_equal(sat[j], sat_gi)) {
01290           // Point `gs[i]' is eps-redundant:
01291           // move it to the bottom of the generator system,
01292           // while keeping `sat_c' consistent.
01293           --gs_rows;
01294           std::swap(gs[i], gs[gs_rows]);
01295           std::swap(sat[i], sat[gs_rows]);
01296           eps_redundant = true;
01297           changed = true;
01298           break;
01299         }
01300       if (!eps_redundant) {
01301         // Let all point encodings have epsilon coordinate 1.
01302         Generator& gi = gs[i];
01303         if (gi[eps_index] != gi[0]) {
01304           gi[eps_index] = gi[0];
01305           // Enforce normalization.
01306           gi.normalize();
01307           changed = true;
01308         }
01309         // Consider next generator.
01310         ++i;
01311       }
01312     }
01313     else
01314       // Consider next generator.
01315       ++i;
01316 
01317   // If needed, erase the eps-redundant generators (also updating
01318   // `index_first_pending').
01319   if (gs_rows < gs.num_rows()) {
01320     gs.erase_to_end(gs_rows);
01321     gs.unset_pending_rows();
01322   }
01323 
01324   if (changed) {
01325     // The generator system is no longer sorted.
01326     x.gen_sys.set_sorted(false);
01327     // The constraint system is no longer up-to-date.
01328     x.clear_constraints_up_to_date();
01329   }
01330 
01331   assert(OK());
01332   return true;
01333 }

PPL::Polyhedron::Three_Valued_Boolean Parma_Polyhedra_Library::Polyhedron::quick_equivalence_test ( const Polyhedron y  )  const [private]

Polynomial but incomplete equivalence test between polyhedra.

Definition at line 329 of file Polyhedron_nonpublic.cc.

References con_sys, constraints_are_minimized(), gen_sys, generators_are_minimized(), has_something_pending(), marked_empty(), Parma_Polyhedra_Library::Constraint_System::num_equalities(), Parma_Polyhedra_Library::Generator_System::num_lines(), Parma_Polyhedra_Library::Matrix::num_rows(), obtain_sorted_constraints(), obtain_sorted_generators(), space_dim, topology(), TVB_DONT_KNOW, TVB_FALSE, and TVB_TRUE.

Referenced by contains().

00329                                                                {
00330   // Private method: the caller must ensure the following.
00331   assert(topology() == y.topology());
00332   assert(space_dim == y.space_dim);
00333   assert(!marked_empty() && !y.marked_empty() && space_dim > 0);
00334 
00335   const Polyhedron& x = *this;
00336 
00337   if (x.is_necessarily_closed()) {
00338     if (!x.has_something_pending() && !y.has_something_pending()) {
00339       bool css_normalized = false;
00340       if (x.constraints_are_minimized() && y.constraints_are_minimized()) {
00341         // Equivalent minimized constraint systems have:
00342         //  - the same number of constraints; ...
00343         if (x.con_sys.num_rows() != y.con_sys.num_rows())
00344           return Polyhedron::TVB_FALSE;
00345         //  - the same number of equalities; ...
00346         dimension_type x_num_equalities = x.con_sys.num_equalities();
00347         if (x_num_equalities != y.con_sys.num_equalities())
00348           return Polyhedron::TVB_FALSE;
00349         //  - if there are no equalities, they have the same constraints.
00350         //    Delay this test: try cheaper tests on generators first.
00351         css_normalized = (x_num_equalities == 0);
00352       }
00353 
00354       if (x.generators_are_minimized() && y.generators_are_minimized()) {
00355         // Equivalent minimized generator systems have:
00356         //  - the same number of generators; ...
00357         if (x.gen_sys.num_rows() != y.gen_sys.num_rows())
00358           return Polyhedron::TVB_FALSE;
00359         //  - the same number of lines; ...
00360         const dimension_type x_num_lines = x.gen_sys.num_lines();
00361         if (x_num_lines != y.gen_sys.num_lines())
00362           return Polyhedron::TVB_FALSE;
00363         //  - if there are no lines, they have the same generators.
00364         if (x_num_lines == 0) {
00365           // Sort the two systems and check for syntactic identity.
00366           x.obtain_sorted_generators();
00367           y.obtain_sorted_generators();
00368           if (x.gen_sys == y.gen_sys)
00369             return Polyhedron::TVB_TRUE;
00370           else
00371             return Polyhedron::TVB_FALSE;
00372         }
00373       }
00374 
00375       if (css_normalized) {
00376         // Sort the two systems and check for identity.
00377         x.obtain_sorted_constraints();
00378         y.obtain_sorted_constraints();
00379         if (x.con_sys == y.con_sys)
00380             return Polyhedron::TVB_TRUE;
00381           else
00382             return Polyhedron::TVB_FALSE;
00383       }
00384     }
00385   }
00386   return Polyhedron::TVB_DONT_KNOW;
00387 }

bool Parma_Polyhedra_Library::Polyhedron::is_included_in ( const Polyhedron y  )  const [private]

Returns true if and only if *this is included in y.

Definition at line 390 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Generator::CLOSURE_POINT, con_sys, constraints_are_minimized(), constraints_are_up_to_date(), Parma_Polyhedra_Library::Constraint::EQUALITY, has_pending_generators(), Parma_Polyhedra_Library::Constraint::is_inequality(), Parma_Polyhedra_Library::Generator::is_line(), Parma_Polyhedra_Library::Generator::LINE, marked_empty(), minimize(), Parma_Polyhedra_Library::Constraint::NONSTRICT_INEQUALITY, Parma_Polyhedra_Library::Matrix::num_rows(), OK(), Parma_Polyhedra_Library::Generator::POINT, process_pending_generators(), Parma_Polyhedra_Library::Generator::RAY, Parma_Polyhedra_Library::Scalar_Products::reduced_sign(), Parma_Polyhedra_Library::Scalar_Products::sign(), space_dim, Parma_Polyhedra_Library::Constraint::STRICT_INEQUALITY, topology(), Parma_Polyhedra_Library::Generator::type(), Parma_Polyhedra_Library::Constraint::type(), and update_constraints().

Referenced by contains().

00390                                                        {
00391   // Private method: the caller must ensure the following.
00392   assert(topology() == y.topology());
00393   assert(space_dim == y.space_dim);
00394   assert(!marked_empty() && !y.marked_empty() && space_dim > 0);
00395 
00396   const Polyhedron& x = *this;
00397 
00398   // `x' cannot have pending constraints, because we need its generators.
00399   if (x.has_pending_constraints() && !x.process_pending_constraints())
00400     return true;
00401   // `y' cannot have pending generators, because we need its constraints.
00402   if (y.has_pending_generators())
00403     y.process_pending_generators();
00404 
00405 #if BE_LAZY
00406   if (!x.generators_are_up_to_date() && !x.update_generators())
00407     return true;
00408   if (!y.constraints_are_up_to_date())
00409     y.update_constraints();
00410 #else
00411   if (!x.generators_are_minimized())
00412     x.minimize();
00413   if (!y.constraints_are_minimized())
00414     y.minimize();
00415 #endif
00416 
00417   assert(x.OK());
00418   assert(y.OK());
00419 
00420   const Generator_System& gs = x.gen_sys;
00421   const Constraint_System& cs = y.con_sys;
00422 
00423   if (x.is_necessarily_closed())
00424     // When working with necessarily closed polyhedra,
00425     // `x' is contained in `y' if and only if all the generators of `x'
00426     // satisfy all the inequalities and saturate all the equalities of `y'.
00427     // This comes from the definition of a polyhedron as the set of
00428     // vectors satisfying a constraint system and the fact that all
00429     // vectors in `x' can be obtained by suitably combining its generators.
00430     for (dimension_type i = cs.num_rows(); i-- > 0; ) {
00431       const Constraint& c = cs[i];
00432       if (c.is_inequality()) {
00433         for (dimension_type j = gs.num_rows(); j-- > 0; ) {
00434           const Generator& g = gs[j];
00435           const int sp_sign = Scalar_Products::sign(c, g);
00436           if (g.is_line()) {
00437             if (sp_sign != 0)
00438               return false;
00439           }
00440           else
00441             // `g' is a ray or a point.
00442             if (sp_sign < 0)
00443               return false;
00444         }
00445       }
00446       else {
00447         // `c' is an equality.
00448         for (dimension_type j = gs.num_rows(); j-- > 0; )
00449           if (Scalar_Products::sign(c, gs[j]) != 0)
00450             return false;
00451       }
00452     }
00453   else {
00454     // Here we have an NNC polyhedron: using the reduced scalar product,
00455     // which ignores the epsilon coefficient.
00456     for (dimension_type i = cs.num_rows(); i-- > 0; ) {
00457       const Constraint& c = cs[i];
00458       switch (c.type()) {
00459       case Constraint::NONSTRICT_INEQUALITY:
00460         for (dimension_type j = gs.num_rows(); j-- > 0; ) {
00461           const Generator& g = gs[j];
00462           const int sp_sign = Scalar_Products::reduced_sign(c, g);
00463           if (g.is_line()) {
00464             if (sp_sign != 0)
00465               return false;
00466           }
00467           else
00468             // `g' is a ray or a point or a closure point.
00469             if (sp_sign < 0)
00470               return false;
00471         }
00472         break;
00473       case Constraint::EQUALITY:
00474         for (dimension_type j = gs.num_rows(); j-- > 0; )
00475           if (Scalar_Products::reduced_sign(c, gs[j]) != 0)
00476             return false;
00477         break;
00478       case Constraint::STRICT_INEQUALITY:
00479         for (dimension_type j = gs.num_rows(); j-- > 0; ) {
00480           const Generator& g = gs[j];
00481           const int sp_sign = Scalar_Products::reduced_sign(c, g);
00482           switch (g.type()) {
00483           case Generator::POINT:
00484             // If a point violates or saturates a strict inequality
00485             // (when ignoring the epsilon coefficients) then it is
00486             // not included in the polyhedron.
00487             if (sp_sign <= 0)
00488               return false;
00489             break;
00490           case Generator::LINE:
00491             // Lines have to saturate all constraints.
00492             if (sp_sign != 0)
00493               return false;
00494             break;
00495           case Generator::RAY:
00496             // Intentionally fall through.
00497           case Generator::CLOSURE_POINT:
00498             // The generator is a ray or closure point: usual test.
00499             if (sp_sign < 0)
00500               return false;
00501             break;
00502           }
00503         }
00504         break;
00505       }
00506     }
00507   }
00508 
00509   // Inclusion holds.
00510   return true;
00511 }

bool Parma_Polyhedra_Library::Polyhedron::bounds ( const Linear_Expression expr,
bool  from_above 
) const [private]

Checks if and how expr is bounded in *this.

Returns true if and only if from_above is true and expr is bounded from above in *this, or from_above is false and expr is bounded from below in *this.

Parameters:
expr The linear expression to test;
from_above true if and only if the boundedness of interest is "from above".
Exceptions:
std::invalid_argument Thrown if expr and *this are dimension-incompatible.

Definition at line 514 of file Polyhedron_nonpublic.cc.

References gen_sys, generators_are_up_to_date(), has_pending_constraints(), Parma_Polyhedra_Library::Scalar_Products::homogeneous_sign(), Parma_Polyhedra_Library::Generator::is_line(), Parma_Polyhedra_Library::Generator::is_line_or_ray(), marked_empty(), Parma_Polyhedra_Library::Matrix::num_rows(), process_pending_constraints(), space_dim, Parma_Polyhedra_Library::Linear_Expression::space_dimension(), throw_dimension_incompatible(), and update_generators().

Referenced by bounds_from_above(), and bounds_from_below().

00515                                                      {
00516   // The dimension of `expr' should not be greater than the dimension
00517   // of `*this'.
00518   const dimension_type expr_space_dim = expr.space_dimension();
00519   if (space_dim < expr_space_dim)
00520     throw_dimension_incompatible((from_above
00521                                   ? "bounds_from_above(e)"
00522                                   : "bounds_from_below(e)"), "e", expr);
00523 
00524   // A zero-dimensional or empty polyhedron bounds everything.
00525   if (space_dim == 0
00526       || marked_empty()
00527       || (has_pending_constraints() && !process_pending_constraints())
00528       || (!generators_are_up_to_date() && !update_generators()))
00529     return true;
00530 
00531   // The polyhedron has updated, possibly pending generators.
00532   for (dimension_type i = gen_sys.num_rows(); i-- > 0; ) {
00533     const Generator& g = gen_sys[i];
00534     // Only lines and rays in `*this' can cause `expr' to be unbounded.
00535     if (g.is_line_or_ray()) {
00536       const int sp_sign = Scalar_Products::homogeneous_sign(expr, g);
00537       if (sp_sign != 0
00538           && (g.is_line()
00539               || (from_above && sp_sign > 0)
00540               || (!from_above && sp_sign < 0)))
00541         // `*this' does not bound `expr'.
00542         return false;
00543     }
00544   }
00545   // No sources of unboundedness have been found for `expr'
00546   // in the given direction.
00547   return true;
00548 }

bool Parma_Polyhedra_Library::Polyhedron::max_min ( const Linear_Expression expr,
const bool  maximize,
Coefficient ext_n,
Coefficient ext_d,
bool &  included,
Generator point 
) const [private]

Maximizes or minimizes expr subject to *this.

Parameters:
expr The linear expression to be maximized or minimized subject to this;
maximize true if maximization is what is wanted;
ext_n The numerator of the extremum value;
ext_d The denominator of the extremum value;
included true if and only if the extremum of expr can actually be reached in * this;
point When maximization or minimization succeeds, will be assigned a point or closure point where expr reaches the corresponding extremum value.
Exceptions:
std::invalid_argument Thrown if expr and *this are dimension-incompatible.
If *this is empty or expr is not bounded in the appropriate direction, false is returned and ext_n, ext_d, included and point are left untouched.

Definition at line 551 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::assign_r(), gen_sys, generators_are_up_to_date(), has_pending_constraints(), Parma_Polyhedra_Library::Scalar_Products::homogeneous_assign(), Parma_Polyhedra_Library::Linear_Expression::inhomogeneous_term(), Parma_Polyhedra_Library::Generator::is_closure_point(), Parma_Polyhedra_Library::Generator::is_line(), Parma_Polyhedra_Library::Generator::is_line_or_ray(), Parma_Polyhedra_Library::Generator::is_point(), marked_empty(), Parma_Polyhedra_Library::Matrix::num_rows(), process_pending_constraints(), space_dim, Parma_Polyhedra_Library::Linear_Expression::space_dimension(), TEMP_INTEGER, throw_dimension_incompatible(), and update_generators().

Referenced by maximize(), and minimize().

00555                                                  {
00556   // The dimension of `expr' should not be greater than the dimension
00557   // of `*this'.
00558   const dimension_type expr_space_dim = expr.space_dimension();
00559   if (space_dim < expr_space_dim)
00560     throw_dimension_incompatible((maximize
00561                                   ? "maximize(e, ...)"
00562                                   : "minimize(e, ...)"), "e", expr);
00563 
00564   // For an empty polyhedron we simply return false.
00565   if (marked_empty()
00566       || (has_pending_constraints() && !process_pending_constraints())
00567       || (!generators_are_up_to_date() && !update_generators()))
00568     return false;
00569 
00570   // The polyhedron has updated, possibly pending generators.
00571   // The following loop will iterate through the generator
00572   // to find the extremum.
00573   mpq_class extremum;
00574 
00575   // True if we have no other candidate extremum to compare with.
00576   bool first_candidate = true;
00577 
00578   // To store the position of the current candidate extremum.
00579   // Initialized only to avoid a compiler warning.
00580   dimension_type ext_position = 0;
00581 
00582   // Whether the current candidate extremum is included or not.
00583   // Initialized only to avoid a compiler warning.
00584   bool ext_included = false;
00585 
00586   TEMP_INTEGER(sp);
00587   for (dimension_type i = gen_sys.num_rows(); i-- > 0; ) {
00588     const Generator& g = gen_sys[i];
00589     Scalar_Products::homogeneous_assign(sp, expr, g);
00590     // Lines and rays in `*this' can cause `expr' to be unbounded.
00591     if (g.is_line_or_ray()) {
00592       const int sp_sign = sgn(sp);
00593       if (sp_sign != 0
00594           && (g.is_line()
00595               || (maximize && sp_sign > 0)
00596               || (!maximize && sp_sign < 0)))
00597         // `expr' is unbounded in `*this'.
00598         return false;
00599     }
00600     else {
00601       // We have a point or a closure point.
00602       assert(g.is_point() || g.is_closure_point());
00603       // Notice that we are ignoring the constant term in `expr' here.
00604       // We will add it to the extremum as soon as we find it.
00605       mpq_class candidate;
00606       assign_r(candidate.get_num(), sp, ROUND_NOT_NEEDED);
00607       assign_r(candidate.get_den(), g[0], ROUND_NOT_NEEDED);
00608       candidate.canonicalize();
00609       const bool g_is_point = g.is_point();
00610       if (first_candidate
00611           || (maximize
00612               && (candidate > extremum
00613                   || (g_is_point
00614                       && !ext_included
00615                       && candidate == extremum)))
00616           || (!maximize
00617               && (candidate < extremum
00618                   || (g_is_point
00619                       && !ext_included
00620                       && candidate == extremum)))) {
00621         // We have a (new) candidate extremum.
00622         first_candidate = false;
00623         extremum = candidate;
00624         ext_position = i;
00625         ext_included = g_is_point;
00626       }
00627     }
00628   }
00629 
00630   // Add in the constant term in `expr'.
00631   mpz_class n;
00632   assign_r(n, expr.inhomogeneous_term(), ROUND_NOT_NEEDED);
00633   extremum += n;
00634 
00635   // The polyhedron is bounded in the right direction and we have
00636   // computed the extremum: write the result into the caller's structures.
00637   assert(!first_candidate);
00638   ext_n = Coefficient(extremum.get_num());
00639   ext_d = Coefficient(extremum.get_den());
00640   included = ext_included;
00641   point = gen_sys[ext_position];
00642 
00643   return true;
00644 }

void Parma_Polyhedra_Library::Polyhedron::select_CH78_constraints ( const Polyhedron y,
Constraint_System cs_selected 
) const [private]

Copies to cs_selection the constraints of y corresponding to the definition of the CH78-widening of *this and y.

Definition at line 40 of file Polyhedron_widenings.cc.

References con_sys, constraints_are_minimized(), gen_sys, generators_are_up_to_date(), has_pending_constraints(), has_something_pending(), Parma_Polyhedra_Library::Constraint_System::insert(), marked_empty(), Parma_Polyhedra_Library::Matrix::num_rows(), Parma_Polyhedra_Library::Generator_System::satisfied_by_all_generators(), space_dim, Parma_Polyhedra_Library::Linear_System::topology(), and topology().

Referenced by H79_widening_assign().

00041                                                                  {
00042   // Private method: the caller must ensure the following conditions.
00043   assert(topology() == y.topology()
00044          && topology() == cs_selection.topology()
00045          && space_dim == y.space_dim);
00046   assert(!marked_empty()
00047          && !has_pending_constraints()
00048          && generators_are_up_to_date());
00049   assert(!y.marked_empty()
00050          && !y.has_something_pending()
00051          && y.constraints_are_minimized());
00052 
00053   // A constraint in `y.con_sys' is copied to `cs_selection'
00054   // if it is satisfied by all the generators of `gen_sys'.
00055 
00056   // Note: the loop index `i' goes upward to avoid reversing
00057   // the ordering of the chosen constraints.
00058   for (dimension_type i = 0, end = y.con_sys.num_rows(); i < end; ++i) {
00059     const Constraint& c = y.con_sys[i];
00060     if (gen_sys.satisfied_by_all_generators(c))
00061       cs_selection.insert(c);
00062   }
00063 }

void Parma_Polyhedra_Library::Polyhedron::select_H79_constraints ( const Polyhedron y,
Constraint_System cs_selected,
Constraint_System cs_not_selected 
) const [private]

Splits the constraints of `x' into two subsets, depending on whether or not they are selected to compute the H79-widening of *this and y.

Definition at line 67 of file Polyhedron_widenings.cc.

References Parma_Polyhedra_Library::Saturation_Row::clear(), con_sys, constraints_are_minimized(), constraints_are_up_to_date(), gen_sys, generators_are_up_to_date(), has_pending_generators(), has_something_pending(), Parma_Polyhedra_Library::Constraint_System::insert(), marked_empty(), Parma_Polyhedra_Library::Matrix::num_rows(), Parma_Polyhedra_Library::Saturation_Matrix::rows_erase_to_end(), sat_g, sat_g_is_up_to_date(), Parma_Polyhedra_Library::Saturation_Row::set(), Parma_Polyhedra_Library::Scalar_Products::sign(), Parma_Polyhedra_Library::Saturation_Matrix::sort_rows(), Parma_Polyhedra_Library::Saturation_Matrix::sorted_contains(), space_dim, Parma_Polyhedra_Library::Linear_System::topology(), topology(), and update_sat_g().

Referenced by BHRZ03_widening_assign(), and H79_widening_assign().

00069                                                                    {
00070   // Private method: the caller must ensure the following conditions
00071   // (beside the inclusion `y <= x').
00072   assert(topology() == y.topology()
00073          && topology() == cs_selected.topology()
00074          && topology() == cs_not_selected.topology());
00075   assert(space_dim == y.space_dim);
00076   assert(!marked_empty()
00077          && !has_pending_generators()
00078          && constraints_are_up_to_date());
00079   assert(!y.marked_empty()
00080          && !y.has_something_pending()
00081          && y.constraints_are_minimized()
00082          && y.generators_are_up_to_date());
00083 
00084   // Obtain a sorted copy of `y.sat_g'.
00085   if (!y.sat_g_is_up_to_date())
00086     y.update_sat_g();
00087   Saturation_Matrix tmp_sat_g = y.sat_g;
00088   // Remove from `tmp_sat_g' the rows corresponding to tautologies
00089   // (i.e., the positivity or epsilon-bounding constraints):
00090   // this is needed in order to widen the polyhedron and not the
00091   // corresponding homogenized polyhedral cone.
00092   const Constraint_System& y_cs = y.con_sys;
00093   dimension_type num_rows = y_cs.num_rows();
00094   for (dimension_type i = 0; i < num_rows; ++i)
00095     if (y_cs[i].is_tautological()) {
00096       --num_rows;
00097       std::swap(tmp_sat_g[i], tmp_sat_g[num_rows]);
00098     }
00099   tmp_sat_g.rows_erase_to_end(num_rows);
00100   tmp_sat_g.sort_rows();
00101 
00102   // A constraint in `con_sys' is copied to `cs_selected'
00103   // if its behavior with respect to `y.gen_sys' is the same
00104   // as that of another constraint in `y.con_sys'.
00105   // otherwise it is copied to `cs_not_selected'.
00106   // Namely, we check whether the saturation row `buffer'
00107   // (built starting from the given constraint and `y.gen_sys')
00108   // is a row of the saturation matrix `tmp_sat_g'.
00109 
00110   // CHECK ME: the following comment is only applicable when `y.gen_sys'
00111   // is minimized. In that case, the comment suggests that it would be
00112   // possible to use a fast (but incomplete) redundancy test based on
00113   // the number of saturators in `buffer'.
00114   // NOTE: If the considered constraint of `con_sys' does not
00115   // satisfy the saturation rule (see Section \ref prelims), then
00116   // it will not appear in the resulting constraint system,
00117   // because `tmp_sat_g' is built starting from a minimized polyhedron.
00118 
00119   // The size of `buffer' will reach sat.num_columns() bit.
00120   Saturation_Row buffer;
00121   // Note: the loop index `i' goes upward to avoid reversing
00122   // the ordering of the chosen constraints.
00123   for (dimension_type i = 0, end = con_sys.num_rows(); i < end; ++i) {
00124     const Constraint& ci = con_sys[i];
00125     // The saturation row `buffer' is built considering
00126     // the `i'-th constraint of the polyhedron `x' and
00127     // all the generators of the polyhedron `y'.
00128     buffer.clear();
00129     for (dimension_type j = y.gen_sys.num_rows(); j-- > 0; ) {
00130       const int sp_sgn = Scalar_Products::sign(ci, y.gen_sys[j]);
00131       // We are assuming that `y <= x'.
00132       assert(sp_sgn >= 0);
00133       if (sp_sgn > 0)
00134         buffer.set(j);
00135     }
00136     // We check whether `buffer' is a row of `tmp_sat_g',
00137     // exploiting its sortedness in order to have faster comparisons.
00138     if (tmp_sat_g.sorted_contains(buffer))
00139       cs_selected.insert(ci);
00140     else
00141       cs_not_selected.insert(ci);
00142   }
00143 }

bool Parma_Polyhedra_Library::Polyhedron::BHRZ03_combining_constraints ( const Polyhedron y,
const BHRZ03_Certificate y_cert,
const Polyhedron H79,
const Constraint_System x_minus_H79_con_sys 
) [private]

Definition at line 377 of file Polyhedron_widenings.cc.

References add_recycled_constraints_and_minimize(), Parma_Polyhedra_Library::Linear_Row::all_homogeneous_terms_are_zero(), Parma_Polyhedra_Library::Constraint_System::clear(), con_sys, constraints_are_minimized(), contains(), gen_sys, generators_are_minimized(), has_something_pending(), Parma_Polyhedra_Library::Constraint_System::insert(), Parma_Polyhedra_Library::Generator::is_closure_point(), Parma_Polyhedra_Library::Constraint::is_inequality(), is_necessarily_closed(), Parma_Polyhedra_Library::Generator::is_point(), Parma_Polyhedra_Library::BHRZ03_Certificate::is_stabilizing(), marked_empty(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), relation_with(), Parma_Polyhedra_Library::Scalar_Products::sign(), space_dim, Parma_Polyhedra_Library::Constraint_System::space_dimension(), Parma_Polyhedra_Library::Poly_Con_Relation::strictly_intersects(), Parma_Polyhedra_Library::Linear_System::topology(), and topology().

Referenced by BHRZ03_widening_assign().

00380                                                                         {
00381   Polyhedron& x = *this;
00382   // It is assumed that `y <= x <= H79'.
00383   assert(x.topology() == y.topology()
00384          && x.topology() == H79.topology()
00385          && x.topology() == x_minus_H79_cs.topology());
00386   assert(x.space_dim == y.space_dim
00387          && x.space_dim == H79.space_dim
00388          && x.space_dim == x_minus_H79_cs.space_dimension());
00389   assert(!x.marked_empty() && !x.has_something_pending()
00390          && x.constraints_are_minimized() && x.generators_are_minimized());
00391   assert(!y.marked_empty() && !y.has_something_pending()
00392          && y.constraints_are_minimized() && y.generators_are_minimized());
00393   assert(!H79.marked_empty() && !H79.has_something_pending()
00394          && H79.constraints_are_minimized() && H79.generators_are_minimized());
00395 
00396   // We will choose from `x_minus_H79_cs' many subsets of constraints,
00397   // that will be collected (one at a time) in `combining_cs'.
00398   // For each group collected, we compute an average constraint,
00399   // that will be stored in `new_cs'.
00400 
00401   // There is no point in applying this technique when `x_minus_H79_cs'
00402   // has one constraint at most (no ``new'' constraint can be computed).
00403   const dimension_type x_minus_H79_cs_num_rows = x_minus_H79_cs.num_rows();
00404   if (x_minus_H79_cs_num_rows <= 1)
00405     return false;
00406 
00407   const Topology tpl = x.topology();
00408   Constraint_System combining_cs(tpl);
00409   Constraint_System new_cs(tpl);
00410 
00411   // Consider the points that belong to both `x.gen_sys' and `y.gen_sys'.
00412   // For NNC polyhedra, the role of points is played by closure points.
00413   const bool closed = x.is_necessarily_closed();
00414   for (dimension_type i = y.gen_sys.num_rows(); i-- > 0; ) {
00415     const Generator& g = y.gen_sys[i];
00416     if ((g.is_point() && closed) || (g.is_closure_point() && !closed)) {
00417       // If in `H79.con_sys' there is already an inequality constraint
00418       // saturating this point, then there is no need to produce another
00419       // constraint.
00420       bool lies_on_the_boundary_of_H79 = false;
00421       const Constraint_System& H79_cs = H79.con_sys;
00422       for (dimension_type j = H79_cs.num_rows(); j-- > 0; ) {
00423         const Constraint& c = H79_cs[j];
00424         if (c.is_inequality() && Scalar_Products::sign(c, g) == 0) {
00425           lies_on_the_boundary_of_H79 = true;
00426           break;
00427         }
00428       }
00429       if (lies_on_the_boundary_of_H79)
00430         continue;
00431 
00432       // Consider all the constraints in `x_minus_H79_cs'
00433       // that are saturated by the point `g'.
00434       combining_cs.clear();
00435       for (dimension_type j = x_minus_H79_cs_num_rows; j-- > 0; ) {
00436         const Constraint& c = x_minus_H79_cs[j];
00437         if (Scalar_Products::sign(c, g) == 0)
00438           combining_cs.insert(c);
00439       }
00440       // Build a new constraint by combining all the chosen constraints.
00441       const dimension_type combining_cs_num_rows = combining_cs.num_rows();
00442       if (combining_cs_num_rows > 0) {
00443         if (combining_cs_num_rows == 1)
00444           // No combination is needed.
00445           new_cs.insert(combining_cs[0]);
00446         else {
00447           Linear_Expression e(0);
00448           bool strict_inequality = false;
00449           for (dimension_type h = combining_cs_num_rows; h-- > 0; ) {
00450             if (combining_cs[h].is_strict_inequality())
00451               strict_inequality = true;
00452             e += Linear_Expression(combining_cs[h]);
00453           }
00454 
00455           if (!e.all_homogeneous_terms_are_zero())
00456             if (strict_inequality)
00457               new_cs.insert(e > 0);
00458             else
00459               new_cs.insert(e >= 0);
00460         }
00461       }
00462     }
00463   }
00464 
00465   // If none of the collected constraints strictly intersects `H79',
00466   // then the technique was unsuccessful.
00467   bool improves_upon_H79 = false;
00468   const Poly_Con_Relation si = Poly_Con_Relation::strictly_intersects();
00469   for (dimension_type i = new_cs.num_rows(); i-- > 0; )
00470     if (H79.relation_with(new_cs[i]) == si) {
00471       improves_upon_H79 = true;
00472       break;
00473     }
00474   if (!improves_upon_H79)
00475     return false;
00476 
00477   // The resulting polyhedron is obtained by adding the constraints
00478   // in `new_cs' to polyhedron `H79'.
00479   Polyhedron result = H79;
00480   result.add_recycled_constraints_and_minimize(new_cs);
00481 
00482   // Check for stabilization with respect to `y_cert' and improvement
00483   // over `H79'.
00484   if (y_cert.is_stabilizing(result) && !result.contains(H79)) {
00485     // The technique was successful.
00486     std::swap(x, result);
00487     assert(x.OK(true));
00488     return true;
00489   }
00490   else
00491     // The technique was unsuccessful.
00492     return false;
00493 }

bool Parma_Polyhedra_Library::Polyhedron::BHRZ03_evolving_points ( const Polyhedron y,
const BHRZ03_Certificate y_cert,
const Polyhedron H79 
) [private]

Definition at line 496 of file Polyhedron_widenings.cc.

References add_recycled_generators_and_minimize(), constraints_are_minimized(), contains(), gen_sys, generators_are_minimized(), has_something_pending(), intersection_assign_and_minimize(), Parma_Polyhedra_Library::Generator::is_closure_point(), is_necessarily_closed(), Parma_Polyhedra_Library::Generator::is_point(), Parma_Polyhedra_Library::BHRZ03_Certificate::is_stabilizing(), Parma_Polyhedra_Library::Linear_Row::linear_combine(), marked_empty(), Parma_Polyhedra_Library::Poly_Gen_Relation::nothing(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), relation_with(), space_dim, and topology().

Referenced by BHRZ03_widening_assign().

00498                                                                {
00499   Polyhedron& x = *this;
00500   // It is assumed that `y <= x <= H79'.
00501   assert(x.topology() == y.topology()
00502          && x.topology() == H79.topology());
00503   assert(x.space_dim == y.space_dim
00504          && x.space_dim == H79.space_dim);
00505   assert(!x.marked_empty() && !x.has_something_pending()
00506          && x.constraints_are_minimized() && x.generators_are_minimized());
00507   assert(!y.marked_empty() && !y.has_something_pending()
00508          && y.constraints_are_minimized() && y.generators_are_minimized());
00509   assert(!H79.marked_empty() && !H79.has_something_pending()
00510          && H79.constraints_are_minimized() && H79.generators_are_minimized());
00511 
00512   // For each point in `x.gen_sys' that is not in `y',
00513   // this technique tries to identify a set of rays that:
00514   //  - are included in polyhedron `H79';
00515   //  - when added to `y' will subsume the point.
00516   Generator_System candidate_rays;
00517 
00518   const dimension_type x_gen_sys_num_rows = x.gen_sys.num_rows();
00519   const dimension_type y_gen_sys_num_rows = y.gen_sys.num_rows();
00520   const bool closed = x.is_necessarily_closed();
00521   for (dimension_type i = x_gen_sys_num_rows; i-- > 0; ) {
00522     Generator& g1 = x.gen_sys[i];
00523     // For C polyhedra, we choose a point of `x.gen_sys'
00524     // that is not included in `y'.
00525     // In the case of NNC polyhedra, we can restrict attention to
00526     // closure points (considering also points will only add redundancy).
00527     if (((g1.is_point() && closed) || (g1.is_closure_point() && !closed))
00528         && y.relation_with(g1) == Poly_Gen_Relation::nothing()) {
00529       // For each point (resp., closure point) `g2' in `y.gen_sys',
00530       // where `g1' and `g2' are different,
00531       // build the candidate ray `g1 - g2'.
00532       for (dimension_type j = y_gen_sys_num_rows; j-- > 0; ) {
00533         const Generator& g2 = y.gen_sys[j];
00534         if ((g2.is_point() && closed)
00535             || (g2.is_closure_point() && !closed)) {
00536           assert(compare(g1, g2) != 0);
00537           Generator ray_from_g2_to_g1 = g1;
00538           ray_from_g2_to_g1.linear_combine(g2, 0);
00539           candidate_rays.insert(ray_from_g2_to_g1);
00540         }
00541       }
00542     }
00543   }
00544 
00545   // Be non-intrusive.
00546   Polyhedron result = x;
00547   result.add_recycled_generators_and_minimize(candidate_rays);
00548   result.intersection_assign_and_minimize(H79);
00549 
00550   // Check for stabilization with respect to `y_cert' and improvement
00551   // over `H79'.
00552   if (y_cert.is_stabilizing(result) && !result.contains(H79)) {
00553     // The technique was successful.
00554     std::swap(x, result);
00555     assert(x.OK(true));
00556     return true;
00557   }
00558   else
00559     // The technique was unsuccessful.
00560     return false;
00561 }

bool Parma_Polyhedra_Library::Polyhedron::BHRZ03_evolving_rays ( const Polyhedron y,
const BHRZ03_Certificate y_cert,
const Polyhedron H79 
) [private]

Definition at line 564 of file Polyhedron_widenings.cc.

References add_recycled_generators_and_minimize(), constraints_are_minimized(), contains(), gen_sys, generators_are_minimized(), has_something_pending(), Parma_Polyhedra_Library::Generator_System::insert(), intersection_assign_and_minimize(), Parma_Polyhedra_Library::Generator::is_ray(), Parma_Polyhedra_Library::BHRZ03_Certificate::is_stabilizing(), marked_empty(), Parma_Polyhedra_Library::Row::normalize(), Parma_Polyhedra_Library::Poly_Gen_Relation::nothing(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), relation_with(), space_dim, Parma_Polyhedra_Library::sub_mul_assign(), TEMP_INTEGER, and topology().

Referenced by BHRZ03_widening_assign().

00566                                                              {
00567   Polyhedron& x = *this;
00568   // It is assumed that `y <= x <= H79'.
00569   assert(x.topology() == y.topology()
00570          && x.topology() == H79.topology());
00571   assert(x.space_dim == y.space_dim
00572          && x.space_dim == H79.space_dim);
00573   assert(!x.marked_empty() && !x.has_something_pending()
00574          && x.constraints_are_minimized() && x.generators_are_minimized());
00575   assert(!y.marked_empty() && !y.has_something_pending()
00576          && y.constraints_are_minimized() && y.generators_are_minimized());
00577   assert(!H79.marked_empty() && !H79.has_something_pending()
00578          && H79.constraints_are_minimized() && H79.generators_are_minimized());
00579 
00580   const dimension_type x_gen_sys_num_rows = x.gen_sys.num_rows();
00581   const dimension_type y_gen_sys_num_rows = y.gen_sys.num_rows();
00582 
00583   // Candidate rays are kept in a temporary generator system.
00584   Generator_System candidate_rays;
00585   TEMP_INTEGER(tmp);
00586   for (dimension_type i = x_gen_sys_num_rows; i-- > 0; ) {
00587     const Generator& x_g = x.gen_sys[i];
00588     // We choose a ray of `x' that does not belong to `y'.
00589     if (x_g.is_ray() && y.relation_with(x_g) == Poly_Gen_Relation::nothing()) {
00590       for (dimension_type j = y_gen_sys_num_rows; j-- > 0; ) {
00591         const Generator& y_g = y.gen_sys[j];
00592         if (y_g.is_ray()) {
00593           Generator new_ray(x_g);
00594           // Modify `new_ray' according to the evolution of `x_g' with
00595           // respect to `y_g'.
00596           std::deque<bool> considered(x.space_dim + 1);
00597           for (dimension_type k = 1; k < x.space_dim; ++k)
00598             if (!considered[k])
00599               for (dimension_type h = k + 1; h <= x.space_dim; ++h)
00600                 if (!considered[h]) {
00601                   tmp = x_g[k] * y_g[h];
00602                   // The following line optimizes the computation of
00603                   // tmp -= x_g[h] * y_g[k];
00604                   sub_mul_assign(tmp, x_g[h], y_g[k]);
00605                   const int clockwise
00606                     = sgn(tmp);
00607                   const int first_or_third_quadrant
00608                     = sgn(x_g[k]) * sgn(x_g[h]);
00609                   switch (clockwise * first_or_third_quadrant) {
00610                   case -1:
00611                     new_ray[k] = 0;
00612                     considered[k] = true;
00613                     break;
00614                   case 1:
00615                     new_ray[h] = 0;
00616                     considered[h] = true;
00617                     break;
00618                   default:
00619                     break;
00620                   }
00621                 }
00622           new_ray.normalize();
00623           candidate_rays.insert(new_ray);
00624         }
00625       }
00626     }
00627   }
00628 
00629   // If there are no candidate rays, we cannot obtain stabilization.
00630   if (candidate_rays.num_rows() == 0)
00631     return false;
00632 
00633   // Be non-intrusive.
00634   Polyhedron result = x;
00635   // Add to `result' the rays in `candidate_rays'
00636   result.add_recycled_generators_and_minimize(candidate_rays);
00637   // Intersect with `H79'.
00638   result.intersection_assign_and_minimize(H79);
00639 
00640   // Check for stabilization with respect to `y' and improvement over `H79'.
00641   if (y_cert.is_stabilizing(result) && !result.contains(H79)) {
00642     // The technique was successful.
00643     std::swap(x, result);
00644     assert(x.OK(true));
00645     return true;
00646   }
00647   else
00648     // The technique was unsuccessful.
00649     return false;
00650 }

void Parma_Polyhedra_Library::Polyhedron::add_space_dimensions ( Linear_System mat1,
Linear_System mat2,
Saturation_Matrix sat1,
Saturation_Matrix sat2,
dimension_type  add_dim 
) [static, private]

Adds new space dimensions to the given matrices.

Parameters:
mat1 The matrix to which columns are added;
mat2 The matrix to which rows and columns are added;
sat1 The saturation matrix whose columns are indexed by the rows of matrix mat1. On entry it is up-to-date;
sat2 The saturation matrix whose columns are indexed by the rows of mat2;
add_dim The number of space dimensions to add.
Adds new space dimensions to the vector space modifying the matrices. This function is invoked only by add_space_dimensions_and_embed() and add_space_dimensions_and_project(), passing the matrix of constraints and that of generators (and the corresponding saturation matrices) in different order (see those methods for details).

Definition at line 34 of file Polyhedron_chdims.cc.

References Parma_Polyhedra_Library::Linear_System::add_rows_and_columns(), Parma_Polyhedra_Library::Matrix::add_zero_columns(), Parma_Polyhedra_Library::Linear_System::first_pending_row(), Parma_Polyhedra_Library::Linear_System::is_necessarily_closed(), Parma_Polyhedra_Library::Linear_System::is_sorted(), Parma_Polyhedra_Library::Saturation_Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), Parma_Polyhedra_Library::Saturation_Matrix::num_rows(), Parma_Polyhedra_Library::Saturation_Matrix::resize(), Parma_Polyhedra_Library::Linear_System::set_index_first_pending_row(), Parma_Polyhedra_Library::Matrix::swap_columns(), Parma_Polyhedra_Library::Linear_System::topology(), and Parma_Polyhedra_Library::Saturation_Matrix::transpose_assign().

Referenced by add_space_dimensions_and_embed(), and add_space_dimensions_and_project().

00038                                                               {
00039   assert(sys1.topology() == sys2.topology());
00040   assert(sys1.num_columns() == sys2.num_columns());
00041   assert(add_dim != 0);
00042 
00043   sys1.add_zero_columns(add_dim);
00044   dimension_type old_index = sys2.first_pending_row();
00045   sys2.add_rows_and_columns(add_dim);
00046   // The added rows are in the non-pending part.
00047   sys2.set_index_first_pending_row(old_index + add_dim);
00048 
00049   // The resulting saturation matrix will be as follows:
00050   // from row    0    to      add_dim-1       : only zeroes
00051   //          add_dim     add_dim+num_rows-1  : old saturation matrix
00052 
00053   // In fact all the old generators saturate all the new constraints
00054   // because the polyhedron has not been embedded in the new space.
00055   sat1.resize(sat1.num_rows() + add_dim, sat1.num_columns());
00056   // The old matrix is moved to the end of the new matrix.
00057   for (dimension_type i = sat1.num_rows() - add_dim; i-- > 0; )
00058     std::swap(sat1[i], sat1[i+add_dim]);
00059   // Computes the "sat_c", too.
00060   sat2.transpose_assign(sat1);
00061 
00062   if (!sys1.is_necessarily_closed()) {
00063     // Moving the epsilon coefficients to the new last column.
00064     dimension_type new_eps_index = sys1.num_columns() - 1;
00065     dimension_type old_eps_index = new_eps_index - add_dim;
00066     // This swap preserves sortedness of `sys1'.
00067     sys1.swap_columns(old_eps_index, new_eps_index);
00068 
00069     // Try to preserve sortedness of `sys2'.
00070     if (!sys2.is_sorted())
00071       sys2.swap_columns(old_eps_index, new_eps_index);
00072     else {
00073       for (dimension_type i = sys2.num_rows(); i-- > add_dim; ) {
00074         Linear_Row& r = sys2[i];
00075         std::swap(r[old_eps_index], r[new_eps_index]);
00076       }
00077       // The upper-right corner of `sys2' contains the J matrix:
00078       // swap coefficients to preserve sortedness.
00079       for (dimension_type i = add_dim; i-- > 0; ++old_eps_index) {
00080         Linear_Row& r = sys2[i];
00081         std::swap(r[old_eps_index], r[old_eps_index + 1]);
00082       }
00083     }
00084     // NOTE: since we swapped columns in both `sys1' and `sys2',
00085     // no swapping is required for `sat1' and `sat2'.
00086   }
00087 }

bool Parma_Polyhedra_Library::Polyhedron::minimize ( bool  con_to_gen,
Linear_System source,
Linear_System dest,
Saturation_Matrix sat 
) [static, private]

Builds and simplifies constraints from generators (or vice versa).

Returns:
true if the polyhedron is empty, false otherwise.
Parameters:
con_to_gen true if source represents the constraints, false otherwise;
source The given system, which is not empty;
dest The system to build and minimize;
sat The saturation matrix.
dest is not const because it will be built (and then modified) during minimize(). Also, sat and source are not const because the former will be built during dest creation and the latter will maybe be sorted and modified by conversion() and simplify().

sat has the generators on its columns and the constraints on its rows if con_to_gen is true, otherwise it has the generators on its rows and the constraints on its columns.

Given source, this function builds (by means of conversion()) dest and then simplifies (invoking simplify()) source, erasing redundant rows. For the sequel we assume that source is the system of constraints and dest is the system of generators. This will simplify the description of the function; the dual case is similar.

Definition at line 69 of file minimize.cc.

References conversion(), Parma_Polyhedra_Library::Linear_System::is_necessarily_closed(), Parma_Polyhedra_Library::Linear_System::is_sorted(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), Parma_Polyhedra_Library::Linear_System::resize_no_copy(), Parma_Polyhedra_Library::Linear_System::set_index_first_pending_row(), Parma_Polyhedra_Library::Linear_Row::set_is_line_or_equality(), Parma_Polyhedra_Library::Linear_System::set_sorted(), simplify(), Parma_Polyhedra_Library::Linear_System::sort_rows(), Parma_Polyhedra_Library::Linear_System::topology(), and Parma_Polyhedra_Library::Saturation_Matrix::transpose_assign().

00072                                                   {
00073   // Topologies have to agree.
00074   assert(source.topology() == dest.topology());
00075   // `source' cannot be empty: even if it is an empty constraint system,
00076   // representing the universe polyhedron, homogenization has added
00077   // the positive constraint. It also cannot be an empty generator system,
00078   // since this function is always called starting from a non-empty
00079   // polyhedron.
00080   assert(source.num_rows() > 0);
00081 
00082   // Sort the source system, if necessary.
00083   if (!source.is_sorted())
00084     source.sort_rows();
00085 
00086   // Initialization of the system of generators `dest'.
00087   // The algorithm works incrementally and we haven't seen any
00088   // constraint yet: as a consequence, `dest' should describe
00089   // the universe polyhedron of the appropriate dimension.
00090   // To this end, we initialize it to the identity matrix of dimension
00091   // `source.num_columns()': the rows represent the lines corresponding
00092   // to the canonical basis of the vector space.
00093 
00094   // Resizing `dest' to be the appropriate square matrix.
00095   dimension_type dest_num_rows = source.num_columns();
00096   // Note that before calling `resize_no_copy()' we must update
00097   // `index_first_pending'.
00098   dest.set_index_first_pending_row(dest_num_rows);
00099   dest.resize_no_copy(dest_num_rows, dest_num_rows);
00100 
00101   // Initialize `dest' to the identity matrix.
00102   for (dimension_type i = dest_num_rows; i-- > 0; ) {
00103     Linear_Row& dest_i = dest[i];
00104     for (dimension_type j = dest_num_rows; j-- > 0; )
00105       dest_i[j] = (i == j) ? 1 : 0;
00106     dest_i.set_is_line_or_equality();
00107   }
00108   // The identity matrix `dest' is not sorted (see the sorting rules
00109   // in Linear_Row.cc).
00110   dest.set_sorted(false);
00111 
00112   // NOTE: the system `dest', as it is now, is not a _legal_ system of
00113   //       generators, because in the first row we have a line with a
00114   //       non-zero divisor (which should only happen for
00115   //       points). However, this is NOT a problem, because `source'
00116   //       necessarily contains the positivity constraint (or a
00117   //       combination of it with another constraint) which will
00118   //       restore things as they should be.
00119 
00120 
00121   // Building a saturation matrix and initializing it by setting
00122   // all of its elements to zero. This matrix will be modified together
00123   // with `dest' during the conversion.
00124   // NOTE: since we haven't seen any constraint yet, the relevant
00125   //       portion of `tmp_sat' is the sub-matrix consisting of
00126   //       the first 0 columns: thus the relevant portion correctly
00127   //       characterizes the initial saturation information.
00128   Saturation_Matrix tmp_sat(dest_num_rows, source.num_rows());
00129 
00130   // By invoking the function conversion(), we populate `dest' with
00131   // the generators characterizing the polyhedron described by all
00132   // the constraints in `source'.
00133   // The `start' parameter is zero (we haven't seen any constraint yet)
00134   // and the 5th parameter (representing the number of lines in `dest'),
00135   // by construction, is equal to `dest_num_rows'.
00136   const dimension_type num_lines_or_equalities
00137     = conversion(source, 0, dest, tmp_sat, dest_num_rows);
00138   // conversion() may have modified the number of rows in `dest'.
00139   dest_num_rows = dest.num_rows();
00140 
00141   // Checking if the generators in `dest' represent an empty polyhedron:
00142   // the polyhedron is empty if there are no points
00143   // (because rays, lines and closure points need a supporting point).
00144   // Points can be detected by looking at:
00145   // - the divisor, for necessarily closed polyhedra;
00146   // - the epsilon coordinate, for NNC polyhedra.
00147   const dimension_type checking_index
00148     = dest.is_necessarily_closed()
00149     ? 0
00150     : dest.num_columns() - 1;
00151   dimension_type first_point;
00152   for (first_point = num_lines_or_equalities;
00153        first_point < dest_num_rows;
00154        ++first_point)
00155     if (dest[first_point][checking_index] > 0)
00156       break;
00157 
00158   if (first_point == dest_num_rows)
00159     if (con_to_gen)
00160       // No point has been found: the polyhedron is empty.
00161       return true;
00162     else
00163       // Here `con_to_gen' is false: `dest' is a system of constraints.
00164       // In this case the condition `first_point == dest_num_rows'
00165       // actually means that all the constraints in `dest' have their
00166       // inhomogeneous term equal to 0.
00167       // This is an ILLEGAL situation, because it implies that
00168       // the constraint system `dest' lacks the positivity constraint
00169       // and no linear combination of the constraints in `dest'
00170       // can reintroduce the positivity constraint.
00171       throw std::runtime_error("PPL internal error");
00172   else {
00173     // A point has been found: the polyhedron is not empty.
00174     // Now invoking simplify() to remove all the redundant constraints
00175     // from the system `source'.
00176     // Since the saturation matrix `tmp_sat' returned by conversion()
00177     // has rows indexed by generators (the rows of `dest') and columns
00178     // indexed by constraints (the rows of `source'), we have to
00179     // transpose it to obtain the saturation matrix needed by simplify().
00180     sat.transpose_assign(tmp_sat);
00181     simplify(source, sat);
00182     return false;
00183   }
00184 }

bool Parma_Polyhedra_Library::Polyhedron::add_and_minimize ( bool  con_to_gen,
Linear_System source1,
Linear_System dest,
Saturation_Matrix sat,
const Linear_System source2 
) [static, private]

Adds given constraints and builds minimized corresponding generators or vice versa.

Returns:
true if the obtained polyhedron is empty, false otherwise.
Parameters:
con_to_gen true if source1 and source2 are system of constraints, false otherwise;
source1 The first element of the given DD pair;
dest The second element of the given DD pair;
sat The saturation matrix that bind source1 to dest;
source2 The new system of generators or constraints.
It is assumed that source1 and source2 are sorted and have no pending rows. It is also assumed that dest has no pending rows. On entry, the rows of sat are indexed by the rows of dest and its columns are indexed by the rows of source1. On exit, the rows of sat are indexed by the rows of dest and its columns are indexed by the rows of the system obtained by merging source1 and source2.

Let us suppose we want to add some constraints to a given system of constraints source1. This method, given a minimized double description pair (source1, dest) and a system of new constraints source2, modifies source1 by adding to it the constraints of source2 that are not in source1. Then, by invoking add_and_minimize(bool, Linear_System&, Linear_System&, Saturation_Matrix&), processes the added constraints obtaining a new DD pair.

This method treats also the dual case, i.e., adding new generators to a previous system of generators. In this case source1 contains the old generators, source2 the new ones and dest is the system of constraints in the given minimized DD pair.

Since source2 contains the constraints (or the generators) that will be added to source1, it is constant: it will not be modified.

Definition at line 233 of file minimize.cc.

References Parma_Polyhedra_Library::Linear_System::add_pending_row(), Parma_Polyhedra_Library::cmp(), Parma_Polyhedra_Library::Linear_System::is_sorted(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Linear_System::num_pending_rows(), and Parma_Polyhedra_Library::Matrix::num_rows().

Referenced by add_recycled_constraints_and_minimize(), add_recycled_generators_and_minimize(), intersection_assign_and_minimize(), poly_hull_assign_and_minimize(), process_pending_constraints(), and process_pending_generators().

00237                                                                 {
00238   // `source1' and `source2' cannot be empty.
00239   assert(source1.num_rows() > 0 && source2.num_rows() > 0);
00240   // `source1' and `source2' must have the same number of columns
00241   // to be merged.
00242   assert(source1.num_columns() == source2.num_columns());
00243   // `source1' and `source2' are fully sorted.
00244   assert(source1.is_sorted() && source1.num_pending_rows() == 0);
00245   assert(source2.is_sorted() && source2.num_pending_rows() == 0);
00246   assert(dest.num_pending_rows() == 0);
00247 
00248   const dimension_type old_source1_num_rows = source1.num_rows();
00249   // `k1' and `k2' run through the rows of `source1' and `source2', resp.
00250   dimension_type k1 = 0;
00251   dimension_type k2 = 0;
00252   dimension_type source2_num_rows = source2.num_rows();
00253   while (k1 < old_source1_num_rows && k2 < source2_num_rows) {
00254     // Add to `source1' the constraints from `source2', as pending rows.
00255     // We exploit the property that initially both `source1' and `source2'
00256     // are sorted and index `k1' only scans the non-pending rows of `source1',
00257     // so that it is not influenced by the pending rows appended to it.
00258     // This way no duplicate (i.e., trivially redundant) constraint
00259     // is introduced in `source1'.
00260     const int cmp = compare(source1[k1], source2[k2]);
00261     if (cmp == 0) {
00262       // We found the same row: there is no need to add `source2[k2]'.
00263       ++k2;
00264       // By sortedness, since `k1 < old_source1_num_rows',
00265       // we can increment index `k1' too.
00266       ++k1;
00267     }
00268     else if (cmp < 0)
00269       // By sortedness, we can increment `k1'.
00270       ++k1;
00271     else {
00272       // Here `cmp > 0'.
00273       // By sortedness, `source2[k2]' cannot be in `source1'.
00274       // We add it as a pending row of `source1' (sortedness unaffected).
00275       source1.add_pending_row(source2[k2]);
00276       // We can increment `k2'.
00277       ++k2;
00278     }
00279   }
00280   // Have we scanned all the rows in `source2'?
00281   if (k2 < source2_num_rows)
00282     // By sortedness, all the rows in `source2' having indexes
00283     // greater than or equal to `k2' were not in `source1'.
00284     // We add them as pending rows of 'source1' (sortedness not affected).
00285     for ( ; k2 < source2_num_rows; ++k2)
00286       source1.add_pending_row(source2[k2]);
00287 
00288   if (source1.num_pending_rows() == 0)
00289     // No row was appended to `source1', because all the constraints
00290     // in `source2' were already in `source1'.
00291     // There is nothing left to do ...
00292     return false;
00293 
00294   return add_and_minimize(con_to_gen, source1, dest, sat);
00295 }

bool Parma_Polyhedra_Library::Polyhedron::add_and_minimize ( bool  con_to_gen,
Linear_System source,
Linear_System dest,
Saturation_Matrix sat 
) [static, private]

Adds given constraints and builds minimized corresponding generators or vice versa. The given constraints are in source.

Returns:
true if the obtained polyhedron is empty, false otherwise.
Parameters:
con_to_gen true if source is a system of constraints, false otherwise;
source The first element of the given DD pair. It also contains the pending rows to be processed;
dest The second element of the given DD pair. It cannot have pending rows;
sat The saturation matrix that bind the upper part of source to dest.
On entry, the rows of sat are indexed by the rows of dest and its columns are indexed by the non-pending rows of source. On exit, the rows of sat are indexed by the rows of dest and its columns are indexed by the rows of source.

Let us suppose that source is a system of constraints. This method assumes that the non-pending part of source and system dest form a double description pair in minimal form and will build a new DD pair in minimal form by processing the pending constraints in source. To this end, it will call conversion()) and simplify.

This method treats also the dual case, i.e., processing pending generators. In this case source contains generators and dest is the system of constraints corresponding to the non-pending part of source.

Definition at line 334 of file minimize.cc.

References conversion(), Parma_Polyhedra_Library::Linear_System::first_pending_row(), Parma_Polyhedra_Library::Linear_System::is_necessarily_closed(), Parma_Polyhedra_Library::Linear_System::is_sorted(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Linear_System::num_lines_or_equalities(), Parma_Polyhedra_Library::Linear_System::num_pending_rows(), Parma_Polyhedra_Library::Matrix::num_rows(), Parma_Polyhedra_Library::Saturation_Matrix::resize(), and simplify().

00337                                                           {
00338   assert(source.num_pending_rows() > 0);
00339   assert(source.num_columns() == dest.num_columns());
00340   assert(source.is_sorted());
00341 
00342   // First, pad the saturation matrix with new columns (of zeroes)
00343   // to accommodate for the pending rows of `source'.
00344   sat.resize(dest.num_rows(), source.num_rows());
00345 
00346   // Incrementally compute the new system of generators.
00347   // Parameter `start' is set to the index of the first pending constraint.
00348   const dimension_type num_lines_or_equalities
00349     = conversion(source, source.first_pending_row(),
00350                  dest, sat,
00351                  dest.num_lines_or_equalities());
00352 
00353   // conversion() may have modified the number of rows in `dest'.
00354   const dimension_type dest_num_rows = dest.num_rows();
00355 
00356   // Checking if the generators in `dest' represent an empty polyhedron:
00357   // the polyhedron is empty if there are no points
00358   // (because rays, lines and closure points need a supporting point).
00359   // Points can be detected by looking at:
00360   // - the divisor, for necessarily closed polyhedra;
00361   // - the epsilon coordinate, for NNC polyhedra.
00362   const dimension_type checking_index
00363     = dest.is_necessarily_closed()
00364     ? 0
00365     : dest.num_columns() - 1;
00366   dimension_type first_point;
00367   for (first_point = num_lines_or_equalities;
00368        first_point < dest_num_rows;
00369        ++first_point)
00370      if (dest[first_point][checking_index] > 0)
00371       break;
00372 
00373   if (first_point == dest_num_rows)
00374     if (con_to_gen)
00375       // No point has been found: the polyhedron is empty.
00376       return true;
00377     else
00378       // Here `con_to_gen' is false: `dest' is a system of constraints.
00379       // In this case the condition `first_point == dest_num_rows'
00380       // actually means that all the constraints in `dest' have their
00381       // inhomogeneous term equal to 0.
00382       // This is an ILLEGAL situation, because it implies that
00383       // the constraint system `dest' lacks the positivity constraint
00384       // and no linear combination of the constraints in `dest'
00385       // can reintroduce the positivity constraint.
00386       throw std::runtime_error("PPL internal error");
00387   else {
00388     // A point has been found: the polyhedron is not empty.
00389     // Now invoking `simplify()' to remove all the redundant constraints
00390     // from the system `source'.
00391     // Since the saturation matrix `sat' returned by `conversion()'
00392     // has rows indexed by generators (the rows of `dest') and columns
00393     // indexed by constraints (the rows of `source'), we have to
00394     // transpose it to obtain the saturation matrix needed by `simplify()'.
00395     sat.transpose();
00396     simplify(source, sat);
00397     // Transposing back.
00398     sat.transpose();
00399     return false;
00400   }
00401 }

PPL::dimension_type Parma_Polyhedra_Library::Polyhedron::conversion ( Linear_System source,
dimension_type  start,
Linear_System dest,
Saturation_Matrix sat,
dimension_type  num_lines_or_equalities 
) [static, private]

Performs the conversion from constraints to generators and vice versa.

Returns:
The number of lines of the polyhedron or the number of equality constraints in the result of conversion.
Parameters:
source The system to use to convert dest: it may be modified;
start The index of source row from which conversion begin;
dest The result of the conversion;
sat The saturation matrix telling us, for each row in source, which are the rows of dest that satisfy but do not saturate it;
num_lines_or_equalities The number of rows in the system dest that are either lines of the polyhedron (when dest is a system of generators) or equality constraints (when dest is a system of constraints).
For simplicity, all the following comments assume we are converting a constraint system source to a generator system dest; the comments for the symmetric case can be obtained by duality.

If some of the constraints in source are redundant, they will be removed. This is why the source is not declared to be a constant parameter.

If start is 0, then source is a sorted system; also, dest is a generator system corresponding to an empty constraint system. If otherwise start is greater than 0, then the two sub-systems of source made by the non-pending rows and the pending rows, respectively, are both sorted; also, dest is the generator system corresponding to the non-pending constraints of source.

Independently from the value of start, dest has lines from index 0 to index num_lines_or_equalities - 1 and rays/points from index num_lines_or_equalities to the last of its rows.

Note that here the rows of sat are indexed by rows of dest and its columns are indexed by rows of source.

We know that polyhedra can be represented by both a system of constraints or a system of generators (points, rays and lines) (see Section Representations of Convex Polyhedra). When we have both descriptions for a polyhedron $P$ we have what is called a double description (or DD pair) for $P$.

Here, the representation system refers to the system $C$ whose rows represent the constraints that characterize $P$ and the generating system, the system $G$ whose rows represent the generators of $P$. We say that a pair $(C, G)$ of (real) systems is a double description pair if

\[ C\vect{x} \geq \vect{0} \quad\iff\quad \exists \vect{\lambda} \geq \vect{0} \mathrel{.} \vect{x} = G\vect{\lambda}. \]

The term "double description" is quite natural in the sense that such a pair contains two different description of the same object. In fact, if we refer to the cone representation of a polyhedron $P$ and we call $C$ and $G$ the systems of constraints and rays respectively, we have

\[ P = \{\, \vect{x} \in \Rset^n \mid C\vect{x} \geq \vect{0}\, \} = \{\, \vect{x} \in \Rset^n \mid \vect{x} = G\vect{\lambda} \text{ for some } \vect{\lambda} \geq \vect{0}\, \}. \]

Because of the theorem of Minkowski (see Section Further Notation and Terminology), we can say that, given a $m \times n$ representation system $C$ such that $\mathop{\mathrm{rank}}(C) = n = \mathit{dimension of the whole space}$ for a non-empty polyhedron $P$, it is always possible to find a generating system $G$ for $P$ such that $(C, G)$ is a DD pair. Conversely, Weyl's theorem ensures that, for each generating system $G$, it is possible to find a representation system $C$ such that $(C, G)$ is a DD pair.

For efficiency reasons, our representation of polyhedra makes use of a double description. We are thus left with two problems:

  1. given $C$ find $G$ such that $(C, G)$ is a DD pair;
  2. given $G$ find $C$ such that $(C, G)$ is a DD pair.

Using Farkas' lemma we can prove that these two problems are computationally equivalent (i.e., linear-time reducible to each other). Farkas' lemma establishes a fundamental property of vectors in $\Rset^n$ that, in a sense, captures the essence of duality. Consider a matrix $A \in \Rset^{m \times n}$ and let $\{ \vect{a}_1, \ldots, \vect{a}_m \}$ be its set of row vectors. Consider also another vector $\vect{c} \in \Rset^n$ such that, whenever a vector $\vect{y} \in \Rset^n$ has a non-negative projection on the $\vect{a}_i$'s, it also has a non-negative projection on $\vect{c}$. The lemma states that $\vect{c}$ has this property if and only if it is in the cone generated by the $\vect{a}_i$'s. Formally, the lemma states the equivalence of the two following assertions:

  1. $ \forall \vect{y} \mathrel{:} (A\vect{y} \geq 0 \implies \langle \vect{y},\vect{c} \rangle \geq 0) $;
  2. $ \exists \vect{\lambda} \geq \vect{0} \mathrel{.} \vect{c}^\mathrm{T} = \vect{\lambda}^\mathrm{T}A $.

With this result we can prove that $(C, G)$ is a DD pair if and only if $(G^\mathrm{T}, C^\mathrm{T})$ is a DD pair.

Suppose $(C, G)$ is a DD pair. Thus, for each $x$ of the appropriate dimension, $C\vect{x} \geq \vect{0}$ if and only if $\exists \lambda \geq 0 \mathrel{.} \vect{x} = G\vect{\lambda}$, which is of course equivalent to $ \exists \vect{\lambda} \geq \vect{0} \mathrel{.} \vect{x}^\mathrm{T} = \vect{\lambda}^\mathrm{T}G^\mathrm{T} $.

First, we assume that $\vect{z}$ is such that $G^\mathrm{T}\vect{z} \geq \vect{0}$ and we will show that $\exists \vect{\mu} \geq \vect{0} \mathrel{.} \vect{z} = C^\mathrm{T}\vect{\mu}$. Let $\vect{x}$ be such that $C\vect{x} \geq \vect{0}$. Since $(C, G)$ is a DD pair, this is equivalent to $ \exists \vect{\lambda} \geq \vect{0} \mathrel{.} \vect{x}^\mathrm{T} = \vect{\lambda}^\mathrm{T}G^\mathrm{T} $, which, by Farkas' lemma is equivalent to $ \forall \vect{y} \mathrel{:} (G^\mathrm{T}\vect{y} \geq \vect{0} \implies \langle \vect{y}, \vect{x} \rangle \geq 0) $. Taking $\vect{y} = \vect{z}$ and recalling our assumption that $G^\mathrm{T}\vect{z} \geq \vect{0}$ we can conclude that $\langle \vect{z}, \vect{x} \rangle \geq 0$, that is equivalent to $\langle \vect{x}, \vect{z} \rangle \geq 0$. We have thus established that $ \forall \vect{x} \mathrel{:} (C\vect{x} \geq \vect{0} \implies \langle \vect{x}, \vect{z} \rangle \geq 0) $. By Farkas' lemma, this is equivalent to $\exists \vect{\mu} \geq \vect{0} \mathrel{.} \vect{z}^\mathrm{T} = \vect{\mu}^\mathrm{T} C$, which is equivalent to what we wanted to prove, that is, $\exists \vect{\mu} \geq \vect{0} \mathrel{.} \vect{z} = C^\mathrm{T}\vect{\mu}$.

In order to prove the reverse implication, the following observation turns out to be useful: when $(C, G)$ is a DD pair, $CG \geq 0$. In fact, let $\vect{e}_j$ be the vector whose components are all $0$ apart from the $j$-th one, which is $1$. Clearly $\vect{e}_j \geq \vect{0}$ and, taking $\vect{\lambda} = \vect{e}_j$ and $\vect{x} = G\vect{\lambda} = G \vect{e}_j$, we have $C\vect{x} = C(G \vect{e}_j) = (CG)\vect{e}_j \geq \vect{0}$, since $(C, G)$ is a DD pair. Thus, as $(CG)\vect{e}_j$ is the $j$-th column of $CG$ and since the choice of $j$ was arbitrary, $CG \geq \vect{0}$.

We now assume that $\vect{z}$ is such that $\exists \vect{\mu} \geq \vect{0} \mathrel{.} \vect{z} = C^\mathrm{T}\vect{\mu}$ and we will prove that $G^\mathrm{T}\vect{z} \geq \vect{0}$. By Farkas' lemma, the assumption $\exists \vect{\mu} \geq \vect{0} \mathrel{.} \vect{z}^\mathrm{T} = \vect{\mu}^\mathrm{T}C$, is equivalent to $\forall \vect{y} \mathrel{:} (C\vect{y} \geq \vect{0} \implies \langle \vect{y}, \vect{z} \rangle \geq 0)$. If we take $\vect{y} = G\vect{e}_j$ then $C\vect{y} = CG\vect{e}_j \geq 0$, since $CG \geq \vect{0}$. So $ \langle \vect{y}, \vect{z} \rangle = (\vect{e}_j^\mathrm{T}G^\mathrm{T}) \vect{z} = \vect{e}_j^\mathrm{T}(G^\mathrm{T} \vect{z}) \geq 0 $, that is, the $j$-th component of $G^\mathrm{T}\vect{z}$ is non-negative. The arbitrary choice of $j$ allows us to conclude that $G^\mathrm{T}\vect{z} \geq \vect{0}$, as required.

In view of this result, the following exposition assumes, for clarity, that the conversion being performed is from constraints to generators. Thus, even if the roles of source and dest can be interchanged, in the sequel we assume the source system will contain the constraints that represent the polyhedron and the dest system will contain the generator that generates it.

There are some observations that are useful to understand this function:

Observation 1: Let $A$ be a system of constraints that generate the polyhedron $P$ and $\vect{c}$ a new constraint that must be added. Suppose that there is a line $\vect{z}$ that does not saturate the constraint $\vect{c}$. If we combine the old lines and rays that do not saturate $\vect{c}$ (except $\vect{z}$) with $\vect{z}$ such that the new ones saturate $\vect{c}$, the new lines and rays also saturate the constraints saturated by the old lines and rays.

In fact, if $\vect{y}_1$ is the old generator that does not saturate $\vect{c}$, $\vect{y}_2$ is the new one such that

\[ \vect{y}_2 = \lambda \vect{y}_1 + \mu \vect{z} \]

and $\vect{c}_1$ is a previous constraint that $\vect{y}_1$ and $\vect{z}$ saturates, we can see

\[ \langle \vect{c}_1, \vect{y}_2 \rangle = \langle \vect{c}_1, (\lambda \vect{y}_1 + \mu \vect{z}) \rangle = \lambda \langle \vect{c}_1, \vect{y}_1 \rangle + \mu \langle \vect{c}_1, \vect{z} \rangle = 0 + \mu \langle \vect{c}_1, \vect{z} \rangle = \mu \langle \vect{c}_1, \vect{z} \rangle \]

and

\[ \mu \langle \vect{c}_1, \vect{z} \rangle = 0. \]

Proposition 1: Let $\vect{r}_1$ and $\vect{r}_2$ be distinct rays of $P$. Then the following statements are equivalent: a) $\vect{r}_1$ and $\vect{r}_2$ are adjacent extreme rays (see Section Further Notation and Terminology); b) $\vect{r}_1$ and $\vect{r}_2$ are extreme rays and the rank of the system composed by the constraints saturated by both $\vect{r}_1$ and $\vect{r}_2$ is equal to $d - 2$, where $d$ is the rank of the system of constraints.

In fact, let $F$ be the system of generators that saturate the constraints saturated by both $\vect{r}_1$ and $\vect{r}_2$. If b) holds, the set $F$ is 2-dimensional and $\vect{r}_1$ and $\vect{r}_2$ generate this set. So, every generator $\vect{x}$ of $F$ can be built as a combination of $\vect{r}_1$ and $\vect{r}_2$, i.e.

\[ \vect{x} = \lambda \vect{r}_1 + \mu \vect{r}_2. \]

This combination is non-negative because there exists at least a constraint $c$ saturated by $\vect{r}_1$ and not $\vect{r}_2$ (or vice versa) (because they are distinct) for which

\[ \langle \vect{c}, \vect{x} \rangle \geq 0 \]

and

\[ \langle \vect{c}, \vect{x} \rangle = \lambda \langle \vect{c}, \vect{r}_1 \rangle (or = \mu \langle \vect{c}, \vect{r}_2 \rangle). \]

So, there is no other extreme ray in $F$ and a) holds. Otherwise, if b) does not hold, the rank of the system generated by the constraints saturated by both $\vect{r}_1$ and $\vect{r}_2$ is equal to $d - k$, with k >= 3, the set $F$ is k -dimensional and at least k extreme rays are necessary to generate $F$. So, $\vect{r}_1$ and $\vect{r}_2$ are not adjacent and a) does not hold.

Proposition 2: When we build the new system of generators starting from a system $A$ of constraints of $P$, if $\vect{c}$ is the constraint to add to $A$ and all lines of $P$ saturate $\vect{c}$, the new set of rays is the union of those rays that saturate, of those that satisfy and of a set $\overline Q$ of rays such that each of them

  1. lies on the hyper-plane represented by the k-th constraint,
  2. is a positive combination of two adjacent rays $\vect{r}_1$ and $\vect{r}_2$ such that the first one satisfies the constraint and the other does not satisfy it. If the adjacency property is not taken in account, the new set of rays is not irredundant, in general.

In fact, if $\vect{r}_1$ and $\vect{r}_2$ are not adjacent, the rank of the system composed by the constraints saturated by both $\vect{r}_1$ and $\vect{r}_2$ is different from $d - 2$ (see the previous proposition) or neither $\vect{r}_1$ nor $\vect{r}_2$ are extreme rays. Since the new ray $\vect{r}$ is a combination of $\vect{r}_1$ and $\vect{r}_2$, it saturates the same constraints saturated by both $\vect{r}_1$ and $\vect{r}_2$. If the rank is less than $d - 2$, the rank of the system composed by $\vect{c}$ (that is saturated by $\vect{r}$) and by the constraints of $A$ saturated by $\vect{r}$ is less than $d - 1$. It means that $r$ is redundant (see Section Further Notation and Terminology). If neither $\vect{r}_1$ nor $\vect{r}_2$ are extreme rays, they belong to a 2-dimensional face containing exactly two extreme rays of $P$. These two adjacent rays build a ray equal to $\vect{r}$ and so $\vect{r}$ is redundant.

Definition at line 350 of file conversion.cc.

References Parma_Polyhedra_Library::Linear_System::add_pending_row(), Parma_Polyhedra_Library::Saturation_Matrix::add_row(), Parma_Polyhedra_Library::Scalar_Products::assign(), Parma_Polyhedra_Library::Coefficient_zero(), Parma_Polyhedra_Library::Saturation_Matrix::columns_erase_to_end(), Parma_Polyhedra_Library::Saturation_Row::count_ones(), Parma_Polyhedra_Library::Matrix::erase_to_end(), Parma_Polyhedra_Library::Linear_System::first_pending_row(), Parma_Polyhedra_Library::Linear_Row::is_ray_or_point_or_inequality(), Parma_Polyhedra_Library::Linear_System::is_sorted(), Parma_Polyhedra_Library::maybe_abandon(), Parma_Polyhedra_Library::neg_assign(), Parma_Polyhedra_Library::normalize2(), Parma_Polyhedra_Library::Saturation_Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Saturation_Matrix::num_rows(), Parma_Polyhedra_Library::Matrix::num_rows(), Parma_Polyhedra_Library::Linear_Row::RAY_OR_POINT_OR_INEQUALITY, Parma_Polyhedra_Library::Saturation_Matrix::rows_erase_to_end(), Parma_Polyhedra_Library::Saturation_Row::set(), Parma_Polyhedra_Library::Linear_System::set_sorted(), Parma_Polyhedra_Library::Linear_Row::strong_normalize(), Parma_Polyhedra_Library::sub_mul_assign(), TEMP_INTEGER, Parma_Polyhedra_Library::Linear_System::topology(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

Referenced by add_and_minimize(), and minimize().

00354                                                                     {
00355   dimension_type source_num_rows = source.num_rows();
00356   dimension_type dest_num_rows = dest.num_rows();
00357   const dimension_type source_num_columns = source.num_columns();
00358   const dimension_type dest_num_columns = dest.num_columns();
00359 
00360   // By construction, the number of columns of `sat' is the same as
00361   // the number of rows of `source'; also, the number of rows of `sat'
00362   // is the same as the number of rows of `dest'.
00363   assert(source_num_rows == sat.num_columns());
00364   assert(dest_num_rows == sat.num_rows());
00365 
00366   // If `start > 0', then we are converting the pending constraints.
00367   assert(start == 0 || start == source.first_pending_row());
00368 
00369   // During the iteration on the constraints in `source' we may identify
00370   // constraints that are redundant: these have to be removed by swapping
00371   // the rows of `source', taking care not to compromise the sortedness
00372   // of the constraints that still have to be considered.
00373   // To this end, the following counter keeps the number of redundant
00374   // constraints seen so far, to be used as a displacement when swapping rows.
00375   dimension_type source_num_redundant = 0;
00376 
00377   TEMP_INTEGER(normalized_sp_i);
00378   TEMP_INTEGER(normalized_sp_o);
00379 
00380   // Converting the sub-system of `source' having rows with indexes
00381   // from `start' to the last one (i.e., `source_num_rows' - 1).
00382   for (dimension_type k = start; k < source_num_rows; ) {
00383 
00384     // All the `source_num_redundant' redundant constraints identified so far
00385     // have consecutive indices starting from `k'.
00386     if (source_num_redundant > 0)
00387       // Let the next constraint have index `k'.
00388       // There is no need to swap the columns of `sat' (all zeroes).
00389       std::swap(source[k], source[k+source_num_redundant]);
00390 
00391     Linear_Row& source_k = source[k];
00392 
00393     // Constraints and generators must have the same dimension,
00394     // otherwise the scalar product below will bomb.
00395     assert(source_num_columns == dest_num_columns);
00396 
00397     // `scalar_prod[i]' will contain the scalar product
00398     // of the constraint `source_k' and the generator `dest[i]'.
00399     // This product is 0 iff the generator saturates the constraint.
00400     static std::vector<Coefficient> scalar_prod;
00401     const int needed_space = dest_num_rows - scalar_prod.size();
00402     if (needed_space > 0)
00403       scalar_prod.insert(scalar_prod.end(), needed_space, Coefficient_zero());
00404     // `index_non_zero' will indicate the first generator in `dest'
00405     // that does not saturate the constraint `source_k'.
00406     dimension_type index_non_zero = 0;
00407     for ( ; index_non_zero < dest_num_rows; ++index_non_zero) {
00408       Scalar_Products::assign(scalar_prod[index_non_zero],
00409                               source_k,
00410                               dest[index_non_zero]);
00411       if (scalar_prod[index_non_zero] != 0)
00412         // The generator does not saturate the constraint.
00413         break;
00414 #if REACTIVE_ABANDONING
00415       // Check if the client has requested abandoning all exponential
00416       // computations.  If so, the exception specified by the client
00417       // is thrown now.
00418       maybe_abandon();
00419 #endif
00420     }
00421     for (dimension_type i = index_non_zero + 1; i < dest_num_rows; ++i) {
00422       Scalar_Products::assign(scalar_prod[i], source_k, dest[i]);
00423 #if REACTIVE_ABANDONING
00424       maybe_abandon();
00425 #endif
00426     }
00427 
00428     // We first treat the case when `index_non_zero' is less than
00429     // `num_lines_or_equalities', i.e., when the generator that
00430     // does not saturate the constraint `source_k' is a line.
00431     // The other case (described later) is when all the lines
00432     // in `dest' (i.e., all the rows having indexes less than
00433     // `num_lines_or_equalities') do saturate the constraint.
00434 
00435     if (index_non_zero < num_lines_or_equalities) {
00436       // Since the generator `dest[index_non_zero]' does not saturate
00437       // the constraint `source_k', it can no longer be a line
00438       // (see saturation rule in Section \ref prelims).
00439       // Therefore, we first transform it to a ray.
00440       dest[index_non_zero].set_is_ray_or_point_or_inequality();
00441       // Of the two possible choices, we select the ray satisfying
00442       // the constraint (namely, the ray whose scalar product
00443       // with the constraint gives a positive result).
00444       if (scalar_prod[index_non_zero] < 0) {
00445         // The ray `dest[index_non_zero]' lies on the wrong half-space:
00446         // we change it to have the opposite direction.
00447         neg_assign(scalar_prod[index_non_zero]);
00448         for (dimension_type j = dest_num_columns; j-- > 0; )
00449           neg_assign(dest[index_non_zero][j]);
00450       }
00451       // Having changed a line to a ray, we set `dest' to be a
00452       // non-sorted system, we decrement the number of lines of `dest' and,
00453       // if necessary, we move the new ray below all the remaining lines.
00454       dest.set_sorted(false);
00455       --num_lines_or_equalities;
00456       if (index_non_zero != num_lines_or_equalities) {
00457         std::swap(dest[index_non_zero],
00458                   dest[num_lines_or_equalities]);
00459         std::swap(scalar_prod[index_non_zero],
00460                   scalar_prod[num_lines_or_equalities]);
00461       }
00462       Linear_Row& dest_nle = dest[num_lines_or_equalities];
00463 
00464       // Computing the new lineality space.
00465       // Since each line must lie on the hyper-plane corresponding to
00466       // the constraint `source_k', the scalar product between
00467       // the line and the constraint must be 0.
00468       // This property already holds for the lines having indexes
00469       // between 0 and `index_non_zero' - 1.
00470       // We have to consider the remaining lines, having indexes
00471       // between `index_non_zero' and `num_lines_or_equalities' - 1.
00472       // Each line that does not saturate the constraint has to be
00473       // linearly combined with generator `dest_nle' so that the
00474       // resulting new line saturates the constraint.
00475       // Note that, by Observation 1 above, the resulting new line
00476       // will still saturate all the constraints that were saturated by
00477       // the old line.
00478 
00479       Coefficient& scalar_prod_nle = scalar_prod[num_lines_or_equalities];
00480       for (dimension_type
00481              i = index_non_zero; i < num_lines_or_equalities; ++i) {
00482         if (scalar_prod[i] != 0) {
00483           // The following fragment optimizes the computation of
00484           //
00485           // Coefficient scale = scalar_prod[i];
00486           // scale.gcd_assign(scalar_prod_nle);
00487           // Coefficient normalized_sp_i = scalar_prod[i] / scale;
00488           // Coefficient normalized_sp_n = scalar_prod_nle / scale;
00489           // for (dimension_type c = dest_num_columns; c-- > 0; ) {
00490           //   dest[i][c] *= normalized_sp_n;
00491           //   dest[i][c] -= normalized_sp_i * dest_nle[c];
00492           // }
00493           normalize2(scalar_prod[i],
00494                      scalar_prod_nle,
00495                      normalized_sp_i,
00496                      normalized_sp_o);
00497           Linear_Row& dest_i = dest[i];
00498           for (dimension_type c = dest_num_columns; c-- > 0; ) {
00499             Coefficient& dest_i_c = dest_i[c];
00500             dest_i_c *= normalized_sp_o;
00501             sub_mul_assign(dest_i_c, normalized_sp_i, dest_nle[c]);
00502           }
00503           dest_i.strong_normalize();
00504           scalar_prod[i] = 0;
00505           // `dest' has already been set as non-sorted.
00506         }
00507       }
00508 
00509       // Computing the new pointed cone.
00510       // Similarly to what we have done during the computation of
00511       // the lineality space, we consider all the remaining rays
00512       // (having indexes strictly greater than `num_lines_or_equalities')
00513       // that do not saturate the constraint `source_k'. These rays
00514       // are positively combined with the ray `dest_nle' so that the
00515       // resulting new rays saturate the constraint.
00516       for (dimension_type
00517              i = num_lines_or_equalities + 1; i < dest_num_rows; ++i) {
00518         if (scalar_prod[i] != 0) {
00519           // The following fragment optimizes the computation of
00520           //
00521           // Coefficient scale = scalar_prod[i];
00522           // scale.gcd_assign(scalar_prod_nle);
00523           // Coefficient normalized_sp_i = scalar_prod[i] / scale;
00524           // Coefficient normalized_sp_n = scalar_prod_nle / scale;
00525           // for (dimension_type c = dest_num_columns; c-- > 0; ) {
00526           //   dest[i][c] *= normalized_sp_n;
00527           //   dest[i][c] -= normalized_sp_i * dest_nle[c];
00528           // }
00529           normalize2(scalar_prod[i],
00530                      scalar_prod_nle,
00531                      normalized_sp_i,
00532                      normalized_sp_o);
00533           Linear_Row& dest_i = dest[i];
00534           for (dimension_type c = dest_num_columns; c-- > 0; ) {
00535             Coefficient& dest_i_c = dest_i[c];
00536             dest_i_c *= normalized_sp_o;
00537             sub_mul_assign(dest_i_c, normalized_sp_i, dest_nle[c]);
00538           }
00539           dest_i.strong_normalize();
00540           scalar_prod[i] = 0;
00541           // `dest' has already been set as non-sorted.
00542         }
00543 #if REACTIVE_ABANDONING
00544         maybe_abandon();
00545 #endif
00546       }
00547       // Since the `scalar_prod_nle' is positive (by construction), it
00548       // does not saturate the constraint `source_k'.  Therefore, if
00549       // the constraint is an inequality, we set to 1 the
00550       // corresponding element of `sat' ...
00551       Saturation_Row& sat_nle = sat[num_lines_or_equalities];
00552       if (source_k.is_ray_or_point_or_inequality())
00553         sat_nle.set(k);
00554       // ... otherwise, the constraint is an equality which is
00555       // violated by the generator `dest_nle': the generator has to be
00556       // removed from `dest'.
00557       else {
00558         --dest_num_rows;
00559         std::swap(dest_nle, dest[dest_num_rows]);
00560         std::swap(scalar_prod_nle, scalar_prod[dest_num_rows]);
00561         std::swap(sat_nle, sat[dest_num_rows]);
00562         // `dest' has already been set as non-sorted.
00563       }
00564       // We continue with the next constraint.
00565       ++k;
00566     }
00567     // Here we have `index_non_zero' >= `num_lines_or_equalities',
00568     // so that all the lines in `dest' saturate the constraint `source_k'.
00569     else {
00570       // First, we reorder the generators in `dest' as follows:
00571       // -# all the lines should have indexes between 0 and
00572       //    `num_lines_or_equalities' - 1 (this already holds);
00573       // -# all the rays that saturate the constraint should have
00574       //    indexes between `num_lines_or_equalities' and
00575       //    `lines_or_equal_bound' - 1; these rays form the set Q=.
00576       // -# all the rays that have a positive scalar product with the
00577       //    constraint should have indexes between `lines_or_equal_bound'
00578       //    and `sup_bound' - 1; these rays form the set Q+.
00579       // -# all the rays that have a negative scalar product with the
00580       //    constraint should have indexes between `sup_bound' and
00581       //    `dest_num_rows' - 1; these rays form the set Q-.
00582       dimension_type lines_or_equal_bound = num_lines_or_equalities;
00583       dimension_type inf_bound = dest_num_rows;
00584       // While we find saturating generators, we simply increment
00585       // `lines_or_equal_bound'.
00586       while (inf_bound > lines_or_equal_bound
00587              && scalar_prod[lines_or_equal_bound] == 0)
00588         ++lines_or_equal_bound;
00589       dimension_type sup_bound = lines_or_equal_bound;
00590       while (inf_bound > sup_bound) {
00591         const int sp_sign = sgn(scalar_prod[sup_bound]);
00592         if (sp_sign == 0) {
00593           // This generator has to be moved in Q=.
00594           std::swap(dest[sup_bound], dest[lines_or_equal_bound]);
00595           std::swap(scalar_prod[sup_bound], scalar_prod[lines_or_equal_bound]);
00596           std::swap(sat[sup_bound], sat[lines_or_equal_bound]);
00597           ++lines_or_equal_bound;
00598           ++sup_bound;
00599           dest.set_sorted(false);
00600         }
00601         else if (sp_sign < 0) {
00602           // This generator has to be moved in Q-.
00603           --inf_bound;
00604           std::swap(dest[sup_bound], dest[inf_bound]);
00605           std::swap(scalar_prod[sup_bound], scalar_prod[inf_bound]);
00606           std::swap(sat[sup_bound], sat[inf_bound]);
00607           dest.set_sorted(false);
00608         }
00609         else
00610           // sp_sign > 0: this generator has to be moved in Q+.
00611           ++sup_bound;
00612       }
00613 
00614       if (sup_bound == dest_num_rows) {
00615         // Here the set Q- is empty.
00616         // If the constraint is an inequality, then all the generators
00617         // in Q= and Q+ satisfy the constraint. The constraint is redundant
00618         // and it can be safely removed from the constraint system.
00619         // This is why the `source' parameter is not declared `const'.
00620         if (source_k.is_ray_or_point_or_inequality()) {
00621           ++source_num_redundant;
00622           --source_num_rows;
00623           // NOTE: we continue with the next cycle of the loop
00624           // without incrementing the index `k', because:
00625           // -# either `k == source_num_rows', and we will exit the loop;
00626           // -# or, having increased `source_num_redundant', we will swap
00627           //    in position `k' a constraint that still has to be examined.
00628         }
00629         else {
00630           // The constraint is an equality, so that all the generators
00631           // in Q+ violate it. Since the set Q- is empty, we can simply
00632           // remove from `dest' all the generators of Q+.
00633           dest_num_rows = lines_or_equal_bound;
00634           // We continue with the next constraint.
00635           ++k;
00636         }
00637       }
00638       else {
00639         // The set Q- is not empty, i.e., at least one generator
00640         // violates the constraint `source_k'.
00641         // We have to further distinguish two cases:
00642         if (sup_bound == num_lines_or_equalities)
00643           // The set Q+ is empty, so that all generators that satisfy
00644           // the constraint also saturate it.
00645           // We can simply remove from `dest' all the generators in Q-.
00646           dest_num_rows = sup_bound;
00647         else {
00648           // The sets Q+ and Q- are both non-empty.
00649           // The generators of the new pointed cone are all those satisfying
00650           // the constraint `source_k' plus a set of new rays enjoying
00651           // the following properties:
00652           // -# they lie on the hyper-plane represented by the constraint
00653           // -# they are obtained as a positive combination of two
00654           //    adjacent rays, the first taken from Q+ and the second
00655           //    taken from Q-.
00656 
00657           // The adjacency property is necessary to have an irredundant
00658           // set of new rays (see proposition 2).
00659           const dimension_type bound = dest_num_rows;
00660 
00661           // In the following loop,
00662           // `i' runs through the generators in the set Q+ and
00663           // `j' runs through the generators in the set Q-.
00664           for (dimension_type i = lines_or_equal_bound; i < sup_bound; ++i) {
00665             for(dimension_type j = sup_bound; j < bound; ++j) {
00666               // Checking if generators `dest[i]' and `dest[j]' are adjacent.
00667               // If there exist another generator that saturates
00668               // all the constraints saturated by both `dest[i]' and
00669               // `dest[j]', then they are NOT adjacent.
00670               Saturation_Row new_satrow;
00671               assert(sat[i].last() == ULONG_MAX || sat[i].last() < k);
00672               assert(sat[j].last() == ULONG_MAX || sat[j].last() < k);
00673               // Being the union of `sat[i]' and `sat[j]',
00674               // `new_satrow' corresponds to a ray that saturates all the
00675               // constraints saturated by both `dest[i]' and `dest[j]'.
00676               set_union(sat[i], sat[j], new_satrow);
00677 
00678               // Computing the number of common saturators.
00679               // NOTE: this number has to be less than `k' because
00680               // we are treating the `k'-th constraint.
00681               const dimension_type
00682                 num_common_satur = k - new_satrow.count_ones();
00683 
00684               // Even before actually creating the new ray as a
00685               // positive combination of `dest[i]' and `dest[j]',
00686               // we exploit saturation information to check if
00687               // it can be an extremal ray. To this end, we refer
00688               // to the definition of a minimal proper face
00689               // (see comments in Polyhedron.defs.hh):
00690               // an extremal ray saturates at least `n' - `t' - 1
00691               // constraints, where `n' is the dimension of the space
00692               // and `t' is the dimension of the lineality space.
00693               // Since `n == source_num_columns - 1' and
00694               // `t == num_lines_or_equalities', we obtain that
00695               // an extremal ray saturates at least
00696               // `source_num_columns - num_lines_or_equalities - 2'
00697               // constraints.
00698               if (num_common_satur
00699                   >= source_num_columns - num_lines_or_equalities - 2) {
00700                 // The minimal proper face rule is satisfied.
00701                 // Now we actually check for redundancy by computing
00702                 // adjacency information.
00703                 bool redundant = false;
00704                 for (dimension_type
00705                        l = num_lines_or_equalities; l < bound; ++l)
00706                   if (l != i && l != j
00707                       && subset_or_equal(sat[l], new_satrow)) {
00708                     // Found another generator saturating all the
00709                     // constraints saturated by both `dest[i]' and `dest[j]'.
00710                     redundant = true;
00711                     break;
00712                   }
00713                 if (!redundant) {
00714                   // Adding the new ray to `dest' and the corresponding
00715                   // saturation row to `sat'.
00716                   if (dest_num_rows == dest.num_rows()) {
00717                     // Make room for one more row.
00718                     dest.add_pending_row(Linear_Row::Flags(dest.topology(),
00719                                                            Linear_Row::RAY_OR_POINT_OR_INEQUALITY));
00720                     sat.add_row(new_satrow);
00721                   }
00722                   else
00723                     sat[dest_num_rows] = new_satrow;
00724                   Linear_Row& new_row = dest[dest_num_rows];
00725                   // The following fragment optimizes the computation of
00726                   //
00727                   // Coefficient scale = scalar_prod[i];
00728                   // scale.gcd_assign(scalar_prod[j]);
00729                   // Coefficient normalized_sp_i = scalar_prod[i] / scale;
00730                   // Coefficient normalized_sp_j = scalar_prod[j] / scale;
00731                   // for (dimension_type c = dest_num_columns; c-- > 0; ) {
00732                   //   new_row[c] = normalized_sp_i * dest[j][c];
00733                   //   new_row[c] -= normalized_sp_j * dest[i][c];
00734                   // }
00735                   normalize2(scalar_prod[i],
00736                              scalar_prod[j],
00737                              normalized_sp_i,
00738                              normalized_sp_o);
00739                   for (dimension_type c = dest_num_columns; c-- > 0; ) {
00740                     Coefficient& new_row_c = new_row[c];
00741                     new_row_c = normalized_sp_i * dest[j][c];
00742                     sub_mul_assign(new_row_c, normalized_sp_o, dest[i][c]);
00743                   }
00744                   new_row.strong_normalize();
00745                   // Since we added a new generator to `dest',
00746                   // we also add a new element to `scalar_prod';
00747                   // by construction, the new ray lies on the hyper-plane
00748                   // represented by the constraint `source_k'.
00749                   // Thus, the added scalar product is 0.
00750                   assert(scalar_prod.size() >= dest_num_rows);
00751                   if (scalar_prod.size() <= dest_num_rows)
00752                     scalar_prod.push_back(Coefficient_zero());
00753                   else
00754                     scalar_prod[dest_num_rows] = Coefficient_zero();
00755                   // Increment the number of generators.
00756                   ++dest_num_rows;
00757                 }
00758               }
00759             }
00760 #if REACTIVE_ABANDONING
00761             maybe_abandon();
00762 #endif
00763           }
00764           // Now we substitute the rays in Q- (i.e., the rays violating
00765           // the constraint) with the newly added rays.
00766           dimension_type j;
00767           if (source_k.is_ray_or_point_or_inequality()) {
00768             // The constraint is an inequality:
00769             // the violating generators are those in Q-.
00770             j = sup_bound;
00771             // For all the generators in Q+, set to 1 the corresponding
00772             // entry for the constraint `source_k' in the saturation matrix.
00773             for (dimension_type l = lines_or_equal_bound; l < sup_bound; ++l)
00774               sat[l].set(k);
00775           }
00776           else
00777             // The constraint is an equality:
00778             // the violating generators are those in the union of Q+ and Q-.
00779             j = lines_or_equal_bound;
00780 
00781           // Swapping the newly added rays
00782           // (index `i' running through `dest_num_rows - 1' down-to `bound')
00783           // with the generators violating the constraint
00784           // (index `j' running through `j' up-to `bound - 1').
00785           dimension_type i = dest_num_rows;
00786           while (j < bound && i > bound) {
00787             --i;
00788             std::swap(dest[i], dest[j]);
00789             std::swap(scalar_prod[i], scalar_prod[j]);
00790             std::swap(sat[i], sat[j]);
00791             ++j;
00792             dest.set_sorted(false);
00793           }
00794           // Setting the number of generators in `dest':
00795           // - if the number of generators violating the constraint
00796           //   is less than or equal to the number of the newly added
00797           //   generators, we assign `i' to `dest_num_rows' because
00798           //   all generators above this index are significant;
00799           // - otherwise, we assign `j' to `dest_num_rows' because
00800           //   all generators below index `j-1' violates the constraint.
00801           dest_num_rows = (j == bound) ? i : j;
00802         }
00803         // We continue with the next constraint.
00804         ++k;
00805       }
00806     }
00807 #if !REACTIVE_ABANDONING
00808     // Check if the client has requested abandoning all exponential
00809     // computations.  If so, the exception specified by the client
00810     // is thrown now.
00811     maybe_abandon();
00812 #endif
00813   }
00814 
00815   // We may have identified some redundant constraints in `source',
00816   // which have been swapped at the end of the system.
00817   if (source_num_redundant > 0) {
00818     assert(source_num_redundant == source.num_rows() - source_num_rows);
00819     source.erase_to_end(source_num_rows);
00820     sat.columns_erase_to_end(source_num_rows);
00821   }
00822   // If `start == 0', then `source' was sorted and remained so.
00823   // If otherwise `start > 0', then the two sub-system made by the
00824   // non-pending rows and the pending rows, respectively, were both sorted.
00825   // Thus, the overall system is sorted if and only if either
00826   // `start == source_num_rows' (i.e., the second sub-system is empty)
00827   // or the row ordering holds for the two rows at the boundary between
00828   // the two sub-systems.
00829   if (start > 0 && start < source_num_rows)
00830     source.set_sorted(compare(source[start - 1], source[start]) <= 0);
00831   // There are no longer pending constraints in `source'.
00832   source.unset_pending_rows();
00833 
00834   // We may have identified some redundant rays in `dest',
00835   // which have been swapped at the end of the system.
00836   if (dest_num_rows < dest.num_rows()) {
00837     dest.erase_to_end(dest_num_rows);
00838     // Be careful: we might have erased some of the non-pending rows.
00839     if (dest.first_pending_row() > dest_num_rows)
00840       dest.unset_pending_rows();
00841     sat.rows_erase_to_end(dest_num_rows);
00842   }
00843   if (dest.is_sorted())
00844     // If the non-pending generators in `dest' are still declared to be
00845     // sorted, then we have to also check for the sortedness of the
00846     // pending generators.
00847     for (dimension_type i = dest.first_pending_row(); i < dest_num_rows; ++i)
00848       if (compare(dest[i - 1], dest[i]) > 0) {
00849         dest.set_sorted(false);
00850         break;
00851       }
00852   // There are no pending generators in `dest'.
00853   dest.unset_pending_rows();
00854 
00855   return num_lines_or_equalities;
00856 }

int Parma_Polyhedra_Library::Polyhedron::simplify ( Linear_System sys,
Saturation_Matrix sat 
) [static, private]

Uses Gauss' elimination method to simplify the result of conversion().

Returns:
The rank of sys.
Parameters:
sys The system to simplify: it will be modified;
sat The saturation matrix corresponding to sys.
sys may be modified by swapping some of its rows and by possibly removing some of them, if they turn out to be redundant.

If sys is a system of constraints, then the rows of sat are indexed by constraints and its columns are indexed by generators; otherwise, if sys is a system of generators, then the rows of sat are indexed by generators and its columns by constraints.

Given a system of constraints or a system of generators, this function simplifies it using Gauss' elimination method (to remove redundant equalities/lines), deleting redundant inequalities/rays/points and making back-substitution. The explanation that follows assumes that sys is a system of constraints. For the case when sys is a system of generators, a similar explanation can be obtain by applying duality.

The explanation relies on the notion of redundancy. (See the Introduction.)

First we make some observations that can help the reader in understanding the function:

Proposition: An inequality that is saturated by all the generators can be transformed to an equality.

In fact, by combining any number of generators that saturate the constraints, we obtain a generator that saturates the constraints too:

\[ \langle \vect{c}, \vect{r}_1 \rangle = 0 \land \langle \vect{c}, \vect{r}_2 \rangle = 0 \Rightarrow \langle \vect{c}, (\lambda_1 \vect{r}_1 + \lambda_2 \vect{r}_2) \rangle = \lambda_1 \langle \vect{c}, \vect{r}_1 \rangle + \lambda_2 \langle \vect{c}, \vect{r}_2 \rangle = 0, \]

where $\lambda_1, \lambda_2$ can be any real number.

Definition at line 82 of file simplify.cc.

References Parma_Polyhedra_Library::Linear_System::back_substitute(), empty, Parma_Polyhedra_Library::Matrix::erase_to_end(), Parma_Polyhedra_Library::Linear_System::gauss(), Parma_Polyhedra_Library::Saturation_Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), Parma_Polyhedra_Library::Linear_System::OK(), Parma_Polyhedra_Library::Saturation_Matrix::rows_erase_to_end(), Parma_Polyhedra_Library::Linear_System::set_sorted(), Parma_Polyhedra_Library::Linear_System::sign_normalize(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

Referenced by add_and_minimize(), and minimize().

00082                                                                   {
00083   // This method is only applied to a well-formed system `sys'.
00084   assert(sys.OK(true));
00085 
00086   dimension_type num_rows = sys.num_rows();
00087   const dimension_type num_columns = sys.num_columns();
00088   const dimension_type num_cols_sat = sat.num_columns();
00089 
00090   // Looking for the first inequality in `sys'.
00091   dimension_type num_lines_or_equalities = 0;
00092   while (num_lines_or_equalities < num_rows
00093          && sys[num_lines_or_equalities].is_line_or_equality())
00094     ++num_lines_or_equalities;
00095 
00096   // `num_saturators[i]' will contain the number of generators
00097   // that saturate the constraint `sys[i]'.
00098   static std::vector<dimension_type> num_saturators;
00099   num_saturators.reserve(num_rows);
00100 
00101   // Computing the number of saturators for each inequality,
00102   // possibly identifying and swapping those that happen to be
00103   // equalities (see Proposition above).
00104   for (dimension_type i = num_lines_or_equalities; i < num_rows; ++i) {
00105     if (sat[i].empty()) {
00106       // The constraint `sys[i]' is saturated by all the generators.
00107       // Thus, either it is already an equality or it can be transformed
00108       // to an equality (see Proposition above).
00109       sys[i].set_is_line_or_equality();
00110       // Note: simple normalization already holds.
00111       sys[i].sign_normalize();
00112       // We also move it just after all the other equalities,
00113       // so that system `sys' keeps its partial sortedness.
00114       if (i != num_lines_or_equalities) {
00115         std::swap(sys[i], sys[num_lines_or_equalities]);
00116         std::swap(sat[i], sat[num_lines_or_equalities]);
00117         std::swap(num_saturators[i], num_saturators[num_lines_or_equalities]);
00118       }
00119       ++num_lines_or_equalities;
00120       // `sys' is no longer sorted.
00121       sys.set_sorted(false);
00122     }
00123     else
00124       // There exists a generator which does not saturate `sys[i]',
00125       // so that `sys[i]' is indeed an inequality.
00126       // We store the number of its saturators.
00127       num_saturators[i] = num_cols_sat - sat[i].count_ones();
00128   }
00129 
00130   // At this point, all the equalities of `sys' (included those
00131   // inequalities that we just transformed to equalities) have
00132   // indexes between 0 and `num_lines_or_equalities' - 1,
00133   // which is the property needed by method gauss().
00134   // We can simplify the system of equalities, obtaining the rank
00135   // of `sys' as result.
00136   const dimension_type rank = sys.gauss(num_lines_or_equalities);
00137 
00138   // Now the irredundant equalities of `sys' have indexes from 0
00139   // to `rank' - 1, whereas the equalities having indexes from `rank'
00140   // to `num_lines_or_equalities' - 1 are all redundant.
00141   // (The inequalities in `sys' have been left untouched.)
00142   // The rows containing equalities are not sorted.
00143 
00144   if (rank < num_lines_or_equalities) {
00145     // We identified some redundant equalities.
00146     // Moving them at the bottom of `sys':
00147     // - index `redundant' runs through the redundant equalities
00148     // - index `erasing' identifies the first row that should
00149     //   be erased after this loop.
00150     // Note that we exit the loop either because we have moved all
00151     // redundant equalities or because we have moved all the
00152     // inequalities.
00153     for (dimension_type redundant = rank,
00154            erasing = num_rows;
00155          redundant < num_lines_or_equalities
00156            && erasing > num_lines_or_equalities;
00157          ) {
00158       --erasing;
00159       std::swap(sys[redundant], sys[erasing]);
00160       std::swap(sat[redundant], sat[erasing]);
00161       std::swap(num_saturators[redundant], num_saturators[erasing]);
00162       sys.set_sorted(false);
00163       ++redundant;
00164     }
00165     // Adjusting the value of `num_rows' to the number of meaningful
00166     // rows of `sys': `num_lines_or_equalities' - `rank' is the number of
00167     // redundant equalities moved to the bottom of `sys', which are
00168     // no longer meaningful.
00169     num_rows -= num_lines_or_equalities - rank;
00170     // Adjusting the value of `num_lines_or_equalities'.
00171     num_lines_or_equalities = rank;
00172   }
00173 
00174   // Now we use the definition of redundancy (given in the Introduction)
00175   // to remove redundant inequalities.
00176 
00177   // First we check the saturation rule, which provides a necessary
00178   // condition for an inequality to be irredundant (i.e., it provides
00179   // a sufficient condition for identifying redundant inequalities).
00180   // Let
00181   //   num_saturators[i] = num_sat_lines[i] + num_sat_rays_or_points[i];
00182   //   dim_lin_space = num_irred_lines;
00183   //   dim_ray_space
00184   //     = dim_vector_space - num_irred_equalities - dim_lin_space
00185   //     = num_columns - 1 - num_lines_or_equalities - dim_lin_space;
00186   //   min_sat_rays_or_points = dim_ray_space.
00187   //
00188   // An inequality saturated by less than `dim_ray_space' _rays/points_
00189   // is redundant. Thus we have the implication
00190   //
00191   //   (num_saturators[i] - num_sat_lines[i] < dim_ray_space)
00192   //      ==>
00193   //        redundant(sys[i]).
00194   //
00195   // Moreover, since every line saturates all inequalities, we also have
00196   //     dim_lin_space = num_sat_lines[i]
00197   // so that we can rewrite the condition above as follows:
00198   //
00199   //   (num_saturators[i] < num_columns - num_lines_or_equalities - 1)
00200   //      ==>
00201   //        redundant(sys[i]).
00202   //
00203   const dimension_type min_saturators
00204     = num_columns - num_lines_or_equalities - 1;
00205   for (dimension_type i = num_lines_or_equalities; i < num_rows; ) {
00206     if (num_saturators[i] < min_saturators) {
00207       // The inequality `sys[i]' is redundant.
00208       --num_rows;
00209       std::swap(sys[i], sys[num_rows]);
00210       std::swap(sat[i], sat[num_rows]);
00211       std::swap(num_saturators[i], num_saturators[num_rows]);
00212       sys.set_sorted(false);
00213     }
00214     else
00215       ++i;
00216   }
00217 
00218   // Now we check the independence rule.
00219   for (dimension_type i = num_lines_or_equalities; i < num_rows; ) {
00220     bool redundant = false;
00221     // NOTE: in the inner loop, index `j' runs through _all_ the
00222     // inequalities and we do not test if `sat[i]' is strictly
00223     // contained into `sat[j]'.  Experimentation has shown that this
00224     // is faster than having `j' only run through the indexes greater
00225     // than `i' and also doing the test `strict_subset(sat[i],
00226     // sat[k])'.
00227     for (dimension_type j = num_lines_or_equalities; j < num_rows; ) {
00228       if (i == j)
00229         // We want to compare different rows of `sys'.
00230         ++j;
00231       else {
00232         // Let us recall that each generator lies on a facet of the
00233         // polyhedron (see the Introduction).
00234         // Given two constraints `c_1' and `c_2', if there are `m'
00235         // generators lying on the hyper-plane corresponding to `c_1',
00236         // the same `m' generators lie on the hyper-plane
00237         // corresponding to `c_2', too, and there is another one lying
00238         // on the latter but not on the former, then `c_2' is more
00239         // restrictive than `c_1', i.e., `c_1' is redundant.
00240         bool strict_subset;
00241         if (subset_or_equal(sat[j], sat[i], strict_subset))
00242           if (strict_subset) {
00243             // All the saturators of the inequality `sys[i]' are
00244             // saturators of the inequality `sys[j]' too,
00245             // and there exists at least one saturator of `sys[j]'
00246             // which is not a saturator of `sys[i]'.
00247             // It follows that inequality `sys[i]' is redundant.
00248             redundant = true;
00249             break;
00250           }
00251           else {
00252             // We have `sat[j] == sat[i]'.  Hence inequalities
00253             // `sys[i]' and `sys[j]' are saturated by the same set of
00254             // generators. Then we can remove either one of the two
00255             // inequalities: we remove `sys[j]'.
00256             --num_rows;
00257             std::swap(sys[j], sys[num_rows]);
00258             std::swap(sat[j], sat[num_rows]);
00259             std::swap(num_saturators[j], num_saturators[num_rows]);
00260             sys.set_sorted(false);
00261           }
00262         else
00263           // If we reach this point then we know that `sat[i]' does
00264           // not contain (and is different from) `sat[j]', so that
00265           // `sys[i]' is not made redundant by inequality `sys[j]'.
00266           ++j;
00267       }
00268     }
00269     if (redundant) {
00270       // The inequality `sys[i]' is redundant.
00271       --num_rows;
00272       std::swap(sys[i], sys[num_rows]);
00273       std::swap(sat[i], sat[num_rows]);
00274       std::swap(num_saturators[i], num_saturators[num_rows]);
00275       sys.set_sorted(false);
00276     }
00277     else
00278       // The inequality `sys[i]' is not redundant.
00279       ++i;
00280   }
00281 
00282   // Here we physically remove the redundant inequalities previously
00283   // moved to the bottom of `sys' and the corresponding `sat' rows.
00284   sys.erase_to_end(num_rows);
00285   sys.unset_pending_rows();
00286   sat.rows_erase_to_end(num_rows);
00287   // At this point the first `num_lines_or_equalities' rows of 'sys'
00288   // represent the irredundant equalities, while the remaining rows
00289   // (i.e., those having indexes from `num_lines_or_equalities' to
00290   // `num_rows' - 1) represent the irredundant inequalities.
00291 #ifndef NDEBUG
00292   // Check if the flag is set (that of the equalities is already set).
00293   for (dimension_type i = num_lines_or_equalities; i < num_rows; ++i)
00294     assert(sys[i].is_ray_or_point_or_inequality());
00295 #endif
00296 
00297   // Finally, since now the sub-system (of `sys') of the irredundant
00298   // equalities is in triangular form, we back substitute each
00299   // variables with the expression obtained considering the equalities
00300   // starting from the last one.
00301   sys.back_substitute(num_lines_or_equalities);
00302 
00303   // The returned value is the number of irredundant equalities i.e.,
00304   // the rank of the sub-system of `sys' containing only equalities.
00305   // (See the Introduction for definition of lineality space dimension.)
00306   return num_lines_or_equalities;
00307 }

void Parma_Polyhedra_Library::Polyhedron::throw_runtime_error ( const char *  method  )  const [protected]

Definition at line 1336 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

Referenced by add_generator().

01336                                                            {
01337   std::ostringstream s;
01338   s << "PPL::";
01339   if (is_necessarily_closed())
01340     s << "C_";
01341   else
01342     s << "NNC_";
01343   s << "Polyhedron::" << method << "." << std::endl;
01344   throw std::runtime_error(s.str());
01345 }

void Parma_Polyhedra_Library::Polyhedron::throw_invalid_argument ( const char *  method,
const char *  reason 
) const [protected]

Definition at line 1348 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

Referenced by affine_image(), affine_preimage(), bounded_affine_image(), bounded_affine_preimage(), fold_space_dimensions(), generalized_affine_image(), generalized_affine_preimage(), map_space_dimensions(), and Polyhedron().

01349                                                                   {
01350   std::ostringstream s;
01351   s << "PPL::";
01352   if (is_necessarily_closed())
01353     s << "C_";
01354   else
01355     s << "NNC_";
01356   s << "Polyhedron::" << method << ":" << std::endl
01357     << reason << ".";
01358   throw std::invalid_argument(s.str());
01359 }

void Parma_Polyhedra_Library::Polyhedron::throw_topology_incompatible ( const char *  method,
const char *  ph_name,
const Polyhedron ph 
) const [protected]

Definition at line 1362 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

Referenced by add_constraint(), add_generator(), add_recycled_constraints(), add_recycled_constraints_and_minimize(), add_recycled_generators(), add_recycled_generators_and_minimize(), BHRZ03_widening_assign(), concatenate_assign(), contains(), H79_widening_assign(), intersection_assign(), intersection_assign_and_minimize(), limited_BHRZ03_extrapolation_assign(), limited_H79_extrapolation_assign(), poly_difference_assign(), poly_hull_assign(), poly_hull_assign_and_minimize(), Polyhedron(), swap(), and time_elapse_assign().

01364                                                                          {
01365   std::ostringstream s;
01366   s << "PPL::";
01367   if (is_necessarily_closed())
01368     s << "C_";
01369   else
01370     s << "NNC_";
01371   s << "Polyhedron::" << method << ":" << std::endl
01372     << ph_name << " is a ";
01373   if (ph.is_necessarily_closed())
01374     s << "C_";
01375   else
01376     s << "NNC_";
01377   s << "Polyhedron." << std::endl;
01378   throw std::invalid_argument(s.str());
01379 }

void Parma_Polyhedra_Library::Polyhedron::throw_topology_incompatible ( const char *  method,
const char *  c_name,
const Constraint c 
) const [protected]

Definition at line 1382 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

01384                                                                       {
01385   assert(is_necessarily_closed());
01386   std::ostringstream s;
01387   s << "PPL::C_Polyhedron::" << method << ":" << std::endl
01388     << c_name << " is a strict inequality.";
01389   throw std::invalid_argument(s.str());
01390 }

void Parma_Polyhedra_Library::Polyhedron::throw_topology_incompatible ( const char *  method,
const char *  g_name,
const Generator g 
) const [protected]

Definition at line 1393 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

01395                                                                      {
01396   assert(is_necessarily_closed());
01397   std::ostringstream s;
01398   s << "PPL::C_Polyhedron::" << method << ":" << std::endl
01399     << g_name << " is a closure point.";
01400   throw std::invalid_argument(s.str());
01401 }

void Parma_Polyhedra_Library::Polyhedron::throw_topology_incompatible ( const char *  method,
const char *  cs_name,
const Constraint_System cs 
) const [protected]

Definition at line 1404 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

01406                                                                              {
01407   assert(is_necessarily_closed());
01408   std::ostringstream s;
01409   s << "PPL::C_Polyhedron::" << method << ":" << std::endl
01410     << cs_name << " contains strict inequalities.";
01411   throw std::invalid_argument(s.str());
01412 }

void Parma_Polyhedra_Library::Polyhedron::throw_topology_incompatible ( const char *  method,
const char *  gs_name,
const Generator_System gs 
) const [protected]

Definition at line 1415 of file Polyhedron_nonpublic.cc.

01417                                                                             {
01418   std::ostringstream s;
01419   s << "PPL::C_Polyhedron::" << method << ":" << std::endl
01420     << gs_name << " contains closure points.";
01421   throw std::invalid_argument(s.str());
01422 }

void Parma_Polyhedra_Library::Polyhedron::throw_dimension_incompatible ( const char *  method,
const char *  other_name,
dimension_type  other_dim 
) const [protected]

void Parma_Polyhedra_Library::Polyhedron::throw_dimension_incompatible ( const char *  method,
const char *  ph_name,
const Polyhedron ph 
) const [protected]

Definition at line 1438 of file Polyhedron_nonpublic.cc.

References space_dimension(), and throw_dimension_incompatible().

01440                                                                           {
01441   throw_dimension_incompatible(method, ph_name, ph.space_dimension());
01442 }

void Parma_Polyhedra_Library::Polyhedron::throw_dimension_incompatible ( const char *  method,
const char *  e_name,
const Linear_Expression e 
) const [protected]

Definition at line 1445 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Linear_Expression::space_dimension(), and throw_dimension_incompatible().

01447                                                                                 {
01448   throw_dimension_incompatible(method, e_name, e.space_dimension());
01449 }

void Parma_Polyhedra_Library::Polyhedron::throw_dimension_incompatible ( const char *  method,
const char *  c_name,
const Constraint c 
) const [protected]

Definition at line 1452 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Constraint::space_dimension(), and throw_dimension_incompatible().

01454                                                                          {
01455   throw_dimension_incompatible(method, c_name, c.space_dimension());
01456 }

void Parma_Polyhedra_Library::Polyhedron::throw_dimension_incompatible ( const char *  method,
const char *  g_name,
const Generator g 
) const [protected]

Definition at line 1459 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Generator::space_dimension(), and throw_dimension_incompatible().

01461                                                                         {
01462   throw_dimension_incompatible(method, g_name, g.space_dimension());
01463 }

void Parma_Polyhedra_Library::Polyhedron::throw_dimension_incompatible ( const char *  method,
const char *  cg_name,
const Congruence cg 
) const [protected]

Definition at line 1466 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Congruence::space_dimension(), and throw_dimension_incompatible().

01468                                                                           {
01469   throw_dimension_incompatible(method, cg_name, cg.space_dimension());
01470 }

void Parma_Polyhedra_Library::Polyhedron::throw_dimension_incompatible ( const char *  method,
const char *  cs_name,
const Constraint_System cs 
) const [protected]

Definition at line 1473 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Constraint_System::space_dimension(), and throw_dimension_incompatible().

01475                                                                                  {
01476   throw_dimension_incompatible(method, cs_name, cs.space_dimension());
01477 }

void Parma_Polyhedra_Library::Polyhedron::throw_dimension_incompatible ( const char *  method,
const char *  gs_name,
const Generator_System gs 
) const [protected]

Definition at line 1480 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Generator_System::space_dimension(), and throw_dimension_incompatible().

01482                                                                                 {
01483   throw_dimension_incompatible(method, gs_name, gs.space_dimension());
01484 }

void Parma_Polyhedra_Library::Polyhedron::throw_dimension_incompatible ( const char *  method,
const char *  cgs_name,
const Congruence_System cgs 
) const [protected]

Definition at line 1487 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Congruence_System::space_dimension(), and throw_dimension_incompatible().

01489                                                                                   {
01490   throw_dimension_incompatible(method, cgs_name, cgs.space_dimension());
01491 }

void Parma_Polyhedra_Library::Polyhedron::throw_dimension_incompatible ( const char *  method,
const char *  var_name,
const Variable  var 
) const [protected]

Definition at line 1494 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed(), Parma_Polyhedra_Library::Variable::space_dimension(), and space_dimension().

01496                                                                         {
01497   std::ostringstream s;
01498   s << "PPL::";
01499   if (is_necessarily_closed())
01500     s << "C_";
01501   else
01502     s << "NNC_";
01503   s << "Polyhedron::" << method << ":" << std::endl
01504     << "this->space_dimension() == " << space_dimension() << ", "
01505     << var_name << ".space_dimension() == " << var.space_dimension() << ".";
01506   throw std::invalid_argument(s.str());
01507 }

void Parma_Polyhedra_Library::Polyhedron::throw_dimension_incompatible ( const char *  method,
dimension_type  required_space_dim 
) const [protected]

Definition at line 1511 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed(), and space_dimension().

01512                                                                       {
01513   std::ostringstream s;
01514   s << "PPL::";
01515   if (is_necessarily_closed())
01516     s << "C_";
01517   else
01518     s << "NNC_";
01519   s << "Polyhedron::" << method << ":" << std::endl
01520     << "this->space_dimension() == " << space_dimension()
01521     << ", required space dimension == " << required_space_dim << ".";
01522   throw std::invalid_argument(s.str());
01523 }

void Parma_Polyhedra_Library::Polyhedron::throw_space_dimension_overflow ( Topology  topol,
const char *  method,
const char *  reason 
) [static, protected]

Definition at line 1526 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::NECESSARILY_CLOSED.

Referenced by add_space_dimensions_and_embed(), add_space_dimensions_and_project(), concatenate_assign(), and expand_space_dimension().

01528                                                                     {
01529   std::ostringstream s;
01530   s << "PPL::";
01531   if (topol == NECESSARILY_CLOSED)
01532     s << "C_";
01533   else
01534     s << "NNC_";
01535   s << "Polyhedron::" << method << ":" << std::endl
01536     << reason << ".";
01537   throw std::length_error(s.str());
01538 }

void Parma_Polyhedra_Library::Polyhedron::throw_invalid_generator ( const char *  method,
const char *  g_name 
) const [protected]

Definition at line 1541 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

Referenced by add_generator().

01542                                                                    {
01543   std::ostringstream s;
01544   s << "PPL::";
01545   if (is_necessarily_closed())
01546     s << "C_";
01547   else
01548     s << "NNC_";
01549   s << "Polyhedron::" << method << ":" << std::endl
01550     << "*this is an empty polyhedron and "
01551     << g_name << " is not a point.";
01552   throw std::invalid_argument(s.str());
01553 }

void Parma_Polyhedra_Library::Polyhedron::throw_invalid_generators ( const char *  method,
const char *  gs_name 
) const [protected]

Definition at line 1556 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

Referenced by add_recycled_generators(), add_recycled_generators_and_minimize(), and Polyhedron().

01557                                                                      {
01558   std::ostringstream s;
01559   s << "PPL::";
01560   if (is_necessarily_closed())
01561     s << "C_";
01562   else
01563     s << "NNC_";
01564   s << "Polyhedron::" << method << ":" << std::endl
01565     << "*this is an empty polyhedron and" << std::endl
01566     << "the non-empty generator system " << gs_name << " contains no points.";
01567   throw std::invalid_argument(s.str());
01568 }


Friends And Related Function Documentation

friend class Parma_Polyhedra_Library::BD_Shape [friend]

Definition at line 2568 of file Polyhedron.defs.hh.

Definition at line 2569 of file Polyhedron.defs.hh.

Definition at line 2570 of file Polyhedron.defs.hh.

bool operator== ( const Polyhedron x,
const Polyhedron y 
) [friend]

std::ostream & operator<< ( std::ostream &  s,
const Polyhedron ph 
) [related]

Output operator.

Writes a textual representation of ph on s: false is written if ph is an empty polyhedron; true is written if ph is a universe polyhedron; a minimized system of constraints defining ph is written otherwise, all constraints in one row separated by ", ".

Definition at line 2959 of file Polyhedron_public.cc.

References is_empty(), and minimized_constraints().

02959                                                                {
02960   if (ph.is_empty())
02961     s << "false";
02962   else
02963     s << ph.minimized_constraints();
02964   return s;
02965 }

bool operator!= ( const Polyhedron x,
const Polyhedron y 
) [related]

Returns true if and only if x and y are different polyhedra.

Note that x and y may be topology- and/or dimension-incompatible polyhedra: in those cases, the value true is returned.

Definition at line 332 of file Polyhedron.inlines.hh.

00332                                                      {
00333   return !(x == y);
00334 }

Specializes std::swap.

Definition at line 100 of file Polyhedron.inlines.hh.

References swap().

00101                                                 {
00102   x.swap(y);
00103 }

template<typename PH>
bool poly_hull_assign_if_exact ( PH &  p,
const PH &  q 
) [related]

If the poly-hull of p and q is exact it is assigned to p and true is returned, otherwise false is returned.

Definition at line 51 of file algorithms.hh.

References Parma_Polyhedra_Library::Powerset< Parma_Polyhedra_Library::Determinate< PH > >::begin(), contains(), and Parma_Polyhedra_Library::Powerset< Parma_Polyhedra_Library::Determinate< PH > >::end().

00051                                               {
00052   PH phull = p;
00053   NNC_Polyhedron nnc_p(p);
00054   phull.poly_hull_assign(q);
00055   std::pair<PH, Polyhedra_Powerset<NNC_Polyhedron> >
00056     partition = linear_partition(q, phull);
00057   const Polyhedra_Powerset<NNC_Polyhedron>& s = partition.second;
00058   typedef Polyhedra_Powerset<NNC_Polyhedron>::const_iterator iter;
00059   for (iter i = s.begin(), s_end = s.end(); i != s_end; ++i)
00060     // The polyhedral hull is exact if and only if all the elements
00061     // of the partition of the polyhedral hull of `p' and `q' with
00062     // respect to `q' are included in `p'
00063     if (!nnc_p.contains(i->element()))
00064       return false;
00065   p = phull;
00066   return true;
00067 }


Member Data Documentation

The number of dimensions of the enclosing vector space.

Definition at line 2043 of file Polyhedron.defs.hh.

Referenced by add_congruence(), add_congruences(), add_constraint(), add_generator(), add_recycled_constraints(), add_recycled_constraints_and_minimize(), add_recycled_generators(), add_recycled_generators_and_minimize(), add_space_dimensions_and_embed(), add_space_dimensions_and_project(), affine_dimension(), affine_image(), affine_preimage(), ascii_dump(), ascii_load(), BHRZ03_combining_constraints(), BHRZ03_evolving_points(), BHRZ03_evolving_rays(), BHRZ03_widening_assign(), bounded_affine_image(), bounded_affine_preimage(), bounded_BHRZ03_extrapolation_assign(), bounded_H79_extrapolation_assign(), bounds(), Parma_Polyhedra_Library::BHRZ03_Certificate::compare(), concatenate_assign(), constraints(), contains(), expand_space_dimension(), fold_space_dimensions(), generalized_affine_image(), generalized_affine_preimage(), generators(), H79_widening_assign(), intersection_assign(), intersection_assign_and_minimize(), is_bounded(), is_included_in(), is_topologically_closed(), is_universe(), limited_BHRZ03_extrapolation_assign(), limited_H79_extrapolation_assign(), map_space_dimensions(), max_min(), minimize(), OK(), operator=(), poly_difference_assign(), poly_hull_assign(), poly_hull_assign_and_minimize(), Polyhedron(), process_pending(), process_pending_constraints(), process_pending_generators(), quick_equivalence_test(), relation_with(), remove_higher_space_dimensions(), remove_space_dimensions(), select_CH78_constraints(), select_H79_constraints(), set_zero_dim_univ(), shrink_bounding_box(), space_dimension(), strongly_minimize_constraints(), strongly_minimize_generators(), swap(), time_elapse_assign(), topological_closure_assign(), update_constraints(), and update_generators().


The documentation for this class was generated from the following files:

Generated on Wed Jul 16 22:55:49 2008 for PPL by  doxygen 1.5.6