Lattice and reflexive polytopes¶
This module provides tools for work with lattice and reflexive polytopes. A convex polytope is the convex hull of finitely many points in \(\RR^n\). The dimension \(n\) of a polytope is the smallest \(n\) such that the polytope can be embedded in \(\RR^n\).
A lattice polytope is a polytope whose vertices all have integer coordinates.
If \(L\) is a lattice polytope, the dual polytope of \(L\) is
A reflexive polytope is a lattice polytope, such that its polar is also a lattice polytope, i.e. it is bounded and has vertices with integer coordinates.
This Sage module uses Package for Analyzing Lattice Polytopes (PALP), which is a program written in C by Maximilian Kreuzer and Harald Skarke, which is freely available under the GNU license terms at http://hep.itp.tuwien.ac.at/~kreuzer/CY/. Moreover, PALP is included standard with Sage.
PALP is described in the paper Arxiv math.SC/0204356. Its distribution also contains the application nef.x, which was created by Erwin Riegler and computes nefpartitions and Hodge data for toric complete intersections.
ACKNOWLEDGMENT: polytope.py module written by William Stein was used as an example of organizing an interface between an external program and Sage. William Stein also helped Andrey Novoseltsev with debugging and tuning of this module.
Robert Bradshaw helped Andrey Novoseltsev to realize plot3d function.
Note
IMPORTANT: PALP requires some parameters to be determined during compilation time, i.e., the maximum dimension of polytopes, the maximum number of points, etc. These limitations may lead to errors during calls to different functions of these module. Currently, a ValueError exception will be raised if the output of poly.x or nef.x is empty or contains the exclamation mark. The error message will contain the exact command that caused an error, the description and vertices of the polytope, and the obtained output.
Data obtained from PALP and some other data is cached and most returned values are immutable. In particular, you cannot change the vertices of the polytope or their order after creation of the polytope.
If you are going to work with large sets of data, take a look at
all_*
functions in this module. They precompute different data
for sequences of polynomials with a few runs of external programs.
This can significantly affect the time of future computations. You
can also use dump/load, but not all data will be stored (currently
only faces and the number of their internal and boundary points are
stored, in addition to polytope vertices and its polar).
AUTHORS:
Andrey Novoseltsev (20070111): initial version
Andrey Novoseltsev (20070115):
all_*
functionsAndrey Novoseltsev (20080401): second version, including:
 dual nefpartitions and necessary convex_hull and minkowski_sum
 builtin sequences of 2 and 3dimensional reflexive polytopes
 plot3d, skeleton_show
Andrey Novoseltsev (20090826): dropped maximal dimension requirement
Andrey Novoseltsev (20101215): new version of nefpartitions
Andrey Novoseltsev (20130930): switch to PointCollection.
Maximilian Kreuzer and Harald Skarke: authors of PALP (which was also used to obtain the list of 3dimensional reflexive polytopes)
Erwin Riegler: the author of nef.x

sage.geometry.lattice_polytope.
LatticePolytope
(data, compute_vertices=True, n=0, lattice=None)¶ Construct a lattice polytope.
INPUT:
data
– points spanning the lattice polytope, specified as one of: a
point collection
(this is the preferred input and it is the quickest and the most memory efficient one);  an iterable of iterables (for example, a list of vectors) defining the point coordinates;
 a file with matrix data, opened for reading, or
 a filename of such a file, see
read_palp_matrix()
for the file format;
 a
compute_vertices
– boolean (default:True
). IfTrue
, theconvex hull of the given points will be computed for determining vertices. Otherwise, the given points must be vertices;
n
– an integer (default: 0) ifdata
is a name of a file,that contains data blocks for several polytopes, the
n
th block will be used;
lattice
– the ambient lattice of the polytope. If not given, a suitable lattice will be determined automatically, most likely thetoric lattice
\(M\) of the appropriate dimension.
OUTPUT:
EXAMPLES:
sage: points = [(1,0,0), (0,1,0), (0,0,1), (1,0,0), (0,1,0), (0,0,1)] sage: p = LatticePolytope(points) sage: p 3d reflexive polytope in 3d lattice M sage: p.vertices() M( 1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), M(1, 0, 0), M( 0, 1, 0), M( 0, 0, 1) in 3d lattice M
We draw a pretty picture of the polytope in 3dimensional space:
sage: p.plot3d().show()
Now we add an extra point, which is in the interior of the polytope...
sage: points.append((0,0,0)) sage: p = LatticePolytope(points) sage: p.nvertices() 6
You can suppress vertex computation for speed but this can lead to mistakes:
sage: p = LatticePolytope(points, compute_vertices=False) ... sage: p.nvertices() 7
Given points must be in the lattice:
sage: LatticePolytope([[1/2], [3/2]]) Traceback (most recent call last): ... ValueError: points [[1/2], [3/2]] are not in 1d lattice M!
But it is OK to create polytopes of nonmaximal dimension:
sage: p = LatticePolytope([(1,0,0), (0,1,0), (0,0,0), ....: (1,0,0), (0,1,0), (0,0,0), (0,0,0)]) sage: p 2d lattice polytope in 3d lattice M sage: p.vertices() M(1, 0, 0), M( 0, 1, 0), M( 1, 0, 0), M( 0, 1, 0) in 3d lattice M
An empty lattice polytope can be considered as well:
sage: p = LatticePolytope([], lattice=ToricLattice(3).dual()); p 1d lattice polytope in 3d lattice M sage: p.lattice_dim() 3 sage: p.npoints() 0 sage: p.nfacets() 0 sage: p.points() Empty collection in 3d lattice M sage: p.faces() ((1d lattice polytope in 3d lattice M,),)

class
sage.geometry.lattice_polytope.
LatticePolytopeClass
(points=None, compute_vertices=None, ambient=None, ambient_vertex_indices=None, ambient_facet_indices=None)¶ Bases:
sage.structure.sage_object.SageObject
,_abcoll.Hashable
Create a lattice polytope.
Warning
This class does not perform any checks of correctness of input nor does it convert input into the standard representation. Use
LatticePolytope()
to construct lattice polytopes.Lattice polytopes are immutable, but they cache most of the returned values.
INPUT:
The input can be either:
points
–PointCollection
;compute_vertices
– boolean.
or (these parameters must be given as keywords):
ambient
– ambient structure, this polytope must be a face ofambient
;ambient_vertex_indices
– increasing list or tuple of integers, indices of vertices ofambient
generating this polytope;ambient_facet_indices
– increasing list or tuple of integers, indices of facets ofambient
generating this polytope.
OUTPUT:
 lattice polytope.
Note
Every polytope has an ambient structure. If it was not specified, it is this polytope itself.

adjacent
()¶ Return faces adjacent to
self
in the ambient face lattice.Two distinct faces \(F_1\) and \(F_2\) of the same face lattice are adjacent if all of the following conditions hold:
 \(F_1\) and \(F_2\) have the same dimension \(d\);
 \(F_1\) and \(F_2\) share a facet of dimension \(d1\);
 \(F_1\) and \(F_2\) are facets of some face of dimension \(d+1\), unless \(d\) is the dimension of the ambient structure.
OUTPUT:
EXAMPLES:
sage: o = lattice_polytope.cross_polytope(3) sage: o.adjacent() () sage: face = o.faces(1)[0] sage: face.adjacent() (1d face of 3d reflexive polytope in 3d lattice M, 1d face of 3d reflexive polytope in 3d lattice M, 1d face of 3d reflexive polytope in 3d lattice M, 1d face of 3d reflexive polytope in 3d lattice M)

affine_transform
(a=1, b=0)¶ Return a*P+b, where P is this lattice polytope.
Note
 While
a
andb
may be rational, the final result must be a lattice polytope, i.e. all vertices must be integral.  If the transform (restricted to this polytope) is bijective, facial structure will be preserved, e.g. the first facet of the image will be spanned by the images of vertices which span the first facet of the original polytope.
INPUT:
a
 (default: 1) rational scalar or matrixb
 (default: 0) rational scalar or vector, scalars are interpreted as vectors with the same components
EXAMPLES:
sage: o = lattice_polytope.cross_polytope(2) sage: o.vertices() M( 1, 0), M( 0, 1), M(1, 0), M( 0, 1) in 2d lattice M sage: o.affine_transform(2).vertices() M( 2, 0), M( 0, 2), M(2, 0), M( 0, 2) in 2d lattice M sage: o.affine_transform(1,1).vertices() M(2, 1), M(1, 2), M(0, 1), M(1, 0) in 2d lattice M sage: o.affine_transform(b=1).vertices() M(2, 1), M(1, 2), M(0, 1), M(1, 0) in 2d lattice M sage: o.affine_transform(b=(1, 0)).vertices() M(2, 0), M(1, 1), M(0, 0), M(1, 1) in 2d lattice M sage: a = matrix(QQ, 2, [1/2, 0, 0, 3/2]) sage: o.polar().vertices() N( 1, 1), N( 1, 1), N(1, 1), N(1, 1) in 2d lattice N sage: o.polar().affine_transform(a, (1/2, 1/2)).vertices() M(1, 1), M(1, 2), M(0, 2), M(0, 1) in 2d lattice M
While you can use rational transformation, the result must be integer:
sage: o.affine_transform(a) Traceback (most recent call last): ... ValueError: points [(1/2, 0), (0, 3/2), (1/2, 0), (0, 3/2)] are not in 2d lattice M!
 While

ambient
()¶ Return the ambient structure of
self
.OUTPUT:
 lattice polytope containing
self
as a face.
EXAMPLES:
sage: o = lattice_polytope.cross_polytope(3) sage: o.ambient() 3d reflexive polytope in 3d lattice M sage: o.ambient() is o True sage: face = o.faces(1)[0] sage: face 1d face of 3d reflexive polytope in 3d lattice M sage: face.ambient() 3d reflexive polytope in 3d lattice M sage: face.ambient() is o True
 lattice polytope containing

ambient_facet_indices
()¶ Return indices of facets of the ambient polytope containing
self
.OUTPUT:
 increasing
tuple
of integers.
EXAMPLES:
The polytope itself is not contained in any of its facets:
sage: o = lattice_polytope.cross_polytope(3) sage: o.ambient_facet_indices() ()
But each of its other faces is contained in one or more facets:
sage: face = o.faces(1)[0] sage: face.ambient_facet_indices() (4, 5) sage: face.vertices() M(1, 0, 0), M(0, 1, 0) in 3d lattice M sage: o.facets()[face.ambient_facet_indices()[0]].vertices() M(1, 0, 0), M(0, 1, 0), M(0, 0, 1) in 3d lattice M
 increasing

ambient_ordered_point_indices
()¶ Return indices of points of the ambient polytope contained in this one.
OUTPUT:
tuple
of integers such that ambient points in this order are geometrically ordered, e.g. for an edge points will appear from one end point to the other.
EXAMPLES:
sage: cube = lattice_polytope.cross_polytope(3).polar() sage: face = cube.facets()[0] sage: face.ambient_ordered_point_indices() (5, 8, 4, 9, 10, 11, 6, 12, 7) sage: cube.points(face.ambient_ordered_point_indices()) N(1, 1, 1), N(1, 1, 0), N(1, 1, 1), N(1, 0, 1), N(1, 0, 0), N(1, 0, 1), N(1, 1, 1), N(1, 1, 0), N(1, 1, 1) in 3d lattice N

