using for loop to install conda package

This commit is contained in:
ton
2023-04-16 11:03:27 +07:00
parent 49da9f29c1
commit 0c2b34d6f8
12168 changed files with 2656238 additions and 1 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,112 @@
import numpy as np
import scipy.special as sc
import pytest
from numpy.testing import assert_allclose, assert_array_equal, suppress_warnings
class TestBdtr:
def test(self):
val = sc.bdtr(0, 1, 0.5)
assert_allclose(val, 0.5)
def test_sum_is_one(self):
val = sc.bdtr([0, 1, 2], 2, 0.5)
assert_array_equal(val, [0.25, 0.75, 1.0])
def test_rounding(self):
double_val = sc.bdtr([0.1, 1.1, 2.1], 2, 0.5)
int_val = sc.bdtr([0, 1, 2], 2, 0.5)
assert_array_equal(double_val, int_val)
@pytest.mark.parametrize('k, n, p', [
(np.inf, 2, 0.5),
(1.0, np.inf, 0.5),
(1.0, 2, np.inf)
])
def test_inf(self, k, n, p):
with suppress_warnings() as sup:
sup.filter(DeprecationWarning)
val = sc.bdtr(k, n, p)
assert np.isnan(val)
def test_domain(self):
val = sc.bdtr(-1.1, 1, 0.5)
assert np.isnan(val)
class TestBdtrc:
def test_value(self):
val = sc.bdtrc(0, 1, 0.5)
assert_allclose(val, 0.5)
def test_sum_is_one(self):
val = sc.bdtrc([0, 1, 2], 2, 0.5)
assert_array_equal(val, [0.75, 0.25, 0.0])
def test_rounding(self):
double_val = sc.bdtrc([0.1, 1.1, 2.1], 2, 0.5)
int_val = sc.bdtrc([0, 1, 2], 2, 0.5)
assert_array_equal(double_val, int_val)
@pytest.mark.parametrize('k, n, p', [
(np.inf, 2, 0.5),
(1.0, np.inf, 0.5),
(1.0, 2, np.inf)
])
def test_inf(self, k, n, p):
with suppress_warnings() as sup:
sup.filter(DeprecationWarning)
val = sc.bdtrc(k, n, p)
assert np.isnan(val)
def test_domain(self):
val = sc.bdtrc(-1.1, 1, 0.5)
val2 = sc.bdtrc(2.1, 1, 0.5)
assert np.isnan(val2)
assert_allclose(val, 1.0)
def test_bdtr_bdtrc_sum_to_one(self):
bdtr_vals = sc.bdtr([0, 1, 2], 2, 0.5)
bdtrc_vals = sc.bdtrc([0, 1, 2], 2, 0.5)
vals = bdtr_vals + bdtrc_vals
assert_allclose(vals, [1.0, 1.0, 1.0])
class TestBdtri:
def test_value(self):
val = sc.bdtri(0, 1, 0.5)
assert_allclose(val, 0.5)
def test_sum_is_one(self):
val = sc.bdtri([0, 1], 2, 0.5)
actual = np.asarray([1 - 1/np.sqrt(2), 1/np.sqrt(2)])
assert_allclose(val, actual)
def test_rounding(self):
double_val = sc.bdtri([0.1, 1.1], 2, 0.5)
int_val = sc.bdtri([0, 1], 2, 0.5)
assert_allclose(double_val, int_val)
@pytest.mark.parametrize('k, n, p', [
(np.inf, 2, 0.5),
(1.0, np.inf, 0.5),
(1.0, 2, np.inf)
])
def test_inf(self, k, n, p):
with suppress_warnings() as sup:
sup.filter(DeprecationWarning)
val = sc.bdtri(k, n, p)
assert np.isnan(val)
@pytest.mark.parametrize('k, n, p', [
(-1.1, 1, 0.5),
(2.1, 1, 0.5)
])
def test_domain(self, k, n, p):
val = sc.bdtri(k, n, p)
assert np.isnan(val)
def test_bdtr_bdtri_roundtrip(self):
bdtr_vals = sc.bdtr([0, 1, 2], 2, 0.5)
roundtrip_vals = sc.bdtri([0, 1, 2], 2, bdtr_vals)
assert_allclose(roundtrip_vals, [0.5, 0.5, np.nan])

View File

@@ -0,0 +1,106 @@
import numpy as np
from numpy.testing import assert_equal, assert_almost_equal, assert_allclose
from scipy.special import boxcox, boxcox1p, inv_boxcox, inv_boxcox1p
# There are more tests of boxcox and boxcox1p in test_mpmath.py.
def test_boxcox_basic():
x = np.array([0.5, 1, 2, 4])
# lambda = 0 => y = log(x)
y = boxcox(x, 0)
assert_almost_equal(y, np.log(x))
# lambda = 1 => y = x - 1
y = boxcox(x, 1)
assert_almost_equal(y, x - 1)
# lambda = 2 => y = 0.5*(x**2 - 1)
y = boxcox(x, 2)
assert_almost_equal(y, 0.5*(x**2 - 1))
# x = 0 and lambda > 0 => y = -1 / lambda
lam = np.array([0.5, 1, 2])
y = boxcox(0, lam)
assert_almost_equal(y, -1.0 / lam)
def test_boxcox_underflow():
x = 1 + 1e-15
lmbda = 1e-306
y = boxcox(x, lmbda)
assert_allclose(y, np.log(x), rtol=1e-14)
def test_boxcox_nonfinite():
# x < 0 => y = nan
x = np.array([-1, -1, -0.5])
y = boxcox(x, [0.5, 2.0, -1.5])
assert_equal(y, np.array([np.nan, np.nan, np.nan]))
# x = 0 and lambda <= 0 => y = -inf
x = 0
y = boxcox(x, [-2.5, 0])
assert_equal(y, np.array([-np.inf, -np.inf]))
def test_boxcox1p_basic():
x = np.array([-0.25, -1e-20, 0, 1e-20, 0.25, 1, 3])
# lambda = 0 => y = log(1+x)
y = boxcox1p(x, 0)
assert_almost_equal(y, np.log1p(x))
# lambda = 1 => y = x
y = boxcox1p(x, 1)
assert_almost_equal(y, x)
# lambda = 2 => y = 0.5*((1+x)**2 - 1) = 0.5*x*(2 + x)
y = boxcox1p(x, 2)
assert_almost_equal(y, 0.5*x*(2 + x))
# x = -1 and lambda > 0 => y = -1 / lambda
lam = np.array([0.5, 1, 2])
y = boxcox1p(-1, lam)
assert_almost_equal(y, -1.0 / lam)
def test_boxcox1p_underflow():
x = np.array([1e-15, 1e-306])
lmbda = np.array([1e-306, 1e-18])
y = boxcox1p(x, lmbda)
assert_allclose(y, np.log1p(x), rtol=1e-14)
def test_boxcox1p_nonfinite():
# x < -1 => y = nan
x = np.array([-2, -2, -1.5])
y = boxcox1p(x, [0.5, 2.0, -1.5])
assert_equal(y, np.array([np.nan, np.nan, np.nan]))
# x = -1 and lambda <= 0 => y = -inf
x = -1
y = boxcox1p(x, [-2.5, 0])
assert_equal(y, np.array([-np.inf, -np.inf]))
def test_inv_boxcox():
x = np.array([0., 1., 2.])
lam = np.array([0., 1., 2.])
y = boxcox(x, lam)
x2 = inv_boxcox(y, lam)
assert_almost_equal(x, x2)
x = np.array([0., 1., 2.])
lam = np.array([0., 1., 2.])
y = boxcox1p(x, lam)
x2 = inv_boxcox1p(y, lam)
assert_almost_equal(x, x2)
def test_inv_boxcox1p_underflow():
x = 1e-15
lam = 1e-306
y = inv_boxcox1p(x, lam)
assert_allclose(y, x, rtol=1e-14)

View File

