test_erfinv.py 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import numpy as np
  2. from numpy.testing import assert_allclose, assert_equal
  3. import pytest
  4. import scipy.special as sc
  5. class TestInverseErrorFunction:
  6. def test_compliment(self):
  7. # Test erfcinv(1 - x) == erfinv(x)
  8. x = np.linspace(-1, 1, 101)
  9. assert_allclose(sc.erfcinv(1 - x), sc.erfinv(x), rtol=0, atol=1e-15)
  10. def test_literal_values(self):
  11. # The expected values were calculated with mpmath:
  12. #
  13. # import mpmath
  14. # mpmath.mp.dps = 200
  15. # for y in [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]:
  16. # x = mpmath.erfinv(y)
  17. # print(x)
  18. #
  19. y = np.array([0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])
  20. actual = sc.erfinv(y)
  21. expected = [
  22. 0.0,
  23. 0.08885599049425769,
  24. 0.1791434546212917,
  25. 0.2724627147267543,
  26. 0.37080715859355795,
  27. 0.4769362762044699,
  28. 0.5951160814499948,
  29. 0.7328690779592167,
  30. 0.9061938024368233,
  31. 1.1630871536766743,
  32. ]
  33. assert_allclose(actual, expected, rtol=0, atol=1e-15)
  34. @pytest.mark.parametrize(
  35. 'f, x, y',
  36. [
  37. (sc.erfinv, -1, -np.inf),
  38. (sc.erfinv, 0, 0),
  39. (sc.erfinv, 1, np.inf),
  40. (sc.erfinv, -100, np.nan),
  41. (sc.erfinv, 100, np.nan),
  42. (sc.erfcinv, 0, np.inf),
  43. (sc.erfcinv, 1, -0.0),
  44. (sc.erfcinv, 2, -np.inf),
  45. (sc.erfcinv, -100, np.nan),
  46. (sc.erfcinv, 100, np.nan),
  47. ],
  48. ids=[
  49. 'erfinv at lower bound',
  50. 'erfinv at midpoint',
  51. 'erfinv at upper bound',
  52. 'erfinv below lower bound',
  53. 'erfinv above upper bound',
  54. 'erfcinv at lower bound',
  55. 'erfcinv at midpoint',
  56. 'erfcinv at upper bound',
  57. 'erfcinv below lower bound',
  58. 'erfcinv above upper bound',
  59. ]
  60. )
  61. def test_domain_bounds(self, f, x, y):
  62. assert_equal(f(x), y)
  63. def test_erfinv_asympt(self):
  64. # regression test for gh-12758: erfinv(x) loses precision at small x
  65. # expected values precomputed with mpmath:
  66. # >>> mpmath.mp.dps = 100
  67. # >>> expected = [float(mpmath.erfinv(t)) for t in x]
  68. x = np.array([1e-20, 1e-15, 1e-14, 1e-10, 1e-8, 0.9e-7, 1.1e-7, 1e-6])
  69. expected = np.array([8.86226925452758e-21,
  70. 8.862269254527581e-16,
  71. 8.86226925452758e-15,
  72. 8.862269254527581e-11,
  73. 8.86226925452758e-09,
  74. 7.97604232907484e-08,
  75. 9.74849617998037e-08,
  76. 8.8622692545299e-07])
  77. assert_allclose(sc.erfinv(x), expected,
  78. rtol=1e-15)
  79. # also test the roundtrip consistency
  80. assert_allclose(sc.erf(sc.erfinv(x)),
  81. x,
  82. rtol=5e-15)