Base class for polyhedra: Miscellaneous methods

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

Bases: Polyhedron_base7

Base class for Polyhedron objects.

INPUT:

  • parent – the parent, an instance of Polyhedra

  • Vrep – list [vertices, rays, lines] or None. The V-representation of the polyhedron; if None, the polyhedron is determined by the H-representation

  • Hrep – list [ieqs, eqns] or None. The H-representation of the polyhedron; if None, the polyhedron is determined by the V-representation

  • Vrep_minimal – (optional) see below

  • Hrep_minimal – (optional) see below

  • pref_rep – string (default: None); one of Vrep or Hrep to pick this in case the backend cannot initialize from complete double description

  • mutable – ignored

If both Vrep and Hrep are provided, then Vrep_minimal and Hrep_minimal must be set to True.

barycentric_subdivision(subdivision_frac=None)[source]

Return the barycentric subdivision of a compact polyhedron.

DEFINITION:

The barycentric subdivision of a compact polyhedron is a standard way to triangulate its faces in such a way that maximal faces correspond to flags of faces of the starting polyhedron (i.e. a maximal chain in the face lattice of the polyhedron). As a simplicial complex, this is known as the order complex of the face lattice of the polyhedron.

REFERENCE:

See Wikipedia article Barycentric_subdivision

Section 6.6, Handbook of Convex Geometry, Volume A, edited by P.M. Gruber and J.M. Wills. 1993, North-Holland Publishing Co..

INPUT:

  • subdivision_frac – number. Gives the proportion how far the new vertices are pulled out of the polytope. Default is 13 and the value should be smaller than 12. The subdivision is computed on the polar polyhedron.

OUTPUT: a Polyhedron object, subdivided as described above

EXAMPLES:

sage: P = polytopes.hypercube(3)
sage: P.barycentric_subdivision()
A 3-dimensional polyhedron in QQ^3 defined as the convex hull
of 26 vertices
sage: P = Polyhedron(vertices=[[0,0,0],[0,1,0],[1,0,0],[0,0,1]])
sage: P.barycentric_subdivision()
A 3-dimensional polyhedron in QQ^3 defined as the convex hull
of 14 vertices
sage: P = Polyhedron(vertices=[[0,1,0],[0,0,1],[1,0,0]])
sage: P.barycentric_subdivision()
A 2-dimensional polyhedron in QQ^3 defined as the convex hull
of 6 vertices
sage: P = polytopes.regular_polygon(4, base_ring=QQ)                        # needs sage.rings.number_field
sage: P.barycentric_subdivision()                                           # needs sage.rings.number_field
A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 8
vertices
>>> from sage.all import *
>>> P = polytopes.hypercube(Integer(3))
>>> P.barycentric_subdivision()
A 3-dimensional polyhedron in QQ^3 defined as the convex hull
of 26 vertices
>>> P = Polyhedron(vertices=[[Integer(0),Integer(0),Integer(0)],[Integer(0),Integer(1),Integer(0)],[Integer(1),Integer(0),Integer(0)],[Integer(0),Integer(0),Integer(1)]])
>>> P.barycentric_subdivision()
A 3-dimensional polyhedron in QQ^3 defined as the convex hull
of 14 vertices
>>> P = Polyhedron(vertices=[[Integer(0),Integer(1),Integer(0)],[Integer(0),Integer(0),Integer(1)],[Integer(1),Integer(0),Integer(0)]])
>>> P.barycentric_subdivision()
A 2-dimensional polyhedron in QQ^3 defined as the convex hull
of 6 vertices
>>> P = polytopes.regular_polygon(Integer(4), base_ring=QQ)                        # needs sage.rings.number_field
>>> P.barycentric_subdivision()                                           # needs sage.rings.number_field
A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 8
vertices
P = polytopes.hypercube(3)
P.barycentric_subdivision()
P = Polyhedron(vertices=[[0,0,0],[0,1,0],[1,0,0],[0,0,1]])
P.barycentric_subdivision()
P = Polyhedron(vertices=[[0,1,0],[0,0,1],[1,0,0]])
P.barycentric_subdivision()
P = polytopes.regular_polygon(4, base_ring=QQ)                        # needs sage.rings.number_field
P.barycentric_subdivision()                                           # needs sage.rings.number_field
boundary_complex()[source]

Return the simplicial complex given by the boundary faces of self, if it is simplicial.

OUTPUT:

A (spherical) simplicial complex

EXAMPLES:

The boundary complex of the octahedron:

