Exponential integrals - Functions

Skip to content
Back to top
View this page
Edit this page

# Exponential integrals

AUTHORS:

- Benjamin Jones (2011-06-12)

This module provides easy access to many exponential integral special functions. It utilizes Maxima’s special functions package and the mpmath library.

REFERENCES:

- [AS1964] Abramowitz and Stegun: Handbook of Mathematical Functions

- Wikipedia article Exponential_integral

- Online Encyclopedia of Special Function: http://algo.inria.fr/esf/index.html

- NIST Digital Library of Mathematical Functions: https://dlmf.nist.gov/

- Maxima special functions package

- mpmath library

AUTHORS:

- Benjamin Jones

  > Implementations of the classes `Function_exp_integral_*`.

- David Joyner and William Stein

  > Authors of the code which was moved from special.py and trans.py. Implementation of `exp_int()` (from sage/functions/special.py). Implementation of `exponential_integral_1()` (from sage/functions/transcendental.py).

class sage.functions.exp_integral.Function_cos_integral

  Bases: `BuiltinFunction`

  The trigonometric integral \(\operatorname{Ci}(z)\) defined by

  \[\operatorname{Ci}(z) = \gamma + \log(z) + \int_0^z \frac{\cos(t)-1}{t} \; dt,\]

  where \(\gamma\) is the Euler gamma constant (`euler_gamma` in Sage), see [AS1964] 5.2.1.

  EXAMPLES:

  Sage

      sage: z = var('z')                                                              # needs sage.symbolic
      sage: cos_integral(z)                                                           # needs sage.symbolic
      cos_integral(z)
      sage: cos_integral(3.0)                                                         # needs mpmath
      0.119629786008000
      sage: cos_integral(0)                                                           # needs sage.symbolic
      cos_integral(0)
      sage: N(cos_integral(0))                                                        # needs mpmath
      -infinity

  Python

      >>> from sage.all import *
      >>> z = var('z')                                                              # needs sage.symbolic
      >>> cos_integral(z)                                                           # needs sage.symbolic
      cos_integral(z)
      >>> cos_integral(RealNumber('3.0'))                                                         # needs mpmath
      0.119629786008000
      >>> cos_integral(Integer(0))                                                           # needs sage.symbolic
      cos_integral(0)
      >>> N(cos_integral(Integer(0)))                                                        # needs mpmath
      -infinity

  Numerical evaluation for real and complex arguments is handled using mpmath:

  Sage

      sage: cos_integral(3.0)                                                         # needs mpmath
      0.119629786008000

  [Python]

      >>> from sage.all import *
      >>> cos_integral(RealNumber('3.0'))                                                         # needs mpmath
      0.119629786008000

  The alias `Ci` can be used instead of `cos_integral`:

  Sage

      sage: Ci(3.0)                                                                   # needs mpmath
      0.119629786008000

  Python

      >>> from sage.all import *
      >>> Ci(RealNumber('3.0'))                                                                   # needs mpmath
      0.119629786008000

  Compare `cos_integral(3.0)` to the definition of the value using numerical integration:

  Sage

      sage: a = numerical_integral((cos(x)-1)/x, 0, 3)[0]                             # needs sage.symbolic
      sage: abs(N(euler_gamma + log(3)) + a - N(cos_integral(3.0))) < 1e-14           # needs sage.symbolic
      True

  [Python]

      >>> from sage.all import *
      >>> a = numerical_integral((cos(x)-Integer(1))/x, Integer(0), Integer(3))[Integer(0)]                             # needs sage.symbolic
      >>> abs(N(euler_gamma + log(Integer(3))) + a - N(cos_integral(RealNumber('3.0')))) < RealNumber('1e-14')           # needs sage.symbolic
      True

  Arbitrary precision and complex arguments are handled:

  Sage

      sage: N(cos_integral(3), digits=30)                                             # needs sage.symbolic
      0.119629786008000327626472281177
      sage: cos_integral(ComplexField(100)(3+I))                                      # needs sage.symbolic
      0.078134230477495714401983633057 - 0.37814733904787920181190368789*I

  Python

      >>> from sage.all import *
      >>> N(cos_integral(Integer(3)), digits=Integer(30))                                             # needs sage.symbolic
      0.119629786008000327626472281177
      >>> cos_integral(ComplexField(Integer(100))(Integer(3)+I))                                      # needs sage.symbolic
      0.078134230477495714401983633057 - 0.37814733904787920181190368789*I

  The limit \(\operatorname{Ci}(z)\) as \(z \to \infty\) is zero:

  Sage

      sage: N(cos_integral(1e23))                                                     # needs mpmath
      -3.24053937643003e-24

  [Python]

      >>> from sage.all import *
      >>> N(cos_integral(RealNumber('1e23')))                                                     # needs mpmath
      -3.24053937643003e-24

  Symbolic derivatives and integrals are handled by Sage and Maxima:

  Sage

      sage: # needs sage.symbolic
      sage: x = var('x')
      sage: f = cos_integral(x)
      sage: f.diff(x)
      cos(x)/x
      sage: f.integrate(x)
      x*cos_integral(x) - sin(x)

  Python

      >>> from sage.all import *
      >>> # needs sage.symbolic
      >>> x = var('x')
      >>> f = cos_integral(x)
      >>> f.diff(x)
      cos(x)/x
      >>> f.integrate(x)
      x*cos_integral(x) - sin(x)

  The Nielsen spiral is the parametric plot of (Si(t), Ci(t)):

  Sage

      sage: # needs sage.symbolic
      sage: t = var('t')
      sage: f(t) = sin_integral(t)
      sage: g(t) = cos_integral(t)
      sage: P = parametric_plot([f, g], (t, 0.5 ,20))                                 # needs sage.plot
      sage: show(P, frame=True, axes=False)                                           # needs sage.plot

  [Python]

      >>> from sage.all import *
      >>> # needs sage.symbolic
      >>> t = var('t')
      >>> __tmp__=var("t"); f = symbolic_expression(sin_integral(t)).function(t)
      >>> __tmp__=var("t"); g = symbolic_expression(cos_integral(t)).function(t)
      >>> P = parametric_plot([f, g], (t, RealNumber('0.5') ,Integer(20)))                                 # needs sage.plot
      >>> show(P, frame=True, axes=False)                                           # needs sage.plot

  ALGORITHM:

  Numerical evaluation is handled using mpmath, but symbolics are handled by Sage and Maxima.

  REFERENCES:

  - Wikipedia article Trigonometric_integral

  - mpmath documentation: ci

