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

The base class for convex polyhedra. More...

#include <Polyhedron.defs.hh>

Inheritance diagram for Parma_Polyhedra_Library::Polyhedron:

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

Collaboration graph
[legend]

List of all members.

Exception Throwers

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

Public 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 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).
bool add_constraint_and_minimize (const Constraint &c)
 Adds a copy of constraint c to the system of constraints of *this, minimizing the result.
void add_generator (const Generator &g)
 Adds a copy of generator g to the system of generators of *this (without minimizing the result).
bool add_generator_and_minimize (const Generator &g)
 Adds a copy of generator g to the system of generators of *this, minimizing the result.
void add_congruence (const Congruence &cg)
 Adds a copy of congruence cg to *this, if cg can be exactly represented by a polyhedron.
bool add_congruence_and_minimize (const Congruence &cg)
 Adds a copy of congruence cg to *this, if cg can be exactly represented by a polyhedron, minimizing the result.
void add_constraints (const Constraint_System &cs)
 Adds a copy of the constraints in cs to the system of constraints of *this (without minimizing the result).
void add_recycled_constraints (Constraint_System &cs)
 Adds the constraints in cs to the system of constraints of *this (without minimizing the result).
bool add_constraints_and_minimize (const Constraint_System &cs)
 Adds a copy of the constraints in cs to the system of constraints of *this, minimizing the result.
bool add_recycled_constraints_and_minimize (Constraint_System &cs)
 Adds the constraints in cs to the system of constraints of *this, minimizing the result.
void add_generators (const Generator_System &gs)
 Adds a copy of the generators in gs to the system of generators of *this (without minimizing the result).
void add_recycled_generators (Generator_System &gs)
 Adds the generators in gs to the system of generators of *this (without minimizing the result).
bool add_generators_and_minimize (const Generator_System &gs)
 Adds a copy of the generators in gs to the system of generators of *this, minimizing the result.
bool add_recycled_generators_and_minimize (Generator_System &gs)
 Adds the generators in gs to the system of generators of *this, minimizing the result.
void add_congruences (const Congruence_System &cgs)
 Adds a copy of the congruences in cgs to *this, if all the congruences can be exactly represented by a polyhedron.
bool add_congruences_and_minimize (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, minimizing the result.
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.
bool add_recycled_congruences_and_minimize (Congruence_System &cgs)
 Adds the congruences in cgs to *this, if all the congruences can be exactly represented by a polyhedron, minimizing the result.
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 &to_be_unconstrained)
 Computes the cylindrification of *this with respect to the set of space dimensions to_be_unconstrained, assigning the result to *this.
void intersection_assign (const Polyhedron &y)
 Assigns to *this the intersection of *this and y. The result is not guaranteed to be minimized.
bool intersection_assign_and_minimize (const Polyhedron &y)
 Assigns to *this the intersection of *this and y, minimizing the result.
void poly_hull_assign (const Polyhedron &y)
 Assigns to *this the poly-hull of *this and y. The result is not guaranteed to be minimized.
bool poly_hull_assign_and_minimize (const Polyhedron &y)
 Assigns to *this the poly-hull of *this and y, minimizing the result.
void upper_bound_assign (const Polyhedron &y)
 Same as poly_hull_assign(y).
void poly_difference_assign (const Polyhedron &y)
 Assigns to *this the poly-difference of *this and y. The result is not guaranteed to be minimized.
void difference_assign (const Polyhedron &y)
 Same as poly_difference_assign(y).
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 topological_closure_assign ()
 Assigns to *this its topological closure.
void BHRZ03_widening_assign (const Polyhedron &y, unsigned *tp=0)
 Assigns to *this the result of computing the BHRZ03-widening between *this and y.
void limited_BHRZ03_extrapolation_assign (const Polyhedron &y, const Constraint_System &cs, unsigned *tp=0)
 Improves the result of the BHRZ03-widening computation by also enforcing those constraints in cs that are satisfied by all the points of *this.
void bounded_BHRZ03_extrapolation_assign (const Polyhedron &y, const Constraint_System &cs, unsigned *tp=0)
 Improves the result of the BHRZ03-widening computation by also enforcing those constraints in cs that are satisfied by all the points of *this, plus all the constraints of the form $\pm x \leq r$ and $\pm x < r$, with $r \in \Qset$, that are satisfied by all the points of *this.
void H79_widening_assign (const Polyhedron &y, unsigned *tp=0)
 Assigns to *this the result of computing the H79-widening between *this and y.
void 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)
 Improves the result of the H79-widening computation by also enforcing those constraints in cs that are satisfied by all the points of *this.
void bounded_H79_extrapolation_assign (const Polyhedron &y, const Constraint_System &cs, unsigned *tp=0)
 Improves the result of the H79-widening computation by also enforcing those constraints in cs that are satisfied by all the points of *this, plus all the constraints of the form $\pm x \leq r$ and $\pm x < r$, with $r \in \Qset$, that are satisfied by all the points of *this.
Member Functions that May Modify the Dimension of the Vector Space
void add_space_dimensions_and_embed (dimension_type m)
 Adds m new space dimensions and embeds the old polyhedron in the new vector space.
void add_space_dimensions_and_project (dimension_type m)
 Adds m new space dimensions to the polyhedron and does not embed it in the new vector space.
void concatenate_assign (const Polyhedron &y)
 Assigns to *this the concatenation of *this and y, taken in this order.
void remove_space_dimensions (const Variables_Set &to_be_removed)
 Removes all the specified dimensions from the vector space.
void remove_higher_space_dimensions (dimension_type new_dimension)
 Removes the higher dimensions of the vector space so that the resulting space will have dimension new_dimension.
template<typename Partial_Function>
void map_space_dimensions (const Partial_Function &pfunc)
 Remaps the dimensions of the vector space according to a partial function.
void expand_space_dimension (Variable var, dimension_type m)
 Creates m copies of the space dimension corresponding to var.
void fold_space_dimensions (const Variables_Set &to_be_folded, Variable var)
 Folds the space dimensions in to_be_folded into var.
Miscellaneous Member Functions
 ~Polyhedron ()
 Destructor.
void swap (Polyhedron &y)
 Swaps *this with polyhedron y. (*this and y can be dimension-incompatible.).
void ascii_dump () const
 Writes to std::cerr an ASCII representation of *this.
void ascii_dump (std::ostream &s) const
 Writes to s an ASCII representation of *this.
void print () const
 Prints *this to std::cerr using operator<<.
bool ascii_load (std::istream &s)
 Loads from s an ASCII representation (as produced by ascii_dump(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.).

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 is_necessarily_closed_for_interfaces (const Polyhedron &)
 Returns true if and only if ph.topology() == NECESSARILY_CLOSED.

Related Functions

(Note that these are not member functions.)

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

Classes

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


Detailed Description

The base class for convex polyhedra.

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

A polyhedron can be specified as either a finite system of constraints or a finite system of generators (see Section Representations of Convex Polyhedra) and it is always possible to obtain either representation. That is, if we know the system of constraints, we can obtain from this the system of generators that define the same polyhedron and vice versa. These systems can contain redundant members: in this case we say that they are not in the minimal form.

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

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

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

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

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

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


Member Typedef Documentation

The numeric type of coefficients.

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


Member Enumeration Documentation

Enumerator:
TVB_TRUE 
TVB_FALSE 
TVB_DONT_KNOW 

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


Constructor & Destructor Documentation

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

Builds a polyhedron having the specified properties.

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

Definition at line 49 of file Polyhedron_nonpublic.cc.

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

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

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

Ordinary copy-constructor.

The complexity argument is ignored.

Definition at line 70 of file Polyhedron_nonpublic.cc.

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

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

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

Builds a polyhedron from a system of constraints.

The polyhedron inherits the space dimension of the constraint system.

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

Definition at line 87 of file Polyhedron_nonpublic.cc.

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

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

Parma_Polyhedra_Library::Polyhedron::Polyhedron ( Topology  topol,
Constraint_System cs,
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 136 of file Polyhedron_nonpublic.cc.

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

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

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

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

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

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

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 34 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(), 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(), Parma_Polyhedra_Library::Constraint_System::swap(), and TEMP_INTEGER.

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

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

Destructor.

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

00095                         {
00096 }


Member Function Documentation

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

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

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

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

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

00111                                            {
00112   return true;
00113 }

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

Initializes the class.

Definition at line 42 of file Polyhedron_public.cc.

References simplify_num_saturators_p, and simplify_num_saturators_size.

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

Finalizes the class.

Definition at line 49 of file Polyhedron_public.cc.

References simplify_num_saturators_p, and simplify_num_saturators_size.

00049                         {
00050   delete [] simplify_num_saturators_p;
00051   simplify_num_saturators_p = 0;
00052   simplify_num_saturators_size = 0;
00053 }

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

Returns false indicating that this domain cannot recycle congruences.

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

00117                                            {
00118   return false;
00119 }

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

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

Definition at line 310 of file Polyhedron_nonpublic.cc.

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

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

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

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

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

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

Definition at line 56 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< PS >::affine_dimension(), and is_discrete().

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

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

Returns the system of constraints.

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

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

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

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

Returns the system of generators.

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

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

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

Returns the system of generators, with no redundant generator.

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

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

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

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

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

References minimized_constraints().

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

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

References minimized_constraints().

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

PPL::Grid_Generator_System Parma_Polyhedra_Library::Polyhedron::grid_generators (  )  const

Returns a universe system of grid generators.

Definition at line 194 of file Polyhedron_public.cc.

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

Referenced by minimized_grid_generators().

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

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

Returns a universe system of grid generators.

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

References grid_generators().

00366                                             {
00367   return grid_generators();
00368 }

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

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

Referenced by BHRZ03_combining_constraints(), BHRZ03_evolving_points(), BHRZ03_evolving_rays(), poly_difference_assign(), and relation_with().

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

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

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

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

References assign(), Parma_Polyhedra_Library::Generator_System::begin(), Parma_Polyhedra_Library::Congruence::coefficient(), 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::Congruence::inhomogeneous_term(), 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(), 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(), TEMP_INTEGER, throw_dimension_incompatible(), and update_generators().

00272                                                        {
00273   dimension_type cg_space_dim = cg.space_dimension();
00274   // Dimension-compatibility check.
00275   if (space_dim < cg_space_dim)
00276     throw_dimension_incompatible("relation_with(cg)", "cg", cg);
00277 
00278   if (cg.is_equality()) {
00279     const Constraint c(cg);
00280     return relation_with(c);
00281   }
00282 
00283   if (marked_empty())
00284     return Poly_Con_Relation::saturates()
00285       && Poly_Con_Relation::is_included()
00286       && Poly_Con_Relation::is_disjoint();
00287 
00288   if (space_dim == 0) {
00289     if (cg.is_inconsistent())
00290       return Poly_Con_Relation::is_disjoint();
00291     else
00292       return Poly_Con_Relation::saturates()
00293         && Poly_Con_Relation::is_included();
00294   }
00295 
00296   if ((has_pending_constraints() && !process_pending_constraints())
00297       || (!generators_are_up_to_date() && !update_generators()))
00298     // The polyhedron is empty.
00299     return Poly_Con_Relation::saturates()
00300       && Poly_Con_Relation::is_included()
00301       && Poly_Con_Relation::is_disjoint();
00302 
00303   // Find the equality corresponding to the congruence (ignoring the modulus).
00304   Linear_Expression expr;
00305   for (dimension_type i = cg_space_dim; i-- > 0; ) {
00306     const Variable v(i);
00307     expr += cg.coefficient(v) * v;
00308   }
00309   expr += cg.inhomogeneous_term();
00310   Constraint c(expr == 0);
00311 
00312   // The polyhedron is non-empty so that there exists a point.
00313   // For an arbitrary generator point find the scalar product with
00314   // the equality.
00315   TEMP_INTEGER(point_val);
00316 
00317   for (Generator_System::const_iterator g = gen_sys.begin(),
00318          gen_sys_end = gen_sys.end(); g != gen_sys_end; ++g) {
00319     if (g->is_point()) {
00320       Scalar_Products::assign(point_val, c, *g);
00321       break;
00322     }
00323   }
00324 
00325   // Find the 2 hyperplanes that satisfies the congruence and are
00326   // nearest to the point such that the point lies on or between these
00327   // hyperplanes.
00328   // Then use the relations between the polyhedron and the corresponding
00329   // half-spaces to determine its relation with the congruence.
00330   const Coefficient& modulus = cg.modulus();
00331 
00332   TEMP_INTEGER(div);
00333   div = modulus;
00334 
00335   TEMP_INTEGER(nearest);
00336   nearest = (point_val / div) * div;
00337 
00338   point_val -= nearest;
00339   expr -= nearest;
00340   if (point_val == 0)
00341      return relation_with(expr == 0);
00342 
00343   Linear_Expression next_expr;
00344   if (point_val > 0) {
00345      next_expr = expr - modulus;
00346   }
00347   else {
00348     expr = - (expr);
00349     next_expr = expr - modulus;
00350   }
00351 
00352   Poly_Con_Relation relations = relation_with(expr >= 0);
00353   assert(!relations.implies(Poly_Con_Relation::saturates())
00354          && !relations.implies(Poly_Con_Relation::is_disjoint()));
00355   if (relations.implies(Poly_Con_Relation::strictly_intersects()))
00356     return Poly_Con_Relation::strictly_intersects();
00357 
00358   assert(relations == Poly_Con_Relation::is_included());
00359   Poly_Con_Relation next_relations = relation_with(next_expr <= 0);
00360   assert(!next_relations.implies(Poly_Con_Relation::saturates())
00361          && !next_relations.implies(Poly_Con_Relation::is_disjoint()));
00362   if (next_relations.implies(Poly_Con_Relation::strictly_intersects()))
00363     return Poly_Con_Relation::strictly_intersects();
00364 
00365   assert(next_relations == Poly_Con_Relation::is_included());
00366   return Poly_Con_Relation::is_disjoint();
00367 }

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

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

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

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

Referenced by affine_dimension(), Parma_Polyhedra_Library::Box< ITV >::Box(), Parma_Polyhedra_Library::Pointset_Powerset< PS >::check_containment(), contains(), generalized_affine_image(), generalized_affine_preimage(), Parma_Polyhedra_Library::Grid::Grid(), H79_widening_assign(), is_disjoint_from(), Parma_Polyhedra_Library::Pointset_Powerset< PS >::linear_partition_aux(), operator<<(), Parma_Polyhedra_Library::Pointset_Powerset< PS >::Pointset_Powerset(), and simplify_using_context_assign().

00179                            {
00180   if (marked_empty())
00181     return true;
00182   // Try a fast-fail test: if generators are up-to-date and
00183   // there are no pending constraints, then the generator system
00184   // (since it is well formed) contains a point.
00185   if (generators_are_up_to_date() && !has_pending_constraints())
00186     return false;
00187   return !minimize();
00188 }

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   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     assert(generators_are_minimized());
00408     if (num_lines == space_dim) {
00409       assert(num_rays == 0);
00410       return true;
00411     }
00412     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       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       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         assert(eps_leq_one[i] == 0 && eps_geq_zero[i] == 0);
00487 #endif
00488       return true;
00489     }
00490   }
00491 }

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

References intersection_assign(), and is_empty().

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

03810                                                          {
03811   Polyhedron z = *this;
03812   z.intersection_assign(y);
03813   return z.is_empty();
03814 }

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

Returns true if and only if *this is discrete.

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

