passagemath-polyhedra 10.6.37__cp314-cp314-musllinux_1_2_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- passagemath_polyhedra/__init__.py +3 -0
- passagemath_polyhedra-10.6.37.dist-info/METADATA +367 -0
- passagemath_polyhedra-10.6.37.dist-info/METADATA.bak +369 -0
- passagemath_polyhedra-10.6.37.dist-info/RECORD +209 -0
- passagemath_polyhedra-10.6.37.dist-info/WHEEL +5 -0
- passagemath_polyhedra-10.6.37.dist-info/top_level.txt +3 -0
- passagemath_polyhedra.libs/libgcc_s-0cd532bd.so.1 +0 -0
- passagemath_polyhedra.libs/libgmp-0e7fc84e.so.10.5.0 +0 -0
- passagemath_polyhedra.libs/libgomp-8949ffbe.so.1.0.0 +0 -0
- passagemath_polyhedra.libs/libstdc++-5d72f927.so.6.0.33 +0 -0
- sage/all__sagemath_polyhedra.py +50 -0
- sage/game_theory/all.py +8 -0
- sage/game_theory/catalog.py +6 -0
- sage/game_theory/catalog_normal_form_games.py +923 -0
- sage/game_theory/cooperative_game.py +844 -0
- sage/game_theory/matching_game.py +1181 -0
- sage/game_theory/normal_form_game.py +2697 -0
- sage/game_theory/parser.py +275 -0
- sage/geometry/all__sagemath_polyhedra.py +22 -0
- sage/geometry/cone.py +6940 -0
- sage/geometry/cone_catalog.py +847 -0
- sage/geometry/cone_critical_angles.py +1027 -0
- sage/geometry/convex_set.py +1119 -0
- sage/geometry/fan.py +3743 -0
- sage/geometry/fan_isomorphism.py +389 -0
- sage/geometry/fan_morphism.py +1884 -0
- sage/geometry/hasse_diagram.py +202 -0
- sage/geometry/hyperplane_arrangement/affine_subspace.py +390 -0
- sage/geometry/hyperplane_arrangement/all.py +1 -0
- sage/geometry/hyperplane_arrangement/arrangement.py +3905 -0
- sage/geometry/hyperplane_arrangement/check_freeness.py +145 -0
- sage/geometry/hyperplane_arrangement/hyperplane.py +773 -0
- sage/geometry/hyperplane_arrangement/library.py +825 -0
- sage/geometry/hyperplane_arrangement/ordered_arrangement.py +642 -0
- sage/geometry/hyperplane_arrangement/plot.py +520 -0
- sage/geometry/integral_points.py +35 -0
- sage/geometry/integral_points_generic_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/integral_points_generic_dense.pyx +7 -0
- sage/geometry/lattice_polytope.py +5894 -0
- sage/geometry/linear_expression.py +773 -0
- sage/geometry/newton_polygon.py +767 -0
- sage/geometry/point_collection.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/point_collection.pyx +1008 -0
- sage/geometry/polyhedral_complex.py +2616 -0
- sage/geometry/polyhedron/all.py +8 -0
- sage/geometry/polyhedron/backend_cdd.py +460 -0
- sage/geometry/polyhedron/backend_cdd_rdf.py +231 -0
- sage/geometry/polyhedron/backend_field.py +347 -0
- sage/geometry/polyhedron/backend_normaliz.py +2503 -0
- sage/geometry/polyhedron/backend_number_field.py +168 -0
- sage/geometry/polyhedron/backend_polymake.py +765 -0
- sage/geometry/polyhedron/backend_ppl.py +582 -0
- sage/geometry/polyhedron/base.py +1206 -0
- sage/geometry/polyhedron/base0.py +1444 -0
- sage/geometry/polyhedron/base1.py +886 -0
- sage/geometry/polyhedron/base2.py +812 -0
- sage/geometry/polyhedron/base3.py +1845 -0
- sage/geometry/polyhedron/base4.py +1262 -0
- sage/geometry/polyhedron/base5.py +2700 -0
- sage/geometry/polyhedron/base6.py +1741 -0
- sage/geometry/polyhedron/base7.py +997 -0
- sage/geometry/polyhedron/base_QQ.py +1258 -0
- sage/geometry/polyhedron/base_RDF.py +98 -0
- sage/geometry/polyhedron/base_ZZ.py +934 -0
- sage/geometry/polyhedron/base_mutable.py +215 -0
- sage/geometry/polyhedron/base_number_field.py +122 -0
- sage/geometry/polyhedron/cdd_file_format.py +155 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/all.py +1 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/base.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd +76 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +3859 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pxd +39 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx +1038 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/conversions.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pxd +9 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx +501 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_data_structure.pxd +207 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd +102 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +2274 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pxd +370 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pyx +84 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pxd +31 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx +587 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pxd +52 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx +560 -0
- sage/geometry/polyhedron/constructor.py +773 -0
- sage/geometry/polyhedron/double_description.py +753 -0
- sage/geometry/polyhedron/double_description_inhomogeneous.py +564 -0
- sage/geometry/polyhedron/face.py +1060 -0
- sage/geometry/polyhedron/generating_function.py +1810 -0
- sage/geometry/polyhedron/lattice_euclidean_group_element.py +178 -0
- sage/geometry/polyhedron/library.py +3502 -0
- sage/geometry/polyhedron/misc.py +121 -0
- sage/geometry/polyhedron/modules/all.py +1 -0
- sage/geometry/polyhedron/modules/formal_polyhedra_module.py +155 -0
- sage/geometry/polyhedron/palp_database.py +447 -0
- sage/geometry/polyhedron/parent.py +1279 -0
- sage/geometry/polyhedron/plot.py +1986 -0
- sage/geometry/polyhedron/ppl_lattice_polygon.py +556 -0
- sage/geometry/polyhedron/ppl_lattice_polytope.py +1257 -0
- sage/geometry/polyhedron/representation.py +1723 -0
- sage/geometry/pseudolines.py +515 -0
- sage/geometry/relative_interior.py +445 -0
- sage/geometry/toric_plotter.py +1103 -0
- sage/geometry/triangulation/all.py +2 -0
- sage/geometry/triangulation/base.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/triangulation/base.pyx +963 -0
- sage/geometry/triangulation/data.h +147 -0
- sage/geometry/triangulation/data.pxd +4 -0
- sage/geometry/triangulation/element.py +914 -0
- sage/geometry/triangulation/functions.h +10 -0
- sage/geometry/triangulation/functions.pxd +4 -0
- sage/geometry/triangulation/point_configuration.py +2256 -0
- sage/geometry/triangulation/triangulations.h +49 -0
- sage/geometry/triangulation/triangulations.pxd +7 -0
- sage/geometry/voronoi_diagram.py +319 -0
- sage/interfaces/all__sagemath_polyhedra.py +1 -0
- sage/interfaces/polymake.py +2028 -0
- sage/numerical/all.py +13 -0
- sage/numerical/all__sagemath_polyhedra.py +11 -0
- sage/numerical/backends/all.py +1 -0
- sage/numerical/backends/all__sagemath_polyhedra.py +1 -0
- sage/numerical/backends/cvxopt_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/cvxopt_backend.pyx +1006 -0
- sage/numerical/backends/cvxopt_backend_test.py +19 -0
- sage/numerical/backends/cvxopt_sdp_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/cvxopt_sdp_backend.pyx +382 -0
- sage/numerical/backends/cvxpy_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/cvxpy_backend.pxd +41 -0
- sage/numerical/backends/cvxpy_backend.pyx +934 -0
- sage/numerical/backends/cvxpy_backend_test.py +13 -0
- sage/numerical/backends/generic_backend_test.py +24 -0
- sage/numerical/backends/interactivelp_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/interactivelp_backend.pxd +36 -0
- sage/numerical/backends/interactivelp_backend.pyx +1231 -0
- sage/numerical/backends/interactivelp_backend_test.py +12 -0
- sage/numerical/backends/logging_backend.py +391 -0
- sage/numerical/backends/matrix_sdp_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/matrix_sdp_backend.pxd +15 -0
- sage/numerical/backends/matrix_sdp_backend.pyx +478 -0
- sage/numerical/backends/ppl_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/ppl_backend.pyx +1126 -0
- sage/numerical/backends/ppl_backend_test.py +13 -0
- sage/numerical/backends/scip_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/scip_backend.pxd +22 -0
- sage/numerical/backends/scip_backend.pyx +1289 -0
- sage/numerical/backends/scip_backend_test.py +13 -0
- sage/numerical/interactive_simplex_method.py +5338 -0
- sage/numerical/knapsack.py +665 -0
- sage/numerical/linear_functions.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/linear_functions.pxd +31 -0
- sage/numerical/linear_functions.pyx +1648 -0
- sage/numerical/linear_tensor.py +470 -0
- sage/numerical/linear_tensor_constraints.py +448 -0
- sage/numerical/linear_tensor_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/linear_tensor_element.pxd +6 -0
- sage/numerical/linear_tensor_element.pyx +459 -0
- sage/numerical/mip.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/mip.pxd +40 -0
- sage/numerical/mip.pyx +3667 -0
- sage/numerical/sdp.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/sdp.pxd +39 -0
- sage/numerical/sdp.pyx +1433 -0
- sage/rings/all__sagemath_polyhedra.py +3 -0
- sage/rings/polynomial/all__sagemath_polyhedra.py +10 -0
- sage/rings/polynomial/omega.py +982 -0
- sage/schemes/all__sagemath_polyhedra.py +2 -0
- sage/schemes/toric/all.py +10 -0
- sage/schemes/toric/chow_group.py +1248 -0
- sage/schemes/toric/divisor.py +2082 -0
- sage/schemes/toric/divisor_class.cpython-314-x86_64-linux-musl.so +0 -0
- sage/schemes/toric/divisor_class.pyx +322 -0
- sage/schemes/toric/fano_variety.py +1606 -0
- sage/schemes/toric/homset.py +650 -0
- sage/schemes/toric/ideal.py +451 -0
- sage/schemes/toric/library.py +1322 -0
- sage/schemes/toric/morphism.py +1958 -0
- sage/schemes/toric/points.py +1032 -0
- sage/schemes/toric/sheaf/all.py +1 -0
- sage/schemes/toric/sheaf/constructor.py +302 -0
- sage/schemes/toric/sheaf/klyachko.py +921 -0
- sage/schemes/toric/toric_subscheme.py +905 -0
- sage/schemes/toric/variety.py +3460 -0
- sage/schemes/toric/weierstrass.py +1078 -0
- sage/schemes/toric/weierstrass_covering.py +457 -0
- sage/schemes/toric/weierstrass_higher.py +288 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.info +10 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v03 +0 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v04 +0 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v05 +1 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v06 +1 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.info +22 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v04 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v05 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v06 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v07 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v08 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v09 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v10 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v11 +1 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v12 +1 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v13 +1 -0
- sage_wheels/share/reflexive_polytopes/reflexive_polytopes_2d +80 -0
- sage_wheels/share/reflexive_polytopes/reflexive_polytopes_3d +37977 -0
|
@@ -0,0 +1,1060 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-polyhedra
|
|
2
|
+
"""
|
|
3
|
+
A class to keep information about faces of a polyhedron
|
|
4
|
+
|
|
5
|
+
This module gives you a tool to work with the faces of a polyhedron
|
|
6
|
+
and their relative position. First, you need to find the faces. To get
|
|
7
|
+
the faces in a particular dimension, use the
|
|
8
|
+
:meth:`~sage.geometry.polyhedron.base.face` method::
|
|
9
|
+
|
|
10
|
+
sage: P = polytopes.cross_polytope(3)
|
|
11
|
+
sage: P.faces(3)
|
|
12
|
+
(A 3-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 6 vertices,)
|
|
13
|
+
sage: [f.ambient_V_indices() for f in P.facets()]
|
|
14
|
+
[(3, 4, 5),
|
|
15
|
+
(2, 4, 5),
|
|
16
|
+
(1, 3, 5),
|
|
17
|
+
(1, 2, 5),
|
|
18
|
+
(0, 3, 4),
|
|
19
|
+
(0, 2, 4),
|
|
20
|
+
(0, 1, 3),
|
|
21
|
+
(0, 1, 2)]
|
|
22
|
+
sage: [f.ambient_V_indices() for f in P.faces(1)]
|
|
23
|
+
[(4, 5),
|
|
24
|
+
(3, 5),
|
|
25
|
+
(2, 5),
|
|
26
|
+
(1, 5),
|
|
27
|
+
(3, 4),
|
|
28
|
+
(2, 4),
|
|
29
|
+
(0, 4),
|
|
30
|
+
(1, 3),
|
|
31
|
+
(0, 3),
|
|
32
|
+
(1, 2),
|
|
33
|
+
(0, 2),
|
|
34
|
+
(0, 1)]
|
|
35
|
+
|
|
36
|
+
or :meth:`~sage.geometry.polyhedron.base.face_lattice` to get the
|
|
37
|
+
whole face lattice as a poset::
|
|
38
|
+
|
|
39
|
+
sage: P.face_lattice() # needs sage.combinat
|
|
40
|
+
Finite lattice containing 28 elements
|
|
41
|
+
|
|
42
|
+
The faces are printed in shorthand notation where each integer is the
|
|
43
|
+
index of a vertex/ray/line in the same order as the containing
|
|
44
|
+
Polyhedron's :meth:`~sage.geometry.polyhedron.base.Vrepresentation` ::
|
|
45
|
+
|
|
46
|
+
sage: face = P.faces(1)[8]; face
|
|
47
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices
|
|
48
|
+
sage: face.ambient_V_indices()
|
|
49
|
+
(0, 3)
|
|
50
|
+
sage: P.Vrepresentation(0)
|
|
51
|
+
A vertex at (-1, 0, 0)
|
|
52
|
+
sage: P.Vrepresentation(3)
|
|
53
|
+
A vertex at (0, 0, 1)
|
|
54
|
+
sage: face.vertices()
|
|
55
|
+
(A vertex at (-1, 0, 0), A vertex at (0, 0, 1))
|
|
56
|
+
|
|
57
|
+
The face itself is not represented by Sage's
|
|
58
|
+
:func:`sage.geometry.polyhedron.constructor.Polyhedron` class, but by
|
|
59
|
+
an auxiliary class to keep the information. You can get the face as a
|
|
60
|
+
polyhedron with the :meth:`PolyhedronFace.as_polyhedron` method::
|
|
61
|
+
|
|
62
|
+
sage: face.as_polyhedron()
|
|
63
|
+
A 1-dimensional polyhedron in ZZ^3 defined as the convex hull of 2 vertices
|
|
64
|
+
sage: _.equations()
|
|
65
|
+
(An equation (0, 1, 0) x + 0 == 0,
|
|
66
|
+
An equation (1, 0, -1) x + 1 == 0)
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
########################################################################
|
|
70
|
+
# Copyright (C) 2012 Volker Braun <vbraun.name@gmail.com>
|
|
71
|
+
#
|
|
72
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
73
|
+
#
|
|
74
|
+
# http://www.gnu.org/licenses/
|
|
75
|
+
########################################################################
|
|
76
|
+
|
|
77
|
+
from sage.structure.richcmp import richcmp_method, richcmp
|
|
78
|
+
from sage.misc.cachefunc import cached_method
|
|
79
|
+
from sage.modules.free_module_element import vector
|
|
80
|
+
from sage.matrix.constructor import matrix
|
|
81
|
+
from sage.geometry.convex_set import ConvexSet_closed
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
#########################################################################
|
|
85
|
+
@richcmp_method
|
|
86
|
+
class PolyhedronFace(ConvexSet_closed):
|
|
87
|
+
r"""
|
|
88
|
+
A face of a polyhedron.
|
|
89
|
+
|
|
90
|
+
This class is for use in
|
|
91
|
+
:meth:`~sage.geometry.polyhedron.base.Polyhedron_base.face_lattice`.
|
|
92
|
+
|
|
93
|
+
INPUT:
|
|
94
|
+
|
|
95
|
+
No checking is performed whether the H/V-representation indices
|
|
96
|
+
actually determine a face of the polyhedron. You should not
|
|
97
|
+
manually create :class:`PolyhedronFace` objects unless you know
|
|
98
|
+
what you are doing.
|
|
99
|
+
|
|
100
|
+
OUTPUT: a :class:`PolyhedronFace`
|
|
101
|
+
|
|
102
|
+
EXAMPLES::
|
|
103
|
+
|
|
104
|
+
sage: octahedron = polytopes.cross_polytope(3)
|
|
105
|
+
sage: inequality = octahedron.Hrepresentation(2)
|
|
106
|
+
sage: face_h = tuple([ inequality ])
|
|
107
|
+
sage: face_v = tuple( inequality.incident() )
|
|
108
|
+
sage: face_h_indices = [ h.index() for h in face_h ]
|
|
109
|
+
sage: face_v_indices = [ v.index() for v in face_v ]
|
|
110
|
+
sage: from sage.geometry.polyhedron.face import PolyhedronFace
|
|
111
|
+
sage: face = PolyhedronFace(octahedron, face_v_indices, face_h_indices)
|
|
112
|
+
sage: face
|
|
113
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 3 vertices
|
|
114
|
+
sage: face.dim()
|
|
115
|
+
2
|
|
116
|
+
sage: face.ambient_V_indices()
|
|
117
|
+
(0, 1, 2)
|
|
118
|
+
sage: face.ambient_Hrepresentation()
|
|
119
|
+
(An inequality (1, 1, 1) x + 1 >= 0,)
|
|
120
|
+
sage: face.ambient_Vrepresentation()
|
|
121
|
+
(A vertex at (-1, 0, 0), A vertex at (0, -1, 0), A vertex at (0, 0, -1))
|
|
122
|
+
|
|
123
|
+
TESTS::
|
|
124
|
+
|
|
125
|
+
sage: TestSuite(face).run()
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
def __init__(self, polyhedron, V_indices, H_indices):
|
|
129
|
+
r"""
|
|
130
|
+
The constructor.
|
|
131
|
+
|
|
132
|
+
See :class:`PolyhedronFace` for more information.
|
|
133
|
+
|
|
134
|
+
INPUT:
|
|
135
|
+
|
|
136
|
+
- ``polyhedron`` -- a :class:`Polyhedron`; the ambient
|
|
137
|
+
polyhedron
|
|
138
|
+
|
|
139
|
+
- ``V_indices`` -- list of sorted integers; the indices of the
|
|
140
|
+
face-spanning V-representation objects in the ambient
|
|
141
|
+
polyhedron
|
|
142
|
+
|
|
143
|
+
- ``H_indices`` -- list of sorted integers; the indices of the
|
|
144
|
+
H-representation objects of the ambient polyhedron that are
|
|
145
|
+
saturated on the face
|
|
146
|
+
|
|
147
|
+
TESTS::
|
|
148
|
+
|
|
149
|
+
sage: from sage.geometry.polyhedron.face import PolyhedronFace
|
|
150
|
+
sage: PolyhedronFace(Polyhedron(), [], []) # indirect doctest
|
|
151
|
+
A -1-dimensional face of a Polyhedron in ZZ^0
|
|
152
|
+
sage: TestSuite(_).run(skip='_test_pickling')
|
|
153
|
+
"""
|
|
154
|
+
self._polyhedron = polyhedron
|
|
155
|
+
self._ambient_Vrepresentation_indices = tuple(V_indices)
|
|
156
|
+
self._ambient_Hrepresentation_indices = tuple(H_indices)
|
|
157
|
+
self._ambient_Vrepresentation = tuple(polyhedron.Vrepresentation(i) for i in V_indices)
|
|
158
|
+
self._ambient_Hrepresentation = tuple(polyhedron.Hrepresentation(i) for i in H_indices)
|
|
159
|
+
if polyhedron.is_mutable():
|
|
160
|
+
polyhedron._add_dependent_object(self)
|
|
161
|
+
|
|
162
|
+
def __hash__(self):
|
|
163
|
+
r"""
|
|
164
|
+
TESTS::
|
|
165
|
+
|
|
166
|
+
sage: P = Polyhedron([[0,0],[0,1],[23,3],[9,12]])
|
|
167
|
+
sage: list(map(hash, P.faces(1))) # random
|
|
168
|
+
[2377119663630407734,
|
|
169
|
+
2377136578164722109,
|
|
170
|
+
5966674064902575359,
|
|
171
|
+
4795242501625591634]
|
|
172
|
+
"""
|
|
173
|
+
return hash((self._polyhedron, self._ambient_Vrepresentation_indices))
|
|
174
|
+
|
|
175
|
+
def vertex_generator(self):
|
|
176
|
+
"""
|
|
177
|
+
Return a generator for the vertices of the face.
|
|
178
|
+
|
|
179
|
+
EXAMPLES::
|
|
180
|
+
|
|
181
|
+
sage: triangle = Polyhedron(vertices=[[1,0],[0,1],[1,1]])
|
|
182
|
+
sage: face = triangle.facets()[0]
|
|
183
|
+
sage: for v in face.vertex_generator(): print(v)
|
|
184
|
+
A vertex at (1, 0)
|
|
185
|
+
A vertex at (1, 1)
|
|
186
|
+
sage: type(face.vertex_generator())
|
|
187
|
+
<... 'generator'>
|
|
188
|
+
|
|
189
|
+
TESTS::
|
|
190
|
+
|
|
191
|
+
sage: TestSuite(face).run(skip='_test_pickling')
|
|
192
|
+
"""
|
|
193
|
+
for V in self.ambient_Vrepresentation():
|
|
194
|
+
if V.is_vertex():
|
|
195
|
+
yield V
|
|
196
|
+
|
|
197
|
+
@cached_method
|
|
198
|
+
def vertices(self):
|
|
199
|
+
"""
|
|
200
|
+
Return all vertices of the face.
|
|
201
|
+
|
|
202
|
+
OUTPUT: a tuple of vertices
|
|
203
|
+
|
|
204
|
+
EXAMPLES::
|
|
205
|
+
|
|
206
|
+
sage: triangle = Polyhedron(vertices=[[1,0],[0,1],[1,1]])
|
|
207
|
+
sage: face = triangle.faces(1)[2]
|
|
208
|
+
sage: face.vertices()
|
|
209
|
+
(A vertex at (0, 1), A vertex at (1, 0))
|
|
210
|
+
|
|
211
|
+
TESTS::
|
|
212
|
+
|
|
213
|
+
sage: TestSuite(face).run(skip='_test_pickling')
|
|
214
|
+
"""
|
|
215
|
+
return tuple(self.vertex_generator())
|
|
216
|
+
|
|
217
|
+
@cached_method
|
|
218
|
+
def n_vertices(self):
|
|
219
|
+
"""
|
|
220
|
+
Return the number of vertices of the face.
|
|
221
|
+
|
|
222
|
+
OUTPUT: integer
|
|
223
|
+
|
|
224
|
+
EXAMPLES::
|
|
225
|
+
|
|
226
|
+
sage: Q = polytopes.cross_polytope(3)
|
|
227
|
+
sage: face = Q.faces(2)[0]
|
|
228
|
+
sage: face.n_vertices()
|
|
229
|
+
3
|
|
230
|
+
|
|
231
|
+
TESTS::
|
|
232
|
+
|
|
233
|
+
sage: TestSuite(face).run(skip='_test_pickling')
|
|
234
|
+
"""
|
|
235
|
+
return len(self.vertices())
|
|
236
|
+
|
|
237
|
+
def ray_generator(self):
|
|
238
|
+
"""
|
|
239
|
+
Return a generator for the rays of the face.
|
|
240
|
+
|
|
241
|
+
EXAMPLES::
|
|
242
|
+
|
|
243
|
+
sage: pi = Polyhedron(ieqs = [[1,1,0],[1,0,1]])
|
|
244
|
+
sage: face = pi.faces(1)[1]
|
|
245
|
+
sage: next(face.ray_generator())
|
|
246
|
+
A ray in the direction (1, 0)
|
|
247
|
+
|
|
248
|
+
TESTS::
|
|
249
|
+
|
|
250
|
+
sage: TestSuite(face).run(skip='_test_pickling')
|
|
251
|
+
"""
|
|
252
|
+
for V in self.ambient_Vrepresentation():
|
|
253
|
+
if V.is_ray():
|
|
254
|
+
yield V
|
|
255
|
+
|
|
256
|
+
@cached_method
|
|
257
|
+
def rays(self):
|
|
258
|
+
"""
|
|
259
|
+
Return the rays of the face.
|
|
260
|
+
|
|
261
|
+
OUTPUT: a tuple of rays
|
|
262
|
+
|
|
263
|
+
EXAMPLES::
|
|
264
|
+
|
|
265
|
+
sage: p = Polyhedron(ieqs = [[0,0,0,1],[0,0,1,0],[1,1,0,0]])
|
|
266
|
+
sage: face = p.faces(2)[2]
|
|
267
|
+
sage: face.rays()
|
|
268
|
+
(A ray in the direction (1, 0, 0), A ray in the direction (0, 1, 0))
|
|
269
|
+
"""
|
|
270
|
+
return tuple(self.ray_generator())
|
|
271
|
+
|
|
272
|
+
@cached_method
|
|
273
|
+
def n_rays(self):
|
|
274
|
+
"""
|
|
275
|
+
Return the number of rays of the face.
|
|
276
|
+
|
|
277
|
+
OUTPUT: integer
|
|
278
|
+
|
|
279
|
+
EXAMPLES::
|
|
280
|
+
|
|
281
|
+
sage: p = Polyhedron(ieqs = [[0,0,0,1],[0,0,1,0],[1,1,0,0]])
|
|
282
|
+
sage: face = p.faces(2)[0]
|
|
283
|
+
sage: face.n_rays()
|
|
284
|
+
2
|
|
285
|
+
"""
|
|
286
|
+
return len(self.rays())
|
|
287
|
+
|
|
288
|
+
def line_generator(self):
|
|
289
|
+
"""
|
|
290
|
+
Return a generator for the lines of the face.
|
|
291
|
+
|
|
292
|
+
EXAMPLES::
|
|
293
|
+
|
|
294
|
+
sage: pr = Polyhedron(rays = [[1,0],[-1,0],[0,1]], vertices = [[-1,-1]])
|
|
295
|
+
sage: face = pr.faces(1)[0]
|
|
296
|
+
sage: next(face.line_generator())
|
|
297
|
+
A line in the direction (1, 0)
|
|
298
|
+
|
|
299
|
+
TESTS::
|
|
300
|
+
|
|
301
|
+
sage: TestSuite(face).run(skip='_test_pickling')
|
|
302
|
+
"""
|
|
303
|
+
for V in self.ambient_Vrepresentation():
|
|
304
|
+
if V.is_line():
|
|
305
|
+
yield V
|
|
306
|
+
|
|
307
|
+
@cached_method
|
|
308
|
+
def lines(self):
|
|
309
|
+
"""
|
|
310
|
+
Return all lines of the face.
|
|
311
|
+
|
|
312
|
+
OUTPUT: a tuple of lines
|
|
313
|
+
|
|
314
|
+
EXAMPLES::
|
|
315
|
+
|
|
316
|
+
sage: p = Polyhedron(rays = [[1,0],[-1,0],[0,1],[1,1]], vertices = [[-2,-2],[2,3]])
|
|
317
|
+
sage: p.lines()
|
|
318
|
+
(A line in the direction (1, 0),)
|
|
319
|
+
"""
|
|
320
|
+
return tuple(self.line_generator())
|
|
321
|
+
|
|
322
|
+
@cached_method
|
|
323
|
+
def n_lines(self):
|
|
324
|
+
"""
|
|
325
|
+
Return the number of lines of the face.
|
|
326
|
+
|
|
327
|
+
OUTPUT: integer
|
|
328
|
+
|
|
329
|
+
EXAMPLES::
|
|
330
|
+
|
|
331
|
+
sage: p = Polyhedron(rays = [[1,0],[-1,0],[0,1],[1,1]], vertices = [[-2,-2],[2,3]])
|
|
332
|
+
sage: p.n_lines()
|
|
333
|
+
1
|
|
334
|
+
"""
|
|
335
|
+
return len(self.lines())
|
|
336
|
+
|
|
337
|
+
def __richcmp__(self, other, op):
|
|
338
|
+
"""
|
|
339
|
+
Compare ``self`` and ``other``.
|
|
340
|
+
|
|
341
|
+
INPUT:
|
|
342
|
+
|
|
343
|
+
- ``other`` -- anything
|
|
344
|
+
|
|
345
|
+
OUTPUT:
|
|
346
|
+
|
|
347
|
+
Two faces test equal if and only if they are faces of the same
|
|
348
|
+
(not just isomorphic) polyhedron and their generators have the
|
|
349
|
+
same indices.
|
|
350
|
+
|
|
351
|
+
EXAMPLES::
|
|
352
|
+
|
|
353
|
+
sage: square = polytopes.hypercube(2)
|
|
354
|
+
sage: f = square.faces(1)
|
|
355
|
+
sage: matrix(4,4, lambda i,j: ZZ(f[i] <= f[j]))
|
|
356
|
+
[1 1 1 0]
|
|
357
|
+
[0 1 0 0]
|
|
358
|
+
[0 1 1 0]
|
|
359
|
+
[1 1 1 1]
|
|
360
|
+
sage: matrix(4,4, lambda i,j: ZZ(f[i] == f[j])) == 1
|
|
361
|
+
True
|
|
362
|
+
"""
|
|
363
|
+
if not isinstance(other, PolyhedronFace):
|
|
364
|
+
return NotImplemented
|
|
365
|
+
if self._polyhedron is not other._polyhedron:
|
|
366
|
+
if (self._polyhedron.Vrepresentation() != other._polyhedron.Vrepresentation()
|
|
367
|
+
or self._polyhedron.Hrepresentation() != other._polyhedron.Hrepresentation()):
|
|
368
|
+
return NotImplemented
|
|
369
|
+
return richcmp(self._ambient_Vrepresentation_indices,
|
|
370
|
+
other._ambient_Vrepresentation_indices, op)
|
|
371
|
+
|
|
372
|
+
def ambient_Hrepresentation(self, index=None):
|
|
373
|
+
r"""
|
|
374
|
+
Return the H-representation objects of the ambient polytope
|
|
375
|
+
defining the face.
|
|
376
|
+
|
|
377
|
+
INPUT:
|
|
378
|
+
|
|
379
|
+
- ``index`` -- integer or ``None`` (default)
|
|
380
|
+
|
|
381
|
+
OUTPUT:
|
|
382
|
+
|
|
383
|
+
If the optional argument is not present, a tuple of
|
|
384
|
+
H-representation objects. Each entry is either an inequality
|
|
385
|
+
or an equation.
|
|
386
|
+
|
|
387
|
+
If the optional integer ``index`` is specified, the
|
|
388
|
+
``index``-th element of the tuple is returned.
|
|
389
|
+
|
|
390
|
+
EXAMPLES::
|
|
391
|
+
|
|
392
|
+
sage: square = polytopes.hypercube(2)
|
|
393
|
+
sage: for face in square.face_lattice(): # needs sage.combinat
|
|
394
|
+
....: print(face.ambient_Hrepresentation())
|
|
395
|
+
(An inequality (-1, 0) x + 1 >= 0, An inequality (0, -1) x + 1 >= 0,
|
|
396
|
+
An inequality (1, 0) x + 1 >= 0, An inequality (0, 1) x + 1 >= 0)
|
|
397
|
+
(An inequality (-1, 0) x + 1 >= 0, An inequality (0, 1) x + 1 >= 0)
|
|
398
|
+
(An inequality (-1, 0) x + 1 >= 0, An inequality (0, -1) x + 1 >= 0)
|
|
399
|
+
(An inequality (-1, 0) x + 1 >= 0,)
|
|
400
|
+
(An inequality (0, -1) x + 1 >= 0, An inequality (1, 0) x + 1 >= 0)
|
|
401
|
+
(An inequality (0, -1) x + 1 >= 0,)
|
|
402
|
+
(An inequality (1, 0) x + 1 >= 0, An inequality (0, 1) x + 1 >= 0)
|
|
403
|
+
(An inequality (0, 1) x + 1 >= 0,)
|
|
404
|
+
(An inequality (1, 0) x + 1 >= 0,)
|
|
405
|
+
()
|
|
406
|
+
"""
|
|
407
|
+
if index is None:
|
|
408
|
+
return self._ambient_Hrepresentation
|
|
409
|
+
else:
|
|
410
|
+
return self._ambient_Hrepresentation[index]
|
|
411
|
+
|
|
412
|
+
def ambient_Vrepresentation(self, index=None):
|
|
413
|
+
r"""
|
|
414
|
+
Return the V-representation objects of the ambient polytope
|
|
415
|
+
defining the face.
|
|
416
|
+
|
|
417
|
+
INPUT:
|
|
418
|
+
|
|
419
|
+
- ``index`` -- integer or ``None`` (default)
|
|
420
|
+
|
|
421
|
+
OUTPUT:
|
|
422
|
+
|
|
423
|
+
If the optional argument is not present, a tuple of
|
|
424
|
+
V-representation objects. Each entry is either a vertex, a
|
|
425
|
+
ray, or a line.
|
|
426
|
+
|
|
427
|
+
If the optional integer ``index`` is specified, the
|
|
428
|
+
``index``-th element of the tuple is returned.
|
|
429
|
+
|
|
430
|
+
EXAMPLES::
|
|
431
|
+
|
|
432
|
+
sage: square = polytopes.hypercube(2)
|
|
433
|
+
sage: for fl in square.face_lattice(): # needs sage.combinat
|
|
434
|
+
....: print(fl.ambient_Vrepresentation())
|
|
435
|
+
()
|
|
436
|
+
(A vertex at (1, -1),)
|
|
437
|
+
(A vertex at (1, 1),)
|
|
438
|
+
(A vertex at (1, -1), A vertex at (1, 1))
|
|
439
|
+
(A vertex at (-1, 1),)
|
|
440
|
+
(A vertex at (1, 1), A vertex at (-1, 1))
|
|
441
|
+
(A vertex at (-1, -1),)
|
|
442
|
+
(A vertex at (1, -1), A vertex at (-1, -1))
|
|
443
|
+
(A vertex at (-1, 1), A vertex at (-1, -1))
|
|
444
|
+
(A vertex at (1, -1), A vertex at (1, 1),
|
|
445
|
+
A vertex at (-1, 1), A vertex at (-1, -1))
|
|
446
|
+
"""
|
|
447
|
+
if index is None:
|
|
448
|
+
return self._ambient_Vrepresentation
|
|
449
|
+
else:
|
|
450
|
+
return self._ambient_Vrepresentation[index]
|
|
451
|
+
|
|
452
|
+
def n_ambient_Hrepresentation(self):
|
|
453
|
+
"""
|
|
454
|
+
Return the number of objects that make up the ambient
|
|
455
|
+
H-representation of the polyhedron.
|
|
456
|
+
|
|
457
|
+
See also :meth:`ambient_Hrepresentation`.
|
|
458
|
+
|
|
459
|
+
OUTPUT: integer
|
|
460
|
+
|
|
461
|
+
EXAMPLES::
|
|
462
|
+
|
|
463
|
+
sage: p = polytopes.cross_polytope(4)
|
|
464
|
+
sage: face = p.face_lattice()[5]; face # needs sage.combinat
|
|
465
|
+
A 1-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 2 vertices
|
|
466
|
+
sage: face.ambient_Hrepresentation() # needs sage.combinat
|
|
467
|
+
(An inequality (1, -1, 1, -1) x + 1 >= 0,
|
|
468
|
+
An inequality (1, 1, 1, 1) x + 1 >= 0,
|
|
469
|
+
An inequality (1, 1, 1, -1) x + 1 >= 0,
|
|
470
|
+
An inequality (1, -1, 1, 1) x + 1 >= 0)
|
|
471
|
+
sage: face.n_ambient_Hrepresentation() # needs sage.combinat
|
|
472
|
+
4
|
|
473
|
+
"""
|
|
474
|
+
return len(self.ambient_Hrepresentation())
|
|
475
|
+
|
|
476
|
+
def n_ambient_Vrepresentation(self):
|
|
477
|
+
"""
|
|
478
|
+
Return the number of objects that make up the ambient
|
|
479
|
+
V-representation of the polyhedron.
|
|
480
|
+
|
|
481
|
+
See also :meth:`ambient_Vrepresentation`.
|
|
482
|
+
|
|
483
|
+
OUTPUT: integer
|
|
484
|
+
|
|
485
|
+
EXAMPLES::
|
|
486
|
+
|
|
487
|
+
sage: p = polytopes.cross_polytope(4)
|
|
488
|
+
sage: face = p.face_lattice()[5]; face # needs sage.combinat
|
|
489
|
+
A 1-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 2 vertices
|
|
490
|
+
sage: face.ambient_Vrepresentation() # needs sage.combinat
|
|
491
|
+
(A vertex at (-1, 0, 0, 0), A vertex at (0, 0, -1, 0))
|
|
492
|
+
sage: face.n_ambient_Vrepresentation() # needs sage.combinat
|
|
493
|
+
2
|
|
494
|
+
"""
|
|
495
|
+
return len(self.ambient_Vrepresentation())
|
|
496
|
+
|
|
497
|
+
def ambient_H_indices(self):
|
|
498
|
+
"""
|
|
499
|
+
Return the indices of the H-representation objects of the
|
|
500
|
+
ambient polyhedron that make up the H-representation of ``self``.
|
|
501
|
+
|
|
502
|
+
See also :meth:`ambient_Hrepresentation`.
|
|
503
|
+
|
|
504
|
+
OUTPUT: tuple of indices
|
|
505
|
+
|
|
506
|
+
EXAMPLES::
|
|
507
|
+
|
|
508
|
+
sage: Q = polytopes.cross_polytope(3)
|
|
509
|
+
sage: F = Q.faces(1)
|
|
510
|
+
sage: [f.ambient_H_indices() for f in F]
|
|
511
|
+
[(4, 5),
|
|
512
|
+
(5, 6),
|
|
513
|
+
(4, 7),
|
|
514
|
+
(6, 7),
|
|
515
|
+
(0, 5),
|
|
516
|
+
(3, 4),
|
|
517
|
+
(0, 3),
|
|
518
|
+
(1, 6),
|
|
519
|
+
(0, 1),
|
|
520
|
+
(2, 7),
|
|
521
|
+
(2, 3),
|
|
522
|
+
(1, 2)]
|
|
523
|
+
"""
|
|
524
|
+
return self._ambient_Hrepresentation_indices
|
|
525
|
+
|
|
526
|
+
def ambient_V_indices(self):
|
|
527
|
+
"""
|
|
528
|
+
Return the indices of the V-representation objects of the
|
|
529
|
+
ambient polyhedron that make up the V-representation of ``self``.
|
|
530
|
+
|
|
531
|
+
See also :meth:`ambient_Vrepresentation`.
|
|
532
|
+
|
|
533
|
+
OUTPUT: tuple of indices
|
|
534
|
+
|
|
535
|
+
EXAMPLES::
|
|
536
|
+
|
|
537
|
+
sage: P = polytopes.cube()
|
|
538
|
+
sage: F = P.faces(2)
|
|
539
|
+
sage: [f.ambient_V_indices() for f in F]
|
|
540
|
+
[(0, 3, 4, 5),
|
|
541
|
+
(0, 1, 5, 6),
|
|
542
|
+
(4, 5, 6, 7),
|
|
543
|
+
(2, 3, 4, 7),
|
|
544
|
+
(1, 2, 6, 7),
|
|
545
|
+
(0, 1, 2, 3)]
|
|
546
|
+
"""
|
|
547
|
+
return self._ambient_Vrepresentation_indices
|
|
548
|
+
|
|
549
|
+
def ambient_dim(self):
|
|
550
|
+
r"""
|
|
551
|
+
Return the dimension of the containing polyhedron.
|
|
552
|
+
|
|
553
|
+
EXAMPLES::
|
|
554
|
+
|
|
555
|
+
sage: P = Polyhedron(vertices = [[1,0,0,0],[0,1,0,0]])
|
|
556
|
+
sage: face = P.faces(1)[0]
|
|
557
|
+
sage: face.ambient_dim()
|
|
558
|
+
4
|
|
559
|
+
"""
|
|
560
|
+
return self._polyhedron.ambient_dim()
|
|
561
|
+
|
|
562
|
+
@cached_method
|
|
563
|
+
def dim(self):
|
|
564
|
+
"""
|
|
565
|
+
Return the dimension of the face.
|
|
566
|
+
|
|
567
|
+
OUTPUT: integer
|
|
568
|
+
|
|
569
|
+
EXAMPLES::
|
|
570
|
+
|
|
571
|
+
sage: fl = polytopes.dodecahedron().face_lattice() # needs sage.combinat sage.rings.number_field
|
|
572
|
+
sage: sorted(x.dim() for x in fl) # needs sage.combinat sage.rings.number_field
|
|
573
|
+
[-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
574
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
575
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3]
|
|
576
|
+
|
|
577
|
+
TESTS:
|
|
578
|
+
|
|
579
|
+
Check that :issue:`28650` is fixed::
|
|
580
|
+
|
|
581
|
+
sage: P = Polyhedron(vertices=[[1,0]], rays=[[1,0], [0,1]])
|
|
582
|
+
sage: P.faces(2)
|
|
583
|
+
(A 2-dimensional face of a Polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays,)
|
|
584
|
+
"""
|
|
585
|
+
if self.n_ambient_Vrepresentation() == 0:
|
|
586
|
+
return -1
|
|
587
|
+
else:
|
|
588
|
+
origin = self.vertices()[0].vector()
|
|
589
|
+
v_list = [vector(v) - origin for v in
|
|
590
|
+
self.ambient_Vrepresentation() if v.is_vertex()]
|
|
591
|
+
v_list += [vector(v) for v in self.ambient_Vrepresentation()
|
|
592
|
+
if v.is_ray() or v.is_line()]
|
|
593
|
+
return matrix(v_list).rank()
|
|
594
|
+
|
|
595
|
+
def _repr_(self):
|
|
596
|
+
r"""
|
|
597
|
+
Return a string representation.
|
|
598
|
+
|
|
599
|
+
OUTPUT: a string listing the V-representation indices of the face
|
|
600
|
+
|
|
601
|
+
EXAMPLES::
|
|
602
|
+
|
|
603
|
+
sage: square = polytopes.hypercube(2)
|
|
604
|
+
sage: a_face = list( square.face_lattice() )[8] # needs sage.combinat
|
|
605
|
+
sage: a_face.__repr__() # needs sage.combinat
|
|
606
|
+
'A 1-dimensional face of a Polyhedron in ZZ^2 defined as the convex hull of 2 vertices'
|
|
607
|
+
"""
|
|
608
|
+
desc = ''
|
|
609
|
+
desc += 'A ' + repr(self.dim()) + '-dimensional face'
|
|
610
|
+
desc += ' of a Polyhedron in '
|
|
611
|
+
desc += self.polyhedron().parent()._repr_ambient_module()
|
|
612
|
+
|
|
613
|
+
if self.n_vertices() > 0:
|
|
614
|
+
desc += ' defined as the convex hull of '
|
|
615
|
+
desc += repr(self.n_vertices())
|
|
616
|
+
if self.n_vertices() == 1:
|
|
617
|
+
desc += ' vertex'
|
|
618
|
+
else:
|
|
619
|
+
desc += ' vertices'
|
|
620
|
+
|
|
621
|
+
if self.n_rays() > 0:
|
|
622
|
+
if self.n_lines() > 0:
|
|
623
|
+
desc += ", "
|
|
624
|
+
else:
|
|
625
|
+
desc += " and "
|
|
626
|
+
desc += repr(self.n_rays())
|
|
627
|
+
if self.n_rays() == 1:
|
|
628
|
+
desc += ' ray'
|
|
629
|
+
else:
|
|
630
|
+
desc += ' rays'
|
|
631
|
+
|
|
632
|
+
if self.n_lines() > 0:
|
|
633
|
+
if self.n_rays() > 0:
|
|
634
|
+
desc += ", "
|
|
635
|
+
else:
|
|
636
|
+
desc += " and "
|
|
637
|
+
desc += repr(self.n_lines())
|
|
638
|
+
if self.n_lines() == 1:
|
|
639
|
+
desc += ' line'
|
|
640
|
+
else:
|
|
641
|
+
desc += ' lines'
|
|
642
|
+
|
|
643
|
+
return desc
|
|
644
|
+
|
|
645
|
+
def polyhedron(self):
|
|
646
|
+
"""
|
|
647
|
+
Return the containing polyhedron.
|
|
648
|
+
|
|
649
|
+
EXAMPLES::
|
|
650
|
+
|
|
651
|
+
sage: P = polytopes.cross_polytope(3); P
|
|
652
|
+
A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 6 vertices
|
|
653
|
+
sage: face = P.facets()[3]; face
|
|
654
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 3 vertices
|
|
655
|
+
sage: face.polyhedron()
|
|
656
|
+
A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 6 vertices
|
|
657
|
+
"""
|
|
658
|
+
return self._polyhedron
|
|
659
|
+
|
|
660
|
+
ambient = polyhedron
|
|
661
|
+
|
|
662
|
+
def ambient_vector_space(self, base_field=None):
|
|
663
|
+
r"""
|
|
664
|
+
Return the ambient vector space.
|
|
665
|
+
|
|
666
|
+
It is the ambient free module of the containing polyhedron tensored
|
|
667
|
+
with a field.
|
|
668
|
+
|
|
669
|
+
INPUT:
|
|
670
|
+
|
|
671
|
+
- ``base_field`` -- a field (default: the fraction field of the base ring)
|
|
672
|
+
|
|
673
|
+
EXAMPLES::
|
|
674
|
+
|
|
675
|
+
sage: half_plane = Polyhedron(ieqs=[(0,1,0)])
|
|
676
|
+
sage: line = half_plane.faces(1)[0]; line
|
|
677
|
+
A 1-dimensional face of a
|
|
678
|
+
Polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line
|
|
679
|
+
sage: line.ambient_vector_space()
|
|
680
|
+
Vector space of dimension 2 over Rational Field
|
|
681
|
+
sage: line.ambient_vector_space(AA) # needs sage.rings.number_field
|
|
682
|
+
Vector space of dimension 2 over Algebraic Real Field
|
|
683
|
+
"""
|
|
684
|
+
return self.polyhedron().ambient_vector_space(base_field=base_field)
|
|
685
|
+
|
|
686
|
+
def is_relatively_open(self):
|
|
687
|
+
r"""
|
|
688
|
+
Return whether ``self`` is relatively open.
|
|
689
|
+
|
|
690
|
+
OUTPUT: boolean
|
|
691
|
+
|
|
692
|
+
EXAMPLES::
|
|
693
|
+
|
|
694
|
+
sage: half_plane = Polyhedron(ieqs=[(0,1,0)])
|
|
695
|
+
sage: line = half_plane.faces(1)[0]; line
|
|
696
|
+
A 1-dimensional face of a
|
|
697
|
+
Polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line
|
|
698
|
+
sage: line.is_relatively_open()
|
|
699
|
+
True
|
|
700
|
+
"""
|
|
701
|
+
return self.as_polyhedron().is_relatively_open()
|
|
702
|
+
|
|
703
|
+
def is_compact(self):
|
|
704
|
+
r"""
|
|
705
|
+
Return whether ``self`` is compact.
|
|
706
|
+
|
|
707
|
+
OUTPUT: boolean
|
|
708
|
+
|
|
709
|
+
EXAMPLES::
|
|
710
|
+
|
|
711
|
+
sage: half_plane = Polyhedron(ieqs=[(0,1,0)])
|
|
712
|
+
sage: line = half_plane.faces(1)[0]; line
|
|
713
|
+
A 1-dimensional face of a
|
|
714
|
+
Polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line
|
|
715
|
+
sage: line.is_compact()
|
|
716
|
+
False
|
|
717
|
+
"""
|
|
718
|
+
return not any(V.is_ray() or V.is_line()
|
|
719
|
+
for V in self.ambient_Vrepresentation())
|
|
720
|
+
|
|
721
|
+
@cached_method
|
|
722
|
+
def as_polyhedron(self, **kwds):
|
|
723
|
+
"""
|
|
724
|
+
Return the face as an independent polyhedron.
|
|
725
|
+
|
|
726
|
+
OUTPUT: a polyhedron
|
|
727
|
+
|
|
728
|
+
EXAMPLES::
|
|
729
|
+
|
|
730
|
+
sage: P = polytopes.cross_polytope(3); P
|
|
731
|
+
A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 6 vertices
|
|
732
|
+
sage: face = P.faces(2)[3]; face
|
|
733
|
+
A 2-dimensional face of a
|
|
734
|
+
Polyhedron in ZZ^3 defined as the convex hull of 3 vertices
|
|
735
|
+
sage: face.as_polyhedron()
|
|
736
|
+
A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices
|
|
737
|
+
|
|
738
|
+
sage: P.intersection(face.as_polyhedron()) == face.as_polyhedron()
|
|
739
|
+
True
|
|
740
|
+
"""
|
|
741
|
+
P = self._polyhedron
|
|
742
|
+
parent = P.parent()
|
|
743
|
+
Vrep = (self.vertices(), self.rays(), self.lines())
|
|
744
|
+
result = P.__class__(parent, Vrep, None)
|
|
745
|
+
if any(kwds.get(kwd) is not None
|
|
746
|
+
for kwd in ('base_ring', 'backend')):
|
|
747
|
+
from .constructor import Polyhedron
|
|
748
|
+
return Polyhedron(result, **kwds)
|
|
749
|
+
return result
|
|
750
|
+
|
|
751
|
+
def _some_elements_(self):
|
|
752
|
+
r"""
|
|
753
|
+
Generate some points of ``self``.
|
|
754
|
+
|
|
755
|
+
If ``self`` is empty, no points are generated; no exception will be raised.
|
|
756
|
+
|
|
757
|
+
EXAMPLES::
|
|
758
|
+
|
|
759
|
+
sage: P = polytopes.cross_polytope(3); P
|
|
760
|
+
A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 6 vertices
|
|
761
|
+
sage: face = P.faces(2)[3]; face
|
|
762
|
+
A 2-dimensional face of a
|
|
763
|
+
Polyhedron in ZZ^3 defined as the convex hull of 3 vertices
|
|
764
|
+
sage: face.as_polyhedron().vertices()
|
|
765
|
+
(A vertex at (0, -1, 0), A vertex at (0, 0, -1), A vertex at (1, 0, 0))
|
|
766
|
+
sage: face.an_element() # indirect doctest
|
|
767
|
+
(1/3, -1/3, -1/3)
|
|
768
|
+
sage: face.some_elements() # indirect doctest
|
|
769
|
+
[(1/3, -1/3, -1/3), (0, -1, 0), (0, -1/2, -1/2), (1/2, -1/4, -1/4)]
|
|
770
|
+
"""
|
|
771
|
+
yield from self.as_polyhedron().some_elements()
|
|
772
|
+
|
|
773
|
+
def contains(self, point):
|
|
774
|
+
"""
|
|
775
|
+
Test whether the polyhedron contains the given ``point``.
|
|
776
|
+
|
|
777
|
+
INPUT:
|
|
778
|
+
|
|
779
|
+
- ``point`` -- a point or its coordinates
|
|
780
|
+
|
|
781
|
+
EXAMPLES::
|
|
782
|
+
|
|
783
|
+
sage: half_plane = Polyhedron(ieqs=[(0,1,0)])
|
|
784
|
+
sage: line = half_plane.faces(1)[0]; line
|
|
785
|
+
A 1-dimensional face of a
|
|
786
|
+
Polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line
|
|
787
|
+
sage: line.contains([0, 1])
|
|
788
|
+
True
|
|
789
|
+
|
|
790
|
+
As a shorthand, one may use the usual ``in`` operator::
|
|
791
|
+
|
|
792
|
+
sage: [5, 7] in line
|
|
793
|
+
False
|
|
794
|
+
"""
|
|
795
|
+
# preprocess in the same way as Polyhedron_base.contains
|
|
796
|
+
try:
|
|
797
|
+
p = vector(point)
|
|
798
|
+
except TypeError: # point not iterable or no common ring for elements
|
|
799
|
+
if len(point) > 0:
|
|
800
|
+
return False
|
|
801
|
+
else:
|
|
802
|
+
p = vector(self.polyhedron().base_ring(), [])
|
|
803
|
+
|
|
804
|
+
if len(p) != self.ambient_dim():
|
|
805
|
+
return False
|
|
806
|
+
|
|
807
|
+
if not self.polyhedron().contains(p):
|
|
808
|
+
return False
|
|
809
|
+
|
|
810
|
+
for H in self.ambient_Hrepresentation():
|
|
811
|
+
if H.eval(p) != 0:
|
|
812
|
+
return False
|
|
813
|
+
return True
|
|
814
|
+
|
|
815
|
+
__contains__ = contains
|
|
816
|
+
|
|
817
|
+
@cached_method
|
|
818
|
+
def normal_cone(self, direction='outer'):
|
|
819
|
+
"""
|
|
820
|
+
Return the polyhedral cone consisting of normal vectors to
|
|
821
|
+
hyperplanes supporting ``self``.
|
|
822
|
+
|
|
823
|
+
INPUT:
|
|
824
|
+
|
|
825
|
+
- ``direction`` -- string (default: ``'outer'``); the direction in
|
|
826
|
+
which to consider the normals. The other allowed option is
|
|
827
|
+
``'inner'``.
|
|
828
|
+
|
|
829
|
+
OUTPUT: a polyhedron
|
|
830
|
+
|
|
831
|
+
EXAMPLES::
|
|
832
|
+
|
|
833
|
+
sage: p = Polyhedron(vertices=[[1,2], [2,1], [-2,2], [-2,-2], [2,-2]])
|
|
834
|
+
sage: for v in p.face_generator(0):
|
|
835
|
+
....: vect = v.vertices()[0].vector()
|
|
836
|
+
....: nc = v.normal_cone().rays_list()
|
|
837
|
+
....: print("{} has outer normal cone spanned by {}".format(vect,nc))
|
|
838
|
+
....:
|
|
839
|
+
(2, 1) has outer normal cone spanned by [[1, 0], [1, 1]]
|
|
840
|
+
(1, 2) has outer normal cone spanned by [[0, 1], [1, 1]]
|
|
841
|
+
(2, -2) has outer normal cone spanned by [[0, -1], [1, 0]]
|
|
842
|
+
(-2, -2) has outer normal cone spanned by [[-1, 0], [0, -1]]
|
|
843
|
+
(-2, 2) has outer normal cone spanned by [[-1, 0], [0, 1]]
|
|
844
|
+
|
|
845
|
+
sage: for v in p.face_generator(0):
|
|
846
|
+
....: vect = v.vertices()[0].vector()
|
|
847
|
+
....: nc = v.normal_cone(direction='inner').rays_list()
|
|
848
|
+
....: print("{} has inner normal cone spanned by {}".format(vect,nc))
|
|
849
|
+
....:
|
|
850
|
+
(2, 1) has inner normal cone spanned by [[-1, -1], [-1, 0]]
|
|
851
|
+
(1, 2) has inner normal cone spanned by [[-1, -1], [0, -1]]
|
|
852
|
+
(2, -2) has inner normal cone spanned by [[-1, 0], [0, 1]]
|
|
853
|
+
(-2, -2) has inner normal cone spanned by [[0, 1], [1, 0]]
|
|
854
|
+
(-2, 2) has inner normal cone spanned by [[0, -1], [1, 0]]
|
|
855
|
+
|
|
856
|
+
The function works for polytopes that are not full-dimensional::
|
|
857
|
+
|
|
858
|
+
sage: p = polytopes.permutahedron(3)
|
|
859
|
+
sage: f1 = p.faces(0)[0]
|
|
860
|
+
sage: f2 = p.faces(1)[0]
|
|
861
|
+
sage: f3 = p.faces(2)[0]
|
|
862
|
+
sage: f1.normal_cone()
|
|
863
|
+
A 3-dimensional polyhedron in ZZ^3 defined as
|
|
864
|
+
the convex hull of 1 vertex, 2 rays, 1 line
|
|
865
|
+
sage: f2.normal_cone()
|
|
866
|
+
A 2-dimensional polyhedron in ZZ^3 defined as
|
|
867
|
+
the convex hull of 1 vertex, 1 ray, 1 line
|
|
868
|
+
sage: f3.normal_cone()
|
|
869
|
+
A 1-dimensional polyhedron in ZZ^3 defined as
|
|
870
|
+
the convex hull of 1 vertex and 1 line
|
|
871
|
+
|
|
872
|
+
Normal cones are only defined for non-empty faces::
|
|
873
|
+
|
|
874
|
+
sage: f0 = p.faces(-1)[0]
|
|
875
|
+
sage: f0.normal_cone()
|
|
876
|
+
Traceback (most recent call last):
|
|
877
|
+
...
|
|
878
|
+
ValueError: the empty face does not have a normal cone
|
|
879
|
+
"""
|
|
880
|
+
if self.dim() == -1:
|
|
881
|
+
raise ValueError("the empty face does not have a normal cone")
|
|
882
|
+
elif direction not in ['outer', 'inner']:
|
|
883
|
+
raise ValueError("the direction should be either 'outer' or 'inner'")
|
|
884
|
+
rays = []
|
|
885
|
+
lines = []
|
|
886
|
+
for facet in self.ambient_Hrepresentation():
|
|
887
|
+
if facet.is_equation():
|
|
888
|
+
lines += [facet.A()]
|
|
889
|
+
elif direction == 'outer':
|
|
890
|
+
rays += [-facet.A()]
|
|
891
|
+
else: # 'inner'
|
|
892
|
+
rays += [facet.A()]
|
|
893
|
+
parent = self.polyhedron().parent()
|
|
894
|
+
origin = self.polyhedron().ambient_space().zero()
|
|
895
|
+
return parent.element_class(parent, [[origin], rays, lines], None)
|
|
896
|
+
|
|
897
|
+
@cached_method
|
|
898
|
+
def affine_tangent_cone(self):
|
|
899
|
+
"""
|
|
900
|
+
Return the affine tangent cone of ``self`` as a polyhedron.
|
|
901
|
+
|
|
902
|
+
It is equal to the sum of ``self`` and the cone of feasible directions
|
|
903
|
+
at any point of the relative interior of ``self``.
|
|
904
|
+
|
|
905
|
+
OUTPUT: a polyhedron
|
|
906
|
+
|
|
907
|
+
EXAMPLES::
|
|
908
|
+
|
|
909
|
+
sage: half_plane_in_space = Polyhedron(ieqs=[(0,1,0,0)], eqns=[(0,0,0,1)])
|
|
910
|
+
sage: line = half_plane_in_space.faces(1)[0]; line
|
|
911
|
+
A 1-dimensional face of a
|
|
912
|
+
Polyhedron in QQ^3 defined as the convex hull of 1 vertex and 1 line
|
|
913
|
+
sage: T_line = line.affine_tangent_cone()
|
|
914
|
+
sage: T_line == half_plane_in_space
|
|
915
|
+
True
|
|
916
|
+
|
|
917
|
+
sage: c = polytopes.cube()
|
|
918
|
+
sage: edge = min(c.faces(1))
|
|
919
|
+
sage: edge.vertices()
|
|
920
|
+
(A vertex at (1, -1, -1), A vertex at (1, 1, -1))
|
|
921
|
+
sage: T_edge = edge.affine_tangent_cone()
|
|
922
|
+
sage: T_edge.Vrepresentation()
|
|
923
|
+
(A line in the direction (0, 1, 0),
|
|
924
|
+
A ray in the direction (0, 0, 1),
|
|
925
|
+
A vertex at (1, 0, -1),
|
|
926
|
+
A ray in the direction (-1, 0, 0))
|
|
927
|
+
|
|
928
|
+
TESTS:
|
|
929
|
+
|
|
930
|
+
Check that :issue:`32658` is fixed::
|
|
931
|
+
|
|
932
|
+
sage: P = polytopes.hypercube(2)
|
|
933
|
+
sage: P.faces(-1)[0].affine_tangent_cone()
|
|
934
|
+
Traceback (most recent call last):
|
|
935
|
+
...
|
|
936
|
+
ValueError: affine tangent cone of the empty face not defined
|
|
937
|
+
"""
|
|
938
|
+
if self.dim() == -1:
|
|
939
|
+
raise ValueError("affine tangent cone of the empty face not defined")
|
|
940
|
+
parent = self.polyhedron().parent()
|
|
941
|
+
new_ieqs = [H for H in self.ambient_Hrepresentation()
|
|
942
|
+
if H.is_inequality()]
|
|
943
|
+
new_eqns = [H for H in self.ambient_Hrepresentation()
|
|
944
|
+
if H.is_equation()]
|
|
945
|
+
return parent.element_class(parent, None, [new_ieqs, new_eqns])
|
|
946
|
+
|
|
947
|
+
@cached_method
|
|
948
|
+
def stacking_locus(self):
|
|
949
|
+
"""
|
|
950
|
+
Return the polyhedron containing the points that sees every facet
|
|
951
|
+
containing ``self``.
|
|
952
|
+
|
|
953
|
+
OUTPUT: a polyhedron
|
|
954
|
+
|
|
955
|
+
EXAMPLES::
|
|
956
|
+
|
|
957
|
+
sage: cp = polytopes.cross_polytope(4)
|
|
958
|
+
sage: facet = cp.facets()[0]
|
|
959
|
+
sage: facet.stacking_locus().vertices()
|
|
960
|
+
(A vertex at (1/2, 1/2, 1/2, 1/2),
|
|
961
|
+
A vertex at (1, 0, 0, 0),
|
|
962
|
+
A vertex at (0, 0, 0, 1),
|
|
963
|
+
A vertex at (0, 0, 1, 0),
|
|
964
|
+
A vertex at (0, 1, 0, 0))
|
|
965
|
+
sage: face = cp.faces(2)[0]
|
|
966
|
+
sage: face.stacking_locus().vertices()
|
|
967
|
+
(A vertex at (0, 1, 0, 0),
|
|
968
|
+
A vertex at (0, 0, 1, 0),
|
|
969
|
+
A vertex at (1, 0, 0, 0),
|
|
970
|
+
A vertex at (1, 1, 1, 0),
|
|
971
|
+
A vertex at (1/2, 1/2, 1/2, 1/2),
|
|
972
|
+
A vertex at (1/2, 1/2, 1/2, -1/2))
|
|
973
|
+
"""
|
|
974
|
+
# Taking all facets that contain the face
|
|
975
|
+
if self.dim() == self.polyhedron().dim() - 1:
|
|
976
|
+
face_star = set([self.ambient_Hrepresentation()[-1]])
|
|
977
|
+
else:
|
|
978
|
+
face_star = set(facet for facet in self.ambient_Hrepresentation() if facet.is_inequality()
|
|
979
|
+
if all(not facet.interior_contains(x) for x in self.vertices()))
|
|
980
|
+
|
|
981
|
+
neighboring_facets = set()
|
|
982
|
+
for facet in face_star:
|
|
983
|
+
for neighbor_facet in facet.neighbors():
|
|
984
|
+
if neighbor_facet not in face_star:
|
|
985
|
+
neighboring_facets.add(neighbor_facet)
|
|
986
|
+
|
|
987
|
+
# Create the polyhedron where we can put the new vertex
|
|
988
|
+
locus_ieqs = [facet.vector() for facet in neighboring_facets]
|
|
989
|
+
locus_ieqs += [-facet.vector() for facet in face_star]
|
|
990
|
+
locus_eqns = self.polyhedron().equations_list()
|
|
991
|
+
parent = self.polyhedron().parent().change_ring(self.polyhedron().base_ring().fraction_field())
|
|
992
|
+
|
|
993
|
+
return parent.element_class(parent, None, [locus_ieqs, locus_eqns])
|
|
994
|
+
|
|
995
|
+
|
|
996
|
+
def combinatorial_face_to_polyhedral_face(polyhedron, combinatorial_face):
|
|
997
|
+
r"""
|
|
998
|
+
Convert a combinatorial face to a face of a polyhedron.
|
|
999
|
+
|
|
1000
|
+
INPUT:
|
|
1001
|
+
|
|
1002
|
+
- ``polyhedron`` -- a polyhedron containing ``combinatorial_face``
|
|
1003
|
+
- ``combinatorial_face`` -- a :class:`CombinatorialFace`
|
|
1004
|
+
|
|
1005
|
+
OUTPUT: a :class:`PolyhedronFace`
|
|
1006
|
+
|
|
1007
|
+
EXAMPLES::
|
|
1008
|
+
|
|
1009
|
+
sage: from sage.geometry.polyhedron.face import combinatorial_face_to_polyhedral_face
|
|
1010
|
+
sage: P = polytopes.simplex()
|
|
1011
|
+
sage: C = P.combinatorial_polyhedron()
|
|
1012
|
+
sage: it = C.face_iter()
|
|
1013
|
+
sage: comb_face = next(it)
|
|
1014
|
+
sage: combinatorial_face_to_polyhedral_face(P, comb_face)
|
|
1015
|
+
A 2-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 3 vertices
|
|
1016
|
+
|
|
1017
|
+
TESTS:
|
|
1018
|
+
|
|
1019
|
+
Making sure that backends do not change their order of
|
|
1020
|
+
inequalities/equations without applying the changes to this method::
|
|
1021
|
+
|
|
1022
|
+
sage: polytopes.simplex(backend='field').equations()[0].index()
|
|
1023
|
+
4
|
|
1024
|
+
sage: polytopes.simplex(backend='ppl').equations()[0].index()
|
|
1025
|
+
0
|
|
1026
|
+
sage: polytopes.simplex(backend='cdd').equations()[0].index() # needs cddexec_gmp
|
|
1027
|
+
4
|
|
1028
|
+
sage: polytopes.simplex(backend='normaliz').equations()[0].index() # optional - pynormaliz
|
|
1029
|
+
4
|
|
1030
|
+
sage: polytopes.simplex(backend='polymake').equations()[0].index() # optional - jupymake
|
|
1031
|
+
4
|
|
1032
|
+
"""
|
|
1033
|
+
V_indices = combinatorial_face.ambient_V_indices()
|
|
1034
|
+
n_equations = polyhedron.n_equations()
|
|
1035
|
+
|
|
1036
|
+
if polyhedron.backend() in ('ppl',):
|
|
1037
|
+
# Equations before inequalities in Hrep.
|
|
1038
|
+
H_indices = tuple(range(n_equations))
|
|
1039
|
+
H_indices += tuple(x+n_equations for x in combinatorial_face.ambient_H_indices(add_equations=False))
|
|
1040
|
+
elif polyhedron.backend() in ('normaliz', 'cdd', 'field', 'number_field', 'polymake'):
|
|
1041
|
+
# Equations after the inequalities in Hrep.
|
|
1042
|
+
n_ieqs = polyhedron.n_inequalities()
|
|
1043
|
+
H_indices = tuple(combinatorial_face.ambient_H_indices(add_equations=False))
|
|
1044
|
+
H_indices += tuple(range(n_ieqs, n_ieqs + n_equations))
|
|
1045
|
+
else:
|
|
1046
|
+
raise NotImplementedError("unknown backend")
|
|
1047
|
+
|
|
1048
|
+
if polyhedron.dimension() == 0:
|
|
1049
|
+
# Taking care of a special case:
|
|
1050
|
+
# In this case the face lattice has a coatom,
|
|
1051
|
+
# but the polyhedron does not have a facet
|
|
1052
|
+
# (a facet is defined to be non-empty).
|
|
1053
|
+
|
|
1054
|
+
# More important, there is no inequality for that coatom.
|
|
1055
|
+
# So the above would produce an index error.
|
|
1056
|
+
# Instead, any case of the 0-dimensional polyhedron
|
|
1057
|
+
# satisfies all of the equations.
|
|
1058
|
+
H_indices = tuple(range(n_equations))
|
|
1059
|
+
|
|
1060
|
+
return PolyhedronFace(polyhedron, V_indices, H_indices)
|