class sage.functions.exp_integral.Function_cosh_integral

  Bases: `BuiltinFunction`

  The trigonometric integral \(\operatorname{Chi}(z)\) defined by

  \[\operatorname{Chi}(z) = \gamma + \log(z) + \int_0^z \frac{\cosh(t)-1}{t} \; dt,\]

  see [AS1964] 5.2.4.

  EXAMPLES:

  Sage

      sage: z = var('z')                                                              # needs sage.symbolic
      sage: cosh_integral(z)                                                          # needs sage.symbolic
      cosh_integral(z)
      sage: cosh_integral(3.0)                                                        # needs mpmath
      4.96039209476561

  Python

      >>> from sage.all import *
      >>> z = var('z')                                                              # needs sage.symbolic
      >>> cosh_integral(z)                                                          # needs sage.symbolic
      cosh_integral(z)
      >>> cosh_integral(RealNumber('3.0'))                                                        # needs mpmath
      4.96039209476561

  Numerical evaluation for real and complex arguments is handled using mpmath:

  Sage

      sage: cosh_integral(1.0)                                                        # needs mpmath
      0.837866940980208

  [Python]

      >>> from sage.all import *
      >>> cosh_integral(RealNumber('1.0'))                                                        # needs mpmath
      0.837866940980208

  The alias `Chi` can be used instead of `cosh_integral`:

  Sage

      sage: Chi(1.0)                                                                  # needs mpmath
      0.837866940980208

  Python

      >>> from sage.all import *
      >>> Chi(RealNumber('1.0'))                                                                  # needs mpmath
      0.837866940980208

  Here is an example from the mpmath documentation:

  Sage

      sage: f(x) = cosh_integral(x)                                                   # needs sage.symbolic
      sage: find_root(f, 0.1, 1.0)                                                    # needs scipy sage.symbolic
      0.523822571389...

  [Python]

      >>> from sage.all import *
      >>> __tmp__=var("x"); f = symbolic_expression(cosh_integral(x)                                                   ).function(x)# needs sage.symbolic
      >>> find_root(f, RealNumber('0.1'), RealNumber('1.0'))                                                    # needs scipy sage.symbolic
      0.523822571389...

  Compare `cosh_integral(3.0)` to the definition of the value using numerical integration:

  Sage

      sage: a = numerical_integral((cosh(x)-1)/x, 0, 3)[0]                            # needs sage.symbolic
      sage: abs(N(euler_gamma + log(3)) + a - N(cosh_integral(3.0))) < 1e-14          # needs sage.symbolic
      True

  Python

      >>> from sage.all import *
      >>> a = numerical_integral((cosh(x)-Integer(1))/x, Integer(0), Integer(3))[Integer(0)]                            # needs sage.symbolic
      >>> abs(N(euler_gamma + log(Integer(3))) + a - N(cosh_integral(RealNumber('3.0')))) < RealNumber('1e-14')          # needs sage.symbolic
      True

  Arbitrary precision and complex arguments are handled:

  Sage

      sage: N(cosh_integral(3), digits=30)                                            # needs sage.symbolic
      4.96039209476560976029791763669
      sage: cosh_integral(ComplexField(100)(3+I))                                     # needs sage.symbolic
      3.9096723099686417127843516794 + 3.0547519627014217273323873274*I

  [Python]

      >>> from sage.all import *
      >>> N(cosh_integral(Integer(3)), digits=Integer(30))                                            # needs sage.symbolic
      4.96039209476560976029791763669
      >>> cosh_integral(ComplexField(Integer(100))(Integer(3)+I))                                     # needs sage.symbolic
      3.9096723099686417127843516794 + 3.0547519627014217273323873274*I

  The limit of \(\operatorname{Chi}(z)\) as \(z \to \infty\) is \(\infty\):

  Sage

      sage: N(cosh_integral(Infinity))                                                # needs mpmath
      +infinity

  Python

      >>> from sage.all import *
      >>> N(cosh_integral(Infinity))                                                # needs mpmath
      +infinity

  Symbolic derivatives and integrals are handled by Sage and Maxima:

  Sage

      sage: # needs sage.symbolic
      sage: x = var('x')
      sage: f = cosh_integral(x)
      sage: f.diff(x)
      cosh(x)/x
      sage: f.integrate(x)
      x*cosh_integral(x) - sinh(x)

  [Python]

      >>> from sage.all import *
      >>> # needs sage.symbolic
      >>> x = var('x')
      >>> f = cosh_integral(x)
      >>> f.diff(x)
      cosh(x)/x
      >>> f.integrate(x)
      x*cosh_integral(x) - sinh(x)

  ALGORITHM:

  Numerical evaluation is handled using mpmath, but symbolics are handled by Sage and Maxima.

  REFERENCES:

  - Wikipedia article Trigonometric_integral

  - mpmath documentation: chi

