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.
- passagemath_polyhedra-10.6.31rc3.dist-info/METADATA +367 -0
- passagemath_polyhedra-10.6.31rc3.dist-info/METADATA.bak +369 -0
- passagemath_polyhedra-10.6.31rc3.dist-info/RECORD +206 -0
- passagemath_polyhedra-10.6.31rc3.dist-info/WHEEL +6 -0
- passagemath_polyhedra-10.6.31rc3.dist-info/top_level.txt +2 -0
- passagemath_polyhedra.libs/libgmp-6e109695.so.10.5.0 +0 -0
- passagemath_polyhedra.libs/libgomp-e985bcbb.so.1.0.0 +0 -0
- sage/all__sagemath_polyhedra.py +50 -0
- sage/game_theory/all.py +8 -0
- sage/game_theory/catalog.py +6 -0
- sage/game_theory/catalog_normal_form_games.py +923 -0
- sage/game_theory/cooperative_game.py +844 -0
- sage/game_theory/matching_game.py +1181 -0
- sage/game_theory/normal_form_game.py +2697 -0
- sage/game_theory/parser.py +275 -0
- sage/geometry/all__sagemath_polyhedra.py +22 -0
- sage/geometry/cone.py +6940 -0
- sage/geometry/cone_catalog.py +847 -0
- sage/geometry/cone_critical_angles.py +1027 -0
- sage/geometry/convex_set.py +1119 -0
- sage/geometry/fan.py +3743 -0
- sage/geometry/fan_isomorphism.py +389 -0
- sage/geometry/fan_morphism.py +1884 -0
- sage/geometry/hasse_diagram.py +202 -0
- sage/geometry/hyperplane_arrangement/affine_subspace.py +390 -0
- sage/geometry/hyperplane_arrangement/all.py +1 -0
- sage/geometry/hyperplane_arrangement/arrangement.py +3895 -0
- sage/geometry/hyperplane_arrangement/check_freeness.py +145 -0
- sage/geometry/hyperplane_arrangement/hyperplane.py +773 -0
- sage/geometry/hyperplane_arrangement/library.py +825 -0
- sage/geometry/hyperplane_arrangement/ordered_arrangement.py +642 -0
- sage/geometry/hyperplane_arrangement/plot.py +520 -0
- sage/geometry/integral_points.py +35 -0
- sage/geometry/integral_points_generic_dense.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/geometry/integral_points_generic_dense.pyx +7 -0
- sage/geometry/lattice_polytope.py +5894 -0
- sage/geometry/linear_expression.py +773 -0
- sage/geometry/newton_polygon.py +767 -0
- sage/geometry/point_collection.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/geometry/point_collection.pyx +1008 -0
- sage/geometry/polyhedral_complex.py +2616 -0
- sage/geometry/polyhedron/all.py +8 -0
- sage/geometry/polyhedron/backend_cdd.py +460 -0
- sage/geometry/polyhedron/backend_cdd_rdf.py +231 -0
- sage/geometry/polyhedron/backend_field.py +347 -0
- sage/geometry/polyhedron/backend_normaliz.py +2503 -0
- sage/geometry/polyhedron/backend_number_field.py +168 -0
- sage/geometry/polyhedron/backend_polymake.py +765 -0
- sage/geometry/polyhedron/backend_ppl.py +582 -0
- sage/geometry/polyhedron/base.py +1206 -0
- sage/geometry/polyhedron/base0.py +1444 -0
- sage/geometry/polyhedron/base1.py +886 -0
- sage/geometry/polyhedron/base2.py +812 -0
- sage/geometry/polyhedron/base3.py +1845 -0
- sage/geometry/polyhedron/base4.py +1262 -0
- sage/geometry/polyhedron/base5.py +2700 -0
- sage/geometry/polyhedron/base6.py +1741 -0
- sage/geometry/polyhedron/base7.py +997 -0
- sage/geometry/polyhedron/base_QQ.py +1258 -0
- sage/geometry/polyhedron/base_RDF.py +98 -0
- sage/geometry/polyhedron/base_ZZ.py +934 -0
- sage/geometry/polyhedron/base_mutable.py +215 -0
- sage/geometry/polyhedron/base_number_field.py +122 -0
- sage/geometry/polyhedron/cdd_file_format.py +155 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/all.py +1 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/base.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd +76 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +3859 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pxd +39 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx +1038 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/conversions.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pxd +9 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx +501 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_data_structure.pxd +207 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd +102 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +2274 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pxd +370 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pyx +84 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pxd +31 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx +587 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pxd +52 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx +560 -0
- sage/geometry/polyhedron/constructor.py +773 -0
- sage/geometry/polyhedron/double_description.py +753 -0
- sage/geometry/polyhedron/double_description_inhomogeneous.py +564 -0
- sage/geometry/polyhedron/face.py +1060 -0
- sage/geometry/polyhedron/generating_function.py +1810 -0
- sage/geometry/polyhedron/lattice_euclidean_group_element.py +178 -0
- sage/geometry/polyhedron/library.py +3502 -0
- sage/geometry/polyhedron/misc.py +121 -0
- sage/geometry/polyhedron/modules/all.py +1 -0
- sage/geometry/polyhedron/modules/formal_polyhedra_module.py +155 -0
- sage/geometry/polyhedron/palp_database.py +447 -0
- sage/geometry/polyhedron/parent.py +1279 -0
- sage/geometry/polyhedron/plot.py +1986 -0
- sage/geometry/polyhedron/ppl_lattice_polygon.py +556 -0
- sage/geometry/polyhedron/ppl_lattice_polytope.py +1257 -0
- sage/geometry/polyhedron/representation.py +1723 -0
- sage/geometry/pseudolines.py +515 -0
- sage/geometry/relative_interior.py +445 -0
- sage/geometry/toric_plotter.py +1103 -0
- sage/geometry/triangulation/all.py +2 -0
- sage/geometry/triangulation/base.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/geometry/triangulation/base.pyx +963 -0
- sage/geometry/triangulation/data.h +147 -0
- sage/geometry/triangulation/data.pxd +4 -0
- sage/geometry/triangulation/element.py +914 -0
- sage/geometry/triangulation/functions.h +10 -0
- sage/geometry/triangulation/functions.pxd +4 -0
- sage/geometry/triangulation/point_configuration.py +2256 -0
- sage/geometry/triangulation/triangulations.h +49 -0
- sage/geometry/triangulation/triangulations.pxd +7 -0
- sage/geometry/voronoi_diagram.py +319 -0
- sage/interfaces/all__sagemath_polyhedra.py +1 -0
- sage/interfaces/polymake.py +2028 -0
- sage/numerical/all.py +13 -0
- sage/numerical/all__sagemath_polyhedra.py +11 -0
- sage/numerical/backends/all.py +1 -0
- sage/numerical/backends/all__sagemath_polyhedra.py +1 -0
- sage/numerical/backends/cvxopt_backend.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/numerical/backends/cvxopt_backend.pyx +1006 -0
- sage/numerical/backends/cvxopt_backend_test.py +19 -0
- sage/numerical/backends/cvxopt_sdp_backend.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/numerical/backends/cvxopt_sdp_backend.pyx +382 -0
- sage/numerical/backends/cvxpy_backend.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/numerical/backends/cvxpy_backend.pxd +41 -0
- sage/numerical/backends/cvxpy_backend.pyx +934 -0
- sage/numerical/backends/cvxpy_backend_test.py +13 -0
- sage/numerical/backends/generic_backend_test.py +24 -0
- sage/numerical/backends/interactivelp_backend.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/numerical/backends/interactivelp_backend.pxd +36 -0
- sage/numerical/backends/interactivelp_backend.pyx +1231 -0
- sage/numerical/backends/interactivelp_backend_test.py +12 -0
- sage/numerical/backends/logging_backend.py +391 -0
- sage/numerical/backends/matrix_sdp_backend.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/numerical/backends/matrix_sdp_backend.pxd +15 -0
- sage/numerical/backends/matrix_sdp_backend.pyx +478 -0
- sage/numerical/backends/ppl_backend.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/numerical/backends/ppl_backend.pyx +1126 -0
- sage/numerical/backends/ppl_backend_test.py +13 -0
- sage/numerical/backends/scip_backend.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/numerical/backends/scip_backend.pxd +22 -0
- sage/numerical/backends/scip_backend.pyx +1289 -0
- sage/numerical/backends/scip_backend_test.py +13 -0
- sage/numerical/interactive_simplex_method.py +5338 -0
- sage/numerical/knapsack.py +665 -0
- sage/numerical/linear_functions.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/numerical/linear_functions.pxd +31 -0
- sage/numerical/linear_functions.pyx +1648 -0
- sage/numerical/linear_tensor.py +470 -0
- sage/numerical/linear_tensor_constraints.py +448 -0
- sage/numerical/linear_tensor_element.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/numerical/linear_tensor_element.pxd +6 -0
- sage/numerical/linear_tensor_element.pyx +459 -0
- sage/numerical/mip.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/numerical/mip.pxd +40 -0
- sage/numerical/mip.pyx +3667 -0
- sage/numerical/sdp.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/numerical/sdp.pxd +39 -0
- sage/numerical/sdp.pyx +1433 -0
- sage/rings/all__sagemath_polyhedra.py +3 -0
- sage/rings/polynomial/all__sagemath_polyhedra.py +10 -0
- sage/rings/polynomial/omega.py +982 -0
- sage/schemes/all__sagemath_polyhedra.py +2 -0
- sage/schemes/toric/all.py +10 -0
- sage/schemes/toric/chow_group.py +1248 -0
- sage/schemes/toric/divisor.py +2082 -0
- sage/schemes/toric/divisor_class.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/schemes/toric/divisor_class.pyx +322 -0
- sage/schemes/toric/fano_variety.py +1606 -0
- sage/schemes/toric/homset.py +650 -0
- sage/schemes/toric/ideal.py +451 -0
- sage/schemes/toric/library.py +1322 -0
- sage/schemes/toric/morphism.py +1958 -0
- sage/schemes/toric/points.py +1032 -0
- sage/schemes/toric/sheaf/all.py +1 -0
- sage/schemes/toric/sheaf/constructor.py +302 -0
- sage/schemes/toric/sheaf/klyachko.py +921 -0
- sage/schemes/toric/toric_subscheme.py +905 -0
- sage/schemes/toric/variety.py +3460 -0
- sage/schemes/toric/weierstrass.py +1078 -0
- sage/schemes/toric/weierstrass_covering.py +457 -0
- sage/schemes/toric/weierstrass_higher.py +288 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.info +10 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v03 +0 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v04 +0 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v05 +1 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v06 +1 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.info +22 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v04 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v05 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v06 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v07 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v08 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v09 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v10 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v11 +1 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v12 +1 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v13 +1 -0
- sage_wheels/share/reflexive_polytopes/reflexive_polytopes_2d +80 -0
- sage_wheels/share/reflexive_polytopes/reflexive_polytopes_3d +37977 -0
|
@@ -0,0 +1,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)
|