ayousanz commited on
Commit
8219a32
·
verified ·
1 Parent(s): 87196c0

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +92 -0
  2. .venv/Lib/site-packages/scipy/sparse/tests/data/csc_py2.npz +3 -0
  3. .venv/Lib/site-packages/scipy/sparse/tests/data/csc_py3.npz +3 -0
  4. .venv/Lib/site-packages/scipy/special/_ufuncs_cxx.pxd +60 -0
  5. .venv/Lib/site-packages/scipy/special/special/cephes/const.h +77 -0
  6. .venv/Lib/site-packages/scipy/special/special/cephes/gamma.h +343 -0
  7. .venv/Lib/site-packages/scipy/special/special/cephes/polevl.h +165 -0
  8. .venv/Lib/site-packages/scipy/special/special/cephes/psi.h +194 -0
  9. .venv/Lib/site-packages/scipy/special/tests/test_dd.py +46 -0
  10. .venv/Lib/site-packages/scipy/special/tests/test_digamma.py +45 -0
  11. .venv/Lib/site-packages/scipy/special/tests/test_ellip_harm.py +278 -0
  12. .venv/Lib/site-packages/scipy/special/tests/test_erfinv.py +89 -0
  13. .venv/Lib/site-packages/scipy/special/tests/test_exponential_integrals.py +118 -0
  14. .venv/Lib/site-packages/scipy/special/tests/test_faddeeva.py +85 -0
  15. .venv/Lib/site-packages/scipy/special/tests/test_gamma.py +12 -0
  16. .venv/Lib/site-packages/scipy/special/tests/test_gammainc.py +136 -0
  17. .venv/Lib/site-packages/scipy/special/tests/test_hyp2f1.py +2180 -0
  18. .venv/Lib/site-packages/scipy/special/tests/test_hypergeometric.py +140 -0
  19. .venv/Lib/site-packages/scipy/special/tests/test_kolmogorov.py +495 -0
  20. .venv/Lib/site-packages/scipy/special/tests/test_lambertw.py +109 -0
  21. .venv/Lib/site-packages/scipy/special/tests/test_log_softmax.py +109 -0
  22. .venv/Lib/site-packages/scipy/special/tests/test_loggamma.py +70 -0
  23. .venv/Lib/site-packages/scipy/special/tests/test_logit.py +145 -0
  24. .venv/Lib/site-packages/scipy/special/tests/test_logsumexp.py +207 -0
  25. .venv/Lib/site-packages/scipy/special/tests/test_mpmath.py +2272 -0
  26. .venv/Lib/site-packages/scipy/special/tests/test_nan_inputs.py +64 -0
  27. .venv/Lib/site-packages/scipy/special/tests/test_ndtr.py +77 -0
  28. .venv/Lib/site-packages/scipy/special/tests/test_ndtri_exp.py +94 -0
  29. .venv/Lib/site-packages/scipy/special/tests/test_orthogonal.py +804 -0
  30. .venv/Lib/site-packages/scipy/special/tests/test_orthogonal_eval.py +272 -0
  31. .venv/Lib/site-packages/scipy/special/tests/test_owens_t.py +53 -0
  32. .venv/Lib/site-packages/scipy/special/tests/test_pcf.py +24 -0
  33. .venv/Lib/site-packages/scipy/special/tests/test_pdtr.py +48 -0
  34. .venv/Lib/site-packages/scipy/special/tests/test_powm1.py +65 -0
  35. .venv/Lib/site-packages/scipy/special/tests/test_precompute_expn_asy.py +24 -0
  36. .venv/Lib/site-packages/scipy/special/tests/test_precompute_gammainc.py +108 -0
  37. .venv/Lib/site-packages/scipy/special/tests/test_precompute_utils.py +36 -0
  38. .venv/Lib/site-packages/scipy/special/tests/test_round.py +16 -0
  39. .venv/Lib/site-packages/scipy/special/tests/test_sf_error.py +134 -0
  40. .venv/Lib/site-packages/scipy/special/tests/test_sici.py +36 -0
  41. .venv/Lib/site-packages/scipy/special/tests/test_specfun.py +36 -0
  42. .venv/Lib/site-packages/scipy/special/tests/test_spence.py +32 -0
  43. .venv/Lib/site-packages/scipy/special/tests/test_spfun_stats.py +61 -0
  44. .venv/Lib/site-packages/scipy/special/tests/test_sph_harm.py +37 -0
  45. .venv/Lib/site-packages/scipy/special/tests/test_spherical_bessel.py +385 -0
  46. .venv/Lib/site-packages/scipy/special/tests/test_support_alternative_backends.py +67 -0
  47. .venv/Lib/site-packages/scipy/special/tests/test_trig.py +72 -0
  48. .venv/Lib/site-packages/scipy/special/tests/test_wrightomega.py +117 -0
  49. .venv/Lib/site-packages/torch/lib/cublasLt64_12.dll +3 -0
  50. .venv/Lib/site-packages/torch/lib/cudnn_engines_precompiled64_9.dll +3 -0
.gitattributes CHANGED
@@ -140,3 +140,95 @@ Data/Tsukuyomi/wavs/VOICEACTRESS100_008.wav filter=lfs diff=lfs merge=lfs -text
140
  Data/Tsukuyomi/wavs/VOICEACTRESS100_012.wav filter=lfs diff=lfs merge=lfs -text
141
  Data/Tsukuyomi/wavs/VOICEACTRESS100_015.wav filter=lfs diff=lfs merge=lfs -text
142
  Data/Tsukuyomi/wavs/VOICEACTRESS100_010.wav filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  Data/Tsukuyomi/wavs/VOICEACTRESS100_012.wav filter=lfs diff=lfs merge=lfs -text
141
  Data/Tsukuyomi/wavs/VOICEACTRESS100_015.wav filter=lfs diff=lfs merge=lfs -text
142
  Data/Tsukuyomi/wavs/VOICEACTRESS100_010.wav filter=lfs diff=lfs merge=lfs -text
143
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_013.wav filter=lfs diff=lfs merge=lfs -text
144
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_016.wav filter=lfs diff=lfs merge=lfs -text
145
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_017.wav filter=lfs diff=lfs merge=lfs -text
146
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_018.wav filter=lfs diff=lfs merge=lfs -text
147
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_021.wav filter=lfs diff=lfs merge=lfs -text
148
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_023.wav filter=lfs diff=lfs merge=lfs -text
149
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_025.wav filter=lfs diff=lfs merge=lfs -text
150
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_024.wav filter=lfs diff=lfs merge=lfs -text
151
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_020.wav filter=lfs diff=lfs merge=lfs -text
152
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_022.wav filter=lfs diff=lfs merge=lfs -text
153
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_019.wav filter=lfs diff=lfs merge=lfs -text
154
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_027.wav filter=lfs diff=lfs merge=lfs -text
155
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_030.wav filter=lfs diff=lfs merge=lfs -text
156
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_041.wav filter=lfs diff=lfs merge=lfs -text
157
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_043.wav filter=lfs diff=lfs merge=lfs -text
158
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_042.wav filter=lfs diff=lfs merge=lfs -text
159
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_026.wav filter=lfs diff=lfs merge=lfs -text
160
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_028.wav filter=lfs diff=lfs merge=lfs -text
161
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_045.wav filter=lfs diff=lfs merge=lfs -text
162
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_044.wav filter=lfs diff=lfs merge=lfs -text
163
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_046.wav filter=lfs diff=lfs merge=lfs -text
164
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_047.wav filter=lfs diff=lfs merge=lfs -text
165
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_029.wav filter=lfs diff=lfs merge=lfs -text
166
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_049.wav filter=lfs diff=lfs merge=lfs -text
167
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_050.wav filter=lfs diff=lfs merge=lfs -text
168
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_048.wav filter=lfs diff=lfs merge=lfs -text
169
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_052.wav filter=lfs diff=lfs merge=lfs -text
170
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_053.wav filter=lfs diff=lfs merge=lfs -text
171
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_055.wav filter=lfs diff=lfs merge=lfs -text
172
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_054.wav filter=lfs diff=lfs merge=lfs -text
173
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_057.wav filter=lfs diff=lfs merge=lfs -text
174
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_058.wav filter=lfs diff=lfs merge=lfs -text
175
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_056.wav filter=lfs diff=lfs merge=lfs -text
176
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_060.wav filter=lfs diff=lfs merge=lfs -text
177
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_031.wav filter=lfs diff=lfs merge=lfs -text
178
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_051.wav filter=lfs diff=lfs merge=lfs -text
179
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_033.wav filter=lfs diff=lfs merge=lfs -text
180
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_059.wav filter=lfs diff=lfs merge=lfs -text
181
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_034.wav filter=lfs diff=lfs merge=lfs -text
182
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_032.wav filter=lfs diff=lfs merge=lfs -text
183
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_037.wav filter=lfs diff=lfs merge=lfs -text
184
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_036.wav filter=lfs diff=lfs merge=lfs -text
185
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_040.wav filter=lfs diff=lfs merge=lfs -text
186
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_061.wav filter=lfs diff=lfs merge=lfs -text
187
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_038.wav filter=lfs diff=lfs merge=lfs -text
188
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_035.wav filter=lfs diff=lfs merge=lfs -text
189
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_062.wav filter=lfs diff=lfs merge=lfs -text
190
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_064.wav filter=lfs diff=lfs merge=lfs -text
191
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_063.wav filter=lfs diff=lfs merge=lfs -text
192
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_067.wav filter=lfs diff=lfs merge=lfs -text
193
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_068.wav filter=lfs diff=lfs merge=lfs -text
194
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_069.wav filter=lfs diff=lfs merge=lfs -text
195
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_065.wav filter=lfs diff=lfs merge=lfs -text
196
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_039.wav filter=lfs diff=lfs merge=lfs -text
197
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_070.wav filter=lfs diff=lfs merge=lfs -text
198
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_066.wav filter=lfs diff=lfs merge=lfs -text
199
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_083.wav filter=lfs diff=lfs merge=lfs -text
200
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_082.wav filter=lfs diff=lfs merge=lfs -text
201
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_081.wav filter=lfs diff=lfs merge=lfs -text
202
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_084.wav filter=lfs diff=lfs merge=lfs -text
203
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_087.wav filter=lfs diff=lfs merge=lfs -text
204
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_085.wav filter=lfs diff=lfs merge=lfs -text
205
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_089.wav filter=lfs diff=lfs merge=lfs -text
206
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_086.wav filter=lfs diff=lfs merge=lfs -text
207
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_088.wav filter=lfs diff=lfs merge=lfs -text
208
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_090.wav filter=lfs diff=lfs merge=lfs -text
209
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_071.wav filter=lfs diff=lfs merge=lfs -text
210
+ .venv/Lib/site-packages/unidic_lite/dicdir/sys.dic filter=lfs diff=lfs merge=lfs -text
211
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_074.wav filter=lfs diff=lfs merge=lfs -text
212
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_075.wav filter=lfs diff=lfs merge=lfs -text
213
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_073.wav filter=lfs diff=lfs merge=lfs -text
214
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_076.wav filter=lfs diff=lfs merge=lfs -text
215
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_078.wav filter=lfs diff=lfs merge=lfs -text
216
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_077.wav filter=lfs diff=lfs merge=lfs -text
217
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_072.wav filter=lfs diff=lfs merge=lfs -text
218
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_080.wav filter=lfs diff=lfs merge=lfs -text
219
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_079.wav filter=lfs diff=lfs merge=lfs -text
220
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_091.wav filter=lfs diff=lfs merge=lfs -text
221
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_095.wav filter=lfs diff=lfs merge=lfs -text
222
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_092.wav filter=lfs diff=lfs merge=lfs -text
223
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_096.wav filter=lfs diff=lfs merge=lfs -text
224
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_098.wav filter=lfs diff=lfs merge=lfs -text
225
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_097.wav filter=lfs diff=lfs merge=lfs -text
226
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_094.wav filter=lfs diff=lfs merge=lfs -text
227
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_093.wav filter=lfs diff=lfs merge=lfs -text
228
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_099.wav filter=lfs diff=lfs merge=lfs -text
229
+ Data/Tsukuyomi/wavs/VOICEACTRESS100_100.wav filter=lfs diff=lfs merge=lfs -text
230
+ .venv/Lib/site-packages/torch/lib/cublasLt64_12.dll filter=lfs diff=lfs merge=lfs -text
231
+ .venv/Lib/site-packages/unidic/dicdir/sys.dic filter=lfs diff=lfs merge=lfs -text
232
+ .venv/Lib/site-packages/torch/lib/cudnn_engines_precompiled64_9.dll filter=lfs diff=lfs merge=lfs -text
233
+ .venv/Lib/site-packages/torch/lib/dnnl.lib filter=lfs diff=lfs merge=lfs -text
234
+ .venv/Lib/site-packages/torch/lib/torch_cuda.dll filter=lfs diff=lfs merge=lfs -text
.venv/Lib/site-packages/scipy/sparse/tests/data/csc_py2.npz ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:bac27f1a3eb1fdd102dae39b7dd61ce83e82f096388e344e14285071984d01fa
3
+ size 846
.venv/Lib/site-packages/scipy/sparse/tests/data/csc_py3.npz ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6b1b84315c7077417e720512d086a5a6217c2875b818d27704ae9b7237c69dfe
3
+ size 851
.venv/Lib/site-packages/scipy/special/_ufuncs_cxx.pxd ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from . cimport sf_error
2
+ cdef void _set_action(sf_error.sf_error_t, sf_error.sf_action_t) noexcept nogil
3
+ cdef void *_export_ccospi
4
+ cdef void *_export_lambertw_scalar
5
+ cdef void *_export_csinpi
6
+ cdef void *_export__stirling2_inexact
7
+ cdef void *_export_ibeta_float
8
+ cdef void *_export_ibeta_double
9
+ cdef void *_export_ibetac_float
10
+ cdef void *_export_ibetac_double
11
+ cdef void *_export_ibetac_inv_float
12
+ cdef void *_export_ibetac_inv_double
13
+ cdef void *_export_ibeta_inv_float
14
+ cdef void *_export_ibeta_inv_double
15
+ cdef void *_export_binom
16
+ cdef void *_export_faddeeva_dawsn
17
+ cdef void *_export_faddeeva_dawsn_complex
18
+ cdef void *_export_fellint_RC
19
+ cdef void *_export_cellint_RC
20
+ cdef void *_export_fellint_RD
21
+ cdef void *_export_cellint_RD
22
+ cdef void *_export_fellint_RF
23
+ cdef void *_export_cellint_RF
24
+ cdef void *_export_fellint_RG
25
+ cdef void *_export_cellint_RG
26
+ cdef void *_export_fellint_RJ
27
+ cdef void *_export_cellint_RJ
28
+ cdef void *_export_faddeeva_erf
29
+ cdef void *_export_faddeeva_erfc_complex
30
+ cdef void *_export_faddeeva_erfcx
31
+ cdef void *_export_faddeeva_erfcx_complex
32
+ cdef void *_export_faddeeva_erfi
33
+ cdef void *_export_faddeeva_erfi_complex
34
+ cdef void *_export_erfinv_float
35
+ cdef void *_export_erfinv_double
36
+ cdef void *_export_expit
37
+ cdef void *_export_expitf
38
+ cdef void *_export_expitl
39
+ cdef void *_export_cgamma
40
+ cdef void *_export_hyp1f1_double
41
+ cdef void *_export_log_expit
42
+ cdef void *_export_log_expitf
43
+ cdef void *_export_log_expitl
44
+ cdef void *_export_faddeeva_log_ndtr
45
+ cdef void *_export_faddeeva_log_ndtr_complex
46
+ cdef void *_export_loggamma_real
47
+ cdef void *_export_loggamma
48
+ cdef void *_export_logit
49
+ cdef void *_export_logitf
50
+ cdef void *_export_logitl
51
+ cdef void *_export_faddeeva_ndtr
52
+ cdef void *_export_powm1_float
53
+ cdef void *_export_powm1_double
54
+ cdef void *_export_cdigamma
55
+ cdef void *_export_digamma
56
+ cdef void *_export_crgamma
57
+ cdef void *_export_faddeeva_voigt_profile
58
+ cdef void *_export_faddeeva_w
59
+ cdef void *_export_wrightomega
60
+ cdef void *_export_wrightomega_real
.venv/Lib/site-packages/scipy/special/special/cephes/const.h ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Translated into C++ by SciPy developers in 2024.
2
+ * Original header with Copyright information appears below.
3
+ *
4
+ * Since we support only IEEE-754 floating point numbers, conditional logic
5
+ * supporting other arithmetic types has been removed.
6
+ */
7
+
8
+ /*
9
+ *
10
+ *
11
+ * const.c
12
+ *
13
+ * Globally declared constants
14
+ *
15
+ *
16
+ *
17
+ * SYNOPSIS:
18
+ *
19
+ * extern double nameofconstant;
20
+ *
21
+ *
22
+ *
23
+ *
24
+ * DESCRIPTION:
25
+ *
26
+ * This file contains a number of mathematical constants and
27
+ * also some needed size parameters of the computer arithmetic.
28
+ * The values are supplied as arrays of hexadecimal integers
29
+ * for IEEE arithmetic, and in a normal decimal scientific notation for
30
+ * other machines. The particular notation used is determined
31
+ * by a symbol (IBMPC, or UNK) defined in the include file
32
+ * mconf.h.
33
+ *
34
+ * The default size parameters are as follows.
35
+ *
36
+ * For UNK mode:
37
+ * MACHEP = 1.38777878078144567553E-17 2**-56
38
+ * MAXLOG = 8.8029691931113054295988E1 log(2**127)
39
+ * MINLOG = -8.872283911167299960540E1 log(2**-128)
40
+ *
41
+ * For IEEE arithmetic (IBMPC):
42
+ * MACHEP = 1.11022302462515654042E-16 2**-53
43
+ * MAXLOG = 7.09782712893383996843E2 log(2**1024)
44
+ * MINLOG = -7.08396418532264106224E2 log(2**-1022)
45
+ *
46
+ * The global symbols for mathematical constants are
47
+ * SQ2OPI = 7.9788456080286535587989E-1 sqrt( 2/pi )
48
+ * LOGSQ2 = 3.46573590279972654709E-1 log(2)/2
49
+ * THPIO4 = 2.35619449019234492885 3*pi/4
50
+ *
51
+ * These lists are subject to change.
52
+ */
53
+ /* const.c */
54
+
55
+ /*
56
+ * Cephes Math Library Release 2.3: March, 1995
57
+ * Copyright 1984, 1995 by Stephen L. Moshier
58
+ */
59
+ #pragma once
60
+
61
+ namespace special {
62
+ namespace cephes {
63
+ namespace detail {
64
+ constexpr double MACHEP = 1.11022302462515654042E-16; // 2**-53
65
+ constexpr double MAXLOG = 7.09782712893383996732E2; // log(DBL_MAX)
66
+ constexpr double MINLOG = -7.451332191019412076235E2; // log 2**-1022
67
+ constexpr double SQ2OPI = 7.9788456080286535587989E-1; // sqrt( 2/pi )
68
+ constexpr double LOGSQ2 = 3.46573590279972654709E-1; // log(2)/2
69
+ constexpr double THPIO4 = 2.35619449019234492885; // 3*pi/4
70
+ // Following two added by SciPy developers.
71
+ // Euler's constant
72
+ constexpr double SCIPY_EULER = 0.577215664901532860606512090082402431;
73
+ // e as long double
74
+ constexpr long double SCIPY_El = 2.718281828459045235360287471352662498L;
75
+ } // namespace detail
76
+ } // namespace cephes
77
+ } // namespace special
.venv/Lib/site-packages/scipy/special/special/cephes/gamma.h ADDED
@@ -0,0 +1,343 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Translated into C++ by SciPy developers in 2024.
2
+ * Original header with Copyright information appears below.
3
+ */
4
+
5
+ /*
6
+ * Gamma function
7
+ *
8
+ *
9
+ *
10
+ * SYNOPSIS:
11
+ *
12
+ * double x, y, Gamma();
13
+ *
14
+ * y = Gamma( x );
15
+ *
16
+ *
17
+ *
18
+ * DESCRIPTION:
19
+ *
20
+ * Returns Gamma function of the argument. The result is
21
+ * correctly signed.
22
+ *
23
+ * Arguments |x| <= 34 are reduced by recurrence and the function
24
+ * approximated by a rational function of degree 6/7 in the
25
+ * interval (2,3). Large arguments are handled by Stirling's
26
+ * formula. Large negative arguments are made positive using
27
+ * a reflection formula.
28
+ *
29
+ *
30
+ * ACCURACY:
31
+ *
32
+ * Relative error:
33
+ * arithmetic domain # trials peak rms
34
+ * IEEE -170,-33 20000 2.3e-15 3.3e-16
35
+ * IEEE -33, 33 20000 9.4e-16 2.2e-16
36
+ * IEEE 33, 171.6 20000 2.3e-15 3.2e-16
37
+ *
38
+ * Error for arguments outside the test range will be larger
39
+ * owing to error amplification by the exponential function.
40
+ *
41
+ */
42
+
43
+ /* lgam()
44
+ *
45
+ * Natural logarithm of Gamma function
46
+ *
47
+ *
48
+ *
49
+ * SYNOPSIS:
50
+ *
51
+ * double x, y, lgam();
52
+ *
53
+ * y = lgam( x );
54
+ *
55
+ *
56
+ *
57
+ * DESCRIPTION:
58
+ *
59
+ * Returns the base e (2.718...) logarithm of the absolute
60
+ * value of the Gamma function of the argument.
61
+ *
62
+ * For arguments greater than 13, the logarithm of the Gamma
63
+ * function is approximated by the logarithmic version of
64
+ * Stirling's formula using a polynomial approximation of
65
+ * degree 4. Arguments between -33 and +33 are reduced by
66
+ * recurrence to the interval [2,3] of a rational approximation.
67
+ * The cosecant reflection formula is employed for arguments
68
+ * less than -33.
69
+ *
70
+ * Arguments greater than MAXLGM return INFINITY and an error
71
+ * message. MAXLGM = 2.556348e305 for IEEE arithmetic.
72
+ *
73
+ *
74
+ *
75
+ * ACCURACY:
76
+ *
77
+ *
78
+ * arithmetic domain # trials peak rms
79
+ * IEEE 0, 3 28000 5.4e-16 1.1e-16
80
+ * IEEE 2.718, 2.556e305 40000 3.5e-16 8.3e-17
81
+ * The error criterion was relative when the function magnitude
82
+ * was greater than one but absolute when it was less than one.
83
+ *
84
+ * The following test used the relative error criterion, though
85
+ * at certain points the relative error could be much higher than
86
+ * indicated.
87
+ * IEEE -200, -4 10000 4.8e-16 1.3e-16
88
+ *
89
+ */
90
+
91
+ /*
92
+ * Cephes Math Library Release 2.2: July, 1992
93
+ * Copyright 1984, 1987, 1989, 1992 by Stephen L. Moshier
94
+ * Direct inquiries to 30 Frost Street, Cambridge, MA 02140
95
+ */
96
+ #pragma once
97
+
98
+ #include "../config.h"
99
+ #include "../error.h"
100
+ #include "polevl.h"
101
+
102
+ namespace special {
103
+ namespace cephes {
104
+ namespace detail {
105
+ constexpr double gamma_P[] = {1.60119522476751861407E-4, 1.19135147006586384913E-3, 1.04213797561761569935E-2,
106
+ 4.76367800457137231464E-2, 2.07448227648435975150E-1, 4.94214826801497100753E-1,
107
+ 9.99999999999999996796E-1};
108
+
109
+ constexpr double gamma_Q[] = {-2.31581873324120129819E-5, 5.39605580493303397842E-4, -4.45641913851797240494E-3,
110
+ 1.18139785222060435552E-2, 3.58236398605498653373E-2, -2.34591795718243348568E-1,
111
+ 7.14304917030273074085E-2, 1.00000000000000000320E0};
112
+
113
+ constexpr double MAXGAM = 171.624376956302725;
114
+ constexpr double LOGPI = 1.14472988584940017414;
115
+
116
+ /* Stirling's formula for the Gamma function */
117
+ constexpr double gamma_STIR[5] = {
118
+ 7.87311395793093628397E-4, -2.29549961613378126380E-4, -2.68132617805781232825E-3,
119
+ 3.47222221605458667310E-3, 8.33333333333482257126E-2,
120
+ };
121
+
122
+ constexpr double MAXSTIR = 143.01608;
123
+ constexpr double SQTPI = 2.50662827463100050242E0;
124
+
125
+ /* Gamma function computed by Stirling's formula.
126
+ * The polynomial STIR is valid for 33 <= x <= 172.
127
+ */
128
+ SPECFUN_HOST_DEVICE inline double stirf(double x) {
129
+ double y, w, v;
130
+
131
+ if (x >= MAXGAM) {
132
+ return (std::numeric_limits<double>::infinity());
133
+ }
134
+ w = 1.0 / x;
135
+ w = 1.0 + w * special::cephes::polevl(w, gamma_STIR, 4);
136
+ y = std::exp(x);
137
+ if (x > MAXSTIR) { /* Avoid overflow in pow() */
138
+ v = std::pow(x, 0.5 * x - 0.25);
139
+ y = v * (v / y);
140
+ } else {
141
+ y = std::pow(x, x - 0.5) / y;
142
+ }
143
+ y = SQTPI * y * w;
144
+ return (y);
145
+ }
146
+ } // namespace detail
147
+
148
+ SPECFUN_HOST_DEVICE inline double Gamma(double x) {
149
+ double p, q, z;
150
+ int i;
151
+ int sgngam = 1;
152
+
153
+ if (!std::isfinite(x)) {
154
+ return x;
155
+ }
156
+ q = std::abs(x);
157
+
158
+ if (q > 33.0) {
159
+ if (x < 0.0) {
160
+ p = floor(q);
161
+ if (p == q) {
162
+ gamnan:
163
+ set_error("Gamma", SF_ERROR_OVERFLOW, NULL);
164
+ return (std::numeric_limits<double>::infinity());
165
+ }
166
+ i = p;
167
+ if ((i & 1) == 0) {
168
+ sgngam = -1;
169
+ }
170
+ z = q - p;
171
+ if (z > 0.5) {
172
+ p += 1.0;
173
+ z = q - p;
174
+ }
175
+ z = q * std::sin(M_PI * z);
176
+ if (z == 0.0) {
177
+ return (sgngam * std::numeric_limits<double>::infinity());
178
+ }
179
+ z = std::abs(z);
180
+ z = M_PI / (z * detail::stirf(q));
181
+ } else {
182
+ z = detail::stirf(x);
183
+ }
184
+ return (sgngam * z);
185
+ }
186
+
187
+ z = 1.0;
188
+ while (x >= 3.0) {
189
+ x -= 1.0;
190
+ z *= x;
191
+ }
192
+
193
+ while (x < 0.0) {
194
+ if (x > -1.E-9) {
195
+ goto small;
196
+ }
197
+ z /= x;
198
+ x += 1.0;
199
+ }
200
+
201
+ while (x < 2.0) {
202
+ if (x < 1.e-9) {
203
+ goto small;
204
+ }
205
+ z /= x;
206
+ x += 1.0;
207
+ }
208
+
209
+ if (x == 2.0) {
210
+ return (z);
211
+ }
212
+
213
+ x -= 2.0;
214
+ p = polevl(x, detail::gamma_P, 6);
215
+ q = polevl(x, detail::gamma_Q, 7);
216
+ return (z * p / q);
217
+
218
+ small:
219
+ if (x == 0.0) {
220
+ goto gamnan;
221
+ } else
222
+ return (z / ((1.0 + 0.5772156649015329 * x) * x));
223
+ }
224
+
225
+ namespace detail {
226
+ /* A[]: Stirling's formula expansion of log Gamma
227
+ * B[], C[]: log Gamma function between 2 and 3
228
+ */
229
+ constexpr double gamma_A[] = {8.11614167470508450300E-4, -5.95061904284301438324E-4, 7.93650340457716943945E-4,
230
+ -2.77777777730099687205E-3, 8.33333333333331927722E-2};
231
+
232
+ constexpr double gamma_B[] = {-1.37825152569120859100E3, -3.88016315134637840924E4, -3.31612992738871184744E5,
233
+ -1.16237097492762307383E6, -1.72173700820839662146E6, -8.53555664245765465627E5};
234
+
235
+ constexpr double gamma_C[] = {
236
+ /* 1.00000000000000000000E0, */
237
+ -3.51815701436523470549E2, -1.70642106651881159223E4, -2.20528590553854454839E5,
238
+ -1.13933444367982507207E6, -2.53252307177582951285E6, -2.01889141433532773231E6};
239
+
240
+ /* log( sqrt( 2*pi ) ) */
241
+ constexpr double LS2PI = 0.91893853320467274178;
242
+
243
+ constexpr double MAXLGM = 2.556348e305;
244
+
245
+ SPECFUN_HOST_DEVICE double lgam_sgn(double x, int *sign) {
246
+ double p, q, u, w, z;
247
+ int i;
248
+
249
+ *sign = 1;
250
+
251
+ if (!std::isfinite(x)) {
252
+ return x;
253
+ }
254
+
255
+ if (x < -34.0) {
256
+ q = -x;
257
+ w = lgam_sgn(q, sign);
258
+ p = floor(q);
259
+ if (p == q) {
260
+ lgsing:
261
+ set_error("lgam", SF_ERROR_SINGULAR, NULL);
262
+ return (std::numeric_limits<double>::infinity());
263
+ }
264
+ i = p;
265
+ if ((i & 1) == 0) {
266
+ *sign = -1;
267
+ } else {
268
+ *sign = 1;
269
+ }
270
+ z = q - p;
271
+ if (z > 0.5) {
272
+ p += 1.0;
273
+ z = p - q;
274
+ }
275
+ z = q * std::sin(M_PI * z);
276
+ if (z == 0.0) {
277
+ goto lgsing;
278
+ }
279
+ /* z = log(M_PI) - log( z ) - w; */
280
+ z = LOGPI - std::log(z) - w;
281
+ return (z);
282
+ }
283
+
284
+ if (x < 13.0) {
285
+ z = 1.0;
286
+ p = 0.0;
287
+ u = x;
288
+ while (u >= 3.0) {
289
+ p -= 1.0;
290
+ u = x + p;
291
+ z *= u;
292
+ }
293
+ while (u < 2.0) {
294
+ if (u == 0.0) {
295
+ goto lgsing;
296
+ }
297
+ z /= u;
298
+ p += 1.0;
299
+ u = x + p;
300
+ }
301
+ if (z < 0.0) {
302
+ *sign = -1;
303
+ z = -z;
304
+ } else {
305
+ *sign = 1;
306
+ }
307
+ if (u == 2.0) {
308
+ return (std::log(z));
309
+ }
310
+ p -= 2.0;
311
+ x = x + p;
312
+ p = x * polevl(x, gamma_B, 5) / p1evl(x, gamma_C, 6);
313
+ return (std::log(z) + p);
314
+ }
315
+
316
+ if (x > MAXLGM) {
317
+ return (*sign * std::numeric_limits<double>::infinity());
318
+ }
319
+
320
+ q = (x - 0.5) * std::log(x) - x + LS2PI;
321
+ if (x > 1.0e8) {
322
+ return (q);
323
+ }
324
+
325
+ p = 1.0 / (x * x);
326
+ if (x >= 1000.0) {
327
+ q += ((7.9365079365079365079365e-4 * p - 2.7777777777777777777778e-3) * p + 0.0833333333333333333333) /
328
+ x;
329
+ } else {
330
+ q += polevl(p, gamma_A, 4) / x;
331
+ }
332
+ return (q);
333
+ }
334
+ } // namespace detail
335
+
336
+ /* Logarithm of Gamma function */
337
+ SPECFUN_HOST_DEVICE double lgam(double x) {
338
+ int sign;
339
+ return detail::lgam_sgn(x, &sign);
340
+ }
341
+
342
+ } // namespace cephes
343
+ } // namespace special
.venv/Lib/site-packages/scipy/special/special/cephes/polevl.h ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Translated into C++ by SciPy developers in 2024.
2
+ * Original header with Copyright information appears below.
3
+ */
4
+
5
+ /* polevl.c
6
+ * p1evl.c
7
+ *
8
+ * Evaluate polynomial
9
+ *
10
+ *
11
+ *
12
+ * SYNOPSIS:
13
+ *
14
+ * int N;
15
+ * double x, y, coef[N+1], polevl[];
16
+ *
17
+ * y = polevl( x, coef, N );
18
+ *
19
+ *
20
+ *
21
+ * DESCRIPTION:
22
+ *
23
+ * Evaluates polynomial of degree N:
24
+ *
25
+ * 2 N
26
+ * y = C + C x + C x +...+ C x
27
+ * 0 1 2 N
28
+ *
29
+ * Coefficients are stored in reverse order:
30
+ *
31
+ * coef[0] = C , ..., coef[N] = C .
32
+ * N 0
33
+ *
34
+ * The function p1evl() assumes that c_N = 1.0 so that coefficent
35
+ * is omitted from the array. Its calling arguments are
36
+ * otherwise the same as polevl().
37
+ *
38
+ *
39
+ * SPEED:
40
+ *
41
+ * In the interest of speed, there are no checks for out
42
+ * of bounds arithmetic. This routine is used by most of
43
+ * the functions in the library. Depending on available
44
+ * equipment features, the user may wish to rewrite the
45
+ * program in microcode or assembly language.
46
+ *
47
+ */
48
+
49
+ /*
50
+ * Cephes Math Library Release 2.1: December, 1988
51
+ * Copyright 1984, 1987, 1988 by Stephen L. Moshier
52
+ * Direct inquiries to 30 Frost Street, Cambridge, MA 02140
53
+ */
54
+
55
+ /* Sources:
56
+ * [1] Holin et. al., "Polynomial and Rational Function Evaluation",
57
+ * https://www.boost.org/doc/libs/1_61_0/libs/math/doc/html/math_toolkit/roots/rational.html
58
+ */
59
+
60
+ /* Scipy changes:
61
+ * - 06-23-2016: add code for evaluating rational functions
62
+ */
63
+ #pragma once
64
+
65
+ #include "../config.h"
66
+
67
+ namespace special {
68
+ namespace cephes {
69
+ SPECFUN_HOST_DEVICE inline double polevl(double x, const double coef[], int N) {
70
+ double ans;
71
+ int i;
72
+ const double *p;
73
+
74
+ p = coef;
75
+ ans = *p++;
76
+ i = N;
77
+
78
+ do {
79
+ ans = ans * x + *p++;
80
+ } while (--i);
81
+
82
+ return (ans);
83
+ }
84
+
85
+ /* p1evl() */
86
+ /* N
87
+ * Evaluate polynomial when coefficient of x is 1.0.
88
+ * That is, C_{N} is assumed to be 1, and that coefficient
89
+ * is not included in the input array coef.
90
+ * coef must have length N and contain the polynomial coefficients
91
+ * stored as
92
+ * coef[0] = C_{N-1}
93
+ * coef[1] = C_{N-2}
94
+ * ...
95
+ * coef[N-2] = C_1
96
+ * coef[N-1] = C_0
97
+ * Otherwise same as polevl.
98
+ */
99
+
100
+ SPECFUN_HOST_DEVICE inline double p1evl(double x, const double coef[], int N) {
101
+ double ans;
102
+ const double *p;
103
+ int i;
104
+
105
+ p = coef;
106
+ ans = x + *p++;
107
+ i = N - 1;
108
+
109
+ do
110
+ ans = ans * x + *p++;
111
+ while (--i);
112
+
113
+ return (ans);
114
+ }
115
+
116
+ /* Evaluate a rational function. See [1]. */
117
+
118
+ SPECFUN_HOST_DEVICE inline double ratevl(double x, const double num[], int M, const double denom[], int N) {
119
+ int i, dir;
120
+ double y, num_ans, denom_ans;
121
+ double absx = std::abs(x);
122
+ const double *p;
123
+
124
+ if (absx > 1) {
125
+ /* Evaluate as a polynomial in 1/x. */
126
+ dir = -1;
127
+ p = num + M;
128
+ y = 1 / x;
129
+ } else {
130
+ dir = 1;
131
+ p = num;
132
+ y = x;
133
+ }
134
+
135
+ /* Evaluate the numerator */
136
+ num_ans = *p;
137
+ p += dir;
138
+ for (i = 1; i <= M; i++) {
139
+ num_ans = num_ans * y + *p;
140
+ p += dir;
141
+ }
142
+
143
+ /* Evaluate the denominator */
144
+ if (absx > 1) {
145
+ p = denom + N;
146
+ } else {
147
+ p = denom;
148
+ }
149
+
150
+ denom_ans = *p;
151
+ p += dir;
152
+ for (i = 1; i <= N; i++) {
153
+ denom_ans = denom_ans * y + *p;
154
+ p += dir;
155
+ }
156
+
157
+ if (absx > 1) {
158
+ i = N - M;
159
+ return std::pow(x, i) * num_ans / denom_ans;
160
+ } else {
161
+ return num_ans / denom_ans;
162
+ }
163
+ }
164
+ } // namespace cephes
165
+ } // namespace special
.venv/Lib/site-packages/scipy/special/special/cephes/psi.h ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Translated into C++ by SciPy developers in 2024.
2
+ * Original header with Copyright information appears below.
3
+ */
4
+
5
+ /* psi.c
6
+ *
7
+ * Psi (digamma) function
8
+ *
9
+ *
10
+ * SYNOPSIS:
11
+ *
12
+ * double x, y, psi();
13
+ *
14
+ * y = psi( x );
15
+ *
16
+ *
17
+ * DESCRIPTION:
18
+ *
19
+ * d -
20
+ * psi(x) = -- ln | (x)
21
+ * dx
22
+ *
23
+ * is the logarithmic derivative of the gamma function.
24
+ * For integer x,
25
+ * n-1
26
+ * -
27
+ * psi(n) = -EUL + > 1/k.
28
+ * -
29
+ * k=1
30
+ *
31
+ * This formula is used for 0 < n <= 10. If x is negative, it
32
+ * is transformed to a positive argument by the reflection
33
+ * formula psi(1-x) = psi(x) + pi cot(pi x).
34
+ * For general positive x, the argument is made greater than 10
35
+ * using the recurrence psi(x+1) = psi(x) + 1/x.
36
+ * Then the following asymptotic expansion is applied:
37
+ *
38
+ * inf. B
39
+ * - 2k
40
+ * psi(x) = log(x) - 1/2x - > -------
41
+ * - 2k
42
+ * k=1 2k x
43
+ *
44
+ * where the B2k are Bernoulli numbers.
45
+ *
46
+ * ACCURACY:
47
+ * Relative error (except absolute when |psi| < 1):
48
+ * arithmetic domain # trials peak rms
49
+ * IEEE 0,30 30000 1.3e-15 1.4e-16
50
+ * IEEE -30,0 40000 1.5e-15 2.2e-16
51
+ *
52
+ * ERROR MESSAGES:
53
+ * message condition value returned
54
+ * psi singularity x integer <=0 INFINITY
55
+ */
56
+
57
+ /*
58
+ * Cephes Math Library Release 2.8: June, 2000
59
+ * Copyright 1984, 1987, 1992, 2000 by Stephen L. Moshier
60
+ */
61
+
62
+ /*
63
+ * Code for the rational approximation on [1, 2] is:
64
+ *
65
+ * (C) Copyright John Maddock 2006.
66
+ * Use, modification and distribution are subject to the
67
+ * Boost Software License, Version 1.0. (See accompanying file
68
+ * LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
69
+ */
70
+ #pragma once
71
+
72
+ #include "../config.h"
73
+ #include "../error.h"
74
+ #include "const.h"
75
+ #include "polevl.h"
76
+
77
+ namespace special {
78
+ namespace cephes {
79
+ namespace detail {
80
+ constexpr double psi_A[] = {8.33333333333333333333E-2, -2.10927960927960927961E-2, 7.57575757575757575758E-3,
81
+ -4.16666666666666666667E-3, 3.96825396825396825397E-3, -8.33333333333333333333E-3,
82
+ 8.33333333333333333333E-2};
83
+
84
+ constexpr float psi_Y = 0.99558162689208984f;
85
+
86
+ constexpr double psi_root1 = 1569415565.0 / 1073741824.0;
87
+ constexpr double psi_root2 = (381566830.0 / 1073741824.0) / 1073741824.0;
88
+ constexpr double psi_root3 = 0.9016312093258695918615325266959189453125e-19;
89
+
90
+ constexpr double psi_P[] = {-0.0020713321167745952, -0.045251321448739056, -0.28919126444774784,
91
+ -0.65031853770896507, -0.32555031186804491, 0.25479851061131551};
92
+ constexpr double psi_Q[] = {-0.55789841321675513e-6,
93
+ 0.0021284987017821144,
94
+ 0.054151797245674225,
95
+ 0.43593529692665969,
96
+ 1.4606242909763515,
97
+ 2.0767117023730469,
98
+ 1.0};
99
+
100
+ SPECFUN_HOST_DEVICE double digamma_imp_1_2(double x) {
101
+ /*
102
+ * Rational approximation on [1, 2] taken from Boost.
103
+ *
104
+ * Now for the approximation, we use the form:
105
+ *
106
+ * digamma(x) = (x - root) * (Y + R(x-1))
107
+ *
108
+ * Where root is the location of the positive root of digamma,
109
+ * Y is a constant, and R is optimised for low absolute error
110
+ * compared to Y.
111
+ *
112
+ * Maximum Deviation Found: 1.466e-18
113
+ * At double precision, max error found: 2.452e-17
114
+ */
115
+ double r, g;
116
+
117
+ g = x - psi_root1;
118
+ g -= psi_root2;
119
+ g -= psi_root3;
120
+ r = special::cephes::polevl(x - 1.0, psi_P, 5) / special::cephes::polevl(x - 1.0, psi_Q, 6);
121
+
122
+ return g * psi_Y + g * r;
123
+ }
124
+
125
+ SPECFUN_HOST_DEVICE double psi_asy(double x) {
126
+ double y, z;
127
+
128
+ if (x < 1.0e17) {
129
+ z = 1.0 / (x * x);
130
+ y = z * special::cephes::polevl(z, psi_A, 6);
131
+ } else {
132
+ y = 0.0;
133
+ }
134
+
135
+ return std::log(x) - (0.5 / x) - y;
136
+ }
137
+ } // namespace detail
138
+
139
+ SPECFUN_HOST_DEVICE double psi(double x) {
140
+ double y = 0.0;
141
+ double q, r;
142
+ int i, n;
143
+
144
+ if (std::isnan(x)) {
145
+ return x;
146
+ } else if (x == std::numeric_limits<double>::infinity()) {
147
+ return x;
148
+ } else if (x == -std::numeric_limits<double>::infinity()) {
149
+ return std::numeric_limits<double>::quiet_NaN();
150
+ } else if (x == 0) {
151
+ set_error("psi", SF_ERROR_SINGULAR, NULL);
152
+ return std::copysign(std::numeric_limits<double>::infinity(), -x);
153
+ } else if (x < 0.0) {
154
+ /* argument reduction before evaluating tan(pi * x) */
155
+ r = std::modf(x, &q);
156
+ if (r == 0.0) {
157
+ set_error("psi", SF_ERROR_SINGULAR, NULL);
158
+ return std::numeric_limits<double>::quiet_NaN();
159
+ }
160
+ y = -M_PI / std::tan(M_PI * r);
161
+ x = 1.0 - x;
162
+ }
163
+
164
+ /* check for positive integer up to 10 */
165
+ if ((x <= 10.0) && (x == std::floor(x))) {
166
+ n = static_cast<int>(x);
167
+ for (i = 1; i < n; i++) {
168
+ y += 1.0 / i;
169
+ }
170
+ y -= detail::SCIPY_EULER;
171
+ return y;
172
+ }
173
+
174
+ /* use the recurrence relation to move x into [1, 2] */
175
+ if (x < 1.0) {
176
+ y -= 1.0 / x;
177
+ x += 1.0;
178
+ } else if (x < 10.0) {
179
+ while (x > 2.0) {
180
+ x -= 1.0;
181
+ y += 1.0 / x;
182
+ }
183
+ }
184
+ if ((1.0 <= x) && (x <= 2.0)) {
185
+ y += detail::digamma_imp_1_2(x);
186
+ return y;
187
+ }
188
+
189
+ /* x is large, use the asymptotic series */
190
+ y += detail::psi_asy(x);
191
+ return y;
192
+ }
193
+ } // namespace cephes
194
+ } // namespace special
.venv/Lib/site-packages/scipy/special/tests/test_dd.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Tests for a few of the "double-double" C functions defined in cephes/dd_*.
2
+
3
+ import pytest
4
+ from numpy.testing import assert_allclose
5
+ from scipy.special._test_internal import _dd_exp, _dd_log, _dd_expm1
6
+
7
+
8
+ # Each tuple in test_data contains:
9
+ # (dd_func, xhi, xlo, expected_yhi, expected_ylo)
10
+ # The expected values were computed with mpmath, e.g.
11
+ #
12
+ # import mpmath
13
+ # mpmath.mp.dps = 100
14
+ # xhi = 10.0
15
+ # xlo = 0.0
16
+ # x = mpmath.mpf(xhi) + mpmath.mpf(xlo)
17
+ # y = mpmath.log(x)
18
+ # expected_yhi = float(y)
19
+ # expected_ylo = float(y - expected_yhi)
20
+ #
21
+ test_data = [
22
+ (_dd_exp, -0.3333333333333333, -1.850371707708594e-17,
23
+ 0.7165313105737893, -2.0286948382455594e-17),
24
+ (_dd_exp, 0.0, 0.0, 1.0, 0.0),
25
+ (_dd_exp, 10.0, 0.0, 22026.465794806718, -1.3780134700517372e-12),
26
+ (_dd_log, 0.03125, 0.0, -3.4657359027997265, -4.930038229799327e-18),
27
+ (_dd_log, 10.0, 0.0, 2.302585092994046, -2.1707562233822494e-16),
28
+ (_dd_expm1, -1.25, 0.0, -0.7134952031398099, -4.7031321153650186e-17),
29
+ (_dd_expm1, -0.484375, 0.0, -0.3839178722093218, 7.609376052156984e-18),
30
+ (_dd_expm1, -0.25, 0.0, -0.22119921692859512, -1.0231869534531498e-17),
31
+ (_dd_expm1, -0.0625, 0.0, -0.06058693718652421, -7.077887227488846e-19),
32
+ (_dd_expm1, 0.0, 0.0, 0.0, 0.0),
33
+ (_dd_expm1, 0.0625, 3.5e-18, 0.06449445891785943, 1.4323095758164254e-18),
34
+ (_dd_expm1, 0.25, 0.0, 0.2840254166877415, -2.133257464457841e-17),
35
+ (_dd_expm1, 0.498046875, 0.0, 0.645504254608231, -9.198435524984236e-18),
36
+ (_dd_expm1, 1.25, 0.0, 2.4903429574618414, -4.604261945372796e-17)
37
+ ]
38
+
39
+
40
+ @pytest.mark.parametrize('dd_func, xhi, xlo, expected_yhi, expected_ylo',
41
+ test_data)
42
+ def test_dd(dd_func, xhi, xlo, expected_yhi, expected_ylo):
43
+ yhi, ylo = dd_func(xhi, xlo)
44
+ assert yhi == expected_yhi, (f"high double ({yhi}) does not equal the "
45
+ f"expected value {expected_yhi}")
46
+ assert_allclose(ylo, expected_ylo, rtol=5e-15)
.venv/Lib/site-packages/scipy/special/tests/test_digamma.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from numpy import pi, log, sqrt
3
+ from numpy.testing import assert_, assert_equal
4
+
5
+ from scipy.special._testutils import FuncData
6
+ import scipy.special as sc
7
+
8
+ # Euler-Mascheroni constant
9
+ euler = 0.57721566490153286
10
+
11
+
12
+ def test_consistency():
13
+ # Make sure the implementation of digamma for real arguments
14
+ # agrees with the implementation of digamma for complex arguments.
15
+
16
+ # It's all poles after -1e16
17
+ x = np.r_[-np.logspace(15, -30, 200), np.logspace(-30, 300, 200)]
18
+ dataset = np.vstack((x + 0j, sc.digamma(x))).T
19
+ FuncData(sc.digamma, dataset, 0, 1, rtol=5e-14, nan_ok=True).check()
20
+
21
+
22
+ def test_special_values():
23
+ # Test special values from Gauss's digamma theorem. See
24
+ #
25
+ # https://en.wikipedia.org/wiki/Digamma_function
26
+
27
+ dataset = [
28
+ (1, -euler),
29
+ (0.5, -2*log(2) - euler),
30
+ (1/3, -pi/(2*sqrt(3)) - 3*log(3)/2 - euler),
31
+ (1/4, -pi/2 - 3*log(2) - euler),
32
+ (1/6, -pi*sqrt(3)/2 - 2*log(2) - 3*log(3)/2 - euler),
33
+ (1/8,
34
+ -pi/2 - 4*log(2) - (pi + log(2 + sqrt(2)) - log(2 - sqrt(2)))/sqrt(2) - euler)
35
+ ]
36
+
37
+ dataset = np.asarray(dataset)
38
+ FuncData(sc.digamma, dataset, 0, 1, rtol=1e-14).check()
39
+
40
+
41
+ def test_nonfinite():
42
+ pts = [0.0, -0.0, np.inf]
43
+ std = [-np.inf, np.inf, np.inf]
44
+ assert_equal(sc.digamma(pts), std)
45
+ assert_(all(np.isnan(sc.digamma([-np.inf, -1]))))
.venv/Lib/site-packages/scipy/special/tests/test_ellip_harm.py ADDED
@@ -0,0 +1,278 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Tests for the Ellipsoidal Harmonic Function,
3
+ # Distributed under the same license as SciPy itself.
4
+ #
5
+
6
+ import numpy as np
7
+ from numpy.testing import (assert_equal, assert_almost_equal, assert_allclose,
8
+ assert_, suppress_warnings)
9
+ from scipy.special._testutils import assert_func_equal
10
+ from scipy.special import ellip_harm, ellip_harm_2, ellip_normal
11
+ from scipy.integrate import IntegrationWarning
12
+ from numpy import sqrt, pi
13
+
14
+
15
+ def test_ellip_potential():
16
+ def change_coefficient(lambda1, mu, nu, h2, k2):
17
+ x = sqrt(lambda1**2*mu**2*nu**2/(h2*k2))
18
+ y = sqrt((lambda1**2 - h2)*(mu**2 - h2)*(h2 - nu**2)/(h2*(k2 - h2)))
19
+ z = sqrt((lambda1**2 - k2)*(k2 - mu**2)*(k2 - nu**2)/(k2*(k2 - h2)))
20
+ return x, y, z
21
+
22
+ def solid_int_ellip(lambda1, mu, nu, n, p, h2, k2):
23
+ return (ellip_harm(h2, k2, n, p, lambda1)*ellip_harm(h2, k2, n, p, mu)
24
+ * ellip_harm(h2, k2, n, p, nu))
25
+
26
+ def solid_int_ellip2(lambda1, mu, nu, n, p, h2, k2):
27
+ return (ellip_harm_2(h2, k2, n, p, lambda1)
28
+ * ellip_harm(h2, k2, n, p, mu)*ellip_harm(h2, k2, n, p, nu))
29
+
30
+ def summation(lambda1, mu1, nu1, lambda2, mu2, nu2, h2, k2):
31
+ tol = 1e-8
32
+ sum1 = 0
33
+ for n in range(20):
34
+ xsum = 0
35
+ for p in range(1, 2*n+2):
36
+ xsum += (4*pi*(solid_int_ellip(lambda2, mu2, nu2, n, p, h2, k2)
37
+ * solid_int_ellip2(lambda1, mu1, nu1, n, p, h2, k2)) /
38
+ (ellip_normal(h2, k2, n, p)*(2*n + 1)))
39
+ if abs(xsum) < 0.1*tol*abs(sum1):
40
+ break
41
+ sum1 += xsum
42
+ return sum1, xsum
43
+
44
+ def potential(lambda1, mu1, nu1, lambda2, mu2, nu2, h2, k2):
45
+ x1, y1, z1 = change_coefficient(lambda1, mu1, nu1, h2, k2)
46
+ x2, y2, z2 = change_coefficient(lambda2, mu2, nu2, h2, k2)
47
+ res = sqrt((x2 - x1)**2 + (y2 - y1)**2 + (z2 - z1)**2)
48
+ return 1/res
49
+
50
+ pts = [
51
+ (120, sqrt(19), 2, 41, sqrt(17), 2, 15, 25),
52
+ (120, sqrt(16), 3.2, 21, sqrt(11), 2.9, 11, 20),
53
+ ]
54
+
55
+ with suppress_warnings() as sup:
56
+ sup.filter(IntegrationWarning, "The occurrence of roundoff error")
57
+ sup.filter(IntegrationWarning, "The maximum number of subdivisions")
58
+
59
+ for p in pts:
60
+ err_msg = repr(p)
61
+ exact = potential(*p)
62
+ result, last_term = summation(*p)
63
+ assert_allclose(exact, result, atol=0, rtol=1e-8, err_msg=err_msg)
64
+ assert_(abs(result - exact) < 10*abs(last_term), err_msg)
65
+
66
+
67
+ def test_ellip_norm():
68
+
69
+ def G01(h2, k2):
70
+ return 4*pi
71
+
72
+ def G11(h2, k2):
73
+ return 4*pi*h2*k2/3
74
+
75
+ def G12(h2, k2):
76
+ return 4*pi*h2*(k2 - h2)/3
77
+
78
+ def G13(h2, k2):
79
+ return 4*pi*k2*(k2 - h2)/3
80
+
81
+ def G22(h2, k2):
82
+ res = (2*(h2**4 + k2**4) - 4*h2*k2*(h2**2 + k2**2) + 6*h2**2*k2**2 +
83
+ sqrt(h2**2 + k2**2 - h2*k2)*(-2*(h2**3 + k2**3) + 3*h2*k2*(h2 + k2)))
84
+ return 16*pi/405*res
85
+
86
+ def G21(h2, k2):
87
+ res = (2*(h2**4 + k2**4) - 4*h2*k2*(h2**2 + k2**2) + 6*h2**2*k2**2
88
+ + sqrt(h2**2 + k2**2 - h2*k2)*(2*(h2**3 + k2**3) - 3*h2*k2*(h2 + k2)))
89
+ return 16*pi/405*res
90
+
91
+ def G23(h2, k2):
92
+ return 4*pi*h2**2*k2*(k2 - h2)/15
93
+
94
+ def G24(h2, k2):
95
+ return 4*pi*h2*k2**2*(k2 - h2)/15
96
+
97
+ def G25(h2, k2):
98
+ return 4*pi*h2*k2*(k2 - h2)**2/15
99
+
100
+ def G32(h2, k2):
101
+ res = (16*(h2**4 + k2**4) - 36*h2*k2*(h2**2 + k2**2) + 46*h2**2*k2**2
102
+ + sqrt(4*(h2**2 + k2**2) - 7*h2*k2)*(-8*(h2**3 + k2**3) +
103
+ 11*h2*k2*(h2 + k2)))
104
+ return 16*pi/13125*k2*h2*res
105
+
106
+ def G31(h2, k2):
107
+ res = (16*(h2**4 + k2**4) - 36*h2*k2*(h2**2 + k2**2) + 46*h2**2*k2**2
108
+ + sqrt(4*(h2**2 + k2**2) - 7*h2*k2)*(8*(h2**3 + k2**3) -
109
+ 11*h2*k2*(h2 + k2)))
110
+ return 16*pi/13125*h2*k2*res
111
+
112
+ def G34(h2, k2):
113
+ res = (6*h2**4 + 16*k2**4 - 12*h2**3*k2 - 28*h2*k2**3 + 34*h2**2*k2**2
114
+ + sqrt(h2**2 + 4*k2**2 - h2*k2)*(-6*h2**3 - 8*k2**3 + 9*h2**2*k2 +
115
+ 13*h2*k2**2))
116
+ return 16*pi/13125*h2*(k2 - h2)*res
117
+
118
+ def G33(h2, k2):
119
+ res = (6*h2**4 + 16*k2**4 - 12*h2**3*k2 - 28*h2*k2**3 + 34*h2**2*k2**2
120
+ + sqrt(h2**2 + 4*k2**2 - h2*k2)*(6*h2**3 + 8*k2**3 - 9*h2**2*k2 -
121
+ 13*h2*k2**2))
122
+ return 16*pi/13125*h2*(k2 - h2)*res
123
+
124
+ def G36(h2, k2):
125
+ res = (16*h2**4 + 6*k2**4 - 28*h2**3*k2 - 12*h2*k2**3 + 34*h2**2*k2**2
126
+ + sqrt(4*h2**2 + k2**2 - h2*k2)*(-8*h2**3 - 6*k2**3 + 13*h2**2*k2 +
127
+ 9*h2*k2**2))
128
+ return 16*pi/13125*k2*(k2 - h2)*res
129
+
130
+ def G35(h2, k2):
131
+ res = (16*h2**4 + 6*k2**4 - 28*h2**3*k2 - 12*h2*k2**3 + 34*h2**2*k2**2
132
+ + sqrt(4*h2**2 + k2**2 - h2*k2)*(8*h2**3 + 6*k2**3 - 13*h2**2*k2 -
133
+ 9*h2*k2**2))
134
+ return 16*pi/13125*k2*(k2 - h2)*res
135
+
136
+ def G37(h2, k2):
137
+ return 4*pi*h2**2*k2**2*(k2 - h2)**2/105
138
+
139
+ known_funcs = {(0, 1): G01, (1, 1): G11, (1, 2): G12, (1, 3): G13,
140
+ (2, 1): G21, (2, 2): G22, (2, 3): G23, (2, 4): G24,
141
+ (2, 5): G25, (3, 1): G31, (3, 2): G32, (3, 3): G33,
142
+ (3, 4): G34, (3, 5): G35, (3, 6): G36, (3, 7): G37}
143
+
144
+ def _ellip_norm(n, p, h2, k2):
145
+ func = known_funcs[n, p]
146
+ return func(h2, k2)
147
+ _ellip_norm = np.vectorize(_ellip_norm)
148
+
149
+ def ellip_normal_known(h2, k2, n, p):
150
+ return _ellip_norm(n, p, h2, k2)
151
+
152
+ # generate both large and small h2 < k2 pairs
153
+ np.random.seed(1234)
154
+ h2 = np.random.pareto(0.5, size=1)
155
+ k2 = h2 * (1 + np.random.pareto(0.5, size=h2.size))
156
+
157
+ points = []
158
+ for n in range(4):
159
+ for p in range(1, 2*n+2):
160
+ points.append((h2, k2, np.full(h2.size, n), np.full(h2.size, p)))
161
+ points = np.array(points)
162
+ with suppress_warnings() as sup:
163
+ sup.filter(IntegrationWarning, "The occurrence of roundoff error")
164
+ assert_func_equal(ellip_normal, ellip_normal_known, points, rtol=1e-12)
165
+
166
+
167
+ def test_ellip_harm_2():
168
+
169
+ def I1(h2, k2, s):
170
+ res = (ellip_harm_2(h2, k2, 1, 1, s)/(3 * ellip_harm(h2, k2, 1, 1, s))
171
+ + ellip_harm_2(h2, k2, 1, 2, s)/(3 * ellip_harm(h2, k2, 1, 2, s)) +
172
+ ellip_harm_2(h2, k2, 1, 3, s)/(3 * ellip_harm(h2, k2, 1, 3, s)))
173
+ return res
174
+
175
+ with suppress_warnings() as sup:
176
+ sup.filter(IntegrationWarning, "The occurrence of roundoff error")
177
+ assert_almost_equal(I1(5, 8, 10), 1/(10*sqrt((100-5)*(100-8))))
178
+
179
+ # Values produced by code from arXiv:1204.0267
180
+ assert_almost_equal(ellip_harm_2(5, 8, 2, 1, 10), 0.00108056853382)
181
+ assert_almost_equal(ellip_harm_2(5, 8, 2, 2, 10), 0.00105820513809)
182
+ assert_almost_equal(ellip_harm_2(5, 8, 2, 3, 10), 0.00106058384743)
183
+ assert_almost_equal(ellip_harm_2(5, 8, 2, 4, 10), 0.00106774492306)
184
+ assert_almost_equal(ellip_harm_2(5, 8, 2, 5, 10), 0.00107976356454)
185
+
186
+
187
+ def test_ellip_harm():
188
+
189
+ def E01(h2, k2, s):
190
+ return 1
191
+
192
+ def E11(h2, k2, s):
193
+ return s
194
+
195
+ def E12(h2, k2, s):
196
+ return sqrt(abs(s*s - h2))
197
+
198
+ def E13(h2, k2, s):
199
+ return sqrt(abs(s*s - k2))
200
+
201
+ def E21(h2, k2, s):
202
+ return s*s - 1/3*((h2 + k2) + sqrt(abs((h2 + k2)*(h2 + k2)-3*h2*k2)))
203
+
204
+ def E22(h2, k2, s):
205
+ return s*s - 1/3*((h2 + k2) - sqrt(abs((h2 + k2)*(h2 + k2)-3*h2*k2)))
206
+
207
+ def E23(h2, k2, s):
208
+ return s * sqrt(abs(s*s - h2))
209
+
210
+ def E24(h2, k2, s):
211
+ return s * sqrt(abs(s*s - k2))
212
+
213
+ def E25(h2, k2, s):
214
+ return sqrt(abs((s*s - h2)*(s*s - k2)))
215
+
216
+ def E31(h2, k2, s):
217
+ return s*s*s - (s/5)*(2*(h2 + k2) + sqrt(4*(h2 + k2)*(h2 + k2) -
218
+ 15*h2*k2))
219
+
220
+ def E32(h2, k2, s):
221
+ return s*s*s - (s/5)*(2*(h2 + k2) - sqrt(4*(h2 + k2)*(h2 + k2) -
222
+ 15*h2*k2))
223
+
224
+ def E33(h2, k2, s):
225
+ return sqrt(abs(s*s - h2))*(s*s - 1/5*((h2 + 2*k2) + sqrt(abs((h2 +
226
+ 2*k2)*(h2 + 2*k2) - 5*h2*k2))))
227
+
228
+ def E34(h2, k2, s):
229
+ return sqrt(abs(s*s - h2))*(s*s - 1/5*((h2 + 2*k2) - sqrt(abs((h2 +
230
+ 2*k2)*(h2 + 2*k2) - 5*h2*k2))))
231
+
232
+ def E35(h2, k2, s):
233
+ return sqrt(abs(s*s - k2))*(s*s - 1/5*((2*h2 + k2) + sqrt(abs((2*h2
234
+ + k2)*(2*h2 + k2) - 5*h2*k2))))
235
+
236
+ def E36(h2, k2, s):
237
+ return sqrt(abs(s*s - k2))*(s*s - 1/5*((2*h2 + k2) - sqrt(abs((2*h2
238
+ + k2)*(2*h2 + k2) - 5*h2*k2))))
239
+
240
+ def E37(h2, k2, s):
241
+ return s * sqrt(abs((s*s - h2)*(s*s - k2)))
242
+
243
+ assert_equal(ellip_harm(5, 8, 1, 2, 2.5, 1, 1),
244
+ ellip_harm(5, 8, 1, 2, 2.5))
245
+
246
+ known_funcs = {(0, 1): E01, (1, 1): E11, (1, 2): E12, (1, 3): E13,
247
+ (2, 1): E21, (2, 2): E22, (2, 3): E23, (2, 4): E24,
248
+ (2, 5): E25, (3, 1): E31, (3, 2): E32, (3, 3): E33,
249
+ (3, 4): E34, (3, 5): E35, (3, 6): E36, (3, 7): E37}
250
+
251
+ point_ref = []
252
+
253
+ def ellip_harm_known(h2, k2, n, p, s):
254
+ for i in range(h2.size):
255
+ func = known_funcs[(int(n[i]), int(p[i]))]
256
+ point_ref.append(func(h2[i], k2[i], s[i]))
257
+ return point_ref
258
+
259
+ np.random.seed(1234)
260
+ h2 = np.random.pareto(0.5, size=30)
261
+ k2 = h2*(1 + np.random.pareto(0.5, size=h2.size))
262
+ s = np.random.pareto(0.5, size=h2.size)
263
+ points = []
264
+ for i in range(h2.size):
265
+ for n in range(4):
266
+ for p in range(1, 2*n+2):
267
+ points.append((h2[i], k2[i], n, p, s[i]))
268
+ points = np.array(points)
269
+ assert_func_equal(ellip_harm, ellip_harm_known, points, rtol=1e-12)
270
+
271
+
272
+ def test_ellip_harm_invalid_p():
273
+ # Regression test. This should return nan.
274
+ n = 4
275
+ # Make p > 2*n + 1.
276
+ p = 2*n + 2
277
+ result = ellip_harm(0.5, 2.0, n, p, 0.2)
278
+ assert np.isnan(result)
.venv/Lib/site-packages/scipy/special/tests/test_erfinv.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from numpy.testing import assert_allclose, assert_equal
3
+ import pytest
4
+
5
+ import scipy.special as sc
6
+
7
+
8
+ class TestInverseErrorFunction:
9
+ def test_compliment(self):
10
+ # Test erfcinv(1 - x) == erfinv(x)
11
+ x = np.linspace(-1, 1, 101)
12
+ assert_allclose(sc.erfcinv(1 - x), sc.erfinv(x), rtol=0, atol=1e-15)
13
+
14
+ def test_literal_values(self):
15
+ # The expected values were calculated with mpmath:
16
+ #
17
+ # import mpmath
18
+ # mpmath.mp.dps = 200
19
+ # for y in [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]:
20
+ # x = mpmath.erfinv(y)
21
+ # print(x)
22
+ #
23
+ y = np.array([0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])
24
+ actual = sc.erfinv(y)
25
+ expected = [
26
+ 0.0,
27
+ 0.08885599049425769,
28
+ 0.1791434546212917,
29
+ 0.2724627147267543,
30
+ 0.37080715859355795,
31
+ 0.4769362762044699,
32
+ 0.5951160814499948,
33
+ 0.7328690779592167,
34
+ 0.9061938024368233,
35
+ 1.1630871536766743,
36
+ ]
37
+ assert_allclose(actual, expected, rtol=0, atol=1e-15)
38
+
39
+ @pytest.mark.parametrize(
40
+ 'f, x, y',
41
+ [
42
+ (sc.erfinv, -1, -np.inf),
43
+ (sc.erfinv, 0, 0),
44
+ (sc.erfinv, 1, np.inf),
45
+ (sc.erfinv, -100, np.nan),
46
+ (sc.erfinv, 100, np.nan),
47
+ (sc.erfcinv, 0, np.inf),
48
+ (sc.erfcinv, 1, -0.0),
49
+ (sc.erfcinv, 2, -np.inf),
50
+ (sc.erfcinv, -100, np.nan),
51
+ (sc.erfcinv, 100, np.nan),
52
+ ],
53
+ ids=[
54
+ 'erfinv at lower bound',
55
+ 'erfinv at midpoint',
56
+ 'erfinv at upper bound',
57
+ 'erfinv below lower bound',
58
+ 'erfinv above upper bound',
59
+ 'erfcinv at lower bound',
60
+ 'erfcinv at midpoint',
61
+ 'erfcinv at upper bound',
62
+ 'erfcinv below lower bound',
63
+ 'erfcinv above upper bound',
64
+ ]
65
+ )
66
+ def test_domain_bounds(self, f, x, y):
67
+ assert_equal(f(x), y)
68
+
69
+ def test_erfinv_asympt(self):
70
+ # regression test for gh-12758: erfinv(x) loses precision at small x
71
+ # expected values precomputed with mpmath:
72
+ # >>> mpmath.mp.dps = 100
73
+ # >>> expected = [float(mpmath.erfinv(t)) for t in x]
74
+ x = np.array([1e-20, 1e-15, 1e-14, 1e-10, 1e-8, 0.9e-7, 1.1e-7, 1e-6])
75
+ expected = np.array([8.86226925452758e-21,
76
+ 8.862269254527581e-16,
77
+ 8.86226925452758e-15,
78
+ 8.862269254527581e-11,
79
+ 8.86226925452758e-09,
80
+ 7.97604232907484e-08,
81
+ 9.74849617998037e-08,
82
+ 8.8622692545299e-07])
83
+ assert_allclose(sc.erfinv(x), expected,
84
+ rtol=1e-15)
85
+
86
+ # also test the roundtrip consistency
87
+ assert_allclose(sc.erf(sc.erfinv(x)),
88
+ x,
89
+ rtol=5e-15)
.venv/Lib/site-packages/scipy/special/tests/test_exponential_integrals.py ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pytest
2
+
3
+ import numpy as np
4
+ from numpy.testing import assert_allclose
5
+ import scipy.special as sc
6
+
7
+
8
+ class TestExp1:
9
+
10
+ def test_branch_cut(self):
11
+ assert np.isnan(sc.exp1(-1))
12
+ assert sc.exp1(complex(-1, 0)).imag == (
13
+ -sc.exp1(complex(-1, -0.0)).imag
14
+ )
15
+
16
+ assert_allclose(
17
+ sc.exp1(complex(-1, 0)),
18
+ sc.exp1(-1 + 1e-20j),
19
+ atol=0,
20
+ rtol=1e-15
21
+ )
22
+ assert_allclose(
23
+ sc.exp1(complex(-1, -0.0)),
24
+ sc.exp1(-1 - 1e-20j),
25
+ atol=0,
26
+ rtol=1e-15
27
+ )
28
+
29
+ def test_834(self):
30
+ # Regression test for #834
31
+ a = sc.exp1(-complex(19.9999990))
32
+ b = sc.exp1(-complex(19.9999991))
33
+ assert_allclose(a.imag, b.imag, atol=0, rtol=1e-15)
34
+
35
+
36
+ class TestScaledExp1:
37
+
38
+ @pytest.mark.parametrize('x, expected', [(0, 0), (np.inf, 1)])
39
+ def test_limits(self, x, expected):
40
+ y = sc._ufuncs._scaled_exp1(x)
41
+ assert y == expected
42
+
43
+ # The expected values were computed with mpmath, e.g.:
44
+ #
45
+ # from mpmath import mp
46
+ # mp.dps = 80
47
+ # x = 1e-25
48
+ # print(float(x*mp.exp(x)*np.expint(1, x)))
49
+ #
50
+ # prints 5.698741165994961e-24
51
+ #
52
+ # The method used to compute _scaled_exp1 changes at x=1
53
+ # and x=1250, so values at those inputs, and values just
54
+ # above and below them, are included in the test data.
55
+ @pytest.mark.parametrize('x, expected',
56
+ [(1e-25, 5.698741165994961e-24),
57
+ (0.1, 0.20146425447084518),
58
+ (0.9995, 0.5962509885831002),
59
+ (1.0, 0.5963473623231941),
60
+ (1.0005, 0.5964436833238044),
61
+ (2.5, 0.7588145912149602),
62
+ (10.0, 0.9156333393978808),
63
+ (100.0, 0.9901942286733019),
64
+ (500.0, 0.9980079523802055),
65
+ (1000.0, 0.9990019940238807),
66
+ (1249.5, 0.9992009578306811),
67
+ (1250.0, 0.9992012769377913),
68
+ (1250.25, 0.9992014363957858),
69
+ (2000.0, 0.9995004992514963),
70
+ (1e4, 0.9999000199940024),
71
+ (1e10, 0.9999999999),
72
+ (1e15, 0.999999999999999),
73
+ ])
74
+ def test_scaled_exp1(self, x, expected):
75
+ y = sc._ufuncs._scaled_exp1(x)
76
+ assert_allclose(y, expected, rtol=2e-15)
77
+
78
+
79
+ class TestExpi:
80
+
81
+ @pytest.mark.parametrize('result', [
82
+ sc.expi(complex(-1, 0)),
83
+ sc.expi(complex(-1, -0.0)),
84
+ sc.expi(-1)
85
+ ])
86
+ def test_branch_cut(self, result):
87
+ desired = -0.21938393439552027368 # Computed using Mpmath
88
+ assert_allclose(result, desired, atol=0, rtol=1e-14)
89
+
90
+ def test_near_branch_cut(self):
91
+ lim_from_above = sc.expi(-1 + 1e-20j)
92
+ lim_from_below = sc.expi(-1 - 1e-20j)
93
+ assert_allclose(
94
+ lim_from_above.real,
95
+ lim_from_below.real,
96
+ atol=0,
97
+ rtol=1e-15
98
+ )
99
+ assert_allclose(
100
+ lim_from_above.imag,
101
+ -lim_from_below.imag,
102
+ atol=0,
103
+ rtol=1e-15
104
+ )
105
+
106
+ def test_continuity_on_positive_real_axis(self):
107
+ assert_allclose(
108
+ sc.expi(complex(1, 0)),
109
+ sc.expi(complex(1, -0.0)),
110
+ atol=0,
111
+ rtol=1e-15
112
+ )
113
+
114
+
115
+ class TestExpn:
116
+
117
+ def test_out_of_domain(self):
118
+ assert all(np.isnan([sc.expn(-1, 1.0), sc.expn(1, -1.0)]))
.venv/Lib/site-packages/scipy/special/tests/test_faddeeva.py ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pytest
2
+
3
+ import numpy as np
4
+ from numpy.testing import assert_allclose
5
+ import scipy.special as sc
6
+ from scipy.special._testutils import FuncData
7
+
8
+
9
+ class TestVoigtProfile:
10
+
11
+ @pytest.mark.parametrize('x, sigma, gamma', [
12
+ (np.nan, 1, 1),
13
+ (0, np.nan, 1),
14
+ (0, 1, np.nan),
15
+ (1, np.nan, 0),
16
+ (np.nan, 1, 0),
17
+ (1, 0, np.nan),
18
+ (np.nan, 0, 1),
19
+ (np.nan, 0, 0)
20
+ ])
21
+ def test_nan(self, x, sigma, gamma):
22
+ assert np.isnan(sc.voigt_profile(x, sigma, gamma))
23
+
24
+ @pytest.mark.parametrize('x, desired', [
25
+ (-np.inf, 0),
26
+ (np.inf, 0)
27
+ ])
28
+ def test_inf(self, x, desired):
29
+ assert sc.voigt_profile(x, 1, 1) == desired
30
+
31
+ def test_against_mathematica(self):
32
+ # Results obtained from Mathematica by computing
33
+ #
34
+ # PDF[VoigtDistribution[gamma, sigma], x]
35
+ #
36
+ points = np.array([
37
+ [-7.89, 45.06, 6.66, 0.0077921073660388806401],
38
+ [-0.05, 7.98, 24.13, 0.012068223646769913478],
39
+ [-13.98, 16.83, 42.37, 0.0062442236362132357833],
40
+ [-12.66, 0.21, 6.32, 0.010052516161087379402],
41
+ [11.34, 4.25, 21.96, 0.0113698923627278917805],
42
+ [-11.56, 20.40, 30.53, 0.0076332760432097464987],
43
+ [-9.17, 25.61, 8.32, 0.011646345779083005429],
44
+ [16.59, 18.05, 2.50, 0.013637768837526809181],
45
+ [9.11, 2.12, 39.33, 0.0076644040807277677585],
46
+ [-43.33, 0.30, 45.68, 0.0036680463875330150996]
47
+ ])
48
+ FuncData(
49
+ sc.voigt_profile,
50
+ points,
51
+ (0, 1, 2),
52
+ 3,
53
+ atol=0,
54
+ rtol=1e-15
55
+ ).check()
56
+
57
+ def test_symmetry(self):
58
+ x = np.linspace(0, 10, 20)
59
+ assert_allclose(
60
+ sc.voigt_profile(x, 1, 1),
61
+ sc.voigt_profile(-x, 1, 1),
62
+ rtol=1e-15,
63
+ atol=0
64
+ )
65
+
66
+ @pytest.mark.parametrize('x, sigma, gamma, desired', [
67
+ (0, 0, 0, np.inf),
68
+ (1, 0, 0, 0)
69
+ ])
70
+ def test_corner_cases(self, x, sigma, gamma, desired):
71
+ assert sc.voigt_profile(x, sigma, gamma) == desired
72
+
73
+ @pytest.mark.parametrize('sigma1, gamma1, sigma2, gamma2', [
74
+ (0, 1, 1e-16, 1),
75
+ (1, 0, 1, 1e-16),
76
+ (0, 0, 1e-16, 1e-16)
77
+ ])
78
+ def test_continuity(self, sigma1, gamma1, sigma2, gamma2):
79
+ x = np.linspace(1, 10, 20)
80
+ assert_allclose(
81
+ sc.voigt_profile(x, sigma1, gamma1),
82
+ sc.voigt_profile(x, sigma2, gamma2),
83
+ rtol=1e-16,
84
+ atol=1e-16
85
+ )
.venv/Lib/site-packages/scipy/special/tests/test_gamma.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import scipy.special as sc
3
+
4
+
5
+ class TestRgamma:
6
+
7
+ def test_gh_11315(self):
8
+ assert sc.rgamma(-35) == 0
9
+
10
+ def test_rgamma_zeros(self):
11
+ x = np.array([0, -10, -100, -1000, -10000])
12
+ assert np.all(sc.rgamma(x) == 0)
.venv/Lib/site-packages/scipy/special/tests/test_gammainc.py ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pytest
2
+
3
+ import numpy as np
4
+ from numpy.testing import assert_allclose, assert_array_equal
5
+
6
+ import scipy.special as sc
7
+ from scipy.special._testutils import FuncData
8
+
9
+
10
+ INVALID_POINTS = [
11
+ (1, -1),
12
+ (0, 0),
13
+ (-1, 1),
14
+ (np.nan, 1),
15
+ (1, np.nan)
16
+ ]
17
+
18
+
19
+ class TestGammainc:
20
+
21
+ @pytest.mark.parametrize('a, x', INVALID_POINTS)
22
+ def test_domain(self, a, x):
23
+ assert np.isnan(sc.gammainc(a, x))
24
+
25
+ def test_a_eq_0_x_gt_0(self):
26
+ assert sc.gammainc(0, 1) == 1
27
+
28
+ @pytest.mark.parametrize('a, x, desired', [
29
+ (np.inf, 1, 0),
30
+ (np.inf, 0, 0),
31
+ (np.inf, np.inf, np.nan),
32
+ (1, np.inf, 1)
33
+ ])
34
+ def test_infinite_arguments(self, a, x, desired):
35
+ result = sc.gammainc(a, x)
36
+ if np.isnan(desired):
37
+ assert np.isnan(result)
38
+ else:
39
+ assert result == desired
40
+
41
+ def test_infinite_limits(self):
42
+ # Test that large arguments converge to the hard-coded limits
43
+ # at infinity.
44
+ assert_allclose(
45
+ sc.gammainc(1000, 100),
46
+ sc.gammainc(np.inf, 100),
47
+ atol=1e-200, # Use `atol` since the function converges to 0.
48
+ rtol=0
49
+ )
50
+ assert sc.gammainc(100, 1000) == sc.gammainc(100, np.inf)
51
+
52
+ def test_x_zero(self):
53
+ a = np.arange(1, 10)
54
+ assert_array_equal(sc.gammainc(a, 0), 0)
55
+
56
+ def test_limit_check(self):
57
+ result = sc.gammainc(1e-10, 1)
58
+ limit = sc.gammainc(0, 1)
59
+ assert np.isclose(result, limit)
60
+
61
+ def gammainc_line(self, x):
62
+ # The line a = x where a simpler asymptotic expansion (analog
63
+ # of DLMF 8.12.15) is available.
64
+ c = np.array([-1/3, -1/540, 25/6048, 101/155520,
65
+ -3184811/3695155200, -2745493/8151736420])
66
+ res = 0
67
+ xfac = 1
68
+ for ck in c:
69
+ res -= ck*xfac
70
+ xfac /= x
71
+ res /= np.sqrt(2*np.pi*x)
72
+ res += 0.5
73
+ return res
74
+
75
+ def test_line(self):
76
+ x = np.logspace(np.log10(25), 300, 500)
77
+ a = x
78
+ dataset = np.vstack((a, x, self.gammainc_line(x))).T
79
+ FuncData(sc.gammainc, dataset, (0, 1), 2, rtol=1e-11).check()
80
+
81
+ def test_roundtrip(self):
82
+ a = np.logspace(-5, 10, 100)
83
+ x = np.logspace(-5, 10, 100)
84
+
85
+ y = sc.gammaincinv(a, sc.gammainc(a, x))
86
+ assert_allclose(x, y, rtol=1e-10)
87
+
88
+
89
+ class TestGammaincc:
90
+
91
+ @pytest.mark.parametrize('a, x', INVALID_POINTS)
92
+ def test_domain(self, a, x):
93
+ assert np.isnan(sc.gammaincc(a, x))
94
+
95
+ def test_a_eq_0_x_gt_0(self):
96
+ assert sc.gammaincc(0, 1) == 0
97
+
98
+ @pytest.mark.parametrize('a, x, desired', [
99
+ (np.inf, 1, 1),
100
+ (np.inf, 0, 1),
101
+ (np.inf, np.inf, np.nan),
102
+ (1, np.inf, 0)
103
+ ])
104
+ def test_infinite_arguments(self, a, x, desired):
105
+ result = sc.gammaincc(a, x)
106
+ if np.isnan(desired):
107
+ assert np.isnan(result)
108
+ else:
109
+ assert result == desired
110
+
111
+ def test_infinite_limits(self):
112
+ # Test that large arguments converge to the hard-coded limits
113
+ # at infinity.
114
+ assert sc.gammaincc(1000, 100) == sc.gammaincc(np.inf, 100)
115
+ assert_allclose(
116
+ sc.gammaincc(100, 1000),
117
+ sc.gammaincc(100, np.inf),
118
+ atol=1e-200, # Use `atol` since the function converges to 0.
119
+ rtol=0
120
+ )
121
+
122
+ def test_limit_check(self):
123
+ result = sc.gammaincc(1e-10,1)
124
+ limit = sc.gammaincc(0,1)
125
+ assert np.isclose(result, limit)
126
+
127
+ def test_x_zero(self):
128
+ a = np.arange(1, 10)
129
+ assert_array_equal(sc.gammaincc(a, 0), 1)
130
+
131
+ def test_roundtrip(self):
132
+ a = np.logspace(-5, 10, 100)
133
+ x = np.logspace(-5, 10, 100)
134
+
135
+ y = sc.gammainccinv(a, sc.gammaincc(a, x))
136
+ assert_allclose(x, y, rtol=1e-14)
.venv/Lib/site-packages/scipy/special/tests/test_hyp2f1.py ADDED
@@ -0,0 +1,2180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Tests for hyp2f1 for complex values.
2
+
3
+ Author: Albert Steppi, with credit to Adam Kullberg (FormerPhycisist) for
4
+ the implementation of mp_hyp2f1 below, which modifies mpmath's hyp2f1 to
5
+ return the same branch as scipy's on the standard branch cut.
6
+ """
7
+
8
+ import sys
9
+ import pytest
10
+ import numpy as np
11
+ from typing import NamedTuple
12
+ from numpy.testing import assert_allclose
13
+
14
+ from scipy.special import hyp2f1
15
+ from scipy.special._testutils import check_version, MissingModule
16
+
17
+
18
+ try:
19
+ import mpmath
20
+ except ImportError:
21
+ mpmath = MissingModule("mpmath")
22
+
23
+
24
+ def mp_hyp2f1(a, b, c, z):
25
+ """Return mpmath hyp2f1 calculated on same branch as scipy hyp2f1.
26
+
27
+ For most values of a,b,c mpmath returns the x - 0j branch of hyp2f1 on the
28
+ branch cut x=(1,inf) whereas scipy's hyp2f1 calculates the x + 0j branch.
29
+ Thus, to generate the right comparison values on the branch cut, we
30
+ evaluate mpmath.hyp2f1 at x + 1e-15*j.
31
+
32
+ The exception to this occurs when c-a=-m in which case both mpmath and
33
+ scipy calculate the x + 0j branch on the branch cut. When this happens
34
+ mpmath.hyp2f1 will be evaluated at the original z point.
35
+ """
36
+ on_branch_cut = z.real > 1.0 and abs(z.imag) < 1.0e-15
37
+ cond1 = abs(c - a - round(c - a)) < 1.0e-15 and round(c - a) <= 0
38
+ cond2 = abs(c - b - round(c - b)) < 1.0e-15 and round(c - b) <= 0
39
+ # Make sure imaginary part is *exactly* zero
40
+ if on_branch_cut:
41
+ z = z.real + 0.0j
42
+ if on_branch_cut and not (cond1 or cond2):
43
+ z_mpmath = z.real + 1.0e-15j
44
+ else:
45
+ z_mpmath = z
46
+ return complex(mpmath.hyp2f1(a, b, c, z_mpmath))
47
+
48
+
49
+ class Hyp2f1TestCase(NamedTuple):
50
+ a: float
51
+ b: float
52
+ c: float
53
+ z: complex
54
+ expected: complex
55
+ rtol: float
56
+
57
+
58
+ class TestHyp2f1:
59
+ """Tests for hyp2f1 for complex values.
60
+
61
+ Expected values for test cases were computed using mpmath. See
62
+ `scipy.special._precompute.hyp2f1_data`. The verbose style of specifying
63
+ test cases is used for readability and to make it easier to mark individual
64
+ cases as expected to fail. Expected failures are used to highlight cases
65
+ where improvements are needed. See
66
+ `scipy.special._precompute.hyp2f1_data.make_hyp2f1_test_cases` for a
67
+ function to generate the boilerplate for the test cases.
68
+
69
+ Assertions have been added to each test to ensure that the test cases match
70
+ the situations that are intended. A final test `test_test_hyp2f1` checks
71
+ that the expected values in the test cases actually match what is computed
72
+ by mpmath. This test is marked slow even though it isn't particularly slow
73
+ so that it won't run by default on continuous integration builds.
74
+ """
75
+ @pytest.mark.parametrize(
76
+ "hyp2f1_test_case",
77
+ [
78
+ pytest.param(
79
+ Hyp2f1TestCase(
80
+ a=0.5,
81
+ b=0.2,
82
+ c=-10,
83
+ z=0.2 + 0.2j,
84
+ expected=np.inf + 0j,
85
+ rtol=0
86
+ )
87
+ ),
88
+ pytest.param(
89
+ Hyp2f1TestCase(
90
+ a=0.5,
91
+ b=0.2,
92
+ c=-10,
93
+ z=0 + 0j,
94
+ expected=1 + 0j,
95
+ rtol=0
96
+ ),
97
+ ),
98
+ pytest.param(
99
+ Hyp2f1TestCase(
100
+ a=0.5,
101
+ b=0,
102
+ c=-10,
103
+ z=0.2 + 0.2j,
104
+ expected=1 + 0j,
105
+ rtol=0
106
+ ),
107
+ ),
108
+ pytest.param(
109
+ Hyp2f1TestCase(
110
+ a=0.5,
111
+ b=0,
112
+ c=0,
113
+ z=0.2 + 0.2j,
114
+ expected=1 + 0j,
115
+ rtol=0,
116
+ ),
117
+ ),
118
+ pytest.param(
119
+ Hyp2f1TestCase(
120
+ a=0.5,
121
+ b=0.2,
122
+ c=0,
123
+ z=0.2 + 0.2j,
124
+ expected=np.inf + 0j,
125
+ rtol=0,
126
+ ),
127
+ ),
128
+ pytest.param(
129
+ Hyp2f1TestCase(
130
+ a=0.5,
131
+ b=0.2,
132
+ c=0,
133
+ z=0 + 0j,
134
+ expected=np.nan + 0j,
135
+ rtol=0,
136
+ ),
137
+ ),
138
+ pytest.param(
139
+ Hyp2f1TestCase(
140
+ a=0.5,
141
+ b=-5,
142
+ c=-10,
143
+ z=0.2 + 0.2j,
144
+ expected=(1.0495404166666666+0.05708208333333334j),
145
+ rtol=1e-15,
146
+ ),
147
+ ),
148
+ pytest.param(
149
+ Hyp2f1TestCase(
150
+ a=0.5,
151
+ b=-10,
152
+ c=-10,
153
+ z=0.2 + 0.2j,
154
+ expected=(1.092966013125+0.13455014673750001j),
155
+ rtol=1e-15,
156
+ ),
157
+ ),
158
+ pytest.param(
159
+ Hyp2f1TestCase(
160
+ a=-10,
161
+ b=-20,
162
+ c=-10,
163
+ z=0.2 + 0.2j,
164
+ expected=(-0.07712512000000005+0.12752814080000005j),
165
+ rtol=1e-13,
166
+ ),
167
+ ),
168
+ pytest.param(
169
+ Hyp2f1TestCase(
170
+ a=-1,
171
+ b=3.2,
172
+ c=-1,
173
+ z=0.2 + 0.2j,
174
+ expected=(1.6400000000000001+0.6400000000000001j),
175
+ rtol=1e-13,
176
+ ),
177
+ ),
178
+ pytest.param(
179
+ Hyp2f1TestCase(
180
+ a=-2,
181
+ b=1.2,
182
+ c=-4,
183
+ z=1 + 0j,
184
+ expected=1.8200000000000001 + 0j,
185
+ rtol=1e-15,
186
+ ),
187
+ ),
188
+ ]
189
+ )
190
+ def test_c_non_positive_int(self, hyp2f1_test_case):
191
+ a, b, c, z, expected, rtol = hyp2f1_test_case
192
+ assert_allclose(hyp2f1(a, b, c, z), expected, rtol=rtol)
193
+
194
+ @pytest.mark.parametrize(
195
+ "hyp2f1_test_case",
196
+ [
197
+ pytest.param(
198
+ Hyp2f1TestCase(
199
+ a=0.5,
200
+ b=0.2,
201
+ c=1.5,
202
+ z=1 + 0j,
203
+ expected=1.1496439092239847 + 0j,
204
+ rtol=1e-15
205
+ ),
206
+ ),
207
+ pytest.param(
208
+ Hyp2f1TestCase(
209
+ a=12.3,
210
+ b=8.0,
211
+ c=20.31,
212
+ z=1 + 0j,
213
+ expected=69280986.75273195 + 0j,
214
+ rtol=1e-15
215
+ ),
216
+ ),
217
+ pytest.param(
218
+ Hyp2f1TestCase(
219
+ a=290.2,
220
+ b=321.5,
221
+ c=700.1,
222
+ z=1 + 0j,
223
+ expected=1.3396562400934e117 + 0j,
224
+ rtol=1e-12,
225
+ ),
226
+ ),
227
+ # Note that here even mpmath produces different results for
228
+ # results that should be equivalent.
229
+ pytest.param(
230
+ Hyp2f1TestCase(
231
+ a=9.2,
232
+ b=621.5,
233
+ c=700.1,
234
+ z=(1+0j),
235
+ expected=(952726652.4158565+0j),
236
+ rtol=5e-13,
237
+ ),
238
+ ),
239
+ pytest.param(
240
+ Hyp2f1TestCase(
241
+ a=621.5,
242
+ b=9.2,
243
+ c=700.1,
244
+ z=(1+0j),
245
+ expected=(952726652.4160284+0j),
246
+ rtol=5e-12,
247
+ ),
248
+ ),
249
+ pytest.param(
250
+ Hyp2f1TestCase(
251
+ a=-101.2,
252
+ b=-400.4,
253
+ c=-172.1,
254
+ z=(1+0j),
255
+ expected=(2.2253618341394838e+37+0j),
256
+ rtol=1e-13,
257
+ ),
258
+ ),
259
+ pytest.param(
260
+ Hyp2f1TestCase(
261
+ a=-400.4,
262
+ b=-101.2,
263
+ c=-172.1,
264
+ z=(1+0j),
265
+ expected=(2.2253618341394838e+37+0j),
266
+ rtol=5e-13,
267
+ ),
268
+ ),
269
+ pytest.param(
270
+ Hyp2f1TestCase(
271
+ a=172.5,
272
+ b=-201.3,
273
+ c=151.2,
274
+ z=(1+0j),
275
+ expected=(7.072266653650905e-135+0j),
276
+ rtol=5e-13,
277
+ ),
278
+ ),
279
+ pytest.param(
280
+ Hyp2f1TestCase(
281
+ a=-201.3,
282
+ b=172.5,
283
+ c=151.2,
284
+ z=(1+0j),
285
+ expected=(7.072266653650905e-135+0j),
286
+ rtol=5e-13,
287
+ ),
288
+ ),
289
+ pytest.param(
290
+ Hyp2f1TestCase(
291
+ a=-102.1,
292
+ b=-20.3,
293
+ c=1.3,
294
+ z=1 + 0j,
295
+ expected=2.7899070752746906e22 + 0j,
296
+ rtol=3e-14,
297
+ ),
298
+ ),
299
+ pytest.param(
300
+ Hyp2f1TestCase(
301
+ a=-202.6,
302
+ b=60.3,
303
+ c=1.5,
304
+ z=1 + 0j,
305
+ expected=-1.3113641413099326e-56 + 0j,
306
+ rtol=1e-12,
307
+ ),
308
+ ),
309
+ ],
310
+ )
311
+ def test_unital_argument(self, hyp2f1_test_case):
312
+ """Tests for case z = 1, c - a - b > 0.
313
+
314
+ Expected answers computed using mpmath.
315
+ """
316
+ a, b, c, z, expected, rtol = hyp2f1_test_case
317
+ assert z == 1 and c - a - b > 0 # Tests the test
318
+ assert_allclose(hyp2f1(a, b, c, z), expected, rtol=rtol)
319
+
320
+ @pytest.mark.parametrize(
321
+ "hyp2f1_test_case",
322
+ [
323
+ pytest.param(
324
+ Hyp2f1TestCase(
325
+ a=0.5,
326
+ b=0.2,
327
+ c=1.3,
328
+ z=-1 + 0j,
329
+ expected=0.9428846409614143 + 0j,
330
+ rtol=1e-15),
331
+ ),
332
+ pytest.param(
333
+ Hyp2f1TestCase(
334
+ a=12.3,
335
+ b=8.0,
336
+ c=5.300000000000001,
337
+ z=-1 + 0j,
338
+ expected=-4.845809986595704e-06 + 0j,
339
+ rtol=1e-15
340
+ ),
341
+ ),
342
+ pytest.param(
343
+ Hyp2f1TestCase(
344
+ a=221.5,
345
+ b=90.2,
346
+ c=132.3,
347
+ z=-1 + 0j,
348
+ expected=2.0490488728377282e-42 + 0j,
349
+ rtol=1e-7,
350
+ ),
351
+ ),
352
+ pytest.param(
353
+ Hyp2f1TestCase(
354
+ a=-102.1,
355
+ b=-20.3,
356
+ c=-80.8,
357
+ z=-1 + 0j,
358
+ expected=45143784.46783885 + 0j,
359
+ rtol=1e-7,
360
+ ),
361
+ marks=pytest.mark.xfail(
362
+ condition=sys.maxsize < 2**32,
363
+ reason="Fails on 32 bit.",
364
+ )
365
+ ),
366
+ ],
367
+ )
368
+ def test_special_case_z_near_minus_1(self, hyp2f1_test_case):
369
+ """Tests for case z ~ -1, c ~ 1 + a - b
370
+
371
+ Expected answers computed using mpmath.
372
+ """
373
+ a, b, c, z, expected, rtol = hyp2f1_test_case
374
+ assert abs(1 + a - b - c) < 1e-15 and abs(z + 1) < 1e-15
375
+ assert_allclose(hyp2f1(a, b, c, z), expected, rtol=rtol)
376
+
377
+ @pytest.mark.parametrize(
378
+ "hyp2f1_test_case",
379
+ [
380
+ pytest.param(
381
+ Hyp2f1TestCase(
382
+ a=-4,
383
+ b=2.02764642551431,
384
+ c=1.0561196186065624,
385
+ z=(0.9473684210526314-0.10526315789473695j),
386
+ expected=(0.0031961077109535375-0.0011313924606557173j),
387
+ rtol=1e-12,
388
+ ),
389
+ ),
390
+ pytest.param(
391
+ Hyp2f1TestCase(
392
+ a=-8,
393
+ b=-7.937789122896016,
394
+ c=-15.964218273004214,
395
+ z=(2-0.10526315789473695j),
396
+ expected=(0.005543763196412503-0.0025948879065698306j),
397
+ rtol=5e-13,
398
+ ),
399
+ ),
400
+ pytest.param(
401
+ Hyp2f1TestCase(
402
+ a=-8,
403
+ b=8.095813935368371,
404
+ c=4.0013768449590685,
405
+ z=(0.9473684210526314-0.10526315789473695j),
406
+ expected=(-0.0003054674127221263-9.261359291755414e-05j),
407
+ rtol=1e-10,
408
+ ),
409
+ ),
410
+ pytest.param(
411
+ Hyp2f1TestCase(
412
+ a=-4,
413
+ b=-3.956227226099288,
414
+ c=-3.9316537064827854,
415
+ z=(1.1578947368421053-0.3157894736842106j),
416
+ expected=(-0.0020809502580892937-0.0041877333232365095j),
417
+ rtol=5e-12,
418
+ ),
419
+ ),
420
+ pytest.param(
421
+ Hyp2f1TestCase(
422
+ a=2.02764642551431,
423
+ b=-4,
424
+ c=2.050308316530781,
425
+ z=(0.9473684210526314-0.10526315789473695j),
426
+ expected=(0.0011282435590058734+0.0002027062303465851j),
427
+ rtol=5e-13,
428
+ ),
429
+ ),
430
+ pytest.param(
431
+ Hyp2f1TestCase(
432
+ a=-7.937789122896016,
433
+ b=-8,
434
+ c=-15.964218273004214,
435
+ z=(1.3684210526315788+0.10526315789473673j),
436
+ expected=(-9.134907719238265e-05-0.00040219233987390723j),
437
+ rtol=5e-12,
438
+ ),
439
+ ),
440
+ pytest.param(
441
+ Hyp2f1TestCase(
442
+ a=4.080187217753502,
443
+ b=-4,
444
+ c=4.0013768449590685,
445
+ z=(0.9473684210526314-0.10526315789473695j),
446
+ expected=(-0.000519013062087489-0.0005855883076830948j),
447
+ rtol=5e-12,
448
+ ),
449
+ ),
450
+ pytest.param(
451
+ Hyp2f1TestCase(
452
+ a=-10000,
453
+ b=2.2,
454
+ c=93459345.3,
455
+ z=(2+2j),
456
+ expected=(0.9995292071559088-0.00047047067522659253j),
457
+ rtol=1e-12,
458
+ ),
459
+ ),
460
+ ]
461
+ )
462
+ def test_a_b_negative_int(self, hyp2f1_test_case):
463
+ a, b, c, z, expected, rtol = hyp2f1_test_case
464
+ assert a == int(a) and a < 0 or b == int(b) and b < 0 # Tests the test
465
+ assert_allclose(hyp2f1(a, b, c, z), expected, rtol=rtol)
466
+
467
+ @pytest.mark.parametrize(
468
+ "hyp2f1_test_case",
469
+ [
470
+ pytest.param(
471
+ Hyp2f1TestCase(
472
+ a=-0.5,
473
+ b=-0.9629749245209605,
474
+ c=-15.5,
475
+ z=(1.1578947368421053-1.1578947368421053j),
476
+ expected=(0.9778506962676361+0.044083801141231616j),
477
+ rtol=3e-12,
478
+ ),
479
+ ),
480
+ pytest.param(
481
+ Hyp2f1TestCase(
482
+ a=8.5,
483
+ b=-3.9316537064827854,
484
+ c=1.5,
485
+ z=(0.9473684210526314-0.10526315789473695j),
486
+ expected=(4.0793167523167675-10.11694246310966j),
487
+ rtol=6e-12,
488
+ ),
489
+ ),
490
+ pytest.param(
491
+ Hyp2f1TestCase(
492
+ a=8.5,
493
+ b=-0.9629749245209605,
494
+ c=2.5,
495
+ z=(1.1578947368421053-0.10526315789473695j),
496
+ expected=(-2.9692999501916915+0.6394599899845594j),
497
+ rtol=1e-11,
498
+ ),
499
+ ),
500
+ pytest.param(
501
+ Hyp2f1TestCase(
502
+ a=-0.5,
503
+ b=-0.9629749245209605,
504
+ c=-15.5,
505
+ z=(1.5789473684210522-1.1578947368421053j),
506
+ expected=(0.9493076367106102-0.04316852977183447j),
507
+ rtol=1e-11,
508
+ ),
509
+ ),
510
+ pytest.param(
511
+ Hyp2f1TestCase(
512
+ a=-0.9220024191881196,
513
+ b=-0.5,
514
+ c=-15.5,
515
+ z=(0.5263157894736841+0.10526315789473673j),
516
+ expected=(0.9844377175631795-0.003120587561483841j),
517
+ rtol=1e-10,
518
+ ),
519
+ ),
520
+ ],
521
+ )
522
+ def test_a_b_neg_int_after_euler_hypergeometric_transformation(
523
+ self, hyp2f1_test_case
524
+ ):
525
+ a, b, c, z, expected, rtol = hyp2f1_test_case
526
+ assert ( # Tests the test
527
+ (abs(c - a - int(c - a)) < 1e-15 and c - a < 0) or
528
+ (abs(c - b - int(c - b)) < 1e-15 and c - b < 0)
529
+ )
530
+ assert_allclose(hyp2f1(a, b, c, z), expected, rtol=rtol)
531
+
532
+ @pytest.mark.parametrize(
533
+ "hyp2f1_test_case",
534
+ [
535
+ pytest.param(
536
+ Hyp2f1TestCase(
537
+ a=-0.9220024191881196,
538
+ b=-0.9629749245209605,
539
+ c=-15.963511401609862,
540
+ z=(0.10526315789473673-0.3157894736842106j),
541
+ expected=(0.9941449585778349+0.01756335047931358j),
542
+ rtol=1e-14,
543
+ ),
544
+ ),
545
+ pytest.param(
546
+ Hyp2f1TestCase(
547
+ a=1.0272592605282642,
548
+ b=-0.9629749245209605,
549
+ c=-15.963511401609862,
550
+ z=(0.5263157894736841+0.5263157894736841j),
551
+ expected=(1.0388722293372104-0.09549450380041416j),
552
+ rtol=5e-11,
553
+ ),
554
+ ),
555
+ pytest.param(
556
+ Hyp2f1TestCase(
557
+ a=2.02764642551431,
558
+ b=1.0561196186065624,
559
+ c=-7.93846038215665,
560
+ z=(0.10526315789473673+0.7368421052631575j),
561
+ expected=(2.1948378809826434+24.934157235172222j),
562
+ rtol=5e-15,
563
+ ),
564
+ ),
565
+ pytest.param(
566
+ Hyp2f1TestCase(
567
+ a=2.02764642551431,
568
+ b=16.088264119063613,
569
+ c=8.031683612216888,
570
+ z=(0.3157894736842106-0.736842105263158j),
571
+ expected=(-0.4075277891264672-0.06819344579666956j),
572
+ rtol=2e-12,
573
+ ),
574
+ ),
575
+ pytest.param(
576
+ Hyp2f1TestCase(
577
+ a=4.080187217753502,
578
+ b=2.050308316530781,
579
+ c=8.031683612216888,
580
+ z=(0.7368421052631575-0.10526315789473695j),
581
+ expected=(2.833535530740603-0.6925373701408158j),
582
+ rtol=5e-15,
583
+ ),
584
+ ),
585
+ pytest.param(
586
+ Hyp2f1TestCase(
587
+ a=2.02764642551431,
588
+ b=2.050308316530781,
589
+ c=4.078873014294075,
590
+ z=(0.10526315789473673-0.3157894736842106j),
591
+ expected=(1.005347176329683-0.3580736009337313j),
592
+ rtol=5e-16,
593
+ ),
594
+ ),
595
+ pytest.param(
596
+ Hyp2f1TestCase(
597
+ a=-0.9220024191881196,
598
+ b=-0.9629749245209605,
599
+ c=-15.963511401609862,
600
+ z=(0.3157894736842106-0.5263157894736843j),
601
+ expected=(0.9824353641135369+0.029271018868990268j),
602
+ rtol=5e-13,
603
+ ),
604
+ ),
605
+ pytest.param(
606
+ Hyp2f1TestCase(
607
+ a=-0.9220024191881196,
608
+ b=-0.9629749245209605,
609
+ c=-159.63511401609862,
610
+ z=(0.3157894736842106-0.5263157894736843j),
611
+ expected=(0.9982436200365834+0.002927268199671111j),
612
+ rtol=1e-7,
613
+ ),
614
+ marks=pytest.mark.xfail(reason="Poor convergence.")
615
+ ),
616
+ pytest.param(
617
+ Hyp2f1TestCase(
618
+ a=2.02764642551431,
619
+ b=16.088264119063613,
620
+ c=8.031683612216888,
621
+ z=(0.5263157894736841-0.5263157894736843j),
622
+ expected=(-0.6906825165778091+0.8176575137504892j),
623
+ rtol=5e-13,
624
+ ),
625
+ ),
626
+ ]
627
+ )
628
+ def test_region1(self, hyp2f1_test_case):
629
+ """|z| < 0.9 and real(z) >= 0."""
630
+ a, b, c, z, expected, rtol = hyp2f1_test_case
631
+ assert abs(z) < 0.9 and z.real >= 0 # Tests the test
632
+ assert_allclose(hyp2f1(a, b, c, z), expected, rtol=rtol)
633
+
634
+ @pytest.mark.parametrize(
635
+ "hyp2f1_test_case",
636
+ [
637
+ pytest.param(
638
+ Hyp2f1TestCase(
639
+ a=2.02764642551431,
640
+ b=1.0561196186065624,
641
+ c=4.078873014294075,
642
+ z=(-0.3157894736842106+0.7368421052631575j),
643
+ expected=(0.7751915029081136+0.24068493258607315j),
644
+ rtol=5e-15,
645
+ ),
646
+ ),
647
+ pytest.param(
648
+ Hyp2f1TestCase(
649
+ a=16.087593263474208,
650
+ b=16.088264119063613,
651
+ c=2.0397202577726152,
652
+ z=(-0.9473684210526316-0.3157894736842106j),
653
+ expected=(6.564549348474962e-07+1.6761570598334562e-06j),
654
+ rtol=5e-09,
655
+ ),
656
+ ),
657
+ pytest.param(
658
+ Hyp2f1TestCase(
659
+ a=1.0272592605282642,
660
+ b=2.050308316530781,
661
+ c=16.056809865262608,
662
+ z=(-0.10526315789473695-0.10526315789473695j),
663
+ expected=(0.9862043298997204-0.013293151372712681j),
664
+ rtol=5e-15,
665
+ ),
666
+ ),
667
+ pytest.param(
668
+ Hyp2f1TestCase(
669
+ a=4.080187217753502,
670
+ b=8.077282662161238,
671
+ c=16.056809865262608,
672
+ z=(-0.3157894736842106-0.736842105263158j),
673
+ expected=(0.16163826638754716-0.41378530376373734j),
674
+ rtol=5e-15,
675
+ ),
676
+ ),
677
+ pytest.param(
678
+ Hyp2f1TestCase(
679
+ a=2.02764642551431,
680
+ b=2.050308316530781,
681
+ c=-0.906685989801748,
682
+ z=(-0.5263157894736843+0.3157894736842106j),
683
+ expected=(-6.256871535165936+0.13824973858225484j),
684
+ rtol=1e-15,
685
+ ),
686
+ ),
687
+ pytest.param(
688
+ Hyp2f1TestCase(
689
+ a=2.02764642551431,
690
+ b=8.077282662161238,
691
+ c=-3.9924618758357022,
692
+ z=(-0.9473684210526316-0.3157894736842106j),
693
+ expected=(75.54672526086316+50.56157041797548j),
694
+ rtol=5e-12,
695
+ ),
696
+ ),
697
+ pytest.param(
698
+ Hyp2f1TestCase(
699
+ a=16.087593263474208,
700
+ b=8.077282662161238,
701
+ c=-1.9631175993998025,
702
+ z=(-0.5263157894736843+0.5263157894736841j),
703
+ expected=(282.0602536306534-82.31597306936214j),
704
+ rtol=5e-13,
705
+ ),
706
+ ),
707
+ pytest.param(
708
+ Hyp2f1TestCase(
709
+ a=8.095813935368371,
710
+ b=-3.9316537064827854,
711
+ c=8.031683612216888,
712
+ z=(-0.5263157894736843-0.10526315789473695j),
713
+ expected=(5.179603735575851+1.4445374002099813j),
714
+ rtol=5e-14,
715
+ ),
716
+ ),
717
+ pytest.param(
718
+ Hyp2f1TestCase(
719
+ a=4.080187217753502,
720
+ b=-7.949900487447654,
721
+ c=1.0651378143226575,
722
+ z=(-0.3157894736842106-0.9473684210526316j),
723
+ expected=(2317.623517606141-269.51476321010324j),
724
+ rtol=5e-13,
725
+ ),
726
+ ),
727
+ pytest.param(
728
+ Hyp2f1TestCase(
729
+ a=16.087593263474208,
730
+ b=-1.92872979730171,
731
+ c=2.0397202577726152,
732
+ z=(-0.736842105263158-0.3157894736842106j),
733
+ expected=(29.179154096175836+22.126690357535043j),
734
+ rtol=5e-15,
735
+ ),
736
+ ),
737
+ pytest.param(
738
+ Hyp2f1TestCase(
739
+ a=8.095813935368371,
740
+ b=-3.9316537064827854,
741
+ c=-15.963511401609862,
742
+ z=(-0.736842105263158-0.10526315789473695j),
743
+ expected=(0.20820247892032057-0.04763956711248794j),
744
+ rtol=5e-14,
745
+ ),
746
+ ),
747
+ pytest.param(
748
+ Hyp2f1TestCase(
749
+ a=1.0272592605282642,
750
+ b=-15.964218273004214,
751
+ c=-1.9631175993998025,
752
+ z=(-0.3157894736842106-0.5263157894736843j),
753
+ expected=(-157471.63920142158+991294.0587828817j),
754
+ rtol=5e-14,
755
+ ),
756
+ ),
757
+ pytest.param(
758
+ Hyp2f1TestCase(
759
+ a=8.095813935368371,
760
+ b=-7.949900487447654,
761
+ c=-7.93846038215665,
762
+ z=(-0.10526315789473695-0.10526315789473695j),
763
+ expected=(0.30765349653210194-0.2979706363594157j),
764
+ rtol=1e-15,
765
+ ),
766
+ ),
767
+ pytest.param(
768
+ Hyp2f1TestCase(
769
+ a=-3.956227226099288,
770
+ b=1.0561196186065624,
771
+ c=8.031683612216888,
772
+ z=(-0.9473684210526316-0.10526315789473695j),
773
+ expected=(1.6787607400597109+0.10056620134616838j),
774
+ rtol=5e-14,
775
+ ),
776
+ ),
777
+ pytest.param(
778
+ Hyp2f1TestCase(
779
+ a=-7.937789122896016,
780
+ b=16.088264119063613,
781
+ c=4.078873014294075,
782
+ z=(-0.5263157894736843-0.736842105263158j),
783
+ expected=(7062.07842506049-12768.77955655703j),
784
+ rtol=5e-15,
785
+ ),
786
+ ),
787
+ pytest.param(
788
+ Hyp2f1TestCase(
789
+ a=-7.937789122896016,
790
+ b=16.088264119063613,
791
+ c=2.0397202577726152,
792
+ z=(-0.3157894736842106+0.7368421052631575j),
793
+ expected=(54749.216391029935-23078.144720887536j),
794
+ rtol=1e-15,
795
+ ),
796
+ ),
797
+ pytest.param(
798
+ Hyp2f1TestCase(
799
+ a=-3.956227226099288,
800
+ b=1.0561196186065624,
801
+ c=-0.906685989801748,
802
+ z=(-0.10526315789473695-0.10526315789473695j),
803
+ expected=(1.21521766411428-4.449385173946672j),
804
+ rtol=5e-15,
805
+ ),
806
+ ),
807
+ pytest.param(
808
+ Hyp2f1TestCase(
809
+ a=-15.980848054962111,
810
+ b=4.0013768449590685,
811
+ c=-1.9631175993998025,
812
+ z=(-0.736842105263158+0.5263157894736841j),
813
+ expected=(19234693144.196907+1617913967.7294445j),
814
+ rtol=5e-14,
815
+ ),
816
+ ),
817
+ pytest.param(
818
+ Hyp2f1TestCase(
819
+ a=-1.9214641416286231,
820
+ b=1.0561196186065624,
821
+ c=-15.963511401609862,
822
+ z=(-0.5263157894736843+0.3157894736842106j),
823
+ expected=(0.9345201094534371+0.03745712558992195j),
824
+ rtol=5e-15,
825
+ ),
826
+ ),
827
+ pytest.param(
828
+ Hyp2f1TestCase(
829
+ a=-7.937789122896016,
830
+ b=-0.9629749245209605,
831
+ c=2.0397202577726152,
832
+ z=(-0.10526315789473695+0.10526315789473673j),
833
+ expected=(0.605732446296829+0.398171533680972j),
834
+ rtol=5e-15,
835
+ ),
836
+ ),
837
+ pytest.param(
838
+ Hyp2f1TestCase(
839
+ a=-1.9214641416286231,
840
+ b=-15.964218273004214,
841
+ c=2.0397202577726152,
842
+ z=(-0.10526315789473695-0.5263157894736843j),
843
+ expected=(-9.753761888305416-4.590126012666959j),
844
+ rtol=5e-15,
845
+ ),
846
+ ),
847
+ pytest.param(
848
+ Hyp2f1TestCase(
849
+ a=-3.956227226099288,
850
+ b=-1.92872979730171,
851
+ c=2.0397202577726152,
852
+ z=(-0.10526315789473695+0.3157894736842106j),
853
+ expected=(0.45587226291120714+1.0694545265819797j),
854
+ rtol=5e-15,
855
+ ),
856
+ ),
857
+ pytest.param(
858
+ Hyp2f1TestCase(
859
+ a=-0.9220024191881196,
860
+ b=-7.949900487447654,
861
+ c=-0.906685989801748,
862
+ z=(-0.736842105263158+0.3157894736842106j),
863
+ expected=(12.334808243233418-76.26089051819054j),
864
+ rtol=5e-14,
865
+ ),
866
+ ),
867
+ pytest.param(
868
+ Hyp2f1TestCase(
869
+ a=-0.9220024191881196,
870
+ b=-7.949900487447654,
871
+ c=-15.963511401609862,
872
+ z=(-0.5263157894736843+0.10526315789473673j),
873
+ expected=(1.2396019687632678-0.047507973161146286j),
874
+ rtol=1e-14,
875
+ ),
876
+ ),
877
+ pytest.param(
878
+ Hyp2f1TestCase(
879
+ a=-15.980848054962111,
880
+ b=-0.9629749245209605,
881
+ c=-0.906685989801748,
882
+ z=(-0.3157894736842106-0.5263157894736843j),
883
+ expected=(97.7889554372208-18.999754543400016j),
884
+ rtol=5e-13,
885
+ ),
886
+ ),
887
+ ]
888
+ )
889
+ def test_region2(self, hyp2f1_test_case):
890
+ """|z| < 1 and real(z) < 0."""
891
+ a, b, c, z, expected, rtol = hyp2f1_test_case
892
+ assert abs(z) < 1 and z.real < 0 # Tests the test
893
+ assert_allclose(hyp2f1(a, b, c, z), expected, rtol=rtol)
894
+
895
+ @pytest.mark.parametrize(
896
+ "hyp2f1_test_case",
897
+ [
898
+ pytest.param(
899
+ Hyp2f1TestCase(
900
+ a=16.25,
901
+ b=4.25,
902
+ c=2.5,
903
+ z=(0.4931034482758623-0.7965517241379311j),
904
+ expected=(38.41207903409937-30.510151276075792j),
905
+ rtol=5e-14,
906
+ ),
907
+ ),
908
+ pytest.param(
909
+ Hyp2f1TestCase(
910
+ a=2.0,
911
+ b=16.087593263474208,
912
+ c=16.088264119063613,
913
+ z=(0.5689655172413794-0.7965517241379311j),
914
+ expected=(-0.6667857912761286-1.0206224321443573j),
915
+ rtol=1e-15,
916
+ ),
917
+ ),
918
+ pytest.param(
919
+ Hyp2f1TestCase(
920
+ a=8.0,
921
+ b=1.0272592605282642,
922
+ c=-7.949900487447654,
923
+ z=(0.4931034482758623-0.7965517241379311j),
924
+ expected=(1679024.1647997478-2748129.775857212j),
925
+ rtol=5e-14,
926
+ ),
927
+ ),
928
+ pytest.param(
929
+ Hyp2f1TestCase(
930
+ a=4.080187217753502,
931
+ b=16.0,
932
+ c=-7.949900487447654,
933
+ z=(0.4931034482758623-0.7965517241379311j),
934
+ expected=(424747226301.16986-1245539049327.2856j),
935
+ rtol=1e-14,
936
+ ),
937
+ ),
938
+ pytest.param(
939
+ Hyp2f1TestCase(
940
+ a=2.02764642551431,
941
+ b=-15.964218273004214,
942
+ c=4.0,
943
+ z=(0.4931034482758623-0.7965517241379311j),
944
+ expected=(-0.0057826199201757595+0.026359861999025885j),
945
+ rtol=5e-06,
946
+ ),
947
+ ),
948
+ pytest.param(
949
+ Hyp2f1TestCase(
950
+ a=2.02764642551431,
951
+ b=-0.9629749245209605,
952
+ c=2.0397202577726152,
953
+ z=(0.5689655172413794-0.7965517241379311j),
954
+ expected=(0.4671901063492606+0.7769632229834897j),
955
+ rtol=5e-14,
956
+ ),
957
+ ),
958
+ pytest.param(
959
+ Hyp2f1TestCase(
960
+ a=2.0,
961
+ b=-3.956227226099288,
962
+ c=-7.949900487447654,
963
+ z=(0.4931034482758623+0.7965517241379312j),
964
+ expected=(0.9422283708145973+1.3476905754773343j),
965
+ rtol=5e-15,
966
+ ),
967
+ ),
968
+ pytest.param(
969
+ Hyp2f1TestCase(
970
+ a=1.0,
971
+ b=-15.980848054962111,
972
+ c=-15.964218273004214,
973
+ z=(0.4931034482758623-0.7965517241379311j),
974
+ expected=(0.4168719497319604-0.9770953555235625j),
975
+ rtol=5e-10,
976
+ ),
977
+ ),
978
+ pytest.param(
979
+ Hyp2f1TestCase(
980
+ a=-0.5,
981
+ b=16.088264119063613,
982
+ c=2.5,
983
+ z=(0.5689655172413794+0.7965517241379312j),
984
+ expected=(1.279096377550619-2.173827694297929j),
985
+ rtol=5e-12,
986
+ ),
987
+ ),
988
+ pytest.param(
989
+ Hyp2f1TestCase(
990
+ a=-1.9214641416286231,
991
+ b=4.0013768449590685,
992
+ c=2.0397202577726152,
993
+ z=(0.4931034482758623+0.7965517241379312j),
994
+ expected=(-2.071520656161738-0.7846098268395909j),
995
+ rtol=5e-14,
996
+ ),
997
+ ),
998
+ pytest.param(
999
+ Hyp2f1TestCase(
1000
+ a=-0.9220024191881196,
1001
+ b=8.0,
1002
+ c=-0.9629749245209605,
1003
+ z=(0.5689655172413794-0.7965517241379311j),
1004
+ expected=(-7.740015495862889+3.386766435696699j),
1005
+ rtol=5e-12,
1006
+ ),
1007
+ ),
1008
+ pytest.param(
1009
+ Hyp2f1TestCase(
1010
+ a=-1.9214641416286231,
1011
+ b=16.088264119063613,
1012
+ c=-7.93846038215665,
1013
+ z=(0.4931034482758623+0.7965517241379312j),
1014
+ expected=(-6318.553685853241-7133.416085202879j),
1015
+ rtol=1e-10,
1016
+ ),
1017
+ ),
1018
+ pytest.param(
1019
+ Hyp2f1TestCase(
1020
+ a=-15.980848054962111,
1021
+ b=-3.9316537064827854,
1022
+ c=16.056809865262608,
1023
+ z=(0.5689655172413794+0.7965517241379312j),
1024
+ expected=(-0.8854577905547399+8.135089099967278j),
1025
+ rtol=5e-14,
1026
+ ),
1027
+ ),
1028
+ pytest.param(
1029
+ Hyp2f1TestCase(
1030
+ a=-1.9214641416286231,
1031
+ b=-0.9629749245209605,
1032
+ c=4.078873014294075,
1033
+ z=(0.4931034482758623+0.7965517241379312j),
1034
+ expected=(1.224291301521487+0.36014711766402485j),
1035
+ rtol=1e-15,
1036
+ ),
1037
+ ),
1038
+ pytest.param(
1039
+ Hyp2f1TestCase(
1040
+ a=-15.75,
1041
+ b=-0.75,
1042
+ c=-1.5,
1043
+ z=(0.4931034482758623+0.7965517241379312j),
1044
+ expected=(-1.5765685855028473-3.9399766961046323j),
1045
+ rtol=1e-3,
1046
+ ),
1047
+ marks=pytest.mark.xfail(
1048
+ reason="Unhandled parameters."
1049
+ )
1050
+ ),
1051
+ pytest.param(
1052
+ Hyp2f1TestCase(
1053
+ a=-15.980848054962111,
1054
+ b=-1.92872979730171,
1055
+ c=-7.93846038215665,
1056
+ z=(0.5689655172413794-0.7965517241379311j),
1057
+ expected=(56.794588688231194+4.556286783533971j),
1058
+ rtol=5e-14,
1059
+ ),
1060
+ ),
1061
+ pytest.param(
1062
+ Hyp2f1TestCase(
1063
+ a=4.5,
1064
+ b=4.5,
1065
+ c=2.050308316530781,
1066
+ z=(0.5689655172413794+0.7965517241379312j),
1067
+ expected=(-4.251456563455306+6.737837111569671j),
1068
+ rtol=5e-14,
1069
+ ),
1070
+ ),
1071
+ pytest.param(
1072
+ Hyp2f1TestCase(
1073
+ a=4.5,
1074
+ b=8.5,
1075
+ c=-1.92872979730171,
1076
+ z=(0.4931034482758623-0.7965517241379311j),
1077
+ expected=(2177143.9156599627-3313617.2748088865j),
1078
+ rtol=5e-14,
1079
+ ),
1080
+ ),
1081
+ pytest.param(
1082
+ Hyp2f1TestCase(
1083
+ a=2.5,
1084
+ b=-1.5,
1085
+ c=4.0013768449590685,
1086
+ z=(0.4931034482758623-0.7965517241379311j),
1087
+ expected=(0.45563554481603946+0.6212000158060831j),
1088
+ rtol=5e-14,
1089
+ ),
1090
+ ),
1091
+ pytest.param(
1092
+ Hyp2f1TestCase(
1093
+ a=8.5,
1094
+ b=-7.5,
1095
+ c=-15.964218273004214,
1096
+ z=(0.4931034482758623+0.7965517241379312j),
1097
+ expected=(61.03201617828073-37.185626416756214j),
1098
+ rtol=5e-14,
1099
+ ),
1100
+ ),
1101
+ pytest.param(
1102
+ Hyp2f1TestCase(
1103
+ a=-15.5,
1104
+ b=16.5,
1105
+ c=4.0013768449590685,
1106
+ z=(0.4931034482758623+0.7965517241379312j),
1107
+ expected=(-33143.425963520735+20790.608514722644j),
1108
+ rtol=1e-14,
1109
+ ),
1110
+ ),
1111
+ pytest.param(
1112
+ Hyp2f1TestCase(
1113
+ a=-0.5,
1114
+ b=4.5,
1115
+ c=-0.9629749245209605,
1116
+ z=(0.5689655172413794+0.7965517241379312j),
1117
+ expected=(30.778600270824423-26.65160354466787j),
1118
+ rtol=5e-13,
1119
+ ),
1120
+ ),
1121
+ pytest.param(
1122
+ Hyp2f1TestCase(
1123
+ a=-0.5,
1124
+ b=-3.5,
1125
+ c=16.088264119063613,
1126
+ z=(0.5689655172413794-0.7965517241379311j),
1127
+ expected=(1.0629792615560487-0.08308454486044772j),
1128
+ rtol=1e-15,
1129
+ ),
1130
+ ),
1131
+ pytest.param(
1132
+ Hyp2f1TestCase(
1133
+ a=-3.5,
1134
+ b=-7.5,
1135
+ c=-0.9629749245209605,
1136
+ z=(0.4931034482758623-0.7965517241379311j),
1137
+ expected=(17431.571802591767+3553.7129767034507j),
1138
+ rtol=5e-14,
1139
+ ),
1140
+ ),
1141
+ pytest.param(
1142
+ Hyp2f1TestCase(
1143
+ a=2.25,
1144
+ b=8.25,
1145
+ c=16.5,
1146
+ z=(0.11379310344827598+0.9482758620689657j),
1147
+ expected=(0.4468600750211926+0.7313214934036885j),
1148
+ rtol=1e-3,
1149
+ ),
1150
+ marks=pytest.mark.xfail(
1151
+ reason="Unhandled parameters."
1152
+ )
1153
+ ),
1154
+ pytest.param(
1155
+ Hyp2f1TestCase(
1156
+ a=8.25,
1157
+ b=16.25,
1158
+ c=4.5,
1159
+ z=(0.3413793103448277+0.8724137931034486j),
1160
+ expected=(-3.905704438293991+3.693347860329299j),
1161
+ rtol=5e-14,
1162
+ ),
1163
+ ),
1164
+ pytest.param(
1165
+ Hyp2f1TestCase(
1166
+ a=4.25,
1167
+ b=4.25,
1168
+ c=-0.5,
1169
+ z=(0.11379310344827598-0.9482758620689655j),
1170
+ expected=(-40.31777941834244-89.89852492432011j),
1171
+ rtol=5e-15,
1172
+ ),
1173
+ ),
1174
+ pytest.param(
1175
+ Hyp2f1TestCase(
1176
+ a=1.0272592605282642,
1177
+ b=8.0,
1178
+ c=-15.964218273004214,
1179
+ z=(0.11379310344827598-0.9482758620689655j),
1180
+ expected=(52584.347773055284-109197.86244309516j),
1181
+ rtol=5e-14,
1182
+ ),
1183
+ ),
1184
+ pytest.param(
1185
+ Hyp2f1TestCase(
1186
+ a=8.095813935368371,
1187
+ b=-15.964218273004214,
1188
+ c=16.056809865262608,
1189
+ z=(0.03793103448275881+0.9482758620689657j),
1190
+ expected=(-1.187733570412592-1.5147865053584582j),
1191
+ rtol=5e-10,
1192
+ ),
1193
+ ),
1194
+ pytest.param(
1195
+ Hyp2f1TestCase(
1196
+ a=4.080187217753502,
1197
+ b=-3.9316537064827854,
1198
+ c=1.0651378143226575,
1199
+ z=(0.26551724137931054+0.9482758620689657j),
1200
+ expected=(13.077494677898947+35.071599628224966j),
1201
+ rtol=5e-13,
1202
+ ),
1203
+ ),
1204
+ pytest.param(
1205
+ Hyp2f1TestCase(
1206
+ a=4.080187217753502,
1207
+ b=-3.5,
1208
+ c=-3.5,
1209
+ z=(0.26551724137931054+0.8724137931034486j),
1210
+ expected=(-0.5359656237994614-0.2344483936591811j),
1211
+ rtol=5e-15,
1212
+ ),
1213
+ ),
1214
+ pytest.param(
1215
+ Hyp2f1TestCase(
1216
+ a=4.25,
1217
+ b=-3.75,
1218
+ c=-1.5,
1219
+ z=(0.26551724137931054+0.9482758620689657j),
1220
+ expected=(1204.8114871663133+64.41022826840198j),
1221
+ rtol=5e-13,
1222
+ ),
1223
+ ),
1224
+ pytest.param(
1225
+ Hyp2f1TestCase(
1226
+ a=-1.9214641416286231,
1227
+ b=16.0,
1228
+ c=4.0013768449590685,
1229
+ z=(0.03793103448275881-0.9482758620689655j),
1230
+ expected=(-9.85268872413994+7.011107558429154j),
1231
+ rtol=5e-15,
1232
+ ),
1233
+ ),
1234
+ pytest.param(
1235
+ Hyp2f1TestCase(
1236
+ a=-7.937789122896016,
1237
+ b=16.0,
1238
+ c=4.0013768449590685,
1239
+ z=(0.3413793103448277-0.8724137931034484j),
1240
+ expected=(528.5522951158454-1412.21630264791j),
1241
+ rtol=1e-15,
1242
+ ),
1243
+ ),
1244
+ pytest.param(
1245
+ Hyp2f1TestCase(
1246
+ a=-15.5,
1247
+ b=1.0561196186065624,
1248
+ c=-7.5,
1249
+ z=(0.4172413793103451+0.8724137931034486j),
1250
+ expected=(133306.45260685298+256510.7045225382j),
1251
+ rtol=5e-15,
1252
+ ),
1253
+ ),
1254
+ pytest.param(
1255
+ Hyp2f1TestCase(
1256
+ a=-7.937789122896016,
1257
+ b=8.077282662161238,
1258
+ c=-15.963511401609862,
1259
+ z=(0.3413793103448277-0.8724137931034484j),
1260
+ expected=(-0.998555715276967+2.774198742229889j),
1261
+ rtol=5e-11,
1262
+ ),
1263
+ ),
1264
+ pytest.param(
1265
+ Hyp2f1TestCase(
1266
+ a=-7.75,
1267
+ b=-0.75,
1268
+ c=1.5,
1269
+ z=(0.11379310344827598-0.9482758620689655j),
1270
+ expected=(2.072445019723025-2.9793504811373515j),
1271
+ rtol=5e-14,
1272
+ ),
1273
+ ),
1274
+ pytest.param(
1275
+ Hyp2f1TestCase(
1276
+ a=-15.5,
1277
+ b=-1.92872979730171,
1278
+ c=1.5,
1279
+ z=(0.11379310344827598-0.9482758620689655j),
1280
+ expected=(-41.87581944176649-32.52980303527139j),
1281
+ rtol=5e-13,
1282
+ ),
1283
+ ),
1284
+ pytest.param(
1285
+ Hyp2f1TestCase(
1286
+ a=-3.75,
1287
+ b=-15.75,
1288
+ c=-0.5,
1289
+ z=(0.11379310344827598-0.9482758620689655j),
1290
+ expected=(-3729.6214864209774-30627.510509112635j),
1291
+ rtol=5e-15,
1292
+ ),
1293
+ ),
1294
+ pytest.param(
1295
+ Hyp2f1TestCase(
1296
+ a=-3.956227226099288,
1297
+ b=-15.964218273004214,
1298
+ c=-0.906685989801748,
1299
+ z=(0.03793103448275881+0.9482758620689657j),
1300
+ expected=(-131615.07820609974+145596.13384245415j),
1301
+ rtol=5e-15,
1302
+ ),
1303
+ ),
1304
+ pytest.param(
1305
+ Hyp2f1TestCase(
1306
+ a=1.5,
1307
+ b=16.5,
1308
+ c=16.088264119063613,
1309
+ z=(0.26551724137931054+0.8724137931034486j),
1310
+ expected=(0.18981844071070744+0.7855036242583742j),
1311
+ rtol=1e-15,
1312
+ ),
1313
+ ),
1314
+ pytest.param(
1315
+ Hyp2f1TestCase(
1316
+ a=16.5,
1317
+ b=8.5,
1318
+ c=-3.9316537064827854,
1319
+ z=(0.11379310344827598-0.9482758620689655j),
1320
+ expected=(110224529.2376068+128287212.04290268j),
1321
+ rtol=5e-13,
1322
+ ),
1323
+ ),
1324
+ pytest.param(
1325
+ Hyp2f1TestCase(
1326
+ a=2.5,
1327
+ b=-7.5,
1328
+ c=4.0013768449590685,
1329
+ z=(0.3413793103448277-0.8724137931034484j),
1330
+ expected=(0.2722302180888523-0.21790187837266162j),
1331
+ rtol=1e-12,
1332
+ ),
1333
+ ),
1334
+ pytest.param(
1335
+ Hyp2f1TestCase(
1336
+ a=8.5,
1337
+ b=-7.5,
1338
+ c=-15.964218273004214,
1339
+ z=(0.11379310344827598-0.9482758620689655j),
1340
+ expected=(-2.8252338010989035+2.430661949756161j),
1341
+ rtol=5e-14,
1342
+ ),
1343
+ ),
1344
+ pytest.param(
1345
+ Hyp2f1TestCase(
1346
+ a=-3.5,
1347
+ b=16.5,
1348
+ c=4.0013768449590685,
1349
+ z=(0.03793103448275881+0.9482758620689657j),
1350
+ expected=(-20.604894257647945+74.5109432558078j),
1351
+ rtol=5e-15,
1352
+ ),
1353
+ ),
1354
+ pytest.param(
1355
+ Hyp2f1TestCase(
1356
+ a=-7.5,
1357
+ b=8.5,
1358
+ c=-0.9629749245209605,
1359
+ z=(0.3413793103448277+0.8724137931034486j),
1360
+ expected=(-2764422.521269463-3965966.9965808876j),
1361
+ rtol=1e-15,
1362
+ ),
1363
+ ),
1364
+ pytest.param(
1365
+ Hyp2f1TestCase(
1366
+ a=-1.5,
1367
+ b=-0.5,
1368
+ c=1.0561196186065624,
1369
+ z=(0.26551724137931054+0.9482758620689657j),
1370
+ expected=(1.2262338560994905+0.6545051266925549j),
1371
+ rtol=1e-15,
1372
+ ),
1373
+ ),
1374
+ pytest.param(
1375
+ Hyp2f1TestCase(
1376
+ a=-0.5,
1377
+ b=-15.5,
1378
+ c=-7.949900487447654,
1379
+ z=(0.4172413793103451-0.8724137931034484j),
1380
+ expected=(-2258.1590330318213+8860.193389158803j),
1381
+ rtol=1.4e-10,
1382
+ ),
1383
+ ),
1384
+ ]
1385
+ )
1386
+ def test_region4(self, hyp2f1_test_case):
1387
+ """0.9 <= |z| <= 1 and |1 - z| >= 1.
1388
+
1389
+ This region is unhandled by of the standard transformations and
1390
+ needs special care.
1391
+ """
1392
+ a, b, c, z, expected, rtol = hyp2f1_test_case
1393
+ assert 0.9 <= abs(z) <= 1 and abs(1 - z) >= 0.9 # Tests the test
1394
+ assert_allclose(hyp2f1(a, b, c, z), expected, rtol=rtol)
1395
+
1396
+ @pytest.mark.parametrize(
1397
+ "hyp2f1_test_case",
1398
+ [
1399
+ pytest.param(
1400
+ Hyp2f1TestCase(
1401
+ a=4.5,
1402
+ b=16.088264119063613,
1403
+ c=8.5,
1404
+ z=(0.6448275862068968+0.8724137931034486j),
1405
+ expected=(0.018601324701770394-0.07618420586062377j),
1406
+ rtol=5e-08,
1407
+ ),
1408
+ ),
1409
+ pytest.param(
1410
+ Hyp2f1TestCase(
1411
+ a=8.25,
1412
+ b=4.25,
1413
+ c=4.5,
1414
+ z=(0.6448275862068968-0.8724137931034484j),
1415
+ expected=(-1.391549471425551-0.118036604903893j),
1416
+ rtol=5e-15,
1417
+ ),
1418
+ ),
1419
+ pytest.param(
1420
+ Hyp2f1TestCase(
1421
+ a=2.02764642551431,
1422
+ b=2.050308316530781,
1423
+ c=-1.9631175993998025,
1424
+ z=(0.6448275862068968+0.8724137931034486j),
1425
+ expected=(-2309.178768155151-1932.7247727595172j),
1426
+ rtol=5e-15,
1427
+ ),
1428
+ ),
1429
+ pytest.param(
1430
+ Hyp2f1TestCase(
1431
+ a=16.087593263474208,
1432
+ b=1.0,
1433
+ c=-15.964218273004214,
1434
+ z=(0.6448275862068968+0.8724137931034486j),
1435
+ expected=(85592537010.05054-8061416766688.324j),
1436
+ rtol=2e-14,
1437
+ ),
1438
+ ),
1439
+ pytest.param(
1440
+ Hyp2f1TestCase(
1441
+ a=8.095813935368371,
1442
+ b=-0.5,
1443
+ c=1.5,
1444
+ z=(0.6448275862068968+0.8724137931034486j),
1445
+ expected=(1.2334498208515172-2.1639498536219732j),
1446
+ rtol=5e-11,
1447
+ ),
1448
+ ),
1449
+ pytest.param(
1450
+ Hyp2f1TestCase(
1451
+ a=16.087593263474208,
1452
+ b=-15.964218273004214,
1453
+ c=4.0,
1454
+ z=(0.6448275862068968+0.8724137931034486j),
1455
+ expected=(102266.35398605966-44976.97828737755j),
1456
+ rtol=1e-3,
1457
+ ),
1458
+ marks=pytest.mark.xfail(
1459
+ reason="Unhandled parameters."
1460
+ )
1461
+ ),
1462
+ pytest.param(
1463
+ Hyp2f1TestCase(
1464
+ a=4.0,
1465
+ b=-3.956227226099288,
1466
+ c=-15.964218273004214,
1467
+ z=(0.6448275862068968-0.8724137931034484j),
1468
+ expected=(-2.9590030930007236-4.190770764773225j),
1469
+ rtol=5e-13,
1470
+ ),
1471
+ ),
1472
+ pytest.param(
1473
+ Hyp2f1TestCase(
1474
+ a=4.080187217753502,
1475
+ b=-15.5,
1476
+ c=-7.5,
1477
+ z=(0.5689655172413794-0.8724137931034484j),
1478
+ expected=(-112554838.92074208+174941462.9202412j),
1479
+ rtol=5e-05,
1480
+ ),
1481
+ ),
1482
+ pytest.param(
1483
+ Hyp2f1TestCase(
1484
+ a=-15.980848054962111,
1485
+ b=2.050308316530781,
1486
+ c=1.0,
1487
+ z=(0.6448275862068968-0.8724137931034484j),
1488
+ expected=(3.7519882374080145+7.360753798667486j),
1489
+ rtol=5e-13,
1490
+ ),
1491
+ ),
1492
+ pytest.param(
1493
+ Hyp2f1TestCase(
1494
+ a=-7.937789122896016,
1495
+ b=2.050308316530781,
1496
+ c=4.0,
1497
+ z=(0.6448275862068968-0.8724137931034484j),
1498
+ expected=(0.000181132943964693+0.07742903103815582j),
1499
+ rtol=5e-14,
1500
+ ),
1501
+ ),
1502
+ pytest.param(
1503
+ Hyp2f1TestCase(
1504
+ a=-7.937789122896016,
1505
+ b=4.0013768449590685,
1506
+ c=-1.9631175993998025,
1507
+ z=(0.5689655172413794+0.8724137931034486j),
1508
+ expected=(386338.760913596-386166.51762171905j),
1509
+ rtol=5e-15,
1510
+ ),
1511
+ ),
1512
+ pytest.param(
1513
+ Hyp2f1TestCase(
1514
+ a=-15.980848054962111,
1515
+ b=8.0,
1516
+ c=-1.92872979730171,
1517
+ z=(0.6448275862068968+0.8724137931034486j),
1518
+ expected=(1348667126.3444858-2375132427.158893j),
1519
+ rtol=5e-14,
1520
+ ),
1521
+ ),
1522
+ pytest.param(
1523
+ Hyp2f1TestCase(
1524
+ a=-3.5,
1525
+ b=-0.9629749245209605,
1526
+ c=4.5,
1527
+ z=(0.5689655172413794+0.8724137931034486j),
1528
+ expected=(1.428353429538678+0.6472718120804372j),
1529
+ rtol=5e-15,
1530
+ ),
1531
+ ),
1532
+ pytest.param(
1533
+ Hyp2f1TestCase(
1534
+ a=-7.937789122896016,
1535
+ b=-0.9629749245209605,
1536
+ c=2.0397202577726152,
1537
+ z=(0.5689655172413794-0.8724137931034484j),
1538
+ expected=(3.1439267526119643-3.145305240375117j),
1539
+ rtol=5e-14,
1540
+ ),
1541
+ ),
1542
+ pytest.param(
1543
+ Hyp2f1TestCase(
1544
+ a=-1.9214641416286231,
1545
+ b=-15.964218273004214,
1546
+ c=-7.93846038215665,
1547
+ z=(0.6448275862068968-0.8724137931034484j),
1548
+ expected=(75.27467675681773+144.0946946292215j),
1549
+ rtol=1e-07,
1550
+ ),
1551
+ ),
1552
+ pytest.param(
1553
+ Hyp2f1TestCase(
1554
+ a=-3.75,
1555
+ b=-7.75,
1556
+ c=-7.5,
1557
+ z=(0.5689655172413794+0.8724137931034486j),
1558
+ expected=(-0.3699450626264222+0.8732812475910993j),
1559
+ rtol=1e-15,
1560
+ ),
1561
+ ),
1562
+ pytest.param(
1563
+ Hyp2f1TestCase(
1564
+ a=1.5,
1565
+ b=16.5,
1566
+ c=1.0561196186065624,
1567
+ z=(0.5689655172413794-0.8724137931034484j),
1568
+ expected=(5.5361025821300665-2.4709693474656285j),
1569
+ rtol=5e-09,
1570
+ ),
1571
+ ),
1572
+ pytest.param(
1573
+ Hyp2f1TestCase(
1574
+ a=1.5,
1575
+ b=8.5,
1576
+ c=-3.9316537064827854,
1577
+ z=(0.6448275862068968-0.8724137931034484j),
1578
+ expected=(-782805.6699207705-537192.581278909j),
1579
+ rtol=5e-14,
1580
+ ),
1581
+ ),
1582
+ pytest.param(
1583
+ Hyp2f1TestCase(
1584
+ a=2.5,
1585
+ b=-15.5,
1586
+ c=1.0561196186065624,
1587
+ z=(0.6448275862068968+0.8724137931034486j),
1588
+ expected=(12.345113400639693-14.993248992902007j),
1589
+ rtol=0.0005,
1590
+ ),
1591
+ ),
1592
+ pytest.param(
1593
+ Hyp2f1TestCase(
1594
+ a=1.5,
1595
+ b=-0.5,
1596
+ c=-15.964218273004214,
1597
+ z=(0.6448275862068968+0.8724137931034486j),
1598
+ expected=(23.698109392667842+97.15002033534108j),
1599
+ rtol=5e-14,
1600
+ ),
1601
+ ),
1602
+ pytest.param(
1603
+ Hyp2f1TestCase(
1604
+ a=-7.5,
1605
+ b=16.5,
1606
+ c=4.0013768449590685,
1607
+ z=(0.6448275862068968-0.8724137931034484j),
1608
+ expected=(1115.2978631811834+915.9212658718577j),
1609
+ rtol=5e-15,
1610
+ ),
1611
+ ),
1612
+ pytest.param(
1613
+ Hyp2f1TestCase(
1614
+ a=-15.5,
1615
+ b=16.5,
1616
+ c=-0.9629749245209605,
1617
+ z=(0.6448275862068968+0.8724137931034486j),
1618
+ expected=(642077722221.6489+535274495398.21027j),
1619
+ rtol=5e-15,
1620
+ ),
1621
+ ),
1622
+ pytest.param(
1623
+ Hyp2f1TestCase(
1624
+ a=-7.5,
1625
+ b=-3.5,
1626
+ c=4.0013768449590685,
1627
+ z=(0.5689655172413794+0.8724137931034486j),
1628
+ expected=(-5.689219222945697+16.877463062787143j),
1629
+ rtol=5e-15,
1630
+ ),
1631
+ ),
1632
+ pytest.param(
1633
+ Hyp2f1TestCase(
1634
+ a=-15.5,
1635
+ b=-1.5,
1636
+ c=-0.9629749245209605,
1637
+ z=(0.5689655172413794-0.8724137931034484j),
1638
+ expected=(-44.32070290703576+1026.9127058617403j),
1639
+ rtol=5e-14,
1640
+ ),
1641
+ ),
1642
+ pytest.param(
1643
+ Hyp2f1TestCase(
1644
+ a=16.25,
1645
+ b=2.25,
1646
+ c=4.5,
1647
+ z=(0.11379310344827598-1.024137931034483j),
1648
+ expected=(-0.021965227124574663+0.009908300237809064j),
1649
+ rtol=1e-3,
1650
+ ),
1651
+ marks=pytest.mark.xfail(
1652
+ reason="Unhandled parameters."
1653
+ )
1654
+ ),
1655
+ pytest.param(
1656
+ Hyp2f1TestCase(
1657
+ a=2.02764642551431,
1658
+ b=1.5,
1659
+ c=16.5,
1660
+ z=(0.26551724137931054+1.024137931034483j),
1661
+ expected=(1.0046072901244183+0.19945500134119992j),
1662
+ rtol=5e-14,
1663
+ ),
1664
+ ),
1665
+ pytest.param(
1666
+ Hyp2f1TestCase(
1667
+ a=16.087593263474208,
1668
+ b=1.0,
1669
+ c=-3.9316537064827854,
1670
+ z=(0.3413793103448277+0.9482758620689657j),
1671
+ expected=(21022.30133421465+49175.98317370489j),
1672
+ rtol=5e-13,
1673
+ ),
1674
+ ),
1675
+ pytest.param(
1676
+ Hyp2f1TestCase(
1677
+ a=4.080187217753502,
1678
+ b=16.088264119063613,
1679
+ c=-1.9631175993998025,
1680
+ z=(0.4172413793103451-0.9482758620689655j),
1681
+ expected=(-7024239.358547302+2481375.02681063j),
1682
+ rtol=5e-14,
1683
+ ),
1684
+ ),
1685
+ pytest.param(
1686
+ Hyp2f1TestCase(
1687
+ a=16.25,
1688
+ b=-15.75,
1689
+ c=1.5,
1690
+ z=(0.18965517241379315+1.024137931034483j),
1691
+ expected=(92371704.94848-403546832.548352j),
1692
+ rtol=5e-06,
1693
+ ),
1694
+ ),
1695
+ pytest.param(
1696
+ Hyp2f1TestCase(
1697
+ a=8.5,
1698
+ b=-7.949900487447654,
1699
+ c=8.5,
1700
+ z=(0.26551724137931054-1.024137931034483j),
1701
+ expected=(1.9335109845308265+5.986542524829654j),
1702
+ rtol=5e-10,
1703
+ ),
1704
+ ),
1705
+ pytest.param(
1706
+ Hyp2f1TestCase(
1707
+ a=8.095813935368371,
1708
+ b=-1.92872979730171,
1709
+ c=-7.93846038215665,
1710
+ z=(0.4931034482758623+0.8724137931034486j),
1711
+ expected=(-122.52639696039328-59.72428067512221j),
1712
+ rtol=5e-14,
1713
+ ),
1714
+ ),
1715
+ pytest.param(
1716
+ Hyp2f1TestCase(
1717
+ a=16.25,
1718
+ b=-1.75,
1719
+ c=-1.5,
1720
+ z=(0.4931034482758623+0.9482758620689657j),
1721
+ expected=(-90.40642053579428+50.50649180047921j),
1722
+ rtol=5e-08,
1723
+ ),
1724
+ ),
1725
+ pytest.param(
1726
+ Hyp2f1TestCase(
1727
+ a=-3.5,
1728
+ b=8.077282662161238,
1729
+ c=16.5,
1730
+ z=(0.4931034482758623+0.9482758620689657j),
1731
+ expected=(-0.2155745818150323-0.564628986876639j),
1732
+ rtol=5e-15,
1733
+ ),
1734
+ ),
1735
+ pytest.param(
1736
+ Hyp2f1TestCase(
1737
+ a=-0.9220024191881196,
1738
+ b=1.0561196186065624,
1739
+ c=8.031683612216888,
1740
+ z=(0.4172413793103451-0.9482758620689655j),
1741
+ expected=(0.9503140488280465+0.11574960074292677j),
1742
+ rtol=5e-15,
1743
+ ),
1744
+ ),
1745
+ pytest.param(
1746
+ Hyp2f1TestCase(
1747
+ a=-0.75,
1748
+ b=2.25,
1749
+ c=-15.5,
1750
+ z=(0.4172413793103451+0.9482758620689657j),
1751
+ expected=(0.9285862488442175+0.8203699266719692j),
1752
+ rtol=5e-13,
1753
+ ),
1754
+ ),
1755
+ pytest.param(
1756
+ Hyp2f1TestCase(
1757
+ a=-7.75,
1758
+ b=4.25,
1759
+ c=-15.5,
1760
+ z=(0.3413793103448277-0.9482758620689655j),
1761
+ expected=(-1.0509834850116921-1.1145522325486075j),
1762
+ rtol=1e-14,
1763
+ ),
1764
+ ),
1765
+ pytest.param(
1766
+ Hyp2f1TestCase(
1767
+ a=-7.937789122896016,
1768
+ b=-0.9629749245209605,
1769
+ c=2.0397202577726152,
1770
+ z=(0.4931034482758623-0.9482758620689655j),
1771
+ expected=(2.88119116536769-3.4249933450696806j),
1772
+ rtol=5e-15,
1773
+ ),
1774
+ ),
1775
+ pytest.param(
1776
+ Hyp2f1TestCase(
1777
+ a=-15.5,
1778
+ b=-15.964218273004214,
1779
+ c=16.5,
1780
+ z=(0.18965517241379315+1.024137931034483j),
1781
+ expected=(199.65868451496038+347.79384207302877j),
1782
+ rtol=1e-13,
1783
+ ),
1784
+ ),
1785
+ pytest.param(
1786
+ Hyp2f1TestCase(
1787
+ a=-15.75,
1788
+ b=-15.75,
1789
+ c=-3.5,
1790
+ z=(0.4931034482758623-0.8724137931034484j),
1791
+ expected=(-208138312553.07013+58631611809.026955j),
1792
+ rtol=5e-14,
1793
+ ),
1794
+ ),
1795
+ pytest.param(
1796
+ Hyp2f1TestCase(
1797
+ a=-7.937789122896016,
1798
+ b=-15.5,
1799
+ c=-7.5,
1800
+ z=(0.3413793103448277+0.9482758620689657j),
1801
+ expected=(-23032.90519856288-18256.94050457296j),
1802
+ rtol=5e-15,
1803
+ ),
1804
+ ),
1805
+ pytest.param(
1806
+ Hyp2f1TestCase(
1807
+ a=4.5,
1808
+ b=1.5,
1809
+ c=1.0561196186065624,
1810
+ z=(0.4931034482758623-0.8724137931034484j),
1811
+ expected=(1.507342459587056+1.2332023580148403j),
1812
+ rtol=1e-15,
1813
+ ),
1814
+ ),
1815
+ pytest.param(
1816
+ Hyp2f1TestCase(
1817
+ a=2.5,
1818
+ b=4.5,
1819
+ c=-3.9316537064827854,
1820
+ z=(0.4172413793103451+0.9482758620689657j),
1821
+ expected=(7044.766127108853-40210.365567285575j),
1822
+ rtol=5e-14,
1823
+ ),
1824
+ ),
1825
+ pytest.param(
1826
+ Hyp2f1TestCase(
1827
+ a=1.5,
1828
+ b=-1.5,
1829
+ c=1.0561196186065624,
1830
+ z=(0.03793103448275881+1.024137931034483j),
1831
+ expected=(0.2725347741628333-2.247314875514784j),
1832
+ rtol=1e-15,
1833
+ ),
1834
+ ),
1835
+ pytest.param(
1836
+ Hyp2f1TestCase(
1837
+ a=4.5,
1838
+ b=-1.5,
1839
+ c=-7.949900487447654,
1840
+ z=(0.26551724137931054+1.024137931034483j),
1841
+ expected=(-11.250200011017546+12.597393659160472j),
1842
+ rtol=5e-14,
1843
+ ),
1844
+ ),
1845
+ pytest.param(
1846
+ Hyp2f1TestCase(
1847
+ a=-7.5,
1848
+ b=8.5,
1849
+ c=16.088264119063613,
1850
+ z=(0.26551724137931054+1.024137931034483j),
1851
+ expected=(-0.18515160890991517+0.7959014164484782j),
1852
+ rtol=1e-15,
1853
+ ),
1854
+ ),
1855
+ pytest.param(
1856
+ Hyp2f1TestCase(
1857
+ a=-7.5,
1858
+ b=16.5,
1859
+ c=-3.9316537064827854,
1860
+ z=(0.3413793103448277-1.024137931034483j),
1861
+ expected=(998246378.8556538+1112032928.103645j),
1862
+ rtol=5e-14,
1863
+ ),
1864
+ ),
1865
+ pytest.param(
1866
+ Hyp2f1TestCase(
1867
+ a=-1.5,
1868
+ b=-3.5,
1869
+ c=2.050308316530781,
1870
+ z=(0.03793103448275881+1.024137931034483j),
1871
+ expected=(0.5527670397711952+2.697662715303637j),
1872
+ rtol=1.2e-15, # rtol bumped from 1e-15 in gh18414
1873
+ ),
1874
+ ),
1875
+ pytest.param(
1876
+ Hyp2f1TestCase(
1877
+ a=-15.5,
1878
+ b=-1.5,
1879
+ c=-0.9629749245209605,
1880
+ z=(0.4931034482758623-0.8724137931034484j),
1881
+ expected=(55.396931662136886+968.467463806326j),
1882
+ rtol=5e-14,
1883
+ ),
1884
+ ),
1885
+ ]
1886
+ )
1887
+ def test_region5(self, hyp2f1_test_case):
1888
+ """1 < |z| < 1.1 and |1 - z| >= 0.9 and real(z) >= 0"""
1889
+ a, b, c, z, expected, rtol = hyp2f1_test_case
1890
+ assert 1 < abs(z) < 1.1 and abs(1 - z) >= 0.9 and z.real >= 0
1891
+ assert_allclose(hyp2f1(a, b, c, z), expected, rtol=rtol)
1892
+
1893
+ @pytest.mark.parametrize(
1894
+ "hyp2f1_test_case",
1895
+ [
1896
+ pytest.param(
1897
+ Hyp2f1TestCase(
1898
+ a=8.095813935368371,
1899
+ b=4.0013768449590685,
1900
+ c=4.078873014294075,
1901
+ z=(-0.9473684210526316+0.5263157894736841j),
1902
+ expected=(-0.0018093573941378783+0.003481887377423739j),
1903
+ rtol=5e-15,
1904
+ ),
1905
+ ),
1906
+ pytest.param(
1907
+ Hyp2f1TestCase(
1908
+ a=16.087593263474208,
1909
+ b=2.050308316530781,
1910
+ c=1.0651378143226575,
1911
+ z=(-0.736842105263158-0.736842105263158j),
1912
+ expected=(-0.00023401243818780545-1.7983496305603562e-05j),
1913
+ rtol=1e-15,
1914
+ ),
1915
+ ),
1916
+ pytest.param(
1917
+ Hyp2f1TestCase(
1918
+ a=1.0272592605282642,
1919
+ b=8.077282662161238,
1920
+ c=4.078873014294075,
1921
+ z=(-0.5263157894736843-0.9473684210526316j),
1922
+ expected=(0.22359773002226846-0.24092487123993353j),
1923
+ rtol=1e-15,
1924
+ ),
1925
+ ),
1926
+ pytest.param(
1927
+ Hyp2f1TestCase(
1928
+ a=1.0272592605282642,
1929
+ b=2.050308316530781,
1930
+ c=-15.963511401609862,
1931
+ z=(-0.9473684210526316-0.5263157894736843j),
1932
+ expected=(1.191573745740011+0.14347394589721466j),
1933
+ rtol=5e-14,
1934
+ ),
1935
+ ),
1936
+ pytest.param(
1937
+ Hyp2f1TestCase(
1938
+ a=4.080187217753502,
1939
+ b=4.0013768449590685,
1940
+ c=-15.963511401609862,
1941
+ z=(-0.9473684210526316-0.5263157894736843j),
1942
+ expected=(31.822620756901784-66.09094396747611j),
1943
+ rtol=5e-14,
1944
+ ),
1945
+ ),
1946
+ pytest.param(
1947
+ Hyp2f1TestCase(
1948
+ a=4.080187217753502,
1949
+ b=8.077282662161238,
1950
+ c=-7.93846038215665,
1951
+ z=(-0.9473684210526316+0.5263157894736841j),
1952
+ expected=(207.16750179245952+34.80478274924269j),
1953
+ rtol=5e-12,
1954
+ ),
1955
+ ),
1956
+ pytest.param(
1957
+ Hyp2f1TestCase(
1958
+ a=8.095813935368371,
1959
+ b=-7.949900487447654,
1960
+ c=8.031683612216888,
1961
+ z=(-0.736842105263158+0.7368421052631575j),
1962
+ expected=(-159.62429364277145+9.154224290644898j),
1963
+ rtol=5e-14,
1964
+ ),
1965
+ ),
1966
+ pytest.param(
1967
+ Hyp2f1TestCase(
1968
+ a=1.0272592605282642,
1969
+ b=-1.92872979730171,
1970
+ c=16.056809865262608,
1971
+ z=(-0.9473684210526316+0.5263157894736841j),
1972
+ expected=(1.121122351247184-0.07170260470126685j),
1973
+ rtol=5e-15,
1974
+ ),
1975
+ ),
1976
+ pytest.param(
1977
+ Hyp2f1TestCase(
1978
+ a=16.087593263474208,
1979
+ b=-0.9629749245209605,
1980
+ c=16.056809865262608,
1981
+ z=(-0.9473684210526316+0.5263157894736841j),
1982
+ expected=(1.9040596681316053-0.4951799449960107j),
1983
+ rtol=5e-14,
1984
+ ),
1985
+ ),
1986
+ pytest.param(
1987
+ Hyp2f1TestCase(
1988
+ a=1.0272592605282642,
1989
+ b=-1.92872979730171,
1990
+ c=-0.906685989801748,
1991
+ z=(-0.9473684210526316-0.5263157894736843j),
1992
+ expected=(-14.496623497780739-21.897524523299875j),
1993
+ rtol=5e-14,
1994
+ ),
1995
+ ),
1996
+ pytest.param(
1997
+ Hyp2f1TestCase(
1998
+ a=4.080187217753502,
1999
+ b=-3.9316537064827854,
2000
+ c=-3.9924618758357022,
2001
+ z=(-0.5263157894736843-0.9473684210526316j),
2002
+ expected=(36.33473466026878+253.88728442029577j),
2003
+ rtol=5e-14,
2004
+ ),
2005
+ ),
2006
+ pytest.param(
2007
+ Hyp2f1TestCase(
2008
+ a=1.0272592605282642,
2009
+ b=-15.964218273004214,
2010
+ c=-0.906685989801748,
2011
+ z=(-0.9473684210526316+0.5263157894736841j),
2012
+ expected=(1505052.5653144997-50820766.81043443j),
2013
+ rtol=1e-14,
2014
+ ),
2015
+ ),
2016
+ pytest.param(
2017
+ Hyp2f1TestCase(
2018
+ a=-3.956227226099288,
2019
+ b=4.0013768449590685,
2020
+ c=1.0651378143226575,
2021
+ z=(-0.5263157894736843+0.9473684210526314j),
2022
+ expected=(-127.79407519260877-28.69899444941112j),
2023
+ rtol=5e-15,
2024
+ ),
2025
+ ),
2026
+ pytest.param(
2027
+ Hyp2f1TestCase(
2028
+ a=-1.9214641416286231,
2029
+ b=8.077282662161238,
2030
+ c=16.056809865262608,
2031
+ z=(-0.9473684210526316-0.5263157894736843j),
2032
+ expected=(2.0623331933754976+0.741234463565458j),
2033
+ rtol=5e-15,
2034
+ ),
2035
+ ),
2036
+ pytest.param(
2037
+ Hyp2f1TestCase(
2038
+ a=-3.956227226099288,
2039
+ b=8.077282662161238,
2040
+ c=2.0397202577726152,
2041
+ z=(-0.9473684210526316+0.5263157894736841j),
2042
+ expected=(30.729193458862525-292.5700835046965j),
2043
+ rtol=1e-15,
2044
+ ),
2045
+ ),
2046
+ pytest.param(
2047
+ Hyp2f1TestCase(
2048
+ a=-1.9214641416286231,
2049
+ b=1.0561196186065624,
2050
+ c=-1.9631175993998025,
2051
+ z=(-0.5263157894736843-0.9473684210526316j),
2052
+ expected=(1.1285917906203495-0.735264575450189j),
2053
+ rtol=5e-15,
2054
+ ),
2055
+ ),
2056
+ pytest.param(
2057
+ Hyp2f1TestCase(
2058
+ a=-0.9220024191881196,
2059
+ b=1.0561196186065624,
2060
+ c=-3.9924618758357022,
2061
+ z=(-0.736842105263158+0.7368421052631575j),
2062
+ expected=(0.6356474446678052-0.02429663008952248j),
2063
+ rtol=5e-14,
2064
+ ),
2065
+ ),
2066
+ pytest.param(
2067
+ Hyp2f1TestCase(
2068
+ a=-1.9214641416286231,
2069
+ b=16.088264119063613,
2070
+ c=-7.93846038215665,
2071
+ z=(-0.736842105263158+0.7368421052631575j),
2072
+ expected=(0.4718880510273174+0.655083067736377j),
2073
+ rtol=1e-11,
2074
+ ),
2075
+ ),
2076
+ pytest.param(
2077
+ Hyp2f1TestCase(
2078
+ a=-7.937789122896016,
2079
+ b=-3.9316537064827854,
2080
+ c=16.056809865262608,
2081
+ z=(-0.9473684210526316+0.5263157894736841j),
2082
+ expected=(-0.14681550942352714+0.16092206364265146j),
2083
+ rtol=5e-11,
2084
+ ),
2085
+ ),
2086
+ pytest.param(
2087
+ Hyp2f1TestCase(
2088
+ a=-0.9220024191881196,
2089
+ b=-15.964218273004214,
2090
+ c=1.0651378143226575,
2091
+ z=(-0.5263157894736843+0.9473684210526314j),
2092
+ expected=(-6.436835190526225+22.883156700606182j),
2093
+ rtol=5e-14,
2094
+ ),
2095
+ ),
2096
+ pytest.param(
2097
+ Hyp2f1TestCase(
2098
+ a=-0.9220024191881196,
2099
+ b=-7.949900487447654,
2100
+ c=4.078873014294075,
2101
+ z=(-0.9473684210526316-0.5263157894736843j),
2102
+ expected=(-0.7505682955068583-1.1026583264249945j),
2103
+ rtol=1e-15,
2104
+ ),
2105
+ ),
2106
+ pytest.param(
2107
+ Hyp2f1TestCase(
2108
+ a=-3.956227226099288,
2109
+ b=-3.9316537064827854,
2110
+ c=-7.93846038215665,
2111
+ z=(-0.9473684210526316-0.5263157894736843j),
2112
+ expected=(3.6247814989198166+2.596041360148318j),
2113
+ rtol=5e-15,
2114
+ ),
2115
+ ),
2116
+ pytest.param(
2117
+ Hyp2f1TestCase(
2118
+ a=-3.956227226099288,
2119
+ b=-15.964218273004214,
2120
+ c=-1.9631175993998025,
2121
+ z=(-0.5263157894736843-0.9473684210526316j),
2122
+ expected=(-59537.65287927933-669074.4342539902j),
2123
+ rtol=5e-15,
2124
+ ),
2125
+ ),
2126
+ pytest.param(
2127
+ Hyp2f1TestCase(
2128
+ a=-3.956227226099288,
2129
+ b=-15.964218273004214,
2130
+ c=-1.9631175993998025,
2131
+ z=(-0.9473684210526316-0.5263157894736843j),
2132
+ expected=(-433084.9970266166+431088.393918521j),
2133
+ rtol=5e-14,
2134
+ ),
2135
+ ),
2136
+ ]
2137
+ )
2138
+ def test_region6(self, hyp2f1_test_case):
2139
+ """|z| > 1 but not in region 5."""
2140
+ a, b, c, z, expected, rtol = hyp2f1_test_case
2141
+ assert (
2142
+ abs(z) > 1 and
2143
+ not (1 < abs(z) < 1.1 and abs(1 - z) >= 0.9 and z.real >= 0)
2144
+ )
2145
+ assert_allclose(hyp2f1(a, b, c, z), expected, rtol=rtol)
2146
+
2147
+ @pytest.mark.slow
2148
+ @check_version(mpmath, "1.0.0")
2149
+ def test_test_hyp2f1(self):
2150
+ """Test that expected values match what is computed by mpmath.
2151
+
2152
+ This gathers the parameters for the test cases out of the pytest marks.
2153
+ The parameters are a, b, c, z, expected, rtol, where expected should
2154
+ be the value of hyp2f1(a, b, c, z) computed with mpmath. The test
2155
+ recomputes hyp2f1(a, b, c, z) using mpmath and verifies that expected
2156
+ actually is the correct value. This allows the data for the tests to
2157
+ live within the test code instead of an external datafile, while
2158
+ avoiding having to compute the results with mpmath during the test,
2159
+ except for when slow tests are being run.
2160
+ """
2161
+ test_methods = [
2162
+ test_method for test_method in dir(self)
2163
+ if test_method.startswith('test') and
2164
+ # Filter properties and attributes (futureproofing).
2165
+ callable(getattr(self, test_method)) and
2166
+ # Filter out this test
2167
+ test_method != 'test_test_hyp2f1'
2168
+ ]
2169
+ for test_method in test_methods:
2170
+ params = self._get_test_parameters(getattr(self, test_method))
2171
+ for a, b, c, z, expected, _ in params:
2172
+ assert_allclose(mp_hyp2f1(a, b, c, z), expected, rtol=2.25e-16)
2173
+
2174
+ def _get_test_parameters(self, test_method):
2175
+ """Get pytest.mark parameters for a test in this class."""
2176
+ return [
2177
+ case.values[0] for mark in test_method.pytestmark
2178
+ if mark.name == 'parametrize'
2179
+ for case in mark.args[1]
2180
+ ]
.venv/Lib/site-packages/scipy/special/tests/test_hypergeometric.py ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pytest
2
+ import numpy as np
3
+ from numpy.testing import assert_allclose, assert_equal
4
+ import scipy.special as sc
5
+
6
+
7
+ class TestHyperu:
8
+
9
+ def test_negative_x(self):
10
+ a, b, x = np.meshgrid(
11
+ [-1, -0.5, 0, 0.5, 1],
12
+ [-1, -0.5, 0, 0.5, 1],
13
+ np.linspace(-100, -1, 10),
14
+ )
15
+ assert np.all(np.isnan(sc.hyperu(a, b, x)))
16
+
17
+ def test_special_cases(self):
18
+ assert sc.hyperu(0, 1, 1) == 1.0
19
+
20
+ @pytest.mark.parametrize('a', [0.5, 1, np.nan])
21
+ @pytest.mark.parametrize('b', [1, 2, np.nan])
22
+ @pytest.mark.parametrize('x', [0.25, 3, np.nan])
23
+ def test_nan_inputs(self, a, b, x):
24
+ assert np.isnan(sc.hyperu(a, b, x)) == np.any(np.isnan([a, b, x]))
25
+
26
+
27
+ class TestHyp1f1:
28
+
29
+ @pytest.mark.parametrize('a, b, x', [
30
+ (np.nan, 1, 1),
31
+ (1, np.nan, 1),
32
+ (1, 1, np.nan)
33
+ ])
34
+ def test_nan_inputs(self, a, b, x):
35
+ assert np.isnan(sc.hyp1f1(a, b, x))
36
+
37
+ def test_poles(self):
38
+ assert_equal(sc.hyp1f1(1, [0, -1, -2, -3, -4], 0.5), np.inf)
39
+
40
+ @pytest.mark.parametrize('a, b, x, result', [
41
+ (-1, 1, 0.5, 0.5),
42
+ (1, 1, 0.5, 1.6487212707001281468),
43
+ (2, 1, 0.5, 2.4730819060501922203),
44
+ (1, 2, 0.5, 1.2974425414002562937),
45
+ (-10, 1, 0.5, -0.38937441413785204475)
46
+ ])
47
+ def test_special_cases(self, a, b, x, result):
48
+ # Hit all the special case branches at the beginning of the
49
+ # function. Desired answers computed using Mpmath.
50
+ assert_allclose(sc.hyp1f1(a, b, x), result, atol=0, rtol=1e-15)
51
+
52
+ @pytest.mark.parametrize('a, b, x, result', [
53
+ (1, 1, 0.44, 1.5527072185113360455),
54
+ (-1, 1, 0.44, 0.55999999999999999778),
55
+ (100, 100, 0.89, 2.4351296512898745592),
56
+ (-100, 100, 0.89, 0.40739062490768104667),
57
+ (1.5, 100, 59.99, 3.8073513625965598107),
58
+ (-1.5, 100, 59.99, 0.25099240047125826943)
59
+ ])
60
+ def test_geometric_convergence(self, a, b, x, result):
61
+ # Test the region where we are relying on the ratio of
62
+ #
63
+ # (|a| + 1) * |x| / |b|
64
+ #
65
+ # being small. Desired answers computed using Mpmath
66
+ assert_allclose(sc.hyp1f1(a, b, x), result, atol=0, rtol=1e-15)
67
+
68
+ @pytest.mark.parametrize('a, b, x, result', [
69
+ (-1, 1, 1.5, -0.5),
70
+ (-10, 1, 1.5, 0.41801777430943080357),
71
+ (-25, 1, 1.5, 0.25114491646037839809),
72
+ (-50, 1, 1.5, -0.25683643975194756115),
73
+ (-80, 1, 1.5, -0.24554329325751503601),
74
+ (-150, 1, 1.5, -0.173364795515420454496),
75
+ ])
76
+ def test_a_negative_integer(self, a, b, x, result):
77
+ # Desired answers computed using Mpmath.
78
+ assert_allclose(sc.hyp1f1(a, b, x), result, atol=0, rtol=2e-14)
79
+
80
+ @pytest.mark.parametrize('a, b, x, expected', [
81
+ (0.01, 150, -4, 0.99973683897677527773), # gh-3492
82
+ (1, 5, 0.01, 1.0020033381011970966), # gh-3593
83
+ (50, 100, 0.01, 1.0050126452421463411), # gh-3593
84
+ (1, 0.3, -1e3, -7.011932249442947651455e-04), # gh-14149
85
+ (1, 0.3, -1e4, -7.001190321418937164734e-05), # gh-14149
86
+ (9, 8.5, -350, -5.224090831922378361082e-20), # gh-17120
87
+ (9, 8.5, -355, -4.595407159813368193322e-20), # gh-17120
88
+ (75, -123.5, 15, 3.425753920814889017493e+06),
89
+ ])
90
+ def test_assorted_cases(self, a, b, x, expected):
91
+ # Expected values were computed with mpmath.hyp1f1(a, b, x).
92
+ assert_allclose(sc.hyp1f1(a, b, x), expected, atol=0, rtol=1e-14)
93
+
94
+ def test_a_neg_int_and_b_equal_x(self):
95
+ # This is a case where the Boost wrapper will call hypergeometric_pFq
96
+ # instead of hypergeometric_1F1. When we use a version of Boost in
97
+ # which https://github.com/boostorg/math/issues/833 is fixed, this
98
+ # test case can probably be moved into test_assorted_cases.
99
+ # The expected value was computed with mpmath.hyp1f1(a, b, x).
100
+ a = -10.0
101
+ b = 2.5
102
+ x = 2.5
103
+ expected = 0.0365323664364104338721
104
+ computed = sc.hyp1f1(a, b, x)
105
+ assert_allclose(computed, expected, atol=0, rtol=1e-13)
106
+
107
+ @pytest.mark.parametrize('a, b, x, desired', [
108
+ (-1, -2, 2, 2),
109
+ (-1, -4, 10, 3.5),
110
+ (-2, -2, 1, 2.5)
111
+ ])
112
+ def test_gh_11099(self, a, b, x, desired):
113
+ # All desired results computed using Mpmath
114
+ assert sc.hyp1f1(a, b, x) == desired
115
+
116
+ @pytest.mark.parametrize('a', [-3, -2])
117
+ def test_x_zero_a_and_b_neg_ints_and_a_ge_b(self, a):
118
+ assert sc.hyp1f1(a, -3, 0) == 1
119
+
120
+ # The "legacy edge cases" mentioned in the comments in the following
121
+ # tests refers to the behavior of hyp1f1(a, b, x) when b is a nonpositive
122
+ # integer. In some subcases, the behavior of SciPy does not match that
123
+ # of Boost (1.81+), mpmath and Mathematica (via Wolfram Alpha online).
124
+ # If the handling of these edges cases is changed to agree with those
125
+ # libraries, these test will have to be updated.
126
+
127
+ @pytest.mark.parametrize('b', [0, -1, -5])
128
+ def test_legacy_case1(self, b):
129
+ # Test results of hyp1f1(0, n, x) for n <= 0.
130
+ # This is a legacy edge case.
131
+ # Boost (versions greater than 1.80), Mathematica (via Wolfram Alpha
132
+ # online) and mpmath all return 1 in this case, but SciPy's hyp1f1
133
+ # returns inf.
134
+ assert_equal(sc.hyp1f1(0, b, [-1.5, 0, 1.5]), [np.inf, np.inf, np.inf])
135
+
136
+ def test_legacy_case2(self):
137
+ # This is a legacy edge case.
138
+ # In software such as boost (1.81+), mpmath and Mathematica,
139
+ # the value is 1.
140
+ assert sc.hyp1f1(-4, -3, 0) == np.inf
.venv/Lib/site-packages/scipy/special/tests/test_kolmogorov.py ADDED
@@ -0,0 +1,495 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import itertools
2
+ import sys
3
+ import pytest
4
+
5
+ import numpy as np
6
+ from numpy.testing import assert_
7
+ from scipy.special._testutils import FuncData
8
+
9
+ from scipy.special import kolmogorov, kolmogi, smirnov, smirnovi
10
+ from scipy.special._ufuncs import (_kolmogc, _kolmogci, _kolmogp,
11
+ _smirnovc, _smirnovci, _smirnovp)
12
+
13
+ _rtol = 1e-10
14
+
15
+ class TestSmirnov:
16
+ def test_nan(self):
17
+ assert_(np.isnan(smirnov(1, np.nan)))
18
+
19
+ def test_basic(self):
20
+ dataset = [(1, 0.1, 0.9),
21
+ (1, 0.875, 0.125),
22
+ (2, 0.875, 0.125 * 0.125),
23
+ (3, 0.875, 0.125 * 0.125 * 0.125)]
24
+
25
+ dataset = np.asarray(dataset)
26
+ FuncData(
27
+ smirnov, dataset, (0, 1), 2, rtol=_rtol
28
+ ).check(dtypes=[int, float, float])
29
+ dataset[:, -1] = 1 - dataset[:, -1]
30
+ FuncData(
31
+ _smirnovc, dataset, (0, 1), 2, rtol=_rtol
32
+ ).check(dtypes=[int, float, float])
33
+
34
+ def test_x_equals_0(self):
35
+ dataset = [(n, 0, 1) for n in itertools.chain(range(2, 20), range(1010, 1020))]
36
+ dataset = np.asarray(dataset)
37
+ FuncData(
38
+ smirnov, dataset, (0, 1), 2, rtol=_rtol
39
+ ).check(dtypes=[int, float, float])
40
+ dataset[:, -1] = 1 - dataset[:, -1]
41
+ FuncData(
42
+ _smirnovc, dataset, (0, 1), 2, rtol=_rtol
43
+ ).check(dtypes=[int, float, float])
44
+
45
+ def test_x_equals_1(self):
46
+ dataset = [(n, 1, 0) for n in itertools.chain(range(2, 20), range(1010, 1020))]
47
+ dataset = np.asarray(dataset)
48
+ FuncData(
49
+ smirnov, dataset, (0, 1), 2, rtol=_rtol
50
+ ).check(dtypes=[int, float, float])
51
+ dataset[:, -1] = 1 - dataset[:, -1]
52
+ FuncData(
53
+ _smirnovc, dataset, (0, 1), 2, rtol=_rtol
54
+ ).check(dtypes=[int, float, float])
55
+
56
+ def test_x_equals_0point5(self):
57
+ dataset = [(1, 0.5, 0.5),
58
+ (2, 0.5, 0.25),
59
+ (3, 0.5, 0.166666666667),
60
+ (4, 0.5, 0.09375),
61
+ (5, 0.5, 0.056),
62
+ (6, 0.5, 0.0327932098765),
63
+ (7, 0.5, 0.0191958707681),
64
+ (8, 0.5, 0.0112953186035),
65
+ (9, 0.5, 0.00661933257355),
66
+ (10, 0.5, 0.003888705)]
67
+
68
+ dataset = np.asarray(dataset)
69
+ FuncData(
70
+ smirnov, dataset, (0, 1), 2, rtol=_rtol
71
+ ).check(dtypes=[int, float, float])
72
+ dataset[:, -1] = 1 - dataset[:, -1]
73
+ FuncData(
74
+ _smirnovc, dataset, (0, 1), 2, rtol=_rtol
75
+ ).check(dtypes=[int, float, float])
76
+
77
+ def test_n_equals_1(self):
78
+ x = np.linspace(0, 1, 101, endpoint=True)
79
+ dataset = np.column_stack([[1]*len(x), x, 1-x])
80
+ FuncData(
81
+ smirnov, dataset, (0, 1), 2, rtol=_rtol
82
+ ).check(dtypes=[int, float, float])
83
+ dataset[:, -1] = 1 - dataset[:, -1]
84
+ FuncData(
85
+ _smirnovc, dataset, (0, 1), 2, rtol=_rtol
86
+ ).check(dtypes=[int, float, float])
87
+
88
+ def test_n_equals_2(self):
89
+ x = np.linspace(0.5, 1, 101, endpoint=True)
90
+ p = np.power(1-x, 2)
91
+ n = np.array([2] * len(x))
92
+ dataset = np.column_stack([n, x, p])
93
+ FuncData(
94
+ smirnov, dataset, (0, 1), 2, rtol=_rtol
95
+ ).check(dtypes=[int, float, float])
96
+ dataset[:, -1] = 1 - dataset[:, -1]
97
+ FuncData(
98
+ _smirnovc, dataset, (0, 1), 2, rtol=_rtol
99
+ ).check(dtypes=[int, float, float])
100
+
101
+ def test_n_equals_3(self):
102
+ x = np.linspace(0.7, 1, 31, endpoint=True)
103
+ p = np.power(1-x, 3)
104
+ n = np.array([3] * len(x))
105
+ dataset = np.column_stack([n, x, p])
106
+ FuncData(
107
+ smirnov, dataset, (0, 1), 2, rtol=_rtol
108
+ ).check(dtypes=[int, float, float])
109
+ dataset[:, -1] = 1 - dataset[:, -1]
110
+ FuncData(
111
+ _smirnovc, dataset, (0, 1), 2, rtol=_rtol
112
+ ).check(dtypes=[int, float, float])
113
+
114
+ def test_n_large(self):
115
+ # test for large values of n
116
+ # Probabilities should go down as n goes up
117
+ x = 0.4
118
+ pvals = np.array([smirnov(n, x) for n in range(400, 1100, 20)])
119
+ dfs = np.diff(pvals)
120
+ assert_(np.all(dfs <= 0), msg='Not all diffs negative %s' % dfs)
121
+
122
+
123
+ class TestSmirnovi:
124
+ def test_nan(self):
125
+ assert_(np.isnan(smirnovi(1, np.nan)))
126
+
127
+ def test_basic(self):
128
+ dataset = [(1, 0.4, 0.6),
129
+ (1, 0.6, 0.4),
130
+ (1, 0.99, 0.01),
131
+ (1, 0.01, 0.99),
132
+ (2, 0.125 * 0.125, 0.875),
133
+ (3, 0.125 * 0.125 * 0.125, 0.875),
134
+ (10, 1.0 / 16 ** 10, 1 - 1.0 / 16)]
135
+
136
+ dataset = np.asarray(dataset)
137
+ FuncData(
138
+ smirnovi, dataset, (0, 1), 2, rtol=_rtol
139
+ ).check(dtypes=[int, float, float])
140
+ dataset[:, 1] = 1 - dataset[:, 1]
141
+ FuncData(
142
+ _smirnovci, dataset, (0, 1), 2, rtol=_rtol
143
+ ).check(dtypes=[int, float, float])
144
+
145
+ def test_x_equals_0(self):
146
+ dataset = [(n, 0, 1) for n in itertools.chain(range(2, 20), range(1010, 1020))]
147
+ dataset = np.asarray(dataset)
148
+ FuncData(
149
+ smirnovi, dataset, (0, 1), 2, rtol=_rtol
150
+ ).check(dtypes=[int, float, float])
151
+ dataset[:, 1] = 1 - dataset[:, 1]
152
+ FuncData(
153
+ _smirnovci, dataset, (0, 1), 2, rtol=_rtol
154
+ ).check(dtypes=[int, float, float])
155
+
156
+ def test_x_equals_1(self):
157
+ dataset = [(n, 1, 0) for n in itertools.chain(range(2, 20), range(1010, 1020))]
158
+ dataset = np.asarray(dataset)
159
+ FuncData(
160
+ smirnovi, dataset, (0, 1), 2, rtol=_rtol
161
+ ).check(dtypes=[int, float, float])
162
+ dataset[:, 1] = 1 - dataset[:, 1]
163
+ FuncData(
164
+ _smirnovci, dataset, (0, 1), 2, rtol=_rtol
165
+ ).check(dtypes=[int, float, float])
166
+
167
+ def test_n_equals_1(self):
168
+ pp = np.linspace(0, 1, 101, endpoint=True)
169
+ # dataset = np.array([(1, p, 1-p) for p in pp])
170
+ dataset = np.column_stack([[1]*len(pp), pp, 1-pp])
171
+ FuncData(
172
+ smirnovi, dataset, (0, 1), 2, rtol=_rtol
173
+ ).check(dtypes=[int, float, float])
174
+ dataset[:, 1] = 1 - dataset[:, 1]
175
+ FuncData(
176
+ _smirnovci, dataset, (0, 1), 2, rtol=_rtol
177
+ ).check(dtypes=[int, float, float])
178
+
179
+ def test_n_equals_2(self):
180
+ x = np.linspace(0.5, 1, 101, endpoint=True)
181
+ p = np.power(1-x, 2)
182
+ n = np.array([2] * len(x))
183
+ dataset = np.column_stack([n, p, x])
184
+ FuncData(
185
+ smirnovi, dataset, (0, 1), 2, rtol=_rtol
186
+ ).check(dtypes=[int, float, float])
187
+ dataset[:, 1] = 1 - dataset[:, 1]
188
+ FuncData(
189
+ _smirnovci, dataset, (0, 1), 2, rtol=_rtol
190
+ ).check(dtypes=[int, float, float])
191
+
192
+ def test_n_equals_3(self):
193
+ x = np.linspace(0.7, 1, 31, endpoint=True)
194
+ p = np.power(1-x, 3)
195
+ n = np.array([3] * len(x))
196
+ dataset = np.column_stack([n, p, x])
197
+ FuncData(
198
+ smirnovi, dataset, (0, 1), 2, rtol=_rtol
199
+ ).check(dtypes=[int, float, float])
200
+ dataset[:, 1] = 1 - dataset[:, 1]
201
+ FuncData(
202
+ _smirnovci, dataset, (0, 1), 2, rtol=_rtol
203
+ ).check(dtypes=[int, float, float])
204
+
205
+ def test_round_trip(self):
206
+ def _sm_smi(n, p):
207
+ return smirnov(n, smirnovi(n, p))
208
+
209
+ def _smc_smci(n, p):
210
+ return _smirnovc(n, _smirnovci(n, p))
211
+
212
+ dataset = [(1, 0.4, 0.4),
213
+ (1, 0.6, 0.6),
214
+ (2, 0.875, 0.875),
215
+ (3, 0.875, 0.875),
216
+ (3, 0.125, 0.125),
217
+ (10, 0.999, 0.999),
218
+ (10, 0.0001, 0.0001)]
219
+
220
+ dataset = np.asarray(dataset)
221
+ FuncData(
222
+ _sm_smi, dataset, (0, 1), 2, rtol=_rtol
223
+ ).check(dtypes=[int, float, float])
224
+ FuncData(
225
+ _smc_smci, dataset, (0, 1), 2, rtol=_rtol
226
+ ).check(dtypes=[int, float, float])
227
+
228
+ def test_x_equals_0point5(self):
229
+ dataset = [(1, 0.5, 0.5),
230
+ (2, 0.5, 0.366025403784),
231
+ (2, 0.25, 0.5),
232
+ (3, 0.5, 0.297156508177),
233
+ (4, 0.5, 0.255520481121),
234
+ (5, 0.5, 0.234559536069),
235
+ (6, 0.5, 0.21715965898),
236
+ (7, 0.5, 0.202722580034),
237
+ (8, 0.5, 0.190621765256),
238
+ (9, 0.5, 0.180363501362),
239
+ (10, 0.5, 0.17157867006)]
240
+
241
+ dataset = np.asarray(dataset)
242
+ FuncData(
243
+ smirnovi, dataset, (0, 1), 2, rtol=_rtol
244
+ ).check(dtypes=[int, float, float])
245
+ dataset[:, 1] = 1 - dataset[:, 1]
246
+ FuncData(
247
+ _smirnovci, dataset, (0, 1), 2, rtol=_rtol
248
+ ).check(dtypes=[int, float, float])
249
+
250
+
251
+ class TestSmirnovp:
252
+ def test_nan(self):
253
+ assert_(np.isnan(_smirnovp(1, np.nan)))
254
+
255
+ def test_basic(self):
256
+ # Check derivative at endpoints
257
+ n1_10 = np.arange(1, 10)
258
+ dataset0 = np.column_stack([n1_10,
259
+ np.full_like(n1_10, 0),
260
+ np.full_like(n1_10, -1)])
261
+ FuncData(
262
+ _smirnovp, dataset0, (0, 1), 2, rtol=_rtol
263
+ ).check(dtypes=[int, float, float])
264
+
265
+ n2_10 = np.arange(2, 10)
266
+ dataset1 = np.column_stack([n2_10,
267
+ np.full_like(n2_10, 1.0),
268
+ np.full_like(n2_10, 0)])
269
+ FuncData(
270
+ _smirnovp, dataset1, (0, 1), 2, rtol=_rtol
271
+ ).check(dtypes=[int, float, float])
272
+
273
+ def test_oneminusoneovern(self):
274
+ # Check derivative at x=1-1/n
275
+ n = np.arange(1, 20)
276
+ x = 1.0/n
277
+ xm1 = 1-1.0/n
278
+ pp1 = -n * x**(n-1)
279
+ pp1 -= (1-np.sign(n-2)**2) * 0.5 # n=2, x=0.5, 1-1/n = 0.5, need to adjust
280
+ dataset1 = np.column_stack([n, xm1, pp1])
281
+ FuncData(
282
+ _smirnovp, dataset1, (0, 1), 2, rtol=_rtol
283
+ ).check(dtypes=[int, float, float])
284
+
285
+ def test_oneovertwon(self):
286
+ # Check derivative at x=1/2n (Discontinuous at x=1/n, so check at x=1/2n)
287
+ n = np.arange(1, 20)
288
+ x = 1.0/2/n
289
+ pp = -(n*x+1) * (1+x)**(n-2)
290
+ dataset0 = np.column_stack([n, x, pp])
291
+ FuncData(
292
+ _smirnovp, dataset0, (0, 1), 2, rtol=_rtol
293
+ ).check(dtypes=[int, float, float])
294
+
295
+ def test_oneovern(self):
296
+ # Check derivative at x=1/n
297
+ # (Discontinuous at x=1/n, hard to tell if x==1/n, only use n=power of 2)
298
+ n = 2**np.arange(1, 10)
299
+ x = 1.0/n
300
+ pp = -(n*x+1) * (1+x)**(n-2) + 0.5
301
+ dataset0 = np.column_stack([n, x, pp])
302
+ FuncData(
303
+ _smirnovp, dataset0, (0, 1), 2, rtol=_rtol
304
+ ).check(dtypes=[int, float, float])
305
+
306
+ @pytest.mark.xfail(sys.maxsize <= 2**32,
307
+ reason="requires 64-bit platform")
308
+ def test_oneovernclose(self):
309
+ # Check derivative at x=1/n
310
+ # (Discontinuous at x=1/n, test on either side: x=1/n +/- 2epsilon)
311
+ n = np.arange(3, 20)
312
+
313
+ x = 1.0/n - 2*np.finfo(float).eps
314
+ pp = -(n*x+1) * (1+x)**(n-2)
315
+ dataset0 = np.column_stack([n, x, pp])
316
+ FuncData(
317
+ _smirnovp, dataset0, (0, 1), 2, rtol=_rtol
318
+ ).check(dtypes=[int, float, float])
319
+
320
+ x = 1.0/n + 2*np.finfo(float).eps
321
+ pp = -(n*x+1) * (1+x)**(n-2) + 1
322
+ dataset1 = np.column_stack([n, x, pp])
323
+ FuncData(
324
+ _smirnovp, dataset1, (0, 1), 2, rtol=_rtol
325
+ ).check(dtypes=[int, float, float])
326
+
327
+
328
+ class TestKolmogorov:
329
+ def test_nan(self):
330
+ assert_(np.isnan(kolmogorov(np.nan)))
331
+
332
+ def test_basic(self):
333
+ dataset = [(0, 1.0),
334
+ (0.5, 0.96394524366487511),
335
+ (0.8275735551899077, 0.5000000000000000),
336
+ (1, 0.26999967167735456),
337
+ (2, 0.00067092525577969533)]
338
+
339
+ dataset = np.asarray(dataset)
340
+ FuncData(kolmogorov, dataset, (0,), 1, rtol=_rtol).check()
341
+
342
+ def test_linspace(self):
343
+ x = np.linspace(0, 2.0, 21)
344
+ dataset = [1.0000000000000000, 1.0000000000000000, 0.9999999999994950,
345
+ 0.9999906941986655, 0.9971923267772983, 0.9639452436648751,
346
+ 0.8642827790506042, 0.7112351950296890, 0.5441424115741981,
347
+ 0.3927307079406543, 0.2699996716773546, 0.1777181926064012,
348
+ 0.1122496666707249, 0.0680922218447664, 0.0396818795381144,
349
+ 0.0222179626165251, 0.0119520432391966, 0.0061774306344441,
350
+ 0.0030676213475797, 0.0014636048371873, 0.0006709252557797]
351
+
352
+ dataset_c = [0.0000000000000000, 6.609305242245699e-53, 5.050407338670114e-13,
353
+ 9.305801334566668e-06, 0.0028076732227017, 0.0360547563351249,
354
+ 0.1357172209493958, 0.2887648049703110, 0.4558575884258019,
355
+ 0.6072692920593457, 0.7300003283226455, 0.8222818073935988,
356
+ 0.8877503333292751, 0.9319077781552336, 0.9603181204618857,
357
+ 0.9777820373834749, 0.9880479567608034, 0.9938225693655559,
358
+ 0.9969323786524203, 0.9985363951628127, 0.9993290747442203]
359
+
360
+ dataset = np.column_stack([x, dataset])
361
+ FuncData(kolmogorov, dataset, (0,), 1, rtol=_rtol).check()
362
+ dataset_c = np.column_stack([x, dataset_c])
363
+ FuncData(_kolmogc, dataset_c, (0,), 1, rtol=_rtol).check()
364
+
365
+ def test_linspacei(self):
366
+ p = np.linspace(0, 1.0, 21, endpoint=True)
367
+ dataset = [np.inf, 1.3580986393225507, 1.2238478702170823,
368
+ 1.1379465424937751, 1.0727491749396481, 1.0191847202536859,
369
+ 0.9730633753323726, 0.9320695842357622, 0.8947644549851197,
370
+ 0.8601710725555463, 0.8275735551899077, 0.7964065373291559,
371
+ 0.7661855555617682, 0.7364542888171910, 0.7067326523068980,
372
+ 0.6764476915028201, 0.6448126061663567, 0.6105590999244391,
373
+ 0.5711732651063401, 0.5196103791686224, 0.0000000000000000]
374
+
375
+ dataset_c = [0.0000000000000000, 0.5196103791686225, 0.5711732651063401,
376
+ 0.6105590999244391, 0.6448126061663567, 0.6764476915028201,
377
+ 0.7067326523068980, 0.7364542888171910, 0.7661855555617682,
378
+ 0.7964065373291559, 0.8275735551899077, 0.8601710725555463,
379
+ 0.8947644549851196, 0.9320695842357622, 0.9730633753323727,
380
+ 1.0191847202536859, 1.0727491749396481, 1.1379465424937754,
381
+ 1.2238478702170825, 1.3580986393225509, np.inf]
382
+
383
+ dataset = np.column_stack([p[1:], dataset[1:]])
384
+ FuncData(kolmogi, dataset, (0,), 1, rtol=_rtol).check()
385
+ dataset_c = np.column_stack([p[:-1], dataset_c[:-1]])
386
+ FuncData(_kolmogci, dataset_c, (0,), 1, rtol=_rtol).check()
387
+
388
+ def test_smallx(self):
389
+ epsilon = 0.1 ** np.arange(1, 14)
390
+ x = np.array([0.571173265106, 0.441027698518, 0.374219690278, 0.331392659217,
391
+ 0.300820537459, 0.277539353999, 0.259023494805, 0.243829561254,
392
+ 0.231063086389, 0.220135543236, 0.210641372041, 0.202290283658,
393
+ 0.19487060742])
394
+
395
+ dataset = np.column_stack([x, 1-epsilon])
396
+ FuncData(kolmogorov, dataset, (0,), 1, rtol=_rtol).check()
397
+
398
+ def test_round_trip(self):
399
+ def _ki_k(_x):
400
+ return kolmogi(kolmogorov(_x))
401
+
402
+ def _kci_kc(_x):
403
+ return _kolmogci(_kolmogc(_x))
404
+
405
+ x = np.linspace(0.0, 2.0, 21, endpoint=True)
406
+ # Exclude 0.1, 0.2. 0.2 almost makes succeeds, but 0.1 has no chance.
407
+ x02 = x[(x == 0) | (x > 0.21)]
408
+ dataset02 = np.column_stack([x02, x02])
409
+ FuncData(_ki_k, dataset02, (0,), 1, rtol=_rtol).check()
410
+
411
+ dataset = np.column_stack([x, x])
412
+ FuncData(_kci_kc, dataset, (0,), 1, rtol=_rtol).check()
413
+
414
+
415
+ class TestKolmogi:
416
+ def test_nan(self):
417
+ assert_(np.isnan(kolmogi(np.nan)))
418
+
419
+ def test_basic(self):
420
+ dataset = [(1.0, 0),
421
+ (0.96394524366487511, 0.5),
422
+ (0.9, 0.571173265106),
423
+ (0.5000000000000000, 0.8275735551899077),
424
+ (0.26999967167735456, 1),
425
+ (0.00067092525577969533, 2)]
426
+
427
+ dataset = np.asarray(dataset)
428
+ FuncData(kolmogi, dataset, (0,), 1, rtol=_rtol).check()
429
+
430
+ def test_smallpcdf(self):
431
+ epsilon = 0.5 ** np.arange(1, 55, 3)
432
+ # kolmogi(1-p) == _kolmogci(p) if 1-(1-p) == p, but not necessarily otherwise
433
+ # Use epsilon s.t. 1-(1-epsilon)) == epsilon,
434
+ # so can use same x-array for both results
435
+
436
+ x = np.array([0.8275735551899077, 0.5345255069097583, 0.4320114038786941,
437
+ 0.3736868442620478, 0.3345161714909591, 0.3057833329315859,
438
+ 0.2835052890528936, 0.2655578150208676, 0.2506869966107999,
439
+ 0.2380971058736669, 0.2272549289962079, 0.2177876361600040,
440
+ 0.2094254686862041, 0.2019676748836232, 0.1952612948137504,
441
+ 0.1891874239646641, 0.1836520225050326, 0.1785795904846466])
442
+
443
+ dataset = np.column_stack([1-epsilon, x])
444
+ FuncData(kolmogi, dataset, (0,), 1, rtol=_rtol).check()
445
+
446
+ dataset = np.column_stack([epsilon, x])
447
+ FuncData(_kolmogci, dataset, (0,), 1, rtol=_rtol).check()
448
+
449
+ def test_smallpsf(self):
450
+ epsilon = 0.5 ** np.arange(1, 55, 3)
451
+ # kolmogi(p) == _kolmogci(1-p) if 1-(1-p) == p, but not necessarily otherwise
452
+ # Use epsilon s.t. 1-(1-epsilon)) == epsilon,
453
+ # so can use same x-array for both results
454
+
455
+ x = np.array([0.8275735551899077, 1.3163786275161036, 1.6651092133663343,
456
+ 1.9525136345289607, 2.2027324540033235, 2.4272929437460848,
457
+ 2.6327688477341593, 2.8233300509220260, 3.0018183401530627,
458
+ 3.1702735084088891, 3.3302184446307912, 3.4828258153113318,
459
+ 3.6290214150152051, 3.7695513262825959, 3.9050272690877326,
460
+ 4.0359582187082550, 4.1627730557884890, 4.2858371743264527])
461
+
462
+ dataset = np.column_stack([epsilon, x])
463
+ FuncData(kolmogi, dataset, (0,), 1, rtol=_rtol).check()
464
+
465
+ dataset = np.column_stack([1-epsilon, x])
466
+ FuncData(_kolmogci, dataset, (0,), 1, rtol=_rtol).check()
467
+
468
+ def test_round_trip(self):
469
+ def _k_ki(_p):
470
+ return kolmogorov(kolmogi(_p))
471
+
472
+ p = np.linspace(0.1, 1.0, 10, endpoint=True)
473
+ dataset = np.column_stack([p, p])
474
+ FuncData(_k_ki, dataset, (0,), 1, rtol=_rtol).check()
475
+
476
+
477
+ class TestKolmogp:
478
+ def test_nan(self):
479
+ assert_(np.isnan(_kolmogp(np.nan)))
480
+
481
+ def test_basic(self):
482
+ dataset = [(0.000000, -0.0),
483
+ (0.200000, -1.532420541338916e-10),
484
+ (0.400000, -0.1012254419260496),
485
+ (0.600000, -1.324123244249925),
486
+ (0.800000, -1.627024345636592),
487
+ (1.000000, -1.071948558356941),
488
+ (1.200000, -0.538512430720529),
489
+ (1.400000, -0.2222133182429472),
490
+ (1.600000, -0.07649302775520538),
491
+ (1.800000, -0.02208687346347873),
492
+ (2.000000, -0.005367402045629683)]
493
+
494
+ dataset = np.asarray(dataset)
495
+ FuncData(_kolmogp, dataset, (0,), 1, rtol=_rtol).check()
.venv/Lib/site-packages/scipy/special/tests/test_lambertw.py ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Tests for the lambertw function,
3
+ # Adapted from the MPMath tests [1] by Yosef Meller, [email protected]
4
+ # Distributed under the same license as SciPy itself.
5
+ #
6
+ # [1] mpmath source code, Subversion revision 992
7
+ # http://code.google.com/p/mpmath/source/browse/trunk/mpmath/tests/test_functions2.py?spec=svn994&r=992
8
+
9
+ import pytest
10
+ import numpy as np
11
+ from numpy.testing import assert_, assert_equal, assert_array_almost_equal
12
+ from scipy.special import lambertw
13
+ from numpy import nan, inf, pi, e, isnan, log, r_, array, complex128
14
+
15
+ from scipy.special._testutils import FuncData
16
+
17
+
18
+ def test_values():
19
+ assert_(isnan(lambertw(nan)))
20
+ assert_equal(lambertw(inf,1).real, inf)
21
+ assert_equal(lambertw(inf,1).imag, 2*pi)
22
+ assert_equal(lambertw(-inf,1).real, inf)
23
+ assert_equal(lambertw(-inf,1).imag, 3*pi)
24
+
25
+ assert_equal(lambertw(1.), lambertw(1., 0))
26
+
27
+ data = [
28
+ (0,0, 0),
29
+ (0+0j,0, 0),
30
+ (inf,0, inf),
31
+ (0,-1, -inf),
32
+ (0,1, -inf),
33
+ (0,3, -inf),
34
+ (e,0, 1),
35
+ (1,0, 0.567143290409783873),
36
+ (-pi/2,0, 1j*pi/2),
37
+ (-log(2)/2,0, -log(2)),
38
+ (0.25,0, 0.203888354702240164),
39
+ (-0.25,0, -0.357402956181388903),
40
+ (-1./10000,0, -0.000100010001500266719),
41
+ (-0.25,-1, -2.15329236411034965),
42
+ (0.25,-1, -3.00899800997004620-4.07652978899159763j),
43
+ (-0.25,-1, -2.15329236411034965),
44
+ (0.25,1, -3.00899800997004620+4.07652978899159763j),
45
+ (-0.25,1, -3.48973228422959210+7.41405453009603664j),
46
+ (-4,0, 0.67881197132094523+1.91195078174339937j),
47
+ (-4,1, -0.66743107129800988+7.76827456802783084j),
48
+ (-4,-1, 0.67881197132094523-1.91195078174339937j),
49
+ (1000,0, 5.24960285240159623),
50
+ (1000,1, 4.91492239981054535+5.44652615979447070j),
51
+ (1000,-1, 4.91492239981054535-5.44652615979447070j),
52
+ (1000,5, 3.5010625305312892+29.9614548941181328j),
53
+ (3+4j,0, 1.281561806123775878+0.533095222020971071j),
54
+ (-0.4+0.4j,0, -0.10396515323290657+0.61899273315171632j),
55
+ (3+4j,1, -0.11691092896595324+5.61888039871282334j),
56
+ (3+4j,-1, 0.25856740686699742-3.85211668616143559j),
57
+ (-0.5,-1, -0.794023632344689368-0.770111750510379110j),
58
+ (-1./10000,1, -11.82350837248724344+6.80546081842002101j),
59
+ (-1./10000,-1, -11.6671145325663544),
60
+ (-1./10000,-2, -11.82350837248724344-6.80546081842002101j),
61
+ (-1./100000,4, -14.9186890769540539+26.1856750178782046j),
62
+ (-1./100000,5, -15.0931437726379218666+32.5525721210262290086j),
63
+ ((2+1j)/10,0, 0.173704503762911669+0.071781336752835511j),
64
+ ((2+1j)/10,1, -3.21746028349820063+4.56175438896292539j),
65
+ ((2+1j)/10,-1, -3.03781405002993088-3.53946629633505737j),
66
+ ((2+1j)/10,4, -4.6878509692773249+23.8313630697683291j),
67
+ (-(2+1j)/10,0, -0.226933772515757933-0.164986470020154580j),
68
+ (-(2+1j)/10,1, -2.43569517046110001+0.76974067544756289j),
69
+ (-(2+1j)/10,-1, -3.54858738151989450-6.91627921869943589j),
70
+ (-(2+1j)/10,4, -4.5500846928118151+20.6672982215434637j),
71
+ (pi,0, 1.073658194796149172092178407024821347547745350410314531),
72
+
73
+ # Former bug in generated branch,
74
+ (-0.5+0.002j,0, -0.78917138132659918344 + 0.76743539379990327749j),
75
+ (-0.5-0.002j,0, -0.78917138132659918344 - 0.76743539379990327749j),
76
+ (-0.448+0.4j,0, -0.11855133765652382241 + 0.66570534313583423116j),
77
+ (-0.448-0.4j,0, -0.11855133765652382241 - 0.66570534313583423116j),
78
+ ]
79
+ data = array(data, dtype=complex128)
80
+
81
+ def w(x, y):
82
+ return lambertw(x, y.real.astype(int))
83
+ with np.errstate(all='ignore'):
84
+ FuncData(w, data, (0,1), 2, rtol=1e-10, atol=1e-13).check()
85
+
86
+
87
+ def test_ufunc():
88
+ assert_array_almost_equal(
89
+ lambertw(r_[0., e, 1.]), r_[0., 1., 0.567143290409783873])
90
+
91
+
92
+ def test_lambertw_ufunc_loop_selection():
93
+ # see https://github.com/scipy/scipy/issues/4895
94
+ dt = np.dtype(np.complex128)
95
+ assert_equal(lambertw(0, 0, 0).dtype, dt)
96
+ assert_equal(lambertw([0], 0, 0).dtype, dt)
97
+ assert_equal(lambertw(0, [0], 0).dtype, dt)
98
+ assert_equal(lambertw(0, 0, [0]).dtype, dt)
99
+ assert_equal(lambertw([0], [0], [0]).dtype, dt)
100
+
101
+
102
+ @pytest.mark.parametrize('z', [1e-316, -2e-320j, -5e-318+1e-320j])
103
+ def test_lambertw_subnormal_k0(z):
104
+ # Verify that subnormal inputs are handled correctly on
105
+ # the branch k=0 (regression test for gh-16291).
106
+ w = lambertw(z)
107
+ # For values this small, we can be sure that numerically,
108
+ # lambertw(z) is z.
109
+ assert w == z
.venv/Lib/site-packages/scipy/special/tests/test_log_softmax.py ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from numpy.testing import assert_allclose
3
+
4
+ import pytest
5
+
6
+ import scipy.special as sc
7
+
8
+
9
+ @pytest.mark.parametrize('x, expected', [
10
+ (np.array([1000, 1]), np.array([0, -999])),
11
+
12
+ # Expected value computed using mpmath (with mpmath.mp.dps = 200) and then
13
+ # converted to float.
14
+ (np.arange(4), np.array([-3.4401896985611953,
15
+ -2.4401896985611953,
16
+ -1.4401896985611953,
17
+ -0.44018969856119533]))
18
+ ])
19
+ def test_log_softmax(x, expected):
20
+ assert_allclose(sc.log_softmax(x), expected, rtol=1e-13)
21
+
22
+
23
+ @pytest.fixture
24
+ def log_softmax_x():
25
+ x = np.arange(4)
26
+ return x
27
+
28
+
29
+ @pytest.fixture
30
+ def log_softmax_expected():
31
+ # Expected value computed using mpmath (with mpmath.mp.dps = 200) and then
32
+ # converted to float.
33
+ expected = np.array([-3.4401896985611953,
34
+ -2.4401896985611953,
35
+ -1.4401896985611953,
36
+ -0.44018969856119533])
37
+ return expected
38
+
39
+
40
+ def test_log_softmax_translation(log_softmax_x, log_softmax_expected):
41
+ # Translation property. If all the values are changed by the same amount,
42
+ # the softmax result does not change.
43
+ x = log_softmax_x + 100
44
+ expected = log_softmax_expected
45
+ assert_allclose(sc.log_softmax(x), expected, rtol=1e-13)
46
+
47
+
48
+ def test_log_softmax_noneaxis(log_softmax_x, log_softmax_expected):
49
+ # When axis=None, softmax operates on the entire array, and preserves
50
+ # the shape.
51
+ x = log_softmax_x.reshape(2, 2)
52
+ expected = log_softmax_expected.reshape(2, 2)
53
+ assert_allclose(sc.log_softmax(x), expected, rtol=1e-13)
54
+
55
+
56
+ @pytest.mark.parametrize('axis_2d, expected_2d', [
57
+ (0, np.log(0.5) * np.ones((2, 2))),
58
+ (1, np.array([[0, -999], [0, -999]]))
59
+ ])
60
+ def test_axes(axis_2d, expected_2d):
61
+ assert_allclose(
62
+ sc.log_softmax([[1000, 1], [1000, 1]], axis=axis_2d),
63
+ expected_2d,
64
+ rtol=1e-13,
65
+ )
66
+
67
+
68
+ @pytest.fixture
69
+ def log_softmax_2d_x():
70
+ x = np.arange(8).reshape(2, 4)
71
+ return x
72
+
73
+
74
+ @pytest.fixture
75
+ def log_softmax_2d_expected():
76
+ # Expected value computed using mpmath (with mpmath.mp.dps = 200) and then
77
+ # converted to float.
78
+ expected = np.array([[-3.4401896985611953,
79
+ -2.4401896985611953,
80
+ -1.4401896985611953,
81
+ -0.44018969856119533],
82
+ [-3.4401896985611953,
83
+ -2.4401896985611953,
84
+ -1.4401896985611953,
85
+ -0.44018969856119533]])
86
+ return expected
87
+
88
+
89
+ def test_log_softmax_2d_axis1(log_softmax_2d_x, log_softmax_2d_expected):
90
+ x = log_softmax_2d_x
91
+ expected = log_softmax_2d_expected
92
+ assert_allclose(sc.log_softmax(x, axis=1), expected, rtol=1e-13)
93
+
94
+
95
+ def test_log_softmax_2d_axis0(log_softmax_2d_x, log_softmax_2d_expected):
96
+ x = log_softmax_2d_x.T
97
+ expected = log_softmax_2d_expected.T
98
+ assert_allclose(sc.log_softmax(x, axis=0), expected, rtol=1e-13)
99
+
100
+
101
+ def test_log_softmax_3d(log_softmax_2d_x, log_softmax_2d_expected):
102
+ # 3-d input, with a tuple for the axis.
103
+ x_3d = log_softmax_2d_x.reshape(2, 2, 2)
104
+ expected_3d = log_softmax_2d_expected.reshape(2, 2, 2)
105
+ assert_allclose(sc.log_softmax(x_3d, axis=(1, 2)), expected_3d, rtol=1e-13)
106
+
107
+
108
+ def test_log_softmax_scalar():
109
+ assert_allclose(sc.log_softmax(1.0), 0.0, rtol=1e-13)
.venv/Lib/site-packages/scipy/special/tests/test_loggamma.py ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from numpy.testing import assert_allclose, assert_
3
+
4
+ from scipy.special._testutils import FuncData
5
+ from scipy.special import gamma, gammaln, loggamma
6
+
7
+
8
+ def test_identities1():
9
+ # test the identity exp(loggamma(z)) = gamma(z)
10
+ x = np.array([-99.5, -9.5, -0.5, 0.5, 9.5, 99.5])
11
+ y = x.copy()
12
+ x, y = np.meshgrid(x, y)
13
+ z = (x + 1J*y).flatten()
14
+ dataset = np.vstack((z, gamma(z))).T
15
+
16
+ def f(z):
17
+ return np.exp(loggamma(z))
18
+
19
+ FuncData(f, dataset, 0, 1, rtol=1e-14, atol=1e-14).check()
20
+
21
+
22
+ def test_identities2():
23
+ # test the identity loggamma(z + 1) = log(z) + loggamma(z)
24
+ x = np.array([-99.5, -9.5, -0.5, 0.5, 9.5, 99.5])
25
+ y = x.copy()
26
+ x, y = np.meshgrid(x, y)
27
+ z = (x + 1J*y).flatten()
28
+ dataset = np.vstack((z, np.log(z) + loggamma(z))).T
29
+
30
+ def f(z):
31
+ return loggamma(z + 1)
32
+
33
+ FuncData(f, dataset, 0, 1, rtol=1e-14, atol=1e-14).check()
34
+
35
+
36
+ def test_complex_dispatch_realpart():
37
+ # Test that the real parts of loggamma and gammaln agree on the
38
+ # real axis.
39
+ x = np.r_[-np.logspace(10, -10), np.logspace(-10, 10)] + 0.5
40
+
41
+ dataset = np.vstack((x, gammaln(x))).T
42
+
43
+ def f(z):
44
+ z = np.array(z, dtype='complex128')
45
+ return loggamma(z).real
46
+
47
+ FuncData(f, dataset, 0, 1, rtol=1e-14, atol=1e-14).check()
48
+
49
+
50
+ def test_real_dispatch():
51
+ x = np.logspace(-10, 10) + 0.5
52
+ dataset = np.vstack((x, gammaln(x))).T
53
+
54
+ FuncData(loggamma, dataset, 0, 1, rtol=1e-14, atol=1e-14).check()
55
+ assert_(loggamma(0) == np.inf)
56
+ assert_(np.isnan(loggamma(-1)))
57
+
58
+
59
+ def test_gh_6536():
60
+ z = loggamma(complex(-3.4, +0.0))
61
+ zbar = loggamma(complex(-3.4, -0.0))
62
+ assert_allclose(z, zbar.conjugate(), rtol=1e-15, atol=0)
63
+
64
+
65
+ def test_branch_cut():
66
+ # Make sure negative zero is treated correctly
67
+ x = -np.logspace(300, -30, 100)
68
+ z = np.asarray([complex(x0, 0.0) for x0 in x])
69
+ zbar = np.asarray([complex(x0, -0.0) for x0 in x])
70
+ assert_allclose(z, zbar.conjugate(), rtol=1e-15, atol=0)
.venv/Lib/site-packages/scipy/special/tests/test_logit.py ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from numpy.testing import (assert_equal, assert_almost_equal,
3
+ assert_allclose)
4
+ from scipy.special import logit, expit, log_expit
5
+
6
+
7
+ class TestLogit:
8
+ def check_logit_out(self, dtype, expected):
9
+ a = np.linspace(0, 1, 10)
10
+ a = np.array(a, dtype=dtype)
11
+ with np.errstate(divide='ignore'):
12
+ actual = logit(a)
13
+
14
+ assert_almost_equal(actual, expected)
15
+
16
+ assert_equal(actual.dtype, np.dtype(dtype))
17
+
18
+ def test_float32(self):
19
+ expected = np.array([-np.inf, -2.07944155,
20
+ -1.25276291, -0.69314718,
21
+ -0.22314353, 0.22314365,
22
+ 0.6931473, 1.25276303,
23
+ 2.07944155, np.inf], dtype=np.float32)
24
+ self.check_logit_out('f4', expected)
25
+
26
+ def test_float64(self):
27
+ expected = np.array([-np.inf, -2.07944154,
28
+ -1.25276297, -0.69314718,
29
+ -0.22314355, 0.22314355,
30
+ 0.69314718, 1.25276297,
31
+ 2.07944154, np.inf])
32
+ self.check_logit_out('f8', expected)
33
+
34
+ def test_nan(self):
35
+ expected = np.array([np.nan]*4)
36
+ with np.errstate(invalid='ignore'):
37
+ actual = logit(np.array([-3., -2., 2., 3.]))
38
+
39
+ assert_equal(expected, actual)
40
+
41
+
42
+ class TestExpit:
43
+ def check_expit_out(self, dtype, expected):
44
+ a = np.linspace(-4, 4, 10)
45
+ a = np.array(a, dtype=dtype)
46
+ actual = expit(a)
47
+ assert_almost_equal(actual, expected)
48
+ assert_equal(actual.dtype, np.dtype(dtype))
49
+
50
+ def test_float32(self):
51
+ expected = np.array([0.01798621, 0.04265125,
52
+ 0.09777259, 0.20860852,
53
+ 0.39068246, 0.60931754,
54
+ 0.79139149, 0.9022274,
55
+ 0.95734876, 0.98201376], dtype=np.float32)
56
+ self.check_expit_out('f4', expected)
57
+
58
+ def test_float64(self):
59
+ expected = np.array([0.01798621, 0.04265125,
60
+ 0.0977726, 0.20860853,
61
+ 0.39068246, 0.60931754,
62
+ 0.79139147, 0.9022274,
63
+ 0.95734875, 0.98201379])
64
+ self.check_expit_out('f8', expected)
65
+
66
+ def test_large(self):
67
+ for dtype in (np.float32, np.float64, np.longdouble):
68
+ for n in (88, 89, 709, 710, 11356, 11357):
69
+ n = np.array(n, dtype=dtype)
70
+ assert_allclose(expit(n), 1.0, atol=1e-20)
71
+ assert_allclose(expit(-n), 0.0, atol=1e-20)
72
+ assert_equal(expit(n).dtype, dtype)
73
+ assert_equal(expit(-n).dtype, dtype)
74
+
75
+
76
+ class TestLogExpit:
77
+
78
+ def test_large_negative(self):
79
+ x = np.array([-10000.0, -750.0, -500.0, -35.0])
80
+ y = log_expit(x)
81
+ assert_equal(y, x)
82
+
83
+ def test_large_positive(self):
84
+ x = np.array([750.0, 1000.0, 10000.0])
85
+ y = log_expit(x)
86
+ # y will contain -0.0, and -0.0 is used in the expected value,
87
+ # but assert_equal does not check the sign of zeros, and I don't
88
+ # think the sign is an essential part of the test (i.e. it would
89
+ # probably be OK if log_expit(1000) returned 0.0 instead of -0.0).
90
+ assert_equal(y, np.array([-0.0, -0.0, -0.0]))
91
+
92
+ def test_basic_float64(self):
93
+ x = np.array([-32, -20, -10, -3, -1, -0.1, -1e-9,
94
+ 0, 1e-9, 0.1, 1, 10, 100, 500, 710, 725, 735])
95
+ y = log_expit(x)
96
+ #
97
+ # Expected values were computed with mpmath:
98
+ #
99
+ # import mpmath
100
+ #
101
+ # mpmath.mp.dps = 100
102
+ #
103
+ # def mp_log_expit(x):
104
+ # return -mpmath.log1p(mpmath.exp(-x))
105
+ #
106
+ # expected = [float(mp_log_expit(t)) for t in x]
107
+ #
108
+ expected = [-32.000000000000014, -20.000000002061153,
109
+ -10.000045398899218, -3.048587351573742,
110
+ -1.3132616875182228, -0.7443966600735709,
111
+ -0.6931471810599453, -0.6931471805599453,
112
+ -0.6931471800599454, -0.6443966600735709,
113
+ -0.3132616875182228, -4.539889921686465e-05,
114
+ -3.720075976020836e-44, -7.124576406741286e-218,
115
+ -4.47628622567513e-309, -1.36930634e-315,
116
+ -6.217e-320]
117
+
118
+ # When tested locally, only one value in y was not exactly equal to
119
+ # expected. That was for x=1, and the y value differed from the
120
+ # expected by 1 ULP. For this test, however, I'll use rtol=1e-15.
121
+ assert_allclose(y, expected, rtol=1e-15)
122
+
123
+ def test_basic_float32(self):
124
+ x = np.array([-32, -20, -10, -3, -1, -0.1, -1e-9,
125
+ 0, 1e-9, 0.1, 1, 10, 100], dtype=np.float32)
126
+ y = log_expit(x)
127
+ #
128
+ # Expected values were computed with mpmath:
129
+ #
130
+ # import mpmath
131
+ #
132
+ # mpmath.mp.dps = 100
133
+ #
134
+ # def mp_log_expit(x):
135
+ # return -mpmath.log1p(mpmath.exp(-x))
136
+ #
137
+ # expected = [np.float32(mp_log_expit(t)) for t in x]
138
+ #
139
+ expected = np.array([-32.0, -20.0, -10.000046, -3.0485873,
140
+ -1.3132616, -0.7443967, -0.6931472,
141
+ -0.6931472, -0.6931472, -0.64439666,
142
+ -0.3132617, -4.5398898e-05, -3.8e-44],
143
+ dtype=np.float32)
144
+
145
+ assert_allclose(y, expected, rtol=5e-7)
.venv/Lib/site-packages/scipy/special/tests/test_logsumexp.py ADDED
@@ -0,0 +1,207 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from numpy.testing import (assert_almost_equal, assert_equal, assert_allclose,
3
+ assert_array_almost_equal, assert_)
4
+
5
+ from scipy.special import logsumexp, softmax
6
+
7
+
8
+ def test_logsumexp():
9
+ # Test whether logsumexp() function correctly handles large inputs.
10
+ a = np.arange(200)
11
+ desired = np.log(np.sum(np.exp(a)))
12
+ assert_almost_equal(logsumexp(a), desired)
13
+
14
+ # Now test with large numbers
15
+ b = [1000, 1000]
16
+ desired = 1000.0 + np.log(2.0)
17
+ assert_almost_equal(logsumexp(b), desired)
18
+
19
+ n = 1000
20
+ b = np.full(n, 10000, dtype='float64')
21
+ desired = 10000.0 + np.log(n)
22
+ assert_almost_equal(logsumexp(b), desired)
23
+
24
+ x = np.array([1e-40] * 1000000)
25
+ logx = np.log(x)
26
+
27
+ X = np.vstack([x, x])
28
+ logX = np.vstack([logx, logx])
29
+ assert_array_almost_equal(np.exp(logsumexp(logX)), X.sum())
30
+ assert_array_almost_equal(np.exp(logsumexp(logX, axis=0)), X.sum(axis=0))
31
+ assert_array_almost_equal(np.exp(logsumexp(logX, axis=1)), X.sum(axis=1))
32
+
33
+ # Handling special values properly
34
+ assert_equal(logsumexp(np.inf), np.inf)
35
+ assert_equal(logsumexp(-np.inf), -np.inf)
36
+ assert_equal(logsumexp(np.nan), np.nan)
37
+ assert_equal(logsumexp([-np.inf, -np.inf]), -np.inf)
38
+
39
+ # Handling an array with different magnitudes on the axes
40
+ assert_array_almost_equal(logsumexp([[1e10, 1e-10],
41
+ [-1e10, -np.inf]], axis=-1),
42
+ [1e10, -1e10])
43
+
44
+ # Test keeping dimensions
45
+ assert_array_almost_equal(logsumexp([[1e10, 1e-10],
46
+ [-1e10, -np.inf]],
47
+ axis=-1,
48
+ keepdims=True),
49
+ [[1e10], [-1e10]])
50
+
51
+ # Test multiple axes
52
+ assert_array_almost_equal(logsumexp([[1e10, 1e-10],
53
+ [-1e10, -np.inf]],
54
+ axis=(-1,-2)),
55
+ 1e10)
56
+
57
+
58
+ def test_logsumexp_b():
59
+ a = np.arange(200)
60
+ b = np.arange(200, 0, -1)
61
+ desired = np.log(np.sum(b*np.exp(a)))
62
+ assert_almost_equal(logsumexp(a, b=b), desired)
63
+
64
+ a = [1000, 1000]
65
+ b = [1.2, 1.2]
66
+ desired = 1000 + np.log(2 * 1.2)
67
+ assert_almost_equal(logsumexp(a, b=b), desired)
68
+
69
+ x = np.array([1e-40] * 100000)
70
+ b = np.linspace(1, 1000, 100000)
71
+ logx = np.log(x)
72
+
73
+ X = np.vstack((x, x))
74
+ logX = np.vstack((logx, logx))
75
+ B = np.vstack((b, b))
76
+ assert_array_almost_equal(np.exp(logsumexp(logX, b=B)), (B * X).sum())
77
+ assert_array_almost_equal(np.exp(logsumexp(logX, b=B, axis=0)),
78
+ (B * X).sum(axis=0))
79
+ assert_array_almost_equal(np.exp(logsumexp(logX, b=B, axis=1)),
80
+ (B * X).sum(axis=1))
81
+
82
+
83
+ def test_logsumexp_sign():
84
+ a = [1,1,1]
85
+ b = [1,-1,-1]
86
+
87
+ r, s = logsumexp(a, b=b, return_sign=True)
88
+ assert_almost_equal(r,1)
89
+ assert_equal(s,-1)
90
+
91
+
92
+ def test_logsumexp_sign_zero():
93
+ a = [1,1]
94
+ b = [1,-1]
95
+
96
+ r, s = logsumexp(a, b=b, return_sign=True)
97
+ assert_(not np.isfinite(r))
98
+ assert_(not np.isnan(r))
99
+ assert_(r < 0)
100
+ assert_equal(s,0)
101
+
102
+
103
+ def test_logsumexp_sign_shape():
104
+ a = np.ones((1,2,3,4))
105
+ b = np.ones_like(a)
106
+
107
+ r, s = logsumexp(a, axis=2, b=b, return_sign=True)
108
+
109
+ assert_equal(r.shape, s.shape)
110
+ assert_equal(r.shape, (1,2,4))
111
+
112
+ r, s = logsumexp(a, axis=(1,3), b=b, return_sign=True)
113
+
114
+ assert_equal(r.shape, s.shape)
115
+ assert_equal(r.shape, (1,3))
116
+
117
+
118
+ def test_logsumexp_complex_sign():
119
+ a = np.array([1 + 1j, 2 - 1j, -2 + 3j])
120
+
121
+ r, s = logsumexp(a, return_sign=True)
122
+
123
+ expected_sumexp = np.exp(a).sum()
124
+ # This is the numpy>=2.0 convention for np.sign
125
+ expected_sign = expected_sumexp / abs(expected_sumexp)
126
+
127
+ assert_allclose(s, expected_sign)
128
+ assert_allclose(s * np.exp(r), expected_sumexp)
129
+
130
+
131
+ def test_logsumexp_shape():
132
+ a = np.ones((1, 2, 3, 4))
133
+ b = np.ones_like(a)
134
+
135
+ r = logsumexp(a, axis=2, b=b)
136
+ assert_equal(r.shape, (1, 2, 4))
137
+
138
+ r = logsumexp(a, axis=(1, 3), b=b)
139
+ assert_equal(r.shape, (1, 3))
140
+
141
+
142
+ def test_logsumexp_b_zero():
143
+ a = [1,10000]
144
+ b = [1,0]
145
+
146
+ assert_almost_equal(logsumexp(a, b=b), 1)
147
+
148
+
149
+ def test_logsumexp_b_shape():
150
+ a = np.zeros((4,1,2,1))
151
+ b = np.ones((3,1,5))
152
+
153
+ logsumexp(a, b=b)
154
+
155
+
156
+ def test_softmax_fixtures():
157
+ assert_allclose(softmax([1000, 0, 0, 0]), np.array([1, 0, 0, 0]),
158
+ rtol=1e-13)
159
+ assert_allclose(softmax([1, 1]), np.array([.5, .5]), rtol=1e-13)
160
+ assert_allclose(softmax([0, 1]), np.array([1, np.e])/(1 + np.e),
161
+ rtol=1e-13)
162
+
163
+ # Expected value computed using mpmath (with mpmath.mp.dps = 200) and then
164
+ # converted to float.
165
+ x = np.arange(4)
166
+ expected = np.array([0.03205860328008499,
167
+ 0.08714431874203256,
168
+ 0.23688281808991013,
169
+ 0.6439142598879722])
170
+
171
+ assert_allclose(softmax(x), expected, rtol=1e-13)
172
+
173
+ # Translation property. If all the values are changed by the same amount,
174
+ # the softmax result does not change.
175
+ assert_allclose(softmax(x + 100), expected, rtol=1e-13)
176
+
177
+ # When axis=None, softmax operates on the entire array, and preserves
178
+ # the shape.
179
+ assert_allclose(softmax(x.reshape(2, 2)), expected.reshape(2, 2),
180
+ rtol=1e-13)
181
+
182
+
183
+ def test_softmax_multi_axes():
184
+ assert_allclose(softmax([[1000, 0], [1000, 0]], axis=0),
185
+ np.array([[.5, .5], [.5, .5]]), rtol=1e-13)
186
+ assert_allclose(softmax([[1000, 0], [1000, 0]], axis=1),
187
+ np.array([[1, 0], [1, 0]]), rtol=1e-13)
188
+
189
+ # Expected value computed using mpmath (with mpmath.mp.dps = 200) and then
190
+ # converted to float.
191
+ x = np.array([[-25, 0, 25, 50],
192
+ [1, 325, 749, 750]])
193
+ expected = np.array([[2.678636961770877e-33,
194
+ 1.9287498479371314e-22,
195
+ 1.3887943864771144e-11,
196
+ 0.999999999986112],
197
+ [0.0,
198
+ 1.9444526359919372e-185,
199
+ 0.2689414213699951,
200
+ 0.7310585786300048]])
201
+ assert_allclose(softmax(x, axis=1), expected, rtol=1e-13)
202
+ assert_allclose(softmax(x.T, axis=0), expected.T, rtol=1e-13)
203
+
204
+ # 3-d input, with a tuple for the axis.
205
+ x3d = x.reshape(2, 2, 2)
206
+ assert_allclose(softmax(x3d, axis=(1, 2)), expected.reshape(2, 2, 2),
207
+ rtol=1e-13)
.venv/Lib/site-packages/scipy/special/tests/test_mpmath.py ADDED
@@ -0,0 +1,2272 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Test SciPy functions versus mpmath, if available.
3
+
4
+ """
5
+ import numpy as np
6
+ from numpy.testing import assert_, assert_allclose
7
+ from numpy import pi
8
+ import pytest
9
+ import itertools
10
+
11
+ from scipy._lib import _pep440
12
+
13
+ import scipy.special as sc
14
+ from scipy.special._testutils import (
15
+ MissingModule, check_version, FuncData,
16
+ assert_func_equal)
17
+ from scipy.special._mptestutils import (
18
+ Arg, FixedArg, ComplexArg, IntArg, assert_mpmath_equal,
19
+ nonfunctional_tooslow, trace_args, time_limited, exception_to_nan,
20
+ inf_to_nan)
21
+ from scipy.special._ufuncs import (
22
+ _sinpi, _cospi, _lgam1p, _lanczos_sum_expg_scaled, _log1pmx,
23
+ _igam_fac)
24
+
25
+ try:
26
+ import mpmath
27
+ except ImportError:
28
+ mpmath = MissingModule('mpmath')
29
+
30
+
31
+ # ------------------------------------------------------------------------------
32
+ # expi
33
+ # ------------------------------------------------------------------------------
34
+
35
+ @check_version(mpmath, '0.10')
36
+ def test_expi_complex():
37
+ dataset = []
38
+ for r in np.logspace(-99, 2, 10):
39
+ for p in np.linspace(0, 2*np.pi, 30):
40
+ z = r*np.exp(1j*p)
41
+ dataset.append((z, complex(mpmath.ei(z))))
42
+ dataset = np.array(dataset, dtype=np.cdouble)
43
+
44
+ FuncData(sc.expi, dataset, 0, 1).check()
45
+
46
+
47
+ # ------------------------------------------------------------------------------
48
+ # expn
49
+ # ------------------------------------------------------------------------------
50
+
51
+ @check_version(mpmath, '0.19')
52
+ def test_expn_large_n():
53
+ # Test the transition to the asymptotic regime of n.
54
+ dataset = []
55
+ for n in [50, 51]:
56
+ for x in np.logspace(0, 4, 200):
57
+ with mpmath.workdps(100):
58
+ dataset.append((n, x, float(mpmath.expint(n, x))))
59
+ dataset = np.asarray(dataset)
60
+
61
+ FuncData(sc.expn, dataset, (0, 1), 2, rtol=1e-13).check()
62
+
63
+ # ------------------------------------------------------------------------------
64
+ # hyp0f1
65
+ # ------------------------------------------------------------------------------
66
+
67
+
68
+ @check_version(mpmath, '0.19')
69
+ def test_hyp0f1_gh5764():
70
+ # Do a small and somewhat systematic test that runs quickly
71
+ dataset = []
72
+ axis = [-99.5, -9.5, -0.5, 0.5, 9.5, 99.5]
73
+ for v in axis:
74
+ for x in axis:
75
+ for y in axis:
76
+ z = x + 1j*y
77
+ # mpmath computes the answer correctly at dps ~ 17 but
78
+ # fails for 20 < dps < 120 (uses a different method);
79
+ # set the dps high enough that this isn't an issue
80
+ with mpmath.workdps(120):
81
+ res = complex(mpmath.hyp0f1(v, z))
82
+ dataset.append((v, z, res))
83
+ dataset = np.array(dataset)
84
+
85
+ FuncData(lambda v, z: sc.hyp0f1(v.real, z), dataset, (0, 1), 2,
86
+ rtol=1e-13).check()
87
+
88
+
89
+ @check_version(mpmath, '0.19')
90
+ def test_hyp0f1_gh_1609():
91
+ # this is a regression test for gh-1609
92
+ vv = np.linspace(150, 180, 21)
93
+ af = sc.hyp0f1(vv, 0.5)
94
+ mf = np.array([mpmath.hyp0f1(v, 0.5) for v in vv])
95
+ assert_allclose(af, mf.astype(float), rtol=1e-12)
96
+
97
+
98
+ # ------------------------------------------------------------------------------
99
+ # hyperu
100
+ # ------------------------------------------------------------------------------
101
+
102
+ @check_version(mpmath, '1.1.0')
103
+ def test_hyperu_around_0():
104
+ dataset = []
105
+ # DLMF 13.2.14-15 test points.
106
+ for n in np.arange(-5, 5):
107
+ for b in np.linspace(-5, 5, 20):
108
+ a = -n
109
+ dataset.append((a, b, 0, float(mpmath.hyperu(a, b, 0))))
110
+ a = -n + b - 1
111
+ dataset.append((a, b, 0, float(mpmath.hyperu(a, b, 0))))
112
+ # DLMF 13.2.16-22 test points.
113
+ for a in [-10.5, -1.5, -0.5, 0, 0.5, 1, 10]:
114
+ for b in [-1.0, -0.5, 0, 0.5, 1, 1.5, 2, 2.5]:
115
+ dataset.append((a, b, 0, float(mpmath.hyperu(a, b, 0))))
116
+ dataset = np.array(dataset)
117
+
118
+ FuncData(sc.hyperu, dataset, (0, 1, 2), 3, rtol=1e-15, atol=5e-13).check()
119
+
120
+
121
+ # ------------------------------------------------------------------------------
122
+ # hyp2f1
123
+ # ------------------------------------------------------------------------------
124
+
125
+ @check_version(mpmath, '1.0.0')
126
+ def test_hyp2f1_strange_points():
127
+ pts = [
128
+ (2, -1, -1, 0.7), # expected: 2.4
129
+ (2, -2, -2, 0.7), # expected: 3.87
130
+ ]
131
+ pts += list(itertools.product([2, 1, -0.7, -1000], repeat=4))
132
+ pts = [
133
+ (a, b, c, x) for a, b, c, x in pts
134
+ if b == c and round(b) == b and b < 0 and b != -1000
135
+ ]
136
+ kw = dict(eliminate=True)
137
+ dataset = [p + (float(mpmath.hyp2f1(*p, **kw)),) for p in pts]
138
+ dataset = np.array(dataset, dtype=np.float64)
139
+
140
+ FuncData(sc.hyp2f1, dataset, (0,1,2,3), 4, rtol=1e-10).check()
141
+
142
+
143
+ @check_version(mpmath, '0.13')
144
+ def test_hyp2f1_real_some_points():
145
+ pts = [
146
+ (1, 2, 3, 0),
147
+ (1./3, 2./3, 5./6, 27./32),
148
+ (1./4, 1./2, 3./4, 80./81),
149
+ (2,-2, -3, 3),
150
+ (2, -3, -2, 3),
151
+ (2, -1.5, -1.5, 3),
152
+ (1, 2, 3, 0),
153
+ (0.7235, -1, -5, 0.3),
154
+ (0.25, 1./3, 2, 0.999),
155
+ (0.25, 1./3, 2, -1),
156
+ (2, 3, 5, 0.99),
157
+ (3./2, -0.5, 3, 0.99),
158
+ (2, 2.5, -3.25, 0.999),
159
+ (-8, 18.016500331508873, 10.805295997850628, 0.90875647507000001),
160
+ (-10, 900, -10.5, 0.99),
161
+ (-10, 900, 10.5, 0.99),
162
+ (-1, 2, 1, 1.0),
163
+ (-1, 2, 1, -1.0),
164
+ (-3, 13, 5, 1.0),
165
+ (-3, 13, 5, -1.0),
166
+ (0.5, 1 - 270.5, 1.5, 0.999**2), # from issue 1561
167
+ ]
168
+ dataset = [p + (float(mpmath.hyp2f1(*p)),) for p in pts]
169
+ dataset = np.array(dataset, dtype=np.float64)
170
+
171
+ with np.errstate(invalid='ignore'):
172
+ FuncData(sc.hyp2f1, dataset, (0,1,2,3), 4, rtol=1e-10).check()
173
+
174
+
175
+ @check_version(mpmath, '0.14')
176
+ def test_hyp2f1_some_points_2():
177
+ # Taken from mpmath unit tests -- this point failed for mpmath 0.13 but
178
+ # was fixed in their SVN since then
179
+ pts = [
180
+ (112, (51,10), (-9,10), -0.99999),
181
+ (10,-900,10.5,0.99),
182
+ (10,-900,-10.5,0.99),
183
+ ]
184
+
185
+ def fev(x):
186
+ if isinstance(x, tuple):
187
+ return float(x[0]) / x[1]
188
+ else:
189
+ return x
190
+
191
+ dataset = [tuple(map(fev, p)) + (float(mpmath.hyp2f1(*p)),) for p in pts]
192
+ dataset = np.array(dataset, dtype=np.float64)
193
+
194
+ FuncData(sc.hyp2f1, dataset, (0,1,2,3), 4, rtol=1e-10).check()
195
+
196
+
197
+ @check_version(mpmath, '0.13')
198
+ def test_hyp2f1_real_some():
199
+ dataset = []
200
+ for a in [-10, -5, -1.8, 1.8, 5, 10]:
201
+ for b in [-2.5, -1, 1, 7.4]:
202
+ for c in [-9, -1.8, 5, 20.4]:
203
+ for z in [-10, -1.01, -0.99, 0, 0.6, 0.95, 1.5, 10]:
204
+ try:
205
+ v = float(mpmath.hyp2f1(a, b, c, z))
206
+ except Exception:
207
+ continue
208
+ dataset.append((a, b, c, z, v))
209
+ dataset = np.array(dataset, dtype=np.float64)
210
+
211
+ with np.errstate(invalid='ignore'):
212
+ FuncData(sc.hyp2f1, dataset, (0,1,2,3), 4, rtol=1e-9,
213
+ ignore_inf_sign=True).check()
214
+
215
+
216
+ @check_version(mpmath, '0.12')
217
+ @pytest.mark.slow
218
+ def test_hyp2f1_real_random():
219
+ npoints = 500
220
+ dataset = np.zeros((npoints, 5), np.float64)
221
+
222
+ np.random.seed(1234)
223
+ dataset[:, 0] = np.random.pareto(1.5, npoints)
224
+ dataset[:, 1] = np.random.pareto(1.5, npoints)
225
+ dataset[:, 2] = np.random.pareto(1.5, npoints)
226
+ dataset[:, 3] = 2*np.random.rand(npoints) - 1
227
+
228
+ dataset[:, 0] *= (-1)**np.random.randint(2, npoints)
229
+ dataset[:, 1] *= (-1)**np.random.randint(2, npoints)
230
+ dataset[:, 2] *= (-1)**np.random.randint(2, npoints)
231
+
232
+ for ds in dataset:
233
+ if mpmath.__version__ < '0.14':
234
+ # mpmath < 0.14 fails for c too much smaller than a, b
235
+ if abs(ds[:2]).max() > abs(ds[2]):
236
+ ds[2] = abs(ds[:2]).max()
237
+ ds[4] = float(mpmath.hyp2f1(*tuple(ds[:4])))
238
+
239
+ FuncData(sc.hyp2f1, dataset, (0, 1, 2, 3), 4, rtol=1e-9).check()
240
+
241
+
242
+ # ------------------------------------------------------------------------------
243
+ # erf (complex)
244
+ # ------------------------------------------------------------------------------
245
+
246
+ @check_version(mpmath, '0.14')
247
+ def test_erf_complex():
248
+ # need to increase mpmath precision for this test
249
+ old_dps, old_prec = mpmath.mp.dps, mpmath.mp.prec
250
+ try:
251
+ mpmath.mp.dps = 70
252
+ x1, y1 = np.meshgrid(np.linspace(-10, 1, 31), np.linspace(-10, 1, 11))
253
+ x2, y2 = np.meshgrid(np.logspace(-80, .8, 31), np.logspace(-80, .8, 11))
254
+ points = np.r_[x1.ravel(),x2.ravel()] + 1j*np.r_[y1.ravel(), y2.ravel()]
255
+
256
+ assert_func_equal(sc.erf, lambda x: complex(mpmath.erf(x)), points,
257
+ vectorized=False, rtol=1e-13)
258
+ assert_func_equal(sc.erfc, lambda x: complex(mpmath.erfc(x)), points,
259
+ vectorized=False, rtol=1e-13)
260
+ finally:
261
+ mpmath.mp.dps, mpmath.mp.prec = old_dps, old_prec
262
+
263
+
264
+ # ------------------------------------------------------------------------------
265
+ # lpmv
266
+ # ------------------------------------------------------------------------------
267
+
268
+ @check_version(mpmath, '0.15')
269
+ def test_lpmv():
270
+ pts = []
271
+ for x in [-0.99, -0.557, 1e-6, 0.132, 1]:
272
+ pts.extend([
273
+ (1, 1, x),
274
+ (1, -1, x),
275
+ (-1, 1, x),
276
+ (-1, -2, x),
277
+ (1, 1.7, x),
278
+ (1, -1.7, x),
279
+ (-1, 1.7, x),
280
+ (-1, -2.7, x),
281
+ (1, 10, x),
282
+ (1, 11, x),
283
+ (3, 8, x),
284
+ (5, 11, x),
285
+ (-3, 8, x),
286
+ (-5, 11, x),
287
+ (3, -8, x),
288
+ (5, -11, x),
289
+ (-3, -8, x),
290
+ (-5, -11, x),
291
+ (3, 8.3, x),
292
+ (5, 11.3, x),
293
+ (-3, 8.3, x),
294
+ (-5, 11.3, x),
295
+ (3, -8.3, x),
296
+ (5, -11.3, x),
297
+ (-3, -8.3, x),
298
+ (-5, -11.3, x),
299
+ ])
300
+
301
+ def mplegenp(nu, mu, x):
302
+ if mu == int(mu) and x == 1:
303
+ # mpmath 0.17 gets this wrong
304
+ if mu == 0:
305
+ return 1
306
+ else:
307
+ return 0
308
+ return mpmath.legenp(nu, mu, x)
309
+
310
+ dataset = [p + (mplegenp(p[1], p[0], p[2]),) for p in pts]
311
+ dataset = np.array(dataset, dtype=np.float64)
312
+
313
+ def evf(mu, nu, x):
314
+ return sc.lpmv(mu.astype(int), nu, x)
315
+
316
+ with np.errstate(invalid='ignore'):
317
+ FuncData(evf, dataset, (0,1,2), 3, rtol=1e-10, atol=1e-14).check()
318
+
319
+
320
+ # ------------------------------------------------------------------------------
321
+ # beta
322
+ # ------------------------------------------------------------------------------
323
+
324
+ @check_version(mpmath, '0.15')
325
+ def test_beta():
326
+ np.random.seed(1234)
327
+
328
+ b = np.r_[np.logspace(-200, 200, 4),
329
+ np.logspace(-10, 10, 4),
330
+ np.logspace(-1, 1, 4),
331
+ np.arange(-10, 11, 1),
332
+ np.arange(-10, 11, 1) + 0.5,
333
+ -1, -2.3, -3, -100.3, -10003.4]
334
+ a = b
335
+
336
+ ab = np.array(np.broadcast_arrays(a[:,None], b[None,:])).reshape(2, -1).T
337
+
338
+ old_dps, old_prec = mpmath.mp.dps, mpmath.mp.prec
339
+ try:
340
+ mpmath.mp.dps = 400
341
+
342
+ assert_func_equal(sc.beta,
343
+ lambda a, b: float(mpmath.beta(a, b)),
344
+ ab,
345
+ vectorized=False,
346
+ rtol=1e-10,
347
+ ignore_inf_sign=True)
348
+
349
+ assert_func_equal(
350
+ sc.betaln,
351
+ lambda a, b: float(mpmath.log(abs(mpmath.beta(a, b)))),
352
+ ab,
353
+ vectorized=False,
354
+ rtol=1e-10)
355
+ finally:
356
+ mpmath.mp.dps, mpmath.mp.prec = old_dps, old_prec
357
+
358
+
359
+ # ------------------------------------------------------------------------------
360
+ # loggamma
361
+ # ------------------------------------------------------------------------------
362
+
363
+ LOGGAMMA_TAYLOR_RADIUS = 0.2
364
+
365
+
366
+ @check_version(mpmath, '0.19')
367
+ def test_loggamma_taylor_transition():
368
+ # Make sure there isn't a big jump in accuracy when we move from
369
+ # using the Taylor series to using the recurrence relation.
370
+
371
+ r = LOGGAMMA_TAYLOR_RADIUS + np.array([-0.1, -0.01, 0, 0.01, 0.1])
372
+ theta = np.linspace(0, 2*np.pi, 20)
373
+ r, theta = np.meshgrid(r, theta)
374
+ dz = r*np.exp(1j*theta)
375
+ z = np.r_[1 + dz, 2 + dz].flatten()
376
+
377
+ dataset = [(z0, complex(mpmath.loggamma(z0))) for z0 in z]
378
+ dataset = np.array(dataset)
379
+
380
+ FuncData(sc.loggamma, dataset, 0, 1, rtol=5e-14).check()
381
+
382
+
383
+ @check_version(mpmath, '0.19')
384
+ def test_loggamma_taylor():
385
+ # Test around the zeros at z = 1, 2.
386
+
387
+ r = np.logspace(-16, np.log10(LOGGAMMA_TAYLOR_RADIUS), 10)
388
+ theta = np.linspace(0, 2*np.pi, 20)
389
+ r, theta = np.meshgrid(r, theta)
390
+ dz = r*np.exp(1j*theta)
391
+ z = np.r_[1 + dz, 2 + dz].flatten()
392
+
393
+ dataset = [(z0, complex(mpmath.loggamma(z0))) for z0 in z]
394
+ dataset = np.array(dataset)
395
+
396
+ FuncData(sc.loggamma, dataset, 0, 1, rtol=5e-14).check()
397
+
398
+
399
+ # ------------------------------------------------------------------------------
400
+ # rgamma
401
+ # ------------------------------------------------------------------------------
402
+
403
+ @check_version(mpmath, '0.19')
404
+ @pytest.mark.slow
405
+ def test_rgamma_zeros():
406
+ # Test around the zeros at z = 0, -1, -2, ..., -169. (After -169 we
407
+ # get values that are out of floating point range even when we're
408
+ # within 0.1 of the zero.)
409
+
410
+ # Can't use too many points here or the test takes forever.
411
+ dx = np.r_[-np.logspace(-1, -13, 3), 0, np.logspace(-13, -1, 3)]
412
+ dy = dx.copy()
413
+ dx, dy = np.meshgrid(dx, dy)
414
+ dz = dx + 1j*dy
415
+ zeros = np.arange(0, -170, -1).reshape(1, 1, -1)
416
+ z = (zeros + np.dstack((dz,)*zeros.size)).flatten()
417
+ with mpmath.workdps(100):
418
+ dataset = [(z0, complex(mpmath.rgamma(z0))) for z0 in z]
419
+
420
+ dataset = np.array(dataset)
421
+ FuncData(sc.rgamma, dataset, 0, 1, rtol=1e-12).check()
422
+
423
+
424
+ # ------------------------------------------------------------------------------
425
+ # digamma
426
+ # ------------------------------------------------------------------------------
427
+
428
+ @check_version(mpmath, '0.19')
429
+ @pytest.mark.slow
430
+ def test_digamma_roots():
431
+ # Test the special-cased roots for digamma.
432
+ root = mpmath.findroot(mpmath.digamma, 1.5)
433
+ roots = [float(root)]
434
+ root = mpmath.findroot(mpmath.digamma, -0.5)
435
+ roots.append(float(root))
436
+ roots = np.array(roots)
437
+
438
+ # If we test beyond a radius of 0.24 mpmath will take forever.
439
+ dx = np.r_[-0.24, -np.logspace(-1, -15, 10), 0, np.logspace(-15, -1, 10), 0.24]
440
+ dy = dx.copy()
441
+ dx, dy = np.meshgrid(dx, dy)
442
+ dz = dx + 1j*dy
443
+ z = (roots + np.dstack((dz,)*roots.size)).flatten()
444
+ with mpmath.workdps(30):
445
+ dataset = [(z0, complex(mpmath.digamma(z0))) for z0 in z]
446
+
447
+ dataset = np.array(dataset)
448
+ FuncData(sc.digamma, dataset, 0, 1, rtol=1e-14).check()
449
+
450
+
451
+ @check_version(mpmath, '0.19')
452
+ def test_digamma_negreal():
453
+ # Test digamma around the negative real axis. Don't do this in
454
+ # TestSystematic because the points need some jiggering so that
455
+ # mpmath doesn't take forever.
456
+
457
+ digamma = exception_to_nan(mpmath.digamma)
458
+
459
+ x = -np.logspace(300, -30, 100)
460
+ y = np.r_[-np.logspace(0, -3, 5), 0, np.logspace(-3, 0, 5)]
461
+ x, y = np.meshgrid(x, y)
462
+ z = (x + 1j*y).flatten()
463
+
464
+ with mpmath.workdps(40):
465
+ dataset = [(z0, complex(digamma(z0))) for z0 in z]
466
+ dataset = np.asarray(dataset)
467
+
468
+ FuncData(sc.digamma, dataset, 0, 1, rtol=1e-13).check()
469
+
470
+
471
+ @check_version(mpmath, '0.19')
472
+ def test_digamma_boundary():
473
+ # Check that there isn't a jump in accuracy when we switch from
474
+ # using the asymptotic series to the reflection formula.
475
+
476
+ x = -np.logspace(300, -30, 100)
477
+ y = np.array([-6.1, -5.9, 5.9, 6.1])
478
+ x, y = np.meshgrid(x, y)
479
+ z = (x + 1j*y).flatten()
480
+
481
+ with mpmath.workdps(30):
482
+ dataset = [(z0, complex(mpmath.digamma(z0))) for z0 in z]
483
+ dataset = np.asarray(dataset)
484
+
485
+ FuncData(sc.digamma, dataset, 0, 1, rtol=1e-13).check()
486
+
487
+
488
+ # ------------------------------------------------------------------------------
489
+ # gammainc
490
+ # ------------------------------------------------------------------------------
491
+
492
+ @check_version(mpmath, '0.19')
493
+ @pytest.mark.slow
494
+ def test_gammainc_boundary():
495
+ # Test the transition to the asymptotic series.
496
+ small = 20
497
+ a = np.linspace(0.5*small, 2*small, 50)
498
+ x = a.copy()
499
+ a, x = np.meshgrid(a, x)
500
+ a, x = a.flatten(), x.flatten()
501
+ with mpmath.workdps(100):
502
+ dataset = [(a0, x0, float(mpmath.gammainc(a0, b=x0, regularized=True)))
503
+ for a0, x0 in zip(a, x)]
504
+ dataset = np.array(dataset)
505
+
506
+ FuncData(sc.gammainc, dataset, (0, 1), 2, rtol=1e-12).check()
507
+
508
+
509
+ # ------------------------------------------------------------------------------
510
+ # spence
511
+ # ------------------------------------------------------------------------------
512
+
513
+ @check_version(mpmath, '0.19')
514
+ @pytest.mark.slow
515
+ def test_spence_circle():
516
+ # The trickiest region for spence is around the circle |z - 1| = 1,
517
+ # so test that region carefully.
518
+
519
+ def spence(z):
520
+ return complex(mpmath.polylog(2, 1 - z))
521
+
522
+ r = np.linspace(0.5, 1.5)
523
+ theta = np.linspace(0, 2*pi)
524
+ z = (1 + np.outer(r, np.exp(1j*theta))).flatten()
525
+ dataset = np.asarray([(z0, spence(z0)) for z0 in z])
526
+
527
+ FuncData(sc.spence, dataset, 0, 1, rtol=1e-14).check()
528
+
529
+
530
+ # ------------------------------------------------------------------------------
531
+ # sinpi and cospi
532
+ # ------------------------------------------------------------------------------
533
+
534
+ @check_version(mpmath, '0.19')
535
+ def test_sinpi_zeros():
536
+ eps = np.finfo(float).eps
537
+ dx = np.r_[-np.logspace(0, -13, 3), 0, np.logspace(-13, 0, 3)]
538
+ dy = dx.copy()
539
+ dx, dy = np.meshgrid(dx, dy)
540
+ dz = dx + 1j*dy
541
+ zeros = np.arange(-100, 100, 1).reshape(1, 1, -1)
542
+ z = (zeros + np.dstack((dz,)*zeros.size)).flatten()
543
+ dataset = np.asarray([(z0, complex(mpmath.sinpi(z0)))
544
+ for z0 in z])
545
+ FuncData(_sinpi, dataset, 0, 1, rtol=2*eps).check()
546
+
547
+
548
+ @check_version(mpmath, '0.19')
549
+ def test_cospi_zeros():
550
+ eps = np.finfo(float).eps
551
+ dx = np.r_[-np.logspace(0, -13, 3), 0, np.logspace(-13, 0, 3)]
552
+ dy = dx.copy()
553
+ dx, dy = np.meshgrid(dx, dy)
554
+ dz = dx + 1j*dy
555
+ zeros = (np.arange(-100, 100, 1) + 0.5).reshape(1, 1, -1)
556
+ z = (zeros + np.dstack((dz,)*zeros.size)).flatten()
557
+ dataset = np.asarray([(z0, complex(mpmath.cospi(z0)))
558
+ for z0 in z])
559
+
560
+ FuncData(_cospi, dataset, 0, 1, rtol=2*eps).check()
561
+
562
+
563
+ # ------------------------------------------------------------------------------
564
+ # ellipj
565
+ # ------------------------------------------------------------------------------
566
+
567
+ @check_version(mpmath, '0.19')
568
+ def test_dn_quarter_period():
569
+ def dn(u, m):
570
+ return sc.ellipj(u, m)[2]
571
+
572
+ def mpmath_dn(u, m):
573
+ return float(mpmath.ellipfun("dn", u=u, m=m))
574
+
575
+ m = np.linspace(0, 1, 20)
576
+ du = np.r_[-np.logspace(-1, -15, 10), 0, np.logspace(-15, -1, 10)]
577
+ dataset = []
578
+ for m0 in m:
579
+ u0 = float(mpmath.ellipk(m0))
580
+ for du0 in du:
581
+ p = u0 + du0
582
+ dataset.append((p, m0, mpmath_dn(p, m0)))
583
+ dataset = np.asarray(dataset)
584
+
585
+ FuncData(dn, dataset, (0, 1), 2, rtol=1e-10).check()
586
+
587
+
588
+ # ------------------------------------------------------------------------------
589
+ # Wright Omega
590
+ # ------------------------------------------------------------------------------
591
+
592
+ def _mpmath_wrightomega(z, dps):
593
+ with mpmath.workdps(dps):
594
+ z = mpmath.mpc(z)
595
+ unwind = mpmath.ceil((z.imag - mpmath.pi)/(2*mpmath.pi))
596
+ res = mpmath.lambertw(mpmath.exp(z), unwind)
597
+ return res
598
+
599
+
600
+ @pytest.mark.slow
601
+ @check_version(mpmath, '0.19')
602
+ def test_wrightomega_branch():
603
+ x = -np.logspace(10, 0, 25)
604
+ picut_above = [np.nextafter(np.pi, np.inf)]
605
+ picut_below = [np.nextafter(np.pi, -np.inf)]
606
+ npicut_above = [np.nextafter(-np.pi, np.inf)]
607
+ npicut_below = [np.nextafter(-np.pi, -np.inf)]
608
+ for i in range(50):
609
+ picut_above.append(np.nextafter(picut_above[-1], np.inf))
610
+ picut_below.append(np.nextafter(picut_below[-1], -np.inf))
611
+ npicut_above.append(np.nextafter(npicut_above[-1], np.inf))
612
+ npicut_below.append(np.nextafter(npicut_below[-1], -np.inf))
613
+ y = np.hstack((picut_above, picut_below, npicut_above, npicut_below))
614
+ x, y = np.meshgrid(x, y)
615
+ z = (x + 1j*y).flatten()
616
+
617
+ dataset = np.asarray([(z0, complex(_mpmath_wrightomega(z0, 25)))
618
+ for z0 in z])
619
+
620
+ FuncData(sc.wrightomega, dataset, 0, 1, rtol=1e-8).check()
621
+
622
+
623
+ @pytest.mark.slow
624
+ @check_version(mpmath, '0.19')
625
+ def test_wrightomega_region1():
626
+ # This region gets less coverage in the TestSystematic test
627
+ x = np.linspace(-2, 1)
628
+ y = np.linspace(1, 2*np.pi)
629
+ x, y = np.meshgrid(x, y)
630
+ z = (x + 1j*y).flatten()
631
+
632
+ dataset = np.asarray([(z0, complex(_mpmath_wrightomega(z0, 25)))
633
+ for z0 in z])
634
+
635
+ FuncData(sc.wrightomega, dataset, 0, 1, rtol=1e-15).check()
636
+
637
+
638
+ @pytest.mark.slow
639
+ @check_version(mpmath, '0.19')
640
+ def test_wrightomega_region2():
641
+ # This region gets less coverage in the TestSystematic test
642
+ x = np.linspace(-2, 1)
643
+ y = np.linspace(-2*np.pi, -1)
644
+ x, y = np.meshgrid(x, y)
645
+ z = (x + 1j*y).flatten()
646
+
647
+ dataset = np.asarray([(z0, complex(_mpmath_wrightomega(z0, 25)))
648
+ for z0 in z])
649
+
650
+ FuncData(sc.wrightomega, dataset, 0, 1, rtol=1e-15).check()
651
+
652
+
653
+ # ------------------------------------------------------------------------------
654
+ # lambertw
655
+ # ------------------------------------------------------------------------------
656
+
657
+ @pytest.mark.slow
658
+ @check_version(mpmath, '0.19')
659
+ def test_lambertw_smallz():
660
+ x, y = np.linspace(-1, 1, 25), np.linspace(-1, 1, 25)
661
+ x, y = np.meshgrid(x, y)
662
+ z = (x + 1j*y).flatten()
663
+
664
+ dataset = np.asarray([(z0, complex(mpmath.lambertw(z0)))
665
+ for z0 in z])
666
+
667
+ FuncData(sc.lambertw, dataset, 0, 1, rtol=1e-13).check()
668
+
669
+
670
+ # ------------------------------------------------------------------------------
671
+ # Systematic tests
672
+ # ------------------------------------------------------------------------------
673
+
674
+ HYPERKW = dict(maxprec=200, maxterms=200)
675
+
676
+
677
+ @pytest.mark.slow
678
+ @check_version(mpmath, '0.17')
679
+ class TestSystematic:
680
+
681
+ def test_airyai(self):
682
+ # oscillating function, limit range
683
+ assert_mpmath_equal(lambda z: sc.airy(z)[0],
684
+ mpmath.airyai,
685
+ [Arg(-1e8, 1e8)],
686
+ rtol=1e-5)
687
+ assert_mpmath_equal(lambda z: sc.airy(z)[0],
688
+ mpmath.airyai,
689
+ [Arg(-1e3, 1e3)])
690
+
691
+ def test_airyai_complex(self):
692
+ assert_mpmath_equal(lambda z: sc.airy(z)[0],
693
+ mpmath.airyai,
694
+ [ComplexArg()])
695
+
696
+ def test_airyai_prime(self):
697
+ # oscillating function, limit range
698
+ assert_mpmath_equal(lambda z: sc.airy(z)[1], lambda z:
699
+ mpmath.airyai(z, derivative=1),
700
+ [Arg(-1e8, 1e8)],
701
+ rtol=1e-5)
702
+ assert_mpmath_equal(lambda z: sc.airy(z)[1], lambda z:
703
+ mpmath.airyai(z, derivative=1),
704
+ [Arg(-1e3, 1e3)])
705
+
706
+ def test_airyai_prime_complex(self):
707
+ assert_mpmath_equal(lambda z: sc.airy(z)[1], lambda z:
708
+ mpmath.airyai(z, derivative=1),
709
+ [ComplexArg()])
710
+
711
+ def test_airybi(self):
712
+ # oscillating function, limit range
713
+ assert_mpmath_equal(lambda z: sc.airy(z)[2], lambda z:
714
+ mpmath.airybi(z),
715
+ [Arg(-1e8, 1e8)],
716
+ rtol=1e-5)
717
+ assert_mpmath_equal(lambda z: sc.airy(z)[2], lambda z:
718
+ mpmath.airybi(z),
719
+ [Arg(-1e3, 1e3)])
720
+
721
+ def test_airybi_complex(self):
722
+ assert_mpmath_equal(lambda z: sc.airy(z)[2], lambda z:
723
+ mpmath.airybi(z),
724
+ [ComplexArg()])
725
+
726
+ def test_airybi_prime(self):
727
+ # oscillating function, limit range
728
+ assert_mpmath_equal(lambda z: sc.airy(z)[3], lambda z:
729
+ mpmath.airybi(z, derivative=1),
730
+ [Arg(-1e8, 1e8)],
731
+ rtol=1e-5)
732
+ assert_mpmath_equal(lambda z: sc.airy(z)[3], lambda z:
733
+ mpmath.airybi(z, derivative=1),
734
+ [Arg(-1e3, 1e3)])
735
+
736
+ def test_airybi_prime_complex(self):
737
+ assert_mpmath_equal(lambda z: sc.airy(z)[3], lambda z:
738
+ mpmath.airybi(z, derivative=1),
739
+ [ComplexArg()])
740
+
741
+ def test_bei(self):
742
+ assert_mpmath_equal(sc.bei,
743
+ exception_to_nan(lambda z: mpmath.bei(0, z, **HYPERKW)),
744
+ [Arg(-1e3, 1e3)])
745
+
746
+ def test_ber(self):
747
+ assert_mpmath_equal(sc.ber,
748
+ exception_to_nan(lambda z: mpmath.ber(0, z, **HYPERKW)),
749
+ [Arg(-1e3, 1e3)])
750
+
751
+ def test_bernoulli(self):
752
+ assert_mpmath_equal(lambda n: sc.bernoulli(int(n))[int(n)],
753
+ lambda n: float(mpmath.bernoulli(int(n))),
754
+ [IntArg(0, 13000)],
755
+ rtol=1e-9, n=13000)
756
+
757
+ def test_besseli(self):
758
+ assert_mpmath_equal(
759
+ sc.iv,
760
+ exception_to_nan(lambda v, z: mpmath.besseli(v, z, **HYPERKW)),
761
+ [Arg(-1e100, 1e100), Arg()],
762
+ atol=1e-270,
763
+ )
764
+
765
+ def test_besseli_complex(self):
766
+ assert_mpmath_equal(
767
+ lambda v, z: sc.iv(v.real, z),
768
+ exception_to_nan(lambda v, z: mpmath.besseli(v, z, **HYPERKW)),
769
+ [Arg(-1e100, 1e100), ComplexArg()],
770
+ )
771
+
772
+ def test_besselj(self):
773
+ assert_mpmath_equal(
774
+ sc.jv,
775
+ exception_to_nan(lambda v, z: mpmath.besselj(v, z, **HYPERKW)),
776
+ [Arg(-1e100, 1e100), Arg(-1e3, 1e3)],
777
+ ignore_inf_sign=True,
778
+ )
779
+
780
+ # loss of precision at large arguments due to oscillation
781
+ assert_mpmath_equal(
782
+ sc.jv,
783
+ exception_to_nan(lambda v, z: mpmath.besselj(v, z, **HYPERKW)),
784
+ [Arg(-1e100, 1e100), Arg(-1e8, 1e8)],
785
+ ignore_inf_sign=True,
786
+ rtol=1e-5,
787
+ )
788
+
789
+ def test_besselj_complex(self):
790
+ assert_mpmath_equal(
791
+ lambda v, z: sc.jv(v.real, z),
792
+ exception_to_nan(lambda v, z: mpmath.besselj(v, z, **HYPERKW)),
793
+ [Arg(), ComplexArg()]
794
+ )
795
+
796
+ def test_besselk(self):
797
+ assert_mpmath_equal(
798
+ sc.kv,
799
+ mpmath.besselk,
800
+ [Arg(-200, 200), Arg(0, np.inf)],
801
+ nan_ok=False,
802
+ rtol=1e-12,
803
+ )
804
+
805
+ def test_besselk_int(self):
806
+ assert_mpmath_equal(
807
+ sc.kn,
808
+ mpmath.besselk,
809
+ [IntArg(-200, 200), Arg(0, np.inf)],
810
+ nan_ok=False,
811
+ rtol=1e-12,
812
+ )
813
+
814
+ def test_besselk_complex(self):
815
+ assert_mpmath_equal(
816
+ lambda v, z: sc.kv(v.real, z),
817
+ exception_to_nan(lambda v, z: mpmath.besselk(v, z, **HYPERKW)),
818
+ [Arg(-1e100, 1e100), ComplexArg()],
819
+ )
820
+
821
+ def test_bessely(self):
822
+ def mpbessely(v, x):
823
+ r = float(mpmath.bessely(v, x, **HYPERKW))
824
+ if abs(r) > 1e305:
825
+ # overflowing to inf a bit earlier is OK
826
+ r = np.inf * np.sign(r)
827
+ if abs(r) == 0 and x == 0:
828
+ # invalid result from mpmath, point x=0 is a divergence
829
+ return np.nan
830
+ return r
831
+ assert_mpmath_equal(
832
+ sc.yv,
833
+ exception_to_nan(mpbessely),
834
+ [Arg(-1e100, 1e100), Arg(-1e8, 1e8)],
835
+ n=5000,
836
+ )
837
+
838
+ def test_bessely_complex(self):
839
+ def mpbessely(v, x):
840
+ r = complex(mpmath.bessely(v, x, **HYPERKW))
841
+ if abs(r) > 1e305:
842
+ # overflowing to inf a bit earlier is OK
843
+ with np.errstate(invalid='ignore'):
844
+ r = np.inf * np.sign(r)
845
+ return r
846
+ assert_mpmath_equal(
847
+ lambda v, z: sc.yv(v.real, z),
848
+ exception_to_nan(mpbessely),
849
+ [Arg(), ComplexArg()],
850
+ n=15000,
851
+ )
852
+
853
+ def test_bessely_int(self):
854
+ def mpbessely(v, x):
855
+ r = float(mpmath.bessely(v, x))
856
+ if abs(r) == 0 and x == 0:
857
+ # invalid result from mpmath, point x=0 is a divergence
858
+ return np.nan
859
+ return r
860
+ assert_mpmath_equal(
861
+ lambda v, z: sc.yn(int(v), z),
862
+ exception_to_nan(mpbessely),
863
+ [IntArg(-1000, 1000), Arg(-1e8, 1e8)],
864
+ )
865
+
866
+ def test_beta(self):
867
+ bad_points = []
868
+
869
+ def beta(a, b, nonzero=False):
870
+ if a < -1e12 or b < -1e12:
871
+ # Function is defined here only at integers, but due
872
+ # to loss of precision this is numerically
873
+ # ill-defined. Don't compare values here.
874
+ return np.nan
875
+ if (a < 0 or b < 0) and (abs(float(a + b)) % 1) == 0:
876
+ # close to a zero of the function: mpmath and scipy
877
+ # will not round here the same, so the test needs to be
878
+ # run with an absolute tolerance
879
+ if nonzero:
880
+ bad_points.append((float(a), float(b)))
881
+ return np.nan
882
+ return mpmath.beta(a, b)
883
+
884
+ assert_mpmath_equal(
885
+ sc.beta,
886
+ lambda a, b: beta(a, b, nonzero=True),
887
+ [Arg(), Arg()],
888
+ dps=400,
889
+ ignore_inf_sign=True,
890
+ )
891
+
892
+ assert_mpmath_equal(
893
+ sc.beta,
894
+ beta,
895
+ np.array(bad_points),
896
+ dps=400,
897
+ ignore_inf_sign=True,
898
+ atol=1e-11,
899
+ )
900
+
901
+ def test_betainc(self):
902
+ assert_mpmath_equal(
903
+ sc.betainc,
904
+ time_limited()(
905
+ exception_to_nan(
906
+ lambda a, b, x: mpmath.betainc(a, b, 0, x, regularized=True)
907
+ )
908
+ ),
909
+ [Arg(), Arg(), Arg()],
910
+ )
911
+
912
+ def test_betaincc(self):
913
+ assert_mpmath_equal(
914
+ sc.betaincc,
915
+ time_limited()(
916
+ exception_to_nan(
917
+ lambda a, b, x: mpmath.betainc(a, b, x, 1, regularized=True)
918
+ )
919
+ ),
920
+ [Arg(), Arg(), Arg()],
921
+ dps=400,
922
+ )
923
+
924
+ def test_binom(self):
925
+ bad_points = []
926
+
927
+ def binomial(n, k, nonzero=False):
928
+ if abs(k) > 1e8*(abs(n) + 1):
929
+ # The binomial is rapidly oscillating in this region,
930
+ # and the function is numerically ill-defined. Don't
931
+ # compare values here.
932
+ return np.nan
933
+ if n < k and abs(float(n-k) - np.round(float(n-k))) < 1e-15:
934
+ # close to a zero of the function: mpmath and scipy
935
+ # will not round here the same, so the test needs to be
936
+ # run with an absolute tolerance
937
+ if nonzero:
938
+ bad_points.append((float(n), float(k)))
939
+ return np.nan
940
+ return mpmath.binomial(n, k)
941
+
942
+ assert_mpmath_equal(
943
+ sc.binom,
944
+ lambda n, k: binomial(n, k, nonzero=True),
945
+ [Arg(), Arg()],
946
+ dps=400,
947
+ )
948
+
949
+ assert_mpmath_equal(
950
+ sc.binom,
951
+ binomial,
952
+ np.array(bad_points),
953
+ dps=400,
954
+ atol=1e-14,
955
+ )
956
+
957
+ def test_chebyt_int(self):
958
+ assert_mpmath_equal(
959
+ lambda n, x: sc.eval_chebyt(int(n), x),
960
+ exception_to_nan(lambda n, x: mpmath.chebyt(n, x, **HYPERKW)),
961
+ [IntArg(), Arg()],
962
+ dps=50,
963
+ )
964
+
965
+ @pytest.mark.xfail(run=False, reason="some cases in hyp2f1 not fully accurate")
966
+ def test_chebyt(self):
967
+ assert_mpmath_equal(
968
+ sc.eval_chebyt,
969
+ lambda n, x: time_limited()(
970
+ exception_to_nan(mpmath.chebyt)
971
+ )(n, x, **HYPERKW),
972
+ [Arg(-101, 101), Arg()],
973
+ n=10000,
974
+ )
975
+
976
+ def test_chebyu_int(self):
977
+ assert_mpmath_equal(
978
+ lambda n, x: sc.eval_chebyu(int(n), x),
979
+ exception_to_nan(lambda n, x: mpmath.chebyu(n, x, **HYPERKW)),
980
+ [IntArg(), Arg()],
981
+ dps=50,
982
+ )
983
+
984
+ @pytest.mark.xfail(run=False, reason="some cases in hyp2f1 not fully accurate")
985
+ def test_chebyu(self):
986
+ assert_mpmath_equal(
987
+ sc.eval_chebyu,
988
+ lambda n, x: time_limited()(
989
+ exception_to_nan(mpmath.chebyu)
990
+ )(n, x, **HYPERKW),
991
+ [Arg(-101, 101), Arg()],
992
+ )
993
+
994
+ def test_chi(self):
995
+ def chi(x):
996
+ return sc.shichi(x)[1]
997
+ assert_mpmath_equal(chi, mpmath.chi, [Arg()])
998
+ # check asymptotic series cross-over
999
+ assert_mpmath_equal(chi, mpmath.chi, [FixedArg([88 - 1e-9, 88, 88 + 1e-9])])
1000
+
1001
+ def test_chi_complex(self):
1002
+ def chi(z):
1003
+ return sc.shichi(z)[1]
1004
+ # chi oscillates as Im[z] -> +- inf, so limit range
1005
+ assert_mpmath_equal(
1006
+ chi,
1007
+ mpmath.chi,
1008
+ [ComplexArg(complex(-np.inf, -1e8), complex(np.inf, 1e8))],
1009
+ rtol=1e-12,
1010
+ )
1011
+
1012
+ def test_ci(self):
1013
+ def ci(x):
1014
+ return sc.sici(x)[1]
1015
+ # oscillating function: limit range
1016
+ assert_mpmath_equal(ci, mpmath.ci, [Arg(-1e8, 1e8)])
1017
+
1018
+ def test_ci_complex(self):
1019
+ def ci(z):
1020
+ return sc.sici(z)[1]
1021
+ # ci oscillates as Re[z] -> +- inf, so limit range
1022
+ assert_mpmath_equal(
1023
+ ci,
1024
+ mpmath.ci,
1025
+ [ComplexArg(complex(-1e8, -np.inf), complex(1e8, np.inf))],
1026
+ rtol=1e-8,
1027
+ )
1028
+
1029
+ def test_cospi(self):
1030
+ eps = np.finfo(float).eps
1031
+ assert_mpmath_equal(_cospi, mpmath.cospi, [Arg()], nan_ok=False, rtol=2*eps)
1032
+
1033
+ def test_cospi_complex(self):
1034
+ assert_mpmath_equal(
1035
+ _cospi,
1036
+ mpmath.cospi,
1037
+ [ComplexArg()],
1038
+ nan_ok=False,
1039
+ rtol=1e-13,
1040
+ )
1041
+
1042
+ def test_digamma(self):
1043
+ assert_mpmath_equal(
1044
+ sc.digamma,
1045
+ exception_to_nan(mpmath.digamma),
1046
+ [Arg()],
1047
+ rtol=1e-12,
1048
+ dps=50,
1049
+ )
1050
+
1051
+ def test_digamma_complex(self):
1052
+ # Test on a cut plane because mpmath will hang. See
1053
+ # test_digamma_negreal for tests on the negative real axis.
1054
+ def param_filter(z):
1055
+ return np.where((z.real < 0) & (np.abs(z.imag) < 1.12), False, True)
1056
+
1057
+ assert_mpmath_equal(
1058
+ sc.digamma,
1059
+ exception_to_nan(mpmath.digamma),
1060
+ [ComplexArg()],
1061
+ rtol=1e-13,
1062
+ dps=40,
1063
+ param_filter=param_filter
1064
+ )
1065
+
1066
+ def test_e1(self):
1067
+ assert_mpmath_equal(
1068
+ sc.exp1,
1069
+ mpmath.e1,
1070
+ [Arg()],
1071
+ rtol=1e-14,
1072
+ )
1073
+
1074
+ def test_e1_complex(self):
1075
+ # E_1 oscillates as Im[z] -> +- inf, so limit range
1076
+ assert_mpmath_equal(
1077
+ sc.exp1,
1078
+ mpmath.e1,
1079
+ [ComplexArg(complex(-np.inf, -1e8), complex(np.inf, 1e8))],
1080
+ rtol=1e-11,
1081
+ )
1082
+
1083
+ # Check cross-over region
1084
+ assert_mpmath_equal(
1085
+ sc.exp1,
1086
+ mpmath.e1,
1087
+ (np.linspace(-50, 50, 171)[:, None]
1088
+ + np.r_[0, np.logspace(-3, 2, 61), -np.logspace(-3, 2, 11)]*1j).ravel(),
1089
+ rtol=1e-11,
1090
+ )
1091
+ assert_mpmath_equal(
1092
+ sc.exp1,
1093
+ mpmath.e1,
1094
+ (np.linspace(-50, -35, 10000) + 0j),
1095
+ rtol=1e-11,
1096
+ )
1097
+
1098
+ def test_exprel(self):
1099
+ assert_mpmath_equal(
1100
+ sc.exprel,
1101
+ lambda x: mpmath.expm1(x)/x if x != 0 else mpmath.mpf('1.0'),
1102
+ [Arg(a=-np.log(np.finfo(np.float64).max),
1103
+ b=np.log(np.finfo(np.float64).max))],
1104
+ )
1105
+ assert_mpmath_equal(
1106
+ sc.exprel,
1107
+ lambda x: mpmath.expm1(x)/x if x != 0 else mpmath.mpf('1.0'),
1108
+ np.array([1e-12, 1e-24, 0, 1e12, 1e24, np.inf]),
1109
+ rtol=1e-11,
1110
+ )
1111
+ assert_(np.isinf(sc.exprel(np.inf)))
1112
+ assert_(sc.exprel(-np.inf) == 0)
1113
+
1114
+ def test_expm1_complex(self):
1115
+ # Oscillates as a function of Im[z], so limit range to avoid loss of precision
1116
+ assert_mpmath_equal(
1117
+ sc.expm1,
1118
+ mpmath.expm1,
1119
+ [ComplexArg(complex(-np.inf, -1e7), complex(np.inf, 1e7))],
1120
+ )
1121
+
1122
+ def test_log1p_complex(self):
1123
+ assert_mpmath_equal(
1124
+ sc.log1p,
1125
+ lambda x: mpmath.log(x+1),
1126
+ [ComplexArg()],
1127
+ dps=60,
1128
+ )
1129
+
1130
+ def test_log1pmx(self):
1131
+ assert_mpmath_equal(
1132
+ _log1pmx,
1133
+ lambda x: mpmath.log(x + 1) - x,
1134
+ [Arg()],
1135
+ dps=60,
1136
+ rtol=1e-14,
1137
+ )
1138
+
1139
+ def test_ei(self):
1140
+ assert_mpmath_equal(sc.expi, mpmath.ei, [Arg()], rtol=1e-11)
1141
+
1142
+ def test_ei_complex(self):
1143
+ # Ei oscillates as Im[z] -> +- inf, so limit range
1144
+ assert_mpmath_equal(
1145
+ sc.expi,
1146
+ mpmath.ei,
1147
+ [ComplexArg(complex(-np.inf, -1e8), complex(np.inf, 1e8))],
1148
+ rtol=1e-9,
1149
+ )
1150
+
1151
+ def test_ellipe(self):
1152
+ assert_mpmath_equal(sc.ellipe, mpmath.ellipe, [Arg(b=1.0)])
1153
+
1154
+ def test_ellipeinc(self):
1155
+ assert_mpmath_equal(sc.ellipeinc, mpmath.ellipe, [Arg(-1e3, 1e3), Arg(b=1.0)])
1156
+
1157
+ def test_ellipeinc_largephi(self):
1158
+ assert_mpmath_equal(sc.ellipeinc, mpmath.ellipe, [Arg(), Arg()])
1159
+
1160
+ def test_ellipf(self):
1161
+ assert_mpmath_equal(sc.ellipkinc, mpmath.ellipf, [Arg(-1e3, 1e3), Arg()])
1162
+
1163
+ def test_ellipf_largephi(self):
1164
+ assert_mpmath_equal(sc.ellipkinc, mpmath.ellipf, [Arg(), Arg()])
1165
+
1166
+ def test_ellipk(self):
1167
+ assert_mpmath_equal(sc.ellipk, mpmath.ellipk, [Arg(b=1.0)])
1168
+ assert_mpmath_equal(
1169
+ sc.ellipkm1,
1170
+ lambda m: mpmath.ellipk(1 - m),
1171
+ [Arg(a=0.0)],
1172
+ dps=400,
1173
+ )
1174
+
1175
+ def test_ellipkinc(self):
1176
+ def ellipkinc(phi, m):
1177
+ return mpmath.ellippi(0, phi, m)
1178
+ assert_mpmath_equal(
1179
+ sc.ellipkinc,
1180
+ ellipkinc,
1181
+ [Arg(-1e3, 1e3), Arg(b=1.0)],
1182
+ ignore_inf_sign=True,
1183
+ )
1184
+
1185
+ def test_ellipkinc_largephi(self):
1186
+ def ellipkinc(phi, m):
1187
+ return mpmath.ellippi(0, phi, m)
1188
+ assert_mpmath_equal(
1189
+ sc.ellipkinc,
1190
+ ellipkinc,
1191
+ [Arg(), Arg(b=1.0)],
1192
+ ignore_inf_sign=True,
1193
+ )
1194
+
1195
+ def test_ellipfun_sn(self):
1196
+ def sn(u, m):
1197
+ # mpmath doesn't get the zero at u = 0--fix that
1198
+ if u == 0:
1199
+ return 0
1200
+ else:
1201
+ return mpmath.ellipfun("sn", u=u, m=m)
1202
+
1203
+ # Oscillating function --- limit range of first argument; the
1204
+ # loss of precision there is an expected numerical feature
1205
+ # rather than an actual bug
1206
+ assert_mpmath_equal(
1207
+ lambda u, m: sc.ellipj(u, m)[0],
1208
+ sn,
1209
+ [Arg(-1e6, 1e6), Arg(a=0, b=1)],
1210
+ rtol=1e-8,
1211
+ )
1212
+
1213
+ def test_ellipfun_cn(self):
1214
+ # see comment in ellipfun_sn
1215
+ assert_mpmath_equal(
1216
+ lambda u, m: sc.ellipj(u, m)[1],
1217
+ lambda u, m: mpmath.ellipfun("cn", u=u, m=m),
1218
+ [Arg(-1e6, 1e6), Arg(a=0, b=1)],
1219
+ rtol=1e-8,
1220
+ )
1221
+
1222
+ def test_ellipfun_dn(self):
1223
+ # see comment in ellipfun_sn
1224
+ assert_mpmath_equal(
1225
+ lambda u, m: sc.ellipj(u, m)[2],
1226
+ lambda u, m: mpmath.ellipfun("dn", u=u, m=m),
1227
+ [Arg(-1e6, 1e6), Arg(a=0, b=1)],
1228
+ rtol=1e-8,
1229
+ )
1230
+
1231
+ def test_erf(self):
1232
+ assert_mpmath_equal(sc.erf, lambda z: mpmath.erf(z), [Arg()])
1233
+
1234
+ def test_erf_complex(self):
1235
+ assert_mpmath_equal(sc.erf, lambda z: mpmath.erf(z), [ComplexArg()], n=200)
1236
+
1237
+ def test_erfc(self):
1238
+ assert_mpmath_equal(
1239
+ sc.erfc,
1240
+ exception_to_nan(lambda z: mpmath.erfc(z)),
1241
+ [Arg()],
1242
+ rtol=1e-13,
1243
+ )
1244
+
1245
+ def test_erfc_complex(self):
1246
+ assert_mpmath_equal(
1247
+ sc.erfc,
1248
+ exception_to_nan(lambda z: mpmath.erfc(z)),
1249
+ [ComplexArg()],
1250
+ n=200,
1251
+ )
1252
+
1253
+ def test_erfi(self):
1254
+ assert_mpmath_equal(sc.erfi, mpmath.erfi, [Arg()], n=200)
1255
+
1256
+ def test_erfi_complex(self):
1257
+ assert_mpmath_equal(sc.erfi, mpmath.erfi, [ComplexArg()], n=200)
1258
+
1259
+ def test_ndtr(self):
1260
+ assert_mpmath_equal(
1261
+ sc.ndtr,
1262
+ exception_to_nan(lambda z: mpmath.ncdf(z)),
1263
+ [Arg()],
1264
+ n=200,
1265
+ )
1266
+
1267
+ def test_ndtr_complex(self):
1268
+ assert_mpmath_equal(
1269
+ sc.ndtr,
1270
+ lambda z: mpmath.erfc(-z/np.sqrt(2.))/2.,
1271
+ [ComplexArg(a=complex(-10000, -10000), b=complex(10000, 10000))],
1272
+ n=400,
1273
+ )
1274
+
1275
+ def test_log_ndtr(self):
1276
+ assert_mpmath_equal(
1277
+ sc.log_ndtr,
1278
+ exception_to_nan(lambda z: mpmath.log(mpmath.ncdf(z))),
1279
+ [Arg()], n=600, dps=300, rtol=1e-13,
1280
+ )
1281
+
1282
+ def test_log_ndtr_complex(self):
1283
+ assert_mpmath_equal(
1284
+ sc.log_ndtr,
1285
+ exception_to_nan(lambda z: mpmath.log(mpmath.erfc(-z/np.sqrt(2.))/2.)),
1286
+ [ComplexArg(a=complex(-10000, -100), b=complex(10000, 100))],
1287
+ n=200, dps=300,
1288
+ )
1289
+
1290
+ def test_eulernum(self):
1291
+ assert_mpmath_equal(
1292
+ lambda n: sc.euler(n)[-1],
1293
+ mpmath.eulernum,
1294
+ [IntArg(1, 10000)],
1295
+ n=10000,
1296
+ )
1297
+
1298
+ def test_expint(self):
1299
+ assert_mpmath_equal(
1300
+ sc.expn,
1301
+ mpmath.expint,
1302
+ [IntArg(0, 200), Arg(0, np.inf)],
1303
+ rtol=1e-13,
1304
+ dps=160,
1305
+ )
1306
+
1307
+ def test_fresnels(self):
1308
+ def fresnels(x):
1309
+ return sc.fresnel(x)[0]
1310
+ assert_mpmath_equal(fresnels, mpmath.fresnels, [Arg()])
1311
+
1312
+ def test_fresnelc(self):
1313
+ def fresnelc(x):
1314
+ return sc.fresnel(x)[1]
1315
+ assert_mpmath_equal(fresnelc, mpmath.fresnelc, [Arg()])
1316
+
1317
+ def test_gamma(self):
1318
+ assert_mpmath_equal(sc.gamma, exception_to_nan(mpmath.gamma), [Arg()])
1319
+
1320
+ def test_gamma_complex(self):
1321
+ assert_mpmath_equal(
1322
+ sc.gamma,
1323
+ exception_to_nan(mpmath.gamma),
1324
+ [ComplexArg()],
1325
+ rtol=5e-13,
1326
+ )
1327
+
1328
+ def test_gammainc(self):
1329
+ # Larger arguments are tested in test_data.py:test_local
1330
+ assert_mpmath_equal(
1331
+ sc.gammainc,
1332
+ lambda z, b: mpmath.gammainc(z, b=b, regularized=True),
1333
+ [Arg(0, 1e4, inclusive_a=False), Arg(0, 1e4)],
1334
+ nan_ok=False,
1335
+ rtol=1e-11,
1336
+ )
1337
+
1338
+ def test_gammaincc(self):
1339
+ # Larger arguments are tested in test_data.py:test_local
1340
+ assert_mpmath_equal(
1341
+ sc.gammaincc,
1342
+ lambda z, a: mpmath.gammainc(z, a=a, regularized=True),
1343
+ [Arg(0, 1e4, inclusive_a=False), Arg(0, 1e4)],
1344
+ nan_ok=False,
1345
+ rtol=1e-11,
1346
+ )
1347
+
1348
+ def test_gammaln(self):
1349
+ # The real part of loggamma is log(|gamma(z)|).
1350
+ def f(z):
1351
+ return mpmath.loggamma(z).real
1352
+
1353
+ assert_mpmath_equal(sc.gammaln, exception_to_nan(f), [Arg()])
1354
+
1355
+ @pytest.mark.xfail(run=False)
1356
+ def test_gegenbauer(self):
1357
+ assert_mpmath_equal(
1358
+ sc.eval_gegenbauer,
1359
+ exception_to_nan(mpmath.gegenbauer),
1360
+ [Arg(-1e3, 1e3), Arg(), Arg()],
1361
+ )
1362
+
1363
+ def test_gegenbauer_int(self):
1364
+ # Redefine functions to deal with numerical + mpmath issues
1365
+ def gegenbauer(n, a, x):
1366
+ # Avoid overflow at large `a` (mpmath would need an even larger
1367
+ # dps to handle this correctly, so just skip this region)
1368
+ if abs(a) > 1e100:
1369
+ return np.nan
1370
+
1371
+ # Deal with n=0, n=1 correctly; mpmath 0.17 doesn't do these
1372
+ # always correctly
1373
+ if n == 0:
1374
+ r = 1.0
1375
+ elif n == 1:
1376
+ r = 2*a*x
1377
+ else:
1378
+ r = mpmath.gegenbauer(n, a, x)
1379
+
1380
+ # Mpmath 0.17 gives wrong results (spurious zero) in some cases, so
1381
+ # compute the value by perturbing the result
1382
+ if float(r) == 0 and a < -1 and float(a) == int(float(a)):
1383
+ r = mpmath.gegenbauer(n, a + mpmath.mpf('1e-50'), x)
1384
+ if abs(r) < mpmath.mpf('1e-50'):
1385
+ r = mpmath.mpf('0.0')
1386
+
1387
+ # Differing overflow thresholds in scipy vs. mpmath
1388
+ if abs(r) > 1e270:
1389
+ return np.inf
1390
+ return r
1391
+
1392
+ def sc_gegenbauer(n, a, x):
1393
+ r = sc.eval_gegenbauer(int(n), a, x)
1394
+ # Differing overflow thresholds in scipy vs. mpmath
1395
+ if abs(r) > 1e270:
1396
+ return np.inf
1397
+ return r
1398
+ assert_mpmath_equal(
1399
+ sc_gegenbauer,
1400
+ exception_to_nan(gegenbauer),
1401
+ [IntArg(0, 100), Arg(-1e9, 1e9), Arg()],
1402
+ n=40000, dps=100, ignore_inf_sign=True, rtol=1e-6,
1403
+ )
1404
+
1405
+ # Check the small-x expansion
1406
+ assert_mpmath_equal(
1407
+ sc_gegenbauer,
1408
+ exception_to_nan(gegenbauer),
1409
+ [IntArg(0, 100), Arg(), FixedArg(np.logspace(-30, -4, 30))],
1410
+ dps=100, ignore_inf_sign=True,
1411
+ )
1412
+
1413
+ @pytest.mark.xfail(run=False)
1414
+ def test_gegenbauer_complex(self):
1415
+ assert_mpmath_equal(
1416
+ lambda n, a, x: sc.eval_gegenbauer(int(n), a.real, x),
1417
+ exception_to_nan(mpmath.gegenbauer),
1418
+ [IntArg(0, 100), Arg(), ComplexArg()],
1419
+ )
1420
+
1421
+ @nonfunctional_tooslow
1422
+ def test_gegenbauer_complex_general(self):
1423
+ assert_mpmath_equal(
1424
+ lambda n, a, x: sc.eval_gegenbauer(n.real, a.real, x),
1425
+ exception_to_nan(mpmath.gegenbauer),
1426
+ [Arg(-1e3, 1e3), Arg(), ComplexArg()],
1427
+ )
1428
+
1429
+ def test_hankel1(self):
1430
+ assert_mpmath_equal(
1431
+ sc.hankel1,
1432
+ exception_to_nan(lambda v, x: mpmath.hankel1(v, x, **HYPERKW)),
1433
+ [Arg(-1e20, 1e20), Arg()],
1434
+ )
1435
+
1436
+ def test_hankel2(self):
1437
+ assert_mpmath_equal(
1438
+ sc.hankel2,
1439
+ exception_to_nan(lambda v, x: mpmath.hankel2(v, x, **HYPERKW)),
1440
+ [Arg(-1e20, 1e20), Arg()],
1441
+ )
1442
+
1443
+ @pytest.mark.xfail(run=False, reason="issues at intermediately large orders")
1444
+ def test_hermite(self):
1445
+ assert_mpmath_equal(
1446
+ lambda n, x: sc.eval_hermite(int(n), x),
1447
+ exception_to_nan(mpmath.hermite),
1448
+ [IntArg(0, 10000), Arg()],
1449
+ )
1450
+
1451
+ # hurwitz: same as zeta
1452
+
1453
+ def test_hyp0f1(self):
1454
+ # mpmath reports no convergence unless maxterms is large enough
1455
+ KW = dict(maxprec=400, maxterms=1500)
1456
+ # n=500 (non-xslow default) fails for one bad point
1457
+ assert_mpmath_equal(
1458
+ sc.hyp0f1,
1459
+ lambda a, x: mpmath.hyp0f1(a, x, **KW),
1460
+ [Arg(-1e7, 1e7), Arg(0, 1e5)],
1461
+ n=5000,
1462
+ )
1463
+ # NB: The range of the second parameter ("z") is limited from below
1464
+ # because of an overflow in the intermediate calculations. The way
1465
+ # for fix it is to implement an asymptotic expansion for Bessel J
1466
+ # (similar to what is implemented for Bessel I here).
1467
+
1468
+ def test_hyp0f1_complex(self):
1469
+ assert_mpmath_equal(
1470
+ lambda a, z: sc.hyp0f1(a.real, z),
1471
+ exception_to_nan(lambda a, x: mpmath.hyp0f1(a, x, **HYPERKW)),
1472
+ [Arg(-10, 10), ComplexArg(complex(-120, -120), complex(120, 120))],
1473
+ )
1474
+ # NB: The range of the first parameter ("v") are limited by an overflow
1475
+ # in the intermediate calculations. Can be fixed by implementing an
1476
+ # asymptotic expansion for Bessel functions for large order.
1477
+
1478
+ def test_hyp1f1(self):
1479
+ def mpmath_hyp1f1(a, b, x):
1480
+ try:
1481
+ return mpmath.hyp1f1(a, b, x)
1482
+ except ZeroDivisionError:
1483
+ return np.inf
1484
+
1485
+ assert_mpmath_equal(
1486
+ sc.hyp1f1,
1487
+ mpmath_hyp1f1,
1488
+ [Arg(-50, 50), Arg(1, 50, inclusive_a=False), Arg(-50, 50)],
1489
+ n=500,
1490
+ nan_ok=False,
1491
+ )
1492
+
1493
+ @pytest.mark.xfail(run=False)
1494
+ def test_hyp1f1_complex(self):
1495
+ assert_mpmath_equal(
1496
+ inf_to_nan(lambda a, b, x: sc.hyp1f1(a.real, b.real, x)),
1497
+ exception_to_nan(lambda a, b, x: mpmath.hyp1f1(a, b, x, **HYPERKW)),
1498
+ [Arg(-1e3, 1e3), Arg(-1e3, 1e3), ComplexArg()],
1499
+ n=2000,
1500
+ )
1501
+
1502
+ @nonfunctional_tooslow
1503
+ def test_hyp2f1_complex(self):
1504
+ # SciPy's hyp2f1 seems to have performance and accuracy problems
1505
+ assert_mpmath_equal(
1506
+ lambda a, b, c, x: sc.hyp2f1(a.real, b.real, c.real, x),
1507
+ exception_to_nan(lambda a, b, c, x: mpmath.hyp2f1(a, b, c, x, **HYPERKW)),
1508
+ [Arg(-1e2, 1e2), Arg(-1e2, 1e2), Arg(-1e2, 1e2), ComplexArg()],
1509
+ n=10,
1510
+ )
1511
+
1512
+ @pytest.mark.xfail(run=False)
1513
+ def test_hyperu(self):
1514
+ assert_mpmath_equal(
1515
+ sc.hyperu,
1516
+ exception_to_nan(lambda a, b, x: mpmath.hyperu(a, b, x, **HYPERKW)),
1517
+ [Arg(), Arg(), Arg()],
1518
+ )
1519
+
1520
+ @pytest.mark.xfail_on_32bit("mpmath issue gh-342: "
1521
+ "unsupported operand mpz, long for pow")
1522
+ def test_igam_fac(self):
1523
+ def mp_igam_fac(a, x):
1524
+ return mpmath.power(x, a)*mpmath.exp(-x)/mpmath.gamma(a)
1525
+
1526
+ assert_mpmath_equal(
1527
+ _igam_fac,
1528
+ mp_igam_fac,
1529
+ [Arg(0, 1e14, inclusive_a=False), Arg(0, 1e14)],
1530
+ rtol=1e-10,
1531
+ )
1532
+
1533
+ def test_j0(self):
1534
+ # The Bessel function at large arguments is j0(x) ~ cos(x + phi)/sqrt(x)
1535
+ # and at large arguments the phase of the cosine loses precision.
1536
+ #
1537
+ # This is numerically expected behavior, so we compare only up to
1538
+ # 1e8 = 1e15 * 1e-7
1539
+ assert_mpmath_equal(sc.j0, mpmath.j0, [Arg(-1e3, 1e3)])
1540
+ assert_mpmath_equal(sc.j0, mpmath.j0, [Arg(-1e8, 1e8)], rtol=1e-5)
1541
+
1542
+ def test_j1(self):
1543
+ # See comment in test_j0
1544
+ assert_mpmath_equal(sc.j1, mpmath.j1, [Arg(-1e3, 1e3)])
1545
+ assert_mpmath_equal(sc.j1, mpmath.j1, [Arg(-1e8, 1e8)], rtol=1e-5)
1546
+
1547
+ @pytest.mark.xfail(run=False)
1548
+ def test_jacobi(self):
1549
+ assert_mpmath_equal(
1550
+ sc.eval_jacobi,
1551
+ exception_to_nan(lambda a, b, c, x: mpmath.jacobi(a, b, c, x, **HYPERKW)),
1552
+ [Arg(), Arg(), Arg(), Arg()],
1553
+ )
1554
+ assert_mpmath_equal(
1555
+ lambda n, b, c, x: sc.eval_jacobi(int(n), b, c, x),
1556
+ exception_to_nan(lambda a, b, c, x: mpmath.jacobi(a, b, c, x, **HYPERKW)),
1557
+ [IntArg(), Arg(), Arg(), Arg()],
1558
+ )
1559
+
1560
+ def test_jacobi_int(self):
1561
+ # Redefine functions to deal with numerical + mpmath issues
1562
+ def jacobi(n, a, b, x):
1563
+ # Mpmath does not handle n=0 case always correctly
1564
+ if n == 0:
1565
+ return 1.0
1566
+ return mpmath.jacobi(n, a, b, x)
1567
+ assert_mpmath_equal(
1568
+ lambda n, a, b, x: sc.eval_jacobi(int(n), a, b, x),
1569
+ lambda n, a, b, x: exception_to_nan(jacobi)(n, a, b, x, **HYPERKW),
1570
+ [IntArg(), Arg(), Arg(), Arg()],
1571
+ n=20000,
1572
+ dps=50,
1573
+ )
1574
+
1575
+ def test_kei(self):
1576
+ def kei(x):
1577
+ if x == 0:
1578
+ # work around mpmath issue at x=0
1579
+ return -pi/4
1580
+ return exception_to_nan(mpmath.kei)(0, x, **HYPERKW)
1581
+ assert_mpmath_equal(sc.kei, kei, [Arg(-1e30, 1e30)], n=1000)
1582
+
1583
+ def test_ker(self):
1584
+ assert_mpmath_equal(
1585
+ sc.ker,
1586
+ exception_to_nan(lambda x: mpmath.ker(0, x, **HYPERKW)),
1587
+ [Arg(-1e30, 1e30)],
1588
+ n=1000,
1589
+ )
1590
+
1591
+ @nonfunctional_tooslow
1592
+ def test_laguerre(self):
1593
+ assert_mpmath_equal(
1594
+ trace_args(sc.eval_laguerre),
1595
+ lambda n, x: exception_to_nan(mpmath.laguerre)(n, x, **HYPERKW),
1596
+ [Arg(), Arg()],
1597
+ )
1598
+
1599
+ def test_laguerre_int(self):
1600
+ assert_mpmath_equal(
1601
+ lambda n, x: sc.eval_laguerre(int(n), x),
1602
+ lambda n, x: exception_to_nan(mpmath.laguerre)(n, x, **HYPERKW),
1603
+ [IntArg(), Arg()],
1604
+ n=20000,
1605
+ )
1606
+
1607
+ @pytest.mark.xfail_on_32bit("see gh-3551 for bad points")
1608
+ def test_lambertw_real(self):
1609
+ assert_mpmath_equal(
1610
+ lambda x, k: sc.lambertw(x, int(k.real)),
1611
+ lambda x, k: mpmath.lambertw(x, int(k.real)),
1612
+ [ComplexArg(-np.inf, np.inf), IntArg(0, 10)],
1613
+ rtol=1e-13, nan_ok=False,
1614
+ )
1615
+
1616
+ def test_lanczos_sum_expg_scaled(self):
1617
+ maxgamma = 171.624376956302725
1618
+ e = np.exp(1)
1619
+ g = 6.024680040776729583740234375
1620
+
1621
+ def gamma(x):
1622
+ with np.errstate(over='ignore'):
1623
+ fac = ((x + g - 0.5)/e)**(x - 0.5)
1624
+ if fac != np.inf:
1625
+ res = fac*_lanczos_sum_expg_scaled(x)
1626
+ else:
1627
+ fac = ((x + g - 0.5)/e)**(0.5*(x - 0.5))
1628
+ res = fac*_lanczos_sum_expg_scaled(x)
1629
+ res *= fac
1630
+ return res
1631
+
1632
+ assert_mpmath_equal(
1633
+ gamma,
1634
+ mpmath.gamma,
1635
+ [Arg(0, maxgamma, inclusive_a=False)],
1636
+ rtol=1e-13,
1637
+ )
1638
+
1639
+ @nonfunctional_tooslow
1640
+ def test_legendre(self):
1641
+ assert_mpmath_equal(sc.eval_legendre, mpmath.legendre, [Arg(), Arg()])
1642
+
1643
+ def test_legendre_int(self):
1644
+ assert_mpmath_equal(
1645
+ lambda n, x: sc.eval_legendre(int(n), x),
1646
+ lambda n, x: exception_to_nan(mpmath.legendre)(n, x, **HYPERKW),
1647
+ [IntArg(), Arg()],
1648
+ n=20000,
1649
+ )
1650
+
1651
+ # Check the small-x expansion
1652
+ assert_mpmath_equal(
1653
+ lambda n, x: sc.eval_legendre(int(n), x),
1654
+ lambda n, x: exception_to_nan(mpmath.legendre)(n, x, **HYPERKW),
1655
+ [IntArg(), FixedArg(np.logspace(-30, -4, 20))],
1656
+ )
1657
+
1658
+ def test_legenp(self):
1659
+ def lpnm(n, m, z):
1660
+ try:
1661
+ v = sc.lpmn(m, n, z)[0][-1,-1]
1662
+ except ValueError:
1663
+ return np.nan
1664
+ if abs(v) > 1e306:
1665
+ # harmonize overflow to inf
1666
+ v = np.inf * np.sign(v.real)
1667
+ return v
1668
+
1669
+ def lpnm_2(n, m, z):
1670
+ v = sc.lpmv(m, n, z)
1671
+ if abs(v) > 1e306:
1672
+ # harmonize overflow to inf
1673
+ v = np.inf * np.sign(v.real)
1674
+ return v
1675
+
1676
+ def legenp(n, m, z):
1677
+ if (z == 1 or z == -1) and int(n) == n:
1678
+ # Special case (mpmath may give inf, we take the limit by
1679
+ # continuity)
1680
+ if m == 0:
1681
+ if n < 0:
1682
+ n = -n - 1
1683
+ return mpmath.power(mpmath.sign(z), n)
1684
+ else:
1685
+ return 0
1686
+
1687
+ if abs(z) < 1e-15:
1688
+ # mpmath has bad performance here
1689
+ return np.nan
1690
+
1691
+ typ = 2 if abs(z) < 1 else 3
1692
+ v = exception_to_nan(mpmath.legenp)(n, m, z, type=typ)
1693
+
1694
+ if abs(v) > 1e306:
1695
+ # harmonize overflow to inf
1696
+ v = mpmath.inf * mpmath.sign(v.real)
1697
+
1698
+ return v
1699
+
1700
+ assert_mpmath_equal(lpnm, legenp, [IntArg(-100, 100), IntArg(-100, 100), Arg()])
1701
+
1702
+ assert_mpmath_equal(
1703
+ lpnm_2,
1704
+ legenp,
1705
+ [IntArg(-100, 100), Arg(-100, 100), Arg(-1, 1)],
1706
+ atol=1e-10,
1707
+ )
1708
+
1709
+ def test_legenp_complex_2(self):
1710
+ def clpnm(n, m, z):
1711
+ try:
1712
+ return sc.clpmn(m.real, n.real, z, type=2)[0][-1,-1]
1713
+ except ValueError:
1714
+ return np.nan
1715
+
1716
+ def legenp(n, m, z):
1717
+ if abs(z) < 1e-15:
1718
+ # mpmath has bad performance here
1719
+ return np.nan
1720
+ return exception_to_nan(mpmath.legenp)(int(n.real), int(m.real), z, type=2)
1721
+
1722
+ # mpmath is quite slow here
1723
+ x = np.array([-2, -0.99, -0.5, 0, 1e-5, 0.5, 0.99, 20, 2e3])
1724
+ y = np.array([-1e3, -0.5, 0.5, 1.3])
1725
+ z = (x[:,None] + 1j*y[None,:]).ravel()
1726
+
1727
+ assert_mpmath_equal(
1728
+ clpnm,
1729
+ legenp,
1730
+ [FixedArg([-2, -1, 0, 1, 2, 10]),
1731
+ FixedArg([-2, -1, 0, 1, 2, 10]),
1732
+ FixedArg(z)],
1733
+ rtol=1e-6,
1734
+ n=500,
1735
+ )
1736
+
1737
+ def test_legenp_complex_3(self):
1738
+ def clpnm(n, m, z):
1739
+ try:
1740
+ return sc.clpmn(m.real, n.real, z, type=3)[0][-1,-1]
1741
+ except ValueError:
1742
+ return np.nan
1743
+
1744
+ def legenp(n, m, z):
1745
+ if abs(z) < 1e-15:
1746
+ # mpmath has bad performance here
1747
+ return np.nan
1748
+ return exception_to_nan(mpmath.legenp)(int(n.real), int(m.real), z, type=3)
1749
+
1750
+ # mpmath is quite slow here
1751
+ x = np.array([-2, -0.99, -0.5, 0, 1e-5, 0.5, 0.99, 20, 2e3])
1752
+ y = np.array([-1e3, -0.5, 0.5, 1.3])
1753
+ z = (x[:,None] + 1j*y[None,:]).ravel()
1754
+
1755
+ assert_mpmath_equal(
1756
+ clpnm,
1757
+ legenp,
1758
+ [FixedArg([-2, -1, 0, 1, 2, 10]),
1759
+ FixedArg([-2, -1, 0, 1, 2, 10]),
1760
+ FixedArg(z)],
1761
+ rtol=1e-6,
1762
+ n=500,
1763
+ )
1764
+
1765
+ @pytest.mark.xfail(run=False, reason="apparently picks wrong function at |z| > 1")
1766
+ def test_legenq(self):
1767
+ def lqnm(n, m, z):
1768
+ return sc.lqmn(m, n, z)[0][-1,-1]
1769
+
1770
+ def legenq(n, m, z):
1771
+ if abs(z) < 1e-15:
1772
+ # mpmath has bad performance here
1773
+ return np.nan
1774
+ return exception_to_nan(mpmath.legenq)(n, m, z, type=2)
1775
+
1776
+ assert_mpmath_equal(
1777
+ lqnm,
1778
+ legenq,
1779
+ [IntArg(0, 100), IntArg(0, 100), Arg()],
1780
+ )
1781
+
1782
+ @nonfunctional_tooslow
1783
+ def test_legenq_complex(self):
1784
+ def lqnm(n, m, z):
1785
+ return sc.lqmn(int(m.real), int(n.real), z)[0][-1,-1]
1786
+
1787
+ def legenq(n, m, z):
1788
+ if abs(z) < 1e-15:
1789
+ # mpmath has bad performance here
1790
+ return np.nan
1791
+ return exception_to_nan(mpmath.legenq)(int(n.real), int(m.real), z, type=2)
1792
+
1793
+ assert_mpmath_equal(
1794
+ lqnm,
1795
+ legenq,
1796
+ [IntArg(0, 100), IntArg(0, 100), ComplexArg()],
1797
+ n=100,
1798
+ )
1799
+
1800
+ def test_lgam1p(self):
1801
+ def param_filter(x):
1802
+ # Filter the poles
1803
+ return np.where((np.floor(x) == x) & (x <= 0), False, True)
1804
+
1805
+ def mp_lgam1p(z):
1806
+ # The real part of loggamma is log(|gamma(z)|)
1807
+ return mpmath.loggamma(1 + z).real
1808
+
1809
+ assert_mpmath_equal(
1810
+ _lgam1p,
1811
+ mp_lgam1p,
1812
+ [Arg()],
1813
+ rtol=1e-13,
1814
+ dps=100,
1815
+ param_filter=param_filter,
1816
+ )
1817
+
1818
+ def test_loggamma(self):
1819
+ def mpmath_loggamma(z):
1820
+ try:
1821
+ res = mpmath.loggamma(z)
1822
+ except ValueError:
1823
+ res = complex(np.nan, np.nan)
1824
+ return res
1825
+
1826
+ assert_mpmath_equal(
1827
+ sc.loggamma,
1828
+ mpmath_loggamma,
1829
+ [ComplexArg()],
1830
+ nan_ok=False,
1831
+ distinguish_nan_and_inf=False,
1832
+ rtol=5e-14,
1833
+ )
1834
+
1835
+ @pytest.mark.xfail(run=False)
1836
+ def test_pcfd(self):
1837
+ def pcfd(v, x):
1838
+ return sc.pbdv(v, x)[0]
1839
+ assert_mpmath_equal(
1840
+ pcfd,
1841
+ exception_to_nan(lambda v, x: mpmath.pcfd(v, x, **HYPERKW)),
1842
+ [Arg(), Arg()],
1843
+ )
1844
+
1845
+ @pytest.mark.xfail(run=False, reason="it's not the same as the mpmath function --- "
1846
+ "maybe different definition?")
1847
+ def test_pcfv(self):
1848
+ def pcfv(v, x):
1849
+ return sc.pbvv(v, x)[0]
1850
+ assert_mpmath_equal(
1851
+ pcfv,
1852
+ lambda v, x: time_limited()(exception_to_nan(mpmath.pcfv))(v, x, **HYPERKW),
1853
+ [Arg(), Arg()],
1854
+ n=1000,
1855
+ )
1856
+
1857
+ def test_pcfw(self):
1858
+ def pcfw(a, x):
1859
+ return sc.pbwa(a, x)[0]
1860
+
1861
+ def dpcfw(a, x):
1862
+ return sc.pbwa(a, x)[1]
1863
+
1864
+ def mpmath_dpcfw(a, x):
1865
+ return mpmath.diff(mpmath.pcfw, (a, x), (0, 1))
1866
+
1867
+ # The Zhang and Jin implementation only uses Taylor series and
1868
+ # is thus accurate in only a very small range.
1869
+ assert_mpmath_equal(
1870
+ pcfw,
1871
+ mpmath.pcfw,
1872
+ [Arg(-5, 5), Arg(-5, 5)],
1873
+ rtol=2e-8,
1874
+ n=100,
1875
+ )
1876
+
1877
+ assert_mpmath_equal(
1878
+ dpcfw,
1879
+ mpmath_dpcfw,
1880
+ [Arg(-5, 5), Arg(-5, 5)],
1881
+ rtol=2e-9,
1882
+ n=100,
1883
+ )
1884
+
1885
+ @pytest.mark.xfail(run=False,
1886
+ reason="issues at large arguments (atol OK, rtol not) "
1887
+ "and <eps-close to z=0")
1888
+ def test_polygamma(self):
1889
+ assert_mpmath_equal(
1890
+ sc.polygamma,
1891
+ time_limited()(exception_to_nan(mpmath.polygamma)),
1892
+ [IntArg(0, 1000), Arg()],
1893
+ )
1894
+
1895
+ def test_rgamma(self):
1896
+ assert_mpmath_equal(
1897
+ sc.rgamma,
1898
+ mpmath.rgamma,
1899
+ [Arg(-8000, np.inf)],
1900
+ n=5000,
1901
+ nan_ok=False,
1902
+ ignore_inf_sign=True,
1903
+ )
1904
+
1905
+ def test_rgamma_complex(self):
1906
+ assert_mpmath_equal(
1907
+ sc.rgamma,
1908
+ exception_to_nan(mpmath.rgamma),
1909
+ [ComplexArg()],
1910
+ rtol=5e-13,
1911
+ )
1912
+
1913
+ @pytest.mark.xfail(reason=("see gh-3551 for bad points on 32 bit "
1914
+ "systems and gh-8095 for another bad "
1915
+ "point"))
1916
+ def test_rf(self):
1917
+ if _pep440.parse(mpmath.__version__) >= _pep440.Version("1.0.0"):
1918
+ # no workarounds needed
1919
+ mppoch = mpmath.rf
1920
+ else:
1921
+ def mppoch(a, m):
1922
+ # deal with cases where the result in double precision
1923
+ # hits exactly a non-positive integer, but the
1924
+ # corresponding extended-precision mpf floats don't
1925
+ if float(a + m) == int(a + m) and float(a + m) <= 0:
1926
+ a = mpmath.mpf(a)
1927
+ m = int(a + m) - a
1928
+ return mpmath.rf(a, m)
1929
+
1930
+ assert_mpmath_equal(sc.poch, mppoch, [Arg(), Arg()], dps=400)
1931
+
1932
+ def test_sinpi(self):
1933
+ eps = np.finfo(float).eps
1934
+ assert_mpmath_equal(
1935
+ _sinpi,
1936
+ mpmath.sinpi,
1937
+ [Arg()],
1938
+ nan_ok=False,
1939
+ rtol=2*eps,
1940
+ )
1941
+
1942
+ def test_sinpi_complex(self):
1943
+ assert_mpmath_equal(
1944
+ _sinpi,
1945
+ mpmath.sinpi,
1946
+ [ComplexArg()],
1947
+ nan_ok=False,
1948
+ rtol=2e-14,
1949
+ )
1950
+
1951
+ def test_shi(self):
1952
+ def shi(x):
1953
+ return sc.shichi(x)[0]
1954
+ assert_mpmath_equal(shi, mpmath.shi, [Arg()])
1955
+ # check asymptotic series cross-over
1956
+ assert_mpmath_equal(shi, mpmath.shi, [FixedArg([88 - 1e-9, 88, 88 + 1e-9])])
1957
+
1958
+ def test_shi_complex(self):
1959
+ def shi(z):
1960
+ return sc.shichi(z)[0]
1961
+ # shi oscillates as Im[z] -> +- inf, so limit range
1962
+ assert_mpmath_equal(
1963
+ shi,
1964
+ mpmath.shi,
1965
+ [ComplexArg(complex(-np.inf, -1e8), complex(np.inf, 1e8))],
1966
+ rtol=1e-12,
1967
+ )
1968
+
1969
+ def test_si(self):
1970
+ def si(x):
1971
+ return sc.sici(x)[0]
1972
+ assert_mpmath_equal(si, mpmath.si, [Arg()])
1973
+
1974
+ def test_si_complex(self):
1975
+ def si(z):
1976
+ return sc.sici(z)[0]
1977
+ # si oscillates as Re[z] -> +- inf, so limit range
1978
+ assert_mpmath_equal(
1979
+ si,
1980
+ mpmath.si,
1981
+ [ComplexArg(complex(-1e8, -np.inf), complex(1e8, np.inf))],
1982
+ rtol=1e-12,
1983
+ )
1984
+
1985
+ def test_spence(self):
1986
+ # mpmath uses a different convention for the dilogarithm
1987
+ def dilog(x):
1988
+ return mpmath.polylog(2, 1 - x)
1989
+ # Spence has a branch cut on the negative real axis
1990
+ assert_mpmath_equal(
1991
+ sc.spence,
1992
+ exception_to_nan(dilog),
1993
+ [Arg(0, np.inf)],
1994
+ rtol=1e-14,
1995
+ )
1996
+
1997
+ def test_spence_complex(self):
1998
+ def dilog(z):
1999
+ return mpmath.polylog(2, 1 - z)
2000
+ assert_mpmath_equal(
2001
+ sc.spence,
2002
+ exception_to_nan(dilog),
2003
+ [ComplexArg()],
2004
+ rtol=1e-14,
2005
+ )
2006
+
2007
+ def test_spherharm(self):
2008
+ def spherharm(l, m, theta, phi):
2009
+ if m > l:
2010
+ return np.nan
2011
+ return sc.sph_harm(m, l, phi, theta)
2012
+ assert_mpmath_equal(
2013
+ spherharm,
2014
+ mpmath.spherharm,
2015
+ [IntArg(0, 100), IntArg(0, 100), Arg(a=0, b=pi), Arg(a=0, b=2*pi)],
2016
+ atol=1e-8,
2017
+ n=6000,
2018
+ dps=150,
2019
+ )
2020
+
2021
+ def test_struveh(self):
2022
+ assert_mpmath_equal(
2023
+ sc.struve,
2024
+ exception_to_nan(mpmath.struveh),
2025
+ [Arg(-1e4, 1e4), Arg(0, 1e4)],
2026
+ rtol=5e-10,
2027
+ )
2028
+
2029
+ def test_struvel(self):
2030
+ def mp_struvel(v, z):
2031
+ if v < 0 and z < -v and abs(v) > 1000:
2032
+ # larger DPS needed for correct results
2033
+ old_dps = mpmath.mp.dps
2034
+ try:
2035
+ mpmath.mp.dps = 300
2036
+ return mpmath.struvel(v, z)
2037
+ finally:
2038
+ mpmath.mp.dps = old_dps
2039
+ return mpmath.struvel(v, z)
2040
+
2041
+ assert_mpmath_equal(
2042
+ sc.modstruve,
2043
+ exception_to_nan(mp_struvel),
2044
+ [Arg(-1e4, 1e4), Arg(0, 1e4)],
2045
+ rtol=5e-10,
2046
+ ignore_inf_sign=True,
2047
+ )
2048
+
2049
+ def test_wrightomega_real(self):
2050
+ def mpmath_wrightomega_real(x):
2051
+ return mpmath.lambertw(mpmath.exp(x), mpmath.mpf('-0.5'))
2052
+
2053
+ # For x < -1000 the Wright Omega function is just 0 to double
2054
+ # precision, and for x > 1e21 it is just x to double
2055
+ # precision.
2056
+ assert_mpmath_equal(
2057
+ sc.wrightomega,
2058
+ mpmath_wrightomega_real,
2059
+ [Arg(-1000, 1e21)],
2060
+ rtol=5e-15,
2061
+ atol=0,
2062
+ nan_ok=False,
2063
+ )
2064
+
2065
+ def test_wrightomega(self):
2066
+ assert_mpmath_equal(
2067
+ sc.wrightomega,
2068
+ lambda z: _mpmath_wrightomega(z, 25),
2069
+ [ComplexArg()],
2070
+ rtol=1e-14,
2071
+ nan_ok=False,
2072
+ )
2073
+
2074
+ def test_hurwitz_zeta(self):
2075
+ assert_mpmath_equal(
2076
+ sc.zeta,
2077
+ exception_to_nan(mpmath.zeta),
2078
+ [Arg(a=1, b=1e10, inclusive_a=False), Arg(a=0, inclusive_a=False)],
2079
+ )
2080
+
2081
+ def test_riemann_zeta(self):
2082
+ assert_mpmath_equal(
2083
+ sc.zeta,
2084
+ lambda x: mpmath.zeta(x) if x != 1 else mpmath.inf,
2085
+ [Arg(-100, 100)],
2086
+ nan_ok=False,
2087
+ rtol=5e-13,
2088
+ )
2089
+
2090
+ def test_zetac(self):
2091
+ assert_mpmath_equal(
2092
+ sc.zetac,
2093
+ lambda x: mpmath.zeta(x) - 1 if x != 1 else mpmath.inf,
2094
+ [Arg(-100, 100)],
2095
+ nan_ok=False,
2096
+ dps=45,
2097
+ rtol=5e-13,
2098
+ )
2099
+
2100
+ def test_boxcox(self):
2101
+
2102
+ def mp_boxcox(x, lmbda):
2103
+ x = mpmath.mp.mpf(x)
2104
+ lmbda = mpmath.mp.mpf(lmbda)
2105
+ if lmbda == 0:
2106
+ return mpmath.mp.log(x)
2107
+ else:
2108
+ return mpmath.mp.powm1(x, lmbda) / lmbda
2109
+
2110
+ assert_mpmath_equal(
2111
+ sc.boxcox,
2112
+ exception_to_nan(mp_boxcox),
2113
+ [Arg(a=0, inclusive_a=False), Arg()],
2114
+ n=200,
2115
+ dps=60,
2116
+ rtol=1e-13,
2117
+ )
2118
+
2119
+ def test_boxcox1p(self):
2120
+
2121
+ def mp_boxcox1p(x, lmbda):
2122
+ x = mpmath.mp.mpf(x)
2123
+ lmbda = mpmath.mp.mpf(lmbda)
2124
+ one = mpmath.mp.mpf(1)
2125
+ if lmbda == 0:
2126
+ return mpmath.mp.log(one + x)
2127
+ else:
2128
+ return mpmath.mp.powm1(one + x, lmbda) / lmbda
2129
+
2130
+ assert_mpmath_equal(
2131
+ sc.boxcox1p,
2132
+ exception_to_nan(mp_boxcox1p),
2133
+ [Arg(a=-1, inclusive_a=False), Arg()],
2134
+ n=200,
2135
+ dps=60,
2136
+ rtol=1e-13,
2137
+ )
2138
+
2139
+ def test_spherical_jn(self):
2140
+ def mp_spherical_jn(n, z):
2141
+ arg = mpmath.mpmathify(z)
2142
+ out = (mpmath.besselj(n + mpmath.mpf(1)/2, arg) /
2143
+ mpmath.sqrt(2*arg/mpmath.pi))
2144
+ if arg.imag == 0:
2145
+ return out.real
2146
+ else:
2147
+ return out
2148
+
2149
+ assert_mpmath_equal(
2150
+ lambda n, z: sc.spherical_jn(int(n), z),
2151
+ exception_to_nan(mp_spherical_jn),
2152
+ [IntArg(0, 200), Arg(-1e8, 1e8)],
2153
+ dps=300,
2154
+ )
2155
+
2156
+ def test_spherical_jn_complex(self):
2157
+ def mp_spherical_jn(n, z):
2158
+ arg = mpmath.mpmathify(z)
2159
+ out = (mpmath.besselj(n + mpmath.mpf(1)/2, arg) /
2160
+ mpmath.sqrt(2*arg/mpmath.pi))
2161
+ if arg.imag == 0:
2162
+ return out.real
2163
+ else:
2164
+ return out
2165
+
2166
+ assert_mpmath_equal(
2167
+ lambda n, z: sc.spherical_jn(int(n.real), z),
2168
+ exception_to_nan(mp_spherical_jn),
2169
+ [IntArg(0, 200), ComplexArg()]
2170
+ )
2171
+
2172
+ def test_spherical_yn(self):
2173
+ def mp_spherical_yn(n, z):
2174
+ arg = mpmath.mpmathify(z)
2175
+ out = (mpmath.bessely(n + mpmath.mpf(1)/2, arg) /
2176
+ mpmath.sqrt(2*arg/mpmath.pi))
2177
+ if arg.imag == 0:
2178
+ return out.real
2179
+ else:
2180
+ return out
2181
+
2182
+ assert_mpmath_equal(
2183
+ lambda n, z: sc.spherical_yn(int(n), z),
2184
+ exception_to_nan(mp_spherical_yn),
2185
+ [IntArg(0, 200), Arg(-1e10, 1e10)],
2186
+ dps=100,
2187
+ )
2188
+
2189
+ def test_spherical_yn_complex(self):
2190
+ def mp_spherical_yn(n, z):
2191
+ arg = mpmath.mpmathify(z)
2192
+ out = (mpmath.bessely(n + mpmath.mpf(1)/2, arg) /
2193
+ mpmath.sqrt(2*arg/mpmath.pi))
2194
+ if arg.imag == 0:
2195
+ return out.real
2196
+ else:
2197
+ return out
2198
+
2199
+ assert_mpmath_equal(
2200
+ lambda n, z: sc.spherical_yn(int(n.real), z),
2201
+ exception_to_nan(mp_spherical_yn),
2202
+ [IntArg(0, 200), ComplexArg()],
2203
+ )
2204
+
2205
+ def test_spherical_in(self):
2206
+ def mp_spherical_in(n, z):
2207
+ arg = mpmath.mpmathify(z)
2208
+ out = (mpmath.besseli(n + mpmath.mpf(1)/2, arg) /
2209
+ mpmath.sqrt(2*arg/mpmath.pi))
2210
+ if arg.imag == 0:
2211
+ return out.real
2212
+ else:
2213
+ return out
2214
+
2215
+ assert_mpmath_equal(
2216
+ lambda n, z: sc.spherical_in(int(n), z),
2217
+ exception_to_nan(mp_spherical_in),
2218
+ [IntArg(0, 200), Arg()],
2219
+ dps=200,
2220
+ atol=10**(-278),
2221
+ )
2222
+
2223
+ def test_spherical_in_complex(self):
2224
+ def mp_spherical_in(n, z):
2225
+ arg = mpmath.mpmathify(z)
2226
+ out = (mpmath.besseli(n + mpmath.mpf(1)/2, arg) /
2227
+ mpmath.sqrt(2*arg/mpmath.pi))
2228
+ if arg.imag == 0:
2229
+ return out.real
2230
+ else:
2231
+ return out
2232
+
2233
+ assert_mpmath_equal(
2234
+ lambda n, z: sc.spherical_in(int(n.real), z),
2235
+ exception_to_nan(mp_spherical_in),
2236
+ [IntArg(0, 200), ComplexArg()],
2237
+ )
2238
+
2239
+ def test_spherical_kn(self):
2240
+ def mp_spherical_kn(n, z):
2241
+ out = (mpmath.besselk(n + mpmath.mpf(1)/2, z) *
2242
+ mpmath.sqrt(mpmath.pi/(2*mpmath.mpmathify(z))))
2243
+ if mpmath.mpmathify(z).imag == 0:
2244
+ return out.real
2245
+ else:
2246
+ return out
2247
+
2248
+ assert_mpmath_equal(
2249
+ lambda n, z: sc.spherical_kn(int(n), z),
2250
+ exception_to_nan(mp_spherical_kn),
2251
+ [IntArg(0, 150), Arg()],
2252
+ dps=100,
2253
+ )
2254
+
2255
+ @pytest.mark.xfail(run=False,
2256
+ reason="Accuracy issues near z = -1 inherited from kv.")
2257
+ def test_spherical_kn_complex(self):
2258
+ def mp_spherical_kn(n, z):
2259
+ arg = mpmath.mpmathify(z)
2260
+ out = (mpmath.besselk(n + mpmath.mpf(1)/2, arg) /
2261
+ mpmath.sqrt(2*arg/mpmath.pi))
2262
+ if arg.imag == 0:
2263
+ return out.real
2264
+ else:
2265
+ return out
2266
+
2267
+ assert_mpmath_equal(
2268
+ lambda n, z: sc.spherical_kn(int(n.real), z),
2269
+ exception_to_nan(mp_spherical_kn),
2270
+ [IntArg(0, 200), ComplexArg()],
2271
+ dps=200,
2272
+ )
.venv/Lib/site-packages/scipy/special/tests/test_nan_inputs.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Test how the ufuncs in special handle nan inputs.
2
+
3
+ """
4
+ from typing import Callable
5
+
6
+ import numpy as np
7
+ from numpy.testing import assert_array_equal, assert_, suppress_warnings
8
+ import pytest
9
+ import scipy.special as sc
10
+
11
+
12
+ KNOWNFAILURES: dict[str, Callable] = {}
13
+
14
+ POSTPROCESSING: dict[str, Callable] = {}
15
+
16
+
17
+ def _get_ufuncs():
18
+ ufuncs = []
19
+ ufunc_names = []
20
+ for name in sorted(sc.__dict__):
21
+ obj = sc.__dict__[name]
22
+ if not isinstance(obj, np.ufunc):
23
+ continue
24
+ msg = KNOWNFAILURES.get(obj)
25
+ if msg is None:
26
+ ufuncs.append(obj)
27
+ ufunc_names.append(name)
28
+ else:
29
+ fail = pytest.mark.xfail(run=False, reason=msg)
30
+ ufuncs.append(pytest.param(obj, marks=fail))
31
+ ufunc_names.append(name)
32
+ return ufuncs, ufunc_names
33
+
34
+
35
+ UFUNCS, UFUNC_NAMES = _get_ufuncs()
36
+
37
+
38
+ @pytest.mark.parametrize("func", UFUNCS, ids=UFUNC_NAMES)
39
+ def test_nan_inputs(func):
40
+ args = (np.nan,)*func.nin
41
+ with suppress_warnings() as sup:
42
+ # Ignore warnings about unsafe casts from legacy wrappers
43
+ sup.filter(RuntimeWarning,
44
+ "floating point number truncated to an integer")
45
+ try:
46
+ with suppress_warnings() as sup:
47
+ sup.filter(DeprecationWarning)
48
+ res = func(*args)
49
+ except TypeError:
50
+ # One of the arguments doesn't take real inputs
51
+ return
52
+ if func in POSTPROCESSING:
53
+ res = POSTPROCESSING[func](*res)
54
+
55
+ msg = f"got {res} instead of nan"
56
+ assert_array_equal(np.isnan(res), True, err_msg=msg)
57
+
58
+
59
+ def test_legacy_cast():
60
+ with suppress_warnings() as sup:
61
+ sup.filter(RuntimeWarning,
62
+ "floating point number truncated to an integer")
63
+ res = sc.bdtrc(np.nan, 1, 0.5)
64
+ assert_(np.isnan(res))
.venv/Lib/site-packages/scipy/special/tests/test_ndtr.py ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from numpy.testing import assert_equal, assert_allclose
3
+ import scipy.special as sc
4
+
5
+
6
+ def test_ndtr():
7
+ assert_equal(sc.ndtr(0), 0.5)
8
+ assert_allclose(sc.ndtr(1), 0.8413447460685429)
9
+
10
+
11
+ class TestNdtri:
12
+
13
+ def test_zero(self):
14
+ assert sc.ndtri(0.5) == 0.0
15
+
16
+ def test_asymptotes(self):
17
+ assert_equal(sc.ndtri([0.0, 1.0]), [-np.inf, np.inf])
18
+
19
+ def test_outside_of_domain(self):
20
+ assert all(np.isnan(sc.ndtri([-1.5, 1.5])))
21
+
22
+
23
+ class TestLogNdtr:
24
+
25
+ # The expected values in these tests were computed with mpmath:
26
+ #
27
+ # def log_ndtr_mp(x):
28
+ # return mpmath.log(mpmath.ncdf(x))
29
+ #
30
+
31
+ def test_log_ndtr_moderate_le8(self):
32
+ x = np.array([-0.75, -0.25, 0, 0.5, 1.5, 2.5, 3, 4, 5, 7, 8])
33
+ expected = np.array([-1.4844482299196562,
34
+ -0.9130617648111351,
35
+ -0.6931471805599453,
36
+ -0.3689464152886564,
37
+ -0.06914345561223398,
38
+ -0.006229025485860002,
39
+ -0.0013508099647481938,
40
+ -3.167174337748927e-05,
41
+ -2.866516129637636e-07,
42
+ -1.279812543886654e-12,
43
+ -6.220960574271786e-16])
44
+ y = sc.log_ndtr(x)
45
+ assert_allclose(y, expected, rtol=1e-14)
46
+
47
+ def test_log_ndtr_values_8_16(self):
48
+ x = np.array([8.001, 8.06, 8.15, 8.5, 10, 12, 14, 16])
49
+ expected = [-6.170639424817055e-16,
50
+ -3.814722443652823e-16,
51
+ -1.819621363526629e-16,
52
+ -9.479534822203318e-18,
53
+ -7.619853024160525e-24,
54
+ -1.776482112077679e-33,
55
+ -7.7935368191928e-45,
56
+ -6.388754400538087e-58]
57
+ y = sc.log_ndtr(x)
58
+ assert_allclose(y, expected, rtol=5e-14)
59
+
60
+ def test_log_ndtr_values_16_31(self):
61
+ x = np.array([16.15, 20.3, 21.4, 26.2, 30.9])
62
+ expected = [-5.678084565148492e-59,
63
+ -6.429244467698346e-92,
64
+ -6.680402412553295e-102,
65
+ -1.328698078458869e-151,
66
+ -5.972288641838264e-210]
67
+ y = sc.log_ndtr(x)
68
+ assert_allclose(y, expected, rtol=2e-13)
69
+
70
+ def test_log_ndtr_values_gt31(self):
71
+ x = np.array([31.6, 32.8, 34.9, 37.1])
72
+ expected = [-1.846036234858162e-219,
73
+ -2.9440539964066835e-236,
74
+ -3.71721649450857e-267,
75
+ -1.4047119663106221e-301]
76
+ y = sc.log_ndtr(x)
77
+ assert_allclose(y, expected, rtol=3e-13)
.venv/Lib/site-packages/scipy/special/tests/test_ndtri_exp.py ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pytest
2
+ import numpy as np
3
+ from numpy.testing import assert_equal, assert_allclose
4
+ from scipy.special import log_ndtr, ndtri_exp
5
+ from scipy.special._testutils import assert_func_equal
6
+
7
+
8
+ def log_ndtr_ndtri_exp(y):
9
+ return log_ndtr(ndtri_exp(y))
10
+
11
+
12
+ @pytest.fixture(scope="class")
13
+ def uniform_random_points():
14
+ random_state = np.random.RandomState(1234)
15
+ points = random_state.random_sample(1000)
16
+ return points
17
+
18
+
19
+ class TestNdtriExp:
20
+ """Tests that ndtri_exp is sufficiently close to an inverse of log_ndtr.
21
+
22
+ We have separate tests for the five intervals (-inf, -10),
23
+ [-10, -2), [-2, -0.14542), [-0.14542, -1e-6), and [-1e-6, 0).
24
+ ndtri_exp(y) is computed in three different ways depending on if y
25
+ is in (-inf, -2), [-2, log(1 - exp(-2))], or [log(1 - exp(-2), 0).
26
+ Each of these intervals is given its own test with two additional tests
27
+ for handling very small values and values very close to zero.
28
+ """
29
+
30
+ @pytest.mark.parametrize(
31
+ "test_input", [-1e1, -1e2, -1e10, -1e20, -np.finfo(float).max]
32
+ )
33
+ def test_very_small_arg(self, test_input, uniform_random_points):
34
+ scale = test_input
35
+ points = scale * (0.5 * uniform_random_points + 0.5)
36
+ assert_func_equal(
37
+ log_ndtr_ndtri_exp,
38
+ lambda y: y, points,
39
+ rtol=1e-14,
40
+ nan_ok=True
41
+ )
42
+
43
+ @pytest.mark.parametrize(
44
+ "interval,expected_rtol",
45
+ [
46
+ ((-10, -2), 1e-14),
47
+ ((-2, -0.14542), 1e-12),
48
+ ((-0.14542, -1e-6), 1e-10),
49
+ ((-1e-6, 0), 1e-6),
50
+ ],
51
+ )
52
+ def test_in_interval(self, interval, expected_rtol, uniform_random_points):
53
+ left, right = interval
54
+ points = (right - left) * uniform_random_points + left
55
+ assert_func_equal(
56
+ log_ndtr_ndtri_exp,
57
+ lambda y: y, points,
58
+ rtol=expected_rtol,
59
+ nan_ok=True
60
+ )
61
+
62
+ def test_extreme(self):
63
+ # bigneg is not quite the largest negative double precision value.
64
+ # Here's why:
65
+ # The round-trip calculation
66
+ # y = ndtri_exp(bigneg)
67
+ # bigneg2 = log_ndtr(y)
68
+ # where bigneg is a very large negative value, would--with infinite
69
+ # precision--result in bigneg2 == bigneg. When bigneg is large enough,
70
+ # y is effectively equal to -sqrt(2)*sqrt(-bigneg), and log_ndtr(y) is
71
+ # effectively -(y/sqrt(2))**2. If we use bigneg = np.finfo(float).min,
72
+ # then by construction, the theoretical value is the most negative
73
+ # finite value that can be represented with 64 bit float point. This
74
+ # means tiny changes in how the computation proceeds can result in the
75
+ # return value being -inf. (E.g. changing the constant representation
76
+ # of 1/sqrt(2) from 0.7071067811865475--which is the value returned by
77
+ # 1/np.sqrt(2)--to 0.7071067811865476--which is the most accurate 64
78
+ # bit floating point representation of 1/sqrt(2)--results in the
79
+ # round-trip that starts with np.finfo(float).min returning -inf. So
80
+ # we'll move the bigneg value a few ULPs towards 0 to avoid this
81
+ # sensitivity.
82
+ # Use the reduce method to apply nextafter four times.
83
+ bigneg = np.nextafter.reduce([np.finfo(float).min, 0, 0, 0, 0])
84
+ # tinyneg is approx. -2.225e-308.
85
+ tinyneg = -np.finfo(float).tiny
86
+ x = np.array([tinyneg, bigneg])
87
+ result = log_ndtr_ndtri_exp(x)
88
+ assert_allclose(result, x, rtol=1e-12)
89
+
90
+ def test_asymptotes(self):
91
+ assert_equal(ndtri_exp([-np.inf, 0.0]), [-np.inf, np.inf])
92
+
93
+ def test_outside_domain(self):
94
+ assert np.isnan(ndtri_exp(1.0))
.venv/Lib/site-packages/scipy/special/tests/test_orthogonal.py ADDED
@@ -0,0 +1,804 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from numpy import array, sqrt
3
+ from numpy.testing import (assert_array_almost_equal, assert_equal,
4
+ assert_almost_equal, assert_allclose)
5
+ from pytest import raises as assert_raises
6
+
7
+ from scipy import integrate
8
+ import scipy.special as sc
9
+ from scipy.special import gamma
10
+ import scipy.special._orthogonal as orth
11
+
12
+
13
+ class TestCheby:
14
+ def test_chebyc(self):
15
+ C0 = orth.chebyc(0)
16
+ C1 = orth.chebyc(1)
17
+ with np.errstate(all='ignore'):
18
+ C2 = orth.chebyc(2)
19
+ C3 = orth.chebyc(3)
20
+ C4 = orth.chebyc(4)
21
+ C5 = orth.chebyc(5)
22
+
23
+ assert_array_almost_equal(C0.c,[2],13)
24
+ assert_array_almost_equal(C1.c,[1,0],13)
25
+ assert_array_almost_equal(C2.c,[1,0,-2],13)
26
+ assert_array_almost_equal(C3.c,[1,0,-3,0],13)
27
+ assert_array_almost_equal(C4.c,[1,0,-4,0,2],13)
28
+ assert_array_almost_equal(C5.c,[1,0,-5,0,5,0],13)
29
+
30
+ def test_chebys(self):
31
+ S0 = orth.chebys(0)
32
+ S1 = orth.chebys(1)
33
+ S2 = orth.chebys(2)
34
+ S3 = orth.chebys(3)
35
+ S4 = orth.chebys(4)
36
+ S5 = orth.chebys(5)
37
+ assert_array_almost_equal(S0.c,[1],13)
38
+ assert_array_almost_equal(S1.c,[1,0],13)
39
+ assert_array_almost_equal(S2.c,[1,0,-1],13)
40
+ assert_array_almost_equal(S3.c,[1,0,-2,0],13)
41
+ assert_array_almost_equal(S4.c,[1,0,-3,0,1],13)
42
+ assert_array_almost_equal(S5.c,[1,0,-4,0,3,0],13)
43
+
44
+ def test_chebyt(self):
45
+ T0 = orth.chebyt(0)
46
+ T1 = orth.chebyt(1)
47
+ T2 = orth.chebyt(2)
48
+ T3 = orth.chebyt(3)
49
+ T4 = orth.chebyt(4)
50
+ T5 = orth.chebyt(5)
51
+ assert_array_almost_equal(T0.c,[1],13)
52
+ assert_array_almost_equal(T1.c,[1,0],13)
53
+ assert_array_almost_equal(T2.c,[2,0,-1],13)
54
+ assert_array_almost_equal(T3.c,[4,0,-3,0],13)
55
+ assert_array_almost_equal(T4.c,[8,0,-8,0,1],13)
56
+ assert_array_almost_equal(T5.c,[16,0,-20,0,5,0],13)
57
+
58
+ def test_chebyu(self):
59
+ U0 = orth.chebyu(0)
60
+ U1 = orth.chebyu(1)
61
+ U2 = orth.chebyu(2)
62
+ U3 = orth.chebyu(3)
63
+ U4 = orth.chebyu(4)
64
+ U5 = orth.chebyu(5)
65
+ assert_array_almost_equal(U0.c,[1],13)
66
+ assert_array_almost_equal(U1.c,[2,0],13)
67
+ assert_array_almost_equal(U2.c,[4,0,-1],13)
68
+ assert_array_almost_equal(U3.c,[8,0,-4,0],13)
69
+ assert_array_almost_equal(U4.c,[16,0,-12,0,1],13)
70
+ assert_array_almost_equal(U5.c,[32,0,-32,0,6,0],13)
71
+
72
+
73
+ class TestGegenbauer:
74
+
75
+ def test_gegenbauer(self):
76
+ a = 5*np.random.random() - 0.5
77
+ if np.any(a == 0):
78
+ a = -0.2
79
+ Ca0 = orth.gegenbauer(0,a)
80
+ Ca1 = orth.gegenbauer(1,a)
81
+ Ca2 = orth.gegenbauer(2,a)
82
+ Ca3 = orth.gegenbauer(3,a)
83
+ Ca4 = orth.gegenbauer(4,a)
84
+ Ca5 = orth.gegenbauer(5,a)
85
+
86
+ assert_array_almost_equal(Ca0.c,array([1]),13)
87
+ assert_array_almost_equal(Ca1.c,array([2*a,0]),13)
88
+ assert_array_almost_equal(Ca2.c,array([2*a*(a+1),0,-a]),13)
89
+ assert_array_almost_equal(Ca3.c,array([4*sc.poch(a,3),0,-6*a*(a+1),
90
+ 0])/3.0,11)
91
+ assert_array_almost_equal(Ca4.c,array([4*sc.poch(a,4),0,-12*sc.poch(a,3),
92
+ 0,3*a*(a+1)])/6.0,11)
93
+ assert_array_almost_equal(Ca5.c,array([4*sc.poch(a,5),0,-20*sc.poch(a,4),
94
+ 0,15*sc.poch(a,3),0])/15.0,11)
95
+
96
+
97
+ class TestHermite:
98
+ def test_hermite(self):
99
+ H0 = orth.hermite(0)
100
+ H1 = orth.hermite(1)
101
+ H2 = orth.hermite(2)
102
+ H3 = orth.hermite(3)
103
+ H4 = orth.hermite(4)
104
+ H5 = orth.hermite(5)
105
+ assert_array_almost_equal(H0.c,[1],13)
106
+ assert_array_almost_equal(H1.c,[2,0],13)
107
+ assert_array_almost_equal(H2.c,[4,0,-2],13)
108
+ assert_array_almost_equal(H3.c,[8,0,-12,0],13)
109
+ assert_array_almost_equal(H4.c,[16,0,-48,0,12],12)
110
+ assert_array_almost_equal(H5.c,[32,0,-160,0,120,0],12)
111
+
112
+ def test_hermitenorm(self):
113
+ # He_n(x) = 2**(-n/2) H_n(x/sqrt(2))
114
+ psub = np.poly1d([1.0/sqrt(2),0])
115
+ H0 = orth.hermitenorm(0)
116
+ H1 = orth.hermitenorm(1)
117
+ H2 = orth.hermitenorm(2)
118
+ H3 = orth.hermitenorm(3)
119
+ H4 = orth.hermitenorm(4)
120
+ H5 = orth.hermitenorm(5)
121
+ he0 = orth.hermite(0)(psub)
122
+ he1 = orth.hermite(1)(psub) / sqrt(2)
123
+ he2 = orth.hermite(2)(psub) / 2.0
124
+ he3 = orth.hermite(3)(psub) / (2*sqrt(2))
125
+ he4 = orth.hermite(4)(psub) / 4.0
126
+ he5 = orth.hermite(5)(psub) / (4.0*sqrt(2))
127
+
128
+ assert_array_almost_equal(H0.c,he0.c,13)
129
+ assert_array_almost_equal(H1.c,he1.c,13)
130
+ assert_array_almost_equal(H2.c,he2.c,13)
131
+ assert_array_almost_equal(H3.c,he3.c,13)
132
+ assert_array_almost_equal(H4.c,he4.c,13)
133
+ assert_array_almost_equal(H5.c,he5.c,13)
134
+
135
+
136
+ class TestShLegendre:
137
+ def test_sh_legendre(self):
138
+ # P*_n(x) = P_n(2x-1)
139
+ psub = np.poly1d([2,-1])
140
+ Ps0 = orth.sh_legendre(0)
141
+ Ps1 = orth.sh_legendre(1)
142
+ Ps2 = orth.sh_legendre(2)
143
+ Ps3 = orth.sh_legendre(3)
144
+ Ps4 = orth.sh_legendre(4)
145
+ Ps5 = orth.sh_legendre(5)
146
+ pse0 = orth.legendre(0)(psub)
147
+ pse1 = orth.legendre(1)(psub)
148
+ pse2 = orth.legendre(2)(psub)
149
+ pse3 = orth.legendre(3)(psub)
150
+ pse4 = orth.legendre(4)(psub)
151
+ pse5 = orth.legendre(5)(psub)
152
+ assert_array_almost_equal(Ps0.c,pse0.c,13)
153
+ assert_array_almost_equal(Ps1.c,pse1.c,13)
154
+ assert_array_almost_equal(Ps2.c,pse2.c,13)
155
+ assert_array_almost_equal(Ps3.c,pse3.c,13)
156
+ assert_array_almost_equal(Ps4.c,pse4.c,12)
157
+ assert_array_almost_equal(Ps5.c,pse5.c,12)
158
+
159
+
160
+ class TestShChebyt:
161
+ def test_sh_chebyt(self):
162
+ # T*_n(x) = T_n(2x-1)
163
+ psub = np.poly1d([2,-1])
164
+ Ts0 = orth.sh_chebyt(0)
165
+ Ts1 = orth.sh_chebyt(1)
166
+ Ts2 = orth.sh_chebyt(2)
167
+ Ts3 = orth.sh_chebyt(3)
168
+ Ts4 = orth.sh_chebyt(4)
169
+ Ts5 = orth.sh_chebyt(5)
170
+ tse0 = orth.chebyt(0)(psub)
171
+ tse1 = orth.chebyt(1)(psub)
172
+ tse2 = orth.chebyt(2)(psub)
173
+ tse3 = orth.chebyt(3)(psub)
174
+ tse4 = orth.chebyt(4)(psub)
175
+ tse5 = orth.chebyt(5)(psub)
176
+ assert_array_almost_equal(Ts0.c,tse0.c,13)
177
+ assert_array_almost_equal(Ts1.c,tse1.c,13)
178
+ assert_array_almost_equal(Ts2.c,tse2.c,13)
179
+ assert_array_almost_equal(Ts3.c,tse3.c,13)
180
+ assert_array_almost_equal(Ts4.c,tse4.c,12)
181
+ assert_array_almost_equal(Ts5.c,tse5.c,12)
182
+
183
+
184
+ class TestShChebyu:
185
+ def test_sh_chebyu(self):
186
+ # U*_n(x) = U_n(2x-1)
187
+ psub = np.poly1d([2,-1])
188
+ Us0 = orth.sh_chebyu(0)
189
+ Us1 = orth.sh_chebyu(1)
190
+ Us2 = orth.sh_chebyu(2)
191
+ Us3 = orth.sh_chebyu(3)
192
+ Us4 = orth.sh_chebyu(4)
193
+ Us5 = orth.sh_chebyu(5)
194
+ use0 = orth.chebyu(0)(psub)
195
+ use1 = orth.chebyu(1)(psub)
196
+ use2 = orth.chebyu(2)(psub)
197
+ use3 = orth.chebyu(3)(psub)
198
+ use4 = orth.chebyu(4)(psub)
199
+ use5 = orth.chebyu(5)(psub)
200
+ assert_array_almost_equal(Us0.c,use0.c,13)
201
+ assert_array_almost_equal(Us1.c,use1.c,13)
202
+ assert_array_almost_equal(Us2.c,use2.c,13)
203
+ assert_array_almost_equal(Us3.c,use3.c,13)
204
+ assert_array_almost_equal(Us4.c,use4.c,12)
205
+ assert_array_almost_equal(Us5.c,use5.c,11)
206
+
207
+
208
+ class TestShJacobi:
209
+ def test_sh_jacobi(self):
210
+ # G^(p,q)_n(x) = n! gamma(n+p)/gamma(2*n+p) * P^(p-q,q-1)_n(2*x-1)
211
+ def conv(n, p):
212
+ return gamma(n + 1) * gamma(n + p) / gamma(2 * n + p)
213
+ psub = np.poly1d([2,-1])
214
+ q = 4 * np.random.random()
215
+ p = q-1 + 2*np.random.random()
216
+ # print("shifted jacobi p,q = ", p, q)
217
+ G0 = orth.sh_jacobi(0,p,q)
218
+ G1 = orth.sh_jacobi(1,p,q)
219
+ G2 = orth.sh_jacobi(2,p,q)
220
+ G3 = orth.sh_jacobi(3,p,q)
221
+ G4 = orth.sh_jacobi(4,p,q)
222
+ G5 = orth.sh_jacobi(5,p,q)
223
+ ge0 = orth.jacobi(0,p-q,q-1)(psub) * conv(0,p)
224
+ ge1 = orth.jacobi(1,p-q,q-1)(psub) * conv(1,p)
225
+ ge2 = orth.jacobi(2,p-q,q-1)(psub) * conv(2,p)
226
+ ge3 = orth.jacobi(3,p-q,q-1)(psub) * conv(3,p)
227
+ ge4 = orth.jacobi(4,p-q,q-1)(psub) * conv(4,p)
228
+ ge5 = orth.jacobi(5,p-q,q-1)(psub) * conv(5,p)
229
+
230
+ assert_array_almost_equal(G0.c,ge0.c,13)
231
+ assert_array_almost_equal(G1.c,ge1.c,13)
232
+ assert_array_almost_equal(G2.c,ge2.c,13)
233
+ assert_array_almost_equal(G3.c,ge3.c,13)
234
+ assert_array_almost_equal(G4.c,ge4.c,13)
235
+ assert_array_almost_equal(G5.c,ge5.c,13)
236
+
237
+
238
+ class TestCall:
239
+ def test_call(self):
240
+ poly = []
241
+ for n in range(5):
242
+ poly.extend([x.strip() for x in
243
+ ("""
244
+ orth.jacobi(%(n)d,0.3,0.9)
245
+ orth.sh_jacobi(%(n)d,0.3,0.9)
246
+ orth.genlaguerre(%(n)d,0.3)
247
+ orth.laguerre(%(n)d)
248
+ orth.hermite(%(n)d)
249
+ orth.hermitenorm(%(n)d)
250
+ orth.gegenbauer(%(n)d,0.3)
251
+ orth.chebyt(%(n)d)
252
+ orth.chebyu(%(n)d)
253
+ orth.chebyc(%(n)d)
254
+ orth.chebys(%(n)d)
255
+ orth.sh_chebyt(%(n)d)
256
+ orth.sh_chebyu(%(n)d)
257
+ orth.legendre(%(n)d)
258
+ orth.sh_legendre(%(n)d)
259
+ """ % dict(n=n)).split()
260
+ ])
261
+ with np.errstate(all='ignore'):
262
+ for pstr in poly:
263
+ p = eval(pstr)
264
+ assert_almost_equal(p(0.315), np.poly1d(p.coef)(0.315),
265
+ err_msg=pstr)
266
+
267
+
268
+ class TestGenlaguerre:
269
+ def test_regression(self):
270
+ assert_equal(orth.genlaguerre(1, 1, monic=False)(0), 2.)
271
+ assert_equal(orth.genlaguerre(1, 1, monic=True)(0), -2.)
272
+ assert_equal(orth.genlaguerre(1, 1, monic=False), np.poly1d([-1, 2]))
273
+ assert_equal(orth.genlaguerre(1, 1, monic=True), np.poly1d([1, -2]))
274
+
275
+
276
+ def verify_gauss_quad(root_func, eval_func, weight_func, a, b, N,
277
+ rtol=1e-15, atol=5e-14):
278
+ # this test is copied from numpy's TestGauss in test_hermite.py
279
+ x, w, mu = root_func(N, True)
280
+
281
+ n = np.arange(N, dtype=np.dtype("long"))
282
+ v = eval_func(n[:,np.newaxis], x)
283
+ vv = np.dot(v*w, v.T)
284
+ vd = 1 / np.sqrt(vv.diagonal())
285
+ vv = vd[:, np.newaxis] * vv * vd
286
+ assert_allclose(vv, np.eye(N), rtol, atol)
287
+
288
+ # check that the integral of 1 is correct
289
+ assert_allclose(w.sum(), mu, rtol, atol)
290
+
291
+ # compare the results of integrating a function with quad.
292
+ def f(x):
293
+ return x ** 3 - 3 * x ** 2 + x - 2
294
+ resI = integrate.quad(lambda x: f(x)*weight_func(x), a, b)
295
+ resG = np.vdot(f(x), w)
296
+ rtol = 1e-6 if 1e-6 < resI[1] else resI[1] * 10
297
+ assert_allclose(resI[0], resG, rtol=rtol)
298
+
299
+ def test_roots_jacobi():
300
+ def rf(a, b):
301
+ return lambda n, mu: sc.roots_jacobi(n, a, b, mu)
302
+ def ef(a, b):
303
+ return lambda n, x: sc.eval_jacobi(n, a, b, x)
304
+ def wf(a, b):
305
+ return lambda x: (1 - x) ** a * (1 + x) ** b
306
+
307
+ vgq = verify_gauss_quad
308
+ vgq(rf(-0.5, -0.75), ef(-0.5, -0.75), wf(-0.5, -0.75), -1., 1., 5)
309
+ vgq(rf(-0.5, -0.75), ef(-0.5, -0.75), wf(-0.5, -0.75), -1., 1.,
310
+ 25, atol=1e-12)
311
+ vgq(rf(-0.5, -0.75), ef(-0.5, -0.75), wf(-0.5, -0.75), -1., 1.,
312
+ 100, atol=1e-11)
313
+
314
+ vgq(rf(0.5, -0.5), ef(0.5, -0.5), wf(0.5, -0.5), -1., 1., 5)
315
+ vgq(rf(0.5, -0.5), ef(0.5, -0.5), wf(0.5, -0.5), -1., 1., 25, atol=1.5e-13)
316
+ vgq(rf(0.5, -0.5), ef(0.5, -0.5), wf(0.5, -0.5), -1., 1., 100, atol=2e-12)
317
+
318
+ vgq(rf(1, 0.5), ef(1, 0.5), wf(1, 0.5), -1., 1., 5, atol=2e-13)
319
+ vgq(rf(1, 0.5), ef(1, 0.5), wf(1, 0.5), -1., 1., 25, atol=2e-13)
320
+ vgq(rf(1, 0.5), ef(1, 0.5), wf(1, 0.5), -1., 1., 100, atol=1e-12)
321
+
322
+ vgq(rf(0.9, 2), ef(0.9, 2), wf(0.9, 2), -1., 1., 5)
323
+ vgq(rf(0.9, 2), ef(0.9, 2), wf(0.9, 2), -1., 1., 25, atol=1e-13)
324
+ vgq(rf(0.9, 2), ef(0.9, 2), wf(0.9, 2), -1., 1., 100, atol=3e-13)
325
+
326
+ vgq(rf(18.24, 27.3), ef(18.24, 27.3), wf(18.24, 27.3), -1., 1., 5)
327
+ vgq(rf(18.24, 27.3), ef(18.24, 27.3), wf(18.24, 27.3), -1., 1., 25,
328
+ atol=1.1e-14)
329
+ vgq(rf(18.24, 27.3), ef(18.24, 27.3), wf(18.24, 27.3), -1., 1.,
330
+ 100, atol=1e-13)
331
+
332
+ vgq(rf(47.1, -0.2), ef(47.1, -0.2), wf(47.1, -0.2), -1., 1., 5, atol=1e-13)
333
+ vgq(rf(47.1, -0.2), ef(47.1, -0.2), wf(47.1, -0.2), -1., 1., 25, atol=2e-13)
334
+ vgq(rf(47.1, -0.2), ef(47.1, -0.2), wf(47.1, -0.2), -1., 1.,
335
+ 100, atol=1e-11)
336
+
337
+ vgq(rf(1., 658.), ef(1., 658.), wf(1., 658.), -1., 1., 5, atol=2e-13)
338
+ vgq(rf(1., 658.), ef(1., 658.), wf(1., 658.), -1., 1., 25, atol=1e-12)
339
+ vgq(rf(1., 658.), ef(1., 658.), wf(1., 658.), -1., 1., 100, atol=1e-11)
340
+ vgq(rf(1., 658.), ef(1., 658.), wf(1., 658.), -1., 1., 250, atol=1e-11)
341
+
342
+ vgq(rf(511., 511.), ef(511., 511.), wf(511., 511.), -1., 1., 5,
343
+ atol=1e-12)
344
+ vgq(rf(511., 511.), ef(511., 511.), wf(511., 511.), -1., 1., 25,
345
+ atol=1e-11)
346
+ vgq(rf(511., 511.), ef(511., 511.), wf(511., 511.), -1., 1., 100,
347
+ atol=1e-10)
348
+
349
+ vgq(rf(511., 512.), ef(511., 512.), wf(511., 512.), -1., 1., 5,
350
+ atol=1e-12)
351
+ vgq(rf(511., 512.), ef(511., 512.), wf(511., 512.), -1., 1., 25,
352
+ atol=1e-11)
353
+ vgq(rf(511., 512.), ef(511., 512.), wf(511., 512.), -1., 1., 100,
354
+ atol=1e-10)
355
+
356
+ vgq(rf(1000., 500.), ef(1000., 500.), wf(1000., 500.), -1., 1., 5,
357
+ atol=1e-12)
358
+ vgq(rf(1000., 500.), ef(1000., 500.), wf(1000., 500.), -1., 1., 25,
359
+ atol=1e-11)
360
+ vgq(rf(1000., 500.), ef(1000., 500.), wf(1000., 500.), -1., 1., 100,
361
+ atol=1e-10)
362
+
363
+ vgq(rf(2.25, 68.9), ef(2.25, 68.9), wf(2.25, 68.9), -1., 1., 5)
364
+ vgq(rf(2.25, 68.9), ef(2.25, 68.9), wf(2.25, 68.9), -1., 1., 25,
365
+ atol=1e-13)
366
+ vgq(rf(2.25, 68.9), ef(2.25, 68.9), wf(2.25, 68.9), -1., 1., 100,
367
+ atol=1e-13)
368
+
369
+ # when alpha == beta == 0, P_n^{a,b}(x) == P_n(x)
370
+ xj, wj = sc.roots_jacobi(6, 0.0, 0.0)
371
+ xl, wl = sc.roots_legendre(6)
372
+ assert_allclose(xj, xl, 1e-14, 1e-14)
373
+ assert_allclose(wj, wl, 1e-14, 1e-14)
374
+
375
+ # when alpha == beta != 0, P_n^{a,b}(x) == C_n^{alpha+0.5}(x)
376
+ xj, wj = sc.roots_jacobi(6, 4.0, 4.0)
377
+ xc, wc = sc.roots_gegenbauer(6, 4.5)
378
+ assert_allclose(xj, xc, 1e-14, 1e-14)
379
+ assert_allclose(wj, wc, 1e-14, 1e-14)
380
+
381
+ x, w = sc.roots_jacobi(5, 2, 3, False)
382
+ y, v, m = sc.roots_jacobi(5, 2, 3, True)
383
+ assert_allclose(x, y, 1e-14, 1e-14)
384
+ assert_allclose(w, v, 1e-14, 1e-14)
385
+
386
+ muI, muI_err = integrate.quad(wf(2,3), -1, 1)
387
+ assert_allclose(m, muI, rtol=muI_err)
388
+
389
+ assert_raises(ValueError, sc.roots_jacobi, 0, 1, 1)
390
+ assert_raises(ValueError, sc.roots_jacobi, 3.3, 1, 1)
391
+ assert_raises(ValueError, sc.roots_jacobi, 3, -2, 1)
392
+ assert_raises(ValueError, sc.roots_jacobi, 3, 1, -2)
393
+ assert_raises(ValueError, sc.roots_jacobi, 3, -2, -2)
394
+
395
+ def test_roots_sh_jacobi():
396
+ def rf(a, b):
397
+ return lambda n, mu: sc.roots_sh_jacobi(n, a, b, mu)
398
+ def ef(a, b):
399
+ return lambda n, x: sc.eval_sh_jacobi(n, a, b, x)
400
+ def wf(a, b):
401
+ return lambda x: (1.0 - x) ** (a - b) * x ** (b - 1.0)
402
+
403
+ vgq = verify_gauss_quad
404
+ vgq(rf(-0.5, 0.25), ef(-0.5, 0.25), wf(-0.5, 0.25), 0., 1., 5)
405
+ vgq(rf(-0.5, 0.25), ef(-0.5, 0.25), wf(-0.5, 0.25), 0., 1.,
406
+ 25, atol=1e-12)
407
+ vgq(rf(-0.5, 0.25), ef(-0.5, 0.25), wf(-0.5, 0.25), 0., 1.,
408
+ 100, atol=1e-11)
409
+
410
+ vgq(rf(0.5, 0.5), ef(0.5, 0.5), wf(0.5, 0.5), 0., 1., 5)
411
+ vgq(rf(0.5, 0.5), ef(0.5, 0.5), wf(0.5, 0.5), 0., 1., 25, atol=1e-13)
412
+ vgq(rf(0.5, 0.5), ef(0.5, 0.5), wf(0.5, 0.5), 0., 1., 100, atol=1e-12)
413
+
414
+ vgq(rf(1, 0.5), ef(1, 0.5), wf(1, 0.5), 0., 1., 5)
415
+ vgq(rf(1, 0.5), ef(1, 0.5), wf(1, 0.5), 0., 1., 25, atol=1.5e-13)
416
+ vgq(rf(1, 0.5), ef(1, 0.5), wf(1, 0.5), 0., 1., 100, atol=2e-12)
417
+
418
+ vgq(rf(2, 0.9), ef(2, 0.9), wf(2, 0.9), 0., 1., 5)
419
+ vgq(rf(2, 0.9), ef(2, 0.9), wf(2, 0.9), 0., 1., 25, atol=1e-13)
420
+ vgq(rf(2, 0.9), ef(2, 0.9), wf(2, 0.9), 0., 1., 100, atol=1e-12)
421
+
422
+ vgq(rf(27.3, 18.24), ef(27.3, 18.24), wf(27.3, 18.24), 0., 1., 5)
423
+ vgq(rf(27.3, 18.24), ef(27.3, 18.24), wf(27.3, 18.24), 0., 1., 25)
424
+ vgq(rf(27.3, 18.24), ef(27.3, 18.24), wf(27.3, 18.24), 0., 1.,
425
+ 100, atol=1e-13)
426
+
427
+ vgq(rf(47.1, 0.2), ef(47.1, 0.2), wf(47.1, 0.2), 0., 1., 5, atol=1e-12)
428
+ vgq(rf(47.1, 0.2), ef(47.1, 0.2), wf(47.1, 0.2), 0., 1., 25, atol=1e-11)
429
+ vgq(rf(47.1, 0.2), ef(47.1, 0.2), wf(47.1, 0.2), 0., 1., 100, atol=1e-10)
430
+
431
+ vgq(rf(68.9, 2.25), ef(68.9, 2.25), wf(68.9, 2.25), 0., 1., 5, atol=3.5e-14)
432
+ vgq(rf(68.9, 2.25), ef(68.9, 2.25), wf(68.9, 2.25), 0., 1., 25, atol=2e-13)
433
+ vgq(rf(68.9, 2.25), ef(68.9, 2.25), wf(68.9, 2.25), 0., 1.,
434
+ 100, atol=1e-12)
435
+
436
+ x, w = sc.roots_sh_jacobi(5, 3, 2, False)
437
+ y, v, m = sc.roots_sh_jacobi(5, 3, 2, True)
438
+ assert_allclose(x, y, 1e-14, 1e-14)
439
+ assert_allclose(w, v, 1e-14, 1e-14)
440
+
441
+ muI, muI_err = integrate.quad(wf(3,2), 0, 1)
442
+ assert_allclose(m, muI, rtol=muI_err)
443
+
444
+ assert_raises(ValueError, sc.roots_sh_jacobi, 0, 1, 1)
445
+ assert_raises(ValueError, sc.roots_sh_jacobi, 3.3, 1, 1)
446
+ assert_raises(ValueError, sc.roots_sh_jacobi, 3, 1, 2) # p - q <= -1
447
+ assert_raises(ValueError, sc.roots_sh_jacobi, 3, 2, -1) # q <= 0
448
+ assert_raises(ValueError, sc.roots_sh_jacobi, 3, -2, -1) # both
449
+
450
+ def test_roots_hermite():
451
+ rootf = sc.roots_hermite
452
+ evalf = sc.eval_hermite
453
+ weightf = orth.hermite(5).weight_func
454
+
455
+ verify_gauss_quad(rootf, evalf, weightf, -np.inf, np.inf, 5)
456
+ verify_gauss_quad(rootf, evalf, weightf, -np.inf, np.inf, 25, atol=1e-13)
457
+ verify_gauss_quad(rootf, evalf, weightf, -np.inf, np.inf, 100, atol=1e-12)
458
+
459
+ # Golub-Welsch branch
460
+ x, w = sc.roots_hermite(5, False)
461
+ y, v, m = sc.roots_hermite(5, True)
462
+ assert_allclose(x, y, 1e-14, 1e-14)
463
+ assert_allclose(w, v, 1e-14, 1e-14)
464
+
465
+ muI, muI_err = integrate.quad(weightf, -np.inf, np.inf)
466
+ assert_allclose(m, muI, rtol=muI_err)
467
+
468
+ # Asymptotic branch (switch over at n >= 150)
469
+ x, w = sc.roots_hermite(200, False)
470
+ y, v, m = sc.roots_hermite(200, True)
471
+ assert_allclose(x, y, 1e-14, 1e-14)
472
+ assert_allclose(w, v, 1e-14, 1e-14)
473
+ assert_allclose(sum(v), m, 1e-14, 1e-14)
474
+
475
+ assert_raises(ValueError, sc.roots_hermite, 0)
476
+ assert_raises(ValueError, sc.roots_hermite, 3.3)
477
+
478
+ def test_roots_hermite_asy():
479
+ # Recursion for Hermite functions
480
+ def hermite_recursion(n, nodes):
481
+ H = np.zeros((n, nodes.size))
482
+ H[0,:] = np.pi**(-0.25) * np.exp(-0.5*nodes**2)
483
+ if n > 1:
484
+ H[1,:] = sqrt(2.0) * nodes * H[0,:]
485
+ for k in range(2, n):
486
+ H[k,:] = sqrt(2.0/k) * nodes * H[k-1,:] - sqrt((k-1.0)/k) * H[k-2,:]
487
+ return H
488
+
489
+ # This tests only the nodes
490
+ def test(N, rtol=1e-15, atol=1e-14):
491
+ x, w = orth._roots_hermite_asy(N)
492
+ H = hermite_recursion(N+1, x)
493
+ assert_allclose(H[-1,:], np.zeros(N), rtol, atol)
494
+ assert_allclose(sum(w), sqrt(np.pi), rtol, atol)
495
+
496
+ test(150, atol=1e-12)
497
+ test(151, atol=1e-12)
498
+ test(300, atol=1e-12)
499
+ test(301, atol=1e-12)
500
+ test(500, atol=1e-12)
501
+ test(501, atol=1e-12)
502
+ test(999, atol=1e-12)
503
+ test(1000, atol=1e-12)
504
+ test(2000, atol=1e-12)
505
+ test(5000, atol=1e-12)
506
+
507
+ def test_roots_hermitenorm():
508
+ rootf = sc.roots_hermitenorm
509
+ evalf = sc.eval_hermitenorm
510
+ weightf = orth.hermitenorm(5).weight_func
511
+
512
+ verify_gauss_quad(rootf, evalf, weightf, -np.inf, np.inf, 5)
513
+ verify_gauss_quad(rootf, evalf, weightf, -np.inf, np.inf, 25, atol=1e-13)
514
+ verify_gauss_quad(rootf, evalf, weightf, -np.inf, np.inf, 100, atol=1e-12)
515
+
516
+ x, w = sc.roots_hermitenorm(5, False)
517
+ y, v, m = sc.roots_hermitenorm(5, True)
518
+ assert_allclose(x, y, 1e-14, 1e-14)
519
+ assert_allclose(w, v, 1e-14, 1e-14)
520
+
521
+ muI, muI_err = integrate.quad(weightf, -np.inf, np.inf)
522
+ assert_allclose(m, muI, rtol=muI_err)
523
+
524
+ assert_raises(ValueError, sc.roots_hermitenorm, 0)
525
+ assert_raises(ValueError, sc.roots_hermitenorm, 3.3)
526
+
527
+ def test_roots_gegenbauer():
528
+ def rootf(a):
529
+ return lambda n, mu: sc.roots_gegenbauer(n, a, mu)
530
+ def evalf(a):
531
+ return lambda n, x: sc.eval_gegenbauer(n, a, x)
532
+ def weightf(a):
533
+ return lambda x: (1 - x ** 2) ** (a - 0.5)
534
+
535
+ vgq = verify_gauss_quad
536
+ vgq(rootf(-0.25), evalf(-0.25), weightf(-0.25), -1., 1., 5)
537
+ vgq(rootf(-0.25), evalf(-0.25), weightf(-0.25), -1., 1., 25, atol=1e-12)
538
+ vgq(rootf(-0.25), evalf(-0.25), weightf(-0.25), -1., 1., 100, atol=1e-11)
539
+
540
+ vgq(rootf(0.1), evalf(0.1), weightf(0.1), -1., 1., 5)
541
+ vgq(rootf(0.1), evalf(0.1), weightf(0.1), -1., 1., 25, atol=1e-13)
542
+ vgq(rootf(0.1), evalf(0.1), weightf(0.1), -1., 1., 100, atol=1e-12)
543
+
544
+ vgq(rootf(1), evalf(1), weightf(1), -1., 1., 5)
545
+ vgq(rootf(1), evalf(1), weightf(1), -1., 1., 25, atol=1e-13)
546
+ vgq(rootf(1), evalf(1), weightf(1), -1., 1., 100, atol=1e-12)
547
+
548
+ vgq(rootf(10), evalf(10), weightf(10), -1., 1., 5)
549
+ vgq(rootf(10), evalf(10), weightf(10), -1., 1., 25, atol=1e-13)
550
+ vgq(rootf(10), evalf(10), weightf(10), -1., 1., 100, atol=1e-12)
551
+
552
+ vgq(rootf(50), evalf(50), weightf(50), -1., 1., 5, atol=1e-13)
553
+ vgq(rootf(50), evalf(50), weightf(50), -1., 1., 25, atol=1e-12)
554
+ vgq(rootf(50), evalf(50), weightf(50), -1., 1., 100, atol=1e-11)
555
+
556
+ # Alpha=170 is where the approximation used in roots_gegenbauer changes
557
+ vgq(rootf(170), evalf(170), weightf(170), -1., 1., 5, atol=1e-13)
558
+ vgq(rootf(170), evalf(170), weightf(170), -1., 1., 25, atol=1e-12)
559
+ vgq(rootf(170), evalf(170), weightf(170), -1., 1., 100, atol=1e-11)
560
+ vgq(rootf(170.5), evalf(170.5), weightf(170.5), -1., 1., 5, atol=1.25e-13)
561
+ vgq(rootf(170.5), evalf(170.5), weightf(170.5), -1., 1., 25, atol=1e-12)
562
+ vgq(rootf(170.5), evalf(170.5), weightf(170.5), -1., 1., 100, atol=1e-11)
563
+
564
+ # Test for failures, e.g. overflows, resulting from large alphas
565
+ vgq(rootf(238), evalf(238), weightf(238), -1., 1., 5, atol=1e-13)
566
+ vgq(rootf(238), evalf(238), weightf(238), -1., 1., 25, atol=1e-12)
567
+ vgq(rootf(238), evalf(238), weightf(238), -1., 1., 100, atol=1e-11)
568
+ vgq(rootf(512.5), evalf(512.5), weightf(512.5), -1., 1., 5, atol=1e-12)
569
+ vgq(rootf(512.5), evalf(512.5), weightf(512.5), -1., 1., 25, atol=1e-11)
570
+ vgq(rootf(512.5), evalf(512.5), weightf(512.5), -1., 1., 100, atol=1e-10)
571
+
572
+ # this is a special case that the old code supported.
573
+ # when alpha = 0, the gegenbauer polynomial is uniformly 0. but it goes
574
+ # to a scaled down copy of T_n(x) there.
575
+ vgq(rootf(0), sc.eval_chebyt, weightf(0), -1., 1., 5)
576
+ vgq(rootf(0), sc.eval_chebyt, weightf(0), -1., 1., 25)
577
+ vgq(rootf(0), sc.eval_chebyt, weightf(0), -1., 1., 100, atol=1e-12)
578
+
579
+ x, w = sc.roots_gegenbauer(5, 2, False)
580
+ y, v, m = sc.roots_gegenbauer(5, 2, True)
581
+ assert_allclose(x, y, 1e-14, 1e-14)
582
+ assert_allclose(w, v, 1e-14, 1e-14)
583
+
584
+ muI, muI_err = integrate.quad(weightf(2), -1, 1)
585
+ assert_allclose(m, muI, rtol=muI_err)
586
+
587
+ assert_raises(ValueError, sc.roots_gegenbauer, 0, 2)
588
+ assert_raises(ValueError, sc.roots_gegenbauer, 3.3, 2)
589
+ assert_raises(ValueError, sc.roots_gegenbauer, 3, -.75)
590
+
591
+ def test_roots_chebyt():
592
+ weightf = orth.chebyt(5).weight_func
593
+ verify_gauss_quad(sc.roots_chebyt, sc.eval_chebyt, weightf, -1., 1., 5)
594
+ verify_gauss_quad(sc.roots_chebyt, sc.eval_chebyt, weightf, -1., 1., 25)
595
+ verify_gauss_quad(sc.roots_chebyt, sc.eval_chebyt, weightf, -1., 1., 100,
596
+ atol=1e-12)
597
+
598
+ x, w = sc.roots_chebyt(5, False)
599
+ y, v, m = sc.roots_chebyt(5, True)
600
+ assert_allclose(x, y, 1e-14, 1e-14)
601
+ assert_allclose(w, v, 1e-14, 1e-14)
602
+
603
+ muI, muI_err = integrate.quad(weightf, -1, 1)
604
+ assert_allclose(m, muI, rtol=muI_err)
605
+
606
+ assert_raises(ValueError, sc.roots_chebyt, 0)
607
+ assert_raises(ValueError, sc.roots_chebyt, 3.3)
608
+
609
+ def test_chebyt_symmetry():
610
+ x, w = sc.roots_chebyt(21)
611
+ pos, neg = x[:10], x[11:]
612
+ assert_equal(neg, -pos[::-1])
613
+ assert_equal(x[10], 0)
614
+
615
+ def test_roots_chebyu():
616
+ weightf = orth.chebyu(5).weight_func
617
+ verify_gauss_quad(sc.roots_chebyu, sc.eval_chebyu, weightf, -1., 1., 5)
618
+ verify_gauss_quad(sc.roots_chebyu, sc.eval_chebyu, weightf, -1., 1., 25)
619
+ verify_gauss_quad(sc.roots_chebyu, sc.eval_chebyu, weightf, -1., 1., 100)
620
+
621
+ x, w = sc.roots_chebyu(5, False)
622
+ y, v, m = sc.roots_chebyu(5, True)
623
+ assert_allclose(x, y, 1e-14, 1e-14)
624
+ assert_allclose(w, v, 1e-14, 1e-14)
625
+
626
+ muI, muI_err = integrate.quad(weightf, -1, 1)
627
+ assert_allclose(m, muI, rtol=muI_err)
628
+
629
+ assert_raises(ValueError, sc.roots_chebyu, 0)
630
+ assert_raises(ValueError, sc.roots_chebyu, 3.3)
631
+
632
+ def test_roots_chebyc():
633
+ weightf = orth.chebyc(5).weight_func
634
+ verify_gauss_quad(sc.roots_chebyc, sc.eval_chebyc, weightf, -2., 2., 5)
635
+ verify_gauss_quad(sc.roots_chebyc, sc.eval_chebyc, weightf, -2., 2., 25)
636
+ verify_gauss_quad(sc.roots_chebyc, sc.eval_chebyc, weightf, -2., 2., 100,
637
+ atol=1e-12)
638
+
639
+ x, w = sc.roots_chebyc(5, False)
640
+ y, v, m = sc.roots_chebyc(5, True)
641
+ assert_allclose(x, y, 1e-14, 1e-14)
642
+ assert_allclose(w, v, 1e-14, 1e-14)
643
+
644
+ muI, muI_err = integrate.quad(weightf, -2, 2)
645
+ assert_allclose(m, muI, rtol=muI_err)
646
+
647
+ assert_raises(ValueError, sc.roots_chebyc, 0)
648
+ assert_raises(ValueError, sc.roots_chebyc, 3.3)
649
+
650
+ def test_roots_chebys():
651
+ weightf = orth.chebys(5).weight_func
652
+ verify_gauss_quad(sc.roots_chebys, sc.eval_chebys, weightf, -2., 2., 5)
653
+ verify_gauss_quad(sc.roots_chebys, sc.eval_chebys, weightf, -2., 2., 25)
654
+ verify_gauss_quad(sc.roots_chebys, sc.eval_chebys, weightf, -2., 2., 100)
655
+
656
+ x, w = sc.roots_chebys(5, False)
657
+ y, v, m = sc.roots_chebys(5, True)
658
+ assert_allclose(x, y, 1e-14, 1e-14)
659
+ assert_allclose(w, v, 1e-14, 1e-14)
660
+
661
+ muI, muI_err = integrate.quad(weightf, -2, 2)
662
+ assert_allclose(m, muI, rtol=muI_err)
663
+
664
+ assert_raises(ValueError, sc.roots_chebys, 0)
665
+ assert_raises(ValueError, sc.roots_chebys, 3.3)
666
+
667
+ def test_roots_sh_chebyt():
668
+ weightf = orth.sh_chebyt(5).weight_func
669
+ verify_gauss_quad(sc.roots_sh_chebyt, sc.eval_sh_chebyt, weightf, 0., 1., 5)
670
+ verify_gauss_quad(sc.roots_sh_chebyt, sc.eval_sh_chebyt, weightf, 0., 1., 25)
671
+ verify_gauss_quad(sc.roots_sh_chebyt, sc.eval_sh_chebyt, weightf, 0., 1.,
672
+ 100, atol=1e-13)
673
+
674
+ x, w = sc.roots_sh_chebyt(5, False)
675
+ y, v, m = sc.roots_sh_chebyt(5, True)
676
+ assert_allclose(x, y, 1e-14, 1e-14)
677
+ assert_allclose(w, v, 1e-14, 1e-14)
678
+
679
+ muI, muI_err = integrate.quad(weightf, 0, 1)
680
+ assert_allclose(m, muI, rtol=muI_err)
681
+
682
+ assert_raises(ValueError, sc.roots_sh_chebyt, 0)
683
+ assert_raises(ValueError, sc.roots_sh_chebyt, 3.3)
684
+
685
+ def test_roots_sh_chebyu():
686
+ weightf = orth.sh_chebyu(5).weight_func
687
+ verify_gauss_quad(sc.roots_sh_chebyu, sc.eval_sh_chebyu, weightf, 0., 1., 5)
688
+ verify_gauss_quad(sc.roots_sh_chebyu, sc.eval_sh_chebyu, weightf, 0., 1., 25)
689
+ verify_gauss_quad(sc.roots_sh_chebyu, sc.eval_sh_chebyu, weightf, 0., 1.,
690
+ 100, atol=1e-13)
691
+
692
+ x, w = sc.roots_sh_chebyu(5, False)
693
+ y, v, m = sc.roots_sh_chebyu(5, True)
694
+ assert_allclose(x, y, 1e-14, 1e-14)
695
+ assert_allclose(w, v, 1e-14, 1e-14)
696
+
697
+ muI, muI_err = integrate.quad(weightf, 0, 1)
698
+ assert_allclose(m, muI, rtol=muI_err)
699
+
700
+ assert_raises(ValueError, sc.roots_sh_chebyu, 0)
701
+ assert_raises(ValueError, sc.roots_sh_chebyu, 3.3)
702
+
703
+ def test_roots_legendre():
704
+ weightf = orth.legendre(5).weight_func
705
+ verify_gauss_quad(sc.roots_legendre, sc.eval_legendre, weightf, -1., 1., 5)
706
+ verify_gauss_quad(sc.roots_legendre, sc.eval_legendre, weightf, -1., 1.,
707
+ 25, atol=1e-13)
708
+ verify_gauss_quad(sc.roots_legendre, sc.eval_legendre, weightf, -1., 1.,
709
+ 100, atol=1e-12)
710
+
711
+ x, w = sc.roots_legendre(5, False)
712
+ y, v, m = sc.roots_legendre(5, True)
713
+ assert_allclose(x, y, 1e-14, 1e-14)
714
+ assert_allclose(w, v, 1e-14, 1e-14)
715
+
716
+ muI, muI_err = integrate.quad(weightf, -1, 1)
717
+ assert_allclose(m, muI, rtol=muI_err)
718
+
719
+ assert_raises(ValueError, sc.roots_legendre, 0)
720
+ assert_raises(ValueError, sc.roots_legendre, 3.3)
721
+
722
+ def test_roots_sh_legendre():
723
+ weightf = orth.sh_legendre(5).weight_func
724
+ verify_gauss_quad(sc.roots_sh_legendre, sc.eval_sh_legendre, weightf, 0., 1., 5)
725
+ verify_gauss_quad(sc.roots_sh_legendre, sc.eval_sh_legendre, weightf, 0., 1.,
726
+ 25, atol=1e-13)
727
+ verify_gauss_quad(sc.roots_sh_legendre, sc.eval_sh_legendre, weightf, 0., 1.,
728
+ 100, atol=1e-12)
729
+
730
+ x, w = sc.roots_sh_legendre(5, False)
731
+ y, v, m = sc.roots_sh_legendre(5, True)
732
+ assert_allclose(x, y, 1e-14, 1e-14)
733
+ assert_allclose(w, v, 1e-14, 1e-14)
734
+
735
+ muI, muI_err = integrate.quad(weightf, 0, 1)
736
+ assert_allclose(m, muI, rtol=muI_err)
737
+
738
+ assert_raises(ValueError, sc.roots_sh_legendre, 0)
739
+ assert_raises(ValueError, sc.roots_sh_legendre, 3.3)
740
+
741
+ def test_roots_laguerre():
742
+ weightf = orth.laguerre(5).weight_func
743
+ verify_gauss_quad(sc.roots_laguerre, sc.eval_laguerre, weightf, 0., np.inf, 5)
744
+ verify_gauss_quad(sc.roots_laguerre, sc.eval_laguerre, weightf, 0., np.inf,
745
+ 25, atol=1e-13)
746
+ verify_gauss_quad(sc.roots_laguerre, sc.eval_laguerre, weightf, 0., np.inf,
747
+ 100, atol=1e-12)
748
+
749
+ x, w = sc.roots_laguerre(5, False)
750
+ y, v, m = sc.roots_laguerre(5, True)
751
+ assert_allclose(x, y, 1e-14, 1e-14)
752
+ assert_allclose(w, v, 1e-14, 1e-14)
753
+
754
+ muI, muI_err = integrate.quad(weightf, 0, np.inf)
755
+ assert_allclose(m, muI, rtol=muI_err)
756
+
757
+ assert_raises(ValueError, sc.roots_laguerre, 0)
758
+ assert_raises(ValueError, sc.roots_laguerre, 3.3)
759
+
760
+ def test_roots_genlaguerre():
761
+ def rootf(a):
762
+ return lambda n, mu: sc.roots_genlaguerre(n, a, mu)
763
+ def evalf(a):
764
+ return lambda n, x: sc.eval_genlaguerre(n, a, x)
765
+ def weightf(a):
766
+ return lambda x: x ** a * np.exp(-x)
767
+
768
+ vgq = verify_gauss_quad
769
+ vgq(rootf(-0.5), evalf(-0.5), weightf(-0.5), 0., np.inf, 5)
770
+ vgq(rootf(-0.5), evalf(-0.5), weightf(-0.5), 0., np.inf, 25, atol=1e-13)
771
+ vgq(rootf(-0.5), evalf(-0.5), weightf(-0.5), 0., np.inf, 100, atol=1e-12)
772
+
773
+ vgq(rootf(0.1), evalf(0.1), weightf(0.1), 0., np.inf, 5)
774
+ vgq(rootf(0.1), evalf(0.1), weightf(0.1), 0., np.inf, 25, atol=1e-13)
775
+ vgq(rootf(0.1), evalf(0.1), weightf(0.1), 0., np.inf, 100, atol=1.6e-13)
776
+
777
+ vgq(rootf(1), evalf(1), weightf(1), 0., np.inf, 5)
778
+ vgq(rootf(1), evalf(1), weightf(1), 0., np.inf, 25, atol=1e-13)
779
+ vgq(rootf(1), evalf(1), weightf(1), 0., np.inf, 100, atol=1.03e-13)
780
+
781
+ vgq(rootf(10), evalf(10), weightf(10), 0., np.inf, 5)
782
+ vgq(rootf(10), evalf(10), weightf(10), 0., np.inf, 25, atol=1e-13)
783
+ vgq(rootf(10), evalf(10), weightf(10), 0., np.inf, 100, atol=1e-12)
784
+
785
+ vgq(rootf(50), evalf(50), weightf(50), 0., np.inf, 5)
786
+ vgq(rootf(50), evalf(50), weightf(50), 0., np.inf, 25, atol=1e-13)
787
+ vgq(rootf(50), evalf(50), weightf(50), 0., np.inf, 100, rtol=1e-14, atol=2e-13)
788
+
789
+ x, w = sc.roots_genlaguerre(5, 2, False)
790
+ y, v, m = sc.roots_genlaguerre(5, 2, True)
791
+ assert_allclose(x, y, 1e-14, 1e-14)
792
+ assert_allclose(w, v, 1e-14, 1e-14)
793
+
794
+ muI, muI_err = integrate.quad(weightf(2.), 0., np.inf)
795
+ assert_allclose(m, muI, rtol=muI_err)
796
+
797
+ assert_raises(ValueError, sc.roots_genlaguerre, 0, 2)
798
+ assert_raises(ValueError, sc.roots_genlaguerre, 3.3, 2)
799
+ assert_raises(ValueError, sc.roots_genlaguerre, 3, -1.1)
800
+
801
+
802
+ def test_gh_6721():
803
+ # Regression test for gh_6721. This should not raise.
804
+ sc.chebyt(65)(0.2)
.venv/Lib/site-packages/scipy/special/tests/test_orthogonal_eval.py ADDED
@@ -0,0 +1,272 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from numpy.testing import assert_, assert_allclose
3
+ import pytest
4
+
5
+ from scipy.special import _ufuncs
6
+ import scipy.special._orthogonal as orth
7
+ from scipy.special._testutils import FuncData
8
+
9
+
10
+ def test_eval_chebyt():
11
+ n = np.arange(0, 10000, 7, dtype=np.dtype("long"))
12
+ x = 2*np.random.rand() - 1
13
+ v1 = np.cos(n*np.arccos(x))
14
+ v2 = _ufuncs.eval_chebyt(n, x)
15
+ assert_(np.allclose(v1, v2, rtol=1e-15))
16
+
17
+
18
+ def test_eval_chebyt_gh20129():
19
+ # https://github.com/scipy/scipy/issues/20129
20
+ assert _ufuncs.eval_chebyt(7, 2 + 0j) == 5042.0
21
+
22
+ def test_eval_genlaguerre_restriction():
23
+ # check it returns nan for alpha <= -1
24
+ assert_(np.isnan(_ufuncs.eval_genlaguerre(0, -1, 0)))
25
+ assert_(np.isnan(_ufuncs.eval_genlaguerre(0.1, -1, 0)))
26
+
27
+
28
+ def test_warnings():
29
+ # ticket 1334
30
+ with np.errstate(all='raise'):
31
+ # these should raise no fp warnings
32
+ _ufuncs.eval_legendre(1, 0)
33
+ _ufuncs.eval_laguerre(1, 1)
34
+ _ufuncs.eval_gegenbauer(1, 1, 0)
35
+
36
+
37
+ class TestPolys:
38
+ """
39
+ Check that the eval_* functions agree with the constructed polynomials
40
+
41
+ """
42
+
43
+ def check_poly(self, func, cls, param_ranges=[], x_range=[], nn=10,
44
+ nparam=10, nx=10, rtol=1e-8):
45
+ np.random.seed(1234)
46
+
47
+ dataset = []
48
+ for n in np.arange(nn):
49
+ params = [a + (b-a)*np.random.rand(nparam) for a,b in param_ranges]
50
+ params = np.asarray(params).T
51
+ if not param_ranges:
52
+ params = [0]
53
+ for p in params:
54
+ if param_ranges:
55
+ p = (n,) + tuple(p)
56
+ else:
57
+ p = (n,)
58
+ x = x_range[0] + (x_range[1] - x_range[0])*np.random.rand(nx)
59
+ x[0] = x_range[0] # always include domain start point
60
+ x[1] = x_range[1] # always include domain end point
61
+ poly = np.poly1d(cls(*p).coef)
62
+ z = np.c_[np.tile(p, (nx,1)), x, poly(x)]
63
+ dataset.append(z)
64
+
65
+ dataset = np.concatenate(dataset, axis=0)
66
+
67
+ def polyfunc(*p):
68
+ p = (p[0].astype(np.dtype("long")),) + p[1:]
69
+ return func(*p)
70
+
71
+ with np.errstate(all='raise'):
72
+ ds = FuncData(polyfunc, dataset, list(range(len(param_ranges)+2)), -1,
73
+ rtol=rtol)
74
+ ds.check()
75
+
76
+ def test_jacobi(self):
77
+ self.check_poly(_ufuncs.eval_jacobi, orth.jacobi,
78
+ param_ranges=[(-0.99, 10), (-0.99, 10)],
79
+ x_range=[-1, 1], rtol=1e-5)
80
+
81
+ def test_sh_jacobi(self):
82
+ self.check_poly(_ufuncs.eval_sh_jacobi, orth.sh_jacobi,
83
+ param_ranges=[(1, 10), (0, 1)], x_range=[0, 1],
84
+ rtol=1e-5)
85
+
86
+ def test_gegenbauer(self):
87
+ self.check_poly(_ufuncs.eval_gegenbauer, orth.gegenbauer,
88
+ param_ranges=[(-0.499, 10)], x_range=[-1, 1],
89
+ rtol=1e-7)
90
+
91
+ def test_chebyt(self):
92
+ self.check_poly(_ufuncs.eval_chebyt, orth.chebyt,
93
+ param_ranges=[], x_range=[-1, 1])
94
+
95
+ def test_chebyu(self):
96
+ self.check_poly(_ufuncs.eval_chebyu, orth.chebyu,
97
+ param_ranges=[], x_range=[-1, 1])
98
+
99
+ def test_chebys(self):
100
+ self.check_poly(_ufuncs.eval_chebys, orth.chebys,
101
+ param_ranges=[], x_range=[-2, 2])
102
+
103
+ def test_chebyc(self):
104
+ self.check_poly(_ufuncs.eval_chebyc, orth.chebyc,
105
+ param_ranges=[], x_range=[-2, 2])
106
+
107
+ def test_sh_chebyt(self):
108
+ with np.errstate(all='ignore'):
109
+ self.check_poly(_ufuncs.eval_sh_chebyt, orth.sh_chebyt,
110
+ param_ranges=[], x_range=[0, 1])
111
+
112
+ def test_sh_chebyu(self):
113
+ self.check_poly(_ufuncs.eval_sh_chebyu, orth.sh_chebyu,
114
+ param_ranges=[], x_range=[0, 1])
115
+
116
+ def test_legendre(self):
117
+ self.check_poly(_ufuncs.eval_legendre, orth.legendre,
118
+ param_ranges=[], x_range=[-1, 1])
119
+
120
+ def test_sh_legendre(self):
121
+ with np.errstate(all='ignore'):
122
+ self.check_poly(_ufuncs.eval_sh_legendre, orth.sh_legendre,
123
+ param_ranges=[], x_range=[0, 1])
124
+
125
+ def test_genlaguerre(self):
126
+ self.check_poly(_ufuncs.eval_genlaguerre, orth.genlaguerre,
127
+ param_ranges=[(-0.99, 10)], x_range=[0, 100])
128
+
129
+ def test_laguerre(self):
130
+ self.check_poly(_ufuncs.eval_laguerre, orth.laguerre,
131
+ param_ranges=[], x_range=[0, 100])
132
+
133
+ def test_hermite(self):
134
+ self.check_poly(_ufuncs.eval_hermite, orth.hermite,
135
+ param_ranges=[], x_range=[-100, 100])
136
+
137
+ def test_hermitenorm(self):
138
+ self.check_poly(_ufuncs.eval_hermitenorm, orth.hermitenorm,
139
+ param_ranges=[], x_range=[-100, 100])
140
+
141
+
142
+ class TestRecurrence:
143
+ """
144
+ Check that the eval_* functions sig='ld->d' and 'dd->d' agree.
145
+
146
+ """
147
+
148
+ def check_poly(self, func, param_ranges=[], x_range=[], nn=10,
149
+ nparam=10, nx=10, rtol=1e-8):
150
+ np.random.seed(1234)
151
+
152
+ dataset = []
153
+ for n in np.arange(nn):
154
+ params = [a + (b-a)*np.random.rand(nparam) for a,b in param_ranges]
155
+ params = np.asarray(params).T
156
+ if not param_ranges:
157
+ params = [0]
158
+ for p in params:
159
+ if param_ranges:
160
+ p = (n,) + tuple(p)
161
+ else:
162
+ p = (n,)
163
+ x = x_range[0] + (x_range[1] - x_range[0])*np.random.rand(nx)
164
+ x[0] = x_range[0] # always include domain start point
165
+ x[1] = x_range[1] # always include domain end point
166
+ kw = dict(sig=(len(p)+1)*'d'+'->d')
167
+ z = np.c_[np.tile(p, (nx,1)), x, func(*(p + (x,)), **kw)]
168
+ dataset.append(z)
169
+
170
+ dataset = np.concatenate(dataset, axis=0)
171
+
172
+ def polyfunc(*p):
173
+ p = (p[0].astype(int),) + p[1:]
174
+ kw = dict(sig='l'+(len(p)-1)*'d'+'->d')
175
+ return func(*p, **kw)
176
+
177
+ with np.errstate(all='raise'):
178
+ ds = FuncData(polyfunc, dataset, list(range(len(param_ranges)+2)), -1,
179
+ rtol=rtol)
180
+ ds.check()
181
+
182
+ def test_jacobi(self):
183
+ self.check_poly(_ufuncs.eval_jacobi,
184
+ param_ranges=[(-0.99, 10), (-0.99, 10)],
185
+ x_range=[-1, 1])
186
+
187
+ def test_sh_jacobi(self):
188
+ self.check_poly(_ufuncs.eval_sh_jacobi,
189
+ param_ranges=[(1, 10), (0, 1)], x_range=[0, 1])
190
+
191
+ def test_gegenbauer(self):
192
+ self.check_poly(_ufuncs.eval_gegenbauer,
193
+ param_ranges=[(-0.499, 10)], x_range=[-1, 1])
194
+
195
+ def test_chebyt(self):
196
+ self.check_poly(_ufuncs.eval_chebyt,
197
+ param_ranges=[], x_range=[-1, 1])
198
+
199
+ def test_chebyu(self):
200
+ self.check_poly(_ufuncs.eval_chebyu,
201
+ param_ranges=[], x_range=[-1, 1])
202
+
203
+ def test_chebys(self):
204
+ self.check_poly(_ufuncs.eval_chebys,
205
+ param_ranges=[], x_range=[-2, 2])
206
+
207
+ def test_chebyc(self):
208
+ self.check_poly(_ufuncs.eval_chebyc,
209
+ param_ranges=[], x_range=[-2, 2])
210
+
211
+ def test_sh_chebyt(self):
212
+ self.check_poly(_ufuncs.eval_sh_chebyt,
213
+ param_ranges=[], x_range=[0, 1])
214
+
215
+ def test_sh_chebyu(self):
216
+ self.check_poly(_ufuncs.eval_sh_chebyu,
217
+ param_ranges=[], x_range=[0, 1])
218
+
219
+ def test_legendre(self):
220
+ self.check_poly(_ufuncs.eval_legendre,
221
+ param_ranges=[], x_range=[-1, 1])
222
+
223
+ def test_sh_legendre(self):
224
+ self.check_poly(_ufuncs.eval_sh_legendre,
225
+ param_ranges=[], x_range=[0, 1])
226
+
227
+ def test_genlaguerre(self):
228
+ self.check_poly(_ufuncs.eval_genlaguerre,
229
+ param_ranges=[(-0.99, 10)], x_range=[0, 100])
230
+
231
+ def test_laguerre(self):
232
+ self.check_poly(_ufuncs.eval_laguerre,
233
+ param_ranges=[], x_range=[0, 100])
234
+
235
+ def test_hermite(self):
236
+ v = _ufuncs.eval_hermite(70, 1.0)
237
+ a = -1.457076485701412e60
238
+ assert_allclose(v, a)
239
+
240
+
241
+ def test_hermite_domain():
242
+ # Regression test for gh-11091.
243
+ assert np.isnan(_ufuncs.eval_hermite(-1, 1.0))
244
+ assert np.isnan(_ufuncs.eval_hermitenorm(-1, 1.0))
245
+
246
+
247
+ @pytest.mark.parametrize("n", [0, 1, 2])
248
+ @pytest.mark.parametrize("x", [0, 1, np.nan])
249
+ def test_hermite_nan(n, x):
250
+ # Regression test for gh-11369.
251
+ assert np.isnan(_ufuncs.eval_hermite(n, x)) == np.any(np.isnan([n, x]))
252
+ assert np.isnan(_ufuncs.eval_hermitenorm(n, x)) == np.any(np.isnan([n, x]))
253
+
254
+
255
+ @pytest.mark.parametrize('n', [0, 1, 2, 3.2])
256
+ @pytest.mark.parametrize('alpha', [1, np.nan])
257
+ @pytest.mark.parametrize('x', [2, np.nan])
258
+ def test_genlaguerre_nan(n, alpha, x):
259
+ # Regression test for gh-11361.
260
+ nan_laguerre = np.isnan(_ufuncs.eval_genlaguerre(n, alpha, x))
261
+ nan_arg = np.any(np.isnan([n, alpha, x]))
262
+ assert nan_laguerre == nan_arg
263
+
264
+
265
+ @pytest.mark.parametrize('n', [0, 1, 2, 3.2])
266
+ @pytest.mark.parametrize('alpha', [0.0, 1, np.nan])
267
+ @pytest.mark.parametrize('x', [1e-6, 2, np.nan])
268
+ def test_gegenbauer_nan(n, alpha, x):
269
+ # Regression test for gh-11370.
270
+ nan_gegenbauer = np.isnan(_ufuncs.eval_gegenbauer(n, alpha, x))
271
+ nan_arg = np.any(np.isnan([n, alpha, x]))
272
+ assert nan_gegenbauer == nan_arg
.venv/Lib/site-packages/scipy/special/tests/test_owens_t.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from numpy.testing import assert_equal, assert_allclose
3
+
4
+ import scipy.special as sc
5
+
6
+
7
+ def test_symmetries():
8
+ np.random.seed(1234)
9
+ a, h = np.random.rand(100), np.random.rand(100)
10
+ assert_equal(sc.owens_t(h, a), sc.owens_t(-h, a))
11
+ assert_equal(sc.owens_t(h, a), -sc.owens_t(h, -a))
12
+
13
+
14
+ def test_special_cases():
15
+ assert_equal(sc.owens_t(5, 0), 0)
16
+ assert_allclose(sc.owens_t(0, 5), 0.5*np.arctan(5)/np.pi,
17
+ rtol=5e-14)
18
+ # Target value is 0.5*Phi(5)*(1 - Phi(5)) for Phi the CDF of the
19
+ # standard normal distribution
20
+ assert_allclose(sc.owens_t(5, 1), 1.4332574485503512543e-07,
21
+ rtol=5e-14)
22
+
23
+
24
+ def test_nans():
25
+ assert_equal(sc.owens_t(20, np.nan), np.nan)
26
+ assert_equal(sc.owens_t(np.nan, 20), np.nan)
27
+ assert_equal(sc.owens_t(np.nan, np.nan), np.nan)
28
+
29
+
30
+ def test_infs():
31
+ h, a = 0, np.inf
32
+ # T(0, a) = 1/2π * arctan(a)
33
+ res = 1/(2*np.pi) * np.arctan(a)
34
+ assert_allclose(sc.owens_t(h, a), res, rtol=5e-14)
35
+ assert_allclose(sc.owens_t(h, -a), -res, rtol=5e-14)
36
+
37
+ h = 1
38
+ # Refer Owens T function definition in Wikipedia
39
+ # https://en.wikipedia.org/wiki/Owen%27s_T_function
40
+ # Value approximated through Numerical Integration
41
+ # using scipy.integrate.quad
42
+ # quad(lambda x: 1/(2*pi)*(exp(-0.5*(1*1)*(1+x*x))/(1+x*x)), 0, inf)
43
+ res = 0.07932762696572854
44
+ assert_allclose(sc.owens_t(h, np.inf), res, rtol=5e-14)
45
+ assert_allclose(sc.owens_t(h, -np.inf), -res, rtol=5e-14)
46
+
47
+ assert_equal(sc.owens_t(np.inf, 1), 0)
48
+ assert_equal(sc.owens_t(-np.inf, 1), 0)
49
+
50
+ assert_equal(sc.owens_t(np.inf, np.inf), 0)
51
+ assert_equal(sc.owens_t(-np.inf, np.inf), 0)
52
+ assert_equal(sc.owens_t(np.inf, -np.inf), -0.0)
53
+ assert_equal(sc.owens_t(-np.inf, -np.inf), -0.0)
.venv/Lib/site-packages/scipy/special/tests/test_pcf.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Tests for parabolic cylinder functions.
2
+
3
+ """
4
+ import numpy as np
5
+ from numpy.testing import assert_allclose, assert_equal
6
+ import scipy.special as sc
7
+
8
+
9
+ def test_pbwa_segfault():
10
+ # Regression test for https://github.com/scipy/scipy/issues/6208.
11
+ #
12
+ # Data generated by mpmath.
13
+ #
14
+ w = 1.02276567211316867161
15
+ wp = -0.48887053372346189882
16
+ assert_allclose(sc.pbwa(0, 0), (w, wp), rtol=1e-13, atol=0)
17
+
18
+
19
+ def test_pbwa_nan():
20
+ # Check that NaN's are returned outside of the range in which the
21
+ # implementation is accurate.
22
+ pts = [(-6, -6), (-6, 6), (6, -6), (6, 6)]
23
+ for p in pts:
24
+ assert_equal(sc.pbwa(*p), (np.nan, np.nan))
.venv/Lib/site-packages/scipy/special/tests/test_pdtr.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import scipy.special as sc
3
+ from numpy.testing import assert_almost_equal, assert_array_equal
4
+
5
+
6
+ class TestPdtr:
7
+ def test(self):
8
+ val = sc.pdtr(0, 1)
9
+ assert_almost_equal(val, np.exp(-1))
10
+
11
+ def test_m_zero(self):
12
+ val = sc.pdtr([0, 1, 2], 0)
13
+ assert_array_equal(val, [1, 1, 1])
14
+
15
+ def test_rounding(self):
16
+ double_val = sc.pdtr([0.1, 1.1, 2.1], 1.0)
17
+ int_val = sc.pdtr([0, 1, 2], 1.0)
18
+ assert_array_equal(double_val, int_val)
19
+
20
+ def test_inf(self):
21
+ val = sc.pdtr(np.inf, 1.0)
22
+ assert_almost_equal(val, 1.0)
23
+
24
+ def test_domain(self):
25
+ val = sc.pdtr(-1.1, 1.0)
26
+ assert np.isnan(val)
27
+
28
+ class TestPdtrc:
29
+ def test_value(self):
30
+ val = sc.pdtrc(0, 1)
31
+ assert_almost_equal(val, 1 - np.exp(-1))
32
+
33
+ def test_m_zero(self):
34
+ val = sc.pdtrc([0, 1, 2], 0.0)
35
+ assert_array_equal(val, [0, 0, 0])
36
+
37
+ def test_rounding(self):
38
+ double_val = sc.pdtrc([0.1, 1.1, 2.1], 1.0)
39
+ int_val = sc.pdtrc([0, 1, 2], 1.0)
40
+ assert_array_equal(double_val, int_val)
41
+
42
+ def test_inf(self):
43
+ val = sc.pdtrc(np.inf, 1.0)
44
+ assert_almost_equal(val, 0.0)
45
+
46
+ def test_domain(self):
47
+ val = sc.pdtrc(-1.1, 1.0)
48
+ assert np.isnan(val)
.venv/Lib/site-packages/scipy/special/tests/test_powm1.py ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pytest
2
+ import numpy as np
3
+ from numpy.testing import assert_allclose
4
+ from scipy.special import powm1
5
+
6
+
7
+ # Expected values were computed with mpmath, e.g.
8
+ #
9
+ # >>> import mpmath
10
+ # >>> mpmath.np.dps = 200
11
+ # >>> print(float(mpmath.powm1(2.0, 1e-7))
12
+ # 6.931472045825965e-08
13
+ #
14
+ powm1_test_cases = [
15
+ (1.25, 0.75, 0.18217701125396976, 1e-15),
16
+ (2.0, 1e-7, 6.931472045825965e-08, 1e-15),
17
+ (25.0, 5e-11, 1.6094379125636148e-10, 1e-15),
18
+ (0.99996, 0.75, -3.0000150002530058e-05, 1e-15),
19
+ (0.9999999999990905, 20, -1.81898940353014e-11, 1e-15),
20
+ (-1.25, 751.0, -6.017550852453444e+72, 2e-15)
21
+ ]
22
+
23
+
24
+ @pytest.mark.parametrize('x, y, expected, rtol', powm1_test_cases)
25
+ def test_powm1(x, y, expected, rtol):
26
+ p = powm1(x, y)
27
+ assert_allclose(p, expected, rtol=rtol)
28
+
29
+
30
+ @pytest.mark.parametrize('x, y, expected',
31
+ [(0.0, 0.0, 0.0),
32
+ (0.0, -1.5, np.inf),
33
+ (0.0, 1.75, -1.0),
34
+ (-1.5, 2.0, 1.25),
35
+ (-1.5, 3.0, -4.375),
36
+ (np.nan, 0.0, 0.0),
37
+ (1.0, np.nan, 0.0),
38
+ (1.0, np.inf, 0.0),
39
+ (1.0, -np.inf, 0.0),
40
+ (np.inf, 7.5, np.inf),
41
+ (np.inf, -7.5, -1.0),
42
+ (3.25, np.inf, np.inf),
43
+ (np.inf, np.inf, np.inf),
44
+ (np.inf, -np.inf, -1.0),
45
+ (np.inf, 0.0, 0.0),
46
+ (-np.inf, 0.0, 0.0),
47
+ (-np.inf, 2.0, np.inf),
48
+ (-np.inf, 3.0, -np.inf),
49
+ (-1.0, float(2**53 - 1), -2.0)])
50
+ def test_powm1_exact_cases(x, y, expected):
51
+ # Test cases where we have an exact expected value.
52
+ p = powm1(x, y)
53
+ assert p == expected
54
+
55
+
56
+ @pytest.mark.parametrize('x, y',
57
+ [(-1.25, 751.03),
58
+ (-1.25, np.inf),
59
+ (np.nan, np.nan),
60
+ (-np.inf, -np.inf),
61
+ (-np.inf, 2.5)])
62
+ def test_powm1_return_nan(x, y):
63
+ # Test cases where the expected return value is nan.
64
+ p = powm1(x, y)
65
+ assert np.isnan(p)
.venv/Lib/site-packages/scipy/special/tests/test_precompute_expn_asy.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from numpy.testing import assert_equal
2
+
3
+ from scipy.special._testutils import check_version, MissingModule
4
+ from scipy.special._precompute.expn_asy import generate_A
5
+
6
+ try:
7
+ import sympy
8
+ from sympy import Poly
9
+ except ImportError:
10
+ sympy = MissingModule("sympy")
11
+
12
+
13
+ @check_version(sympy, "1.0")
14
+ def test_generate_A():
15
+ # Data from DLMF 8.20.5
16
+ x = sympy.symbols('x')
17
+ Astd = [Poly(1, x),
18
+ Poly(1, x),
19
+ Poly(1 - 2*x),
20
+ Poly(1 - 8*x + 6*x**2)]
21
+ Ares = generate_A(len(Astd))
22
+
23
+ for p, q in zip(Astd, Ares):
24
+ assert_equal(p, q)
.venv/Lib/site-packages/scipy/special/tests/test_precompute_gammainc.py ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pytest
2
+
3
+ from scipy.special._testutils import MissingModule, check_version
4
+ from scipy.special._mptestutils import (
5
+ Arg, IntArg, mp_assert_allclose, assert_mpmath_equal)
6
+ from scipy.special._precompute.gammainc_asy import (
7
+ compute_g, compute_alpha, compute_d)
8
+ from scipy.special._precompute.gammainc_data import gammainc, gammaincc
9
+
10
+ try:
11
+ import sympy
12
+ except ImportError:
13
+ sympy = MissingModule('sympy')
14
+
15
+ try:
16
+ import mpmath as mp
17
+ except ImportError:
18
+ mp = MissingModule('mpmath')
19
+
20
+
21
+ @check_version(mp, '0.19')
22
+ def test_g():
23
+ # Test data for the g_k. See DLMF 5.11.4.
24
+ with mp.workdps(30):
25
+ g = [mp.mpf(1), mp.mpf(1)/12, mp.mpf(1)/288,
26
+ -mp.mpf(139)/51840, -mp.mpf(571)/2488320,
27
+ mp.mpf(163879)/209018880, mp.mpf(5246819)/75246796800]
28
+ mp_assert_allclose(compute_g(7), g)
29
+
30
+
31
+ @pytest.mark.slow
32
+ @check_version(mp, '0.19')
33
+ @check_version(sympy, '0.7')
34
+ @pytest.mark.xfail_on_32bit("rtol only 2e-11, see gh-6938")
35
+ def test_alpha():
36
+ # Test data for the alpha_k. See DLMF 8.12.14.
37
+ with mp.workdps(30):
38
+ alpha = [mp.mpf(0), mp.mpf(1), mp.mpf(1)/3, mp.mpf(1)/36,
39
+ -mp.mpf(1)/270, mp.mpf(1)/4320, mp.mpf(1)/17010,
40
+ -mp.mpf(139)/5443200, mp.mpf(1)/204120]
41
+ mp_assert_allclose(compute_alpha(9), alpha)
42
+
43
+
44
+ @pytest.mark.xslow
45
+ @check_version(mp, '0.19')
46
+ @check_version(sympy, '0.7')
47
+ def test_d():
48
+ # Compare the d_{k, n} to the results in appendix F of [1].
49
+ #
50
+ # Sources
51
+ # -------
52
+ # [1] DiDonato and Morris, Computation of the Incomplete Gamma
53
+ # Function Ratios and their Inverse, ACM Transactions on
54
+ # Mathematical Software, 1986.
55
+
56
+ with mp.workdps(50):
57
+ dataset = [(0, 0, -mp.mpf('0.333333333333333333333333333333')),
58
+ (0, 12, mp.mpf('0.102618097842403080425739573227e-7')),
59
+ (1, 0, -mp.mpf('0.185185185185185185185185185185e-2')),
60
+ (1, 12, mp.mpf('0.119516285997781473243076536700e-7')),
61
+ (2, 0, mp.mpf('0.413359788359788359788359788360e-2')),
62
+ (2, 12, -mp.mpf('0.140925299108675210532930244154e-7')),
63
+ (3, 0, mp.mpf('0.649434156378600823045267489712e-3')),
64
+ (3, 12, -mp.mpf('0.191111684859736540606728140873e-7')),
65
+ (4, 0, -mp.mpf('0.861888290916711698604702719929e-3')),
66
+ (4, 12, mp.mpf('0.288658297427087836297341274604e-7')),
67
+ (5, 0, -mp.mpf('0.336798553366358150308767592718e-3')),
68
+ (5, 12, mp.mpf('0.482409670378941807563762631739e-7')),
69
+ (6, 0, mp.mpf('0.531307936463992223165748542978e-3')),
70
+ (6, 12, -mp.mpf('0.882860074633048352505085243179e-7')),
71
+ (7, 0, mp.mpf('0.344367606892377671254279625109e-3')),
72
+ (7, 12, -mp.mpf('0.175629733590604619378669693914e-6')),
73
+ (8, 0, -mp.mpf('0.652623918595309418922034919727e-3')),
74
+ (8, 12, mp.mpf('0.377358774161109793380344937299e-6')),
75
+ (9, 0, -mp.mpf('0.596761290192746250124390067179e-3')),
76
+ (9, 12, mp.mpf('0.870823417786464116761231237189e-6'))]
77
+ d = compute_d(10, 13)
78
+ res = [d[k][n] for k, n, std in dataset]
79
+ std = [x[2] for x in dataset]
80
+ mp_assert_allclose(res, std)
81
+
82
+
83
+ @check_version(mp, '0.19')
84
+ def test_gammainc():
85
+ # Quick check that the gammainc in
86
+ # special._precompute.gammainc_data agrees with mpmath's
87
+ # gammainc.
88
+ assert_mpmath_equal(gammainc,
89
+ lambda a, x: mp.gammainc(a, b=x, regularized=True),
90
+ [Arg(0, 100, inclusive_a=False), Arg(0, 100)],
91
+ nan_ok=False, rtol=1e-17, n=50, dps=50)
92
+
93
+
94
+ @pytest.mark.xslow
95
+ @check_version(mp, '0.19')
96
+ def test_gammaincc():
97
+ # Check that the gammaincc in special._precompute.gammainc_data
98
+ # agrees with mpmath's gammainc.
99
+ assert_mpmath_equal(lambda a, x: gammaincc(a, x, dps=1000),
100
+ lambda a, x: mp.gammainc(a, a=x, regularized=True),
101
+ [Arg(20, 100), Arg(20, 100)],
102
+ nan_ok=False, rtol=1e-17, n=50, dps=1000)
103
+
104
+ # Test the fast integer path
105
+ assert_mpmath_equal(gammaincc,
106
+ lambda a, x: mp.gammainc(a, a=x, regularized=True),
107
+ [IntArg(1, 100), Arg(0, 100)],
108
+ nan_ok=False, rtol=1e-17, n=50, dps=50)
.venv/Lib/site-packages/scipy/special/tests/test_precompute_utils.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pytest
2
+
3
+ from scipy.special._testutils import MissingModule, check_version
4
+ from scipy.special._mptestutils import mp_assert_allclose
5
+ from scipy.special._precompute.utils import lagrange_inversion
6
+
7
+ try:
8
+ import sympy
9
+ except ImportError:
10
+ sympy = MissingModule('sympy')
11
+
12
+ try:
13
+ import mpmath as mp
14
+ except ImportError:
15
+ mp = MissingModule('mpmath')
16
+
17
+
18
+ @pytest.mark.slow
19
+ @check_version(sympy, '0.7')
20
+ @check_version(mp, '0.19')
21
+ class TestInversion:
22
+ @pytest.mark.xfail_on_32bit("rtol only 2e-9, see gh-6938")
23
+ def test_log(self):
24
+ with mp.workdps(30):
25
+ logcoeffs = mp.taylor(lambda x: mp.log(1 + x), 0, 10)
26
+ expcoeffs = mp.taylor(lambda x: mp.exp(x) - 1, 0, 10)
27
+ invlogcoeffs = lagrange_inversion(logcoeffs)
28
+ mp_assert_allclose(invlogcoeffs, expcoeffs)
29
+
30
+ @pytest.mark.xfail_on_32bit("rtol only 1e-15, see gh-6938")
31
+ def test_sin(self):
32
+ with mp.workdps(30):
33
+ sincoeffs = mp.taylor(mp.sin, 0, 10)
34
+ asincoeffs = mp.taylor(mp.asin, 0, 10)
35
+ invsincoeffs = lagrange_inversion(sincoeffs)
36
+ mp_assert_allclose(invsincoeffs, asincoeffs, atol=1e-30)
.venv/Lib/site-packages/scipy/special/tests/test_round.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import pytest
3
+
4
+ from scipy.special import _test_internal
5
+
6
+
7
+ @pytest.mark.skipif(not _test_internal.have_fenv(), reason="no fenv()")
8
+ def test_add_round_up():
9
+ np.random.seed(1234)
10
+ _test_internal.test_add_round(10**5, 'up')
11
+
12
+
13
+ @pytest.mark.skipif(not _test_internal.have_fenv(), reason="no fenv()")
14
+ def test_add_round_down():
15
+ np.random.seed(1234)
16
+ _test_internal.test_add_round(10**5, 'down')
.venv/Lib/site-packages/scipy/special/tests/test_sf_error.py ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ import warnings
3
+
4
+ import numpy as np
5
+ from numpy.testing import assert_, assert_equal, IS_PYPY
6
+ import pytest
7
+ from pytest import raises as assert_raises
8
+
9
+ import scipy.special as sc
10
+ from scipy.special._ufuncs import _sf_error_test_function
11
+
12
+ _sf_error_code_map = {
13
+ # skip 'ok'
14
+ 'singular': 1,
15
+ 'underflow': 2,
16
+ 'overflow': 3,
17
+ 'slow': 4,
18
+ 'loss': 5,
19
+ 'no_result': 6,
20
+ 'domain': 7,
21
+ 'arg': 8,
22
+ 'other': 9
23
+ }
24
+
25
+ _sf_error_actions = [
26
+ 'ignore',
27
+ 'warn',
28
+ 'raise'
29
+ ]
30
+
31
+
32
+ def _check_action(fun, args, action):
33
+ # TODO: special expert should correct
34
+ # the coercion at the true location?
35
+ args = np.asarray(args, dtype=np.dtype("long"))
36
+ if action == 'warn':
37
+ with pytest.warns(sc.SpecialFunctionWarning):
38
+ fun(*args)
39
+ elif action == 'raise':
40
+ with assert_raises(sc.SpecialFunctionError):
41
+ fun(*args)
42
+ else:
43
+ # action == 'ignore', make sure there are no warnings/exceptions
44
+ with warnings.catch_warnings():
45
+ warnings.simplefilter("error")
46
+ fun(*args)
47
+
48
+
49
+ def test_geterr():
50
+ err = sc.geterr()
51
+ for key, value in err.items():
52
+ assert_(key in _sf_error_code_map)
53
+ assert_(value in _sf_error_actions)
54
+
55
+
56
+ def test_seterr():
57
+ entry_err = sc.geterr()
58
+ try:
59
+ for category, error_code in _sf_error_code_map.items():
60
+ for action in _sf_error_actions:
61
+ geterr_olderr = sc.geterr()
62
+ seterr_olderr = sc.seterr(**{category: action})
63
+ assert_(geterr_olderr == seterr_olderr)
64
+ newerr = sc.geterr()
65
+ assert_(newerr[category] == action)
66
+ geterr_olderr.pop(category)
67
+ newerr.pop(category)
68
+ assert_(geterr_olderr == newerr)
69
+ _check_action(_sf_error_test_function, (error_code,), action)
70
+ finally:
71
+ sc.seterr(**entry_err)
72
+
73
+
74
+ @pytest.mark.skipif(IS_PYPY, reason="Test not meaningful on PyPy")
75
+ def test_sf_error_special_refcount():
76
+ # Regression test for gh-16233.
77
+ # Check that the reference count of scipy.special is not increased
78
+ # when a SpecialFunctionError is raised.
79
+ refcount_before = sys.getrefcount(sc)
80
+ with sc.errstate(all='raise'):
81
+ with pytest.raises(sc.SpecialFunctionError, match='domain error'):
82
+ sc.ndtri(2.0)
83
+ refcount_after = sys.getrefcount(sc)
84
+ assert refcount_after == refcount_before
85
+
86
+
87
+ def test_errstate_pyx_basic():
88
+ olderr = sc.geterr()
89
+ with sc.errstate(singular='raise'):
90
+ with assert_raises(sc.SpecialFunctionError):
91
+ sc.loggamma(0)
92
+ assert_equal(olderr, sc.geterr())
93
+
94
+
95
+ def test_errstate_c_basic():
96
+ olderr = sc.geterr()
97
+ with sc.errstate(domain='raise'):
98
+ with assert_raises(sc.SpecialFunctionError):
99
+ sc.spence(-1)
100
+ assert_equal(olderr, sc.geterr())
101
+
102
+
103
+ def test_errstate_cpp_basic():
104
+ olderr = sc.geterr()
105
+ with sc.errstate(underflow='raise'):
106
+ with assert_raises(sc.SpecialFunctionError):
107
+ sc.wrightomega(-1000)
108
+ assert_equal(olderr, sc.geterr())
109
+
110
+
111
+ def test_errstate_cpp_scipy_special():
112
+ olderr = sc.geterr()
113
+ with sc.errstate(singular='raise'):
114
+ with assert_raises(sc.SpecialFunctionError):
115
+ sc.lambertw(0, 1)
116
+ assert_equal(olderr, sc.geterr())
117
+
118
+
119
+ def test_errstate():
120
+ for category, error_code in _sf_error_code_map.items():
121
+ for action in _sf_error_actions:
122
+ olderr = sc.geterr()
123
+ with sc.errstate(**{category: action}):
124
+ _check_action(_sf_error_test_function, (error_code,), action)
125
+ assert_equal(olderr, sc.geterr())
126
+
127
+
128
+ def test_errstate_all_but_one():
129
+ olderr = sc.geterr()
130
+ with sc.errstate(all='raise', singular='ignore'):
131
+ sc.gammaln(0)
132
+ with assert_raises(sc.SpecialFunctionError):
133
+ sc.spence(-1.0)
134
+ assert_equal(olderr, sc.geterr())
.venv/Lib/site-packages/scipy/special/tests/test_sici.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+
3
+ import scipy.special as sc
4
+ from scipy.special._testutils import FuncData
5
+
6
+
7
+ def test_sici_consistency():
8
+ # Make sure the implementation of sici for real arguments agrees
9
+ # with the implementation of sici for complex arguments.
10
+
11
+ # On the negative real axis Cephes drops the imaginary part in ci
12
+ def sici(x):
13
+ si, ci = sc.sici(x + 0j)
14
+ return si.real, ci.real
15
+
16
+ x = np.r_[-np.logspace(8, -30, 200), 0, np.logspace(-30, 8, 200)]
17
+ si, ci = sc.sici(x)
18
+ dataset = np.column_stack((x, si, ci))
19
+ FuncData(sici, dataset, 0, (1, 2), rtol=1e-12).check()
20
+
21
+
22
+ def test_shichi_consistency():
23
+ # Make sure the implementation of shichi for real arguments agrees
24
+ # with the implementation of shichi for complex arguments.
25
+
26
+ # On the negative real axis Cephes drops the imaginary part in chi
27
+ def shichi(x):
28
+ shi, chi = sc.shichi(x + 0j)
29
+ return shi.real, chi.real
30
+
31
+ # Overflow happens quickly, so limit range
32
+ x = np.r_[-np.logspace(np.log10(700), -30, 200), 0,
33
+ np.logspace(-30, np.log10(700), 200)]
34
+ shi, chi = sc.shichi(x)
35
+ dataset = np.column_stack((x, shi, chi))
36
+ FuncData(shichi, dataset, 0, (1, 2), rtol=1e-14).check()
.venv/Lib/site-packages/scipy/special/tests/test_specfun.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Various made-up tests to hit different branches of the code in specfun.c
3
+ """
4
+
5
+ import numpy as np
6
+ from numpy.testing import assert_allclose
7
+ from scipy import special
8
+
9
+
10
+ def test_cchg_branches():
11
+ res = special.hyp1f1(0.1, 1, 7.0-24.0j)
12
+ assert_allclose(res, (-3.7659844658568016+4.970311359851648j))
13
+
14
+
15
+ def test_cva2_cv0_branches():
16
+ res, resp = special.mathieu_cem([40, 129], [13, 14], [30, 45])
17
+ assert_allclose(res, np.array([-0.3741211, 0.74441928]))
18
+ assert_allclose(resp, np.array([-37.02872758, -86.13549877]))
19
+
20
+ res, resp = special.mathieu_sem([40, 129], [13, 14], [30, 45])
21
+ assert_allclose(res, np.array([0.92955551, 0.66771207]))
22
+ assert_allclose(resp, np.array([-14.91073448, 96.02954185]))
23
+
24
+
25
+ def test_chgm_branches():
26
+ res = special.eval_genlaguerre(-3.2, 3, 2.5)
27
+ assert_allclose(res, -0.7077721935779854)
28
+
29
+
30
+ def test_hygfz_branches():
31
+ """(z == 1.0) && (c-a-b > 0.0)"""
32
+ res = special.hyp2f1(1.5, 2.5, 4.5, 1.+0.j)
33
+ assert_allclose(res, 10.30835089459151+0j)
34
+ """(cabs(z+1) < eps) && (fabs(c-a+b - 1.0) < eps)"""
35
+ res = special.hyp2f1(5+5e-16, 2, 2, -1.0 + 5e-16j)
36
+ assert_allclose(res, 0.031249999999999986+3.9062499999999994e-17j)
.venv/Lib/site-packages/scipy/special/tests/test_spence.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from numpy import sqrt, log, pi
3
+ from scipy.special._testutils import FuncData
4
+ from scipy.special import spence
5
+
6
+
7
+ def test_consistency():
8
+ # Make sure the implementation of spence for real arguments
9
+ # agrees with the implementation of spence for imaginary arguments.
10
+
11
+ x = np.logspace(-30, 300, 200)
12
+ dataset = np.vstack((x + 0j, spence(x))).T
13
+ FuncData(spence, dataset, 0, 1, rtol=1e-14).check()
14
+
15
+
16
+ def test_special_points():
17
+ # Check against known values of Spence's function.
18
+
19
+ phi = (1 + sqrt(5))/2
20
+ dataset = [(1, 0),
21
+ (2, -pi**2/12),
22
+ (0.5, pi**2/12 - log(2)**2/2),
23
+ (0, pi**2/6),
24
+ (-1, pi**2/4 - 1j*pi*log(2)),
25
+ ((-1 + sqrt(5))/2, pi**2/15 - log(phi)**2),
26
+ ((3 - sqrt(5))/2, pi**2/10 - log(phi)**2),
27
+ (phi, -pi**2/15 + log(phi)**2/2),
28
+ # Corrected from Zagier, "The Dilogarithm Function"
29
+ ((3 + sqrt(5))/2, -pi**2/10 - log(phi)**2)]
30
+
31
+ dataset = np.asarray(dataset)
32
+ FuncData(spence, dataset, 0, 1, rtol=1e-14).check()
.venv/Lib/site-packages/scipy/special/tests/test_spfun_stats.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from numpy.testing import (assert_array_equal,
3
+ assert_array_almost_equal_nulp, assert_almost_equal)
4
+ from pytest import raises as assert_raises
5
+
6
+ from scipy.special import gammaln, multigammaln
7
+
8
+
9
+ class TestMultiGammaLn:
10
+
11
+ def test1(self):
12
+ # A test of the identity
13
+ # Gamma_1(a) = Gamma(a)
14
+ np.random.seed(1234)
15
+ a = np.abs(np.random.randn())
16
+ assert_array_equal(multigammaln(a, 1), gammaln(a))
17
+
18
+ def test2(self):
19
+ # A test of the identity
20
+ # Gamma_2(a) = sqrt(pi) * Gamma(a) * Gamma(a - 0.5)
21
+ a = np.array([2.5, 10.0])
22
+ result = multigammaln(a, 2)
23
+ expected = np.log(np.sqrt(np.pi)) + gammaln(a) + gammaln(a - 0.5)
24
+ assert_almost_equal(result, expected)
25
+
26
+ def test_bararg(self):
27
+ assert_raises(ValueError, multigammaln, 0.5, 1.2)
28
+
29
+
30
+ def _check_multigammaln_array_result(a, d):
31
+ # Test that the shape of the array returned by multigammaln
32
+ # matches the input shape, and that all the values match
33
+ # the value computed when multigammaln is called with a scalar.
34
+ result = multigammaln(a, d)
35
+ assert_array_equal(a.shape, result.shape)
36
+ a1 = a.ravel()
37
+ result1 = result.ravel()
38
+ for i in range(a.size):
39
+ assert_array_almost_equal_nulp(result1[i], multigammaln(a1[i], d))
40
+
41
+
42
+ def test_multigammaln_array_arg():
43
+ # Check that the array returned by multigammaln has the correct
44
+ # shape and contains the correct values. The cases have arrays
45
+ # with several different shapes.
46
+ # The cases include a regression test for ticket #1849
47
+ # (a = np.array([2.0]), an array with a single element).
48
+ np.random.seed(1234)
49
+
50
+ cases = [
51
+ # a, d
52
+ (np.abs(np.random.randn(3, 2)) + 5, 5),
53
+ (np.abs(np.random.randn(1, 2)) + 5, 5),
54
+ (np.arange(10.0, 18.0).reshape(2, 2, 2), 3),
55
+ (np.array([2.0]), 3),
56
+ (np.float64(2.0), 3),
57
+ ]
58
+
59
+ for a, d in cases:
60
+ _check_multigammaln_array_result(a, d)
61
+
.venv/Lib/site-packages/scipy/special/tests/test_sph_harm.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from numpy.testing import assert_allclose
3
+ import scipy.special as sc
4
+
5
+
6
+ def test_first_harmonics():
7
+ # Test against explicit representations of the first four
8
+ # spherical harmonics which use `theta` as the azimuthal angle,
9
+ # `phi` as the polar angle, and include the Condon-Shortley
10
+ # phase.
11
+
12
+ # Notation is Ymn
13
+ def Y00(theta, phi):
14
+ return 0.5*np.sqrt(1/np.pi)
15
+
16
+ def Yn11(theta, phi):
17
+ return 0.5*np.sqrt(3/(2*np.pi))*np.exp(-1j*theta)*np.sin(phi)
18
+
19
+ def Y01(theta, phi):
20
+ return 0.5*np.sqrt(3/np.pi)*np.cos(phi)
21
+
22
+ def Y11(theta, phi):
23
+ return -0.5*np.sqrt(3/(2*np.pi))*np.exp(1j*theta)*np.sin(phi)
24
+
25
+ harms = [Y00, Yn11, Y01, Y11]
26
+ m = [0, -1, 0, 1]
27
+ n = [0, 1, 1, 1]
28
+
29
+ theta = np.linspace(0, 2*np.pi)
30
+ phi = np.linspace(0, np.pi)
31
+ theta, phi = np.meshgrid(theta, phi)
32
+
33
+ for harm, m, n in zip(harms, m, n):
34
+ assert_allclose(sc.sph_harm(m, n, theta, phi),
35
+ harm(theta, phi),
36
+ rtol=1e-15, atol=1e-15,
37
+ err_msg=f"Y^{m}_{n} incorrect")
.venv/Lib/site-packages/scipy/special/tests/test_spherical_bessel.py ADDED
@@ -0,0 +1,385 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Tests of spherical Bessel functions.
3
+ #
4
+ import numpy as np
5
+ from numpy.testing import (assert_almost_equal, assert_allclose,
6
+ assert_array_almost_equal, suppress_warnings)
7
+ import pytest
8
+ from numpy import sin, cos, sinh, cosh, exp, inf, nan, r_, pi
9
+
10
+ from scipy.special import spherical_jn, spherical_yn, spherical_in, spherical_kn
11
+ from scipy.integrate import quad
12
+
13
+
14
+ class TestSphericalJn:
15
+ def test_spherical_jn_exact(self):
16
+ # https://dlmf.nist.gov/10.49.E3
17
+ # Note: exact expression is numerically stable only for small
18
+ # n or z >> n.
19
+ x = np.array([0.12, 1.23, 12.34, 123.45, 1234.5])
20
+ assert_allclose(spherical_jn(2, x),
21
+ (-1/x + 3/x**3)*sin(x) - 3/x**2*cos(x))
22
+
23
+ def test_spherical_jn_recurrence_complex(self):
24
+ # https://dlmf.nist.gov/10.51.E1
25
+ n = np.array([1, 2, 3, 7, 12])
26
+ x = 1.1 + 1.5j
27
+ assert_allclose(spherical_jn(n - 1, x) + spherical_jn(n + 1, x),
28
+ (2*n + 1)/x*spherical_jn(n, x))
29
+
30
+ def test_spherical_jn_recurrence_real(self):
31
+ # https://dlmf.nist.gov/10.51.E1
32
+ n = np.array([1, 2, 3, 7, 12])
33
+ x = 0.12
34
+ assert_allclose(spherical_jn(n - 1, x) + spherical_jn(n + 1,x),
35
+ (2*n + 1)/x*spherical_jn(n, x))
36
+
37
+ def test_spherical_jn_inf_real(self):
38
+ # https://dlmf.nist.gov/10.52.E3
39
+ n = 6
40
+ x = np.array([-inf, inf])
41
+ assert_allclose(spherical_jn(n, x), np.array([0, 0]))
42
+
43
+ def test_spherical_jn_inf_complex(self):
44
+ # https://dlmf.nist.gov/10.52.E3
45
+ n = 7
46
+ x = np.array([-inf + 0j, inf + 0j, inf*(1+1j)])
47
+ with suppress_warnings() as sup:
48
+ sup.filter(RuntimeWarning, "invalid value encountered in multiply")
49
+ assert_allclose(spherical_jn(n, x), np.array([0, 0, inf*(1+1j)]))
50
+
51
+ def test_spherical_jn_large_arg_1(self):
52
+ # https://github.com/scipy/scipy/issues/2165
53
+ # Reference value computed using mpmath, via
54
+ # besselj(n + mpf(1)/2, z)*sqrt(pi/(2*z))
55
+ assert_allclose(spherical_jn(2, 3350.507), -0.00029846226538040747)
56
+
57
+ def test_spherical_jn_large_arg_2(self):
58
+ # https://github.com/scipy/scipy/issues/1641
59
+ # Reference value computed using mpmath, via
60
+ # besselj(n + mpf(1)/2, z)*sqrt(pi/(2*z))
61
+ assert_allclose(spherical_jn(2, 10000), 3.0590002633029811e-05)
62
+
63
+ def test_spherical_jn_at_zero(self):
64
+ # https://dlmf.nist.gov/10.52.E1
65
+ # But note that n = 0 is a special case: j0 = sin(x)/x -> 1
66
+ n = np.array([0, 1, 2, 5, 10, 100])
67
+ x = 0
68
+ assert_allclose(spherical_jn(n, x), np.array([1, 0, 0, 0, 0, 0]))
69
+
70
+
71
+ class TestSphericalYn:
72
+ def test_spherical_yn_exact(self):
73
+ # https://dlmf.nist.gov/10.49.E5
74
+ # Note: exact expression is numerically stable only for small
75
+ # n or z >> n.
76
+ x = np.array([0.12, 1.23, 12.34, 123.45, 1234.5])
77
+ assert_allclose(spherical_yn(2, x),
78
+ (1/x - 3/x**3)*cos(x) - 3/x**2*sin(x))
79
+
80
+ def test_spherical_yn_recurrence_real(self):
81
+ # https://dlmf.nist.gov/10.51.E1
82
+ n = np.array([1, 2, 3, 7, 12])
83
+ x = 0.12
84
+ assert_allclose(spherical_yn(n - 1, x) + spherical_yn(n + 1,x),
85
+ (2*n + 1)/x*spherical_yn(n, x))
86
+
87
+ def test_spherical_yn_recurrence_complex(self):
88
+ # https://dlmf.nist.gov/10.51.E1
89
+ n = np.array([1, 2, 3, 7, 12])
90
+ x = 1.1 + 1.5j
91
+ assert_allclose(spherical_yn(n - 1, x) + spherical_yn(n + 1, x),
92
+ (2*n + 1)/x*spherical_yn(n, x))
93
+
94
+ def test_spherical_yn_inf_real(self):
95
+ # https://dlmf.nist.gov/10.52.E3
96
+ n = 6
97
+ x = np.array([-inf, inf])
98
+ assert_allclose(spherical_yn(n, x), np.array([0, 0]))
99
+
100
+ def test_spherical_yn_inf_complex(self):
101
+ # https://dlmf.nist.gov/10.52.E3
102
+ n = 7
103
+ x = np.array([-inf + 0j, inf + 0j, inf*(1+1j)])
104
+ with suppress_warnings() as sup:
105
+ sup.filter(RuntimeWarning, "invalid value encountered in multiply")
106
+ assert_allclose(spherical_yn(n, x), np.array([0, 0, inf*(1+1j)]))
107
+
108
+ def test_spherical_yn_at_zero(self):
109
+ # https://dlmf.nist.gov/10.52.E2
110
+ n = np.array([0, 1, 2, 5, 10, 100])
111
+ x = 0
112
+ assert_allclose(spherical_yn(n, x), np.full(n.shape, -inf))
113
+
114
+ def test_spherical_yn_at_zero_complex(self):
115
+ # Consistently with numpy:
116
+ # >>> -np.cos(0)/0
117
+ # -inf
118
+ # >>> -np.cos(0+0j)/(0+0j)
119
+ # (-inf + nan*j)
120
+ n = np.array([0, 1, 2, 5, 10, 100])
121
+ x = 0 + 0j
122
+ assert_allclose(spherical_yn(n, x), np.full(n.shape, nan))
123
+
124
+
125
+ class TestSphericalJnYnCrossProduct:
126
+ def test_spherical_jn_yn_cross_product_1(self):
127
+ # https://dlmf.nist.gov/10.50.E3
128
+ n = np.array([1, 5, 8])
129
+ x = np.array([0.1, 1, 10])
130
+ left = (spherical_jn(n + 1, x) * spherical_yn(n, x) -
131
+ spherical_jn(n, x) * spherical_yn(n + 1, x))
132
+ right = 1/x**2
133
+ assert_allclose(left, right)
134
+
135
+ def test_spherical_jn_yn_cross_product_2(self):
136
+ # https://dlmf.nist.gov/10.50.E3
137
+ n = np.array([1, 5, 8])
138
+ x = np.array([0.1, 1, 10])
139
+ left = (spherical_jn(n + 2, x) * spherical_yn(n, x) -
140
+ spherical_jn(n, x) * spherical_yn(n + 2, x))
141
+ right = (2*n + 3)/x**3
142
+ assert_allclose(left, right)
143
+
144
+
145
+ class TestSphericalIn:
146
+ def test_spherical_in_exact(self):
147
+ # https://dlmf.nist.gov/10.49.E9
148
+ x = np.array([0.12, 1.23, 12.34, 123.45])
149
+ assert_allclose(spherical_in(2, x),
150
+ (1/x + 3/x**3)*sinh(x) - 3/x**2*cosh(x))
151
+
152
+ def test_spherical_in_recurrence_real(self):
153
+ # https://dlmf.nist.gov/10.51.E4
154
+ n = np.array([1, 2, 3, 7, 12])
155
+ x = 0.12
156
+ assert_allclose(spherical_in(n - 1, x) - spherical_in(n + 1,x),
157
+ (2*n + 1)/x*spherical_in(n, x))
158
+
159
+ def test_spherical_in_recurrence_complex(self):
160
+ # https://dlmf.nist.gov/10.51.E1
161
+ n = np.array([1, 2, 3, 7, 12])
162
+ x = 1.1 + 1.5j
163
+ assert_allclose(spherical_in(n - 1, x) - spherical_in(n + 1,x),
164
+ (2*n + 1)/x*spherical_in(n, x))
165
+
166
+ def test_spherical_in_inf_real(self):
167
+ # https://dlmf.nist.gov/10.52.E3
168
+ n = 5
169
+ x = np.array([-inf, inf])
170
+ assert_allclose(spherical_in(n, x), np.array([-inf, inf]))
171
+
172
+ def test_spherical_in_inf_complex(self):
173
+ # https://dlmf.nist.gov/10.52.E5
174
+ # Ideally, i1n(n, 1j*inf) = 0 and i1n(n, (1+1j)*inf) = (1+1j)*inf, but
175
+ # this appears impossible to achieve because C99 regards any complex
176
+ # value with at least one infinite part as a complex infinity, so
177
+ # 1j*inf cannot be distinguished from (1+1j)*inf. Therefore, nan is
178
+ # the correct return value.
179
+ n = 7
180
+ x = np.array([-inf + 0j, inf + 0j, inf*(1+1j)])
181
+ assert_allclose(spherical_in(n, x), np.array([-inf, inf, nan]))
182
+
183
+ def test_spherical_in_at_zero(self):
184
+ # https://dlmf.nist.gov/10.52.E1
185
+ # But note that n = 0 is a special case: i0 = sinh(x)/x -> 1
186
+ n = np.array([0, 1, 2, 5, 10, 100])
187
+ x = 0
188
+ assert_allclose(spherical_in(n, x), np.array([1, 0, 0, 0, 0, 0]))
189
+
190
+
191
+ class TestSphericalKn:
192
+ def test_spherical_kn_exact(self):
193
+ # https://dlmf.nist.gov/10.49.E13
194
+ x = np.array([0.12, 1.23, 12.34, 123.45])
195
+ assert_allclose(spherical_kn(2, x),
196
+ pi/2*exp(-x)*(1/x + 3/x**2 + 3/x**3))
197
+
198
+ def test_spherical_kn_recurrence_real(self):
199
+ # https://dlmf.nist.gov/10.51.E4
200
+ n = np.array([1, 2, 3, 7, 12])
201
+ x = 0.12
202
+ assert_allclose(
203
+ (-1)**(n - 1)*spherical_kn(n - 1, x) - (-1)**(n + 1)*spherical_kn(n + 1,x),
204
+ (-1)**n*(2*n + 1)/x*spherical_kn(n, x)
205
+ )
206
+
207
+ def test_spherical_kn_recurrence_complex(self):
208
+ # https://dlmf.nist.gov/10.51.E4
209
+ n = np.array([1, 2, 3, 7, 12])
210
+ x = 1.1 + 1.5j
211
+ assert_allclose(
212
+ (-1)**(n - 1)*spherical_kn(n - 1, x) - (-1)**(n + 1)*spherical_kn(n + 1,x),
213
+ (-1)**n*(2*n + 1)/x*spherical_kn(n, x)
214
+ )
215
+
216
+ def test_spherical_kn_inf_real(self):
217
+ # https://dlmf.nist.gov/10.52.E6
218
+ n = 5
219
+ x = np.array([-inf, inf])
220
+ assert_allclose(spherical_kn(n, x), np.array([-inf, 0]))
221
+
222
+ def test_spherical_kn_inf_complex(self):
223
+ # https://dlmf.nist.gov/10.52.E6
224
+ # The behavior at complex infinity depends on the sign of the real
225
+ # part: if Re(z) >= 0, then the limit is 0; if Re(z) < 0, then it's
226
+ # z*inf. This distinction cannot be captured, so we return nan.
227
+ n = 7
228
+ x = np.array([-inf + 0j, inf + 0j, inf*(1+1j)])
229
+ assert_allclose(spherical_kn(n, x), np.array([-inf, 0, nan]))
230
+
231
+ def test_spherical_kn_at_zero(self):
232
+ # https://dlmf.nist.gov/10.52.E2
233
+ n = np.array([0, 1, 2, 5, 10, 100])
234
+ x = 0
235
+ assert_allclose(spherical_kn(n, x), np.full(n.shape, inf))
236
+
237
+ def test_spherical_kn_at_zero_complex(self):
238
+ # https://dlmf.nist.gov/10.52.E2
239
+ n = np.array([0, 1, 2, 5, 10, 100])
240
+ x = 0 + 0j
241
+ assert_allclose(spherical_kn(n, x), np.full(n.shape, nan))
242
+
243
+
244
+ class SphericalDerivativesTestCase:
245
+ def fundamental_theorem(self, n, a, b):
246
+ integral, tolerance = quad(lambda z: self.df(n, z), a, b)
247
+ assert_allclose(integral,
248
+ self.f(n, b) - self.f(n, a),
249
+ atol=tolerance)
250
+
251
+ @pytest.mark.slow
252
+ def test_fundamental_theorem_0(self):
253
+ self.fundamental_theorem(0, 3.0, 15.0)
254
+
255
+ @pytest.mark.slow
256
+ def test_fundamental_theorem_7(self):
257
+ self.fundamental_theorem(7, 0.5, 1.2)
258
+
259
+
260
+ class TestSphericalJnDerivatives(SphericalDerivativesTestCase):
261
+ def f(self, n, z):
262
+ return spherical_jn(n, z)
263
+
264
+ def df(self, n, z):
265
+ return spherical_jn(n, z, derivative=True)
266
+
267
+ def test_spherical_jn_d_zero(self):
268
+ n = np.array([0, 1, 2, 3, 7, 15])
269
+ assert_allclose(spherical_jn(n, 0, derivative=True),
270
+ np.array([0, 1/3, 0, 0, 0, 0]))
271
+
272
+
273
+ class TestSphericalYnDerivatives(SphericalDerivativesTestCase):
274
+ def f(self, n, z):
275
+ return spherical_yn(n, z)
276
+
277
+ def df(self, n, z):
278
+ return spherical_yn(n, z, derivative=True)
279
+
280
+
281
+ class TestSphericalInDerivatives(SphericalDerivativesTestCase):
282
+ def f(self, n, z):
283
+ return spherical_in(n, z)
284
+
285
+ def df(self, n, z):
286
+ return spherical_in(n, z, derivative=True)
287
+
288
+ def test_spherical_in_d_zero(self):
289
+ n = np.array([0, 1, 2, 3, 7, 15])
290
+ spherical_in(n, 0, derivative=False)
291
+ assert_allclose(spherical_in(n, 0, derivative=True),
292
+ np.array([0, 1/3, 0, 0, 0, 0]))
293
+
294
+
295
+ class TestSphericalKnDerivatives(SphericalDerivativesTestCase):
296
+ def f(self, n, z):
297
+ return spherical_kn(n, z)
298
+
299
+ def df(self, n, z):
300
+ return spherical_kn(n, z, derivative=True)
301
+
302
+
303
+ class TestSphericalOld:
304
+ # These are tests from the TestSpherical class of test_basic.py,
305
+ # rewritten to use spherical_* instead of sph_* but otherwise unchanged.
306
+
307
+ def test_sph_in(self):
308
+ # This test reproduces test_basic.TestSpherical.test_sph_in.
309
+ i1n = np.empty((2,2))
310
+ x = 0.2
311
+
312
+ i1n[0][0] = spherical_in(0, x)
313
+ i1n[0][1] = spherical_in(1, x)
314
+ i1n[1][0] = spherical_in(0, x, derivative=True)
315
+ i1n[1][1] = spherical_in(1, x, derivative=True)
316
+
317
+ inp0 = (i1n[0][1])
318
+ inp1 = (i1n[0][0] - 2.0/0.2 * i1n[0][1])
319
+ assert_array_almost_equal(i1n[0],np.array([1.0066800127054699381,
320
+ 0.066933714568029540839]),12)
321
+ assert_array_almost_equal(i1n[1],[inp0,inp1],12)
322
+
323
+ def test_sph_in_kn_order0(self):
324
+ x = 1.
325
+ sph_i0 = np.empty((2,))
326
+ sph_i0[0] = spherical_in(0, x)
327
+ sph_i0[1] = spherical_in(0, x, derivative=True)
328
+ sph_i0_expected = np.array([np.sinh(x)/x,
329
+ np.cosh(x)/x-np.sinh(x)/x**2])
330
+ assert_array_almost_equal(r_[sph_i0], sph_i0_expected)
331
+
332
+ sph_k0 = np.empty((2,))
333
+ sph_k0[0] = spherical_kn(0, x)
334
+ sph_k0[1] = spherical_kn(0, x, derivative=True)
335
+ sph_k0_expected = np.array([0.5*pi*exp(-x)/x,
336
+ -0.5*pi*exp(-x)*(1/x+1/x**2)])
337
+ assert_array_almost_equal(r_[sph_k0], sph_k0_expected)
338
+
339
+ def test_sph_jn(self):
340
+ s1 = np.empty((2,3))
341
+ x = 0.2
342
+
343
+ s1[0][0] = spherical_jn(0, x)
344
+ s1[0][1] = spherical_jn(1, x)
345
+ s1[0][2] = spherical_jn(2, x)
346
+ s1[1][0] = spherical_jn(0, x, derivative=True)
347
+ s1[1][1] = spherical_jn(1, x, derivative=True)
348
+ s1[1][2] = spherical_jn(2, x, derivative=True)
349
+
350
+ s10 = -s1[0][1]
351
+ s11 = s1[0][0]-2.0/0.2*s1[0][1]
352
+ s12 = s1[0][1]-3.0/0.2*s1[0][2]
353
+ assert_array_almost_equal(s1[0],[0.99334665397530607731,
354
+ 0.066400380670322230863,
355
+ 0.0026590560795273856680],12)
356
+ assert_array_almost_equal(s1[1],[s10,s11,s12],12)
357
+
358
+ def test_sph_kn(self):
359
+ kn = np.empty((2,3))
360
+ x = 0.2
361
+
362
+ kn[0][0] = spherical_kn(0, x)
363
+ kn[0][1] = spherical_kn(1, x)
364
+ kn[0][2] = spherical_kn(2, x)
365
+ kn[1][0] = spherical_kn(0, x, derivative=True)
366
+ kn[1][1] = spherical_kn(1, x, derivative=True)
367
+ kn[1][2] = spherical_kn(2, x, derivative=True)
368
+
369
+ kn0 = -kn[0][1]
370
+ kn1 = -kn[0][0]-2.0/0.2*kn[0][1]
371
+ kn2 = -kn[0][1]-3.0/0.2*kn[0][2]
372
+ assert_array_almost_equal(kn[0],[6.4302962978445670140,
373
+ 38.581777787067402086,
374
+ 585.15696310385559829],12)
375
+ assert_array_almost_equal(kn[1],[kn0,kn1,kn2],9)
376
+
377
+ def test_sph_yn(self):
378
+ sy1 = spherical_yn(2, 0.2)
379
+ sy2 = spherical_yn(0, 0.2)
380
+ assert_almost_equal(sy1,-377.52483,5) # previous values in the system
381
+ assert_almost_equal(sy2,-4.9003329,5)
382
+ sphpy = (spherical_yn(0, 0.2) - 2*spherical_yn(2, 0.2))/3
383
+ sy3 = spherical_yn(1, 0.2, derivative=True)
384
+ # compare correct derivative val. (correct =-system val).
385
+ assert_almost_equal(sy3,sphpy,4)
.venv/Lib/site-packages/scipy/special/tests/test_support_alternative_backends.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pytest
2
+ from hypothesis import given, strategies, reproduce_failure # noqa: F401
3
+ import hypothesis.extra.numpy as npst
4
+
5
+ from scipy.special._support_alternative_backends import (get_array_special_func,
6
+ array_special_func_map)
7
+ from scipy.conftest import array_api_compatible
8
+ from scipy import special
9
+ from scipy._lib._array_api import xp_assert_close
10
+ from scipy._lib.array_api_compat import numpy as np
11
+
12
+ try:
13
+ import array_api_strict
14
+ HAVE_ARRAY_API_STRICT = True
15
+ except ImportError:
16
+ HAVE_ARRAY_API_STRICT = False
17
+
18
+
19
+ @pytest.mark.skipif(not HAVE_ARRAY_API_STRICT,
20
+ reason="`array_api_strict` not installed")
21
+ def test_dispatch_to_unrecognize_library():
22
+ xp = array_api_strict
23
+ f = get_array_special_func('ndtr', xp=xp, n_array_args=1)
24
+ x = [1, 2, 3]
25
+ res = f(xp.asarray(x))
26
+ ref = xp.asarray(special.ndtr(np.asarray(x)))
27
+ xp_assert_close(res, ref, xp=xp)
28
+
29
+
30
+ @array_api_compatible
31
+ @given(data=strategies.data())
32
+ @pytest.mark.parametrize('f_name_n_args', array_special_func_map.items())
33
+ def test_support_alternative_backends(xp, data, f_name_n_args):
34
+ f_name, n_args = f_name_n_args
35
+ f = getattr(special, f_name)
36
+
37
+ mbs = npst.mutually_broadcastable_shapes(num_shapes=n_args)
38
+ shapes, final_shape = data.draw(mbs)
39
+
40
+ dtype = data.draw(strategies.sampled_from(['float32', 'float64']))
41
+ dtype_np = getattr(np, dtype)
42
+ dtype_xp = getattr(xp, dtype)
43
+
44
+ elements = dict(min_value=dtype_np(-10), max_value=dtype_np(10),
45
+ allow_subnormal=False)
46
+ args_np = [np.asarray(data.draw(npst.arrays(dtype_np, shape, elements=elements)))
47
+ for shape in shapes]
48
+
49
+ # `torch.asarray(np.asarray(1.))` produces
50
+ # TypeError: can't convert np.ndarray of type numpy.object_.
51
+ # So we extract the scalar from 0d arrays.
52
+ args_xp = [xp.asarray(arg[()], dtype=dtype_xp) for arg in args_np]
53
+
54
+ ref = np.asarray(f(*args_np))
55
+ res = f(*args_xp)
56
+
57
+ eps = np.finfo(dtype).eps
58
+ # PyTorch seems to struggle with precision near the poles of `gammaln`,
59
+ # so the tolerance needs to be quite loose (eps**0.2) - see gh-19935.
60
+ # To compensate, we also check that the root-mean-square error is
61
+ # less than eps**0.5.
62
+ ref = xp.asarray(ref, dtype=dtype_xp)
63
+ xp_assert_close(res, ref, rtol=eps**0.2, atol=eps*10,
64
+ check_namespace=True, check_shape=True, check_dtype=True,)
65
+ xp_assert_close(xp.sqrt(xp.mean(res**2)), xp.sqrt(xp.mean(ref**2)),
66
+ rtol=eps**0.5, atol=eps*10,
67
+ check_namespace=False, check_shape=False, check_dtype=False,)
.venv/Lib/site-packages/scipy/special/tests/test_trig.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pytest
2
+ import numpy as np
3
+ from numpy.testing import assert_equal, assert_allclose, suppress_warnings
4
+
5
+ from scipy.special._ufuncs import _sinpi as sinpi
6
+ from scipy.special._ufuncs import _cospi as cospi
7
+
8
+
9
+ def test_integer_real_part():
10
+ x = np.arange(-100, 101)
11
+ y = np.hstack((-np.linspace(310, -30, 10), np.linspace(-30, 310, 10)))
12
+ x, y = np.meshgrid(x, y)
13
+ z = x + 1j*y
14
+ # In the following we should be *exactly* right
15
+ res = sinpi(z)
16
+ assert_equal(res.real, 0.0)
17
+ res = cospi(z)
18
+ assert_equal(res.imag, 0.0)
19
+
20
+
21
+ def test_half_integer_real_part():
22
+ x = np.arange(-100, 101) + 0.5
23
+ y = np.hstack((-np.linspace(310, -30, 10), np.linspace(-30, 310, 10)))
24
+ x, y = np.meshgrid(x, y)
25
+ z = x + 1j*y
26
+ # In the following we should be *exactly* right
27
+ res = sinpi(z)
28
+ assert_equal(res.imag, 0.0)
29
+ res = cospi(z)
30
+ assert_equal(res.real, 0.0)
31
+
32
+
33
+ @pytest.mark.skip("Temporary skip while gh-19526 is being resolved")
34
+ def test_intermediate_overlow():
35
+ # Make sure we avoid overflow in situations where cosh/sinh would
36
+ # overflow but the product with sin/cos would not
37
+ sinpi_pts = [complex(1 + 1e-14, 227),
38
+ complex(1e-35, 250),
39
+ complex(1e-301, 445)]
40
+ # Data generated with mpmath
41
+ sinpi_std = [complex(-8.113438309924894e+295, -np.inf),
42
+ complex(1.9507801934611995e+306, np.inf),
43
+ complex(2.205958493464539e+306, np.inf)]
44
+ with suppress_warnings() as sup:
45
+ sup.filter(RuntimeWarning, "invalid value encountered in multiply")
46
+ for p, std in zip(sinpi_pts, sinpi_std):
47
+ res = sinpi(p)
48
+ assert_allclose(res.real, std.real)
49
+ assert_allclose(res.imag, std.imag)
50
+
51
+ # Test for cosine, less interesting because cos(0) = 1.
52
+ p = complex(0.5 + 1e-14, 227)
53
+ std = complex(-8.113438309924894e+295, -np.inf)
54
+ with suppress_warnings() as sup:
55
+ sup.filter(RuntimeWarning, "invalid value encountered in multiply")
56
+ res = cospi(p)
57
+ assert_allclose(res.real, std.real)
58
+ assert_allclose(res.imag, std.imag)
59
+
60
+
61
+ def test_zero_sign():
62
+ y = sinpi(-0.0)
63
+ assert y == 0.0
64
+ assert np.signbit(y)
65
+
66
+ y = sinpi(0.0)
67
+ assert y == 0.0
68
+ assert not np.signbit(y)
69
+
70
+ y = cospi(0.5)
71
+ assert y == 0.0
72
+ assert not np.signbit(y)
.venv/Lib/site-packages/scipy/special/tests/test_wrightomega.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pytest
2
+ import numpy as np
3
+ from numpy.testing import assert_, assert_equal, assert_allclose
4
+
5
+ import scipy.special as sc
6
+ from scipy.special._testutils import assert_func_equal
7
+
8
+
9
+ def test_wrightomega_nan():
10
+ pts = [complex(np.nan, 0),
11
+ complex(0, np.nan),
12
+ complex(np.nan, np.nan),
13
+ complex(np.nan, 1),
14
+ complex(1, np.nan)]
15
+ for p in pts:
16
+ res = sc.wrightomega(p)
17
+ assert_(np.isnan(res.real))
18
+ assert_(np.isnan(res.imag))
19
+
20
+
21
+ def test_wrightomega_inf_branch():
22
+ pts = [complex(-np.inf, np.pi/4),
23
+ complex(-np.inf, -np.pi/4),
24
+ complex(-np.inf, 3*np.pi/4),
25
+ complex(-np.inf, -3*np.pi/4)]
26
+ expected_results = [complex(0.0, 0.0),
27
+ complex(0.0, -0.0),
28
+ complex(-0.0, 0.0),
29
+ complex(-0.0, -0.0)]
30
+ for p, expected in zip(pts, expected_results):
31
+ res = sc.wrightomega(p)
32
+ # We can't use assert_equal(res, expected) because in older versions of
33
+ # numpy, assert_equal doesn't check the sign of the real and imaginary
34
+ # parts when comparing complex zeros. It does check the sign when the
35
+ # arguments are *real* scalars.
36
+ assert_equal(res.real, expected.real)
37
+ assert_equal(res.imag, expected.imag)
38
+
39
+
40
+ def test_wrightomega_inf():
41
+ pts = [complex(np.inf, 10),
42
+ complex(-np.inf, 10),
43
+ complex(10, np.inf),
44
+ complex(10, -np.inf)]
45
+ for p in pts:
46
+ assert_equal(sc.wrightomega(p), p)
47
+
48
+
49
+ def test_wrightomega_singular():
50
+ pts = [complex(-1.0, np.pi),
51
+ complex(-1.0, -np.pi)]
52
+ for p in pts:
53
+ res = sc.wrightomega(p)
54
+ assert_equal(res, -1.0)
55
+ assert_(np.signbit(res.imag) == np.bool_(False))
56
+
57
+
58
+ @pytest.mark.parametrize('x, desired', [
59
+ (-np.inf, 0),
60
+ (np.inf, np.inf),
61
+ ])
62
+ def test_wrightomega_real_infinities(x, desired):
63
+ assert sc.wrightomega(x) == desired
64
+
65
+
66
+ def test_wrightomega_real_nan():
67
+ assert np.isnan(sc.wrightomega(np.nan))
68
+
69
+
70
+ def test_wrightomega_real_series_crossover():
71
+ desired_error = 2 * np.finfo(float).eps
72
+ crossover = 1e20
73
+ x_before_crossover = np.nextafter(crossover, -np.inf)
74
+ x_after_crossover = np.nextafter(crossover, np.inf)
75
+ # Computed using Mpmath
76
+ desired_before_crossover = 99999999999999983569.948
77
+ desired_after_crossover = 100000000000000016337.948
78
+ assert_allclose(
79
+ sc.wrightomega(x_before_crossover),
80
+ desired_before_crossover,
81
+ atol=0,
82
+ rtol=desired_error,
83
+ )
84
+ assert_allclose(
85
+ sc.wrightomega(x_after_crossover),
86
+ desired_after_crossover,
87
+ atol=0,
88
+ rtol=desired_error,
89
+ )
90
+
91
+
92
+ def test_wrightomega_exp_approximation_crossover():
93
+ desired_error = 2 * np.finfo(float).eps
94
+ crossover = -50
95
+ x_before_crossover = np.nextafter(crossover, np.inf)
96
+ x_after_crossover = np.nextafter(crossover, -np.inf)
97
+ # Computed using Mpmath
98
+ desired_before_crossover = 1.9287498479639314876e-22
99
+ desired_after_crossover = 1.9287498479639040784e-22
100
+ assert_allclose(
101
+ sc.wrightomega(x_before_crossover),
102
+ desired_before_crossover,
103
+ atol=0,
104
+ rtol=desired_error,
105
+ )
106
+ assert_allclose(
107
+ sc.wrightomega(x_after_crossover),
108
+ desired_after_crossover,
109
+ atol=0,
110
+ rtol=desired_error,
111
+ )
112
+
113
+
114
+ def test_wrightomega_real_versus_complex():
115
+ x = np.linspace(-500, 500, 1001)
116
+ results = sc.wrightomega(x + 0j).real
117
+ assert_func_equal(sc.wrightomega, results, x, atol=0, rtol=1e-14)
.venv/Lib/site-packages/torch/lib/cublasLt64_12.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:111614ef49d83141a8556416fb9faf9019990f21d40f777fe5d47af65489e90d
3
+ size 538818048
.venv/Lib/site-packages/torch/lib/cudnn_engines_precompiled64_9.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:680625354e9f2ac80d573cc94fc5190848198262557226edd482aaca4ccb9113
3
+ size 588910632