
Welcome to pplpy's documentation!
*********************************

Contents:

Cython wrapper for the Parma Polyhedra Library (PPL)

The Parma Polyhedra Library (PPL) is a library for polyhedral
computations over *QQ*. This interface tries to reproduce the C++ API
as faithfully as possible in Cython/Sage. For example, the following
C++ excerpt:

   Variable x(0);
   Variable y(1);
   Constraint_System cs;
   cs.insert(x >= 0);
   cs.insert(x <= 3);
   cs.insert(y >= 0);
   cs.insert(y <= 3);
   C_Polyhedron poly_from_constraints(cs);

translates into:

>>> from ppl import Variable, Constraint_System, C_Polyhedron
>>> x = Variable(0)
>>> y = Variable(1)
>>> cs = Constraint_System()
>>> cs.insert(x >= 0)
>>> cs.insert(x <= 3)
>>> cs.insert(y >= 0)
>>> cs.insert(y <= 3)
>>> poly_from_constraints = C_Polyhedron(cs)

The same polyhedron constructed from generators:

>>> from ppl import Variable, Generator_System, C_Polyhedron, point
>>> gs = Generator_System()
>>> 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))
>>> poly_from_generators = C_Polyhedron(gs)

Rich comparisons test equality/inequality and strict/non-strict
containment:

>>> poly_from_generators == poly_from_constraints
True
>>> poly_from_generators >= poly_from_constraints
True
>>> poly_from_generators <  poly_from_constraints
False
>>> poly_from_constraints.minimized_generators()
Generator_System {point(0/1, 0/1), point(0/1, 3/1), point(3/1, 0/1), point(3/1, 3/1)}
>>> poly_from_constraints.minimized_constraints()
Constraint_System {-x0+3>=0, -x1+3>=0, x0>=0, x1>=0}

As we see above, the library is generally easy to use. There are a few
pitfalls that are not entirely obvious without consulting the
documentation, in particular:

* There are no vectors used to describe "Generator" (points, closure
  points, rays, lines) or "Constraint" (strict inequalities, non-
  strict inequalities, or equations). Coordinates are always specified
  via linear polynomials in "Variable"

* All coordinates of rays and lines as well as all coefficients of
  constraint relations are (arbitrary precision) integers. Only the
  generators "point()" and "closure_point()" allow one to specify an
  overall divisor of the otherwise integral coordinates. For example:

  >>> from ppl import Variable, point
  >>> x = Variable(0); y = Variable(1)
  >>> p = point( 2*x+3*y, 5 ); p
  point(2/5, 3/5)
  >>> p.coefficient(x)
  2
  >>> p.coefficient(y)
  3
  >>> p.divisor()
  5

* PPL supports (topologically) closed polyhedra ("C_Polyhedron") as
  well as not neccesarily closed polyhedra ("NNC_Polyhedron"). Only
  the latter allows closure points (=points of the closure but not of
  the actual polyhedron) and strict inequalities (">" and "<")

The naming convention for the C++ classes is that they start with
"PPL_", for example, the original "Linear_Expression" becomes
"PPL_Linear_Expression". The Python wrapper has the same name as the
original library class, that is, just "Linear_Expression". In short:

* If you are using the Python wrapper (if in doubt: thats you), then
  you use the same names as the PPL C++ class library.

* If you are writing your own Cython code, you can access the
  underlying C++ classes by adding the prefix "PPL_".

Finally, PPL is fast. For example, here is the permutahedron of 5
basis vectors:

>>> from ppl import Variable, Generator_System, point, C_Polyhedron
>>> basis = range(0,5)
>>> x = [ Variable(i) for i in basis ]
>>> gs = Generator_System();
>>> from itertools import permutations
>>> for coeff in permutations(basis):
...    gs.insert(point( sum( (coeff[i]+1)*x[i] for i in basis ) ))
>>> C_Polyhedron(gs)
A 4-dimensional polyhedron in QQ^5 defined as the convex hull of 120 points

DIFFERENCES VS. C++

Since Python and C++ syntax are not always compatible, there are
necessarily some differences. The main ones are:

* The "Linear_Expression" also accepts an iterable as input for the
  homogeneous cooefficients.

* "Polyhedron" and its subclasses as well as "Generator_System" and
  "Constraint_System" can be set immutable via a "set_immutable()"
  method. This is the analog of declaring a C++ instance "const". All
  other classes are immutable by themselves.

AUTHORS:

* Volker Braun (2010-10-08): initial version (within Sage).

* Risan (2012-02-19): extension for MIP_Problem class (within Sage)

* Vincent Delecroix (2016): convert Sage files into a standalone
  Python package

class class ppl.C_Polyhedron

   Bases: "ppl.Polyhedron"

   Wrapper for PPL's "C_Polyhedron" class.

   An object of the class "C_Polyhedron" represents a topologically
   closed convex polyhedron in the vector space. See "NNC_Polyhedron"
   for more general (not necessarily closed) polyhedra.

   When building a closed polyhedron starting from a system of
   constraints, an exception is thrown if the system contains a strict
   inequality constraint. Similarly, an exception is thrown when
   building a closed polyhedron starting from a system of generators
   containing a closure point.

   INPUT:

   * "arg" -- the defining data of the polyhedron. Any one of the
     following is accepted:

     * A non-negative integer. Depending on "degenerate_element",
       either the space-filling or the empty polytope in the given
       dimension "arg" is constructed.

     * A "Constraint_System".

     * A "Generator_System".

     * A single "Constraint".

     * A single "Generator".

     * A "C_Polyhedron".

   * "degenerate_element" -- string, either "'universe'" or
     "'empty'". Only used if "arg" is an integer.

   OUTPUT:

   A "C_Polyhedron".

   Examples:

   >>> from ppl import Constraint, Constraint_System, Generator, Generator_System, Variable, C_Polyhedron, point, ray
   >>> x = Variable(0)
   >>> y = Variable(1)
   >>> C_Polyhedron( 5*x-2*y >=  x+y-1 )
   A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point, 1 ray, 1 line
   >>> cs = Constraint_System()
   >>> cs.insert( x >= 0 )
   >>> cs.insert( y >= 0 )
   >>> C_Polyhedron(cs)
   A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point, 2 rays
   >>> C_Polyhedron( point(x+y) )
   A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point
   >>> gs = Generator_System()
   >>> gs.insert( point(-x-y) )
   >>> gs.insert( ray(x) )
   >>> C_Polyhedron(gs)
   A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point, 1 ray

   The empty and universe polyhedra are constructed like this:

   >>> C_Polyhedron(3, 'empty')
   The empty polyhedron in QQ^3
   >>> C_Polyhedron(3, 'empty').constraints()
   Constraint_System {-1==0}
   >>> C_Polyhedron(3, 'universe')
   The space-filling polyhedron in QQ^3
   >>> C_Polyhedron(3, 'universe').constraints()
   Constraint_System {}

   Note that, by convention, the generator system of a polyhedron is
   either empty or contains at least one point. In particular, if you
   define a polyhedron via a non-empty "Generator_System" it must
   contain a point (at any position). If you start with a single
   generator, this generator must be a point:

   >>> C_Polyhedron( ray(x) )
   Traceback (most recent call last):
   ...
   ValueError: PPL::C_Polyhedron::C_Polyhedron(gs):
   *this is an empty polyhedron and
   the non-empty generator system gs contains no points.

class class ppl.Constraint

   Bases: "object"

   Wrapper for PPL's "Constraint" class.

   An object of the class "Constraint" is either:

   * an equality *sum_{i=0}^{n-1} a_i x_i + b = 0*

   * a non-strict inequality *sum_{i=0}^{n-1} a_i x_i + b geq 0*

   * a strict inequality *sum_{i=0}^{n-1} a_i x_i + b > 0*

   where *n* is the dimension of the space, *a_i* is the integer
   coefficient of variable *x_i*, and *b_i* is the integer
   inhomogeneous term.

   INPUT/OUTPUT:

   You construct constraints by writing inequalities in
   "Linear_Expression". Do not attempt to manually construct
   constraints.

   Examples:

   >>> from ppl import Constraint, Variable, Linear_Expression
   >>> x = Variable(0)
   >>> y = Variable(1)
   >>> 5*x-2*y >  x+y-1
   4*x0-3*x1+1>0
   >>> 5*x-2*y >= x+y-1
   4*x0-3*x1+1>=0
   >>> 5*x-2*y == x+y-1
   4*x0-3*x1+1==0
   >>> 5*x-2*y <= x+y-1
   -4*x0+3*x1-1>=0
   >>> 5*x-2*y <  x+y-1
   -4*x0+3*x1-1>0
   >>> x > 0
   x0>0

   Special care is needed if the left hand side is a constant:

   >>> 0 == 1    # watch out!
   False
   >>> Linear_Expression(0) == 1
   -1==0

   OK()

      Check if all the invariants are satisfied.

      Examples:

      >>> from ppl import Linear_Expression, Variable
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> ineq = (3*x+2*y+1>=0)
      >>> ineq.OK()
      True

   ascii_dump()

      Write an ASCII dump to stderr.

      Examples:

      >>> cmd  = 'from ppl import Linear_Expression, Variable\n'
      >>> cmd += 'x = Variable(0)\n'
      >>> cmd += 'y = Variable(1)\n'
      >>> cmd += 'e = (3*x+2*y+1 > 0)\n'
      >>> cmd += 'e.ascii_dump()\n'
      >>> import subprocess
      >>> import sys
      >>> subprocess.call(['python', '-c', cmd], stderr=subprocess.STDOUT)
      size 4 1 3 2 -1 > (NNC)

   coefficient()

      Return the coefficient of the variable "v".

      INPUT:

      * "v" -- a "Variable".

      OUTPUT:

      An integer.

      Examples:

      >>> from ppl import Variable
      >>> x = Variable(0)
      >>> ineq = 3*x+1 > 0
      >>> ineq.coefficient(x)
      3
      >>> y = Variable(1)
      >>> ineq = 3**50 * y + 2 > 1
      >>> ineq.coefficient(y)
      717897987691852588770249L
      >>> ineq.coefficient(x)
      0

   coefficients()

      Return the coefficients of the constraint.

      See also "coefficient()".

      OUTPUT:

      A tuple of integers of length "space_dimension()".

      Examples:

      >>> from ppl import Variable
      >>> x = Variable(0);  y = Variable(1)
      >>> ineq = ( 3*x+5*y+1 ==  2);  ineq
      3*x0+5*x1-1==0
      >>> ineq.coefficients()
      (3, 5)

   inhomogeneous_term()

      Return the inhomogeneous term of the constraint.

      OUTPUT:

      Integer.

      Examples:

      >>> from ppl import Variable
      >>> y = Variable(1)
      >>> ineq = 10+y > 9
      >>> ineq
      x1+1>0
      >>> ineq.inhomogeneous_term()
      1
      >>> ineq = 2**66 + y > 0
      >>> ineq.inhomogeneous_term()
      73786976294838206464L

   is_equality()

      Test whether "self" is an equality.

      OUTPUT:

      Boolean. Returns "True" if and only if "self" is an equality
      constraint.

      Examples:

      >>> from ppl import Variable
      >>> x = Variable(0)
      >>> (x==0).is_equality()
      True
      >>> (x>=0).is_equality()
      False
      >>> (x>0).is_equality()
      False

   is_equivalent_to()

      Test whether "self" and "c" are equivalent.

      INPUT:

      * "c" -- a "Constraint".

      OUTPUT:

      Boolean. Returns "True" if and only if "self" and "c" are
      equivalent constraints.

      Note that constraints having different space dimensions are not
      equivalent. However, constraints having different types may
      nonetheless be equivalent, if they both are tautologies or
      inconsistent.

      Examples:

      >>> from ppl import Variable, Linear_Expression
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> (x > 0).is_equivalent_to(Linear_Expression(0) < x)
      True
      >>> (x > 0).is_equivalent_to(0*y < x)
      False
      >>> (0*x > 1).is_equivalent_to(0*x == -2)
      True

   is_inconsistent()

      Test whether "self" is an inconsistent constraint, that is,
      always false.

      An inconsistent constraint can have either one of the following
      forms:

      * an equality: *sum 0 x_i + b = 0* with *bnot=0*,

      * a non-strict inequality: *sum 0 x_i + b geq 0* with *b< 0*,
        or

      * a strict inequality: *sum 0 x_i + b > 0* with *bleq 0*.

      OUTPUT:

      Boolean. Returns "True" if and only if "self" is an inconsistent
      constraint.

      Examples:

      >>> from ppl import Variable
      >>> x = Variable(0)
      >>> (x==1).is_inconsistent()
      False
      >>> (0*x>=1).is_inconsistent()
      True

   is_inequality()

      Test whether "self" is an inequality.

      OUTPUT:

      Boolean. Returns "True" if and only if "self" is an inequality
      constraint, either strict or non-strict.

      Examples:

      >>> from ppl import Variable
      >>> x = Variable(0)
      >>> (x==0).is_inequality()
      False
      >>> (x>=0).is_inequality()
      True
      >>> (x>0).is_inequality()
      True

   is_nonstrict_inequality()

      Test whether "self" is a non-strict inequality.

      OUTPUT:

      Boolean. Returns "True" if and only if "self" is an non-strict
      inequality constraint.

      Examples:

      >>> from ppl import Variable
      >>> x = Variable(0)
      >>> (x==0).is_nonstrict_inequality()
      False
      >>> (x>=0).is_nonstrict_inequality()
      True
      >>> (x>0).is_nonstrict_inequality()
      False

   is_strict_inequality()

      Test whether "self" is a strict inequality.

      OUTPUT:

      Boolean. Returns "True" if and only if "self" is an strict
      inequality constraint.

      Examples:

      >>> from ppl import Variable
      >>> x = Variable(0)
      >>> (x==0).is_strict_inequality()
      False
      >>> (x>=0).is_strict_inequality()
      False
      >>> (x>0).is_strict_inequality()
      True

   is_tautological()

      Test whether "self" is a tautological constraint.

      A tautology can have either one of the following forms:

      * an equality: *sum 0 x_i + 0 = 0*,

      * a non-strict inequality: *sum 0 x_i + b geq 0* with *bgeq
        0*, or

      * a strict inequality: *sum 0 x_i + b > 0* with *b> 0*.

      OUTPUT:

      Boolean. Returns "True" if and only if "self" is a tautological
      constraint.

      Examples:

      >>> from ppl import Variable
      >>> x = Variable(0)
      >>> (x==0).is_tautological()
      False
      >>> (0*x>=0).is_tautological()
      True

   space_dimension()

      Return the dimension of the vector space enclosing "self".

      OUTPUT:

      Integer.

      Examples:

      >>> from ppl import Variable
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> (x>=0).space_dimension()
      1
      >>> (y==1).space_dimension()
      2

   type()

      Return the constraint type of "self".

      OUTPUT:

      String. One of "'equality'", "'nonstrict_inequality'", or
      "'strict_inequality'".

      Examples:

      >>> from ppl import Variable
      >>> x = Variable(0)
      >>> (x==0).type()
      'equality'
      >>> (x>=0).type()
      'nonstrict_inequality'
      >>> (x>0).type()
      'strict_inequality'

