Base class for polyhedra: Methods for plotting and affine hull projection#

class sage.geometry.polyhedron.base6.Polyhedron_base6(parent, Vrep, Hrep, Vrep_minimal=None, Hrep_minimal=None, pref_rep=None, mutable=False, **kwds)[source]#

Bases: Polyhedron_base5

Methods related to plotting including affine hull projection.

affine_hull(*args, **kwds)[source]#

Return the affine hull of self as a polyhedron.

EXAMPLES:

sage: half_plane_in_space = Polyhedron(ieqs=[(0,1,0,0)], eqns=[(0,0,0,1)])
sage: half_plane_in_space.affine_hull().Hrepresentation()
(An equation (0, 0, 1) x + 0 == 0,)

sage: polytopes.cube().affine_hull().is_universe()
True
>>> from sage.all import *
>>> half_plane_in_space = Polyhedron(ieqs=[(Integer(0),Integer(1),Integer(0),Integer(0))], eqns=[(Integer(0),Integer(0),Integer(0),Integer(1))])
>>> half_plane_in_space.affine_hull().Hrepresentation()
(An equation (0, 0, 1) x + 0 == 0,)

>>> polytopes.cube().affine_hull().is_universe()
True
affine_hull_manifold(name=None, latex_name=None, start_index=0, ambient_space=None, ambient_chart=None, names=None, **kwds)[source]#

Return the affine hull of self as a manifold.

If self is full-dimensional, it is just the ambient Euclidean space. Otherwise, it is a Riemannian submanifold of the ambient Euclidean space.

INPUT:

  • ambient_space – a EuclideanSpace of the ambient dimension (default: the manifold of ambient_chart, if provided; otherwise, a new instance of EuclideanSpace).

  • ambient_chart – a chart on ambient_space.

  • names – names for the coordinates on the affine hull.

  • optional arguments accepted by affine_hull_projection().

The default chart is determined by the optional arguments of affine_hull_projection().

EXAMPLES:

sage: # needs sage.symbolic
sage: triangle = Polyhedron([(1, 0, 0), (0, 1, 0), (0, 0, 1)]);  triangle
A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices
sage: A = triangle.affine_hull_manifold(name='A'); A
2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3
sage: A.embedding().display()
A → E^3
   (x0, x1) ↦ (x, y, z) = (t0 + x0, t0 + x1, t0 - x0 - x1 + 1)
sage: A.embedding().inverse().display()
E^3 → A
   (x, y, z) ↦ (x0, x1) = (x, y)
sage: A.adapted_chart()
[Chart (E^3, (x0_E3, x1_E3, t0_E3))]
sage: A.normal().display()
n = 1/3*sqrt(3) e_x + 1/3*sqrt(3) e_y + 1/3*sqrt(3) e_z
sage: A.induced_metric()       # Need to call this before volume_form
Riemannian metric gamma on the
 2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3
sage: A.volume_form()
2-form eps_gamma on the
 2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3
>>> from sage.all import *
>>> # needs sage.symbolic
>>> triangle = Polyhedron([(Integer(1), Integer(0), Integer(0)), (Integer(0), Integer(1), Integer(0)), (Integer(0), Integer(0), Integer(1))]);  triangle
A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices
>>> A = triangle.affine_hull_manifold(name='A'); A
2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3
>>> A.embedding().display()
A → E^3
   (x0, x1) ↦ (x, y, z) = (t0 + x0, t0 + x1, t0 - x0 - x1 + 1)
>>> A.embedding().inverse().display()
E^3 → A
   (x, y, z) ↦ (x0, x1) = (x, y)
>>> A.adapted_chart()
[Chart (E^3, (x0_E3, x1_E3, t0_E3))]
>>> A.normal().display()
n = 1/3*sqrt(3) e_x + 1/3*sqrt(3) e_y + 1/3*sqrt(3) e_z
>>> A.induced_metric()       # Need to call this before volume_form
Riemannian metric gamma on the
 2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3
>>> A.volume_form()
2-form eps_gamma on the
 2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3

Orthogonal version:

sage: A = triangle.affine_hull_manifold(name='A', orthogonal=True); A       # needs sage.symbolic
2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3
sage: A.embedding().display()                                               # needs sage.symbolic
A → E^3
   (x0, x1) ↦ (x, y, z) = (t0 - 1/2*x0 - 1/3*x1 + 1,
                           t0 + 1/2*x0 - 1/3*x1, t0 + 2/3*x1)
sage: A.embedding().inverse().display()                                     # needs sage.symbolic
E^3 → A
   (x, y, z) ↦ (x0, x1) = (-x + y + 1, -1/2*x - 1/2*y + z + 1/2)
>>> from sage.all import *
>>> A = triangle.affine_hull_manifold(name='A', orthogonal=True); A       # needs sage.symbolic
2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3
>>> A.embedding().display()                                               # needs sage.symbolic
A → E^3
   (x0, x1) ↦ (x, y, z) = (t0 - 1/2*x0 - 1/3*x1 + 1,
                           t0 + 1/2*x0 - 1/3*x1, t0 + 2/3*x1)
>>> A.embedding().inverse().display()                                     # needs sage.symbolic
E^3 → A
   (x, y, z) ↦ (x0, x1) = (-x + y + 1, -1/2*x - 1/2*y + z + 1/2)

Arrangement of affine hull of facets:

sage: # needs sage.rings.number_field sage.symbolic
sage: D = polytopes.dodecahedron()
sage: E3 = EuclideanSpace(3)
sage: submanifolds = [              # long time
....:     F.as_polyhedron().affine_hull_manifold(name=f'F{i}',
....:                                            orthogonal=True, ambient_space=E3)
....:     for i, F in enumerate(D.facets())]
sage: sum(FM.plot({},               # long time, not tested                 # needs sage.plot
....:             srange(-2, 2, 0.1), srange(-2, 2, 0.1),
....:             opacity=0.2)
....:     for FM in submanifolds) + D.plot()
Graphics3d Object
>>> from sage.all import *
>>> # needs sage.rings.number_field sage.symbolic
>>> D = polytopes.dodecahedron()
>>> E3 = EuclideanSpace(Integer(3))
>>> submanifolds = [              # long time
...     F.as_polyhedron().affine_hull_manifold(name=f'F{i}',
...                                            orthogonal=True, ambient_space=E3)
...     for i, F in enumerate(D.facets())]
>>> sum(FM.plot({},               # long time, not tested                 # needs sage.plot
...             srange(-Integer(2), Integer(2), RealNumber('0.1')), srange(-Integer(2), Integer(2), RealNumber('0.1')),
...             opacity=RealNumber('0.2'))
...     for FM in submanifolds) + D.plot()
Graphics3d Object

Full-dimensional case:

sage: cube = polytopes.cube(); cube
A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices
sage: cube.affine_hull_manifold()                                           # needs sage.symbolic
Euclidean space E^3
>>> from sage.all import *
>>> cube = polytopes.cube(); cube
A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices
>>> cube.affine_hull_manifold()                                           # needs sage.symbolic
Euclidean space E^3
affine_hull_projection(as_polyhedron, as_affine_map=None, orthogonal=False, orthonormal=False, extend=False, minimal=False, return_all_data=False, as_convex_set=False)[source]#

Return the polyhedron projected into its affine hull.

Each polyhedron is contained in some smallest affine subspace (possibly the entire ambient space) – its affine hull. We provide an affine linear map that projects the ambient space of the polyhedron to the standard Euclidean space of dimension of the polyhedron, which restricts to a bijection from the affine hull.

The projection map is not unique; some parameters control the choice of the map. Other parameters control the output of the function.