ambient_point_indices
()¶ Return indices of points of the ambient polytope contained in this one.
OUTPUT:
tuple
of integers, the order corresponds to the order of points of this polytope.
EXAMPLES:
sage: cube = lattice_polytope.cross_polytope(3).polar() sage: face = cube.facets()[0] sage: face.ambient_point_indices() (4, 5, 6, 7, 8, 9, 10, 11, 12) sage: cube.points(face.ambient_point_indices()) == face.points() True

ambient_vertex_indices
()¶ Return indices of vertices of the ambient structure generating
self
.OUTPUT:
 increasing
tuple
of integers.
EXAMPLES:
sage: o = lattice_polytope.cross_polytope(3) sage: o.ambient_vertex_indices() (0, 1, 2, 3, 4, 5) sage: face = o.faces(1)[0] sage: face.ambient_vertex_indices() (0, 1)
 increasing

boundary_point_indices
()¶ Return indices of (relative) boundary lattice points of this polytope.
OUTPUT:
 increasing
tuple
of integers.
EXAMPLES:
All points but the origin are on the boundary of this square:
sage: square = lattice_polytope.cross_polytope(2).polar() sage: square.points() N( 1, 1), N( 1, 1), N(1, 1), N(1, 1), N(1, 0), N( 0, 1), N( 0, 0), N( 0, 1), N( 1, 0) in 2d lattice N sage: square.boundary_point_indices() (0, 1, 2, 3, 4, 5, 7, 8)
For an edge the boundary is formed by the end points:
sage: face = square.edges()[0] sage: face.points() N(1, 1), N(1, 1), N(1, 0) in 2d lattice N sage: face.boundary_point_indices() (0, 1)
 increasing

boundary_points
()¶ Return (relative) boundary lattice points of this polytope.
OUTPUT:
 a
point collection
.
EXAMPLES:
All points but the origin are on the boundary of this square:
sage: square = lattice_polytope.cross_polytope(2).polar() sage: square.boundary_points() N( 1, 1), N( 1, 1), N(1, 1), N(1, 1), N(1, 0), N( 0, 1), N( 0, 1), N( 1, 0) in 2d lattice N
For an edge the boundary is formed by the end points:
sage: face = square.edges()[0] sage: face.boundary_points() N(1, 1), N(1, 1) in 2d lattice N
 a

dim
()¶ Return the dimension of this polytope.
EXAMPLES: We create a 3dimensional octahedron and check its dimension:
sage: o = lattice_polytope.cross_polytope(3) sage: o.dim() 3
Now we create a 2dimensional diamond in a 3dimensional space:
sage: p = LatticePolytope([(1,0,0), (0,1,0), (1,0,0), (0,1,0)]) sage: p.dim() 2 sage: p.lattice_dim() 3

distances
(point=None)¶ Return the matrix of distances for this polytope or distances for the given point.
The matrix of distances m gives distances m[i,j] between the ith facet (which is also the ith vertex of the polar polytope in the reflexive case) and jth point of this polytope.
If point is specified, integral distances from the point to all facets of this polytope will be computed.
This function CAN be used for polytopes whose dimension is smaller than the dimension of the ambient space. In this case distances are computed in the affine subspace spanned by the polytope and if the point is given, it must be in this subspace.
EXAMPLES: The matrix of distances for a 3dimensional octahedron:
sage: o = lattice_polytope.cross_polytope(3) sage: o.distances() [2 0 0 0 2 2 1] [2 2 0 0 0 2 1] [2 2 2 0 0 0 1] [2 0 2 0 2 0 1] [0 0 2 2 2 0 1] [0 0 0 2 2 2 1] [0 2 0 2 0 2 1] [0 2 2 2 0 0 1]
Distances from facets to the point (1,2,3):
sage: o.distances([1,2,3]) (3, 1, 7, 3, 1, 5, 1, 5)
It is OK to use RATIONAL coordinates:
sage: o.distances([1,2,3/2]) (3/2, 5/2, 11/2, 3/2, 1/2, 7/2, 1/2, 7/2) sage: o.distances([1,2,sqrt(2)]) Traceback (most recent call last): ... TypeError: unable to convert sqrt(2) to an element of Rational Field
Now we create a nonspanning polytope:
sage: p = LatticePolytope([(1,0,0), (0,1,0), (1,0,0), (0,1,0)]) sage: p.distances() [2 2 0 0 1] [2 0 0 2 1] [0 0 2 2 1] [0 2 2 0 1] sage: p.distances((1/2, 3, 0)) (9/2, 3/2, 5/2, 7/2) sage: p.distances((1, 1, 1)) Traceback (most recent call last): ... ArithmeticError: vector is not in free module

dual
()¶ Return the dual face under face duality of polar reflexive polytopes.
This duality extends the correspondence between vertices and facets.
OUTPUT:
EXAMPLES:
sage: o = lattice_polytope.cross_polytope(4) sage: e = o.edges()[0]; e 1d face of 4d reflexive polytope in 4d lattice M sage: ed = e.dual(); ed 2d face of 4d reflexive polytope in 4d lattice N sage: ed.ambient() is e.ambient().polar() True sage: e.ambient_vertex_indices() == ed.ambient_facet_indices() True sage: e.ambient_facet_indices() == ed.ambient_vertex_indices() True

