Ticket #10039: trac_10039_parma_polyhedra_library.patch

File trac_10039_parma_polyhedra_library.patch, 186.4 KB (added by vbraun, 9 years ago)

Updated patch

  • doc/en/reference/libs.rst

    # HG changeset patch
    # User Volker Braun <vbraun@stp.dias.ie>
    # Date 1289832157 18000
    # Node ID 0d39515604d22713367e60588001de14df381fb1
    # Parent  138a6dc8b57213feb88f1dbfbb0d67b7f60f3d2e
    Trac #10039: Cython wrapper around the Parma Polyhedra Library
    
    diff -r 138a6dc8b572 -r 0d39515604d2 doc/en/reference/libs.rst
    a b  
    3232   sage/libs/mwrank/interface
    3333   sage/libs/singular/function
    3434   sage/libs/singular/option
     35   sage/libs/ppl
  • module_list.py

    diff -r 138a6dc8b572 -r 0d39515604d2 module_list.py
    a b  
    578578              sources = ["sage/libs/pari/gen.pyx"],
    579579              libraries = ['pari', 'gmp']),
    580580   
     581    Extension('sage.libs.ppl',
     582              sources = ['sage/libs/ppl.pyx', 'sage/libs/ppl_shim.cc'],
     583              libraries = ['ppl', 'gmpxx', 'gmp', 'm'],
     584              language="c++",
     585              depends = [SAGE_LOCAL + "/include/ppl.hh"]),
     586
    581587    Extension('sage.libs.ratpoints',
    582588              sources = ["sage/libs/ratpoints.pyx"],
    583589              depends = [SAGE_ROOT + '/local/include/ratpoints.h'],
  • new file sage/libs/ppl.pyx

    diff -r 138a6dc8b572 -r 0d39515604d2 sage/libs/ppl.pyx
    - +  
     1r"""
     2Cython wrapper for the Parma Polyhedra Library (PPL)
     3
     4The Parma Polyhedra Library (PPL) is a library for polyhedral
     5computations over `\QQ`. This interface tries to reproduce the C++ API
     6as faithfully as possible in Cython/Sage. For example, the following
     7C++ excerpt:
     8
     9.. code-block:: c++
     10
     11    Variable x(0);
     12    Variable y(1);
     13    Constraint_System cs;
     14    cs.insert(x >= 0);
     15    cs.insert(x <= 3);
     16    cs.insert(y >= 0);
     17    cs.insert(y <= 3);
     18    C_Polyhedron poly_from_constraints(cs);
     19
     20translates into::
     21
     22    sage: from sage.libs.ppl import Variable, Constraint_System, C_Polyhedron
     23    sage: x = Variable(0)
     24    sage: y = Variable(1)
     25    sage: cs = Constraint_System()
     26    sage: cs.insert(x >= 0)
     27    sage: cs.insert(x <= 3)
     28    sage: cs.insert(y >= 0)
     29    sage: cs.insert(y <= 3)
     30    sage: poly_from_constraints = C_Polyhedron(cs)
     31
     32The same polyhedron constructed from generators::
     33
     34    sage: from sage.libs.ppl import Variable, Generator_System, C_Polyhedron, point
     35    sage: gs = Generator_System()
     36    sage: gs.insert(point(0*x + 0*y))
     37    sage: gs.insert(point(0*x + 3*y))
     38    sage: gs.insert(point(3*x + 0*y))
     39    sage: gs.insert(point(3*x + 3*y))
     40    sage: poly_from_generators = C_Polyhedron(gs)
     41
     42Rich comparisons test equality/inequality and strict/non-strict
     43containment::
     44
     45    sage: poly_from_generators == poly_from_constraints
     46    True
     47    sage: poly_from_generators >= poly_from_constraints
     48    True
     49    sage: poly_from_generators <  poly_from_constraints
     50    False
     51    sage: poly_from_constraints.minimized_generators()
     52    Generator_System {point(0/1, 0/1), point(0/1, 3/1), point(3/1, 0/1), point(3/1, 3/1)}
     53    sage: poly_from_constraints.minimized_constraints()
     54    Constraint_System {-x0+3>=0, -x1+3>=0, x0>=0, x1>=0}
     55
     56As we see above, the library is generally easy to use. There are a few
     57pitfalls that are not entirely obvious without consulting the
     58documentation, in particular:
     59
     60* There are no vectors used to describe :class:`Generator` (points,
     61  closure points, rays, lines) or :class:`Constraint` (strict
     62  inequalities, non-strict inequalities, or equations). Coordinates
     63  are always specified via linear polynomials in :class:`Variable`
     64
     65* All coordinates of rays and lines as well as all coefficients of
     66  constraint relations are (arbitrary precision) integers. Only the
     67  generators :func:`point` and :func:`closure_point` allow one to
     68  specify an overall divisor of the otherwise integral
     69  coordinates. For example::
     70
     71      sage: from sage.libs.ppl import Variable, point
     72      sage: x = Variable(0); y = Variable(1)
     73      sage: p = point( 2*x+3*y, 5 ); p
     74      point(2/5, 3/5)
     75      sage: p.coefficient(x)
     76      2
     77      sage: p.coefficient(y)
     78      3
     79      sage: p.divisor()
     80      5
     81
     82* PPL supports (topologically) closed polyhedra
     83  (:class:`C_Polyhedron`) as well as not neccesarily closed polyhedra
     84  (:class:`NNC_Polyhedron`). Only the latter allows closure points
     85  (=points of the closure but not of the actual polyhedron) and strict
     86  inequalities (``>`` and ``<``)
     87
     88The naming convention for the C++ classes is that they start with
     89``PPL_``, for example, the original ``Linear_Expression`` becomes
     90``PPL_Linear_Expression``. The Python wrapper has the same name as the
     91original library class, that is, just ``Linear_Expression``. In short:
     92
     93* If you are using the Python wrapper (if in doubt: thats you), then
     94  you use the same names as the PPL C++ class library.
     95
     96* If you are writing your own Cython code, you can access the
     97  underlying C++ classes by adding the prefix ``PPL_``.
     98
     99Finally, PPL is fast. For example, here is the permutahedron of 6
     100basis vectors::
     101
     102    sage: from sage.libs.ppl import Variable, Generator_System, point, C_Polyhedron
     103    sage: basis = range(0,6)
     104    sage: x = [ Variable(i) for i in basis ]
     105    sage: gs = Generator_System();
     106    sage: for coeff in permutations(basis):
     107    ...      gs.insert(point( sum( (coeff[i]+1)*x[i] for i in basis ) ))
     108    ...
     109    sage: C_Polyhedron(gs)
     110    A 5-dimensional polyhedron in QQ^6 defined as the convex hull of 720 points.
     111
     112The computation finishes without noticeable delay on my desktop
     113(timeit measures it to be 35msec). Cddlib needs about 3 minutes on the
     114same hardware::
     115
     116    sage: basis = range(0,6)
     117    sage: x = [ Variable(i) for i in basis ]
     118    sage: gs = [ tuple(coeff) for coeff in permutations(basis) ]
     119    sage: Polyhedron(vertices=gs)   # long time
     120    A 5-dimensional polyhedron in QQ^6 defined as the convex hull of 720 vertices.
     121
     122DIFFERENCES VS. C++
     123
     124Since Python and C++ syntax are not always compatible, there are
     125necessarily some differences. The main ones are:
     126
     127* The :class:`Linear_Expression` also accepts an iterable as input for
     128  the homogeneous cooefficients.
     129
     130* :class:`Polyhedron` and its subclasses as well as
     131  :class:`Generator_System` and :class:`Constraint_System` can be set
     132  immutable via a ``set_immutable()` method. This is the analog of
     133  declaring a C++ instance ``const``. All other classes are immutable
     134  by themselves.
     135
     136AUTHORS:
     137
     138- Volker Braun (2010-10-08): initial version.
     139"""
     140
     141#*****************************************************************************
     142#       Copyright (C) 2010 Volker Braun  <vbraun.name@gmail.com>
     143#
     144#  Distributed under the terms of the GNU General Public License (GPL)
     145#
     146#                  http://www.gnu.org/licenses/
     147#*****************************************************************************
     148
     149from sage.libs.gmp.mpz cimport mpz_t, mpz_set
     150from sage.rings.integer cimport Integer
     151
     152include '../ext/interrupt.pxi'
     153include "../ext/stdsage.pxi"
     154include "../ext/cdefs.pxi"
     155
     156from libcpp cimport bool as cppbool
     157
     158####################################################
     159# Potentially expensive operations:
     160#  - compute dual description
     161#  - solve linear program
     162# These can only be triggered by methods in the Polyhedron class
     163# they need to be wrapped in sig_on() / sig_off()
     164
     165####################################################
     166cdef extern from "gmpxx.h":
     167    cdef cppclass mpz_class:
     168        mpz_class()
     169        mpz_class(int i)
     170        mpz_class(mpz_t z)
     171        mpz_class(mpz_class)
     172        mpz_t* get_mpz_t()
     173
     174
     175####################################################
     176# PPL can use floating-point arithmetic to compute integers
     177cdef extern from "ppl.hh" namespace "Parma_Polyhedra_Library":
     178    cdef void set_rounding_for_PPL()
     179    cdef void restore_pre_PPL_rounding()
     180
     181# but with PPL's rounding the gsl will be very unhappy; must turn off!
     182restore_pre_PPL_rounding()
     183
     184
     185####################################################
     186# Cython does not support ctypedef within cppclass; Hack around this restriction:
     187cdef extern from "ppl.hh" namespace "Parma_Polyhedra_Library::Generator":
     188    ctypedef enum PPL_GeneratorType:
     189        LINE, RAY, POINT, CLOSURE_POINT
     190
     191cdef extern from "ppl.hh" namespace "Parma_Polyhedra_Library::Constraint":
     192    ctypedef enum PPL_ConstraintType:
     193        EQUALITY, NONSTRICT_INEQUALITY, STRICT_INEQUALITY
     194
     195
     196####################################################
     197cdef extern from "ppl.hh" namespace "Parma_Polyhedra_Library":
     198
     199    ctypedef size_t PPL_dimension_type  "Parma_Polyhedra_Library::dimension_type"
     200    ctypedef mpz_class PPL_Coefficient  "Parma_Polyhedra_Library::Coefficient"
     201    cdef cppclass PPL_Variable          "Parma_Polyhedra_Library::Variable"
     202    cdef cppclass PPL_Linear_Expression "Parma_Polyhedra_Library::Linear_Expression"
     203    cdef cppclass PPL_Generator         "Parma_Polyhedra_Library::Generator"
     204    cdef cppclass PPL_Generator_System  "Parma_Polyhedra_Library::Generator_System"
     205    cdef cppclass PPL_Constraint        "Parma_Polyhedra_Library::Constraint"
     206    cdef cppclass PPL_Constraint_System "Parma_Polyhedra_Library::Constraint_System"
     207    cdef cppclass PPL_Polyhedron        "Parma_Polyhedra_Library::Polyhedron"
     208    cdef cppclass PPL_C_Polyhedron      "Parma_Polyhedra_Library::C_Polyhedron"   (PPL_Polyhedron)
     209    cdef cppclass PPL_NNC_Polyhedron    "Parma_Polyhedra_Library::NNC_Polyhedron" (PPL_Polyhedron)
     210    cdef cppclass PPL_Poly_Gen_Relation "Parma_Polyhedra_Library::Poly_Gen_Relation"
     211    cdef cppclass PPL_Poly_Con_Relation "Parma_Polyhedra_Library::Poly_Con_Relation"
     212
     213    cdef cppclass PPL_Variable:
     214        PPL_Variable(PPL_dimension_type i)
     215        PPL_dimension_type id()
     216        bint OK()
     217        PPL_dimension_type space_dimension()
     218
     219    cdef cppclass PPL_Linear_Expression:
     220        PPL_Linear_Expression()
     221        PPL_Linear_Expression(PPL_Linear_Expression &e)
     222        PPL_Linear_Expression(PPL_Coefficient n)
     223        PPL_Linear_Expression(PPL_Variable v)
     224        PPL_dimension_type space_dimension()
     225        PPL_Coefficient coefficient(PPL_Variable v)
     226        PPL_Coefficient inhomogeneous_term()
     227        bint is_zero()
     228        bint all_homogeneous_terms_are_zero()
     229        void ascii_dump()
     230        bint OK()
     231        PPL_Linear_Expression operator+(PPL_Linear_Expression& e)
     232        PPL_Linear_Expression operator-(PPL_Linear_Expression& e)
     233        PPL_Linear_Expression operator*(PPL_Coefficient n)
     234        PPL_Constraint operator> (PPL_Linear_Expression& e)
     235        PPL_Constraint operator>=(PPL_Linear_Expression& e)
     236        PPL_Constraint operator==(PPL_Linear_Expression& e)
     237        PPL_Constraint operator<=(PPL_Linear_Expression& e)
     238        PPL_Constraint operator< (PPL_Linear_Expression& e)
     239
     240    cdef cppclass PPL_Generator:
     241        PPL_Generator(PPL_Generator &g)
     242        # Cython does not support static members
     243        #PPL_Generator line(PPL_Linear_Expression &e)
     244        #PPL_Generator ray(PPL_Linear_Expression &e)
     245        #PPL_Generator point(PPL_Linear_Expression &e, PPL_Coefficient d)
     246        #PPL_Generator closure_point(PPL_Linear_Expression &e)
     247        PPL_dimension_type space_dimension()
     248        PPL_GeneratorType type()
     249        bint is_line()
     250        bint is_ray()
     251        bint is_line_or_ray()
     252        bint is_point()
     253        bint is_closure_point()
     254        PPL_Coefficient coefficient(PPL_Variable v)
     255        PPL_Coefficient divisor() except +
     256        bint is_equivalent_to(PPL_Generator &y)
     257        void ascii_dump()
     258        bint OK()
     259
     260    cdef cppclass PPL_Constraint:
     261        PPL_Constraint(PPL_Constraint &g)
     262        PPL_dimension_type space_dimension()
     263        PPL_ConstraintType type()
     264        bint is_equality()
     265        bint is_inequality()
     266        bint is_nonstrict_inequality()
     267        bint is_strict_inequality()
     268        PPL_Coefficient coefficient(PPL_Variable v)
     269        PPL_Coefficient inhomogeneous_term()
     270        bint is_tautological()
     271        bint is_inconsistent()       
     272        bint is_equivalent_to(PPL_Constraint &y)
     273        void ascii_dump()
     274        bint OK()
     275
     276    cdef cppclass PPL_Generator_System:
     277        # This seems to not work in cython
     278        #cppclass PPL_const_iterator "const_iterator":
     279        #    PPL_Generator operator*()
     280        #    PPL_const_iterator operator++()
     281        #    bint operator==(PPL_const_iterator&)
     282        #    bint operator!=(PPL_const_iterator&)
     283        #PPL_const_iterator begin()
     284        #PPL_const_iterator end()
     285        PPL_Generator_System()
     286        PPL_Generator_System(PPL_Generator &g)
     287        PPL_Generator_System(PPL_Generator_System &gs)
     288        PPL_dimension_type space_dimension()
     289        void clear()
     290        void insert(PPL_Generator &g)
     291        bint empty()
     292        void ascii_dump()
     293        bint OK()
     294       
     295    cdef cppclass PPL_Constraint_System:
     296        # This seems to not work in cython
     297        #cppclass PPL_const_iterator "const_iterator":
     298        #    PPL_Constraint operator*()
     299        #    PPL_const_iterator operator++()
     300        #    bint operator==(PPL_const_iterator&)
     301        #    bint operator!=(PPL_const_iterator&)
     302        #PPL_const_iterator begin()
     303        #PPL_const_iterator end()
     304        PPL_Constraint_System()
     305        PPL_Constraint_System(PPL_Constraint &g)
     306        PPL_Constraint_System(PPL_Constraint_System &gs)
     307        PPL_dimension_type space_dimension()
     308        bint has_equalities()
     309        bint has_strict_inequalities()
     310        void clear()
     311        void insert(PPL_Constraint &g)
     312        bint empty()
     313        void ascii_dump()
     314        bint OK()
     315         
     316    cdef enum PPL_Degenerate_Element:
     317        UNIVERSE, EMPTY
     318
     319    cdef cppclass PPL_Polyhedron:
     320        PPL_dimension_type space_dimension()
     321        PPL_dimension_type affine_dimension()
     322        PPL_Constraint_System& constraints()
     323        PPL_Constraint_System& minimized_constraints()
     324        PPL_Generator_System& generators()
     325        PPL_Generator_System& minimized_generators()
     326        PPL_Poly_Con_Relation relation_with(PPL_Constraint &c) except +ValueError
     327        PPL_Poly_Gen_Relation relation_with(PPL_Generator &g) except +ValueError
     328        bint is_empty()
     329        bint is_universe()
     330        bint is_topologically_closed()
     331        bint is_disjoint_from(PPL_Polyhedron &y) except +ValueError
     332        bint is_discrete()
     333        bint is_bounded()
     334        bint contains_integer_point()
     335        bint constrains(PPL_Variable var) except +ValueError
     336        bint bounds_from_above(PPL_Linear_Expression &expr) except +ValueError
     337        bint bounds_from_below(PPL_Linear_Expression &expr) except +ValueError
     338        bint maximize(PPL_Linear_Expression &expr, PPL_Coefficient &sup_n, PPL_Coefficient &sup_d,
     339                      cppbool &maximum)
     340        bint maximize(PPL_Linear_Expression &expr, PPL_Coefficient &sup_n, PPL_Coefficient &sup_d,
     341                      cppbool &maximum, PPL_Generator &g)
     342        bint minimize(PPL_Linear_Expression &expr, PPL_Coefficient &inf_n, PPL_Coefficient &inf_d,
     343                      cppbool &minimum)
     344        bint minimize(PPL_Linear_Expression &expr, PPL_Coefficient &inf_n, PPL_Coefficient &inf_d,
     345                      cppbool &minimum, PPL_Generator &g)
     346        bint frequency(PPL_Linear_Expression &expr, PPL_Coefficient &freq_n, PPL_Coefficient &freq_d,
     347                       PPL_Coefficient &val_n, PPL_Coefficient &val_d)
     348        bint contains(PPL_Polyhedron &y) except +ValueError
     349        bint strictly_contains(PPL_Polyhedron &y) except +ValueError
     350        void add_constraint(PPL_Constraint &c) except +ValueError
     351        void add_generator(PPL_Generator &g) except +ValueError
     352        void add_constraints(PPL_Constraint_System &cs) except +ValueError
     353        void add_generators(PPL_Generator_System &gs) except +ValueError
     354        void refine_with_constraint(PPL_Constraint &c) except +ValueError
     355        void refine_with_constraints(PPL_Constraint_System &cs) except +ValueError
     356        void unconstrain(PPL_Variable var) except +ValueError
     357        void intersection_assign(PPL_Polyhedron &y) except +ValueError
     358        void poly_hull_assign(PPL_Polyhedron &y) except +ValueError
     359        void upper_bound_assign(PPL_Polyhedron &y) except +ValueError
     360        void poly_difference_assign(PPL_Polyhedron &y) except +ValueError
     361        void difference_assign(PPL_Polyhedron &y) except +ValueError
     362        void drop_some_non_integer_points()
     363        void topological_closure_assign()
     364        void add_space_dimensions_and_embed(PPL_dimension_type m) except +ValueError
     365        void add_space_dimensions_and_project(PPL_dimension_type m) except +ValueError
     366        void concatenate_assign(PPL_Polyhedron &y) except +ValueError
     367        void remove_higher_space_dimensions(PPL_dimension_type new_dimension) except +ValueError
     368        void ascii_dump()
     369        int hash_code()
     370        PPL_dimension_type max_space_dimension()
     371        bint OK(cppbool check_not_empty=false)
     372        bint operator!=(PPL_Polyhedron &y)
     373        bint operator==(PPL_Polyhedron &y)
     374
     375    cdef cppclass PPL_C_Polyhedron(PPL_Polyhedron):
     376        PPL_C_Polyhedron(PPL_dimension_type num_dimensions, PPL_Degenerate_Element)
     377        PPL_C_Polyhedron(PPL_Constraint_System &cs) except +ValueError
     378        PPL_C_Polyhedron(PPL_Generator_System &gs) except +ValueError
     379        PPL_C_Polyhedron(PPL_C_Polyhedron &y)
     380
     381    cdef cppclass PPL_NNC_Polyhedron(PPL_Polyhedron):
     382        PPL_NNC_Polyhedron(PPL_dimension_type num_dimensions, PPL_Degenerate_Element kind)
     383        PPL_NNC_Polyhedron(PPL_Constraint_System &cs) except +ValueError
     384        PPL_NNC_Polyhedron(PPL_Generator_System &gs) except +ValueError
     385        PPL_NNC_Polyhedron(PPL_NNC_Polyhedron &y)
     386        PPL_NNC_Polyhedron(PPL_C_Polyhedron &y)
     387
     388    cdef cppclass PPL_Poly_Gen_Relation:
     389        PPL_Poly_Gen_Relation(PPL_Poly_Gen_Relation &cpy_from)
     390        bint implies(PPL_Poly_Gen_Relation &y)
     391        void ascii_dump()
     392        bint OK()
     393
     394    cdef cppclass PPL_Poly_Con_Relation:
     395        PPL_Poly_Con_Relation(PPL_Poly_Con_Relation &cpy_from)
     396        bint implies(PPL_Poly_Con_Relation &y)
     397        void ascii_dump()
     398        bint OK()
     399
     400
     401cdef extern from "ppl.hh":
     402    PPL_Generator PPL_line          "Parma_Polyhedra_Library::line"          (PPL_Linear_Expression &e) except +ValueError
     403    PPL_Generator PPL_ray           "Parma_Polyhedra_Library::ray"           (PPL_Linear_Expression &e) except +ValueError
     404    PPL_Generator PPL_point         "Parma_Polyhedra_Library::point"         (PPL_Linear_Expression &e, PPL_Coefficient &d) except +ValueError
     405    PPL_Generator PPL_closure_point "Parma_Polyhedra_Library::closure_point" (PPL_Linear_Expression &e, PPL_Coefficient &d) except +ValueError
     406
     407
     408####################################################
     409# Cython does not support static methods; hack around
     410cdef extern from "ppl.hh":
     411
     412    PPL_Poly_Gen_Relation PPL_Poly_Gen_Relation_nothing  "Parma_Polyhedra_Library::Poly_Gen_Relation::nothing"  ()
     413    PPL_Poly_Gen_Relation PPL_Poly_Gen_Relation_subsumes "Parma_Polyhedra_Library::Poly_Gen_Relation::subsumes" ()
     414
     415    PPL_Poly_Con_Relation PPL_Poly_Con_Relation_nothing  "Parma_Polyhedra_Library::Poly_Con_Relation::nothing"  ()
     416    PPL_Poly_Con_Relation PPL_Poly_Con_Relation_is_disjoint "Parma_Polyhedra_Library::Poly_Con_Relation::is_disjoint" ()
     417    PPL_Poly_Con_Relation PPL_Poly_Con_Relation_strictly_intersects "Parma_Polyhedra_Library::Poly_Con_Relation::strictly_intersects" ()
     418    PPL_Poly_Con_Relation PPL_Poly_Con_Relation_is_included "Parma_Polyhedra_Library::Poly_Con_Relation::is_included" ()
     419    PPL_Poly_Con_Relation PPL_Poly_Con_Relation_saturates "Parma_Polyhedra_Library::Poly_Con_Relation::saturates" ()
     420
     421
     422
     423####################################################
     424# Workaround for private constructors
     425cdef extern from "ppl_shim.hh":
     426    PPL_Poly_Gen_Relation* new_relation_with(PPL_Polyhedron &p, PPL_Generator &g) except +ValueError
     427    PPL_Poly_Con_Relation* new_relation_with(PPL_Polyhedron &p, PPL_Constraint &c) except +ValueError
     428
     429
     430### Forward declarations ###########################
     431cdef class _mutable_or_immutable(object)
     432cdef class Variable(object)
     433cdef class Linear_Expression(object)
     434cdef class Generator(object)
     435cdef class Generator_System(_mutable_or_immutable)
     436cdef class Generator_System_iterator(object)
     437cdef class Constraint(object)
     438cdef class Constraint_System(_mutable_or_immutable)
     439cdef class Constraint_System_iterator(object)
     440cdef class Polyhedron(_mutable_or_immutable)
     441cdef class C_Polyhedron(Polyhedron)
     442cdef class NNC_Polyhedron(Polyhedron)
     443cdef class Poly_Gen_Relation(object)
     444cdef class Poly_Con_Relation(object)
     445
     446
     447
     448
     449####################################################
     450### _mutable_or_immutable ##########################
     451####################################################
     452cdef class _mutable_or_immutable(object):
     453    r"""
     454    A base class for mutable or immutable objects.
     455
     456    By default, any object is mutable. It can then be
     457    :meth:`set_immutable`.
     458
     459    EXAMPLES::
     460     
     461        sage: from sage.libs.ppl import _mutable_or_immutable as ExampleObj
     462        sage: x = ExampleObj()
     463        sage: x.is_mutable()
     464        True
     465        sage: x.is_immutable()
     466        False
     467        sage: x.set_immutable()
     468        sage: x.is_mutable()
     469        False
     470    """
     471   
     472    cdef bint _is_mutable
     473
     474    def __cinit__(self):
     475        """
     476        The Cython constructor.
     477       
     478        TESTS::
     479
     480            sage: from sage.libs.ppl import _mutable_or_immutable as ExampleObj
     481            sage: x = ExampleObj()    # indirect doctest
     482            sage: x.is_mutable()
     483            True
     484        """
     485        self._is_mutable = True
     486
     487
     488    def set_immutable(self):
     489        """
     490        Make this object immutable.
     491
     492        This operation cannot be undone.
     493
     494        EXAMPLES::
     495       
     496            sage: from sage.libs.ppl import _mutable_or_immutable as ExampleObj
     497            sage: x = ExampleObj()
     498            sage: x.is_mutable()
     499            True
     500            sage: x.set_immutable()
     501            sage: x.is_mutable()
     502            False
     503        """
     504        self._is_mutable = False
     505
     506
     507    def is_mutable(self):
     508        """
     509        Return whether this object is mutable.
     510
     511        The data members of the object can only be modified if the
     512        object is mutable.
     513               
     514        OUTPUT:
     515
     516        Boolean.
     517
     518        EXAMPLES::
     519       
     520            sage: from sage.libs.ppl import _mutable_or_immutable as ExampleObj
     521            sage: x = ExampleObj()
     522            sage: x.is_mutable()
     523            True
     524        """
     525        return self._is_mutable
     526
     527
     528    def is_immutable(self):
     529        """
     530        Return whether this object is immutable.
     531       
     532        OUTPUT:
     533
     534        Boolean.
     535
     536        EXAMPLES::
     537       
     538            sage: from sage.libs.ppl import _mutable_or_immutable as ExampleObj
     539            sage: x = ExampleObj()
     540            sage: x.is_immutable()
     541            False
     542        """
     543        return not self._is_mutable
     544
     545
     546    def assert_mutable(self, msg):
     547        r"""
     548        Raise ``ValueError`` if the object is not mutable.
     549
     550        INPUT:
     551
     552        - ``msg`` -- a string. The message to be returned together
     553          with the ``ValueError``
     554
     555        OUTPUT:
     556
     557        This method returns no output. A ``ValueError``` is raised if
     558        the object is not mutable.
     559       
     560        EXAMPLES::
     561       
     562            sage: from sage.libs.ppl import _mutable_or_immutable as ExampleObj
     563            sage: x = ExampleObj()
     564            sage: x.assert_mutable("this will not trigger")
     565            sage: x.set_immutable()
     566            sage: x.assert_mutable("this will trigger")
     567            Traceback (most recent call last):
     568            ...
     569            ValueError: this will trigger
     570        """
     571        if not self._is_mutable:
     572            raise ValueError(msg)
     573
     574
     575####################################################
     576### Polyhedron #####################################
     577####################################################
     578cdef class Polyhedron(_mutable_or_immutable):
     579    r"""
     580    Wrapper for PPL's ``Polyhedron`` class.
     581
     582    An object of the class Polyhedron represents a convex polyhedron
     583    in the vector space.
     584
     585    A polyhedron can be specified as either a finite system of
     586    constraints or a finite system of generators (see Section
     587    Representations of Convex Polyhedra) and it is always possible to
     588    obtain either representation. That is, if we know the system of
     589    constraints, we can obtain from this the system of generators that
     590    define the same polyhedron and vice versa. These systems can
     591    contain redundant members: in this case we say that they are not
     592    in the minimal form.
     593
     594    INPUT/OUTPUT:
     595
     596    This is an abstract base for :class:`C_Polyhedron` and
     597    :class:`NNC_Polyhedron`. You cannot instantiate this class.
     598    """
     599
     600    cdef PPL_Polyhedron *thisptr
     601
     602
     603    def __init__(self):
     604        r"""
     605        The Python constructor.
     606
     607        See also :class:`C_Polyhedron` and
     608        :class:`NNC_Polyhedron`. You must not instantiate
     609        :class:`Polyhedron` objects.
     610
     611        TESTS::
     612
     613            sage: from sage.libs.ppl import Polyhedron
     614            sage: Polyhedron()
     615            Traceback (most recent call last):
     616            ...
     617            NotImplementedError: The Polyhedron class is abstract, you must not instantiate it.
     618        """
     619        raise NotImplementedError, 'The Polyhedron class is abstract, you must not instantiate it.'
     620
     621
     622    def __repr__(self):
     623        """
     624        Return a string representation.
     625
     626        OUTPUT:
     627
     628        String.
     629       
     630        EXAMPLES::
     631
     632            sage: from sage.libs.ppl import Variable, C_Polyhedron
     633            sage: x = Variable(0)
     634            sage: y = Variable(1)
     635            sage: C_Polyhedron( 5*x-2*y >=  x+y-1 ).__repr__()
     636            'A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point, 1 ray, 1 line.'
     637
     638        Special cases::
     639
     640            sage: C_Polyhedron(3, 'empty').__repr__()
     641            'The empty polyhedron in QQ^3.'
     642            sage: C_Polyhedron(3, 'universe').__repr__()
     643            'The space-filling polyhedron in QQ^3.'
     644        """
     645        dim = self.affine_dimension()
     646        ambient_dim = self.space_dimension()
     647        gs = self.minimized_generators()
     648        n_points = 0
     649        n_closure_points = 0
     650        n_lines = 0
     651        n_rays = 0
     652        for g in gs:
     653            if g.is_line():
     654                n_lines += 1
     655            elif g.is_ray():
     656                n_rays += 1
     657            elif g.is_point():
     658                n_points += 1
     659            elif g.is_closure_point():
     660                n_closure_points += 1
     661            else:
     662                assert False
     663        if self.is_empty():
     664            return 'The empty polyhedron in QQ^'+str(ambient_dim)+'.'
     665        if self.is_universe():
     666            return 'The space-filling polyhedron in QQ^'+str(ambient_dim)+'.'
     667        desc = 'A ' + str(dim) + '-dimensional polyhedron'
     668        desc += ' in QQ'
     669        desc += '^' + str(ambient_dim)
     670        desc += ' defined as the convex hull of '
     671        first = True
     672        if n_points>0:
     673            if not first:
     674                desc += ", "
     675            first = False
     676            desc += str(n_points)
     677            if n_points==1:  desc += ' point'
     678            else:          desc += ' points'
     679        if n_closure_points>0:
     680            if not first:
     681                desc += ", "
     682            first = False
     683            desc += str(n_closure_points)
     684            if n_closure_points==1:  desc += ' closure_point'
     685            else:          desc += ' closure_points'
     686        if n_rays>0:
     687            if not first:
     688                desc += ", "
     689            first = False
     690            desc += str(n_rays)
     691            if n_rays==1:  desc += ' ray'
     692            else:          desc += ' rays'
     693        if n_lines>0:
     694            if not first:
     695                desc += ", "
     696            first = False
     697            desc += repr(n_lines)
     698            if n_lines==1: desc +=' line'
     699            else:          desc +=' lines'
     700        return desc + ".";
     701
     702
     703    def space_dimension(self):
     704        r"""
     705        Return the dimension of the vector space enclosing ``self``.
     706
     707        OUTPUT:
     708       
     709        Integer.
     710
     711        EXAMPLES::
     712
     713            sage: from sage.libs.ppl import Variable, C_Polyhedron
     714            sage: x = Variable(0)
     715            sage: y = Variable(1)
     716            sage: p = C_Polyhedron( 5*x-2*y >=  x+y-1 )
     717            sage: p.space_dimension()
     718            2
     719        """
     720        return self.thisptr.space_dimension()
     721
     722
     723    def affine_dimension(self):
     724        r"""
     725        Return the affine dimension of ``self``.
     726
     727        OUTPUT:
     728
     729        An integer. Returns 0 if ``self`` is empty. Otherwise, returns
     730        the affine dimension of ``self``.
     731
     732        EXAMPLES::
     733
     734            sage: from sage.libs.ppl import Variable, C_Polyhedron
     735            sage: x = Variable(0)
     736            sage: y = Variable(1)
     737            sage: p = C_Polyhedron( 5*x-2*y ==  x+y-1 )
     738            sage: p.affine_dimension()
     739            1
     740        """
     741        sig_on()
     742        cdef size_t dim = self.thisptr.affine_dimension()
     743        sig_off()
     744        return dim
     745       
     746
     747    def constraints(self):
     748        r"""
     749        Returns the system of constraints.
     750
     751        See also :meth:`minimized_constraints`.
     752
     753        OUTPUT:
     754       
     755        A :class:`Constraint_System`.
     756
     757        EXAMPLES::
     758
     759            sage: from sage.libs.ppl import Variable, C_Polyhedron
     760            sage: x = Variable(0)
     761            sage: y = Variable(1)
     762            sage: p = C_Polyhedron( y>=0 )
     763            sage: p.add_constraint( x>=0 )
     764            sage: p.add_constraint( x+y>=0 )
     765            sage: p.constraints()
     766            Constraint_System {x1>=0, x0>=0, x0+x1>=0}
     767            sage: p.minimized_constraints()
     768            Constraint_System {x1>=0, x0>=0}
     769        """
     770        sig_on()
     771        cdef PPL_Constraint_System cs = self.thisptr.constraints()
     772        sig_off()
     773        return _wrap_Constraint_System(cs)
     774
     775
     776    def minimized_constraints(self):
     777        r"""
     778        Returns the minimized system of constraints.
     779
     780        See also :meth:`constraints`.
     781
     782        OUTPUT:
     783       
     784        A :class:`Constraint_System`.
     785
     786        EXAMPLES::
     787
     788            sage: from sage.libs.ppl import Variable, C_Polyhedron
     789            sage: x = Variable(0)
     790            sage: y = Variable(1)
     791            sage: p = C_Polyhedron( y>=0 )
     792            sage: p.add_constraint( x>=0 )
     793            sage: p.add_constraint( x+y>=0 )
     794            sage: p.constraints()
     795            Constraint_System {x1>=0, x0>=0, x0+x1>=0}
     796            sage: p.minimized_constraints()
     797            Constraint_System {x1>=0, x0>=0}
     798        """
     799        sig_on()
     800        cdef PPL_Constraint_System cs = self.thisptr.minimized_constraints()
     801        sig_off()
     802        return _wrap_Constraint_System(cs)
     803
     804
     805    def generators(self):
     806        r"""
     807        Returns the system of generators.
     808
     809        See also :meth:`minimized_generators`.
     810
     811        OUTPUT:
     812       
     813        A :class:`Generator_System`.
     814
     815        EXAMPLES::
     816
     817            sage: from sage.libs.ppl import Variable, C_Polyhedron, point
     818            sage: x = Variable(0)
     819            sage: y = Variable(1)
     820            sage: p = C_Polyhedron(3,'empty')
     821            sage: p.add_generator( point(-x-y) )
     822            sage: p.add_generator( point(0) )
     823            sage: p.add_generator( point(+x+y) )
     824            sage: p.generators()
     825            Generator_System {point(-1/1, -1/1, 0/1), point(0/1, 0/1, 0/1), point(1/1, 1/1, 0/1)}
     826            sage: p.minimized_generators()
     827            Generator_System {point(-1/1, -1/1, 0/1), point(1/1, 1/1, 0/1)}
     828        """
     829        sig_on()
     830        cdef PPL_Generator_System gs = self.thisptr.generators()
     831        sig_off()
     832        return _wrap_Generator_System(gs)
     833
     834
     835    def minimized_generators(self):
     836        r"""
     837        Returns the minimized system of generators.
     838
     839        See also :meth:`generators`.
     840
     841        OUTPUT:
     842       
     843        A :class:`Generator_System`.
     844
     845        EXAMPLES::
     846
     847            sage: from sage.libs.ppl import Variable, C_Polyhedron, point
     848            sage: x = Variable(0)
     849            sage: y = Variable(1)
     850            sage: p = C_Polyhedron(3,'empty')
     851            sage: p.add_generator( point(-x-y) )
     852            sage: p.add_generator( point(0) )
     853            sage: p.add_generator( point(+x+y) )
     854            sage: p.generators()
     855            Generator_System {point(-1/1, -1/1, 0/1), point(0/1, 0/1, 0/1), point(1/1, 1/1, 0/1)}
     856            sage: p.minimized_generators()
     857            Generator_System {point(-1/1, -1/1, 0/1), point(1/1, 1/1, 0/1)}
     858        """
     859        sig_on()
     860        cdef PPL_Generator_System gs = self.thisptr.minimized_generators()
     861        sig_off()
     862        return _wrap_Generator_System(gs)
     863
     864
     865    cdef _relation_with_generator(Polyhedron self, Generator g):
     866        r"""
     867        Helper method for :meth:`relation_with`.
     868        """
     869        rel = Poly_Gen_Relation(True)
     870        try:
     871            sig_on()
     872            rel.thisptr = new_relation_with(self.thisptr[0], g.thisptr[0])
     873        except ValueError, msg:
     874            # we must initialize rel.thisptr to something
     875            rel.thisptr = new PPL_Poly_Gen_Relation(PPL_Poly_Gen_Relation_nothing())
     876            raise ValueError, msg
     877        finally:
     878            sig_off()
     879        return rel
     880
     881
     882    cdef _relation_with_constraint(Polyhedron self, Constraint c):
     883        r"""
     884        Helper method for :meth:`relation_with`.
     885        """
     886        rel = Poly_Con_Relation(True)
     887        try:
     888            sig_on()
     889            rel.thisptr = new_relation_with(self.thisptr[0], c.thisptr[0])
     890        except ValueError, msg:
     891            # we must initialize rel.thisptr to something
     892            rel.thisptr = new PPL_Poly_Con_Relation(PPL_Poly_Con_Relation_nothing())
     893            raise ValueError, msg
     894        finally:
     895            sig_off()
     896        return rel
     897
     898
     899    def relation_with(self, arg):
     900        r"""
     901        Return the relations holding between the polyhedron ``self``
     902        and the generator or constraint ``arg``.
     903       
     904        INPUT:
     905
     906        - ``arg`` -- a :class:`Generator` or a :class:`Constraint`.
     907
     908        OUTPUT:
     909
     910        A :class:`Poly_Gen_Relation` or a :class:`Poly_Con_Relation`
     911        according to the type of the input.
     912
     913        Raises ``ValueError`` if ``self`` and the generator/constraint
     914        ``arg`` are dimension-incompatible.
     915
     916        EXAMPLES::
     917       
     918            sage: from sage.libs.ppl import Variable, C_Polyhedron, point, ray, Poly_Con_Relation
     919            sage: x = Variable(0);  y = Variable(1)
     920            sage: p = C_Polyhedron(2, 'empty')
     921            sage: p.add_generator( point(1*x+0*y) )
     922            sage: p.add_generator( point(0*x+1*y) )
     923            sage: p.minimized_constraints()
     924            Constraint_System {x0+x1-1==0, -x1+1>=0, x1>=0}
     925            sage: p.relation_with( point(1*x+1*y) )
     926            nothing
     927            sage: p.relation_with( point(1*x+1*y, 2) )
     928            subsumes
     929            sage: p.relation_with( x+y==-1 )
     930            is_disjoint
     931            sage: p.relation_with( x==y )
     932            strictly_intersects
     933            sage: p.relation_with( x+y<=1 )
     934            is_included, saturates
     935            sage: p.relation_with( x+y<1 )
     936            is_disjoint, saturates
     937
     938        In a Sage program you will usually use :meth:`relation_with`
     939        together with :meth:`~sage.libs.ppl.Poly_Gen_Relation.implies`
     940        or :meth:`~sage.libs.ppl.Poly_Con_Relation.implies`, for
     941        example::
     942
     943            sage: p.relation_with( x+y<1 ).implies(Poly_Con_Relation.saturates())
     944            True
     945
     946        You can only get relations with dimension-compatible
     947        generators or constraints::
     948
     949            sage: z = Variable(2)
     950            sage: p.relation_with( point(x+y+z) )
     951            Traceback (most recent call last):
     952            ...
     953            ValueError: PPL::C_Polyhedron::relation_with(g):
     954            this->space_dimension() == 2, g.space_dimension() == 3.
     955            sage: p.relation_with( z>0 )
     956            Traceback (most recent call last):
     957            ...
     958            ValueError: PPL::C_Polyhedron::relation_with(c):
     959            this->space_dimension() == 2, c.space_dimension() == 3.
     960        """
     961        if isinstance(arg, Generator):
     962            return self._relation_with_generator(arg)
     963        if isinstance(arg, Constraint):
     964            return self._relation_with_constraint(arg)
     965        else:
     966            raise TypeError, 'Argument must be Generator or a Constraint'
     967
     968
     969    def is_empty(self):
     970        """
     971        Test if ``self`` is an empty polyhedron.
     972
     973        OUTPUT:
     974
     975        Boolean.
     976
     977        EXAMPLES::
     978       
     979            sage: from sage.libs.ppl import C_Polyhedron
     980            sage: C_Polyhedron(3, 'empty').is_empty()
     981            True
     982            sage: C_Polyhedron(3, 'universe').is_empty()
     983            False
     984        """
     985        sig_on()
     986        cdef bint result = self.thisptr.is_empty()
     987        sig_off()
     988        return result
     989
     990
     991    def is_universe(self):
     992        """
     993        Test if ``self`` is a universe (space-filling) polyhedron.
     994
     995        OUTPUT:
     996
     997        Boolean.
     998
     999        EXAMPLES::
     1000       
     1001            sage: from sage.libs.ppl import C_Polyhedron
     1002            sage: C_Polyhedron(3, 'empty').is_universe()
     1003            False
     1004            sage: C_Polyhedron(3, 'universe').is_universe()
     1005            True
     1006        """
     1007        sig_on()
     1008        cdef bint result = self.thisptr.is_universe()
     1009        sig_off()
     1010        return result
     1011
     1012
     1013    def is_topologically_closed(self):
     1014        """
     1015        Tests if ``self`` is topologically closed.
     1016
     1017        OUTPUT:
     1018
     1019        Returns ``True`` if and only if ``self`` is a topologically
     1020        closed subset of the ambient vector space.
     1021
     1022        EXAMPLES::
     1023       
     1024            sage: from sage.libs.ppl import Variable, C_Polyhedron, NNC_Polyhedron
     1025            sage: x = Variable(0);  y = Variable(1)
     1026            sage: C_Polyhedron(3, 'universe').is_topologically_closed()
     1027            True
     1028            sage: C_Polyhedron( x>=1 ).is_topologically_closed()
     1029            True
     1030            sage: NNC_Polyhedron( x>1 ).is_topologically_closed()
     1031            False
     1032        """
     1033        sig_on()
     1034        cdef bint result = self.thisptr.is_topologically_closed()
     1035        sig_off()
     1036        return result
     1037
     1038
     1039    def is_disjoint_from(self, Polyhedron y):
     1040        r"""
     1041        Tests whether ``self`` and ``y`` are disjoint.
     1042
     1043        INPUT:
     1044
     1045        - ``y`` -- a :class:`Polyhedron`.
     1046
     1047        OUTPUT:
     1048
     1049        Boolean. Returns ``True`` if and only if ``self`` and ``y``
     1050        are disjoint.
     1051       
     1052        Rayises a ``ValueError`` if ``self`` and ``y`` are
     1053        topology-incompatible or dimension-incompatible.
     1054
     1055        EXAMPLES::
     1056
     1057            sage: from sage.libs.ppl import Variable, C_Polyhedron, NNC_Polyhedron
     1058            sage: x = Variable(0);  y = Variable(1)
     1059            sage: C_Polyhedron(x<=0).is_disjoint_from( C_Polyhedron(x>=1) )
     1060            True
     1061       
     1062        This is not allowed::
     1063
     1064            sage: x = Variable(0);  y = Variable(1)
     1065            sage: poly_1d = C_Polyhedron(x<=0)
     1066            sage: poly_2d = C_Polyhedron(x+0*y>=1)
     1067            sage: poly_1d.is_disjoint_from(poly_2d)
     1068            Traceback (most recent call last):
     1069            ...
     1070            ValueError: PPL::C_Polyhedron::intersection_assign(y):
     1071            this->space_dimension() == 1, y.space_dimension() == 2.
     1072
     1073        Nor is this::
     1074       
     1075            sage: x = Variable(0);  y = Variable(1)
     1076            sage: c_poly   =   C_Polyhedron( x<=0 )
     1077            sage: nnc_poly = NNC_Polyhedron( x >0 )
     1078            sage: c_poly.is_disjoint_from(nnc_poly)
     1079            Traceback (most recent call last):
     1080            ...
     1081            ValueError: PPL::C_Polyhedron::intersection_assign(y):
     1082            y is a NNC_Polyhedron.
     1083            sage: NNC_Polyhedron(c_poly).is_disjoint_from(nnc_poly)
     1084            True
     1085        """
     1086        cdef bint result
     1087        try:
     1088            sig_on()
     1089            result = self.thisptr.is_disjoint_from(y.thisptr[0])
     1090        finally:
     1091            sig_off()
     1092        return result
     1093
     1094
     1095    def is_discrete(self):
     1096        r"""
     1097        Test whether ``self`` is discrete.
     1098       
     1099        OUTPUT:
     1100       
     1101        Boolean. Returns ``True`` if and only if ``self`` is discrete.
     1102
     1103        EXAMPLES::
     1104
     1105            sage: from sage.libs.ppl import Variable, C_Polyhedron, point, ray
     1106            sage: x = Variable(0);  y = Variable(1)
     1107            sage: p = C_Polyhedron( point(1*x+2*y) )
     1108            sage: p.is_discrete()
     1109            True
     1110            sage: p.add_generator( point(x) )
     1111            sage: p.is_discrete()
     1112            False
     1113        """
     1114        sig_on()
     1115        cdef bint result = self.thisptr.is_discrete()
     1116        sig_off()
     1117        return result
     1118
     1119
     1120    def is_bounded(self):
     1121        r"""
     1122        Test whether ``self`` is bounded.
     1123       
     1124        OUTPUT:
     1125       
     1126        Boolean. Returns ``True`` if and only if ``self`` is a bounded polyhedron.
     1127
     1128        EXAMPLES::
     1129
     1130            sage: from sage.libs.ppl import Variable, NNC_Polyhedron, point, closure_point, ray
     1131            sage: x = Variable(0)
     1132            sage: p = NNC_Polyhedron( point(0*x) )
     1133            sage: p.add_generator( closure_point(1*x) )
     1134            sage: p.is_bounded()
     1135            True
     1136            sage: p.add_generator( ray(1*x) )
     1137            sage: p.is_bounded()
     1138            False
     1139        """
     1140        sig_on()
     1141        cdef bint result = self.thisptr.is_bounded()
     1142        sig_off()
     1143        return result
     1144
     1145
     1146    def contains_integer_point(self):
     1147        r"""
     1148        Test whether ``self`` contains an integer point.
     1149       
     1150        OUTPUT:
     1151       
     1152        Boolean. Returns ``True`` if and only if ``self`` contains an
     1153        integer point.
     1154
     1155        EXAMPLES::
     1156
     1157            sage: from sage.libs.ppl import Variable, NNC_Polyhedron
     1158            sage: x = Variable(0)
     1159            sage: p = NNC_Polyhedron(x>0)
     1160            sage: p.add_constraint(x<1)
     1161            sage: p.contains_integer_point()
     1162            False
     1163            sage: p.topological_closure_assign()
     1164            sage: p.contains_integer_point()
     1165            True
     1166        """
     1167        sig_on()
     1168        cdef bint result = self.thisptr.contains_integer_point()
     1169        sig_off()
     1170        return result
     1171
     1172
     1173    def constrains(self, Variable var):
     1174        r"""
     1175        Test whether ``var`` is constrained in ``self``.
     1176       
     1177        INPUT:
     1178
     1179        - ``var`` -- a :class:`Variable`.
     1180
     1181        OUTPUT:
     1182
     1183        Boolean. Returns ``True`` if and only if ``var`` is
     1184        constrained in ``self``.
     1185
     1186        Raises a ``ValueError`` if ``var`` is not a space dimension of
     1187        ``self``.
     1188
     1189        EXAMPLES::
     1190
     1191            sage: from sage.libs.ppl import Variable, C_Polyhedron
     1192            sage: x = Variable(0)
     1193            sage: p = C_Polyhedron(1, 'universe')
     1194            sage: p.constrains(x)
     1195            False
     1196            sage: p = C_Polyhedron(x>=0)
     1197            sage: p.constrains(x)
     1198            True
     1199            sage: y = Variable(1)
     1200            sage: p.constrains(y)
     1201            Traceback (most recent call last):
     1202            ...
     1203            ValueError: PPL::C_Polyhedron::constrains(v):
     1204            this->space_dimension() == 1, v.space_dimension() == 2.
     1205        """
     1206        cdef bint result
     1207        try:
     1208            sig_on()
     1209            result = self.thisptr.constrains(var.thisptr[0])
     1210        finally:
     1211            sig_off()
     1212        return result
     1213
     1214
     1215    def bounds_from_above(self, Linear_Expression expr):
     1216        r"""
     1217        Test whether the ``expr`` is bounded from above.
     1218
     1219        INPUT:
     1220
     1221        - ``expr`` -- a :class:`Linear_Expression`
     1222       
     1223        OUTPUT:
     1224       
     1225        Boolean. Returns ``True`` if and only if ``expr`` is bounded
     1226        from above in ``self``.
     1227
     1228        Raises a ``ValueError`` if ``expr`` and ``this`` are
     1229        dimension-incompatible.
     1230
     1231        EXAMPLES::
     1232       
     1233            sage: from sage.libs.ppl import Variable, C_Polyhedron, Linear_Expression
     1234            sage: x = Variable(0);  y = Variable(1)
     1235            sage: p = C_Polyhedron(y<=0)
     1236            sage: p.bounds_from_above(x+1)
     1237            False
     1238            sage: p.bounds_from_above(Linear_Expression(y))
     1239            True
     1240            sage: p = C_Polyhedron(x<=0)
     1241            sage: p.bounds_from_above(y+1)
     1242            Traceback (most recent call last):
     1243            ...
     1244            ValueError: PPL::C_Polyhedron::bounds_from_above(e):
     1245            this->space_dimension() == 1, e.space_dimension() == 2.
     1246        """
     1247        cdef bint result
     1248        try:
     1249            sig_on()
     1250            result = self.thisptr.bounds_from_above(expr.thisptr[0])
     1251        finally:
     1252            sig_off()
     1253        return result
     1254
     1255
     1256    def bounds_from_below(self, Linear_Expression expr):
     1257        r"""
     1258        Test whether the ``expr`` is bounded from above.
     1259
     1260        INPUT:
     1261
     1262        - ``expr`` -- a :class:`Linear_Expression`
     1263       
     1264        OUTPUT:
     1265       
     1266        Boolean. Returns ``True`` if and only if ``expr`` is bounded
     1267        from above in ``self``.
     1268
     1269        Raises a ``ValueError`` if ``expr`` and ``this`` are
     1270        dimension-incompatible.
     1271
     1272        EXAMPLES::
     1273       
     1274            sage: from sage.libs.ppl import Variable, C_Polyhedron, Linear_Expression
     1275            sage: x = Variable(0);  y = Variable(1)
     1276            sage: p = C_Polyhedron(y>=0)
     1277            sage: p.bounds_from_below(x+1)
     1278            False
     1279            sage: p.bounds_from_below(Linear_Expression(y))
     1280            True
     1281            sage: p = C_Polyhedron(x<=0)
     1282            sage: p.bounds_from_below(y+1)
     1283            Traceback (most recent call last):
     1284            ...
     1285            ValueError: PPL::C_Polyhedron::bounds_from_below(e):
     1286            this->space_dimension() == 1, e.space_dimension() == 2.
     1287        """
     1288        cdef bint result
     1289        try:
     1290            sig_on()
     1291            result = self.thisptr.bounds_from_below(expr.thisptr[0])
     1292        finally:
     1293            sig_off()
     1294        return result
     1295
     1296
     1297    def maximize(self, Linear_Expression expr):
     1298        r"""
     1299        Maximize ``expr``.
     1300
     1301        INPUT:
     1302       
     1303        - ``expr`` -- a :class:`Linear_Expression`.
     1304
     1305        OUTPUT:
     1306
     1307        A dictionary with the following keyword:value pairs:
     1308
     1309        * ``'bounded'``: Boolean. Whether the linear expression
     1310          ``expr`` is bounded from above on ``self``.
     1311
     1312        * ``'sup_n'``: Integer. The numerator of the supremum value.
     1313
     1314        * ``'sup_d'``: Integer. The denominator of the supremum
     1315          value. Can be zero if the linear expression is not bounded.
     1316
     1317        * ``'maximum'``: Boolean. ``True`` if and only if the supremum
     1318          is also the maximum value.
     1319
     1320        * ``'generator'``: a :class:`Generator`. When maximization
     1321          succeeds, will be assigned a point or closure point where
     1322          expr reaches its supremum value.  If ``expr`` is unbounded,
     1323          ``None``.
     1324
     1325        EXAMPLES::
     1326
     1327            sage: from sage.libs.ppl import Variable, C_Polyhedron, NNC_Polyhedron, Constraint_System, Linear_Expression
     1328            sage: x = Variable(0);  y = Variable(1)
     1329            sage: cs = Constraint_System()
     1330            sage: cs.insert( x>=0 )
     1331            sage: cs.insert( y>=0 )
     1332            sage: cs.insert( 3*x+5*y<=10 )
     1333            sage: p = C_Polyhedron(cs)
     1334            sage: p.maximize( x+y )
     1335            {'sup_d': 3, 'sup_n': 10, 'bounded': True, 'maximum': True, 'generator': point(10/3, 0/3)}
     1336
     1337        Unbounded case::
     1338
     1339            sage: cs = Constraint_System()
     1340            sage: cs.insert( x>0 )
     1341            sage: p = NNC_Polyhedron(cs)
     1342            sage: p.maximize( +x )
     1343            {'sup_d': 0, 'sup_n': 0, 'bounded': False, 'maximum': False, 'generator': None}
     1344            sage: p.maximize( -x )
     1345            {'sup_d': 1, 'sup_n': 0, 'bounded': True, 'maximum': False, 'generator': closure_point(0/1)}
     1346        """
     1347        cdef PPL_Coefficient sup_n
     1348        cdef PPL_Coefficient sup_d
     1349        cdef Generator g = point()
     1350        cdef cppbool maximum
     1351        sig_on()
     1352        rc = self.thisptr.maximize(<PPL_Linear_Expression&>expr.thisptr[0], sup_n, sup_d, maximum, g.thisptr[0])
     1353        sig_off()
     1354
     1355        cdef Integer Int_sup_n = Integer(0)
     1356        mpz_set(Int_sup_n.value, sup_n.get_mpz_t())
     1357        cdef Integer Int_sup_d = Integer(0)
     1358        mpz_set(Int_sup_d.value, sup_d.get_mpz_t())
     1359
     1360        if rc:
     1361            return { 'bounded':rc, 'sup_n':Int_sup_n, 'sup_d':Int_sup_d, 'maximum':maximum, 'generator':g }
     1362        else:
     1363            return { 'bounded':rc, 'sup_n':Int_sup_n, 'sup_d':Int_sup_d, 'maximum':maximum, 'generator':None }
     1364
     1365
     1366    def minimize(self, Linear_Expression expr):
     1367        r"""
     1368        Minimize ``expr``.
     1369
     1370        INPUT:
     1371       
     1372        - ``expr`` -- a :class:`Linear_Expression`.
     1373
     1374        OUTPUT:
     1375
     1376        A dictionary with the following keyword:value pairs:
     1377
     1378        * ``'bounded'``: Boolean. Whether the linear expression
     1379          ``expr`` is bounded from below on ``self``.
     1380
     1381        * ``'inf_n'``: Integer. The numerator of the supremum value.
     1382
     1383        * ``'inf_d'``: Integer. The denominator of the supremum
     1384          value. Can be zero if the linear expression is not bounded.
     1385
     1386        * ``'minimum'``: Boolean. ``True`` if and only if the infimum
     1387          is also the minimum value.
     1388
     1389        * ``'generator'``: a :class:`Generator` or ``None``. When
     1390          maximization succeeds, will be assigned a point or closure
     1391          point where expr reaches its supremum value. If ``expr`` is
     1392          unbounded, ``None``.
     1393       
     1394        EXAMPLES::
     1395
     1396            sage: from sage.libs.ppl import Variable, C_Polyhedron, NNC_Polyhedron, Constraint_System, Linear_Expression
     1397            sage: x = Variable(0);  y = Variable(1)
     1398            sage: cs = Constraint_System()
     1399            sage: cs.insert( x>=0 )
     1400            sage: cs.insert( y>=0 )
     1401            sage: cs.insert( 3*x+5*y<=10 )
     1402            sage: p = C_Polyhedron(cs)
     1403            sage: p.minimize( x+y )
     1404            {'minimum': True, 'bounded': True, 'inf_d': 1, 'generator': point(0/1, 0/1), 'inf_n': 0}
     1405
     1406        Unbounded case::
     1407
     1408            sage: cs = Constraint_System()
     1409            sage: cs.insert( x>0 )
     1410            sage: p = NNC_Polyhedron(cs)
     1411            sage: p.minimize( +x )
     1412            {'minimum': False, 'bounded': True, 'inf_d': 1, 'generator': closure_point(0/1), 'inf_n': 0}
     1413            sage: p.minimize( -x )
     1414            {'minimum': False, 'bounded': False, 'inf_d': 0, 'generator': None, 'inf_n': 0}
     1415        """
     1416        cdef PPL_Coefficient inf_n
     1417        cdef PPL_Coefficient inf_d
     1418        cdef Generator g = point()
     1419        cdef cppbool minimum
     1420        sig_on()
     1421        rc = self.thisptr.minimize(<PPL_Linear_Expression&>expr.thisptr[0], inf_n, inf_d, minimum, g.thisptr[0])
     1422        sig_off()
     1423
     1424        cdef Integer Int_inf_n = Integer(0)
     1425        mpz_set(Int_inf_n.value, inf_n.get_mpz_t())
     1426        cdef Integer Int_inf_d = Integer(0)
     1427        mpz_set(Int_inf_d.value, inf_d.get_mpz_t())
     1428
     1429        if rc:
     1430            return { 'bounded':rc, 'inf_n':Int_inf_n, 'inf_d':Int_inf_d, 'minimum':minimum, 'generator':g }
     1431        else:
     1432            return { 'bounded':rc, 'inf_n':Int_inf_n, 'inf_d':Int_inf_d, 'minimum':minimum, 'generator':None }
     1433
     1434
     1435    def contains(self, Polyhedron y):
     1436        r"""
     1437        Test whether ``self`` contains ``y``.
     1438
     1439        INPUT:
     1440
     1441        - ``y`` -- a :class:`Polyhedron`.
     1442
     1443        OUTPUT:
     1444       
     1445        Boolean. Returns ``True`` if and only if ``self`` contains ``y``.
     1446
     1447        Raises a ``ValueError`` if ``self`` and ``y`` are
     1448        topology-incompatible or dimension-incompatible.
     1449
     1450        EXAMPLES::
     1451
     1452            sage: from sage.libs.ppl import Variable, C_Polyhedron, NNC_Polyhedron
     1453            sage: x = Variable(0)
     1454            sage: y = Variable(1)
     1455            sage: p0 = C_Polyhedron( x>=0 )
     1456            sage: p1 = C_Polyhedron( x>=1 )
     1457            sage: p0.contains(p1)
     1458            True
     1459            sage: p1.contains(p0)
     1460            False
     1461
     1462        Errors are raised if the dimension or topology is not compatible::
     1463
     1464            sage: p0.contains(C_Polyhedron(y>=0))
     1465            Traceback (most recent call last):
     1466            ...
     1467            ValueError: PPL::C_Polyhedron::contains(y):
     1468            this->space_dimension() == 1, y.space_dimension() == 2.
     1469            sage: p0.contains(NNC_Polyhedron(x>0))
     1470            Traceback (most recent call last):
     1471            ...
     1472            ValueError: PPL::C_Polyhedron::contains(y):
     1473            y is a NNC_Polyhedron.
     1474        """
     1475        cdef bint result
     1476        try:
     1477            sig_on()
     1478            result = self.thisptr.contains(y.thisptr[0])
     1479        finally:
     1480            sig_off()
     1481        return result
     1482
     1483       
     1484    def strictly_contains(self, Polyhedron y):
     1485        r"""
     1486        Test whether ``self`` strictly contains ``y``.
     1487
     1488        INPUT:
     1489
     1490        - ``y`` -- a :class:`Polyhedron`.
     1491
     1492        OUTPUT:
     1493       
     1494        Boolean. Returns ``True`` if and only if ``self`` contains
     1495        ``y`` and ``self`` does not equal ``y``.
     1496
     1497        Raises a ``ValueError`` if ``self`` and ``y`` are
     1498        topology-incompatible or dimension-incompatible.
     1499
     1500        EXAMPLES::
     1501
     1502            sage: from sage.libs.ppl import Variable, C_Polyhedron, NNC_Polyhedron
     1503            sage: x = Variable(0)
     1504            sage: y = Variable(1)
     1505            sage: p0 = C_Polyhedron( x>=0 )
     1506            sage: p1 = C_Polyhedron( x>=1 )
     1507            sage: p0.strictly_contains(p1)
     1508            True
     1509            sage: p1.strictly_contains(p0)
     1510            False
     1511
     1512        Errors are raised if the dimension or topology is not compatible::
     1513
     1514            sage: p0.strictly_contains(C_Polyhedron(y>=0))
     1515            Traceback (most recent call last):
     1516            ...
     1517            ValueError: PPL::C_Polyhedron::contains(y):
     1518            this->space_dimension() == 1, y.space_dimension() == 2.
     1519            sage: p0.strictly_contains(NNC_Polyhedron(x>0))
     1520            Traceback (most recent call last):
     1521            ...
     1522            ValueError: PPL::C_Polyhedron::contains(y):
     1523            y is a NNC_Polyhedron.
     1524        """
     1525        cdef bint result
     1526        try:
     1527            sig_on()
     1528            result = self.thisptr.strictly_contains(y.thisptr[0])
     1529        finally:
     1530            sig_off()
     1531        return result
     1532
     1533
     1534    def add_constraint(self, Constraint c):
     1535        r"""       
     1536        Add a constraint to the polyhedron.
     1537
     1538        Adds a copy of constraint ``c`` to the system of constraints
     1539        of ``self``, without minimizing the result.
     1540
     1541        See alse :meth:`add_constraints`.
     1542
     1543        INPUT:
     1544       
     1545        - ``c`` -- the :class:`Constraint` that will be added to the
     1546          system of constraints of ``self``.
     1547       
     1548        OUTPUT:
     1549
     1550        This method modifies the polyhedron ``self`` and does not
     1551        return anything.
     1552
     1553        Raises a ``ValueError`` if ``self`` and the constraint ``c`` are
     1554        topology-incompatible or dimension-incompatible.
     1555
     1556        EXAMPLES::
     1557
     1558            sage: from sage.libs.ppl import Variable, C_Polyhedron
     1559            sage: x = Variable(0)
     1560            sage: y = Variable(1)
     1561            sage: p = C_Polyhedron( y>=0 )
     1562            sage: p.add_constraint( x>=0 )
     1563
     1564         We just added a 1-d constraint to a 2-d polyhedron, this is
     1565         fine. The other way is not::
     1566
     1567            sage: p = C_Polyhedron( x>=0 )
     1568            sage: p.add_constraint( y>=0 )
     1569            Traceback (most recent call last):
     1570            ...
     1571            ValueError: PPL::C_Polyhedron::add_constraint(c):
     1572            this->space_dimension() == 1, c.space_dimension() == 2.
     1573
     1574         The constraint must also be topology-compatible, that is,
     1575         :class:`C_Polyhedron` only allows non-strict inequalities::
     1576
     1577            sage: p = C_Polyhedron( x>=0 )
     1578            sage: p.add_constraint( x< 1 )
     1579            Traceback (most recent call last):
     1580            ...
     1581            ValueError: PPL::C_Polyhedron::add_constraint(c):
     1582            c is a strict inequality.
     1583        """
     1584        self.assert_mutable('The Polyhedron is not mutable!')
     1585        try:
     1586            sig_on()
     1587            self.thisptr.add_constraint(c.thisptr[0])
     1588        finally:
     1589            sig_off()
     1590 
     1591
     1592    def add_generator(self, Generator g):
     1593        r"""       
     1594        Add a generator to the polyhedron.
     1595
     1596        Adds a copy of constraint ``c`` to the system of generators
     1597        of ``self``, without minimizing the result.
     1598
     1599        INPUT:
     1600       
     1601        - ``g`` -- the :class:`Generator` that will be added to the
     1602          system of Generators of ``self``.
     1603       
     1604        OUTPUT:
     1605
     1606        This method modifies the polyhedron ``self`` and does not
     1607        return anything.
     1608
     1609        Raises a ``ValueError`` if ``self`` and the generator ``g``
     1610        are topology-incompatible or dimension-incompatible, or if
     1611        ``self`` is an empty polyhedron and ``g`` is not a point.
     1612
     1613        EXAMPLES::
     1614
     1615            sage: from sage.libs.ppl import Variable, C_Polyhedron, point, closure_point, ray
     1616            sage: x = Variable(0)
     1617            sage: y = Variable(1)
     1618            sage: p = C_Polyhedron(1, 'empty')
     1619            sage: p.add_generator( point(0*x) )
     1620
     1621         We just added a 1-d generator to a 2-d polyhedron, this is
     1622         fine. The other way is not::
     1623
     1624            sage: p = C_Polyhedron(1, 'empty')
     1625            sage: p.add_generator(  point(0*y) )
     1626            Traceback (most recent call last):
     1627            ...
     1628            ValueError: PPL::C_Polyhedron::add_generator(g):
     1629            this->space_dimension() == 1, g.space_dimension() == 2.
     1630
     1631         The constraint must also be topology-compatible, that is,
     1632         :class:`C_Polyhedron` does not allow :func:`closure_point`
     1633         generators::
     1634
     1635            sage: p = C_Polyhedron( point(0*x+0*y) )
     1636            sage: p.add_generator( closure_point(0*x) )
     1637            Traceback (most recent call last):
     1638            ...
     1639            ValueError: PPL::C_Polyhedron::add_generator(g):
     1640            g is a closure point.
     1641
     1642        Finally, ever non-empty polyhedron must have at least one
     1643        point generator::
     1644
     1645            sage: p = C_Polyhedron(3, 'empty')
     1646            sage: p.add_generator( ray(x) )
     1647            Traceback (most recent call last):
     1648            ...
     1649            ValueError: PPL::C_Polyhedron::add_generator(g):
     1650            *this is an empty polyhedron and g is not a point.
     1651        """
     1652        self.assert_mutable('The Polyhedron is not mutable!')
     1653        try:
     1654            sig_on()
     1655            self.thisptr.add_generator(g.thisptr[0])
     1656        finally:
     1657            sig_off()
     1658
     1659
     1660    def add_constraints(self, Constraint_System cs):
     1661        r"""       
     1662        Add constraints to the polyhedron.
     1663
     1664        Adds a copy of constraints in ``cs`` to the system of constraints
     1665        of ``self``, without minimizing the result.
     1666
     1667        See alse :meth:`add_constraint`.
     1668
     1669        INPUT:
     1670       
     1671        - ``cs`` -- the :class:`Constraint_System` that will be added
     1672          to the system of constraints of ``self``.
     1673       
     1674        OUTPUT:
     1675
     1676        This method modifies the polyhedron ``self`` and does not
     1677        return anything.
     1678
     1679        Raises a ``ValueError`` if ``self`` and the constraints in
     1680        ``cs`` are topology-incompatible or dimension-incompatible.
     1681
     1682        EXAMPLES::
     1683
     1684            sage: from sage.libs.ppl import Variable, C_Polyhedron, Constraint_System
     1685            sage: x = Variable(0)
     1686            sage: y = Variable(1)
     1687            sage: cs = Constraint_System()
     1688            sage: cs.insert(x>=0)
     1689            sage: cs.insert(y>=0)
     1690            sage: p = C_Polyhedron( y<=1 )
     1691            sage: p.add_constraints(cs)
     1692
     1693         We just added a 1-d constraint to a 2-d polyhedron, this is
     1694         fine. The other way is not::
     1695
     1696            sage: p = C_Polyhedron( x<=1 )
     1697            sage: p.add_constraints(cs)
     1698            Traceback (most recent call last):
     1699            ...
     1700            ValueError: PPL::C_Polyhedron::add_recycled_constraints(cs):
     1701            this->space_dimension() == 1, cs.space_dimension() == 2.
     1702
     1703         The constraints must also be topology-compatible, that is,
     1704         :class:`C_Polyhedron` only allows non-strict inequalities::
     1705
     1706            sage: p = C_Polyhedron( x>=0 )
     1707            sage: p.add_constraints( Constraint_System(x<0) )
     1708            Traceback (most recent call last):
     1709            ...
     1710            ValueError: PPL::C_Polyhedron::add_recycled_constraints(cs):
     1711            cs contains strict inequalities.
     1712        """
     1713        self.assert_mutable('The Polyhedron is not mutable!')
     1714        try:
     1715            sig_on()
     1716            self.thisptr.add_constraints(cs.thisptr[0])
     1717        finally:
     1718            sig_off()
     1719 
     1720
     1721    def add_generators(self, Generator_System gs):
     1722        r"""       
     1723        Add generators to the polyhedron.
     1724
     1725        Adds a copy of the generators in ``gs`` to the system of
     1726        generators of ``self``, without minimizing the result.
     1727
     1728        See alse :meth:`add_generator`.
     1729
     1730        INPUT:
     1731       
     1732        - ``gs`` -- the :class:`Generator_System` that will be added
     1733          to the system of constraints of ``self``.
     1734       
     1735        OUTPUT:
     1736
     1737        This method modifies the polyhedron ``self`` and does not
     1738        return anything.
     1739
     1740        Raises a ``ValueError`` if ``self`` and one of the generators
     1741        in ``gs`` are topology-incompatible or dimension-incompatible,
     1742        or if ``self`` is an empty polyhedron and ``gs`` does not
     1743        contain a point.
     1744
     1745        EXAMPLES::
     1746
     1747            sage: from sage.libs.ppl import Variable, C_Polyhedron, Generator_System, point, ray, closure_point
     1748            sage: x = Variable(0)
     1749            sage: y = Variable(1)
     1750            sage: gs = Generator_System()
     1751            sage: gs.insert(point(0*x+0*y))
     1752            sage: gs.insert(point(1*x+1*y))
     1753            sage: p = C_Polyhedron(2, 'empty')
     1754            sage: p.add_generators(gs)
     1755
     1756         We just added a 1-d constraint to a 2-d polyhedron, this is
     1757         fine. The other way is not::
     1758
     1759            sage: p = C_Polyhedron(1, 'empty')
     1760            sage: p.add_generators(gs)
     1761            Traceback (most recent call last):
     1762            ...
     1763            ValueError: PPL::C_Polyhedron::add_recycled_generators(gs):
     1764            this->space_dimension() == 1, gs.space_dimension() == 2.
     1765
     1766         The constraints must also be topology-compatible, that is,
     1767         :class:`C_Polyhedron` does not allow :func:`closure_point`
     1768         generators::
     1769
     1770            sage: p = C_Polyhedron( point(0*x+0*y) )
     1771            sage: p.add_generators( Generator_System(closure_point(x) ))
     1772            Traceback (most recent call last):
     1773            ...
     1774            ValueError: PPL::C_Polyhedron::add_recycled_generators(gs):
     1775            gs contains closure points.
     1776        """
     1777        self.assert_mutable('The Polyhedron is not mutable!')
     1778        try:
     1779            sig_on()
     1780            self.thisptr.add_generators(gs.thisptr[0])
     1781        finally:
     1782            sig_off()
     1783
     1784
     1785    def unconstrain(self, Variable var):
     1786        r"""
     1787        Compute the cylindrification of ``self`` with respect to space
     1788        dimension ``var``.
     1789
     1790        INPUT:
     1791
     1792        - ``var`` -- a :class:`Variable`. The space dimension that
     1793          will be unconstrained.  Exceptions:
     1794
     1795        OUTPUT:
     1796
     1797        This method assigns the cylindrification to ``self`` and does
     1798        not return anything.
     1799
     1800        Raises a ``ValueError`` if ``var`` is not a space dimension of
     1801        ``self``.
     1802
     1803        EXAMPLES::
     1804
     1805            sage: from sage.libs.ppl import Variable, C_Polyhedron, point
     1806            sage: x = Variable(0)
     1807            sage: y = Variable(1)
     1808            sage: p = C_Polyhedron( point(x+y) ); p
     1809            A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point.
     1810            sage: p.unconstrain(x); p
     1811            A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point, 1 line.
     1812            sage: z = Variable(2)
     1813            sage: p.unconstrain(z)
     1814            Traceback (most recent call last):
     1815            ...
     1816            ValueError: PPL::C_Polyhedron::unconstrain(var):           
     1817            this->space_dimension() == 2, required space dimension == 3.
     1818        """
     1819        try:
     1820            sig_on()
     1821            self.thisptr.unconstrain(var.thisptr[0])
     1822        finally:
     1823            sig_off()
     1824
     1825
     1826    def intersection_assign(self, Polyhedron y):
     1827        r"""
     1828        Assign to ``self`` the intersection of ``self`` and ``y``.
     1829
     1830        INPUT:
     1831
     1832        - ``y`` -- a :class:`Polyhedron`
     1833
     1834        OUTPUT:
     1835
     1836        This method assigns the intersection to ``self`` and does not
     1837        return anything.
     1838
     1839        Raises a ``ValueError`` if ``self`` and and ``y`` are
     1840        topology-incompatible or dimension-incompatible.
     1841
     1842        EXAMPLES::
     1843
     1844            sage: from sage.libs.ppl import Variable, C_Polyhedron, NNC_Polyhedron
     1845            sage: x = Variable(0)
     1846            sage: y = Variable(1)
     1847            sage: p = C_Polyhedron( 1*x+0*y >= 0 )
     1848            sage: p.intersection_assign( C_Polyhedron(y>=0) )
     1849            sage: p.constraints()
     1850            Constraint_System {x0>=0, x1>=0}
     1851            sage: z = Variable(2)
     1852            sage: p.intersection_assign( C_Polyhedron(z>=0) )
     1853            Traceback (most recent call last):
     1854            ...
     1855            ValueError: PPL::C_Polyhedron::intersection_assign(y):
     1856            this->space_dimension() == 2, y.space_dimension() == 3.
     1857            sage: p.intersection_assign( NNC_Polyhedron(x+y<1) )
     1858            Traceback (most recent call last):
     1859            ...
     1860            ValueError: PPL::C_Polyhedron::intersection_assign(y):
     1861            y is a NNC_Polyhedron.
     1862        """
     1863        self.assert_mutable('The Polyhedron is not mutable!')
     1864        try:
     1865            sig_on()
     1866            self.thisptr.intersection_assign(y.thisptr[0])
     1867        finally:
     1868            sig_off()
     1869
     1870
     1871    def poly_hull_assign(self, Polyhedron y):
     1872        r"""
     1873        Assign to ``self`` the poly-hull of ``self`` and ``y``.
     1874
     1875        For any pair of NNC polyhedra `P_1` and `P_2`, the convex
     1876        polyhedral hull (or poly-hull) of is the smallest NNC
     1877        polyhedron that includes both `P_1` and `P_2`. The poly-hull
     1878        of any pair of closed polyhedra in is also closed.
     1879
     1880        INPUT:
     1881
     1882        - ``y`` -- a :class:`Polyhedron`
     1883
     1884        OUTPUT:
     1885
     1886        This method assigns the poly-hull to ``self`` and does not
     1887        return anything.
     1888
     1889        Raises a ``ValueError`` if ``self`` and and ``y`` are
     1890        topology-incompatible or dimension-incompatible.
     1891
     1892        EXAMPLES::
     1893
     1894            sage: from sage.libs.ppl import Variable, C_Polyhedron, point, NNC_Polyhedron
     1895            sage: x = Variable(0)
     1896            sage: y = Variable(1)
     1897            sage: p = C_Polyhedron( point(1*x+0*y) )
     1898            sage: p.poly_hull_assign(C_Polyhedron( point(0*x+1*y) ))
     1899            sage: p.generators()
     1900            Generator_System {point(0/1, 1/1), point(1/1, 0/1)}
     1901
     1902        ``self`` and ``y`` must be dimension- and topology-compatible,
     1903        or an exception is raised::
     1904
     1905            sage: z = Variable(2)
     1906            sage: p.poly_hull_assign( C_Polyhedron(z>=0) )
     1907            Traceback (most recent call last):
     1908            ...
     1909            ValueError: PPL::C_Polyhedron::poly_hull_assign(y):
     1910            this->space_dimension() == 2, y.space_dimension() == 3.
     1911            sage: p.poly_hull_assign( NNC_Polyhedron(x+y<1) )
     1912            Traceback (most recent call last):
     1913            ...
     1914            ValueError: PPL::C_Polyhedron::poly_hull_assign(y):
     1915            y is a NNC_Polyhedron.
     1916        """
     1917        self.assert_mutable('The Polyhedron is not mutable!')
     1918        try:
     1919            sig_on()
     1920            self.thisptr.poly_hull_assign(y.thisptr[0])
     1921        finally:
     1922            sig_off()
     1923
     1924
     1925    upper_bound_assign = poly_hull_assign
     1926
     1927
     1928    def poly_difference_assign(self, Polyhedron y):
     1929        r"""
     1930        Assign to ``self`` the poly-difference of ``self`` and ``y``.
     1931
     1932        For any pair of NNC polyhedra `P_1` and `P_2` the convex
     1933        polyhedral difference (or poly-difference) of `P_1` and `P_2`
     1934        is defined as the smallest convex polyhedron containing the
     1935        set-theoretic difference `P_1\setminus P_2` of `P_1` and
     1936        `P_2`.
     1937
     1938        In general, even if `P_1` and `P_2` are topologically closed
     1939        polyhedra, their poly-difference may be a convex polyhedron
     1940        that is not topologically closed. For this reason, when
     1941        computing the poly-difference of two :class:`C_Polyhedron`,
     1942        the library will enforce the topological closure of the
     1943        result.
     1944
     1945        INPUT:
     1946
     1947        - ``y`` -- a :class:`Polyhedron`
     1948
     1949        OUTPUT:
     1950
     1951        This method assigns the poly-difference to ``self`` and does
     1952        not return anything.
     1953
     1954        Raises a ``ValueError`` if ``self`` and and ``y`` are
     1955        topology-incompatible or dimension-incompatible.
     1956
     1957        EXAMPLES::
     1958
     1959            sage: from sage.libs.ppl import Variable, C_Polyhedron, point, closure_point, NNC_Polyhedron
     1960            sage: x = Variable(0)
     1961            sage: p = NNC_Polyhedron( point(0*x) )
     1962            sage: p.add_generator( point(1*x) )
     1963            sage: p.poly_difference_assign(NNC_Polyhedron( point(0*x) ))
     1964            sage: p.minimized_constraints()
     1965            Constraint_System {-x0+1>=0, x0>0}
     1966
     1967        The poly-difference of :class:`C_polyhedron` is really its closure::
     1968
     1969            sage: p = C_Polyhedron( point(0*x) )
     1970            sage: p.add_generator( point(1*x) )
     1971            sage: p.poly_difference_assign(C_Polyhedron( point(0*x) ))
     1972            sage: p.minimized_constraints()
     1973            Constraint_System {x0>=0, -x0+1>=0}
     1974
     1975        ``self`` and ``y`` must be dimension- and topology-compatible,
     1976        or an exception is raised::
     1977
     1978            sage: y = Variable(1)
     1979            sage: p.poly_difference_assign( C_Polyhedron(y>=0) )
     1980            Traceback (most recent call last):
     1981            ...
     1982            ValueError: PPL::C_Polyhedron::poly_difference_assign(y):
     1983            this->space_dimension() == 1, y.space_dimension() == 2.
     1984            sage: p.poly_difference_assign( NNC_Polyhedron(x+y<1) )
     1985            Traceback (most recent call last):
     1986            ...
     1987            ValueError: PPL::C_Polyhedron::poly_difference_assign(y):
     1988            y is a NNC_Polyhedron.
     1989        """
     1990        self.assert_mutable('The Polyhedron is not mutable!')
     1991        try:
     1992            sig_on()
     1993            self.thisptr.poly_difference_assign(y.thisptr[0])
     1994        finally:
     1995            sig_off()
     1996
     1997
     1998    difference_assign = poly_difference_assign
     1999
     2000
     2001    def drop_some_non_integer_points(self):
     2002        r"""
     2003        Possibly tighten ``self`` by dropping some points with
     2004        non-integer coordinates.
     2005
     2006        The modified polyhedron satisfies:
     2007
     2008        * it is (not necessarily strictly) contained in the original
     2009          polyhedron.
     2010
     2011        * integral vertices (generating points with integer
     2012          coordinates) of the original polyhedron are not removed.
     2013
     2014        .. NOTE::
     2015       
     2016            The modified polyhedron is not neccessarily a lattice
     2017            polyhedron; Some vertices will, in general, still be
     2018            rational. Lattice points interior to the polyhedron may be
     2019            lost in the process.
     2020
     2021        EXAMPLES::
     2022
     2023            sage: from sage.libs.ppl import Variable, NNC_Polyhedron, Constraint_System
     2024            sage: x = Variable(0)
     2025            sage: y = Variable(1)
     2026            sage: cs = Constraint_System()
     2027            sage: cs.insert( x>=0 )
     2028            sage: cs.insert( y>=0 )
     2029            sage: cs.insert( 3*x+2*y<5 )
     2030            sage: p = NNC_Polyhedron(cs)
     2031            sage: p.minimized_generators()
     2032            Generator_System {point(0/1, 0/1), closure_point(0/2, 5/2), closure_point(5/3, 0/3)}
     2033            sage: p.drop_some_non_integer_points()
     2034            sage: p.minimized_generators()
     2035            Generator_System {point(0/1, 0/1), point(0/1, 2/1), point(4/3, 0/3)}
     2036        """
     2037        self.assert_mutable('The Polyhedron is not mutable!')
     2038        sig_on()
     2039        self.thisptr.drop_some_non_integer_points()
     2040        sig_off()
     2041
     2042
     2043    def topological_closure_assign(self):
     2044        r"""
     2045        Assign to ``self`` its topological closure.
     2046
     2047        EXAMPLES::
     2048       
     2049            sage: from sage.libs.ppl import Variable, NNC_Polyhedron
     2050            sage: x = Variable(0)
     2051            sage: p = NNC_Polyhedron(x>0)
     2052            sage: p.is_topologically_closed()
     2053            False
     2054            sage: p.topological_closure_assign()
     2055            sage: p.is_topologically_closed()
     2056            True
     2057            sage: p.minimized_constraints()
     2058            Constraint_System {x0>=0}
     2059        """
     2060        self.assert_mutable('The Polyhedron is not mutable!')
     2061        sig_on()
     2062        self.thisptr.topological_closure_assign()
     2063        sig_off()
     2064
     2065
     2066    def add_space_dimensions_and_embed(self, m):
     2067        r"""
     2068        Add ``m`` new space dimensions and embed ``self`` in the new
     2069        vector space.
     2070
     2071        The new space dimensions will be those having the highest
     2072        indexes in the new polyhedron, which is characterized by a
     2073        system of constraints in which the variables running through
     2074        the new dimensions are not constrained. For instance, when
     2075        starting from the polyhedron `P` and adding a third space
     2076        dimension, the result will be the polyhedron
     2077
     2078        .. MATH::
     2079
     2080            \Big\{
     2081            (x,y,z)^T \in \RR^3
     2082            \Big|
     2083            (x,y)^T \in P
     2084            \Big\}
     2085
     2086        INPUT:
     2087
     2088        - ``m`` -- integer.
     2089
     2090        OUTPUT:
     2091
     2092        This method assigns the embedded polyhedron to ``self`` and
     2093        does not return anything.
     2094
     2095        Raises a ``ValueError`` if adding ``m`` new space dimensions
     2096        would cause the vector space to exceed dimension
     2097        ``self.max_space_dimension()``.
     2098
     2099        EXAMPLES::
     2100
     2101            sage: from sage.libs.ppl import Variable, C_Polyhedron, point
     2102            sage: x = Variable(0)
     2103            sage: p = C_Polyhedron( point(3*x) )
     2104            sage: p.add_space_dimensions_and_embed(1)
     2105            sage: p.minimized_generators()
     2106            Generator_System {line(0, 1), point(3/1, 0/1)}
     2107            sage: p.add_space_dimensions_and_embed( p.max_space_dimension() )
     2108            Traceback (most recent call last):
     2109            ...
     2110            ValueError: PPL::C_Polyhedron::add_space_dimensions_and_embed(m):
     2111            adding m new space dimensions exceeds the maximum allowed space dimension.
     2112        """
     2113        self.assert_mutable('The Polyhedron is not mutable!')
     2114        m = int(m)
     2115        try:
     2116            sig_on()
     2117            self.thisptr.add_space_dimensions_and_embed(m)
     2118        finally:
     2119            sig_off()
     2120
     2121
     2122    def add_space_dimensions_and_project(self, m):
     2123        r"""
     2124        Add ``m`` new space dimensions and embed ``self`` in the new
     2125        vector space.
     2126
     2127        The new space dimensions will be those having the highest
     2128        indexes in the new polyhedron, which is characterized by a
     2129        system of constraints in which the variables running through
     2130        the new dimensions are all constrained to be equal to `0`.
     2131        For instance, when starting from the polyhedron `P` and adding
     2132        a third space dimension, the result will be the polyhedron
     2133
     2134        .. MATH::
     2135
     2136            \Big\{
     2137            (x,y,0)^T \in \RR^3
     2138            \Big|
     2139            (x,y)^T \in P
     2140            \Big\}
     2141
     2142        INPUT:
     2143
     2144        - ``m`` -- integer.
     2145
     2146        OUTPUT:
     2147
     2148        This method assigns the projected polyhedron to ``self`` and
     2149        does not return anything.
     2150
     2151        Raises a ``ValueError`` if adding ``m`` new space dimensions
     2152        would cause the vector space to exceed dimension
     2153        ``self.max_space_dimension()``.
     2154
     2155        EXAMPLES::
     2156
     2157            sage: from sage.libs.ppl import Variable, C_Polyhedron, point
     2158            sage: x = Variable(0)
     2159            sage: p = C_Polyhedron( point(3*x) )
     2160            sage: p.add_space_dimensions_and_project(1)
     2161            sage: p.minimized_generators()
     2162            Generator_System {point(3/1, 0/1)}
     2163            sage: p.add_space_dimensions_and_project( p.max_space_dimension() )
     2164            Traceback (most recent call last):
     2165            ...
     2166            ValueError: PPL::C_Polyhedron::add_space_dimensions_and_project(m):
     2167            adding m new space dimensions exceeds the maximum allowed space dimension.
     2168        """
     2169        self.assert_mutable('The Polyhedron is not mutable!')
     2170        m = int(m)
     2171        try:
     2172            sig_on()
     2173            self.thisptr.add_space_dimensions_and_project(m)
     2174        finally:
     2175            sig_off()
     2176
     2177
     2178    def concatenate_assign(self, Polyhedron y):
     2179        r"""
     2180        Assign to ``self`` the concatenation of ``self`` and ``y``.
     2181
     2182        This functions returns the Cartiesian product of ``self`` and
     2183        ``y``.
     2184
     2185        Viewing a polyhedron as a set of tuples (its points), it is
     2186        sometimes useful to consider the set of tuples obtained by
     2187        concatenating an ordered pair of polyhedra. Formally, the
     2188        concatenation of the polyhedra `P` and `Q` (taken in this
     2189        order) is the polyhedron such that
     2190
     2191        .. MATH::
     2192
     2193            R =
     2194            \Big\{
     2195            (x_0,\dots,x_{n-1},y_0,\dots,y_{m-1})^T \in \RR^{n+m}
     2196            \Big|
     2197            (x_0,\dots,x_{n-1})^T \in P
     2198            ,~
     2199            (y_0,\dots,y_{m-1})^T \in Q
     2200            \Big\}
     2201
     2202        Another way of seeing it is as follows: first embed polyhedron
     2203        `P` into a vector space of dimension `n+m` and then add a
     2204        suitably renamed-apart version of the constraints defining
     2205        `Q`.
     2206
     2207        INPUT:
     2208
     2209        - ``m`` -- integer.
     2210
     2211        OUTPUT:
     2212
     2213        This method assigns the concatenated polyhedron to ``self`` and
     2214        does not return anything.
     2215
     2216        Raises a ``ValueError`` if ``self`` and ``y`` are
     2217        topology-incompatible or if adding ``y.space_dimension()`` new
     2218        space dimensions would cause the vector space to exceed
     2219        dimension ``self.max_space_dimension()``.
     2220
     2221        EXAMPLES::
     2222
     2223            sage: from sage.libs.ppl import Variable, C_Polyhedron, NNC_Polyhedron, point
     2224            sage: x = Variable(0)
     2225            sage: p1 = C_Polyhedron( point(1*x) )
     2226            sage: p2 = C_Polyhedron( point(2*x) )
     2227            sage: p1.concatenate_assign(p2)
     2228            sage: p1.minimized_generators()
     2229            Generator_System {point(1/1, 2/1)}
     2230
     2231        The polyhedra must be topology-compatible and not exceed the
     2232        maximum space dimension::
     2233
     2234            sage: p1.concatenate_assign( NNC_Polyhedron(1, 'universe') )
     2235            Traceback (most recent call last):
     2236            ...
     2237            ValueError: PPL::C_Polyhedron::concatenate_assign(y):
     2238            y is a NNC_Polyhedron.
     2239            sage: p1.concatenate_assign( C_Polyhedron(p1.max_space_dimension(), 'empty') )
     2240            Traceback (most recent call last):
     2241            ...
     2242            ValueError: PPL::C_Polyhedron::concatenate_assign(y):
     2243            concatenation exceeds the maximum allowed space dimension.
     2244        """
     2245        self.assert_mutable('The Polyhedron is not mutable!')
     2246        try:
     2247            sig_on()
     2248            self.thisptr.concatenate_assign(y.thisptr[0])
     2249        finally:
     2250            sig_off()
     2251
     2252
     2253    def remove_higher_space_dimensions(self, new_dimension):
     2254        r"""
     2255        Remove the higher dimensions of the vector space so that the
     2256        resulting space will have dimension ``new_dimension``.
     2257
     2258        OUTPUT:
     2259
     2260        This method modifies ``self`` and does not return anything.
     2261
     2262        Raises a ``ValueError`` if ``new_dimensions`` is greater than
     2263        the space dimension of ``self``.
     2264
     2265        EXAMPLES::
     2266
     2267            sage: from sage.libs.ppl import C_Polyhedron, Variable
     2268            sage: x = Variable(0)
     2269            sage: y = Variable(1)
     2270            sage: p = C_Polyhedron(3*x+0*y==2)
     2271            sage: p.remove_higher_space_dimensions(1)
     2272            sage: p.minimized_constraints()
     2273            Constraint_System {3*x0-2==0}
     2274            sage: p.remove_higher_space_dimensions(2)
     2275            Traceback (most recent call last):
     2276            ...
     2277            ValueError: PPL::C_Polyhedron::remove_higher_space_dimensions(nd):
     2278            this->space_dimension() == 1, required space dimension == 2.
     2279        """
     2280        self.assert_mutable('The Polyhedron is not mutable!')
     2281        new_dimension = int(new_dimension)
     2282        try:
     2283            sig_on()
     2284            self.thisptr.remove_higher_space_dimensions(new_dimension)
     2285        finally:
     2286            sig_off()
     2287
     2288
     2289    def ascii_dump(self):
     2290        r"""
     2291        Write an ASCII dump to stderr.
     2292       
     2293        EXAMPLES::
     2294
     2295            sage: sage_cmd  = 'from sage.libs.ppl import C_Polyhedron, Variable\n'
     2296            sage: sage_cmd += 'x = Variable(0)\n'
     2297            sage: sage_cmd += 'y = Variable(1)\n'
     2298            sage: sage_cmd += 'p = C_Polyhedron(3*x+2*y==1)\n'
     2299            sage: sage_cmd += 'p.minimized_generators()\n'
     2300            sage: sage_cmd += 'p.ascii_dump()\n'
     2301            sage: from sage.tests.cmdline import test_executable
     2302            sage: (out, err, ret) = test_executable(['sage', '-c', sage_cmd]);  # indirect doctest
     2303            sage: print err
     2304            space_dim 2
     2305            -ZE -EM  +CM +GM  +CS +GS  -CP -GP  -SC +SG
     2306            con_sys (up-to-date)
     2307            topology NECESSARILY_CLOSED
     2308            2 x 3 (sorted)
     2309            index_first_pending 2
     2310            -1 3 2 =
     2311            1 0 0 >=
     2312            <BLANKLINE>
     2313            gen_sys (up-to-date)
     2314            topology NECESSARILY_CLOSED
     2315            2 x 3 (not_sorted)
     2316            index_first_pending 2
     2317            0 2 -3 L
     2318            2 0 1 P
     2319            <BLANKLINE>
     2320            sat_c
     2321            0 x 0
     2322            <BLANKLINE>           
     2323            sat_g
     2324            2 x 2
     2325            0 0
     2326            0 1
     2327        """
     2328        sig_on()
     2329        self.thisptr.ascii_dump()
     2330        sig_off()
     2331
     2332
     2333    def max_space_dimension(self):
     2334        r"""
     2335        Return the maximum space dimension all kinds of Polyhedron can handle.
     2336
     2337        OUTPUT:
     2338
     2339        Integer.
     2340
     2341        EXAMPLES::
     2342       
     2343            sage: from sage.libs.ppl import C_Polyhedron
     2344            sage: C_Polyhedron(1, 'empty').max_space_dimension()   # random output
     2345            1152921504606846973
     2346            sage: max_dim = C_Polyhedron(1, 'empty').max_space_dimension()
     2347            sage: max_dim in (357913939, 1152921504606846973)  # 32 or 64 bit
     2348            True
     2349        """
     2350        return self.thisptr.max_space_dimension()
     2351
     2352
     2353    def OK(self, check_non_empty=False):
     2354        """
     2355        Check if all the invariants are satisfied.
     2356
     2357        The check is performed so as to intrude as little as
     2358        possible. If the library has been compiled with run-time
     2359        assertions enabled, error messages are written on std::cerr in
     2360        case invariants are violated. This is useful for the purpose
     2361        of debugging the library.
     2362       
     2363        INPUT:
     2364       
     2365        - ``check_not_empty`` -- boolean. ``True`` if and only if, in
     2366          addition to checking the invariants, ``self`` must be
     2367          checked to be not empty.
     2368
     2369        OUTPUT:
     2370       
     2371        ``True`` if and only if ``self`` satisfies all the invariants
     2372        and either ``check_not_empty`` is ``False`` or ``self`` is not
     2373        empty.
     2374
     2375        EXAMPLES::
     2376
     2377            sage: from sage.libs.ppl import Linear_Expression, Variable
     2378            sage: x = Variable(0)
     2379            sage: y = Variable(1)
     2380            sage: e = 3*x+2*y+1
     2381            sage: e.OK()
     2382            True
     2383        """
     2384        sig_on()
     2385        cdef bint result = self.thisptr.OK()
     2386        sig_off()
     2387        return result
     2388
     2389   
     2390    def __richcmp__(Polyhedron lhs, Polyhedron rhs, op):
     2391        r"""
     2392        Comparison for polyhedra.
     2393       
     2394        INPUT:
     2395
     2396        - ``lhs``, ``rhs`` -- :class:`Polyhedron`.
     2397       
     2398        - ``op`` -- integer. The comparison operation to be performed.
     2399
     2400        OUTPUT:
     2401         
     2402        Boolean.
     2403
     2404        EXAMPLES::
     2405
     2406            sage: from sage.libs.ppl import Variable, C_Polyhedron
     2407            sage: x = Variable(0)
     2408            sage: C_Polyhedron(x>=0) > C_Polyhedron(x>=1)    # indirect doctest
     2409            True
     2410        """
     2411        cdef result
     2412        sig_on()
     2413        if op==0:      # <   0
     2414            result = rhs.strictly_contains(lhs)
     2415        elif op==1:    # <=  1
     2416            result = rhs.contains(lhs)
     2417        elif op==2:    # ==  2
     2418            result = (lhs.thisptr[0] == rhs.thisptr[0])
     2419        elif op==4:    # >   4
     2420            result = lhs.strictly_contains(rhs)
     2421        elif op==5:    # >=  5
     2422            result = lhs.contains(rhs)
     2423        elif op==3:    # !=  3
     2424            result = (lhs.thisptr[0] != rhs.thisptr[0])
     2425        else:
     2426            assert False  # unreachable
     2427        sig_off()
     2428        return result
     2429
     2430
     2431####################################################
     2432### C_Polyhedron ###################################
     2433####################################################
     2434cdef class C_Polyhedron(Polyhedron):
     2435    r"""
     2436    Wrapper for PPL's ``C_Polyhedron`` class.
     2437
     2438    An object of the class :class:`C_Polyhedron` represents a
     2439    topologically closed convex polyhedron in the vector space. See
     2440    :class:`NNC_Polyhedron` for more general (not necessarily closed)
     2441    polyhedra.
     2442
     2443    When building a closed polyhedron starting from a system of
     2444    constraints, an exception is thrown if the system contains a
     2445    strict inequality constraint. Similarly, an exception is thrown
     2446    when building a closed polyhedron starting from a system of
     2447    generators containing a closure point.
     2448   
     2449    INPUT:
     2450
     2451    - ``arg`` -- the defining data of the polyhedron. Any one of the
     2452      following is accepted:
     2453   
     2454      * A non-negative integer. Depending on ``degenerate_element``,
     2455        either the space-filling or the empty polytope in the given
     2456        dimension ``arg`` is constructed.
     2457   
     2458      * A :class:`Constraint_System`.
     2459
     2460      * A :class:`Generator_System`.
     2461
     2462      * A single :class:`Constraint`.
     2463
     2464      * A single :class:`Generator`.
     2465
     2466      * A :class:`C_Polyhedron`.
     2467
     2468    - ``degenerate_element`` -- string, either ``'universe'`` or
     2469      ``'empty'``. Only used if ``arg`` is an integer.
     2470
     2471    OUTPUT:
     2472
     2473    A :class:`C_Polyhedron`.
     2474
     2475    EXAMPLES::
     2476
     2477        sage: from sage.libs.ppl import Constraint, Constraint_System, Generator, Generator_System, Variable, C_Polyhedron, point, ray
     2478        sage: x = Variable(0)
     2479        sage: y = Variable(1)
     2480        sage: C_Polyhedron( 5*x-2*y >=  x+y-1 )
     2481        A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point, 1 ray, 1 line.
     2482        sage: cs = Constraint_System()
     2483        sage: cs.insert( x >= 0 )
     2484        sage: cs.insert( y >= 0 )
     2485        sage: C_Polyhedron(cs)
     2486        A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point, 2 rays.
     2487        sage: C_Polyhedron( point(x+y) )
     2488        A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point.
     2489        sage: gs = Generator_System()
     2490        sage: gs.insert( point(-x-y) )
     2491        sage: gs.insert( ray(x) )
     2492        sage: C_Polyhedron(gs)
     2493        A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point, 1 ray.
     2494       
     2495    The empty and universe polyhedra are constructed like this::
     2496
     2497        sage: C_Polyhedron(3, 'empty')
     2498        The empty polyhedron in QQ^3.
     2499        sage: C_Polyhedron(3, 'empty').constraints()
     2500        Constraint_System {-1==0}
     2501        sage: C_Polyhedron(3, 'universe')
     2502        The space-filling polyhedron in QQ^3.
     2503        sage: C_Polyhedron(3, 'universe').constraints()
     2504        Constraint_System {}
     2505
     2506    Note that, by convention, the generator system of a polyhedron is
     2507    either empty or contains at least one point. In particular, if you
     2508    define a polyhedron via a non-empty :class:`Generator_System` it
     2509    must contain a point (at any position). If you start with a single
     2510    generator, this generator must be a point::
     2511
     2512        sage: C_Polyhedron( ray(x) )
     2513        Traceback (most recent call last):
     2514        ...
     2515        ValueError: PPL::C_Polyhedron::C_Polyhedron(gs):
     2516        *this is an empty polyhedron and
     2517        the non-empty generator system gs contains no points.
     2518    """
     2519
     2520
     2521    def __cinit__(self, arg, degenerate_element='universe'):
     2522        """
     2523        The Cython constructor.
     2524       
     2525        See :class:`C_Polyhedron` for documentation.
     2526
     2527        TESTS::
     2528         
     2529            sage: from sage.libs.ppl import C_Polyhedron
     2530            sage: C_Polyhedron(3, 'empty')   # indirect doctest
     2531            The empty polyhedron in QQ^3.
     2532        """
     2533        if PY_TYPE_CHECK(arg, C_Polyhedron):
     2534            ph = <C_Polyhedron>arg
     2535            self.thisptr = new PPL_C_Polyhedron(<PPL_C_Polyhedron&>ph.thisptr[0])
     2536            return
     2537        if PY_TYPE_CHECK(arg, Generator):
     2538            arg = Generator_System(arg)
     2539        if PY_TYPE_CHECK(arg, Constraint):
     2540            arg = Constraint_System(arg)
     2541        if PY_TYPE_CHECK(arg, Generator_System):
     2542            gs = <Generator_System>arg
     2543            self.thisptr = new PPL_C_Polyhedron(gs.thisptr[0])
     2544            return
     2545        if PY_TYPE_CHECK(arg, Constraint_System):
     2546            cs = <Constraint_System>arg
     2547            self.thisptr = new PPL_C_Polyhedron(cs.thisptr[0])
     2548            return
     2549        try:
     2550            dim = int(arg)
     2551            assert dim>=0
     2552        except ValueError:
     2553            raise ValueError, 'Cannot initialize C_Polyhedron with '+str(arg)+'.'
     2554        degenerate_element = degenerate_element.lower()
     2555        if degenerate_element=='universe':
     2556            self.thisptr = new PPL_C_Polyhedron(<PPL_dimension_type>dim, UNIVERSE)
     2557            return
     2558        elif degenerate_element=='empty':
     2559            self.thisptr = new PPL_C_Polyhedron(<PPL_dimension_type>dim, EMPTY)
     2560            return
     2561        else:
     2562            raise ValueError, 'Unknown value: degenerate_element='+str(degenerate_element)+'.'
     2563
     2564
     2565    def __init__(self, *args):
     2566        """
     2567        The Python destructor.
     2568
     2569        See :class:`C_Polyhedron` for documentation.
     2570
     2571        TESTS::
     2572         
     2573            sage: from sage.libs.ppl import C_Polyhedron
     2574            sage: C_Polyhedron(3, 'empty')   # indirect doctest
     2575            The empty polyhedron in QQ^3.
     2576        """
     2577        # override Polyhedron.__init__
     2578        pass
     2579
     2580
     2581    def __dealloc__(self):
     2582        """
     2583        The Cython destructor.
     2584        """
     2585        del self.thisptr
     2586
     2587       
     2588
     2589
     2590####################################################
     2591### NNC_Polyhedron #################################
     2592####################################################
     2593cdef class NNC_Polyhedron(Polyhedron):
     2594    r"""
     2595    Wrapper for PPL's ``NNC_Polyhedron`` class.
     2596
     2597    An object of the class ``NNC_Polyhedron`` represents a not
     2598    necessarily closed (NNC) convex polyhedron in the vector space.
     2599
     2600    Note: Since NNC polyhedra are a generalization of closed
     2601    polyhedra, any object of the class :class:`C_Polyhedron` can be
     2602    (explicitly) converted into an object of the class
     2603    :class:`NNC_Polyhedron`. The reason for defining two different
     2604    classes is that objects of the class :class:`C_Polyhedron` are
     2605    characterized by a more efficient implementation, requiring less
     2606    time and memory resources.
     2607
     2608    INPUT:
     2609
     2610    - ``arg`` -- the defining data of the polyhedron. Any one of the
     2611      following is accepted:
     2612   
     2613      * An non-negative integer. Depending on ``degenerate_element``,
     2614        either the space-filling or the empty polytope in the given
     2615        dimension ``arg`` is constructed.
     2616   
     2617      * A :class:`Constraint_System`.
     2618
     2619      * A :class:`Generator_System`.
     2620
     2621      * A single :class:`Constraint`.
     2622
     2623      * A single :class:`Generator`.
     2624
     2625      * A :class:`NNC_Polyhedron`.
     2626
     2627      * A :class:`C_Polyhedron`.
     2628
     2629    - ``degenerate_element`` -- string, either ``'universe'`` or
     2630      ``'empty'``. Only used if ``arg`` is an integer.
     2631
     2632    OUTPUT:
     2633
     2634    A :class:`C_Polyhedron`.
     2635
     2636    EXAMPLES::
     2637
     2638        sage: from sage.libs.ppl import Constraint, Constraint_System, Generator, Generator_System, Variable, NNC_Polyhedron, point, ray, closure_point
     2639        sage: x = Variable(0)
     2640        sage: y = Variable(1)
     2641        sage: NNC_Polyhedron( 5*x-2*y >  x+y-1 )
     2642        A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point, 1 closure_point, 1 ray, 1 line.
     2643        sage: cs = Constraint_System()
     2644        sage: cs.insert( x > 0 )
     2645        sage: cs.insert( y > 0 )
     2646        sage: NNC_Polyhedron(cs)
     2647        A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point, 1 closure_point, 2 rays.
     2648        sage: NNC_Polyhedron( point(x+y) )
     2649        A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point.
     2650        sage: gs = Generator_System()
     2651        sage: gs.insert( point(-y) )
     2652        sage: gs.insert( closure_point(-x-y) )
     2653        sage: gs.insert( ray(x) )
     2654        sage: p = NNC_Polyhedron(gs); p
     2655        A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point, 1 closure_point, 1 ray.
     2656        sage: p.minimized_constraints()
     2657        Constraint_System {x1+1==0, x0+1>0}
     2658
     2659    Note that, by convention, every polyhedron must contain a point::
     2660
     2661        sage: NNC_Polyhedron( closure_point(x+y) )
     2662        Traceback (most recent call last):
     2663        ...
     2664        ValueError: PPL::NNC_Polyhedron::NNC_Polyhedron(gs):
     2665        *this is an empty polyhedron and
     2666        the non-empty generator system gs contains no points.
     2667    """
     2668
     2669
     2670    def __cinit__(self, arg, degenerate_element='universe'):
     2671        """
     2672        The Cython constructor.
     2673       
     2674        See :class:`NNC_Polyhedron` for documentation.
     2675
     2676        TESTS::
     2677         
     2678            sage: from sage.libs.ppl import NNC_Polyhedron
     2679            sage: NNC_Polyhedron(3, 'empty')   # indirect doctest
     2680            The empty polyhedron in QQ^3.
     2681        """
     2682        if PY_TYPE_CHECK(arg, NNC_Polyhedron):
     2683            p_nnc = <NNC_Polyhedron>arg
     2684            self.thisptr = new PPL_NNC_Polyhedron(<PPL_NNC_Polyhedron&>p_nnc.thisptr[0])
     2685            return
     2686        if PY_TYPE_CHECK(arg, C_Polyhedron):
     2687            p_c = <C_Polyhedron>arg
     2688            self.thisptr = new PPL_NNC_Polyhedron(<PPL_C_Polyhedron&>p_c.thisptr[0])
     2689            return
     2690        if PY_TYPE_CHECK(arg, Generator):
     2691            arg = Generator_System(arg)
     2692        if PY_TYPE_CHECK(arg, Constraint):
     2693            arg = Constraint_System(arg)
     2694        if PY_TYPE_CHECK(arg, Generator_System):
     2695            gs = <Generator_System>arg
     2696            self.thisptr = new PPL_NNC_Polyhedron(gs.thisptr[0])
     2697            return
     2698        if PY_TYPE_CHECK(arg, Constraint_System):
     2699            cs = <Constraint_System>arg
     2700            self.thisptr = new PPL_NNC_Polyhedron(cs.thisptr[0])
     2701            return
     2702        try:
     2703            dim = int(arg)
     2704            assert dim>=0
     2705        except ValueError:
     2706            raise ValueError, 'Cannot initialize NNC_Polyhedron with '+str(arg)+'.'
     2707        degenerate_element = degenerate_element.lower()
     2708        if degenerate_element=='universe':
     2709            self.thisptr = new PPL_NNC_Polyhedron(<PPL_dimension_type>dim, UNIVERSE)
     2710            return
     2711        elif degenerate_element=='empty':
     2712            self.thisptr = new PPL_NNC_Polyhedron(<PPL_dimension_type>dim, EMPTY)
     2713            return
     2714        else:
     2715            raise ValueError, 'Unknown value: degenerate_element='+str(degenerate_element)+'.'
     2716
     2717
     2718    def __init__(self, *args):
     2719        """
     2720        The Python destructor.
     2721
     2722        See :class:`NNC_Polyhedron` for documentation.
     2723
     2724        TESTS::
     2725         
     2726            sage: from sage.libs.ppl import NNC_Polyhedron
     2727            sage: NNC_Polyhedron(3, 'empty')   # indirect doctest
     2728            The empty polyhedron in QQ^3.
     2729        """
     2730        # override Polyhedron.__init__
     2731        pass
     2732
     2733
     2734    def __dealloc__(self):
     2735        """
     2736        The Cython destructor.
     2737        """
     2738        del self.thisptr
     2739
     2740
     2741
     2742####################################################
     2743### Variable #######################################
     2744####################################################
     2745cdef class Variable(object):
     2746    r"""
     2747    Wrapper for PPL's ``Variable`` class.
     2748
     2749    A dimension of the vector space.
     2750
     2751    An object of the class Variable represents a dimension of the
     2752    space, that is one of the Cartesian axes. Variables are used as
     2753    basic blocks in order to build more complex linear
     2754    expressions. Each variable is identified by a non-negative
     2755    integer, representing the index of the corresponding Cartesian
     2756    axis (the first axis has index 0). The space dimension of a
     2757    variable is the dimension of the vector space made by all the
     2758    Cartesian axes having an index less than or equal to that of the
     2759    considered variable; thus, if a variable has index `i`, its space
     2760    dimension is `i+1`.
     2761
     2762    INPUT:
     2763
     2764    - ``i`` -- integer. The index of the axis.
     2765
     2766    OUTPUT:
     2767
     2768    A :class:`Variable`
     2769
     2770    EXAMPLES::
     2771
     2772        sage: from sage.libs.ppl import Variable
     2773        sage: x = Variable(123)
     2774        sage: x.id()
     2775        123
     2776        sage: x
     2777        x123
     2778
     2779    Note that the "meaning" of an object of the class Variable is
     2780    completely specified by the integer index provided to its
     2781    constructor: be careful not to be mislead by C++ language variable
     2782    names. For instance, in the following example the linear
     2783    expressions ``e1`` and ``e2`` are equivalent, since the two
     2784    variables ``x`` and ``z`` denote the same Cartesian axis::
     2785
     2786        sage: x = Variable(0)
     2787        sage: y = Variable(1)
     2788        sage: z = Variable(0)
     2789        sage: e1 = x + y; e1
     2790        x0+x1
     2791        sage: e2 = y + z; e2
     2792        x0+x1
     2793        sage: e1 - e2
     2794        0
     2795    """   
     2796
     2797    cdef PPL_Variable *thisptr
     2798
     2799     
     2800    def __cinit__(self, PPL_dimension_type i):
     2801        """
     2802        The Cython constructor.
     2803       
     2804        See :class:`Variable` for documentation.
     2805
     2806        TESTS::
     2807
     2808            sage: from sage.libs.ppl import Variable
     2809            sage: Variable(123)   # indirect doctest
     2810            x123
     2811        """
     2812        self.thisptr = new PPL_Variable(i)
     2813
     2814
     2815    def __dealloc__(self):
     2816        """
     2817        The Cython destructor.
     2818        """
     2819        del self.thisptr
     2820
     2821
     2822    def id(self):
     2823        """
     2824        Return the index of the Cartesian axis associated to the variable.
     2825
     2826        EXAMPLES::
     2827
     2828            sage: from sage.libs.ppl import Variable
     2829            sage: x = Variable(123)
     2830            sage: x.id()
     2831            123
     2832        """
     2833        return self.thisptr.id()
     2834
     2835
     2836    def OK(self):
     2837        """
     2838        Checks if all the invariants are satisfied.
     2839       
     2840        OUTPUT:
     2841       
     2842        Boolean.
     2843
     2844        EXAMPLES::
     2845
     2846            sage: from sage.libs.ppl import Variable
     2847            sage: x = Variable(0)
     2848            sage: x.OK()
     2849            True
     2850        """
     2851        return self.thisptr.OK()
     2852
     2853
     2854    def space_dimension(self):
     2855        r"""
     2856        Return the dimension of the vector space enclosing ``self``.
     2857       
     2858        OUPUT:
     2859       
     2860        Integer. The returned value is ``self.id()+1``.
     2861
     2862        EXAMPLES::
     2863
     2864            sage: from sage.libs.ppl import Variable
     2865            sage: x = Variable(0)
     2866            sage: x.space_dimension()
     2867            1
     2868        """
     2869        return self.thisptr.space_dimension()
     2870       
     2871
     2872    def __repr__(self):
     2873        """
     2874        Return a string representation.
     2875
     2876        OUTPUT:
     2877
     2878        String.
     2879
     2880        EXAMPLES::
     2881
     2882            sage: from sage.libs.ppl import Variable
     2883            sage: x = Variable(0)
     2884            sage: x.__repr__()
     2885            'x0'
     2886        """
     2887        return 'x{0}'.format(self.id())
     2888
     2889
     2890    def __add__(self, other):
     2891        r"""
     2892        Return the sum ``self`` + ``other``.
     2893
     2894        INPUT:
     2895
     2896        - ``self``, ``other`` -- anything convertible to
     2897          ``Linear_Expression``: An integer, a :class:`Variable`, or a
     2898          :class:`Linear_Expression`.
     2899
     2900        OUTPUT:
     2901
     2902        A :class:`Linear_Expression` representing ``self`` + ``other``.
     2903       
     2904        EXAMPLES::
     2905       
     2906            sage: from sage.libs.ppl import Variable
     2907            sage: x = Variable(0); y = Variable(1)
     2908            sage: x + 15
     2909            x0+15
     2910            sage: 15 + y
     2911            x1+15
     2912        """
     2913        return Linear_Expression(self)+Linear_Expression(other)
     2914   
     2915
     2916    def __sub__(self, other):
     2917        r"""
     2918        Return the difference ``self`` - ``other``.
     2919
     2920        INPUT:
     2921
     2922        - ``self``, ``other`` -- anything convertible to
     2923          ``Linear_Expression``: An integer, a :class:`Variable`, or a
     2924          :class:`Linear_Expression`.
     2925
     2926        OUTPUT:
     2927
     2928        A :class:`Linear_Expression` representing ``self`` - ``other``.
     2929       
     2930        EXAMPLES::
     2931       
     2932            sage: from sage.libs.ppl import Variable
     2933            sage: x = Variable(0); y = Variable(1)
     2934            sage: x - 15
     2935            x0-15
     2936            sage: 15 - y
     2937            -x1+15
     2938        """
     2939        return Linear_Expression(self)-Linear_Expression(other)
     2940   
     2941
     2942    def __mul__(self, other):
     2943        r"""
     2944        Return the product ``self`` * ``other``.
     2945
     2946        INPUT:
     2947
     2948        - ``self``, ``other`` -- One must be an integer, the other a
     2949          :class:`Variable`.
     2950
     2951        OUTPUT:
     2952
     2953        A :class:`Linear_Expression` representing ``self`` * ``other``.
     2954       
     2955        EXAMPLES::
     2956       
     2957            sage: from sage.libs.ppl import Variable
     2958            sage: x = Variable(0); y = Variable(1)
     2959            sage: x * 15
     2960            15*x0
     2961            sage: 15 * y
     2962            15*x1
     2963        """
     2964        if PY_TYPE_CHECK(self, Variable):
     2965            return Linear_Expression(self) * other
     2966        else:
     2967            return Linear_Expression(other) * self
     2968
     2969
     2970    def __pos__(self):
     2971        r"""
     2972        Return ``self`` as :class:`Linear_Expression`
     2973
     2974        OUTPUT:
     2975
     2976        The :class:`Linear_Expression` ``+self``
     2977
     2978        EXAMPLES::
     2979
     2980            sage: from sage.libs.ppl import Variable
     2981            sage: x = Variable(0); x
     2982            x0
     2983            sage: +x
     2984            x0
     2985        """
     2986        return Linear_Expression(self)
     2987
     2988
     2989    def __neg__(self):
     2990        r"""
     2991        Return -``self`` as :class:`Linear_Expression`
     2992
     2993        OUTPUT:
     2994
     2995        The :class:`Linear_Expression` ``-self``
     2996
     2997        EXAMPLES::
     2998
     2999            sage: from sage.libs.ppl import Variable
     3000            sage: x = Variable(0); x
     3001            x0
     3002            sage: -x
     3003            -x0
     3004        """
     3005        return Linear_Expression(self)*(-1)
     3006
     3007   
     3008    def __richcmp__(self, other, op):
     3009        """
     3010        Construct :class:`Constraint` from equalities or inequalities.
     3011
     3012        INPUT:
     3013
     3014        - ``self``, ``other`` -- anything convertible to a
     3015          :class:`Linear_Expression`
     3016
     3017        - ``op`` -- the operation.
     3018
     3019        EXAMPLES::
     3020       
     3021            sage: from sage.libs.ppl import Variable
     3022            sage: x = Variable(0)
     3023            sage: y = Variable(1)
     3024            sage: x <  y
     3025            -x0+x1>0
     3026            sage: x <= 0
     3027            -x0>=0
     3028            sage: x == y-y
     3029            x0==0
     3030            sage: x >= -2
     3031            x0+2>=0
     3032            sage: x >  0
     3033            x0>0
     3034            sage: 0 == 1    # watch out!
     3035            False
     3036            sage: 0*x == 1
     3037            -1==0
     3038        """
     3039        return _make_Constraint_from_richcmp(self, other, op)
     3040
     3041
     3042####################################################
     3043### Linear_Expression ##############################
     3044####################################################
     3045cdef class Linear_Expression(object):
     3046    r"""
     3047    Wrapper for PPL's ``PPL_Linear_Expression`` class.
     3048
     3049    INPUT:
     3050
     3051    The constructor accepts zero, one, or two arguments.
     3052
     3053    If there are two arguments ``Linear_Expression(a,b)``, they are
     3054    interpreted as
     3055
     3056    - ``a`` -- an iterable of integer coefficients, for example a
     3057      list.
     3058
     3059    - ``b`` -- an integer. The inhomogeneous term.
     3060
     3061    A single argument ``Linear_Expression(arg)`` is interpreted as
     3062
     3063    - ``arg`` -- something that determines a linear
     3064      expression. Possibilities are:
     3065
     3066      * a :class:`Variable`: The linear expression given by that
     3067        variable.
     3068
     3069      * a :class:`Linear_Expression`: The copy constructor.
     3070
     3071      * an integer: Constructs the constant linear expression.
     3072
     3073    No argument is the default constructor and returns the zero linear
     3074    expression.
     3075       
     3076    OUTPUT:
     3077
     3078    A :class:`Linear_Expression`
     3079
     3080    EXAMPLES::
     3081
     3082        sage: from sage.libs.ppl import Variable, Linear_Expression
     3083        sage: Linear_Expression([1,2,3,4],5)
     3084        x0+2*x1+3*x2+4*x3+5
     3085        sage: Linear_Expression(10)
     3086        10
     3087        sage: Linear_Expression()
     3088        0
     3089        sage: Linear_Expression(10).inhomogeneous_term()
     3090        10
     3091        sage: x = Variable(123)
     3092        sage: expr = x+1; expr
     3093        x123+1
     3094        sage: expr.OK()
     3095        True
     3096        sage: expr.coefficient(x)
     3097        1
     3098        sage: expr.coefficient( Variable(124) )
     3099        0
     3100    """   
     3101
     3102    cdef PPL_Linear_Expression *thisptr
     3103
     3104
     3105    def __cinit__(self, *args):
     3106        """
     3107        The Cython constructor.
     3108       
     3109        See :class:`Linear_Expression` for documentation.
     3110
     3111        TESTS::
     3112       
     3113            sage: from sage.libs.ppl import Linear_Expression
     3114            sage: Linear_Expression(10)   # indirect doctest
     3115            10
     3116        """
     3117        if len(args)==2:
     3118            a = args[0]
     3119            b = args[1]
     3120            ex = Linear_Expression(0)
     3121            for i in range(0,len(a)):
     3122                ex = ex + Variable(i).__mul__(Integer(a[i]))
     3123            arg = ex + b
     3124        elif len(args)==1:
     3125            arg = args[0]
     3126        elif len(args)==0:
     3127            self.thisptr = new PPL_Linear_Expression()
     3128            return
     3129        else:
     3130            assert False, 'Cannot initialize with more than 2 arguments.'
     3131
     3132        if PY_TYPE_CHECK(arg, Variable):
     3133            v = <Variable>arg
     3134            self.thisptr = new PPL_Linear_Expression(v.thisptr[0])
     3135            return
     3136        if PY_TYPE_CHECK(arg, Linear_Expression):
     3137            e = <Linear_Expression>arg
     3138            self.thisptr = new PPL_Linear_Expression(e.thisptr[0])
     3139            return
     3140        try:
     3141            c = Integer(arg)
     3142            self.thisptr = new PPL_Linear_Expression(PPL_Coefficient(c.value))
     3143            return
     3144        except ValueError:
     3145            raise ValueError, 'Cannot initialize with '+str(args)+'.'
     3146
     3147
     3148    def __dealloc__(self):
     3149        """
     3150        The Cython destructor.
     3151        """
     3152        del self.thisptr
     3153
     3154
     3155    def space_dimension(self):
     3156        """
     3157        Return the dimension of the vector space necessary for the
     3158        linear expression.
     3159
     3160        OUTPUT:
     3161
     3162        Integer.
     3163
     3164        EXAMPLES::
     3165
     3166            sage: from sage.libs.ppl import Variable
     3167            sage: x = Variable(0)
     3168            sage: y = Variable(1)
     3169            sage: ( x+y+1 ).space_dimension()
     3170            2
     3171            sage: ( x+y   ).space_dimension()
     3172            2
     3173            sage: (   y+1 ).space_dimension()
     3174            2
     3175            sage: ( x  +1 ).space_dimension()
     3176            1
     3177            sage: ( y+1-y ).space_dimension()
     3178            2
     3179        """
     3180        return self.thisptr.space_dimension()
     3181
     3182       
     3183    def coefficient(self, Variable v):
     3184        """
     3185        Return the coefficient of the variable ``v``.
     3186
     3187        INPUT:
     3188       
     3189        - ``v`` -- a :class:`Variable`.
     3190
     3191        OUTPUT:
     3192       
     3193        An integer.
     3194
     3195        EXAMPLES::
     3196
     3197            sage: from sage.libs.ppl import Variable
     3198            sage: x = Variable(0)
     3199            sage: e = 3*x+1
     3200            sage: e.coefficient(x)
     3201            3
     3202        """
     3203        cdef Integer c = Integer(0)
     3204        mpz_set(c.value, self.thisptr.coefficient(v.thisptr[0]).get_mpz_t())
     3205        return c
     3206
     3207
     3208    def coefficients(self):
     3209        """
     3210        Return the coefficients of the linear expression.
     3211
     3212        OUTPUT:
     3213       
     3214        A tuple of integers of length :meth:`space_dimension`.
     3215
     3216        EXAMPLES::
     3217
     3218            sage: from sage.libs.ppl import Variable
     3219            sage: x = Variable(0);  y = Variable(1)
     3220            sage: e = 3*x+5*y+1
     3221            sage: e.coefficients()
     3222            (3, 5)
     3223        """
     3224        cdef int d = self.space_dimension()
     3225        cdef int i
     3226        cdef Integer c = Integer(0)
     3227        coeffs = []
     3228        for i in range(0,d):
     3229            mpz_set(c.value, self.thisptr.coefficient(PPL_Variable(i)).get_mpz_t())
     3230            coeffs.append(Integer(c))
     3231        return tuple(coeffs)
     3232
     3233
     3234    def inhomogeneous_term(self):
     3235        """
     3236        Return the inhomogeneous term of the linear expression.
     3237
     3238        OUTPUT:
     3239       
     3240        Integer.
     3241
     3242        EXAMPLES::
     3243
     3244            sage: from sage.libs.ppl import Variable, Linear_Expression
     3245            sage: Linear_Expression(10).inhomogeneous_term()
     3246            10
     3247        """
     3248        cdef Integer c = Integer(0)
     3249        mpz_set(c.value, self.thisptr.inhomogeneous_term().get_mpz_t())
     3250        return c
     3251
     3252
     3253    def is_zero(self):
     3254        """
     3255        Test if ``self`` is the zero linear expression.
     3256
     3257        OUTPUT:
     3258       
     3259        Boolean.
     3260
     3261        EXAMPLES::
     3262
     3263            sage: from sage.libs.ppl import Variable, Linear_Expression
     3264            sage: Linear_Expression(0).is_zero()
     3265            True
     3266            sage: Linear_Expression(10).is_zero()
     3267            False
     3268        """
     3269        return self.thisptr.is_zero()
     3270
     3271
     3272    def all_homogeneous_terms_are_zero(self):
     3273        """
     3274        Test if ``self`` is a constant linear expression.
     3275
     3276        OUTPUT:
     3277       
     3278        Boolean.
     3279
     3280        EXAMPLES::
     3281
     3282            sage: from sage.libs.ppl import Variable, Linear_Expression
     3283            sage: Linear_Expression(10).all_homogeneous_terms_are_zero()
     3284            True
     3285        """
     3286        return self.thisptr.all_homogeneous_terms_are_zero()
     3287
     3288
     3289    def ascii_dump(self):
     3290        r"""
     3291        Write an ASCII dump to stderr.
     3292       
     3293        EXAMPLES::
     3294
     3295            sage: sage_cmd  = 'from sage.libs.ppl import Linear_Expression, Variable\n'
     3296            sage: sage_cmd += 'x = Variable(0)\n'
     3297            sage: sage_cmd += 'y = Variable(1)\n'
     3298            sage: sage_cmd += 'e = 3*x+2*y+1\n'
     3299            sage: sage_cmd += 'e.ascii_dump()\n'
     3300            sage: from sage.tests.cmdline import test_executable
     3301            sage: (out, err, ret) = test_executable(['sage', '-c', sage_cmd]);  # indirect doctest
     3302            sage: print err
     3303            size 3 1 3 2 f -RPI_V -RPI  -NNC_V -NNC
     3304        """
     3305        self.thisptr.ascii_dump()
     3306
     3307
     3308    def OK(self):
     3309        """
     3310        Check if all the invariants are satisfied.
     3311
     3312        EXAMPLES::
     3313
     3314            sage: from sage.libs.ppl import Linear_Expression, Variable
     3315            sage: x = Variable(0)
     3316            sage: y = Variable(1)
     3317            sage: e = 3*x+2*y+1
     3318            sage: e.OK()
     3319            True
     3320        """
     3321        return self.thisptr.OK()
     3322
     3323
     3324    def __repr__(self):
     3325        r"""
     3326        Return a string representation of the linear expression.
     3327       
     3328        OUTPUT:
     3329
     3330        A string.
     3331
     3332        EXAMPLES::
     3333
     3334            sage: from sage.libs.ppl import Linear_Expression, Variable
     3335            sage: x = Variable(0)
     3336            sage: y = Variable(1)
     3337            sage: x+1
     3338            x0+1
     3339            sage: x+1-x
     3340            1
     3341            sage: 2*x
     3342            2*x0
     3343            sage: x-x-1
     3344            -1
     3345            sage: x-x
     3346            0
     3347        """
     3348        s = ''
     3349        first = True
     3350        for i in range(0,self.space_dimension()):
     3351            x = Variable(i)
     3352            coeff = self.coefficient(x)
     3353            if coeff==0: continue
     3354            if first and coeff==1:
     3355                s += '%r' % x
     3356                first = False
     3357            elif first and coeff==-1:
     3358                s += '-%r' % x
     3359                first = False
     3360            elif first and coeff!=1:
     3361                s += '%d*%r' % (coeff, x)
     3362                first = False
     3363            elif coeff==1:
     3364                s += '+%r' % x
     3365            elif coeff==-1:
     3366                s += '-%r' % x
     3367            else:
     3368                s += '%+d*%r' % (coeff, x)
     3369        inhomog = self.inhomogeneous_term()
     3370        if inhomog!=0:
     3371            if first:
     3372                s += '%d' % inhomog
     3373                first = False
     3374            else:
     3375                s += '%+d' % inhomog
     3376        if first:
     3377            s = '0'
     3378        return s
     3379
     3380
     3381    def __add__(self, other):
     3382        r"""
     3383        Add ``self`` and ``other``.
     3384
     3385        INPUT:
     3386
     3387        - ``self``, ``other`` -- anything that can be used to
     3388          construct a :class:`Linear_Expression`. One of them, not
     3389          necessarily ``self``, is guaranteed to be a
     3390          :class:``Linear_Expression``, otherwise Python would not
     3391          have called this method.
     3392
     3393        OUTPUT:
     3394
     3395        The sum as a :class:`Linear_Expression`
     3396
     3397        EXAMPLES::
     3398
     3399            sage: from sage.libs.ppl import Linear_Expression, Variable
     3400            sage: x = Variable(0)
     3401            sage: y = Variable(1)
     3402            sage: 9+x+y+(1+x)+y+y
     3403            2*x0+3*x1+10
     3404        """
     3405        cdef Linear_Expression lhs = Linear_Expression(self)
     3406        cdef Linear_Expression rhs = Linear_Expression(other)
     3407        cdef Linear_Expression result = Linear_Expression()
     3408        result.thisptr[0] = lhs.thisptr[0] + rhs.thisptr[0]
     3409        return result
     3410
     3411
     3412    def __sub__(self, other):
     3413        r"""
     3414        Subtract ``other`` from ``self``.
     3415
     3416        INPUT:
     3417
     3418        - ``self``, ``other`` -- anything that can be used to
     3419          construct a :class:`Linear_Expression`. One of them, not
     3420          necessarily ``self``, is guaranteed to be a
     3421          :class:``Linear_Expression``, otherwise Python would not
     3422          have called this method.
     3423
     3424        OUTPUT:
     3425
     3426        The difference as a :class:`Linear_Expression`
     3427
     3428        EXAMPLES::
     3429
     3430            sage: from sage.libs.ppl import Linear_Expression, Variable
     3431            sage: x = Variable(0)
     3432            sage: y = Variable(1)
     3433            sage: 9-x-y-(1-x)-y-y
     3434            -3*x1+8
     3435        """
     3436        cdef Linear_Expression lhs = Linear_Expression(self)
     3437        cdef Linear_Expression rhs = Linear_Expression(other)
     3438        cdef Linear_Expression result = Linear_Expression()
     3439        result.thisptr[0] = lhs.thisptr[0] - rhs.thisptr[0]
     3440        return result
     3441
     3442
     3443    def __mul__(self, other):
     3444        r"""
     3445        Multiply ``self`` with ``other``.
     3446
     3447        INPUT:
     3448
     3449        - ``self``, ``other`` -- anything that can be used to
     3450          construct a :class:`Linear_Expression`. One of them, not
     3451          necessarily ``self``, is guaranteed to be a
     3452          :class:``Linear_Expression``, otherwise Python would not
     3453          have called this method.
     3454
     3455        OUTPUT:
     3456
     3457        The product as a :class:`Linear_Expression`
     3458
     3459        EXAMPLES::
     3460
     3461            sage: from sage.libs.ppl import Linear_Expression, Variable
     3462            sage: x = Variable(0)
     3463            sage: y = Variable(1)
     3464            sage: 8*(x+1)
     3465            8*x0+8
     3466            sage: y*8
     3467            8*x1
     3468        """
     3469        cdef Linear_Expression e
     3470        cdef Integer c
     3471        if PY_TYPE_CHECK(self, Linear_Expression):
     3472            e = <Linear_Expression>self
     3473            c = Integer(other)
     3474        else:
     3475            e = <Linear_Expression>other
     3476            c = Integer(self)
     3477
     3478        cdef Linear_Expression result = Linear_Expression()
     3479        result.thisptr[0] = e.thisptr[0] * PPL_Coefficient(c.value)
     3480        return result
     3481
     3482
     3483    def __pos__(self):
     3484        """
     3485        Return ``self``.
     3486
     3487        EXAMPLES::
     3488       
     3489            sage: from sage.libs.ppl import Variable, Linear_Expression
     3490            sage: +Linear_Expression(1)
     3491            1
     3492            sage: x = Variable(0)
     3493            sage: +(x+1)
     3494            x0+1
     3495        """
     3496        return self
     3497
     3498
     3499    def __neg__(self):
     3500        """
     3501        Return the negative of ``self``.
     3502
     3503        EXAMPLES::
     3504       
     3505            sage: from sage.libs.ppl import Variable, Linear_Expression
     3506            sage: -Linear_Expression(1)
     3507            -1
     3508            sage: x = Variable(0)
     3509            sage: -(x+1)
     3510            -x0-1           
     3511        """
     3512        return self*(-1)
     3513
     3514
     3515    def __richcmp__(self, other, int op):
     3516        """
     3517        Construct :class:`Constraint`s
     3518
     3519        EXAMPLES::
     3520       
     3521            sage: from sage.libs.ppl import Variable
     3522            sage: x = Variable(0)
     3523            sage: y = Variable(1)
     3524            sage: x+1 <  y-2
     3525            -x0+x1-3>0
     3526            sage: x+1 <= y-2
     3527            -x0+x1-3>=0
     3528            sage: x+1 == y-2
     3529            x0-x1+3==0
     3530            sage: x+1 >= y-2
     3531            x0-x1+3>=0
     3532            sage: x+1 >  y-2
     3533            x0-x1+3>0
     3534        """
     3535        return _make_Constraint_from_richcmp(self, other, op)
     3536
     3537
     3538####################################################
     3539### Generator ######################################
     3540####################################################
     3541cdef _wrap_Generator(PPL_Generator generator):
     3542    """
     3543    Wrap a C++ ``PPL_Generator`` into a Cython ``Generator``.
     3544    """
     3545    cdef Generator g = Generator(True)
     3546    g.thisptr = new PPL_Generator(generator)
     3547    return g
     3548
     3549
     3550####################################################
     3551# C++ static methods not supported
     3552# Note that the PPL_Generator default constructor is private, hence we must return pointers
     3553cdef extern from "ppl_shim.hh":
     3554    PPL_Generator* new_line(PPL_Linear_Expression &e) except +ValueError
     3555    PPL_Generator* new_ray(PPL_Linear_Expression &e) except +ValueError
     3556    PPL_Generator* new_point(PPL_Linear_Expression &e, PPL_Coefficient d) except +ValueError
     3557    PPL_Generator* new_closure_point(PPL_Linear_Expression &e, PPL_Coefficient d) except +ValueError
     3558
     3559
     3560####################################################
     3561cdef class Generator(object):
     3562    r"""
     3563    Wrapper for PPL's ``Generator`` class.
     3564   
     3565    An object of the class Generator is one of the following:
     3566
     3567      * a line `\ell = (a_0, \dots, a_{n-1})^T`
     3568
     3569      * a ray `r = (a_0, \dots, a_{n-1})^T`
     3570
     3571      * a point `p = (\tfrac{a_0}{d}, \dots, \tfrac{a_{n-1}}{d})^T`
     3572
     3573      * a closure point `c = (\tfrac{a_0}{d}, \dots, \tfrac{a_{n-1}}{d})^T`
     3574
     3575    where `n` is the dimension of the space and, for points and
     3576    closure points, `d` is the divisor.
     3577   
     3578    INPUT/OUTPUT:
     3579
     3580    Use the helper functions :func:`line`, :func:`ray`, :func:`point`,
     3581    and :func:`closure_point` to construct generators. Analogous class
     3582    methods are also available, see :meth:`Generator.line`,
     3583    :meth:`Generator.ray`, :meth:`Generator.point`,
     3584    :meth:`Generator.closure_point`. Do not attempt to construct
     3585    generators manually.
     3586
     3587    .. NOTE::
     3588
     3589        The generators are constructed from linear expressions. The
     3590        inhomogeneous term is always silently discarded.
     3591
     3592    EXAMPLES::
     3593
     3594        sage: from sage.libs.ppl import Generator, Variable
     3595        sage: x = Variable(0)
     3596        sage: y = Variable(1)
     3597        sage: Generator.line(5*x-2*y)
     3598        line(5, -2)
     3599        sage: Generator.ray(5*x-2*y)
     3600        ray(5, -2)
     3601        sage: Generator.point(5*x-2*y, 7)
     3602        point(5/7, -2/7)
     3603        sage: Generator.closure_point(5*x-2*y, 7)
     3604        closure_point(5/7, -2/7)
     3605    """
     3606
     3607    cdef PPL_Generator *thisptr
     3608
     3609   
     3610    def __cinit__(self, do_not_construct_manually=False):
     3611        """
     3612        The Cython constructor.
     3613       
     3614        See :class:`Variable` for documentation.
     3615
     3616        TESTS::
     3617
     3618            sage: from sage.libs.ppl import Variable, line
     3619            sage: x = Variable(0)
     3620            sage: line(x)   # indirect doctest
     3621            line(1)
     3622        """
     3623        assert(do_not_construct_manually)
     3624        self.thisptr = NULL
     3625
     3626
     3627    def __dealloc__(self):
     3628        """
     3629        The Cython destructor.
     3630        """
     3631        assert self.thisptr!=NULL, 'Do not construct Generators manually!'
     3632        del self.thisptr
     3633
     3634
     3635    @classmethod
     3636    def line(cls, expression):
     3637        """
     3638        Construct a line.
     3639
     3640        INPUT:
     3641       
     3642        - ``expression`` -- a :class:`Linear_Expression` or something
     3643          convertible to it (:class:`Variable` or integer).
     3644
     3645        OUTPUT:
     3646
     3647        A new :class:`Generator` representing the line.
     3648
     3649        Raises a ``ValueError` if the homogeneous part of
     3650        ``expression`` represents the origin of the vector space.
     3651
     3652        EXAMPLES::
     3653
     3654            sage: from sage.libs.ppl import Generator, Variable
     3655            sage: y = Variable(1)
     3656            sage: Generator.line(2*y)
     3657            line(0, 1)
     3658            sage: Generator.line(y)
     3659            line(0, 1)
     3660            sage: Generator.line(1)
     3661            Traceback (most recent call last):
     3662            ...
     3663            ValueError: PPL::line(e):
     3664            e == 0, but the origin cannot be a line.
     3665        """
     3666        cdef Linear_Expression e = Linear_Expression(expression)
     3667        # This does not work as Cython gets confused by the private default ctor
     3668        #   return _wrap_Generator(PPL_line(e.thisptr[0]))
     3669        # workaround follows
     3670        cdef Generator g = Generator(True)
     3671        try:
     3672            g.thisptr = new_line(e.thisptr[0])
     3673        except ValueError, msg:
     3674            # g.thisptr must be set to something valid or g.__dealloc__() will segfault
     3675            g.thisptr = new_point(e.thisptr[0],PPL_Coefficient(1))
     3676            raise ValueError, msg
     3677        return g
     3678
     3679
     3680    @classmethod
     3681    def ray(cls, expression):
     3682        """
     3683        Construct a ray.
     3684
     3685        INPUT:
     3686       
     3687        - ``expression`` -- a :class:`Linear_Expression` or something
     3688          convertible to it (:class:`Variable` or integer).
     3689
     3690        OUTPUT:
     3691
     3692        A new :class:`Generator` representing the ray.
     3693
     3694        Raises a ``ValueError` if the homogeneous part of
     3695        ``expression`` represents the origin of the vector space.
     3696
     3697        EXAMPLES::
     3698
     3699            sage: from sage.libs.ppl import Generator, Variable
     3700            sage: y = Variable(1)
     3701            sage: Generator.ray(2*y)
     3702            ray(0, 1)
     3703            sage: Generator.ray(y)
     3704            ray(0, 1)
     3705            sage: Generator.ray(1)
     3706            Traceback (most recent call last):
     3707            ...
     3708            ValueError: PPL::ray(e):
     3709            e == 0, but the origin cannot be a ray.
     3710        """
     3711        cdef Linear_Expression e = Linear_Expression(expression)
     3712        # This does not work as Cython gets confused by the private default ctor
     3713        #   return _wrap_Generator(PPL_ray(e.thisptr[0]))
     3714        # workaround follows
     3715        cdef Generator g = Generator(True)
     3716        try:
     3717            g.thisptr = new_ray(e.thisptr[0])
     3718        except ValueError, msg:
     3719            # g.thisptr must be set to something valid or g.__dealloc__() will segfault
     3720            g.thisptr = new_point(e.thisptr[0],PPL_Coefficient(1))
     3721            raise ValueError, msg
     3722        return g
     3723
     3724
     3725    @classmethod
     3726    def point(cls, expression=0, divisor=1):
     3727        """
     3728        Construct a point.
     3729
     3730        INPUT:
     3731       
     3732        - ``expression`` -- a :class:`Linear_Expression` or something
     3733          convertible to it (:class:`Variable` or integer).
     3734
     3735        - ``divisor`` -- an integer.
     3736
     3737        OUTPUT:
     3738
     3739        A new :class:`Generator` representing the point.
     3740
     3741        Raises a ``ValueError` if ``divisor==0``.
     3742
     3743        EXAMPLES::
     3744
     3745            sage: from sage.libs.ppl import Generator, Variable
     3746            sage: y = Variable(1)
     3747            sage: Generator.point(2*y+7, 3)
     3748            point(0/3, 2/3)
     3749            sage: Generator.point(y+7, 3)
     3750            point(0/3, 1/3)
     3751            sage: Generator.point(7, 3)
     3752            point()
     3753            sage: Generator.point(0, 0)
     3754            Traceback (most recent call last):
     3755            ...
     3756            ValueError: PPL::point(e, d):
     3757            d == 0.
     3758        """
     3759        cdef Linear_Expression e = Linear_Expression(expression)
     3760        cdef Integer d = Integer(divisor)
     3761        # This does not work as Cython gets confused by the private default ctor
     3762        #   return _wrap_Generator(PPL_point(e.thisptr[0], PPL_Coefficient(d.value)))
     3763        # workaround follows
     3764        cdef Generator g = Generator(True)
     3765        try:
     3766            g.thisptr = new_point(e.thisptr[0], PPL_Coefficient(d.value))
     3767        except ValueError, msg:
     3768            # g.thisptr must be set to something valid or g.__dealloc__() will segfault
     3769            g.thisptr = new_point(e.thisptr[0],PPL_Coefficient(1))
     3770            raise ValueError, msg
     3771        return g
     3772
     3773
     3774    @classmethod
     3775    def closure_point(cls, expression=0, divisor=1):
     3776        """
     3777        Construct a closure point.
     3778
     3779        A closure point is a point of the topological closure of a
     3780        polyhedron that is not a point of the polyhedron itself.
     3781
     3782        INPUT:
     3783       
     3784        - ``expression`` -- a :class:`Linear_Expression` or something
     3785          convertible to it (:class:`Variable` or integer).
     3786
     3787        - ``divisor`` -- an integer.
     3788
     3789        OUTPUT:
     3790
     3791        A new :class:`Generator` representing the point.
     3792
     3793        Raises a ``ValueError` if ``divisor==0``.
     3794
     3795        EXAMPLES::
     3796
     3797            sage: from sage.libs.ppl import Generator, Variable
     3798            sage: y = Variable(1)
     3799            sage: Generator.closure_point(2*y+7, 3)
     3800            closure_point(0/3, 2/3)
     3801            sage: Generator.closure_point(y+7, 3)
     3802            closure_point(0/3, 1/3)
     3803            sage: Generator.closure_point(7, 3)
     3804            closure_point()
     3805            sage: Generator.closure_point(0, 0)
     3806            Traceback (most recent call last):
     3807            ...
     3808            ValueError: PPL::closure_point(e, d):
     3809            d == 0.
     3810        """
     3811        cdef Linear_Expression e = Linear_Expression(expression)
     3812        cdef Integer d = Integer(divisor)
     3813        # This does not work as Cython gets confused by the private default ctor
     3814        #   return _wrap_Generator(PPL_closure_point(e.thisptr[0], PPL_Coefficient(d.value)))
     3815        # workaround follows
     3816        cdef Generator g = Generator(True)
     3817        try:
     3818            g.thisptr = new_closure_point(e.thisptr[0], PPL_Coefficient(d.value))
     3819        except ValueError, msg:
     3820            # g.thisptr must be set to something valid or g.__dealloc__() will segfault
     3821            g.thisptr = new_point(e.thisptr[0],PPL_Coefficient(1))
     3822            raise ValueError, msg
     3823        return g
     3824
     3825
     3826    def __repr__(self):
     3827        """
     3828        Return a string representation of the generator.
     3829
     3830        OUTPUT:
     3831
     3832        String.
     3833
     3834        EXAMPLES::
     3835
     3836            sage: from sage.libs.ppl import Generator, Variable
     3837            sage: x = Variable(0)
     3838            sage: y = Variable(1)
     3839            sage: e = 2*x-y+5
     3840            sage: Generator.line(e)
     3841            line(2, -1)
     3842            sage: Generator.ray(e)
     3843            ray(2, -1)
     3844            sage: Generator.point(e, 3)
     3845            point(2/3, -1/3)
     3846            sage: Generator.closure_point(e, 3)
     3847            closure_point(2/3, -1/3)
     3848        """
     3849        t = self.type()
     3850        if t=='line':
     3851            s = 'line('
     3852            div = ''
     3853        elif t=='ray':
     3854            s = 'ray('
     3855            div = ''
     3856        elif t=='point':
     3857            s = 'point('
     3858            div = '/'+str(self.divisor())
     3859        elif t=='closure_point':
     3860            s = 'closure_point('
     3861            div = '/'+str(self.divisor())
     3862        else:
     3863            assert(False)
     3864
     3865        for i in range(0,self.space_dimension()):
     3866            if i>0:
     3867                s += ', '
     3868            s += str(self.coefficient(Variable(i))) + div
     3869
     3870        s += ')'
     3871        return s
     3872
     3873
     3874    def space_dimension(self):
     3875        r"""
     3876        Return the dimension of the vector space enclosing ``self``.
     3877
     3878        OUTPUT:
     3879       
     3880        Integer.
     3881
     3882        EXAMPLES::
     3883
     3884            sage: from sage.libs.ppl import Variable, point
     3885            sage: x = Variable(0)
     3886            sage: y = Variable(1)
     3887            sage: point(x).space_dimension()
     3888            1
     3889            sage: point(y).space_dimension()
     3890            2
     3891        """
     3892        return self.thisptr.space_dimension()
     3893   
     3894
     3895    def type(self):
     3896        r"""
     3897        Return the generator type of ``self``.
     3898
     3899        OUTPUT:
     3900
     3901        String. One of ``'line'``, ``'ray'``, ``'point'``, or
     3902        ``'closure_point'``.
     3903
     3904        EXAMPLES::
     3905
     3906            sage: from sage.libs.ppl import Variable, point, closure_point, ray, line
     3907            sage: x = Variable(0)
     3908            sage: line(x).type()
     3909            'line'
     3910            sage: ray(x).type()
     3911            'ray'
     3912            sage: point(x,2).type()
     3913            'point'
     3914            sage: closure_point(x,2).type()
     3915            'closure_point'
     3916        """
     3917        t = self.thisptr.type()
     3918        if t==LINE:
     3919            return 'line'
     3920        elif t==RAY:
     3921            return 'ray'
     3922        elif t==POINT:
     3923            return 'point'
     3924        elif t==CLOSURE_POINT:
     3925            return 'closure_point'
     3926        assert False
     3927
     3928
     3929    def is_line(self):
     3930        r"""
     3931        Test whether ``self`` is a line.
     3932       
     3933        OUTPUT:
     3934       
     3935        Boolean.
     3936
     3937        EXAMPLES::
     3938
     3939            sage: from sage.libs.ppl import Variable, point, closure_point, ray, line
     3940            sage: x = Variable(0)
     3941            sage: line(x).is_line()
     3942            True
     3943            sage: ray(x).is_line()
     3944            False
     3945            sage: point(x,2).is_line()
     3946            False
     3947            sage: closure_point(x,2).is_line()
     3948            False
     3949        """
     3950        return self.thisptr.is_line()
     3951       
     3952
     3953    def is_ray(self):
     3954        r"""
     3955        Test whether ``self`` is a ray.
     3956       
     3957        OUTPUT:
     3958       
     3959        Boolean.
     3960
     3961        EXAMPLES::
     3962
     3963            sage: from sage.libs.ppl import Variable, point, closure_point, ray, line
     3964            sage: x = Variable(0)
     3965            sage: line(x).is_ray()
     3966            False
     3967            sage: ray(x).is_ray()
     3968            True
     3969            sage: point(x,2).is_ray()
     3970            False
     3971            sage: closure_point(x,2).is_ray()
     3972            False
     3973        """
     3974        return self.thisptr.is_ray()
     3975       
     3976
     3977    def is_line_or_ray(self):
     3978        r"""
     3979        Test whether ``self`` is a line or a ray.
     3980       
     3981        OUTPUT:
     3982       
     3983        Boolean.
     3984
     3985        EXAMPLES::
     3986
     3987            sage: from sage.libs.ppl import Variable, point, closure_point, ray, line
     3988            sage: x = Variable(0)
     3989            sage: line(x).is_line_or_ray()
     3990            True
     3991            sage: ray(x).is_line_or_ray()
     3992            True
     3993            sage: point(x,2).is_line_or_ray()
     3994            False
     3995            sage: closure_point(x,2).is_line_or_ray()
     3996            False
     3997        """
     3998        return self.thisptr.is_line_or_ray()
     3999       
     4000
     4001    def is_point(self):
     4002        r"""
     4003        Test whether ``self`` is a point.
     4004       
     4005        OUTPUT:
     4006       
     4007        Boolean.
     4008
     4009        EXAMPLES::
     4010
     4011            sage: from sage.libs.ppl import Variable, point, closure_point, ray, line
     4012            sage: x = Variable(0)
     4013            sage: line(x).is_point()
     4014            False
     4015            sage: ray(x).is_point()
     4016            False
     4017            sage: point(x,2).is_point()
     4018            True
     4019            sage: closure_point(x,2).is_point()
     4020            False
     4021        """
     4022        return self.thisptr.is_point()
     4023       
     4024
     4025    def is_closure_point(self):
     4026        r"""
     4027        Test whether ``self`` is a closure point.
     4028       
     4029        OUTPUT:
     4030       
     4031        Boolean.
     4032
     4033        EXAMPLES::
     4034
     4035            sage: from sage.libs.ppl import Variable, point, closure_point, ray, line
     4036            sage: x = Variable(0)
     4037            sage: line(x).is_closure_point()
     4038            False
     4039            sage: ray(x).is_closure_point()
     4040            False
     4041            sage: point(x,2).is_closure_point()
     4042            False
     4043            sage: closure_point(x,2).is_closure_point()
     4044            True
     4045        """
     4046        return self.thisptr.is_closure_point()
     4047       
     4048
     4049    def coefficient(self, Variable v):
     4050        """
     4051        Return the coefficient of the variable ``v``.
     4052
     4053        INPUT:
     4054       
     4055        - ``v`` -- a :class:`Variable`.
     4056
     4057        OUTPUT:
     4058       
     4059        An integer.
     4060
     4061        EXAMPLES::
     4062
     4063            sage: from sage.libs.ppl import Variable, line
     4064            sage: x = Variable(0)
     4065            sage: line = line(3*x+1)
     4066            sage: line
     4067            line(1)
     4068            sage: line.coefficient(x)
     4069            1
     4070        """
     4071        cdef Integer c = Integer(0)
     4072        mpz_set(c.value, self.thisptr.coefficient(v.thisptr[0]).get_mpz_t())
     4073        return c
     4074
     4075
     4076    def coefficients(self):
     4077        """
     4078        Return the coefficients of the generator.
     4079
     4080        See also :meth:`coefficient`.
     4081
     4082        OUTPUT:
     4083       
     4084        A tuple of integers of length :meth:`space_dimension`.
     4085
     4086        EXAMPLES::
     4087
     4088            sage: from sage.libs.ppl import Variable, point
     4089            sage: x = Variable(0);  y = Variable(1)
     4090            sage: p = point(3*x+5*y+1, 2); p
     4091            point(3/2, 5/2)
     4092            sage: p.coefficients()
     4093            (3, 5)
     4094        """
     4095        cdef int d = self.space_dimension()
     4096        cdef int i
     4097        cdef Integer c = Integer(0)
     4098        coeffs = []
     4099        for i in range(0,d):
     4100            mpz_set(c.value, self.thisptr.coefficient(PPL_Variable(i)).get_mpz_t())
     4101            coeffs.append(Integer(c))
     4102        return tuple(coeffs)
     4103
     4104
     4105    def divisor(self):
     4106        """
     4107        If ``self`` is either a point or a closure point, return its
     4108        divisor.
     4109
     4110        OUTPUT:
     4111       
     4112        An integer. If ``self`` is a ray or a line, raises
     4113        ``ValueError``.
     4114
     4115        EXAMPLES::
     4116
     4117            sage: from sage.libs.ppl import Generator, Variable
     4118            sage: x = Variable(0)
     4119            sage: y = Variable(1)
     4120            sage: point = Generator.point(2*x-y+5)
     4121            sage: point.divisor()
     4122            1
     4123            sage: line = Generator.line(2*x-y+5)
     4124            sage: line.divisor()
     4125            Traceback (most recent call last):
     4126            ...
     4127            ValueError: PPL::Generator::divisor():
     4128            *this is neither a point nor a closure point.
     4129        """
     4130        cdef Integer c = Integer(0)
     4131        mpz_set(c.value, self.thisptr.divisor().get_mpz_t())
     4132        return c
     4133
     4134
     4135    def is_equivalent_to(self, Generator g):
     4136        r"""
     4137        Test whether ``self`` and ``g`` are equivalent.
     4138       
     4139        INPUT:
     4140
     4141        - ``g`` -- a :class:`Generator`.
     4142
     4143        OUTPUT:
     4144
     4145        Boolean. Returns ``True`` if and only if ``self`` and ``g``
     4146        are equivalent generators.
     4147       
     4148        Note that generators having different space dimensions are not
     4149        equivalent.
     4150
     4151        EXAMPLES::
     4152       
     4153            sage: from sage.libs.ppl import Generator, Variable, point, line
     4154            sage: x = Variable(0)
     4155            sage: y = Variable(1)
     4156            sage: point(2*x    , 2).is_equivalent_to( point(x) )
     4157            True
     4158            sage: point(2*x+0*y, 2).is_equivalent_to( point(x) )
     4159            False
     4160            sage: line(4*x).is_equivalent_to(line(x))
     4161            True
     4162        """
     4163        return self.thisptr.is_equivalent_to(g.thisptr[0])
     4164
     4165
     4166    def ascii_dump(self):
     4167        r"""
     4168        Write an ASCII dump to stderr.
     4169       
     4170        EXAMPLES::
     4171
     4172            sage: sage_cmd  = 'from sage.libs.ppl import Linear_Expression, Variable, point\n'
     4173            sage: sage_cmd += 'x = Variable(0)\n'
     4174            sage: sage_cmd += 'y = Variable(1)\n'
     4175            sage: sage_cmd += 'p = point(3*x+2*y)\n'
     4176            sage: sage_cmd += 'p.ascii_dump()\n'
     4177            sage: from sage.tests.cmdline import test_executable
     4178            sage: (out, err, ret) = test_executable(['sage', '-c', sage_cmd]);   # indirect doctest
     4179            sage: print err
     4180            size 3 1 3 2 f -RPI_V +RPI  -NNC_V -NNC
     4181        """
     4182        self.thisptr.ascii_dump()
     4183
     4184
     4185    def OK(self):
     4186        """
     4187        Check if all the invariants are satisfied.
     4188
     4189        EXAMPLES::
     4190
     4191            sage: from sage.libs.ppl import Linear_Expression, Variable
     4192            sage: x = Variable(0)
     4193            sage: y = Variable(1)
     4194            sage: e = 3*x+2*y+1
     4195            sage: e.OK()
     4196            True
     4197        """
     4198        return self.thisptr.OK()
     4199
     4200
     4201
     4202####################################################
     4203def line(expression):
     4204    """
     4205    Constuct a line.
     4206   
     4207    See :meth:`Generator.line` for documentation.
     4208
     4209    EXAMPLES::
     4210
     4211        sage: from sage.libs.ppl import Variable, line
     4212        sage: y = Variable(1)
     4213        sage: line(2*y)
     4214        line(0, 1)
     4215    """
     4216    return Generator.line(expression)
     4217
     4218
     4219####################################################
     4220def ray(expression):
     4221    """
     4222    Constuct a ray.
     4223   
     4224    See :meth:`Generator.ray` for documentation.
     4225
     4226    EXAMPLES::
     4227
     4228        sage: from sage.libs.ppl import Variable, ray
     4229        sage: y = Variable(1)
     4230        sage: ray(2*y)
     4231        ray(0, 1)
     4232    """
     4233    return Generator.ray(expression)
     4234
     4235
     4236####################################################
     4237def point(expression=0, divisor=1):
     4238    """
     4239    Constuct a point.
     4240   
     4241    See :meth:`Generator.point` for documentation.
     4242
     4243    EXAMPLES::
     4244
     4245        sage: from sage.libs.ppl import Variable, point
     4246        sage: y = Variable(1)
     4247        sage: point(2*y, 5)
     4248        point(0/5, 2/5)
     4249    """
     4250    return Generator.point(expression, divisor)
     4251
     4252
     4253####################################################
     4254def closure_point(expression=0, divisor=1):
     4255    """
     4256    Constuct a closure point.
     4257   
     4258    See :meth:`Generator.closure_point` for documentation.
     4259
     4260    EXAMPLES::
     4261
     4262        sage: from sage.libs.ppl import Variable, closure_point
     4263        sage: y = Variable(1)
     4264        sage: closure_point(2*y, 5)
     4265        closure_point(0/5, 2/5)
     4266    """
     4267    return Generator.closure_point(expression, divisor)
     4268
     4269
     4270
     4271####################################################
     4272### Generator_System  ##############################
     4273####################################################
     4274cdef _wrap_Generator_System(PPL_Generator_System generator_system):
     4275    """
     4276    Wrap a C++ ``PPL_Generator_System`` into a Cython ``Generator_System``.
     4277    """
     4278    cdef Generator_System gs = Generator_System()
     4279    del gs.thisptr
     4280    gs.thisptr = new PPL_Generator_System(generator_system)
     4281    return gs
     4282
     4283
     4284####################################################
     4285cdef class Generator_System(_mutable_or_immutable):
     4286    """
     4287    Wrapper for PPL's ``Generator_System`` class.
     4288   
     4289    An object of the class Generator_System is a system of generators,
     4290    i.e., a multiset of objects of the class Generator (lines, rays,
     4291    points and closure points). When inserting generators in a system,
     4292    space dimensions are automatically adjusted so that all the
     4293    generators in the system are defined on the same vector space. A
     4294    system of generators which is meant to define a non-empty
     4295    polyhedron must include at least one point: the reason is that
     4296    lines, rays and closure points need a supporting point (lines and
     4297    rays only specify directions while closure points only specify
     4298    points in the topological closure of the NNC polyhedron).
     4299
     4300    EXAMPLES::
     4301
     4302        sage: from sage.libs.ppl import Generator_System, Variable, line, ray, point, closure_point
     4303        sage: x = Variable(0)
     4304        sage: y = Variable(1)
     4305        sage: gs = Generator_System( line(5*x-2*y) )
     4306        sage: gs.insert( ray(6*x-3*y) )
     4307        sage: gs.insert( point(2*x-7*y, 5) )
     4308        sage: gs.insert( closure_point(9*x-1*y, 2) )
     4309        sage: gs
     4310        Generator_System {line(5, -2), ray(2, -1), point(2/5, -7/5), closure_point(9/2, -1/2)}
     4311    """
     4312
     4313    cdef PPL_Generator_System *thisptr
     4314
     4315   
     4316    def __cinit__(self, arg=None):
     4317        """
     4318        The Cython constructor.
     4319       
     4320        See :class:`Generator_System` for documentation.
     4321
     4322        TESTS::
     4323
     4324            sage: from sage.libs.ppl import Generator_System
     4325            sage: Generator_System()   # indirect doctest
     4326            Generator_System {}
     4327        """
     4328        if arg is None:
     4329            self.thisptr = new PPL_Generator_System()
     4330            return
     4331        if PY_TYPE_CHECK(arg, Generator):
     4332            g = <Generator>arg
     4333            self.thisptr = new PPL_Generator_System(g.thisptr[0])
     4334            return
     4335        if PY_TYPE_CHECK(arg, Generator_System):
     4336            gs = <Generator_System>arg
     4337            self.thisptr = new PPL_Generator_System(gs.thisptr[0])
     4338            return
     4339        raise ValueError, 'Cannot initialize with '+str(arg)+'.'
     4340
     4341
     4342    def __dealloc__(self):
     4343        """
     4344        The Cython destructor.
     4345        """
     4346        del self.thisptr
     4347
     4348       
     4349    def space_dimension(self):
     4350        r"""
     4351        Return the dimension of the vector space enclosing ``self``.
     4352
     4353        OUTPUT:
     4354       
     4355        Integer.
     4356
     4357        EXAMPLES::
     4358
     4359            sage: from sage.libs.ppl import Variable, Generator_System, point
     4360            sage: x = Variable(0)
     4361            sage: gs = Generator_System( point(3*x) )
     4362            sage: gs.space_dimension()
     4363            1
     4364        """
     4365        return self.thisptr.space_dimension()
     4366
     4367
     4368    def clear(self):
     4369        r"""
     4370        Removes all generators from the generator system and sets its
     4371        space dimension to 0.
     4372
     4373        EXAMPLES::
     4374
     4375            sage: from sage.libs.ppl import Variable, Generator_System, point
     4376            sage: x = Variable(0)
     4377            sage: gs = Generator_System( point(3*x) ); gs
     4378            Generator_System {point(3/1)}
     4379            sage: gs.clear()
     4380            sage: gs
     4381            Generator_System {}
     4382        """
     4383        self.assert_mutable('The Generator_System is not mutable!')
     4384        self.thisptr.clear()
     4385
     4386
     4387    def insert(self, Generator g):
     4388        """
     4389        Insert ``g`` into the generator system.
     4390
     4391        The number of space dimensions of ``self`` is increased, if needed.
     4392
     4393        INPUT:
     4394
     4395        - ``g`` -- a :class:`Generator`.
     4396
     4397        EXAMPLES::
     4398     
     4399            sage: from sage.libs.ppl import Variable, Generator_System, point
     4400            sage: x = Variable(0)
     4401            sage: gs = Generator_System( point(3*x) )
     4402            sage: gs.insert( point(-3*x) )
     4403            sage: gs
     4404            Generator_System {point(3/1), point(-3/1)}
     4405        """
     4406        self.assert_mutable('The Generator_System is not mutable!')
     4407        self.thisptr.insert(g.thisptr[0])
     4408
     4409
     4410    def empty(self):
     4411        """
     4412        Return ``True`` if and only if ``self`` has no generators.
     4413
     4414        OUTPUT:
     4415       
     4416        Boolean.
     4417
     4418        EXAMPLES::
     4419     
     4420            sage: from sage.libs.ppl import Variable, Generator_System, point
     4421            sage: x = Variable(0)
     4422            sage: gs = Generator_System()
     4423            sage: gs.empty()
     4424            True
     4425            sage: gs.insert( point(-3*x) )
     4426            sage: gs.empty()
     4427            False
     4428        """
     4429        return self.thisptr.empty()
     4430
     4431
     4432    def ascii_dump(self):
     4433        r"""
     4434        Write an ASCII dump to stderr.
     4435       
     4436        EXAMPLES::
     4437
     4438            sage: sage_cmd  = 'from sage.libs.ppl import Generator_System, point, Variable\n'
     4439            sage: sage_cmd += 'x = Variable(0)\n'
     4440            sage: sage_cmd += 'y = Variable(1)\n'
     4441            sage: sage_cmd += 'gs = Generator_System( point(3*x+2*y+1) )\n'
     4442            sage: sage_cmd += 'gs.ascii_dump()\n'
     4443            sage: from sage.tests.cmdline import test_executable
     4444            sage: (out, err, ret) = test_executable(['sage', '-c', sage_cmd]);   # indirect doctest
     4445            sage: print err
     4446            topology NECESSARILY_CLOSED
     4447            1 x 3 (sorted)
     4448            index_first_pending 1
     4449            1 3 2 P
     4450        """
     4451        self.thisptr.ascii_dump()
     4452
     4453
     4454    def OK(self):
     4455        """
     4456        Check if all the invariants are satisfied.
     4457
     4458        EXAMPLES::
     4459
     4460            sage: from sage.libs.ppl import Variable, Generator_System, point
     4461            sage: x = Variable(0)
     4462            sage: y = Variable(1)
     4463            sage: gs = Generator_System( point(3*x+2*y+1) )
     4464            sage: gs.OK()
     4465            True
     4466        """
     4467        return self.thisptr.OK()
     4468
     4469
     4470    def __iter__(self):
     4471        """
     4472        Iterate through the generators of the system.
     4473
     4474        EXAMPLES::
     4475       
     4476            sage: from sage.libs.ppl import Generator_System, Variable, point
     4477            sage: x = Variable(0)
     4478            sage: gs = Generator_System(point(3*x))
     4479            sage: iter = gs.__iter__()
     4480            sage: iter.next()
     4481            point(3/1)
     4482        """
     4483        return Generator_System_iterator(self)
     4484
     4485
     4486    def __repr__(self):
     4487        r"""
     4488        Return a string representation of the generator system.
     4489       
     4490        OUTPUT:
     4491
     4492        A string.
     4493
     4494        EXAMPLES::
     4495
     4496            sage: from sage.libs.ppl import Generator_System, Variable, point, ray
     4497            sage: x = Variable(0)
     4498            sage: y = Variable(1)
     4499            sage: gs = Generator_System(point(3*x+2*y+1))
     4500            sage: gs.insert(ray(x))
     4501            sage: gs.__repr__()
     4502            'Generator_System {point(3/1, 2/1), ray(1, 0)}'
     4503        """
     4504        s = 'Generator_System {'
     4505        s += ', '.join([ g.__repr__() for g in self ])
     4506        s += '}'
     4507        return s
     4508
     4509
     4510####################################################
     4511### Generator_System_iterator ######################
     4512####################################################
     4513cdef extern from "ppl_shim.hh":
     4514    ctypedef void* gs_iterator_ptr
     4515    cdef gs_iterator_ptr init_gs_iterator(PPL_Generator_System &gs)
     4516    cdef PPL_Generator next_gs_iterator(gs_iterator_ptr)
     4517    cdef bint is_end_gs_iterator(PPL_Generator_System &gs, gs_iterator_ptr gsi_ptr)
     4518    cdef void delete_gs_iterator(gs_iterator_ptr)
     4519
     4520
     4521####################################################
     4522cdef class Generator_System_iterator(object):
     4523    """
     4524    Wrapper for PPL's ``Generator_System::const_iterator`` class.
     4525
     4526    EXAMPLES::
     4527
     4528        sage: from sage.libs.ppl import Generator_System, Variable, line, ray, point, closure_point, Generator_System_iterator
     4529        sage: x = Variable(0)
     4530        sage: y = Variable(1)
     4531        sage: gs = Generator_System( line(5*x-2*y) )
     4532        sage: gs.insert( ray(6*x-3*y) )
     4533        sage: gs.insert( point(2*x-7*y, 5) )
     4534        sage: gs.insert( closure_point(9*x-1*y, 2) )
     4535        sage: Generator_System_iterator(gs).next()
     4536        line(5, -2)
     4537        sage: list(gs)
     4538        [line(5, -2), ray(2, -1), point(2/5, -7/5), closure_point(9/2, -1/2)]
     4539    """
     4540
     4541    cdef Generator_System gs
     4542    cdef gs_iterator_ptr gsi_ptr
     4543
     4544
     4545    def __cinit__(self, Generator_System gs):
     4546        r"""
     4547        The Cython constructor.
     4548
     4549        TESTS::
     4550       
     4551            sage: from sage.libs.ppl import Generator_System, Generator_System_iterator
     4552            sage: iter = Generator_System_iterator(Generator_System())   # indirect doctest
     4553        """
     4554        self.gs = gs
     4555        self.gsi_ptr = init_gs_iterator(gs.thisptr[0])
     4556
     4557
     4558    def __dealloc__(self):
     4559        """
     4560        The Cython destructor.
     4561        """
     4562        delete_gs_iterator(self.gsi_ptr)
     4563
     4564
     4565    def __next__(Generator_System_iterator self):
     4566        r"""
     4567        The next iteration.
     4568
     4569        OUTPUT:
     4570       
     4571        A :class:`Generator`.
     4572
     4573        EXAMPLES::
     4574       
     4575            sage: from sage.libs.ppl import Generator_System, Variable, point, Generator_System_iterator
     4576            sage: x = Variable(0)
     4577            sage: y = Variable(1)
     4578            sage: gs = Generator_System( point(5*x-2*y) )
     4579            sage: Generator_System_iterator(gs).next()
     4580            point(5/1, -2/1)
     4581        """
     4582        if is_end_gs_iterator((<Generator_System>self.gs).thisptr[0], self.gsi_ptr):
     4583            raise StopIteration
     4584        return _wrap_Generator(next_gs_iterator(self.gsi_ptr))
     4585
     4586
     4587####################################################
     4588### Constraint ######################################
     4589####################################################
     4590cdef _wrap_Constraint(PPL_Constraint constraint):
     4591    """
     4592    Wrap a C++ ``PPL_Constraint`` into a Cython ``Constraint``.
     4593    """
     4594    cdef Constraint c = Constraint(True)
     4595    c.thisptr = new PPL_Constraint(constraint)
     4596    return c
     4597
     4598
     4599####################################################
     4600cdef _make_Constraint_from_richcmp(lhs_, rhs_, op):
     4601    cdef Linear_Expression lhs = Linear_Expression(lhs_)
     4602    cdef Linear_Expression rhs = Linear_Expression(rhs_)
     4603    if op==0:      # <   0
     4604        return _wrap_Constraint(lhs.thisptr[0] <  rhs.thisptr[0])
     4605    elif op==1:    # <=  1
     4606        return _wrap_Constraint(lhs.thisptr[0] <= rhs.thisptr[0])
     4607    elif op==2:    # ==  2
     4608        return _wrap_Constraint(lhs.thisptr[0] == rhs.thisptr[0])
     4609    elif op==4:    # >   4
     4610        return _wrap_Constraint(lhs.thisptr[0] >  rhs.thisptr[0])
     4611    elif op==5:    # >=  5
     4612        return _wrap_Constraint(lhs.thisptr[0] >= rhs.thisptr[0])
     4613    elif op==3:    # !=  3
     4614        raise NotImplementedError
     4615    else:
     4616        assert(False)
     4617
     4618
     4619####################################################
     4620cdef class Constraint(object):
     4621    """
     4622    Wrapper for PPL's ``Constraint`` class.
     4623   
     4624    An object of the class ``Constraint`` is either:
     4625
     4626    * an equality `\sum_{i=0}^{n-1} a_i x_i + b = 0`
     4627
     4628    * a non-strict inequality `\sum_{i=0}^{n-1} a_i x_i + b \geq 0`
     4629
     4630    * a strict inequality `\sum_{i=0}^{n-1} a_i x_i + b > 0`
     4631
     4632    where `n` is the dimension of the space, `a_i` is the integer
     4633    coefficient of variable `x_i`, and `b_i` is the integer
     4634    inhomogeneous term.
     4635
     4636    INPUT/OUTPUT:
     4637
     4638    You construct constraints by writing inequalities in
     4639    :class:`Linear_Expression`. Do not attempt to manually construct
     4640    constraints.
     4641
     4642    EXAMPLES::
     4643
     4644        sage: from sage.libs.ppl import Constraint, Variable, Linear_Expression
     4645        sage: x = Variable(0)
     4646        sage: y = Variable(1)
     4647        sage: 5*x-2*y >  x+y-1
     4648        4*x0-3*x1+1>0
     4649        sage: 5*x-2*y >= x+y-1
     4650        4*x0-3*x1+1>=0
     4651        sage: 5*x-2*y == x+y-1
     4652        4*x0-3*x1+1==0
     4653        sage: 5*x-2*y <= x+y-1
     4654        -4*x0+3*x1-1>=0
     4655        sage: 5*x-2*y <  x+y-1
     4656        -4*x0+3*x1-1>0
     4657        sage: x > 0
     4658        x0>0
     4659
     4660    Special care is needed if the left hand side is a constant::
     4661
     4662        sage: 0 == 1    # watch out!
     4663        False
     4664        sage: Linear_Expression(0) == 1
     4665        -1==0
     4666    """
     4667
     4668    cdef PPL_Constraint *thisptr
     4669
     4670   
     4671    def __cinit__(self, do_not_construct_manually=False):
     4672        """
     4673        The Cython constructor.
     4674       
     4675        See :class:`Constraint` for documentation.
     4676
     4677        TESTS::
     4678
     4679            sage: from sage.libs.ppl import Constraint, Variable, Linear_Expression
     4680            sage: x = Variable(0)
     4681            sage: x>0   # indirect doctest
     4682            x0>0
     4683        """
     4684        assert(do_not_construct_manually)
     4685        self.thisptr = NULL
     4686
     4687
     4688    def __dealloc__(self):
     4689        """
     4690        The Cython destructor.
     4691        """
     4692        assert self.thisptr!=NULL, 'Do not construct Constraints manually!'
     4693        del self.thisptr
     4694
     4695
     4696    def __repr__(self):
     4697        """
     4698        Return a string representation of the constraint.
     4699
     4700        OUTPUT:
     4701
     4702        String.
     4703
     4704        EXAMPLES::
     4705
     4706            sage: from sage.libs.ppl import Constraint, Variable
     4707            sage: x = Variable(0)
     4708            sage: y = Variable(1)
     4709            sage: (2*x-y+5 >  x).__repr__() 
     4710            'x0-x1+5>0'
     4711            sage: (2*x-y+5 == x).__repr__()
     4712            'x0-x1+5==0'
     4713            sage: (2*x-y+5 >= x).__repr__()
     4714            'x0-x1+5>=0'
     4715        """
     4716        e = sum([ self.coefficient(x)*x
     4717                  for x in [Variable(i)
     4718                            for i in range(0,self.space_dimension())] ])
     4719        e += self.inhomogeneous_term()
     4720        s = e.__repr__()
     4721        t = self.type()
     4722        if t=='equality':
     4723            s += '==0'
     4724        elif t=='nonstrict_inequality':
     4725            s += '>=0'
     4726        elif t=='strict_inequality':
     4727            s += '>0'
     4728        else:
     4729            assert(False)
     4730        return s
     4731
     4732
     4733    def space_dimension(self):
     4734        r"""
     4735        Return the dimension of the vector space enclosing ``self``.
     4736
     4737        OUTPUT:
     4738       
     4739        Integer.
     4740
     4741        EXAMPLES::
     4742
     4743            sage: from sage.libs.ppl import Variable
     4744            sage: x = Variable(0)
     4745            sage: y = Variable(1)
     4746            sage: (x>=0).space_dimension()
     4747            1
     4748            sage: (y==1).space_dimension()
     4749            2
     4750        """
     4751        return self.thisptr.space_dimension()
     4752   
     4753
     4754    def type(self):
     4755        r"""
     4756        Return the constraint type of ``self``.
     4757
     4758        OUTPUT:
     4759
     4760        String. One of ``'equality'``, ``'nonstrict_inequality'``, or
     4761        ``'strict_inequality'``.
     4762
     4763        EXAMPLES::
     4764
     4765            sage: from sage.libs.ppl import Variable
     4766            sage: x = Variable(0)
     4767            sage: (x==0).type()
     4768            'equality'
     4769            sage: (x>=0).type()
     4770            'nonstrict_inequality'
     4771            sage: (x>0).type()
     4772            'strict_inequality'
     4773        """
     4774        t = self.thisptr.type()
     4775        if t==EQUALITY:
     4776            return 'equality'
     4777        elif t==NONSTRICT_INEQUALITY:
     4778            return 'nonstrict_inequality'
     4779        elif t==STRICT_INEQUALITY:
     4780            return 'strict_inequality'
     4781
     4782
     4783    def is_equality(self):
     4784        r"""
     4785        Test whether ``self`` is an equality.
     4786       
     4787        OUTPUT:
     4788       
     4789        Boolean. Returns ``True`` if and only if ``self`` is an
     4790        equality constraint.
     4791
     4792        EXAMPLES::
     4793
     4794            sage: from sage.libs.ppl import Variable
     4795            sage: x = Variable(0)
     4796            sage: (x==0).is_equality()
     4797            True
     4798            sage: (x>=0).is_equality()
     4799            False
     4800            sage: (x>0).is_equality()
     4801            False
     4802        """
     4803        return self.thisptr.is_equality()
     4804       
     4805
     4806    def is_inequality(self):
     4807        r"""
     4808        Test whether ``self`` is an inequality.
     4809       
     4810        OUTPUT:
     4811       
     4812        Boolean. Returns ``True`` if and only if ``self`` is an
     4813        inequality constraint, either strict or non-strict.
     4814
     4815        EXAMPLES::
     4816
     4817            sage: from sage.libs.ppl import Variable
     4818            sage: x = Variable(0)
     4819            sage: (x==0).is_inequality()
     4820            False
     4821            sage: (x>=0).is_inequality()
     4822            True
     4823            sage: (x>0).is_inequality()
     4824            True
     4825        """
     4826        return self.thisptr.is_inequality()
     4827       
     4828
     4829    def is_nonstrict_inequality(self):
     4830        r"""
     4831        Test whether ``self`` is a non-strict inequality.
     4832       
     4833        OUTPUT:
     4834       
     4835        Boolean. Returns ``True`` if and only if ``self`` is an
     4836        non-strict inequality constraint.
     4837
     4838        EXAMPLES::
     4839
     4840            sage: from sage.libs.ppl import Variable
     4841            sage: x = Variable(0)
     4842            sage: (x==0).is_nonstrict_inequality()
     4843            False
     4844            sage: (x>=0).is_nonstrict_inequality()
     4845            True
     4846            sage: (x>0).is_nonstrict_inequality()
     4847            False
     4848        """
     4849        return self.thisptr.is_nonstrict_inequality()
     4850       
     4851
     4852    def is_strict_inequality(self):
     4853        r"""
     4854        Test whether ``self`` is a strict inequality.
     4855       
     4856        OUTPUT:
     4857       
     4858        Boolean. Returns ``True`` if and only if ``self`` is an
     4859        strict inequality constraint.
     4860
     4861        EXAMPLES::
     4862
     4863            sage: from sage.libs.ppl import Variable
     4864            sage: x = Variable(0)
     4865            sage: (x==0).is_strict_inequality()
     4866            False
     4867            sage: (x>=0).is_strict_inequality()
     4868            False
     4869            sage: (x>0).is_strict_inequality()
     4870            True
     4871        """
     4872        return self.thisptr.is_strict_inequality()
     4873       
     4874
     4875    def coefficient(self, Variable v):
     4876        """
     4877        Return the coefficient of the variable ``v``.
     4878
     4879        INPUT:
     4880       
     4881        - ``v`` -- a :class:`Variable`.
     4882
     4883        OUTPUT:
     4884       
     4885        An integer.
     4886
     4887        EXAMPLES::
     4888
     4889            sage: from sage.libs.ppl import Variable
     4890            sage: x = Variable(0)
     4891            sage: ineq = (3*x+1 > 0)
     4892            sage: ineq.coefficient(x)
     4893            3
     4894        """
     4895        cdef Integer c = Integer(0)
     4896        mpz_set(c.value, self.thisptr.coefficient(v.thisptr[0]).get_mpz_t())
     4897        return c
     4898
     4899
     4900    def coefficients(self):
     4901        """
     4902        Return the coefficients of the constraint.
     4903
     4904        See also :meth:`coefficient`.
     4905
     4906        OUTPUT:
     4907       
     4908        A tuple of integers of length :meth:`space_dimension`.
     4909
     4910        EXAMPLES::
     4911
     4912            sage: from sage.libs.ppl import Variable
     4913            sage: x = Variable(0);  y = Variable(1)
     4914            sage: ineq = ( 3*x+5*y+1 ==  2);  ineq
     4915            3*x0+5*x1-1==0
     4916            sage: ineq.coefficients()
     4917            (3, 5)
     4918        """
     4919        cdef int d = self.space_dimension()
     4920        cdef int i
     4921        cdef Integer c = Integer(0)
     4922        coeffs = []
     4923        for i in range(0,d):
     4924            mpz_set(c.value, self.thisptr.coefficient(PPL_Variable(i)).get_mpz_t())
     4925            coeffs.append(Integer(c))
     4926        return tuple(coeffs)
     4927
     4928
     4929    def inhomogeneous_term(self):
     4930        """
     4931        Return the inhomogeneous term of the constraint.
     4932
     4933        OUTPUT:
     4934       
     4935        Integer.
     4936
     4937        EXAMPLES::
     4938
     4939            sage: from sage.libs.ppl import Variable
     4940            sage: y = Variable(1)
     4941            sage: ineq = ( 10+y > 9 )
     4942            sage: ineq
     4943            x1+1>0
     4944            sage: ineq.inhomogeneous_term()
     4945            1
     4946        """
     4947        cdef Integer c = Integer(0)
     4948        mpz_set(c.value, self.thisptr.inhomogeneous_term().get_mpz_t())
     4949        return c
     4950
     4951
     4952    def is_tautological(self):
     4953        r"""
     4954        Test whether ``self`` is a tautological constraint.
     4955       
     4956        A tautology can have either one of the following forms:
     4957
     4958        * an equality: `\sum 0 x_i + 0 = 0`,
     4959
     4960        * a non-strict inequality: `\sum 0 x_i + b \geq 0` with `b\geq 0`, or
     4961
     4962        * a strict inequality: `\sum 0 x_i + b > 0` with `b> 0`.
     4963
     4964        OUTPUT:
     4965       
     4966        Boolean. Returns ``True`` if and only if ``self`` is a
     4967        tautological constraint.
     4968
     4969        EXAMPLES::
     4970
     4971            sage: from sage.libs.ppl import Variable
     4972            sage: x = Variable(0)
     4973            sage: (x==0).is_tautological()
     4974            False
     4975            sage: (0*x>=0).is_tautological()
     4976            True
     4977        """
     4978        return self.thisptr.is_tautological()
     4979
     4980
     4981    def is_inconsistent(self):
     4982        r"""
     4983        Test whether ``self`` is an inconsistent constraint, that is, always false.
     4984       
     4985        An inconsistent constraint can have either one of the
     4986        following forms:
     4987
     4988        * an equality: `\sum 0 x_i + b = 0` with `b\not=0`,
     4989
     4990        * a non-strict inequality: `\sum 0 x_i + b \geq 0` with `b< 0`, or
     4991
     4992        * a strict inequality: `\sum 0 x_i + b > 0` with `b\leq 0`.
     4993
     4994        OUTPUT:
     4995       
     4996        Boolean. Returns ``True`` if and only if ``self`` is an
     4997        inconsistent constraint.
     4998
     4999        EXAMPLES::
     5000
     5001            sage: from sage.libs.ppl import Variable
     5002            sage: x = Variable(0)
     5003            sage: (x==1).is_inconsistent()
     5004            False
     5005            sage: (0*x>=1).is_inconsistent()
     5006            True
     5007        """
     5008        return self.thisptr.is_inconsistent()
     5009
     5010
     5011    def is_equivalent_to(self, Constraint c):
     5012        r"""
     5013        Test whether ``self`` and ``c`` are equivalent.
     5014       
     5015        INPUT:
     5016
     5017        - ``c`` -- a :class:`Constraint`.
     5018
     5019        OUTPUT:
     5020
     5021        Boolean. Returns ``True`` if and only if ``self`` and ``c``
     5022        are equivalent constraints.
     5023       
     5024        Note that constraints having different space dimensions are
     5025        not equivalent. However, constraints having different types
     5026        may nonetheless be equivalent, if they both are tautologies or
     5027        inconsistent.
     5028
     5029        EXAMPLES::
     5030       
     5031            sage: from sage.libs.ppl import Variable, Linear_Expression
     5032            sage: x = Variable(0)
     5033            sage: y = Variable(1)
     5034            sage: ( x>0 ).is_equivalent_to( Linear_Expression(0)<x )
     5035            True
     5036            sage: ( x>0 ).is_equivalent_to( 0*y<x )
     5037            False
     5038            sage: ( 0*x>1 ).is_equivalent_to( 0*x==-2 )
     5039            True
     5040        """
     5041        return self.thisptr.is_equivalent_to(c.thisptr[0])
     5042
     5043
     5044    def ascii_dump(self):
     5045        r"""
     5046        Write an ASCII dump to stderr.
     5047       
     5048        EXAMPLES::
     5049
     5050            sage: sage_cmd  = 'from sage.libs.ppl import Linear_Expression, Variable\n'
     5051            sage: sage_cmd += 'x = Variable(0)\n'
     5052            sage: sage_cmd += 'y = Variable(1)\n'
     5053            sage: sage_cmd += 'e = (3*x+2*y+1 > 0)\n'
     5054            sage: sage_cmd += 'e.ascii_dump()\n'
     5055            sage: from sage.tests.cmdline import test_executable
     5056            sage: (out, err, ret) = test_executable(['sage', '-c', sage_cmd]);   # indirect doctest
     5057            sage: print err
     5058            size 4 1 3 2 -1 f -RPI_V +RPI  -NNC_V +NNC
     5059        """
     5060        self.thisptr.ascii_dump()
     5061
     5062
     5063    def OK(self):
     5064        """
     5065        Check if all the invariants are satisfied.
     5066
     5067        EXAMPLES::
     5068
     5069            sage: from sage.libs.ppl import Linear_Expression, Variable
     5070            sage: x = Variable(0)
     5071            sage: y = Variable(1)
     5072            sage: ineq = (3*x+2*y+1>=0)
     5073            sage: ineq.OK()
     5074            True
     5075        """
     5076        return self.thisptr.OK()
     5077
     5078
     5079####################################################
     5080### Constraint_System  ##############################
     5081####################################################
     5082cdef _wrap_Constraint_System(PPL_Constraint_System constraint_system):
     5083    """
     5084    Wrap a C++ ``PPL_Constraint_System`` into a Cython ``Constraint_System``.
     5085    """
     5086    cdef Constraint_System cs = Constraint_System()
     5087    del cs.thisptr
     5088    cs.thisptr = new PPL_Constraint_System(constraint_system)
     5089    return cs
     5090
     5091
     5092####################################################
     5093cdef class Constraint_System(object):
     5094    """
     5095    Wrapper for PPL's ``Constraint_System`` class.
     5096   
     5097    An object of the class Constraint_System is a system of
     5098    constraints, i.e., a multiset of objects of the class
     5099    Constraint. When inserting constraints in a system, space
     5100    dimensions are automatically adjusted so that all the constraints
     5101    in the system are defined on the same vector space.
     5102
     5103    EXAMPLES::
     5104
     5105        sage: from sage.libs.ppl import Constraint_System, Variable
     5106        sage: x = Variable(0)
     5107        sage: y = Variable(1)
     5108        sage: cs = Constraint_System( 5*x-2*y > 0 )
     5109        sage: cs.insert( 6*x<3*y )
     5110        sage: cs.insert( x >= 2*x-7*y )
     5111        sage: cs
     5112        Constraint_System {5*x0-2*x1>0, -6*x0+3*x1>0, -x0+7*x1>=0}
     5113    """
     5114
     5115    cdef PPL_Constraint_System *thisptr
     5116
     5117   
     5118    def __cinit__(self, arg=None):
     5119        """
     5120        The Cython constructor.
     5121       
     5122        See :class:`Constraint_System` for documentation.
     5123
     5124        TESTS::
     5125
     5126            sage: from sage.libs.ppl import Constraint_System
     5127            sage: Constraint_System()   
     5128            Constraint_System {}
     5129        """
     5130        if arg is None:
     5131            self.thisptr = new PPL_Constraint_System()
     5132            return
     5133        if PY_TYPE_CHECK(arg, Constraint):
     5134            g = <Constraint>arg
     5135            self.thisptr = new PPL_Constraint_System(g.thisptr[0])
     5136            return
     5137        if PY_TYPE_CHECK(arg, Constraint_System):
     5138            gs = <Constraint_System>arg
     5139            self.thisptr = new PPL_Constraint_System(gs.thisptr[0])
     5140            return
     5141        raise ValueError, 'Cannot initialize with '+str(arg)+'.'
     5142
     5143
     5144    def __dealloc__(self):
     5145        """
     5146        The Cython destructor.
     5147        """
     5148        del self.thisptr
     5149
     5150       
     5151    def space_dimension(self):
     5152        r"""
     5153        Return the dimension of the vector space enclosing ``self``.
     5154
     5155        OUTPUT:
     5156       
     5157        Integer.
     5158
     5159        EXAMPLES::
     5160
     5161            sage: from sage.libs.ppl import Variable, Constraint_System
     5162            sage: x = Variable(0)
     5163            sage: cs = Constraint_System( x>0 )
     5164            sage: cs.space_dimension()
     5165            1
     5166        """
     5167        return self.thisptr.space_dimension()
     5168
     5169
     5170    def has_equalities(self):
     5171        r"""
     5172        Tests whether ``self`` contains one or more equality constraints.
     5173
     5174        OUTPUT:
     5175
     5176        Boolean.
     5177       
     5178        EXAMPLES::
     5179
     5180            sage: from sage.libs.ppl import Variable, Constraint_System
     5181            sage: x = Variable(0)
     5182            sage: cs = Constraint_System()
     5183            sage: cs.insert( x>0 )
     5184            sage: cs.insert( x<0 )
     5185            sage: cs.has_equalities()
     5186            False
     5187            sage: cs.insert( x==0 )
     5188            sage: cs.has_equalities()
     5189            True
     5190        """
     5191        return self.thisptr.has_equalities()
     5192
     5193
     5194    def has_strict_inequalities(self):
     5195        r"""
     5196        Tests whether ``self`` contains one or more strict inequality constraints.
     5197
     5198        OUTPUT:
     5199
     5200        Boolean.
     5201       
     5202        EXAMPLES::
     5203
     5204            sage: from sage.libs.ppl import Variable, Constraint_System
     5205            sage: x = Variable(0)
     5206            sage: cs = Constraint_System()
     5207            sage: cs.insert( x>=0 )
     5208            sage: cs.insert( x==-1 )
     5209            sage: cs.has_strict_inequalities()
     5210            False
     5211            sage: cs.insert( x>0 )
     5212            sage: cs.has_strict_inequalities()
     5213            True
     5214        """
     5215        return self.thisptr.has_strict_inequalities()
     5216
     5217
     5218    def clear(self):
     5219        r"""
     5220        Removes all constraints from the constraint system and sets its
     5221        space dimension to 0.
     5222
     5223        EXAMPLES::
     5224
     5225            sage: from sage.libs.ppl import Variable, Constraint_System
     5226            sage: x = Variable(0)
     5227            sage: cs = Constraint_System(x>0)
     5228            sage: cs
     5229            Constraint_System {x0>0}
     5230            sage: cs.clear()
     5231            sage: cs
     5232            Constraint_System {}
     5233        """
     5234        self.assert_mutable('The Constraint_System is not mutable!')
     5235        self.thisptr.clear()
     5236
     5237
     5238    def insert(self, Constraint c):
     5239        """
     5240        Insert ``c`` into the constraint system.
     5241
     5242        INPUT:
     5243
     5244        - ``c`` -- a :class:`Constraint`.
     5245
     5246        EXAMPLES::
     5247
     5248            sage: from sage.libs.ppl import Variable, Constraint_System
     5249            sage: x = Variable(0)
     5250            sage: cs = Constraint_System()
     5251            sage: cs.insert( x>0 )
     5252            sage: cs
     5253            Constraint_System {x0>0}
     5254        """
     5255        self.assert_mutable('The Constraint_System is not mutable!')
     5256        self.thisptr.insert(c.thisptr[0])
     5257
     5258
     5259    def empty(self):
     5260        """
     5261        Return ``True`` if and only if ``self`` has no constraints.
     5262
     5263        OUTPUT:
     5264       
     5265        Boolean.
     5266
     5267        EXAMPLES::
     5268     
     5269            sage: from sage.libs.ppl import Variable, Constraint_System, point
     5270            sage: x = Variable(0)
     5271            sage: cs = Constraint_System()
     5272            sage: cs.empty()
     5273            True
     5274            sage: cs.insert( x>0 )
     5275            sage: cs.empty()
     5276            False
     5277        """
     5278        return self.thisptr.empty()
     5279
     5280
     5281    def ascii_dump(self):
     5282        r"""
     5283        Write an ASCII dump to stderr.
     5284       
     5285        EXAMPLES::
     5286
     5287            sage: sage_cmd  = 'from sage.libs.ppl import Constraint_System, Variable\n'
     5288            sage: sage_cmd += 'x = Variable(0)\n'
     5289            sage: sage_cmd += 'y = Variable(1)\n'
     5290            sage: sage_cmd += 'cs = Constraint_System( 3*x > 2*y+1 )\n'
     5291            sage: sage_cmd += 'cs.ascii_dump()\n'
     5292            sage: from sage.tests.cmdline import test_executable
     5293            sage: (out, err, ret) = test_executable(['sage', '-c', sage_cmd]);   # indirect doctest
     5294            sage: print err
     5295            topology NOT_NECESSARILY_CLOSED
     5296            1 x 4 (sorted)
     5297            index_first_pending 1
     5298            -1 3 -2 -1 >
     5299        """
     5300        self.thisptr.ascii_dump()
     5301
     5302
     5303    def OK(self):
     5304        """
     5305        Check if all the invariants are satisfied.
     5306
     5307        EXAMPLES::
     5308
     5309            sage: from sage.libs.ppl import Variable, Constraint_System
     5310            sage: x = Variable(0)
     5311            sage: y = Variable(1)
     5312            sage: cs = Constraint_System( 3*x+2*y+1 <= 10 )
     5313            sage: cs.OK()
     5314            True
     5315        """
     5316        return self.thisptr.OK()
     5317
     5318
     5319    def __iter__(self):
     5320        """
     5321        Iterate through the constraints of the system.
     5322
     5323        EXAMPLES::
     5324
     5325            sage: from sage.libs.ppl import Variable, Constraint_System
     5326            sage: x = Variable(0)
     5327            sage: cs = Constraint_System( x>0 )
     5328            sage: iter = cs.__iter__()
     5329            sage: iter.next()
     5330            x0>0
     5331            sage: list(cs)   # uses __iter__() internally
     5332            [x0>0]
     5333        """
     5334        return Constraint_System_iterator(self)
     5335
     5336
     5337    def __repr__(self):
     5338        r"""
     5339        Return a string representation of the constraint system.
     5340       
     5341        OUTPUT:
     5342
     5343        A string.
     5344
     5345        EXAMPLES::
     5346
     5347            sage: from sage.libs.ppl import Constraint_System, Variable
     5348            sage: x = Variable(0)
     5349            sage: y = Variable(1)
     5350            sage: cs = Constraint_System( 3*x+2*y+1 < 3)
     5351            sage: cs.insert( 0*x>x+1 )
     5352            sage: cs.__repr__()
     5353            'Constraint_System {-3*x0-2*x1+2>0, -x0-1>0}'
     5354        """
     5355        s = 'Constraint_System {'
     5356        s += ', '.join([ c.__repr__() for c in self ])
     5357        s += '}'
     5358        return s
     5359
     5360
     5361####################################################
     5362### Constraint_System_iterator #####################
     5363####################################################
     5364cdef extern from "ppl_shim.hh":
     5365    ctypedef void* cs_iterator_ptr
     5366    cdef cs_iterator_ptr init_cs_iterator(PPL_Constraint_System &cs)
     5367    cdef PPL_Constraint next_cs_iterator(cs_iterator_ptr)
     5368    cdef bint is_end_cs_iterator(PPL_Constraint_System &cs, cs_iterator_ptr csi_ptr)
     5369    cdef void delete_cs_iterator(cs_iterator_ptr)
     5370
     5371
     5372####################################################
     5373cdef class Constraint_System_iterator(object):
     5374    """
     5375    Wrapper for PPL's ``Constraint_System::const_iterator`` class.
     5376
     5377    EXAMPLES::
     5378
     5379        sage: from sage.libs.ppl import Constraint_System, Variable, Constraint_System_iterator
     5380        sage: x = Variable(0)
     5381        sage: y = Variable(1)
     5382        sage: cs = Constraint_System( 5*x < 2*y )
     5383        sage: cs.insert( 6*x-3*y==0 )
     5384        sage: cs.insert( x >= 2*x-7*y )
     5385        sage: Constraint_System_iterator(cs).next()
     5386        -5*x0+2*x1>0
     5387        sage: list(cs)
     5388        [-5*x0+2*x1>0, 2*x0-x1==0, -x0+7*x1>=0]
     5389    """
     5390
     5391    cdef Constraint_System cs
     5392    cdef cs_iterator_ptr csi_ptr
     5393
     5394
     5395    def __cinit__(self, Constraint_System cs):
     5396        """
     5397        The Cython constructor.
     5398
     5399        See :class:`Constraint_System_iterator` for documentation.
     5400
     5401        TESTS::
     5402       
     5403            sage: from sage.libs.ppl import Constraint_System, Constraint_System_iterator
     5404            sage: iter = Constraint_System_iterator( Constraint_System() )   # indirect doctest
     5405        """
     5406        self.cs = cs
     5407        self.csi_ptr = init_cs_iterator(cs.thisptr[0])
     5408
     5409
     5410    def __dealloc__(self):
     5411        """
     5412        The Cython destructor.
     5413        """
     5414        delete_cs_iterator(self.csi_ptr)
     5415
     5416
     5417    def __next__(Constraint_System_iterator self):
     5418        r"""
     5419        The next iteration.
     5420
     5421        OUTPUT:
     5422       
     5423        A :class:`Generator`.
     5424
     5425        EXAMPLES::
     5426
     5427            sage: from sage.libs.ppl import Constraint_System, Variable, Constraint_System_iterator
     5428            sage: x = Variable(0)
     5429            sage: cs = Constraint_System( 5*x > 0 )
     5430            sage: Constraint_System_iterator(cs).next()
     5431            5*x0>0
     5432        """       
     5433        if is_end_cs_iterator((<Constraint_System>self.cs).thisptr[0], self.csi_ptr):
     5434            raise StopIteration
     5435        return _wrap_Constraint(next_cs_iterator(self.csi_ptr))
     5436
     5437
     5438
     5439####################################################
     5440### Poly_Gen_Relation ##############################
     5441####################################################
     5442cdef _wrap_Poly_Gen_Relation(PPL_Poly_Gen_Relation relation):
     5443    """
     5444    Wrap a C++ ``PPL_Poly_Gen_Relation`` into a Cython ``Poly_Gen_Relation``.
     5445    """
     5446    cdef Poly_Gen_Relation rel = Poly_Gen_Relation(True)
     5447    rel.thisptr = new PPL_Poly_Gen_Relation(relation)
     5448    return rel
     5449
     5450
     5451####################################################
     5452cdef class Poly_Gen_Relation(object):
     5453    r"""
     5454    Wrapper for PPL's ``Poly_Con_Relation`` class.
     5455
     5456    INPUT/OUTPUT:
     5457
     5458    You must not construct :class:`Poly_Gen_Relation` objects
     5459    manually. You will usually get them from
     5460    :meth:`~sage.libs.ppl.Polyhedron.relation_with`. You can also get
     5461    pre-defined relations from the class methods :meth:`nothing` and
     5462    :meth:`subsumes`.
     5463
     5464    EXAMPLES::
     5465
     5466        sage: from sage.libs.ppl import Poly_Gen_Relation
     5467        sage: nothing = Poly_Gen_Relation.nothing(); nothing
     5468        nothing
     5469        sage: subsumes = Poly_Gen_Relation.subsumes(); subsumes
     5470        subsumes
     5471        sage: nothing.implies( subsumes )
     5472        False
     5473        sage: subsumes.implies( nothing )
     5474        True
     5475    """
     5476
     5477    cdef PPL_Poly_Gen_Relation *thisptr
     5478
     5479
     5480    def __cinit__(self, do_not_construct_manually=False):
     5481        """
     5482        The Cython constructor.
     5483       
     5484        See :class:`Poly_Gen_Relation` for documentation.
     5485
     5486        TESTS::
     5487
     5488            sage: from sage.libs.ppl import Poly_Gen_Relation
     5489            sage: Poly_Gen_Relation.nothing()
     5490            nothing
     5491        """
     5492        assert(do_not_construct_manually)
     5493        self.thisptr = NULL
     5494
     5495
     5496    def __dealloc__(self):
     5497        """
     5498        The Cython destructor.
     5499        """
     5500        assert self.thisptr!=NULL, 'Do not construct Poly_Gen_Relation objects manually!'
     5501        del self.thisptr
     5502
     5503
     5504    def implies(self, Poly_Gen_Relation y):
     5505        r"""
     5506        Test whether ``self`` implies ``y``.
     5507
     5508        INPUT:
     5509
     5510        - ``y`` -- a :class:`Poly_Gen_Relation`.
     5511       
     5512        OUTPUT:
     5513
     5514        Boolean. ``True`` if and only if ``self`` implies ``y``.
     5515
     5516        EXAMPLES::
     5517
     5518            sage: from sage.libs.ppl import Poly_Gen_Relation
     5519            sage: nothing = Poly_Gen_Relation.nothing()
     5520            sage: nothing.implies( nothing )
     5521            True
     5522        """
     5523        return self.thisptr.implies(y.thisptr[0])
     5524
     5525
     5526    @classmethod
     5527    def nothing(cls):
     5528        r"""
     5529        Return the assertion that says nothing.
     5530
     5531        OUTPUT:
     5532
     5533        A :class:`Poly_Gen_Relation`.
     5534
     5535        EXAMPLES::
     5536       
     5537            sage: from sage.libs.ppl import Poly_Gen_Relation
     5538            sage: Poly_Gen_Relation.nothing()
     5539            nothing
     5540        """
     5541        return _wrap_Poly_Gen_Relation(PPL_Poly_Gen_Relation_nothing())
     5542
     5543
     5544    @classmethod
     5545    def subsumes(cls):
     5546        r"""
     5547        Return the assertion "Adding the generator would not change
     5548        the polyhedron".
     5549
     5550        OUTPUT:
     5551
     5552        A :class:`Poly_Gen_Relation`.
     5553
     5554        EXAMPLES::
     5555       
     5556            sage: from sage.libs.ppl import Poly_Gen_Relation
     5557            sage: Poly_Gen_Relation.subsumes()
     5558            subsumes
     5559        """
     5560        return _wrap_Poly_Gen_Relation(PPL_Poly_Gen_Relation_subsumes())
     5561
     5562
     5563    def ascii_dump(self):
     5564        r"""
     5565        Write an ASCII dump to stderr.
     5566       
     5567        EXAMPLES::
     5568
     5569            sage: sage_cmd  = 'from sage.libs.ppl import Poly_Gen_Relation\n'
     5570            sage: sage_cmd += 'Poly_Gen_Relation.nothing().ascii_dump()\n'
     5571            sage: from sage.tests.cmdline import test_executable
     5572            sage: (out, err, ret) = test_executable(['sage', '-c', sage_cmd]);   # indirect doctest
     5573            sage: print err
     5574            NOTHING
     5575        """
     5576        self.thisptr.ascii_dump()
     5577
     5578
     5579    def OK(self, check_non_empty=False):
     5580        """
     5581        Check if all the invariants are satisfied.
     5582       
     5583        EXAMPLES::
     5584
     5585            sage: from sage.libs.ppl import Poly_Gen_Relation
     5586            sage: Poly_Gen_Relation.nothing().OK()
     5587            True
     5588        """
     5589        return self.thisptr.OK()
     5590
     5591       
     5592    def __repr__(self):
     5593        r"""
     5594        Return a string representation.
     5595
     5596        OUTPUT:
     5597
     5598        String.
     5599       
     5600        EXAMPLES::
     5601
     5602            sage: from sage.libs.ppl import Poly_Gen_Relation
     5603            sage: Poly_Gen_Relation.nothing().__repr__()
     5604            'nothing'
     5605        """
     5606        if self.implies(Poly_Gen_Relation.subsumes()):
     5607            return 'subsumes'
     5608        else:
     5609            return 'nothing'
     5610
     5611
     5612####################################################
     5613### Poly_Con_Relation ##############################
     5614####################################################
     5615cdef _wrap_Poly_Con_Relation(PPL_Poly_Con_Relation relation):
     5616    """
     5617    Wrap a C++ ``PPL_Poly_Con_Relation`` into a Cython ``Poly_Con_Relation``.
     5618    """
     5619    cdef Poly_Con_Relation rel = Poly_Con_Relation(True)
     5620    rel.thisptr = new PPL_Poly_Con_Relation(relation)
     5621    return rel
     5622
     5623
     5624####################################################
     5625cdef class Poly_Con_Relation(object):
     5626    r"""
     5627    Wrapper for PPL's ``Poly_Con_Relation`` class.
     5628
     5629    INPUT/OUTPUT:
     5630
     5631    You must not construct :class:`Poly_Con_Relation` objects
     5632    manually. You will usually get them from
     5633    :meth:`~sage.libs.ppl.Polyhedron.relation_with`. You can also get
     5634    pre-defined relations from the class methods :meth:`nothing`,
     5635    :meth:`is_disjoint`, :meth:`strictly_intersects`,
     5636    :meth:`is_included`, and :meth:`saturates`.
     5637
     5638    EXAMPLES::
     5639
     5640        sage: from sage.libs.ppl import Poly_Con_Relation
     5641        sage: saturates     = Poly_Con_Relation.saturates();  saturates
     5642        saturates
     5643        sage: is_included   = Poly_Con_Relation.is_included(); is_included
     5644        is_included
     5645        sage: is_included.implies(saturates)
     5646        False
     5647        sage: saturates.implies(is_included)
     5648        False
     5649        sage: rels = []
     5650        sage: rels.append( Poly_Con_Relation.nothing() )
     5651        sage: rels.append( Poly_Con_Relation.is_disjoint() )
     5652        sage: rels.append( Poly_Con_Relation.strictly_intersects() )
     5653        sage: rels.append( Poly_Con_Relation.is_included() )
     5654        sage: rels.append( Poly_Con_Relation.saturates() )
     5655        sage: rels
     5656        [nothing, is_disjoint, strictly_intersects, is_included, saturates]
     5657        sage: from sage.matrix.constructor import matrix
     5658        sage: m = matrix(5,5)
     5659        sage: for i, rel_i in enumerate(rels):
     5660        ...       for j, rel_j in enumerate(rels):
     5661        ...           m[i,j] = rel_i.implies(rel_j)
     5662        sage: m
     5663        [1 0 0 0 0]
     5664        [1 1 0 0 0]
     5665        [1 0 1 0 0]
     5666        [1 0 0 1 0]
     5667        [1 0 0 0 1]
     5668    """
     5669
     5670    cdef PPL_Poly_Con_Relation *thisptr
     5671
     5672
     5673    def __cinit__(self, do_not_construct_manually=False):
     5674        """
     5675        The Cython constructor.
     5676       
     5677        See :class:`Poly_Con_Relation` for documentation.
     5678
     5679        TESTS::
     5680
     5681            sage: from sage.libs.ppl import Poly_Con_Relation
     5682            sage: Poly_Con_Relation.nothing()
     5683            nothing
     5684        """
     5685        assert(do_not_construct_manually)
     5686        self.thisptr = NULL
     5687
     5688
     5689    def __dealloc__(self):
     5690        """
     5691        The Cython destructor.
     5692        """
     5693        assert self.thisptr!=NULL, 'Do not construct Poly_Con_Relation objects manually!'
     5694        del self.thisptr
     5695
     5696
     5697    def implies(self, Poly_Con_Relation y):
     5698        r"""
     5699        Test whether ``self`` implies ``y``.
     5700
     5701        INPUT:
     5702
     5703        - ``y`` -- a :class:`Poly_Con_Relation`.
     5704       
     5705        OUTPUT:
     5706
     5707        Boolean. ``True`` if and only if ``self`` implies ``y``.
     5708
     5709        EXAMPLES::
     5710
     5711            sage: from sage.libs.ppl import Poly_Con_Relation
     5712            sage: nothing = Poly_Con_Relation.nothing()
     5713            sage: nothing.implies( nothing )
     5714            True
     5715        """
     5716        return self.thisptr.implies(y.thisptr[0])
     5717
     5718
     5719    @classmethod
     5720    def nothing(cls):
     5721        r"""
     5722        Return the assertion that says nothing.
     5723
     5724        OUTPUT:
     5725
     5726        A :class:`Poly_Con_Relation`.
     5727
     5728        EXAMPLES::
     5729       
     5730            sage: from sage.libs.ppl import Poly_Con_Relation
     5731            sage: Poly_Con_Relation.nothing()
     5732            nothing
     5733        """
     5734        return _wrap_Poly_Con_Relation(PPL_Poly_Con_Relation_nothing())
     5735
     5736
     5737    @classmethod
     5738    def is_disjoint(cls):
     5739        r"""
     5740        Return the assertion "The polyhedron and the set of points
     5741        satisfying the constraint are disjoint".
     5742
     5743        OUTPUT:
     5744
     5745        A :class:`Poly_Con_Relation`.
     5746
     5747        EXAMPLES::
     5748       
     5749            sage: from sage.libs.ppl import Poly_Con_Relation
     5750            sage: Poly_Con_Relation.is_disjoint()
     5751            is_disjoint
     5752        """
     5753        return _wrap_Poly_Con_Relation(PPL_Poly_Con_Relation_is_disjoint())
     5754
     5755
     5756    @classmethod
     5757    def strictly_intersects(cls):
     5758        r"""
     5759        Return the assertion "The polyhedron intersects the set of
     5760        points satisfying the constraint, but it is not included in
     5761        it".
     5762
     5763        OUTPUT:
     5764
     5765        A :class:`Poly_Con_Relation`.
     5766
     5767        EXAMPLES::
     5768       
     5769            sage: from sage.libs.ppl import Poly_Con_Relation
     5770            sage: Poly_Con_Relation.strictly_intersects()
     5771            strictly_intersects
     5772        """
     5773        return _wrap_Poly_Con_Relation(PPL_Poly_Con_Relation_strictly_intersects())
     5774
     5775
     5776    @classmethod
     5777    def is_included(cls):
     5778        r"""
     5779        Return the assertion "The polyhedron is included in the set of
     5780        points satisfying the constraint".
     5781
     5782        OUTPUT:
     5783
     5784        A :class:`Poly_Con_Relation`.
     5785
     5786        EXAMPLES::
     5787       
     5788            sage: from sage.libs.ppl import Poly_Con_Relation
     5789            sage: Poly_Con_Relation.is_included()
     5790            is_included
     5791        """
     5792        return _wrap_Poly_Con_Relation(PPL_Poly_Con_Relation_is_included())
     5793
     5794
     5795    @classmethod
     5796    def saturates(cls):
     5797        r"""
     5798        Return the assertion "".
     5799
     5800        OUTPUT:
     5801
     5802        A :class:`Poly_Con_Relation`.
     5803
     5804        EXAMPLES::
     5805       
     5806            sage: from sage.libs.ppl import Poly_Con_Relation
     5807            sage: Poly_Con_Relation.saturates()
     5808            saturates
     5809        """
     5810        return _wrap_Poly_Con_Relation(PPL_Poly_Con_Relation_saturates())
     5811
     5812
     5813    def ascii_dump(self):
     5814        r"""
     5815        Write an ASCII dump to stderr.
     5816       
     5817        EXAMPLES::
     5818
     5819            sage: sage_cmd  = 'from sage.libs.ppl import Poly_Con_Relation\n'
     5820            sage: sage_cmd += 'Poly_Con_Relation.nothing().ascii_dump()\n'
     5821            sage: from sage.tests.cmdline import test_executable
     5822            sage: (out, err, ret) = test_executable(['sage', '-c', sage_cmd]);   # indirect doctest
     5823            sage: print err
     5824            NOTHING
     5825        """
     5826        self.thisptr.ascii_dump()
     5827
     5828
     5829    def OK(self, check_non_empty=False):
     5830        """
     5831        Check if all the invariants are satisfied.
     5832       
     5833        EXAMPLES::
     5834
     5835            sage: from sage.libs.ppl import Poly_Con_Relation
     5836            sage: Poly_Con_Relation.nothing().OK()
     5837            True
     5838        """
     5839        return self.thisptr.OK()
     5840
     5841       
     5842    def __repr__(self):
     5843        r"""
     5844        Return a string representation.
     5845
     5846        OUTPUT:
     5847
     5848        String.
     5849       
     5850        EXAMPLES::
     5851
     5852            sage: from sage.libs.ppl import Poly_Con_Relation
     5853            sage: Poly_Con_Relation.nothing().__repr__()
     5854            'nothing'
     5855        """
     5856        rel = []
     5857        if self.implies(Poly_Con_Relation.is_disjoint()):
     5858            rel.append('is_disjoint')
     5859        if self.implies(Poly_Con_Relation.strictly_intersects()):
     5860            rel.append('strictly_intersects')
     5861        if self.implies(Poly_Con_Relation.is_included()):
     5862            rel.append('is_included')
     5863        if self.implies(Poly_Con_Relation.saturates()):
     5864            rel.append('saturates')
     5865
     5866        if len(rel)>0:
     5867            return ', '.join(rel)
     5868        else:
     5869            return 'nothing'
     5870
     5871
     5872
     5873####################################################
     5874####################################################
     5875####################################################
     5876####################################################
  • new file sage/libs/ppl_shim.cc

    diff -r 138a6dc8b572 -r 0d39515604d2 sage/libs/ppl_shim.cc
    - +  
     1#include "ppl_shim.hh"
     2
     3
     4
     5
     6// /************************************************************/
     7Generator* new_line(const Linear_Expression& e)
     8{
     9  return new Generator(Generator::line(e));
     10}
     11
     12Generator* new_ray(const Linear_Expression& e)
     13{
     14  return new Generator(Generator::ray(e));
     15}
     16
     17Generator* new_point(const Linear_Expression& e, Coefficient d)
     18{
     19  return new Generator(Generator::point(e, d));
     20}
     21
     22Generator* new_closure_point(const Linear_Expression& e, Coefficient d)
     23{
     24  return new Generator(Generator::closure_point(e, d));
     25}
     26
     27
     28/************************************************************/
     29Poly_Gen_Relation* new_relation_with(const Polyhedron &p, const Generator &g)
     30{
     31  return new Poly_Gen_Relation(p.relation_with(g));
     32}
     33
     34Poly_Con_Relation* new_relation_with(const Polyhedron &p, const Constraint &c)
     35{
     36  return new Poly_Con_Relation(p.relation_with(c));
     37}
     38
     39
     40/************************************************************/
     41typedef Generator_System::const_iterator* gs_iterator_ptr;
     42
     43gs_iterator_ptr init_gs_iterator(const Generator_System &gs)
     44{
     45  return new Generator_System::const_iterator(gs.begin());
     46}
     47
     48Generator next_gs_iterator(gs_iterator_ptr gsi_ptr)
     49{
     50  return *(*gsi_ptr)++;
     51}
     52
     53bool is_end_gs_iterator(const Generator_System &gs, gs_iterator_ptr gsi_ptr)
     54{
     55  return (*gsi_ptr) == gs.end();
     56}
     57
     58void delete_gs_iterator(gs_iterator_ptr gsi_ptr)
     59{
     60  delete gsi_ptr;
     61}
     62
     63
     64/************************************************************/
     65typedef Constraint_System::const_iterator* cs_iterator_ptr;
     66
     67cs_iterator_ptr init_cs_iterator(const Constraint_System &cs)
     68{
     69  return new Constraint_System::const_iterator(cs.begin());
     70}
     71
     72Constraint next_cs_iterator(cs_iterator_ptr csi_ptr)
     73{
     74  return *(*csi_ptr)++;
     75}
     76
     77bool is_end_cs_iterator(const Constraint_System &cs, cs_iterator_ptr csi_ptr)
     78{
     79  return (*csi_ptr) == cs.end();
     80}
     81
     82void delete_cs_iterator(cs_iterator_ptr csi_ptr)
     83{
     84  delete csi_ptr;
     85}
     86
  • new file sage/libs/ppl_shim.hh

    diff -r 138a6dc8b572 -r 0d39515604d2 sage/libs/ppl_shim.hh
    - +  
     1#ifndef PPL_SHIM__H
     2#define PPL_SHIM__H
     3
     4
     5
     6#include <ppl.hh>
     7
     8using namespace Parma_Polyhedra_Library;
     9
     10
     11// access Generator's static methods
     12Generator* new_line(const Linear_Expression& e);
     13Generator* new_ray(const Linear_Expression& e);
     14Generator* new_point(const Linear_Expression& e, Coefficient d);
     15Generator* new_closure_point(const Linear_Expression& e, Coefficient d);
     16
     17// Poly_Gen_Relation/Poly_Con_Relation have no default constructor
     18Poly_Gen_Relation* new_relation_with(const Polyhedron &p, const Generator &g);
     19Poly_Con_Relation* new_relation_with(const Polyhedron &p, const Constraint &c);
     20
     21
     22// Iterator for Generator_System
     23typedef Generator_System::const_iterator* gs_iterator_ptr;
     24gs_iterator_ptr init_gs_iterator(const Generator_System &gs);
     25Generator next_gs_iterator(gs_iterator_ptr);
     26bool is_end_gs_iterator(const Generator_System &gs, gs_iterator_ptr gsi_ptr);
     27void delete_gs_iterator(gs_iterator_ptr);
     28
     29
     30// Iterator for Constraint_System
     31typedef Constraint_System::const_iterator* cs_iterator_ptr;
     32cs_iterator_ptr init_cs_iterator(const Constraint_System &cs);
     33Constraint next_cs_iterator(cs_iterator_ptr);
     34bool is_end_cs_iterator(const Constraint_System &cs, cs_iterator_ptr csi_ptr);
     35void delete_cs_iterator(cs_iterator_ptr);
     36
     37
     38
     39#endif