class class ppl.Constraint_System

   Bases: "ppl._mutable_or_immutable"

   Wrapper for PPL's "Constraint_System" class.

   An object of the class Constraint_System is a system of
   constraints, i.e., a multiset of objects of the class Constraint.
   When inserting constraints in a system, space dimensions are
   automatically adjusted so that all the constraints in the system
   are defined on the same vector space.

   Examples:

   >>> from ppl import Constraint_System, Variable
   >>> x = Variable(0)
   >>> y = Variable(1)
   >>> cs = Constraint_System( 5*x-2*y > 0 )
   >>> cs.insert( 6*x<3*y )
   >>> cs.insert( x >= 2*x-7*y )
   >>> cs
   Constraint_System {5*x0-2*x1>0, -2*x0+x1>0, -x0+7*x1>=0}

   OK()

      Check if all the invariants are satisfied.

      Examples:

      >>> from ppl import Variable, Constraint_System
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> cs = Constraint_System( 3*x+2*y+1 <= 10 )
      >>> cs.OK()
      True

   ascii_dump()

      Write an ASCII dump to stderr.

      Examples:

      >>> cmd  = 'from ppl import Constraint_System, Variable\n'
      >>> cmd += 'x = Variable(0)\n'
      >>> cmd += 'y = Variable(1)\n'
      >>> cmd += 'cs = Constraint_System( 3*x > 2*y+1 )\n'
      >>> cmd += 'cs.ascii_dump()\n'
      >>> import subprocess
      >>> import sys
      >>> subprocess.call(['python', '-c', cmd], stderr=subprocess.STDOUT)
      topology NOT_NECESSARILY_CLOSED
      1 x 2 SPARSE (sorted)
      index_first_pending 1
      size 4 -1 3 -2 -1 > (NNC)

   clear()

      Removes all constraints from the constraint system and sets its
      space dimension to 0.

      Examples:

      >>> from ppl import Variable, Constraint_System
      >>> x = Variable(0)
      >>> cs = Constraint_System(x>0)
      >>> cs
      Constraint_System {x0>0}
      >>> cs.clear()
      >>> cs
      Constraint_System {}

   empty()

      Return "True" if and only if "self" has no constraints.

      OUTPUT:

      Boolean.

      Examples:

      >>> from ppl import Variable, Constraint_System, point
      >>> x = Variable(0)
      >>> cs = Constraint_System()
      >>> cs.empty()
      True
      >>> cs.insert( x>0 )
      >>> cs.empty()
      False

   has_equalities()

      Tests whether "self" contains one or more equality constraints.

      OUTPUT:

      Boolean.

      Examples:

      >>> from ppl import Variable, Constraint_System
      >>> x = Variable(0)
      >>> cs = Constraint_System()
      >>> cs.insert( x>0 )
      >>> cs.insert( x<0 )
      >>> cs.has_equalities()
      False
      >>> cs.insert( x==0 )
      >>> cs.has_equalities()
      True

   has_strict_inequalities()

      Tests whether "self" contains one or more strict inequality
      constraints.

      OUTPUT:

      Boolean.

      Examples:

      >>> from ppl import Variable, Constraint_System
      >>> x = Variable(0)
      >>> cs = Constraint_System()
      >>> cs.insert( x>=0 )
      >>> cs.insert( x==-1 )
      >>> cs.has_strict_inequalities()
      False
      >>> cs.insert( x>0 )
      >>> cs.has_strict_inequalities()
      True

   insert()

      Insert "c" into the constraint system.

      INPUT:

      * "c" -- a "Constraint".

      Examples:

      >>> from ppl import Variable, Constraint_System
      >>> x = Variable(0)
      >>> cs = Constraint_System()
      >>> cs.insert( x>0 )
      >>> cs
      Constraint_System {x0>0}

   space_dimension()

      Return the dimension of the vector space enclosing "self".

      OUTPUT:

      Integer.

      Examples:

      >>> from ppl import Variable, Constraint_System
      >>> x = Variable(0)
      >>> cs = Constraint_System( x>0 )
      >>> cs.space_dimension()
      1

class class ppl.Constraint_System_iterator

   Bases: "object"

   Wrapper for PPL's "Constraint_System::const_iterator" class.

   Examples:

   >>> from ppl import Constraint_System, Variable, Constraint_System_iterator
   >>> x = Variable(0)
   >>> y = Variable(1)
   >>> cs = Constraint_System( 5*x < 2*y )
   >>> cs.insert( 6*x-3*y==0 )
   >>> cs.insert( x >= 2*x-7*y )
   >>> next(Constraint_System_iterator(cs))
   -5*x0+2*x1>0
   >>> list(cs)
   [-5*x0+2*x1>0, 2*x0-x1==0, -x0+7*x1>=0]

   next

      x.next() -> the next value, or raise StopIteration

class class ppl.Generator

   Bases: "object"

   Wrapper for PPL's "Generator" class.

   An object of the class Generator is one of the following:

      * a line *ell = (a_0, dots, a_{n-1})^T*

      * a ray *r = (a_0, dots, a_{n-1})^T*

      * a point *p = (tfrac{a_0}{d}, dots, tfrac{a_{n-1}}{d})^T*

      * a closure point *c = (tfrac{a_0}{d}, dots,
        tfrac{a_{n-1}}{d})^T*

   where *n* is the dimension of the space and, for points and closure
   points, *d* is the divisor.

   INPUT/OUTPUT:

   Use the helper functions "line()", "ray()", "point()", and
   "closure_point()" to construct generators. Analogous class methods
   are also available, see "Generator.line()", "Generator.ray()",
   "Generator.point()", "Generator.closure_point()". Do not attempt to
   construct generators manually.

   Note: The generators are constructed from linear expressions. The
     inhomogeneous term is always silently discarded.

   Examples:

   >>> from ppl import Generator, Variable
   >>> x = Variable(0)
   >>> y = Variable(1)
   >>> Generator.line(5*x-2*y)
   line(5, -2)
   >>> Generator.ray(5*x-2*y)
   ray(5, -2)
   >>> Generator.point(5*x-2*y, 7)
   point(5/7, -2/7)
   >>> Generator.closure_point(5*x-2*y, 7)
   closure_point(5/7, -2/7)

   OK()

      Check if all the invariants are satisfied.

      Examples:

      >>> from ppl import Linear_Expression, Variable
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> e = 3*x+2*y+1
      >>> e.OK()
      True

   ascii_dump()

      Write an ASCII dump to stderr.

      Examples:

      >>> cmd  = 'from ppl import Linear_Expression, Variable, point\n'
      >>> cmd += 'x = Variable(0)\n'
      >>> cmd += 'y = Variable(1)\n'
      >>> cmd += 'p = point(3*x+2*y)\n'
      >>> cmd += 'p.ascii_dump()\n'
      >>> import subprocess
      >>> import sys
      >>> subprocess.call(['python', '-c', cmd], stderr=subprocess.STDOUT)
      size 3 1 3 2 P (C)

   static closure_point()

      Construct a closure point.

      A closure point is a point of the topological closure of a
      polyhedron that is not a point of the polyhedron itself.

      INPUT:

      * "expression" -- a "Linear_Expression" or something
        convertible to it ("Variable" or integer).

      * "divisor" -- an integer.

      OUTPUT:

      A new "Generator" representing the point.

      Raises a "ValueError` if ``divisor==0".

      Examples:

      >>> from ppl import Generator, Variable
      >>> y = Variable(1)
      >>> Generator.closure_point(2*y+7, 3)
      closure_point(0/3, 2/3)
      >>> Generator.closure_point(y+7, 3)
      closure_point(0/3, 1/3)
      >>> Generator.closure_point(7, 3)
      closure_point()
      >>> Generator.closure_point(0, 0)
      Traceback (most recent call last):
      ...
      ValueError: PPL::closure_point(e, d):
      d == 0.

   coefficient()

      Return the coefficient of the variable "v".

      INPUT:

      * "v" -- a "Variable".

      OUTPUT:

      An integer.

      Examples:

      >>> from ppl import Variable, line
      >>> x = Variable(0)
      >>> line = line(3*x+1)
      >>> line
      line(1)
      >>> line.coefficient(x)
      1

   coefficients()

      Return the coefficients of the generator.

      See also "coefficient()".

      OUTPUT:

      A tuple of integers of length "space_dimension()".

      Examples:

      >>> from ppl import Variable, point
      >>> x = Variable(0);  y = Variable(1)
      >>> p = point(3*x+5*y+1, 2); p
      point(3/2, 5/2)
      >>> p.coefficients()
      (3, 5)

   divisor()

      If "self" is either a point or a closure point, return its
      divisor.

      OUTPUT:

      An integer. If "self" is a ray or a line, raises "ValueError".

      Examples:

      >>> from ppl import Generator, Variable
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> point = Generator.point(2*x-y+5)
      >>> point.divisor()
      1
      >>> line = Generator.line(2*x-y+5)
      >>> line.divisor()
      Traceback (most recent call last):
      ...
      ValueError: PPL::Generator::divisor():
      *this is neither a point nor a closure point.

   is_closure_point()

      Test whether "self" is a closure point.

      OUTPUT:

      Boolean.

      Examples:

      >>> from ppl import Variable, point, closure_point, ray, line
      >>> x = Variable(0)
      >>> line(x).is_closure_point()
      False
      >>> ray(x).is_closure_point()
      False
      >>> point(x,2).is_closure_point()
      False
      >>> closure_point(x,2).is_closure_point()
      True

   is_equivalent_to()

      Test whether "self" and "g" are equivalent.

      INPUT:

      * "g" -- a "Generator".

      OUTPUT:

      Boolean. Returns "True" if and only if "self" and "g" are
      equivalent generators.

      Note that generators having different space dimensions are not
      equivalent.

      Examples:

      >>> from ppl import Generator, Variable, point, line
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> point(2*x    , 2).is_equivalent_to( point(x) )
      True
      >>> point(2*x+0*y, 2).is_equivalent_to( point(x) )
      False
      >>> line(4*x).is_equivalent_to(line(x))
      True

   is_line()

      Test whether "self" is a line.

      OUTPUT:

      Boolean.

      Examples:

      >>> from ppl import Variable, point, closure_point, ray, line
      >>> x = Variable(0)
      >>> line(x).is_line()
      True
      >>> ray(x).is_line()
      False
      >>> point(x,2).is_line()
      False
      >>> closure_point(x,2).is_line()
      False

   is_line_or_ray()

      Test whether "self" is a line or a ray.

      OUTPUT:

      Boolean.

      Examples:

      >>> from ppl import Variable, point, closure_point, ray, line
      >>> x = Variable(0)
      >>> line(x).is_line_or_ray()
      True
      >>> ray(x).is_line_or_ray()
      True
      >>> point(x,2).is_line_or_ray()
      False
      >>> closure_point(x,2).is_line_or_ray()
      False

   is_point()

      Test whether "self" is a point.

      OUTPUT:

      Boolean.

      Examples:

      >>> from ppl import Variable, point, closure_point, ray, line
      >>> x = Variable(0)
      >>> line(x).is_point()
      False
      >>> ray(x).is_point()
      False
      >>> point(x,2).is_point()
      True
      >>> closure_point(x,2).is_point()
      False

   is_ray()

      Test whether "self" is a ray.

      OUTPUT:

      Boolean.

      Examples:

      >>> from ppl import Variable, point, closure_point, ray, line
      >>> x = Variable(0)
      >>> line(x).is_ray()
      False
      >>> ray(x).is_ray()
      True
      >>> point(x,2).is_ray()
      False
      >>> closure_point(x,2).is_ray()
      False

   static line()

      Construct a line.

      INPUT:

      * "expression" -- a "Linear_Expression" or something
        convertible to it ("Variable" or integer).

      OUTPUT:

      A new "Generator" representing the line.

      Raises a "ValueError` if the homogeneous part of ``expression"
      represents the origin of the vector space.

      Examples:

      >>> from ppl import Generator, Variable
      >>> y = Variable(1)
      >>> Generator.line(2*y)
      line(0, 1)
      >>> Generator.line(y)
      line(0, 1)
      >>> Generator.line(1)
      Traceback (most recent call last):
      ...
      ValueError: PPL::line(e):
      e == 0, but the origin cannot be a line.

   static point()

      Construct a point.

      INPUT:

      * "expression" -- a "Linear_Expression" or something
        convertible to it ("Variable" or integer).

      * "divisor" -- an integer.

      OUTPUT:

      A new "Generator" representing the point.

      Raises a "ValueError` if ``divisor==0".

      Examples:

      >>> from ppl import Generator, Variable
      >>> y = Variable(1)
      >>> Generator.point(2*y+7, 3)
      point(0/3, 2/3)
      >>> Generator.point(y+7, 3)
      point(0/3, 1/3)
      >>> Generator.point(7, 3)
      point()
      >>> Generator.point(0, 0)
      Traceback (most recent call last):
      ...
      ValueError: PPL::point(e, d):
      d == 0.

   static ray()

      Construct a ray.

      INPUT:

      * "expression" -- a "Linear_Expression" or something
        convertible to it ("Variable" or integer).

      OUTPUT:

      A new "Generator" representing the ray.

      Raises a "ValueError` if the homogeneous part of ``expression"
      represents the origin of the vector space.

      Examples:

      >>> from ppl import Generator, Variable
      >>> y = Variable(1)
      >>> Generator.ray(2*y)
      ray(0, 1)
      >>> Generator.ray(y)
      ray(0, 1)
      >>> Generator.ray(1)
      Traceback (most recent call last):
      ...
      ValueError: PPL::ray(e):
      e == 0, but the origin cannot be a ray.

   space_dimension()

      Return the dimension of the vector space enclosing "self".

      OUTPUT:

      Integer.

      Examples:

      >>> from ppl import Variable, point
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> point(x).space_dimension()
      1
      >>> point(y).space_dimension()
      2

   type()

      Return the generator type of "self".

      OUTPUT:

      String. One of "'line'", "'ray'", "'point'", or
      "'closure_point'".

      Examples:

      >>> from ppl import Variable, point, closure_point, ray, line
      >>> x = Variable(0)
      >>> line(x).type()
      'line'
      >>> ray(x).type()
      'ray'
      >>> point(x,2).type()
      'point'
      >>> closure_point(x,2).type()
      'closure_point'