class sage.functions.exp_integral.Function_exp_integral

  Bases: `BuiltinFunction`

  The generalized complex exponential integral Ei(z) defined by

  \[\operatorname{Ei}(x) = \int_{-\infty}^x \frac{e^t}{t} \; dt\]

  for x > 0 and for complex arguments by analytic continuation, see [AS1964] 5.1.2.

  EXAMPLES:

  Sage

      sage: # needs sage.symbolic
      sage: Ei(10)
      Ei(10)
      sage: Ei(I)
      Ei(I)
      sage: Ei(3+I)
      Ei(I + 3)
      sage: Ei(10r)
      Ei(10)

      sage: Ei(1.3)                                                                   # needs mpmath
      2.72139888023202
      sage: Ei(1.3r)                                                                  # needs mpmath
      2.7213988802320235

  Python

      >>> from sage.all import *
      >>> # needs sage.symbolic
      >>> Ei(Integer(10))
      Ei(10)
      >>> Ei(I)
      Ei(I)
      >>> Ei(Integer(3)+I)
      Ei(I + 3)
      >>> Ei(10)
      Ei(10)

      >>> Ei(RealNumber('1.3'))                                                                   # needs mpmath
      2.72139888023202
      >>> Ei(1.3)                                                                  # needs mpmath
      2.7213988802320235

  The branch cut for this function is along the negative real axis:

  Sage

      sage: Ei(-3 + 0.1*I)                                                            # needs sage.symbolic
      -0.0129379427181693 + 3.13993830250942*I
      sage: Ei(-3 - 0.1*I)                                                            # needs sage.symbolic
      -0.0129379427181693 - 3.13993830250942*I

  [Python]

      >>> from sage.all import *
      >>> Ei(-Integer(3) + RealNumber('0.1')*I)                                                            # needs sage.symbolic
      -0.0129379427181693 + 3.13993830250942*I
      >>> Ei(-Integer(3) - RealNumber('0.1')*I)                                                            # needs sage.symbolic
      -0.0129379427181693 - 3.13993830250942*I

  The precision for the result is deduced from the precision of the input. Convert the input to a higher precision explicitly if a result with higher precision is desired:

  Sage

      sage: Ei(RealField(300)(1.1))                                                   # needs sage.rings.real_mpfr
      2.16737827956340282358378734233807621497112737591639704719499002090327541763352339357795426

  Python

      >>> from sage.all import *
      >>> Ei(RealField(Integer(300))(RealNumber('1.1')))                                                   # needs sage.rings.real_mpfr
      2.16737827956340282358378734233807621497112737591639704719499002090327541763352339357795426

  ALGORITHM: Uses mpmath.

class sage.functions.exp_integral.Function_exp_integral_e

  Bases: `BuiltinFunction`

  The generalized complex exponential integral \(E_n(z)\) defined by

  \[E_n(z) = \int_1^{\infty} \frac{e^{-z t}}{t^n} \; dt\]

  for complex numbers \(n\) and \(z\), see [AS1964] 5.1.4.

  The special case where \(n = 1\) is denoted in Sage by `exp_integral_e1`.

  EXAMPLES:

  Numerical evaluation is handled using mpmath:

  Sage

      sage: N(exp_integral_e(1, 1))                                                   # needs sage.symbolic
      0.219383934395520
      sage: exp_integral_e(1, RealField(100)(1))                                      # needs sage.symbolic
      0.21938393439552027367716377546

  Python

      >>> from sage.all import *
      >>> N(exp_integral_e(Integer(1), Integer(1)))                                                   # needs sage.symbolic
      0.219383934395520
      >>> exp_integral_e(Integer(1), RealField(Integer(100))(Integer(1)))                                      # needs sage.symbolic
      0.21938393439552027367716377546

  We can compare this to PARI’s evaluation of `exponential_integral_1()`:

  Sage

      sage: N(exponential_integral_1(1))                                              # needs sage.symbolic
      0.219383934395520

  [Python]

      >>> from sage.all import *
      >>> N(exponential_integral_1(Integer(1)))                                              # needs sage.symbolic
      0.219383934395520

  We can verify one case of [AS1964] 5.1.45, i.e. \(E_n(z) = z^{n-1}\Gamma(1-n,z)\):

  Sage

      sage: N(exp_integral_e(2, 3+I))                                                 # needs sage.symbolic
      0.00354575823814662 - 0.00973200528288687*I
      sage: N((3+I)*gamma(-1, 3+I))                                                   # needs sage.symbolic
      0.00354575823814662 - 0.00973200528288687*I

  Python

      >>> from sage.all import *
      >>> N(exp_integral_e(Integer(2), Integer(3)+I))                                                 # needs sage.symbolic
      0.00354575823814662 - 0.00973200528288687*I
      >>> N((Integer(3)+I)*gamma(-Integer(1), Integer(3)+I))                                                   # needs sage.symbolic
      0.00354575823814662 - 0.00973200528288687*I

  Maxima returns the following improper integral as a multiple of `exp_integral_e(1,1)`:

  Sage

      sage: uu = integral(e^(-x)*log(x+1), x, 0, oo); uu                              # needs sage.symbolic
      e*exp_integral_e(1, 1)
      sage: uu.n(digits=30)                                                           # needs sage.symbolic
      0.596347362323194074341078499369

  [Python]

      >>> from sage.all import *
      >>> uu = integral(e**(-x)*log(x+Integer(1)), x, Integer(0), oo); uu                              # needs sage.symbolic
      e*exp_integral_e(1, 1)
      >>> uu.n(digits=Integer(30))                                                           # needs sage.symbolic
      0.596347362323194074341078499369

  Symbolic derivatives and integrals are handled by Sage and Maxima:

  Sage

      sage: # needs sage.symbolic
      sage: x = var('x')
      sage: f = exp_integral_e(2,x)
      sage: f.diff(x)
      -exp_integral_e(1, x)
      sage: f.integrate(x)
      -exp_integral_e(3, x)
      sage: f = exp_integral_e(-1, x)
      sage: f.integrate(x)
      Ei(-x) - gamma(-1, x)

  Python

      >>> from sage.all import *
      >>> # needs sage.symbolic
      >>> x = var('x')
      >>> f = exp_integral_e(Integer(2),x)
      >>> f.diff(x)
      -exp_integral_e(1, x)
      >>> f.integrate(x)
      -exp_integral_e(3, x)
      >>> f = exp_integral_e(-Integer(1), x)
      >>> f.integrate(x)
      Ei(-x) - gamma(-1, x)

  Some special values of `exp_integral_e` can be simplified. [AS1964] 5.1.23:

  Sage

      sage: exp_integral_e(0, x)                                                      # needs sage.symbolic
      e^(-x)/x

  [Python]

      >>> from sage.all import *
      >>> exp_integral_e(Integer(0), x)                                                      # needs sage.symbolic
      e^(-x)/x

  [AS1964] 5.1.24:

  Sage

      sage: # needs sage.symbolic
      sage: exp_integral_e(6, 0)
      1/5
      sage: nn = var('nn')
      sage: assume(nn > 1)
      sage: f = exp_integral_e(nn, 0)
      sage: f.simplify()
      1/(nn - 1)

  Python

      >>> from sage.all import *
      >>> # needs sage.symbolic
      >>> exp_integral_e(Integer(6), Integer(0))
      1/5
      >>> nn = var('nn')
      >>> assume(nn > Integer(1))
      >>> f = exp_integral_e(nn, Integer(0))
      >>> f.simplify()
      1/(nn - 1)

  ALGORITHM:

  Numerical evaluation is handled using mpmath, but symbolics are handled by Sage and Maxima.

