Base class for polyhedra over \(\QQ\)¶
- class sage.geometry.polyhedron.base_QQ.Polyhedron_QQ(parent, Vrep, Hrep, Vrep_minimal=None, Hrep_minimal=None, pref_rep=None, mutable=False, **kwds)[source]¶
Bases:
Polyhedron_base
Base class for Polyhedra over \(\QQ\).
- Hstar_function(acting_group=None, output=None)[source]¶
Return \(H^*\) as a rational function in \(t\) with coefficients in the ring of class functions of the
acting_group
of this polytope.Here, \(H^*(t) = \sum_{m} \chi_{m\text{self}}t^m \det(Id-\rho(t))\). The irreducible characters of
acting_group
form an orthonormal basis for the ring of class functions with values in \(\CC\). The coefficients of \(H^*(t)\) are expressed in this basis.INPUT:
acting_group
– (default=None) a permgroup object. A subgroup of the polytope’srestricted_automorphism_group
. IfNone
, it is set to the fullrestricted_automorphism_group
of the polytope. The acting group should always useoutput='permutation'
.output
– string. an output option. The allowed values are:None
(default): returns the rational function \(H^*(t)\). \(H^*\) is a rational function in \(t\) with coefficients in the ring of class functions.'e_series_list'
: Returns a list of the ehrhart_series for the fixed_subpolytopes of each conjugacy class representative.'determinant_vec'
: Returns a list of the determinants of \(Id-\rho*t\) for each conjugacy class representative.'Hstar_as_lin_comb'
: Returns a vector of the coefficients of the irreducible representations in the expression of \(H^*\).'prod_det_es'
: Returns a vector of the product of determinants and the Ehrhart series.'complete'
: Returns a list withHstar
,Hstar_as_lin_comb
, character table of the acting group, and whetherHstar
is effective.
OUTPUT:
The default output is the rational function \(H^*\). \(H^*\) is a rational function in \(t\) with coefficients in the ring of class functions. There are several output options to see the intermediary outputs of the function.
EXAMPLES:
The \(H^*\)-polynomial of the standard (\(d-1\))-dimensional simplex \(S = conv(e_1, \dots, e_d)\) under its
restricted_automorphism_group()
is equal to 1 = \(\chi_{trivial}\) (Prop 6.1 [Stap2011]). Here is the computation for the 3-dimensional standard simplex:sage: # optional - pynormaliz sage: S = polytopes.simplex(3, backend='normaliz'); S A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 4 vertices sage: G = S.restricted_automorphism_group( ....: output='permutation') sage: G.is_isomorphic(SymmetricGroup(4)) True sage: Hstar = S._Hstar_function_normaliz(G); Hstar chi_4 sage: G.character_table() [ 1 -1 1 1 -1] [ 3 -1 0 -1 1] [ 2 0 -1 2 0] [ 3 1 0 -1 -1] [ 1 1 1 1 1]
>>> from sage.all import * >>> # optional - pynormaliz >>> S = polytopes.simplex(Integer(3), backend='normaliz'); S A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 4 vertices >>> G = S.restricted_automorphism_group( ... output='permutation') >>> G.is_isomorphic(SymmetricGroup(Integer(4))) True >>> Hstar = S._Hstar_function_normaliz(G); Hstar chi_4 >>> G.character_table() [ 1 -1 1 1 -1] [ 3 -1 0 -1 1] [ 2 0 -1 2 0] [ 3 1 0 -1 -1] [ 1 1 1 1 1]
# optional - pynormaliz S = polytopes.simplex(3, backend='normaliz'); S G = S.restricted_automorphism_group( output='permutation') G.is_isomorphic(SymmetricGroup(4)) Hstar = S._Hstar_function_normaliz(G); Hstar G.character_table()
The next example is Example 7.6 in [Stap2011], and shows that \(H^*\) is not always a polynomial. Let P be the polytope with vertices \(\pm(0,0,1),\pm(1,0,1), \pm(0,1,1), \pm(1,1,1)\) and let G = \(\Zmod{2}\) act on P as follows:
sage: # optional - pynormaliz sage: P = Polyhedron(vertices=[[0,0,1], [0,0,-1], [1,0,1], ....: [-1,0,-1], [0,1,1], ....: [0,-1,-1], [1,1,1], [-1,-1,-1]], ....: backend='normaliz') sage: K = P.restricted_automorphism_group( ....: output='permutation') sage: G = K.subgroup(gens=[K([(0,2),(1,3),(4,6),(5,7)])]) sage: conj_reps = G.conjugacy_classes_representatives() sage: Dict = P.permutations_to_matrices(conj_reps, ....: acting_group=G) sage: list(Dict.keys())[0] (0,2)(1,3)(4,6)(5,7) sage: list(Dict.values())[0] [-1 0 1 0] [ 0 1 0 0] [ 0 0 1 0] [ 0 0 0 1] sage: len(G) 2 sage: G.character_table() [ 1 1] [ 1 -1]
>>> from sage.all import * >>> # optional - pynormaliz >>> P = Polyhedron(vertices=[[Integer(0),Integer(0),Integer(1)], [Integer(0),Integer(0),-Integer(1)], [Integer(1),Integer(0),Integer(1)], ... [-Integer(1),Integer(0),-Integer(1)], [Integer(0),Integer(1),Integer(1)], ... [Integer(0),-Integer(1),-Integer(1)], [Integer(1),Integer(1),Integer(1)], [-Integer(1),-Integer(1),-Integer(1)]], ... backend='normaliz') >>> K = P.restricted_automorphism_group( ... output='permutation') >>> G = K.subgroup(gens=[K([(Integer(0),Integer(2)),(Integer(1),Integer(3)),(Integer(4),Integer(6)),(Integer(5),Integer(7))])]) >>> conj_reps = G.conjugacy_classes_representatives() >>> Dict = P.permutations_to_matrices(conj_reps, ... acting_group=G) >>> list(Dict.keys())[Integer(0)] (0,2)(1,3)(4,6)(5,7) >>> list(Dict.values())[Integer(0)] [-1 0 1 0] [ 0 1 0 0] [ 0 0 1 0] [ 0 0 0 1] >>> len(G) 2 >>> G.character_table() [ 1 1] [ 1 -1]
# optional - pynormaliz P = Polyhedron(vertices=[[0,0,1], [0,0,-1], [1,0,1], [-1,0,-1], [0,1,1], [0,-1,-1], [1,1,1], [-1,-1,-1]], backend='normaliz') K = P.restricted_automorphism_group( output='permutation') G = K.subgroup(gens=[K([(0,2),(1,3),(4,6),(5,7)])]) conj_reps = G.conjugacy_classes_representatives() Dict = P.permutations_to_matrices(conj_reps, acting_group=G) list(Dict.keys())[0] list(Dict.values())[0] len(G) G.character_table()
Then we calculate the rational function \(H^*(t)\):
sage: Hst = P._Hstar_function_normaliz(G); Hst # optional - pynormaliz (chi_0*t^4 + (3*chi_0 + 3*chi_1)*t^3 + (8*chi_0 + 2*chi_1)*t^2 + (3*chi_0 + 3*chi_1)*t + chi_0)/(t + 1)
>>> from sage.all import * >>> Hst = P._Hstar_function_normaliz(G); Hst # optional - pynormaliz (chi_0*t^4 + (3*chi_0 + 3*chi_1)*t^3 + (8*chi_0 + 2*chi_1)*t^2 + (3*chi_0 + 3*chi_1)*t + chi_0)/(t + 1)
Hst = P._Hstar_function_normaliz(G); Hst # optional - pynormaliz
To see the exact as written in [Stap2011], we can format it as
'Hstar_as_lin_comb'
. The first coordinate is the coefficient of the trivial character; the second is the coefficient of the sign character:sage: lin = P._Hstar_function_normaliz( # optional - pynormaliz ....: G, output='Hstar_as_lin_comb'); lin ((t^4 + 3*t^3 + 8*t^2 + 3*t + 1)/(t + 1), (3*t^3 + 2*t^2 + 3*t)/(t + 1))
>>> from sage.all import * >>> lin = P._Hstar_function_normaliz( # optional - pynormaliz ... G, output='Hstar_as_lin_comb'); lin ((t^4 + 3*t^3 + 8*t^2 + 3*t + 1)/(t + 1), (3*t^3 + 2*t^2 + 3*t)/(t + 1))
lin = P._Hstar_function_normaliz( # optional - pynormaliz G, output='Hstar_as_lin_comb'); lin
- ehrhart_polynomial(engine=None, variable='t', 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)[source]¶
Return the Ehrhart polynomial of this polyhedron.
The polyhedron must be a lattice polytope. 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 article Ehrhart_polynomial. The Ehrhart polynomial may be computed using either LattE Integrale or Normaliz by setting
engine
to ‘latte’ or ‘normaliz’ respectively.INPUT:
engine
– string; the backend to use. Allowed values are:None
(default); When no input is given the Ehrhart polynomial is computed using LattE Integrale (optional)'latte'
; use LattE integrale program (optional)'normaliz'
; use Normaliz program (optional package pynormaliz). The backend ofself
must be set to'normaliz'
.
variable
– string (default:'t'
); the variable in which the Ehrhart polynomial should be expressedWhen the
engine
is'latte'
, the additional input values are:verbose
– boolean (default:False
); ifTrue
, print the whole output of the LattE command
The following options are passed to the LattE command, for details consult the LattE documentation:
dual
– boolean; triangulate and signed-decompose in the dual spaceirrational_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) ofmaxdet
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
OUTPUT: a univariate polynomial in
variable
over a rational fieldSee also
latte
the interface to LattE Integrale PyNormalizEXAMPLES:
To start, we find the Ehrhart polynomial of a three-dimensional
simplex
, first usingengine='latte'
. Leaving the engine unspecified sets theengine
to'latte'
by default:sage: simplex = Polyhedron(vertices=[(0,0,0),(3,3,3),(-3,2,1),(1,-1,-2)]) sage: simplex = simplex.change_ring(QQ) sage: poly = simplex.ehrhart_polynomial(engine='latte') # optional - latte_int sage: poly # optional - latte_int 7/2*t^3 + 2*t^2 - 1/2*t + 1 sage: poly(1) # optional - latte_int 6 sage: len(simplex.integral_points()) 6 sage: poly(2) # optional - latte_int 36 sage: len((2*simplex).integral_points()) 36
>>> from sage.all import * >>> simplex = Polyhedron(vertices=[(Integer(0),Integer(0),Integer(0)),(Integer(3),Integer(3),Integer(3)),(-Integer(3),Integer(2),Integer(1)),(Integer(1),-Integer(1),-Integer(2))]) >>> simplex = simplex.change_ring(QQ) >>> poly = simplex.ehrhart_polynomial(engine='latte') # optional - latte_int >>> poly # optional - latte_int 7/2*t^3 + 2*t^2 - 1/2*t + 1 >>> poly(Integer(1)) # optional - latte_int 6 >>> len(simplex.integral_points()) 6 >>> poly(Integer(2)) # optional - latte_int 36 >>> len((Integer(2)*simplex).integral_points()) 36
simplex = Polyhedron(vertices=[(0,0,0),(3,3,3),(-3,2,1),(1,-1,-2)]) simplex = simplex.change_ring(QQ) poly = simplex.ehrhart_polynomial(engine='latte') # optional - latte_int poly # optional - latte_int poly(1) # optional - latte_int len(simplex.integral_points()) poly(2) # optional - latte_int len((2*simplex).integral_points())
Now we find the same Ehrhart polynomial, this time using
engine='normaliz'
. To use the Normaliz engine, thesimplex
must be defined withbackend='normaliz'
:sage: # optional - pynormaliz sage: simplex = Polyhedron(vertices=[(0,0,0), (3,3,3), ....: (-3,2,1), (1,-1,-2)], ....: backend='normaliz') sage: simplex = simplex.change_ring(QQ) sage: poly = simplex.ehrhart_polynomial(engine='normaliz') sage: poly 7/2*t^3 + 2*t^2 - 1/2*t + 1
>>> from sage.all import * >>> # optional - pynormaliz >>> simplex = Polyhedron(vertices=[(Integer(0),Integer(0),Integer(0)), (Integer(3),Integer(3),Integer(3)), ... (-Integer(3),Integer(2),Integer(1)), (Integer(1),-Integer(1),-Integer(2))], ... backend='normaliz') >>> simplex = simplex.change_ring(QQ) >>> poly = simplex.ehrhart_polynomial(engine='normaliz') >>> poly 7/2*t^3 + 2*t^2 - 1/2*t + 1
# optional - pynormaliz simplex = Polyhedron(vertices=[(0,0,0), (3,3,3), (-3,2,1), (1,-1,-2)], backend='normaliz') simplex = simplex.change_ring(QQ) poly = simplex.ehrhart_polynomial(engine='normaliz') poly
If the
engine='normaliz'
, the backend should be'normaliz'
, otherwise it returns an error:sage: simplex = Polyhedron(vertices=[(0,0,0), (3,3,3), ....: (-3,2,1), (1,-1,-2)]) sage: simplex = simplex.change_ring(QQ) sage: simplex.ehrhart_polynomial(engine='normaliz') Traceback (most recent call last): ... TypeError: The backend of the polyhedron should be 'normaliz'
>>> from sage.all import * >>> simplex = Polyhedron(vertices=[(Integer(0),Integer(0),Integer(0)), (Integer(3),Integer(3),Integer(3)), ... (-Integer(3),Integer(2),Integer(1)), (Integer(1),-Integer(1),-Integer(2))]) >>> simplex = simplex.change_ring(QQ) >>> simplex.ehrhart_polynomial(engine='normaliz') Traceback (most recent call last): ... TypeError: The backend of the polyhedron should be 'normaliz'
simplex = Polyhedron(vertices=[(0,0,0), (3,3,3), (-3,2,1), (1,-1,-2)]) simplex = simplex.change_ring(QQ) simplex.ehrhart_polynomial(engine='normaliz')
The polyhedron should be compact:
sage: C = Polyhedron(rays=[[1,2], [2,1]], # optional - pynormaliz ....: backend='normaliz') sage: C = C.change_ring(QQ) # optional - pynormaliz sage: C.ehrhart_polynomial() # optional - pynormaliz Traceback (most recent call last): ... ValueError: Ehrhart polynomial only defined for compact polyhedra
>>> from sage.all import * >>> C = Polyhedron(rays=[[Integer(1),Integer(2)], [Integer(2),Integer(1)]], # optional - pynormaliz ... backend='normaliz') >>> C = C.change_ring(QQ) # optional - pynormaliz >>> C.ehrhart_polynomial() # optional - pynormaliz Traceback (most recent call last): ... ValueError: Ehrhart polynomial only defined for compact polyhedra
C = Polyhedron(rays=[[1,2], [2,1]], # optional - pynormaliz backend='normaliz') C = C.change_ring(QQ) # optional - pynormaliz C.ehrhart_polynomial() # optional - pynormaliz
The polyhedron should have integral vertices:
sage: L = Polyhedron(vertices=[[0], [1/2]]) sage: L.ehrhart_polynomial() Traceback (most recent call last): ... TypeError: the polytope has nonintegral vertices, use ehrhart_quasipolynomial with backend 'normaliz'
>>> from sage.all import * >>> L = Polyhedron(vertices=[[Integer(0)], [Integer(1)/Integer(2)]]) >>> L.ehrhart_polynomial() Traceback (most recent call last): ... TypeError: the polytope has nonintegral vertices, use ehrhart_quasipolynomial with backend 'normaliz'
L = Polyhedron(vertices=[[0], [1/2]]) L.ehrhart_polynomial()
- ehrhart_quasipolynomial(variable='t', engine=None, 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)[source]¶
Compute the Ehrhart quasipolynomial of this polyhedron with rational vertices.
If the polyhedron is a lattice polytope, returns the Ehrhart polynomial, a univariate polynomial in
variable
over a rational field. If the polyhedron has rational, nonintegral vertices, returns a tuple of polynomials invariable
over a rational field. The Ehrhart counting function of a polytope \(P\) with rational vertices is given by a quasipolynomial. That is, there exists a positive integer \(l\) and \(l\) polynomials \(ehr_{P,i} \text{ for } i \in \{1,\dots,l \}\) such that if \(t\) is equivalent to \(i\) mod \(l\) then \(tP \cap \mathbb Z^d = ehr_{P,i}(t)\).INPUT:
variable
– string (default:'t'
); the variable in which the Ehrhart polynomial should be expressedengine
– string; the backend to use. Allowed values are:None
(default); When no input is given the Ehrhart polynomial is computed using Normaliz (optional)'latte'
; use LattE Integrale program (requires optional package ‘latte_int’)'normaliz'
; use the Normaliz program (requires optional package ‘pynormaliz’). The backend ofself
must be set to ‘normaliz’.
When the
engine
is ‘latte’, the additional input values are:verbose
– boolean (default:False
); ifTrue
, print the whole output of the LattE command
The following options are passed to the LattE command, for details consult the LattE documentation:
dual
– boolean; triangulate and signed-decompose in the dual spaceirrational_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) ofmaxdet
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
OUTPUT:
A univariate polynomial over a rational field or a tuple of such polynomials.
See also
latte
the interface to LattE Integrale PyNormalizWarning
If the polytope has rational, non integral vertices, it must have
backend='normaliz'
.EXAMPLES:
As a first example, consider the line segment [0,1/2]. If we dilate this line segment by an even integral factor \(k\), then the dilated line segment will contain \(k/2 +1\) lattice points. If \(k\) is odd then there will be \(k/2+1/2\) lattice points in the dilated line segment. Note that it is necessary to set the backend of the polytope to ‘normaliz’:
sage: line_seg = Polyhedron(vertices=[[0], [1/2]], # optional - pynormaliz ....: backend='normaliz'); line_seg A 1-dimensional polyhedron in QQ^1 defined as the convex hull of 2 vertices sage: line_seg.ehrhart_quasipolynomial() # optional - pynormaliz (1/2*t + 1, 1/2*t + 1/2)
>>> from sage.all import * >>> line_seg = Polyhedron(vertices=[[Integer(0)], [Integer(1)/Integer(2)]], # optional - pynormaliz ... backend='normaliz'); line_seg A 1-dimensional polyhedron in QQ^1 defined as the convex hull of 2 vertices >>> line_seg.ehrhart_quasipolynomial() # optional - pynormaliz (1/2*t + 1, 1/2*t + 1/2)
line_seg = Polyhedron(vertices=[[0], [1/2]], # optional - pynormaliz backend='normaliz'); line_seg line_seg.ehrhart_quasipolynomial() # optional - pynormaliz
For a more exciting example, let us look at the subpolytope of the 3 dimensional permutahedron fixed by the reflection across the hyperplane \(x_1 = x_4\):
sage: verts = [[3/2, 3, 4, 3/2], ....: [3/2, 4, 3, 3/2], ....: [5/2, 1, 4, 5/2], ....: [5/2, 4, 1, 5/2], ....: [7/2, 1, 2, 7/2], ....: [7/2, 2, 1, 7/2]] sage: subpoly = Polyhedron(vertices=verts, # optional - pynormaliz ....: backend='normaliz') sage: eq = subpoly.ehrhart_quasipolynomial(); eq # optional - pynormaliz (4*t^2 + 3*t + 1, 4*t^2 + 2*t) sage: eq = subpoly.ehrhart_quasipolynomial(); eq # optional - pynormaliz (4*t^2 + 3*t + 1, 4*t^2 + 2*t) sage: even_ep = eq[0] # optional - pynormaliz sage: odd_ep = eq[1] # optional - pynormaliz sage: even_ep(2) # optional - pynormaliz 23 sage: ts = 2*subpoly # optional - pynormaliz sage: ts.integral_points_count() # optional - pynormaliz latte_int 23 sage: odd_ep(1) # optional - pynormaliz 6 sage: subpoly.integral_points_count() # optional - pynormaliz latte_int 6
>>> from sage.all import * >>> verts = [[Integer(3)/Integer(2), Integer(3), Integer(4), Integer(3)/Integer(2)], ... [Integer(3)/Integer(2), Integer(4), Integer(3), Integer(3)/Integer(2)], ... [Integer(5)/Integer(2), Integer(1), Integer(4), Integer(5)/Integer(2)], ... [Integer(5)/Integer(2), Integer(4), Integer(1), Integer(5)/Integer(2)], ... [Integer(7)/Integer(2), Integer(1), Integer(2), Integer(7)/Integer(2)], ... [Integer(7)/Integer(2), Integer(2), Integer(1), Integer(7)/Integer(2)]] >>> subpoly = Polyhedron(vertices=verts, # optional - pynormaliz ... backend='normaliz') >>> eq = subpoly.ehrhart_quasipolynomial(); eq # optional - pynormaliz (4*t^2 + 3*t + 1, 4*t^2 + 2*t) >>> eq = subpoly.ehrhart_quasipolynomial(); eq # optional - pynormaliz (4*t^2 + 3*t + 1, 4*t^2 + 2*t) >>> even_ep = eq[Integer(0)] # optional - pynormaliz >>> odd_ep = eq[Integer(1)] # optional - pynormaliz >>> even_ep(Integer(2)) # optional - pynormaliz 23 >>> ts = Integer(2)*subpoly # optional - pynormaliz >>> ts.integral_points_count() # optional - pynormaliz latte_int 23 >>> odd_ep(Integer(1)) # optional - pynormaliz 6 >>> subpoly.integral_points_count() # optional - pynormaliz latte_int 6
verts = [[3/2, 3, 4, 3/2], [3/2, 4, 3, 3/2], [5/2, 1, 4, 5/2], [5/2, 4, 1, 5/2], [7/2, 1, 2, 7/2], [7/2, 2, 1, 7/2]] subpoly = Polyhedron(vertices=verts, # optional - pynormaliz backend='normaliz') eq = subpoly.ehrhart_quasipolynomial(); eq # optional - pynormaliz eq = subpoly.ehrhart_quasipolynomial(); eq # optional - pynormaliz even_ep = eq[0] # optional - pynormaliz odd_ep = eq[1] # optional - pynormaliz even_ep(2) # optional - pynormaliz ts = 2*subpoly # optional - pynormaliz ts.integral_points_count() # optional - pynormaliz latte_int odd_ep(1) # optional - pynormaliz subpoly.integral_points_count() # optional - pynormaliz latte_int
A polytope with rational nonintegral vertices must have
backend='normaliz'
:sage: line_seg = Polyhedron(vertices=[[0], [1/2]]) sage: line_seg.ehrhart_quasipolynomial() Traceback (most recent call last): ... TypeError: The backend of the polyhedron should be 'normaliz'
>>> from sage.all import * >>> line_seg = Polyhedron(vertices=[[Integer(0)], [Integer(1)/Integer(2)]]) >>> line_seg.ehrhart_quasipolynomial() Traceback (most recent call last): ... TypeError: The backend of the polyhedron should be 'normaliz'
line_seg = Polyhedron(vertices=[[0], [1/2]]) line_seg.ehrhart_quasipolynomial()
The polyhedron should be compact:
sage: C = Polyhedron(rays=[[1/2,2], [2,1]], # optional - pynormaliz ....: backend='normaliz') sage: C.ehrhart_quasipolynomial() # optional - pynormaliz Traceback (most recent call last): ... ValueError: Ehrhart quasipolynomial only defined for compact polyhedra
>>> from sage.all import * >>> C = Polyhedron(rays=[[Integer(1)/Integer(2),Integer(2)], [Integer(2),Integer(1)]], # optional - pynormaliz ... backend='normaliz') >>> C.ehrhart_quasipolynomial() # optional - pynormaliz Traceback (most recent call last): ... ValueError: Ehrhart quasipolynomial only defined for compact polyhedra
C = Polyhedron(rays=[[1/2,2], [2,1]], # optional - pynormaliz backend='normaliz') C.ehrhart_quasipolynomial() # optional - pynormaliz
If the polytope happens to be a lattice polytope, the Ehrhart polynomial is returned:
sage: # optional - pynormaliz sage: simplex = Polyhedron(vertices=[(0,0,0), (3,3,3), ....: (-3,2,1), (1,-1,-2)], ....: backend='normaliz') sage: simplex = simplex.change_ring(QQ) sage: poly = simplex.ehrhart_quasipolynomial( ....: engine='normaliz'); poly 7/2*t^3 + 2*t^2 - 1/2*t + 1 sage: simplex.ehrhart_polynomial() # optional - latte_int 7/2*t^3 + 2*t^2 - 1/2*t + 1
>>> from sage.all import * >>> # optional - pynormaliz >>> simplex = Polyhedron(vertices=[(Integer(0),Integer(0),Integer(0)), (Integer(3),Integer(3),Integer(3)), ... (-Integer(3),Integer(2),Integer(1)), (Integer(1),-Integer(1),-Integer(2))], ... backend='normaliz') >>> simplex = simplex.change_ring(QQ) >>> poly = simplex.ehrhart_quasipolynomial( ... engine='normaliz'); poly 7/2*t^3 + 2*t^2 - 1/2*t + 1 >>> simplex.ehrhart_polynomial() # optional - latte_int 7/2*t^3 + 2*t^2 - 1/2*t + 1
# optional - pynormaliz simplex = Polyhedron(vertices=[(0,0,0), (3,3,3), (-3,2,1), (1,-1,-2)], backend='normaliz') simplex = simplex.change_ring(QQ) poly = simplex.ehrhart_quasipolynomial( engine='normaliz'); poly simplex.ehrhart_polynomial() # optional - latte_int
- fixed_subpolytope(vertex_permutation)[source]¶
Return the fixed subpolytope of this polytope by the cyclic action of
vertex_permutation
.The fixed subpolytope of this polytope under the
vertex_permutation
is the subset of this polytope that is fixed pointwise.INPUT:
vertex_permutation
– permutation; a permutation of the vertices ofself
OUTPUT: a subpolytope of
self
Note
The vertex_permutation is obtained as a permutation of the vertices represented as a permutation. For example, vertex_permutation = self.restricted_automorphism_group(output=’permutation’).
Requiring a lattice polytope as opposed to a rational polytope as input is purely conventional.
EXAMPLES:
The fixed subpolytopes of the cube can be obtained as follows:
sage: Cube = polytopes.cube(backend = 'normaliz') # optional - pynormaliz sage: AG = Cube.restricted_automorphism_group( # optional - pynormaliz ....: output='permutation') sage: reprs = AG.conjugacy_classes_representatives() # optional - pynormaliz
>>> from sage.all import * >>> Cube = polytopes.cube(backend = 'normaliz') # optional - pynormaliz >>> AG = Cube.restricted_automorphism_group( # optional - pynormaliz ... output='permutation') >>> reprs = AG.conjugacy_classes_representatives() # optional - pynormaliz
Cube = polytopes.cube(backend = 'normaliz') # optional - pynormaliz AG = Cube.restricted_automorphism_group( # optional - pynormaliz output='permutation') reprs = AG.conjugacy_classes_representatives() # optional - pynormaliz
The fixed subpolytope of the identity element of the group is the entire cube:
sage: reprs[0] # optional - pynormaliz () sage: Cube.fixed_subpolytope(vertex_permutation=reprs[0]) # optional - pynormaliz A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 8 vertices sage: _.vertices() # optional - pynormaliz (A vertex at (-1, -1, -1), A vertex at (-1, -1, 1), A vertex at (-1, 1, -1), A vertex at (-1, 1, 1), A vertex at (1, -1, -1), A vertex at (1, -1, 1), A vertex at (1, 1, -1), A vertex at (1, 1, 1))
>>> from sage.all import * >>> reprs[Integer(0)] # optional - pynormaliz () >>> Cube.fixed_subpolytope(vertex_permutation=reprs[Integer(0)]) # optional - pynormaliz A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 8 vertices >>> _.vertices() # optional - pynormaliz (A vertex at (-1, -1, -1), A vertex at (-1, -1, 1), A vertex at (-1, 1, -1), A vertex at (-1, 1, 1), A vertex at (1, -1, -1), A vertex at (1, -1, 1), A vertex at (1, 1, -1), A vertex at (1, 1, 1))
reprs[0] # optional - pynormaliz Cube.fixed_subpolytope(vertex_permutation=reprs[0]) # optional - pynormaliz _.vertices() # optional - pynormaliz
You can obtain non-trivial examples:
sage: G = AG([(0,1),(2,3),(4,5),(6,7)]) # optional - pynormaliz sage: fsp = Cube.fixed_subpolytope(G); fsp # optional - pynormaliz A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices sage: fsp.vertices() # optional - pynormaliz (A vertex at (-1, -1, 0), A vertex at (-1, 1, 0), A vertex at (1, -1, 0), A vertex at (1, 1, 0))
>>> from sage.all import * >>> G = AG([(Integer(0),Integer(1)),(Integer(2),Integer(3)),(Integer(4),Integer(5)),(Integer(6),Integer(7))]) # optional - pynormaliz >>> fsp = Cube.fixed_subpolytope(G); fsp # optional - pynormaliz A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices >>> fsp.vertices() # optional - pynormaliz (A vertex at (-1, -1, 0), A vertex at (-1, 1, 0), A vertex at (1, -1, 0), A vertex at (1, 1, 0))
G = AG([(0,1),(2,3),(4,5),(6,7)]) # optional - pynormaliz fsp = Cube.fixed_subpolytope(G); fsp # optional - pynormaliz fsp.vertices() # optional - pynormaliz
The next example shows that
fixed_subpolytope()
works for rational polytopes:sage: # optional - pynormaliz sage: P = Polyhedron(vertices=[[0], [1/2]], ....: backend='normaliz') sage: P.vertices() (A vertex at (0), A vertex at (1/2)) sage: G = P.restricted_automorphism_group( ....: output='permutation'); G Permutation Group with generators [(0,1)] sage: len(G) 2 sage: fixed_set = P.fixed_subpolytope(G.gens()[0]) sage: fixed_set A 0-dimensional polyhedron in QQ^1 defined as the convex hull of 1 vertex sage: fixed_set.vertices_list() [[1/4]]
>>> from sage.all import * >>> # optional - pynormaliz >>> P = Polyhedron(vertices=[[Integer(0)], [Integer(1)/Integer(2)]], ... backend='normaliz') >>> P.vertices() (A vertex at (0), A vertex at (1/2)) >>> G = P.restricted_automorphism_group( ... output='permutation'); G Permutation Group with generators [(0,1)] >>> len(G) 2 >>> fixed_set = P.fixed_subpolytope(G.gens()[Integer(0)]) >>> fixed_set A 0-dimensional polyhedron in QQ^1 defined as the convex hull of 1 vertex >>> fixed_set.vertices_list() [[1/4]]
# optional - pynormaliz P = Polyhedron(vertices=[[0], [1/2]], backend='normaliz') P.vertices() G = P.restricted_automorphism_group( output='permutation'); G len(G) fixed_set = P.fixed_subpolytope(G.gens()[0]) fixed_set fixed_set.vertices_list()
- fixed_subpolytopes(conj_class_reps)[source]¶
Return the fixed subpolytopes of this polytope under the actions of the given conjugacy class representatives.
The
conj_class_reps
are representatives of the conjugacy classes of a subgroup of the automorphism group of this polytope. For an element of the automorphism group, the fixed subpolytope is the subset of this polytope that is fixed pointwise.INPUT:
conj_class_reps
– list of representatives of the conjugacy classes of the subgroup of therestricted_automorphism_group()
of the polytope. Each element is written as a permutation of the vertices of the polytope.
OUTPUT:
A dictionary where the elements of
conj_class_reps
are keys and the fixed subpolytopes are values.Note
Two elements in the same conjugacy class fix lattice-isomorphic subpolytopes.
EXAMPLES:
Here is an example for the square:
sage: # optional - pynormaliz, needs sage.groups sage: p = polytopes.hypercube(2, backend='normaliz'); p A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 4 vertices sage: aut_p = p.restricted_automorphism_group( ....: output='permutation') sage: aut_p.order() 8 sage: conj_list = aut_p.conjugacy_classes_representatives() sage: fixedpolytopes_dict = p.fixed_subpolytopes(conj_list) sage: fixedpolytopes_dict[aut_p([(0,3),(1,2)])] A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex
>>> from sage.all import * >>> # optional - pynormaliz, needs sage.groups >>> p = polytopes.hypercube(Integer(2), backend='normaliz'); p A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 4 vertices >>> aut_p = p.restricted_automorphism_group( ... output='permutation') >>> aut_p.order() 8 >>> conj_list = aut_p.conjugacy_classes_representatives() >>> fixedpolytopes_dict = p.fixed_subpolytopes(conj_list) >>> fixedpolytopes_dict[aut_p([(Integer(0),Integer(3)),(Integer(1),Integer(2))])] A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex
# optional - pynormaliz, needs sage.groups p = polytopes.hypercube(2, backend='normaliz'); p aut_p = p.restricted_automorphism_group( output='permutation') aut_p.order() conj_list = aut_p.conjugacy_classes_representatives() fixedpolytopes_dict = p.fixed_subpolytopes(conj_list) fixedpolytopes_dict[aut_p([(0,3),(1,2)])]
- integral_points_count(verbose=False, use_Hrepresentation=False, explicit_enumeration_threshold=1000, preprocess=True, **kwds)[source]¶
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 exceedsexplicit_enumeration_threshold
.INPUT:
verbose
– boolean (default:False
); whether to display verbose outputuse_Hrepresentation
– boolean (default:False
); whether to send the H or V representation to LattEpreprocess
– boolean (default:True
); whether, if the integral hull is known to lie in a coordinate hyperplane, to tighten bounds to reduce dimension
See also
latte
the interface to LattE interfacesEXAMPLES:
sage: P = polytopes.cube() sage: P.integral_points_count() 27 sage: P.integral_points_count(explicit_enumeration_threshold=0) # optional - latte_int 27
>>> from sage.all import * >>> P = polytopes.cube() >>> P.integral_points_count() 27 >>> P.integral_points_count(explicit_enumeration_threshold=Integer(0)) # optional - latte_int 27
P = polytopes.cube() P.integral_points_count() P.integral_points_count(explicit_enumeration_threshold=0) # optional - latte_int
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
>>> from sage.all import * >>> (Integer(1000000000)*P).integral_points_count(verbose=True) # optional - latte_int This is LattE integrale... ... Total time:... 8000000012000000006000000001
(1000000000*P).integral_points_count(verbose=True) # optional - latte_int
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) 1
>>> from sage.all import * >>> Q = P*(Integer(8)/Integer(9)) >>> Q.integral_points_count() 1 >>> Q.integral_points_count(explicit_enumeration_threshold=Integer(0)) 1
Q = P*(8/9) Q.integral_points_count() Q.integral_points_count(explicit_enumeration_threshold=0)
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: ...
>>> from sage.all import * >>> P = Polyhedron(vertices=[[Integer(1)/Integer(2), Integer(1)/Integer(3)]], rays=[[Integer(1), Integer(1)]]) >>> P.integral_points_count() Traceback (most recent call last): ... NotImplementedError: ... >>> P = Polyhedron(vertices=[[Integer(1), Integer(1)]], rays=[[Integer(1), Integer(1)]]) >>> P.integral_points_count() Traceback (most recent call last): ... NotImplementedError: ...
P = Polyhedron(vertices=[[1/2, 1/3]], rays=[[1, 1]]) P.integral_points_count() P = Polyhedron(vertices=[[1, 1]], rays=[[1, 1]]) P.integral_points_count()
“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 # needs sage.combinat 33
>>> from sage.all import * >>> 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+Integer(3))*x[i] for i in range(d)) <= b) ... return lp.polyhedron(backend=backend) >>> fibonacci_knapsack(Integer(20), Integer(12)).integral_points_count() # does not finish with preprocess=False # needs sage.combinat 33
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) fibonacci_knapsack(20, 12).integral_points_count() # does not finish with preprocess=False # needs sage.combinat
- is_effective(Hstar, Hstar_as_lin_comb)[source]¶
Test for the effectiveness of the
Hstar
series of this polytope.The
Hstar
series of the polytope is determined by the action of a subgroup of the polytope’srestricted_automorphism_group()
. TheHstar
series is effective if it is a polynomial in \(t\) and the coefficient of each \(t^i\) is an effective character in the ring of class functions of the acting group. A character \(\rho\) is effective if the coefficients of the irreducible representations in the expression of \(\rho\) are nonnegative integers.INPUT:
Hstar
– a rational function in \(t\) with coefficients in the ring of class functionsHstar_as_lin_comb
– vector. The coefficients of the irreducible representations of the acting group in the expression ofHstar
as a linear combination of irreducible representations with coefficients in the field of rational functions in \(t\).
OUTPUT: boolean; whether the
Hstar
series is effectiveSee also
EXAMPLES:
The \(H^*\) series of the two-dimensional permutahedron under the action of the symmetric group is effective:
sage: # optional - pynormaliz sage: p3 = polytopes.permutahedron(3, backend='normaliz') sage: G = p3.restricted_automorphism_group( ....: output='permutation') sage: reflection12 = G([(0,2),(1,4),(3,5)]) sage: reflection23 = G([(0,1),(2,3),(4,5)]) sage: S3 = G.subgroup(gens=[reflection12, reflection23]) sage: S3.is_isomorphic(SymmetricGroup(3)) True sage: Hstar = p3.Hstar_function(S3) sage: Hlin = p3.Hstar_function(S3, ....: output='Hstar_as_lin_comb') sage: p3.is_effective(Hstar, Hlin) True
>>> from sage.all import * >>> # optional - pynormaliz >>> p3 = polytopes.permutahedron(Integer(3), backend='normaliz') >>> G = p3.restricted_automorphism_group( ... output='permutation') >>> reflection12 = G([(Integer(0),Integer(2)),(Integer(1),Integer(4)),(Integer(3),Integer(5))]) >>> reflection23 = G([(Integer(0),Integer(1)),(Integer(2),Integer(3)),(Integer(4),Integer(5))]) >>> S3 = G.subgroup(gens=[reflection12, reflection23]) >>> S3.is_isomorphic(SymmetricGroup(Integer(3))) True >>> Hstar = p3.Hstar_function(S3) >>> Hlin = p3.Hstar_function(S3, ... output='Hstar_as_lin_comb') >>> p3.is_effective(Hstar, Hlin) True
# optional - pynormaliz p3 = polytopes.permutahedron(3, backend='normaliz') G = p3.restricted_automorphism_group( output='permutation') reflection12 = G([(0,2),(1,4),(3,5)]) reflection23 = G([(0,1),(2,3),(4,5)]) S3 = G.subgroup(gens=[reflection12, reflection23]) S3.is_isomorphic(SymmetricGroup(3)) Hstar = p3.Hstar_function(S3) Hlin = p3.Hstar_function(S3, output='Hstar_as_lin_comb') p3.is_effective(Hstar, Hlin)
If the \(H^*\)-series is not polynomial, then it is not effective:
sage: # optional - pynormaliz sage: P = Polyhedron(vertices=[[0,0,1], [0,0,-1], [1,0,1], ....: [-1,0,-1], [0,1,1], ....: [0,-1,-1], [1,1,1], [-1,-1,-1]], ....: backend='normaliz') sage: G = P.restricted_automorphism_group( ....: output='permutation') sage: H = G.subgroup(gens=[G([(0,2),(1,3),(4,6),(5,7)])]) sage: Hstar = P.Hstar_function(H); Hstar (chi_0*t^4 + (3*chi_0 + 3*chi_1)*t^3 + (8*chi_0 + 2*chi_1)*t^2 + (3*chi_0 + 3*chi_1)*t + chi_0)/(t + 1) sage: Hstar_lin = P.Hstar_function(H, ....: output='Hstar_as_lin_comb') sage: P.is_effective(Hstar, Hstar_lin) False
>>> from sage.all import * >>> # optional - pynormaliz >>> P = Polyhedron(vertices=[[Integer(0),Integer(0),Integer(1)], [Integer(0),Integer(0),-Integer(1)], [Integer(1),Integer(0),Integer(1)], ... [-Integer(1),Integer(0),-Integer(1)], [Integer(0),Integer(1),Integer(1)], ... [Integer(0),-Integer(1),-Integer(1)], [Integer(1),Integer(1),Integer(1)], [-Integer(1),-Integer(1),-Integer(1)]], ... backend='normaliz') >>> G = P.restricted_automorphism_group( ... output='permutation') >>> H = G.subgroup(gens=[G([(Integer(0),Integer(2)),(Integer(1),Integer(3)),(Integer(4),Integer(6)),(Integer(5),Integer(7))])]) >>> Hstar = P.Hstar_function(H); Hstar (chi_0*t^4 + (3*chi_0 + 3*chi_1)*t^3 + (8*chi_0 + 2*chi_1)*t^2 + (3*chi_0 + 3*chi_1)*t + chi_0)/(t + 1) >>> Hstar_lin = P.Hstar_function(H, ... output='Hstar_as_lin_comb') >>> P.is_effective(Hstar, Hstar_lin) False
# optional - pynormaliz P = Polyhedron(vertices=[[0,0,1], [0,0,-1], [1,0,1], [-1,0,-1], [0,1,1], [0,-1,-1], [1,1,1], [-1,-1,-1]], backend='normaliz') G = P.restricted_automorphism_group( output='permutation') H = G.subgroup(gens=[G([(0,2),(1,3),(4,6),(5,7)])]) Hstar = P.Hstar_function(H); Hstar Hstar_lin = P.Hstar_function(H, output='Hstar_as_lin_comb') P.is_effective(Hstar, Hstar_lin)