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,934 @@
1
+ # sage_setup: distribution = sagemath-polyhedra
2
+ r"""
3
+ Base class for polyhedra over `\ZZ`
4
+ """
5
+
6
+ # ****************************************************************************
7
+ # Copyright (C) 2011-2013 Volker Braun <vbraun.name@gmail.com>
8
+ # 2015 Nathann Cohen
9
+ # 2015 Vincent Delecroix
10
+ # 2017-2018 Frédéric Chapoton
11
+ # 2019 Sophia Elia
12
+ # 2019-2020 Jonathan Kliem
13
+ # 2023 Luze Xu
14
+ # 2023 Matthias Koeppe
15
+ #
16
+ # This program is free software: you can redistribute it and/or modify
17
+ # it under the terms of the GNU General Public License as published by
18
+ # the Free Software Foundation, either version 2 of the License, or
19
+ # (at your option) any later version.
20
+ # https://www.gnu.org/licenses/
21
+ # ****************************************************************************
22
+
23
+ from sage.rings.integer_ring import ZZ
24
+ from sage.rings.rational_field import QQ
25
+ from sage.misc.cachefunc import cached_method
26
+ from sage.modules.free_module_element import vector
27
+ from .base_QQ import Polyhedron_QQ
28
+ from sage.arith.misc import gcd
29
+
30
+
31
+ #########################################################################
32
+ class Polyhedron_ZZ(Polyhedron_QQ):
33
+ r"""
34
+ Base class for Polyhedra over `\ZZ`.
35
+
36
+ TESTS::
37
+
38
+ sage: p = Polyhedron([(0,0)], base_ring=ZZ); p
39
+ A 0-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex
40
+ sage: TestSuite(p).run()
41
+ """
42
+ _base_ring = ZZ
43
+
44
+ def __getattribute__(self, name):
45
+ r"""
46
+ TESTS:
47
+
48
+ A lattice polytope does not have a Ehrhart quasipolynomial because it
49
+ is always a polynomial::
50
+
51
+ sage: P = polytopes.cube()
52
+ sage: P.__getattribute__(name='ehrhart_quasipolynomial')
53
+ Traceback (most recent call last):
54
+ ...
55
+ AttributeError: ehrhart_quasipolynomial
56
+ """
57
+ if name in ['ehrhart_quasipolynomial']:
58
+ raise AttributeError(name)
59
+ return super().__getattribute__(name)
60
+
61
+ def __dir__(self):
62
+ r"""
63
+ TESTS:
64
+
65
+ Removes the Ehrhart quasipolynomial from the list of methods for the
66
+ lattice polyhedron::
67
+
68
+ sage: P = polytopes.cube()
69
+ sage: 'ehrhart_polynomial' in P.__dir__()
70
+ True
71
+ sage: 'ehrhart_quasipolynomial' in P.__dir__()
72
+ False
73
+ """
74
+ orig_dir = (set(dir(self.__class__)) | set(self.__dict__.keys()))
75
+ return sorted(orig_dir - set(['ehrhart_quasipolynomial']))
76
+
77
+ def is_lattice_polytope(self):
78
+ r"""
79
+ Return whether the polyhedron is a lattice polytope.
80
+
81
+ OUTPUT:
82
+
83
+ ``True`` if the polyhedron is compact and has only integral
84
+ vertices, ``False`` otherwise.
85
+
86
+ EXAMPLES::
87
+
88
+ sage: polytopes.cross_polytope(3).is_lattice_polytope()
89
+ True
90
+ sage: polytopes.regular_polygon(5).is_lattice_polytope() # needs sage.rings.number_field
91
+ False
92
+
93
+ TESTS:
94
+
95
+ Check :issue:`22622`::
96
+
97
+ sage: P1 = Polyhedron(vertices = [[1, 0], [0, 1]], rays = [[1, 1]])
98
+ sage: P1.is_lattice_polytope()
99
+ False
100
+ """
101
+ return self.is_compact()
102
+
103
+ def _ehrhart_polynomial_latte(self, verbose=False, dual=None,
104
+ irrational_primal=None, irrational_all_primal=None, maxdet=None,
105
+ no_decomposition=None, compute_vertex_cones=None, smith_form=None,
106
+ dualization=None, triangulation=None, triangulation_max_height=None,
107
+ **kwds):
108
+ r"""
109
+ Return the Ehrhart polynomial of this polyhedron using LattE integrale.
110
+
111
+ Let `P` be a lattice polytope in `\RR^d` and define `L(P,t) = \# (tP
112
+ \cap \ZZ^d)`. Then E. Ehrhart proved in 1962 that `L` coincides with a
113
+ rational polynomial of degree `d` for integer `t`. `L` is called the
114
+ *Ehrhart polynomial* of `P`. For more information see the
115
+ :wikipedia:`Ehrhart_polynomial`.
116
+
117
+ INPUT:
118
+
119
+ - ``verbose`` -- boolean (default: ``False``); if ``True``, print the
120
+ whole output of the LattE command
121
+
122
+ The following options are passed to the LattE command, for details you
123
+ should consult `the LattE documentation
124
+ <https://www.math.ucdavis.edu/~latte/software/packages/latte_current/>`__:
125
+
126
+ - ``dual`` -- boolean; triangulate and signed-decompose in the dual
127
+ space
128
+
129
+ - ``irrational_primal`` -- boolean; triangulate in the dual space,
130
+ signed-decompose in the primal space using irrationalization
131
+
132
+ - ``irrational_all_primal`` -- boolean; triangulate and signed-decompose
133
+ in the primal space using irrationalization
134
+
135
+ - ``maxdet`` -- integer; decompose down to an index (determinant) of
136
+ ``maxdet`` instead of index 1 (unimodular cones)
137
+
138
+ - ``no_decomposition`` -- boolean; do not signed-decompose simplicial cones
139
+
140
+ - ``compute_vertex_cones`` -- string; either 'cdd' or 'lrs' or '4ti2'
141
+
142
+ - ``smith_form`` -- string; either 'ilio' or 'lidia'
143
+
144
+ - ``dualization`` -- string; either 'cdd' or '4ti2'
145
+
146
+ - ``triangulation`` -- string; 'cddlib', '4ti2' or 'topcom'
147
+
148
+ - ``triangulation_max_height`` -- integer; use a uniform distribution of
149
+ height from 1 to this number
150
+
151
+ .. NOTE::
152
+
153
+ Any additional argument is forwarded to LattE's executable
154
+ ``count``. All occurrences of '_' will be replaced with a '-'.
155
+
156
+ ALGORITHM:
157
+
158
+ This method calls the program ``count`` from LattE integrale, a program
159
+ for lattice point enumeration (see
160
+ https://www.math.ucdavis.edu/~latte/).
161
+
162
+ .. SEEALSO::
163
+
164
+ :mod:`~sage.interfaces.latte` the interface to LattE integrale
165
+
166
+ EXAMPLES::
167
+
168
+ sage: P = Polyhedron(vertices=[(0,0,0),(3,3,3),(-3,2,1),(1,-1,-2)])
169
+ sage: p = P._ehrhart_polynomial_latte() # optional - latte_int
170
+ sage: p # optional - latte_int
171
+ 7/2*t^3 + 2*t^2 - 1/2*t + 1
172
+ sage: p(1) # optional - latte_int
173
+ 6
174
+ sage: len(P.integral_points())
175
+ 6
176
+ sage: p(2) # optional - latte_int
177
+ 36
178
+ sage: len((2*P).integral_points())
179
+ 36
180
+
181
+ The unit hypercubes::
182
+
183
+ sage: # optional - latte_int
184
+ sage: from itertools import product
185
+ sage: def hypercube(d):
186
+ ....: return Polyhedron(vertices=list(product([0,1],repeat=d)))
187
+ sage: hypercube(3)._ehrhart_polynomial_latte()
188
+ t^3 + 3*t^2 + 3*t + 1
189
+ sage: hypercube(4)._ehrhart_polynomial_latte()
190
+ t^4 + 4*t^3 + 6*t^2 + 4*t + 1
191
+ sage: hypercube(5)._ehrhart_polynomial_latte()
192
+ t^5 + 5*t^4 + 10*t^3 + 10*t^2 + 5*t + 1
193
+ sage: hypercube(6)._ehrhart_polynomial_latte()
194
+ t^6 + 6*t^5 + 15*t^4 + 20*t^3 + 15*t^2 + 6*t + 1
195
+
196
+ TESTS:
197
+
198
+ Test options::
199
+
200
+ sage: P = Polyhedron(ieqs=[[1,-1,1,0], [-1,2,-1,0], [1,1,-2,0]], eqns=[[-1,2,-1,-3]], base_ring=ZZ)
201
+
202
+ sage: p = P._ehrhart_polynomial_latte(maxdet=5, verbose=True) # optional - latte_int
203
+ This is LattE integrale ...
204
+ ...
205
+ Invocation: ...count... --ehrhart-polynomial '--redundancy-check=none' --cdd '--maxdet=5' /dev/stdin
206
+ ...
207
+ sage: p # optional - latte_int
208
+ 1/2*t^2 + 3/2*t + 1
209
+
210
+ sage: p = P._ehrhart_polynomial_latte(dual=True, verbose=True) # optional - latte_int
211
+ This is LattE integrale ...
212
+ ...
213
+ Invocation: ...count... --ehrhart-polynomial '--redundancy-check=none' --cdd --dual /dev/stdin
214
+ ...
215
+ sage: p # optional - latte_int
216
+ 1/2*t^2 + 3/2*t + 1
217
+
218
+ sage: p = P._ehrhart_polynomial_latte(irrational_primal=True, verbose=True) # optional - latte_int
219
+ This is LattE integrale ...
220
+ ...
221
+ Invocation: ...count... --ehrhart-polynomial '--redundancy-check=none' --cdd --irrational-primal /dev/stdin
222
+ ...
223
+ sage: p # optional - latte_int
224
+ 1/2*t^2 + 3/2*t + 1
225
+
226
+ sage: p = P._ehrhart_polynomial_latte(irrational_all_primal=True, verbose=True) # optional - latte_int
227
+ This is LattE integrale ...
228
+ ...
229
+ Invocation: ...count... --ehrhart-polynomial '--redundancy-check=none' --cdd --irrational-all-primal /dev/stdin
230
+ ...
231
+ sage: p # optional - latte_int
232
+ 1/2*t^2 + 3/2*t + 1
233
+
234
+ Test bad options::
235
+
236
+ sage: P._ehrhart_polynomial_latte(bim_bam_boum=19) # optional - latte_int
237
+ Traceback (most recent call last):
238
+ ...
239
+ RuntimeError: LattE integrale program failed (exit code 1):
240
+ ...
241
+ Invocation: ...count... --ehrhart-polynomial '--redundancy-check=none' --cdd '--bim-bam-boum=19' /dev/stdin
242
+ Unknown command/option --bim-bam-boum=19
243
+ """
244
+ # note: the options below are explicitly written in the function
245
+ # declaration in order to keep tab completion (see #18211).
246
+ kwds.update({
247
+ 'dual' : dual,
248
+ 'irrational_primal' : irrational_primal,
249
+ 'irrational_all_primal' : irrational_all_primal,
250
+ 'maxdet' : maxdet,
251
+ 'no_decomposition' : no_decomposition,
252
+ 'compute_vertex_cones' : compute_vertex_cones,
253
+ 'smith_form' : smith_form,
254
+ 'dualization' : dualization,
255
+ 'triangulation' : triangulation,
256
+ 'triangulation_max_height': triangulation_max_height})
257
+
258
+ from sage.interfaces.latte import count
259
+ ine = self.cdd_Hrepresentation()
260
+ return count(ine, cdd=True, ehrhart_polynomial=True, verbose=verbose, **kwds)
261
+
262
+ def _ehrhart_polynomial_normaliz(self, variable='t'):
263
+ r"""
264
+ Compute the Ehrhart polynomial of a lattice polytope using Normaliz.
265
+
266
+ The backend of ``self`` must be 'normaliz'.
267
+
268
+ INPUT:
269
+
270
+ - ``variable`` -- string (default: ``'t'``); the variable in which the
271
+ Ehrhart polynomial is expressed
272
+
273
+ OUTPUT: a univariate polynomial over a rational field
274
+
275
+ EXAMPLES::
276
+
277
+ sage: c = Polyhedron(vertices = [[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]],backend='normaliz') # optional - pynormaliz
278
+ sage: c._ehrhart_polynomial_normaliz() # optional - pynormaliz
279
+ t^3 + 3*t^2 + 3*t + 1
280
+
281
+ Changing the variable works::
282
+
283
+ sage: c._ehrhart_polynomial_normaliz(variable='k') # optional - pynormaliz
284
+ k^3 + 3*k^2 + 3*k + 1
285
+
286
+ TESTS:
287
+
288
+ Receive a type error if the backend is not normaliz::
289
+
290
+ sage: c = Polyhedron(vertices = [[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]])
291
+ sage: c._ehrhart_polynomial_normaliz()
292
+ Traceback (most recent call last):
293
+ ...
294
+ TypeError: The polyhedron's backend should be 'normaliz'
295
+ """
296
+ raise TypeError("The polyhedron's backend should be 'normaliz'")
297
+
298
+ @cached_method(do_pickle=True)
299
+ def ehrhart_polynomial(self, engine=None, variable='t', verbose=False,
300
+ dual=None, irrational_primal=None,
301
+ irrational_all_primal=None, maxdet=None,
302
+ no_decomposition=None, compute_vertex_cones=None,
303
+ smith_form=None, dualization=None,
304
+ triangulation=None, triangulation_max_height=None,
305
+ **kwds):
306
+ r"""
307
+ Return the Ehrhart polynomial of this polyhedron.
308
+
309
+ Let `P` be a lattice polytope in `\RR^d` and define `L(P,t) = \# (tP
310
+ \cap \ZZ^d)`. Then E. Ehrhart proved in 1962 that `L` coincides with a
311
+ rational polynomial of degree `d` for integer `t`. `L` is called the
312
+ *Ehrhart polynomial* of `P`. For more information see the
313
+ :wikipedia:`Ehrhart_polynomial`.
314
+
315
+ The Ehrhart polynomial may be computed using either LattE Integrale
316
+ or Normaliz by setting ``engine`` to 'latte' or 'normaliz' respectively.
317
+
318
+ INPUT:
319
+
320
+ - ``engine`` -- string; the backend to use. Allowed values are:
321
+
322
+ * ``None`` (default); When no input is given the Ehrhart polynomial
323
+ is computed using LattE Integrale (optional)
324
+ * ``'latte'``; use LattE integrale program (optional)
325
+ * ``'normaliz'``; use Normaliz program (optional). The backend of
326
+ ``self`` must be set to 'normaliz'.
327
+
328
+ - ``variable`` -- string (default: ``'t'``); the variable in which the
329
+ Ehrhart polynomial should be expressed
330
+
331
+ - When the ``engine`` is 'latte' or None, the additional input values are:
332
+
333
+ * ``verbose`` -- boolean (default: ``False``); if ``True``, print the
334
+ whole output of the LattE command.
335
+
336
+ The following options are passed to the LattE command, for details
337
+ consult `the LattE documentation
338
+ <https://www.math.ucdavis.edu/~latte/software/packages/latte_current/>`__:
339
+
340
+ * ``dual`` -- boolean; triangulate and signed-decompose in the dual
341
+ space
342
+ * ``irrational_primal`` -- boolean; triangulate in the dual space,
343
+ signed-decompose in the primal space using irrationalization.
344
+ * ``irrational_all_primal`` -- boolean; triangulate and signed-decompose
345
+ in the primal space using irrationalization.
346
+ * ``maxdet`` -- integer; decompose down to an index (determinant) of
347
+ ``maxdet`` instead of index 1 (unimodular cones).
348
+ * ``no_decomposition`` -- boolean; do not signed-decompose
349
+ simplicial cones.
350
+ * ``compute_vertex_cones`` -- string; either 'cdd' or 'lrs' or '4ti2'
351
+ * ``smith_form`` -- string; either 'ilio' or 'lidia'
352
+ * ``dualization`` -- string; either 'cdd' or '4ti2'
353
+ * ``triangulation`` -- string; 'cddlib', '4ti2' or 'topcom'
354
+ * ``triangulation_max_height`` -- integer; use a uniform distribution of
355
+ height from 1 to this number
356
+
357
+ OUTPUT:
358
+
359
+ The Ehrhart polynomial as a univariate polynomial in ``variable``
360
+ over a rational field.
361
+
362
+ .. SEEALSO::
363
+
364
+ :mod:`~sage.interfaces.latte` the interface to LattE Integrale
365
+ `PyNormaliz <https://pypi.org/project/PyNormaliz>`_
366
+
367
+ EXAMPLES:
368
+
369
+ To start, we find the Ehrhart polynomial of a three-dimensional
370
+ ``simplex``, first using ``engine='latte'``. Leaving the engine
371
+ unspecified sets the ``engine`` to 'latte' by default::
372
+
373
+ sage: simplex = Polyhedron(vertices=[(0,0,0),(3,3,3),(-3,2,1),(1,-1,-2)])
374
+ sage: poly = simplex.ehrhart_polynomial(engine = 'latte') # optional - latte_int
375
+ sage: poly # optional - latte_int
376
+ 7/2*t^3 + 2*t^2 - 1/2*t + 1
377
+ sage: poly(1) # optional - latte_int
378
+ 6
379
+ sage: len(simplex.integral_points())
380
+ 6
381
+ sage: poly(2) # optional - latte_int
382
+ 36
383
+ sage: len((2*simplex).integral_points())
384
+ 36
385
+
386
+ Now we find the same Ehrhart polynomial, this time using
387
+ ``engine='normaliz'``. To use the Normaliz engine, the ``simplex`` must
388
+ be defined with ``backend='normaliz'``::
389
+
390
+ sage: simplex = Polyhedron(vertices=[(0,0,0),(3,3,3),(-3,2,1),(1,-1,-2)], backend='normaliz') # optional - pynormaliz
391
+ sage: poly = simplex.ehrhart_polynomial(engine='normaliz') # optional - pynormaliz
392
+ sage: poly # optional - pynormaliz
393
+ 7/2*t^3 + 2*t^2 - 1/2*t + 1
394
+
395
+ If the ``engine='normaliz'``, the backend should be ``'normaliz'``, otherwise
396
+ it returns an error::
397
+
398
+ sage: simplex = Polyhedron(vertices=[(0,0,0),(3,3,3),(-3,2,1),(1,-1,-2)])
399
+ sage: simplex.ehrhart_polynomial(engine='normaliz')
400
+ Traceback (most recent call last):
401
+ ...
402
+ TypeError: The polyhedron's backend should be 'normaliz'
403
+
404
+ Now we find the Ehrhart polynomials of the unit hypercubes of
405
+ dimensions three through six. They are computed first with
406
+ ``engine='latte'`` and then with ``engine='normaliz'``.
407
+ The degree of the Ehrhart polynomial matches the dimension of the
408
+ hypercube, and the coefficient of the leading monomial equals the
409
+ volume of the unit hypercube::
410
+
411
+ sage: # optional - latte_int
412
+ sage: from itertools import product
413
+ sage: def hypercube(d):
414
+ ....: return Polyhedron(vertices=list(product([0,1],repeat=d)))
415
+ sage: hypercube(3).ehrhart_polynomial()
416
+ t^3 + 3*t^2 + 3*t + 1
417
+ sage: hypercube(4).ehrhart_polynomial()
418
+ t^4 + 4*t^3 + 6*t^2 + 4*t + 1
419
+ sage: hypercube(5).ehrhart_polynomial()
420
+ t^5 + 5*t^4 + 10*t^3 + 10*t^2 + 5*t + 1
421
+ sage: hypercube(6).ehrhart_polynomial()
422
+ t^6 + 6*t^5 + 15*t^4 + 20*t^3 + 15*t^2 + 6*t + 1
423
+
424
+ sage: # optional - pynormaliz
425
+ sage: from itertools import product
426
+ sage: def hypercube(d):
427
+ ....: return Polyhedron(vertices=list(product([0,1],repeat=d)),backend='normaliz')
428
+ sage: hypercube(3).ehrhart_polynomial(engine='normaliz')
429
+ t^3 + 3*t^2 + 3*t + 1
430
+ sage: hypercube(4).ehrhart_polynomial(engine='normaliz')
431
+ t^4 + 4*t^3 + 6*t^2 + 4*t + 1
432
+ sage: hypercube(5).ehrhart_polynomial(engine='normaliz')
433
+ t^5 + 5*t^4 + 10*t^3 + 10*t^2 + 5*t + 1
434
+ sage: hypercube(6).ehrhart_polynomial(engine='normaliz')
435
+ t^6 + 6*t^5 + 15*t^4 + 20*t^3 + 15*t^2 + 6*t + 1
436
+
437
+ An empty polyhedron::
438
+
439
+ sage: p = Polyhedron(ambient_dim=3, vertices=[])
440
+ sage: p.ehrhart_polynomial()
441
+ 0
442
+ sage: parent(_)
443
+ Univariate Polynomial Ring in t over Rational Field
444
+
445
+ The polyhedron should be compact::
446
+
447
+ sage: C = Polyhedron(rays=[[1,2],[2,1]])
448
+ sage: C.ehrhart_polynomial()
449
+ Traceback (most recent call last):
450
+ ...
451
+ ValueError: Ehrhart polynomial only defined for compact polyhedra
452
+
453
+ TESTS:
454
+
455
+ The cache of the Ehrhart polynomial is being pickled::
456
+
457
+ sage: P = polytopes.cube()
458
+ sage: P.ehrhart_polynomial() # optional - latte_int
459
+ 8*t^3 + 12*t^2 + 6*t + 1
460
+ sage: Q = loads(dumps(P))
461
+ sage: Q.ehrhart_polynomial.is_in_cache() # optional - latte_int
462
+ True
463
+ """
464
+ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
465
+ from sage.rings.rational_field import QQ
466
+ R = PolynomialRing(QQ, variable)
467
+
468
+ if self.is_empty():
469
+ return R.zero()
470
+
471
+ if self.dimension() == 0:
472
+ return R.one()
473
+
474
+ if not self.is_compact():
475
+ raise ValueError("Ehrhart polynomial only defined for compact polyhedra")
476
+
477
+ if engine is None:
478
+ # setting the default to 'latte'
479
+ engine = 'latte'
480
+ if engine == 'latte':
481
+ poly = self._ehrhart_polynomial_latte(verbose, dual,
482
+ irrational_primal, irrational_all_primal, maxdet,
483
+ no_decomposition, compute_vertex_cones, smith_form,
484
+ dualization, triangulation, triangulation_max_height,
485
+ **kwds)
486
+ return poly.change_variable_name(variable)
487
+ # TO DO: replace this change of variable by creating the appropriate
488
+ # polynomial ring in the latte interface.
489
+
490
+ elif engine == 'normaliz':
491
+ return self._ehrhart_polynomial_normaliz(variable)
492
+ else:
493
+ raise ValueError("engine must be 'latte' or 'normaliz'")
494
+
495
+ @cached_method
496
+ def polar(self):
497
+ """
498
+ Return the polar (dual) polytope.
499
+
500
+ The polytope must have the IP-property (see
501
+ :meth:`has_IP_property`), that is, the origin must be an
502
+ interior point. In particular, it must be full-dimensional.
503
+
504
+ OUTPUT:
505
+
506
+ The polytope whose vertices are the coefficient vectors of the
507
+ inequalities of ``self`` with inhomogeneous term normalized to
508
+ unity.
509
+
510
+ EXAMPLES::
511
+
512
+ sage: p = Polyhedron(vertices=[(1,0,0),(0,1,0),(0,0,1),(-1,-1,-1)], base_ring=ZZ)
513
+ sage: p.polar()
514
+ A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 4 vertices
515
+ sage: type(_)
516
+ <class 'sage.geometry.polyhedron.parent.Polyhedra_ZZ_ppl_with_category.element_class'>
517
+ sage: p.polar().base_ring()
518
+ Integer Ring
519
+
520
+ TESTS:
521
+
522
+ Test that :issue:`28551` is fixed::
523
+
524
+ sage: polytopes.cube(backend='normaliz').polar().backend() # optional - pynormaliz
525
+ 'normaliz'
526
+ """
527
+ if not self.has_IP_property():
528
+ raise ValueError('The polytope must have the IP property.')
529
+
530
+ vertices = tuple(ieq.A() / ieq.b() for
531
+ ieq in self.inequality_generator())
532
+
533
+ ieqs = ((1,) + tuple(v[:]) for v in self.vertices())
534
+
535
+ pref_rep = 'Hrep' if self.n_vertices() <= self.n_inequalities() else 'Vrep'
536
+
537
+ if all(v_i in ZZ for v in vertices for v_i in v):
538
+ parent = self.parent()
539
+ vertices = (v.change_ring(ZZ) for v in vertices)
540
+ else:
541
+ parent = self.parent().change_ring(QQ)
542
+
543
+ return parent.element_class(parent, [vertices, [], []], [ieqs, []],
544
+ Vrep_minimal=True, Hrep_minimal=True, pref_rep=pref_rep)
545
+
546
+ @cached_method
547
+ def is_reflexive(self):
548
+ r"""
549
+ A lattice polytope is reflexive if it contains the origin in its interior
550
+ and its polar with respect to the origin is a lattice polytope.
551
+
552
+ Equivalently, it is reflexive if it is of the form `\{x \in \mathbb{R}^d: Ax \leq 1\}`
553
+ for some integer matrix `A` and `d` the ambient dimension.
554
+
555
+ EXAMPLES::
556
+
557
+ sage: p = Polyhedron(vertices=[(1,0,0),(0,1,0),(0,0,1),(-1,-1,-1)], base_ring=ZZ)
558
+ sage: p.is_reflexive()
559
+ True
560
+ sage: polytopes.hypercube(4).is_reflexive()
561
+ True
562
+ sage: p = Polyhedron(vertices=[(1,0), (0,2), (-1,0), (0,-1)], base_ring=ZZ)
563
+ sage: p.is_reflexive()
564
+ False
565
+ sage: p = Polyhedron(vertices=[(1,0), (0,2), (-1,0)], base_ring=ZZ)
566
+ sage: p.is_reflexive()
567
+ False
568
+
569
+ An error is raised, if the polyhedron is not compact::
570
+
571
+ sage: p = Polyhedron(rays=[(1,)], base_ring=ZZ)
572
+ sage: p.is_reflexive()
573
+ Traceback (most recent call last):
574
+ ...
575
+ ValueError: the polyhedron is not compact
576
+ """
577
+ if not self.is_compact():
578
+ raise ValueError("the polyhedron is not compact")
579
+
580
+ for H in self.Hrepresentation():
581
+ if H.is_equation():
582
+ return False
583
+ b = H.b()
584
+ if b < 1:
585
+ return False
586
+ if not all(v_i/b in ZZ for v_i in H.A()):
587
+ return False
588
+
589
+ return True
590
+
591
+ @cached_method
592
+ def has_IP_property(self) -> bool:
593
+ """
594
+ Test whether the polyhedron has the IP property.
595
+
596
+ The IP (interior point) property means that
597
+
598
+ * ``self`` is compact (a polytope).
599
+
600
+ * ``self`` contains the origin as an interior point.
601
+
602
+ This implies that
603
+
604
+ * ``self`` is full-dimensional.
605
+
606
+ * The dual polyhedron is again a polytope (that is, a compact
607
+ polyhedron), though not necessarily a lattice polytope.
608
+
609
+ EXAMPLES::
610
+
611
+ sage: Polyhedron([(1,1),(1,0),(0,1)], base_ring=ZZ).has_IP_property()
612
+ False
613
+ sage: Polyhedron([(0,0),(1,0),(0,1)], base_ring=ZZ).has_IP_property()
614
+ False
615
+ sage: Polyhedron([(-1,-1),(1,0),(0,1)], base_ring=ZZ).has_IP_property()
616
+ True
617
+
618
+ REFERENCES:
619
+
620
+ - [PALP]_
621
+ """
622
+ return self.is_compact() and self.interior_contains(self.ambient_space().zero())
623
+
624
+ def fibration_generator(self, dim):
625
+ """
626
+ Generate the lattice polytope fibrations.
627
+
628
+ For the purposes of this function, a lattice polytope fiber is
629
+ a sub-lattice polytope. Projecting the plane spanned by the
630
+ subpolytope to a point yields another lattice polytope, the
631
+ base of the fibration.
632
+
633
+ INPUT:
634
+
635
+ - ``dim`` -- integer; the dimension of the lattice polytope
636
+ fiber
637
+
638
+ OUTPUT:
639
+
640
+ A generator yielding the distinct lattice polytope fibers of
641
+ given dimension.
642
+
643
+ EXAMPLES::
644
+
645
+ sage: P = Polyhedron(toric_varieties.P4_11169().fan().rays(), base_ring=ZZ) # needs palp sage.graphs
646
+ sage: list(P.fibration_generator(2)) # needs palp sage.graphs
647
+ [A 2-dimensional polyhedron in ZZ^4 defined as the convex hull of 3 vertices]
648
+ """
649
+ from sage.combinat.combination import Combinations
650
+ if not self.is_compact():
651
+ raise ValueError('Only polytopes (compact polyhedra) are allowed.')
652
+
653
+ nonzero_points = [p for p in self.integral_points() if not p.is_zero()]
654
+ origin = [[0]*self.ambient_dim()]
655
+ fibers = set()
656
+ parent = self.parent()
657
+
658
+ for points in Combinations(nonzero_points, dim):
659
+ plane = parent.element_class(parent, [origin,[],points], None)
660
+ if plane.dim() != dim:
661
+ continue
662
+ fiber = self.intersection(plane)
663
+ if fiber.base_ring() is not ZZ:
664
+ continue
665
+ fiber_vertices = tuple(sorted(tuple(v) for v in fiber.vertex_generator()))
666
+ if fiber_vertices not in fibers:
667
+ yield fiber
668
+ fibers.update([fiber_vertices])
669
+ plane._delete()
670
+
671
+ def find_translation(self, translated_polyhedron):
672
+ r"""
673
+ Return the translation vector to ``translated_polyhedron``.
674
+
675
+ INPUT:
676
+
677
+ - ``translated_polyhedron`` -- a polyhedron
678
+
679
+ OUTPUT:
680
+
681
+ A `\ZZ`-vector that translates ``self`` to
682
+ ``translated_polyhedron``. A :exc:`ValueError` is raised if
683
+ ``translated_polyhedron`` is not a translation of ``self``,
684
+ this can be used to check that two polyhedra are not
685
+ translates of each other.
686
+
687
+ EXAMPLES::
688
+
689
+ sage: X = polytopes.cube()
690
+ sage: X.find_translation(X + vector([2,3,5]))
691
+ (2, 3, 5)
692
+ sage: X.find_translation(2*X)
693
+ Traceback (most recent call last):
694
+ ...
695
+ ValueError: polyhedron is not a translation of self
696
+ """
697
+ no_translation_exception = ValueError('polyhedron is not a translation of self')
698
+ if ( set(self.rays()) != set(translated_polyhedron.rays()) or
699
+ set(self.lines()) != set(translated_polyhedron.lines()) or
700
+ self.n_vertices() != translated_polyhedron.n_vertices() ):
701
+ raise no_translation_exception
702
+ sorted_vertices = sorted(map(vector, self.vertices()))
703
+ sorted_translated_vertices = sorted(map(vector, translated_polyhedron.vertices()))
704
+ v = sorted_translated_vertices[0] - sorted_vertices[0]
705
+ if any(vertex+v != translated_vertex
706
+ for vertex, translated_vertex in zip(sorted_vertices, sorted_translated_vertices)):
707
+ raise no_translation_exception
708
+ return v
709
+
710
+ def _subpoly_parallel_facets(self):
711
+ r"""
712
+ Generator for all lattice sub-polyhedra with parallel facets.
713
+
714
+ In a sub-polyhedron `Y\subset X` not all edges of `Y` need to
715
+ be parallel to `X`. This method iterates over all
716
+ sub-polyhedra where they are parallel, up to an overall
717
+ translation of the sub-polyhedron. Degenerate sub-polyhedra of
718
+ dimension strictly smaller are included.
719
+
720
+ OUTPUT:
721
+
722
+ A generator yielding `\ZZ`-polyhedra. By construction, each
723
+ facet of the returned polyhedron is parallel to one of the
724
+ facets of ``self``.
725
+
726
+ EXAMPLES::
727
+
728
+ sage: X = Polyhedron(vertices=[(0,0), (0,1), (1,0), (1,1)])
729
+ sage: X._subpoly_parallel_facets()
730
+ <generator object ..._subpoly_parallel_facets at 0x...>
731
+ sage: for p in X._subpoly_parallel_facets():
732
+ ....: print(p.Vrepresentation())
733
+ (A vertex at (0, 0),)
734
+ (A vertex at (0, -1), A vertex at (0, 0))
735
+ (A vertex at (-1, 0), A vertex at (0, 0))
736
+ (A vertex at (-1, -1), A vertex at (-1, 0), A vertex at (0, -1), A vertex at (0, 0))
737
+
738
+ TESTS::
739
+
740
+ sage: X = Polyhedron(vertices=[(0,), (3,)])
741
+ sage: [ p.vertices() for p in X._subpoly_parallel_facets() ]
742
+ [(A vertex at (0),),
743
+ (A vertex at (-1), A vertex at (0)),
744
+ (A vertex at (-2), A vertex at (0)),
745
+ (A vertex at (-3), A vertex at (0))]
746
+ sage: list( Polyhedron(vertices=[[0,0]])._subpoly_parallel_facets() )
747
+ [A 0-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex]
748
+ sage: list( Polyhedron()._subpoly_parallel_facets() )
749
+ [The empty polyhedron in ZZ^0]
750
+ """
751
+ if self.dim() > 2 or not self.is_compact():
752
+ raise NotImplementedError('only implemented for bounded polygons')
753
+ from sage.geometry.polyhedron.plot import cyclic_sort_vertices_2d
754
+ vertices = cyclic_sort_vertices_2d(self.vertices())
755
+ n = len(vertices)
756
+ if n == 1: # single point
757
+ yield self
758
+ return
759
+ edge_vectors = []
760
+ for i in range(n):
761
+ v = vertices[(i+1) % n].vector() - vertices[i].vector()
762
+ d = gcd(list(v))
763
+ v_prim = (v/d).change_ring(ZZ)
764
+ edge_vectors.append([ v_prim*i for i in range(d+1) ])
765
+ origin = self.ambient_space().zero()
766
+ parent = self.parent()
767
+ from itertools import product
768
+ for edges in product(*edge_vectors):
769
+ v = []
770
+ point = origin
771
+ for e in edges:
772
+ point += e
773
+ v.append(point)
774
+ if point != origin: # does not close up, not a subpolygon
775
+ continue
776
+ yield parent([v, [], []], None)
777
+
778
+ @cached_method
779
+ def minkowski_decompositions(self):
780
+ r"""
781
+ Return all Minkowski sums that add up to the polyhedron.
782
+
783
+ OUTPUT:
784
+
785
+ A tuple consisting of pairs `(X,Y)` of `\ZZ`-polyhedra that
786
+ add up to ``self``. All pairs up to exchange of the summands
787
+ are returned, that is, `(Y,X)` is not included if `(X,Y)`
788
+ already is.
789
+
790
+ EXAMPLES::
791
+
792
+ sage: square = Polyhedron(vertices=[(0,0),(1,0),(0,1),(1,1)])
793
+ sage: square.minkowski_decompositions()
794
+ ((A 0-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex,
795
+ A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 4 vertices),
796
+ (A 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices,
797
+ A 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices))
798
+
799
+ Example from http://cgi.di.uoa.gr/~amantzaf/geo/ ::
800
+
801
+ sage: Q = Polyhedron(vertices=[(4,0), (6,0), (0,3), (4,3)])
802
+ sage: R = Polyhedron(vertices=[(0,0), (5,0), (8,4), (3,2)])
803
+ sage: (Q+R).minkowski_decompositions()
804
+ ((A 0-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex,
805
+ A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 7 vertices),
806
+ (A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 4 vertices,
807
+ A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 4 vertices),
808
+ (A 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices,
809
+ A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 7 vertices),
810
+ (A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 5 vertices,
811
+ A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 4 vertices),
812
+ (A 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices,
813
+ A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 7 vertices),
814
+ (A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 5 vertices,
815
+ A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 3 vertices),
816
+ (A 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices,
817
+ A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 7 vertices),
818
+ (A 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices,
819
+ A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 6 vertices))
820
+
821
+ sage: [ len(square.dilation(i).minkowski_decompositions())
822
+ ....: for i in range(6) ]
823
+ [1, 2, 5, 8, 13, 18]
824
+ sage: [ integer_ceil((i^2 + 2*i - 1) / 2) + 1 for i in range(10) ]
825
+ [1, 2, 5, 8, 13, 18, 25, 32, 41, 50]
826
+ """
827
+ if self.dim() > 2 or not self.is_compact():
828
+ raise NotImplementedError('only implemented for bounded polygons')
829
+ summands = []
830
+
831
+ def is_known_summand(poly):
832
+ for summand in summands:
833
+ try:
834
+ poly.find_translation(summand)
835
+ return True
836
+ except ValueError:
837
+ pass
838
+ decompositions = []
839
+ for X in self._subpoly_parallel_facets():
840
+ if is_known_summand(X):
841
+ continue
842
+ Y = self - X
843
+ Y = Y.change_ring(ZZ) # Minkowski difference returns QQ-polyhedron
844
+ if X + Y != self:
845
+ continue
846
+ decompositions.append((X, Y))
847
+ summands += [X, Y]
848
+ return tuple(decompositions)
849
+
850
+ def normal_form(self, algorithm='palp_native', permutation=False):
851
+ r"""
852
+ Return the normal form of vertices of the lattice polytope ``self``.
853
+
854
+ INPUT:
855
+
856
+ - ``algorithm`` -- must be ``'palp_native'``, the default
857
+
858
+ - ``permutation`` -- boolean (default: ``False``); if ``True``, the permutation
859
+ applied to vertices to obtain the normal form is returned as well
860
+
861
+ For more more detail,
862
+ see :meth:`~sage.geometry.lattice_polytope.LatticePolytopeClass.normal_form`.
863
+
864
+ EXAMPLES:
865
+
866
+ We compute the normal form of the "diamond"::
867
+
868
+ sage: d = Polyhedron([(1,0), (0,1), (-1,0), (0,-1)])
869
+ sage: d.vertices()
870
+ (A vertex at (-1, 0),
871
+ A vertex at (0, -1),
872
+ A vertex at (0, 1),
873
+ A vertex at (1, 0))
874
+ sage: d.normal_form() # needs sage.groups
875
+ [(1, 0), (0, 1), (0, -1), (-1, 0)]
876
+ sage: d.lattice_polytope().normal_form("palp_native") # needs sage.groups
877
+ M( 1, 0),
878
+ M( 0, 1),
879
+ M( 0, -1),
880
+ M(-1, 0)
881
+ in 2-d lattice M
882
+
883
+ Using ``permutation=True``::
884
+
885
+ sage: d.normal_form(permutation=True) # needs sage.groups
886
+ ([(1, 0), (0, 1), (0, -1), (-1, 0)], ())
887
+
888
+ It is not possible to compute normal forms for polytopes which do not
889
+ span the space::
890
+
891
+ sage: p = Polyhedron([(1,0,0), (0,1,0), (-1,0,0), (0,-1,0)])
892
+ sage: p.normal_form() # needs sage.groups
893
+ Traceback (most recent call last):
894
+ ...
895
+ ValueError: normal form is not defined for lower-dimensional polyhedra, got
896
+ A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 4 vertices
897
+
898
+ The normal form is also not defined for unbounded polyhedra::
899
+
900
+ sage: p = Polyhedron(vertices=[[1, 1]], rays=[[1, 0], [0, 1]], base_ring=ZZ)
901
+ sage: p.normal_form() # needs sage.groups
902
+ Traceback (most recent call last):
903
+ ...
904
+ ValueError: normal form is not defined for unbounded polyhedra, got
905
+ A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex and 2 rays
906
+
907
+ See :issue:`15280` for proposed extensions to these cases.
908
+
909
+ TESTS::
910
+
911
+ sage: d.normal_form(algorithm='palp_fiction') # needs sage.groups
912
+ Traceback (most recent call last):
913
+ ...
914
+ ValueError: algorithm must be 'palp_native'
915
+ """
916
+ from sage.geometry.palp_normal_form import _palp_PM_max, _palp_canonical_order
917
+
918
+ if algorithm != "palp_native":
919
+ raise ValueError("algorithm must be 'palp_native'")
920
+
921
+ if self.dim() < self.ambient_dim():
922
+ raise ValueError("normal form is not defined for lower-dimensional polyhedra, got %s" % self)
923
+
924
+ if not self.is_compact():
925
+ raise ValueError("normal form is not defined for unbounded polyhedra, got %s" % self)
926
+
927
+ PM = self.slack_matrix().transpose()
928
+ PM_max, permutations = _palp_PM_max(PM, check=True)
929
+ out = _palp_canonical_order(self.vertices(), PM_max, permutations)
930
+
931
+ if permutation:
932
+ return out
933
+ else:
934
+ return out[0]