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