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.

Classes

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

Public Types

typedef Coefficient coefficient_type
 The numeric type of coefficients.

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.
Congruence_System congruences () const
 Returns a system of (equality) congruences satisfied by *this.
Congruence_System minimized_congruences () const
 Returns a system of (equality) congruences satisfied by *this, with no redundant congruences and having the same affine dimension as *this.
Grid_Generator_System grid_generators () const
 Returns a universe system of grid generators.
Grid_Generator_System minimized_grid_generators () const
 Returns a universe system of grid generators.
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.
Poly_Con_Relation relation_with (const Congruence &cg) const
 Returns the relations holding between the polyhedron *this and the congruence c.
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_discrete () const
 Returns true if and only if *this is discrete.
bool is_bounded () const
 Returns true if and only if *this is a bounded polyhedron.
bool contains_integer_point () const
 Returns true if and only if *this contains at least one integer point.
bool constrains (Variable var) const
 Returns true if and only if var is constrained in *this.
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 &g) 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 &g) 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 frequency (const Linear_Expression &expr, Coefficient &freq_n, Coefficient &freq_d, Coefficient &val_n, Coefficient &val_d) const
 Returns true if and only if there exist a unique value val such that *this saturates the equality expr = val.
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.
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).
void add_generator (const Generator &g)
 Adds a copy of generator g to the system of generators of *this (without minimizing the result).
void add_congruence (const Congruence &cg)
 Adds a copy of congruence cg to *this, if cg can be exactly represented by a polyhedron.
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).
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).
void add_congruences (const Congruence_System &cgs)
 Adds a copy of the congruences in cgs to *this, if all the congruences can be exactly represented by a polyhedron.
void add_recycled_congruences (Congruence_System &cgs)
 Adds the congruences in cgs to *this, if all the congruences can be exactly represented by a polyhedron.
void refine_with_constraint (const Constraint &c)
 Uses a copy of constraint c to refine *this.
void refine_with_congruence (const Congruence &cg)
 Uses a copy of congruence cg to refine *this.
void refine_with_constraints (const Constraint_System &cs)
 Uses a copy of the constraints in cs to refine *this.
void refine_with_congruences (const Congruence_System &cgs)
 Uses a copy of the congruences in cgs to refine *this.
void unconstrain (Variable var)
 Computes the cylindrification of *this with respect to space dimension var, assigning the result to *this.
void unconstrain (const Variables_Set &vars)
 Computes the cylindrification of *this with respect to the set of space dimensions vars, assigning the result to *this.
void intersection_assign (const Polyhedron &y)
 Assigns to *this the intersection of *this and y.
void poly_hull_assign (const Polyhedron &y)
 Assigns to *this the poly-hull of *this and y.
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.
void difference_assign (const Polyhedron &y)
 Same as poly_difference_assign(y).
bool simplify_using_context_assign (const Polyhedron &y)
 Assigns to *this a meet-preserving simplification of *this with respect to y. If false is returned, then the intersection is empty.
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, 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, 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, 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, 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 wrap_assign (const Variables_Set &vars, Bounded_Integer_Type_Width w, Bounded_Integer_Type_Representation r, Bounded_Integer_Type_Overflow o, const Constraint_System *pcs=0, unsigned complexity_threshold=16, bool wrap_individually=true)
 Wraps the specified dimensions of the vector space.
void drop_some_non_integer_points (Complexity_Class complexity=ANY_COMPLEXITY)
 Possibly tightens *this by dropping some points with non-integer coordinates.
void drop_some_non_integer_points (const Variables_Set &vars, Complexity_Class complexity=ANY_COMPLEXITY)
 Possibly tightens *this by dropping some points with non-integer coordinates for the space dimensions corresponding to vars.
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)
 Assigns to *this the result of computing the limited extrapolation between *this and y using the BHRZ03-widening operator.
void bounded_BHRZ03_extrapolation_assign (const Polyhedron &y, const Constraint_System &cs, unsigned *tp=0)
 Assigns to *this the result of computing the bounded extrapolation between *this and y using the BHRZ03-widening operator.
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 widening_assign (const Polyhedron &y, unsigned *tp=0)
 Same as H79_widening_assign(y, tp).
void limited_H79_extrapolation_assign (const Polyhedron &y, const Constraint_System &cs, unsigned *tp=0)
 Assigns to *this the result of computing the limited extrapolation between *this and y using the H79-widening operator.
void bounded_H79_extrapolation_assign (const Polyhedron &y, const Constraint_System &cs, unsigned *tp=0)
 Assigns to *this the result of computing the bounded extrapolation between *this and y using the H79-widening operator.
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 &vars)
 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 &vars, Variable dest)
 Folds the space dimensions in vars into dest.
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(std::ostream&) const) 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.
int32_t hash_code () const
 Returns a 32-bit hash code for *this.

Static Public Member Functions

static dimension_type max_space_dimension ()
 Returns the maximum space dimension all kinds of Polyhedron can handle.
static bool can_recycle_constraint_systems ()
 Returns true indicating that this domain has methods that can recycle constraints.
static void initialize ()
 Initializes the class.
static void finalize ()
 Finalizes the class.
static bool can_recycle_congruence_systems ()
 Returns false indicating that this domain cannot recycle congruences.

Protected Member Functions

 Polyhedron (Topology topol, dimension_type num_dimensions, Degenerate_Element kind)
 Builds a polyhedron having the specified properties.
 Polyhedron (const Polyhedron &y, Complexity_Class complexity=ANY_COMPLEXITY)
 Ordinary copy constructor.
 Polyhedron (Topology topol, const Constraint_System &cs)
 Builds a polyhedron from a system of constraints.
 Polyhedron (Topology topol, Constraint_System &cs, Recycle_Input dummy)
 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, Recycle_Input dummy)
 Builds a polyhedron recycling a system of generators.
template<typename Interval >
 Polyhedron (Topology topol, const Box< Interval > &box, Complexity_Class complexity=ANY_COMPLEXITY)
 Builds a polyhedron from a box.
Polyhedronoperator= (const Polyhedron &y)
 The assignment operator. (*this and y can be dimension-incompatible.).
bool BFT00_poly_hull_assign_if_exact (const Polyhedron &y)
 If the poly-hull of *this and y is exact it is assigned to *this and true is returned, otherwise false is returned.
bool BHZ09_poly_hull_assign_if_exact (const Polyhedron &y)
bool BHZ09_C_poly_hull_assign_if_exact (const Polyhedron &y)
bool BHZ09_NNC_poly_hull_assign_if_exact (const Polyhedron &y)
void drop_some_non_integer_points (const Variables_Set *pvars, Complexity_Class complexity)
 Possibly tightens *this by dropping some points with non-integer coordinates for the space dimensions corresponding to *pvars.

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.
void refine_no_check (const Constraint &c)
 Uses a copy of constraint c to refine the system of constraints of *this.
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, bool maximize, Coefficient &ext_n, Coefficient &ext_d, bool &included, Generator &g) 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.
Constraint_System simplified_constraints () const
 If constraints are up-to-date, obtain a simplified copy of them.
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, Bit_Matrix &sat1, Bit_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, Bit_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, Bit_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, Bit_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, Bit_Matrix &sat, dimension_type num_lines_or_equalities)
 Performs the conversion from constraints to generators and vice versa.
static dimension_type simplify (Linear_System &mat, Bit_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.
Bit_Matrix sat_c
 The saturation matrix having constraints on its columns.
Bit_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.

Static Private Attributes

static dimension_typesimplify_num_saturators_p = 0
 Pointer to an array used by simplify().
static size_t simplify_num_saturators_size = 0
 Dimension of an array used by simplify().

Friends

class Parma_Polyhedra_Library::Box
class Parma_Polyhedra_Library::BD_Shape
class Parma_Polyhedra_Library::Octagonal_Shape
class Parma_Polyhedra_Library::Grid
class Parma_Polyhedra_Library::BHRZ03_Certificate
class Parma_Polyhedra_Library::H79_Certificate
bool operator== (const Polyhedron &x, const Polyhedron &y)
bool Parma_Polyhedra_Library::Interfaces::is_necessarily_closed_for_interfaces (const Polyhedron &)

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.

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, 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)

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.

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 vars;
  vars.insert(y);
  vars.insert(z);
  ph.remove_space_dimensions(vars);
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> vars1;
  vars1.insert(y);
  ph.remove_space_dimensions(vars1);
  set<Variable> vars2;
  vars2.insert(z);
  ph.remove_space_dimensions(vars2);
In this case, the result is the polyhedron $\bigl\{(3, 0)^\transpose \bigr\} \sseq \Rset^2$: when removing the set of dimensions vars2 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 365 of file Polyhedron.defs.hh.


Member Typedef Documentation

The numeric type of coefficients.

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


Member Enumeration Documentation

Enumerator:
TVB_TRUE 
TVB_FALSE 
TVB_DONT_KNOW 

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

02296                             {
02297     TVB_TRUE,
02298     TVB_FALSE,
02299     TVB_DONT_KNOW
02300   };


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 50 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.

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

Parma_Polyhedra_Library::Polyhedron::Polyhedron ( const Polyhedron y,
Complexity_Class  complexity = ANY_COMPLEXITY 
) [protected]

Ordinary copy constructor.

The complexity argument is ignored.