References affine_dimension().

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

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::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::Checked::le(), marked_empty(), Parma_Polyhedra_Library::Matrix::num_rows(), process_pending(), space_dim, Parma_Polyhedra_Library::Constraint::STRICT_INEQUALITY, TEMP_INTEGER, 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 true;
00574 
00575   // FIXME: do also exploit info regarding rays and lines, if possible.
00576   // Is any integer point already available?
00577   if (generators_are_up_to_date() && !has_pending_constraints())
00578     for (dimension_type i = gen_sys.num_rows(); i-- > 0; )
00579       if (gen_sys[i].is_point() && gen_sys[i].divisor() == 1)
00580         return true;
00581 
00582   const Constraint_System& cs = constraints();
00583 #if 0 // TEMPORARILY DISABLED.
00584   MIP_Problem mip(space_dim,
00585                   cs.begin(), cs.end(),
00586                   Variables_Set(Variable(0), Variable(space_dim-1)));
00587 #else
00588   // FIXME: temporary workaround, to be removed as soon as the MIP
00589   // problem class will correctly and precisely handle
00590   // ((strict) in-) equality constraints having all integer variables.
00591   MIP_Problem mip(space_dim);
00592   mip.add_to_integer_space_dimensions(Variables_Set(Variable(0),
00593                                                     Variable(space_dim-1)));
00594   TEMP_INTEGER(homogeneous_gcd);
00595   TEMP_INTEGER(gcd);
00596   DIRTY_TEMP0(mpq_class, rational_inhomogeneous);
00597   TEMP_INTEGER(tightened_inhomogeneous);
00598   for (Constraint_System::const_iterator cs_i = cs.begin(),
00599          cs_end = cs.end(); cs_i != cs_end; ++cs_i) {
00600     const Constraint& c = *cs_i;
00601     const Constraint::Type c_type = c.type();
00602     const Coefficient& inhomogeneous = c.inhomogeneous_term();
00603     if (c_type == Constraint::STRICT_INEQUALITY) {
00604       // CHECKME: should we change the behavior of Linear_Expression(c) ?
00605       // Compute the GCD of the coefficients of c
00606       // (disregarding the inhomogeneous term and the espilon dimension).
00607       homogeneous_gcd = 0;
00608       for (dimension_type i = space_dim; i-- > 0; )
00609         gcd_assign(homogeneous_gcd,
00610                    homogeneous_gcd, c.coefficient(Variable(i)));
00611       Linear_Expression le;
00612       for (dimension_type i = space_dim; i-- > 0; )
00613         le += (c.coefficient(Variable(i)) / homogeneous_gcd) * Variable(i);
00614       // Add the integer part of `inhomogeneous'.
00615       le += (inhomogeneous / homogeneous_gcd);
00616       // Further tighten the constraint if the inhomogeneous term
00617       // was integer, i.e., if `homogeneous_gcd' divides `inhomogeneous'.
00618       gcd_assign(gcd, homogeneous_gcd, inhomogeneous);
00619       if (gcd == homogeneous_gcd)
00620         le -= 1;
00621       mip.add_constraint(le >= 0);
00622     }
00623     else {
00624       // Equality or non-strict inequality.
00625       // If possible, avoid useless gcd computations.
00626       if (inhomogeneous == 0)
00627         // The inhomogeneous term cannot be tightened.
00628         mip.add_constraint(c);
00629       else {
00630         // Compute the GCD of the coefficients of c
00631         // (disregarding the inhomogeneous term)
00632         // to see whether or not the inhomogeneous term can be tightened.
00633         homogeneous_gcd = 0;
00634         for (dimension_type i = space_dim; i-- > 0; )
00635           gcd_assign(homogeneous_gcd,
00636                      homogeneous_gcd, c.coefficient(Variable(i)));
00637         if (homogeneous_gcd == 1)
00638           // The normalized inhomogeneous term is integer:
00639           // add the constraint as-is.
00640           mip.add_constraint(c);
00641         else {
00642           assert(homogeneous_gcd > 1);
00643           // Here the normalized inhomogeneous term is rational:
00644           // the constraint has to be tightened.
00645 #ifndef NDEBUG
00646           // `homogeneous_gcd' does not divide `inhomogeneous'.
00647           // FIXME: add a divisibility test for Coefficient.
00648           gcd_assign(gcd, homogeneous_gcd, inhomogeneous);
00649           assert(gcd == 1);
00650 #endif
00651           if (c.type() == Constraint::EQUALITY)
00652             return false;
00653           // Extract the homogeneous part of the constraint.
00654           Linear_Expression le = Linear_Expression(c);
00655           le -= inhomogeneous;
00656           // Tighten the inhomogeneous term.
00657           assign_r(rational_inhomogeneous.get_num(),
00658                    inhomogeneous, ROUND_NOT_NEEDED);
00659           assign_r(rational_inhomogeneous.get_den(),
00660                    homogeneous_gcd, ROUND_NOT_NEEDED);
00661           // Note: canonicalization is not needed (as gcd == 1).
00662           assert(is_canonical(rational_inhomogeneous));
00663           assign_r(tightened_inhomogeneous,
00664                    rational_inhomogeneous, ROUND_DOWN);
00665           tightened_inhomogeneous *= homogeneous_gcd;
00666           le += tightened_inhomogeneous;
00667           mip.add_constraint(le >= 0);
00668         }
00669       }
00670     }
00671   }
00672 #endif // TEMPORARY WORKAROUND.
00673   return mip.is_satisfiable();
00674 }

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

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

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

References bounds().

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

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

References bounds().

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

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

References max_min().

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

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

References max_min().

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

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

References max_min().

Referenced by Parma_Polyhedra_Library::BHRZ03_Certificate::BHRZ03_Certificate(), BHRZ03_combining_constraints(), BHRZ03_evolving_points(), BHRZ03_evolving_rays(), BHRZ03_widening_assign(), 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(), intersection_assign_and_minimize(), is_included_in(), limited_BHRZ03_extrapolation_assign(), limited_H79_extrapolation_assign(), poly_difference_assign(), poly_hull_assign_and_minimize(), and simplify_using_context_assign().

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

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

References max_min().

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

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

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

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

03786                                                  {
03787   const Polyhedron& x = *this;
03788 
03789   // Topology compatibility check.
03790   if (x.topology() != y.topology())
03791     throw_topology_incompatible("contains(y)", "y", y);
03792 
03793   // Dimension-compatibility check.
03794   if (x.space_dim != y.space_dim)
03795     throw_dimension_incompatible("contains(y)", "y", y);
03796 
03797   if (y.marked_empty())
03798     return true;
03799   else if (x.marked_empty())
03800     return y.is_empty();
03801   else if (y.space_dim == 0)
03802     return true;
03803   else if (x.quick_equivalence_test(y) == Polyhedron::TVB_TRUE)
03804     return true;
03805   else
03806     return y.is_included_in(x);
03807 }

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

References contains().

00399                                                        {
00400   const Polyhedron& x = *this;
00401   return x.contains(y) && !y.contains(x);
00402 }

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 766 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(), empty, 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_recycled_generators_and_minimize(), add_space_dimensions_and_embed(), add_space_dimensions_and_project(), affine_image(), affine_preimage(), ascii_load(), BHRZ03_combining_constraints(), BHRZ03_evolving_points(), BHRZ03_evolving_rays(), BHRZ03_widening_assign(), bounded_affine_image(), bounded_affine_preimage(), Parma_Polyhedra_Library::C_Polyhedron::C_Polyhedron(), concatenate_assign(), expand_space_dimension(), fold_space_dimensions(), generalized_affine_image(), generalized_affine_preimage(), H79_widening_assign(), intersection_assign(), intersection_assign_and_minimize(), is_included_in(), limited_BHRZ03_extrapolation_assign(), limited_H79_extrapolation_assign(), map_space_dimensions(), minimize(), Parma_Polyhedra_Library::NNC_Polyhedron::NNC_Polyhedron(), poly_difference_assign(), poly_hull_assign(), poly_hull_assign_and_minimize(), Polyhedron(), 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().

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

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 1237 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< PS >::affine_dimension(), Parma_Polyhedra_Library::C_Polyhedron::C_Polyhedron(), and Parma_Polyhedra_Library::Pointset_Powerset< PS >::linear_partition_aux().

01237                                                  {
01238   // Topology-compatibility check.
01239   if (c.is_strict_inequality() && is_necessarily_closed()) {
01240     // Trivially true/false strict inequalities are legal.
01241     if (c.is_tautological())
01242       return;
01243     if (c.is_inconsistent()) {
01244       set_empty();
01245       return;
01246     }
01247     // Here c is a non-trivial strict inequality.
01248     throw_topology_incompatible("add_constraint(c)", "c", c);
01249   }
01250 
01251   // Dimension-compatibility check:
01252   // the dimension of `c' can not be greater than space_dim.
01253   if (space_dim < c.space_dimension())
01254     throw_dimension_incompatible("add_constraint(c)", "c", c);
01255 
01256   if (!marked_empty())
01257     refine_no_check(c);
01258 }

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

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

Parameters:
c The constraint that will be added to the system of constraints of *this.
Returns:
false if and only if the result is empty.
Exceptions:
std::invalid_argument Thrown if *this and constraint c are topology-incompatible or dimension-incompatible.
Deprecated:
See A Note on the Implementation of the Operators.

Definition at line 1299 of file Polyhedron_public.cc.

References add_recycled_constraints_and_minimize().

01299                                                               {
01300   Constraint_System cs(c);
01301   return add_recycled_constraints_and_minimize(cs);
01302 }

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

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

Referenced by generalized_affine_image().

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

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

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

Returns:
false if and only if the result is empty.
Exceptions:
std::invalid_argument Thrown if *this and generator g are topology-incompatible or dimension-incompatible, or if *this is an empty polyhedron and g is not a point.
Deprecated:
See A Note on the Implementation of the Operators.

Definition at line 1440 of file Polyhedron_public.cc.

References add_recycled_generators_and_minimize().

01440                                                             {
01441   // TODO: this is just an executable specification.
01442   Generator_System gs(g);
01443   return add_recycled_generators_and_minimize(gs);
01444 }

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

Referenced by add_congruence_and_minimize().

01261                                                   {
01262   // Dimension-compatibility check:
01263   // the dimension of `cg' can not be greater than space_dim.
01264   if (space_dim < cg.space_dimension())
01265     throw_dimension_incompatible("add_congruence(cg)", "cg", cg);
01266 
01267   // Handle the case of proper congruences first.
01268   if (cg.is_proper_congruence()) {
01269     if (cg.is_tautological())
01270       return;
01271     if (cg.is_inconsistent()) {
01272       set_empty();
01273       return;
01274     }
01275     // Non-trivial and proper congruences are not allowed.
01276     throw_invalid_argument("add_congruence(cg)",
01277                            "cg is a non-trivial, proper congruence");
01278   }
01279 
01280   assert(cg.is_equality());
01281   // Handle empty and 0-dim cases first.
01282   if (marked_empty())
01283     return;
01284   if (space_dim == 0) {
01285     if (cg.is_inconsistent())
01286       set_empty();
01287     return;
01288   }
01289 
01290   // Add the equality.
01291   Linear_Expression le(cg);
01292   Constraint c(le, Constraint::EQUALITY, NECESSARILY_CLOSED);
01293   // Enforce normalization.
01294   c.strong_normalize();
01295   refine_no_check(c);
01296 }

bool Parma_Polyhedra_Library::Polyhedron::add_congruence_and_minimize ( const Congruence cg  )  [inline]

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

Returns:
false if and only if the result is empty.
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.
Deprecated:
See A Note on the Implementation of the Operators.

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

References add_congruence(), and minimize().

00371                                                             {
00372   add_congruence(cg);
00373   return minimize();
00374 }

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_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(), add_recycled_constraints_and_minimize(), 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   assert(OK());
01537 }

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

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

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

Definition at line 1553 of file Polyhedron_public.cc.

References add_recycled_constraints_and_minimize().

01553                                                                        {
01554   Constraint_System cs_copy = cs;
01555   return add_recycled_constraints_and_minimize(cs_copy);
01556 }

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

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

Returns:
false if and only if the result is empty.
Parameters:
cs The constraint system 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.
Deprecated:
See A Note on the Implementation of the Operators.

Definition at line 1547 of file Polyhedron_public.cc.

References add_recycled_constraints(), and minimize().

Referenced by add_constraint_and_minimize(), and add_constraints_and_minimize().

01547                                                                           {
01548   add_recycled_constraints(cs);
01549   return minimize();
01550 }

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

References add_recycled_generators().

01652                                                         {
01653   // TODO: this is just an executable specification.
01654   Generator_System gs_copy = gs;
01655   add_recycled_generators(gs_copy);
01656 }

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 1559 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(), Parma_Polyhedra_Library::Polyhedron::Status::set_zero_dim_univ(), space_dim, Parma_Polyhedra_Library::Generator_System::space_dimension(), status, Parma_Polyhedra_Library::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().

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

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

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

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

Definition at line 1733 of file Polyhedron_public.cc.

References add_recycled_generators_and_minimize().

01733                                                                      {
01734   // TODO: this is just an executable specification.
01735   Generator_System gs_copy = gs;
01736   return add_recycled_generators_and_minimize(gs_copy);
01737 }

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

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

Returns:
false if and only if the result is empty.
Parameters:
gs The generator system 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 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.
Deprecated:
See A Note on the Implementation of the Operators.

Definition at line 1659 of file Polyhedron_public.cc.

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

Referenced by add_generator_and_minimize(), and add_generators_and_minimize().

01659                                                                         {
01660   // Topology compatibility check.
01661   if (is_necessarily_closed() && gs.has_closure_points())
01662     throw_topology_incompatible("add_recycled_generators_and_minimize(gs)",
01663                                 "gs", gs);
01664   // Dimension-compatibility check:
01665   // the dimension of `gs' can not be greater than space_dim.
01666   const dimension_type gs_space_dim = gs.space_dimension();
01667   if (space_dim < gs_space_dim)
01668     throw_dimension_incompatible("add_recycled_generators_and_minimize(gs)",
01669                                  "gs", gs);
01670 
01671   // Adding no generators is equivalent to just requiring minimization.
01672   if (gs.has_no_rows())
01673     return minimize();
01674 
01675   // Adding valid generators to a zero-dimensional polyhedron
01676   // transform it in the zero-dimensional universe polyhedron.
01677   if (space_dim == 0) {
01678     if (marked_empty() && !gs.has_points())
01679       throw_invalid_generators("add_recycled_generators_and_minimize(gs)",
01680                                "gs");
01681     status.set_zero_dim_univ();
01682     assert(OK(true));
01683     return true;
01684   }
01685 
01686   // Adjust `gs' to the right topology.
01687   // NOTE: we already checked for topology compatibility;
01688   // also, we do NOT adjust dimensions now, so that we will
01689   // spend less time to sort rows.
01690   gs.adjust_topology_and_space_dimension(topology(), gs_space_dim);
01691 
01692   // For NNC polyhedra, each point must be matched by
01693   // the corresponding closure point.
01694   if (!is_necessarily_closed())
01695     gs.add_corresponding_closure_points();
01696 
01697   // `gs' has to be fully sorted, thus it cannot have pending rows.
01698   if (gs.num_pending_rows() > 0) {
01699     gs.unset_pending_rows();
01700     gs.sort_rows();
01701   }
01702   else if (!gs.is_sorted())
01703     gs.sort_rows();
01704 
01705   // Now adjusting dimensions (topology already adjusted).
01706   // NOTE: sortedness is preserved.
01707   gs.adjust_topology_and_space_dimension(topology(), space_dim);
01708 
01709   if (minimize()) {
01710     obtain_sorted_generators_with_sat_g();
01711     // This call to `add_and_minimize()' cannot return `false'.
01712     add_and_minimize(false, gen_sys, con_sys, sat_g, gs);
01713     clear_sat_c_up_to_date();
01714   }
01715   else {
01716     // The polyhedron was empty: check if `gs' contains a point.
01717     if (!gs.has_points())
01718       throw_invalid_generators("add_recycled_generators_and_minimize(gs)",
01719                                "gs");
01720     // `gs' has a point: the polyhedron is no longer empty
01721     // and generators are up-to-date.
01722     std::swap(gen_sys, gs);
01723     clear_empty();
01724     set_generators_up_to_date();
01725     // This call to `minimize()' cannot return `false'.
01726     minimize();
01727   }
01728   assert(OK(true));
01729   return true;
01730 }

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 1740 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_congruences_and_minimize(), add_recycled_congruences(), Parma_Polyhedra_Library::C_Polyhedron::C_Polyhedron(), and Parma_Polyhedra_Library::NNC_Polyhedron::NNC_Polyhedron().

01740                                                            {
01741   // Dimension-compatibility check.
01742   if (space_dim < cgs.space_dimension())
01743     throw_dimension_incompatible("add_congruences(cgs)", "cgs", cgs);
01744 
01745   Constraint_System cs;
01746   bool inserted = false;
01747   for (Congruence_System::const_iterator i = cgs.begin(),
01748          cgs_end = cgs.end(); i != cgs_end; ++i) {
01749     const Congruence& cg = *i;
01750     if (cg.is_equality()) {
01751       Linear_Expression le(cg);
01752       Constraint c(le, Constraint::EQUALITY, NECESSARILY_CLOSED);
01753       // Enforce normalization.
01754       c.strong_normalize();
01755       // TODO: Consider stealing the row in c when adding it to cs.
01756       cs.insert(c);
01757       inserted = true;
01758     }
01759     else {
01760       assert(cg.is_proper_congruence());
01761       if (cg.is_inconsistent()) {
01762         set_empty();
01763         return;
01764       }
01765       if (!cg.is_tautological())
01766         throw_invalid_argument("add_congruences(cgs)",
01767                                "cgs has a non-trivial, proper congruence");
01768     }
01769   }
01770   // Only add cs if it contains something.
01771   if (inserted)
01772     add_recycled_constraints(cs);
01773 }

bool Parma_Polyhedra_Library::Polyhedron::add_congruences_and_minimize ( const Congruence_System cgs  )  [inline]

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

Returns:
false if and only if the result is empty.
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
Deprecated:
See A Note on the Implementation of the Operators.

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

References add_congruences(), and minimize().

Referenced by add_recycled_congruences_and_minimize().

00377                                                                      {
00378   add_congruences(cgs);
00379   return minimize();
00380 }

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

References add_congruences().

00383                                                            {
00384   add_congruences(cgs);
00385 }