INPUT:

  • as_polyhedron (or as_convex_set) – (boolean or the default None) and

  • as_affine_map – (boolean, default False) control the output

    The default as_polyhedron=None translates to as_polyhedron=not as_affine_map, therefore to as_polyhedron=True if nothing is specified.

    If exactly one of either as_polyhedron or as_affine_map is set, then either a polyhedron or the affine transformation is returned. The affine transformation sends the embedded polytope to a fulldimensional one. It is given as a pair (A, b), where A is a linear transformation and \(b\) is a vector, and the affine transformation sends v to A(v)+b.

    If both as_polyhedron and as_affine_map are set, then both are returned, encapsulated in an instance of AffineHullProjectionData.

  • return_all_data – (boolean, default False)

    If set, then as_polyhedron and as_affine_map will set (possibly overridden) and additional (internal) data concerning the transformation is returned. Everything is encapsulated in an instance of AffineHullProjectionData in this case.

  • orthogonal – boolean (default: False); if True, provide an orthogonal transformation.

  • orthonormal – boolean (default: False); if True, provide an orthonormal transformation. If the base ring does not provide the necessary square roots, the extend parameter needs to be set to True.

  • extend – boolean (default: False); if True, allow base ring to be extended if necessary. This becomes relevant when requiring an orthonormal transformation.

  • minimal – boolean (default: False); if True, when doing an extension, it computes the minimal base ring of the extension, otherwise the base ring is AA.

OUTPUT:

A full-dimensional polyhedron or an affine transformation, depending on the parameters as_polyhedron and as_affine_map, or an instance of AffineHullProjectionData containing all data (parameter return_all_data).

If the output is an instance of AffineHullProjectionData, the following fields may be set:

  • image – the projection of the original polyhedron

  • projection_map – the affine map as a pair whose first component is a linear transformation and its second component a shift; see above.

  • section_map – an affine map as a pair whose first component is a linear transformation and its second component a shift. It maps the codomain of affine_map to the affine hull of self. It is a right inverse of projection_map.

Note that all of these data are compatible.

Todo

  • make the parameters orthogonal and orthonormal work with unbounded polyhedra.

EXAMPLES:

sage: triangle = Polyhedron([(1,0,0), (0,1,0), (0,0,1)]);  triangle
A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices
sage: triangle.affine_hull_projection()
A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 3 vertices

sage: half3d = Polyhedron(vertices=[(3,2,1)], rays=[(1,0,0)])
sage: half3d.affine_hull_projection().Vrepresentation()
(A ray in the direction (1), A vertex at (3))
>>> from sage.all import *
>>> triangle = Polyhedron([(Integer(1),Integer(0),Integer(0)), (Integer(0),Integer(1),Integer(0)), (Integer(0),Integer(0),Integer(1))]);  triangle
A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices
>>> triangle.affine_hull_projection()
A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 3 vertices

>>> half3d = Polyhedron(vertices=[(Integer(3),Integer(2),Integer(1))], rays=[(Integer(1),Integer(0),Integer(0))])
>>> half3d.affine_hull_projection().Vrepresentation()
(A ray in the direction (1), A vertex at (3))

The resulting affine hulls depend on the parameter orthogonal and orthonormal:

sage: L = Polyhedron([[1,0], [0,1]]); L
A 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices
sage: A = L.affine_hull_projection(); A
A 1-dimensional polyhedron in ZZ^1 defined as the convex hull of 2 vertices
sage: A.vertices()
(A vertex at (0), A vertex at (1))
sage: A = L.affine_hull_projection(orthogonal=True); A
A 1-dimensional polyhedron in QQ^1 defined as the convex hull of 2 vertices
sage: A.vertices()
(A vertex at (0), A vertex at (2))
sage: A = L.affine_hull_projection(orthonormal=True)                        # needs sage.rings.number_field
Traceback (most recent call last):
...
ValueError: the base ring needs to be extended; try with "extend=True"
sage: A = L.affine_hull_projection(orthonormal=True, extend=True); A        # needs sage.rings.number_field
A 1-dimensional polyhedron in AA^1 defined as the convex hull of 2 vertices
sage: A.vertices()                                                          # needs sage.rings.number_field
(A vertex at (1.414213562373095?), A vertex at (0.?e-18))
>>> from sage.all import *
>>> L = Polyhedron([[Integer(1),Integer(0)], [Integer(0),Integer(1)]]); L
A 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices
>>> A = L.affine_hull_projection(); A
A 1-dimensional polyhedron in ZZ^1 defined as the convex hull of 2 vertices
>>> A.vertices()
(A vertex at (0), A vertex at (1))
>>> A = L.affine_hull_projection(orthogonal=True); A
A 1-dimensional polyhedron in QQ^1 defined as the convex hull of 2 vertices
>>> A.vertices()
(A vertex at (0), A vertex at (2))
>>> A = L.affine_hull_projection(orthonormal=True)                        # needs sage.rings.number_field
Traceback (most recent call last):
...
ValueError: the base ring needs to be extended; try with "extend=True"
>>> A = L.affine_hull_projection(orthonormal=True, extend=True); A        # needs sage.rings.number_field
A 1-dimensional polyhedron in AA^1 defined as the convex hull of 2 vertices
>>> A.vertices()                                                          # needs sage.rings.number_field
(A vertex at (1.414213562373095?), A vertex at (0.?e-18))

More generally:

sage: S = polytopes.simplex(); S
A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 4 vertices
sage: S.vertices()
(A vertex at (0, 0, 0, 1),
 A vertex at (0, 0, 1, 0),
 A vertex at (0, 1, 0, 0),
 A vertex at (1, 0, 0, 0))
sage: A = S.affine_hull_projection(); A
A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 4 vertices
sage: A.vertices()
(A vertex at (0, 0, 0),
 A vertex at (0, 0, 1),
 A vertex at (0, 1, 0),
 A vertex at (1, 0, 0))
sage: A = S.affine_hull_projection(orthogonal=True); A
A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices
sage: A.vertices()
(A vertex at (0, 0, 0),
 A vertex at (2, 0, 0),
 A vertex at (1, 3/2, 0),
 A vertex at (1, 1/2, 4/3))
sage: A = S.affine_hull_projection(orthonormal=True, extend=True); A        # needs sage.rings.number_field
A 3-dimensional polyhedron in AA^3 defined as the convex hull of 4 vertices
sage: A.vertices()                                                          # needs sage.rings.number_field
(A vertex at (0.7071067811865475?, 0.4082482904638630?, 1.154700538379252?),
 A vertex at (0.7071067811865475?, 1.224744871391589?, 0.?e-18),
 A vertex at (1.414213562373095?, 0.?e-18, 0.?e-18),
 A vertex at (0.?e-18, 0.?e-18, 0.?e-18))
>>> from sage.all import *
>>> S = polytopes.simplex(); S
A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 4 vertices
>>> S.vertices()
(A vertex at (0, 0, 0, 1),
 A vertex at (0, 0, 1, 0),
 A vertex at (0, 1, 0, 0),
 A vertex at (1, 0, 0, 0))
>>> A = S.affine_hull_projection(); A
A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 4 vertices
>>> A.vertices()
(A vertex at (0, 0, 0),
 A vertex at (0, 0, 1),
 A vertex at (0, 1, 0),
 A vertex at (1, 0, 0))
>>> A = S.affine_hull_projection(orthogonal=True); A
A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices
>>> A.vertices()
(A vertex at (0, 0, 0),
 A vertex at (2, 0, 0),
 A vertex at (1, 3/2, 0),
 A vertex at (1, 1/2, 4/3))
>>> A = S.affine_hull_projection(orthonormal=True, extend=True); A        # needs sage.rings.number_field
A 3-dimensional polyhedron in AA^3 defined as the convex hull of 4 vertices
>>> A.vertices()                                                          # needs sage.rings.number_field
(A vertex at (0.7071067811865475?, 0.4082482904638630?, 1.154700538379252?),
 A vertex at (0.7071067811865475?, 1.224744871391589?, 0.?e-18),
 A vertex at (1.414213562373095?, 0.?e-18, 0.?e-18),
 A vertex at (0.?e-18, 0.?e-18, 0.?e-18))