Definition at line 71 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().

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

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 88 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(), swap(), throw_topology_incompatible(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

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

Parma_Polyhedra_Library::Polyhedron::Polyhedron ( Topology  topol,
Constraint_System cs,
Recycle_Input  dummy 
) [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 may be recycled to build the polyhedron.
dummy A dummy tag to syntactically differentiate this one from the other constructors.
Exceptions:
std::invalid_argument Thrown if the topology of cs is incompatible with topol.

Definition at line 137 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(), swap(), throw_topology_incompatible(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

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

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 185 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, swap(), throw_invalid_generators(), throw_topology_incompatible(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

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

Parma_Polyhedra_Library::Polyhedron::Polyhedron ( Topology  topol,
Generator_System gs,
Recycle_Input  dummy 
) [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 may be recycled to build the polyhedron.
dummy A dummy tag to syntactically differentiate this one from the other constructors.
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 248 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::Matrix::has_no_rows(), 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(), 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, swap(), throw_invalid_generators(), throw_topology_incompatible(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

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

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

Builds a polyhedron from a box.

This will use an algorithm whose complexity is polynomial and build the smallest polyhedron with topology topol containing box.

Parameters:
topol The topology of the polyhedron;
box The box representing the polyhedron to be built;
complexity This argument is ignored.

Definition at line 36 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::Box< ITV >::get_lower_bound(), Parma_Polyhedra_Library::Box< ITV >::get_upper_bound(), Parma_Polyhedra_Library::Constraint_System::insert(), Parma_Polyhedra_Library::Box< ITV >::is_empty(), Parma_Polyhedra_Library::NECESSARILY_CLOSED, Parma_Polyhedra_Library::Matrix::num_rows(), OK(), PPL_DIRTY_TEMP_COEFFICIENT, 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::Box< ITV >::space_dimension(), and Parma_Polyhedra_Library::Constraint_System::swap().

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

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

Destructor.

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

00096                         {
00097 }


Member Function Documentation

bool Parma_Polyhedra_Library::Polyhedron::add_and_minimize ( bool  con_to_gen,
Linear_System source,
Linear_System dest,
Bit_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 335 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::Bit_Matrix::resize(), and simplify().

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

bool Parma_Polyhedra_Library::Polyhedron::add_and_minimize ( bool  con_to_gen,
Linear_System source1,
Linear_System dest,
Bit_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&, Bit_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 234 of file minimize.cc.

References Parma_Polyhedra_Library::Linear_System::add_pending_row(), Parma_Polyhedra_Library::cmp(), Parma_Polyhedra_Library::Matrix::has_no_rows(), 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 process_pending_constraints(), and process_pending_generators().

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

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

Adds a copy of congruence cg to *this, if cg can be exactly represented by a polyhedron.

Exceptions:
std::invalid_argument Thrown if *this and congruence cg are dimension-incompatible, of if cg is a proper congruence which is neither a tautology, nor a contradiction.

Definition at line 1274 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::Constraint::EQUALITY, Parma_Polyhedra_Library::Congruence::is_equality(), Parma_Polyhedra_Library::Congruence::is_inconsistent(), Parma_Polyhedra_Library::Congruence::is_proper_congruence(), Parma_Polyhedra_Library::Congruence::is_tautological(), Parma_Polyhedra_Library::Checked::le, marked_empty(), Parma_Polyhedra_Library::NECESSARILY_CLOSED, refine_no_check(), set_empty(), space_dim, Parma_Polyhedra_Library::Congruence::space_dimension(), Parma_Polyhedra_Library::Linear_Row::strong_normalize(), throw_dimension_incompatible(), and throw_invalid_argument().

01274                                                   {
01275   // Dimension-compatibility check:
01276   // the dimension of `cg' can not be greater than space_dim.
01277   if (space_dim < cg.space_dimension())
01278     throw_dimension_incompatible("add_congruence(cg)", "cg", cg);
01279 
01280   // Handle the case of proper congruences first.
01281   if (cg.is_proper_congruence()) {
01282     if (cg.is_tautological())
01283       return;
01284     if (cg.is_inconsistent()) {
01285       set_empty();
01286       return;
01287     }
01288     // Non-trivial and proper congruences are not allowed.
01289     throw_invalid_argument("add_congruence(cg)",
01290                            "cg is a non-trivial, proper congruence");
01291   }
01292 
01293   PPL_ASSERT(cg.is_equality());
01294   // Handle empty and 0-dim cases first.
01295   if (marked_empty())
01296     return;
01297   if (space_dim == 0) {
01298     if (cg.is_inconsistent())
01299       set_empty();
01300     return;
01301   }
01302 
01303   // Add the equality.
01304   Linear_Expression le(cg);
01305   Constraint c(le, Constraint::EQUALITY, NECESSARILY_CLOSED);
01306   // Enforce normalization.
01307   c.strong_normalize();
01308   refine_no_check(c);
01309 }

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

Adds a copy of the congruences in cgs to *this, if all the congruences can be exactly represented by a polyhedron.

Parameters:
cgs The congruences to be added.
Exceptions:
std::invalid_argument Thrown if *this and cgs are dimension-incompatible, of if there exists in cgs a proper congruence which is neither a tautology, nor a contradiction.

Definition at line 1647 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::Congruence::is_equality(), Parma_Polyhedra_Library::Congruence::is_inconsistent(), Parma_Polyhedra_Library::Congruence::is_proper_congruence(), Parma_Polyhedra_Library::Congruence::is_tautological(), Parma_Polyhedra_Library::Checked::le, Parma_Polyhedra_Library::NECESSARILY_CLOSED, set_empty(), space_dim, Parma_Polyhedra_Library::Congruence_System::space_dimension(), Parma_Polyhedra_Library::Linear_Row::strong_normalize(), throw_dimension_incompatible(), and throw_invalid_argument().

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

01647                                                            {
01648   // Dimension-compatibility check.
01649   if (space_dim < cgs.space_dimension())
01650     throw_dimension_incompatible("add_congruences(cgs)", "cgs", cgs);
01651 
01652   Constraint_System cs;
01653   bool inserted = false;
01654   for (Congruence_System::const_iterator i = cgs.begin(),
01655          cgs_end = cgs.end(); i != cgs_end; ++i) {
01656     const Congruence& cg = *i;
01657     if (cg.is_equality()) {
01658       Linear_Expression le(cg);
01659       Constraint c(le, Constraint::EQUALITY, NECESSARILY_CLOSED);
01660       // Enforce normalization.
01661       c.strong_normalize();
01662       // TODO: Consider stealing the row in c when adding it to cs.
01663       cs.insert(c);
01664       inserted = true;
01665     }
01666     else {
01667       PPL_ASSERT(cg.is_proper_congruence());
01668       if (cg.is_inconsistent()) {
01669         set_empty();
01670         return;
01671       }
01672       if (!cg.is_tautological())
01673         throw_invalid_argument("add_congruences(cgs)",
01674                                "cgs has a non-trivial, proper congruence");
01675     }
01676   }
01677   // Only add cs if it contains something.
01678   if (inserted)
01679     add_recycled_constraints(cs);
01680 }

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).

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

Definition at line 1250 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::Constraint::is_inconsistent(), is_necessarily_closed(), Parma_Polyhedra_Library::Constraint::is_strict_inequality(), Parma_Polyhedra_Library::Constraint::is_tautological(), marked_empty(), refine_no_check(), set_empty(), space_dim, Parma_Polyhedra_Library::Constraint::space_dimension(), throw_dimension_incompatible(), and throw_topology_incompatible().

Referenced by Parma_Polyhedra_Library::Pointset_Powerset< PSET >::affine_dimension(), BHZ09_NNC_poly_hull_assign_if_exact(), Parma_Polyhedra_Library::C_Polyhedron::C_Polyhedron(), and Parma_Polyhedra_Library::Pointset_Powerset< PSET >::linear_partition_aux().

01250                                                  {
01251   // Topology-compatibility check.
01252   if (c.is_strict_inequality() && is_necessarily_closed()) {
01253     // Trivially true/false strict inequalities are legal.
01254     if (c.is_tautological())
01255       return;
01256     if (c.is_inconsistent()) {
01257       set_empty();
01258       return;
01259     }
01260     // Here c is a non-trivial strict inequality.
01261     throw_topology_incompatible("add_constraint(c)", "c", c);
01262   }
01263 
01264   // Dimension-compatibility check:
01265   // the dimension of `c' can not be greater than space_dim.
01266   if (space_dim < c.space_dimension())
01267     throw_dimension_incompatible("add_constraint(c)", "c", c);
01268 
01269   if (!marked_empty())
01270     refine_no_check(c);
01271 }

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 1540 of file Polyhedron_public.cc.

References add_recycled_constraints().

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

01540                                                           {
01541   // TODO: this is just an executable specification.
01542   Constraint_System cs_copy = cs;
01543   add_recycled_constraints(cs_copy);
01544 }

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 1312 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(), set_zero_dim_univ(), space_dim, Parma_Polyhedra_Library::Generator::space_dimension(), throw_dimension_incompatible(), throw_invalid_generator(), throw_runtime_error(), throw_topology_incompatible(), topology(), Parma_Polyhedra_Library::Generator::type(), and update_generators().

Referenced by BFT00_poly_hull_assign_if_exact(), BHZ09_C_poly_hull_assign_if_exact(), BHZ09_NNC_poly_hull_assign_if_exact(), and generalized_affine_image().

01312                                                {
01313   // Topology-compatibility check.
01314   if (g.is_closure_point() && is_necessarily_closed())
01315     throw_topology_incompatible("add_generator(g)", "g", g);
01316   // Dimension-compatibility check:
01317   // the dimension of `g' can not be greater than space_dim.
01318   const dimension_type g_space_dim = g.space_dimension();
01319   if (space_dim < g_space_dim)
01320     throw_dimension_incompatible("add_generator(g)", "g", g);
01321 
01322   // Dealing with a zero-dimensional space polyhedron first.
01323   if (space_dim == 0) {
01324     // It is not possible to create 0-dim rays or lines.
01325     PPL_ASSERT(g.is_point() || g.is_closure_point());
01326     // Closure points can only be inserted in non-empty polyhedra.
01327     if (marked_empty()) {
01328       if (g.type() != Generator::POINT)
01329         throw_invalid_generator("add_generator(g)", "g");
01330       else
01331         set_zero_dim_univ();
01332     }
01333     PPL_ASSERT_HEAVY(OK());
01334     return;
01335   }
01336 
01337   if (marked_empty()
01338       || (has_pending_constraints() && !process_pending_constraints())
01339       || (!generators_are_up_to_date() && !update_generators())) {
01340     // Here the polyhedron is empty:
01341     // the specification says we can only insert a point.
01342     if (!g.is_point())
01343       throw_invalid_generator("add_generator(g)", "g");
01344     if (g.is_necessarily_closed() || !is_necessarily_closed()) {
01345       gen_sys.insert(g);
01346       // Since `gen_sys' was empty, after inserting `g' we have to resize
01347       // the system of generators to have the right dimension.
01348       gen_sys.adjust_topology_and_space_dimension(topology(), space_dim);
01349       if (!is_necessarily_closed()) {
01350         // In the NNC topology, each point has to be matched by
01351         // a corresponding closure point:
01352         // turn the just inserted point into the corresponding
01353         // (normalized) closure point.
01354         Generator& cp = gen_sys[gen_sys.num_rows() - 1];
01355         cp[space_dim + 1] = 0;
01356         cp.normalize();
01357         // Re-insert the point (which is already normalized).
01358         gen_sys.insert(g);
01359       }
01360     }
01361     else {
01362       // Note: here we have a _legal_ topology mismatch,
01363       // because `g' is NOT a closure point (it is a point!)
01364       // However, by barely invoking `gen_sys.insert(g)' we would
01365       // cause a change in the topology of `gen_sys', which is wrong.
01366       // Thus, we insert a "topology corrected" copy of `g'.
01367       const Linear_Expression nc_expr = Linear_Expression(g);
01368       gen_sys.insert(Generator::point(nc_expr, g.divisor()));
01369       // Since `gen_sys' was empty, after inserting `g' we have to resize
01370       // the system of generators to have the right dimension.
01371       gen_sys.adjust_topology_and_space_dimension(topology(), space_dim);
01372     }
01373     // No longer empty, generators up-to-date and minimized.
01374     clear_empty();
01375     set_generators_minimized();
01376   }
01377   else {
01378     PPL_ASSERT(generators_are_up_to_date());
01379     const bool has_pending = can_have_something_pending();
01380     if (g.is_necessarily_closed() || !is_necessarily_closed()) {
01381       // Since `gen_sys' is not empty, the topology and space dimension
01382       // of the inserted generator are automatically adjusted.
01383       if (has_pending)
01384         gen_sys.insert_pending(g);
01385       else
01386         gen_sys.insert(g);
01387       if (!is_necessarily_closed() && g.is_point()) {
01388         // In the NNC topology, each point has to be matched by
01389         // a corresponding closure point:
01390         // turn the just inserted point into the corresponding
01391         // (normalized) closure point.
01392         Generator& cp = gen_sys[gen_sys.num_rows() - 1];
01393         cp[space_dim + 1] = 0;
01394         cp.normalize();
01395         // Re-insert the point (which is already normalized).
01396         if (has_pending)
01397           gen_sys.insert_pending(g);
01398         else
01399           gen_sys.insert(g);
01400       }
01401     }
01402     else {
01403       PPL_ASSERT(!g.is_closure_point());
01404       // Note: here we have a _legal_ topology mismatch, because
01405       // `g' is NOT a closure point.
01406       // However, by barely invoking `gen_sys.insert(g)' we would
01407       // cause a change in the topology of `gen_sys', which is wrong.
01408       // Thus, we insert a "topology corrected" copy of `g'.
01409       const Linear_Expression nc_expr = Linear_Expression(g);
01410       switch (g.type()) {
01411       case Generator::LINE:
01412         if (has_pending)
01413           gen_sys.insert_pending(Generator::line(nc_expr));
01414         else
01415           gen_sys.insert(Generator::line(nc_expr));
01416         break;
01417       case Generator::RAY:
01418         if (has_pending)
01419           gen_sys.insert_pending(Generator::ray(nc_expr));
01420         else
01421           gen_sys.insert(Generator::ray(nc_expr));
01422         break;
01423       case Generator::POINT:
01424         if (has_pending)
01425           gen_sys.insert_pending(Generator::point(nc_expr, g.divisor()));
01426         else
01427           gen_sys.insert(Generator::point(nc_expr, g.divisor()));
01428         break;
01429       default:
01430         throw_runtime_error("add_generator(const Generator& g)");
01431       }
01432     }
01433 
01434     if (has_pending)
01435       set_generators_pending();
01436     else {
01437       // After adding the new generator,
01438       // constraints are no longer up-to-date.
01439       clear_generators_minimized();
01440       clear_constraints_up_to_date();
01441     }
01442   }
01443   PPL_ASSERT_HEAVY(OK());
01444 }

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 1640 of file Polyhedron_public.cc.

References add_recycled_generators().

01640                                                         {
01641   // TODO: this is just an executable specification.
01642   Generator_System gs_copy = gs;
01643   add_recycled_generators(gs_copy);
01644 }

void Parma_Polyhedra_Library::Polyhedron::add_recycled_congruences ( Congruence_System cgs  )  [inline]

Adds the congruences in cgs to *this, if all the congruences can be exactly represented by a polyhedron.

Parameters:
cgs The congruences to be added. Its elements may be recycled.
Exceptions:
std::invalid_argument Thrown if *this and cgs are dimension-incompatible, of if there exists in cgs a proper congruence which is neither a tautology, nor a contradiction
Warning:
The only assumption that can be made on cgs upon successful or exceptional return is that it can be safely destroyed.

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

References add_congruences().

00372                                                            {
00373   add_congruences(cgs);
00374 }

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 to be added to *this. The constraints in cs may be recycled.
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 1447 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(), Parma_Polyhedra_Library::Matrix::has_no_rows(), 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(), 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, Parma_Polyhedra_Library::swap(), throw_dimension_incompatible(), throw_topology_incompatible(), topology(), Parma_Polyhedra_Library::Linear_System::unset_pending_rows(), and update_constraints().

Referenced by add_congruences(), add_constraints(), BHRZ03_combining_constraints(), bounded_BHRZ03_extrapolation_assign(), bounded_H79_extrapolation_assign(), expand_space_dimension(), H79_widening_assign(), limited_BHRZ03_extrapolation_assign(), limited_H79_extrapolation_assign(), refine_with_congruences(), and simplify_using_context_assign().

01447                                                              {
01448   // Topology compatibility check.
01449   if (is_necessarily_closed() && cs.has_strict_inequalities()) {
01450     // We check if _all_ strict inequalities in cs are trivially false.
01451     // (The iterators already filter away trivially true constraints.)
01452     for (Constraint_System::const_iterator i = cs.begin(),
01453            i_end = cs.end(); i != i_end; ++i) {
01454       if (i->is_strict_inequality()
01455           && !i->is_inconsistent())
01456         throw_topology_incompatible("add_recycled_constraints(cs)",
01457                                     "cs", cs);
01458     }
01459     // If we reach this point, all strict inequalities were inconsistent.
01460     set_empty();
01461     return;
01462   }
01463 
01464   // Dimension-compatibility check:
01465   // the dimension of `cs' can not be greater than space_dim.
01466   const dimension_type cs_space_dim = cs.space_dimension();
01467   if (space_dim < cs_space_dim)
01468     throw_dimension_incompatible("add_recycled_constraints(cs)", "cs", cs);
01469 
01470   // Adding no constraints is a no-op.
01471   if (cs.has_no_rows())
01472     return;
01473 
01474   if (space_dim == 0) {
01475     // In a 0-dimensional space the constraints are
01476     // tautologies (e.g., 0 == 0 or 1 >= 0 or 1 > 0) or
01477     // inconsistent (e.g., 1 == 0 or -1 >= 0 or 0 > 0).
01478     // In a system of constraints `begin()' and `end()' are equal
01479     // if and only if the system only contains tautologies.
01480     if (cs.begin() != cs.end())
01481       // There is a constraint, it must be inconsistent,
01482       // the polyhedron is empty.
01483       status.set_empty();
01484     return;
01485   }
01486 
01487   if (marked_empty())
01488     return;
01489 
01490   // The constraints (possibly with pending rows) are required.
01491   if (has_pending_generators())
01492     process_pending_generators();
01493   else if (!constraints_are_up_to_date())
01494     update_constraints();
01495 
01496   // Adjust `cs' to the right topology and space dimension.
01497   // NOTE: we already checked for topology compatibility.
01498   cs.adjust_topology_and_space_dimension(topology(), space_dim);
01499 
01500   const bool adding_pending = can_have_something_pending();
01501 
01502   // Here we do not require `con_sys' to be sorted.
01503   // also, we _swap_ (instead of copying) the coefficients of `cs'
01504   // (which is not a const).
01505   const dimension_type old_num_rows = con_sys.num_rows();
01506   const dimension_type cs_num_rows = cs.num_rows();
01507   const dimension_type cs_num_columns = cs.num_columns();
01508   con_sys.add_zero_rows(cs_num_rows,
01509                         Linear_Row::Flags(topology(),
01510                                           Linear_Row::RAY_OR_POINT_OR_INEQUALITY));
01511   for (dimension_type i = cs_num_rows; i-- > 0; ) {
01512     // NOTE: we cannot directly swap the rows, since they might have
01513     // different capacities (besides possibly having different sizes):
01514     // thus, we steal one coefficient at a time.
01515     Constraint& new_c = con_sys[old_num_rows + i];
01516     Constraint& old_c = cs[i];
01517     if (old_c.is_equality())
01518       new_c.set_is_equality();
01519     for (dimension_type j = cs_num_columns; j-- > 0; )
01520       std::swap(new_c[j], old_c[j]);
01521   }
01522 
01523   if (adding_pending)
01524     set_constraints_pending();
01525   else {
01526     // The newly added ones are not pending constraints.
01527     con_sys.unset_pending_rows();
01528     // They have been simply appended.
01529     con_sys.set_sorted(false);
01530     // Constraints are not minimized and generators are not up-to-date.
01531     clear_constraints_minimized();
01532     clear_generators_up_to_date();
01533   }
01534   // Note: the constraint system may have become unsatisfiable, thus
01535   // we do not check for satisfiability.
01536   PPL_ASSERT_HEAVY(OK());
01537 }

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 to be added to *this. The generators in gs may be recycled.
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 1547 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(), Parma_Polyhedra_Library::Matrix::has_no_rows(), 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(), set_zero_dim_univ(), space_dim, Parma_Polyhedra_Library::Generator_System::space_dimension(), Parma_Polyhedra_Library::swap(), swap(), throw_dimension_incompatible(), throw_invalid_generators(), throw_topology_incompatible(), topology(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

Referenced by add_generators(), BHRZ03_evolving_points(), BHRZ03_evolving_rays(), generalized_affine_image(), and generalized_affine_preimage().

01547                                                            {
01548   // Topology compatibility check.
01549   if (is_necessarily_closed() && gs.has_closure_points())
01550     throw_topology_incompatible("add_recycled_generators(gs)", "gs", gs);
01551   // Dimension-compatibility check:
01552   // the dimension of `gs' can not be greater than space_dim.
01553   const dimension_type gs_space_dim = gs.space_dimension();
01554   if (space_dim < gs_space_dim)
01555     throw_dimension_incompatible("add_recycled_generators(gs)", "gs", gs);
01556 
01557   // Adding no generators is a no-op.
01558   if (gs.has_no_rows())
01559     return;
01560 
01561   // Adding valid generators to a zero-dimensional polyhedron
01562   // transform it in the zero-dimensional universe polyhedron.
01563   if (space_dim == 0) {
01564     if (marked_empty() && !gs.has_points())
01565       throw_invalid_generators("add_recycled_generators(gs)", "gs");
01566     set_zero_dim_univ();
01567     PPL_ASSERT_HEAVY(OK(true));
01568     return;
01569   }
01570 
01571   // Adjust `gs' to the right topology and dimensions.
01572   // NOTE: we already checked for topology compatibility.
01573   gs.adjust_topology_and_space_dimension(topology(), space_dim);
01574   // For NNC polyhedra, each point must be matched by
01575   // the corresponding closure point.
01576   if (!is_necessarily_closed())
01577     gs.add_corresponding_closure_points();
01578 
01579   // The generators (possibly with pending rows) are required.
01580   if ((has_pending_constraints() && !process_pending_constraints())
01581       || (!generators_are_up_to_date() && !minimize())) {
01582     // We have just discovered that `*this' is empty.
01583     // So `gs' must contain at least one point.
01584     if (!gs.has_points())
01585       throw_invalid_generators("add_recycled_generators(gs)", "gs");
01586     // The polyhedron is no longer empty and generators are up-to-date.
01587     std::swap(gen_sys, gs);
01588     if (gen_sys.num_pending_rows() > 0) {
01589       // Even though `gs' has pending generators, since the constraints
01590       // of the polyhedron are not up-to-date, the polyhedron cannot
01591       // have pending generators. By integrating the pending part
01592       // of `gen_sys' we may loose sortedness.
01593       gen_sys.unset_pending_rows();
01594       gen_sys.set_sorted(false);
01595     }
01596     set_generators_up_to_date();
01597     clear_empty();
01598     PPL_ASSERT_HEAVY(OK());
01599     return;
01600   }
01601 
01602   const bool adding_pending = can_have_something_pending();
01603 
01604   // Here we do not require `gen_sys' to be sorted.
01605   // also, we _swap_ (instead of copying) the coefficients of `gs'
01606   // (which is not a const).
01607   const dimension_type old_num_rows = gen_sys.num_rows();
01608   const dimension_type gs_num_rows = gs.num_rows();
01609   const dimension_type gs_num_columns = gs.num_columns();
01610   gen_sys.add_zero_rows(gs_num_rows,
01611                         Linear_Row::Flags(topology(),
01612                                           Linear_Row::RAY_OR_POINT_OR_INEQUALITY));
01613   for (dimension_type i = gs_num_rows; i-- > 0; ) {
01614     // NOTE: we cannot directly swap the rows, since they might have
01615     // different capacities (besides possibly having different sizes):
01616     // thus, we steal one coefficient at a time.
01617     Generator& new_g = gen_sys[old_num_rows + i];
01618     Generator& old_g = gs[i];
01619     if (old_g.is_line())
01620       new_g.set_is_line();
01621     for (dimension_type j = gs_num_columns; j-- > 0; )
01622       std::swap(new_g[j], old_g[j]);
01623   }
01624 
01625   if (adding_pending)
01626     set_generators_pending();
01627   else {
01628     // The newly added ones are not pending generators.
01629     gen_sys.unset_pending_rows();
01630     // They have been simply appended.
01631     gen_sys.set_sorted(false);
01632     // Constraints are not up-to-date and generators are not minimized.
01633     clear_constraints_up_to_date();
01634     clear_generators_minimized();
01635   }
01636   PPL_ASSERT_HEAVY(OK(true));
01637 }

void Parma_Polyhedra_Library::Polyhedron::add_space_dimensions ( Linear_System mat1,
Linear_System mat2,
Bit_Matrix sat1,
Bit_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 36 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::Bit_Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), Parma_Polyhedra_Library::Bit_Matrix::num_rows(), Parma_Polyhedra_Library::Bit_Matrix::resize(), Parma_Polyhedra_Library::Linear_System::set_index_first_pending_row(), swap(), Parma_Polyhedra_Library::swap(), Parma_Polyhedra_Library::Matrix::swap_columns(), Parma_Polyhedra_Library::Linear_System::topology(), and Parma_Polyhedra_Library::Bit_Matrix::transpose_assign().

Referenced by add_space_dimensions_and_embed(), and add_space_dimensions_and_project().

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

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 92 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(), and generalized_affine_preimage().

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

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 188 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::Matrix::has_no_rows(), 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, swap(), 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().

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

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 60 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 Parma_Polyhedra_Library::Pointset_Powerset< PSET >::affine_dimension(), BHZ09_C_poly_hull_assign_if_exact(), and is_discrete().

00060                                       {
00061   if (is_empty())
00062     return 0;
00063 
00064   const Constraint_System& cs = minimized_constraints();
00065   dimension_type d = space_dim;
00066   for (Constraint_System::const_iterator i = cs.begin(),
00067          cs_end = cs.end(); i != cs_end; ++i)
00068     if (i->is_equality())
00069       --d;
00070   return d;
00071 }

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 2557 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(), 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(), and generalized_affine_image().

02559                                                             {
02560   // The denominator cannot be zero.
02561   if (denominator == 0)
02562     throw_invalid_argument("affine_image(v, e, d)", "d == 0");
02563 
02564   // Dimension-compatibility checks.
02565   // The dimension of `expr' should not be greater than the dimension
02566   // of `*this'.
02567   if (space_dim < expr.space_dimension())
02568     throw_dimension_incompatible("affine_image(v, e, d)", "e", expr);
02569   // `var' should be one of the dimensions of the polyhedron.
02570   const dimension_type var_space_dim = var.space_dimension();
02571   if (space_dim < var_space_dim)
02572     throw_dimension_incompatible("affine_image(v, e, d)", "v", var);
02573 
02574   if (marked_empty())
02575     return;
02576 
02577   if (expr.coefficient(var) != 0) {
02578     // The transformation is invertible:
02579     // minimality and saturators are preserved, so that
02580     // pending rows, if present, are correctly handled.
02581     if (generators_are_up_to_date()) {
02582       // Generator_System::affine_image() requires the third argument
02583       // to be a positive Coefficient.
02584       if (denominator > 0)
02585         gen_sys.affine_image(var_space_dim, expr, denominator);
02586       else
02587         gen_sys.affine_image(var_space_dim, -expr, -denominator);
02588     }
02589     if (constraints_are_up_to_date()) {
02590       // To build the inverse transformation,
02591       // after copying and negating `expr',
02592       // we exchange the roles of `expr[var_space_dim]' and `denominator'.
02593       Linear_Expression inverse;
02594       if (expr[var_space_dim] > 0) {
02595         inverse = -expr;
02596         inverse[var_space_dim] = denominator;
02597         con_sys.affine_preimage(var_space_dim, inverse, expr[var_space_dim]);
02598       }
02599       else {
02600         // The new denominator is negative: we negate everything once
02601         // more, as Constraint_System::affine_preimage() requires the
02602         // third argument to be positive.
02603         inverse = expr;
02604         inverse[var_space_dim] = denominator;
02605         neg_assign(inverse[var_space_dim]);
02606         con_sys.affine_preimage(var_space_dim, inverse, -expr[var_space_dim]);
02607       }
02608     }
02609   }
02610   else {
02611     // The transformation is not invertible.
02612     // We need an up-to-date system of generators.
02613     if (has_something_pending())
02614       remove_pending_to_obtain_generators();
02615     else if (!generators_are_up_to_date())
02616       minimize();
02617     if (!marked_empty()) {
02618       // Generator_System::affine_image() requires the third argument
02619       // to be a positive Coefficient.
02620       if (denominator > 0)
02621         gen_sys.affine_image(var_space_dim, expr, denominator);
02622       else
02623         gen_sys.affine_image(var_space_dim, -expr, -denominator);
02624 
02625       clear_constraints_up_to_date();
02626       clear_generators_minimized();
02627       clear_sat_c_up_to_date();
02628       clear_sat_g_up_to_date();
02629     }
02630   }
02631   PPL_ASSERT_HEAVY(OK());
02632 }

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 2637 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(), 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().

02639                                                                {
02640   // The denominator cannot be zero.
02641   if (denominator == 0)
02642     throw_invalid_argument("affine_preimage(v, e, d)", "d == 0");
02643 
02644   // Dimension-compatibility checks.
02645   // The dimension of `expr' should not be greater than the dimension
02646   // of `*this'.
02647   if (space_dim < expr.space_dimension())
02648     throw_dimension_incompatible("affine_preimage(v, e, d)", "e", expr);
02649   // `var' should be one of the dimensions of the polyhedron.
02650   const dimension_type var_space_dim = var.space_dimension();
02651   if (space_dim < var_space_dim)
02652     throw_dimension_incompatible("affine_preimage(v, e, d)", "v", var);
02653 
02654   if (marked_empty())
02655     return;
02656 
02657   if (expr.coefficient(var) != 0) {
02658     // The transformation is invertible:
02659     // minimality and saturators are preserved.
02660     if (constraints_are_up_to_date()) {
02661       // Constraint_System::affine_preimage() requires the third argument
02662       // to be a positive Coefficient.
02663       if (denominator > 0)
02664         con_sys.affine_preimage(var_space_dim, expr, denominator);
02665       else
02666         con_sys.affine_preimage(var_space_dim, -expr, -denominator);
02667     }
02668     if (generators_are_up_to_date()) {
02669       // To build the inverse transformation,
02670       // after copying and negating `expr',
02671       // we exchange the roles of `expr[var_space_dim]' and `denominator'.
02672       Linear_Expression inverse;
02673       if (expr[var_space_dim] > 0) {
02674         inverse = -expr;
02675         inverse[var_space_dim] = denominator;
02676         gen_sys.affine_image(var_space_dim, inverse, expr[var_space_dim]);
02677       }
02678       else {
02679         // The new denominator is negative:
02680         // we negate everything once more, as Generator_System::affine_image()
02681         // requires the third argument to be positive.
02682         inverse = expr;
02683         inverse[var_space_dim] = denominator;
02684         neg_assign(inverse[var_space_dim]);
02685         gen_sys.affine_image(var_space_dim, inverse, -expr[var_space_dim]);
02686       }
02687     }
02688   }
02689   else {
02690     // The transformation is not invertible.
02691     // We need an up-to-date system of constraints.
02692     if (has_something_pending())
02693       remove_pending_to_obtain_constraints();
02694     else if (!constraints_are_up_to_date())
02695       minimize();
02696     // Constraint_System::affine_preimage() requires the third argument
02697     // to be a positive Coefficient.
02698     if (denominator > 0)
02699       con_sys.affine_preimage(var_space_dim, expr, denominator);
02700     else
02701       con_sys.affine_preimage(var_space_dim, -expr, -denominator);
02702     // Generators, minimality and saturators are no longer valid.
02703     clear_generators_up_to_date();
02704     clear_constraints_minimized();
02705     clear_sat_c_up_to_date();
02706     clear_sat_g_up_to_date();
02707   }
02708   PPL_ASSERT_HEAVY(OK());
02709 }

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

Writes to s an ASCII representation of *this.

Definition at line 3676 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::Bit_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, and status.

03676                                              {
03677   s << "space_dim " << space_dim << "\n";
03678   status.ascii_dump(s);
03679   s << "\ncon_sys ("
03680     << (constraints_are_up_to_date() ? "" : "not_")
03681     << "up-to-date)"
03682     << "\n";
03683   con_sys.ascii_dump(s);
03684   s << "\ngen_sys ("
03685     << (generators_are_up_to_date() ? "" : "not_")
03686     << "up-to-date)"
03687     << "\n";
03688   gen_sys.ascii_dump(s);
03689   s << "\nsat_c\n";
03690   sat_c.ascii_dump(s);
03691   s << "\nsat_g\n";
03692   sat_g.ascii_dump(s);
03693   s << "\n";
03694 }

void Parma_Polyhedra_Library::Polyhedron::ascii_dump (  )  const

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

Referenced by OK().

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

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

Definition at line 3699 of file Polyhedron_public.cc.

03699                                        {
03700   std::string str;
03701 
03702   if (!(s >> str) || str != "space_dim")
03703     return false;
03704 
03705   if (!(s >> space_dim))
03706     return false;
03707 
03708   if (!status.ascii_load(s))
03709     return false;
03710 
03711   if (!(s >> str) || str != "con_sys")
03712     return false;
03713 
03714   if (!(s >> str) || (str != "(not_up-to-date)" && str != "(up-to-date)"))
03715     return false;
03716 
03717   if (!con_sys.ascii_load(s))
03718     return false;
03719 
03720   if (!(s >> str) || str != "gen_sys")
03721     return false;
03722 
03723   if (!(s >> str) || (str != "(not_up-to-date)" && str != "(up-to-date)"))
03724     return false;
03725 
03726   if (!gen_sys.ascii_load(s))
03727     return false;
03728 
03729   if (!(s >> str) || str != "sat_c")
03730     return false;
03731 
03732   if (!sat_c.ascii_load(s))
03733     return false;
03734 
03735   if (!(s >> str) || str != "sat_g")
03736     return false;
03737 
03738   if (!sat_g.ascii_load(s))
03739     return false;
03740 
03741   // Check invariants.
03742   PPL_ASSERT_HEAVY(OK());
03743   return true;
03744 }

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

If the poly-hull of *this and y is exact it is assigned to *this and true is returned, otherwise false is returned.

Current implementation is based on (a variant of) Algorithm 8.1 in A. Bemporad, K. Fukuda, and F. D. Torrisi Convexity Recognition of the Union of Polyhedra Technical Report AUT00-13, ETH Zurich, 2000

Note:
It is assumed that *this and y are topologically closed and dimension-compatible; if the assumption does not hold, the behavior is undefined.

Definition at line 1883 of file Polyhedron_nonpublic.cc.

References add_generator(), Parma_Polyhedra_Library::Linear_Row::all_homogeneous_terms_are_zero(), con_sys, gen_sys, Parma_Polyhedra_Library::Poly_Con_Relation::implies(), is_empty(), Parma_Polyhedra_Library::Constraint::is_equality(), Parma_Polyhedra_Library::Poly_Con_Relation::is_included(), Parma_Polyhedra_Library::Linear_Row::is_line_or_equality(), is_necessarily_closed(), marked_empty(), minimize(), Parma_Polyhedra_Library::Row::normalize(), Parma_Polyhedra_Library::Poly_Gen_Relation::nothing(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), relation_with(), Parma_Polyhedra_Library::Linear_Row::set_is_ray_or_point_or_inequality(), Parma_Polyhedra_Library::Linear_Row::sign_normalize(), Parma_Polyhedra_Library::Row::size(), space_dim, Parma_Polyhedra_Library::Poly_Gen_Relation::subsumes(), topology(), and upper_bound_assign().

Referenced by Parma_Polyhedra_Library::C_Polyhedron::poly_hull_assign_if_exact().

01883                                                                   {
01884   // Declare a const reference to *this (to avoid accidental modifications).
01885   const Polyhedron& x = *this;
01886   // Private method: the caller must ensure the following.
01887   PPL_ASSERT(x.is_necessarily_closed());
01888   PPL_ASSERT(x.topology() == y.topology());
01889   PPL_ASSERT(x.space_dim == y.space_dim);
01890 
01891   // The zero-dim case is trivial.
01892   if (x.space_dim == 0) {
01893     upper_bound_assign(y);
01894     return true;
01895   }
01896   // If `x' or `y' is (known to be) empty, the convex union is exact.
01897   if (x.marked_empty()) {
01898     *this = y;
01899     return true;
01900   }
01901   else if (y.is_empty())
01902     return true;
01903   else if (x.is_empty()) {
01904     *this = y;
01905     return true;
01906   }
01907 
01908   // Here both `x' and `y' are known to be non-empty.
01909 
01910   // Implementation based on Algorithm 8.1 (page 15) in [BemporadFT00TR],
01911   // generalized so as to also allow for unbounded polyhedra.
01912   // The extension to unbounded polyhedra is obtained by mimicking
01913   // what done in Algorithm 8.2 (page 19) wrt Algorithm 6.2 (page 13).
01914   // We also apply a couple of improvements (see steps 2.1, 3.1, 6.1, 7.1)
01915   // so as to quickly handle special cases and avoid the splitting
01916   // of equalities/lines into pairs of inequalities/rays.
01917 
01918   (void) x.minimize();
01919   (void) y.minimize();
01920   const Constraint_System& x_cs = x.con_sys;
01921   const Constraint_System& y_cs = y.con_sys;
01922   const Generator_System& x_gs = x.gen_sys;
01923   const Generator_System& y_gs = y.gen_sys;
01924   const dimension_type x_gs_num_rows = x_gs.num_rows();
01925   const dimension_type y_gs_num_rows = y_gs.num_rows();
01926 
01927   // Step 1: generators of `x' that are redundant in `y', and vice versa.
01928   std::vector<bool> x_gs_red_in_y(x_gs_num_rows, false);
01929   dimension_type num_x_gs_red_in_y = 0;
01930   for (dimension_type i = x_gs_num_rows; i-- > 0; )
01931     if (y.relation_with(x_gs[i]).implies(Poly_Gen_Relation::subsumes())) {
01932       x_gs_red_in_y[i] = true;
01933       ++num_x_gs_red_in_y;
01934     }
01935   std::vector<bool> y_gs_red_in_x(y_gs_num_rows, false);
01936   dimension_type num_y_gs_red_in_x = 0;
01937   for (dimension_type i = y_gs_num_rows; i-- > 0; )
01938     if (x.relation_with(y_gs[i]).implies(Poly_Gen_Relation::subsumes())) {
01939       y_gs_red_in_x[i] = true;
01940       ++num_y_gs_red_in_x;
01941     }
01942 
01943   // Step 2: if no redundant generator has been identified,
01944   // then the union is not convex. CHECKME: why?
01945   if (num_x_gs_red_in_y == 0 && num_y_gs_red_in_x == 0)
01946     return false;
01947 
01948   // Step 2.1: while at it, also perform quick inclusion tests.
01949   if (num_y_gs_red_in_x == y_gs_num_rows)
01950     // `y' is included into `x': union is convex.
01951     return true;
01952   if (num_x_gs_red_in_y == x_gs_num_rows) {
01953     // `x' is included into `y': union is convex.
01954     *this = y;
01955     return true;
01956   }
01957 
01958   // Here we know that `x' is not included in `y', and vice versa.
01959 
01960   // Step 3: constraints of `x' that are satisfied by `y', and vice versa.
01961   const dimension_type x_cs_num_rows = x_cs.num_rows();
01962   std::vector<bool> x_cs_red_in_y(x_cs_num_rows, false);
01963   for (dimension_type i = x_cs_num_rows; i-- > 0; ) {
01964     const Constraint& x_cs_i = x_cs[i];
01965     if (y.relation_with(x_cs_i).implies(Poly_Con_Relation::is_included()))
01966       x_cs_red_in_y[i] = true;
01967     else if (x_cs_i.is_equality())
01968       // Step 3.1: `x' has an equality not satified by `y':
01969       // union is not convex (recall that `y' does not contain `x').
01970       // NOTE: this would be false for NNC polyhedra.
01971       // Example: x = { A == 0 }, y = { 0 < A <= 1 }.
01972       return false;
01973   }
01974   const dimension_type y_cs_num_rows = y_cs.num_rows();
01975   std::vector<bool> y_cs_red_in_x(y_cs_num_rows, false);
01976   for (dimension_type i = y_cs_num_rows; i-- > 0; ) {
01977     const Constraint& y_cs_i = y_cs[i];
01978     if (x.relation_with(y_cs_i).implies(Poly_Con_Relation::is_included()))
01979       y_cs_red_in_x[i] = true;
01980     else if (y_cs_i.is_equality())
01981       // Step 3.1: `y' has an equality not satified by `x':
01982       // union is not convex (see explanation above).
01983       return false;
01984   }
01985 
01986   // Loop in steps 5-9: for each pair of non-redundant generators,
01987   // compute their "mid-point" and check if it is both in `x' and `y'.
01988 
01989   // Note: reasoning at the polyhedral cone level.
01990   // CHECKME, FIXME: Polyhedron is a (deprecated) friend of Generator.
01991   // Here below we systematically exploit such a friendship, so as to
01992   // freely reinterpret a Generator as a Linear_Row and vice versa.
01993   Linear_Row mid_row;
01994   const Generator& mid_g = static_cast<const Generator&>(mid_row);
01995 
01996   for (dimension_type i = x_gs_num_rows; i-- > 0; ) {
01997     if (x_gs_red_in_y[i])
01998       continue;
01999     const Linear_Row& x_row = static_cast<const Linear_Row&>(x_gs[i]);
02000     const dimension_type row_sz = x_row.size();
02001     const bool x_row_is_line = x_row.is_line_or_equality();
02002     for (dimension_type j = y_gs_num_rows; j-- > 0; ) {
02003       if (y_gs_red_in_x[j])
02004         continue;
02005       const Linear_Row& y_row = static_cast<const Linear_Row&>(y_gs[j]);
02006       const bool y_row_is_line = y_row.is_line_or_equality();
02007 
02008       // Step 6: compute mid_row = x_row + y_row.
02009       // NOTE: no need to actually compute the "mid-point",
02010       // since any strictly positive combination would do.
02011       mid_row = x_row;
02012       for (dimension_type k = row_sz; k-- > 0; )
02013         mid_row[k] += y_row[k];
02014       // A zero ray is not a well formed generator.
02015       const bool illegal_ray
02016         = (mid_row[0] == 0 && mid_row.all_homogeneous_terms_are_zero());
02017       // A zero ray cannot be generated from a line: this holds
02018       // because x_row (resp., y_row) is not subsumed by y (resp., x).
02019       PPL_ASSERT(!(illegal_ray && (x_row_is_line || y_row_is_line)));
02020       if (illegal_ray)
02021         continue;
02022       if (x_row_is_line) {
02023         mid_row.normalize();
02024         if (y_row_is_line)
02025           // mid_row is a line too: sign normalization is needed.
02026           mid_row.sign_normalize();
02027         else
02028           // mid_row is a ray/point.
02029           mid_row.set_is_ray_or_point_or_inequality();
02030       }
02031 
02032       // Step 7: check if mid_g is in the union of x and y.
02033       if (x.relation_with(mid_g) == Poly_Gen_Relation::nothing()
02034           && y.relation_with(mid_g) == Poly_Gen_Relation::nothing())
02035         return false;
02036 
02037       // If either x_row or y_row is a line, we should use its
02038       // negation to produce another generator to be tested too.
02039       // NOTE: exclusive-or is meant.
02040       if (!x_row_is_line && y_row_is_line) {
02041         // Step 6.1: (re-)compute mid_row = x_row - y_row.
02042         mid_row = x_row;
02043         for (dimension_type k = row_sz; k-- > 0; )
02044           mid_row[k] -= y_row[k];
02045         mid_row.normalize();
02046         // Step 7.1: check if mid_g is in the union of x and y.
02047         if (x.relation_with(mid_g) == Poly_Gen_Relation::nothing()
02048             && y.relation_with(mid_g) == Poly_Gen_Relation::nothing())
02049           return false;
02050       }
02051       else if (x_row_is_line && !y_row_is_line) {
02052         // Step 6.1: (re-)compute mid_row = - x_row + y_row.
02053         mid_row = y_row;
02054         for (dimension_type k = row_sz; k-- > 0; )
02055           mid_row[k] -= x_row[k];
02056         mid_row.normalize();
02057         // Step 7.1: check if mid_g is in the union of x and y.
02058         if (x.relation_with(mid_g) == Poly_Gen_Relation::nothing()
02059             && y.relation_with(mid_g) == Poly_Gen_Relation::nothing())
02060           return false;
02061       }
02062     }
02063   }
02064 
02065   // Here we know that the union of x and y is convex.
02066   // TODO: exploit knowledge on the cardinality of non-redudnant
02067   // constraints/generators to improve the convex-hull computation.
02068   // Using generators allows for exploiting incrementality.
02069   for (dimension_type j = 0; j < y_gs_num_rows; ++j) {
02070     if (!y_gs_red_in_x[j])
02071       add_generator(y_gs[j]);
02072   }
02073   PPL_ASSERT_HEAVY(OK());
02074   return true;
02075 }

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 385 of file Polyhedron_widenings.cc.

References add_recycled_constraints(), Parma_Polyhedra_Library::Linear_Expression::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(), minimize(), 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(), swap(), Parma_Polyhedra_Library::Linear_System::topology(), and topology().

Referenced by BHRZ03_widening_assign().

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

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

Definition at line 507 of file Polyhedron_widenings.cc.

References add_recycled_generators(), constraints_are_minimized(), contains(), gen_sys, generators_are_minimized(), has_something_pending(), intersection_assign(), 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(), minimize(), Parma_Polyhedra_Library::Poly_Gen_Relation::nothing(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), relation_with(), space_dim, swap(), and topology().

Referenced by BHRZ03_widening_assign().

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

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

Definition at line 577 of file Polyhedron_widenings.cc.

References add_recycled_generators(), constraints_are_minimized(), contains(), gen_sys, generators_are_minimized(), Parma_Polyhedra_Library::Matrix::has_no_rows(), has_something_pending(), Parma_Polyhedra_Library::Generator_System::insert(), intersection_assign(), Parma_Polyhedra_Library::Generator::is_ray(), Parma_Polyhedra_Library::BHRZ03_Certificate::is_stabilizing(), marked_empty(), minimize(), Parma_Polyhedra_Library::Row::normalize(), Parma_Polyhedra_Library::Poly_Gen_Relation::nothing(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), PPL_DIRTY_TEMP_COEFFICIENT, relation_with(), space_dim, Parma_Polyhedra_Library::sub_mul_assign(), swap(), and topology().

Referenced by BHRZ03_widening_assign().

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

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 666 of file Polyhedron_widenings.cc.

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

Referenced by limited_BHRZ03_extrapolation_assign().

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

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

Definition at line 1445 of file Polyhedron_nonpublic.cc.

References add_generator(), affine_dimension(), con_sys, gen_sys, Parma_Polyhedra_Library::Poly_Con_Relation::implies(), is_empty(), Parma_Polyhedra_Library::Poly_Con_Relation::is_included(), is_included_in(), is_necessarily_closed(), minimize(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), relation_with(), sat_g, sat_g_is_up_to_date(), Parma_Polyhedra_Library::Bit_Row::set(), Parma_Polyhedra_Library::Bit_Row::set_until(), space_dim, Parma_Polyhedra_Library::Poly_Gen_Relation::subsumes(), and update_sat_g().

Referenced by BHZ09_poly_hull_assign_if_exact().

01445                                                                     {
01446   Polyhedron& x = *this;
01447   // Private method: the caller must ensure the following.
01448   PPL_ASSERT(x.is_necessarily_closed() && y.is_necessarily_closed());
01449   PPL_ASSERT(x.space_dim > 0 && x.space_dim == y.space_dim);
01450   PPL_ASSERT(!x.is_empty() && !y.is_empty());
01451 
01452   // Minimization is not really required, but it is probably the best
01453   // way of getting constraints, generators and saturation matrices
01454   // up-to-date; it also removes redundant constraints/generators.
01455   (void) x.minimize();
01456   (void) y.minimize();
01457 
01458   // Handle a special case: for topologically closed polyhedra P and Q,
01459   // if the affine dimension of P is greater than that of Q, then
01460   // their upper bound is exact if and only if P includes Q.
01461   const dimension_type x_affine_dim = x.affine_dimension();
01462   const dimension_type y_affine_dim = y.affine_dimension();
01463   if (x_affine_dim > y_affine_dim)
01464     return y.is_included_in(x);
01465   else if (x_affine_dim < y_affine_dim) {
01466     if (x.is_included_in(y)) {
01467       x = y;
01468       return true;
01469     }
01470     else
01471       return false;
01472   }
01473 
01474   const Constraint_System& x_cs = x.con_sys;
01475   const Generator_System& x_gs = x.gen_sys;
01476   const Generator_System& y_gs = y.gen_sys;
01477   const dimension_type x_gs_num_rows = x_gs.num_rows();
01478   const dimension_type y_gs_num_rows = y_gs.num_rows();
01479 
01480   // Step 1: generators of `x' that are redundant in `y', and vice versa.
01481   Bit_Row x_gs_red_in_y;
01482   dimension_type num_x_gs_red_in_y = 0;
01483   for (dimension_type i = x_gs_num_rows; i-- > 0; )
01484     if (y.relation_with(x_gs[i]).implies(Poly_Gen_Relation::subsumes())) {
01485       x_gs_red_in_y.set(i);
01486       ++num_x_gs_red_in_y;
01487     }
01488   Bit_Row y_gs_red_in_x;
01489   dimension_type num_y_gs_red_in_x = 0;
01490   for (dimension_type i = y_gs_num_rows; i-- > 0; )
01491     if (x.relation_with(y_gs[i]).implies(Poly_Gen_Relation::subsumes())) {
01492       y_gs_red_in_x.set(i);
01493       ++num_y_gs_red_in_x;
01494     }
01495 
01496   // Step 2: filter away special cases.
01497 
01498   // Step 2.1: inclusion tests.
01499   if (num_y_gs_red_in_x == y_gs_num_rows)
01500     // `y' is included into `x': upper bound `x' is exact.
01501     return true;
01502   if (num_x_gs_red_in_y == x_gs_num_rows) {
01503     // `x' is included into `y': upper bound `y' is exact.
01504     x = y;
01505     return true;
01506   }
01507 
01508   // Step 2.2: if no generator of `x' is redundant for `y', then
01509   // (as by 2.1 there exists a constraint of `x' non-redundant for `y')
01510   // the upper bound is not exact; the same if exchanging `x' and `y'.
01511   if (num_x_gs_red_in_y == 0 || num_y_gs_red_in_x == 0)
01512     return false;
01513 
01514   // Step 3: see if `x' has a non-redundant constraint `c_x' that is not
01515   // satisfied by `y' and a non-redundant generator in `y' (see Step 1)
01516   // saturating `c_x'. If so, the upper bound is not exact.
01517 
01518   // Make sure the saturation matrix for `x' is up to date.
01519   // Any sat matrix would do: we choose `sat_g' because it matches
01520   // the two nested loops (constraints on rows and generators on columns).
01521   if (!x.sat_g_is_up_to_date())
01522     x.update_sat_g();
01523   const Bit_Matrix& x_sat = x.sat_g;
01524 
01525   Bit_Row all_ones;
01526   all_ones.set_until(x_gs_num_rows);
01527   Bit_Row row_union;
01528   for (dimension_type i = x_cs.num_rows(); i-- > 0; ) {
01529     const bool included
01530       = y.relation_with(x_cs[i]).implies(Poly_Con_Relation::is_included());
01531     if (!included) {
01532       set_union(x_gs_red_in_y, x_sat[i], row_union);
01533       if (row_union != all_ones)
01534         return false;
01535     }
01536   }
01537 
01538   // Here we know that the upper bound is exact: compute it.
01539   for (dimension_type j = y_gs_num_rows; j-- > 0; )
01540     if (!y_gs_red_in_x[j])
01541       add_generator(y_gs[j]);
01542 
01543   PPL_ASSERT_HEAVY(OK());
01544   return true;
01545 }

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

Definition at line 1548 of file Polyhedron_nonpublic.cc.

References add_constraint(), add_generator(), Parma_Polyhedra_Library::Bit_Row::clear(), con_sys, constraints(), contains(), Parma_Polyhedra_Library::Bit_Row::empty(), Parma_Polyhedra_Library::Bit_Row::first(), gen_sys, Parma_Polyhedra_Library::Poly_Con_Relation::implies(), Parma_Polyhedra_Library::Generator::is_closure_point(), Parma_Polyhedra_Library::Poly_Con_Relation::is_disjoint(), is_empty(), Parma_Polyhedra_Library::Constraint::is_equality(), Parma_Polyhedra_Library::Poly_Con_Relation::is_included(), is_necessarily_closed(), Parma_Polyhedra_Library::Generator::is_point(), Parma_Polyhedra_Library::Constraint::is_strict_inequality(), minimize(), Parma_Polyhedra_Library::Bit_Row::next(), Parma_Polyhedra_Library::Matrix::num_rows(), Parma_Polyhedra_Library::Scalar_Products::reduced_sign(), relation_with(), sat_g, sat_g_is_up_to_date(), Parma_Polyhedra_Library::Bit_Row::set(), Parma_Polyhedra_Library::Bit_Row::set_until(), space_dim, Parma_Polyhedra_Library::Poly_Gen_Relation::subsumes(), swap(), and update_sat_g().

Referenced by BHZ09_poly_hull_assign_if_exact().

01548                                                                       {
01549   const Polyhedron& x = *this;
01550   // Private method: the caller must ensure the following.
01551   PPL_ASSERT(!x.is_necessarily_closed() && !y.is_necessarily_closed());
01552   PPL_ASSERT(x.space_dim > 0 && x.space_dim == y.space_dim);
01553   PPL_ASSERT(!x.is_empty() && !y.is_empty());
01554 
01555   // Minimization is not really required, but it is probably the best
01556   // way of getting constraints, generators and saturation matrices
01557   // up-to-date; it also removes redundant constraints/generators.
01558   (void) x.minimize();
01559   (void) y.minimize();
01560 
01561   const Generator_System& x_gs = x.gen_sys;
01562   const Generator_System& y_gs = y.gen_sys;
01563   const dimension_type x_gs_num_rows = x_gs.num_rows();
01564   const dimension_type y_gs_num_rows = y_gs.num_rows();
01565 
01566   // Compute generators of `x' that are non-redundant in `y' ...
01567   Bit_Row x_gs_nonred_in_y;
01568   Bit_Row x_points_nonred_in_y;
01569   Bit_Row x_closure_points;
01570   dimension_type num_x_gs_nonred_in_y = 0;
01571   for (dimension_type i = x_gs_num_rows; i-- > 0; ) {
01572     const Generator& x_gs_i = x_gs[i];
01573     if (x_gs_i.is_closure_point())
01574       x_closure_points.set(i);
01575     if (y.relation_with(x_gs[i]).implies(Poly_Gen_Relation::subsumes()))
01576       continue;
01577     x_gs_nonred_in_y.set(i);
01578     ++num_x_gs_nonred_in_y;
01579     if (x_gs_i.is_point())
01580       x_points_nonred_in_y.set(i);
01581   }
01582 
01583   // If `x' is included into `y', the upper bound `y' is exact.
01584   if (num_x_gs_nonred_in_y == 0) {
01585     *this = y;
01586     return true;
01587   }
01588 
01589   // ... and vice versa, generators of `y' that are non-redundant in `x'.
01590   Bit_Row y_gs_nonred_in_x;
01591   Bit_Row y_points_nonred_in_x;
01592   Bit_Row y_closure_points;
01593   dimension_type num_y_gs_nonred_in_x = 0;
01594   for (dimension_type i = y_gs_num_rows; i-- > 0; ) {
01595     const Generator& y_gs_i = y_gs[i];
01596     if (y_gs_i.is_closure_point())
01597       y_closure_points.set(i);
01598     if (x.relation_with(y_gs_i).implies(Poly_Gen_Relation::subsumes()))
01599       continue;
01600     y_gs_nonred_in_x.set(i);
01601     ++num_y_gs_nonred_in_x;
01602     if (y_gs_i.is_point())
01603       y_points_nonred_in_x.set(i);
01604   }
01605 
01606   // If `y' is included into `x', the upper bound `x' is exact.
01607   if (num_y_gs_nonred_in_x == 0)
01608     return true;
01609 
01610   Bit_Row x_nonpoints_nonred_in_y;
01611   set_difference(x_gs_nonred_in_y, x_points_nonred_in_y,
01612                  x_nonpoints_nonred_in_y);
01613 
01614   const Constraint_System& x_cs = x.con_sys;
01615   const Constraint_System& y_cs = y.con_sys;
01616   const dimension_type x_cs_num_rows = x_cs.num_rows();
01617   const dimension_type y_cs_num_rows = y_cs.num_rows();
01618 
01619   // Filter away the points of `x_gs' that would be redundant
01620   // in the topological closure of `y'.
01621   Bit_Row x_points_nonred_in_y_closure;
01622   for (dimension_type i = x_points_nonred_in_y.first();
01623        i != ULONG_MAX; i = x_points_nonred_in_y.next(i)) {
01624     const Generator& x_p = x_gs[i];
01625     PPL_ASSERT(x_p.is_point());
01626     // NOTE: we cannot use Constraint_System::relation_with()
01627     // as we need to treat strict inequalities as if they were nonstrict.
01628     for (dimension_type j = y_cs_num_rows; j-- > 0; ) {
01629       const Constraint& y_c = y_cs[j];
01630       const int sp_sign = Scalar_Products::reduced_sign(y_c, x_p);
01631       if (sp_sign < 0 || (y_c.is_equality() && sp_sign > 0)) {
01632         x_points_nonred_in_y_closure.set(i);
01633         break;
01634       }
01635     }
01636   }
01637 
01638   // Make sure the saturation matrix for `x' is up to date.
01639   // Any sat matrix would do: we choose `sat_g' because it matches
01640   // the two nested loops (constraints on rows and generators on columns).
01641   if (!x.sat_g_is_up_to_date())
01642     x.update_sat_g();
01643   const Bit_Matrix& x_sat = x.sat_g;
01644 
01645   Bit_Row x_cs_condition_3;
01646   Bit_Row x_gs_condition_3;
01647   Bit_Row all_ones;
01648   all_ones.set_until(x_gs_num_rows);
01649   Bit_Row saturators;
01650   Bit_Row tmp_set;
01651   for (dimension_type i = x_cs_num_rows; i-- > 0; ) {
01652     const Constraint& x_c = x_cs[i];
01653     // Skip constraint if it is not violated by `y'.
01654     if (y.relation_with(x_c).implies(Poly_Con_Relation::is_included()))
01655       continue;
01656     set_difference(all_ones, x_sat[i], saturators);
01657     // Check condition 1.
01658     set_intersection(x_nonpoints_nonred_in_y, saturators, tmp_set);
01659     if (!tmp_set.empty())
01660       return false;
01661     if (x_c.is_strict_inequality()) {
01662       // Postpone check for condition 3.
01663       x_cs_condition_3.set(i);
01664       set_intersection(x_closure_points, saturators, tmp_set);
01665       set_union(x_gs_condition_3, tmp_set, x_gs_condition_3);
01666     }
01667     else {
01668       // Check condition 2.
01669       set_intersection(x_points_nonred_in_y_closure, saturators, tmp_set);
01670       if (!tmp_set.empty())
01671         return false;
01672     }
01673   }
01674 
01675   // Now exchange the roles of `x' and `y'
01676   // (the statement of the NNC theorem in BHZ09 is symmetric).
01677 
01678   Bit_Row y_nonpoints_nonred_in_x;
01679   set_difference(y_gs_nonred_in_x, y_points_nonred_in_x,
01680                  y_nonpoints_nonred_in_x);
01681 
01682   // Filter away the points of `y_gs' that would be redundant
01683   // in the topological closure of `x'.
01684   Bit_Row y_points_nonred_in_x_closure;
01685   for (dimension_type i = y_points_nonred_in_x.first();
01686        i != ULONG_MAX; i = y_points_nonred_in_x.next(i)) {
01687     const Generator& y_p = y_gs[i];
01688     PPL_ASSERT(y_p.is_point());
01689     // NOTE: we cannot use Constraint_System::relation_with()
01690     // as we need to treat strict inequalities as if they were nonstrict.
01691     for (dimension_type j = x_cs_num_rows; j-- > 0; ) {
01692       const Constraint& x_c = x_cs[j];
01693       const int sp_sign = Scalar_Products::reduced_sign(x_c, y_p);
01694       if (sp_sign < 0 || (x_c.is_equality() && sp_sign > 0)) {
01695         y_points_nonred_in_x_closure.set(i);
01696         break;
01697       }
01698     }
01699   }
01700 
01701   // Make sure the saturation matrix `sat_g' for `y' is up to date.
01702   if (!y.sat_g_is_up_to_date())
01703     y.update_sat_g();
01704   const Bit_Matrix& y_sat = y.sat_g;
01705 
01706   Bit_Row y_cs_condition_3;
01707   Bit_Row y_gs_condition_3;
01708   all_ones.clear();
01709   all_ones.set_until(y_gs_num_rows);
01710   for (dimension_type i = y_cs_num_rows; i-- > 0; ) {
01711     const Constraint& y_c = y_cs[i];
01712     // Skip constraint if it is not violated by `x'.
01713     if (x.relation_with(y_c).implies(Poly_Con_Relation::is_included()))
01714       continue;
01715     set_difference(all_ones, y_sat[i], saturators);
01716     // Check condition 1.
01717     set_intersection(y_nonpoints_nonred_in_x, saturators, tmp_set);
01718     if (!tmp_set.empty())
01719       return false;
01720     if (y_c.is_strict_inequality()) {
01721       // Postpone check for condition 3.
01722       y_cs_condition_3.set(i);
01723       set_intersection(y_closure_points, saturators, tmp_set);
01724       set_union(y_gs_condition_3, tmp_set, y_gs_condition_3);
01725     }
01726     else {
01727       // Check condition 2.
01728       set_intersection(y_points_nonred_in_x_closure, saturators, tmp_set);
01729       if (!tmp_set.empty())
01730         return false;
01731     }
01732   }
01733 
01734   // Now considering condition 3.
01735 
01736   if (x_cs_condition_3.empty() && y_cs_condition_3.empty()) {
01737     // No test for condition 3 is needed.
01738     // The hull is exact: compute it.
01739     for (dimension_type j = y_gs_num_rows; j-- > 0; )
01740       if (y_gs_nonred_in_x[j])
01741         add_generator(y_gs[j]);
01742     return true;
01743   }
01744 
01745   // We have anyway to compute the upper bound and its constraints too.
01746   Polyhedron ub(x);
01747   for (dimension_type j = y_gs_num_rows; j-- > 0; )
01748     if (y_gs_nonred_in_x[j])
01749       ub.add_generator(y_gs[j]);
01750   (void) ub.minimize();
01751   PPL_ASSERT(!ub.is_empty());
01752 
01753   // NOTE: the following computation of x_gs_condition_3_not_in_y
01754   // (resp., y_gs_condition_3_not_in_x) is not required for correctness.
01755   // It is done so as to later apply a speculative test
01756   // (i.e., a non-conclusive but computationally lighter test).
01757 
01758   // Filter away from `x_gs_condition_3' those closure points
01759   // that, when considered as points, would belong to `y',
01760   // i.e., those that violate no strict constraint in `y_cs'.
01761   Bit_Row x_gs_condition_3_not_in_y;
01762   for (dimension_type i = y_cs_num_rows; i-- > 0; ) {
01763     const Constraint& y_c = y_cs[i];
01764     if (y_c.is_strict_inequality()) {
01765       for (dimension_type j = x_gs_condition_3.first();
01766            j != ULONG_MAX; j = x_gs_condition_3.next(j)) {
01767         const Generator& x_cp = x_gs[j];
01768         PPL_ASSERT(x_cp.is_closure_point());
01769         const int sp_sign = Scalar_Products::reduced_sign(y_c, x_cp);
01770         PPL_ASSERT(sp_sign >= 0);
01771         if (sp_sign == 0) {
01772           x_gs_condition_3.clear(j);
01773           x_gs_condition_3_not_in_y.set(j);
01774         }
01775       }
01776       if (x_gs_condition_3.empty())
01777         break;
01778     }
01779   }
01780   // Symmetrically, filter away from `y_gs_condition_3' those
01781   // closure points that, when considered as points, would belong to `x',
01782   // i.e., those that violate no strict constraint in `x_cs'.
01783   Bit_Row y_gs_condition_3_not_in_x;
01784   for (dimension_type i = x_cs_num_rows; i-- > 0; ) {
01785     if (x_cs[i].is_strict_inequality()) {
01786       const Constraint& x_c = x_cs[i];
01787       for (dimension_type j = y_gs_condition_3.first();
01788            j != ULONG_MAX; j = y_gs_condition_3.next(j)) {
01789         const Generator& y_cp = y_gs[j];
01790         PPL_ASSERT(y_cp.is_closure_point());
01791         const int sp_sign = Scalar_Products::reduced_sign(x_c, y_cp);
01792         PPL_ASSERT(sp_sign >= 0);
01793         if (sp_sign == 0) {
01794           y_gs_condition_3.clear(j);
01795           y_gs_condition_3_not_in_x.set(j);
01796         }
01797       }
01798       if (y_gs_condition_3.empty())
01799         break;
01800     }
01801   }
01802 
01803   // NOTE: here we apply the speculative test.
01804   // Check if there exists a closure point in `x_gs_condition_3_not_in_y'
01805   // or `y_gs_condition_3_not_in_x' that belongs (as point) to the hull.
01806   // If so, the hull is not exact.
01807   const Constraint_System& ub_cs = ub.constraints();
01808   for (dimension_type i = ub_cs.num_rows(); i-- > 0; ) {
01809     if (ub_cs[i].is_strict_inequality()) {
01810       const Constraint& ub_c = ub_cs[i];
01811       for (dimension_type j = x_gs_condition_3_not_in_y.first();
01812            j != ULONG_MAX; j = x_gs_condition_3_not_in_y.next(j)) {
01813         const Generator& x_cp = x_gs[j];
01814         PPL_ASSERT(x_cp.is_closure_point());
01815         const int sp_sign = Scalar_Products::reduced_sign(ub_c, x_cp);
01816         PPL_ASSERT(sp_sign >= 0);
01817         if (sp_sign == 0)
01818           x_gs_condition_3_not_in_y.clear(j);
01819       }
01820       for (dimension_type j = y_gs_condition_3_not_in_x.first();
01821            j != ULONG_MAX; j = y_gs_condition_3_not_in_x.next(j)) {
01822         const Generator& y_cp = y_gs[j];
01823         PPL_ASSERT(y_cp.is_closure_point());
01824         const int sp_sign = Scalar_Products::reduced_sign(ub_c, y_cp);
01825         PPL_ASSERT(sp_sign >= 0);
01826         if (sp_sign == 0)
01827           y_gs_condition_3_not_in_x.clear(j);
01828       }
01829     }
01830   }
01831 
01832   if (!(x_gs_condition_3_not_in_y.empty()
01833         && y_gs_condition_3_not_in_x.empty()))
01834     // There exist a closure point satisfying condition 3,
01835     // hence the hull is not exact.
01836     return false;
01837 
01838   // The speculative test was not successful:
01839   // apply the expensive (but conclusive) test for condition 3.
01840 
01841   // Consider strict inequalities in `x' violated by `y'.
01842   for (dimension_type i = x_cs_condition_3.first();
01843        i != ULONG_MAX; i = x_cs_condition_3.next(i)) {
01844     const Constraint& x_cs_i = x_cs[i];
01845     PPL_ASSERT(x_cs_i.is_strict_inequality());
01846     // Build the equality constraint induced by x_cs_i.
01847     Constraint eq_i(Linear_Expression(x_cs_i) == 0);
01848     PPL_ASSERT(!(ub.relation_with(eq_i)
01849                  .implies(Poly_Con_Relation::is_disjoint())));
01850     Polyhedron ub_inters_hyperplane(ub);
01851     ub_inters_hyperplane.add_constraint(eq_i);
01852     Polyhedron y_inters_hyperplane(y);
01853     y_inters_hyperplane.add_constraint(eq_i);
01854     if (!y_inters_hyperplane.contains(ub_inters_hyperplane))
01855       // The hull is not exact.
01856       return false;
01857   }
01858 
01859   // Consider strict inequalities in `y' violated by `x'.
01860   for (dimension_type i = y_cs_condition_3.first();
01861        i != ULONG_MAX; i = y_cs_condition_3.next(i)) {
01862     const Constraint& y_cs_i = y_cs[i];
01863     PPL_ASSERT(y_cs_i.is_strict_inequality());
01864     // Build the equality constraint induced by y_cs_i.
01865     Constraint eq_i(Linear_Expression(y_cs_i) == 0);
01866     PPL_ASSERT(!(ub.relation_with(eq_i)
01867                  .implies(Poly_Con_Relation::is_disjoint())));
01868     Polyhedron ub_inters_hyperplane(ub);
01869     ub_inters_hyperplane.add_constraint(eq_i);
01870     Polyhedron x_inters_hyperplane(x);
01871     x_inters_hyperplane.add_constraint(eq_i);
01872     if (!x_inters_hyperplane.contains(ub_inters_hyperplane))
01873       // The hull is not exact.
01874       return false;
01875   }
01876 
01877   // The hull is exact.
01878   swap(ub);
01879   return true;
01880 }

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

Definition at line 1413 of file Polyhedron_nonpublic.cc.

References BHZ09_C_poly_hull_assign_if_exact(), BHZ09_NNC_poly_hull_assign_if_exact(), is_empty(), is_necessarily_closed(), marked_empty(), space_dim, topology(), and upper_bound_assign().

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

01413                                                                   {
01414   Polyhedron& x = *this;
01415 
01416   // Private method: the caller must ensure the following.
01417   PPL_ASSERT(x.topology() == y.topology());
01418   PPL_ASSERT(x.space_dim == y.space_dim);
01419 
01420   // The zero-dim case is trivial.
01421   if (x.space_dim == 0) {
01422     x.upper_bound_assign(y);
01423     return true;
01424   }
01425 
01426   // If `x' or `y' are (known to be) empty, the upper bound is exact.
01427   if (x.marked_empty()) {
01428     x = y;
01429     return true;
01430   }
01431   else if (y.is_empty())
01432     return true;
01433   else if (x.is_empty()) {
01434     x = y;
01435     return true;
01436   }
01437 
01438   if (x.is_necessarily_closed())
01439     return x.BHZ09_C_poly_hull_assign_if_exact(y);
01440   else
01441     return x.BHZ09_NNC_poly_hull_assign_if_exact(y);
01442 }

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 2713 of file Polyhedron_public.cc.

References add_space_dimensions_and_embed(), Parma_Polyhedra_Library::Linear_Expression::coefficient(), generalized_affine_image(), Parma_Polyhedra_Library::GREATER_OR_EQUAL, Parma_Polyhedra_Library::LESS_OR_EQUAL, marked_empty(), OK(), refine_no_check(), remove_higher_space_dimensions(), Parma_Polyhedra_Library::Linear_Expression::space_dimension(), Parma_Polyhedra_Library::Variable::space_dimension(), throw_dimension_incompatible(), and throw_invalid_argument().

02716                                                                     {
02717   // The denominator cannot be zero.
02718   if (denominator == 0)
02719     throw_invalid_argument("bounded_affine_image(v, lb, ub, d)", "d == 0");
02720 
02721   // Dimension-compatibility checks.
02722   // `var' should be one of the dimensions of the polyhedron.
02723   const dimension_type var_space_dim = var.space_dimension();
02724   if (space_dim < var_space_dim)
02725     throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
02726                                  "v", var);
02727   // The dimension of `lb_expr' and `ub_expr' should not be
02728   // greater than the dimension of `*this'.
02729   const dimension_type lb_space_dim = lb_expr.space_dimension();
02730   if (space_dim < lb_space_dim)
02731     throw_dimension_incompatible("bounded_affine_image(v, lb, ub)",
02732                                  "lb", lb_expr);
02733   const dimension_type ub_space_dim = ub_expr.space_dimension();
02734   if (space_dim < ub_space_dim)
02735     throw_dimension_incompatible("bounded_affine_image(v, lb, ub)",
02736                                  "ub", ub_expr);
02737 
02738   // Any image of an empty polyhedron is empty.
02739   if (marked_empty())
02740     return;
02741 
02742   // Check whether `var' occurs in `lb_expr' and/or `ub_expr'.
02743   if (lb_expr.coefficient(var) == 0) {
02744     // Here `var' may only occur in `ub_expr'.
02745     generalized_affine_image(var,
02746                              LESS_OR_EQUAL,
02747                              ub_expr,
02748                              denominator);
02749     if (denominator > 0)
02750       refine_no_check(lb_expr <= denominator*var);
02751     else
02752       refine_no_check(denominator*var <= lb_expr);
02753   }
02754   else if (ub_expr.coefficient(var) == 0) {
02755     // Here `var' only occurs in `lb_expr'.
02756     generalized_affine_image(var,
02757                              GREATER_OR_EQUAL,
02758                              lb_expr,
02759                              denominator);
02760     if (denominator > 0)
02761       refine_no_check(denominator*var <= ub_expr);
02762     else
02763       refine_no_check(ub_expr <= denominator*var);
02764   }
02765   else {
02766     // Here `var' occurs in both `lb_expr' and `ub_expr'.
02767     // To ease the computation, we add an additional dimension.
02768     const Variable new_var = Variable(space_dim);
02769     add_space_dimensions_and_embed(1);
02770     // Constrain the new dimension to be equal to `ub_expr'.
02771     refine_no_check(denominator*new_var == ub_expr);
02772     // Apply the affine lower bound.
02773     generalized_affine_image(var,
02774                              GREATER_OR_EQUAL,
02775                              lb_expr,
02776                              denominator);
02777     if (!marked_empty())
02778       // Now apply the affine upper bound, as recorded in `new_var'.
02779       refine_no_check(new_var >= var);
02780     // Remove the temporarily added dimension.
02781     remove_higher_space_dimensions(space_dim-1);
02782   }
02783   PPL_ASSERT_HEAVY(OK());
02784 }

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 2788 of file Polyhedron_public.cc.

References 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(), marked_empty(), OK(), Parma_Polyhedra_Library::Linear_System::permute_columns(), refine_no_check(), remove_higher_space_dimensions(), Parma_Polyhedra_Library::Linear_Expression::space_dimension(), Parma_Polyhedra_Library::Variable::space_dimension(), throw_dimension_incompatible(), throw_invalid_argument(), and unconstrain().

02791                                                                        {
02792   // The denominator cannot be zero.
02793   if (denominator == 0)
02794     throw_invalid_argument("bounded_affine_preimage(v, lb, ub, d)", "d == 0");
02795 
02796   // Dimension-compatibility checks.
02797   // `var' should be one of the dimensions of the polyhedron.
02798   const dimension_type var_space_dim = var.space_dimension();
02799   if (space_dim < var_space_dim)
02800     throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
02801                                  "v", var);
02802   // The dimension of `lb_expr' and `ub_expr' should not be
02803   // greater than the dimension of `*this'.
02804   const dimension_type lb_space_dim = lb_expr.space_dimension();
02805   if (space_dim < lb_space_dim)
02806     throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub)",
02807                                  "lb", lb_expr);
02808   const dimension_type ub_space_dim = ub_expr.space_dimension();
02809   if (space_dim < ub_space_dim)
02810     throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub)",
02811                                  "ub", ub_expr);
02812 
02813   // Any preimage of an empty polyhedron is empty.
02814   if (marked_empty())
02815     return;
02816 
02817   // Check whether `var' occurs in neither `lb_expr' nor `ub_expr'.
02818   if (lb_expr.coefficient(var) == 0 && ub_expr.coefficient(var) == 0) {
02819     if (denominator > 0) {
02820       refine_no_check(lb_expr <= denominator*var);
02821       refine_no_check(denominator*var <= ub_expr);
02822     }
02823     else {
02824       refine_no_check(ub_expr <= denominator*var);
02825       refine_no_check(denominator*var <= lb_expr);
02826     }
02827     unconstrain(var);
02828   }
02829   else {
02830     // Here `var' occurs in `lb_expr' or `ub_expr'.
02831     // To ease the computation, add an additional dimension.
02832     const Variable new_var = Variable(space_dim);
02833     add_space_dimensions_and_embed(1);
02834     // Swap dimensions `var' and `new_var'.
02835     std::vector<dimension_type> swapping_cycle;
02836     swapping_cycle.push_back(var_space_dim);
02837     swapping_cycle.push_back(space_dim);
02838     swapping_cycle.push_back(0);
02839     if (constraints_are_up_to_date())
02840       con_sys.permute_columns(swapping_cycle);
02841     if (generators_are_up_to_date())
02842       gen_sys.permute_columns(swapping_cycle);
02843     // Constrain the new dimension as dictated by `lb_expr' and `ub_expr'.
02844     // (we force minimization because we will need the generators).
02845     if (denominator > 0) {
02846       refine_no_check(lb_expr <= denominator*new_var);
02847       refine_no_check(denominator*new_var <= ub_expr);
02848     }
02849     else {
02850       refine_no_check(ub_expr <= denominator*new_var);
02851       refine_no_check(denominator*new_var <= lb_expr);
02852     }
02853     // Remove the temporarily added dimension.
02854     remove_higher_space_dimensions(space_dim-1);
02855   }
02856   PPL_ASSERT_HEAVY(OK());
02857 }

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

Assigns to *this the result of computing the bounded extrapolation between *this and y using the BHRZ03-widening operator.

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 847 of file Polyhedron_widenings.cc.

References add_recycled_constraints(), Parma_Polyhedra_Library::ANY_COMPLEXITY, and limited_BHRZ03_extrapolation_assign().

00849                                                     {
00850   Rational_Box x_box(*this, ANY_COMPLEXITY);
00851   Rational_Box y_box(y, ANY_COMPLEXITY);
00852   x_box.CC76_widening_assign(y_box);
00853   limited_BHRZ03_extrapolation_assign(y, cs, tp);
00854   Constraint_System x_box_cs = x_box.constraints();
00855   add_recycled_constraints(x_box_cs);
00856 }

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

Assigns to *this the result of computing the bounded extrapolation between *this and y using the H79-widening operator.

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 372 of file Polyhedron_widenings.cc.

References add_recycled_constraints(), Parma_Polyhedra_Library::ANY_COMPLEXITY, and limited_H79_extrapolation_assign().

00374                                                                 {
00375   Rational_Box x_box(*this, ANY_COMPLEXITY);
00376   Rational_Box y_box(y, ANY_COMPLEXITY);
00377   x_box.CC76_widening_assign(y_box);
00378   limited_H79_extrapolation_assign(y, cs, tp);
00379   Constraint_System x_box_cs = x_box.constraints();
00380   add_recycled_constraints(x_box_cs);
00381 }

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 519 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().

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

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 306 of file Polyhedron.inlines.hh.

References bounds().

00306                                                                  {
00307   return bounds(expr, true);
00308 }

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 311 of file Polyhedron.inlines.hh.

References bounds().

00311                                                                  {
00312   return bounds(expr, false);
00313 }

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

Returns false indicating that this domain cannot recycle congruences.

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

00118                                            {
00119   return false;
00120 }

bool Parma_Polyhedra_Library::Polyhedron::can_recycle_constraint_systems (  )  [inline, static]

Returns true indicating that this domain has methods that can recycle constraints.

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

00112                                            {
00113   return true;
00114 }

void Parma_Polyhedra_Library::Polyhedron::clear_constraints_minimized (  )  [inline, private]
void Parma_Polyhedra_Library::Polyhedron::clear_constraints_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 234 of file Polyhedron.inlines.hh.

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

Referenced by add_generator(), and add_recycled_generators().

00234                         {
00235   status.reset_empty();
00236 }

void Parma_Polyhedra_Library::Polyhedron::clear_generators_minimized (  )  [inline, private]
void Parma_Polyhedra_Library::Polyhedron::clear_generators_up_to_date (  )  [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 249 of file Polyhedron.inlines.hh.

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

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

00249                                       {
00250   status.reset_c_pending();
00251 }

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

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

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

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

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

00254                                      {
00255   status.reset_g_pending();
00256 }

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]
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 288 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::Bit_Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Bit_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::Bit_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, Parma_Polyhedra_Library::swap(), swap(), Parma_Polyhedra_Library::Matrix::swap_columns(), throw_space_dimension_overflow(), throw_topology_incompatible(), topology(), Parma_Polyhedra_Library::Bit_Matrix::transpose_assign(), Parma_Polyhedra_Library::Linear_System::unset_pending_rows(), and update_constraints().

00288                                                      {
00289   if (topology() != y.topology())
00290     throw_topology_incompatible("concatenate_assign(y)", "y", y);
00291 
00292   // The space dimension of the resulting polyhedron should not
00293   // overflow the maximum allowed space dimension.
00294   const dimension_type added_columns = y.space_dim;
00295   if (added_columns > max_space_dimension() - space_dim)
00296     throw_space_dimension_overflow(topology(),
00297                                    "concatenate_assign(y)",
00298                                    "concatenation exceeds the maximum "
00299                                    "allowed space dimension");
00300 
00301   // If `*this' or `y' are empty polyhedra, it is sufficient to adjust
00302   // the dimension of the space.
00303   if (marked_empty() || y.marked_empty()) {
00304     space_dim += added_columns;
00305     set_empty();
00306     return;
00307   }
00308 
00309   // If `y' is a non-empty 0-dim space polyhedron, the result is `*this'.
00310   if (added_columns == 0)
00311     return;
00312 
00313   // If `*this' is a non-empty 0-dim space polyhedron, the result is `y'.
00314   if (space_dim == 0) {
00315     *this = y;
00316     return;
00317   }
00318 
00319   // TODO: this implementation is just an executable specification.
00320   Constraint_System cs = y.constraints();
00321 
00322   // The constraints of `x' (possibly with pending rows) are required.
00323   if (has_pending_generators())
00324     process_pending_generators();
00325   else if (!constraints_are_up_to_date())
00326     update_constraints();
00327 
00328   // The matrix for the new system of constraints is obtained
00329   // by leaving the old system of constraints in the upper left-hand side
00330   // and placing the constraints of `cs' in the lower right-hand side.
00331   // NOTE: here topologies agree, whereas dimensions may not agree.
00332   dimension_type old_num_rows = con_sys.num_rows();
00333   dimension_type old_num_columns = con_sys.num_columns();
00334   dimension_type added_rows = cs.num_rows();
00335 
00336   // We already dealt with the cases of an empty or zero-dim `y' polyhedron;
00337   // also, `cs' contains the low-level constraints, at least.
00338   PPL_ASSERT(added_rows > 0 && added_columns > 0);
00339 
00340   con_sys.add_zero_rows_and_columns(added_rows, added_columns,
00341                                     Linear_Row::Flags(topology(),
00342                                                       Linear_Row::RAY_OR_POINT_OR_INEQUALITY));
00343   // Move the epsilon coefficient to the last column, if needed.
00344   if (!is_necessarily_closed())
00345     con_sys.swap_columns(old_num_columns - 1,
00346                          old_num_columns - 1 + added_columns);
00347   dimension_type cs_num_columns = cs.num_columns();
00348   // Steal the constraints from `cs' and put them in `con_sys'
00349   // using the right displacement for coefficients.
00350   for (dimension_type i = added_rows; i-- > 0; ) {
00351     Constraint& c_old = cs[i];
00352     Constraint& c_new = con_sys[old_num_rows + i];
00353     // Method `add_zero_rows_and_columns', by default, added 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   PPL_ASSERT_HEAVY(OK());
00414 }

Congruence_System Parma_Polyhedra_Library::Polyhedron::congruences (  )  const [inline]

Returns a system of (equality) congruences satisfied by *this.

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

References minimized_constraints().

00357                               {
00358   return Congruence_System(minimized_constraints());
00359 }

bool Parma_Polyhedra_Library::Polyhedron::constrains ( Variable  var  )  const

Returns true if and only if var is constrained in *this.

Exceptions:
std::invalid_argument Thrown if var is not a space dimension of *this.

Definition at line 690 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::Linear_Row::coefficient(), con_sys, 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(), Parma_Polyhedra_Library::Variable::id(), Parma_Polyhedra_Library::Generator::is_line(), Parma_Polyhedra_Library::Generator::is_line_or_ray(), marked_empty(), minimize(), Parma_Polyhedra_Library::Matrix::num_rows(), process_pending_generators(), space_dim, Parma_Polyhedra_Library::Variable::space_dimension(), throw_dimension_incompatible(), and update_constraints().

00690                                                   {
00691   // `var' should be one of the dimensions of the polyhedron.
00692   const dimension_type var_space_dim = var.space_dimension();
00693   if (space_dim < var_space_dim)
00694     throw_dimension_incompatible("constrains(v)", "v", var);
00695 
00696   // An empty polyhedron constrains all variables.
00697   if (marked_empty())
00698     return true;
00699 
00700   if (generators_are_up_to_date() && !has_pending_constraints()) {
00701     // Since generators are up-to-date and there are no pending
00702     // constraints, the generator system (since it is well formed)
00703     // contains a point.  Hence the polyhedron is not empty.
00704     if (constraints_are_up_to_date() && !has_pending_generators())
00705       // Here a variable is constrained if and only if it is
00706       // syntactically constrained.
00707       goto syntactic_check;
00708 
00709     if (generators_are_minimized()) {
00710       // Try a quick, incomplete check for the universe polyhedron:
00711       // a universe polyhedron constrains no variable.
00712       // Count the number of non-pending
00713       // (hence, linearly independent) lines.
00714       dimension_type num_lines = 0;
00715       const dimension_type first_pending = gen_sys.first_pending_row();
00716       for (dimension_type i = first_pending; i-- > 0; )
00717         if (gen_sys[i].is_line())
00718           ++num_lines;
00719 
00720       if (num_lines == space_dim)
00721         return false;
00722     }
00723 
00724     // Scan generators: perhaps we will find a generator equivalent to
00725     // line(var) or a pair of generators equivalent to ray(-var) and
00726     // ray(var).
00727     bool have_positive_ray = false;
00728     bool have_negative_ray = false;
00729     const dimension_type var_id = var.id();
00730     for (dimension_type i = gen_sys.num_rows(); i-- > 0; ) {
00731       const Generator& gen_sys_i = gen_sys[i];
00732       if (gen_sys_i.is_line_or_ray()) {
00733         const Linear_Row& row = gen_sys_i;
00734         const int sign = sgn(row.coefficient(var_id));
00735         if (sign != 0) {
00736           for (dimension_type j = space_dim+1; --j > 0; )
00737             if (j != var_id && row[j] != 0)
00738               goto next;
00739           if (gen_sys_i.is_line())
00740             return true;
00741           if (sign > 0)
00742             if (have_negative_ray)
00743               return true;
00744             else
00745               have_positive_ray = true;
00746           else if (have_positive_ray)
00747             return true;
00748           else
00749             have_negative_ray = true;
00750         }
00751       }
00752     next:
00753       ;
00754     }
00755 
00756     // We are still here: at least we know that, since generators are
00757     // up-to-date and there are no pending constraints, then the
00758     // generator system (since it is well formed) contains a point.
00759     // Hence the polyhedron is not empty.
00760     if (has_pending_generators())
00761       process_pending_generators();
00762     else if (!constraints_are_up_to_date())
00763       update_constraints();
00764     goto syntactic_check;
00765   }
00766 
00767   // We must minimize to detect emptiness and obtain constraints.
00768   if (!minimize())
00769     return true;
00770 
00771  syntactic_check:
00772   for (dimension_type i = con_sys.num_rows(); i-- > 0; )
00773     if (con_sys[i].coefficient(var) != 0)
00774       return true;
00775   return false;
00776 }

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

Returns the system of constraints.

Definition at line 74 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::Constraint_System::adjust_topology_and_space_dimension(), con_sys, constraints_are_up_to_date(), Parma_Polyhedra_Library::Matrix::has_no_rows(), 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(), BHZ09_NNC_poly_hull_assign_if_exact(), Parma_Polyhedra_Library::Box< ITV >::Box(), Parma_Polyhedra_Library::C_Polyhedron::C_Polyhedron(), concatenate_assign(), contains_integer_point(), expand_space_dimension(), Parma_Polyhedra_Library::Grid::Grid(), minimized_constraints(), Parma_Polyhedra_Library::NNC_Polyhedron::NNC_Polyhedron(), Parma_Polyhedra_Library::Octagonal_Shape< T >::Octagonal_Shape(), and poly_difference_assign().

00074                                  {
00075   if (marked_empty()) {
00076     // We want `con_sys' to only contain the unsatisfiable constraint
00077     // of the appropriate dimension.
00078     if (con_sys.has_no_rows()) {
00079       // The 0-dim unsatisfiable constraint is extended to
00080       // the appropriate dimension and then stored in `con_sys'.
00081       Constraint_System unsat_cs = Constraint_System::zero_dim_empty();
00082       unsat_cs.adjust_topology_and_space_dimension(topology(), space_dim);
00083       const_cast<Constraint_System&>(con_sys).swap(unsat_cs);
00084     }
00085     else {
00086       // Checking that `con_sys' contains the right thing.
00087       PPL_ASSERT(con_sys.space_dimension() == space_dim);
00088       PPL_ASSERT(con_sys.num_rows() == 1);
00089       PPL_ASSERT(con_sys[0].is_inconsistent());
00090     }
00091     return con_sys;
00092   }
00093 
00094   if (space_dim == 0) {
00095     // Zero-dimensional universe.
00096     PPL_ASSERT(con_sys.num_rows() == 0 && con_sys.num_columns() == 0);
00097     return con_sys;
00098   }
00099 
00100   // If the polyhedron has pending generators, we process them to obtain
00101   // the constraints. No processing is needed if the polyhedron has
00102   // pending constraints.
00103   if (has_pending_generators())
00104     process_pending_generators();
00105   else if (!constraints_are_up_to_date())
00106     update_constraints();
00107 
00108   // TODO: reconsider whether to really sort constraints at this stage.
00109 #if ENSURE_SORTEDNESS
00110   // We insist in returning a sorted system of constraints,
00111   // but sorting is useless if there are pending constraints.
00112   if (!has_pending_constraints())
00113     obtain_sorted_constraints();
00114 #endif
00115   return con_sys;
00116 }

bool Parma_Polyhedra_Library::Polyhedron::constraints_are_minimized (  )  const [inline, private]
bool Parma_Polyhedra_Library::Polyhedron::constraints_are_up_to_date (  )  const [inline, private]
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 3645 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(), BHZ09_NNC_poly_hull_assign_if_exact(), Parma_Polyhedra_Library::Pointset_Powerset< PSET >::check_containment(), H79_widening_assign(), limited_BHRZ03_extrapolation_assign(), limited_H79_extrapolation_assign(), poly_difference_assign(), poly_hull_assign_if_exact(), and strictly_contains().

03645                                                  {
03646   const Polyhedron& x = *this;
03647 
03648   // Topology compatibility check.
03649   if (x.topology() != y.topology())
03650     throw_topology_incompatible("contains(y)", "y", y);
03651 
03652   // Dimension-compatibility check.
03653   if (x.space_dim != y.space_dim)
03654     throw_dimension_incompatible("contains(y)", "y", y);
03655 
03656   if (y.marked_empty())
03657     return true;
03658   else if (x.marked_empty())
03659     return y.is_empty();
03660   else if (y.space_dim == 0)
03661     return true;
03662   else if (x.quick_equivalence_test(y) == Polyhedron::TVB_TRUE)
03663     return true;
03664   else
03665     return y.is_included_in(x);
03666 }

bool Parma_Polyhedra_Library::Polyhedron::contains_integer_point (  )  const

Returns true if and only if *this contains at least one integer point.

Definition at line 560 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::assign_r(), Parma_Polyhedra_Library::Constraint_System::begin(), Parma_Polyhedra_Library::Constraint::coefficient(), constraints(), Parma_Polyhedra_Library::Constraint_System::end(), Parma_Polyhedra_Library::Constraint::EQUALITY, Parma_Polyhedra_Library::gcd_assign(), gen_sys, generators_are_up_to_date(), has_pending_constraints(), Parma_Polyhedra_Library::Constraint::inhomogeneous_term(), Parma_Polyhedra_Library::is_canonical(), Parma_Polyhedra_Library::Constraint::is_inconsistent(), Parma_Polyhedra_Library::Checked::le, marked_empty(), Parma_Polyhedra_Library::Matrix::num_rows(), PPL_DIRTY_TEMP_COEFFICIENT, process_pending(), space_dim, Parma_Polyhedra_Library::Constraint::STRICT_INEQUALITY, and Parma_Polyhedra_Library::Constraint::type().

00560                                             {
00561   // Any empty polyhedron does not contain integer points.
00562   if (marked_empty())
00563     return false;
00564 
00565   // A zero-dimensional, universe polyhedron has, by convention, an
00566   // integer point.
00567   if (space_dim == 0)
00568     return true;
00569 
00570   // CHECKME: do we really want to call conversion to check for emptiness?
00571   if (has_pending_constraints() && !process_pending())
00572     // Empty again.
00573     return false;
00574 
00575   // FIXME: do also exploit info regarding rays and lines, if possible.
00576   // Is any integer point already available?
00577   PPL_ASSERT(!has_pending_constraints());
00578   if (generators_are_up_to_date())
00579     for (dimension_type i = gen_sys.num_rows(); i-- > 0; )
00580       if (gen_sys[i].is_point() && gen_sys[i].divisor() == 1)
00581         return true;
00582 
00583   const Constraint_System& cs = constraints();
00584 #if 0 // TEMPORARILY DISABLED.
00585   MIP_Problem mip(space_dim,
00586                   cs.begin(), cs.end(),
00587                   Variables_Set(Variable(0), Variable(space_dim-1)));
00588 #else
00589   // FIXME: temporary workaround, to be removed as soon as the MIP
00590   // problem class will correctly and precisely handle
00591   // ((strict) in-) equality constraints having all integer variables.
00592   MIP_Problem mip(space_dim);
00593   mip.add_to_integer_space_dimensions(Variables_Set(Variable(0),
00594                                                     Variable(space_dim-1)));
00595   PPL_DIRTY_TEMP_COEFFICIENT(homogeneous_gcd);
00596   PPL_DIRTY_TEMP_COEFFICIENT(gcd);
00597   PPL_DIRTY_TEMP0(mpq_class, rational_inhomogeneous);
00598   PPL_DIRTY_TEMP_COEFFICIENT(tightened_inhomogeneous);
00599   for (Constraint_System::const_iterator cs_i = cs.begin(),
00600          cs_end = cs.end(); cs_i != cs_end; ++cs_i) {
00601     const Constraint& c = *cs_i;
00602     const Constraint::Type c_type = c.type();
00603     const Coefficient& inhomogeneous = c.inhomogeneous_term();
00604     if (c_type == Constraint::STRICT_INEQUALITY) {
00605       // CHECKME: should we change the behavior of Linear_Expression(c) ?
00606       // Compute the GCD of the coefficients of c
00607       // (disregarding the inhomogeneous term and the espilon dimension).
00608       homogeneous_gcd = 0;
00609       for (dimension_type i = space_dim; i-- > 0; )
00610         gcd_assign(homogeneous_gcd,
00611                    homogeneous_gcd, c.coefficient(Variable(i)));
00612       if (homogeneous_gcd == 0) {
00613         // NOTE: since tautological constraints are already filtered away
00614         // by iterators, here we must have an inconsistent constraint.
00615         PPL_ASSERT(c.is_inconsistent());
00616         return false;
00617       }
00618       Linear_Expression le;
00619       for (dimension_type i = space_dim; i-- > 0; )
00620         le += (c.coefficient(Variable(i)) / homogeneous_gcd) * Variable(i);
00621       // Add the integer part of `inhomogeneous'.
00622       le += (inhomogeneous / homogeneous_gcd);
00623       // Further tighten the constraint if the inhomogeneous term
00624       // was integer, i.e., if `homogeneous_gcd' divides `inhomogeneous'.
00625       gcd_assign(gcd, homogeneous_gcd, inhomogeneous);
00626       if (gcd == homogeneous_gcd)
00627         le -= 1;
00628       mip.add_constraint(le >= 0);
00629     }
00630     else {
00631       // Equality or non-strict inequality.
00632       // If possible, avoid useless gcd computations.
00633       if (inhomogeneous == 0)
00634         // The inhomogeneous term cannot be tightened.
00635         mip.add_constraint(c);
00636       else {
00637         // Compute the GCD of the coefficients of c
00638         // (disregarding the inhomogeneous term)
00639         // to see whether or not the inhomogeneous term can be tightened.
00640         homogeneous_gcd = 0;
00641         for (dimension_type i = space_dim; i-- > 0; )
00642           gcd_assign(homogeneous_gcd,
00643                      homogeneous_gcd, c.coefficient(Variable(i)));
00644         if (homogeneous_gcd == 0) {
00645           // NOTE: since tautological constraints are already filtered away
00646           // by iterators, here we must have an inconsistent constraint.
00647           PPL_ASSERT(c.is_inconsistent());
00648           return false;
00649         }
00650         else if (homogeneous_gcd == 1)
00651           // The normalized inhomogeneous term is integer:
00652           // add the constraint as-is.
00653           mip.add_constraint(c);
00654         else {
00655           PPL_ASSERT(homogeneous_gcd > 1);
00656           // Here the normalized inhomogeneous term is rational:
00657           // the constraint has to be tightened.
00658 #ifndef NDEBUG
00659           // `homogeneous_gcd' does not divide `inhomogeneous'.
00660           // FIXME: add a divisibility test for Coefficient.
00661           gcd_assign(gcd, homogeneous_gcd, inhomogeneous);
00662           PPL_ASSERT(gcd == 1);
00663 #endif
00664           if (c.type() == Constraint::EQUALITY)
00665             return false;
00666           // Extract the homogeneous part of the constraint.
00667           Linear_Expression le = Linear_Expression(c);
00668           le -= inhomogeneous;
00669           // Tighten the inhomogeneous term.
00670           assign_r(rational_inhomogeneous.get_num(),
00671                    inhomogeneous, ROUND_NOT_NEEDED);
00672           assign_r(rational_inhomogeneous.get_den(),
00673                    homogeneous_gcd, ROUND_NOT_NEEDED);
00674           // Note: canonicalization is not needed (as gcd == 1).
00675           PPL_ASSERT(is_canonical(rational_inhomogeneous));
00676           assign_r(tightened_inhomogeneous,
00677                    rational_inhomogeneous, ROUND_DOWN);
00678           tightened_inhomogeneous *= homogeneous_gcd;
00679           le += tightened_inhomogeneous;
00680           mip.add_constraint(le >= 0);
00681         }
00682       }
00683     }
00684   }
00685 #endif // TEMPORARY WORKAROUND.
00686   return mip.is_satisfiable();
00687 }

PPL::dimension_type Parma_Polyhedra_Library::Polyhedron::conversion ( Linear_System source,
dimension_type  start,
Linear_System dest,
Bit_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 348 of file conversion.cc.

References Parma_Polyhedra_Library::Linear_System::add_pending_row(), Parma_Polyhedra_Library::Bit_Matrix::add_recycled_row(), Parma_Polyhedra_Library::Scalar_Products::assign(), Parma_Polyhedra_Library::Coefficient_zero(), Parma_Polyhedra_Library::Bit_Matrix::columns_erase_to_end(), Parma_Polyhedra_Library::Bit_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::Bit_Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Bit_Matrix::num_rows(), Parma_Polyhedra_Library::Matrix::num_rows(), PPL_DIRTY_TEMP_COEFFICIENT, Parma_Polyhedra_Library::Linear_Row::RAY_OR_POINT_OR_INEQUALITY, Parma_Polyhedra_Library::Bit_Matrix::rows_erase_to_end(), Parma_Polyhedra_Library::Bit_Row::set(), Parma_Polyhedra_Library::Linear_System::set_sorted(), Parma_Polyhedra_Library::Linear_Row::strong_normalize(), Parma_Polyhedra_Library::sub_mul_assign(), Parma_Polyhedra_Library::Bit_Matrix::swap(), swap(), Parma_Polyhedra_Library::Linear_System::topology(), Parma_Polyhedra_Library::Linear_System::unset_pending_rows(), WEIGHT_ADD_MUL, and WEIGHT_BEGIN.

Referenced by add_and_minimize(), and minimize().

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

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

Same as poly_difference_assign(y).

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

References poly_difference_assign().

00086                                                  {
00087   poly_difference_assign(y);
00088 }

void Parma_Polyhedra_Library::Polyhedron::drop_some_non_integer_points ( const Variables_Set pvars,
Complexity_Class  complexity 
) [protected]

Possibly tightens *this by dropping some points with non-integer coordinates for the space dimensions corresponding to *pvars.

Parameters:
pvars When nonzero, points with non-integer coordinates for the variables/space-dimensions contained in *pvars can be discarded.
complexity The maximal complexity of any algorithms used.
Note:
Currently there is no optimality guarantee, not even if complexity is ANY_COMPLEXITY.

Definition at line 2078 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::ANY_COMPLEXITY, clear_constraints_minimized(), clear_generators_up_to_date(), con_sys, constraints_are_up_to_date(), Parma_Polyhedra_Library::Constraint::epsilon_leq_one(), Parma_Polyhedra_Library::exact_div_assign(), Parma_Polyhedra_Library::gcd_assign(), has_pending_constraints(), has_pending_generators(), Parma_Polyhedra_Library::Constraint_System::insert(), Parma_Polyhedra_Library::Constraint::is_equality(), is_necessarily_closed(), Parma_Polyhedra_Library::Constraint::is_tautological(), marked_empty(), Parma_Polyhedra_Library::neg_assign(), Parma_Polyhedra_Library::Row::normalize(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), PPL_DIRTY_TEMP_COEFFICIENT, process_pending_constraints(), process_pending_generators(), set_empty(), Parma_Polyhedra_Library::Linear_System::set_sorted(), space_dim, and update_constraints().

02079                                                                            {
02080   // There is nothing to do for an empty set of variables.
02081   if (pvars != 0 && pvars->empty())
02082     return;
02083 
02084   // Any empty polyhedron does not contain integer points.
02085   if (marked_empty())
02086     return;
02087 
02088   // A zero-dimensional, universe polyhedron has, by convention, an
02089   // integer point.
02090   if (space_dim == 0) {
02091     set_empty();
02092     return;
02093   }
02094 
02095   // The constraints (possibly with pending rows) are required.
02096   if (has_pending_generators()) {
02097     // Processing of pending generators is exponential in the worst case.
02098     if (complexity != ANY_COMPLEXITY)
02099       return;
02100     else
02101       process_pending_generators();
02102   }
02103   if (!constraints_are_up_to_date()) {
02104     // Constraints update is exponential in the worst case.
02105     if (complexity != ANY_COMPLEXITY)
02106       return;
02107     else
02108       update_constraints();
02109   }
02110   // For NNC polyhedra we need to process any pending constraints.
02111   if (!is_necessarily_closed() && has_pending_constraints()) {
02112     if (complexity != ANY_COMPLEXITY)
02113       return;
02114     else if (!process_pending_constraints())
02115       // We just discovered the polyhedron is empty.
02116       return;
02117   }
02118 
02119   PPL_ASSERT(!has_pending_generators() && constraints_are_up_to_date());
02120   PPL_ASSERT(is_necessarily_closed() || !has_pending_constraints());
02121 
02122   bool changed = false;
02123   const dimension_type eps_index = space_dim + 1;
02124   PPL_DIRTY_TEMP_COEFFICIENT(gcd);
02125 
02126   for (dimension_type j = con_sys.num_rows(); j-- > 0; ) {
02127     Constraint& c = con_sys[j];
02128     if (c.is_tautological())
02129       goto next_constraint;
02130 
02131     if (pvars != 0) {
02132       for (dimension_type i = space_dim; i-- > 0; )
02133         if (c[i+1] != 0 && pvars->find(i) == pvars->end())
02134           goto next_constraint;
02135     }
02136 
02137     if (!is_necessarily_closed()) {
02138       // Transform all strict inequalities into non-strict ones,
02139       // with the inhomogeneous term incremented by 1.
02140       if (c[eps_index] < 0) {
02141         c[eps_index] = 0;
02142         --c[0];
02143         // Enforce normalization.
02144         // FIXME: is this really necessary?
02145         c.normalize();
02146         changed = true;
02147       }
02148     }
02149 
02150     {
02151       // Compute the GCD of all the homogeneous terms.
02152       dimension_type i = space_dim+1;
02153       while (i > 1) {
02154         const Coefficient& c_i = c[--i];
02155         if (const int c_i_sign = sgn(c_i)) {
02156           gcd = c_i;
02157           if (c_i_sign < 0)
02158             neg_assign(gcd);
02159           goto compute_gcd;
02160         }
02161       }
02162       // We reach this point only if all the coefficients were zero.
02163       goto next_constraint;
02164 
02165     compute_gcd:
02166       if (gcd == 1)
02167         goto next_constraint;
02168       while (i > 1) {
02169         const Coefficient& c_i = c[--i];
02170         if (c_i != 0) {
02171           // See the comment in Row::normalize().
02172           gcd_assign(gcd, c_i, gcd);
02173           if (gcd == 1)
02174             goto next_constraint;
02175         }
02176       }
02177       PPL_ASSERT(gcd != 1);
02178       PPL_ASSERT(c[0] % gcd != 0);
02179 
02180       // If we have an equality, the polyhedron becomes empty.
02181       if (c.is_equality()) {
02182         set_empty();
02183         return;
02184       }
02185 
02186       // Divide the inhomogeneous coefficients by the GCD.
02187       for (dimension_type k = space_dim+1; --k > 0; ) {
02188         Coefficient& c_k = c[k];
02189         exact_div_assign(c_k, c_k, gcd);
02190       }
02191       Coefficient& c_0 = c[0];
02192       const int c_0_sign = sgn(c_0);
02193       c_0 /= gcd;
02194       if (c_0_sign < 0)
02195         --c_0;
02196       changed = true;
02197     }
02198 
02199   next_constraint:
02200     ;
02201   }
02202 
02203   if (changed) {
02204     if (!is_necessarily_closed()) {
02205       con_sys.insert(Constraint::epsilon_leq_one());
02206       // FIXME: make sure that the following line really can stay here
02207       // and should not be moved below the brace.
02208       con_sys.set_sorted(false);
02209     }
02210 
02211     // After changing the system of constraints, the generators
02212     // are no longer up-to-date and the constraints are no longer
02213     // minimized.
02214     clear_generators_up_to_date();
02215     clear_constraints_minimized();
02216   }
02217   PPL_ASSERT_HEAVY(OK());
02218 }

void Parma_Polyhedra_Library::Polyhedron::drop_some_non_integer_points ( const Variables_Set vars,
Complexity_Class  complexity = ANY_COMPLEXITY 
) [inline]

Possibly tightens *this by dropping some points with non-integer coordinates for the space dimensions corresponding to vars.

Parameters:
vars Points with non-integer coordinates for these variables/space-dimensions can be discarded.
complexity The maximal complexity of any algorithms used.
Note:
Currently there is no optimality guarantee, not even if complexity is ANY_COMPLEXITY.

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

References drop_some_non_integer_points().

00396                                                                       {
00397   drop_some_non_integer_points(&vars, complexity);
00398 }

void Parma_Polyhedra_Library::Polyhedron::drop_some_non_integer_points ( Complexity_Class  complexity = ANY_COMPLEXITY  )  [inline]

Possibly tightens *this by dropping some points with non-integer coordinates.

Parameters:
complexity The maximal complexity of any algorithms used.
Note:
Currently there is no optimality guarantee, not even if complexity is ANY_COMPLEXITY.

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

Referenced by drop_some_non_integer_points().

00389                                                                     {
00390   const Variables_Set* p_vs = 0;
00391   drop_some_non_integer_points(p_vs, complexity);
00392 }

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 548 of file Polyhedron_chdims.cc.

References add_recycled_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().

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

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 3747 of file Polyhedron_public.cc.

References con_sys, Parma_Polyhedra_Library::Bit_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().

03747                                               {
03748   return
03749     con_sys.external_memory_in_bytes()
03750     + gen_sys.external_memory_in_bytes()
03751     + sat_c.external_memory_in_bytes()
03752     + sat_g.external_memory_in_bytes();
03753 }

void Parma_Polyhedra_Library::Polyhedron::finalize (  )  [static]

Finalizes the class.

Definition at line 53 of file Polyhedron_public.cc.

References simplify_num_saturators_p, and simplify_num_saturators_size.

00053                         {
00054   delete [] simplify_num_saturators_p;
00055   simplify_num_saturators_p = 0;
00056   simplify_num_saturators_size = 0;
00057 }

void Parma_Polyhedra_Library::Polyhedron::fold_space_dimensions ( const Variables_Set vars,
Variable  dest 
)

Folds the space dimensions in vars into dest.

Parameters:
vars The set of Variable objects corresponding to the space dimensions to be folded;
dest 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 dest or with one of the Variable objects contained in vars. Also thrown if dest is contained in vars.

If *this has space dimension $n$, with $n > 0$, dest has space dimension $k \leq n$, vars is a set of variables whose maximum space dimension is also less than or equal to $n$, and dest is not a member of vars, then the space dimensions corresponding to variables in vars are folded into the $k$-th space dimension.

Definition at line 604 of file Polyhedron_chdims.cc.

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

00605                                                       {
00606   // TODO: this implementation is _really_ an executable specification.
00607 
00608   // `dest' should be one of the dimensions of the polyhedron.
00609   if (dest.space_dimension() > space_dim)
00610     throw_dimension_incompatible("fold_space_dimensions(vs, v)", "v", dest);
00611 
00612   // The folding of no dimensions is a no-op.
00613   if (vars.empty())
00614     return;
00615 
00616   // All variables in `vars' should be dimensions of the polyhedron.
00617   if (vars.space_dimension() > space_dim)
00618     throw_dimension_incompatible("fold_space_dimensions(vs, v)",
00619                                  "vs.space_dimension()",
00620                                  vars.space_dimension());
00621 
00622   // Moreover, `dest.id()' should not occur in `vars'.
00623   if (vars.find(dest.id()) != vars.end())
00624     throw_invalid_argument("fold_space_dimensions(vs, v)",
00625                            "v should not occur in vs");
00626 
00627   // All of the affine images we are going to compute are not invertible,
00628   // hence we will need to compute the generators of the polyehdron.
00629   // Since we keep taking copies, make sure that a single conversion
00630   // from constraints to generators is computed.
00631   (void) generators();
00632   // Having generators, we now know if the polyhedron is empty:
00633   // in that case, folding is equivalent to just removing space dimensions.
00634   if (!marked_empty()) {
00635     for (Variables_Set::const_iterator i = vars.begin(),
00636            vs_end = vars.end(); i != vs_end; ++i) {
00637       Polyhedron copy = *this;
00638       copy.affine_image(dest, Linear_Expression(Variable(*i)));
00639       poly_hull_assign(copy);
00640     }
00641   }
00642   remove_space_dimensions(vars);
00643   PPL_ASSERT_HEAVY(OK());
00644 }

bool Parma_Polyhedra_Library::Polyhedron::frequency ( const Linear_Expression expr,
Coefficient freq_n,
Coefficient freq_d,
Coefficient val_n,
Coefficient val_d 
) const

Returns true if and only if there exist a unique value val such that *this saturates the equality expr = val.

Parameters:
expr The linear expression for which the frequency is needed;
freq_n If true is returned, the value is set to $0$; Present for interface compatibility with class Grid, where the frequency can have a non-zero value;
freq_d If true is returned, the value is set to $1$;
val_n The numerator of val;
val_d The denominator of val;
Exceptions:
std::invalid_argument Thrown if expr and *this are dimension-incompatible.

If false is returned, then freq_n, freq_d, val_n and val_d are left untouched.

Definition at line 3462 of file Polyhedron_public.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(), is_empty(), Parma_Polyhedra_Library::Generator::is_line_or_ray(), Parma_Polyhedra_Library::Generator::is_point(), marked_empty(), Parma_Polyhedra_Library::Matrix::num_rows(), PPL_DIRTY_TEMP_COEFFICIENT, process_pending_constraints(), Parma_Polyhedra_Library::Linear_Expression::space_dimension(), throw_dimension_incompatible(), and update_generators().

03464                                                                          {
03465   // The dimension of `expr' must be at most the dimension of *this.
03466   if (space_dim < expr.space_dimension())
03467     throw_dimension_incompatible("frequency(e, ...)", "e", expr);
03468 
03469   // If the `expr' has a constant value, then the frequency
03470   // `freq_n' is 0. Otherwise the values for \p expr are not discrete
03471   // and we return false.
03472 
03473   // Space dimension = 0: if empty, then return false;
03474   // otherwise the frequency is 1 and the value is 0
03475   if (space_dim == 0) {
03476     if (is_empty())
03477       return false;
03478     freq_n = 0;
03479     freq_d = 1;
03480     val_n = expr.inhomogeneous_term();
03481     val_d = 1;
03482     return true;
03483   }
03484 
03485   // For an empty polyhedron, we simply return false.
03486   if (marked_empty()
03487       || (has_pending_constraints() && !process_pending_constraints())
03488       || (!generators_are_up_to_date() && !update_generators()))
03489     return false;
03490 
03491   // The polyhedron has updated, possibly pending generators.
03492   // The following loop will iterate through the generator
03493   // to see if `expr' has a constant value.
03494   PPL_DIRTY_TEMP0(mpq_class, value);
03495 
03496   // True if we have no other candidate value to compare with.
03497   bool first_candidate = true;
03498 
03499   PPL_DIRTY_TEMP_COEFFICIENT(sp);
03500   PPL_DIRTY_TEMP0(mpq_class, candidate);
03501   for (dimension_type i = gen_sys.num_rows(); i-- > 0; ) {
03502     const Generator& gen_sys_i = gen_sys[i];
03503     Scalar_Products::homogeneous_assign(sp, expr, gen_sys_i);
03504     // Lines and rays in `*this' can cause `expr' to be non-constant.
03505     if (gen_sys_i.is_line_or_ray()) {
03506       const int sp_sign = sgn(sp);
03507       if (sp_sign != 0)
03508         // `expr' is unbounded in `*this'.
03509         return false;
03510     }
03511     else {
03512       // We have a point or a closure point.
03513       PPL_ASSERT(gen_sys_i.is_point() || gen_sys_i.is_closure_point());
03514       // Notice that we are ignoring the constant term in `expr' here.
03515       // We will add it to the value if there is a constant value.
03516       assign_r(candidate.get_num(), sp, ROUND_NOT_NEEDED);
03517       assign_r(candidate.get_den(), gen_sys_i[0], ROUND_NOT_NEEDED);
03518       candidate.canonicalize();
03519       if (first_candidate) {
03520         // We have a (new) candidate value.
03521         first_candidate = false;
03522         value = candidate;
03523       }
03524       else if (candidate != value)
03525         return false;
03526     }
03527   }
03528 
03529   // Add in the constant term in `expr'.
03530   PPL_DIRTY_TEMP0(mpz_class, n);
03531   assign_r(n, expr.inhomogeneous_term(), ROUND_NOT_NEEDED);
03532   value += n;
03533   // FIXME: avoid these temporaries, if possible.
03534   // This can be done adding an `assign' function working on native
03535   // and checked or an operator= that have on one side a checked and
03536   // on the other a native or checked.
03537   // The reason why now we can't use operator= is the fact that we
03538   // still can have Coefficient defined to mpz_class (and not
03539   // Checked_Number<mpz_class>).
03540   val_n = Coefficient(value.get_num());
03541   val_d = Coefficient(value.get_den());
03542 
03543   freq_n = 0;
03544   freq_d = 1;
03545   return true;
03546 }

void Parma_Polyhedra_Library::Polyhedron::generalized_affine_image ( const Linear_Expression lhs,
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 3054 of file Polyhedron_public.cc.

References add_recycled_generators(), add_space_dimensions_and_embed(), Parma_Polyhedra_Library::Linear_Expression::coefficient(), Parma_Polyhedra_Library::EQUAL, Parma_Polyhedra_Library::GREATER_OR_EQUAL, Parma_Polyhedra_Library::GREATER_THAN, Parma_Polyhedra_Library::Generator_System::insert(), is_empty(), is_necessarily_closed(), Parma_Polyhedra_Library::LESS_OR_EQUAL, Parma_Polyhedra_Library::LESS_THAN, marked_empty(), Parma_Polyhedra_Library::NOT_EQUAL, OK(), refine_no_check(), remove_higher_space_dimensions(), Parma_Polyhedra_Library::Linear_Expression::space_dimension(), throw_dimension_incompatible(), and throw_invalid_argument().

03056                                                                         {
03057   // Dimension-compatibility checks.
03058   // The dimension of `lhs' should not be greater than the dimension
03059   // of `*this'.
03060   dimension_type lhs_space_dim = lhs.space_dimension();
03061   if (space_dim < lhs_space_dim)
03062     throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
03063                                  "e1", lhs);
03064   // The dimension of `rhs' should not be greater than the dimension
03065   // of `*this'.
03066   const dimension_type rhs_space_dim = rhs.space_dimension();
03067   if (space_dim < rhs_space_dim)
03068     throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
03069                                  "e2", rhs);
03070 
03071   // Strict relation symbols are only admitted for NNC polyhedra.
03072   if (is_necessarily_closed()
03073       && (relsym == LESS_THAN || relsym == GREATER_THAN))
03074     throw_invalid_argument("generalized_affine_image(e1, r, e2)",
03075                            "r is a strict relation symbol");
03076   // The relation symbol cannot be a disequality.
03077   if (relsym == NOT_EQUAL)
03078     throw_invalid_argument("generalized_affine_image(e1, r, e2)",
03079                            "r is the disequality relation symbol");
03080 
03081   // Any image of an empty polyhedron is empty.
03082   if (marked_empty())
03083     return;
03084 
03085   // Compute the actual space dimension of `lhs',
03086   // i.e., the highest dimension having a non-zero coefficient in `lhs'.
03087   for ( ; lhs_space_dim > 0; lhs_space_dim--)
03088     if (lhs.coefficient(Variable(lhs_space_dim - 1)) != 0)
03089       break;
03090   // If all variables have a zero coefficient, then `lhs' is a constant:
03091   // we can simply add the constraint `lhs relsym rhs'.
03092   if (lhs_space_dim == 0) {
03093     switch (relsym) {
03094     case LESS_THAN:
03095       refine_no_check(lhs < rhs);
03096       break;
03097     case LESS_OR_EQUAL:
03098       refine_no_check(lhs <= rhs);
03099       break;
03100     case EQUAL:
03101       refine_no_check(lhs == rhs);
03102       break;
03103     case GREATER_OR_EQUAL:
03104       refine_no_check(lhs >= rhs);
03105       break;
03106     case GREATER_THAN:
03107       refine_no_check(lhs > rhs);
03108       break;
03109     case NOT_EQUAL:
03110       // The NOT_EQUAL case has been already dealt with.
03111       throw std::runtime_error("PPL internal error");
03112     }
03113     return;
03114   }
03115 
03116   // Gather in `new_lines' the collections of all the lines having
03117   // the direction of variables occurring in `lhs'.
03118   // While at it, check whether or not there exists a variable
03119   // occurring in both `lhs' and `rhs'.
03120   Generator_System new_lines;
03121   bool lhs_vars_intersects_rhs_vars = false;
03122   for (dimension_type i = lhs_space_dim; i-- > 0; )
03123     if (lhs.coefficient(Variable(i)) != 0) {
03124       new_lines.insert(line(Variable(i)));
03125       if (rhs.coefficient(Variable(i)) != 0)
03126         lhs_vars_intersects_rhs_vars = true;
03127     }
03128 
03129   if (lhs_vars_intersects_rhs_vars) {
03130     // Some variables in `lhs' also occur in `rhs'.
03131     // To ease the computation, we add an additional dimension.
03132     const Variable new_var = Variable(space_dim);
03133     add_space_dimensions_and_embed(1);
03134 
03135     // Constrain the new dimension to be equal to the right hand side.
03136     // (check for emptiness because we will add lines).
03137     refine_no_check(new_var == rhs);
03138     if (!is_empty()) {
03139       // Existentially quantify the variables in the left hand side.
03140       add_recycled_generators(new_lines);
03141 
03142       // Constrain the new dimension so that it is related to
03143       // the left hand side as dictated by `relsym'
03144       // (we force minimization because we will need the generators).
03145       switch (relsym) {
03146       case LESS_THAN:
03147         refine_no_check(lhs < new_var);
03148         break;
03149       case LESS_OR_EQUAL:
03150         refine_no_check(lhs <= new_var);
03151         break;
03152       case EQUAL:
03153         refine_no_check(lhs == new_var);
03154         break;
03155       case GREATER_OR_EQUAL:
03156         refine_no_check(lhs >= new_var);
03157         break;
03158       case GREATER_THAN:
03159         refine_no_check(lhs > new_var);
03160         break;
03161       case NOT_EQUAL:
03162         // The NOT_EQUAL case has been already dealt with.
03163         throw std::runtime_error("PPL internal error");
03164       }
03165     }
03166     // Remove the temporarily added dimension.
03167     remove_higher_space_dimensions(space_dim-1);
03168   }
03169   else {
03170     // `lhs' and `rhs' variables are disjoint:
03171     // there is no need to add a further dimension.
03172 
03173     // Any image of an empty polyhedron is empty.
03174     // Note: DO check for emptiness here, as we will add lines.
03175     if (is_empty())
03176       return;
03177 
03178     // Existentially quantify the variables in the left hand side.
03179     add_recycled_generators(new_lines);
03180 
03181     // Constrain the left hand side expression so that it is related to
03182     // the right hand side expression as dictated by `relsym'.
03183     switch (relsym) {
03184     case LESS_THAN:
03185       refine_no_check(lhs < rhs);
03186       break;
03187     case LESS_OR_EQUAL:
03188       refine_no_check(lhs <= rhs);
03189       break;
03190     case EQUAL:
03191       refine_no_check(lhs == rhs);
03192       break;
03193     case GREATER_OR_EQUAL:
03194       refine_no_check(lhs >= rhs);
03195       break;
03196     case GREATER_THAN:
03197       refine_no_check(lhs > rhs);
03198       break;
03199     case NOT_EQUAL:
03200       // The NOT_EQUAL case has been already dealt with.
03201       throw std::runtime_error("PPL internal error");
03202     }
03203   }
03204   PPL_ASSERT_HEAVY(OK());
03205 }

void Parma_Polyhedra_Library::Polyhedron::generalized_affine_image ( Variable  var,
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 2861 of file Polyhedron_public.cc.

References add_generator(), 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_OR_EQUAL, Parma_Polyhedra_Library::GREATER_THAN, is_empty(), is_necessarily_closed(), Parma_Polyhedra_Library::LESS_OR_EQUAL, Parma_Polyhedra_Library::LESS_THAN, minimize(), Parma_Polyhedra_Library::NOT_EQUAL, Parma_Polyhedra_Library::Matrix::num_rows(), OK(), Parma_Polyhedra_Library::Linear_System::set_sorted(), 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(), and generalized_affine_preimage().

02864                                                                         {
02865   // The denominator cannot be zero.
02866   if (denominator == 0)
02867     throw_invalid_argument("generalized_affine_image(v, r, e, d)", "d == 0");
02868 
02869   // Dimension-compatibility checks.
02870   // The dimension of `expr' should not be greater than the dimension
02871   // of `*this'.
02872   if (space_dim < expr.space_dimension())
02873     throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
02874                                  "e", expr);
02875   // `var' should be one of the dimensions of the polyhedron.
02876   const dimension_type var_space_dim = var.space_dimension();
02877   if (space_dim < var_space_dim)
02878     throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
02879                                  "v", var);
02880 
02881   // Strict relation symbols are only admitted for NNC polyhedra.
02882   if (is_necessarily_closed()
02883       && (relsym == LESS_THAN || relsym == GREATER_THAN))
02884     throw_invalid_argument("generalized_affine_image(v, r, e, d)",
02885                            "r is a strict relation symbol");
02886   // The relation symbol cannot be a disequality.
02887   if (relsym == NOT_EQUAL)
02888     throw_invalid_argument("generalized_affine_image(v, r, e, d)",
02889                            "r is the disequality relation symbol");
02890 
02891   // First compute the affine image.
02892   affine_image(var, expr, denominator);
02893 
02894   if (relsym == EQUAL)
02895     // The affine relation is indeed an affine function.
02896     return;
02897 
02898   // Any image of an empty polyhedron is empty.
02899   // Note: DO check for emptiness here, as we will later add a ray.
02900   if (is_empty())
02901     return;
02902 
02903   switch (relsym) {
02904   case LESS_OR_EQUAL:
02905     add_generator(ray(-var));
02906     break;
02907   case GREATER_OR_EQUAL:
02908     add_generator(ray(var));
02909     break;
02910   case LESS_THAN:
02911   // Intentionally fall through.
02912   case GREATER_THAN:
02913     {
02914       // The relation symbol is strict.
02915       PPL_ASSERT(!is_necessarily_closed());
02916       // While adding the ray, we minimize the generators
02917       // in order to avoid adding too many redundant generators later.
02918       add_generator(ray(relsym == GREATER_THAN ? var : -var));
02919       minimize();
02920       // We split each point of the generator system into two generators:
02921       // a closure point, having the same coordinates of the given point,
02922       // and another point, having the same coordinates for all but the
02923       // `var' dimension, which is displaced along the direction of the
02924       // newly introduced ray.
02925       const dimension_type eps_index = space_dim + 1;
02926       for (dimension_type i =  gen_sys.num_rows(); i-- > 0; )
02927         if (gen_sys[i].is_point()) {
02928           // Add a `var'-displaced copy of `gen_sys[i]' to the generator system.
02929           gen_sys.add_row(gen_sys[i]);
02930           if (relsym == GREATER_THAN)
02931             ++gen_sys[gen_sys.num_rows()-1][var_space_dim];
02932           else
02933             --gen_sys[gen_sys.num_rows()-1][var_space_dim];
02934           // Transform `gen_sys[i]' into a closure point.
02935           gen_sys[i][eps_index] = 0;
02936         }
02937       clear_constraints_up_to_date();
02938       clear_generators_minimized();
02939       gen_sys.set_sorted(false);
02940       clear_sat_c_up_to_date();
02941       clear_sat_g_up_to_date();
02942     }
02943     break;
02944   default:
02945     // The EQUAL and NOT_EQUAL cases have been already dealt with.
02946     throw std::runtime_error("PPL internal error");
02947   }
02948   PPL_ASSERT_HEAVY(OK());
02949 }

void Parma_Polyhedra_Library::Polyhedron::generalized_affine_preimage ( const Linear_Expression lhs,
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 3208 of file Polyhedron_public.cc.

References add_recycled_generators(), add_space_dimensions_and_embed(), Parma_Polyhedra_Library::Linear_Expression::coefficient(), Parma_Polyhedra_Library::EQUAL, generalized_affine_image(), Parma_Polyhedra_Library::GREATER_OR_EQUAL, Parma_Polyhedra_Library::GREATER_THAN, Parma_Polyhedra_Library::Generator_System::insert(), is_empty(), is_necessarily_closed(), Parma_Polyhedra_Library::LESS_OR_EQUAL, Parma_Polyhedra_Library::LESS_THAN, marked_empty(), Parma_Polyhedra_Library::NOT_EQUAL, OK(), refine_no_check(), remove_higher_space_dimensions(), Parma_Polyhedra_Library::Linear_Expression::space_dimension(), throw_dimension_incompatible(), and throw_invalid_argument().

03210                                                                            {
03211   // Dimension-compatibility checks.
03212   // The dimension of `lhs' should not be greater than the dimension
03213   // of `*this'.
03214   dimension_type lhs_space_dim = lhs.space_dimension();
03215   if (space_dim < lhs_space_dim)
03216     throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2)",
03217                                  "e1", lhs);
03218   // The dimension of `rhs' should not be greater than the dimension
03219   // of `*this'.
03220   const dimension_type rhs_space_dim = rhs.space_dimension();
03221   if (space_dim < rhs_space_dim)
03222     throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2)",
03223                                  "e2", rhs);
03224 
03225   // Strict relation symbols are only admitted for NNC polyhedra.
03226   if (is_necessarily_closed()
03227       && (relsym == LESS_THAN || relsym == GREATER_THAN))
03228     throw_invalid_argument("generalized_affine_preimage(e1, r, e2)",
03229                            "r is a strict relation symbol");
03230   // The relation symbol cannot be a disequality.
03231   if (relsym == NOT_EQUAL)
03232     throw_invalid_argument("generalized_affine_preimage(e1, r, e2)",
03233                            "r is the disequality relation symbol");
03234 
03235   // Any preimage of an empty polyhedron is empty.
03236   if (marked_empty())
03237     return;
03238 
03239   // Compute the actual space dimension of `lhs',
03240   // i.e., the highest dimension having a non-zero coefficient in `lhs'.
03241   for ( ; lhs_space_dim > 0; lhs_space_dim--)
03242     if (lhs.coefficient(Variable(lhs_space_dim - 1)) != 0)
03243       break;
03244 
03245   // If all variables have a zero coefficient, then `lhs' is a constant:
03246   // in this case, preimage and image happen to be the same.
03247   if (lhs_space_dim == 0) {
03248     generalized_affine_image(lhs, relsym, rhs);
03249     return;
03250   }
03251 
03252   // Gather in `new_lines' the collections of all the lines having
03253   // the direction of variables occurring in `lhs'.
03254   // While at it, check whether or not there exists a variable
03255   // occurring in both `lhs' and `rhs'.
03256   Generator_System new_lines;
03257   bool lhs_vars_intersects_rhs_vars = false;
03258   for (dimension_type i = lhs_space_dim; i-- > 0; )
03259     if (lhs.coefficient(Variable(i)) != 0) {
03260       new_lines.insert(line(Variable(i)));
03261       if (rhs.coefficient(Variable(i)) != 0)
03262         lhs_vars_intersects_rhs_vars = true;
03263     }
03264 
03265   if (lhs_vars_intersects_rhs_vars) {
03266     // Some variables in `lhs' also occur in `rhs'.
03267     // To ease the computation, we add an additional dimension.
03268     const Variable new_var = Variable(space_dim);
03269     add_space_dimensions_and_embed(1);
03270 
03271     // Constrain the new dimension to be equal to `lhs'
03272     // (also check for emptiness because we have to add lines).
03273     refine_no_check(new_var == lhs);
03274     if (!is_empty()) {
03275       // Existentially quantify the variables in the left hand side.
03276       add_recycled_generators(new_lines);
03277 
03278       // Constrain the new dimension so that it is related to
03279       // the right hand side as dictated by `relsym'.
03280       switch (relsym) {
03281       case LESS_THAN:
03282         refine_no_check(new_var < rhs);
03283         break;
03284       case LESS_OR_EQUAL:
03285         refine_no_check(new_var <= rhs);
03286         break;
03287       case EQUAL:
03288         refine_no_check(new_var == rhs);
03289         break;
03290       case GREATER_OR_EQUAL:
03291         refine_no_check(new_var >= rhs);
03292         break;
03293       case GREATER_THAN:
03294         refine_no_check(new_var > rhs);
03295         break;
03296       case NOT_EQUAL:
03297         // The NOT_EQUAL case has been already dealt with.
03298         throw std::runtime_error("PPL internal error");
03299       }
03300     }
03301     // Remove the temporarily added dimension.
03302     remove_higher_space_dimensions(space_dim-1);
03303   }
03304   else {
03305     // `lhs' and `rhs' variables are disjoint:
03306     // there is no need to add a further dimension.
03307 
03308     // Constrain the left hand side expression so that it is related to
03309     // the right hand side expression as dictated by `relsym'.
03310     switch (relsym) {
03311     case LESS_THAN:
03312       refine_no_check(lhs < rhs);
03313       break;
03314     case LESS_OR_EQUAL:
03315       refine_no_check(lhs <= rhs);
03316       break;
03317     case EQUAL:
03318       refine_no_check(lhs == rhs);
03319       break;
03320     case GREATER_OR_EQUAL:
03321       refine_no_check(lhs >= rhs);
03322       break;
03323     case GREATER_THAN:
03324       refine_no_check(lhs > rhs);
03325       break;
03326     case NOT_EQUAL:
03327       // The NOT_EQUAL case has been already dealt with.
03328       throw std::runtime_error("PPL internal error");
03329     }
03330     // Any image of an empty polyhedron is empty.
03331     // Note: DO check for emptiness here, as we will add lines.
03332     if (is_empty())
03333       return;
03334     // Existentially quantify all the variables occurring in `lhs'.
03335     add_recycled_generators(new_lines);
03336   }
03337   PPL_ASSERT_HEAVY(OK());
03338 }