bool Parma_Polyhedra_Library::Polyhedron::add_recycled_congruences_and_minimize ( Congruence_System cgs  )  [inline]

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

Returns:
false if and only if the result is empty.
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.
Deprecated:
See A Note on the Implementation of the Operators.

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

References add_congruences_and_minimize().

00388                                                                         {
00389   return add_congruences_and_minimize(cgs);
00390 }

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

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

01776                                                          {
01777   // Dimension-compatibility check.
01778   if (space_dim < c.space_dimension())
01779     throw_dimension_incompatible("refine_with_constraint(c)", "c", c);
01780   // If the polyhedron is known to be empty, do nothing.
01781   if (!marked_empty())
01782     refine_no_check(c);
01783 }

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

01786                                                           {
01787   // Dimension-compatibility check.
01788   if (space_dim < cg.space_dimension())
01789     throw_dimension_incompatible("refine_with_congruence(cg)", "cg", cg);
01790 
01791   // If the polyhedron is known to be empty, do nothing.
01792   if (marked_empty())
01793     return;
01794 
01795   // Dealing with a zero-dimensional space polyhedron first.
01796   if (space_dim == 0) {
01797     if (!cg.is_tautological())
01798       set_empty();
01799     return;
01800   }
01801 
01802   if (cg.is_equality()) {
01803     Linear_Expression le(cg);
01804     Constraint c(le, Constraint::EQUALITY, NECESSARILY_CLOSED);
01805     // Enforce normalization.
01806     c.strong_normalize();
01807     refine_no_check(c);
01808   }
01809 }

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

01812                                                                   {
01813   // TODO: this is just an executable specification.
01814 
01815   // Dimension-compatibility check.
01816   const dimension_type cs_space_dim = cs.space_dimension();
01817   if (space_dim < cs_space_dim)
01818     throw_dimension_incompatible("refine_with_constraints(cs)a",
01819                                  "cs", cs);
01820 
01821   // Adding no constraints is a no-op.
01822   if (cs.has_no_rows())
01823     return;
01824 
01825   if (space_dim == 0) {
01826     // In a 0-dimensional space the constraints are
01827     // tautologies (e.g., 0 == 0 or 1 >= 0 or 1 > 0) or
01828     // inconsistent (e.g., 1 == 0 or -1 >= 0 or 0 > 0).
01829     // In a system of constraints `begin()' and `end()' are equal
01830     // if and only if the system only contains tautologies.
01831     if (cs.begin() != cs.end())
01832       // There is a constraint, it must be inconsistent,
01833       // the polyhedron is empty.
01834       status.set_empty();
01835     return;
01836   }
01837 
01838   if (marked_empty())
01839     return;
01840 
01841   // The constraints (possibly with pending rows) are required.
01842   if (has_pending_generators())
01843     process_pending_generators();
01844   else if (!constraints_are_up_to_date())
01845     update_constraints();
01846 
01847   const bool adding_pending = can_have_something_pending();
01848   for (dimension_type i = cs.num_rows(); i-- > 0; ) {
01849     const Constraint& c = cs[i];
01850 
01851     if (c.is_necessarily_closed() || !is_necessarily_closed())
01852       // Since `con_sys' is not empty, the topology and space dimension
01853       // of the inserted constraint are automatically adjusted.
01854       if (adding_pending)
01855         con_sys.insert_pending(c);
01856       else
01857         con_sys.insert(c);
01858     else {
01859       // Here we know that *this is necessarily closed so even if c is
01860       // topologically closed, by barely invoking `con_sys.insert(c)' we
01861       // would cause a change in the topology of `con_sys', which is
01862       // wrong.  Thus, we insert a topology closed and "topology
01863       // corrected" version of `c'.
01864       Linear_Expression nc_expr = Linear_Expression(c);
01865       if (c.is_equality())
01866         if (adding_pending)
01867           con_sys.insert_pending(nc_expr == 0);
01868         else
01869           con_sys.insert(nc_expr == 0);
01870       else
01871         if (adding_pending)
01872           con_sys.insert_pending(nc_expr >= 0);
01873         else
01874           con_sys.insert(nc_expr >= 0);
01875     }
01876   }
01877 
01878   if (adding_pending)
01879     set_constraints_pending();
01880   else {
01881     // Constraints are not minimized and generators are not up-to-date.
01882     clear_constraints_minimized();
01883     clear_generators_up_to_date();
01884   }
01885 
01886   // Note: the constraint system may have become unsatisfiable, thus
01887   // we do not check for satisfiability.
01888   assert(OK());
01889 }

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

01892                                                                    {
01893   // Dimension-compatibility check.
01894   if (space_dim < cgs.space_dimension())
01895     throw_dimension_incompatible("refine_with_congruences(cgs)", "cgs", cgs);
01896 
01897   Constraint_System cs;
01898   bool inserted = false;
01899   for (Congruence_System::const_iterator i = cgs.begin(),
01900          cgs_end = cgs.end(); i != cgs_end; ++i) {
01901     if (i->is_equality()) {
01902       Linear_Expression le(*i);
01903       Constraint c(le, Constraint::EQUALITY, NECESSARILY_CLOSED);
01904       // Enforce normalization.
01905       c.strong_normalize();
01906       // TODO: Consider stealing the row in c when adding it to cs.
01907       cs.insert(c);
01908       inserted = true;
01909     }
01910     else if (i->is_inconsistent()) {
01911       set_empty();
01912       return;
01913     }
01914   }
01915   // Only add cgs if congruences were inserted into cgs, as the
01916   // dimension of cs must be at most that of the polyhedron.
01917   if (inserted)
01918     add_recycled_constraints(cs);
01919 }

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 1922 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::Variable::id(), 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, throw_dimension_incompatible(), and update_generators().

Referenced by bounded_affine_preimage(), and generalized_affine_preimage().

01922                                              {
01923   // Dimension-compatibility check.
01924   if (space_dim < var.id())
01925     throw_dimension_incompatible("unconstrain(var)", var.id());
01926 
01927   // Do something only if the polyhedron is non-empty.
01928   if (marked_empty()
01929       || (has_pending_constraints() && !process_pending_constraints())
01930       || (!generators_are_up_to_date() && !update_generators()))
01931     // Empty: do nothing.
01932     return;
01933 
01934   assert(generators_are_up_to_date());
01935   // Since `gen_sys' is not empty, the topology and space dimension
01936   // of the inserted generator are automatically adjusted.
01937   if (can_have_something_pending()) {
01938     gen_sys.insert_pending(Generator::line(var));
01939     set_generators_pending();
01940   }
01941   else {
01942     gen_sys.insert(Generator::line(var));
01943     // After adding the new generator,
01944     // constraints are no longer up-to-date.
01945     clear_generators_minimized();
01946     clear_constraints_up_to_date();
01947   }
01948   assert(OK(true));
01949 }

void Parma_Polyhedra_Library::Polyhedron::unconstrain ( const Variables_Set &  to_be_unconstrained  ) 

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

Parameters:
to_be_unconstrained 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 to_be_removed.

Definition at line 1952 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, throw_dimension_incompatible(), and update_generators().

01952                                                                    {
01953   // The cylindrification wrt no dimensions is a no-op.
01954   // This case also captures the only legal cylindrification
01955   // of a polyhedron in a 0-dim space.
01956   if (to_be_unconstrained.empty())
01957     return;
01958 
01959   // Dimension-compatibility check.
01960   const dimension_type min_space_dim = to_be_unconstrained.space_dimension();
01961   if (space_dim < min_space_dim)
01962     throw_dimension_incompatible("unconstrain(vs)", min_space_dim);
01963 
01964   // Do something only if the polyhedron is non-empty.
01965   if (marked_empty()
01966       || (has_pending_constraints() && !process_pending_constraints())
01967       || (!generators_are_up_to_date() && !update_generators()))
01968     // Empty: do nothing.
01969     return;
01970 
01971   assert(generators_are_up_to_date());
01972   // Since `gen_sys' is not empty, the topology and space dimension
01973   // of the inserted generators are automatically adjusted.
01974   Variables_Set::const_iterator tbu = to_be_unconstrained.begin();
01975   Variables_Set::const_iterator tbu_end = to_be_unconstrained.end();
01976   if (can_have_something_pending()) {
01977     for ( ; tbu != tbu_end; ++tbu)
01978       gen_sys.insert_pending(Generator::line(Variable(*tbu)));
01979     set_generators_pending();
01980   }
01981   else {
01982     for ( ; tbu != tbu_end; ++tbu)
01983       gen_sys.insert(Generator::line(Variable(*tbu)));
01984     // After adding the new generators,
01985     // constraints are no longer up-to-date.
01986     clear_generators_minimized();
01987     clear_constraints_up_to_date();
01988   }
01989   assert(OK(true));
01990 }

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

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

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

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

01993                                                       {
01994   Polyhedron& x = *this;
01995   // Topology compatibility check.
01996   if (x.topology() != y.topology())
01997     throw_topology_incompatible("intersection_assign(y)", "y", y);
01998   // Dimension-compatibility check.
01999   if (x.space_dim != y.space_dim)
02000     throw_dimension_incompatible("intersection_assign(y)", "y", y);
02001 
02002   // If one of the two polyhedra is empty, the intersection is empty.
02003   if (x.marked_empty())
02004     return;
02005   if (y.marked_empty()) {
02006     x.set_empty();
02007     return;
02008   }
02009 
02010   // If both polyhedra are zero-dimensional,
02011   // then at this point they are necessarily non-empty,
02012   // so that their intersection is non-empty too.
02013   if (x.space_dim == 0)
02014     return;
02015 
02016   // Both systems of constraints have to be up-to-date,
02017   // possibly having pending constraints.
02018   if (x.has_pending_generators())
02019     x.process_pending_generators();
02020   else if (!x.constraints_are_up_to_date())
02021     x.update_constraints();
02022 
02023   if (y.has_pending_generators())
02024     y.process_pending_generators();
02025   else if (!y.constraints_are_up_to_date())
02026     y.update_constraints();
02027 
02028   // Here both systems are up-to-date and possibly have pending constraints
02029   // (but they cannot have pending generators).
02030   assert(!x.has_pending_generators() && x.constraints_are_up_to_date());
02031   assert(!y.has_pending_generators() && y.constraints_are_up_to_date());
02032 
02033   // If `x' can support pending constraints,
02034   // the constraints of `y' are added as pending constraints of `x'.
02035   if (x.can_have_something_pending()) {
02036     x.con_sys.add_pending_rows(y.con_sys);
02037     x.set_constraints_pending();
02038   }
02039   else {
02040     // `x' cannot support pending constraints.
02041     // If both constraint systems are (fully) sorted, then we can
02042     // merge them; otherwise we simply add the second to the first.
02043     if (x.con_sys.is_sorted()
02044         && y.con_sys.is_sorted() && !y.has_pending_constraints())
02045       x.con_sys.merge_rows_assign(y.con_sys);
02046     else
02047       x.con_sys.add_rows(y.con_sys);
02048     // Generators are no longer up-to-date and constraints are no
02049     // longer minimized.
02050     x.clear_generators_up_to_date();
02051     x.clear_constraints_minimized();
02052   }
02053   assert(x.OK() && y.OK());
02054 }

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

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

Returns:
false if and only if the result is empty.
Exceptions:
std::invalid_argument Thrown if *this and y are topology-incompatible or dimension-incompatible.
Deprecated:
See A Note on the Implementation of the Operators.

Definition at line 2057 of file Polyhedron_public.cc.

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

02057                                                                    {
02058   Polyhedron& x = *this;
02059   // Topology compatibility check.
02060   if (x.topology() != y.topology())
02061     throw_topology_incompatible("intersection_assign_and_minimize(y)",
02062                                 "y", y);
02063   // Dimension-compatibility check.
02064   if (x.space_dim != y.space_dim)
02065     throw_dimension_incompatible("intersection_assign_and_minimize(y)",
02066                                  "y", y);
02067 
02068   // If one of the two polyhedra is empty, the intersection is empty.
02069   if (x.marked_empty())
02070     return false;
02071   if (y.marked_empty()) {
02072     x.set_empty();
02073     return false;
02074   }
02075 
02076   // If both polyhedra are zero-dimensional,
02077   // then at this point they are necessarily non-empty,
02078   // so that their intersection is non-empty too.
02079   if (x.space_dim == 0)
02080     return true;
02081 
02082   // `x' must be minimized and have sorted constraints.
02083   // `minimize()' will process any pending constraints or generators.
02084   if (!x.minimize())
02085     // We have just discovered that `x' is empty.
02086     return false;
02087   x.obtain_sorted_constraints_with_sat_c();
02088 
02089   // `y' must have updated, possibly pending constraints.
02090   if (y.has_pending_generators())
02091     y.process_pending_generators();
02092   else if (!y.constraints_are_up_to_date())
02093     y.update_constraints();
02094 
02095   bool empty;
02096   if (y.con_sys.num_pending_rows() > 0) {
02097     // Integrate `y.con_sys' as pending constraints of `x',
02098     // sort them in place and then call `add_and_minimize()'.
02099     x.con_sys.add_pending_rows(y.con_sys);
02100     x.con_sys.sort_pending_and_remove_duplicates();
02101     if (x.con_sys.num_pending_rows() == 0) {
02102       // All pending constraints were duplicates.
02103       x.clear_pending_constraints();
02104       assert(OK(true));
02105       return true;
02106     }
02107     empty = add_and_minimize(true, x.con_sys, x.gen_sys, x.sat_c);
02108   }
02109   else {
02110     y.obtain_sorted_constraints();
02111     empty = add_and_minimize(true, x.con_sys, x.gen_sys, x.sat_c, y.con_sys);
02112   }
02113 
02114   if (empty)
02115     x.set_empty();
02116   else {
02117     // On exit of the function `intersection_assign_and_minimize()'
02118     // the polyhedron is up-to-date and `sat_c' is meaningful.
02119     x.set_sat_c_up_to_date();
02120     x.clear_sat_g_up_to_date();
02121   }
02122   assert(x.OK(!empty));
02123   return !empty;
02124 }

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

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

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

Definition at line 2566 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< PS >::affine_dimension(), fold_space_dimensions(), poly_difference_assign(), and upper_bound_assign().

02566                                                    {
02567   Polyhedron& x = *this;
02568   // Topology compatibility check.
02569   if (x.topology() != y.topology())
02570     throw_topology_incompatible("poly_hull_assign(y)", "y", y);
02571   // Dimension-compatibility check.
02572   if (x.space_dim != y.space_dim)
02573     throw_dimension_incompatible("poly_hull_assign(y)", "y", y);
02574 
02575   // The poly-hull of a polyhedron `p' with an empty polyhedron is `p'.
02576   if (y.marked_empty())
02577     return;
02578   if (x.marked_empty()) {
02579     x = y;
02580     return;
02581   }
02582 
02583   // If both polyhedra are zero-dimensional,
02584   // then at this point they are necessarily universe polyhedra,
02585   // so that their poly-hull is the universe polyhedron too.
02586   if (x.space_dim == 0)
02587     return;
02588 
02589   // Both systems of generators have to be up-to-date,
02590   // possibly having pending generators.
02591   if ((x.has_pending_constraints() && !x.process_pending_constraints())
02592       || (!x.generators_are_up_to_date() && !x.update_generators())) {
02593     // Discovered `x' empty when updating generators.
02594     x = y;
02595     return;
02596   }
02597   if ((y.has_pending_constraints() && !y.process_pending_constraints())
02598       || (!y.generators_are_up_to_date() && !y.update_generators()))
02599     // Discovered `y' empty when updating generators.
02600     return;
02601 
02602   // Here both systems are up-to-date and possibly have pending generators
02603   // (but they cannot have pending constraints).
02604   assert(!x.has_pending_constraints() && x.generators_are_up_to_date());
02605   assert(!y.has_pending_constraints() && y.generators_are_up_to_date());
02606 
02607   // If `x' can support pending generators,
02608   // the generators of `y' are added as pending generators of `x'.
02609   if (x.can_have_something_pending()) {
02610     x.gen_sys.add_pending_rows(y.gen_sys);
02611     x.set_generators_pending();
02612   }
02613   else {
02614     // `x' cannot support pending generators.
02615     // If both generator systems are (fully) sorted, then we can merge
02616     // them; otherwise we simply add the second to the first.
02617     if (x.gen_sys.is_sorted()
02618         && y.gen_sys.is_sorted() && !y.has_pending_generators())
02619       x.gen_sys.merge_rows_assign(y.gen_sys);
02620     else
02621       x.gen_sys.add_rows(y.gen_sys);
02622     // Constraints are no longer up-to-date
02623     // and generators are no longer minimized.
02624     x.clear_constraints_up_to_date();
02625     x.clear_generators_minimized();
02626   }
02627   // At this point both `x' and `y' are not empty.
02628   assert(x.OK(true) && y.OK(true));
02629 }

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

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