class class ppl.Generator_System

   Bases: "ppl._mutable_or_immutable"

   Wrapper for PPL's "Generator_System" class.

   An object of the class Generator_System is a system of generators,
   i.e., a multiset of objects of the class Generator (lines, rays,
   points and closure points). When inserting generators in a system,
   space dimensions are automatically adjusted so that all the
   generators in the system are defined on the same vector space. A
   system of generators which is meant to define a non-empty
   polyhedron must include at least one point: the reason is that
   lines, rays and closure points need a supporting point (lines and
   rays only specify directions while closure points only specify
   points in the topological closure of the NNC polyhedron).

   Examples:

   >>> from ppl import Generator_System, Variable, line, ray, point, closure_point
   >>> x = Variable(0)
   >>> y = Variable(1)
   >>> gs = Generator_System(line(5*x-2*y))
   >>> gs.insert(ray(6*x-3*y))
   >>> gs.insert(point(2*x-7*y, 5))
   >>> gs.insert(closure_point(9*x-1*y, 2))
   >>> gs
   Generator_System {line(5, -2), ray(2, -1), point(2/5, -7/5), closure_point(9/2, -1/2)}

   OK()

      Check if all the invariants are satisfied.

      Examples:

      >>> from ppl import Variable, Generator_System, point
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> gs = Generator_System( point(3*x+2*y+1) )
      >>> gs.OK()
      True

   ascii_dump()

      Write an ASCII dump to stderr.

      Examples:

      >>> cmd  = 'from ppl import Generator_System, point, Variable\n'
      >>> cmd += 'x = Variable(0)\n'
      >>> cmd += 'y = Variable(1)\n'
      >>> cmd += 'gs = Generator_System( point(3*x+2*y+1) )\n'
      >>> cmd += 'gs.ascii_dump()\n'
      >>> import subprocess
      >>> import sys
      >>> subprocess.call(['python', '-c', cmd], stderr=subprocess.STDOUT)
      topology NECESSARILY_CLOSED
      1 x 2 SPARSE (sorted)
      index_first_pending 1
      size 3 1 3 2 P (C)

   clear()

      Removes all generators from the generator system and sets its
      space dimension to 0.

      Examples:

      >>> from ppl import Variable, Generator_System, point
      >>> x = Variable(0)
      >>> gs = Generator_System( point(3*x) ); gs
      Generator_System {point(3/1)}
      >>> gs.clear()
      >>> gs
      Generator_System {}

   empty()

      Return "True" if and only if "self" has no generators.

      OUTPUT:

      Boolean.

      Examples:

      >>> from ppl import Variable, Generator_System, point
      >>> x = Variable(0)
      >>> gs = Generator_System()
      >>> gs.empty()
      True
      >>> gs.insert( point(-3*x) )
      >>> gs.empty()
      False

   insert()

      Insert "g" into the generator system.

      The number of space dimensions of "self" is increased, if
      needed.

      INPUT:

      * "g" -- a "Generator".

      Examples:

      >>> from ppl import Variable, Generator_System, point
      >>> x = Variable(0)
      >>> gs = Generator_System( point(3*x) )
      >>> gs.insert( point(-3*x) )
      >>> gs
      Generator_System {point(3/1), point(-3/1)}

   space_dimension()

      Return the dimension of the vector space enclosing "self".

      OUTPUT:

      Integer.

      Examples:

      >>> from ppl import Variable, Generator_System, point
      >>> x = Variable(0)
      >>> gs = Generator_System( point(3*x) )
      >>> gs.space_dimension()
      1

class class ppl.Generator_System_iterator

   Bases: "object"

   Wrapper for PPL's "Generator_System::const_iterator" class.

   Examples:

   >>> from ppl import Generator_System, Variable, line, ray, point, closure_point, Generator_System_iterator
   >>> x = Variable(0)
   >>> y = Variable(1)
   >>> gs = Generator_System( line(5*x-2*y) )
   >>> gs.insert( ray(6*x-3*y) )
   >>> gs.insert( point(2*x-7*y, 5) )
   >>> gs.insert( closure_point(9*x-1*y, 2) )
   >>> next(Generator_System_iterator(gs))
   line(5, -2)
   >>> list(gs)
   [line(5, -2), ray(2, -1), point(2/5, -7/5), closure_point(9/2, -1/2)]

   next

      x.next() -> the next value, or raise StopIteration

class class ppl.Linear_Expression

   Bases: "object"

   Wrapper for PPL's "PPL_Linear_Expression" class.

   INPUT:

   The constructor accepts zero, one, or two arguments.

   If there are two arguments "Linear_Expression(a,b)", they are
   interpreted as

   * "a" -- an iterable of integer coefficients, for example a list.

   * "b" -- an integer. The inhomogeneous term.

   A single argument "Linear_Expression(arg)" is interpreted as

   * "arg" -- something that determines a linear expression.
     Possibilities are:

     * a "Variable": The linear expression given by that variable.

     * a "Linear_Expression": The copy constructor.

     * an integer: Constructs the constant linear expression.

   No argument is the default constructor and returns the zero linear
   expression.

   OUTPUT:

   A "Linear_Expression"

   Examples:

   >>> from ppl import Variable, Linear_Expression
   >>> Linear_Expression([1,2,3,4],5)
   x0+2*x1+3*x2+4*x3+5
   >>> Linear_Expression(10)
   10
   >>> Linear_Expression()
   0
   >>> Linear_Expression(10).inhomogeneous_term()
   10
   >>> x = Variable(123)
   >>> expr = x+1; expr
   x123+1
   >>> expr.OK()
   True
   >>> expr.coefficient(x)
   1
   >>> expr.coefficient( Variable(124) )
   0

   OK()

      Check if all the invariants are satisfied.

      Examples:

      >>> from ppl import Linear_Expression, Variable
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> e = 3*x+2*y+1
      >>> e.OK()
      True

   all_homogeneous_terms_are_zero()

      Test if "self" is a constant linear expression.

      OUTPUT:

      Boolean.

      Examples:

      >>> from ppl import Variable, Linear_Expression
      >>> Linear_Expression(10).all_homogeneous_terms_are_zero()
      True

   ascii_dump()

      Write an ASCII dump to stderr.

      Examples:

      >>> cmd  = 'from ppl import Linear_Expression, Variable\n'
      >>> cmd += 'x = Variable(0)\n'
      >>> cmd += 'y = Variable(1)\n'
      >>> cmd += 'e = 3*x+2*y+1\n'
      >>> cmd += 'e.ascii_dump()\n'
      >>> import subprocess
      >>> import sys
      >>> subprocess.call(['python', '-c', cmd], stderr=subprocess.STDOUT)
      size 3 1 3 2

   coefficient()

      Return the coefficient of the variable "v".

      INPUT:

      * "v" -- a "Variable".

      OUTPUT:

      An integer.

      Examples:

      >>> from ppl import Variable
      >>> x = Variable(0)
      >>> e = 3*x+1
      >>> e.coefficient(x)
      3

   coefficients()

      Return the coefficients of the linear expression.

      OUTPUT:

      A tuple of integers of length "space_dimension()".

      Examples:

      >>> from ppl import Variable
      >>> x = Variable(0);  y = Variable(1)
      >>> e = 3*x+5*y+1
      >>> e.coefficients()
      (3, 5)

   inhomogeneous_term()

      Return the inhomogeneous term of the linear expression.

      OUTPUT:

      Integer.

      Examples:

      >>> from ppl import Variable, Linear_Expression
      >>> Linear_Expression(10).inhomogeneous_term()
      10

   is_zero()

      Test if "self" is the zero linear expression.

      OUTPUT:

      Boolean.

      Examples:

      >>> from ppl import Variable, Linear_Expression
      >>> Linear_Expression(0).is_zero()
      True
      >>> Linear_Expression(10).is_zero()
      False

   space_dimension()

      Return the dimension of the vector space necessary for the
      linear expression.

      OUTPUT:

      Integer.

      Examples:

      >>> from ppl import Variable
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> (x+y+1).space_dimension()
      2
      >>> (x+y).space_dimension()
      2
      >>> (y+1).space_dimension()
      2
      >>> (x+1).space_dimension()
      1
      >>> (y+1-y).space_dimension()
      2