void Parma_Polyhedra_Library::Polyhedron::generalized_affine_preimage ( Variable  var,
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 2953 of file Polyhedron_public.cc.

References affine_preimage(), Parma_Polyhedra_Library::Linear_Expression::coefficient(), Parma_Polyhedra_Library::EQUAL, generalized_affine_image(), Parma_Polyhedra_Library::GREATER_OR_EQUAL, Parma_Polyhedra_Library::GREATER_THAN, is_necessarily_closed(), Parma_Polyhedra_Library::LESS_OR_EQUAL, Parma_Polyhedra_Library::LESS_THAN, Parma_Polyhedra_Library::neg_assign(), Parma_Polyhedra_Library::NOT_EQUAL, OK(), PPL_DIRTY_TEMP_COEFFICIENT, refine_no_check(), Parma_Polyhedra_Library::Variable::space_dimension(), Parma_Polyhedra_Library::Linear_Expression::space_dimension(), throw_dimension_incompatible(), throw_invalid_argument(), and unconstrain().

02956                                                                            {
02957   // The denominator cannot be zero.
02958   if (denominator == 0)
02959     throw_invalid_argument("generalized_affine_preimage(v, r, e, d)",
02960                            "d == 0");
02961 
02962   // Dimension-compatibility checks.
02963   // The dimension of `expr' should not be greater than the dimension
02964   // of `*this'.
02965   if (space_dim < expr.space_dimension())
02966     throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
02967                                  "e", expr);
02968   // `var' should be one of the dimensions of the polyhedron.
02969   const dimension_type var_space_dim = var.space_dimension();
02970   if (space_dim < var_space_dim)
02971     throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
02972                                  "v", var);
02973 
02974   // Strict relation symbols are only admitted for NNC polyhedra.
02975   if (is_necessarily_closed()
02976       && (relsym == LESS_THAN || relsym == GREATER_THAN))
02977     throw_invalid_argument("generalized_affine_preimage(v, r, e, d)",
02978                            "r is a strict relation symbol");
02979   // The relation symbol cannot be a disequality.
02980   if (relsym == NOT_EQUAL)
02981     throw_invalid_argument("generalized_affine_preimage(v, r, e, d)",
02982                            "r is the disequality relation symbol");
02983 
02984   // Check whether the affine relation is indeed an affine function.
02985   if (relsym == EQUAL) {
02986     affine_preimage(var, expr, denominator);
02987     return;
02988   }
02989 
02990   // Compute the reversed relation symbol to simplify later coding.
02991   Relation_Symbol reversed_relsym;
02992   switch (relsym) {
02993   case LESS_THAN:
02994     reversed_relsym = GREATER_THAN;
02995     break;
02996   case LESS_OR_EQUAL:
02997     reversed_relsym = GREATER_OR_EQUAL;
02998     break;
02999   case GREATER_OR_EQUAL:
03000     reversed_relsym = LESS_OR_EQUAL;
03001     break;
03002   case GREATER_THAN:
03003     reversed_relsym = LESS_THAN;
03004     break;
03005   default:
03006     // The EQUAL and NOT_EQUAL cases have been already dealt with.
03007     throw std::runtime_error("PPL internal error");
03008   }
03009 
03010   // Check whether the preimage of this affine relation can be easily
03011   // computed as the image of its inverse relation.
03012   const Coefficient& var_coefficient = expr.coefficient(var);
03013   if (var_coefficient != 0) {
03014     Linear_Expression inverse_expr
03015       = expr - (denominator + var_coefficient) * var;
03016     PPL_DIRTY_TEMP_COEFFICIENT(inverse_denominator);
03017     neg_assign(inverse_denominator, var_coefficient);
03018     Relation_Symbol inverse_relsym
03019       = (sgn(denominator) == sgn(inverse_denominator))
03020       ? relsym : reversed_relsym;
03021     generalized_affine_image(var, inverse_relsym, inverse_expr,
03022                              inverse_denominator);
03023     return;
03024   }
03025 
03026   // Here `var_coefficient == 0', so that the preimage cannot
03027   // be easily computed by inverting the affine relation.
03028   // Shrink the polyhedron by adding the constraint induced
03029   // by the affine relation.
03030   const Relation_Symbol corrected_relsym
03031     = (denominator > 0) ? relsym : reversed_relsym;
03032   switch (corrected_relsym) {
03033   case LESS_THAN:
03034     refine_no_check(denominator*var < expr);
03035     break;
03036   case LESS_OR_EQUAL:
03037     refine_no_check(denominator*var <= expr);
03038     break;
03039   case GREATER_OR_EQUAL:
03040     refine_no_check(denominator*var >= expr);
03041     break;
03042   case GREATER_THAN:
03043     refine_no_check(denominator*var > expr);
03044     break;
03045   default:
03046     // The EQUAL and NOT_EQUAL cases have been already dealt with.
03047     throw std::runtime_error("PPL internal error");
03048   }
03049   unconstrain(var);
03050   PPL_ASSERT_HEAVY(OK());
03051 }

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

