Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
241818 views
1
r"""
2
Classes describing the Fourier expansion of Jacobi forms of degree `1`
3
with indices in `\mathbf{N}`.
4
5
AUTHOR :
6
7
- Martin Raum (2010 - 04 - 04) Initial version
8
"""
9
10
#===============================================================================
11
#
12
# Copyright (C) 2010 Martin Raum
13
#
14
# This program is free software; you can redistribute it and/or
15
# modify it under the terms of the GNU General Public License
16
# as published by the Free Software Foundation; either version 3
17
# of the License, or (at your option) any later version.
18
#
19
# This program is distributed in the hope that it will be useful,
20
# but WITHOUT ANY WARRANTY; without even the implied warranty of
21
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22
# General Public License for more details.
23
#
24
# You should have received a copy of the GNU General Public License
25
# along with this program; if not, see <http://www.gnu.org/licenses/>.
26
#
27
#===============================================================================
28
29
## even weight
30
## c(n, r) = c(n', r') <=> r' \equiv \pm r (2m) and r'**2 - 4 n' m = r**2 - 4 n m
31
32
from operator import xor
33
from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import TrivialCharacterMonoid,\
34
TrivialRepresentation
35
from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_module import EquivariantMonoidPowerSeriesModule
36
from psage.modform.jacobiforms.jacobiformd1nn_fourierexpansion_cython import creduce, \
37
mult_coeff_int, mult_coeff_int_weak, \
38
mult_coeff_generic, mult_coeff_generic_weak
39
from sage.matrix.constructor import matrix
40
from sage.misc.cachefunc import cached_method, cached_function
41
from sage.misc.functional import isqrt
42
from sage.misc.latex import latex
43
from sage.rings.infinity import infinity
44
from sage.rings.integer import Integer
45
from sage.rings.integer_ring import ZZ
46
from sage.rings.rational_field import QQ
47
from sage.structure.sage_object import SageObject
48
import itertools
49
import operator
50
51
52
#===============================================================================
53
# JacobiFormD1NNIndices
54
#===============================================================================
55
56
class JacobiFormD1NNIndices ( SageObject ) :
57
def __init__(self, m, reduced = True, weak_forms = False) :
58
r"""
59
INPUT:
60
61
- `m` -- The index of the associated Jacobi forms.
62
- ``reduced`` -- If True the reduction of Fourier indices
63
with respect to the full Jacobi group
64
will be considered. Otherwise, only the
65
restriction `r**2 =< 4 n m` or `r**2 =< 4 m n + m**2`
66
will be considered.
67
- ``weak_forms`` -- If True the weak condition
68
`r**2 =< 4 m n` will be imposed on the
69
indices.
70
NOTE:
71
72
The Fourier expansion of a form is assumed to be indexed
73
`\sum c(n,r) z^n \zeta^r` . The indices are pairs `(n, r)`.
74
"""
75
self.__m = m
76
self.__reduced = reduced
77
self.__weak_forms = weak_forms
78
79
def ngens(self) :
80
return len(self.gens())
81
82
def gen(self, i = 0) :
83
if i < self.ngens() :
84
return self.gens()[i]
85
86
raise ValueError("There is no generator %s" % (i,))
87
88
@cached_method
89
def gens(self) :
90
# FIXME: This is incorrect for almost all indices m
91
return [(1,0), (1,1)]
92
93
def jacobi_index(self) :
94
return self.__m
95
96
def is_commutative(self) :
97
return True
98
99
def monoid(self) :
100
return JacobiFormD1NNIndices(self.__m, False, self.__weak_forms)
101
102
def group(self) :
103
r"""
104
These are the invertible, integral lower triogonal matrices
105
with bottom right entry `1`.
106
"""
107
return "L^1_2(ZZ)"
108
109
def is_monoid_action(self) :
110
r"""
111
True if the representation respects the monoid structure.
112
"""
113
return False
114
115
def filter(self, bound) :
116
return JacobiFormD1NNFilter(bound, self.__m, self.__reduced, self.__weak_forms)
117
118
def filter_all(self) :
119
return JacobiFormD1NNFilter(infinity, self.__m, self.__reduced, self.__weak_forms)
120
121
def minimal_composition_filter(self, ls, rs) :
122
return JacobiFormD1NNFilter( min([k[0] for k in ls])
123
+ min([k[0] for k in rs]),
124
self.__reduced, self.__weak_forms )
125
126
def _reduction_function(self) :
127
return lambda k: creduce(k, self.__m)
128
129
def reduce(self, s) :
130
return creduce(s, self.__m)
131
132
def decompositions(self, s) :
133
(n, r) = s
134
135
fm = 4 * self.__m
136
if self.__weak_forms :
137
yield ((0,0), (n,r))
138
yield ((n,r), (0,0))
139
140
msq = self.__m**2
141
for n1 in xrange(1, n) :
142
n2 = n - n1
143
for r1 in xrange( max(r - isqrt(fm * n2 + msq),
144
isqrt(fm * n1 + msq - 1) + 1),
145
min( r + isqrt(fm * n2 + msq) + 1,
146
isqrt(fm * n1 + msq) + 1 ) ) :
147
yield ((n1, r1), (n2, r - r1))
148
else :
149
yield ((0,0), (n,r))
150
yield ((n,r), (0,0))
151
152
for n1 in xrange(1, n) :
153
n2 = n - n1
154
##r = r1 + r2
155
##r1**2 <= 4 n1 m
156
## (r - r1)**2 <= 4 n2 m
157
## r1**2 - 2*r1*r + r**2 - 4 m n2 <= 0
158
## r1 <-> r \pm \sqrt{r**2 - r**2 + 4 m n2}
159
for r1 in xrange( max(r - isqrt(fm * n2),
160
isqrt(fm * n1 - 1) + 1),
161
min( r + isqrt(fm * n2) + 1,
162
isqrt(fm * n1) + 1 ) ) :
163
yield ((n1, r1), (n2, r - r1))
164
165
raise StopIteration
166
167
def zero_element(self) :
168
return (0,0)
169
170
def __contains__(self, k) :
171
try :
172
(n, r) = k
173
except TypeError:
174
return False
175
176
return isinstance(n, (int, Integer)) and isinstance(r, (int,Integer))
177
178
def __cmp__(self, other) :
179
c = cmp(type(self), type(other))
180
181
if c == 0 :
182
c = cmp(self.__reduced, other.__reduced)
183
if c == 0 :
184
c = cmp(self.__weak_forms, other.__weak_forms)
185
if c == 0 :
186
c = cmp(self.__m, other.__m)
187
188
return c
189
190
def __hash__(self) :
191
return reduce(xor, [hash(self.__m), hash(self.__reduced),
192
hash(self.__weak_forms)])
193
194
def _repr_(self) :
195
return "Jacobi Fourier indices for index %s forms" % (self.__m,)
196
197
def _latex_(self) :
198
return r"\text{Jacobi Fourier indices for index $%s$ forms}" % (latex(self.__m),)
199
200
#===============================================================================
201
# JacobiFormD1NNFilter
202
#===============================================================================
203
204
class JacobiFormD1NNFilter ( SageObject ) :
205
r"""
206
The filter which will consider the index `n` in the normal
207
notation `\sum c(n,r) z^n \zeta^r`.
208
"""
209
210
def __init__(self, bound, m, reduced = True, weak_forms = False) :
211
r"""
212
INPUT:
213
214
- ``bound`` -- A natural number or exceptionally
215
infinity reflection the bound for n.
216
- `m` -- The index of the associated Jacobi forms.
217
- ``reduced`` -- If True the reduction of Fourier indices
218
with respect to the full Jacobi group
219
will be considered. Otherwise, only the
220
restriction `r**2 \le 4 n m` or `r**2 \le 4 m n + m^2`
221
will be considered.
222
- ``weak_forms`` -- If True the weak condition
223
`r**2 \le 4 m n` will be imposed on the
224
indices.
225
NOTE:
226
227
The Fourier expansion of a form is assumed to be indexed
228
`\sum c(n,r) z^n \zeta^r` . The indices are pairs `(n, r)`.
229
"""
230
self.__m = m
231
if isinstance(bound, JacobiFormD1NNFilter) :
232
bound = bound.index()
233
self.__bound = bound
234
self.__reduced = reduced
235
self.__weak_forms = weak_forms
236
237
def jacobi_index(self) :
238
return self.__m
239
240
def is_reduced(self) :
241
return self.__reduced
242
243
def is_weak_filter(self) :
244
"""
245
Return whether this is a filter for weak Jacobi forms or not.
246
"""
247
return self.__weak_jacobi_forms
248
249
def filter_all(self) :
250
return JacobiFormD1NNFilter(infinity, self.__m, self.__reduced, self.__weak_forms)
251
252
def zero_filter(self) :
253
return JacobiFormD1NNFilter(0, self.__m, self.__reduced, self.__weak_forms)
254
255
def is_infinite(self) :
256
return self.__bound is infinity
257
258
def is_all(self) :
259
return self.is_infinite()
260
261
def index(self) :
262
return self.__bound
263
264
def __contains__(self, k) :
265
m = self.__m
266
267
if ( k[1]**2 > 4 * m * k[0] + m**2
268
if self.__weak_forms
269
else k[1]**2 > 4 * m * k[0] ) :
270
return False
271
272
if k[0] < self.__bound :
273
return True
274
elif self.__reduced :
275
return creduce(k, m)[0][0] < self.__bound
276
277
return False
278
279
def __iter__(self) :
280
return itertools.chain(self.iter_indefinite_forms(),
281
self.iter_positive_forms())
282
283
def iter_positive_forms(self) :
284
fm = 4 * self.__m
285
if self.__reduced :
286
if self.__weak_forms :
287
msq = self.__m**2
288
for n in xrange(1, self.__bound) :
289
for r in xrange(min(self.__m + 1, isqrt(fm * n + msq - 1) + 1)) :
290
yield (n, r)
291
else :
292
for n in xrange(1, self.__bound) :
293
for r in xrange(min(self.__m + 1, isqrt(fm * n - 1) + 1)) :
294
yield (n, r)
295
else :
296
if self.__weak_forms :
297
msq = self.__m**2
298
for n in xrange(1, self.__bound) :
299
for r in xrange(isqrt(fm * n + msq - 1) + 1) :
300
yield (n, r)
301
else :
302
for n in xrange(1, self.__bound) :
303
for r in xrange(isqrt(fm * n - 1) + 1) :
304
yield (n, r)
305
306
raise StopIteration
307
308
def iter_indefinite_forms(self) :
309
fm = Integer(4 * self.__m)
310
311
if self.__reduced :
312
if self.__weak_forms :
313
msq = self.__m**2
314
for n in xrange(0, min(self.__m // 4 + 1, self.__bound)) :
315
for r in xrange( isqrt(fm * n - 1) + 1 if n != 0 else 0,
316
isqrt(fm * n + msq + 1) ) :
317
yield (n, r)
318
else :
319
320
for r in xrange(0, min(self.__m + 1,
321
isqrt((self.__bound - 1) * fm) + 1) ) :
322
if fm.divides(r**2) :
323
yield (r**2 // fm, r)
324
else :
325
if self.__weak_forms :
326
msq = self.__m**2
327
for n in xrange(0, self.__bound) :
328
for r in xrange( isqrt(fm * n - 1) + 1 if n != 0 else 0,
329
isqrt(fm * n + msq + 1) ) :
330
yield (n, r)
331
else :
332
for n in xrange(0, self.__bound) :
333
if (fm * n).is_square() :
334
yield(n, isqrt(fm * n))
335
336
raise StopIteration
337
338
def __cmp__(self, other) :
339
c = cmp(type(self), type(other))
340
341
if c == 0 :
342
c = cmp(self.__reduced, other.__reduced)
343
if c == 0 :
344
c = cmp(self.__weak_forms, other.__weak_forms)
345
if c == 0 :
346
c = cmp(self.__m, other.__m)
347
if c == 0 :
348
c = cmp(self.__bound, other.__bound)
349
350
return c
351
352
def __hash__(self) :
353
return reduce( xor, map(hash, [ self.__reduced, self.__weak_forms,
354
self.__m, self.__bound ]) )
355
356
def _repr_(self) :
357
return "Jacobi precision %s" % (self.__bound,)
358
359
def _latex_(self) :
360
return r"\text{Jacobi precision $%s$}" % (latex(self.__bound),)
361
362
#===============================================================================
363
# JacobiD1NNFourierExpansionModule
364
#===============================================================================
365
366
def JacobiD1NNFourierExpansionModule(K, m, weak_forms = False) :
367
r"""
368
INPUT:
369
370
- `m` -- The index of the associated Jacobi forms.
371
- `weak_forms` -- If True the weak condition
372
`r^2 \le 4 m n`n will be imposed on the
373
indices.
374
"""
375
376
R = EquivariantMonoidPowerSeriesModule(
377
JacobiFormD1NNIndices(m, weak_forms = weak_forms),
378
TrivialCharacterMonoid("L^1_2(ZZ)", ZZ),
379
TrivialRepresentation("L^1_2(ZZ)", K) )
380
381
if K is ZZ :
382
R._set_multiply_function( lambda k, d1,d2, ch1,ch2, res : mult_coeff_int(k, d1, d2, ch1, ch2, res, m)
383
if not weak_forms
384
else lambda k, d1,d2, ch1,ch2, res : mult_coeff_int_weak(k, d1, d2, ch1, ch2, res, m) )
385
else :
386
R._set_multiply_function( lambda k, d1,d2, ch1,ch2, res : mult_coeff_generic(k, d1, d2, ch1, ch2, res, m)
387
if not weak_forms
388
else lambda k, d1,d2, ch1,ch2, res : mult_coeff_generic_weak(k, d1, d2, ch1, ch2, res, m) )
389
390
return R
391
392