sage: # needs sage.graphs
sage: oc = polytopes.octahedron()
sage: sc_oc = oc.boundary_complex()
sage: fl_oc = oc.face_lattice()                                             # needs sage.combinat
sage: fl_sc = sc_oc.face_poset()                                            # needs sage.combinat
sage: [len(x) for x in fl_oc.level_sets()]                                  # needs sage.combinat
[1, 6, 12, 8, 1]
sage: [len(x) for x in fl_sc.level_sets()]                                  # needs sage.combinat
[6, 12, 8]
sage: sc_oc.euler_characteristic()
2
sage: sc_oc.homology()
{0: 0, 1: 0, 2: Z}
>>> from sage.all import *
>>> # needs sage.graphs
>>> oc = polytopes.octahedron()
>>> sc_oc = oc.boundary_complex()
>>> fl_oc = oc.face_lattice()                                             # needs sage.combinat
>>> fl_sc = sc_oc.face_poset()                                            # needs sage.combinat
>>> [len(x) for x in fl_oc.level_sets()]                                  # needs sage.combinat
[1, 6, 12, 8, 1]
>>> [len(x) for x in fl_sc.level_sets()]                                  # needs sage.combinat
[6, 12, 8]
>>> sc_oc.euler_characteristic()
2
>>> sc_oc.homology()
{0: 0, 1: 0, 2: Z}
# needs sage.graphs
oc = polytopes.octahedron()
sc_oc = oc.boundary_complex()
fl_oc = oc.face_lattice()                                             # needs sage.combinat
fl_sc = sc_oc.face_poset()                                            # needs sage.combinat
[len(x) for x in fl_oc.level_sets()]                                  # needs sage.combinat
[len(x) for x in fl_sc.level_sets()]                                  # needs sage.combinat
sc_oc.euler_characteristic()
sc_oc.homology()

The polyhedron should be simplicial:

sage: c = polytopes.cube()
sage: c.boundary_complex()
Traceback (most recent call last):
...
NotImplementedError: this function is only implemented for simplicial polytopes
>>> from sage.all import *
>>> c = polytopes.cube()
>>> c.boundary_complex()
Traceback (most recent call last):
...
NotImplementedError: this function is only implemented for simplicial polytopes
c = polytopes.cube()
c.boundary_complex()
bounding_box(integral=False, integral_hull=False)[source]

Return the coordinates of a rectangular box containing the non-empty polytope.

INPUT:

  • integral – boolean (default: False); whether to only allow integral coordinates in the bounding box

  • integral_hull – boolean (default: False); if True, return a box containing the integral points of the polytope, or None, None if it is known that the polytope has no integral points

OUTPUT:

A pair of tuples (box_min, box_max) where box_min are the coordinates of a point bounding the coordinates of the polytope from below and box_max bounds the coordinates from above.

EXAMPLES:

sage: Polyhedron([(1/3,2/3), (2/3, 1/3)]).bounding_box()
((1/3, 1/3), (2/3, 2/3))
sage: Polyhedron([(1/3,2/3), (2/3, 1/3)]).bounding_box(integral=True)
((0, 0), (1, 1))
sage: Polyhedron([(1/3,2/3), (2/3, 1/3)]).bounding_box(integral_hull=True)
(None, None)
sage: Polyhedron([(1/3,2/3), (3/3, 4/3)]).bounding_box(integral_hull=True)
((1, 1), (1, 1))
sage: polytopes.buckyball(exact=False).bounding_box()                       # needs sage.groups
((-0.8090169944, -0.8090169944, -0.8090169944),
 (0.8090169944, 0.8090169944, 0.8090169944))
>>> from sage.all import *
>>> Polyhedron([(Integer(1)/Integer(3),Integer(2)/Integer(3)), (Integer(2)/Integer(3), Integer(1)/Integer(3))]).bounding_box()
((1/3, 1/3), (2/3, 2/3))
>>> Polyhedron([(Integer(1)/Integer(3),Integer(2)/Integer(3)), (Integer(2)/Integer(3), Integer(1)/Integer(3))]).bounding_box(integral=True)
((0, 0), (1, 1))
>>> Polyhedron([(Integer(1)/Integer(3),Integer(2)/Integer(3)), (Integer(2)/Integer(3), Integer(1)/Integer(3))]).bounding_box(integral_hull=True)
(None, None)
>>> Polyhedron([(Integer(1)/Integer(3),Integer(2)/Integer(3)), (Integer(3)/Integer(3), Integer(4)/Integer(3))]).bounding_box(integral_hull=True)
((1, 1), (1, 1))
>>> polytopes.buckyball(exact=False).bounding_box()                       # needs sage.groups
((-0.8090169944, -0.8090169944, -0.8090169944),
 (0.8090169944, 0.8090169944, 0.8090169944))
Polyhedron([(1/3,2/3), (2/3, 1/3)]).bounding_box()
Polyhedron([(1/3,2/3), (2/3, 1/3)]).bounding_box(integral=True)
Polyhedron([(1/3,2/3), (2/3, 1/3)]).bounding_box(integral_hull=True)
Polyhedron([(1/3,2/3), (3/3, 4/3)]).bounding_box(integral_hull=True)
polytopes.buckyball(exact=False).bounding_box()                       # needs sage.groups
center()[source]

Return the average of the vertices.

OUTPUT:

The center of the polyhedron. All rays and lines are ignored. Raises a ZeroDivisionError for the empty polytope.

EXAMPLES:

sage: p = polytopes.hypercube(3)
sage: p = p + vector([1,0,0])
sage: p.center()
(1, 0, 0)
>>> from sage.all import *
>>> p = polytopes.hypercube(Integer(3))
>>> p = p + vector([Integer(1),Integer(0),Integer(0)])
>>> p.center()
(1, 0, 0)
p = polytopes.hypercube(3)
p = p + vector([1,0,0])
p.center()
face_fan()[source]

Return the face fan of a compact rational polyhedron.

OUTPUT:

A fan of the ambient space as a RationalPolyhedralFan.

See also

normal_fan().

EXAMPLES:

sage: T = polytopes.cuboctahedron()
sage: T.face_fan()
Rational polyhedral fan in 3-d lattice M
>>> from sage.all import *
>>> T = polytopes.cuboctahedron()
>>> T.face_fan()
Rational polyhedral fan in 3-d lattice M
T = polytopes.cuboctahedron()
T.face_fan()

The polytope should contain the origin in the interior:

sage: P = Polyhedron(vertices=[[1/2, 1], [1, 1/2]])
sage: P.face_fan()
Traceback (most recent call last):
...
ValueError: face fans are defined only for polytopes
containing the origin as an interior point!

sage: Q = Polyhedron(vertices=[[-1, 1/2], [1, -1/2]])
sage: Q.contains([0,0])
True
sage: FF = Q.face_fan(); FF
Rational polyhedral fan in 2-d lattice M
>>> from sage.all import *
>>> P = Polyhedron(vertices=[[Integer(1)/Integer(2), Integer(1)], [Integer(1), Integer(1)/Integer(2)]])
>>> P.face_fan()
Traceback (most recent call last):
...
ValueError: face fans are defined only for polytopes
containing the origin as an interior point!

>>> Q = Polyhedron(vertices=[[-Integer(1), Integer(1)/Integer(2)], [Integer(1), -Integer(1)/Integer(2)]])
>>> Q.contains([Integer(0),Integer(0)])
True
>>> FF = Q.face_fan(); FF
Rational polyhedral fan in 2-d lattice M
P = Polyhedron(vertices=[[1/2, 1], [1, 1/2]])
P.face_fan()
Q = Polyhedron(vertices=[[-1, 1/2], [1, -1/2]])
Q.contains([0,0])
FF = Q.face_fan(); FF

The polytope has to have rational coordinates:

sage: S = polytopes.dodecahedron()                                          # needs sage.groups sage.rings.number_field
sage: S.face_fan()                                                          # needs sage.groups sage.rings.number_field
Traceback (most recent call last):
...
NotImplementedError: face fan handles only polytopes over the rationals
>>> from sage.all import *
>>> S = polytopes.dodecahedron()                                          # needs sage.groups sage.rings.number_field
>>> S.face_fan()                                                          # needs sage.groups sage.rings.number_field
Traceback (most recent call last):
...
NotImplementedError: face fan handles only polytopes over the rationals
S = polytopes.dodecahedron()                                          # needs sage.groups sage.rings.number_field
S.face_fan()                                                          # needs sage.groups sage.rings.number_field

REFERENCES:

For more information, see Chapter 7 of [Zie2007].

hyperplane_arrangement()[source]

Return the hyperplane arrangement defined by the equations and inequalities.

OUTPUT:

A hyperplane arrangement consisting of the hyperplanes defined by the Hrepresentation(). If the polytope is full-dimensional, this is the hyperplane arrangement spanned by the facets of the polyhedron.

EXAMPLES:

sage: p = polytopes.hypercube(2)
sage: p.hyperplane_arrangement()
Arrangement <-t0 + 1 | -t1 + 1 | t1 + 1 | t0 + 1>
>>> from sage.all import *
>>> p = polytopes.hypercube(Integer(2))
>>> p.hyperplane_arrangement()
Arrangement <-t0 + 1 | -t1 + 1 | t1 + 1 | t0 + 1>
p = polytopes.hypercube(2)
p.hyperplane_arrangement()
is_inscribed(certificate=False)[source]

This function tests whether the vertices of the polyhedron are inscribed on a sphere.

The polyhedron is expected to be compact and full-dimensional. A full-dimensional compact polytope is inscribed if there exists a point in space which is equidistant to all its vertices.

ALGORITHM:

The function first computes the circumsphere of a full-dimensional simplex with vertices of self. It is found by lifting the points on a paraboloid to find the hyperplane on which the circumsphere is lifted. Then, it checks if all other vertices are equidistant to the circumcenter of that simplex.

INPUT:

  • certificate – boolean (default: False); specifies whether to return the circumcenter, if found

OUTPUT: if certificate is true, returns a tuple containing:

  1. Boolean.

  2. The circumcenter of the polytope or None.

If certificate is false:

  • a Boolean.

EXAMPLES:

sage: q = Polyhedron(vertices=[[1,1,1,1],[-1,-1,1,1],[1,-1,-1,1],
....:                            [-1,1,-1,1],[1,1,1,-1],[-1,-1,1,-1],
....:                            [1,-1,-1,-1],[-1,1,-1,-1],[0,0,10/13,-24/13],
....:                            [0,0,-10/13,-24/13]])
sage: q.is_inscribed(certificate=True)
(True, (0, 0, 0, 0))

sage: cube = polytopes.cube()
sage: cube.is_inscribed()
True

sage: translated_cube = Polyhedron(vertices=[v.vector() + vector([1,2,3])
....:                                        for v in cube.vertices()])
sage: translated_cube.is_inscribed(certificate=True)
(True, (1, 2, 3))

sage: truncated_cube = cube.face_truncation(cube.faces(0)[0])
sage: truncated_cube.is_inscribed()
False
>>> from sage.all import *
>>> q = Polyhedron(vertices=[[Integer(1),Integer(1),Integer(1),Integer(1)],[-Integer(1),-Integer(1),Integer(1),Integer(1)],[Integer(1),-Integer(1),-Integer(1),Integer(1)],
...                            [-Integer(1),Integer(1),-Integer(1),Integer(1)],[Integer(1),Integer(1),Integer(1),-Integer(1)],[-Integer(1),-Integer(1),Integer(1),-Integer(1)],
...                            [Integer(1),-Integer(1),-Integer(1),-Integer(1)],[-Integer(1),Integer(1),-Integer(1),-Integer(1)],[Integer(0),Integer(0),Integer(10)/Integer(13),-Integer(24)/Integer(13)],
...                            [Integer(0),Integer(0),-Integer(10)/Integer(13),-Integer(24)/Integer(13)]])
>>> q.is_inscribed(certificate=True)
(True, (0, 0, 0, 0))

>>> cube = polytopes.cube()
>>> cube.is_inscribed()
True

>>> translated_cube = Polyhedron(vertices=[v.vector() + vector([Integer(1),Integer(2),Integer(3)])
...                                        for v in cube.vertices()])
>>> translated_cube.is_inscribed(certificate=True)
(True, (1, 2, 3))

>>> truncated_cube = cube.face_truncation(cube.faces(Integer(0))[Integer(0)])
>>> truncated_cube.is_inscribed()
False
q = Polyhedron(vertices=[[1,1,1,1],[-1,-1,1,1],[1,-1,-1,1],
                           [-1,1,-1,1],[1,1,1,-1],[-1,-1,1,-1],
                           [1,-1,-1,-1],[-1,1,-1,-1],[0,0,10/13,-24/13],
                           [0,0,-10/13,-24/13]])
q.is_inscribed(certificate=True)
cube = polytopes.cube()
cube.is_inscribed()
translated_cube = Polyhedron(vertices=[v.vector() + vector([1,2,3])
                                       for v in cube.vertices()])
translated_cube.is_inscribed(certificate=True)
truncated_cube = cube.face_truncation(cube.faces(0)[0])
truncated_cube.is_inscribed()

The method is not implemented for non-full-dimensional polytope or unbounded polyhedra:

sage: square = Polyhedron(vertices=[[1,0,0],[0,1,0],[1,1,0],[0,0,0]])
sage: square.is_inscribed()
Traceback (most recent call last):
...
NotImplementedError: this function is implemented for full-dimensional polyhedra only

sage: p = Polyhedron(vertices=[(0,0)],rays=[(1,0),(0,1)])
sage: p.is_inscribed()
Traceback (most recent call last):
...
NotImplementedError: this function is not implemented for unbounded polyhedra
>>> from sage.all import *
>>> square = Polyhedron(vertices=[[Integer(1),Integer(0),Integer(0)],[Integer(0),Integer(1),Integer(0)],[Integer(1),Integer(1),Integer(0)],[Integer(0),Integer(0),Integer(0)]])
>>> square.is_inscribed()
Traceback (most recent call last):
...
NotImplementedError: this function is implemented for full-dimensional polyhedra only

>>> p = Polyhedron(vertices=[(Integer(0),Integer(0))],rays=[(Integer(1),Integer(0)),(Integer(0),Integer(1))])
>>> p.is_inscribed()
Traceback (most recent call last):
...
NotImplementedError: this function is not implemented for unbounded polyhedra
square = Polyhedron(vertices=[[1,0,0],[0,1,0],[1,1,0],[0,0,0]])
square.is_inscribed()
p = Polyhedron(vertices=[(0,0)],rays=[(1,0),(0,1)])
p.is_inscribed()
is_minkowski_summand(Y)[source]

Test whether Y is a Minkowski summand.

See minkowski_sum().

OUTPUT: boolean; whether there exists another polyhedron Z such that self can be written as YZ

EXAMPLES:

sage: A = polytopes.hypercube(2)
sage: B = Polyhedron(vertices=[(0,1), (1/2,1)])
sage: C = Polyhedron(vertices=[(1,1)])
sage: A.is_minkowski_summand(B)
True
sage: A.is_minkowski_summand(C)
True
sage: B.is_minkowski_summand(C)
True
sage: B.is_minkowski_summand(A)
False
sage: C.is_minkowski_summand(A)
False
sage: C.is_minkowski_summand(B)
False
>>> from sage.all import *
>>> A = polytopes.hypercube(Integer(2))
>>> B = Polyhedron(vertices=[(Integer(0),Integer(1)), (Integer(1)/Integer(2),Integer(1))])
>>> C = Polyhedron(vertices=[(Integer(1),Integer(1))])
>>> A.is_minkowski_summand(B)
True
>>> A.is_minkowski_summand(C)
True
>>> B.is_minkowski_summand(C)
True
>>> B.is_minkowski_summand(A)
False
>>> C.is_minkowski_summand(A)
False
>>> C.is_minkowski_summand(B)
False
A = polytopes.hypercube(2)
B = Polyhedron(vertices=[(0,1), (1/2,1)])
C = Polyhedron(vertices=[(1,1)])
A.is_minkowski_summand(B)
A.is_minkowski_summand(C)
B.is_minkowski_summand(C)
B.is_minkowski_summand(A)
C.is_minkowski_summand(A)
C.is_minkowski_summand(B)
normal_fan(direction='inner')[source]

Return the normal fan of a compact full-dimensional rational polyhedron.

This returns the inner normal fan of self. For the outer normal fan, use direction='outer'.

INPUT:

  • direction – either 'inner' (default) or 'outer'; if set to 'inner', use the inner normal vectors to span the cones of the fan, if set to 'outer', use the outer normal vectors.

OUTPUT:

A complete fan of the ambient space as a RationalPolyhedralFan.

See also

face_fan().

EXAMPLES:

sage: S = Polyhedron(vertices=[[0, 0], [1, 0], [0, 1]])
sage: S.normal_fan()
Rational polyhedral fan in 2-d lattice N

sage: C = polytopes.hypercube(4)
sage: NF = C.normal_fan(); NF
Rational polyhedral fan in 4-d lattice N
>>> from sage.all import *
>>> S = Polyhedron(vertices=[[Integer(0), Integer(0)], [Integer(1), Integer(0)], [Integer(0), Integer(1)]])
>>> S.normal_fan()
Rational polyhedral fan in 2-d lattice N

>>> C = polytopes.hypercube(Integer(4))
>>> NF = C.normal_fan(); NF
Rational polyhedral fan in 4-d lattice N
S = Polyhedron(vertices=[[0, 0], [1, 0], [0, 1]])
S.normal_fan()
C = polytopes.hypercube(4)
NF = C.normal_fan(); NF

Currently, it is only possible to get the normal fan of a bounded rational polytope:

sage: P = Polyhedron(rays=[[1, 0], [0, 1]])
sage: P.normal_fan()
Traceback (most recent call last):
...
NotImplementedError: the normal fan is only supported for polytopes (compact polyhedra).

sage: Q = Polyhedron(vertices=[[1, 0, 0], [0, 1, 0], [0, 0, 1]])
sage: Q.normal_fan()
Traceback (most recent call last):
...
ValueError: the normal fan is only defined for full-dimensional polytopes

sage: R = Polyhedron(vertices=[[0, 0],                                      # needs sage.rings.number_field sage.symbolic
....:                          [AA(sqrt(2)), 0],
....:                          [0, AA(sqrt(2))]])
sage: R.normal_fan()                                                        # needs sage.rings.number_field sage.symbolic
Traceback (most recent call last):
...
NotImplementedError: normal fan handles only polytopes over the rationals

sage: P = Polyhedron(vertices=[[0,0], [2,0], [0,2], [2,1], [1,2]])
sage: P.normal_fan(direction=None)
Traceback (most recent call last):
...
TypeError: the direction should be 'inner' or 'outer'

sage: inner_nf = P.normal_fan()
sage: inner_nf.rays()
N( 1,  0),
N( 0, -1),
N( 0,  1),
N(-1,  0),
N(-1, -1)
in 2-d lattice N

sage: outer_nf = P.normal_fan(direction='outer')
sage: outer_nf.rays()
N( 1,  0),
N( 1,  1),
N( 0,  1),
N(-1,  0),
N( 0, -1)
in 2-d lattice N
>>> from sage.all import *
>>> P = Polyhedron(rays=[[Integer(1), Integer(0)], [Integer(0), Integer(1)]])
>>> P.normal_fan()
Traceback (most recent call last):
...
NotImplementedError: the normal fan is only supported for polytopes (compact polyhedra).

>>> Q = Polyhedron(vertices=[[Integer(1), Integer(0), Integer(0)], [Integer(0), Integer(1), Integer(0)], [Integer(0), Integer(0), Integer(1)]])
>>> Q.normal_fan()
Traceback (most recent call last):
...
ValueError: the normal fan is only defined for full-dimensional polytopes

