passagemath-polyhedra 10.6.31rc3__cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_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.

Files changed (206) hide show
  1. passagemath_polyhedra-10.6.31rc3.dist-info/METADATA +367 -0
  2. passagemath_polyhedra-10.6.31rc3.dist-info/METADATA.bak +369 -0
  3. passagemath_polyhedra-10.6.31rc3.dist-info/RECORD +206 -0
  4. passagemath_polyhedra-10.6.31rc3.dist-info/WHEEL +6 -0
  5. passagemath_polyhedra-10.6.31rc3.dist-info/top_level.txt +2 -0
  6. passagemath_polyhedra.libs/libgmp-6e109695.so.10.5.0 +0 -0
  7. passagemath_polyhedra.libs/libgomp-e985bcbb.so.1.0.0 +0 -0
  8. sage/all__sagemath_polyhedra.py +50 -0
  9. sage/game_theory/all.py +8 -0
  10. sage/game_theory/catalog.py +6 -0
  11. sage/game_theory/catalog_normal_form_games.py +923 -0
  12. sage/game_theory/cooperative_game.py +844 -0
  13. sage/game_theory/matching_game.py +1181 -0
  14. sage/game_theory/normal_form_game.py +2697 -0
  15. sage/game_theory/parser.py +275 -0
  16. sage/geometry/all__sagemath_polyhedra.py +22 -0
  17. sage/geometry/cone.py +6940 -0
  18. sage/geometry/cone_catalog.py +847 -0
  19. sage/geometry/cone_critical_angles.py +1027 -0
  20. sage/geometry/convex_set.py +1119 -0
  21. sage/geometry/fan.py +3743 -0
  22. sage/geometry/fan_isomorphism.py +389 -0
  23. sage/geometry/fan_morphism.py +1884 -0
  24. sage/geometry/hasse_diagram.py +202 -0
  25. sage/geometry/hyperplane_arrangement/affine_subspace.py +390 -0
  26. sage/geometry/hyperplane_arrangement/all.py +1 -0
  27. sage/geometry/hyperplane_arrangement/arrangement.py +3895 -0
  28. sage/geometry/hyperplane_arrangement/check_freeness.py +145 -0
  29. sage/geometry/hyperplane_arrangement/hyperplane.py +773 -0
  30. sage/geometry/hyperplane_arrangement/library.py +825 -0
  31. sage/geometry/hyperplane_arrangement/ordered_arrangement.py +642 -0
  32. sage/geometry/hyperplane_arrangement/plot.py +520 -0
  33. sage/geometry/integral_points.py +35 -0
  34. sage/geometry/integral_points_generic_dense.cpython-314-x86_64-linux-gnu.so +0 -0
  35. sage/geometry/integral_points_generic_dense.pyx +7 -0
  36. sage/geometry/lattice_polytope.py +5894 -0
  37. sage/geometry/linear_expression.py +773 -0
  38. sage/geometry/newton_polygon.py +767 -0
  39. sage/geometry/point_collection.cpython-314-x86_64-linux-gnu.so +0 -0
  40. sage/geometry/point_collection.pyx +1008 -0
  41. sage/geometry/polyhedral_complex.py +2616 -0
  42. sage/geometry/polyhedron/all.py +8 -0
  43. sage/geometry/polyhedron/backend_cdd.py +460 -0
  44. sage/geometry/polyhedron/backend_cdd_rdf.py +231 -0
  45. sage/geometry/polyhedron/backend_field.py +347 -0
  46. sage/geometry/polyhedron/backend_normaliz.py +2503 -0
  47. sage/geometry/polyhedron/backend_number_field.py +168 -0
  48. sage/geometry/polyhedron/backend_polymake.py +765 -0
  49. sage/geometry/polyhedron/backend_ppl.py +582 -0
  50. sage/geometry/polyhedron/base.py +1206 -0
  51. sage/geometry/polyhedron/base0.py +1444 -0
  52. sage/geometry/polyhedron/base1.py +886 -0
  53. sage/geometry/polyhedron/base2.py +812 -0
  54. sage/geometry/polyhedron/base3.py +1845 -0
  55. sage/geometry/polyhedron/base4.py +1262 -0
  56. sage/geometry/polyhedron/base5.py +2700 -0
  57. sage/geometry/polyhedron/base6.py +1741 -0
  58. sage/geometry/polyhedron/base7.py +997 -0
  59. sage/geometry/polyhedron/base_QQ.py +1258 -0
  60. sage/geometry/polyhedron/base_RDF.py +98 -0
  61. sage/geometry/polyhedron/base_ZZ.py +934 -0
  62. sage/geometry/polyhedron/base_mutable.py +215 -0
  63. sage/geometry/polyhedron/base_number_field.py +122 -0
  64. sage/geometry/polyhedron/cdd_file_format.py +155 -0
  65. sage/geometry/polyhedron/combinatorial_polyhedron/all.py +1 -0
  66. sage/geometry/polyhedron/combinatorial_polyhedron/base.cpython-314-x86_64-linux-gnu.so +0 -0
  67. sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd +76 -0
  68. sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +3859 -0
  69. sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.cpython-314-x86_64-linux-gnu.so +0 -0
  70. sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pxd +39 -0
  71. sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx +1038 -0
  72. sage/geometry/polyhedron/combinatorial_polyhedron/conversions.cpython-314-x86_64-linux-gnu.so +0 -0
  73. sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pxd +9 -0
  74. sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx +501 -0
  75. sage/geometry/polyhedron/combinatorial_polyhedron/face_data_structure.pxd +207 -0
  76. sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.cpython-314-x86_64-linux-gnu.so +0 -0
  77. sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd +102 -0
  78. sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +2274 -0
  79. sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.cpython-314-x86_64-linux-gnu.so +0 -0
  80. sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pxd +370 -0
  81. sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pyx +84 -0
  82. sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.cpython-314-x86_64-linux-gnu.so +0 -0
  83. sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pxd +31 -0
  84. sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx +587 -0
  85. sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.cpython-314-x86_64-linux-gnu.so +0 -0
  86. sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pxd +52 -0
  87. sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx +560 -0
  88. sage/geometry/polyhedron/constructor.py +773 -0
  89. sage/geometry/polyhedron/double_description.py +753 -0
  90. sage/geometry/polyhedron/double_description_inhomogeneous.py +564 -0
  91. sage/geometry/polyhedron/face.py +1060 -0
  92. sage/geometry/polyhedron/generating_function.py +1810 -0
  93. sage/geometry/polyhedron/lattice_euclidean_group_element.py +178 -0
  94. sage/geometry/polyhedron/library.py +3502 -0
  95. sage/geometry/polyhedron/misc.py +121 -0
  96. sage/geometry/polyhedron/modules/all.py +1 -0
  97. sage/geometry/polyhedron/modules/formal_polyhedra_module.py +155 -0
  98. sage/geometry/polyhedron/palp_database.py +447 -0
  99. sage/geometry/polyhedron/parent.py +1279 -0
  100. sage/geometry/polyhedron/plot.py +1986 -0
  101. sage/geometry/polyhedron/ppl_lattice_polygon.py +556 -0
  102. sage/geometry/polyhedron/ppl_lattice_polytope.py +1257 -0
  103. sage/geometry/polyhedron/representation.py +1723 -0
  104. sage/geometry/pseudolines.py +515 -0
  105. sage/geometry/relative_interior.py +445 -0
  106. sage/geometry/toric_plotter.py +1103 -0
  107. sage/geometry/triangulation/all.py +2 -0
  108. sage/geometry/triangulation/base.cpython-314-x86_64-linux-gnu.so +0 -0
  109. sage/geometry/triangulation/base.pyx +963 -0
  110. sage/geometry/triangulation/data.h +147 -0
  111. sage/geometry/triangulation/data.pxd +4 -0
  112. sage/geometry/triangulation/element.py +914 -0
  113. sage/geometry/triangulation/functions.h +10 -0
  114. sage/geometry/triangulation/functions.pxd +4 -0
  115. sage/geometry/triangulation/point_configuration.py +2256 -0
  116. sage/geometry/triangulation/triangulations.h +49 -0
  117. sage/geometry/triangulation/triangulations.pxd +7 -0
  118. sage/geometry/voronoi_diagram.py +319 -0
  119. sage/interfaces/all__sagemath_polyhedra.py +1 -0
  120. sage/interfaces/polymake.py +2028 -0
  121. sage/numerical/all.py +13 -0
  122. sage/numerical/all__sagemath_polyhedra.py +11 -0
  123. sage/numerical/backends/all.py +1 -0
  124. sage/numerical/backends/all__sagemath_polyhedra.py +1 -0
  125. sage/numerical/backends/cvxopt_backend.cpython-314-x86_64-linux-gnu.so +0 -0
  126. sage/numerical/backends/cvxopt_backend.pyx +1006 -0
  127. sage/numerical/backends/cvxopt_backend_test.py +19 -0
  128. sage/numerical/backends/cvxopt_sdp_backend.cpython-314-x86_64-linux-gnu.so +0 -0
  129. sage/numerical/backends/cvxopt_sdp_backend.pyx +382 -0
  130. sage/numerical/backends/cvxpy_backend.cpython-314-x86_64-linux-gnu.so +0 -0
  131. sage/numerical/backends/cvxpy_backend.pxd +41 -0
  132. sage/numerical/backends/cvxpy_backend.pyx +934 -0
  133. sage/numerical/backends/cvxpy_backend_test.py +13 -0
  134. sage/numerical/backends/generic_backend_test.py +24 -0
  135. sage/numerical/backends/interactivelp_backend.cpython-314-x86_64-linux-gnu.so +0 -0
  136. sage/numerical/backends/interactivelp_backend.pxd +36 -0
  137. sage/numerical/backends/interactivelp_backend.pyx +1231 -0
  138. sage/numerical/backends/interactivelp_backend_test.py +12 -0
  139. sage/numerical/backends/logging_backend.py +391 -0
  140. sage/numerical/backends/matrix_sdp_backend.cpython-314-x86_64-linux-gnu.so +0 -0
  141. sage/numerical/backends/matrix_sdp_backend.pxd +15 -0
  142. sage/numerical/backends/matrix_sdp_backend.pyx +478 -0
  143. sage/numerical/backends/ppl_backend.cpython-314-x86_64-linux-gnu.so +0 -0
  144. sage/numerical/backends/ppl_backend.pyx +1126 -0
  145. sage/numerical/backends/ppl_backend_test.py +13 -0
  146. sage/numerical/backends/scip_backend.cpython-314-x86_64-linux-gnu.so +0 -0
  147. sage/numerical/backends/scip_backend.pxd +22 -0
  148. sage/numerical/backends/scip_backend.pyx +1289 -0
  149. sage/numerical/backends/scip_backend_test.py +13 -0
  150. sage/numerical/interactive_simplex_method.py +5338 -0
  151. sage/numerical/knapsack.py +665 -0
  152. sage/numerical/linear_functions.cpython-314-x86_64-linux-gnu.so +0 -0
  153. sage/numerical/linear_functions.pxd +31 -0
  154. sage/numerical/linear_functions.pyx +1648 -0
  155. sage/numerical/linear_tensor.py +470 -0
  156. sage/numerical/linear_tensor_constraints.py +448 -0
  157. sage/numerical/linear_tensor_element.cpython-314-x86_64-linux-gnu.so +0 -0
  158. sage/numerical/linear_tensor_element.pxd +6 -0
  159. sage/numerical/linear_tensor_element.pyx +459 -0
  160. sage/numerical/mip.cpython-314-x86_64-linux-gnu.so +0 -0
  161. sage/numerical/mip.pxd +40 -0
  162. sage/numerical/mip.pyx +3667 -0
  163. sage/numerical/sdp.cpython-314-x86_64-linux-gnu.so +0 -0
  164. sage/numerical/sdp.pxd +39 -0
  165. sage/numerical/sdp.pyx +1433 -0
  166. sage/rings/all__sagemath_polyhedra.py +3 -0
  167. sage/rings/polynomial/all__sagemath_polyhedra.py +10 -0
  168. sage/rings/polynomial/omega.py +982 -0
  169. sage/schemes/all__sagemath_polyhedra.py +2 -0
  170. sage/schemes/toric/all.py +10 -0
  171. sage/schemes/toric/chow_group.py +1248 -0
  172. sage/schemes/toric/divisor.py +2082 -0
  173. sage/schemes/toric/divisor_class.cpython-314-x86_64-linux-gnu.so +0 -0
  174. sage/schemes/toric/divisor_class.pyx +322 -0
  175. sage/schemes/toric/fano_variety.py +1606 -0
  176. sage/schemes/toric/homset.py +650 -0
  177. sage/schemes/toric/ideal.py +451 -0
  178. sage/schemes/toric/library.py +1322 -0
  179. sage/schemes/toric/morphism.py +1958 -0
  180. sage/schemes/toric/points.py +1032 -0
  181. sage/schemes/toric/sheaf/all.py +1 -0
  182. sage/schemes/toric/sheaf/constructor.py +302 -0
  183. sage/schemes/toric/sheaf/klyachko.py +921 -0
  184. sage/schemes/toric/toric_subscheme.py +905 -0
  185. sage/schemes/toric/variety.py +3460 -0
  186. sage/schemes/toric/weierstrass.py +1078 -0
  187. sage/schemes/toric/weierstrass_covering.py +457 -0
  188. sage/schemes/toric/weierstrass_higher.py +288 -0
  189. sage_wheels/share/reflexive_polytopes/Full2d/zzdb.info +10 -0
  190. sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v03 +0 -0
  191. sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v04 +0 -0
  192. sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v05 +1 -0
  193. sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v06 +1 -0
  194. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.info +22 -0
  195. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v04 +0 -0
  196. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v05 +0 -0
  197. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v06 +0 -0
  198. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v07 +0 -0
  199. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v08 +0 -0
  200. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v09 +0 -0
  201. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v10 +0 -0
  202. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v11 +1 -0
  203. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v12 +1 -0
  204. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v13 +1 -0
  205. sage_wheels/share/reflexive_polytopes/reflexive_polytopes_2d +80 -0
  206. sage_wheels/share/reflexive_polytopes/reflexive_polytopes_3d +37977 -0