@@ -0,0 +1,424 @@
"""
Test cdflib functions versus mpmath, if available.
The following functions still need tests:
- ncfdtr
- ncfdtri
- ncfdtridfn
- ncfdtridfd
- ncfdtrinc
- nbdtrik
- nbdtrin
- nrdtrimn
- nrdtrisd
- pdtrik
- nctdtr
- nctdtrit
- nctdtridf
- nctdtrinc
"""
import itertools
import numpy as np
from numpy.testing import assert_equal, assert_allclose
import pytest
import scipy.special as sp
from scipy.special._testutils import (
MissingModule, check_version, FuncData)
from scipy.special._mptestutils import (
Arg, IntArg, get_args, mpf2float, assert_mpmath_equal)
try:
import mpmath
except ImportError:
mpmath = MissingModule('mpmath')
class ProbArg:
"""Generate a set of probabilities on [0, 1]."""
def __init__(self):
# Include the endpoints for compatibility with Arg et. al.
self.a = 0
self.b = 1
def values(self, n):
"""Return an array containing approximatively n numbers."""
m = max(1, n//3)
v1 = np.logspace(-30, np.log10(0.3), m)
v2 = np.linspace(0.3, 0.7, m + 1, endpoint=False)[1:]
v3 = 1 - np.logspace(np.log10(0.3), -15, m)
v = np.r_[v1, v2, v3]
return np.unique(v)
class EndpointFilter:
def __init__(self, a, b, rtol, atol):
self.a = a
self.b = b
self.rtol = rtol
self.atol = atol
def __call__(self, x):
mask1 = np.abs(x - self.a) < self.rtol*np.abs(self.a) + self.atol
mask2 = np.abs(x - self.b) < self.rtol*np.abs(self.b) + self.atol
return np.where(mask1 | mask2, False, True)
class _CDFData:
def __init__(self, spfunc, mpfunc, index, argspec, spfunc_first=True,
dps=20, n=5000, rtol=None, atol=None,
endpt_rtol=None, endpt_atol=None):
self.spfunc = spfunc
self.mpfunc = mpfunc
self.index = index
self.argspec = argspec
self.spfunc_first = spfunc_first
self.dps = dps
self.n = n
self.rtol = rtol
self.atol = atol
if not isinstance(argspec, list):
self.endpt_rtol = None
self.endpt_atol = None
elif endpt_rtol is not None or endpt_atol is not None:
if isinstance(endpt_rtol, list):
self.endpt_rtol = endpt_rtol
else:
self.endpt_rtol = [endpt_rtol]*len(self.argspec)
if isinstance(endpt_atol, list):
self.endpt_atol = endpt_atol
else:
self.endpt_atol = [endpt_atol]*len(self.argspec)
else:
self.endpt_rtol = None
self.endpt_atol = None
def idmap(self, *args):
if self.spfunc_first:
res = self.spfunc(*args)
if np.isnan(res):
return np.nan
args = list(args)
args[self.index] = res
with mpmath.workdps(self.dps):
res = self.mpfunc(*tuple(args))
# Imaginary parts are spurious
res = mpf2float(res.real)
else:
with mpmath.workdps(self.dps):
res = self.mpfunc(*args)
res = mpf2float(res.real)
args = list(args)
args[self.index] = res
res = self.spfunc(*tuple(args))
return res
def get_param_filter(self):
if self.endpt_rtol is None and self.endpt_atol is None:
return None
filters = []
for rtol, atol, spec in zip(self.endpt_rtol, self.endpt_atol, self.argspec):
if rtol is None and atol is None:
filters.append(None)
continue
elif rtol is None:
rtol = 0.0
elif atol is None:
atol = 0.0
filters.append(EndpointFilter(spec.a, spec.b, rtol, atol))
return filters
def check(self):
# Generate values for the arguments
args = get_args(self.argspec, self.n)
param_filter = self.get_param_filter()
param_columns = tuple(range(args.shape[1]))
result_columns = args.shape[1]
args = np.hstack((args, args[:,self.index].reshape(args.shape[0], 1)))
FuncData(self.idmap, args,
param_columns=param_columns, result_columns=result_columns,
rtol=self.rtol, atol=self.atol, vectorized=False,
param_filter=param_filter).check()
def _assert_inverts(*a, **kw):
d = _CDFData(*a, **kw)
d.check()
def _binomial_cdf(k, n, p):
k, n, p = mpmath.mpf(k), mpmath.mpf(n), mpmath.mpf(p)
if k <= 0:
return mpmath.mpf(0)
elif k >= n:
return mpmath.mpf(1)
onemp = mpmath.fsub(1, p, exact=True)
return mpmath.betainc(n - k, k + 1, x2=onemp, regularized=True)
def _f_cdf(dfn, dfd, x):
if x < 0:
return mpmath.mpf(0)
dfn, dfd, x = mpmath.mpf(dfn), mpmath.mpf(dfd), mpmath.mpf(x)
ub = dfn*x/(dfn*x + dfd)
res = mpmath.betainc(dfn/2, dfd/2, x2=ub, regularized=True)
return res
def _student_t_cdf(df, t, dps=None):
if dps is None:
dps = mpmath.mp.dps
with mpmath.workdps(dps):
df, t = mpmath.mpf(df), mpmath.mpf(t)
fac = mpmath.hyp2f1(0.5, 0.5*(df + 1), 1.5, -t**2/df)
fac *= t*mpmath.gamma(0.5*(df + 1))
fac /= mpmath.sqrt(mpmath.pi*df)*mpmath.gamma(0.5*df)
return 0.5 + fac
def _noncentral_chi_pdf(t, df, nc):
res = mpmath.besseli(df/2 - 1, mpmath.sqrt(nc*t))
res *= mpmath.exp(-(t + nc)/2)*(t/nc)**(df/4 - 1/2)/2
return res
def _noncentral_chi_cdf(x, df, nc, dps=None):
if dps is None:
dps = mpmath.mp.dps
x, df, nc = mpmath.mpf(x), mpmath.mpf(df), mpmath.mpf(nc)
with mpmath.workdps(dps):
res = mpmath.quad(lambda t: _noncentral_chi_pdf(t, df, nc), [0, x])
return res
def _tukey_lmbda_quantile(p, lmbda):
# For lmbda != 0
return (p**lmbda - (1 - p)**lmbda)/lmbda
@pytest.mark.slow
@check_version(mpmath, '0.19')
class TestCDFlib:
@pytest.mark.xfail(run=False)
def test_bdtrik(self):
_assert_inverts(
sp.bdtrik,
_binomial_cdf,
0, [ProbArg(), IntArg(1, 1000), ProbArg()],
rtol=1e-4)
def test_bdtrin(self):
_assert_inverts(
sp.bdtrin,
_binomial_cdf,
1, [IntArg(1, 1000), ProbArg(), ProbArg()],
rtol=1e-4, endpt_atol=[None, None, 1e-6])
def test_btdtria(self):
_assert_inverts(
sp.btdtria,
lambda a, b, x: mpmath.betainc(a, b, x2=x, regularized=True),
0, [ProbArg(), Arg(0, 1e2, inclusive_a=False),
Arg(0, 1, inclusive_a=False, inclusive_b=False)],
rtol=1e-6)
def test_btdtrib(self):
# Use small values of a or mpmath doesn't converge
_assert_inverts(
sp.btdtrib,
lambda a, b, x: mpmath.betainc(a, b, x2=x, regularized=True),
1, [Arg(0, 1e2, inclusive_a=False), ProbArg(),
Arg(0, 1, inclusive_a=False, inclusive_b=False)],
rtol=1e-7, endpt_atol=[None, 1e-18, 1e-15])
@pytest.mark.xfail(run=False)
def test_fdtridfd(self):
_assert_inverts(
sp.fdtridfd,
_f_cdf,
1, [IntArg(1, 100), ProbArg(), Arg(0, 100, inclusive_a=False)],
rtol=1e-7)
def test_gdtria(self):
_assert_inverts(
sp.gdtria,
lambda a, b, x: mpmath.gammainc(b, b=a*x, regularized=True),
0, [ProbArg(), Arg(0, 1e3, inclusive_a=False),
Arg(0, 1e4, inclusive_a=False)], rtol=1e-7,
endpt_atol=[None, 1e-7, 1e-10])
def test_gdtrib(self):
# Use small values of a and x or mpmath doesn't converge
_assert_inverts(
sp.gdtrib,
lambda a, b, x: mpmath.gammainc(b, b=a*x, regularized=True),
1, [Arg(0, 1e2, inclusive_a=False), ProbArg(),
Arg(0, 1e3, inclusive_a=False)], rtol=1e-5)
def test_gdtrix(self):
_assert_inverts(
sp.gdtrix,
lambda a, b, x: mpmath.gammainc(b, b=a*x, regularized=True),
2, [Arg(0, 1e3, inclusive_a=False), Arg(0, 1e3, inclusive_a=False),
ProbArg()], rtol=1e-7,
endpt_atol=[None, 1e-7, 1e-10])
def test_stdtr(self):
# Ideally the left endpoint for Arg() should be 0.
assert_mpmath_equal(
sp.stdtr,
_student_t_cdf,
[IntArg(1, 100), Arg(1e-10, np.inf)], rtol=1e-7)
@pytest.mark.xfail(run=False)
def test_stdtridf(self):
_assert_inverts(
sp.stdtridf,
_student_t_cdf,
0, [ProbArg(), Arg()], rtol=1e-7)
def test_stdtrit(self):
_assert_inverts(
sp.stdtrit,
_student_t_cdf,
1, [IntArg(1, 100), ProbArg()], rtol=1e-7,
endpt_atol=[None, 1e-10])
def test_chdtriv(self):
_assert_inverts(
sp.chdtriv,
lambda v, x: mpmath.gammainc(v/2, b=x/2, regularized=True),
0, [ProbArg(), IntArg(1, 100)], rtol=1e-4)
@pytest.mark.xfail(run=False)
def test_chndtridf(self):
# Use a larger atol since mpmath is doing numerical integration
_assert_inverts(
sp.chndtridf,
_noncentral_chi_cdf,
1, [Arg(0, 100, inclusive_a=False), ProbArg(),
Arg(0, 100, inclusive_a=False)],
n=1000, rtol=1e-4, atol=1e-15)
@pytest.mark.xfail(run=False)
def test_chndtrinc(self):
# Use a larger atol since mpmath is doing numerical integration
_assert_inverts(
sp.chndtrinc,
_noncentral_chi_cdf,
2, [Arg(0, 100, inclusive_a=False), IntArg(1, 100), ProbArg()],
n=1000, rtol=1e-4, atol=1e-15)
def test_chndtrix(self):
# Use a larger atol since mpmath is doing numerical integration
_assert_inverts(
sp.chndtrix,
_noncentral_chi_cdf,
0, [ProbArg(), IntArg(1, 100), Arg(0, 100, inclusive_a=False)],
n=1000, rtol=1e-4, atol=1e-15,
endpt_atol=[1e-6, None, None])
def test_tklmbda_zero_shape(self):
# When lmbda = 0 the CDF has a simple closed form
one = mpmath.mpf(1)
assert_mpmath_equal(
lambda x: sp.tklmbda(x, 0),
lambda x: one/(mpmath.exp(-x) + one),
[Arg()], rtol=1e-7)
def test_tklmbda_neg_shape(self):
_assert_inverts(
sp.tklmbda,
_tukey_lmbda_quantile,
0, [ProbArg(), Arg(-25, 0, inclusive_b=False)],
spfunc_first=False, rtol=1e-5,
endpt_atol=[1e-9, 1e-5])
@pytest.mark.xfail(run=False)
def test_tklmbda_pos_shape(self):
_assert_inverts(
sp.tklmbda,
_tukey_lmbda_quantile,
0, [ProbArg(), Arg(0, 100, inclusive_a=False)],
spfunc_first=False, rtol=1e-5)
def test_nonfinite():
funcs = [
("btdtria", 3),
("btdtrib", 3),
("bdtrik", 3),
("bdtrin", 3),
("chdtriv", 2),
("chndtr", 3),
("chndtrix", 3),
("chndtridf", 3),
("chndtrinc", 3),
("fdtridfd", 3),
("ncfdtr", 4),
("ncfdtri", 4),
("ncfdtridfn", 4),
("ncfdtridfd", 4),
("ncfdtrinc", 4),
("gdtrix", 3),
("gdtrib", 3),
("gdtria", 3),
("nbdtrik", 3),
("nbdtrin", 3),
("nrdtrimn", 3),
("nrdtrisd", 3),
("pdtrik", 2),
("stdtr", 2),
("stdtrit", 2),
("stdtridf", 2),
("nctdtr", 3),
("nctdtrit", 3),
("nctdtridf", 3),
("nctdtrinc", 3),
("tklmbda", 2),
]
np.random.seed(1)
for func, numargs in funcs:
func = getattr(sp, func)
args_choices = [(float(x), np.nan, np.inf, -np.inf) for x in
np.random.rand(numargs)]
for args in itertools.product(*args_choices):
res = func(*args)
if any(np.isnan(x) for x in args):
# Nan inputs should result to nan output
assert_equal(res, np.nan)
else:
# All other inputs should return something (but not
# raise exceptions or cause hangs)
pass
def test_chndtrix_gh2158():
# test that gh-2158 is resolved; previously this blew up
res = sp.chndtrix(0.999999, 2, np.arange(20.)+1e-6)
# Generated in R
# options(digits=16)
# ncp <- seq(0, 19) + 1e-6
# print(qchisq(0.999999, df = 2, ncp = ncp))
res_exp = [27.63103493142305, 35.25728589950540, 39.97396073236288,
43.88033702110538, 47.35206403482798, 50.54112500166103,
53.52720257322766, 56.35830042867810, 59.06600769498512,
61.67243118946381, 64.19376191277179, 66.64228141346548,
69.02756927200180, 71.35726934749408, 73.63759723904816,
75.87368842650227, 78.06984431185720, 80.22971052389806,
82.35640899964173, 84.45263768373256]
assert_allclose(res, res_exp)

View File

@@ -0,0 +1,49 @@
# gh-14777 regression tests
# Test stdtr and stdtrit with infinite df and large values of df
import numpy as np
from numpy.testing import assert_allclose, assert_equal
from scipy.special import stdtr, stdtrit, ndtr, ndtri
def test_stdtr_vs_R_large_df():
df = [1e10, 1e12, 1e120, np.inf]
t = 1.
res = stdtr(df, t)
# R Code:
# options(digits=20)
# pt(1., c(1e10, 1e12, 1e120, Inf))
res_R = [0.84134474605644460343,
0.84134474606842180044,
0.84134474606854281475,
0.84134474606854292578]
assert_allclose(res, res_R, rtol=2e-15)
# last value should also agree with ndtr
assert_equal(res[3], ndtr(1.))
def test_stdtrit_vs_R_large_df():
df = [1e10, 1e12, 1e120, np.inf]
p = 0.1
res = stdtrit(df, p)
# R Code:
# options(digits=20)
# qt(0.1, c(1e10, 1e12, 1e120, Inf))
res_R = [-1.2815515656292593150,
-1.2815515655454472466,
-1.2815515655446008125,
-1.2815515655446008125]
assert_allclose(res, res_R, rtol=1e-15)
# last value should also agree with ndtri
assert_equal(res[3], ndtri(0.1))
def test_stdtr_stdtri_invalid():
# a mix of large and inf df with t/p equal to nan
df = [1e10, 1e12, 1e120, np.inf]
x = np.nan
res1 = stdtr(df, x)
res2 = stdtrit(df, x)
res_ex = 4*[np.nan]
assert_equal(res1, res_ex)
assert_equal(res2, res_ex)

View File

@@ -0,0 +1,84 @@
import numpy as np
from numpy.testing import assert_allclose
import pytest
from scipy.special._ufuncs import _cosine_cdf, _cosine_invcdf
# These values are (x, p) where p is the expected exact value of
# _cosine_cdf(x). These values will be tested for exact agreement.
_coscdf_exact = [
(-4.0, 0.0),
(0, 0.5),
(np.pi, 1.0),
(4.0, 1.0),
]
@pytest.mark.parametrize("x, expected", _coscdf_exact)
def test_cosine_cdf_exact(x, expected):
assert _cosine_cdf(x) == expected
# These values are (x, p), where p is the expected value of
# _cosine_cdf(x). The expected values were computed with mpmath using
# 50 digits of precision. These values will be tested for agreement
# with the computed values using a very small relative tolerance.
# The value at -np.pi is not 0, because -np.pi does not equal -π.
_coscdf_close = [
(3.1409, 0.999999999991185),
(2.25, 0.9819328173287907),
# -1.6 is the threshold below which the Pade approximant is used.
(-1.599, 0.08641959838382553),
(-1.601, 0.086110582992713),
(-2.0, 0.0369709335961611),
(-3.0, 7.522387241801384e-05),
(-3.1415, 2.109869685443648e-14),
(-3.14159, 4.956444476505336e-19),
(-np.pi, 4.871934450264861e-50),
]
@pytest.mark.parametrize("x, expected", _coscdf_close)
def test_cosine_cdf(x, expected):
assert_allclose(_cosine_cdf(x), expected, rtol=5e-15)
# These values are (p, x) where x is the expected exact value of
# _cosine_invcdf(p). These values will be tested for exact agreement.
_cosinvcdf_exact = [
(0.0, -np.pi),
(0.5, 0.0),
(1.0, np.pi),
]
@pytest.mark.parametrize("p, expected", _cosinvcdf_exact)
def test_cosine_invcdf_exact(p, expected):
assert _cosine_invcdf(p) == expected
def test_cosine_invcdf_invalid_p():
# Check that p values outside of [0, 1] return nan.
assert np.isnan(_cosine_invcdf([-0.1, 1.1])).all()
# These values are (p, x), where x is the expected value of _cosine_invcdf(p).
# The expected values were computed with mpmath using 50 digits of precision.
_cosinvcdf_close = [
(1e-50, -np.pi),
(1e-14, -3.1415204137058454),
(1e-08, -3.1343686589124524),
(0.0018001, -2.732563923138336),
(0.010, -2.41276589008678),
(0.060, -1.7881244975330157),
(0.125, -1.3752523669869274),
(0.250, -0.831711193579736),
(0.400, -0.3167954512395289),
(0.419, -0.25586025626919906),
(0.421, -0.24947570750445663),
(0.750, 0.831711193579736),
(0.940, 1.7881244975330153),
(0.9999999996, 3.1391220839917167),
]
@pytest.mark.parametrize("p, expected", _cosinvcdf_close)
def test_cosine_invcdf(p, expected):
assert_allclose(_cosine_invcdf(p), expected, rtol=1e-14)

View File

@@ -0,0 +1,352 @@
from __future__ import annotations
from typing import List, Tuple, Callable, Optional
import pytest
from itertools import product
from numpy.testing import assert_allclose, suppress_warnings
from scipy import special
from scipy.special import cython_special
bint_points = [True, False]
int_points = [-10, -1, 1, 10]
real_points = [-10.0, -1.0, 1.0, 10.0]
complex_points = [complex(*tup) for tup in product(real_points, repeat=2)]
CYTHON_SIGNATURE_MAP = {
'b': 'bint',
'f': 'float',
'd': 'double',
'g': 'long double',
'F': 'float complex',
'D': 'double complex',
'G': 'long double complex',
'i': 'int',
'l': 'long'
}
TEST_POINTS = {
'b': bint_points,
'f': real_points,
'd': real_points,
'g': real_points,
'F': complex_points,
'D': complex_points,
'G': complex_points,
'i': int_points,
'l': int_points,
}
PARAMS: List[Tuple[Callable, Callable, Tuple[str, ...], Optional[str]]] = [
(special.agm, cython_special.agm, ('dd',), None),
(special.airy, cython_special._airy_pywrap, ('d', 'D'), None),
(special.airye, cython_special._airye_pywrap, ('d', 'D'), None),
(special.bdtr, cython_special.bdtr, ('dld', 'ddd'), None),
(special.bdtrc, cython_special.bdtrc, ('dld', 'ddd'), None),
(special.bdtri, cython_special.bdtri, ('dld', 'ddd'), None),
(special.bdtrik, cython_special.bdtrik, ('ddd',), None),
(special.bdtrin, cython_special.bdtrin, ('ddd',), None),
(special.bei, cython_special.bei, ('d',), None),
(special.beip, cython_special.beip, ('d',), None),
(special.ber, cython_special.ber, ('d',), None),
(special.berp, cython_special.berp, ('d',), None),
(special.besselpoly, cython_special.besselpoly, ('ddd',), None),
(special.beta, cython_special.beta, ('dd',), None),
(special.betainc, cython_special.betainc, ('ddd',), None),
(special.betaincinv, cython_special.betaincinv, ('ddd',), None),
(special.betaln, cython_special.betaln, ('dd',), None),
(special.binom, cython_special.binom, ('dd',), None),
(special.boxcox, cython_special.boxcox, ('dd',), None),
(special.boxcox1p, cython_special.boxcox1p, ('dd',), None),
(special.btdtr, cython_special.btdtr, ('ddd',), None),
(special.btdtri, cython_special.btdtri, ('ddd',), None),
(special.btdtria, cython_special.btdtria, ('ddd',), None),
(special.btdtrib, cython_special.btdtrib, ('ddd',), None),
(special.cbrt, cython_special.cbrt, ('d',), None),
(special.chdtr, cython_special.chdtr, ('dd',), None),
(special.chdtrc, cython_special.chdtrc, ('dd',), None),
(special.chdtri, cython_special.chdtri, ('dd',), None),
(special.chdtriv, cython_special.chdtriv, ('dd',), None),
(special.chndtr, cython_special.chndtr, ('ddd',), None),
(special.chndtridf, cython_special.chndtridf, ('ddd',), None),
(special.chndtrinc, cython_special.chndtrinc, ('ddd',), None),
(special.chndtrix, cython_special.chndtrix, ('ddd',), None),
(special.cosdg, cython_special.cosdg, ('d',), None),
(special.cosm1, cython_special.cosm1, ('d',), None),
(special.cotdg, cython_special.cotdg, ('d',), None),
(special.dawsn, cython_special.dawsn, ('d', 'D'), None),
(special.ellipe, cython_special.ellipe, ('d',), None),
(special.ellipeinc, cython_special.ellipeinc, ('dd',), None),
(special.ellipj, cython_special._ellipj_pywrap, ('dd',), None),
(special.ellipkinc, cython_special.ellipkinc, ('dd',), None),
(special.ellipkm1, cython_special.ellipkm1, ('d',), None),
(special.ellipk, cython_special.ellipk, ('d',), None),
(special.elliprc, cython_special.elliprc, ('dd', 'DD'), None),
(special.elliprd, cython_special.elliprd, ('ddd', 'DDD'), None),
(special.elliprf, cython_special.elliprf, ('ddd', 'DDD'), None),
(special.elliprg, cython_special.elliprg, ('ddd', 'DDD'), None),
(special.elliprj, cython_special.elliprj, ('dddd', 'DDDD'), None),
(special.entr, cython_special.entr, ('d',), None),
(special.erf, cython_special.erf, ('d', 'D'), None),
(special.erfc, cython_special.erfc, ('d', 'D'), None),
(special.erfcx, cython_special.erfcx, ('d', 'D'), None),
(special.erfi, cython_special.erfi, ('d', 'D'), None),
(special.erfinv, cython_special.erfinv, ('d',), None),
(special.erfcinv, cython_special.erfcinv, ('d',), None),
(special.eval_chebyc, cython_special.eval_chebyc, ('dd', 'dD', 'ld'), None),
(special.eval_chebys, cython_special.eval_chebys, ('dd', 'dD', 'ld'),
'd and l differ for negative int'),
(special.eval_chebyt, cython_special.eval_chebyt, ('dd', 'dD', 'ld'),
'd and l differ for negative int'),
(special.eval_chebyu, cython_special.eval_chebyu, ('dd', 'dD', 'ld'),
'd and l differ for negative int'),
(special.eval_gegenbauer, cython_special.eval_gegenbauer, ('ddd', 'ddD', 'ldd'),
'd and l differ for negative int'),
(special.eval_genlaguerre, cython_special.eval_genlaguerre, ('ddd', 'ddD', 'ldd'),
'd and l differ for negative int'),
(special.eval_hermite, cython_special.eval_hermite, ('ld',), None),
(special.eval_hermitenorm, cython_special.eval_hermitenorm, ('ld',), None),
(special.eval_jacobi, cython_special.eval_jacobi, ('dddd', 'dddD', 'lddd'),
'd and l differ for negative int'),
(special.eval_laguerre, cython_special.eval_laguerre, ('dd', 'dD', 'ld'),
'd and l differ for negative int'),
(special.eval_legendre, cython_special.eval_legendre, ('dd', 'dD', 'ld'), None),
(special.eval_sh_chebyt, cython_special.eval_sh_chebyt, ('dd', 'dD', 'ld'), None),
(special.eval_sh_chebyu, cython_special.eval_sh_chebyu, ('dd', 'dD', 'ld'),
'd and l differ for negative int'),
(special.eval_sh_jacobi, cython_special.eval_sh_jacobi, ('dddd', 'dddD', 'lddd'),
'd and l differ for negative int'),
(special.eval_sh_legendre, cython_special.eval_sh_legendre, ('dd', 'dD', 'ld'), None),
(special.exp1, cython_special.exp1, ('d', 'D'), None),
(special.exp10, cython_special.exp10, ('d',), None),
(special.exp2, cython_special.exp2, ('d',), None),
(special.expi, cython_special.expi, ('d', 'D'), None),
(special.expit, cython_special.expit, ('f', 'd', 'g'), None),
(special.expm1, cython_special.expm1, ('d', 'D'), None),
(special.expn, cython_special.expn, ('ld', 'dd'), None),
(special.exprel, cython_special.exprel, ('d',), None),
(special.fdtr, cython_special.fdtr, ('ddd',), None),
(special.fdtrc, cython_special.fdtrc, ('ddd',), None),
(special.fdtri, cython_special.fdtri, ('ddd',), None),
(special.fdtridfd, cython_special.fdtridfd, ('ddd',), None),
(special.fresnel, cython_special._fresnel_pywrap, ('d', 'D'), None),
(special.gamma, cython_special.gamma, ('d', 'D'), None),
(special.gammainc, cython_special.gammainc, ('dd',), None),
(special.gammaincc, cython_special.gammaincc, ('dd',), None),
(special.gammainccinv, cython_special.gammainccinv, ('dd',), None),
(special.gammaincinv, cython_special.gammaincinv, ('dd',), None),
(special.gammaln, cython_special.gammaln, ('d',), None),
(special.gammasgn, cython_special.gammasgn, ('d',), None),
(special.gdtr, cython_special.gdtr, ('ddd',), None),
(special.gdtrc, cython_special.gdtrc, ('ddd',), None),
(special.gdtria, cython_special.gdtria, ('ddd',), None),
(special.gdtrib, cython_special.gdtrib, ('ddd',), None),
(special.gdtrix, cython_special.gdtrix, ('ddd',), None),
(special.hankel1, cython_special.hankel1, ('dD',), None),
(special.hankel1e, cython_special.hankel1e, ('dD',), None),
(special.hankel2, cython_special.hankel2, ('dD',), None),
(special.hankel2e, cython_special.hankel2e, ('dD',), None),
(special.huber, cython_special.huber, ('dd',), None),
(special.hyp0f1, cython_special.hyp0f1, ('dd', 'dD'), None),
(special.hyp1f1, cython_special.hyp1f1, ('ddd', 'ddD'), None),
(special.hyp2f1, cython_special.hyp2f1, ('dddd', 'dddD'), None),
(special.hyperu, cython_special.hyperu, ('ddd',), None),
(special.i0, cython_special.i0, ('d',), None),
(special.i0e, cython_special.i0e, ('d',), None),
(special.i1, cython_special.i1, ('d',), None),
(special.i1e, cython_special.i1e, ('d',), None),
(special.inv_boxcox, cython_special.inv_boxcox, ('dd',), None),
(special.inv_boxcox1p, cython_special.inv_boxcox1p, ('dd',), None),
(special.it2i0k0, cython_special._it2i0k0_pywrap, ('d',), None),
(special.it2j0y0, cython_special._it2j0y0_pywrap, ('d',), None),
(special.it2struve0, cython_special.it2struve0, ('d',), None),
(special.itairy, cython_special._itairy_pywrap, ('d',), None),
(special.iti0k0, cython_special._iti0k0_pywrap, ('d',), None),
(special.itj0y0, cython_special._itj0y0_pywrap, ('d',), None),
(special.itmodstruve0, cython_special.itmodstruve0, ('d',), None),
(special.itstruve0, cython_special.itstruve0, ('d',), None),
(special.iv, cython_special.iv, ('dd', 'dD'), None),
(special.ive, cython_special.ive, ('dd', 'dD'), None),
(special.j0, cython_special.j0, ('d',), None),
(special.j1, cython_special.j1, ('d',), None),
(special.jv, cython_special.jv, ('dd', 'dD'), None),
(special.jve, cython_special.jve, ('dd', 'dD'), None),
(special.k0, cython_special.k0, ('d',), None),
(special.k0e, cython_special.k0e, ('d',), None),
(special.k1, cython_special.k1, ('d',), None),
(special.k1e, cython_special.k1e, ('d',), None),
(special.kei, cython_special.kei, ('d',), None),
(special.keip, cython_special.keip, ('d',), None),
(special.kelvin, cython_special._kelvin_pywrap, ('d',), None),
(special.ker, cython_special.ker, ('d',), None),
(special.kerp, cython_special.kerp, ('d',), None),
(special.kl_div, cython_special.kl_div, ('dd',), None),
(special.kn, cython_special.kn, ('ld', 'dd'), None),
(special.kolmogi, cython_special.kolmogi, ('d',), None),
(special.kolmogorov, cython_special.kolmogorov, ('d',), None),
(special.kv, cython_special.kv, ('dd', 'dD'), None),
(special.kve, cython_special.kve, ('dd', 'dD'), None),
(special.log1p, cython_special.log1p, ('d', 'D'), None),
(special.log_expit, cython_special.log_expit, ('f', 'd', 'g'), None),
(special.log_ndtr, cython_special.log_ndtr, ('d', 'D'), None),
(special.ndtri_exp, cython_special.ndtri_exp, ('d',), None),
(special.loggamma, cython_special.loggamma, ('D',), None),
(special.logit, cython_special.logit, ('f', 'd', 'g'), None),
(special.lpmv, cython_special.lpmv, ('ddd',), None),
(special.mathieu_a, cython_special.mathieu_a, ('dd',), None),
(special.mathieu_b, cython_special.mathieu_b, ('dd',), None),
(special.mathieu_cem, cython_special._mathieu_cem_pywrap, ('ddd',), None),
(special.mathieu_modcem1, cython_special._mathieu_modcem1_pywrap, ('ddd',), None),
(special.mathieu_modcem2, cython_special._mathieu_modcem2_pywrap, ('ddd',), None),
(special.mathieu_modsem1, cython_special._mathieu_modsem1_pywrap, ('ddd',), None),
(special.mathieu_modsem2, cython_special._mathieu_modsem2_pywrap, ('ddd',), None),
(special.mathieu_sem, cython_special._mathieu_sem_pywrap, ('ddd',), None),
(special.modfresnelm, cython_special._modfresnelm_pywrap, ('d',), None),
(special.modfresnelp, cython_special._modfresnelp_pywrap, ('d',), None),
(special.modstruve, cython_special.modstruve, ('dd',), None),
(special.nbdtr, cython_special.nbdtr, ('lld', 'ddd'), None),
(special.nbdtrc, cython_special.nbdtrc, ('lld', 'ddd'), None),
(special.nbdtri, cython_special.nbdtri, ('lld', 'ddd'), None),
(special.nbdtrik, cython_special.nbdtrik, ('ddd',), None),
(special.nbdtrin, cython_special.nbdtrin, ('ddd',), None),
(special.ncfdtr, cython_special.ncfdtr, ('dddd',), None),
(special.ncfdtri, cython_special.ncfdtri, ('dddd',), None),
(special.ncfdtridfd, cython_special.ncfdtridfd, ('dddd',), None),
(special.ncfdtridfn, cython_special.ncfdtridfn, ('dddd',), None),
(special.ncfdtrinc, cython_special.ncfdtrinc, ('dddd',), None),
(special.nctdtr, cython_special.nctdtr, ('ddd',), None),
(special.nctdtridf, cython_special.nctdtridf, ('ddd',), None),
(special.nctdtrinc, cython_special.nctdtrinc, ('ddd',), None),
(special.nctdtrit, cython_special.nctdtrit, ('ddd',), None),
(special.ndtr, cython_special.ndtr, ('d', 'D'), None),
(special.ndtri, cython_special.ndtri, ('d',), None),
(special.nrdtrimn, cython_special.nrdtrimn, ('ddd',), None),
(special.nrdtrisd, cython_special.nrdtrisd, ('ddd',), None),
(special.obl_ang1, cython_special._obl_ang1_pywrap, ('dddd',), None),
(special.obl_ang1_cv, cython_special._obl_ang1_cv_pywrap, ('ddddd',), None),
(special.obl_cv, cython_special.obl_cv, ('ddd',), None),
(special.obl_rad1, cython_special._obl_rad1_pywrap, ('dddd',), "see gh-6211"),
(special.obl_rad1_cv, cython_special._obl_rad1_cv_pywrap, ('ddddd',), "see gh-6211"),
(special.obl_rad2, cython_special._obl_rad2_pywrap, ('dddd',), "see gh-6211"),
(special.obl_rad2_cv, cython_special._obl_rad2_cv_pywrap, ('ddddd',), "see gh-6211"),
(special.pbdv, cython_special._pbdv_pywrap, ('dd',), None),
(special.pbvv, cython_special._pbvv_pywrap, ('dd',), None),
(special.pbwa, cython_special._pbwa_pywrap, ('dd',), None),
(special.pdtr, cython_special.pdtr, ('dd', 'dd'), None),
(special.pdtrc, cython_special.pdtrc, ('dd', 'dd'), None),
(special.pdtri, cython_special.pdtri, ('ld', 'dd'), None),
(special.pdtrik, cython_special.pdtrik, ('dd',), None),
(special.poch, cython_special.poch, ('dd',), None),
(special.powm1, cython_special.powm1, ('dd',), None),
(special.pro_ang1, cython_special._pro_ang1_pywrap, ('dddd',), None),
(special.pro_ang1_cv, cython_special._pro_ang1_cv_pywrap, ('ddddd',), None),
(special.pro_cv, cython_special.pro_cv, ('ddd',), None),
(special.pro_rad1, cython_special._pro_rad1_pywrap, ('dddd',), "see gh-6211"),
(special.pro_rad1_cv, cython_special._pro_rad1_cv_pywrap, ('ddddd',), "see gh-6211"),
(special.pro_rad2, cython_special._pro_rad2_pywrap, ('dddd',), "see gh-6211"),
(special.pro_rad2_cv, cython_special._pro_rad2_cv_pywrap, ('ddddd',), "see gh-6211"),
(special.pseudo_huber, cython_special.pseudo_huber, ('dd',), None),
(special.psi, cython_special.psi, ('d', 'D'), None),
(special.radian, cython_special.radian, ('ddd',), None),
(special.rel_entr, cython_special.rel_entr, ('dd',), None),
(special.rgamma, cython_special.rgamma, ('d', 'D'), None),
(special.round, cython_special.round, ('d',), None),
(special.spherical_jn, cython_special.spherical_jn, ('ld', 'ldb', 'lD', 'lDb'), None),
(special.spherical_yn, cython_special.spherical_yn, ('ld', 'ldb', 'lD', 'lDb'), None),
(special.spherical_in, cython_special.spherical_in, ('ld', 'ldb', 'lD', 'lDb'), None),
(special.spherical_kn, cython_special.spherical_kn, ('ld', 'ldb', 'lD', 'lDb'), None),
(special.shichi, cython_special._shichi_pywrap, ('d', 'D'), None),
(special.sici, cython_special._sici_pywrap, ('d', 'D'), None),
(special.sindg, cython_special.sindg, ('d',), None),
(special.smirnov, cython_special.smirnov, ('ld', 'dd'), None),
(special.smirnovi, cython_special.smirnovi, ('ld', 'dd'), None),
(special.spence, cython_special.spence, ('d', 'D'), None),
(special.sph_harm, cython_special.sph_harm, ('lldd', 'dddd'), None),
(special.stdtr, cython_special.stdtr, ('dd',), None),
(special.stdtridf, cython_special.stdtridf, ('dd',), None),
(special.stdtrit, cython_special.stdtrit, ('dd',), None),
(special.struve, cython_special.struve, ('dd',), None),
(special.tandg, cython_special.tandg, ('d',), None),
(special.tklmbda, cython_special.tklmbda, ('dd',), None),
(special.voigt_profile, cython_special.voigt_profile, ('ddd',), None),
(special.wofz, cython_special.wofz, ('D',), None),
(special.wright_bessel, cython_special.wright_bessel, ('ddd',), None),
(special.wrightomega, cython_special.wrightomega, ('D',), None),
(special.xlog1py, cython_special.xlog1py, ('dd', 'DD'), None),
(special.xlogy, cython_special.xlogy, ('dd', 'DD'), None),
(special.y0, cython_special.y0, ('d',), None),
(special.y1, cython_special.y1, ('d',), None),
(special.yn, cython_special.yn, ('ld', 'dd'), None),
(special.yv, cython_special.yv, ('dd', 'dD'), None),
(special.yve, cython_special.yve, ('dd', 'dD'), None),
(special.zetac, cython_special.zetac, ('d',), None),
(special.owens_t, cython_special.owens_t, ('dd',), None)
]
IDS = [x[0].__name__ for x in PARAMS]
def _generate_test_points(typecodes):
axes = tuple(TEST_POINTS[x] for x in typecodes)
pts = list(product(*axes))
return pts
def test_cython_api_completeness():
# Check that everything is tested
for name in dir(cython_special):
func = getattr(cython_special, name)
if callable(func) and not name.startswith('_'):
for _, cyfun, _, _ in PARAMS:
if cyfun is func:
break
else:
raise RuntimeError(f"{name} missing from tests!")
@pytest.mark.parametrize("param", PARAMS, ids=IDS)
def test_cython_api(param):
pyfunc, cyfunc, specializations, knownfailure = param
if knownfailure:
pytest.xfail(reason=knownfailure)
# Check which parameters are expected to be fused types
max_params = max(len(spec) for spec in specializations)
values = [set() for _ in range(max_params)]
for typecodes in specializations:
for j, v in enumerate(typecodes):
values[j].add(v)
seen = set()
is_fused_code = [False] * len(values)
for j, v in enumerate(values):
vv = tuple(sorted(v))
if vv in seen:
continue
is_fused_code[j] = (len(v) > 1)
seen.add(vv)
# Check results
for typecodes in specializations:
# Pick the correct specialized function
signature = [CYTHON_SIGNATURE_MAP[code]
for j, code in enumerate(typecodes)
if is_fused_code[j]]
if signature:
cy_spec_func = cyfunc[tuple(signature)]
else:
signature = None
cy_spec_func = cyfunc
# Test it
pts = _generate_test_points(typecodes)
for pt in pts:
with suppress_warnings() as sup:
sup.filter(DeprecationWarning)
pyval = pyfunc(*pt)
cyval = cy_spec_func(*pt)
assert_allclose(cyval, pyval, err_msg="{} {} {}".format(pt, typecodes, signature))

View File

@@ -0,0 +1,617 @@
import os
import numpy as np
from numpy.testing import suppress_warnings
import pytest
from scipy.special import (
lpn, lpmn, lpmv, lqn, lqmn, sph_harm, eval_legendre, eval_hermite,
eval_laguerre, eval_genlaguerre, binom, cbrt, expm1, log1p, zeta,
jn, jv, jvp, yn, yv, yvp, iv, ivp, kn, kv, kvp,
gamma, gammaln, gammainc, gammaincc, gammaincinv, gammainccinv, digamma,
beta, betainc, betaincinv, poch,
ellipe, ellipeinc, ellipk, ellipkm1, ellipkinc, ellipj,
elliprc, elliprd, elliprf, elliprg, elliprj,
erf, erfc, erfinv, erfcinv, exp1, expi, expn,
bdtrik, btdtr, btdtri, btdtria, btdtrib, chndtr, gdtr, gdtrc, gdtrix, gdtrib,
nbdtrik, pdtrik, owens_t,
mathieu_a, mathieu_b, mathieu_cem, mathieu_sem, mathieu_modcem1,
mathieu_modsem1, mathieu_modcem2, mathieu_modsem2,
ellip_harm, ellip_harm_2, spherical_jn, spherical_yn, wright_bessel
)
from scipy.integrate import IntegrationWarning
from scipy.special._testutils import FuncData
DATASETS_BOOST = np.load(os.path.join(os.path.dirname(__file__),
"data", "boost.npz"))
DATASETS_GSL = np.load(os.path.join(os.path.dirname(__file__),
"data", "gsl.npz"))
DATASETS_LOCAL = np.load(os.path.join(os.path.dirname(__file__),
"data", "local.npz"))
def data(func, dataname, *a, **kw):
kw.setdefault('dataname', dataname)
return FuncData(func, DATASETS_BOOST[dataname], *a, **kw)
def data_gsl(func, dataname, *a, **kw):
kw.setdefault('dataname', dataname)
return FuncData(func, DATASETS_GSL[dataname], *a, **kw)
def data_local(func, dataname, *a, **kw):
kw.setdefault('dataname', dataname)
return FuncData(func, DATASETS_LOCAL[dataname], *a, **kw)
def ellipk_(k):
return ellipk(k*k)
def ellipkinc_(f, k):
return ellipkinc(f, k*k)
def ellipe_(k):
return ellipe(k*k)
def ellipeinc_(f, k):
return ellipeinc(f, k*k)
def ellipj_(k):
return ellipj(k*k)
def zeta_(x):
return zeta(x, 1.)
def assoc_legendre_p_boost_(nu, mu, x):
# the boost test data is for integer orders only
return lpmv(mu, nu.astype(int), x)
def legendre_p_via_assoc_(nu, x):
return lpmv(0, nu, x)
def lpn_(n, x):
return lpn(n.astype('l'), x)[0][-1]
def lqn_(n, x):
return lqn(n.astype('l'), x)[0][-1]
def legendre_p_via_lpmn(n, x):
return lpmn(0, n, x)[0][0,-1]
def legendre_q_via_lqmn(n, x):
return lqmn(0, n, x)[0][0,-1]
def mathieu_ce_rad(m, q, x):
return mathieu_cem(m, q, x*180/np.pi)[0]
def mathieu_se_rad(m, q, x):
return mathieu_sem(m, q, x*180/np.pi)[0]
def mathieu_mc1_scaled(m, q, x):
# GSL follows a different normalization.
# We follow Abramowitz & Stegun, they apparently something else.
return mathieu_modcem1(m, q, x)[0] * np.sqrt(np.pi/2)
def mathieu_ms1_scaled(m, q, x):
return mathieu_modsem1(m, q, x)[0] * np.sqrt(np.pi/2)
def mathieu_mc2_scaled(m, q, x):
return mathieu_modcem2(m, q, x)[0] * np.sqrt(np.pi/2)
def mathieu_ms2_scaled(m, q, x):
return mathieu_modsem2(m, q, x)[0] * np.sqrt(np.pi/2)
def eval_legendre_ld(n, x):
return eval_legendre(n.astype('l'), x)
def eval_legendre_dd(n, x):
return eval_legendre(n.astype('d'), x)
def eval_hermite_ld(n, x):
return eval_hermite(n.astype('l'), x)
def eval_laguerre_ld(n, x):
return eval_laguerre(n.astype('l'), x)
def eval_laguerre_dd(n, x):
return eval_laguerre(n.astype('d'), x)
def eval_genlaguerre_ldd(n, a, x):
return eval_genlaguerre(n.astype('l'), a, x)
def eval_genlaguerre_ddd(n, a, x):
return eval_genlaguerre(n.astype('d'), a, x)
def bdtrik_comp(y, n, p):
return bdtrik(1-y, n, p)
def btdtri_comp(a, b, p):
return btdtri(a, b, 1-p)
def btdtria_comp(p, b, x):
return btdtria(1-p, b, x)
def btdtrib_comp(a, p, x):
return btdtrib(a, 1-p, x)
def gdtr_(p, x):
return gdtr(1.0, p, x)
def gdtrc_(p, x):
return gdtrc(1.0, p, x)
def gdtrix_(b, p):
return gdtrix(1.0, b, p)
def gdtrix_comp(b, p):
return gdtrix(1.0, b, 1-p)
def gdtrib_(p, x):
return gdtrib(1.0, p, x)
def gdtrib_comp(p, x):
return gdtrib(1.0, 1-p, x)
def nbdtrik_comp(y, n, p):
return nbdtrik(1-y, n, p)
def pdtrik_comp(p, m):
return pdtrik(1-p, m)
def poch_(z, m):
return 1.0 / poch(z, m)
def poch_minus(z, m):
return 1.0 / poch(z, -m)
def spherical_jn_(n, x):
return spherical_jn(n.astype('l'), x)
def spherical_yn_(n, x):
return spherical_yn(n.astype('l'), x)
def sph_harm_(m, n, theta, phi):
y = sph_harm(m, n, theta, phi)
return (y.real, y.imag)
def cexpm1(x, y):
z = expm1(x + 1j*y)
return z.real, z.imag
def clog1p(x, y):
z = log1p(x + 1j*y)
return z.real, z.imag
BOOST_TESTS = [
data(assoc_legendre_p_boost_, 'assoc_legendre_p_ipp-assoc_legendre_p', (0,1,2), 3, rtol=1e-11),
data(legendre_p_via_assoc_, 'legendre_p_ipp-legendre_p', (0,1), 2, rtol=1e-11),
data(legendre_p_via_assoc_, 'legendre_p_large_ipp-legendre_p_large', (0,1), 2, rtol=9.6e-14),
data(legendre_p_via_lpmn, 'legendre_p_ipp-legendre_p', (0,1), 2, rtol=5e-14, vectorized=False),
data(legendre_p_via_lpmn, 'legendre_p_large_ipp-legendre_p_large', (0,1), 2, rtol=9.6e-14, vectorized=False),
data(lpn_, 'legendre_p_ipp-legendre_p', (0,1), 2, rtol=5e-14, vectorized=False),
data(lpn_, 'legendre_p_large_ipp-legendre_p_large', (0,1), 2, rtol=3e-13, vectorized=False),
data(eval_legendre_ld, 'legendre_p_ipp-legendre_p', (0,1), 2, rtol=6e-14),
data(eval_legendre_ld, 'legendre_p_large_ipp-legendre_p_large', (0,1), 2, rtol=2e-13),
data(eval_legendre_dd, 'legendre_p_ipp-legendre_p', (0,1), 2, rtol=2e-14),
data(eval_legendre_dd, 'legendre_p_large_ipp-legendre_p_large', (0,1), 2, rtol=2e-13),
data(lqn_, 'legendre_p_ipp-legendre_p', (0,1), 3, rtol=2e-14, vectorized=False),
data(lqn_, 'legendre_p_large_ipp-legendre_p_large', (0,1), 3, rtol=2e-12, vectorized=False),
data(legendre_q_via_lqmn, 'legendre_p_ipp-legendre_p', (0,1), 3, rtol=2e-14, vectorized=False),
data(legendre_q_via_lqmn, 'legendre_p_large_ipp-legendre_p_large', (0,1), 3, rtol=2e-12, vectorized=False),
data(beta, 'beta_exp_data_ipp-beta_exp_data', (0,1), 2, rtol=1e-13),
data(beta, 'beta_exp_data_ipp-beta_exp_data', (0,1), 2, rtol=1e-13),
data(beta, 'beta_med_data_ipp-beta_med_data', (0,1), 2, rtol=5e-13),
data(betainc, 'ibeta_small_data_ipp-ibeta_small_data', (0,1,2), 5, rtol=6e-15),
data(betainc, 'ibeta_data_ipp-ibeta_data', (0,1,2), 5, rtol=5e-13),
data(betainc, 'ibeta_int_data_ipp-ibeta_int_data', (0,1,2), 5, rtol=2e-14),
data(betainc, 'ibeta_large_data_ipp-ibeta_large_data', (0,1,2), 5, rtol=4e-10),
data(betaincinv, 'ibeta_inv_data_ipp-ibeta_inv_data', (0,1,2), 3, rtol=1e-5),
data(btdtr, 'ibeta_small_data_ipp-ibeta_small_data', (0,1,2), 5, rtol=6e-15),
data(btdtr, 'ibeta_data_ipp-ibeta_data', (0,1,2), 5, rtol=4e-13),
data(btdtr, 'ibeta_int_data_ipp-ibeta_int_data', (0,1,2), 5, rtol=2e-14),
data(btdtr, 'ibeta_large_data_ipp-ibeta_large_data', (0,1,2), 5, rtol=4e-10),
data(btdtri, 'ibeta_inv_data_ipp-ibeta_inv_data', (0,1,2), 3, rtol=1e-5),
data(btdtri_comp, 'ibeta_inv_data_ipp-ibeta_inv_data', (0,1,2), 4, rtol=8e-7),
data(btdtria, 'ibeta_inva_data_ipp-ibeta_inva_data', (2,0,1), 3, rtol=5e-9),
data(btdtria_comp, 'ibeta_inva_data_ipp-ibeta_inva_data', (2,0,1), 4, rtol=5e-9),
data(btdtrib, 'ibeta_inva_data_ipp-ibeta_inva_data', (0,2,1), 5, rtol=5e-9),
data(btdtrib_comp, 'ibeta_inva_data_ipp-ibeta_inva_data', (0,2,1), 6, rtol=5e-9),
data(binom, 'binomial_data_ipp-binomial_data', (0,1), 2, rtol=1e-13),
data(binom, 'binomial_large_data_ipp-binomial_large_data', (0,1), 2, rtol=5e-13),
data(bdtrik, 'binomial_quantile_ipp-binomial_quantile_data', (2,0,1), 3, rtol=5e-9),
data(bdtrik_comp, 'binomial_quantile_ipp-binomial_quantile_data', (2,0,1), 4, rtol=5e-9),
data(nbdtrik, 'negative_binomial_quantile_ipp-negative_binomial_quantile_data', (2,0,1), 3, rtol=4e-9),
data(nbdtrik_comp, 'negative_binomial_quantile_ipp-negative_binomial_quantile_data', (2,0,1), 4, rtol=4e-9),
data(pdtrik, 'poisson_quantile_ipp-poisson_quantile_data', (1,0), 2, rtol=3e-9),
data(pdtrik_comp, 'poisson_quantile_ipp-poisson_quantile_data', (1,0), 3, rtol=4e-9),
data(cbrt, 'cbrt_data_ipp-cbrt_data', 1, 0),
data(digamma, 'digamma_data_ipp-digamma_data', 0, 1),
data(digamma, 'digamma_data_ipp-digamma_data', 0j, 1),
data(digamma, 'digamma_neg_data_ipp-digamma_neg_data', 0, 1, rtol=2e-13),
data(digamma, 'digamma_neg_data_ipp-digamma_neg_data', 0j, 1, rtol=1e-13),
data(digamma, 'digamma_root_data_ipp-digamma_root_data', 0, 1, rtol=1e-15),
data(digamma, 'digamma_root_data_ipp-digamma_root_data', 0j, 1, rtol=1e-15),
data(digamma, 'digamma_small_data_ipp-digamma_small_data', 0, 1, rtol=1e-15),
data(digamma, 'digamma_small_data_ipp-digamma_small_data', 0j, 1, rtol=1e-14),
data(ellipk_, 'ellint_k_data_ipp-ellint_k_data', 0, 1),
data(ellipkinc_, 'ellint_f_data_ipp-ellint_f_data', (0,1), 2, rtol=1e-14),
data(ellipe_, 'ellint_e_data_ipp-ellint_e_data', 0, 1),
data(ellipeinc_, 'ellint_e2_data_ipp-ellint_e2_data', (0,1), 2, rtol=1e-14),
data(erf, 'erf_data_ipp-erf_data', 0, 1),
data(erf, 'erf_data_ipp-erf_data', 0j, 1, rtol=1e-13),
data(erfc, 'erf_data_ipp-erf_data', 0, 2, rtol=6e-15),
data(erf, 'erf_large_data_ipp-erf_large_data', 0, 1),
data(erf, 'erf_large_data_ipp-erf_large_data', 0j, 1),
data(erfc, 'erf_large_data_ipp-erf_large_data', 0, 2, rtol=4e-14),
data(erf, 'erf_small_data_ipp-erf_small_data', 0, 1),
data(erf, 'erf_small_data_ipp-erf_small_data', 0j, 1, rtol=1e-13),
data(erfc, 'erf_small_data_ipp-erf_small_data', 0, 2),
data(erfinv, 'erf_inv_data_ipp-erf_inv_data', 0, 1),
data(erfcinv, 'erfc_inv_data_ipp-erfc_inv_data', 0, 1),
data(erfcinv, 'erfc_inv_big_data_ipp-erfc_inv_big_data', 0, 1, param_filter=(lambda s: s > 0)),
data(exp1, 'expint_1_data_ipp-expint_1_data', 1, 2, rtol=1e-13),
data(exp1, 'expint_1_data_ipp-expint_1_data', 1j, 2, rtol=5e-9),
data(expi, 'expinti_data_ipp-expinti_data', 0, 1, rtol=1e-13),
data(expi, 'expinti_data_double_ipp-expinti_data_double', 0, 1, rtol=1e-13),
data(expi, 'expinti_data_long_ipp-expinti_data_long', 0, 1),
data(expn, 'expint_small_data_ipp-expint_small_data', (0,1), 2),
data(expn, 'expint_data_ipp-expint_data', (0,1), 2, rtol=1e-14),
data(gamma, 'test_gamma_data_ipp-near_0', 0, 1),
data(gamma, 'test_gamma_data_ipp-near_1', 0, 1),
data(gamma, 'test_gamma_data_ipp-near_2', 0, 1),
data(gamma, 'test_gamma_data_ipp-near_m10', 0, 1),
data(gamma, 'test_gamma_data_ipp-near_m55', 0, 1, rtol=7e-12),
data(gamma, 'test_gamma_data_ipp-factorials', 0, 1, rtol=4e-14),
data(gamma, 'test_gamma_data_ipp-near_0', 0j, 1, rtol=2e-9),
data(gamma, 'test_gamma_data_ipp-near_1', 0j, 1, rtol=2e-9),
data(gamma, 'test_gamma_data_ipp-near_2', 0j, 1, rtol=2e-9),
data(gamma, 'test_gamma_data_ipp-near_m10', 0j, 1, rtol=2e-9),
data(gamma, 'test_gamma_data_ipp-near_m55', 0j, 1, rtol=2e-9),
data(gamma, 'test_gamma_data_ipp-factorials', 0j, 1, rtol=2e-13),
data(gammaln, 'test_gamma_data_ipp-near_0', 0, 2, rtol=5e-11),
data(gammaln, 'test_gamma_data_ipp-near_1', 0, 2, rtol=5e-11),
data(gammaln, 'test_gamma_data_ipp-near_2', 0, 2, rtol=2e-10),
data(gammaln, 'test_gamma_data_ipp-near_m10', 0, 2, rtol=5e-11),
data(gammaln, 'test_gamma_data_ipp-near_m55', 0, 2, rtol=5e-11),
data(gammaln, 'test_gamma_data_ipp-factorials', 0, 2),
data(gammainc, 'igamma_small_data_ipp-igamma_small_data', (0,1), 5, rtol=5e-15),
data(gammainc, 'igamma_med_data_ipp-igamma_med_data', (0,1), 5, rtol=2e-13),
data(gammainc, 'igamma_int_data_ipp-igamma_int_data', (0,1), 5, rtol=2e-13),
data(gammainc, 'igamma_big_data_ipp-igamma_big_data', (0,1), 5, rtol=1e-12),
data(gdtr_, 'igamma_small_data_ipp-igamma_small_data', (0,1), 5, rtol=1e-13),
data(gdtr_, 'igamma_med_data_ipp-igamma_med_data', (0,1), 5, rtol=2e-13),
data(gdtr_, 'igamma_int_data_ipp-igamma_int_data', (0,1), 5, rtol=2e-13),
data(gdtr_, 'igamma_big_data_ipp-igamma_big_data', (0,1), 5, rtol=2e-9),
data(gammaincc, 'igamma_small_data_ipp-igamma_small_data', (0,1), 3, rtol=1e-13),
data(gammaincc, 'igamma_med_data_ipp-igamma_med_data', (0,1), 3, rtol=2e-13),
data(gammaincc, 'igamma_int_data_ipp-igamma_int_data', (0,1), 3, rtol=4e-14),
data(gammaincc, 'igamma_big_data_ipp-igamma_big_data', (0,1), 3, rtol=1e-11),
data(gdtrc_, 'igamma_small_data_ipp-igamma_small_data', (0,1), 3, rtol=1e-13),
data(gdtrc_, 'igamma_med_data_ipp-igamma_med_data', (0,1), 3, rtol=2e-13),
data(gdtrc_, 'igamma_int_data_ipp-igamma_int_data', (0,1), 3, rtol=4e-14),
data(gdtrc_, 'igamma_big_data_ipp-igamma_big_data', (0,1), 3, rtol=1e-11),
data(gdtrib_, 'igamma_inva_data_ipp-igamma_inva_data', (1,0), 2, rtol=5e-9),
data(gdtrib_comp, 'igamma_inva_data_ipp-igamma_inva_data', (1,0), 3, rtol=5e-9),
data(poch_, 'tgamma_delta_ratio_data_ipp-tgamma_delta_ratio_data', (0,1), 2, rtol=2e-13),
data(poch_, 'tgamma_delta_ratio_int_ipp-tgamma_delta_ratio_int', (0,1), 2,),
data(poch_, 'tgamma_delta_ratio_int2_ipp-tgamma_delta_ratio_int2', (0,1), 2,),
data(poch_minus, 'tgamma_delta_ratio_data_ipp-tgamma_delta_ratio_data', (0,1), 3, rtol=2e-13),
data(poch_minus, 'tgamma_delta_ratio_int_ipp-tgamma_delta_ratio_int', (0,1), 3),
data(poch_minus, 'tgamma_delta_ratio_int2_ipp-tgamma_delta_ratio_int2', (0,1), 3),
data(eval_hermite_ld, 'hermite_ipp-hermite', (0,1), 2, rtol=2e-14),
data(eval_laguerre_ld, 'laguerre2_ipp-laguerre2', (0,1), 2, rtol=7e-12),
data(eval_laguerre_dd, 'laguerre2_ipp-laguerre2', (0,1), 2, knownfailure='hyp2f1 insufficiently accurate.'),
data(eval_genlaguerre_ldd, 'laguerre3_ipp-laguerre3', (0,1,2), 3, rtol=2e-13),
data(eval_genlaguerre_ddd, 'laguerre3_ipp-laguerre3', (0,1,2), 3, knownfailure='hyp2f1 insufficiently accurate.'),
data(log1p, 'log1p_expm1_data_ipp-log1p_expm1_data', 0, 1),
data(expm1, 'log1p_expm1_data_ipp-log1p_expm1_data', 0, 2),
data(iv, 'bessel_i_data_ipp-bessel_i_data', (0,1), 2, rtol=1e-12),
data(iv, 'bessel_i_data_ipp-bessel_i_data', (0,1j), 2, rtol=2e-10, atol=1e-306),
data(iv, 'bessel_i_int_data_ipp-bessel_i_int_data', (0,1), 2, rtol=1e-9),
data(iv, 'bessel_i_int_data_ipp-bessel_i_int_data', (0,1j), 2, rtol=2e-10),
data(ivp, 'bessel_i_prime_int_data_ipp-bessel_i_prime_int_data', (0,1), 2, rtol=1.2e-13),
data(ivp, 'bessel_i_prime_int_data_ipp-bessel_i_prime_int_data', (0,1j), 2, rtol=1.2e-13, atol=1e-300),
data(jn, 'bessel_j_int_data_ipp-bessel_j_int_data', (0,1), 2, rtol=1e-12),
data(jn, 'bessel_j_int_data_ipp-bessel_j_int_data', (0,1j), 2, rtol=1e-12),
data(jn, 'bessel_j_large_data_ipp-bessel_j_large_data', (0,1), 2, rtol=6e-11),
data(jn, 'bessel_j_large_data_ipp-bessel_j_large_data', (0,1j), 2, rtol=6e-11),
data(jv, 'bessel_j_int_data_ipp-bessel_j_int_data', (0,1), 2, rtol=1e-12),
data(jv, 'bessel_j_int_data_ipp-bessel_j_int_data', (0,1j), 2, rtol=1e-12),
data(jv, 'bessel_j_data_ipp-bessel_j_data', (0,1), 2, rtol=1e-12),
data(jv, 'bessel_j_data_ipp-bessel_j_data', (0,1j), 2, rtol=1e-12),
data(jvp, 'bessel_j_prime_int_data_ipp-bessel_j_prime_int_data', (0,1), 2, rtol=1e-13),
data(jvp, 'bessel_j_prime_int_data_ipp-bessel_j_prime_int_data', (0,1j), 2, rtol=1e-13),
data(jvp, 'bessel_j_prime_large_data_ipp-bessel_j_prime_large_data', (0,1), 2, rtol=1e-11),
data(jvp, 'bessel_j_prime_large_data_ipp-bessel_j_prime_large_data', (0,1j), 2, rtol=1e-11),
data(kn, 'bessel_k_int_data_ipp-bessel_k_int_data', (0,1), 2, rtol=1e-12),
data(kv, 'bessel_k_int_data_ipp-bessel_k_int_data', (0,1), 2, rtol=1e-12),
data(kv, 'bessel_k_int_data_ipp-bessel_k_int_data', (0,1j), 2, rtol=1e-12),
data(kv, 'bessel_k_data_ipp-bessel_k_data', (0,1), 2, rtol=1e-12),
data(kv, 'bessel_k_data_ipp-bessel_k_data', (0,1j), 2, rtol=1e-12),
data(kvp, 'bessel_k_prime_int_data_ipp-bessel_k_prime_int_data', (0,1), 2, rtol=3e-14),
data(kvp, 'bessel_k_prime_int_data_ipp-bessel_k_prime_int_data', (0,1j), 2, rtol=3e-14),
data(kvp, 'bessel_k_prime_data_ipp-bessel_k_prime_data', (0,1), 2, rtol=7e-14),
data(kvp, 'bessel_k_prime_data_ipp-bessel_k_prime_data', (0,1j), 2, rtol=7e-14),
data(yn, 'bessel_y01_data_ipp-bessel_y01_data', (0,1), 2, rtol=1e-12),
data(yn, 'bessel_yn_data_ipp-bessel_yn_data', (0,1), 2, rtol=1e-12),
data(yv, 'bessel_yn_data_ipp-bessel_yn_data', (0,1), 2, rtol=1e-12),
data(yv, 'bessel_yn_data_ipp-bessel_yn_data', (0,1j), 2, rtol=1e-12),
data(yv, 'bessel_yv_data_ipp-bessel_yv_data', (0,1), 2, rtol=1e-10),
data(yv, 'bessel_yv_data_ipp-bessel_yv_data', (0,1j), 2, rtol=1e-10),
data(yvp, 'bessel_yv_prime_data_ipp-bessel_yv_prime_data', (0, 1), 2, rtol=4e-9),
data(yvp, 'bessel_yv_prime_data_ipp-bessel_yv_prime_data', (0, 1j), 2, rtol=4e-9),
data(zeta_, 'zeta_data_ipp-zeta_data', 0, 1, param_filter=(lambda s: s > 1)),
data(zeta_, 'zeta_neg_data_ipp-zeta_neg_data', 0, 1, param_filter=(lambda s: s > 1)),
data(zeta_, 'zeta_1_up_data_ipp-zeta_1_up_data', 0, 1, param_filter=(lambda s: s > 1)),
data(zeta_, 'zeta_1_below_data_ipp-zeta_1_below_data', 0, 1, param_filter=(lambda s: s > 1)),
data(gammaincinv, 'gamma_inv_small_data_ipp-gamma_inv_small_data', (0,1), 2, rtol=1e-11),
data(gammaincinv, 'gamma_inv_data_ipp-gamma_inv_data', (0,1), 2, rtol=1e-14),
data(gammaincinv, 'gamma_inv_big_data_ipp-gamma_inv_big_data', (0,1), 2, rtol=1e-11),
data(gammainccinv, 'gamma_inv_small_data_ipp-gamma_inv_small_data', (0,1), 3, rtol=1e-12),
data(gammainccinv, 'gamma_inv_data_ipp-gamma_inv_data', (0,1), 3, rtol=1e-14),
data(gammainccinv, 'gamma_inv_big_data_ipp-gamma_inv_big_data', (0,1), 3, rtol=1e-14),
data(gdtrix_, 'gamma_inv_small_data_ipp-gamma_inv_small_data', (0,1), 2, rtol=3e-13, knownfailure='gdtrix unflow some points'),
data(gdtrix_, 'gamma_inv_data_ipp-gamma_inv_data', (0,1), 2, rtol=3e-15),
data(gdtrix_, 'gamma_inv_big_data_ipp-gamma_inv_big_data', (0,1), 2),
data(gdtrix_comp, 'gamma_inv_small_data_ipp-gamma_inv_small_data', (0,1), 2, knownfailure='gdtrix bad some points'),
data(gdtrix_comp, 'gamma_inv_data_ipp-gamma_inv_data', (0,1), 3, rtol=6e-15),
data(gdtrix_comp, 'gamma_inv_big_data_ipp-gamma_inv_big_data', (0,1), 3),
data(chndtr, 'nccs_ipp-nccs', (2,0,1), 3, rtol=3e-5),
data(chndtr, 'nccs_big_ipp-nccs_big', (2,0,1), 3, rtol=5e-4, knownfailure='chndtr inaccurate some points'),
data(sph_harm_, 'spherical_harmonic_ipp-spherical_harmonic', (1,0,3,2), (4,5), rtol=5e-11,
param_filter=(lambda p: np.ones(p.shape, '?'),
lambda p: np.ones(p.shape, '?'),
lambda p: np.logical_and(p < 2*np.pi, p >= 0),
lambda p: np.logical_and(p < np.pi, p >= 0))),
data(spherical_jn_, 'sph_bessel_data_ipp-sph_bessel_data', (0,1), 2, rtol=1e-13),
data(spherical_yn_, 'sph_neumann_data_ipp-sph_neumann_data', (0,1), 2, rtol=8e-15),
data(owens_t, 'owens_t_ipp-owens_t', (0, 1), 2, rtol=5e-14),
data(owens_t, 'owens_t_large_data_ipp-owens_t_large_data', (0, 1), 2, rtol=8e-12),
# -- test data exists in boost but is not used in scipy --
# ibeta_derivative_data_ipp/ibeta_derivative_data.txt
# ibeta_derivative_int_data_ipp/ibeta_derivative_int_data.txt
# ibeta_derivative_large_data_ipp/ibeta_derivative_large_data.txt
# ibeta_derivative_small_data_ipp/ibeta_derivative_small_data.txt
# bessel_y01_prime_data_ipp/bessel_y01_prime_data.txt
# bessel_yn_prime_data_ipp/bessel_yn_prime_data.txt
# sph_bessel_prime_data_ipp/sph_bessel_prime_data.txt
# sph_neumann_prime_data_ipp/sph_neumann_prime_data.txt
# ellint_d2_data_ipp/ellint_d2_data.txt
# ellint_d_data_ipp/ellint_d_data.txt
# ellint_pi2_data_ipp/ellint_pi2_data.txt
# ellint_pi3_data_ipp/ellint_pi3_data.txt
# ellint_pi3_large_data_ipp/ellint_pi3_large_data.txt
data(elliprc, 'ellint_rc_data_ipp-ellint_rc_data', (0, 1), 2,
rtol=5e-16),
data(elliprd, 'ellint_rd_data_ipp-ellint_rd_data', (0, 1, 2), 3,
rtol=5e-16),
data(elliprd, 'ellint_rd_0xy_ipp-ellint_rd_0xy', (0, 1, 2), 3,
rtol=5e-16),
data(elliprd, 'ellint_rd_0yy_ipp-ellint_rd_0yy', (0, 1, 2), 3,
rtol=5e-16),
data(elliprd, 'ellint_rd_xxx_ipp-ellint_rd_xxx', (0, 1, 2), 3,
rtol=5e-16),
# Some of the following rtol for elliprd may be larger than 5e-16 to
# work around some hard cases in the Boost test where we get slightly
# larger error than the ideal bound when the x (==y) input is close to
# zero.
# Also the accuracy on 32-bit buids with g++ may suffer from excess
# loss of precision; see GCC bugzilla 323
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323
data(elliprd, 'ellint_rd_xxz_ipp-ellint_rd_xxz', (0, 1, 2), 3,
rtol=6.5e-16),
data(elliprd, 'ellint_rd_xyy_ipp-ellint_rd_xyy', (0, 1, 2), 3,
rtol=6e-16),
data(elliprf, 'ellint_rf_data_ipp-ellint_rf_data', (0, 1, 2), 3,
rtol=5e-16),
data(elliprf, 'ellint_rf_xxx_ipp-ellint_rf_xxx', (0, 1, 2), 3,
rtol=5e-16),
data(elliprf, 'ellint_rf_xyy_ipp-ellint_rf_xyy', (0, 1, 2), 3,
rtol=5e-16),
data(elliprf, 'ellint_rf_xy0_ipp-ellint_rf_xy0', (0, 1, 2), 3,
rtol=5e-16),
data(elliprf, 'ellint_rf_0yy_ipp-ellint_rf_0yy', (0, 1, 2), 3,
rtol=5e-16),
# The accuracy of R_G is primarily limited by R_D that is used
# internally. It is generally worse than R_D. Notice that we increased
# the rtol for R_G here. The cases with duplicate arguments are
# slightly less likely to be unbalanced (at least two arguments are
# already balanced) so the error bound is slightly better. Again,
# precision with g++ 32-bit is even worse.
data(elliprg, 'ellint_rg_ipp-ellint_rg', (0, 1, 2), 3,
rtol=8.0e-16),
data(elliprg, 'ellint_rg_xxx_ipp-ellint_rg_xxx', (0, 1, 2), 3,
rtol=6e-16),
data(elliprg, 'ellint_rg_xyy_ipp-ellint_rg_xyy', (0, 1, 2), 3,
rtol=7.5e-16),
data(elliprg, 'ellint_rg_xy0_ipp-ellint_rg_xy0', (0, 1, 2), 3,
rtol=5e-16),
data(elliprg, 'ellint_rg_00x_ipp-ellint_rg_00x', (0, 1, 2), 3,
rtol=5e-16),
data(elliprj, 'ellint_rj_data_ipp-ellint_rj_data', (0, 1, 2, 3), 4,
rtol=5e-16, atol=1e-25,
param_filter=(lambda s: s <= 5e-26,)),
# ellint_rc_data_ipp/ellint_rc_data.txt
# ellint_rd_0xy_ipp/ellint_rd_0xy.txt
# ellint_rd_0yy_ipp/ellint_rd_0yy.txt
# ellint_rd_data_ipp/ellint_rd_data.txt
# ellint_rd_xxx_ipp/ellint_rd_xxx.txt
# ellint_rd_xxz_ipp/ellint_rd_xxz.txt
# ellint_rd_xyy_ipp/ellint_rd_xyy.txt
# ellint_rf_0yy_ipp/ellint_rf_0yy.txt
# ellint_rf_data_ipp/ellint_rf_data.txt
# ellint_rf_xxx_ipp/ellint_rf_xxx.txt
# ellint_rf_xy0_ipp/ellint_rf_xy0.txt
# ellint_rf_xyy_ipp/ellint_rf_xyy.txt
# ellint_rg_00x_ipp/ellint_rg_00x.txt
# ellint_rg_ipp/ellint_rg.txt
# ellint_rg_xxx_ipp/ellint_rg_xxx.txt
# ellint_rg_xy0_ipp/ellint_rg_xy0.txt
# ellint_rg_xyy_ipp/ellint_rg_xyy.txt
# ellint_rj_data_ipp/ellint_rj_data.txt
# ellint_rj_e2_ipp/ellint_rj_e2.txt
# ellint_rj_e3_ipp/ellint_rj_e3.txt
# ellint_rj_e4_ipp/ellint_rj_e4.txt
# ellint_rj_zp_ipp/ellint_rj_zp.txt
# jacobi_elliptic_ipp/jacobi_elliptic.txt
# jacobi_elliptic_small_ipp/jacobi_elliptic_small.txt
# jacobi_large_phi_ipp/jacobi_large_phi.txt
# jacobi_near_1_ipp/jacobi_near_1.txt
# jacobi_zeta_big_phi_ipp/jacobi_zeta_big_phi.txt
# jacobi_zeta_data_ipp/jacobi_zeta_data.txt
# heuman_lambda_data_ipp/heuman_lambda_data.txt
# hypergeometric_0F2_ipp/hypergeometric_0F2.txt
# hypergeometric_1F1_big_ipp/hypergeometric_1F1_big.txt
# hypergeometric_1F1_ipp/hypergeometric_1F1.txt
# hypergeometric_1F1_small_random_ipp/hypergeometric_1F1_small_random.txt
# hypergeometric_1F2_ipp/hypergeometric_1F2.txt
# hypergeometric_1f1_large_regularized_ipp/hypergeometric_1f1_large_regularized.txt
# hypergeometric_1f1_log_large_unsolved_ipp/hypergeometric_1f1_log_large_unsolved.txt
# hypergeometric_2F0_half_ipp/hypergeometric_2F0_half.txt
# hypergeometric_2F0_integer_a2_ipp/hypergeometric_2F0_integer_a2.txt
# hypergeometric_2F0_ipp/hypergeometric_2F0.txt
# hypergeometric_2F0_large_z_ipp/hypergeometric_2F0_large_z.txt
# hypergeometric_2F1_ipp/hypergeometric_2F1.txt
# hypergeometric_2F2_ipp/hypergeometric_2F2.txt
# ncbeta_big_ipp/ncbeta_big.txt
# nct_small_delta_ipp/nct_small_delta.txt
# nct_asym_ipp/nct_asym.txt
# ncbeta_ipp/ncbeta.txt
# powm1_data_ipp/powm1_big_data.txt
# powm1_sqrtp1m1_test_hpp/sqrtp1m1_data.txt
# sinc_data_ipp/sinc_data.txt
# test_gamma_data_ipp/gammap1m1_data.txt
# tgamma_ratio_data_ipp/tgamma_ratio_data.txt
# trig_data_ipp/trig_data.txt
# trig_data2_ipp/trig_data2.txt
]
@pytest.mark.parametrize('test', BOOST_TESTS, ids=repr)
def test_boost(test):
_test_factory(test)
GSL_TESTS = [
data_gsl(mathieu_a, 'mathieu_ab', (0, 1), 2, rtol=1e-13, atol=1e-13),
data_gsl(mathieu_b, 'mathieu_ab', (0, 1), 3, rtol=1e-13, atol=1e-13),
# Also the GSL output has limited accuracy...
data_gsl(mathieu_ce_rad, 'mathieu_ce_se', (0, 1, 2), 3, rtol=1e-7, atol=1e-13),
data_gsl(mathieu_se_rad, 'mathieu_ce_se', (0, 1, 2), 4, rtol=1e-7, atol=1e-13),
data_gsl(mathieu_mc1_scaled, 'mathieu_mc_ms', (0, 1, 2), 3, rtol=1e-7, atol=1e-13),
data_gsl(mathieu_ms1_scaled, 'mathieu_mc_ms', (0, 1, 2), 4, rtol=1e-7, atol=1e-13),
data_gsl(mathieu_mc2_scaled, 'mathieu_mc_ms', (0, 1, 2), 5, rtol=1e-7, atol=1e-13),
data_gsl(mathieu_ms2_scaled, 'mathieu_mc_ms', (0, 1, 2), 6, rtol=1e-7, atol=1e-13),
]
@pytest.mark.parametrize('test', GSL_TESTS, ids=repr)
def test_gsl(test):
_test_factory(test)
LOCAL_TESTS = [
data_local(ellipkinc, 'ellipkinc_neg_m', (0, 1), 2),
data_local(ellipkm1, 'ellipkm1', 0, 1),
data_local(ellipeinc, 'ellipeinc_neg_m', (0, 1), 2),
data_local(clog1p, 'log1p_expm1_complex', (0,1), (2,3), rtol=1e-14),
data_local(cexpm1, 'log1p_expm1_complex', (0,1), (4,5), rtol=1e-14),
data_local(gammainc, 'gammainc', (0, 1), 2, rtol=1e-12),
data_local(gammaincc, 'gammaincc', (0, 1), 2, rtol=1e-11),
data_local(ellip_harm_2, 'ellip',(0, 1, 2, 3, 4), 6, rtol=1e-10, atol=1e-13),
data_local(ellip_harm, 'ellip',(0, 1, 2, 3, 4), 5, rtol=1e-10, atol=1e-13),
data_local(wright_bessel, 'wright_bessel', (0, 1, 2), 3, rtol=1e-11),
]
@pytest.mark.parametrize('test', LOCAL_TESTS, ids=repr)
def test_local(test):
_test_factory(test)
def _test_factory(test, dtype=np.double):
"""Boost test"""
with suppress_warnings() as sup:
sup.filter(IntegrationWarning, "The occurrence of roundoff error is detected")
with np.errstate(all='ignore'):
test.check(dtype=dtype)

View File

@@ -0,0 +1,46 @@
# Tests for a few of the "double-double" C functions defined in cephes/dd_*.
import pytest
from numpy.testing import assert_allclose
from scipy.special._test_internal import _dd_exp, _dd_log, _dd_expm1
# Each tuple in test_data contains:
# (dd_func, xhi, xlo, expected_yhi, expected_ylo)
# The expected values were computed with mpmath, e.g.
#
# import mpmath
# mpmath.mp.dps = 100
# xhi = 10.0
# xlo = 0.0
# x = mpmath.mpf(xhi) + mpmath.mpf(xlo)
# y = mpmath.log(x)
# expected_yhi = float(y)
# expected_ylo = float(y - expected_yhi)
#
test_data = [
(_dd_exp, -0.3333333333333333, -1.850371707708594e-17,
0.7165313105737893, -2.0286948382455594e-17),
(_dd_exp, 0.0, 0.0, 1.0, 0.0),
(_dd_exp, 10.0, 0.0, 22026.465794806718, -1.3780134700517372e-12),
(_dd_log, 0.03125, 0.0, -3.4657359027997265, -4.930038229799327e-18),
(_dd_log, 10.0, 0.0, 2.302585092994046, -2.1707562233822494e-16),
(_dd_expm1, -1.25, 0.0, -0.7134952031398099, -4.7031321153650186e-17),
(_dd_expm1, -0.484375, 0.0, -0.3839178722093218, 7.609376052156984e-18),
(_dd_expm1, -0.25, 0.0, -0.22119921692859512, -1.0231869534531498e-17),
(_dd_expm1, -0.0625, 0.0, -0.06058693718652421, -7.077887227488846e-19),
(_dd_expm1, 0.0, 0.0, 0.0, 0.0),
(_dd_expm1, 0.0625, 3.5e-18, 0.06449445891785943, 1.4323095758164254e-18),
(_dd_expm1, 0.25, 0.0, 0.2840254166877415, -2.133257464457841e-17),
(_dd_expm1, 0.498046875, 0.0, 0.645504254608231, -9.198435524984236e-18),
(_dd_expm1, 1.25, 0.0, 2.4903429574618414, -4.604261945372796e-17)
]
@pytest.mark.parametrize('dd_func, xhi, xlo, expected_yhi, expected_ylo',
test_data)
def test_dd(dd_func, xhi, xlo, expected_yhi, expected_ylo):
yhi, ylo = dd_func(xhi, xlo)
assert yhi == expected_yhi, (f"high double ({yhi}) does not equal the "
f"expected value {expected_yhi}")
assert_allclose(ylo, expected_ylo, rtol=5e-15)

View File

@@ -0,0 +1,42 @@
import numpy as np
from numpy import pi, log, sqrt
from numpy.testing import assert_, assert_equal
from scipy.special._testutils import FuncData
import scipy.special as sc
# Euler-Mascheroni constant
euler = 0.57721566490153286
def test_consistency():
# Make sure the implementation of digamma for real arguments
# agrees with the implementation of digamma for complex arguments.
# It's all poles after -1e16
x = np.r_[-np.logspace(15, -30, 200), np.logspace(-30, 300, 200)]
dataset = np.vstack((x + 0j, sc.digamma(x))).T
FuncData(sc.digamma, dataset, 0, 1, rtol=5e-14, nan_ok=True).check()
def test_special_values():
# Test special values from Gauss's digamma theorem. See
#
# https://en.wikipedia.org/wiki/Digamma_function
dataset = [(1, -euler),
(0.5, -2*log(2) - euler),
(1/3, -pi/(2*sqrt(3)) - 3*log(3)/2 - euler),
(1/4, -pi/2 - 3*log(2) - euler),
(1/6, -pi*sqrt(3)/2 - 2*log(2) - 3*log(3)/2 - euler),
(1/8, -pi/2 - 4*log(2) - (pi + log(2 + sqrt(2)) - log(2 - sqrt(2)))/sqrt(2) - euler)]
dataset = np.asarray(dataset)
FuncData(sc.digamma, dataset, 0, 1, rtol=1e-14).check()
def test_nonfinite():
pts = [0.0, -0.0, np.inf]
std = [-np.inf, np.inf, np.inf]
assert_equal(sc.digamma(pts), std)
assert_(all(np.isnan(sc.digamma([-np.inf, -1]))))

View File

@@ -0,0 +1,278 @@
#
# Tests for the Ellipsoidal Harmonic Function,
# Distributed under the same license as SciPy itself.
#
import numpy as np
from numpy.testing import (assert_equal, assert_almost_equal, assert_allclose,
assert_, suppress_warnings)
from scipy.special._testutils import assert_func_equal
from scipy.special import ellip_harm, ellip_harm_2, ellip_normal
from scipy.integrate import IntegrationWarning
from numpy import sqrt, pi
def test_ellip_potential():
def change_coefficient(lambda1, mu, nu, h2, k2):
x = sqrt(lambda1**2*mu**2*nu**2/(h2*k2))
y = sqrt((lambda1**2 - h2)*(mu**2 - h2)*(h2 - nu**2)/(h2*(k2 - h2)))
z = sqrt((lambda1**2 - k2)*(k2 - mu**2)*(k2 - nu**2)/(k2*(k2 - h2)))
return x, y, z
def solid_int_ellip(lambda1, mu, nu, n, p, h2, k2):
return (ellip_harm(h2, k2, n, p, lambda1)*ellip_harm(h2, k2, n, p, mu)
* ellip_harm(h2, k2, n, p, nu))
def solid_int_ellip2(lambda1, mu, nu, n, p, h2, k2):
return (ellip_harm_2(h2, k2, n, p, lambda1)
* ellip_harm(h2, k2, n, p, mu)*ellip_harm(h2, k2, n, p, nu))
def summation(lambda1, mu1, nu1, lambda2, mu2, nu2, h2, k2):
tol = 1e-8
sum1 = 0
for n in range(20):
xsum = 0
for p in range(1, 2*n+2):
xsum += (4*pi*(solid_int_ellip(lambda2, mu2, nu2, n, p, h2, k2)
* solid_int_ellip2(lambda1, mu1, nu1, n, p, h2, k2)) /
(ellip_normal(h2, k2, n, p)*(2*n + 1)))
if abs(xsum) < 0.1*tol*abs(sum1):
break
sum1 += xsum
return sum1, xsum
def potential(lambda1, mu1, nu1, lambda2, mu2, nu2, h2, k2):
x1, y1, z1 = change_coefficient(lambda1, mu1, nu1, h2, k2)
x2, y2, z2 = change_coefficient(lambda2, mu2, nu2, h2, k2)
res = sqrt((x2 - x1)**2 + (y2 - y1)**2 + (z2 - z1)**2)
return 1/res
pts = [
(120, sqrt(19), 2, 41, sqrt(17), 2, 15, 25),
(120, sqrt(16), 3.2, 21, sqrt(11), 2.9, 11, 20),
]
with suppress_warnings() as sup:
sup.filter(IntegrationWarning, "The occurrence of roundoff error")
sup.filter(IntegrationWarning, "The maximum number of subdivisions")
for p in pts:
err_msg = repr(p)
exact = potential(*p)
result, last_term = summation(*p)
assert_allclose(exact, result, atol=0, rtol=1e-8, err_msg=err_msg)
assert_(abs(result - exact) < 10*abs(last_term), err_msg)
def test_ellip_norm():
def G01(h2, k2):
return 4*pi
def G11(h2, k2):
return 4*pi*h2*k2/3
def G12(h2, k2):
return 4*pi*h2*(k2 - h2)/3
def G13(h2, k2):
return 4*pi*k2*(k2 - h2)/3
def G22(h2, k2):
res = (2*(h2**4 + k2**4) - 4*h2*k2*(h2**2 + k2**2) + 6*h2**2*k2**2 +
sqrt(h2**2 + k2**2 - h2*k2)*(-2*(h2**3 + k2**3) + 3*h2*k2*(h2 + k2)))
return 16*pi/405*res
def G21(h2, k2):
res = (2*(h2**4 + k2**4) - 4*h2*k2*(h2**2 + k2**2) + 6*h2**2*k2**2
+ sqrt(h2**2 + k2**2 - h2*k2)*(2*(h2**3 + k2**3) - 3*h2*k2*(h2 + k2)))
return 16*pi/405*res
def G23(h2, k2):
return 4*pi*h2**2*k2*(k2 - h2)/15
def G24(h2, k2):
return 4*pi*h2*k2**2*(k2 - h2)/15
def G25(h2, k2):
return 4*pi*h2*k2*(k2 - h2)**2/15
def G32(h2, k2):
res = (16*(h2**4 + k2**4) - 36*h2*k2*(h2**2 + k2**2) + 46*h2**2*k2**2
+ sqrt(4*(h2**2 + k2**2) - 7*h2*k2)*(-8*(h2**3 + k2**3) +
11*h2*k2*(h2 + k2)))
return 16*pi/13125*k2*h2*res
def G31(h2, k2):
res = (16*(h2**4 + k2**4) - 36*h2*k2*(h2**2 + k2**2) + 46*h2**2*k2**2
+ sqrt(4*(h2**2 + k2**2) - 7*h2*k2)*(8*(h2**3 + k2**3) -
11*h2*k2*(h2 + k2)))
return 16*pi/13125*h2*k2*res
def G34(h2, k2):
res = (6*h2**4 + 16*k2**4 - 12*h2**3*k2 - 28*h2*k2**3 + 34*h2**2*k2**2
+ sqrt(h2**2 + 4*k2**2 - h2*k2)*(-6*h2**3 - 8*k2**3 + 9*h2**2*k2 +
13*h2*k2**2))
return 16*pi/13125*h2*(k2 - h2)*res
def G33(h2, k2):
res = (6*h2**4 + 16*k2**4 - 12*h2**3*k2 - 28*h2*k2**3 + 34*h2**2*k2**2
+ sqrt(h2**2 + 4*k2**2 - h2*k2)*(6*h2**3 + 8*k2**3 - 9*h2**2*k2 -
13*h2*k2**2))
return 16*pi/13125*h2*(k2 - h2)*res
def G36(h2, k2):
res = (16*h2**4 + 6*k2**4 - 28*h2**3*k2 - 12*h2*k2**3 + 34*h2**2*k2**2
+ sqrt(4*h2**2 + k2**2 - h2*k2)*(-8*h2**3 - 6*k2**3 + 13*h2**2*k2 +
9*h2*k2**2))
return 16*pi/13125*k2*(k2 - h2)*res
def G35(h2, k2):
res = (16*h2**4 + 6*k2**4 - 28*h2**3*k2 - 12*h2*k2**3 + 34*h2**2*k2**2
+ sqrt(4*h2**2 + k2**2 - h2*k2)*(8*h2**3 + 6*k2**3 - 13*h2**2*k2 -
9*h2*k2**2))
return 16*pi/13125*k2*(k2 - h2)*res
def G37(h2, k2):
return 4*pi*h2**2*k2**2*(k2 - h2)**2/105
known_funcs = {(0, 1): G01, (1, 1): G11, (1, 2): G12, (1, 3): G13,
(2, 1): G21, (2, 2): G22, (2, 3): G23, (2, 4): G24,
(2, 5): G25, (3, 1): G31, (3, 2): G32, (3, 3): G33,
(3, 4): G34, (3, 5): G35, (3, 6): G36, (3, 7): G37}
def _ellip_norm(n, p, h2, k2):
func = known_funcs[n, p]
return func(h2, k2)
_ellip_norm = np.vectorize(_ellip_norm)
def ellip_normal_known(h2, k2, n, p):
return _ellip_norm(n, p, h2, k2)
# generate both large and small h2 < k2 pairs
np.random.seed(1234)
h2 = np.random.pareto(0.5, size=1)
k2 = h2 * (1 + np.random.pareto(0.5, size=h2.size))
points = []
for n in range(4):
for p in range(1, 2*n+2):
points.append((h2, k2, np.full(h2.size, n), np.full(h2.size, p)))
points = np.array(points)
with suppress_warnings() as sup:
sup.filter(IntegrationWarning, "The occurrence of roundoff error")
assert_func_equal(ellip_normal, ellip_normal_known, points, rtol=1e-12)
def test_ellip_harm_2():
def I1(h2, k2, s):
res = (ellip_harm_2(h2, k2, 1, 1, s)/(3 * ellip_harm(h2, k2, 1, 1, s))
+ ellip_harm_2(h2, k2, 1, 2, s)/(3 * ellip_harm(h2, k2, 1, 2, s)) +
ellip_harm_2(h2, k2, 1, 3, s)/(3 * ellip_harm(h2, k2, 1, 3, s)))
return res
with suppress_warnings() as sup:
sup.filter(IntegrationWarning, "The occurrence of roundoff error")
assert_almost_equal(I1(5, 8, 10), 1/(10*sqrt((100-5)*(100-8))))
# Values produced by code from arXiv:1204.0267
assert_almost_equal(ellip_harm_2(5, 8, 2, 1, 10), 0.00108056853382)
assert_almost_equal(ellip_harm_2(5, 8, 2, 2, 10), 0.00105820513809)
assert_almost_equal(ellip_harm_2(5, 8, 2, 3, 10), 0.00106058384743)
assert_almost_equal(ellip_harm_2(5, 8, 2, 4, 10), 0.00106774492306)
assert_almost_equal(ellip_harm_2(5, 8, 2, 5, 10), 0.00107976356454)
def test_ellip_harm():
def E01(h2, k2, s):
return 1
def E11(h2, k2, s):
return s
def E12(h2, k2, s):
return sqrt(abs(s*s - h2))
def E13(h2, k2, s):
return sqrt(abs(s*s - k2))
def E21(h2, k2, s):
return s*s - 1/3*((h2 + k2) + sqrt(abs((h2 + k2)*(h2 + k2)-3*h2*k2)))
def E22(h2, k2, s):
return s*s - 1/3*((h2 + k2) - sqrt(abs((h2 + k2)*(h2 + k2)-3*h2*k2)))
def E23(h2, k2, s):
return s * sqrt(abs(s*s - h2))
def E24(h2, k2, s):
return s * sqrt(abs(s*s - k2))
def E25(h2, k2, s):
return sqrt(abs((s*s - h2)*(s*s - k2)))
def E31(h2, k2, s):
return s*s*s - (s/5)*(2*(h2 + k2) + sqrt(4*(h2 + k2)*(h2 + k2) -
15*h2*k2))
def E32(h2, k2, s):
return s*s*s - (s/5)*(2*(h2 + k2) - sqrt(4*(h2 + k2)*(h2 + k2) -
15*h2*k2))
def E33(h2, k2, s):
return sqrt(abs(s*s - h2))*(s*s - 1/5*((h2 + 2*k2) + sqrt(abs((h2 +
2*k2)*(h2 + 2*k2) - 5*h2*k2))))
def E34(h2, k2, s):
return sqrt(abs(s*s - h2))*(s*s - 1/5*((h2 + 2*k2) - sqrt(abs((h2 +
2*k2)*(h2 + 2*k2) - 5*h2*k2))))
def E35(h2, k2, s):
return sqrt(abs(s*s - k2))*(s*s - 1/5*((2*h2 + k2) + sqrt(abs((2*h2
+ k2)*(2*h2 + k2) - 5*h2*k2))))
def E36(h2, k2, s):
return sqrt(abs(s*s - k2))*(s*s - 1/5*((2*h2 + k2) - sqrt(abs((2*h2
+ k2)*(2*h2 + k2) - 5*h2*k2))))
def E37(h2, k2, s):
return s * sqrt(abs((s*s - h2)*(s*s - k2)))
assert_equal(ellip_harm(5, 8, 1, 2, 2.5, 1, 1),
ellip_harm(5, 8, 1, 2, 2.5))
known_funcs = {(0, 1): E01, (1, 1): E11, (1, 2): E12, (1, 3): E13,
(2, 1): E21, (2, 2): E22, (2, 3): E23, (2, 4): E24,
(2, 5): E25, (3, 1): E31, (3, 2): E32, (3, 3): E33,
(3, 4): E34, (3, 5): E35, (3, 6): E36, (3, 7): E37}
point_ref = []
def ellip_harm_known(h2, k2, n, p, s):
for i in range(h2.size):
func = known_funcs[(int(n[i]), int(p[i]))]
point_ref.append(func(h2[i], k2[i], s[i]))
return point_ref
np.random.seed(1234)
h2 = np.random.pareto(0.5, size=30)
k2 = h2*(1 + np.random.pareto(0.5, size=h2.size))
s = np.random.pareto(0.5, size=h2.size)
points = []
for i in range(h2.size):
for n in range(4):
for p in range(1, 2*n+2):
points.append((h2[i], k2[i], n, p, s[i]))
points = np.array(points)
assert_func_equal(ellip_harm, ellip_harm_known, points, rtol=1e-12)
def test_ellip_harm_invalid_p():
# Regression test. This should return nan.
n = 4
# Make p > 2*n + 1.
p = 2*n + 2
result = ellip_harm(0.5, 2.0, n, p, 0.2)
assert np.isnan(result)

View File

@@ -0,0 +1,89 @@
import numpy as np
from numpy.testing import assert_allclose, assert_equal
import pytest
import scipy.special as sc
class TestInverseErrorFunction:
def test_compliment(self):
# Test erfcinv(1 - x) == erfinv(x)
x = np.linspace(-1, 1, 101)
assert_allclose(sc.erfcinv(1 - x), sc.erfinv(x), rtol=0, atol=1e-15)
def test_literal_values(self):
# The expected values were calculated with mpmath:
#
# import mpmath
# mpmath.mp.dps = 200
# for y in [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]:
# x = mpmath.erfinv(y)
# print(x)
#
y = np.array([0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])
actual = sc.erfinv(y)
expected = [
0.0,
0.08885599049425769,
0.1791434546212917,
0.2724627147267543,
0.37080715859355795,
0.4769362762044699,
0.5951160814499948,
0.7328690779592167,
0.9061938024368233,
1.1630871536766743,
]
assert_allclose(actual, expected, rtol=0, atol=1e-15)
@pytest.mark.parametrize(
'f, x, y',
[
(sc.erfinv, -1, -np.inf),
(sc.erfinv, 0, 0),
(sc.erfinv, 1, np.inf),
(sc.erfinv, -100, np.nan),
(sc.erfinv, 100, np.nan),
(sc.erfcinv, 0, np.inf),
(sc.erfcinv, 1, -0.0),
(sc.erfcinv, 2, -np.inf),
(sc.erfcinv, -100, np.nan),
(sc.erfcinv, 100, np.nan),
],
ids=[
'erfinv at lower bound',
'erfinv at midpoint',
'erfinv at upper bound',
'erfinv below lower bound',
'erfinv above upper bound',
'erfcinv at lower bound',
'erfcinv at midpoint',
'erfcinv at upper bound',
'erfcinv below lower bound',
'erfcinv above upper bound',
]
)
def test_domain_bounds(self, f, x, y):
assert_equal(f(x), y)
def test_erfinv_asympt(self):
# regression test for gh-12758: erfinv(x) loses precision at small x
# expected values precomputed with mpmath:
# >>> mpmath.mp.dps = 100
# >>> expected = [float(mpmath.erfinv(t)) for t in x]
x = np.array([1e-20, 1e-15, 1e-14, 1e-10, 1e-8, 0.9e-7, 1.1e-7, 1e-6])
expected = np.array([8.86226925452758e-21,
8.862269254527581e-16,
8.86226925452758e-15,
8.862269254527581e-11,
8.86226925452758e-09,
7.97604232907484e-08,
9.74849617998037e-08,
8.8622692545299e-07])
assert_allclose(sc.erfinv(x), expected,
rtol=1e-15)
# also test the roundtrip consistency
assert_allclose(sc.erf(sc.erfinv(x)),
x,
rtol=5e-15)

View File

@@ -0,0 +1,75 @@
import pytest
import numpy as np
from numpy.testing import assert_allclose
import scipy.special as sc
class TestExp1:
def test_branch_cut(self):
assert np.isnan(sc.exp1(-1))
assert sc.exp1(complex(-1, 0)).imag == (
-sc.exp1(complex(-1, -0.0)).imag
)
assert_allclose(
sc.exp1(complex(-1, 0)),
sc.exp1(-1 + 1e-20j),
atol=0,
rtol=1e-15
)
assert_allclose(
sc.exp1(complex(-1, -0.0)),
sc.exp1(-1 - 1e-20j),
atol=0,
rtol=1e-15
)
def test_834(self):
# Regression test for #834
a = sc.exp1(-complex(19.9999990))
b = sc.exp1(-complex(19.9999991))
assert_allclose(a.imag, b.imag, atol=0, rtol=1e-15)
class TestExpi:
@pytest.mark.parametrize('result', [
sc.expi(complex(-1, 0)),
sc.expi(complex(-1, -0.0)),
sc.expi(-1)
])
def test_branch_cut(self, result):
desired = -0.21938393439552027368 # Computed using Mpmath
assert_allclose(result, desired, atol=0, rtol=1e-14)
def test_near_branch_cut(self):
lim_from_above = sc.expi(-1 + 1e-20j)
lim_from_below = sc.expi(-1 - 1e-20j)
assert_allclose(
lim_from_above.real,
lim_from_below.real,
atol=0,
rtol=1e-15
)
assert_allclose(
lim_from_above.imag,
-lim_from_below.imag,
atol=0,
rtol=1e-15
)
def test_continuity_on_positive_real_axis(self):
assert_allclose(
sc.expi(complex(1, 0)),
sc.expi(complex(1, -0.0)),
atol=0,
rtol=1e-15
)
class TestExpn:
def test_out_of_domain(self):
assert all(np.isnan([sc.expn(-1, 1.0), sc.expn(1, -1.0)]))

View File

@@ -0,0 +1,85 @@
import pytest
import numpy as np
from numpy.testing import assert_allclose
import scipy.special as sc
from scipy.special._testutils import FuncData
class TestVoigtProfile:
@pytest.mark.parametrize('x, sigma, gamma', [
(np.nan, 1, 1),
(0, np.nan, 1),
(0, 1, np.nan),
(1, np.nan, 0),
(np.nan, 1, 0),
(1, 0, np.nan),
(np.nan, 0, 1),
(np.nan, 0, 0)
])
def test_nan(self, x, sigma, gamma):
assert np.isnan(sc.voigt_profile(x, sigma, gamma))
@pytest.mark.parametrize('x, desired', [
(-np.inf, 0),
(np.inf, 0)
])
def test_inf(self, x, desired):
assert sc.voigt_profile(x, 1, 1) == desired
def test_against_mathematica(self):
# Results obtained from Mathematica by computing
#
# PDF[VoigtDistribution[gamma, sigma], x]
#
points = np.array([
[-7.89, 45.06, 6.66, 0.0077921073660388806401],
[-0.05, 7.98, 24.13, 0.012068223646769913478],
[-13.98, 16.83, 42.37, 0.0062442236362132357833],
[-12.66, 0.21, 6.32, 0.010052516161087379402],
[11.34, 4.25, 21.96, 0.0113698923627278917805],
[-11.56, 20.40, 30.53, 0.0076332760432097464987],
[-9.17, 25.61, 8.32, 0.011646345779083005429],
[16.59, 18.05, 2.50, 0.013637768837526809181],
[9.11, 2.12, 39.33, 0.0076644040807277677585],
[-43.33, 0.30, 45.68, 0.0036680463875330150996]
])
FuncData(
sc.voigt_profile,
points,
(0, 1, 2),
3,
atol=0,
rtol=1e-15
).check()
def test_symmetry(self):
x = np.linspace(0, 10, 20)
assert_allclose(
sc.voigt_profile(x, 1, 1),
sc.voigt_profile(-x, 1, 1),
rtol=1e-15,
atol=0
)
@pytest.mark.parametrize('x, sigma, gamma, desired', [
(0, 0, 0, np.inf),
(1, 0, 0, 0)
])
def test_corner_cases(self, x, sigma, gamma, desired):
assert sc.voigt_profile(x, sigma, gamma) == desired
@pytest.mark.parametrize('sigma1, gamma1, sigma2, gamma2', [
(0, 1, 1e-16, 1),
(1, 0, 1, 1e-16),
(0, 0, 1e-16, 1e-16)
])
def test_continuity(self, sigma1, gamma1, sigma2, gamma2):
x = np.linspace(1, 10, 20)
assert_allclose(
sc.voigt_profile(x, sigma1, gamma1),
sc.voigt_profile(x, sigma2, gamma2),
rtol=1e-16,
atol=1e-16
)

View File

@@ -0,0 +1,12 @@
import numpy as np
import scipy.special as sc
class TestRgamma:
def test_gh_11315(self):
assert sc.rgamma(-35) == 0
def test_rgamma_zeros(self):
x = np.array([0, -10, -100, -1000, -10000])
assert np.all(sc.rgamma(x) == 0)

View File

@@ -0,0 +1,136 @@
import pytest
import numpy as np
from numpy.testing import assert_allclose, assert_array_equal
import scipy.special as sc
from scipy.special._testutils import FuncData
INVALID_POINTS = [
(1, -1),
(0, 0),
(-1, 1),
(np.nan, 1),
(1, np.nan)
]
class TestGammainc:
@pytest.mark.parametrize('a, x', INVALID_POINTS)
def test_domain(self, a, x):
assert np.isnan(sc.gammainc(a, x))
def test_a_eq_0_x_gt_0(self):
assert sc.gammainc(0, 1) == 1
@pytest.mark.parametrize('a, x, desired', [
(np.inf, 1, 0),
(np.inf, 0, 0),
(np.inf, np.inf, np.nan),
(1, np.inf, 1)
])
def test_infinite_arguments(self, a, x, desired):
result = sc.gammainc(a, x)
if np.isnan(desired):
assert np.isnan(result)
else:
assert result == desired
def test_infinite_limits(self):
# Test that large arguments converge to the hard-coded limits
# at infinity.
assert_allclose(
sc.gammainc(1000, 100),
sc.gammainc(np.inf, 100),
atol=1e-200, # Use `atol` since the function converges to 0.
rtol=0
)
assert sc.gammainc(100, 1000) == sc.gammainc(100, np.inf)
def test_x_zero(self):
a = np.arange(1, 10)
assert_array_equal(sc.gammainc(a, 0), 0)
def test_limit_check(self):
result = sc.gammainc(1e-10, 1)
limit = sc.gammainc(0, 1)
assert np.isclose(result, limit)
def gammainc_line(self, x):
# The line a = x where a simpler asymptotic expansion (analog
# of DLMF 8.12.15) is available.
c = np.array([-1/3, -1/540, 25/6048, 101/155520,
-3184811/3695155200, -2745493/8151736420])
res = 0
xfac = 1
for ck in c:
res -= ck*xfac
xfac /= x
res /= np.sqrt(2*np.pi*x)
res += 0.5
return res
def test_line(self):
x = np.logspace(np.log10(25), 300, 500)
a = x
dataset = np.vstack((a, x, self.gammainc_line(x))).T
FuncData(sc.gammainc, dataset, (0, 1), 2, rtol=1e-11).check()
def test_roundtrip(self):
a = np.logspace(-5, 10, 100)
x = np.logspace(-5, 10, 100)
y = sc.gammaincinv(a, sc.gammainc(a, x))
assert_allclose(x, y, rtol=1e-10)
class TestGammaincc:
@pytest.mark.parametrize('a, x', INVALID_POINTS)
def test_domain(self, a, x):
assert np.isnan(sc.gammaincc(a, x))
def test_a_eq_0_x_gt_0(self):
assert sc.gammaincc(0, 1) == 0
@pytest.mark.parametrize('a, x, desired', [
(np.inf, 1, 1),
(np.inf, 0, 1),
(np.inf, np.inf, np.nan),
(1, np.inf, 0)
])
def test_infinite_arguments(self, a, x, desired):
result = sc.gammaincc(a, x)
if np.isnan(desired):
assert np.isnan(result)
else:
assert result == desired
def test_infinite_limits(self):
# Test that large arguments converge to the hard-coded limits
# at infinity.
assert sc.gammaincc(1000, 100) == sc.gammaincc(np.inf, 100)
assert_allclose(
sc.gammaincc(100, 1000),
sc.gammaincc(100, np.inf),
atol=1e-200, # Use `atol` since the function converges to 0.
rtol=0
)
def test_limit_check(self):
result = sc.gammaincc(1e-10,1)
limit = sc.gammaincc(0,1)
assert np.isclose(result, limit)
def test_x_zero(self):
a = np.arange(1, 10)
assert_array_equal(sc.gammaincc(a, 0), 1)
def test_roundtrip(self):
a = np.logspace(-5, 10, 100)
x = np.logspace(-5, 10, 100)
y = sc.gammainccinv(a, sc.gammaincc(a, x))
assert_allclose(x, y, rtol=1e-14)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,140 @@
import pytest
import numpy as np
from numpy.testing import assert_allclose, assert_equal
import scipy.special as sc
class TestHyperu:
def test_negative_x(self):
a, b, x = np.meshgrid(
[-1, -0.5, 0, 0.5, 1],
[-1, -0.5, 0, 0.5, 1],
np.linspace(-100, -1, 10),
)
assert np.all(np.isnan(sc.hyperu(a, b, x)))
def test_special_cases(self):
assert sc.hyperu(0, 1, 1) == 1.0
@pytest.mark.parametrize('a', [0.5, 1, np.nan])
@pytest.mark.parametrize('b', [1, 2, np.nan])
@pytest.mark.parametrize('x', [0.25, 3, np.nan])
def test_nan_inputs(self, a, b, x):
assert np.isnan(sc.hyperu(a, b, x)) == np.any(np.isnan([a, b, x]))
class TestHyp1f1:
@pytest.mark.parametrize('a, b, x', [
(np.nan, 1, 1),
(1, np.nan, 1),
(1, 1, np.nan)
])
def test_nan_inputs(self, a, b, x):
assert np.isnan(sc.hyp1f1(a, b, x))
def test_poles(self):
assert_equal(sc.hyp1f1(1, [0, -1, -2, -3, -4], 0.5), np.infty)
@pytest.mark.parametrize('a, b, x, result', [
(-1, 1, 0.5, 0.5),
(1, 1, 0.5, 1.6487212707001281468),
(2, 1, 0.5, 2.4730819060501922203),
(1, 2, 0.5, 1.2974425414002562937),
(-10, 1, 0.5, -0.38937441413785204475)
])
def test_special_cases(self, a, b, x, result):
# Hit all the special case branches at the beginning of the
# function. Desired answers computed using Mpmath.
assert_allclose(sc.hyp1f1(a, b, x), result, atol=0, rtol=1e-15)
@pytest.mark.parametrize('a, b, x, result', [
(1, 1, 0.44, 1.5527072185113360455),
(-1, 1, 0.44, 0.55999999999999999778),
(100, 100, 0.89, 2.4351296512898745592),
(-100, 100, 0.89, 0.40739062490768104667),
(1.5, 100, 59.99, 3.8073513625965598107),
(-1.5, 100, 59.99, 0.25099240047125826943)
])
def test_geometric_convergence(self, a, b, x, result):
# Test the region where we are relying on the ratio of
#
# (|a| + 1) * |x| / |b|
#
# being small. Desired answers computed using Mpmath
assert_allclose(sc.hyp1f1(a, b, x), result, atol=0, rtol=1e-15)
@pytest.mark.parametrize('a, b, x, result', [
(-1, 1, 1.5, -0.5),
(-10, 1, 1.5, 0.41801777430943080357),
(-25, 1, 1.5, 0.25114491646037839809),
(-50, 1, 1.5, -0.25683643975194756115),
(-80, 1, 1.5, -0.24554329325751503601),
(-150, 1, 1.5, -0.173364795515420454496),
])
def test_a_negative_integer(self, a, b, x, result):
# Desired answers computed using Mpmath.
assert_allclose(sc.hyp1f1(a, b, x), result, atol=0, rtol=1e-14)
@pytest.mark.parametrize('a, b, x, expected', [
(0.01, 150, -4, 0.99973683897677527773), # gh-3492
(1, 5, 0.01, 1.0020033381011970966), # gh-3593
(50, 100, 0.01, 1.0050126452421463411), # gh-3593
(1, 0.3, -1e3, -7.011932249442947651455e-04), # gh-14149
(1, 0.3, -1e4, -7.001190321418937164734e-05), # gh-14149
(9, 8.5, -350, -5.224090831922378361082e-20), # gh-17120
(9, 8.5, -355, -4.595407159813368193322e-20), # gh-17120
(75, -123.5, 15, 3.425753920814889017493e+06),
])
def test_assorted_cases(self, a, b, x, expected):
# Expected values were computed with mpmath.hyp1f1(a, b, x).
assert_allclose(sc.hyp1f1(a, b, x), expected, atol=0, rtol=1e-14)
def test_a_neg_int_and_b_equal_x(self):
# This is a case where the Boost wrapper will call hypergeometric_pFq
# instead of hypergeometric_1F1. When we use a version of Boost in
# which https://github.com/boostorg/math/issues/833 is fixed, this
# test case can probably be moved into test_assorted_cases.
# The expected value was computed with mpmath.hyp1f1(a, b, x).
a = -10.0
b = 2.5
x = 2.5
expected = 0.0365323664364104338721
computed = sc.hyp1f1(a, b, x)
assert_allclose(computed, expected, atol=0, rtol=1e-13)
@pytest.mark.parametrize('a, b, x, desired', [
(-1, -2, 2, 2),
(-1, -4, 10, 3.5),
(-2, -2, 1, 2.5)
])
def test_gh_11099(self, a, b, x, desired):
# All desired results computed using Mpmath
assert sc.hyp1f1(a, b, x) == desired
@pytest.mark.parametrize('a', [-3, -2])
def test_x_zero_a_and_b_neg_ints_and_a_ge_b(self, a):
assert sc.hyp1f1(a, -3, 0) == 1
# The "legacy edge cases" mentioned in the comments in the following
# tests refers to the behavior of hyp1f1(a, b, x) when b is a nonpositive
# integer. In some subcases, the behavior of SciPy does not match that
# of Boost (1.81+), mpmath and Mathematica (via Wolfram Alpha online).
# If the handling of these edges cases is changed to agree with those
# libraries, these test will have to be updated.
@pytest.mark.parametrize('b', [0, -1, -5])
def test_legacy_case1(self, b):
# Test results of hyp1f1(0, n, x) for n <= 0.
# This is a legacy edge case.
# Boost (versions greater than 1.80), Mathematica (via Wolfram Alpha
# online) and mpmath all return 1 in this case, but SciPy's hyp1f1
# returns inf.
assert_equal(sc.hyp1f1(0, b, [-1.5, 0, 1.5]), [np.inf, np.inf, np.inf])
def test_legacy_case2(self):
# This is a legacy edge case.
# In software such as boost (1.81+), mpmath and Mathematica,
# the value is 1.
assert sc.hyp1f1(-4, -3, 0) == np.inf

View File

@@ -0,0 +1,412 @@
import itertools
import sys
import pytest
import numpy as np
from numpy.testing import assert_
from scipy.special._testutils import FuncData
from scipy.special import kolmogorov, kolmogi, smirnov, smirnovi
from scipy.special._ufuncs import (_kolmogc, _kolmogci, _kolmogp,
_smirnovc, _smirnovci, _smirnovp)
_rtol = 1e-10
class TestSmirnov:
def test_nan(self):
assert_(np.isnan(smirnov(1, np.nan)))
def test_basic(self):
dataset = [(1, 0.1, 0.9),
(1, 0.875, 0.125),
(2, 0.875, 0.125 * 0.125),
(3, 0.875, 0.125 * 0.125 * 0.125)]
dataset = np.asarray(dataset)
FuncData(smirnov, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
dataset[:, -1] = 1 - dataset[:, -1]
FuncData(_smirnovc, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
def test_x_equals_0(self):
dataset = [(n, 0, 1) for n in itertools.chain(range(2, 20), range(1010, 1020))]
dataset = np.asarray(dataset)
FuncData(smirnov, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
dataset[:, -1] = 1 - dataset[:, -1]
FuncData(_smirnovc, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
def test_x_equals_1(self):
dataset = [(n, 1, 0) for n in itertools.chain(range(2, 20), range(1010, 1020))]
dataset = np.asarray(dataset)
FuncData(smirnov, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
dataset[:, -1] = 1 - dataset[:, -1]
FuncData(_smirnovc, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
def test_x_equals_0point5(self):
dataset = [(1, 0.5, 0.5),
(2, 0.5, 0.25),
(3, 0.5, 0.166666666667),
(4, 0.5, 0.09375),
(5, 0.5, 0.056),
(6, 0.5, 0.0327932098765),
(7, 0.5, 0.0191958707681),
(8, 0.5, 0.0112953186035),
(9, 0.5, 0.00661933257355),
(10, 0.5, 0.003888705)]
dataset = np.asarray(dataset)
FuncData(smirnov, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
dataset[:, -1] = 1 - dataset[:, -1]
FuncData(_smirnovc, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
def test_n_equals_1(self):
x = np.linspace(0, 1, 101, endpoint=True)
dataset = np.column_stack([[1]*len(x), x, 1-x])
FuncData(smirnov, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
dataset[:, -1] = 1 - dataset[:, -1]
FuncData(_smirnovc, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
def test_n_equals_2(self):
x = np.linspace(0.5, 1, 101, endpoint=True)
p = np.power(1-x, 2)
n = np.array([2] * len(x))
dataset = np.column_stack([n, x, p])
FuncData(smirnov, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
dataset[:, -1] = 1 - dataset[:, -1]
FuncData(_smirnovc, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
def test_n_equals_3(self):
x = np.linspace(0.7, 1, 31, endpoint=True)
p = np.power(1-x, 3)
n = np.array([3] * len(x))
dataset = np.column_stack([n, x, p])
FuncData(smirnov, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
dataset[:, -1] = 1 - dataset[:, -1]
FuncData(_smirnovc, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
def test_n_large(self):
# test for large values of n
# Probabilities should go down as n goes up
x = 0.4
pvals = np.array([smirnov(n, x) for n in range(400, 1100, 20)])
dfs = np.diff(pvals)
assert_(np.all(dfs <= 0), msg='Not all diffs negative %s' % dfs)
class TestSmirnovi:
def test_nan(self):
assert_(np.isnan(smirnovi(1, np.nan)))
def test_basic(self):
dataset = [(1, 0.4, 0.6),
(1, 0.6, 0.4),
(1, 0.99, 0.01),
(1, 0.01, 0.99),
(2, 0.125 * 0.125, 0.875),
(3, 0.125 * 0.125 * 0.125, 0.875),
(10, 1.0 / 16 ** 10, 1 - 1.0 / 16)]
dataset = np.asarray(dataset)
FuncData(smirnovi, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
dataset[:, 1] = 1 - dataset[:, 1]
FuncData(_smirnovci, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
def test_x_equals_0(self):
dataset = [(n, 0, 1) for n in itertools.chain(range(2, 20), range(1010, 1020))]
dataset = np.asarray(dataset)
FuncData(smirnovi, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
dataset[:, 1] = 1 - dataset[:, 1]
FuncData(_smirnovci, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
def test_x_equals_1(self):
dataset = [(n, 1, 0) for n in itertools.chain(range(2, 20), range(1010, 1020))]
dataset = np.asarray(dataset)
FuncData(smirnovi, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
dataset[:, 1] = 1 - dataset[:, 1]
FuncData(_smirnovci, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
def test_n_equals_1(self):
pp = np.linspace(0, 1, 101, endpoint=True)
# dataset = np.array([(1, p, 1-p) for p in pp])
dataset = np.column_stack([[1]*len(pp), pp, 1-pp])
FuncData(smirnovi, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
dataset[:, 1] = 1 - dataset[:, 1]
FuncData(_smirnovci, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
def test_n_equals_2(self):
x = np.linspace(0.5, 1, 101, endpoint=True)
p = np.power(1-x, 2)
n = np.array([2] * len(x))
dataset = np.column_stack([n, p, x])
FuncData(smirnovi, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
dataset[:, 1] = 1 - dataset[:, 1]
FuncData(_smirnovci, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
def test_n_equals_3(self):
x = np.linspace(0.7, 1, 31, endpoint=True)
p = np.power(1-x, 3)
n = np.array([3] * len(x))
dataset = np.column_stack([n, p, x])
FuncData(smirnovi, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
dataset[:, 1] = 1 - dataset[:, 1]
FuncData(_smirnovci, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
def test_round_trip(self):
def _sm_smi(n, p):
return smirnov(n, smirnovi(n, p))
def _smc_smci(n, p):
return _smirnovc(n, _smirnovci(n, p))
dataset = [(1, 0.4, 0.4),
(1, 0.6, 0.6),
(2, 0.875, 0.875),
(3, 0.875, 0.875),
(3, 0.125, 0.125),
(10, 0.999, 0.999),
(10, 0.0001, 0.0001)]
dataset = np.asarray(dataset)
FuncData(_sm_smi, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
FuncData(_smc_smci, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
def test_x_equals_0point5(self):
dataset = [(1, 0.5, 0.5),
(2, 0.5, 0.366025403784),
(2, 0.25, 0.5),
(3, 0.5, 0.297156508177),
(4, 0.5, 0.255520481121),
(5, 0.5, 0.234559536069),
(6, 0.5, 0.21715965898),
(7, 0.5, 0.202722580034),
(8, 0.5, 0.190621765256),
(9, 0.5, 0.180363501362),
(10, 0.5, 0.17157867006)]
dataset = np.asarray(dataset)
FuncData(smirnovi, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
dataset[:, 1] = 1 - dataset[:, 1]
FuncData(_smirnovci, dataset, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
class TestSmirnovp:
def test_nan(self):
assert_(np.isnan(_smirnovp(1, np.nan)))
def test_basic(self):
# Check derivative at endpoints
n1_10 = np.arange(1, 10)
dataset0 = np.column_stack([n1_10, np.full_like(n1_10, 0), np.full_like(n1_10, -1)])
FuncData(_smirnovp, dataset0, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
n2_10 = np.arange(2, 10)
dataset1 = np.column_stack([n2_10, np.full_like(n2_10, 1.0), np.full_like(n2_10, 0)])
FuncData(_smirnovp, dataset1, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
def test_oneminusoneovern(self):
# Check derivative at x=1-1/n
n = np.arange(1, 20)
x = 1.0/n
xm1 = 1-1.0/n
pp1 = -n * x**(n-1)
pp1 -= (1-np.sign(n-2)**2) * 0.5 # n=2, x=0.5, 1-1/n = 0.5, need to adjust
dataset1 = np.column_stack([n, xm1, pp1])
FuncData(_smirnovp, dataset1, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
def test_oneovertwon(self):
# Check derivative at x=1/2n (Discontinuous at x=1/n, so check at x=1/2n)
n = np.arange(1, 20)
x = 1.0/2/n
pp = -(n*x+1) * (1+x)**(n-2)
dataset0 = np.column_stack([n, x, pp])
FuncData(_smirnovp, dataset0, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
def test_oneovern(self):
# Check derivative at x=1/n (Discontinuous at x=1/n, hard to tell if x==1/n, only use n=power of 2)
n = 2**np.arange(1, 10)
x = 1.0/n
pp = -(n*x+1) * (1+x)**(n-2) + 0.5
dataset0 = np.column_stack([n, x, pp])
FuncData(_smirnovp, dataset0, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
@pytest.mark.xfail(sys.maxsize <= 2**32,
reason="requires 64-bit platform")
def test_oneovernclose(self):
# Check derivative at x=1/n (Discontinuous at x=1/n, test on either side: x=1/n +/- 2epsilon)
n = np.arange(3, 20)
x = 1.0/n - 2*np.finfo(float).eps
pp = -(n*x+1) * (1+x)**(n-2)
dataset0 = np.column_stack([n, x, pp])
FuncData(_smirnovp, dataset0, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
x = 1.0/n + 2*np.finfo(float).eps
pp = -(n*x+1) * (1+x)**(n-2) + 1
dataset1 = np.column_stack([n, x, pp])
FuncData(_smirnovp, dataset1, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
class TestKolmogorov:
def test_nan(self):
assert_(np.isnan(kolmogorov(np.nan)))
def test_basic(self):
dataset = [(0, 1.0),
(0.5, 0.96394524366487511),
(0.8275735551899077, 0.5000000000000000),
(1, 0.26999967167735456),
(2, 0.00067092525577969533)]
dataset = np.asarray(dataset)
FuncData(kolmogorov, dataset, (0,), 1, rtol=_rtol).check()
def test_linspace(self):
x = np.linspace(0, 2.0, 21)
dataset = [1.0000000000000000, 1.0000000000000000, 0.9999999999994950,
0.9999906941986655, 0.9971923267772983, 0.9639452436648751,
0.8642827790506042, 0.7112351950296890, 0.5441424115741981,
0.3927307079406543, 0.2699996716773546, 0.1777181926064012,
0.1122496666707249, 0.0680922218447664, 0.0396818795381144,
0.0222179626165251, 0.0119520432391966, 0.0061774306344441,
0.0030676213475797, 0.0014636048371873, 0.0006709252557797]
dataset_c = [0.0000000000000000, 6.609305242245699e-53, 5.050407338670114e-13,
9.305801334566668e-06, 0.0028076732227017, 0.0360547563351249,
0.1357172209493958, 0.2887648049703110, 0.4558575884258019,
0.6072692920593457, 0.7300003283226455, 0.8222818073935988,
0.8877503333292751, 0.9319077781552336, 0.9603181204618857,
0.9777820373834749, 0.9880479567608034, 0.9938225693655559,
0.9969323786524203, 0.9985363951628127, 0.9993290747442203]
dataset = np.column_stack([x, dataset])
FuncData(kolmogorov, dataset, (0,), 1, rtol=_rtol).check()
dataset_c = np.column_stack([x, dataset_c])
FuncData(_kolmogc, dataset_c, (0,), 1, rtol=_rtol).check()
def test_linspacei(self):
p = np.linspace(0, 1.0, 21, endpoint=True)
dataset = [np.inf, 1.3580986393225507, 1.2238478702170823,
1.1379465424937751, 1.0727491749396481, 1.0191847202536859,
0.9730633753323726, 0.9320695842357622, 0.8947644549851197,
0.8601710725555463, 0.8275735551899077, 0.7964065373291559,
0.7661855555617682, 0.7364542888171910, 0.7067326523068980,
0.6764476915028201, 0.6448126061663567, 0.6105590999244391,
0.5711732651063401, 0.5196103791686224, 0.0000000000000000]
dataset_c = [0.0000000000000000, 0.5196103791686225, 0.5711732651063401,
0.6105590999244391, 0.6448126061663567, 0.6764476915028201,
0.7067326523068980, 0.7364542888171910, 0.7661855555617682,
0.7964065373291559, 0.8275735551899077, 0.8601710725555463,
0.8947644549851196, 0.9320695842357622, 0.9730633753323727,
1.0191847202536859, 1.0727491749396481, 1.1379465424937754,
1.2238478702170825, 1.3580986393225509, np.inf]
dataset = np.column_stack([p[1:], dataset[1:]])
FuncData(kolmogi, dataset, (0,), 1, rtol=_rtol).check()
dataset_c = np.column_stack([p[:-1], dataset_c[:-1]])
FuncData(_kolmogci, dataset_c, (0,), 1, rtol=_rtol).check()
def test_smallx(self):
epsilon = 0.1 ** np.arange(1, 14)
x = np.array([0.571173265106, 0.441027698518, 0.374219690278, 0.331392659217,
0.300820537459, 0.277539353999, 0.259023494805, 0.243829561254,
0.231063086389, 0.220135543236, 0.210641372041, 0.202290283658,
0.19487060742])
dataset = np.column_stack([x, 1-epsilon])
FuncData(kolmogorov, dataset, (0,), 1, rtol=_rtol).check()
def test_round_trip(self):
def _ki_k(_x):
return kolmogi(kolmogorov(_x))
def _kci_kc(_x):
return _kolmogci(_kolmogc(_x))
x = np.linspace(0.0, 2.0, 21, endpoint=True)
x02 = x[(x == 0) | (x > 0.21)] # Exclude 0.1, 0.2. 0.2 almost makes succeeds, but 0.1 has no chance.
dataset02 = np.column_stack([x02, x02])
FuncData(_ki_k, dataset02, (0,), 1, rtol=_rtol).check()
dataset = np.column_stack([x, x])
FuncData(_kci_kc, dataset, (0,), 1, rtol=_rtol).check()
class TestKolmogi:
def test_nan(self):
assert_(np.isnan(kolmogi(np.nan)))
def test_basic(self):
dataset = [(1.0, 0),
(0.96394524366487511, 0.5),
(0.9, 0.571173265106),
(0.5000000000000000, 0.8275735551899077),
(0.26999967167735456, 1),
(0.00067092525577969533, 2)]
dataset = np.asarray(dataset)
FuncData(kolmogi, dataset, (0,), 1, rtol=_rtol).check()
def test_smallpcdf(self):
epsilon = 0.5 ** np.arange(1, 55, 3)
# kolmogi(1-p) == _kolmogci(p) if 1-(1-p) == p, but not necessarily otherwise
# Use epsilon s.t. 1-(1-epsilon)) == epsilon, so can use same x-array for both results
x = np.array([0.8275735551899077, 0.5345255069097583, 0.4320114038786941,
0.3736868442620478, 0.3345161714909591, 0.3057833329315859,
0.2835052890528936, 0.2655578150208676, 0.2506869966107999,
0.2380971058736669, 0.2272549289962079, 0.2177876361600040,
0.2094254686862041, 0.2019676748836232, 0.1952612948137504,
0.1891874239646641, 0.1836520225050326, 0.1785795904846466])
dataset = np.column_stack([1-epsilon, x])
FuncData(kolmogi, dataset, (0,), 1, rtol=_rtol).check()
dataset = np.column_stack([epsilon, x])
FuncData(_kolmogci, dataset, (0,), 1, rtol=_rtol).check()
def test_smallpsf(self):
epsilon = 0.5 ** np.arange(1, 55, 3)
# kolmogi(p) == _kolmogci(1-p) if 1-(1-p) == p, but not necessarily otherwise
# Use epsilon s.t. 1-(1-epsilon)) == epsilon, so can use same x-array for both results
x = np.array([0.8275735551899077, 1.3163786275161036, 1.6651092133663343,
1.9525136345289607, 2.2027324540033235, 2.4272929437460848,
2.6327688477341593, 2.8233300509220260, 3.0018183401530627,
3.1702735084088891, 3.3302184446307912, 3.4828258153113318,
3.6290214150152051, 3.7695513262825959, 3.9050272690877326,
4.0359582187082550, 4.1627730557884890, 4.2858371743264527])
dataset = np.column_stack([epsilon, x])
FuncData(kolmogi, dataset, (0,), 1, rtol=_rtol).check()
dataset = np.column_stack([1-epsilon, x])
FuncData(_kolmogci, dataset, (0,), 1, rtol=_rtol).check()
def test_round_trip(self):
def _k_ki(_p):
return kolmogorov(kolmogi(_p))
p = np.linspace(0.1, 1.0, 10, endpoint=True)
dataset = np.column_stack([p, p])
FuncData(_k_ki, dataset, (0,), 1, rtol=_rtol).check()
class TestKolmogp:
def test_nan(self):
assert_(np.isnan(_kolmogp(np.nan)))
def test_basic(self):
dataset = [(0.000000, -0.0),
(0.200000, -1.532420541338916e-10),
(0.400000, -0.1012254419260496),
(0.600000, -1.324123244249925),
(0.800000, -1.627024345636592),
(1.000000, -1.071948558356941),
(1.200000, -0.538512430720529),
(1.400000, -0.2222133182429472),
(1.600000, -0.07649302775520538),
(1.800000, -0.02208687346347873),
(2.000000, -0.005367402045629683)]
dataset = np.asarray(dataset)
FuncData(_kolmogp, dataset, (0,), 1, rtol=_rtol).check()

View File

@@ -0,0 +1,109 @@
#
# Tests for the lambertw function,
# Adapted from the MPMath tests [1] by Yosef Meller, mellerf@netvision.net.il
# Distributed under the same license as SciPy itself.
#
# [1] mpmath source code, Subversion revision 992
# http://code.google.com/p/mpmath/source/browse/trunk/mpmath/tests/test_functions2.py?spec=svn994&r=992
import pytest
import numpy as np
from numpy.testing import assert_, assert_equal, assert_array_almost_equal
from scipy.special import lambertw
from numpy import nan, inf, pi, e, isnan, log, r_, array, complex_
from scipy.special._testutils import FuncData
def test_values():
assert_(isnan(lambertw(nan)))
assert_equal(lambertw(inf,1).real, inf)
assert_equal(lambertw(inf,1).imag, 2*pi)
assert_equal(lambertw(-inf,1).real, inf)
assert_equal(lambertw(-inf,1).imag, 3*pi)
assert_equal(lambertw(1.), lambertw(1., 0))
data = [
(0,0, 0),
(0+0j,0, 0),
(inf,0, inf),
(0,-1, -inf),
(0,1, -inf),
(0,3, -inf),
(e,0, 1),
(1,0, 0.567143290409783873),
(-pi/2,0, 1j*pi/2),
(-log(2)/2,0, -log(2)),
(0.25,0, 0.203888354702240164),
(-0.25,0, -0.357402956181388903),
(-1./10000,0, -0.000100010001500266719),
(-0.25,-1, -2.15329236411034965),
(0.25,-1, -3.00899800997004620-4.07652978899159763j),
(-0.25,-1, -2.15329236411034965),
(0.25,1, -3.00899800997004620+4.07652978899159763j),
(-0.25,1, -3.48973228422959210+7.41405453009603664j),
(-4,0, 0.67881197132094523+1.91195078174339937j),
(-4,1, -0.66743107129800988+7.76827456802783084j),
(-4,-1, 0.67881197132094523-1.91195078174339937j),
(1000,0, 5.24960285240159623),
(1000,1, 4.91492239981054535+5.44652615979447070j),
(1000,-1, 4.91492239981054535-5.44652615979447070j),
(1000,5, 3.5010625305312892+29.9614548941181328j),
(3+4j,0, 1.281561806123775878+0.533095222020971071j),
(-0.4+0.4j,0, -0.10396515323290657+0.61899273315171632j),
(3+4j,1, -0.11691092896595324+5.61888039871282334j),
(3+4j,-1, 0.25856740686699742-3.85211668616143559j),
(-0.5,-1, -0.794023632344689368-0.770111750510379110j),
(-1./10000,1, -11.82350837248724344+6.80546081842002101j),
(-1./10000,-1, -11.6671145325663544),
(-1./10000,-2, -11.82350837248724344-6.80546081842002101j),
(-1./100000,4, -14.9186890769540539+26.1856750178782046j),
(-1./100000,5, -15.0931437726379218666+32.5525721210262290086j),
((2+1j)/10,0, 0.173704503762911669+0.071781336752835511j),
((2+1j)/10,1, -3.21746028349820063+4.56175438896292539j),
((2+1j)/10,-1, -3.03781405002993088-3.53946629633505737j),
((2+1j)/10,4, -4.6878509692773249+23.8313630697683291j),
(-(2+1j)/10,0, -0.226933772515757933-0.164986470020154580j),
(-(2+1j)/10,1, -2.43569517046110001+0.76974067544756289j),
(-(2+1j)/10,-1, -3.54858738151989450-6.91627921869943589j),
(-(2+1j)/10,4, -4.5500846928118151+20.6672982215434637j),
(pi,0, 1.073658194796149172092178407024821347547745350410314531),
# Former bug in generated branch,
(-0.5+0.002j,0, -0.78917138132659918344 + 0.76743539379990327749j),
(-0.5-0.002j,0, -0.78917138132659918344 - 0.76743539379990327749j),
(-0.448+0.4j,0, -0.11855133765652382241 + 0.66570534313583423116j),
(-0.448-0.4j,0, -0.11855133765652382241 - 0.66570534313583423116j),
]
data = array(data, dtype=complex_)
def w(x, y):
return lambertw(x, y.real.astype(int))
with np.errstate(all='ignore'):
FuncData(w, data, (0,1), 2, rtol=1e-10, atol=1e-13).check()
def test_ufunc():
assert_array_almost_equal(
lambertw(r_[0., e, 1.]), r_[0., 1., 0.567143290409783873])
def test_lambertw_ufunc_loop_selection():
# see https://github.com/scipy/scipy/issues/4895
dt = np.dtype(np.complex128)
assert_equal(lambertw(0, 0, 0).dtype, dt)
assert_equal(lambertw([0], 0, 0).dtype, dt)
assert_equal(lambertw(0, [0], 0).dtype, dt)
assert_equal(lambertw(0, 0, [0]).dtype, dt)
assert_equal(lambertw([0], [0], [0]).dtype, dt)
@pytest.mark.parametrize('z', [1e-316, -2e-320j, -5e-318+1e-320j])
def test_lambertw_subnormal_k0(z):
# Verify that subnormal inputs are handled correctly on
# the branch k=0 (regression test for gh-16291).
w = lambertw(z)
# For values this small, we can be sure that numerically,
# lambertw(z) is z.
assert w == z

View File

@@ -0,0 +1,109 @@
import numpy as np
from numpy.testing import assert_allclose
import pytest
import scipy.special as sc
@pytest.mark.parametrize('x, expected', [
(np.array([1000, 1]), np.array([0, -999])),
# Expected value computed using mpmath (with mpmath.mp.dps = 200) and then
# converted to float.
(np.arange(4), np.array([-3.4401896985611953,
-2.4401896985611953,
-1.4401896985611953,
-0.44018969856119533]))
])
def test_log_softmax(x, expected):
assert_allclose(sc.log_softmax(x), expected, rtol=1e-13)
@pytest.fixture
def log_softmax_x():
x = np.arange(4)
return x
@pytest.fixture
def log_softmax_expected():
# Expected value computed using mpmath (with mpmath.mp.dps = 200) and then
# converted to float.
expected = np.array([-3.4401896985611953,
-2.4401896985611953,
-1.4401896985611953,
-0.44018969856119533])
return expected
def test_log_softmax_translation(log_softmax_x, log_softmax_expected):
# Translation property. If all the values are changed by the same amount,
# the softmax result does not change.
x = log_softmax_x + 100
expected = log_softmax_expected
assert_allclose(sc.log_softmax(x), expected, rtol=1e-13)
def test_log_softmax_noneaxis(log_softmax_x, log_softmax_expected):
# When axis=None, softmax operates on the entire array, and preserves
# the shape.
x = log_softmax_x.reshape(2, 2)
expected = log_softmax_expected.reshape(2, 2)
assert_allclose(sc.log_softmax(x), expected, rtol=1e-13)
@pytest.mark.parametrize('axis_2d, expected_2d', [
(0, np.log(0.5) * np.ones((2, 2))),
(1, np.array([[0, -999], [0, -999]]))
])
def test_axes(axis_2d, expected_2d):
assert_allclose(
sc.log_softmax([[1000, 1], [1000, 1]], axis=axis_2d),
expected_2d,
rtol=1e-13,
)
@pytest.fixture
def log_softmax_2d_x():
x = np.arange(8).reshape(2, 4)
return x
@pytest.fixture
def log_softmax_2d_expected():
# Expected value computed using mpmath (with mpmath.mp.dps = 200) and then
# converted to float.
expected = np.array([[-3.4401896985611953,
-2.4401896985611953,
-1.4401896985611953,
-0.44018969856119533],
[-3.4401896985611953,
-2.4401896985611953,
-1.4401896985611953,
-0.44018969856119533]])
return expected
def test_log_softmax_2d_axis1(log_softmax_2d_x, log_softmax_2d_expected):
x = log_softmax_2d_x
expected = log_softmax_2d_expected
assert_allclose(sc.log_softmax(x, axis=1), expected, rtol=1e-13)
def test_log_softmax_2d_axis0(log_softmax_2d_x, log_softmax_2d_expected):
x = log_softmax_2d_x.T
expected = log_softmax_2d_expected.T
assert_allclose(sc.log_softmax(x, axis=0), expected, rtol=1e-13)
def test_log_softmax_3d(log_softmax_2d_x, log_softmax_2d_expected):
# 3-d input, with a tuple for the axis.
x_3d = log_softmax_2d_x.reshape(2, 2, 2)
expected_3d = log_softmax_2d_expected.reshape(2, 2, 2)
assert_allclose(sc.log_softmax(x_3d, axis=(1, 2)), expected_3d, rtol=1e-13)
def test_log_softmax_scalar():
assert_allclose(sc.log_softmax(1.0), 0.0, rtol=1e-13)

View File

@@ -0,0 +1,70 @@
import numpy as np
from numpy.testing import assert_allclose, assert_
from scipy.special._testutils import FuncData
from scipy.special import gamma, gammaln, loggamma
def test_identities1():
# test the identity exp(loggamma(z)) = gamma(z)
x = np.array([-99.5, -9.5, -0.5, 0.5, 9.5, 99.5])
y = x.copy()
x, y = np.meshgrid(x, y)
z = (x + 1J*y).flatten()
dataset = np.vstack((z, gamma(z))).T
def f(z):
return np.exp(loggamma(z))
FuncData(f, dataset, 0, 1, rtol=1e-14, atol=1e-14).check()
def test_identities2():
# test the identity loggamma(z + 1) = log(z) + loggamma(z)
x = np.array([-99.5, -9.5, -0.5, 0.5, 9.5, 99.5])
y = x.copy()
x, y = np.meshgrid(x, y)
z = (x + 1J*y).flatten()
dataset = np.vstack((z, np.log(z) + loggamma(z))).T
def f(z):
return loggamma(z + 1)
FuncData(f, dataset, 0, 1, rtol=1e-14, atol=1e-14).check()
def test_complex_dispatch_realpart():
# Test that the real parts of loggamma and gammaln agree on the
# real axis.
x = np.r_[-np.logspace(10, -10), np.logspace(-10, 10)] + 0.5
dataset = np.vstack((x, gammaln(x))).T
def f(z):
z = np.array(z, dtype='complex128')
return loggamma(z).real
FuncData(f, dataset, 0, 1, rtol=1e-14, atol=1e-14).check()
def test_real_dispatch():
x = np.logspace(-10, 10) + 0.5
dataset = np.vstack((x, gammaln(x))).T
FuncData(loggamma, dataset, 0, 1, rtol=1e-14, atol=1e-14).check()
assert_(loggamma(0) == np.inf)
assert_(np.isnan(loggamma(-1)))
def test_gh_6536():
z = loggamma(complex(-3.4, +0.0))
zbar = loggamma(complex(-3.4, -0.0))
assert_allclose(z, zbar.conjugate(), rtol=1e-15, atol=0)
def test_branch_cut():
# Make sure negative zero is treated correctly
x = -np.logspace(300, -30, 100)
z = np.asarray([complex(x0, 0.0) for x0 in x])
zbar = np.asarray([complex(x0, -0.0) for x0 in x])
assert_allclose(z, zbar.conjugate(), rtol=1e-15, atol=0)

View File

@@ -0,0 +1,145 @@
import numpy as np
from numpy.testing import (assert_equal, assert_almost_equal,
assert_allclose)
from scipy.special import logit, expit, log_expit
class TestLogit:
def check_logit_out(self, dtype, expected):
a = np.linspace(0, 1, 10)
a = np.array(a, dtype=dtype)
with np.errstate(divide='ignore'):
actual = logit(a)
assert_almost_equal(actual, expected)
assert_equal(actual.dtype, np.dtype(dtype))
def test_float32(self):
expected = np.array([-np.inf, -2.07944155,
-1.25276291, -0.69314718,
-0.22314353, 0.22314365,
0.6931473, 1.25276303,
2.07944155, np.inf], dtype=np.float32)
self.check_logit_out('f4', expected)
def test_float64(self):
expected = np.array([-np.inf, -2.07944154,
-1.25276297, -0.69314718,
-0.22314355, 0.22314355,
0.69314718, 1.25276297,
2.07944154, np.inf])
self.check_logit_out('f8', expected)
def test_nan(self):
expected = np.array([np.nan]*4)
with np.errstate(invalid='ignore'):
actual = logit(np.array([-3., -2., 2., 3.]))
assert_equal(expected, actual)
class TestExpit:
def check_expit_out(self, dtype, expected):
a = np.linspace(-4, 4, 10)
a = np.array(a, dtype=dtype)
actual = expit(a)
assert_almost_equal(actual, expected)
assert_equal(actual.dtype, np.dtype(dtype))
def test_float32(self):
expected = np.array([0.01798621, 0.04265125,
0.09777259, 0.20860852,
0.39068246, 0.60931754,
0.79139149, 0.9022274,
0.95734876, 0.98201376], dtype=np.float32)
self.check_expit_out('f4', expected)
def test_float64(self):
expected = np.array([0.01798621, 0.04265125,
0.0977726, 0.20860853,
0.39068246, 0.60931754,
0.79139147, 0.9022274,
0.95734875, 0.98201379])
self.check_expit_out('f8', expected)
def test_large(self):
for dtype in (np.float32, np.float64, np.longdouble):
for n in (88, 89, 709, 710, 11356, 11357):
n = np.array(n, dtype=dtype)
assert_allclose(expit(n), 1.0, atol=1e-20)
assert_allclose(expit(-n), 0.0, atol=1e-20)
assert_equal(expit(n).dtype, dtype)
assert_equal(expit(-n).dtype, dtype)
class TestLogExpit:
def test_large_negative(self):
x = np.array([-10000.0, -750.0, -500.0, -35.0])
y = log_expit(x)
assert_equal(y, x)
def test_large_positive(self):
x = np.array([750.0, 1000.0, 10000.0])
y = log_expit(x)
# y will contain -0.0, and -0.0 is used in the expected value,
# but assert_equal does not check the sign of zeros, and I don't
# think the sign is an essential part of the test (i.e. it would
# probably be OK if log_expit(1000) returned 0.0 instead of -0.0).
assert_equal(y, np.array([-0.0, -0.0, -0.0]))
def test_basic_float64(self):
x = np.array([-32, -20, -10, -3, -1, -0.1, -1e-9,
0, 1e-9, 0.1, 1, 10, 100, 500, 710, 725, 735])
y = log_expit(x)
#
# Expected values were computed with mpmath:
#
# import mpmath
#
# mpmath.mp.dps = 100
#
# def mp_log_expit(x):
# return -mpmath.log1p(mpmath.exp(-x))
#
# expected = [float(mp_log_expit(t)) for t in x]
#
expected = [-32.000000000000014, -20.000000002061153,
-10.000045398899218, -3.048587351573742,
-1.3132616875182228, -0.7443966600735709,
-0.6931471810599453, -0.6931471805599453,
-0.6931471800599454, -0.6443966600735709,
-0.3132616875182228, -4.539889921686465e-05,
-3.720075976020836e-44, -7.124576406741286e-218,
-4.47628622567513e-309, -1.36930634e-315,
-6.217e-320]
# When tested locally, only one value in y was not exactly equal to
# expected. That was for x=1, and the y value differed from the
# expected by 1 ULP. For this test, however, I'll use rtol=1e-15.
assert_allclose(y, expected, rtol=1e-15)
def test_basic_float32(self):
x = np.array([-32, -20, -10, -3, -1, -0.1, -1e-9,
0, 1e-9, 0.1, 1, 10, 100], dtype=np.float32)
y = log_expit(x)
#
# Expected values were computed with mpmath:
#
# import mpmath
#
# mpmath.mp.dps = 100
#
# def mp_log_expit(x):
# return -mpmath.log1p(mpmath.exp(-x))
#
# expected = [np.float32(mp_log_expit(t)) for t in x]
#
expected = np.array([-32.0, -20.0, -10.000046, -3.0485873,
-1.3132616, -0.7443967, -0.6931472,
-0.6931472, -0.6931472, -0.64439666,
-0.3132617, -4.5398898e-05, -3.8e-44],
dtype=np.float32)
assert_allclose(y, expected, rtol=5e-7)

View File

@@ -0,0 +1,194 @@
import numpy as np
from numpy.testing import (assert_almost_equal, assert_equal, assert_allclose,
assert_array_almost_equal, assert_)
from scipy.special import logsumexp, softmax
def test_logsumexp():
# Test whether logsumexp() function correctly handles large inputs.
a = np.arange(200)
desired = np.log(np.sum(np.exp(a)))
assert_almost_equal(logsumexp(a), desired)
# Now test with large numbers
b = [1000, 1000]
desired = 1000.0 + np.log(2.0)
assert_almost_equal(logsumexp(b), desired)
n = 1000
b = np.full(n, 10000, dtype='float64')
desired = 10000.0 + np.log(n)
assert_almost_equal(logsumexp(b), desired)
x = np.array([1e-40] * 1000000)
logx = np.log(x)
X = np.vstack([x, x])
logX = np.vstack([logx, logx])
assert_array_almost_equal(np.exp(logsumexp(logX)), X.sum())
assert_array_almost_equal(np.exp(logsumexp(logX, axis=0)), X.sum(axis=0))
assert_array_almost_equal(np.exp(logsumexp(logX, axis=1)), X.sum(axis=1))
# Handling special values properly
assert_equal(logsumexp(np.inf), np.inf)
assert_equal(logsumexp(-np.inf), -np.inf)
assert_equal(logsumexp(np.nan), np.nan)
assert_equal(logsumexp([-np.inf, -np.inf]), -np.inf)
# Handling an array with different magnitudes on the axes
assert_array_almost_equal(logsumexp([[1e10, 1e-10],
[-1e10, -np.inf]], axis=-1),
[1e10, -1e10])
# Test keeping dimensions
assert_array_almost_equal(logsumexp([[1e10, 1e-10],
[-1e10, -np.inf]],
axis=-1,
keepdims=True),
[[1e10], [-1e10]])
# Test multiple axes
assert_array_almost_equal(logsumexp([[1e10, 1e-10],
[-1e10, -np.inf]],
axis=(-1,-2)),
1e10)
def test_logsumexp_b():
a = np.arange(200)
b = np.arange(200, 0, -1)
desired = np.log(np.sum(b*np.exp(a)))
assert_almost_equal(logsumexp(a, b=b), desired)
a = [1000, 1000]
b = [1.2, 1.2]
desired = 1000 + np.log(2 * 1.2)
assert_almost_equal(logsumexp(a, b=b), desired)
x = np.array([1e-40] * 100000)
b = np.linspace(1, 1000, 100000)
logx = np.log(x)
X = np.vstack((x, x))
logX = np.vstack((logx, logx))
B = np.vstack((b, b))
assert_array_almost_equal(np.exp(logsumexp(logX, b=B)), (B * X).sum())
assert_array_almost_equal(np.exp(logsumexp(logX, b=B, axis=0)),
(B * X).sum(axis=0))
assert_array_almost_equal(np.exp(logsumexp(logX, b=B, axis=1)),
(B * X).sum(axis=1))
def test_logsumexp_sign():
a = [1,1,1]
b = [1,-1,-1]
r, s = logsumexp(a, b=b, return_sign=True)
assert_almost_equal(r,1)
assert_equal(s,-1)
def test_logsumexp_sign_zero():
a = [1,1]
b = [1,-1]
r, s = logsumexp(a, b=b, return_sign=True)
assert_(not np.isfinite(r))
assert_(not np.isnan(r))
assert_(r < 0)
assert_equal(s,0)
def test_logsumexp_sign_shape():
a = np.ones((1,2,3,4))
b = np.ones_like(a)
r, s = logsumexp(a, axis=2, b=b, return_sign=True)
assert_equal(r.shape, s.shape)
assert_equal(r.shape, (1,2,4))
r, s = logsumexp(a, axis=(1,3), b=b, return_sign=True)
assert_equal(r.shape, s.shape)
assert_equal(r.shape, (1,3))
def test_logsumexp_shape():
a = np.ones((1, 2, 3, 4))
b = np.ones_like(a)
r = logsumexp(a, axis=2, b=b)
assert_equal(r.shape, (1, 2, 4))
r = logsumexp(a, axis=(1, 3), b=b)
assert_equal(r.shape, (1, 3))
def test_logsumexp_b_zero():
a = [1,10000]
b = [1,0]
assert_almost_equal(logsumexp(a, b=b), 1)
def test_logsumexp_b_shape():
a = np.zeros((4,1,2,1))
b = np.ones((3,1,5))
logsumexp(a, b=b)
def test_softmax_fixtures():
assert_allclose(softmax([1000, 0, 0, 0]), np.array([1, 0, 0, 0]),
rtol=1e-13)
assert_allclose(softmax([1, 1]), np.array([.5, .5]), rtol=1e-13)
assert_allclose(softmax([0, 1]), np.array([1, np.e])/(1 + np.e),
rtol=1e-13)
# Expected value computed using mpmath (with mpmath.mp.dps = 200) and then
# converted to float.
x = np.arange(4)
expected = np.array([0.03205860328008499,
0.08714431874203256,
0.23688281808991013,
0.6439142598879722])
assert_allclose(softmax(x), expected, rtol=1e-13)
# Translation property. If all the values are changed by the same amount,
# the softmax result does not change.
assert_allclose(softmax(x + 100), expected, rtol=1e-13)
# When axis=None, softmax operates on the entire array, and preserves
# the shape.
assert_allclose(softmax(x.reshape(2, 2)), expected.reshape(2, 2),
rtol=1e-13)
def test_softmax_multi_axes():
assert_allclose(softmax([[1000, 0], [1000, 0]], axis=0),
np.array([[.5, .5], [.5, .5]]), rtol=1e-13)
assert_allclose(softmax([[1000, 0], [1000, 0]], axis=1),
np.array([[1, 0], [1, 0]]), rtol=1e-13)
# Expected value computed using mpmath (with mpmath.mp.dps = 200) and then
# converted to float.
x = np.array([[-25, 0, 25, 50],
[1, 325, 749, 750]])
expected = np.array([[2.678636961770877e-33,
1.9287498479371314e-22,
1.3887943864771144e-11,
0.999999999986112],
[0.0,
1.9444526359919372e-185,
0.2689414213699951,
0.7310585786300048]])
assert_allclose(softmax(x, axis=1), expected, rtol=1e-13)
assert_allclose(softmax(x.T, axis=0), expected.T, rtol=1e-13)
# 3-d input, with a tuple for the axis.
x3d = x.reshape(2, 2, 2)
assert_allclose(softmax(x3d, axis=(1, 2)), expected.reshape(2, 2, 2),
rtol=1e-13)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,64 @@
"""Test how the ufuncs in special handle nan inputs.
"""
from typing import Callable, Dict
import numpy as np
from numpy.testing import assert_array_equal, assert_, suppress_warnings
import pytest
import scipy.special as sc
KNOWNFAILURES: Dict[str, Callable] = {}
POSTPROCESSING: Dict[str, Callable] = {}
def _get_ufuncs():
ufuncs = []
ufunc_names = []
for name in sorted(sc.__dict__):
obj = sc.__dict__[name]
if not isinstance(obj, np.ufunc):
continue
msg = KNOWNFAILURES.get(obj)
if msg is None:
ufuncs.append(obj)
ufunc_names.append(name)
else:
fail = pytest.mark.xfail(run=False, reason=msg)
ufuncs.append(pytest.param(obj, marks=fail))
ufunc_names.append(name)
return ufuncs, ufunc_names
UFUNCS, UFUNC_NAMES = _get_ufuncs()
@pytest.mark.parametrize("func", UFUNCS, ids=UFUNC_NAMES)
def test_nan_inputs(func):
args = (np.nan,)*func.nin
with suppress_warnings() as sup:
# Ignore warnings about unsafe casts from legacy wrappers
sup.filter(RuntimeWarning,
"floating point number truncated to an integer")
try:
with suppress_warnings() as sup:
sup.filter(DeprecationWarning)
res = func(*args)
except TypeError:
# One of the arguments doesn't take real inputs
return
if func in POSTPROCESSING:
res = POSTPROCESSING[func](*res)
msg = "got {} instead of nan".format(res)
assert_array_equal(np.isnan(res), True, err_msg=msg)
def test_legacy_cast():
with suppress_warnings() as sup:
sup.filter(RuntimeWarning,
"floating point number truncated to an integer")
res = sc.bdtrc(np.nan, 1, 0.5)
assert_(np.isnan(res))

View File

@@ -0,0 +1,77 @@
import numpy as np
from numpy.testing import assert_equal, assert_allclose
import scipy.special as sc
def test_ndtr():
assert_equal(sc.ndtr(0), 0.5)
assert_allclose(sc.ndtr(1), 0.8413447460685429)
class TestNdtri:
def test_zero(self):
assert sc.ndtri(0.5) == 0.0
def test_asymptotes(self):
assert_equal(sc.ndtri([0.0, 1.0]), [-np.inf, np.inf])
def test_outside_of_domain(self):
assert all(np.isnan(sc.ndtri([-1.5, 1.5])))
class TestLogNdtr:
# The expected values in these tests were computed with mpmath:
#
# def log_ndtr_mp(x):
# return mpmath.log(mpmath.ncdf(x))
#
def test_log_ndtr_moderate_le8(self):
x = np.array([-0.75, -0.25, 0, 0.5, 1.5, 2.5, 3, 4, 5, 7, 8])
expected = np.array([-1.4844482299196562,
-0.9130617648111351,
-0.6931471805599453,
-0.3689464152886564,
-0.06914345561223398,
-0.006229025485860002,
-0.0013508099647481938,
-3.167174337748927e-05,
-2.866516129637636e-07,
-1.279812543886654e-12,
-6.220960574271786e-16])
y = sc.log_ndtr(x)
assert_allclose(y, expected, rtol=1e-14)
def test_log_ndtr_values_8_16(self):
x = np.array([8.001, 8.06, 8.15, 8.5, 10, 12, 14, 16])
expected = [-6.170639424817055e-16,
-3.814722443652823e-16,
-1.819621363526629e-16,
-9.479534822203318e-18,
-7.619853024160525e-24,
-1.776482112077679e-33,
-7.7935368191928e-45,
-6.388754400538087e-58]
y = sc.log_ndtr(x)
assert_allclose(y, expected, rtol=5e-14)
def test_log_ndtr_values_16_31(self):
x = np.array([16.15, 20.3, 21.4, 26.2, 30.9])
expected = [-5.678084565148492e-59,
-6.429244467698346e-92,
-6.680402412553295e-102,
-1.328698078458869e-151,
-5.972288641838264e-210]
y = sc.log_ndtr(x)
assert_allclose(y, expected, rtol=2e-13)
def test_log_ndtr_values_gt31(self):
x = np.array([31.6, 32.8, 34.9, 37.1])
expected = [-1.846036234858162e-219,
-2.9440539964066835e-236,
-3.71721649450857e-267,
-1.4047119663106221e-301]
y = sc.log_ndtr(x)
assert_allclose(y, expected, rtol=3e-13)

View File

@@ -0,0 +1,94 @@
import pytest
import numpy as np
from numpy.testing import assert_equal, assert_allclose
from scipy.special import log_ndtr, ndtri_exp
from scipy.special._testutils import assert_func_equal
def log_ndtr_ndtri_exp(y):
return log_ndtr(ndtri_exp(y))
@pytest.fixture(scope="class")
def uniform_random_points():
random_state = np.random.RandomState(1234)
points = random_state.random_sample(1000)
return points
class TestNdtriExp:
"""Tests that ndtri_exp is sufficiently close to an inverse of log_ndtr.
We have separate tests for the five intervals (-inf, -10),
[-10, -2), [-2, -0.14542), [-0.14542, -1e-6), and [-1e-6, 0).
ndtri_exp(y) is computed in three different ways depending on if y
is in (-inf, -2), [-2, log(1 - exp(-2))], or [log(1 - exp(-2), 0).
Each of these intervals is given its own test with two additional tests
for handling very small values and values very close to zero.
"""
@pytest.mark.parametrize(
"test_input", [-1e1, -1e2, -1e10, -1e20, -np.finfo(float).max]
)
def test_very_small_arg(self, test_input, uniform_random_points):
scale = test_input
points = scale * (0.5 * uniform_random_points + 0.5)
assert_func_equal(
log_ndtr_ndtri_exp,
lambda y: y, points,
rtol=1e-14,
nan_ok=True
)
@pytest.mark.parametrize(
"interval,expected_rtol",
[
((-10, -2), 1e-14),
((-2, -0.14542), 1e-12),
((-0.14542, -1e-6), 1e-10),
((-1e-6, 0), 1e-6),
],
)
def test_in_interval(self, interval, expected_rtol, uniform_random_points):
left, right = interval
points = (right - left) * uniform_random_points + left
assert_func_equal(
log_ndtr_ndtri_exp,
lambda y: y, points,
rtol=expected_rtol,
nan_ok=True
)
def test_extreme(self):
# bigneg is not quite the largest negative double precision value.
# Here's why:
# The round-trip calculation
# y = ndtri_exp(bigneg)
# bigneg2 = log_ndtr(y)
# where bigneg is a very large negative value, would--with infinite
# precision--result in bigneg2 == bigneg. When bigneg is large enough,
# y is effectively equal to -sqrt(2)*sqrt(-bigneg), and log_ndtr(y) is
# effectively -(y/sqrt(2))**2. If we use bigneg = np.finfo(float).min,
# then by construction, the theoretical value is the most negative
# finite value that can be represented with 64 bit float point. This
# means tiny changes in how the computation proceeds can result in the
# return value being -inf. (E.g. changing the constant representation
# of 1/sqrt(2) from 0.7071067811865475--which is the value returned by
# 1/np.sqrt(2)--to 0.7071067811865476--which is the most accurate 64
# bit floating point representation of 1/sqrt(2)--results in the
# round-trip that starts with np.finfo(float).min returning -inf. So
# we'll move the bigneg value a few ULPs towards 0 to avoid this
# sensitivity.
# Use the reduce method to apply nextafter four times.
bigneg = np.nextafter.reduce([np.finfo(float).min, 0, 0, 0, 0])
# tinyneg is approx. -2.225e-308.
tinyneg = -np.finfo(float).tiny
x = np.array([tinyneg, bigneg])
result = log_ndtr_ndtri_exp(x)
assert_allclose(result, x, rtol=1e-12)
def test_asymptotes(self):
assert_equal(ndtri_exp([-np.inf, 0.0]), [-np.inf, np.inf])
def test_outside_domain(self):
assert np.isnan(ndtri_exp(1.0))

View File

@@ -0,0 +1,791 @@
import numpy as np
from numpy import array, sqrt
from numpy.testing import (assert_array_almost_equal, assert_equal,
assert_almost_equal, assert_allclose)
from pytest import raises as assert_raises
from scipy import integrate
import scipy.special as sc
from scipy.special import gamma
import scipy.special._orthogonal as orth
class TestCheby:
def test_chebyc(self):
C0 = orth.chebyc(0)
C1 = orth.chebyc(1)
with np.errstate(all='ignore'):
C2 = orth.chebyc(2)
C3 = orth.chebyc(3)
C4 = orth.chebyc(4)
C5 = orth.chebyc(5)
assert_array_almost_equal(C0.c,[2],13)
assert_array_almost_equal(C1.c,[1,0],13)
assert_array_almost_equal(C2.c,[1,0,-2],13)
assert_array_almost_equal(C3.c,[1,0,-3,0],13)
assert_array_almost_equal(C4.c,[1,0,-4,0,2],13)
assert_array_almost_equal(C5.c,[1,0,-5,0,5,0],13)
def test_chebys(self):
S0 = orth.chebys(0)
S1 = orth.chebys(1)
S2 = orth.chebys(2)
S3 = orth.chebys(3)
S4 = orth.chebys(4)
S5 = orth.chebys(5)
assert_array_almost_equal(S0.c,[1],13)
assert_array_almost_equal(S1.c,[1,0],13)
assert_array_almost_equal(S2.c,[1,0,-1],13)
assert_array_almost_equal(S3.c,[1,0,-2,0],13)
assert_array_almost_equal(S4.c,[1,0,-3,0,1],13)
assert_array_almost_equal(S5.c,[1,0,-4,0,3,0],13)
def test_chebyt(self):
T0 = orth.chebyt(0)
T1 = orth.chebyt(1)
T2 = orth.chebyt(2)
T3 = orth.chebyt(3)
T4 = orth.chebyt(4)
T5 = orth.chebyt(5)
assert_array_almost_equal(T0.c,[1],13)
assert_array_almost_equal(T1.c,[1,0],13)
assert_array_almost_equal(T2.c,[2,0,-1],13)
assert_array_almost_equal(T3.c,[4,0,-3,0],13)
assert_array_almost_equal(T4.c,[8,0,-8,0,1],13)
assert_array_almost_equal(T5.c,[16,0,-20,0,5,0],13)
def test_chebyu(self):
U0 = orth.chebyu(0)
U1 = orth.chebyu(1)
U2 = orth.chebyu(2)
U3 = orth.chebyu(3)
U4 = orth.chebyu(4)
U5 = orth.chebyu(5)
assert_array_almost_equal(U0.c,[1],13)
assert_array_almost_equal(U1.c,[2,0],13)
assert_array_almost_equal(U2.c,[4,0,-1],13)
assert_array_almost_equal(U3.c,[8,0,-4,0],13)
assert_array_almost_equal(U4.c,[16,0,-12,0,1],13)
assert_array_almost_equal(U5.c,[32,0,-32,0,6,0],13)
class TestGegenbauer:
def test_gegenbauer(self):
a = 5*np.random.random() - 0.5
if np.any(a == 0):
a = -0.2
Ca0 = orth.gegenbauer(0,a)
Ca1 = orth.gegenbauer(1,a)
Ca2 = orth.gegenbauer(2,a)
Ca3 = orth.gegenbauer(3,a)
Ca4 = orth.gegenbauer(4,a)
Ca5 = orth.gegenbauer(5,a)
assert_array_almost_equal(Ca0.c,array([1]),13)
assert_array_almost_equal(Ca1.c,array([2*a,0]),13)
assert_array_almost_equal(Ca2.c,array([2*a*(a+1),0,-a]),13)
assert_array_almost_equal(Ca3.c,array([4*sc.poch(a,3),0,-6*a*(a+1),
0])/3.0,11)
assert_array_almost_equal(Ca4.c,array([4*sc.poch(a,4),0,-12*sc.poch(a,3),
0,3*a*(a+1)])/6.0,11)
assert_array_almost_equal(Ca5.c,array([4*sc.poch(a,5),0,-20*sc.poch(a,4),
0,15*sc.poch(a,3),0])/15.0,11)
class TestHermite:
def test_hermite(self):
H0 = orth.hermite(0)
H1 = orth.hermite(1)
H2 = orth.hermite(2)
H3 = orth.hermite(3)
H4 = orth.hermite(4)
H5 = orth.hermite(5)
assert_array_almost_equal(H0.c,[1],13)
assert_array_almost_equal(H1.c,[2,0],13)
assert_array_almost_equal(H2.c,[4,0,-2],13)
assert_array_almost_equal(H3.c,[8,0,-12,0],13)
assert_array_almost_equal(H4.c,[16,0,-48,0,12],12)
assert_array_almost_equal(H5.c,[32,0,-160,0,120,0],12)
def test_hermitenorm(self):
# He_n(x) = 2**(-n/2) H_n(x/sqrt(2))
psub = np.poly1d([1.0/sqrt(2),0])
H0 = orth.hermitenorm(0)
H1 = orth.hermitenorm(1)
H2 = orth.hermitenorm(2)
H3 = orth.hermitenorm(3)
H4 = orth.hermitenorm(4)
H5 = orth.hermitenorm(5)
he0 = orth.hermite(0)(psub)
he1 = orth.hermite(1)(psub) / sqrt(2)
he2 = orth.hermite(2)(psub) / 2.0
he3 = orth.hermite(3)(psub) / (2*sqrt(2))
he4 = orth.hermite(4)(psub) / 4.0
he5 = orth.hermite(5)(psub) / (4.0*sqrt(2))
assert_array_almost_equal(H0.c,he0.c,13)
assert_array_almost_equal(H1.c,he1.c,13)
assert_array_almost_equal(H2.c,he2.c,13)
assert_array_almost_equal(H3.c,he3.c,13)
assert_array_almost_equal(H4.c,he4.c,13)
assert_array_almost_equal(H5.c,he5.c,13)
class _test_sh_legendre:
def test_sh_legendre(self):
# P*_n(x) = P_n(2x-1)
psub = np.poly1d([2,-1])
Ps0 = orth.sh_legendre(0)
Ps1 = orth.sh_legendre(1)
Ps2 = orth.sh_legendre(2)
Ps3 = orth.sh_legendre(3)
Ps4 = orth.sh_legendre(4)
Ps5 = orth.sh_legendre(5)
pse0 = orth.legendre(0)(psub)
pse1 = orth.legendre(1)(psub)
pse2 = orth.legendre(2)(psub)
pse3 = orth.legendre(3)(psub)
pse4 = orth.legendre(4)(psub)
pse5 = orth.legendre(5)(psub)
assert_array_almost_equal(Ps0.c,pse0.c,13)
assert_array_almost_equal(Ps1.c,pse1.c,13)
assert_array_almost_equal(Ps2.c,pse2.c,13)
assert_array_almost_equal(Ps3.c,pse3.c,13)
assert_array_almost_equal(Ps4.c,pse4.c,12)
assert_array_almost_equal(Ps5.c,pse5.c,12)
class _test_sh_chebyt:
def test_sh_chebyt(self):
# T*_n(x) = T_n(2x-1)
psub = np.poly1d([2,-1])
Ts0 = orth.sh_chebyt(0)
Ts1 = orth.sh_chebyt(1)
Ts2 = orth.sh_chebyt(2)
Ts3 = orth.sh_chebyt(3)
Ts4 = orth.sh_chebyt(4)
Ts5 = orth.sh_chebyt(5)
tse0 = orth.chebyt(0)(psub)
tse1 = orth.chebyt(1)(psub)
tse2 = orth.chebyt(2)(psub)
tse3 = orth.chebyt(3)(psub)
tse4 = orth.chebyt(4)(psub)
tse5 = orth.chebyt(5)(psub)
assert_array_almost_equal(Ts0.c,tse0.c,13)
assert_array_almost_equal(Ts1.c,tse1.c,13)
assert_array_almost_equal(Ts2.c,tse2.c,13)
assert_array_almost_equal(Ts3.c,tse3.c,13)
assert_array_almost_equal(Ts4.c,tse4.c,12)
assert_array_almost_equal(Ts5.c,tse5.c,12)
class _test_sh_chebyu:
def test_sh_chebyu(self):
# U*_n(x) = U_n(2x-1)
psub = np.poly1d([2,-1])
Us0 = orth.sh_chebyu(0)
Us1 = orth.sh_chebyu(1)
Us2 = orth.sh_chebyu(2)
Us3 = orth.sh_chebyu(3)
Us4 = orth.sh_chebyu(4)
Us5 = orth.sh_chebyu(5)
use0 = orth.chebyu(0)(psub)
use1 = orth.chebyu(1)(psub)
use2 = orth.chebyu(2)(psub)
use3 = orth.chebyu(3)(psub)
use4 = orth.chebyu(4)(psub)
use5 = orth.chebyu(5)(psub)
assert_array_almost_equal(Us0.c,use0.c,13)
assert_array_almost_equal(Us1.c,use1.c,13)
assert_array_almost_equal(Us2.c,use2.c,13)
assert_array_almost_equal(Us3.c,use3.c,13)
assert_array_almost_equal(Us4.c,use4.c,12)
assert_array_almost_equal(Us5.c,use5.c,11)
class _test_sh_jacobi:
def test_sh_jacobi(self):
# G^(p,q)_n(x) = n! gamma(n+p)/gamma(2*n+p) * P^(p-q,q-1)_n(2*x-1)
conv = lambda n,p: gamma(n+1)*gamma(n+p)/gamma(2*n+p)
psub = np.poly1d([2,-1])
q = 4 * np.random.random()
p = q-1 + 2*np.random.random()
# print("shifted jacobi p,q = ", p, q)
G0 = orth.sh_jacobi(0,p,q)
G1 = orth.sh_jacobi(1,p,q)
G2 = orth.sh_jacobi(2,p,q)
G3 = orth.sh_jacobi(3,p,q)
G4 = orth.sh_jacobi(4,p,q)
G5 = orth.sh_jacobi(5,p,q)
ge0 = orth.jacobi(0,p-q,q-1)(psub) * conv(0,p)
ge1 = orth.jacobi(1,p-q,q-1)(psub) * conv(1,p)
ge2 = orth.jacobi(2,p-q,q-1)(psub) * conv(2,p)
ge3 = orth.jacobi(3,p-q,q-1)(psub) * conv(3,p)
ge4 = orth.jacobi(4,p-q,q-1)(psub) * conv(4,p)
ge5 = orth.jacobi(5,p-q,q-1)(psub) * conv(5,p)
assert_array_almost_equal(G0.c,ge0.c,13)
assert_array_almost_equal(G1.c,ge1.c,13)
assert_array_almost_equal(G2.c,ge2.c,13)
assert_array_almost_equal(G3.c,ge3.c,13)
assert_array_almost_equal(G4.c,ge4.c,13)
assert_array_almost_equal(G5.c,ge5.c,13)
class TestCall:
def test_call(self):
poly = []
for n in range(5):
poly.extend([x.strip() for x in
("""
orth.jacobi(%(n)d,0.3,0.9)
orth.sh_jacobi(%(n)d,0.3,0.9)
orth.genlaguerre(%(n)d,0.3)
orth.laguerre(%(n)d)
orth.hermite(%(n)d)
orth.hermitenorm(%(n)d)
orth.gegenbauer(%(n)d,0.3)
orth.chebyt(%(n)d)
orth.chebyu(%(n)d)
orth.chebyc(%(n)d)
orth.chebys(%(n)d)
orth.sh_chebyt(%(n)d)
orth.sh_chebyu(%(n)d)
orth.legendre(%(n)d)
orth.sh_legendre(%(n)d)
""" % dict(n=n)).split()
])
with np.errstate(all='ignore'):
for pstr in poly:
p = eval(pstr)
assert_almost_equal(p(0.315), np.poly1d(p.coef)(0.315),
err_msg=pstr)
class TestGenlaguerre:
def test_regression(self):
assert_equal(orth.genlaguerre(1, 1, monic=False)(0), 2.)
assert_equal(orth.genlaguerre(1, 1, monic=True)(0), -2.)
assert_equal(orth.genlaguerre(1, 1, monic=False), np.poly1d([-1, 2]))
assert_equal(orth.genlaguerre(1, 1, monic=True), np.poly1d([1, -2]))
def verify_gauss_quad(root_func, eval_func, weight_func, a, b, N,
rtol=1e-15, atol=5e-14):
# this test is copied from numpy's TestGauss in test_hermite.py
x, w, mu = root_func(N, True)
n = np.arange(N)
v = eval_func(n[:,np.newaxis], x)
vv = np.dot(v*w, v.T)
vd = 1 / np.sqrt(vv.diagonal())
vv = vd[:, np.newaxis] * vv * vd
assert_allclose(vv, np.eye(N), rtol, atol)
# check that the integral of 1 is correct
assert_allclose(w.sum(), mu, rtol, atol)
# compare the results of integrating a function with quad.
f = lambda x: x**3 - 3*x**2 + x - 2
resI = integrate.quad(lambda x: f(x)*weight_func(x), a, b)
resG = np.vdot(f(x), w)
rtol = 1e-6 if 1e-6 < resI[1] else resI[1] * 10
assert_allclose(resI[0], resG, rtol=rtol)
def test_roots_jacobi():
rf = lambda a, b: lambda n, mu: sc.roots_jacobi(n, a, b, mu)
ef = lambda a, b: lambda n, x: sc.eval_jacobi(n, a, b, x)
wf = lambda a, b: lambda x: (1 - x)**a * (1 + x)**b
vgq = verify_gauss_quad
vgq(rf(-0.5, -0.75), ef(-0.5, -0.75), wf(-0.5, -0.75), -1., 1., 5)
vgq(rf(-0.5, -0.75), ef(-0.5, -0.75), wf(-0.5, -0.75), -1., 1.,
25, atol=1e-12)
vgq(rf(-0.5, -0.75), ef(-0.5, -0.75), wf(-0.5, -0.75), -1., 1.,
100, atol=1e-11)
vgq(rf(0.5, -0.5), ef(0.5, -0.5), wf(0.5, -0.5), -1., 1., 5)
vgq(rf(0.5, -0.5), ef(0.5, -0.5), wf(0.5, -0.5), -1., 1., 25, atol=1.5e-13)
vgq(rf(0.5, -0.5), ef(0.5, -0.5), wf(0.5, -0.5), -1., 1., 100, atol=2e-12)
vgq(rf(1, 0.5), ef(1, 0.5), wf(1, 0.5), -1., 1., 5, atol=2e-13)
vgq(rf(1, 0.5), ef(1, 0.5), wf(1, 0.5), -1., 1., 25, atol=2e-13)
vgq(rf(1, 0.5), ef(1, 0.5), wf(1, 0.5), -1., 1., 100, atol=1e-12)
vgq(rf(0.9, 2), ef(0.9, 2), wf(0.9, 2), -1., 1., 5)
vgq(rf(0.9, 2), ef(0.9, 2), wf(0.9, 2), -1., 1., 25, atol=1e-13)
vgq(rf(0.9, 2), ef(0.9, 2), wf(0.9, 2), -1., 1., 100, atol=3e-13)
vgq(rf(18.24, 27.3), ef(18.24, 27.3), wf(18.24, 27.3), -1., 1., 5)
vgq(rf(18.24, 27.3), ef(18.24, 27.3), wf(18.24, 27.3), -1., 1., 25,
atol=1.1e-14)
vgq(rf(18.24, 27.3), ef(18.24, 27.3), wf(18.24, 27.3), -1., 1.,
100, atol=1e-13)
vgq(rf(47.1, -0.2), ef(47.1, -0.2), wf(47.1, -0.2), -1., 1., 5, atol=1e-13)
vgq(rf(47.1, -0.2), ef(47.1, -0.2), wf(47.1, -0.2), -1., 1., 25, atol=2e-13)
vgq(rf(47.1, -0.2), ef(47.1, -0.2), wf(47.1, -0.2), -1., 1.,
100, atol=1e-11)
vgq(rf(1., 658.), ef(1., 658.), wf(1., 658.), -1., 1., 5, atol=2e-13)
vgq(rf(1., 658.), ef(1., 658.), wf(1., 658.), -1., 1., 25, atol=1e-12)
vgq(rf(1., 658.), ef(1., 658.), wf(1., 658.), -1., 1., 100, atol=1e-11)
vgq(rf(1., 658.), ef(1., 658.), wf(1., 658.), -1., 1., 250, atol=1e-11)
vgq(rf(511., 511.), ef(511., 511.), wf(511., 511.), -1., 1., 5,
atol=1e-12)
vgq(rf(511., 511.), ef(511., 511.), wf(511., 511.), -1., 1., 25,
atol=1e-11)
vgq(rf(511., 511.), ef(511., 511.), wf(511., 511.), -1., 1., 100,
atol=1e-10)
vgq(rf(511., 512.), ef(511., 512.), wf(511., 512.), -1., 1., 5,
atol=1e-12)
vgq(rf(511., 512.), ef(511., 512.), wf(511., 512.), -1., 1., 25,
atol=1e-11)
vgq(rf(511., 512.), ef(511., 512.), wf(511., 512.), -1., 1., 100,
atol=1e-10)
vgq(rf(1000., 500.), ef(1000., 500.), wf(1000., 500.), -1., 1., 5,
atol=1e-12)
vgq(rf(1000., 500.), ef(1000., 500.), wf(1000., 500.), -1., 1., 25,
atol=1e-11)
vgq(rf(1000., 500.), ef(1000., 500.), wf(1000., 500.), -1., 1., 100,
atol=1e-10)
vgq(rf(2.25, 68.9), ef(2.25, 68.9), wf(2.25, 68.9), -1., 1., 5)
vgq(rf(2.25, 68.9), ef(2.25, 68.9), wf(2.25, 68.9), -1., 1., 25,
atol=1e-13)
vgq(rf(2.25, 68.9), ef(2.25, 68.9), wf(2.25, 68.9), -1., 1., 100,
atol=1e-13)
# when alpha == beta == 0, P_n^{a,b}(x) == P_n(x)
xj, wj = sc.roots_jacobi(6, 0.0, 0.0)
xl, wl = sc.roots_legendre(6)
assert_allclose(xj, xl, 1e-14, 1e-14)
assert_allclose(wj, wl, 1e-14, 1e-14)
# when alpha == beta != 0, P_n^{a,b}(x) == C_n^{alpha+0.5}(x)
xj, wj = sc.roots_jacobi(6, 4.0, 4.0)
xc, wc = sc.roots_gegenbauer(6, 4.5)
assert_allclose(xj, xc, 1e-14, 1e-14)
assert_allclose(wj, wc, 1e-14, 1e-14)
x, w = sc.roots_jacobi(5, 2, 3, False)
y, v, m = sc.roots_jacobi(5, 2, 3, True)
assert_allclose(x, y, 1e-14, 1e-14)
assert_allclose(w, v, 1e-14, 1e-14)
muI, muI_err = integrate.quad(wf(2,3), -1, 1)
assert_allclose(m, muI, rtol=muI_err)
assert_raises(ValueError, sc.roots_jacobi, 0, 1, 1)
assert_raises(ValueError, sc.roots_jacobi, 3.3, 1, 1)
assert_raises(ValueError, sc.roots_jacobi, 3, -2, 1)
assert_raises(ValueError, sc.roots_jacobi, 3, 1, -2)
assert_raises(ValueError, sc.roots_jacobi, 3, -2, -2)
def test_roots_sh_jacobi():
rf = lambda a, b: lambda n, mu: sc.roots_sh_jacobi(n, a, b, mu)
ef = lambda a, b: lambda n, x: sc.eval_sh_jacobi(n, a, b, x)
wf = lambda a, b: lambda x: (1. - x)**(a - b) * (x)**(b - 1.)
vgq = verify_gauss_quad
vgq(rf(-0.5, 0.25), ef(-0.5, 0.25), wf(-0.5, 0.25), 0., 1., 5)
vgq(rf(-0.5, 0.25), ef(-0.5, 0.25), wf(-0.5, 0.25), 0., 1.,
25, atol=1e-12)
vgq(rf(-0.5, 0.25), ef(-0.5, 0.25), wf(-0.5, 0.25), 0., 1.,
100, atol=1e-11)
vgq(rf(0.5, 0.5), ef(0.5, 0.5), wf(0.5, 0.5), 0., 1., 5)
vgq(rf(0.5, 0.5), ef(0.5, 0.5), wf(0.5, 0.5), 0., 1., 25, atol=1e-13)
vgq(rf(0.5, 0.5), ef(0.5, 0.5), wf(0.5, 0.5), 0., 1., 100, atol=1e-12)
vgq(rf(1, 0.5), ef(1, 0.5), wf(1, 0.5), 0., 1., 5)
vgq(rf(1, 0.5), ef(1, 0.5), wf(1, 0.5), 0., 1., 25, atol=1.5e-13)
vgq(rf(1, 0.5), ef(1, 0.5), wf(1, 0.5), 0., 1., 100, atol=2e-12)
vgq(rf(2, 0.9), ef(2, 0.9), wf(2, 0.9), 0., 1., 5)
vgq(rf(2, 0.9), ef(2, 0.9), wf(2, 0.9), 0., 1., 25, atol=1e-13)
vgq(rf(2, 0.9), ef(2, 0.9), wf(2, 0.9), 0., 1., 100, atol=1e-12)
vgq(rf(27.3, 18.24), ef(27.3, 18.24), wf(27.3, 18.24), 0., 1., 5)
vgq(rf(27.3, 18.24), ef(27.3, 18.24), wf(27.3, 18.24), 0., 1., 25)
vgq(rf(27.3, 18.24), ef(27.3, 18.24), wf(27.3, 18.24), 0., 1.,
100, atol=1e-13)
vgq(rf(47.1, 0.2), ef(47.1, 0.2), wf(47.1, 0.2), 0., 1., 5, atol=1e-12)
vgq(rf(47.1, 0.2), ef(47.1, 0.2), wf(47.1, 0.2), 0., 1., 25, atol=1e-11)
vgq(rf(47.1, 0.2), ef(47.1, 0.2), wf(47.1, 0.2), 0., 1., 100, atol=1e-10)
vgq(rf(68.9, 2.25), ef(68.9, 2.25), wf(68.9, 2.25), 0., 1., 5, atol=3.5e-14)
vgq(rf(68.9, 2.25), ef(68.9, 2.25), wf(68.9, 2.25), 0., 1., 25, atol=2e-13)
vgq(rf(68.9, 2.25), ef(68.9, 2.25), wf(68.9, 2.25), 0., 1.,
100, atol=1e-12)
x, w = sc.roots_sh_jacobi(5, 3, 2, False)
y, v, m = sc.roots_sh_jacobi(5, 3, 2, True)
assert_allclose(x, y, 1e-14, 1e-14)
assert_allclose(w, v, 1e-14, 1e-14)
muI, muI_err = integrate.quad(wf(3,2), 0, 1)
assert_allclose(m, muI, rtol=muI_err)
assert_raises(ValueError, sc.roots_sh_jacobi, 0, 1, 1)
assert_raises(ValueError, sc.roots_sh_jacobi, 3.3, 1, 1)
assert_raises(ValueError, sc.roots_sh_jacobi, 3, 1, 2) # p - q <= -1
assert_raises(ValueError, sc.roots_sh_jacobi, 3, 2, -1) # q <= 0
assert_raises(ValueError, sc.roots_sh_jacobi, 3, -2, -1) # both
def test_roots_hermite():
rootf = sc.roots_hermite
evalf = sc.eval_hermite
weightf = orth.hermite(5).weight_func
verify_gauss_quad(rootf, evalf, weightf, -np.inf, np.inf, 5)
verify_gauss_quad(rootf, evalf, weightf, -np.inf, np.inf, 25, atol=1e-13)
verify_gauss_quad(rootf, evalf, weightf, -np.inf, np.inf, 100, atol=1e-12)
# Golub-Welsch branch
x, w = sc.roots_hermite(5, False)
y, v, m = sc.roots_hermite(5, True)
assert_allclose(x, y, 1e-14, 1e-14)
assert_allclose(w, v, 1e-14, 1e-14)
muI, muI_err = integrate.quad(weightf, -np.inf, np.inf)
assert_allclose(m, muI, rtol=muI_err)
# Asymptotic branch (switch over at n >= 150)
x, w = sc.roots_hermite(200, False)
y, v, m = sc.roots_hermite(200, True)
assert_allclose(x, y, 1e-14, 1e-14)
assert_allclose(w, v, 1e-14, 1e-14)
assert_allclose(sum(v), m, 1e-14, 1e-14)
assert_raises(ValueError, sc.roots_hermite, 0)
assert_raises(ValueError, sc.roots_hermite, 3.3)
def test_roots_hermite_asy():
# Recursion for Hermite functions
def hermite_recursion(n, nodes):
H = np.zeros((n, nodes.size))
H[0,:] = np.pi**(-0.25) * np.exp(-0.5*nodes**2)
if n > 1:
H[1,:] = sqrt(2.0) * nodes * H[0,:]
for k in range(2, n):
H[k,:] = sqrt(2.0/k) * nodes * H[k-1,:] - sqrt((k-1.0)/k) * H[k-2,:]
return H
# This tests only the nodes
def test(N, rtol=1e-15, atol=1e-14):
x, w = orth._roots_hermite_asy(N)
H = hermite_recursion(N+1, x)
assert_allclose(H[-1,:], np.zeros(N), rtol, atol)
assert_allclose(sum(w), sqrt(np.pi), rtol, atol)
test(150, atol=1e-12)
test(151, atol=1e-12)
test(300, atol=1e-12)
test(301, atol=1e-12)
test(500, atol=1e-12)
test(501, atol=1e-12)
test(999, atol=1e-12)
test(1000, atol=1e-12)
test(2000, atol=1e-12)
test(5000, atol=1e-12)
def test_roots_hermitenorm():
rootf = sc.roots_hermitenorm
evalf = sc.eval_hermitenorm
weightf = orth.hermitenorm(5).weight_func
verify_gauss_quad(rootf, evalf, weightf, -np.inf, np.inf, 5)
verify_gauss_quad(rootf, evalf, weightf, -np.inf, np.inf, 25, atol=1e-13)
verify_gauss_quad(rootf, evalf, weightf, -np.inf, np.inf, 100, atol=1e-12)
x, w = sc.roots_hermitenorm(5, False)
y, v, m = sc.roots_hermitenorm(5, True)
assert_allclose(x, y, 1e-14, 1e-14)
assert_allclose(w, v, 1e-14, 1e-14)
muI, muI_err = integrate.quad(weightf, -np.inf, np.inf)
assert_allclose(m, muI, rtol=muI_err)
assert_raises(ValueError, sc.roots_hermitenorm, 0)
assert_raises(ValueError, sc.roots_hermitenorm, 3.3)
def test_roots_gegenbauer():
rootf = lambda a: lambda n, mu: sc.roots_gegenbauer(n, a, mu)
evalf = lambda a: lambda n, x: sc.eval_gegenbauer(n, a, x)
weightf = lambda a: lambda x: (1 - x**2)**(a - 0.5)
vgq = verify_gauss_quad
vgq(rootf(-0.25), evalf(-0.25), weightf(-0.25), -1., 1., 5)
vgq(rootf(-0.25), evalf(-0.25), weightf(-0.25), -1., 1., 25, atol=1e-12)
vgq(rootf(-0.25), evalf(-0.25), weightf(-0.25), -1., 1., 100, atol=1e-11)
vgq(rootf(0.1), evalf(0.1), weightf(0.1), -1., 1., 5)
vgq(rootf(0.1), evalf(0.1), weightf(0.1), -1., 1., 25, atol=1e-13)
vgq(rootf(0.1), evalf(0.1), weightf(0.1), -1., 1., 100, atol=1e-12)
vgq(rootf(1), evalf(1), weightf(1), -1., 1., 5)
vgq(rootf(1), evalf(1), weightf(1), -1., 1., 25, atol=1e-13)
vgq(rootf(1), evalf(1), weightf(1), -1., 1., 100, atol=1e-12)
vgq(rootf(10), evalf(10), weightf(10), -1., 1., 5)
vgq(rootf(10), evalf(10), weightf(10), -1., 1., 25, atol=1e-13)
vgq(rootf(10), evalf(10), weightf(10), -1., 1., 100, atol=1e-12)
vgq(rootf(50), evalf(50), weightf(50), -1., 1., 5, atol=1e-13)
vgq(rootf(50), evalf(50), weightf(50), -1., 1., 25, atol=1e-12)
vgq(rootf(50), evalf(50), weightf(50), -1., 1., 100, atol=1e-11)
# Alpha=170 is where the approximation used in roots_gegenbauer changes
vgq(rootf(170), evalf(170), weightf(170), -1., 1., 5, atol=1e-13)
vgq(rootf(170), evalf(170), weightf(170), -1., 1., 25, atol=1e-12)
vgq(rootf(170), evalf(170), weightf(170), -1., 1., 100, atol=1e-11)
vgq(rootf(170.5), evalf(170.5), weightf(170.5), -1., 1., 5, atol=1.25e-13)
vgq(rootf(170.5), evalf(170.5), weightf(170.5), -1., 1., 25, atol=1e-12)
vgq(rootf(170.5), evalf(170.5), weightf(170.5), -1., 1., 100, atol=1e-11)
# Test for failures, e.g. overflows, resulting from large alphas
vgq(rootf(238), evalf(238), weightf(238), -1., 1., 5, atol=1e-13)
vgq(rootf(238), evalf(238), weightf(238), -1., 1., 25, atol=1e-12)
vgq(rootf(238), evalf(238), weightf(238), -1., 1., 100, atol=1e-11)
vgq(rootf(512.5), evalf(512.5), weightf(512.5), -1., 1., 5, atol=1e-12)
vgq(rootf(512.5), evalf(512.5), weightf(512.5), -1., 1., 25, atol=1e-11)
vgq(rootf(512.5), evalf(512.5), weightf(512.5), -1., 1., 100, atol=1e-10)
# this is a special case that the old code supported.
# when alpha = 0, the gegenbauer polynomial is uniformly 0. but it goes
# to a scaled down copy of T_n(x) there.
vgq(rootf(0), sc.eval_chebyt, weightf(0), -1., 1., 5)
vgq(rootf(0), sc.eval_chebyt, weightf(0), -1., 1., 25)
vgq(rootf(0), sc.eval_chebyt, weightf(0), -1., 1., 100, atol=1e-12)
x, w = sc.roots_gegenbauer(5, 2, False)
y, v, m = sc.roots_gegenbauer(5, 2, True)
assert_allclose(x, y, 1e-14, 1e-14)
assert_allclose(w, v, 1e-14, 1e-14)
muI, muI_err = integrate.quad(weightf(2), -1, 1)
assert_allclose(m, muI, rtol=muI_err)
assert_raises(ValueError, sc.roots_gegenbauer, 0, 2)
assert_raises(ValueError, sc.roots_gegenbauer, 3.3, 2)
assert_raises(ValueError, sc.roots_gegenbauer, 3, -.75)
def test_roots_chebyt():
weightf = orth.chebyt(5).weight_func
verify_gauss_quad(sc.roots_chebyt, sc.eval_chebyt, weightf, -1., 1., 5)
verify_gauss_quad(sc.roots_chebyt, sc.eval_chebyt, weightf, -1., 1., 25)
verify_gauss_quad(sc.roots_chebyt, sc.eval_chebyt, weightf, -1., 1., 100, atol=1e-12)
x, w = sc.roots_chebyt(5, False)
y, v, m = sc.roots_chebyt(5, True)
assert_allclose(x, y, 1e-14, 1e-14)
assert_allclose(w, v, 1e-14, 1e-14)
muI, muI_err = integrate.quad(weightf, -1, 1)
assert_allclose(m, muI, rtol=muI_err)
assert_raises(ValueError, sc.roots_chebyt, 0)
assert_raises(ValueError, sc.roots_chebyt, 3.3)
def test_chebyt_symmetry():
x, w = sc.roots_chebyt(21)
pos, neg = x[:10], x[11:]
assert_equal(neg, -pos[::-1])
assert_equal(x[10], 0)
def test_roots_chebyu():
weightf = orth.chebyu(5).weight_func
verify_gauss_quad(sc.roots_chebyu, sc.eval_chebyu, weightf, -1., 1., 5)
verify_gauss_quad(sc.roots_chebyu, sc.eval_chebyu, weightf, -1., 1., 25)
verify_gauss_quad(sc.roots_chebyu, sc.eval_chebyu, weightf, -1., 1., 100)
x, w = sc.roots_chebyu(5, False)
y, v, m = sc.roots_chebyu(5, True)
assert_allclose(x, y, 1e-14, 1e-14)
assert_allclose(w, v, 1e-14, 1e-14)
muI, muI_err = integrate.quad(weightf, -1, 1)
assert_allclose(m, muI, rtol=muI_err)
assert_raises(ValueError, sc.roots_chebyu, 0)
assert_raises(ValueError, sc.roots_chebyu, 3.3)
def test_roots_chebyc():
weightf = orth.chebyc(5).weight_func
verify_gauss_quad(sc.roots_chebyc, sc.eval_chebyc, weightf, -2., 2., 5)
verify_gauss_quad(sc.roots_chebyc, sc.eval_chebyc, weightf, -2., 2., 25)
verify_gauss_quad(sc.roots_chebyc, sc.eval_chebyc, weightf, -2., 2., 100, atol=1e-12)
x, w = sc.roots_chebyc(5, False)
y, v, m = sc.roots_chebyc(5, True)
assert_allclose(x, y, 1e-14, 1e-14)
assert_allclose(w, v, 1e-14, 1e-14)
muI, muI_err = integrate.quad(weightf, -2, 2)
assert_allclose(m, muI, rtol=muI_err)
assert_raises(ValueError, sc.roots_chebyc, 0)
assert_raises(ValueError, sc.roots_chebyc, 3.3)
def test_roots_chebys():
weightf = orth.chebys(5).weight_func
verify_gauss_quad(sc.roots_chebys, sc.eval_chebys, weightf, -2., 2., 5)
verify_gauss_quad(sc.roots_chebys, sc.eval_chebys, weightf, -2., 2., 25)
verify_gauss_quad(sc.roots_chebys, sc.eval_chebys, weightf, -2., 2., 100)
x, w = sc.roots_chebys(5, False)
y, v, m = sc.roots_chebys(5, True)
assert_allclose(x, y, 1e-14, 1e-14)
assert_allclose(w, v, 1e-14, 1e-14)
muI, muI_err = integrate.quad(weightf, -2, 2)
assert_allclose(m, muI, rtol=muI_err)
assert_raises(ValueError, sc.roots_chebys, 0)
assert_raises(ValueError, sc.roots_chebys, 3.3)
def test_roots_sh_chebyt():
weightf = orth.sh_chebyt(5).weight_func
verify_gauss_quad(sc.roots_sh_chebyt, sc.eval_sh_chebyt, weightf, 0., 1., 5)
verify_gauss_quad(sc.roots_sh_chebyt, sc.eval_sh_chebyt, weightf, 0., 1., 25)
verify_gauss_quad(sc.roots_sh_chebyt, sc.eval_sh_chebyt, weightf, 0., 1.,
100, atol=1e-13)
x, w = sc.roots_sh_chebyt(5, False)
y, v, m = sc.roots_sh_chebyt(5, True)
assert_allclose(x, y, 1e-14, 1e-14)
assert_allclose(w, v, 1e-14, 1e-14)
muI, muI_err = integrate.quad(weightf, 0, 1)
assert_allclose(m, muI, rtol=muI_err)
assert_raises(ValueError, sc.roots_sh_chebyt, 0)
assert_raises(ValueError, sc.roots_sh_chebyt, 3.3)
def test_roots_sh_chebyu():
weightf = orth.sh_chebyu(5).weight_func
verify_gauss_quad(sc.roots_sh_chebyu, sc.eval_sh_chebyu, weightf, 0., 1., 5)
verify_gauss_quad(sc.roots_sh_chebyu, sc.eval_sh_chebyu, weightf, 0., 1., 25)
verify_gauss_quad(sc.roots_sh_chebyu, sc.eval_sh_chebyu, weightf, 0., 1.,
100, atol=1e-13)
x, w = sc.roots_sh_chebyu(5, False)
y, v, m = sc.roots_sh_chebyu(5, True)
assert_allclose(x, y, 1e-14, 1e-14)
assert_allclose(w, v, 1e-14, 1e-14)
muI, muI_err = integrate.quad(weightf, 0, 1)
assert_allclose(m, muI, rtol=muI_err)
assert_raises(ValueError, sc.roots_sh_chebyu, 0)
assert_raises(ValueError, sc.roots_sh_chebyu, 3.3)
def test_roots_legendre():
weightf = orth.legendre(5).weight_func
verify_gauss_quad(sc.roots_legendre, sc.eval_legendre, weightf, -1., 1., 5)
verify_gauss_quad(sc.roots_legendre, sc.eval_legendre, weightf, -1., 1.,
25, atol=1e-13)
verify_gauss_quad(sc.roots_legendre, sc.eval_legendre, weightf, -1., 1.,
100, atol=1e-12)
x, w = sc.roots_legendre(5, False)
y, v, m = sc.roots_legendre(5, True)
assert_allclose(x, y, 1e-14, 1e-14)
assert_allclose(w, v, 1e-14, 1e-14)
muI, muI_err = integrate.quad(weightf, -1, 1)
assert_allclose(m, muI, rtol=muI_err)
assert_raises(ValueError, sc.roots_legendre, 0)
assert_raises(ValueError, sc.roots_legendre, 3.3)
def test_roots_sh_legendre():
weightf = orth.sh_legendre(5).weight_func
verify_gauss_quad(sc.roots_sh_legendre, sc.eval_sh_legendre, weightf, 0., 1., 5)
verify_gauss_quad(sc.roots_sh_legendre, sc.eval_sh_legendre, weightf, 0., 1.,
25, atol=1e-13)
verify_gauss_quad(sc.roots_sh_legendre, sc.eval_sh_legendre, weightf, 0., 1.,
100, atol=1e-12)
x, w = sc.roots_sh_legendre(5, False)
y, v, m = sc.roots_sh_legendre(5, True)
assert_allclose(x, y, 1e-14, 1e-14)
assert_allclose(w, v, 1e-14, 1e-14)
muI, muI_err = integrate.quad(weightf, 0, 1)
assert_allclose(m, muI, rtol=muI_err)
assert_raises(ValueError, sc.roots_sh_legendre, 0)
assert_raises(ValueError, sc.roots_sh_legendre, 3.3)
def test_roots_laguerre():
weightf = orth.laguerre(5).weight_func
verify_gauss_quad(sc.roots_laguerre, sc.eval_laguerre, weightf, 0., np.inf, 5)
verify_gauss_quad(sc.roots_laguerre, sc.eval_laguerre, weightf, 0., np.inf,
25, atol=1e-13)
verify_gauss_quad(sc.roots_laguerre, sc.eval_laguerre, weightf, 0., np.inf,
100, atol=1e-12)
x, w = sc.roots_laguerre(5, False)
y, v, m = sc.roots_laguerre(5, True)
assert_allclose(x, y, 1e-14, 1e-14)
assert_allclose(w, v, 1e-14, 1e-14)
muI, muI_err = integrate.quad(weightf, 0, np.inf)
assert_allclose(m, muI, rtol=muI_err)
assert_raises(ValueError, sc.roots_laguerre, 0)
assert_raises(ValueError, sc.roots_laguerre, 3.3)
def test_roots_genlaguerre():
rootf = lambda a: lambda n, mu: sc.roots_genlaguerre(n, a, mu)
evalf = lambda a: lambda n, x: sc.eval_genlaguerre(n, a, x)
weightf = lambda a: lambda x: x**a * np.exp(-x)
vgq = verify_gauss_quad
vgq(rootf(-0.5), evalf(-0.5), weightf(-0.5), 0., np.inf, 5)
vgq(rootf(-0.5), evalf(-0.5), weightf(-0.5), 0., np.inf, 25, atol=1e-13)
vgq(rootf(-0.5), evalf(-0.5), weightf(-0.5), 0., np.inf, 100, atol=1e-12)
vgq(rootf(0.1), evalf(0.1), weightf(0.1), 0., np.inf, 5)
vgq(rootf(0.1), evalf(0.1), weightf(0.1), 0., np.inf, 25, atol=1e-13)
vgq(rootf(0.1), evalf(0.1), weightf(0.1), 0., np.inf, 100, atol=1.6e-13)
vgq(rootf(1), evalf(1), weightf(1), 0., np.inf, 5)
vgq(rootf(1), evalf(1), weightf(1), 0., np.inf, 25, atol=1e-13)
vgq(rootf(1), evalf(1), weightf(1), 0., np.inf, 100, atol=1.03e-13)
vgq(rootf(10), evalf(10), weightf(10), 0., np.inf, 5)
vgq(rootf(10), evalf(10), weightf(10), 0., np.inf, 25, atol=1e-13)
vgq(rootf(10), evalf(10), weightf(10), 0., np.inf, 100, atol=1e-12)
vgq(rootf(50), evalf(50), weightf(50), 0., np.inf, 5)
vgq(rootf(50), evalf(50), weightf(50), 0., np.inf, 25, atol=1e-13)
vgq(rootf(50), evalf(50), weightf(50), 0., np.inf, 100, rtol=1e-14, atol=2e-13)
x, w = sc.roots_genlaguerre(5, 2, False)
y, v, m = sc.roots_genlaguerre(5, 2, True)
assert_allclose(x, y, 1e-14, 1e-14)
assert_allclose(w, v, 1e-14, 1e-14)
muI, muI_err = integrate.quad(weightf(2.), 0., np.inf)
assert_allclose(m, muI, rtol=muI_err)
assert_raises(ValueError, sc.roots_genlaguerre, 0, 2)
assert_raises(ValueError, sc.roots_genlaguerre, 3.3, 2)
assert_raises(ValueError, sc.roots_genlaguerre, 3, -1.1)
def test_gh_6721():
# Regresssion test for gh_6721. This should not raise.
sc.chebyt(65)(0.2)

View File

@@ -0,0 +1,268 @@
import numpy as np
from numpy.testing import assert_, assert_allclose
import pytest
from scipy.special import _ufuncs
import scipy.special._orthogonal as orth
from scipy.special._testutils import FuncData
def test_eval_chebyt():
n = np.arange(0, 10000, 7)
x = 2*np.random.rand() - 1
v1 = np.cos(n*np.arccos(x))
v2 = _ufuncs.eval_chebyt(n, x)
assert_(np.allclose(v1, v2, rtol=1e-15))
def test_eval_genlaguerre_restriction():
# check it returns nan for alpha <= -1
assert_(np.isnan(_ufuncs.eval_genlaguerre(0, -1, 0)))
assert_(np.isnan(_ufuncs.eval_genlaguerre(0.1, -1, 0)))
def test_warnings():
# ticket 1334
with np.errstate(all='raise'):
# these should raise no fp warnings
_ufuncs.eval_legendre(1, 0)
_ufuncs.eval_laguerre(1, 1)
_ufuncs.eval_gegenbauer(1, 1, 0)
class TestPolys:
"""
Check that the eval_* functions agree with the constructed polynomials
"""
def check_poly(self, func, cls, param_ranges=[], x_range=[], nn=10,
nparam=10, nx=10, rtol=1e-8):
np.random.seed(1234)
dataset = []
for n in np.arange(nn):
params = [a + (b-a)*np.random.rand(nparam) for a,b in param_ranges]
params = np.asarray(params).T
if not param_ranges:
params = [0]
for p in params:
if param_ranges:
p = (n,) + tuple(p)
else:
p = (n,)
x = x_range[0] + (x_range[1] - x_range[0])*np.random.rand(nx)
x[0] = x_range[0] # always include domain start point
x[1] = x_range[1] # always include domain end point
poly = np.poly1d(cls(*p).coef)
z = np.c_[np.tile(p, (nx,1)), x, poly(x)]
dataset.append(z)
dataset = np.concatenate(dataset, axis=0)
def polyfunc(*p):
p = (p[0].astype(int),) + p[1:]
return func(*p)
with np.errstate(all='raise'):
ds = FuncData(polyfunc, dataset, list(range(len(param_ranges)+2)), -1,
rtol=rtol)
ds.check()
def test_jacobi(self):
self.check_poly(_ufuncs.eval_jacobi, orth.jacobi,
param_ranges=[(-0.99, 10), (-0.99, 10)],
x_range=[-1, 1], rtol=1e-5)
def test_sh_jacobi(self):
self.check_poly(_ufuncs.eval_sh_jacobi, orth.sh_jacobi,
param_ranges=[(1, 10), (0, 1)], x_range=[0, 1],
rtol=1e-5)
def test_gegenbauer(self):
self.check_poly(_ufuncs.eval_gegenbauer, orth.gegenbauer,
param_ranges=[(-0.499, 10)], x_range=[-1, 1],
rtol=1e-7)
def test_chebyt(self):
self.check_poly(_ufuncs.eval_chebyt, orth.chebyt,
param_ranges=[], x_range=[-1, 1])
def test_chebyu(self):
self.check_poly(_ufuncs.eval_chebyu, orth.chebyu,
param_ranges=[], x_range=[-1, 1])
def test_chebys(self):
self.check_poly(_ufuncs.eval_chebys, orth.chebys,
param_ranges=[], x_range=[-2, 2])
def test_chebyc(self):
self.check_poly(_ufuncs.eval_chebyc, orth.chebyc,
param_ranges=[], x_range=[-2, 2])
def test_sh_chebyt(self):
with np.errstate(all='ignore'):
self.check_poly(_ufuncs.eval_sh_chebyt, orth.sh_chebyt,
param_ranges=[], x_range=[0, 1])
def test_sh_chebyu(self):
self.check_poly(_ufuncs.eval_sh_chebyu, orth.sh_chebyu,
param_ranges=[], x_range=[0, 1])
def test_legendre(self):
self.check_poly(_ufuncs.eval_legendre, orth.legendre,
param_ranges=[], x_range=[-1, 1])
def test_sh_legendre(self):
with np.errstate(all='ignore'):
self.check_poly(_ufuncs.eval_sh_legendre, orth.sh_legendre,
param_ranges=[], x_range=[0, 1])
def test_genlaguerre(self):
self.check_poly(_ufuncs.eval_genlaguerre, orth.genlaguerre,
param_ranges=[(-0.99, 10)], x_range=[0, 100])
def test_laguerre(self):
self.check_poly(_ufuncs.eval_laguerre, orth.laguerre,
param_ranges=[], x_range=[0, 100])
def test_hermite(self):
self.check_poly(_ufuncs.eval_hermite, orth.hermite,
param_ranges=[], x_range=[-100, 100])
def test_hermitenorm(self):
self.check_poly(_ufuncs.eval_hermitenorm, orth.hermitenorm,
param_ranges=[], x_range=[-100, 100])
class TestRecurrence:
"""
Check that the eval_* functions sig='ld->d' and 'dd->d' agree.
"""
def check_poly(self, func, param_ranges=[], x_range=[], nn=10,
nparam=10, nx=10, rtol=1e-8):
np.random.seed(1234)
dataset = []
for n in np.arange(nn):
params = [a + (b-a)*np.random.rand(nparam) for a,b in param_ranges]
params = np.asarray(params).T
if not param_ranges:
params = [0]
for p in params:
if param_ranges:
p = (n,) + tuple(p)
else:
p = (n,)
x = x_range[0] + (x_range[1] - x_range[0])*np.random.rand(nx)
x[0] = x_range[0] # always include domain start point
x[1] = x_range[1] # always include domain end point
kw = dict(sig=(len(p)+1)*'d'+'->d')
z = np.c_[np.tile(p, (nx,1)), x, func(*(p + (x,)), **kw)]
dataset.append(z)
dataset = np.concatenate(dataset, axis=0)
def polyfunc(*p):
p = (p[0].astype(int),) + p[1:]
kw = dict(sig='l'+(len(p)-1)*'d'+'->d')
return func(*p, **kw)
with np.errstate(all='raise'):
ds = FuncData(polyfunc, dataset, list(range(len(param_ranges)+2)), -1,
rtol=rtol)
ds.check()
def test_jacobi(self):
self.check_poly(_ufuncs.eval_jacobi,
param_ranges=[(-0.99, 10), (-0.99, 10)],
x_range=[-1, 1])
def test_sh_jacobi(self):
self.check_poly(_ufuncs.eval_sh_jacobi,
param_ranges=[(1, 10), (0, 1)], x_range=[0, 1])
def test_gegenbauer(self):
self.check_poly(_ufuncs.eval_gegenbauer,
param_ranges=[(-0.499, 10)], x_range=[-1, 1])
def test_chebyt(self):
self.check_poly(_ufuncs.eval_chebyt,
param_ranges=[], x_range=[-1, 1])
def test_chebyu(self):
self.check_poly(_ufuncs.eval_chebyu,
param_ranges=[], x_range=[-1, 1])
def test_chebys(self):
self.check_poly(_ufuncs.eval_chebys,
param_ranges=[], x_range=[-2, 2])
def test_chebyc(self):
self.check_poly(_ufuncs.eval_chebyc,
param_ranges=[], x_range=[-2, 2])
def test_sh_chebyt(self):
self.check_poly(_ufuncs.eval_sh_chebyt,
param_ranges=[], x_range=[0, 1])
def test_sh_chebyu(self):
self.check_poly(_ufuncs.eval_sh_chebyu,
param_ranges=[], x_range=[0, 1])
def test_legendre(self):
self.check_poly(_ufuncs.eval_legendre,
param_ranges=[], x_range=[-1, 1])
def test_sh_legendre(self):
self.check_poly(_ufuncs.eval_sh_legendre,
param_ranges=[], x_range=[0, 1])
def test_genlaguerre(self):
self.check_poly(_ufuncs.eval_genlaguerre,
param_ranges=[(-0.99, 10)], x_range=[0, 100])
def test_laguerre(self):
self.check_poly(_ufuncs.eval_laguerre,
param_ranges=[], x_range=[0, 100])
def test_hermite(self):
v = _ufuncs.eval_hermite(70, 1.0)
a = -1.457076485701412e60
assert_allclose(v, a)
def test_hermite_domain():
# Regression test for gh-11091.
assert np.isnan(_ufuncs.eval_hermite(-1, 1.0))
assert np.isnan(_ufuncs.eval_hermitenorm(-1, 1.0))
@pytest.mark.parametrize("n", [0, 1, 2])
@pytest.mark.parametrize("x", [0, 1, np.nan])
def test_hermite_nan(n, x):
# Regression test for gh-11369.
assert np.isnan(_ufuncs.eval_hermite(n, x)) == np.any(np.isnan([n, x]))
assert np.isnan(_ufuncs.eval_hermitenorm(n, x)) == np.any(np.isnan([n, x]))
@pytest.mark.parametrize('n', [0, 1, 2, 3.2])
@pytest.mark.parametrize('alpha', [1, np.nan])
@pytest.mark.parametrize('x', [2, np.nan])
def test_genlaguerre_nan(n, alpha, x):
# Regression test for gh-11361.
nan_laguerre = np.isnan(_ufuncs.eval_genlaguerre(n, alpha, x))
nan_arg = np.any(np.isnan([n, alpha, x]))
assert nan_laguerre == nan_arg
@pytest.mark.parametrize('n', [0, 1, 2, 3.2])
@pytest.mark.parametrize('alpha', [0.0, 1, np.nan])
@pytest.mark.parametrize('x', [1e-6, 2, np.nan])
def test_gegenbauer_nan(n, alpha, x):
# Regression test for gh-11370.
nan_gegenbauer = np.isnan(_ufuncs.eval_gegenbauer(n, alpha, x))
nan_arg = np.any(np.isnan([n, alpha, x]))
assert nan_gegenbauer == nan_arg

View File

@@ -0,0 +1,53 @@
import numpy as np
from numpy.testing import assert_equal, assert_allclose
import scipy.special as sc
def test_symmetries():
np.random.seed(1234)
a, h = np.random.rand(100), np.random.rand(100)
assert_equal(sc.owens_t(h, a), sc.owens_t(-h, a))
assert_equal(sc.owens_t(h, a), -sc.owens_t(h, -a))
def test_special_cases():
assert_equal(sc.owens_t(5, 0), 0)
assert_allclose(sc.owens_t(0, 5), 0.5*np.arctan(5)/np.pi,
rtol=5e-14)
# Target value is 0.5*Phi(5)*(1 - Phi(5)) for Phi the CDF of the
# standard normal distribution
assert_allclose(sc.owens_t(5, 1), 1.4332574485503512543e-07,
rtol=5e-14)
def test_nans():
assert_equal(sc.owens_t(20, np.nan), np.nan)
assert_equal(sc.owens_t(np.nan, 20), np.nan)
assert_equal(sc.owens_t(np.nan, np.nan), np.nan)
def test_infs():
h, a = 0, np.inf
# T(0, a) = 1/2π * arctan(a)
res = 1/(2*np.pi) * np.arctan(a)
assert_allclose(sc.owens_t(h, a), res, rtol=5e-14)
assert_allclose(sc.owens_t(h, -a), -res, rtol=5e-14)
h = 1
# Refer Owens T function definition in Wikipedia
# https://en.wikipedia.org/wiki/Owen%27s_T_function
# Value approximated through Numerical Integration
# using scipy.integrate.quad
# quad(lambda x: 1/(2*pi)*(exp(-0.5*(1*1)*(1+x*x))/(1+x*x)), 0, inf)
res = 0.07932762696572854
assert_allclose(sc.owens_t(h, np.inf), res, rtol=5e-14)
assert_allclose(sc.owens_t(h, -np.inf), -res, rtol=5e-14)
assert_equal(sc.owens_t(np.inf, 1), 0)
assert_equal(sc.owens_t(-np.inf, 1), 0)
assert_equal(sc.owens_t(np.inf, np.inf), 0)
assert_equal(sc.owens_t(-np.inf, np.inf), 0)
assert_equal(sc.owens_t(np.inf, -np.inf), -0.0)
assert_equal(sc.owens_t(-np.inf, -np.inf), -0.0)

View File

@@ -0,0 +1,24 @@
"""Tests for parabolic cylinder functions.
"""
import numpy as np
from numpy.testing import assert_allclose, assert_equal
import scipy.special as sc
def test_pbwa_segfault():
# Regression test for https://github.com/scipy/scipy/issues/6208.
#
# Data generated by mpmath.
#
w = 1.02276567211316867161
wp = -0.48887053372346189882
assert_allclose(sc.pbwa(0, 0), (w, wp), rtol=1e-13, atol=0)
def test_pbwa_nan():
# Check that NaN's are returned outside of the range in which the
# implementation is accurate.
pts = [(-6, -6), (-6, 6), (6, -6), (6, 6)]
for p in pts:
assert_equal(sc.pbwa(*p), (np.nan, np.nan))

View File

@@ -0,0 +1,48 @@
import numpy as np
import scipy.special as sc
from numpy.testing import assert_almost_equal, assert_array_equal
class TestPdtr:
def test(self):
val = sc.pdtr(0, 1)
assert_almost_equal(val, np.exp(-1))
def test_m_zero(self):
val = sc.pdtr([0, 1, 2], 0)
assert_array_equal(val, [1, 1, 1])
def test_rounding(self):
double_val = sc.pdtr([0.1, 1.1, 2.1], 1.0)
int_val = sc.pdtr([0, 1, 2], 1.0)
assert_array_equal(double_val, int_val)
def test_inf(self):
val = sc.pdtr(np.inf, 1.0)
assert_almost_equal(val, 1.0)
def test_domain(self):
val = sc.pdtr(-1.1, 1.0)
assert np.isnan(val)
class TestPdtrc:
def test_value(self):
val = sc.pdtrc(0, 1)
assert_almost_equal(val, 1 - np.exp(-1))
def test_m_zero(self):
val = sc.pdtrc([0, 1, 2], 0.0)
assert_array_equal(val, [0, 0, 0])
def test_rounding(self):
double_val = sc.pdtrc([0.1, 1.1, 2.1], 1.0)
int_val = sc.pdtrc([0, 1, 2], 1.0)
assert_array_equal(double_val, int_val)
def test_inf(self):
val = sc.pdtrc(np.inf, 1.0)
assert_almost_equal(val, 0.0)
def test_domain(self):
val = sc.pdtrc(-1.1, 1.0)
assert np.isnan(val)

View File

@@ -0,0 +1,65 @@
import pytest
import numpy as np
from numpy.testing import assert_allclose
from scipy.special import powm1
# Expected values were computed with mpmath, e.g.
#
# >>> import mpmath
# >>> mpmath.np.dps = 200
# >>> print(float(mpmath.powm1(2.0, 1e-7))
# 6.931472045825965e-08
#
powm1_test_cases = [
(1.25, 0.75, 0.18217701125396976, 1e-15),
(2.0, 1e-7, 6.931472045825965e-08, 1e-15),
(25.0, 5e-11, 1.6094379125636148e-10, 1e-15),
(0.99996, 0.75, -3.0000150002530058e-05, 1e-15),
(0.9999999999990905, 20, -1.81898940353014e-11, 1e-15),
(-1.25, 751.0, -6.017550852453444e+72, 2e-15)
]
@pytest.mark.parametrize('x, y, expected, rtol', powm1_test_cases)
def test_powm1(x, y, expected, rtol):
p = powm1(x, y)
assert_allclose(p, expected, rtol=rtol)
@pytest.mark.parametrize('x, y, expected',
[(0.0, 0.0, 0.0),
(0.0, -1.5, np.inf),
(0.0, 1.75, -1.0),
(-1.5, 2.0, 1.25),
(-1.5, 3.0, -4.375),
(np.nan, 0.0, 0.0),
(1.0, np.nan, 0.0),
(1.0, np.inf, 0.0),
(1.0, -np.inf, 0.0),
(np.inf, 7.5, np.inf),
(np.inf, -7.5, -1.0),
(3.25, np.inf, np.inf),
(np.inf, np.inf, np.inf),
(np.inf, -np.inf, -1.0),
(np.inf, 0.0, 0.0),
(-np.inf, 0.0, 0.0),
(-np.inf, 2.0, np.inf),
(-np.inf, 3.0, -np.inf),
(-1.0, float(2**53 - 1), -2.0)])
def test_powm1_exact_cases(x, y, expected):
# Test cases where we have an exact expected value.
p = powm1(x, y)
assert p == expected
@pytest.mark.parametrize('x, y',
[(-1.25, 751.03),
(-1.25, np.inf),
(np.nan, np.nan),
(-np.inf, -np.inf),
(-np.inf, 2.5)])
def test_powm1_return_nan(x, y):
# Test cases where the expected return value is nan.
p = powm1(x, y)
assert np.isnan(p)

View File

@@ -0,0 +1,24 @@
from numpy.testing import assert_equal
from scipy.special._testutils import check_version, MissingModule
from scipy.special._precompute.expn_asy import generate_A
try:
import sympy
from sympy import Poly
except ImportError:
sympy = MissingModule("sympy")
@check_version(sympy, "1.0")
def test_generate_A():
# Data from DLMF 8.20.5
x = sympy.symbols('x')
Astd = [Poly(1, x),
Poly(1, x),
Poly(1 - 2*x),
Poly(1 - 8*x + 6*x**2)]
Ares = generate_A(len(Astd))
for p, q in zip(Astd, Ares):
assert_equal(p, q)

View File

@@ -0,0 +1,109 @@
import numpy as np # np is actually used, in the decorators below.
import pytest
from scipy.special._testutils import MissingModule, check_version
from scipy.special._mptestutils import (
Arg, IntArg, mp_assert_allclose, assert_mpmath_equal)
from scipy.special._precompute.gammainc_asy import (
compute_g, compute_alpha, compute_d)
from scipy.special._precompute.gammainc_data import gammainc, gammaincc
try:
import sympy
except ImportError:
sympy = MissingModule('sympy')
try:
import mpmath as mp
except ImportError:
mp = MissingModule('mpmath')
@check_version(mp, '0.19')
def test_g():
# Test data for the g_k. See DLMF 5.11.4.
with mp.workdps(30):
g = [mp.mpf(1), mp.mpf(1)/12, mp.mpf(1)/288,
-mp.mpf(139)/51840, -mp.mpf(571)/2488320,
mp.mpf(163879)/209018880, mp.mpf(5246819)/75246796800]
mp_assert_allclose(compute_g(7), g)
@pytest.mark.slow
@check_version(mp, '0.19')
@check_version(sympy, '0.7')
@pytest.mark.xfail_on_32bit("rtol only 2e-11, see gh-6938")
def test_alpha():
# Test data for the alpha_k. See DLMF 8.12.14.
with mp.workdps(30):
alpha = [mp.mpf(0), mp.mpf(1), mp.mpf(1)/3, mp.mpf(1)/36,
-mp.mpf(1)/270, mp.mpf(1)/4320, mp.mpf(1)/17010,
-mp.mpf(139)/5443200, mp.mpf(1)/204120]
mp_assert_allclose(compute_alpha(9), alpha)
@pytest.mark.xslow
@check_version(mp, '0.19')
@check_version(sympy, '0.7')
def test_d():
# Compare the d_{k, n} to the results in appendix F of [1].
#
# Sources
# -------
# [1] DiDonato and Morris, Computation of the Incomplete Gamma
# Function Ratios and their Inverse, ACM Transactions on
# Mathematical Software, 1986.
with mp.workdps(50):
dataset = [(0, 0, -mp.mpf('0.333333333333333333333333333333')),
(0, 12, mp.mpf('0.102618097842403080425739573227e-7')),
(1, 0, -mp.mpf('0.185185185185185185185185185185e-2')),
(1, 12, mp.mpf('0.119516285997781473243076536700e-7')),
(2, 0, mp.mpf('0.413359788359788359788359788360e-2')),
(2, 12, -mp.mpf('0.140925299108675210532930244154e-7')),
(3, 0, mp.mpf('0.649434156378600823045267489712e-3')),
(3, 12, -mp.mpf('0.191111684859736540606728140873e-7')),
(4, 0, -mp.mpf('0.861888290916711698604702719929e-3')),
(4, 12, mp.mpf('0.288658297427087836297341274604e-7')),
(5, 0, -mp.mpf('0.336798553366358150308767592718e-3')),
(5, 12, mp.mpf('0.482409670378941807563762631739e-7')),
(6, 0, mp.mpf('0.531307936463992223165748542978e-3')),
(6, 12, -mp.mpf('0.882860074633048352505085243179e-7')),
(7, 0, mp.mpf('0.344367606892377671254279625109e-3')),
(7, 12, -mp.mpf('0.175629733590604619378669693914e-6')),
(8, 0, -mp.mpf('0.652623918595309418922034919727e-3')),
(8, 12, mp.mpf('0.377358774161109793380344937299e-6')),
(9, 0, -mp.mpf('0.596761290192746250124390067179e-3')),
(9, 12, mp.mpf('0.870823417786464116761231237189e-6'))]
d = compute_d(10, 13)
res = [d[k][n] for k, n, std in dataset]
std = [x[2] for x in dataset]
mp_assert_allclose(res, std)
@check_version(mp, '0.19')
def test_gammainc():
# Quick check that the gammainc in
# special._precompute.gammainc_data agrees with mpmath's
# gammainc.
assert_mpmath_equal(gammainc,
lambda a, x: mp.gammainc(a, b=x, regularized=True),
[Arg(0, 100, inclusive_a=False), Arg(0, 100)],
nan_ok=False, rtol=1e-17, n=50, dps=50)
@pytest.mark.xslow
@check_version(mp, '0.19')
def test_gammaincc():
# Check that the gammaincc in special._precompute.gammainc_data
# agrees with mpmath's gammainc.
assert_mpmath_equal(lambda a, x: gammaincc(a, x, dps=1000),
lambda a, x: mp.gammainc(a, a=x, regularized=True),
[Arg(20, 100), Arg(20, 100)],
nan_ok=False, rtol=1e-17, n=50, dps=1000)
# Test the fast integer path
assert_mpmath_equal(gammaincc,
lambda a, x: mp.gammainc(a, a=x, regularized=True),
[IntArg(1, 100), Arg(0, 100)],
nan_ok=False, rtol=1e-17, n=50, dps=50)

View File

@@ -0,0 +1,36 @@
import pytest
from scipy.special._testutils import MissingModule, check_version
from scipy.special._mptestutils import mp_assert_allclose
from scipy.special._precompute.utils import lagrange_inversion
try:
import sympy
except ImportError:
sympy = MissingModule('sympy')
try:
import mpmath as mp
except ImportError:
mp = MissingModule('mpmath')
@pytest.mark.slow
@check_version(sympy, '0.7')
@check_version(mp, '0.19')
class TestInversion:
@pytest.mark.xfail_on_32bit("rtol only 2e-9, see gh-6938")
def test_log(self):
with mp.workdps(30):
logcoeffs = mp.taylor(lambda x: mp.log(1 + x), 0, 10)
expcoeffs = mp.taylor(lambda x: mp.exp(x) - 1, 0, 10)
invlogcoeffs = lagrange_inversion(logcoeffs)
mp_assert_allclose(invlogcoeffs, expcoeffs)
@pytest.mark.xfail_on_32bit("rtol only 1e-15, see gh-6938")
def test_sin(self):
with mp.workdps(30):
sincoeffs = mp.taylor(mp.sin, 0, 10)
asincoeffs = mp.taylor(mp.asin, 0, 10)
invsincoeffs = lagrange_inversion(sincoeffs)
mp_assert_allclose(invsincoeffs, asincoeffs, atol=1e-30)

View File

@@ -0,0 +1,16 @@
import numpy as np
import pytest
from scipy.special import _test_internal
@pytest.mark.skipif(not _test_internal.have_fenv(), reason="no fenv()")
def test_add_round_up():
np.random.seed(1234)
_test_internal.test_add_round(10**5, 'up')
@pytest.mark.skipif(not _test_internal.have_fenv(), reason="no fenv()")
def test_add_round_down():
np.random.seed(1234)
_test_internal.test_add_round(10**5, 'down')

View File

@@ -0,0 +1,122 @@
import sys
import warnings
from numpy.testing import assert_, assert_equal, IS_PYPY
import pytest
from pytest import raises as assert_raises
import scipy.special as sc
from scipy.special._ufuncs import _sf_error_test_function
_sf_error_code_map = {
# skip 'ok'
'singular': 1,
'underflow': 2,
'overflow': 3,
'slow': 4,
'loss': 5,
'no_result': 6,
'domain': 7,
'arg': 8,
'other': 9
}
_sf_error_actions = [
'ignore',
'warn',
'raise'
]
def _check_action(fun, args, action):
if action == 'warn':
with pytest.warns(sc.SpecialFunctionWarning):
fun(*args)
elif action == 'raise':
with assert_raises(sc.SpecialFunctionError):
fun(*args)
else:
# action == 'ignore', make sure there are no warnings/exceptions
with warnings.catch_warnings():
warnings.simplefilter("error")
fun(*args)
def test_geterr():
err = sc.geterr()
for key, value in err.items():
assert_(key in _sf_error_code_map)
assert_(value in _sf_error_actions)
def test_seterr():
entry_err = sc.geterr()
try:
for category, error_code in _sf_error_code_map.items():
for action in _sf_error_actions:
geterr_olderr = sc.geterr()
seterr_olderr = sc.seterr(**{category: action})
assert_(geterr_olderr == seterr_olderr)
newerr = sc.geterr()
assert_(newerr[category] == action)
geterr_olderr.pop(category)
newerr.pop(category)
assert_(geterr_olderr == newerr)
_check_action(_sf_error_test_function, (error_code,), action)
finally:
sc.seterr(**entry_err)
@pytest.mark.skipif(IS_PYPY, reason="Test not meaningful on PyPy")
def test_sf_error_special_refcount():
# Regression test for gh-16233.
# Check that the reference count of scipy.special is not increased
# when a SpecialFunctionError is raised.
refcount_before = sys.getrefcount(sc)
with sc.errstate(all='raise'):
with pytest.raises(sc.SpecialFunctionError, match='domain error'):
sc.ndtri(2.0)
refcount_after = sys.getrefcount(sc)
assert refcount_after == refcount_before
def test_errstate_pyx_basic():
olderr = sc.geterr()
with sc.errstate(singular='raise'):
with assert_raises(sc.SpecialFunctionError):
sc.loggamma(0)
assert_equal(olderr, sc.geterr())
def test_errstate_c_basic():
olderr = sc.geterr()
with sc.errstate(domain='raise'):
with assert_raises(sc.SpecialFunctionError):
sc.spence(-1)
assert_equal(olderr, sc.geterr())
def test_errstate_cpp_basic():
olderr = sc.geterr()
with sc.errstate(underflow='raise'):
with assert_raises(sc.SpecialFunctionError):
sc.wrightomega(-1000)
assert_equal(olderr, sc.geterr())
def test_errstate():
for category, error_code in _sf_error_code_map.items():
for action in _sf_error_actions:
olderr = sc.geterr()
with sc.errstate(**{category: action}):
_check_action(_sf_error_test_function, (error_code,), action)
assert_equal(olderr, sc.geterr())
def test_errstate_all_but_one():
olderr = sc.geterr()
with sc.errstate(all='raise', singular='ignore'):
sc.gammaln(0)
with assert_raises(sc.SpecialFunctionError):
sc.spence(-1.0)
assert_equal(olderr, sc.geterr())

View File

@@ -0,0 +1,36 @@
import numpy as np
import scipy.special as sc
from scipy.special._testutils import FuncData
def test_sici_consistency():
# Make sure the implementation of sici for real arguments agrees
# with the implementation of sici for complex arguments.
# On the negative real axis Cephes drops the imaginary part in ci
def sici(x):
si, ci = sc.sici(x + 0j)
return si.real, ci.real
x = np.r_[-np.logspace(8, -30, 200), 0, np.logspace(-30, 8, 200)]
si, ci = sc.sici(x)
dataset = np.column_stack((x, si, ci))
FuncData(sici, dataset, 0, (1, 2), rtol=1e-12).check()
def test_shichi_consistency():
# Make sure the implementation of shichi for real arguments agrees
# with the implementation of shichi for complex arguments.
# On the negative real axis Cephes drops the imaginary part in chi
def shichi(x):
shi, chi = sc.shichi(x + 0j)
return shi.real, chi.real
# Overflow happens quickly, so limit range
x = np.r_[-np.logspace(np.log10(700), -30, 200), 0,
np.logspace(-30, np.log10(700), 200)]
shi, chi = sc.shichi(x)
dataset = np.column_stack((x, shi, chi))
FuncData(shichi, dataset, 0, (1, 2), rtol=1e-14).check()

View File

@@ -0,0 +1,32 @@
import numpy as np
from numpy import sqrt, log, pi
from scipy.special._testutils import FuncData
from scipy.special import spence
def test_consistency():
# Make sure the implementation of spence for real arguments
# agrees with the implementation of spence for imaginary arguments.
x = np.logspace(-30, 300, 200)
dataset = np.vstack((x + 0j, spence(x))).T
FuncData(spence, dataset, 0, 1, rtol=1e-14).check()
def test_special_points():
# Check against known values of Spence's function.
phi = (1 + sqrt(5))/2
dataset = [(1, 0),
(2, -pi**2/12),
(0.5, pi**2/12 - log(2)**2/2),
(0, pi**2/6),
(-1, pi**2/4 - 1j*pi*log(2)),
((-1 + sqrt(5))/2, pi**2/15 - log(phi)**2),
((3 - sqrt(5))/2, pi**2/10 - log(phi)**2),
(phi, -pi**2/15 + log(phi)**2/2),
# Corrected from Zagier, "The Dilogarithm Function"
((3 + sqrt(5))/2, -pi**2/10 - log(phi)**2)]
dataset = np.asarray(dataset)
FuncData(spence, dataset, 0, 1, rtol=1e-14).check()

View File

@@ -0,0 +1,61 @@
import numpy as np
from numpy.testing import (assert_array_equal,
assert_array_almost_equal_nulp, assert_almost_equal)
from pytest import raises as assert_raises
from scipy.special import gammaln, multigammaln
class TestMultiGammaLn:
def test1(self):
# A test of the identity
# Gamma_1(a) = Gamma(a)
np.random.seed(1234)
a = np.abs(np.random.randn())
assert_array_equal(multigammaln(a, 1), gammaln(a))
def test2(self):
# A test of the identity
# Gamma_2(a) = sqrt(pi) * Gamma(a) * Gamma(a - 0.5)
a = np.array([2.5, 10.0])
result = multigammaln(a, 2)
expected = np.log(np.sqrt(np.pi)) + gammaln(a) + gammaln(a - 0.5)
assert_almost_equal(result, expected)
def test_bararg(self):
assert_raises(ValueError, multigammaln, 0.5, 1.2)
def _check_multigammaln_array_result(a, d):
# Test that the shape of the array returned by multigammaln
# matches the input shape, and that all the values match
# the value computed when multigammaln is called with a scalar.
result = multigammaln(a, d)
assert_array_equal(a.shape, result.shape)
a1 = a.ravel()
result1 = result.ravel()
for i in range(a.size):
assert_array_almost_equal_nulp(result1[i], multigammaln(a1[i], d))
def test_multigammaln_array_arg():
# Check that the array returned by multigammaln has the correct
# shape and contains the correct values. The cases have arrays
# with several differnent shapes.
# The cases include a regression test for ticket #1849
# (a = np.array([2.0]), an array with a single element).
np.random.seed(1234)
cases = [
# a, d
(np.abs(np.random.randn(3, 2)) + 5, 5),
(np.abs(np.random.randn(1, 2)) + 5, 5),
(np.arange(10.0, 18.0).reshape(2, 2, 2), 3),
(np.array([2.0]), 3),
(np.float64(2.0), 3),
]
for a, d in cases:
_check_multigammaln_array_result(a, d)

View File

@@ -0,0 +1,37 @@
import numpy as np
from numpy.testing import assert_allclose
import scipy.special as sc
def test_first_harmonics():
# Test against explicit representations of the first four
# spherical harmonics which use `theta` as the azimuthal angle,
# `phi` as the polar angle, and include the Condon-Shortley
# phase.
# Notation is Ymn
def Y00(theta, phi):
return 0.5*np.sqrt(1/np.pi)
def Yn11(theta, phi):
return 0.5*np.sqrt(3/(2*np.pi))*np.exp(-1j*theta)*np.sin(phi)
def Y01(theta, phi):
return 0.5*np.sqrt(3/np.pi)*np.cos(phi)
def Y11(theta, phi):
return -0.5*np.sqrt(3/(2*np.pi))*np.exp(1j*theta)*np.sin(phi)
harms = [Y00, Yn11, Y01, Y11]
m = [0, -1, 0, 1]
n = [0, 1, 1, 1]
theta = np.linspace(0, 2*np.pi)
phi = np.linspace(0, np.pi)
theta, phi = np.meshgrid(theta, phi)
for harm, m, n in zip(harms, m, n):
assert_allclose(sc.sph_harm(m, n, theta, phi),
harm(theta, phi),
rtol=1e-15, atol=1e-15,
err_msg="Y^{}_{} incorrect".format(m, n))

View File

@@ -0,0 +1,379 @@
#
# Tests of spherical Bessel functions.
#
import numpy as np
from numpy.testing import (assert_almost_equal, assert_allclose,
assert_array_almost_equal, suppress_warnings)
import pytest
from numpy import sin, cos, sinh, cosh, exp, inf, nan, r_, pi
from scipy.special import spherical_jn, spherical_yn, spherical_in, spherical_kn
from scipy.integrate import quad
class TestSphericalJn:
def test_spherical_jn_exact(self):
# https://dlmf.nist.gov/10.49.E3
# Note: exact expression is numerically stable only for small
# n or z >> n.
x = np.array([0.12, 1.23, 12.34, 123.45, 1234.5])
assert_allclose(spherical_jn(2, x),
(-1/x + 3/x**3)*sin(x) - 3/x**2*cos(x))
def test_spherical_jn_recurrence_complex(self):
# https://dlmf.nist.gov/10.51.E1
n = np.array([1, 2, 3, 7, 12])
x = 1.1 + 1.5j
assert_allclose(spherical_jn(n - 1, x) + spherical_jn(n + 1, x),
(2*n + 1)/x*spherical_jn(n, x))
def test_spherical_jn_recurrence_real(self):
# https://dlmf.nist.gov/10.51.E1
n = np.array([1, 2, 3, 7, 12])
x = 0.12
assert_allclose(spherical_jn(n - 1, x) + spherical_jn(n + 1,x),
(2*n + 1)/x*spherical_jn(n, x))
def test_spherical_jn_inf_real(self):
# https://dlmf.nist.gov/10.52.E3
n = 6
x = np.array([-inf, inf])
assert_allclose(spherical_jn(n, x), np.array([0, 0]))
def test_spherical_jn_inf_complex(self):
# https://dlmf.nist.gov/10.52.E3
n = 7
x = np.array([-inf + 0j, inf + 0j, inf*(1+1j)])
with suppress_warnings() as sup:
sup.filter(RuntimeWarning, "invalid value encountered in multiply")
assert_allclose(spherical_jn(n, x), np.array([0, 0, inf*(1+1j)]))
def test_spherical_jn_large_arg_1(self):
# https://github.com/scipy/scipy/issues/2165
# Reference value computed using mpmath, via
# besselj(n + mpf(1)/2, z)*sqrt(pi/(2*z))
assert_allclose(spherical_jn(2, 3350.507), -0.00029846226538040747)
def test_spherical_jn_large_arg_2(self):
# https://github.com/scipy/scipy/issues/1641
# Reference value computed using mpmath, via
# besselj(n + mpf(1)/2, z)*sqrt(pi/(2*z))
assert_allclose(spherical_jn(2, 10000), 3.0590002633029811e-05)
def test_spherical_jn_at_zero(self):
# https://dlmf.nist.gov/10.52.E1
# But note that n = 0 is a special case: j0 = sin(x)/x -> 1
n = np.array([0, 1, 2, 5, 10, 100])
x = 0
assert_allclose(spherical_jn(n, x), np.array([1, 0, 0, 0, 0, 0]))
class TestSphericalYn:
def test_spherical_yn_exact(self):
# https://dlmf.nist.gov/10.49.E5
# Note: exact expression is numerically stable only for small
# n or z >> n.
x = np.array([0.12, 1.23, 12.34, 123.45, 1234.5])
assert_allclose(spherical_yn(2, x),
(1/x - 3/x**3)*cos(x) - 3/x**2*sin(x))
def test_spherical_yn_recurrence_real(self):
# https://dlmf.nist.gov/10.51.E1
n = np.array([1, 2, 3, 7, 12])
x = 0.12
assert_allclose(spherical_yn(n - 1, x) + spherical_yn(n + 1,x),
(2*n + 1)/x*spherical_yn(n, x))
def test_spherical_yn_recurrence_complex(self):
# https://dlmf.nist.gov/10.51.E1
n = np.array([1, 2, 3, 7, 12])
x = 1.1 + 1.5j
assert_allclose(spherical_yn(n - 1, x) + spherical_yn(n + 1, x),
(2*n + 1)/x*spherical_yn(n, x))
def test_spherical_yn_inf_real(self):
# https://dlmf.nist.gov/10.52.E3
n = 6
x = np.array([-inf, inf])
assert_allclose(spherical_yn(n, x), np.array([0, 0]))
def test_spherical_yn_inf_complex(self):
# https://dlmf.nist.gov/10.52.E3
n = 7
x = np.array([-inf + 0j, inf + 0j, inf*(1+1j)])
with suppress_warnings() as sup:
sup.filter(RuntimeWarning, "invalid value encountered in multiply")
assert_allclose(spherical_yn(n, x), np.array([0, 0, inf*(1+1j)]))
def test_spherical_yn_at_zero(self):
# https://dlmf.nist.gov/10.52.E2
n = np.array([0, 1, 2, 5, 10, 100])
x = 0
assert_allclose(spherical_yn(n, x), np.full(n.shape, -inf))
def test_spherical_yn_at_zero_complex(self):
# Consistently with numpy:
# >>> -np.cos(0)/0
# -inf
# >>> -np.cos(0+0j)/(0+0j)
# (-inf + nan*j)
n = np.array([0, 1, 2, 5, 10, 100])
x = 0 + 0j
assert_allclose(spherical_yn(n, x), np.full(n.shape, nan))
class TestSphericalJnYnCrossProduct:
def test_spherical_jn_yn_cross_product_1(self):
# https://dlmf.nist.gov/10.50.E3
n = np.array([1, 5, 8])
x = np.array([0.1, 1, 10])
left = (spherical_jn(n + 1, x) * spherical_yn(n, x) -
spherical_jn(n, x) * spherical_yn(n + 1, x))
right = 1/x**2
assert_allclose(left, right)
def test_spherical_jn_yn_cross_product_2(self):
# https://dlmf.nist.gov/10.50.E3
n = np.array([1, 5, 8])
x = np.array([0.1, 1, 10])
left = (spherical_jn(n + 2, x) * spherical_yn(n, x) -
spherical_jn(n, x) * spherical_yn(n + 2, x))
right = (2*n + 3)/x**3
assert_allclose(left, right)
class TestSphericalIn:
def test_spherical_in_exact(self):
# https://dlmf.nist.gov/10.49.E9
x = np.array([0.12, 1.23, 12.34, 123.45])
assert_allclose(spherical_in(2, x),
(1/x + 3/x**3)*sinh(x) - 3/x**2*cosh(x))
def test_spherical_in_recurrence_real(self):
# https://dlmf.nist.gov/10.51.E4
n = np.array([1, 2, 3, 7, 12])
x = 0.12
assert_allclose(spherical_in(n - 1, x) - spherical_in(n + 1,x),
(2*n + 1)/x*spherical_in(n, x))
def test_spherical_in_recurrence_complex(self):
# https://dlmf.nist.gov/10.51.E1
n = np.array([1, 2, 3, 7, 12])
x = 1.1 + 1.5j
assert_allclose(spherical_in(n - 1, x) - spherical_in(n + 1,x),
(2*n + 1)/x*spherical_in(n, x))
def test_spherical_in_inf_real(self):
# https://dlmf.nist.gov/10.52.E3
n = 5
x = np.array([-inf, inf])
assert_allclose(spherical_in(n, x), np.array([-inf, inf]))
def test_spherical_in_inf_complex(self):
# https://dlmf.nist.gov/10.52.E5
# Ideally, i1n(n, 1j*inf) = 0 and i1n(n, (1+1j)*inf) = (1+1j)*inf, but
# this appears impossible to achieve because C99 regards any complex
# value with at least one infinite part as a complex infinity, so
# 1j*inf cannot be distinguished from (1+1j)*inf. Therefore, nan is
# the correct return value.
n = 7
x = np.array([-inf + 0j, inf + 0j, inf*(1+1j)])
assert_allclose(spherical_in(n, x), np.array([-inf, inf, nan]))
def test_spherical_in_at_zero(self):
# https://dlmf.nist.gov/10.52.E1
# But note that n = 0 is a special case: i0 = sinh(x)/x -> 1
n = np.array([0, 1, 2, 5, 10, 100])
x = 0
assert_allclose(spherical_in(n, x), np.array([1, 0, 0, 0, 0, 0]))
class TestSphericalKn:
def test_spherical_kn_exact(self):
# https://dlmf.nist.gov/10.49.E13
x = np.array([0.12, 1.23, 12.34, 123.45])
assert_allclose(spherical_kn(2, x),
pi/2*exp(-x)*(1/x + 3/x**2 + 3/x**3))
def test_spherical_kn_recurrence_real(self):
# https://dlmf.nist.gov/10.51.E4
n = np.array([1, 2, 3, 7, 12])
x = 0.12
assert_allclose((-1)**(n - 1)*spherical_kn(n - 1, x) - (-1)**(n + 1)*spherical_kn(n + 1,x),
(-1)**n*(2*n + 1)/x*spherical_kn(n, x))
def test_spherical_kn_recurrence_complex(self):
# https://dlmf.nist.gov/10.51.E4
n = np.array([1, 2, 3, 7, 12])
x = 1.1 + 1.5j
assert_allclose((-1)**(n - 1)*spherical_kn(n - 1, x) - (-1)**(n + 1)*spherical_kn(n + 1,x),
(-1)**n*(2*n + 1)/x*spherical_kn(n, x))
def test_spherical_kn_inf_real(self):
# https://dlmf.nist.gov/10.52.E6
n = 5
x = np.array([-inf, inf])
assert_allclose(spherical_kn(n, x), np.array([-inf, 0]))
def test_spherical_kn_inf_complex(self):
# https://dlmf.nist.gov/10.52.E6
# The behavior at complex infinity depends on the sign of the real
# part: if Re(z) >= 0, then the limit is 0; if Re(z) < 0, then it's
# z*inf. This distinction cannot be captured, so we return nan.
n = 7
x = np.array([-inf + 0j, inf + 0j, inf*(1+1j)])
assert_allclose(spherical_kn(n, x), np.array([-inf, 0, nan]))
def test_spherical_kn_at_zero(self):
# https://dlmf.nist.gov/10.52.E2
n = np.array([0, 1, 2, 5, 10, 100])
x = 0
assert_allclose(spherical_kn(n, x), np.full(n.shape, inf))
def test_spherical_kn_at_zero_complex(self):
# https://dlmf.nist.gov/10.52.E2
n = np.array([0, 1, 2, 5, 10, 100])
x = 0 + 0j
assert_allclose(spherical_kn(n, x), np.full(n.shape, nan))
class SphericalDerivativesTestCase:
def fundamental_theorem(self, n, a, b):
integral, tolerance = quad(lambda z: self.df(n, z), a, b)
assert_allclose(integral,
self.f(n, b) - self.f(n, a),
atol=tolerance)
@pytest.mark.slow
def test_fundamental_theorem_0(self):
self.fundamental_theorem(0, 3.0, 15.0)
@pytest.mark.slow
def test_fundamental_theorem_7(self):
self.fundamental_theorem(7, 0.5, 1.2)
class TestSphericalJnDerivatives(SphericalDerivativesTestCase):
def f(self, n, z):
return spherical_jn(n, z)
def df(self, n, z):
return spherical_jn(n, z, derivative=True)
def test_spherical_jn_d_zero(self):
n = np.array([0, 1, 2, 3, 7, 15])
assert_allclose(spherical_jn(n, 0, derivative=True),
np.array([0, 1/3, 0, 0, 0, 0]))
class TestSphericalYnDerivatives(SphericalDerivativesTestCase):
def f(self, n, z):
return spherical_yn(n, z)
def df(self, n, z):
return spherical_yn(n, z, derivative=True)
class TestSphericalInDerivatives(SphericalDerivativesTestCase):
def f(self, n, z):
return spherical_in(n, z)
def df(self, n, z):
return spherical_in(n, z, derivative=True)
def test_spherical_in_d_zero(self):
n = np.array([1, 2, 3, 7, 15])
assert_allclose(spherical_in(n, 0, derivative=True),
np.zeros(5))
class TestSphericalKnDerivatives(SphericalDerivativesTestCase):
def f(self, n, z):
return spherical_kn(n, z)
def df(self, n, z):
return spherical_kn(n, z, derivative=True)
class TestSphericalOld:
# These are tests from the TestSpherical class of test_basic.py,
# rewritten to use spherical_* instead of sph_* but otherwise unchanged.
def test_sph_in(self):
# This test reproduces test_basic.TestSpherical.test_sph_in.
i1n = np.empty((2,2))
x = 0.2
i1n[0][0] = spherical_in(0, x)
i1n[0][1] = spherical_in(1, x)
i1n[1][0] = spherical_in(0, x, derivative=True)
i1n[1][1] = spherical_in(1, x, derivative=True)
inp0 = (i1n[0][1])
inp1 = (i1n[0][0] - 2.0/0.2 * i1n[0][1])
assert_array_almost_equal(i1n[0],np.array([1.0066800127054699381,
0.066933714568029540839]),12)
assert_array_almost_equal(i1n[1],[inp0,inp1],12)
def test_sph_in_kn_order0(self):
x = 1.
sph_i0 = np.empty((2,))
sph_i0[0] = spherical_in(0, x)
sph_i0[1] = spherical_in(0, x, derivative=True)
sph_i0_expected = np.array([np.sinh(x)/x,
np.cosh(x)/x-np.sinh(x)/x**2])
assert_array_almost_equal(r_[sph_i0], sph_i0_expected)
sph_k0 = np.empty((2,))
sph_k0[0] = spherical_kn(0, x)
sph_k0[1] = spherical_kn(0, x, derivative=True)
sph_k0_expected = np.array([0.5*pi*exp(-x)/x,
-0.5*pi*exp(-x)*(1/x+1/x**2)])
assert_array_almost_equal(r_[sph_k0], sph_k0_expected)
def test_sph_jn(self):
s1 = np.empty((2,3))
x = 0.2
s1[0][0] = spherical_jn(0, x)
s1[0][1] = spherical_jn(1, x)
s1[0][2] = spherical_jn(2, x)
s1[1][0] = spherical_jn(0, x, derivative=True)
s1[1][1] = spherical_jn(1, x, derivative=True)
s1[1][2] = spherical_jn(2, x, derivative=True)
s10 = -s1[0][1]
s11 = s1[0][0]-2.0/0.2*s1[0][1]
s12 = s1[0][1]-3.0/0.2*s1[0][2]
assert_array_almost_equal(s1[0],[0.99334665397530607731,
0.066400380670322230863,
0.0026590560795273856680],12)
assert_array_almost_equal(s1[1],[s10,s11,s12],12)
def test_sph_kn(self):
kn = np.empty((2,3))
x = 0.2
kn[0][0] = spherical_kn(0, x)
kn[0][1] = spherical_kn(1, x)
kn[0][2] = spherical_kn(2, x)
kn[1][0] = spherical_kn(0, x, derivative=True)
kn[1][1] = spherical_kn(1, x, derivative=True)
kn[1][2] = spherical_kn(2, x, derivative=True)
kn0 = -kn[0][1]
kn1 = -kn[0][0]-2.0/0.2*kn[0][1]
kn2 = -kn[0][1]-3.0/0.2*kn[0][2]
assert_array_almost_equal(kn[0],[6.4302962978445670140,
38.581777787067402086,
585.15696310385559829],12)
assert_array_almost_equal(kn[1],[kn0,kn1,kn2],9)
def test_sph_yn(self):
sy1 = spherical_yn(2, 0.2)
sy2 = spherical_yn(0, 0.2)
assert_almost_equal(sy1,-377.52483,5) # previous values in the system
assert_almost_equal(sy2,-4.9003329,5)
sphpy = (spherical_yn(0, 0.2) - 2*spherical_yn(2, 0.2))/3
sy3 = spherical_yn(1, 0.2, derivative=True)
assert_almost_equal(sy3,sphpy,4) # compare correct derivative val. (correct =-system val).

View File

@@ -0,0 +1,66 @@
import numpy as np
from numpy.testing import assert_equal, assert_allclose, suppress_warnings
from scipy.special._ufuncs import _sinpi as sinpi
from scipy.special._ufuncs import _cospi as cospi
def test_integer_real_part():
x = np.arange(-100, 101)
y = np.hstack((-np.linspace(310, -30, 10), np.linspace(-30, 310, 10)))
x, y = np.meshgrid(x, y)
z = x + 1j*y
# In the following we should be *exactly* right
res = sinpi(z)
assert_equal(res.real, 0.0)
res = cospi(z)
assert_equal(res.imag, 0.0)
def test_half_integer_real_part():
x = np.arange(-100, 101) + 0.5
y = np.hstack((-np.linspace(310, -30, 10), np.linspace(-30, 310, 10)))
x, y = np.meshgrid(x, y)
z = x + 1j*y
# In the following we should be *exactly* right
res = sinpi(z)
assert_equal(res.imag, 0.0)
res = cospi(z)
assert_equal(res.real, 0.0)
def test_intermediate_overlow():
# Make sure we avoid overflow in situations where cosh/sinh would
# overflow but the product with sin/cos would not
sinpi_pts = [complex(1 + 1e-14, 227),
complex(1e-35, 250),
complex(1e-301, 445)]
# Data generated with mpmath
sinpi_std = [complex(-8.113438309924894e+295, -np.inf),
complex(1.9507801934611995e+306, np.inf),
complex(2.205958493464539e+306, np.inf)]
with suppress_warnings() as sup:
sup.filter(RuntimeWarning, "invalid value encountered in multiply")
for p, std in zip(sinpi_pts, sinpi_std):
assert_allclose(sinpi(p), std)
# Test for cosine, less interesting because cos(0) = 1.
p = complex(0.5 + 1e-14, 227)
std = complex(-8.113438309924894e+295, -np.inf)
with suppress_warnings() as sup:
sup.filter(RuntimeWarning, "invalid value encountered in multiply")
assert_allclose(cospi(p), std)
def test_zero_sign():
y = sinpi(-0.0)
assert y == 0.0
assert np.signbit(y)
y = sinpi(0.0)
assert y == 0.0
assert not np.signbit(y)
y = cospi(0.5)
assert y == 0.0
assert not np.signbit(y)

View File

@@ -0,0 +1,115 @@
# Reference MPMATH implementation:
#
# import mpmath
# from mpmath import nsum
#
# def Wright_Series_MPMATH(a, b, z, dps=50, method='r+s+e', steps=[1000]):
# """Compute Wright' generalized Bessel function as Series.
#
# This uses mpmath for arbitrary precision.
# """
# with mpmath.workdps(dps):
# res = nsum(lambda k: z**k/mpmath.fac(k) * mpmath.rgamma(a*k+b),
# [0, mpmath.inf],
# tol=dps, method=method, steps=steps
# )
#
# return res
import pytest
import numpy as np
from numpy.testing import assert_equal, assert_allclose
import scipy.special as sc
from scipy.special import rgamma, wright_bessel
@pytest.mark.parametrize('a', [0, 1e-6, 0.1, 0.5, 1, 10])
@pytest.mark.parametrize('b', [0, 1e-6, 0.1, 0.5, 1, 10])
def test_wright_bessel_zero(a, b):
"""Test at x = 0."""
assert_equal(wright_bessel(a, b, 0.), rgamma(b))
@pytest.mark.parametrize('b', [0, 1e-6, 0.1, 0.5, 1, 10])
@pytest.mark.parametrize('x', [0, 1e-6, 0.1, 0.5, 1])
def test_wright_bessel_iv(b, x):
"""Test relation of wright_bessel and modified bessel function iv.
iv(z) = (1/2*z)**v * Phi(1, v+1; 1/4*z**2).
See https://dlmf.nist.gov/10.46.E2
"""
if x != 0:
v = b - 1
wb = wright_bessel(1, v + 1, x**2 / 4.)
# Note: iv(v, x) has precision of less than 1e-12 for some cases
# e.g v=1-1e-6 and x=1e-06)
assert_allclose(np.power(x / 2., v) * wb,
sc.iv(v, x),
rtol=1e-11, atol=1e-11)
@pytest.mark.parametrize('a', [0, 1e-6, 0.1, 0.5, 1, 10])
@pytest.mark.parametrize('b', [1, 1 + 1e-3, 2, 5, 10])
@pytest.mark.parametrize('x', [0, 1e-6, 0.1, 0.5, 1, 5, 10, 100])
def test_wright_functional(a, b, x):
"""Test functional relation of wright_bessel.
Phi(a, b-1, z) = a*z*Phi(a, b+a, z) + (b-1)*Phi(a, b, z)
Note that d/dx Phi(a, b, x) = Phi(a, b-1, x)
See Eq. (22) of
B. Stankovic, On the Function of E. M. Wright,
Publ. de l' Institut Mathematique, Beograd,
Nouvelle S`er. 10 (1970), 113-124.
"""
assert_allclose(wright_bessel(a, b - 1, x),
a * x * wright_bessel(a, b + a, x)
+ (b - 1) * wright_bessel(a, b, x),
rtol=1e-8, atol=1e-8)
# grid of rows [a, b, x, value, accuracy] that do not reach 1e-11 accuracy
# see output of:
# cd scipy/scipy/_precompute
# python wright_bessel_data.py
grid_a_b_x_value_acc = np.array([
[0.1, 100.0, 709.7827128933841, 8.026353022981087e+34, 2e-8],
[0.5, 10.0, 709.7827128933841, 2.680788404494657e+48, 9e-8],
[0.5, 10.0, 1000.0, 2.005901980702872e+64, 1e-8],
[0.5, 100.0, 1000.0, 3.4112367580445246e-117, 6e-8],
[1.0, 20.0, 100000.0, 1.7717158630699857e+225, 3e-11],
[1.0, 100.0, 100000.0, 1.0269334596230763e+22, np.nan],
[1.0000000000000222, 20.0, 100000.0, 1.7717158630001672e+225, 3e-11],
[1.0000000000000222, 100.0, 100000.0, 1.0269334595866202e+22, np.nan],
[1.5, 0.0, 500.0, 15648961196.432373, 3e-11],
[1.5, 2.220446049250313e-14, 500.0, 15648961196.431465, 3e-11],
[1.5, 1e-10, 500.0, 15648961192.344728, 3e-11],
[1.5, 1e-05, 500.0, 15648552437.334162, 3e-11],
[1.5, 0.1, 500.0, 12049870581.10317, 2e-11],
[1.5, 20.0, 100000.0, 7.81930438331405e+43, 3e-9],
[1.5, 100.0, 100000.0, 9.653370857459075e-130, np.nan],
])
@pytest.mark.xfail
@pytest.mark.parametrize(
'a, b, x, phi',
grid_a_b_x_value_acc[:, :4].tolist())
def test_wright_data_grid_failures(a, b, x, phi):
"""Test cases of test_data that do not reach relative accuracy of 1e-11"""
assert_allclose(wright_bessel(a, b, x), phi, rtol=1e-11)
@pytest.mark.parametrize(
'a, b, x, phi, accuracy',
grid_a_b_x_value_acc.tolist())
def test_wright_data_grid_less_accurate(a, b, x, phi, accuracy):
"""Test cases of test_data that do not reach relative accuracy of 1e-11
Here we test for reduced accuracy or even nan.
"""
if np.isnan(accuracy):
assert np.isnan(wright_bessel(a, b, x))
else:
assert_allclose(wright_bessel(a, b, x), phi, rtol=accuracy)

View File

@@ -0,0 +1,117 @@
import pytest
import numpy as np
from numpy.testing import assert_, assert_equal, assert_allclose
import scipy.special as sc
from scipy.special._testutils import assert_func_equal
def test_wrightomega_nan():
pts = [complex(np.nan, 0),
complex(0, np.nan),
complex(np.nan, np.nan),
complex(np.nan, 1),
complex(1, np.nan)]
for p in pts:
res = sc.wrightomega(p)
assert_(np.isnan(res.real))
assert_(np.isnan(res.imag))
def test_wrightomega_inf_branch():
pts = [complex(-np.inf, np.pi/4),
complex(-np.inf, -np.pi/4),
complex(-np.inf, 3*np.pi/4),
complex(-np.inf, -3*np.pi/4)]
expected_results = [complex(0.0, 0.0),
complex(0.0, -0.0),
complex(-0.0, 0.0),
complex(-0.0, -0.0)]
for p, expected in zip(pts, expected_results):
res = sc.wrightomega(p)
# We can't use assert_equal(res, expected) because in older versions of
# numpy, assert_equal doesn't check the sign of the real and imaginary
# parts when comparing complex zeros. It does check the sign when the
# arguments are *real* scalars.
assert_equal(res.real, expected.real)
assert_equal(res.imag, expected.imag)
def test_wrightomega_inf():
pts = [complex(np.inf, 10),
complex(-np.inf, 10),
complex(10, np.inf),
complex(10, -np.inf)]
for p in pts:
assert_equal(sc.wrightomega(p), p)
def test_wrightomega_singular():
pts = [complex(-1.0, np.pi),
complex(-1.0, -np.pi)]
for p in pts:
res = sc.wrightomega(p)
assert_equal(res, -1.0)
assert_(np.signbit(res.imag) == False)
@pytest.mark.parametrize('x, desired', [
(-np.inf, 0),
(np.inf, np.inf),
])
def test_wrightomega_real_infinities(x, desired):
assert sc.wrightomega(x) == desired
def test_wrightomega_real_nan():
assert np.isnan(sc.wrightomega(np.nan))
def test_wrightomega_real_series_crossover():
desired_error = 2 * np.finfo(float).eps
crossover = 1e20
x_before_crossover = np.nextafter(crossover, -np.inf)
x_after_crossover = np.nextafter(crossover, np.inf)
# Computed using Mpmath
desired_before_crossover = 99999999999999983569.948
desired_after_crossover = 100000000000000016337.948
assert_allclose(
sc.wrightomega(x_before_crossover),
desired_before_crossover,
atol=0,
rtol=desired_error,
)
assert_allclose(
sc.wrightomega(x_after_crossover),
desired_after_crossover,
atol=0,
rtol=desired_error,
)
def test_wrightomega_exp_approximation_crossover():
desired_error = 2 * np.finfo(float).eps
crossover = -50
x_before_crossover = np.nextafter(crossover, np.inf)
x_after_crossover = np.nextafter(crossover, -np.inf)
# Computed using Mpmath
desired_before_crossover = 1.9287498479639314876e-22
desired_after_crossover = 1.9287498479639040784e-22
assert_allclose(
sc.wrightomega(x_before_crossover),
desired_before_crossover,
atol=0,
rtol=desired_error,
)
assert_allclose(
sc.wrightomega(x_after_crossover),
desired_after_crossover,
atol=0,
rtol=desired_error,
)
def test_wrightomega_real_versus_complex():
x = np.linspace(-500, 500, 1001)
results = sc.wrightomega(x + 0j).real
assert_func_equal(sc.wrightomega, results, x, atol=0, rtol=1e-14)

Some files were not shown because too many files have changed in this diff Show More