Returns the system of generators.

Definition at line 130 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(), Parma_Polyhedra_Library::Matrix::has_no_rows(), 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 Parma_Polyhedra_Library::Generator_System::zero_dim_univ().

Referenced by Parma_Polyhedra_Library::BD_Shape< T >::BD_Shape(), Parma_Polyhedra_Library::Box< ITV >::Box(), fold_space_dimensions(), Parma_Polyhedra_Library::Grid::Grid(), map_space_dimensions(), minimized_generators(), and Parma_Polyhedra_Library::Octagonal_Shape< T >::Octagonal_Shape().

00130                                 {
00131   if (marked_empty()) {
00132     PPL_ASSERT(gen_sys.has_no_rows());
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   if (space_dim == 0) {
00144     PPL_ASSERT(gen_sys.num_rows() == 0 && gen_sys.num_columns() == 0);
00145     return Generator_System::zero_dim_univ();
00146   }
00147 
00148   // If the polyhedron has pending constraints, we process them to obtain
00149   // the generators (we may discover that the polyhedron is empty).
00150   // No processing is needed if the polyhedron has pending generators.
00151   if ((has_pending_constraints() && !process_pending_constraints())
00152       || (!generators_are_up_to_date() && !update_generators())) {
00153     // We have just discovered that `*this' is empty.
00154     PPL_ASSERT(gen_sys.has_no_rows());
00155     // We want `gen_sys' to have the appropriate space dimension,
00156     // even though it is an empty generator system.
00157     if (gen_sys.space_dimension() != space_dim) {
00158       Generator_System gs;
00159       gs.adjust_topology_and_space_dimension(topology(), space_dim);
00160       const_cast<Generator_System&>(gen_sys).swap(gs);
00161     }
00162     return gen_sys;
00163   }
00164 
00165   // TODO: reconsider whether to really sort generators at this stage.
00166 #if ENSURE_SORTEDNESS
00167   // We insist in returning a sorted system of generators,
00168   // but sorting is useless if there are pending generators.
00169   if (!has_pending_generators())
00170     obtain_sorted_generators();
00171 #else
00172   // In the case of an NNC polyhedron, if the generator system is fully
00173   // minimized (i.e., minimized and with no pending generator), then
00174   // return a sorted system of generators: this is needed so that the
00175   // const_iterator could correctly filter out the matched closure points.
00176   if (!is_necessarily_closed()
00177       && generators_are_minimized() && !has_pending_generators())
00178     obtain_sorted_generators();
00179 #endif
00180   return gen_sys;
00181 }

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 143 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(), constrains(), generators(), is_topologically_closed(), is_universe(), minimize(), OK(), quick_equivalence_test(), simplify_using_context_assign(), update_sat_c(), and update_sat_g().

00143                                            {
00144   return status.test_g_minimized();
00145 }

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

Returns a universe system of grid generators.

Definition at line 198 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::Grid_Generator_System::insert(), and space_dim.

Referenced by minimized_grid_generators().

00198                                      {
00199   Grid_Generator_System ggs(space_dim);
00200   // Trivially true point.
00201   ggs.insert(grid_point(0*(Variable(0))));
00202   // A line for each dimension.
00203   dimension_type dim = 0;
00204   while (dim < space_dim)
00205     ggs.insert(grid_line(Variable(dim)));
00206   return ggs;
00207 }

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 157 of file Polyhedron_widenings.cc.

References add_recycled_constraints(), con_sys, constraints_are_up_to_date(), contains(), Parma_Polyhedra_Library::Matrix::has_no_rows(), has_pending_generators(), intersection_assign(), is_empty(), 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, swap(), 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 widening_assign().

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

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]
int32_t Parma_Polyhedra_Library::Polyhedron::hash_code (  )  const [inline]