dual_lattice
()¶ Return the dual of the ambient lattice of
self
.OUTPUT:
 a lattice. If possible (that is, if
lattice()
has adual()
method), the dual lattice is returned. Otherwise, \(\ZZ^n\) is returned, where \(n\) is the dimension ofself
.
EXAMPLES:
sage: LatticePolytope([(1,0)]).dual_lattice() 2d lattice N sage: LatticePolytope([], lattice=ZZ^3).dual_lattice() Ambient free module of rank 3 over the principal ideal domain Integer Ring
 a lattice. If possible (that is, if

edges
()¶ Return edges (faces of dimension 1) of
self
.OUTPUT:
EXAMPLES:
sage: o = lattice_polytope.cross_polytope(3) sage: o.edges() (1d face of 3d reflexive polytope in 3d lattice M, ... 1d face of 3d reflexive polytope in 3d lattice M) sage: len(o.edges()) 12

edges_lp
(*args, **kwds)¶ Deprecated: Use
edges()
instead. See trac ticket #22122 for details.

face_lattice
()¶ Return the face lattice of
self
.This lattice will have the empty polytope as the bottom and this polytope itself as the top.
OUTPUT:
EXAMPLES:
Let’s take a look at the face lattice of a square:
sage: square = LatticePolytope([(0,0), (1,0), (1,1), (0,1)]) sage: L = square.face_lattice() sage: L Finite poset containing 10 elements with distinguished linear extension
To see all faces arranged by dimension, you can do this:
sage: for level in L.level_sets(): print(level) [1d face of 2d lattice polytope in 2d lattice M] [0d face of 2d lattice polytope in 2d lattice M, 0d face of 2d lattice polytope in 2d lattice M, 0d face of 2d lattice polytope in 2d lattice M, 0d face of 2d lattice polytope in 2d lattice M] [1d face of 2d lattice polytope in 2d lattice M, 1d face of 2d lattice polytope in 2d lattice M, 1d face of 2d lattice polytope in 2d lattice M, 1d face of 2d lattice polytope in 2d lattice M] [2d lattice polytope in 2d lattice M]
For a particular face you can look at its actual vertices...
sage: face = L.level_sets()[1][0] sage: face.vertices() M(0, 0) in 2d lattice M
... or you can see the index of the vertex of the original polytope that corresponds to the above one:
sage: face.ambient_vertex_indices() (0,) sage: square.vertex(0) M(0, 0)
An alternative to extracting faces from the face lattice is to use
faces()
method:sage: face is square.faces(dim=0)[0] True
The advantage of working with the face lattice directly is that you can (relatively easily) get faces that are related to the given one:
sage: face = L.level_sets()[1][0] sage: D = L.hasse_diagram() sage: D.neighbors(face) [1d face of 2d lattice polytope in 2d lattice M, 1d face of 2d lattice polytope in 2d lattice M, 1d face of 2d lattice polytope in 2d lattice M]
However, you can achieve some of this functionality using
facets()
,facet_of()
, andadjacent()
methods:sage: face = square.faces(0)[0] sage: face 0d face of 2d lattice polytope in 2d lattice M sage: face.vertices() M(0, 0) in 2d lattice M sage: face.facets() (1d face of 2d lattice polytope in 2d lattice M,) sage: face.facet_of() (1d face of 2d lattice polytope in 2d lattice M, 1d face of 2d lattice polytope in 2d lattice M) sage: face.adjacent() (0d face of 2d lattice polytope in 2d lattice M, 0d face of 2d lattice polytope in 2d lattice M) sage: face.adjacent()[0].vertices() M(1, 0) in 2d lattice M
Note that if
p
is a face ofsuperp
, then the face lattice ofp
consists of (appropriate) faces ofsuperp
:sage: superp = LatticePolytope([(1,2,3,4), (5,6,7,8), ....: (1,2,4,8), (1,3,9,7)]) sage: superp.face_lattice() Finite poset containing 16 elements with distinguished linear extension sage: superp.face_lattice().top() 3d lattice polytope in 4d lattice M sage: p = superp.facets()[0] sage: p 2d face of 3d lattice polytope in 4d lattice M sage: p.face_lattice() Finite poset containing 8 elements with distinguished linear extension sage: p.face_lattice().bottom() 1d face of 3d lattice polytope in 4d lattice M sage: p.face_lattice().top() 2d face of 3d lattice polytope in 4d lattice M sage: p.face_lattice().top() is p True

faces
(dim=None, codim=None)¶ Return faces of
self
of specified (co)dimension.INPUT:
dim
– integer, dimension of the requested faces;codim
– integer, codimension of the requested faces.
Note
You can specify at most one parameter. If you don’t give any, then all faces will be returned.
OUTPUT:
 if either
dim
orcodim
is given, the output will be atuple
oflattice polytopes
;  if neither
dim
norcodim
is given, the output will be thetuple
of tuples as above, giving faces of all existing dimensions. If you care about inclusion relations between faces, consider usingface_lattice()
oradjacent()
,facet_of()
, andfacets()
.
EXAMPLES:
Let’s take a look at the faces of a square:
sage: square = LatticePolytope([(0,0), (1,0), (1,1), (0,1)]) sage: square.faces() ((1d face of 2d lattice polytope in 2d lattice M,), (0d face of 2d lattice polytope in 2d lattice M, 0d face of 2d lattice polytope in 2d lattice M, 0d face of 2d lattice polytope in 2d lattice M, 0d face of 2d lattice polytope in 2d lattice M), (1d face of 2d lattice polytope in 2d lattice M, 1d face of 2d lattice polytope in 2d lattice M, 1d face of 2d lattice polytope in 2d lattice M, 1d face of 2d lattice polytope in 2d lattice M), (2d lattice polytope in 2d lattice M,))
Its faces of dimension one (i.e., edges):
sage: square.faces(dim=1) (1d face of 2d lattice polytope in 2d lattice M, 1d face of 2d lattice polytope in 2d lattice M, 1d face of 2d lattice polytope in 2d lattice M, 1d face of 2d lattice polytope in 2d lattice M)
Its faces of codimension one are the same (also edges):
sage: square.faces(codim=1) is square.faces(dim=1) True
Let’s pick a particular face:
sage: face = square.faces(dim=1)[0]
Now you can look at the actual vertices of this face...
sage: face.vertices() M(0, 0), M(0, 1) in 2d lattice M
... or you can see indices of the vertices of the original polytope that correspond to the above ones:
sage: face.ambient_vertex_indices() (0, 3) sage: square.vertices(face.ambient_vertex_indices()) M(0, 0), M(0, 1) in 2d lattice M

faces_lp
(*args, **kwds)¶ Deprecated: Use
faces()
instead. See trac ticket #22122 for details.

facet_constant
(i)¶ Return the constant in the
i
th facet inequality of this polytope.The ith facet inequality is given by self.facet_normal(i) * X + self.facet_constant(i) >= 0.
INPUT:
i
 integer, the index of the facet
OUTPUT:
 integer – the constant in the
i
th facet inequality.
EXAMPLES:
Let’s take a look at facets of the octahedron and some polytopes inside it:
sage: o = lattice_polytope.cross_polytope(3) sage: o.vertices() M( 1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), M(1, 0, 0), M( 0, 1, 0), M( 0, 0, 1) in 3d lattice M sage: o.facet_normal(0) N(1, 1, 1) sage: o.facet_constant(0) 1 sage: p = LatticePolytope(o.vertices()(1,2,3,4,5)) sage: p.vertices() M( 0, 1, 0), M( 0, 0, 1), M(1, 0, 0), M( 0, 1, 0), M( 0, 0, 1) in 3d lattice M sage: p.facet_normal(0) N(1, 0, 0) sage: p.facet_constant(0) 0 sage: p = LatticePolytope(o.vertices()(1,2,4,5)) sage: p.vertices() M(0, 1, 0), M(0, 0, 1), M(0, 1, 0), M(0, 0, 1) in 3d lattice M sage: p.facet_normal(0) N(0, 1, 1) sage: p.facet_constant(0) 1
This is a 2dimensional lattice polytope in a 4dimensional space:
sage: p = LatticePolytope([(1,1,1,3), (1,1,1,3), (0,0,0,0)]) sage: p 2d lattice polytope in 4d lattice M sage: p.vertices() M( 1, 1, 1, 3), M(1, 1, 1, 3), M( 0, 0, 0, 0) in 4d lattice M sage: fns = [p.facet_normal(i) for i in range(p.nfacets())] sage: fns [N(11, 1, 1, 3), N(0, 1, 1, 3), N(11, 1, 1, 3)] sage: fcs = [p.facet_constant(i) for i in range(p.nfacets())] sage: fcs [0, 11, 0]
Now we manually compute the distance matrix of this polytope. Since it is a triangle, each line (corresponding to a facet) should have two zeros (vertices of the corresponding facet) and one positive number (since our normals are inner):
sage: matrix([[fns[i] * p.vertex(j) + fcs[i] ....: for j in range(p.nvertices())] ....: for i in range(p.nfacets())]) [22 0 0] [ 0 0 11] [ 0 22 0]

facet_constants
()¶ Return facet constants of
self
.OUTPUT:
 an integer vector.
EXAMPLES:
For reflexive polytopes all constants are 1:
sage: o = lattice_polytope.cross_polytope(3) sage: o.vertices() M( 1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), M(1, 0, 0), M( 0, 1, 0), M( 0, 0, 1) in 3d lattice M sage: o.facet_constants() (1, 1, 1, 1, 1, 1, 1, 1)
Here is an example of a 3dimensional polytope in a 4dimensional space with 3 facets containing the origin:
sage: p = LatticePolytope([(0,0,0,0), (1,1,1,3), ....: (1,1,1,3), (1,1,1,3)]) sage: p.vertices() M( 0, 0, 0, 0), M( 1, 1, 1, 3), M( 1, 1, 1, 3), M(1, 1, 1, 3) in 4d lattice M sage: p.facet_constants() (0, 0, 10, 0)

facet_normal
(i)¶ Return the inner normal to the
i
th facet of this polytope.If this polytope is not fulldimensional, facet normals will be orthogonal to the integer kernel of the affine subspace spanned by this polytope.
INPUT:
i
– integer, the index of the facet
OUTPUT:
 vectors – the inner normal of the
i
th facet
EXAMPLES:
Let’s take a look at facets of the octahedron and some polytopes inside it:
sage: o = lattice_polytope.cross_polytope(3) sage: o.vertices() M( 1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), M(1, 0, 0), M( 0, 1, 0), M( 0, 0, 1) in 3d lattice M sage: o.facet_normal(0) N(1, 1, 1) sage: o.facet_constant(0) 1 sage: p = LatticePolytope(o.vertices()(1,2,3,4,5)) sage: p.vertices() M( 0, 1, 0), M( 0, 0, 1), M(1, 0, 0), M( 0, 1, 0), M( 0, 0, 1) in 3d lattice M sage: p.facet_normal(0) N(1, 0, 0) sage: p.facet_constant(0) 0 sage: p = LatticePolytope(o.vertices()(1,2,4,5)) sage: p.vertices() M(0, 1, 0), M(0, 0, 1), M(0, 1, 0), M(0, 0, 1) in 3d lattice M sage: p.facet_normal(0) N(0, 1, 1) sage: p.facet_constant(0) 1
Here is an example of a 3dimensional polytope in a 4dimensional space:
sage: p = LatticePolytope([(0,0,0,0), (1,1,1,3), ....: (1,1,1,3), (1,1,1,3)]) sage: p.vertices() M( 0, 0, 0, 0), M( 1, 1, 1, 3), M( 1, 1, 1, 3), M(1, 1, 1, 3) in 4d lattice M sage: ker = p.vertices().column_matrix().integer_kernel().matrix() sage: ker [ 0 0 3 1] sage: ker * p.facet_normals() [0 0 0 0]
Now we manually compute the distance matrix of this polytope. Since it is a simplex, each line (corresponding to a facet) should consist of zeros (indicating generating vertices of the corresponding facet) and a single positive number (since our normals are inner):
sage: matrix([[p.facet_normal(i) * p.vertex(j) ....: + p.facet_constant(i) ....: for j in range(p.nvertices())] ....: for i in range(p.nfacets())]) [ 0 20 0 0] [ 0 0 20 0] [10 0 0 0] [ 0 0 0 20]

facet_normals
()¶ Return inner normals to the facets of
self
.OUTPUT:
 a
point collection
in thedual_lattice()
ofself
.
EXAMPLES:
Normals to facets of an octahedron are vertices of a cube:
sage: o = lattice_polytope.cross_polytope(3) sage: o.vertices() M( 1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), M(1, 0, 0), M( 0, 1, 0), M( 0, 0, 1) in 3d lattice M sage: o.facet_normals() N( 1, 1, 1), N( 1, 1, 1), N( 1, 1, 1), N( 1, 1, 1), N(1, 1, 1), N(1, 1, 1), N(1, 1, 1), N(1, 1, 1) in 3d lattice N
Here is an example of a 3dimensional polytope in a 4dimensional space:
sage: p = LatticePolytope([(0,0,0,0), (1,1,1,3), ....: (1,1,1,3), (1,1,1,3)]) sage: p.vertices() M( 0, 0, 0, 0), M( 1, 1, 1, 3), M( 1, 1, 1, 3), M(1, 1, 1, 3) in 4d lattice M sage: p.facet_normals() N( 0, 10, 1, 3), N( 10, 10, 0, 0), N( 0, 0, 1, 3), N(10, 0, 1, 3) in 4d lattice N
 a

facet_of
()¶ Return elements of the ambient face lattice having
self
as a facet.OUTPUT:
EXAMPLES:
sage: square = LatticePolytope([(0,0), (1,0), (1,1), (0,1)]) sage: square.facet_of() () sage: face = square.faces(0)[0] sage: len(face.facet_of()) 2 sage: face.facet_of()[1] 1d face of 2d lattice polytope in 2d lattice M

facets
()¶ Return facets (faces of codimension 1) of
self
.OUTPUT:
EXAMPLES:
sage: o = lattice_polytope.cross_polytope(3) sage: o.facets() (2d face of 3d reflexive polytope in 3d lattice M, ... 2d face of 3d reflexive polytope in 3d lattice M) sage: len(o.facets()) 8

facets_lp
(*args, **kwds)¶ Deprecated: Use
facets()
instead. See trac ticket #22122 for details.

index
()¶ Return the index of this polytope in the internal database of 2 or 3dimensional reflexive polytopes. Databases are stored in the directory of the package.
Note
The first call to this function for each dimension can take a few seconds while the dictionary of all polytopes is constructed, but after that it is cached and fast.
Return type: integer EXAMPLES: We check what is the index of the “diamond” in the database:
sage: d = lattice_polytope.cross_polytope(2) sage: d.index() 3
Note that polytopes with the same index are not necessarily the same:
sage: d.vertices() M( 1, 0), M( 0, 1), M(1, 0), M( 0, 1) in 2d lattice M sage: lattice_polytope.ReflexivePolytope(2,3).vertices() M( 1, 0), M( 0, 1), M( 0, 1), M(1, 0) in 2d lattice M
But they are in the same \(GL(Z^n)\) orbit and have the same normal form:
sage: d.normal_form() M( 1, 0), M( 0, 1), M( 0, 1), M(1, 0) in 2d lattice M sage: lattice_polytope.ReflexivePolytope(2,3).normal_form() M( 1, 0), M( 0, 1), M( 0, 1), M(1, 0) in 2d lattice M

interior_point_indices
()¶ Return indices of (relative) interior lattice points of this polytope.
OUTPUT:
 increasing
tuple
of integers.
EXAMPLES:
The origin is the only interior point of this square:
sage: square = lattice_polytope.cross_polytope(2).polar() sage: square.points() N( 1, 1), N( 1, 1), N(1, 1), N(1, 1), N(1, 0), N( 0, 1), N( 0, 0), N( 0, 1), N( 1, 0) in 2d lattice N sage: square.interior_point_indices() (6,)
Its edges also have a single interior point each:
sage: face = square.edges()[0] sage: face.points() N(1, 1), N(1, 1), N(1, 0) in 2d lattice N sage: face.interior_point_indices() (2,)
 increasing

interior_points
()¶ Return (relative) boundary lattice points of this polytope.
OUTPUT:
 a
point collection
.
EXAMPLES:
The origin is the only interior point of this square:
sage: square = lattice_polytope.cross_polytope(2).polar() sage: square.interior_points() N(0, 0) in 2d lattice N
Its edges also have a single interior point each:
sage: face = square.edges()[0] sage: face.interior_points() N(1, 0) in 2d lattice N
 a

is_reflexive
()¶ Return True if this polytope is reflexive.
EXAMPLES: The 3dimensional octahedron is reflexive (and 4319 other 3polytopes):
sage: o = lattice_polytope.cross_polytope(3) sage: o.is_reflexive() True
But not all polytopes are reflexive:
sage: p = LatticePolytope([(1,0,0), (0,1,17), (1,0,0), (0,1,0)]) sage: p.is_reflexive() False
Only fulldimensional polytopes can be reflexive (otherwise the polar set is not a polytope at all, since it is unbounded):
sage: p = LatticePolytope([(1,0,0), (0,1,0), (1,0,0), (0,1,0)]) sage: p.is_reflexive() False

lattice
()¶ Return the ambient lattice of
self
.OUTPUT:
 a lattice.
EXAMPLES:
sage: lattice_polytope.cross_polytope(3).lattice() 3d lattice M

lattice_dim
()¶ Return the dimension of the ambient lattice of
self
.OUTPUT:
 integer.
EXAMPLES:
sage: p = LatticePolytope([(1,0)]) sage: p.lattice_dim() 2 sage: p.dim() 0

linearly_independent_vertices
()¶ Return a maximal set of linearly independent vertices.
OUTPUT:
A tuple of vertex indices.
EXAMPLES:
sage: L = LatticePolytope([[0, 0], [1, 1], [1, 1]]) sage: L.linearly_independent_vertices() (1, 2) sage: L = LatticePolytope([[0, 0, 0]]) sage: L.linearly_independent_vertices() () sage: L = LatticePolytope([[0, 1, 0]]) sage: L.linearly_independent_vertices() (0,)

nef_partitions
(keep_symmetric=False, keep_products=True, keep_projections=True, hodge_numbers=False)¶ Return 2part nefpartitions of
self
.INPUT:
keep_symmetric
– (default:False
) ifTrue
, “s” option will be passed tonef.x
in order to keep symmetric partitions, i.e. partitions related by lattice automorphisms preservingself
;keep_products
– (default:True
) ifTrue
, “D” option will be passed tonef.x
in order to keep product partitions, with corresponding complete intersections being direct products;keep_projections
– (default:True
) ifTrue
, “P” option will be passed tonef.x
in order to keep projection partitions, i.e. partitions with one of the parts consisting of a single vertex;hodge_numbers
– (default:False
) ifFalse
, “p” option will be passed tonef.x
in order to skip Hodge numbers computation, which takes a lot of time.
OUTPUT:
 a sequence of
nefpartitions
.
Type
NefPartition?
for definitions and notation.EXAMPLES:
Nefpartitions of the 4dimensional crosspolytope:
sage: p = lattice_polytope.cross_polytope(4) sage: p.nef_partitions() [ Nefpartition {0, 1, 4, 5} U {2, 3, 6, 7} (direct product), Nefpartition {0, 1, 2, 4} U {3, 5, 6, 7}, Nefpartition {0, 1, 2, 4, 5} U {3, 6, 7}, Nefpartition {0, 1, 2, 4, 5, 6} U {3, 7} (direct product), Nefpartition {0, 1, 2, 3} U {4, 5, 6, 7}, Nefpartition {0, 1, 2, 3, 4} U {5, 6, 7}, Nefpartition {0, 1, 2, 3, 4, 5} U {6, 7}, Nefpartition {0, 1, 2, 3, 4, 5, 6} U {7} (projection) ]
Now we omit projections:
sage: p.nef_partitions(keep_projections=False) [ Nefpartition {0, 1, 4, 5} U {2, 3, 6, 7} (direct product), Nefpartition {0, 1, 2, 4} U {3, 5, 6, 7}, Nefpartition {0, 1, 2, 4, 5} U {3, 6, 7}, Nefpartition {0, 1, 2, 4, 5, 6} U {3, 7} (direct product), Nefpartition {0, 1, 2, 3} U {4, 5, 6, 7}, Nefpartition {0, 1, 2, 3, 4} U {5, 6, 7}, Nefpartition {0, 1, 2, 3, 4, 5} U {6, 7} ]
Currently Hodge numbers cannot be computed for a given nefpartition:
sage: p.nef_partitions()[1].hodge_numbers() Traceback (most recent call last): ... NotImplementedError: use nef_partitions(hodge_numbers=True)!
But they can be obtained from
nef.x
for all nefpartitions at once. Partitions will be exactly the same:sage: p.nef_partitions(hodge_numbers=True) # long time (2s on sage.math, 2011) [ Nefpartition {0, 1, 4, 5} U {2, 3, 6, 7} (direct product), Nefpartition {0, 1, 2, 4} U {3, 5, 6, 7}, Nefpartition {0, 1, 2, 4, 5} U {3, 6, 7}, Nefpartition {0, 1, 2, 4, 5, 6} U {3, 7} (direct product), Nefpartition {0, 1, 2, 3} U {4, 5, 6, 7}, Nefpartition {0, 1, 2, 3, 4} U {5, 6, 7}, Nefpartition {0, 1, 2, 3, 4, 5} U {6, 7}, Nefpartition {0, 1, 2, 3, 4, 5, 6} U {7} (projection) ]
Now it is possible to get Hodge numbers:
sage: p.nef_partitions(hodge_numbers=True)[1].hodge_numbers() (20,)
Since nefpartitions are cached, their Hodge numbers are accessible after the first request, even if you do not specify
hodge_numbers=True
anymore:sage: p.nef_partitions()[1].hodge_numbers() (20,)
We illustrate removal of symmetric partitions on a diamond:
sage: p = lattice_polytope.cross_polytope(2) sage: p.nef_partitions() [ Nefpartition {0, 2} U {1, 3} (direct product), Nefpartition {0, 1} U {2, 3}, Nefpartition {0, 1, 2} U {3} (projection) ] sage: p.nef_partitions(keep_symmetric=True) [ Nefpartition {0, 1, 3} U {2} (projection), Nefpartition {0, 2, 3} U {1} (projection), Nefpartition {0, 3} U {1, 2}, Nefpartition {1, 2, 3} U {0} (projection), Nefpartition {1, 3} U {0, 2} (direct product), Nefpartition {2, 3} U {0, 1}, Nefpartition {0, 1, 2} U {3} (projection) ]
Nefpartitions can be computed only for reflexive polytopes:
sage: p = LatticePolytope([(1,0,0), (0,1,0), (0,0,2), ....: (1,0,0), (0,1,0), (0,0,1)]) sage: p.nef_partitions() Traceback (most recent call last): ... ValueError: The given polytope is not reflexive! Polytope: 3d lattice polytope in 3d lattice M

nef_x
(keys)¶ Run nef.x with given
keys
on vertices of this polytope.INPUT:
keys
 a string of options passed to nef.x. The key “f” is added automatically.
OUTPUT: the output of nef.x as a string.
EXAMPLES: This call is used internally for computing nefpartitions:
sage: o = lattice_polytope.cross_polytope(3) sage: s = o.nef_x("N V p") sage: s # output contains random time M:27 8 N:7 6 codim=2 #part=5 3 6 Vertices of P: 1 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 1 P:0 V:2 4 5 0sec 0cpu P:2 V:3 4 5 0sec 0cpu P:3 V:4 5 0sec 0cpu np=3 d:1 p:1 0sec 0cpu

nfacets
()¶ Return the number of facets of this polytope.
EXAMPLES: The number of facets of the 3dimensional octahedron:
sage: o = lattice_polytope.cross_polytope(3) sage: o.nfacets() 8
The number of facets of an interval is 2:
sage: LatticePolytope(([1],[2])).nfacets() 2
Now consider a 2dimensional diamond in a 3dimensional space:
sage: p = LatticePolytope([(1,0,0), (0,1,0), (1,0,0), (0,1,0)]) sage: p.nfacets() 4

normal_form
(algorithm='palp', permutation=False)¶ Return the normal form of vertices of
self
.Two fulldimensional lattice polytopes are in the same
GL(\mathbb{Z})
orbit if and only if their normal forms are the same. Normal form is not defined and thus cannot be used for polytopes whose dimension is smaller than the dimension of the ambient space.The original algorithm was presented in [KS1998] and implemented in PALP. A modified version of the PALP algorithm is discussed in [GK2013] and available here as “palp_modified”.
INPUT:
algorithm
– (default: “palp”) The algorithm which is used to compute the normal form. Options are: “palp” – Run external PALP code, usually the fastest option.
 “palp_native” – The original PALP algorithm implemented in sage. Currently considerably slower than PALP.
 “palp_modified” – A modified version of the PALP algorithm which determines the maximal vertexfacet pairing matrix first and then computes its automorphisms, while the PALP algorithm does both things concurrently.
permutation
– (default:False
) IfTrue
the permutation applied to vertices to obtain the normal form is returned as well. Note that the different algorithms may return different results that nevertheless lead to the same normal form.
OUTPUT:
 a
point collection
in thelattice()
ofself
or a tuple of it and a permutation.
EXAMPLES:
We compute the normal form of the “diamond”:
sage: d = LatticePolytope([(1,0), (0,1), (1,0), (0,1)]) sage: d.vertices() M( 1, 0), M( 0, 1), M(1, 0), M( 0, 1) in 2d lattice M sage: d.normal_form() M( 1, 0), M( 0, 1), M( 0, 1), M(1, 0) in 2d lattice M
The diamond is the 3rd polytope in the internal database:
sage: d.index() 3 sage: d 2d reflexive polytope #3 in 2d lattice M
You can get it in its normal form (in the default lattice) as
sage: lattice_polytope.ReflexivePolytope(2, 3).vertices() M( 1, 0), M( 0, 1), M( 0, 1), M(1, 0) in 2d lattice M
It is not possible to compute normal forms for polytopes which do not span the space:
sage: p = LatticePolytope([(1,0,0), (0,1,0), (1,0,0), (0,1,0)]) sage: p.normal_form() Traceback (most recent call last): ... ValueError: normal form is not defined for 2d lattice polytope in 3d lattice M
We can perform the same examples using other algorithms:
sage: o = lattice_polytope.cross_polytope(2) sage: o.normal_form(algorithm="palp_native") M( 1, 0), M( 0, 1), M( 0, 1), M(1, 0) in 2d lattice M sage: o = lattice_polytope.cross_polytope(2) sage: o.normal_form(algorithm="palp_modified") M( 1, 0), M( 0, 1), M( 0, 1), M(1, 0) in 2d lattice M

npoints
()¶ Return the number of lattice points of this polytope.
EXAMPLES: The number of lattice points of the 3dimensional octahedron and its polar cube:
sage: o = lattice_polytope.cross_polytope(3) sage: o.npoints() 7 sage: cube = o.polar() sage: cube.npoints() 27

nvertices
()¶ Return the number of vertices of this polytope.
EXAMPLES: The number of vertices of the 3dimensional octahedron and its polar cube:
sage: o = lattice_polytope.cross_polytope(3) sage: o.nvertices() 6 sage: cube = o.polar() sage: cube.nvertices() 8

origin
()¶ Return the index of the origin in the list of points of self.
OUTPUT:
 integer if the origin belongs to this polytope,
None
otherwise.
EXAMPLES:
sage: p = lattice_polytope.cross_polytope(2) sage: p.origin() 4 sage: p.point(p.origin()) M(0, 0) sage: p = LatticePolytope(([1],[2])) sage: p.points() M(1), M(2) in 1d lattice M sage: print(p.origin()) None
Now we make sure that the origin of nonfulldimensional polytopes can be identified correctly (trac ticket #10661):
sage: LatticePolytope([(1,0,0), (1,0,0)]).origin() 2
 integer if the origin belongs to this polytope,

parent
()¶ Return the set of all lattice polytopes.
EXAMPLES:
sage: o = lattice_polytope.cross_polytope(3) sage: o.parent() Set of all Lattice Polytopes

plot3d
(show_facets=True, facet_opacity=0.5, facet_color=(0, 1, 0), facet_colors=None, show_edges=True, edge_thickness=3, edge_color=(0.5, 0.5, 0.5), show_vertices=True, vertex_size=10, vertex_color=(1, 0, 0), show_points=True, point_size=10, point_color=(0, 0, 1), show_vindices=None, vindex_color=(0, 0, 0), vlabels=None, show_pindices=None, pindex_color=(0, 0, 0), index_shift=1.1)¶ Return a 3dplot of this polytope.
Polytopes with ambient dimension 1 and 2 will be plotted along xaxis or in xyplane respectively. Polytopes of dimension 3 and less with ambient dimension 4 and greater will be plotted in some basis of the spanned space.
By default, everything is shown with more or less pretty combination of size and color parameters.
INPUT: Most of the parameters are selfexplanatory:
show_facets
 (default:True)facet_opacity
 (default:0.5)facet_color
 (default:(0,1,0))facet_colors
 (default:None) if specified, must be a list of colors for each facet separately, used instead offacet_color
show_edges
 (default:True) whether to draw edges as linesedge_thickness
 (default:3)edge_color
 (default:(0.5,0.5,0.5))show_vertices
 (default:True) whether to draw vertices as ballsvertex_size
 (default:10)vertex_color
 (default:(1,0,0))show_points
 (default:True) whether to draw other poits as ballspoint_size
 (default:10)point_color
 (default:(0,0,1))show_vindices
 (default:same as show_vertices) whether to show indices of verticesvindex_color
 (default:(0,0,0)) color for vertex labelsvlabels
 (default:None) if specified, must be a list of labels for each vertex, default labels are vertex indiciesshow_pindices
 (default:same as show_points) whether to show indices of other pointspindex_color
 (default:(0,0,0)) color for point labelsindex_shift
 (default:1.1)) if 1, labels are placed exactly at the corresponding points. Otherwise the label position is computed as a multiple of the point position vector.
EXAMPLES: The default plot of a cube:
sage: c = lattice_polytope.cross_polytope(3).polar() sage: c.plot3d() Graphics3d Object
Plot without facets and points, shown without the frame:
sage: c.plot3d(show_facets=false,show_points=false).show(frame=False)
Plot with facets of different colors:
sage: c.plot3d(facet_colors=rainbow(c.nfacets(), 'rgbtuple')) Graphics3d Object
It is also possible to plot lower dimensional polytops in 3D (let’s also change labels of vertices):
sage: lattice_polytope.cross_polytope(2).plot3d(vlabels=["A", "B", "C", "D"]) Graphics3d Object

point
(i)¶ Return the ith point of this polytope, i.e. the ith column of the matrix returned by points().
EXAMPLES: First few points are actually vertices:
sage: o = lattice_polytope.cross_polytope(3) sage: o.vertices() M( 1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), M(1, 0, 0), M( 0, 1, 0), M( 0, 0, 1) in 3d lattice M sage: o.point(1) M(0, 1, 0)
The only other point in the octahedron is the origin:
sage: o.point(6) M(0, 0, 0) sage: o.points() M( 1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), M(1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), M( 0, 0, 0) in 3d lattice M

points
(*args, **kwds)¶ Return all lattice points of
self
.INPUT:
 any arguments given will be passed on to the returned object.
OUTPUT:
 a
point collection
.
EXAMPLES:
Lattice points of the octahedron and its polar cube:
sage: o = lattice_polytope.cross_polytope(3) sage: o.points() M( 1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), M(1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), M( 0, 0, 0) in 3d lattice M sage: cube = o.polar() sage: cube.points() N( 1, 1, 1), N( 1, 1, 1), N( 1, 1, 1), N( 1, 1, 1), N(1, 1, 1), N(1, 1, 1), N(1, 1, 1), N(1, 1, 1), N(1, 1, 0), N(1, 0, 1), N(1, 0, 0), N(1, 0, 1), N(1, 1, 0), N( 0, 1, 1), N( 0, 1, 0), N( 0, 1, 1), N( 0, 0, 1), N( 0, 0, 0), N( 0, 0, 1), N( 0, 1, 1), N( 0, 1, 0), N( 0, 1, 1), N( 1, 1, 0), N( 1, 0, 1), N( 1, 0, 0), N( 1, 0, 1), N( 1, 1, 0) in 3d lattice N
Lattice points of a 2dimensional diamond in a 3dimensional space:
sage: p = LatticePolytope([(1,0,0), (0,1,0), (1,0,0), (0,1,0)]) sage: p.points() M( 1, 0, 0), M( 0, 1, 0), M(1, 0, 0), M( 0, 1, 0), M( 0, 0, 0) in 3d lattice M
Only two of the above points:
sage: p.points(1, 3) M(0, 1, 0), M(0, 1, 0) in 3d lattice MWe check that points of a zerodimensional polytope can be computed:
sage: p = LatticePolytope([[1]]) sage: p.points() M(1) in 1d lattice M

polar
()¶ Return the polar polytope, if this polytope is reflexive.
EXAMPLES: The polar polytope to the 3dimensional octahedron:
sage: o = lattice_polytope.cross_polytope(3) sage: cube = o.polar() sage: cube 3d reflexive polytope in 3d lattice N
The polar polytope “remembers” the original one:
sage: cube.polar() 3d reflexive polytope in 3d lattice M sage: cube.polar().polar() is cube True
Only reflexive polytopes have polars:
sage: p = LatticePolytope([(1,0,0), (0,1,0), (0,0,2), ....: (1,0,0), (0,1,0), (0,0,1)]) sage: p.polar() Traceback (most recent call last): ... ValueError: The given polytope is not reflexive! Polytope: 3d lattice polytope in 3d lattice M

poly_x
(keys, reduce_dimension=False)¶ Run poly.x with given
keys
on vertices of this polytope.INPUT:
keys
 a string of options passed to poly.x. The key “f” is added automatically.reduce_dimension
 (default: False) ifTrue
and this polytope is not fulldimensional, poly.x will be called for the vertices of this polytope in some basis of the spanned affine space.
OUTPUT: the output of poly.x as a string.
EXAMPLES: This call is used for determining if a polytope is reflexive or not:
sage: o = lattice_polytope.cross_polytope(3) sage: print(o.poly_x("e")) 8 3 Vertices of Pdual <> Equations of P 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Since PALP has limits on different parameters determined during compilation, the following code is likely to fail, unless you change default settings of PALP:
sage: BIG = lattice_polytope.cross_polytope(7) sage: BIG 7d reflexive polytope in 7d lattice M sage: BIG.poly_x("e") # possibly different output depending on your system Traceback (most recent call last): ... ValueError: Error executing 'poly.x fe' for the given polytope! Output: Please increase POLY_Dmax to at least 7
You cannot call poly.x for polytopes that don’t span the space (if you could, it would crush anyway):
sage: p = LatticePolytope([(1,0,0), (0,1,0), (1,0,0), (0,1,0)]) sage: p.poly_x("e") Traceback (most recent call last): ... ValueError: Cannot run PALP for a 2dimensional polytope in a 3dimensional space!
But if you know what you are doing, you can call it for the polytope in some basis of the spanned space:
sage: print(p.poly_x("e", reduce_dimension=True)) 4 2 Equations of P 1 1 0 1 1 2 1 1 0 1 1 2

polyhedron
()¶ Return the Polyhedron object determined by this polytope’s vertices.
EXAMPLES:
sage: o = lattice_polytope.cross_polytope(2) sage: o.polyhedron() A 2dimensional polyhedron in ZZ^2 defined as the convex hull of 4 vertices

show3d
()¶ Show a 3d picture of the polytope with default settings and without axes or frame.
See self.plot3d? for more details.
EXAMPLES:
sage: o = lattice_polytope.cross_polytope(3) sage: o.show3d()

skeleton
()¶ Return the graph of the oneskeleton of this polytope.
EXAMPLES:
sage: d = lattice_polytope.cross_polytope(2) sage: g = d.skeleton() sage: g Graph on 4 vertices sage: g.edges() [(0, 1, None), (0, 3, None), (1, 2, None), (2, 3, None)]

skeleton_points
(k=1)¶ Return the increasing list of indices of lattice points in kskeleton of the polytope (k is 1 by default).
EXAMPLES: We compute all skeleton points for the cube:
sage: o = lattice_polytope.cross_polytope(3) sage: c = o.polar() sage: c.skeleton_points() [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 15, 19, 21, 22, 23, 25, 26]
The default was 1skeleton:
sage: c.skeleton_points(k=1) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 15, 19, 21, 22, 23, 25, 26]
0skeleton just lists all vertices:
sage: c.skeleton_points(k=0) [0, 1, 2, 3, 4, 5, 6, 7]
2skeleton lists all points except for the origin (point #17):
sage: c.skeleton_points(k=2) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26]
3skeleton includes all points:
sage: c.skeleton_points(k=3) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26]
It is OK to compute higher dimensional skeletons  you will get the list of all points:
sage: c.skeleton_points(k=100) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26]

