test_wright_bessel.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. # Reference MPMATH implementation:
  2. #
  3. # import mpmath
  4. # from mpmath import nsum
  5. #
  6. # def Wright_Series_MPMATH(a, b, z, dps=50, method='r+s+e', steps=[1000]):
  7. # """Compute Wright' generalized Bessel function as Series.
  8. #
  9. # This uses mpmath for arbitrary precision.
  10. # """
  11. # with mpmath.workdps(dps):
  12. # res = nsum(lambda k: z**k/mpmath.fac(k) * mpmath.rgamma(a*k+b),
  13. # [0, mpmath.inf],
  14. # tol=dps, method=method, steps=steps
  15. # )
  16. #
  17. # return res
  18. import pytest
  19. import numpy as np
  20. from numpy.testing import assert_equal, assert_allclose
  21. import scipy.special as sc
  22. from scipy.special import rgamma, wright_bessel
  23. @pytest.mark.parametrize('a', [0, 1e-6, 0.1, 0.5, 1, 10])
  24. @pytest.mark.parametrize('b', [0, 1e-6, 0.1, 0.5, 1, 10])
  25. def test_wright_bessel_zero(a, b):
  26. """Test at x = 0."""
  27. assert_equal(wright_bessel(a, b, 0.), rgamma(b))
  28. @pytest.mark.parametrize('b', [0, 1e-6, 0.1, 0.5, 1, 10])
  29. @pytest.mark.parametrize('x', [0, 1e-6, 0.1, 0.5, 1])
  30. def test_wright_bessel_iv(b, x):
  31. """Test relation of wright_bessel and modified bessel function iv.
  32. iv(z) = (1/2*z)**v * Phi(1, v+1; 1/4*z**2).
  33. See https://dlmf.nist.gov/10.46.E2
  34. """
  35. if x != 0:
  36. v = b - 1
  37. wb = wright_bessel(1, v + 1, x**2 / 4.)
  38. # Note: iv(v, x) has precision of less than 1e-12 for some cases
  39. # e.g v=1-1e-6 and x=1e-06)
  40. assert_allclose(np.power(x / 2., v) * wb,
  41. sc.iv(v, x),
  42. rtol=1e-11, atol=1e-11)
  43. @pytest.mark.parametrize('a', [0, 1e-6, 0.1, 0.5, 1, 10])
  44. @pytest.mark.parametrize('b', [1, 1 + 1e-3, 2, 5, 10])
  45. @pytest.mark.parametrize('x', [0, 1e-6, 0.1, 0.5, 1, 5, 10, 100])
  46. def test_wright_functional(a, b, x):
  47. """Test functional relation of wright_bessel.
  48. Phi(a, b-1, z) = a*z*Phi(a, b+a, z) + (b-1)*Phi(a, b, z)
  49. Note that d/dx Phi(a, b, x) = Phi(a, b-1, x)
  50. See Eq. (22) of
  51. B. Stankovic, On the Function of E. M. Wright,
  52. Publ. de l' Institut Mathematique, Beograd,
  53. Nouvelle S`er. 10 (1970), 113-124.
  54. """
  55. assert_allclose(wright_bessel(a, b - 1, x),
  56. a * x * wright_bessel(a, b + a, x)
  57. + (b - 1) * wright_bessel(a, b, x),
  58. rtol=1e-8, atol=1e-8)
  59. # grid of rows [a, b, x, value, accuracy] that do not reach 1e-11 accuracy
  60. # see output of:
  61. # cd scipy/scipy/_precompute
  62. # python wright_bessel_data.py
  63. grid_a_b_x_value_acc = np.array([
  64. [0.1, 100.0, 709.7827128933841, 8.026353022981087e+34, 2e-8],
  65. [0.5, 10.0, 709.7827128933841, 2.680788404494657e+48, 9e-8],
  66. [0.5, 10.0, 1000.0, 2.005901980702872e+64, 1e-8],
  67. [0.5, 100.0, 1000.0, 3.4112367580445246e-117, 6e-8],
  68. [1.0, 20.0, 100000.0, 1.7717158630699857e+225, 3e-11],
  69. [1.0, 100.0, 100000.0, 1.0269334596230763e+22, np.nan],
  70. [1.0000000000000222, 20.0, 100000.0, 1.7717158630001672e+225, 3e-11],
  71. [1.0000000000000222, 100.0, 100000.0, 1.0269334595866202e+22, np.nan],
  72. [1.5, 0.0, 500.0, 15648961196.432373, 3e-11],
  73. [1.5, 2.220446049250313e-14, 500.0, 15648961196.431465, 3e-11],
  74. [1.5, 1e-10, 500.0, 15648961192.344728, 3e-11],
  75. [1.5, 1e-05, 500.0, 15648552437.334162, 3e-11],
  76. [1.5, 0.1, 500.0, 12049870581.10317, 2e-11],
  77. [1.5, 20.0, 100000.0, 7.81930438331405e+43, 3e-9],
  78. [1.5, 100.0, 100000.0, 9.653370857459075e-130, np.nan],
  79. ])
  80. @pytest.mark.xfail
  81. @pytest.mark.parametrize(
  82. 'a, b, x, phi',
  83. grid_a_b_x_value_acc[:, :4].tolist())
  84. def test_wright_data_grid_failures(a, b, x, phi):
  85. """Test cases of test_data that do not reach relative accuracy of 1e-11"""
  86. assert_allclose(wright_bessel(a, b, x), phi, rtol=1e-11)
  87. @pytest.mark.parametrize(
  88. 'a, b, x, phi, accuracy',
  89. grid_a_b_x_value_acc.tolist())
  90. def test_wright_data_grid_less_accurate(a, b, x, phi, accuracy):
  91. """Test cases of test_data that do not reach relative accuracy of 1e-11
  92. Here we test for reduced accuracy or even nan.
  93. """
  94. if np.isnan(accuracy):
  95. assert np.isnan(wright_bessel(a, b, x))
  96. else:
  97. assert_allclose(wright_bessel(a, b, x), phi, rtol=accuracy)