Base class for polyhedra: Methods related to lattice points#
- class sage.geometry.polyhedron.base2.Polyhedron_base2(parent, Vrep, Hrep, Vrep_minimal=None, Hrep_minimal=None, pref_rep=None, mutable=False, **kwds)#
Bases:
sage.geometry.polyhedron.base1.Polyhedron_base1
Methods related to lattice points.
See
sage.geometry.polyhedron.base.Polyhedron_base
.- get_integral_point(index, **kwds)#
Return the
index
-th integral point in this polyhedron.This is equivalent to
sorted(self.integral_points())[index]
. However, so long asintegral_points_count()
does not need to enumerate all integral points, neither does this method. Hence it can be significantly faster. If the polyhedron is not compact, aValueError
is raised.INPUT:
index
– integer. The index of the integral point to be found. If this is not in [0,self.integral_point_count()
), anIndexError
is raised.**kwds
– optional keyword parameters that are passed tointegral_points_count()
.
ALGORITHM:
The function computes each of the components of the requested point in turn. To compute x_i, the ith component, it bisects the upper and lower bounds on x_i given by the bounding box. At each bisection, it uses
integral_points_count()
to determine on which side of the bisecting hyperplane the requested point lies.See also
EXAMPLES:
sage: P = Polyhedron(vertices=[(-1,-1),(1,0),(1,1),(0,1)]) sage: P.get_integral_point(1) (0, 0) sage: P.get_integral_point(4) (1, 1) sage: sorted(P.integral_points()) [(-1, -1), (0, 0), (0, 1), (1, 0), (1, 1)] sage: P.get_integral_point(5) Traceback (most recent call last): ... IndexError: ... sage: Q = Polyhedron([(1,3), (2, 7), (9, 77)]) sage: [Q.get_integral_point(i) for i in range(Q.integral_points_count())] == sorted(Q.integral_points()) True sage: Q.get_integral_point(0, explicit_enumeration_threshold=0, triangulation='cddlib') # optional - latte_int (1, 3) sage: Q.get_integral_point(0, explicit_enumeration_threshold=0, triangulation='cddlib', foo=True) # optional - latte_int Traceback (most recent call last): ... RuntimeError: ... sage: R = Polyhedron(vertices=[[1/2, 1/3]], rays=[[1, 1]]) sage: R.get_integral_point(0) Traceback (most recent call last): ... ValueError: ...
- h_star_vector()#
Return the \(h^*\)-vector of the lattice polytope.
The \(h^*\)-vector records the coefficients of the polynomial in the numerator of the Ehrhart series of a lattice polytope.
INPUT:
self
– A lattice polytope.
OUTPUT:
A list whose entries give the \(h^*\)-vector.
EXAMPLES:
The \(h^*\)-vector of a unimodular simplex S (a simplex with volume = \(\frac{1}{dim(S)!}\)) is always 1. Here we test this on simplices up to dimension 3:
sage: s1 = polytopes.simplex(1,backend='normaliz') # optional - pynormaliz sage: s2 = polytopes.simplex(2,backend='normaliz') # optional - pynormaliz sage: s3 = polytopes.simplex(3,backend='normaliz') # optional - pynormaliz sage: [s1.h_star_vector(),s2.h_star_vector(),s3.h_star_vector()] # optional - pynormaliz [[1], [1], [1]]
For a less trivial example, we compute the \(h^*\)-vector of the \(0/1\)-cube, which has the Eulerian numbers \((3,i)\) for \(i \in [0,2]\) as an \(h^*\)-vector:
sage: cube = polytopes.cube(intervals='zero_one', backend='normaliz') # optional - pynormaliz sage: cube.h_star_vector() # optional - pynormaliz [1, 4, 1] sage: from sage.combinat.combinat import eulerian_number sage: [eulerian_number(3,i) for i in range(3)] [1, 4, 1]
- integral_points(threshold=100000)#
Return the integral points in the polyhedron.
Uses either the naive algorithm (iterate over a rectangular bounding box) or triangulation + Smith form.
INPUT:
threshold
– integer (default: 100000). Use the naive algorithm as long as the bounding box is smaller than this.
OUTPUT:
The list of integral points in the polyhedron. If the polyhedron is not compact, a
ValueError
is raised.EXAMPLES:
sage: Polyhedron(vertices=[(-1,-1),(1,0),(1,1),(0,1)]).integral_points() ((-1, -1), (0, 0), (0, 1), (1, 0), (1, 1)) sage: simplex = Polyhedron([(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 = Polyhedron([(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 = Polyhedron([(2,3,7)]) sage: point.integral_points() ((2, 3, 7),) sage: empty = Polyhedron() 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 = Polyhedron(v); simplex A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 5 vertices sage: len(simplex.integral_points()) 49
A case where rounding in the right direction goes a long way:
sage: P = 1/10*polytopes.hypercube(14, backend='field') sage: P.integral_points() ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),)
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 = Polyhedron(v) sage: pts1 = P.integral_points() # Sage's own code sage: all(P.contains(p) for p in pts1) True sage: pts2 = LatticePolytope(v).points() # optional - palp sage: for p in pts1: p.set_immutable() sage: set(pts1) == set(pts2) # optional - palp True sage: timeit('Polyhedron(v).integral_points()') # not tested - random 625 loops, best of 3: 1.41 ms per loop sage: timeit('LatticePolytope(v).points()') # not tested - random 25 loops, best of 3: 17.2 ms per loop
- integral_points_count(**kwds)#
Return the number of integral points in the polyhedron.
This generic version of this method simply calls
integral_points()
.EXAMPLES:
sage: P = polytopes.cube() sage: P.integral_points_count() 27
We shrink the polyhedron a little bit:
sage: Q = P*(8/9) sage: Q.integral_points_count() 1
Same for a polyhedron whose coordinates are not rationals. Note that the answer is an integer even though there are no guarantees for exactness:
sage: Q = P*RDF(8/9) sage: Q.integral_points_count() 1
Unbounded polyhedra (with or without lattice points) are not supported:
sage: P = Polyhedron(vertices=[[1/2, 1/3]], rays=[[1, 1]]) sage: P.integral_points_count() Traceback (most recent call last): ... NotImplementedError: ... sage: P = Polyhedron(vertices=[[1, 1]], rays=[[1, 1]]) sage: P.integral_points_count() Traceback (most recent call last): ... NotImplementedError: ...
- is_lattice_polytope()#
Return whether the polyhedron is a lattice polytope.
OUTPUT:
True
if the polyhedron is compact and has only integral vertices,False
otherwise.EXAMPLES:
sage: polytopes.cross_polytope(3).is_lattice_polytope() True sage: polytopes.regular_polygon(5).is_lattice_polytope() # optional - sage.rings.number_field False
- lattice_polytope(envelope=False)#
Return an encompassing lattice polytope.
INPUT:
envelope
– boolean (default:False
). If the polyhedron has non-integral vertices, this option decides whether to return a strictly larger lattice polytope or raise aValueError
. This option has no effect if the polyhedron has already integral vertices.
OUTPUT:
A
LatticePolytope
. If the polyhedron is compact and has integral vertices, the lattice polytope equals the polyhedron. If the polyhedron is compact but has at least one non-integral vertex, a strictly larger lattice polytope is returned.If the polyhedron is not compact, a
NotImplementedError
is raised.If the polyhedron is not integral and
envelope=False
, aValueError
is raised.ALGORITHM:
For each non-integral vertex, a bounding box of integral points is added and the convex hull of these integral points is returned.
EXAMPLES:
First, a polyhedron with integral vertices:
sage: P = Polyhedron(vertices=[(1, 0), (0, 1), (-1, 0), (0, -1)]) sage: lp = P.lattice_polytope() sage: lp # optional - palp 2-d reflexive polytope #3 in 2-d lattice M sage: lp.vertices() M(-1, 0), M( 0, -1), M( 0, 1), M( 1, 0) in 2-d lattice M
Here is a polyhedron with non-integral vertices:
sage: P = Polyhedron( vertices = [(1/2, 1/2), (0, 1), (-1, 0), (0, -1)]) sage: lp = P.lattice_polytope() Traceback (most recent call last): ... ValueError: Some vertices are not integral. You probably want to add the argument "envelope=True" to compute an enveloping lattice polytope. sage: lp = P.lattice_polytope(True) sage: lp # optional - palp 2-d reflexive polytope #5 in 2-d lattice M sage: lp.vertices() M(-1, 0), M( 0, -1), M( 1, 1), M( 0, 1), M( 1, 0) in 2-d lattice M
- random_integral_point(**kwds)#
Return an integral point in this polyhedron chosen uniformly at random.
INPUT:
**kwds
– optional keyword parameters that are passed toget_integral_point()
.
OUTPUT:
The integral point in the polyhedron chosen uniformly at random. If the polyhedron is not compact, a
ValueError
is raised. If the polyhedron does not contain any integral points, anEmptySetError
is raised.See also
EXAMPLES:
sage: P = Polyhedron(vertices=[(-1,-1),(1,0),(1,1),(0,1)]) sage: P.random_integral_point() # random (0, 0) sage: P.random_integral_point() in P.integral_points() True sage: P.random_integral_point(explicit_enumeration_threshold=0, triangulation='cddlib') # random, optional - latte_int (1, 1) sage: P.random_integral_point(explicit_enumeration_threshold=0, triangulation='cddlib', foo=7) # optional - latte_int Traceback (most recent call last): ... RuntimeError: ... sage: Q = Polyhedron(vertices=[(2, 1/3)], rays=[(1, 2)]) sage: Q.random_integral_point() Traceback (most recent call last): ... ValueError: ... sage: R = Polyhedron(vertices=[(1/2, 0), (1, 1/2), (0, 1/2)]) sage: R.random_integral_point() Traceback (most recent call last): ... EmptySetError: ...