Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/geometry/polyhedron/representation.py
8817 views
1
"""
2
H(yperplane) and V(ertex) representation objects for polyhedra
3
"""
4
5
########################################################################
6
# Copyright (C) 2008 Marshall Hampton <[email protected]>
7
# Copyright (C) 2011 Volker Braun <[email protected]>
8
#
9
# Distributed under the terms of the GNU General Public License (GPL)
10
#
11
# http://www.gnu.org/licenses/
12
########################################################################
13
14
15
from sage.structure.sage_object import SageObject
16
from sage.structure.element import is_Vector
17
from sage.rings.all import QQ, ZZ, RDF
18
from sage.modules.free_module_element import vector
19
20
21
22
#########################################################################
23
# PolyhedronRepresentation
24
# / \
25
# / \
26
# Hrepresentation Vrepresentation
27
# / \ / | \
28
# / \ / | \
29
# Inequality Equation Vertex Ray Line
30
31
class PolyhedronRepresentation(SageObject):
32
"""
33
The internal base class for all representation objects of
34
``Polyhedron`` (vertices/rays/lines and inequalites/equations)
35
36
.. note::
37
38
You should not (and cannot) instantiate it yourself. You can
39
only obtain them from a Polyhedron() class.
40
41
TESTS::
42
43
sage: import sage.geometry.polyhedron.representation as P
44
sage: P.PolyhedronRepresentation()
45
<class 'sage.geometry.polyhedron.representation.PolyhedronRepresentation'>
46
"""
47
48
# Numeric values for the output of the type() method
49
INEQUALITY = 0
50
EQUATION = 1
51
VERTEX = 2
52
RAY = 3
53
LINE = 4
54
55
def __len__(self):
56
"""
57
Returns the length of the representation data.
58
59
TESTS::
60
61
sage: p = Polyhedron(vertices=[[1,2,3]])
62
sage: v = p.Vrepresentation(0)
63
sage: v.__len__()
64
3
65
"""
66
return self._vector.degree()
67
68
def __getitem__(self, i):
69
"""
70
Supports indexing.
71
72
TESTS::
73
74
sage: p = Polyhedron(vertices=[[1,2,3]])
75
sage: v = p.Vrepresentation(0)
76
sage: v.__getitem__(1)
77
2
78
"""
79
return self._vector[i]
80
81
def __cmp__(self, other):
82
"""
83
Compare two representation objects
84
85
They are equal if and only if they define the same
86
vertex/ray/line or inequality/equation in the ambient space,
87
regardless of the polyhedron that they belong to.
88
89
INPUT:
90
91
- ``other`` -- anything.
92
93
OUTPUT:
94
95
One of `-1`, `0`, `+1`. ``True`` if and only if ``other`` represents the same
96
H-representation object.
97
98
EXAMPLES::
99
100
sage: triangle = Polyhedron([(0,0), (1,0), (0,1)])
101
sage: ieq = triangle.inequality_generator().next(); ieq
102
An inequality (1, 0) x + 0 >= 0
103
sage: ieq == copy(ieq)
104
True
105
sage: cmp(ieq, copy(ieq))
106
0
107
108
sage: cmp(ieq, 'a string')
109
-1
110
111
sage: square = Polyhedron([(0,0), (1,0), (0,1), (1,1)], base_ring=QQ)
112
sage: cmp(square.Vrepresentation(0), triangle.Vrepresentation(0))
113
0
114
115
sage: ieq = square.Hrepresentation(0); ieq.vector()
116
(0, 1, 0)
117
sage: abs(cmp(ieq, Polyhedron([(0,1,0)]).Vrepresentation(0)))
118
1
119
"""
120
if not isinstance(other, PolyhedronRepresentation):
121
return -1
122
type_cmp = cmp(type(self), type(other))
123
if (type_cmp != 0): return type_cmp
124
return cmp(self._vector, other._vector)
125
126
def vector(self, base_ring=None):
127
"""
128
Returns the vector representation of the H/V-representation object.
129
130
INPUT:
131
132
- ``base_ring`` -- the base ring of the vector.
133
134
OUTPUT:
135
136
For a V-representation object, a vector of length
137
:meth:`~sage.geometry.polyhedron.base.Polyhedron_base.ambient_dim`. For
138
a H-representation object, a vector of length
139
:meth:`~sage.geometry.polyhedron.base.Polyhedron_base.ambient_dim`
140
+ 1.
141
142
EXAMPLES::
143
144
sage: s = polytopes.cuboctahedron()
145
sage: v = s.vertex_generator().next()
146
sage: v
147
A vertex at (-1/2, -1/2, 0)
148
sage: v.vector()
149
(-1/2, -1/2, 0)
150
sage: v()
151
(-1/2, -1/2, 0)
152
sage: type(v())
153
<type 'sage.modules.vector_rational_dense.Vector_rational_dense'>
154
155
Conversion to a different base ring can be forced with the optional argument::
156
157
sage: v.vector(RDF)
158
(-0.5, -0.5, 0.0)
159
sage: vector(RDF, v)
160
(-0.5, -0.5, 0.0)
161
"""
162
if (base_ring is None) or (base_ring is self._base_ring):
163
return self._vector
164
else:
165
return vector(base_ring, self._vector)
166
167
_vector_ = vector
168
169
def polyhedron(self):
170
"""
171
Returns the underlying polyhedron.
172
173
TESTS::
174
175
sage: p = Polyhedron(vertices=[[1,2,3]])
176
sage: v = p.Vrepresentation(0)
177
sage: v.polyhedron()
178
A 0-dimensional polyhedron in ZZ^3 defined as the convex hull of 1 vertex
179
"""
180
return self._polyhedron
181
182
def __call__(self):
183
"""
184
Returns the vector representation of the representation
185
object. Shorthand for the vector() method.
186
187
TESTS::
188
189
sage: p = Polyhedron(vertices=[[1,2,3]])
190
sage: v = p.Vrepresentation(0)
191
sage: v.__call__()
192
(1, 2, 3)
193
"""
194
return self._vector
195
196
def index(self):
197
"""
198
Returns an arbitrary but fixed number according to the internal
199
storage order.
200
201
NOTES:
202
203
H-representation and V-representation objects are enumerated
204
independently. That is, amongst all vertices/rays/lines there
205
will be one with ``index()==0``, and amongs all
206
inequalities/equations there will be one with ``index()==0``,
207
unless the polyhedron is empty or spans the whole space.
208
209
EXAMPLES::
210
211
sage: s = Polyhedron(vertices=[[1],[-1]])
212
sage: first_vertex = s.vertex_generator().next()
213
sage: first_vertex.index()
214
0
215
sage: first_vertex == s.Vrepresentation(0)
216
True
217
"""
218
return self._index
219
220
def __add__(self, coordinate_list):
221
"""
222
Return the coordinates concatenated with ``coordinate_list``.
223
224
INPUT:
225
226
- ``coordinate_list`` -- a list.
227
228
OUTPUT:
229
230
The coordinates of ``self`` concatenated with ``coordinate_list``.
231
232
EXAMPLES::
233
234
sage: p = Polyhedron(ieqs = [[0,1,0],[0,0,1],[1,-1,0,],[1,0,-1]])
235
sage: v = p.Vrepresentation(0); v
236
A vertex at (1, 0)
237
sage: v + [4,5]
238
[1, 0, 4, 5]
239
"""
240
if not isinstance(coordinate_list, list):
241
raise TypeError('Can only concatenate with a list of coordinates')
242
return list(self) + coordinate_list
243
244
def __radd__(self, coordinate_list):
245
"""
246
Return ``coordinate_list`` concatenated with the coordinates.
247
248
INPUT:
249
250
- ``coordinate_list`` -- a list.
251
252
OUTPUT:
253
254
``coordinate_list`` concatenated with the coordinates of ``self``.
255
256
EXAMPLES::
257
258
sage: p = Polyhedron(ieqs = [[0,1,0],[0,0,1],[1,-1,0,],[1,0,-1]])
259
sage: v = p.Vrepresentation(0); v
260
A vertex at (1, 0)
261
sage: [4,5] + v
262
[4, 5, 1, 0]
263
"""
264
if not isinstance(coordinate_list, list):
265
raise TypeError('Can only concatenate with a list of coordinates')
266
return coordinate_list + list(self)
267
268
def count(self, i):
269
"""
270
Count the number of occurrences of ``i`` in the coordinates.
271
272
INPUT:
273
274
- ``i`` -- Anything.
275
276
OUTPUT:
277
278
Integer. The number of occurrences of ``i`` in the coordinates.
279
280
EXAMPLES::
281
282
sage: p = Polyhedron(vertices=[(0,1,1,2,1)])
283
sage: v = p.Vrepresentation(0); v
284
A vertex at (0, 1, 1, 2, 1)
285
sage: v.count(1)
286
3
287
"""
288
return sum([1 for j in self if i==j])
289
290
291
class Hrepresentation(PolyhedronRepresentation):
292
"""
293
The internal base class for H-representation objects of
294
a polyhedron. Inherits from ``PolyhedronRepresentation``.
295
"""
296
297
def __init__(self, polyhedron_parent):
298
"""
299
Initializes the PolyhedronRepresentation object.
300
301
TESTS::
302
303
sage: from sage.geometry.polyhedron.representation import Hrepresentation
304
sage: pr = Hrepresentation(Polyhedron(vertices = [[1,2,3]]).parent())
305
sage: tuple(pr)
306
(0, 0, 0, 0)
307
sage: TestSuite(pr).run(skip='_test_pickling')
308
"""
309
self._polyhedron_parent = polyhedron_parent
310
self._base_ring = polyhedron_parent.base_ring()
311
self._vector = polyhedron_parent.Hrepresentation_space()(0)
312
self._A = polyhedron_parent.ambient_space()(0)
313
self._b = polyhedron_parent.base_ring()(0)
314
self._index = 0
315
316
def _set_data(self, polyhedron, data):
317
"""
318
Initialization function.
319
320
The H/V-representation objects are kept in a pool, and this
321
function is used to reassign new values to already existing
322
(but unused) objects. You must not call this function on
323
objects that are in normal use.
324
325
INPUT:
326
327
- ``polyhedron`` -- the new polyhedron.
328
329
- ``data`` -- the H-representation data.
330
331
TESTS::
332
333
sage: p = Polyhedron(ieqs = [[0,1,0],[0,0,1],[1,-1,0,],[1,0,-1]])
334
sage: pH = p.Hrepresentation(0) # indirect doctest
335
sage: TestSuite(pH).run(skip='_test_pickling')
336
"""
337
assert polyhedron.parent() is self._polyhedron_parent
338
if len(data) != self._vector.degree():
339
raise ValueError, \
340
'H-representation data requires a list of length ambient_dim+1'
341
342
for i in range(0, self._vector.degree()):
343
self._vector.set(i, data[i])
344
for i in range(0, self._A.degree()):
345
self._A.set(i, data[i+1])
346
self._b = self._base_ring(data[0])
347
348
self._index = len(polyhedron._Hrepresentation)
349
polyhedron._Hrepresentation.append(self)
350
self._polyhedron = polyhedron
351
352
def is_H(self):
353
"""
354
Returns True if the object is part of a H-representation
355
(inequality or equation).
356
357
EXAMPLES::
358
359
sage: p = Polyhedron(ieqs = [[0,1,0],[0,0,1],[1,-1,0,],[1,0,-1]])
360
sage: pH = p.Hrepresentation(0)
361
sage: pH.is_H()
362
True
363
"""
364
return True
365
366
def is_inequality(self):
367
"""
368
Returns True if the object is an inequality of the H-representation.
369
370
EXAMPLES::
371
372
sage: p = Polyhedron(ieqs = [[0,1,0],[0,0,1],[1,-1,0,],[1,0,-1]])
373
sage: pH = p.Hrepresentation(0)
374
sage: pH.is_inequality()
375
True
376
"""
377
return False
378
379
def is_equation(self):
380
"""
381
Returns True if the object is an equation of the H-representation.
382
383
EXAMPLES::
384
385
sage: p = Polyhedron(ieqs = [[0,1,0],[0,0,1],[1,-1,0,],[1,0,-1]], eqns = [[1,1,-1]])
386
sage: pH = p.Hrepresentation(0)
387
sage: pH.is_equation()
388
True
389
"""
390
return False
391
392
def A(self):
393
r"""
394
Returns the coefficient vector `A` in `A\vec{x}+b`.
395
396
EXAMPLES::
397
398
sage: p = Polyhedron(ieqs = [[0,1,0],[0,0,1],[1,-1,0,],[1,0,-1]])
399
sage: pH = p.Hrepresentation(2)
400
sage: pH.A()
401
(1, 0)
402
"""
403
return self._A
404
405
def b(self):
406
r"""
407
Returns the constant `b` in `A\vec{x}+b`.
408
409
EXAMPLES::
410
411
sage: p = Polyhedron(ieqs = [[0,1,0],[0,0,1],[1,-1,0,],[1,0,-1]])
412
sage: pH = p.Hrepresentation(2)
413
sage: pH.b()
414
0
415
"""
416
return self._b
417
418
def neighbors(self):
419
"""
420
Iterate over the adjacent facets (i.e. inequalities/equations)
421
422
EXAMPLES::
423
424
sage: p = Polyhedron(ieqs = [[0,0,0,1],[0,0,1,0,],[0,1,0,0],
425
... [1,-1,0,0],[1,0,-1,0,],[1,0,0,-1]])
426
sage: pH = p.Hrepresentation(0)
427
sage: a = list(pH.neighbors())
428
sage: a[0]
429
An inequality (0, -1, 0) x + 1 >= 0
430
sage: list(a[0])
431
[1, 0, -1, 0]
432
"""
433
adjacency_matrix = self.polyhedron().facet_adjacency_matrix()
434
for x in self.polyhedron().Hrep_generator():
435
if adjacency_matrix[self.index(), x.index()] == 1:
436
yield x
437
438
def adjacent(self):
439
"""
440
Alias for neighbors().
441
442
TESTS::
443
444
sage: p = Polyhedron(ieqs = [[0,0,0,2],[0,0,1,0,],[0,10,0,0],
445
... [1,-1,0,0],[1,0,-1,0,],[1,0,0,-1]])
446
sage: pH = p.Hrepresentation(0)
447
sage: a = list(pH.neighbors())
448
sage: b = list(pH.adjacent())
449
sage: a==b
450
True
451
"""
452
return self.neighbors()
453
454
def is_incident(self, Vobj):
455
"""
456
Returns whether the incidence matrix element (Vobj,self) == 1
457
458
EXAMPLES::
459
460
sage: p = Polyhedron(ieqs = [[0,0,0,1],[0,0,1,0,],[0,1,0,0],
461
... [1,-1,0,0],[1,0,-1,0,],[1,0,0,-1]])
462
sage: pH = p.Hrepresentation(0)
463
sage: pH.is_incident(p.Vrepresentation(1))
464
True
465
sage: pH.is_incident(p.Vrepresentation(5))
466
False
467
"""
468
return self.polyhedron().incidence_matrix()[Vobj.index(), self.index()] == 1
469
470
def __mul__(self, Vobj):
471
"""
472
Shorthand for ``self.eval(x)``
473
474
EXAMPLES::
475
476
sage: p = Polyhedron(ieqs = [[0,0,0,1],[0,0,1,0,],[0,1,0,0],
477
... [1,-1,0,0],[1,0,-1,0,],[1,0,0,-1]])
478
sage: pH = p.Hrepresentation(0)
479
sage: pH*p.Vrepresentation(5)
480
1
481
"""
482
return self.eval(Vobj)
483
484
def eval(self, Vobj):
485
r"""
486
Evaluates the left hand side `A\vec{x}+b` on the given
487
vertex/ray/line.
488
489
NOTES:
490
491
* Evaluating on a vertex returns `A\vec{x}+b`
492
* Evaluating on a ray returns `A\vec{r}`. Only the sign or
493
whether it is zero is meaningful.
494
* Evaluating on a line returns `A\vec{l}`. Only whether it
495
is zero or not is meaningful.
496
497
EXAMPLES::
498
499
sage: triangle = Polyhedron(vertices=[[1,0],[0,1],[-1,-1]])
500
sage: ineq = triangle.inequality_generator().next()
501
sage: ineq
502
An inequality (2, -1) x + 1 >= 0
503
sage: [ ineq.eval(v) for v in triangle.vertex_generator() ]
504
[0, 0, 3]
505
sage: [ ineq * v for v in triangle.vertex_generator() ]
506
[0, 0, 3]
507
508
If you pass a vector, it is assumed to be the coordinate vector of a point::
509
510
sage: ineq.eval( vector(ZZ, [3,2]) )
511
5
512
"""
513
if is_Vector(Vobj):
514
return self.A() * Vobj + self.b()
515
return Vobj.evaluated_on(self)
516
517
def incident(self):
518
"""
519
Returns a generator for the incident H-representation objects,
520
that is, the vertices/rays/lines satisfying the (in)equality.
521
522
EXAMPLES::
523
524
sage: triangle = Polyhedron(vertices=[[1,0],[0,1],[-1,-1]])
525
sage: ineq = triangle.inequality_generator().next()
526
sage: ineq
527
An inequality (2, -1) x + 1 >= 0
528
sage: [ v for v in ineq.incident()]
529
[A vertex at (-1, -1), A vertex at (0, 1)]
530
sage: p = Polyhedron(vertices=[[0,0,0],[0,1,0],[0,0,1]], rays=[[1,-1,-1]])
531
sage: ineq = p.Hrepresentation(2)
532
sage: ineq
533
An inequality (1, 0, 1) x + 0 >= 0
534
sage: [ x for x in ineq.incident() ]
535
[A vertex at (0, 0, 0),
536
A vertex at (0, 1, 0),
537
A ray in the direction (1, -1, -1)]
538
"""
539
incidence_matrix = self.polyhedron().incidence_matrix()
540
for V in self.polyhedron().Vrep_generator():
541
if incidence_matrix[V.index(), self.index()] == 1:
542
yield V
543
544
545
class Inequality(Hrepresentation):
546
"""
547
A linear inequality (supporting hyperplane) of the
548
polyhedron. Inherits from ``Hrepresentation``.
549
"""
550
551
def type(self):
552
r"""
553
Returns the type (equation/inequality/vertex/ray/line) as an
554
integer.
555
556
OUTPUT:
557
558
Integer. One of ``PolyhedronRepresentation.INEQUALITY``,
559
``.EQUATION``, ``.VERTEX``, ``.RAY``, or ``.LINE``.
560
561
EXAMPLES::
562
563
sage: p = Polyhedron(vertices = [[0,0,0],[1,1,0],[1,2,0]])
564
sage: repr_obj = p.inequality_generator().next()
565
sage: repr_obj.type()
566
0
567
sage: repr_obj.type() == repr_obj.INEQUALITY
568
True
569
sage: repr_obj.type() == repr_obj.EQUATION
570
False
571
sage: repr_obj.type() == repr_obj.VERTEX
572
False
573
sage: repr_obj.type() == repr_obj.RAY
574
False
575
sage: repr_obj.type() == repr_obj.LINE
576
False
577
"""
578
return self.INEQUALITY
579
580
581
def is_inequality(self):
582
"""
583
Returns True since this is, by construction, an inequality.
584
585
EXAMPLES::
586
587
sage: p = Polyhedron(vertices = [[0,0,0],[1,1,0],[1,2,0]])
588
sage: a = p.inequality_generator().next()
589
sage: a.is_inequality()
590
True
591
"""
592
return True
593
594
def _repr_(self):
595
"""
596
The string representation of the inequality.
597
598
EXAMPLES::
599
600
sage: p = Polyhedron(vertices = [[0,0,0],[1,1,0],[1,2,0]])
601
sage: a = p.inequality_generator().next()
602
sage: a._repr_()
603
'An inequality (-1, 1, 0) x + 0 >= 0'
604
sage: Polyhedron(ieqs=[(1,-1),(-1,2)]).Hrepresentation()
605
(An inequality (-1) x + 1 >= 0, An inequality (2) x - 1 >= 0)
606
sage: Polyhedron(eqns=[(1,0)]).Hrepresentation()
607
(An equation -1 == 0,)
608
sage: Polyhedron(eqns=[(-1,0)]).Hrepresentation()
609
(An equation -1 == 0,)
610
"""
611
s = 'An inequality '
612
have_A = not self.A().is_zero()
613
if have_A:
614
s += repr(self.A()) + ' x '
615
if self.b()>=0:
616
if have_A:
617
s += '+'
618
else:
619
s += '-'
620
if have_A:
621
s += ' '
622
s += repr(abs(self.b())) + ' >= 0'
623
return s
624
625
def contains(self, Vobj):
626
"""
627
Tests whether the halfspace (including its boundary) defined
628
by the inequality contains the given vertex/ray/line.
629
630
EXAMPLES::
631
632
sage: p = polytopes.cross_polytope(3)
633
sage: i1 = p.inequality_generator().next()
634
sage: [i1.contains(q) for q in p.vertex_generator()]
635
[True, True, True, True, True, True]
636
sage: p2 = 3*polytopes.n_cube(3)
637
sage: [i1.contains(q) for q in p2.vertex_generator()]
638
[True, False, False, False, True, True, True, False]
639
"""
640
try:
641
if Vobj.is_vector(): # assume we were passed a point
642
return self.polyhedron()._is_nonneg( self.eval(Vobj) )
643
except AttributeError:
644
pass
645
646
if Vobj.is_line():
647
return self.polyhedron()._is_zero( self.eval(Vobj) )
648
else:
649
return self.polyhedron()._is_nonneg( self.eval(Vobj) )
650
651
def interior_contains(self, Vobj):
652
"""
653
Tests whether the interior of the halfspace (excluding its
654
boundary) defined by the inequality contains the given
655
vertex/ray/line.
656
657
EXAMPLES::
658
659
sage: p = polytopes.cross_polytope(3)
660
sage: i1 = p.inequality_generator().next()
661
sage: [i1.interior_contains(q) for q in p.vertex_generator()]
662
[False, True, True, False, False, True]
663
sage: p2 = 3*polytopes.n_cube(3)
664
sage: [i1.interior_contains(q) for q in p2.vertex_generator()]
665
[True, False, False, False, True, True, True, False]
666
667
If you pass a vector, it is assumed to be the coordinate vector of a point::
668
669
sage: P = Polyhedron(vertices=[[1,1],[1,-1],[-1,1],[-1,-1]])
670
sage: p = vector(ZZ, [1,0] )
671
sage: [ ieq.interior_contains(p) for ieq in P.inequality_generator() ]
672
[True, True, False, True]
673
"""
674
try:
675
if Vobj.is_vector(): # assume we were passed a point
676
return self.polyhedron()._is_positive( self.eval(Vobj) )
677
except AttributeError:
678
pass
679
680
if Vobj.is_line():
681
return self.polyhedron()._is_zero( self.eval(Vobj) )
682
elif Vobj.is_vertex():
683
return self.polyhedron()._is_positive( self.eval(Vobj) )
684
else: # Vobj.is_ray()
685
return self.polyhedron()._is_nonneg( self.eval(Vobj) )
686
687
688
class Equation(Hrepresentation):
689
"""
690
A linear equation of the polyhedron. That is, the polyhedron is
691
strictly smaller-dimensional than the ambient space, and contained
692
in this hyperplane. Inherits from ``Hrepresentation``.
693
"""
694
695
def type(self):
696
r"""
697
Returns the type (equation/inequality/vertex/ray/line) as an
698
integer.
699
700
OUTPUT:
701
702
Integer. One of ``PolyhedronRepresentation.INEQUALITY``,
703
``.EQUATION``, ``.VERTEX``, ``.RAY``, or ``.LINE``.
704
705
EXAMPLES::
706
707
sage: p = Polyhedron(vertices = [[0,0,0],[1,1,0],[1,2,0]])
708
sage: repr_obj = p.equation_generator().next()
709
sage: repr_obj.type()
710
1
711
sage: repr_obj.type() == repr_obj.INEQUALITY
712
False
713
sage: repr_obj.type() == repr_obj.EQUATION
714
True
715
sage: repr_obj.type() == repr_obj.VERTEX
716
False
717
sage: repr_obj.type() == repr_obj.RAY
718
False
719
sage: repr_obj.type() == repr_obj.LINE
720
False
721
"""
722
return self.EQUATION
723
724
725
def is_equation(self):
726
"""
727
Tests if this object is an equation. By construction, it must be.
728
729
TESTS::
730
731
sage: p = Polyhedron(vertices = [[0,0,0],[1,1,0],[1,2,0]])
732
sage: a = p.equation_generator().next()
733
sage: a.is_equation()
734
True
735
"""
736
return True
737
738
def _repr_(self):
739
"""
740
A string representation of this object.
741
742
TESTS::
743
744
sage: p = Polyhedron(vertices = [[0,0,0],[1,1,0],[1,2,0]])
745
sage: a = p.equation_generator().next()
746
sage: a._repr_()
747
'An equation (0, 0, 1) x + 0 == 0'
748
sage: Polyhedron().Hrepresentation(0)
749
An equation -1 == 0
750
"""
751
s = 'An equation '
752
have_A = not self.A().is_zero()
753
if have_A:
754
s += repr(self.A()) + ' x '
755
if self.b()>=0:
756
if have_A:
757
s += '+'
758
else:
759
s += '-'
760
if have_A:
761
s += ' '
762
s += repr(abs(self.b())) + ' == 0'
763
return s
764
765
def contains(self, Vobj):
766
"""
767
Tests whether the hyperplane defined by the equation contains
768
the given vertex/ray/line.
769
770
EXAMPLES::
771
772
sage: p = Polyhedron(vertices = [[0,0,0],[1,1,0],[1,2,0]])
773
sage: v = p.vertex_generator().next()
774
sage: v
775
A vertex at (0, 0, 0)
776
sage: a = p.equation_generator().next()
777
sage: a
778
An equation (0, 0, 1) x + 0 == 0
779
sage: a.contains(v)
780
True
781
"""
782
return self.polyhedron()._is_zero( self.eval(Vobj) )
783
784
def interior_contains(self, Vobj):
785
"""
786
Tests whether the interior of the halfspace (excluding its
787
boundary) defined by the inequality contains the given
788
vertex/ray/line.
789
790
NOTE:
791
792
Returns False for any equation.
793
794
EXAMPLES::
795
796
sage: p = Polyhedron(vertices = [[0,0,0],[1,1,0],[1,2,0]])
797
sage: v = p.vertex_generator().next()
798
sage: v
799
A vertex at (0, 0, 0)
800
sage: a = p.equation_generator().next()
801
sage: a
802
An equation (0, 0, 1) x + 0 == 0
803
sage: a.interior_contains(v)
804
False
805
"""
806
return False
807
808
809
class Vrepresentation(PolyhedronRepresentation):
810
"""
811
The base class for V-representation objects of a
812
polyhedron. Inherits from ``PolyhedronRepresentation``.
813
"""
814
815
def __init__(self, polyhedron_parent):
816
"""
817
Initializes the PolyhedronRepresentation object.
818
819
TESTS::
820
821
sage: p = Polyhedron(vertices = [[0,0,0],[1,1,0],[1,2,0]])
822
sage: a = p.inequality_generator().next()
823
sage: a
824
An inequality (-1, 1, 0) x + 0 >= 0
825
sage: TestSuite(a).run(skip='_test_pickling')
826
"""
827
self._polyhedron_parent = polyhedron_parent
828
self._base_ring = polyhedron_parent.base_ring()
829
self._vector = polyhedron_parent.Vrepresentation_space()(0)
830
self._index = 0
831
832
def _set_data(self, polyhedron, data):
833
"""
834
Initialization function.
835
836
The H/V-representation objects are kept in a pool, and this
837
function is used to reassign new values to already existing
838
(but unused) objects. You must not call this function on
839
objects that are in normal use.
840
841
INPUT:
842
843
- ``polyhedron`` -- the new polyhedron.
844
845
- ``data`` -- the V-representation data.
846
847
TESTS::
848
849
sage: p = Polyhedron(ieqs = [[0,1,0],[0,0,1],[1,-1,0,],[1,0,-1]])
850
sage: pV = p.Vrepresentation(0) # indirect doctest
851
sage: TestSuite(pV).run(skip='_test_pickling')
852
"""
853
assert polyhedron.parent() is self._polyhedron_parent
854
if len(data) != self._vector.degree():
855
raise ValueError, \
856
'V-representation data requires a list of length ambient_dim'
857
858
for i in range(0, self._vector.degree()):
859
self._vector.set(i, data[i])
860
861
self._index = len(polyhedron._Vrepresentation)
862
polyhedron._Vrepresentation.append(self)
863
self._polyhedron = polyhedron
864
865
def is_V(self):
866
"""
867
Returns True if the object is part of a V-representation
868
(a vertex, ray, or line).
869
870
EXAMPLES::
871
872
sage: p = Polyhedron(vertices = [[0,0],[1,0],[0,3],[1,3]])
873
sage: v = p.vertex_generator().next()
874
sage: v.is_V()
875
True
876
"""
877
return True
878
879
def is_vertex(self):
880
"""
881
Returns True if the object is a vertex of the V-representation.
882
This method is over-ridden by the corresponding method in the
883
derived class Vertex.
884
885
EXAMPLES::
886
887
sage: p = Polyhedron(vertices = [[0,0],[1,0],[0,3],[1,3]])
888
sage: v = p.vertex_generator().next()
889
sage: v.is_vertex()
890
True
891
sage: p = Polyhedron(ieqs = [[1, 0, 0, 0, 1], [1, 1, 0, 0, 0], [1, 0, 1, 0, 0]])
892
sage: r1 = p.ray_generator().next()
893
sage: r1.is_vertex()
894
False
895
"""
896
return False
897
898
def is_ray(self):
899
"""
900
Returns True if the object is a ray of the V-representation.
901
This method is over-ridden by the corresponding method in the
902
derived class Ray.
903
904
EXAMPLES::
905
906
sage: p = Polyhedron(ieqs = [[1, 0, 0, 0, 1], [1, 1, 0, 0, 0], [1, 0, 1, 0, 0]])
907
sage: r1 = p.ray_generator().next()
908
sage: r1.is_ray()
909
True
910
sage: v1 = p.vertex_generator().next()
911
sage: v1
912
A vertex at (-1, -1, 0, -1)
913
sage: v1.is_ray()
914
False
915
"""
916
return False
917
918
def is_line(self):
919
"""
920
Returns True if the object is a line of the V-representation.
921
This method is over-ridden by the corresponding method in the
922
derived class Line.
923
924
EXAMPLES::
925
926
sage: p = Polyhedron(ieqs = [[1, 0, 0, 0, 1], [1, 1, 0, 0, 0], [1, 0, 1, 0, 0]])
927
sage: line1 = p.line_generator().next()
928
sage: line1.is_line()
929
True
930
sage: v1 = p.vertex_generator().next()
931
sage: v1.is_line()
932
False
933
"""
934
return False
935
936
def neighbors(self):
937
"""
938
Returns a generator for the adjacent vertices/rays/lines.
939
940
EXAMPLES::
941
942
sage: p = Polyhedron(vertices = [[0,0],[1,0],[0,3],[1,4]])
943
sage: v = p.vertex_generator().next()
944
sage: v.neighbors().next()
945
A vertex at (0, 3)
946
"""
947
adjacency_matrix = self.polyhedron().vertex_adjacency_matrix()
948
for x in self.polyhedron().Vrep_generator():
949
if adjacency_matrix[self.index(), x.index()] == 1:
950
yield x
951
952
def adjacent(self):
953
"""
954
Alias for neighbors().
955
956
TESTS::
957
958
sage: p = Polyhedron(vertices = [[0,0],[1,0],[0,3],[1,4]])
959
sage: v = p.vertex_generator().next()
960
sage: a = v.neighbors().next()
961
sage: b = v.adjacent().next()
962
sage: a==b
963
True
964
"""
965
return self.neighbors()
966
967
def is_incident(self, Hobj):
968
"""
969
Returns whether the incidence matrix element (self,Hobj) == 1
970
971
EXAMPLES::
972
973
sage: p = polytopes.n_cube(3)
974
sage: h1 = p.inequality_generator().next()
975
sage: h1
976
An inequality (0, 0, -1) x + 1 >= 0
977
sage: v1 = p.vertex_generator().next()
978
sage: v1
979
A vertex at (-1, -1, -1)
980
sage: v1.is_incident(h1)
981
False
982
"""
983
return self.polyhedron().incidence_matrix()[self.index(), Hobj.index()] == 1
984
985
def __mul__(self, Hobj):
986
"""
987
Shorthand for self.evaluated_on(Hobj)
988
989
TESTS::
990
991
sage: p = polytopes.n_cube(3)
992
sage: h1 = p.inequality_generator().next()
993
sage: v1 = p.vertex_generator().next()
994
sage: v1.__mul__(h1)
995
2
996
"""
997
return self.evaluated_on(Hobj)
998
999
def incident(self):
1000
"""
1001
Returns a generator for the equations/inequalities that are satisfied on the given
1002
vertex/ray/line.
1003
1004
EXAMPLES::
1005
1006
sage: triangle = Polyhedron(vertices=[[1,0],[0,1],[-1,-1]])
1007
sage: ineq = triangle.inequality_generator().next()
1008
sage: ineq
1009
An inequality (2, -1) x + 1 >= 0
1010
sage: [ v for v in ineq.incident()]
1011
[A vertex at (-1, -1), A vertex at (0, 1)]
1012
sage: p = Polyhedron(vertices=[[0,0,0],[0,1,0],[0,0,1]], rays=[[1,-1,-1]])
1013
sage: ineq = p.Hrepresentation(2)
1014
sage: ineq
1015
An inequality (1, 0, 1) x + 0 >= 0
1016
sage: [ x for x in ineq.incident() ]
1017
[A vertex at (0, 0, 0),
1018
A vertex at (0, 1, 0),
1019
A ray in the direction (1, -1, -1)]
1020
"""
1021
incidence_matrix = self.polyhedron().incidence_matrix()
1022
for H in self.polyhedron().Hrep_generator():
1023
if incidence_matrix[self.index(), H.index()] == 1:
1024
yield H
1025
1026
1027
class Vertex(Vrepresentation):
1028
"""
1029
A vertex of the polyhedron. Inherits from ``Vrepresentation``.
1030
"""
1031
1032
def type(self):
1033
r"""
1034
Returns the type (equation/inequality/vertex/ray/line) as an
1035
integer.
1036
1037
OUTPUT:
1038
1039
Integer. One of ``PolyhedronRepresentation.INEQUALITY``,
1040
``.EQUATION``, ``.VERTEX``, ``.RAY``, or ``.LINE``.
1041
1042
EXAMPLES::
1043
1044
sage: p = Polyhedron(vertices = [[0,0,0],[1,1,0],[1,2,0]])
1045
sage: repr_obj = p.vertex_generator().next()
1046
sage: repr_obj.type()
1047
2
1048
sage: repr_obj.type() == repr_obj.INEQUALITY
1049
False
1050
sage: repr_obj.type() == repr_obj.EQUATION
1051
False
1052
sage: repr_obj.type() == repr_obj.VERTEX
1053
True
1054
sage: repr_obj.type() == repr_obj.RAY
1055
False
1056
sage: repr_obj.type() == repr_obj.LINE
1057
False
1058
"""
1059
return self.VERTEX
1060
1061
1062
def is_vertex(self):
1063
"""
1064
Tests if this object is a vertex. By construction it always is.
1065
1066
EXAMPLES::
1067
1068
sage: p = Polyhedron(ieqs = [[0,0,1],[0,1,0],[1,-1,0]])
1069
sage: a = p.vertex_generator().next()
1070
sage: a.is_vertex()
1071
True
1072
"""
1073
return True
1074
1075
def _repr_(self):
1076
"""
1077
Returns a string representation of the vertex.
1078
1079
OUTPUT:
1080
1081
String.
1082
1083
TESTS::
1084
1085
sage: p = Polyhedron(ieqs = [[0,0,1],[0,1,0],[1,-1,0]])
1086
sage: v = p.vertex_generator().next()
1087
sage: v.__repr__()
1088
'A vertex at (1, 0)'
1089
"""
1090
return 'A vertex at ' + repr(self.vector());
1091
1092
def evaluated_on(self, Hobj):
1093
r"""
1094
Returns `A\vec{x}+b`
1095
1096
EXAMPLES::
1097
1098
sage: p = polytopes.n_cube(3)
1099
sage: v = p.vertex_generator().next()
1100
sage: h = p.inequality_generator().next()
1101
sage: v
1102
A vertex at (-1, -1, -1)
1103
sage: h
1104
An inequality (0, 0, -1) x + 1 >= 0
1105
sage: v.evaluated_on(h)
1106
2
1107
"""
1108
return Hobj.A() * self.vector() + Hobj.b()
1109
1110
def is_integral(self):
1111
r"""
1112
Return whether the coordinates of the vertex are all integral.
1113
1114
OUTPUT:
1115
1116
Boolean.
1117
1118
EXAMPLES::
1119
1120
sage: p = Polyhedron([(1/2,3,5), (0,0,0), (2,3,7)])
1121
sage: [ v.is_integral() for v in p.vertex_generator() ]
1122
[True, False, True]
1123
"""
1124
return (self._base_ring is ZZ) or all(x in ZZ for x in self)
1125
1126
1127
class Ray(Vrepresentation):
1128
"""
1129
A ray of the polyhedron. Inherits from ``Vrepresentation``.
1130
"""
1131
1132
def type(self):
1133
r"""
1134
Returns the type (equation/inequality/vertex/ray/line) as an
1135
integer.
1136
1137
OUTPUT:
1138
1139
Integer. One of ``PolyhedronRepresentation.INEQUALITY``,
1140
``.EQUATION``, ``.VERTEX``, ``.RAY``, or ``.LINE``.
1141
1142
EXAMPLES::
1143
1144
sage: p = Polyhedron(ieqs = [[0,0,1],[0,1,0],[1,-1,0]])
1145
sage: repr_obj = p.ray_generator().next()
1146
sage: repr_obj.type()
1147
3
1148
sage: repr_obj.type() == repr_obj.INEQUALITY
1149
False
1150
sage: repr_obj.type() == repr_obj.EQUATION
1151
False
1152
sage: repr_obj.type() == repr_obj.VERTEX
1153
False
1154
sage: repr_obj.type() == repr_obj.RAY
1155
True
1156
sage: repr_obj.type() == repr_obj.LINE
1157
False
1158
"""
1159
return self.RAY
1160
1161
1162
def is_ray(self):
1163
"""
1164
Tests if this object is a ray. Always True by construction.
1165
1166
EXAMPLES::
1167
1168
sage: p = Polyhedron(ieqs = [[0,0,1],[0,1,0],[1,-1,0]])
1169
sage: a = p.ray_generator().next()
1170
sage: a.is_ray()
1171
True
1172
"""
1173
return True
1174
1175
def _repr_(self):
1176
"""
1177
A string representation of the ray.
1178
1179
TESTS::
1180
1181
sage: p = Polyhedron(ieqs = [[0,0,1],[0,1,0],[1,-1,0]])
1182
sage: a = p.ray_generator().next()
1183
sage: a._repr_()
1184
'A ray in the direction (0, 1)'
1185
"""
1186
return 'A ray in the direction ' + repr(self.vector());
1187
1188
def evaluated_on(self, Hobj):
1189
r"""
1190
Returns `A\vec{r}`
1191
1192
EXAMPLES::
1193
1194
sage: p = Polyhedron(ieqs = [[0,0,1],[0,1,0],[1,-1,0]])
1195
sage: a = p.ray_generator().next()
1196
sage: h = p.inequality_generator().next()
1197
sage: a.evaluated_on(h)
1198
0
1199
"""
1200
return Hobj.A() * self.vector()
1201
1202
1203
class Line(Vrepresentation):
1204
r"""
1205
A line (Minkowski summand `\simeq\RR`) of the
1206
polyhedron. Inherits from ``Vrepresentation``.
1207
"""
1208
1209
def type(self):
1210
r"""
1211
Returns the type (equation/inequality/vertex/ray/line) as an
1212
integer.
1213
1214
OUTPUT:
1215
1216
Integer. One of ``PolyhedronRepresentation.INEQUALITY``,
1217
``.EQUATION``, ``.VERTEX``, ``.RAY``, or ``.LINE``.
1218
1219
EXAMPLES::
1220
1221
sage: p = Polyhedron(ieqs = [[1, 0, 0, 1],[1,1,0,0]])
1222
sage: repr_obj = p.line_generator().next()
1223
sage: repr_obj.type()
1224
4
1225
sage: repr_obj.type() == repr_obj.INEQUALITY
1226
False
1227
sage: repr_obj.type() == repr_obj.EQUATION
1228
False
1229
sage: repr_obj.type() == repr_obj.VERTEX
1230
False
1231
sage: repr_obj.type() == repr_obj.RAY
1232
False
1233
sage: repr_obj.type() == repr_obj.LINE
1234
True
1235
"""
1236
return self.LINE
1237
1238
def is_line(self):
1239
"""
1240
Tests if the object is a line. By construction it must be.
1241
1242
TESTS::
1243
1244
sage: p = Polyhedron(ieqs = [[1, 0, 0, 1],[1,1,0,0]])
1245
sage: a = p.line_generator().next()
1246
sage: a.is_line()
1247
True
1248
"""
1249
return True
1250
1251
def _repr_(self):
1252
"""
1253
A string representation of the line.
1254
1255
TESTS::
1256
1257
sage: p = Polyhedron(ieqs = [[1, 0, 0, 1],[1,1,0,0]])
1258
sage: a = p.line_generator().next()
1259
sage: a.__repr__()
1260
'A line in the direction (0, 1, 0)'
1261
"""
1262
return 'A line in the direction ' + repr(self.vector());
1263
1264
def evaluated_on(self, Hobj):
1265
r"""
1266
Returns `A\vec{\ell}`
1267
1268
EXAMPLES::
1269
1270
sage: p = Polyhedron(ieqs = [[1, 0, 0, 1],[1,1,0,0]])
1271
sage: a = p.line_generator().next()
1272
sage: h = p.inequality_generator().next()
1273
sage: a.evaluated_on(h)
1274
0
1275
"""
1276
return Hobj.A() * self.vector()
1277
1278
1279
1280