|
|
|
|
|
|
|
|
|
import numpy as np |
|
import math |
|
import warnings |
|
from collections import defaultdict |
|
from heapq import heapify, heappop |
|
from numpy import (pi, asarray, floor, isscalar, sqrt, where, |
|
sin, place, issubdtype, extract, inexact, nan, zeros, sinc) |
|
|
|
from . import _ufuncs |
|
from ._ufuncs import (mathieu_a, mathieu_b, iv, jv, gamma, rgamma, |
|
psi, hankel1, hankel2, yv, kv, poch, binom, |
|
_stirling2_inexact) |
|
|
|
from ._gufuncs import _lqn, _lqmn, _rctj, _rcty |
|
from ._input_validation import _nonneg_int_or_fail |
|
from . import _specfun |
|
from ._comb import _comb_int |
|
from ._multiufuncs import (assoc_legendre_p_all, |
|
legendre_p_all) |
|
from scipy._lib.deprecation import _deprecated |
|
|
|
|
|
__all__ = [ |
|
'ai_zeros', |
|
'assoc_laguerre', |
|
'bei_zeros', |
|
'beip_zeros', |
|
'ber_zeros', |
|
'bernoulli', |
|
'berp_zeros', |
|
'bi_zeros', |
|
'clpmn', |
|
'comb', |
|
'digamma', |
|
'diric', |
|
'erf_zeros', |
|
'euler', |
|
'factorial', |
|
'factorial2', |
|
'factorialk', |
|
'fresnel_zeros', |
|
'fresnelc_zeros', |
|
'fresnels_zeros', |
|
'h1vp', |
|
'h2vp', |
|
'ivp', |
|
'jn_zeros', |
|
'jnjnp_zeros', |
|
'jnp_zeros', |
|
'jnyn_zeros', |
|
'jvp', |
|
'kei_zeros', |
|
'keip_zeros', |
|
'kelvin_zeros', |
|
'ker_zeros', |
|
'kerp_zeros', |
|
'kvp', |
|
'lmbda', |
|
'lpmn', |
|
'lpn', |
|
'lqmn', |
|
'lqn', |
|
'mathieu_even_coef', |
|
'mathieu_odd_coef', |
|
'obl_cv_seq', |
|
'pbdn_seq', |
|
'pbdv_seq', |
|
'pbvv_seq', |
|
'perm', |
|
'polygamma', |
|
'pro_cv_seq', |
|
'riccati_jn', |
|
'riccati_yn', |
|
'sinc', |
|
'softplus', |
|
'stirling2', |
|
'y0_zeros', |
|
'y1_zeros', |
|
'y1p_zeros', |
|
'yn_zeros', |
|
'ynp_zeros', |
|
'yvp', |
|
'zeta' |
|
] |
|
|
|
|
|
__DEPRECATION_MSG_1_15 = ( |
|
"`scipy.special.{}` is deprecated as of SciPy 1.15.0 and will be " |
|
"removed in SciPy 1.17.0. Please use `scipy.special.{}` instead." |
|
) |
|
|
|
|
|
_FACTORIALK_LIMITS_64BITS = {1: 20, 2: 33, 3: 44, 4: 54, 5: 65, |
|
6: 74, 7: 84, 8: 93, 9: 101} |
|
|
|
_FACTORIALK_LIMITS_32BITS = {1: 12, 2: 19, 3: 25, 4: 31, 5: 37, |
|
6: 43, 7: 47, 8: 51, 9: 56} |
|
|
|
|
|
def diric(x, n): |
|
"""Periodic sinc function, also called the Dirichlet function. |
|
|
|
The Dirichlet function is defined as:: |
|
|
|
diric(x, n) = sin(x * n/2) / (n * sin(x / 2)), |
|
|
|
where `n` is a positive integer. |
|
|
|
Parameters |
|
---------- |
|
x : array_like |
|
Input data |
|
n : int |
|
Integer defining the periodicity. |
|
|
|
Returns |
|
------- |
|
diric : ndarray |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> from scipy import special |
|
>>> import matplotlib.pyplot as plt |
|
|
|
>>> x = np.linspace(-8*np.pi, 8*np.pi, num=201) |
|
>>> plt.figure(figsize=(8, 8)); |
|
>>> for idx, n in enumerate([2, 3, 4, 9]): |
|
... plt.subplot(2, 2, idx+1) |
|
... plt.plot(x, special.diric(x, n)) |
|
... plt.title('diric, n={}'.format(n)) |
|
>>> plt.show() |
|
|
|
The following example demonstrates that `diric` gives the magnitudes |
|
(modulo the sign and scaling) of the Fourier coefficients of a |
|
rectangular pulse. |
|
|
|
Suppress output of values that are effectively 0: |
|
|
|
>>> np.set_printoptions(suppress=True) |
|
|
|
Create a signal `x` of length `m` with `k` ones: |
|
|
|
>>> m = 8 |
|
>>> k = 3 |
|
>>> x = np.zeros(m) |
|
>>> x[:k] = 1 |
|
|
|
Use the FFT to compute the Fourier transform of `x`, and |
|
inspect the magnitudes of the coefficients: |
|
|
|
>>> np.abs(np.fft.fft(x)) |
|
array([ 3. , 2.41421356, 1. , 0.41421356, 1. , |
|
0.41421356, 1. , 2.41421356]) |
|
|
|
Now find the same values (up to sign) using `diric`. We multiply |
|
by `k` to account for the different scaling conventions of |
|
`numpy.fft.fft` and `diric`: |
|
|
|
>>> theta = np.linspace(0, 2*np.pi, m, endpoint=False) |
|
>>> k * special.diric(theta, k) |
|
array([ 3. , 2.41421356, 1. , -0.41421356, -1. , |
|
-0.41421356, 1. , 2.41421356]) |
|
""" |
|
x, n = asarray(x), asarray(n) |
|
n = asarray(n + (x-x)) |
|
x = asarray(x + (n-n)) |
|
if issubdtype(x.dtype, inexact): |
|
ytype = x.dtype |
|
else: |
|
ytype = float |
|
y = zeros(x.shape, ytype) |
|
|
|
|
|
|
|
if np.finfo(ytype).eps < 1e-18: |
|
minval = 1e-11 |
|
elif np.finfo(ytype).eps < 1e-15: |
|
minval = 1e-7 |
|
else: |
|
minval = 1e-3 |
|
|
|
mask1 = (n <= 0) | (n != floor(n)) |
|
place(y, mask1, nan) |
|
|
|
x = x / 2 |
|
denom = sin(x) |
|
mask2 = (1-mask1) & (abs(denom) < minval) |
|
xsub = extract(mask2, x) |
|
nsub = extract(mask2, n) |
|
zsub = xsub / pi |
|
place(y, mask2, pow(-1, np.round(zsub)*(nsub-1))) |
|
|
|
mask = (1-mask1) & (1-mask2) |
|
xsub = extract(mask, x) |
|
nsub = extract(mask, n) |
|
dsub = extract(mask, denom) |
|
place(y, mask, sin(nsub*xsub)/(nsub*dsub)) |
|
return y |
|
|
|
|
|
def jnjnp_zeros(nt): |
|
"""Compute zeros of integer-order Bessel functions Jn and Jn'. |
|
|
|
Results are arranged in order of the magnitudes of the zeros. |
|
|
|
Parameters |
|
---------- |
|
nt : int |
|
Number (<=1200) of zeros to compute |
|
|
|
Returns |
|
------- |
|
zo[l-1] : ndarray |
|
Value of the lth zero of Jn(x) and Jn'(x). Of length `nt`. |
|
n[l-1] : ndarray |
|
Order of the Jn(x) or Jn'(x) associated with lth zero. Of length `nt`. |
|
m[l-1] : ndarray |
|
Serial number of the zeros of Jn(x) or Jn'(x) associated |
|
with lth zero. Of length `nt`. |
|
t[l-1] : ndarray |
|
0 if lth zero in zo is zero of Jn(x), 1 if it is a zero of Jn'(x). Of |
|
length `nt`. |
|
|
|
See Also |
|
-------- |
|
jn_zeros, jnp_zeros : to get separated arrays of zeros. |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996, chapter 5. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
""" |
|
if not isscalar(nt) or (floor(nt) != nt) or (nt > 1200): |
|
raise ValueError("Number must be integer <= 1200.") |
|
nt = int(nt) |
|
n, m, t, zo = _specfun.jdzo(nt) |
|
return zo[1:nt+1], n[:nt], m[:nt], t[:nt] |
|
|
|
|
|
def jnyn_zeros(n, nt): |
|
"""Compute nt zeros of Bessel functions Jn(x), Jn'(x), Yn(x), and Yn'(x). |
|
|
|
Returns 4 arrays of length `nt`, corresponding to the first `nt` |
|
zeros of Jn(x), Jn'(x), Yn(x), and Yn'(x), respectively. The zeros |
|
are returned in ascending order. |
|
|
|
Parameters |
|
---------- |
|
n : int |
|
Order of the Bessel functions |
|
nt : int |
|
Number (<=1200) of zeros to compute |
|
|
|
Returns |
|
------- |
|
Jn : ndarray |
|
First `nt` zeros of Jn |
|
Jnp : ndarray |
|
First `nt` zeros of Jn' |
|
Yn : ndarray |
|
First `nt` zeros of Yn |
|
Ynp : ndarray |
|
First `nt` zeros of Yn' |
|
|
|
See Also |
|
-------- |
|
jn_zeros, jnp_zeros, yn_zeros, ynp_zeros |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996, chapter 5. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
Examples |
|
-------- |
|
Compute the first three roots of :math:`J_1`, :math:`J_1'`, |
|
:math:`Y_1` and :math:`Y_1'`. |
|
|
|
>>> from scipy.special import jnyn_zeros |
|
>>> jn_roots, jnp_roots, yn_roots, ynp_roots = jnyn_zeros(1, 3) |
|
>>> jn_roots, yn_roots |
|
(array([ 3.83170597, 7.01558667, 10.17346814]), |
|
array([2.19714133, 5.42968104, 8.59600587])) |
|
|
|
Plot :math:`J_1`, :math:`J_1'`, :math:`Y_1`, :math:`Y_1'` and their roots. |
|
|
|
>>> import numpy as np |
|
>>> import matplotlib.pyplot as plt |
|
>>> from scipy.special import jnyn_zeros, jvp, jn, yvp, yn |
|
>>> jn_roots, jnp_roots, yn_roots, ynp_roots = jnyn_zeros(1, 3) |
|
>>> fig, ax = plt.subplots() |
|
>>> xmax= 11 |
|
>>> x = np.linspace(0, xmax) |
|
>>> x[0] += 1e-15 |
|
>>> ax.plot(x, jn(1, x), label=r"$J_1$", c='r') |
|
>>> ax.plot(x, jvp(1, x, 1), label=r"$J_1'$", c='b') |
|
>>> ax.plot(x, yn(1, x), label=r"$Y_1$", c='y') |
|
>>> ax.plot(x, yvp(1, x, 1), label=r"$Y_1'$", c='c') |
|
>>> zeros = np.zeros((3, )) |
|
>>> ax.scatter(jn_roots, zeros, s=30, c='r', zorder=5, |
|
... label=r"$J_1$ roots") |
|
>>> ax.scatter(jnp_roots, zeros, s=30, c='b', zorder=5, |
|
... label=r"$J_1'$ roots") |
|
>>> ax.scatter(yn_roots, zeros, s=30, c='y', zorder=5, |
|
... label=r"$Y_1$ roots") |
|
>>> ax.scatter(ynp_roots, zeros, s=30, c='c', zorder=5, |
|
... label=r"$Y_1'$ roots") |
|
>>> ax.hlines(0, 0, xmax, color='k') |
|
>>> ax.set_ylim(-0.6, 0.6) |
|
>>> ax.set_xlim(0, xmax) |
|
>>> ax.legend(ncol=2, bbox_to_anchor=(1., 0.75)) |
|
>>> plt.tight_layout() |
|
>>> plt.show() |
|
""" |
|
if not (isscalar(nt) and isscalar(n)): |
|
raise ValueError("Arguments must be scalars.") |
|
if (floor(n) != n) or (floor(nt) != nt): |
|
raise ValueError("Arguments must be integers.") |
|
if (nt <= 0): |
|
raise ValueError("nt > 0") |
|
return _specfun.jyzo(abs(n), nt) |
|
|
|
|
|
def jn_zeros(n, nt): |
|
r"""Compute zeros of integer-order Bessel functions Jn. |
|
|
|
Compute `nt` zeros of the Bessel functions :math:`J_n(x)` on the |
|
interval :math:`(0, \infty)`. The zeros are returned in ascending |
|
order. Note that this interval excludes the zero at :math:`x = 0` |
|
that exists for :math:`n > 0`. |
|
|
|
Parameters |
|
---------- |
|
n : int |
|
Order of Bessel function |
|
nt : int |
|
Number of zeros to return |
|
|
|
Returns |
|
------- |
|
ndarray |
|
First `nt` zeros of the Bessel function. |
|
|
|
See Also |
|
-------- |
|
jv: Real-order Bessel functions of the first kind |
|
jnp_zeros: Zeros of :math:`Jn'` |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996, chapter 5. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
Examples |
|
-------- |
|
Compute the first four positive roots of :math:`J_3`. |
|
|
|
>>> from scipy.special import jn_zeros |
|
>>> jn_zeros(3, 4) |
|
array([ 6.3801619 , 9.76102313, 13.01520072, 16.22346616]) |
|
|
|
Plot :math:`J_3` and its first four positive roots. Note |
|
that the root located at 0 is not returned by `jn_zeros`. |
|
|
|
>>> import numpy as np |
|
>>> import matplotlib.pyplot as plt |
|
>>> from scipy.special import jn, jn_zeros |
|
>>> j3_roots = jn_zeros(3, 4) |
|
>>> xmax = 18 |
|
>>> xmin = -1 |
|
>>> x = np.linspace(xmin, xmax, 500) |
|
>>> fig, ax = plt.subplots() |
|
>>> ax.plot(x, jn(3, x), label=r'$J_3$') |
|
>>> ax.scatter(j3_roots, np.zeros((4, )), s=30, c='r', |
|
... label=r"$J_3$_Zeros", zorder=5) |
|
>>> ax.scatter(0, 0, s=30, c='k', |
|
... label=r"Root at 0", zorder=5) |
|
>>> ax.hlines(0, 0, xmax, color='k') |
|
>>> ax.set_xlim(xmin, xmax) |
|
>>> plt.legend() |
|
>>> plt.show() |
|
""" |
|
return jnyn_zeros(n, nt)[0] |
|
|
|
|
|
def jnp_zeros(n, nt): |
|
r"""Compute zeros of integer-order Bessel function derivatives Jn'. |
|
|
|
Compute `nt` zeros of the functions :math:`J_n'(x)` on the |
|
interval :math:`(0, \infty)`. The zeros are returned in ascending |
|
order. Note that this interval excludes the zero at :math:`x = 0` |
|
that exists for :math:`n > 1`. |
|
|
|
Parameters |
|
---------- |
|
n : int |
|
Order of Bessel function |
|
nt : int |
|
Number of zeros to return |
|
|
|
Returns |
|
------- |
|
ndarray |
|
First `nt` zeros of the Bessel function. |
|
|
|
See Also |
|
-------- |
|
jvp: Derivatives of integer-order Bessel functions of the first kind |
|
jv: Float-order Bessel functions of the first kind |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996, chapter 5. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
Examples |
|
-------- |
|
Compute the first four roots of :math:`J_2'`. |
|
|
|
>>> from scipy.special import jnp_zeros |
|
>>> jnp_zeros(2, 4) |
|
array([ 3.05423693, 6.70613319, 9.96946782, 13.17037086]) |
|
|
|
As `jnp_zeros` yields the roots of :math:`J_n'`, it can be used to |
|
compute the locations of the peaks of :math:`J_n`. Plot |
|
:math:`J_2`, :math:`J_2'` and the locations of the roots of :math:`J_2'`. |
|
|
|
>>> import numpy as np |
|
>>> import matplotlib.pyplot as plt |
|
>>> from scipy.special import jn, jnp_zeros, jvp |
|
>>> j2_roots = jnp_zeros(2, 4) |
|
>>> xmax = 15 |
|
>>> x = np.linspace(0, xmax, 500) |
|
>>> fig, ax = plt.subplots() |
|
>>> ax.plot(x, jn(2, x), label=r'$J_2$') |
|
>>> ax.plot(x, jvp(2, x, 1), label=r"$J_2'$") |
|
>>> ax.hlines(0, 0, xmax, color='k') |
|
>>> ax.scatter(j2_roots, np.zeros((4, )), s=30, c='r', |
|
... label=r"Roots of $J_2'$", zorder=5) |
|
>>> ax.set_ylim(-0.4, 0.8) |
|
>>> ax.set_xlim(0, xmax) |
|
>>> plt.legend() |
|
>>> plt.show() |
|
""" |
|
return jnyn_zeros(n, nt)[1] |
|
|
|
|
|
def yn_zeros(n, nt): |
|
r"""Compute zeros of integer-order Bessel function Yn(x). |
|
|
|
Compute `nt` zeros of the functions :math:`Y_n(x)` on the interval |
|
:math:`(0, \infty)`. The zeros are returned in ascending order. |
|
|
|
Parameters |
|
---------- |
|
n : int |
|
Order of Bessel function |
|
nt : int |
|
Number of zeros to return |
|
|
|
Returns |
|
------- |
|
ndarray |
|
First `nt` zeros of the Bessel function. |
|
|
|
See Also |
|
-------- |
|
yn: Bessel function of the second kind for integer order |
|
yv: Bessel function of the second kind for real order |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996, chapter 5. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
Examples |
|
-------- |
|
Compute the first four roots of :math:`Y_2`. |
|
|
|
>>> from scipy.special import yn_zeros |
|
>>> yn_zeros(2, 4) |
|
array([ 3.38424177, 6.79380751, 10.02347798, 13.20998671]) |
|
|
|
Plot :math:`Y_2` and its first four roots. |
|
|
|
>>> import numpy as np |
|
>>> import matplotlib.pyplot as plt |
|
>>> from scipy.special import yn, yn_zeros |
|
>>> xmin = 2 |
|
>>> xmax = 15 |
|
>>> x = np.linspace(xmin, xmax, 500) |
|
>>> fig, ax = plt.subplots() |
|
>>> ax.hlines(0, xmin, xmax, color='k') |
|
>>> ax.plot(x, yn(2, x), label=r'$Y_2$') |
|
>>> ax.scatter(yn_zeros(2, 4), np.zeros((4, )), s=30, c='r', |
|
... label='Roots', zorder=5) |
|
>>> ax.set_ylim(-0.4, 0.4) |
|
>>> ax.set_xlim(xmin, xmax) |
|
>>> plt.legend() |
|
>>> plt.show() |
|
""" |
|
return jnyn_zeros(n, nt)[2] |
|
|
|
|
|
def ynp_zeros(n, nt): |
|
r"""Compute zeros of integer-order Bessel function derivatives Yn'(x). |
|
|
|
Compute `nt` zeros of the functions :math:`Y_n'(x)` on the |
|
interval :math:`(0, \infty)`. The zeros are returned in ascending |
|
order. |
|
|
|
Parameters |
|
---------- |
|
n : int |
|
Order of Bessel function |
|
nt : int |
|
Number of zeros to return |
|
|
|
Returns |
|
------- |
|
ndarray |
|
First `nt` zeros of the Bessel derivative function. |
|
|
|
|
|
See Also |
|
-------- |
|
yvp |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996, chapter 5. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
Examples |
|
-------- |
|
Compute the first four roots of the first derivative of the |
|
Bessel function of second kind for order 0 :math:`Y_0'`. |
|
|
|
>>> from scipy.special import ynp_zeros |
|
>>> ynp_zeros(0, 4) |
|
array([ 2.19714133, 5.42968104, 8.59600587, 11.74915483]) |
|
|
|
Plot :math:`Y_0`, :math:`Y_0'` and confirm visually that the roots of |
|
:math:`Y_0'` are located at local extrema of :math:`Y_0`. |
|
|
|
>>> import numpy as np |
|
>>> import matplotlib.pyplot as plt |
|
>>> from scipy.special import yn, ynp_zeros, yvp |
|
>>> zeros = ynp_zeros(0, 4) |
|
>>> xmax = 13 |
|
>>> x = np.linspace(0, xmax, 500) |
|
>>> fig, ax = plt.subplots() |
|
>>> ax.plot(x, yn(0, x), label=r'$Y_0$') |
|
>>> ax.plot(x, yvp(0, x, 1), label=r"$Y_0'$") |
|
>>> ax.scatter(zeros, np.zeros((4, )), s=30, c='r', |
|
... label=r"Roots of $Y_0'$", zorder=5) |
|
>>> for root in zeros: |
|
... y0_extremum = yn(0, root) |
|
... lower = min(0, y0_extremum) |
|
... upper = max(0, y0_extremum) |
|
... ax.vlines(root, lower, upper, color='r') |
|
>>> ax.hlines(0, 0, xmax, color='k') |
|
>>> ax.set_ylim(-0.6, 0.6) |
|
>>> ax.set_xlim(0, xmax) |
|
>>> plt.legend() |
|
>>> plt.show() |
|
""" |
|
return jnyn_zeros(n, nt)[3] |
|
|
|
|
|
def y0_zeros(nt, complex=False): |
|
"""Compute nt zeros of Bessel function Y0(z), and derivative at each zero. |
|
|
|
The derivatives are given by Y0'(z0) = -Y1(z0) at each zero z0. |
|
|
|
Parameters |
|
---------- |
|
nt : int |
|
Number of zeros to return |
|
complex : bool, default False |
|
Set to False to return only the real zeros; set to True to return only |
|
the complex zeros with negative real part and positive imaginary part. |
|
Note that the complex conjugates of the latter are also zeros of the |
|
function, but are not returned by this routine. |
|
|
|
Returns |
|
------- |
|
z0n : ndarray |
|
Location of nth zero of Y0(z) |
|
y0pz0n : ndarray |
|
Value of derivative Y0'(z0) for nth zero |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996, chapter 5. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
Examples |
|
-------- |
|
Compute the first 4 real roots and the derivatives at the roots of |
|
:math:`Y_0`: |
|
|
|
>>> import numpy as np |
|
>>> from scipy.special import y0_zeros |
|
>>> zeros, grads = y0_zeros(4) |
|
>>> with np.printoptions(precision=5): |
|
... print(f"Roots: {zeros}") |
|
... print(f"Gradients: {grads}") |
|
Roots: [ 0.89358+0.j 3.95768+0.j 7.08605+0.j 10.22235+0.j] |
|
Gradients: [-0.87942+0.j 0.40254+0.j -0.3001 +0.j 0.2497 +0.j] |
|
|
|
Plot the real part of :math:`Y_0` and the first four computed roots. |
|
|
|
>>> import matplotlib.pyplot as plt |
|
>>> from scipy.special import y0 |
|
>>> xmin = 0 |
|
>>> xmax = 11 |
|
>>> x = np.linspace(xmin, xmax, 500) |
|
>>> fig, ax = plt.subplots() |
|
>>> ax.hlines(0, xmin, xmax, color='k') |
|
>>> ax.plot(x, y0(x), label=r'$Y_0$') |
|
>>> zeros, grads = y0_zeros(4) |
|
>>> ax.scatter(zeros.real, np.zeros((4, )), s=30, c='r', |
|
... label=r'$Y_0$_zeros', zorder=5) |
|
>>> ax.set_ylim(-0.5, 0.6) |
|
>>> ax.set_xlim(xmin, xmax) |
|
>>> plt.legend(ncol=2) |
|
>>> plt.show() |
|
|
|
Compute the first 4 complex roots and the derivatives at the roots of |
|
:math:`Y_0` by setting ``complex=True``: |
|
|
|
>>> y0_zeros(4, True) |
|
(array([ -2.40301663+0.53988231j, -5.5198767 +0.54718001j, |
|
-8.6536724 +0.54841207j, -11.79151203+0.54881912j]), |
|
array([ 0.10074769-0.88196771j, -0.02924642+0.5871695j , |
|
0.01490806-0.46945875j, -0.00937368+0.40230454j])) |
|
""" |
|
if not isscalar(nt) or (floor(nt) != nt) or (nt <= 0): |
|
raise ValueError("Arguments must be scalar positive integer.") |
|
kf = 0 |
|
kc = not complex |
|
return _specfun.cyzo(nt, kf, kc) |
|
|
|
|
|
def y1_zeros(nt, complex=False): |
|
"""Compute nt zeros of Bessel function Y1(z), and derivative at each zero. |
|
|
|
The derivatives are given by Y1'(z1) = Y0(z1) at each zero z1. |
|
|
|
Parameters |
|
---------- |
|
nt : int |
|
Number of zeros to return |
|
complex : bool, default False |
|
Set to False to return only the real zeros; set to True to return only |
|
the complex zeros with negative real part and positive imaginary part. |
|
Note that the complex conjugates of the latter are also zeros of the |
|
function, but are not returned by this routine. |
|
|
|
Returns |
|
------- |
|
z1n : ndarray |
|
Location of nth zero of Y1(z) |
|
y1pz1n : ndarray |
|
Value of derivative Y1'(z1) for nth zero |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996, chapter 5. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
Examples |
|
-------- |
|
Compute the first 4 real roots and the derivatives at the roots of |
|
:math:`Y_1`: |
|
|
|
>>> import numpy as np |
|
>>> from scipy.special import y1_zeros |
|
>>> zeros, grads = y1_zeros(4) |
|
>>> with np.printoptions(precision=5): |
|
... print(f"Roots: {zeros}") |
|
... print(f"Gradients: {grads}") |
|
Roots: [ 2.19714+0.j 5.42968+0.j 8.59601+0.j 11.74915+0.j] |
|
Gradients: [ 0.52079+0.j -0.34032+0.j 0.27146+0.j -0.23246+0.j] |
|
|
|
Extract the real parts: |
|
|
|
>>> realzeros = zeros.real |
|
>>> realzeros |
|
array([ 2.19714133, 5.42968104, 8.59600587, 11.74915483]) |
|
|
|
Plot :math:`Y_1` and the first four computed roots. |
|
|
|
>>> import matplotlib.pyplot as plt |
|
>>> from scipy.special import y1 |
|
>>> xmin = 0 |
|
>>> xmax = 13 |
|
>>> x = np.linspace(xmin, xmax, 500) |
|
>>> zeros, grads = y1_zeros(4) |
|
>>> fig, ax = plt.subplots() |
|
>>> ax.hlines(0, xmin, xmax, color='k') |
|
>>> ax.plot(x, y1(x), label=r'$Y_1$') |
|
>>> ax.scatter(zeros.real, np.zeros((4, )), s=30, c='r', |
|
... label=r'$Y_1$_zeros', zorder=5) |
|
>>> ax.set_ylim(-0.5, 0.5) |
|
>>> ax.set_xlim(xmin, xmax) |
|
>>> plt.legend() |
|
>>> plt.show() |
|
|
|
Compute the first 4 complex roots and the derivatives at the roots of |
|
:math:`Y_1` by setting ``complex=True``: |
|
|
|
>>> y1_zeros(4, True) |
|
(array([ -0.50274327+0.78624371j, -3.83353519+0.56235654j, |
|
-7.01590368+0.55339305j, -10.17357383+0.55127339j]), |
|
array([-0.45952768+1.31710194j, 0.04830191-0.69251288j, |
|
-0.02012695+0.51864253j, 0.011614 -0.43203296j])) |
|
""" |
|
if not isscalar(nt) or (floor(nt) != nt) or (nt <= 0): |
|
raise ValueError("Arguments must be scalar positive integer.") |
|
kf = 1 |
|
kc = not complex |
|
return _specfun.cyzo(nt, kf, kc) |
|
|
|
|
|
def y1p_zeros(nt, complex=False): |
|
"""Compute nt zeros of Bessel derivative Y1'(z), and value at each zero. |
|
|
|
The values are given by Y1(z1) at each z1 where Y1'(z1)=0. |
|
|
|
Parameters |
|
---------- |
|
nt : int |
|
Number of zeros to return |
|
complex : bool, default False |
|
Set to False to return only the real zeros; set to True to return only |
|
the complex zeros with negative real part and positive imaginary part. |
|
Note that the complex conjugates of the latter are also zeros of the |
|
function, but are not returned by this routine. |
|
|
|
Returns |
|
------- |
|
z1pn : ndarray |
|
Location of nth zero of Y1'(z) |
|
y1z1pn : ndarray |
|
Value of derivative Y1(z1) for nth zero |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996, chapter 5. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
Examples |
|
-------- |
|
Compute the first four roots of :math:`Y_1'` and the values of |
|
:math:`Y_1` at these roots. |
|
|
|
>>> import numpy as np |
|
>>> from scipy.special import y1p_zeros |
|
>>> y1grad_roots, y1_values = y1p_zeros(4) |
|
>>> with np.printoptions(precision=5): |
|
... print(f"Y1' Roots: {y1grad_roots.real}") |
|
... print(f"Y1 values: {y1_values.real}") |
|
Y1' Roots: [ 3.68302 6.9415 10.1234 13.28576] |
|
Y1 values: [ 0.41673 -0.30317 0.25091 -0.21897] |
|
|
|
`y1p_zeros` can be used to calculate the extremal points of :math:`Y_1` |
|
directly. Here we plot :math:`Y_1` and the first four extrema. |
|
|
|
>>> import matplotlib.pyplot as plt |
|
>>> from scipy.special import y1, yvp |
|
>>> y1_roots, y1_values_at_roots = y1p_zeros(4) |
|
>>> real_roots = y1_roots.real |
|
>>> xmax = 15 |
|
>>> x = np.linspace(0, xmax, 500) |
|
>>> x[0] += 1e-15 |
|
>>> fig, ax = plt.subplots() |
|
>>> ax.plot(x, y1(x), label=r'$Y_1$') |
|
>>> ax.plot(x, yvp(1, x, 1), label=r"$Y_1'$") |
|
>>> ax.scatter(real_roots, np.zeros((4, )), s=30, c='r', |
|
... label=r"Roots of $Y_1'$", zorder=5) |
|
>>> ax.scatter(real_roots, y1_values_at_roots.real, s=30, c='k', |
|
... label=r"Extrema of $Y_1$", zorder=5) |
|
>>> ax.hlines(0, 0, xmax, color='k') |
|
>>> ax.set_ylim(-0.5, 0.5) |
|
>>> ax.set_xlim(0, xmax) |
|
>>> ax.legend(ncol=2, bbox_to_anchor=(1., 0.75)) |
|
>>> plt.tight_layout() |
|
>>> plt.show() |
|
""" |
|
if not isscalar(nt) or (floor(nt) != nt) or (nt <= 0): |
|
raise ValueError("Arguments must be scalar positive integer.") |
|
kf = 2 |
|
kc = not complex |
|
return _specfun.cyzo(nt, kf, kc) |
|
|
|
|
|
def _bessel_diff_formula(v, z, n, L, phase): |
|
|
|
|
|
|
|
|
|
v = asarray(v) |
|
p = 1.0 |
|
s = L(v-n, z) |
|
for i in range(1, n+1): |
|
p = phase * (p * (n-i+1)) / i |
|
s += p*L(v-n + i*2, z) |
|
return s / (2.**n) |
|
|
|
|
|
def jvp(v, z, n=1): |
|
"""Compute derivatives of Bessel functions of the first kind. |
|
|
|
Compute the nth derivative of the Bessel function `Jv` with |
|
respect to `z`. |
|
|
|
Parameters |
|
---------- |
|
v : array_like or float |
|
Order of Bessel function |
|
z : complex |
|
Argument at which to evaluate the derivative; can be real or |
|
complex. |
|
n : int, default 1 |
|
Order of derivative. For 0 returns the Bessel function `jv` itself. |
|
|
|
Returns |
|
------- |
|
scalar or ndarray |
|
Values of the derivative of the Bessel function. |
|
|
|
Notes |
|
----- |
|
The derivative is computed using the relation DLFM 10.6.7 [2]_. |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996, chapter 5. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
.. [2] NIST Digital Library of Mathematical Functions. |
|
https://dlmf.nist.gov/10.6.E7 |
|
|
|
Examples |
|
-------- |
|
|
|
Compute the Bessel function of the first kind of order 0 and |
|
its first two derivatives at 1. |
|
|
|
>>> from scipy.special import jvp |
|
>>> jvp(0, 1, 0), jvp(0, 1, 1), jvp(0, 1, 2) |
|
(0.7651976865579666, -0.44005058574493355, -0.3251471008130331) |
|
|
|
Compute the first derivative of the Bessel function of the first |
|
kind for several orders at 1 by providing an array for `v`. |
|
|
|
>>> jvp([0, 1, 2], 1, 1) |
|
array([-0.44005059, 0.3251471 , 0.21024362]) |
|
|
|
Compute the first derivative of the Bessel function of the first |
|
kind of order 0 at several points by providing an array for `z`. |
|
|
|
>>> import numpy as np |
|
>>> points = np.array([0., 1.5, 3.]) |
|
>>> jvp(0, points, 1) |
|
array([-0. , -0.55793651, -0.33905896]) |
|
|
|
Plot the Bessel function of the first kind of order 1 and its |
|
first three derivatives. |
|
|
|
>>> import matplotlib.pyplot as plt |
|
>>> x = np.linspace(-10, 10, 1000) |
|
>>> fig, ax = plt.subplots() |
|
>>> ax.plot(x, jvp(1, x, 0), label=r"$J_1$") |
|
>>> ax.plot(x, jvp(1, x, 1), label=r"$J_1'$") |
|
>>> ax.plot(x, jvp(1, x, 2), label=r"$J_1''$") |
|
>>> ax.plot(x, jvp(1, x, 3), label=r"$J_1'''$") |
|
>>> plt.legend() |
|
>>> plt.show() |
|
""" |
|
n = _nonneg_int_or_fail(n, 'n') |
|
if n == 0: |
|
return jv(v, z) |
|
else: |
|
return _bessel_diff_formula(v, z, n, jv, -1) |
|
|
|
|
|
def yvp(v, z, n=1): |
|
"""Compute derivatives of Bessel functions of the second kind. |
|
|
|
Compute the nth derivative of the Bessel function `Yv` with |
|
respect to `z`. |
|
|
|
Parameters |
|
---------- |
|
v : array_like of float |
|
Order of Bessel function |
|
z : complex |
|
Argument at which to evaluate the derivative |
|
n : int, default 1 |
|
Order of derivative. For 0 returns the BEssel function `yv` |
|
|
|
Returns |
|
------- |
|
scalar or ndarray |
|
nth derivative of the Bessel function. |
|
|
|
See Also |
|
-------- |
|
yv : Bessel functions of the second kind |
|
|
|
Notes |
|
----- |
|
The derivative is computed using the relation DLFM 10.6.7 [2]_. |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996, chapter 5. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
.. [2] NIST Digital Library of Mathematical Functions. |
|
https://dlmf.nist.gov/10.6.E7 |
|
|
|
Examples |
|
-------- |
|
Compute the Bessel function of the second kind of order 0 and |
|
its first two derivatives at 1. |
|
|
|
>>> from scipy.special import yvp |
|
>>> yvp(0, 1, 0), yvp(0, 1, 1), yvp(0, 1, 2) |
|
(0.088256964215677, 0.7812128213002889, -0.8694697855159659) |
|
|
|
Compute the first derivative of the Bessel function of the second |
|
kind for several orders at 1 by providing an array for `v`. |
|
|
|
>>> yvp([0, 1, 2], 1, 1) |
|
array([0.78121282, 0.86946979, 2.52015239]) |
|
|
|
Compute the first derivative of the Bessel function of the |
|
second kind of order 0 at several points by providing an array for `z`. |
|
|
|
>>> import numpy as np |
|
>>> points = np.array([0.5, 1.5, 3.]) |
|
>>> yvp(0, points, 1) |
|
array([ 1.47147239, 0.41230863, -0.32467442]) |
|
|
|
Plot the Bessel function of the second kind of order 1 and its |
|
first three derivatives. |
|
|
|
>>> import matplotlib.pyplot as plt |
|
>>> x = np.linspace(0, 5, 1000) |
|
>>> x[0] += 1e-15 |
|
>>> fig, ax = plt.subplots() |
|
>>> ax.plot(x, yvp(1, x, 0), label=r"$Y_1$") |
|
>>> ax.plot(x, yvp(1, x, 1), label=r"$Y_1'$") |
|
>>> ax.plot(x, yvp(1, x, 2), label=r"$Y_1''$") |
|
>>> ax.plot(x, yvp(1, x, 3), label=r"$Y_1'''$") |
|
>>> ax.set_ylim(-10, 10) |
|
>>> plt.legend() |
|
>>> plt.show() |
|
""" |
|
n = _nonneg_int_or_fail(n, 'n') |
|
if n == 0: |
|
return yv(v, z) |
|
else: |
|
return _bessel_diff_formula(v, z, n, yv, -1) |
|
|
|
|
|
def kvp(v, z, n=1): |
|
"""Compute derivatives of real-order modified Bessel function Kv(z) |
|
|
|
Kv(z) is the modified Bessel function of the second kind. |
|
Derivative is calculated with respect to `z`. |
|
|
|
Parameters |
|
---------- |
|
v : array_like of float |
|
Order of Bessel function |
|
z : array_like of complex |
|
Argument at which to evaluate the derivative |
|
n : int, default 1 |
|
Order of derivative. For 0 returns the Bessel function `kv` itself. |
|
|
|
Returns |
|
------- |
|
out : ndarray |
|
The results |
|
|
|
See Also |
|
-------- |
|
kv |
|
|
|
Notes |
|
----- |
|
The derivative is computed using the relation DLFM 10.29.5 [2]_. |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996, chapter 6. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
.. [2] NIST Digital Library of Mathematical Functions. |
|
https://dlmf.nist.gov/10.29.E5 |
|
|
|
Examples |
|
-------- |
|
Compute the modified bessel function of the second kind of order 0 and |
|
its first two derivatives at 1. |
|
|
|
>>> from scipy.special import kvp |
|
>>> kvp(0, 1, 0), kvp(0, 1, 1), kvp(0, 1, 2) |
|
(0.42102443824070834, -0.6019072301972346, 1.0229316684379428) |
|
|
|
Compute the first derivative of the modified Bessel function of the second |
|
kind for several orders at 1 by providing an array for `v`. |
|
|
|
>>> kvp([0, 1, 2], 1, 1) |
|
array([-0.60190723, -1.02293167, -3.85158503]) |
|
|
|
Compute the first derivative of the modified Bessel function of the |
|
second kind of order 0 at several points by providing an array for `z`. |
|
|
|
>>> import numpy as np |
|
>>> points = np.array([0.5, 1.5, 3.]) |
|
>>> kvp(0, points, 1) |
|
array([-1.65644112, -0.2773878 , -0.04015643]) |
|
|
|
Plot the modified bessel function of the second kind and its |
|
first three derivatives. |
|
|
|
>>> import matplotlib.pyplot as plt |
|
>>> x = np.linspace(0, 5, 1000) |
|
>>> fig, ax = plt.subplots() |
|
>>> ax.plot(x, kvp(1, x, 0), label=r"$K_1$") |
|
>>> ax.plot(x, kvp(1, x, 1), label=r"$K_1'$") |
|
>>> ax.plot(x, kvp(1, x, 2), label=r"$K_1''$") |
|
>>> ax.plot(x, kvp(1, x, 3), label=r"$K_1'''$") |
|
>>> ax.set_ylim(-2.5, 2.5) |
|
>>> plt.legend() |
|
>>> plt.show() |
|
""" |
|
n = _nonneg_int_or_fail(n, 'n') |
|
if n == 0: |
|
return kv(v, z) |
|
else: |
|
return (-1)**n * _bessel_diff_formula(v, z, n, kv, 1) |
|
|
|
|
|
def ivp(v, z, n=1): |
|
"""Compute derivatives of modified Bessel functions of the first kind. |
|
|
|
Compute the nth derivative of the modified Bessel function `Iv` |
|
with respect to `z`. |
|
|
|
Parameters |
|
---------- |
|
v : array_like or float |
|
Order of Bessel function |
|
z : array_like |
|
Argument at which to evaluate the derivative; can be real or |
|
complex. |
|
n : int, default 1 |
|
Order of derivative. For 0, returns the Bessel function `iv` itself. |
|
|
|
Returns |
|
------- |
|
scalar or ndarray |
|
nth derivative of the modified Bessel function. |
|
|
|
See Also |
|
-------- |
|
iv |
|
|
|
Notes |
|
----- |
|
The derivative is computed using the relation DLFM 10.29.5 [2]_. |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996, chapter 6. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
.. [2] NIST Digital Library of Mathematical Functions. |
|
https://dlmf.nist.gov/10.29.E5 |
|
|
|
Examples |
|
-------- |
|
Compute the modified Bessel function of the first kind of order 0 and |
|
its first two derivatives at 1. |
|
|
|
>>> from scipy.special import ivp |
|
>>> ivp(0, 1, 0), ivp(0, 1, 1), ivp(0, 1, 2) |
|
(1.2660658777520084, 0.565159103992485, 0.7009067737595233) |
|
|
|
Compute the first derivative of the modified Bessel function of the first |
|
kind for several orders at 1 by providing an array for `v`. |
|
|
|
>>> ivp([0, 1, 2], 1, 1) |
|
array([0.5651591 , 0.70090677, 0.29366376]) |
|
|
|
Compute the first derivative of the modified Bessel function of the |
|
first kind of order 0 at several points by providing an array for `z`. |
|
|
|
>>> import numpy as np |
|
>>> points = np.array([0., 1.5, 3.]) |
|
>>> ivp(0, points, 1) |
|
array([0. , 0.98166643, 3.95337022]) |
|
|
|
Plot the modified Bessel function of the first kind of order 1 and its |
|
first three derivatives. |
|
|
|
>>> import matplotlib.pyplot as plt |
|
>>> x = np.linspace(-5, 5, 1000) |
|
>>> fig, ax = plt.subplots() |
|
>>> ax.plot(x, ivp(1, x, 0), label=r"$I_1$") |
|
>>> ax.plot(x, ivp(1, x, 1), label=r"$I_1'$") |
|
>>> ax.plot(x, ivp(1, x, 2), label=r"$I_1''$") |
|
>>> ax.plot(x, ivp(1, x, 3), label=r"$I_1'''$") |
|
>>> plt.legend() |
|
>>> plt.show() |
|
""" |
|
n = _nonneg_int_or_fail(n, 'n') |
|
if n == 0: |
|
return iv(v, z) |
|
else: |
|
return _bessel_diff_formula(v, z, n, iv, 1) |
|
|
|
|
|
def h1vp(v, z, n=1): |
|
"""Compute derivatives of Hankel function H1v(z) with respect to `z`. |
|
|
|
Parameters |
|
---------- |
|
v : array_like |
|
Order of Hankel function |
|
z : array_like |
|
Argument at which to evaluate the derivative. Can be real or |
|
complex. |
|
n : int, default 1 |
|
Order of derivative. For 0 returns the Hankel function `h1v` itself. |
|
|
|
Returns |
|
------- |
|
scalar or ndarray |
|
Values of the derivative of the Hankel function. |
|
|
|
See Also |
|
-------- |
|
hankel1 |
|
|
|
Notes |
|
----- |
|
The derivative is computed using the relation DLFM 10.6.7 [2]_. |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996, chapter 5. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
.. [2] NIST Digital Library of Mathematical Functions. |
|
https://dlmf.nist.gov/10.6.E7 |
|
|
|
Examples |
|
-------- |
|
Compute the Hankel function of the first kind of order 0 and |
|
its first two derivatives at 1. |
|
|
|
>>> from scipy.special import h1vp |
|
>>> h1vp(0, 1, 0), h1vp(0, 1, 1), h1vp(0, 1, 2) |
|
((0.7651976865579664+0.088256964215677j), |
|
(-0.44005058574493355+0.7812128213002889j), |
|
(-0.3251471008130329-0.8694697855159659j)) |
|
|
|
Compute the first derivative of the Hankel function of the first kind |
|
for several orders at 1 by providing an array for `v`. |
|
|
|
>>> h1vp([0, 1, 2], 1, 1) |
|
array([-0.44005059+0.78121282j, 0.3251471 +0.86946979j, |
|
0.21024362+2.52015239j]) |
|
|
|
Compute the first derivative of the Hankel function of the first kind |
|
of order 0 at several points by providing an array for `z`. |
|
|
|
>>> import numpy as np |
|
>>> points = np.array([0.5, 1.5, 3.]) |
|
>>> h1vp(0, points, 1) |
|
array([-0.24226846+1.47147239j, -0.55793651+0.41230863j, |
|
-0.33905896-0.32467442j]) |
|
""" |
|
n = _nonneg_int_or_fail(n, 'n') |
|
if n == 0: |
|
return hankel1(v, z) |
|
else: |
|
return _bessel_diff_formula(v, z, n, hankel1, -1) |
|
|
|
|
|
def h2vp(v, z, n=1): |
|
"""Compute derivatives of Hankel function H2v(z) with respect to `z`. |
|
|
|
Parameters |
|
---------- |
|
v : array_like |
|
Order of Hankel function |
|
z : array_like |
|
Argument at which to evaluate the derivative. Can be real or |
|
complex. |
|
n : int, default 1 |
|
Order of derivative. For 0 returns the Hankel function `h2v` itself. |
|
|
|
Returns |
|
------- |
|
scalar or ndarray |
|
Values of the derivative of the Hankel function. |
|
|
|
See Also |
|
-------- |
|
hankel2 |
|
|
|
Notes |
|
----- |
|
The derivative is computed using the relation DLFM 10.6.7 [2]_. |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996, chapter 5. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
.. [2] NIST Digital Library of Mathematical Functions. |
|
https://dlmf.nist.gov/10.6.E7 |
|
|
|
Examples |
|
-------- |
|
Compute the Hankel function of the second kind of order 0 and |
|
its first two derivatives at 1. |
|
|
|
>>> from scipy.special import h2vp |
|
>>> h2vp(0, 1, 0), h2vp(0, 1, 1), h2vp(0, 1, 2) |
|
((0.7651976865579664-0.088256964215677j), |
|
(-0.44005058574493355-0.7812128213002889j), |
|
(-0.3251471008130329+0.8694697855159659j)) |
|
|
|
Compute the first derivative of the Hankel function of the second kind |
|
for several orders at 1 by providing an array for `v`. |
|
|
|
>>> h2vp([0, 1, 2], 1, 1) |
|
array([-0.44005059-0.78121282j, 0.3251471 -0.86946979j, |
|
0.21024362-2.52015239j]) |
|
|
|
Compute the first derivative of the Hankel function of the second kind |
|
of order 0 at several points by providing an array for `z`. |
|
|
|
>>> import numpy as np |
|
>>> points = np.array([0.5, 1.5, 3.]) |
|
>>> h2vp(0, points, 1) |
|
array([-0.24226846-1.47147239j, -0.55793651-0.41230863j, |
|
-0.33905896+0.32467442j]) |
|
""" |
|
n = _nonneg_int_or_fail(n, 'n') |
|
if n == 0: |
|
return hankel2(v, z) |
|
else: |
|
return _bessel_diff_formula(v, z, n, hankel2, -1) |
|
|
|
|
|
def riccati_jn(n, x): |
|
r"""Compute Ricatti-Bessel function of the first kind and its derivative. |
|
|
|
The Ricatti-Bessel function of the first kind is defined as :math:`x |
|
j_n(x)`, where :math:`j_n` is the spherical Bessel function of the first |
|
kind of order :math:`n`. |
|
|
|
This function computes the value and first derivative of the |
|
Ricatti-Bessel function for all orders up to and including `n`. |
|
|
|
Parameters |
|
---------- |
|
n : int |
|
Maximum order of function to compute |
|
x : float |
|
Argument at which to evaluate |
|
|
|
Returns |
|
------- |
|
jn : ndarray |
|
Value of j0(x), ..., jn(x) |
|
jnp : ndarray |
|
First derivative j0'(x), ..., jn'(x) |
|
|
|
Notes |
|
----- |
|
The computation is carried out via backward recurrence, using the |
|
relation DLMF 10.51.1 [2]_. |
|
|
|
Wrapper for a Fortran routine created by Shanjie Zhang and Jianming |
|
Jin [1]_. |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
.. [2] NIST Digital Library of Mathematical Functions. |
|
https://dlmf.nist.gov/10.51.E1 |
|
|
|
""" |
|
if not (isscalar(n) and isscalar(x)): |
|
raise ValueError("arguments must be scalars.") |
|
n = _nonneg_int_or_fail(n, 'n', strict=False) |
|
if (n == 0): |
|
n1 = 1 |
|
else: |
|
n1 = n |
|
|
|
jn = np.empty((n1 + 1,), dtype=np.float64) |
|
jnp = np.empty_like(jn) |
|
|
|
_rctj(x, out=(jn, jnp)) |
|
return jn[:(n+1)], jnp[:(n+1)] |
|
|
|
|
|
def riccati_yn(n, x): |
|
"""Compute Ricatti-Bessel function of the second kind and its derivative. |
|
|
|
The Ricatti-Bessel function of the second kind is defined here as :math:`+x |
|
y_n(x)`, where :math:`y_n` is the spherical Bessel function of the second |
|
kind of order :math:`n`. *Note that this is in contrast to a common convention |
|
that includes a minus sign in the definition.* |
|
|
|
This function computes the value and first derivative of the function for |
|
all orders up to and including `n`. |
|
|
|
Parameters |
|
---------- |
|
n : int |
|
Maximum order of function to compute |
|
x : float |
|
Argument at which to evaluate |
|
|
|
Returns |
|
------- |
|
yn : ndarray |
|
Value of y0(x), ..., yn(x) |
|
ynp : ndarray |
|
First derivative y0'(x), ..., yn'(x) |
|
|
|
Notes |
|
----- |
|
The computation is carried out via ascending recurrence, using the |
|
relation DLMF 10.51.1 [2]_. |
|
|
|
Wrapper for a Fortran routine created by Shanjie Zhang and Jianming |
|
Jin [1]_. |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
.. [2] NIST Digital Library of Mathematical Functions. |
|
https://dlmf.nist.gov/10.51.E1 |
|
|
|
""" |
|
if not (isscalar(n) and isscalar(x)): |
|
raise ValueError("arguments must be scalars.") |
|
n = _nonneg_int_or_fail(n, 'n', strict=False) |
|
if (n == 0): |
|
n1 = 1 |
|
else: |
|
n1 = n |
|
|
|
yn = np.empty((n1 + 1,), dtype=np.float64) |
|
ynp = np.empty_like(yn) |
|
_rcty(x, out=(yn, ynp)) |
|
|
|
return yn[:(n+1)], ynp[:(n+1)] |
|
|
|
|
|
def erf_zeros(nt): |
|
"""Compute the first nt zero in the first quadrant, ordered by absolute value. |
|
|
|
Zeros in the other quadrants can be obtained by using the symmetries |
|
erf(-z) = erf(z) and erf(conj(z)) = conj(erf(z)). |
|
|
|
|
|
Parameters |
|
---------- |
|
nt : int |
|
The number of zeros to compute |
|
|
|
Returns |
|
------- |
|
The locations of the zeros of erf : ndarray (complex) |
|
Complex values at which zeros of erf(z) |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
Examples |
|
-------- |
|
>>> from scipy import special |
|
>>> special.erf_zeros(1) |
|
array([1.45061616+1.880943j]) |
|
|
|
Check that erf is (close to) zero for the value returned by erf_zeros |
|
|
|
>>> special.erf(special.erf_zeros(1)) |
|
array([4.95159469e-14-1.16407394e-16j]) |
|
|
|
""" |
|
if (floor(nt) != nt) or (nt <= 0) or not isscalar(nt): |
|
raise ValueError("Argument must be positive scalar integer.") |
|
return _specfun.cerzo(nt) |
|
|
|
|
|
def fresnelc_zeros(nt): |
|
"""Compute nt complex zeros of cosine Fresnel integral C(z). |
|
|
|
Parameters |
|
---------- |
|
nt : int |
|
Number of zeros to compute |
|
|
|
Returns |
|
------- |
|
fresnelc_zeros: ndarray |
|
Zeros of the cosine Fresnel integral |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
""" |
|
if (floor(nt) != nt) or (nt <= 0) or not isscalar(nt): |
|
raise ValueError("Argument must be positive scalar integer.") |
|
return _specfun.fcszo(1, nt) |
|
|
|
|
|
def fresnels_zeros(nt): |
|
"""Compute nt complex zeros of sine Fresnel integral S(z). |
|
|
|
Parameters |
|
---------- |
|
nt : int |
|
Number of zeros to compute |
|
|
|
Returns |
|
------- |
|
fresnels_zeros: ndarray |
|
Zeros of the sine Fresnel integral |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
""" |
|
if (floor(nt) != nt) or (nt <= 0) or not isscalar(nt): |
|
raise ValueError("Argument must be positive scalar integer.") |
|
return _specfun.fcszo(2, nt) |
|
|
|
|
|
def fresnel_zeros(nt): |
|
"""Compute nt complex zeros of sine and cosine Fresnel integrals S(z) and C(z). |
|
|
|
Parameters |
|
---------- |
|
nt : int |
|
Number of zeros to compute |
|
|
|
Returns |
|
------- |
|
zeros_sine: ndarray |
|
Zeros of the sine Fresnel integral |
|
zeros_cosine : ndarray |
|
Zeros of the cosine Fresnel integral |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
""" |
|
if (floor(nt) != nt) or (nt <= 0) or not isscalar(nt): |
|
raise ValueError("Argument must be positive scalar integer.") |
|
return _specfun.fcszo(2, nt), _specfun.fcszo(1, nt) |
|
|
|
|
|
def assoc_laguerre(x, n, k=0.0): |
|
"""Compute the generalized (associated) Laguerre polynomial of degree n and order k. |
|
|
|
The polynomial :math:`L^{(k)}_n(x)` is orthogonal over ``[0, inf)``, |
|
with weighting function ``exp(-x) * x**k`` with ``k > -1``. |
|
|
|
Parameters |
|
---------- |
|
x : float or ndarray |
|
Points where to evaluate the Laguerre polynomial |
|
n : int |
|
Degree of the Laguerre polynomial |
|
k : int |
|
Order of the Laguerre polynomial |
|
|
|
Returns |
|
------- |
|
assoc_laguerre: float or ndarray |
|
Associated laguerre polynomial values |
|
|
|
Notes |
|
----- |
|
`assoc_laguerre` is a simple wrapper around `eval_genlaguerre`, with |
|
reversed argument order ``(x, n, k=0.0) --> (n, k, x)``. |
|
|
|
""" |
|
return _ufuncs.eval_genlaguerre(n, k, x) |
|
|
|
|
|
digamma = psi |
|
|
|
|
|
def polygamma(n, x): |
|
r"""Polygamma functions. |
|
|
|
Defined as :math:`\psi^{(n)}(x)` where :math:`\psi` is the |
|
`digamma` function. See [dlmf]_ for details. |
|
|
|
Parameters |
|
---------- |
|
n : array_like |
|
The order of the derivative of the digamma function; must be |
|
integral |
|
x : array_like |
|
Real valued input |
|
|
|
Returns |
|
------- |
|
ndarray |
|
Function results |
|
|
|
See Also |
|
-------- |
|
digamma |
|
|
|
References |
|
---------- |
|
.. [dlmf] NIST, Digital Library of Mathematical Functions, |
|
https://dlmf.nist.gov/5.15 |
|
|
|
Examples |
|
-------- |
|
>>> from scipy import special |
|
>>> x = [2, 3, 25.5] |
|
>>> special.polygamma(1, x) |
|
array([ 0.64493407, 0.39493407, 0.03999467]) |
|
>>> special.polygamma(0, x) == special.psi(x) |
|
array([ True, True, True], dtype=bool) |
|
|
|
""" |
|
n, x = asarray(n), asarray(x) |
|
fac2 = (-1.0)**(n+1) * gamma(n+1.0) * zeta(n+1, x) |
|
return where(n == 0, psi(x), fac2) |
|
|
|
|
|
def mathieu_even_coef(m, q): |
|
r"""Fourier coefficients for even Mathieu and modified Mathieu functions. |
|
|
|
The Fourier series of the even solutions of the Mathieu differential |
|
equation are of the form |
|
|
|
.. math:: \mathrm{ce}_{2n}(z, q) = \sum_{k=0}^{\infty} A_{(2n)}^{(2k)} \cos 2kz |
|
|
|
.. math:: \mathrm{ce}_{2n+1}(z, q) = |
|
\sum_{k=0}^{\infty} A_{(2n+1)}^{(2k+1)} \cos (2k+1)z |
|
|
|
This function returns the coefficients :math:`A_{(2n)}^{(2k)}` for even |
|
input m=2n, and the coefficients :math:`A_{(2n+1)}^{(2k+1)}` for odd input |
|
m=2n+1. |
|
|
|
Parameters |
|
---------- |
|
m : int |
|
Order of Mathieu functions. Must be non-negative. |
|
q : float (>=0) |
|
Parameter of Mathieu functions. Must be non-negative. |
|
|
|
Returns |
|
------- |
|
Ak : ndarray |
|
Even or odd Fourier coefficients, corresponding to even or odd m. |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
.. [2] NIST Digital Library of Mathematical Functions |
|
https://dlmf.nist.gov/28.4#i |
|
|
|
""" |
|
if not (isscalar(m) and isscalar(q)): |
|
raise ValueError("m and q must be scalars.") |
|
if (q < 0): |
|
raise ValueError("q >=0") |
|
if (m != floor(m)) or (m < 0): |
|
raise ValueError("m must be an integer >=0.") |
|
|
|
if (q <= 1): |
|
qm = 7.5 + 56.1*sqrt(q) - 134.7*q + 90.7*sqrt(q)*q |
|
else: |
|
qm = 17.0 + 3.1*sqrt(q) - .126*q + .0037*sqrt(q)*q |
|
km = int(qm + 0.5*m) |
|
if km > 251: |
|
warnings.warn("Too many predicted coefficients.", RuntimeWarning, stacklevel=2) |
|
kd = 1 |
|
m = int(floor(m)) |
|
if m % 2: |
|
kd = 2 |
|
|
|
a = mathieu_a(m, q) |
|
fc = _specfun.fcoef(kd, m, q, a) |
|
return fc[:km] |
|
|
|
|
|
def mathieu_odd_coef(m, q): |
|
r"""Fourier coefficients for even Mathieu and modified Mathieu functions. |
|
|
|
The Fourier series of the odd solutions of the Mathieu differential |
|
equation are of the form |
|
|
|
.. math:: \mathrm{se}_{2n+1}(z, q) = |
|
\sum_{k=0}^{\infty} B_{(2n+1)}^{(2k+1)} \sin (2k+1)z |
|
|
|
.. math:: \mathrm{se}_{2n+2}(z, q) = |
|
\sum_{k=0}^{\infty} B_{(2n+2)}^{(2k+2)} \sin (2k+2)z |
|
|
|
This function returns the coefficients :math:`B_{(2n+2)}^{(2k+2)}` for even |
|
input m=2n+2, and the coefficients :math:`B_{(2n+1)}^{(2k+1)}` for odd |
|
input m=2n+1. |
|
|
|
Parameters |
|
---------- |
|
m : int |
|
Order of Mathieu functions. Must be non-negative. |
|
q : float (>=0) |
|
Parameter of Mathieu functions. Must be non-negative. |
|
|
|
Returns |
|
------- |
|
Bk : ndarray |
|
Even or odd Fourier coefficients, corresponding to even or odd m. |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
""" |
|
if not (isscalar(m) and isscalar(q)): |
|
raise ValueError("m and q must be scalars.") |
|
if (q < 0): |
|
raise ValueError("q >=0") |
|
if (m != floor(m)) or (m <= 0): |
|
raise ValueError("m must be an integer > 0") |
|
|
|
if (q <= 1): |
|
qm = 7.5 + 56.1*sqrt(q) - 134.7*q + 90.7*sqrt(q)*q |
|
else: |
|
qm = 17.0 + 3.1*sqrt(q) - .126*q + .0037*sqrt(q)*q |
|
km = int(qm + 0.5*m) |
|
if km > 251: |
|
warnings.warn("Too many predicted coefficients.", RuntimeWarning, stacklevel=2) |
|
kd = 4 |
|
m = int(floor(m)) |
|
if m % 2: |
|
kd = 3 |
|
|
|
b = mathieu_b(m, q) |
|
fc = _specfun.fcoef(kd, m, q, b) |
|
return fc[:km] |
|
|
|
|
|
@_deprecated(__DEPRECATION_MSG_1_15.format("lpmn", "assoc_legendre_p_all")) |
|
def lpmn(m, n, z): |
|
"""Sequence of associated Legendre functions of the first kind. |
|
|
|
Computes the associated Legendre function of the first kind of order m and |
|
degree n, ``Pmn(z)`` = :math:`P_n^m(z)`, and its derivative, ``Pmn'(z)``. |
|
Returns two arrays of size ``(m+1, n+1)`` containing ``Pmn(z)`` and |
|
``Pmn'(z)`` for all orders from ``0..m`` and degrees from ``0..n``. |
|
|
|
This function takes a real argument ``z``. For complex arguments ``z`` |
|
use clpmn instead. |
|
|
|
.. deprecated:: 1.15.0 |
|
This function is deprecated and will be removed in SciPy 1.17.0. |
|
Please `scipy.special.assoc_legendre_p_all` instead. |
|
|
|
Parameters |
|
---------- |
|
m : int |
|
``|m| <= n``; the order of the Legendre function. |
|
n : int |
|
where ``n >= 0``; the degree of the Legendre function. Often |
|
called ``l`` (lower case L) in descriptions of the associated |
|
Legendre function |
|
z : array_like |
|
Input value. |
|
|
|
Returns |
|
------- |
|
Pmn_z : (m+1, n+1) array |
|
Values for all orders 0..m and degrees 0..n |
|
Pmn_d_z : (m+1, n+1) array |
|
Derivatives for all orders 0..m and degrees 0..n |
|
|
|
See Also |
|
-------- |
|
clpmn: associated Legendre functions of the first kind for complex z |
|
|
|
Notes |
|
----- |
|
In the interval (-1, 1), Ferrer's function of the first kind is |
|
returned. The phase convention used for the intervals (1, inf) |
|
and (-inf, -1) is such that the result is always real. |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
.. [2] NIST Digital Library of Mathematical Functions |
|
https://dlmf.nist.gov/14.3 |
|
|
|
""" |
|
|
|
n = _nonneg_int_or_fail(n, 'n', strict=False) |
|
|
|
if (abs(m) > n): |
|
raise ValueError("m must be <= n.") |
|
|
|
if np.iscomplexobj(z): |
|
raise ValueError("Argument must be real. Use clpmn instead.") |
|
|
|
m, n = int(m), int(n) |
|
|
|
branch_cut = np.where(np.abs(z) <= 1, 2, 3) |
|
|
|
p, pd = assoc_legendre_p_all(n, abs(m), z, branch_cut=branch_cut, diff_n=1) |
|
p = np.swapaxes(p, 0, 1) |
|
pd = np.swapaxes(pd, 0, 1) |
|
|
|
if (m >= 0): |
|
p = p[:(m + 1)] |
|
pd = pd[:(m + 1)] |
|
else: |
|
p = np.insert(p[:(m - 1):-1], 0, p[0], axis=0) |
|
pd = np.insert(pd[:(m - 1):-1], 0, pd[0], axis=0) |
|
|
|
return p, pd |
|
|
|
|
|
@_deprecated(__DEPRECATION_MSG_1_15.format("clpmn", "assoc_legendre_p_all")) |
|
def clpmn(m, n, z, type=3): |
|
"""Associated Legendre function of the first kind for complex arguments. |
|
|
|
Computes the associated Legendre function of the first kind of order m and |
|
degree n, ``Pmn(z)`` = :math:`P_n^m(z)`, and its derivative, ``Pmn'(z)``. |
|
Returns two arrays of size ``(m+1, n+1)`` containing ``Pmn(z)`` and |
|
``Pmn'(z)`` for all orders from ``0..m`` and degrees from ``0..n``. |
|
|
|
.. deprecated:: 1.15.0 |
|
This function is deprecated and will be removed in SciPy 1.17.0. |
|
Please use `scipy.special.assoc_legendre_p_all` instead. |
|
|
|
Parameters |
|
---------- |
|
m : int |
|
``|m| <= n``; the order of the Legendre function. |
|
n : int |
|
where ``n >= 0``; the degree of the Legendre function. Often |
|
called ``l`` (lower case L) in descriptions of the associated |
|
Legendre function |
|
z : array_like, float or complex |
|
Input value. |
|
type : int, optional |
|
takes values 2 or 3 |
|
2: cut on the real axis ``|x| > 1`` |
|
3: cut on the real axis ``-1 < x < 1`` (default) |
|
|
|
Returns |
|
------- |
|
Pmn_z : (m+1, n+1) array |
|
Values for all orders ``0..m`` and degrees ``0..n`` |
|
Pmn_d_z : (m+1, n+1) array |
|
Derivatives for all orders ``0..m`` and degrees ``0..n`` |
|
|
|
See Also |
|
-------- |
|
lpmn: associated Legendre functions of the first kind for real z |
|
|
|
Notes |
|
----- |
|
By default, i.e. for ``type=3``, phase conventions are chosen according |
|
to [1]_ such that the function is analytic. The cut lies on the interval |
|
(-1, 1). Approaching the cut from above or below in general yields a phase |
|
factor with respect to Ferrer's function of the first kind |
|
(cf. `lpmn`). |
|
|
|
For ``type=2`` a cut at ``|x| > 1`` is chosen. Approaching the real values |
|
on the interval (-1, 1) in the complex plane yields Ferrer's function |
|
of the first kind. |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
.. [2] NIST Digital Library of Mathematical Functions |
|
https://dlmf.nist.gov/14.21 |
|
|
|
""" |
|
|
|
if (abs(m) > n): |
|
raise ValueError("m must be <= n.") |
|
|
|
if not (type == 2 or type == 3): |
|
raise ValueError("type must be either 2 or 3.") |
|
|
|
m, n = int(m), int(n) |
|
|
|
if not np.iscomplexobj(z): |
|
z = np.asarray(z, dtype=complex) |
|
|
|
out, out_jac = assoc_legendre_p_all(n, abs(m), z, branch_cut=type, diff_n=1) |
|
out = np.swapaxes(out, 0, 1) |
|
out_jac = np.swapaxes(out_jac, 0, 1) |
|
|
|
if (m >= 0): |
|
out = out[:(m + 1)] |
|
out_jac = out_jac[:(m + 1)] |
|
else: |
|
out = np.insert(out[:(m - 1):-1], 0, out[0], axis=0) |
|
out_jac = np.insert(out_jac[:(m - 1):-1], 0, out_jac[0], axis=0) |
|
|
|
return out, out_jac |
|
|
|
|
|
def lqmn(m, n, z): |
|
"""Sequence of associated Legendre functions of the second kind. |
|
|
|
Computes the associated Legendre function of the second kind of order m and |
|
degree n, ``Qmn(z)`` = :math:`Q_n^m(z)`, and its derivative, ``Qmn'(z)``. |
|
Returns two arrays of size ``(m+1, n+1)`` containing ``Qmn(z)`` and |
|
``Qmn'(z)`` for all orders from ``0..m`` and degrees from ``0..n``. |
|
|
|
Parameters |
|
---------- |
|
m : int |
|
``|m| <= n``; the order of the Legendre function. |
|
n : int |
|
where ``n >= 0``; the degree of the Legendre function. Often |
|
called ``l`` (lower case L) in descriptions of the associated |
|
Legendre function |
|
z : array_like, complex |
|
Input value. |
|
|
|
Returns |
|
------- |
|
Qmn_z : (m+1, n+1) array |
|
Values for all orders 0..m and degrees 0..n |
|
Qmn_d_z : (m+1, n+1) array |
|
Derivatives for all orders 0..m and degrees 0..n |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
""" |
|
if not isscalar(m) or (m < 0): |
|
raise ValueError("m must be a non-negative integer.") |
|
if not isscalar(n) or (n < 0): |
|
raise ValueError("n must be a non-negative integer.") |
|
|
|
m, n = int(m), int(n) |
|
|
|
mm = max(1, m) |
|
nn = max(1, n) |
|
|
|
z = np.asarray(z) |
|
if (not np.issubdtype(z.dtype, np.inexact)): |
|
z = z.astype(np.float64) |
|
|
|
if np.iscomplexobj(z): |
|
q = np.empty((mm + 1, nn + 1) + z.shape, dtype=np.complex128) |
|
else: |
|
q = np.empty((mm + 1, nn + 1) + z.shape, dtype=np.float64) |
|
qd = np.empty_like(q) |
|
if (z.ndim == 0): |
|
_lqmn(z, out=(q, qd)) |
|
else: |
|
|
|
_lqmn(z, |
|
out=(np.moveaxis(q, (0, 1), (-2, -1)), |
|
np.moveaxis(qd, (0, 1), (-2, -1)))) |
|
|
|
return q[:(m+1), :(n+1)], qd[:(m+1), :(n+1)] |
|
|
|
|
|
def bernoulli(n): |
|
"""Bernoulli numbers B0..Bn (inclusive). |
|
|
|
Parameters |
|
---------- |
|
n : int |
|
Indicated the number of terms in the Bernoulli series to generate. |
|
|
|
Returns |
|
------- |
|
ndarray |
|
The Bernoulli numbers ``[B(0), B(1), ..., B(n)]``. |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
.. [2] "Bernoulli number", Wikipedia, https://en.wikipedia.org/wiki/Bernoulli_number |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> from scipy.special import bernoulli, zeta |
|
>>> bernoulli(4) |
|
array([ 1. , -0.5 , 0.16666667, 0. , -0.03333333]) |
|
|
|
The Wikipedia article ([2]_) points out the relationship between the |
|
Bernoulli numbers and the zeta function, ``B_n^+ = -n * zeta(1 - n)`` |
|
for ``n > 0``: |
|
|
|
>>> n = np.arange(1, 5) |
|
>>> -n * zeta(1 - n) |
|
array([ 0.5 , 0.16666667, -0. , -0.03333333]) |
|
|
|
Note that, in the notation used in the wikipedia article, |
|
`bernoulli` computes ``B_n^-`` (i.e. it used the convention that |
|
``B_1`` is -1/2). The relation given above is for ``B_n^+``, so the |
|
sign of 0.5 does not match the output of ``bernoulli(4)``. |
|
|
|
""" |
|
if not isscalar(n) or (n < 0): |
|
raise ValueError("n must be a non-negative integer.") |
|
n = int(n) |
|
if (n < 2): |
|
n1 = 2 |
|
else: |
|
n1 = n |
|
return _specfun.bernob(int(n1))[:(n+1)] |
|
|
|
|
|
def euler(n): |
|
"""Euler numbers E(0), E(1), ..., E(n). |
|
|
|
The Euler numbers [1]_ are also known as the secant numbers. |
|
|
|
Because ``euler(n)`` returns floating point values, it does not give |
|
exact values for large `n`. The first inexact value is E(22). |
|
|
|
Parameters |
|
---------- |
|
n : int |
|
The highest index of the Euler number to be returned. |
|
|
|
Returns |
|
------- |
|
ndarray |
|
The Euler numbers [E(0), E(1), ..., E(n)]. |
|
The odd Euler numbers, which are all zero, are included. |
|
|
|
References |
|
---------- |
|
.. [1] Sequence A122045, The On-Line Encyclopedia of Integer Sequences, |
|
https://oeis.org/A122045 |
|
.. [2] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> from scipy.special import euler |
|
>>> euler(6) |
|
array([ 1., 0., -1., 0., 5., 0., -61.]) |
|
|
|
>>> euler(13).astype(np.int64) |
|
array([ 1, 0, -1, 0, 5, 0, -61, |
|
0, 1385, 0, -50521, 0, 2702765, 0]) |
|
|
|
>>> euler(22)[-1] # Exact value of E(22) is -69348874393137901. |
|
-69348874393137976.0 |
|
|
|
""" |
|
if not isscalar(n) or (n < 0): |
|
raise ValueError("n must be a non-negative integer.") |
|
n = int(n) |
|
if (n < 2): |
|
n1 = 2 |
|
else: |
|
n1 = n |
|
return _specfun.eulerb(n1)[:(n+1)] |
|
|
|
|
|
@_deprecated(__DEPRECATION_MSG_1_15.format("lpn", "legendre_p_all")) |
|
def lpn(n, z): |
|
"""Legendre function of the first kind. |
|
|
|
Compute sequence of Legendre functions of the first kind (polynomials), |
|
Pn(z) and derivatives for all degrees from 0 to n (inclusive). |
|
|
|
See also special.legendre for polynomial class. |
|
|
|
.. deprecated:: 1.15.0 |
|
This function is deprecated and will be removed in SciPy 1.17.0. |
|
Please use `scipy.special.legendre_p_all` instead. |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
""" |
|
|
|
return legendre_p_all(n, z, diff_n=1) |
|
|
|
|
|
def lqn(n, z): |
|
"""Legendre function of the second kind. |
|
|
|
Compute sequence of Legendre functions of the second kind, Qn(z) and |
|
derivatives for all degrees from 0 to n (inclusive). |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
""" |
|
n = _nonneg_int_or_fail(n, 'n', strict=False) |
|
if (n < 1): |
|
n1 = 1 |
|
else: |
|
n1 = n |
|
|
|
z = np.asarray(z) |
|
if (not np.issubdtype(z.dtype, np.inexact)): |
|
z = z.astype(float) |
|
|
|
if np.iscomplexobj(z): |
|
qn = np.empty((n1 + 1,) + z.shape, dtype=np.complex128) |
|
else: |
|
qn = np.empty((n1 + 1,) + z.shape, dtype=np.float64) |
|
qd = np.empty_like(qn) |
|
if (z.ndim == 0): |
|
_lqn(z, out=(qn, qd)) |
|
else: |
|
|
|
_lqn(z, |
|
out=(np.moveaxis(qn, 0, -1), |
|
np.moveaxis(qd, 0, -1))) |
|
|
|
return qn[:(n+1)], qd[:(n+1)] |
|
|
|
|
|
def ai_zeros(nt): |
|
""" |
|
Compute `nt` zeros and values of the Airy function Ai and its derivative. |
|
|
|
Computes the first `nt` zeros, `a`, of the Airy function Ai(x); |
|
first `nt` zeros, `ap`, of the derivative of the Airy function Ai'(x); |
|
the corresponding values Ai(a'); |
|
and the corresponding values Ai'(a). |
|
|
|
Parameters |
|
---------- |
|
nt : int |
|
Number of zeros to compute |
|
|
|
Returns |
|
------- |
|
a : ndarray |
|
First `nt` zeros of Ai(x) |
|
ap : ndarray |
|
First `nt` zeros of Ai'(x) |
|
ai : ndarray |
|
Values of Ai(x) evaluated at first `nt` zeros of Ai'(x) |
|
aip : ndarray |
|
Values of Ai'(x) evaluated at first `nt` zeros of Ai(x) |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
Examples |
|
-------- |
|
>>> from scipy import special |
|
>>> a, ap, ai, aip = special.ai_zeros(3) |
|
>>> a |
|
array([-2.33810741, -4.08794944, -5.52055983]) |
|
>>> ap |
|
array([-1.01879297, -3.24819758, -4.82009921]) |
|
>>> ai |
|
array([ 0.53565666, -0.41901548, 0.38040647]) |
|
>>> aip |
|
array([ 0.70121082, -0.80311137, 0.86520403]) |
|
|
|
""" |
|
kf = 1 |
|
if not isscalar(nt) or (floor(nt) != nt) or (nt <= 0): |
|
raise ValueError("nt must be a positive integer scalar.") |
|
return _specfun.airyzo(nt, kf) |
|
|
|
|
|
def bi_zeros(nt): |
|
""" |
|
Compute `nt` zeros and values of the Airy function Bi and its derivative. |
|
|
|
Computes the first `nt` zeros, b, of the Airy function Bi(x); |
|
first `nt` zeros, b', of the derivative of the Airy function Bi'(x); |
|
the corresponding values Bi(b'); |
|
and the corresponding values Bi'(b). |
|
|
|
Parameters |
|
---------- |
|
nt : int |
|
Number of zeros to compute |
|
|
|
Returns |
|
------- |
|
b : ndarray |
|
First `nt` zeros of Bi(x) |
|
bp : ndarray |
|
First `nt` zeros of Bi'(x) |
|
bi : ndarray |
|
Values of Bi(x) evaluated at first `nt` zeros of Bi'(x) |
|
bip : ndarray |
|
Values of Bi'(x) evaluated at first `nt` zeros of Bi(x) |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
Examples |
|
-------- |
|
>>> from scipy import special |
|
>>> b, bp, bi, bip = special.bi_zeros(3) |
|
>>> b |
|
array([-1.17371322, -3.2710933 , -4.83073784]) |
|
>>> bp |
|
array([-2.29443968, -4.07315509, -5.51239573]) |
|
>>> bi |
|
array([-0.45494438, 0.39652284, -0.36796916]) |
|
>>> bip |
|
array([ 0.60195789, -0.76031014, 0.83699101]) |
|
|
|
""" |
|
kf = 2 |
|
if not isscalar(nt) or (floor(nt) != nt) or (nt <= 0): |
|
raise ValueError("nt must be a positive integer scalar.") |
|
return _specfun.airyzo(nt, kf) |
|
|
|
|
|
def lmbda(v, x): |
|
r"""Jahnke-Emden Lambda function, Lambdav(x). |
|
|
|
This function is defined as [2]_, |
|
|
|
.. math:: \Lambda_v(x) = \Gamma(v+1) \frac{J_v(x)}{(x/2)^v}, |
|
|
|
where :math:`\Gamma` is the gamma function and :math:`J_v` is the |
|
Bessel function of the first kind. |
|
|
|
Parameters |
|
---------- |
|
v : float |
|
Order of the Lambda function |
|
x : float |
|
Value at which to evaluate the function and derivatives |
|
|
|
Returns |
|
------- |
|
vl : ndarray |
|
Values of Lambda_vi(x), for vi=v-int(v), vi=1+v-int(v), ..., vi=v. |
|
dl : ndarray |
|
Derivatives Lambda_vi'(x), for vi=v-int(v), vi=1+v-int(v), ..., vi=v. |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
.. [2] Jahnke, E. and Emde, F. "Tables of Functions with Formulae and |
|
Curves" (4th ed.), Dover, 1945 |
|
""" |
|
if not (isscalar(v) and isscalar(x)): |
|
raise ValueError("arguments must be scalars.") |
|
if (v < 0): |
|
raise ValueError("argument must be > 0.") |
|
n = int(v) |
|
v0 = v - n |
|
if (n < 1): |
|
n1 = 1 |
|
else: |
|
n1 = n |
|
v1 = n1 + v0 |
|
if (v != floor(v)): |
|
vm, vl, dl = _specfun.lamv(v1, x) |
|
else: |
|
vm, vl, dl = _specfun.lamn(v1, x) |
|
return vl[:(n+1)], dl[:(n+1)] |
|
|
|
|
|
def pbdv_seq(v, x): |
|
"""Parabolic cylinder functions Dv(x) and derivatives. |
|
|
|
Parameters |
|
---------- |
|
v : float |
|
Order of the parabolic cylinder function |
|
x : float |
|
Value at which to evaluate the function and derivatives |
|
|
|
Returns |
|
------- |
|
dv : ndarray |
|
Values of D_vi(x), for vi=v-int(v), vi=1+v-int(v), ..., vi=v. |
|
dp : ndarray |
|
Derivatives D_vi'(x), for vi=v-int(v), vi=1+v-int(v), ..., vi=v. |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996, chapter 13. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
""" |
|
if not (isscalar(v) and isscalar(x)): |
|
raise ValueError("arguments must be scalars.") |
|
n = int(v) |
|
v0 = v-n |
|
if (n < 1): |
|
n1 = 1 |
|
else: |
|
n1 = n |
|
v1 = n1 + v0 |
|
dv, dp, pdf, pdd = _specfun.pbdv(v1, x) |
|
return dv[:n1+1], dp[:n1+1] |
|
|
|
|
|
def pbvv_seq(v, x): |
|
"""Parabolic cylinder functions Vv(x) and derivatives. |
|
|
|
Parameters |
|
---------- |
|
v : float |
|
Order of the parabolic cylinder function |
|
x : float |
|
Value at which to evaluate the function and derivatives |
|
|
|
Returns |
|
------- |
|
dv : ndarray |
|
Values of V_vi(x), for vi=v-int(v), vi=1+v-int(v), ..., vi=v. |
|
dp : ndarray |
|
Derivatives V_vi'(x), for vi=v-int(v), vi=1+v-int(v), ..., vi=v. |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996, chapter 13. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
""" |
|
if not (isscalar(v) and isscalar(x)): |
|
raise ValueError("arguments must be scalars.") |
|
n = int(v) |
|
v0 = v-n |
|
if (n <= 1): |
|
n1 = 1 |
|
else: |
|
n1 = n |
|
v1 = n1 + v0 |
|
dv, dp, pdf, pdd = _specfun.pbvv(v1, x) |
|
return dv[:n1+1], dp[:n1+1] |
|
|
|
|
|
def pbdn_seq(n, z): |
|
"""Parabolic cylinder functions Dn(z) and derivatives. |
|
|
|
Parameters |
|
---------- |
|
n : int |
|
Order of the parabolic cylinder function |
|
z : complex |
|
Value at which to evaluate the function and derivatives |
|
|
|
Returns |
|
------- |
|
dv : ndarray |
|
Values of D_i(z), for i=0, ..., i=n. |
|
dp : ndarray |
|
Derivatives D_i'(z), for i=0, ..., i=n. |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996, chapter 13. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
""" |
|
if not (isscalar(n) and isscalar(z)): |
|
raise ValueError("arguments must be scalars.") |
|
if (floor(n) != n): |
|
raise ValueError("n must be an integer.") |
|
if (abs(n) <= 1): |
|
n1 = 1 |
|
else: |
|
n1 = n |
|
cpb, cpd = _specfun.cpbdn(n1, z) |
|
return cpb[:n1+1], cpd[:n1+1] |
|
|
|
|
|
def ber_zeros(nt): |
|
"""Compute nt zeros of the Kelvin function ber. |
|
|
|
Parameters |
|
---------- |
|
nt : int |
|
Number of zeros to compute. Must be positive. |
|
|
|
Returns |
|
------- |
|
ndarray |
|
First `nt` zeros of the Kelvin function. |
|
|
|
See Also |
|
-------- |
|
ber |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
""" |
|
if not isscalar(nt) or (floor(nt) != nt) or (nt <= 0): |
|
raise ValueError("nt must be positive integer scalar.") |
|
return _specfun.klvnzo(nt, 1) |
|
|
|
|
|
def bei_zeros(nt): |
|
"""Compute nt zeros of the Kelvin function bei. |
|
|
|
Parameters |
|
---------- |
|
nt : int |
|
Number of zeros to compute. Must be positive. |
|
|
|
Returns |
|
------- |
|
ndarray |
|
First `nt` zeros of the Kelvin function. |
|
|
|
See Also |
|
-------- |
|
bei |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
""" |
|
if not isscalar(nt) or (floor(nt) != nt) or (nt <= 0): |
|
raise ValueError("nt must be positive integer scalar.") |
|
return _specfun.klvnzo(nt, 2) |
|
|
|
|
|
def ker_zeros(nt): |
|
"""Compute nt zeros of the Kelvin function ker. |
|
|
|
Parameters |
|
---------- |
|
nt : int |
|
Number of zeros to compute. Must be positive. |
|
|
|
Returns |
|
------- |
|
ndarray |
|
First `nt` zeros of the Kelvin function. |
|
|
|
See Also |
|
-------- |
|
ker |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
""" |
|
if not isscalar(nt) or (floor(nt) != nt) or (nt <= 0): |
|
raise ValueError("nt must be positive integer scalar.") |
|
return _specfun.klvnzo(nt, 3) |
|
|
|
|
|
def kei_zeros(nt): |
|
"""Compute nt zeros of the Kelvin function kei. |
|
|
|
Parameters |
|
---------- |
|
nt : int |
|
Number of zeros to compute. Must be positive. |
|
|
|
Returns |
|
------- |
|
ndarray |
|
First `nt` zeros of the Kelvin function. |
|
|
|
See Also |
|
-------- |
|
kei |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
""" |
|
if not isscalar(nt) or (floor(nt) != nt) or (nt <= 0): |
|
raise ValueError("nt must be positive integer scalar.") |
|
return _specfun.klvnzo(nt, 4) |
|
|
|
|
|
def berp_zeros(nt): |
|
"""Compute nt zeros of the derivative of the Kelvin function ber. |
|
|
|
Parameters |
|
---------- |
|
nt : int |
|
Number of zeros to compute. Must be positive. |
|
|
|
Returns |
|
------- |
|
ndarray |
|
First `nt` zeros of the derivative of the Kelvin function. |
|
|
|
See Also |
|
-------- |
|
ber, berp |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
|
|
Examples |
|
-------- |
|
Compute the first 5 zeros of the derivative of the Kelvin function. |
|
|
|
>>> from scipy.special import berp_zeros |
|
>>> berp_zeros(5) |
|
array([ 6.03871081, 10.51364251, 14.96844542, 19.41757493, 23.86430432]) |
|
|
|
""" |
|
if not isscalar(nt) or (floor(nt) != nt) or (nt <= 0): |
|
raise ValueError("nt must be positive integer scalar.") |
|
return _specfun.klvnzo(nt, 5) |
|
|
|
|
|
def beip_zeros(nt): |
|
"""Compute nt zeros of the derivative of the Kelvin function bei. |
|
|
|
Parameters |
|
---------- |
|
nt : int |
|
Number of zeros to compute. Must be positive. |
|
|
|
Returns |
|
------- |
|
ndarray |
|
First `nt` zeros of the derivative of the Kelvin function. |
|
|
|
See Also |
|
-------- |
|
bei, beip |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
""" |
|
if not isscalar(nt) or (floor(nt) != nt) or (nt <= 0): |
|
raise ValueError("nt must be positive integer scalar.") |
|
return _specfun.klvnzo(nt, 6) |
|
|
|
|
|
def kerp_zeros(nt): |
|
"""Compute nt zeros of the derivative of the Kelvin function ker. |
|
|
|
Parameters |
|
---------- |
|
nt : int |
|
Number of zeros to compute. Must be positive. |
|
|
|
Returns |
|
------- |
|
ndarray |
|
First `nt` zeros of the derivative of the Kelvin function. |
|
|
|
See Also |
|
-------- |
|
ker, kerp |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
""" |
|
if not isscalar(nt) or (floor(nt) != nt) or (nt <= 0): |
|
raise ValueError("nt must be positive integer scalar.") |
|
return _specfun.klvnzo(nt, 7) |
|
|
|
|
|
def keip_zeros(nt): |
|
"""Compute nt zeros of the derivative of the Kelvin function kei. |
|
|
|
Parameters |
|
---------- |
|
nt : int |
|
Number of zeros to compute. Must be positive. |
|
|
|
Returns |
|
------- |
|
ndarray |
|
First `nt` zeros of the derivative of the Kelvin function. |
|
|
|
See Also |
|
-------- |
|
kei, keip |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
""" |
|
if not isscalar(nt) or (floor(nt) != nt) or (nt <= 0): |
|
raise ValueError("nt must be positive integer scalar.") |
|
return _specfun.klvnzo(nt, 8) |
|
|
|
|
|
def kelvin_zeros(nt): |
|
"""Compute nt zeros of all Kelvin functions. |
|
|
|
Returned in a length-8 tuple of arrays of length nt. The tuple contains |
|
the arrays of zeros of (ber, bei, ker, kei, ber', bei', ker', kei'). |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
""" |
|
if not isscalar(nt) or (floor(nt) != nt) or (nt <= 0): |
|
raise ValueError("nt must be positive integer scalar.") |
|
return (_specfun.klvnzo(nt, 1), |
|
_specfun.klvnzo(nt, 2), |
|
_specfun.klvnzo(nt, 3), |
|
_specfun.klvnzo(nt, 4), |
|
_specfun.klvnzo(nt, 5), |
|
_specfun.klvnzo(nt, 6), |
|
_specfun.klvnzo(nt, 7), |
|
_specfun.klvnzo(nt, 8)) |
|
|
|
|
|
def pro_cv_seq(m, n, c): |
|
"""Characteristic values for prolate spheroidal wave functions. |
|
|
|
Compute a sequence of characteristic values for the prolate |
|
spheroidal wave functions for mode m and n'=m..n and spheroidal |
|
parameter c. |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
""" |
|
if not (isscalar(m) and isscalar(n) and isscalar(c)): |
|
raise ValueError("Arguments must be scalars.") |
|
if (n != floor(n)) or (m != floor(m)): |
|
raise ValueError("Modes must be integers.") |
|
if (n-m > 199): |
|
raise ValueError("Difference between n and m is too large.") |
|
maxL = n-m+1 |
|
return _specfun.segv(m, n, c, 1)[1][:maxL] |
|
|
|
|
|
def obl_cv_seq(m, n, c): |
|
"""Characteristic values for oblate spheroidal wave functions. |
|
|
|
Compute a sequence of characteristic values for the oblate |
|
spheroidal wave functions for mode m and n'=m..n and spheroidal |
|
parameter c. |
|
|
|
References |
|
---------- |
|
.. [1] Zhang, Shanjie and Jin, Jianming. "Computation of Special |
|
Functions", John Wiley and Sons, 1996. |
|
https://people.sc.fsu.edu/~jburkardt/f77_src/special_functions/special_functions.html |
|
|
|
""" |
|
if not (isscalar(m) and isscalar(n) and isscalar(c)): |
|
raise ValueError("Arguments must be scalars.") |
|
if (n != floor(n)) or (m != floor(m)): |
|
raise ValueError("Modes must be integers.") |
|
if (n-m > 199): |
|
raise ValueError("Difference between n and m is too large.") |
|
maxL = n-m+1 |
|
return _specfun.segv(m, n, c, -1)[1][:maxL] |
|
|
|
|
|
def comb(N, k, *, exact=False, repetition=False): |
|
"""The number of combinations of N things taken k at a time. |
|
|
|
This is often expressed as "N choose k". |
|
|
|
Parameters |
|
---------- |
|
N : int, ndarray |
|
Number of things. |
|
k : int, ndarray |
|
Number of elements taken. |
|
exact : bool, optional |
|
For integers, if `exact` is False, then floating point precision is |
|
used, otherwise the result is computed exactly. |
|
|
|
.. deprecated:: 1.14.0 |
|
``exact=True`` is deprecated for non-integer `N` and `k` and will raise an |
|
error in SciPy 1.16.0 |
|
repetition : bool, optional |
|
If `repetition` is True, then the number of combinations with |
|
repetition is computed. |
|
|
|
Returns |
|
------- |
|
val : int, float, ndarray |
|
The total number of combinations. |
|
|
|
See Also |
|
-------- |
|
binom : Binomial coefficient considered as a function of two real |
|
variables. |
|
|
|
Notes |
|
----- |
|
- Array arguments accepted only for exact=False case. |
|
- If N < 0, or k < 0, then 0 is returned. |
|
- If k > N and repetition=False, then 0 is returned. |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> from scipy.special import comb |
|
>>> k = np.array([3, 4]) |
|
>>> n = np.array([10, 10]) |
|
>>> comb(n, k, exact=False) |
|
array([ 120., 210.]) |
|
>>> comb(10, 3, exact=True) |
|
120 |
|
>>> comb(10, 3, exact=True, repetition=True) |
|
220 |
|
|
|
""" |
|
if repetition: |
|
return comb(N + k - 1, k, exact=exact) |
|
if exact: |
|
if int(N) == N and int(k) == k: |
|
|
|
return _comb_int(N, k) |
|
|
|
|
|
msg = ("`exact=True` is deprecated for non-integer `N` and `k` and will raise " |
|
"an error in SciPy 1.16.0") |
|
warnings.warn(msg, DeprecationWarning, stacklevel=2) |
|
return comb(N, k) |
|
else: |
|
k, N = asarray(k), asarray(N) |
|
cond = (k <= N) & (N >= 0) & (k >= 0) |
|
vals = binom(N, k) |
|
if isinstance(vals, np.ndarray): |
|
vals[~cond] = 0 |
|
elif not cond: |
|
vals = np.float64(0) |
|
return vals |
|
|
|
|
|
def perm(N, k, exact=False): |
|
"""Permutations of N things taken k at a time, i.e., k-permutations of N. |
|
|
|
It's also known as "partial permutations". |
|
|
|
Parameters |
|
---------- |
|
N : int, ndarray |
|
Number of things. |
|
k : int, ndarray |
|
Number of elements taken. |
|
exact : bool, optional |
|
If ``True``, calculate the answer exactly using long integer arithmetic (`N` |
|
and `k` must be scalar integers). If ``False``, a floating point approximation |
|
is calculated (more rapidly) using `poch`. Default is ``False``. |
|
|
|
Returns |
|
------- |
|
val : int, ndarray |
|
The number of k-permutations of N. |
|
|
|
Notes |
|
----- |
|
- Array arguments accepted only for exact=False case. |
|
- If k > N, N < 0, or k < 0, then a 0 is returned. |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> from scipy.special import perm |
|
>>> k = np.array([3, 4]) |
|
>>> n = np.array([10, 10]) |
|
>>> perm(n, k) |
|
array([ 720., 5040.]) |
|
>>> perm(10, 3, exact=True) |
|
720 |
|
|
|
""" |
|
if exact: |
|
N = np.squeeze(N)[()] |
|
k = np.squeeze(k)[()] |
|
if not (isscalar(N) and isscalar(k)): |
|
raise ValueError("`N` and `k` must scalar integers be with `exact=True`.") |
|
|
|
floor_N, floor_k = int(N), int(k) |
|
non_integral = not (floor_N == N and floor_k == k) |
|
if (k > N) or (N < 0) or (k < 0): |
|
if non_integral: |
|
msg = ("Non-integer `N` and `k` with `exact=True` is deprecated and " |
|
"will raise an error in SciPy 1.16.0.") |
|
warnings.warn(msg, DeprecationWarning, stacklevel=2) |
|
return 0 |
|
if non_integral: |
|
raise ValueError("Non-integer `N` and `k` with `exact=True` is not " |
|
"supported.") |
|
val = 1 |
|
for i in range(floor_N - floor_k + 1, floor_N + 1): |
|
val *= i |
|
return val |
|
else: |
|
k, N = asarray(k), asarray(N) |
|
cond = (k <= N) & (N >= 0) & (k >= 0) |
|
vals = poch(N - k + 1, k) |
|
if isinstance(vals, np.ndarray): |
|
vals[~cond] = 0 |
|
elif not cond: |
|
vals = np.float64(0) |
|
return vals |
|
|
|
|
|
|
|
def _range_prod(lo, hi, k=1): |
|
""" |
|
Product of a range of numbers spaced k apart (from hi). |
|
|
|
For k=1, this returns the product of |
|
lo * (lo+1) * (lo+2) * ... * (hi-2) * (hi-1) * hi |
|
= hi! / (lo-1)! |
|
|
|
For k>1, it correspond to taking only every k'th number when |
|
counting down from hi - e.g. 18!!!! = _range_prod(1, 18, 4). |
|
|
|
Breaks into smaller products first for speed: |
|
_range_prod(2, 9) = ((2*3)*(4*5))*((6*7)*(8*9)) |
|
""" |
|
if lo == 1 and k == 1: |
|
return math.factorial(hi) |
|
|
|
if lo + k < hi: |
|
mid = (hi + lo) // 2 |
|
if k > 1: |
|
|
|
mid = mid - ((mid - hi) % k) |
|
return _range_prod(lo, mid, k) * _range_prod(mid + k, hi, k) |
|
elif lo + k == hi: |
|
return lo * hi |
|
else: |
|
return hi |
|
|
|
|
|
def _factorialx_array_exact(n, k=1): |
|
""" |
|
Exact computation of factorial for an array. |
|
|
|
The factorials are computed in incremental fashion, by taking |
|
the sorted unique values of n and multiplying the intervening |
|
numbers between the different unique values. |
|
|
|
In other words, the factorial for the largest input is only |
|
computed once, with each other result computed in the process. |
|
|
|
k > 1 corresponds to the multifactorial. |
|
""" |
|
un = np.unique(n) |
|
|
|
|
|
|
|
un = un[~np.isnan(un)] |
|
|
|
|
|
if np.isnan(n).any(): |
|
dt = float |
|
elif k in _FACTORIALK_LIMITS_64BITS.keys(): |
|
if un[-1] > _FACTORIALK_LIMITS_64BITS[k]: |
|
|
|
dt = object |
|
elif un[-1] > _FACTORIALK_LIMITS_32BITS[k]: |
|
|
|
dt = np.int64 |
|
else: |
|
dt = np.dtype("long") |
|
else: |
|
|
|
dt = object |
|
|
|
out = np.empty_like(n, dtype=dt) |
|
|
|
|
|
un = un[un > 1] |
|
out[n < 2] = 1 |
|
out[n < 0] = 0 |
|
|
|
|
|
|
|
|
|
for lane in range(0, k): |
|
ul = un[(un % k) == lane] if k > 1 else un |
|
if ul.size: |
|
|
|
|
|
val = _range_prod(1, int(ul[0]), k=k) |
|
out[n == ul[0]] = val |
|
for i in range(len(ul) - 1): |
|
|
|
|
|
prev = ul[i] |
|
current = ul[i + 1] |
|
|
|
|
|
|
|
val *= _range_prod(int(prev + 1), int(current), k=k) |
|
out[n == current] = val |
|
|
|
if np.isnan(n).any(): |
|
out = out.astype(np.float64) |
|
out[np.isnan(n)] = np.nan |
|
return out |
|
|
|
|
|
def _factorialx_array_approx(n, k, extend): |
|
""" |
|
Calculate approximation to multifactorial for array n and integer k. |
|
|
|
Ensure that values aren't calculated unnecessarily. |
|
""" |
|
if extend == "complex": |
|
return _factorialx_approx_core(n, k=k, extend=extend) |
|
|
|
|
|
result = zeros(n.shape) |
|
|
|
place(result, np.isnan(n), np.nan) |
|
|
|
cond = (n >= 0) |
|
n_to_compute = extract(cond, n) |
|
place(result, cond, _factorialx_approx_core(n_to_compute, k=k, extend=extend)) |
|
return result |
|
|
|
|
|
def _gamma1p(vals): |
|
""" |
|
returns gamma(n+1), though with NaN at -1 instead of inf, c.f. #21827 |
|
""" |
|
res = gamma(vals + 1) |
|
|
|
|
|
if isinstance(res, np.ndarray): |
|
if not _is_subdtype(vals.dtype, "c"): |
|
res[vals == -1] = np.nan |
|
elif np.isinf(res) and vals == -1: |
|
res = np.float64("nan") |
|
return res |
|
|
|
|
|
def _factorialx_approx_core(n, k, extend): |
|
""" |
|
Core approximation to multifactorial for array n and integer k. |
|
""" |
|
if k == 1: |
|
|
|
|
|
result = _gamma1p(n) |
|
if isinstance(n, np.ndarray): |
|
|
|
result = np.array(result) |
|
return result |
|
|
|
if extend == "complex": |
|
|
|
p_dtype = complex if (_is_subdtype(type(k), "c") or k < 0) else None |
|
with warnings.catch_warnings(): |
|
|
|
warnings.simplefilter("ignore", RuntimeWarning) |
|
|
|
result = np.power(k, n / k, dtype=p_dtype) * _gamma1p(n / k) |
|
result *= rgamma(1 / k + 1) / np.power(k, 1 / k, dtype=p_dtype) |
|
if isinstance(n, np.ndarray): |
|
|
|
result = np.array(result) |
|
return result |
|
|
|
|
|
n_mod_k = n % k |
|
|
|
|
|
if not isinstance(n, np.ndarray): |
|
return ( |
|
np.power(k, (n - n_mod_k) / k) |
|
* gamma(n / k + 1) / gamma(n_mod_k / k + 1) |
|
* max(n_mod_k, 1) |
|
) |
|
|
|
|
|
result = np.power(k, n / k) * gamma(n / k + 1) |
|
|
|
|
|
def corr(k, r): return np.power(k, -r / k) / gamma(r / k + 1) * r |
|
for r in np.unique(n_mod_k): |
|
if r == 0: |
|
continue |
|
|
|
result[n_mod_k == r] *= corr(k, int(r)) |
|
return result |
|
|
|
|
|
def _is_subdtype(dtype, dtypes): |
|
""" |
|
Shorthand for calculating whether dtype is subtype of some dtypes. |
|
|
|
Also allows specifying a list instead of just a single dtype. |
|
|
|
Additionaly, the most important supertypes from |
|
https://numpy.org/doc/stable/reference/arrays.scalars.html |
|
can optionally be specified using abbreviations as follows: |
|
"i": np.integer |
|
"f": np.floating |
|
"c": np.complexfloating |
|
"n": np.number (contains the other three) |
|
""" |
|
dtypes = dtypes if isinstance(dtypes, list) else [dtypes] |
|
|
|
mapping = { |
|
"i": np.integer, |
|
"f": np.floating, |
|
"c": np.complexfloating, |
|
"n": np.number |
|
} |
|
dtypes = [mapping.get(x, x) for x in dtypes] |
|
return any(np.issubdtype(dtype, dt) for dt in dtypes) |
|
|
|
|
|
def _factorialx_wrapper(fname, n, k, exact, extend): |
|
""" |
|
Shared implementation for factorial, factorial2 & factorialk. |
|
""" |
|
if extend not in ("zero", "complex"): |
|
raise ValueError( |
|
f"argument `extend` must be either 'zero' or 'complex', received: {extend}" |
|
) |
|
if exact and extend == "complex": |
|
raise ValueError("Incompatible options: `exact=True` and `extend='complex'`") |
|
|
|
msg_unsup = ( |
|
"Unsupported data type for {vname} in {fname}: {dtype}\n" |
|
) |
|
if fname == "factorial": |
|
msg_unsup += ( |
|
"Permitted data types are integers and floating point numbers, " |
|
"as well as complex numbers if `extend='complex' is passed." |
|
) |
|
else: |
|
msg_unsup += ( |
|
"Permitted data types are integers, as well as floating point " |
|
"numbers and complex numbers if `extend='complex' is passed." |
|
) |
|
msg_exact_not_possible = ( |
|
"`exact=True` only supports integers, cannot use data type {dtype}" |
|
) |
|
msg_needs_complex = ( |
|
"In order to use non-integer arguments, you must opt into this by passing " |
|
"`extend='complex'`. Note that this changes the result for all negative " |
|
"arguments (which by default return 0)." |
|
) |
|
|
|
if fname == "factorial2": |
|
msg_needs_complex += (" Additionally, it will rescale the values of the double" |
|
" factorial at even integers by a factor of sqrt(2/pi).") |
|
elif fname == "factorialk": |
|
msg_needs_complex += (" Additionally, it will perturb the values of the" |
|
" multifactorial at most positive integers `n`.") |
|
|
|
if not _is_subdtype(type(k), ["i", "f", "c"]): |
|
raise ValueError(msg_unsup.format(vname="`k`", fname=fname, dtype=type(k))) |
|
elif _is_subdtype(type(k), ["f", "c"]) and extend != "complex": |
|
raise ValueError(msg_needs_complex) |
|
|
|
if extend == "zero" and k < 1: |
|
msg = f"For `extend='zero'`, k must be a positive integer, received: {k}" |
|
raise ValueError(msg) |
|
elif k == 0: |
|
raise ValueError("Parameter k cannot be zero!") |
|
|
|
|
|
types_requiring_complex = "c" if fname == "factorial" else ["f", "c"] |
|
|
|
|
|
if np.ndim(n) == 0 and not isinstance(n, np.ndarray): |
|
|
|
if not _is_subdtype(type(n), ["i", "f", "c", type(None)]): |
|
raise ValueError(msg_unsup.format(vname="`n`", fname=fname, dtype=type(n))) |
|
elif _is_subdtype(type(n), types_requiring_complex) and extend != "complex": |
|
raise ValueError(msg_needs_complex) |
|
elif n is None or np.isnan(n): |
|
complexify = (extend == "complex") and _is_subdtype(type(n), "c") |
|
return np.complex128("nan+nanj") if complexify else np.float64("nan") |
|
elif extend == "zero" and n < 0: |
|
return 0 if exact else np.float64(0) |
|
elif n in {0, 1}: |
|
return 1 if exact else np.float64(1) |
|
elif exact and _is_subdtype(type(n), "i"): |
|
|
|
return _range_prod(1, n, k=k) |
|
elif exact: |
|
|
|
raise ValueError(msg_exact_not_possible.format(dtype=type(n))) |
|
|
|
return _factorialx_approx_core(n, k=k, extend=extend) |
|
|
|
|
|
n = asarray(n) |
|
|
|
if not _is_subdtype(n.dtype, ["i", "f", "c"]): |
|
raise ValueError(msg_unsup.format(vname="`n`", fname=fname, dtype=n.dtype)) |
|
elif _is_subdtype(n.dtype, types_requiring_complex) and extend != "complex": |
|
raise ValueError(msg_needs_complex) |
|
elif exact and _is_subdtype(n.dtype, ["f"]): |
|
|
|
raise ValueError(msg_exact_not_possible.format(dtype=n.dtype)) |
|
|
|
if n.size == 0: |
|
|
|
return n |
|
elif exact: |
|
|
|
return _factorialx_array_exact(n, k=k) |
|
|
|
return _factorialx_array_approx(n, k=k, extend=extend) |
|
|
|
|
|
def factorial(n, exact=False, extend="zero"): |
|
""" |
|
The factorial of a number or array of numbers. |
|
|
|
The factorial of non-negative integer `n` is the product of all |
|
positive integers less than or equal to `n`:: |
|
|
|
n! = n * (n - 1) * (n - 2) * ... * 1 |
|
|
|
Parameters |
|
---------- |
|
n : int or float or complex (or array_like thereof) |
|
Input values for ``n!``. Complex values require ``extend='complex'``. |
|
By default, the return value for ``n < 0`` is 0. |
|
exact : bool, optional |
|
If ``exact`` is set to True, calculate the answer exactly using |
|
integer arithmetic, otherwise approximate using the gamma function |
|
(faster, but yields floats instead of integers). |
|
Default is False. |
|
extend : string, optional |
|
One of ``'zero'`` or ``'complex'``; this determines how values ``n<0`` |
|
are handled - by default they are 0, but it is possible to opt into the |
|
complex extension of the factorial (see below). |
|
|
|
Returns |
|
------- |
|
nf : int or float or complex or ndarray |
|
Factorial of ``n``, as integer, float or complex (depending on ``exact`` |
|
and ``extend``). Array inputs are returned as arrays. |
|
|
|
Notes |
|
----- |
|
For arrays with ``exact=True``, the factorial is computed only once, for |
|
the largest input, with each other result computed in the process. |
|
The output dtype is increased to ``int64`` or ``object`` if necessary. |
|
|
|
With ``exact=False`` the factorial is approximated using the gamma |
|
function (which is also the definition of the complex extension): |
|
|
|
.. math:: n! = \\Gamma(n+1) |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> from scipy.special import factorial |
|
>>> arr = np.array([3, 4, 5]) |
|
>>> factorial(arr, exact=False) |
|
array([ 6., 24., 120.]) |
|
>>> factorial(arr, exact=True) |
|
array([ 6, 24, 120]) |
|
>>> factorial(5, exact=True) |
|
120 |
|
|
|
""" |
|
return _factorialx_wrapper("factorial", n, k=1, exact=exact, extend=extend) |
|
|
|
|
|
def factorial2(n, exact=False, extend="zero"): |
|
"""Double factorial. |
|
|
|
This is the factorial with every second value skipped. E.g., ``7!! = 7 * 5 |
|
* 3 * 1``. It can be approximated numerically as:: |
|
|
|
n!! = 2 ** (n / 2) * gamma(n / 2 + 1) * sqrt(2 / pi) n odd |
|
= 2 ** (n / 2) * gamma(n / 2 + 1) n even |
|
= 2 ** (n / 2) * (n / 2)! n even |
|
|
|
The formula for odd ``n`` is the basis for the complex extension. |
|
|
|
Parameters |
|
---------- |
|
n : int or float or complex (or array_like thereof) |
|
Input values for ``n!!``. Non-integer values require ``extend='complex'``. |
|
By default, the return value for ``n < 0`` is 0. |
|
exact : bool, optional |
|
If ``exact`` is set to True, calculate the answer exactly using |
|
integer arithmetic, otherwise use above approximation (faster, |
|
but yields floats instead of integers). |
|
Default is False. |
|
extend : string, optional |
|
One of ``'zero'`` or ``'complex'``; this determines how values ``n<0`` |
|
are handled - by default they are 0, but it is possible to opt into the |
|
complex extension of the double factorial. This also enables passing |
|
complex values to ``n``. |
|
|
|
.. warning:: |
|
|
|
Using the ``'complex'`` extension also changes the values of the |
|
double factorial for even integers, reducing them by a factor of |
|
``sqrt(2/pi) ~= 0.79``, see [1]. |
|
|
|
Returns |
|
------- |
|
nf : int or float or complex or ndarray |
|
Double factorial of ``n``, as integer, float or complex (depending on |
|
``exact`` and ``extend``). Array inputs are returned as arrays. |
|
|
|
Examples |
|
-------- |
|
>>> from scipy.special import factorial2 |
|
>>> factorial2(7, exact=False) |
|
array(105.00000000000001) |
|
>>> factorial2(7, exact=True) |
|
105 |
|
|
|
References |
|
---------- |
|
.. [1] Complex extension to double factorial |
|
https://en.wikipedia.org/wiki/Double_factorial#Complex_arguments |
|
""" |
|
return _factorialx_wrapper("factorial2", n, k=2, exact=exact, extend=extend) |
|
|
|
|
|
def factorialk(n, k, exact=False, extend="zero"): |
|
"""Multifactorial of n of order k, n(!!...!). |
|
|
|
This is the multifactorial of n skipping k values. For example, |
|
|
|
factorialk(17, 4) = 17!!!! = 17 * 13 * 9 * 5 * 1 |
|
|
|
In particular, for any integer ``n``, we have |
|
|
|
factorialk(n, 1) = factorial(n) |
|
|
|
factorialk(n, 2) = factorial2(n) |
|
|
|
Parameters |
|
---------- |
|
n : int or float or complex (or array_like thereof) |
|
Input values for multifactorial. Non-integer values require |
|
``extend='complex'``. By default, the return value for ``n < 0`` is 0. |
|
n : int or float or complex (or array_like thereof) |
|
Order of multifactorial. Non-integer values require ``extend='complex'``. |
|
exact : bool, optional |
|
If ``exact`` is set to True, calculate the answer exactly using |
|
integer arithmetic, otherwise use an approximation (faster, |
|
but yields floats instead of integers) |
|
Default is False. |
|
extend : string, optional |
|
One of ``'zero'`` or ``'complex'``; this determines how values ``n<0`` are |
|
handled - by default they are 0, but it is possible to opt into the complex |
|
extension of the multifactorial. This enables passing complex values, |
|
not only to ``n`` but also to ``k``. |
|
|
|
.. warning:: |
|
|
|
Using the ``'complex'`` extension also changes the values of the |
|
multifactorial at integers ``n != 1 (mod k)`` by a factor depending |
|
on both ``k`` and ``n % k``, see below or [1]. |
|
|
|
Returns |
|
------- |
|
nf : int or float or complex or ndarray |
|
Multifactorial (order ``k``) of ``n``, as integer, float or complex (depending |
|
on ``exact`` and ``extend``). Array inputs are returned as arrays. |
|
|
|
Examples |
|
-------- |
|
>>> from scipy.special import factorialk |
|
>>> factorialk(5, k=1, exact=True) |
|
120 |
|
>>> factorialk(5, k=3, exact=True) |
|
10 |
|
>>> factorialk([5, 7, 9], k=3, exact=True) |
|
array([ 10, 28, 162]) |
|
>>> factorialk([5, 7, 9], k=3, exact=False) |
|
array([ 10., 28., 162.]) |
|
|
|
Notes |
|
----- |
|
While less straight-forward than for the double-factorial, it's possible to |
|
calculate a general approximation formula of n!(k) by studying ``n`` for a given |
|
remainder ``r < k`` (thus ``n = m * k + r``, resp. ``r = n % k``), which can be |
|
put together into something valid for all integer values ``n >= 0`` & ``k > 0``:: |
|
|
|
n!(k) = k ** ((n - r)/k) * gamma(n/k + 1) / gamma(r/k + 1) * max(r, 1) |
|
|
|
This is the basis of the approximation when ``exact=False``. |
|
|
|
In principle, any fixed choice of ``r`` (ignoring its relation ``r = n%k`` |
|
to ``n``) would provide a suitable analytic continuation from integer ``n`` |
|
to complex ``z`` (not only satisfying the functional equation but also |
|
being logarithmically convex, c.f. Bohr-Mollerup theorem) -- in fact, the |
|
choice of ``r`` above only changes the function by a constant factor. The |
|
final constraint that determines the canonical continuation is ``f(1) = 1``, |
|
which forces ``r = 1`` (see also [1]).:: |
|
|
|
z!(k) = k ** ((z - 1)/k) * gamma(z/k + 1) / gamma(1/k + 1) |
|
|
|
References |
|
---------- |
|
.. [1] Complex extension to multifactorial |
|
https://en.wikipedia.org/wiki/Double_factorial#Alternative_extension_of_the_multifactorial |
|
""" |
|
return _factorialx_wrapper("factorialk", n, k=k, exact=exact, extend=extend) |
|
|
|
|
|
def stirling2(N, K, *, exact=False): |
|
r"""Generate Stirling number(s) of the second kind. |
|
|
|
Stirling numbers of the second kind count the number of ways to |
|
partition a set with N elements into K non-empty subsets. |
|
|
|
The values this function returns are calculated using a dynamic |
|
program which avoids redundant computation across the subproblems |
|
in the solution. For array-like input, this implementation also |
|
avoids redundant computation across the different Stirling number |
|
calculations. |
|
|
|
The numbers are sometimes denoted |
|
|
|
.. math:: |
|
|
|
{N \brace{K}} |
|
|
|
see [1]_ for details. This is often expressed-verbally-as |
|
"N subset K". |
|
|
|
Parameters |
|
---------- |
|
N : int, ndarray |
|
Number of things. |
|
K : int, ndarray |
|
Number of non-empty subsets taken. |
|
exact : bool, optional |
|
Uses dynamic programming (DP) with floating point |
|
numbers for smaller arrays and uses a second order approximation due to |
|
Temme for larger entries of `N` and `K` that allows trading speed for |
|
accuracy. See [2]_ for a description. Temme approximation is used for |
|
values ``n>50``. The max error from the DP has max relative error |
|
``4.5*10^-16`` for ``n<=50`` and the max error from the Temme approximation |
|
has max relative error ``5*10^-5`` for ``51 <= n < 70`` and |
|
``9*10^-6`` for ``70 <= n < 101``. Note that these max relative errors will |
|
decrease further as `n` increases. |
|
|
|
Returns |
|
------- |
|
val : int, float, ndarray |
|
The number of partitions. |
|
|
|
See Also |
|
-------- |
|
comb : The number of combinations of N things taken k at a time. |
|
|
|
Notes |
|
----- |
|
- If N < 0, or K < 0, then 0 is returned. |
|
- If K > N, then 0 is returned. |
|
|
|
The output type will always be `int` or ndarray of `object`. |
|
The input must contain either numpy or python integers otherwise a |
|
TypeError is raised. |
|
|
|
References |
|
---------- |
|
.. [1] R. L. Graham, D. E. Knuth and O. Patashnik, "Concrete |
|
Mathematics: A Foundation for Computer Science," Addison-Wesley |
|
Publishing Company, Boston, 1989. Chapter 6, page 258. |
|
|
|
.. [2] Temme, Nico M. "Asymptotic estimates of Stirling numbers." |
|
Studies in Applied Mathematics 89.3 (1993): 233-243. |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> from scipy.special import stirling2 |
|
>>> k = np.array([3, -1, 3]) |
|
>>> n = np.array([10, 10, 9]) |
|
>>> stirling2(n, k) |
|
array([9330.0, 0.0, 3025.0]) |
|
|
|
""" |
|
output_is_scalar = np.isscalar(N) and np.isscalar(K) |
|
|
|
N, K = asarray(N), asarray(K) |
|
if not np.issubdtype(N.dtype, np.integer): |
|
raise TypeError("Argument `N` must contain only integers") |
|
if not np.issubdtype(K.dtype, np.integer): |
|
raise TypeError("Argument `K` must contain only integers") |
|
if not exact: |
|
|
|
|
|
|
|
return _stirling2_inexact(N.astype(float), K.astype(float)) |
|
nk_pairs = list( |
|
set([(n.take(0), k.take(0)) |
|
for n, k in np.nditer([N, K], ['refs_ok'])]) |
|
) |
|
heapify(nk_pairs) |
|
|
|
snsk_vals = defaultdict(int) |
|
for pair in [(0, 0), (1, 1), (2, 1), (2, 2)]: |
|
snsk_vals[pair] = 1 |
|
|
|
n_old, n_row = 2, [0, 1, 1] |
|
while nk_pairs: |
|
n, k = heappop(nk_pairs) |
|
if n < 2 or k > n or k <= 0: |
|
continue |
|
elif k == n or k == 1: |
|
snsk_vals[(n, k)] = 1 |
|
continue |
|
elif n != n_old: |
|
num_iters = n - n_old |
|
while num_iters > 0: |
|
n_row.append(1) |
|
|
|
for j in range(len(n_row)-2, 1, -1): |
|
n_row[j] = n_row[j]*j + n_row[j-1] |
|
num_iters -= 1 |
|
snsk_vals[(n, k)] = n_row[k] |
|
else: |
|
snsk_vals[(n, k)] = n_row[k] |
|
n_old, n_row = n, n_row |
|
out_types = [object, object, object] if exact else [float, float, float] |
|
|
|
it = np.nditer( |
|
[N, K, None], |
|
['buffered', 'refs_ok'], |
|
[['readonly'], ['readonly'], ['writeonly', 'allocate']], |
|
op_dtypes=out_types, |
|
) |
|
with it: |
|
while not it.finished: |
|
it[2] = snsk_vals[(int(it[0]), int(it[1]))] |
|
it.iternext() |
|
output = it.operands[2] |
|
|
|
if output_is_scalar: |
|
output = output.take(0) |
|
return output |
|
|
|
|
|
def zeta(x, q=None, out=None): |
|
r""" |
|
Riemann or Hurwitz zeta function. |
|
|
|
Parameters |
|
---------- |
|
x : array_like of float or complex. |
|
Input data |
|
q : array_like of float, optional |
|
Input data, must be real. Defaults to Riemann zeta. When `q` is |
|
``None``, complex inputs `x` are supported. If `q` is not ``None``, |
|
then currently only real inputs `x` with ``x >= 1`` are supported, |
|
even when ``q = 1.0`` (corresponding to the Riemann zeta function). |
|
|
|
out : ndarray, optional |
|
Output array for the computed values. |
|
|
|
Returns |
|
------- |
|
out : array_like |
|
Values of zeta(x). |
|
|
|
See Also |
|
-------- |
|
zetac |
|
|
|
Notes |
|
----- |
|
The two-argument version is the Hurwitz zeta function |
|
|
|
.. math:: |
|
|
|
\zeta(x, q) = \sum_{k=0}^{\infty} \frac{1}{(k + q)^x}; |
|
|
|
see [dlmf]_ for details. The Riemann zeta function corresponds to |
|
the case when ``q = 1``. |
|
|
|
For complex inputs with ``q = None``, points with |
|
``abs(z.imag) > 1e9`` and ``0 <= abs(z.real) < 2.5`` are currently not |
|
supported due to slow convergence causing excessive runtime. |
|
|
|
References |
|
---------- |
|
.. [dlmf] NIST, Digital Library of Mathematical Functions, |
|
https://dlmf.nist.gov/25.11#i |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> from scipy.special import zeta, polygamma, factorial |
|
|
|
Some specific values: |
|
|
|
>>> zeta(2), np.pi**2/6 |
|
(1.6449340668482266, 1.6449340668482264) |
|
|
|
>>> zeta(4), np.pi**4/90 |
|
(1.0823232337111381, 1.082323233711138) |
|
|
|
First nontrivial zero: |
|
|
|
>>> zeta(0.5 + 14.134725141734695j) |
|
0 + 0j |
|
|
|
Relation to the `polygamma` function: |
|
|
|
>>> m = 3 |
|
>>> x = 1.25 |
|
>>> polygamma(m, x) |
|
array(2.782144009188397) |
|
>>> (-1)**(m+1) * factorial(m) * zeta(m+1, x) |
|
2.7821440091883969 |
|
|
|
""" |
|
if q is None: |
|
return _ufuncs._riemann_zeta(x, out) |
|
else: |
|
return _ufuncs._zeta(x, q, out) |
|
|
|
|
|
def softplus(x, **kwargs): |
|
r""" |
|
Compute the softplus function element-wise. |
|
|
|
The softplus function is defined as: ``softplus(x) = log(1 + exp(x))``. |
|
It is a smooth approximation of the rectifier function (ReLU). |
|
|
|
Parameters |
|
---------- |
|
x : array_like |
|
Input value. |
|
**kwargs |
|
For other keyword-only arguments, see the |
|
`ufunc docs <https://numpy.org/doc/stable/reference/ufuncs.html>`_. |
|
|
|
Returns |
|
------- |
|
softplus : ndarray |
|
Logarithm of ``exp(0) + exp(x)``. |
|
|
|
Examples |
|
-------- |
|
>>> from scipy import special |
|
|
|
>>> special.softplus(0) |
|
0.6931471805599453 |
|
|
|
>>> special.softplus([-1, 0, 1]) |
|
array([0.31326169, 0.69314718, 1.31326169]) |
|
""" |
|
return np.logaddexp(0, x, **kwargs) |
|
|