test_boost_ufuncs.py 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import pytest
  2. import numpy as np
  3. from numpy.testing import assert_allclose
  4. import scipy.special._ufuncs as scu
  5. from scipy.integrate import tanhsinh
  6. type_char_to_type_tol = {'f': (np.float32, 32*np.finfo(np.float32).eps),
  7. 'd': (np.float64, 32*np.finfo(np.float64).eps)}
  8. # Each item in this list is
  9. # (func, args, expected_value)
  10. # All the values can be represented exactly, even with np.float32.
  11. #
  12. # This is not an exhaustive test data set of all the functions!
  13. # It is a spot check of several functions, primarily for
  14. # checking that the different data types are handled correctly.
  15. test_data = [
  16. (scu._beta_pdf, (0.5, 2, 3), 1.5),
  17. (scu._beta_pdf, (0, 1, 5), 5.0),
  18. (scu._beta_pdf, (1, 5, 1), 5.0),
  19. (scu._beta_ppf, (0.5, 5., 5.), 0.5), # gh-21303
  20. (scu._binom_cdf, (1, 3, 0.5), 0.5),
  21. (scu._binom_pmf, (1, 4, 0.5), 0.25),
  22. (scu._hypergeom_cdf, (2, 3, 5, 6), 0.5),
  23. (scu._nbinom_cdf, (1, 4, 0.25), 0.015625),
  24. (scu._ncf_mean, (10, 12, 2.5), 1.5),
  25. ]
  26. @pytest.mark.parametrize('func, args, expected', test_data)
  27. def test_stats_boost_ufunc(func, args, expected):
  28. type_sigs = func.types
  29. type_chars = [sig.split('->')[-1] for sig in type_sigs]
  30. for type_char in type_chars:
  31. typ, rtol = type_char_to_type_tol[type_char]
  32. args = [typ(arg) for arg in args]
  33. # Harmless overflow warnings are a "feature" of some wrappers on some
  34. # platforms. This test is about dtype and accuracy, so let's avoid false
  35. # test failures cause by these warnings. See gh-17432.
  36. with np.errstate(over='ignore'):
  37. value = func(*args)
  38. assert isinstance(value, typ)
  39. assert_allclose(value, expected, rtol=rtol)
  40. def test_landau():
  41. # Test that Landau distribution ufuncs are wrapped as expected;
  42. # accuracy is tested by Boost.
  43. x = np.linspace(-3, 10, 10)
  44. args = (0, 1)
  45. res = tanhsinh(lambda x: scu._landau_pdf(x, *args), -np.inf, x)
  46. cdf = scu._landau_cdf(x, *args)
  47. assert_allclose(res.integral, cdf)
  48. sf = scu._landau_sf(x, *args)
  49. assert_allclose(sf, 1-cdf)
  50. ppf = scu._landau_ppf(cdf, *args)
  51. assert_allclose(ppf, x)
  52. isf = scu._landau_isf(sf, *args)
  53. assert_allclose(isf, x, rtol=1e-6)
  54. def test_gh22956():
  55. _ = scu._ncx2_pdf(30, 1e307, 16)
  56. @pytest.mark.parametrize("func", [scu._binom_cdf, scu._binom_sf])
  57. @pytest.mark.parametrize("dtype", [np.float32, np.float64])
  58. def test_extreme_inputs_for_binomial_probabilities(func, dtype):
  59. # certain inputs caused C++ exceptions in boost
  60. # resulting in Python interpreter crashes
  61. k = 3e18
  62. n = 10e18
  63. p = 0.3
  64. func(dtype(k), dtype(n), dtype(p))
  65. @pytest.mark.parametrize("func", [scu._binom_ppf, scu._binom_isf])
  66. @pytest.mark.parametrize("dtype", [np.float32, np.float64])
  67. def test_extreme_inputs_for_binomial_quantiles(func, dtype):
  68. # certain inputs caused C++ exceptions in boost
  69. # resulting in Python interpreter crashes
  70. n = 10e18
  71. p = 0.5
  72. func(dtype(p), dtype(n), dtype(p))