class class ppl.MIP_Problem

   Bases: "ppl._mutable_or_immutable"

   wrapper for PPL's MIP_Problem class

   An object of the class MIP_Problem represents a Mixed Integer
   (Linear) Program problem.

   INPUT:

   * "dim" -- integer

   * "args" -- an array of the defining data of the MIP_Problem. For
     each element, any one of the following is accepted:

     * A "Constraint_System".

     * A "Linear_Expression".

   OUTPUT:

   A "MIP_Problem".

   Examples:

   >>> from ppl import Variable, Constraint_System, MIP_Problem
   >>> x = Variable(0)
   >>> y = Variable(1)
   >>> cs = Constraint_System()
   >>> cs.insert(x >= 0)
   >>> cs.insert(y >= 0)
   >>> cs.insert(3 * x + 5 * y <= 10)
   >>> m = MIP_Problem(2, cs, x + y)
   >>> m.optimal_value()
   Fraction(10, 3)
   >>> float(_)
   3.3333333333333335
   >>> m.optimizing_point()
   point(10/3, 0/3)

   OK()

      Check if all the invariants are satisfied.

      OUTPUT:

      "True" if and only if "self" satisfies all the invariants.

      Examples:

      >>> from ppl import Variable, Constraint_System, MIP_Problem
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> m = MIP_Problem()
      >>> m.add_space_dimensions_and_embed(2)
      >>> m.add_constraint(x >= 0)
      >>> m.OK()
      True

   add_constraint()

      Adds a copy of constraint c to the MIP problem.

      Examples:

      >>> from ppl import Variable, Constraint_System, MIP_Problem
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> m = MIP_Problem()
      >>> m.add_space_dimensions_and_embed(2)
      >>> m.add_constraint(x >= 0)
      >>> m.add_constraint(y >= 0)
      >>> m.add_constraint(3 * x + 5 * y <= 10)
      >>> m.set_objective_function(x + y)
      >>> m.optimal_value()
      Fraction(10, 3)

      Tests:

      >>> z = Variable(2)
      >>> m.add_constraint(z >= -3)
      Traceback (most recent call last):
      ...
      ValueError: PPL::MIP_Problem::add_constraint(c):
      c.space_dimension() == 3 exceeds this->space_dimension == 2.

   add_constraints()

      Adds a copy of the constraints in cs to the MIP problem.

      Examples:

      >>> from ppl import Variable, Constraint_System, MIP_Problem
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> cs = Constraint_System()
      >>> cs.insert(x >= 0)
      >>> cs.insert(y >= 0)
      >>> cs.insert(3 * x + 5 * y <= 10)
      >>> m = MIP_Problem(2)
      >>> m.set_objective_function(x + y)
      >>> m.add_constraints(cs)
      >>> m.optimal_value()
      Fraction(10, 3)

      Tests:

      >>> p = Variable(9)
      >>> cs.insert(p >= -3)
      >>> m.add_constraints(cs)
      Traceback (most recent call last):
      ...
      ValueError: PPL::MIP_Problem::add_constraints(cs):
      cs.space_dimension() == 10 exceeds this->space_dimension() == 2.

   add_space_dimensions_and_embed()

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

      Examples:

      >>> from ppl import Variable, Constraint_System, MIP_Problem
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> cs = Constraint_System()
      >>> cs.insert( x >= 0)
      >>> cs.insert( y >= 0 )
      >>> cs.insert( 3 * x + 5 * y <= 10 )
      >>> m = MIP_Problem(2, cs, x + y)
      >>> m.add_space_dimensions_and_embed(5)
      >>> m.space_dimension()
      7

   clear()

      Reset the MIP_Problem to be equal to the trivial MIP_Problem.

      Examples:

      >>> from ppl import Variable, Constraint_System, MIP_Problem
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> cs = Constraint_System()
      >>> cs.insert( x >= 0)
      >>> cs.insert( y >= 0 )
      >>> cs.insert( 3 * x + 5 * y <= 10 )
      >>> m = MIP_Problem(2, cs, x + y)
      >>> m.objective_function()
      x0+x1
      >>> m.clear()
      >>> m.objective_function()
      0

   evaluate_objective_function()

      Return the result of evaluating the objective function on
      evaluating_point. ValueError thrown if self and evaluating_point
      are dimension-incompatible or if the generator evaluating_point
      is not a point.

      Examples:

      >>> from ppl import Variable, Constraint_System, MIP_Problem, Generator
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> m = MIP_Problem()
      >>> m.add_space_dimensions_and_embed(2)
      >>> m.add_constraint(x >= 0)
      >>> m.add_constraint(y >= 0)
      >>> m.add_constraint(3 * x + 5 * y <= 10)
      >>> m.set_objective_function(x + y)
      >>> g = Generator.point(5 * x - 2 * y, 7)
      >>> m.evaluate_objective_function(g)
      Fraction(3, 7)
      >>> z = Variable(2)
      >>> g = Generator.point(5 * x - 2 * z, 7)
      >>> m.evaluate_objective_function(g)
      Traceback (most recent call last):
      ...
      ValueError: PPL::MIP_Problem::evaluate_objective_function(p, n, d):
      *this and p are dimension incompatible.

   is_satisfiable()

      Check if the MIP_Problem is satisfiable

      Examples:

      >>> from ppl import Variable, Constraint_System, MIP_Problem
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> m = MIP_Problem()
      >>> m.add_space_dimensions_and_embed(2)
      >>> m.add_constraint(x >= 0)
      >>> m.add_constraint(y >= 0)
      >>> m.add_constraint(3 * x + 5 * y <= 10)
      >>> m.is_satisfiable()
      True

   objective_function()

      Return the optimal value of the MIP_Problem.

      Examples:

      >>> from ppl import Variable, Constraint_System, MIP_Problem
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> cs = Constraint_System()
      >>> cs.insert( x >= 0)
      >>> cs.insert( y >= 0 )
      >>> cs.insert( 3 * x + 5 * y <= 10 )
      >>> m = MIP_Problem(2, cs, x + y)
      >>> m.objective_function()
      x0+x1

   optimal_value()

      Return the optimal value of the MIP_Problem. ValueError thrown
      if self does not have an optimizing point, i.e., if the MIP
      problem is unbounded or not satisfiable.

      Examples:

      >>> from ppl import Variable, Constraint_System, MIP_Problem
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> cs = Constraint_System()
      >>> cs.insert( x >= 0 )
      >>> cs.insert( y >= 0 )
      >>> cs.insert( 3 * x + 5 * y <= 10 )
      >>> m = MIP_Problem(2, cs, x + y)
      >>> m.optimal_value()
      10/3
      >>> cs = Constraint_System()
      >>> cs.insert( x >= 0 )
      >>> m = MIP_Problem(1, cs, x + x )
      >>> m.optimal_value()
      Traceback (most recent call last):
      ...
      ValueError: PPL::MIP_Problem::optimizing_point():
      *this does not have an optimizing point.

   optimization_mode()

      Return the optimization mode used in the MIP_Problem.

      It will return "maximization" if the MIP_Problem was set to
      MAXIMIZATION mode, and "minimization" otherwise.

      Examples:

      >>> from ppl import MIP_Problem
      >>> m = MIP_Problem()
      >>> m.optimization_mode()
      'maximization'

   optimizing_point()

      Returns an optimal point for the MIP_Problem, if it exists.

      Examples:

      >>> from ppl import Variable, Constraint_System, MIP_Problem
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> m = MIP_Problem()
      >>> m.add_space_dimensions_and_embed(2)
      >>> m.add_constraint(x >= 0)
      >>> m.add_constraint(y >= 0)
      >>> m.add_constraint(3 * x + 5 * y <= 10)
      >>> m.set_objective_function(x + y)
      >>> m.optimizing_point()
      point(10/3, 0/3)

   set_objective_function()

      Sets the objective function to obj.

      Examples:

      >>> from ppl import Variable, Constraint_System, MIP_Problem
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> m = MIP_Problem()
      >>> m.add_space_dimensions_and_embed(2)
      >>> m.add_constraint(x >= 0)
      >>> m.add_constraint(y >= 0)
      >>> m.add_constraint(3 * x + 5 * y <= 10)
      >>> m.set_objective_function(x + y)
      >>> m.optimal_value()
      Fraction(10, 3)

      Tests:

      >>> z = Variable(2)
      >>> m.set_objective_function(x + y + z)
      Traceback (most recent call last):
      ...
      ValueError: PPL::MIP_Problem::set_objective_function(obj):
      obj.space_dimension() == 3 exceeds this->space_dimension == 2.

   set_optimization_mode()

      Sets the optimization mode to mode.

      Examples:

      >>> from ppl import MIP_Problem
      >>> m = MIP_Problem()
      >>> m.optimization_mode()
      'maximization'
      >>> m.set_optimization_mode('minimization')
      >>> m.optimization_mode()
      'minimization'

      Tests:

      >>> m.set_optimization_mode('max')
      Traceback (most recent call last):
      ...
      ValueError: Unknown value: mode=max.

   solve()

      Optimizes the MIP_Problem

      Examples:

      >>> from ppl import Variable, Constraint_System, MIP_Problem
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> m = MIP_Problem()
      >>> m.add_space_dimensions_and_embed(2)
      >>> m.add_constraint(x >= 0)
      >>> m.add_constraint(y >= 0)
      >>> m.add_constraint(3 * x + 5 * y <= 10)
      >>> m.set_objective_function(x + y)
      >>> m.solve()
      {'status': 'optimized'}

   space_dimension()

      Return the space dimension of the MIP_Problem.

      Examples:

      >>> from ppl import Variable, Constraint_System, MIP_Problem
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> cs = Constraint_System()
      >>> cs.insert( x >= 0)
      >>> cs.insert( y >= 0 )
      >>> cs.insert( 3 * x + 5 * y <= 10 )
      >>> m = MIP_Problem(2, cs, x + y)
      >>> m.space_dimension()
      2

class class ppl.NNC_Polyhedron

   Bases: "ppl.Polyhedron"

   Wrapper for PPL's "NNC_Polyhedron" class.

   An object of the class "NNC_Polyhedron" represents a not
   necessarily closed (NNC) convex polyhedron in the vector space.

   Note: Since NNC polyhedra are a generalization of closed polyhedra,
   any object of the class "C_Polyhedron" can be (explicitly)
   converted into an object of the class "NNC_Polyhedron". The reason
   for defining two different classes is that objects of the class
   "C_Polyhedron" are characterized by a more efficient
   implementation, requiring less time and memory resources.

   INPUT:

   * "arg" -- the defining data of the polyhedron. Any one of the
     following is accepted:

     * An non-negative integer. Depending on "degenerate_element",
       either the space-filling or the empty polytope in the given
       dimension "arg" is constructed.

     * A "Constraint_System".

     * A "Generator_System".

     * A single "Constraint".

     * A single "Generator".

     * A "NNC_Polyhedron".

     * A "C_Polyhedron".

   * "degenerate_element" -- string, either "'universe'" or
     "'empty'". Only used if "arg" is an integer.

   OUTPUT:

   A "C_Polyhedron".

   Examples:

   >>> from ppl import Constraint, Constraint_System, Generator, Generator_System, Variable, NNC_Polyhedron, point, ray, closure_point
   >>> x = Variable(0)
   >>> y = Variable(1)
   >>> NNC_Polyhedron( 5*x-2*y >  x+y-1 )
   A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point, 1 closure_point, 1 ray, 1 line
   >>> cs = Constraint_System()
   >>> cs.insert( x > 0 )
   >>> cs.insert( y > 0 )
   >>> NNC_Polyhedron(cs)
   A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point, 1 closure_point, 2 rays
   >>> NNC_Polyhedron( point(x+y) )
   A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point
   >>> gs = Generator_System()
   >>> gs.insert( point(-y) )
   >>> gs.insert( closure_point(-x-y) )
   >>> gs.insert( ray(x) )
   >>> p = NNC_Polyhedron(gs); p
   A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point, 1 closure_point, 1 ray
   >>> p.minimized_constraints()
   Constraint_System {x1+1==0, x0+1>0}

   Note that, by convention, every polyhedron must contain a point:

   >>> NNC_Polyhedron( closure_point(x+y) )
   Traceback (most recent call last):
   ...
   ValueError: PPL::NNC_Polyhedron::NNC_Polyhedron(gs):
   *this is an empty polyhedron and
   the non-empty generator system gs contains no points.

