Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +92 -0
- .venv/Lib/site-packages/scipy/sparse/tests/data/csc_py2.npz +3 -0
- .venv/Lib/site-packages/scipy/sparse/tests/data/csc_py3.npz +3 -0
- .venv/Lib/site-packages/scipy/special/_ufuncs_cxx.pxd +60 -0
- .venv/Lib/site-packages/scipy/special/special/cephes/const.h +77 -0
- .venv/Lib/site-packages/scipy/special/special/cephes/gamma.h +343 -0
- .venv/Lib/site-packages/scipy/special/special/cephes/polevl.h +165 -0
- .venv/Lib/site-packages/scipy/special/special/cephes/psi.h +194 -0
- .venv/Lib/site-packages/scipy/special/tests/test_dd.py +46 -0
- .venv/Lib/site-packages/scipy/special/tests/test_digamma.py +45 -0
- .venv/Lib/site-packages/scipy/special/tests/test_ellip_harm.py +278 -0
- .venv/Lib/site-packages/scipy/special/tests/test_erfinv.py +89 -0
- .venv/Lib/site-packages/scipy/special/tests/test_exponential_integrals.py +118 -0
- .venv/Lib/site-packages/scipy/special/tests/test_faddeeva.py +85 -0
- .venv/Lib/site-packages/scipy/special/tests/test_gamma.py +12 -0
- .venv/Lib/site-packages/scipy/special/tests/test_gammainc.py +136 -0
- .venv/Lib/site-packages/scipy/special/tests/test_hyp2f1.py +2180 -0
- .venv/Lib/site-packages/scipy/special/tests/test_hypergeometric.py +140 -0
- .venv/Lib/site-packages/scipy/special/tests/test_kolmogorov.py +495 -0
- .venv/Lib/site-packages/scipy/special/tests/test_lambertw.py +109 -0
- .venv/Lib/site-packages/scipy/special/tests/test_log_softmax.py +109 -0
- .venv/Lib/site-packages/scipy/special/tests/test_loggamma.py +70 -0
- .venv/Lib/site-packages/scipy/special/tests/test_logit.py +145 -0
- .venv/Lib/site-packages/scipy/special/tests/test_logsumexp.py +207 -0
- .venv/Lib/site-packages/scipy/special/tests/test_mpmath.py +2272 -0
- .venv/Lib/site-packages/scipy/special/tests/test_nan_inputs.py +64 -0
- .venv/Lib/site-packages/scipy/special/tests/test_ndtr.py +77 -0
- .venv/Lib/site-packages/scipy/special/tests/test_ndtri_exp.py +94 -0
- .venv/Lib/site-packages/scipy/special/tests/test_orthogonal.py +804 -0
- .venv/Lib/site-packages/scipy/special/tests/test_orthogonal_eval.py +272 -0
- .venv/Lib/site-packages/scipy/special/tests/test_owens_t.py +53 -0
- .venv/Lib/site-packages/scipy/special/tests/test_pcf.py +24 -0
- .venv/Lib/site-packages/scipy/special/tests/test_pdtr.py +48 -0
- .venv/Lib/site-packages/scipy/special/tests/test_powm1.py +65 -0
- .venv/Lib/site-packages/scipy/special/tests/test_precompute_expn_asy.py +24 -0
- .venv/Lib/site-packages/scipy/special/tests/test_precompute_gammainc.py +108 -0
- .venv/Lib/site-packages/scipy/special/tests/test_precompute_utils.py +36 -0
- .venv/Lib/site-packages/scipy/special/tests/test_round.py +16 -0
- .venv/Lib/site-packages/scipy/special/tests/test_sf_error.py +134 -0
- .venv/Lib/site-packages/scipy/special/tests/test_sici.py +36 -0
- .venv/Lib/site-packages/scipy/special/tests/test_specfun.py +36 -0
- .venv/Lib/site-packages/scipy/special/tests/test_spence.py +32 -0
- .venv/Lib/site-packages/scipy/special/tests/test_spfun_stats.py +61 -0
- .venv/Lib/site-packages/scipy/special/tests/test_sph_harm.py +37 -0
- .venv/Lib/site-packages/scipy/special/tests/test_spherical_bessel.py +385 -0
- .venv/Lib/site-packages/scipy/special/tests/test_support_alternative_backends.py +67 -0
- .venv/Lib/site-packages/scipy/special/tests/test_trig.py +72 -0
- .venv/Lib/site-packages/scipy/special/tests/test_wrightomega.py +117 -0
- .venv/Lib/site-packages/torch/lib/cublasLt64_12.dll +3 -0
- .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
|