skeleton_show
(normal=None)¶ Show the graph of oneskeleton of this polytope. Works only for polytopes in a 3dimensional space.
INPUT:
normal
 a 3dimensional vector (can be given as a list), which should be perpendicular to the screen. If not given, will be selected randomly (new each time and it may be far from “nice”).
EXAMPLES: Show a pretty picture of the octahedron:
sage: o = lattice_polytope.cross_polytope(3) sage: o.skeleton_show([1,2,4])
Does not work for a diamond at the moment:
sage: d = lattice_polytope.cross_polytope(2) sage: d.skeleton_show() Traceback (most recent call last): ... NotImplementedError: skeleton view is implemented only in 3d space

traverse_boundary
()¶ Return a list of indices of vertices of a 2dimensional polytope in their boundary order.
Needed for plot3d function of polytopes.
EXAMPLES:
sage: p = lattice_polytope.cross_polytope(2).polar() sage: p.traverse_boundary() [3, 0, 1, 2]

vertex
(i)¶ Return the ith vertex of this polytope, i.e. the ith column of the matrix returned by vertices().
EXAMPLES: Note that numeration starts with zero:
sage: o = lattice_polytope.cross_polytope(3) sage: o.vertices() M( 1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), M(1, 0, 0), M( 0, 1, 0), M( 0, 0, 1) in 3d lattice M sage: o.vertex(3) M(1, 0, 0)