>>> R = Polyhedron(vertices=[[Integer(0), Integer(0)],                                      # needs sage.rings.number_field sage.symbolic
...                          [AA(sqrt(Integer(2))), Integer(0)],
...                          [Integer(0), AA(sqrt(Integer(2)))]])
>>> R.normal_fan()                                                        # needs sage.rings.number_field sage.symbolic
Traceback (most recent call last):
...
NotImplementedError: normal fan handles only polytopes over the rationals

>>> P = Polyhedron(vertices=[[Integer(0),Integer(0)], [Integer(2),Integer(0)], [Integer(0),Integer(2)], [Integer(2),Integer(1)], [Integer(1),Integer(2)]])
>>> P.normal_fan(direction=None)
Traceback (most recent call last):
...
TypeError: the direction should be 'inner' or 'outer'

>>> inner_nf = P.normal_fan()
>>> inner_nf.rays()
N( 1,  0),
N( 0, -1),
N( 0,  1),
N(-1,  0),
N(-1, -1)
in 2-d lattice N

>>> outer_nf = P.normal_fan(direction='outer')
>>> outer_nf.rays()
N( 1,  0),
N( 1,  1),
N( 0,  1),
N(-1,  0),
N( 0, -1)
in 2-d lattice N
P = Polyhedron(rays=[[1, 0], [0, 1]])
P.normal_fan()
Q = Polyhedron(vertices=[[1, 0, 0], [0, 1, 0], [0, 0, 1]])
Q.normal_fan()
R = Polyhedron(vertices=[[0, 0],                                      # needs sage.rings.number_field sage.symbolic
                         [AA(sqrt(2)), 0],
                         [0, AA(sqrt(2))]])
R.normal_fan()                                                        # needs sage.rings.number_field sage.symbolic
P = Polyhedron(vertices=[[0,0], [2,0], [0,2], [2,1], [1,2]])
P.normal_fan(direction=None)
inner_nf = P.normal_fan()
inner_nf.rays()
outer_nf = P.normal_fan(direction='outer')
outer_nf.rays()

REFERENCES:

For more information, see Chapter 7 of [Zie2007].

permutations_to_matrices(conj_class_reps, acting_group=None, additional_elts=None)[source]

Return a dictionary between different representations of elements in the acting_group, with group elements represented as permutations of the vertices of this polytope (keys) or matrices (values).

The dictionary has entries for the generators of the acting_group and the representatives of conjugacy classes in conj_class_reps. By default, the acting_group is the restricted_automorphism_group() of the polytope. Each element in additional_elts also becomes a key.

INPUT:

OUTPUT:

A dictionary between elements of the acting_group expressed as permutations (keys) and matrices (values).

EXAMPLES:

This example shows the dictionary between permutations and matrices for the generators of the restricted_automorphism_group of the ±1 2-dimensional square. The permutations are written in terms of the vertices of the square:

sage: # optional - pynormaliz, needs sage.groups
sage: square = Polyhedron(vertices=[[1,1], [-1,1],
....:                               [-1,-1], [1,-1]],
....:                     backend='normaliz')
sage: square.vertices()
(A vertex at (-1, -1),
 A vertex at (-1, 1),
 A vertex at (1, -1),
 A vertex at (1, 1))
sage: aut_square = square.restricted_automorphism_group(output='permutation')
sage: conj_reps = aut_square.conjugacy_classes_representatives()
sage: gens_dict = square.permutations_to_matrices(conj_reps)
sage: rotation_180 = aut_square([(0,3),(1,2)])
sage: rotation_180, gens_dict[rotation_180]
(
            [-1  0  0]
            [ 0 -1  0]
(0,3)(1,2), [ 0  0  1]
)
>>> from sage.all import *
>>> # optional - pynormaliz, needs sage.groups
>>> square = Polyhedron(vertices=[[Integer(1),Integer(1)], [-Integer(1),Integer(1)],
...                               [-Integer(1),-Integer(1)], [Integer(1),-Integer(1)]],
...                     backend='normaliz')
>>> square.vertices()
(A vertex at (-1, -1),
 A vertex at (-1, 1),
 A vertex at (1, -1),
 A vertex at (1, 1))
>>> aut_square = square.restricted_automorphism_group(output='permutation')
>>> conj_reps = aut_square.conjugacy_classes_representatives()
>>> gens_dict = square.permutations_to_matrices(conj_reps)
>>> rotation_180 = aut_square([(Integer(0),Integer(3)),(Integer(1),Integer(2))])
>>> rotation_180, gens_dict[rotation_180]
(
            [-1  0  0]
            [ 0 -1  0]
(0,3)(1,2), [ 0  0  1]
)
# optional - pynormaliz, needs sage.groups
square = Polyhedron(vertices=[[1,1], [-1,1],
                              [-1,-1], [1,-1]],
                    backend='normaliz')
square.vertices()
aut_square = square.restricted_automorphism_group(output='permutation')
conj_reps = aut_square.conjugacy_classes_representatives()
gens_dict = square.permutations_to_matrices(conj_reps)
rotation_180 = aut_square([(0,3),(1,2)])
rotation_180, gens_dict[rotation_180]

