@@ -219,6 +219,38 @@ def _repr_(self):
219219 """
220220 return str (self .q_expansion ())
221221
222+ def _pari_init_ (self ):
223+ """
224+ Conversion to Pari.
225+
226+ TESTS::
227+
228+ sage: M = EisensteinForms(96, 2)
229+ sage: M.6
230+ O(q^6)
231+ sage: M.7
232+ O(q^6)
233+ sage: pari(M.6) == pari(M.7)
234+ False
235+ sage: pari(M.6).mfcoefs(10)
236+ [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
237+
238+ sage: M = ModularForms(DirichletGroup(17).0^2, 2)
239+ sage: pari(M.0).mfcoefs(5)
240+ [0, 1, Mod(-t^3 + t^2 - 1, t^4 + 1), Mod(t^3 - t^2 - t - 1, t^4 + 1), Mod(2*t^3 - t^2 + 2*t, t^4 + 1), Mod(-t^3 - t^2, t^4 + 1)]
241+ sage: M.0.qexp(5)
242+ q + (-zeta8^3 + zeta8^2 - 1)*q^2 + (zeta8^3 - zeta8^2 - zeta8 - 1)*q^3 + (2*zeta8^3 - zeta8^2 + 2*zeta8)*q^4 + O(q^5)
243+ """
244+ from sage .libs .pari import pari
245+ from sage .rings .number_field .number_field_element import NumberFieldElement
246+ M = pari (self .parent ())
247+ f = self .qexp (self .parent ().sturm_bound ())
248+ coefficients = [
249+ x .__pari__ ('t' ) if isinstance (x , NumberFieldElement ) else x
250+ for x in f ]
251+ # we cannot compute pari(f) directly because we need to set the variable name as t
252+ return M .mflinear (M .mftobasis (coefficients + [0 ] * (f .prec () - len (coefficients ))))
253+
222254 def __call__ (self , x , prec = None ):
223255 """
224256 Evaluate the `q`-expansion of this modular form at x.
@@ -233,9 +265,150 @@ def __call__(self, x, prec=None):
233265
234266 sage: f(0)
235267 0
236- """
268+
269+ Evaluate numerically::
270+
271+ sage: f = ModularForms(1, 12).0
272+ sage: f(0.3) # rel tol 1e-12
273+ 2.34524576548591e-6
274+ sage: f = EisensteinForms(1, 4).0
275+ sage: f(0.9) # rel tol 1e-12
276+ 1.26475942209241e7
277+
278+ TESTS::
279+
280+ sage: f = ModularForms(96, 2).0
281+ sage: f(0.3) # rel tol 1e-12
282+ 0.299999997396191
283+ sage: f(0.0+0.0*I)
284+ 0
285+
286+ For simplicity, ``float`` or ``complex`` input are converted to ``CC``, except for
287+ input ``0`` where exact result is returned::
288+
289+ sage: result = f(0.3r); result # rel tol 1e-12
290+ 0.299999997396191
291+ sage: result.parent()
292+ Complex Field with 53 bits of precision
293+ sage: result = f(0.3r + 0.3jr); result # rel tol 1e-12
294+ 0.299999359878484 + 0.299999359878484*I
295+ sage: result.parent()
296+ Complex Field with 53 bits of precision
297+
298+ Symbolic numerical values use precision of ``CC`` by default::
299+
300+ sage: f(sqrt(1/2)) # rel tol 1e-12
301+ 0.700041406692037
302+ sage: f(sqrt(1/2)*QQbar.zeta(8)) # rel tol 1e-12
303+ 0.496956554651376 + 0.496956554651376*I
304+
305+ Higher precision::
306+
307+ sage: f(ComplexField(128)(0.3)) # rel tol 1e-36
308+ 0.29999999739619131029285166058750164058
309+ sage: f(ComplexField(128)(1+2*I)/3) # rel tol 1e-36
310+ 0.32165384572356882556790532669389900691 + 0.67061244638367586302820790711257777390*I
311+
312+ Confirm numerical evaluation matches the q-expansion::
313+
314+ sage: f = EisensteinForms(1, 4).0
315+ sage: f(0.3) # rel tol 1e-12
316+ 741.741819297986
317+ sage: f.qexp(50).polynomial()(0.3) # rel tol 1e-12
318+ 741.741819297986
319+
320+ With a nontrivial character::
321+
322+ sage: M = ModularForms(DirichletGroup(17).0^2, 2)
323+ sage: M.0(0.5) # rel tol 1e-12
324+ 0.166916655031616 + 0.0111529051752428*I
325+ sage: M.0.qexp(60).polynomial()(0.5) # rel tol 1e-12
326+ 0.166916655031616 + 0.0111529051752428*I
327+
328+ Higher precision::
329+
330+ sage: f(ComplexField(128)(1+2*I)/3) # rel tol 1e-36
331+ 429.19994832206294278688085399056359632 - 786.15736284188243351153830824852974995*I
332+ sage: f.qexp(400).polynomial()(ComplexField(128)(1+2*I)/3) # rel tol 1e-36
333+ 429.19994832206294278688085399056359631 - 786.15736284188243351153830824852974999*I
334+
335+ Check ``SR`` does not make the result lose precision::
336+
337+ sage: f(ComplexField(128)(1+2*I)/3 + x - x) # rel tol 1e-36
338+ 429.19994832206294278688085399056359632 - 786.15736284188243351153830824852974995*I
339+ """
340+ from sage .rings .integer import Integer
341+ from sage .misc .functional import log
342+ from sage .structure .element import parent
343+ from sage .rings .complex_mpfr import ComplexNumber
344+ from sage .rings .cc import CC
345+ from sage .rings .real_mpfr import RealNumber
346+ from sage .symbolic .constants import pi
347+ from sage .rings .imaginary_unit import I # import from here instead of sage.symbolic.constants to avoid cast to SR
348+ from sage .symbolic .expression import Expression
349+ if isinstance (x , Expression ):
350+ try :
351+ x = x .pyobject ()
352+ except TypeError :
353+ pass
354+ if x in CC :
355+ if x == 0 :
356+ return self .qexp (1 )[0 ]
357+ if not isinstance (x , (RealNumber , ComplexNumber )):
358+ x = CC (x ) # might lose precision if this is done unconditionally (TODO what about interval and ball types?)
359+ if isinstance (x , (RealNumber , ComplexNumber )):
360+ return self .eval_at_tau (log (x )/ (2 * parent (x )(pi )* I )) # cast to parent(x) to force numerical evaluation of pi
237361 return self .q_expansion (prec )(x )
238362
363+ def eval_at_tau (self , tau ):
364+ r"""
365+ Evaluate this modular form at the half-period ratio `\tau`.
366+ This is related to `q` by `q = e^{2\pi i \tau}`.
367+
368+ EXAMPLES::
369+
370+ sage: f = ModularForms(1, 12).0
371+ sage: f.eval_at_tau(0.3 * I) # rel tol 1e-12
372+ 0.00150904633897550
373+
374+ TESTS:
375+
376+ Symbolic numerical values use precision of ``CC`` by default::
377+
378+ sage: f.eval_at_tau(sqrt(1/5)*I) # rel tol 1e-12
379+ 0.0123633234207127
380+ sage: f.eval_at_tau(sqrt(1/2)*QQbar.zeta(8)) # rel tol 1e-12
381+ -0.114263670441098
382+
383+ For simplicity, ``complex`` input are converted to ``CC``::
384+
385+ sage: result = f.eval_at_tau(0.3jr); result # rel tol 1e-12
386+ 0.00150904633897550
387+ sage: result.parent()
388+ Complex Field with 53 bits of precision
389+
390+ Check ``SR`` does not make the result lose precision::
391+
392+ sage: f = EisensteinForms(1, 4).0
393+ sage: f.eval_at_tau(ComplexField(128)(1+2*I)/3 + x - x) # rel tol 1e-36
394+ -1.0451570582202060056197878314286036966 + 2.7225112098519803098203933583286590274*I
395+ """
396+ from sage .libs .pari .convert_sage import gen_to_sage
397+ from sage .libs .pari import pari
398+ from sage .rings .cc import CC
399+ from sage .rings .complex_mpfr import ComplexNumber , ComplexField
400+ from sage .rings .real_mpfr import RealNumber
401+ from sage .symbolic .expression import Expression
402+ if isinstance (tau , Expression ):
403+ try :
404+ tau = tau .pyobject ()
405+ except TypeError :
406+ pass
407+ if not isinstance (tau , (RealNumber , ComplexNumber )):
408+ tau = CC (tau )
409+ precision = tau .prec ()
410+ return ComplexField (precision )(pari .mfeval (self .parent (), self , tau , precision = precision ))
411+
239412 @cached_method
240413 def valuation (self ):
241414 """
0 commit comments