vertex_facet_pairing_matrix
()¶ Return the vertex facet pairing matrix \(PM\).
Return a matrix whose the \(i, j^\text{th}\) entry is the height of the \(j^\text{th}\) vertex over the \(i^\text{th}\) facet. The ordering of the vertices and facets is as in
vertices()
andfacets()
.EXAMPLES:
sage: L = lattice_polytope.cross_polytope(3) sage: L.vertex_facet_pairing_matrix() [2 0 0 0 2 2] [2 2 0 0 0 2] [2 2 2 0 0 0] [2 0 2 0 2 0] [0 0 2 2 2 0] [0 0 0 2 2 2] [0 2 0 2 0 2] [0 2 2 2 0 0]

vertices
(*args, **kwds)¶ Return vertices of
self
.INPUT:
 any arguments given will be passed on to the returned object.
OUTPUT:
 a
point collection
.
EXAMPLES:
Vertices of the octahedron and its polar cube are in dual lattices:
sage: o = lattice_polytope.cross_polytope(3) sage: o.vertices() M( 1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), M(1, 0, 0), M( 0, 1, 0), M( 0, 0, 1) in 3d lattice M sage: cube = o.polar() sage: cube.vertices() N( 1, 1, 1), N( 1, 1, 1), N( 1, 1, 1), N( 1, 1, 1), N(1, 1, 1), N(1, 1, 1), N(1, 1, 1), N(1, 1, 1) in 3d lattice N