class class ppl.Poly_Con_Relation

   Bases: "object"

   Wrapper for PPL's "Poly_Con_Relation" class.

   INPUT/OUTPUT:

   You must not construct "Poly_Con_Relation" objects manually. You
   will usually get them from "relation_with()". You can also get pre-
   defined relations from the class methods "nothing()",
   "is_disjoint()", "strictly_intersects()", "is_included()", and
   "saturates()".

   Examples:

   >>> from ppl import Poly_Con_Relation
   >>> saturates     = Poly_Con_Relation.saturates();  saturates
   saturates
   >>> is_included   = Poly_Con_Relation.is_included(); is_included
   is_included
   >>> is_included.implies(saturates)
   False
   >>> saturates.implies(is_included)
   False
   >>> rels = []
   >>> rels.append(Poly_Con_Relation.nothing())
   >>> rels.append(Poly_Con_Relation.is_disjoint())
   >>> rels.append(Poly_Con_Relation.strictly_intersects())
   >>> rels.append(Poly_Con_Relation.is_included())
   >>> rels.append(Poly_Con_Relation.saturates())
   >>> rels
   [nothing, is_disjoint, strictly_intersects, is_included, saturates]
   >>> for i, rel_i in enumerate(rels):
   ...       for j, rel_j in enumerate(rels):
   ...           print int(rel_i.implies(rel_j)),
   ...       print
   1 0 0 0 0
   1 1 0 0 0
   1 0 1 0 0
   1 0 0 1 0
   1 0 0 0 1

   OK()

      Check if all the invariants are satisfied.

      Examples:

      >>> from ppl import Poly_Con_Relation
      >>> Poly_Con_Relation.nothing().OK()
      True

   ascii_dump()

      Write an ASCII dump to stderr.

      Examples:

      >>> cmd  = 'from ppl import Poly_Con_Relation\n'
      >>> cmd += 'Poly_Con_Relation.nothing().ascii_dump()\n'
      >>> import subprocess
      >>> import sys
      >>> subprocess.call(['python', '-c', cmd], stderr=subprocess.STDOUT)
      NOTHING

   implies()

      Test whether "self" implies "y".

      INPUT:

      * "y" -- a "Poly_Con_Relation".

      OUTPUT:

      Boolean. "True" if and only if "self" implies "y".

      Examples:

      >>> from ppl import Poly_Con_Relation
      >>> nothing = Poly_Con_Relation.nothing()
      >>> nothing.implies( nothing )
      True

   static is_disjoint()

      Return the assertion "The polyhedron and the set of points
      satisfying the constraint are disjoint".

      OUTPUT:

      A "Poly_Con_Relation".

      Examples:

      >>> from ppl import Poly_Con_Relation
      >>> Poly_Con_Relation.is_disjoint()
      is_disjoint

   static is_included()

      Return the assertion "The polyhedron is included in the set of
      points satisfying the constraint".

      OUTPUT:

      A "Poly_Con_Relation".

      Examples:

      >>> from ppl import Poly_Con_Relation
      >>> Poly_Con_Relation.is_included()
      is_included

   static nothing()

      Return the assertion that says nothing.

      OUTPUT:

      A "Poly_Con_Relation".

      Examples:

      >>> from ppl import Poly_Con_Relation
      >>> Poly_Con_Relation.nothing()
      nothing

   static saturates()

      Return the assertion "".

      OUTPUT:

      A "Poly_Con_Relation".

      Examples:

      >>> from ppl import Poly_Con_Relation
      >>> Poly_Con_Relation.saturates()
      saturates

   static strictly_intersects()

      Return the assertion "The polyhedron intersects the set of
      points satisfying the constraint, but it is not included in it".

      Returns:
         a "Poly_Con_Relation".

      Examples:

      >>> from ppl import Poly_Con_Relation
      >>> Poly_Con_Relation.strictly_intersects()
      strictly_intersects

class class ppl.Poly_Gen_Relation

   Bases: "object"

   Wrapper for PPL's "Poly_Con_Relation" class.

   INPUT/OUTPUT:

   You must not construct "Poly_Gen_Relation" objects manually. You
   will usually get them from "relation_with()". You can also get pre-
   defined relations from the class methods "nothing()" and
   "subsumes()".

   Examples:

   >>> from ppl import Poly_Gen_Relation
   >>> nothing = Poly_Gen_Relation.nothing(); nothing
   nothing
   >>> subsumes = Poly_Gen_Relation.subsumes(); subsumes
   subsumes
   >>> nothing.implies( subsumes )
   False
   >>> subsumes.implies( nothing )
   True

   OK()

      Check if all the invariants are satisfied.

      Examples:

      >>> from ppl import Poly_Gen_Relation
      >>> Poly_Gen_Relation.nothing().OK()
      True

   ascii_dump()

      Write an ASCII dump to stderr.

      Examples:

      >>> cmd  = 'from ppl import Poly_Gen_Relation\n'
      >>> cmd += 'Poly_Gen_Relation.nothing().ascii_dump()\n'
      >>> import subprocess
      >>> import sys
      >>> subprocess.call(['python', '-c', cmd], stderr=subprocess.STDOUT)
      NOTHING

   implies()

      Test whether "self" implies "y".

      INPUT:

      * "y" -- a "Poly_Gen_Relation".

      OUTPUT:

      Boolean. "True" if and only if "self" implies "y".

      Examples:

      >>> from ppl import Poly_Gen_Relation
      >>> nothing = Poly_Gen_Relation.nothing()
      >>> nothing.implies( nothing )
      True

   static nothing()

      Return the assertion that says nothing.

      OUTPUT:

      A "Poly_Gen_Relation".

      Examples:

      >>> from ppl import Poly_Gen_Relation
      >>> Poly_Gen_Relation.nothing()
      nothing

   static subsumes()

      Return the assertion "Adding the generator would not change the
      polyhedron".

      OUTPUT:

      A "Poly_Gen_Relation".

      Examples:

      >>> from ppl import Poly_Gen_Relation
      >>> Poly_Gen_Relation.subsumes()
      subsumes

