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