class
sage.geometry.lattice_polytope.
NefPartition
(data, Delta_polar, check=True)¶ Bases:
sage.structure.sage_object.SageObject
,_abcoll.Hashable
Create a nefpartition.
INPUT:
data
– a list of integers, the \(i\)th element of this list must be the part of the $i$th vertex ofDelta_polar
in this nefpartition;Delta_polar
– alattice polytope
;check
– by default the input will be checked for correctness, i.e. thatdata
indeed specify a nefpartition. If you are sure that the input is correct, you can speed up construction viacheck=False
option.
OUTPUT:
 a nefpartition of
Delta_polar
.
Let \(M\) and \(N\) be dual lattices. Let \(\Delta \subset M_\RR\) be a reflexive polytope with polar \(\Delta^\circ \subset N_\RR\). Let \(X_\Delta\) be the toric variety associated to the normal fan of \(\Delta\). A nefpartition is a decomposition of the vertex set \(V\) of \(\Delta^\circ\) into a disjoint union \(V = V_0 \sqcup V_1 \sqcup \dots \sqcup V_{k1}\) such that divisors \(E_i = \sum_{v\in V_i} D_v\) are Cartier (here \(D_v\) are prime torusinvariant Weil divisors corresponding to vertices of \(\Delta^\circ\)). Equivalently, let \(\nabla_i \subset N_\RR\) be the convex hull of vertices from \(V_i\) and the origin. These polytopes form a nefpartition if their Minkowski sum \(\nabla \subset N_\RR\) is a reflexive polytope.
The dual nefpartition is formed by polytopes \(\Delta_i \subset M_\RR\) of \(E_i\), which give a decomposition of the vertex set of \(\nabla^\circ \subset M_\RR\) and their Minkowski sum is \(\Delta\), i.e. the polar duality of reflexive polytopes switches convex hull and Minkowski sum for dual nefpartitions:
\[\begin{split}\Delta^\circ &= \mathrm{Conv} \left(\nabla_0, \nabla_1, \dots, \nabla_{k1}\right), \\ \nabla^{\phantom{\circ}} &= \nabla_0 + \nabla_1 + \dots + \nabla_{k1}, \\ & \\ \Delta^{\phantom{\circ}} &= \Delta_0 + \Delta_1 + \dots + \Delta_{k1}, \\ \nabla^\circ &= \mathrm{Conv} \left(\Delta_0, \Delta_1, \dots, \Delta_{k1}\right).\end{split}\]One can also interpret the duality of nefpartitions as the duality of the associated cones. Below \(\overline{M} = M \times \ZZ^k\) and \(\overline{N} = N \times \ZZ^k\) are dual lattices.
The Cayley polytope \(P \subset \overline{M}_\RR\) of a nefpartition is given by \(P = \mathrm{Conv}(\Delta_0 \times e_0, \Delta_1 \times e_1, \ldots, \Delta_{k1} \times e_{k1})\), where \(\{e_i\}_{i=0}^{k1}\) is the standard basis of \(\ZZ^k\). The dual Cayley polytope \(P^* \subset \overline{N}_\RR\) is the Cayley polytope of the dual nefpartition.
The Cayley cone \(C \subset \overline{M}_\RR\) of a nefpartition is the cone spanned by its Cayley polytope. The dual Cayley cone \(C^\vee \subset \overline{M}_\RR\) is the usual dual cone of \(C\). It turns out, that \(C^\vee\) is spanned by \(P^*\).
It is also possible to go back from the Cayley cone to the Cayley polytope, since \(C\) is a reflexive Gorenstein cone supported by \(P\): primitive integral ray generators of \(C\) are contained in an affine hyperplane and coincide with vertices of \(P\).
See Section 4.3.1 in [CK1999] and references therein for further details, or [BN2008] for a purely combinatorial approach.
EXAMPLES:
It is very easy to create a nefpartition for the octahedron, since for this polytope any decomposition of vertices is a nefpartition. We create a 3part nefpartition with the 0th and 1st vertices belonging to the 0th part (recall that numeration in Sage starts with 0), the 2nd and 5th vertices belonging to the 1st part, and 3rd and 4th vertices belonging to the 2nd part:
sage: o = lattice_polytope.cross_polytope(3) sage: np = NefPartition([0,0,1,2,2,1], o) sage: np Nefpartition {0, 1} U {2, 5} U {3, 4}
The octahedron plays the role of \(\Delta^\circ\) in the above description:
sage: np.Delta_polar() is o True
The dual nefpartition (corresponding to the “mirror complete intersection”) gives decomposition of the vertex set of \(\nabla^\circ\):
sage: np.dual() Nefpartition {0, 1, 2} U {3, 4} U {5, 6, 7} sage: np.nabla_polar().vertices() N(1, 1, 0), N(1, 0, 0), N( 0, 1, 0), N( 0, 0, 1), N( 0, 0, 1), N( 1, 0, 0), N( 0, 1, 0), N( 1, 1, 0) in 3d lattice N
Of course, \(\nabla^\circ\) is \(\Delta^\circ\) from the point of view of the dual nefpartition:
sage: np.dual().Delta_polar() is np.nabla_polar() True sage: np.Delta(1).vertices() N(0, 0, 1), N(0, 0, 1) in 3d lattice N sage: np.dual().nabla(1).vertices() N(0, 0, 1), N(0, 0, 1) in 3d lattice N
Instead of constructing nefpartitions directly, you can request all 2part nefpartitions of a given reflexive polytope (they will be computed using
nef.x
program from PALP):sage: o.nef_partitions() [ Nefpartition {0, 1, 3} U {2, 4, 5}, Nefpartition {0, 1, 3, 4} U {2, 5} (direct product), Nefpartition {0, 1, 2} U {3, 4, 5}, Nefpartition {0, 1, 2, 3} U {4, 5}, Nefpartition {0, 1, 2, 3, 4} U {5} (projection) ]

Delta
(i=None)¶ Return the polytope \(\Delta\) or \(\Delta_i\) corresponding to
self
.INPUT:
i
– an integer. If not given, \(\Delta\) will be returned.
OUTPUT:
See
nefpartition
class documentation for definitions and notation.EXAMPLES:
sage: o = lattice_polytope.cross_polytope(3) sage: np = o.nef_partitions()[0] sage: np Nefpartition {0, 1, 3} U {2, 4, 5} sage: np.Delta().polar() is o True sage: np.Delta().vertices() N( 1, 1, 1), N( 1, 1, 1), N( 1, 1, 1), N( 1, 1, 1), N(1, 1, 1), N(1, 1, 1), N(1, 1, 1), N(1, 1, 1) in 3d lattice N sage: np.Delta(0).vertices() N(1, 1, 0), N(1, 0, 0), N( 1, 0, 0), N( 1, 1, 0) in 3d lattice N

Delta_polar
()¶ Return the polytope \(\Delta^\circ\) corresponding to
self
.OUTPUT:
See
nefpartition
class documentation for definitions and notation.EXAMPLES:
sage: o = lattice_polytope.cross_polytope(3) sage: np = o.nef_partitions()[0] sage: np Nefpartition {0, 1, 3} U {2, 4, 5} sage: np.Delta_polar() is o True

Deltas
()¶ Return the polytopes \(\Delta_i\) corresponding to
self
.OUTPUT:
 a tuple of
lattice polytopes
.
See
nefpartition
class documentation for definitions and notation.EXAMPLES:
sage: o = lattice_polytope.cross_polytope(3) sage: np = o.nef_partitions()[0] sage: np Nefpartition {0, 1, 3} U {2, 4, 5} sage: np.Delta().vertices() N( 1, 1, 1), N( 1, 1, 1), N( 1, 1, 1), N( 1, 1, 1), N(1, 1, 1), N(1, 1, 1), N(1, 1, 1), N(1, 1, 1) in 3d lattice N sage: [Delta_i.vertices() for Delta_i in np.Deltas()] [N(1, 1, 0), N(1, 0, 0), N( 1, 0, 0), N( 1, 1, 0) in 3d lattice N, N(0, 0, 1), N(0, 1, 1), N(0, 0, 1), N(0, 1, 1) in 3d lattice N] sage: np.nabla_polar().vertices() N(1, 1, 0), N( 1, 1, 0), N( 1, 0, 0), N(1, 0, 0), N( 0, 1, 1), N( 0, 1, 1), N( 0, 0, 1), N( 0, 0, 1) in 3d lattice N
 a tuple of

dual
()¶ Return the dual nefpartition.
OUTPUT:
See the class documentation for the definition.
ALGORITHM:
See Proposition 3.19 in [BN2008].
Note
Automatically constructed dual nefpartitions will be ordered, i.e. vertex partition of \(\nabla\) will look like \(\{0, 1, 2\} \sqcup \{3, 4, 5, 6\} \sqcup \{7, 8\}\).
EXAMPLES:
sage: o = lattice_polytope.cross_polytope(3) sage: np = o.nef_partitions()[0] sage: np Nefpartition {0, 1, 3} U {2, 4, 5} sage: np.dual() Nefpartition {0, 1, 2, 3} U {4, 5, 6, 7} sage: np.dual().Delta() is np.nabla() True sage: np.dual().nabla(0) is np.Delta(0) True

