Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/geometry/polyhedron/constructor.py
8817 views
1
r"""
2
Polyhedra
3
4
In this module, a polyhedron is a convex (possibly unbounded) set in
5
Euclidean space cut out by a finite set of linear inequalities and
6
linear equations. Note that the dimension of the polyhedron can be
7
less than the dimension of the ambient space. There are two
8
complementary representations of the same data:
9
10
**H(alf-space/Hyperplane)-representation**
11
This describes a polyhedron as the common solution set of a
12
finite number of
13
14
* linear **inequalities** `A \vec{x} + b \geq 0`, and
15
16
* linear **equations** `C \vec{x} + d = 0`.
17
18
19
**V(ertex)-representation**
20
The other representation is as the convex hull of vertices (and
21
rays and lines to all for unbounded polyhedra) as generators. The
22
polyhedron is then the Minkowski sum
23
24
.. MATH::
25
26
P = \text{conv}\{v_1,\dots,v_k\} +
27
\sum_{i=1}^m \RR_+ r_i +
28
\sum_{j=1}^n \RR \ell_j
29
30
where
31
32
* **vertices** `v_1`, `\dots`, `v_k` are a finite number of
33
points. Each vertex is specified by an arbitrary vector, and two
34
points are equal if and only if the vector is the same.
35
36
* **rays** `r_1`, `\dots`, `r_m` are a finite number of directions
37
(directions of infinity). Each ray is specified by a non-zero
38
vector, and two rays are equal if and only if the vectors are
39
the same up to rescaling with a positive constant.
40
41
* **lines** `\ell_1`, `\dots`, `\ell_n` are a finite number of
42
unoriented directions. In other words, a line is equivalent to
43
the set `\{r, -r\}` for a ray `r`. Each line is specified by a
44
non-zero vector, and two lines are equivalent if and only if the
45
vectors are the same up to rescaling with a non-zero (possibly
46
negative) constant.
47
48
When specifying a polyhedron, you can input a non-minimal set of
49
inequalities/equations or generating vertices/rays/lines. The
50
non-minimal generators are usually called points, non-extremal rays,
51
and non-extremal lines, but for our purposes it is more convenient to
52
always talk about vertices/rays/lines. Sage will remove any
53
superfluous representation objects and always return a minimal
54
representation. For example, `(0,0)` is a superfluous vertex here::
55
56
sage: triangle = Polyhedron(vertices=[(0,2), (-1,0), (1,0), (0,0)])
57
sage: triangle.vertices()
58
(A vertex at (-1, 0), A vertex at (1, 0), A vertex at (0, 2))
59
60
A polytope is defined as a bounded polyhedron. In this case, the
61
minimal representation is unique and a vertex of the minimal
62
representation is equivalent to a 0-dimensional face of the
63
polytope. This is why one generally does not distinguish vertices and
64
0-dimensional faces. But for non-bounded polyhedra we have to allow
65
for a more general notion of "vertex" in order to make sense of the
66
Minkowsi sum presentation::
67
68
sage: half_plane = Polyhedron(ieqs=[(0,1,0)])
69
sage: half_plane.Hrepresentation()
70
(An inequality (1, 0) x + 0 >= 0,)
71
sage: half_plane.Vrepresentation()
72
(A line in the direction (0, 1), A ray in the direction (1, 0), A vertex at (0, 0))
73
74
Note how we need a point in the above example to anchor the ray and
75
line. But any point on the boundary of the half-plane would serve the
76
purpose just as well. Sage picked the origin here, but this choice is
77
not unique. Similarly, the choice of ray is arbitrary but necessary to
78
generate the half-plane.
79
80
Finally, note that while rays and lines generate unbounded edges of
81
the polyhedron they are not in a one-to-one correspondence with
82
them. For example, the infinite strip has two infinite edges (1-faces)
83
but only one generating line::
84
85
sage: strip = Polyhedron(vertices=[(1,0),(-1,0)], lines=[(0,1)])
86
sage: strip.Hrepresentation()
87
(An inequality (1, 0) x + 1 >= 0, An inequality (-1, 0) x + 1 >= 0)
88
sage: strip.lines()
89
(A line in the direction (0, 1),)
90
sage: strip.faces(1)
91
(<0,1>, <0,2>)
92
sage: for face in strip.faces(1):
93
... print face, '=', face.as_polyhedron().Vrepresentation()
94
<0,1> = (A line in the direction (0, 1), A vertex at (-1, 0))
95
<0,2> = (A line in the direction (0, 1), A vertex at (1, 0))
96
97
EXAMPLES::
98
99
sage: trunc_quadr = Polyhedron(vertices=[[1,0],[0,1]], rays=[[1,0],[0,1]])
100
sage: trunc_quadr
101
A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices and 2 rays
102
sage: v = trunc_quadr.vertex_generator().next() # the first vertex in the internal enumeration
103
sage: v
104
A vertex at (0, 1)
105
sage: v.vector()
106
(0, 1)
107
sage: list(v)
108
[0, 1]
109
sage: len(v)
110
2
111
sage: v[0] + v[1]
112
1
113
sage: v.is_vertex()
114
True
115
sage: type(v)
116
<class 'sage.geometry.polyhedron.representation.Vertex'>
117
sage: type( v() )
118
<type 'sage.modules.vector_integer_dense.Vector_integer_dense'>
119
sage: v.polyhedron()
120
A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices and 2 rays
121
sage: r = trunc_quadr.ray_generator().next()
122
sage: r
123
A ray in the direction (0, 1)
124
sage: r.vector()
125
(0, 1)
126
sage: list( v.neighbors() )
127
[A ray in the direction (0, 1), A vertex at (1, 0)]
128
129
Inequalities `A \vec{x} + b \geq 0` (and, similarly, equations) are
130
specified by a list ``[b, A]``::
131
132
sage: Polyhedron(ieqs=[(0,1,0),(0,0,1),(1,-1,-1)]).Hrepresentation()
133
(An inequality (-1, -1) x + 1 >= 0,
134
An inequality (1, 0) x + 0 >= 0,
135
An inequality (0, 1) x + 0 >= 0)
136
137
See :func:`Polyhedron` for a detailed description of all possible ways
138
to construct a polyhedron.
139
140
REFERENCES:
141
142
Komei Fukuda's `FAQ in Polyhedral Computation
143
<http://www.ifor.math.ethz.ch/~fukuda/polyfaq/polyfaq.html>`_
144
145
AUTHORS:
146
147
- Marshall Hampton: first version, bug fixes, and various improvements, 2008 and 2009
148
- Arnaud Bergeron: improvements to triangulation and rendering, 2008
149
- Sebastien Barthelemy: documentation improvements, 2008
150
- Volker Braun: refactoring, handle non-compact case, 2009 and 2010
151
- Andrey Novoseltsev: added Hasse_diagram_from_incidences, 2010
152
- Volker Braun: rewrite to use PPL instead of cddlib, 2011
153
"""
154
155
########################################################################
156
# Copyright (C) 2008 Marshall Hampton <[email protected]>
157
# Copyright (C) 2011 Volker Braun <[email protected]>
158
#
159
# Distributed under the terms of the GNU General Public License (GPL)
160
#
161
# http://www.gnu.org/licenses/
162
########################################################################
163
164
from sage.rings.all import QQ, ZZ, RDF
165
from sage.misc.decorators import rename_keyword
166
167
from misc import _make_listlist, _common_length_of
168
169
170
171
172
173
174
#########################################################################
175
@rename_keyword(deprecation=11634, field='base_ring')
176
def Polyhedron(vertices=None, rays=None, lines=None,
177
ieqs=None, eqns=None,
178
ambient_dim=None, base_ring=None, minimize=True, verbose=False,
179
backend=None):
180
"""
181
Construct a polyhedron object.
182
183
You may either define it with vertex/ray/line or
184
inequalities/equations data, but not both. Redundant data will
185
automatically be removed (unless ``minimize=False``), and the
186
complementary representation will be computed.
187
188
INPUT:
189
190
- ``vertices`` -- list of point. Each point can be specified as
191
any iterable container of ``base_ring`` elements. If ``rays`` or
192
``lines`` are specified but no ``vertices``, the origin is
193
taken to be the single vertex.
194
195
- ``rays`` -- list of rays. Each ray can be specified as any
196
iterable container of ``base_ring`` elements.
197
198
- ``lines`` -- list of lines. Each line can be specified as any
199
iterable container of ``base_ring`` elements.
200
201
- ``ieqs`` -- list of inequalities. Each line can be specified as any
202
iterable container of ``base_ring`` elements. An entry equal to
203
``[-1,7,3,4]`` represents the inequality `7x_1+3x_2+4x_3\geq 1`.
204
205
- ``eqns`` -- list of equalities. Each line can be specified as
206
any iterable container of ``base_ring`` elements. An entry equal to
207
``[-1,7,3,4]`` represents the equality `7x_1+3x_2+4x_3= 1`.
208
209
- ``base_ring`` -- either ``QQ`` or ``RDF``. The field over which
210
the polyhedron will be defined. For ``QQ``, exact arithmetic
211
will be used. For ``RDF``, floating point numbers will be
212
used. Floating point arithmetic is faster but might give the
213
wrong result for degenerate input.
214
215
- ``ambient_dim`` -- integer. The ambient space dimension. Usually
216
can be figured out automatically from the H/Vrepresentation
217
dimensions.
218
219
- ``backend`` -- string or ``None`` (default). The backend to use. Valid choices are
220
221
* ``'cdd'``: use cdd
222
(:mod:`~sage.geometry.polyhedron.backend_cdd`) with `\QQ` or
223
`\RDF` coefficients depending on ``base_ring``.
224
225
226
* ``'ppl'``: use ppl
227
(:mod:`~sage.geometry.polyhedron.backend_ppl`) with `\ZZ` or
228
`\QQ` coefficients depending on ``base_ring``.
229
230
Some backends support further optional arguments:
231
232
- ``minimize`` -- boolean (default: ``True``). Whether to
233
immediately remove redundant H/V-representation data. Currently
234
not used.
235
236
- ``verbose`` -- boolean (default: ``False``). Whether to print
237
verbose output for debugging purposes. Only supported by the cdd
238
backends.
239
240
OUTPUT:
241
242
The polyhedron defined by the input data.
243
244
EXAMPLES:
245
246
Construct some polyhedra::
247
248
sage: square_from_vertices = Polyhedron(vertices = [[1, 1], [1, -1], [-1, 1], [-1, -1]])
249
sage: square_from_ieqs = Polyhedron(ieqs = [[1, 0, 1], [1, 1, 0], [1, 0, -1], [1, -1, 0]])
250
sage: list(square_from_ieqs.vertex_generator())
251
[A vertex at (1, -1),
252
A vertex at (1, 1),
253
A vertex at (-1, 1),
254
A vertex at (-1, -1)]
255
sage: list(square_from_vertices.inequality_generator())
256
[An inequality (1, 0) x + 1 >= 0,
257
An inequality (0, 1) x + 1 >= 0,
258
An inequality (-1, 0) x + 1 >= 0,
259
An inequality (0, -1) x + 1 >= 0]
260
sage: p = Polyhedron(vertices = [[1.1, 2.2], [3.3, 4.4]], base_ring=RDF)
261
sage: p.n_inequalities()
262
2
263
264
The same polyhedron given in two ways::
265
266
sage: p = Polyhedron(ieqs = [[0,1,0,0],[0,0,1,0]])
267
sage: p.Vrepresentation()
268
(A line in the direction (0, 0, 1),
269
A ray in the direction (1, 0, 0),
270
A ray in the direction (0, 1, 0),
271
A vertex at (0, 0, 0))
272
sage: q = Polyhedron(vertices=[[0,0,0]], rays=[[1,0,0],[0,1,0]], lines=[[0,0,1]])
273
sage: q.Hrepresentation()
274
(An inequality (1, 0, 0) x + 0 >= 0,
275
An inequality (0, 1, 0) x + 0 >= 0)
276
277
Finally, a more complicated example. Take `\mathbb{R}_{\geq 0}^6` with
278
coordinates `a, b, \dots, f` and
279
280
* The inequality `e+b \geq c+d`
281
* The inequality `e+c \geq b+d`
282
* The equation `a+b+c+d+e+f = 31`
283
284
::
285
286
sage: positive_coords = Polyhedron(ieqs=[
287
... [0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0],
288
... [0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 1]])
289
sage: P = Polyhedron(ieqs=positive_coords.inequalities() + (
290
... [0,0,1,-1,-1,1,0], [0,0,-1,1,-1,1,0]), eqns=[[-31,1,1,1,1,1,1]])
291
sage: P
292
A 5-dimensional polyhedron in QQ^6 defined as the convex hull of 7 vertices
293
sage: P.dim()
294
5
295
sage: P.Vrepresentation()
296
(A vertex at (31, 0, 0, 0, 0, 0), A vertex at (0, 0, 0, 0, 0, 31),
297
A vertex at (0, 0, 0, 0, 31, 0), A vertex at (0, 0, 31/2, 0, 31/2, 0),
298
A vertex at (0, 31/2, 31/2, 0, 0, 0), A vertex at (0, 31/2, 0, 0, 31/2, 0),
299
A vertex at (0, 0, 0, 31/2, 31/2, 0))
300
301
.. NOTE::
302
303
* Once constructed, a ``Polyhedron`` object is immutable.
304
* Although the option ``field=RDF`` allows numerical data to
305
be used, it might not give the right answer for degenerate
306
input data - the results can depend upon the tolerance
307
setting of cdd.
308
"""
309
# Clean up the arguments
310
vertices = _make_listlist(vertices)
311
rays = _make_listlist(rays)
312
lines = _make_listlist(lines)
313
ieqs = _make_listlist(ieqs)
314
eqns = _make_listlist(eqns)
315
316
got_Vrep = (len(vertices+rays+lines) > 0)
317
got_Hrep = (len(ieqs+eqns) > 0)
318
319
if got_Vrep and got_Hrep:
320
raise ValueError('You cannot specify both H- and V-representation.')
321
elif got_Vrep:
322
deduced_ambient_dim = _common_length_of(vertices, rays, lines)[1]
323
elif got_Hrep:
324
deduced_ambient_dim = _common_length_of(ieqs, eqns)[1] - 1
325
else:
326
if ambient_dim is None:
327
deduced_ambient_dim = 0
328
else:
329
deduced_ambient_dim = ambient_dim
330
if base_ring is None:
331
base_ring = ZZ
332
333
# set ambient_dim
334
if ambient_dim is not None and deduced_ambient_dim!=ambient_dim:
335
raise ValueError('Ambient space dimension mismatch. Try removing the "ambient_dim" parameter.')
336
ambient_dim = deduced_ambient_dim
337
338
# figure out base_ring
339
from sage.misc.flatten import flatten
340
values = flatten(vertices+rays+lines+ieqs+eqns)
341
if base_ring is not None:
342
try:
343
convert = not all(x.parent() is base_ring for x in values)
344
except AttributeError: # No x.parent() method?
345
convert = True
346
else:
347
from sage.rings.integer import is_Integer
348
from sage.rings.rational import is_Rational
349
from sage.rings.real_double import is_RealDoubleElement
350
if all(is_Integer(x) for x in values):
351
if got_Vrep:
352
base_ring = ZZ
353
else: # integral inequalities usually do not determine a latice polytope!
354
base_ring = QQ
355
convert=False
356
elif all(is_Rational(x) for x in values):
357
base_ring = QQ
358
convert=False
359
elif all(is_RealDoubleElement(x) for x in values):
360
base_ring = RDF
361
convert=False
362
else:
363
try:
364
map(ZZ, values)
365
if got_Vrep:
366
base_ring = ZZ
367
else:
368
base_ring = QQ
369
convert = True
370
except TypeError:
371
from sage.structure.sequence import Sequence
372
values = Sequence(values)
373
if QQ.has_coerce_map_from(values.universe()):
374
base_ring = QQ
375
convert = True
376
else:
377
base_ring = RDF
378
convert = True
379
380
# Add the origin if necesarry
381
if got_Vrep and len(vertices)==0:
382
vertices = [ [0]*ambient_dim ]
383
384
# Specific backends can override the base_ring
385
from sage.geometry.polyhedron.parent import Polyhedra
386
parent = Polyhedra(base_ring, ambient_dim, backend=backend)
387
base_ring = parent.base_ring()
388
389
# Convert into base_ring if necessary
390
def convert_base_ring(lstlst):
391
return [ [base_ring(x) for x in lst] for lst in lstlst]
392
Hrep = Vrep = None
393
if got_Hrep:
394
Hrep = [ieqs, eqns]
395
if got_Vrep:
396
Vrep = [vertices, rays, lines]
397
398
# finally, construct the Polyhedron
399
return parent(Vrep, Hrep, convert=convert, verbose=verbose)
400
401