passagemath-polyhedra 10.6.31rc3__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.
Potentially problematic release.
This version of passagemath-polyhedra might be problematic. Click here for more details.
- passagemath_polyhedra-10.6.31rc3.dist-info/METADATA +367 -0
- passagemath_polyhedra-10.6.31rc3.dist-info/METADATA.bak +369 -0
- passagemath_polyhedra-10.6.31rc3.dist-info/RECORD +208 -0
- passagemath_polyhedra-10.6.31rc3.dist-info/WHEEL +5 -0
- passagemath_polyhedra-10.6.31rc3.dist-info/top_level.txt +2 -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 +3895 -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,1845 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-polyhedra
|
|
2
|
+
r"""
|
|
3
|
+
Base class for polyhedra: Methods regarding the combinatorics of a polyhedron
|
|
4
|
+
|
|
5
|
+
Excluding methods relying on :mod:`sage.graphs`.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
# ****************************************************************************
|
|
9
|
+
# Copyright (C) 2008-2012 Marshall Hampton <hamptonio@gmail.com>
|
|
10
|
+
# Copyright (C) 2011-2015 Volker Braun <vbraun.name@gmail.com>
|
|
11
|
+
# Copyright (C) 2012-2018 Frederic Chapoton
|
|
12
|
+
# Copyright (C) 2013 Andrey Novoseltsev
|
|
13
|
+
# Copyright (C) 2014-2017 Moritz Firsching
|
|
14
|
+
# Copyright (C) 2014-2019 Thierry Monteil
|
|
15
|
+
# Copyright (C) 2015 Nathann Cohen
|
|
16
|
+
# Copyright (C) 2015-2017 Jeroen Demeyer
|
|
17
|
+
# Copyright (C) 2015-2017 Vincent Delecroix
|
|
18
|
+
# Copyright (C) 2015-2018 Dima Pasechnik
|
|
19
|
+
# Copyright (C) 2015-2020 Jean-Philippe Labbe <labbe at math.huji.ac.il>
|
|
20
|
+
# Copyright (C) 2015-2021 Matthias Koeppe
|
|
21
|
+
# Copyright (C) 2016-2019 Daniel Krenn
|
|
22
|
+
# Copyright (C) 2017 Marcelo Forets
|
|
23
|
+
# Copyright (C) 2017-2018 Mark Bell
|
|
24
|
+
# Copyright (C) 2019 Julian Ritter
|
|
25
|
+
# Copyright (C) 2019-2020 Laith Rastanawi
|
|
26
|
+
# Copyright (C) 2019-2020 Sophia Elia
|
|
27
|
+
# Copyright (C) 2019-2021 Jonathan Kliem <jonathan.kliem@gmail.com>
|
|
28
|
+
#
|
|
29
|
+
# This program is free software: you can redistribute it and/or modify
|
|
30
|
+
# it under the terms of the GNU General Public License as published by
|
|
31
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
32
|
+
# (at your option) any later version.
|
|
33
|
+
# https://www.gnu.org/licenses/
|
|
34
|
+
# ****************************************************************************
|
|
35
|
+
|
|
36
|
+
from sage.misc.cachefunc import cached_method
|
|
37
|
+
from sage.matrix.constructor import matrix
|
|
38
|
+
from sage.rings.integer_ring import ZZ
|
|
39
|
+
from sage.rings.rational_field import QQ
|
|
40
|
+
from .base2 import Polyhedron_base2
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class Polyhedron_base3(Polyhedron_base2):
|
|
44
|
+
"""
|
|
45
|
+
Methods related to the combinatorics of a polyhedron.
|
|
46
|
+
|
|
47
|
+
See :class:`sage.geometry.polyhedron.base.Polyhedron_base`.
|
|
48
|
+
|
|
49
|
+
TESTS::
|
|
50
|
+
|
|
51
|
+
sage: from sage.geometry.polyhedron.base3 import Polyhedron_base3
|
|
52
|
+
sage: P = polytopes.cube()
|
|
53
|
+
sage: Polyhedron_base3.is_simple(P)
|
|
54
|
+
True
|
|
55
|
+
sage: Polyhedron_base3.is_simplicial(P)
|
|
56
|
+
False
|
|
57
|
+
sage: Polyhedron_base3.is_prism(P)
|
|
58
|
+
True
|
|
59
|
+
sage: Polyhedron_base3.is_pyramid(P)
|
|
60
|
+
False
|
|
61
|
+
sage: Polyhedron_base3.combinatorial_polyhedron.f(P)
|
|
62
|
+
A 3-dimensional combinatorial polyhedron with 6 facets
|
|
63
|
+
sage: Polyhedron_base3.facets(P)
|
|
64
|
+
(A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 4 vertices,
|
|
65
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 4 vertices,
|
|
66
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 4 vertices,
|
|
67
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 4 vertices,
|
|
68
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 4 vertices,
|
|
69
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 4 vertices)
|
|
70
|
+
sage: Polyhedron_base3.f_vector.f(P)
|
|
71
|
+
(1, 8, 12, 6, 1)
|
|
72
|
+
sage: next(Polyhedron_base3.face_generator(P))
|
|
73
|
+
A 3-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 8 vertices
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
def _init_empty_polyhedron(self):
|
|
77
|
+
"""
|
|
78
|
+
Initialize an empty polyhedron.
|
|
79
|
+
|
|
80
|
+
TESTS::
|
|
81
|
+
|
|
82
|
+
sage: Polyhedron().vertex_adjacency_matrix() # indirect doctest
|
|
83
|
+
[]
|
|
84
|
+
sage: Polyhedron().facet_adjacency_matrix()
|
|
85
|
+
[0]
|
|
86
|
+
"""
|
|
87
|
+
Polyhedron_base2._init_empty_polyhedron(self)
|
|
88
|
+
|
|
89
|
+
V_matrix = matrix(ZZ, 0, 0, 0)
|
|
90
|
+
V_matrix.set_immutable()
|
|
91
|
+
self.vertex_adjacency_matrix.set_cache(V_matrix)
|
|
92
|
+
|
|
93
|
+
H_matrix = matrix(ZZ, 1, 1, 0)
|
|
94
|
+
H_matrix.set_immutable()
|
|
95
|
+
self.facet_adjacency_matrix.set_cache(H_matrix)
|
|
96
|
+
|
|
97
|
+
@cached_method
|
|
98
|
+
def slack_matrix(self):
|
|
99
|
+
r"""
|
|
100
|
+
Return the slack matrix.
|
|
101
|
+
|
|
102
|
+
The entries correspond to the evaluation of the Hrepresentation
|
|
103
|
+
elements on the Vrepresentation elements.
|
|
104
|
+
|
|
105
|
+
.. NOTE::
|
|
106
|
+
|
|
107
|
+
The columns correspond to inequalities/equations in the
|
|
108
|
+
order :meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.Hrepresentation`, the rows correspond to
|
|
109
|
+
vertices/rays/lines in the order
|
|
110
|
+
:meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.Vrepresentation`.
|
|
111
|
+
|
|
112
|
+
.. SEEALSO::
|
|
113
|
+
|
|
114
|
+
:meth:`incidence_matrix`.
|
|
115
|
+
|
|
116
|
+
EXAMPLES::
|
|
117
|
+
|
|
118
|
+
sage: P = polytopes.cube()
|
|
119
|
+
sage: P.slack_matrix()
|
|
120
|
+
[0 2 2 2 0 0]
|
|
121
|
+
[0 0 2 2 0 2]
|
|
122
|
+
[0 0 0 2 2 2]
|
|
123
|
+
[0 2 0 2 2 0]
|
|
124
|
+
[2 2 0 0 2 0]
|
|
125
|
+
[2 2 2 0 0 0]
|
|
126
|
+
[2 0 2 0 0 2]
|
|
127
|
+
[2 0 0 0 2 2]
|
|
128
|
+
|
|
129
|
+
sage: P = polytopes.cube(intervals='zero_one')
|
|
130
|
+
sage: P.slack_matrix()
|
|
131
|
+
[0 1 1 1 0 0]
|
|
132
|
+
[0 0 1 1 0 1]
|
|
133
|
+
[0 0 0 1 1 1]
|
|
134
|
+
[0 1 0 1 1 0]
|
|
135
|
+
[1 1 0 0 1 0]
|
|
136
|
+
[1 1 1 0 0 0]
|
|
137
|
+
[1 0 1 0 0 1]
|
|
138
|
+
[1 0 0 0 1 1]
|
|
139
|
+
|
|
140
|
+
sage: # needs sage.groups sage.rings.number_field
|
|
141
|
+
sage: P = polytopes.dodecahedron().faces(2)[0].as_polyhedron()
|
|
142
|
+
sage: P.slack_matrix()
|
|
143
|
+
[1/2*sqrt5 - 1/2 0 0 1 1/2*sqrt5 - 1/2 0]
|
|
144
|
+
[ 0 0 1/2*sqrt5 - 1/2 1/2*sqrt5 - 1/2 1 0]
|
|
145
|
+
[ 0 1/2*sqrt5 - 1/2 1 0 1/2*sqrt5 - 1/2 0]
|
|
146
|
+
[ 1 1/2*sqrt5 - 1/2 0 1/2*sqrt5 - 1/2 0 0]
|
|
147
|
+
[1/2*sqrt5 - 1/2 1 1/2*sqrt5 - 1/2 0 0 0]
|
|
148
|
+
|
|
149
|
+
sage: P = Polyhedron(rays=[[1, 0], [0, 1]])
|
|
150
|
+
sage: P.slack_matrix()
|
|
151
|
+
[0 0]
|
|
152
|
+
[0 1]
|
|
153
|
+
[1 0]
|
|
154
|
+
|
|
155
|
+
TESTS::
|
|
156
|
+
|
|
157
|
+
sage: Polyhedron().slack_matrix()
|
|
158
|
+
[]
|
|
159
|
+
sage: Polyhedron(base_ring=QuadraticField(2)).slack_matrix().base_ring() # needs sage.rings.number_field
|
|
160
|
+
Number Field in a with defining polynomial x^2 - 2 with a = 1.41...
|
|
161
|
+
"""
|
|
162
|
+
if not self.n_Vrepresentation() or not self.n_Hrepresentation():
|
|
163
|
+
slack_matrix = matrix(self.base_ring(), self.n_Vrepresentation(),
|
|
164
|
+
self.n_Hrepresentation(), 0)
|
|
165
|
+
else:
|
|
166
|
+
Vrep_matrix = matrix(self.base_ring(), self.Vrepresentation())
|
|
167
|
+
Hrep_matrix = matrix(self.base_ring(), self.Hrepresentation())
|
|
168
|
+
|
|
169
|
+
# Getting homogeneous coordinates of the Vrepresentation.
|
|
170
|
+
hom_helper = matrix(self.base_ring(), [1 if v.is_vertex() else 0 for v in self.Vrepresentation()])
|
|
171
|
+
hom_Vrep = hom_helper.stack(Vrep_matrix.transpose())
|
|
172
|
+
|
|
173
|
+
slack_matrix = (Hrep_matrix * hom_Vrep).transpose()
|
|
174
|
+
|
|
175
|
+
slack_matrix.set_immutable()
|
|
176
|
+
return slack_matrix
|
|
177
|
+
|
|
178
|
+
@cached_method
|
|
179
|
+
def incidence_matrix(self):
|
|
180
|
+
"""
|
|
181
|
+
Return the incidence matrix.
|
|
182
|
+
|
|
183
|
+
.. NOTE::
|
|
184
|
+
|
|
185
|
+
The columns correspond to inequalities/equations in the
|
|
186
|
+
order :meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.Hrepresentation`, the rows correspond to
|
|
187
|
+
vertices/rays/lines in the order
|
|
188
|
+
:meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.Vrepresentation`.
|
|
189
|
+
|
|
190
|
+
.. SEEALSO::
|
|
191
|
+
|
|
192
|
+
:meth:`slack_matrix`.
|
|
193
|
+
|
|
194
|
+
EXAMPLES::
|
|
195
|
+
|
|
196
|
+
sage: p = polytopes.cuboctahedron()
|
|
197
|
+
sage: p.incidence_matrix()
|
|
198
|
+
[0 0 1 1 0 1 0 0 0 0 1 0 0 0]
|
|
199
|
+
[0 0 0 1 0 0 1 0 1 0 1 0 0 0]
|
|
200
|
+
[0 0 1 1 1 0 0 1 0 0 0 0 0 0]
|
|
201
|
+
[1 0 0 1 1 0 1 0 0 0 0 0 0 0]
|
|
202
|
+
[0 0 0 0 0 1 0 0 1 1 1 0 0 0]
|
|
203
|
+
[0 0 1 0 0 1 0 1 0 0 0 1 0 0]
|
|
204
|
+
[1 0 0 0 0 0 1 0 1 0 0 0 1 0]
|
|
205
|
+
[1 0 0 0 1 0 0 1 0 0 0 0 0 1]
|
|
206
|
+
[0 1 0 0 0 1 0 0 0 1 0 1 0 0]
|
|
207
|
+
[0 1 0 0 0 0 0 0 1 1 0 0 1 0]
|
|
208
|
+
[0 1 0 0 0 0 0 1 0 0 0 1 0 1]
|
|
209
|
+
[1 1 0 0 0 0 0 0 0 0 0 0 1 1]
|
|
210
|
+
sage: v = p.Vrepresentation(0)
|
|
211
|
+
sage: v
|
|
212
|
+
A vertex at (-1, -1, 0)
|
|
213
|
+
sage: h = p.Hrepresentation(2)
|
|
214
|
+
sage: h
|
|
215
|
+
An inequality (1, 1, -1) x + 2 >= 0
|
|
216
|
+
sage: h.eval(v) # evaluation (1, 1, -1) * (-1/2, -1/2, 0) + 1
|
|
217
|
+
0
|
|
218
|
+
sage: h*v # same as h.eval(v)
|
|
219
|
+
0
|
|
220
|
+
sage: p.incidence_matrix() [0,2] # this entry is (v,h)
|
|
221
|
+
1
|
|
222
|
+
sage: h.contains(v)
|
|
223
|
+
True
|
|
224
|
+
sage: p.incidence_matrix() [2,0] # note: not symmetric
|
|
225
|
+
0
|
|
226
|
+
|
|
227
|
+
The incidence matrix depends on the ambient dimension::
|
|
228
|
+
|
|
229
|
+
sage: simplex = polytopes.simplex(); simplex
|
|
230
|
+
A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 4 vertices
|
|
231
|
+
sage: simplex.incidence_matrix()
|
|
232
|
+
[1 1 1 1 0]
|
|
233
|
+
[1 1 1 0 1]
|
|
234
|
+
[1 1 0 1 1]
|
|
235
|
+
[1 0 1 1 1]
|
|
236
|
+
sage: simplex = simplex.affine_hull_projection(); simplex
|
|
237
|
+
A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 4 vertices
|
|
238
|
+
sage: simplex.incidence_matrix()
|
|
239
|
+
[1 1 1 0]
|
|
240
|
+
[1 1 0 1]
|
|
241
|
+
[1 0 1 1]
|
|
242
|
+
[0 1 1 1]
|
|
243
|
+
|
|
244
|
+
An incidence matrix does not determine a unique
|
|
245
|
+
polyhedron::
|
|
246
|
+
|
|
247
|
+
sage: P = Polyhedron(vertices=[[0,1],[1,1],[1,0]])
|
|
248
|
+
sage: P.incidence_matrix()
|
|
249
|
+
[1 1 0]
|
|
250
|
+
[1 0 1]
|
|
251
|
+
[0 1 1]
|
|
252
|
+
|
|
253
|
+
sage: Q = Polyhedron(vertices=[[0,1], [1,0]], rays=[[1,1]])
|
|
254
|
+
sage: Q.incidence_matrix()
|
|
255
|
+
[1 1 0]
|
|
256
|
+
[1 0 1]
|
|
257
|
+
[0 1 1]
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
An example of two polyhedra with isomorphic face lattices
|
|
261
|
+
but different incidence matrices::
|
|
262
|
+
|
|
263
|
+
sage: Q.incidence_matrix()
|
|
264
|
+
[1 1 0]
|
|
265
|
+
[1 0 1]
|
|
266
|
+
[0 1 1]
|
|
267
|
+
|
|
268
|
+
sage: R = Polyhedron(vertices=[[0,1], [1,0]], rays=[[1,3/2], [3/2,1]])
|
|
269
|
+
sage: R.incidence_matrix()
|
|
270
|
+
[1 1 0]
|
|
271
|
+
[1 0 1]
|
|
272
|
+
[0 1 0]
|
|
273
|
+
[0 0 1]
|
|
274
|
+
|
|
275
|
+
The incidence matrix has base ring integers. This way one can express various
|
|
276
|
+
counting questions::
|
|
277
|
+
|
|
278
|
+
sage: P = polytopes.twenty_four_cell()
|
|
279
|
+
sage: M = P.incidence_matrix()
|
|
280
|
+
sage: sum(sum(x) for x in M) == P.flag_f_vector(0, 3) # needs sage.combinat
|
|
281
|
+
True
|
|
282
|
+
|
|
283
|
+
TESTS:
|
|
284
|
+
|
|
285
|
+
Check that :issue:`28828` is fixed::
|
|
286
|
+
|
|
287
|
+
sage: R.incidence_matrix().is_immutable()
|
|
288
|
+
True
|
|
289
|
+
|
|
290
|
+
Test that this method works for inexact base ring
|
|
291
|
+
(``cdd`` sets the cache already)::
|
|
292
|
+
|
|
293
|
+
sage: # needs sage.groups
|
|
294
|
+
sage: P = polytopes.dodecahedron(exact=False)
|
|
295
|
+
sage: M = P.incidence_matrix.cache
|
|
296
|
+
sage: P.incidence_matrix.clear_cache()
|
|
297
|
+
sage: M == P.incidence_matrix()
|
|
298
|
+
True
|
|
299
|
+
"""
|
|
300
|
+
if self.base_ring() in (ZZ, QQ):
|
|
301
|
+
# Much faster for integers or rationals.
|
|
302
|
+
incidence_matrix = self.slack_matrix().zero_pattern_matrix(ZZ)
|
|
303
|
+
incidence_matrix.set_immutable()
|
|
304
|
+
return incidence_matrix
|
|
305
|
+
|
|
306
|
+
incidence_matrix = matrix(ZZ, self.n_Vrepresentation(),
|
|
307
|
+
self.n_Hrepresentation(), 0)
|
|
308
|
+
|
|
309
|
+
Vvectors_vertices = tuple((v.vector(), v.index())
|
|
310
|
+
for v in self.Vrep_generator()
|
|
311
|
+
if v.is_vertex())
|
|
312
|
+
Vvectors_rays_lines = tuple((v.vector(), v.index())
|
|
313
|
+
for v in self.Vrep_generator()
|
|
314
|
+
if not v.is_vertex())
|
|
315
|
+
|
|
316
|
+
# Determine ``is_zero`` to save lots of time.
|
|
317
|
+
if self.base_ring().is_exact():
|
|
318
|
+
def is_zero(x):
|
|
319
|
+
return not x
|
|
320
|
+
else:
|
|
321
|
+
is_zero = self._is_zero
|
|
322
|
+
|
|
323
|
+
for H in self.Hrep_generator():
|
|
324
|
+
Hconst = H.b()
|
|
325
|
+
Hvec = H.A()
|
|
326
|
+
Hindex = H.index()
|
|
327
|
+
for Vvec, Vindex in Vvectors_vertices:
|
|
328
|
+
if is_zero(Hvec*Vvec + Hconst):
|
|
329
|
+
incidence_matrix[Vindex, Hindex] = 1
|
|
330
|
+
|
|
331
|
+
# A ray or line is considered incident with a hyperplane,
|
|
332
|
+
# if it is orthogonal to the normal vector of the hyperplane.
|
|
333
|
+
for Vvec, Vindex in Vvectors_rays_lines:
|
|
334
|
+
if is_zero(Hvec*Vvec):
|
|
335
|
+
incidence_matrix[Vindex, Hindex] = 1
|
|
336
|
+
|
|
337
|
+
incidence_matrix.set_immutable()
|
|
338
|
+
return incidence_matrix
|
|
339
|
+
|
|
340
|
+
@cached_method
|
|
341
|
+
def combinatorial_polyhedron(self):
|
|
342
|
+
r"""
|
|
343
|
+
Return the combinatorial type of ``self``.
|
|
344
|
+
|
|
345
|
+
See :class:`sage.geometry.polyhedron.combinatorial_polyhedron.base.CombinatorialPolyhedron`.
|
|
346
|
+
|
|
347
|
+
EXAMPLES::
|
|
348
|
+
|
|
349
|
+
sage: polytopes.cube().combinatorial_polyhedron()
|
|
350
|
+
A 3-dimensional combinatorial polyhedron with 6 facets
|
|
351
|
+
|
|
352
|
+
sage: polytopes.cyclic_polytope(4,10).combinatorial_polyhedron()
|
|
353
|
+
A 4-dimensional combinatorial polyhedron with 35 facets
|
|
354
|
+
|
|
355
|
+
sage: Polyhedron(rays=[[0,1], [1,0]]).combinatorial_polyhedron()
|
|
356
|
+
A 2-dimensional combinatorial polyhedron with 2 facets
|
|
357
|
+
"""
|
|
358
|
+
from sage.geometry.polyhedron.combinatorial_polyhedron.base import CombinatorialPolyhedron
|
|
359
|
+
return CombinatorialPolyhedron(self)
|
|
360
|
+
|
|
361
|
+
def _test_combinatorial_polyhedron(self, tester=None, **options):
|
|
362
|
+
"""
|
|
363
|
+
Run test suite of combinatorial polyhedron.
|
|
364
|
+
|
|
365
|
+
TESTS::
|
|
366
|
+
|
|
367
|
+
sage: polytopes.cross_polytope(3)._test_combinatorial_polyhedron()
|
|
368
|
+
"""
|
|
369
|
+
from sage.misc.sage_unittest import TestSuite
|
|
370
|
+
|
|
371
|
+
tester = self._tester(tester=tester, **options)
|
|
372
|
+
tester.info("\n Running the test suite of self.combinatorial_polyhedron()")
|
|
373
|
+
TestSuite(self.combinatorial_polyhedron()).run(verbose=tester._verbose,
|
|
374
|
+
prefix=tester._prefix+" ")
|
|
375
|
+
tester.info(tester._prefix + " ", newline=False)
|
|
376
|
+
|
|
377
|
+
def face_generator(self, face_dimension=None, algorithm=None):
|
|
378
|
+
r"""
|
|
379
|
+
Return an iterator over the faces of given dimension.
|
|
380
|
+
|
|
381
|
+
If dimension is not specified return an iterator over all faces.
|
|
382
|
+
|
|
383
|
+
INPUT:
|
|
384
|
+
|
|
385
|
+
- ``face_dimension`` -- integer (default: ``None``);
|
|
386
|
+
yield only faces of this dimension if specified
|
|
387
|
+
|
|
388
|
+
- ``algorithm`` -- string (optional);
|
|
389
|
+
specify whether to start with facets or vertices:
|
|
390
|
+
|
|
391
|
+
* ``'primal'`` -- start with the facets
|
|
392
|
+
* ``'dual'`` -- start with the vertices
|
|
393
|
+
* ``None`` -- choose automatically
|
|
394
|
+
|
|
395
|
+
OUTPUT:
|
|
396
|
+
|
|
397
|
+
A :class:`~sage.geometry.polyhedron.combinatorial_polyhedron.face_iterator.FaceIterator_geom`.
|
|
398
|
+
This class iterates over faces as
|
|
399
|
+
:class:`~sage.geometry.polyhedron.face.PolyhedronFace`. See
|
|
400
|
+
:mod:`~sage.geometry.polyhedron.face` for details. The order
|
|
401
|
+
is random but fixed.
|
|
402
|
+
|
|
403
|
+
EXAMPLES::
|
|
404
|
+
|
|
405
|
+
sage: P = polytopes.cube()
|
|
406
|
+
sage: it = P.face_generator()
|
|
407
|
+
sage: it
|
|
408
|
+
Iterator over the faces of a 3-dimensional polyhedron in ZZ^3
|
|
409
|
+
sage: list(it)
|
|
410
|
+
[A 3-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 8 vertices,
|
|
411
|
+
A -1-dimensional face of a Polyhedron in ZZ^3,
|
|
412
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 4 vertices,
|
|
413
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 4 vertices,
|
|
414
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 4 vertices,
|
|
415
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 4 vertices,
|
|
416
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 4 vertices,
|
|
417
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 4 vertices,
|
|
418
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
419
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
420
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
421
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
422
|
+
A 0-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 1 vertex,
|
|
423
|
+
A 0-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 1 vertex,
|
|
424
|
+
A 0-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 1 vertex,
|
|
425
|
+
A 0-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 1 vertex,
|
|
426
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
427
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
428
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
429
|
+
A 0-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 1 vertex,
|
|
430
|
+
A 0-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 1 vertex,
|
|
431
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
432
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
433
|
+
A 0-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 1 vertex,
|
|
434
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
435
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
436
|
+
A 0-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 1 vertex,
|
|
437
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices]
|
|
438
|
+
|
|
439
|
+
sage: P = polytopes.hypercube(4)
|
|
440
|
+
sage: list(P.face_generator(2))[:4]
|
|
441
|
+
[A 2-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 4 vertices,
|
|
442
|
+
A 2-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 4 vertices,
|
|
443
|
+
A 2-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 4 vertices,
|
|
444
|
+
A 2-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 4 vertices]
|
|
445
|
+
|
|
446
|
+
If a polytope has more facets than vertices, the dual mode is chosen::
|
|
447
|
+
|
|
448
|
+
sage: P = polytopes.cross_polytope(3)
|
|
449
|
+
sage: list(P.face_generator())
|
|
450
|
+
[A 3-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 6 vertices,
|
|
451
|
+
A -1-dimensional face of a Polyhedron in ZZ^3,
|
|
452
|
+
A 0-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 1 vertex,
|
|
453
|
+
A 0-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 1 vertex,
|
|
454
|
+
A 0-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 1 vertex,
|
|
455
|
+
A 0-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 1 vertex,
|
|
456
|
+
A 0-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 1 vertex,
|
|
457
|
+
A 0-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 1 vertex,
|
|
458
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
459
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
460
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
461
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
462
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 3 vertices,
|
|
463
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 3 vertices,
|
|
464
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 3 vertices,
|
|
465
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 3 vertices,
|
|
466
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
467
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
468
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
469
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 3 vertices,
|
|
470
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 3 vertices,
|
|
471
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
472
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
473
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 3 vertices,
|
|
474
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
475
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
476
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 3 vertices,
|
|
477
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices]
|
|
478
|
+
|
|
479
|
+
The face iterator can also be slightly modified.
|
|
480
|
+
In non-dual mode we can skip subfaces of the current (proper) face::
|
|
481
|
+
|
|
482
|
+
sage: P = polytopes.cube()
|
|
483
|
+
sage: it = P.face_generator(algorithm='primal')
|
|
484
|
+
sage: _ = next(it), next(it)
|
|
485
|
+
sage: face = next(it)
|
|
486
|
+
sage: face.ambient_H_indices()
|
|
487
|
+
(5,)
|
|
488
|
+
sage: it.ignore_subfaces()
|
|
489
|
+
sage: face = next(it)
|
|
490
|
+
sage: face.ambient_H_indices()
|
|
491
|
+
(4,)
|
|
492
|
+
sage: it.ignore_subfaces()
|
|
493
|
+
sage: [face.ambient_H_indices() for face in it]
|
|
494
|
+
[(3,),
|
|
495
|
+
(2,),
|
|
496
|
+
(1,),
|
|
497
|
+
(0,),
|
|
498
|
+
(2, 3),
|
|
499
|
+
(1, 3),
|
|
500
|
+
(1, 2, 3),
|
|
501
|
+
(1, 2),
|
|
502
|
+
(0, 2),
|
|
503
|
+
(0, 1, 2),
|
|
504
|
+
(0, 1)]
|
|
505
|
+
|
|
506
|
+
In dual mode we can skip supfaces of the current (proper) face::
|
|
507
|
+
|
|
508
|
+
sage: P = polytopes.cube()
|
|
509
|
+
sage: it = P.face_generator(algorithm='dual')
|
|
510
|
+
sage: _ = next(it), next(it)
|
|
511
|
+
sage: face = next(it)
|
|
512
|
+
sage: face.ambient_V_indices()
|
|
513
|
+
(7,)
|
|
514
|
+
sage: it.ignore_supfaces()
|
|
515
|
+
sage: next(it)
|
|
516
|
+
A 0-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 1 vertex
|
|
517
|
+
sage: face = next(it)
|
|
518
|
+
sage: face.ambient_V_indices()
|
|
519
|
+
(5,)
|
|
520
|
+
sage: it.ignore_supfaces()
|
|
521
|
+
sage: [face.ambient_V_indices() for face in it]
|
|
522
|
+
[(4,),
|
|
523
|
+
(3,),
|
|
524
|
+
(2,),
|
|
525
|
+
(1,),
|
|
526
|
+
(0,),
|
|
527
|
+
(1, 6),
|
|
528
|
+
(3, 4),
|
|
529
|
+
(2, 3),
|
|
530
|
+
(0, 3),
|
|
531
|
+
(0, 1, 2, 3),
|
|
532
|
+
(1, 2),
|
|
533
|
+
(0, 1)]
|
|
534
|
+
|
|
535
|
+
In non-dual mode, we cannot skip supfaces::
|
|
536
|
+
|
|
537
|
+
sage: it = P.face_generator(algorithm='primal')
|
|
538
|
+
sage: _ = next(it), next(it)
|
|
539
|
+
sage: next(it)
|
|
540
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 4 vertices
|
|
541
|
+
sage: it.ignore_supfaces()
|
|
542
|
+
Traceback (most recent call last):
|
|
543
|
+
...
|
|
544
|
+
ValueError: only possible when in dual mode
|
|
545
|
+
|
|
546
|
+
In dual mode, we cannot skip subfaces::
|
|
547
|
+
|
|
548
|
+
sage: it = P.face_generator(algorithm='dual')
|
|
549
|
+
sage: _ = next(it), next(it)
|
|
550
|
+
sage: next(it)
|
|
551
|
+
A 0-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 1 vertex
|
|
552
|
+
sage: it.ignore_subfaces()
|
|
553
|
+
Traceback (most recent call last):
|
|
554
|
+
...
|
|
555
|
+
ValueError: only possible when not in dual mode
|
|
556
|
+
|
|
557
|
+
We can only skip sub-/supfaces of proper faces::
|
|
558
|
+
|
|
559
|
+
sage: it = P.face_generator(algorithm='primal')
|
|
560
|
+
sage: next(it)
|
|
561
|
+
A 3-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 8 vertices
|
|
562
|
+
sage: it.ignore_subfaces()
|
|
563
|
+
Traceback (most recent call last):
|
|
564
|
+
...
|
|
565
|
+
ValueError: iterator not set to a face yet
|
|
566
|
+
|
|
567
|
+
.. SEEALSO::
|
|
568
|
+
|
|
569
|
+
:class:`~sage.geometry.polyhedron.combinatorial_polyhedron.face_iterator.FaceIterator_geom`.
|
|
570
|
+
|
|
571
|
+
ALGORITHM:
|
|
572
|
+
|
|
573
|
+
See :class:`~sage.geometry.polyhedron.combinatorial_polyhedron.face_iterator.FaceIterator`.
|
|
574
|
+
|
|
575
|
+
TESTS::
|
|
576
|
+
|
|
577
|
+
sage: P = polytopes.simplex()
|
|
578
|
+
sage: list(P.face_generator(-2))
|
|
579
|
+
[]
|
|
580
|
+
sage: list(P.face_generator(-1))
|
|
581
|
+
[A -1-dimensional face of a Polyhedron in ZZ^4]
|
|
582
|
+
sage: list(P.face_generator(3))
|
|
583
|
+
[A 3-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 4 vertices]
|
|
584
|
+
|
|
585
|
+
sage: list(Polyhedron().face_generator())
|
|
586
|
+
[A -1-dimensional face of a Polyhedron in ZZ^0]
|
|
587
|
+
|
|
588
|
+
Check that :issue:`29155` is fixed::
|
|
589
|
+
|
|
590
|
+
sage: P = polytopes.permutahedron(3)
|
|
591
|
+
sage: [f] = P.face_generator(2)
|
|
592
|
+
sage: f.ambient_Hrepresentation()
|
|
593
|
+
(An equation (1, 1, 1) x - 6 == 0,)
|
|
594
|
+
|
|
595
|
+
Check that we catch incorrect algorithms::
|
|
596
|
+
|
|
597
|
+
sage: list(P.face_generator(2, algorithm='integrate'))[:4]
|
|
598
|
+
Traceback (most recent call last):
|
|
599
|
+
...
|
|
600
|
+
ValueError: algorithm must be 'primal', 'dual' or None
|
|
601
|
+
"""
|
|
602
|
+
dual = None
|
|
603
|
+
if algorithm == 'primal':
|
|
604
|
+
dual = False
|
|
605
|
+
elif algorithm == 'dual':
|
|
606
|
+
dual = True
|
|
607
|
+
elif algorithm is not None:
|
|
608
|
+
raise ValueError("algorithm must be 'primal', 'dual' or None")
|
|
609
|
+
|
|
610
|
+
from sage.geometry.polyhedron.combinatorial_polyhedron.face_iterator import FaceIterator_geom
|
|
611
|
+
return FaceIterator_geom(self, output_dimension=face_dimension, dual=dual)
|
|
612
|
+
|
|
613
|
+
def faces(self, face_dimension):
|
|
614
|
+
"""
|
|
615
|
+
Return the faces of given dimension.
|
|
616
|
+
|
|
617
|
+
INPUT:
|
|
618
|
+
|
|
619
|
+
- ``face_dimension`` -- integer; the dimension of the faces
|
|
620
|
+
whose representation will be returned
|
|
621
|
+
|
|
622
|
+
OUTPUT:
|
|
623
|
+
|
|
624
|
+
A tuple of
|
|
625
|
+
:class:`~sage.geometry.polyhedron.face.PolyhedronFace`. See
|
|
626
|
+
module :mod:`sage.geometry.polyhedron.face` for details. The order
|
|
627
|
+
is random but fixed.
|
|
628
|
+
|
|
629
|
+
.. SEEALSO::
|
|
630
|
+
|
|
631
|
+
:meth:`face_generator`,
|
|
632
|
+
:meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.facet`.
|
|
633
|
+
|
|
634
|
+
EXAMPLES:
|
|
635
|
+
|
|
636
|
+
Here we find the vertex and face indices of the eight three-dimensional
|
|
637
|
+
facets of the four-dimensional hypercube::
|
|
638
|
+
|
|
639
|
+
sage: p = polytopes.hypercube(4)
|
|
640
|
+
sage: list(f.ambient_V_indices() for f in p.faces(3))
|
|
641
|
+
[(0, 5, 6, 7, 8, 9, 14, 15),
|
|
642
|
+
(1, 4, 5, 6, 10, 13, 14, 15),
|
|
643
|
+
(1, 2, 6, 7, 8, 10, 11, 15),
|
|
644
|
+
(8, 9, 10, 11, 12, 13, 14, 15),
|
|
645
|
+
(0, 3, 4, 5, 9, 12, 13, 14),
|
|
646
|
+
(0, 2, 3, 7, 8, 9, 11, 12),
|
|
647
|
+
(1, 2, 3, 4, 10, 11, 12, 13),
|
|
648
|
+
(0, 1, 2, 3, 4, 5, 6, 7)]
|
|
649
|
+
|
|
650
|
+
sage: face = p.faces(3)[3]
|
|
651
|
+
sage: face.ambient_Hrepresentation()
|
|
652
|
+
(An inequality (1, 0, 0, 0) x + 1 >= 0,)
|
|
653
|
+
sage: face.vertices()
|
|
654
|
+
(A vertex at (-1, -1, 1, -1),
|
|
655
|
+
A vertex at (-1, -1, 1, 1),
|
|
656
|
+
A vertex at (-1, 1, -1, -1),
|
|
657
|
+
A vertex at (-1, 1, 1, -1),
|
|
658
|
+
A vertex at (-1, 1, 1, 1),
|
|
659
|
+
A vertex at (-1, 1, -1, 1),
|
|
660
|
+
A vertex at (-1, -1, -1, 1),
|
|
661
|
+
A vertex at (-1, -1, -1, -1))
|
|
662
|
+
|
|
663
|
+
You can use the
|
|
664
|
+
:meth:`~sage.geometry.polyhedron.representation.PolyhedronRepresentation.index`
|
|
665
|
+
method to enumerate vertices and inequalities::
|
|
666
|
+
|
|
667
|
+
sage: def get_idx(rep): return rep.index()
|
|
668
|
+
sage: [get_idx(_) for _ in face.ambient_Hrepresentation()]
|
|
669
|
+
[4]
|
|
670
|
+
sage: [get_idx(_) for _ in face.ambient_Vrepresentation()]
|
|
671
|
+
[8, 9, 10, 11, 12, 13, 14, 15]
|
|
672
|
+
|
|
673
|
+
sage: [ ([get_idx(_) for _ in face.ambient_Vrepresentation()],
|
|
674
|
+
....: [get_idx(_) for _ in face.ambient_Hrepresentation()])
|
|
675
|
+
....: for face in p.faces(3) ]
|
|
676
|
+
[([0, 5, 6, 7, 8, 9, 14, 15], [7]),
|
|
677
|
+
([1, 4, 5, 6, 10, 13, 14, 15], [6]),
|
|
678
|
+
([1, 2, 6, 7, 8, 10, 11, 15], [5]),
|
|
679
|
+
([8, 9, 10, 11, 12, 13, 14, 15], [4]),
|
|
680
|
+
([0, 3, 4, 5, 9, 12, 13, 14], [3]),
|
|
681
|
+
([0, 2, 3, 7, 8, 9, 11, 12], [2]),
|
|
682
|
+
([1, 2, 3, 4, 10, 11, 12, 13], [1]),
|
|
683
|
+
([0, 1, 2, 3, 4, 5, 6, 7], [0])]
|
|
684
|
+
|
|
685
|
+
TESTS::
|
|
686
|
+
|
|
687
|
+
sage: pr = Polyhedron(rays = [[1,0,0],[-1,0,0],[0,1,0]], vertices = [[-1,-1,-1]], lines=[(0,0,1)])
|
|
688
|
+
sage: pr.faces(4)
|
|
689
|
+
()
|
|
690
|
+
sage: pr.faces(3)[0].ambient_V_indices()
|
|
691
|
+
(0, 1, 2, 3)
|
|
692
|
+
sage: pr.facets()[0].ambient_V_indices()
|
|
693
|
+
(0, 1, 2)
|
|
694
|
+
sage: pr.faces(1)
|
|
695
|
+
()
|
|
696
|
+
sage: pr.faces(0)
|
|
697
|
+
()
|
|
698
|
+
sage: pr.faces(-1)
|
|
699
|
+
(A -1-dimensional face of a Polyhedron in QQ^3,)
|
|
700
|
+
"""
|
|
701
|
+
return tuple(self.face_generator(face_dimension))
|
|
702
|
+
|
|
703
|
+
def facets(self):
|
|
704
|
+
r"""
|
|
705
|
+
Return the facets of the polyhedron.
|
|
706
|
+
|
|
707
|
+
Facets are the maximal nontrivial faces of polyhedra.
|
|
708
|
+
The empty face and the polyhedron itself are trivial.
|
|
709
|
+
|
|
710
|
+
A facet of a `d`-dimensional polyhedron is a face of dimension
|
|
711
|
+
`d-1`. For `d \neq 0` the converse is true as well.
|
|
712
|
+
|
|
713
|
+
OUTPUT:
|
|
714
|
+
|
|
715
|
+
A tuple of
|
|
716
|
+
:class:`~sage.geometry.polyhedron.face.PolyhedronFace`. See
|
|
717
|
+
:mod:`~sage.geometry.polyhedron.face` for details. The order
|
|
718
|
+
is random but fixed.
|
|
719
|
+
|
|
720
|
+
.. SEEALSO:: :meth:`facets`
|
|
721
|
+
|
|
722
|
+
EXAMPLES:
|
|
723
|
+
|
|
724
|
+
Here we find the eight three-dimensional facets of the
|
|
725
|
+
four-dimensional hypercube::
|
|
726
|
+
|
|
727
|
+
sage: p = polytopes.hypercube(4)
|
|
728
|
+
sage: p.facets()
|
|
729
|
+
(A 3-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 8 vertices,
|
|
730
|
+
A 3-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 8 vertices,
|
|
731
|
+
A 3-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 8 vertices,
|
|
732
|
+
A 3-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 8 vertices,
|
|
733
|
+
A 3-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 8 vertices,
|
|
734
|
+
A 3-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 8 vertices,
|
|
735
|
+
A 3-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 8 vertices,
|
|
736
|
+
A 3-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 8 vertices)
|
|
737
|
+
|
|
738
|
+
This is the same result as explicitly finding the
|
|
739
|
+
three-dimensional faces::
|
|
740
|
+
|
|
741
|
+
sage: dim = p.dimension()
|
|
742
|
+
sage: p.faces(dim-1)
|
|
743
|
+
(A 3-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 8 vertices,
|
|
744
|
+
A 3-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 8 vertices,
|
|
745
|
+
A 3-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 8 vertices,
|
|
746
|
+
A 3-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 8 vertices,
|
|
747
|
+
A 3-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 8 vertices,
|
|
748
|
+
A 3-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 8 vertices,
|
|
749
|
+
A 3-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 8 vertices,
|
|
750
|
+
A 3-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 8 vertices)
|
|
751
|
+
|
|
752
|
+
The ``0``-dimensional polyhedron does not have facets::
|
|
753
|
+
|
|
754
|
+
sage: P = Polyhedron([[0]])
|
|
755
|
+
sage: P.facets()
|
|
756
|
+
()
|
|
757
|
+
"""
|
|
758
|
+
if self.dimension() == 0:
|
|
759
|
+
return ()
|
|
760
|
+
return self.faces(self.dimension()-1)
|
|
761
|
+
|
|
762
|
+
@cached_method(do_pickle=True, key=lambda self, x, y, z: None)
|
|
763
|
+
def f_vector(self, num_threads=None, parallelization_depth=None, algorithm=None):
|
|
764
|
+
r"""
|
|
765
|
+
Return the f-vector.
|
|
766
|
+
|
|
767
|
+
INPUT:
|
|
768
|
+
|
|
769
|
+
- ``num_threads`` -- integer (optional); specify the number of threads;
|
|
770
|
+
otherwise determined by :func:`~sage.parallel.ncpus.ncpus`
|
|
771
|
+
|
|
772
|
+
- ``parallelization_depth`` -- integer (optional); specify
|
|
773
|
+
how deep in the lattice the parallelization is done
|
|
774
|
+
|
|
775
|
+
- ``algorithm`` -- string (optional);
|
|
776
|
+
specify whether the face generator starts with facets or vertices:
|
|
777
|
+
|
|
778
|
+
* ``'primal'`` -- start with the facets
|
|
779
|
+
* ``'dual'`` -- start with the vertices
|
|
780
|
+
* ``None`` -- choose automatically
|
|
781
|
+
|
|
782
|
+
OUTPUT:
|
|
783
|
+
|
|
784
|
+
Return a vector whose `i`-th entry is the number of
|
|
785
|
+
`i-2`-dimensional faces of the polytope.
|
|
786
|
+
|
|
787
|
+
.. NOTE::
|
|
788
|
+
|
|
789
|
+
The ``vertices`` as given by :meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.vertices`
|
|
790
|
+
do not need to correspond to `0`-dimensional faces. If a polyhedron
|
|
791
|
+
contains `k` lines they correspond to `k`-dimensional faces.
|
|
792
|
+
See example below.
|
|
793
|
+
|
|
794
|
+
EXAMPLES::
|
|
795
|
+
|
|
796
|
+
sage: p = Polyhedron(vertices=[[1, 2, 3], [1, 3, 2],
|
|
797
|
+
....: [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1], [0, 0, 0]])
|
|
798
|
+
sage: p.f_vector()
|
|
799
|
+
(1, 7, 12, 7, 1)
|
|
800
|
+
|
|
801
|
+
sage: polytopes.cyclic_polytope(4,10).f_vector()
|
|
802
|
+
(1, 10, 45, 70, 35, 1)
|
|
803
|
+
|
|
804
|
+
sage: polytopes.hypercube(5).f_vector()
|
|
805
|
+
(1, 32, 80, 80, 40, 10, 1)
|
|
806
|
+
|
|
807
|
+
Polyhedra with lines do not have `0`-faces::
|
|
808
|
+
|
|
809
|
+
sage: Polyhedron(ieqs=[[1,-1,0,0],[1,1,0,0]]).f_vector()
|
|
810
|
+
(1, 0, 0, 2, 1)
|
|
811
|
+
|
|
812
|
+
However, the method :meth:`Polyhedron_base.vertices` returns
|
|
813
|
+
two points that belong to the ``Vrepresentation``::
|
|
814
|
+
|
|
815
|
+
sage: P = Polyhedron(ieqs=[[1,-1,0],[1,1,0]])
|
|
816
|
+
sage: P.vertices()
|
|
817
|
+
(A vertex at (1, 0), A vertex at (-1, 0))
|
|
818
|
+
sage: P.f_vector()
|
|
819
|
+
(1, 0, 2, 1)
|
|
820
|
+
|
|
821
|
+
TESTS:
|
|
822
|
+
|
|
823
|
+
Check that :issue:`28828` is fixed::
|
|
824
|
+
|
|
825
|
+
sage: P.f_vector().is_immutable()
|
|
826
|
+
True
|
|
827
|
+
|
|
828
|
+
The cache of the f-vector is being pickled::
|
|
829
|
+
|
|
830
|
+
sage: P = polytopes.cube()
|
|
831
|
+
sage: P.f_vector()
|
|
832
|
+
(1, 8, 12, 6, 1)
|
|
833
|
+
sage: Q = loads(dumps(P))
|
|
834
|
+
sage: Q.f_vector.is_in_cache()
|
|
835
|
+
True
|
|
836
|
+
"""
|
|
837
|
+
return self.combinatorial_polyhedron().f_vector(num_threads, parallelization_depth, algorithm=algorithm)
|
|
838
|
+
|
|
839
|
+
def bounded_edges(self):
|
|
840
|
+
"""
|
|
841
|
+
Return the bounded edges (excluding rays and lines).
|
|
842
|
+
|
|
843
|
+
OUTPUT: a generator for pairs of vertices, one pair per edge
|
|
844
|
+
|
|
845
|
+
EXAMPLES::
|
|
846
|
+
|
|
847
|
+
sage: p = Polyhedron(vertices=[[1,0],[0,1]], rays=[[1,0],[0,1]])
|
|
848
|
+
sage: [ e for e in p.bounded_edges() ]
|
|
849
|
+
[(A vertex at (0, 1), A vertex at (1, 0))]
|
|
850
|
+
sage: for e in p.bounded_edges(): print(e)
|
|
851
|
+
(A vertex at (0, 1), A vertex at (1, 0))
|
|
852
|
+
"""
|
|
853
|
+
obj = self.Vrepresentation()
|
|
854
|
+
for i in range(len(obj)):
|
|
855
|
+
if not obj[i].is_vertex():
|
|
856
|
+
continue
|
|
857
|
+
for j in range(i+1, len(obj)):
|
|
858
|
+
if not obj[j].is_vertex():
|
|
859
|
+
continue
|
|
860
|
+
if self.vertex_adjacency_matrix()[i, j] == 0:
|
|
861
|
+
continue
|
|
862
|
+
yield (obj[i], obj[j])
|
|
863
|
+
|
|
864
|
+
@cached_method
|
|
865
|
+
def vertex_adjacency_matrix(self, algorithm=None):
|
|
866
|
+
"""
|
|
867
|
+
Return the binary matrix of vertex adjacencies.
|
|
868
|
+
|
|
869
|
+
INPUT:
|
|
870
|
+
|
|
871
|
+
- ``algorithm`` -- string (optional);
|
|
872
|
+
specify whether the face generator starts with facets or vertices:
|
|
873
|
+
|
|
874
|
+
* ``'primal'`` -- start with the facets
|
|
875
|
+
* ``'dual'`` -- start with the vertices
|
|
876
|
+
* ``None`` -- choose automatically
|
|
877
|
+
|
|
878
|
+
EXAMPLES::
|
|
879
|
+
|
|
880
|
+
sage: polytopes.simplex(4).vertex_adjacency_matrix()
|
|
881
|
+
[0 1 1 1 1]
|
|
882
|
+
[1 0 1 1 1]
|
|
883
|
+
[1 1 0 1 1]
|
|
884
|
+
[1 1 1 0 1]
|
|
885
|
+
[1 1 1 1 0]
|
|
886
|
+
|
|
887
|
+
The rows and columns of the vertex adjacency matrix correspond
|
|
888
|
+
to the :meth:`Vrepresentation` objects: vertices, rays, and
|
|
889
|
+
lines. The `(i,j)` matrix entry equals `1` if the `i`-th and
|
|
890
|
+
`j`-th V-representation object are adjacent.
|
|
891
|
+
|
|
892
|
+
Two vertices are adjacent if they are the endpoints of an
|
|
893
|
+
edge, that is, a one-dimensional face. For unbounded polyhedra
|
|
894
|
+
this clearly needs to be generalized and we define two
|
|
895
|
+
V-representation objects (see
|
|
896
|
+
:mod:`sage.geometry.polyhedron.constructor`) to be adjacent if
|
|
897
|
+
they together generate a one-face. There are three possible
|
|
898
|
+
combinations:
|
|
899
|
+
|
|
900
|
+
* Two vertices can bound a finite-length edge.
|
|
901
|
+
|
|
902
|
+
* A vertex and a ray can generate a half-infinite edge
|
|
903
|
+
starting at the vertex and with the direction given by the
|
|
904
|
+
ray.
|
|
905
|
+
|
|
906
|
+
* A vertex and a line can generate an infinite edge. The
|
|
907
|
+
position of the vertex on the line is arbitrary in this
|
|
908
|
+
case, only its transverse position matters. The direction of
|
|
909
|
+
the edge is given by the line generator.
|
|
910
|
+
|
|
911
|
+
For example, take the half-plane::
|
|
912
|
+
|
|
913
|
+
sage: half_plane = Polyhedron(ieqs=[(0,1,0)])
|
|
914
|
+
sage: half_plane.Hrepresentation()
|
|
915
|
+
(An inequality (1, 0) x + 0 >= 0,)
|
|
916
|
+
|
|
917
|
+
Its (non-unique) V-representation consists of a vertex, a ray,
|
|
918
|
+
and a line. The only edge is spanned by the vertex and the
|
|
919
|
+
line generator, so they are adjacent::
|
|
920
|
+
|
|
921
|
+
sage: half_plane.Vrepresentation()
|
|
922
|
+
(A line in the direction (0, 1), A ray in the direction (1, 0), A vertex at (0, 0))
|
|
923
|
+
sage: half_plane.vertex_adjacency_matrix()
|
|
924
|
+
[0 0 1]
|
|
925
|
+
[0 0 0]
|
|
926
|
+
[1 0 0]
|
|
927
|
+
|
|
928
|
+
In one dimension higher, that is for a half-space in 3
|
|
929
|
+
dimensions, there is no one-dimensional face. Hence nothing is
|
|
930
|
+
adjacent::
|
|
931
|
+
|
|
932
|
+
sage: Polyhedron(ieqs=[(0,1,0,0)]).vertex_adjacency_matrix()
|
|
933
|
+
[0 0 0 0]
|
|
934
|
+
[0 0 0 0]
|
|
935
|
+
[0 0 0 0]
|
|
936
|
+
[0 0 0 0]
|
|
937
|
+
|
|
938
|
+
EXAMPLES:
|
|
939
|
+
|
|
940
|
+
In a bounded polygon, every vertex has precisely two adjacent ones::
|
|
941
|
+
|
|
942
|
+
sage: P = Polyhedron(vertices=[(0, 1), (1, 0), (3, 0), (4, 1)])
|
|
943
|
+
sage: for v in P.Vrep_generator():
|
|
944
|
+
....: print("{} {}".format(P.adjacency_matrix().row(v.index()), v))
|
|
945
|
+
(0, 1, 0, 1) A vertex at (0, 1)
|
|
946
|
+
(1, 0, 1, 0) A vertex at (1, 0)
|
|
947
|
+
(0, 1, 0, 1) A vertex at (3, 0)
|
|
948
|
+
(1, 0, 1, 0) A vertex at (4, 1)
|
|
949
|
+
|
|
950
|
+
If the V-representation of the polygon contains vertices and
|
|
951
|
+
one ray, then each V-representation object is adjacent to two
|
|
952
|
+
V-representation objects::
|
|
953
|
+
|
|
954
|
+
sage: P = Polyhedron(vertices=[(0, 1), (1, 0), (3, 0), (4, 1)],
|
|
955
|
+
....: rays=[(0,1)])
|
|
956
|
+
sage: for v in P.Vrep_generator():
|
|
957
|
+
....: print("{} {}".format(P.adjacency_matrix().row(v.index()), v))
|
|
958
|
+
(0, 1, 0, 0, 1) A ray in the direction (0, 1)
|
|
959
|
+
(1, 0, 1, 0, 0) A vertex at (0, 1)
|
|
960
|
+
(0, 1, 0, 1, 0) A vertex at (1, 0)
|
|
961
|
+
(0, 0, 1, 0, 1) A vertex at (3, 0)
|
|
962
|
+
(1, 0, 0, 1, 0) A vertex at (4, 1)
|
|
963
|
+
|
|
964
|
+
If the V-representation of the polygon contains vertices and
|
|
965
|
+
two distinct rays, then each vertex is adjacent to two
|
|
966
|
+
V-representation objects (which can now be vertices or
|
|
967
|
+
rays). The two rays are not adjacent to each other::
|
|
968
|
+
|
|
969
|
+
sage: P = Polyhedron(vertices=[(0, 1), (1, 0), (3, 0), (4, 1)],
|
|
970
|
+
....: rays=[(0,1), (1,1)])
|
|
971
|
+
sage: for v in P.Vrep_generator():
|
|
972
|
+
....: print("{} {}".format(P.adjacency_matrix().row(v.index()), v))
|
|
973
|
+
(0, 1, 0, 0, 0) A ray in the direction (0, 1)
|
|
974
|
+
(1, 0, 1, 0, 0) A vertex at (0, 1)
|
|
975
|
+
(0, 1, 0, 0, 1) A vertex at (1, 0)
|
|
976
|
+
(0, 0, 0, 0, 1) A ray in the direction (1, 1)
|
|
977
|
+
(0, 0, 1, 1, 0) A vertex at (3, 0)
|
|
978
|
+
|
|
979
|
+
The vertex adjacency matrix has base ring integers. This way one can express various
|
|
980
|
+
counting questions::
|
|
981
|
+
|
|
982
|
+
sage: P = polytopes.cube()
|
|
983
|
+
sage: Q = P.stack(P.faces(2)[0])
|
|
984
|
+
sage: M = Q.vertex_adjacency_matrix()
|
|
985
|
+
sage: sum(M)
|
|
986
|
+
(4, 4, 3, 3, 4, 4, 4, 3, 3)
|
|
987
|
+
sage: G = Q.vertex_graph() # needs sage.graphs
|
|
988
|
+
sage: G.degree() # needs sage.graphs
|
|
989
|
+
[4, 4, 3, 3, 4, 4, 4, 3, 3]
|
|
990
|
+
|
|
991
|
+
TESTS:
|
|
992
|
+
|
|
993
|
+
Check that :issue:`28828` is fixed::
|
|
994
|
+
|
|
995
|
+
sage: P.adjacency_matrix().is_immutable()
|
|
996
|
+
True
|
|
997
|
+
"""
|
|
998
|
+
return self.combinatorial_polyhedron().vertex_adjacency_matrix(algorithm=algorithm)
|
|
999
|
+
|
|
1000
|
+
adjacency_matrix = vertex_adjacency_matrix
|
|
1001
|
+
|
|
1002
|
+
@cached_method
|
|
1003
|
+
def facet_adjacency_matrix(self, algorithm=None):
|
|
1004
|
+
"""
|
|
1005
|
+
Return the adjacency matrix for the facets.
|
|
1006
|
+
|
|
1007
|
+
INPUT:
|
|
1008
|
+
|
|
1009
|
+
- ``algorithm`` -- string (optional);
|
|
1010
|
+
specify whether the face generator starts with facets or vertices:
|
|
1011
|
+
|
|
1012
|
+
* ``'primal'`` -- start with the facets
|
|
1013
|
+
* ``'dual'`` -- start with the vertices
|
|
1014
|
+
* ``None`` -- choose automatically
|
|
1015
|
+
|
|
1016
|
+
EXAMPLES::
|
|
1017
|
+
|
|
1018
|
+
sage: s4 = polytopes.simplex(4, project=True) # needs cddexec
|
|
1019
|
+
sage: s4.facet_adjacency_matrix() # needs cddexec
|
|
1020
|
+
[0 1 1 1 1]
|
|
1021
|
+
[1 0 1 1 1]
|
|
1022
|
+
[1 1 0 1 1]
|
|
1023
|
+
[1 1 1 0 1]
|
|
1024
|
+
[1 1 1 1 0]
|
|
1025
|
+
|
|
1026
|
+
sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)])
|
|
1027
|
+
sage: p.facet_adjacency_matrix()
|
|
1028
|
+
[0 1 1]
|
|
1029
|
+
[1 0 1]
|
|
1030
|
+
[1 1 0]
|
|
1031
|
+
|
|
1032
|
+
|
|
1033
|
+
The facet adjacency matrix has base ring integers. This way one can express various
|
|
1034
|
+
counting questions::
|
|
1035
|
+
|
|
1036
|
+
sage: P = polytopes.cube()
|
|
1037
|
+
sage: Q = P.stack(P.faces(2)[0])
|
|
1038
|
+
sage: M = Q.facet_adjacency_matrix()
|
|
1039
|
+
sage: sum(M)
|
|
1040
|
+
(4, 4, 4, 4, 3, 3, 3, 3, 4)
|
|
1041
|
+
|
|
1042
|
+
TESTS:
|
|
1043
|
+
|
|
1044
|
+
Check that :issue:`28828` is fixed::
|
|
1045
|
+
|
|
1046
|
+
sage: s4.facet_adjacency_matrix().is_immutable() # needs cddexec
|
|
1047
|
+
True
|
|
1048
|
+
|
|
1049
|
+
Checks that :issue:`22455` is fixed::
|
|
1050
|
+
|
|
1051
|
+
sage: s = polytopes.simplex(2)
|
|
1052
|
+
sage: s.facet_adjacency_matrix()
|
|
1053
|
+
[0 1 1]
|
|
1054
|
+
[1 0 1]
|
|
1055
|
+
[1 1 0]
|
|
1056
|
+
"""
|
|
1057
|
+
return self.combinatorial_polyhedron().facet_adjacency_matrix(algorithm=algorithm)
|
|
1058
|
+
|
|
1059
|
+
def a_maximal_chain(self):
|
|
1060
|
+
r"""
|
|
1061
|
+
Return a maximal chain of the face lattice in increasing order.
|
|
1062
|
+
|
|
1063
|
+
EXAMPLES::
|
|
1064
|
+
|
|
1065
|
+
sage: P = polytopes.cube()
|
|
1066
|
+
sage: P.a_maximal_chain()
|
|
1067
|
+
[A -1-dimensional face of a Polyhedron in ZZ^3,
|
|
1068
|
+
A 0-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 1 vertex,
|
|
1069
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
1070
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 4 vertices,
|
|
1071
|
+
A 3-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 8 vertices]
|
|
1072
|
+
sage: P = polytopes.cube()
|
|
1073
|
+
sage: chain = P.a_maximal_chain(); chain
|
|
1074
|
+
[A -1-dimensional face of a Polyhedron in ZZ^3,
|
|
1075
|
+
A 0-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 1 vertex,
|
|
1076
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices,
|
|
1077
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 4 vertices,
|
|
1078
|
+
A 3-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 8 vertices]
|
|
1079
|
+
sage: [face.ambient_V_indices() for face in chain]
|
|
1080
|
+
[(), (5,), (0, 5), (0, 3, 4, 5), (0, 1, 2, 3, 4, 5, 6, 7)]
|
|
1081
|
+
|
|
1082
|
+
TESTS:
|
|
1083
|
+
|
|
1084
|
+
Check output for the empty polyhedron::
|
|
1085
|
+
|
|
1086
|
+
sage: P = Polyhedron()
|
|
1087
|
+
sage: P.a_maximal_chain()
|
|
1088
|
+
[A -1-dimensional face of a Polyhedron in ZZ^0]
|
|
1089
|
+
"""
|
|
1090
|
+
comb_chain = self.combinatorial_polyhedron().a_maximal_chain()
|
|
1091
|
+
|
|
1092
|
+
from sage.geometry.polyhedron.face import combinatorial_face_to_polyhedral_face
|
|
1093
|
+
empty_face = self.faces(-1)[0]
|
|
1094
|
+
universe = self.faces(self.dim())[0]
|
|
1095
|
+
|
|
1096
|
+
if self.dim() == -1:
|
|
1097
|
+
return [empty_face]
|
|
1098
|
+
|
|
1099
|
+
return [empty_face] + \
|
|
1100
|
+
[combinatorial_face_to_polyhedral_face(self, face)
|
|
1101
|
+
for face in comb_chain] + \
|
|
1102
|
+
[universe]
|
|
1103
|
+
|
|
1104
|
+
def is_simplex(self):
|
|
1105
|
+
r"""
|
|
1106
|
+
Return whether the polyhedron is a simplex.
|
|
1107
|
+
|
|
1108
|
+
A simplex is a bounded polyhedron with `d+1` vertices, where
|
|
1109
|
+
`d` is the dimension.
|
|
1110
|
+
|
|
1111
|
+
EXAMPLES::
|
|
1112
|
+
|
|
1113
|
+
sage: Polyhedron([(0,0,0), (1,0,0), (0,1,0)]).is_simplex()
|
|
1114
|
+
True
|
|
1115
|
+
sage: polytopes.simplex(3).is_simplex()
|
|
1116
|
+
True
|
|
1117
|
+
sage: polytopes.hypercube(3).is_simplex()
|
|
1118
|
+
False
|
|
1119
|
+
"""
|
|
1120
|
+
return self.is_compact() and (self.dim()+1 == self.n_vertices())
|
|
1121
|
+
|
|
1122
|
+
def simplicity(self):
|
|
1123
|
+
r"""
|
|
1124
|
+
Return the largest integer `k` such that the polytope is `k`-simple.
|
|
1125
|
+
|
|
1126
|
+
A polytope `P` is `k`-simple, if every `(d-1-k)`-face
|
|
1127
|
+
is contained in exactly `k+1` facets of `P` for `1 \leq k \leq d-1`.
|
|
1128
|
+
Equivalently it is `k`-simple if the polar/dual polytope is `k`-simplicial.
|
|
1129
|
+
If ``self`` is a simplex, it returns its dimension.
|
|
1130
|
+
|
|
1131
|
+
EXAMPLES::
|
|
1132
|
+
|
|
1133
|
+
sage: polytopes.hypersimplex(4,2).simplicity()
|
|
1134
|
+
1
|
|
1135
|
+
sage: polytopes.hypersimplex(5,2).simplicity()
|
|
1136
|
+
2
|
|
1137
|
+
sage: polytopes.hypersimplex(6,2).simplicity()
|
|
1138
|
+
3
|
|
1139
|
+
sage: polytopes.simplex(3).simplicity()
|
|
1140
|
+
3
|
|
1141
|
+
sage: polytopes.simplex(1).simplicity()
|
|
1142
|
+
1
|
|
1143
|
+
|
|
1144
|
+
The method is not implemented for unbounded polyhedra::
|
|
1145
|
+
|
|
1146
|
+
sage: p = Polyhedron(vertices=[(0,0)],rays=[(1,0),(0,1)])
|
|
1147
|
+
sage: p.simplicity()
|
|
1148
|
+
Traceback (most recent call last):
|
|
1149
|
+
...
|
|
1150
|
+
NotImplementedError: this function is implemented for polytopes only
|
|
1151
|
+
"""
|
|
1152
|
+
if not self.is_compact():
|
|
1153
|
+
raise NotImplementedError("this function is implemented for polytopes only")
|
|
1154
|
+
return self.combinatorial_polyhedron().simplicity()
|
|
1155
|
+
|
|
1156
|
+
def is_simple(self):
|
|
1157
|
+
"""
|
|
1158
|
+
Test for simplicity of a polytope.
|
|
1159
|
+
|
|
1160
|
+
See :wikipedia:`Simple_polytope`
|
|
1161
|
+
|
|
1162
|
+
EXAMPLES::
|
|
1163
|
+
|
|
1164
|
+
sage: p = Polyhedron([[0,0,0],[1,0,0],[0,1,0],[0,0,1]])
|
|
1165
|
+
sage: p.is_simple()
|
|
1166
|
+
True
|
|
1167
|
+
sage: p = Polyhedron([[0,0,0],[4,4,0],[4,0,0],[0,4,0],[2,2,2]])
|
|
1168
|
+
sage: p.is_simple()
|
|
1169
|
+
False
|
|
1170
|
+
"""
|
|
1171
|
+
if not self.is_compact():
|
|
1172
|
+
return False
|
|
1173
|
+
return self.combinatorial_polyhedron().is_simple()
|
|
1174
|
+
|
|
1175
|
+
def simpliciality(self):
|
|
1176
|
+
r"""
|
|
1177
|
+
Return the largest integer `k` such that the polytope is `k`-simplicial.
|
|
1178
|
+
|
|
1179
|
+
A polytope is `k`-simplicial, if every `k`-face is a simplex.
|
|
1180
|
+
If ``self`` is a simplex, returns its dimension.
|
|
1181
|
+
|
|
1182
|
+
EXAMPLES::
|
|
1183
|
+
|
|
1184
|
+
sage: polytopes.cyclic_polytope(10,4).simpliciality()
|
|
1185
|
+
3
|
|
1186
|
+
sage: polytopes.hypersimplex(5,2).simpliciality()
|
|
1187
|
+
2
|
|
1188
|
+
sage: polytopes.cross_polytope(4).simpliciality()
|
|
1189
|
+
3
|
|
1190
|
+
sage: polytopes.simplex(3).simpliciality()
|
|
1191
|
+
3
|
|
1192
|
+
sage: polytopes.simplex(1).simpliciality()
|
|
1193
|
+
1
|
|
1194
|
+
|
|
1195
|
+
The method is not implemented for unbounded polyhedra::
|
|
1196
|
+
|
|
1197
|
+
sage: p = Polyhedron(vertices=[(0,0)],rays=[(1,0),(0,1)])
|
|
1198
|
+
sage: p.simpliciality()
|
|
1199
|
+
Traceback (most recent call last):
|
|
1200
|
+
...
|
|
1201
|
+
NotImplementedError: this function is implemented for polytopes only
|
|
1202
|
+
"""
|
|
1203
|
+
if not self.is_compact():
|
|
1204
|
+
raise NotImplementedError("this function is implemented for polytopes only")
|
|
1205
|
+
return self.combinatorial_polyhedron().simpliciality()
|
|
1206
|
+
|
|
1207
|
+
def is_simplicial(self):
|
|
1208
|
+
"""
|
|
1209
|
+
Test if the polytope is simplicial.
|
|
1210
|
+
|
|
1211
|
+
A polytope is simplicial if every facet is a simplex.
|
|
1212
|
+
|
|
1213
|
+
See :wikipedia:`Simplicial_polytope`
|
|
1214
|
+
|
|
1215
|
+
EXAMPLES::
|
|
1216
|
+
|
|
1217
|
+
sage: p = polytopes.hypercube(3)
|
|
1218
|
+
sage: p.is_simplicial()
|
|
1219
|
+
False
|
|
1220
|
+
sage: q = polytopes.simplex(5, project=True) # needs cddexec
|
|
1221
|
+
sage: q.is_simplicial() # needs cddexec
|
|
1222
|
+
True
|
|
1223
|
+
sage: p = Polyhedron([[0,0,0],[1,0,0],[0,1,0],[0,0,1]])
|
|
1224
|
+
sage: p.is_simplicial()
|
|
1225
|
+
True
|
|
1226
|
+
sage: q = Polyhedron([[1,1,1],[-1,1,1],[1,-1,1],[-1,-1,1],[1,1,-1]])
|
|
1227
|
+
sage: q.is_simplicial()
|
|
1228
|
+
False
|
|
1229
|
+
sage: P = polytopes.simplex(); P
|
|
1230
|
+
A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 4 vertices
|
|
1231
|
+
sage: P.is_simplicial()
|
|
1232
|
+
True
|
|
1233
|
+
|
|
1234
|
+
The method is not implemented for unbounded polyhedra::
|
|
1235
|
+
|
|
1236
|
+
sage: p = Polyhedron(vertices=[(0,0)],rays=[(1,0),(0,1)])
|
|
1237
|
+
sage: p.is_simplicial()
|
|
1238
|
+
Traceback (most recent call last):
|
|
1239
|
+
...
|
|
1240
|
+
NotImplementedError: this function is implemented for polytopes only
|
|
1241
|
+
"""
|
|
1242
|
+
if not self.is_compact():
|
|
1243
|
+
raise NotImplementedError("this function is implemented for polytopes only")
|
|
1244
|
+
return self.combinatorial_polyhedron().is_simplicial()
|
|
1245
|
+
|
|
1246
|
+
def is_pyramid(self, certificate=False):
|
|
1247
|
+
"""
|
|
1248
|
+
Test whether the polytope is a pyramid over one of its facets.
|
|
1249
|
+
|
|
1250
|
+
INPUT:
|
|
1251
|
+
|
|
1252
|
+
- ``certificate`` -- boolean (default: ``False``); specifies whether
|
|
1253
|
+
to return a vertex of the polytope which is the apex of a pyramid,
|
|
1254
|
+
if found
|
|
1255
|
+
|
|
1256
|
+
OUTPUT: if ``certificate`` is ``True``, returns a tuple containing:
|
|
1257
|
+
|
|
1258
|
+
1. Boolean.
|
|
1259
|
+
2. The apex of the pyramid or ``None``.
|
|
1260
|
+
|
|
1261
|
+
If ``certificate`` is ``False`` returns a boolean.
|
|
1262
|
+
|
|
1263
|
+
EXAMPLES::
|
|
1264
|
+
|
|
1265
|
+
sage: P = polytopes.simplex(3)
|
|
1266
|
+
sage: P.is_pyramid()
|
|
1267
|
+
True
|
|
1268
|
+
sage: P.is_pyramid(certificate=True)
|
|
1269
|
+
(True, A vertex at (1, 0, 0, 0))
|
|
1270
|
+
sage: egyptian_pyramid = polytopes.regular_polygon(4).pyramid() # needs sage.rings.number_field
|
|
1271
|
+
sage: egyptian_pyramid.is_pyramid() # needs sage.rings.number_field
|
|
1272
|
+
True
|
|
1273
|
+
sage: Q = polytopes.octahedron()
|
|
1274
|
+
sage: Q.is_pyramid()
|
|
1275
|
+
False
|
|
1276
|
+
|
|
1277
|
+
For the `0`-dimensional polyhedron, the output is ``True``,
|
|
1278
|
+
but it cannot be constructed as a pyramid over the empty polyhedron::
|
|
1279
|
+
|
|
1280
|
+
sage: P = Polyhedron([[0]])
|
|
1281
|
+
sage: P.is_pyramid()
|
|
1282
|
+
True
|
|
1283
|
+
sage: Polyhedron().pyramid()
|
|
1284
|
+
Traceback (most recent call last):
|
|
1285
|
+
...
|
|
1286
|
+
ZeroDivisionError: rational division by zero
|
|
1287
|
+
"""
|
|
1288
|
+
if not self.is_compact():
|
|
1289
|
+
raise ValueError("polyhedron has to be compact")
|
|
1290
|
+
|
|
1291
|
+
return self.combinatorial_polyhedron().is_pyramid(certificate)
|
|
1292
|
+
|
|
1293
|
+
def is_bipyramid(self, certificate=False):
|
|
1294
|
+
r"""
|
|
1295
|
+
Test whether the polytope is combinatorially equivalent to a
|
|
1296
|
+
bipyramid over some polytope.
|
|
1297
|
+
|
|
1298
|
+
INPUT:
|
|
1299
|
+
|
|
1300
|
+
- ``certificate`` -- boolean (default: ``False``); specifies whether
|
|
1301
|
+
to return two vertices of the polytope which are the apices of a
|
|
1302
|
+
bipyramid, if found
|
|
1303
|
+
|
|
1304
|
+
OUTPUT: if ``certificate`` is ``True``, returns a tuple containing:
|
|
1305
|
+
|
|
1306
|
+
1. Boolean.
|
|
1307
|
+
2. ``None`` or a tuple containing:
|
|
1308
|
+
a. The first apex.
|
|
1309
|
+
b. The second apex.
|
|
1310
|
+
|
|
1311
|
+
If ``certificate`` is ``False`` returns a boolean.
|
|
1312
|
+
|
|
1313
|
+
EXAMPLES::
|
|
1314
|
+
|
|
1315
|
+
sage: P = polytopes.octahedron()
|
|
1316
|
+
sage: P.is_bipyramid()
|
|
1317
|
+
True
|
|
1318
|
+
sage: P.is_bipyramid(certificate=True)
|
|
1319
|
+
(True, [A vertex at (1, 0, 0), A vertex at (-1, 0, 0)])
|
|
1320
|
+
sage: Q = polytopes.cyclic_polytope(3,7)
|
|
1321
|
+
sage: Q.is_bipyramid()
|
|
1322
|
+
False
|
|
1323
|
+
sage: R = Q.bipyramid()
|
|
1324
|
+
sage: R.is_bipyramid(certificate=True)
|
|
1325
|
+
(True, [A vertex at (1, 3, 13, 63), A vertex at (-1, 3, 13, 63)])
|
|
1326
|
+
|
|
1327
|
+
TESTS::
|
|
1328
|
+
|
|
1329
|
+
sage: P = polytopes.permutahedron(4).bipyramid()
|
|
1330
|
+
sage: P.is_bipyramid()
|
|
1331
|
+
True
|
|
1332
|
+
|
|
1333
|
+
sage: P = polytopes.cube()
|
|
1334
|
+
sage: P.is_bipyramid()
|
|
1335
|
+
False
|
|
1336
|
+
|
|
1337
|
+
sage: P = Polyhedron(vertices=[[0,1], [1,0]], rays=[[1,1]])
|
|
1338
|
+
sage: P.is_bipyramid()
|
|
1339
|
+
Traceback (most recent call last):
|
|
1340
|
+
...
|
|
1341
|
+
ValueError: polyhedron has to be compact
|
|
1342
|
+
"""
|
|
1343
|
+
if not self.is_compact():
|
|
1344
|
+
raise ValueError("polyhedron has to be compact")
|
|
1345
|
+
|
|
1346
|
+
return self.combinatorial_polyhedron().is_bipyramid(certificate)
|
|
1347
|
+
|
|
1348
|
+
def is_prism(self, certificate=False):
|
|
1349
|
+
"""
|
|
1350
|
+
Test whether the polytope is combinatorially equivalent to a prism of
|
|
1351
|
+
some polytope.
|
|
1352
|
+
|
|
1353
|
+
INPUT:
|
|
1354
|
+
|
|
1355
|
+
- ``certificate`` -- boolean (default: ``False``); specifies whether
|
|
1356
|
+
to return two facets of the polytope which are the bases of a prism,
|
|
1357
|
+
if found
|
|
1358
|
+
|
|
1359
|
+
OUTPUT: if ``certificate`` is ``True``, returns a tuple containing:
|
|
1360
|
+
|
|
1361
|
+
1. Boolean.
|
|
1362
|
+
2. ``None`` or a tuple containing:
|
|
1363
|
+
a. List of the vertices of the first base facet.
|
|
1364
|
+
b. List of the vertices of the second base facet.
|
|
1365
|
+
|
|
1366
|
+
If ``certificate`` is ``False`` returns a boolean.
|
|
1367
|
+
|
|
1368
|
+
EXAMPLES::
|
|
1369
|
+
|
|
1370
|
+
sage: P = polytopes.cube()
|
|
1371
|
+
sage: P.is_prism()
|
|
1372
|
+
True
|
|
1373
|
+
sage: P.is_prism(certificate=True)
|
|
1374
|
+
(True,
|
|
1375
|
+
[(A vertex at (1, -1, -1),
|
|
1376
|
+
A vertex at (1, -1, 1),
|
|
1377
|
+
A vertex at (-1, -1, 1),
|
|
1378
|
+
A vertex at (-1, -1, -1)),
|
|
1379
|
+
(A vertex at (1, 1, -1),
|
|
1380
|
+
A vertex at (1, 1, 1),
|
|
1381
|
+
A vertex at (-1, 1, -1),
|
|
1382
|
+
A vertex at (-1, 1, 1))])
|
|
1383
|
+
sage: Q = polytopes.cyclic_polytope(3,8)
|
|
1384
|
+
sage: Q.is_prism()
|
|
1385
|
+
False
|
|
1386
|
+
sage: R = Q.prism()
|
|
1387
|
+
sage: R.is_prism(certificate=True)
|
|
1388
|
+
(True,
|
|
1389
|
+
[(A vertex at (0, 3, 9, 27),
|
|
1390
|
+
A vertex at (0, 6, 36, 216),
|
|
1391
|
+
A vertex at (0, 0, 0, 0),
|
|
1392
|
+
A vertex at (0, 7, 49, 343),
|
|
1393
|
+
A vertex at (0, 5, 25, 125),
|
|
1394
|
+
A vertex at (0, 1, 1, 1),
|
|
1395
|
+
A vertex at (0, 2, 4, 8),
|
|
1396
|
+
A vertex at (0, 4, 16, 64)),
|
|
1397
|
+
(A vertex at (1, 6, 36, 216),
|
|
1398
|
+
A vertex at (1, 0, 0, 0),
|
|
1399
|
+
A vertex at (1, 7, 49, 343),
|
|
1400
|
+
A vertex at (1, 5, 25, 125),
|
|
1401
|
+
A vertex at (1, 1, 1, 1),
|
|
1402
|
+
A vertex at (1, 2, 4, 8),
|
|
1403
|
+
A vertex at (1, 4, 16, 64),
|
|
1404
|
+
A vertex at (1, 3, 9, 27))])
|
|
1405
|
+
|
|
1406
|
+
TESTS::
|
|
1407
|
+
|
|
1408
|
+
sage: P = polytopes.cross_polytope(5)
|
|
1409
|
+
sage: P.is_prism()
|
|
1410
|
+
False
|
|
1411
|
+
|
|
1412
|
+
sage: P = polytopes.permutahedron(4).prism()
|
|
1413
|
+
sage: P.is_prism()
|
|
1414
|
+
True
|
|
1415
|
+
|
|
1416
|
+
sage: P = Polyhedron(vertices=[[0,1], [1,0]], rays=[[1,1]])
|
|
1417
|
+
sage: P.is_prism()
|
|
1418
|
+
Traceback (most recent call last):
|
|
1419
|
+
...
|
|
1420
|
+
NotImplementedError: polyhedron has to be compact
|
|
1421
|
+
"""
|
|
1422
|
+
if not self.is_compact():
|
|
1423
|
+
raise NotImplementedError("polyhedron has to be compact")
|
|
1424
|
+
|
|
1425
|
+
return self.combinatorial_polyhedron().is_prism(certificate)
|
|
1426
|
+
|
|
1427
|
+
def is_lawrence_polytope(self):
|
|
1428
|
+
"""
|
|
1429
|
+
Return ``True`` if ``self`` is a Lawrence polytope.
|
|
1430
|
+
|
|
1431
|
+
A polytope is called a Lawrence polytope if it has a centrally
|
|
1432
|
+
symmetric (normalized) Gale diagram.
|
|
1433
|
+
|
|
1434
|
+
EXAMPLES::
|
|
1435
|
+
|
|
1436
|
+
sage: P = polytopes.hypersimplex(5,2)
|
|
1437
|
+
sage: L = P.lawrence_polytope()
|
|
1438
|
+
sage: L.is_lattice_polytope()
|
|
1439
|
+
True
|
|
1440
|
+
|
|
1441
|
+
sage: egyptian_pyramid = polytopes.regular_polygon(4).pyramid() # needs sage.number_field
|
|
1442
|
+
sage: egyptian_pyramid.is_lawrence_polytope() # needs sage.number_field
|
|
1443
|
+
True
|
|
1444
|
+
|
|
1445
|
+
sage: polytopes.octahedron().is_lawrence_polytope()
|
|
1446
|
+
False
|
|
1447
|
+
|
|
1448
|
+
REFERENCES:
|
|
1449
|
+
|
|
1450
|
+
For more information, see [BaSt1990]_.
|
|
1451
|
+
"""
|
|
1452
|
+
if not self.is_compact():
|
|
1453
|
+
raise NotImplementedError("self must be a polytope")
|
|
1454
|
+
|
|
1455
|
+
return self.combinatorial_polyhedron().is_lawrence_polytope()
|
|
1456
|
+
|
|
1457
|
+
def neighborliness(self):
|
|
1458
|
+
r"""
|
|
1459
|
+
Return the largest ``k``, such that the polyhedron is ``k``-neighborly.
|
|
1460
|
+
|
|
1461
|
+
A polyhedron is `k`-neighborly if every set of `n` vertices forms a face
|
|
1462
|
+
for `n` up to `k`.
|
|
1463
|
+
|
|
1464
|
+
In case of the `d`-dimensional simplex, it returns `d + 1`.
|
|
1465
|
+
|
|
1466
|
+
.. SEEALSO::
|
|
1467
|
+
|
|
1468
|
+
:meth:`is_neighborly`
|
|
1469
|
+
|
|
1470
|
+
EXAMPLES::
|
|
1471
|
+
|
|
1472
|
+
sage: cube = polytopes.cube()
|
|
1473
|
+
sage: cube.neighborliness()
|
|
1474
|
+
1
|
|
1475
|
+
sage: P = Polyhedron(); P
|
|
1476
|
+
The empty polyhedron in ZZ^0
|
|
1477
|
+
sage: P.neighborliness()
|
|
1478
|
+
0
|
|
1479
|
+
sage: P = Polyhedron([[0]]); P
|
|
1480
|
+
A 0-dimensional polyhedron in ZZ^1 defined as the convex hull of 1 vertex
|
|
1481
|
+
sage: P.neighborliness()
|
|
1482
|
+
1
|
|
1483
|
+
sage: S = polytopes.simplex(5); S
|
|
1484
|
+
A 5-dimensional polyhedron in ZZ^6 defined as the convex hull of 6 vertices
|
|
1485
|
+
sage: S.neighborliness()
|
|
1486
|
+
6
|
|
1487
|
+
sage: C = polytopes.cyclic_polytope(7,10); C
|
|
1488
|
+
A 7-dimensional polyhedron in QQ^7 defined as the convex hull of 10 vertices
|
|
1489
|
+
sage: C.neighborliness()
|
|
1490
|
+
3
|
|
1491
|
+
sage: C = polytopes.cyclic_polytope(6,11); C
|
|
1492
|
+
A 6-dimensional polyhedron in QQ^6 defined as the convex hull of 11 vertices
|
|
1493
|
+
sage: C.neighborliness()
|
|
1494
|
+
3
|
|
1495
|
+
sage: [polytopes.cyclic_polytope(5,n).neighborliness() for n in range(6,10)]
|
|
1496
|
+
[6, 2, 2, 2]
|
|
1497
|
+
"""
|
|
1498
|
+
return self.combinatorial_polyhedron().neighborliness()
|
|
1499
|
+
|
|
1500
|
+
def is_neighborly(self, k=None):
|
|
1501
|
+
r"""
|
|
1502
|
+
Return whether the polyhedron is neighborly.
|
|
1503
|
+
|
|
1504
|
+
If the input ``k`` is provided, then return whether the polyhedron is ``k``-neighborly
|
|
1505
|
+
|
|
1506
|
+
A polyhedron is neighborly if every set of `n` vertices forms a face
|
|
1507
|
+
for `n` up to floor of half the dimension of the polyhedron.
|
|
1508
|
+
It is `k`-neighborly if this is true for `n` up to `k`.
|
|
1509
|
+
|
|
1510
|
+
INPUT:
|
|
1511
|
+
|
|
1512
|
+
- ``k`` -- the dimension up to which to check if every set of ``k``
|
|
1513
|
+
vertices forms a face. If no ``k`` is provided, check up to floor
|
|
1514
|
+
of half the dimension of the polyhedron.
|
|
1515
|
+
|
|
1516
|
+
OUTPUT:
|
|
1517
|
+
|
|
1518
|
+
- ``True`` if every set of up to ``k`` vertices forms a face,
|
|
1519
|
+
- ``False`` otherwise
|
|
1520
|
+
|
|
1521
|
+
.. SEEALSO::
|
|
1522
|
+
|
|
1523
|
+
:meth:`neighborliness`
|
|
1524
|
+
|
|
1525
|
+
EXAMPLES::
|
|
1526
|
+
|
|
1527
|
+
sage: cube = polytopes.hypercube(3)
|
|
1528
|
+
sage: cube.is_neighborly()
|
|
1529
|
+
True
|
|
1530
|
+
sage: cube = polytopes.hypercube(4)
|
|
1531
|
+
sage: cube.is_neighborly()
|
|
1532
|
+
False
|
|
1533
|
+
|
|
1534
|
+
Cyclic polytopes are neighborly::
|
|
1535
|
+
|
|
1536
|
+
sage: all(polytopes.cyclic_polytope(i, i + 1 + j).is_neighborly() for i in range(5) for j in range(3))
|
|
1537
|
+
True
|
|
1538
|
+
|
|
1539
|
+
The neighborliness of a polyhedron equals floor of dimension half
|
|
1540
|
+
(or larger in case of a simplex) if and only if the polyhedron
|
|
1541
|
+
is neighborly::
|
|
1542
|
+
|
|
1543
|
+
sage: testpolys = [polytopes.cube(), polytopes.cyclic_polytope(6, 9), polytopes.simplex(6)]
|
|
1544
|
+
sage: [(P.neighborliness() >= P.dim() // 2) == P.is_neighborly() for P in testpolys]
|
|
1545
|
+
[True, True, True]
|
|
1546
|
+
"""
|
|
1547
|
+
return self.combinatorial_polyhedron().is_neighborly()
|
|
1548
|
+
|
|
1549
|
+
def join_of_Vrep(self, *Vrepresentatives):
|
|
1550
|
+
r"""
|
|
1551
|
+
Return the smallest face that contains ``Vrepresentatives``.
|
|
1552
|
+
|
|
1553
|
+
INPUT:
|
|
1554
|
+
|
|
1555
|
+
- ``Vrepresentatives`` -- vertices/rays/lines of ``self`` or indices of such
|
|
1556
|
+
|
|
1557
|
+
OUTPUT: a :class:`~sage.geometry.polyhedron.face.PolyhedronFace`
|
|
1558
|
+
|
|
1559
|
+
.. NOTE::
|
|
1560
|
+
|
|
1561
|
+
In the case of unbounded polyhedra, the join of rays etc. may not be well-defined.
|
|
1562
|
+
|
|
1563
|
+
EXAMPLES::
|
|
1564
|
+
|
|
1565
|
+
sage: P = polytopes.permutahedron(5)
|
|
1566
|
+
sage: P.join_of_Vrep(1)
|
|
1567
|
+
A 0-dimensional face of a Polyhedron in ZZ^5 defined as the convex hull of 1 vertex
|
|
1568
|
+
sage: P.join_of_Vrep()
|
|
1569
|
+
A -1-dimensional face of a Polyhedron in ZZ^5
|
|
1570
|
+
sage: P.join_of_Vrep(0,12,13).ambient_V_indices()
|
|
1571
|
+
(0, 12, 13, 68)
|
|
1572
|
+
|
|
1573
|
+
The input is flexible::
|
|
1574
|
+
|
|
1575
|
+
sage: P.join_of_Vrep(2, P.vertices()[3], P.Vrepresentation(4))
|
|
1576
|
+
A 2-dimensional face of a Polyhedron in ZZ^5 defined as the convex hull of 6 vertices
|
|
1577
|
+
|
|
1578
|
+
::
|
|
1579
|
+
|
|
1580
|
+
sage: P = polytopes.cube()
|
|
1581
|
+
sage: a, b = P.faces(0)[:2]
|
|
1582
|
+
sage: P.join_of_Vrep(a, b)
|
|
1583
|
+
A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices
|
|
1584
|
+
|
|
1585
|
+
In the case of an unbounded polyhedron, the join may not be well-defined::
|
|
1586
|
+
|
|
1587
|
+
sage: P = Polyhedron(vertices=[[1,0], [0,1]], rays=[[1,1]])
|
|
1588
|
+
sage: P.join_of_Vrep(0)
|
|
1589
|
+
A 0-dimensional face of a Polyhedron in QQ^2 defined as the convex hull of 1 vertex
|
|
1590
|
+
sage: P.join_of_Vrep(0,1)
|
|
1591
|
+
A 1-dimensional face of a Polyhedron in QQ^2 defined as the convex hull of 2 vertices
|
|
1592
|
+
sage: P.join_of_Vrep(0,2)
|
|
1593
|
+
A 1-dimensional face of a Polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 ray
|
|
1594
|
+
sage: P.join_of_Vrep(1,2)
|
|
1595
|
+
A 1-dimensional face of a Polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 ray
|
|
1596
|
+
sage: P.join_of_Vrep(2)
|
|
1597
|
+
Traceback (most recent call last):
|
|
1598
|
+
...
|
|
1599
|
+
ValueError: the join is not well-defined
|
|
1600
|
+
|
|
1601
|
+
The ``Vrepresentatives`` must be of ``self``::
|
|
1602
|
+
|
|
1603
|
+
sage: P = polytopes.cube(backend='ppl')
|
|
1604
|
+
sage: Q = polytopes.cube(backend='field')
|
|
1605
|
+
sage: v = P.vertices()[0]
|
|
1606
|
+
sage: P.join_of_Vrep(v)
|
|
1607
|
+
A 0-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 1 vertex
|
|
1608
|
+
sage: Q.join_of_Vrep(v)
|
|
1609
|
+
Traceback (most recent call last):
|
|
1610
|
+
...
|
|
1611
|
+
ValueError: not a Vrepresentative of ``self``
|
|
1612
|
+
sage: f = P.faces(0)[0]
|
|
1613
|
+
sage: P.join_of_Vrep(v)
|
|
1614
|
+
A 0-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 1 vertex
|
|
1615
|
+
sage: Q.join_of_Vrep(v)
|
|
1616
|
+
Traceback (most recent call last):
|
|
1617
|
+
...
|
|
1618
|
+
ValueError: not a Vrepresentative of ``self``
|
|
1619
|
+
|
|
1620
|
+
TESTS:
|
|
1621
|
+
|
|
1622
|
+
``least_common_superface_of_Vrep`` is an alias::
|
|
1623
|
+
|
|
1624
|
+
sage: P.least_common_superface_of_Vrep(v)
|
|
1625
|
+
A 0-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 1 vertex
|
|
1626
|
+
sage: P.least_common_superface_of_Vrep == P.join_of_Vrep
|
|
1627
|
+
True
|
|
1628
|
+
|
|
1629
|
+
Error message for invalid input::
|
|
1630
|
+
|
|
1631
|
+
sage: P.join_of_Vrep('foo')
|
|
1632
|
+
Traceback (most recent call last):
|
|
1633
|
+
...
|
|
1634
|
+
ValueError: foo is not a Vrepresentative
|
|
1635
|
+
"""
|
|
1636
|
+
from sage.geometry.polyhedron.representation import Vrepresentation
|
|
1637
|
+
from sage.geometry.polyhedron.face import PolyhedronFace
|
|
1638
|
+
|
|
1639
|
+
new_indices = [0]*len(Vrepresentatives)
|
|
1640
|
+
for i, v in enumerate(Vrepresentatives):
|
|
1641
|
+
if isinstance(v, PolyhedronFace) and v.dim() == 0:
|
|
1642
|
+
if v.polyhedron() is not self:
|
|
1643
|
+
raise ValueError("not a Vrepresentative of ``self``")
|
|
1644
|
+
new_indices[i] = v.ambient_V_indices()[0]
|
|
1645
|
+
elif v in ZZ:
|
|
1646
|
+
new_indices[i] = v
|
|
1647
|
+
elif isinstance(v, Vrepresentation):
|
|
1648
|
+
if v.polyhedron() is not self:
|
|
1649
|
+
raise ValueError("not a Vrepresentative of ``self``")
|
|
1650
|
+
new_indices[i] = v.index()
|
|
1651
|
+
else:
|
|
1652
|
+
raise ValueError("{} is not a Vrepresentative".format(v))
|
|
1653
|
+
|
|
1654
|
+
return self.face_generator().join_of_Vrep(*new_indices)
|
|
1655
|
+
|
|
1656
|
+
least_common_superface_of_Vrep = join_of_Vrep
|
|
1657
|
+
|
|
1658
|
+
def meet_of_Hrep(self, *Hrepresentatives):
|
|
1659
|
+
r"""
|
|
1660
|
+
Return the largest face that is contained in ``Hrepresentatives``.
|
|
1661
|
+
|
|
1662
|
+
INPUT:
|
|
1663
|
+
|
|
1664
|
+
- ``Hrepresentatives`` -- facets or indices of Hrepresentatives;
|
|
1665
|
+
the indices are assumed to be the indices of the
|
|
1666
|
+
:meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.Hrepresentation`
|
|
1667
|
+
|
|
1668
|
+
OUTPUT: a :class:`~sage.geometry.polyhedron.face.PolyhedronFace`
|
|
1669
|
+
|
|
1670
|
+
EXAMPLES::
|
|
1671
|
+
|
|
1672
|
+
sage: P = polytopes.permutahedron(5)
|
|
1673
|
+
sage: P.meet_of_Hrep()
|
|
1674
|
+
A 4-dimensional face of a Polyhedron in ZZ^5 defined as the convex hull of 120 vertices
|
|
1675
|
+
sage: P.meet_of_Hrep(1)
|
|
1676
|
+
A 3-dimensional face of a Polyhedron in ZZ^5 defined as the convex hull of 24 vertices
|
|
1677
|
+
sage: P.meet_of_Hrep(4)
|
|
1678
|
+
A 3-dimensional face of a Polyhedron in ZZ^5 defined as the convex hull of 12 vertices
|
|
1679
|
+
sage: P.meet_of_Hrep(1,3,7)
|
|
1680
|
+
A 1-dimensional face of a Polyhedron in ZZ^5 defined as the convex hull of 2 vertices
|
|
1681
|
+
sage: P.meet_of_Hrep(1,3,7).ambient_H_indices()
|
|
1682
|
+
(0, 1, 3, 7)
|
|
1683
|
+
|
|
1684
|
+
The indices are the indices of the
|
|
1685
|
+
:meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.Hrepresentation`.
|
|
1686
|
+
``0`` corresponds to an equation and is ignored::
|
|
1687
|
+
|
|
1688
|
+
sage: P.meet_of_Hrep(0)
|
|
1689
|
+
A 4-dimensional face of a Polyhedron in ZZ^5 defined as the convex hull of 120 vertices
|
|
1690
|
+
|
|
1691
|
+
The input is flexible::
|
|
1692
|
+
|
|
1693
|
+
sage: P.meet_of_Hrep(P.facets()[-1], P.inequalities()[2], 7)
|
|
1694
|
+
A 1-dimensional face of a Polyhedron in ZZ^5 defined as the convex hull of 2 vertices
|
|
1695
|
+
|
|
1696
|
+
The ``Hrepresentatives`` must belong to ``self``::
|
|
1697
|
+
|
|
1698
|
+
sage: P = polytopes.cube(backend='ppl')
|
|
1699
|
+
sage: Q = polytopes.cube(backend='field')
|
|
1700
|
+
sage: f = P.facets()[0]
|
|
1701
|
+
sage: P.meet_of_Hrep(f)
|
|
1702
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 4 vertices
|
|
1703
|
+
sage: Q.meet_of_Hrep(f)
|
|
1704
|
+
Traceback (most recent call last):
|
|
1705
|
+
...
|
|
1706
|
+
ValueError: not a facet of ``self``
|
|
1707
|
+
sage: f = P.inequalities()[0]
|
|
1708
|
+
sage: P.meet_of_Hrep(f)
|
|
1709
|
+
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 4 vertices
|
|
1710
|
+
sage: Q.meet_of_Hrep(f)
|
|
1711
|
+
Traceback (most recent call last):
|
|
1712
|
+
...
|
|
1713
|
+
ValueError: not a facet of ``self``
|
|
1714
|
+
|
|
1715
|
+
TESTS:
|
|
1716
|
+
|
|
1717
|
+
Equations are not considered by the combinatorial polyhedron.
|
|
1718
|
+
We check that the index corresponds to the
|
|
1719
|
+
:meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.Hrepresentation` index::
|
|
1720
|
+
|
|
1721
|
+
sage: P = polytopes.permutahedron(3, backend='field')
|
|
1722
|
+
sage: P.Hrepresentation()
|
|
1723
|
+
(An inequality (0, 0, 1) x - 1 >= 0,
|
|
1724
|
+
An inequality (0, 1, 0) x - 1 >= 0,
|
|
1725
|
+
An inequality (0, 1, 1) x - 3 >= 0,
|
|
1726
|
+
An inequality (1, 0, 0) x - 1 >= 0,
|
|
1727
|
+
An inequality (1, 0, 1) x - 3 >= 0,
|
|
1728
|
+
An inequality (1, 1, 0) x - 3 >= 0,
|
|
1729
|
+
An equation (1, 1, 1) x - 6 == 0)
|
|
1730
|
+
sage: P.meet_of_Hrep(0).ambient_Hrepresentation()
|
|
1731
|
+
(An inequality (0, 0, 1) x - 1 >= 0, An equation (1, 1, 1) x - 6 == 0)
|
|
1732
|
+
|
|
1733
|
+
sage: P = polytopes.permutahedron(3, backend='ppl')
|
|
1734
|
+
sage: P.Hrepresentation()
|
|
1735
|
+
(An equation (1, 1, 1) x - 6 == 0,
|
|
1736
|
+
An inequality (1, 1, 0) x - 3 >= 0,
|
|
1737
|
+
An inequality (-1, -1, 0) x + 5 >= 0,
|
|
1738
|
+
An inequality (0, 1, 0) x - 1 >= 0,
|
|
1739
|
+
An inequality (-1, 0, 0) x + 3 >= 0,
|
|
1740
|
+
An inequality (1, 0, 0) x - 1 >= 0,
|
|
1741
|
+
An inequality (0, -1, 0) x + 3 >= 0)
|
|
1742
|
+
sage: P.meet_of_Hrep(1).ambient_Hrepresentation()
|
|
1743
|
+
(An equation (1, 1, 1) x - 6 == 0, An inequality (1, 1, 0) x - 3 >= 0)
|
|
1744
|
+
|
|
1745
|
+
``greatest_common_subface_of_Hrep`` is an alias::
|
|
1746
|
+
|
|
1747
|
+
sage: P.greatest_common_subface_of_Hrep(1).ambient_Hrepresentation()
|
|
1748
|
+
(An equation (1, 1, 1) x - 6 == 0, An inequality (1, 1, 0) x - 3 >= 0)
|
|
1749
|
+
sage: P.greatest_common_subface_of_Hrep == P.meet_of_Hrep
|
|
1750
|
+
True
|
|
1751
|
+
|
|
1752
|
+
Error message for invalid input::
|
|
1753
|
+
|
|
1754
|
+
sage: P.meet_of_Hrep('foo')
|
|
1755
|
+
Traceback (most recent call last):
|
|
1756
|
+
...
|
|
1757
|
+
ValueError: foo is not a Hrepresentative
|
|
1758
|
+
"""
|
|
1759
|
+
from sage.geometry.polyhedron.representation import Inequality, Equation
|
|
1760
|
+
from sage.geometry.polyhedron.face import PolyhedronFace
|
|
1761
|
+
|
|
1762
|
+
# Equations are ignored by combinatorial polyhedron for indexing.
|
|
1763
|
+
offset = 0
|
|
1764
|
+
if self.n_equations() and self.Hrepresentation(0).is_equation():
|
|
1765
|
+
offset = self.n_equations()
|
|
1766
|
+
|
|
1767
|
+
new_indices = []
|
|
1768
|
+
for i, facet in enumerate(Hrepresentatives):
|
|
1769
|
+
if isinstance(facet, PolyhedronFace) and facet.dim() + 1 == self.dim():
|
|
1770
|
+
if facet.polyhedron() is not self:
|
|
1771
|
+
raise ValueError("not a facet of ``self``")
|
|
1772
|
+
H_indices = facet.ambient_H_indices()
|
|
1773
|
+
facet = H_indices[0] if H_indices[0] >= offset else H_indices[-1]
|
|
1774
|
+
|
|
1775
|
+
if facet in ZZ and facet >= offset:
|
|
1776
|
+
# Note that ``CombinatorialPolyhedron`` ignores indices of equations
|
|
1777
|
+
# and has equations last.
|
|
1778
|
+
new_indices.append(facet - offset)
|
|
1779
|
+
elif isinstance(facet, Inequality):
|
|
1780
|
+
if facet.polyhedron() is not self:
|
|
1781
|
+
raise ValueError("not a facet of ``self``")
|
|
1782
|
+
new_indices.append(facet.index() - offset)
|
|
1783
|
+
elif isinstance(facet, Equation):
|
|
1784
|
+
# Ignore equations.
|
|
1785
|
+
continue
|
|
1786
|
+
elif facet in ZZ and 0 <= facet < offset:
|
|
1787
|
+
# Ignore equations.
|
|
1788
|
+
continue
|
|
1789
|
+
else:
|
|
1790
|
+
raise ValueError("{} is not a Hrepresentative".format(facet))
|
|
1791
|
+
|
|
1792
|
+
return self.face_generator().meet_of_Hrep(*new_indices)
|
|
1793
|
+
|
|
1794
|
+
greatest_common_subface_of_Hrep = meet_of_Hrep
|
|
1795
|
+
|
|
1796
|
+
def _test_combinatorial_face_as_combinatorial_polyhedron(self, tester=None, **options):
|
|
1797
|
+
"""
|
|
1798
|
+
Run tests on obtaining the combinatorial face as combinatorial polyhedron.
|
|
1799
|
+
|
|
1800
|
+
TESTS::
|
|
1801
|
+
|
|
1802
|
+
sage: polytopes.cross_polytope(3)._test_combinatorial_face_as_combinatorial_polyhedron()
|
|
1803
|
+
"""
|
|
1804
|
+
if not self.is_compact():
|
|
1805
|
+
return
|
|
1806
|
+
if self.dim() > 7 or self.n_vertices() > 100 or self.n_facets() > 100:
|
|
1807
|
+
# Avoid very long tests.
|
|
1808
|
+
return
|
|
1809
|
+
if self.dim() < 1:
|
|
1810
|
+
# Avoid trivial cases.
|
|
1811
|
+
return
|
|
1812
|
+
|
|
1813
|
+
from sage.misc.prandom import random
|
|
1814
|
+
|
|
1815
|
+
if tester is None:
|
|
1816
|
+
tester = self._tester(**options)
|
|
1817
|
+
|
|
1818
|
+
it = self.face_generator()
|
|
1819
|
+
_ = next(it), next(it) # get rid of non_proper faces
|
|
1820
|
+
C1 = self.combinatorial_polyhedron()
|
|
1821
|
+
it1 = C1.face_iter()
|
|
1822
|
+
C2 = C1.dual()
|
|
1823
|
+
algorithm = 'primal' if it1.dual else 'dual'
|
|
1824
|
+
it2 = C2.face_iter(algorithm=algorithm)
|
|
1825
|
+
|
|
1826
|
+
for f in it:
|
|
1827
|
+
f1 = next(it1)
|
|
1828
|
+
f2 = next(it2)
|
|
1829
|
+
if random() < 0.95:
|
|
1830
|
+
# Only test a random 5 percent of the faces.
|
|
1831
|
+
continue
|
|
1832
|
+
|
|
1833
|
+
P = f.as_polyhedron()
|
|
1834
|
+
D1 = f1.as_combinatorial_polyhedron()
|
|
1835
|
+
D2 = f2.as_combinatorial_polyhedron(quotient=True).dual()
|
|
1836
|
+
D1._test_bitsets(tester, **options)
|
|
1837
|
+
D2._test_bitsets(tester, **options)
|
|
1838
|
+
try:
|
|
1839
|
+
import sage.graphs.graph
|
|
1840
|
+
assert sage.graphs.graph # to muffle pyflakes
|
|
1841
|
+
except ImportError:
|
|
1842
|
+
pass
|
|
1843
|
+
else:
|
|
1844
|
+
tester.assertTrue(P.combinatorial_polyhedron().vertex_facet_graph().is_isomorphic(D1.vertex_facet_graph()))
|
|
1845
|
+
tester.assertTrue(P.combinatorial_polyhedron().vertex_facet_graph().is_isomorphic(D2.vertex_facet_graph()))
|