With the parameter minimal one can get a minimal base ring:

sage: # needs sage.rings.number_field
sage: s = polytopes.simplex(3)
sage: s_AA = s.affine_hull_projection(orthonormal=True, extend=True)
sage: s_AA.base_ring()
Algebraic Real Field
sage: s_full = s.affine_hull_projection(orthonormal=True, extend=True,
....:                                   minimal=True)
sage: s_full.base_ring()
Number Field in a with defining polynomial y^4 - 4*y^2 + 1
 with a = 0.5176380902050415?
>>> from sage.all import *
>>> # needs sage.rings.number_field
>>> s = polytopes.simplex(Integer(3))
>>> s_AA = s.affine_hull_projection(orthonormal=True, extend=True)
>>> s_AA.base_ring()
Algebraic Real Field
>>> s_full = s.affine_hull_projection(orthonormal=True, extend=True,
...                                   minimal=True)
>>> s_full.base_ring()
Number Field in a with defining polynomial y^4 - 4*y^2 + 1
 with a = 0.5176380902050415?

More examples with the orthonormal parameter:

sage: P = polytopes.permutahedron(3); P
A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 6 vertices
sage: set([F.as_polyhedron().affine_hull_projection(                        # needs sage.combinat sage.rings.number_field
....:          orthonormal=True, extend=True).volume()
....:     for F in P.affine_hull_projection().faces(1)]) == {1, sqrt(AA(2))}
True
sage: set([F.as_polyhedron().affine_hull_projection(                        # needs sage.combinat sage.rings.number_field
....:          orthonormal=True, extend=True).volume()
....:     for F in P.affine_hull_projection(
....:             orthonormal=True, extend=True).faces(1)]) == {sqrt(AA(2))}
True

sage: # needs sage.rings.number_field
sage: D = polytopes.dodecahedron()
sage: F = D.faces(2)[0].as_polyhedron()
sage: F.affine_hull_projection(orthogonal=True)
A 2-dimensional polyhedron in
 (Number Field in sqrt5 with defining polynomial x^2 - 5
  with sqrt5 = 2.236067977499790?)^2
 defined as the convex hull of 5 vertices
sage: F.affine_hull_projection(orthonormal=True, extend=True)
A 2-dimensional polyhedron in AA^2 defined as the convex hull of 5 vertices

sage: # needs sage.rings.number_field
sage: K.<sqrt2> = QuadraticField(2)
sage: P = Polyhedron([2*[K.zero()],2*[sqrt2]]); P
A 1-dimensional polyhedron in
 (Number Field in sqrt2 with defining polynomial x^2 - 2
  with sqrt2 = 1.414213562373095?)^2
 defined as the convex hull of 2 vertices
sage: P.vertices()
(A vertex at (0, 0), A vertex at (sqrt2, sqrt2))
sage: A = P.affine_hull_projection(orthonormal=True); A
A 1-dimensional polyhedron in
 (Number Field in sqrt2 with defining polynomial x^2 - 2
  with sqrt2 = 1.414213562373095?)^1
 defined as the convex hull of 2 vertices
sage: A.vertices()
(A vertex at (0), A vertex at (2))

sage: # needs sage.rings.number_field
sage: K.<sqrt3> = QuadraticField(3)
sage: P = Polyhedron([2*[K.zero()], 2*[sqrt3]]); P
A 1-dimensional polyhedron in
 (Number Field in sqrt3 with defining polynomial x^2 - 3
  with sqrt3 = 1.732050807568878?)^2
 defined as the convex hull of 2 vertices
sage: P.vertices()
(A vertex at (0, 0), A vertex at (sqrt3, sqrt3))
sage: A = P.affine_hull_projection(orthonormal=True)
Traceback (most recent call last):
...
ValueError: the base ring needs to be extended; try with "extend=True"
sage: A = P.affine_hull_projection(orthonormal=True, extend=True); A
A 1-dimensional polyhedron in AA^1 defined as the convex hull of 2 vertices
sage: A.vertices()
(A vertex at (0), A vertex at (2.449489742783178?))
sage: sqrt(6).n()
2.44948974278318
>>> from sage.all import *
>>> P = polytopes.permutahedron(Integer(3)); P
A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 6 vertices
>>> set([F.as_polyhedron().affine_hull_projection(                        # needs sage.combinat sage.rings.number_field
...          orthonormal=True, extend=True).volume()
...     for F in P.affine_hull_projection().faces(Integer(1))]) == {Integer(1), sqrt(AA(Integer(2)))}
True
>>> set([F.as_polyhedron().affine_hull_projection(                        # needs sage.combinat sage.rings.number_field
...          orthonormal=True, extend=True).volume()
...     for F in P.affine_hull_projection(
...             orthonormal=True, extend=True).faces(Integer(1))]) == {sqrt(AA(Integer(2)))}
True

>>> # needs sage.rings.number_field
>>> D = polytopes.dodecahedron()
>>> F = D.faces(Integer(2))[Integer(0)].as_polyhedron()
>>> F.affine_hull_projection(orthogonal=True)
A 2-dimensional polyhedron in
 (Number Field in sqrt5 with defining polynomial x^2 - 5
  with sqrt5 = 2.236067977499790?)^2
 defined as the convex hull of 5 vertices
>>> F.affine_hull_projection(orthonormal=True, extend=True)
A 2-dimensional polyhedron in AA^2 defined as the convex hull of 5 vertices

>>> # needs sage.rings.number_field
>>> K = QuadraticField(Integer(2), names=('sqrt2',)); (sqrt2,) = K._first_ngens(1)
>>> P = Polyhedron([Integer(2)*[K.zero()],Integer(2)*[sqrt2]]); P
A 1-dimensional polyhedron in
 (Number Field in sqrt2 with defining polynomial x^2 - 2
  with sqrt2 = 1.414213562373095?)^2
 defined as the convex hull of 2 vertices
>>> P.vertices()
(A vertex at (0, 0), A vertex at (sqrt2, sqrt2))
>>> A = P.affine_hull_projection(orthonormal=True); A
A 1-dimensional polyhedron in
 (Number Field in sqrt2 with defining polynomial x^2 - 2
  with sqrt2 = 1.414213562373095?)^1
 defined as the convex hull of 2 vertices
>>> A.vertices()
(A vertex at (0), A vertex at (2))

>>> # needs sage.rings.number_field
>>> K = QuadraticField(Integer(3), names=('sqrt3',)); (sqrt3,) = K._first_ngens(1)
>>> P = Polyhedron([Integer(2)*[K.zero()], Integer(2)*[sqrt3]]); P
A 1-dimensional polyhedron in
 (Number Field in sqrt3 with defining polynomial x^2 - 3
  with sqrt3 = 1.732050807568878?)^2
 defined as the convex hull of 2 vertices
>>> P.vertices()
(A vertex at (0, 0), A vertex at (sqrt3, sqrt3))
>>> A = P.affine_hull_projection(orthonormal=True)
Traceback (most recent call last):
...
ValueError: the base ring needs to be extended; try with "extend=True"
>>> A = P.affine_hull_projection(orthonormal=True, extend=True); A
A 1-dimensional polyhedron in AA^1 defined as the convex hull of 2 vertices
>>> A.vertices()
(A vertex at (0), A vertex at (2.449489742783178?))
>>> sqrt(Integer(6)).n()
2.44948974278318

The affine hull is combinatorially equivalent to the input:

sage: P.is_combinatorially_isomorphic(P.affine_hull_projection())           # needs sage.rings.number_field
True
sage: P.is_combinatorially_isomorphic(P.affine_hull_projection(             # needs sage.rings.number_field
....:     orthogonal=True))
True
sage: P.is_combinatorially_isomorphic(P.affine_hull_projection(             # needs sage.rings.number_field
....:     orthonormal=True, extend=True))
True
>>> from sage.all import *
>>> P.is_combinatorially_isomorphic(P.affine_hull_projection())           # needs sage.rings.number_field
True
>>> P.is_combinatorially_isomorphic(P.affine_hull_projection(             # needs sage.rings.number_field
...     orthogonal=True))
True
>>> P.is_combinatorially_isomorphic(P.affine_hull_projection(             # needs sage.rings.number_field
...     orthonormal=True, extend=True))
True