hodge_numbers
()¶ Return Hodge numbers corresponding to
self
.OUTPUT:
 a tuple of integers (produced by
nef.x
program from PALP).
EXAMPLES:
Currently, you need to request Hodge numbers when you compute nefpartitions:
sage: p = lattice_polytope.cross_polytope(5) sage: np = p.nef_partitions()[0] # long time (4s on sage.math, 2011) sage: np.hodge_numbers() # long time Traceback (most recent call last): ... NotImplementedError: use nef_partitions(hodge_numbers=True)! sage: np = p.nef_partitions(hodge_numbers=True)[0] # long time (13s on sage.math, 2011) sage: np.hodge_numbers() # long time (19, 19)
 a tuple of integers (produced by

nabla
(i=None)¶ Return the polytope \(\nabla\) or \(\nabla_i\) corresponding to
self
.INPUT:
i
– an integer. If not given, \(\nabla\) will be returned.
OUTPUT:
See
nefpartition
class documentation for definitions and notation.EXAMPLES:
sage: o = lattice_polytope.cross_polytope(3) sage: np = o.nef_partitions()[0] sage: np Nefpartition {0, 1, 3} U {2, 4, 5} sage: np.Delta_polar().vertices() M( 1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), M(1, 0, 0), M( 0, 1, 0), M( 0, 0, 1) in 3d lattice M sage: np.nabla(0).vertices() M(1, 0, 0), M( 1, 0, 0), M( 0, 1, 0) in 3d lattice M sage: np.nabla().vertices() M(1, 0, 1), M(1, 0, 1), M( 1, 0, 1), M( 1, 0, 1), M( 0, 1, 1), M( 0, 1, 1), M( 1, 1, 0), M(1, 1, 0) in 3d lattice M

nabla_polar
()¶ Return the polytope \(\nabla^\circ\) corresponding to
self
.OUTPUT:
See
nefpartition
class documentation for definitions and notation.EXAMPLES:
sage: o = lattice_polytope.cross_polytope(3) sage: np = o.nef_partitions()[0] sage: np Nefpartition {0, 1, 3} U {2, 4, 5} sage: np.nabla_polar().vertices() N(1, 1, 0), N( 1, 1, 0), N( 1, 0, 0), N(1, 0, 0), N( 0, 1, 1), N( 0, 1, 1), N( 0, 0, 1), N( 0, 0, 1) in 3d lattice N sage: np.nabla_polar() is np.dual().Delta_polar() True

nablas
()¶ Return the polytopes \(\nabla_i\) corresponding to
self
.OUTPUT:
 a tuple of
lattice polytopes
.
See
nefpartition
class documentation for definitions and notation.EXAMPLES:
sage: o = lattice_polytope.cross_polytope(3) sage: np = o.nef_partitions()[0] sage: np Nefpartition {0, 1, 3} U {2, 4, 5} sage: np.Delta_polar().vertices() M( 1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), M(1, 0, 0), M( 0, 1, 0), M( 0, 0, 1) in 3d lattice M sage: [nabla_i.vertices() for nabla_i in np.nablas()] [M(1, 0, 0), M( 1, 0, 0), M( 0, 1, 0) in 3d lattice M, M(0, 1, 0), M(0, 0, 1), M(0, 0, 1) in 3d lattice M]
 a tuple of

nparts
()¶ Return the number of parts in
self
.OUTPUT:
 an integer.
EXAMPLES:
sage: o = lattice_polytope.cross_polytope(3) sage: np = o.nef_partitions()[0] sage: np Nefpartition {0, 1, 3} U {2, 4, 5} sage: np.nparts() 2

part
(i, all_points=False)¶ Return the
i
th part ofself
.INPUT:
i
– an integerall_points
– (default: False) whether to list all lattice points or just vertices
OUTPUT:
 a tuple of integers, indices of vertices (or all lattice points) of $Delta^circ$ belonging to $V_i$.
See
nefpartition
class documentation for definitions and notation.EXAMPLES:
sage: o = lattice_polytope.cross_polytope(3) sage: np = o.nef_partitions()[0] sage: np Nefpartition {0, 1, 3} U {2, 4, 5} sage: np.part(0) (0, 1, 3) sage: np.part(0, all_points=True) (0, 1, 3) sage: np.dual().part(0) (0, 1, 2, 3) sage: np.dual().part(0, all_points=True) (0, 1, 2, 3, 8)

part_of
(i)¶ Return the index of the part containing the
i
th vertex.INPUT:
i
– an integer.
OUTPUT:
 an integer \(j\) such that the
i
th vertex of \(\Delta^\circ\) belongs to $V_j$.
See
nefpartition
class documentation for definitions and notation.EXAMPLES:
sage: o = lattice_polytope.cross_polytope(3) sage: np = o.nef_partitions()[0] sage: np Nefpartition {0, 1, 3} U {2, 4, 5} sage: np.part_of(3) 0 sage: np.part_of(2) 1

part_of_point
(i)¶ Return the index of the part containing the
i
th point.INPUT:
i
– an integer.
OUTPUT:
 an integer \(j\) such that the
i
th point of \(\Delta^\circ\) belongs to \(\nabla_j\).
Note
Since a nefpartition induces a partition on the set of boundary lattice points of \(\Delta^\circ\), the value of \(j\) is welldefined for all \(i\) but the one that corresponds to the origin, in which case this method will raise a
ValueError
exception. (The origin always belongs to all \(\nabla_j\).)See
nefpartition
class documentation for definitions and notation.EXAMPLES:
We consider a relatively complicated reflexive polytope #2252 (easily accessible in Sage as
ReflexivePolytope(3, 2252)
, we create it here explicitly to avoid loading the whole database):sage: p = LatticePolytope([(1,0,0), (0,1,0), (0,0,1), (0,1,1), ....: (0,1,1), (1,1,0), (0,1,1), (1,1,0), (1,1,2)]) sage: np = p.nef_partitions()[0] sage: np Nefpartition {1, 2, 5, 7, 8} U {0, 3, 4, 6} sage: p.nvertices() 9 sage: p.npoints() 15
We see that the polytope has 6 more points in addition to vertices. One of them is the origin:
sage: p.origin() 14 sage: np.part_of_point(14) Traceback (most recent call last): ... ValueError: the origin belongs to all parts!
But the remaining 5 are partitioned by
np
:sage: [n for n in range(p.npoints()) ....: if p.origin() != n and np.part_of_point(n) == 0] [1, 2, 5, 7, 8, 9, 11, 13] sage: [n for n in range(p.npoints()) ....: if p.origin() != n and np.part_of_point(n) == 1] [0, 3, 4, 6, 10, 12]

parts
(all_points=False)¶ Return all parts of
self
.INPUT:
all_points
– (default: False) whether to list all lattice points or just vertices
OUTPUT:
 a tuple of tuples of integers. The \(i\)th tuple contains indices of vertices (or all lattice points) of $Delta^circ$ belonging to $V_i$
See
nefpartition
class documentation for definitions and notation.EXAMPLES:
sage: o = lattice_polytope.cross_polytope(3) sage: np = o.nef_partitions()[0] sage: np Nefpartition {0, 1, 3} U {2, 4, 5} sage: np.parts() ((0, 1, 3), (2, 4, 5)) sage: np.parts(all_points=True) ((0, 1, 3), (2, 4, 5)) sage: np.dual().parts() ((0, 1, 2, 3), (4, 5, 6, 7)) sage: np.dual().parts(all_points=True) ((0, 1, 2, 3, 8), (4, 5, 6, 7, 10))

sage.geometry.lattice_polytope.
ReflexivePolytope
(dim, n)¶ Return nth reflexive polytope from the database of 2 or 3dimensional reflexive polytopes.
Note
 Numeration starts with zero: \(0 \leq n \leq 15\) for \({\rm dim} = 2\) and \(0 \leq n \leq 4318\) for \({\rm dim} = 3\).
 During the first call, all reflexive polytopes of requested dimension are loaded and cached for future use, so the first call for 3dimensional polytopes can take several seconds, but all consecutive calls are fast.
 Equivalent to
ReflexivePolytopes(dim)[n]
but checks bounds first.
EXAMPLES: The 3rd 2dimensional polytope is “the diamond:”
sage: ReflexivePolytope(2, 3) 2d reflexive polytope #3 in 2d lattice M sage: lattice_polytope.ReflexivePolytope(2,3).vertices() M( 1, 0), M( 0, 1), M( 0, 1), M(1, 0) in 2d lattice M
There are 16 reflexive polygons and numeration starts with 0:
sage: ReflexivePolytope(2,16) Traceback (most recent call last): ... ValueError: there are only 16 reflexive polygons!
It is not possible to load a 4dimensional polytope in this way:
sage: ReflexivePolytope(4,16) Traceback (most recent call last): ... NotImplementedError: only 2 and 3dimensional reflexive polytopes are available!

sage.geometry.lattice_polytope.
ReflexivePolytopes
(dim)¶ Return the sequence of all 2 or 3dimensional reflexive polytopes.
Note
During the first call the database is loaded and cached for future use, so repetitive calls will return the same object in memory.
Parameters: dim (2 or 3) – dimension of required reflexive polytopes Return type: list of lattice polytopes EXAMPLES: There are 16 reflexive polygons:
sage: len(ReflexivePolytopes(2)) 16
It is not possible to load 4dimensional polytopes in this way:
sage: ReflexivePolytopes(4) Traceback (most recent call last): ... NotImplementedError: only 2 and 3dimensional reflexive polytopes are available!

class
sage.geometry.lattice_polytope.
SetOfAllLatticePolytopesClass
¶

sage.geometry.lattice_polytope.
all_cached_data
(polytopes)¶ Compute all cached data for all given
polytopes
and their polars.This functions does it MUCH faster than member functions of
LatticePolytope
during the first run. So it is recommended to use this functions if you work with big sets of data. None of the polytopes in the given sequence should be constructed as the polar polytope to another one.INPUT: a sequence of lattice polytopes.
EXAMPLES: This function has no output, it is just a fast way to work with long sequences of polytopes. Of course, you can use short sequences as well:
sage: o = lattice_polytope.cross_polytope(3) sage: lattice_polytope.all_cached_data([o])

sage.geometry.lattice_polytope.
all_facet_equations
(polytopes)¶ Compute polar polytopes for all reflexive and equations of facets for all nonreflexive
polytopes
.all_facet_equations
andall_polars
are synonyms.This functions does it MUCH faster than member functions of
LatticePolytope
during the first run. So it is recommended to use this functions if you work with big sets of data.INPUT: a sequence of lattice polytopes.
EXAMPLES: This function has no output, it is just a fast way to work with long sequences of polytopes. Of course, you can use short sequences as well:
sage: o = lattice_polytope.cross_polytope(3) sage: lattice_polytope.all_polars([o]) sage: o.polar() 3d reflexive polytope in 3d lattice N

sage.geometry.lattice_polytope.
all_nef_partitions
(polytopes, keep_symmetric=False)¶ Compute nefpartitions for all given
polytopes
.This functions does it MUCH faster than member functions of
LatticePolytope
during the first run. So it is recommended to use this functions if you work with big sets of data.Note: member function
is_reflexive
will be called separately for each polytope. It is strictly recommended to callall_polars
on the sequence ofpolytopes
before using this function.INPUT: a sequence of lattice polytopes.
EXAMPLES: This function has no output, it is just a fast way to work with long sequences of polytopes. Of course, you can use short sequences as well:
sage: o = lattice_polytope.cross_polytope(3) sage: lattice_polytope.all_nef_partitions([o]) sage: o.nef_partitions() [ Nefpartition {0, 1, 3} U {2, 4, 5}, Nefpartition {0, 1, 3, 4} U {2, 5} (direct product), Nefpartition {0, 1, 2} U {3, 4, 5}, Nefpartition {0, 1, 2, 3} U {4, 5}, Nefpartition {0, 1, 2, 3, 4} U {5} (projection) ]
You cannot use this function for nonreflexive polytopes:
sage: p = LatticePolytope([(1,0,0), (0,1,0), (0,0,2), ....: (1,0,0), (0,1,0), (0,0,1)]) sage: lattice_polytope.all_nef_partitions([o, p]) Traceback (most recent call last): ... ValueError: nefpartitions can be computed for reflexive polytopes only