class class ppl.Polyhedron

   Bases: "ppl._mutable_or_immutable"

   Wrapper for PPL's "Polyhedron" class.

   An object of the class Polyhedron represents a convex polyhedron in
   the vector space.

   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.

   INPUT/OUTPUT:

   This is an abstract base for "C_Polyhedron" and "NNC_Polyhedron".
   You cannot instantiate this class.

   OK()

      Check if all the invariants are satisfied.

      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.

      INPUT:

      * "check_not_empty" -- boolean. "True" if and only if, in
        addition to checking the invariants, "self" must be checked to
        be not empty.

      OUTPUT:

      "True" if and only if "self" satisfies all the invariants and
      either "check_not_empty" is "False" or "self" is not empty.

      Examples:

      >>> from ppl import Linear_Expression, Variable
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> e = 3*x+2*y+1
      >>> e.OK()
      True

   add_constraint()

      Add a constraint to the polyhedron.

      Adds a copy of constraint "c" to the system of constraints of
      "self", without minimizing the result.

      See alse "add_constraints()".

      INPUT:

      * "c" -- the "Constraint" that will be added to the system of
        constraints of "self".

      OUTPUT:

      This method modifies the polyhedron "self" and does not return
      anything.

      Raises a "ValueError" if "self" and the constraint "c" are
      topology-incompatible or dimension-incompatible.

      Examples:

      >>> from ppl import Variable, C_Polyhedron
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> p = C_Polyhedron( y>=0 )
      >>> p.add_constraint( x>=0 )

         We just added a 1-d constraint to a 2-d polyhedron, this is
         fine. The other way is not:

      >>> p = C_Polyhedron( x>=0 )
      >>> p.add_constraint( y>=0 )
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::add_constraint(c):
      this->space_dimension() == 1, c.space_dimension() == 2.

         The constraint must also be topology-compatible, that is,
         "C_Polyhedron" only allows non-strict inequalities:

      >>> p = C_Polyhedron( x>=0 )
      >>> p.add_constraint( x< 1 )
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::add_constraint(c):
      c is a strict inequality.

   add_constraints()

      Add constraints to the polyhedron.

      Adds a copy of constraints in "cs" to the system of constraints
      of "self", without minimizing the result.

      See alse "add_constraint()".

      INPUT:

      * "cs" -- the "Constraint_System" that will be added to the
        system of constraints of "self".

      OUTPUT:

      This method modifies the polyhedron "self" and does not return
      anything.

      Raises a "ValueError" if "self" and the constraints in "cs" are
      topology-incompatible or dimension-incompatible.

      Examples:

      >>> from ppl import Variable, C_Polyhedron, Constraint_System
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> cs = Constraint_System()
      >>> cs.insert(x>=0)
      >>> cs.insert(y>=0)
      >>> p = C_Polyhedron( y<=1 )
      >>> p.add_constraints(cs)

      We just added a 1-d constraint to a 2-d polyhedron, this is
      fine. The other way is not:

      >>> p = C_Polyhedron( x<=1 )
      >>> p.add_constraints(cs)
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::add_recycled_constraints(cs):
      this->space_dimension() == 1, cs.space_dimension() == 2.

      The constraints must also be topology-compatible, that is,
      "C_Polyhedron" only allows non-strict inequalities:

      >>> p = C_Polyhedron( x>=0 )
      >>> p.add_constraints( Constraint_System(x<0) )
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::add_recycled_constraints(cs):
      cs contains strict inequalities.

   add_generator()

      Add a generator to the polyhedron.

      Adds a copy of constraint "c" to the system of generators of
      "self", without minimizing the result.

      INPUT:

      * "g" -- the "Generator" that will be added to the system of
        Generators of "self".

      OUTPUT:

      This method modifies the polyhedron "self" and does not return
      anything.

      Raises a "ValueError" if "self" and the generator "g" are
      topology-incompatible or dimension-incompatible, or if "self" is
      an empty polyhedron and "g" is not a point.

      Examples:

      >>> from ppl import Variable, C_Polyhedron, point, closure_point, ray
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> p = C_Polyhedron(1, 'empty')
      >>> p.add_generator( point(0*x) )

         We just added a 1-d generator to a 2-d polyhedron, this is
         fine. The other way is not:

      >>> p = C_Polyhedron(1, 'empty')
      >>> p.add_generator(  point(0*y) )
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::add_generator(g):
      this->space_dimension() == 1, g.space_dimension() == 2.

         The constraint must also be topology-compatible, that is,
         "C_Polyhedron" does not allow "closure_point()" generators:

      >>> p = C_Polyhedron( point(0*x+0*y) )
      >>> p.add_generator( closure_point(0*x) )
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::add_generator(g):
      g is a closure point.

      Finally, ever non-empty polyhedron must have at least one point
      generator:

      >>> p = C_Polyhedron(3, 'empty')
      >>> p.add_generator( ray(x) )
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::add_generator(g):
      *this is an empty polyhedron and g is not a point.

   add_generators()

      Add generators to the polyhedron.

      Adds a copy of the generators in "gs" to the system of
      generators of "self", without minimizing the result.

      See alse "add_generator()".

      INPUT:

      * "gs" -- the "Generator_System" that will be added to the
        system of constraints of "self".

      OUTPUT:

      This method modifies the polyhedron "self" and does not return
      anything.

      Raises a "ValueError" if "self" and one of the generators in
      "gs" are topology-incompatible or dimension-incompatible, or if
      "self" is an empty polyhedron and "gs" does not contain a point.

      Examples:

      >>> from ppl import Variable, C_Polyhedron, Generator_System, point, ray, closure_point
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> gs = Generator_System()
      >>> gs.insert(point(0*x+0*y))
      >>> gs.insert(point(1*x+1*y))
      >>> p = C_Polyhedron(2, 'empty')
      >>> p.add_generators(gs)

      We just added a 1-d constraint to a 2-d polyhedron, this is
      fine. The other way is not:

      >>> p = C_Polyhedron(1, 'empty')
      >>> p.add_generators(gs)
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::add_recycled_generators(gs):
      this->space_dimension() == 1, gs.space_dimension() == 2.

      The constraints must also be topology-compatible, that is,
      "C_Polyhedron" does not allow "closure_point()" generators:

      >>> p = C_Polyhedron( point(0*x+0*y) )
      >>> p.add_generators( Generator_System(closure_point(x) ))
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::add_recycled_generators(gs):
      gs contains closure points.

   add_space_dimensions_and_embed()

      Add "m" new space dimensions and embed "self" in the new vector
      space.

      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 *P* and adding a third space dimension, the
      result will be the polyhedron

         \Big\{ (x,y,z)^T \in \RR^3 \Big| (x,y)^T \in P \Big\}

      INPUT:

      * "m" -- integer.

      OUTPUT:

      This method assigns the embedded polyhedron to "self" and does
      not return anything.

      Raises a "ValueError" if adding "m" new space dimensions would
      cause the vector space to exceed dimension
      "self.max_space_dimension()".

      Examples:

      >>> from ppl import Variable, C_Polyhedron, point
      >>> x = Variable(0)
      >>> p = C_Polyhedron( point(3*x) )
      >>> p.add_space_dimensions_and_embed(1)
      >>> p.minimized_generators()
      Generator_System {line(0, 1), point(3/1, 0/1)}
      >>> p.add_space_dimensions_and_embed( p.max_space_dimension() )
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::add_space_dimensions_and_embed(m):
      adding m new space dimensions exceeds the maximum allowed space dimension.

   add_space_dimensions_and_project()

      Add "m" new space dimensions and embed "self" in the new vector
      space.

      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 *P* and adding a
      third space dimension, the result will be the polyhedron

         \Big\{ (x,y,0)^T \in \RR^3 \Big| (x,y)^T \in P \Big\}

      INPUT:

      * "m" -- integer.

      OUTPUT:

      This method assigns the projected polyhedron to "self" and does
      not return anything.

      Raises a "ValueError" if adding "m" new space dimensions would
      cause the vector space to exceed dimension
      "self.max_space_dimension()".

      Examples:

      >>> from ppl import Variable, C_Polyhedron, point
      >>> x = Variable(0)
      >>> p = C_Polyhedron( point(3*x) )
      >>> p.add_space_dimensions_and_project(1)
      >>> p.minimized_generators()
      Generator_System {point(3/1, 0/1)}
      >>> p.add_space_dimensions_and_project( p.max_space_dimension() )
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::add_space_dimensions_and_project(m):
      adding m new space dimensions exceeds the maximum allowed space dimension.

   affine_dimension()

      Return the affine dimension of "self".

      OUTPUT:

      An integer. Returns 0 if "self" is empty. Otherwise, returns the
      affine dimension of "self".

      Examples:

      >>> from ppl import Variable, C_Polyhedron
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> p = C_Polyhedron( 5*x-2*y ==  x+y-1 )
      >>> p.affine_dimension()
      1

   ascii_dump()

      Write an ASCII dump to stderr.

      Examples:

      >>> cmd  = 'from ppl import C_Polyhedron, Variable\n'
      >>> cmd += 'x = Variable(0)\n'
      >>> cmd += 'y = Variable(1)\n'
      >>> cmd += 'p = C_Polyhedron(3*x+2*y==1)\n'
      >>> cmd += 'p.minimized_generators()\n'
      >>> cmd += 'p.ascii_dump()\n'
      >>> import subprocess
      >>> import sys
      >>> out = subprocess.call(['python', '-c', cmd], stderr=subprocess.STDOUT)
      space_dim 2
      -ZE -EM  +CM +GM  +CS +GS  -CP -GP  -SC +SG
      con_sys (up-to-date)
      topology NECESSARILY_CLOSED
      2 x 2 SPARSE (sorted)
      index_first_pending 2
      size 3 -1 3 2 = (C)
      size 3 1 0 0 >= (C)
      <BLANKLINE>
      gen_sys (up-to-date)
      topology NECESSARILY_CLOSED
      2 x 2 DENSE (not_sorted)
      index_first_pending 2
      size 3 0 2 -3 L (C)
      size 3 2 0 1 P (C)
      <BLANKLINE>
      sat_c
      0 x 0
      <BLANKLINE>
      sat_g
      2 x 2
      0 0
      0 1
      >>> print out
      0

   bounds_from_above()

      Test whether the "expr" is bounded from above.

      INPUT:

      * "expr" -- a "Linear_Expression"

      OUTPUT:

      Boolean. Returns "True" if and only if "expr" is bounded from
      above in "self".

      Raises a "ValueError" if "expr" and "this" are dimension-
      incompatible.

      Examples:

      >>> from ppl import Variable, C_Polyhedron, Linear_Expression
      >>> x = Variable(0);  y = Variable(1)
      >>> p = C_Polyhedron(y<=0)
      >>> p.bounds_from_above(x+1)
      False
      >>> p.bounds_from_above(Linear_Expression(y))
      True
      >>> p = C_Polyhedron(x<=0)
      >>> p.bounds_from_above(y+1)
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::bounds_from_above(e):
      this->space_dimension() == 1, e.space_dimension() == 2.

   bounds_from_below()

      Test whether the "expr" is bounded from above.

      INPUT:

      * "expr" -- a "Linear_Expression"

      OUTPUT:

      Boolean. Returns "True" if and only if "expr" is bounded from
      above in "self".

      Raises a "ValueError" if "expr" and "this" are dimension-
      incompatible.

      Examples:

      >>> from ppl import Variable, C_Polyhedron, Linear_Expression
      >>> x = Variable(0);  y = Variable(1)
      >>> p = C_Polyhedron(y>=0)
      >>> p.bounds_from_below(x+1)
      False
      >>> p.bounds_from_below(Linear_Expression(y))
      True
      >>> p = C_Polyhedron(x<=0)
      >>> p.bounds_from_below(y+1)
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::bounds_from_below(e):
      this->space_dimension() == 1, e.space_dimension() == 2.

   concatenate_assign()

      Assign to "self" the concatenation of "self" and "y".

      This functions returns the Cartiesian product of "self" and "y".

      Viewing a polyhedron as a set of tuples (its points), it is
      sometimes useful to consider the set of tuples obtained by
      concatenating an ordered pair of polyhedra. Formally, the
      concatenation of the polyhedra *P* and *Q* (taken in this order)
      is the polyhedron such that

         R = \Big\{ (x_0,\dots,x_{n-1},y_0,\dots,y_{m-1})^T \in
         \RR^{n+m} \Big| (x_0,\dots,x_{n-1})^T \in P ,~
         (y_0,\dots,y_{m-1})^T \in Q \Big\}

      Another way of seeing it is as follows: first embed polyhedron
      *P* into a vector space of dimension *n+m* and then add a
      suitably renamed-apart version of the constraints defining *Q*.

      INPUT:

      * "m" -- integer.

      OUTPUT:

      This method assigns the concatenated polyhedron to "self" and
      does not return anything.

      Raises a "ValueError" if "self" and "y" are topology-
      incompatible or if adding "y.space_dimension()" new space
      dimensions would cause the vector space to exceed dimension
      "self.max_space_dimension()".

      Examples:

      >>> from ppl import Variable, C_Polyhedron, NNC_Polyhedron, point
      >>> x = Variable(0)
      >>> p1 = C_Polyhedron( point(1*x) )
      >>> p2 = C_Polyhedron( point(2*x) )
      >>> p1.concatenate_assign(p2)
      >>> p1.minimized_generators()
      Generator_System {point(1/1, 2/1)}

      The polyhedra must be topology-compatible and not exceed the
      maximum space dimension:

      >>> p1.concatenate_assign( NNC_Polyhedron(1, 'universe') )
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::concatenate_assign(y):
      y is a NNC_Polyhedron.
      >>> p1.concatenate_assign( C_Polyhedron(p1.max_space_dimension(), 'empty') )
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::concatenate_assign(y):
      concatenation exceeds the maximum allowed space dimension.

   constrains()

      Test whether "var" is constrained in "self".

      INPUT:

      * "var" -- a "Variable".

      OUTPUT:

      Boolean. Returns "True" if and only if "var" is constrained in
      "self".

      Raises a "ValueError" if "var" is not a space dimension of
      "self".

      Examples:

      >>> from ppl import Variable, C_Polyhedron
      >>> x = Variable(0)
      >>> p = C_Polyhedron(1, 'universe')
      >>> p.constrains(x)
      False
      >>> p = C_Polyhedron(x>=0)
      >>> p.constrains(x)
      True
      >>> y = Variable(1)
      >>> p.constrains(y)
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::constrains(v):
      this->space_dimension() == 1, v.space_dimension() == 2.

   constraints()

      Returns the system of constraints.

      See also "minimized_constraints()".

      OUTPUT:

      A "Constraint_System".

      Examples:

      >>> from ppl import Variable, C_Polyhedron
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> p = C_Polyhedron(y >= 0)
      >>> p.add_constraint(x >= 0)
      >>> p.add_constraint(x+y >= 0)
      >>> p.constraints()
      Constraint_System {x1>=0, x0>=0, x0+x1>=0}
      >>> p.minimized_constraints()
      Constraint_System {x1>=0, x0>=0}

   contains()

      Test whether "self" contains "y".

      INPUT:

      * "y" -- a "Polyhedron".

      OUTPUT:

      Boolean. Returns "True" if and only if "self" contains "y".

      Raises a "ValueError" if "self" and "y" are topology-
      incompatible or dimension-incompatible.

      Examples:

      >>> from ppl import Variable, C_Polyhedron, NNC_Polyhedron
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> p0 = C_Polyhedron( x>=0 )
      >>> p1 = C_Polyhedron( x>=1 )
      >>> p0.contains(p1)
      True
      >>> p1.contains(p0)
      False

      Errors are raised if the dimension or topology is not
      compatible:

      >>> p0.contains(C_Polyhedron(y>=0))
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::contains(y):
      this->space_dimension() == 1, y.space_dimension() == 2.
      >>> p0.contains(NNC_Polyhedron(x>0))
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::contains(y):
      y is a NNC_Polyhedron.

   contains_integer_point()

      Test whether "self" contains an integer point.

      OUTPUT:

      Boolean. Returns "True" if and only if "self" contains an
      integer point.

      Examples:

      >>> from ppl import Variable, NNC_Polyhedron
      >>> x = Variable(0)
      >>> p = NNC_Polyhedron(x>0)
      >>> p.add_constraint(x<1)
      >>> p.contains_integer_point()
      False
      >>> p.topological_closure_assign()
      >>> p.contains_integer_point()
      True

   difference_assign()

      Assign to "self" the poly-difference of "self" and "y".

      For any pair of NNC polyhedra *P_1* and *P_2* the convex
      polyhedral difference (or poly-difference) of *P_1* and *P_2* is
      defined as the smallest convex polyhedron containing the set-
      theoretic difference *P_1setminus P_2* of *P_1* and *P_2*.

      In general, even if *P_1* and *P_2* are topologically closed
      polyhedra, their poly-difference may be a convex polyhedron that
      is not topologically closed. For this reason, when computing the
      poly-difference of two "C_Polyhedron", the library will enforce
      the topological closure of the result.

      INPUT:

      * "y" -- a "Polyhedron"

      OUTPUT:

      This method assigns the poly-difference to "self" and does not
      return anything.

      Raises a "ValueError" if "self" and and "y" are topology-
      incompatible or dimension-incompatible.

      Examples:

      >>> from ppl import Variable, C_Polyhedron, point, closure_point, NNC_Polyhedron
      >>> x = Variable(0)
      >>> p = NNC_Polyhedron( point(0*x) )
      >>> p.add_generator( point(1*x) )
      >>> p.poly_difference_assign(NNC_Polyhedron( point(0*x) ))
      >>> p.minimized_constraints()
      Constraint_System {-x0+1>=0, x0>0}

      The poly-difference of "C_polyhedron" is really its closure:

      >>> p = C_Polyhedron( point(0*x) )
      >>> p.add_generator( point(1*x) )
      >>> p.poly_difference_assign(C_Polyhedron( point(0*x) ))
      >>> p.minimized_constraints()
      Constraint_System {x0>=0, -x0+1>=0}

      "self" and "y" must be dimension- and topology-compatible, or an
      exception is raised:

      >>> y = Variable(1)
      >>> p.poly_difference_assign( C_Polyhedron(y>=0) )
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::poly_difference_assign(y):
      this->space_dimension() == 1, y.space_dimension() == 2.
      >>> p.poly_difference_assign( NNC_Polyhedron(x+y<1) )
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::poly_difference_assign(y):
      y is a NNC_Polyhedron.

   drop_some_non_integer_points()

      Possibly tighten "self" by dropping some points with non-integer
      coordinates.

      The modified polyhedron satisfies:

      * it is (not necessarily strictly) contained in the original
        polyhedron.

      * integral vertices (generating points with integer
        coordinates) of the original polyhedron are not removed.

      Note: The modified polyhedron is not neccessarily a lattice
        polyhedron; Some vertices will, in general, still be rational.
        Lattice points interior to the polyhedron may be lost in the
        process.

      Examples:

      >>> from ppl import Variable, NNC_Polyhedron, Constraint_System
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> cs = Constraint_System()
      >>> cs.insert( x>=0 )
      >>> cs.insert( y>=0 )
      >>> cs.insert( 3*x+2*y<5 )
      >>> p = NNC_Polyhedron(cs)
      >>> p.minimized_generators()
      Generator_System {point(0/1, 0/1), closure_point(0/2, 5/2), closure_point(5/3, 0/3)}
      >>> p.drop_some_non_integer_points()
      >>> p.minimized_generators()
      Generator_System {point(0/1, 0/1), point(0/1, 2/1), point(4/3, 0/3)}

   generators()

      Returns the system of generators.

      See also "minimized_generators()".

      OUTPUT:

      A "Generator_System".

      Examples:

      >>> from ppl import Variable, C_Polyhedron, point
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> p = C_Polyhedron(3,'empty')
      >>> p.add_generator(point(-x-y))
      >>> p.add_generator(point(0))
      >>> p.add_generator(point(+x+y))
      >>> p.generators()
      Generator_System {point(-1/1, -1/1, 0/1), point(0/1, 0/1, 0/1), point(1/1, 1/1, 0/1)}
      >>> p.minimized_generators()
      Generator_System {point(-1/1, -1/1, 0/1), point(1/1, 1/1, 0/1)}

   intersection_assign()

      Assign to "self" the intersection of "self" and "y".

      INPUT:

      * "y" -- a "Polyhedron"

      OUTPUT:

      This method assigns the intersection to "self" and does not
      return anything.

      Raises a "ValueError" if "self" and and "y" are topology-
      incompatible or dimension-incompatible.

      Examples:

      >>> from ppl import Variable, C_Polyhedron, NNC_Polyhedron
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> p = C_Polyhedron( 1*x+0*y >= 0 )
      >>> p.intersection_assign( C_Polyhedron(y>=0) )
      >>> p.constraints()
      Constraint_System {x0>=0, x1>=0}
      >>> z = Variable(2)
      >>> p.intersection_assign( C_Polyhedron(z>=0) )
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::intersection_assign(y):
      this->space_dimension() == 2, y.space_dimension() == 3.
      >>> p.intersection_assign( NNC_Polyhedron(x+y<1) )
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::intersection_assign(y):
      y is a NNC_Polyhedron.

   is_bounded()

      Test whether "self" is bounded.

      OUTPUT:

      Boolean. Returns "True" if and only if "self" is a bounded
      polyhedron.

      Examples:

      >>> from ppl import Variable, NNC_Polyhedron, point, closure_point, ray
      >>> x = Variable(0)
      >>> p = NNC_Polyhedron( point(0*x) )
      >>> p.add_generator( closure_point(1*x) )
      >>> p.is_bounded()
      True
      >>> p.add_generator( ray(1*x) )
      >>> p.is_bounded()
      False

   is_discrete()

      Test whether "self" is discrete.

      OUTPUT:

      Boolean. Returns "True" if and only if "self" is discrete.

      Examples:

      >>> from ppl import Variable, C_Polyhedron, point, ray
      >>> x = Variable(0);  y = Variable(1)
      >>> p = C_Polyhedron( point(1*x+2*y) )
      >>> p.is_discrete()
      True
      >>> p.add_generator( point(x) )
      >>> p.is_discrete()
      False

   is_disjoint_from()

      Tests whether "self" and "y" are disjoint.

      INPUT:

      * "y" -- a "Polyhedron".

      OUTPUT:

      Boolean. Returns "True" if and only if "self" and "y" are
      disjoint.

      Rayises a "ValueError" if "self" and "y" are topology-
      incompatible or dimension-incompatible.

      Examples:

      >>> from ppl import Variable, C_Polyhedron, NNC_Polyhedron
      >>> x = Variable(0);  y = Variable(1)
      >>> C_Polyhedron(x<=0).is_disjoint_from( C_Polyhedron(x>=1) )
      True

      This is not allowed:

         >>> x = Variable(0);  y = Variable(1)
         >>> poly_1d = C_Polyhedron(x<=0)
         >>> poly_2d = C_Polyhedron(x+0*y>=1)
         >>> poly_1d.is_disjoint_from(poly_2d)
         Traceback (most recent call last):
         ...
         ValueError: PPL::C_Polyhedron::intersection_assign(y):
         this->space_dimension() == 1, y.space_dimension() == 2.

      Nor is this:

         >>> x = Variable(0);  y = Variable(1)
         >>> c_poly   =   C_Polyhedron( x<=0 )
         >>> nnc_poly = NNC_Polyhedron( x >0 )
         >>> c_poly.is_disjoint_from(nnc_poly)
         Traceback (most recent call last):
         ...
         ValueError: PPL::C_Polyhedron::intersection_assign(y):
         y is a NNC_Polyhedron.
         >>> NNC_Polyhedron(c_poly).is_disjoint_from(nnc_poly)
         True

   is_empty()

      Test if "self" is an empty polyhedron.

      OUTPUT:

      Boolean.

      Examples:

      >>> from ppl import C_Polyhedron
      >>> C_Polyhedron(3, 'empty').is_empty()
      True
      >>> C_Polyhedron(3, 'universe').is_empty()
      False

   is_topologically_closed()

      Tests if "self" is topologically closed.

      OUTPUT:

      Returns "True" if and only if "self" is a topologically closed
      subset of the ambient vector space.

      Examples:

      >>> from ppl import Variable, C_Polyhedron, NNC_Polyhedron
      >>> x = Variable(0);  y = Variable(1)
      >>> C_Polyhedron(3, 'universe').is_topologically_closed()
      True
      >>> C_Polyhedron( x>=1 ).is_topologically_closed()
      True
      >>> NNC_Polyhedron( x>1 ).is_topologically_closed()
      False

   is_universe()

      Test if "self" is a universe (space-filling) polyhedron.

      OUTPUT:

      Boolean.

      Examples:

      >>> from ppl import C_Polyhedron
      >>> C_Polyhedron(3, 'empty').is_universe()
      False
      >>> C_Polyhedron(3, 'universe').is_universe()
      True

   max_space_dimension()

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

      OUTPUT:

      Integer.

      Examples:

      >>> from ppl import C_Polyhedron
      >>> C_Polyhedron(1, 'empty').max_space_dimension()   # random output
      1152921504606846974
      >>> C_Polyhedron(1, 'empty').max_space_dimension()
      357913940            # 32-bit
      1152921504606846974  # 64-bit

   maximize()

      Maximize "expr".

      INPUT:

      * "expr" -- a "Linear_Expression".

      OUTPUT:

      A dictionary with the following keyword:value pair:

      * "'bounded'": Boolean. Whether the linear expression "expr"
        is bounded from above on "self".

      If "expr" is bounded from above, the following additional
      keyword:value pairs are set to provide information about the
      supremum:

      * "'sup_n'": Integer. The numerator of the supremum value.

      * "'sup_d'": Non-zero integer. The denominator of the supremum
        value.

      * "'maximum'": Boolean. "True" if and only if the supremum is
        also the maximum value.

      * "'generator'": a "Generator". A point or closure point where
        expr reaches its supremum value.

      Examples:

      >>> from ppl import Variable, C_Polyhedron, NNC_Polyhedron, Constraint_System, Linear_Expression
      >>> x = Variable(0);  y = Variable(1)
      >>> cs = Constraint_System()
      >>> cs.insert(x >= 0)
      >>> cs.insert(y >= 0)
      >>> cs.insert(3*x+5*y <= 10)
      >>> p = C_Polyhedron(cs)
      >>> pm = p.maximize(x+y)
      >>> for key in sorted(pm):
      ...     print key, pm[key]
      bounded True
      generator point(10/3, 0/3)
      maximum True
      sup_d 3
      sup_n 10

      Unbounded case:

         >>> cs = Constraint_System()
         >>> cs.insert(x > 0)
         >>> p = NNC_Polyhedron(cs)
         >>> p.maximize(+x)
         {'bounded': False}
         >>> pm = p.maximize(-x)
         >>> for key in pm:
         ...     print key, pm[key]
         bounded True
         generator closure_point(0/1)
         maximum False
         sup_d 1
         sup_n 0

   minimize()

      Minimize "expr".

      INPUT:

      * "expr" -- a "Linear_Expression".

      OUTPUT:

      A dictionary with the following keyword:value pair:

      * "'bounded'": Boolean. Whether the linear expression "expr"
        is bounded from below on "self".

      If "expr" is bounded from below, the following additional
      keyword:value pairs are set to provide information about the
      infimum:

      * "'inf_n'": Integer. The numerator of the infimum value.

      * "'inf_d'": Non-zero integer. The denominator of the infimum
        value.

      * "'minimum'": Boolean. "True" if and only if the infimum is
        also the minimum value.

      * "'generator'": a "Generator". A point or closure point where
        expr reaches its infimum value.

      Examples:

      >>> from ppl import Variable, C_Polyhedron, NNC_Polyhedron, Constraint_System, Linear_Expression
      >>> x = Variable(0);  y = Variable(1)
      >>> cs = Constraint_System()
      >>> cs.insert( x>=0 )
      >>> cs.insert( y>=0 )
      >>> cs.insert( 3*x+5*y<=10 )
      >>> p = C_Polyhedron(cs)
      >>> pm = p.minimize( x+y )
      >>> for key in sorted(pm):
      ...     print key, pm[key]
      bounded True
      generator point(0/1, 0/1)
      inf_d 1
      inf_n 0
      minimum True

      Unbounded case:

      >>> cs = Constraint_System()
      >>> cs.insert(x > 0)
      >>> p = NNC_Polyhedron(cs)
      >>> pm = p.minimize(+x)
      >>> for key in sorted(pm):
      ...    print key, pm[key]
      bounded True
      generator closure_point(0/1)
      inf_d 1
      inf_n 0
      minimum False
      >>> p.minimize( -x )
      {'bounded': False}

   minimized_constraints()

      Returns the minimized system of constraints.

      See also "constraints()".

      OUTPUT:

      A "Constraint_System".

      Examples:

      >>> from ppl import Variable, C_Polyhedron
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> p = C_Polyhedron(y >= 0)
      >>> p.add_constraint(x >= 0)
      >>> p.add_constraint(x+y >= 0)
      >>> p.constraints()
      Constraint_System {x1>=0, x0>=0, x0+x1>=0}
      >>> p.minimized_constraints()
      Constraint_System {x1>=0, x0>=0}

   minimized_generators()

      Returns the minimized system of generators.

      See also "generators()".

      OUTPUT:

      A "Generator_System".

      Examples:

      >>> from ppl import Variable, C_Polyhedron, point
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> p = C_Polyhedron(3,'empty')
      >>> p.add_generator(point(-x-y))
      >>> p.add_generator(point(0))
      >>> p.add_generator(point(+x+y))
      >>> p.generators()
      Generator_System {point(-1/1, -1/1, 0/1), point(0/1, 0/1, 0/1), point(1/1, 1/1, 0/1)}
      >>> p.minimized_generators()
      Generator_System {point(-1/1, -1/1, 0/1), point(1/1, 1/1, 0/1)}

   poly_difference_assign()

      Assign to "self" the poly-difference of "self" and "y".

      For any pair of NNC polyhedra *P_1* and *P_2* the convex
      polyhedral difference (or poly-difference) of *P_1* and *P_2* is
      defined as the smallest convex polyhedron containing the set-
      theoretic difference *P_1setminus P_2* of *P_1* and *P_2*.

      In general, even if *P_1* and *P_2* are topologically closed
      polyhedra, their poly-difference may be a convex polyhedron that
      is not topologically closed. For this reason, when computing the
      poly-difference of two "C_Polyhedron", the library will enforce
      the topological closure of the result.

      INPUT:

      * "y" -- a "Polyhedron"

      OUTPUT:

      This method assigns the poly-difference to "self" and does not
      return anything.

      Raises a "ValueError" if "self" and and "y" are topology-
      incompatible or dimension-incompatible.

      Examples:

      >>> from ppl import Variable, C_Polyhedron, point, closure_point, NNC_Polyhedron
      >>> x = Variable(0)
      >>> p = NNC_Polyhedron( point(0*x) )
      >>> p.add_generator( point(1*x) )
      >>> p.poly_difference_assign(NNC_Polyhedron( point(0*x) ))
      >>> p.minimized_constraints()
      Constraint_System {-x0+1>=0, x0>0}

      The poly-difference of "C_polyhedron" is really its closure:

      >>> p = C_Polyhedron( point(0*x) )
      >>> p.add_generator( point(1*x) )
      >>> p.poly_difference_assign(C_Polyhedron( point(0*x) ))
      >>> p.minimized_constraints()
      Constraint_System {x0>=0, -x0+1>=0}

      "self" and "y" must be dimension- and topology-compatible, or an
      exception is raised:

      >>> y = Variable(1)
      >>> p.poly_difference_assign( C_Polyhedron(y>=0) )
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::poly_difference_assign(y):
      this->space_dimension() == 1, y.space_dimension() == 2.
      >>> p.poly_difference_assign( NNC_Polyhedron(x+y<1) )
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::poly_difference_assign(y):
      y is a NNC_Polyhedron.

   poly_hull_assign()

      Assign to "self" the poly-hull of "self" and "y".

      For any pair of NNC polyhedra *P_1* and *P_2*, the convex
      polyhedral hull (or poly-hull) of is the smallest NNC polyhedron
      that includes both *P_1* and *P_2*. The poly-hull of any pair of
      closed polyhedra in is also closed.

      INPUT:

      * "y" -- a "Polyhedron"

      OUTPUT:

      This method assigns the poly-hull to "self" and does not return
      anything.

      Raises a "ValueError" if "self" and and "y" are topology-
      incompatible or dimension-incompatible.

      Examples:

      >>> from ppl import Variable, C_Polyhedron, point, NNC_Polyhedron
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> p = C_Polyhedron( point(1*x+0*y) )
      >>> p.poly_hull_assign(C_Polyhedron( point(0*x+1*y) ))
      >>> p.generators()
      Generator_System {point(0/1, 1/1), point(1/1, 0/1)}

      "self" and "y" must be dimension- and topology-compatible, or an
      exception is raised:

      >>> z = Variable(2)
      >>> p.poly_hull_assign( C_Polyhedron(z>=0) )
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::poly_hull_assign(y):
      this->space_dimension() == 2, y.space_dimension() == 3.
      >>> p.poly_hull_assign( NNC_Polyhedron(x+y<1) )
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::poly_hull_assign(y):
      y is a NNC_Polyhedron.

   relation_with()

      Return the relations holding between the polyhedron "self" and
      the generator or constraint "arg".

      INPUT:

      * "arg" -- a "Generator" or a "Constraint".

      OUTPUT:

      A "Poly_Gen_Relation" or a "Poly_Con_Relation" according to the
      type of the input.

      Raises "ValueError" if "self" and the generator/constraint "arg"
      are dimension-incompatible.

      Examples:

      >>> from ppl import Variable, C_Polyhedron, point, ray, Poly_Con_Relation
      >>> x = Variable(0);  y = Variable(1)
      >>> p = C_Polyhedron(2, 'empty')
      >>> p.add_generator( point(1*x+0*y) )
      >>> p.add_generator( point(0*x+1*y) )
      >>> p.minimized_constraints()
      Constraint_System {x0+x1-1==0, -x1+1>=0, x1>=0}
      >>> p.relation_with( point(1*x+1*y) )
      nothing
      >>> p.relation_with( point(1*x+1*y, 2) )
      subsumes
      >>> p.relation_with( x+y==-1 )
      is_disjoint
      >>> p.relation_with( x==y )
      strictly_intersects
      >>> p.relation_with( x+y<=1 )
      is_included, saturates
      >>> p.relation_with( x+y<1 )
      is_disjoint, saturates

      In a Sage program you will usually use "relation_with()"
      together with "implies()" or "implies()", for example:

         >>> p.relation_with( x+y<1 ).implies(Poly_Con_Relation.saturates())
         True

      You can only get relations with dimension-compatible generators
      or constraints:

         >>> z = Variable(2)
         >>> p.relation_with( point(x+y+z) )
         Traceback (most recent call last):
         ...
         ValueError: PPL::C_Polyhedron::relation_with(g):
         this->space_dimension() == 2, g.space_dimension() == 3.
         >>> p.relation_with( z>0 )
         Traceback (most recent call last):
         ...
         ValueError: PPL::C_Polyhedron::relation_with(c):
         this->space_dimension() == 2, c.space_dimension() == 3.

   remove_higher_space_dimensions()

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

      OUTPUT:

      This method modifies "self" and does not return anything.

      Raises a "ValueError" if "new_dimensions" is greater than the
      space dimension of "self".

      Examples:

      >>> from ppl import C_Polyhedron, Variable
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> p = C_Polyhedron(3*x+0*y==2)
      >>> p.remove_higher_space_dimensions(1)
      >>> p.minimized_constraints()
      Constraint_System {3*x0-2==0}
      >>> p.remove_higher_space_dimensions(2)
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::remove_higher_space_dimensions(nd):
      this->space_dimension() == 1, required space dimension == 2.

   space_dimension()

      Return the dimension of the vector space enclosing "self".

      OUTPUT:

      Integer.

      Examples:

      >>> from ppl import Variable, C_Polyhedron
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> p = C_Polyhedron( 5*x-2*y >=  x+y-1 )
      >>> p.space_dimension()
      2

   strictly_contains()

      Test whether "self" strictly contains "y".

      INPUT:

      * "y" -- a "Polyhedron".

      OUTPUT:

      Boolean. Returns "True" if and only if "self" contains "y" and
      "self" does not equal "y".

      Raises a "ValueError" if "self" and "y" are topology-
      incompatible or dimension-incompatible.

      Examples:

      >>> from ppl import Variable, C_Polyhedron, NNC_Polyhedron
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> p0 = C_Polyhedron( x>=0 )
      >>> p1 = C_Polyhedron( x>=1 )
      >>> p0.strictly_contains(p1)
      True
      >>> p1.strictly_contains(p0)
      False

      Errors are raised if the dimension or topology is not
      compatible:

      >>> p0.strictly_contains(C_Polyhedron(y>=0))
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::contains(y):
      this->space_dimension() == 1, y.space_dimension() == 2.
      >>> p0.strictly_contains(NNC_Polyhedron(x>0))
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::contains(y):
      y is a NNC_Polyhedron.

   topological_closure_assign()

      Assign to "self" its topological closure.

      Examples:

      >>> from ppl import Variable, NNC_Polyhedron
      >>> x = Variable(0)
      >>> p = NNC_Polyhedron(x>0)
      >>> p.is_topologically_closed()
      False
      >>> p.topological_closure_assign()
      >>> p.is_topologically_closed()
      True
      >>> p.minimized_constraints()
      Constraint_System {x0>=0}

   unconstrain()

      Compute the cylindrification of "self" with respect to space
      dimension "var".

      INPUT:

      * "var" -- a "Variable". The space dimension that will be
        unconstrained.  Exceptions:

      OUTPUT:

      This method assigns the cylindrification to "self" and does not
      return anything.

      Raises a "ValueError" if "var" is not a space dimension of
      "self".

      Examples:

      >>> from ppl import Variable, C_Polyhedron, point
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> p = C_Polyhedron( point(x+y) ); p
      A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point
      >>> p.unconstrain(x); p
      A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point, 1 line
      >>> z = Variable(2)
      >>> p.unconstrain(z)
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::unconstrain(var):
      this->space_dimension() == 2, required space dimension == 3.

   upper_bound_assign()

      Assign to "self" the poly-hull of "self" and "y".

      For any pair of NNC polyhedra *P_1* and *P_2*, the convex
      polyhedral hull (or poly-hull) of is the smallest NNC polyhedron
      that includes both *P_1* and *P_2*. The poly-hull of any pair of
      closed polyhedra in is also closed.

      INPUT:

      * "y" -- a "Polyhedron"

      OUTPUT:

      This method assigns the poly-hull to "self" and does not return
      anything.

      Raises a "ValueError" if "self" and and "y" are topology-
      incompatible or dimension-incompatible.

      Examples:

      >>> from ppl import Variable, C_Polyhedron, point, NNC_Polyhedron
      >>> x = Variable(0)
      >>> y = Variable(1)
      >>> p = C_Polyhedron( point(1*x+0*y) )
      >>> p.poly_hull_assign(C_Polyhedron( point(0*x+1*y) ))
      >>> p.generators()
      Generator_System {point(0/1, 1/1), point(1/1, 0/1)}

      "self" and "y" must be dimension- and topology-compatible, or an
      exception is raised:

      >>> z = Variable(2)
      >>> p.poly_hull_assign( C_Polyhedron(z>=0) )
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::poly_hull_assign(y):
      this->space_dimension() == 2, y.space_dimension() == 3.
      >>> p.poly_hull_assign( NNC_Polyhedron(x+y<1) )
      Traceback (most recent call last):
      ...
      ValueError: PPL::C_Polyhedron::poly_hull_assign(y):
      y is a NNC_Polyhedron.

