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,997 @@
1
+ # sage_setup: distribution = sagemath-polyhedra
2
+ r"""
3
+ Base class for polyhedra: Methods for triangulation and volume computation
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.cpython.string import bytes_to_str
35
+ from sage.misc.cachefunc import cached_method
36
+ from sage.modules.free_module_element import vector
37
+ from sage.rings.integer_ring import ZZ
38
+ from sage.rings.rational_field import QQ
39
+ from .base6 import Polyhedron_base6
40
+
41
+
42
+ class Polyhedron_base7(Polyhedron_base6):
43
+ r"""
44
+ Methods related to triangulation and volume.
45
+
46
+ TESTS::
47
+
48
+ sage: # needs sage.combinat
49
+ sage: from sage.geometry.polyhedron.base7 import Polyhedron_base7
50
+ sage: P = polytopes.associahedron(['A', 3])
51
+ sage: Polyhedron_base7.centroid(P)
52
+ (81/632, 36/79, 81/632)
53
+ sage: Polyhedron_base7.triangulate(P)
54
+ (<0,1,2,13>, <0,1,7,13>, <0,2,5,13>, <0,6,7,12>, <0,6,8,13>,
55
+ <0,6,12,13>, <0,7,12,13>, <1,2,7,12>, <1,2,12,13>, <1,7,12,13>,
56
+ <2,3,7,12>, <2,3,12,13>, <3,4,7,12>, <3,11,12,13>, <6,8,9,12>,
57
+ <6,8,12,13>, <6,9,10,12>, <8,9,12,13>)
58
+ sage: Polyhedron_base7.volume(P, measure='induced')
59
+ 79/3
60
+ """
61
+ @cached_method(do_pickle=True)
62
+ def centroid(self, engine='auto', **kwds):
63
+ r"""
64
+ Return the center of the mass of the polytope.
65
+
66
+ The mass is taken with respect to the induced Lebesgue measure,
67
+ see :meth:`volume`.
68
+
69
+ If the polyhedron is not compact, a :exc:`NotImplementedError` is
70
+ raised.
71
+
72
+ INPUT:
73
+
74
+ - ``engine`` -- either 'auto' (default), 'internal',
75
+ 'TOPCOM', or 'normaliz'. The 'internal' and 'TOPCOM' instruct
76
+ this package to always use its own triangulation algorithms
77
+ or TOPCOM's algorithms, respectively. By default ('auto'),
78
+ TOPCOM is used if it is available and internal routines otherwise.
79
+
80
+ - ``**kwds`` -- keyword arguments that are passed to the
81
+ triangulation engine (see :meth:`triangulate`)
82
+
83
+ OUTPUT: the centroid as vector
84
+
85
+ ALGORITHM:
86
+
87
+ We triangulate the polytope and find the barycenter of the simplices.
88
+ We add the individual barycenters weighted by the fraction of the total
89
+ mass.
90
+
91
+ EXAMPLES::
92
+
93
+ sage: P = polytopes.hypercube(2).pyramid()
94
+ sage: P.centroid()
95
+ (1/4, 0, 0)
96
+
97
+ sage: P = polytopes.associahedron(['A', 2]) # needs sage.combinat
98
+ sage: P.centroid() # needs sage.combinat
99
+ (2/21, 2/21)
100
+
101
+ sage: P = polytopes.permutahedron(4, backend='normaliz') # optional - pynormaliz
102
+ sage: P.centroid() # optional - pynormaliz
103
+ (5/2, 5/2, 5/2, 5/2)
104
+
105
+ The method is not implemented for unbounded polyhedra::
106
+
107
+ sage: P = Polyhedron(vertices=[(0, 0)], rays=[(1, 0), (0, 1)])
108
+ sage: P.centroid()
109
+ Traceback (most recent call last):
110
+ ...
111
+ NotImplementedError: the polyhedron is not compact
112
+
113
+ The centroid of an empty polyhedron is not defined::
114
+
115
+ sage: Polyhedron().centroid()
116
+ Traceback (most recent call last):
117
+ ...
118
+ ZeroDivisionError: rational division by zero
119
+
120
+ TESTS::
121
+
122
+ sage: Polyhedron(vertices=[[0,1]]).centroid()
123
+ (0, 1)
124
+ """
125
+ if not self.is_compact():
126
+ raise NotImplementedError("the polyhedron is not compact")
127
+ if self.n_vertices() == self.dim() + 1:
128
+ # The centroid of a simplex is its center.
129
+ return self.center()
130
+
131
+ triangulation = self.triangulate(engine=engine, **kwds)
132
+
133
+ if self.ambient_dim() == self.dim():
134
+ pc = triangulation.point_configuration()
135
+ else:
136
+ from sage.geometry.triangulation.point_configuration import PointConfiguration
137
+ A, b = self.affine_hull_projection(as_affine_map=True, orthogonal=True, orthonormal=True, extend=True)
138
+ pc = PointConfiguration(A(v.vector()) for v in self.Vrep_generator())
139
+
140
+ barycenters = [sum(self.Vrepresentation(i).vector() for i in simplex)/(self.dim() + 1) for simplex in triangulation]
141
+ volumes = [pc.volume(simplex) for simplex in triangulation]
142
+
143
+ centroid = sum(volumes[i]*barycenters[i] for i in range(len(volumes)))/sum(volumes)
144
+ if self.ambient_dim() != self.dim():
145
+ # By the affine hull projection, the centroid has base ring ``AA``,
146
+ # we try return the centroid in a reasonable ring.
147
+ try:
148
+ return centroid.change_ring(self.base_ring().fraction_field())
149
+ except ValueError:
150
+ pass
151
+ return centroid
152
+
153
+ def _triangulate_normaliz(self):
154
+ r"""
155
+ Give a triangulation of the polyhedron using normaliz.
156
+
157
+ OUTPUT:
158
+
159
+ A tuple of pairs ``(simplex,simplex_volume)`` used in the
160
+ triangulation.
161
+
162
+ .. NOTE::
163
+
164
+ This function depends on Normaliz (i.e. the ``pynormaliz`` optional
165
+ package). See the Normaliz documentation for further details.
166
+
167
+ TESTS::
168
+
169
+ sage: K = Polyhedron(vertices=[[1,1]], rays=[[1,0],[1,2]])
170
+ sage: K._triangulate_normaliz()
171
+ Traceback (most recent call last):
172
+ ...
173
+ TypeError: the polyhedron's backend should be 'normaliz'
174
+ """
175
+ raise TypeError("the polyhedron's backend should be 'normaliz'")
176
+
177
+ def triangulate(self, engine='auto', connected=True, fine=False, regular=None, star=None):
178
+ r"""
179
+ Return a triangulation of the polytope.
180
+
181
+ INPUT:
182
+
183
+ - ``engine`` -- either 'auto' (default), 'internal',
184
+ 'TOPCOM', or 'normaliz'. The 'internal' and 'TOPCOM' instruct
185
+ this package to always use its own triangulation algorithms
186
+ or TOPCOM's algorithms, respectively. By default ('auto'),
187
+ TOPCOM is used if it is available and internal routines otherwise.
188
+
189
+ The remaining keyword parameters are passed through to the
190
+ :class:`~sage.geometry.triangulation.point_configuration.PointConfiguration`
191
+ constructor:
192
+
193
+ - ``connected`` -- boolean (default: ``True``); whether the
194
+ triangulations should be connected to the regular
195
+ triangulations via bistellar flips. These are much easier to
196
+ compute than all triangulations.
197
+
198
+ - ``fine`` -- boolean (default: ``False``); whether the
199
+ triangulations must be fine, that is, make use of all points
200
+ of the configuration
201
+
202
+ - ``regular`` -- boolean or ``None`` (default:
203
+ ``None``); whether the triangulations must be regular. A
204
+ regular triangulation is one that is induced by a
205
+ piecewise-linear convex support function. In other words,
206
+ the shadows of the faces of a polyhedron in one higher
207
+ dimension.
208
+
209
+ * ``True``: Only regular triangulations.
210
+
211
+ * ``False``: Only non-regular triangulations.
212
+
213
+ * ``None`` (default): Both kinds of triangulation.
214
+
215
+ - ``star`` -- either ``None`` (default) or a point. Whether
216
+ the triangulations must be star. A triangulation is star if
217
+ all maximal simplices contain a common point. The central
218
+ point can be specified by its index (an integer) in the
219
+ given points or by its coordinates (anything iterable.)
220
+
221
+ OUTPUT:
222
+
223
+ A triangulation of the convex hull of the vertices as a
224
+ :class:`~sage.geometry.triangulation.element.Triangulation`. The
225
+ indices in the triangulation correspond to the
226
+ :meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.Vrepresentation` objects.
227
+
228
+ EXAMPLES::
229
+
230
+ sage: cube = polytopes.hypercube(3)
231
+ sage: triangulation = cube.triangulate(
232
+ ....: engine='internal') # to make doctest independent of TOPCOM
233
+ sage: triangulation
234
+ (<0,1,2,7>, <0,1,5,7>, <0,2,3,7>, <0,3,4,7>, <0,4,5,7>, <1,5,6,7>)
235
+ sage: simplex_indices = triangulation[0]; simplex_indices
236
+ (0, 1, 2, 7)
237
+ sage: simplex_vertices = [cube.Vrepresentation(i) for i in simplex_indices]
238
+ sage: simplex_vertices
239
+ [A vertex at (1, -1, -1),
240
+ A vertex at (1, 1, -1),
241
+ A vertex at (1, 1, 1),
242
+ A vertex at (-1, 1, 1)]
243
+ sage: Polyhedron(simplex_vertices)
244
+ A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 4 vertices
245
+
246
+ It is possible to use ``'normaliz'`` as an engine. For this, the
247
+ polyhedron should have the backend set to normaliz::
248
+
249
+ sage: P = Polyhedron(vertices=[[0,0,1], [1,0,1], # optional - pynormaliz
250
+ ....: [0,1,1], [1,1,1]],
251
+ ....: backend='normaliz')
252
+ sage: P.triangulate(engine='normaliz') # optional - pynormaliz
253
+ (<0,1,2>, <1,2,3>)
254
+
255
+ sage: P = Polyhedron(vertices=[[0,0,1], [1,0,1],
256
+ ....: [0,1,1], [1,1,1]])
257
+ sage: P.triangulate(engine='normaliz')
258
+ Traceback (most recent call last):
259
+ ...
260
+ TypeError: the polyhedron's backend should be 'normaliz'
261
+
262
+ The normaliz engine can triangulate pointed cones::
263
+
264
+ sage: # optional - pynormaliz
265
+ sage: C1 = Polyhedron(rays=[[0,0,1], [1,0,1],
266
+ ....: [0,1,1], [1,1,1]],
267
+ ....: backend='normaliz')
268
+ sage: C1.triangulate(engine='normaliz')
269
+ (<0,1,2>, <1,2,3>)
270
+ sage: C2 = Polyhedron(rays=[[1,0,1], [0,0,1],
271
+ ....: [0,1,1], [1,1,10/9]],
272
+ ....: backend='normaliz')
273
+ sage: C2.triangulate(engine='normaliz')
274
+ (<0,1,2>, <1,2,3>)
275
+
276
+ They can also be affine cones::
277
+
278
+ sage: K = Polyhedron(vertices=[[1,1,1]], # optional - pynormaliz
279
+ ....: rays=[[1,0,0], [0,1,0], [1,1,-1], [1,1,1]],
280
+ ....: backend='normaliz')
281
+ sage: K.triangulate(engine='normaliz') # optional - pynormaliz
282
+ (<0,1,2>, <0,1,3>)
283
+ """
284
+ if self.lines():
285
+ raise NotImplementedError('triangulation of polyhedra with lines is not supported')
286
+ if len(self.vertices_list()) >= 2 and self.rays_list():
287
+ raise NotImplementedError('triangulation of non-compact polyhedra that are not cones is not supported')
288
+ if not self.is_compact() and engine != 'normaliz':
289
+ raise NotImplementedError("triangulation of pointed polyhedra requires 'normaliz'")
290
+ from sage.geometry.triangulation.point_configuration import PointConfiguration
291
+ if self.is_compact():
292
+ pc = PointConfiguration((v.vector() for v in self.vertex_generator()),
293
+ connected=connected, fine=fine, regular=regular, star=star)
294
+ # If the engine is not normaliz, we pass directly to the
295
+ # PointConfiguration module.
296
+ if engine != 'normaliz':
297
+ pc.set_engine(engine)
298
+ return pc.triangulate()
299
+ else:
300
+ return pc(self._triangulate_normaliz())
301
+ else: # From above, we have a pointed cone and the engine is normaliz
302
+ try:
303
+ pc = PointConfiguration((v.vector() for v in self.ray_generator()),
304
+ connected=connected, fine=fine, regular=regular, star=star)
305
+ return pc(self._triangulate_normaliz())
306
+ except AssertionError:
307
+ # PointConfiguration is not adapted to inhomogeneous cones
308
+ # This is a hack. TODO: Implement the necessary things in
309
+ # PointConfiguration to accept such cases.
310
+ c = self.representative_point()
311
+ normed_v = ((1/(r.vector()*c))*r.vector() for r in self.ray_generator())
312
+ pc = PointConfiguration(normed_v, connected=connected, fine=fine, regular=regular, star=star)
313
+ return pc(self._triangulate_normaliz())
314
+
315
+ def _volume_lrs(self, verbose=False):
316
+ """
317
+ Compute the volume of a polytope using lrs.
318
+
319
+ OUTPUT: the exact volume as a rational number
320
+
321
+ EXAMPLES::
322
+
323
+ sage: polytopes.hypercube(3)._volume_lrs() # optional - lrslib
324
+ 8
325
+ sage: (polytopes.hypercube(3)*2)._volume_lrs() # optional - lrslib
326
+ 64
327
+ sage: polytopes.twenty_four_cell()._volume_lrs() # optional - lrslib
328
+ 2
329
+
330
+ REFERENCES:
331
+
332
+ - David Avis's lrs program.
333
+ """
334
+ from sage.features.lrs import Lrs
335
+ Lrs().require()
336
+
337
+ from sage.misc.temporary_file import tmp_filename
338
+ from subprocess import Popen, PIPE
339
+
340
+ in_str = self.cdd_Vrepresentation()
341
+ in_str += 'volume'
342
+ in_filename = tmp_filename()
343
+ in_file = open(in_filename, 'w')
344
+ in_file.write(in_str)
345
+ in_file.close()
346
+ if verbose:
347
+ print(in_str)
348
+
349
+ lrs_procs = Popen([Lrs().absolute_filename(), in_filename],
350
+ stdin=PIPE, stdout=PIPE, stderr=PIPE)
351
+ ans, err = lrs_procs.communicate()
352
+ ans = bytes_to_str(ans)
353
+ err = bytes_to_str(err)
354
+ if verbose:
355
+ print(ans)
356
+ # FIXME: check err
357
+
358
+ for a_line in ans.splitlines():
359
+ if 'Volume=' in a_line:
360
+ volume = a_line.split('Volume=')[1]
361
+ volume = QQ(volume)
362
+ return volume
363
+
364
+ raise ValueError("lrs did not return a volume")
365
+
366
+ def _volume_latte(self, verbose=False, algorithm='triangulate', **kwargs):
367
+ """
368
+ Compute the volume of a polytope using LattE integrale.
369
+
370
+ INPUT:
371
+
372
+ - ``arg`` -- a cdd or LattE description string
373
+
374
+ - ``algorithm`` -- (default: ``'triangulate'``) the integration method;
375
+ use 'triangulate' for polytope triangulation or 'cone-decompose' for
376
+ tangent cone decomposition method
377
+
378
+ - ``raw_output`` -- if ``True`` then return directly the output string
379
+ from LattE
380
+
381
+ - ``verbose`` -- if ``True`` then return directly verbose output from
382
+ LattE
383
+
384
+ - For all other options, consult the LattE manual.
385
+
386
+ OUTPUT: a rational value, or a string if ``raw_output`` if set to ``True``
387
+
388
+ .. NOTE::
389
+
390
+ This function depends on LattE (i.e., the ``latte_int`` optional
391
+ package). See the LattE documentation for further details.
392
+
393
+ EXAMPLES::
394
+
395
+ sage: # optional - latte_int
396
+ sage: polytopes.hypercube(3)._volume_latte()
397
+ 8
398
+ sage: (polytopes.hypercube(3)*2)._volume_latte()
399
+ 64
400
+ sage: polytopes.twenty_four_cell()._volume_latte()
401
+ 2
402
+ sage: polytopes.cuboctahedron()._volume_latte()
403
+ 20/3
404
+
405
+ TESTS:
406
+
407
+ Testing triangulate algorithm::
408
+
409
+ sage: polytopes.cuboctahedron()._volume_latte(algorithm='triangulate') # optional - latte_int
410
+ 20/3
411
+
412
+ Testing cone decomposition algorithm::
413
+
414
+ sage: polytopes.cuboctahedron()._volume_latte(algorithm='cone-decompose') # optional - latte_int
415
+ 20/3
416
+
417
+ Testing raw output::
418
+
419
+ sage: polytopes.cuboctahedron()._volume_latte(raw_output=True) # optional - latte_int
420
+ '20/3'
421
+
422
+ Testing inexact rings::
423
+
424
+ sage: # needs cddexec_gmp
425
+ sage: P = Polyhedron(vertices=[[0,0], [1,0], [0,1]], base_ring=RDF)
426
+ sage: P.volume(engine='latte')
427
+ Traceback (most recent call last):
428
+ ...
429
+ ValueError: LattE integrale cannot be applied over inexact rings
430
+ """
431
+ from sage.rings.real_double import RDF
432
+
433
+ if self.base_ring() == RDF:
434
+ raise ValueError("LattE integrale cannot be applied over inexact rings")
435
+ else:
436
+ from sage.interfaces.latte import integrate
437
+
438
+ return integrate(self.cdd_Hrepresentation(), algorithm=algorithm, cdd=True, verbose=verbose, **kwargs)
439
+
440
+ def _volume_normaliz(self, measure='induced'):
441
+ r"""
442
+ Compute the volume of a polytope using normaliz.
443
+
444
+ INPUT:
445
+
446
+ - ``measure`` -- (default: ``'induced'``) the measure to take;
447
+ 'induced' correspond to ``EuclideanVolume`` in normaliz and
448
+ 'induced_lattice' correspond to ``Volume`` in normaliz
449
+
450
+ OUTPUT:
451
+
452
+ A float value (when ``measure`` is 'induced') or a rational number
453
+ (when ``measure`` is 'induced_lattice')
454
+
455
+ .. NOTE::
456
+
457
+ This function depends on Normaliz (i.e., the ``pynormaliz`` optional
458
+ package). See the Normaliz documentation for further details.
459
+
460
+ TESTS::
461
+
462
+ sage: P = Polyhedron(vertices=[[0,0], [1,0], [0,1], [1,1]])
463
+ sage: P._volume_normaliz()
464
+ Traceback (most recent call last):
465
+ ...
466
+ TypeError: the backend should be normaliz
467
+ """
468
+ raise TypeError("the backend should be normaliz")
469
+
470
+ @cached_method(do_pickle=True)
471
+ def volume(self, measure='ambient', engine='auto', **kwds):
472
+ """
473
+ Return the volume of the polytope.
474
+
475
+ INPUT:
476
+
477
+ - ``measure`` -- string. The measure to use. Allowed values are:
478
+
479
+ * ``ambient`` (default): Lebesgue measure of ambient space (volume)
480
+ * ``induced``: Lebesgue measure of the affine hull (relative volume)
481
+ * ``induced_rational``: Scaling of the Lebesgue measure for rational
482
+ polytopes, such that the unit hypercube has volume 1
483
+ * ``induced_lattice``: Scaling of the Lebesgue measure, such that the
484
+ volume of the hypercube is factorial(n)
485
+
486
+ - ``engine`` -- string. The backend to use. Allowed values are:
487
+
488
+ * ``'auto'`` (default): choose engine according to measure
489
+ * ``'internal'``: see :meth:`triangulate`
490
+ * ``'TOPCOM'``: see :meth:`triangulate`
491
+ * ``'lrs'``: use David Avis's lrs program (optional)
492
+ * ``'latte'``: use LattE integrale program (optional)
493
+ * ``'normaliz'``: use Normaliz program (optional)
494
+
495
+ - ``**kwds`` -- keyword arguments that are passed to the
496
+ triangulation engine
497
+
498
+ OUTPUT: the volume of the polytope
499
+
500
+ EXAMPLES::
501
+
502
+ sage: polytopes.hypercube(3).volume()
503
+ 8
504
+ sage: (polytopes.hypercube(3)*2).volume()
505
+ 64
506
+ sage: polytopes.twenty_four_cell().volume()
507
+ 2
508
+
509
+ Volume of the same polytopes, using the optional package lrslib
510
+ (which requires a rational polytope)::
511
+
512
+ sage: I3 = polytopes.hypercube(3)
513
+ sage: I3.volume(engine='lrs') # optional - lrslib
514
+ 8
515
+ sage: C24 = polytopes.twenty_four_cell()
516
+ sage: C24.volume(engine='lrs') # optional - lrslib
517
+ 2
518
+
519
+ If the base ring is exact, the answer is exact::
520
+
521
+ sage: P5 = polytopes.regular_polygon(5) # needs sage.rings.number_field
522
+ sage: P5.volume() # needs sage.rings.number_field
523
+ 2.377641290737884?
524
+
525
+ sage: polytopes.icosahedron().volume() # needs sage.groups sage.rings.number_field
526
+ 5/12*sqrt5 + 5/4
527
+ sage: numerical_approx(_) # abs tol 1e9 # needs sage.groups sage.rings.number_field
528
+ 2.18169499062491
529
+
530
+ When considering lower-dimensional polytopes, we can ask for the
531
+ ambient (full-dimensional), the induced measure (of the affine
532
+ hull) or, in the case of lattice polytopes, for the induced rational measure.
533
+ This is controlled by the parameter ``measure``. Different engines
534
+ may have different ideas on the definition of volume of a
535
+ lower-dimensional object::
536
+
537
+ sage: P = Polyhedron([[0, 0], [1, 1]])
538
+ sage: P.volume()
539
+ 0
540
+ sage: P.volume(measure='induced') # needs sage.rings.number_field
541
+ 1.414213562373095?
542
+ sage: P.volume(measure='induced_rational') # optional - latte_int
543
+ 1
544
+
545
+ sage: # needs sage.rings.number_field
546
+ sage: S = polytopes.regular_polygon(6); S
547
+ A 2-dimensional polyhedron in AA^2 defined as the convex hull of 6 vertices
548
+ sage: edge = S.faces(1)[4].as_polyhedron()
549
+ sage: edge.vertices()
550
+ (A vertex at (0.866025403784439?, 1/2), A vertex at (0, 1))
551
+ sage: edge.volume()
552
+ 0
553
+ sage: edge.volume(measure='induced')
554
+ 1
555
+
556
+ sage: # optional - pynormaliz
557
+ sage: P = Polyhedron(backend='normaliz',
558
+ ....: vertices=[[1,0,0], [0,0,1],
559
+ ....: [-1,1,1], [-1,2,0]])
560
+ sage: P.volume()
561
+ 0
562
+ sage: P.volume(measure='induced') # needs sage.rings.number_field
563
+ 2.598076211353316?
564
+ sage: P.volume(measure='induced', engine='normaliz')
565
+ 2.598076211353316
566
+ sage: P.volume(measure='induced_rational') # optional - latte_int
567
+ 3/2
568
+ sage: P.volume(measure='induced_rational',
569
+ ....: engine='normaliz')
570
+ 3/2
571
+ sage: P.volume(measure='induced_lattice')
572
+ 3
573
+
574
+ The same polytope without normaliz backend::
575
+
576
+ sage: P = Polyhedron(vertices=[[1,0,0], [0,0,1], [-1,1,1], [-1,2,0]])
577
+ sage: P.volume(measure='induced_lattice', engine='latte') # optional - latte_int
578
+ 3
579
+
580
+ sage: # needs sage.groups sage.rings.number_field
581
+ sage: Dexact = polytopes.dodecahedron()
582
+ sage: F0 = Dexact.faces(2)[0].as_polyhedron()
583
+ sage: v = F0.volume(measure='induced', engine='internal'); v
584
+ 1.53406271079097?
585
+ sage: F4 = Dexact.faces(2)[4].as_polyhedron()
586
+ sage: v = F4.volume(measure='induced', engine='internal'); v
587
+ 1.53406271079097?
588
+ sage: RDF(v) # abs tol 1e-9
589
+ 1.53406271079044
590
+
591
+ sage: # needs sage.groups
592
+ sage: Dinexact = polytopes.dodecahedron(exact=False)
593
+ sage: F2 = Dinexact.faces(2)[2].as_polyhedron()
594
+ sage: w = F2.volume(measure='induced', engine='internal')
595
+ sage: RDF(w) # abs tol 1e-9
596
+ 1.5340627082974878
597
+
598
+ sage: all(polytopes.simplex(d).volume(measure='induced') # needs sage.rings.number_field sage.symbolic
599
+ ....: == sqrt(d+1)/factorial(d)
600
+ ....: for d in range(1,5))
601
+ True
602
+
603
+ sage: I = Polyhedron([[-3, 0], [0, 9]])
604
+ sage: I.volume(measure='induced') # needs sage.rings.number_field
605
+ 9.48683298050514?
606
+ sage: I.volume(measure='induced_rational') # optional - latte_int
607
+ 3
608
+
609
+ sage: T = Polyhedron([[3, 0, 0], [0, 4, 0], [0, 0, 5]])
610
+ sage: T.volume(measure='induced') # needs sage.rings.number_field
611
+ 13.86542462386205?
612
+ sage: T.volume(measure='induced_rational') # optional - latte_int
613
+ 1/2
614
+
615
+ sage: Q = Polyhedron(vertices=[(0, 0, 1, 1), (0, 1, 1, 0), (1, 1, 0, 0)])
616
+ sage: Q.volume(measure='induced')
617
+ 1
618
+ sage: Q.volume(measure='induced_rational') # optional - latte_int
619
+ 1/2
620
+
621
+ The volume of a full-dimensional unbounded polyhedron is infinity::
622
+
623
+ sage: P = Polyhedron(vertices=[[1, 0], [0, 1]], rays=[[1, 1]])
624
+ sage: P.volume()
625
+ +Infinity
626
+
627
+ The volume of a non full-dimensional unbounded polyhedron depends on the measure used::
628
+
629
+ sage: P = Polyhedron(ieqs = [[1,1,1], [-1,-1,-1], [3,1,0]]); P
630
+ A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 ray
631
+ sage: P.volume()
632
+ 0
633
+ sage: P.volume(measure='induced')
634
+ +Infinity
635
+ sage: P.volume(measure='ambient')
636
+ 0
637
+ sage: P.volume(measure='induced_rational') # optional - pynormaliz
638
+ +Infinity
639
+ sage: P.volume(measure='induced_rational',engine='latte')
640
+ +Infinity
641
+
642
+ The volume in `0`-dimensional space is taken by counting measure::
643
+
644
+ sage: P = Polyhedron(vertices=[[]]); P
645
+ A 0-dimensional polyhedron in ZZ^0 defined as the convex hull of 1 vertex
646
+ sage: P.volume()
647
+ 1
648
+ sage: P = Polyhedron(vertices=[]); P
649
+ The empty polyhedron in ZZ^0
650
+ sage: P.volume()
651
+ 0
652
+
653
+ TESTS:
654
+
655
+ The cache of the volume is being pickled::
656
+
657
+ sage: P = polytopes.cube()
658
+ sage: P.volume()
659
+ 8
660
+ sage: Q = loads(dumps(P))
661
+ sage: Q.volume.is_in_cache()
662
+ True
663
+
664
+ Induced volumes work with lrs (:issue:`33410`)::
665
+
666
+ sage: P = Polyhedron([[0, 0], [1, 1]])
667
+ sage: P.volume(measure='induced', engine='lrs') # optional - lrslib, needs sage.rings.number_field
668
+ 1.414213562373095?
669
+ """
670
+ from sage.features import FeatureNotPresentError
671
+ if measure == 'induced_rational' and engine not in ['auto', 'latte', 'normaliz']:
672
+ raise RuntimeError("the induced rational measure can only be computed with the engine set to `auto`, `latte`, or `normaliz`")
673
+ if measure == 'induced_lattice' and engine not in ['auto', 'latte', 'normaliz']:
674
+ raise RuntimeError("the induced lattice measure can only be computed with the engine set to `auto`, `latte`, or `normaliz`")
675
+ if engine == 'auto' and measure == 'induced_rational':
676
+ # Enforce a default choice, change if a better engine is found.
677
+ from sage.features.latte import Latte
678
+ try:
679
+ Latte().require()
680
+ engine = 'latte'
681
+ except FeatureNotPresentError:
682
+ from sage.features.normaliz import PyNormaliz
683
+ try:
684
+ PyNormaliz().require()
685
+ engine = 'normaliz'
686
+ except FeatureNotPresentError:
687
+ raise RuntimeError("the induced rational measure can only be computed with the optional packages `latte_int`, or `pynormaliz`")
688
+
689
+ if engine == 'auto' and measure == 'induced_lattice':
690
+ # Enforce a default choice, change if a better engine is found.
691
+ from sage.features.normaliz import PyNormaliz
692
+ try:
693
+ PyNormaliz().require()
694
+ engine = 'normaliz'
695
+ except FeatureNotPresentError:
696
+ try:
697
+ from sage.features.latte import Latte
698
+ Latte().require()
699
+ engine = 'latte'
700
+ except FeatureNotPresentError:
701
+ raise RuntimeError("the induced rational measure can only be computed with the optional packages `latte_int`, or `pynormaliz`")
702
+
703
+ if engine == 'auto' and measure == 'ambient' and self.backend() == 'normaliz':
704
+ engine = 'normaliz'
705
+
706
+ if measure == 'ambient':
707
+ if self.dim() < self.ambient_dim():
708
+ return self.base_ring().zero()
709
+ elif self.dim() == 0:
710
+ return 1
711
+ # if the polyhedron is unbounded, return infinity
712
+ if not self.is_compact():
713
+ from sage.rings.infinity import infinity
714
+ return infinity
715
+ if engine == 'lrs':
716
+ return self._volume_lrs(**kwds)
717
+ elif engine == 'latte':
718
+ return self._volume_latte(**kwds)
719
+ elif engine == 'normaliz':
720
+ return self._volume_normaliz(measure='ambient')
721
+
722
+ triangulation = self.triangulate(engine=engine, **kwds)
723
+ pc = triangulation.point_configuration()
724
+ return sum([pc.volume(simplex) for simplex in triangulation]) / ZZ(self.dim()).factorial()
725
+ elif measure == 'induced':
726
+ # if polyhedron is actually full-dimensional, return volume with ambient measure
727
+ if self.dim() == self.ambient_dim():
728
+ return self.volume(measure='ambient', engine=engine, **kwds)
729
+ # if the polyhedron is unbounded, return infinity
730
+ if not self.is_compact():
731
+ from sage.rings.infinity import infinity
732
+ return infinity
733
+ if engine == 'normaliz':
734
+ return self._volume_normaliz(measure='euclidean')
735
+ # use an orthogonal transformation, which preserves volume up to a factor provided by the transformation matrix
736
+ affine_hull_data = self.affine_hull_projection(orthogonal=True, as_polyhedron=True, as_affine_map=True)
737
+ A = affine_hull_data.projection_linear_map.matrix()
738
+ Adet = (A.transpose() * A).det()
739
+ scaled_volume = affine_hull_data.image.volume(measure='ambient', engine=engine, **kwds)
740
+ if Adet.is_square():
741
+ sqrt_Adet = Adet.sqrt()
742
+ else:
743
+ from sage.rings.qqbar import AA
744
+ sqrt_Adet = AA(Adet).sqrt()
745
+ scaled_volume = AA(scaled_volume)
746
+ return scaled_volume / sqrt_Adet
747
+ elif measure == 'induced_rational':
748
+ # if the polyhedron is unbounded, return infinity
749
+ if not self.is_compact():
750
+ from sage.rings.infinity import infinity
751
+ return infinity
752
+ if engine == 'latte':
753
+ return self._volume_latte(**kwds)
754
+ else: # engine is 'normaliz'
755
+ return self._volume_normaliz(measure='induced_lattice') / ZZ(self.dim()).factorial()
756
+ elif measure == 'induced_lattice':
757
+ # if the polyhedron is unbounded, return infinity
758
+ if not self.is_compact():
759
+ from sage.rings.infinity import infinity
760
+ return infinity
761
+ if engine == 'latte':
762
+ return self._volume_latte(**kwds) * ZZ(self.dim()).factorial()
763
+ else: # engine is 'normaliz'
764
+ return self._volume_normaliz(measure='induced_lattice')
765
+ else:
766
+ raise TypeError("the measure should be `ambient`, `induced`, `induced_rational`, or `induced_lattice`")
767
+
768
+ def integrate(self, function, measure='ambient', **kwds):
769
+ r"""
770
+ Return the integral of ``function`` over this polytope.
771
+
772
+ INPUT:
773
+
774
+ - ``self`` -- Polyhedron
775
+
776
+ - ``function`` -- a multivariate polynomial or
777
+ a valid LattE description string for polynomials
778
+
779
+ - ``measure`` -- string, the measure to use
780
+
781
+ Allowed values are:
782
+
783
+ * ``ambient`` (default): Lebesgue measure of ambient space,
784
+ * ``induced``: Lebesgue measure of the affine hull,
785
+ * ``induced_nonnormalized``: Lebesgue measure of the affine hull
786
+ without the normalization by `\sqrt{\det(A^\top A)}` (with
787
+ `A` being the affine transformation matrix; see :meth:`affine_hull`).
788
+
789
+ - ``**kwds`` -- additional keyword arguments that
790
+ are passed to the engine
791
+
792
+ OUTPUT: the integral of the polynomial over the polytope
793
+
794
+ .. NOTE::
795
+
796
+ The polytope triangulation algorithm is used. This function depends
797
+ on LattE (i.e., the ``latte_int`` optional package).
798
+
799
+ EXAMPLES::
800
+
801
+ sage: P = polytopes.cube()
802
+ sage: x, y, z = polygens(QQ, 'x, y, z')
803
+ sage: P.integrate(x^2*y^2*z^2) # optional - latte_int
804
+ 8/27
805
+
806
+ If the polyhedron has floating point coordinates, an inexact result can
807
+ be obtained if we transform to rational coordinates::
808
+
809
+ sage: # needs cddexec_gmp sage.rings.real_interval_field
810
+ sage: P = 1.4142*polytopes.cube()
811
+ sage: P_QQ = Polyhedron(vertices=[[QQ(vi) for vi in v] for v in P.vertex_generator()])
812
+ sage: RDF(P_QQ.integrate(x^2*y^2*z^2)) # optional - latte_int
813
+ 6.703841212195228
814
+
815
+ Integral over a non full-dimensional polytope::
816
+
817
+ sage: x, y = polygens(QQ, 'x, y')
818
+ sage: P = Polyhedron(vertices=[[0,0], [1,1]])
819
+ sage: P.integrate(x*y)
820
+ 0
821
+ sage: ixy = P.integrate(x*y, measure='induced'); ixy # optional - latte_int, needs sage.rings.number_field sage.symbolic
822
+ 0.4714045207910317?
823
+ sage: ixy.parent() # optional - latte_int, needs sage.rings.number_field sage.symbolic
824
+ Algebraic Real Field
825
+
826
+ Convert to a symbolic expression::
827
+
828
+ sage: ixy.radical_expression() # optional - latte_int, needs sage.rings.number_field sage.symbolic
829
+ 1/3*sqrt(2)
830
+
831
+ Another non full-dimensional polytope integration::
832
+
833
+ sage: R.<x, y, z> = QQ[]
834
+ sage: P = polytopes.simplex(2)
835
+ sage: V = AA(P.volume(measure='induced')) # needs sage.rings.number_field
836
+ sage: V.radical_expression() # needs sage.rings.number_field sage.symbolic
837
+ 1/2*sqrt(3)
838
+ sage: P.integrate(R(1), measure='induced') == V # optional - latte_int, needs sage.rings.number_field sage.symbolic
839
+ True
840
+
841
+ Computing the mass center::
842
+
843
+ sage: (P.integrate(x, measure='induced') # optional - latte_int, needs sage.rings.number_field sage.symbolic
844
+ ....: / V).radical_expression()
845
+ 1/3
846
+ sage: (P.integrate(y, measure='induced') # optional - latte_int, needs sage.rings.number_field sage.symbolic
847
+ ....: / V).radical_expression()
848
+ 1/3
849
+ sage: (P.integrate(z, measure='induced') # optional - latte_int, needs sage.rings.number_field sage.symbolic
850
+ ....: / V).radical_expression()
851
+ 1/3
852
+
853
+ TESTS:
854
+
855
+ Testing a three-dimensional integral::
856
+
857
+ sage: P = polytopes.octahedron()
858
+ sage: x, y, z = polygens(QQ, 'x, y, z')
859
+ sage: P.integrate(2*x^2*y^4*z^6 + z^2) # optional - latte_int
860
+ 630632/4729725
861
+
862
+ Testing a polytope with non-rational vertices::
863
+
864
+ sage: P = polytopes.icosahedron() # needs sage.groups sage.rings.number_field
865
+ sage: P.integrate(x^2*y^2*z^2) # optional - latte_int, needs sage.groups sage.rings.number_field
866
+ Traceback (most recent call last):
867
+ ...
868
+ TypeError: the base ring must be ZZ, QQ, or RDF
869
+
870
+ Testing a univariate polynomial::
871
+
872
+ sage: P = Polyhedron(vertices=[[0], [1]])
873
+ sage: x = polygen(QQ, 'x')
874
+ sage: P.integrate(x) # optional - latte_int
875
+ 1/2
876
+
877
+ Testing a polytope with floating point coordinates::
878
+
879
+ sage: P = Polyhedron(vertices=[[0, 0], [1, 0], [1.1, 1.1], [0, 1]]) # needs cddexec
880
+ sage: P.integrate('[[1,[2,2]]]') # needs cddexec
881
+ Traceback (most recent call last):
882
+ ...
883
+ TypeError: LattE integrale cannot be applied over inexact rings
884
+
885
+ Integration of zero-polynomial::
886
+
887
+ sage: R.<x, y, z> = QQ[]
888
+ sage: P = polytopes.simplex(2)
889
+ sage: P.integrate(R(0))
890
+ 0
891
+ sage: P.integrate('[]') # with LattE description string
892
+ 0
893
+
894
+ ::
895
+
896
+ sage: R.<x, y, z> = QQ[]
897
+ sage: P = Polyhedron(vertices=[(0, 0, 1), (0, 1, 0)])
898
+ sage: P.integrate(x^2)
899
+ 0
900
+ """
901
+ if function == 0 or function == '[]':
902
+ return self.base_ring().zero()
903
+
904
+ if not self.is_compact():
905
+ raise NotImplementedError(
906
+ 'integration over non-compact polyhedra not allowed')
907
+
908
+ if measure == 'ambient':
909
+ if not self.is_full_dimensional():
910
+ return self.base_ring().zero()
911
+
912
+ return self._integrate_latte_(function, **kwds)
913
+
914
+ elif measure == 'induced' or measure == 'induced_nonnormalized':
915
+ # if polyhedron is actually full-dimensional,
916
+ # return with ambient measure
917
+ if self.is_full_dimensional():
918
+ return self.integrate(function, measure='ambient', **kwds)
919
+
920
+ if isinstance(function, str):
921
+ raise NotImplementedError(
922
+ 'LattE description strings for polynomials not allowed '
923
+ 'when using measure="induced"')
924
+
925
+ # use an orthogonal transformation
926
+ affine_hull_data = self.affine_hull_projection(orthogonal=True, return_all_data=True)
927
+ polyhedron = affine_hull_data.image
928
+ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
929
+ R = PolynomialRing(affine_hull_data.section_linear_map.base_ring(), 'x', self.dim())
930
+ coordinate_images = affine_hull_data.section_linear_map.matrix().transpose() * vector(R.gens()) + affine_hull_data.section_translation
931
+
932
+ hom = function.parent().hom(coordinate_images)
933
+ function_in_affine_hull = hom(function)
934
+
935
+ I = polyhedron.integrate(function_in_affine_hull,
936
+ measure='ambient', **kwds)
937
+ if measure == 'induced_nonnormalized':
938
+ return I
939
+ else:
940
+ A = affine_hull_data.projection_linear_map.matrix()
941
+ Adet = (A.transpose() * A).det()
942
+ try:
943
+ from sage.rings.qqbar import AA
944
+ Adet = AA.coerce(Adet)
945
+ except TypeError:
946
+ pass
947
+ return I / Adet.sqrt()
948
+
949
+ else:
950
+ raise ValueError('unknown measure "{}"'.format(measure))
951
+
952
+ def _integrate_latte_(self, polynomial, **kwds):
953
+ r"""
954
+ Return the integral of a polynomial over this polytope by calling LattE.
955
+
956
+ INPUT:
957
+
958
+ - ``polynomial`` -- a multivariate polynomial or
959
+ a valid LattE description string for polynomials
960
+
961
+ - ``**kwds`` -- additional keyword arguments that are passed
962
+ to the engine
963
+
964
+ OUTPUT: the integral of the polynomial over the polytope
965
+
966
+ .. NOTE::
967
+
968
+ The polytope triangulation algorithm is used. This function depends
969
+ on LattE (i.e., the ``latte_int`` optional package).
970
+
971
+ TESTS::
972
+
973
+ sage: P = polytopes.cube()
974
+ sage: x, y, z = polygens(QQ, 'x, y, z')
975
+ sage: P._integrate_latte_(x^2 + y^2*z^2) # optional - latte_int
976
+ 32/9
977
+
978
+ ::
979
+
980
+ sage: R = PolynomialRing(QQ, '', 0)
981
+ sage: Polyhedron(vertices=[()]).integrate(R(42))
982
+ 42
983
+ """
984
+ from sage.rings.real_double import RDF
985
+
986
+ if self.base_ring() == RDF:
987
+ raise TypeError("LattE integrale cannot be applied over inexact rings")
988
+ if self.dimension() == 0:
989
+ vertices = self.vertices()
990
+ assert len(self.vertices()) == 1
991
+ vertex = tuple(vertices[0])
992
+ return polynomial(vertex)
993
+
994
+ from sage.interfaces.latte import integrate
995
+ return integrate(self.cdd_Hrepresentation(),
996
+ polynomial,
997
+ cdd=True, **kwds)