def latte_generating_series(L, M=None): r""" EXAMPLES:: sage: from surface_dynamics.misc.multiplicative_multivariate_generating_series import latte_generating_series sage: ieqs = [[0, 1, 0, 0, 0, 0, 0], ....: [0, 0, 1, -1, 1, 0, 0], ....: [0, 0, 0, 0, 1, 0, 0], ....: [0, 0, 0, 1, 0, 0, 0], ....: [0, 0, 1, 0, 0, 0, 0]] sage: eqns = [[0, 0, 1, -1, 1, 0, -1], [0, 0, 1, -1, 1, -1, 0]] sage: L = Polyhedron(ieqs=ieqs, eqns=eqns) sage: latte_generating_series(L) # optional - latte_int (1)/((1 - x2^-1*x4*x5)*(1 - x2*x3)*(1 - x1*x2)*(1 - x0)) + (1)/((1 - x3*x4*x5)*(1 - x2*x4^-1*x5^-1)*(1 - x1*x4*x5)*(1 - x0)) """ if M is None: M = MultiplicativeMultivariateGeneratingSeriesRing( 'x', L.ambient_dim()) try: from sage.interfaces.latte import count except ImportError: from sage.version import version raise ValueError( 'your Sage version is too old ({}) to use this function'.format( version)) ans = count(L.cdd_Hrepresentation(), cdd=True, multivariate_generating_function=True, raw_output=True) return parse_latte_generating_series(M, ans)
def latte_generating_series(L, M=None): r""" EXAMPLES:: sage: from surface_dynamics.misc.multivariate_generating_series import latte_generating_series sage: ieqs = [[0, 1, 0, 0, 0, 0, 0], ....: [0, 0, 1, -1, 1, 0, 0], ....: [0, 0, 0, 0, 1, 0, 0], ....: [0, 0, 0, 1, 0, 0, 0], ....: [0, 0, 1, 0, 0, 0, 0]] sage: eqns = [[0, 0, 1, -1, 1, 0, -1], [0, 0, 1, -1, 1, -1, 0]] sage: L = Polyhedron(ieqs=ieqs, eqns=eqns) sage: latte_generating_series(L) # optional - latte_int (1)/((1 - x2^-1*x4*x5)*(1 - x2*x3)*(1 - x1*x2)*(1 - x0)) + (1)/((1 - x3*x4*x5)*(1 - x2*x4^-1*x5^-1)*(1 - x1*x4*x5)*(1 - x0)) """ if M is None: M = MultivariateGeneratingSeriesRing('x', L.ambient_dim()) try: from sage.interfaces.latte import count except ImportError: from sage.version import version raise ValueError('your Sage version is too old ({}) to use this function'.format(version)) ans = count(L.cdd_Hrepresentation(), cdd=True, multivariate_generating_function=True, raw_output=True) return parse_latte_generating_series(M, ans)
def _ehrhart_polynomial_latte(self, verbose=False, dual=None, irrational_primal=None, irrational_all_primal=None, maxdet=None, no_decomposition=None, compute_vertex_cones=None, smith_form=None, dualization=None, triangulation=None, triangulation_max_height=None, **kwds): r""" Return the Ehrhart polynomial of this polyhedron using LattE integrale. Let `P` be a lattice polytope in `\RR^d` and define `L(P,t) = \# (tP \cap \ZZ^d)`. Then E. Ehrhart proved in 1962 that `L` coincides with a rational polynomial of degree `d` for integer `t`. `L` is called the *Ehrhart polynomial* of `P`. For more information see the :wikipedia:`Ehrhart_polynomial`. INPUT: - ``verbose`` - boolean (default: ``False``); if ``True``, print the whole output of the LattE command. The following options are passed to the LattE command, for details you should consult `the LattE documentation <https://www.math.ucdavis.edu/~latte/software/packages/latte_current/>`__: - ``dual`` - boolean; triangulate and signed-decompose in the dual space - ``irrational_primal`` - boolean; triangulate in the dual space, signed-decompose in the primal space using irrationalization. - ``irrational_all_primal`` - boolean; triangulate and signed-decompose in the primal space using irrationalization. - ``maxdet`` -- integer; decompose down to an index (determinant) of ``maxdet`` instead of index 1 (unimodular cones). - ``no_decomposition`` -- boolean; do not signed-decompose simplicial cones. - ``compute_vertex_cones`` -- string; either 'cdd' or 'lrs' or '4ti2' - ``smith_form`` -- string; either 'ilio' or 'lidia' - ``dualization`` -- string; either 'cdd' or '4ti2' - ``triangulation`` - string; 'cddlib', '4ti2' or 'topcom' - ``triangulation_max_height`` - integer; use a uniform distribution of height from 1 to this number .. NOTE:: Any additional argument is forwarded to LattE's executable ``count``. All occurrences of '_' will be replaced with a '-'. ALGORITHM: This method calls the program ``count`` from LattE integrale, a program for lattice point enumeration (see https://www.math.ucdavis.edu/~latte/). .. SEEALSO:: :mod:`~sage.interfaces.latte` the interface to LattE integrale EXAMPLES:: sage: P = Polyhedron(vertices=[(0,0,0),(3,3,3),(-3,2,1),(1,-1,-2)]) sage: p = P._ehrhart_polynomial_latte() # optional - latte_int sage: p # optional - latte_int 7/2*t^3 + 2*t^2 - 1/2*t + 1 sage: p(1) # optional - latte_int 6 sage: len(P.integral_points()) # optional - latte_int 6 sage: p(2) # optional - latte_int 36 sage: len((2*P).integral_points()) # optional - latte_int 36 The unit hypercubes:: sage: from itertools import product sage: def hypercube(d): ....: return Polyhedron(vertices=list(product([0,1],repeat=d))) sage: hypercube(3)._ehrhart_polynomial_latte() # optional - latte_int t^3 + 3*t^2 + 3*t + 1 sage: hypercube(4)._ehrhart_polynomial_latte() # optional - latte_int t^4 + 4*t^3 + 6*t^2 + 4*t + 1 sage: hypercube(5)._ehrhart_polynomial_latte() # optional - latte_int t^5 + 5*t^4 + 10*t^3 + 10*t^2 + 5*t + 1 sage: hypercube(6)._ehrhart_polynomial_latte() # optional - latte_int t^6 + 6*t^5 + 15*t^4 + 20*t^3 + 15*t^2 + 6*t + 1 TESTS: Test options:: sage: P = Polyhedron(ieqs=[[1,-1,1,0], [-1,2,-1,0], [1,1,-2,0]], eqns=[[-1,2,-1,-3]], base_ring=ZZ) sage: p = P._ehrhart_polynomial_latte(maxdet=5, verbose=True) # optional - latte_int This is LattE integrale ... ... Invocation: count --ehrhart-polynomial '--redundancy-check=none' --cdd '--maxdet=5' /dev/stdin ... sage: p # optional - latte_int 1/2*t^2 + 3/2*t + 1 sage: p = P._ehrhart_polynomial_latte(dual=True, verbose=True) # optional - latte_int This is LattE integrale ... ... Invocation: count --ehrhart-polynomial '--redundancy-check=none' --cdd --dual /dev/stdin ... sage: p # optional - latte_int 1/2*t^2 + 3/2*t + 1 sage: p = P._ehrhart_polynomial_latte(irrational_primal=True, verbose=True) # optional - latte_int This is LattE integrale ... ... Invocation: count --ehrhart-polynomial '--redundancy-check=none' --cdd --irrational-primal /dev/stdin ... sage: p # optional - latte_int 1/2*t^2 + 3/2*t + 1 sage: p = P._ehrhart_polynomial_latte(irrational_all_primal=True, verbose=True) # optional - latte_int This is LattE integrale ... ... Invocation: count --ehrhart-polynomial '--redundancy-check=none' --cdd --irrational-all-primal /dev/stdin ... sage: p # optional - latte_int 1/2*t^2 + 3/2*t + 1 Test bad options:: sage: P._ehrhart_polynomial_latte(bim_bam_boum=19) # optional - latte_int Traceback (most recent call last): ... RuntimeError: LattE integrale program failed (exit code 1): ... Invocation: count --ehrhart-polynomial '--redundancy-check=none' --cdd '--bim-bam-boum=19' /dev/stdin Unknown command/option --bim-bam-boum=19 """ # note: the options below are explicitly written in the function # declaration in order to keep tab completion (see #18211). kwds.update({ 'dual': dual, 'irrational_primal': irrational_primal, 'irrational_all_primal': irrational_all_primal, 'maxdet': maxdet, 'no_decomposition': no_decomposition, 'compute_vertex_cones': compute_vertex_cones, 'smith_form': smith_form, 'dualization': dualization, 'triangulation': triangulation, 'triangulation_max_height': triangulation_max_height }) from sage.interfaces.latte import count ine = self.cdd_Hrepresentation() return count(ine, cdd=True, ehrhart_polynomial=True, verbose=verbose, **kwds)
def integral_points_count(self, verbose=False, use_Hrepresentation=False, explicit_enumeration_threshold=1000, preprocess=True, **kwds): r""" Return the number of integral points in the polyhedron. This method uses the optional package ``latte_int`` if an estimate for lattice points based on bounding boxes exceeds ``explicit_enumeration_threshold``. INPUT: - ``verbose`` (boolean; ``False`` by default) -- whether to display verbose output. - ``use_Hrepresentation`` - (boolean; ``False`` by default) -- whether to send the H or V representation to LattE - ``preprocess`` - (boolean; ``True`` by default) -- whether, if the integral hull is known to lie in a coordinate hyperplane, to tighten bounds to reduce dimension .. SEEALSO:: :mod:`~sage.interfaces.latte` the interface to LattE interfaces EXAMPLES:: sage: P = polytopes.cube() sage: P.integral_points_count() 27 sage: P.integral_points_count(explicit_enumeration_threshold=0) # optional - latte_int 27 We enlarge the polyhedron to force the use of the generating function methods implemented in LattE integrale, rather than explicit enumeration. sage: (1000000000*P).integral_points_count(verbose=True) # optional - latte_int This is LattE integrale... ... Total time:... 8000000012000000006000000001 We shrink the polyhedron a little bit:: sage: Q = P*(8/9) sage: Q.integral_points_count() 1 sage: Q.integral_points_count(explicit_enumeration_threshold=0) # optional - latte_int 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: ... "Fibonacci" knapsacks (preprocessing helps a lot):: sage: def fibonacci_knapsack(d, b, backend=None): ....: lp = MixedIntegerLinearProgram(base_ring=QQ) ....: x = lp.new_variable(nonnegative=True) ....: lp.add_constraint(lp.sum(fibonacci(i+3)*x[i] for i in range(d)) <= b) ....: return lp.polyhedron(backend=backend) sage: fibonacci_knapsack(20, 12).integral_points_count() # does not finish with preprocess=False 33 TESTS: We check that :trac:`21491` is fixed:: sage: P = Polyhedron(ieqs=[], eqns=[[-10,0,1],[-10,1,0]]) sage: P.integral_points_count() # optional - latte_int 1 sage: P = Polyhedron(ieqs=[], eqns=[[-11,0,2],[-10,1,0]]) sage: P.integral_points_count() # optional - latte_int 0 """ if self.is_empty(): return 0 if self.dimension() == 0: return 1 if self.is_lattice_polytope() else 0 if not self.is_compact(): # LattE just prints the warning 'readCddExtFile:: Given polyhedron is unbounded!!!' # but then returns 0. raise NotImplementedError('Unbounded polyhedra are not supported') # 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 0 box_points = prod(max_coord-min_coord+1 for min_coord, max_coord in zip(box_min, box_max)) if explicit_enumeration_threshold is None or box_points <= explicit_enumeration_threshold: return len(self.integral_points()) p = self if preprocess: # If integral hull is known to lie in a coordinate hyperplane, # tighten bounds to reduce dimension. rat_box_min, rat_box_max = self.bounding_box(integral=False) if any(a == b and (ra < a or b < rb) for ra, a, b, rb in zip(rat_box_min, box_min, box_max, rat_box_max)): lp, x = self.to_linear_program(return_variable=True) for i, a in enumerate(box_min): lp.set_min(x[i], a) for i, b in enumerate(box_max): lp.set_max(x[i], b) p = lp.polyhedron() # this recomputes the double description, which is wasteful if p.is_empty(): return 0 if p.dimension() == 0: return 1 if p.is_lattice_polytope() else 0 # LattE does not like V-representation of lower-dimensional polytopes. if not p.is_full_dimensional(): use_Hrepresentation = True from sage.interfaces.latte import count return count( p.cdd_Hrepresentation() if use_Hrepresentation else p.cdd_Vrepresentation(), cdd=True, verbose=verbose, **kwds)
def ehrhart_polynomial(self, verbose=False, dual=None, irrational_primal=None, irrational_all_primal=None, maxdet=None, no_decomposition=None, compute_vertex_cones=None, smith_form=None, dualization=None, triangulation=None, triangulation_max_height=None, **kwds): r""" Return the Ehrhart polynomial of this polyhedron. Let `P` be a lattice polytope in `\RR^d` and define `L(P,t) = \# (tP \cap \ZZ^d)`. Then E. Ehrhart proved in 1962 that `L` coincides with a rational polynomial of degree `d` for integer `t`. `L` is called the *Ehrhart polynomial* of `P`. For more information see the :wikipedia:`Ehrhart_polynomial`. INPUT: - ``verbose`` - (boolean, default to ``False``) if ``True``, print the whole output of the LattE command. The following options are passed to the LattE command, for details you should consult `the LattE documentation <https://www.math.ucdavis.edu/~latte/software/packages/latte_current/>`__: - ``dual`` - (boolean) triangulate and signed-decompose in the dual space - ``irrational_primal`` - (boolean) triangulate in the dual space, signed-decompose in the primal space using irrationalization. - ``irrational_all_primal`` - (boolean) Triangulate and signed-decompose in the primal space using irrationalization. - ``maxdet`` -- (integer) decompose down to an index (determinant) of ``maxdet`` instead of index 1 (unimodular cones). - ``no_decomposition`` -- (boolean) do not signed-decompose simplicial cones. - ``compute_vertex_cones`` -- (string) either 'cdd' or 'lrs' or '4ti2' - ``smith_form`` -- (string) either 'ilio' or 'lidia' - ``dualization`` -- (string) either 'cdd' or '4ti2' - ``triangulation`` - (string) 'cddlib', '4ti2' or 'topcom' - ``triangulation_max_height`` - (integer) use a uniform distribution of height from 1 to this number .. NOTE:: Any additional argument is forwarded to LattE's executable ``count``. All occurrences of '_' will be replaced with a '-'. ALGORITHM: This method calls the program ``count`` from LattE integrale, a program for lattice point enumeration (see https://www.math.ucdavis.edu/~latte/). .. SEEALSO:: :mod:`~sage.interfaces.latte` the interface to LattE integrale EXAMPLES:: sage: P = Polyhedron(vertices=[(0,0,0),(3,3,3),(-3,2,1),(1,-1,-2)]) sage: p = P.ehrhart_polynomial() # optional - latte_int sage: p # optional - latte_int 7/2*t^3 + 2*t^2 - 1/2*t + 1 sage: p(1) # optional - latte_int 6 sage: len(P.integral_points()) 6 sage: p(2) # optional - latte_int 36 sage: len((2*P).integral_points()) 36 The unit hypercubes:: sage: from itertools import product sage: def hypercube(d): ....: return Polyhedron(vertices=list(product([0,1],repeat=d))) sage: hypercube(3).ehrhart_polynomial() # optional - latte_int t^3 + 3*t^2 + 3*t + 1 sage: hypercube(4).ehrhart_polynomial() # optional - latte_int t^4 + 4*t^3 + 6*t^2 + 4*t + 1 sage: hypercube(5).ehrhart_polynomial() # optional - latte_int t^5 + 5*t^4 + 10*t^3 + 10*t^2 + 5*t + 1 sage: hypercube(6).ehrhart_polynomial() # optional - latte_int t^6 + 6*t^5 + 15*t^4 + 20*t^3 + 15*t^2 + 6*t + 1 An empty polyhedron:: sage: P = Polyhedron(ambient_dim=3, vertices=[]) sage: P.ehrhart_polynomial() # optional - latte_int 0 sage: parent(_) # optional - latte_int Univariate Polynomial Ring in t over Rational Field TESTS: Test options:: sage: P = Polyhedron(ieqs=[[1,-1,1,0], [-1,2,-1,0], [1,1,-2,0]], eqns=[[-1,2,-1,-3]], base_ring=ZZ) sage: p = P.ehrhart_polynomial(maxdet=5, verbose=True) # optional - latte_int This is LattE integrale ... ... Invocation: count --ehrhart-polynomial '--redundancy-check=none' --cdd '--maxdet=5' /dev/stdin ... sage: p # optional - latte_int 1/2*t^2 + 3/2*t + 1 sage: p = P.ehrhart_polynomial(dual=True, verbose=True) # optional - latte_int This is LattE integrale ... ... Invocation: count --ehrhart-polynomial '--redundancy-check=none' --cdd --dual /dev/stdin ... sage: p # optional - latte_int 1/2*t^2 + 3/2*t + 1 sage: p = P.ehrhart_polynomial(irrational_primal=True, verbose=True) # optional - latte_int This is LattE integrale ... ... Invocation: count --ehrhart-polynomial '--redundancy-check=none' --cdd --irrational-primal /dev/stdin ... sage: p # optional - latte_int 1/2*t^2 + 3/2*t + 1 sage: p = P.ehrhart_polynomial(irrational_all_primal=True, verbose=True) # optional - latte_int This is LattE integrale ... ... Invocation: count --ehrhart-polynomial '--redundancy-check=none' --cdd --irrational-all-primal /dev/stdin ... sage: p # optional - latte_int 1/2*t^2 + 3/2*t + 1 Test bad options:: sage: P.ehrhart_polynomial(bim_bam_boum=19) # optional - latte_int Traceback (most recent call last): ... RuntimeError: LattE integrale program failed (exit code 1): ... Invocation: count --ehrhart-polynomial '--redundancy-check=none' --cdd '--bim-bam-boum=19' /dev/stdin Unknown command/option --bim-bam-boum=19 """ if self.is_empty(): from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ R = PolynomialRing(QQ, 't') return R.zero() # note: the options below are explicitely written in the function # declaration in order to keep tab completion (see #18211). kwds.update({ 'dual' : dual, 'irrational_primal' : irrational_primal, 'irrational_all_primal' : irrational_all_primal, 'maxdet' : maxdet, 'no_decomposition' : no_decomposition, 'compute_vertex_cones' : compute_vertex_cones, 'smith_form' : smith_form, 'dualization' : dualization, 'triangulation' : triangulation, 'triangulation_max_height': triangulation_max_height}) from sage.interfaces.latte import count ine = self.cdd_Hrepresentation() return count(ine, cdd=True, ehrhart_polynomial=True, verbose=verbose, **kwds)
def integral_points_count(self, verbose=False, use_Hrepresentation=False, explicit_enumeration_threshold=1000, preprocess=True, **kwds): r""" Return the number of integral points in the polyhedron. This method uses the optional package ``latte_int`` if an estimate for lattice points based on bounding boxes exceeds ``explicit_enumeration_threshold``. INPUT: - ``verbose`` (boolean; ``False`` by default) -- whether to display verbose output. - ``use_Hrepresentation`` - (boolean; ``False`` by default) -- whether to send the H or V representation to LattE - ``preprocess`` - (boolean; ``True`` by default) -- whether, if the integral hull is known to lie in a coordinate hyperplane, to tighten bounds to reduce dimension .. SEEALSO:: :mod:`~sage.interfaces.latte` the interface to LattE interfaces EXAMPLES:: sage: P = polytopes.cube() sage: P.integral_points_count() 27 sage: P.integral_points_count(explicit_enumeration_threshold=0) # optional - latte_int 27 We enlarge the polyhedron to force the use of the generating function methods implemented in LattE integrale, rather than explicit enumeration. sage: (1000000000*P).integral_points_count(verbose=True) # optional - latte_int This is LattE integrale... ... Total time:... 8000000012000000006000000001 We shrink the polyhedron a little bit:: sage: Q = P*(8/9) sage: Q.integral_points_count() 1 sage: Q.integral_points_count(explicit_enumeration_threshold=0) # optional - latte_int 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: ... "Fibonacci" knapsacks (preprocessing helps a lot):: sage: def fibonacci_knapsack(d, b, backend=None): ....: lp = MixedIntegerLinearProgram(base_ring=QQ) ....: x = lp.new_variable(nonnegative=True) ....: lp.add_constraint(lp.sum(fibonacci(i+3)*x[i] for i in range(d)) <= b) ....: return lp.polyhedron(backend=backend) sage: fibonacci_knapsack(20, 12).integral_points_count() # does not finish with preprocess=False 33 TESTS: We check that :trac:`21491` is fixed:: sage: P = Polyhedron(ieqs=[], eqns=[[-10,0,1],[-10,1,0]]) sage: P.integral_points_count() # optional - latte_int 1 sage: P = Polyhedron(ieqs=[], eqns=[[-11,0,2],[-10,1,0]]) sage: P.integral_points_count() # optional - latte_int 0 """ if self.is_empty(): return 0 if self.dimension() == 0: return 1 if self.is_lattice_polytope() else 0 if not self.is_compact(): # LattE just prints the warning 'readCddExtFile:: Given polyhedron is unbounded!!!' # but then returns 0. raise NotImplementedError('Unbounded polyhedra are not supported') # 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 0 box_points = prod(max_coord-min_coord+1 for min_coord, max_coord in zip(box_min, box_max)) if explicit_enumeration_threshold is None or box_points <= explicit_enumeration_threshold: return len(self.integral_points()) p = self if preprocess: # If integral hull is known to lie in a coordinate hyperplane, # tighten bounds to reduce dimension. rat_box_min, rat_box_max = self.bounding_box(integral=False) if any(a == b and (ra < a or b < rb) for ra, a, b, rb in zip(rat_box_min, box_min, box_max, rat_box_max)): lp, x = self.to_linear_program(return_variable=True) for i, a in enumerate(box_min): lp.set_min(x[i], a) for i, b in enumerate(box_max): lp.set_max(x[i], b) p = lp.polyhedron() # this recomputes the double description, which is wasteful if p.is_empty(): return 0 if p.dimension() == 0: return 1 if p.is_lattice_polytope() else 0 # LattE does not like V-representation of lower-dimensional polytopes. if not p.is_full_dimensional(): use_Hrepresentation = True from sage.interfaces.latte import count return count( p.cdd_Hrepresentation() if use_Hrepresentation else p.cdd_Vrepresentation(), cdd=True, verbose=verbose, **kwds)