sage.geometry.lattice_polytope.
all_points
(polytopes)¶ Compute lattice points for all given
polytopes
.This functions does it MUCH faster than member functions of
LatticePolytope
during the first run. So it is recommended to use this functions if you work with big sets of data.INPUT: a sequence of lattice polytopes.
EXAMPLES: This function has no output, it is just a fast way to work with long sequences of polytopes. Of course, you can use short sequences as well:
sage: o = lattice_polytope.cross_polytope(3) sage: lattice_polytope.all_points([o]) sage: o.points() M( 1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), M(1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), M( 0, 0, 0) in 3d lattice M

sage.geometry.lattice_polytope.
all_polars
(polytopes)¶ Compute polar polytopes for all reflexive and equations of facets for all nonreflexive
polytopes
.all_facet_equations
andall_polars
are synonyms.This functions does it MUCH faster than member functions of
LatticePolytope
during the first run. So it is recommended to use this functions if you work with big sets of data.INPUT: a sequence of lattice polytopes.
EXAMPLES: This function has no output, it is just a fast way to work with long sequences of polytopes. Of course, you can use short sequences as well:
sage: o = lattice_polytope.cross_polytope(3) sage: lattice_polytope.all_polars([o]) sage: o.polar() 3d reflexive polytope in 3d lattice N

sage.geometry.lattice_polytope.
convex_hull
(points)¶ Compute the convex hull of the given points.
Note
points
might not span the space. Also, it fails for large numbers of vertices in dimensions 4 or greaterINPUT:
points
 a list that can be converted into vectors of the same dimension over ZZ.
OUTPUT: list of vertices of the convex hull of the given points (as vectors).
EXAMPLES: Let’s compute the convex hull of several points on a line in the plane:
sage: lattice_polytope.convex_hull([[1,2],[3,4],[5,6],[7,8]]) [(1, 2), (7, 8)]

sage.geometry.lattice_polytope.
cross_polytope
(dim)¶ Return a crosspolytope of the given dimension.
INPUT:
dim
– an integer.
OUTPUT:
EXAMPLES:
sage: o = lattice_polytope.cross_polytope(3) sage: o 3d reflexive polytope in 3d lattice M sage: o.vertices() M( 1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), M(1, 0, 0), M( 0, 1, 0), M( 0, 0, 1) in 3d lattice M

sage.geometry.lattice_polytope.
integral_length
(v)¶ Compute the integral length of a given rational vector.
INPUT:
v
 any object which can be converted to a list of rationals
OUTPUT: Rational number
r
such thatv = r u
, whereu
is the primitive integral vector in the direction ofv
.EXAMPLES:
sage: lattice_polytope.integral_length([1, 2, 4]) 1 sage: lattice_polytope.integral_length([2, 2, 4]) 2 sage: lattice_polytope.integral_length([2/3, 2, 4]) 2/3

sage.geometry.lattice_polytope.
is_LatticePolytope
(x)¶ Check if
x
is a lattice polytope.INPUT:
x
– anything.
OUTPUT:
True
ifx
is alattice polytope
,False
otherwise.
EXAMPLES:
sage: from sage.geometry.lattice_polytope import is_LatticePolytope sage: is_LatticePolytope(1) False sage: p = LatticePolytope([(1,0), (0,1), (1,1)]) sage: p 2d reflexive polytope #0 in 2d lattice M sage: is_LatticePolytope(p) True

sage.geometry.lattice_polytope.
is_NefPartition
(x)¶ Check if
x
is a nefpartition.INPUT:
x
– anything.
OUTPUT:
True
ifx
is anefpartition
andFalse
otherwise.
EXAMPLES:
sage: from sage.geometry.lattice_polytope import is_NefPartition sage: is_NefPartition(1) False sage: o = lattice_polytope.cross_polytope(3) sage: np = o.nef_partitions()[0] sage: np Nefpartition {0, 1, 3} U {2, 4, 5} sage: is_NefPartition(np) True

sage.geometry.lattice_polytope.
minkowski_sum
(points1, points2)¶ Compute the Minkowski sum of two convex polytopes.
Note
Polytopes might not be of maximal dimension.
INPUT:
points1, points2
 lists of objects that can be converted into vectors of the same dimension, treated as vertices of two polytopes.
OUTPUT: list of vertices of the Minkowski sum, given as vectors.
EXAMPLES: Let’s compute the Minkowski sum of two line segments:
sage: lattice_polytope.minkowski_sum([[1,0],[1,0]],[[0,1],[0,1]]) [(1, 1), (1, 1), (1, 1), (1, 1)]

sage.geometry.lattice_polytope.
positive_integer_relations
(points)¶ Return relations between given points.
INPUT:
points
 lattice points given as columns of a matrix
OUTPUT: matrix of relations between given points with nonnegative integer coefficients
EXAMPLES: This is a 3dimensional reflexive polytope:
sage: p = LatticePolytope([(1,0,0), (0,1,0), ....: (1,1,0), (0,0,1), (1,0,1)]) sage: p.points() M( 1, 0, 0), M( 0, 1, 0), M(1, 1, 0), M( 0, 0, 1), M(1, 0, 1), M( 0, 0, 0) in 3d lattice M
We can compute linear relations between its points in the following way:
sage: p.points().matrix().kernel().echelonized_basis_matrix() [ 1 0 0 1 1 0] [ 0 1 1 1 1 0] [ 0 0 0 0 0 1]
However, the above relations may contain negative and rational numbers. This function transforms them in such a way, that all coefficients are nonnegative integers:
sage: lattice_polytope.positive_integer_relations(p.points().column_matrix()) [1 0 0 1 1 0] [1 1 1 0 0 0] [0 0 0 0 0 1] sage: cm = ReflexivePolytope(2,1).vertices().column_matrix() sage: lattice_polytope.positive_integer_relations(cm) [2 1 1]

sage.geometry.lattice_polytope.
read_all_polytopes
(file_name)¶ Read all polytopes from the given file.
INPUT:
file_name
– a string with the name of a file with VERTICES of polytopes.
OUTPUT:
 a sequence of polytopes.
EXAMPLES:
We use poly.x to compute two polar polytopes and read them:
sage: d = lattice_polytope.cross_polytope(2) sage: o = lattice_polytope.cross_polytope(3) sage: result_name = lattice_polytope._palp("poly.x fe", [d, o]) sage: with open(result_name) as f: ....: print(f.read()) 4 2 Vertices of Pdual <> Equations of P 1 1 1 1 1 1 1 1 8 3 Vertices of Pdual <> Equations of P 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 sage: lattice_polytope.read_all_polytopes(result_name) [ 2d reflexive polytope #14 in 2d lattice M, 3d reflexive polytope in 3d lattice M ] sage: os.remove(result_name)

sage.geometry.lattice_polytope.
read_palp_matrix
(data, permutation=False)¶ Read and return an integer matrix from a string or an opened file.
First input line must start with two integers m and n, the number of rows and columns of the matrix. The rest of the first line is ignored. The next m lines must contain n numbers each.
If m>n, returns the transposed matrix. If the string is empty or EOF is reached, returns the empty matrix, constructed by
matrix()
.INPUT:
data
– Either a string containing the filename or the file itself containing the output by PALP.
permutation
– (default:False
) IfTrue
, try to retrieve the permutation output by PALP. This parameter makes sense only when PALP computed the normal form of a lattice polytope.
OUTPUT:
A matrix or a tuple of a matrix and a permutation.
EXAMPLES:
sage: lattice_polytope.read_palp_matrix("2 3 comment \n 1 2 3 \n 4 5 6") [1 2 3] [4 5 6] sage: lattice_polytope.read_palp_matrix("3 2 Will be transposed \n 1 2 \n 3 4 \n 5 6") [1 3 5] [2 4 6]

sage.geometry.lattice_polytope.
set_palp_dimension
(d)¶ Set the dimension for PALP calls to
d
.INPUT:
d
– an integer from the list [4,5,6,11] orNone
.
OUTPUT:
 none.
PALP has many hardcoded limits, which must be specified before compilation, one of them is dimension. Sage includes several versions with different dimension settings (which may also affect other limits and enable certain features of PALP). You can change the version which will be used by calling this function. Such a change is not done automatically for each polytope based on its dimension, since depending on what you are doing it may be necessary to use dimensions higher than that of the input polytope.
EXAMPLES:
Let’s try to work with a 7dimensional polytope:
sage: p = lattice_polytope.cross_polytope(7) sage: p._palp("poly.x fv") Traceback (most recent call last): ... ValueError: Error executing 'poly.x fv' for the given polytope! Output: Please increase POLY_Dmax to at least 7
However, we can work with this polytope by changing PALP dimension to 11:
sage: lattice_polytope.set_palp_dimension(11) sage: p._palp("poly.x fv") '7 14 Vertices of P...'
Let’s go back to default settings:
sage: lattice_polytope.set_palp_dimension(None)

sage.geometry.lattice_polytope.
skip_palp_matrix
(data, n=1)¶ Skip matrix data in a file.
INPUT:
data
 opened file with blocks of matrix data in the following format: A block consisting of m+1 lines has the number m as the first element of its first line.n
 (default: 1) integer, specifies how many blocks should be skipped
If EOF is reached during the process, raises ValueError exception.
EXAMPLES: We create a file with vertices of the square and the cube, but read only the second set:
sage: d = lattice_polytope.cross_polytope(2) sage: o = lattice_polytope.cross_polytope(3) sage: result_name = lattice_polytope._palp("poly.x fe", [d, o]) sage: with open(result_name) as f: ....: print(f.read()) 4 2 Vertices of Pdual <> Equations of P 1 1 1 1 1 1 1 1 8 3 Vertices of Pdual <> Equations of P 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 sage: f = open(result_name) sage: lattice_polytope.skip_palp_matrix(f) sage: lattice_polytope.read_palp_matrix(f) [1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1] [ 1 1 1 1 1 1 1 1] sage: f.close() sage: os.remove(result_name)

sage.geometry.lattice_polytope.
write_palp_matrix
(m, ofile=None, comment='', format=None)¶ Write
m
intoofile
in PALP format.INPUT:
m
– a matrix over integers or apoint collection
.ofile
– a file opened for writing (default: stdout)comment
– a string (default: empty) see output descriptionformat
– a format string used to print matrix entries.
OUTPUT:
 nothing is returned, output written to
ofile
has the format First line: number_of_rows number_of_columns comment
 Next number_of_rows lines: rows of the matrix.
EXAMPLES:
sage: o = lattice_polytope.cross_polytope(3) sage: lattice_polytope.write_palp_matrix(o.vertices(), comment="3D Octahedron") 3 6 3D Octahedron 1 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 1 sage: lattice_polytope.write_palp_matrix(o.vertices(), format="%4d") 3 6 1 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 1