class sage.functions.exp_integral.Function_exp_integral_e1

  Bases: `BuiltinFunction`

  The generalized complex exponential integral \(E_1(z)\) defined by

  \[E_1(z) = \int_z^\infty \frac{e^{-t}}{t} \; dt\]

  see [AS1964] 5.1.4.

  EXAMPLES:

  Sage

      sage: exp_integral_e1(x)                                                        # needs sage.symbolic
      exp_integral_e1(x)
      sage: exp_integral_e1(1.0)                                                      # needs mpmath
      0.219383934395520

  Python

      >>> from sage.all import *
      >>> exp_integral_e1(x)                                                        # needs sage.symbolic
      exp_integral_e1(x)
      >>> exp_integral_e1(RealNumber('1.0'))                                                      # needs mpmath
      0.219383934395520

  Numerical evaluation is handled using mpmath:

  Sage

      sage: N(exp_integral_e1(1))                                                     # needs sage.symbolic
      0.219383934395520
      sage: exp_integral_e1(RealField(100)(1))                                        # needs sage.rings.real_mpfr
      0.21938393439552027367716377546

  [Python]

      >>> from sage.all import *
      >>> N(exp_integral_e1(Integer(1)))                                                     # needs sage.symbolic
      0.219383934395520
      >>> exp_integral_e1(RealField(Integer(100))(Integer(1)))                                        # needs sage.rings.real_mpfr
      0.21938393439552027367716377546

  We can compare this to PARI’s evaluation of `exponential_integral_1()`:

  Sage

      sage: N(exp_integral_e1(2.0))                                                   # needs mpmath
      0.0489005107080611
      sage: N(exponential_integral_1(2.0))                                            # needs sage.rings.real_mpfr
      0.0489005107080611

  Python

      >>> from sage.all import *
      >>> N(exp_integral_e1(RealNumber('2.0')))                                                   # needs mpmath
      0.0489005107080611
      >>> N(exponential_integral_1(RealNumber('2.0')))                                            # needs sage.rings.real_mpfr
      0.0489005107080611

  Symbolic derivatives and integrals are handled by Sage and Maxima:

  Sage

      sage: # needs sage.symbolic
      sage: x = var('x')
      sage: f = exp_integral_e1(x)
      sage: f.diff(x)
      -e^(-x)/x
      sage: f.integrate(x)
      -exp_integral_e(2, x)

  [Python]

      >>> from sage.all import *
      >>> # needs sage.symbolic
      >>> x = var('x')
      >>> f = exp_integral_e1(x)
      >>> f.diff(x)
      -e^(-x)/x
      >>> f.integrate(x)
      -exp_integral_e(2, x)

  ALGORITHM:

  Numerical evaluation is handled using mpmath, but symbolics are handled by Sage and Maxima.

class sage.functions.exp_integral.Function_log_integral

  Bases: `BuiltinFunction`

  The logarithmic integral \(\operatorname{li}(z)\) defined by

  \[\operatorname{li}(x) = \int_0^z \frac{dt}{\ln(t)} = \operatorname{Ei}(\ln(x))\]

  for x > 1 and by analytic continuation for complex arguments z (see [AS1964] 5.1.3).

  EXAMPLES:

  Numerical evaluation for real and complex arguments is handled using mpmath:

  Sage

      sage: N(log_integral(3))                                                        # needs sage.symbolic
      2.16358859466719
      sage: N(log_integral(3), digits=30)                                             # needs sage.symbolic
      2.16358859466719197287692236735
      sage: log_integral(ComplexField(100)(3+I))                                      # needs sage.symbolic
      2.2879892769816826157078450911 + 0.87232935488528370139883806779*I
      sage: log_integral(0)                                                           # needs mpmath
      0

  Python

      >>> from sage.all import *
      >>> N(log_integral(Integer(3)))                                                        # needs sage.symbolic
      2.16358859466719
      >>> N(log_integral(Integer(3)), digits=Integer(30))                                             # needs sage.symbolic
      2.16358859466719197287692236735
      >>> log_integral(ComplexField(Integer(100))(Integer(3)+I))                                      # needs sage.symbolic
      2.2879892769816826157078450911 + 0.87232935488528370139883806779*I
      >>> log_integral(Integer(0))                                                           # needs mpmath
      0

  Symbolic derivatives and integrals are handled by Sage and Maxima:

  Sage

      sage: # needs sage.symbolic
      sage: x = var('x')
      sage: f = log_integral(x)
      sage: f.diff(x)
      1/log(x)
      sage: f.integrate(x)
      x*log_integral(x) - Ei(2*log(x))

  [Python]

      >>> from sage.all import *
      >>> # needs sage.symbolic
      >>> x = var('x')
      >>> f = log_integral(x)
      >>> f.diff(x)
      1/log(x)
      >>> f.integrate(x)
      x*log_integral(x) - Ei(2*log(x))

  Here is a test from the mpmath documentation. There are 1,925,320,391,606,803,968,923 many prime numbers less than 1e23. The value of `log_integral(1e23)` is very close to this:

  Sage

      sage: log_integral(1e23)                                                        # needs mpmath
      1.92532039161405e21

  Python

      >>> from sage.all import *
      >>> log_integral(RealNumber('1e23'))                                                        # needs mpmath
      1.92532039161405e21

  ALGORITHM:

  Numerical evaluation is handled using mpmath, but symbolics are handled by Sage and Maxima.

  REFERENCES:

  - Wikipedia article Logarithmic_integral_function

  - mpmath documentation: logarithmic-integral