The orthonormal=True parameter preserves volumes; it provides an isometric copy of the polyhedron:

sage: # needs sage.rings.number_field
sage: Pentagon = polytopes.dodecahedron().faces(2)[0].as_polyhedron()
sage: P = Pentagon.affine_hull_projection(orthonormal=True, extend=True)
sage: _, c= P.is_inscribed(certificate=True)
sage: c
(0.4721359549995794?, 0.6498393924658126?)
sage: circumradius = (c - vector(P.vertices()[0])).norm()
sage: p = polytopes.regular_polygon(5)
sage: p.volume()
2.377641290737884?
sage: P.volume()
1.53406271079097?
sage: p.volume()*circumradius^2
1.534062710790965?
sage: P.volume() == p.volume()*circumradius^2
True
>>> from sage.all import *
>>> # needs sage.rings.number_field
>>> Pentagon = polytopes.dodecahedron().faces(Integer(2))[Integer(0)].as_polyhedron()
>>> P = Pentagon.affine_hull_projection(orthonormal=True, extend=True)
>>> _, c= P.is_inscribed(certificate=True)
>>> c
(0.4721359549995794?, 0.6498393924658126?)
>>> circumradius = (c - vector(P.vertices()[Integer(0)])).norm()
>>> p = polytopes.regular_polygon(Integer(5))
>>> p.volume()
2.377641290737884?
>>> P.volume()
1.53406271079097?
>>> p.volume()*circumradius**Integer(2)
1.534062710790965?
>>> P.volume() == p.volume()*circumradius**Integer(2)
True

One can also use orthogonal parameter to calculate volumes; in this case we don’t need to switch base rings. One has to divide by the square root of the determinant of the linear part of the affine transformation times its transpose:

sage: # needs sage.rings.number_field
sage: Pentagon = polytopes.dodecahedron().faces(2)[0].as_polyhedron()
sage: Pnormal = Pentagon.affine_hull_projection(orthonormal=True,
....:                                           extend=True)
sage: Pgonal  = Pentagon.affine_hull_projection(orthogonal=True)
sage: A, b    = Pentagon.affine_hull_projection(orthogonal=True,
....:                                           as_affine_map=True)
sage: Adet = (A.matrix().transpose()*A.matrix()).det()
sage: Pnormal.volume()
1.53406271079097?
sage: Pgonal.volume()/Adet.sqrt(extend=True)
-80*(55*sqrt(5) - 123)/sqrt(-6368*sqrt(5) + 14240)
sage: Pgonal.volume()/AA(Adet).sqrt().n(digits=20)
1.5340627107909646813
sage: AA(Pgonal.volume()^2) == (Pnormal.volume()^2)*AA(Adet)
True
>>> from sage.all import *
>>> # needs sage.rings.number_field
>>> Pentagon = polytopes.dodecahedron().faces(Integer(2))[Integer(0)].as_polyhedron()
>>> Pnormal = Pentagon.affine_hull_projection(orthonormal=True,
...                                           extend=True)
>>> Pgonal  = Pentagon.affine_hull_projection(orthogonal=True)
>>> A, b    = Pentagon.affine_hull_projection(orthogonal=True,
...                                           as_affine_map=True)
>>> Adet = (A.matrix().transpose()*A.matrix()).det()
>>> Pnormal.volume()
1.53406271079097?
>>> Pgonal.volume()/Adet.sqrt(extend=True)
-80*(55*sqrt(5) - 123)/sqrt(-6368*sqrt(5) + 14240)
>>> Pgonal.volume()/AA(Adet).sqrt().n(digits=Integer(20))
1.5340627107909646813
>>> AA(Pgonal.volume()**Integer(2)) == (Pnormal.volume()**Integer(2))*AA(Adet)
True

Another example with as_affine_map=True:

sage: # needs sage.combinat sage.rings.number_field
sage: P = polytopes.permutahedron(4)
sage: Q    = P.affine_hull_projection(orthonormal=True, extend=True)
sage: A, b = P.affine_hull_projection(orthonormal=True, extend=True,
....:                                 as_affine_map=True)
sage: Q.center()
(0.7071067811865475?, 1.224744871391589?, 1.732050807568878?)
sage: A(P.center()) + b == Q.center()
True
>>> from sage.all import *
>>> # needs sage.combinat sage.rings.number_field
>>> P = polytopes.permutahedron(Integer(4))
>>> Q    = P.affine_hull_projection(orthonormal=True, extend=True)
>>> A, b = P.affine_hull_projection(orthonormal=True, extend=True,
...                                 as_affine_map=True)
>>> Q.center()
(0.7071067811865475?, 1.224744871391589?, 1.732050807568878?)
>>> A(P.center()) + b == Q.center()
True

For unbounded, non full-dimensional polyhedra, the orthogonal=True and orthonormal=True is not implemented:

sage: P = Polyhedron(ieqs=[[0, 1, 0], [0, 0, 1], [0, 0, -1]]); P
A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 ray
sage: P.is_compact()
False
sage: P.is_full_dimensional()
False
sage: P.affine_hull_projection(orthogonal=True)
Traceback (most recent call last):
...
NotImplementedError: "orthogonal=True" and "orthonormal=True"
work only for compact polyhedra
sage: P.affine_hull_projection(orthonormal=True)
Traceback (most recent call last):
...
NotImplementedError: "orthogonal=True" and "orthonormal=True"
work only for compact polyhedra
>>> from sage.all import *
>>> P = Polyhedron(ieqs=[[Integer(0), Integer(1), Integer(0)], [Integer(0), Integer(0), Integer(1)], [Integer(0), Integer(0), -Integer(1)]]); P
A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 ray
>>> P.is_compact()
False
>>> P.is_full_dimensional()
False
>>> P.affine_hull_projection(orthogonal=True)
Traceback (most recent call last):
...
NotImplementedError: "orthogonal=True" and "orthonormal=True"
work only for compact polyhedra
>>> P.affine_hull_projection(orthonormal=True)
Traceback (most recent call last):
...
NotImplementedError: "orthogonal=True" and "orthonormal=True"
work only for compact polyhedra

Setting as_affine_map to True without orthogonal or orthonormal set to True:

sage: S = polytopes.simplex()
sage: S.affine_hull_projection(as_affine_map=True)
(Vector space morphism represented by the matrix:
 [1 0 0]
 [0 1 0]
 [0 0 1]
 [0 0 0]
 Domain: Vector space of dimension 4 over Rational Field
 Codomain: Vector space of dimension 3 over Rational Field,
 (0, 0, 0))
>>> from sage.all import *
>>> S = polytopes.simplex()
>>> S.affine_hull_projection(as_affine_map=True)
(Vector space morphism represented by the matrix:
 [1 0 0]
 [0 1 0]
 [0 0 1]
 [0 0 0]
 Domain: Vector space of dimension 4 over Rational Field
 Codomain: Vector space of dimension 3 over Rational Field,
 (0, 0, 0))

If the polyhedron is full-dimensional, it is returned:

sage: polytopes.cube().affine_hull_projection()
A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices
sage: polytopes.cube().affine_hull_projection(as_affine_map=True)
(Vector space morphism represented by the matrix:
 [1 0 0]
 [0 1 0]
 [0 0 1]
 Domain: Vector space of dimension 3 over Rational Field
 Codomain: Vector space of dimension 3 over Rational Field,
 (0, 0, 0))