Returns a 32-bit hash code for *this.

If x and y are such that x == y, then x.hash_code() == y.hash_code().

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

References space_dimension().

00045                             {
00046   return space_dimension() & 0x7fffffff;
00047 }

void Parma_Polyhedra_Library::Polyhedron::initialize (  )  [static]

Initializes the class.

Definition at line 46 of file Polyhedron_public.cc.

References simplify_num_saturators_p, and simplify_num_saturators_size.

00046                           {
00047   PPL_ASSERT(simplify_num_saturators_p == 0);
00048   PPL_ASSERT(simplify_num_saturators_size == 0);
00049   simplify_num_saturators_p = new dimension_type[simplify_num_saturators_size];
00050 }

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

Assigns to *this the intersection of *this and y.

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

Definition at line 1900 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 BHRZ03_evolving_points(), BHRZ03_evolving_rays(), H79_widening_assign(), and is_disjoint_from().

01900                                                       {
01901   Polyhedron& x = *this;
01902   // Topology compatibility check.
01903   if (x.topology() != y.topology())
01904     throw_topology_incompatible("intersection_assign(y)", "y", y);
01905   // Dimension-compatibility check.
01906   if (x.space_dim != y.space_dim)
01907     throw_dimension_incompatible("intersection_assign(y)", "y", y);
01908 
01909   // If one of the two polyhedra is empty, the intersection is empty.
01910   if (x.marked_empty())
01911     return;
01912   if (y.marked_empty()) {
01913     x.set_empty();
01914     return;
01915   }
01916 
01917   // If both polyhedra are zero-dimensional,
01918   // then at this point they are necessarily non-empty,
01919   // so that their intersection is non-empty too.
01920   if (x.space_dim == 0)
01921     return;
01922 
01923   // Both systems of constraints have to be up-to-date,
01924   // possibly having pending constraints.
01925   if (x.has_pending_generators())
01926     x.process_pending_generators();
01927   else if (!x.constraints_are_up_to_date())
01928     x.update_constraints();
01929 
01930   if (y.has_pending_generators())
01931     y.process_pending_generators();
01932   else if (!y.constraints_are_up_to_date())
01933     y.update_constraints();
01934 
01935   // Here both systems are up-to-date and possibly have pending constraints
01936   // (but they cannot have pending generators).
01937   PPL_ASSERT(!x.has_pending_generators() && x.constraints_are_up_to_date());
01938   PPL_ASSERT(!y.has_pending_generators() && y.constraints_are_up_to_date());
01939 
01940   // If `x' can support pending constraints,
01941   // the constraints of `y' are added as pending constraints of `x'.
01942   if (x.can_have_something_pending()) {
01943     x.con_sys.add_pending_rows(y.con_sys);
01944     x.set_constraints_pending();
01945   }
01946   else {
01947     // `x' cannot support pending constraints.
01948     // If both constraint systems are (fully) sorted, then we can
01949     // merge them; otherwise we simply add the second to the first.
01950     if (x.con_sys.is_sorted()
01951         && y.con_sys.is_sorted() && !y.has_pending_constraints())
01952       x.con_sys.merge_rows_assign(y.con_sys);
01953     else
01954       x.con_sys.add_rows(y.con_sys);
01955     // Generators are no longer up-to-date and constraints are no
01956     // longer minimized.
01957     x.clear_generators_up_to_date();
01958     x.clear_constraints_minimized();
01959   }
01960   PPL_ASSERT_HEAVY(x.OK() && y.OK());
01961 }

bool Parma_Polyhedra_Library::Polyhedron::is_bounded (  )  const

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

Definition at line 494 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().

00494                                 {
00495   // A zero-dimensional or empty polyhedron is bounded.
00496   if (space_dim == 0
00497       || marked_empty()
00498       || (has_pending_constraints() && !process_pending_constraints())
00499       || (!generators_are_up_to_date() && !update_generators()))
00500     return true;
00501 
00502   // If the system of generators contains any line or a ray,
00503   // then the polyhedron is unbounded.
00504   for (dimension_type i = gen_sys.num_rows(); i-- > 0; )
00505     if (gen_sys[i].is_line_or_ray())
00506       return false;
00507 
00508   // The system of generators is composed only by
00509   // points and closure points: the polyhedron is bounded.
00510   return true;
00511 }

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

Returns true if and only if *this is discrete.

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

References affine_dimension().

00069                               {
00070   return affine_dimension() == 0;
00071 }

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 3669 of file Polyhedron_public.cc.

References intersection_assign(), and is_empty().

Referenced by Parma_Polyhedra_Library::Pointset_Powerset< PSET >::check_containment().

03669                                                          {
03670   Polyhedron z = *this;
03671   z.intersection_assign(y);
03672   return z.is_empty();
03673 }

bool Parma_Polyhedra_Library::Polyhedron::is_empty (  )  const [inline]
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 395 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 BHZ09_C_poly_hull_assign_if_exact(), and contains().

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

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 74 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_generators(), add_space_dimensions_and_embed(), add_space_dimensions_and_project(), BFT00_poly_hull_assign_if_exact(), Parma_Polyhedra_Library::BHRZ03_Certificate::BHRZ03_Certificate(), BHRZ03_combining_constraints(), BHRZ03_evolving_points(), BHZ09_C_poly_hull_assign_if_exact(), BHZ09_NNC_poly_hull_assign_if_exact(), BHZ09_poly_hull_assign_if_exact(), Parma_Polyhedra_Library::H79_Certificate::compare(), Parma_Polyhedra_Library::BHRZ03_Certificate::compare(), concatenate_assign(), drop_some_non_integer_points(), generalized_affine_image(), generalized_affine_preimage(), generators(), Parma_Polyhedra_Library::H79_Certificate::H79_Certificate(), H79_widening_assign(), Parma_Polyhedra_Library::Interfaces::is_necessarily_closed_for_interfaces(), is_topologically_closed(), is_universe(), limited_BHRZ03_extrapolation_assign(), limited_H79_extrapolation_assign(), minimized_constraints(), minimized_generators(), OK(), poly_difference_assign(), refine_no_check(), refine_with_constraints(), remove_higher_space_dimensions(), select_H79_constraints(), simplify_using_context_assign(), 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(), topological_closure_assign(), and wrap_assign().

00074                                         {
00075   // We can check either one of the two matrices.
00076   // (`con_sys' is slightly better, since it is placed at offset 0.)
00077   return con_sys.is_necessarily_closed();
00078 }

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 514 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().

00514                                              {
00515   // Necessarily closed polyhedra are trivially closed.
00516   if (is_necessarily_closed())
00517     return true;
00518   // Any empty or zero-dimensional polyhedron is closed.
00519   if (marked_empty()
00520       || space_dim == 0
00521       || (has_something_pending() && !process_pending()))
00522      return true;
00523 
00524   // At this point there are no pending constraints or generators.
00525   PPL_ASSERT(!has_something_pending());
00526 
00527   if (generators_are_minimized()) {
00528     // A polyhedron is closed if and only if all of its (non-redundant)
00529     // closure points are matched by a corresponding point.
00530     const dimension_type n_rows = gen_sys.num_rows();
00531     const dimension_type n_lines = gen_sys.num_lines();
00532     for (dimension_type i = n_rows; i-- > n_lines; ) {
00533       const Generator& gi = gen_sys[i];
00534       if (gi.is_closure_point()) {
00535         bool gi_has_no_matching_point = true;
00536         for (dimension_type j = n_rows; j-- > n_lines; ) {
00537           const Generator& gj = gen_sys[j];
00538           if (i != j
00539               && gj.is_point()
00540               && gi.is_matching_closure_point(gj)) {
00541             gi_has_no_matching_point = false;
00542             break;
00543           }
00544         }
00545         if (gi_has_no_matching_point)
00546           return false;
00547       }
00548     }
00549     // All closure points are matched.
00550     return true;
00551   }
00552 
00553   // A polyhedron is closed if, after strong minimization
00554   // of its constraint system, it has no strict inequalities.
00555   strongly_minimize_constraints();
00556   return marked_empty() || !con_sys.has_strict_inequalities();
00557 }

bool Parma_Polyhedra_Library::Polyhedron::is_universe (  )  const

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

Definition at line 370 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(), and Parma_Polyhedra_Library::Octagonal_Shape< T >::Octagonal_Shape().

00370                                  {
00371   if (marked_empty())
00372     return false;
00373 
00374   if (space_dim == 0)
00375     return true;
00376 
00377   if (!has_pending_generators() && constraints_are_up_to_date()) {
00378     // Search for a constraint that is not a tautology.
00379     for (dimension_type i = con_sys.num_rows(); i-- > 0; )
00380       if (!con_sys[i].is_tautological())
00381         return false;
00382     // All the constraints are tautologies.
00383     return true;
00384   }
00385 
00386   PPL_ASSERT(!has_pending_constraints() && generators_are_up_to_date());
00387 
00388   // Try a fast-fail test.
00389   dimension_type num_lines = 0;
00390   dimension_type num_rays = 0;
00391   const dimension_type first_pending = gen_sys.first_pending_row();
00392   for (dimension_type i = first_pending; i-- > 0; )
00393     switch (gen_sys[i].type()) {
00394     case Generator::RAY:
00395       ++num_rays;
00396       break;
00397     case Generator::LINE:
00398       ++num_lines;
00399       break;
00400     default:
00401       break;
00402     }
00403 
00404   if (has_pending_generators()) {
00405     // The non-pending part of `gen_sys' was minimized:
00406     // a success-first test is possible in this case.
00407     PPL_ASSERT(generators_are_minimized());
00408     if (num_lines == space_dim) {
00409       PPL_ASSERT(num_rays == 0);
00410       return true;
00411     }
00412     PPL_ASSERT(num_lines < space_dim);
00413     // Now scan the pending generators.
00414     dimension_type num_pending_lines = 0;
00415     dimension_type num_pending_rays = 0;
00416     const dimension_type gs_num_rows = gen_sys.num_rows();
00417     for (dimension_type i = first_pending; i < gs_num_rows; ++i)
00418       switch (gen_sys[i].type()) {
00419       case Generator::RAY:
00420         ++num_pending_rays;
00421         break;
00422       case Generator::LINE:
00423         ++num_pending_lines;
00424         break;
00425       default:
00426         break;
00427       }
00428     // If no pending rays and lines were found,
00429     // then it is not the universe polyhedron.
00430     if (num_pending_rays == 0 && num_pending_lines == 0)
00431       return false;
00432     // Factor away the lines already seen (to be on the safe side,
00433     // we assume they are all linearly independent).
00434     if (num_lines + num_pending_lines < space_dim) {
00435       const dimension_type num_dims_missing
00436         = space_dim - (num_lines + num_pending_lines);
00437       // In order to span an n dimensional space (where n = num_dims_missing),
00438       // at least n+1 rays are needed.
00439       if (num_rays + num_pending_rays <= num_dims_missing)
00440         return false;
00441     }
00442   }
00443   else {
00444     // There is nothing pending.
00445     if (generators_are_minimized()) {
00446       // The exact test is possible.
00447       PPL_ASSERT(num_rays == 0 || num_lines < space_dim);
00448       return num_lines == space_dim;
00449     }
00450     else
00451       // Only the fast-fail test can be computed: in order to span
00452       // an n dimensional space (where n = space_dim - num_lines),
00453       // at least n+1 rays are needed.
00454       if (num_lines < space_dim && num_lines + num_rays <= space_dim)
00455         return false;
00456   }
00457 
00458   // We need the polyhedron in minimal form.
00459   if (has_pending_generators())
00460     process_pending_generators();
00461   else if (!constraints_are_minimized())
00462     minimize();
00463   if (is_necessarily_closed())
00464     return con_sys.num_rows() == 1
00465       && con_sys[0].is_inequality()
00466       && con_sys[0].is_tautological();
00467   else {
00468     // NNC polyhedron.
00469     if (con_sys.num_rows() != 2
00470         || con_sys[0].is_equality()
00471         || con_sys[1].is_equality())
00472       return false;
00473     else {
00474       // If the system of constraints contains two rows that
00475       // are not equalities, we are sure that they are
00476       // epsilon constraints: in this case we know that
00477       // the polyhedron is universe.
00478 #ifndef NDEBUG
00479       obtain_sorted_constraints();
00480       const Constraint& eps_leq_one = con_sys[0];
00481       const Constraint& eps_geq_zero = con_sys[1];
00482       const dimension_type eps_index = con_sys.num_columns() - 1;
00483       PPL_ASSERT(eps_leq_one[0] > 0 && eps_leq_one[eps_index] < 0
00484              && eps_geq_zero[0] == 0 && eps_geq_zero[eps_index] > 0);
00485       for (dimension_type i = 1; i < eps_index; ++i)
00486         PPL_ASSERT(eps_leq_one[i] == 0 && eps_geq_zero[i] == 0);
00487 #endif
00488       return true;
00489     }
00490   }
00491 }

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

Assigns to *this the result of computing the limited extrapolation between *this and y using the BHRZ03-widening operator.

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 763 of file Polyhedron_widenings.cc.

References add_recycled_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().

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

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

Assigns to *this the result of computing the limited extrapolation between *this and y using the H79-widening operator.

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 288 of file Polyhedron_widenings.cc.

References add_recycled_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(), and Parma_Polyhedra_Library::BD_Shape< T >::limited_H79_extrapolation_assign().

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

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 type parameter 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 151 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(), Parma_Polyhedra_Library::Matrix::has_no_rows(), has_pending_constraints(), Parma_Polyhedra_Library::Generator_System::insert(), Parma_Polyhedra_Library::Generator::LINE, marked_empty(), Parma_Polyhedra_Library::not_a_dimension(), 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, swap(), throw_invalid_argument(), topology(), Parma_Polyhedra_Library::Generator::type(), and update_generators().

00151                                                               {
00152   if (space_dim == 0)
00153     return;
00154 
00155   if (pfunc.has_empty_codomain()) {
00156     // All dimensions vanish: the polyhedron becomes zero_dimensional.
00157     if (marked_empty()
00158         || (has_pending_constraints()
00159             && !remove_pending_to_obtain_generators())
00160         || (!generators_are_up_to_date() && !update_generators())) {
00161       // Removing all dimensions from the empty polyhedron.
00162       space_dim = 0;
00163       con_sys.clear();
00164     }
00165     else
00166       // Removing all dimensions from a non-empty polyhedron.
00167       set_zero_dim_univ();
00168 
00169     PPL_ASSERT_HEAVY(OK());
00170     return;
00171   }
00172 
00173   const dimension_type new_space_dimension = pfunc.max_in_codomain() + 1;
00174 
00175   if (new_space_dimension == space_dim) {
00176     // The partial function `pfunc' is indeed total and thus specifies
00177     // a permutation, that is, a renaming of the dimensions.  For
00178     // maximum efficiency, we will simply permute the columns of the
00179     // constraint system and/or the generator system.
00180 
00181     // We first compute suitable permutation cycles for the columns of
00182     // the `con_sys' and `gen_sys' matrices.  We will represent them
00183     // with a linear array, using 0 as a terminator for each cycle
00184     // (notice that the columns with index 0 of `con_sys' and
00185     // `gen_sys' represent the inhomogeneous terms, and thus are
00186     // unaffected by the permutation of dimensions).
00187     // Cycles of length 1 will be omitted so that, in the worst case,
00188     // we will have `space_dim' elements organized in `space_dim/2'
00189     // cycles, which means we will have at most `space_dim/2'
00190     // terminators.
00191     std::vector<dimension_type> cycles;
00192     cycles.reserve(space_dim + space_dim/2);
00193 
00194     // Used to mark elements as soon as they are inserted in a cycle.
00195     std::deque<bool> visited(space_dim);
00196 
00197     for (dimension_type i = space_dim; i-- > 0; ) {
00198       if (!visited[i]) {
00199         dimension_type j = i;
00200         do {
00201           visited[j] = true;
00202           // The following initialization is only to make the compiler happy.
00203           dimension_type k = 0;
00204           if (!pfunc.maps(j, k))
00205             throw_invalid_argument("map_space_dimensions(pfunc)",
00206                                    " pfunc is inconsistent");
00207           if (k == j)
00208             // Cycle of length 1: skip it.
00209             goto skip;
00210 
00211           cycles.push_back(j+1);
00212           // Go along the cycle.
00213           j = k;
00214         } while (!visited[j]);
00215         // End of cycle: mark it.
00216         cycles.push_back(0);
00217       skip:
00218         ;
00219       }
00220     }
00221 
00222     // If `cycles' is empty then `pfunc' is the identity.
00223     if (cycles.empty())
00224       return;
00225 
00226     // Permute all that is up-to-date.  Notice that the contents of
00227     // the saturation matrices is unaffected by the permutation of
00228     // columns: they remain valid, if they were so.
00229     if (constraints_are_up_to_date())
00230       con_sys.permute_columns(cycles);
00231 
00232     if (generators_are_up_to_date())
00233       gen_sys.permute_columns(cycles);
00234 
00235     PPL_ASSERT_HEAVY(OK());
00236     return;
00237   }
00238 
00239   // If control gets here, then `pfunc' is not a permutation and some
00240   // dimensions must be projected away.
00241 
00242   // If there are pending constraints, using `generators()' we process them.
00243   const Generator_System& old_gensys = generators();
00244 
00245   if (old_gensys.has_no_rows()) {
00246     // The polyhedron is empty.
00247     Polyhedron new_polyhedron(topology(), new_space_dimension, EMPTY);
00248     std::swap(*this, new_polyhedron);
00249     PPL_ASSERT_HEAVY(OK());
00250     return;
00251   }
00252 
00253   // Make a local copy of the partial function.
00254   std::vector<dimension_type> pfunc_maps(space_dim, not_a_dimension());
00255   for (dimension_type j = space_dim; j-- > 0; ) {
00256     dimension_type pfunc_j;
00257     if (pfunc.maps(j, pfunc_j))
00258       pfunc_maps[j] = pfunc_j;
00259   }
00260 
00261   Generator_System new_gensys;
00262   for (Generator_System::const_iterator i = old_gensys.begin(),
00263          old_gensys_end = old_gensys.end(); i != old_gensys_end; ++i) {
00264     const Generator& old_g = *i;
00265     Linear_Expression e(0 * Variable(new_space_dimension-1));
00266     bool all_zeroes = true;
00267     for (dimension_type j = space_dim; j-- > 0; ) {
00268       if (old_g.coefficient(Variable(j)) != 0
00269           && pfunc_maps[j] != not_a_dimension()) {
00270         e += Variable(pfunc_maps[j]) * old_g.coefficient(Variable(j));
00271         all_zeroes = false;
00272       }
00273     }
00274     switch (old_g.type()) {
00275     case Generator::LINE:
00276       if (!all_zeroes)
00277         new_gensys.insert(line(e));
00278       break;
00279     case Generator::RAY:
00280       if (!all_zeroes)
00281         new_gensys.insert(ray(e));
00282       break;
00283     case Generator::POINT:
00284       // A point in the origin has all zero homogeneous coefficients.
00285       new_gensys.insert(point(e, old_g.divisor()));
00286       break;
00287     case Generator::CLOSURE_POINT:
00288       // A closure point in the origin has all zero homogeneous coefficients.
00289       new_gensys.insert(closure_point(e, old_g.divisor()));
00290       break;
00291     }
00292   }
00293   Polyhedron new_polyhedron(topology(), new_gensys);
00294   std::swap(*this, new_polyhedron);
00295   PPL_ASSERT_HEAVY(OK(true));
00296 }

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 123 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_space_dimensions_and_embed(), add_space_dimensions_and_project(), affine_image(), affine_preimage(), Parma_Polyhedra_Library::BD_Shape< T >::BD_Shape(), BFT00_poly_hull_assign_if_exact(), Parma_Polyhedra_Library::BHRZ03_Certificate::BHRZ03_Certificate(), BHRZ03_combining_constraints(), BHRZ03_evolving_points(), BHRZ03_evolving_rays(), BHRZ03_widening_assign(), BHZ09_poly_hull_assign_if_exact(), bounded_affine_image(), bounded_affine_preimage(), bounds(), Parma_Polyhedra_Library::Box< ITV >::Box(), Parma_Polyhedra_Library::H79_Certificate::compare(), Parma_Polyhedra_Library::BHRZ03_Certificate::compare(), concatenate_assign(), constrains(), constraints(), contains(), contains_integer_point(), drop_some_non_integer_points(), fold_space_dimensions(), frequency(), generalized_affine_image(), generalized_affine_preimage(), generators(), Parma_Polyhedra_Library::Grid::Grid(), Parma_Polyhedra_Library::H79_Certificate::H79_Certificate(), H79_widening_assign(), intersection_assign(), 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(), Parma_Polyhedra_Library::Octagonal_Shape< T >::Octagonal_Shape(), OK(), operator=(), poly_difference_assign(), poly_hull_assign(), process_pending(), process_pending_constraints(), process_pending_generators(), quick_equivalence_test(), refine_no_check(), refine_with_congruence(), refine_with_constraint(), refine_with_constraints(), relation_with(), remove_higher_space_dimensions(), remove_space_dimensions(), select_CH78_constraints(), select_H79_constraints(), time_elapse_assign(), topological_closure_assign(), unconstrain(), update_constraints(), and update_generators().

00123                                {
00124   return status.test_empty();
00125 }

bool Parma_Polyhedra_Library::Polyhedron::max_min ( const Linear_Expression expr,
bool  maximize,
Coefficient ext_n,
Coefficient ext_d,
bool &  included,
Generator g 
) 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;
g 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 g are left untouched.

Definition at line 556 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(), PPL_DIRTY_TEMP_COEFFICIENT, process_pending_constraints(), space_dim, Parma_Polyhedra_Library::Linear_Expression::space_dimension(), throw_dimension_incompatible(), and update_generators().

Referenced by maximize(), and minimize().

00560                                              {
00561   // The dimension of `expr' should not be greater than the dimension
00562   // of `*this'.
00563   const dimension_type expr_space_dim = expr.space_dimension();
00564   if (space_dim < expr_space_dim)
00565     throw_dimension_incompatible((maximize
00566                                   ? "maximize(e, ...)"
00567                                   : "minimize(e, ...)"), "e", expr);
00568 
00569   // Deal with zero-dim polyhedra first.
00570   if (space_dim == 0) {
00571     if (marked_empty())
00572       return false;
00573     else {
00574       ext_n = expr.inhomogeneous_term();
00575       ext_d = 1;
00576       included = true;
00577       g = point();
00578       return true;
00579     }
00580   }
00581 
00582   // For an empty polyhedron we simply return false.
00583   if (marked_empty()
00584       || (has_pending_constraints() && !process_pending_constraints())
00585       || (!generators_are_up_to_date() && !update_generators()))
00586     return false;
00587 
00588   // The polyhedron has updated, possibly pending generators.
00589   // The following loop will iterate through the generator
00590   // to find the extremum.
00591   PPL_DIRTY_TEMP0(mpq_class, extremum);
00592 
00593   // True if we have no other candidate extremum to compare with.
00594   bool first_candidate = true;
00595 
00596   // To store the position of the current candidate extremum.
00597   PPL_UNINITIALIZED(dimension_type, ext_position);
00598 
00599   // Whether the current candidate extremum is included or not.
00600   PPL_UNINITIALIZED(bool, ext_included);
00601 
00602   PPL_DIRTY_TEMP_COEFFICIENT(sp);
00603   for (dimension_type i = gen_sys.num_rows(); i-- > 0; ) {
00604     const Generator& gen_sys_i = gen_sys[i];
00605     Scalar_Products::homogeneous_assign(sp, expr, gen_sys_i);
00606     // Lines and rays in `*this' can cause `expr' to be unbounded.
00607     if (gen_sys_i.is_line_or_ray()) {
00608       const int sp_sign = sgn(sp);
00609       if (sp_sign != 0
00610           && (gen_sys_i.is_line()
00611               || (maximize && sp_sign > 0)
00612               || (!maximize && sp_sign < 0)))
00613         // `expr' is unbounded in `*this'.
00614         return false;
00615     }
00616     else {
00617       // We have a point or a closure point.
00618       PPL_ASSERT(gen_sys_i.is_point() || gen_sys_i.is_closure_point());
00619       // Notice that we are ignoring the constant term in `expr' here.
00620       // We will add it to the extremum as soon as we find it.
00621       PPL_DIRTY_TEMP0(mpq_class, candidate);
00622       assign_r(candidate.get_num(), sp, ROUND_NOT_NEEDED);
00623       assign_r(candidate.get_den(), gen_sys_i[0], ROUND_NOT_NEEDED);
00624       candidate.canonicalize();
00625       const bool g_is_point = gen_sys_i.is_point();
00626       if (first_candidate
00627           || (maximize
00628               && (candidate > extremum
00629                   || (g_is_point
00630                       && !ext_included
00631                       && candidate == extremum)))
00632           || (!maximize
00633               && (candidate < extremum
00634                   || (g_is_point
00635                       && !ext_included
00636                       && candidate == extremum)))) {
00637         // We have a (new) candidate extremum.
00638         first_candidate = false;
00639         extremum = candidate;
00640         ext_position = i;
00641         ext_included = g_is_point;
00642       }
00643     }
00644   }
00645 
00646   // Add in the constant term in `expr'.
00647   PPL_DIRTY_TEMP0(mpz_class, n);
00648   assign_r(n, expr.inhomogeneous_term(), ROUND_NOT_NEEDED);
00649   extremum += n;
00650 
00651   // The polyhedron is bounded in the right direction and we have
00652   // computed the extremum: write the result into the caller's structures.
00653   PPL_ASSERT(!first_candidate);
00654   // FIXME: avoid these temporaries, if possible.
00655   // This can be done adding an `assign' function working on native
00656   // and checked or an operator= that have on one side a checked and
00657   // on the other a native or checked.
00658   // The reason why now we can't use operator= is the fact that we
00659   // still can have Coefficient defined to mpz_class (and not
00660   // Checked_Number<mpz_class>).
00661   ext_n = Coefficient(extremum.get_num());
00662   ext_d = Coefficient(extremum.get_den());
00663   included = ext_included;
00664   g = gen_sys[ext_position];
00665 
00666   return true;
00667 }

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 50 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().

00050                                 {
00051   using std::min;
00052   // One dimension is reserved to have a value of type dimension_type
00053   // that does not represent a legal dimension.
00054   return min(std::numeric_limits<dimension_type>::max() - 1,
00055              min(Constraint_System::max_space_dimension(),
00056                  Generator_System::max_space_dimension()
00057                  )
00058              );
00059 }

bool Parma_Polyhedra_Library::Polyhedron::maximize ( const Linear_Expression expr,
Coefficient sup_n,
Coefficient sup_d,
bool &  maximum,
Generator g 
) 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;
g 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 g are left untouched.

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

References max_min().

00326                                          {
00327   return max_min(expr, true, sup_n, sup_d, maximum, g);
00328 }

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 316 of file Polyhedron.inlines.hh.

References max_min().

00318                                           {
00319   Generator g(point());
00320   return max_min(expr, true, sup_n, sup_d, maximum, g);
00321 }