Returns:
false if and only if the result is empty.
Exceptions:
std::invalid_argument Thrown if *this and y are topology-incompatible or dimension-incompatible.
Deprecated:
See A Note on the Implementation of the Operators.

Definition at line 2632 of file Polyhedron_public.cc.

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

02632                                                                 {
02633   Polyhedron& x = *this;
02634   // Topology compatibility check.
02635   if (x.topology() != y.topology())
02636     throw_topology_incompatible("poly_hull_assign_and_minimize(y)", "y", y);
02637   // Dimension-compatibility check.
02638   if (x.space_dim != y.space_dim)
02639     throw_dimension_incompatible("poly_hull_assign_and_minimize(y)", "y", y);
02640 
02641   // The poly-hull of a polyhedron `p' with an empty polyhedron is `p'.
02642   if (y.marked_empty())
02643     return minimize();
02644   if (x.marked_empty()) {
02645     x = y;
02646     return minimize();
02647   }
02648 
02649   // If both polyhedra are zero-dimensional,
02650   // then at this point they are necessarily universe polyhedra,
02651   // so that their poly-hull is the universe polyhedron too.
02652   if (x.space_dim == 0)
02653     return true;
02654 
02655   // `x' must have minimized constraints and generators.
02656   // `minimize()' will process any pending constraints or generators.
02657   if (!x.minimize()) {
02658     // We have just discovered that `x' is empty.
02659     x = y;
02660     return minimize();
02661   }
02662   // x must have `sat_g' up-to-date and sorted generators.
02663   x.obtain_sorted_generators_with_sat_g();
02664 
02665   // `y' must have updated, possibly pending generators.
02666   if ((y.has_pending_constraints() && !y.process_pending_constraints())
02667       || (!y.generators_are_up_to_date() && !y.update_generators()))
02668     // We have just discovered that `y' is empty
02669     // (and we know that `x' is not empty).
02670     return true;
02671 
02672   if (y.gen_sys.num_pending_rows() > 0) {
02673     // Integrate `y.gen_sys' as pending generators of `x',
02674     // sort them in place and then call `add_and_minimize()'.
02675     x.gen_sys.add_pending_rows(y.gen_sys);
02676     x.gen_sys.sort_pending_and_remove_duplicates();
02677     if (x.gen_sys.num_pending_rows() == 0) {
02678       // All pending generators were duplicates.
02679       x.clear_pending_generators();
02680       assert(OK(true) && y.OK());
02681       return true;
02682     }
02683     add_and_minimize(false, x.gen_sys, x.con_sys, x.sat_g);
02684   }
02685   else {
02686     y.obtain_sorted_generators();
02687     add_and_minimize(false, x.gen_sys, x.con_sys, x.sat_g, y.gen_sys);
02688   }
02689   x.clear_sat_c_up_to_date();
02690 
02691   assert(x.OK(true) && y.OK());
02692   return true;
02693 }

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

Same as poly_hull_assign(y).

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

References poly_hull_assign().

00080                                                   {
00081   poly_hull_assign(y);
00082 }

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

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

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

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

02696                                                          {
02697   Polyhedron& x = *this;
02698   // Topology compatibility check.
02699   if (x.topology() != y.topology())
02700     throw_topology_incompatible("poly_difference_assign(y)", "y", y);
02701   // Dimension-compatibility check.
02702   if (x.space_dim != y.space_dim)
02703     throw_dimension_incompatible("poly_difference_assign(y)", "y", y);
02704 
02705   // The difference of a polyhedron `p' and an empty polyhedron is `p'.
02706   if (y.marked_empty())
02707     return;
02708   // The difference of an empty polyhedron and of a polyhedron `p' is empty.
02709   if (x.marked_empty())
02710     return;
02711 
02712   // If both polyhedra are zero-dimensional,
02713   // then at this point they are necessarily universe polyhedra,
02714   // so that their difference is empty.
02715   if (x.space_dim == 0) {
02716     x.set_empty();
02717     return;
02718   }
02719 
02720   // TODO: This is just an executable specification.
02721   //       Have to find a more efficient method.
02722 
02723   if (y.contains(x)) {
02724     x.set_empty();
02725     return;
02726   }
02727 
02728   // Being lazy here is only harmful.
02729   // `minimize()' will process any pending constraints or generators.
02730   if (!y.minimize())
02731     return;
02732   x.minimize();
02733 
02734   Polyhedron new_polyhedron(topology(), x.space_dim, EMPTY);
02735 
02736   const Constraint_System& y_cs = y.constraints();
02737   for (Constraint_System::const_iterator i = y_cs.begin(),
02738          y_cs_end = y_cs.end(); i != y_cs_end; ++i) {
02739     const Constraint& c = *i;
02740     assert(!c.is_tautological());
02741     assert(!c.is_inconsistent());
02742     // If the polyhedron `x' is included in the polyhedron defined by
02743     // `c', then `c' can be skipped, as adding its complement to `x'
02744     // would result in the empty polyhedron.  Moreover, if we operate
02745     // on C-polyhedra and `c' is a non-strict inequality, c _must_ be
02746     // skipped for otherwise we would obtain a result that is less
02747     // precise than the poly-difference.
02748     if (x.relation_with(c).implies(Poly_Con_Relation::is_included()))
02749       continue;
02750     Polyhedron z = x;
02751     const Linear_Expression e = Linear_Expression(c);
02752     switch (c.type()) {
02753     case Constraint::NONSTRICT_INEQUALITY:
02754       if (is_necessarily_closed())
02755         z.refine_no_check(e <= 0);
02756       else
02757         z.refine_no_check(e < 0);
02758       break;
02759     case Constraint::STRICT_INEQUALITY:
02760       z.refine_no_check(e <= 0);
02761       break;
02762     case Constraint::EQUALITY:
02763       if (is_necessarily_closed())
02764         // We have already filtered out the case
02765         // when `x' is included in `y': the result is `x'.
02766         return;
02767       else {
02768         Polyhedron w = x;
02769         w.refine_no_check(e < 0);
02770         new_polyhedron.poly_hull_assign(w);
02771         z.refine_no_check(e > 0);
02772       }
02773       break;
02774     }
02775     new_polyhedron.poly_hull_assign(z);
02776   }
02777   *this = new_polyhedron;
02778 
02779   assert(OK());
02780 }

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

Same as poly_difference_assign(y).

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

References poly_difference_assign().

00085                                                  {
00086   poly_difference_assign(y);
00087 }

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 2218 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(), add_to_system_and_check_independence(), Parma_Polyhedra_Library::Generator_System::begin(), Parma_Polyhedra_Library::Generator::CLOSURE_POINT, con_sys, constraints_are_minimized(), constraints_are_up_to_date(), drop_redundant_inequalities(), 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(), Parma_Polyhedra_Library::Polyhedron::Status::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.

02218                                                                 {
02219   Polyhedron& x = *this;
02220   // Topology compatibility check.
02221   if (x.topology() != y.topology())
02222     throw_topology_incompatible("simplify_using_context_assign(y)", "y", y);
02223   // Dimension-compatibility check.
02224   if (x.space_dim != y.space_dim)
02225     throw_dimension_incompatible("simplify_using_context_assign(y)", "y", y);
02226 
02227   // Filter away the zero-dimensional case.
02228   if (x.space_dim == 0) {
02229     if (y.is_empty()) {
02230       x.status.set_zero_dim_univ();
02231       return false;
02232     }
02233     else
02234       return !x.is_empty();
02235   }
02236 
02237   // If `y' is empty, the biggest enlargement for `x' is the universe.
02238   if (!y.minimize()) {
02239     Polyhedron ph(x.topology(), x.space_dim, UNIVERSE);
02240     swap(ph);
02241     return false;
02242   }
02243 
02244   // If `x' is empty, the intersection is empty.
02245   if (!x.minimize()) {
02246     // Search for a constraint of `y' that is not a tautology.
02247     assert(!y.has_pending_generators() && y.constraints_are_up_to_date());
02248     for (dimension_type i = y.con_sys.num_rows(); i-- > 0; ) {
02249       const Constraint& y_con_sys_i = y.con_sys[i];
02250       if (!y_con_sys_i.is_tautological()) {
02251         // Found: we obtain a constraint `c' contradicting the one we
02252         // found, and assign to `x' the polyhedron `ph' with `c' as
02253         // the only constraint.
02254         Polyhedron ph(x.topology(), x.space_dim, UNIVERSE);
02255         Linear_Expression le(y_con_sys_i);
02256         switch (y_con_sys_i.type()) {
02257         case Constraint::EQUALITY:
02258           ph.refine_no_check(le == 1);
02259           break;
02260         case Constraint::NONSTRICT_INEQUALITY:
02261           ph.refine_no_check(le <= -1);
02262           break;
02263         case Constraint::STRICT_INEQUALITY:
02264           ph.refine_no_check(le == 0);
02265           break;
02266         }
02267         swap(ph);
02268         assert(OK());
02269         return false;
02270       }
02271     }
02272     // `y' is the universe: `x' cannot be enlarged.
02273     return false;
02274   }
02275 
02276   assert(x.constraints_are_minimized()
02277          && !x.has_something_pending()
02278          && y.generators_are_minimized()
02279          && !y.has_something_pending());
02280   const Constraint_System& x_cs = x.con_sys;
02281   const dimension_type x_cs_num_rows = x_cs.num_rows();
02282   const Generator_System& y_gs = y.gen_sys;
02283 
02284   // Record into `redundant_by_y' the info about which constraints of
02285   // `x' are redundant in the context `y'.  Count the number of
02286   // redundancies found.
02287   std::vector<bool> redundant_by_y(x_cs_num_rows, false);
02288   dimension_type num_redundant_by_y = 0;
02289   for (dimension_type i = 0; i < x_cs_num_rows; ++i)
02290     if (y_gs.satisfied_by_all_generators(x_cs[i])) {
02291       redundant_by_y[i] = true;
02292       ++num_redundant_by_y;
02293     }
02294 
02295   Constraint_System result_cs;
02296 
02297   if (num_redundant_by_y < x_cs_num_rows) {
02298     // Some constraints were not identified as redundant (yet?).
02299     const Constraint_System& y_cs = y.con_sys;
02300     const dimension_type y_cs_num_rows = y_cs.num_rows();
02301     // Compute into `z' the minimized intersection of `x' and `y'.
02302     const bool x_first = (x_cs_num_rows > y_cs_num_rows);
02303     Polyhedron z(x_first ? x : y);
02304     if (x_first)
02305       z.add_constraints(y_cs);
02306     else {
02307       // Only copy (and then recycle) the non-redundant constraints.
02308       Constraint_System tmp_cs;
02309       for (dimension_type i = 0; i < x_cs_num_rows; ++i) {
02310         if (!redundant_by_y[i])
02311           tmp_cs.insert(x_cs[i]);
02312       }
02313       z.add_recycled_constraints(tmp_cs);
02314     }
02315     if (!z.minimize()) {
02316       // The objective function is the default, zero.
02317       // We do not care about minimization or maximization, since
02318       // we are only interested in satisfiability.
02319       MIP_Problem lp;
02320       if (x.is_necessarily_closed()) {
02321         lp.add_space_dimensions_and_embed(x.space_dim);
02322         lp.add_constraints(y_cs);
02323       }
02324       else {
02325         // KLUDGE: temporarily mark `y_cs' if it was necessarily
02326         // closed, so that we can interpret the epsilon dimension as a
02327         // standard dimension. Be careful to reset the topology of `cs'
02328         // even on exceptional execution path.
02329         const_cast<Constraint_System&>(y_cs).set_necessarily_closed();
02330         try {
02331           lp.add_space_dimensions_and_embed(x.space_dim+1);
02332           lp.add_constraints(y_cs);
02333           const_cast<Constraint_System&>(y_cs).set_not_necessarily_closed();
02334         }
02335         catch (...) {
02336           const_cast<Constraint_System&>(y_cs).set_not_necessarily_closed();
02337           throw;
02338         }
02339       }
02340       // We apply the following heuristics here: constraints of `x' that
02341       // are not made redundant by `y' are added to `lp' depending on
02342       // the number of generators of `y' they rule out (the more generators
02343       // they rule out, the sooner they are added).  Of course, as soon
02344       // as `lp' becomes unsatisfiable, we stopp adding.
02345       std::vector<Ruled_Out_Pair>
02346         ruled_out_vec(x_cs_num_rows - num_redundant_by_y);
02347       for (dimension_type i = 0, j = 0; i < x_cs_num_rows; ++i) {
02348         if (!redundant_by_y[i]) {
02349           const Constraint& c = x_cs[i];
02350           Topology_Adjusted_Scalar_Product_Sign sps(c);
02351           dimension_type num_ruled_out_generators = 0;
02352           for (Generator_System::const_iterator k = y_gs.begin(),
02353                  y_gs_end = y_gs.end(); k != y_gs_end; ++k) {
02354             const Generator& g = *k;
02355             const int sp_sign = sps(g, c);
02356             if (x.is_necessarily_closed()) {
02357               if (g.is_line()) {
02358                 // Lines must saturate the constraint.
02359                 if (sp_sign != 0)
02360                   goto ruled_out;
02361               }
02362               else {
02363                 // `g' is either a ray, a point or a closure point.
02364                 if (c.is_inequality()) {
02365                   // `c' is a non-strict inequality.
02366                   if (sp_sign < 0)
02367                     goto ruled_out;
02368                 }
02369                 else
02370                   // `c' is an equality.
02371                   if (sp_sign != 0)
02372                     goto ruled_out;
02373               }
02374             }
02375             else
02376               // The topology is not necessarily closed.
02377               switch (g.type()) {
02378               case Generator::LINE:
02379                 // Lines must saturate the constraint.
02380                 if (sp_sign != 0)
02381                   goto ruled_out;
02382                 break;
02383               case Generator::POINT:
02384                 // Have to perform the special test when dealing with
02385                 // a strict inequality.
02386                 switch (c.type()) {
02387                 case Constraint::EQUALITY:
02388                   if (sp_sign != 0)
02389                     goto ruled_out;
02390                   break;
02391                 case Constraint::NONSTRICT_INEQUALITY:
02392                   if (sp_sign < 0)
02393                     goto ruled_out;
02394                   break;
02395                 case Constraint::STRICT_INEQUALITY:
02396                   if (sp_sign <= 0)
02397                     goto ruled_out;
02398                   break;
02399                 }
02400                 break;
02401               case Generator::RAY:
02402                 // Intentionally fall through.
02403               case Generator::CLOSURE_POINT:
02404                 if (c.is_inequality()) {
02405                   // Constraint `c' is either a strict or a non-strict
02406                   // inequality.
02407                   if (sp_sign < 0)
02408                     goto ruled_out;
02409                 }
02410                 else
02411                   // Constraint `c' is an equality.
02412                   if (sp_sign != 0)
02413                     goto ruled_out;
02414                 break;
02415               }
02416 
02417             // If we reach this point, `g' satisfies `c'.
02418             continue;
02419           ruled_out:
02420             ++num_ruled_out_generators;
02421           }
02422           ruled_out_vec[j].constraint_index = i;
02423           ruled_out_vec[j].num_ruled_out = num_ruled_out_generators;
02424           ++j;
02425         }
02426       }
02427       std::sort(ruled_out_vec.begin(), ruled_out_vec.end(),
02428                 Ruled_Out_Less_Than());
02429 
02430       for (std::vector<Ruled_Out_Pair>::const_iterator
02431              j = ruled_out_vec.begin(), rov_end = ruled_out_vec.end();
02432            j != rov_end;
02433            ++j) {
02434         const Constraint& c = x_cs[j->constraint_index];
02435         result_cs.insert(c);
02436         lp.add_constraint(c);
02437         MIP_Problem_Status status = lp.solve();
02438         if (status == UNFEASIBLE_MIP_PROBLEM) {
02439           Polyhedron result_ph(x.topology(), x.space_dim, UNIVERSE);
02440           result_ph.add_constraints(result_cs);
02441           x.swap(result_ph);
02442           assert(x.OK());
02443           return false;
02444         }
02445       }
02446       // Cannot exit from here.
02447       assert(false);
02448     }
02449     else {
02450       // Here `z' is not empty and minimized.
02451       assert(z.constraints_are_minimized()
02452              && z.generators_are_minimized()
02453              && !z.has_something_pending());
02454       const Constraint_System& z_cs = z.con_sys;
02455       const Generator_System& z_gs = z.gen_sys;
02456       const dimension_type z_gs_num_rows = z_gs.num_rows();
02457 
02458       // Compute the number of equalities in x_cs, y_cs and z_cs
02459       // (exploiting minimal form knowledge).
02460       dimension_type x_cs_num_eq = 0;
02461       while (x_cs[x_cs_num_eq].is_equality())
02462         ++x_cs_num_eq;
02463       dimension_type y_cs_num_eq = 0;
02464       while (y_cs[y_cs_num_eq].is_equality())
02465         ++y_cs_num_eq;
02466       dimension_type z_cs_num_eq = 0;
02467       while (z_cs[z_cs_num_eq].is_equality())
02468         ++z_cs_num_eq;
02469       assert(x_cs_num_eq <= z_cs_num_eq && y_cs_num_eq <= z_cs_num_eq);
02470 
02471       // Identify non-redundant equalities.
02472       Constraint_System nonred_eq;
02473       dimension_type num_nonred_eq = 0;
02474       const dimension_type needed_nonred_eq = z_cs_num_eq - y_cs_num_eq;
02475       Linear_System eqs(x.topology());
02476       if (needed_nonred_eq > 0) {
02477         // Populate eqs with the equalities from y.
02478         for (dimension_type i = 0; i < y_cs_num_eq; ++i)
02479           eqs.insert(y_cs[i]);
02480         // Try to find another `needed_nonred_eq' linear independent
02481         // equalities among those from x.
02482         for (dimension_type i = 0; i < x_cs_num_eq; ++i) {
02483           const Constraint& x_cs_i = x_cs[i];
02484           if (add_to_system_and_check_independence(eqs, x_cs_i)) {
02485             // x_cs_i is linear independent.
02486             nonred_eq.insert(x_cs_i);
02487             ++num_nonred_eq;
02488             if (num_nonred_eq == needed_nonred_eq)
02489               // Already found all the needed equalities.
02490               break;
02491           }
02492         }
02493         // NOTE: if num_nonred_eq < needed_nonred_eq
02494         // then we haven't found all the needed equalities yet:
02495         // this means that some inequalities from x actually holds
02496         // as "masked" equalities in the context of y.
02497         assert(eqs.num_rows() <= z_cs_num_eq);
02498         assert(num_nonred_eq <= needed_nonred_eq);
02499         assert(z_cs_num_eq - eqs.num_rows()
02500                == needed_nonred_eq - num_nonred_eq);
02501       }
02502 
02503       // Identify non-redundant inequalities.
02504       // Avoid useless copies (no modifications are needed).
02505       std::vector<const Constraint*> p_nonred_ineq;
02506       // Fill p_nonred_ineq with (pointers to) inequalities from y_cs ...
02507       for (dimension_type i = y_cs_num_eq; i < y_cs_num_rows; ++i)
02508         p_nonred_ineq.push_back(&y_cs[i]);
02509       // ... and (pointers to) non-redundant inequalities from x_cs.
02510       for (dimension_type i = x_cs_num_eq; i < x_cs_num_rows; ++i)
02511         if (!redundant_by_y[i])
02512           p_nonred_ineq.push_back(&x_cs[i]);
02513 
02514       const dimension_type p_nonred_ineq_size = p_nonred_ineq.size();
02515       const dimension_type y_cs_num_ineq = y_cs_num_rows - y_cs_num_eq;
02516 
02517       // Compute saturation info.
02518       const dimension_type sat_num_rows = p_nonred_ineq_size;
02519       Bit_Matrix sat(sat_num_rows, z_gs_num_rows);
02520       for (dimension_type i = sat_num_rows; i-- > 0; ) {
02521         const Constraint& nonred_ineq_i = *(p_nonred_ineq[i]);
02522         Bit_Row& sat_i = sat[i];
02523         for (dimension_type j = z_gs_num_rows; j-- > 0; )
02524           if (Scalar_Products::sign(nonred_ineq_i, z_gs[j]))
02525             sat_i.set(j);
02526         if (sat_i.empty() && num_nonred_eq < needed_nonred_eq) {
02527           // `nonred_ineq_i' is actually masking an equality
02528           // and we are still looking for some masked inequalities.
02529           // Iteration goes downwards, so the inequality comes from x_cs.
02530           assert(i >= y_cs_num_ineq);
02531           // Check if the equality is independent in eqs.
02532           Linear_Row masked_eq = Linear_Row(nonred_ineq_i);
02533           masked_eq.set_is_line_or_equality();
02534           masked_eq.sign_normalize();
02535           if (add_to_system_and_check_independence(eqs, masked_eq)) {
02536             // It is independent: add the _inequality_ to nonred_eq.
02537             nonred_eq.insert(nonred_ineq_i);
02538             ++num_nonred_eq;
02539           }
02540         }
02541       }
02542       // Here we have already found all the needed (masked) equalities.
02543       assert(num_nonred_eq == needed_nonred_eq);
02544 
02545       drop_redundant_inequalities(p_nonred_ineq, x.topology(),
02546                                   sat, z_cs_num_eq);
02547 
02548       // Place the nonredundant (masked) equalities into result_cs.
02549       result_cs.swap(nonred_eq);
02550       // Add to result_cs the nonredundant inequalities from x_cs,
02551       // i.e., those having indices no smaller than y_cs_num_ineq.
02552       for (dimension_type i = y_cs_num_ineq; i < p_nonred_ineq_size; ++i)
02553         if (p_nonred_ineq[i])
02554           result_cs.insert(*p_nonred_ineq[i]);
02555     }
02556   }
02557 
02558   Polyhedron result_ph(x.topology(), x.space_dim, UNIVERSE);
02559   result_ph.add_recycled_constraints(result_cs);
02560   x.swap(result_ph);
02561   assert(x.OK());
02562   return true;
02563 }

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

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