>>> from sage.all import *
>>> polytopes.cube().affine_hull_projection()
A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices
>>> polytopes.cube().affine_hull_projection(as_affine_map=True)
(Vector space morphism represented by the matrix:
 [1 0 0]
 [0 1 0]
 [0 0 1]
 Domain: Vector space of dimension 3 over Rational Field
 Codomain: Vector space of dimension 3 over Rational Field,
 (0, 0, 0))

Return polyhedron and affine map:

sage: S = polytopes.simplex(2)
sage: data = S.affine_hull_projection(orthogonal=True,
....:                                 as_polyhedron=True,
....:                                 as_affine_map=True); data
AffineHullProjectionData(image=A 2-dimensional polyhedron in QQ^2
                               defined as the convex hull of 3 vertices,
    projection_linear_map=Vector space morphism represented by the matrix:
        [  -1 -1/2]
        [   1 -1/2]
        [   0    1]
        Domain:   Vector space of dimension 3 over Rational Field
        Codomain: Vector space of dimension 2 over Rational Field,
    projection_translation=(1, 1/2),
    section_linear_map=None,
    section_translation=None)
>>> from sage.all import *
>>> S = polytopes.simplex(Integer(2))
>>> data = S.affine_hull_projection(orthogonal=True,
...                                 as_polyhedron=True,
...                                 as_affine_map=True); data
AffineHullProjectionData(image=A 2-dimensional polyhedron in QQ^2
                               defined as the convex hull of 3 vertices,
    projection_linear_map=Vector space morphism represented by the matrix:
        [  -1 -1/2]
        [   1 -1/2]
        [   0    1]
        Domain:   Vector space of dimension 3 over Rational Field
        Codomain: Vector space of dimension 2 over Rational Field,
    projection_translation=(1, 1/2),
    section_linear_map=None,
    section_translation=None)

Return all data:

sage: data = S.affine_hull_projection(orthogonal=True, return_all_data=True); data
AffineHullProjectionData(image=A 2-dimensional polyhedron in QQ^2
                               defined as the convex hull of 3 vertices,
    projection_linear_map=Vector space morphism represented by the matrix:
        [  -1 -1/2]
        [   1 -1/2]
        [   0    1]
        Domain:   Vector space of dimension 3 over Rational Field
        Codomain: Vector space of dimension 2 over Rational Field,
    projection_translation=(1, 1/2),
    section_linear_map=Vector space morphism represented by the matrix:
        [-1/2  1/2    0]
        [-1/3 -1/3  2/3]
        Domain:   Vector space of dimension 2 over Rational Field
        Codomain: Vector space of dimension 3 over Rational Field,
    section_translation=(1, 0, 0))
>>> from sage.all import *
>>> data = S.affine_hull_projection(orthogonal=True, return_all_data=True); data
AffineHullProjectionData(image=A 2-dimensional polyhedron in QQ^2
                               defined as the convex hull of 3 vertices,
    projection_linear_map=Vector space morphism represented by the matrix:
        [  -1 -1/2]
        [   1 -1/2]
        [   0    1]
        Domain:   Vector space of dimension 3 over Rational Field
        Codomain: Vector space of dimension 2 over Rational Field,
    projection_translation=(1, 1/2),
    section_linear_map=Vector space morphism represented by the matrix:
        [-1/2  1/2    0]
        [-1/3 -1/3  2/3]
        Domain:   Vector space of dimension 2 over Rational Field
        Codomain: Vector space of dimension 3 over Rational Field,
    section_translation=(1, 0, 0))

The section map is a right inverse of the projection map:

sage: mat = data.section_linear_map.matrix().transpose()
sage: data.image.linear_transformation(mat) + data.section_translation == S
True
>>> from sage.all import *
>>> mat = data.section_linear_map.matrix().transpose()
>>> data.image.linear_transformation(mat) + data.section_translation == S
True

Same without orthogonal=True:

sage: data = S.affine_hull_projection(return_all_data=True); data
AffineHullProjectionData(image=A 2-dimensional polyhedron in ZZ^2
                               defined as the convex hull of 3 vertices,
    projection_linear_map=Vector space morphism represented by the matrix:
        [1 0]
        [0 1]
        [0 0]
        Domain:   Vector space of dimension 3 over Rational Field
        Codomain: Vector space of dimension 2 over Rational Field,
    projection_translation=(0, 0),
    section_linear_map=Vector space morphism represented by the matrix:
        [ 1  0 -1]
        [ 0  1 -1]
        Domain:   Vector space of dimension 2 over Rational Field
        Codomain: Vector space of dimension 3 over Rational Field,
    section_translation=(0, 0, 1))
sage: mat = data.section_linear_map.matrix().transpose()
sage: data.image.linear_transformation(mat) + data.section_translation == S
True
>>> from sage.all import *
>>> data = S.affine_hull_projection(return_all_data=True); data
AffineHullProjectionData(image=A 2-dimensional polyhedron in ZZ^2
                               defined as the convex hull of 3 vertices,
    projection_linear_map=Vector space morphism represented by the matrix:
        [1 0]
        [0 1]
        [0 0]
        Domain:   Vector space of dimension 3 over Rational Field
        Codomain: Vector space of dimension 2 over Rational Field,
    projection_translation=(0, 0),
    section_linear_map=Vector space morphism represented by the matrix:
        [ 1  0 -1]
        [ 0  1 -1]
        Domain:   Vector space of dimension 2 over Rational Field
        Codomain: Vector space of dimension 3 over Rational Field,
    section_translation=(0, 0, 1))
>>> mat = data.section_linear_map.matrix().transpose()
>>> data.image.linear_transformation(mat) + data.section_translation == S
True
sage: P0 = Polyhedron(
....:     ieqs=[(0, -1, 0, 1, 1, 1), (0, 1, 1, 0, -1, -1), (0, -1, 1, 1, 0, 0),
....:           (0, 1, 0, 0, 0, 0), (0, 0, 1, 1, -1, -1), (0, 0, 0, 0, 0, 1),
....:           (0, 0, 0, 0, 1, 0), (0, 0, 0, 1, 0, -1), (0, 0, 1, 0, 0, 0)])
sage: P = P0.intersection(Polyhedron(eqns=[(-1, 1, 1, 1, 1, 1)]))
sage: P.dim()
4
sage: P.affine_hull_projection(orthogonal=True, as_affine_map=True)[0]
Vector space morphism represented by the matrix:
[    0     0     0   1/3]
[ -2/3  -1/6     0 -1/12]
[  1/3  -1/6   1/2 -1/12]
[    0   1/2     0 -1/12]
[  1/3  -1/6  -1/2 -1/12]
Domain: Vector space of dimension 5 over Rational Field
Codomain: Vector space of dimension 4 over Rational Field
>>> from sage.all import *
>>> P0 = Polyhedron(
...     ieqs=[(Integer(0), -Integer(1), Integer(0), Integer(1), Integer(1), Integer(1)), (Integer(0), Integer(1), Integer(1), Integer(0), -Integer(1), -Integer(1)), (Integer(0), -Integer(1), Integer(1), Integer(1), Integer(0), Integer(0)),
...           (Integer(0), Integer(1), Integer(0), Integer(0), Integer(0), Integer(0)), (Integer(0), Integer(0), Integer(1), Integer(1), -Integer(1), -Integer(1)), (Integer(0), Integer(0), Integer(0), Integer(0), Integer(0), Integer(1)),
...           (Integer(0), Integer(0), Integer(0), Integer(0), Integer(1), Integer(0)), (Integer(0), Integer(0), Integer(0), Integer(1), Integer(0), -Integer(1)), (Integer(0), Integer(0), Integer(1), Integer(0), Integer(0), Integer(0))])
>>> P = P0.intersection(Polyhedron(eqns=[(-Integer(1), Integer(1), Integer(1), Integer(1), Integer(1), Integer(1))]))
>>> P.dim()
4
>>> P.affine_hull_projection(orthogonal=True, as_affine_map=True)[Integer(0)]
Vector space morphism represented by the matrix:
[    0     0     0   1/3]
[ -2/3  -1/6     0 -1/12]
[  1/3  -1/6   1/2 -1/12]
[    0   1/2     0 -1/12]
[  1/3  -1/6  -1/2 -1/12]
Domain: Vector space of dimension 5 over Rational Field
Codomain: Vector space of dimension 4 over Rational Field
gale_transform()[source]#

