passagemath-polyhedra 10.6.37__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.
- passagemath_polyhedra/__init__.py +3 -0
- passagemath_polyhedra-10.6.37.dist-info/METADATA +367 -0
- passagemath_polyhedra-10.6.37.dist-info/METADATA.bak +369 -0
- passagemath_polyhedra-10.6.37.dist-info/RECORD +209 -0
- passagemath_polyhedra-10.6.37.dist-info/WHEEL +5 -0
- passagemath_polyhedra-10.6.37.dist-info/top_level.txt +3 -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 +3905 -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,1119 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-polyhedra
|
|
2
|
+
r"""
|
|
3
|
+
Convex Sets
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
# ****************************************************************************
|
|
7
|
+
# Copyright (C) 2021 Matthias Koeppe
|
|
8
|
+
#
|
|
9
|
+
# This program is free software: you can redistribute it and/or modify
|
|
10
|
+
# it under the terms of the GNU General Public License as published by
|
|
11
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
12
|
+
# (at your option) any later version.
|
|
13
|
+
# https://www.gnu.org/licenses/
|
|
14
|
+
# ****************************************************************************
|
|
15
|
+
|
|
16
|
+
from dataclasses import dataclass
|
|
17
|
+
from typing import Any
|
|
18
|
+
from copy import copy
|
|
19
|
+
|
|
20
|
+
from sage.structure.sage_object import SageObject
|
|
21
|
+
from sage.sets.set import Set_base
|
|
22
|
+
from sage.categories.sets_cat import EmptySetError
|
|
23
|
+
from sage.misc.abstract_method import abstract_method
|
|
24
|
+
from sage.misc.cachefunc import cached_method
|
|
25
|
+
from sage.rings.infinity import infinity
|
|
26
|
+
from sage.rings.integer_ring import ZZ
|
|
27
|
+
from sage.modules.free_module_element import vector
|
|
28
|
+
from sage.matrix.constructor import matrix
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class AffineHullProjectionData:
|
|
33
|
+
image: Any = None
|
|
34
|
+
projection_linear_map: Any = None
|
|
35
|
+
projection_translation: Any = None
|
|
36
|
+
section_linear_map: Any = None
|
|
37
|
+
section_translation: Any = None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class ConvexSet_base(SageObject, Set_base):
|
|
41
|
+
"""
|
|
42
|
+
Abstract base class for convex sets.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
def is_empty(self):
|
|
46
|
+
r"""
|
|
47
|
+
Test whether ``self`` is the empty set.
|
|
48
|
+
|
|
49
|
+
OUTPUT: boolean
|
|
50
|
+
|
|
51
|
+
EXAMPLES::
|
|
52
|
+
|
|
53
|
+
sage: p = LatticePolytope([], lattice=ToricLattice(3).dual()); p
|
|
54
|
+
-1-d lattice polytope in 3-d lattice M
|
|
55
|
+
sage: p.is_empty()
|
|
56
|
+
True
|
|
57
|
+
"""
|
|
58
|
+
return self.dim() < 0
|
|
59
|
+
|
|
60
|
+
def is_finite(self):
|
|
61
|
+
r"""
|
|
62
|
+
Test whether ``self`` is a finite set.
|
|
63
|
+
|
|
64
|
+
OUTPUT: boolean
|
|
65
|
+
|
|
66
|
+
EXAMPLES::
|
|
67
|
+
|
|
68
|
+
sage: p = LatticePolytope([], lattice=ToricLattice(3).dual()); p
|
|
69
|
+
-1-d lattice polytope in 3-d lattice M
|
|
70
|
+
sage: p.is_finite()
|
|
71
|
+
True
|
|
72
|
+
sage: q = Polyhedron(ambient_dim=2); q
|
|
73
|
+
The empty polyhedron in ZZ^2
|
|
74
|
+
sage: q.is_finite()
|
|
75
|
+
True
|
|
76
|
+
sage: r = Polyhedron(rays=[(1, 0)]); r
|
|
77
|
+
A 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex and 1 ray
|
|
78
|
+
sage: r.is_finite()
|
|
79
|
+
False
|
|
80
|
+
"""
|
|
81
|
+
return self.dim() < 1
|
|
82
|
+
|
|
83
|
+
def cardinality(self):
|
|
84
|
+
"""
|
|
85
|
+
Return the cardinality of this set.
|
|
86
|
+
|
|
87
|
+
OUTPUT: either an integer or ``Infinity``
|
|
88
|
+
|
|
89
|
+
EXAMPLES::
|
|
90
|
+
|
|
91
|
+
sage: p = LatticePolytope([], lattice=ToricLattice(3).dual()); p
|
|
92
|
+
-1-d lattice polytope in 3-d lattice M
|
|
93
|
+
sage: p.cardinality()
|
|
94
|
+
0
|
|
95
|
+
sage: q = Polyhedron(ambient_dim=2); q
|
|
96
|
+
The empty polyhedron in ZZ^2
|
|
97
|
+
sage: q.cardinality()
|
|
98
|
+
0
|
|
99
|
+
sage: r = Polyhedron(rays=[(1, 0)]); r
|
|
100
|
+
A 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex and 1 ray
|
|
101
|
+
sage: r.cardinality()
|
|
102
|
+
+Infinity
|
|
103
|
+
"""
|
|
104
|
+
if self.dim() < 0:
|
|
105
|
+
return ZZ(0)
|
|
106
|
+
if self.dim() == 0:
|
|
107
|
+
return ZZ(1)
|
|
108
|
+
return infinity
|
|
109
|
+
|
|
110
|
+
def is_universe(self):
|
|
111
|
+
r"""
|
|
112
|
+
Test whether ``self`` is the whole ambient space.
|
|
113
|
+
|
|
114
|
+
OUTPUT: boolean
|
|
115
|
+
|
|
116
|
+
TESTS::
|
|
117
|
+
|
|
118
|
+
sage: from sage.geometry.convex_set import ConvexSet_base
|
|
119
|
+
sage: C = ConvexSet_base()
|
|
120
|
+
sage: C.is_universe()
|
|
121
|
+
Traceback (most recent call last):
|
|
122
|
+
...
|
|
123
|
+
NotImplementedError
|
|
124
|
+
"""
|
|
125
|
+
if not self.is_full_dimensional():
|
|
126
|
+
return False
|
|
127
|
+
raise NotImplementedError
|
|
128
|
+
|
|
129
|
+
def dim(self):
|
|
130
|
+
r"""
|
|
131
|
+
Return the dimension of ``self``.
|
|
132
|
+
|
|
133
|
+
Subclasses must provide an implementation of this method or of the
|
|
134
|
+
method :meth:`an_affine_basis`.
|
|
135
|
+
|
|
136
|
+
TESTS::
|
|
137
|
+
|
|
138
|
+
sage: from sage.geometry.convex_set import ConvexSet_base
|
|
139
|
+
sage: C = ConvexSet_base()
|
|
140
|
+
sage: C.dim()
|
|
141
|
+
Traceback (most recent call last):
|
|
142
|
+
...
|
|
143
|
+
NotImplementedError
|
|
144
|
+
"""
|
|
145
|
+
if self.an_affine_basis != NotImplemented:
|
|
146
|
+
return len(self.an_affine_basis()) - 1
|
|
147
|
+
raise NotImplementedError
|
|
148
|
+
|
|
149
|
+
def dimension(self):
|
|
150
|
+
r"""
|
|
151
|
+
Return the dimension of ``self``.
|
|
152
|
+
|
|
153
|
+
This is the same as :meth:`dim`.
|
|
154
|
+
|
|
155
|
+
EXAMPLES::
|
|
156
|
+
|
|
157
|
+
sage: from sage.geometry.convex_set import ConvexSet_base
|
|
158
|
+
sage: class ExampleSet(ConvexSet_base):
|
|
159
|
+
....: def dim(self):
|
|
160
|
+
....: return 42
|
|
161
|
+
sage: ExampleSet().dimension()
|
|
162
|
+
42
|
|
163
|
+
"""
|
|
164
|
+
return self.dim()
|
|
165
|
+
|
|
166
|
+
@abstract_method
|
|
167
|
+
def ambient_vector_space(self, base_field=None):
|
|
168
|
+
r"""
|
|
169
|
+
Return the ambient vector space.
|
|
170
|
+
|
|
171
|
+
Subclasses must provide an implementation of this method.
|
|
172
|
+
|
|
173
|
+
The default implementations of :meth:`ambient`, :meth:`ambient_dim`,
|
|
174
|
+
:meth:`ambient_dimension` use this method.
|
|
175
|
+
|
|
176
|
+
EXAMPLES::
|
|
177
|
+
|
|
178
|
+
sage: from sage.geometry.convex_set import ConvexSet_base
|
|
179
|
+
sage: C = ConvexSet_base()
|
|
180
|
+
sage: C.ambient_vector_space()
|
|
181
|
+
Traceback (most recent call last):
|
|
182
|
+
...
|
|
183
|
+
NotImplementedError: <abstract method ambient_vector_space at ...>
|
|
184
|
+
"""
|
|
185
|
+
|
|
186
|
+
def ambient(self):
|
|
187
|
+
r"""
|
|
188
|
+
Return the ambient convex set or space.
|
|
189
|
+
|
|
190
|
+
The default implementation delegates to :meth:`ambient_vector_space`.
|
|
191
|
+
|
|
192
|
+
EXAMPLES::
|
|
193
|
+
|
|
194
|
+
sage: from sage.geometry.convex_set import ConvexSet_base
|
|
195
|
+
sage: class ExampleSet(ConvexSet_base):
|
|
196
|
+
....: def ambient_vector_space(self, base_field=None):
|
|
197
|
+
....: return (base_field or QQ)^2001
|
|
198
|
+
sage: ExampleSet().ambient()
|
|
199
|
+
Vector space of dimension 2001 over Rational Field
|
|
200
|
+
"""
|
|
201
|
+
return self.ambient_vector_space()
|
|
202
|
+
|
|
203
|
+
def ambient_dim(self):
|
|
204
|
+
r"""
|
|
205
|
+
Return the dimension of the ambient convex set or space.
|
|
206
|
+
|
|
207
|
+
The default implementation obtains it from :meth:`ambient`.
|
|
208
|
+
|
|
209
|
+
EXAMPLES::
|
|
210
|
+
|
|
211
|
+
sage: from sage.geometry.convex_set import ConvexSet_base
|
|
212
|
+
sage: class ExampleSet(ConvexSet_base):
|
|
213
|
+
....: def ambient(self):
|
|
214
|
+
....: return QQ^7
|
|
215
|
+
sage: ExampleSet().ambient_dim()
|
|
216
|
+
7
|
|
217
|
+
"""
|
|
218
|
+
return self.ambient().dimension()
|
|
219
|
+
|
|
220
|
+
def ambient_dimension(self):
|
|
221
|
+
r"""
|
|
222
|
+
Return the dimension of the ambient convex set or space.
|
|
223
|
+
|
|
224
|
+
This is the same as :meth:`ambient_dim`.
|
|
225
|
+
|
|
226
|
+
EXAMPLES::
|
|
227
|
+
|
|
228
|
+
sage: from sage.geometry.convex_set import ConvexSet_base
|
|
229
|
+
sage: class ExampleSet(ConvexSet_base):
|
|
230
|
+
....: def ambient_dim(self):
|
|
231
|
+
....: return 91
|
|
232
|
+
sage: ExampleSet().ambient_dimension()
|
|
233
|
+
91
|
|
234
|
+
"""
|
|
235
|
+
return self.ambient_dim()
|
|
236
|
+
|
|
237
|
+
@abstract_method(optional=True)
|
|
238
|
+
def an_affine_basis(self):
|
|
239
|
+
r"""
|
|
240
|
+
Return points that form an affine basis for the affine hull.
|
|
241
|
+
|
|
242
|
+
The points are guaranteed to lie in the topological closure of ``self``.
|
|
243
|
+
|
|
244
|
+
EXAMPLES::
|
|
245
|
+
|
|
246
|
+
sage: from sage.geometry.convex_set import ConvexSet_base
|
|
247
|
+
sage: C = ConvexSet_base()
|
|
248
|
+
sage: C.an_affine_basis()
|
|
249
|
+
Traceback (most recent call last):
|
|
250
|
+
...
|
|
251
|
+
TypeError: 'NotImplementedType' object is not callable
|
|
252
|
+
"""
|
|
253
|
+
|
|
254
|
+
def _test_an_affine_basis(self, tester=None, **options):
|
|
255
|
+
r"""
|
|
256
|
+
Run tests on the method :meth:`.an_affine_basis`.
|
|
257
|
+
|
|
258
|
+
TESTS::
|
|
259
|
+
|
|
260
|
+
sage: c = Cone([(1,0)])
|
|
261
|
+
sage: c._test_an_affine_basis()
|
|
262
|
+
"""
|
|
263
|
+
if tester is None:
|
|
264
|
+
tester = self._tester(**options)
|
|
265
|
+
try:
|
|
266
|
+
if self.an_affine_basis == NotImplemented:
|
|
267
|
+
raise NotImplementedError
|
|
268
|
+
b = self.an_affine_basis()
|
|
269
|
+
except NotImplementedError:
|
|
270
|
+
pass
|
|
271
|
+
else:
|
|
272
|
+
m = matrix([1] + list(v) for v in b)
|
|
273
|
+
tester.assertEqual(m.rank(), self.dim() + 1)
|
|
274
|
+
closure = self.closure()
|
|
275
|
+
for v in b:
|
|
276
|
+
tester.assertIn(v, closure)
|
|
277
|
+
|
|
278
|
+
def affine_hull(self, *args, **kwds):
|
|
279
|
+
r"""
|
|
280
|
+
Return the affine hull of ``self`` as a polyhedron.
|
|
281
|
+
|
|
282
|
+
EXAMPLES::
|
|
283
|
+
|
|
284
|
+
sage: from sage.geometry.convex_set import ConvexSet_compact
|
|
285
|
+
sage: class EmbeddedDisk(ConvexSet_compact):
|
|
286
|
+
....: def an_affine_basis(self):
|
|
287
|
+
....: return [vector([1, 0, 0]), vector([1, 1, 0]), vector([1, 0, 1])]
|
|
288
|
+
sage: O = EmbeddedDisk()
|
|
289
|
+
sage: O.dim()
|
|
290
|
+
2
|
|
291
|
+
sage: O.affine_hull()
|
|
292
|
+
A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex and 2 lines
|
|
293
|
+
"""
|
|
294
|
+
from .polyhedron.constructor import Polyhedron
|
|
295
|
+
i_affine_basis = iter(self.an_affine_basis())
|
|
296
|
+
try:
|
|
297
|
+
v = next(i_affine_basis)
|
|
298
|
+
except StopIteration:
|
|
299
|
+
return Polyhedron(ambient_dim=self.ambient_dim())
|
|
300
|
+
v = vector(v)
|
|
301
|
+
return Polyhedron(vertices=[v], lines=[vector(p) - v for p in i_affine_basis])
|
|
302
|
+
|
|
303
|
+
@cached_method
|
|
304
|
+
def _affine_hull_projection(self, *,
|
|
305
|
+
as_convex_set=True, as_affine_map=True, as_section_map=True,
|
|
306
|
+
orthogonal=False, orthonormal=False,
|
|
307
|
+
extend=False, minimal=False):
|
|
308
|
+
r"""
|
|
309
|
+
Return ``self`` projected into its affine hull.
|
|
310
|
+
|
|
311
|
+
Each convex set is contained in some smallest affine subspace
|
|
312
|
+
(possibly the entire ambient space) -- its affine hull. We
|
|
313
|
+
provide an affine linear map that projects the ambient space of
|
|
314
|
+
the convex set to the standard Euclidean space of dimension of
|
|
315
|
+
the convex set, which restricts to a bijection from the affine
|
|
316
|
+
hull.
|
|
317
|
+
|
|
318
|
+
The projection map is not unique; some parameters control the
|
|
319
|
+
choice of the map. Other parameters control the output of the
|
|
320
|
+
function.
|
|
321
|
+
|
|
322
|
+
This default implementation delegates to
|
|
323
|
+
:meth:`~sage.geometry.polyhedron.base.Polyhedron_base._affine_hull_projection`,
|
|
324
|
+
applied to the :meth:`affine_hull` of ``self``.
|
|
325
|
+
|
|
326
|
+
Subclasses should override this method if they can provide a
|
|
327
|
+
more direct implementation or additional options.
|
|
328
|
+
|
|
329
|
+
EXAMPLES::
|
|
330
|
+
|
|
331
|
+
sage: from sage.geometry.convex_set import ConvexSet_compact
|
|
332
|
+
sage: class EmbeddedEllipse(ConvexSet_compact):
|
|
333
|
+
....: def __init__(self, p, *rr):
|
|
334
|
+
....: self._p = vector(p)
|
|
335
|
+
....: self._rr = tuple(vector(r) for r in rr)
|
|
336
|
+
....: def an_affine_basis(self):
|
|
337
|
+
....: return [self._p] + [self._p + r for r in self._rr]
|
|
338
|
+
....: def linear_transformation(self, linear_transf):
|
|
339
|
+
....: return EmbeddedEllipse(linear_transf * self._p,
|
|
340
|
+
....: *[linear_transf * r for r in self._rr])
|
|
341
|
+
....: def translation(self, displacement):
|
|
342
|
+
....: return EmbeddedEllipse(self._p + displacement, *self._rr)
|
|
343
|
+
sage: EmbeddedEllipse([2, 2, 2], [0, 1, 0], [0, 0, 1])._affine_hull_projection()
|
|
344
|
+
AffineHullProjectionData(image=<__main__.EmbeddedEllipse object at 0x...>,
|
|
345
|
+
projection_linear_map=Vector space morphism represented by the matrix:
|
|
346
|
+
[0 0]
|
|
347
|
+
[1 0]
|
|
348
|
+
[0 1]
|
|
349
|
+
Domain: Vector space of dimension 3 over Rational Field
|
|
350
|
+
Codomain: Vector space of dimension 2 over Rational Field,
|
|
351
|
+
projection_translation=(0, 0),
|
|
352
|
+
section_linear_map=Vector space morphism represented by the matrix:
|
|
353
|
+
[0 1 0]
|
|
354
|
+
[0 0 1]
|
|
355
|
+
Domain: Vector space of dimension 2 over Rational Field
|
|
356
|
+
Codomain: Vector space of dimension 3 over Rational Field,
|
|
357
|
+
section_translation=(2, 0, 0))
|
|
358
|
+
"""
|
|
359
|
+
affine_hull = self.affine_hull()
|
|
360
|
+
data = affine_hull._affine_hull_projection(
|
|
361
|
+
as_convex_set=False, as_affine_map=True, as_section_map=True,
|
|
362
|
+
orthogonal=orthogonal, orthonormal=orthonormal,
|
|
363
|
+
extend=extend, minimal=minimal)
|
|
364
|
+
if as_convex_set:
|
|
365
|
+
data = copy(data)
|
|
366
|
+
matrix = data.projection_linear_map.matrix().transpose()
|
|
367
|
+
projected = self.linear_transformation(matrix)
|
|
368
|
+
data.image = projected.translation(data.projection_translation)
|
|
369
|
+
return data
|
|
370
|
+
|
|
371
|
+
def affine_hull_projection(self, as_convex_set=None, as_affine_map=False,
|
|
372
|
+
orthogonal=False, orthonormal=False,
|
|
373
|
+
extend=False, minimal=False,
|
|
374
|
+
return_all_data=False, **kwds):
|
|
375
|
+
r"""
|
|
376
|
+
Return ``self`` projected into its affine hull.
|
|
377
|
+
|
|
378
|
+
Each convex set is contained in some smallest affine subspace
|
|
379
|
+
(possibly the entire ambient space) -- its affine hull. We
|
|
380
|
+
provide an affine linear map that projects the ambient space of
|
|
381
|
+
the convex set to the standard Euclidean space of dimension of
|
|
382
|
+
the convex set, which restricts to a bijection from the affine
|
|
383
|
+
hull.
|
|
384
|
+
|
|
385
|
+
The projection map is not unique; some parameters control the
|
|
386
|
+
choice of the map. Other parameters control the output of the
|
|
387
|
+
function.
|
|
388
|
+
|
|
389
|
+
EXAMPLES::
|
|
390
|
+
|
|
391
|
+
sage: P = Polyhedron(vertices=[[1, 0], [0, 1]])
|
|
392
|
+
sage: ri_P = P.relative_interior(); ri_P
|
|
393
|
+
Relative interior of a 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices
|
|
394
|
+
sage: ri_P.affine_hull_projection(as_affine_map=True)
|
|
395
|
+
(Vector space morphism represented by the matrix:
|
|
396
|
+
[1]
|
|
397
|
+
[0]
|
|
398
|
+
Domain: Vector space of dimension 2 over Rational Field
|
|
399
|
+
Codomain: Vector space of dimension 1 over Rational Field,
|
|
400
|
+
(0))
|
|
401
|
+
sage: P_aff = P.affine_hull_projection(); P_aff
|
|
402
|
+
A 1-dimensional polyhedron in ZZ^1 defined as the convex hull of 2 vertices
|
|
403
|
+
sage: ri_P_aff = ri_P.affine_hull_projection(); ri_P_aff
|
|
404
|
+
Relative interior of a 1-dimensional polyhedron in QQ^1 defined as the convex hull of 2 vertices
|
|
405
|
+
sage: ri_P_aff.closure() == P_aff
|
|
406
|
+
True
|
|
407
|
+
"""
|
|
408
|
+
if as_convex_set is None:
|
|
409
|
+
as_convex_set = not as_affine_map
|
|
410
|
+
if not as_affine_map and not as_convex_set:
|
|
411
|
+
raise ValueError('combining "as_affine_map=False" and '
|
|
412
|
+
'"as_convex_set=False" not allowed')
|
|
413
|
+
if return_all_data:
|
|
414
|
+
as_convex_set = True
|
|
415
|
+
as_affine_map = True
|
|
416
|
+
|
|
417
|
+
result = self._affine_hull_projection(
|
|
418
|
+
as_convex_set=as_convex_set, as_affine_map=as_affine_map, as_section_map=return_all_data,
|
|
419
|
+
orthogonal=orthogonal, orthonormal=orthonormal,
|
|
420
|
+
extend=extend, minimal=minimal, **kwds)
|
|
421
|
+
|
|
422
|
+
# assemble result
|
|
423
|
+
if return_all_data or (as_convex_set and as_affine_map):
|
|
424
|
+
return result
|
|
425
|
+
elif as_affine_map:
|
|
426
|
+
return (result.projection_linear_map, result.projection_translation)
|
|
427
|
+
else:
|
|
428
|
+
return result.image
|
|
429
|
+
|
|
430
|
+
def codimension(self):
|
|
431
|
+
r"""
|
|
432
|
+
Return the codimension of ``self`` in ``self.ambient()``.
|
|
433
|
+
|
|
434
|
+
EXAMPLES::
|
|
435
|
+
|
|
436
|
+
sage: P = Polyhedron(vertices=[(1,2,3)], rays=[(1,0,0)])
|
|
437
|
+
sage: P.codimension()
|
|
438
|
+
2
|
|
439
|
+
|
|
440
|
+
An alias is :meth:`codim`::
|
|
441
|
+
|
|
442
|
+
sage: P.codim()
|
|
443
|
+
2
|
|
444
|
+
"""
|
|
445
|
+
return self.ambient_dim() - self.dim()
|
|
446
|
+
|
|
447
|
+
codim = codimension
|
|
448
|
+
|
|
449
|
+
def is_full_dimensional(self):
|
|
450
|
+
r"""
|
|
451
|
+
Return whether ``self`` is full dimensional.
|
|
452
|
+
|
|
453
|
+
OUTPUT: boolean; whether the polyhedron is not contained in any strict
|
|
454
|
+
affine subspace
|
|
455
|
+
|
|
456
|
+
EXAMPLES::
|
|
457
|
+
|
|
458
|
+
sage: c = Cone([(1,0)])
|
|
459
|
+
sage: c.is_full_dimensional()
|
|
460
|
+
False
|
|
461
|
+
|
|
462
|
+
sage: polytopes.hypercube(3).is_full_dimensional()
|
|
463
|
+
True
|
|
464
|
+
sage: Polyhedron(vertices=[(1,2,3)], rays=[(1,0,0)]).is_full_dimensional()
|
|
465
|
+
False
|
|
466
|
+
"""
|
|
467
|
+
return self.dim() == self.ambient_dim()
|
|
468
|
+
|
|
469
|
+
def is_open(self):
|
|
470
|
+
r"""
|
|
471
|
+
Return whether ``self`` is open.
|
|
472
|
+
|
|
473
|
+
The default implementation of this method only knows that the
|
|
474
|
+
empty set and the ambient space are open.
|
|
475
|
+
|
|
476
|
+
OUTPUT: boolean
|
|
477
|
+
|
|
478
|
+
EXAMPLES::
|
|
479
|
+
|
|
480
|
+
sage: from sage.geometry.convex_set import ConvexSet_base
|
|
481
|
+
sage: class ExampleSet(ConvexSet_base):
|
|
482
|
+
....: def is_empty(self):
|
|
483
|
+
....: return False
|
|
484
|
+
....: def is_universe(self):
|
|
485
|
+
....: return True
|
|
486
|
+
sage: ExampleSet().is_open()
|
|
487
|
+
True
|
|
488
|
+
"""
|
|
489
|
+
if self.is_empty() or self.is_universe():
|
|
490
|
+
return True
|
|
491
|
+
raise NotImplementedError
|
|
492
|
+
|
|
493
|
+
def is_relatively_open(self):
|
|
494
|
+
r"""
|
|
495
|
+
Return whether ``self`` is relatively open.
|
|
496
|
+
|
|
497
|
+
The default implementation of this method only knows that open
|
|
498
|
+
sets are also relatively open, and in addition singletons are
|
|
499
|
+
relatively open.
|
|
500
|
+
|
|
501
|
+
OUTPUT: boolean
|
|
502
|
+
|
|
503
|
+
EXAMPLES::
|
|
504
|
+
|
|
505
|
+
sage: from sage.geometry.convex_set import ConvexSet_base
|
|
506
|
+
sage: class ExampleSet(ConvexSet_base):
|
|
507
|
+
....: def is_open(self):
|
|
508
|
+
....: return True
|
|
509
|
+
sage: ExampleSet().is_relatively_open()
|
|
510
|
+
True
|
|
511
|
+
"""
|
|
512
|
+
if self.is_open():
|
|
513
|
+
return True
|
|
514
|
+
if self.dim() == 0:
|
|
515
|
+
return True
|
|
516
|
+
raise NotImplementedError
|
|
517
|
+
|
|
518
|
+
def is_closed(self):
|
|
519
|
+
r"""
|
|
520
|
+
Return whether ``self`` is closed.
|
|
521
|
+
|
|
522
|
+
The default implementation of this method only knows that the
|
|
523
|
+
empty set, a singleton set, and the ambient space are closed.
|
|
524
|
+
|
|
525
|
+
OUTPUT: boolean
|
|
526
|
+
|
|
527
|
+
EXAMPLES::
|
|
528
|
+
|
|
529
|
+
sage: from sage.geometry.convex_set import ConvexSet_base
|
|
530
|
+
sage: class ExampleSet(ConvexSet_base):
|
|
531
|
+
....: def dim(self):
|
|
532
|
+
....: return 0
|
|
533
|
+
sage: ExampleSet().is_closed()
|
|
534
|
+
True
|
|
535
|
+
"""
|
|
536
|
+
if self.is_empty() or self.dim() == 0 or self.is_universe():
|
|
537
|
+
return True
|
|
538
|
+
raise NotImplementedError
|
|
539
|
+
|
|
540
|
+
def is_compact(self):
|
|
541
|
+
r"""
|
|
542
|
+
Return whether ``self`` is compact.
|
|
543
|
+
|
|
544
|
+
The default implementation of this method only knows that a
|
|
545
|
+
non-closed set cannot be compact, and that the empty set and
|
|
546
|
+
a singleton set are compact.
|
|
547
|
+
|
|
548
|
+
OUTPUT: boolean
|
|
549
|
+
|
|
550
|
+
sage: from sage.geometry.convex_set import ConvexSet_base
|
|
551
|
+
sage: class ExampleSet(ConvexSet_base):
|
|
552
|
+
....: def dim(self):
|
|
553
|
+
....: return 0
|
|
554
|
+
sage: ExampleSet().is_compact()
|
|
555
|
+
True
|
|
556
|
+
"""
|
|
557
|
+
if not self.is_closed():
|
|
558
|
+
return False
|
|
559
|
+
if self.dim() < 1:
|
|
560
|
+
return True
|
|
561
|
+
raise NotImplementedError
|
|
562
|
+
|
|
563
|
+
def closure(self):
|
|
564
|
+
r"""
|
|
565
|
+
Return the topological closure of ``self``.
|
|
566
|
+
|
|
567
|
+
EXAMPLES::
|
|
568
|
+
|
|
569
|
+
sage: from sage.geometry.convex_set import ConvexSet_closed
|
|
570
|
+
sage: C = ConvexSet_closed()
|
|
571
|
+
sage: C.closure() is C
|
|
572
|
+
True
|
|
573
|
+
"""
|
|
574
|
+
if self.is_closed():
|
|
575
|
+
return self
|
|
576
|
+
raise NotImplementedError
|
|
577
|
+
|
|
578
|
+
def interior(self):
|
|
579
|
+
r"""
|
|
580
|
+
Return the topological interior of ``self``.
|
|
581
|
+
|
|
582
|
+
EXAMPLES::
|
|
583
|
+
|
|
584
|
+
sage: from sage.geometry.convex_set import ConvexSet_open
|
|
585
|
+
sage: C = ConvexSet_open()
|
|
586
|
+
sage: C.interior() is C
|
|
587
|
+
True
|
|
588
|
+
"""
|
|
589
|
+
if self.is_open():
|
|
590
|
+
return self
|
|
591
|
+
raise NotImplementedError
|
|
592
|
+
|
|
593
|
+
def relative_interior(self):
|
|
594
|
+
r"""
|
|
595
|
+
Return the relative interior of ``self``.
|
|
596
|
+
|
|
597
|
+
EXAMPLES::
|
|
598
|
+
|
|
599
|
+
sage: from sage.geometry.convex_set import ConvexSet_relatively_open
|
|
600
|
+
sage: C = ConvexSet_relatively_open()
|
|
601
|
+
sage: C.relative_interior() is C
|
|
602
|
+
True
|
|
603
|
+
"""
|
|
604
|
+
if self.is_relatively_open():
|
|
605
|
+
return self
|
|
606
|
+
raise NotImplementedError
|
|
607
|
+
|
|
608
|
+
@cached_method
|
|
609
|
+
def representative_point(self):
|
|
610
|
+
"""
|
|
611
|
+
Return a "generic" point of ``self``.
|
|
612
|
+
|
|
613
|
+
OUTPUT: a point in the relative interior of ``self`` as a coordinate vector
|
|
614
|
+
|
|
615
|
+
EXAMPLES::
|
|
616
|
+
|
|
617
|
+
sage: C = Cone([[1, 2, 0], [2, 1, 0]])
|
|
618
|
+
sage: C.representative_point()
|
|
619
|
+
(1, 1, 0)
|
|
620
|
+
"""
|
|
621
|
+
affine_basis = self.an_affine_basis()
|
|
622
|
+
return sum(affine_basis) / len(affine_basis)
|
|
623
|
+
|
|
624
|
+
def _test_convex_set(self, tester=None, **options):
|
|
625
|
+
"""
|
|
626
|
+
Run some tests on the methods of :class:`ConvexSet_base`.
|
|
627
|
+
|
|
628
|
+
TESTS::
|
|
629
|
+
|
|
630
|
+
sage: from sage.geometry.convex_set import ConvexSet_open
|
|
631
|
+
sage: class FaultyConvexSet(ConvexSet_open):
|
|
632
|
+
....: def ambient(self):
|
|
633
|
+
....: return QQ^55
|
|
634
|
+
....: def ambient_vector_space(self, base_field=None):
|
|
635
|
+
....: return QQ^16
|
|
636
|
+
....: def is_universe(self):
|
|
637
|
+
....: return True
|
|
638
|
+
....: def dim(self):
|
|
639
|
+
....: return 42
|
|
640
|
+
....: def ambient_dim(self):
|
|
641
|
+
....: return 91
|
|
642
|
+
sage: TestSuite(FaultyConvexSet()).run(skip=('_test_pickling', '_test_contains', '_test_as_set_object'))
|
|
643
|
+
Failure in _test_convex_set:
|
|
644
|
+
...
|
|
645
|
+
The following tests failed: _test_convex_set
|
|
646
|
+
|
|
647
|
+
sage: class BiggerOnTheInside(ConvexSet_open):
|
|
648
|
+
....: def dim(self):
|
|
649
|
+
....: return 100000
|
|
650
|
+
....: def ambient_vector_space(self):
|
|
651
|
+
....: return QQ^3
|
|
652
|
+
....: def ambient(self):
|
|
653
|
+
....: return QQ^3
|
|
654
|
+
....: def ambient_dim(self):
|
|
655
|
+
....: return 3
|
|
656
|
+
sage: TestSuite(BiggerOnTheInside()).run(skip=('_test_pickling', '_test_contains', '_test_as_set_object'))
|
|
657
|
+
Failure in _test_convex_set:
|
|
658
|
+
...
|
|
659
|
+
The following tests failed: _test_convex_set
|
|
660
|
+
"""
|
|
661
|
+
if tester is None:
|
|
662
|
+
tester = self._tester(**options)
|
|
663
|
+
dim = self.dim()
|
|
664
|
+
codim = self.codim()
|
|
665
|
+
tester.assertLessEqual(dim, self.ambient_dim())
|
|
666
|
+
if dim >= 0:
|
|
667
|
+
tester.assertEqual(dim + codim, self.ambient_dim())
|
|
668
|
+
if self.is_empty():
|
|
669
|
+
tester.assertEqual(dim, -1)
|
|
670
|
+
if self.is_universe():
|
|
671
|
+
tester.assertTrue(self.is_full_dimensional())
|
|
672
|
+
cl_self = self.closure()
|
|
673
|
+
try:
|
|
674
|
+
int_self = self.interior()
|
|
675
|
+
except NotImplementedError:
|
|
676
|
+
int_self = None
|
|
677
|
+
try:
|
|
678
|
+
relint_self = self.relative_interior()
|
|
679
|
+
except NotImplementedError:
|
|
680
|
+
relint_self = None
|
|
681
|
+
if self.is_full_dimensional():
|
|
682
|
+
tester.assertEqual(int_self, relint_self)
|
|
683
|
+
if self.is_relatively_open():
|
|
684
|
+
tester.assertEqual(self, relint_self)
|
|
685
|
+
if self.is_open():
|
|
686
|
+
tester.assertEqual(self, int_self)
|
|
687
|
+
if self.is_closed():
|
|
688
|
+
tester.assertEqual(self, cl_self)
|
|
689
|
+
if self.is_compact():
|
|
690
|
+
tester.assertTrue(self.is_closed())
|
|
691
|
+
from sage.misc.sage_unittest import TestSuite
|
|
692
|
+
if relint_self is not None and relint_self is not self:
|
|
693
|
+
tester.info("\n Running the test suite of self.relative_interior()")
|
|
694
|
+
TestSuite(relint_self).run(verbose=tester._verbose,
|
|
695
|
+
prefix=tester._prefix + " ")
|
|
696
|
+
tester.info(tester._prefix + " ", newline=False)
|
|
697
|
+
|
|
698
|
+
# Optional methods
|
|
699
|
+
|
|
700
|
+
def an_element(self):
|
|
701
|
+
r"""
|
|
702
|
+
Return a point of ``self``.
|
|
703
|
+
|
|
704
|
+
If ``self`` is empty, an :exc:`EmptySetError` will be raised.
|
|
705
|
+
|
|
706
|
+
The default implementation delegates to :meth:`_some_elements_`.
|
|
707
|
+
|
|
708
|
+
EXAMPLES::
|
|
709
|
+
|
|
710
|
+
sage: from sage.geometry.convex_set import ConvexSet_compact
|
|
711
|
+
sage: class BlueBox(ConvexSet_compact):
|
|
712
|
+
....: def _some_elements_(self):
|
|
713
|
+
....: yield 'blue'
|
|
714
|
+
....: yield 'cyan'
|
|
715
|
+
sage: BlueBox().an_element()
|
|
716
|
+
'blue'
|
|
717
|
+
"""
|
|
718
|
+
if self._some_elements_ == NotImplemented:
|
|
719
|
+
raise NotImplementedError
|
|
720
|
+
try:
|
|
721
|
+
return next(iter(self._some_elements_()))
|
|
722
|
+
except StopIteration:
|
|
723
|
+
raise EmptySetError
|
|
724
|
+
|
|
725
|
+
def some_elements(self):
|
|
726
|
+
r"""
|
|
727
|
+
Return a list of some points of ``self``.
|
|
728
|
+
|
|
729
|
+
If ``self`` is empty, an empty list is returned; no exception will be raised.
|
|
730
|
+
|
|
731
|
+
The default implementation delegates to :meth:`_some_elements_`.
|
|
732
|
+
|
|
733
|
+
EXAMPLES::
|
|
734
|
+
|
|
735
|
+
sage: from sage.geometry.convex_set import ConvexSet_compact
|
|
736
|
+
sage: class BlueBox(ConvexSet_compact):
|
|
737
|
+
....: def _some_elements_(self):
|
|
738
|
+
....: yield 'blue'
|
|
739
|
+
....: yield 'cyan'
|
|
740
|
+
sage: BlueBox().some_elements()
|
|
741
|
+
['blue', 'cyan']
|
|
742
|
+
"""
|
|
743
|
+
if self._some_elements_ == NotImplemented:
|
|
744
|
+
raise NotImplementedError
|
|
745
|
+
return list(self._some_elements_())
|
|
746
|
+
|
|
747
|
+
def _some_elements_(self):
|
|
748
|
+
r"""
|
|
749
|
+
Generate some points of ``self``.
|
|
750
|
+
|
|
751
|
+
If ``self`` is empty, no points are generated; no exception will be raised.
|
|
752
|
+
|
|
753
|
+
TESTS::
|
|
754
|
+
|
|
755
|
+
sage: from sage.geometry.convex_set import ConvexSet_base
|
|
756
|
+
sage: C = ConvexSet_base()
|
|
757
|
+
sage: list(C._some_elements_())
|
|
758
|
+
Traceback (most recent call last):
|
|
759
|
+
...
|
|
760
|
+
TypeError: 'NotImplementedType' object is not callable
|
|
761
|
+
"""
|
|
762
|
+
yield self.representative_point()
|
|
763
|
+
|
|
764
|
+
@abstract_method(optional=True)
|
|
765
|
+
def cartesian_product(self, other):
|
|
766
|
+
"""
|
|
767
|
+
Return the Cartesian product.
|
|
768
|
+
|
|
769
|
+
INPUT:
|
|
770
|
+
|
|
771
|
+
- ``other`` -- another convex set
|
|
772
|
+
|
|
773
|
+
OUTPUT: the Cartesian product of ``self`` and ``other``
|
|
774
|
+
|
|
775
|
+
TESTS::
|
|
776
|
+
|
|
777
|
+
sage: from sage.geometry.convex_set import ConvexSet_base
|
|
778
|
+
sage: C = ConvexSet_base()
|
|
779
|
+
sage: C.cartesian_product(C)
|
|
780
|
+
Traceback (most recent call last):
|
|
781
|
+
...
|
|
782
|
+
TypeError: 'NotImplementedType' object is not callable
|
|
783
|
+
"""
|
|
784
|
+
|
|
785
|
+
@abstract_method(optional=True)
|
|
786
|
+
def contains(self, point):
|
|
787
|
+
"""
|
|
788
|
+
Test whether ``self`` contains the given ``point``.
|
|
789
|
+
|
|
790
|
+
INPUT:
|
|
791
|
+
|
|
792
|
+
- ``point`` -- a point or its coordinates
|
|
793
|
+
|
|
794
|
+
TESTS::
|
|
795
|
+
|
|
796
|
+
sage: from sage.geometry.convex_set import ConvexSet_base
|
|
797
|
+
sage: C = ConvexSet_base()
|
|
798
|
+
sage: C.contains(vector([0, 0]))
|
|
799
|
+
Traceback (most recent call last):
|
|
800
|
+
...
|
|
801
|
+
TypeError: 'NotImplementedType' object is not callable
|
|
802
|
+
"""
|
|
803
|
+
|
|
804
|
+
def _test_contains(self, tester=None, **options):
|
|
805
|
+
"""
|
|
806
|
+
Test the ``contains`` method.
|
|
807
|
+
|
|
808
|
+
EXAMPLES::
|
|
809
|
+
|
|
810
|
+
sage: from sage.geometry.convex_set import ConvexSet_closed
|
|
811
|
+
sage: class FaultyConvexSet(ConvexSet_closed):
|
|
812
|
+
....: def ambient_vector_space(self, base_field=QQ):
|
|
813
|
+
....: return base_field^2
|
|
814
|
+
....: ambient = ambient_vector_space
|
|
815
|
+
....: def contains(self, point):
|
|
816
|
+
....: if isinstance(point, (tuple, list)):
|
|
817
|
+
....: return all(x in ZZ for x in point)
|
|
818
|
+
....: return point.parent() == ZZ^2
|
|
819
|
+
sage: FaultyConvexSet()._test_contains()
|
|
820
|
+
Traceback (most recent call last):
|
|
821
|
+
...
|
|
822
|
+
AssertionError: False != True
|
|
823
|
+
|
|
824
|
+
sage: class AlsoFaultyConvexSet(ConvexSet_closed):
|
|
825
|
+
....: def ambient_vector_space(self, base_field=QQ):
|
|
826
|
+
....: return base_field^2
|
|
827
|
+
....: def ambient(self):
|
|
828
|
+
....: return ZZ^2
|
|
829
|
+
....: def contains(self, point):
|
|
830
|
+
....: return point in ZZ^2
|
|
831
|
+
sage: AlsoFaultyConvexSet()._test_contains()
|
|
832
|
+
Traceback (most recent call last):
|
|
833
|
+
...
|
|
834
|
+
AssertionError: True != False
|
|
835
|
+
"""
|
|
836
|
+
if tester is None:
|
|
837
|
+
tester = self._tester(**options)
|
|
838
|
+
ambient = self.ambient()
|
|
839
|
+
space = self.ambient_vector_space()
|
|
840
|
+
try:
|
|
841
|
+
ambient_point = ambient.an_element()
|
|
842
|
+
except (AttributeError, NotImplementedError, EmptySetError):
|
|
843
|
+
ambient_point = None
|
|
844
|
+
space_point = space.an_element()
|
|
845
|
+
else:
|
|
846
|
+
space_point = space(ambient_point)
|
|
847
|
+
space_coords = space.coordinates(space_point)
|
|
848
|
+
if self.contains != NotImplemented:
|
|
849
|
+
contains_space_point = self.contains(space_point)
|
|
850
|
+
if ambient_point is not None:
|
|
851
|
+
tester.assertEqual(contains_space_point, self.contains(ambient_point))
|
|
852
|
+
tester.assertEqual(contains_space_point, self.contains(space_coords))
|
|
853
|
+
if space.base_ring().is_exact():
|
|
854
|
+
try:
|
|
855
|
+
from sage.rings.qqbar import AA
|
|
856
|
+
except ImportError:
|
|
857
|
+
pass
|
|
858
|
+
else:
|
|
859
|
+
ext_space = self.ambient_vector_space(AA)
|
|
860
|
+
ext_space_point = ext_space(space_point)
|
|
861
|
+
tester.assertEqual(contains_space_point, self.contains(ext_space_point))
|
|
862
|
+
try:
|
|
863
|
+
from sage.symbolic.ring import SR
|
|
864
|
+
symbolic_space = self.ambient_vector_space(SR)
|
|
865
|
+
symbolic_space_point = symbolic_space(space_point)
|
|
866
|
+
# Only test that it can accept SR vectors without error.
|
|
867
|
+
self.contains(symbolic_space_point)
|
|
868
|
+
except ImportError:
|
|
869
|
+
pass
|
|
870
|
+
# Test that elements returned by some_elements are contained.
|
|
871
|
+
try:
|
|
872
|
+
points = self.some_elements()
|
|
873
|
+
except NotImplementedError:
|
|
874
|
+
pass
|
|
875
|
+
else:
|
|
876
|
+
for point in points:
|
|
877
|
+
tester.assertTrue(self.contains(point))
|
|
878
|
+
tester.assertIn(point, self)
|
|
879
|
+
|
|
880
|
+
@abstract_method(optional=True)
|
|
881
|
+
def intersection(self, other):
|
|
882
|
+
r"""
|
|
883
|
+
Return the intersection of ``self`` and ``other``.
|
|
884
|
+
|
|
885
|
+
INPUT:
|
|
886
|
+
|
|
887
|
+
- ``other`` -- another convex set
|
|
888
|
+
|
|
889
|
+
OUTPUT: the intersection
|
|
890
|
+
|
|
891
|
+
TESTS::
|
|
892
|
+
|
|
893
|
+
sage: from sage.geometry.convex_set import ConvexSet_base
|
|
894
|
+
sage: C = ConvexSet_base()
|
|
895
|
+
sage: C.intersection(C)
|
|
896
|
+
Traceback (most recent call last):
|
|
897
|
+
...
|
|
898
|
+
TypeError: 'NotImplementedType' object is not callable
|
|
899
|
+
"""
|
|
900
|
+
|
|
901
|
+
def dilation(self, scalar):
|
|
902
|
+
"""
|
|
903
|
+
Return the dilated (uniformly stretched) set.
|
|
904
|
+
|
|
905
|
+
INPUT:
|
|
906
|
+
|
|
907
|
+
- ``scalar`` -- a scalar, not necessarily in :meth:`base_ring`
|
|
908
|
+
|
|
909
|
+
EXAMPLES::
|
|
910
|
+
|
|
911
|
+
sage: from sage.geometry.convex_set import ConvexSet_compact
|
|
912
|
+
sage: class GlorifiedPoint(ConvexSet_compact):
|
|
913
|
+
....: def __init__(self, p):
|
|
914
|
+
....: self._p = p
|
|
915
|
+
....: def ambient_vector_space(self):
|
|
916
|
+
....: return self._p.parent().vector_space()
|
|
917
|
+
....: def linear_transformation(self, linear_transf):
|
|
918
|
+
....: return GlorifiedPoint(linear_transf * self._p)
|
|
919
|
+
sage: P = GlorifiedPoint(vector([2, 3]))
|
|
920
|
+
sage: P.dilation(10)._p
|
|
921
|
+
(20, 30)
|
|
922
|
+
"""
|
|
923
|
+
linear_transf = scalar * matrix.identity(self.ambient_dim())
|
|
924
|
+
return self.linear_transformation(linear_transf)
|
|
925
|
+
|
|
926
|
+
@abstract_method(optional=True)
|
|
927
|
+
def linear_transformation(self, linear_transf):
|
|
928
|
+
"""
|
|
929
|
+
Return the linear transformation of ``self``.
|
|
930
|
+
|
|
931
|
+
INPUT:
|
|
932
|
+
|
|
933
|
+
- ``linear_transf`` -- a matrix
|
|
934
|
+
|
|
935
|
+
TESTS::
|
|
936
|
+
|
|
937
|
+
sage: from sage.geometry.convex_set import ConvexSet_base
|
|
938
|
+
sage: C = ConvexSet_base()
|
|
939
|
+
sage: T = matrix.identity(3)
|
|
940
|
+
sage: C.linear_transformation(T)
|
|
941
|
+
Traceback (most recent call last):
|
|
942
|
+
...
|
|
943
|
+
TypeError: 'NotImplementedType' object is not callable
|
|
944
|
+
"""
|
|
945
|
+
|
|
946
|
+
@abstract_method(optional=True)
|
|
947
|
+
def translation(self, displacement):
|
|
948
|
+
"""
|
|
949
|
+
Return the translation of ``self`` by a ``displacement`` vector.
|
|
950
|
+
|
|
951
|
+
INPUT:
|
|
952
|
+
|
|
953
|
+
- ``displacement`` -- a displacement vector or a list/tuple of
|
|
954
|
+
coordinates that determines a displacement vector
|
|
955
|
+
|
|
956
|
+
TESTS::
|
|
957
|
+
|
|
958
|
+
sage: from sage.geometry.convex_set import ConvexSet_base
|
|
959
|
+
sage: C = ConvexSet_base()
|
|
960
|
+
sage: t = vector([1, 2, 3])
|
|
961
|
+
sage: C.translation(t)
|
|
962
|
+
Traceback (most recent call last):
|
|
963
|
+
...
|
|
964
|
+
TypeError: 'NotImplementedType' object is not callable
|
|
965
|
+
"""
|
|
966
|
+
|
|
967
|
+
|
|
968
|
+
class ConvexSet_closed(ConvexSet_base):
|
|
969
|
+
r"""
|
|
970
|
+
Abstract base class for closed convex sets.
|
|
971
|
+
"""
|
|
972
|
+
|
|
973
|
+
def is_closed(self):
|
|
974
|
+
r"""
|
|
975
|
+
Return whether ``self`` is closed.
|
|
976
|
+
|
|
977
|
+
OUTPUT: boolean
|
|
978
|
+
|
|
979
|
+
EXAMPLES::
|
|
980
|
+
|
|
981
|
+
sage: hcube = polytopes.hypercube(5)
|
|
982
|
+
sage: hcube.is_closed()
|
|
983
|
+
True
|
|
984
|
+
"""
|
|
985
|
+
return True
|
|
986
|
+
|
|
987
|
+
def is_open(self):
|
|
988
|
+
r"""
|
|
989
|
+
Return whether ``self`` is open.
|
|
990
|
+
|
|
991
|
+
OUTPUT: boolean
|
|
992
|
+
|
|
993
|
+
EXAMPLES::
|
|
994
|
+
|
|
995
|
+
sage: hcube = polytopes.hypercube(5)
|
|
996
|
+
sage: hcube.is_open()
|
|
997
|
+
False
|
|
998
|
+
|
|
999
|
+
sage: zerocube = polytopes.hypercube(0)
|
|
1000
|
+
sage: zerocube.is_open()
|
|
1001
|
+
True
|
|
1002
|
+
"""
|
|
1003
|
+
return self.is_empty() or self.is_universe()
|
|
1004
|
+
|
|
1005
|
+
|
|
1006
|
+
class ConvexSet_compact(ConvexSet_closed):
|
|
1007
|
+
r"""
|
|
1008
|
+
Abstract base class for compact convex sets.
|
|
1009
|
+
"""
|
|
1010
|
+
|
|
1011
|
+
def is_universe(self):
|
|
1012
|
+
r"""
|
|
1013
|
+
Return whether ``self`` is the whole ambient space.
|
|
1014
|
+
|
|
1015
|
+
OUTPUT: boolean
|
|
1016
|
+
|
|
1017
|
+
EXAMPLES::
|
|
1018
|
+
|
|
1019
|
+
sage: cross3 = lattice_polytope.cross_polytope(3)
|
|
1020
|
+
sage: cross3.is_universe()
|
|
1021
|
+
False
|
|
1022
|
+
sage: point0 = LatticePolytope([[]]); point0
|
|
1023
|
+
0-d reflexive polytope in 0-d lattice M
|
|
1024
|
+
sage: point0.is_universe()
|
|
1025
|
+
True
|
|
1026
|
+
"""
|
|
1027
|
+
return self.ambient_dim() == 0 and not self.is_empty()
|
|
1028
|
+
|
|
1029
|
+
def is_compact(self):
|
|
1030
|
+
r"""
|
|
1031
|
+
Return whether ``self`` is compact.
|
|
1032
|
+
|
|
1033
|
+
OUTPUT: boolean
|
|
1034
|
+
|
|
1035
|
+
EXAMPLES::
|
|
1036
|
+
|
|
1037
|
+
sage: cross3 = lattice_polytope.cross_polytope(3)
|
|
1038
|
+
sage: cross3.is_compact()
|
|
1039
|
+
True
|
|
1040
|
+
"""
|
|
1041
|
+
return True
|
|
1042
|
+
|
|
1043
|
+
is_relatively_open = ConvexSet_closed.is_open
|
|
1044
|
+
|
|
1045
|
+
|
|
1046
|
+
class ConvexSet_relatively_open(ConvexSet_base):
|
|
1047
|
+
r"""
|
|
1048
|
+
Abstract base class for relatively open convex sets.
|
|
1049
|
+
"""
|
|
1050
|
+
|
|
1051
|
+
def is_relatively_open(self):
|
|
1052
|
+
r"""
|
|
1053
|
+
Return whether ``self`` is relatively open.
|
|
1054
|
+
|
|
1055
|
+
OUTPUT: boolean
|
|
1056
|
+
|
|
1057
|
+
EXAMPLES::
|
|
1058
|
+
|
|
1059
|
+
sage: segment = Polyhedron([[1, 2], [3, 4]])
|
|
1060
|
+
sage: ri_segment = segment.relative_interior()
|
|
1061
|
+
sage: ri_segment.is_relatively_open()
|
|
1062
|
+
True
|
|
1063
|
+
"""
|
|
1064
|
+
return True
|
|
1065
|
+
|
|
1066
|
+
def is_open(self):
|
|
1067
|
+
r"""
|
|
1068
|
+
Return whether ``self`` is open.
|
|
1069
|
+
|
|
1070
|
+
OUTPUT: boolean
|
|
1071
|
+
|
|
1072
|
+
EXAMPLES::
|
|
1073
|
+
|
|
1074
|
+
sage: segment = Polyhedron([[1, 2], [3, 4]])
|
|
1075
|
+
sage: ri_segment = segment.relative_interior()
|
|
1076
|
+
sage: ri_segment.is_open()
|
|
1077
|
+
False
|
|
1078
|
+
"""
|
|
1079
|
+
return self.is_empty() or self.is_full_dimensional()
|
|
1080
|
+
|
|
1081
|
+
|
|
1082
|
+
class ConvexSet_open(ConvexSet_relatively_open):
|
|
1083
|
+
r"""
|
|
1084
|
+
Abstract base class for open convex sets.
|
|
1085
|
+
"""
|
|
1086
|
+
|
|
1087
|
+
def is_open(self):
|
|
1088
|
+
r"""
|
|
1089
|
+
Return whether ``self`` is open.
|
|
1090
|
+
|
|
1091
|
+
OUTPUT: boolean
|
|
1092
|
+
|
|
1093
|
+
EXAMPLES::
|
|
1094
|
+
|
|
1095
|
+
sage: from sage.geometry.convex_set import ConvexSet_open
|
|
1096
|
+
sage: b = ConvexSet_open()
|
|
1097
|
+
sage: b.is_open()
|
|
1098
|
+
True
|
|
1099
|
+
"""
|
|
1100
|
+
return True
|
|
1101
|
+
|
|
1102
|
+
def is_closed(self):
|
|
1103
|
+
r"""
|
|
1104
|
+
Return whether ``self`` is closed.
|
|
1105
|
+
|
|
1106
|
+
OUTPUT: boolean
|
|
1107
|
+
|
|
1108
|
+
EXAMPLES::
|
|
1109
|
+
|
|
1110
|
+
sage: from sage.geometry.convex_set import ConvexSet_open
|
|
1111
|
+
sage: class OpenBall(ConvexSet_open):
|
|
1112
|
+
....: def dim(self):
|
|
1113
|
+
....: return 3
|
|
1114
|
+
....: def is_universe(self):
|
|
1115
|
+
....: return False
|
|
1116
|
+
sage: OpenBall().is_closed()
|
|
1117
|
+
False
|
|
1118
|
+
"""
|
|
1119
|
+
return self.is_empty() or self.is_universe()
|