Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/functions/transcendental.py
4079 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
from sage.libs.mpmath import utils as mpmath_utils
22
import sage.libs.pari.all
23
from sage.libs.pari.all import pari
24
import sage.rings.complex_field as complex_field
25
import sage.rings.real_double as real_double
26
from sage.gsl.integration import numerical_integral
27
from sage.structure.parent import Parent
28
from sage.structure.coerce import parent
29
from sage.symbolic.expression import Expression
30
from sage.functions.log import exp
31
32
from sage.rings.all import (is_RealNumber, RealField,
33
is_ComplexNumber, ComplexField,
34
ZZ, RR, RDF, CDF, prime_range)
35
36
from sage.symbolic.function import GinacFunction, BuiltinFunction, is_inexact
37
38
39
CC = complex_field.ComplexField()
40
I = CC.gen(0)
41
42
def exponential_integral_1(x, n=0):
43
r"""
44
Returns the exponential integral `E_1(x)`. If the optional
45
argument `n` is given, computes list of the first
46
`n` values of the exponential integral
47
`E_1(x m)`.
48
49
The exponential integral `E_1(x)` is
50
51
.. math::
52
53
E_1(x) = \int_{x}^{\infty} e^{-t}/t dt
54
55
56
57
INPUT:
58
59
60
- ``x`` - a positive real number
61
62
- ``n`` - (default: 0) a nonnegative integer; if
63
nonzero, then return a list of values E_1(x\*m) for m =
64
1,2,3,...,n. This is useful, e.g., when computing derivatives of
65
L-functions.
66
67
68
OUTPUT:
69
70
71
- ``float`` - if n is 0 (the default) or
72
73
- ``list`` - list of floats if n 0
74
75
76
EXAMPLES::
77
78
sage: exponential_integral_1(2)
79
0.04890051070806112
80
sage: w = exponential_integral_1(2,4); w
81
[0.04890051070806112, 0.003779352409848906..., 0.00036008245216265873, 3.7665622843924...e-05]
82
83
IMPLEMENTATION: We use the PARI C-library functions eint1 and
84
veceint1.
85
86
REFERENCE:
87
88
- See page 262, Prop 5.6.12, of Cohen's book "A Course in
89
Computational Algebraic Number Theory".
90
91
REMARKS: When called with the optional argument n, the PARI
92
C-library is fast for values of n up to some bound, then very very
93
slow. For example, if x=5, then the computation takes less than a
94
second for n=800000, and takes "forever" for n=900000.
95
"""
96
if n <= 0:
97
return float(pari(x).eint1())
98
else:
99
return [float(z) for z in pari(x).eint1(n)]
100
101
102
class Function_zeta(GinacFunction):
103
def __init__(self):
104
r"""
105
Riemann zeta function at s with s a real or complex number.
106
107
INPUT:
108
109
- ``s`` - real or complex number
110
111
If s is a real number the computation is done using the MPFR
112
library. When the input is not real, the computation is done using
113
the PARI C library.
114
115
EXAMPLES::
116
117
sage: zeta(x)
118
zeta(x)
119
sage: zeta(2)
120
1/6*pi^2
121
sage: zeta(2.)
122
1.64493406684823
123
sage: RR = RealField(200)
124
sage: zeta(RR(2))
125
1.6449340668482264364724151666460251892189499012067984377356
126
sage: zeta(I)
127
zeta(I)
128
sage: zeta(I).n()
129
0.00330022368532410 - 0.418155449141322*I
130
131
It is possible to use the ``hold`` argument to prevent
132
automatic evaluation::
133
134
sage: zeta(2,hold=True)
135
zeta(2)
136
137
To then evaluate again, we currently must use Maxima via
138
:meth:`sage.symbolic.expression.Expression.simplify`::
139
140
sage: a = zeta(2,hold=True); a.simplify()
141
1/6*pi^2
142
143
TESTS::
144
145
sage: latex(zeta(x))
146
\zeta(x)
147
sage: a = loads(dumps(zeta(x)))
148
sage: a.operator() == zeta
149
True
150
151
sage: zeta(1)
152
Infinity
153
sage: zeta(x).subs(x=1)
154
Infinity
155
"""
156
GinacFunction.__init__(self, "zeta")
157
158
zeta = Function_zeta()
159
160
class Function_zetaderiv(GinacFunction):
161
def __init__(self):
162
r"""
163
Derivatives of the Riemann zeta function.
164
165
EXAMPLES::
166
167
sage: zetaderiv(1, x)
168
zetaderiv(1, x)
169
sage: zetaderiv(1, x).diff(x)
170
zetaderiv(2, x)
171
sage: var('n')
172
n
173
sage: zetaderiv(n,x)
174
zetaderiv(n, x)
175
176
TESTS::
177
178
sage: latex(zetaderiv(2,x))
179
\zeta^\prime\left(2, x\right)
180
sage: a = loads(dumps(zetaderiv(2,x)))
181
sage: a.operator() == zetaderiv
182
True
183
"""
184
GinacFunction.__init__(self, "zetaderiv", nargs=2)
185
186
zetaderiv = Function_zetaderiv()
187
188
def zeta_symmetric(s):
189
r"""
190
Completed function `\xi(s)` that satisfies
191
`\xi(s) = \xi(1-s)` and has zeros at the same points as the
192
Riemann zeta function.
193
194
INPUT:
195
196
197
- ``s`` - real or complex number
198
199
200
If s is a real number the computation is done using the MPFR
201
library. When the input is not real, the computation is done using
202
the PARI C library.
203
204
More precisely,
205
206
.. math::
207
208
xi(s) = \gamma(s/2 + 1) * (s-1) * \pi^{-s/2} * \zeta(s).
209
210
211
212
EXAMPLES::
213
214
sage: zeta_symmetric(0.7)
215
0.497580414651127
216
sage: zeta_symmetric(1-0.7)
217
0.497580414651127
218
sage: RR = RealField(200)
219
sage: zeta_symmetric(RR(0.7))
220
0.49758041465112690357779107525638385212657443284080589766062
221
sage: C.<i> = ComplexField()
222
sage: zeta_symmetric(0.5 + i*14.0)
223
0.000201294444235258 + 1.49077798716757e-19*I
224
sage: zeta_symmetric(0.5 + i*14.1)
225
0.0000489893483255687 + 4.40457132572236e-20*I
226
sage: zeta_symmetric(0.5 + i*14.2)
227
-0.0000868931282620101 + 7.11507675693612e-20*I
228
229
REFERENCE:
230
231
- I copied the definition of xi from
232
http://www.math.ubc.ca/~pugh/RiemannZeta/RiemannZetaLong.html
233
"""
234
if not (is_ComplexNumber(s) or is_RealNumber(s)):
235
s = ComplexField()(s)
236
237
R = s.parent()
238
if s == 1: # deal with poles, hopefully
239
return R(0.5)
240
241
return (s/2 + 1).gamma() * (s-1) * (R.pi()**(-s/2)) * s.zeta()
242
243
244
## # Use PARI on complex nubmer
245
## prec = s.prec()
246
## s = pari.new_with_bits_prec(s, prec)
247
## pi = pari.pi()
248
## w = (s/2 + 1).gamma() * (s-1) * pi **(-s/2) * s.zeta()
249
## z = w._sage_()
250
## if z.prec() < prec:
251
## raise RuntimeError, "Error computing zeta_symmetric(%s) -- precision loss."%s
252
## return z
253
254
255
#def pi_approx(prec=53):
256
# """
257
# Return pi computed to prec bits of precision.
258
# """
259
# return real_field.RealField(prec).pi()
260
261
262
class Function_exp_integral(BuiltinFunction):
263
def __init__(self):
264
"""
265
Return the value of the complex exponential integral Ei(z) at a
266
complex number z.
267
268
EXAMPLES::
269
270
sage: Ei(10)
271
Ei(10)
272
sage: Ei(I)
273
Ei(I)
274
sage: Ei(3+I)
275
Ei(I + 3)
276
sage: Ei(1.3)
277
2.72139888023202
278
279
The branch cut for this function is along the negative real axis::
280
281
sage: Ei(-3 + 0.1*I)
282
-0.0129379427181693 + 3.13993830250942*I
283
sage: Ei(-3 - 0.1*I)
284
-0.0129379427181693 - 3.13993830250942*I
285
286
ALGORITHM: Uses mpmath.
287
"""
288
BuiltinFunction.__init__(self, "Ei")
289
290
def _eval_(self, x ):
291
"""
292
EXAMPLES::
293
294
sage: Ei(10)
295
Ei(10)
296
sage: Ei(I)
297
Ei(I)
298
sage: Ei(1.3)
299
2.72139888023202
300
sage: Ei(10r)
301
Ei(10)
302
sage: Ei(1.3r)
303
2.72139888023202
304
"""
305
if not isinstance(x, Expression) and is_inexact(x):
306
return self._evalf_(x, parent(x))
307
return None
308
309
def _evalf_(self, x, parent=None):
310
"""
311
EXAMPLES::
312
313
sage: Ei(10).n()
314
2492.22897624188
315
sage: Ei(20).n()
316
2.56156526640566e7
317
sage: Ei(I).n()
318
0.337403922900968 + 2.51687939716208*I
319
sage: Ei(3+I).n()
320
7.82313467600158 + 6.09751978399231*I
321
"""
322
import mpmath
323
if isinstance(parent, Parent) and hasattr(parent, 'prec'):
324
prec = parent.prec()
325
else:
326
prec = 53
327
return mpmath_utils.call(mpmath.ei, x, prec=prec)
328
329
def __call__(self, x, prec=None, coerce=True, hold=False ):
330
"""
331
Note that the ``prec`` argument is deprecated. The precision for
332
the result is deduced from the precision of the input. Convert
333
the input to a higher precision explicitly if a result with higher
334
precision is desired.
335
336
EXAMPLES::
337
338
sage: t = Ei(RealField(100)(2.5)); t
339
7.0737658945786007119235519625
340
sage: t.prec()
341
100
342
343
sage: Ei(1.1, prec=300)
344
doctest:...: DeprecationWarning: The prec keyword argument is deprecated. Explicitly set the precision of the input, for example Ei(RealField(300)(1)), or use the prec argument to .n() for exact inputs, e.g., Ei(1).n(300), instead.
345
2.16737827956340306615064476647912607220394065907142504328679588538509331805598360907980986
346
"""
347
if prec is not None:
348
from sage.misc.misc import deprecation
349
deprecation("The prec keyword argument is deprecated. Explicitly set the precision of the input, for example Ei(RealField(300)(1)), or use the prec argument to .n() for exact inputs, e.g., Ei(1).n(300), instead.")
350
351
import mpmath
352
return mpmath_utils.call(mpmath.ei, x, prec=prec)
353
354
return BuiltinFunction.__call__(self, x, coerce=coerce, hold=hold)
355
356
def _derivative_(self, x, diff_param=None):
357
"""
358
EXAMPLES::
359
360
sage: Ei(x).diff(x)
361
e^x/x
362
sage: Ei(x).diff(x).subs(x=1)
363
e
364
sage: Ei(x^2).diff(x)
365
2*e^(x^2)/x
366
sage: f = function('f')
367
sage: Ei(f(x)).diff(x)
368
e^f(x)*D[0](f)(x)/f(x)
369
"""
370
return exp(x)/x
371
372
Ei = Function_exp_integral()
373
374
375
def Li(x, eps_rel=None, err_bound=False):
376
r"""
377
Return value of the function Li(x) as a real double field element.
378
379
This is the function
380
381
.. math::
382
383
\int_2^{x} dt / \log(t).
384
385
386
387
The function Li(x) is an approximation for the number of primes up
388
to `x`. In fact, the famous Riemann Hypothesis is
389
equivalent to the statement that for `x \geq 2.01` we have
390
391
.. math::
392
393
|\pi(x) - Li(x)| \leq \sqrt{x} \log(x).
394
395
396
For "small" `x`, `Li(x)` is always slightly bigger
397
than `\pi(x)`. However it is a theorem that there are (very
398
large, e.g., around `10^{316}`) values of `x` so
399
that `\pi(x) > Li(x)`. See
400
"A new bound for the smallest x with `\pi(x) > li(x)`",
401
Bays and Hudson, Mathematics of Computation, 69 (2000) 1285-1296.
402
403
ALGORITHM: Computed numerically using GSL.
404
405
INPUT:
406
407
408
- ``x`` - a real number = 2.
409
410
411
OUTPUT:
412
413
414
- ``x`` - a real double
415
416
417
EXAMPLES::
418
419
sage: Li(2)
420
0.0
421
sage: Li(5)
422
2.58942452992
423
sage: Li(1000)
424
176.56449421
425
sage: Li(10^5)
426
9628.76383727
427
sage: prime_pi(10^5)
428
9592
429
sage: Li(1)
430
Traceback (most recent call last):
431
...
432
ValueError: Li only defined for x at least 2.
433
434
::
435
436
sage: for n in range(1,7):
437
... print '%-10s%-10s%-20s'%(10^n, prime_pi(10^n), Li(10^n))
438
10 4 5.12043572467
439
100 25 29.080977804
440
1000 168 176.56449421
441
10000 1229 1245.09205212
442
100000 9592 9628.76383727
443
1000000 78498 78626.5039957
444
"""
445
x = float(x)
446
if x < 2:
447
raise ValueError, "Li only defined for x at least 2."
448
if eps_rel:
449
ans = numerical_integral(_one_over_log, 2, float(x),
450
eps_rel=eps_rel)
451
else:
452
ans = numerical_integral(_one_over_log, 2, float(x))
453
if err_bound:
454
return real_double.RDF(ans[0]), ans[1]
455
else:
456
return real_double.RDF(ans[0])
457
# Old PARI version -- much much slower
458
#x = RDF(x)
459
#return RDF(gp('intnum(t=2,%s,1/log(t))'%x))
460
461
import math
462
def _one_over_log(t):
463
"""
464
Internal function for quick computation of log integrals.
465
466
TESTS::
467
468
sage: from sage.functions.transcendental import _one_over_log
469
sage: _one_over_log(e)
470
1.0
471
sage: _one_over_log(2)
472
1.4426950408889634
473
sage: Li(100)
474
29.080977804
475
"""
476
return 1/math.log(t)
477
478
from sage.rings.polynomial.polynomial_real_mpfr_dense import PolynomialRealDense
479
480
class DickmanRho(BuiltinFunction):
481
r"""
482
Dickman's function is the continuous function satisfying the
483
differential equation
484
485
.. math::
486
487
x \rho'(x) + \rho(x-1) = 0
488
489
with initial conditions `\rho(x)=1` for
490
`0 \le x \le 1`. It is useful in estimating the frequency
491
of smooth numbers as asymptotically
492
493
.. math::
494
495
\Psi(a, a^{1/s}) \sim a \rho(s)
496
497
where `\Psi(a,b)` is the number of `b`-smooth
498
numbers less than `a`.
499
500
ALGORITHM:
501
502
Dickmans's function is analytic on the interval
503
`[n,n+1]` for each integer `n`. To evaluate at
504
`n+t, 0 \le t < 1`, a power series is recursively computed
505
about `n+1/2` using the differential equation stated above.
506
As high precision arithmetic may be needed for intermediate results
507
the computed series are cached for later use.
508
509
Simple explicit formulas are used for the intervals [0,1] and
510
[1,2].
511
512
EXAMPLES::
513
514
sage: dickman_rho(2)
515
0.306852819440055
516
sage: dickman_rho(10)
517
2.77017183772596e-11
518
sage: dickman_rho(10.00000000000000000000000000000000000000)
519
2.77017183772595898875812120063434232634e-11
520
sage: plot(log(dickman_rho(x)), (x, 0, 15))
521
522
AUTHORS:
523
524
- Robert Bradshaw (2008-09)
525
526
REFERENCES:
527
528
- G. Marsaglia, A. Zaman, J. Marsaglia. "Numerical
529
Solutions to some Classical Differential-Difference Equations."
530
Mathematics of Computation, Vol. 53, No. 187 (1989).
531
"""
532
def __init__(self):
533
"""
534
Constructs an object to represent Dickman's rho function.
535
536
TESTS::
537
538
sage: dickman_rho(x)
539
dickman_rho(x)
540
sage: dickman_rho(3)
541
0.0486083882911316
542
sage: dickman_rho(pi)
543
0.0359690758968463
544
"""
545
self._cur_prec = 0
546
BuiltinFunction.__init__(self, "dickman_rho", 1)
547
548
def _eval_(self, x):
549
"""
550
EXAMPLES::
551
552
sage: [dickman_rho(n) for n in [1..10]]
553
[1.00000000000000, 0.306852819440055, 0.0486083882911316, 0.00491092564776083, 0.000354724700456040, 0.0000196496963539553, 8.74566995329392e-7, 3.23206930422610e-8, 1.01624828273784e-9, 2.77017183772596e-11]
554
sage: dickman_rho(0)
555
1.00000000000000
556
"""
557
if not is_RealNumber(x):
558
try:
559
x = RR(x)
560
except (TypeError, ValueError):
561
return None #PrimitiveFunction.__call__(self, SR(x))
562
if x < 0:
563
return x.parent()(0)
564
elif x <= 1:
565
return x.parent()(1)
566
elif x <= 2:
567
return 1 - x.log()
568
n = x.floor()
569
if self._cur_prec < x.parent().prec() or not self._f.has_key(n):
570
self._cur_prec = rel_prec = x.parent().prec()
571
# Go a bit beyond so we're not constantly re-computing.
572
max = x.parent()(1.1)*x + 10
573
abs_prec = (-self.approximate(max).log2() + rel_prec + 2*max.log2()).ceil()
574
self._f = {}
575
if sys.getrecursionlimit() < max + 10:
576
sys.setrecursionlimit(int(max) + 10)
577
self._compute_power_series(max.floor(), abs_prec, cache_ring=x.parent())
578
return self._f[n](2*(x-n-x.parent()(0.5)))
579
580
def power_series(self, n, abs_prec):
581
"""
582
This function returns the power series about `n+1/2` used
583
to evaluate Dickman's function. It is scaled such that the interval
584
`[n,n+1]` corresponds to x in `[-1,1]`.
585
586
INPUT:
587
588
- ``n`` - the lower endpoint of the interval for which
589
this power series holds
590
591
- ``abs_prec`` - the absolute precision of the
592
resulting power series
593
594
EXAMPLES::
595
596
sage: f = dickman_rho.power_series(2, 20); f
597
-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
598
sage: f(-1), f(0), f(1)
599
(0.30685, 0.13032, 0.048608)
600
sage: dickman_rho(2), dickman_rho(2.5), dickman_rho(3)
601
(0.306852819440055, 0.130319561832251, 0.0486083882911316)
602
"""
603
return self._compute_power_series(n, abs_prec, cache_ring=None)
604
605
def _compute_power_series(self, n, abs_prec, cache_ring=None):
606
"""
607
Compute the power series giving Dickman's function on [n, n+1], by
608
recursion in n. For internal use; self.power_series() is a wrapper
609
around this intended for the user.
610
611
INPUT:
612
613
- ``n`` - the lower endpoint of the interval for which
614
this power series holds
615
616
- ``abs_prec`` - the absolute precision of the
617
resulting power series
618
619
- ``cache_ring`` - for internal use, caches the power
620
series at this precision.
621
622
EXAMPLES::
623
624
sage: f = dickman_rho.power_series(2, 20); f
625
-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
626
"""
627
if n <= 1:
628
if n <= -1:
629
return PolynomialRealDense(RealField(abs_prec)['x'])
630
if n == 0:
631
return PolynomialRealDense(RealField(abs_prec)['x'], [1])
632
elif n == 1:
633
nterms = (RDF(abs_prec) * RDF(2).log()/RDF(3).log()).ceil()
634
R = RealField(abs_prec)
635
neg_three = ZZ(-3)
636
coeffs = [1 - R(1.5).log()] + [neg_three**-k/k for k in range(1, nterms)]
637
f = PolynomialRealDense(R['x'], coeffs)
638
if cache_ring is not None:
639
self._f[n] = f.truncate_abs(f[0] >> (cache_ring.prec()+1)).change_ring(cache_ring)
640
return f
641
else:
642
f = self._compute_power_series(n-1, abs_prec, cache_ring)
643
# integrand = f / (2n+1 + x)
644
# We calculate this way because the most significant term is the constant term,
645
# and so we want to push the error accumulation and remainder out to the least
646
# significant terms.
647
integrand = f.reverse().quo_rem(PolynomialRealDense(f.parent(), [1, 2*n+1]))[0].reverse()
648
integrand = integrand.truncate_abs(RR(2)**-abs_prec)
649
iintegrand = integrand.integral()
650
ff = PolynomialRealDense(f.parent(), [f(1) + iintegrand(-1)]) - iintegrand
651
i = 0
652
while abs(f[i]) < abs(f[i+1]):
653
i += 1
654
rel_prec = int(abs_prec + abs(RR(f[i])).log2())
655
if cache_ring is not None:
656
self._f[n] = ff.truncate_abs(ff[0] >> (cache_ring.prec()+1)).change_ring(cache_ring)
657
return ff.change_ring(RealField(rel_prec))
658
659
def approximate(self, x, parent=None):
660
r"""
661
Approximate using de Bruijn's formula
662
663
.. math::
664
665
\rho(x) \sim \frac{exp(-x \xi + Ei(\xi))}{\sqrt{2\pi x}\xi}
666
667
which is asymptotically equal to Dickman's function, and is much
668
faster to compute.
669
670
REFERENCES:
671
672
- N. De Bruijn, "The Asymptotic behavior of a function
673
occurring in the theory of primes." J. Indian Math Soc. v 15.
674
(1951)
675
676
EXAMPLES::
677
678
sage: dickman_rho.approximate(10)
679
2.41739196365564e-11
680
sage: dickman_rho(10)
681
2.77017183772596e-11
682
sage: dickman_rho.approximate(1000)
683
4.32938809066403e-3464
684
"""
685
log, exp, sqrt, pi = math.log, math.exp, math.sqrt, math.pi
686
x = float(x)
687
xi = log(x)
688
y = (exp(xi)-1.0)/xi - x
689
while abs(y) > 1e-12:
690
dydxi = (exp(xi)*(xi-1.0) + 1.0)/(xi*xi)
691
xi -= y/dydxi
692
y = (exp(xi)-1.0)/xi - x
693
return (-x*xi + RR(xi).eint()).exp() / (sqrt(2*pi*x)*xi)
694
695
dickman_rho = DickmanRho()
696
697