class sage.functions.exp_integral.Function_log_integral_offset

  Bases: `BuiltinFunction`

  The offset logarithmic integral, or Eulerian logarithmic integral, \(\operatorname{Li}(x)\) is defined by

  \[\operatorname{Li}(x) = \int_2^x \frac{dt}{\ln(t)} = \operatorname{li}(x)-\operatorname{li}(2)\]

  for \(x \ge 2\).

  The offset logarithmic integral should also not be confused with the polylogarithm (also denoted by \(\operatorname{Li}(x)\) ), which is implemented as `sage.functions.log.Function_polylog`.

  \(\operatorname{Li}(x)\) is identical to \(\operatorname{li}(x)\) except that the lower limit of integration is \(2\) rather than \(0\) to avoid the singularity at \(x = 1\) of

  \[\frac{1}{\ln(t)}\]

  See `Function_log_integral` for details of \(\operatorname{li}(x)\). Thus \(\operatorname{Li}(x)\) can also be represented by

  \[\operatorname{Li}(x) = \operatorname{li}(x)-\operatorname{li}(2)\]

  So we have:

  Sage

      sage: li(4.5) - li(2.0) - Li(4.5)                                               # needs mpmath
      0.000000000000000

  Python

      >>> from sage.all import *
      >>> li(RealNumber('4.5')) - li(RealNumber('2.0')) - Li(RealNumber('4.5'))                                               # needs mpmath
      0.000000000000000

  \(\operatorname{Li}(x)\) is extended to complex arguments \(z\) by analytic continuation (see [AS1964] 5.1.3):

  Sage

      sage: Li(6.6 + 5.4*I)                                                           # needs sage.symbolic
      3.97032201503632 + 2.62311237593572*I

  [Python]

      >>> from sage.all import *
      >>> Li(RealNumber('6.6') + RealNumber('5.4')*I)                                                           # needs sage.symbolic
      3.97032201503632 + 2.62311237593572*I

  The function \(\operatorname{Li}\) is an approximation for the number of primes up to \(x\). In fact, the famous Riemann Hypothesis is

  \[|\pi(x) - \operatorname{Li}(x)| \leq \sqrt{x} \log(x).\]

  For “small” \(x\), \(\operatorname{Li}(x)\) is always slightly bigger than \(\pi(x)\). However it is a theorem that there are very large values of \(x\) (e.g., around \(10^{316}\)), such that \(\exists x: \pi(x) > \operatorname{Li}(x)\). See “A new bound for the smallest x with \(\pi(x) > \operatorname{li}(x)\)”, Bays and Hudson, Mathematics of Computation, 69 (2000) 1285-1296.

  Note

  Definite integration returns a part symbolic and part numerical result. This is because when Li(x) is evaluated it is passed as li(x)-li(2).

  EXAMPLES:

  Numerical evaluation for real and complex arguments is handled using mpmath:

  Sage

      sage: # needs sage.symbolic
      sage: N(log_integral_offset(3))
      1.11842481454970
      sage: N(log_integral_offset(3), digits=30)
      1.11842481454969918803233347815
      sage: log_integral_offset(ComplexField(100)(3+I))
      1.2428254968641898308632562019 + 0.87232935488528370139883806779*I
      sage: log_integral_offset(2)
      0
      sage: for n in range(1,7):                                                      # needs primecountpy
      ....:  print('%-10s%-10s%-20s'%(10^n, prime_pi(10^n), N(Li(10^n))))
      10        4         5.12043572466980
      100       25        29.0809778039621
      1000      168       176.564494210035
      10000     1229      1245.09205211927
      100000    9592      9628.76383727068
      1000000   78498     78626.5039956821

  Python

      >>> from sage.all import *
      >>> # needs sage.symbolic
      >>> N(log_integral_offset(Integer(3)))
      1.11842481454970
      >>> N(log_integral_offset(Integer(3)), digits=Integer(30))
      1.11842481454969918803233347815
      >>> log_integral_offset(ComplexField(Integer(100))(Integer(3)+I))
      1.2428254968641898308632562019 + 0.87232935488528370139883806779*I
      >>> log_integral_offset(Integer(2))
      0
      >>> for n in range(Integer(1),Integer(7)):                                                      # needs primecountpy
      ...  print('%-10s%-10s%-20s'%(Integer(10)**n, prime_pi(Integer(10)**n), N(Li(Integer(10)**n))))
      10        4         5.12043572466980
      100       25        29.0809778039621
      1000      168       176.564494210035
      10000     1229      1245.09205211927
      100000    9592      9628.76383727068
      1000000   78498     78626.5039956821

  Here is a test from the mpmath documentation. There are 1,925,320,391,606,803,968,923 prime numbers less than 1e23. The value of `log_integral_offset(1e23)` is very close to this:

  Sage

      sage: log_integral_offset(1e23)                                                 # needs mpmath
      1.92532039161405e21

  [Python]

      >>> from sage.all import *
      >>> log_integral_offset(RealNumber('1e23'))                                                 # needs mpmath
      1.92532039161405e21

  Symbolic derivatives are handled by Sage and integration by Maxima:

  Sage

      sage: # needs sage.symbolic
      sage: x = var('x')
      sage: f = log_integral_offset(x)
      sage: f.diff(x)
      1/log(x)
      sage: f.integrate(x)
      -x*log_integral(2) + x*log_integral(x) - Ei(2*log(x))
      sage: Li(x).integrate(x, 2.0, 4.5).n(digits=10)
      3.186411697
      sage: N(f.integrate(x, 2.0, 3.0))   # abs tol 1e-15
      0.601621785860587

  Python

      >>> from sage.all import *
      >>> # needs sage.symbolic
      >>> x = var('x')
      >>> f = log_integral_offset(x)
      >>> f.diff(x)
      1/log(x)
      >>> f.integrate(x)
      -x*log_integral(2) + x*log_integral(x) - Ei(2*log(x))
      >>> Li(x).integrate(x, RealNumber('2.0'), RealNumber('4.5')).n(digits=Integer(10))
      3.186411697
      >>> N(f.integrate(x, RealNumber('2.0'), RealNumber('3.0')))   # abs tol 1e-15
      0.601621785860587

  ALGORITHM:

  Numerical evaluation is handled using mpmath, but symbolics are handled by Sage and Maxima.

  REFERENCES:

  - Wikipedia article Logarithmic_integral_function

  - mpmath documentation: logarithmic-integral