bool Parma_Polyhedra_Library::Polyhedron::minimize ( bool  con_to_gen,
Linear_System source,
Linear_System dest,
Bit_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 70 of file minimize.cc.

References conversion(), Parma_Polyhedra_Library::Matrix::has_no_rows(), 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::Bit_Matrix::transpose_assign().

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

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 1039 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_generators(), affine_image(), affine_preimage(), constrains(), generalized_affine_image(), is_empty(), is_universe(), minimized_constraints(), minimized_generators(), OK(), strongly_minimize_constraints(), strongly_minimize_generators(), update_constraints(), and update_generators().

01039                               {
01040   // 0-dim space or empty polyhedra are already minimized.
01041   if (marked_empty())
01042     return false;
01043   if (space_dim == 0)
01044     return true;
01045 
01046   // If the polyhedron has something pending, process it.
01047   if (has_something_pending()) {
01048     const bool not_empty = process_pending();
01049     PPL_ASSERT_HEAVY(OK());
01050     return not_empty;
01051   }
01052 
01053   // Here there are no pending constraints or generators.
01054   // Is the polyhedron already minimized?
01055   if (constraints_are_minimized() && generators_are_minimized())
01056     return true;
01057 
01058   // If constraints or generators are up-to-date, invoking
01059   // update_generators() or update_constraints(), respectively,
01060   // minimizes both constraints and generators.
01061   // If both are up-to-date it does not matter whether we use
01062   // update_generators() or update_constraints():
01063   // both minimize constraints and generators.
01064   if (constraints_are_up_to_date()) {
01065     // We may discover here that `*this' is empty.
01066     const bool ret = update_generators();
01067     PPL_ASSERT_HEAVY(OK());
01068     return ret;
01069   }
01070   else {
01071     PPL_ASSERT(generators_are_up_to_date());
01072     update_constraints();
01073     PPL_ASSERT_HEAVY(OK());
01074     return true;
01075   }
01076 }

bool Parma_Polyhedra_Library::Polyhedron::minimize ( const Linear_Expression expr,
Coefficient inf_n,
Coefficient inf_d,
bool &  minimum,
Generator g 
) 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;
g 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 g are left untouched.

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

References max_min().

00341                                          {
00342   return max_min(expr, false, inf_n, inf_d, minimum, g);
00343 }

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 331 of file Polyhedron.inlines.hh.

References max_min().

Referenced by BFT00_poly_hull_assign_if_exact(), Parma_Polyhedra_Library::BHRZ03_Certificate::BHRZ03_Certificate(), BHRZ03_combining_constraints(), BHRZ03_evolving_points(), BHRZ03_evolving_rays(), BHRZ03_widening_assign(), BHZ09_C_poly_hull_assign_if_exact(), BHZ09_NNC_poly_hull_assign_if_exact(), Parma_Polyhedra_Library::H79_Certificate::compare(), Parma_Polyhedra_Library::BHRZ03_Certificate::compare(), Parma_Polyhedra_Library::Grid::Grid(), Parma_Polyhedra_Library::H79_Certificate::H79_Certificate(), H79_widening_assign(), is_included_in(), limited_BHRZ03_extrapolation_assign(), limited_H79_extrapolation_assign(), poly_difference_assign(), and simplify_using_context_assign().

00333                                           {
00334   Generator g(point());
00335   return max_min(expr, false, inf_n, inf_d, minimum, g);
00336 }

Congruence_System Parma_Polyhedra_Library::Polyhedron::minimized_congruences (  )  const [inline]

Returns a system of (equality) congruences satisfied by *this, with no redundant congruences and having the same affine dimension as *this.

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

References minimized_constraints().

00362                                         {
00363   return Congruence_System(minimized_constraints());
00364 }

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

Returns the system of generators, with no redundant generator.

Definition at line 184 of file Polyhedron_public.cc.

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

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

00184                                           {
00185   // `minimize()' or `strongly_minimize_generators()'
00186   // will process any pending constraints or generators.
00187   if (is_necessarily_closed())
00188     minimize();
00189   else
00190     strongly_minimize_generators();
00191   // Note: calling generators() on a strongly minimized NNC generator
00192   // system will also ensure sortedness, which is required to correctly
00193   // filter away the matched closure points.
00194   return generators();
00195 }

Grid_Generator_System Parma_Polyhedra_Library::Polyhedron::minimized_grid_generators (  )  const [inline]

Returns a universe system of grid generators.

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

References grid_generators().

00367                                             {
00368   return grid_generators();
00369 }

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 914 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::Bit_Matrix::transpose_assign().

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

00914                                                {
00915   PPL_ASSERT(constraints_are_up_to_date());
00916   // `con_sys' will be sorted up to `index_first_pending'.
00917   Polyhedron& x = const_cast<Polyhedron&>(*this);
00918   if (!x.con_sys.is_sorted()) {
00919     if (x.sat_g_is_up_to_date()) {
00920       // Sorting constraints keeping `sat_g' consistent.
00921       x.con_sys.sort_and_remove_with_sat(x.sat_g);
00922       // `sat_c' is not up-to-date anymore.
00923       x.clear_sat_c_up_to_date();
00924     }
00925     else if (x.sat_c_is_up_to_date()) {
00926       // Using `sat_c' to obtain `sat_g', then it is like previous case.
00927       x.sat_g.transpose_assign(x.sat_c);
00928       x.con_sys.sort_and_remove_with_sat(x.sat_g);
00929       x.set_sat_g_up_to_date();
00930       x.clear_sat_c_up_to_date();
00931     }
00932     else
00933       // If neither `sat_g' nor `sat_c' are up-to-date,
00934       // we just sort the constraints.
00935       x.con_sys.sort_rows();
00936   }
00937 
00938   PPL_ASSERT(con_sys.check_sorted());
00939 }

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 970 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::Bit_Matrix::transpose_assign(), and update_sat_c().

Referenced by process_pending_constraints().

00970                                                           {
00971   PPL_ASSERT(constraints_are_up_to_date());
00972   PPL_ASSERT(constraints_are_minimized());
00973   // `con_sys' will be sorted up to `index_first_pending'.
00974   Polyhedron& x = const_cast<Polyhedron&>(*this);
00975   // At least one of the saturation matrices must be up-to-date.
00976   if (!x.sat_c_is_up_to_date() && !x.sat_g_is_up_to_date())
00977     x.update_sat_c();
00978 
00979   if (x.con_sys.is_sorted()) {
00980     if (x.sat_c_is_up_to_date())
00981       // If constraints are already sorted and sat_c is up to
00982       // date there is nothing to do.
00983       return;
00984   }
00985   else {
00986     if (!x.sat_g_is_up_to_date()) {
00987       // If constraints are not sorted and sat_g is not up-to-date
00988       // we obtain sat_g from sat_c (that has to be up-to-date)...
00989       x.sat_g.transpose_assign(x.sat_c);
00990       x.set_sat_g_up_to_date();
00991     }
00992     // ... and sort it together with constraints.
00993     x.con_sys.sort_and_remove_with_sat(x.sat_g);
00994   }
00995   // Obtaining sat_c from sat_g.
00996   x.sat_c.transpose_assign(x.sat_g);
00997   x.set_sat_c_up_to_date();
00998   // Constraints are sorted now.
00999   x.con_sys.set_sorted(true);
01000 
01001   PPL_ASSERT(con_sys.check_sorted());
01002 }

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 942 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::Bit_Matrix::transpose_assign().

Referenced by generators(), and quick_equivalence_test().

00942                                               {
00943   PPL_ASSERT(generators_are_up_to_date());
00944   // `gen_sys' will be sorted up to `index_first_pending'.
00945   Polyhedron& x = const_cast<Polyhedron&>(*this);
00946   if (!x.gen_sys.is_sorted()) {
00947     if (x.sat_c_is_up_to_date()) {
00948       // Sorting generators keeping 'sat_c' consistent.
00949       x.gen_sys.sort_and_remove_with_sat(x.sat_c);
00950       // `sat_g' is not up-to-date anymore.
00951       x.clear_sat_g_up_to_date();
00952     }
00953     else if (x.sat_g_is_up_to_date()) {
00954       // Obtaining `sat_c' from `sat_g' and proceeding like previous case.
00955       x.sat_c.transpose_assign(x.sat_g);
00956       x.gen_sys.sort_and_remove_with_sat(x.sat_c);
00957       x.set_sat_c_up_to_date();
00958       x.clear_sat_g_up_to_date();
00959     }
00960     else
00961       // If neither `sat_g' nor `sat_c' are up-to-date, we just sort
00962       // the generators.
00963       x.gen_sys.sort_rows();
00964   }
00965 
00966   PPL_ASSERT(gen_sys.check_sorted());
00967 }

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 1005 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::Bit_Matrix::transpose_assign(), and update_sat_g().

Referenced by process_pending_generators().

01005                                                          {
01006   PPL_ASSERT(generators_are_up_to_date());
01007   // `gen_sys' will be sorted up to `index_first_pending'.
01008   Polyhedron& x = const_cast<Polyhedron&>(*this);
01009   // At least one of the saturation matrices must be up-to-date.
01010   if (!x.sat_c_is_up_to_date() && !x.sat_g_is_up_to_date())
01011     x.update_sat_g();
01012 
01013   if (x.gen_sys.is_sorted()) {
01014     if (x.sat_g_is_up_to_date())
01015       // If generators are already sorted and sat_g is up to
01016       // date there is nothing to do.
01017       return;
01018   }
01019   else {
01020     if (!x.sat_c_is_up_to_date()) {
01021       // If generators are not sorted and sat_c is not up-to-date
01022       // we obtain sat_c from sat_g (that has to be up-to-date)...
01023       x.sat_c.transpose_assign(x.sat_g);
01024       x.set_sat_c_up_to_date();
01025     }
01026     // ... and sort it together with generators.
01027     x.gen_sys.sort_and_remove_with_sat(x.sat_c);
01028   }
01029   // Obtaining sat_g from sat_c.
01030   x.sat_g.transpose_assign(sat_c);
01031   x.set_sat_g_up_to_date();
01032   // Generators are sorted now.
01033   x.gen_sys.set_sorted(true);
01034 
01035   PPL_ASSERT(gen_sys.check_sorted());
01036 }

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 779 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(), Parma_Polyhedra_Library::Matrix::has_no_rows(), 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::Bit_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::Bit_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::Bit_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_generator(), add_recycled_constraints(), add_recycled_generators(), add_space_dimensions_and_embed(), add_space_dimensions_and_project(), affine_image(), affine_preimage(), Parma_Polyhedra_Library::Polyhedron::Status::ascii_load(), BFT00_poly_hull_assign_if_exact(), BHRZ03_combining_constraints(), BHRZ03_evolving_points(), BHRZ03_evolving_rays(), BHRZ03_widening_assign(), BHZ09_C_poly_hull_assign_if_exact(), bounded_affine_image(), bounded_affine_preimage(), Parma_Polyhedra_Library::C_Polyhedron::C_Polyhedron(), concatenate_assign(), drop_some_non_integer_points(), expand_space_dimension(), fold_space_dimensions(), generalized_affine_image(), generalized_affine_preimage(), H79_widening_assign(), intersection_assign(), 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(), Polyhedron(), process_pending_constraints(), process_pending_generators(), refine_no_check(), refine_with_constraints(), remove_higher_space_dimensions(), remove_pending_to_obtain_constraints(), remove_pending_to_obtain_generators(), remove_space_dimensions(), simplify_using_context_assign(), strongly_minimize_constraints(), strongly_minimize_generators(), time_elapse_assign(), topological_closure_assign(), and unconstrain().

00779                                             {
00780 #ifndef NDEBUG
00781   using std::endl;
00782   using std::cerr;
00783 #endif
00784 
00785   // The expected number of columns in the constraint and generator
00786   // systems, if they are not empty.
00787   const dimension_type poly_num_columns
00788     = space_dim + (is_necessarily_closed() ? 1 : 2);
00789 
00790   // Check whether the topologies of `con_sys' and `gen_sys' agree.
00791   if (con_sys.topology() != gen_sys.topology()) {
00792 #ifndef NDEBUG
00793     cerr << "Constraints and generators have different topologies!"
00794          << endl;
00795 #endif
00796     goto bomb;
00797   }
00798 
00799   // Check whether the saturation matrices are well-formed.
00800   if (!sat_c.OK())
00801     goto bomb;
00802   if (!sat_g.OK())
00803     goto bomb;
00804 
00805   // Check whether the status information is legal.
00806   if (!status.OK())
00807     goto bomb;
00808 
00809   if (marked_empty()) {
00810     if (check_not_empty) {
00811       // The caller does not want the polyhedron to be empty.
00812 #ifndef NDEBUG
00813       cerr << "Empty polyhedron!" << endl;
00814 #endif
00815       goto bomb;
00816     }
00817 
00818     // An empty polyhedron is allowed if the system of constraints
00819     // either has no rows or only contains an unsatisfiable constraint
00820     // and if it has no pending constraints or generators.
00821     if (has_something_pending()) {
00822 #ifndef NDEBUG
00823       cerr << "The polyhedron is empty, "
00824            << "but it has something pending" << endl;
00825 #endif
00826       goto bomb;
00827     }
00828     if (con_sys.has_no_rows())
00829       return true;
00830     else {
00831       if (con_sys.space_dimension() != space_dim) {
00832 #ifndef NDEBUG
00833         cerr << "The polyhedron is in a space of dimension "
00834              << space_dim
00835              << " while the system of constraints is in a space of dimension "
00836              << con_sys.space_dimension()
00837              << endl;
00838 #endif
00839         goto bomb;
00840       }
00841       if (con_sys.num_rows() != 1) {
00842 #ifndef NDEBUG
00843         cerr << "The system of constraints for an empty polyhedron "
00844              << "has more then one row"
00845              << endl;
00846 #endif
00847         goto bomb;
00848       }
00849       if (!con_sys[0].is_inconsistent()) {
00850 #ifndef NDEBUG
00851         cerr << "Empty polyhedron with a satisfiable system of constraints"
00852              << endl;
00853 #endif
00854         goto bomb;
00855       }
00856       // Here we have only one, inconsistent constraint.
00857       return true;
00858     }
00859   }
00860 
00861   // A zero-dimensional, non-empty polyhedron is legal only if the
00862   // system of constraint `con_sys' and the system of generators
00863   // `gen_sys' have no rows.
00864   if (space_dim == 0) {
00865     if (has_something_pending()) {
00866 #ifndef NDEBUG
00867       cerr << "Zero-dimensional polyhedron with something pending"
00868            << endl;
00869 #endif
00870       goto bomb;
00871     }
00872     if (!con_sys.has_no_rows() || !gen_sys.has_no_rows()) {
00873 #ifndef NDEBUG
00874       cerr << "Zero-dimensional polyhedron with a non-empty"
00875            << endl
00876            << "system of constraints or generators."
00877            << endl;
00878 #endif
00879       goto bomb;
00880     }
00881     return true;
00882   }
00883 
00884   // A polyhedron is defined by a system of constraints
00885   // or a system of generators: at least one of them must be up to date.
00886   if (!constraints_are_up_to_date() && !generators_are_up_to_date()) {
00887 #ifndef NDEBUG
00888     cerr << "Polyhedron not empty, not zero-dimensional"
00889          << endl
00890          << "and with neither constraints nor generators up-to-date!"
00891          << endl;
00892 #endif
00893     goto bomb;
00894   }
00895 
00896   // Here we check if the size of the matrices is consistent.
00897   // Let us suppose that all the matrices are up-to-date; this means:
00898   // `con_sys' : number of constraints x poly_num_columns
00899   // `gen_sys' : number of generators  x poly_num_columns
00900   // `sat_c'   : number of generators  x number of constraints
00901   // `sat_g'   : number of constraints x number of generators.
00902   if (constraints_are_up_to_date()) {
00903     if (con_sys.num_columns() != poly_num_columns) {
00904 #ifndef NDEBUG
00905       cerr << "Incompatible size! (con_sys and space_dim)"
00906            << endl;
00907 #endif
00908       goto bomb;
00909     }
00910     if (sat_c_is_up_to_date())
00911       if (con_sys.first_pending_row() != sat_c.num_columns()) {
00912 #ifndef NDEBUG
00913         cerr << "Incompatible size! (con_sys and sat_c)"
00914              << endl;
00915 #endif
00916         goto bomb;
00917       }
00918     if (sat_g_is_up_to_date())
00919       if (con_sys.first_pending_row() != sat_g.num_rows()) {
00920 #ifndef NDEBUG
00921         cerr << "Incompatible size! (con_sys and sat_g)"
00922              << endl;
00923 #endif
00924         goto bomb;
00925       }
00926     if (generators_are_up_to_date())
00927       if (con_sys.num_columns() != gen_sys.num_columns()) {
00928 #ifndef NDEBUG
00929         cerr << "Incompatible size! (con_sys and gen_sys)"
00930              << endl;
00931 #endif
00932         goto bomb;
00933       }
00934   }
00935 
00936   if (generators_are_up_to_date()) {
00937     if (gen_sys.num_columns() != poly_num_columns) {
00938 #ifndef NDEBUG
00939       cerr << "Incompatible size! (gen_sys and space_dim)"
00940            << endl;
00941 #endif
00942       goto bomb;
00943     }
00944     if (sat_c_is_up_to_date())
00945       if (gen_sys.first_pending_row() != sat_c.num_rows()) {
00946 #ifndef NDEBUG
00947         cerr << "Incompatible size! (gen_sys and sat_c)"
00948              << endl;
00949 #endif
00950         goto bomb;
00951       }
00952     if (sat_g_is_up_to_date())
00953       if (gen_sys.first_pending_row() != sat_g.num_columns()) {
00954 #ifndef NDEBUG
00955         cerr << "Incompatible size! (gen_sys and sat_g)"
00956              << endl;
00957 #endif
00958         goto bomb;
00959       }
00960 
00961     // Check if the system of generators is well-formed.
00962     if (!gen_sys.OK())
00963       goto bomb;
00964 
00965     if (gen_sys.first_pending_row() == 0) {
00966 #ifndef NDEBUG
00967       cerr << "Up-to-date generator system with all rows pending!"
00968            << endl;
00969 #endif
00970       goto bomb;
00971     }
00972 
00973     // A non-empty system of generators describing a polyhedron
00974     // is valid if and only if it contains a point.
00975     if (!gen_sys.has_no_rows() && !gen_sys.has_points()) {
00976 #ifndef NDEBUG
00977       cerr << "Non-empty generator system declared up-to-date "
00978            << "has no points!"
00979            << endl;
00980 #endif
00981       goto bomb;
00982     }
00983 
00984 #if 0 // To be activated when Status keeps strong minimization flags.
00985     //=================================================
00986     // TODO: this test is wrong in the general case.
00987     // However, such an invariant does hold for a
00988     // strongly-minimized Generator_System.
00989     // We will activate this test as soon as the Status
00990     // flags will be able to remember if a system is
00991     // strongly minimized.
00992 
00993     // Checking that the number of closure points is always
00994     // greater than the number of points.
00995     if (!is_necessarily_closed()) {
00996       dimension_type num_points = 0;
00997       dimension_type num_closure_points = 0;
00998       dimension_type eps_index = gen_sys.num_columns() - 1;
00999       for (dimension_type i = gen_sys.num_rows(); i-- > 0; )
01000         if (!gen_sys[i].is_line_or_ray())
01001           if (gen_sys[i][eps_index] > 0)
01002             ++num_points;
01003           else
01004             ++num_closure_points;
01005       if (num_points > num_closure_points) {
01006 #ifndef NDEBUG
01007         cerr << "# POINTS > # CLOSURE_POINTS" << endl;
01008 #endif
01009         goto bomb;
01010       }
01011     }
01012     //=================================================
01013 #endif
01014 
01015     if (generators_are_minimized()) {
01016       // If the system of generators is minimized, the number of
01017       // lines, rays and points of the polyhedron must be the same as
01018       // of a temporary, minimized one. If this does not happen then
01019       // the polyhedron is not OK.
01020       Constraint_System new_con_sys(topology());
01021       Generator_System gs_without_pending = gen_sys;
01022       gs_without_pending.erase_to_end(gen_sys.first_pending_row());
01023       gs_without_pending.unset_pending_rows();
01024       Generator_System copy_of_gen_sys = gs_without_pending;
01025       Bit_Matrix new_sat_c;
01026       minimize(false, copy_of_gen_sys, new_con_sys, new_sat_c);
01027       const dimension_type copy_num_lines = copy_of_gen_sys.num_lines();
01028       if (gs_without_pending.num_rows() != copy_of_gen_sys.num_rows()
01029           || gs_without_pending.num_lines() != copy_num_lines
01030           || gs_without_pending.num_rays() != copy_of_gen_sys.num_rays()) {
01031 #ifndef NDEBUG
01032         cerr << "Generators are declared minimized, but they are not!\n"
01033              << "Here is the minimized form of the generators:\n";
01034         copy_of_gen_sys.ascii_dump(cerr);
01035         cerr << endl;
01036 #endif
01037         goto bomb;
01038       }
01039 
01040       // CHECKME : the following observation is not formally true
01041       //           for a NNC_Polyhedron. But it may be true for its
01042       //           representation ...
01043 
01044       // If the corresponding polyhedral cone is _pointed_, then
01045       // a minimal system of generators is unique up to positive scaling.
01046       // We thus verify if the cone is pointed (i.e., there are no lines)
01047       // and, after normalizing and sorting a copy of the system `gen_sys'
01048       // of the polyhedron (we use a copy not to modify the polyhedron's
01049       // system) and the system `copy_of_gen_sys' that has been just
01050       // minimized, we check if the two matrices are identical.  If
01051       // they are different it means that the generators of the
01052       // polyhedron are declared minimized, but they are not.
01053       if (copy_num_lines == 0) {
01054         copy_of_gen_sys.strong_normalize();
01055         copy_of_gen_sys.sort_rows();
01056         gs_without_pending.strong_normalize();
01057         gs_without_pending.sort_rows();
01058         if (copy_of_gen_sys != gs_without_pending) {
01059 #ifndef NDEBUG
01060           cerr << "Generators are declared minimized, but they are not!\n"
01061                << "(we are in the case:\n"
01062                << "dimension of lineality space equal to 0)\n"
01063                << "Here is the minimized form of the generators:\n";
01064           copy_of_gen_sys.ascii_dump(cerr);
01065           cerr << endl;
01066 #endif
01067             goto bomb;
01068         }
01069       }
01070     }
01071   }
01072 
01073   if (constraints_are_up_to_date()) {
01074     // Check if the system of constraints is well-formed.
01075     if (!con_sys.OK())
01076       goto bomb;
01077 
01078     if (con_sys.first_pending_row() == 0) {
01079 #ifndef NDEBUG
01080       cerr << "Up-to-date constraint system with all rows pending!"
01081            << endl;
01082 #endif
01083       goto bomb;
01084     }
01085 
01086     // A non-empty system of constraints describing a polyhedron
01087     // must contain a constraint with a non-zero inhomogeneous term;
01088     // such a constraint corresponds to (a combination of other
01089     // constraints with):
01090     // -* the positivity constraint, for necessarily closed polyhedra;
01091     // -* the epsilon <= 1 constraint, for NNC polyhedra.
01092     bool no_positivity_constraint = true;
01093     for (dimension_type i = con_sys.num_rows(); i-- > 0; )
01094       if (con_sys[i].inhomogeneous_term() != 0) {
01095         no_positivity_constraint = false;
01096         break;
01097       }
01098     if (no_positivity_constraint) {
01099 #ifndef NDEBUG
01100       cerr << "Non-empty constraint system has no positivity constraint"
01101            << endl;
01102 #endif
01103       goto bomb;
01104     }
01105 
01106     if (!is_necessarily_closed()) {
01107       // A non-empty system of constraints describing a NNC polyhedron
01108       // must also contain a (combination of) the constraint epsilon >= 0,
01109       // i.e., a constraint with a positive epsilon coefficient.
01110       bool no_epsilon_geq_zero = true;
01111       const dimension_type eps_index = con_sys.num_columns() - 1;
01112       for (dimension_type i = con_sys.num_rows(); i-- > 0; )
01113         if (con_sys[i][eps_index] > 0) {
01114           no_epsilon_geq_zero = false;
01115           break;
01116         }
01117       if (no_epsilon_geq_zero) {
01118 #ifndef NDEBUG
01119         cerr << "Non-empty constraint system for NNC polyhedron "
01120              << "has no epsilon >= 0 constraint"
01121              << endl;
01122 #endif
01123         goto bomb;
01124       }
01125     }
01126 
01127     Constraint_System cs_without_pending = con_sys;
01128     cs_without_pending.erase_to_end(con_sys.first_pending_row());
01129     cs_without_pending.unset_pending_rows();
01130     Constraint_System copy_of_con_sys = cs_without_pending;
01131     bool empty = false;
01132     if (check_not_empty || constraints_are_minimized()) {
01133       Generator_System new_gen_sys(topology());
01134       Bit_Matrix new_sat_g;
01135       empty = minimize(true, copy_of_con_sys, new_gen_sys, new_sat_g);
01136     }
01137 
01138     if (empty && check_not_empty) {
01139 #ifndef NDEBUG
01140       cerr << "Unsatisfiable system of constraints!"
01141            << endl;
01142 #endif
01143       goto bomb;
01144     }
01145 
01146     if (constraints_are_minimized()) {
01147       // If the constraints are minimized, the number of equalities
01148       // and of inequalities of the system of the polyhedron must be
01149       // the same of the temporary minimized one.
01150       // If it does not happen, the polyhedron is not OK.
01151       if (cs_without_pending.num_rows() != copy_of_con_sys.num_rows()
01152           || cs_without_pending.num_equalities()
01153           != copy_of_con_sys.num_equalities()) {
01154 #ifndef NDEBUG
01155         cerr << "Constraints are declared minimized, but they are not!\n"
01156              << "Here is the minimized form of the constraints:\n";
01157         copy_of_con_sys.ascii_dump(cerr);
01158         cerr << endl;
01159 #endif
01160         goto bomb;
01161       }
01162       // The system `copy_of_con_sys' has the form that is obtained
01163       // after applying methods gauss() and back_substitute().
01164       // A system of constraints can be minimal even if it does not
01165       // have this form. So, to verify if the polyhedron is correct,
01166       // we copy the system `con_sys' in a temporary one and then
01167       // modify it using method simplify() (which calls both gauss()
01168       // and back_substitute()).
01169       // If the temporary system and `copy_of_con_sys' are different,
01170       // the polyhedron is not OK.
01171       copy_of_con_sys.strong_normalize();
01172       copy_of_con_sys.sort_rows();
01173       cs_without_pending.simplify();
01174       cs_without_pending.strong_normalize();
01175       cs_without_pending.sort_rows();
01176       if (cs_without_pending != copy_of_con_sys) {
01177 #ifndef NDEBUG
01178         cerr << "Constraints are declared minimized, but they are not!\n"
01179              << "Here is the minimized form of the constraints:\n";
01180         copy_of_con_sys.ascii_dump(cerr);
01181         cerr << endl;
01182 #endif
01183         goto bomb;
01184       }
01185     }
01186   }
01187 
01188   if (sat_c_is_up_to_date())
01189     for (dimension_type i = sat_c.num_rows(); i-- > 0; ) {
01190       const Generator tmp_gen = gen_sys[i];
01191       const Bit_Row tmp_sat = sat_c[i];
01192       for (dimension_type j = sat_c.num_columns(); j-- > 0; )
01193         if (Scalar_Products::sign(con_sys[j], tmp_gen) != tmp_sat[j]) {
01194 #ifndef NDEBUG
01195           cerr << "sat_c is declared up-to-date, but it is not!"
01196                << endl;
01197 #endif
01198           goto bomb;
01199         }
01200     }
01201 
01202   if (sat_g_is_up_to_date())
01203     for (dimension_type i = sat_g.num_rows(); i-- > 0; ) {
01204       const Constraint tmp_con = con_sys[i];
01205       const Bit_Row tmp_sat = sat_g[i];
01206       for (dimension_type j = sat_g.num_columns(); j-- > 0; )
01207         if (Scalar_Products::sign(tmp_con, gen_sys[j]) != tmp_sat[j]) {
01208 #ifndef NDEBUG
01209           cerr << "sat_g is declared up-to-date, but it is not!"
01210                << endl;
01211 #endif
01212           goto bomb;
01213         }
01214     }
01215 
01216   if (has_pending_constraints()) {
01217     if (con_sys.num_pending_rows() == 0) {
01218 #ifndef NDEBUG
01219       cerr << "The polyhedron is declared to have pending constraints, "
01220            << "but con_sys has no pending rows!"
01221            << endl;
01222 #endif
01223       goto bomb;
01224     }
01225   }
01226 
01227   if (has_pending_generators()) {
01228     if (gen_sys.num_pending_rows() == 0) {
01229 #ifndef NDEBUG
01230       cerr << "The polyhedron is declared to have pending generators, "
01231            << "but gen_sys has no pending rows!"
01232            << endl;
01233 #endif
01234       goto bomb;
01235     }
01236   }
01237 
01238   return true;
01239 
01240  bomb:
01241 #ifndef NDEBUG
01242   cerr << "Here is the guilty polyhedron:"
01243        << endl;
01244   ascii_dump(cerr);
01245 #endif
01246   return false;
01247 }

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

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

Definition at line 311 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().

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

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

Assigns to *this the poly-difference of *this and y.

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

Definition at line 2469 of file Polyhedron_public.cc.

References 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(), refine_no_check(), 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().

02469                                                          {
02470   Polyhedron& x = *this;
02471   // Topology compatibility check.
02472   if (x.topology() != y.topology())
02473     throw_topology_incompatible("poly_difference_assign(y)", "y", y);
02474   // Dimension-compatibility check.
02475   if (x.space_dim != y.space_dim)
02476     throw_dimension_incompatible("poly_difference_assign(y)", "y", y);
02477 
02478   // The difference of a polyhedron `p' and an empty polyhedron is `p'.
02479   if (y.marked_empty())
02480     return;
02481   // The difference of an empty polyhedron and of a polyhedron `p' is empty.
02482   if (x.marked_empty())
02483     return;
02484 
02485   // If both polyhedra are zero-dimensional,
02486   // then at this point they are necessarily universe polyhedra,
02487   // so that their difference is empty.
02488   if (x.space_dim == 0) {
02489     x.set_empty();
02490     return;
02491   }
02492 
02493   // TODO: This is just an executable specification.
02494   //       Have to find a more efficient method.
02495 
02496   if (y.contains(x)) {
02497     x.set_empty();
02498     return;
02499   }
02500 
02501   // Being lazy here is only harmful.
02502   // `minimize()' will process any pending constraints or generators.
02503   if (!y.minimize())
02504     return;
02505   x.minimize();
02506 
02507   Polyhedron new_polyhedron(topology(), x.space_dim, EMPTY);
02508 
02509   const Constraint_System& y_cs = y.constraints();
02510   for (Constraint_System::const_iterator i = y_cs.begin(),
02511          y_cs_end = y_cs.end(); i != y_cs_end; ++i) {
02512     const Constraint& c = *i;
02513     PPL_ASSERT(!c.is_tautological());
02514     PPL_ASSERT(!c.is_inconsistent());
02515     // If the polyhedron `x' is included in the polyhedron defined by
02516     // `c', then `c' can be skipped, as adding its complement to `x'
02517     // would result in the empty polyhedron.  Moreover, if we operate
02518     // on C-polyhedra and `c' is a non-strict inequality, c _must_ be
02519     // skipped for otherwise we would obtain a result that is less
02520     // precise than the poly-difference.
02521     if (x.relation_with(c).implies(Poly_Con_Relation::is_included()))
02522       continue;
02523     Polyhedron z = x;
02524     const Linear_Expression e = Linear_Expression(c);
02525     switch (c.type()) {
02526     case Constraint::NONSTRICT_INEQUALITY:
02527       if (is_necessarily_closed())
02528         z.refine_no_check(e <= 0);
02529       else
02530         z.refine_no_check(e < 0);
02531       break;
02532     case Constraint::STRICT_INEQUALITY:
02533       z.refine_no_check(e <= 0);
02534       break;
02535     case Constraint::EQUALITY:
02536       if (is_necessarily_closed())
02537         // We have already filtered out the case
02538         // when `x' is included in `y': the result is `x'.
02539         return;
02540       else {
02541         Polyhedron w = x;
02542         w.refine_no_check(e < 0);
02543         new_polyhedron.poly_hull_assign(w);
02544         z.refine_no_check(e > 0);
02545       }
02546       break;
02547     }
02548     new_polyhedron.poly_hull_assign(z);
02549   }
02550   *this = new_polyhedron;
02551 
02552   PPL_ASSERT_HEAVY(OK());
02553 }

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

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

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

Definition at line 2403 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 Parma_Polyhedra_Library::Pointset_Powerset< PSET >::affine_dimension(), fold_space_dimensions(), poly_difference_assign(), and upper_bound_assign().

02403                                                    {
02404   Polyhedron& x = *this;
02405   // Topology compatibility check.
02406   if (x.topology() != y.topology())
02407     throw_topology_incompatible("poly_hull_assign(y)", "y", y);
02408   // Dimension-compatibility check.
02409   if (x.space_dim != y.space_dim)
02410     throw_dimension_incompatible("poly_hull_assign(y)", "y", y);
02411 
02412   // The poly-hull of a polyhedron `p' with an empty polyhedron is `p'.
02413   if (y.marked_empty())
02414     return;
02415   if (x.marked_empty()) {
02416     x = y;
02417     return;
02418   }
02419 
02420   // If both polyhedra are zero-dimensional,
02421   // then at this point they are necessarily universe polyhedra,
02422   // so that their poly-hull is the universe polyhedron too.
02423   if (x.space_dim == 0)
02424     return;
02425 
02426   // Both systems of generators have to be up-to-date,
02427   // possibly having pending generators.
02428   if ((x.has_pending_constraints() && !x.process_pending_constraints())
02429       || (!x.generators_are_up_to_date() && !x.update_generators())) {
02430     // Discovered `x' empty when updating generators.
02431     x = y;
02432     return;
02433   }
02434   if ((y.has_pending_constraints() && !y.process_pending_constraints())
02435       || (!y.generators_are_up_to_date() && !y.update_generators()))
02436     // Discovered `y' empty when updating generators.
02437     return;
02438 
02439   // Here both systems are up-to-date and possibly have pending generators
02440   // (but they cannot have pending constraints).
02441   PPL_ASSERT(!x.has_pending_constraints() && x.generators_are_up_to_date());
02442   PPL_ASSERT(!y.has_pending_constraints() && y.generators_are_up_to_date());
02443 
02444   // If `x' can support pending generators,
02445   // the generators of `y' are added as pending generators of `x'.
02446   if (x.can_have_something_pending()) {
02447     x.gen_sys.add_pending_rows(y.gen_sys);
02448     x.set_generators_pending();
02449   }
02450   else {
02451     // `x' cannot support pending generators.
02452     // If both generator systems are (fully) sorted, then we can merge
02453     // them; otherwise we simply add the second to the first.
02454     if (x.gen_sys.is_sorted()
02455         && y.gen_sys.is_sorted() && !y.has_pending_generators())
02456       x.gen_sys.merge_rows_assign(y.gen_sys);
02457     else
02458       x.gen_sys.add_rows(y.gen_sys);
02459     // Constraints are no longer up-to-date
02460     // and generators are no longer minimized.
02461     x.clear_constraints_up_to_date();
02462     x.clear_generators_minimized();
02463   }
02464   // At this point both `x' and `y' are not empty.
02465   PPL_ASSERT_HEAVY(x.OK(true) && y.OK(true));
02466 }

void Parma_Polyhedra_Library::Polyhedron::print (  )  const

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

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 291 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 contains_integer_point(), is_topologically_closed(), and minimize().

00291                                   {
00292   PPL_ASSERT(space_dim > 0 && !marked_empty());
00293   PPL_ASSERT(has_something_pending());
00294 
00295   Polyhedron& x = const_cast<Polyhedron&>(*this);
00296 
00297   if (x.has_pending_constraints())
00298     return x.process_pending_constraints();
00299 
00300   PPL_ASSERT(x.has_pending_generators());
00301   x.process_pending_generators();
00302   return true;
00303 }

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 688 of file Polyhedron_nonpublic.cc.

References add_and_minimize(), clear_pending_constraints(), clear_sat_g_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_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::Bit_Matrix::transpose_assign().

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

00688                                                  {
00689   PPL_ASSERT(space_dim > 0 && !marked_empty());
00690   PPL_ASSERT(has_pending_constraints() && !has_pending_generators());
00691 
00692   Polyhedron& x = const_cast<Polyhedron&>(*this);
00693 
00694   // Integrate the pending part of the system of constraints and minimize.
00695   // We need `sat_c' up-to-date and `con_sys' sorted (together with `sat_c').
00696   if (!x.sat_c_is_up_to_date())
00697     x.sat_c.transpose_assign(x.sat_g);
00698   if (!x.con_sys.is_sorted())
00699     x.obtain_sorted_constraints_with_sat_c();
00700   // We sort in place the pending constraints, erasing those constraints
00701   // that also occur in the non-pending part of `con_sys'.
00702   x.con_sys.sort_pending_and_remove_duplicates();
00703   if (x.con_sys.num_pending_rows() == 0) {
00704     // All pending constraints were duplicates.
00705     x.clear_pending_constraints();
00706     PPL_ASSERT_HEAVY(OK(true));
00707     return true;
00708   }
00709 
00710   const bool empty = add_and_minimize(true, x.con_sys, x.gen_sys, x.sat_c);
00711   PPL_ASSERT(x.con_sys.num_pending_rows() == 0);
00712 
00713   if (empty)
00714     x.set_empty();
00715   else {
00716     x.clear_pending_constraints();
00717     x.clear_sat_g_up_to_date();
00718     x.set_sat_c_up_to_date();
00719   }
00720   PPL_ASSERT_HEAVY(OK(!empty));
00721   return !empty;
00722 }

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 725 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::Bit_Matrix::transpose_assign().

Referenced by add_recycled_constraints(), concatenate_assign(), constrains(), constraints(), drop_some_non_integer_points(), H79_widening_assign(), intersection_assign(), is_included_in(), is_universe(), process_pending(), refine_no_check(), refine_with_constraints(), relation_with(), and remove_pending_to_obtain_constraints().

00725                                                 {
00726   PPL_ASSERT(space_dim > 0 && !marked_empty());
00727   PPL_ASSERT(has_pending_generators() && !has_pending_constraints());
00728 
00729   Polyhedron& x = const_cast<Polyhedron&>(*this);
00730 
00731   // Integrate the pending part of the system of generators and minimize.
00732   // We need `sat_g' up-to-date and `gen_sys' sorted (together with `sat_g').
00733   if (!x.sat_g_is_up_to_date())
00734     x.sat_g.transpose_assign(x.sat_c);
00735   if (!x.gen_sys.is_sorted())
00736     x.obtain_sorted_generators_with_sat_g();
00737   // We sort in place the pending generators, erasing those generators
00738   // that also occur in the non-pending part of `gen_sys'.
00739   x.gen_sys.sort_pending_and_remove_duplicates();
00740   if (x.gen_sys.num_pending_rows() == 0) {
00741     // All pending generators were duplicates.
00742     x.clear_pending_generators();
00743     PPL_ASSERT_HEAVY(OK(true));
00744     return;
00745   }
00746 
00747   add_and_minimize(false, x.gen_sys, x.con_sys, x.sat_g);
00748   PPL_ASSERT(x.gen_sys.num_pending_rows() == 0);
00749 
00750   x.clear_pending_generators();
00751   x.clear_sat_c_up_to_date();
00752   x.set_sat_g_up_to_date();
00753 }

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 334 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().

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

void Parma_Polyhedra_Library::Polyhedron::refine_no_check ( const Constraint c  )  [private]

Uses a copy of constraint c to refine the system of constraints of *this.

Parameters:
c The constraint to be added. If it is dimension-incompatible with *this, the behavior is undefined.

Definition at line 1355 of file Polyhedron_nonpublic.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::Constraint::is_inconsistent(), is_necessarily_closed(), Parma_Polyhedra_Library::Linear_Row::is_necessarily_closed(), marked_empty(), OK(), process_pending_generators(), set_constraints_pending(), set_empty(), space_dim, Parma_Polyhedra_Library::Constraint::space_dimension(), and update_constraints().

Referenced by add_congruence(), add_constraint(), bounded_affine_image(), bounded_affine_preimage(), generalized_affine_image(), generalized_affine_preimage(), poly_difference_assign(), refine_with_congruence(), and refine_with_constraint().

01355                                                   {
01356   PPL_ASSERT(!marked_empty());
01357   PPL_ASSERT(space_dim >= c.space_dimension());
01358 
01359   // Dealing with a zero-dimensional space polyhedron first.
01360   if (space_dim == 0) {
01361     if (c.is_inconsistent())
01362       set_empty();
01363     return;
01364   }
01365 
01366   // The constraints (possibly with pending rows) are required.
01367   if (has_pending_generators())
01368     process_pending_generators();
01369   else if (!constraints_are_up_to_date())
01370     update_constraints();
01371 
01372   const bool adding_pending = can_have_something_pending();
01373 
01374   if (c.is_necessarily_closed() || !is_necessarily_closed())
01375     // Since `con_sys' is not empty, the topology and space dimension
01376     // of the inserted constraint are automatically adjusted.
01377     if (adding_pending)
01378       con_sys.insert_pending(c);
01379     else
01380       con_sys.insert(c);
01381   else {
01382     // Here we know that the system of constraints has at least a row.
01383     // However, by barely invoking `con_sys.insert(c)' we would
01384     // cause a change in the topology of `con_sys', which is wrong.
01385     // Thus, we insert a "topology corrected" copy of `c'.
01386     Linear_Expression nc_expr = Linear_Expression(c);
01387     if (c.is_equality())
01388       if (adding_pending)
01389         con_sys.insert_pending(nc_expr == 0);
01390       else
01391         con_sys.insert(nc_expr == 0);
01392     else
01393       if (adding_pending)
01394         con_sys.insert_pending(nc_expr >= 0);
01395       else
01396         con_sys.insert(nc_expr >= 0);
01397   }
01398 
01399   if (adding_pending)
01400     set_constraints_pending();
01401   else {
01402     // Constraints are not minimized and generators are not up-to-date.
01403     clear_constraints_minimized();
01404     clear_generators_up_to_date();
01405   }
01406 
01407   // Note: the constraint system may have become unsatisfiable, thus
01408   // we do not check for satisfiability.
01409   PPL_ASSERT_HEAVY(OK());
01410 }

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

Uses a copy of congruence cg to refine *this.

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

Definition at line 1693 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::Constraint::EQUALITY, Parma_Polyhedra_Library::Congruence::is_equality(), Parma_Polyhedra_Library::Congruence::is_tautological(), Parma_Polyhedra_Library::Checked::le, marked_empty(), Parma_Polyhedra_Library::NECESSARILY_CLOSED, refine_no_check(), set_empty(), space_dim, Parma_Polyhedra_Library::Congruence::space_dimension(), Parma_Polyhedra_Library::Linear_Row::strong_normalize(), and throw_dimension_incompatible().

01693                                                           {
01694   // Dimension-compatibility check.
01695   if (space_dim < cg.space_dimension())
01696     throw_dimension_incompatible("refine_with_congruence(cg)", "cg", cg);
01697 
01698   // If the polyhedron is known to be empty, do nothing.
01699   if (marked_empty())
01700     return;
01701 
01702   // Dealing with a zero-dimensional space polyhedron first.
01703   if (space_dim == 0) {
01704     if (!cg.is_tautological())
01705       set_empty();
01706     return;
01707   }
01708 
01709   if (cg.is_equality()) {
01710     Linear_Expression le(cg);
01711     Constraint c(le, Constraint::EQUALITY, NECESSARILY_CLOSED);
01712     // Enforce normalization.
01713     c.strong_normalize();
01714     refine_no_check(c);
01715   }
01716 }

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

Uses a copy of the congruences in cgs to refine *this.

Parameters:
cgs Contains the congruences used to refine the system of constraints of *this.
Exceptions:
std::invalid_argument Thrown if *this and cgs are dimension-incompatible.

Definition at line 1799 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::Checked::le, Parma_Polyhedra_Library::NECESSARILY_CLOSED, set_empty(), space_dim, Parma_Polyhedra_Library::Congruence_System::space_dimension(), Parma_Polyhedra_Library::Linear_Row::strong_normalize(), and throw_dimension_incompatible().

01799                                                                    {
01800   // Dimension-compatibility check.
01801   if (space_dim < cgs.space_dimension())
01802     throw_dimension_incompatible("refine_with_congruences(cgs)", "cgs", cgs);
01803 
01804   Constraint_System cs;
01805   bool inserted = false;
01806   for (Congruence_System::const_iterator i = cgs.begin(),
01807          cgs_end = cgs.end(); i != cgs_end; ++i) {
01808     if (i->is_equality()) {
01809       Linear_Expression le(*i);
01810       Constraint c(le, Constraint::EQUALITY, NECESSARILY_CLOSED);
01811       // Enforce normalization.
01812       c.strong_normalize();
01813       // TODO: Consider stealing the row in c when adding it to cs.
01814       cs.insert(c);
01815       inserted = true;
01816     }
01817     else if (i->is_inconsistent()) {
01818       set_empty();
01819       return;
01820     }
01821   }
01822   // Only add cgs if congruences were inserted into cgs, as the
01823   // dimension of cs must be at most that of the polyhedron.
01824   if (inserted)
01825     add_recycled_constraints(cs);
01826 }

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

Uses a copy of constraint c to refine *this.

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

Definition at line 1683 of file Polyhedron_public.cc.

References marked_empty(), refine_no_check(), space_dim, Parma_Polyhedra_Library::Constraint::space_dimension(), and throw_dimension_incompatible().

01683                                                          {
01684   // Dimension-compatibility check.
01685   if (space_dim < c.space_dimension())
01686     throw_dimension_incompatible("refine_with_constraint(c)", "c", c);
01687   // If the polyhedron is known to be empty, do nothing.
01688   if (!marked_empty())
01689     refine_no_check(c);
01690 }

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

Uses a copy of the constraints in cs to refine *this.

Parameters:
cs Contains the constraints used to refine the system of constraints of *this.
Exceptions:
std::invalid_argument Thrown if *this and cs are dimension-incompatible.

Definition at line 1719 of file Polyhedron_public.cc.

References 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(), Parma_Polyhedra_Library::Matrix::has_no_rows(), has_pending_generators(), Parma_Polyhedra_Library::Constraint_System::insert(), Parma_Polyhedra_Library::Constraint_System::insert_pending(), Parma_Polyhedra_Library::Constraint::is_equality(), is_necessarily_closed(), Parma_Polyhedra_Library::Linear_Row::is_necessarily_closed(), marked_empty(), Parma_Polyhedra_Library::Matrix::num_rows(), OK(), process_pending_generators(), set_constraints_pending(), Parma_Polyhedra_Library::Polyhedron::Status::set_empty(), space_dim, Parma_Polyhedra_Library::Constraint_System::space_dimension(), status, throw_dimension_incompatible(), and update_constraints().

01719                                                                   {
01720   // TODO: this is just an executable specification.
01721 
01722   // Dimension-compatibility check.
01723   const dimension_type cs_space_dim = cs.space_dimension();
01724   if (space_dim < cs_space_dim)
01725     throw_dimension_incompatible("refine_with_constraints(cs)a",
01726                                  "cs", cs);
01727 
01728   // Adding no constraints is a no-op.
01729   if (cs.has_no_rows())
01730     return;
01731 
01732   if (space_dim == 0) {
01733     // In a 0-dimensional space the constraints are
01734     // tautologies (e.g., 0 == 0 or 1 >= 0 or 1 > 0) or
01735     // inconsistent (e.g., 1 == 0 or -1 >= 0 or 0 > 0).
01736     // In a system of constraints `begin()' and `end()' are equal
01737     // if and only if the system only contains tautologies.
01738     if (cs.begin() != cs.end())
01739       // There is a constraint, it must be inconsistent,
01740       // the polyhedron is empty.
01741       status.set_empty();
01742     return;
01743   }
01744 
01745   if (marked_empty())
01746     return;
01747 
01748   // The constraints (possibly with pending rows) are required.
01749   if (has_pending_generators())
01750     process_pending_generators();
01751   else if (!constraints_are_up_to_date())
01752     update_constraints();
01753 
01754   const bool adding_pending = can_have_something_pending();
01755   for (dimension_type i = cs.num_rows(); i-- > 0; ) {
01756     const Constraint& c = cs[i];
01757 
01758     if (c.is_necessarily_closed() || !is_necessarily_closed())
01759       // Since `con_sys' is not empty, the topology and space dimension
01760       // of the inserted constraint are automatically adjusted.
01761       if (adding_pending)
01762         con_sys.insert_pending(c);
01763       else
01764         con_sys.insert(c);
01765     else {
01766       // Here we know that *this is necessarily closed so even if c is
01767       // topologically closed, by barely invoking `con_sys.insert(c)' we
01768       // would cause a change in the topology of `con_sys', which is
01769       // wrong.  Thus, we insert a topology closed and "topology
01770       // corrected" version of `c'.
01771       Linear_Expression nc_expr = Linear_Expression(c);
01772       if (c.is_equality())
01773         if (adding_pending)
01774           con_sys.insert_pending(nc_expr == 0);
01775         else
01776           con_sys.insert(nc_expr == 0);
01777       else
01778         if (adding_pending)
01779           con_sys.insert_pending(nc_expr >= 0);
01780         else
01781           con_sys.insert(nc_expr >= 0);
01782     }
01783   }
01784 
01785   if (adding_pending)
01786     set_constraints_pending();
01787   else {
01788     // Constraints are not minimized and generators are not up-to-date.
01789     clear_constraints_minimized();
01790     clear_generators_up_to_date();
01791   }
01792 
01793   // Note: the constraint system may have become unsatisfiable, thus
01794   // we do not check for satisfiability.
01795   PPL_ASSERT_HEAVY(OK());
01796 }

PPL::Poly_Con_Relation Parma_Polyhedra_Library::Polyhedron::relation_with ( const Congruence cg  )  const

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

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

Definition at line 276 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::Scalar_Products::assign(), Parma_Polyhedra_Library::Generator_System::begin(), Parma_Polyhedra_Library::Generator_System::end(), gen_sys, generators_are_up_to_date(), has_pending_constraints(), Parma_Polyhedra_Library::Poly_Con_Relation::implies(), Parma_Polyhedra_Library::Poly_Con_Relation::is_disjoint(), Parma_Polyhedra_Library::Congruence::is_equality(), Parma_Polyhedra_Library::Poly_Con_Relation::is_included(), Parma_Polyhedra_Library::Congruence::is_inconsistent(), marked_empty(), Parma_Polyhedra_Library::Congruence::modulus(), PPL_DIRTY_TEMP_COEFFICIENT, process_pending_constraints(), relation_with(), Parma_Polyhedra_Library::Poly_Con_Relation::saturates(), space_dim, Parma_Polyhedra_Library::Congruence::space_dimension(), Parma_Polyhedra_Library::Poly_Con_Relation::strictly_intersects(), throw_dimension_incompatible(), and update_generators().

00276                                                        {
00277   dimension_type cg_space_dim = cg.space_dimension();
00278   // Dimension-compatibility check.
00279   if (space_dim < cg_space_dim)
00280     throw_dimension_incompatible("relation_with(cg)", "cg", cg);
00281 
00282   if (cg.is_equality()) {
00283     const Constraint c(cg);
00284     return relation_with(c);
00285   }
00286 
00287   if (marked_empty())
00288     return Poly_Con_Relation::saturates()
00289       && Poly_Con_Relation::is_included()
00290       && Poly_Con_Relation::is_disjoint();
00291 
00292   if (space_dim == 0) {
00293     if (cg.is_inconsistent())
00294       return Poly_Con_Relation::is_disjoint();
00295     else
00296       return Poly_Con_Relation::saturates()
00297         && Poly_Con_Relation::is_included();
00298   }
00299 
00300   if ((has_pending_constraints() && !process_pending_constraints())
00301       || (!generators_are_up_to_date() && !update_generators()))
00302     // The polyhedron is empty.
00303     return Poly_Con_Relation::saturates()
00304       && Poly_Con_Relation::is_included()
00305       && Poly_Con_Relation::is_disjoint();
00306 
00307   // Build the equality corresponding to the congruence (ignoring the modulus).
00308   Linear_Expression expr = Linear_Expression(cg);
00309   Constraint c(expr == 0);
00310 
00311   // The polyhedron is non-empty so that there exists a point.
00312   // For an arbitrary generator point, compute the scalar product with
00313   // the equality.
00314   PPL_DIRTY_TEMP_COEFFICIENT(sp_point);
00315   for (Generator_System::const_iterator gs_i = gen_sys.begin(),
00316          gs_end = gen_sys.end(); gs_i != gs_end; ++gs_i) {
00317     if (gs_i->is_point()) {
00318       Scalar_Products::assign(sp_point, c, *gs_i);
00319       expr -= sp_point;
00320       break;
00321     }
00322   }
00323 
00324   // Find two hyperplanes that satisfy the congruence and are near to
00325   // the generating point (so that the point lies on or between these
00326   // two hyperplanes).
00327   // Then use the relations between the polyhedron and the halfspaces
00328   // corresponding to the hyperplanes to determine the result.
00329 
00330   // Compute the distance from the point to an hyperplane.
00331   const Coefficient& modulus = cg.modulus();
00332   PPL_DIRTY_TEMP_COEFFICIENT(signed_distance);
00333   signed_distance = sp_point % modulus;
00334   if (signed_distance == 0)
00335     // The point is lying on the hyperplane.
00336     return relation_with(expr == 0);
00337   else
00338     // The point is not lying on the hyperplane.
00339     expr += signed_distance;
00340 
00341   // Build first halfspace constraint.
00342   const bool positive = (signed_distance > 0);
00343   Constraint first_halfspace = positive ? (expr >= 0) : (expr <= 0);
00344 
00345   Poly_Con_Relation first_rels = relation_with(first_halfspace);
00346   PPL_ASSERT(!first_rels.implies(Poly_Con_Relation::saturates())
00347          && !first_rels.implies(Poly_Con_Relation::is_disjoint()));
00348   if (first_rels.implies(Poly_Con_Relation::strictly_intersects()))
00349     return Poly_Con_Relation::strictly_intersects();
00350 
00351   // Build second halfspace.
00352   if (positive)
00353     expr -= modulus;
00354   else
00355     expr += modulus;
00356   Constraint second_halfspace = positive ? (expr <= 0) : (expr >= 0);
00357 
00358   PPL_ASSERT(first_rels == Poly_Con_Relation::is_included());
00359   Poly_Con_Relation second_rels = relation_with(second_halfspace);
00360   PPL_ASSERT(!second_rels.implies(Poly_Con_Relation::saturates())
00361          && !second_rels.implies(Poly_Con_Relation::is_disjoint()));
00362   if (second_rels.implies(Poly_Con_Relation::strictly_intersects()))
00363     return Poly_Con_Relation::strictly_intersects();
00364 
00365   PPL_ASSERT(second_rels == Poly_Con_Relation::is_included());
00366   return Poly_Con_Relation::is_disjoint();
00367 }

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 250 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().

00250                                                      {
00251   // Dimension-compatibility check.
00252   if (space_dim < g.space_dimension())
00253     throw_dimension_incompatible("relation_with(g)", "g", g);
00254 
00255   // The empty polyhedron cannot subsume a generator.
00256   if (marked_empty())
00257     return Poly_Gen_Relation::nothing();
00258 
00259   // A universe polyhedron in a zero-dimensional space subsumes
00260   // all the generators of a zero-dimensional space.
00261   if (space_dim == 0)
00262     return Poly_Gen_Relation::subsumes();
00263 
00264   if (has_pending_generators())
00265     process_pending_generators();
00266   else if (!constraints_are_up_to_date())
00267     update_constraints();
00268 
00269   return
00270     con_sys.satisfies_all_constraints(g)
00271     ? Poly_Gen_Relation::subsumes()
00272     : Poly_Gen_Relation::nothing();
00273 }

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 210 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 BFT00_poly_hull_assign_if_exact(), BHRZ03_combining_constraints(), BHRZ03_evolving_points(), BHRZ03_evolving_rays(), BHZ09_C_poly_hull_assign_if_exact(), BHZ09_NNC_poly_hull_assign_if_exact(), poly_difference_assign(), and relation_with().

00210                                                       {
00211   // Dimension-compatibility check.
00212   if (space_dim < c.space_dimension())
00213     throw_dimension_incompatible("relation_with(c)", "c", c);
00214 
00215   if (marked_empty())
00216     return Poly_Con_Relation::saturates()
00217       && Poly_Con_Relation::is_included()
00218       && Poly_Con_Relation::is_disjoint();
00219 
00220   if (space_dim == 0) {
00221     if (c.is_inconsistent())
00222       if (c.is_strict_inequality() && c.inhomogeneous_term() == 0)
00223         // The constraint 0 > 0 implicitly defines the hyperplane 0 = 0;
00224         // thus, the zero-dimensional point also saturates it.
00225         return Poly_Con_Relation::saturates()
00226           && Poly_Con_Relation::is_disjoint();
00227       else
00228         return Poly_Con_Relation::is_disjoint();
00229     else if (c.is_equality() || c.inhomogeneous_term() == 0)
00230       return Poly_Con_Relation::saturates()
00231         && Poly_Con_Relation::is_included();
00232     else
00233       // The zero-dimensional point saturates
00234       // neither the positivity constraint 1 >= 0,
00235       // nor the strict positivity constraint 1 > 0.
00236       return Poly_Con_Relation::is_included();
00237   }
00238 
00239   if ((has_pending_constraints() && !process_pending_constraints())
00240       || (!generators_are_up_to_date() && !update_generators()))
00241     // The polyhedron is empty.
00242     return Poly_Con_Relation::saturates()
00243       && Poly_Con_Relation::is_included()
00244       && Poly_Con_Relation::is_disjoint();
00245 
00246   return gen_sys.relation_with(c);
00247 }

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 490 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(), and generalized_affine_preimage().

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

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 756 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().

00756                                                           {
00757   PPL_ASSERT(has_something_pending());
00758 
00759   Polyhedron& x = const_cast<Polyhedron&>(*this);
00760 
00761   // If the polyhedron has pending constraints, simply unset them.
00762   if (x.has_pending_constraints()) {
00763     // Integrate the pending constraints, which are possibly not sorted.
00764     x.con_sys.unset_pending_rows();
00765     x.con_sys.set_sorted(false);
00766     x.clear_pending_constraints();
00767     x.clear_constraints_minimized();
00768     x.clear_generators_up_to_date();
00769   }
00770   else {
00771     PPL_ASSERT(x.has_pending_generators());
00772     // We must process the pending generators and obtain the
00773     // corresponding system of constraints.
00774     x.process_pending_generators();
00775   }
00776   PPL_ASSERT_HEAVY(OK(true));
00777 }

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 780 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().

00780                                                          {
00781   PPL_ASSERT(has_something_pending());
00782 
00783   Polyhedron& x = const_cast<Polyhedron&>(*this);
00784 
00785   // If the polyhedron has pending generators, simply unset them.
00786   if (x.has_pending_generators()) {
00787     // Integrate the pending generators, which are possibly not sorted.
00788     x.gen_sys.unset_pending_rows();
00789     x.gen_sys.set_sorted(false);
00790     x.clear_pending_generators();
00791     x.clear_generators_minimized();
00792     x.clear_constraints_up_to_date();
00793     PPL_ASSERT_HEAVY(OK(true));
00794     return true;
00795   }
00796   else {
00797     PPL_ASSERT(x.has_pending_constraints());
00798     // We must integrate the pending constraints and obtain the
00799     // corresponding system of generators.
00800     return x.process_pending_constraints();
00801   }
00802 }

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

Removes all the specified dimensions from the vector space.

Parameters:
vars 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 vars.

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, Parma_Polyhedra_Library::Variables_Set::space_dimension(), throw_dimension_incompatible(), and update_generators().

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

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::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   PPL_ASSERT(topology() == y.topology()
00044          && topology() == cs_selection.topology()
00045          && space_dim == y.space_dim);
00046   PPL_ASSERT(!marked_empty()
00047          && !has_pending_constraints()
00048          && generators_are_up_to_date());
00049   PPL_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::Bit_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(), is_necessarily_closed(), Parma_Polyhedra_Library::Constraint::is_strict_inequality(), marked_empty(), Parma_Polyhedra_Library::Matrix::num_rows(), Parma_Polyhedra_Library::Bit_Matrix::rows_erase_to_end(), sat_g, sat_g_is_up_to_date(), Parma_Polyhedra_Library::Bit_Row::set(), Parma_Polyhedra_Library::Scalar_Products::sign(), Parma_Polyhedra_Library::Bit_Matrix::sort_rows(), Parma_Polyhedra_Library::Bit_Matrix::sorted_contains(), space_dim, strongly_minimize_constraints(), swap(), Parma_Polyhedra_Library::Linear_System::topology(), topology(), update_generators(), 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   PPL_ASSERT(topology() == y.topology()
00073          && topology() == cs_selected.topology()
00074          && topology() == cs_not_selected.topology());
00075   PPL_ASSERT(space_dim == y.space_dim);
00076   PPL_ASSERT(!marked_empty()
00077          && !has_pending_generators()
00078          && constraints_are_up_to_date());
00079   PPL_ASSERT(!y.marked_empty()
00080          && !y.has_something_pending()
00081          && y.constraints_are_minimized()
00082          && y.generators_are_up_to_date());
00083 
00084   // FIXME: this is a workaround for NNC polyhedra.
00085   if (!y.is_necessarily_closed()) {
00086     // Force strong minimization of constraints.
00087     y.strongly_minimize_constraints();
00088     // Recompute generators (without compromising constraint minimization).
00089     y.update_generators();
00090   }
00091 
00092   // Obtain a sorted copy of `y.sat_g'.
00093   if (!y.sat_g_is_up_to_date())
00094     y.update_sat_g();
00095   Bit_Matrix tmp_sat_g = y.sat_g;
00096   // Remove from `tmp_sat_g' the rows corresponding to tautologies
00097   // (i.e., the positivity or epsilon-bounding constraints):
00098   // this is needed in order to widen the polyhedron and not the
00099   // corresponding homogenized polyhedral cone.
00100   const Constraint_System& y_cs = y.con_sys;
00101   dimension_type num_rows = y_cs.num_rows();
00102   for (dimension_type i = 0; i < num_rows; ++i)
00103     if (y_cs[i].is_tautological()) {
00104       --num_rows;
00105       std::swap(tmp_sat_g[i], tmp_sat_g[num_rows]);
00106     }
00107   tmp_sat_g.rows_erase_to_end(num_rows);
00108   tmp_sat_g.sort_rows();
00109 
00110   // A constraint in `con_sys' is copied to `cs_selected'
00111   // if its behavior with respect to `y.gen_sys' is the same
00112   // as that of another constraint in `y.con_sys'.
00113   // otherwise it is copied to `cs_not_selected'.
00114   // Namely, we check whether the saturation row `buffer'
00115   // (built starting from the given constraint and `y.gen_sys')
00116   // is a row of the saturation matrix `tmp_sat_g'.
00117 
00118   // CHECKME: the following comment is only applicable when `y.gen_sys'
00119   // is minimized. In that case, the comment suggests that it would be
00120   // possible to use a fast (but incomplete) redundancy test based on
00121   // the number of saturators in `buffer'.
00122   // NOTE: If the considered constraint of `con_sys' does not
00123   // satisfy the saturation rule (see Section \ref prelims), then
00124   // it will not appear in the resulting constraint system,
00125   // because `tmp_sat_g' is built starting from a minimized polyhedron.
00126 
00127   // The size of `buffer' will reach sat.num_columns() bits.
00128   Bit_Row buffer;
00129   // Note: the loop index `i' goes upward to avoid reversing
00130   // the ordering of the chosen constraints.
00131   for (dimension_type i = 0, end = con_sys.num_rows(); i < end; ++i) {
00132     const Constraint& ci = con_sys[i];
00133     // The saturation row `buffer' is built considering
00134     // the `i'-th constraint of the polyhedron `x' and
00135     // all the generators of the polyhedron `y'.
00136     buffer.clear();
00137     for (dimension_type j = y.gen_sys.num_rows(); j-- > 0; ) {
00138       const int sp_sgn = Scalar_Products::sign(ci, y.gen_sys[j]);
00139       // We are assuming that `y <= x'.
00140       PPL_ASSERT(sp_sgn >= 0
00141              || (!is_necessarily_closed()
00142                  && ci.is_strict_inequality()
00143                  && y.gen_sys[j].is_point()));
00144       if (sp_sgn > 0)
00145         buffer.set(j);
00146     }
00147     // We check whether `buffer' is a row of `tmp_sat_g',
00148     // exploiting its sortedness in order to have faster comparisons.
00149     if (tmp_sat_g.sorted_contains(buffer))
00150       cs_selected.insert(ci);
00151     else
00152       cs_not_selected.insert(ci);
00153   }
00154 }

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

