Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
""" Fast Lattice Polytopes using PPL.
The :func:`LatticePolytope_PPL` class is a thin wrapper around PPL polyhedra. Its main purpose is to be fast to construct, at the cost of being much less full-featured than the usual polyhedra. This makes it possible to iterate with it over the list of all 473800776 reflexive polytopes in 4 dimensions.
.. NOTE::
For general lattice polyhedra you should use :func:`~sage.geometry.polyhedron.constructor.Polyhedron` with ``base_ring=ZZ``.
The class derives from the PPL :class:`sage.libs.ppl.C_Polyhedron` class, so you can work with the underlying generator and constraint objects. However, integral points are generally represented by `\ZZ`-vectors. In the following, we always use *generator* to refer the PPL generator objects and *vertex* (or integral point) for the corresponding `\ZZ`-vector.
EXAMPLES::
sage: vertices = [(1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1), (-9, -6, -1, -1)] sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: P = LatticePolytope_PPL(vertices); P A 4-dimensional lattice polytope in ZZ^4 with 5 vertices sage: P.integral_points() ((-9, -6, -1, -1), (-3, -2, 0, 0), (-2, -1, 0, 0), (-1, -1, 0, 0), (-1, 0, 0, 0), (0, 0, 0, 0), (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 0, 1), (0, 0, 1, 0)) sage: P.integral_points_not_interior_to_facets() ((-9, -6, -1, -1), (-3, -2, 0, 0), (0, 0, 0, 0), (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 0, 1), (0, 0, 1, 0))
Fibrations of the lattice polytopes are defined as lattice sub-polytopes and give rise to fibrations of toric varieties for suitable fan refinements. We can compute them using :meth:`~LatticePolytope_PPL.fibration_generator` ::
sage: F = next(P.fibration_generator(2)) sage: F.vertices() ((1, 0, 0, 0), (0, 1, 0, 0), (-3, -2, 0, 0))
Finally, we can compute automorphisms and identify fibrations that only differ by a lattice automorphism::
sage: square = LatticePolytope_PPL((-1,-1),(-1,1),(1,-1),(1,1)) sage: fibers = [ f.vertices() for f in square.fibration_generator(1) ]; fibers [((1, 0), (-1, 0)), ((0, 1), (0, -1)), ((-1, -1), (1, 1)), ((-1, 1), (1, -1))] sage: square.pointsets_mod_automorphism(fibers) (frozenset({(0, -1), (0, 1)}), frozenset({(-1, -1), (1, 1)}))
AUTHORS:
- Volker Braun: initial version, 2012 """
######################################################################## # Copyright (C) 2012 Volker Braun <vbraun.name@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # # http://www.gnu.org/licenses/ ########################################################################
vector, zero_vector ) matrix, column_matrix, diagonal_matrix ) C_Polyhedron, Linear_Expression, Variable, point, ray, line, Generator, Generator_System, Generator_System_iterator ) C_Polyhedron, Linear_Expression, Variable, point, ray, line, Generator, Generator_System, Constraint_System, Poly_Con_Relation )
######################################################################## """ Return the appropriate class in the given dimension.
Helper function for :func:`LatticePolytope_PPL`. You should not have to use this function manually.
INPUT:
- ``dim`` -- integer. The ambient space dimenson.
OUTPUT:
The appropriate class for the lattice polytope.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import _class_for_LatticePolytope sage: _class_for_LatticePolytope(2) <class 'sage.geometry.polyhedron.ppl_lattice_polygon.LatticePolygon_PPL_class'> sage: _class_for_LatticePolytope(3) <class 'sage.geometry.polyhedron.ppl_lattice_polytope.LatticePolytope_PPL_class'> """
######################################################################## """ Construct a new instance of the PPL-based lattice polytope class.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: LatticePolytope_PPL((0,0),(1,0),(0,1)) A 2-dimensional lattice polytope in ZZ^2 with 3 vertices
sage: from sage.libs.ppl import point, Generator_System, C_Polyhedron, Linear_Expression, Variable sage: p = point(Linear_Expression([2,3],0)); p point(2/1, 3/1) sage: LatticePolytope_PPL(p) A 0-dimensional lattice polytope in ZZ^2 with 1 vertex
sage: P = C_Polyhedron(Generator_System(p)); P A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point sage: LatticePolytope_PPL(P) A 0-dimensional lattice polytope in ZZ^2 with 1 vertex
A ``TypeError`` is raised if the arguments do not specify a lattice polytope::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: LatticePolytope_PPL((0,0),(1/2,1)) Traceback (most recent call last): ... TypeError: no conversion of this rational to integer
sage: from sage.libs.ppl import point, Generator_System, C_Polyhedron, Linear_Expression, Variable sage: p = point(Linear_Expression([2,3],0), 5); p point(2/5, 3/5) sage: LatticePolytope_PPL(p) Traceback (most recent call last): ... TypeError: generator is not a lattice polytope generator
sage: P = C_Polyhedron(Generator_System(p)); P A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point sage: LatticePolytope_PPL(P) Traceback (most recent call last): ... TypeError: polyhedron has non-integral generators """ and isinstance(args[0], (list, tuple)) \ and isinstance(args[0][0], (list,tuple)): else: else:
######################################################################## """ The lattice polytope class.
You should use :func:`LatticePolytope_PPL` to construct instances.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: LatticePolytope_PPL((0,0),(1,0),(0,1)) A 2-dimensional lattice polytope in ZZ^2 with 3 vertices """
""" Return the string representation
OUTPUT:
A string.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: P = LatticePolytope_PPL((0,0),(1,0),(0,1)) sage: P A 2-dimensional lattice polytope in ZZ^2 with 3 vertices sage: P._repr_() 'A 2-dimensional lattice polytope in ZZ^2 with 3 vertices'
sage: LatticePolytope_PPL() The empty lattice polytope in ZZ^0 """ else:
""" Return whether the lattice polytope is compact.
OUTPUT:
Always ``True``, since polytopes are by definition compact.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: LatticePolytope_PPL((0,0),(1,0),(0,1)).is_bounded() True """
def n_vertices(self): """ Return the number of vertices.
OUTPUT:
An integer, the number of vertices.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: LatticePolytope_PPL((0,0,0), (1,0,0), (0,1,0)).n_vertices() 3 """
def is_simplex(self): r""" Return whether the polyhedron is a simplex.
OUTPUT:
Boolean, whether the polyhedron is a simplex (possibly of strictly smaller dimension than the ambient space).
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: LatticePolytope_PPL((0,0,0), (1,0,0), (0,1,0)).is_simplex() True """
def bounding_box(self): r""" Return the coordinates of a rectangular box containing the non-empty polytope.
OUTPUT:
A pair of tuples ``(box_min, box_max)`` where ``box_min`` are the coordinates of a point bounding the coordinates of the polytope from below and ``box_max`` bounds the coordinates from above.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: LatticePolytope_PPL((0,0),(1,0),(0,1)).bounding_box() ((0, 0), (1, 1)) """ raise ValueError('empty polytope is not allowed')
def n_integral_points(self): """ Return the number of integral points.
OUTPUT:
Integer. The number of integral points contained in the lattice polytope.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: LatticePolytope_PPL((0,0),(1,0),(0,1)).n_integral_points() 3 """ return tuple()
def integral_points(self): r""" Return the integral points in the polyhedron.
Uses the naive algorithm (iterate over a rectangular bounding box).
OUTPUT:
The list of integral points in the polyhedron. If the polyhedron is not compact, a ``ValueError`` is raised.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: LatticePolytope_PPL((-1,-1),(1,0),(1,1),(0,1)).integral_points() ((-1, -1), (0, 0), (0, 1), (1, 0), (1, 1))
sage: simplex = LatticePolytope_PPL((1,2,3), (2,3,7), (-2,-3,-11)) sage: simplex.integral_points() ((-2, -3, -11), (0, 0, -2), (1, 2, 3), (2, 3, 7))
The polyhedron need not be full-dimensional::
sage: simplex = LatticePolytope_PPL((1,2,3,5), (2,3,7,5), (-2,-3,-11,5)) sage: simplex.integral_points() ((-2, -3, -11, 5), (0, 0, -2, 5), (1, 2, 3, 5), (2, 3, 7, 5))
sage: point = LatticePolytope_PPL((2,3,7)) sage: point.integral_points() ((2, 3, 7),)
sage: empty = LatticePolytope_PPL() sage: empty.integral_points() ()
Here is a simplex where the naive algorithm of running over all points in a rectangular bounding box no longer works fast enough::
sage: v = [(1,0,7,-1), (-2,-2,4,-3), (-1,-1,-1,4), (2,9,0,-5), (-2,-1,5,1)] sage: simplex = LatticePolytope_PPL(v); simplex A 4-dimensional lattice polytope in ZZ^4 with 5 vertices sage: len(simplex.integral_points()) 49
Finally, the 3-d reflexive polytope number 4078::
sage: v = [(1,0,0), (0,1,0), (0,0,1), (0,0,-1), (0,-2,1), ....: (-1,2,-1), (-1,2,-2), (-1,1,-2), (-1,-1,2), (-1,-3,2)] sage: P = LatticePolytope_PPL(*v) sage: pts1 = P.integral_points() # Sage's own code sage: pts2 = LatticePolytope(v).points() # PALP sage: for p in pts1: p.set_immutable() sage: set(pts1) == set(pts2) True
sage: timeit('Polyhedron(v).integral_points()') # random output sage: timeit('LatticePolytope(v).points()') # random output sage: timeit('LatticePolytope_PPL(*v).integral_points()') # random output """
def _integral_points_saturating(self): """ Return the integral points together with information about which inequalities are saturated.
See :func:`~sage.geometry.integral_points.rectangular_box_points`.
OUTPUT:
A tuple of pairs (one for each integral point) consisting of a pair ``(point, Hrep)``, where ``point`` is the coordinate vector of the integral point and ``Hrep`` is the set of indices of the :meth:`minimized_constraints` that are saturated at the point.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: quad = LatticePolytope_PPL((-1,-1),(0,1),(1,0),(1,1)) sage: quad._integral_points_saturating() (((-1, -1), frozenset({0, 1})), ((0, 0), frozenset()), ((0, 1), frozenset({0, 3})), ((1, 0), frozenset({1, 2})), ((1, 1), frozenset({2, 3}))) """ return tuple() return_saturated=True)
def integral_points_not_interior_to_facets(self): """ Return the integral points not interior to facets
OUTPUT:
A tuple whose entries are the coordinate vectors of integral points not interior to facets (codimension one faces) of the lattice polytope.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: square = LatticePolytope_PPL((-1,-1),(-1,1),(1,-1),(1,1)) sage: square.n_integral_points() 9 sage: square.integral_points_not_interior_to_facets() ((-1, -1), (-1, 1), (0, 0), (1, -1), (1, 1)) """
def vertices(self): r""" Return the vertices as a tuple of `\ZZ`-vectors.
OUTPUT:
A tuple of `\ZZ`-vectors. Each entry is the coordinate vector of an integral points of the lattice polytope.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: p = LatticePolytope_PPL((-9,-6,-1,-1),(0,0,0,1),(0,0,1,0),(0,1,0,0),(1,0,0,0)) sage: p.vertices() ((-9, -6, -1, -1), (0, 0, 0, 1), (0, 0, 1, 0), (0, 1, 0, 0), (1, 0, 0, 0)) sage: p.minimized_generators() Generator_System {point(-9/1, -6/1, -1/1, -1/1), point(0/1, 0/1, 0/1, 1/1), point(0/1, 0/1, 1/1, 0/1), point(0/1, 1/1, 0/1, 0/1), point(1/1, 0/1, 0/1, 0/1)} """
""" Return the vertices saturating the constraint
INPUT:
- ``constraint`` -- a constraint (inequality or equation) of the polytope.
OUTPUT:
The tuple of vertices saturating the constraint. The vertices are returned as `\ZZ`-vectors, as in :meth:`vertices`.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: p = LatticePolytope_PPL((0,0),(0,1),(1,0)) sage: ieq = next(iter(p.constraints())); ieq x0>=0 sage: p.vertices_saturating(ieq) ((0, 0), (0, 1)) """
def is_full_dimensional(self): """ Return whether the lattice polytope is full dimensional.
OUTPUT:
Boolean. Whether the :meth:`affine_dimension` equals the ambient space dimension.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: p = LatticePolytope_PPL((0,0),(0,1)) sage: p.is_full_dimensional() False sage: q = LatticePolytope_PPL((0,0),(0,1),(1,0)) sage: q.is_full_dimensional() True """
""" Generate the lattice polytope fibrations.
For the purposes of this function, a lattice polytope fiber is a sub-lattice polytope. Projecting the plane spanned by the subpolytope to a point yields another lattice polytope, the base of the fibration.
INPUT:
- ``dim`` -- integer. The dimension of the lattice polytope fiber.
OUTPUT:
A generator yielding the distinct lattice polytope fibers of given dimension.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: p = LatticePolytope_PPL((-9,-6,-1,-1),(0,0,0,1),(0,0,1,0),(0,1,0,0),(1,0,0,0)) sage: list( p.fibration_generator(2) ) [A 2-dimensional lattice polytope in ZZ^4 with 3 vertices] """ # "points" are the potential vertices of the fiber. They are # in the $codim$-skeleton of the polytope, which is contained # in the points that saturate at least $dim$ equations.
# iterate over point combinations subject to all points being on one facet. else: else:
continue continue
""" Return ``pointsets`` modulo the automorphisms of ``self``.
INPUT:
- ``polytopes`` a tuple/list/iterable of subsets of the integral points of ``self``.
OUTPUT:
Representatives of the point sets modulo the :meth:`lattice_automorphism_group` of ``self``.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: square = LatticePolytope_PPL((-1,-1),(-1,1),(1,-1),(1,1)) sage: fibers = [ f.vertices() for f in square.fibration_generator(1) ] sage: square.pointsets_mod_automorphism(fibers) (frozenset({(0, -1), (0, 1)}), frozenset({(-1, -1), (1, 1)}))
sage: cell24 = LatticePolytope_PPL( ....: (1,0,0,0),(0,1,0,0),(0,0,1,0),(0,0,0,1),(1,-1,-1,1),(0,0,-1,1), ....: (0,-1,0,1),(-1,0,0,1),(1,0,0,-1),(0,1,0,-1),(0,0,1,-1),(-1,1,1,-1), ....: (1,-1,-1,0),(0,0,-1,0),(0,-1,0,0),(-1,0,0,0),(1,-1,0,0),(1,0,-1,0), ....: (0,1,1,-1),(-1,1,1,0),(-1,1,0,0),(-1,0,1,0),(0,-1,-1,1),(0,0,0,-1)) sage: fibers = [ f.vertices() for f in cell24.fibration_generator(2) ] sage: cell24.pointsets_mod_automorphism(fibers) # long time (frozenset({(-1, 0, 1, 0), (0, -1, -1, 1), (0, 1, 1, -1), (1, 0, -1, 0)}), frozenset({(-1, 0, 0, 0), (-1, 0, 0, 1), (0, 0, 0, -1), (0, 0, 0, 1), (1, 0, 0, -1), (1, 0, 0, 0)})) """ point_labels=tuple(range(len(points))))
def ambient_space(self): r""" Return the ambient space.
OUTPUT:
The free module `\ZZ^d`, where `d` is the ambient space dimension.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: point = LatticePolytope_PPL((1,2,3)) sage: point.ambient_space() Ambient free module of rank 3 over the principal ideal domain Integer Ring """
r""" Test whether point is contained in the polytope.
INPUT:
- ``point_coordinates`` -- a list/tuple/iterable of rational numbers. The coordinates of the point.
OUTPUT:
Boolean.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: line = LatticePolytope_PPL((1,2,3), (-1,-2,-3)) sage: line.contains([0,0,0]) True sage: line.contains([1,0,0]) False """
def contains_origin(self): """ Test whether the polytope contains the origin
OUTPUT:
Boolean.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: LatticePolytope_PPL((1,2,3), (-1,-2,-3)).contains_origin() True sage: LatticePolytope_PPL((1,2,5), (-1,-2,-3)).contains_origin() False """
def affine_space(self): r""" Return the affine space spanned by the polytope.
OUTPUT:
The free module `\ZZ^n`, where `n` is the dimension of the affine space spanned by the points of the polytope.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: point = LatticePolytope_PPL((1,2,3)) sage: point.affine_space() Free module of degree 3 and rank 0 over Integer Ring Echelon basis matrix: [] sage: line = LatticePolytope_PPL((1,1,1), (1,2,3)) sage: line.affine_space() Free module of degree 3 and rank 1 over Integer Ring Echelon basis matrix: [0 1 2] """
""" Return the lattice polytope restricted to :meth:`affine_space`.
OUTPUT:
A new, full-dimensional lattice polytope.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: poly_4d = LatticePolytope_PPL((-9,-6,0,0),(0,1,0,0),(1,0,0,0)); poly_4d A 2-dimensional lattice polytope in ZZ^4 with 3 vertices sage: poly_4d.space_dimension() 4 sage: poly_2d = poly_4d.affine_lattice_polytope(); poly_2d A 2-dimensional lattice polytope in ZZ^2 with 3 vertices sage: poly_2d.space_dimension() 2 """ else: v0 = vertices[0] vertices = [ V.coordinates(v-v0) for v in self.vertices() ]
""" The projection that maps the sub-polytope ``fiber`` to a single point.
OUTPUT:
The quotient module of the ambient space modulo the :meth:`affine_space` spanned by the fiber.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: poly = LatticePolytope_PPL((-9,-6,-1,-1),(0,0,0,1),(0,0,1,0),(0,1,0,0),(1,0,0,0)) sage: fiber = next(poly.fibration_generator(2)) sage: poly.base_projection(fiber) Finitely generated module V/W over Integer Ring with invariants (0, 0) """
""" The projection that maps the sub-polytope ``fiber`` to a single point.
OUTPUT:
An integer matrix that represents the projection to the base.
.. SEEALSO::
The :meth:`base_projection` yields equivalent information, and is easier to use. However, just returning the matrix has lower overhead.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: poly = LatticePolytope_PPL((-9,-6,-1,-1),(0,0,0,1),(0,0,1,0),(0,1,0,0),(1,0,0,0)) sage: fiber = next(poly.fibration_generator(2)) sage: poly.base_projection_matrix(fiber) [0 0 1 0] [0 0 0 1]
Note that the basis choice in :meth:`base_projection` for the quotient is usually different::
sage: proj = poly.base_projection(fiber) sage: proj_matrix = poly.base_projection_matrix(fiber) sage: [ proj(p) for p in poly.integral_points() ] [(-1, -1), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (1, 0), (0, 1)] sage: [ proj_matrix*p for p in poly.integral_points() ] [(-1, -1), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 1), (1, 0)] """
""" Return the primitive lattice vectors that generate the direction given by the base projection of points.
INPUT:
- ``fiber`` -- a sub-lattice polytope defining the :meth:`base_projection`.
- ``points`` -- the points to project to the base.
OUTPUT:
A tuple of primitive `\ZZ`-vectors.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: poly = LatticePolytope_PPL((-9,-6,-1,-1),(0,0,0,1),(0,0,1,0),(0,1,0,0),(1,0,0,0)) sage: fiber = next(poly.fibration_generator(2)) sage: poly.base_rays(fiber, poly.integral_points_not_interior_to_facets()) ((-1, -1), (0, 1), (1, 0))
sage: p = LatticePolytope_PPL((1,0),(1,2),(-1,0)) sage: f = LatticePolytope_PPL((1,0),(-1,0)) sage: p.base_rays(f, p.integral_points()) ((1),) """
def has_IP_property(self): """ Whether the lattice polytope has the IP property.
That is, the polytope is full-dimensional and the origin is a interior point not on the boundary.
OUTPUT:
Boolean.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: LatticePolytope_PPL((-1,-1),(0,1),(1,0)).has_IP_property() True sage: LatticePolytope_PPL((-1,-1),(1,1)).has_IP_property() False """
r""" Return the restricted automorphism group.
First, let the linear automorphism group be the subgroup of the Euclidean group `E(d) = GL(d,\RR) \ltimes \RR^d` preserving the `d`-dimensional polyhedron. The Euclidean group acts in the usual way `\vec{x}\mapsto A\vec{x}+b` on the ambient space. The restricted automorphism group is the subgroup of the linear automorphism group generated by permutations of vertices. If the polytope is full-dimensional, it is equal to the full (unrestricted) automorphism group.
INPUT:
- ``vertex_labels`` -- a tuple or ``None`` (default). The labels of the vertices that will be used in the output permutation group. By default, the vertices are used themselves.
OUTPUT:
A :class:`PermutationGroup<sage.groups.perm_gps.permgroup.PermutationGroup_generic>` acting on the vertices (or the ``vertex_labels``, if specified).
REFERENCES:
[BSS2009]_
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: Z3square = LatticePolytope_PPL((0,0), (1,2), (2,1), (3,3)) sage: Z3square.restricted_automorphism_group(vertex_labels=(1,2,3,4)) Permutation Group with generators [(2,3), (1,2)(3,4), (1,4)] sage: G = Z3square.restricted_automorphism_group(); G Permutation Group with generators [((1,2),(2,1)), ((0,0),(1,2))((2,1),(3,3)), ((0,0),(3,3))] sage: tuple(G.domain()) == Z3square.vertices() True sage: G.orbit(Z3square.vertices()[0]) ((0, 0), (1, 2), (3, 3), (2, 1))
sage: cell24 = LatticePolytope_PPL( ....: (1,0,0,0),(0,1,0,0),(0,0,1,0),(0,0,0,1),(1,-1,-1,1),(0,0,-1,1), ....: (0,-1,0,1),(-1,0,0,1),(1,0,0,-1),(0,1,0,-1),(0,0,1,-1),(-1,1,1,-1), ....: (1,-1,-1,0),(0,0,-1,0),(0,-1,0,0),(-1,0,0,0),(1,-1,0,0),(1,0,-1,0), ....: (0,1,1,-1),(-1,1,1,0),(-1,1,0,0),(-1,0,1,0),(0,-1,-1,1),(0,0,0,-1)) sage: cell24.restricted_automorphism_group().cardinality() 1152 """ return self.affine_lattice_polytope().\ restricted_automorphism_group(vertex_labels=vertex_labels) # good coordinates for the vertices
# Finally, construct the graph
""" The integral subgroup of the restricted automorphism group.
INPUT:
- ``points`` -- A tuple of coordinate vectors or ``None`` (default). If specified, the points must form complete orbits under the lattice automorphism group. If ``None`` all vertices are used.
- ``point_labels`` -- A tuple of labels for the ``points`` or ``None`` (default). These will be used as labels for the do permutation group. If ``None`` the ``points`` will be used themselves.
OUTPUT:
The integral subgroup of the restricted automorphism group acting on the given ``points``, or all vertices if not specified.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: Z3square = LatticePolytope_PPL((0,0), (1,2), (2,1), (3,3)) sage: Z3square.lattice_automorphism_group() Permutation Group with generators [(), ((1,2),(2,1)), ((0,0),(3,3)), ((0,0),(3,3))((1,2),(2,1))]
sage: G1 = Z3square.lattice_automorphism_group(point_labels=(1,2,3,4)); G1 Permutation Group with generators [(), (2,3), (1,4), (1,4)(2,3)] sage: G1.cardinality() 4
sage: G2 = Z3square.restricted_automorphism_group(vertex_labels=(1,2,3,4)); G2 Permutation Group with generators [(2,3), (1,2)(3,4), (1,4)] sage: G2.cardinality() 8
sage: points = Z3square.integral_points(); points ((0, 0), (1, 1), (1, 2), (2, 1), (2, 2), (3, 3)) sage: Z3square.lattice_automorphism_group(points, point_labels=(1,2,3,4,5,6)) Permutation Group with generators [(), (3,4), (1,6)(2,5), (1,6)(2,5)(3,4)]
Point labels also work for lattice polytopes that are not full-dimensional, see :trac:`16669`::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: lp = LatticePolytope_PPL((1,0,0),(0,1,0),(-1,-1,0)) sage: lp.lattice_automorphism_group(point_labels=(0,1,2)) Permutation Group with generators [(), (1,2), (0,1), (0,1,2), (0,2,1), (0,2)] """ point_labels=point_labels)
vertex_labels=tuple(range(len(vertices)))) for p in points ]
""" Generate the maximal lattice sub-polytopes.
OUTPUT:
A generator yielding the maximal (with respect to inclusion) lattice sub polytopes. That is, each can be gotten as the convex hull of the integral points of ``self`` with one vertex removed.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: P = LatticePolytope_PPL((1,0,0), (0,1,0), (0,0,1), (-1,-1,-1)) sage: for p in P.sub_polytope_generator(): ....: print(p.vertices()) ((0, 0, 0), (0, 0, 1), (0, 1, 0), (1, 0, 0)) ((-1, -1, -1), (0, 0, 0), (0, 1, 0), (1, 0, 0)) ((-1, -1, -1), (0, 0, 0), (0, 0, 1), (1, 0, 0)) ((-1, -1, -1), (0, 0, 0), (0, 0, 1), (0, 1, 0)) """
def _find_isomorphism_to_subreflexive_polytope(self): """ Find an isomorphism to a sub-polytope of a maximal reflexive polytope.
OUTPUT:
A tuple consisting of the ambient reflexive polytope, the subpolytope, and the embedding of ``self`` into the ambient polytope.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: polygon = LatticePolytope_PPL((0,0,2,1),(0,1,2,0),(2,3,0,0),(2,0,0,3)) sage: polygon._find_isomorphism_to_subreflexive_polytope() (A 2-dimensional lattice polytope in ZZ^2 with 3 vertices, A 2-dimensional lattice polytope in ZZ^2 with 4 vertices, The map A*x+b with A= [ 1 1] [ 0 1] [-1 -1] [ 1 0] b = (-1, 0, 3, 0)) sage: ambient, sub, embedding = _ sage: ambient.vertices() ((0, 0), (0, 3), (3, 0)) sage: sub.vertices() ((0, 1), (3, 0), (0, 3), (1, 0)) """ LatticePolytopesNotIsomorphicError, LatticePolytopeNoEmbeddingError LatticePolytopeNoEmbeddingError
""" Find an embedding as a sub-polytope of a maximal reflexive polytope.
INPUT:
- ``hom`` -- string. One of ``'hom'`` (default), ``'polytope'``, or ``points``. How the embedding is returned. See the output section for details.
OUTPUT:
An embedding into a reflexive polytope. Depending on the ``output`` option slightly different data is returned.
- If ``output='hom'``, a map from a reflexive polytope onto ``self`` is returned.
- If ``output='polytope'``, a reflexive polytope that contains ``self`` (up to a lattice linear transformation) is returned. That is, the domain of the ``output='hom'`` map is returned. If the affine span of ``self`` is less or equal 2-dimensional, the output is one of the following three possibilities:
:func:`~sage.geometry.polyhedron.ppl_lattice_polygon.polar_P2_polytope`, :func:`~sage.geometry.polyhedron.ppl_lattice_polygon.polar_P1xP1_polytope`, or :func:`~sage.geometry.polyhedron.ppl_lattice_polygon.polar_P2_112_polytope`.
- If ``output='points'``, a dictionary containing the integral points of ``self`` as keys and the corresponding integral point of the reflexive polytope as value.
If there is no such embedding, a :class:`~sage.geometry.polyhedron.lattice_euclidean_group_element.LatticePolytopeNoEmbeddingError` is raised. Even if it exists, the ambient reflexive polytope is usually not uniquely determined an a random but fixed choice will be returned.
EXAMPLES::
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: polygon = LatticePolytope_PPL((0,0,2,1),(0,1,2,0),(2,3,0,0),(2,0,0,3)) sage: polygon.embed_in_reflexive_polytope() The map A*x+b with A= [ 1 1] [ 0 1] [-1 -1] [ 1 0] b = (-1, 0, 3, 0) sage: polygon.embed_in_reflexive_polytope('polytope') A 2-dimensional lattice polytope in ZZ^2 with 3 vertices sage: polygon.embed_in_reflexive_polytope('points') {(0, 0, 2, 1): (1, 0), (0, 1, 2, 0): (0, 1), (1, 0, 1, 2): (2, 0), (1, 1, 1, 1): (1, 1), (1, 2, 1, 0): (0, 2), (2, 0, 0, 3): (3, 0), (2, 1, 0, 2): (2, 1), (2, 2, 0, 1): (1, 2), (2, 3, 0, 0): (0, 3)}
sage: LatticePolytope_PPL((0,0), (4,0), (0,4)).embed_in_reflexive_polytope() Traceback (most recent call last): ... LatticePolytopeNoEmbeddingError: not a sub-polytope of a reflexive polygon """ raise NotImplementedError('can only embed in reflexive polygons') else: raise ValueError('output='+str(output)+' is not valid.')
|