Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/functions/transcendental.py
8815 views
1
"""
2
Transcendental Functions
3
"""
4
5
#*****************************************************************************
6
# Copyright (C) 2005 William Stein <[email protected]>
7
#
8
# Distributed under the terms of the GNU General Public License (GPL)
9
#
10
# This code is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
# General Public License for more details.
14
#
15
# The full text of the GPL is available at:
16
#
17
# http://www.gnu.org/licenses/
18
#*****************************************************************************
19
20
import sys
21
import sage.libs.pari.all
22
from sage.libs.pari.all import pari
23
import sage.rings.complex_field as complex_field
24
from sage.structure.coerce import parent
25
from sage.structure.element import get_coercion_model
26
from sage.symbolic.expression import Expression
27
from sage.functions.other import factorial, psi
28
29
from sage.rings.all import (ComplexField, ZZ, RR, RDF)
30
from sage.rings.complex_number import is_ComplexNumber
31
from sage.rings.real_mpfr import (RealField, is_RealNumber)
32
33
from sage.symbolic.function import GinacFunction, BuiltinFunction, is_inexact
34
35
import sage.libs.mpmath.utils as mpmath_utils
36
from sage.misc.superseded import deprecation
37
from sage.combinat.combinat import bernoulli_polynomial
38
39
CC = complex_field.ComplexField()
40
I = CC.gen(0)
41
42
43
class Function_zeta(GinacFunction):
44
def __init__(self):
45
r"""
46
Riemann zeta function at s with s a real or complex number.
47
48
INPUT:
49
50
- ``s`` - real or complex number
51
52
If s is a real number the computation is done using the MPFR
53
library. When the input is not real, the computation is done using
54
the PARI C library.
55
56
EXAMPLES::
57
58
sage: zeta(x)
59
zeta(x)
60
sage: zeta(2)
61
1/6*pi^2
62
sage: zeta(2.)
63
1.64493406684823
64
sage: RR = RealField(200)
65
sage: zeta(RR(2))
66
1.6449340668482264364724151666460251892189499012067984377356
67
sage: zeta(I)
68
zeta(I)
69
sage: zeta(I).n()
70
0.00330022368532410 - 0.418155449141322*I
71
72
It is possible to use the ``hold`` argument to prevent
73
automatic evaluation::
74
75
sage: zeta(2,hold=True)
76
zeta(2)
77
78
To then evaluate again, we currently must use Maxima via
79
:meth:`sage.symbolic.expression.Expression.simplify`::
80
81
sage: a = zeta(2,hold=True); a.simplify()
82
1/6*pi^2
83
84
TESTS::
85
86
sage: latex(zeta(x))
87
\zeta(x)
88
sage: a = loads(dumps(zeta(x)))
89
sage: a.operator() == zeta
90
True
91
92
sage: zeta(1)
93
Infinity
94
sage: zeta(x).subs(x=1)
95
Infinity
96
"""
97
GinacFunction.__init__(self, "zeta")
98
99
zeta = Function_zeta()
100
101
102
class Function_HurwitzZeta(BuiltinFunction):
103
def __init__(self):
104
r"""
105
TESTS::
106
107
sage: latex(hurwitz_zeta(x, 2))
108
\zeta\left(x, 2\right)
109
sage: hurwitz_zeta(x, 2)._sympy_()
110
zeta(x, 2)
111
"""
112
BuiltinFunction.__init__(self, 'hurwitz_zeta', nargs=2,
113
conversions=dict(mathematica='HurwitzZeta',
114
sympy='zeta'),
115
latex_name='\zeta')
116
117
def _eval_(self, s, x):
118
r"""
119
TESTS::
120
121
sage: hurwitz_zeta(x, 1)
122
zeta(x)
123
sage: hurwitz_zeta(4, 3)
124
1/90*pi^4 - 17/16
125
sage: hurwitz_zeta(-4, x)
126
-1/5*x^5 + 1/2*x^4 - 1/3*x^3 + 1/30*x
127
sage: hurwitz_zeta(3, 0.5)
128
8.41439832211716
129
"""
130
co = get_coercion_model().canonical_coercion(s, x)[0]
131
if is_inexact(co) and not isinstance(co, Expression):
132
return self._evalf_(s, x, parent=parent(co))
133
if x == 1:
134
return zeta(s)
135
if s in ZZ and s > 1:
136
return ((-1) ** s) * psi(s - 1, x) / factorial(s - 1)
137
elif s in ZZ and s < 0:
138
return -bernoulli_polynomial(x, -s + 1) / (-s + 1)
139
else:
140
return
141
142
def _evalf_(self, s, x, parent):
143
r"""
144
TESTS::
145
146
sage: hurwitz_zeta(11/10, 1/2).n()
147
12.1038134956837
148
sage: hurwitz_zeta(11/10, 1/2).n(100)
149
12.103813495683755105709077413
150
sage: hurwitz_zeta(11/10, 1 + 1j).n()
151
9.85014164287853 - 1.06139499403981*I
152
"""
153
from mpmath import zeta
154
return mpmath_utils.call(zeta, s, x, parent=parent)
155
156
def _derivative_(self, s, x, diff_param):
157
r"""
158
TESTS::
159
160
sage: y = var('y')
161
sage: diff(hurwitz_zeta(x, y), y)
162
-x*hurwitz_zeta(x + 1, y)
163
"""
164
if diff_param == 1:
165
return -s * hurwitz_zeta(s + 1, x)
166
else:
167
raise NotImplementedError('derivative with respect to first '
168
'argument')
169
170
hurwitz_zeta_func = Function_HurwitzZeta()
171
172
173
def hurwitz_zeta(s, x, prec=None, **kwargs):
174
r"""
175
The Hurwitz zeta function `\zeta(s, x)`, where `s` and `x` are complex.
176
177
The Hurwitz zeta function is one of the many zeta functions. It
178
defined as
179
180
.. math::
181
182
\zeta(s, x) = \sum_{k=0}^{\infty} (k + x)^{-s}.
183
184
185
When `x = 1`, this coincides with Riemann's zeta function.
186
The Dirichlet L-functions may be expressed as a linear combination
187
of Hurwitz zeta functions.
188
189
EXAMPLES:
190
191
Symbolic evaluations::
192
193
sage: hurwitz_zeta(x, 1)
194
zeta(x)
195
sage: hurwitz_zeta(4, 3)
196
1/90*pi^4 - 17/16
197
sage: hurwitz_zeta(-4, x)
198
-1/5*x^5 + 1/2*x^4 - 1/3*x^3 + 1/30*x
199
sage: hurwitz_zeta(7, -1/2)
200
127*zeta(7) - 128
201
sage: hurwitz_zeta(-3, 1)
202
1/120
203
204
Numerical evaluations::
205
206
sage: hurwitz_zeta(3, 1/2).n()
207
8.41439832211716
208
sage: hurwitz_zeta(11/10, 1/2).n()
209
12.1038134956837
210
sage: hurwitz_zeta(3, x).series(x, 60).subs(x=0.5).n()
211
8.41439832211716
212
sage: hurwitz_zeta(3, 0.5)
213
8.41439832211716
214
215
REFERENCES:
216
217
- :wikipedia:`Hurwitz_zeta_function`
218
"""
219
if prec:
220
deprecation(15095, 'the syntax hurwitz_zeta(s, x, prec) has been '
221
'deprecated. Use hurwitz_zeta(s, x).n(digits=prec) '
222
'instead.')
223
return hurwitz_zeta_func(s, x).n(digits=prec)
224
return hurwitz_zeta_func(s, x, **kwargs)
225
226
227
class Function_zetaderiv(GinacFunction):
228
def __init__(self):
229
r"""
230
Derivatives of the Riemann zeta function.
231
232
EXAMPLES::
233
234
sage: zetaderiv(1, x)
235
zetaderiv(1, x)
236
sage: zetaderiv(1, x).diff(x)
237
zetaderiv(2, x)
238
sage: var('n')
239
n
240
sage: zetaderiv(n,x)
241
zetaderiv(n, x)
242
sage: zetaderiv(1, 4).n()
243
-0.0689112658961254
244
sage: import mpmath; mpmath.diff(lambda x: mpmath.zeta(x), 4)
245
mpf('-0.068911265896125382')
246
247
TESTS::
248
249
sage: latex(zetaderiv(2,x))
250
\zeta^\prime\left(2, x\right)
251
sage: a = loads(dumps(zetaderiv(2,x)))
252
sage: a.operator() == zetaderiv
253
True
254
"""
255
GinacFunction.__init__(self, "zetaderiv", nargs=2)
256
257
def _evalf_(self, n, x, parent):
258
from mpmath import zeta
259
return mpmath_utils.call(zeta, x, 1, n, parent=parent)
260
261
zetaderiv = Function_zetaderiv()
262
263
def zeta_symmetric(s):
264
r"""
265
Completed function `\xi(s)` that satisfies
266
`\xi(s) = \xi(1-s)` and has zeros at the same points as the
267
Riemann zeta function.
268
269
INPUT:
270
271
272
- ``s`` - real or complex number
273
274
275
If s is a real number the computation is done using the MPFR
276
library. When the input is not real, the computation is done using
277
the PARI C library.
278
279
More precisely,
280
281
.. math::
282
283
xi(s) = \gamma(s/2 + 1) * (s-1) * \pi^{-s/2} * \zeta(s).
284
285
286
287
EXAMPLES::
288
289
sage: zeta_symmetric(0.7)
290
0.497580414651127
291
sage: zeta_symmetric(1-0.7)
292
0.497580414651127
293
sage: RR = RealField(200)
294
sage: zeta_symmetric(RR(0.7))
295
0.49758041465112690357779107525638385212657443284080589766062
296
sage: C.<i> = ComplexField()
297
sage: zeta_symmetric(0.5 + i*14.0)
298
0.000201294444235258 + 1.49077798716757e-19*I
299
sage: zeta_symmetric(0.5 + i*14.1)
300
0.0000489893483255687 + 4.40457132572236e-20*I
301
sage: zeta_symmetric(0.5 + i*14.2)
302
-0.0000868931282620101 + 7.11507675693612e-20*I
303
304
REFERENCE:
305
306
- I copied the definition of xi from
307
http://web.viu.ca/pughg/RiemannZeta/RiemannZetaLong.html
308
"""
309
if not (is_ComplexNumber(s) or is_RealNumber(s)):
310
s = ComplexField()(s)
311
312
R = s.parent()
313
if s == 1: # deal with poles, hopefully
314
return R(0.5)
315
316
return (s/2 + 1).gamma() * (s-1) * (R.pi()**(-s/2)) * s.zeta()
317
318
import math
319
from sage.rings.polynomial.polynomial_real_mpfr_dense import PolynomialRealDense
320
321
class DickmanRho(BuiltinFunction):
322
r"""
323
Dickman's function is the continuous function satisfying the
324
differential equation
325
326
.. math::
327
328
x \rho'(x) + \rho(x-1) = 0
329
330
with initial conditions `\rho(x)=1` for
331
`0 \le x \le 1`. It is useful in estimating the frequency
332
of smooth numbers as asymptotically
333
334
.. math::
335
336
\Psi(a, a^{1/s}) \sim a \rho(s)
337
338
where `\Psi(a,b)` is the number of `b`-smooth
339
numbers less than `a`.
340
341
ALGORITHM:
342
343
Dickmans's function is analytic on the interval
344
`[n,n+1]` for each integer `n`. To evaluate at
345
`n+t, 0 \le t < 1`, a power series is recursively computed
346
about `n+1/2` using the differential equation stated above.
347
As high precision arithmetic may be needed for intermediate results
348
the computed series are cached for later use.
349
350
Simple explicit formulas are used for the intervals [0,1] and
351
[1,2].
352
353
EXAMPLES::
354
355
sage: dickman_rho(2)
356
0.306852819440055
357
sage: dickman_rho(10)
358
2.77017183772596e-11
359
sage: dickman_rho(10.00000000000000000000000000000000000000)
360
2.77017183772595898875812120063434232634e-11
361
sage: plot(log(dickman_rho(x)), (x, 0, 15))
362
363
AUTHORS:
364
365
- Robert Bradshaw (2008-09)
366
367
REFERENCES:
368
369
- G. Marsaglia, A. Zaman, J. Marsaglia. "Numerical
370
Solutions to some Classical Differential-Difference Equations."
371
Mathematics of Computation, Vol. 53, No. 187 (1989).
372
"""
373
def __init__(self):
374
"""
375
Constructs an object to represent Dickman's rho function.
376
377
TESTS::
378
379
sage: dickman_rho(x)
380
dickman_rho(x)
381
sage: dickman_rho(3)
382
0.0486083882911316
383
sage: dickman_rho(pi)
384
0.0359690758968463
385
"""
386
self._cur_prec = 0
387
BuiltinFunction.__init__(self, "dickman_rho", 1)
388
389
def _eval_(self, x):
390
"""
391
EXAMPLES::
392
393
sage: [dickman_rho(n) for n in [1..10]]
394
[1.00000000000000, 0.306852819440055, 0.0486083882911316, 0.00491092564776083, 0.000354724700456040, 0.0000196496963539553, 8.74566995329392e-7, 3.23206930422610e-8, 1.01624828273784e-9, 2.77017183772596e-11]
395
sage: dickman_rho(0)
396
1.00000000000000
397
"""
398
if not is_RealNumber(x):
399
try:
400
x = RR(x)
401
except (TypeError, ValueError):
402
return None #PrimitiveFunction.__call__(self, SR(x))
403
if x < 0:
404
return x.parent()(0)
405
elif x <= 1:
406
return x.parent()(1)
407
elif x <= 2:
408
return 1 - x.log()
409
n = x.floor()
410
if self._cur_prec < x.parent().prec() or not self._f.has_key(n):
411
self._cur_prec = rel_prec = x.parent().prec()
412
# Go a bit beyond so we're not constantly re-computing.
413
max = x.parent()(1.1)*x + 10
414
abs_prec = (-self.approximate(max).log2() + rel_prec + 2*max.log2()).ceil()
415
self._f = {}
416
if sys.getrecursionlimit() < max + 10:
417
sys.setrecursionlimit(int(max) + 10)
418
self._compute_power_series(max.floor(), abs_prec, cache_ring=x.parent())
419
return self._f[n](2*(x-n-x.parent()(0.5)))
420
421
def power_series(self, n, abs_prec):
422
"""
423
This function returns the power series about `n+1/2` used
424
to evaluate Dickman's function. It is scaled such that the interval
425
`[n,n+1]` corresponds to x in `[-1,1]`.
426
427
INPUT:
428
429
- ``n`` - the lower endpoint of the interval for which
430
this power series holds
431
432
- ``abs_prec`` - the absolute precision of the
433
resulting power series
434
435
EXAMPLES::
436
437
sage: f = dickman_rho.power_series(2, 20); f
438
-9.9376e-8*x^11 + 3.7722e-7*x^10 - 1.4684e-6*x^9 + 5.8783e-6*x^8 - 0.000024259*x^7 + 0.00010341*x^6 - 0.00045583*x^5 + 0.0020773*x^4 - 0.0097336*x^3 + 0.045224*x^2 - 0.11891*x + 0.13032
439
sage: f(-1), f(0), f(1)
440
(0.30685, 0.13032, 0.048608)
441
sage: dickman_rho(2), dickman_rho(2.5), dickman_rho(3)
442
(0.306852819440055, 0.130319561832251, 0.0486083882911316)
443
"""
444
return self._compute_power_series(n, abs_prec, cache_ring=None)
445
446
def _compute_power_series(self, n, abs_prec, cache_ring=None):
447
"""
448
Compute the power series giving Dickman's function on [n, n+1], by
449
recursion in n. For internal use; self.power_series() is a wrapper
450
around this intended for the user.
451
452
INPUT:
453
454
- ``n`` - the lower endpoint of the interval for which
455
this power series holds
456
457
- ``abs_prec`` - the absolute precision of the
458
resulting power series
459
460
- ``cache_ring`` - for internal use, caches the power
461
series at this precision.
462
463
EXAMPLES::
464
465
sage: f = dickman_rho.power_series(2, 20); f
466
-9.9376e-8*x^11 + 3.7722e-7*x^10 - 1.4684e-6*x^9 + 5.8783e-6*x^8 - 0.000024259*x^7 + 0.00010341*x^6 - 0.00045583*x^5 + 0.0020773*x^4 - 0.0097336*x^3 + 0.045224*x^2 - 0.11891*x + 0.13032
467
"""
468
if n <= 1:
469
if n <= -1:
470
return PolynomialRealDense(RealField(abs_prec)['x'])
471
if n == 0:
472
return PolynomialRealDense(RealField(abs_prec)['x'], [1])
473
elif n == 1:
474
nterms = (RDF(abs_prec) * RDF(2).log()/RDF(3).log()).ceil()
475
R = RealField(abs_prec)
476
neg_three = ZZ(-3)
477
coeffs = [1 - R(1.5).log()] + [neg_three**-k/k for k in range(1, nterms)]
478
f = PolynomialRealDense(R['x'], coeffs)
479
if cache_ring is not None:
480
self._f[n] = f.truncate_abs(f[0] >> (cache_ring.prec()+1)).change_ring(cache_ring)
481
return f
482
else:
483
f = self._compute_power_series(n-1, abs_prec, cache_ring)
484
# integrand = f / (2n+1 + x)
485
# We calculate this way because the most significant term is the constant term,
486
# and so we want to push the error accumulation and remainder out to the least
487
# significant terms.
488
integrand = f.reverse().quo_rem(PolynomialRealDense(f.parent(), [1, 2*n+1]))[0].reverse()
489
integrand = integrand.truncate_abs(RR(2)**-abs_prec)
490
iintegrand = integrand.integral()
491
ff = PolynomialRealDense(f.parent(), [f(1) + iintegrand(-1)]) - iintegrand
492
i = 0
493
while abs(f[i]) < abs(f[i+1]):
494
i += 1
495
rel_prec = int(abs_prec + abs(RR(f[i])).log2())
496
if cache_ring is not None:
497
self._f[n] = ff.truncate_abs(ff[0] >> (cache_ring.prec()+1)).change_ring(cache_ring)
498
return ff.change_ring(RealField(rel_prec))
499
500
def approximate(self, x, parent=None):
501
r"""
502
Approximate using de Bruijn's formula
503
504
.. math::
505
506
\rho(x) \sim \frac{exp(-x \xi + Ei(\xi))}{\sqrt{2\pi x}\xi}
507
508
which is asymptotically equal to Dickman's function, and is much
509
faster to compute.
510
511
REFERENCES:
512
513
- N. De Bruijn, "The Asymptotic behavior of a function
514
occurring in the theory of primes." J. Indian Math Soc. v 15.
515
(1951)
516
517
EXAMPLES::
518
519
sage: dickman_rho.approximate(10)
520
2.41739196365564e-11
521
sage: dickman_rho(10)
522
2.77017183772596e-11
523
sage: dickman_rho.approximate(1000)
524
4.32938809066403e-3464
525
"""
526
log, exp, sqrt, pi = math.log, math.exp, math.sqrt, math.pi
527
x = float(x)
528
xi = log(x)
529
y = (exp(xi)-1.0)/xi - x
530
while abs(y) > 1e-12:
531
dydxi = (exp(xi)*(xi-1.0) + 1.0)/(xi*xi)
532
xi -= y/dydxi
533
y = (exp(xi)-1.0)/xi - x
534
return (-x*xi + RR(xi).eint()).exp() / (sqrt(2*pi*x)*xi)
535
536
dickman_rho = DickmanRho()
537
538