Referenced by fold_space_dimensions(), and generalized_affine_image().

02786                                                             {
02787   // The denominator cannot be zero.
02788   if (denominator == 0)
02789     throw_invalid_argument("affine_image(v, e, d)", "d == 0");
02790 
02791   // Dimension-compatibility checks.
02792   // The dimension of `expr' should not be greater than the dimension
02793   // of `*this'.
02794   if (space_dim < expr.space_dimension())
02795     throw_dimension_incompatible("affine_image(v, e, d)", "e", expr);
02796   // `var' should be one of the dimensions of the polyhedron.
02797   const dimension_type var_space_dim = var.space_dimension();
02798   if (space_dim < var_space_dim)
02799     throw_dimension_incompatible("affine_image(v, e, d)", "v", var);
02800 
02801   if (marked_empty())
02802     return;
02803 
02804   if (expr.coefficient(var) != 0) {
02805     // The transformation is invertible:
02806     // minimality and saturators are preserved, so that
02807     // pending rows, if present, are correctly handled.
02808     if (generators_are_up_to_date()) {
02809       // Generator_System::affine_image() requires the third argument
02810       // to be a positive Coefficient.
02811       if (denominator > 0)
02812         gen_sys.affine_image(var_space_dim, expr, denominator);
02813       else
02814         gen_sys.affine_image(var_space_dim, -expr, -denominator);
02815     }
02816     if (constraints_are_up_to_date()) {
02817       // To build the inverse transformation,
02818       // after copying and negating `expr',
02819       // we exchange the roles of `expr[var_space_dim]' and `denominator'.
02820       Linear_Expression inverse;
02821       if (expr[var_space_dim] > 0) {
02822         inverse = -expr;
02823         inverse[var_space_dim] = denominator;
02824         con_sys.affine_preimage(var_space_dim, inverse, expr[var_space_dim]);
02825       }
02826       else {
02827         // The new denominator is negative: we negate everything once
02828         // more, as Constraint_System::affine_preimage() requires the
02829         // third argument to be positive.
02830         inverse = expr;
02831         inverse[var_space_dim] = denominator;
02832         neg_assign(inverse[var_space_dim]);
02833         con_sys.affine_preimage(var_space_dim, inverse, -expr[var_space_dim]);
02834       }
02835     }
02836   }
02837   else {
02838     // The transformation is not invertible.
02839     // We need an up-to-date system of generators.
02840     if (has_something_pending())
02841       remove_pending_to_obtain_generators();
02842     else if (!generators_are_up_to_date())
02843       minimize();
02844     if (!marked_empty()) {
02845       // Generator_System::affine_image() requires the third argument
02846       // to be a positive Coefficient.
02847       if (denominator > 0)
02848         gen_sys.affine_image(var_space_dim, expr, denominator);
02849       else
02850         gen_sys.affine_image(var_space_dim, -expr, -denominator);
02851 
02852       clear_constraints_up_to_date();
02853       clear_generators_minimized();
02854       clear_sat_c_up_to_date();
02855       clear_sat_g_up_to_date();
02856     }
02857   }
02858   assert(OK());
02859 }

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

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

Referenced by generalized_affine_preimage().

02866                                                                {
02867   // The denominator cannot be zero.
02868   if (denominator == 0)
02869     throw_invalid_argument("affine_preimage(v, e, d)", "d == 0");
02870 
02871   // Dimension-compatibility checks.
02872   // The dimension of `expr' should not be greater than the dimension
02873   // of `*this'.
02874   if (space_dim < expr.space_dimension())
02875     throw_dimension_incompatible("affine_preimage(v, e, d)", "e", expr);
02876   // `var' should be one of the dimensions of the polyhedron.
02877   const dimension_type var_space_dim = var.space_dimension();
02878   if (space_dim < var_space_dim)
02879     throw_dimension_incompatible("affine_preimage(v, e, d)", "v", var);
02880 
02881   if (marked_empty())
02882     return;
02883 
02884   if (expr.coefficient(var) != 0) {
02885     // The transformation is invertible:
02886     // minimality and saturators are preserved.
02887     if (constraints_are_up_to_date()) {
02888       // Constraint_System::affine_preimage() requires the third argument
02889       // to be a positive Coefficient.
02890       if (denominator > 0)
02891         con_sys.affine_preimage(var_space_dim, expr, denominator);
02892       else
02893         con_sys.affine_preimage(var_space_dim, -expr, -denominator);
02894     }
02895     if (generators_are_up_to_date()) {
02896       // To build the inverse transformation,
02897       // after copying and negating `expr',
02898       // we exchange the roles of `expr[var_space_dim]' and `denominator'.
02899       Linear_Expression inverse;
02900       if (expr[var_space_dim] > 0) {
02901         inverse = -expr;
02902         inverse[var_space_dim] = denominator;
02903         gen_sys.affine_image(var_space_dim, inverse, expr[var_space_dim]);
02904       }
02905       else {
02906         // The new denominator is negative:
02907         // we negate everything once more, as Generator_System::affine_image()
02908         // requires the third argument to be positive.
02909         inverse = expr;
02910         inverse[var_space_dim] = denominator;
02911         neg_assign(inverse[var_space_dim]);
02912         gen_sys.affine_image(var_space_dim, inverse, -expr[var_space_dim]);
02913       }
02914     }
02915   }
02916   else {
02917     // The transformation is not invertible.
02918     // We need an up-to-date system of constraints.
02919     if (has_something_pending())
02920       remove_pending_to_obtain_constraints();
02921     else if (!constraints_are_up_to_date())
02922       minimize();
02923     // Constraint_System::affine_preimage() requires the third argument
02924     // to be a positive Coefficient.
02925     if (denominator > 0)
02926       con_sys.affine_preimage(var_space_dim, expr, denominator);
02927     else
02928       con_sys.affine_preimage(var_space_dim, -expr, -denominator);
02929     // Generators, minimality and saturators are no longer valid.
02930     clear_generators_up_to_date();
02931     clear_constraints_minimized();
02932     clear_sat_c_up_to_date();
02933     clear_sat_g_up_to_date();
02934   }
02935   assert(OK());
02936 }

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 3088 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(), space_dim, Parma_Polyhedra_Library::Variable::space_dimension(), Parma_Polyhedra_Library::Linear_Expression::space_dimension(), throw_dimension_incompatible(), and throw_invalid_argument().

Referenced by bounded_affine_image(), and generalized_affine_preimage().

03091                                                                         {
03092   // The denominator cannot be zero.
03093   if (denominator == 0)
03094     throw_invalid_argument("generalized_affine_image(v, r, e, d)", "d == 0");
03095 
03096   // Dimension-compatibility checks.
03097   // The dimension of `expr' should not be greater than the dimension
03098   // of `*this'.
03099   if (space_dim < expr.space_dimension())
03100     throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
03101                                  "e", expr);
03102   // `var' should be one of the dimensions of the polyhedron.
03103   const dimension_type var_space_dim = var.space_dimension();
03104   if (space_dim < var_space_dim)
03105     throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
03106                                  "v", var);
03107 
03108   // Strict relation symbols are only admitted for NNC polyhedra.
03109   if (is_necessarily_closed()
03110       && (relsym == LESS_THAN || relsym == GREATER_THAN))
03111     throw_invalid_argument("generalized_affine_image(v, r, e, d)",
03112                            "r is a strict relation symbol");
03113   // The relation symbol cannot be a disequality.
03114   if (relsym == NOT_EQUAL)
03115     throw_invalid_argument("generalized_affine_image(v, r, e, d)",
03116                            "r is the disequality relation symbol");
03117 
03118   // First compute the affine image.
03119   affine_image(var, expr, denominator);
03120 
03121   if (relsym == EQUAL)
03122     // The affine relation is indeed an affine function.
03123     return;
03124 
03125   // Any image of an empty polyhedron is empty.
03126   // Note: DO check for emptiness here, as we will later add a ray.
03127   if (is_empty())
03128     return;
03129 
03130   switch (relsym) {
03131   case LESS_OR_EQUAL:
03132     add_generator(ray(-var));
03133     break;
03134   case GREATER_OR_EQUAL:
03135     add_generator(ray(var));
03136     break;
03137   case LESS_THAN:
03138   // Intentionally fall through.
03139   case GREATER_THAN:
03140     {
03141       // The relation symbol is strict.
03142       assert(!is_necessarily_closed());
03143       // While adding the ray, we minimize the generators
03144       // in order to avoid adding too many redundant generators later.
03145       add_generator(ray(relsym == GREATER_THAN ? var : -var));
03146       minimize();
03147       // We split each point of the generator system into two generators:
03148       // a closure point, having the same coordinates of the given point,
03149       // and another point, having the same coordinates for all but the
03150       // `var' dimension, which is displaced along the direction of the
03151       // newly introduced ray.
03152       const dimension_type eps_index = space_dim + 1;
03153       for (dimension_type i =  gen_sys.num_rows(); i-- > 0; )
03154         if (gen_sys[i].is_point()) {
03155           Generator& g = gen_sys[i];
03156           // Add a `var'-displaced copy of `g' to the generator system.
03157           gen_sys.add_row(g);
03158           if (relsym == GREATER_THAN)
03159             ++gen_sys[gen_sys.num_rows()-1][var_space_dim];
03160           else
03161             --gen_sys[gen_sys.num_rows()-1][var_space_dim];
03162           // Transform `g' into a closure point.
03163           g[eps_index] = 0;
03164         }
03165       clear_constraints_up_to_date();
03166       clear_generators_minimized();
03167       gen_sys.set_sorted(false);
03168       clear_sat_c_up_to_date();
03169       clear_sat_g_up_to_date();
03170     }
03171     break;
03172   default:
03173     // The EQUAL and NOT_EQUAL cases have been already dealt with.
03174     throw std::runtime_error("PPL internal error");
03175   }
03176   assert(OK());
03177 }

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 3181 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(), refine_no_check(), space_dim, Parma_Polyhedra_Library::Variable::space_dimension(), Parma_Polyhedra_Library::Linear_Expression::space_dimension(), TEMP_INTEGER, throw_dimension_incompatible(), throw_invalid_argument(), and unconstrain().

