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 """ if self.is_empty(): return tuple() box_min, box_max = self.bounding_box() from sage.geometry.integral_points import rectangular_box_points return rectangular_box_points(list(box_min), list(box_max), self, count_only=True)
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}))) """ if self.is_empty(): return tuple() box_min, box_max = self.bounding_box() from sage.geometry.integral_points import rectangular_box_points points = rectangular_box_points(list(box_min), list(box_max), self, return_saturated=True) if not self.n_integral_points.is_in_cache(): self.n_integral_points.set_cache(len(points)) if not self.integral_points.is_in_cache(): self.integral_points.set_cache(tuple(p[0] for p in points)) return points
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 intgeral 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}))) """ if self.is_empty(): return tuple() box_min, box_max = self.bounding_box() from sage.geometry.integral_points import rectangular_box_points points = rectangular_box_points(list(box_min), list(box_max), self, return_saturated=True) if not self.n_integral_points.is_in_cache(): self.n_integral_points.set_cache(len(points)) if not self.integral_points.is_in_cache(): self.integral_points.set_cache(tuple(p[0] for p in points)) return points
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 """ if self.is_empty(): return tuple() box_min, box_max = self.bounding_box() from sage.geometry.integral_points import rectangular_box_points points = rectangular_box_points(list(box_min), list(box_max), self) if not self.n_integral_points.is_in_cache(): self.n_integral_points.set_cache(len(points)) return points
def integral_points(self, threshold=10000): r""" 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: 10000); use the naïve 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)], # optional - pynormaliz ....: backend='normaliz').integral_points() ((-1, -1), (0, 0), (0, 1), (1, 0), (1, 1)) sage: simplex = Polyhedron([(1,2,3), (2,3,7), (-2,-3,-11)], # optional - pynormaliz ....: backend='normaliz') sage: simplex.integral_points() # optional - pynormaliz ((-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)], # optional - pynormaliz ....: backend='normaliz') sage: simplex.integral_points() # optional - pynormaliz ((-2, -3, -11, 5), (0, 0, -2, 5), (1, 2, 3, 5), (2, 3, 7, 5)) sage: point = Polyhedron([(2,3,7)], # optional - pynormaliz ....: backend='normaliz') sage: point.integral_points() # optional - pynormaliz ((2, 3, 7),) sage: empty = Polyhedron(backend='normaliz') # optional - pynormaliz sage: empty.integral_points() # optional - pynormaliz () 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, backend='normaliz'); simplex # optional - pynormaliz A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 5 vertices sage: len(simplex.integral_points()) # optional - pynormaliz 49 A rather thin polytope for which the bounding box method would be a very bad idea (note this is a rational (non-lattice) polytope, so the other backends use the bounding box method):: sage: P = Polyhedron(vertices=((0, 0), (178933,37121))) + 1/1000*polytopes.hypercube(2) sage: P = Polyhedron(vertices=P.vertices_list(), # optional - pynormaliz ....: backend='normaliz') sage: len(P.integral_points()) # optional - pynormaliz 434 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, backend='normaliz') # optional - pynormaliz sage: pts1 = P.integral_points() # optional - pynormaliz sage: all(P.contains(p) for p in pts1) # optional - pynormaliz True sage: pts2 = LatticePolytope(v).points() # PALP sage: for p in pts1: p.set_immutable() # optional - pynormaliz sage: set(pts1) == set(pts2) # optional - pynormaliz True sage: timeit('Polyhedron(v, backend='normaliz').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 TESTS: Test some trivial cases (see :trac:`17937`): Empty polyhedron in 1 dimension:: sage: P = Polyhedron(ambient_dim=1, backend='normaliz') # optional - pynormaliz sage: P.integral_points() # optional - pynormaliz () Empty polyhedron in 0 dimensions:: sage: P = Polyhedron(ambient_dim=0, backend='normaliz') # optional - pynormaliz sage: P.integral_points() # optional - pynormaliz () Single point in 1 dimension:: sage: P = Polyhedron([[3]], backend='normaliz') # optional - pynormaliz sage: P.integral_points() # optional - pynormaliz ((3),) Single non-integral point in 1 dimension:: sage: P = Polyhedron([[1/2]], backend='normaliz') # optional - pynormaliz sage: P.integral_points() # optional - pynormaliz () Single point in 0 dimensions:: sage: P = Polyhedron([[]], backend='normaliz') # optional - pynormaliz sage: P.integral_points() # optional - pynormaliz ((),) A polytope with no integral points (:trac:`22938`):: sage: ieqs = [[1, 2, -1, 0], [0, -1, 2, -1], [0, 0, -1, 2], ....: [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, -1], ....: [-1, -1, -1, -1], [1, 1, 0, 0], [1, 0, 1, 0], ....: [1, 0, 0, 1]] sage: P = Polyhedron(ieqs=ieqs, backend='normaliz') # optional - pynormaliz sage: P.bounding_box() # optional - pynormaliz ((-3/4, -1/2, -1/4), (-1/2, -1/4, 0)) sage: P.bounding_box(integral_hull=True) # optional - pynormaliz (None, None) sage: P.integral_points() # optional - pynormaliz () """ import PyNormaliz if not self.is_compact(): raise ValueError( 'can only enumerate points in a compact polyhedron') # Trivial cases: polyhedron with 0 or 1 vertices if self.n_vertices() == 0: return () if self.n_vertices() == 1: v = self.vertices_list()[0] try: return (vector(ZZ, v), ) except TypeError: # vertex not integral return () # for small bounding boxes, it is faster to naively iterate over the points of the box if threshold > 1: box_min, box_max = self.bounding_box(integral_hull=True) if box_min is None: return () box_points = prod( max_coord - min_coord + 1 for min_coord, max_coord in zip(box_min, box_max)) if box_points < threshold: from sage.geometry.integral_points import rectangular_box_points return rectangular_box_points(list(box_min), list(box_max), self) # Compute with normaliz points = [] cone = self._normaliz_cone assert cone for g in PyNormaliz.NmzResult(cone, "ModuleGenerators"): assert g[-1] == 1 points.append(vector(ZZ, g[:-1])) return tuple(points)
def integral_points(self, threshold=10000): r""" 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: 10000); use the naïve 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)], # optional - pynormaliz ....: backend='normaliz').integral_points() ((-1, -1), (0, 0), (0, 1), (1, 0), (1, 1)) sage: simplex = Polyhedron([(1,2,3), (2,3,7), (-2,-3,-11)], # optional - pynormaliz ....: backend='normaliz') sage: simplex.integral_points() # optional - pynormaliz ((-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)], # optional - pynormaliz ....: backend='normaliz') sage: simplex.integral_points() # optional - pynormaliz ((-2, -3, -11, 5), (0, 0, -2, 5), (1, 2, 3, 5), (2, 3, 7, 5)) sage: point = Polyhedron([(2,3,7)], # optional - pynormaliz ....: backend='normaliz') sage: point.integral_points() # optional - pynormaliz ((2, 3, 7),) sage: empty = Polyhedron(backend='normaliz') # optional - pynormaliz sage: empty.integral_points() # optional - pynormaliz () 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, backend='normaliz'); simplex # optional - pynormaliz A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 5 vertices sage: len(simplex.integral_points()) # optional - pynormaliz 49 A rather thin polytope for which the bounding box method would be a very bad idea (note this is a rational (non-lattice) polytope, so the other backends use the bounding box method):: sage: P = Polyhedron(vertices=((0, 0), (178933,37121))) + 1/1000*polytopes.hypercube(2) sage: P = Polyhedron(vertices=P.vertices_list(), # optional - pynormaliz ....: backend='normaliz') sage: len(P.integral_points()) # optional - pynormaliz 434 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, backend='normaliz') # optional - pynormaliz sage: pts1 = P.integral_points() # optional - pynormaliz sage: all(P.contains(p) for p in pts1) # optional - pynormaliz True sage: pts2 = LatticePolytope(v).points() # PALP sage: for p in pts1: p.set_immutable() # optional - pynormaliz sage: set(pts1) == set(pts2) # optional - pynormaliz True sage: timeit('Polyhedron(v, backend='normaliz').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 TESTS: Test some trivial cases (see :trac:`17937`): Empty polyhedron in 1 dimension:: sage: P = Polyhedron(ambient_dim=1, backend='normaliz') # optional - pynormaliz sage: P.integral_points() # optional - pynormaliz () Empty polyhedron in 0 dimensions:: sage: P = Polyhedron(ambient_dim=0, backend='normaliz') # optional - pynormaliz sage: P.integral_points() # optional - pynormaliz () Single point in 1 dimension:: sage: P = Polyhedron([[3]], backend='normaliz') # optional - pynormaliz sage: P.integral_points() # optional - pynormaliz ((3),) Single non-integral point in 1 dimension:: sage: P = Polyhedron([[1/2]], backend='normaliz') # optional - pynormaliz sage: P.integral_points() # optional - pynormaliz () Single point in 0 dimensions:: sage: P = Polyhedron([[]], backend='normaliz') # optional - pynormaliz sage: P.integral_points() # optional - pynormaliz ((),) A polytope with no integral points (:trac:`22938`):: sage: ieqs = [[1, 2, -1, 0], [0, -1, 2, -1], [0, 0, -1, 2], ....: [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, -1], ....: [-1, -1, -1, -1], [1, 1, 0, 0], [1, 0, 1, 0], ....: [1, 0, 0, 1]] sage: P = Polyhedron(ieqs=ieqs, backend='normaliz') # optional - pynormaliz sage: P.bounding_box() # optional - pynormaliz ((-3/4, -1/2, -1/4), (-1/2, -1/4, 0)) sage: P.bounding_box(integral_hull=True) # optional - pynormaliz (None, None) sage: P.integral_points() # optional - pynormaliz () Check the polytopes from :trac:`22984`:: sage: base = [[0, 2, 0, -1, 0, 0, 0, 0, 0], ....: [0, 0, 2, 0, -1, 0, 0, 0, 0], ....: [1, -1, 0, 2, -1, 0, 0, 0, 0], ....: [0, 0, -1, -1, 2, -1, 0, 0, 0], ....: [0, 0, 0, 0, -1, 2, -1, 0, 0], ....: [0, 0, 0, 0, 0, -1, 2, -1, 0], ....: [1, 0, 0, 0, 0, 0, -1, 2, -1], ....: [0, 0, 0, 0, 0, 0, 0, -1, 2], ....: [0, -1, 0, 0, 0, 0, 0, 0, 0], ....: [0, 0, -1, 0, 0, 0, 0, 0, 0], ....: [0, 0, 0, -1, 0, 0, 0, 0, 0], ....: [0, 0, 0, 0, -1, 0, 0, 0, 0], ....: [0, 0, 0, 0, 0, -1, 0, 0, 0], ....: [0, 0, 0, 0, 0, 0, -1, 0, 0], ....: [0, 0, 0, 0, 0, 0, 0, -1, 0], ....: [0, 0, 0, 0, 0, 0, 0, 0, -1], ....: [-1, -1, -1, -1, -1, -1, -1, -1, -1]] sage: ieqs = base + [ ....: [2, 1, 0, 0, 0, 0, 0, 0, 0], ....: [4, 0, 1, 0, 0, 0, 0, 0, 0], ....: [4, 0, 0, 1, 0, 0, 0, 0, 0], ....: [7, 0, 0, 0, 1, 0, 0, 0, 0], ....: [6, 0, 0, 0, 0, 1, 0, 0, 0], ....: [4, 0, 0, 0, 0, 0, 1, 0, 0], ....: [2, 0, 0, 0, 0, 0, 0, 1, 0], ....: [1, 0, 0, 0, 0, 0, 0, 0, 1]] sage: P = Polyhedron(ieqs=ieqs, backend='normaliz') # optional - pynormaliz sage: P.integral_points() # optional - pynormaliz ((-2, -2, -4, -5, -4, -3, -2, -1), (-2, -2, -4, -5, -4, -3, -2, 0), (-1, -2, -3, -4, -3, -2, -2, -1), (-1, -2, -3, -4, -3, -2, -1, 0), (-1, -1, -2, -2, -2, -2, -2, -1), (-1, -1, -2, -2, -1, -1, -1, 0), (-1, -1, -2, -2, -1, 0, 0, 0), (-1, 0, -2, -2, -2, -2, -2, -1), (0, -1, -1, -2, -2, -2, -2, -1), (0, 0, -1, -1, -1, -1, -1, 0)) sage: ieqs = base + [ ....: [3, 1, 0, 0, 0, 0, 0, 0, 0], ....: [4, 0, 1, 0, 0, 0, 0, 0, 0], ....: [6, 0, 0, 1, 0, 0, 0, 0, 0], ....: [8, 0, 0, 0, 1, 0, 0, 0, 0], ....: [6, 0, 0, 0, 0, 1, 0, 0, 0], ....: [4, 0, 0, 0, 0, 0, 1, 0, 0], ....: [2, 0, 0, 0, 0, 0, 0, 1, 0], ....: [1, 0, 0, 0, 0, 0, 0, 0, 1]] sage: P = Polyhedron(ieqs=ieqs, backend='normaliz') # optional - pynormaliz sage: P.integral_points() # optional - pynormaliz ((-3, -4, -6, -8, -6, -4, -2, -1), (-3, -4, -6, -8, -6, -4, -2, 0), (-2, -2, -4, -5, -4, -3, -2, -1), (-2, -2, -4, -5, -4, -3, -2, 0), (-1, -2, -3, -4, -3, -2, -2, -1), (-1, -2, -3, -4, -3, -2, -1, 0), (-1, -1, -2, -2, -2, -2, -2, -1), (-1, -1, -2, -2, -1, -1, -1, 0), (-1, -1, -2, -2, -1, 0, 0, 0), (-1, 0, -2, -2, -2, -2, -2, -1), (0, -1, -1, -2, -2, -2, -2, -1), (0, 0, -1, -1, -1, -1, -1, 0)) """ import PyNormaliz if not self.is_compact(): raise ValueError('can only enumerate points in a compact polyhedron') # Trivial cases: polyhedron with 0 or 1 vertices if self.n_vertices() == 0: return () if self.n_vertices() == 1: v = self.vertices_list()[0] try: return (vector(ZZ, v),) except TypeError: # vertex not integral return () # for small bounding boxes, it is faster to naively iterate over the points of the box if threshold > 1: box_min, box_max = self.bounding_box(integral_hull=True) if box_min is None: return () box_points = prod(max_coord-min_coord+1 for min_coord, max_coord in zip(box_min, box_max)) if box_points<threshold: from sage.geometry.integral_points import rectangular_box_points return rectangular_box_points(list(box_min), list(box_max), self) # Compute with normaliz points = [] cone = self._normaliz_cone assert cone for g in PyNormaliz.NmzResult(cone, "ModuleGenerators"): assert g[-1] == 1 points.append(vector(ZZ, g[:-1])) return tuple(points)
def integral_points(self, threshold=100000): r""" 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() # PALP sage: for p in pts1: p.set_immutable() sage: set(pts1) == set(pts2) 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 TESTS: Test some trivial cases (see :trac:`17937`):: sage: P = Polyhedron(ambient_dim=1) # empty polyhedron in 1 dimension sage: P.integral_points() () sage: P = Polyhedron(ambient_dim=0) # empty polyhedron in 0 dimensions sage: P.integral_points() () sage: P = Polyhedron([[3]]) # single point in 1 dimension sage: P.integral_points() ((3),) sage: P = Polyhedron([[1/2]]) # single non-integral point in 1 dimension sage: P.integral_points() () sage: P = Polyhedron([[]]) # single point in 0 dimensions sage: P.integral_points() ((),) Test unbounded polyhedron:: sage: P = Polyhedron(rays=[[1,0,0]]) sage: P.integral_points() Traceback (most recent call last): ... ValueError: can only enumerate points in a compact polyhedron """ from sage.misc.misc_c import prod if not self.is_compact(): raise ValueError('can only enumerate points in a compact polyhedron') # Trivial cases: polyhedron with 0 or 1 vertices if self.n_vertices() == 0: return () if self.n_vertices() == 1: v = self.vertices_list()[0] try: return (vector(ZZ, v),) except TypeError: # vertex not integral return () # for small bounding boxes, it is faster to naively iterate over the points of the box box_min, box_max = self.bounding_box(integral_hull=True) if box_min is None: return () box_points = prod(max_coord-min_coord+1 for min_coord, max_coord in zip(box_min, box_max)) if not self.is_lattice_polytope() or \ (self.is_simplex() and box_points < 1000) or \ box_points < threshold: from sage.geometry.integral_points import rectangular_box_points return rectangular_box_points(list(box_min), list(box_max), self) # for more complicate polytopes, triangulate & use smith normal form from sage.geometry.integral_points import simplex_points if self.is_simplex(): return simplex_points(self.Vrepresentation()) triangulation = self.triangulate() points = set() for simplex in triangulation: triang_vertices = [self.Vrepresentation(i) for i in simplex] new_points = simplex_points(triang_vertices) for p in new_points: p.set_immutable() points.update(new_points) # assert all(self.contains(p) for p in points) # slow return tuple(points)