passagemath-polyhedra 10.6.31rc3__cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-polyhedra might be problematic. Click here for more details.
- passagemath_polyhedra-10.6.31rc3.dist-info/METADATA +367 -0
- passagemath_polyhedra-10.6.31rc3.dist-info/METADATA.bak +369 -0
- passagemath_polyhedra-10.6.31rc3.dist-info/RECORD +206 -0
- passagemath_polyhedra-10.6.31rc3.dist-info/WHEEL +6 -0
- passagemath_polyhedra-10.6.31rc3.dist-info/top_level.txt +2 -0
- passagemath_polyhedra.libs/libgmp-6e109695.so.10.5.0 +0 -0
- passagemath_polyhedra.libs/libgomp-e985bcbb.so.1.0.0 +0 -0
- sage/all__sagemath_polyhedra.py +50 -0
- sage/game_theory/all.py +8 -0
- sage/game_theory/catalog.py +6 -0
- sage/game_theory/catalog_normal_form_games.py +923 -0
- sage/game_theory/cooperative_game.py +844 -0
- sage/game_theory/matching_game.py +1181 -0
- sage/game_theory/normal_form_game.py +2697 -0
- sage/game_theory/parser.py +275 -0
- sage/geometry/all__sagemath_polyhedra.py +22 -0
- sage/geometry/cone.py +6940 -0
- sage/geometry/cone_catalog.py +847 -0
- sage/geometry/cone_critical_angles.py +1027 -0
- sage/geometry/convex_set.py +1119 -0
- sage/geometry/fan.py +3743 -0
- sage/geometry/fan_isomorphism.py +389 -0
- sage/geometry/fan_morphism.py +1884 -0
- sage/geometry/hasse_diagram.py +202 -0
- sage/geometry/hyperplane_arrangement/affine_subspace.py +390 -0
- sage/geometry/hyperplane_arrangement/all.py +1 -0
- sage/geometry/hyperplane_arrangement/arrangement.py +3895 -0
- sage/geometry/hyperplane_arrangement/check_freeness.py +145 -0
- sage/geometry/hyperplane_arrangement/hyperplane.py +773 -0
- sage/geometry/hyperplane_arrangement/library.py +825 -0
- sage/geometry/hyperplane_arrangement/ordered_arrangement.py +642 -0
- sage/geometry/hyperplane_arrangement/plot.py +520 -0
- sage/geometry/integral_points.py +35 -0
- sage/geometry/integral_points_generic_dense.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/geometry/integral_points_generic_dense.pyx +7 -0
- sage/geometry/lattice_polytope.py +5894 -0
- sage/geometry/linear_expression.py +773 -0
- sage/geometry/newton_polygon.py +767 -0
- sage/geometry/point_collection.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/geometry/point_collection.pyx +1008 -0
- sage/geometry/polyhedral_complex.py +2616 -0
- sage/geometry/polyhedron/all.py +8 -0
- sage/geometry/polyhedron/backend_cdd.py +460 -0
- sage/geometry/polyhedron/backend_cdd_rdf.py +231 -0
- sage/geometry/polyhedron/backend_field.py +347 -0
- sage/geometry/polyhedron/backend_normaliz.py +2503 -0
- sage/geometry/polyhedron/backend_number_field.py +168 -0
- sage/geometry/polyhedron/backend_polymake.py +765 -0
- sage/geometry/polyhedron/backend_ppl.py +582 -0
- sage/geometry/polyhedron/base.py +1206 -0
- sage/geometry/polyhedron/base0.py +1444 -0
- sage/geometry/polyhedron/base1.py +886 -0
- sage/geometry/polyhedron/base2.py +812 -0
- sage/geometry/polyhedron/base3.py +1845 -0
- sage/geometry/polyhedron/base4.py +1262 -0
- sage/geometry/polyhedron/base5.py +2700 -0
- sage/geometry/polyhedron/base6.py +1741 -0
- sage/geometry/polyhedron/base7.py +997 -0
- sage/geometry/polyhedron/base_QQ.py +1258 -0
- sage/geometry/polyhedron/base_RDF.py +98 -0
- sage/geometry/polyhedron/base_ZZ.py +934 -0
- sage/geometry/polyhedron/base_mutable.py +215 -0
- sage/geometry/polyhedron/base_number_field.py +122 -0
- sage/geometry/polyhedron/cdd_file_format.py +155 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/all.py +1 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/base.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd +76 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +3859 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pxd +39 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx +1038 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/conversions.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pxd +9 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx +501 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_data_structure.pxd +207 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd +102 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +2274 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pxd +370 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pyx +84 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pxd +31 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx +587 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pxd +52 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx +560 -0
- sage/geometry/polyhedron/constructor.py +773 -0
- sage/geometry/polyhedron/double_description.py +753 -0
- sage/geometry/polyhedron/double_description_inhomogeneous.py +564 -0
- sage/geometry/polyhedron/face.py +1060 -0
- sage/geometry/polyhedron/generating_function.py +1810 -0
- sage/geometry/polyhedron/lattice_euclidean_group_element.py +178 -0
- sage/geometry/polyhedron/library.py +3502 -0
- sage/geometry/polyhedron/misc.py +121 -0
- sage/geometry/polyhedron/modules/all.py +1 -0
- sage/geometry/polyhedron/modules/formal_polyhedra_module.py +155 -0
- sage/geometry/polyhedron/palp_database.py +447 -0
- sage/geometry/polyhedron/parent.py +1279 -0
- sage/geometry/polyhedron/plot.py +1986 -0
- sage/geometry/polyhedron/ppl_lattice_polygon.py +556 -0
- sage/geometry/polyhedron/ppl_lattice_polytope.py +1257 -0
- sage/geometry/polyhedron/representation.py +1723 -0
- sage/geometry/pseudolines.py +515 -0
- sage/geometry/relative_interior.py +445 -0
- sage/geometry/toric_plotter.py +1103 -0
- sage/geometry/triangulation/all.py +2 -0
- sage/geometry/triangulation/base.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/geometry/triangulation/base.pyx +963 -0
- sage/geometry/triangulation/data.h +147 -0
- sage/geometry/triangulation/data.pxd +4 -0
- sage/geometry/triangulation/element.py +914 -0
- sage/geometry/triangulation/functions.h +10 -0
- sage/geometry/triangulation/functions.pxd +4 -0
- sage/geometry/triangulation/point_configuration.py +2256 -0
- sage/geometry/triangulation/triangulations.h +49 -0
- sage/geometry/triangulation/triangulations.pxd +7 -0
- sage/geometry/voronoi_diagram.py +319 -0
- sage/interfaces/all__sagemath_polyhedra.py +1 -0
- sage/interfaces/polymake.py +2028 -0
- sage/numerical/all.py +13 -0
- sage/numerical/all__sagemath_polyhedra.py +11 -0
- sage/numerical/backends/all.py +1 -0
- sage/numerical/backends/all__sagemath_polyhedra.py +1 -0
- sage/numerical/backends/cvxopt_backend.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/numerical/backends/cvxopt_backend.pyx +1006 -0
- sage/numerical/backends/cvxopt_backend_test.py +19 -0
- sage/numerical/backends/cvxopt_sdp_backend.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/numerical/backends/cvxopt_sdp_backend.pyx +382 -0
- sage/numerical/backends/cvxpy_backend.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/numerical/backends/cvxpy_backend.pxd +41 -0
- sage/numerical/backends/cvxpy_backend.pyx +934 -0
- sage/numerical/backends/cvxpy_backend_test.py +13 -0
- sage/numerical/backends/generic_backend_test.py +24 -0
- sage/numerical/backends/interactivelp_backend.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/numerical/backends/interactivelp_backend.pxd +36 -0
- sage/numerical/backends/interactivelp_backend.pyx +1231 -0
- sage/numerical/backends/interactivelp_backend_test.py +12 -0
- sage/numerical/backends/logging_backend.py +391 -0
- sage/numerical/backends/matrix_sdp_backend.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/numerical/backends/matrix_sdp_backend.pxd +15 -0
- sage/numerical/backends/matrix_sdp_backend.pyx +478 -0
- sage/numerical/backends/ppl_backend.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/numerical/backends/ppl_backend.pyx +1126 -0
- sage/numerical/backends/ppl_backend_test.py +13 -0
- sage/numerical/backends/scip_backend.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/numerical/backends/scip_backend.pxd +22 -0
- sage/numerical/backends/scip_backend.pyx +1289 -0
- sage/numerical/backends/scip_backend_test.py +13 -0
- sage/numerical/interactive_simplex_method.py +5338 -0
- sage/numerical/knapsack.py +665 -0
- sage/numerical/linear_functions.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/numerical/linear_functions.pxd +31 -0
- sage/numerical/linear_functions.pyx +1648 -0
- sage/numerical/linear_tensor.py +470 -0
- sage/numerical/linear_tensor_constraints.py +448 -0
- sage/numerical/linear_tensor_element.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/numerical/linear_tensor_element.pxd +6 -0
- sage/numerical/linear_tensor_element.pyx +459 -0
- sage/numerical/mip.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/numerical/mip.pxd +40 -0
- sage/numerical/mip.pyx +3667 -0
- sage/numerical/sdp.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/numerical/sdp.pxd +39 -0
- sage/numerical/sdp.pyx +1433 -0
- sage/rings/all__sagemath_polyhedra.py +3 -0
- sage/rings/polynomial/all__sagemath_polyhedra.py +10 -0
- sage/rings/polynomial/omega.py +982 -0
- sage/schemes/all__sagemath_polyhedra.py +2 -0
- sage/schemes/toric/all.py +10 -0
- sage/schemes/toric/chow_group.py +1248 -0
- sage/schemes/toric/divisor.py +2082 -0
- sage/schemes/toric/divisor_class.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/schemes/toric/divisor_class.pyx +322 -0
- sage/schemes/toric/fano_variety.py +1606 -0
- sage/schemes/toric/homset.py +650 -0
- sage/schemes/toric/ideal.py +451 -0
- sage/schemes/toric/library.py +1322 -0
- sage/schemes/toric/morphism.py +1958 -0
- sage/schemes/toric/points.py +1032 -0
- sage/schemes/toric/sheaf/all.py +1 -0
- sage/schemes/toric/sheaf/constructor.py +302 -0
- sage/schemes/toric/sheaf/klyachko.py +921 -0
- sage/schemes/toric/toric_subscheme.py +905 -0
- sage/schemes/toric/variety.py +3460 -0
- sage/schemes/toric/weierstrass.py +1078 -0
- sage/schemes/toric/weierstrass_covering.py +457 -0
- sage/schemes/toric/weierstrass_higher.py +288 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.info +10 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v03 +0 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v04 +0 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v05 +1 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v06 +1 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.info +22 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v04 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v05 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v06 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v07 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v08 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v09 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v10 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v11 +1 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v12 +1 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v13 +1 -0
- sage_wheels/share/reflexive_polytopes/reflexive_polytopes_2d +80 -0
- sage_wheels/share/reflexive_polytopes/reflexive_polytopes_3d +37977 -0
|
@@ -0,0 +1,753 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-polyhedra
|
|
2
|
+
r"""
|
|
3
|
+
Double Description Algorithm for Cones
|
|
4
|
+
|
|
5
|
+
This module implements the double description algorithm for extremal
|
|
6
|
+
vertex enumeration in a pointed cone following [FP1996]_. With a
|
|
7
|
+
little bit of preprocessing (see
|
|
8
|
+
:mod:`~sage.geometry.polyhedron.double_description_inhomogeneous`)
|
|
9
|
+
this defines a backend for polyhedral computations. But as far as this
|
|
10
|
+
module is concerned, *inequality* always means without a constant term
|
|
11
|
+
and the origin is always a point of the cone.
|
|
12
|
+
|
|
13
|
+
EXAMPLES::
|
|
14
|
+
|
|
15
|
+
sage: from sage.geometry.polyhedron.double_description import StandardAlgorithm
|
|
16
|
+
sage: A = matrix(QQ, [(1,0,1), (0,1,1), (-1,-1,1)])
|
|
17
|
+
sage: alg = StandardAlgorithm(A); alg
|
|
18
|
+
Pointed cone with inequalities
|
|
19
|
+
(1, 0, 1)
|
|
20
|
+
(0, 1, 1)
|
|
21
|
+
(-1, -1, 1)
|
|
22
|
+
sage: DD, _ = alg.initial_pair(); DD
|
|
23
|
+
Double description pair (A, R) defined by
|
|
24
|
+
[ 1 0 1] [ 2/3 -1/3 -1/3]
|
|
25
|
+
A = [ 0 1 1], R = [-1/3 2/3 -1/3]
|
|
26
|
+
[-1 -1 1] [ 1/3 1/3 1/3]
|
|
27
|
+
|
|
28
|
+
The implementation works over any exact field that is embedded in
|
|
29
|
+
`\RR`, for example::
|
|
30
|
+
|
|
31
|
+
sage: from sage.geometry.polyhedron.double_description import StandardAlgorithm
|
|
32
|
+
sage: A = matrix(AA, [(1,0,1), (0,1,1), (-AA(2).sqrt(),-AA(3).sqrt(),1), # needs sage.rings.number_field
|
|
33
|
+
....: (-AA(3).sqrt(),-AA(2).sqrt(),1)])
|
|
34
|
+
sage: alg = StandardAlgorithm(A)
|
|
35
|
+
sage: alg.run().R # needs sage.rings.number_field
|
|
36
|
+
[(-0.4177376677004119?, 0.5822623322995881?, 0.4177376677004119?),
|
|
37
|
+
(-0.2411809548974793?, -0.2411809548974793?, 0.2411809548974793?),
|
|
38
|
+
(0.07665629029830300?, 0.07665629029830300?, 0.2411809548974793?),
|
|
39
|
+
(0.5822623322995881?, -0.4177376677004119?, 0.4177376677004119?)]
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
#*****************************************************************************
|
|
43
|
+
# Copyright (C) 2014 Volker Braun <vbraun.name@gmail.com>
|
|
44
|
+
# 2015 Vincent Delecroix <20100.delecroix@gmail.com>
|
|
45
|
+
#
|
|
46
|
+
# This program is free software: you can redistribute it and/or modify
|
|
47
|
+
# it under the terms of the GNU General Public License as published by
|
|
48
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
49
|
+
# (at your option) any later version.
|
|
50
|
+
# http://www.gnu.org/licenses/
|
|
51
|
+
#*****************************************************************************
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
#*****************************************************************************
|
|
55
|
+
# TODO
|
|
56
|
+
#
|
|
57
|
+
# The adjacency check should use caching and the "combinatorial
|
|
58
|
+
# criterion" instead of the "algebraic criterion", see [FP1996]
|
|
59
|
+
# for definition. Since coefficient arithmetic is relatively expensive
|
|
60
|
+
# we should avoid it as far as possible.
|
|
61
|
+
#
|
|
62
|
+
# Also, the variants of the double description algorithm described in
|
|
63
|
+
# [FP1996] should be implemented. The design of this module is
|
|
64
|
+
# such that variants of the basic algorithm should be easy to add as
|
|
65
|
+
# subclasses of DoubleDescriptionPair and Problem.
|
|
66
|
+
# *****************************************************************************
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# Compare with PPL if the base ring is QQ. Can be left enabled since
|
|
70
|
+
# we don't use the Python fallback for polyhedra over QQ unless you
|
|
71
|
+
# construct one by hand.
|
|
72
|
+
|
|
73
|
+
VERIFY_RESULT = True
|
|
74
|
+
|
|
75
|
+
import itertools
|
|
76
|
+
|
|
77
|
+
from sage.misc.cachefunc import cached_method
|
|
78
|
+
from sage.rings.rational_field import QQ
|
|
79
|
+
from sage.modules.free_module_element import vector
|
|
80
|
+
from sage.matrix.matrix_space import MatrixSpace
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def random_inequalities(d, n):
|
|
84
|
+
"""
|
|
85
|
+
Random collections of inequalities for testing purposes.
|
|
86
|
+
|
|
87
|
+
INPUT:
|
|
88
|
+
|
|
89
|
+
- ``d`` -- integer; the dimension
|
|
90
|
+
|
|
91
|
+
- ``n`` -- integer; the number of random inequalities to generate
|
|
92
|
+
|
|
93
|
+
OUTPUT: a random set of inequalities as a :class:`StandardAlgorithm` instance
|
|
94
|
+
|
|
95
|
+
EXAMPLES::
|
|
96
|
+
|
|
97
|
+
sage: from sage.geometry.polyhedron.double_description import random_inequalities
|
|
98
|
+
sage: P = random_inequalities(5, 10)
|
|
99
|
+
sage: P.run().verify()
|
|
100
|
+
"""
|
|
101
|
+
from sage.matrix.constructor import random_matrix
|
|
102
|
+
while True:
|
|
103
|
+
A = random_matrix(QQ, n, d)
|
|
104
|
+
if A.rank() == min(n, d) and not any(a == 0 for a in A.rows()):
|
|
105
|
+
break
|
|
106
|
+
return StandardAlgorithm(A)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class DoubleDescriptionPair:
|
|
110
|
+
|
|
111
|
+
def __init__(self, problem, A_rows, R_cols):
|
|
112
|
+
r"""
|
|
113
|
+
Base class for a double description pair `(A, R)`.
|
|
114
|
+
|
|
115
|
+
.. warning::
|
|
116
|
+
|
|
117
|
+
You should use the :meth:`Problem.initial_pair` or
|
|
118
|
+
:meth:`Problem.run` to generate double description pairs
|
|
119
|
+
for a set of inequalities, and not generate
|
|
120
|
+
``DoubleDescriptionPair`` instances directly.
|
|
121
|
+
|
|
122
|
+
INPUT:
|
|
123
|
+
|
|
124
|
+
- ``problem`` -- instance of :class:`Problem`
|
|
125
|
+
|
|
126
|
+
- ``A_rows`` -- list of row vectors of the matrix `A`; these
|
|
127
|
+
encode the inequalities
|
|
128
|
+
|
|
129
|
+
- ``R_cols`` -- list of column vectors of the matrix
|
|
130
|
+
`R`; these encode the rays
|
|
131
|
+
|
|
132
|
+
TESTS::
|
|
133
|
+
|
|
134
|
+
sage: from sage.geometry.polyhedron.double_description import \
|
|
135
|
+
....: DoubleDescriptionPair, Problem
|
|
136
|
+
sage: A = matrix(QQ, [(1,0,1), (0,1,1), (-1,-1,1)])
|
|
137
|
+
sage: alg = Problem(A)
|
|
138
|
+
sage: DoubleDescriptionPair(alg,
|
|
139
|
+
....: [(1, 0, 1), (0, 1, 1), (-1, -1, 1)],
|
|
140
|
+
....: [(2/3, -1/3, 1/3), (-1/3, 2/3, 1/3), (-1/3, -1/3, 1/3)])
|
|
141
|
+
Double description pair (A, R) defined by
|
|
142
|
+
[ 1 0 1] [ 2/3 -1/3 -1/3]
|
|
143
|
+
A = [ 0 1 1], R = [-1/3 2/3 -1/3]
|
|
144
|
+
[-1 -1 1] [ 1/3 1/3 1/3]
|
|
145
|
+
"""
|
|
146
|
+
self.problem = problem
|
|
147
|
+
self.A = list(A_rows)
|
|
148
|
+
self.R = list(R_cols)
|
|
149
|
+
self.one = problem._field.one()
|
|
150
|
+
self.zero = problem._field.zero()
|
|
151
|
+
|
|
152
|
+
# a cache for scalar products (see the method zero_set)
|
|
153
|
+
self.zero_set_cache = {}
|
|
154
|
+
|
|
155
|
+
def _make_new(self, A_rows, R_cols):
|
|
156
|
+
r"""
|
|
157
|
+
Construct a new double description pair.
|
|
158
|
+
|
|
159
|
+
INPUT:
|
|
160
|
+
|
|
161
|
+
- ``A_rows`` -- list of row vectors of the matrix `A`; these
|
|
162
|
+
encode the inequalities
|
|
163
|
+
|
|
164
|
+
- ``R_cols`` -- list of column vectors of the matrix
|
|
165
|
+
`R`; these encode the rays
|
|
166
|
+
|
|
167
|
+
OUTPUT:
|
|
168
|
+
|
|
169
|
+
A new double description pair of the same (sub)class of
|
|
170
|
+
:class:`DoubleDescriptionProblem`.
|
|
171
|
+
|
|
172
|
+
EXAMPLES::
|
|
173
|
+
|
|
174
|
+
sage: from sage.geometry.polyhedron.double_description import \
|
|
175
|
+
....: DoubleDescriptionPair, StandardAlgorithm
|
|
176
|
+
sage: A = matrix(QQ, [(1,0,1), (0,1,1), (-1,-1,1)])
|
|
177
|
+
sage: DD = StandardAlgorithm(A).run()
|
|
178
|
+
sage: DDnew = DD._make_new(DD.A, DD.R); DDnew
|
|
179
|
+
Double description pair (A, R) defined by
|
|
180
|
+
[ 1 0 1] [ 2/3 -1/3 -1/3]
|
|
181
|
+
A = [ 0 1 1], R = [-1/3 2/3 -1/3]
|
|
182
|
+
[-1 -1 1] [ 1/3 1/3 1/3]
|
|
183
|
+
sage: DDnew is DD
|
|
184
|
+
False
|
|
185
|
+
sage: DDnew.__class__ is DD.__class__
|
|
186
|
+
True
|
|
187
|
+
"""
|
|
188
|
+
return self.__class__(self.problem, A_rows, R_cols)
|
|
189
|
+
|
|
190
|
+
def __repr__(self):
|
|
191
|
+
r"""
|
|
192
|
+
Return string representation.
|
|
193
|
+
|
|
194
|
+
OUTPUT: string
|
|
195
|
+
|
|
196
|
+
EXAMPLES::
|
|
197
|
+
|
|
198
|
+
sage: from sage.geometry.polyhedron.double_description import \
|
|
199
|
+
....: DoubleDescriptionPair, StandardAlgorithm
|
|
200
|
+
sage: A = matrix(QQ, [(1,0,1), (0,1,1), (-1,-1,1)])
|
|
201
|
+
sage: DD = StandardAlgorithm(A).run()
|
|
202
|
+
sage: DD.__repr__()
|
|
203
|
+
'Double description pair (A, R) defined by\n [ 1 0 1]
|
|
204
|
+
[ 2/3 -1/3 -1/3]\nA = [ 0 1 1], R = [-1/3 2/3 -1/3]\n
|
|
205
|
+
[-1 -1 1] [ 1/3 1/3 1/3]'
|
|
206
|
+
"""
|
|
207
|
+
from sage.typeset.ascii_art import ascii_art
|
|
208
|
+
from sage.matrix.constructor import matrix
|
|
209
|
+
s = ascii_art('Double description pair (A, R) defined by')
|
|
210
|
+
A = ascii_art(matrix(self.A))
|
|
211
|
+
A._baseline = (len(self.A) // 2)
|
|
212
|
+
A = ascii_art('A = ') + A
|
|
213
|
+
R = ascii_art(matrix(self.R).transpose())
|
|
214
|
+
if len(self.R) > 0:
|
|
215
|
+
R._baseline = (len(self.R[0]) // 2)
|
|
216
|
+
else:
|
|
217
|
+
R._baseline = 0
|
|
218
|
+
R = ascii_art('R = ') + R
|
|
219
|
+
return str(s * (A + ascii_art(', ') + R))
|
|
220
|
+
|
|
221
|
+
def inner_product_matrix(self):
|
|
222
|
+
"""
|
|
223
|
+
Return the inner product matrix between the rows of `A`
|
|
224
|
+
and the columns of `R`.
|
|
225
|
+
|
|
226
|
+
OUTPUT:
|
|
227
|
+
|
|
228
|
+
A matrix over the base ring. There is one row for each row of
|
|
229
|
+
`A` and one column for each column of `R`.
|
|
230
|
+
|
|
231
|
+
EXAMPLES::
|
|
232
|
+
|
|
233
|
+
sage: from sage.geometry.polyhedron.double_description import StandardAlgorithm
|
|
234
|
+
sage: A = matrix(QQ, [(1,0,1), (0,1,1), (-1,-1,1)])
|
|
235
|
+
sage: alg = StandardAlgorithm(A)
|
|
236
|
+
sage: DD, _ = alg.initial_pair()
|
|
237
|
+
sage: DD.inner_product_matrix()
|
|
238
|
+
[1 0 0]
|
|
239
|
+
[0 1 0]
|
|
240
|
+
[0 0 1]
|
|
241
|
+
"""
|
|
242
|
+
from sage.matrix.constructor import matrix
|
|
243
|
+
return matrix(self.problem.base_ring(), [[a.inner_product(r) for r in self.R] for a in self.A])
|
|
244
|
+
|
|
245
|
+
def cone(self):
|
|
246
|
+
r"""
|
|
247
|
+
Return the cone defined by `A`.
|
|
248
|
+
|
|
249
|
+
This method is for debugging only. Assumes that the base ring
|
|
250
|
+
is `\QQ`.
|
|
251
|
+
|
|
252
|
+
OUTPUT:
|
|
253
|
+
|
|
254
|
+
The cone defined by the inequalities as a
|
|
255
|
+
:func:`~sage.geometry.polyhedron.constructor.Polyhedron`,
|
|
256
|
+
using the PPL backend.
|
|
257
|
+
|
|
258
|
+
EXAMPLES::
|
|
259
|
+
|
|
260
|
+
sage: from sage.geometry.polyhedron.double_description import StandardAlgorithm
|
|
261
|
+
sage: A = matrix(QQ, [(1,0,1), (0,1,1), (-1,-1,1)])
|
|
262
|
+
sage: DD, _ = StandardAlgorithm(A).initial_pair()
|
|
263
|
+
sage: DD.cone().Hrepresentation()
|
|
264
|
+
(An inequality (-1, -1, 1) x + 0 >= 0,
|
|
265
|
+
An inequality (0, 1, 1) x + 0 >= 0,
|
|
266
|
+
An inequality (1, 0, 1) x + 0 >= 0)
|
|
267
|
+
"""
|
|
268
|
+
from sage.geometry.polyhedron.constructor import Polyhedron
|
|
269
|
+
assert self.problem.base_ring() == QQ # required for PPL backend
|
|
270
|
+
|
|
271
|
+
if not self.A:
|
|
272
|
+
return Polyhedron(vertices=[[0] * self.problem.dim()], backend='ppl')
|
|
273
|
+
else:
|
|
274
|
+
ieqs = [[0] + list(a) for a in self.A]
|
|
275
|
+
return Polyhedron(ieqs=ieqs, base_ring=self.problem.base_ring(), backend='ppl')
|
|
276
|
+
|
|
277
|
+
def verify(self):
|
|
278
|
+
r"""
|
|
279
|
+
Validate the double description pair.
|
|
280
|
+
|
|
281
|
+
This method used the PPL backend to check that the double
|
|
282
|
+
description pair is valid. An assertion is triggered if it is
|
|
283
|
+
not. Does nothing if the base ring is not `\QQ`.
|
|
284
|
+
|
|
285
|
+
EXAMPLES::
|
|
286
|
+
|
|
287
|
+
sage: from sage.geometry.polyhedron.double_description import \
|
|
288
|
+
....: DoubleDescriptionPair, Problem
|
|
289
|
+
sage: A = matrix(QQ, [(1,0,1), (0,1,1), (-1,-1,1)])
|
|
290
|
+
sage: alg = Problem(A)
|
|
291
|
+
sage: DD = DoubleDescriptionPair(alg,
|
|
292
|
+
....: [(1, 0, 3), (0, 1, 1), (-1, -1, 1)],
|
|
293
|
+
....: [(2/3, -1/3, 1/3), (-1/3, 2/3, 1/3), (-1/3, -1/3, 1/3)])
|
|
294
|
+
sage: DD.verify()
|
|
295
|
+
Traceback (most recent call last):
|
|
296
|
+
...
|
|
297
|
+
assert A_cone == R_cone
|
|
298
|
+
AssertionError
|
|
299
|
+
"""
|
|
300
|
+
from sage.geometry.polyhedron.constructor import Polyhedron
|
|
301
|
+
if self.problem.base_ring() is not QQ:
|
|
302
|
+
return
|
|
303
|
+
A_cone = self.cone()
|
|
304
|
+
R_cone = Polyhedron(vertices=[[self.zero] * self.problem.dim()], rays=self.R,
|
|
305
|
+
base_ring=self.problem.base_ring(), backend='ppl')
|
|
306
|
+
assert A_cone == R_cone
|
|
307
|
+
assert A_cone.n_inequalities() <= len(self.A)
|
|
308
|
+
assert R_cone.n_rays() == len(self.R)
|
|
309
|
+
|
|
310
|
+
def R_by_sign(self, a):
|
|
311
|
+
"""
|
|
312
|
+
Classify the rays into those that are positive, zero, and negative on `a`.
|
|
313
|
+
|
|
314
|
+
INPUT:
|
|
315
|
+
|
|
316
|
+
- ``a`` -- vector; coefficient vector of a homogeneous inequality
|
|
317
|
+
|
|
318
|
+
OUTPUT:
|
|
319
|
+
|
|
320
|
+
A triple consisting of the rays (columns of `R`) that are
|
|
321
|
+
positive, zero, and negative on `a`. In that order.
|
|
322
|
+
|
|
323
|
+
EXAMPLES::
|
|
324
|
+
|
|
325
|
+
sage: from sage.geometry.polyhedron.double_description import StandardAlgorithm
|
|
326
|
+
sage: A = matrix(QQ, [(1,0,1), (0,1,1), (-1,-1,1)])
|
|
327
|
+
sage: DD, _ = StandardAlgorithm(A).initial_pair()
|
|
328
|
+
sage: DD.R_by_sign(vector([1,-1,0]))
|
|
329
|
+
([(2/3, -1/3, 1/3)], [(-1/3, -1/3, 1/3)], [(-1/3, 2/3, 1/3)])
|
|
330
|
+
sage: DD.R_by_sign(vector([1,1,1]))
|
|
331
|
+
([(2/3, -1/3, 1/3), (-1/3, 2/3, 1/3)], [], [(-1/3, -1/3, 1/3)])
|
|
332
|
+
"""
|
|
333
|
+
pos = []
|
|
334
|
+
nul = []
|
|
335
|
+
neg = []
|
|
336
|
+
for r in self.R:
|
|
337
|
+
sgn = a * r
|
|
338
|
+
if sgn == self.zero:
|
|
339
|
+
nul.append(r)
|
|
340
|
+
elif sgn > self.zero:
|
|
341
|
+
pos.append(r)
|
|
342
|
+
else:
|
|
343
|
+
neg.append(r)
|
|
344
|
+
return pos, nul, neg
|
|
345
|
+
|
|
346
|
+
def zero_set(self, ray):
|
|
347
|
+
"""
|
|
348
|
+
Return the zero set (active set) `Z(r)`.
|
|
349
|
+
|
|
350
|
+
INPUT:
|
|
351
|
+
|
|
352
|
+
- ``ray`` -- a ray vector
|
|
353
|
+
|
|
354
|
+
OUTPUT: a set containing the inequality vectors that are zero on ``ray``
|
|
355
|
+
|
|
356
|
+
EXAMPLES::
|
|
357
|
+
|
|
358
|
+
sage: from sage.geometry.polyhedron.double_description import Problem
|
|
359
|
+
sage: A = matrix(QQ, [(1,0,1), (0,1,1), (-1,-1,1)])
|
|
360
|
+
sage: DD, _ = Problem(A).initial_pair()
|
|
361
|
+
sage: r = DD.R[0]; r
|
|
362
|
+
(2/3, -1/3, 1/3)
|
|
363
|
+
sage: DD.zero_set(r)
|
|
364
|
+
{(-1, -1, 1), (0, 1, 1)}
|
|
365
|
+
"""
|
|
366
|
+
if ray not in self.zero_set_cache:
|
|
367
|
+
self.zero_set_cache[ray] = (0, set())
|
|
368
|
+
n, t = self.zero_set_cache[ray]
|
|
369
|
+
if n != len(self.A):
|
|
370
|
+
t.update(self.A[i] for i in range(n,len(self.A)) if self.A[i].inner_product(ray) == self.zero)
|
|
371
|
+
self.zero_set_cache[ray] = (len(self.A), t)
|
|
372
|
+
return t
|
|
373
|
+
|
|
374
|
+
def is_extremal(self, ray):
|
|
375
|
+
"""
|
|
376
|
+
Test whether the ray is extremal.
|
|
377
|
+
|
|
378
|
+
EXAMPLES::
|
|
379
|
+
|
|
380
|
+
sage: from sage.geometry.polyhedron.double_description import StandardAlgorithm
|
|
381
|
+
sage: A = matrix(QQ, [(0,1,0), (1,0,0), (0,-1,1), (-1,0,1)])
|
|
382
|
+
sage: DD = StandardAlgorithm(A).run()
|
|
383
|
+
sage: DD.is_extremal(DD.R[0])
|
|
384
|
+
True
|
|
385
|
+
"""
|
|
386
|
+
from sage.matrix.constructor import matrix
|
|
387
|
+
A_Zray = matrix(self.problem.base_ring(), list(self.zero_set(ray)))
|
|
388
|
+
return A_Zray.rank() == self.problem.dim() - 1
|
|
389
|
+
|
|
390
|
+
@cached_method
|
|
391
|
+
def matrix_space(self, nrows, ncols):
|
|
392
|
+
r"""
|
|
393
|
+
Return a matrix space of size ``nrows`` and ``ncols`` over the base ring
|
|
394
|
+
of ``self``.
|
|
395
|
+
|
|
396
|
+
These matrix spaces are cached to avoid their creation in the very
|
|
397
|
+
demanding :meth:`add_inequality` and more precisely :meth:`are_adjacent`.
|
|
398
|
+
|
|
399
|
+
EXAMPLES::
|
|
400
|
+
|
|
401
|
+
sage: from sage.geometry.polyhedron.double_description import Problem
|
|
402
|
+
sage: A = matrix(QQ, [(1,0,1), (0,1,1), (-1,-1,1)])
|
|
403
|
+
sage: DD, _ = Problem(A).initial_pair()
|
|
404
|
+
sage: DD.matrix_space(2,2)
|
|
405
|
+
Full MatrixSpace of 2 by 2 dense matrices over Rational Field
|
|
406
|
+
sage: DD.matrix_space(3,2)
|
|
407
|
+
Full MatrixSpace of 3 by 2 dense matrices over Rational Field
|
|
408
|
+
|
|
409
|
+
sage: # needs sage.rings.number_field
|
|
410
|
+
sage: K.<sqrt2> = QuadraticField(2)
|
|
411
|
+
sage: A = matrix([[1,sqrt2],[2,0]])
|
|
412
|
+
sage: DD, _ = Problem(A).initial_pair()
|
|
413
|
+
sage: DD.matrix_space(1,2)
|
|
414
|
+
Full MatrixSpace of 1 by 2 dense matrices
|
|
415
|
+
over Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095?
|
|
416
|
+
"""
|
|
417
|
+
return MatrixSpace(self.problem.base_ring(), nrows, ncols)
|
|
418
|
+
|
|
419
|
+
def are_adjacent(self, r1, r2):
|
|
420
|
+
"""
|
|
421
|
+
Return whether the two rays are adjacent.
|
|
422
|
+
|
|
423
|
+
INPUT:
|
|
424
|
+
|
|
425
|
+
- ``r1``, ``r2`` -- two rays
|
|
426
|
+
|
|
427
|
+
OUTPUT: boolean; whether the two rays are adjacent
|
|
428
|
+
|
|
429
|
+
EXAMPLES::
|
|
430
|
+
|
|
431
|
+
sage: from sage.geometry.polyhedron.double_description import StandardAlgorithm
|
|
432
|
+
sage: A = matrix(QQ, [(0,1,0), (1,0,0), (0,-1,1), (-1,0,1)])
|
|
433
|
+
sage: DD = StandardAlgorithm(A).run()
|
|
434
|
+
sage: DD.are_adjacent(DD.R[0], DD.R[1])
|
|
435
|
+
True
|
|
436
|
+
sage: DD.are_adjacent(DD.R[0], DD.R[2])
|
|
437
|
+
True
|
|
438
|
+
sage: DD.are_adjacent(DD.R[0], DD.R[3])
|
|
439
|
+
False
|
|
440
|
+
"""
|
|
441
|
+
Z = self.zero_set(r1).intersection(self.zero_set(r2))
|
|
442
|
+
if not Z:
|
|
443
|
+
return self.problem.dim() == 2
|
|
444
|
+
Z = list(Z)
|
|
445
|
+
|
|
446
|
+
# here we try to create a matrix as fast as possible
|
|
447
|
+
# since the generic matrix constructor is very slow (trac #18231)
|
|
448
|
+
A_Z12 = self.matrix_space(len(Z), len(Z[0])).matrix(Z, coerce=False)
|
|
449
|
+
return A_Z12.rank() == self.problem.dim() - 2
|
|
450
|
+
|
|
451
|
+
def dual(self):
|
|
452
|
+
"""
|
|
453
|
+
Return the dual.
|
|
454
|
+
|
|
455
|
+
OUTPUT:
|
|
456
|
+
|
|
457
|
+
For the double description pair `(A, R)` this method returns
|
|
458
|
+
the dual double description pair `(R^T, A^T)`
|
|
459
|
+
|
|
460
|
+
EXAMPLES::
|
|
461
|
+
|
|
462
|
+
sage: from sage.geometry.polyhedron.double_description import Problem
|
|
463
|
+
sage: A = matrix(QQ, [(0,1,0), (1,0,0), (0,-1,1), (-1,0,1)])
|
|
464
|
+
sage: DD, _ = Problem(A).initial_pair()
|
|
465
|
+
sage: DD
|
|
466
|
+
Double description pair (A, R) defined by
|
|
467
|
+
[ 0 1 0] [0 1 0]
|
|
468
|
+
A = [ 1 0 0], R = [1 0 0]
|
|
469
|
+
[ 0 -1 1] [1 0 1]
|
|
470
|
+
sage: DD.dual()
|
|
471
|
+
Double description pair (A, R) defined by
|
|
472
|
+
[0 1 1] [ 0 1 0]
|
|
473
|
+
A = [1 0 0], R = [ 1 0 -1]
|
|
474
|
+
[0 0 1] [ 0 0 1]
|
|
475
|
+
"""
|
|
476
|
+
return self._make_new(self.R, self.A)
|
|
477
|
+
|
|
478
|
+
def first_coordinate_plane(self):
|
|
479
|
+
"""
|
|
480
|
+
Restrict to the first coordinate plane.
|
|
481
|
+
|
|
482
|
+
OUTPUT:
|
|
483
|
+
|
|
484
|
+
A new double description pair with the constraint `x_0 = 0`
|
|
485
|
+
added.
|
|
486
|
+
|
|
487
|
+
EXAMPLES::
|
|
488
|
+
|
|
489
|
+
sage: A = matrix([(1, 1), (-1, 1)])
|
|
490
|
+
sage: from sage.geometry.polyhedron.double_description import StandardAlgorithm
|
|
491
|
+
sage: DD, _ = StandardAlgorithm(A).initial_pair()
|
|
492
|
+
sage: DD
|
|
493
|
+
Double description pair (A, R) defined by
|
|
494
|
+
A = [ 1 1], R = [ 1/2 -1/2]
|
|
495
|
+
[-1 1] [ 1/2 1/2]
|
|
496
|
+
sage: DD.first_coordinate_plane()
|
|
497
|
+
Double description pair (A, R) defined by
|
|
498
|
+
[ 1 1]
|
|
499
|
+
A = [-1 1], R = [ 0]
|
|
500
|
+
[-1 0] [1/2]
|
|
501
|
+
[ 1 0]
|
|
502
|
+
"""
|
|
503
|
+
R = self.problem.base_ring()
|
|
504
|
+
d = self.problem.dim()
|
|
505
|
+
a_neg = vector(R, [-self.one] + [self.zero] * (d - 1))
|
|
506
|
+
a_pos = vector(R, [+self.one] + [self.zero] * (d - 1))
|
|
507
|
+
new = self._make_new(self.A, self.R)
|
|
508
|
+
new.add_inequality(a_neg)
|
|
509
|
+
new.add_inequality(a_pos)
|
|
510
|
+
return new
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
class Problem:
|
|
514
|
+
|
|
515
|
+
pair_class = DoubleDescriptionPair
|
|
516
|
+
|
|
517
|
+
def __init__(self, A):
|
|
518
|
+
r"""
|
|
519
|
+
Base class for implementations of the double description algorithm.
|
|
520
|
+
|
|
521
|
+
It does not make sense to instantiate the base class directly,
|
|
522
|
+
it just provides helpers for implementations.
|
|
523
|
+
|
|
524
|
+
INPUT:
|
|
525
|
+
|
|
526
|
+
- ``A`` -- a matrix; the rows of the matrix are interpreted as
|
|
527
|
+
homogeneous inequalities `A x \geq 0`. Must have maximal rank.
|
|
528
|
+
|
|
529
|
+
TESTS::
|
|
530
|
+
|
|
531
|
+
sage: A = matrix([(1, 1), (-1, 1)])
|
|
532
|
+
sage: from sage.geometry.polyhedron.double_description import Problem
|
|
533
|
+
sage: Problem(A)
|
|
534
|
+
Pointed cone with inequalities
|
|
535
|
+
(1, 1)
|
|
536
|
+
(-1, 1)
|
|
537
|
+
"""
|
|
538
|
+
assert A.rank() == A.ncols() # implementation assumes maximal rank
|
|
539
|
+
if A.is_mutable():
|
|
540
|
+
A = A.__copy__()
|
|
541
|
+
A.set_immutable()
|
|
542
|
+
self._A = A
|
|
543
|
+
self._field = A.base_ring().fraction_field()
|
|
544
|
+
|
|
545
|
+
@cached_method
|
|
546
|
+
def A(self):
|
|
547
|
+
"""
|
|
548
|
+
Return the rows of the defining matrix `A`.
|
|
549
|
+
|
|
550
|
+
OUTPUT: the matrix `A` whose rows are the inequalities
|
|
551
|
+
|
|
552
|
+
EXAMPLES::
|
|
553
|
+
|
|
554
|
+
sage: A = matrix([(1, 1), (-1, 1)])
|
|
555
|
+
sage: from sage.geometry.polyhedron.double_description import Problem
|
|
556
|
+
sage: Problem(A).A()
|
|
557
|
+
((1, 1), (-1, 1))
|
|
558
|
+
"""
|
|
559
|
+
rows = [a.change_ring(self._field) for a in self._A.rows()]
|
|
560
|
+
for a in rows:
|
|
561
|
+
a.set_immutable()
|
|
562
|
+
return tuple(rows)
|
|
563
|
+
|
|
564
|
+
def A_matrix(self):
|
|
565
|
+
"""
|
|
566
|
+
Return the defining matrix `A`.
|
|
567
|
+
|
|
568
|
+
OUTPUT: matrix whose rows are the inequalities
|
|
569
|
+
|
|
570
|
+
EXAMPLES::
|
|
571
|
+
|
|
572
|
+
sage: A = matrix([(1, 1), (-1, 1)])
|
|
573
|
+
sage: from sage.geometry.polyhedron.double_description import Problem
|
|
574
|
+
sage: Problem(A).A_matrix()
|
|
575
|
+
[ 1 1]
|
|
576
|
+
[-1 1]
|
|
577
|
+
"""
|
|
578
|
+
return self._A
|
|
579
|
+
|
|
580
|
+
def base_ring(self):
|
|
581
|
+
"""
|
|
582
|
+
Return the base field.
|
|
583
|
+
|
|
584
|
+
OUTPUT: a field
|
|
585
|
+
|
|
586
|
+
EXAMPLES::
|
|
587
|
+
|
|
588
|
+
sage: A = matrix(AA, [(1, 1), (-1, 1)]) # needs sage.rings.number_field
|
|
589
|
+
sage: from sage.geometry.polyhedron.double_description import Problem
|
|
590
|
+
sage: Problem(A).base_ring() # needs sage.rings.number_field
|
|
591
|
+
Algebraic Real Field
|
|
592
|
+
"""
|
|
593
|
+
return self._field
|
|
594
|
+
|
|
595
|
+
@cached_method
|
|
596
|
+
def dim(self):
|
|
597
|
+
"""
|
|
598
|
+
Return the ambient space dimension.
|
|
599
|
+
|
|
600
|
+
OUTPUT: integer; the ambient space dimension of the cone
|
|
601
|
+
|
|
602
|
+
EXAMPLES::
|
|
603
|
+
|
|
604
|
+
sage: A = matrix(QQ, [(1, 1), (-1, 1)])
|
|
605
|
+
sage: from sage.geometry.polyhedron.double_description import Problem
|
|
606
|
+
sage: Problem(A).dim()
|
|
607
|
+
2
|
|
608
|
+
"""
|
|
609
|
+
return self._A.ncols()
|
|
610
|
+
|
|
611
|
+
def __repr__(self):
|
|
612
|
+
r"""
|
|
613
|
+
Return a string representation.
|
|
614
|
+
|
|
615
|
+
OUTPUT: string
|
|
616
|
+
|
|
617
|
+
EXAMPLES::
|
|
618
|
+
|
|
619
|
+
sage: A = matrix(QQ, [(1, 1), (-1, 1)])
|
|
620
|
+
sage: from sage.geometry.polyhedron.double_description import Problem
|
|
621
|
+
sage: Problem(A).__repr__()
|
|
622
|
+
'Pointed cone with inequalities\n(1, 1)\n(-1, 1)'
|
|
623
|
+
"""
|
|
624
|
+
return 'Pointed cone with inequalities\n' + '\n'.join(map(str, self.A()))
|
|
625
|
+
|
|
626
|
+
def initial_pair(self):
|
|
627
|
+
"""
|
|
628
|
+
Return an initial double description pair.
|
|
629
|
+
|
|
630
|
+
Picks an initial set of rays by selecting a basis. This is
|
|
631
|
+
probably the most efficient way to select the initial set.
|
|
632
|
+
|
|
633
|
+
INPUT:
|
|
634
|
+
|
|
635
|
+
- ``pair_class`` -- subclass of
|
|
636
|
+
:class:`DoubleDescriptionPair`
|
|
637
|
+
|
|
638
|
+
OUTPUT:
|
|
639
|
+
|
|
640
|
+
A pair consisting of a :class:`DoubleDescriptionPair` instance
|
|
641
|
+
and the tuple of remaining unused inequalities.
|
|
642
|
+
|
|
643
|
+
EXAMPLES::
|
|
644
|
+
|
|
645
|
+
sage: A = matrix([(-1, 1), (-1, 2), (1/2, -1/2), (1/2, 2)])
|
|
646
|
+
sage: from sage.geometry.polyhedron.double_description import Problem
|
|
647
|
+
sage: DD, remaining = Problem(A).initial_pair()
|
|
648
|
+
sage: DD.verify()
|
|
649
|
+
sage: remaining
|
|
650
|
+
[(1/2, -1/2), (1/2, 2)]
|
|
651
|
+
"""
|
|
652
|
+
pivot_rows = self.A_matrix().pivot_rows()
|
|
653
|
+
A0 = [self.A()[pivot] for pivot in pivot_rows]
|
|
654
|
+
Ac = [self.A()[i] for i in range(len(self.A())) if i not in pivot_rows]
|
|
655
|
+
from sage.matrix.constructor import identity_matrix, matrix
|
|
656
|
+
I = identity_matrix(self.base_ring(), self.dim())
|
|
657
|
+
R = matrix(self.base_ring(), A0).solve_right(I)
|
|
658
|
+
return self.pair_class(self, A0, R.columns()), list(Ac)
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
class StandardDoubleDescriptionPair(DoubleDescriptionPair):
|
|
662
|
+
"""
|
|
663
|
+
Double description pair for the "Standard Algorithm".
|
|
664
|
+
|
|
665
|
+
See :class:`StandardAlgorithm`.
|
|
666
|
+
|
|
667
|
+
TESTS::
|
|
668
|
+
|
|
669
|
+
sage: A = matrix([(-1, 1, 0), (-1, 2, 1), (1/2, -1/2, -1)])
|
|
670
|
+
sage: from sage.geometry.polyhedron.double_description import StandardAlgorithm
|
|
671
|
+
sage: DD, _ = StandardAlgorithm(A).initial_pair()
|
|
672
|
+
"""
|
|
673
|
+
|
|
674
|
+
def add_inequality(self, a):
|
|
675
|
+
"""
|
|
676
|
+
Add the inequality ``a`` to the matrix `A` of the double description.
|
|
677
|
+
|
|
678
|
+
INPUT:
|
|
679
|
+
|
|
680
|
+
- ``a`` -- vector; an inequality
|
|
681
|
+
|
|
682
|
+
EXAMPLES::
|
|
683
|
+
|
|
684
|
+
sage: A = matrix([(-1, 1, 0), (-1, 2, 1), (1/2, -1/2, -1)])
|
|
685
|
+
sage: from sage.geometry.polyhedron.double_description import StandardAlgorithm
|
|
686
|
+
sage: DD, _ = StandardAlgorithm(A).initial_pair()
|
|
687
|
+
sage: DD.add_inequality(vector([1,0,0]))
|
|
688
|
+
sage: DD
|
|
689
|
+
Double description pair (A, R) defined by
|
|
690
|
+
[ -1 1 0] [ 1 1 0 0]
|
|
691
|
+
A = [ -1 2 1], R = [ 1 1 1 1]
|
|
692
|
+
[ 1/2 -1/2 -1] [ 0 -1 -1/2 -2]
|
|
693
|
+
[ 1 0 0]
|
|
694
|
+
"""
|
|
695
|
+
R_pos, R_nul, R_neg = self.R_by_sign(a)
|
|
696
|
+
if not R_neg:
|
|
697
|
+
return
|
|
698
|
+
R_new = []
|
|
699
|
+
for rp, rn in itertools.product(R_pos, R_neg):
|
|
700
|
+
if not self.are_adjacent(rp, rn):
|
|
701
|
+
continue
|
|
702
|
+
r = a.inner_product(rp) * rn - a.inner_product(rn) * rp
|
|
703
|
+
r.set_immutable()
|
|
704
|
+
R_new.append(r)
|
|
705
|
+
self.R = R_pos + R_nul + R_new
|
|
706
|
+
self.A.append(a)
|
|
707
|
+
|
|
708
|
+
|
|
709
|
+
class StandardAlgorithm(Problem):
|
|
710
|
+
"""
|
|
711
|
+
Standard implementation of the double description algorithm.
|
|
712
|
+
|
|
713
|
+
See [FP1996]_ for the definition of the "Standard
|
|
714
|
+
Algorithm".
|
|
715
|
+
|
|
716
|
+
EXAMPLES::
|
|
717
|
+
|
|
718
|
+
sage: A = matrix(QQ, [(1, 1), (-1, 1)])
|
|
719
|
+
sage: from sage.geometry.polyhedron.double_description import StandardAlgorithm
|
|
720
|
+
sage: DD = StandardAlgorithm(A).run()
|
|
721
|
+
sage: DD.R # the extremal rays
|
|
722
|
+
[(1/2, 1/2), (-1/2, 1/2)]
|
|
723
|
+
"""
|
|
724
|
+
pair_class = StandardDoubleDescriptionPair
|
|
725
|
+
|
|
726
|
+
def run(self):
|
|
727
|
+
"""
|
|
728
|
+
Run the Standard Algorithm.
|
|
729
|
+
|
|
730
|
+
OUTPUT:
|
|
731
|
+
|
|
732
|
+
A double description pair `(A, R)` of all inequalities as a
|
|
733
|
+
:class:`DoubleDescriptionPair`. By virtue of the double
|
|
734
|
+
description algorithm, the columns of `R` are the extremal
|
|
735
|
+
rays.
|
|
736
|
+
|
|
737
|
+
EXAMPLES::
|
|
738
|
+
|
|
739
|
+
sage: from sage.geometry.polyhedron.double_description import StandardAlgorithm
|
|
740
|
+
sage: A = matrix(QQ, [(0,1,0), (1,0,0), (0,-1,1), (-1,0,1)])
|
|
741
|
+
sage: StandardAlgorithm(A).run()
|
|
742
|
+
Double description pair (A, R) defined by
|
|
743
|
+
[ 0 1 0] [0 0 1 1]
|
|
744
|
+
A = [ 1 0 0], R = [1 0 1 0]
|
|
745
|
+
[ 0 -1 1] [1 1 1 1]
|
|
746
|
+
[-1 0 1]
|
|
747
|
+
"""
|
|
748
|
+
DD, remaining = self.initial_pair()
|
|
749
|
+
for a in remaining:
|
|
750
|
+
DD.add_inequality(a)
|
|
751
|
+
if VERIFY_RESULT:
|
|
752
|
+
DD.verify()
|
|
753
|
+
return DD
|