@@ -1017,90 +1017,6 @@ def integral_hull(self):
10171017 return self .parent ().element_class ._from_normaliz_cone (parent = self .parent (),
10181018 normaliz_cone = cone )
10191019
1020- def ehrhart_quasipolynomial (self , variable = 't' ):
1021- r"""
1022- Return the Ehrhart quasi-polynomial of a compact rational polyhedron
1023- using Normaliz.
1024-
1025- INPUT:
1026-
1027- - ``variable`` -- string (default: ``'t'``)
1028-
1029- OUTPUT:
1030-
1031- If it is a polynomial, returns the polynomial. Otherwise, returns a
1032- tuple of rational polynomials whose length is the quasi-period of the
1033- quasi-polynomial and each rational polynomial describes a residue class.
1034-
1035- EXAMPLES::
1036-
1037- sage: C = Polyhedron(vertices = [[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]],backend='normaliz') # optional - pynormaliz
1038- sage: C.ehrhart_quasipolynomial() # optional - pynormaliz
1039- t^3 + 3*t^2 + 3*t + 1
1040-
1041- sage: P = Polyhedron(vertices=[[0,0],[3/2,0],[0,3/2],[1,1]],backend='normaliz') # optional - pynormaliz
1042- sage: P.ehrhart_quasipolynomial() # optional - pynormaliz
1043- (3/2*t^2 + 2*t + 1, 3/2*t^2 + 2*t + 1/2)
1044- sage: P.ehrhart_quasipolynomial('x') # optional - pynormaliz
1045- (3/2*x^2 + 2*x + 1, 3/2*x^2 + 2*x + 1/2)
1046-
1047- The quasi-polynomial evaluated at ``i`` counts the integral points
1048- in the ``i``-th dilate::
1049-
1050- sage: Q = Polyhedron(vertices = [[-1/3],[2/3]],backend='normaliz') # optional - pynormaliz
1051- sage: p0,p1,p2 = Q.ehrhart_quasipolynomial() # optional - pynormaliz
1052- sage: r0 = [p0(i) for i in range(15)] # optional - pynormaliz
1053- sage: r1 = [p1(i) for i in range(15)] # optional - pynormaliz
1054- sage: r2 = [p2(i) for i in range(15)] # optional - pynormaliz
1055- sage: result = [None]*15 # optional - pynormaliz
1056- sage: result[::3] = r0[::3] # optional - pynormaliz
1057- sage: result[1::3] = r1[1::3] # optional - pynormaliz
1058- sage: result[2::3] = r2[2::3] # optional - pynormaliz
1059- sage: result == [(i*Q).integral_points_count() for i in range(15)] # optional - pynormaliz
1060- True
1061-
1062- The polyhedron should be compact::
1063-
1064- sage: C = Polyhedron(backend='normaliz',rays=[[1,2],[2,1]]) # optional - pynormaliz
1065- sage: C.ehrhart_quasipolynomial() # optional - pynormaliz
1066- Traceback (most recent call last):
1067- ...
1068- NotImplementedError: Ehrhart quasi-polynomial can only be computed for compact polyhedron
1069-
1070- .. SEEALSO::
1071-
1072- :meth:`~sage.geometry.polyhedron.backend_normaliz.hilbert_series`,
1073- :meth:`~sage.geometry.polyhedron.backend_normaliz.ehrhart_series`
1074- """
1075- if self .is_empty ():
1076- return 0
1077-
1078- if not self .is_compact ():
1079- raise NotImplementedError ("Ehrhart quasi-polynomial can only be computed for compact polyhedron" )
1080-
1081- cone = self ._normaliz_cone
1082- # Normaliz needs to compute the EhrhartSeries first
1083- PythonModule ("PyNormaliz" , spkg = "pynormaliz" ).require ()
1084- import PyNormaliz
1085- assert PyNormaliz .NmzCompute (cone , ["EhrhartSeries" ])
1086- e = self ._nmz_result (cone , "EhrhartQuasiPolynomial" )
1087-
1088- from sage .rings .polynomial .polynomial_ring_constructor import PolynomialRing
1089- poly_ring = PolynomialRing (QQ , variable )
1090- t = poly_ring .gens ()[0 ]
1091- if len (e ) == 2 :
1092- # It is a polynomial
1093- es = sum ([e [0 ][i ]* t ** i for i in range (len (e [0 ]))])
1094- return es / ZZ (e [1 ])
1095- else :
1096- # It is a quasi-polynomial
1097- polynomials = []
1098- for p in e [:- 1 ]:
1099- es = sum ([p [i ]* t ** i for i in range (len (p ))]) / ZZ (e [- 1 ])
1100- polynomials += [es ]
1101-
1102- return tuple (polynomials )
1103-
11041020 def _volume_normaliz (self , measure = 'euclidean' ):
11051021 r"""
11061022 Computes the volume of a polytope using normaliz.
@@ -1316,6 +1232,81 @@ def ehrhart_series(self, variable='t'):
13161232
13171233 return es
13181234
1235+ def _ehrhart_quasipolynomial_normaliz (self , variable = 't' ):
1236+ r"""
1237+ Return the Ehrhart quasipolynomial of a compact rational polyhedron
1238+ using Normaliz.
1239+
1240+ If it is a polynomial, returns the polynomial. Otherwise, returns a
1241+ tuple of rational polynomials whose length is the quasi-period of the
1242+ quasipolynomial and each rational polynomial describes a residue class.
1243+
1244+ INPUT:
1245+
1246+ - ``variable`` -- string (default: ``'t'``)
1247+
1248+ OUTPUT:
1249+
1250+ A polynomial or tuple of polynomials.
1251+
1252+ EXAMPLES::
1253+
1254+ sage: C = Polyhedron(vertices = [[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]],backend='normaliz') # optional - pynormaliz
1255+ sage: C._ehrhart_quasipolynomial_normaliz() # optional - pynormaliz
1256+ t^3 + 3*t^2 + 3*t + 1
1257+
1258+ sage: P = Polyhedron(vertices=[[0,0],[3/2,0],[0,3/2],[1,1]],backend='normaliz') # optional - pynormaliz
1259+ sage: P._ehrhart_quasipolynomial_normaliz() # optional - pynormaliz
1260+ (3/2*t^2 + 2*t + 1, 3/2*t^2 + 2*t + 1/2)
1261+ sage: P._ehrhart_quasipolynomial_normaliz('x') # optional - pynormaliz
1262+ (3/2*x^2 + 2*x + 1, 3/2*x^2 + 2*x + 1/2)
1263+
1264+ The quasipolynomial evaluated at ``i`` counts the integral points
1265+ in the ``i``-th dilate::
1266+
1267+ sage: Q = Polyhedron(vertices = [[-1/3],[2/3]],backend='normaliz') # optional - pynormaliz
1268+ sage: p0,p1,p2 = Q._ehrhart_quasipolynomial_normaliz() # optional - pynormaliz
1269+ sage: r0 = [p0(i) for i in range(15)] # optional - pynormaliz
1270+ sage: r1 = [p1(i) for i in range(15)] # optional - pynormaliz
1271+ sage: r2 = [p2(i) for i in range(15)] # optional - pynormaliz
1272+ sage: result = [None]*15 # optional - pynormaliz
1273+ sage: result[::3] = r0[::3] # optional - pynormaliz
1274+ sage: result[1::3] = r1[1::3] # optional - pynormaliz
1275+ sage: result[2::3] = r2[2::3] # optional - pynormaliz
1276+ sage: result == [(i*Q).integral_points_count() for i in range(15)] # optional - pynormaliz
1277+ True
1278+
1279+
1280+ .. SEEALSO::
1281+
1282+ :meth:`~sage.geometry.polyhedron.backend_normaliz.hilbert_series`,
1283+ :meth:`~sage.geometry.polyhedron.backend_normaliz.ehrhart_series`
1284+ """
1285+ cone = self ._normaliz_cone
1286+ # Normaliz needs to compute the EhrhartSeries first
1287+ PythonModule ("PyNormaliz" , spkg = "pynormaliz" ).require ()
1288+ import PyNormaliz
1289+ assert PyNormaliz .NmzCompute (cone , ["EhrhartSeries" ])
1290+ e = self ._nmz_result (cone , "EhrhartQuasiPolynomial" )
1291+
1292+ from sage .rings .polynomial .polynomial_ring_constructor import PolynomialRing
1293+ poly_ring = PolynomialRing (QQ , variable )
1294+ t = poly_ring .gens ()[0 ]
1295+ if len (e ) == 2 :
1296+ # It is a polynomial
1297+ es = sum ([e [0 ][i ]* t ** i for i in range (len (e [0 ]))])
1298+ return es / ZZ (e [1 ])
1299+ else :
1300+ # It is a quasipolynomial
1301+ polynomials = []
1302+ for p in e [:- 1 ]:
1303+ es = sum ([p [i ]* t ** i for i in range (len (p ))]) / ZZ (e [- 1 ])
1304+ polynomials += [es ]
1305+
1306+ return tuple (polynomials )
1307+
1308+ _ehrhart_polynomial_normaliz = _ehrhart_quasipolynomial_normaliz
1309+
13191310 def hilbert_series (self , grading , variable = 't' ):
13201311 r"""
13211312 Return the Hilbert series of the polyhedron with respect to ``grading``.
0 commit comments