class sage.functions.exp_integral.Function_sin_integral

  Bases: `BuiltinFunction`

  The trigonometric integral \(\operatorname{Si}(z)\) defined by

  \[\operatorname{Si}(z) = \int_0^z \frac{\sin(t)}{t} \; dt,\]

  see [AS1964] 5.2.1.

  EXAMPLES:

  Numerical evaluation for real and complex arguments is handled using mpmath:

  Sage

      sage: sin_integral(0)                                                           # needs mpmath
      0
      sage: sin_integral(0.0)                                                         # needs mpmath
      0.000000000000000
      sage: sin_integral(3.0)                                                         # needs mpmath
      1.84865252799947
      sage: N(sin_integral(3), digits=30)                                             # needs sage.symbolic
      1.84865252799946825639773025111
      sage: sin_integral(ComplexField(100)(3+I))                                      # needs sage.symbolic
      2.0277151656451253616038525998 + 0.015210926166954211913653130271*I

  Python

      >>> from sage.all import *
      >>> sin_integral(Integer(0))                                                           # needs mpmath
      0
      >>> sin_integral(RealNumber('0.0'))                                                         # needs mpmath
      0.000000000000000
      >>> sin_integral(RealNumber('3.0'))                                                         # needs mpmath
      1.84865252799947
      >>> N(sin_integral(Integer(3)), digits=Integer(30))                                             # needs sage.symbolic
      1.84865252799946825639773025111
      >>> sin_integral(ComplexField(Integer(100))(Integer(3)+I))                                      # needs sage.symbolic
      2.0277151656451253616038525998 + 0.015210926166954211913653130271*I

  The alias `Si` can be used instead of `sin_integral`:

  Sage

      sage: Si(3.0)                                                                   # needs mpmath
      1.84865252799947

  [Python]

      >>> from sage.all import *
      >>> Si(RealNumber('3.0'))                                                                   # needs mpmath
      1.84865252799947

  The limit of \(\operatorname{Si}(z)\) as \(z \to \infty\) is \(\pi/2\):

  Sage

      sage: N(sin_integral(1e23))                                                     # needs mpmath
      1.57079632679490
      sage: N(pi/2)                                                                   # needs sage.symbolic
      1.57079632679490

  Python

      >>> from sage.all import *
      >>> N(sin_integral(RealNumber('1e23')))                                                     # needs mpmath
      1.57079632679490
      >>> N(pi/Integer(2))                                                                   # needs sage.symbolic
      1.57079632679490

  At 200 bits of precision \(\operatorname{Si}(10^{23})\) agrees with \(\pi/2\) up to \(10^{-24}\):

  Sage

      sage: sin_integral(RealField(200)(1e23))                                        # needs sage.rings.real_mpfr
      1.5707963267948966192313288218697837425815368604836679189519
      sage: N(pi/2, prec=200)                                                         # needs sage.symbolic
      1.5707963267948966192313216916397514420985846996875529104875

  [Python]

      >>> from sage.all import *
      >>> sin_integral(RealField(Integer(200))(RealNumber('1e23')))                                        # needs sage.rings.real_mpfr
      1.5707963267948966192313288218697837425815368604836679189519
      >>> N(pi/Integer(2), prec=Integer(200))                                                         # needs sage.symbolic
      1.5707963267948966192313216916397514420985846996875529104875

  The exponential sine integral is analytic everywhere:

  Sage

      sage: sin_integral(-1.0)                                                        # needs mpmath
      -0.946083070367183
      sage: sin_integral(-2.0)                                                        # needs mpmath
      -1.60541297680269
      sage: sin_integral(-1e23)                                                       # needs mpmath
      -1.57079632679490

  Python

      >>> from sage.all import *
      >>> sin_integral(-RealNumber('1.0'))                                                        # needs mpmath
      -0.946083070367183
      >>> sin_integral(-RealNumber('2.0'))                                                        # needs mpmath
      -1.60541297680269
      >>> sin_integral(-RealNumber('1e23'))                                                       # needs mpmath
      -1.57079632679490

  Symbolic derivatives and integrals are handled by Sage and Maxima:

  Sage

      sage: # needs sage.symbolic
      sage: x = var('x')
      sage: f = sin_integral(x)
      sage: f.diff(x)
      sin(x)/x
      sage: f.integrate(x)
      x*sin_integral(x) + cos(x)
      sage: integrate(sin(x)/x, x)
      -1/2*I*Ei(I*x) + 1/2*I*Ei(-I*x)

  [Python]

      >>> from sage.all import *
      >>> # needs sage.symbolic
      >>> x = var('x')
      >>> f = sin_integral(x)
      >>> f.diff(x)
      sin(x)/x
      >>> f.integrate(x)
      x*sin_integral(x) + cos(x)
      >>> integrate(sin(x)/x, x)
      -1/2*I*Ei(I*x) + 1/2*I*Ei(-I*x)

  Compare values of the functions \(\operatorname{Si}(x)\) and \(f(x) = (1/2)i \cdot \operatorname{Ei}(-ix) - (1/2)i \cdot \operatorname{Ei}(ix) - \pi/2\), which are both anti-derivatives of \(\sin(x)/x\), at some random positive real numbers:

  Sage

      sage: f(x) = 1/2*I*Ei(-I*x) - 1/2*I*Ei(I*x) - pi/2                              # needs sage.symbolic
      sage: g(x) = sin_integral(x)                                                    # needs sage.symbolic
      sage: R = [abs(RDF.random_element()) for i in range(100)]
      sage: all(abs(f(x) - g(x)) < 1e-10 for x in R)                                  # needs sage.symbolic
      True

  Python

      >>> from sage.all import *
      >>> __tmp__=var("x"); f = symbolic_expression(Integer(1)/Integer(2)*I*Ei(-I*x) - Integer(1)/Integer(2)*I*Ei(I*x) - pi/Integer(2)                              ).function(x)# needs sage.symbolic
      >>> __tmp__=var("x"); g = symbolic_expression(sin_integral(x)                                                    ).function(x)# needs sage.symbolic
      >>> R = [abs(RDF.random_element()) for i in range(Integer(100))]
      >>> all(abs(f(x) - g(x)) < RealNumber('1e-10') for x in R)                                  # needs sage.symbolic
      True

  The Nielsen spiral is the parametric plot of (Si(t), Ci(t)):

  Sage

      sage: # needs sage.symbolic
      sage: x = var('x')
      sage: f(x) = sin_integral(x)
      sage: g(x) = cos_integral(x)
      sage: P = parametric_plot([f, g], (x, 0.5 ,20))                                 # needs sage.plot
      sage: show(P, frame=True, axes=False)                                           # needs sage.plot

  [Python]

      >>> from sage.all import *
      >>> # needs sage.symbolic
      >>> x = var('x')
      >>> __tmp__=var("x"); f = symbolic_expression(sin_integral(x)).function(x)
      >>> __tmp__=var("x"); g = symbolic_expression(cos_integral(x)).function(x)
      >>> P = parametric_plot([f, g], (x, RealNumber('0.5') ,Integer(20)))                                 # needs sage.plot
      >>> show(P, frame=True, axes=False)                                           # needs sage.plot

  ALGORITHM:

  Numerical evaluation is handled using mpmath, but symbolics are handled by Sage and Maxima.

  REFERENCES:

  - Wikipedia article Trigonometric_integral

  - mpmath documentation: si

