passagemath-polyhedra 10.6.31rc3__cp314-cp314-musllinux_1_2_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-polyhedra might be problematic. Click here for more details.
- passagemath_polyhedra-10.6.31rc3.dist-info/METADATA +367 -0
- passagemath_polyhedra-10.6.31rc3.dist-info/METADATA.bak +369 -0
- passagemath_polyhedra-10.6.31rc3.dist-info/RECORD +208 -0
- passagemath_polyhedra-10.6.31rc3.dist-info/WHEEL +5 -0
- passagemath_polyhedra-10.6.31rc3.dist-info/top_level.txt +2 -0
- passagemath_polyhedra.libs/libgcc_s-0cd532bd.so.1 +0 -0
- passagemath_polyhedra.libs/libgmp-0e7fc84e.so.10.5.0 +0 -0
- passagemath_polyhedra.libs/libgomp-8949ffbe.so.1.0.0 +0 -0
- passagemath_polyhedra.libs/libstdc++-5d72f927.so.6.0.33 +0 -0
- sage/all__sagemath_polyhedra.py +50 -0
- sage/game_theory/all.py +8 -0
- sage/game_theory/catalog.py +6 -0
- sage/game_theory/catalog_normal_form_games.py +923 -0
- sage/game_theory/cooperative_game.py +844 -0
- sage/game_theory/matching_game.py +1181 -0
- sage/game_theory/normal_form_game.py +2697 -0
- sage/game_theory/parser.py +275 -0
- sage/geometry/all__sagemath_polyhedra.py +22 -0
- sage/geometry/cone.py +6940 -0
- sage/geometry/cone_catalog.py +847 -0
- sage/geometry/cone_critical_angles.py +1027 -0
- sage/geometry/convex_set.py +1119 -0
- sage/geometry/fan.py +3743 -0
- sage/geometry/fan_isomorphism.py +389 -0
- sage/geometry/fan_morphism.py +1884 -0
- sage/geometry/hasse_diagram.py +202 -0
- sage/geometry/hyperplane_arrangement/affine_subspace.py +390 -0
- sage/geometry/hyperplane_arrangement/all.py +1 -0
- sage/geometry/hyperplane_arrangement/arrangement.py +3895 -0
- sage/geometry/hyperplane_arrangement/check_freeness.py +145 -0
- sage/geometry/hyperplane_arrangement/hyperplane.py +773 -0
- sage/geometry/hyperplane_arrangement/library.py +825 -0
- sage/geometry/hyperplane_arrangement/ordered_arrangement.py +642 -0
- sage/geometry/hyperplane_arrangement/plot.py +520 -0
- sage/geometry/integral_points.py +35 -0
- sage/geometry/integral_points_generic_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/integral_points_generic_dense.pyx +7 -0
- sage/geometry/lattice_polytope.py +5894 -0
- sage/geometry/linear_expression.py +773 -0
- sage/geometry/newton_polygon.py +767 -0
- sage/geometry/point_collection.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/point_collection.pyx +1008 -0
- sage/geometry/polyhedral_complex.py +2616 -0
- sage/geometry/polyhedron/all.py +8 -0
- sage/geometry/polyhedron/backend_cdd.py +460 -0
- sage/geometry/polyhedron/backend_cdd_rdf.py +231 -0
- sage/geometry/polyhedron/backend_field.py +347 -0
- sage/geometry/polyhedron/backend_normaliz.py +2503 -0
- sage/geometry/polyhedron/backend_number_field.py +168 -0
- sage/geometry/polyhedron/backend_polymake.py +765 -0
- sage/geometry/polyhedron/backend_ppl.py +582 -0
- sage/geometry/polyhedron/base.py +1206 -0
- sage/geometry/polyhedron/base0.py +1444 -0
- sage/geometry/polyhedron/base1.py +886 -0
- sage/geometry/polyhedron/base2.py +812 -0
- sage/geometry/polyhedron/base3.py +1845 -0
- sage/geometry/polyhedron/base4.py +1262 -0
- sage/geometry/polyhedron/base5.py +2700 -0
- sage/geometry/polyhedron/base6.py +1741 -0
- sage/geometry/polyhedron/base7.py +997 -0
- sage/geometry/polyhedron/base_QQ.py +1258 -0
- sage/geometry/polyhedron/base_RDF.py +98 -0
- sage/geometry/polyhedron/base_ZZ.py +934 -0
- sage/geometry/polyhedron/base_mutable.py +215 -0
- sage/geometry/polyhedron/base_number_field.py +122 -0
- sage/geometry/polyhedron/cdd_file_format.py +155 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/all.py +1 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/base.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd +76 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +3859 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pxd +39 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx +1038 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/conversions.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pxd +9 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx +501 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_data_structure.pxd +207 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd +102 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +2274 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pxd +370 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pyx +84 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pxd +31 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx +587 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pxd +52 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx +560 -0
- sage/geometry/polyhedron/constructor.py +773 -0
- sage/geometry/polyhedron/double_description.py +753 -0
- sage/geometry/polyhedron/double_description_inhomogeneous.py +564 -0
- sage/geometry/polyhedron/face.py +1060 -0
- sage/geometry/polyhedron/generating_function.py +1810 -0
- sage/geometry/polyhedron/lattice_euclidean_group_element.py +178 -0
- sage/geometry/polyhedron/library.py +3502 -0
- sage/geometry/polyhedron/misc.py +121 -0
- sage/geometry/polyhedron/modules/all.py +1 -0
- sage/geometry/polyhedron/modules/formal_polyhedra_module.py +155 -0
- sage/geometry/polyhedron/palp_database.py +447 -0
- sage/geometry/polyhedron/parent.py +1279 -0
- sage/geometry/polyhedron/plot.py +1986 -0
- sage/geometry/polyhedron/ppl_lattice_polygon.py +556 -0
- sage/geometry/polyhedron/ppl_lattice_polytope.py +1257 -0
- sage/geometry/polyhedron/representation.py +1723 -0
- sage/geometry/pseudolines.py +515 -0
- sage/geometry/relative_interior.py +445 -0
- sage/geometry/toric_plotter.py +1103 -0
- sage/geometry/triangulation/all.py +2 -0
- sage/geometry/triangulation/base.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/triangulation/base.pyx +963 -0
- sage/geometry/triangulation/data.h +147 -0
- sage/geometry/triangulation/data.pxd +4 -0
- sage/geometry/triangulation/element.py +914 -0
- sage/geometry/triangulation/functions.h +10 -0
- sage/geometry/triangulation/functions.pxd +4 -0
- sage/geometry/triangulation/point_configuration.py +2256 -0
- sage/geometry/triangulation/triangulations.h +49 -0
- sage/geometry/triangulation/triangulations.pxd +7 -0
- sage/geometry/voronoi_diagram.py +319 -0
- sage/interfaces/all__sagemath_polyhedra.py +1 -0
- sage/interfaces/polymake.py +2028 -0
- sage/numerical/all.py +13 -0
- sage/numerical/all__sagemath_polyhedra.py +11 -0
- sage/numerical/backends/all.py +1 -0
- sage/numerical/backends/all__sagemath_polyhedra.py +1 -0
- sage/numerical/backends/cvxopt_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/cvxopt_backend.pyx +1006 -0
- sage/numerical/backends/cvxopt_backend_test.py +19 -0
- sage/numerical/backends/cvxopt_sdp_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/cvxopt_sdp_backend.pyx +382 -0
- sage/numerical/backends/cvxpy_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/cvxpy_backend.pxd +41 -0
- sage/numerical/backends/cvxpy_backend.pyx +934 -0
- sage/numerical/backends/cvxpy_backend_test.py +13 -0
- sage/numerical/backends/generic_backend_test.py +24 -0
- sage/numerical/backends/interactivelp_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/interactivelp_backend.pxd +36 -0
- sage/numerical/backends/interactivelp_backend.pyx +1231 -0
- sage/numerical/backends/interactivelp_backend_test.py +12 -0
- sage/numerical/backends/logging_backend.py +391 -0
- sage/numerical/backends/matrix_sdp_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/matrix_sdp_backend.pxd +15 -0
- sage/numerical/backends/matrix_sdp_backend.pyx +478 -0
- sage/numerical/backends/ppl_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/ppl_backend.pyx +1126 -0
- sage/numerical/backends/ppl_backend_test.py +13 -0
- sage/numerical/backends/scip_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/scip_backend.pxd +22 -0
- sage/numerical/backends/scip_backend.pyx +1289 -0
- sage/numerical/backends/scip_backend_test.py +13 -0
- sage/numerical/interactive_simplex_method.py +5338 -0
- sage/numerical/knapsack.py +665 -0
- sage/numerical/linear_functions.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/linear_functions.pxd +31 -0
- sage/numerical/linear_functions.pyx +1648 -0
- sage/numerical/linear_tensor.py +470 -0
- sage/numerical/linear_tensor_constraints.py +448 -0
- sage/numerical/linear_tensor_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/linear_tensor_element.pxd +6 -0
- sage/numerical/linear_tensor_element.pyx +459 -0
- sage/numerical/mip.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/mip.pxd +40 -0
- sage/numerical/mip.pyx +3667 -0
- sage/numerical/sdp.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/sdp.pxd +39 -0
- sage/numerical/sdp.pyx +1433 -0
- sage/rings/all__sagemath_polyhedra.py +3 -0
- sage/rings/polynomial/all__sagemath_polyhedra.py +10 -0
- sage/rings/polynomial/omega.py +982 -0
- sage/schemes/all__sagemath_polyhedra.py +2 -0
- sage/schemes/toric/all.py +10 -0
- sage/schemes/toric/chow_group.py +1248 -0
- sage/schemes/toric/divisor.py +2082 -0
- sage/schemes/toric/divisor_class.cpython-314-x86_64-linux-musl.so +0 -0
- sage/schemes/toric/divisor_class.pyx +322 -0
- sage/schemes/toric/fano_variety.py +1606 -0
- sage/schemes/toric/homset.py +650 -0
- sage/schemes/toric/ideal.py +451 -0
- sage/schemes/toric/library.py +1322 -0
- sage/schemes/toric/morphism.py +1958 -0
- sage/schemes/toric/points.py +1032 -0
- sage/schemes/toric/sheaf/all.py +1 -0
- sage/schemes/toric/sheaf/constructor.py +302 -0
- sage/schemes/toric/sheaf/klyachko.py +921 -0
- sage/schemes/toric/toric_subscheme.py +905 -0
- sage/schemes/toric/variety.py +3460 -0
- sage/schemes/toric/weierstrass.py +1078 -0
- sage/schemes/toric/weierstrass_covering.py +457 -0
- sage/schemes/toric/weierstrass_higher.py +288 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.info +10 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v03 +0 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v04 +0 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v05 +1 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v06 +1 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.info +22 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v04 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v05 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v06 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v07 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v08 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v09 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v10 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v11 +1 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v12 +1 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v13 +1 -0
- sage_wheels/share/reflexive_polytopes/reflexive_polytopes_2d +80 -0
- sage_wheels/share/reflexive_polytopes/reflexive_polytopes_3d +37977 -0
|
@@ -0,0 +1,812 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-polyhedra
|
|
2
|
+
r"""
|
|
3
|
+
Base class for polyhedra: Methods related to lattice points
|
|
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
|
+
import itertools
|
|
35
|
+
|
|
36
|
+
from sage.misc.cachefunc import cached_method
|
|
37
|
+
from sage.rings.integer_ring import ZZ
|
|
38
|
+
from sage.modules.free_module_element import vector
|
|
39
|
+
from .base1 import Polyhedron_base1
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class Polyhedron_base2(Polyhedron_base1):
|
|
43
|
+
"""
|
|
44
|
+
Methods related to lattice points.
|
|
45
|
+
|
|
46
|
+
See :class:`sage.geometry.polyhedron.base.Polyhedron_base`.
|
|
47
|
+
|
|
48
|
+
TESTS::
|
|
49
|
+
|
|
50
|
+
sage: from sage.geometry.polyhedron.base2 import Polyhedron_base2
|
|
51
|
+
sage: P = polytopes.cube()
|
|
52
|
+
sage: Polyhedron_base2.is_lattice_polytope.f(P)
|
|
53
|
+
True
|
|
54
|
+
sage: Polyhedron_base2.lattice_polytope(P)
|
|
55
|
+
3-d reflexive polytope in 3-d lattice M
|
|
56
|
+
sage: Polyhedron_base2.integral_points(P)
|
|
57
|
+
((-1, -1, -1),
|
|
58
|
+
(-1, -1, 0),
|
|
59
|
+
(-1, -1, 1),
|
|
60
|
+
(-1, 0, -1),
|
|
61
|
+
(-1, 0, 0),
|
|
62
|
+
(-1, 0, 1),
|
|
63
|
+
(-1, 1, -1),
|
|
64
|
+
(-1, 1, 0),
|
|
65
|
+
(-1, 1, 1),
|
|
66
|
+
(0, -1, -1),
|
|
67
|
+
(0, -1, 0),
|
|
68
|
+
(0, -1, 1),
|
|
69
|
+
(0, 0, -1),
|
|
70
|
+
(0, 0, 0),
|
|
71
|
+
(0, 0, 1),
|
|
72
|
+
(0, 1, -1),
|
|
73
|
+
(0, 1, 0),
|
|
74
|
+
(0, 1, 1),
|
|
75
|
+
(1, -1, -1),
|
|
76
|
+
(1, -1, 0),
|
|
77
|
+
(1, -1, 1),
|
|
78
|
+
(1, 0, -1),
|
|
79
|
+
(1, 0, 0),
|
|
80
|
+
(1, 0, 1),
|
|
81
|
+
(1, 1, -1),
|
|
82
|
+
(1, 1, 0),
|
|
83
|
+
(1, 1, 1))
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
@cached_method
|
|
87
|
+
def is_lattice_polytope(self):
|
|
88
|
+
r"""
|
|
89
|
+
Return whether the polyhedron is a lattice polytope.
|
|
90
|
+
|
|
91
|
+
OUTPUT:
|
|
92
|
+
|
|
93
|
+
``True`` if the polyhedron is compact and has only integral
|
|
94
|
+
vertices, ``False`` otherwise.
|
|
95
|
+
|
|
96
|
+
EXAMPLES::
|
|
97
|
+
|
|
98
|
+
sage: polytopes.cross_polytope(3).is_lattice_polytope()
|
|
99
|
+
True
|
|
100
|
+
sage: polytopes.regular_polygon(5).is_lattice_polytope() # needs sage.rings.number_field
|
|
101
|
+
False
|
|
102
|
+
"""
|
|
103
|
+
if not self.is_compact():
|
|
104
|
+
return False
|
|
105
|
+
if self.base_ring() is ZZ:
|
|
106
|
+
return True
|
|
107
|
+
return all(v.is_integral() for v in self.vertex_generator())
|
|
108
|
+
|
|
109
|
+
@cached_method
|
|
110
|
+
def lattice_polytope(self, envelope=False):
|
|
111
|
+
r"""
|
|
112
|
+
Return an encompassing lattice polytope.
|
|
113
|
+
|
|
114
|
+
INPUT:
|
|
115
|
+
|
|
116
|
+
- ``envelope`` -- boolean (default: ``False``); if the
|
|
117
|
+
polyhedron has non-integral vertices, this option decides
|
|
118
|
+
whether to return a strictly larger lattice polytope or
|
|
119
|
+
raise a :exc:`ValueError`. This option has no effect if the
|
|
120
|
+
polyhedron has already integral vertices.
|
|
121
|
+
|
|
122
|
+
OUTPUT:
|
|
123
|
+
|
|
124
|
+
A :class:`LatticePolytope
|
|
125
|
+
<sage.geometry.lattice_polytope.LatticePolytopeClass>`. If the
|
|
126
|
+
polyhedron is compact and has integral vertices, the lattice
|
|
127
|
+
polytope equals the polyhedron. If the polyhedron is compact
|
|
128
|
+
but has at least one non-integral vertex, a strictly larger
|
|
129
|
+
lattice polytope is returned.
|
|
130
|
+
|
|
131
|
+
If the polyhedron is not compact, a :exc:`NotImplementedError` is
|
|
132
|
+
raised.
|
|
133
|
+
|
|
134
|
+
If the polyhedron is not integral and ``envelope=False``, a
|
|
135
|
+
:exc:`ValueError` is raised.
|
|
136
|
+
|
|
137
|
+
ALGORITHM:
|
|
138
|
+
|
|
139
|
+
For each non-integral vertex, a bounding box of integral
|
|
140
|
+
points is added and the convex hull of these integral points
|
|
141
|
+
is returned.
|
|
142
|
+
|
|
143
|
+
EXAMPLES:
|
|
144
|
+
|
|
145
|
+
First, a polyhedron with integral vertices::
|
|
146
|
+
|
|
147
|
+
sage: P = Polyhedron(vertices=[(1, 0), (0, 1), (-1, 0), (0, -1)])
|
|
148
|
+
sage: lp = P.lattice_polytope(); lp
|
|
149
|
+
2-d reflexive polytope... in 2-d lattice M
|
|
150
|
+
sage: lp # optional - polytopes_db, needs palp sage.groups
|
|
151
|
+
2-d reflexive polytope #3 in 2-d lattice M
|
|
152
|
+
sage: lp.vertices()
|
|
153
|
+
M(-1, 0),
|
|
154
|
+
M( 0, -1),
|
|
155
|
+
M( 0, 1),
|
|
156
|
+
M( 1, 0)
|
|
157
|
+
in 2-d lattice M
|
|
158
|
+
|
|
159
|
+
Here is a polyhedron with non-integral vertices::
|
|
160
|
+
|
|
161
|
+
sage: P = Polyhedron( vertices = [(1/2, 1/2), (0, 1), (-1, 0), (0, -1)])
|
|
162
|
+
sage: lp = P.lattice_polytope()
|
|
163
|
+
Traceback (most recent call last):
|
|
164
|
+
...
|
|
165
|
+
ValueError: Some vertices are not integral. You probably want
|
|
166
|
+
to add the argument "envelope=True" to compute an enveloping
|
|
167
|
+
lattice polytope.
|
|
168
|
+
sage: lp = P.lattice_polytope(True)
|
|
169
|
+
sage: lp # optional - polytopes_db, needs palp sage.groups
|
|
170
|
+
2-d reflexive polytope #5 in 2-d lattice M
|
|
171
|
+
sage: lp.vertices()
|
|
172
|
+
M(-1, 0),
|
|
173
|
+
M( 0, -1),
|
|
174
|
+
M( 1, 1),
|
|
175
|
+
M( 0, 1),
|
|
176
|
+
M( 1, 0)
|
|
177
|
+
in 2-d lattice M
|
|
178
|
+
"""
|
|
179
|
+
if not self.is_compact():
|
|
180
|
+
raise NotImplementedError('only compact lattice polytopes are allowed')
|
|
181
|
+
|
|
182
|
+
try:
|
|
183
|
+
vertices = self.vertices_matrix(ZZ).columns()
|
|
184
|
+
except TypeError:
|
|
185
|
+
if not envelope:
|
|
186
|
+
raise ValueError('Some vertices are not integral. '
|
|
187
|
+
'You probably want to add the argument '
|
|
188
|
+
'"envelope=True" to compute an enveloping lattice polytope.')
|
|
189
|
+
from sage.arith.misc import integer_ceil as ceil
|
|
190
|
+
from sage.arith.misc import integer_floor as floor
|
|
191
|
+
vertices = []
|
|
192
|
+
for v in self.vertex_generator():
|
|
193
|
+
vbox = [ set([floor(x), ceil(x)]) for x in v ]
|
|
194
|
+
vertices.extend( itertools.product(*vbox) )
|
|
195
|
+
|
|
196
|
+
# construct the (enveloping) lattice polytope
|
|
197
|
+
from sage.geometry.lattice_polytope import LatticePolytope
|
|
198
|
+
return LatticePolytope(vertices)
|
|
199
|
+
|
|
200
|
+
def _integral_points_PALP(self):
|
|
201
|
+
r"""
|
|
202
|
+
Return the integral points in the polyhedron using PALP.
|
|
203
|
+
|
|
204
|
+
This method is for testing purposes and will eventually be removed.
|
|
205
|
+
|
|
206
|
+
OUTPUT:
|
|
207
|
+
|
|
208
|
+
The list of integral points in the polyhedron. If the
|
|
209
|
+
polyhedron is not compact, a :exc:`ValueError` is raised.
|
|
210
|
+
|
|
211
|
+
EXAMPLES::
|
|
212
|
+
|
|
213
|
+
sage: Polyhedron(vertices=[(-1,-1),(1,0),(1,1),(0,1)])._integral_points_PALP() # needs palp
|
|
214
|
+
[M(-1, -1), M(0, 1), M(1, 0), M(1, 1), M(0, 0)]
|
|
215
|
+
sage: Polyhedron(vertices=[(-1/2,-1/2),(1,0),(1,1),(0,1)]).lattice_polytope(True).points() # needs palp
|
|
216
|
+
M(-1, -1),
|
|
217
|
+
M(-1, 0),
|
|
218
|
+
M( 0, -1),
|
|
219
|
+
M( 1, 1),
|
|
220
|
+
M( 0, 1),
|
|
221
|
+
M( 1, 0),
|
|
222
|
+
M( 0, 0)
|
|
223
|
+
in 2-d lattice M
|
|
224
|
+
sage: Polyhedron(vertices=[(-1/2,-1/2),(1,0),(1,1),(0,1)])._integral_points_PALP() # needs palp
|
|
225
|
+
[M(1, 1), M(0, 1), M(1, 0), M(0, 0)]
|
|
226
|
+
"""
|
|
227
|
+
if not self.is_compact():
|
|
228
|
+
raise ValueError('can only enumerate points in a compact polyhedron')
|
|
229
|
+
lp = self.lattice_polytope(True)
|
|
230
|
+
# remove cached values to get accurate timings
|
|
231
|
+
try:
|
|
232
|
+
del lp._points
|
|
233
|
+
del lp._npoints
|
|
234
|
+
except AttributeError:
|
|
235
|
+
pass
|
|
236
|
+
if self.is_lattice_polytope():
|
|
237
|
+
return list(lp.points())
|
|
238
|
+
return [p for p in lp.points() if self.contains(p)]
|
|
239
|
+
|
|
240
|
+
@cached_method(do_pickle=True)
|
|
241
|
+
def h_star_vector(self):
|
|
242
|
+
r"""
|
|
243
|
+
Return the `h^*`-vector of the lattice polytope.
|
|
244
|
+
|
|
245
|
+
The `h^*`-vector records the coefficients of the polynomial in the
|
|
246
|
+
numerator of the Ehrhart series of a lattice polytope.
|
|
247
|
+
|
|
248
|
+
INPUT:
|
|
249
|
+
|
|
250
|
+
- ``self`` -- a lattice polytope
|
|
251
|
+
|
|
252
|
+
OUTPUT:
|
|
253
|
+
|
|
254
|
+
A list whose entries give the `h^*`-vector.
|
|
255
|
+
|
|
256
|
+
.. NOTE::
|
|
257
|
+
|
|
258
|
+
The backend of ``self`` should be ``'normaliz'``.
|
|
259
|
+
This function depends on Normaliz (i.e. the ``'pynormaliz'`` optional
|
|
260
|
+
package). See the Normaliz documentation for further details.
|
|
261
|
+
|
|
262
|
+
EXAMPLES:
|
|
263
|
+
|
|
264
|
+
The `h^*`-vector of a unimodular simplex S (a simplex with
|
|
265
|
+
volume = `\frac{1}{dim(S)!}`) is always 1. Here we test this on
|
|
266
|
+
simplices up to dimension 3::
|
|
267
|
+
|
|
268
|
+
sage: # optional - pynormaliz
|
|
269
|
+
sage: s1 = polytopes.simplex(1,backend='normaliz')
|
|
270
|
+
sage: s2 = polytopes.simplex(2,backend='normaliz')
|
|
271
|
+
sage: s3 = polytopes.simplex(3,backend='normaliz')
|
|
272
|
+
sage: [s1.h_star_vector(), s2.h_star_vector(), s3.h_star_vector()]
|
|
273
|
+
[[1], [1], [1]]
|
|
274
|
+
|
|
275
|
+
For a less trivial example, we compute the `h^*`-vector of the
|
|
276
|
+
`0/1`-cube, which has the Eulerian numbers `(3,i)` for `i \in [0,2]`
|
|
277
|
+
as an `h^*`-vector::
|
|
278
|
+
|
|
279
|
+
sage: cube = polytopes.cube(intervals='zero_one', backend='normaliz') # optional - pynormaliz
|
|
280
|
+
sage: cube.h_star_vector() # optional - pynormaliz
|
|
281
|
+
[1, 4, 1]
|
|
282
|
+
sage: from sage.combinat.combinat import eulerian_number
|
|
283
|
+
sage: [eulerian_number(3,i) for i in range(3)]
|
|
284
|
+
[1, 4, 1]
|
|
285
|
+
|
|
286
|
+
TESTS::
|
|
287
|
+
|
|
288
|
+
sage: s3 = polytopes.simplex(3)
|
|
289
|
+
sage: s3.h_star_vector()
|
|
290
|
+
Traceback (most recent call last):
|
|
291
|
+
...
|
|
292
|
+
TypeError: The backend of self must be normaliz
|
|
293
|
+
|
|
294
|
+
sage: t = Polyhedron(vertices=[[0],[1/2]])
|
|
295
|
+
sage: t.h_star_vector()
|
|
296
|
+
Traceback (most recent call last):
|
|
297
|
+
...
|
|
298
|
+
TypeError: The h_star vector is only defined for lattice polytopes
|
|
299
|
+
|
|
300
|
+
sage: t2 = Polyhedron(vertices=[[AA(sqrt(2))], [1/2]]) # needs sage.rings.number_field sage.symbolic
|
|
301
|
+
sage: t2.h_star_vector() # needs sage.rings.number_field sage.symbolic
|
|
302
|
+
Traceback (most recent call last):
|
|
303
|
+
...
|
|
304
|
+
TypeError: The h_star vector is only defined for lattice polytopes
|
|
305
|
+
|
|
306
|
+
Check that the `h^*`-vector is pickled::
|
|
307
|
+
|
|
308
|
+
sage: new_cube = loads(dumps(cube)) # optional - pynormaliz
|
|
309
|
+
sage: new_cube.h_star_vector.is_in_cache() # optional - pynormaliz
|
|
310
|
+
True
|
|
311
|
+
"""
|
|
312
|
+
if self.is_empty():
|
|
313
|
+
return 0
|
|
314
|
+
if not self.is_lattice_polytope():
|
|
315
|
+
raise TypeError('The h_star vector is only defined for lattice polytopes')
|
|
316
|
+
if not self.backend() == 'normaliz':
|
|
317
|
+
raise TypeError('The backend of self must be normaliz')
|
|
318
|
+
return self._h_star_vector_normaliz()
|
|
319
|
+
|
|
320
|
+
def _h_star_vector_normaliz(self):
|
|
321
|
+
r"""
|
|
322
|
+
Return the `h^*`-vector of a lattice polytope with backend = 'normaliz'.
|
|
323
|
+
|
|
324
|
+
INPUT:
|
|
325
|
+
|
|
326
|
+
- ``self`` -- a lattice polytope
|
|
327
|
+
|
|
328
|
+
OUTPUT:
|
|
329
|
+
|
|
330
|
+
The `h^*`-vector as a list.
|
|
331
|
+
|
|
332
|
+
.. NOTE::
|
|
333
|
+
|
|
334
|
+
The backend of ``self`` should be ``'normaliz'``.
|
|
335
|
+
|
|
336
|
+
TESTS::
|
|
337
|
+
|
|
338
|
+
sage: s3 = polytopes.simplex(3)
|
|
339
|
+
sage: s3._h_star_vector_normaliz()
|
|
340
|
+
Traceback (most recent call last):
|
|
341
|
+
...
|
|
342
|
+
TypeError: the backend should be normaliz
|
|
343
|
+
"""
|
|
344
|
+
raise TypeError("the backend should be normaliz")
|
|
345
|
+
|
|
346
|
+
def integral_points_count(self, **kwds):
|
|
347
|
+
r"""
|
|
348
|
+
Return the number of integral points in the polyhedron.
|
|
349
|
+
|
|
350
|
+
This generic version of this method simply calls :meth:`integral_points`.
|
|
351
|
+
|
|
352
|
+
EXAMPLES::
|
|
353
|
+
|
|
354
|
+
sage: P = polytopes.cube()
|
|
355
|
+
sage: P.integral_points_count()
|
|
356
|
+
27
|
|
357
|
+
|
|
358
|
+
We shrink the polyhedron a little bit::
|
|
359
|
+
|
|
360
|
+
sage: Q = P*(8/9)
|
|
361
|
+
sage: Q.integral_points_count()
|
|
362
|
+
1
|
|
363
|
+
|
|
364
|
+
Same for a polyhedron whose coordinates are not rationals. Note that
|
|
365
|
+
the answer is an integer even though there are no guarantees for
|
|
366
|
+
exactness::
|
|
367
|
+
|
|
368
|
+
sage: Q = P*RDF(8/9) # needs cddexec_gmp
|
|
369
|
+
sage: Q.integral_points_count() # needs cddexec_gmp
|
|
370
|
+
1
|
|
371
|
+
|
|
372
|
+
Unbounded polyhedra (with or without lattice points) are not supported::
|
|
373
|
+
|
|
374
|
+
sage: P = Polyhedron(vertices=[[1/2, 1/3]], rays=[[1, 1]])
|
|
375
|
+
sage: P.integral_points_count()
|
|
376
|
+
Traceback (most recent call last):
|
|
377
|
+
...
|
|
378
|
+
NotImplementedError: ...
|
|
379
|
+
sage: P = Polyhedron(vertices=[[1, 1]], rays=[[1, 1]])
|
|
380
|
+
sage: P.integral_points_count()
|
|
381
|
+
Traceback (most recent call last):
|
|
382
|
+
...
|
|
383
|
+
NotImplementedError: ...
|
|
384
|
+
"""
|
|
385
|
+
return len(self.integral_points())
|
|
386
|
+
|
|
387
|
+
def integral_points(self, threshold=100000):
|
|
388
|
+
r"""
|
|
389
|
+
Return the integral points in the polyhedron.
|
|
390
|
+
|
|
391
|
+
Uses either the naive algorithm (iterate over a rectangular
|
|
392
|
+
bounding box) or triangulation + Smith form.
|
|
393
|
+
|
|
394
|
+
INPUT:
|
|
395
|
+
|
|
396
|
+
- ``threshold`` -- integer (default: 100000); use the naive
|
|
397
|
+
algorithm as long as the bounding box is smaller than this
|
|
398
|
+
|
|
399
|
+
OUTPUT:
|
|
400
|
+
|
|
401
|
+
The list of integral points in the polyhedron. If the
|
|
402
|
+
polyhedron is not compact, a :exc:`ValueError` is raised.
|
|
403
|
+
|
|
404
|
+
EXAMPLES::
|
|
405
|
+
|
|
406
|
+
sage: Polyhedron(vertices=[(-1,-1),(1,0),(1,1),(0,1)]).integral_points()
|
|
407
|
+
((-1, -1), (0, 0), (0, 1), (1, 0), (1, 1))
|
|
408
|
+
|
|
409
|
+
sage: simplex = Polyhedron([(1,2,3), (2,3,7), (-2,-3,-11)])
|
|
410
|
+
sage: simplex.integral_points()
|
|
411
|
+
((-2, -3, -11), (0, 0, -2), (1, 2, 3), (2, 3, 7))
|
|
412
|
+
|
|
413
|
+
The polyhedron need not be full-dimensional::
|
|
414
|
+
|
|
415
|
+
sage: simplex = Polyhedron([(1,2,3,5), (2,3,7,5), (-2,-3,-11,5)])
|
|
416
|
+
sage: simplex.integral_points()
|
|
417
|
+
((-2, -3, -11, 5), (0, 0, -2, 5), (1, 2, 3, 5), (2, 3, 7, 5))
|
|
418
|
+
|
|
419
|
+
sage: point = Polyhedron([(2,3,7)])
|
|
420
|
+
sage: point.integral_points()
|
|
421
|
+
((2, 3, 7),)
|
|
422
|
+
|
|
423
|
+
sage: empty = Polyhedron()
|
|
424
|
+
sage: empty.integral_points()
|
|
425
|
+
()
|
|
426
|
+
|
|
427
|
+
Here is a simplex where the naive algorithm of running over
|
|
428
|
+
all points in a rectangular bounding box no longer works fast
|
|
429
|
+
enough::
|
|
430
|
+
|
|
431
|
+
sage: v = [(1,0,7,-1), (-2,-2,4,-3), (-1,-1,-1,4), (2,9,0,-5), (-2,-1,5,1)]
|
|
432
|
+
sage: simplex = Polyhedron(v); simplex
|
|
433
|
+
A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 5 vertices
|
|
434
|
+
sage: len(simplex.integral_points())
|
|
435
|
+
49
|
|
436
|
+
|
|
437
|
+
A case where rounding in the right direction goes a long way::
|
|
438
|
+
|
|
439
|
+
sage: P = 1/10*polytopes.hypercube(14, backend='field')
|
|
440
|
+
sage: P.integral_points()
|
|
441
|
+
((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),)
|
|
442
|
+
|
|
443
|
+
Finally, the 3-d reflexive polytope number 4078::
|
|
444
|
+
|
|
445
|
+
sage: v = [(1,0,0), (0,1,0), (0,0,1), (0,0,-1), (0,-2,1),
|
|
446
|
+
....: (-1,2,-1), (-1,2,-2), (-1,1,-2), (-1,-1,2), (-1,-3,2)]
|
|
447
|
+
sage: P = Polyhedron(v)
|
|
448
|
+
sage: pts1 = P.integral_points() # Sage's own code
|
|
449
|
+
sage: all(P.contains(p) for p in pts1)
|
|
450
|
+
True
|
|
451
|
+
sage: pts2 = LatticePolytope(v).points() # needs palp
|
|
452
|
+
sage: for p in pts1: p.set_immutable()
|
|
453
|
+
sage: set(pts1) == set(pts2) # needs palp
|
|
454
|
+
True
|
|
455
|
+
|
|
456
|
+
sage: timeit('Polyhedron(v).integral_points()') # not tested - random
|
|
457
|
+
625 loops, best of 3: 1.41 ms per loop
|
|
458
|
+
sage: timeit('LatticePolytope(v).points()') # not tested - random
|
|
459
|
+
25 loops, best of 3: 17.2 ms per loop
|
|
460
|
+
|
|
461
|
+
TESTS:
|
|
462
|
+
|
|
463
|
+
Test some trivial cases (see :issue:`17937`)::
|
|
464
|
+
|
|
465
|
+
sage: P = Polyhedron(ambient_dim=1) # empty polyhedron in 1 dimension
|
|
466
|
+
sage: P.integral_points()
|
|
467
|
+
()
|
|
468
|
+
sage: P = Polyhedron(ambient_dim=0) # empty polyhedron in 0 dimensions
|
|
469
|
+
sage: P.integral_points()
|
|
470
|
+
()
|
|
471
|
+
sage: P = Polyhedron([[3]]) # single point in 1 dimension
|
|
472
|
+
sage: P.integral_points()
|
|
473
|
+
((3),)
|
|
474
|
+
sage: P = Polyhedron([[1/2]]) # single non-integral point in 1 dimension
|
|
475
|
+
sage: P.integral_points()
|
|
476
|
+
()
|
|
477
|
+
sage: P = Polyhedron([[]]) # single point in 0 dimensions
|
|
478
|
+
sage: P.integral_points()
|
|
479
|
+
((),)
|
|
480
|
+
|
|
481
|
+
Test unbounded polyhedron::
|
|
482
|
+
|
|
483
|
+
sage: P = Polyhedron(rays=[[1,0,0]])
|
|
484
|
+
sage: P.integral_points()
|
|
485
|
+
Traceback (most recent call last):
|
|
486
|
+
...
|
|
487
|
+
ValueError: can only enumerate points in a compact polyhedron
|
|
488
|
+
"""
|
|
489
|
+
from sage.misc.misc_c import prod
|
|
490
|
+
if not self.is_compact():
|
|
491
|
+
raise ValueError('can only enumerate points in a compact polyhedron')
|
|
492
|
+
# Trivial cases: polyhedron with 0 or 1 vertices
|
|
493
|
+
if self.n_vertices() == 0:
|
|
494
|
+
return ()
|
|
495
|
+
if self.n_vertices() == 1:
|
|
496
|
+
v = self.vertices_list()[0]
|
|
497
|
+
try:
|
|
498
|
+
return (vector(ZZ, v),)
|
|
499
|
+
except TypeError: # vertex not integral
|
|
500
|
+
return ()
|
|
501
|
+
|
|
502
|
+
# for small bounding boxes, it is faster to naively iterate over the points of the box
|
|
503
|
+
box_min, box_max = self.bounding_box(integral_hull=True)
|
|
504
|
+
if box_min is None:
|
|
505
|
+
return ()
|
|
506
|
+
box_points = prod(max_coord-min_coord+1 for min_coord, max_coord in zip(box_min, box_max))
|
|
507
|
+
if not self.is_lattice_polytope() or \
|
|
508
|
+
(self.is_simplex() and box_points < 1000) or \
|
|
509
|
+
box_points < threshold:
|
|
510
|
+
from sage.geometry.integral_points import rectangular_box_points
|
|
511
|
+
return rectangular_box_points(list(box_min), list(box_max), self)
|
|
512
|
+
|
|
513
|
+
# for more complicate polytopes, triangulate & use smith normal form
|
|
514
|
+
from sage.geometry.integral_points import simplex_points
|
|
515
|
+
if self.is_simplex():
|
|
516
|
+
return simplex_points(self.Vrepresentation())
|
|
517
|
+
triangulation = self.triangulate()
|
|
518
|
+
points = set()
|
|
519
|
+
for simplex in triangulation:
|
|
520
|
+
triang_vertices = [self.Vrepresentation(i) for i in simplex]
|
|
521
|
+
new_points = simplex_points(triang_vertices)
|
|
522
|
+
for p in new_points:
|
|
523
|
+
p.set_immutable()
|
|
524
|
+
points.update(new_points)
|
|
525
|
+
# assert all(self.contains(p) for p in points) # slow
|
|
526
|
+
return tuple(points)
|
|
527
|
+
|
|
528
|
+
def get_integral_point(self, index, **kwds):
|
|
529
|
+
r"""
|
|
530
|
+
Return the ``index``-th integral point in this polyhedron.
|
|
531
|
+
|
|
532
|
+
This is equivalent to ``sorted(self.integral_points())[index]``.
|
|
533
|
+
However, so long as :meth:`integral_points_count` does not need to
|
|
534
|
+
enumerate all integral points, neither does this method. Hence it can
|
|
535
|
+
be significantly faster. If the polyhedron is not compact, a
|
|
536
|
+
:exc:`ValueError` is raised.
|
|
537
|
+
|
|
538
|
+
INPUT:
|
|
539
|
+
|
|
540
|
+
- ``index`` -- integer; the index of the integral point to be found. If
|
|
541
|
+
this is not in [0, ``self.integral_point_count()``), an :exc:`IndexError`
|
|
542
|
+
is raised.
|
|
543
|
+
|
|
544
|
+
- ``**kwds`` -- optional keyword parameters that are passed to
|
|
545
|
+
:meth:`integral_points_count`
|
|
546
|
+
|
|
547
|
+
ALGORITHM:
|
|
548
|
+
|
|
549
|
+
The function computes each of the components of the requested point in
|
|
550
|
+
turn. To compute x_i, the `i`-th component, it bisects the upper and lower
|
|
551
|
+
bounds on x_i given by the bounding box. At each bisection, it uses
|
|
552
|
+
:meth:`integral_points_count` to determine on which side of the
|
|
553
|
+
bisecting hyperplane the requested point lies.
|
|
554
|
+
|
|
555
|
+
.. SEEALSO::
|
|
556
|
+
|
|
557
|
+
:meth:`integral_points_count`.
|
|
558
|
+
|
|
559
|
+
EXAMPLES::
|
|
560
|
+
|
|
561
|
+
sage: P = Polyhedron(vertices=[(-1,-1),(1,0),(1,1),(0,1)])
|
|
562
|
+
sage: P.get_integral_point(1)
|
|
563
|
+
(0, 0)
|
|
564
|
+
sage: P.get_integral_point(4)
|
|
565
|
+
(1, 1)
|
|
566
|
+
sage: sorted(P.integral_points())
|
|
567
|
+
[(-1, -1), (0, 0), (0, 1), (1, 0), (1, 1)]
|
|
568
|
+
sage: P.get_integral_point(5)
|
|
569
|
+
Traceback (most recent call last):
|
|
570
|
+
...
|
|
571
|
+
IndexError: ...
|
|
572
|
+
|
|
573
|
+
sage: Q = Polyhedron([(1,3), (2, 7), (9, 77)])
|
|
574
|
+
sage: [Q.get_integral_point(i) for i in range(Q.integral_points_count())] == sorted(Q.integral_points())
|
|
575
|
+
True
|
|
576
|
+
sage: Q.get_integral_point(0, explicit_enumeration_threshold=0, triangulation='cddlib') # optional - latte_int
|
|
577
|
+
(1, 3)
|
|
578
|
+
sage: Q.get_integral_point(0, explicit_enumeration_threshold=0, triangulation='cddlib', foo=True) # optional - latte_int
|
|
579
|
+
Traceback (most recent call last):
|
|
580
|
+
...
|
|
581
|
+
RuntimeError: ...
|
|
582
|
+
|
|
583
|
+
sage: R = Polyhedron(vertices=[[1/2, 1/3]], rays=[[1, 1]])
|
|
584
|
+
sage: R.get_integral_point(0)
|
|
585
|
+
Traceback (most recent call last):
|
|
586
|
+
...
|
|
587
|
+
ValueError: ...
|
|
588
|
+
"""
|
|
589
|
+
from sage.arith.misc import integer_ceil as ceil
|
|
590
|
+
from sage.arith.misc import integer_floor as floor
|
|
591
|
+
if not self.is_compact():
|
|
592
|
+
raise ValueError('can only enumerate points in a compact polyhedron')
|
|
593
|
+
|
|
594
|
+
if not 0 <= index < self.integral_points_count(**kwds):
|
|
595
|
+
raise IndexError('polytope index out of range')
|
|
596
|
+
|
|
597
|
+
D = self.ambient_dim()
|
|
598
|
+
lower_bounds, upper_bounds = self.bounding_box()
|
|
599
|
+
coordinate = []
|
|
600
|
+
P = self
|
|
601
|
+
S = self.parent()
|
|
602
|
+
for i in range(D): # Now compute x_i, the ith component of coordinate.
|
|
603
|
+
lower, upper = ceil(lower_bounds[i]), floor(upper_bounds[i]) + 1 # So lower <= x_i < upper.
|
|
604
|
+
while lower < upper-1:
|
|
605
|
+
guess = (lower + upper) // 2 # > lower.
|
|
606
|
+
# Build new polyhedron by intersecting P with the halfspace {x_i < guess}.
|
|
607
|
+
P_lt_guess = P.intersection(S(None, ([[guess-1] + [0] * i + [-1] + [0] * (D - i - 1)], [])))
|
|
608
|
+
# Avoid computing P_geq_guess = P.intersection({x_i >= guess}) right now, it might not be needed.
|
|
609
|
+
P_lt_guess_count = P_lt_guess.integral_points_count(**kwds)
|
|
610
|
+
if P_lt_guess_count > index: # Move upper down to guess.
|
|
611
|
+
upper = guess
|
|
612
|
+
index -= 0
|
|
613
|
+
P = P_lt_guess
|
|
614
|
+
else: # P_lt_guess_count <= index: # Move lower up to guess.
|
|
615
|
+
lower = guess
|
|
616
|
+
index -= P_lt_guess_count
|
|
617
|
+
P_geq_guess = P.intersection(S(None, ([[-guess] + [0] * i + [1] + [0] * (D - i - 1)], [])))
|
|
618
|
+
P = P_geq_guess
|
|
619
|
+
coordinate.append(lower) # Record the new component that we have found.
|
|
620
|
+
point = vector(ZZ, coordinate)
|
|
621
|
+
point.set_immutable()
|
|
622
|
+
return point
|
|
623
|
+
|
|
624
|
+
def random_integral_point(self, **kwds):
|
|
625
|
+
r"""
|
|
626
|
+
Return an integral point in this polyhedron chosen uniformly at random.
|
|
627
|
+
|
|
628
|
+
INPUT:
|
|
629
|
+
|
|
630
|
+
- ``**kwds`` -- optional keyword parameters that are passed to
|
|
631
|
+
:meth:`get_integral_point`
|
|
632
|
+
|
|
633
|
+
OUTPUT:
|
|
634
|
+
|
|
635
|
+
The integral point in the polyhedron chosen uniformly at random. If the
|
|
636
|
+
polyhedron is not compact, a :exc:`ValueError` is raised. If the
|
|
637
|
+
polyhedron does not contain any integral points, an
|
|
638
|
+
:class:`~sage.categories.sets_cat.EmptySetError` is raised.
|
|
639
|
+
|
|
640
|
+
.. SEEALSO::
|
|
641
|
+
|
|
642
|
+
:meth:`get_integral_point`.
|
|
643
|
+
|
|
644
|
+
EXAMPLES::
|
|
645
|
+
|
|
646
|
+
sage: P = Polyhedron(vertices=[(-1,-1),(1,0),(1,1),(0,1)])
|
|
647
|
+
sage: P.random_integral_point() # random
|
|
648
|
+
(0, 0)
|
|
649
|
+
sage: P.random_integral_point() in P.integral_points()
|
|
650
|
+
True
|
|
651
|
+
sage: P.random_integral_point(explicit_enumeration_threshold=0, # random, optional - latte_int
|
|
652
|
+
....: triangulation='cddlib')
|
|
653
|
+
(1, 1)
|
|
654
|
+
sage: P.random_integral_point(explicit_enumeration_threshold=0, # optional - latte_int
|
|
655
|
+
....: triangulation='cddlib', foo=7)
|
|
656
|
+
Traceback (most recent call last):
|
|
657
|
+
...
|
|
658
|
+
RuntimeError: ...
|
|
659
|
+
|
|
660
|
+
sage: Q = Polyhedron(vertices=[(2, 1/3)], rays=[(1, 2)])
|
|
661
|
+
sage: Q.random_integral_point()
|
|
662
|
+
Traceback (most recent call last):
|
|
663
|
+
...
|
|
664
|
+
ValueError: ...
|
|
665
|
+
|
|
666
|
+
sage: R = Polyhedron(vertices=[(1/2, 0), (1, 1/2), (0, 1/2)])
|
|
667
|
+
sage: R.random_integral_point()
|
|
668
|
+
Traceback (most recent call last):
|
|
669
|
+
...
|
|
670
|
+
EmptySetError: ...
|
|
671
|
+
"""
|
|
672
|
+
from sage.misc.randstate import current_randstate
|
|
673
|
+
|
|
674
|
+
if not self.is_compact():
|
|
675
|
+
raise ValueError('can only sample integral points in a compact polyhedron')
|
|
676
|
+
|
|
677
|
+
count = self.integral_points_count()
|
|
678
|
+
if count == 0:
|
|
679
|
+
from sage.categories.sets_cat import EmptySetError
|
|
680
|
+
raise EmptySetError('polyhedron does not contain any integral points')
|
|
681
|
+
|
|
682
|
+
return self.get_integral_point(current_randstate().python_random().randint(0, count-1), **kwds)
|
|
683
|
+
|
|
684
|
+
def generating_function_of_integral_points(self, **kwds):
|
|
685
|
+
r"""
|
|
686
|
+
Return the multivariate generating function of the
|
|
687
|
+
integral points of this polyhedron.
|
|
688
|
+
|
|
689
|
+
To be precise, this returns
|
|
690
|
+
|
|
691
|
+
.. MATH::
|
|
692
|
+
|
|
693
|
+
\sum_{(r_0,\dots,r_{d-1}) \in \mathit{polyhedron}\cap \ZZ^d}
|
|
694
|
+
y_0^{r_0} \dots y_{d-1}^{r_{d-1}}.
|
|
695
|
+
|
|
696
|
+
This calls
|
|
697
|
+
:func:`~sage.geometry.polyhedron.generating_function.generating_function_of_integral_points`,
|
|
698
|
+
so have a look at the documentation and examples there.
|
|
699
|
+
|
|
700
|
+
INPUT:
|
|
701
|
+
|
|
702
|
+
The following keyword arguments are passed to
|
|
703
|
+
:func:`~sage.geometry.polyhedron.generating_function.generating_function_of_integral_points`:
|
|
704
|
+
|
|
705
|
+
- ``split`` -- boolean (default: ``False``) or list
|
|
706
|
+
|
|
707
|
+
- ``split=False`` computes the generating function directly,
|
|
708
|
+
without any splitting.
|
|
709
|
+
|
|
710
|
+
- When ``split`` is a list of disjoint polyhedra, then
|
|
711
|
+
for each of these polyhedra, this polyhedron is intersected with it,
|
|
712
|
+
its generating function computed and all these generating functions
|
|
713
|
+
are summed up.
|
|
714
|
+
|
|
715
|
+
- ``split=True`` splits into `d!` disjoint polyhedra.
|
|
716
|
+
|
|
717
|
+
- ``result_as_tuple`` -- (default: ``None``) a boolean or ``None``
|
|
718
|
+
|
|
719
|
+
This specifies whether the output is a (partial) factorization
|
|
720
|
+
(``result_as_tuple=False``) or a sum of such (partial)
|
|
721
|
+
factorizations (``result_as_tuple=True``). By default
|
|
722
|
+
(``result_as_tuple=None``), this is automatically determined.
|
|
723
|
+
If the output is a sum, it is represented as a tuple whose
|
|
724
|
+
entries are the summands.
|
|
725
|
+
|
|
726
|
+
- ``indices`` -- (default: ``None``) a list or tuple
|
|
727
|
+
|
|
728
|
+
If this
|
|
729
|
+
is ``None``, this is automatically determined.
|
|
730
|
+
|
|
731
|
+
- ``name`` -- (default: ``'y'``) a string
|
|
732
|
+
|
|
733
|
+
The variable names of the Laurent polynomial ring of the output
|
|
734
|
+
are this string followed by an integer.
|
|
735
|
+
|
|
736
|
+
- ``names`` -- list or tuple of names (strings), or a comma separated string
|
|
737
|
+
|
|
738
|
+
``name`` is extracted from ``names``, therefore ``names`` has to contain
|
|
739
|
+
exactly one variable name, and ``name`` and``names`` cannot be specified
|
|
740
|
+
both at the same time.
|
|
741
|
+
|
|
742
|
+
- ``Factorization_sort`` (default: ``False``) and
|
|
743
|
+
``Factorization_simplify`` (default: ``True``) -- booleans
|
|
744
|
+
|
|
745
|
+
These are passed on to
|
|
746
|
+
:class:`sage.structure.factorization.Factorization` when creating
|
|
747
|
+
the result.
|
|
748
|
+
|
|
749
|
+
- ``sort_factors`` -- boolean (default: ``False``)
|
|
750
|
+
|
|
751
|
+
If set, then the factors of the output are sorted such that the
|
|
752
|
+
numerator is first and only then all factors of the denominator. It
|
|
753
|
+
is ensured that the sorting is always the same; use this for
|
|
754
|
+
doctesting.
|
|
755
|
+
|
|
756
|
+
OUTPUT:
|
|
757
|
+
|
|
758
|
+
The generating function as a (partial)
|
|
759
|
+
:class:`~sage.structure.factorization.Factorization`
|
|
760
|
+
of the result whose factors are Laurent polynomials
|
|
761
|
+
|
|
762
|
+
The result might be a tuple of such factorizations
|
|
763
|
+
(depending on the parameter ``result_as_tuple``) as well.
|
|
764
|
+
|
|
765
|
+
.. NOTE::
|
|
766
|
+
|
|
767
|
+
At the moment, only polyhedra with nonnegative coordinates
|
|
768
|
+
(i.e. a polyhedron in the nonnegative orthant) are handled.
|
|
769
|
+
|
|
770
|
+
EXAMPLES::
|
|
771
|
+
|
|
772
|
+
sage: # needs sage.combinat
|
|
773
|
+
sage: P2 = (Polyhedron(ieqs=[(0, 0, 0, 1), (0, 0, 1, 0), (0, 1, 0, -1)]),
|
|
774
|
+
....: Polyhedron(ieqs=[(0, -1, 0, 1), (0, 1, 0, 0), (0, 0, 1, 0)]))
|
|
775
|
+
sage: P2[0].generating_function_of_integral_points(sort_factors=True)
|
|
776
|
+
1 * (-y0 + 1)^-1 * (-y1 + 1)^-1 * (-y0*y2 + 1)^-1
|
|
777
|
+
sage: P2[1].generating_function_of_integral_points(sort_factors=True)
|
|
778
|
+
1 * (-y1 + 1)^-1 * (-y2 + 1)^-1 * (-y0*y2 + 1)^-1
|
|
779
|
+
sage: (P2[0] & P2[1]).Hrepresentation()
|
|
780
|
+
(An equation (1, 0, -1) x + 0 == 0,
|
|
781
|
+
An inequality (1, 0, 0) x + 0 >= 0,
|
|
782
|
+
An inequality (0, 1, 0) x + 0 >= 0)
|
|
783
|
+
sage: (P2[0] & P2[1]).generating_function_of_integral_points(sort_factors=True)
|
|
784
|
+
1 * (-y1 + 1)^-1 * (-y0*y2 + 1)^-1
|
|
785
|
+
|
|
786
|
+
The number of integer partitions
|
|
787
|
+
`1 \leq r_0 \leq r_1 \leq r_2 \leq r_3 \leq r_4`::
|
|
788
|
+
|
|
789
|
+
sage: # needs sage.combinat
|
|
790
|
+
sage: P = Polyhedron(ieqs=[(-1, 1, 0, 0, 0, 0), (0, -1, 1, 0, 0, 0),
|
|
791
|
+
....: (0, 0, -1, 1, 0, 0), (0, 0, 0, -1, 1, 0),
|
|
792
|
+
....: (0, 0, 0, 0, -1, 1)])
|
|
793
|
+
sage: f = P.generating_function_of_integral_points(sort_factors=True); f
|
|
794
|
+
y0*y1*y2*y3*y4 * (-y4 + 1)^-1 * (-y3*y4 + 1)^-1 * (-y2*y3*y4 + 1)^-1 *
|
|
795
|
+
(-y1*y2*y3*y4 + 1)^-1 * (-y0*y1*y2*y3*y4 + 1)^-1
|
|
796
|
+
sage: f = f.value()
|
|
797
|
+
sage: P.<z> = PowerSeriesRing(ZZ)
|
|
798
|
+
sage: c = f.subs({y: z for y in f.parent().gens()}); c
|
|
799
|
+
z^5 + z^6 + 2*z^7 + 3*z^8 + 5*z^9 + 7*z^10 + 10*z^11 + 13*z^12 + 18*z^13 +
|
|
800
|
+
23*z^14 + 30*z^15 + 37*z^16 + 47*z^17 + 57*z^18 + 70*z^19 + 84*z^20 +
|
|
801
|
+
101*z^21 + 119*z^22 + 141*z^23 + 164*z^24 + O(z^25)
|
|
802
|
+
sage: ([Partitions(k, length=5).cardinality() for k in range(5,20)] ==
|
|
803
|
+
....: c.truncate().coefficients(sparse=False)[5:20])
|
|
804
|
+
True
|
|
805
|
+
|
|
806
|
+
.. SEEALSO::
|
|
807
|
+
|
|
808
|
+
More examples can be found at
|
|
809
|
+
:func:`~sage.geometry.polyhedron.generating_function.generating_function_of_integral_points`.
|
|
810
|
+
"""
|
|
811
|
+
from .generating_function import generating_function_of_integral_points
|
|
812
|
+
return generating_function_of_integral_points(self, **kwds)
|