class class ppl.Variable

   Bases: "object"

   Wrapper for PPL's "Variable" class.

   A dimension of the vector space.

   An object of the class Variable represents a dimension of the
   space, that is one of the Cartesian axes. Variables are used as
   basic blocks in order to build more complex linear expressions.
   Each variable is identified by a non-negative integer, representing
   the index of the corresponding Cartesian axis (the first axis has
   index 0). The space dimension of a variable is the dimension of the
   vector space made by all the Cartesian axes having an index less
   than or equal to that of the considered variable; thus, if a
   variable has index *i*, its space dimension is *i+1*.

   INPUT:

   * "i" -- integer. The index of the axis.

   OUTPUT:

   A "Variable"

   Examples:

   >>> from ppl import Variable
   >>> x = Variable(123)
   >>> x.id()
   123
   >>> x
   x123

   Note that the "meaning" of an object of the class Variable is
   completely specified by the integer index provided to its
   constructor: be careful not to be mislead by C++ language variable
   names. For instance, in the following example the linear
   expressions "e1" and "e2" are equivalent, since the two variables
   "x" and "z" denote the same Cartesian axis:

   >>> x = Variable(0)
   >>> y = Variable(1)
   >>> z = Variable(0)
   >>> e1 = x + y; e1
   x0+x1
   >>> e2 = y + z; e2
   x0+x1
   >>> e1 - e2
   0

   OK()

      Checks if all the invariants are satisfied.

      OUTPUT:

      Boolean.

      Examples:

      >>> from ppl import Variable
      >>> x = Variable(0)
      >>> x.OK()
      True

   id()

      Return the index of the Cartesian axis associated to the
      variable.

      Examples:

      >>> from ppl import Variable
      >>> x = Variable(123)
      >>> x.id()
      123

   space_dimension()

      Return the dimension of the vector space enclosing "self".

      OUPUT:

      Integer. The returned value is "self.id()+1".

      Examples:

      >>> from ppl import Variable
      >>> x = Variable(0)
      >>> x.space_dimension()
      1