@@ -0,0 +1,1206 @@
1
+ # sage_setup: distribution = sagemath-polyhedra
2
+ r"""
3
+ Base class for polyhedra: Miscellaneous methods
4
+ """
5
+
6
+ # ****************************************************************************
7
+ # Copyright (C) 2008-2012 Marshall Hampton <hamptonio@gmail.com>
8
+ # Copyright (C) 2011-2015 Volker Braun <vbraun.name@gmail.com>
9
+ # Copyright (C) 2012-2018 Frederic Chapoton
10
+ # Copyright (C) 2013 Andrey Novoseltsev
11
+ # Copyright (C) 2014-2017 Moritz Firsching
12
+ # Copyright (C) 2014-2019 Thierry Monteil
13
+ # Copyright (C) 2015 Nathann Cohen
14
+ # Copyright (C) 2015-2017 Jeroen Demeyer
15
+ # Copyright (C) 2015-2017 Vincent Delecroix
16
+ # Copyright (C) 2015-2018 Dima Pasechnik
17
+ # Copyright (C) 2015-2020 Jean-Philippe Labbe <labbe at math.huji.ac.il>
18
+ # Copyright (C) 2015-2021 Matthias Koeppe
19
+ # Copyright (C) 2016-2019 Daniel Krenn
20
+ # Copyright (C) 2017 Marcelo Forets
21
+ # Copyright (C) 2017-2018 Mark Bell
22
+ # Copyright (C) 2019 Julian Ritter
23
+ # Copyright (C) 2019-2020 Laith Rastanawi
24
+ # Copyright (C) 2019-2020 Sophia Elia
25
+ # Copyright (C) 2019-2021 Jonathan Kliem <jonathan.kliem@gmail.com>
26
+ #
27
+ # This program is free software: you can redistribute it and/or modify
28
+ # it under the terms of the GNU General Public License as published by
29
+ # the Free Software Foundation, either version 2 of the License, or
30
+ # (at your option) any later version.
31
+ # https://www.gnu.org/licenses/
32
+ # ****************************************************************************
33
+
34
+ from sage.misc.cachefunc import cached_method
35
+
36
+ from sage.rings.integer_ring import ZZ
37
+ from sage.rings.rational_field import QQ
38
+ from sage.matrix.constructor import matrix
39
+ from sage.modules.free_module_element import vector
40
+
41
+ from .base7 import Polyhedron_base7
42
+
43
+ #########################################################################
44
+ # Notes if you want to implement your own backend:
45
+ #
46
+ # * derive from Polyhedron_base
47
+ #
48
+ # * you must implement _init_from_Vrepresentation and
49
+ # _init_from_Hrepresentation
50
+ #
51
+ # * You might want to override _init_empty_polyhedron
52
+ #
53
+ # * You may implement _init_from_Vrepresentation_and_Hrepresentation
54
+ #
55
+ # * You can of course also override any other method for which you
56
+ # have a faster implementation.
57
+ #########################################################################
58
+
59
+
60
+ #########################################################################
61
+ def is_Polyhedron(X):
62
+ """
63
+ Test whether ``X`` is a Polyhedron.
64
+
65
+ INPUT:
66
+
67
+ - ``X`` -- anything
68
+
69
+ OUTPUT: boolean
70
+
71
+ EXAMPLES::
72
+
73
+ sage: p = polytopes.hypercube(2)
74
+ sage: from sage.geometry.polyhedron.base import is_Polyhedron
75
+ sage: is_Polyhedron(p)
76
+ doctest:warning...
77
+ DeprecationWarning: is_Polyhedron is deprecated, use isinstance instead
78
+ See https://github.com/sagemath/sage/issues/34307 for details.
79
+ True
80
+ sage: is_Polyhedron(123456)
81
+ False
82
+ """
83
+ from sage.misc.superseded import deprecation
84
+ deprecation(34307, "is_Polyhedron is deprecated, use isinstance instead")
85
+ return isinstance(X, Polyhedron_base)
86
+
87
+
88
+ #########################################################################
89
+ class Polyhedron_base(Polyhedron_base7):
90
+ """
91
+ Base class for Polyhedron objects.
92
+
93
+ INPUT:
94
+
95
+ - ``parent`` -- the parent, an instance of
96
+ :class:`~sage.geometry.polyhedron.parent.Polyhedra`
97
+
98
+ - ``Vrep`` -- list ``[vertices, rays, lines]`` or ``None``. The
99
+ V-representation of the polyhedron; if ``None``, the polyhedron
100
+ is determined by the H-representation
101
+
102
+ - ``Hrep`` -- list ``[ieqs, eqns]`` or ``None``. The
103
+ H-representation of the polyhedron; if ``None``, the polyhedron
104
+ is determined by the V-representation
105
+
106
+ - ``Vrep_minimal`` -- (optional) see below
107
+
108
+ - ``Hrep_minimal`` -- (optional) see below
109
+
110
+ - ``pref_rep`` -- string (default: ``None``);
111
+ one of ``Vrep`` or ``Hrep`` to pick this in case the backend
112
+ cannot initialize from complete double description
113
+
114
+ - ``mutable`` -- ignored
115
+
116
+ If both ``Vrep`` and ``Hrep`` are provided, then
117
+ ``Vrep_minimal`` and ``Hrep_minimal`` must be set to ``True``.
118
+
119
+ TESTS::
120
+
121
+ sage: p = Polyhedron()
122
+ sage: TestSuite(p).run()
123
+
124
+ ::
125
+
126
+ sage: p = Polyhedron(vertices=[(1,0), (0,1)], rays=[(1,1)], base_ring=ZZ)
127
+ sage: TestSuite(p).run()
128
+
129
+ ::
130
+
131
+ sage: p = polytopes.flow_polytope(digraphs.DeBruijn(3,2)) # needs sage.combinat sage.graphs
132
+ sage: TestSuite(p).run()
133
+
134
+ ::
135
+
136
+ sage: TestSuite(Polyhedron([[]])).run()
137
+ sage: TestSuite(Polyhedron([[0]])).run()
138
+ sage: TestSuite(Polyhedron([[1]])).run()
139
+
140
+ ::
141
+
142
+ sage: P3 = polytopes.permutahedron(3)
143
+ sage: P = P3 * Polyhedron(rays=[[0,0,1], [0,1,1], [1,2,3]])
144
+ sage: TestSuite(P).run()
145
+
146
+ ::
147
+
148
+ sage: P = P3 * Polyhedron(rays=[[0,0,1], [0,1,1]], lines=[[1,0,0]])
149
+ sage: TestSuite(P).run()
150
+
151
+ ::
152
+
153
+ sage: M = random_matrix(ZZ, 5, 5, distribution='uniform')
154
+ sage: while True:
155
+ ....: M = random_matrix(ZZ, 5, 5, distribution='uniform')
156
+ ....: if M.rank() != 5:
157
+ ....: break
158
+ ....:
159
+ sage: P = Polyhedron(M)
160
+ sage: TestSuite(P).run()
161
+ """
162
+
163
+ def _test_basic_properties(self, tester=None, **options):
164
+ """
165
+ Run some basic tests to see, that some general assertion on polyhedra hold.
166
+
167
+ TESTS::
168
+
169
+ sage: polytopes.cross_polytope(3)._test_basic_properties()
170
+ """
171
+ from .constructor import Polyhedron
172
+
173
+ if tester is None:
174
+ tester = self._tester(**options)
175
+
176
+ tester.assertEqual(self.n_vertices() + self.n_rays() + self.n_lines(), self.n_Vrepresentation())
177
+ tester.assertEqual(self.n_inequalities() + self.n_equations(), self.n_Hrepresentation())
178
+ if self.n_vertices():
179
+ # Depending on the backend, this does not hold for the empty polyhedron.
180
+ tester.assertEqual(self.dim() + self.n_equations(), self.ambient_dim())
181
+
182
+ tester.assertTrue(all(len(v[::]) == self.ambient_dim() for v in self.Vrep_generator()))
183
+ tester.assertTrue(all(len(h[::]) == self.ambient_dim() + 1 for h in self.Hrep_generator()))
184
+
185
+ if self.n_vertices() + self.n_rays() < 40:
186
+ tester.assertEqual(self, Polyhedron(vertices=self.vertices(), rays=self.rays(), lines=self.lines(), ambient_dim=self.ambient_dim()))
187
+ if self.n_inequalities() < 40:
188
+ tester.assertEqual(self, Polyhedron(ieqs=self.inequalities(), eqns=self.equations(), ambient_dim=self.ambient_dim()))
189
+
190
+ def to_linear_program(self, solver=None, return_variable=False, base_ring=None):
191
+ r"""
192
+ Return a linear optimization problem over the polyhedron in the form of
193
+ a :class:`MixedIntegerLinearProgram`.
194
+
195
+ INPUT:
196
+
197
+ - ``solver`` -- select a solver (MIP backend). See the documentation
198
+ of for :class:`MixedIntegerLinearProgram`. Set to ``None`` by default.
199
+
200
+ - ``return_variable`` -- boolean (default: ``False``); if ``True``, return a tuple
201
+ ``(p, x)``, where ``p`` is the :class:`MixedIntegerLinearProgram` object
202
+ and ``x`` is the vector-valued MIP variable in this problem, indexed
203
+ from 0. If ``False``, only return ``p``.
204
+
205
+ - ``base_ring`` -- select a field over which the linear program should be
206
+ set up. Use ``RDF`` to request a fast inexact (floating point) solver
207
+ even if ``self`` is exact.
208
+
209
+ Note that the :class:`MixedIntegerLinearProgram` object will have the
210
+ null function as an objective to be maximized.
211
+
212
+ .. SEEALSO::
213
+
214
+ :meth:`~MixedIntegerLinearProgram.polyhedron` -- return the
215
+ polyhedron associated with a :class:`MixedIntegerLinearProgram`
216
+ object.
217
+
218
+ EXAMPLES:
219
+
220
+ Exact rational linear program::
221
+
222
+ sage: p = polytopes.cube()
223
+ sage: p.to_linear_program()
224
+ Linear Program (no objective, 3 variables, 6 constraints)
225
+ sage: lp, x = p.to_linear_program(return_variable=True)
226
+ sage: lp.set_objective(2*x[0] + 1*x[1] + 39*x[2])
227
+ sage: lp.solve()
228
+ 42
229
+ sage: lp.get_values(x[0], x[1], x[2])
230
+ [1, 1, 1]
231
+
232
+ Floating-point linear program::
233
+
234
+ sage: lp, x = p.to_linear_program(return_variable=True, base_ring=RDF)
235
+ sage: lp.set_objective(2*x[0] + 1*x[1] + 39*x[2])
236
+ sage: lp.solve()
237
+ 42.0
238
+
239
+ Irrational algebraic linear program over an embedded number field::
240
+
241
+ sage: # needs sage.groups sage.rings.number_field
242
+ sage: p = polytopes.icosahedron()
243
+ sage: lp, x = p.to_linear_program(return_variable=True)
244
+ sage: lp.set_objective(x[0] + x[1] + x[2])
245
+ sage: lp.solve()
246
+ 1/4*sqrt5 + 3/4
247
+
248
+ Same example with floating point::
249
+
250
+ sage: # needs sage.groups sage.rings.number_field
251
+ sage: lp, x = p.to_linear_program(return_variable=True, base_ring=RDF)
252
+ sage: lp.set_objective(x[0] + x[1] + x[2])
253
+ sage: lp.solve() # tol 1e-5
254
+ 1.3090169943749475
255
+
256
+ Same example with a specific floating point solver::
257
+
258
+ sage: # needs sage.groups sage.rings.number_field
259
+ sage: lp, x = p.to_linear_program(return_variable=True, solver='GLPK')
260
+ sage: lp.set_objective(x[0] + x[1] + x[2])
261
+ sage: lp.solve() # tol 1e-8
262
+ 1.3090169943749475
263
+
264
+ Irrational algebraic linear program over `AA`::
265
+
266
+ sage: # needs sage.groups sage.rings.number_field
267
+ sage: p = polytopes.icosahedron(base_ring=AA)
268
+ sage: lp, x = p.to_linear_program(return_variable=True)
269
+ sage: lp.set_objective(x[0] + x[1] + x[2])
270
+ sage: lp.solve() # long time
271
+ 1.309016994374948?
272
+
273
+ TESTS::
274
+
275
+ sage: p = polytopes.flow_polytope(digraphs.DeBruijn(3,2)); p # needs sage.combinat sage.graphs
276
+ A 19-dimensional polyhedron in QQ^27
277
+ defined as the convex hull of 1 vertex and 148 rays
278
+ sage: p.to_linear_program().polyhedron() == p
279
+ True
280
+
281
+ sage: p = polytopes.icosahedron() # needs sage.groups sage.rings.number_field
282
+ sage: p.to_linear_program(solver='PPL') # needs sage.groups sage.rings.number_field
283
+ Traceback (most recent call last):
284
+ ...
285
+ TypeError: The PPL backend only supports rational data.
286
+
287
+ Test that equations are handled correctly (:issue:`24154`)::
288
+
289
+ sage: p = Polyhedron(vertices=[[19]])
290
+ sage: lp, x = p.to_linear_program(return_variable=True)
291
+ sage: lp.set_objective(x[0])
292
+ sage: lp.solve()
293
+ 19
294
+ """
295
+ if base_ring is None:
296
+ base_ring = self.base_ring()
297
+ base_ring = base_ring.fraction_field()
298
+ from sage.numerical.mip import MixedIntegerLinearProgram
299
+ p = MixedIntegerLinearProgram(solver=solver, base_ring=base_ring)
300
+ x = p.new_variable(real=True, nonnegative=False)
301
+
302
+ for ineqn in self.inequalities_list():
303
+ b = -ineqn.pop(0)
304
+ p.add_constraint(p.sum([x[i] * ineqn[i] for i in range(len(ineqn))]) >= b)
305
+
306
+ for eqn in self.equations_list():
307
+ b = -eqn.pop(0)
308
+ p.add_constraint(p.sum([x[i] * eqn[i] for i in range(len(eqn))]) == b)
309
+
310
+ if return_variable:
311
+ return p, x
312
+ else:
313
+ return p
314
+
315
+ def boundary_complex(self):
316
+ """
317
+ Return the simplicial complex given by the boundary faces of ``self``,
318
+ if it is simplicial.
319
+
320
+ OUTPUT:
321
+
322
+ A (spherical) simplicial complex
323
+
324
+ EXAMPLES:
325
+
326
+ The boundary complex of the octahedron::
327
+
328
+ sage: # needs sage.graphs
329
+ sage: oc = polytopes.octahedron()
330
+ sage: sc_oc = oc.boundary_complex()
331
+ sage: fl_oc = oc.face_lattice() # needs sage.combinat
332
+ sage: fl_sc = sc_oc.face_poset() # needs sage.combinat
333
+ sage: [len(x) for x in fl_oc.level_sets()] # needs sage.combinat
334
+ [1, 6, 12, 8, 1]
335
+ sage: [len(x) for x in fl_sc.level_sets()] # needs sage.combinat
336
+ [6, 12, 8]
337
+ sage: sc_oc.euler_characteristic()
338
+ 2
339
+ sage: sc_oc.homology()
340
+ {0: 0, 1: 0, 2: Z}
341
+
342
+ The polyhedron should be simplicial::
343
+
344
+ sage: c = polytopes.cube()
345
+ sage: c.boundary_complex()
346
+ Traceback (most recent call last):
347
+ ...
348
+ NotImplementedError: this function is only implemented for simplicial polytopes
349
+
350
+ TESTS::
351
+
352
+ sage: p = Polyhedron(rays=[[1,1]])
353
+ sage: p.boundary_complex()
354
+ Traceback (most recent call last):
355
+ ...
356
+ ValueError: self should be compact
357
+ """
358
+ if not self.is_compact():
359
+ raise ValueError("self should be compact")
360
+
361
+ if self.is_simplicial():
362
+ from sage.topology.simplicial_complex import SimplicialComplex
363
+ inc_mat_cols = self.incidence_matrix().columns()
364
+ ineq_indices = [inc_mat_cols[i].nonzero_positions()
365
+ for i in range(self.n_Hrepresentation())
366
+ if self.Hrepresentation()[i].is_inequality()]
367
+ return SimplicialComplex(ineq_indices, maximality_check=False)
368
+ else:
369
+ raise NotImplementedError("this function is only implemented for simplicial polytopes")
370
+
371
+ @cached_method
372
+ def center(self):
373
+ """
374
+ Return the average of the vertices.
375
+
376
+ .. SEEALSO::
377
+
378
+ :meth:`sage.geometry.polyhedron.base1.Polyhedron_base1.representative_point`.
379
+
380
+ OUTPUT:
381
+
382
+ The center of the polyhedron. All rays and lines are
383
+ ignored. Raises a :exc:`ZeroDivisionError` for the empty
384
+ polytope.
385
+
386
+ EXAMPLES::
387
+
388
+ sage: p = polytopes.hypercube(3)
389
+ sage: p = p + vector([1,0,0])
390
+ sage: p.center()
391
+ (1, 0, 0)
392
+ """
393
+ if self.dim() == 0:
394
+ return self.vertices()[0].vector()
395
+ else:
396
+ vertex_sum = vector(self.base_ring(), [0] * self.ambient_dim())
397
+ for v in self.vertex_generator():
398
+ vertex_sum += v.vector()
399
+ vertex_sum.set_immutable()
400
+ return vertex_sum / self.n_vertices()
401
+
402
+ @cached_method
403
+ def radius_square(self):
404
+ """
405
+ Return the square of the maximal distance from the
406
+ :meth:`center` to a vertex. All rays and lines are ignored.
407
+
408
+ OUTPUT:
409
+
410
+ The square of the radius, which is in
411
+ :meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.base_ring`.
412
+
413
+ EXAMPLES::
414
+
415
+ sage: p = polytopes.permutahedron(4, project = False)
416
+ sage: p.radius_square()
417
+ 5
418
+ """
419
+ vertices = [v.vector() - self.center() for v in self.vertex_generator()]
420
+ return max(v.dot_product(v) for v in vertices)
421
+
422
+ def radius(self):
423
+ """
424
+ Return the maximal distance from the center to a vertex. All
425
+ rays and lines are ignored.
426
+
427
+ OUTPUT:
428
+
429
+ The radius for a rational polyhedron is, in general, not
430
+ rational. use :meth:`radius_square` if you need a rational
431
+ distance measure.
432
+
433
+ EXAMPLES::
434
+
435
+ sage: p = polytopes.hypercube(4)
436
+ sage: p.radius()
437
+ 2
438
+ """
439
+ return self.radius_square().sqrt()
440
+
441
+ def is_inscribed(self, certificate=False):
442
+ """
443
+ This function tests whether the vertices of the polyhedron are
444
+ inscribed on a sphere.
445
+
446
+ The polyhedron is expected to be compact and full-dimensional.
447
+ A full-dimensional compact polytope is inscribed if there exists
448
+ a point in space which is equidistant to all its vertices.
449
+
450
+ ALGORITHM:
451
+
452
+ The function first computes the circumsphere of a full-dimensional
453
+ simplex with vertices of ``self``. It is found by lifting the points on a
454
+ paraboloid to find the hyperplane on which the circumsphere is lifted.
455
+ Then, it checks if all other vertices are equidistant to the
456
+ circumcenter of that simplex.
457
+
458
+ INPUT:
459
+
460
+ - ``certificate`` -- boolean (default: ``False``); specifies whether to
461
+ return the circumcenter, if found
462
+
463
+ OUTPUT: if ``certificate`` is true, returns a tuple containing:
464
+
465
+ 1. Boolean.
466
+ 2. The circumcenter of the polytope or None.
467
+
468
+ If ``certificate`` is false:
469
+
470
+ - a Boolean.
471
+
472
+ EXAMPLES::
473
+
474
+ sage: q = Polyhedron(vertices=[[1,1,1,1],[-1,-1,1,1],[1,-1,-1,1],
475
+ ....: [-1,1,-1,1],[1,1,1,-1],[-1,-1,1,-1],
476
+ ....: [1,-1,-1,-1],[-1,1,-1,-1],[0,0,10/13,-24/13],
477
+ ....: [0,0,-10/13,-24/13]])
478
+ sage: q.is_inscribed(certificate=True)
479
+ (True, (0, 0, 0, 0))
480
+
481
+ sage: cube = polytopes.cube()
482
+ sage: cube.is_inscribed()
483
+ True
484
+
485
+ sage: translated_cube = Polyhedron(vertices=[v.vector() + vector([1,2,3])
486
+ ....: for v in cube.vertices()])
487
+ sage: translated_cube.is_inscribed(certificate=True)
488
+ (True, (1, 2, 3))
489
+
490
+ sage: truncated_cube = cube.face_truncation(cube.faces(0)[0])
491
+ sage: truncated_cube.is_inscribed()
492
+ False
493
+
494
+ The method is not implemented for non-full-dimensional polytope or
495
+ unbounded polyhedra::
496
+
497
+ sage: square = Polyhedron(vertices=[[1,0,0],[0,1,0],[1,1,0],[0,0,0]])
498
+ sage: square.is_inscribed()
499
+ Traceback (most recent call last):
500
+ ...
501
+ NotImplementedError: this function is implemented for full-dimensional polyhedra only
502
+
503
+ sage: p = Polyhedron(vertices=[(0,0)],rays=[(1,0),(0,1)])
504
+ sage: p.is_inscribed()
505
+ Traceback (most recent call last):
506
+ ...
507
+ NotImplementedError: this function is not implemented for unbounded polyhedra
508
+
509
+ TESTS:
510
+
511
+ We check that :issue:`28464` is fixed::
512
+
513
+ sage: P = Polyhedron(vertices=[(-130658298093891402635075/416049251842505144482473,
514
+ ....: 177469511761879509172000/1248147755527515433447419,
515
+ ....: 485550543257132133136169/2496295511055030866894838,
516
+ ....: 2010744967797898733758669/2496295511055030866894838),
517
+ ....: (-146945725603929909850/706333405676769433081,
518
+ ....: -84939725782618445000/706333405676769433081,
519
+ ....: 560600045283000988081/1412666811353538866162,
520
+ ....: 969778382942371268081/1412666811353538866162),
521
+ ....: (-46275018824497300/140422338198040641,
522
+ ....: -5747688262110000/46807446066013547, 1939357556329/7033601552658,
523
+ ....: 1939357556329/7033601552658), (-17300/59929, -10000/59929, 39929/119858,
524
+ ....: 39929/119858), (-4700/32209, -10000/32209, 12209/64418, 12209/64418),
525
+ ....: (QQ(0), QQ(0), QQ(0), QQ(1)), (QQ(0), QQ(0), 1/2, 1/2), (300/10027,
526
+ ....: -10000/30081, 10081/60162, 10081/60162), (112393975400/1900567733649,
527
+ ....: 117311600000/633522577883, 43678681/95197362, 43678681/95197362),
528
+ ....: (6109749955400/133380598418321, 37106807920000/133380598418321,
529
+ ....: 2677964249/6680888498, 2677964249/6680888498),
530
+ ....: (29197890764005600/402876806828660641,
531
+ ....: -2150510776960000/402876806828660641,
532
+ ....: 398575785274740641/805753613657321282,
533
+ ....: 398575785274740641/805753613657321282),
534
+ ....: (5576946899441759759983005325/110078073300232813237456943251,
535
+ ....: -29071211718677797926570478000/110078073300232813237456943251,
536
+ ....: 59439312069347378584317232001/220156146600465626474913886502,
537
+ ....: 181346577228466312205473034501/220156146600465626474913886502),
538
+ ....: (150040732779124914266530235300/6774574358246204311268446913881,
539
+ ....: -2813827375989039189507000218000/6774574358246204311268446913881,
540
+ ....: 1260217414021285074925933133881/13549148716492408622536893827762,
541
+ ....: 3232518047094242684574253773881/13549148716492408622536893827762),
542
+ ....: (3816349407976279597850158016285000/88842127448735433741180809504357161,
543
+ ....: 27965821247423216557301387453968000/88842127448735433741180809504357161,
544
+ ....: 68546256000224819256028677086357161/177684254897470867482361619008714322,
545
+ ....: 86062257922545755787315412690197161/177684254897470867482361619008714322)])
546
+ sage: P.is_inscribed()
547
+ True
548
+
549
+ sage: P = Polyhedron(vertices=[[0, -1, 0, 0],
550
+ ....: [0, 0, -1, 0],
551
+ ....: [0, 0, 0, -1],
552
+ ....: [0, 0, +1, 0],
553
+ ....: [0, 0, 0, +1],
554
+ ....: [+1, 0, 0, 0]])
555
+ sage: P.is_inscribed()
556
+ True
557
+
558
+ We check that :issue:`29125` is fixed::
559
+
560
+ sage: P = Polyhedron(vertices=[[-2,-1], [-2,1], [0,-1], [0,1]], backend='field')
561
+ sage: P.is_inscribed()
562
+ True
563
+ sage: V = P.Vrepresentation()
564
+ sage: H = P.Hrepresentation()
565
+ sage: parent = P.parent()
566
+ sage: for V1 in Permutations(V):
567
+ ....: P1 = parent._element_constructor_(
568
+ ....: [V1, [], []], [H, []], Vrep_minimal=True, Hrep_minimal=True)
569
+ ....: assert P1.is_inscribed()
570
+ """
571
+
572
+ if not self.is_compact():
573
+ raise NotImplementedError("this function is not implemented for unbounded polyhedra")
574
+
575
+ if not self.is_full_dimensional():
576
+ raise NotImplementedError("this function is implemented for full-dimensional polyhedra only")
577
+
578
+ dimension = self.dimension()
579
+ vertices = self.vertices()
580
+
581
+ # We obtain vertices that are an affine basis of the affine hull.
582
+ affine_basis = self.an_affine_basis()
583
+ raw_data = []
584
+ for vertex in affine_basis:
585
+ vertex_vector = vertex.vector()
586
+ raw_data += [[sum(i**2 for i in vertex_vector)] +
587
+ list(vertex_vector) + [1]]
588
+ matrix_data = matrix(raw_data)
589
+
590
+ # The determinant "a" should not be zero because
591
+ # the vertices in ``affine_basis`` are an affine basis.
592
+ a = matrix_data.matrix_from_columns(range(1, dimension+2)).determinant()
593
+
594
+ minors = [(-1)**(i)*matrix_data.matrix_from_columns([j for j in range(dimension+2) if j != i]).determinant()
595
+ for i in range(1, dimension+1)]
596
+ c = (-1)**(dimension+1)*matrix_data.matrix_from_columns(range(dimension+1)).determinant()
597
+
598
+ circumcenter = vector([minors[i]/(2*a) for i in range(dimension)])
599
+ squared_circumradius = (sum(m**2 for m in minors) - 4 * a * c) / (4*a**2)
600
+
601
+ # Checking if the circumcenter has the correct sign
602
+ if not all(sum(i**2 for i in v.vector() - circumcenter) == squared_circumradius
603
+ for v in vertices if v in affine_basis):
604
+ circumcenter = - circumcenter
605
+
606
+ is_inscribed = all(sum(i**2 for i in v.vector() - circumcenter) == squared_circumradius
607
+ for v in vertices if v not in affine_basis)
608
+
609
+ if certificate:
610
+ if is_inscribed:
611
+ return (True, circumcenter)
612
+ else:
613
+ return (False, None)
614
+ else:
615
+ return is_inscribed
616
+
617
+ def hyperplane_arrangement(self):
618
+ """
619
+ Return the hyperplane arrangement defined by the equations and
620
+ inequalities.
621
+
622
+ OUTPUT:
623
+
624
+ A :class:`hyperplane arrangement
625
+ <sage.geometry.hyperplane_arrangement.arrangement.HyperplaneArrangementElement>`
626
+ consisting of the hyperplanes defined by the
627
+ :meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.Hrepresentation`.
628
+ If the polytope is full-dimensional, this is the hyperplane
629
+ arrangement spanned by the facets of the polyhedron.
630
+
631
+ EXAMPLES::
632
+
633
+ sage: p = polytopes.hypercube(2)
634
+ sage: p.hyperplane_arrangement()
635
+ Arrangement <-t0 + 1 | -t1 + 1 | t1 + 1 | t0 + 1>
636
+ """
637
+ names = tuple('t' + str(i) for i in range(self.ambient_dim()))
638
+ from sage.geometry.hyperplane_arrangement.arrangement import HyperplaneArrangements
639
+ field = self.base_ring().fraction_field()
640
+ H = HyperplaneArrangements(field, names)
641
+ return H(self)
642
+
643
+ @cached_method
644
+ def normal_fan(self, direction='inner'):
645
+ r"""
646
+ Return the normal fan of a compact full-dimensional rational polyhedron.
647
+
648
+ This returns the inner normal fan of ``self``. For the outer normal fan,
649
+ use ``direction='outer'``.
650
+
651
+ INPUT:
652
+
653
+ - ``direction`` -- either ``'inner'`` (default) or ``'outer'``; if
654
+ set to ``'inner'``, use the inner normal vectors to span the cones of
655
+ the fan, if set to ``'outer'``, use the outer normal vectors.
656
+
657
+ OUTPUT:
658
+
659
+ A complete fan of the ambient space as a
660
+ :class:`~sage.geometry.fan.RationalPolyhedralFan`.
661
+
662
+ .. SEEALSO::
663
+
664
+ :meth:`face_fan`.
665
+
666
+ EXAMPLES::
667
+
668
+ sage: S = Polyhedron(vertices=[[0, 0], [1, 0], [0, 1]])
669
+ sage: S.normal_fan()
670
+ Rational polyhedral fan in 2-d lattice N
671
+
672
+ sage: C = polytopes.hypercube(4)
673
+ sage: NF = C.normal_fan(); NF
674
+ Rational polyhedral fan in 4-d lattice N
675
+
676
+ Currently, it is only possible to get the normal fan of a bounded rational polytope::
677
+
678
+ sage: P = Polyhedron(rays=[[1, 0], [0, 1]])
679
+ sage: P.normal_fan()
680
+ Traceback (most recent call last):
681
+ ...
682
+ NotImplementedError: the normal fan is only supported for polytopes (compact polyhedra).
683
+
684
+ sage: Q = Polyhedron(vertices=[[1, 0, 0], [0, 1, 0], [0, 0, 1]])
685
+ sage: Q.normal_fan()
686
+ Traceback (most recent call last):
687
+ ...
688
+ ValueError: the normal fan is only defined for full-dimensional polytopes
689
+
690
+ sage: R = Polyhedron(vertices=[[0, 0], # needs sage.rings.number_field sage.symbolic
691
+ ....: [AA(sqrt(2)), 0],
692
+ ....: [0, AA(sqrt(2))]])
693
+ sage: R.normal_fan() # needs sage.rings.number_field sage.symbolic
694
+ Traceback (most recent call last):
695
+ ...
696
+ NotImplementedError: normal fan handles only polytopes over the rationals
697
+
698
+ sage: P = Polyhedron(vertices=[[0,0], [2,0], [0,2], [2,1], [1,2]])
699
+ sage: P.normal_fan(direction=None)
700
+ Traceback (most recent call last):
701
+ ...
702
+ TypeError: the direction should be 'inner' or 'outer'
703
+
704
+ sage: inner_nf = P.normal_fan()
705
+ sage: inner_nf.rays()
706
+ N( 1, 0),
707
+ N( 0, -1),
708
+ N( 0, 1),
709
+ N(-1, 0),
710
+ N(-1, -1)
711
+ in 2-d lattice N
712
+
713
+ sage: outer_nf = P.normal_fan(direction='outer')
714
+ sage: outer_nf.rays()
715
+ N( 1, 0),
716
+ N( 1, 1),
717
+ N( 0, 1),
718
+ N(-1, 0),
719
+ N( 0, -1)
720
+ in 2-d lattice N
721
+
722
+ REFERENCES:
723
+
724
+ For more information, see Chapter 7 of [Zie2007]_.
725
+ """
726
+ from sage.geometry.fan import NormalFan
727
+
728
+ if not QQ.has_coerce_map_from(self.base_ring()):
729
+ raise NotImplementedError('normal fan handles only polytopes over the rationals')
730
+ if direction == 'inner':
731
+ return NormalFan(self)
732
+ elif direction == 'outer':
733
+ return NormalFan(-self)
734
+ else:
735
+ raise TypeError("the direction should be 'inner' or 'outer'")
736
+
737
+ @cached_method
738
+ def face_fan(self):
739
+ r"""
740
+ Return the face fan of a compact rational polyhedron.
741
+
742
+ OUTPUT:
743
+
744
+ A fan of the ambient space as a
745
+ :class:`~sage.geometry.fan.RationalPolyhedralFan`.
746
+
747
+ .. SEEALSO::
748
+
749
+ :meth:`normal_fan`.
750
+
751
+ EXAMPLES::
752
+
753
+ sage: T = polytopes.cuboctahedron()
754
+ sage: T.face_fan()
755
+ Rational polyhedral fan in 3-d lattice M
756
+
757
+ The polytope should contain the origin in the interior::
758
+
759
+ sage: P = Polyhedron(vertices=[[1/2, 1], [1, 1/2]])
760
+ sage: P.face_fan()
761
+ Traceback (most recent call last):
762
+ ...
763
+ ValueError: face fans are defined only for polytopes
764
+ containing the origin as an interior point!
765
+
766
+ sage: Q = Polyhedron(vertices=[[-1, 1/2], [1, -1/2]])
767
+ sage: Q.contains([0,0])
768
+ True
769
+ sage: FF = Q.face_fan(); FF
770
+ Rational polyhedral fan in 2-d lattice M
771
+
772
+ The polytope has to have rational coordinates::
773
+
774
+ sage: S = polytopes.dodecahedron() # needs sage.groups sage.rings.number_field
775
+ sage: S.face_fan() # needs sage.groups sage.rings.number_field
776
+ Traceback (most recent call last):
777
+ ...
778
+ NotImplementedError: face fan handles only polytopes over the rationals
779
+
780
+ REFERENCES:
781
+
782
+ For more information, see Chapter 7 of [Zie2007]_.
783
+ """
784
+ from sage.geometry.fan import FaceFan
785
+
786
+ if not QQ.has_coerce_map_from(self.base_ring()):
787
+ raise NotImplementedError('face fan handles only polytopes over the rationals')
788
+
789
+ return FaceFan(self)
790
+
791
+ def is_minkowski_summand(self, Y):
792
+ r"""
793
+ Test whether ``Y`` is a Minkowski summand.
794
+
795
+ See :meth:`~sage.geometry.polyhedron.base5.Polyhedron_base5.minkowski_sum`.
796
+
797
+ OUTPUT: boolean; whether there exists another polyhedron `Z` such that
798
+ ``self`` can be written as `Y\oplus Z`
799
+
800
+ EXAMPLES::
801
+
802
+ sage: A = polytopes.hypercube(2)
803
+ sage: B = Polyhedron(vertices=[(0,1), (1/2,1)])
804
+ sage: C = Polyhedron(vertices=[(1,1)])
805
+ sage: A.is_minkowski_summand(B)
806
+ True
807
+ sage: A.is_minkowski_summand(C)
808
+ True
809
+ sage: B.is_minkowski_summand(C)
810
+ True
811
+ sage: B.is_minkowski_summand(A)
812
+ False
813
+ sage: C.is_minkowski_summand(A)
814
+ False
815
+ sage: C.is_minkowski_summand(B)
816
+ False
817
+ """
818
+ return self.minkowski_difference(Y).minkowski_sum(Y) == self
819
+
820
+ def barycentric_subdivision(self, subdivision_frac=None):
821
+ r"""
822
+ Return the barycentric subdivision of a compact polyhedron.
823
+
824
+ DEFINITION:
825
+
826
+ The barycentric subdivision of a compact polyhedron is a standard way
827
+ to triangulate its faces in such a way that maximal faces correspond to
828
+ flags of faces of the starting polyhedron (i.e. a maximal chain in the
829
+ face lattice of the polyhedron). As a simplicial complex, this is known
830
+ as the order complex of the face lattice of the polyhedron.
831
+
832
+ REFERENCE:
833
+
834
+ See :wikipedia:`Barycentric_subdivision`
835
+
836
+ Section 6.6, Handbook of Convex Geometry, Volume A, edited by P.M. Gruber and J.M.
837
+ Wills. 1993, North-Holland Publishing Co..
838
+
839
+ INPUT:
840
+
841
+ - ``subdivision_frac`` -- number. Gives the proportion how far the new
842
+ vertices are pulled out of the polytope. Default is `\frac{1}{3}` and
843
+ the value should be smaller than `\frac{1}{2}`. The subdivision is
844
+ computed on the polar polyhedron.
845
+
846
+ OUTPUT: a Polyhedron object, subdivided as described above
847
+
848
+ EXAMPLES::
849
+
850
+ sage: P = polytopes.hypercube(3)
851
+ sage: P.barycentric_subdivision()
852
+ A 3-dimensional polyhedron in QQ^3 defined as the convex hull
853
+ of 26 vertices
854
+ sage: P = Polyhedron(vertices=[[0,0,0],[0,1,0],[1,0,0],[0,0,1]])
855
+ sage: P.barycentric_subdivision()
856
+ A 3-dimensional polyhedron in QQ^3 defined as the convex hull
857
+ of 14 vertices
858
+ sage: P = Polyhedron(vertices=[[0,1,0],[0,0,1],[1,0,0]])
859
+ sage: P.barycentric_subdivision()
860
+ A 2-dimensional polyhedron in QQ^3 defined as the convex hull
861
+ of 6 vertices
862
+ sage: P = polytopes.regular_polygon(4, base_ring=QQ) # needs sage.rings.number_field
863
+ sage: P.barycentric_subdivision() # needs sage.rings.number_field
864
+ A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 8
865
+ vertices
866
+
867
+ TESTS::
868
+
869
+ sage: P.barycentric_subdivision(1/2)
870
+ Traceback (most recent call last):
871
+ ...
872
+ ValueError: the subdivision fraction should be between 0 and 1/2
873
+ sage: P = Polyhedron(ieqs=[[1,0,1],[0,1,0],[1,0,0],[0,0,1]])
874
+ sage: P.barycentric_subdivision()
875
+ Traceback (most recent call last):
876
+ ...
877
+ ValueError: the polytope has to be compact
878
+ sage: P = Polyhedron(vertices=[[0,0,0],[0,1,0],[1,0,0],[0,0,1]], backend='field')
879
+ sage: P.barycentric_subdivision()
880
+ A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 14 vertices
881
+
882
+ sage: polytopes.simplex(backend='field').barycentric_subdivision().backend()
883
+ 'field'
884
+ sage: polytopes.cube(backend='cdd').barycentric_subdivision().backend() # needs cddexec_gmp
885
+ 'cdd'
886
+ """
887
+ if subdivision_frac is None:
888
+ subdivision_frac = ZZ.one() / 3
889
+
890
+ if not self.is_compact():
891
+ raise ValueError("the polytope has to be compact")
892
+ if not (0 < subdivision_frac < ZZ.one() / 2):
893
+ raise ValueError("the subdivision fraction should be "
894
+ "between 0 and 1/2")
895
+
896
+ barycenter = self.center()
897
+ parent = self.parent().base_extend(subdivision_frac)
898
+
899
+ start_polar = (self - barycenter).polar(in_affine_span=True)
900
+ polar = (self - barycenter).polar(in_affine_span=True)
901
+
902
+ for i in range(self.dimension() - 1):
903
+
904
+ new_ineq = []
905
+ subdivided_faces = list(start_polar.faces(i))
906
+ Hrep = polar.Hrepresentation()
907
+
908
+ for face in subdivided_faces:
909
+
910
+ face_vertices = face.vertices()
911
+ normal_vectors = []
912
+
913
+ for facet in Hrep:
914
+ if all(facet.contains(v) and not facet.interior_contains(v)
915
+ for v in face_vertices):
916
+ # The facet contains the face
917
+ normal_vectors.append(facet.A())
918
+
919
+ normal_vector = sum(normal_vectors)
920
+ B = - normal_vector * (face_vertices[0].vector())
921
+ linear_evaluation = {-normal_vector * v.vector()
922
+ for v in polar.vertices()}
923
+
924
+ if B == max(linear_evaluation):
925
+ C = max(linear_evaluation.difference(set([B])))
926
+ else:
927
+ C = min(linear_evaluation.difference(set([B])))
928
+
929
+ ineq_vector = [(1 - subdivision_frac) * B + subdivision_frac * C] + list(normal_vector)
930
+ new_ineq += [ineq_vector]
931
+
932
+ new_ieqs = polar.inequalities_list() + new_ineq
933
+ new_eqns = polar.equations_list()
934
+
935
+ polar = parent.element_class(parent, None, [new_ieqs, new_eqns])
936
+
937
+ return (polar.polar(in_affine_span=True)) + barycenter
938
+
939
+ def permutations_to_matrices(self, conj_class_reps, acting_group=None, additional_elts=None):
940
+ r"""
941
+ Return a dictionary between different representations of elements in
942
+ the ``acting_group``, with group elements represented as permutations
943
+ of the vertices of this polytope (keys) or matrices (values).
944
+
945
+ The dictionary has entries for the generators of the ``acting_group``
946
+ and the representatives of conjugacy classes in ``conj_class_reps``. By
947
+ default, the ``acting_group`` is the
948
+ :meth:`~sage.geometry.polyhedron.base4.Polyhedron_base4.restricted_automorphism_group`
949
+ of the polytope. Each element in ``additional_elts`` also becomes a key.
950
+
951
+ INPUT:
952
+
953
+ - ``conj_class_reps`` -- list; a list of representatives of the
954
+ conjugacy classes of the ``acting_group``
955
+
956
+ - ``acting_group`` -- a subgroup of polytope's
957
+ :meth:`~sage.geometry.polyhedron.base4.Polyhedron_base4.restricted_automorphism_group`
958
+
959
+ - ``additional_elts`` -- list (default: ``None``); a subset of the
960
+ :meth:`~sage.geometry.polyhedron.base4.Polyhedron_base4.restricted_automorphism_group`
961
+ of the polytope expressed as permutations.
962
+
963
+ OUTPUT:
964
+
965
+ A dictionary between elements of the ``acting_group`` expressed as permutations
966
+ (keys) and matrices (values).
967
+
968
+ EXAMPLES:
969
+
970
+ This example shows the dictionary between permutations and matrices
971
+ for the generators of the ``restricted_automorphism_group`` of the
972
+ `\pm 1` 2-dimensional square. The permutations are written in terms
973
+ of the vertices of the square::
974
+
975
+ sage: # optional - pynormaliz, needs sage.groups
976
+ sage: square = Polyhedron(vertices=[[1,1], [-1,1],
977
+ ....: [-1,-1], [1,-1]],
978
+ ....: backend='normaliz')
979
+ sage: square.vertices()
980
+ (A vertex at (-1, -1),
981
+ A vertex at (-1, 1),
982
+ A vertex at (1, -1),
983
+ A vertex at (1, 1))
984
+ sage: aut_square = square.restricted_automorphism_group(output='permutation')
985
+ sage: conj_reps = aut_square.conjugacy_classes_representatives()
986
+ sage: gens_dict = square.permutations_to_matrices(conj_reps)
987
+ sage: rotation_180 = aut_square([(0,3),(1,2)])
988
+ sage: rotation_180, gens_dict[rotation_180]
989
+ (
990
+ [-1 0 0]
991
+ [ 0 -1 0]
992
+ (0,3)(1,2), [ 0 0 1]
993
+ )
994
+
995
+ This example tests the functionality for additional elements::
996
+
997
+ sage: # needs sage.groups sage.rings.real_mpfr
998
+ sage: C = polytopes.cross_polytope(2)
999
+ sage: G = C.restricted_automorphism_group(output='permutation')
1000
+ sage: conj_reps = G.conjugacy_classes_representatives()
1001
+ sage: add_elt = G([(0, 2, 3, 1)])
1002
+ sage: dict = C.permutations_to_matrices(conj_reps,
1003
+ ....: additional_elts=[add_elt])
1004
+ sage: dict[add_elt]
1005
+ [ 0 1 0]
1006
+ [-1 0 0]
1007
+ [ 0 0 1]
1008
+ """
1009
+ if self.is_empty():
1010
+ raise NotImplementedError('empty polyhedra are not supported')
1011
+ if not self.is_compact():
1012
+ raise NotImplementedError('unbounded polyhedra are not supported')
1013
+ V = [v.homogeneous_vector() for v in self.Vrepresentation()]
1014
+ Qplus = sum(v.column() * v.row() for v in V).pseudoinverse()
1015
+ Vplus = list(matrix(V) * Qplus)
1016
+ W = 1 - sum(V[i].column() * Vplus[i].row() for i in range(len(V)))
1017
+
1018
+ G = self.restricted_automorphism_group(output='permutation')
1019
+ if acting_group is not None:
1020
+ G = acting_group
1021
+
1022
+ group_dict = {}
1023
+
1024
+ def permutation_to_matrix(permutation, V, Vplus, W):
1025
+ A = sum(V[permutation(i)].column() * Vplus[i].row()
1026
+ for i in range(len(V)))
1027
+ return A + W
1028
+
1029
+ for perm in G.gens():
1030
+ group_dict[perm] = permutation_to_matrix(perm, V, Vplus, W)
1031
+
1032
+ for perm in conj_class_reps:
1033
+ group_dict[perm] = permutation_to_matrix(perm, V, Vplus, W)
1034
+
1035
+ if additional_elts is not None:
1036
+ for perm in additional_elts:
1037
+ group_dict[perm] = permutation_to_matrix(perm, V, Vplus, W)
1038
+ return group_dict
1039
+
1040
+ @cached_method
1041
+ def bounding_box(self, integral=False, integral_hull=False):
1042
+ r"""
1043
+ Return the coordinates of a rectangular box containing the non-empty polytope.
1044
+
1045
+ INPUT:
1046
+
1047
+ - ``integral`` -- boolean (default: ``False``); whether to
1048
+ only allow integral coordinates in the bounding box
1049
+
1050
+ - ``integral_hull`` -- boolean (default: ``False``); if ``True``, return a
1051
+ box containing the integral points of the polytope, or ``None, None`` if it
1052
+ is known that the polytope has no integral points
1053
+
1054
+ OUTPUT:
1055
+
1056
+ A pair of tuples ``(box_min, box_max)`` where ``box_min`` are
1057
+ the coordinates of a point bounding the coordinates of the
1058
+ polytope from below and ``box_max`` bounds the coordinates
1059
+ from above.
1060
+
1061
+ EXAMPLES::
1062
+
1063
+ sage: Polyhedron([(1/3,2/3), (2/3, 1/3)]).bounding_box()
1064
+ ((1/3, 1/3), (2/3, 2/3))
1065
+ sage: Polyhedron([(1/3,2/3), (2/3, 1/3)]).bounding_box(integral=True)
1066
+ ((0, 0), (1, 1))
1067
+ sage: Polyhedron([(1/3,2/3), (2/3, 1/3)]).bounding_box(integral_hull=True)
1068
+ (None, None)
1069
+ sage: Polyhedron([(1/3,2/3), (3/3, 4/3)]).bounding_box(integral_hull=True)
1070
+ ((1, 1), (1, 1))
1071
+ sage: polytopes.buckyball(exact=False).bounding_box() # needs sage.groups
1072
+ ((-0.8090169944, -0.8090169944, -0.8090169944),
1073
+ (0.8090169944, 0.8090169944, 0.8090169944))
1074
+
1075
+ TESTS::
1076
+
1077
+ sage: Polyhedron().bounding_box()
1078
+ Traceback (most recent call last):
1079
+ ...
1080
+ ValueError: empty polytope is not allowed
1081
+ """
1082
+ from sage.arith.misc import integer_ceil as ceil
1083
+ from sage.arith.misc import integer_floor as floor
1084
+ box_min = []
1085
+ box_max = []
1086
+ if not self.is_compact():
1087
+ raise ValueError("only polytopes (compact polyhedra) are allowed")
1088
+ if self.n_vertices() == 0:
1089
+ raise ValueError("empty polytope is not allowed")
1090
+ for i in range(self.ambient_dim()):
1091
+ coords = [v[i] for v in self.vertex_generator()]
1092
+ max_coord = max(coords)
1093
+ min_coord = min(coords)
1094
+ if integral_hull:
1095
+ a = ceil(min_coord)
1096
+ b = floor(max_coord)
1097
+ if a > b:
1098
+ return None, None
1099
+ box_max.append(b)
1100
+ box_min.append(a)
1101
+ elif integral:
1102
+ box_max.append(ceil(max_coord))
1103
+ box_min.append(floor(min_coord))
1104
+ else:
1105
+ box_max.append(max_coord)
1106
+ box_min.append(min_coord)
1107
+ return (tuple(box_min), tuple(box_max))
1108
+
1109
+ def _polymake_init_(self):
1110
+ """
1111
+ Return a polymake "Polytope" object corresponding to ``self``.
1112
+
1113
+ EXAMPLES::
1114
+
1115
+ sage: P = polytopes.cube()
1116
+ sage: PP = polymake(P) # optional - jupymake
1117
+ sage: PP.N_VERTICES # optional - jupymake
1118
+ 8
1119
+
1120
+ Lower-dimensional polyhedron::
1121
+
1122
+ sage: P = Polyhedron(vertices=[[1, 0], [0, 1]])
1123
+ sage: PP = polymake(P) # optional - jupymake
1124
+ sage: PP.COMBINATORIAL_DIM # optional - jupymake
1125
+ 1
1126
+ sage: PP.AFFINE_HULL # optional - jupymake
1127
+ -1 1 1
1128
+
1129
+ Empty polyhedron::
1130
+
1131
+ sage: P = Polyhedron(ambient_dim=2, vertices=[])
1132
+ sage: PP = polymake(P) # optional - jupymake
1133
+ sage: PP.COMBINATORIAL_DIM # optional - jupymake
1134
+ -1
1135
+
1136
+ Pointed unbounded polyhedron::
1137
+
1138
+ sage: P = Polyhedron(vertices=[[1, 0], [0, 1]], rays=[[1, 0]])
1139
+ sage: PP = polymake(P) # optional - jupymake
1140
+ sage: PP.VERTICES # optional - jupymake
1141
+ 1 0 1
1142
+ 1 1 0
1143
+ 0 1 0
1144
+ sage: PP.FACETS # optional - jupymake
1145
+ 1 0 -1
1146
+ -1 1 1
1147
+ 0 0 1
1148
+
1149
+ Non-pointed polyhedron::
1150
+
1151
+ sage: # optional - jupymake
1152
+ sage: P = Polyhedron(vertices=[[1, 0], [0, 1]], lines=[[1, 0]])
1153
+ sage: PP = polymake(P)
1154
+ sage: PP.VERTICES
1155
+ 1 0 1
1156
+ 1 0 0
1157
+ sage: PP.FACETS
1158
+ 1 0 -1
1159
+ 0 0 1
1160
+ sage: PP.LINEALITY_SPACE
1161
+ 0 1 0
1162
+
1163
+ Algebraic polyhedron::
1164
+
1165
+ sage: # needs sage.groups sage.rings.number_field
1166
+ sage: P = polytopes.dodecahedron(); P
1167
+ A 3-dimensional polyhedron
1168
+ in (Number Field in sqrt5 with defining polynomial x^2 - 5
1169
+ with sqrt5 = 2.236067977499790?)^3
1170
+ defined as the convex hull of 20 vertices
1171
+ sage: print("Maybe recompile warning"); PP = polymake(P); PP # optional - jupymake
1172
+ Maybe recompile warning...
1173
+ Polytope<QuadraticExtension<Rational>>[...]
1174
+ sage: sorted(PP.VERTICES[:], key=repr)[0] # optional - jupymake
1175
+ 1 -1+1r5 -4+2r5 0
1176
+
1177
+ Floating-point polyhedron::
1178
+
1179
+ sage: # optional - jupymake, needs sage.groups
1180
+ sage: P = polytopes.dodecahedron(exact=False); P
1181
+ A 3-dimensional polyhedron in RDF^3 defined as the convex hull of 20 vertices
1182
+ sage: print("There may be a recompilation warning"); PP = polymake(P); PP
1183
+ There may be a recompilation warning...
1184
+ Polytope<Float>[...]
1185
+ sage: sorted(PP.VERTICES[:], key=repr)[0]
1186
+ 1 -0.472135955 0 -1.236067978
1187
+ """
1188
+ from sage.interfaces.polymake import polymake
1189
+ polymake_field = polymake(self.base_ring().fraction_field())
1190
+ polymake_class = "Polytope<{}>".format(polymake_field)
1191
+ if self.is_empty():
1192
+ # Polymake 3.1 cannot enter an empty polyhedron using
1193
+ # FACETS and AFFINE_HULL.
1194
+ # Use corresponding input properties instead.
1195
+ # https://forum.polymake.org/viewtopic.php?f=8&t=545
1196
+ return polymake.new_object(polymake_class,
1197
+ INEQUALITIES=self.inequalities_list(),
1198
+ EQUATIONS=self.equations_list())
1199
+
1200
+ verts_and_rays = [[1] + v for v in self.vertices_list()]
1201
+ verts_and_rays += [[0] + r for r in self.rays_list()]
1202
+ return polymake.new_object(polymake_class,
1203
+ FACETS=self.inequalities_list(),
1204
+ AFFINE_HULL=self.equations_list(),
1205
+ VERTICES=verts_and_rays,
1206
+ LINEALITY_SPACE=[[0] + l for l in self.lines_list()])