03184                                                                            {
03185   // The denominator cannot be zero.
03186   if (denominator == 0)
03187     throw_invalid_argument("generalized_affine_preimage(v, r, e, d)",
03188                            "d == 0");
03189 
03190   // Dimension-compatibility checks.
03191   // The dimension of `expr' should not be greater than the dimension
03192   // of `*this'.
03193   if (space_dim < expr.space_dimension())
03194     throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
03195                                  "e", expr);
03196   // `var' should be one of the dimensions of the polyhedron.
03197   const dimension_type var_space_dim = var.space_dimension();
03198   if (space_dim < var_space_dim)
03199     throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
03200                                  "v", var);
03201 
03202   // Strict relation symbols are only admitted for NNC polyhedra.
03203   if (is_necessarily_closed()
03204       && (relsym == LESS_THAN || relsym == GREATER_THAN))
03205     throw_invalid_argument("generalized_affine_preimage(v, r, e, d)",
03206                            "r is a strict relation symbol");
03207   // The relation symbol cannot be a disequality.
03208   if (relsym == NOT_EQUAL)
03209     throw_invalid_argument("generalized_affine_preimage(v, r, e, d)",
03210                            "r is the disequality relation symbol");
03211 
03212   // Check whether the affine relation is indeed an affine function.
03213   if (relsym == EQUAL) {
03214     affine_preimage(var, expr, denominator);
03215     return;
03216   }
03217 
03218   // Compute the reversed relation symbol to simplify later coding.
03219   Relation_Symbol reversed_relsym;
03220   switch (relsym) {
03221   case LESS_THAN:
03222     reversed_relsym = GREATER_THAN;
03223     break;
03224   case LESS_OR_EQUAL:
03225     reversed_relsym = GREATER_OR_EQUAL;
03226     break;
03227   case GREATER_OR_EQUAL:
03228     reversed_relsym = LESS_OR_EQUAL;
03229     break;
03230   case GREATER_THAN:
03231     reversed_relsym = LESS_THAN;
03232     break;
03233   default:
03234     // The EQUAL and NOT_EQUAL cases have been already dealt with.
03235     throw std::runtime_error("PPL internal error");
03236   }
03237 
03238   // Check whether the preimage of this affine relation can be easily
03239   // computed as the image of its inverse relation.
03240   const Coefficient& var_coefficient = expr.coefficient(var);
03241   if (var_coefficient != 0) {
03242     Linear_Expression inverse_expr
03243       = expr - (denominator + var_coefficient) * var;
03244     TEMP_INTEGER(inverse_denominator);
03245     neg_assign(inverse_denominator, var_coefficient);
03246     Relation_Symbol inverse_relsym
03247       = (sgn(denominator) == sgn(inverse_denominator))
03248       ? relsym : reversed_relsym;
03249     generalized_affine_image(var, inverse_relsym, inverse_expr,
03250                              inverse_denominator);
03251     return;
03252   }
03253 
03254   // Here `var_coefficient == 0', so that the preimage cannot
03255   // be easily computed by inverting the affine relation.
03256   // Shrink the polyhedron by adding the constraint induced
03257   // by the affine relation.
03258   const Relation_Symbol corrected_relsym
03259     = (denominator > 0) ? relsym : reversed_relsym;
03260   switch (corrected_relsym) {
03261   case LESS_THAN:
03262     refine_no_check(denominator*var < expr);
03263     break;
03264   case LESS_OR_EQUAL:
03265     refine_no_check(denominator*var <= expr);
03266     break;
03267   case GREATER_OR_EQUAL:
03268     refine_no_check(denominator*var >= expr);
03269     break;
03270   case GREATER_THAN:
03271     refine_no_check(denominator*var > expr);
03272     break;
03273   default:
03274     // The EQUAL and NOT_EQUAL cases have been already dealt with.
03275     throw std::runtime_error("PPL internal error");
03276   }
03277   unconstrain(var);
03278   assert(OK());
03279 }

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 3282 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(), space_dim, Parma_Polyhedra_Library::Linear_Expression::space_dimension(), throw_dimension_incompatible(), and throw_invalid_argument().

03284                                                                         {
03285   // Dimension-compatibility checks.
03286   // The dimension of `lhs' should not be greater than the dimension
03287   // of `*this'.
03288   dimension_type lhs_space_dim = lhs.space_dimension();
03289   if (space_dim < lhs_space_dim)
03290     throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
03291                                  "e1", lhs);
03292   // The dimension of `rhs' should not be greater than the dimension
03293   // of `*this'.
03294   const dimension_type rhs_space_dim = rhs.space_dimension();
03295   if (space_dim < rhs_space_dim)
03296     throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
03297                                  "e2", rhs);
03298 
03299   // Strict relation symbols are only admitted for NNC polyhedra.
03300   if (is_necessarily_closed()
03301       && (relsym == LESS_THAN || relsym == GREATER_THAN))
03302     throw_invalid_argument("generalized_affine_image(e1, r, e2)",
03303                            "r is a strict relation symbol");
03304   // The relation symbol cannot be a disequality.
03305   if (relsym == NOT_EQUAL)
03306     throw_invalid_argument("generalized_affine_image(e1, r, e2)",
03307                            "r is the disequality relation symbol");
03308 
03309   // Any image of an empty polyhedron is empty.
03310   if (marked_empty())
03311     return;
03312 
03313   // Compute the actual space dimension of `lhs',
03314   // i.e., the highest dimension having a non-zero coefficient in `lhs'.
03315   for ( ; lhs_space_dim > 0; lhs_space_dim--)
03316     if (lhs.coefficient(Variable(lhs_space_dim - 1)) != 0)
03317       break;
03318   // If all variables have a zero coefficient, then `lhs' is a constant:
03319   // we can simply add the constraint `lhs relsym rhs'.
03320   if (lhs_space_dim == 0) {
03321     switch (relsym) {
03322     case LESS_THAN:
03323       refine_no_check(lhs < rhs);
03324       break;
03325     case LESS_OR_EQUAL:
03326       refine_no_check(lhs <= rhs);
03327       break;
03328     case EQUAL:
03329       refine_no_check(lhs == rhs);
03330       break;
03331     case GREATER_OR_EQUAL:
03332       refine_no_check(lhs >= rhs);
03333       break;
03334     case GREATER_THAN:
03335       refine_no_check(lhs > rhs);
03336       break;
03337     case NOT_EQUAL:
03338       // The NOT_EQUAL case has been already dealt with.
03339       throw std::runtime_error("PPL internal error");
03340     }
03341     return;
03342   }
03343 
03344   // Gather in `new_lines' the collections of all the lines having
03345   // the direction of variables occurring in `lhs'.
03346   // While at it, check whether or not there exists a variable
03347   // occurring in both `lhs' and `rhs'.
03348   Generator_System new_lines;
03349   bool lhs_vars_intersects_rhs_vars = false;
03350   for (dimension_type i = lhs_space_dim; i-- > 0; )
03351     if (lhs.coefficient(Variable(i)) != 0) {
03352       new_lines.insert(line(Variable(i)));
03353       if (rhs.coefficient(Variable(i)) != 0)
03354         lhs_vars_intersects_rhs_vars = true;
03355     }
03356 
03357   if (lhs_vars_intersects_rhs_vars) {
03358     // Some variables in `lhs' also occur in `rhs'.
03359     // To ease the computation, we add an additional dimension.
03360     const Variable new_var = Variable(space_dim);
03361     add_space_dimensions_and_embed(1);
03362 
03363     // Constrain the new dimension to be equal to the right hand side.
03364     // (check for emptiness because we will add lines).
03365     refine_no_check(new_var == rhs);
03366     if (!is_empty()) {
03367       // Existentially quantify the variables in the left hand side.
03368       add_recycled_generators(new_lines);
03369 
03370       // Constrain the new dimension so that it is related to
03371       // the left hand side as dictated by `relsym'
03372       // (we force minimization because we will need the generators).
03373       switch (relsym) {
03374       case LESS_THAN:
03375         refine_no_check(lhs < new_var);
03376         break;
03377       case LESS_OR_EQUAL:
03378         refine_no_check(lhs <= new_var);
03379         break;
03380       case EQUAL:
03381         refine_no_check(lhs == new_var);
03382         break;
03383       case GREATER_OR_EQUAL:
03384         refine_no_check(lhs >= new_var);
03385         break;
03386       case GREATER_THAN:
03387         refine_no_check(lhs > new_var);
03388         break;
03389       case NOT_EQUAL:
03390         // The NOT_EQUAL case has been already dealt with.
03391         throw std::runtime_error("PPL internal error");
03392       }
03393     }
03394     // Remove the temporarily added dimension.
03395     remove_higher_space_dimensions(space_dim-1);
03396   }
03397   else {
03398     // `lhs' and `rhs' variables are disjoint:
03399     // there is no need to add a further dimension.
03400 
03401     // Any image of an empty polyhedron is empty.
03402     // Note: DO check for emptiness here, as we will add lines.
03403     if (is_empty())
03404       return;
03405 
03406     // Existentially quantify the variables in the left hand side.
03407     add_recycled_generators(new_lines);
03408 
03409     // Constrain the left hand side expression so that it is related to
03410     // the right hand side expression as dictated by `relsym'.
03411     switch (relsym) {
03412     case LESS_THAN:
03413       refine_no_check(lhs < rhs);
03414       break;
03415     case LESS_OR_EQUAL:
03416       refine_no_check(lhs <= rhs);
03417       break;
03418     case EQUAL:
03419       refine_no_check(lhs == rhs);
03420       break;
03421     case GREATER_OR_EQUAL:
03422       refine_no_check(lhs >= rhs);
03423       break;
03424     case GREATER_THAN:
03425       refine_no_check(lhs > rhs);
03426       break;
03427     case NOT_EQUAL:
03428       // The NOT_EQUAL case has been already dealt with.
03429       throw std::runtime_error("PPL internal error");
03430     }
03431   }
03432   assert(OK());
03433 }

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 3436 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(), space_dim, Parma_Polyhedra_Library::Linear_Expression::space_dimension(), throw_dimension_incompatible(), and throw_invalid_argument().

03438                                                                            {
03439   // Dimension-compatibility checks.
03440   // The dimension of `lhs' should not be greater than the dimension
03441   // of `*this'.
03442   dimension_type lhs_space_dim = lhs.space_dimension();
03443   if (space_dim < lhs_space_dim)
03444     throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2)",
03445                                  "e1", lhs);
03446   // The dimension of `rhs' should not be greater than the dimension
03447   // of `*this'.
03448   const dimension_type rhs_space_dim = rhs.space_dimension();
03449   if (space_dim < rhs_space_dim)
03450     throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2)",
03451                                  "e2", rhs);
03452 
03453   // Strict relation symbols are only admitted for NNC polyhedra.
03454   if (is_necessarily_closed()
03455       && (relsym == LESS_THAN || relsym == GREATER_THAN))
03456     throw_invalid_argument("generalized_affine_preimage(e1, r, e2)",
03457                            "r is a strict relation symbol");
03458   // The relation symbol cannot be a disequality.
03459   if (relsym == NOT_EQUAL)
03460     throw_invalid_argument("generalized_affine_preimage(e1, r, e2)",
03461                            "r is the disequality relation symbol");
03462 
03463   // Any preimage of an empty polyhedron is empty.
03464   if (marked_empty())
03465     return;
03466 
03467   // Compute the actual space dimension of `lhs',
03468   // i.e., the highest dimension having a non-zero coefficient in `lhs'.
03469   for ( ; lhs_space_dim > 0; lhs_space_dim--)
03470     if (lhs.coefficient(Variable(lhs_space_dim - 1)) != 0)
03471       break;
03472 
03473   // If all variables have a zero coefficient, then `lhs' is a constant:
03474   // in this case, preimage and image happen to be the same.
03475   if (lhs_space_dim == 0) {
03476     generalized_affine_image(lhs, relsym, rhs);
03477     return;
03478   }
03479 
03480   // Gather in `new_lines' the collections of all the lines having
03481   // the direction of variables occurring in `lhs'.
03482   // While at it, check whether or not there exists a variable
03483   // occurring in both `lhs' and `rhs'.
03484   Generator_System new_lines;
03485   bool lhs_vars_intersects_rhs_vars = false;
03486   for (dimension_type i = lhs_space_dim; i-- > 0; )
03487     if (lhs.coefficient(Variable(i)) != 0) {
03488       new_lines.insert(line(Variable(i)));
03489       if (rhs.coefficient(Variable(i)) != 0)
03490         lhs_vars_intersects_rhs_vars = true;
03491     }
03492 
03493   if (lhs_vars_intersects_rhs_vars) {
03494     // Some variables in `lhs' also occur in `rhs'.
03495     // To ease the computation, we add an additional dimension.
03496     const Variable new_var = Variable(space_dim);
03497     add_space_dimensions_and_embed(1);
03498 
03499     // Constrain the new dimension to be equal to `lhs'
03500     // (also check for emptiness because we have to add lines).
03501     refine_no_check(new_var == lhs);
03502     if (!is_empty()) {
03503       // Existentially quantify the variables in the left hand side.
03504       add_recycled_generators(new_lines);
03505 
03506       // Constrain the new dimension so that it is related to
03507       // the right hand side as dictated by `relsym'.
03508       switch (relsym) {
03509       case LESS_THAN:
03510         refine_no_check(new_var < rhs);
03511         break;
03512       case LESS_OR_EQUAL:
03513         refine_no_check(new_var <= rhs);
03514         break;
03515       case EQUAL:
03516         refine_no_check(new_var == rhs);
03517         break;
03518       case GREATER_OR_EQUAL:
03519         refine_no_check(new_var >= rhs);
03520         break;
03521       case GREATER_THAN:
03522         refine_no_check(new_var > rhs);
03523         break;
03524       case NOT_EQUAL:
03525         // The NOT_EQUAL case has been already dealt with.
03526         throw std::runtime_error("PPL internal error");
03527       }
03528     }
03529     // Remove the temporarily added dimension.
03530     remove_higher_space_dimensions(space_dim-1);
03531   }
03532   else {
03533     // `lhs' and `rhs' variables are disjoint:
03534     // there is no need to add a further dimension.
03535 
03536     // Constrain the left hand side expression so that it is related to
03537     // the right hand side expression as dictated by `relsym'.
03538     switch (relsym) {
03539     case LESS_THAN:
03540       refine_no_check(lhs < rhs);
03541       break;
03542     case LESS_OR_EQUAL:
03543       refine_no_check(lhs <= rhs);
03544       break;
03545     case EQUAL:
03546       refine_no_check(lhs == rhs);
03547       break;
03548     case GREATER_OR_EQUAL:
03549       refine_no_check(lhs >= rhs);
03550       break;
03551     case GREATER_THAN:
03552       refine_no_check(lhs > rhs);
03553       break;
03554     case NOT_EQUAL:
03555       // The NOT_EQUAL case has been already dealt with.
03556       throw std::runtime_error("PPL internal error");
03557     }
03558     // Any image of an empty polyhedron is empty.
03559     // Note: DO check for emptiness here, as we will add lines.
03560     if (is_empty())
03561       return;
03562     // Existentially quantify all the variables occurring in `lhs'.
03563     add_recycled_generators(new_lines);
03564   }
03565   assert(OK());
03566 }

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 2940 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(), space_dim, Parma_Polyhedra_Library::Linear_Expression::space_dimension(), Parma_Polyhedra_Library::Variable::space_dimension(), throw_dimension_incompatible(), and throw_invalid_argument().

02943                                                                     {
02944   // The denominator cannot be zero.
02945   if (denominator == 0)
02946     throw_invalid_argument("bounded_affine_image(v, lb, ub, d)", "d == 0");
02947 
02948   // Dimension-compatibility checks.
02949   // `var' should be one of the dimensions of the polyhedron.
02950   const dimension_type var_space_dim = var.space_dimension();
02951   if (space_dim < var_space_dim)
02952     throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
02953                                  "v", var);
02954   // The dimension of `lb_expr' and `ub_expr' should not be
02955   // greater than the dimension of `*this'.
02956   const dimension_type lb_space_dim = lb_expr.space_dimension();
02957   if (space_dim < lb_space_dim)
02958     throw_dimension_incompatible("bounded_affine_image(v, lb, ub)",
02959                                  "lb", lb_expr);
02960   const dimension_type ub_space_dim = ub_expr.space_dimension();
02961   if (space_dim < ub_space_dim)
02962     throw_dimension_incompatible("bounded_affine_image(v, lb, ub)",
02963                                  "ub", ub_expr);
02964 
02965   // Any image of an empty polyhedron is empty.
02966   if (marked_empty())
02967     return;
02968 
02969   // Check whether `var' occurs in `lb_expr' and/or `ub_expr'.
02970   if (lb_expr.coefficient(var) == 0) {
02971     // Here `var' may only occur in `ub_expr'.
02972     generalized_affine_image(var,
02973                              LESS_OR_EQUAL,
02974                              ub_expr,
02975                              denominator);
02976     if (denominator > 0)
02977       refine_no_check(lb_expr <= denominator*var);
02978     else
02979       refine_no_check(denominator*var <= lb_expr);
02980   }
02981   else if (ub_expr.coefficient(var) == 0) {
02982     // Here `var' only occurs in `lb_expr'.
02983     generalized_affine_image(var,
02984                              GREATER_OR_EQUAL,
02985                              lb_expr,
02986                              denominator);
02987     if (denominator > 0)
02988       refine_no_check(denominator*var <= ub_expr);
02989     else
02990       refine_no_check(ub_expr <= denominator*var);
02991   }
02992   else {
02993     // Here `var' occurs in both `lb_expr' and `ub_expr'.
02994     // To ease the computation, we add an additional dimension.
02995     const Variable new_var = Variable(space_dim);
02996     add_space_dimensions_and_embed(1);
02997     // Constrain the new dimension to be equal to `ub_expr'.
02998     refine_no_check(denominator*new_var == ub_expr);
02999     // Apply the affine lower bound.
03000     generalized_affine_image(var,
03001                              GREATER_OR_EQUAL,
03002                              lb_expr,
03003                              denominator);
03004     if (!marked_empty())
03005       // Now apply the affine upper bound, as recorded in `new_var'.
03006       refine_no_check(new_var >= var);
03007     // Remove the temporarily added dimension.
03008     remove_higher_space_dimensions(space_dim-1);
03009   }
03010   assert(OK());
03011 }

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 3015 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(), space_dim, Parma_Polyhedra_Library::Linear_Expression::space_dimension(), Parma_Polyhedra_Library::Variable::space_dimension(), throw_dimension_incompatible(), throw_invalid_argument(), and unconstrain().