ppl.closure_point()

   Construct a closure point.

   A closure point is a point of the topological closure of a
   polyhedron that is not a point of the polyhedron itself.

   INPUT:

   * "expression" -- a "Linear_Expression" or something convertible
     to it ("Variable" or integer).

   * "divisor" -- an integer.

   OUTPUT:

   A new "Generator" representing the point.

   Raises a "ValueError` if ``divisor==0".

   Examples:

   >>> from ppl import Generator, Variable
   >>> y = Variable(1)
   >>> Generator.closure_point(2*y+7, 3)
   closure_point(0/3, 2/3)
   >>> Generator.closure_point(y+7, 3)
   closure_point(0/3, 1/3)
   >>> Generator.closure_point(7, 3)
   closure_point()
   >>> Generator.closure_point(0, 0)
   Traceback (most recent call last):
   ...
   ValueError: PPL::closure_point(e, d):
   d == 0.

ppl.equation()

   Constuct an equation.

   INPUT:

   * "expression" -- a "Linear_Expression".

   OUTPUT:

   The equation "expression" == 0.

   Examples:

   >>> from ppl import Variable, equation
   >>> y = Variable(1)
   >>> 2*y+1 == 0
   2*x1+1==0
   >>> equation(2*y+1)
   2*x1+1==0

ppl.inequality()

   Constuct an inequality.

   INPUT:

   * "expression" -- a "Linear_Expression".

   OUTPUT:

   The inequality "expression" >= 0.

   Examples:

   >>> from ppl import Variable, inequality
   >>> y = Variable(1)
   >>> 2*y+1 >= 0
   2*x1+1>=0
   >>> inequality(2*y+1)
   2*x1+1>=0

ppl.line()

   Construct a line.

   INPUT:

   * "expression" -- a "Linear_Expression" or something convertible
     to it ("Variable" or integer).

   OUTPUT:

   A new "Generator" representing the line.

   Raises a "ValueError` if the homogeneous part of ``expression"
   represents the origin of the vector space.

   Examples:

   >>> from ppl import Generator, Variable
   >>> y = Variable(1)
   >>> Generator.line(2*y)
   line(0, 1)
   >>> Generator.line(y)
   line(0, 1)
   >>> Generator.line(1)
   Traceback (most recent call last):
   ...
   ValueError: PPL::line(e):
   e == 0, but the origin cannot be a line.

ppl.point()

   Construct a point.

   INPUT:

   * "expression" -- a "Linear_Expression" or something convertible
     to it ("Variable" or integer).

   * "divisor" -- an integer.

   OUTPUT:

   A new "Generator" representing the point.

   Raises a "ValueError` if ``divisor==0".

   Examples:

   >>> from ppl import Generator, Variable
   >>> y = Variable(1)
   >>> Generator.point(2*y+7, 3)
   point(0/3, 2/3)
   >>> Generator.point(y+7, 3)
   point(0/3, 1/3)
   >>> Generator.point(7, 3)
   point()
   >>> Generator.point(0, 0)
   Traceback (most recent call last):
   ...
   ValueError: PPL::point(e, d):
   d == 0.

ppl.ray()

   Construct a ray.

   INPUT:

   * "expression" -- a "Linear_Expression" or something convertible
     to it ("Variable" or integer).

   OUTPUT:

   A new "Generator" representing the ray.

   Raises a "ValueError` if the homogeneous part of ``expression"
   represents the origin of the vector space.

   Examples:

   >>> from ppl import Generator, Variable
   >>> y = Variable(1)
   >>> Generator.ray(2*y)
   ray(0, 1)
   >>> Generator.ray(y)
   ray(0, 1)
   >>> Generator.ray(1)
   Traceback (most recent call last):
   ...
   ValueError: PPL::ray(e):
   e == 0, but the origin cannot be a ray.

ppl.strict_inequality()

   Constuct a strict inequality.

   INPUT:

   * "expression" -- a "Linear_Expression".

   OUTPUT:

   The inequality "expression" > 0.

   Examples:

   >>> from ppl import Variable, strict_inequality
   >>> y = Variable(1)
   >>> 2*y+1 > 0
   2*x1+1>0
   >>> strict_inequality(2*y+1)
   2*x1+1>0


Indices and tables
******************

* *Index*

* *Module Index*

* *Search Page*
