passagemath-polyhedra 10.6.31rc3__cp314-cp314-macosx_13_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of passagemath-polyhedra might be problematic. Click here for more details.

Files changed (205) hide show
  1. passagemath_polyhedra-10.6.31rc3.dist-info/METADATA +368 -0
  2. passagemath_polyhedra-10.6.31rc3.dist-info/METADATA.bak +371 -0
  3. passagemath_polyhedra-10.6.31rc3.dist-info/RECORD +205 -0
  4. passagemath_polyhedra-10.6.31rc3.dist-info/WHEEL +6 -0
  5. passagemath_polyhedra-10.6.31rc3.dist-info/top_level.txt +2 -0
  6. passagemath_polyhedra.dylibs/libgmp.10.dylib +0 -0
  7. sage/all__sagemath_polyhedra.py +50 -0
  8. sage/game_theory/all.py +8 -0
  9. sage/game_theory/catalog.py +6 -0
  10. sage/game_theory/catalog_normal_form_games.py +923 -0
  11. sage/game_theory/cooperative_game.py +844 -0
  12. sage/game_theory/matching_game.py +1181 -0
  13. sage/game_theory/normal_form_game.py +2697 -0
  14. sage/game_theory/parser.py +275 -0
  15. sage/geometry/all__sagemath_polyhedra.py +22 -0
  16. sage/geometry/cone.py +6940 -0
  17. sage/geometry/cone_catalog.py +847 -0
  18. sage/geometry/cone_critical_angles.py +1027 -0
  19. sage/geometry/convex_set.py +1119 -0
  20. sage/geometry/fan.py +3743 -0
  21. sage/geometry/fan_isomorphism.py +389 -0
  22. sage/geometry/fan_morphism.py +1884 -0
  23. sage/geometry/hasse_diagram.py +202 -0
  24. sage/geometry/hyperplane_arrangement/affine_subspace.py +390 -0
  25. sage/geometry/hyperplane_arrangement/all.py +1 -0
  26. sage/geometry/hyperplane_arrangement/arrangement.py +3895 -0
  27. sage/geometry/hyperplane_arrangement/check_freeness.py +145 -0
  28. sage/geometry/hyperplane_arrangement/hyperplane.py +773 -0
  29. sage/geometry/hyperplane_arrangement/library.py +825 -0
  30. sage/geometry/hyperplane_arrangement/ordered_arrangement.py +642 -0
  31. sage/geometry/hyperplane_arrangement/plot.py +520 -0
  32. sage/geometry/integral_points.py +35 -0
  33. sage/geometry/integral_points_generic_dense.cpython-314-darwin.so +0 -0
  34. sage/geometry/integral_points_generic_dense.pyx +7 -0
  35. sage/geometry/lattice_polytope.py +5894 -0
  36. sage/geometry/linear_expression.py +773 -0
  37. sage/geometry/newton_polygon.py +767 -0
  38. sage/geometry/point_collection.cpython-314-darwin.so +0 -0
  39. sage/geometry/point_collection.pyx +1008 -0
  40. sage/geometry/polyhedral_complex.py +2616 -0
  41. sage/geometry/polyhedron/all.py +8 -0
  42. sage/geometry/polyhedron/backend_cdd.py +460 -0
  43. sage/geometry/polyhedron/backend_cdd_rdf.py +231 -0
  44. sage/geometry/polyhedron/backend_field.py +347 -0
  45. sage/geometry/polyhedron/backend_normaliz.py +2503 -0
  46. sage/geometry/polyhedron/backend_number_field.py +168 -0
  47. sage/geometry/polyhedron/backend_polymake.py +765 -0
  48. sage/geometry/polyhedron/backend_ppl.py +582 -0
  49. sage/geometry/polyhedron/base.py +1206 -0
  50. sage/geometry/polyhedron/base0.py +1444 -0
  51. sage/geometry/polyhedron/base1.py +886 -0
  52. sage/geometry/polyhedron/base2.py +812 -0
  53. sage/geometry/polyhedron/base3.py +1845 -0
  54. sage/geometry/polyhedron/base4.py +1262 -0
  55. sage/geometry/polyhedron/base5.py +2700 -0
  56. sage/geometry/polyhedron/base6.py +1741 -0
  57. sage/geometry/polyhedron/base7.py +997 -0
  58. sage/geometry/polyhedron/base_QQ.py +1258 -0
  59. sage/geometry/polyhedron/base_RDF.py +98 -0
  60. sage/geometry/polyhedron/base_ZZ.py +934 -0
  61. sage/geometry/polyhedron/base_mutable.py +215 -0
  62. sage/geometry/polyhedron/base_number_field.py +122 -0
  63. sage/geometry/polyhedron/cdd_file_format.py +155 -0
  64. sage/geometry/polyhedron/combinatorial_polyhedron/all.py +1 -0
  65. sage/geometry/polyhedron/combinatorial_polyhedron/base.cpython-314-darwin.so +0 -0
  66. sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd +76 -0
  67. sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +3859 -0
  68. sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.cpython-314-darwin.so +0 -0
  69. sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pxd +39 -0
  70. sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx +1038 -0
  71. sage/geometry/polyhedron/combinatorial_polyhedron/conversions.cpython-314-darwin.so +0 -0
  72. sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pxd +9 -0
  73. sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx +501 -0
  74. sage/geometry/polyhedron/combinatorial_polyhedron/face_data_structure.pxd +207 -0
  75. sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.cpython-314-darwin.so +0 -0
  76. sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd +102 -0
  77. sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +2274 -0
  78. sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.cpython-314-darwin.so +0 -0
  79. sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pxd +370 -0
  80. sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pyx +84 -0
  81. sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.cpython-314-darwin.so +0 -0
  82. sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pxd +31 -0
  83. sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx +587 -0
  84. sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.cpython-314-darwin.so +0 -0
  85. sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pxd +52 -0
  86. sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx +560 -0
  87. sage/geometry/polyhedron/constructor.py +773 -0
  88. sage/geometry/polyhedron/double_description.py +753 -0
  89. sage/geometry/polyhedron/double_description_inhomogeneous.py +564 -0
  90. sage/geometry/polyhedron/face.py +1060 -0
  91. sage/geometry/polyhedron/generating_function.py +1810 -0
  92. sage/geometry/polyhedron/lattice_euclidean_group_element.py +178 -0
  93. sage/geometry/polyhedron/library.py +3502 -0
  94. sage/geometry/polyhedron/misc.py +121 -0
  95. sage/geometry/polyhedron/modules/all.py +1 -0
  96. sage/geometry/polyhedron/modules/formal_polyhedra_module.py +155 -0
  97. sage/geometry/polyhedron/palp_database.py +447 -0
  98. sage/geometry/polyhedron/parent.py +1279 -0
  99. sage/geometry/polyhedron/plot.py +1986 -0
  100. sage/geometry/polyhedron/ppl_lattice_polygon.py +556 -0
  101. sage/geometry/polyhedron/ppl_lattice_polytope.py +1257 -0
  102. sage/geometry/polyhedron/representation.py +1723 -0
  103. sage/geometry/pseudolines.py +515 -0
  104. sage/geometry/relative_interior.py +445 -0
  105. sage/geometry/toric_plotter.py +1103 -0
  106. sage/geometry/triangulation/all.py +2 -0
  107. sage/geometry/triangulation/base.cpython-314-darwin.so +0 -0
  108. sage/geometry/triangulation/base.pyx +963 -0
  109. sage/geometry/triangulation/data.h +147 -0
  110. sage/geometry/triangulation/data.pxd +4 -0
  111. sage/geometry/triangulation/element.py +914 -0
  112. sage/geometry/triangulation/functions.h +10 -0
  113. sage/geometry/triangulation/functions.pxd +4 -0
  114. sage/geometry/triangulation/point_configuration.py +2256 -0
  115. sage/geometry/triangulation/triangulations.h +49 -0
  116. sage/geometry/triangulation/triangulations.pxd +7 -0
  117. sage/geometry/voronoi_diagram.py +319 -0
  118. sage/interfaces/all__sagemath_polyhedra.py +1 -0
  119. sage/interfaces/polymake.py +2028 -0
  120. sage/numerical/all.py +13 -0
  121. sage/numerical/all__sagemath_polyhedra.py +11 -0
  122. sage/numerical/backends/all.py +1 -0
  123. sage/numerical/backends/all__sagemath_polyhedra.py +1 -0
  124. sage/numerical/backends/cvxopt_backend.cpython-314-darwin.so +0 -0
  125. sage/numerical/backends/cvxopt_backend.pyx +1006 -0
  126. sage/numerical/backends/cvxopt_backend_test.py +19 -0
  127. sage/numerical/backends/cvxopt_sdp_backend.cpython-314-darwin.so +0 -0
  128. sage/numerical/backends/cvxopt_sdp_backend.pyx +382 -0
  129. sage/numerical/backends/cvxpy_backend.cpython-314-darwin.so +0 -0
  130. sage/numerical/backends/cvxpy_backend.pxd +41 -0
  131. sage/numerical/backends/cvxpy_backend.pyx +934 -0
  132. sage/numerical/backends/cvxpy_backend_test.py +13 -0
  133. sage/numerical/backends/generic_backend_test.py +24 -0
  134. sage/numerical/backends/interactivelp_backend.cpython-314-darwin.so +0 -0
  135. sage/numerical/backends/interactivelp_backend.pxd +36 -0
  136. sage/numerical/backends/interactivelp_backend.pyx +1231 -0
  137. sage/numerical/backends/interactivelp_backend_test.py +12 -0
  138. sage/numerical/backends/logging_backend.py +391 -0
  139. sage/numerical/backends/matrix_sdp_backend.cpython-314-darwin.so +0 -0
  140. sage/numerical/backends/matrix_sdp_backend.pxd +15 -0
  141. sage/numerical/backends/matrix_sdp_backend.pyx +478 -0
  142. sage/numerical/backends/ppl_backend.cpython-314-darwin.so +0 -0
  143. sage/numerical/backends/ppl_backend.pyx +1126 -0
  144. sage/numerical/backends/ppl_backend_test.py +13 -0
  145. sage/numerical/backends/scip_backend.cpython-314-darwin.so +0 -0
  146. sage/numerical/backends/scip_backend.pxd +22 -0
  147. sage/numerical/backends/scip_backend.pyx +1289 -0
  148. sage/numerical/backends/scip_backend_test.py +13 -0
  149. sage/numerical/interactive_simplex_method.py +5338 -0
  150. sage/numerical/knapsack.py +665 -0
  151. sage/numerical/linear_functions.cpython-314-darwin.so +0 -0
  152. sage/numerical/linear_functions.pxd +31 -0
  153. sage/numerical/linear_functions.pyx +1648 -0
  154. sage/numerical/linear_tensor.py +470 -0
  155. sage/numerical/linear_tensor_constraints.py +448 -0
  156. sage/numerical/linear_tensor_element.cpython-314-darwin.so +0 -0
  157. sage/numerical/linear_tensor_element.pxd +6 -0
  158. sage/numerical/linear_tensor_element.pyx +459 -0
  159. sage/numerical/mip.cpython-314-darwin.so +0 -0
  160. sage/numerical/mip.pxd +40 -0
  161. sage/numerical/mip.pyx +3667 -0
  162. sage/numerical/sdp.cpython-314-darwin.so +0 -0
  163. sage/numerical/sdp.pxd +39 -0
  164. sage/numerical/sdp.pyx +1433 -0
  165. sage/rings/all__sagemath_polyhedra.py +3 -0
  166. sage/rings/polynomial/all__sagemath_polyhedra.py +10 -0
  167. sage/rings/polynomial/omega.py +982 -0
  168. sage/schemes/all__sagemath_polyhedra.py +2 -0
  169. sage/schemes/toric/all.py +10 -0
  170. sage/schemes/toric/chow_group.py +1248 -0
  171. sage/schemes/toric/divisor.py +2082 -0
  172. sage/schemes/toric/divisor_class.cpython-314-darwin.so +0 -0
  173. sage/schemes/toric/divisor_class.pyx +322 -0
  174. sage/schemes/toric/fano_variety.py +1606 -0
  175. sage/schemes/toric/homset.py +650 -0
  176. sage/schemes/toric/ideal.py +451 -0
  177. sage/schemes/toric/library.py +1322 -0
  178. sage/schemes/toric/morphism.py +1958 -0
  179. sage/schemes/toric/points.py +1032 -0
  180. sage/schemes/toric/sheaf/all.py +1 -0
  181. sage/schemes/toric/sheaf/constructor.py +302 -0
  182. sage/schemes/toric/sheaf/klyachko.py +921 -0
  183. sage/schemes/toric/toric_subscheme.py +905 -0
  184. sage/schemes/toric/variety.py +3460 -0
  185. sage/schemes/toric/weierstrass.py +1078 -0
  186. sage/schemes/toric/weierstrass_covering.py +457 -0
  187. sage/schemes/toric/weierstrass_higher.py +288 -0
  188. sage_wheels/share/reflexive_polytopes/Full2d/zzdb.info +10 -0
  189. sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v03 +0 -0
  190. sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v04 +0 -0
  191. sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v05 +1 -0
  192. sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v06 +1 -0
  193. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.info +22 -0
  194. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v04 +0 -0
  195. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v05 +0 -0
  196. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v06 +0 -0
  197. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v07 +0 -0
  198. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v08 +0 -0
  199. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v09 +0 -0
  200. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v10 +0 -0
  201. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v11 +1 -0
  202. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v12 +1 -0
  203. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v13 +1 -0
  204. sage_wheels/share/reflexive_polytopes/reflexive_polytopes_2d +80 -0
  205. sage_wheels/share/reflexive_polytopes/reflexive_polytopes_3d +37977 -0