03018                                                                        {
03019   // The denominator cannot be zero.
03020   if (denominator == 0)
03021     throw_invalid_argument("bounded_affine_preimage(v, lb, ub, d)", "d == 0");
03022 
03023   // Dimension-compatibility checks.
03024   // `var' should be one of the dimensions of the polyhedron.
03025   const dimension_type var_space_dim = var.space_dimension();
03026   if (space_dim < var_space_dim)
03027     throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
03028                                  "v", var);
03029   // The dimension of `lb_expr' and `ub_expr' should not be
03030   // greater than the dimension of `*this'.
03031   const dimension_type lb_space_dim = lb_expr.space_dimension();
03032   if (space_dim < lb_space_dim)
03033     throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub)",
03034                                  "lb", lb_expr);
03035   const dimension_type ub_space_dim = ub_expr.space_dimension();
03036   if (space_dim < ub_space_dim)
03037     throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub)",
03038                                  "ub", ub_expr);
03039 
03040   // Any preimage of an empty polyhedron is empty.
03041   if (marked_empty())
03042     return;
03043 
03044   // Check whether `var' occurs in neither `lb_expr' nor `ub_expr'.
03045   if (lb_expr.coefficient(var) == 0 && ub_expr.coefficient(var) == 0) {
03046     if (denominator > 0) {
03047       refine_no_check(lb_expr <= denominator*var);
03048       refine_no_check(denominator*var <= ub_expr);
03049     }
03050     else {
03051       refine_no_check(ub_expr <= denominator*var);
03052       refine_no_check(denominator*var <= lb_expr);
03053     }
03054     unconstrain(var);
03055   }
03056   else {
03057     // Here `var' occurs in `lb_expr' or `ub_expr'.
03058     // To ease the computation, add an additional dimension.
03059     const Variable new_var = Variable(space_dim);
03060     add_space_dimensions_and_embed(1);
03061     // Swap dimensions `var' and `new_var'.
03062     std::vector<dimension_type> swapping_cycle;
03063     swapping_cycle.push_back(var_space_dim);
03064     swapping_cycle.push_back(space_dim);
03065     swapping_cycle.push_back(0);
03066     if (constraints_are_up_to_date())
03067       con_sys.permute_columns(swapping_cycle);
03068     if (generators_are_up_to_date())
03069       gen_sys.permute_columns(swapping_cycle);
03070     // Constrain the new dimension as dictated by `lb_expr' and `ub_expr'.
03071     // (we force minimization because we will need the generators).
03072     if (denominator > 0) {
03073       refine_no_check(lb_expr <= denominator*new_var);
03074       refine_no_check(denominator*new_var <= ub_expr);
03075     }
03076     else {
03077       refine_no_check(ub_expr <= denominator*new_var);
03078       refine_no_check(denominator*new_var <= lb_expr);
03079     }
03080     // Remove the temporarily added dimension.
03081     remove_higher_space_dimensions(space_dim-1);
03082   }
03083   assert(OK());
03084 }

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 3569 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, Parma_Polyhedra_Library::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().

03569                                                      {
03570   Polyhedron& x = *this;
03571   // Topology compatibility check.
03572   if (x.topology() != y.topology())
03573     throw_topology_incompatible("time_elapse_assign(y)", "y", y);
03574   // Dimension-compatibility checks.
03575   if (x.space_dim != y.space_dim)
03576     throw_dimension_incompatible("time_elapse_assign(y)", "y", y);
03577 
03578   // Dealing with the zero-dimensional case.
03579   if (x.space_dim == 0) {
03580     if (y.marked_empty())
03581       x.set_empty();
03582     return;
03583   }
03584 
03585   // If either one of `x' or `y' is empty, the result is empty too.
03586   if (x.marked_empty() || y.marked_empty()
03587       || (x.has_pending_constraints() && !x.process_pending_constraints())
03588       || (!x.generators_are_up_to_date() && !x.update_generators())
03589       || (y.has_pending_constraints() && !y.process_pending_constraints())
03590       || (!y.generators_are_up_to_date() && !y.update_generators())) {
03591     x.set_empty();
03592     return;
03593   }
03594 
03595   // At this point both generator systems are up-to-date,
03596   // possibly containing pending generators.
03597   Generator_System gs = y.gen_sys;
03598   dimension_type gs_num_rows = gs.num_rows();
03599 
03600   if (!x.is_necessarily_closed())
03601     // `x' and `y' are NNC polyhedra.
03602     for (dimension_type i = gs_num_rows; i-- > 0; )
03603       switch (gs[i].type()) {
03604       case Generator::POINT:
03605         // The points of `gs' can be erased,
03606         // since their role can be played by closure points.
03607         --gs_num_rows;
03608         std::swap(gs[i], gs[gs_num_rows]);
03609         break;
03610       case Generator::CLOSURE_POINT:
03611         {
03612           Generator& cp = gs[i];
03613           // If it is the origin, erase it.
03614           if (cp.all_homogeneous_terms_are_zero()) {
03615             --gs_num_rows;
03616             std::swap(cp, gs[gs_num_rows]);
03617           }
03618           // Otherwise, transform the closure point into a ray.
03619           else {
03620             cp[0] = 0;
03621             // Enforce normalization.
03622             cp.normalize();
03623           }
03624         }
03625         break;
03626       default:
03627         // For rays and lines, nothing to be done.
03628         break;
03629       }
03630   else
03631     // `x' and `y' are C polyhedra.
03632     for (dimension_type i = gs_num_rows; i-- > 0; )
03633       switch (gs[i].type()) {
03634       case Generator::POINT:
03635         {
03636           Generator& p = gs[i];
03637           // If it is the origin, erase it.
03638           if (p.all_homogeneous_terms_are_zero()) {
03639             --gs_num_rows;
03640             std::swap(p, gs[gs_num_rows]);
03641           }
03642           // Otherwise, transform the point into a ray.
03643           else {
03644             p[0] = 0;
03645             // Enforce normalization.
03646             p.normalize();
03647           }
03648         }
03649         break;
03650       default:
03651         // For rays and lines, nothing to be done.
03652         break;
03653       }
03654   // If it was present, erase the origin point or closure point,
03655   // which cannot be transformed into a valid ray or line.
03656   // For NNC polyhedra, also erase all the points of `gs',
03657   // whose role can be played by the closure points.
03658   // These have been previously moved to the end of `gs'.
03659   gs.erase_to_end(gs_num_rows);
03660   gs.unset_pending_rows();
03661 
03662   // `gs' may now have no rows.
03663   // Namely, this happens when `y' was the singleton polyhedron
03664   // having the origin as the one and only point.
03665   // In such a case, the resulting polyhedron is equal to `x'.
03666   if (gs_num_rows == 0)
03667     return;
03668 
03669   // If the polyhedron can have something pending, we add `gs'
03670   // to `gen_sys' as pending rows
03671   if (x.can_have_something_pending()) {
03672     x.gen_sys.add_pending_rows(gs);
03673     x.set_generators_pending();
03674   }
03675   // Otherwise, the two systems are merged.
03676   // `Linear_System::merge_rows_assign()' requires both systems to be sorted.
03677   else {
03678     if (!x.gen_sys.is_sorted())
03679       x.gen_sys.sort_rows();
03680     gs.sort_rows();
03681     x.gen_sys.merge_rows_assign(gs);
03682     // Only the system of generators is up-to-date.
03683     x.clear_constraints_up_to_date();
03684     x.clear_generators_minimized();
03685   }
03686   assert(x.OK(true) && y.OK(true));
03687 }

void Parma_Polyhedra_Library::Polyhedron::topological_closure_assign (  ) 

Assigns to *this its topological closure.

Definition at line 3690 of file Polyhedron_public.cc.

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

03690                                           {
03691   // Necessarily closed polyhedra are trivially closed.
03692   if (is_necessarily_closed())
03693     return;
03694   // Any empty or zero-dimensional polyhedron is closed.
03695   if (marked_empty() || space_dim == 0)
03696     return;
03697 
03698   // The computation can be done using constraints or generators.
03699   // If we use constraints, we will change them, so that having pending
03700   // constraints would be useless. If we use generators, we add generators,
03701   // so that having pending generators still makes sense.
03702 
03703   // Process any pending constraints.
03704   if (has_pending_constraints() && !process_pending_constraints())
03705     return;
03706 
03707   // Use constraints only if they are available and
03708   // there are no pending generators.
03709   if (!has_pending_generators() && constraints_are_up_to_date()) {
03710     const dimension_type eps_index = space_dim + 1;
03711     bool changed = false;
03712     // Transform all strict inequalities into non-strict ones.
03713     for (dimension_type i = con_sys.num_rows(); i-- > 0; ) {
03714       Constraint& c = con_sys[i];
03715       if (c[eps_index] < 0 && !c.is_tautological()) {
03716         c[eps_index] = 0;
03717         // Enforce normalization.
03718         c.normalize();
03719         changed = true;
03720       }
03721     }
03722     if (changed) {
03723       con_sys.insert(Constraint::epsilon_leq_one());
03724       con_sys.set_sorted(false);
03725       // After changing the system of constraints, the generators
03726       // are no longer up-to-date and the constraints are no longer
03727       // minimized.
03728       clear_generators_up_to_date();
03729       clear_constraints_minimized();
03730     }
03731   }
03732   else {
03733     // Here we use generators, possibly keeping constraints.
03734     assert(generators_are_up_to_date());
03735     // Add the corresponding point to each closure point.
03736     gen_sys.add_corresponding_points();
03737     if (can_have_something_pending())
03738       set_generators_pending();
03739     else {
03740       // We cannot have pending generators; this also implies
03741       // that generators may have lost their sortedness.
03742       gen_sys.unset_pending_rows();
03743       gen_sys.set_sorted(false);
03744       // Constraints are not up-to-date and generators are not minimized.
03745       clear_constraints_up_to_date();
03746       clear_generators_minimized();
03747     }
03748   }
03749   assert(OK());
03750 }

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 665 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, Parma_Polyhedra_Library::swap(), throw_dimension_incompatible(), throw_topology_incompatible(), topology(), and Parma_Polyhedra_Library::UNIVERSE.

Referenced by limited_BHRZ03_extrapolation_assign().

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

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

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

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

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

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

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

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

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

Definition at line 846 of file Polyhedron_widenings.cc.

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

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

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 156 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, Parma_Polyhedra_Library::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().

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

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

Same as H79_widening_assign(y, tp).

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

References H79_widening_assign().

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

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

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

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

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

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

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

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

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

Definition at line 371 of file Polyhedron_widenings.cc.

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

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

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 91 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, Parma_Polyhedra_Library::swap(), 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().

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

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 187 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, Parma_Polyhedra_Library::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().

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

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

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

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

Removes all the specified dimensions from the vector space.

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

Definition at line 416 of file Polyhedron_chdims.cc.

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

Referenced by fold_space_dimensions().

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

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

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

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

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

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

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

Definition at line 149 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, Parma_Polyhedra_Library::swap(), throw_invalid_argument(), topology(), Parma_Polyhedra_Library::Generator::type(), and update_generators().

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

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

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

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

Folds the space dimensions in to_be_folded into var.

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

Definition at line 603 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::Variable::space_dimension(), throw_dimension_incompatible(), and throw_invalid_argument().

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

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

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

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

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

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

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

00099                               {
00100   if (topology() != y.topology())
00101     throw_topology_incompatible("swap(y)", "y", y);
00102   std::swap(con_sys, y.con_sys);
00103   std::swap(gen_sys, y.gen_sys);
00104   std::swap(sat_c, y.sat_c);
00105   std::swap(sat_g, y.sat_g);
00106   std::swap(status, y.status);
00107   std::swap(space_dim, y.space_dim);
00108 }

void Parma_Polyhedra_Library::Polyhedron::ascii_dump (  )  const

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

Referenced by OK().

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

Writes to s an ASCII representation of *this.

Definition at line 3817 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, space_dim, and status.

03817                                              {
03818   s << "space_dim " << space_dim << "\n";
03819   status.ascii_dump(s);
03820   s << "\ncon_sys ("
03821     << (constraints_are_up_to_date() ? "" : "not_")
03822     << "up-to-date)"
03823     << "\n";
03824   con_sys.ascii_dump(s);
03825   s << "\ngen_sys ("
03826     << (generators_are_up_to_date() ? "" : "not_")
03827     << "up-to-date)"
03828     << "\n";
03829   gen_sys.ascii_dump(s);
03830   s << "\nsat_c\n";
03831   sat_c.ascii_dump(s);
03832   s << "\nsat_g\n";
03833   sat_g.ascii_dump(s);
03834   s << "\n";
03835 }

void Parma_Polyhedra_Library::Polyhedron::print (  )  const

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

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

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

Definition at line 3840 of file Polyhedron_public.cc.

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

03840                                        {
03841   std::string str;
03842 
03843   if (!(s >> str) || str != "space_dim")
03844     return false;
03845 
03846   if (!(s >> space_dim))
03847     return false;
03848 
03849   if (!status.ascii_load(s))
03850     return false;
03851 
03852   if (!(s >> str) || str != "con_sys")
03853     return false;
03854 
03855   if (!(s >> str) || (str != "(not_up-to-date)" && str != "(up-to-date)"))
03856     return false;
03857 
03858   if (!con_sys.ascii_load(s))
03859     return false;
03860 
03861   if (!(s >> str) || str != "gen_sys")
03862     return false;
03863 
03864   if (!(s >> str) || (str != "(not_up-to-date)" && str != "(up-to-date)"))
03865     return false;
03866 
03867   if (!gen_sys.ascii_load(s))
03868     return false;
03869 
03870   if (!(s >> str) || str != "sat_c")
03871     return false;
03872 
03873   if (!sat_c.ascii_load(s))
03874     return false;
03875 
03876   if (!(s >> str) || str != "sat_g")
03877     return false;
03878 
03879   if (!sat_g.ascii_load(s))
03880     return false;
03881 
03882   // Check invariants.
03883   assert(OK());
03884   return true;
03885 }

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

References external_memory_in_bytes().

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

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

03888                                               {
03889   return
03890     con_sys.external_memory_in_bytes()
03891     + gen_sys.external_memory_in_bytes()
03892     + sat_c.external_memory_in_bytes()
03893     + sat_g.external_memory_in_bytes();
03894 }

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

References space_dimension().

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

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

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

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

Definition at line 73 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_recycled_generators_and_minimize(), add_space_dimensions_and_embed(), add_space_dimensions_and_project(), Parma_Polyhedra_Library::BHRZ03_Certificate::BHRZ03_Certificate(), BHRZ03_combining_constraints(), BHRZ03_evolving_points(), Parma_Polyhedra_Library::H79_Certificate::compare(), Parma_Polyhedra_Library::BHRZ03_Certificate::compare(), concatenate_assign(), generalized_affine_image(), generalized_affine_preimage(), generators(), Parma_Polyhedra_Library::H79_Certificate::H79_Certificate(), H79_widening_assign(), 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(), and topological_closure_assign().

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

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

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

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

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

Referenced by add_congruence(), add_constraint(), add_generator(), add_recycled_constraints(), add_recycled_generators(), add_recycled_generators_and_minimize(), add_space_dimensions_and_embed(), add_space_dimensions_and_project(), affine_image(), affine_preimage(), Parma_Polyhedra_Library::BD_Shape< T >::BD_Shape(), Parma_Polyhedra_Library::BHRZ03_Certificate::BHRZ03_Certificate(), BHRZ03_combining_constraints(), BHRZ03_evolving_points(), BHRZ03_evolving_rays(), BHRZ03_widening_assign(), bounded_affine_image(), bounded_affine_preimage(), bounds(), Parma_Polyhedra_Library::Box< ITV >::Box(), Parma_Polyhedra_Library::H79_Certificate::compare(), Parma_Polyhedra_Library::BHRZ03_Certificate::compare(), concatenate_assign(), constrains(), constraints(), contains(), contains_integer_point(), fold_space_dimensions(), generalized_affine_image(), generalized_affine_preimage(), generators(), Parma_Polyhedra_Library::Grid::Grid(), Parma_Polyhedra_Library::H79_Certificate::H79_Certificate(), H79_widening_assign(), intersection_assign(), intersection_assign_and_minimize(), is_bounded(), is_empty(), is_included_in(), is_topologically_closed(), is_universe(), limited_BHRZ03_extrapolation_assign(), limited_H79_extrapolation_assign(), map_space_dimensions(), max_min(), minimize(), Parma_Polyhedra_Library::Octagonal_Shape< T >::Octagonal_Shape(), OK(), operator=(), poly_difference_assign(), poly_hull_assign(), poly_hull_assign_and_minimize(), 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().

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

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

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

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

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

Returns true if the system of generators is minimized.

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

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

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

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

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

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

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

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

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

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

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

Definition at line 662 of file Polyhedron_nonpublic.cc.

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

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

00662                                  {
00663   status.set_zero_dim_univ();
00664   space_dim = 0;
00665   con_sys.clear();
00666   gen_sys.clear();
00667 }

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

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

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

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

