passagemath-latte-4ti2 10.6.33__cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-latte-4ti2 might be problematic. Click here for more details.
- passagemath_latte_4ti2-10.6.33.dist-info/METADATA +157 -0
- passagemath_latte_4ti2-10.6.33.dist-info/RECORD +65 -0
- passagemath_latte_4ti2-10.6.33.dist-info/WHEEL +6 -0
- passagemath_latte_4ti2-10.6.33.dist-info/top_level.txt +2 -0
- passagemath_latte_4ti2.libs/lib4ti2common-a503c59a.so.0.0.0 +0 -0
- passagemath_latte_4ti2.libs/lib4ti2gmp-cc07667c.so.0.0.0 +0 -0
- passagemath_latte_4ti2.libs/lib4ti2int32-8edd6011.so.0.0.0 +0 -0
- passagemath_latte_4ti2.libs/lib4ti2int64-f6cc34ab.so.0.0.0 +0 -0
- passagemath_latte_4ti2.libs/lib4ti2util-1e2ba2e1.so.0.0.0 +0 -0
- passagemath_latte_4ti2.libs/libLiDIA-e2c3e770.so.0.0.0 +0 -0
- passagemath_latte_4ti2.libs/libcddgmp-ac579979.so.0.1.3 +0 -0
- passagemath_latte_4ti2.libs/libgf2x-fbd36f80.so.3.0.0 +0 -0
- passagemath_latte_4ti2.libs/libglpk-30fa236a.so.40.3.1 +0 -0
- passagemath_latte_4ti2.libs/libgmp-93ebf16a.so.10.5.0 +0 -0
- passagemath_latte_4ti2.libs/libgmpxx-0d9ed651.so.4.7.0 +0 -0
- passagemath_latte_4ti2.libs/liblatte-5119da9a.so.0.0.0 +0 -0
- passagemath_latte_4ti2.libs/libnormalize-2d5ac6a7.so.0.0.0 +0 -0
- passagemath_latte_4ti2.libs/libntl-0043a3a2.so.44.0.1 +0 -0
- passagemath_latte_4ti2.libs/libzsolve-acbcdf65.so.0.0.0 +0 -0
- sage/all__sagemath_latte_4ti2.py +4 -0
- sage/interfaces/all__sagemath_latte_4ti2.py +1 -0
- sage/interfaces/four_ti_2.py +531 -0
- sage/interfaces/latte.py +632 -0
- sage/libs/all__sagemath_latte_4ti2.py +1 -0
- sage/libs/latte_int.cpython-314t-aarch64-linux-gnu.so +0 -0
- sage/libs/latte_int.pyx +1 -0
- sage_wheels/bin/4ti2gmp +0 -0
- sage_wheels/bin/4ti2int32 +0 -0
- sage_wheels/bin/4ti2int64 +0 -0
- sage_wheels/bin/ConvertCDDextToLatte +0 -0
- sage_wheels/bin/ConvertCDDineToLatte +0 -0
- sage_wheels/bin/circuits +64 -0
- sage_wheels/bin/count +0 -0
- sage_wheels/bin/count-linear-forms-from-polynomial +0 -0
- sage_wheels/bin/ehrhart +0 -0
- sage_wheels/bin/ehrhart3 +0 -0
- sage_wheels/bin/genmodel +0 -0
- sage_wheels/bin/gensymm +0 -0
- sage_wheels/bin/graver +17 -0
- sage_wheels/bin/groebner +64 -0
- sage_wheels/bin/hilbert +17 -0
- sage_wheels/bin/hilbert-from-rays +0 -0
- sage_wheels/bin/hilbert-from-rays-symm +0 -0
- sage_wheels/bin/integrate +0 -0
- sage_wheels/bin/latte-maximize +0 -0
- sage_wheels/bin/latte-minimize +0 -0
- sage_wheels/bin/latte2ext +0 -0
- sage_wheels/bin/latte2ine +0 -0
- sage_wheels/bin/markov +64 -0
- sage_wheels/bin/minimize +64 -0
- sage_wheels/bin/normalform +64 -0
- sage_wheels/bin/output +0 -0
- sage_wheels/bin/polyhedron-to-cones +0 -0
- sage_wheels/bin/ppi +0 -0
- sage_wheels/bin/qsolve +64 -0
- sage_wheels/bin/rays +64 -0
- sage_wheels/bin/top-ehrhart-knapsack +0 -0
- sage_wheels/bin/triangulate +0 -0
- sage_wheels/bin/walk +64 -0
- sage_wheels/bin/zbasis +64 -0
- sage_wheels/bin/zsolve +0 -0
- sage_wheels/share/latte-int/m-knapsack.mpl +1245 -0
- sage_wheels/share/latte-int/simplify.add +7 -0
- sage_wheels/share/latte-int/simplify2.add +9 -0
- sage_wheels/share/latte-int/simplify3.add +13 -0
sage/interfaces/latte.py
ADDED
|
@@ -0,0 +1,632 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-latte-4ti2
|
|
2
|
+
# sage.doctest: optional - latte_int
|
|
3
|
+
r"""
|
|
4
|
+
Interface to LattE integrale programs
|
|
5
|
+
"""
|
|
6
|
+
# ****************************************************************************
|
|
7
|
+
# Copyright (C) 2017 Vincent Delecroix <vincent.delecroix@gmail.com>
|
|
8
|
+
#
|
|
9
|
+
# This program is free software: you can redistribute it and/or modify
|
|
10
|
+
# it under the terms of the GNU General Public License as published by
|
|
11
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
12
|
+
# (at your option) any later version.
|
|
13
|
+
# https://www.gnu.org/licenses/
|
|
14
|
+
# ****************************************************************************
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
from sage.cpython.string import str_to_bytes, bytes_to_str
|
|
18
|
+
|
|
19
|
+
from subprocess import Popen, PIPE
|
|
20
|
+
from sage.rings.integer import Integer
|
|
21
|
+
from sage.features.latte import Latte_count, Latte_integrate
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def count(arg, ehrhart_polynomial=False, multivariate_generating_function=False, raw_output=False, verbose=False, **kwds):
|
|
25
|
+
r"""
|
|
26
|
+
Call to the program count from LattE integrale.
|
|
27
|
+
|
|
28
|
+
INPUT:
|
|
29
|
+
|
|
30
|
+
- ``arg`` -- a cdd or LattE description string
|
|
31
|
+
|
|
32
|
+
- ``ehrhart_polynomial``, ``multivariate_generating_function`` -- to
|
|
33
|
+
compute Ehrhart polynomial or multivariate generating function instead of
|
|
34
|
+
just counting points
|
|
35
|
+
|
|
36
|
+
- ``raw_output`` -- if ``True`` then return directly the output string from LattE
|
|
37
|
+
|
|
38
|
+
- For all other options of the count program, consult the LattE manual
|
|
39
|
+
|
|
40
|
+
- ``name`` -- -- (default: ``'y'``) a string
|
|
41
|
+
|
|
42
|
+
The variable names of the Laurent polynomial ring of the multivariate_generating_function
|
|
43
|
+
|
|
44
|
+
- ``Factorization_sort`` (default: ``False``) and
|
|
45
|
+
``Factorization_simplify`` (default: ``False``) -- booleans
|
|
46
|
+
|
|
47
|
+
These are passed on to
|
|
48
|
+
:class:`sage.structure.factorization.Factorization` when creating
|
|
49
|
+
the result.
|
|
50
|
+
|
|
51
|
+
OUTPUT:
|
|
52
|
+
|
|
53
|
+
Either a string (if ``raw_output`` if set to ``True``) or an integer (when
|
|
54
|
+
counting points), or a polynomial (if ``ehrhart_polynomial`` is set to
|
|
55
|
+
``True``) or a tuple of ``Factorization`` objects
|
|
56
|
+
:class:`~sage.structure.factorization.Factorization` whose factors are Laurent polynomials
|
|
57
|
+
(if ``multivariate_generating_function`` is set to ``True``)
|
|
58
|
+
|
|
59
|
+
EXAMPLES::
|
|
60
|
+
|
|
61
|
+
sage: from sage.interfaces.latte import count
|
|
62
|
+
sage: P = 2 * polytopes.cube()
|
|
63
|
+
|
|
64
|
+
Counting integer points from either the H or V representation::
|
|
65
|
+
|
|
66
|
+
sage: count(P.cdd_Hrepresentation(), cdd=True) # optional - latte_int
|
|
67
|
+
125
|
|
68
|
+
sage: count(P.cdd_Vrepresentation(), cdd=True) # optional - latte_int
|
|
69
|
+
125
|
|
70
|
+
|
|
71
|
+
Ehrhart polynomial::
|
|
72
|
+
|
|
73
|
+
sage: count(P.cdd_Hrepresentation(), cdd=True, # optional - latte_int
|
|
74
|
+
....: ehrhart_polynomial=True)
|
|
75
|
+
64*t^3 + 48*t^2 + 12*t + 1
|
|
76
|
+
|
|
77
|
+
Returning a string of the multivariate generating function when ``raw_output=True``.
|
|
78
|
+
Returning the summands of the multivariate generating function in a tuple of ``Factorization`` objects
|
|
79
|
+
with the same format as
|
|
80
|
+
:meth:`sage.geometry.polyhedron.generating_function.generating_function_of_integral_points`
|
|
81
|
+
does when ``result_as_tuple=True``::
|
|
82
|
+
|
|
83
|
+
sage: opts = {'cdd': True,
|
|
84
|
+
....: 'multivariate_generating_function': True,
|
|
85
|
+
....: 'raw_output': True}
|
|
86
|
+
sage: cddin = P.cdd_Hrepresentation()
|
|
87
|
+
sage: print(count(cddin, **opts)) # optional - latte_int
|
|
88
|
+
x[0]^2*x[1]^(-2)*x[2]^(-2)/((1-x[1])*(1-x[2])*(1-x[0]^(-1)))
|
|
89
|
+
+ x[0]^(-2)*x[1]^(-2)*x[2]^(-2)/((1-x[1])*(1-x[2])*(1-x[0]))
|
|
90
|
+
+ x[0]^2*x[1]^(-2)*x[2]^2/((1-x[1])*(1-x[2]^(-1))*(1-x[0]^(-1)))
|
|
91
|
+
+ x[0]^(-2)*x[1]^(-2)*x[2]^2/((1-x[1])*(1-x[0])*(1-x[2]^(-1)))
|
|
92
|
+
+ x[0]^2*x[1]^2*x[2]^(-2)/((1-x[2])*(1-x[1]^(-1))*(1-x[0]^(-1)))
|
|
93
|
+
+ x[0]^(-2)*x[1]^2*x[2]^(-2)/((1-x[2])*(1-x[0])*(1-x[1]^(-1)))
|
|
94
|
+
+ x[0]^2*x[1]^2*x[2]^2/((1-x[2]^(-1))*(1-x[1]^(-1))*(1-x[0]^(-1)))
|
|
95
|
+
+ x[0]^(-2)*x[1]^2*x[2]^2/((1-x[0])*(1-x[2]^(-1))*(1-x[1]^(-1)))
|
|
96
|
+
sage: count(cddin, cdd=True, multivariate_generating_function=True) # optional - latte_int
|
|
97
|
+
((y0^2*y1^-2*y2^-2) * (-y1 + 1)^-1 * (-y2 + 1)^-1 * (1 - y0^-1)^-1,
|
|
98
|
+
(y0^-2*y1^-2*y2^-2) * (-y1 + 1)^-1 * (-y2 + 1)^-1 * (-y0 + 1)^-1,
|
|
99
|
+
(y0^2*y1^-2*y2^2) * (-y1 + 1)^-1 * (1 - y2^-1)^-1 * (1 - y0^-1)^-1,
|
|
100
|
+
(y0^-2*y1^-2*y2^2) * (-y1 + 1)^-1 * (-y0 + 1)^-1 * (1 - y2^-1)^-1,
|
|
101
|
+
(y0^2*y1^2*y2^-2) * (-y2 + 1)^-1 * (1 - y1^-1)^-1 * (1 - y0^-1)^-1,
|
|
102
|
+
(y0^-2*y1^2*y2^-2) * (-y2 + 1)^-1 * (-y0 + 1)^-1 * (1 - y1^-1)^-1,
|
|
103
|
+
y0^2*y1^2*y2^2 * (1 - y2^-1)^-1 * (1 - y1^-1)^-1 * (1 - y0^-1)^-1,
|
|
104
|
+
(y0^-2*y1^2*y2^2) * (-y0 + 1)^-1 * (1 - y2^-1)^-1 * (1 - y1^-1)^-1)
|
|
105
|
+
|
|
106
|
+
TESTS:
|
|
107
|
+
|
|
108
|
+
Testing raw output::
|
|
109
|
+
|
|
110
|
+
sage: from sage.interfaces.latte import count
|
|
111
|
+
sage: P = polytopes.cuboctahedron()
|
|
112
|
+
sage: cddin = P.cdd_Vrepresentation()
|
|
113
|
+
sage: count(cddin, cdd=True, raw_output=True) # optional - latte_int
|
|
114
|
+
'19'
|
|
115
|
+
sage: count(cddin, cdd=True, raw_output=True, ehrhart_polynomial=True) # optional - latte_int
|
|
116
|
+
' + 1 * t^0 + 10/3 * t^1 + 8 * t^2 + 20/3 * t^3'
|
|
117
|
+
sage: count(cddin, cdd=True, raw_output=True, # optional - latte_int
|
|
118
|
+
....: multivariate_generating_function=True)
|
|
119
|
+
'x[0]^(-1)*x[1]^(-1)/((1-x[0]*x[2])*(1-x[0]^(-1)*x[1])*(1-x[2]^(-1)))\n + x[0]^(-1)*x[1]^(-1)/((1-x[2])*(1-x[0]^(-1)*x[1])*(1-x[0]*x[2]^(-1)))\n + ... + x[0]*x[1]/((1-x[0]^(-1)*x[2])*(1-x[0]*x[1]^(-1))*(1-x[2]^(-1)))\n + x[0]*x[1]/((1-x[2])*(1-x[0]*x[1]^(-1))*(1-x[0]^(-1)*x[2]^(-1)))\n'
|
|
120
|
+
|
|
121
|
+
Testing multivariate generating function::
|
|
122
|
+
|
|
123
|
+
sage: from sage.interfaces.latte import count # optional - latte_int
|
|
124
|
+
sage: P = polytopes.cuboctahedron()
|
|
125
|
+
sage: cddin = P.cdd_Vrepresentation()
|
|
126
|
+
sage: count(cddin, cdd=True, multivariate_generating_function=True) # optional - latte_int
|
|
127
|
+
((y0^-1*y1^-1) * (-y0*y2 + 1)^-1 * (1 - y0^-1*y1)^-1 * (1 - y2^-1)^-1,
|
|
128
|
+
(y0^-1*y1^-1) * (-y2 + 1)^-1 * (1 - y0^-1*y1)^-1 * (-y0*y2^-1 + 1)^-1,
|
|
129
|
+
...
|
|
130
|
+
y0*y1 * (1 - y0^-1*y2)^-1 * (-y0*y1^-1 + 1)^-1 * (1 - y2^-1)^-1,
|
|
131
|
+
y0*y1 * (-y2 + 1)^-1 * (-y0*y1^-1 + 1)^-1 * (1 - y0^-1*y2^-1)^-1)
|
|
132
|
+
|
|
133
|
+
sage: P = Polyhedron(rays=[[0,1], [1,0]])
|
|
134
|
+
sage: cddin = P.cdd_Hrepresentation()
|
|
135
|
+
sage: count(cddin, cdd=True, raw_output=True, # optional - latte_int
|
|
136
|
+
....: multivariate_generating_function=True)
|
|
137
|
+
'1/((1-x[1])*(1-x[0]))\n'
|
|
138
|
+
sage: count(cddin, cdd=True, multivariate_generating_function=True) # optional - latte_int
|
|
139
|
+
(1 * (-y1 + 1)^-1 * (-y0 + 1)^-1,)
|
|
140
|
+
|
|
141
|
+
Testing the ``verbose`` option::
|
|
142
|
+
|
|
143
|
+
sage: from sage.interfaces.latte import count
|
|
144
|
+
sage: P = polytopes.cuboctahedron()
|
|
145
|
+
sage: cddin = P.cdd_Vrepresentation()
|
|
146
|
+
sage: n = count(cddin, cdd=True, verbose=True, raw_output=True) # optional - latte_int
|
|
147
|
+
This is LattE integrale ...
|
|
148
|
+
...
|
|
149
|
+
Invocation: ...count... '--redundancy-check=none' --cdd /dev/stdin
|
|
150
|
+
...
|
|
151
|
+
Total Unimodular Cones: ...
|
|
152
|
+
Maximum number of simplicial cones in memory at once: ...
|
|
153
|
+
<BLANKLINE>
|
|
154
|
+
**** The number of lattice points is: ****
|
|
155
|
+
Total time: ... sec
|
|
156
|
+
|
|
157
|
+
Trivial input for which LattE's preprocessor does all the work::
|
|
158
|
+
|
|
159
|
+
sage: P = Polyhedron(vertices=[[0,0,0]])
|
|
160
|
+
sage: cddin = P.cdd_Hrepresentation()
|
|
161
|
+
sage: count(cddin, cdd=True, raw_output=False) # optional - latte_int
|
|
162
|
+
1
|
|
163
|
+
|
|
164
|
+
Testing the runtime error::
|
|
165
|
+
|
|
166
|
+
sage: P = Polyhedron(rays=[[0,1], [1,0]])
|
|
167
|
+
sage: cddin = P.cdd_Hrepresentation()
|
|
168
|
+
sage: count(cddin, cdd=True, raw_output=False) # optional - latte_int
|
|
169
|
+
Traceback (most recent call last):
|
|
170
|
+
...
|
|
171
|
+
RuntimeError: LattE integrale program failed (exit code 1):
|
|
172
|
+
This is LattE integrale ...
|
|
173
|
+
...
|
|
174
|
+
The polyhedron is unbounded.
|
|
175
|
+
"""
|
|
176
|
+
arg = str_to_bytes(arg)
|
|
177
|
+
|
|
178
|
+
args = [Latte_count().absolute_filename()]
|
|
179
|
+
if ehrhart_polynomial and multivariate_generating_function:
|
|
180
|
+
raise ValueError
|
|
181
|
+
if ehrhart_polynomial:
|
|
182
|
+
args.append('--ehrhart-polynomial')
|
|
183
|
+
elif multivariate_generating_function:
|
|
184
|
+
args.append('--multivariate-generating-function')
|
|
185
|
+
|
|
186
|
+
if 'redundancy_check' not in kwds:
|
|
187
|
+
args.append('--redundancy-check=none')
|
|
188
|
+
|
|
189
|
+
mgf_kwds = {}
|
|
190
|
+
for key,value in kwds.items():
|
|
191
|
+
if key in ["name", "Factorization_sort", "Factorization_simplify", "sort_factors"]:
|
|
192
|
+
mgf_kwds[key] = value
|
|
193
|
+
continue
|
|
194
|
+
if value is None or value is False:
|
|
195
|
+
continue
|
|
196
|
+
|
|
197
|
+
key = key.replace('_', '-')
|
|
198
|
+
if value is True:
|
|
199
|
+
args.append(f'--{key}')
|
|
200
|
+
else:
|
|
201
|
+
args.append(f'--{key}={value}')
|
|
202
|
+
|
|
203
|
+
if multivariate_generating_function:
|
|
204
|
+
from sage.misc.temporary_file import tmp_filename
|
|
205
|
+
filename = tmp_filename()
|
|
206
|
+
with open(filename, 'w') as f:
|
|
207
|
+
f.write(bytes_to_str(arg))
|
|
208
|
+
args += [filename]
|
|
209
|
+
else:
|
|
210
|
+
args += ['/dev/stdin']
|
|
211
|
+
|
|
212
|
+
# The cwd argument is needed because latte
|
|
213
|
+
# always produces diagnostic output files.
|
|
214
|
+
import tempfile
|
|
215
|
+
tempd = tempfile.TemporaryDirectory()
|
|
216
|
+
|
|
217
|
+
latte_proc = Popen(args,
|
|
218
|
+
stdin=PIPE, stdout=PIPE,
|
|
219
|
+
stderr=(None if verbose else PIPE),
|
|
220
|
+
cwd=tempd.name)
|
|
221
|
+
|
|
222
|
+
ans, err = latte_proc.communicate(arg)
|
|
223
|
+
if err:
|
|
224
|
+
err = bytes_to_str(err)
|
|
225
|
+
ret_code = latte_proc.poll()
|
|
226
|
+
if ret_code:
|
|
227
|
+
if err is None:
|
|
228
|
+
err = ", see error message above"
|
|
229
|
+
else:
|
|
230
|
+
err = ":\n" + err
|
|
231
|
+
raise RuntimeError("LattE integrale program failed (exit code {})".format(ret_code) + err.strip())
|
|
232
|
+
|
|
233
|
+
ans = bytes_to_str(ans)
|
|
234
|
+
|
|
235
|
+
# There's an error handler below that uses the numOfLatticePoints
|
|
236
|
+
# file created by latte, so we can't cleanup() the temporary
|
|
237
|
+
# directory here. Instead we have to clean it up before the
|
|
238
|
+
# (several) return statements.
|
|
239
|
+
if ehrhart_polynomial:
|
|
240
|
+
ans = ans.splitlines()[-2]
|
|
241
|
+
if raw_output:
|
|
242
|
+
tempd.cleanup()
|
|
243
|
+
return ans
|
|
244
|
+
else:
|
|
245
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
246
|
+
from sage.rings.rational_field import QQ
|
|
247
|
+
R = PolynomialRing(QQ, 't')
|
|
248
|
+
tempd.cleanup()
|
|
249
|
+
return R(ans)
|
|
250
|
+
elif multivariate_generating_function:
|
|
251
|
+
with open(filename + '.rat') as f:
|
|
252
|
+
ans = f.read()
|
|
253
|
+
if raw_output:
|
|
254
|
+
tempd.cleanup()
|
|
255
|
+
return ans
|
|
256
|
+
else:
|
|
257
|
+
tempd.cleanup()
|
|
258
|
+
return str_to_multivariate_generating_function(ans, **mgf_kwds)
|
|
259
|
+
else:
|
|
260
|
+
if ans: # Sometimes (when LattE's preproc does the work), no output appears on stdout.
|
|
261
|
+
ans = ans.splitlines()[-1]
|
|
262
|
+
if not ans:
|
|
263
|
+
# opening a file is slow (30e-6s), so we read the file
|
|
264
|
+
# numOfLatticePoints only in case of a IndexError above
|
|
265
|
+
with open(tempd.name + '/numOfLatticePoints') as f:
|
|
266
|
+
ans = f.read()
|
|
267
|
+
|
|
268
|
+
if raw_output:
|
|
269
|
+
tempd.cleanup()
|
|
270
|
+
return ans
|
|
271
|
+
else:
|
|
272
|
+
tempd.cleanup()
|
|
273
|
+
return Integer(ans)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def str_to_multivariate_generating_function(raw_output_str, name=None, **kwds):
|
|
277
|
+
r"""
|
|
278
|
+
Helper function for :func:`count` if ``multivariate_generating_function`` is set to ``True``
|
|
279
|
+
which preprocess the raw output string to a tuple of summands.
|
|
280
|
+
|
|
281
|
+
TESTS:
|
|
282
|
+
|
|
283
|
+
sage: from sage.interfaces.latte import count, str_to_multivariate_generating_function
|
|
284
|
+
sage: P = Polyhedron(ieqs=[(0, 1, 0, 0), (0, -1, 1, 0)], eqns=[(0, -1, -1, 2)])
|
|
285
|
+
sage: cddin = P.cdd_Hrepresentation()
|
|
286
|
+
sage: raw_output_str = count(cddin, cdd=True, raw_output=True,
|
|
287
|
+
....: multivariate_generating_function=True)
|
|
288
|
+
sage: str_to_multivariate_generating_function(raw_output_str, name='xi')
|
|
289
|
+
(1 * (-xi0*xi1*xi2 + 1)^-1 * (-xi1^2*xi2 + 1)^-1,)
|
|
290
|
+
"""
|
|
291
|
+
from sage.rings.integer_ring import ZZ
|
|
292
|
+
from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing
|
|
293
|
+
import re
|
|
294
|
+
|
|
295
|
+
indices_regex = re.compile(r'(?<=\[)(\d*)(?=\])')
|
|
296
|
+
indices = range(max(ZZ(index) for index in indices_regex.findall(raw_output_str)) + 1)
|
|
297
|
+
if name is None:
|
|
298
|
+
name = 'y'
|
|
299
|
+
|
|
300
|
+
B = LaurentPolynomialRing(ZZ,
|
|
301
|
+
tuple(name + str(k) for k in indices),
|
|
302
|
+
len(indices))
|
|
303
|
+
raw_output_list = raw_output_str[:-1].split('\n + ')
|
|
304
|
+
return tuple(_str_to_multivariate_generating_function(a, B, **kwds) for a in raw_output_list)
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def _str_to_multivariate_generating_function(summand, B=None,
|
|
308
|
+
Factorization_sort=False, Factorization_simplify=False,
|
|
309
|
+
sort_factors=False):
|
|
310
|
+
r"""
|
|
311
|
+
Helper function for :func:`str_to_multivariate_generating_function`
|
|
312
|
+
which convert a summand string to a ``Factorization`` object.
|
|
313
|
+
|
|
314
|
+
Each summand is in the format
|
|
315
|
+
.. MATH::
|
|
316
|
+
|
|
317
|
+
(\sum_{k\in K}y^{s_0}*y^{v_k}})\prod_{j\in J}(1 - y^{v_j})^{-1}.
|
|
318
|
+
|
|
319
|
+
TESTS::
|
|
320
|
+
|
|
321
|
+
sage: from sage.interfaces.latte import _str_to_multivariate_generating_function
|
|
322
|
+
sage: B = LaurentPolynomialRing(ZZ, 'y', 3)
|
|
323
|
+
sage: _str_to_multivariate_generating_function(
|
|
324
|
+
....: '(-1)*x[0]^(-1)*x[2]/((1-x[0]^(-1)*x[1]^(-1))*(1-x[0]^(-1)*x[2]^(-1))*(1-x[0]))', B)
|
|
325
|
+
(-y0^-1*y2) * (1 - y0^-1*y1^-1)^-1 * (1 - y0^-1*y2^-1)^-1 * (-y0 + 1)^-1
|
|
326
|
+
sage: _str_to_multivariate_generating_function('(-1)/((1-x[0]*x[1]*x[2])*(1-x[1]^2*x[2]))\n', B)
|
|
327
|
+
(-1) * (-y0*y1*y2 + 1)^-1 * (-y1^2*y2 + 1)^-1
|
|
328
|
+
sage: _str_to_multivariate_generating_function(
|
|
329
|
+
....: '((-1)*x[0]*x[2]^2 + x[1]^(-2)*x[2])/((1-x[0]*x[1]*x[2])*(1-x[1]^2*x[2]))', B)
|
|
330
|
+
(-y0*y2^2 + y1^-2*y2) * (-y0*y1*y2 + 1)^-1 * (-y1^2*y2 + 1)^-1
|
|
331
|
+
"""
|
|
332
|
+
from sage.rings.integer_ring import ZZ
|
|
333
|
+
from sage.structure.factorization import Factorization
|
|
334
|
+
import re
|
|
335
|
+
|
|
336
|
+
numerator_str, denominator_str = summand.split('/')
|
|
337
|
+
|
|
338
|
+
gen_regex = re.compile(r'(?<=\[)(\d*)(?=\])')
|
|
339
|
+
exponent_regex = re.compile(r'([\d|-]+)')
|
|
340
|
+
|
|
341
|
+
def str_to_laurent_monomial(monomial_str, B):
|
|
342
|
+
result = 1
|
|
343
|
+
for gen_str in monomial_str.split('*'):
|
|
344
|
+
gen_exponent = gen_str.split('^')
|
|
345
|
+
if len(gen_exponent) == 1:
|
|
346
|
+
result *= B.gens()[ZZ(gen_regex.findall(gen_exponent[0])[0])]
|
|
347
|
+
else:
|
|
348
|
+
result *= B.gens()[ZZ(gen_regex.findall(gen_exponent[0])[0])] ** ZZ(exponent_regex.findall(gen_exponent[1])[0])
|
|
349
|
+
return result
|
|
350
|
+
|
|
351
|
+
def str_to_coef_times_laurent_monomial(monomial_str, B):
|
|
352
|
+
if 'x' not in monomial_str:
|
|
353
|
+
if '*' in monomial_str:
|
|
354
|
+
aa, bb = monomial_str.split('*')
|
|
355
|
+
return ZZ(aa.replace('(','').replace(')',''))*ZZ(bb.replace('(','').replace(')',''))
|
|
356
|
+
else:
|
|
357
|
+
return ZZ(monomial_str.replace('(','').replace(')',''))
|
|
358
|
+
elif 'x' in monomial_str.split('*',1)[0]:
|
|
359
|
+
return str_to_laurent_monomial(monomial_str, B)
|
|
360
|
+
else:
|
|
361
|
+
return ZZ(monomial_str.split('*',1)[0].replace('(','').replace(')',''))*str_to_laurent_monomial(monomial_str.split('*',1)[1],B)
|
|
362
|
+
|
|
363
|
+
numerator = sum(str_to_coef_times_laurent_monomial(a, B) for a in numerator_str.split('+'))
|
|
364
|
+
|
|
365
|
+
term_regex = re.compile(r'(?<=1-)(.+?)(?=$|\)$|\)\*\()')
|
|
366
|
+
terms = (str_to_laurent_monomial(a, B) for a in term_regex.findall(denominator_str[1:-1]))
|
|
367
|
+
if sort_factors:
|
|
368
|
+
def key(t):
|
|
369
|
+
D = t.dict().popitem()[0]
|
|
370
|
+
return (-sum(abs(d) for d in D), D)
|
|
371
|
+
terms = sorted(terms, key=key, reverse=True)
|
|
372
|
+
return Factorization([(numerator, 1)] +
|
|
373
|
+
[(1-t, -1) for t in terms],
|
|
374
|
+
sort=Factorization_sort,
|
|
375
|
+
simplify=Factorization_simplify)
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
def integrate(arg, polynomial=None, algorithm='triangulate', raw_output=False, verbose=False, **kwds):
|
|
379
|
+
r"""
|
|
380
|
+
Call to the function integrate from LattE integrale.
|
|
381
|
+
|
|
382
|
+
INPUT:
|
|
383
|
+
|
|
384
|
+
- ``arg`` -- a cdd or LattE description string
|
|
385
|
+
|
|
386
|
+
- ``polynomial`` -- multivariate polynomial or valid LattE polynomial description string
|
|
387
|
+
If given, the valuation parameter of LattE is set to integrate, and is set to volume otherwise
|
|
388
|
+
|
|
389
|
+
- ``algorithm`` -- (default: ``'triangulate'``) the integration method; use 'triangulate' for
|
|
390
|
+
polytope triangulation or 'cone-decompose' for tangent cone decomposition method
|
|
391
|
+
|
|
392
|
+
- ``raw_output`` -- if ``True`` then return directly the output string from LattE
|
|
393
|
+
|
|
394
|
+
- ``verbose`` -- if ``True`` then return directly verbose output from LattE
|
|
395
|
+
|
|
396
|
+
- For all other options of the integrate program, consult the LattE manual
|
|
397
|
+
|
|
398
|
+
OUTPUT: either a string (if ``raw_output`` if set to ``True``) or a rational
|
|
399
|
+
|
|
400
|
+
EXAMPLES::
|
|
401
|
+
|
|
402
|
+
sage: from sage.interfaces.latte import integrate
|
|
403
|
+
sage: P = 2 * polytopes.cube()
|
|
404
|
+
sage: x, y, z = polygen(QQ, 'x, y, z')
|
|
405
|
+
|
|
406
|
+
Integrating over a polynomial over a polytope in either the H or V representation::
|
|
407
|
+
|
|
408
|
+
sage: integrate(P.cdd_Hrepresentation(), x^2*y^2*z^2, cdd=True) # optional - latte_int
|
|
409
|
+
4096/27
|
|
410
|
+
sage: integrate(P.cdd_Vrepresentation(), x^2*y^2*z^2, cdd=True) # optional - latte_int
|
|
411
|
+
4096/27
|
|
412
|
+
|
|
413
|
+
Computing the volume of a polytope in either the H or V representation::
|
|
414
|
+
|
|
415
|
+
sage: integrate(P.cdd_Hrepresentation(), cdd=True) # optional - latte_int
|
|
416
|
+
64
|
|
417
|
+
sage: integrate(P.cdd_Vrepresentation(), cdd=True) # optional - latte_int
|
|
418
|
+
64
|
|
419
|
+
|
|
420
|
+
Polynomials given as a string in LattE description are also accepted::
|
|
421
|
+
|
|
422
|
+
sage: integrate(P.cdd_Hrepresentation(), '[[1,[2,2,2]]]', cdd=True) # optional - latte_int
|
|
423
|
+
4096/27
|
|
424
|
+
|
|
425
|
+
TESTS:
|
|
426
|
+
|
|
427
|
+
Testing raw output::
|
|
428
|
+
|
|
429
|
+
sage: from sage.interfaces.latte import integrate
|
|
430
|
+
sage: P = polytopes.cuboctahedron()
|
|
431
|
+
sage: cddin = P.cdd_Vrepresentation()
|
|
432
|
+
sage: x, y, z = polygen(QQ, 'x, y, z')
|
|
433
|
+
sage: f = 3*x^2*y^4*z^6 + 7*y^3*z^5
|
|
434
|
+
sage: integrate(cddin, f, cdd=True, raw_output=True) # optional - latte_int
|
|
435
|
+
'629/47775'
|
|
436
|
+
|
|
437
|
+
Testing the ``verbose`` option to integrate over a polytope::
|
|
438
|
+
|
|
439
|
+
sage: ans = integrate(cddin, f, cdd=True, verbose=True, # optional - latte_int
|
|
440
|
+
....: raw_output=True)
|
|
441
|
+
This is LattE integrale ...
|
|
442
|
+
...
|
|
443
|
+
Invocation: ...integrate... --valuation=integrate --triangulate --redundancy-check=none --cdd --monomials=... /dev/stdin
|
|
444
|
+
...
|
|
445
|
+
|
|
446
|
+
Testing triangulate algorithm::
|
|
447
|
+
|
|
448
|
+
sage: from sage.interfaces.latte import integrate
|
|
449
|
+
sage: P = polytopes.cuboctahedron()
|
|
450
|
+
sage: cddin = P.cdd_Vrepresentation()
|
|
451
|
+
sage: integrate(cddin, algorithm='triangulate', cdd=True) # optional - latte_int
|
|
452
|
+
20/3
|
|
453
|
+
|
|
454
|
+
Testing convex decomposition algorithm::
|
|
455
|
+
|
|
456
|
+
sage: from sage.interfaces.latte import integrate
|
|
457
|
+
sage: P = polytopes.cuboctahedron()
|
|
458
|
+
sage: cddin = P.cdd_Vrepresentation()
|
|
459
|
+
sage: integrate(cddin, algorithm='cone-decompose', cdd=True) # optional - latte_int
|
|
460
|
+
20/3
|
|
461
|
+
|
|
462
|
+
Testing raw output::
|
|
463
|
+
|
|
464
|
+
sage: from sage.interfaces.latte import integrate
|
|
465
|
+
sage: P = polytopes.cuboctahedron()
|
|
466
|
+
sage: cddin = P.cdd_Vrepresentation()
|
|
467
|
+
sage: integrate(cddin, cdd=True, raw_output=True) # optional - latte_int
|
|
468
|
+
'20/3'
|
|
469
|
+
|
|
470
|
+
Testing polynomial given as a string in LattE description::
|
|
471
|
+
|
|
472
|
+
sage: from sage.interfaces.latte import integrate
|
|
473
|
+
sage: P = polytopes.cuboctahedron()
|
|
474
|
+
sage: integrate(P.cdd_Hrepresentation(), # optional - latte_int
|
|
475
|
+
....: '[[3,[2,4,6]],[7,[0, 3, 5]]]', cdd=True)
|
|
476
|
+
629/47775
|
|
477
|
+
|
|
478
|
+
Testing the ``verbose`` option to compute the volume of a polytope::
|
|
479
|
+
|
|
480
|
+
sage: from sage.interfaces.latte import integrate
|
|
481
|
+
sage: P = polytopes.cuboctahedron()
|
|
482
|
+
sage: cddin = P.cdd_Vrepresentation()
|
|
483
|
+
sage: ans = integrate(cddin, cdd=True, raw_output=True, verbose=True) # optional - latte_int
|
|
484
|
+
This is LattE integrale ...
|
|
485
|
+
...
|
|
486
|
+
Invocation: ...integrate... --valuation=volume --triangulate --redundancy-check=none --cdd /dev/stdin
|
|
487
|
+
...
|
|
488
|
+
|
|
489
|
+
Testing the runtime error::
|
|
490
|
+
|
|
491
|
+
sage: P = Polyhedron(rays=[[1,0],[0,1]])
|
|
492
|
+
sage: P._volume_latte() # optional - latte_int
|
|
493
|
+
Traceback (most recent call last):
|
|
494
|
+
...
|
|
495
|
+
RuntimeError: LattE integrale program failed (exit code -6):
|
|
496
|
+
This is LattE integrale ...
|
|
497
|
+
...
|
|
498
|
+
determinant: nonsquare matrix
|
|
499
|
+
"""
|
|
500
|
+
arg = str_to_bytes(arg)
|
|
501
|
+
|
|
502
|
+
from sage.rings.rational import Rational
|
|
503
|
+
|
|
504
|
+
args = [Latte_integrate().absolute_filename()]
|
|
505
|
+
|
|
506
|
+
got_polynomial = bool(polynomial is not None)
|
|
507
|
+
|
|
508
|
+
if got_polynomial:
|
|
509
|
+
args.append('--valuation=integrate')
|
|
510
|
+
else:
|
|
511
|
+
args.append('--valuation=volume')
|
|
512
|
+
|
|
513
|
+
if algorithm == 'triangulate':
|
|
514
|
+
args.append('--triangulate')
|
|
515
|
+
elif algorithm == 'cone-decompose':
|
|
516
|
+
args.append('--cone-decompose')
|
|
517
|
+
|
|
518
|
+
if 'redundancy_check' not in kwds:
|
|
519
|
+
args.append('--redundancy-check=none')
|
|
520
|
+
|
|
521
|
+
for key, value in kwds.items():
|
|
522
|
+
if value is None or value is False:
|
|
523
|
+
continue
|
|
524
|
+
|
|
525
|
+
key = key.replace('_', '-')
|
|
526
|
+
if value is True:
|
|
527
|
+
args.append(f'--{key}')
|
|
528
|
+
else:
|
|
529
|
+
args.append(f'--{key}={value}')
|
|
530
|
+
|
|
531
|
+
if got_polynomial:
|
|
532
|
+
if not isinstance(polynomial, str):
|
|
533
|
+
# transform polynomial to LattE description
|
|
534
|
+
monomials_list = to_latte_polynomial(polynomial)
|
|
535
|
+
else:
|
|
536
|
+
monomials_list = str(polynomial)
|
|
537
|
+
|
|
538
|
+
from sage.misc.temporary_file import tmp_filename
|
|
539
|
+
filename_polynomial = tmp_filename()
|
|
540
|
+
|
|
541
|
+
with open(filename_polynomial, 'w') as f:
|
|
542
|
+
f.write(monomials_list)
|
|
543
|
+
args += ['--monomials=' + filename_polynomial]
|
|
544
|
+
|
|
545
|
+
args += ['/dev/stdin']
|
|
546
|
+
|
|
547
|
+
# The cwd argument is needed because latte
|
|
548
|
+
# always produces diagnostic output files.
|
|
549
|
+
import tempfile
|
|
550
|
+
tempd = tempfile.TemporaryDirectory()
|
|
551
|
+
|
|
552
|
+
latte_proc = Popen(args,
|
|
553
|
+
stdin=PIPE, stdout=PIPE,
|
|
554
|
+
stderr=(None if verbose else PIPE),
|
|
555
|
+
cwd=tempd.name)
|
|
556
|
+
|
|
557
|
+
ans, err = latte_proc.communicate(arg)
|
|
558
|
+
if err:
|
|
559
|
+
err = bytes_to_str(err)
|
|
560
|
+
ret_code = latte_proc.poll()
|
|
561
|
+
if ret_code:
|
|
562
|
+
if err is None:
|
|
563
|
+
err = ", see error message above"
|
|
564
|
+
else:
|
|
565
|
+
err = ":\n" + err
|
|
566
|
+
raise RuntimeError("LattE integrale program failed (exit code {})".format(ret_code) + err.strip())
|
|
567
|
+
|
|
568
|
+
ans = bytes_to_str(ans)
|
|
569
|
+
ans = ans.splitlines()
|
|
570
|
+
ans = ans[-5].split()
|
|
571
|
+
assert ans[0] == 'Answer:'
|
|
572
|
+
ans = ans[1]
|
|
573
|
+
|
|
574
|
+
tempd.cleanup()
|
|
575
|
+
if raw_output:
|
|
576
|
+
return ans
|
|
577
|
+
else:
|
|
578
|
+
return Rational(ans)
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
def to_latte_polynomial(polynomial):
|
|
582
|
+
r"""
|
|
583
|
+
Helper function to transform a polynomial to its LattE description.
|
|
584
|
+
|
|
585
|
+
INPUT:
|
|
586
|
+
|
|
587
|
+
- ``polynomial`` -- a multivariate polynomial
|
|
588
|
+
|
|
589
|
+
OUTPUT: string that describes the monomials list and exponent vectors
|
|
590
|
+
|
|
591
|
+
TESTS:
|
|
592
|
+
|
|
593
|
+
Testing a polynomial in three variables::
|
|
594
|
+
|
|
595
|
+
sage: from sage.interfaces.latte import to_latte_polynomial
|
|
596
|
+
sage: x, y, z = polygens(QQ, 'x, y, z')
|
|
597
|
+
sage: f = 3*x^2*y^4*z^6 + 7*y^3*z^5
|
|
598
|
+
sage: to_latte_polynomial(f)
|
|
599
|
+
'[[3, [2, 4, 6]], [7, [0, 3, 5]]]'
|
|
600
|
+
|
|
601
|
+
sage: to_latte_polynomial(x.parent().zero())
|
|
602
|
+
'[]'
|
|
603
|
+
|
|
604
|
+
Testing a univariate polynomial::
|
|
605
|
+
|
|
606
|
+
sage: x = polygen(QQ, 'x')
|
|
607
|
+
sage: to_latte_polynomial((x-1)^2)
|
|
608
|
+
'[[1, [0]], [-2, [1]], [1, [2]]]'
|
|
609
|
+
|
|
610
|
+
sage: to_latte_polynomial(x.parent().zero())
|
|
611
|
+
'[]'
|
|
612
|
+
"""
|
|
613
|
+
if polynomial == 0:
|
|
614
|
+
return str([])
|
|
615
|
+
|
|
616
|
+
from sage.rings.polynomial.polydict import ETuple
|
|
617
|
+
|
|
618
|
+
coefficients_list = polynomial.coefficients()
|
|
619
|
+
|
|
620
|
+
# transform list of exponents into a list of lists.
|
|
621
|
+
# this branch handles the multivariate/univariate case
|
|
622
|
+
if isinstance(polynomial.exponents()[0], ETuple):
|
|
623
|
+
exponents_list = [list(exponent_vector_i) for exponent_vector_i in polynomial.exponents()]
|
|
624
|
+
else:
|
|
625
|
+
exponents_list = [[exponent_vector_i] for exponent_vector_i in polynomial.exponents()]
|
|
626
|
+
|
|
627
|
+
# assuming that the order in coefficients() and exponents() methods match
|
|
628
|
+
monomials_list = [list(monomial_i)
|
|
629
|
+
for monomial_i
|
|
630
|
+
in zip(coefficients_list, exponents_list)]
|
|
631
|
+
|
|
632
|
+
return str(monomials_list)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-latte-4ti2
|
|
Binary file
|
sage/libs/latte_int.pyx
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-latte-4ti2
|
sage_wheels/bin/4ti2gmp
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|