class sage.functions.exp_integral.Function_sinh_integral

  Bases: `BuiltinFunction`

  The trigonometric integral \(\operatorname{Shi}(z)\) defined by

  \[\operatorname{Shi}(z) = \int_0^z \frac{\sinh(t)}{t} \; dt,\]

  see [AS1964] 5.2.3.

  EXAMPLES:

  Numerical evaluation for real and complex arguments is handled using mpmath:

  Sage

      sage: sinh_integral(3.0)                                                        # needs mpmath
      4.97344047585981
      sage: sinh_integral(1.0)                                                        # needs mpmath
      1.05725087537573
      sage: sinh_integral(-1.0)                                                       # needs mpmath
      -1.05725087537573

  Python

      >>> from sage.all import *
      >>> sinh_integral(RealNumber('3.0'))                                                        # needs mpmath
      4.97344047585981
      >>> sinh_integral(RealNumber('1.0'))                                                        # needs mpmath
      1.05725087537573
      >>> sinh_integral(-RealNumber('1.0'))                                                       # needs mpmath
      -1.05725087537573

  The alias `Shi` can be used instead of `sinh_integral`:

  Sage

      sage: Shi(3.0)                                                                  # needs mpmath
      4.97344047585981

  [Python]

      >>> from sage.all import *
      >>> Shi(RealNumber('3.0'))                                                                  # needs mpmath
      4.97344047585981

  Compare `sinh_integral(3.0)` to the definition of the value using numerical integration:

  Sage

      sage: a = numerical_integral(sinh(x)/x, 0, 3)[0]                                # needs sage.symbolic
      sage: abs(a - N(sinh_integral(3))) < 1e-14                                      # needs sage.symbolic
      True

  Python

      >>> from sage.all import *
      >>> a = numerical_integral(sinh(x)/x, Integer(0), Integer(3))[Integer(0)]                                # needs sage.symbolic
      >>> abs(a - N(sinh_integral(Integer(3)))) < RealNumber('1e-14')                                      # needs sage.symbolic
      True

  Arbitrary precision and complex arguments are handled:

  Sage

      sage: N(sinh_integral(3), digits=30)                                            # needs sage.symbolic
      4.97344047585980679771041838252
      sage: sinh_integral(ComplexField(100)(3+I))                                     # needs sage.symbolic
      3.9134623660329374406788354078 + 3.0427678212908839256360163759*I

  [Python]

      >>> from sage.all import *
      >>> N(sinh_integral(Integer(3)), digits=Integer(30))                                            # needs sage.symbolic
      4.97344047585980679771041838252
      >>> sinh_integral(ComplexField(Integer(100))(Integer(3)+I))                                     # needs sage.symbolic
      3.9134623660329374406788354078 + 3.0427678212908839256360163759*I

  The limit \(\operatorname{Shi}(z)\) as \(z \to \infty\) is \(\infty\):

  Sage

      sage: N(sinh_integral(Infinity))                                                # needs mpmath
      +infinity

  Python

      >>> from sage.all import *
      >>> N(sinh_integral(Infinity))                                                # needs mpmath
      +infinity

  Symbolic derivatives and integrals are handled by Sage and Maxima:

  Sage

      sage: x = var('x')                                                              # needs sage.symbolic
      sage: f = sinh_integral(x)                                                      # needs sage.symbolic
      sage: f.diff(x)                                                                 # needs sage.symbolic
      sinh(x)/x

      sage: f.integrate(x)                                                            # needs sage.symbolic
      x*sinh_integral(x) - cosh(x)

  [Python]

      >>> from sage.all import *
      >>> x = var('x')                                                              # needs sage.symbolic
      >>> f = sinh_integral(x)                                                      # needs sage.symbolic
      >>> f.diff(x)                                                                 # needs sage.symbolic
      sinh(x)/x

      >>> f.integrate(x)                                                            # needs sage.symbolic
      x*sinh_integral(x) - cosh(x)

  Note that due to some problems with the way Maxima handles these expressions, definite integrals can sometimes give unexpected results (typically when using inexact endpoints) due to inconsistent branching:

  Sage

      sage: integrate(sinh_integral(x), x, 0, 1/2)                                    # needs sage.symbolic
      -cosh(1/2) + 1/2*sinh_integral(1/2) + 1
      sage: integrate(sinh_integral(x), x, 0, 1/2).n()  # correct                     # needs sage.symbolic
      0.125872409703453
      sage: integrate(sinh_integral(x), x, 0, 0.5).n()  # fixed in maxima 5.29.1      # needs sage.symbolic
      0.125872409703453

  Python

      >>> from sage.all import *
      >>> integrate(sinh_integral(x), x, Integer(0), Integer(1)/Integer(2))                                    # needs sage.symbolic
      -cosh(1/2) + 1/2*sinh_integral(1/2) + 1
      >>> integrate(sinh_integral(x), x, Integer(0), Integer(1)/Integer(2)).n()  # correct                     # needs sage.symbolic
      0.125872409703453
      >>> integrate(sinh_integral(x), x, Integer(0), RealNumber('0.5')).n()  # fixed in maxima 5.29.1      # needs sage.symbolic
      0.125872409703453

  ALGORITHM:

  Numerical evaluation is handled using mpmath, but symbolics are handled by Sage and Maxima.

  REFERENCES:

  - Wikipedia article Trigonometric_integral

  - mpmath documentation: shi