00191                                        {
00192   status.set_c_up_to_date();
00193 }

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

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

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

00196                                       {
00197   status.set_g_up_to_date();
00198 }

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

Sets status to express that constraints are minimized.

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

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

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

Sets status to express that generators are minimized.

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

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

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

Sets status to express that constraints are pending.

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

00213                                     {
00214   status.set_c_pending();
00215 }

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

Sets status to express that generators are pending.

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

00218                                    {
00219   status.set_g_pending();
00220 }

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

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

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

Clears the status flag indicating that the polyhedron is empty.

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

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

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

00233                         {
00234   status.reset_empty();
00235 }

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

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

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

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

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

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

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

00280                                         {
00281   clear_pending_generators();
00282   clear_generators_minimized();
00283   clear_sat_c_up_to_date();
00284   clear_sat_g_up_to_date();
00285   status.reset_g_up_to_date();
00286   // Can get rid of gen_sys here.
00287 }

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

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

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

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

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

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

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

00248                                       {
00249   status.reset_c_pending();
00250 }

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

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

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

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

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

00253                                      {
00254   status.reset_g_pending();
00255 }

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

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

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

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

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

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

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

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

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

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

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

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 717 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(), H79_widening_assign(), intersection_assign(), intersection_assign_and_minimize(), is_included_in(), is_universe(), process_pending(), refine_no_check(), refine_with_constraints(), relation_with(), and remove_pending_to_obtain_constraints().

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

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

00748                                                           {
00749   assert(has_something_pending());
00750 
00751   Polyhedron& x = const_cast<Polyhedron&>(*this);
00752 
00753   // If the polyhedron has pending constraints, simply unset them.
00754   if (x.has_pending_constraints()) {
00755     // Integrate the pending constraints, which are possibly not sorted.
00756     x.con_sys.unset_pending_rows();
00757     x.con_sys.set_sorted(false);
00758     x.clear_pending_constraints();
00759     x.clear_constraints_minimized();
00760     x.clear_generators_up_to_date();
00761   }
00762   else {
00763     assert(x.has_pending_generators());
00764     // We must process the pending generators and obtain the
00765     // corresponding system of constraints.
00766     x.process_pending_generators();
00767   }
00768   assert(OK(true));
00769 }

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

00772                                                          {
00773   assert(has_something_pending());
00774 
00775   Polyhedron& x = const_cast<Polyhedron&>(*this);
00776 
00777   // If the polyhedron has pending generators, simply unset them.
00778   if (x.has_pending_generators()) {
00779     // Integrate the pending generators, which are possibly not sorted.
00780     x.gen_sys.unset_pending_rows();
00781     x.gen_sys.set_sorted(false);
00782     x.clear_pending_generators();
00783     x.clear_generators_minimized();
00784     x.clear_constraints_up_to_date();
00785     assert(OK(true));
00786     return true;
00787   }
00788   else {
00789     assert(x.has_pending_constraints());
00790     // We must integrate the pending constraints and obtain the
00791     // corresponding system of generators.
00792     return x.process_pending_constraints();
00793   }
00794 }

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 797 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(), H79_widening_assign(), intersection_assign(), intersection_assign_and_minimize(), is_included_in(), minimize(), refine_no_check(), refine_with_constraints(), and relation_with().

00797                                         {
00798   assert(space_dim > 0);
00799   assert(!marked_empty());
00800   assert(generators_are_up_to_date());
00801   // We assume the polyhedron has no pending constraints or generators.
00802   assert(!has_something_pending());
00803 
00804   Polyhedron& x = const_cast<Polyhedron&>(*this);
00805   minimize(false, x.gen_sys, x.con_sys, x.sat_c);
00806   // `sat_c' is the only saturation matrix up-to-date.
00807   x.set_sat_c_up_to_date();
00808   x.clear_sat_g_up_to_date();
00809   // The system of constraints and the system of generators
00810   // are minimized.
00811   x.set_constraints_minimized();
00812   x.set_generators_minimized();
00813 }

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

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

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

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

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

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

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 874 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(), obtain_sorted_generators_with_sat_g(), and select_H79_constraints().

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

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 906 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(), intersection_assign_and_minimize(), is_universe(), and quick_equivalence_test().

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

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 934 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(), poly_hull_assign_and_minimize(), and quick_equivalence_test().

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

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 962 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 intersection_assign_and_minimize(), and process_pending_constraints().

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

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 997 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 add_recycled_generators_and_minimize(), poly_hull_assign_and_minimize(), and process_pending_generators().

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

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 1031 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_congruence_and_minimize(), add_congruences_and_minimize(), add_recycled_constraints_and_minimize(), add_recycled_generators(), add_recycled_generators_and_minimize(), affine_image(), affine_preimage(), constrains(), generalized_affine_image(), is_empty(), is_universe(), minimized_constraints(), minimized_generators(), OK(), poly_hull_assign_and_minimize(), strongly_minimize_constraints(), strongly_minimize_generators(), update_constraints(), and update_generators().

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

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 1071 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, Parma_Polyhedra_Library::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().

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

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 1255 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, Parma_Polyhedra_Library::swap(), Parma_Polyhedra_Library::Bit_Matrix::transpose_assign(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

Referenced by minimized_generators().

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

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

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

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

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

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

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

Referenced by contains().

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

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

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

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

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

Referenced by maximize(), and minimize().

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

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

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

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 66 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(), Parma_Polyhedra_Library::swap(), Parma_Polyhedra_Library::Linear_System::topology(), topology(), update_generators(), and update_sat_g().

Referenced by BHRZ03_widening_assign(), and H79_widening_assign().

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

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

References add_recycled_constraints(), Parma_Polyhedra_Library::Linear_Row::all_homogeneous_terms_are_zero(), Parma_Polyhedra_Library::Constraint_System::clear(), con_sys, constraints_are_minimized(), contains(), gen_sys, generators_are_minimized(), has_something_pending(), Parma_Polyhedra_Library::Constraint_System::insert(), Parma_Polyhedra_Library::Generator::is_closure_point(), Parma_Polyhedra_Library::Constraint::is_inequality(), is_necessarily_closed(), Parma_Polyhedra_Library::Generator::is_point(), Parma_Polyhedra_Library::BHRZ03_Certificate::is_stabilizing(), marked_empty(), 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(), Parma_Polyhedra_Library::swap(), Parma_Polyhedra_Library::Linear_System::topology(), and topology().

Referenced by BHRZ03_widening_assign().

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

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

Definition at line 506 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, Parma_Polyhedra_Library::swap(), and topology().

Referenced by BHRZ03_widening_assign().

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

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

Definition at line 576 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(), relation_with(), space_dim, Parma_Polyhedra_Library::sub_mul_assign(), Parma_Polyhedra_Library::swap(), TEMP_INTEGER, and topology().

Referenced by BHRZ03_widening_assign().

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

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

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

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

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

bool Parma_Polyhedra_Library::Polyhedron::add_and_minimize ( bool  con_to_gen,
Linear_System source1,
Linear_System dest,
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 233 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 add_recycled_generators_and_minimize(), intersection_assign_and_minimize(), poly_hull_assign_and_minimize(), process_pending_constraints(), and process_pending_generators().

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

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

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

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

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

References Parma_Polyhedra_Library::Linear_System::add_pending_row(), Parma_Polyhedra_Library::Bit_Matrix::add_row(), 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(), 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::swap(), TEMP_INTEGER, Parma_Polyhedra_Library::Linear_System::topology(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

Referenced by add_and_minimize(), and minimize().

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

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 81 of file simplify.cc.

References Parma_Polyhedra_Library::Linear_System::back_substitute(), Parma_Polyhedra_Library::compute_capacity(), empty, 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, Parma_Polyhedra_Library::swap(), and Parma_Polyhedra_Library::Linear_System::unset_pending_rows().

Referenced by add_and_minimize(), and minimize().

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

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

Definition at line 1412 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

Referenced by add_generator().

01412                                                            {
01413   std::ostringstream s;
01414   s << "PPL::";
01415   if (is_necessarily_closed())
01416     s << "C_";
01417   else
01418     s << "NNC_";
01419   s << "Polyhedron::" << method << "." << std::endl;
01420   throw std::runtime_error(s.str());
01421 }

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

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

01425                                                                   {
01426   std::ostringstream s;
01427   s << "PPL::";
01428   if (is_necessarily_closed())
01429     s << "C_";
01430   else
01431     s << "NNC_";
01432   s << "Polyhedron::" << method << ":" << std::endl
01433     << reason << ".";
01434   throw std::invalid_argument(s.str());
01435 }

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

Definition at line 1438 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

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

01440                                                                          {
01441   std::ostringstream s;
01442   s << "PPL::";
01443   if (is_necessarily_closed())
01444     s << "C_";
01445   else
01446     s << "NNC_";
01447   s << "Polyhedron::" << method << ":" << std::endl
01448     << ph_name << " is a ";
01449   if (ph.is_necessarily_closed())
01450     s << "C_";
01451   else
01452     s << "NNC_";
01453   s << "Polyhedron." << std::endl;
01454   throw std::invalid_argument(s.str());
01455 }

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

Definition at line 1458 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

01460                                                                       {
01461   assert(is_necessarily_closed());
01462   std::ostringstream s;
01463   s << "PPL::C_Polyhedron::" << method << ":" << std::endl
01464     << c_name << " is a strict inequality.";
01465   throw std::invalid_argument(s.str());
01466 }

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

Definition at line 1469 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

01471                                                                      {
01472   assert(is_necessarily_closed());
01473   std::ostringstream s;
01474   s << "PPL::C_Polyhedron::" << method << ":" << std::endl
01475     << g_name << " is a closure point.";
01476   throw std::invalid_argument(s.str());
01477 }

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

Definition at line 1480 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

01482                                                                              {
01483   assert(is_necessarily_closed());
01484   std::ostringstream s;
01485   s << "PPL::C_Polyhedron::" << method << ":" << std::endl
01486     << cs_name << " contains strict inequalities.";
01487   throw std::invalid_argument(s.str());
01488 }

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

Definition at line 1491 of file Polyhedron_nonpublic.cc.

01493                                                                             {
01494   std::ostringstream s;
01495   s << "PPL::C_Polyhedron::" << method << ":" << std::endl
01496     << gs_name << " contains closure points.";
01497   throw std::invalid_argument(s.str());
01498 }

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

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

Definition at line 1514 of file Polyhedron_nonpublic.cc.

References space_dimension(), and throw_dimension_incompatible().

01516                                                                           {
01517   throw_dimension_incompatible(method, ph_name, ph.space_dimension());
01518 }

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

Definition at line 1521 of file Polyhedron_nonpublic.cc.

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

01523                                                                                 {
01524   throw_dimension_incompatible(method, e_name, e.space_dimension());
01525 }

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

Definition at line 1528 of file Polyhedron_nonpublic.cc.

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

01530                                                                          {
01531   throw_dimension_incompatible(method, c_name, c.space_dimension());
01532 }

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

Definition at line 1535 of file Polyhedron_nonpublic.cc.

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

01537                                                                         {
01538   throw_dimension_incompatible(method, g_name, g.space_dimension());
01539 }

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

Definition at line 1542 of file Polyhedron_nonpublic.cc.

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

01544                                                                           {
01545   throw_dimension_incompatible(method, cg_name, cg.space_dimension());
01546 }

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

Definition at line 1549 of file Polyhedron_nonpublic.cc.

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

01551                                                                                  {
01552   throw_dimension_incompatible(method, cs_name, cs.space_dimension());
01553 }

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

Definition at line 1556 of file Polyhedron_nonpublic.cc.

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

01558                                                                                 {
01559   throw_dimension_incompatible(method, gs_name, gs.space_dimension());
01560 }

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

Definition at line 1563 of file Polyhedron_nonpublic.cc.

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

01565                                                                                   {
01566   throw_dimension_incompatible(method, cgs_name, cgs.space_dimension());
01567 }

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

Definition at line 1570 of file Polyhedron_nonpublic.cc.

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

01572                                                                         {
01573   std::ostringstream s;
01574   s << "PPL::";
01575   if (is_necessarily_closed())
01576     s << "C_";
01577   else
01578     s << "NNC_";
01579   s << "Polyhedron::" << method << ":" << std::endl
01580     << "this->space_dimension() == " << space_dimension() << ", "
01581     << var_name << ".space_dimension() == " << var.space_dimension() << ".";
01582   throw std::invalid_argument(s.str());
01583 }

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

Definition at line 1587 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed(), and space_dimension().

01588                                                                       {
01589   std::ostringstream s;
01590   s << "PPL::";
01591   if (is_necessarily_closed())
01592     s << "C_";
01593   else
01594     s << "NNC_";
01595   s << "Polyhedron::" << method << ":" << std::endl
01596     << "this->space_dimension() == " << space_dimension()
01597     << ", required space dimension == " << required_space_dim << ".";
01598   throw std::invalid_argument(s.str());
01599 }

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

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

01604                                                                     {
01605   std::ostringstream s;
01606   s << "PPL::";
01607   if (topol == NECESSARILY_CLOSED)
01608     s << "C_";
01609   else
01610     s << "NNC_";
01611   s << "Polyhedron::" << method << ":" << std::endl
01612     << reason << ".";
01613   throw std::length_error(s.str());
01614 }

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

Definition at line 1617 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

Referenced by add_generator().

01618                                                                    {
01619   std::ostringstream s;
01620   s << "PPL::";
01621   if (is_necessarily_closed())
01622     s << "C_";
01623   else
01624     s << "NNC_";
01625   s << "Polyhedron::" << method << ":" << std::endl
01626     << "*this is an empty polyhedron and "
01627     << g_name << " is not a point.";
01628   throw std::invalid_argument(s.str());
01629 }

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

Definition at line 1632 of file Polyhedron_nonpublic.cc.

References is_necessarily_closed().

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

01633                                                                      {
01634   std::ostringstream s;
01635   s << "PPL::";
01636   if (is_necessarily_closed())
01637     s << "C_";
01638   else
01639     s << "NNC_";
01640   s << "Polyhedron::" << method << ":" << std::endl
01641     << "*this is an empty polyhedron and" << std::endl
01642     << "the non-empty generator system " << gs_name << " contains no points.";
01643   throw std::invalid_argument(s.str());
01644 }


Friends And Related Function Documentation

friend class Parma_Polyhedra_Library::Box [friend]

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

friend class Parma_Polyhedra_Library::BD_Shape [friend]

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

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

friend class Parma_Polyhedra_Library::Grid [friend]

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

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

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

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

bool is_necessarily_closed_for_interfaces ( const Polyhedron ph  )  [friend]

Returns true if and only if ph.topology() == NECESSARILY_CLOSED.

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

References is_empty(), and minimized_constraints().

03898                                                                {
03899   if (ph.is_empty())
03900     s << "false";
03901   else
03902     s << ph.minimized_constraints();
03903   return s;
03904 }

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

00394                                                      {
00395   return !(x == y);
00396 }

Specializes std::swap.

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

References swap().

00420                                            {
00421   x.swap(y);
00422 }

template<typename PH>
bool poly_hull_assign_if_exact ( PH &  p,
const PH &  q 
) [related]

If the poly-hull of p and q is exact it is assigned to p and true is returned, otherwise false is returned.

Definition at line 51 of file algorithms.hh.

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

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


Member Data Documentation

The number of dimensions of the enclosing vector space.

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

Referenced by add_congruence(), add_congruences(), add_constraint(), add_generator(), add_recycled_constraints(), add_recycled_generators(), add_recycled_generators_and_minimize(), add_space_dimensions_and_embed(), add_space_dimensions_and_project(), affine_dimension(), affine_image(), affine_preimage(), ascii_dump(), ascii_load(), BHRZ03_combining_constraints(), BHRZ03_evolving_points(), BHRZ03_evolving_rays(), BHRZ03_widening_assign(), bounded_affine_image(), bounded_affine_preimage(), bounds(), Parma_Polyhedra_Library::BHRZ03_Certificate::compare(), concatenate_assign(), constrains(), constraints(), contains(), contains_integer_point(), drop_redundant_inequalities(), expand_space_dimension(), fold_space_dimensions(), generalized_affine_image(), generalized_affine_preimage(), generators(), grid_generators(), H79_widening_assign(), intersection_assign(), intersection_assign_and_minimize(), is_bounded(), is_included_in(), is_topologically_closed(), is_universe(), limited_BHRZ03_extrapolation_assign(), limited_H79_extrapolation_assign(), map_space_dimensions(), max_min(), minimize(), OK(), operator=(), poly_difference_assign(), poly_hull_assign(), poly_hull_assign_and_minimize(), Polyhedron(), process_pending(), process_pending_constraints(), process_pending_generators(), quick_equivalence_test(), 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(), topological_closure_assign(), unconstrain(), update_constraints(), and update_generators().

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 2772 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 2780 of file Polyhedron.defs.hh.

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


The documentation for this class was generated from the following files:

Generated on Sat Oct 11 10:41:10 2008 for PPL by  doxygen 1.5.6