Sets status to express that constraints are minimized.

Definition at line 202 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().

00202                                       {
00203   set_constraints_up_to_date();
00204   status.set_c_minimized();
00205 }

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

Sets status to express that constraints are pending.

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

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

Referenced by add_recycled_constraints(), concatenate_assign(), intersection_assign(), refine_no_check(), and refine_with_constraints().

00214                                     {
00215   status.set_c_pending();
00216 }

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 192 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().

00192                                        {
00193   status.set_c_up_to_date();
00194 }

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

Sets status to express that generators are minimized.

Definition at line 208 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().

00208                                      {
00209   set_generators_up_to_date();
00210   status.set_g_minimized();
00211 }

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

Sets status to express that generators are pending.

Definition at line 219 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(), topological_closure_assign(), and unconstrain().

00219                                    {
00220   status.set_g_pending();
00221 }

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 197 of file Polyhedron.inlines.hh.

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

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

00197                                       {
00198   status.set_g_up_to_date();
00199 }

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::set_zero_dim_univ (  )  [private]
Constraint_System Parma_Polyhedra_Library::Polyhedron::simplified_constraints (  )  const [inline, private]

If constraints are up-to-date, obtain a simplified copy of them.

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

References con_sys, constraints_are_minimized(), constraints_are_up_to_date(), has_pending_constraints(), Parma_Polyhedra_Library::Linear_System::num_pending_rows(), Parma_Polyhedra_Library::Constraint_System::simplify(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

Referenced by Parma_Polyhedra_Library::Box< ITV >::Box().

00346                                          {
00347   PPL_ASSERT(constraints_are_up_to_date());
00348   Constraint_System cs(con_sys);
00349   if (cs.num_pending_rows() > 0)
00350     cs.unset_pending_rows();
00351   if (has_pending_constraints() || !constraints_are_minimized())
00352     cs.simplify();
00353   return cs;
00354 }

PPL::dimension_type Parma_Polyhedra_Library::Polyhedron::simplify ( Linear_System sys,
Bit_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 84 of file simplify.cc.

References Parma_Polyhedra_Library::Linear_System::back_substitute(), Parma_Polyhedra_Library::compute_capacity(), Parma_Polyhedra_Library::Matrix::erase_to_end(), Parma_Polyhedra_Library::Linear_System::gauss(), Parma_Polyhedra_Library::Bit_Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_columns(), Parma_Polyhedra_Library::Matrix::num_rows(), Parma_Polyhedra_Library::Linear_System::OK(), Parma_Polyhedra_Library::Bit_Matrix::rows_erase_to_end(), Parma_Polyhedra_Library::Linear_System::set_sorted(), Parma_Polyhedra_Library::Linear_System::sign_normalize(), simplify_num_saturators_p, simplify_num_saturators_size, swap(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

Referenced by add_and_minimize(), and minimize().

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

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

Assigns to *this a meet-preserving simplification of *this with respect to y. If false is returned, then the intersection is empty.

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

Definition at line 2055 of file Polyhedron_public.cc.

References Parma_Polyhedra_Library::MIP_Problem::add_constraint(), Parma_Polyhedra_Library::MIP_Problem::add_constraints(), add_constraints(), add_recycled_constraints(), Parma_Polyhedra_Library::MIP_Problem::add_space_dimensions_and_embed(), Parma_Polyhedra_Library::Generator_System::begin(), Parma_Polyhedra_Library::Generator::CLOSURE_POINT, con_sys, constraints_are_minimized(), constraints_are_up_to_date(), Parma_Polyhedra_Library::Bit_Row::empty(), Parma_Polyhedra_Library::Generator_System::end(), Parma_Polyhedra_Library::Constraint::EQUALITY, gen_sys, generators_are_minimized(), has_pending_generators(), has_something_pending(), Parma_Polyhedra_Library::Constraint_System::insert(), is_empty(), Parma_Polyhedra_Library::Constraint::is_inequality(), Parma_Polyhedra_Library::Generator::is_line(), is_necessarily_closed(), Parma_Polyhedra_Library::Constraint::is_tautological(), Parma_Polyhedra_Library::Checked::le, Parma_Polyhedra_Library::Generator::LINE, minimize(), Parma_Polyhedra_Library::Constraint::NONSTRICT_INEQUALITY, Parma_Polyhedra_Library::Matrix::num_rows(), OK(), Parma_Polyhedra_Library::Generator::POINT, Parma_Polyhedra_Library::Generator::RAY, Parma_Polyhedra_Library::Generator_System::satisfied_by_all_generators(), Parma_Polyhedra_Library::Bit_Row::set(), Parma_Polyhedra_Library::Linear_Row::set_is_line_or_equality(), set_zero_dim_univ(), Parma_Polyhedra_Library::Scalar_Products::sign(), Parma_Polyhedra_Library::Linear_Row::sign_normalize(), Parma_Polyhedra_Library::MIP_Problem::solve(), space_dim, status, Parma_Polyhedra_Library::Constraint::STRICT_INEQUALITY, Parma_Polyhedra_Library::Constraint_System::swap(), swap(), throw_dimension_incompatible(), throw_topology_incompatible(), topology(), Parma_Polyhedra_Library::Generator::type(), Parma_Polyhedra_Library::Constraint::type(), Parma_Polyhedra_Library::UNFEASIBLE_MIP_PROBLEM, and Parma_Polyhedra_Library::UNIVERSE.

02055                                                                 {
02056   Polyhedron& x = *this;
02057   // Topology compatibility check.
02058   if (x.topology() != y.topology())
02059     throw_topology_incompatible("simplify_using_context_assign(y)", "y", y);
02060   // Dimension-compatibility check.
02061   if (x.space_dim != y.space_dim)
02062     throw_dimension_incompatible("simplify_using_context_assign(y)", "y", y);
02063 
02064   // Filter away the zero-dimensional case.
02065   if (x.space_dim == 0) {
02066     if (y.is_empty()) {
02067       x.set_zero_dim_univ();
02068       return false;
02069     }
02070     else
02071       return !x.is_empty();
02072   }
02073 
02074   // If `y' is empty, the biggest enlargement for `x' is the universe.
02075   if (!y.minimize()) {
02076     Polyhedron ph(x.topology(), x.space_dim, UNIVERSE);
02077     swap(ph);
02078     return false;
02079   }
02080 
02081   // If `x' is empty, the intersection is empty.
02082   if (!x.minimize()) {
02083     // Search for a constraint of `y' that is not a tautology.
02084     PPL_ASSERT(!y.has_pending_generators() && y.constraints_are_up_to_date());
02085     for (dimension_type i = y.con_sys.num_rows(); i-- > 0; ) {
02086       const Constraint& y_con_sys_i = y.con_sys[i];
02087       if (!y_con_sys_i.is_tautological()) {
02088         // Found: we obtain a constraint `c' contradicting the one we
02089         // found, and assign to `x' the polyhedron `ph' with `c' as
02090         // the only constraint.
02091         Polyhedron ph(x.topology(), x.space_dim, UNIVERSE);
02092         Linear_Expression le(y_con_sys_i);
02093         switch (y_con_sys_i.type()) {
02094         case Constraint::EQUALITY:
02095           ph.refine_no_check(le == 1);
02096           break;
02097         case Constraint::NONSTRICT_INEQUALITY:
02098           ph.refine_no_check(le <= -1);
02099           break;
02100         case Constraint::STRICT_INEQUALITY:
02101           ph.refine_no_check(le == 0);
02102           break;
02103         }
02104         swap(ph);
02105         PPL_ASSERT_HEAVY(OK());
02106         return false;
02107       }
02108     }
02109     // `y' is the universe: `x' cannot be enlarged.
02110     return false;
02111   }
02112 
02113   PPL_ASSERT(x.constraints_are_minimized()
02114          && !x.has_something_pending()
02115          && y.generators_are_minimized()
02116          && !y.has_something_pending());
02117   const Constraint_System& x_cs = x.con_sys;
02118   const dimension_type x_cs_num_rows = x_cs.num_rows();
02119   const Generator_System& y_gs = y.gen_sys;
02120 
02121   // Record into `redundant_by_y' the info about which constraints of
02122   // `x' are redundant in the context `y'.  Count the number of
02123   // redundancies found.
02124   std::vector<bool> redundant_by_y(x_cs_num_rows, false);
02125   dimension_type num_redundant_by_y = 0;
02126   for (dimension_type i = 0; i < x_cs_num_rows; ++i)
02127     if (y_gs.satisfied_by_all_generators(x_cs[i])) {
02128       redundant_by_y[i] = true;
02129       ++num_redundant_by_y;
02130     }
02131 
02132   Constraint_System result_cs;
02133 
02134   if (num_redundant_by_y < x_cs_num_rows) {
02135     // Some constraints were not identified as redundant (yet?).
02136     const Constraint_System& y_cs = y.con_sys;
02137     const dimension_type y_cs_num_rows = y_cs.num_rows();
02138     // Compute into `z' the minimized intersection of `x' and `y'.
02139     const bool x_first = (x_cs_num_rows > y_cs_num_rows);
02140     Polyhedron z(x_first ? x : y);
02141     if (x_first)
02142       z.add_constraints(y_cs);
02143     else {
02144       // Only copy (and then recycle) the non-redundant constraints.
02145       Constraint_System tmp_cs;
02146       for (dimension_type i = 0; i < x_cs_num_rows; ++i) {
02147         if (!redundant_by_y[i])
02148           tmp_cs.insert(x_cs[i]);
02149       }
02150       z.add_recycled_constraints(tmp_cs);
02151     }
02152     if (!z.minimize()) {
02153       // The objective function is the default, zero.
02154       // We do not care about minimization or maximization, since
02155       // we are only interested in satisfiability.
02156       MIP_Problem lp;
02157       if (x.is_necessarily_closed()) {
02158         lp.add_space_dimensions_and_embed(x.space_dim);
02159         lp.add_constraints(y_cs);
02160       }
02161       else {
02162         // KLUDGE: temporarily mark `y_cs' if it was necessarily
02163         // closed, so that we can interpret the epsilon dimension as a
02164         // standard dimension. Be careful to reset the topology of `cs'
02165         // even on exceptional execution path.
02166         const_cast<Constraint_System&>(y_cs).set_necessarily_closed();
02167         try {
02168           lp.add_space_dimensions_and_embed(x.space_dim+1);
02169           lp.add_constraints(y_cs);
02170           const_cast<Constraint_System&>(y_cs).set_not_necessarily_closed();
02171         }
02172         catch (...) {
02173           const_cast<Constraint_System&>(y_cs).set_not_necessarily_closed();
02174           throw;
02175         }
02176       }
02177       // We apply the following heuristics here: constraints of `x' that
02178       // are not made redundant by `y' are added to `lp' depending on
02179       // the number of generators of `y' they rule out (the more generators
02180       // they rule out, the sooner they are added).  Of course, as soon
02181       // as `lp' becomes unsatisfiable, we stop adding.
02182       std::vector<Ruled_Out_Pair>
02183         ruled_out_vec(x_cs_num_rows - num_redundant_by_y);
02184       for (dimension_type i = 0, j = 0; i < x_cs_num_rows; ++i) {
02185         if (!redundant_by_y[i]) {
02186           const Constraint& c = x_cs[i];
02187           Topology_Adjusted_Scalar_Product_Sign sps(c);
02188           dimension_type num_ruled_out_generators = 0;
02189           for (Generator_System::const_iterator k = y_gs.begin(),
02190                  y_gs_end = y_gs.end(); k != y_gs_end; ++k) {
02191             const Generator& g = *k;
02192             const int sp_sign = sps(g, c);
02193             if (x.is_necessarily_closed()) {
02194               if (g.is_line()) {
02195                 // Lines must saturate the constraint.
02196                 if (sp_sign != 0)
02197                   goto ruled_out;
02198               }
02199               else {
02200                 // `g' is either a ray, a point or a closure point.
02201                 if (c.is_inequality()) {
02202                   // `c' is a non-strict inequality.
02203                   if (sp_sign < 0)
02204                     goto ruled_out;
02205                 }
02206                 else
02207                   // `c' is an equality.
02208                   if (sp_sign != 0)
02209                     goto ruled_out;
02210               }
02211             }
02212             else
02213               // The topology is not necessarily closed.
02214               switch (g.type()) {
02215               case Generator::LINE:
02216                 // Lines must saturate the constraint.
02217                 if (sp_sign != 0)
02218                   goto ruled_out;
02219                 break;
02220               case Generator::POINT:
02221                 // Have to perform the special test when dealing with
02222                 // a strict inequality.
02223                 switch (c.type()) {
02224                 case Constraint::EQUALITY:
02225                   if (sp_sign != 0)
02226                     goto ruled_out;
02227                   break;
02228                 case Constraint::NONSTRICT_INEQUALITY:
02229                   if (sp_sign < 0)
02230                     goto ruled_out;
02231                   break;
02232                 case Constraint::STRICT_INEQUALITY:
02233                   if (sp_sign <= 0)
02234                     goto ruled_out;
02235                   break;
02236                 }
02237                 break;
02238               case Generator::RAY:
02239                 // Intentionally fall through.
02240               case Generator::CLOSURE_POINT:
02241                 if (c.is_inequality()) {
02242                   // Constraint `c' is either a strict or a non-strict
02243                   // inequality.
02244                   if (sp_sign < 0)
02245                     goto ruled_out;
02246                 }
02247                 else
02248                   // Constraint `c' is an equality.
02249                   if (sp_sign != 0)
02250                     goto ruled_out;
02251                 break;
02252               }
02253 
02254             // If we reach this point, `g' satisfies `c'.
02255             continue;
02256           ruled_out:
02257             ++num_ruled_out_generators;
02258           }
02259           ruled_out_vec[j].constraint_index = i;
02260           ruled_out_vec[j].num_ruled_out = num_ruled_out_generators;
02261           ++j;
02262         }
02263       }
02264       std::sort(ruled_out_vec.begin(), ruled_out_vec.end(),
02265                 Ruled_Out_Less_Than());
02266 
02267       for (std::vector<Ruled_Out_Pair>::const_iterator
02268              j = ruled_out_vec.begin(), rov_end = ruled_out_vec.end();
02269            j != rov_end;
02270            ++j) {
02271         const Constraint& c = x_cs[j->constraint_index];
02272         result_cs.insert(c);
02273         lp.add_constraint(c);
02274         MIP_Problem_Status status = lp.solve();
02275         if (status == UNFEASIBLE_MIP_PROBLEM) {
02276           Polyhedron result_ph(x.topology(), x.space_dim, UNIVERSE);
02277           result_ph.add_constraints(result_cs);
02278           x.swap(result_ph);
02279           PPL_ASSERT_HEAVY(x.OK());
02280           return false;
02281         }
02282       }
02283       // Cannot exit from here.
02284       PPL_ASSERT(false);
02285     }
02286     else {
02287       // Here `z' is not empty and minimized.
02288       PPL_ASSERT(z.constraints_are_minimized()
02289              && z.generators_are_minimized()
02290              && !z.has_something_pending());
02291       const Constraint_System& z_cs = z.con_sys;
02292       const Generator_System& z_gs = z.gen_sys;
02293       const dimension_type z_gs_num_rows = z_gs.num_rows();
02294 
02295       // Compute the number of equalities in x_cs, y_cs and z_cs
02296       // (exploiting minimal form knowledge).
02297       dimension_type x_cs_num_eq = 0;
02298       while (x_cs[x_cs_num_eq].is_equality())
02299         ++x_cs_num_eq;
02300       dimension_type y_cs_num_eq = 0;
02301       while (y_cs[y_cs_num_eq].is_equality())
02302         ++y_cs_num_eq;
02303       dimension_type z_cs_num_eq = 0;
02304       while (z_cs[z_cs_num_eq].is_equality())
02305         ++z_cs_num_eq;
02306       PPL_ASSERT(x_cs_num_eq <= z_cs_num_eq && y_cs_num_eq <= z_cs_num_eq);
02307 
02308       // Identify non-redundant equalities.
02309       Constraint_System nonred_eq;
02310       dimension_type num_nonred_eq = 0;
02311       const dimension_type needed_nonred_eq = z_cs_num_eq - y_cs_num_eq;
02312       Linear_System eqs(x.topology());
02313       if (needed_nonred_eq > 0) {
02314         // Populate eqs with the equalities from y.
02315         for (dimension_type i = 0; i < y_cs_num_eq; ++i)
02316           eqs.insert(y_cs[i]);
02317         // Try to find another `needed_nonred_eq' linear independent
02318         // equalities among those from x.
02319         for (dimension_type i = 0; i < x_cs_num_eq; ++i) {
02320           const Constraint& x_cs_i = x_cs[i];
02321           if (add_to_system_and_check_independence(eqs, x_cs_i)) {
02322             // x_cs_i is linear independent.
02323             nonred_eq.insert(x_cs_i);
02324             ++num_nonred_eq;
02325             if (num_nonred_eq == needed_nonred_eq)
02326               // Already found all the needed equalities.
02327               break;
02328           }
02329         }
02330         // NOTE: if num_nonred_eq < needed_nonred_eq
02331         // then we haven't found all the needed equalities yet:
02332         // this means that some inequalities from x actually holds
02333         // as "masked" equalities in the context of y.
02334         PPL_ASSERT(eqs.num_rows() <= z_cs_num_eq);
02335         PPL_ASSERT(num_nonred_eq <= needed_nonred_eq);
02336         PPL_ASSERT(z_cs_num_eq - eqs.num_rows()
02337                == needed_nonred_eq - num_nonred_eq);
02338       }
02339 
02340       // Identify non-redundant inequalities.
02341       // Avoid useless copies (no modifications are needed).
02342       std::vector<const Constraint*> p_nonred_ineq;
02343       // Fill p_nonred_ineq with (pointers to) inequalities from y_cs ...
02344       for (dimension_type i = y_cs_num_eq; i < y_cs_num_rows; ++i)
02345         p_nonred_ineq.push_back(&y_cs[i]);
02346       // ... and (pointers to) non-redundant inequalities from x_cs.
02347       for (dimension_type i = x_cs_num_eq; i < x_cs_num_rows; ++i)
02348         if (!redundant_by_y[i])
02349           p_nonred_ineq.push_back(&x_cs[i]);
02350 
02351       const dimension_type p_nonred_ineq_size = p_nonred_ineq.size();
02352       const dimension_type y_cs_num_ineq = y_cs_num_rows - y_cs_num_eq;
02353 
02354       // Compute saturation info.
02355       const dimension_type sat_num_rows = p_nonred_ineq_size;
02356       Bit_Matrix sat(sat_num_rows, z_gs_num_rows);
02357       for (dimension_type i = sat_num_rows; i-- > 0; ) {
02358         const Constraint& nonred_ineq_i = *(p_nonred_ineq[i]);
02359         Bit_Row& sat_i = sat[i];
02360         for (dimension_type j = z_gs_num_rows; j-- > 0; )
02361           if (Scalar_Products::sign(nonred_ineq_i, z_gs[j]))
02362             sat_i.set(j);
02363         if (sat_i.empty() && num_nonred_eq < needed_nonred_eq) {
02364           // `nonred_ineq_i' is actually masking an equality
02365           // and we are still looking for some masked inequalities.
02366           // Iteration goes downwards, so the inequality comes from x_cs.
02367           PPL_ASSERT(i >= y_cs_num_ineq);
02368           // Check if the equality is independent in eqs.
02369           Linear_Row masked_eq = Linear_Row(nonred_ineq_i);
02370           masked_eq.set_is_line_or_equality();
02371           masked_eq.sign_normalize();
02372           if (add_to_system_and_check_independence(eqs, masked_eq)) {
02373             // It is independent: add the _inequality_ to nonred_eq.
02374             nonred_eq.insert(nonred_ineq_i);
02375             ++num_nonred_eq;
02376           }
02377         }
02378       }
02379       // Here we have already found all the needed (masked) equalities.
02380       PPL_ASSERT(num_nonred_eq == needed_nonred_eq);
02381 
02382       drop_redundant_inequalities(p_nonred_ineq, x.topology(),
02383                                   sat, z_cs_num_eq);
02384 
02385       // Place the nonredundant (masked) equalities into result_cs.
02386       result_cs.swap(nonred_eq);
02387       // Add to result_cs the nonredundant inequalities from x_cs,
02388       // i.e., those having indices no smaller than y_cs_num_ineq.
02389       for (dimension_type i = y_cs_num_ineq; i < p_nonred_ineq_size; ++i)
02390         if (p_nonred_ineq[i])
02391           result_cs.insert(*p_nonred_ineq[i]);
02392     }
02393   }
02394 
02395   Polyhedron result_ph(x.topology(), x.space_dim, UNIVERSE);
02396   result_ph.add_recycled_constraints(result_cs);
02397   x.swap(result_ph);
02398   PPL_ASSERT_HEAVY(x.OK());
02399   return true;
02400 }

dimension_type Parma_Polyhedra_Library::Polyhedron::space_dimension (  )  const [inline]
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 383 of file Polyhedron.inlines.hh.

References contains().

00383                                                        {
00384   const Polyhedron& x = *this;
00385   return x.contains(y) && !y.contains(x);
00386 }

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 1079 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::MIP_Problem::add_constraints(), Parma_Polyhedra_Library::MIP_Problem::add_space_dimensions_and_embed(), Parma_Polyhedra_Library::Bit_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::Bit_Row::set(), Parma_Polyhedra_Library::Linear_System::set_necessarily_closed(), Parma_Polyhedra_Library::Linear_System::set_not_necessarily_closed(), Parma_Polyhedra_Library::MIP_Problem::set_objective_function(), Parma_Polyhedra_Library::MIP_Problem::set_optimization_mode(), Parma_Polyhedra_Library::Linear_System::set_sorted(), Parma_Polyhedra_Library::MIP_Problem::solve(), space_dim, Parma_Polyhedra_Library::Constraint_System::space_dimension(), status, swap(), Parma_Polyhedra_Library::Bit_Matrix::transpose_assign(), Parma_Polyhedra_Library::UNBOUNDED_MIP_PROBLEM, Parma_Polyhedra_Library::UNFEASIBLE_MIP_PROBLEM, and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

Referenced by is_topologically_closed(), minimized_constraints(), and select_H79_constraints().

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

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 1257 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::Bit_Row::set(), Parma_Polyhedra_Library::Linear_System::set_sorted(), space_dim, swap(), Parma_Polyhedra_Library::Bit_Matrix::transpose_assign(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

Referenced by minimized_generators().

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

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

Definition at line 2396 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed(), and space_dimension().

02397                                                                       {
02398   std::ostringstream s;
02399   s << "PPL::";
02400   if (is_necessarily_closed())
02401     s << "C_";
02402   else
02403     s << "NNC_";
02404   s << "Polyhedron::" << method << ":" << std::endl
02405     << "this->space_dimension() == " << space_dimension()
02406     << ", required space dimension == " << required_space_dim << ".";
02407   throw std::invalid_argument(s.str());
02408 }

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

Definition at line 2379 of file Polyhedron_nonpublic.cc.

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

02381                                                                         {
02382   std::ostringstream s;
02383   s << "PPL::";
02384   if (is_necessarily_closed())
02385     s << "C_";
02386   else
02387     s << "NNC_";
02388   s << "Polyhedron::" << method << ":" << std::endl
02389     << "this->space_dimension() == " << space_dimension() << ", "
02390     << var_name << ".space_dimension() == " << var.space_dimension() << ".";
02391   throw std::invalid_argument(s.str());
02392 }

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

Definition at line 2372 of file Polyhedron_nonpublic.cc.

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

02374                                                                                   {
02375   throw_dimension_incompatible(method, cgs_name, cgs.space_dimension());
02376 }

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

Definition at line 2365 of file Polyhedron_nonpublic.cc.

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

02367                                                                                 {
02368   throw_dimension_incompatible(method, gs_name, gs.space_dimension());
02369 }

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

Definition at line 2358 of file Polyhedron_nonpublic.cc.

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

02360                                                                                  {
02361   throw_dimension_incompatible(method, cs_name, cs.space_dimension());
02362 }

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

Definition at line 2351 of file Polyhedron_nonpublic.cc.

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

02353                                                                           {
02354   throw_dimension_incompatible(method, cg_name, cg.space_dimension());
02355 }

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

Definition at line 2344 of file Polyhedron_nonpublic.cc.

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

02346                                                                         {
02347   throw_dimension_incompatible(method, g_name, g.space_dimension());
02348 }

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

Definition at line 2337 of file Polyhedron_nonpublic.cc.

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

02339                                                                          {
02340   throw_dimension_incompatible(method, c_name, c.space_dimension());
02341 }

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

Definition at line 2330 of file Polyhedron_nonpublic.cc.

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

02332                                                                                 {
02333   throw_dimension_incompatible(method, e_name, e.space_dimension());
02334 }

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

Definition at line 2323 of file Polyhedron_nonpublic.cc.

References space_dimension(), and throw_dimension_incompatible().

02325                                                                           {
02326   throw_dimension_incompatible(method, ph_name, ph.space_dimension());
02327 }

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_invalid_argument ( const char *  method,
const char *  reason 
) const [protected]

Definition at line 2233 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

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

02234                                                                   {
02235   std::ostringstream s;
02236   s << "PPL::";
02237   if (is_necessarily_closed())
02238     s << "C_";
02239   else
02240     s << "NNC_";
02241   s << "Polyhedron::" << method << ":" << std::endl
02242     << reason << ".";
02243   throw std::invalid_argument(s.str());
02244 }

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

Definition at line 2426 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

Referenced by add_generator().

02427                                                                    {
02428   std::ostringstream s;
02429   s << "PPL::";
02430   if (is_necessarily_closed())
02431     s << "C_";
02432   else
02433     s << "NNC_";
02434   s << "Polyhedron::" << method << ":" << std::endl
02435     << "*this is an empty polyhedron and "
02436     << g_name << " is not a point.";
02437   throw std::invalid_argument(s.str());
02438 }

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

Definition at line 2441 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

Referenced by add_recycled_generators(), and Polyhedron().

02442                                                                      {
02443   std::ostringstream s;
02444   s << "PPL::";
02445   if (is_necessarily_closed())
02446     s << "C_";
02447   else
02448     s << "NNC_";
02449   s << "Polyhedron::" << method << ":" << std::endl
02450     << "*this is an empty polyhedron and" << std::endl
02451     << "the non-empty generator system " << gs_name << " contains no points.";
02452   throw std::invalid_argument(s.str());
02453 }

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

Definition at line 2221 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

Referenced by add_generator().

02221                                                            {
02222   std::ostringstream s;
02223   s << "PPL::";
02224   if (is_necessarily_closed())
02225     s << "C_";
02226   else
02227     s << "NNC_";
02228   s << "Polyhedron::" << method << "." << std::endl;
02229   throw std::runtime_error(s.str());
02230 }

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

Definition at line 2411 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().

02413                                                                     {
02414   std::ostringstream s;
02415   s << "PPL::";
02416   if (topol == NECESSARILY_CLOSED)
02417     s << "C_";
02418   else
02419     s << "NNC_";
02420   s << "Polyhedron::" << method << ":" << std::endl
02421     << reason << ".";
02422   throw std::length_error(s.str());
02423 }

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

Definition at line 2300 of file Polyhedron_nonpublic.cc.

02302                                                                             {
02303   std::ostringstream s;
02304   s << "PPL::C_Polyhedron::" << method << ":" << std::endl
02305     << gs_name << " contains closure points.";
02306   throw std::invalid_argument(s.str());
02307 }

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

Definition at line 2289 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

02291                                                                              {
02292   PPL_ASSERT(is_necessarily_closed());
02293   std::ostringstream s;
02294   s << "PPL::C_Polyhedron::" << method << ":" << std::endl
02295     << cs_name << " contains strict inequalities.";
02296   throw std::invalid_argument(s.str());
02297 }

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

Definition at line 2278 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

02280                                                                      {
02281   PPL_ASSERT(is_necessarily_closed());
02282   std::ostringstream s;
02283   s << "PPL::C_Polyhedron::" << method << ":" << std::endl
02284     << g_name << " is a closure point.";
02285   throw std::invalid_argument(s.str());
02286 }

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

Definition at line 2267 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

02269                                                                       {
02270   PPL_ASSERT(is_necessarily_closed());
02271   std::ostringstream s;
02272   s << "PPL::C_Polyhedron::" << method << ":" << std::endl
02273     << c_name << " is a strict inequality.";
02274   throw std::invalid_argument(s.str());
02275 }

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

Definition at line 2247 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

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

02249                                                                          {
02250   std::ostringstream s;
02251   s << "PPL::";
02252   if (is_necessarily_closed())
02253     s << "C_";
02254   else
02255     s << "NNC_";
02256   s << "Polyhedron::" << method << ":" << std::endl
02257     << ph_name << " is a ";
02258   if (ph.is_necessarily_closed())
02259     s << "C_";
02260   else
02261     s << "NNC_";
02262   s << "Polyhedron." << std::endl;
02263   throw std::invalid_argument(s.str());
02264 }

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 3341 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, swap(), throw_dimension_incompatible(), throw_topology_incompatible(), topology(), Parma_Polyhedra_Library::Linear_System::unset_pending_rows(), and update_generators().

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

03341                                                      {
03342   Polyhedron& x = *this;
03343   // Topology compatibility check.
03344   if (x.topology() != y.topology())
03345     throw_topology_incompatible("time_elapse_assign(y)", "y", y);
03346   // Dimension-compatibility checks.
03347   if (x.space_dim != y.space_dim)
03348     throw_dimension_incompatible("time_elapse_assign(y)", "y", y);
03349 
03350   // Dealing with the zero-dimensional case.
03351   if (x.space_dim == 0) {
03352     if (y.marked_empty())
03353       x.set_empty();
03354     return;
03355   }
03356 
03357   // If either one of `x' or `y' is empty, the result is empty too.
03358   if (x.marked_empty() || y.marked_empty()
03359       || (x.has_pending_constraints() && !x.process_pending_constraints())
03360       || (!x.generators_are_up_to_date() && !x.update_generators())
03361       || (y.has_pending_constraints() && !y.process_pending_constraints())
03362       || (!y.generators_are_up_to_date() && !y.update_generators())) {
03363     x.set_empty();
03364     return;
03365   }
03366 
03367   // At this point both generator systems are up-to-date,
03368   // possibly containing pending generators.
03369   Generator_System gs = y.gen_sys;
03370   dimension_type gs_num_rows = gs.num_rows();
03371 
03372   if (!x.is_necessarily_closed())
03373     // `x' and `y' are NNC polyhedra.
03374     for (dimension_type i = gs_num_rows; i-- > 0; )
03375       switch (gs[i].type()) {
03376       case Generator::POINT:
03377         // The points of `gs' can be erased,
03378         // since their role can be played by closure points.
03379         --gs_num_rows;
03380         std::swap(gs[i], gs[gs_num_rows]);
03381         break;
03382       case Generator::CLOSURE_POINT:
03383         {
03384           Generator& cp = gs[i];
03385           // If it is the origin, erase it.
03386           if (cp.all_homogeneous_terms_are_zero()) {
03387             --gs_num_rows;
03388             std::swap(cp, gs[gs_num_rows]);
03389           }
03390           // Otherwise, transform the closure point into a ray.
03391           else {
03392             cp[0] = 0;
03393             // Enforce normalization.
03394             cp.normalize();
03395           }
03396         }
03397         break;
03398       default:
03399         // For rays and lines, nothing to be done.
03400         break;
03401       }
03402   else
03403     // `x' and `y' are C polyhedra.
03404     for (dimension_type i = gs_num_rows; i-- > 0; )
03405       switch (gs[i].type()) {
03406       case Generator::POINT:
03407         {
03408           Generator& p = gs[i];
03409           // If it is the origin, erase it.
03410           if (p.all_homogeneous_terms_are_zero()) {
03411             --gs_num_rows;
03412             std::swap(p, gs[gs_num_rows]);
03413           }
03414           // Otherwise, transform the point into a ray.
03415           else {
03416             p[0] = 0;
03417             // Enforce normalization.
03418             p.normalize();
03419           }
03420         }
03421         break;
03422       default:
03423         // For rays and lines, nothing to be done.
03424         break;
03425       }
03426   // If it was present, erase the origin point or closure point,
03427   // which cannot be transformed into a valid ray or line.
03428   // For NNC polyhedra, also erase all the points of `gs',
03429   // whose role can be played by the closure points.
03430   // These have been previously moved to the end of `gs'.
03431   gs.erase_to_end(gs_num_rows);
03432   gs.unset_pending_rows();
03433 
03434   // `gs' may now have no rows.
03435   // Namely, this happens when `y' was the singleton polyhedron
03436   // having the origin as the one and only point.
03437   // In such a case, the resulting polyhedron is equal to `x'.
03438   if (gs_num_rows == 0)
03439     return;
03440 
03441   // If the polyhedron can have something pending, we add `gs'
03442   // to `gen_sys' as pending rows
03443   if (x.can_have_something_pending()) {
03444     x.gen_sys.add_pending_rows(gs);
03445     x.set_generators_pending();
03446   }
03447   // Otherwise, the two systems are merged.
03448   // `Linear_System::merge_rows_assign()' requires both systems to be sorted.
03449   else {
03450     if (!x.gen_sys.is_sorted())
03451       x.gen_sys.sort_rows();
03452     gs.sort_rows();
03453     x.gen_sys.merge_rows_assign(gs);
03454     // Only the system of generators is up-to-date.
03455     x.clear_constraints_up_to_date();
03456     x.clear_generators_minimized();
03457   }
03458   PPL_ASSERT_HEAVY(x.OK(true) && y.OK(true));
03459 }

void Parma_Polyhedra_Library::Polyhedron::topological_closure_assign (  ) 

Assigns to *this its topological closure.

Definition at line 3549 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(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

03549                                           {
03550   // Necessarily closed polyhedra are trivially closed.
03551   if (is_necessarily_closed())
03552     return;
03553   // Any empty or zero-dimensional polyhedron is closed.
03554   if (marked_empty() || space_dim == 0)
03555     return;
03556 
03557   // The computation can be done using constraints or generators.
03558   // If we use constraints, we will change them, so that having pending
03559   // constraints would be useless. If we use generators, we add generators,
03560   // so that having pending generators still makes sense.
03561 
03562   // Process any pending constraints.
03563   if (has_pending_constraints() && !process_pending_constraints())
03564     return;
03565 
03566   // Use constraints only if they are available and
03567   // there are no pending generators.
03568   if (!has_pending_generators() && constraints_are_up_to_date()) {
03569     const dimension_type eps_index = space_dim + 1;
03570     bool changed = false;
03571     // Transform all strict inequalities into non-strict ones.
03572     for (dimension_type i = con_sys.num_rows(); i-- > 0; ) {
03573       Constraint& c = con_sys[i];
03574       if (c[eps_index] < 0 && !c.is_tautological()) {
03575         c[eps_index] = 0;
03576         // Enforce normalization.
03577         c.normalize();
03578         changed = true;
03579       }
03580     }
03581     if (changed) {
03582       con_sys.insert(Constraint::epsilon_leq_one());
03583       con_sys.set_sorted(false);
03584       // After changing the system of constraints, the generators
03585       // are no longer up-to-date and the constraints are no longer
03586       // minimized.
03587       clear_generators_up_to_date();
03588       clear_constraints_minimized();
03589     }
03590   }
03591   else {
03592     // Here we use generators, possibly keeping constraints.
03593     PPL_ASSERT(generators_are_up_to_date());
03594     // Add the corresponding point to each closure point.
03595     gen_sys.add_corresponding_points();
03596     if (can_have_something_pending())
03597       set_generators_pending();
03598     else {
03599       // We cannot have pending generators; this also implies
03600       // that generators may have lost their sortedness.
03601       gen_sys.unset_pending_rows();
03602       gen_sys.set_sorted(false);
03603       // Constraints are not up-to-date and generators are not minimized.
03604       clear_constraints_up_to_date();
03605       clear_generators_minimized();
03606     }
03607   }
03608   PPL_ASSERT_HEAVY(OK());
03609 }

Topology Parma_Polyhedra_Library::Polyhedron::topology (  )  const [inline, private]
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 }

void Parma_Polyhedra_Library::Polyhedron::unconstrain ( const Variables_Set vars  ) 

Computes the cylindrification of *this with respect to the set of space dimensions vars, assigning the result to *this.

Parameters:
vars The set of space dimension that will be unconstrained.
Exceptions:
std::invalid_argument Thrown if *this is dimension-incompatible with one of the Variable objects contained in vars.

Definition at line 1859 of file Polyhedron_public.cc.

References can_have_something_pending(), clear_constraints_up_to_date(), clear_generators_minimized(), 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::line(), marked_empty(), OK(), process_pending_constraints(), set_generators_pending(), space_dim, Parma_Polyhedra_Library::Variables_Set::space_dimension(), throw_dimension_incompatible(), and update_generators().

01859                                                     {
01860   // The cylindrification wrt no dimensions is a no-op.
01861   // This case also captures the only legal cylindrification
01862   // of a polyhedron in a 0-dim space.
01863   if (vars.empty())
01864     return;
01865 
01866   // Dimension-compatibility check.
01867   const dimension_type min_space_dim = vars.space_dimension();
01868   if (space_dim < min_space_dim)
01869     throw_dimension_incompatible("unconstrain(vs)", min_space_dim);
01870 
01871   // Do something only if the polyhedron is non-empty.
01872   if (marked_empty()
01873       || (has_pending_constraints() && !process_pending_constraints())
01874       || (!generators_are_up_to_date() && !update_generators()))
01875     // Empty: do nothing.
01876     return;
01877 
01878   PPL_ASSERT(generators_are_up_to_date());
01879   // Since `gen_sys' is not empty, the topology and space dimension
01880   // of the inserted generators are automatically adjusted.
01881   Variables_Set::const_iterator vsi = vars.begin();
01882   Variables_Set::const_iterator vsi_end = vars.end();
01883   if (can_have_something_pending()) {
01884     for ( ; vsi != vsi_end; ++vsi)
01885       gen_sys.insert_pending(Generator::line(Variable(*vsi)));
01886     set_generators_pending();
01887   }
01888   else {
01889     for ( ; vsi != vsi_end; ++vsi)
01890       gen_sys.insert(Generator::line(Variable(*vsi)));
01891     // After adding the new generators,
01892     // constraints are no longer up-to-date.
01893     clear_generators_minimized();
01894     clear_constraints_up_to_date();
01895   }
01896   PPL_ASSERT_HEAVY(OK(true));
01897 }

void Parma_Polyhedra_Library::Polyhedron::unconstrain ( Variable  var  ) 

Computes the cylindrification of *this with respect to space dimension var, assigning the result to *this.

Parameters:
var The space dimension that will be unconstrained.
Exceptions:
std::invalid_argument Thrown if var is not a space dimension of *this.

Definition at line 1829 of file Polyhedron_public.cc.

References can_have_something_pending(), clear_constraints_up_to_date(), clear_generators_minimized(), 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::line(), marked_empty(), OK(), process_pending_constraints(), set_generators_pending(), space_dim, Parma_Polyhedra_Library::Variable::space_dimension(), throw_dimension_incompatible(), and update_generators().

Referenced by bounded_affine_preimage(), and generalized_affine_preimage().

01829                                              {
01830   // Dimension-compatibility check.
01831   if (space_dim < var.space_dimension())
01832     throw_dimension_incompatible("unconstrain(var)", var.space_dimension());
01833 
01834   // Do something only if the polyhedron is non-empty.
01835   if (marked_empty()
01836       || (has_pending_constraints() && !process_pending_constraints())
01837       || (!generators_are_up_to_date() && !update_generators()))
01838     // Empty: do nothing.
01839     return;
01840 
01841   PPL_ASSERT(generators_are_up_to_date());
01842   // Since `gen_sys' is not empty, the topology and space dimension
01843   // of the inserted generator are automatically adjusted.
01844   if (can_have_something_pending()) {
01845     gen_sys.insert_pending(Generator::line(var));
01846     set_generators_pending();
01847   }
01848   else {
01849     gen_sys.insert(Generator::line(var));
01850     // After adding the new generator,
01851     // constraints are no longer up-to-date.
01852     clear_generators_minimized();
01853     clear_constraints_up_to_date();
01854   }
01855   PPL_ASSERT_HEAVY(OK(true));
01856 }

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 805 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_recycled_constraints(), concatenate_assign(), constrains(), constraints(), drop_some_non_integer_points(), H79_widening_assign(), intersection_assign(), is_included_in(), minimize(), refine_no_check(), refine_with_constraints(), and relation_with().

00805                                         {
00806   PPL_ASSERT(space_dim > 0);
00807   PPL_ASSERT(!marked_empty());
00808   PPL_ASSERT(generators_are_up_to_date());
00809   // We assume the polyhedron has no pending constraints or generators.
00810   PPL_ASSERT(!has_something_pending());
00811 
00812   Polyhedron& x = const_cast<Polyhedron&>(*this);
00813   minimize(false, x.gen_sys, x.con_sys, x.sat_c);
00814   // `sat_c' is the only saturation matrix up-to-date.
00815   x.set_sat_c_up_to_date();
00816   x.clear_sat_g_up_to_date();
00817   // The system of constraints and the system of generators
00818   // are minimized.
00819   x.set_constraints_minimized();
00820   x.set_generators_minimized();
00821 }

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 824 of file Polyhedron_nonpublic.cc.

References clear_sat_c_up_to_date(), con_sys, constraints_are_up_to_date(), 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(), frequency(), generators(), is_bounded(), limited_BHRZ03_extrapolation_assign(), limited_H79_extrapolation_assign(), map_space_dimensions(), max_min(), minimize(), poly_hull_assign(), relation_with(), remove_higher_space_dimensions(), remove_space_dimensions(), select_H79_constraints(), time_elapse_assign(), and unconstrain().

00824                                        {
00825   PPL_ASSERT(space_dim > 0);
00826   PPL_ASSERT(!marked_empty());
00827   PPL_ASSERT(constraints_are_up_to_date());
00828   // We assume the polyhedron has no pending constraints or generators.
00829   PPL_ASSERT(!has_something_pending());
00830 
00831   Polyhedron& x = const_cast<Polyhedron&>(*this);
00832   // If the system of constraints is not consistent the
00833   // polyhedron is empty.
00834   const bool empty = minimize(true, x.con_sys, x.gen_sys, x.sat_g);
00835   if (empty)
00836     x.set_empty();
00837   else {
00838     // `sat_g' is the only saturation matrix up-to-date.
00839     x.set_sat_g_up_to_date();
00840     x.clear_sat_c_up_to_date();
00841     // The system of constraints and the system of generators
00842     // are minimized.
00843     x.set_constraints_minimized();
00844     x.set_generators_minimized();
00845   }
00846   return !empty;
00847 }

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 850 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Bit_Matrix::clear(), con_sys, constraints_are_minimized(), Parma_Polyhedra_Library::Linear_System::first_pending_row(), gen_sys, generators_are_minimized(), Parma_Polyhedra_Library::Bit_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().

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

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 882 of file Polyhedron_nonpublic.cc.

References Parma_Polyhedra_Library::Bit_Matrix::clear(), con_sys, constraints_are_minimized(), Parma_Polyhedra_Library::Linear_System::first_pending_row(), gen_sys, generators_are_minimized(), Parma_Polyhedra_Library::Bit_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(), BHZ09_C_poly_hull_assign_if_exact(), BHZ09_NNC_poly_hull_assign_if_exact(), obtain_sorted_generators_with_sat_g(), and select_H79_constraints().

00882                                   {
00883   PPL_ASSERT(constraints_are_minimized());
00884   PPL_ASSERT(generators_are_minimized());
00885   PPL_ASSERT(!sat_g_is_up_to_date());
00886 
00887   // We only consider non-pending rows.
00888   const dimension_type csr = con_sys.first_pending_row();
00889   const dimension_type gsr = gen_sys.first_pending_row();
00890   Polyhedron& x = const_cast<Polyhedron&>(*this);
00891 
00892   // The columns of `sat_g' represent generators and its
00893   // rows represent the constraints: resize accordingly.
00894   x.sat_g.resize(csr, gsr);
00895   for (dimension_type i = csr; i-- > 0; )
00896     for (dimension_type j = gsr; j-- > 0; ) {
00897       const int sp_sign = Scalar_Products::sign(con_sys[i], gen_sys[j]);
00898       // The negativity of this scalar product would mean
00899       // that the generator `gen_sys[j]' violates the constraint
00900       // `con_sys[i]' and it is not possible because both generators
00901       // and constraints are up-to-date.
00902       PPL_ASSERT(sp_sign >= 0);
00903       if (sp_sign > 0)
00904         // `gen_sys[j]' satisfies (without saturate) `con_sys[i]'.
00905         x.sat_g[i].set(j);
00906       else
00907         // `gen_sys[j]' saturates `con_sys[i]'.
00908         x.sat_g[i].clear(j);
00909     }
00910   x.set_sat_g_up_to_date();
00911 }

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

Same as poly_hull_assign(y).

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

References poly_hull_assign().

Referenced by BFT00_poly_hull_assign_if_exact(), and BHZ09_poly_hull_assign_if_exact().

00081                                                   {
00082   poly_hull_assign(y);
00083 }

void Parma_Polyhedra_Library::Polyhedron::widening_assign ( const Polyhedron y,
unsigned *  tp = 0 
) [inline]

Same as H79_widening_assign(y, tp).

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

References H79_widening_assign().

00091                                                              {
00092   H79_widening_assign(y, tp);
00093 }

void Parma_Polyhedra_Library::Polyhedron::wrap_assign ( const Variables_Set vars,
Bounded_Integer_Type_Width  w,
Bounded_Integer_Type_Representation  r,
Bounded_Integer_Type_Overflow  o,
const Constraint_System pcs = 0,
unsigned  complexity_threshold = 16,
bool  wrap_individually = true 
)

Wraps the specified dimensions of the vector space.

Parameters:
vars The set of Variable objects corresponding to the space dimensions to be wrapped.
w The width of the bounded integer type corresponding to all the dimensions to be wrapped.
r The representation of the bounded integer type corresponding to all the dimensions to be wrapped.
o The overflow behavior of the bounded integer type corresponding to all the dimensions to be wrapped.
pcs Possibly null pointer to a constraint system whose variables are contained in vars. If *pcs depends on variables not in vars, the behavior is undefined. When non-null, the pointed-to constraint system is assumed to represent the conditional or looping construct guard with respect to which wrapping is performed. Since wrapping requires the computation of upper bounds and due to non-distributivity of constraint refinement over upper bounds, passing a constraint system in this way can be more precise than refining the result of the wrapping operation with the constraints in *pcs.
complexity_threshold A precision parameter of the wrapping operator: higher values result in possibly improved precision.
wrap_individually true if the dimensions should be wrapped individually (something that results in much greater efficiency to the detriment of precision).
Exceptions:
std::invalid_argument Thrown if *pcs is dimension-incompatible with vars, or if *this is dimension-incompatible vars or with *pcs.

Definition at line 3756 of file Polyhedron_public.cc.

References is_necessarily_closed().

03762                                                      {
03763   if (is_necessarily_closed())
03764     Implementation::wrap_assign(static_cast<C_Polyhedron&>(*this),
03765                                 vars, w, r, o, pcs,
03766                                 complexity_threshold, wrap_individually,
03767                                 "C_Polyhedron");
03768   else
03769     Implementation::wrap_assign(static_cast<NNC_Polyhedron&>(*this),
03770                                 vars, w, r, o, pcs,
03771                                 complexity_threshold, wrap_individually,
03772                                 "NNC_Polyhedron");
03773 }


Friends And Related Function Documentation

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 378 of file Polyhedron.inlines.hh.

00378                                                      {
00379   return !(x == y);
00380 }

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 3777 of file Polyhedron_public.cc.

References is_empty(), and minimized_constraints().

03777                                                                {
03778   if (ph.is_empty())
03779     s << "false";
03780   else
03781     s << ph.minimized_constraints();
03782   return s;
03783 }

bool operator== ( const Polyhedron x,
const Polyhedron y 
) [friend]
friend class Parma_Polyhedra_Library::BD_Shape [friend]

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

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

friend class Parma_Polyhedra_Library::Box [friend]

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

friend class Parma_Polyhedra_Library::Grid [friend]

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

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

bool Parma_Polyhedra_Library::Interfaces::is_necessarily_closed_for_interfaces ( const Polyhedron  )  [friend]

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

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 52 of file algorithms.hh.

References Parma_Polyhedra_Library::Powerset< Parma_Polyhedra_Library::Determinate< PSET > >::begin(), contains(), and Parma_Polyhedra_Library::Powerset< Parma_Polyhedra_Library::Determinate< PSET > >::end().

00052                                               {
00053   PH phull = p;
00054   NNC_Polyhedron nnc_p(p);
00055   phull.poly_hull_assign(q);
00056   std::pair<PH, Pointset_Powerset<NNC_Polyhedron> >
00057     partition = linear_partition(q, phull);
00058   const Pointset_Powerset<NNC_Polyhedron>& s = partition.second;
00059   typedef Pointset_Powerset<NNC_Polyhedron>::const_iterator iter;
00060   for (iter i = s.begin(), s_end = s.end(); i != s_end; ++i)
00061     // The polyhedral hull is exact if and only if all the elements
00062     // of the partition of the polyhedral hull of `p' and `q' with
00063     // respect to `q' are included in `p'
00064     if (!nnc_p.contains(i->pointset()))
00065       return false;
00066   p = phull;
00067   return true;
00068 }

Specializes std::swap.

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

References swap().

00417                                            {
00418   x.swap(y);
00419 }


Member Data Documentation

PPL::dimension_type * Parma_Polyhedra_Library::Polyhedron::simplify_num_saturators_p = 0 [static, private]

Pointer to an array used by simplify().

Holds (between class initialization and finalization) a pointer to an array, allocated with operator new[](), of simplify_num_saturators_size elements.

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

Referenced by finalize(), initialize(), and simplify().

Dimension of an array used by simplify().

Holds (between class initialization and finalization) the size of the array pointed to by simplify_num_saturators_p.

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

Referenced by finalize(), initialize(), and simplify().

The number of dimensions of the enclosing vector space.

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

Referenced by add_congruence(), add_congruences(), add_constraint(), add_generator(), add_recycled_constraints(), add_recycled_generators(), add_space_dimensions_and_embed(), add_space_dimensions_and_project(), affine_dimension(), BFT00_poly_hull_assign_if_exact(), BHRZ03_combining_constraints(), BHRZ03_evolving_points(), BHRZ03_evolving_rays(), BHRZ03_widening_assign(), BHZ09_C_poly_hull_assign_if_exact(), BHZ09_NNC_poly_hull_assign_if_exact(), BHZ09_poly_hull_assign_if_exact(), bounds(), Parma_Polyhedra_Library::BHRZ03_Certificate::compare(), concatenate_assign(), constrains(), constraints(), contains(), contains_integer_point(), drop_some_non_integer_points(), expand_space_dimension(), fold_space_dimensions(), generators(), grid_generators(), H79_widening_assign(), intersection_assign(), 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(), Polyhedron(), process_pending(), process_pending_constraints(), process_pending_generators(), quick_equivalence_test(), refine_no_check(), refine_with_congruence(), refine_with_congruences(), refine_with_constraint(), refine_with_constraints(), relation_with(), remove_higher_space_dimensions(), remove_space_dimensions(), select_CH78_constraints(), select_H79_constraints(), set_zero_dim_univ(), simplify_using_context_assign(), space_dimension(), strongly_minimize_constraints(), strongly_minimize_generators(), swap(), time_elapse_assign(), unconstrain(), update_constraints(), and update_generators().


The documentation for this class was generated from the following files:
Generated on Sun Feb 27 16:20:26 2011 for PPL by  doxygen 1.6.3