This example tests the functionality for additional elements:

sage: # needs sage.groups sage.rings.real_mpfr
sage: C = polytopes.cross_polytope(2)
sage: G = C.restricted_automorphism_group(output='permutation')
sage: conj_reps = G.conjugacy_classes_representatives()
sage: add_elt = G([(0, 2, 3, 1)])
sage: dict = C.permutations_to_matrices(conj_reps,
....:                                   additional_elts=[add_elt])
sage: dict[add_elt]
 [ 0  1  0]
 [-1  0  0]
 [ 0  0  1]
>>> from sage.all import *
>>> # needs sage.groups sage.rings.real_mpfr
>>> C = polytopes.cross_polytope(Integer(2))
>>> G = C.restricted_automorphism_group(output='permutation')
>>> conj_reps = G.conjugacy_classes_representatives()
>>> add_elt = G([(Integer(0), Integer(2), Integer(3), Integer(1))])
>>> dict = C.permutations_to_matrices(conj_reps,
...                                   additional_elts=[add_elt])
>>> dict[add_elt]
 [ 0  1  0]
 [-1  0  0]
 [ 0  0  1]
# needs sage.groups sage.rings.real_mpfr
C = polytopes.cross_polytope(2)
G = C.restricted_automorphism_group(output='permutation')
conj_reps = G.conjugacy_classes_representatives()
add_elt = G([(0, 2, 3, 1)])
dict = C.permutations_to_matrices(conj_reps,
                                  additional_elts=[add_elt])
dict[add_elt]
radius()[source]

Return the maximal distance from the center to a vertex. All rays and lines are ignored.

OUTPUT:

The radius for a rational polyhedron is, in general, not rational. use radius_square() if you need a rational distance measure.

EXAMPLES:

sage: p = polytopes.hypercube(4)
sage: p.radius()
2
>>> from sage.all import *
>>> p = polytopes.hypercube(Integer(4))
>>> p.radius()
2
p = polytopes.hypercube(4)
p.radius()
radius_square()[source]

Return the square of the maximal distance from the center() to a vertex. All rays and lines are ignored.

OUTPUT:

The square of the radius, which is in base_ring().

EXAMPLES:

sage: p = polytopes.permutahedron(4, project = False)
sage: p.radius_square()
5
>>> from sage.all import *
>>> p = polytopes.permutahedron(Integer(4), project = False)
>>> p.radius_square()
5
p = polytopes.permutahedron(4, project = False)
p.radius_square()
to_linear_program(solver=None, return_variable=False, base_ring=None)[source]

Return a linear optimization problem over the polyhedron in the form of a MixedIntegerLinearProgram.

INPUT:

  • solver – select a solver (MIP backend). See the documentation of for MixedIntegerLinearProgram. Set to None by default.

  • return_variable – boolean (default: False); if True, return a tuple (p, x), where p is the MixedIntegerLinearProgram object and x is the vector-valued MIP variable in this problem, indexed from 0. If False, only return p.

  • base_ring – select a field over which the linear program should be set up. Use RDF to request a fast inexact (floating point) solver even if self is exact.

Note that the MixedIntegerLinearProgram object will have the null function as an objective to be maximized.

See also

polyhedron() – return the polyhedron associated with a MixedIntegerLinearProgram object.

EXAMPLES:

Exact rational linear program:

sage: p = polytopes.cube()
sage: p.to_linear_program()
Linear Program (no objective, 3 variables, 6 constraints)
sage: lp, x = p.to_linear_program(return_variable=True)
sage: lp.set_objective(2*x[0] + 1*x[1] + 39*x[2])
sage: lp.solve()
42
sage: lp.get_values(x[0], x[1], x[2])
[1, 1, 1]
>>> from sage.all import *
>>> p = polytopes.cube()
>>> p.to_linear_program()
Linear Program (no objective, 3 variables, 6 constraints)
>>> lp, x = p.to_linear_program(return_variable=True)
>>> lp.set_objective(Integer(2)*x[Integer(0)] + Integer(1)*x[Integer(1)] + Integer(39)*x[Integer(2)])
>>> lp.solve()
42
>>> lp.get_values(x[Integer(0)], x[Integer(1)], x[Integer(2)])
[1, 1, 1]
p = polytopes.cube()
p.to_linear_program()
lp, x = p.to_linear_program(return_variable=True)
lp.set_objective(2*x[0] + 1*x[1] + 39*x[2])
lp.solve()
lp.get_values(x[0], x[1], x[2])

Floating-point linear program:

sage: lp, x = p.to_linear_program(return_variable=True, base_ring=RDF)
sage: lp.set_objective(2*x[0] + 1*x[1] + 39*x[2])
sage: lp.solve()
42.0
>>> from sage.all import *
>>> lp, x = p.to_linear_program(return_variable=True, base_ring=RDF)
>>> lp.set_objective(Integer(2)*x[Integer(0)] + Integer(1)*x[Integer(1)] + Integer(39)*x[Integer(2)])
>>> lp.solve()
42.0
lp, x = p.to_linear_program(return_variable=True, base_ring=RDF)
lp.set_objective(2*x[0] + 1*x[1] + 39*x[2])
lp.solve()