sage.functions.exp_integral.exponential_integral_1(x, n=0)

  Return the exponential integral \(E_1(x)\). If the optional argument \(n\) is given, computes list of the first \(n\) values of the exponential integral \(E_1(x m)\).

  The exponential integral \(E_1(x)\) is

  \[E_1(x) = \int_{x}^{\infty} \frac{e^{-t}}{t} \; dt\]

  INPUT:

  - `x` – a positive real number

  - `n` – (default: 0) a nonnegative integer; if nonzero, then return a list of values `E_1(x*m)` for m = 1,2,3,…,n. This is useful, e.g., when computing derivatives of \(L\)-functions.

  OUTPUT:

  A real number if n is 0 (the default) or a list of reals if n > 0. The precision is the same as the input, with a default of 53 bits in case the input is exact.

  EXAMPLES:

  Sage

      sage: # needs sage.libs.pari sage.rings.real_mpfr
      sage: exponential_integral_1(2)
      0.0489005107080611
      sage: exponential_integral_1(2, 4)  # abs tol 1e-18
      [0.0489005107080611, 0.00377935240984891, 0.000360082452162659, 0.0000376656228439245]
      sage: exponential_integral_1(40, 5)
      [0.000000000000000, 2.22854325868847e-37, 6.33732515501151e-55,
       2.02336191509997e-72, 6.88522610630764e-90]
      sage: r = exponential_integral_1(RealField(150)(1)); r
      0.21938393439552027367716377546012164903104729
      sage: parent(r)
      Real Field with 150 bits of precision
      sage: exponential_integral_1(RealField(150)(100))
      3.6835977616820321802351926205081189876552201e-46

      sage: exponential_integral_1(0)
      +Infinity

  Python

      >>> from sage.all import *
      >>> # needs sage.libs.pari sage.rings.real_mpfr
      >>> exponential_integral_1(Integer(2))
      0.0489005107080611
      >>> exponential_integral_1(Integer(2), Integer(4))  # abs tol 1e-18
      [0.0489005107080611, 0.00377935240984891, 0.000360082452162659, 0.0000376656228439245]
      >>> exponential_integral_1(Integer(40), Integer(5))
      [0.000000000000000, 2.22854325868847e-37, 6.33732515501151e-55,
       2.02336191509997e-72, 6.88522610630764e-90]
      >>> r = exponential_integral_1(RealField(Integer(150))(Integer(1))); r
      0.21938393439552027367716377546012164903104729
      >>> parent(r)
      Real Field with 150 bits of precision
      >>> exponential_integral_1(RealField(Integer(150))(Integer(100)))
      3.6835977616820321802351926205081189876552201e-46

      >>> exponential_integral_1(Integer(0))
      +Infinity

  ALGORITHM: use the PARI C-library function pari:eint1.

  REFERENCE:

  - See Proposition 5.6.12 of Cohen’s book “A Course in Computational Algebraic Number Theory”.