Return the Gale transform of a polytope as described in the reference below.

OUTPUT:

A list of vectors, the Gale transform. The dimension is the dimension of the affine dependencies of the vertices of the polytope.

EXAMPLES:

This is from the reference, for a triangular prism:

sage: p = Polyhedron(vertices = [[0,0],[0,1],[1,0]])
sage: p2 = p.prism()
sage: p2.gale_transform()
((-1, 0), (0, -1), (1, 1), (-1, -1), (1, 0), (0, 1))
>>> from sage.all import *
>>> p = Polyhedron(vertices = [[Integer(0),Integer(0)],[Integer(0),Integer(1)],[Integer(1),Integer(0)]])
>>> p2 = p.prism()
>>> p2.gale_transform()
((-1, 0), (0, -1), (1, 1), (-1, -1), (1, 0), (0, 1))

REFERENCES:

Lectures in Geometric Combinatorics, R.R.Thomas, 2006, AMS Press.

See also

gale_transform_to_polyhedron().

plot(point=None, line=None, polygon=None, wireframe='blue', fill='green', position=None, orthonormal=True, **kwds)[source]#

Return a graphical representation.

INPUT:

  • point, line, polygon – Parameters to pass to point (0d), line (1d), and polygon (2d) plot commands. Allowed values are:

    • A Python dictionary to be passed as keywords to the plot commands.

    • A string or triple of numbers: The color. This is equivalent to passing the dictionary {'color':...}.

    • False: Switches off the drawing of the corresponding graphics object

  • wireframe, fill – Similar to point, line, and polygon, but fill is used for the graphics objects in the dimension of the polytope (or of dimension 2 for higher dimensional polytopes) and wireframe is used for all lower-dimensional graphics objects (default: ‘green’ for fill and ‘blue’ for wireframe)

  • position – positive number; the position to take the projection point in Schlegel diagrams.

  • orthonormal – Boolean (default: True); whether to use orthonormal projections.

  • **kwds – optional keyword parameters that are passed to all graphics objects.

OUTPUT:

A (multipart) graphics object.

EXAMPLES:

sage: square = polytopes.hypercube(2)
sage: point = Polyhedron([[1,1]])
sage: line = Polyhedron([[1,1],[2,1]])
sage: cube = polytopes.hypercube(3)
sage: hypercube = polytopes.hypercube(4)
>>> from sage.all import *
>>> square = polytopes.hypercube(Integer(2))
>>> point = Polyhedron([[Integer(1),Integer(1)]])
>>> line = Polyhedron([[Integer(1),Integer(1)],[Integer(2),Integer(1)]])
>>> cube = polytopes.hypercube(Integer(3))
>>> hypercube = polytopes.hypercube(Integer(4))

By default, the wireframe is rendered in blue and the fill in green:

sage: # needs sage.plot
sage: square.plot()
Graphics object consisting of 6 graphics primitives
sage: point.plot()
Graphics object consisting of 1 graphics primitive
sage: line.plot()
Graphics object consisting of 2 graphics primitives
sage: cube.plot()
Graphics3d Object
sage: hypercube.plot()
Graphics3d Object
>>> from sage.all import *
>>> # needs sage.plot
>>> square.plot()
Graphics object consisting of 6 graphics primitives
>>> point.plot()
Graphics object consisting of 1 graphics primitive
>>> line.plot()
Graphics object consisting of 2 graphics primitives
>>> cube.plot()
Graphics3d Object
>>> hypercube.plot()
Graphics3d Object

Draw the lines in red and nothing else:

sage: # needs sage.plot
sage: square.plot(point=False, line='red', polygon=False)
Graphics object consisting of 4 graphics primitives
sage: point.plot(point=False, line='red', polygon=False)
Graphics object consisting of 0 graphics primitives
sage: line.plot(point=False, line='red', polygon=False)
Graphics object consisting of 1 graphics primitive
sage: cube.plot(point=False, line='red', polygon=False)
Graphics3d Object
sage: hypercube.plot(point=False, line='red', polygon=False)
Graphics3d Object
>>> from sage.all import *
>>> # needs sage.plot
>>> square.plot(point=False, line='red', polygon=False)
Graphics object consisting of 4 graphics primitives
>>> point.plot(point=False, line='red', polygon=False)
Graphics object consisting of 0 graphics primitives
>>> line.plot(point=False, line='red', polygon=False)
Graphics object consisting of 1 graphics primitive
>>> cube.plot(point=False, line='red', polygon=False)
Graphics3d Object
>>> hypercube.plot(point=False, line='red', polygon=False)
Graphics3d Object

Draw points in red, no lines, and a blue polygon:

sage: # needs sage.plot
sage: square.plot(point={'color':'red'}, line=False, polygon=(0,0,1))
Graphics object consisting of 2 graphics primitives
sage: point.plot(point={'color':'red'}, line=False, polygon=(0,0,1))
Graphics object consisting of 1 graphics primitive
sage: line.plot(point={'color':'red'}, line=False, polygon=(0,0,1))
Graphics object consisting of 1 graphics primitive
sage: cube.plot(point={'color':'red'}, line=False, polygon=(0,0,1))
Graphics3d Object
sage: hypercube.plot(point={'color':'red'}, line=False, polygon=(0,0,1))
Graphics3d Object
>>> from sage.all import *
>>> # needs sage.plot
>>> square.plot(point={'color':'red'}, line=False, polygon=(Integer(0),Integer(0),Integer(1)))
Graphics object consisting of 2 graphics primitives
>>> point.plot(point={'color':'red'}, line=False, polygon=(Integer(0),Integer(0),Integer(1)))
Graphics object consisting of 1 graphics primitive
>>> line.plot(point={'color':'red'}, line=False, polygon=(Integer(0),Integer(0),Integer(1)))
Graphics object consisting of 1 graphics primitive
>>> cube.plot(point={'color':'red'}, line=False, polygon=(Integer(0),Integer(0),Integer(1)))
Graphics3d Object
>>> hypercube.plot(point={'color':'red'}, line=False, polygon=(Integer(0),Integer(0),Integer(1)))
Graphics3d Object

If we instead use the fill and wireframe options, the coloring depends on the dimension of the object:

sage: # needs sage.plot
sage: square.plot(fill='green', wireframe='red')
Graphics object consisting of 6 graphics primitives
sage: point.plot(fill='green', wireframe='red')
Graphics object consisting of 1 graphics primitive
sage: line.plot(fill='green', wireframe='red')
Graphics object consisting of 2 graphics primitives
sage: cube.plot(fill='green', wireframe='red')
Graphics3d Object
sage: hypercube.plot(fill='green', wireframe='red')
Graphics3d Object
>>> from sage.all import *
>>> # needs sage.plot
>>> square.plot(fill='green', wireframe='red')
Graphics object consisting of 6 graphics primitives
>>> point.plot(fill='green', wireframe='red')
Graphics object consisting of 1 graphics primitive
>>> line.plot(fill='green', wireframe='red')
Graphics object consisting of 2 graphics primitives
>>> cube.plot(fill='green', wireframe='red')
Graphics3d Object
>>> hypercube.plot(fill='green', wireframe='red')
Graphics3d Object

It is possible to draw polyhedra up to dimension 4, no matter what the ambient dimension is:

sage: hcube = polytopes.hypercube(5)
sage: facet = hcube.facets()[0].as_polyhedron(); facet
A 4-dimensional polyhedron in ZZ^5 defined as the convex hull of 16 vertices
sage: facet.plot()                                                          # needs sage.plot
Graphics3d Object
>>> from sage.all import *
>>> hcube = polytopes.hypercube(Integer(5))
>>> facet = hcube.facets()[Integer(0)].as_polyhedron(); facet
A 4-dimensional polyhedron in ZZ^5 defined as the convex hull of 16 vertices
>>> facet.plot()                                                          # needs sage.plot
Graphics3d Object

For a 3d plot, we may draw the polygons with rainbow colors, using any of the following ways:

sage: cube.plot(polygon='rainbow')                                          # needs sage.plot
Graphics3d Object
sage: cube.plot(polygon={'color':'rainbow'})                                # needs sage.plot
Graphics3d Object
sage: cube.plot(fill='rainbow')                                             # needs sage.plot
Graphics3d Object
>>> from sage.all import *
>>> cube.plot(polygon='rainbow')                                          # needs sage.plot
Graphics3d Object
>>> cube.plot(polygon={'color':'rainbow'})                                # needs sage.plot
Graphics3d Object
>>> cube.plot(fill='rainbow')                                             # needs sage.plot
Graphics3d Object

For a 3d plot, the size of a point, the thickness of a line and the width of an arrow are controlled by the respective parameters:

sage: prism = Polyhedron(vertices=[[0,0,0],[1,0,0],[0,1,0]], rays=[[0,0,1]])
sage: prism.plot(size=20, thickness=30, width=1)                            # needs sage.plot
Graphics3d Object
sage: prism.plot(point={'size':20, 'color':'black'},                        # needs sage.plot
....:            line={'thickness':30, 'width':1, 'color':'black'},
....:            polygon='rainbow')
Graphics3d Object
>>> from sage.all import *
>>> prism = Polyhedron(vertices=[[Integer(0),Integer(0),Integer(0)],[Integer(1),Integer(0),Integer(0)],[Integer(0),Integer(1),Integer(0)]], rays=[[Integer(0),Integer(0),Integer(1)]])
>>> prism.plot(size=Integer(20), thickness=Integer(30), width=Integer(1))                            # needs sage.plot
Graphics3d Object
>>> prism.plot(point={'size':Integer(20), 'color':'black'},                        # needs sage.plot
...            line={'thickness':Integer(30), 'width':Integer(1), 'color':'black'},
...            polygon='rainbow')
Graphics3d Object
projection(projection=None)[source]#

Return a projection object.

INPUT:

  • proj – a projection function

OUTPUT:

The identity projection. This is useful for plotting polyhedra.

See also

schlegel_projection() for a more interesting projection.

EXAMPLES:

sage: p = polytopes.hypercube(3)
sage: proj = p.projection()
sage: proj
The projection of a polyhedron into 3 dimensions
>>> from sage.all import *
>>> p = polytopes.hypercube(Integer(3))
>>> proj = p.projection()
>>> proj
The projection of a polyhedron into 3 dimensions
render_solid(**kwds)[source]#

Return a solid rendering of a 2- or 3-d polytope.

EXAMPLES:

sage: p = polytopes.hypercube(3)
sage: p_solid = p.render_solid(opacity=.7)                                  # needs sage.plot
sage: type(p_solid)                                                         # needs sage.plot
<class 'sage.plot.plot3d.index_face_set.IndexFaceSet'>
>>> from sage.all import *
>>> p = polytopes.hypercube(Integer(3))
>>> p_solid = p.render_solid(opacity=RealNumber('.7'))                                  # needs sage.plot
>>> type(p_solid)                                                         # needs sage.plot
<class 'sage.plot.plot3d.index_face_set.IndexFaceSet'>
render_wireframe(**kwds)[source]#

For polytopes in 2 or 3 dimensions, return the edges as a list of lines.

EXAMPLES:

sage: p = Polyhedron([[1,2,],[1,1],[0,0]])
sage: p_wireframe = p.render_wireframe()                                    # needs sage.plot
sage: p_wireframe._objects                                                  # needs sage.plot
[Line defined by 2 points, Line defined by 2 points, Line defined by 2 points]
>>> from sage.all import *
>>> p = Polyhedron([[Integer(1),Integer(2),],[Integer(1),Integer(1)],[Integer(0),Integer(0)]])
>>> p_wireframe = p.render_wireframe()                                    # needs sage.plot
>>> p_wireframe._objects                                                  # needs sage.plot
[Line defined by 2 points, Line defined by 2 points, Line defined by 2 points]
schlegel_projection(facet=None, position=None)[source]#

Return the Schlegel projection.

  • The facet is orthonormally transformed into its affine hull.

  • The position specifies a point coming out of the barycenter of the facet from which the other vertices will be projected into the facet.

INPUT:

  • facet – a PolyhedronFace. The facet into which the Schlegel diagram is created. The default is the first facet.

  • position – a positive number. Determines a relative distance from the barycenter of facet. A value close to 0 will place the projection point close to the facet and a large value further away. Default is \(1\). If the given value is too large, an error is returned.

OUTPUT:

A Projection object.

EXAMPLES:

sage: p = polytopes.hypercube(3)
sage: sch_proj = p.schlegel_projection()
sage: schlegel_edge_indices = sch_proj.lines
sage: schlegel_edges = [sch_proj.coordinates_of(x) for x in schlegel_edge_indices]
sage: len([x for x in schlegel_edges if x[0][0] > 0])
8
>>> from sage.all import *
>>> p = polytopes.hypercube(Integer(3))
>>> sch_proj = p.schlegel_projection()
>>> schlegel_edge_indices = sch_proj.lines
>>> schlegel_edges = [sch_proj.coordinates_of(x) for x in schlegel_edge_indices]
>>> len([x for x in schlegel_edges if x[Integer(0)][Integer(0)] > Integer(0)])
8

The Schlegel projection preserves the convexity of facets, see Issue #30015:

sage: fcube = polytopes.hypercube(4)
sage: tfcube = fcube.face_truncation(fcube.faces(0)[0])
sage: tfcube.facets()[-1]
A 3-dimensional face of a Polyhedron in QQ^4 defined as the convex hull of 8 vertices
sage: sp = tfcube.schlegel_projection(tfcube.facets()[-1])
sage: sp.plot()                                                             # needs sage.plot
Graphics3d Object
>>> from sage.all import *
>>> fcube = polytopes.hypercube(Integer(4))
>>> tfcube = fcube.face_truncation(fcube.faces(Integer(0))[Integer(0)])
>>> tfcube.facets()[-Integer(1)]
A 3-dimensional face of a Polyhedron in QQ^4 defined as the convex hull of 8 vertices
>>> sp = tfcube.schlegel_projection(tfcube.facets()[-Integer(1)])
>>> sp.plot()                                                             # needs sage.plot
Graphics3d Object

The same truncated cube but see inside the tetrahedral facet:

sage: tfcube.facets()[4]
A 3-dimensional face of a Polyhedron in QQ^4 defined as the convex hull of 4 vertices
sage: sp = tfcube.schlegel_projection(tfcube.facets()[4])                   # needs sage.symbolic
sage: sp.plot()                                                             # needs sage.plot sage.symbolic
Graphics3d Object
>>> from sage.all import *
>>> tfcube.facets()[Integer(4)]
A 3-dimensional face of a Polyhedron in QQ^4 defined as the convex hull of 4 vertices
>>> sp = tfcube.schlegel_projection(tfcube.facets()[Integer(4)])                   # needs sage.symbolic
>>> sp.plot()                                                             # needs sage.plot sage.symbolic
Graphics3d Object

A different values of position changes the projection:

sage: # needs sage.symbolic
sage: sp = tfcube.schlegel_projection(tfcube.facets()[4], 1/2)
sage: sp.plot()                                                             # needs sage.plot
Graphics3d Object
sage: sp = tfcube.schlegel_projection(tfcube.facets()[4], 4)
sage: sp.plot()                                                             # needs sage.plot
Graphics3d Object
>>> from sage.all import *
>>> # needs sage.symbolic
>>> sp = tfcube.schlegel_projection(tfcube.facets()[Integer(4)], Integer(1)/Integer(2))
>>> sp.plot()                                                             # needs sage.plot
Graphics3d Object
>>> sp = tfcube.schlegel_projection(tfcube.facets()[Integer(4)], Integer(4))
>>> sp.plot()                                                             # needs sage.plot
Graphics3d Object

A value which is too large give a projection point that sees more than one facet resulting in a error:

sage: sp = tfcube.schlegel_projection(tfcube.facets()[4], 5)
Traceback (most recent call last):
...
ValueError: the chosen position is too large
>>> from sage.all import *
>>> sp = tfcube.schlegel_projection(tfcube.facets()[Integer(4)], Integer(5))
Traceback (most recent call last):
...
ValueError: the chosen position is too large
show(**kwds)[source]#

Display graphics immediately

This method attempts to display the graphics immediately, without waiting for the currently running code (if any) to return to the command line. Be careful, calling it from within a loop will potentially launch a large number of external viewer programs.

INPUT:

  • kwds – optional keyword arguments. See plot() for the description of available options.

OUTPUT:

This method does not return anything. Use plot() if you want to generate a graphics object that can be saved or further transformed.

EXAMPLES:

sage: square = polytopes.hypercube(2)
sage: square.show(point='red')                                              # needs sage.plot
>>> from sage.all import *
>>> square = polytopes.hypercube(Integer(2))
>>> square.show(point='red')                                              # needs sage.plot
tikz(view=[0, 0, 1], angle=0, scale=1, edge_color='blue!95!black', facet_color='blue!95!black', opacity=0.8, vertex_color='green', axis=False, output_type=None)[source]#

Return a tikz picture of self as a string or as a TikzPicture according to a projection view and an angle angle obtained via the threejs viewer. self must be bounded.

INPUT:

  • view – list (default: [0,0,1]) representing the rotation axis (see note below).

  • angle – integer (default: 0) angle of rotation in degree from 0 to 360 (see note below).

  • scale – integer (default: 1) specifying the scaling of the tikz picture.

  • edge_color – string (default: ‘blue!95!black’) representing colors which tikz recognize.

  • facet_color – string (default: ‘blue!95!black’) representing colors which tikz recognize.

  • vertex_color – string (default: ‘green’) representing colors which tikz recognize.

  • opacity – real number (default: 0.8) between 0 and 1 giving the opacity of the front facets.

  • axis – Boolean (default: False) draw the axes at the origin or not.

  • output_type – string (default: None), valid values are None (deprecated), 'LatexExpr' and 'TikzPicture', whether to return a LatexExpr object (which inherits from Python str) or a TikzPicture object from module sage.misc.latex_standalone

OUTPUT:

  • LatexExpr object or TikzPicture object

Note

This is a wrapper of a method of the projection object self.projection(). See tikz() for more detail.

The inputs view and angle can be obtained by visualizing it using .show(aspect_ratio=1). This will open an interactive view in your default browser, where you can rotate the polytope. Once the desired view angle is found, click on the information icon in the lower right-hand corner and select Get Viewpoint. This will copy a string of the form ‘[x,y,z],angle’ to your local clipboard. Go back to Sage and type Img = P.tikz([x,y,z],angle).

The inputs view and angle can also be obtained from the viewer Jmol:

1) Right click on the image
2) Select ``Console``
3) Select the tab ``State``
4) Scroll to the line ``moveto``

It reads something like:

moveto 0.0 {x y z angle} Scale

The view is then [x,y,z] and angle is angle. The following number is the scale.

Jmol performs a rotation of angle degrees along the vector [x,y,z] and show the result from the z-axis.

EXAMPLES:

sage: # needs sage.plot
sage: co = polytopes.cuboctahedron()
sage: Img = co.tikz([0, 0, 1], 0, output_type='TikzPicture')
sage: Img
\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}%
        [x={(1.000000cm, 0.000000cm)},
        y={(0.000000cm, 1.000000cm)},
        z={(0.000000cm, 0.000000cm)},
        scale=1.000000,
...
Use print to see the full content.
...
\node[vertex] at (1.00000, 0.00000, 1.00000)     {};
\node[vertex] at (1.00000, 1.00000, 0.00000)     {};
%%
%%
\end{tikzpicture}
\end{document}
sage: print('\n'.join(Img.content().splitlines()[12:21]))
%% with the command: ._tikz_3d_in_3d and parameters:
%% view = [0, 0, 1]
%% angle = 0
%% scale = 1
%% edge_color = blue!95!black
%% facet_color = blue!95!black
%% opacity = 0.8
%% vertex_color = green
%% axis = False
sage: print('\n'.join(Img.content().splitlines()[22:26]))
%% Coordinate of the vertices:
%%
\coordinate (-1.00000, -1.00000, 0.00000) at (-1.00000, -1.00000, 0.00000);
\coordinate (-1.00000, 0.00000, -1.00000) at (-1.00000, 0.00000, -1.00000);
>>> from sage.all import *
>>> # needs sage.plot
>>> co = polytopes.cuboctahedron()
>>> Img = co.tikz([Integer(0), Integer(0), Integer(1)], Integer(0), output_type='TikzPicture')
>>> Img
\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}%
        [x={(1.000000cm, 0.000000cm)},
        y={(0.000000cm, 1.000000cm)},
        z={(0.000000cm, 0.000000cm)},
        scale=1.000000,
...
Use print to see the full content.
...
\node[vertex] at (1.00000, 0.00000, 1.00000)     {};
\node[vertex] at (1.00000, 1.00000, 0.00000)     {};
%%
%%
\end{tikzpicture}
\end{document}
>>> print('\n'.join(Img.content().splitlines()[Integer(12):Integer(21)]))
%% with the command: ._tikz_3d_in_3d and parameters:
%% view = [0, 0, 1]
%% angle = 0
%% scale = 1
%% edge_color = blue!95!black
%% facet_color = blue!95!black
%% opacity = 0.8
%% vertex_color = green
%% axis = False
>>> print('\n'.join(Img.content().splitlines()[Integer(22):Integer(26)]))
%% Coordinate of the vertices:
%%
\coordinate (-1.00000, -1.00000, 0.00000) at (-1.00000, -1.00000, 0.00000);
\coordinate (-1.00000, 0.00000, -1.00000) at (-1.00000, 0.00000, -1.00000);

When output type is a sage.misc.latex_standalone.TikzPicture:

sage: # needs sage.plot
sage: co = polytopes.cuboctahedron()
sage: t = co.tikz([674, 108, -731], 112, output_type='TikzPicture'); t
\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}%
        [x={(0.249656cm, -0.577639cm)},
        y={(0.777700cm, -0.358578cm)},
        z={(-0.576936cm, -0.733318cm)},
        scale=1.000000,
...
Use print to see the full content.
...
\node[vertex] at (1.00000, 0.00000, 1.00000)     {};
\node[vertex] at (1.00000, 1.00000, 0.00000)     {};
%%
%%
\end{tikzpicture}
\end{document}
sage: path_to_file = t.pdf()        # not tested
>>> from sage.all import *
>>> # needs sage.plot
>>> co = polytopes.cuboctahedron()
>>> t = co.tikz([Integer(674), Integer(108), -Integer(731)], Integer(112), output_type='TikzPicture'); t
\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}%
        [x={(0.249656cm, -0.577639cm)},
        y={(0.777700cm, -0.358578cm)},
        z={(-0.576936cm, -0.733318cm)},
        scale=1.000000,
...
Use print to see the full content.
...
\node[vertex] at (1.00000, 0.00000, 1.00000)     {};
\node[vertex] at (1.00000, 1.00000, 0.00000)     {};
%%
%%
\end{tikzpicture}
\end{document}
>>> path_to_file = t.pdf()        # not tested