Irrational algebraic linear program over an embedded number field:

sage: # needs sage.groups sage.rings.number_field
sage: p = polytopes.icosahedron()
sage: lp, x = p.to_linear_program(return_variable=True)
sage: lp.set_objective(x[0] + x[1] + x[2])
sage: lp.solve()
1/4*sqrt5 + 3/4
>>> from sage.all import *
>>> # needs sage.groups sage.rings.number_field
>>> p = polytopes.icosahedron()
>>> lp, x = p.to_linear_program(return_variable=True)
>>> lp.set_objective(x[Integer(0)] + x[Integer(1)] + x[Integer(2)])
>>> lp.solve()
1/4*sqrt5 + 3/4
# needs sage.groups sage.rings.number_field
p = polytopes.icosahedron()
lp, x = p.to_linear_program(return_variable=True)
lp.set_objective(x[0] + x[1] + x[2])
lp.solve()

Same example with floating point:

sage: # needs sage.groups sage.rings.number_field
sage: lp, x = p.to_linear_program(return_variable=True, base_ring=RDF)
sage: lp.set_objective(x[0] + x[1] + x[2])
sage: lp.solve()                                               # tol 1e-5
1.3090169943749475
>>> from sage.all import *
>>> # needs sage.groups sage.rings.number_field
>>> lp, x = p.to_linear_program(return_variable=True, base_ring=RDF)
>>> lp.set_objective(x[Integer(0)] + x[Integer(1)] + x[Integer(2)])
>>> lp.solve()                                               # tol 1e-5
1.3090169943749475
# needs sage.groups sage.rings.number_field
lp, x = p.to_linear_program(return_variable=True, base_ring=RDF)
lp.set_objective(x[0] + x[1] + x[2])
lp.solve()                                               # tol 1e-5

Same example with a specific floating point solver:

sage: # needs sage.groups sage.rings.number_field
sage: lp, x = p.to_linear_program(return_variable=True, solver='GLPK')
sage: lp.set_objective(x[0] + x[1] + x[2])
sage: lp.solve()                                               # tol 1e-8
1.3090169943749475
>>> from sage.all import *
>>> # needs sage.groups sage.rings.number_field
>>> lp, x = p.to_linear_program(return_variable=True, solver='GLPK')
>>> lp.set_objective(x[Integer(0)] + x[Integer(1)] + x[Integer(2)])
>>> lp.solve()                                               # tol 1e-8
1.3090169943749475
# needs sage.groups sage.rings.number_field
lp, x = p.to_linear_program(return_variable=True, solver='GLPK')
lp.set_objective(x[0] + x[1] + x[2])
lp.solve()                                               # tol 1e-8

Irrational algebraic linear program over AA:

sage: # needs sage.groups sage.rings.number_field
sage: p = polytopes.icosahedron(base_ring=AA)
sage: lp, x = p.to_linear_program(return_variable=True)
sage: lp.set_objective(x[0] + x[1] + x[2])
sage: lp.solve()                    # long time
1.309016994374948?
>>> from sage.all import *
>>> # needs sage.groups sage.rings.number_field
>>> p = polytopes.icosahedron(base_ring=AA)
>>> lp, x = p.to_linear_program(return_variable=True)
>>> lp.set_objective(x[Integer(0)] + x[Integer(1)] + x[Integer(2)])
>>> lp.solve()                    # long time
1.309016994374948?
# needs sage.groups sage.rings.number_field
p = polytopes.icosahedron(base_ring=AA)
lp, x = p.to_linear_program(return_variable=True)
lp.set_objective(x[0] + x[1] + x[2])
lp.solve()                    # long time
sage.geometry.polyhedron.base.is_Polyhedron(X)[source]

Test whether X is a Polyhedron.

INPUT:

  • X – anything

OUTPUT: boolean

EXAMPLES:

sage: p = polytopes.hypercube(2)
sage: from sage.geometry.polyhedron.base import is_Polyhedron
sage: is_Polyhedron(p)
doctest:warning...
DeprecationWarning: is_Polyhedron is deprecated, use isinstance instead
See https://github.com/sagemath/sage/issues/34307 for details.
True
sage: is_Polyhedron(123456)
False
>>> from sage.all import *
>>> p = polytopes.hypercube(Integer(2))
>>> from sage.geometry.polyhedron.base import is_Polyhedron
>>> is_Polyhedron(p)
doctest:warning...
DeprecationWarning: is_Polyhedron is deprecated, use isinstance instead
See https://github.com/sagemath/sage/issues/34307 for details.
True
>>> is_Polyhedron(Integer(123456))
False
p = polytopes.hypercube(2)
from sage.geometry.polyhedron.base import is_Polyhedron
is_Polyhedron(p)
is_Polyhedron(123456)