# 33.1 Lattice and reflexive polytopes

Module: sage.geometry.lattice_polytope

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 . The dimension of a polytope is the smallest such that the polytope can be embedded in .

A lattice polytope is a polytope whose vertices all have integer coordinates.

If is a lattice polytope, the dual polytope of is

all

A reflexive polytope is a lattice polytope, such that its polar is also a lattice polytope, i.e. 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 licence terms at http://tph16.tuwien.ac.at/~kreuzer/CY/. Moreover, PALP is included standard with SAGE.

PALP is described in the paper math.SC/0204356. Its distribution also contains the application nef.x, which was created by Erwin Riegler and computes nef partitions 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.

IMPORTANT NOTE: 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).

Author Log:

• Andrey Novoseltsev (2007-01-11): initial version of this module
• Andrey Novoseltsev (2007-01-15: all_* functions
• Maximilian Kreuzer and Harald Skarke: authors of PALP
• Erwin Riegler: the author of nef.x

Module-level Functions

 LatticePolytope( data, [desc=None], [compute_vertices=False], [copy_vertices=True], [n=0])
Construct a lattice polytope.

LatticePolytope(data, [desc], [compute_vertices], [copy_vertices], [n])

INPUT:
data -- a matrix of \emph{MAXIMAL} rank, whose columns are vertices of
the polytope (unless \code{compute_vertices} is True);
a file with matrix data, open for reading;
or a filename of such a file.
See \code{read_palp_matrix} for the file format.
Points of the given matrix must span the space.
desc -- (default: "A lattice polytope") description of the polytope.
compute_vertices -- (default: False) if True, the convex hull of
the given points will be computed for determining vertices.
Otherwise, the given points are vertices.
copy_vertices -- (default: True) if False and \code{data} is a
matrix of vertices, it will be made immutable.
n -- (default: 0) if \code{data} is a name of a file, that contains
data blocks for several polytopes, the n-th block will be used.
\emph{NUMERATION STARTS WITH ZERO}.

OUTPUT:
a lattice polytope


Here we construct a polytope from a matrix whose columns are vertices in 3-dimensional space. In the first case a copy of the given matrix is made during construction, in the second one the matrix is made immutable and used as a matrix of vertices.

sage: m = matrix(ZZ, [[1, 0, 0, -1,  0,  0],
...                   [0, 1, 0,  0, -1,  0],
...                   [0, 0, 1,  0,  0, -1]])
...
sage: p = LatticePolytope(m)
sage: p
A lattice polytope: 3-dimensional, 6 vertices.
sage: m.is_mutable()
True
sage: m is p.vertices()
False
sage: p = LatticePolytope(m, copy_vertices=False)
sage: m.is_mutable()
False
sage: m is p.vertices()
True


We draw a pretty picture of the polytype in 3-dimensional space:

sage: p.plot().show()


Now we add an extra point to the matrix...

sage: m = matrix(ZZ, [[1, 0, 0, -1,  0,  0, 0],
...                   [0, 1, 0,  0, -1,  0, 0],
...                   [0, 0, 1,  0,  0, -1, 0]])
...
sage: p = LatticePolytope(m, "A lattice polytope with WRONG vertices")
sage: p
A lattice polytope with WRONG vertices: 3-dimensional, 7 vertices.


The above construction is WRONG since the origin is an interior point of the octahedron. If you don't know in advance that your data are vertices of the polytope, use compute_vertices option as below:

sage: p = LatticePolytope(m, "A lattice polytope constructed from 7 points",
...                         compute_vertices=True)
...
sage: p
A lattice polytope constructed from 7 points: 3-dimensional, 6 vertices.


Points of the given matrix must always span the space, this conditions will be checked only if you specify compute_vertices option:

sage: m = matrix(ZZ, [[1, 0, -1,  0],
...                   [0, 1,  0, -1],
...                   [0, 0,  0,  0]])
...
sage: p = LatticePolytope(m, compute_vertices=True)
Traceback (most recent call last):
...
ValueError: Points must span the space!


 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 codeLatticePolytope 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.


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.octahedron(3)
sage: lattice_polytope.all_cached_data([o])
sage: o.faces()
[
[[5], [1], [0], [3], [4], [2]],
[[1, 5], [0, 5], [0, 1], [3, 5], [1, 3], [4, 5], [0, 4], [3, 4], [1, 2],
[0, 2], [2, 3], [2, 4]],
[[0, 1, 5], [1, 3, 5], [0, 4, 5], [3, 4, 5], [0, 1, 2], [1, 2, 3], [0, 2,
4], [2, 3, 4]]
]


However, you cannot use it for polytopes that are constructed as polar polytopes of others:

sage: lattice_polytope.all_cached_data([o.polar()])
Traceback (most recent call last):
...
ValueError: Cannot read face structure for a polytope constructed as polar,
use _compute_faces!


 all_faces( polytopes)
Compute faces for all given polytopes.

This functions does it MUCH faster than member functions of codeLatticePolytope 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.


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.octahedron(3)
sage: lattice_polytope.all_faces([o])
sage: o.faces()
[
[[5], [1], [0], [3], [4], [2]],
[[1, 5], [0, 5], [0, 1], [3, 5], [1, 3], [4, 5], [0, 4], [3, 4], [1, 2],
[0, 2], [2, 3], [2, 4]],
[[0, 1, 5], [1, 3, 5], [0, 4, 5], [3, 4, 5], [0, 1, 2], [1, 2, 3], [0, 2,
4], [2, 3, 4]]
]


However, you cannot use it for polytopes that are constructed as polar polytopes of others:

sage: lattice_polytope.all_faces([o.polar()])
Traceback (most recent call last):
...
ValueError: Cannot read face structure for a polytope constructed as polar,
use _compute_faces!


 all_nef_partitions( polytopes, [keep_symmetric=False])
Compute NEF-partitions for all given polytopes.

This functions does it MUCH faster than member functions of codeLatticePolytope 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 call all_polars on the sequence of polytopes before using this function.

INPUT:
a sequence of lattice polytopes.


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.octahedron(3)
sage: lattice_polytope.all_nef_partitions([o])
sage: o.nef_partitions()
[
[1, 1, 0, 1, 0, 0],
[1, 1, 1, 0, 0, 0],
[1, 1, 1, 1, 0, 0]
]


You cannot use this function for non-reflexive polytopes:

sage: m = matrix(ZZ, [[1, 0, 0, -1,  0,  0],
...                   [0, 1, 0,  0, -1,  0],
...                   [0, 0, 2,  0,  0, -1]])
...
sage: p = LatticePolytope(m)
sage: lattice_polytope.all_nef_partitions([o, p])
Traceback (most recent call last):
...
ValueError: The given polytope is not reflexive!
Polytope: A lattice polytope: 3-dimensional, 6 vertices.


 all_points( polytopes)
Compute lattice points for all given polytopes.

This functions does it MUCH faster than member functions of codeLatticePolytope 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.


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.octahedron(3)
sage: lattice_polytope.all_points([o])
sage: o.points()
[ 1  0  0 -1  0  0  0]
[ 0  1  0  0 -1  0  0]
[ 0  0  1  0  0 -1  0]


 all_polars( polytopes)
Compute polar polytopes for all reflexive and equations of facets for all non-reflexive polytopes.

This functions does it MUCH faster than member functions of codeLatticePolytope 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.


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.octahedron(3)
sage: lattice_polytope.all_polars([o])
sage: o.polar()
A polytope polar to An octahedron: 3-dimensional, 8 vertices.


 filter_polytopes( f, polytopes, [subseq=None], [print_numbers=False])
Use the function f to filter polytopes in a list.

INPUT:
f -- filtering function, it must take one argument, a lattice polytope,
and return True or False.
polytopes -- list of polytopes.
subseq -- (default: None) list of integers. If it is specified, only
polytopes with these numbers will be considered.
print_numbers -- (default: False) if True, the number of the current
polytope will be printed on the screen before calling \code{f}.

OUTPUT:
a list of integers --- numbers of polytopes in the given list, that
satisfy the given condition (i.e. function \code{f} returns True)
and are elements of subseq, if it is given.


Consider a sequence of octahedrons:

sage: polytopes = Sequence([lattice_polytope.octahedron(n) for n in range(2, 7)], cr=True)
sage: polytopes
[
An octahedron: 2-dimensional, 4 vertices.,
An octahedron: 3-dimensional, 6 vertices.,
An octahedron: 4-dimensional, 8 vertices.,
An octahedron: 5-dimensional, 10 vertices.,
An octahedron: 6-dimensional, 12 vertices.
]


This filters octahedrons of dimension at least 4:

sage: lattice_polytope.filter_polytopes(lambda p: p.dim() >= 4, polytopes)
[2, 3, 4]


For long tests you can see the current progress:

sage: lattice_polytope.filter_polytopes(lambda p: p.nvertices() >= 10, polytopes, print_numbers=True)
0
1
2
3
4
[3, 4]


Here we consider only some of the polytopes:

sage: lattice_polytope.filter_polytopes(lambda p: p.nvertices() >= 10, polytopes, [2, 3, 4], print_numbers=True)
2
3
4
[3, 4]


 octahedron( dim)
Return an octahedron of the given dimension.

Here are 3- and 4-dimensional octahedrons:

sage: o = lattice_polytope.octahedron(3)
sage: o
An octahedron: 3-dimensional, 6 vertices.
sage: o.vertices()
[ 1  0  0 -1  0  0]
[ 0  1  0  0 -1  0]
[ 0  0  1  0  0 -1]
sage: o = lattice_polytope.octahedron(4)
sage: o
An octahedron: 4-dimensional, 8 vertices.
sage: o.vertices()
[ 1  0  0  0 -1  0  0  0]
[ 0  1  0  0  0 -1  0  0]
[ 0  0  1  0  0  0 -1  0]
[ 0  0  0  1  0  0  0 -1]


There exists only one octahedron of each dimension:

sage: o is lattice_polytope.octahedron(4)
True


 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 non-negative integer
coefficients


This is a 3-dimensional reflexive polytope:

sage: m = matrix(ZZ,[[1, 0, -1, 0, -1],
...                  [0, 1, -1, 0,  0],
...                  [0, 0,  0, 1, -1]])
...
sage: p = LatticePolytope(m)
sage: p.points()
[ 1  0 -1  0 -1  0]
[ 0  1 -1  0  0  0]
[ 0  0  0  1 -1  0]


We can compute linear relations between its points in the following way:

sage: p.points().transpose().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 non-negative integers:

sage: lattice_polytope.positive_integer_relations(p.points())
[1 0 0 1 1 0]
[1 1 1 0 0 0]
[0 0 0 0 0 1]


 projective_space( dim)
Return a simplex of the given dimension, corresponding to .

We construct 3- and 4-dimensional simplexes:

sage: p = lattice_polytope.projective_space(3)
sage: p
A simplex: 3-dimensional, 4 vertices.
sage: p.vertices()
[ 1  0  0 -1]
[ 0  1  0 -1]
[ 0  0  1 -1]
sage: p = lattice_polytope.projective_space(4)
sage: p
A simplex: 4-dimensional, 5 vertices.
sage: p.vertices()
[ 1  0  0  0 -1]
[ 0  1  0  0 -1]
[ 0  0  1  0 -1]
[ 0  0  0  1 -1]


Read all polytopes from the given file.

INPUT:
file_name -- the name of a file with vertices of polytopes
desc -- a string, that will be used for creating polytope descriptions.
By default it will be set to 'A lattice polytope #%d from
"filename"'
and will be used as \code{desc % n} where \code{n} is the number of
the polytope in the file (\emph{STARTING WITH ZERO}).

OUTPUT:
a sequence of polytopes


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().

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_matrix_to_maxima( m)
Convert a SAGE matrix to the string representation of Maxima.

 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.

 write_palp_matrix( m, [ofile=None], [comment=], [format=None])
Write a matrix into a file.

INPUT:
m -- a matrix over integers.
ofile -- a file opened for writing (default: stdout)
comment -- a string (default: empty) see output description
format -- a format string used to print matrix entries. By default,
"%nd" will be used, where n is the maximum entry length.

OUTPUT:
First line: number_of_rows number_of_columns comment
Next number_of_rows lines: rows of the matrix.


This functions is used for writing polytope vertices in PALP format:

sage: o = lattice_polytope.octahedron(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


Class: _PolytopeFace

class _PolytopeFace
_PolytopeFace(polytope, vertices, facets)

Construct a polytope face.

POLYTOPE FACES SHOULD NOT BE CONSTRUCTED OUTSIDE OF LATTICE POLYTOPES!

INPUT: polytope - a polytope whose face is being constructed. vertices - a sequence of indices of generating vertices. facets - a sequence of indices of facets containing this face.

 _PolytopeFace( self, polytope, vertices, facets)
Construct a face.

Functions: boundary_points, facets, interior_points, nboundary_points, nfacets, ninterior_points, npoints, nvertices, points, vertices

 boundary_points( self)
Return a sequence of indices of boundary lattice points of this face.

Boundary lattice points of one of the facets of the 3-dimensional cube:

sage: o = lattice_polytope.octahedron(3)
sage: cube = o.polar()
sage: face = cube.facets()[0]
sage: face.boundary_points()
[0, 1, 2, 3, 11, 15, 21, 25]


 facets( self)
Return a sequence of indices of facets containing this face.

Facets containing one of the edges of the 3-dimensional octahedron:

sage: o = lattice_polytope.octahedron(3)
sage: edge = o.faces(dim=1)[0]
sage: edge.facets()
[0, 1]


Thus edge is the intersection of facets 0 and 1:

sage: edge
[1, 5]
sage: o.facets()[0]
[0, 1, 5]
sage: o.facets()[1]
[1, 3, 5]


 interior_points( self)
Return a sequence of indices of interior lattice points of this face.

Interior lattice points of one of the facets of the 3-dimensional cube:

sage: o = lattice_polytope.octahedron(3)
sage: cube = o.polar()
sage: face = cube.facets()[0]
sage: face.interior_points()
[18]


 nboundary_points( self)
Return the number of boundary lattice points of this face.

The number of boundary lattice points of one of the facets of the 3-dimensional cube:

sage: o = lattice_polytope.octahedron(3)
sage: cube = o.polar()
sage: face = cube.facets()[0]
sage: face.nboundary_points()
8


 nfacets( self)
Return the number of facets containing this face.

The number of facets containing one of the edges of the 3-dimensional octahedron:

sage: o = lattice_polytope.octahedron(3)
sage: edge = o.faces(dim=1)[0]
sage: edge.nfacets()
2


 ninterior_points( self)
Return the number of interior lattice points of this face.

The number of interior lattice points of one of the facets of the 3-dimensional cube:

sage: o = lattice_polytope.octahedron(3)
sage: cube = o.polar()
sage: face = cube.facets()[0]
sage: face.ninterior_points()
1


 npoints( self)
Return the number of lattice points of this face.

The number of lattice points of one of the facets of the 3-dimensional cube:

sage: o = lattice_polytope.octahedron(3)
sage: cube = o.polar()
sage: face = cube.facets()[0]
sage: face.npoints()
9


 nvertices( self)
Return the number of vertices generating this face.

The number of vertices generating one of the facets of the 3-dimensional cube:

sage: o = lattice_polytope.octahedron(3)
sage: cube = o.polar()
sage: face = cube.facets()[0]
sage: face.nvertices()
4


 points( self)
Return a sequence of indices of lattice points of this face.

The lattice points of one of the facets of the 3-dimensional cube:

sage: o = lattice_polytope.octahedron(3)
sage: cube = o.polar()
sage: face = cube.facets()[0]
sage: face.points()
[0, 1, 2, 3, 11, 15, 18, 21, 25]


 vertices( self)
Return a sequence of indices of vertices generating this face.

The vertices generating one of the facets of the 3-dimensional cube:

sage: o = lattice_polytope.octahedron(3)
sage: cube = o.polar()
sage: face = cube.facets()[0]
sage: face.vertices()
[0, 1, 2, 3]


Special Functions: __reduce__, _repr_

 __reduce__( self)
Reduction function. Does not store data that can be relatively fast recomputed.

 _repr_( self)
Return a string representation of this face.

Class: LatticePolytopeClass

class LatticePolytopeClass
Class of lattice/reflexive polytopes.

Use LatticePolytope for constructing a polytope.

 LatticePolytopeClass( self, data, desc, compute_vertices, [copy_vertices=True], [n=0])
Construct a lattice polytope. See LatticePolytope.

Functions: dim, distances, faces, facets, is_reflexive, mif, nef_partitions, nef_x, nfacets, npoints, nvertices, parent, plot, points, polar, poly_x, show, vertices

 dim( self)
Return the dimension of this polytope.

We create a 3-dimensional octahedron and check its dimension:

sage: o = lattice_polytope.octahedron(3)
sage: o.dim()
3


 distances( self)
Return the matrix of distances for this polytope.

This matrix m gives distances m[i,j] between the i-th facet (which is also the i-th vertex of the polar polytope in the reflexive case) and j-th point of this polytope.

The matrix of distances for a 3-dimensional octahedron:

sage: o = lattice_polytope.octahedron(3)
sage: o.distances()
[0 0 2 2 2 0 1]
[2 0 2 0 2 0 1]
[0 2 2 2 0 0 1]
[2 2 2 0 0 0 1]
[0 0 0 2 2 2 1]
[2 0 0 0 2 2 1]
[0 2 0 2 0 2 1]
[2 2 0 0 0 2 1]


 faces( self, [dim=None], [codim=None])
Return the sequence of faces of this polytope.

If dim or codim are specified, returns a sequence of faces of the corresponding dimension or codimension. Otherwise returns the sequence of such sequences for all dimensions.

All faces of the 3-dimensional octahedron:

sage: o = lattice_polytope.octahedron(3)
sage: o.faces()
[
[[5], [1], [0], [3], [4], [2]],
[[1, 5], [0, 5], [0, 1], [3, 5], [1, 3], [4, 5], [0, 4], [3, 4], [1, 2],
[0, 2], [2, 3], [2, 4]],
[[0, 1, 5], [1, 3, 5], [0, 4, 5], [3, 4, 5], [0, 1, 2], [1, 2, 3], [0, 2,
4], [2, 3, 4]]
]


Its faces of dimension one (i.e., edges):

sage: o.faces(dim=1)
[[1, 5], [0, 5], [0, 1], [3, 5], [1, 3], [4, 5], [0, 4], [3, 4], [1, 2],
[0, 2], [2, 3], [2, 4]]


Its faces of codimension two (also edges):

sage: o.faces(codim=2)
[[1, 5], [0, 5], [0, 1], [3, 5], [1, 3], [4, 5], [0, 4], [3, 4], [1, 2],
[0, 2], [2, 3], [2, 4]]


It is an error to specify both dimension and codimension at the same time, even if they do agree:

sage: o.faces(dim=1, codim=2)
Traceback (most recent call last):
...
ValueError: Both dim and codim are given!


 facets( self)
Return the sequence of facets of this polytope.

All facets of the 3-dimensional octahedron:

sage: o = lattice_polytope.octahedron(3)
sage: o.facets()
[[0, 1, 5], [1, 3, 5], [0, 4, 5], [3, 4, 5], [0, 1, 2], [1, 2, 3], [0, 2,
4], [2, 3, 4]]


Facets are the same as faces of codimension one:

sage: o.facets() is o.faces(codim=1)
True


 is_reflexive( self)
Return True if this polytope is reflexive.

The 3-dimensional octahedron is reflexive (and 4318 other 3-polytopes):

sage: o = lattice_polytope.octahedron(3)
sage: o.is_reflexive()
True


But not all polytopes are reflexive:

sage: m = matrix(ZZ, [[1, 0, 0, -1,  0,  0],
...                   [0, 1, 0,  0, -1,  0],
...                   [0, 0, 0,  0,  0, -1]])
...
sage: p = LatticePolytope(m)
sage: p.is_reflexive()
False


 mif( self, partition)
Return all vectors , grouped into matrices.

INPUT:
partition -- NEF-partition (instance of class NEFPartition)

OUTPUT:
A sequence of matrices, one for each facet f of this polytope.
Each row of each matrix corresponds to a part of the NEF-partition.


We compute matrices for one of the nef-partitions of the 3-dimensional octahedron:

sage: o = lattice_polytope.octahedron(3)
sage: nefp = o.nef_partitions()[0]
sage: o.mif(nefp)
[
[ 0  0  1]
[-1 -1  0],
[ 0  0  1]
[ 1 -1  0],
[ 0  1  1]
[-1  0  0],
[0 1 1]
[1 0 0],
[ 0  0 -1]
[-1 -1  0],
[ 0  0 -1]
[ 1 -1  0],
[ 0  1 -1]
[-1  0  0],
[ 0  1 -1]
[ 1  0  0]
]


 nef_partitions( self, [keep_symmetric=False])
Return the sequence of NEF-partitions for this polytope.

INPUT:
keep_symmetric -- (default: False) if True, "-s" option will be
passed to nef.x in order to keep symmetric partitions.


NEF-partitions of the 3-dimensional octahedron:

sage: o = lattice_polytope.octahedron(3)
sage: o.nef_partitions()
[
[1, 1, 0, 1, 0, 0],
[1, 1, 1, 0, 0, 0],
[1, 1, 1, 1, 0, 0]
]


Now we compute NEF-partitions for the same octahedron without taking into account symmetries:

sage: o.nef_partitions(True)
[
[1, 1, 1, 0, 0, 1],
[1, 1, 0, 0, 1, 1],
[1, 1, 0, 1, 0, 1],
[1, 1, 0, 0, 0, 1],
[0, 1, 1, 1, 0, 1],
[0, 1, 1, 0, 0, 1],
[0, 1, 0, 1, 1, 1],
[0, 1, 0, 0, 1, 1],
[0, 1, 0, 1, 0, 1],
[1, 0, 1, 1, 1, 0],
[1, 0, 1, 0, 1, 1],
[1, 0, 1, 0, 0, 1],
[1, 0, 0, 1, 1, 1],
[1, 0, 0, 0, 1, 1],
[1, 0, 0, 1, 0, 1],
[0, 1, 1, 1, 1, 0],
[0, 0, 1, 1, 1, 1],
[0, 0, 1, 0, 1, 1],
[0, 0, 1, 1, 0, 1],
[0, 0, 0, 1, 1, 1],
[1, 1, 1, 1, 0, 0],
[1, 1, 1, 0, 1, 0]
]


NEF-partitions can be computed only for reflexive polytopes:

sage: m = matrix(ZZ, [[1, 0, 0, -1,  0,  0],
...                   [0, 1, 0,  0, -1,  0],
...                   [0, 0, 2,  0,  0, -1]])
...
sage: p = LatticePolytope(m)
sage: p.nef_partitions()
Traceback (most recent call last):
...
ValueError: The given polytope is not reflexive!
Polytope: A lattice polytope: 3-dimensional, 6 vertices.


 nef_x( self, keys)
Run nef.x wilth 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.


This call is used internally for computing NEF-partitions:

sage: o = lattice_polytope.octahedron(3)
sage: s = o.nef_x("-N -Lv -p")
sage: s                         # output contains random time
M:27 8 N:7 6  #part=5
3 6 Vertices in N-lattice:
0    0    0    1   -1    0
0    0    1    0    0   -1
-1    1    0    0    0    0
------------------------------
1    1    0    0    0    0  d=2  codim=2
0    0    1    0    0    1  d=2  codim=2
0    0    0    1    1    0  d=2  codim=2
P:0 V:1 4 5   (1 1) (1 1) (1 1)     0sec  0cpu
P:1 V:3 4 5   (0 2) (1 1) (2 0)     0sec  0cpu
P:3 V:4 5   (0 2) (1 1) (1 1)     0sec  0cpu
np=3 d:1 p:1    0sec     0cpu


 nfacets( self)
Return the number of facets of this polytope.

The number of facets of the 3-dimensional octahedron:

sage: o = lattice_polytope.octahedron(3)
sage: o.nfacets()
8


 npoints( self)
Return the number of lattice points of this polytope.

The number of lattice points of the 3-dimensional octahedron and its polar cube:

sage: o = lattice_polytope.octahedron(3)
sage: o.npoints()
7
sage: cube = o.polar()
sage: cube.npoints()
27


 nvertices( self)
Return the number of vertices of this polytope.

The number of vertices of the 3-dimensional octahedron and its polar cube:

sage: o = lattice_polytope.octahedron(3)
sage: o.nvertices()
6
sage: cube = o.polar()
sage: cube.nvertices()
8


 parent( self)
Return the set of all lattice polytopes.

sage: o = lattice_polytope.octahedron(3)
sage: o.parent()
Set of all Lattice Polytopes


 plot( self, [camera_center=None])
Draw a 3d picture of the polytope.

INPUT:
self -- polytope of dimension 3.
camera_center -- (default: random) location of center of
the camera (i.e., viewer)

OUTPUT:
-- a tachyon 3d raytracer plot of the polytope


The face colors are random.

Author: William Stein and Tom Boothby

sage: o = lattice_polytope.octahedron(3)
sage: o.plot().show()


 points( self)
Return all lattice points of this polytope as columns of a matrix.

The lattice points of the 3-dimensional octahedron and its polar cube:

sage: o = lattice_polytope.octahedron(3)
sage: o.points()
[ 1  0  0 -1  0  0  0]
[ 0  1  0  0 -1  0  0]
[ 0  0  1  0  0 -1  0]
sage: cube = o.polar()
sage: cube.points()
[-1  1 -1  1 -1  1 -1  1 -1 -1 -1 -1 -1  0  0  0  0  0  0  0  0  0  1  1  1
1  1]
[-1 -1  1  1 -1 -1  1  1 -1  0  0  0  1 -1 -1 -1  0  0  0  1  1  1 -1  0  0
0  1]
[ 1  1  1  1 -1 -1 -1 -1  0 -1  0  1  0 -1  0  1 -1  0  1 -1  0  1  0 -1  0
1  0]


 polar( self)
Return the polar polytope, if this polytope is reflexive.

The polar polytope to the 3-dimensional octahedron:

sage: o = lattice_polytope.octahedron(3)
sage: cube = o.polar()
sage: cube
A polytope polar to An octahedron: 3-dimensional, 8 vertices.


The polar polytope "remembers" the original one:

sage: cube.polar()
An octahedron: 3-dimensional, 6 vertices.
sage: cube.polar().polar() is cube
True


Only reflexive polytopes have polars:

sage: m = matrix(ZZ, [[1, 0, 0, -1,  0,  0],
...                   [0, 1, 0,  0, -1,  0],
...                   [0, 0, 2,  0,  0, -1]])
...
sage: p = LatticePolytope(m)
sage: p.polar()
Traceback (most recent call last):
...
ValueError: The given polytope is not reflexive!
Polytope: A lattice polytope: 3-dimensional, 6 vertices.


 poly_x( self, keys)
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.

OUTPUT:
the output of poly.x as a string.


This call is used for determining if a polytope is reflexive or not:

sage: o = lattice_polytope.octahedron(3)
sage: print o.poly_x("e")
8 3  Vertices of P-dual <-> 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: BIGO = lattice_polytope.octahedron(7)
sage: BIGO
An octahedron: 7-dimensional, 14 vertices.
sage: BIGO.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!
Polytope: An octahedron: 7-dimensional, 14 vertices.
Vertices:
[ 1  0  0  0  0  0  0 -1  0  0  0  0  0  0]
[ 0  1  0  0  0  0  0  0 -1  0  0  0  0  0]
[ 0  0  1  0  0  0  0  0  0 -1  0  0  0  0]
[ 0  0  0  1  0  0  0  0  0  0 -1  0  0  0]
[ 0  0  0  0  1  0  0  0  0  0  0 -1  0  0]
[ 0  0  0  0  0  1  0  0  0  0  0  0 -1  0]
[ 0  0  0  0  0  0  1  0  0  0  0  0  0 -1]
Output:
increase POLY_Dmax!


 show( self, [camera_center=None])
Draw a 3d picture of the polytope.

See self.plot? for more details.

 vertices( self)
Return vertices of this polytope as columns of a matrix.

The lattice points of the 3-dimensional octahedron and its polar cube:

sage: o = lattice_polytope.octahedron(3)
sage: o.vertices()
[ 1  0  0 -1  0  0]
[ 0  1  0  0 -1  0]
[ 0  0  1  0  0 -1]
sage: cube = o.polar()
sage: cube.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]


 __reduce__( self)
Reduction function. Does not store data that can be relatively fast recomputed.

 __setstate__( self, state)
Restores the state of pickled polytope.

 _compute_faces( self)
Compute and cache faces of this polytope.

If this polytope is reflexive and the polar polytope was already computed, computes faces of both in order to save time and preserve the one-to-one correspondence between the faces of this polytope of dimension d and the faces of the polar polytope of codimension d+1.

 _face_compute_points( self, face)
Compute lattice points of face.

 _face_split_points( self, face)
Compute boundary and interior lattice points of face.

 _palp( self, command)
Run command on vertices of this polytope.

Returns the output of command as a string.

Read equations of facets/vertices of polar polytope from string or file.

Read faces informations from string or file.

Read NEF-partitions from string or file.

 _repr_( self)
Return a string representation of this polytope.

Class: NEFPartition

class NEFPartition
Construct a NEF-partition from the given list.

A NEF-partition with parts, , is represented by a single list of lenght , in which the -th entry is the part number of the -th vertex of a polytope.

NOTE THAT NUMERATON OF PARTS STARTS WITH ZERO.

All elements of the list will be coerced to integers, so it is OK to use either a list of numbers or a list of strings:

sage: lattice_polytope.NEFPartition([1, 1, 0, 0, 0, 1])
[1, 1, 0, 0, 0, 1]
sage: lattice_polytope.NEFPartition(['1', '1', '0', '0', '0', '1'])
[1, 1, 0, 0, 0, 1]

 NEFPartition( self, data)
Construct a NEF-partition.

Functions: nparts, part, part_of_vertex

 nparts( self)
Return the number of parts of this partitions.

sage: nefp = lattice_polytope.NEFPartition([1, 1, 0, 0, 0, 1])
sage: nefp.nparts()
2


 part( self, i)
Return the i-th part of the partition.

NUMERATON OF PARTS STARTS WITH ZERO.

sage: nefp = lattice_polytope.NEFPartition([1, 1, 0, 0, 0, 1])
sage: nefp.part(0)
[2, 3, 4]
sage: nefp.part(1)
[0, 1, 5]


 part_of_vertex( self, i)
Return the index of the part containing the i-vertex.

nefp.part_of_vertex(i) is equivalent to nefp[i].

sage: nefp = lattice_polytope.NEFPartition([1, 1, 0, 0, 0, 1])
sage: nefp.part_of_vertex(3)
0
sage: nefp.part_of_vertex(5)
1
sage: nefp[3]
0
sage: nefp[5]
1


You cannot change a NEF-partition once it is constructed:

sage: nefp[3] = 1
Traceback (most recent call last):
...

Class: SetOfAllLatticePolytopesClass