@@ -0,0 +1,1741 @@
1
+ # sage_setup: distribution = sagemath-polyhedra
2
+ r"""
3
+ Base class for polyhedra: Methods for plotting and affine hull projection
4
+ """
5
+
6
+ # ****************************************************************************
7
+ # Copyright (C) 2008-2012 Marshall Hampton <hamptonio@gmail.com>
8
+ # Copyright (C) 2011-2015 Volker Braun <vbraun.name@gmail.com>
9
+ # Copyright (C) 2012-2018 Frederic Chapoton
10
+ # Copyright (C) 2013 Andrey Novoseltsev
11
+ # Copyright (C) 2014-2017 Moritz Firsching
12
+ # Copyright (C) 2014-2019 Thierry Monteil
13
+ # Copyright (C) 2015 Nathann Cohen
14
+ # Copyright (C) 2015-2017 Jeroen Demeyer
15
+ # Copyright (C) 2015-2017 Vincent Delecroix
16
+ # Copyright (C) 2015-2018 Dima Pasechnik
17
+ # Copyright (C) 2015-2020 Jean-Philippe Labbe <labbe at math.huji.ac.il>
18
+ # Copyright (C) 2015-2021 Matthias Koeppe
19
+ # Copyright (C) 2016-2019 Daniel Krenn
20
+ # Copyright (C) 2017 Marcelo Forets
21
+ # Copyright (C) 2017-2018 Mark Bell
22
+ # Copyright (C) 2019 Julian Ritter
23
+ # Copyright (C) 2019-2020 Laith Rastanawi
24
+ # Copyright (C) 2019-2020 Sophia Elia
25
+ # Copyright (C) 2019-2021 Jonathan Kliem <jonathan.kliem@gmail.com>
26
+ #
27
+ # This program is free software: you can redistribute it and/or modify
28
+ # it under the terms of the GNU General Public License as published by
29
+ # the Free Software Foundation, either version 2 of the License, or
30
+ # (at your option) any later version.
31
+ # https://www.gnu.org/licenses/
32
+ # ****************************************************************************
33
+
34
+ from sage.misc.cachefunc import cached_method
35
+ from sage.modules.vector_space_morphism import linear_transformation
36
+ from sage.matrix.constructor import matrix
37
+ from sage.modules.free_module_element import vector
38
+ from sage.geometry.convex_set import AffineHullProjectionData
39
+ from .base5 import Polyhedron_base5
40
+
41
+
42
+ class Polyhedron_base6(Polyhedron_base5):
43
+ r"""
44
+ Methods related to plotting including affine hull projection.
45
+
46
+ TESTS::
47
+
48
+ sage: from sage.geometry.polyhedron.base6 import Polyhedron_base6
49
+ sage: P = polytopes.cube()
50
+ sage: Polyhedron_base6.plot(P) # needs sage.plot
51
+ Graphics3d Object
52
+ sage: print(Polyhedron_base6.tikz(P, output_type='TikzPicture')) # needs sage.plot
53
+ \RequirePackage{luatex85}
54
+ \documentclass[tikz]{standalone}
55
+ \begin{document}
56
+ \begin{tikzpicture}%
57
+ [x={(1.000000cm, 0.000000cm)},
58
+ y={(-0.000000cm, 1.000000cm)},
59
+ z={(0.000000cm, -0.000000cm)},
60
+ scale=1.000000,
61
+ back/.style={loosely dotted, thin},
62
+ edge/.style={color=blue!95!black, thick},
63
+ facet/.style={fill=blue!95!black,fill opacity=0.800000},
64
+ vertex/.style={inner sep=1pt,circle,draw=green!25!black,fill=green!75!black,thick}]
65
+ %
66
+ %
67
+ %% This TikZ-picture was produced with Sagemath version ...
68
+ %% with the command: ._tikz_3d_in_3d and parameters:
69
+ %% view = [0, 0, 1]
70
+ %% angle = 0
71
+ %% scale = 1
72
+ %% edge_color = blue!95!black
73
+ %% facet_color = blue!95!black
74
+ %% opacity = 0.8
75
+ %% vertex_color = green
76
+ %% axis = False
77
+ %%
78
+ %% Coordinate of the vertices:
79
+ %%
80
+ \coordinate (1.00000, -1.00000, -1.00000) at (1.00000, -1.00000, -1.00000);
81
+ \coordinate (1.00000, 1.00000, -1.00000) at (1.00000, 1.00000, -1.00000);
82
+ \coordinate (1.00000, 1.00000, 1.00000) at (1.00000, 1.00000, 1.00000);
83
+ \coordinate (1.00000, -1.00000, 1.00000) at (1.00000, -1.00000, 1.00000);
84
+ \coordinate (-1.00000, -1.00000, 1.00000) at (-1.00000, -1.00000, 1.00000);
85
+ \coordinate (-1.00000, -1.00000, -1.00000) at (-1.00000, -1.00000, -1.00000);
86
+ \coordinate (-1.00000, 1.00000, -1.00000) at (-1.00000, 1.00000, -1.00000);
87
+ \coordinate (-1.00000, 1.00000, 1.00000) at (-1.00000, 1.00000, 1.00000);
88
+ %%
89
+ %%
90
+ %% Drawing edges in the back
91
+ %%
92
+ \draw[edge,back] (1.00000, -1.00000, -1.00000) -- (1.00000, 1.00000, -1.00000);
93
+ \draw[edge,back] (1.00000, -1.00000, -1.00000) -- (1.00000, -1.00000, 1.00000);
94
+ \draw[edge,back] (1.00000, -1.00000, -1.00000) -- (-1.00000, -1.00000, -1.00000);
95
+ \draw[edge,back] (1.00000, 1.00000, -1.00000) -- (1.00000, 1.00000, 1.00000);
96
+ \draw[edge,back] (1.00000, 1.00000, -1.00000) -- (-1.00000, 1.00000, -1.00000);
97
+ \draw[edge,back] (-1.00000, -1.00000, 1.00000) -- (-1.00000, -1.00000, -1.00000);
98
+ \draw[edge,back] (-1.00000, -1.00000, -1.00000) -- (-1.00000, 1.00000, -1.00000);
99
+ \draw[edge,back] (-1.00000, 1.00000, -1.00000) -- (-1.00000, 1.00000, 1.00000);
100
+ %%
101
+ %%
102
+ %% Drawing vertices in the back
103
+ %%
104
+ \node[vertex] at (1.00000, -1.00000, -1.00000) {};
105
+ \node[vertex] at (1.00000, 1.00000, -1.00000) {};
106
+ \node[vertex] at (-1.00000, 1.00000, -1.00000) {};
107
+ \node[vertex] at (-1.00000, -1.00000, -1.00000) {};
108
+ %%
109
+ %%
110
+ %% Drawing the facets
111
+ %%
112
+ \fill[facet] (-1.00000, 1.00000, 1.00000) -- (1.00000, 1.00000, 1.00000) -- (1.00000, -1.00000, 1.00000) -- (-1.00000, -1.00000, 1.00000) -- cycle {};
113
+ %%
114
+ %%
115
+ %% Drawing edges in the front
116
+ %%
117
+ \draw[edge] (1.00000, 1.00000, 1.00000) -- (1.00000, -1.00000, 1.00000);
118
+ \draw[edge] (1.00000, 1.00000, 1.00000) -- (-1.00000, 1.00000, 1.00000);
119
+ \draw[edge] (1.00000, -1.00000, 1.00000) -- (-1.00000, -1.00000, 1.00000);
120
+ \draw[edge] (-1.00000, -1.00000, 1.00000) -- (-1.00000, 1.00000, 1.00000);
121
+ %%
122
+ %%
123
+ %% Drawing the vertices in the front
124
+ %%
125
+ \node[vertex] at (1.00000, 1.00000, 1.00000) {};
126
+ \node[vertex] at (1.00000, -1.00000, 1.00000) {};
127
+ \node[vertex] at (-1.00000, -1.00000, 1.00000) {};
128
+ \node[vertex] at (-1.00000, 1.00000, 1.00000) {};
129
+ %%
130
+ %%
131
+ \end{tikzpicture}
132
+ \end{document}
133
+
134
+ sage: Q = polytopes.hypercube(4)
135
+ sage: Polyhedron_base6.show(Q) # needs sage.plot
136
+ sage: Polyhedron_base6.schlegel_projection(Q)
137
+ The projection of a polyhedron into 3 dimensions
138
+
139
+ sage: R = polytopes.simplex(5)
140
+ sage: Polyhedron_base6.affine_hull(R)
141
+ A 5-dimensional polyhedron in ZZ^6 defined as the convex hull of 1 vertex and 5 lines
142
+ sage: Polyhedron_base6.affine_hull_projection(R)
143
+ A 5-dimensional polyhedron in ZZ^5 defined as the convex hull of 6 vertices
144
+ """
145
+ def plot(self,
146
+ point=None, line=None, polygon=None, # None means unspecified by the user
147
+ wireframe='blue', fill='green',
148
+ position=None,
149
+ orthonormal=True, # whether to use orthonormal projections
150
+ **kwds):
151
+ r"""
152
+ Return a graphical representation.
153
+
154
+ INPUT:
155
+
156
+ - ``point``, ``line``, ``polygon`` -- parameters to pass to
157
+ point (0d), line (1d), and polygon (2d) plot commands.
158
+ Allowed values are:
159
+
160
+ * A Python dictionary to be passed as keywords to the plot
161
+ commands.
162
+
163
+ * A string or triple of numbers: The color. This is
164
+ equivalent to passing the dictionary ``{'color':...}``.
165
+
166
+ * ``False``: Switches off the drawing of the corresponding
167
+ graphics object
168
+
169
+ - ``wireframe``, ``fill`` -- similar to ``point``, ``line``,
170
+ and ``polygon``, but ``fill`` is used for the graphics
171
+ objects in the dimension of the polytope (or of dimension 2
172
+ for higher dimensional polytopes) and ``wireframe`` is used
173
+ for all lower-dimensional graphics objects
174
+ (default: 'green' for ``fill`` and 'blue' for ``wireframe``)
175
+
176
+ - ``position`` -- positive number; the position to take the projection
177
+ point in Schlegel diagrams
178
+
179
+ - ``orthonormal`` -- boolean (default: ``True``); whether to use
180
+ orthonormal projections
181
+
182
+ - ``**kwds`` -- optional keyword parameters that are passed to
183
+ all graphics objects
184
+
185
+ OUTPUT:
186
+
187
+ A (multipart) graphics object.
188
+
189
+ EXAMPLES::
190
+
191
+ sage: square = polytopes.hypercube(2)
192
+ sage: point = Polyhedron([[1,1]])
193
+ sage: line = Polyhedron([[1,1],[2,1]])
194
+ sage: cube = polytopes.hypercube(3)
195
+ sage: hypercube = polytopes.hypercube(4)
196
+
197
+ By default, the wireframe is rendered in blue and the fill in green::
198
+
199
+ sage: # needs sage.plot
200
+ sage: square.plot()
201
+ Graphics object consisting of 6 graphics primitives
202
+ sage: point.plot()
203
+ Graphics object consisting of 1 graphics primitive
204
+ sage: line.plot()
205
+ Graphics object consisting of 2 graphics primitives
206
+ sage: cube.plot()
207
+ Graphics3d Object
208
+ sage: hypercube.plot()
209
+ Graphics3d Object
210
+
211
+ Draw the lines in red and nothing else::
212
+
213
+ sage: # needs sage.plot
214
+ sage: square.plot(point=False, line='red', polygon=False)
215
+ Graphics object consisting of 4 graphics primitives
216
+ sage: point.plot(point=False, line='red', polygon=False)
217
+ Graphics object consisting of 0 graphics primitives
218
+ sage: line.plot(point=False, line='red', polygon=False)
219
+ Graphics object consisting of 1 graphics primitive
220
+ sage: cube.plot(point=False, line='red', polygon=False)
221
+ Graphics3d Object
222
+ sage: hypercube.plot(point=False, line='red', polygon=False)
223
+ Graphics3d Object
224
+
225
+ Draw points in red, no lines, and a blue polygon::
226
+
227
+ sage: # needs sage.plot
228
+ sage: square.plot(point={'color':'red'}, line=False, polygon=(0,0,1))
229
+ Graphics object consisting of 2 graphics primitives
230
+ sage: point.plot(point={'color':'red'}, line=False, polygon=(0,0,1))
231
+ Graphics object consisting of 1 graphics primitive
232
+ sage: line.plot(point={'color':'red'}, line=False, polygon=(0,0,1))
233
+ Graphics object consisting of 1 graphics primitive
234
+ sage: cube.plot(point={'color':'red'}, line=False, polygon=(0,0,1))
235
+ Graphics3d Object
236
+ sage: hypercube.plot(point={'color':'red'}, line=False, polygon=(0,0,1))
237
+ Graphics3d Object
238
+
239
+ If we instead use the ``fill`` and ``wireframe`` options, the
240
+ coloring depends on the dimension of the object::
241
+
242
+ sage: # needs sage.plot
243
+ sage: square.plot(fill='green', wireframe='red')
244
+ Graphics object consisting of 6 graphics primitives
245
+ sage: point.plot(fill='green', wireframe='red')
246
+ Graphics object consisting of 1 graphics primitive
247
+ sage: line.plot(fill='green', wireframe='red')
248
+ Graphics object consisting of 2 graphics primitives
249
+ sage: cube.plot(fill='green', wireframe='red')
250
+ Graphics3d Object
251
+ sage: hypercube.plot(fill='green', wireframe='red')
252
+ Graphics3d Object
253
+
254
+ It is possible to draw polyhedra up to dimension 4, no matter what the
255
+ ambient dimension is::
256
+
257
+ sage: hcube = polytopes.hypercube(5)
258
+ sage: facet = hcube.facets()[0].as_polyhedron(); facet
259
+ A 4-dimensional polyhedron in ZZ^5 defined as the convex hull of 16 vertices
260
+ sage: facet.plot() # needs sage.plot
261
+ Graphics3d Object
262
+
263
+ For a 3d plot, we may draw the polygons with rainbow colors, using any of the following ways::
264
+
265
+ sage: cube.plot(polygon='rainbow') # needs sage.plot
266
+ Graphics3d Object
267
+ sage: cube.plot(polygon={'color':'rainbow'}) # needs sage.plot
268
+ Graphics3d Object
269
+ sage: cube.plot(fill='rainbow') # needs sage.plot
270
+ Graphics3d Object
271
+
272
+ For a 3d plot, the size of a point, the thickness of a line and the width of an arrow
273
+ are controlled by the respective parameters::
274
+
275
+ sage: prism = Polyhedron(vertices=[[0,0,0],[1,0,0],[0,1,0]], rays=[[0,0,1]])
276
+ sage: prism.plot(size=20, thickness=30, width=1) # needs sage.plot
277
+ Graphics3d Object
278
+ sage: prism.plot(point={'size':20, 'color':'black'}, # needs sage.plot
279
+ ....: line={'thickness':30, 'width':1, 'color':'black'},
280
+ ....: polygon='rainbow')
281
+ Graphics3d Object
282
+
283
+ TESTS::
284
+
285
+ sage: for p in square.plot(): # needs sage.plot
286
+ ....: print("{} {}".format(p.options()['rgbcolor'], p))
287
+ blue Point set defined by 4 point(s)
288
+ blue Line defined by 2 points
289
+ blue Line defined by 2 points
290
+ blue Line defined by 2 points
291
+ blue Line defined by 2 points
292
+ green Polygon defined by 4 points
293
+
294
+ sage: for p in line.plot(): # needs sage.plot
295
+ ....: print("{} {}".format(p.options()['rgbcolor'], p))
296
+ blue Point set defined by 2 point(s)
297
+ green Line defined by 2 points
298
+
299
+ sage: for p in point.plot(): # needs sage.plot
300
+ ....: print("{} {}".format(p.options()['rgbcolor'], p))
301
+ green Point set defined by 1 point(s)
302
+
303
+ Draw the lines in red and nothing else::
304
+
305
+ sage: for p in square.plot(point=False, line='red', polygon=False): # needs sage.plot
306
+ ....: print("{} {}".format(p.options()['rgbcolor'], p))
307
+ red Line defined by 2 points
308
+ red Line defined by 2 points
309
+ red Line defined by 2 points
310
+ red Line defined by 2 points
311
+
312
+ Draw vertices in red, no lines, and a blue polygon::
313
+
314
+ sage: for p in square.plot(point={'color':'red'}, line=False, polygon=(0,0,1)): # needs sage.plot
315
+ ....: print("{} {}".format(p.options()['rgbcolor'], p))
316
+ red Point set defined by 4 point(s)
317
+ (0, 0, 1) Polygon defined by 4 points
318
+
319
+ sage: for p in line.plot(point={'color':'red'}, line=False, polygon=(0,0,1)): # needs sage.plot
320
+ ....: print("{} {}".format(p.options()['rgbcolor'], p))
321
+ red Point set defined by 2 point(s)
322
+
323
+ sage: for p in point.plot(point={'color':'red'}, line=False, polygon=(0,0,1)): # needs sage.plot
324
+ ....: print("{} {}".format(p.options()['rgbcolor'], p))
325
+ red Point set defined by 1 point(s)
326
+
327
+ Draw in red without wireframe::
328
+
329
+ sage: for p in square.plot(wireframe=False, fill='red'): # needs sage.plot
330
+ ....: print("{} {}".format(p.options()['rgbcolor'], p))
331
+ red Polygon defined by 4 points
332
+
333
+ sage: for p in line.plot(wireframe=False, fill='red'): # needs sage.plot
334
+ ....: print("{} {}".format(p.options()['rgbcolor'], p))
335
+ red Line defined by 2 points
336
+
337
+ sage: for p in point.plot(wireframe=False, fill='red'): # needs sage.plot
338
+ ....: print("{} {}".format(p.options()['rgbcolor'], p))
339
+ red Point set defined by 1 point(s)
340
+
341
+ We try to draw the polytope in 2 or 3 dimensions::
342
+
343
+ sage: # needs sage.plot
344
+ sage: type(Polyhedron(ieqs=[(1,)]).plot())
345
+ <class 'sage.plot.graphics.Graphics'>
346
+ sage: type(polytopes.hypercube(1).plot())
347
+ <class 'sage.plot.graphics.Graphics'>
348
+ sage: type(polytopes.hypercube(2).plot())
349
+ <class 'sage.plot.graphics.Graphics'>
350
+ sage: type(polytopes.hypercube(3).plot())
351
+ <class 'sage.plot.plot3d.base.Graphics3dGroup'>
352
+
353
+ In 4d a projection to 3d is used::
354
+
355
+ sage: type(polytopes.hypercube(4).plot()) # needs sage.plot
356
+ <class 'sage.plot.plot3d.base.Graphics3dGroup'>
357
+ sage: type(polytopes.hypercube(5).plot())
358
+ Traceback (most recent call last):
359
+ ...
360
+ NotImplementedError: plotting of 5-dimensional polyhedra not implemented
361
+
362
+ If the polyhedron is not full-dimensional, the :meth:`affine_hull_projection` is used if necessary::
363
+
364
+ sage: # needs sage.plot
365
+ sage: type(Polyhedron([(0,), (1,)]).plot())
366
+ <class 'sage.plot.graphics.Graphics'>
367
+ sage: type(Polyhedron([(0,0), (1,1)]).plot())
368
+ <class 'sage.plot.graphics.Graphics'>
369
+ sage: type(Polyhedron([(0,0,0), (1,1,1)]).plot())
370
+ <class 'sage.plot.plot3d.base.Graphics3dGroup'>
371
+ sage: type(Polyhedron([(0,0,0,0), (1,1,1,1)]).plot())
372
+ <class 'sage.plot.graphics.Graphics'>
373
+ sage: type(Polyhedron([(0,0,0,0,0), (1,1,1,1,1)]).plot()) # needs sage.symbolic
374
+ <class 'sage.plot.graphics.Graphics'>
375
+ sage: type(Polyhedron([(0,0,0,0), (1,1,1,1), (1,0,0,0)]).plot()) # needs sage.symbolic
376
+ <class 'sage.plot.graphics.Graphics'>
377
+
378
+ TESTS:
379
+
380
+ Check that :issue:`30015` is fixed::
381
+
382
+ sage: fcube = polytopes.hypercube(4)
383
+ sage: tfcube = fcube.face_truncation(fcube.faces(0)[0])
384
+ sage: sp = tfcube.schlegel_projection()
385
+ sage: for face in tfcube.faces(2): # needs cddexec
386
+ ....: vertices = face.ambient_Vrepresentation()
387
+ ....: indices = [sp.coord_index_of(vector(x)) for x in vertices]
388
+ ....: projected_vertices = [sp.transformed_coords[i] for i in indices]
389
+ ....: assert Polyhedron(projected_vertices).dim() == 2
390
+
391
+ Check that :issue:`31802` is fixed::
392
+
393
+ sage: # needs sage.plot
394
+ sage: halfspace = Polyhedron(rays=[(0, 0, 1)], lines=[(1, 0, 0), (0, 1, 0)])
395
+ sage: len(halfspace.projection().arrows)
396
+ 5
397
+ sage: halfspace.plot(fill=(0, 1, 0))
398
+ Graphics3d Object
399
+ sage: fullspace = Polyhedron(lines=[(1, 0, 0), (0, 1, 0), (0, 0, 1)])
400
+ sage: len(fullspace.projection().arrows)
401
+ 6
402
+ sage: fullspace.plot(color=(1, 0, 0), alpha=0.5)
403
+ Graphics3d Object
404
+ sage: cone = Polyhedron(rays=[(1, 0, 0), (0, 1, 0), (0, 0, 1)])
405
+ sage: cone.plot(fill='rainbow', alpha=0.6)
406
+ Graphics3d Object
407
+ sage: p = Polyhedron(vertices=[(0, 0, 0), (1, 0, 0)], rays=[(-1, 1, 0), (1, 1, 0), (0, 0, 1)])
408
+ sage: p.plot(fill='mediumspringgreen', point='red', size=30, width=2)
409
+ Graphics3d Object
410
+
411
+ sage: cylinder = Polyhedron(vertices=[(0, 0, 0), (1, 0, 0), (0, 1, 0)], lines=[(0, 0, 1)])
412
+ sage: cylinder.plot(fill='red') # check it is not all black # needs sage.plot
413
+ Graphics3d Object
414
+ sage: quarter = Polyhedron(rays=[(-1, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)])
415
+ sage: quarter.plot(fill='rainbow') # check it is not all black nor with too many colors # needs sage.plot
416
+ Graphics3d Object
417
+ """
418
+ def merge_options(*opts):
419
+ merged = dict()
420
+ for i in range(len(opts)):
421
+ opt = opts[i]
422
+ if opt is None:
423
+ continue
424
+ elif opt is False:
425
+ return False
426
+ elif isinstance(opt, (str, list, tuple)):
427
+ merged['color'] = opt
428
+ else:
429
+ merged.update(opt)
430
+ return merged
431
+
432
+ d = min(self.dim(), 2)
433
+ opts = [wireframe] * d + [fill] + [False] * (2-d)
434
+ # The point/line/polygon options take precedence over wireframe/fill
435
+ opts = [merge_options(opt1, opt2, kwds)
436
+ for opt1, opt2 in zip(opts, [point, line, polygon])]
437
+
438
+ def project(polyhedron, ortho):
439
+ if polyhedron.ambient_dim() <= 3:
440
+ return polyhedron.projection()
441
+ elif polyhedron.dim() <= 3:
442
+ if ortho:
443
+ return polyhedron.affine_hull_projection(orthonormal=True, extend=True).projection()
444
+ else:
445
+ return polyhedron.affine_hull_projection().projection()
446
+ elif polyhedron.dimension() == 4:
447
+ # For 4d-polyhedron, we can use schlegel projections:
448
+ return polyhedron.schlegel_projection(position=position)
449
+ else:
450
+ return polyhedron.projection()
451
+
452
+ projection = project(self, orthonormal)
453
+ try:
454
+ plot_method = projection.plot
455
+ except AttributeError:
456
+ raise NotImplementedError('plotting of {0}-dimensional polyhedra not implemented'
457
+ .format(self.ambient_dim()))
458
+ return plot_method(*opts)
459
+
460
+ def show(self, **kwds):
461
+ r"""
462
+ Display graphics immediately.
463
+
464
+ This method attempts to display the graphics immediately,
465
+ without waiting for the currently running code (if any) to
466
+ return to the command line. Be careful, calling it from within
467
+ a loop will potentially launch a large number of external
468
+ viewer programs.
469
+
470
+ INPUT:
471
+
472
+ - ``kwds`` -- optional keyword arguments; see :meth:`plot` for
473
+ the description of available options
474
+
475
+ OUTPUT:
476
+
477
+ This method does not return anything. Use :meth:`plot` if you
478
+ want to generate a graphics object that can be saved or
479
+ further transformed.
480
+
481
+ EXAMPLES::
482
+
483
+ sage: square = polytopes.hypercube(2)
484
+ sage: square.show(point='red') # needs sage.plot
485
+ """
486
+ self.plot(**kwds).show()
487
+
488
+ def tikz(self, view=[0, 0, 1], angle=0, scale=1,
489
+ edge_color='blue!95!black', facet_color='blue!95!black',
490
+ opacity=0.8, vertex_color='green', axis=False,
491
+ output_type=None):
492
+ r"""
493
+ Return a tikz picture of ``self`` as a string or as a
494
+ :class:`~sage.misc.latex_standalone.TikzPicture`
495
+ according to a projection ``view`` and an angle ``angle``
496
+ obtained via the threejs viewer. ``self`` must be bounded.
497
+
498
+ INPUT:
499
+
500
+ - ``view`` -- list (default: [0,0,1]) representing the rotation axis (see note below)
501
+ - ``angle`` -- integer (default: 0); angle of rotation in degree from 0 to 360 (see note
502
+ below)
503
+ - ``scale`` -- integer (default: 1); the scaling of the tikz picture
504
+ - ``edge_color`` -- string (default: ``'blue!95!black'``); representing colors which tikz
505
+ recognizes
506
+ - ``facet_color`` -- string (default: ``'blue!95!black'``); representing colors which tikz
507
+ recognizes
508
+ - ``vertex_color`` -- string (default: ``'green'``); representing colors which tikz
509
+ recognizes
510
+ - ``opacity`` -- real number (default: 0.8) between 0 and 1 giving the opacity of
511
+ the front facets
512
+ - ``axis`` -- boolean (default: ``False``); draw the axes at the origin or not
513
+ - ``output_type`` -- string (default: ``None``); valid values
514
+ are ``None`` (deprecated), ``'LatexExpr'`` and ``'TikzPicture'``,
515
+ whether to return a LatexExpr object (which inherits from Python
516
+ str) or a ``TikzPicture`` object from module
517
+ :mod:`sage.misc.latex_standalone`
518
+
519
+ OUTPUT: LatexExpr object or TikzPicture object
520
+
521
+ .. NOTE::
522
+
523
+ This is a wrapper of a method of the projection object
524
+ ``self.projection()``. See :meth:`~sage.geometry.polyhedron.plot.Projection.tikz`
525
+ for more detail.
526
+
527
+ The inputs ``view`` and ``angle`` can be obtained by visualizing it
528
+ using ``.show(aspect_ratio=1)``. This will open an interactive view
529
+ in your default browser, where you can rotate the polytope. Once
530
+ the desired view angle is found, click on the information icon in
531
+ the lower right-hand corner and select *Get Viewpoint*. This will
532
+ copy a string of the form '[x,y,z],angle' to your local clipboard.
533
+ Go back to Sage and type ``Img = P.tikz([x,y,z],angle)``.
534
+
535
+ The inputs ``view`` and ``angle`` can also be obtained from the
536
+ viewer Jmol::
537
+
538
+ 1) Right click on the image
539
+ 2) Select ``Console``
540
+ 3) Select the tab ``State``
541
+ 4) Scroll to the line ``moveto``
542
+
543
+ It reads something like::
544
+
545
+ moveto 0.0 {x y z angle} Scale
546
+
547
+ The ``view`` is then [x,y,z] and ``angle`` is angle.
548
+ The following number is the scale.
549
+
550
+ Jmol performs a rotation of ``angle`` degrees along the
551
+ vector [x,y,z] and show the result from the z-axis.
552
+
553
+ EXAMPLES::
554
+
555
+ sage: # needs sage.plot
556
+ sage: co = polytopes.cuboctahedron()
557
+ sage: Img = co.tikz([0, 0, 1], 0, output_type='TikzPicture')
558
+ sage: Img
559
+ \documentclass[tikz]{standalone}
560
+ \begin{document}
561
+ \begin{tikzpicture}%
562
+ [x={(1.000000cm, 0.000000cm)},
563
+ y={(0.000000cm, 1.000000cm)},
564
+ z={(0.000000cm, 0.000000cm)},
565
+ scale=1.000000,
566
+ ...
567
+ Use print to see the full content.
568
+ ...
569
+ \node[vertex] at (1.00000, 0.00000, 1.00000) {};
570
+ \node[vertex] at (1.00000, 1.00000, 0.00000) {};
571
+ %%
572
+ %%
573
+ \end{tikzpicture}
574
+ \end{document}
575
+ sage: print('\n'.join(Img.content().splitlines()[12:21]))
576
+ %% with the command: ._tikz_3d_in_3d and parameters:
577
+ %% view = [0, 0, 1]
578
+ %% angle = 0
579
+ %% scale = 1
580
+ %% edge_color = blue!95!black
581
+ %% facet_color = blue!95!black
582
+ %% opacity = 0.8
583
+ %% vertex_color = green
584
+ %% axis = False
585
+ sage: print('\n'.join(Img.content().splitlines()[22:26]))
586
+ %% Coordinate of the vertices:
587
+ %%
588
+ \coordinate (-1.00000, -1.00000, 0.00000) at (-1.00000, -1.00000, 0.00000);
589
+ \coordinate (-1.00000, 0.00000, -1.00000) at (-1.00000, 0.00000, -1.00000);
590
+
591
+ When output type is a :class:`sage.misc.latex_standalone.TikzPicture`::
592
+
593
+ sage: # needs sage.plot
594
+ sage: co = polytopes.cuboctahedron()
595
+ sage: t = co.tikz([674, 108, -731], 112, output_type='TikzPicture'); t
596
+ \documentclass[tikz]{standalone}
597
+ \begin{document}
598
+ \begin{tikzpicture}%
599
+ [x={(0.249656cm, -0.577639cm)},
600
+ y={(0.777700cm, -0.358578cm)},
601
+ z={(-0.576936cm, -0.733318cm)},
602
+ scale=1.000000,
603
+ ...
604
+ Use print to see the full content.
605
+ ...
606
+ \node[vertex] at (1.00000, 0.00000, 1.00000) {};
607
+ \node[vertex] at (1.00000, 1.00000, 0.00000) {};
608
+ %%
609
+ %%
610
+ \end{tikzpicture}
611
+ \end{document}
612
+ sage: path_to_file = t.pdf() # not tested
613
+ """
614
+ return self.projection().tikz(view, angle, scale,
615
+ edge_color, facet_color,
616
+ opacity, vertex_color, axis,
617
+ output_type=output_type)
618
+
619
+ def _rich_repr_(self, display_manager, **kwds):
620
+ r"""
621
+ Rich Output Magic Method.
622
+
623
+ See :mod:`sage.repl.rich_output` for details.
624
+
625
+ EXAMPLES::
626
+
627
+ sage: from sage.repl.rich_output import get_display_manager
628
+ sage: dm = get_display_manager()
629
+ sage: polytopes.hypercube(2)._rich_repr_(dm)
630
+ OutputPlainText container
631
+
632
+ The ``supplemental_plot`` preference lets us control whether
633
+ this object is shown as text or picture+text::
634
+
635
+ sage: dm.preferences.supplemental_plot
636
+ 'never'
637
+ sage: del dm.preferences.supplemental_plot
638
+ sage: polytopes.hypercube(3)
639
+ A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices (use the .plot() method to plot)
640
+ sage: dm.preferences.supplemental_plot = 'never'
641
+ """
642
+ prefs = display_manager.preferences
643
+ is_small = (self.ambient_dim() <= 2)
644
+ can_plot = (prefs.supplemental_plot != 'never')
645
+ plot_graph = can_plot and (prefs.supplemental_plot == 'always' or is_small)
646
+ # Under certain circumstances we display the plot as graphics
647
+ if plot_graph:
648
+ plot_kwds = dict(kwds)
649
+ plot_kwds.setdefault('title', repr(self))
650
+ output = self.plot(**plot_kwds)._rich_repr_(display_manager)
651
+ if output is not None:
652
+ return output
653
+ # create text for non-graphical output
654
+ if can_plot:
655
+ text = '{0} (use the .plot() method to plot)'.format(repr(self))
656
+ else:
657
+ text = repr(self)
658
+ # latex() produces huge tikz environment, override
659
+ tp = display_manager.types
660
+ if (prefs.text == 'latex' and tp.OutputLatex in display_manager.supported_output()):
661
+ return tp.OutputLatex(r'\text{{{0}}}'.format(text))
662
+ return tp.OutputPlainText(text)
663
+
664
+ @cached_method
665
+ def gale_transform(self):
666
+ r"""
667
+ Return the Gale transform of a polytope as described in the
668
+ reference below.
669
+
670
+ OUTPUT:
671
+
672
+ A list of vectors, the Gale transform. The dimension is the
673
+ dimension of the affine dependencies of the vertices of the
674
+ polytope.
675
+
676
+ EXAMPLES:
677
+
678
+ This is from the reference, for a triangular prism::
679
+
680
+ sage: p = Polyhedron(vertices = [[0,0],[0,1],[1,0]])
681
+ sage: p2 = p.prism()
682
+ sage: p2.gale_transform()
683
+ ((-1, 0), (0, -1), (1, 1), (-1, -1), (1, 0), (0, 1))
684
+
685
+ REFERENCES:
686
+
687
+ Lectures in Geometric Combinatorics, R.R.Thomas, 2006, AMS Press.
688
+
689
+ .. SEEALSO::
690
+
691
+ :func:`~sage.geometry.polyhedron.library.gale_transform_to_polyhedron`.
692
+
693
+ TESTS::
694
+
695
+ sage: P = Polyhedron(rays=[[1,0,0]])
696
+ sage: P.gale_transform()
697
+ Traceback (most recent call last):
698
+ ...
699
+ ValueError: not a polytope
700
+
701
+ Check that :issue:`29073` is fixed::
702
+
703
+ sage: P = polytopes.icosahedron(exact=False) # needs sage.groups
704
+ sage: sum(P.gale_transform()).norm() < 1e-15 # needs sage.groups
705
+ True
706
+ """
707
+ if not self.is_compact():
708
+ raise ValueError('not a polytope')
709
+
710
+ A = matrix(self.n_vertices(),
711
+ [[1]+x for x in self.vertex_generator()])
712
+ A = A.transpose()
713
+ A_ker = A.right_kernel_matrix(basis='computed')
714
+ return tuple(A_ker.columns())
715
+
716
+ def _test_gale_transform(self, tester=None, **options):
717
+ r"""
718
+ Run tests on the method :meth:`.gale_transform` and its inverse
719
+ :meth:`~sage.geometry.polyhedron.library.gale_transform_to_polytope`.
720
+
721
+ TESTS::
722
+
723
+ sage: polytopes.cross_polytope(3)._test_gale_transform()
724
+ """
725
+ if tester is None:
726
+ tester = self._tester(**options)
727
+
728
+ if not self.is_compact():
729
+ with tester.assertRaises(ValueError):
730
+ self.gale_transform()
731
+ return
732
+
733
+ # Check :issue:`29073`.
734
+ if not self.base_ring().is_exact() and self.ambient_dim() > 0:
735
+ g = self.gale_transform()
736
+ tester.assertTrue(sum(g).norm() < 1e-10 or sum(g).norm()/matrix(g).norm() < 1e-13)
737
+ return
738
+
739
+ # Prevent very long doctests.
740
+ if self.n_vertices() + self.n_rays() > 50 or self.n_facets() > 50:
741
+ return
742
+
743
+ if not self.is_empty():
744
+ # ``gale_transform_to_polytope`` needs at least one vertex to work.
745
+ from sage.geometry.polyhedron.library import gale_transform_to_polytope
746
+ g = self.gale_transform()
747
+ P = gale_transform_to_polytope(g, base_ring=self.base_ring(), backend=self.backend())
748
+
749
+ try:
750
+ import sage.graphs.graph
751
+ assert sage.graphs.graph # to muffle pyflakes
752
+ except ImportError:
753
+ pass
754
+ else:
755
+ tester.assertTrue(self.is_combinatorially_isomorphic(P))
756
+
757
+ def projection(self, projection=None):
758
+ r"""
759
+ Return a projection object.
760
+
761
+ INPUT:
762
+
763
+ - ``proj`` -- a projection function
764
+
765
+ OUTPUT:
766
+
767
+ The identity projection. This is useful for plotting
768
+ polyhedra.
769
+
770
+ .. SEEALSO::
771
+
772
+ :meth:`~sage.geometry.polyhedron.base6.Polyhedron_base6.schlegel_projection` for a more interesting projection.
773
+
774
+ EXAMPLES::
775
+
776
+ sage: p = polytopes.hypercube(3)
777
+ sage: proj = p.projection()
778
+ sage: proj
779
+ The projection of a polyhedron into 3 dimensions
780
+ """
781
+ from .plot import Projection
782
+ if projection is not None:
783
+ self.projection = Projection(self, projection)
784
+ else:
785
+ self.projection = Projection(self)
786
+ return self.projection
787
+
788
+ def render_solid(self, **kwds):
789
+ r"""
790
+ Return a solid rendering of a 2- or 3-d polytope.
791
+
792
+ EXAMPLES::
793
+
794
+ sage: p = polytopes.hypercube(3)
795
+ sage: p_solid = p.render_solid(opacity=.7) # needs sage.plot
796
+ sage: type(p_solid) # needs sage.plot
797
+ <class 'sage.plot.plot3d.index_face_set.IndexFaceSet'>
798
+ """
799
+ proj = self.projection()
800
+ if self.ambient_dim() == 3:
801
+ return proj.render_solid_3d(**kwds)
802
+ if self.ambient_dim() == 2:
803
+ return proj.render_fill_2d(**kwds)
804
+ raise ValueError("render_solid is only defined for 2 and 3 dimensional polyhedra")
805
+
806
+ def render_wireframe(self, **kwds):
807
+ r"""
808
+ For polytopes in 2 or 3 dimensions, return the edges
809
+ as a list of lines.
810
+
811
+ EXAMPLES::
812
+
813
+ sage: p = Polyhedron([[1,2,],[1,1],[0,0]])
814
+ sage: p_wireframe = p.render_wireframe() # needs sage.plot
815
+ sage: p_wireframe._objects # needs sage.plot
816
+ [Line defined by 2 points, Line defined by 2 points, Line defined by 2 points]
817
+ """
818
+ proj = self.projection()
819
+ if self.ambient_dim() == 3:
820
+ return proj.render_wireframe_3d(**kwds)
821
+ if self.ambient_dim() == 2:
822
+ return proj.render_outline_2d(**kwds)
823
+ raise ValueError("render_wireframe is only defined for 2 and 3 dimensional polyhedra")
824
+
825
+ def schlegel_projection(self, facet=None, position=None):
826
+ r"""
827
+ Return the Schlegel projection.
828
+
829
+ * The facet is orthonormally transformed into its affine hull.
830
+
831
+ * The position specifies a point coming out of the barycenter of the
832
+ facet from which the other vertices will be projected into the facet.
833
+
834
+ INPUT:
835
+
836
+ - ``facet`` -- a :class:`~sage.geometry.polyhedron.face.PolyhedronFace`
837
+ The facet into which the Schlegel diagram is created. The default is the first facet
838
+
839
+ - ``position`` -- a positive number. Determines a relative distance
840
+ from the barycenter of ``facet``. A value close to 0 will place the
841
+ projection point close to the facet and a large value further away.
842
+ Default is `1`. If the given value is too large, an error is returned.
843
+
844
+ OUTPUT: a :class:`~sage.geometry.polyhedron.plot.Projection` object
845
+
846
+ EXAMPLES::
847
+
848
+ sage: p = polytopes.hypercube(3)
849
+ sage: sch_proj = p.schlegel_projection()
850
+ sage: schlegel_edge_indices = sch_proj.lines
851
+ sage: schlegel_edges = [sch_proj.coordinates_of(x) for x in schlegel_edge_indices]
852
+ sage: len([x for x in schlegel_edges if x[0][0] > 0])
853
+ 8
854
+
855
+ The Schlegel projection preserves the convexity of facets, see :issue:`30015`::
856
+
857
+ sage: fcube = polytopes.hypercube(4)
858
+ sage: tfcube = fcube.face_truncation(fcube.faces(0)[0])
859
+ sage: tfcube.facets()[-1]
860
+ A 3-dimensional face of a Polyhedron in QQ^4 defined as the convex hull of 8 vertices
861
+ sage: sp = tfcube.schlegel_projection(tfcube.facets()[-1])
862
+ sage: sp.plot() # needs sage.plot
863
+ Graphics3d Object
864
+
865
+ The same truncated cube but see inside the tetrahedral facet::
866
+
867
+ sage: tfcube.facets()[4]
868
+ A 3-dimensional face of a Polyhedron in QQ^4 defined as the convex hull of 4 vertices
869
+ sage: sp = tfcube.schlegel_projection(tfcube.facets()[4]) # needs sage.symbolic
870
+ sage: sp.plot() # needs sage.plot sage.symbolic
871
+ Graphics3d Object
872
+
873
+ A different values of ``position`` changes the projection::
874
+
875
+ sage: # needs sage.symbolic
876
+ sage: sp = tfcube.schlegel_projection(tfcube.facets()[4], 1/2)
877
+ sage: sp.plot() # needs sage.plot
878
+ Graphics3d Object
879
+ sage: sp = tfcube.schlegel_projection(tfcube.facets()[4], 4)
880
+ sage: sp.plot() # needs sage.plot
881
+ Graphics3d Object
882
+
883
+ A value which is too large give a projection point that sees more than
884
+ one facet resulting in a error::
885
+
886
+ sage: sp = tfcube.schlegel_projection(tfcube.facets()[4], 5)
887
+ Traceback (most recent call last):
888
+ ...
889
+ ValueError: the chosen position is too large
890
+ """
891
+ proj = self.projection()
892
+ return proj.schlegel(facet, position)
893
+
894
+ def affine_hull(self, *args, **kwds):
895
+ r"""
896
+ Return the affine hull of ``self`` as a polyhedron.
897
+
898
+ EXAMPLES::
899
+
900
+ sage: half_plane_in_space = Polyhedron(ieqs=[(0,1,0,0)], eqns=[(0,0,0,1)])
901
+ sage: half_plane_in_space.affine_hull().Hrepresentation()
902
+ (An equation (0, 0, 1) x + 0 == 0,)
903
+
904
+ sage: polytopes.cube().affine_hull().is_universe()
905
+ True
906
+ """
907
+ if args or kwds:
908
+ raise TypeError("the method 'affine_hull' does not take any parameters; perhaps you meant 'affine_hull_projection'")
909
+ if not self.inequalities():
910
+ return self
911
+ self_as_face = self.faces(self.dimension())[0]
912
+ return self_as_face.affine_tangent_cone()
913
+
914
+ @cached_method
915
+ def _affine_hull_projection(self, *,
916
+ as_convex_set=True, as_affine_map=True, as_section_map=True,
917
+ orthogonal=False, orthonormal=False,
918
+ extend=False, minimal=False):
919
+ r"""
920
+ Return ``self`` projected into its affine hull.
921
+
922
+ INPUT:
923
+
924
+ See :meth:`affine_hull_projection`.
925
+
926
+ OUTPUT:
927
+
928
+ An instance of :class:`~sage.geometry.convex_set.AffineHullProjectionData`.
929
+ See :meth:`affine_hull_projection` for details.
930
+
931
+ TESTS:
932
+
933
+ Check that :issue:`23355` is fixed::
934
+
935
+ sage: P = Polyhedron([[7]]); P
936
+ A 0-dimensional polyhedron in ZZ^1 defined as the convex hull of 1 vertex
937
+ sage: P.affine_hull_projection()
938
+ A 0-dimensional polyhedron in ZZ^0 defined as the convex hull of 1 vertex
939
+ sage: P.affine_hull_projection(orthonormal='True')
940
+ A 0-dimensional polyhedron in QQ^0 defined as the convex hull of 1 vertex
941
+ sage: P.affine_hull_projection(orthogonal='True')
942
+ A 0-dimensional polyhedron in QQ^0 defined as the convex hull of 1 vertex
943
+
944
+ Check that :issue:`24047` is fixed::
945
+
946
+ sage: P1 = Polyhedron(vertices=[[-1, 1], [0, -1], [0, 0], [-1, -1]])
947
+ sage: P2 = Polyhedron(vertices=[[1, 1], [1, -1], [0, -1], [0, 0]])
948
+ sage: P = P1.intersection(P2)
949
+ sage: A, b = P.affine_hull_projection(as_affine_map=True,
950
+ ....: orthonormal=True, extend=True)
951
+
952
+ sage: Polyhedron([(2,3,4)]).affine_hull_projection()
953
+ A 0-dimensional polyhedron in ZZ^0 defined as the convex hull of 1 vertex
954
+
955
+ Check that backend is preserved::
956
+
957
+ sage: polytopes.simplex(backend='field').affine_hull_projection().backend()
958
+ 'field'
959
+
960
+ sage: P = Polyhedron(vertices=[[0,0], [1,0]], backend='field')
961
+ sage: P.affine_hull_projection(orthogonal=True, orthonormal=True,
962
+ ....: extend=True).backend()
963
+ 'field'
964
+
965
+ Check that :issue:`29116` is fixed::
966
+
967
+ sage: V = [[1, 0, -1, 0, 0],
968
+ ....: [1, 0, 0, -1, 0],
969
+ ....: [1, 0, 0, 0, -1],
970
+ ....: [1, 0, 0, +1, 0],
971
+ ....: [1, 0, 0, 0, +1],
972
+ ....: [1, +1, 0, 0, 0]]
973
+ sage: P = Polyhedron(V)
974
+ sage: P.affine_hull_projection()
975
+ A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 6 vertices
976
+ sage: P.affine_hull_projection(orthonormal=True) # needs sage.symbolic
977
+ Traceback (most recent call last):
978
+ ...
979
+ ValueError: the base ring needs to be extended; try with "extend=True"
980
+ sage: P.affine_hull_projection(orthonormal=True, extend=True) # needs sage.rings.number_field sage.symbolic
981
+ A 4-dimensional polyhedron in AA^4 defined as the convex hull of 6 vertices
982
+ """
983
+ result = AffineHullProjectionData()
984
+
985
+ if self.is_empty():
986
+ raise ValueError('affine hull projection of an empty polyhedron is undefined')
987
+
988
+ # handle trivial full-dimensional case
989
+ if self.ambient_dim() == self.dim():
990
+ if as_convex_set:
991
+ result.image = self
992
+ if as_affine_map:
993
+ identity = linear_transformation(matrix(self.base_ring(),
994
+ self.dim(),
995
+ self.dim(),
996
+ self.base_ring().one()))
997
+ result.projection_linear_map = result.section_linear_map = identity
998
+ result.projection_translation = result.section_translation = self.ambient_space().zero()
999
+ elif orthogonal or orthonormal:
1000
+ # see TODO
1001
+ if not self.is_compact():
1002
+ raise NotImplementedError('"orthogonal=True" and "orthonormal=True" work only for compact polyhedra')
1003
+ affine_basis = self.an_affine_basis()
1004
+ v0 = affine_basis[0].vector()
1005
+ # We implicitly translate the first vertex of the affine basis to zero.
1006
+ vi = tuple(v.vector() - v0 for v in affine_basis[1:])
1007
+ M = matrix(self.base_ring(), self.dim(), self.ambient_dim(), vi)
1008
+
1009
+ # Switch base_ring to AA if necessary,
1010
+ # since gram_schmidt needs to be able to take square roots.
1011
+ # Pick orthonormal basis and transform all vertices accordingly
1012
+ # if the orthonormal transform makes it necessary, change base ring.
1013
+ try:
1014
+ A, G = M.gram_schmidt(orthonormal=orthonormal)
1015
+ except TypeError:
1016
+ if not extend:
1017
+ raise ValueError('the base ring needs to be extended; try with "extend=True"')
1018
+ from sage.rings.qqbar import AA
1019
+ M = matrix(AA, M)
1020
+ A = M.gram_schmidt(orthonormal=orthonormal)[0]
1021
+ if minimal:
1022
+ from sage.rings.qqbar import number_field_elements_from_algebraics
1023
+ new_ring = number_field_elements_from_algebraics(A.list(), embedded=True, minimal=True)[0]
1024
+ A = A.change_ring(new_ring)
1025
+ L = linear_transformation(A, side='right')
1026
+ ambient_translation = -vector(A.base_ring(), affine_basis[0])
1027
+ image_translation = A * ambient_translation
1028
+ # Note the order. We compute ``A*self`` and then translate the image.
1029
+ # ``A*self`` uses the incidence matrix and we avoid recomputation.
1030
+ # Also, if the new base ring is ``AA``, we want to avoid computing the incidence matrix in that ring.
1031
+ # ``convert=True`` takes care of the case, where there might be no coercion (``AA`` and quadratic field).
1032
+ if as_convex_set:
1033
+ result.image = self.linear_transformation(A, new_base_ring=A.base_ring()) + image_translation
1034
+ if as_affine_map:
1035
+ result.projection_linear_map = L
1036
+ result.projection_translation = image_translation
1037
+ if as_section_map:
1038
+ L_dagger = linear_transformation(A.transpose() * (A * A.transpose()).inverse(), side='right')
1039
+ result.section_linear_map = L_dagger
1040
+ result.section_translation = v0.change_ring(A.base_ring())
1041
+ else:
1042
+ # translate one vertex to the origin
1043
+ v0 = self.vertices()[0].vector()
1044
+ gens = []
1045
+ for v in self.vertices()[1:]:
1046
+ gens.append(v.vector() - v0)
1047
+ for r in self.rays():
1048
+ gens.append(r.vector())
1049
+ for l in self.lines():
1050
+ gens.append(l.vector())
1051
+
1052
+ # Pick subset of coordinates to coordinatize the affine span
1053
+ M = matrix(gens)
1054
+ pivots = M.pivots()
1055
+
1056
+ A = matrix(self.base_ring(), len(pivots), self.ambient_dim(),
1057
+ [[1 if j == i else 0 for j in range(self.ambient_dim())] for i in pivots])
1058
+ if as_affine_map:
1059
+ image_translation = vector(self.base_ring(), self.dim())
1060
+ L = linear_transformation(A, side='right')
1061
+ result.projection_linear_map = L
1062
+ result.projection_translation = image_translation
1063
+ if as_convex_set:
1064
+ result.image = A*self
1065
+ if as_section_map:
1066
+ if self.dim():
1067
+ B = M.transpose()/(A*M.transpose())
1068
+ else:
1069
+ B = matrix(self.ambient_dim(), 0)
1070
+ L_section = linear_transformation(B, side='right')
1071
+ result.section_linear_map = L_section
1072
+ result.section_translation = v0 - L_section(L(v0) + image_translation)
1073
+
1074
+ return result
1075
+
1076
+ def affine_hull_projection(self,
1077
+ as_polyhedron=None, as_affine_map=False,
1078
+ orthogonal=False, orthonormal=False,
1079
+ extend=False, minimal=False,
1080
+ return_all_data=False,
1081
+ *, as_convex_set=None):
1082
+ r"""
1083
+ Return the polyhedron projected into its affine hull.
1084
+
1085
+ Each polyhedron is contained in some smallest affine subspace
1086
+ (possibly the entire ambient space) -- its affine hull. We
1087
+ provide an affine linear map that projects the ambient space of
1088
+ the polyhedron to the standard Euclidean space of dimension of
1089
+ the polyhedron, which restricts to a bijection from the affine
1090
+ hull.
1091
+
1092
+ The projection map is not unique; some parameters control the
1093
+ choice of the map. Other parameters control the output of the
1094
+ function.
1095
+
1096
+ INPUT:
1097
+
1098
+ - ``as_polyhedron``, ``as_convex_set`` -- boolean or the default
1099
+ ``None``; one of the two to be set
1100
+
1101
+ - ``as_affine_map`` -- boolean (default: ``False``); control the output
1102
+
1103
+ The default ``as_polyhedron=None`` translates to
1104
+ ``as_polyhedron=not as_affine_map``,
1105
+ therefore to ``as_polyhedron=True`` if nothing is specified.
1106
+
1107
+ If exactly one of either ``as_polyhedron`` or ``as_affine_map`` is
1108
+ set, then either a polyhedron or the affine transformation
1109
+ is returned. The affine transformation
1110
+ sends the embedded polytope to a fulldimensional one.
1111
+ It is given as a pair ``(A, b)``, where A is a linear transformation
1112
+ and `b` is a vector, and the affine transformation sends ``v`` to
1113
+ ``A(v)+b``.
1114
+
1115
+ If both ``as_polyhedron`` and ``as_affine_map`` are set, then
1116
+ both are returned, encapsulated in an instance of
1117
+ :class:`~sage.geometry.convex_set.AffineHullProjectionData`.
1118
+
1119
+ - ``return_all_data`` -- boolean (default: ``False``)
1120
+
1121
+ If set, then ``as_polyhedron`` and ``as_affine_map`` will set
1122
+ (possibly overridden) and additional (internal) data concerning
1123
+ the transformation is returned. Everything is encapsulated
1124
+ in an instance of
1125
+ :class:`~sage.geometry.convex_set.AffineHullProjectionData` in
1126
+ this case.
1127
+
1128
+ - ``orthogonal`` -- boolean (default: ``False``); if ``True``,
1129
+ provide an orthogonal transformation
1130
+
1131
+ - ``orthonormal`` -- boolean (default: ``False``); if ``True``,
1132
+ provide an orthonormal transformation. If the base ring does not
1133
+ provide the necessary square roots, the extend parameter
1134
+ needs to be set to ``True``.
1135
+
1136
+ - ``extend`` -- boolean (default: ``False``); if ``True``,
1137
+ allow base ring to be extended if necessary. This becomes
1138
+ relevant when requiring an orthonormal transformation.
1139
+
1140
+ - ``minimal`` -- boolean (default: ``False``); if ``True``,
1141
+ when doing an extension, it computes the minimal base ring of the
1142
+ extension, otherwise the base ring is ``AA``.
1143
+
1144
+ OUTPUT:
1145
+
1146
+ A full-dimensional polyhedron or an affine transformation,
1147
+ depending on the parameters ``as_polyhedron`` and ``as_affine_map``,
1148
+ or an instance of :class:`~sage.geometry.convex_set.AffineHullProjectionData`
1149
+ containing all data (parameter ``return_all_data``).
1150
+
1151
+ If the output is an instance of
1152
+ :class:`~sage.geometry.convex_set.AffineHullProjectionData`, the
1153
+ following fields may be set:
1154
+
1155
+ - ``image`` -- the projection of the original polyhedron
1156
+
1157
+ - ``projection_map`` -- the affine map as a pair whose first component
1158
+ is a linear transformation and its second component a shift;
1159
+ see above.
1160
+
1161
+ - ``section_map`` -- an affine map as a pair whose first component
1162
+ is a linear transformation and its second component a shift.
1163
+ It maps the codomain of ``affine_map`` to the affine hull of
1164
+ ``self``. It is a right inverse of ``projection_map``.
1165
+
1166
+ Note that all of these data are compatible.
1167
+
1168
+ .. TODO::
1169
+
1170
+ - make the parameters ``orthogonal`` and ``orthonormal`` work
1171
+ with unbounded polyhedra.
1172
+
1173
+ EXAMPLES::
1174
+
1175
+ sage: triangle = Polyhedron([(1,0,0), (0,1,0), (0,0,1)]); triangle
1176
+ A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices
1177
+ sage: triangle.affine_hull_projection()
1178
+ A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 3 vertices
1179
+
1180
+ sage: half3d = Polyhedron(vertices=[(3,2,1)], rays=[(1,0,0)])
1181
+ sage: half3d.affine_hull_projection().Vrepresentation()
1182
+ (A ray in the direction (1), A vertex at (3))
1183
+
1184
+ The resulting affine hulls depend on the parameter ``orthogonal`` and ``orthonormal``::
1185
+
1186
+ sage: L = Polyhedron([[1,0], [0,1]]); L
1187
+ A 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices
1188
+ sage: A = L.affine_hull_projection(); A
1189
+ A 1-dimensional polyhedron in ZZ^1 defined as the convex hull of 2 vertices
1190
+ sage: A.vertices()
1191
+ (A vertex at (0), A vertex at (1))
1192
+ sage: A = L.affine_hull_projection(orthogonal=True); A
1193
+ A 1-dimensional polyhedron in QQ^1 defined as the convex hull of 2 vertices
1194
+ sage: A.vertices()
1195
+ (A vertex at (0), A vertex at (2))
1196
+ sage: A = L.affine_hull_projection(orthonormal=True) # needs sage.rings.number_field sage.symbolic
1197
+ Traceback (most recent call last):
1198
+ ...
1199
+ ValueError: the base ring needs to be extended; try with "extend=True"
1200
+ sage: A = L.affine_hull_projection(orthonormal=True, extend=True); A # needs sage.rings.number_field sage.symbolic
1201
+ A 1-dimensional polyhedron in AA^1 defined as the convex hull of 2 vertices
1202
+ sage: A.vertices() # needs sage.rings.number_field sage.symbolic
1203
+ (A vertex at (1.414213562373095?), A vertex at (0.?e-18))
1204
+
1205
+ More generally::
1206
+
1207
+ sage: S = polytopes.simplex(); S
1208
+ A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 4 vertices
1209
+ sage: S.vertices()
1210
+ (A vertex at (0, 0, 0, 1),
1211
+ A vertex at (0, 0, 1, 0),
1212
+ A vertex at (0, 1, 0, 0),
1213
+ A vertex at (1, 0, 0, 0))
1214
+ sage: A = S.affine_hull_projection(); A
1215
+ A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 4 vertices
1216
+ sage: A.vertices()
1217
+ (A vertex at (0, 0, 0),
1218
+ A vertex at (0, 0, 1),
1219
+ A vertex at (0, 1, 0),
1220
+ A vertex at (1, 0, 0))
1221
+ sage: A = S.affine_hull_projection(orthogonal=True); A
1222
+ A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices
1223
+ sage: A.vertices()
1224
+ (A vertex at (0, 0, 0),
1225
+ A vertex at (2, 0, 0),
1226
+ A vertex at (1, 3/2, 0),
1227
+ A vertex at (1, 1/2, 4/3))
1228
+ sage: A = S.affine_hull_projection(orthonormal=True, extend=True); A # needs sage.rings.number_field sage.symbolic
1229
+ A 3-dimensional polyhedron in AA^3 defined as the convex hull of 4 vertices
1230
+ sage: A.vertices() # needs sage.rings.number_field sage.symbolic
1231
+ (A vertex at (0.7071067811865475?, 0.4082482904638630?, 1.154700538379252?),
1232
+ A vertex at (0.7071067811865475?, 1.224744871391589?, 0.?e-18),
1233
+ A vertex at (1.414213562373095?, 0.?e-18, 0.?e-18),
1234
+ A vertex at (0.?e-18, 0.?e-18, 0.?e-18))
1235
+
1236
+ With the parameter ``minimal`` one can get a minimal base ring::
1237
+
1238
+ sage: # needs sage.rings.number_field sage.symbolic
1239
+ sage: s = polytopes.simplex(3)
1240
+ sage: s_AA = s.affine_hull_projection(orthonormal=True, extend=True)
1241
+ sage: s_AA.base_ring()
1242
+ Algebraic Real Field
1243
+ sage: s_full = s.affine_hull_projection(orthonormal=True, extend=True,
1244
+ ....: minimal=True)
1245
+ sage: s_full.base_ring()
1246
+ Number Field in a with defining polynomial y^4 - 4*y^2 + 1
1247
+ with a = 0.5176380902050415?
1248
+
1249
+ More examples with the ``orthonormal`` parameter::
1250
+
1251
+ sage: P = polytopes.permutahedron(3); P
1252
+ A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 6 vertices
1253
+ sage: set([F.as_polyhedron().affine_hull_projection( # needs sage.combinat sage.rings.number_field sage.symbolic
1254
+ ....: orthonormal=True, extend=True).volume()
1255
+ ....: for F in P.affine_hull_projection().faces(1)]) == {1, sqrt(AA(2))}
1256
+ True
1257
+ sage: set([F.as_polyhedron().affine_hull_projection( # needs sage.combinat sage.rings.number_field sage.symbolic
1258
+ ....: orthonormal=True, extend=True).volume()
1259
+ ....: for F in P.affine_hull_projection(
1260
+ ....: orthonormal=True, extend=True).faces(1)]) == {sqrt(AA(2))}
1261
+ True
1262
+
1263
+ sage: # needs sage.groups sage.rings.number_field
1264
+ sage: D = polytopes.dodecahedron()
1265
+ sage: F = D.faces(2)[0].as_polyhedron()
1266
+ sage: F.affine_hull_projection(orthogonal=True)
1267
+ A 2-dimensional polyhedron in
1268
+ (Number Field in sqrt5 with defining polynomial x^2 - 5
1269
+ with sqrt5 = 2.236067977499790?)^2
1270
+ defined as the convex hull of 5 vertices
1271
+ sage: F.affine_hull_projection(orthonormal=True, extend=True) # needs sage.symbolic
1272
+ A 2-dimensional polyhedron in AA^2 defined as the convex hull of 5 vertices
1273
+
1274
+ sage: # needs sage.rings.number_field
1275
+ sage: K.<sqrt2> = QuadraticField(2)
1276
+ sage: P = Polyhedron([2*[K.zero()],2*[sqrt2]]); P
1277
+ A 1-dimensional polyhedron in
1278
+ (Number Field in sqrt2 with defining polynomial x^2 - 2
1279
+ with sqrt2 = 1.414213562373095?)^2
1280
+ defined as the convex hull of 2 vertices
1281
+ sage: P.vertices()
1282
+ (A vertex at (0, 0), A vertex at (sqrt2, sqrt2))
1283
+ sage: A = P.affine_hull_projection(orthonormal=True); A
1284
+ A 1-dimensional polyhedron in
1285
+ (Number Field in sqrt2 with defining polynomial x^2 - 2
1286
+ with sqrt2 = 1.414213562373095?)^1
1287
+ defined as the convex hull of 2 vertices
1288
+ sage: A.vertices()
1289
+ (A vertex at (0), A vertex at (2))
1290
+
1291
+ sage: # needs sage.rings.number_field sage.symbolic
1292
+ sage: K.<sqrt3> = QuadraticField(3)
1293
+ sage: P = Polyhedron([2*[K.zero()], 2*[sqrt3]]); P
1294
+ A 1-dimensional polyhedron in
1295
+ (Number Field in sqrt3 with defining polynomial x^2 - 3
1296
+ with sqrt3 = 1.732050807568878?)^2
1297
+ defined as the convex hull of 2 vertices
1298
+ sage: P.vertices()
1299
+ (A vertex at (0, 0), A vertex at (sqrt3, sqrt3))
1300
+ sage: A = P.affine_hull_projection(orthonormal=True)
1301
+ Traceback (most recent call last):
1302
+ ...
1303
+ ValueError: the base ring needs to be extended; try with "extend=True"
1304
+ sage: A = P.affine_hull_projection(orthonormal=True, extend=True); A
1305
+ A 1-dimensional polyhedron in AA^1 defined as the convex hull of 2 vertices
1306
+ sage: A.vertices()
1307
+ (A vertex at (0), A vertex at (2.449489742783178?))
1308
+ sage: sqrt(6).n()
1309
+ 2.44948974278318
1310
+
1311
+ The affine hull is combinatorially equivalent to the input::
1312
+
1313
+ sage: # needs sage.graphs sage.rings.number_field
1314
+ sage: P.is_combinatorially_isomorphic(P.affine_hull_projection())
1315
+ True
1316
+ sage: P.is_combinatorially_isomorphic(P.affine_hull_projection(
1317
+ ....: orthogonal=True))
1318
+ True
1319
+ sage: P.is_combinatorially_isomorphic(P.affine_hull_projection(
1320
+ ....: orthonormal=True, extend=True))
1321
+ True
1322
+
1323
+ The ``orthonormal=True`` parameter preserves volumes;
1324
+ it provides an isometric copy of the polyhedron::
1325
+
1326
+ sage: # needs sage.groups sage.rings.number_field sage.symbolic
1327
+ sage: Pentagon = polytopes.dodecahedron().faces(2)[0].as_polyhedron()
1328
+ sage: P = Pentagon.affine_hull_projection(orthonormal=True, extend=True)
1329
+ sage: _, c= P.is_inscribed(certificate=True)
1330
+ sage: c
1331
+ (0.4721359549995794?, 0.6498393924658126?)
1332
+ sage: circumradius = (c - vector(P.vertices()[0])).norm()
1333
+ sage: p = polytopes.regular_polygon(5)
1334
+ sage: p.volume()
1335
+ 2.377641290737884?
1336
+ sage: P.volume()
1337
+ 1.53406271079097?
1338
+ sage: p.volume()*circumradius^2
1339
+ 1.534062710790965?
1340
+ sage: P.volume() == p.volume()*circumradius^2
1341
+ True
1342
+
1343
+ One can also use ``orthogonal`` parameter to calculate volumes;
1344
+ in this case we don't need to switch base rings. One has to divide
1345
+ by the square root of the determinant of the linear part of the
1346
+ affine transformation times its transpose::
1347
+
1348
+ sage: # needs sage.groups sage.rings.number_field
1349
+ sage: Pentagon = polytopes.dodecahedron().faces(2)[0].as_polyhedron()
1350
+ sage: Pnormal = Pentagon.affine_hull_projection(orthonormal=True,
1351
+ ....: extend=True)
1352
+ sage: Pgonal = Pentagon.affine_hull_projection(orthogonal=True)
1353
+ sage: A, b = Pentagon.affine_hull_projection(orthogonal=True,
1354
+ ....: as_affine_map=True)
1355
+ sage: Adet = (A.matrix().transpose()*A.matrix()).det()
1356
+ sage: Pnormal.volume()
1357
+ 1.53406271079097?
1358
+ sage: Pgonal.volume()/Adet.sqrt(extend=True) # needs sage.symbolic
1359
+ -80*(55*sqrt(5) - 123)/sqrt(-6368*sqrt(5) + 14240)
1360
+ sage: Pgonal.volume()/AA(Adet).sqrt().n(digits=20)
1361
+ 1.5340627107909646813
1362
+ sage: AA(Pgonal.volume()^2) == (Pnormal.volume()^2)*AA(Adet)
1363
+ True
1364
+
1365
+ Another example with ``as_affine_map=True``::
1366
+
1367
+ sage: # needs sage.combinat sage.rings.number_field
1368
+ sage: P = polytopes.permutahedron(4)
1369
+ sage: Q = P.affine_hull_projection(orthonormal=True, extend=True)
1370
+ sage: A, b = P.affine_hull_projection(orthonormal=True, extend=True,
1371
+ ....: as_affine_map=True)
1372
+ sage: Q.center()
1373
+ (0.7071067811865475?, 1.224744871391589?, 1.732050807568878?)
1374
+ sage: A(P.center()) + b == Q.center()
1375
+ True
1376
+
1377
+ For unbounded, non full-dimensional polyhedra, the ``orthogonal=True`` and ``orthonormal=True``
1378
+ is not implemented::
1379
+
1380
+ sage: P = Polyhedron(ieqs=[[0, 1, 0], [0, 0, 1], [0, 0, -1]]); P
1381
+ A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 ray
1382
+ sage: P.is_compact()
1383
+ False
1384
+ sage: P.is_full_dimensional()
1385
+ False
1386
+ sage: P.affine_hull_projection(orthogonal=True)
1387
+ Traceback (most recent call last):
1388
+ ...
1389
+ NotImplementedError: "orthogonal=True" and "orthonormal=True"
1390
+ work only for compact polyhedra
1391
+ sage: P.affine_hull_projection(orthonormal=True)
1392
+ Traceback (most recent call last):
1393
+ ...
1394
+ NotImplementedError: "orthogonal=True" and "orthonormal=True"
1395
+ work only for compact polyhedra
1396
+
1397
+ Setting ``as_affine_map`` to ``True``
1398
+ without ``orthogonal`` or ``orthonormal`` set to ``True``::
1399
+
1400
+ sage: S = polytopes.simplex()
1401
+ sage: S.affine_hull_projection(as_affine_map=True)
1402
+ (Vector space morphism represented by the matrix:
1403
+ [1 0 0]
1404
+ [0 1 0]
1405
+ [0 0 1]
1406
+ [0 0 0]
1407
+ Domain: Vector space of dimension 4 over Rational Field
1408
+ Codomain: Vector space of dimension 3 over Rational Field,
1409
+ (0, 0, 0))
1410
+
1411
+ If the polyhedron is full-dimensional, it is returned::
1412
+
1413
+ sage: polytopes.cube().affine_hull_projection()
1414
+ A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices
1415
+ sage: polytopes.cube().affine_hull_projection(as_affine_map=True)
1416
+ (Vector space morphism represented by the matrix:
1417
+ [1 0 0]
1418
+ [0 1 0]
1419
+ [0 0 1]
1420
+ Domain: Vector space of dimension 3 over Rational Field
1421
+ Codomain: Vector space of dimension 3 over Rational Field,
1422
+ (0, 0, 0))
1423
+
1424
+ Return polyhedron and affine map::
1425
+
1426
+ sage: S = polytopes.simplex(2)
1427
+ sage: data = S.affine_hull_projection(orthogonal=True,
1428
+ ....: as_polyhedron=True,
1429
+ ....: as_affine_map=True); data
1430
+ AffineHullProjectionData(image=A 2-dimensional polyhedron in QQ^2
1431
+ defined as the convex hull of 3 vertices,
1432
+ projection_linear_map=Vector space morphism represented by the matrix:
1433
+ [ -1 -1/2]
1434
+ [ 1 -1/2]
1435
+ [ 0 1]
1436
+ Domain: Vector space of dimension 3 over Rational Field
1437
+ Codomain: Vector space of dimension 2 over Rational Field,
1438
+ projection_translation=(1, 1/2),
1439
+ section_linear_map=None,
1440
+ section_translation=None)
1441
+
1442
+ Return all data::
1443
+
1444
+ sage: data = S.affine_hull_projection(orthogonal=True, return_all_data=True); data
1445
+ AffineHullProjectionData(image=A 2-dimensional polyhedron in QQ^2
1446
+ defined as the convex hull of 3 vertices,
1447
+ projection_linear_map=Vector space morphism represented by the matrix:
1448
+ [ -1 -1/2]
1449
+ [ 1 -1/2]
1450
+ [ 0 1]
1451
+ Domain: Vector space of dimension 3 over Rational Field
1452
+ Codomain: Vector space of dimension 2 over Rational Field,
1453
+ projection_translation=(1, 1/2),
1454
+ section_linear_map=Vector space morphism represented by the matrix:
1455
+ [-1/2 1/2 0]
1456
+ [-1/3 -1/3 2/3]
1457
+ Domain: Vector space of dimension 2 over Rational Field
1458
+ Codomain: Vector space of dimension 3 over Rational Field,
1459
+ section_translation=(1, 0, 0))
1460
+
1461
+ The section map is a right inverse of the projection map::
1462
+
1463
+ sage: mat = data.section_linear_map.matrix().transpose()
1464
+ sage: data.image.linear_transformation(mat) + data.section_translation == S
1465
+ True
1466
+
1467
+ Same without ``orthogonal=True``::
1468
+
1469
+ sage: data = S.affine_hull_projection(return_all_data=True); data
1470
+ AffineHullProjectionData(image=A 2-dimensional polyhedron in ZZ^2
1471
+ defined as the convex hull of 3 vertices,
1472
+ projection_linear_map=Vector space morphism represented by the matrix:
1473
+ [1 0]
1474
+ [0 1]
1475
+ [0 0]
1476
+ Domain: Vector space of dimension 3 over Rational Field
1477
+ Codomain: Vector space of dimension 2 over Rational Field,
1478
+ projection_translation=(0, 0),
1479
+ section_linear_map=Vector space morphism represented by the matrix:
1480
+ [ 1 0 -1]
1481
+ [ 0 1 -1]
1482
+ Domain: Vector space of dimension 2 over Rational Field
1483
+ Codomain: Vector space of dimension 3 over Rational Field,
1484
+ section_translation=(0, 0, 1))
1485
+ sage: mat = data.section_linear_map.matrix().transpose()
1486
+ sage: data.image.linear_transformation(mat) + data.section_translation == S
1487
+ True
1488
+
1489
+ ::
1490
+
1491
+ sage: P0 = Polyhedron(
1492
+ ....: ieqs=[(0, -1, 0, 1, 1, 1), (0, 1, 1, 0, -1, -1), (0, -1, 1, 1, 0, 0),
1493
+ ....: (0, 1, 0, 0, 0, 0), (0, 0, 1, 1, -1, -1), (0, 0, 0, 0, 0, 1),
1494
+ ....: (0, 0, 0, 0, 1, 0), (0, 0, 0, 1, 0, -1), (0, 0, 1, 0, 0, 0)])
1495
+ sage: P = P0.intersection(Polyhedron(eqns=[(-1, 1, 1, 1, 1, 1)]))
1496
+ sage: P.dim()
1497
+ 4
1498
+ sage: P.affine_hull_projection(orthogonal=True, as_affine_map=True)[0]
1499
+ Vector space morphism represented by the matrix:
1500
+ [ 0 0 0 1/3]
1501
+ [ -2/3 -1/6 0 -1/12]
1502
+ [ 1/3 -1/6 1/2 -1/12]
1503
+ [ 0 1/2 0 -1/12]
1504
+ [ 1/3 -1/6 -1/2 -1/12]
1505
+ Domain: Vector space of dimension 5 over Rational Field
1506
+ Codomain: Vector space of dimension 4 over Rational Field
1507
+ """
1508
+ if as_polyhedron is not None:
1509
+ as_convex_set = as_polyhedron
1510
+ return super().affine_hull_projection(
1511
+ as_convex_set=as_convex_set, as_affine_map=as_affine_map,
1512
+ orthogonal=orthogonal, orthonormal=orthonormal,
1513
+ extend=extend, minimal=minimal,
1514
+ return_all_data=return_all_data)
1515
+
1516
+ def _test_affine_hull_projection(self, tester=None, verbose=False, **options):
1517
+ r"""
1518
+ Run tests on the method :meth:`.affine_hull_projection`.
1519
+
1520
+ TESTS::
1521
+
1522
+ sage: D = polytopes.dodecahedron() # needs sage.groups sage.rings.number_field
1523
+ sage: D.facets()[0].as_polyhedron()._test_affine_hull_projection() # needs sage.groups sage.rings.number_field
1524
+ """
1525
+ if tester is None:
1526
+ tester = self._tester(**options)
1527
+
1528
+ if self.is_empty():
1529
+ # Undefined, nothing to test
1530
+ return
1531
+
1532
+ if self.n_vertices() > 30 or self.n_facets() > 30 or self.dim() > 6:
1533
+ # Avoid very long doctests.
1534
+ return
1535
+
1536
+ try:
1537
+ from sage.rings.qqbar import AA
1538
+ except ImportError:
1539
+ AA = None
1540
+
1541
+ data_sets = []
1542
+ data_sets.append(self.affine_hull_projection(return_all_data=True))
1543
+ if self.is_compact():
1544
+ data_sets.append(self.affine_hull_projection(return_all_data=True,
1545
+ orthogonal=True,
1546
+ extend=True))
1547
+ if AA is not None:
1548
+ try:
1549
+ data_sets.append(self.affine_hull_projection(return_all_data=True,
1550
+ orthonormal=True,
1551
+ extend=True))
1552
+ data_sets.append(self.affine_hull_projection(return_all_data=True,
1553
+ orthonormal=True,
1554
+ extend=True,
1555
+ minimal=True))
1556
+ except ModuleNotFoundError:
1557
+ pass
1558
+
1559
+ for i, data in enumerate(data_sets):
1560
+ if verbose:
1561
+ print("Running test number {}".format(i))
1562
+ M = data.projection_linear_map.matrix().transpose()
1563
+ tester.assertEqual(self.linear_transformation(M, new_base_ring=M.base_ring())
1564
+ + data.projection_translation,
1565
+ data.image)
1566
+
1567
+ M = data.section_linear_map.matrix().transpose()
1568
+ if M.base_ring() is AA:
1569
+ self_extend = self.change_ring(AA)
1570
+ else:
1571
+ self_extend = self
1572
+ tester.assertEqual(data.image.linear_transformation(M)
1573
+ + data.section_translation,
1574
+ self_extend)
1575
+ if i == 0:
1576
+ tester.assertEqual(data.image.base_ring(), self.base_ring())
1577
+ else:
1578
+ # Test whether the map is orthogonal.
1579
+ M = data.projection_linear_map.matrix()
1580
+ tester.assertTrue((M.transpose() * M).is_diagonal())
1581
+ if i > 1:
1582
+ # Test whether the map is orthonormal.
1583
+ tester.assertTrue((M.transpose() * M).is_one())
1584
+ if i == 3:
1585
+ # Test that the extension is indeed minimal.
1586
+ if self.base_ring() is not AA:
1587
+ tester.assertIsNot(data.image.base_ring(), AA)
1588
+
1589
+ def affine_hull_manifold(self, name=None, latex_name=None, start_index=0, ambient_space=None,
1590
+ ambient_chart=None, names=None, **kwds):
1591
+ r"""
1592
+ Return the affine hull of ``self`` as a manifold.
1593
+
1594
+ If ``self`` is full-dimensional, it is just the ambient Euclidean space.
1595
+ Otherwise, it is a Riemannian submanifold of the ambient Euclidean space.
1596
+
1597
+ INPUT:
1598
+
1599
+ - ``ambient_space`` -- a :class:`~sage.manifolds.differentiable.examples.euclidean.EuclideanSpace`
1600
+ of the ambient dimension (default: the manifold of ``ambient_chart``, if provided;
1601
+ otherwise, a new instance of ``EuclideanSpace``).
1602
+
1603
+ - ``ambient_chart`` -- a chart on ``ambient_space``
1604
+
1605
+ - ``names`` -- names for the coordinates on the affine hull
1606
+
1607
+ - optional arguments accepted by :meth:`affine_hull_projection`
1608
+
1609
+ The default chart is determined by the optional arguments of
1610
+ :meth:`affine_hull_projection`.
1611
+
1612
+ EXAMPLES::
1613
+
1614
+ sage: # needs sage.symbolic
1615
+ sage: triangle = Polyhedron([(1, 0, 0), (0, 1, 0), (0, 0, 1)]); triangle
1616
+ A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices
1617
+ sage: A = triangle.affine_hull_manifold(name='A'); A
1618
+ 2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3
1619
+ sage: A.embedding().display()
1620
+ A → E^3
1621
+ (x0, x1) ↦ (x, y, z) = (t0 + x0, t0 + x1, t0 - x0 - x1 + 1)
1622
+ sage: A.embedding().inverse().display()
1623
+ E^3 → A
1624
+ (x, y, z) ↦ (x0, x1) = (x, y)
1625
+ sage: A.adapted_chart()
1626
+ [Chart (E^3, (x0_E3, x1_E3, t0_E3))]
1627
+ sage: A.normal().display()
1628
+ n = 1/3*sqrt(3) e_x + 1/3*sqrt(3) e_y + 1/3*sqrt(3) e_z
1629
+ sage: A.induced_metric() # Need to call this before volume_form
1630
+ Riemannian metric gamma on the
1631
+ 2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3
1632
+ sage: A.volume_form()
1633
+ 2-form eps_gamma on the
1634
+ 2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3
1635
+
1636
+ Orthogonal version::
1637
+
1638
+ sage: A = triangle.affine_hull_manifold(name='A', orthogonal=True); A # needs sage.symbolic
1639
+ 2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3
1640
+ sage: A.embedding().display() # needs sage.symbolic
1641
+ A → E^3
1642
+ (x0, x1) ↦ (x, y, z) = (t0 - 1/2*x0 - 1/3*x1 + 1,
1643
+ t0 + 1/2*x0 - 1/3*x1, t0 + 2/3*x1)
1644
+ sage: A.embedding().inverse().display() # needs sage.symbolic
1645
+ E^3 → A
1646
+ (x, y, z) ↦ (x0, x1) = (-x + y + 1, -1/2*x - 1/2*y + z + 1/2)
1647
+
1648
+ Arrangement of affine hull of facets::
1649
+
1650
+ sage: # needs sage.rings.number_field sage.symbolic
1651
+ sage: D = polytopes.dodecahedron()
1652
+ sage: E3 = EuclideanSpace(3)
1653
+ sage: submanifolds = [ # long time
1654
+ ....: F.as_polyhedron().affine_hull_manifold(name=f'F{i}',
1655
+ ....: orthogonal=True, ambient_space=E3)
1656
+ ....: for i, F in enumerate(D.facets())]
1657
+ sage: sum(FM.plot({}, # long time, not tested # needs sage.plot
1658
+ ....: srange(-2, 2, 0.1), srange(-2, 2, 0.1),
1659
+ ....: opacity=0.2)
1660
+ ....: for FM in submanifolds) + D.plot()
1661
+ Graphics3d Object
1662
+
1663
+ Full-dimensional case::
1664
+
1665
+ sage: cube = polytopes.cube(); cube
1666
+ A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices
1667
+ sage: cube.affine_hull_manifold() # needs sage.symbolic
1668
+ Euclidean space E^3
1669
+ """
1670
+ if ambient_space is None:
1671
+ if ambient_chart is not None:
1672
+ ambient_space = ambient_chart.manifold()
1673
+ else:
1674
+ from sage.manifolds.differentiable.examples.euclidean import EuclideanSpace
1675
+ ambient_space = EuclideanSpace(self.ambient_dim(), start_index=start_index)
1676
+ if ambient_space.dimension() != self.ambient_dim():
1677
+ raise ValueError('ambient_space and ambient_chart must match the ambient dimension')
1678
+
1679
+ if self.is_full_dimensional():
1680
+ return ambient_space
1681
+
1682
+ if ambient_chart is None:
1683
+ ambient_chart = ambient_space.default_chart()
1684
+ CE = ambient_chart
1685
+
1686
+ from sage.manifolds.manifold import Manifold
1687
+ if name is None:
1688
+ name, latex_name = self._affine_hull_name_latex_name()
1689
+ H = Manifold(self.dim(), name, ambient=ambient_space, structure='Riemannian',
1690
+ latex_name=latex_name, start_index=start_index)
1691
+ if names is None:
1692
+ names = tuple(f'x{i}' for i in range(self.dim()))
1693
+ CH = H.chart(names=names)
1694
+
1695
+ data = self.affine_hull_projection(return_all_data=True, **kwds)
1696
+ projection_matrix = data.projection_linear_map.matrix().transpose()
1697
+ projection_translation_vector = data.projection_translation
1698
+ section_matrix = data.section_linear_map.matrix().transpose()
1699
+ section_translation_vector = data.section_translation
1700
+
1701
+ from sage.symbolic.ring import SR
1702
+ # We use the slacks of the (linear independent) equations as the foliation parameters
1703
+ foliation_parameters = vector(SR.var(f't{i}') for i in range(self.ambient_dim() - self.dim()))
1704
+ normal_matrix = matrix(equation.A() for equation in self.equation_generator()).transpose()
1705
+ slack_matrix = normal_matrix.pseudoinverse()
1706
+
1707
+ phi = H.diff_map(ambient_space, {(CH, CE):
1708
+ (section_matrix * vector(CH._xx) + section_translation_vector
1709
+ + normal_matrix * foliation_parameters).list()})
1710
+ phi_inv = ambient_space.diff_map(H, {(CE, CH):
1711
+ (projection_matrix * vector(CE._xx) + projection_translation_vector).list()})
1712
+
1713
+ foliation_scalar_fields = {parameter:
1714
+ ambient_space.scalar_field({CE: slack_matrix.row(i) * (vector(CE._xx) - section_translation_vector)})
1715
+ for i, parameter in enumerate(foliation_parameters)}
1716
+
1717
+ H.set_embedding(phi, inverse=phi_inv,
1718
+ var=list(foliation_parameters), t_inverse=foliation_scalar_fields)
1719
+ return H
1720
+
1721
+ def _affine_hull_name_latex_name(self, name=None, latex_name=None):
1722
+ r"""
1723
+ Return the default name of the affine hull.
1724
+
1725
+ EXAMPLES::
1726
+
1727
+ sage: polytopes.cube()._affine_hull_name_latex_name('C', r'\square')
1728
+ ('aff_C', '\\mathop{\\mathrm{aff}}(\\square)')
1729
+
1730
+ sage: Polyhedron(vertices=[[0, 1], [1, 0]])._affine_hull_name_latex_name()
1731
+ ('aff_P', '\\mathop{\\mathrm{aff}}(P)')
1732
+ """
1733
+
1734
+ if name is None:
1735
+ name = 'P'
1736
+ if latex_name is None:
1737
+ latex_name = name
1738
+ operator = 'aff'
1739
+ aff_name = f'{operator}_{name}'
1740
+ aff_latex_name = r'\mathop{\mathrm{' + operator + '}}(' + latex_name + ')'
1741
+ return aff_name, aff_latex_name