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