scipy 1.15.3__cp312-cp312-macosx_12_0_arm64.whl → 1.16.0rc2__cp312-cp312-macosx_12_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- scipy/.dylibs/libscipy_openblas.dylib +0 -0
- scipy/__config__.py +8 -8
- scipy/__init__.py +3 -6
- scipy/_cyutility.cpython-312-darwin.so +0 -0
- scipy/_lib/_array_api.py +486 -161
- scipy/_lib/_array_api_compat_vendor.py +9 -0
- scipy/_lib/_bunch.py +4 -0
- scipy/_lib/_ccallback_c.cpython-312-darwin.so +0 -0
- scipy/_lib/_docscrape.py +1 -1
- scipy/_lib/_elementwise_iterative_method.py +15 -26
- scipy/_lib/_sparse.py +41 -0
- scipy/_lib/_test_deprecation_call.cpython-312-darwin.so +0 -0
- scipy/_lib/_test_deprecation_def.cpython-312-darwin.so +0 -0
- scipy/_lib/_testutils.py +6 -2
- scipy/_lib/_util.py +222 -125
- scipy/_lib/array_api_compat/__init__.py +4 -4
- scipy/_lib/array_api_compat/_internal.py +19 -6
- scipy/_lib/array_api_compat/common/__init__.py +1 -1
- scipy/_lib/array_api_compat/common/_aliases.py +365 -193
- scipy/_lib/array_api_compat/common/_fft.py +94 -64
- scipy/_lib/array_api_compat/common/_helpers.py +413 -180
- scipy/_lib/array_api_compat/common/_linalg.py +116 -40
- scipy/_lib/array_api_compat/common/_typing.py +179 -10
- scipy/_lib/array_api_compat/cupy/__init__.py +1 -4
- scipy/_lib/array_api_compat/cupy/_aliases.py +61 -41
- scipy/_lib/array_api_compat/cupy/_info.py +16 -6
- scipy/_lib/array_api_compat/cupy/_typing.py +24 -39
- scipy/_lib/array_api_compat/dask/array/__init__.py +6 -3
- scipy/_lib/array_api_compat/dask/array/_aliases.py +267 -108
- scipy/_lib/array_api_compat/dask/array/_info.py +105 -34
- scipy/_lib/array_api_compat/dask/array/fft.py +5 -8
- scipy/_lib/array_api_compat/dask/array/linalg.py +21 -22
- scipy/_lib/array_api_compat/numpy/__init__.py +13 -15
- scipy/_lib/array_api_compat/numpy/_aliases.py +98 -49
- scipy/_lib/array_api_compat/numpy/_info.py +36 -16
- scipy/_lib/array_api_compat/numpy/_typing.py +27 -43
- scipy/_lib/array_api_compat/numpy/fft.py +11 -5
- scipy/_lib/array_api_compat/numpy/linalg.py +75 -22
- scipy/_lib/array_api_compat/torch/__init__.py +3 -5
- scipy/_lib/array_api_compat/torch/_aliases.py +262 -159
- scipy/_lib/array_api_compat/torch/_info.py +27 -16
- scipy/_lib/array_api_compat/torch/_typing.py +3 -0
- scipy/_lib/array_api_compat/torch/fft.py +17 -18
- scipy/_lib/array_api_compat/torch/linalg.py +16 -16
- scipy/_lib/array_api_extra/__init__.py +26 -3
- scipy/_lib/array_api_extra/_delegation.py +171 -0
- scipy/_lib/array_api_extra/_lib/__init__.py +1 -0
- scipy/_lib/array_api_extra/_lib/_at.py +463 -0
- scipy/_lib/array_api_extra/_lib/_backends.py +46 -0
- scipy/_lib/array_api_extra/_lib/_funcs.py +937 -0
- scipy/_lib/array_api_extra/_lib/_lazy.py +357 -0
- scipy/_lib/array_api_extra/_lib/_testing.py +278 -0
- scipy/_lib/array_api_extra/_lib/_utils/__init__.py +1 -0
- scipy/_lib/array_api_extra/_lib/_utils/_compat.py +74 -0
- scipy/_lib/array_api_extra/_lib/_utils/_compat.pyi +45 -0
- scipy/_lib/array_api_extra/_lib/_utils/_helpers.py +559 -0
- scipy/_lib/array_api_extra/_lib/_utils/_typing.py +10 -0
- scipy/_lib/array_api_extra/_lib/_utils/_typing.pyi +105 -0
- scipy/_lib/array_api_extra/testing.py +359 -0
- scipy/_lib/decorator.py +2 -2
- scipy/_lib/doccer.py +1 -7
- scipy/_lib/messagestream.cpython-312-darwin.so +0 -0
- scipy/_lib/pyprima/__init__.py +212 -0
- scipy/_lib/pyprima/cobyla/__init__.py +0 -0
- scipy/_lib/pyprima/cobyla/cobyla.py +559 -0
- scipy/_lib/pyprima/cobyla/cobylb.py +714 -0
- scipy/_lib/pyprima/cobyla/geometry.py +226 -0
- scipy/_lib/pyprima/cobyla/initialize.py +215 -0
- scipy/_lib/pyprima/cobyla/trustregion.py +492 -0
- scipy/_lib/pyprima/cobyla/update.py +289 -0
- scipy/_lib/pyprima/common/__init__.py +0 -0
- scipy/_lib/pyprima/common/_bounds.py +34 -0
- scipy/_lib/pyprima/common/_linear_constraints.py +46 -0
- scipy/_lib/pyprima/common/_nonlinear_constraints.py +54 -0
- scipy/_lib/pyprima/common/_project.py +173 -0
- scipy/_lib/pyprima/common/checkbreak.py +93 -0
- scipy/_lib/pyprima/common/consts.py +47 -0
- scipy/_lib/pyprima/common/evaluate.py +99 -0
- scipy/_lib/pyprima/common/history.py +38 -0
- scipy/_lib/pyprima/common/infos.py +30 -0
- scipy/_lib/pyprima/common/linalg.py +435 -0
- scipy/_lib/pyprima/common/message.py +290 -0
- scipy/_lib/pyprima/common/powalg.py +131 -0
- scipy/_lib/pyprima/common/preproc.py +277 -0
- scipy/_lib/pyprima/common/present.py +5 -0
- scipy/_lib/pyprima/common/ratio.py +54 -0
- scipy/_lib/pyprima/common/redrho.py +47 -0
- scipy/_lib/pyprima/common/selectx.py +296 -0
- scipy/_lib/tests/test__util.py +105 -121
- scipy/_lib/tests/test_array_api.py +166 -35
- scipy/_lib/tests/test_bunch.py +7 -0
- scipy/_lib/tests/test_ccallback.py +2 -10
- scipy/_lib/tests/test_public_api.py +13 -0
- scipy/cluster/_hierarchy.cpython-312-darwin.so +0 -0
- scipy/cluster/_optimal_leaf_ordering.cpython-312-darwin.so +0 -0
- scipy/cluster/_vq.cpython-312-darwin.so +0 -0
- scipy/cluster/hierarchy.py +393 -223
- scipy/cluster/tests/test_hierarchy.py +273 -335
- scipy/cluster/tests/test_vq.py +45 -61
- scipy/cluster/vq.py +39 -35
- scipy/conftest.py +263 -157
- scipy/constants/_constants.py +4 -1
- scipy/constants/tests/test_codata.py +2 -2
- scipy/constants/tests/test_constants.py +11 -18
- scipy/datasets/_download_all.py +15 -1
- scipy/datasets/_fetchers.py +7 -1
- scipy/datasets/_utils.py +1 -1
- scipy/differentiate/_differentiate.py +25 -25
- scipy/differentiate/tests/test_differentiate.py +24 -25
- scipy/fft/_basic.py +20 -0
- scipy/fft/_helper.py +3 -34
- scipy/fft/_pocketfft/helper.py +29 -1
- scipy/fft/_pocketfft/tests/test_basic.py +2 -4
- scipy/fft/_pocketfft/tests/test_real_transforms.py +4 -4
- scipy/fft/_realtransforms.py +13 -0
- scipy/fft/tests/test_basic.py +27 -25
- scipy/fft/tests/test_fftlog.py +16 -7
- scipy/fft/tests/test_helper.py +18 -34
- scipy/fft/tests/test_real_transforms.py +8 -10
- scipy/fftpack/convolve.cpython-312-darwin.so +0 -0
- scipy/fftpack/tests/test_basic.py +2 -4
- scipy/fftpack/tests/test_real_transforms.py +8 -9
- scipy/integrate/_bvp.py +9 -3
- scipy/integrate/_cubature.py +3 -2
- scipy/integrate/_dop.cpython-312-darwin.so +0 -0
- scipy/integrate/_lsoda.cpython-312-darwin.so +0 -0
- scipy/integrate/_ode.py +9 -2
- scipy/integrate/_odepack.cpython-312-darwin.so +0 -0
- scipy/integrate/_quad_vec.py +21 -29
- scipy/integrate/_quadpack.cpython-312-darwin.so +0 -0
- scipy/integrate/_quadpack_py.py +11 -7
- scipy/integrate/_quadrature.py +3 -3
- scipy/integrate/_rules/_base.py +2 -2
- scipy/integrate/_tanhsinh.py +48 -47
- scipy/integrate/_test_odeint_banded.cpython-312-darwin.so +0 -0
- scipy/integrate/_vode.cpython-312-darwin.so +0 -0
- scipy/integrate/tests/test__quad_vec.py +0 -6
- scipy/integrate/tests/test_banded_ode_solvers.py +85 -0
- scipy/integrate/tests/test_cubature.py +21 -35
- scipy/integrate/tests/test_quadrature.py +6 -8
- scipy/integrate/tests/test_tanhsinh.py +56 -48
- scipy/interpolate/__init__.py +70 -58
- scipy/interpolate/_bary_rational.py +22 -22
- scipy/interpolate/_bsplines.py +119 -66
- scipy/interpolate/_cubic.py +65 -50
- scipy/interpolate/_dfitpack.cpython-312-darwin.so +0 -0
- scipy/interpolate/_dierckx.cpython-312-darwin.so +0 -0
- scipy/interpolate/_fitpack.cpython-312-darwin.so +0 -0
- scipy/interpolate/_fitpack2.py +9 -6
- scipy/interpolate/_fitpack_impl.py +32 -26
- scipy/interpolate/_fitpack_repro.py +23 -19
- scipy/interpolate/_interpnd.cpython-312-darwin.so +0 -0
- scipy/interpolate/_interpolate.py +30 -12
- scipy/interpolate/_ndbspline.py +13 -18
- scipy/interpolate/_ndgriddata.py +5 -8
- scipy/interpolate/_polyint.py +95 -31
- scipy/interpolate/_ppoly.cpython-312-darwin.so +0 -0
- scipy/interpolate/_rbf.py +2 -2
- scipy/interpolate/_rbfinterp.py +1 -1
- scipy/interpolate/_rbfinterp_pythran.cpython-312-darwin.so +0 -0
- scipy/interpolate/_rgi.py +31 -26
- scipy/interpolate/_rgi_cython.cpython-312-darwin.so +0 -0
- scipy/interpolate/dfitpack.py +0 -20
- scipy/interpolate/interpnd.py +1 -2
- scipy/interpolate/tests/test_bary_rational.py +2 -2
- scipy/interpolate/tests/test_bsplines.py +97 -1
- scipy/interpolate/tests/test_fitpack2.py +39 -1
- scipy/interpolate/tests/test_interpnd.py +32 -20
- scipy/interpolate/tests/test_interpolate.py +48 -4
- scipy/interpolate/tests/test_rgi.py +2 -1
- scipy/io/_fast_matrix_market/__init__.py +2 -0
- scipy/io/_harwell_boeing/_fortran_format_parser.py +19 -16
- scipy/io/_harwell_boeing/hb.py +7 -11
- scipy/io/_idl.py +5 -7
- scipy/io/_netcdf.py +15 -5
- scipy/io/_test_fortran.cpython-312-darwin.so +0 -0
- scipy/io/arff/tests/test_arffread.py +3 -3
- scipy/io/matlab/__init__.py +5 -3
- scipy/io/matlab/_mio.py +4 -1
- scipy/io/matlab/_mio5.py +19 -13
- scipy/io/matlab/_mio5_utils.cpython-312-darwin.so +0 -0
- scipy/io/matlab/_mio_utils.cpython-312-darwin.so +0 -0
- scipy/io/matlab/_miobase.py +4 -1
- scipy/io/matlab/_streams.cpython-312-darwin.so +0 -0
- scipy/io/matlab/tests/test_mio.py +46 -18
- scipy/io/matlab/tests/test_mio_funcs.py +1 -1
- scipy/io/tests/test_mmio.py +7 -1
- scipy/io/tests/test_wavfile.py +41 -0
- scipy/io/wavfile.py +57 -10
- scipy/linalg/_basic.py +113 -86
- scipy/linalg/_cythonized_array_utils.cpython-312-darwin.so +0 -0
- scipy/linalg/_decomp.py +22 -9
- scipy/linalg/_decomp_cholesky.py +28 -13
- scipy/linalg/_decomp_cossin.py +45 -30
- scipy/linalg/_decomp_interpolative.cpython-312-darwin.so +0 -0
- scipy/linalg/_decomp_ldl.py +4 -1
- scipy/linalg/_decomp_lu.py +18 -6
- scipy/linalg/_decomp_lu_cython.cpython-312-darwin.so +0 -0
- scipy/linalg/_decomp_polar.py +2 -0
- scipy/linalg/_decomp_qr.py +6 -2
- scipy/linalg/_decomp_qz.py +3 -0
- scipy/linalg/_decomp_schur.py +3 -1
- scipy/linalg/_decomp_svd.py +13 -2
- scipy/linalg/_decomp_update.cpython-312-darwin.so +0 -0
- scipy/linalg/_expm_frechet.py +4 -0
- scipy/linalg/_fblas.cpython-312-darwin.so +0 -0
- scipy/linalg/_flapack.cpython-312-darwin.so +0 -0
- scipy/linalg/_linalg_pythran.cpython-312-darwin.so +0 -0
- scipy/linalg/_matfuncs.py +187 -4
- scipy/linalg/_matfuncs_expm.cpython-312-darwin.so +0 -0
- scipy/linalg/_matfuncs_schur_sqrtm.cpython-312-darwin.so +0 -0
- scipy/linalg/_matfuncs_sqrtm.py +1 -99
- scipy/linalg/_matfuncs_sqrtm_triu.cpython-312-darwin.so +0 -0
- scipy/linalg/_procrustes.py +2 -0
- scipy/linalg/_sketches.py +17 -6
- scipy/linalg/_solve_toeplitz.cpython-312-darwin.so +0 -0
- scipy/linalg/_solvers.py +7 -2
- scipy/linalg/_special_matrices.py +26 -36
- scipy/linalg/cython_blas.cpython-312-darwin.so +0 -0
- scipy/linalg/cython_lapack.cpython-312-darwin.so +0 -0
- scipy/linalg/lapack.py +22 -2
- scipy/linalg/tests/_cython_examples/meson.build +7 -0
- scipy/linalg/tests/test_basic.py +31 -16
- scipy/linalg/tests/test_batch.py +588 -0
- scipy/linalg/tests/test_cythonized_array_utils.py +0 -2
- scipy/linalg/tests/test_decomp.py +40 -3
- scipy/linalg/tests/test_decomp_cossin.py +14 -0
- scipy/linalg/tests/test_decomp_ldl.py +1 -1
- scipy/linalg/tests/test_lapack.py +115 -7
- scipy/linalg/tests/test_matfuncs.py +157 -102
- scipy/linalg/tests/test_procrustes.py +0 -7
- scipy/linalg/tests/test_solve_toeplitz.py +1 -1
- scipy/linalg/tests/test_special_matrices.py +1 -5
- scipy/ndimage/__init__.py +1 -0
- scipy/ndimage/_cytest.cpython-312-darwin.so +0 -0
- scipy/ndimage/_delegators.py +8 -2
- scipy/ndimage/_filters.py +453 -5
- scipy/ndimage/_interpolation.py +36 -6
- scipy/ndimage/_measurements.py +4 -2
- scipy/ndimage/_morphology.py +5 -0
- scipy/ndimage/_nd_image.cpython-312-darwin.so +0 -0
- scipy/ndimage/_ni_docstrings.py +5 -1
- scipy/ndimage/_ni_label.cpython-312-darwin.so +0 -0
- scipy/ndimage/_ni_support.py +1 -5
- scipy/ndimage/_rank_filter_1d.cpython-312-darwin.so +0 -0
- scipy/ndimage/_support_alternative_backends.py +18 -6
- scipy/ndimage/tests/test_filters.py +370 -259
- scipy/ndimage/tests/test_fourier.py +7 -9
- scipy/ndimage/tests/test_interpolation.py +68 -61
- scipy/ndimage/tests/test_measurements.py +18 -35
- scipy/ndimage/tests/test_morphology.py +143 -131
- scipy/ndimage/tests/test_splines.py +1 -3
- scipy/odr/__odrpack.cpython-312-darwin.so +0 -0
- scipy/optimize/_basinhopping.py +13 -7
- scipy/optimize/_bglu_dense.cpython-312-darwin.so +0 -0
- scipy/optimize/_bracket.py +17 -24
- scipy/optimize/_chandrupatla.py +9 -10
- scipy/optimize/_cobyla_py.py +104 -123
- scipy/optimize/_constraints.py +14 -10
- scipy/optimize/_differentiable_functions.py +371 -230
- scipy/optimize/_differentialevolution.py +4 -3
- scipy/optimize/_direct.cpython-312-darwin.so +0 -0
- scipy/optimize/_dual_annealing.py +1 -1
- scipy/optimize/_elementwise.py +1 -4
- scipy/optimize/_group_columns.cpython-312-darwin.so +0 -0
- scipy/optimize/_lbfgsb.cpython-312-darwin.so +0 -0
- scipy/optimize/_lbfgsb_py.py +57 -16
- scipy/optimize/_linprog_doc.py +2 -2
- scipy/optimize/_linprog_highs.py +2 -2
- scipy/optimize/_linprog_ip.py +25 -10
- scipy/optimize/_linprog_util.py +14 -16
- scipy/optimize/_lsap.cpython-312-darwin.so +0 -0
- scipy/optimize/_lsq/common.py +3 -3
- scipy/optimize/_lsq/dogbox.py +16 -2
- scipy/optimize/_lsq/givens_elimination.cpython-312-darwin.so +0 -0
- scipy/optimize/_lsq/least_squares.py +198 -126
- scipy/optimize/_lsq/lsq_linear.py +6 -6
- scipy/optimize/_lsq/trf.py +35 -8
- scipy/optimize/_milp.py +3 -1
- scipy/optimize/_minimize.py +105 -36
- scipy/optimize/_minpack.cpython-312-darwin.so +0 -0
- scipy/optimize/_minpack_py.py +21 -14
- scipy/optimize/_moduleTNC.cpython-312-darwin.so +0 -0
- scipy/optimize/_nnls.py +20 -21
- scipy/optimize/_nonlin.py +34 -3
- scipy/optimize/_numdiff.py +288 -110
- scipy/optimize/_optimize.py +86 -48
- scipy/optimize/_pava_pybind.cpython-312-darwin.so +0 -0
- scipy/optimize/_remove_redundancy.py +5 -5
- scipy/optimize/_root_scalar.py +1 -1
- scipy/optimize/_shgo.py +6 -0
- scipy/optimize/_shgo_lib/_complex.py +1 -1
- scipy/optimize/_slsqp_py.py +216 -124
- scipy/optimize/_slsqplib.cpython-312-darwin.so +0 -0
- scipy/optimize/_spectral.py +1 -1
- scipy/optimize/_tnc.py +8 -1
- scipy/optimize/_trlib/_trlib.cpython-312-darwin.so +0 -0
- scipy/optimize/_trustregion.py +20 -6
- scipy/optimize/_trustregion_constr/canonical_constraint.py +7 -7
- scipy/optimize/_trustregion_constr/equality_constrained_sqp.py +1 -1
- scipy/optimize/_trustregion_constr/minimize_trustregion_constr.py +11 -3
- scipy/optimize/_trustregion_constr/projections.py +12 -8
- scipy/optimize/_trustregion_constr/qp_subproblem.py +9 -9
- scipy/optimize/_trustregion_constr/tests/test_projections.py +7 -7
- scipy/optimize/_trustregion_constr/tests/test_qp_subproblem.py +77 -77
- scipy/optimize/_trustregion_constr/tr_interior_point.py +5 -5
- scipy/optimize/_trustregion_exact.py +0 -1
- scipy/optimize/_zeros.cpython-312-darwin.so +0 -0
- scipy/optimize/_zeros_py.py +97 -17
- scipy/optimize/cython_optimize/_zeros.cpython-312-darwin.so +0 -0
- scipy/optimize/slsqp.py +0 -1
- scipy/optimize/tests/test__basinhopping.py +1 -1
- scipy/optimize/tests/test__differential_evolution.py +4 -4
- scipy/optimize/tests/test__linprog_clean_inputs.py +5 -3
- scipy/optimize/tests/test__numdiff.py +66 -22
- scipy/optimize/tests/test__remove_redundancy.py +2 -2
- scipy/optimize/tests/test__shgo.py +9 -1
- scipy/optimize/tests/test_bracket.py +36 -46
- scipy/optimize/tests/test_chandrupatla.py +133 -135
- scipy/optimize/tests/test_cobyla.py +74 -45
- scipy/optimize/tests/test_constraints.py +1 -1
- scipy/optimize/tests/test_differentiable_functions.py +226 -6
- scipy/optimize/tests/test_lbfgsb_hessinv.py +22 -0
- scipy/optimize/tests/test_least_squares.py +125 -13
- scipy/optimize/tests/test_linear_assignment.py +3 -3
- scipy/optimize/tests/test_linprog.py +3 -3
- scipy/optimize/tests/test_lsq_linear.py +6 -6
- scipy/optimize/tests/test_minimize_constrained.py +2 -2
- scipy/optimize/tests/test_minpack.py +4 -4
- scipy/optimize/tests/test_nnls.py +43 -3
- scipy/optimize/tests/test_nonlin.py +36 -0
- scipy/optimize/tests/test_optimize.py +95 -17
- scipy/optimize/tests/test_slsqp.py +36 -4
- scipy/optimize/tests/test_zeros.py +34 -1
- scipy/signal/__init__.py +12 -23
- scipy/signal/_delegators.py +568 -0
- scipy/signal/_filter_design.py +459 -241
- scipy/signal/_fir_filter_design.py +262 -90
- scipy/signal/_lti_conversion.py +3 -2
- scipy/signal/_ltisys.py +118 -91
- scipy/signal/_max_len_seq_inner.cpython-312-darwin.so +0 -0
- scipy/signal/_peak_finding_utils.cpython-312-darwin.so +0 -0
- scipy/signal/_polyutils.py +172 -0
- scipy/signal/_short_time_fft.py +519 -70
- scipy/signal/_signal_api.py +30 -0
- scipy/signal/_signaltools.py +719 -399
- scipy/signal/_sigtools.cpython-312-darwin.so +0 -0
- scipy/signal/_sosfilt.cpython-312-darwin.so +0 -0
- scipy/signal/_spectral_py.py +230 -50
- scipy/signal/_spline.cpython-312-darwin.so +0 -0
- scipy/signal/_spline_filters.py +108 -68
- scipy/signal/_support_alternative_backends.py +73 -0
- scipy/signal/_upfirdn.py +4 -1
- scipy/signal/_upfirdn_apply.cpython-312-darwin.so +0 -0
- scipy/signal/_waveforms.py +2 -11
- scipy/signal/_wavelets.py +1 -1
- scipy/signal/fir_filter_design.py +1 -0
- scipy/signal/spline.py +4 -11
- scipy/signal/tests/_scipy_spectral_test_shim.py +2 -171
- scipy/signal/tests/test_bsplines.py +114 -79
- scipy/signal/tests/test_cont2discrete.py +9 -2
- scipy/signal/tests/test_filter_design.py +721 -481
- scipy/signal/tests/test_fir_filter_design.py +332 -140
- scipy/signal/tests/test_savitzky_golay.py +4 -3
- scipy/signal/tests/test_short_time_fft.py +221 -3
- scipy/signal/tests/test_signaltools.py +2144 -1348
- scipy/signal/tests/test_spectral.py +50 -6
- scipy/signal/tests/test_splines.py +161 -96
- scipy/signal/tests/test_upfirdn.py +84 -50
- scipy/signal/tests/test_waveforms.py +20 -0
- scipy/signal/tests/test_windows.py +607 -466
- scipy/signal/windows/_windows.py +287 -148
- scipy/sparse/__init__.py +23 -4
- scipy/sparse/_base.py +270 -108
- scipy/sparse/_bsr.py +7 -4
- scipy/sparse/_compressed.py +59 -231
- scipy/sparse/_construct.py +90 -38
- scipy/sparse/_coo.py +115 -181
- scipy/sparse/_csc.py +4 -4
- scipy/sparse/_csparsetools.cpython-312-darwin.so +0 -0
- scipy/sparse/_csr.py +2 -2
- scipy/sparse/_data.py +48 -48
- scipy/sparse/_dia.py +105 -18
- scipy/sparse/_dok.py +0 -23
- scipy/sparse/_index.py +4 -4
- scipy/sparse/_matrix.py +23 -0
- scipy/sparse/_sparsetools.cpython-312-darwin.so +0 -0
- scipy/sparse/_sputils.py +37 -22
- scipy/sparse/base.py +0 -9
- scipy/sparse/bsr.py +0 -14
- scipy/sparse/compressed.py +0 -23
- scipy/sparse/construct.py +0 -6
- scipy/sparse/coo.py +0 -14
- scipy/sparse/csc.py +0 -3
- scipy/sparse/csgraph/_flow.cpython-312-darwin.so +0 -0
- scipy/sparse/csgraph/_matching.cpython-312-darwin.so +0 -0
- scipy/sparse/csgraph/_min_spanning_tree.cpython-312-darwin.so +0 -0
- scipy/sparse/csgraph/_reordering.cpython-312-darwin.so +0 -0
- scipy/sparse/csgraph/_shortest_path.cpython-312-darwin.so +0 -0
- scipy/sparse/csgraph/_tools.cpython-312-darwin.so +0 -0
- scipy/sparse/csgraph/_traversal.cpython-312-darwin.so +0 -0
- scipy/sparse/csgraph/tests/test_matching.py +14 -2
- scipy/sparse/csgraph/tests/test_pydata_sparse.py +4 -1
- scipy/sparse/csgraph/tests/test_shortest_path.py +83 -27
- scipy/sparse/csr.py +0 -5
- scipy/sparse/data.py +1 -6
- scipy/sparse/dia.py +0 -7
- scipy/sparse/dok.py +0 -10
- scipy/sparse/linalg/_dsolve/_superlu.cpython-312-darwin.so +0 -0
- scipy/sparse/linalg/_dsolve/linsolve.py +9 -0
- scipy/sparse/linalg/_dsolve/tests/test_linsolve.py +35 -28
- scipy/sparse/linalg/_eigen/arpack/_arpack.cpython-312-darwin.so +0 -0
- scipy/sparse/linalg/_eigen/arpack/arpack.py +23 -17
- scipy/sparse/linalg/_eigen/lobpcg/lobpcg.py +6 -6
- scipy/sparse/linalg/_interface.py +17 -18
- scipy/sparse/linalg/_isolve/_gcrotmk.py +4 -4
- scipy/sparse/linalg/_isolve/iterative.py +51 -45
- scipy/sparse/linalg/_isolve/lgmres.py +6 -6
- scipy/sparse/linalg/_isolve/minres.py +5 -5
- scipy/sparse/linalg/_isolve/tfqmr.py +7 -7
- scipy/sparse/linalg/_isolve/utils.py +2 -8
- scipy/sparse/linalg/_matfuncs.py +1 -1
- scipy/sparse/linalg/_norm.py +1 -1
- scipy/sparse/linalg/_propack/_cpropack.cpython-312-darwin.so +0 -0
- scipy/sparse/linalg/_propack/_dpropack.cpython-312-darwin.so +0 -0
- scipy/sparse/linalg/_propack/_spropack.cpython-312-darwin.so +0 -0
- scipy/sparse/linalg/_propack/_zpropack.cpython-312-darwin.so +0 -0
- scipy/sparse/linalg/_special_sparse_arrays.py +39 -38
- scipy/sparse/linalg/tests/test_pydata_sparse.py +14 -0
- scipy/sparse/tests/test_arithmetic1d.py +5 -2
- scipy/sparse/tests/test_base.py +214 -42
- scipy/sparse/tests/test_common1d.py +7 -7
- scipy/sparse/tests/test_construct.py +1 -1
- scipy/sparse/tests/test_coo.py +272 -4
- scipy/sparse/tests/test_sparsetools.py +5 -0
- scipy/sparse/tests/test_sputils.py +36 -7
- scipy/spatial/_ckdtree.cpython-312-darwin.so +0 -0
- scipy/spatial/_distance_pybind.cpython-312-darwin.so +0 -0
- scipy/spatial/_distance_wrap.cpython-312-darwin.so +0 -0
- scipy/spatial/_hausdorff.cpython-312-darwin.so +0 -0
- scipy/spatial/_qhull.cpython-312-darwin.so +0 -0
- scipy/spatial/_voronoi.cpython-312-darwin.so +0 -0
- scipy/spatial/distance.py +49 -42
- scipy/spatial/tests/test_distance.py +15 -1
- scipy/spatial/tests/test_kdtree.py +1 -0
- scipy/spatial/tests/test_qhull.py +7 -2
- scipy/spatial/transform/__init__.py +5 -3
- scipy/spatial/transform/_rigid_transform.cpython-312-darwin.so +0 -0
- scipy/spatial/transform/_rotation.cpython-312-darwin.so +0 -0
- scipy/spatial/transform/tests/test_rigid_transform.py +1221 -0
- scipy/spatial/transform/tests/test_rotation.py +1213 -832
- scipy/spatial/transform/tests/test_rotation_groups.py +3 -3
- scipy/spatial/transform/tests/test_rotation_spline.py +29 -8
- scipy/special/__init__.py +1 -47
- scipy/special/_add_newdocs.py +34 -772
- scipy/special/_basic.py +22 -25
- scipy/special/_comb.cpython-312-darwin.so +0 -0
- scipy/special/_ellip_harm_2.cpython-312-darwin.so +0 -0
- scipy/special/_gufuncs.cpython-312-darwin.so +0 -0
- scipy/special/_logsumexp.py +67 -58
- scipy/special/_orthogonal.pyi +1 -1
- scipy/special/_specfun.cpython-312-darwin.so +0 -0
- scipy/special/_special_ufuncs.cpython-312-darwin.so +0 -0
- scipy/special/_spherical_bessel.py +4 -4
- scipy/special/_support_alternative_backends.py +212 -119
- scipy/special/_test_internal.cpython-312-darwin.so +0 -0
- scipy/special/_testutils.py +4 -4
- scipy/special/_ufuncs.cpython-312-darwin.so +0 -0
- scipy/special/_ufuncs.pyi +1 -0
- scipy/special/_ufuncs.pyx +215 -1400
- scipy/special/_ufuncs_cxx.cpython-312-darwin.so +0 -0
- scipy/special/_ufuncs_cxx.pxd +2 -15
- scipy/special/_ufuncs_cxx.pyx +5 -44
- scipy/special/_ufuncs_cxx_defs.h +2 -16
- scipy/special/_ufuncs_defs.h +0 -8
- scipy/special/cython_special.cpython-312-darwin.so +0 -0
- scipy/special/cython_special.pxd +1 -1
- scipy/special/tests/_cython_examples/meson.build +10 -1
- scipy/special/tests/test_basic.py +153 -20
- scipy/special/tests/test_boost_ufuncs.py +3 -0
- scipy/special/tests/test_cdflib.py +35 -11
- scipy/special/tests/test_gammainc.py +16 -0
- scipy/special/tests/test_hyp2f1.py +2 -2
- scipy/special/tests/test_log1mexp.py +85 -0
- scipy/special/tests/test_logsumexp.py +206 -64
- scipy/special/tests/test_mpmath.py +1 -0
- scipy/special/tests/test_nan_inputs.py +1 -1
- scipy/special/tests/test_orthogonal.py +17 -18
- scipy/special/tests/test_sf_error.py +3 -2
- scipy/special/tests/test_sph_harm.py +6 -7
- scipy/special/tests/test_support_alternative_backends.py +211 -76
- scipy/stats/__init__.py +4 -1
- scipy/stats/_ansari_swilk_statistics.cpython-312-darwin.so +0 -0
- scipy/stats/_axis_nan_policy.py +5 -12
- scipy/stats/_biasedurn.cpython-312-darwin.so +0 -0
- scipy/stats/_continued_fraction.py +387 -0
- scipy/stats/_continuous_distns.py +277 -310
- scipy/stats/_correlation.py +1 -1
- scipy/stats/_covariance.py +6 -3
- scipy/stats/_discrete_distns.py +39 -32
- scipy/stats/_distn_infrastructure.py +39 -12
- scipy/stats/_distribution_infrastructure.py +900 -238
- scipy/stats/_entropy.py +9 -10
- scipy/{_lib → stats}/_finite_differences.py +1 -1
- scipy/stats/_hypotests.py +83 -50
- scipy/stats/_kde.py +53 -49
- scipy/stats/_ksstats.py +1 -1
- scipy/stats/_levy_stable/__init__.py +7 -15
- scipy/stats/_levy_stable/levyst.cpython-312-darwin.so +0 -0
- scipy/stats/_morestats.py +118 -73
- scipy/stats/_mstats_basic.py +13 -17
- scipy/stats/_mstats_extras.py +8 -8
- scipy/stats/_multivariate.py +89 -113
- scipy/stats/_new_distributions.py +97 -20
- scipy/stats/_page_trend_test.py +12 -5
- scipy/stats/_probability_distribution.py +265 -43
- scipy/stats/_qmc.py +14 -9
- scipy/stats/_qmc_cy.cpython-312-darwin.so +0 -0
- scipy/stats/_qmvnt.py +16 -95
- scipy/stats/_qmvnt_cy.cpython-312-darwin.so +0 -0
- scipy/stats/_quantile.py +335 -0
- scipy/stats/_rcont/rcont.cpython-312-darwin.so +0 -0
- scipy/stats/_resampling.py +4 -29
- scipy/stats/_sampling.py +1 -1
- scipy/stats/_sobol.cpython-312-darwin.so +0 -0
- scipy/stats/_stats.cpython-312-darwin.so +0 -0
- scipy/stats/_stats_mstats_common.py +21 -2
- scipy/stats/_stats_py.py +550 -476
- scipy/stats/_stats_pythran.cpython-312-darwin.so +0 -0
- scipy/stats/_unuran/unuran_wrapper.cpython-312-darwin.so +0 -0
- scipy/stats/_unuran/unuran_wrapper.pyi +2 -1
- scipy/stats/_variation.py +6 -8
- scipy/stats/_wilcoxon.py +13 -7
- scipy/stats/tests/common_tests.py +6 -4
- scipy/stats/tests/test_axis_nan_policy.py +62 -24
- scipy/stats/tests/test_continued_fraction.py +173 -0
- scipy/stats/tests/test_continuous.py +379 -60
- scipy/stats/tests/test_continuous_basic.py +18 -12
- scipy/stats/tests/test_discrete_basic.py +14 -8
- scipy/stats/tests/test_discrete_distns.py +16 -16
- scipy/stats/tests/test_distributions.py +95 -75
- scipy/stats/tests/test_entropy.py +40 -48
- scipy/stats/tests/test_fit.py +4 -3
- scipy/stats/tests/test_hypotests.py +153 -24
- scipy/stats/tests/test_kdeoth.py +109 -41
- scipy/stats/tests/test_marray.py +289 -0
- scipy/stats/tests/test_morestats.py +79 -47
- scipy/stats/tests/test_mstats_basic.py +3 -3
- scipy/stats/tests/test_multivariate.py +434 -83
- scipy/stats/tests/test_qmc.py +13 -10
- scipy/stats/tests/test_quantile.py +199 -0
- scipy/stats/tests/test_rank.py +119 -112
- scipy/stats/tests/test_resampling.py +47 -56
- scipy/stats/tests/test_sampling.py +9 -4
- scipy/stats/tests/test_stats.py +799 -939
- scipy/stats/tests/test_variation.py +8 -6
- scipy/version.py +2 -2
- {scipy-1.15.3.dist-info → scipy-1.16.0rc2.dist-info}/LICENSE.txt +4 -4
- {scipy-1.15.3.dist-info → scipy-1.16.0rc2.dist-info}/METADATA +11 -11
- {scipy-1.15.3.dist-info → scipy-1.16.0rc2.dist-info}/RECORD +561 -568
- scipy-1.16.0rc2.dist-info/WHEEL +6 -0
- scipy/_lib/array_api_extra/_funcs.py +0 -484
- scipy/_lib/array_api_extra/_typing.py +0 -8
- scipy/interpolate/_bspl.cpython-312-darwin.so +0 -0
- scipy/optimize/_cobyla.cpython-312-darwin.so +0 -0
- scipy/optimize/_cython_nnls.cpython-312-darwin.so +0 -0
- scipy/optimize/_slsqp.cpython-312-darwin.so +0 -0
- scipy/spatial/qhull_src/COPYING.txt +0 -38
- scipy/special/libsf_error_state.dylib +0 -0
- scipy/special/tests/test_log_softmax.py +0 -109
- scipy/special/tests/test_xsf_cuda.py +0 -114
- scipy/special/xsf/binom.h +0 -89
- scipy/special/xsf/cdflib.h +0 -100
- scipy/special/xsf/cephes/airy.h +0 -307
- scipy/special/xsf/cephes/besselpoly.h +0 -51
- scipy/special/xsf/cephes/beta.h +0 -257
- scipy/special/xsf/cephes/cbrt.h +0 -131
- scipy/special/xsf/cephes/chbevl.h +0 -85
- scipy/special/xsf/cephes/chdtr.h +0 -193
- scipy/special/xsf/cephes/const.h +0 -87
- scipy/special/xsf/cephes/ellie.h +0 -293
- scipy/special/xsf/cephes/ellik.h +0 -251
- scipy/special/xsf/cephes/ellpe.h +0 -107
- scipy/special/xsf/cephes/ellpk.h +0 -117
- scipy/special/xsf/cephes/expn.h +0 -260
- scipy/special/xsf/cephes/gamma.h +0 -398
- scipy/special/xsf/cephes/hyp2f1.h +0 -596
- scipy/special/xsf/cephes/hyperg.h +0 -361
- scipy/special/xsf/cephes/i0.h +0 -149
- scipy/special/xsf/cephes/i1.h +0 -158
- scipy/special/xsf/cephes/igam.h +0 -421
- scipy/special/xsf/cephes/igam_asymp_coeff.h +0 -195
- scipy/special/xsf/cephes/igami.h +0 -313
- scipy/special/xsf/cephes/j0.h +0 -225
- scipy/special/xsf/cephes/j1.h +0 -198
- scipy/special/xsf/cephes/jv.h +0 -715
- scipy/special/xsf/cephes/k0.h +0 -164
- scipy/special/xsf/cephes/k1.h +0 -163
- scipy/special/xsf/cephes/kn.h +0 -243
- scipy/special/xsf/cephes/lanczos.h +0 -112
- scipy/special/xsf/cephes/ndtr.h +0 -275
- scipy/special/xsf/cephes/poch.h +0 -85
- scipy/special/xsf/cephes/polevl.h +0 -167
- scipy/special/xsf/cephes/psi.h +0 -194
- scipy/special/xsf/cephes/rgamma.h +0 -111
- scipy/special/xsf/cephes/scipy_iv.h +0 -811
- scipy/special/xsf/cephes/shichi.h +0 -248
- scipy/special/xsf/cephes/sici.h +0 -224
- scipy/special/xsf/cephes/sindg.h +0 -221
- scipy/special/xsf/cephes/tandg.h +0 -139
- scipy/special/xsf/cephes/trig.h +0 -58
- scipy/special/xsf/cephes/unity.h +0 -186
- scipy/special/xsf/cephes/zeta.h +0 -172
- scipy/special/xsf/config.h +0 -304
- scipy/special/xsf/digamma.h +0 -205
- scipy/special/xsf/error.h +0 -57
- scipy/special/xsf/evalpoly.h +0 -47
- scipy/special/xsf/expint.h +0 -266
- scipy/special/xsf/hyp2f1.h +0 -694
- scipy/special/xsf/iv_ratio.h +0 -173
- scipy/special/xsf/lambertw.h +0 -150
- scipy/special/xsf/loggamma.h +0 -163
- scipy/special/xsf/sici.h +0 -200
- scipy/special/xsf/tools.h +0 -427
- scipy/special/xsf/trig.h +0 -164
- scipy/special/xsf/wright_bessel.h +0 -843
- scipy/special/xsf/zlog1.h +0 -35
- scipy/stats/_mvn.cpython-312-darwin.so +0 -0
- scipy-1.15.3.dist-info/WHEEL +0 -4
@@ -1,3 +1,4 @@
|
|
1
|
+
import itertools as it
|
1
2
|
import os
|
2
3
|
import pickle
|
3
4
|
from copy import deepcopy
|
@@ -9,24 +10,26 @@ from numpy.testing import assert_allclose, assert_equal
|
|
9
10
|
from hypothesis import strategies, given, reproduce_failure, settings # noqa: F401
|
10
11
|
import hypothesis.extra.numpy as npst
|
11
12
|
|
13
|
+
from scipy import special
|
12
14
|
from scipy import stats
|
13
15
|
from scipy.stats._fit import _kolmogorov_smirnov
|
14
16
|
from scipy.stats._ksstats import kolmogn
|
15
17
|
from scipy.stats import qmc
|
16
|
-
from scipy.stats._distr_params import distcont
|
18
|
+
from scipy.stats._distr_params import distcont, distdiscrete
|
17
19
|
from scipy.stats._distribution_infrastructure import (
|
18
|
-
_Domain,
|
20
|
+
_Domain, _RealInterval, _Parameter, _Parameterization, _RealParameter,
|
19
21
|
ContinuousDistribution, ShiftedScaledDistribution, _fiinfo,
|
20
22
|
_generate_domain_support, Mixture)
|
21
23
|
from scipy.stats._new_distributions import StandardNormal, _LogUniform, _Gamma
|
22
|
-
from scipy.stats import
|
24
|
+
from scipy.stats._new_distributions import DiscreteDistribution
|
25
|
+
from scipy.stats import Normal, Uniform, Binomial
|
23
26
|
|
24
27
|
|
25
|
-
class
|
28
|
+
class Test_RealInterval:
|
26
29
|
rng = np.random.default_rng(349849812549824)
|
27
30
|
|
28
31
|
def test_iv(self):
|
29
|
-
domain =
|
32
|
+
domain = _RealInterval(endpoints=('a', 'b'))
|
30
33
|
message = "The endpoints of the distribution are defined..."
|
31
34
|
with pytest.raises(TypeError, match=message):
|
32
35
|
domain.get_numerical_endpoints(dict)
|
@@ -37,7 +40,7 @@ class Test_RealDomain:
|
|
37
40
|
def test_contains_simple(self, x):
|
38
41
|
# Test `contains` when endpoints are defined by constants
|
39
42
|
a, b = -np.inf, np.pi
|
40
|
-
domain =
|
43
|
+
domain = _RealInterval(endpoints=(a, b), inclusive=(False, True))
|
41
44
|
assert_equal(domain.contains(x), (a < x) & (x <= b))
|
42
45
|
|
43
46
|
@pytest.mark.slow
|
@@ -45,6 +48,7 @@ class Test_RealDomain:
|
|
45
48
|
inclusive_a=strategies.booleans(),
|
46
49
|
inclusive_b=strategies.booleans(),
|
47
50
|
data=strategies.data())
|
51
|
+
@pytest.mark.thread_unsafe
|
48
52
|
def test_contains(self, shapes, inclusive_a, inclusive_b, data):
|
49
53
|
# Test `contains` when endpoints are defined by parameters
|
50
54
|
input_shapes, result_shape = shapes
|
@@ -67,10 +71,10 @@ class Test_RealDomain:
|
|
67
71
|
np.linspace(a, b, 10),
|
68
72
|
np.linspace(b, b+d, 10)])
|
69
73
|
# Domain is defined by two parameters, 'a' and 'b'
|
70
|
-
domain =
|
74
|
+
domain = _RealInterval(endpoints=('a', 'b'),
|
71
75
|
inclusive=(inclusive_a, inclusive_b))
|
72
|
-
domain.define_parameters(_RealParameter('a', domain=
|
73
|
-
_RealParameter('b', domain=
|
76
|
+
domain.define_parameters(_RealParameter('a', domain=_RealInterval()),
|
77
|
+
_RealParameter('b', domain=_RealInterval()))
|
74
78
|
# Check that domain and string evaluation give the same result
|
75
79
|
res = domain.contains(x, dict(a=a, b=b))
|
76
80
|
|
@@ -85,12 +89,31 @@ class Test_RealDomain:
|
|
85
89
|
ref = eval(f'(a {left_comparison} x) & (x {right_comparison} b)')
|
86
90
|
assert_equal(res, ref)
|
87
91
|
|
92
|
+
@pytest.mark.parametrize("inclusive", list(it.product([True, False], repeat=2)))
|
93
|
+
@pytest.mark.parametrize("a,b", [(0, 1), (3, 1)])
|
94
|
+
def test_contains_function_endpoints(self, inclusive, a, b):
|
95
|
+
# Test `contains` when endpoints are defined by functions.
|
96
|
+
endpoints = (lambda a, b: (a - b) / 2, lambda a, b: (a + b) / 2)
|
97
|
+
domain = _RealInterval(endpoints=endpoints, inclusive=inclusive)
|
98
|
+
x = np.asarray([(a - 2*b)/2, (a - b)/2, a/2, (a + b)/2, (a + 2*b)/2])
|
99
|
+
res = domain.contains(x, dict(a=a, b=b))
|
100
|
+
|
101
|
+
numerical_endpoints = ((a - b) / 2, (a + b) / 2)
|
102
|
+
assert numerical_endpoints == domain.get_numerical_endpoints(dict(a=a, b=b))
|
103
|
+
alpha, beta = numerical_endpoints
|
104
|
+
|
105
|
+
above_left = alpha <= x if inclusive[0] else alpha < x
|
106
|
+
below_right = x <= beta if inclusive[1] else x < beta
|
107
|
+
ref = above_left & below_right
|
108
|
+
assert_equal(res, ref)
|
109
|
+
|
110
|
+
|
88
111
|
@pytest.mark.parametrize('case', [
|
89
112
|
(-np.inf, np.pi, False, True, r"(-\infty, \pi]"),
|
90
113
|
('a', 5, True, False, "[a, 5)")
|
91
114
|
])
|
92
115
|
def test_str(self, case):
|
93
|
-
domain =
|
116
|
+
domain = _RealInterval(endpoints=case[:2], inclusive=case[2:4])
|
94
117
|
assert str(domain) == case[4]
|
95
118
|
|
96
119
|
@pytest.mark.slow
|
@@ -105,6 +128,7 @@ class Test_RealDomain:
|
|
105
128
|
inclusive_a=strategies.booleans(),
|
106
129
|
inclusive_b=strategies.booleans(),
|
107
130
|
)
|
131
|
+
@pytest.mark.thread_unsafe
|
108
132
|
def test_str2(self, a, b, inclusive_a, inclusive_b):
|
109
133
|
# I wrote this independently from the implementation of __str__, but
|
110
134
|
# I imagine it looks pretty similar to __str__.
|
@@ -112,7 +136,7 @@ class Test_RealDomain:
|
|
112
136
|
b = _Domain.symbols.get(b, b)
|
113
137
|
left_bracket = '[' if inclusive_a else '('
|
114
138
|
right_bracket = ']' if inclusive_b else ')'
|
115
|
-
domain =
|
139
|
+
domain = _RealInterval(endpoints=(a, b),
|
116
140
|
inclusive=(inclusive_a, inclusive_b))
|
117
141
|
ref = f"{left_bracket}{a}, {b}{right_bracket}"
|
118
142
|
assert str(domain) == ref
|
@@ -120,8 +144,8 @@ class Test_RealDomain:
|
|
120
144
|
def test_symbols_gh22137(self):
|
121
145
|
# `symbols` was accidentally shared between instances originally
|
122
146
|
# Check that this is no longer the case
|
123
|
-
domain1 =
|
124
|
-
domain2 =
|
147
|
+
domain1 = _RealInterval(endpoints=(0, 1))
|
148
|
+
domain2 = _RealInterval(endpoints=(0, 1))
|
125
149
|
assert domain1.symbols is not domain2.symbols
|
126
150
|
|
127
151
|
|
@@ -153,7 +177,7 @@ def draw_distribution_from_family(family, data, rng, proportions, min_side=0):
|
|
153
177
|
y = dist._variable.draw(y_shape, parameter_values=dist._parameters,
|
154
178
|
proportions=proportions, rng=rng, region='typical')
|
155
179
|
xy_result_shape = np.broadcast_shapes(y_shape, x_result_shape)
|
156
|
-
p_domain =
|
180
|
+
p_domain = _RealInterval((0, 1), (True, True))
|
157
181
|
p_var = _RealParameter('p', domain=p_domain)
|
158
182
|
p = p_var.draw(x_shape, proportions=proportions, rng=rng)
|
159
183
|
with np.errstate(divide='ignore', invalid='ignore'):
|
@@ -162,19 +186,26 @@ def draw_distribution_from_family(family, data, rng, proportions, min_side=0):
|
|
162
186
|
return dist, x, y, p, logp, result_shape, x_result_shape, xy_result_shape
|
163
187
|
|
164
188
|
|
165
|
-
|
189
|
+
continuous_families = [
|
166
190
|
StandardNormal,
|
167
191
|
Normal,
|
168
192
|
Uniform,
|
169
193
|
_LogUniform
|
170
194
|
]
|
171
195
|
|
196
|
+
discrete_families = [
|
197
|
+
Binomial,
|
198
|
+
]
|
199
|
+
|
200
|
+
families = continuous_families + discrete_families
|
201
|
+
|
172
202
|
|
173
203
|
class TestDistributions:
|
174
204
|
@pytest.mark.fail_slow(60) # need to break up check_moment_funcs
|
175
205
|
@settings(max_examples=20)
|
176
206
|
@pytest.mark.parametrize('family', families)
|
177
207
|
@given(data=strategies.data(), seed=strategies.integers(min_value=0))
|
208
|
+
@pytest.mark.thread_unsafe
|
178
209
|
def test_support_moments_sample(self, family, data, seed):
|
179
210
|
rng = np.random.default_rng(seed)
|
180
211
|
|
@@ -214,6 +245,7 @@ class TestDistributions:
|
|
214
245
|
])
|
215
246
|
@settings(max_examples=20)
|
216
247
|
@given(data=strategies.data(), seed=strategies.integers(min_value=0))
|
248
|
+
@pytest.mark.thread_unsafe
|
217
249
|
def test_funcs(self, family, data, seed, func, methods, arg):
|
218
250
|
if family == Uniform and func == 'mode':
|
219
251
|
pytest.skip("Mode is not unique; `method`s disagree.")
|
@@ -247,6 +279,7 @@ class TestDistributions:
|
|
247
279
|
check_ccdf2(dist, False, x, y, xy_result_shape, methods)
|
248
280
|
check_ccdf2(dist, True, x, y, xy_result_shape, methods)
|
249
281
|
|
282
|
+
@pytest.mark.thread_unsafe
|
250
283
|
def test_plot(self):
|
251
284
|
try:
|
252
285
|
import matplotlib.pyplot as plt
|
@@ -300,6 +333,8 @@ class TestDistributions:
|
|
300
333
|
# Safe subtraction is needed in special cases
|
301
334
|
x = np.asarray([-1e-20, -1e-21, 1e-20, 1e-21, -1e-20])
|
302
335
|
y = np.asarray([-1e-21, -1e-20, 1e-21, 1e-20, 1e-20])
|
336
|
+
|
337
|
+
|
303
338
|
p0 = X.pdf(0)*(y-x)
|
304
339
|
p1 = X.cdf(x, y, method='subtraction_safe')
|
305
340
|
p2 = X.cdf(x, y, method='subtraction')
|
@@ -385,7 +420,11 @@ def check_sample_shape_NaNs(dist, fname, sample_shape, result_shape, rng):
|
|
385
420
|
|
386
421
|
sample1 = sample_method(sample_shape, method=method, rng=42)
|
387
422
|
sample2 = sample_method(sample_shape, method=method, rng=42)
|
388
|
-
|
423
|
+
if not isinstance(dist, DiscreteDistribution):
|
424
|
+
# The idea is that it's very unlikely that the random sample
|
425
|
+
# for a randomly chosen seed will match that for seed 42,
|
426
|
+
# but it is not so unlikely if `dist` is a discrete distribution.
|
427
|
+
assert not np.any(np.equal(res, sample1))
|
389
428
|
assert_equal(sample1, sample2)
|
390
429
|
|
391
430
|
|
@@ -485,6 +524,13 @@ def check_cdf2(dist, log, x, y, result_shape, methods):
|
|
485
524
|
assert np.isscalar(ref)
|
486
525
|
|
487
526
|
for method in methods:
|
527
|
+
if isinstance(dist, DiscreteDistribution):
|
528
|
+
message = ("Two argument cdf functions are currently only supported for "
|
529
|
+
"continuous distributions.")
|
530
|
+
with pytest.raises(NotImplementedError, match=message):
|
531
|
+
res = (np.exp(dist.logcdf(x, y, method=method)) if log
|
532
|
+
else dist.cdf(x, y, method=method))
|
533
|
+
continue
|
488
534
|
res = (np.exp(dist.logcdf(x, y, method=method)) if log
|
489
535
|
else dist.cdf(x, y, method=method))
|
490
536
|
np.testing.assert_allclose(res, ref, atol=1e-14)
|
@@ -513,6 +559,13 @@ def check_ccdf2(dist, log, x, y, result_shape, methods):
|
|
513
559
|
assert np.isscalar(ref)
|
514
560
|
|
515
561
|
for method in methods:
|
562
|
+
message = ("Two argument cdf functions are currently only supported for "
|
563
|
+
"continuous distributions.")
|
564
|
+
if isinstance(dist, DiscreteDistribution):
|
565
|
+
with pytest.raises(NotImplementedError, match=message):
|
566
|
+
res = (np.exp(dist.logccdf(x, y, method=method)) if log
|
567
|
+
else dist.ccdf(x, y, method=method))
|
568
|
+
continue
|
516
569
|
res = (np.exp(dist.logccdf(x, y, method=method)) if log
|
517
570
|
else dist.ccdf(x, y, method=method))
|
518
571
|
np.testing.assert_allclose(res, ref, atol=1e-14)
|
@@ -526,9 +579,9 @@ def check_nans_and_edges(dist, fname, arg, res):
|
|
526
579
|
|
527
580
|
valid_parameters = get_valid_parameters(dist)
|
528
581
|
if fname in {'icdf', 'iccdf'}:
|
529
|
-
arg_domain =
|
582
|
+
arg_domain = _RealInterval(endpoints=(0, 1), inclusive=(True, True))
|
530
583
|
elif fname in {'ilogcdf', 'ilogccdf'}:
|
531
|
-
arg_domain =
|
584
|
+
arg_domain = _RealInterval(endpoints=(-inf, 0), inclusive=(True, True))
|
532
585
|
else:
|
533
586
|
arg_domain = dist._variable.domain
|
534
587
|
|
@@ -550,50 +603,65 @@ def check_nans_and_edges(dist, fname, arg, res):
|
|
550
603
|
outside_arg_plus = (outside_arg == 1) & valid_parameters
|
551
604
|
endpoint_arg_minus = (endpoint_arg == -1) & valid_parameters
|
552
605
|
endpoint_arg_plus = (endpoint_arg == 1) & valid_parameters
|
606
|
+
|
607
|
+
is_discrete = isinstance(dist, DiscreteDistribution)
|
553
608
|
# Writing this independently of how the are set in the distribution
|
554
609
|
# infrastructure. That is very compact; this is very verbose.
|
555
610
|
if fname in {'logpdf'}:
|
556
611
|
assert_equal(res[outside_arg_minus], -np.inf)
|
557
612
|
assert_equal(res[outside_arg_plus], -np.inf)
|
558
|
-
|
559
|
-
assert_equal(res[
|
613
|
+
ref = -np.inf if not is_discrete else np.inf
|
614
|
+
assert_equal(res[endpoint_arg_minus & ~valid_arg], ref)
|
615
|
+
assert_equal(res[endpoint_arg_plus & ~valid_arg], ref)
|
560
616
|
elif fname in {'pdf'}:
|
561
617
|
assert_equal(res[outside_arg_minus], 0)
|
562
618
|
assert_equal(res[outside_arg_plus], 0)
|
563
|
-
|
564
|
-
assert_equal(res[
|
565
|
-
|
619
|
+
ref = 0 if not is_discrete else np.inf
|
620
|
+
assert_equal(res[endpoint_arg_minus & ~valid_arg], ref)
|
621
|
+
assert_equal(res[endpoint_arg_plus & ~valid_arg], ref)
|
622
|
+
elif fname in {'logcdf'} and not is_discrete:
|
566
623
|
assert_equal(res[outside_arg_minus], -inf)
|
567
624
|
assert_equal(res[outside_arg_plus], 0)
|
568
625
|
assert_equal(res[endpoint_arg_minus], -inf)
|
569
626
|
assert_equal(res[endpoint_arg_plus], 0)
|
570
|
-
elif fname in {'cdf'}:
|
627
|
+
elif fname in {'cdf'} and not is_discrete:
|
571
628
|
assert_equal(res[outside_arg_minus], 0)
|
572
629
|
assert_equal(res[outside_arg_plus], 1)
|
573
630
|
assert_equal(res[endpoint_arg_minus], 0)
|
574
631
|
assert_equal(res[endpoint_arg_plus], 1)
|
575
|
-
elif fname in {'logccdf'}:
|
632
|
+
elif fname in {'logccdf'} and not is_discrete:
|
576
633
|
assert_equal(res[outside_arg_minus], 0)
|
577
634
|
assert_equal(res[outside_arg_plus], -inf)
|
578
635
|
assert_equal(res[endpoint_arg_minus], 0)
|
579
636
|
assert_equal(res[endpoint_arg_plus], -inf)
|
580
|
-
elif fname in {'ccdf'}:
|
637
|
+
elif fname in {'ccdf'} and not is_discrete:
|
581
638
|
assert_equal(res[outside_arg_minus], 1)
|
582
639
|
assert_equal(res[outside_arg_plus], 0)
|
583
640
|
assert_equal(res[endpoint_arg_minus], 1)
|
584
641
|
assert_equal(res[endpoint_arg_plus], 0)
|
585
|
-
elif fname in {'ilogcdf', 'icdf'}:
|
642
|
+
elif fname in {'ilogcdf', 'icdf'} and not is_discrete:
|
586
643
|
assert_equal(res[outside_arg == -1], np.nan)
|
587
644
|
assert_equal(res[outside_arg == 1], np.nan)
|
588
645
|
assert_equal(res[endpoint_arg == -1], a[endpoint_arg == -1])
|
589
646
|
assert_equal(res[endpoint_arg == 1], b[endpoint_arg == 1])
|
590
|
-
elif fname in {'ilogccdf', 'iccdf'}:
|
647
|
+
elif fname in {'ilogccdf', 'iccdf'} and not is_discrete:
|
591
648
|
assert_equal(res[outside_arg == -1], np.nan)
|
592
649
|
assert_equal(res[outside_arg == 1], np.nan)
|
593
650
|
assert_equal(res[endpoint_arg == -1], b[endpoint_arg == -1])
|
594
651
|
assert_equal(res[endpoint_arg == 1], a[endpoint_arg == 1])
|
595
652
|
|
596
|
-
|
653
|
+
exclude = {'logmean', 'mean', 'logskewness', 'skewness', 'support'}
|
654
|
+
if isinstance(dist, DiscreteDistribution):
|
655
|
+
exclude.update({'pdf', 'logpdf'})
|
656
|
+
|
657
|
+
if (
|
658
|
+
fname not in exclude
|
659
|
+
and not (isinstance(dist, Binomial)
|
660
|
+
and np.any((dist.n == 0) | (dist.p == 0) | (dist.p == 1)))):
|
661
|
+
# This can fail in degenerate case where Binomial distribution is a point
|
662
|
+
# distribution. Further on, we could factor out an is_degenerate function
|
663
|
+
# for the tests, or think about storing info about degeneracy in the
|
664
|
+
# instances.
|
597
665
|
assert np.isfinite(res[all_valid & (endpoint_arg == 0)]).all()
|
598
666
|
|
599
667
|
|
@@ -623,7 +691,6 @@ def check_moment_funcs(dist, result_shape):
|
|
623
691
|
orders = getattr(formula, 'orders', set(range(6)))
|
624
692
|
return order in orders
|
625
693
|
|
626
|
-
|
627
694
|
dist.reset_cache()
|
628
695
|
|
629
696
|
### Check Raw Moments ###
|
@@ -676,6 +743,7 @@ def check_moment_funcs(dist, result_shape):
|
|
676
743
|
dist.moment(i, 'raw')
|
677
744
|
check(i, 'central', 'transform', ref)
|
678
745
|
|
746
|
+
variance = dist.variance()
|
679
747
|
dist.reset_cache()
|
680
748
|
|
681
749
|
# If we have standard moment formulas, or if there are
|
@@ -686,9 +754,9 @@ def check_moment_funcs(dist, result_shape):
|
|
686
754
|
for i in range(3, 6):
|
687
755
|
ref = dist.moment(i, 'central', method='quadrature')
|
688
756
|
check(i, 'central', 'normalize', ref,
|
689
|
-
success=has_formula(i, 'standardized'))
|
757
|
+
success=has_formula(i, 'standardized') and not np.any(variance == 0))
|
690
758
|
dist.moment(i, 'standardized') # build up the cache
|
691
|
-
check(i, 'central', 'normalize', ref)
|
759
|
+
check(i, 'central', 'normalize', ref, success=not np.any(variance == 0))
|
692
760
|
|
693
761
|
### Check Standardized Moments ###
|
694
762
|
|
@@ -701,7 +769,13 @@ def check_moment_funcs(dist, result_shape):
|
|
701
769
|
assert ref.shape == result_shape
|
702
770
|
check(i, 'standardized', 'formula', ref,
|
703
771
|
success=has_formula(i, 'standardized'))
|
704
|
-
|
772
|
+
if not (
|
773
|
+
isinstance(dist, Binomial)
|
774
|
+
and np.any((dist.n == 0) | (dist.p == 0) | (dist.p == 1))
|
775
|
+
):
|
776
|
+
# This test will fail for degenerate case where binomial distribution
|
777
|
+
# is a point distribution.
|
778
|
+
check(i, 'standardized', 'general', ref, success=i <= 2)
|
705
779
|
check(i, 'standardized', 'normalize', ref)
|
706
780
|
|
707
781
|
if isinstance(dist, ShiftedScaledDistribution):
|
@@ -827,7 +901,7 @@ def classify_arg(dist, arg, arg_domain):
|
|
827
901
|
|
828
902
|
def test_input_validation():
|
829
903
|
class Test(ContinuousDistribution):
|
830
|
-
_variable = _RealParameter('x', domain=
|
904
|
+
_variable = _RealParameter('x', domain=_RealInterval())
|
831
905
|
|
832
906
|
message = ("The `Test` distribution family does not accept parameters, "
|
833
907
|
"but parameters `{'a'}` were provided.")
|
@@ -856,10 +930,10 @@ def test_input_validation():
|
|
856
930
|
Test().moment(2, kind='coconut')
|
857
931
|
|
858
932
|
class Test2(ContinuousDistribution):
|
859
|
-
_p1 = _RealParameter('c', domain=
|
860
|
-
_p2 = _RealParameter('d', domain=
|
933
|
+
_p1 = _RealParameter('c', domain=_RealInterval())
|
934
|
+
_p2 = _RealParameter('d', domain=_RealInterval())
|
861
935
|
_parameterizations = [_Parameterization(_p1, _p2)]
|
862
|
-
_variable = _RealParameter('x', domain=
|
936
|
+
_variable = _RealParameter('x', domain=_RealInterval())
|
863
937
|
|
864
938
|
message = ("The provided parameters `{a}` do not match a supported "
|
865
939
|
"parameterization of the `Test2` distribution family.")
|
@@ -1031,28 +1105,35 @@ class TestAttributes:
|
|
1031
1105
|
|
1032
1106
|
|
1033
1107
|
class TestMakeDistribution:
|
1034
|
-
@pytest.mark.parametrize('i, distdata', enumerate(distcont))
|
1035
|
-
def
|
1108
|
+
@pytest.mark.parametrize('i, distdata', enumerate(distcont + distdiscrete))
|
1109
|
+
def test_rv_generic(self, i, distdata):
|
1036
1110
|
distname = distdata[0]
|
1037
1111
|
|
1038
1112
|
slow = {'argus', 'exponpow', 'exponweib', 'genexpon', 'gompertz', 'halfgennorm',
|
1039
|
-
'johnsonsb', 'kappa4', 'ksone', 'kstwo', 'kstwobign', '
|
1040
|
-
'powernorm', 'recipinvgauss', 'studentized_range',
|
1113
|
+
'johnsonsb', 'kappa4', 'ksone', 'kstwo', 'kstwobign', 'norminvgauss',
|
1114
|
+
'powerlognorm', 'powernorm', 'recipinvgauss', 'studentized_range',
|
1115
|
+
'vonmises_line', # continuous
|
1116
|
+
'betanbinom', 'logser', 'skellam', 'zipf'} # discrete
|
1041
1117
|
if not int(os.environ.get('SCIPY_XSLOW', '0')) and distname in slow:
|
1042
1118
|
pytest.skip('Skipping as XSLOW')
|
1043
1119
|
|
1044
|
-
if distname in {
|
1045
|
-
'levy_stable',
|
1046
|
-
'vonmises',
|
1120
|
+
if distname in { # skip these distributions
|
1121
|
+
'levy_stable', # private methods seem to require >= 1d args
|
1122
|
+
'vonmises', # circular distribution; shouldn't work
|
1123
|
+
'poisson_binom', # vector shape parameter
|
1124
|
+
'hypergeom', # distribution functions need interpolation
|
1125
|
+
'nchypergeom_fisher', # distribution functions need interpolation
|
1126
|
+
'nchypergeom_wallenius', # distribution functions need interpolation
|
1047
1127
|
}:
|
1048
1128
|
return
|
1049
1129
|
|
1050
1130
|
# skip single test, mostly due to slight disagreement
|
1051
1131
|
custom_tolerances = {'ksone': 1e-5, 'kstwo': 1e-5} # discontinuous PDF
|
1052
1132
|
skip_entropy = {'kstwobign', 'pearson3'} # tolerance issue
|
1053
|
-
skip_skewness = {'exponpow', 'ksone'} # tolerance
|
1054
|
-
skip_kurtosis = {'chi', 'exponpow', 'invgamma', # tolerance
|
1055
|
-
'johnsonsb', 'ksone', 'kstwo'
|
1133
|
+
skip_skewness = {'exponpow', 'ksone', 'nchypergeom_wallenius'} # tolerance
|
1134
|
+
skip_kurtosis = {'chi', 'exponpow', 'invgamma', # tolerance
|
1135
|
+
'johnsonsb', 'ksone', 'kstwo', # tolerance
|
1136
|
+
'nchypergeom_wallenius'} # tolerance
|
1056
1137
|
skip_logccdf = {'arcsine', 'skewcauchy', 'trapezoid', 'triang'} # tolerance
|
1057
1138
|
skip_raw = {2: {'alpha', 'foldcauchy', 'halfcauchy', 'levy', 'levy_l'},
|
1058
1139
|
3: {'pareto'}, # stats.pareto is just wrong
|
@@ -1075,6 +1156,10 @@ class TestMakeDistribution:
|
|
1075
1156
|
assert_allclose(X.support(), Y.support())
|
1076
1157
|
if distname not in skip_entropy:
|
1077
1158
|
assert_allclose(X.entropy(), Y.entropy(), rtol=rtol)
|
1159
|
+
if isinstance(Y, stats.rv_discrete):
|
1160
|
+
# some continuous distributions have trouble with `logentropy` because
|
1161
|
+
# it uses complex numbers
|
1162
|
+
assert_allclose(np.exp(X.logentropy()), Y.entropy(), rtol=rtol)
|
1078
1163
|
assert_allclose(X.median(), Y.median(), rtol=rtol)
|
1079
1164
|
assert_allclose(X.mean(), m, rtol=rtol, atol=atol)
|
1080
1165
|
assert_allclose(X.variance(), v, rtol=rtol, atol=atol)
|
@@ -1083,15 +1168,29 @@ class TestMakeDistribution:
|
|
1083
1168
|
if distname not in skip_kurtosis:
|
1084
1169
|
assert_allclose(X.kurtosis(convention='excess'), k,
|
1085
1170
|
rtol=rtol, atol=atol)
|
1086
|
-
|
1087
|
-
|
1171
|
+
if isinstance(dist, stats.rv_continuous):
|
1172
|
+
assert_allclose(X.logpdf(x), Y.logpdf(x), rtol=rtol)
|
1173
|
+
assert_allclose(X.pdf(x), Y.pdf(x), rtol=rtol)
|
1174
|
+
else:
|
1175
|
+
assert_allclose(X.logpmf(x), Y.logpmf(x), rtol=rtol)
|
1176
|
+
assert_allclose(X.pmf(x), Y.pmf(x), rtol=rtol)
|
1088
1177
|
assert_allclose(X.logcdf(x), Y.logcdf(x), rtol=rtol)
|
1089
1178
|
assert_allclose(X.cdf(x), Y.cdf(x), rtol=rtol)
|
1090
1179
|
if distname not in skip_logccdf:
|
1091
1180
|
assert_allclose(X.logccdf(x), Y.logsf(x), rtol=rtol)
|
1092
1181
|
assert_allclose(X.ccdf(x), Y.sf(x), rtol=rtol)
|
1093
|
-
|
1094
|
-
|
1182
|
+
|
1183
|
+
# old infrastructure convention for ppf(p=0) and isf(p=1) is different than
|
1184
|
+
# new infrastructure. Adjust reference values accordingly.
|
1185
|
+
a, _ = Y.support()
|
1186
|
+
ref_ppf = Y.ppf(p)
|
1187
|
+
ref_ppf[p == 0] = a
|
1188
|
+
ref_isf = Y.isf(p)
|
1189
|
+
ref_isf[p == 1] = a
|
1190
|
+
|
1191
|
+
assert_allclose(X.icdf(p), ref_ppf, rtol=rtol)
|
1192
|
+
assert_allclose(X.iccdf(p), ref_isf, rtol=rtol)
|
1193
|
+
|
1095
1194
|
for order in range(5):
|
1096
1195
|
if distname not in skip_raw.get(order, {}):
|
1097
1196
|
assert_allclose(X.moment(order, kind='raw'),
|
@@ -1100,10 +1199,222 @@ class TestMakeDistribution:
|
|
1100
1199
|
if distname not in skip_standardized:
|
1101
1200
|
assert_allclose(X.moment(order, kind='standardized'),
|
1102
1201
|
Y.stats('mvsk'[order-1]), rtol=rtol, atol=atol)
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1202
|
+
if isinstance(dist, stats.rv_continuous):
|
1203
|
+
# For discrete distributions, these won't agree at the far left end
|
1204
|
+
# of the support, and the new infrastructure is slow there (for now).
|
1205
|
+
seed = 845298245687345
|
1206
|
+
assert_allclose(X.sample(shape=10, rng=seed),
|
1207
|
+
Y.rvs(size=10,
|
1208
|
+
random_state=np.random.default_rng(seed)),
|
1209
|
+
rtol=rtol)
|
1210
|
+
|
1211
|
+
def test_custom(self):
|
1212
|
+
rng = np.random.default_rng(7548723590230982)
|
1213
|
+
|
1214
|
+
class MyLogUniform:
|
1215
|
+
@property
|
1216
|
+
def __make_distribution_version__(self):
|
1217
|
+
return "1.16.0"
|
1218
|
+
|
1219
|
+
@property
|
1220
|
+
def parameters(self):
|
1221
|
+
return {'a': {'endpoints': (0, np.inf), 'inclusive': (False, False)},
|
1222
|
+
'b': {'endpoints': ('a', np.inf), 'inclusive': (False, False)}}
|
1223
|
+
|
1224
|
+
@property
|
1225
|
+
def support(self):
|
1226
|
+
return {'endpoints': ('a', 'b')}
|
1227
|
+
|
1228
|
+
def pdf(self, x, a, b):
|
1229
|
+
return 1 / (x * (np.log(b) - np.log(a)))
|
1230
|
+
|
1231
|
+
def sample(self, shape, *, a, b, rng=None):
|
1232
|
+
p = rng.uniform(size=shape)
|
1233
|
+
return np.exp(np.log(a) + p * (np.log(b) - np.log(a)))
|
1234
|
+
|
1235
|
+
def moment(self, order, kind='raw', *, a, b):
|
1236
|
+
if order == 1 and kind == 'raw':
|
1237
|
+
# quadrature is perfectly accurate here; add 1e-10 error so we
|
1238
|
+
# can tell the difference between the two
|
1239
|
+
return (b - a) / np.log(b/a) + 1e-10
|
1240
|
+
|
1241
|
+
LogUniform = stats.make_distribution(MyLogUniform())
|
1242
|
+
|
1243
|
+
X = LogUniform(a=np.exp(1), b=np.exp(3))
|
1244
|
+
Y = stats.exp(Uniform(a=1., b=3.))
|
1245
|
+
x = X.sample(shape=10, rng=rng)
|
1246
|
+
p = X.cdf(x)
|
1247
|
+
|
1248
|
+
assert_allclose(X.support(), Y.support())
|
1249
|
+
assert_allclose(X.entropy(), Y.entropy())
|
1250
|
+
assert_allclose(X.median(), Y.median())
|
1251
|
+
assert_allclose(X.logpdf(x), Y.logpdf(x))
|
1252
|
+
assert_allclose(X.pdf(x), Y.pdf(x))
|
1253
|
+
assert_allclose(X.logcdf(x), Y.logcdf(x))
|
1254
|
+
assert_allclose(X.cdf(x), Y.cdf(x))
|
1255
|
+
assert_allclose(X.logccdf(x), Y.logccdf(x))
|
1256
|
+
assert_allclose(X.ccdf(x), Y.ccdf(x))
|
1257
|
+
assert_allclose(X.icdf(p), Y.icdf(p))
|
1258
|
+
assert_allclose(X.iccdf(p), Y.iccdf(p))
|
1259
|
+
for kind in ['raw', 'central', 'standardized']:
|
1260
|
+
for order in range(5):
|
1261
|
+
assert_allclose(X.moment(order, kind=kind),
|
1262
|
+
Y.moment(order, kind=kind))
|
1263
|
+
|
1264
|
+
# Confirm that the `sample` and `moment` methods are overriden as expected
|
1265
|
+
sample_formula = X.sample(shape=10, rng=0, method='formula')
|
1266
|
+
sample_inverse = X.sample(shape=10, rng=0, method='inverse_transform')
|
1267
|
+
assert_allclose(sample_formula, sample_inverse)
|
1268
|
+
assert not np.all(sample_formula == sample_inverse)
|
1269
|
+
|
1270
|
+
assert_allclose(X.mean(method='formula'), X.mean(method='quadrature'))
|
1271
|
+
assert not X.mean(method='formula') == X.mean(method='quadrature')
|
1272
|
+
|
1273
|
+
# pdf and cdf formulas below can warn on boundary of support in some cases.
|
1274
|
+
# See https://github.com/scipy/scipy/pull/22560#discussion_r1962763840.
|
1275
|
+
@pytest.mark.slow
|
1276
|
+
@pytest.mark.filterwarnings("ignore::RuntimeWarning")
|
1277
|
+
@pytest.mark.parametrize("c", [-1, 0, 1, np.asarray([-2.1, -1., 0., 1., 2.1])])
|
1278
|
+
def test_custom_variable_support(self, c):
|
1279
|
+
rng = np.random.default_rng(7548723590230982)
|
1280
|
+
|
1281
|
+
class MyGenExtreme:
|
1282
|
+
@property
|
1283
|
+
def __make_distribution_version__(self):
|
1284
|
+
return "1.16.0"
|
1285
|
+
|
1286
|
+
@property
|
1287
|
+
def parameters(self):
|
1288
|
+
return {
|
1289
|
+
'c': {'endpoints': (-np.inf, np.inf), 'inclusive': (False, False)},
|
1290
|
+
'mu': {'endpoints': (-np.inf, np.inf), 'inclusive': (False, False)},
|
1291
|
+
'sigma': {'endpoints': (0, np.inf), 'inclusive': (False, False)}
|
1292
|
+
}
|
1293
|
+
|
1294
|
+
@property
|
1295
|
+
def support(self):
|
1296
|
+
def left(*, c, mu, sigma):
|
1297
|
+
c, mu, sigma = np.broadcast_arrays(c, mu, sigma)
|
1298
|
+
result = np.empty_like(c)
|
1299
|
+
result[c >= 0] = -np.inf
|
1300
|
+
result[c < 0] = mu[c < 0] + sigma[c < 0] / c[c < 0]
|
1301
|
+
return result[()]
|
1302
|
+
|
1303
|
+
def right(*, c, mu, sigma):
|
1304
|
+
c, mu, sigma = np.broadcast_arrays(c, mu, sigma)
|
1305
|
+
result = np.empty_like(c)
|
1306
|
+
result[c <= 0] = np.inf
|
1307
|
+
result[c > 0] = mu[c > 0] + sigma[c > 0] / c[c > 0]
|
1308
|
+
return result[()]
|
1309
|
+
|
1310
|
+
return {"endpoints": (left, right), "inclusive": (False, False)}
|
1311
|
+
|
1312
|
+
def pdf(self, x, *, c, mu, sigma):
|
1313
|
+
x, c, mu, sigma = np.broadcast_arrays(x, c, mu, sigma)
|
1314
|
+
t = np.empty_like(x)
|
1315
|
+
mask = (c == 0)
|
1316
|
+
t[mask] = np.exp(-(x[mask] - mu[mask])/sigma[mask])
|
1317
|
+
t[~mask] = (
|
1318
|
+
1 - c[~mask]*(x[~mask] - mu[~mask])/sigma[~mask]
|
1319
|
+
)**(1/c[~mask])
|
1320
|
+
result = 1/sigma * t**(1 - c)*np.exp(-t)
|
1321
|
+
return result[()]
|
1322
|
+
|
1323
|
+
def cdf(self, x, *, c, mu, sigma):
|
1324
|
+
x, c, mu, sigma = np.broadcast_arrays(x, c, mu, sigma)
|
1325
|
+
t = np.empty_like(x)
|
1326
|
+
mask = (c == 0)
|
1327
|
+
t[mask] = np.exp(-(x[mask] - mu[mask])/sigma[mask])
|
1328
|
+
t[~mask] = (
|
1329
|
+
1 - c[~mask]*(x[~mask] - mu[~mask])/sigma[~mask]
|
1330
|
+
)**(1/c[~mask])
|
1331
|
+
return np.exp(-t)[()]
|
1332
|
+
|
1333
|
+
GenExtreme1 = stats.make_distribution(MyGenExtreme())
|
1334
|
+
GenExtreme2 = stats.make_distribution(stats.genextreme)
|
1335
|
+
|
1336
|
+
X1 = GenExtreme1(c=c, mu=0, sigma=1)
|
1337
|
+
X2 = GenExtreme2(c=c)
|
1338
|
+
|
1339
|
+
x = X1.sample(shape=10, rng=rng)
|
1340
|
+
p = X1.cdf(x)
|
1341
|
+
|
1342
|
+
assert_allclose(X1.support(), X2.support())
|
1343
|
+
assert_allclose(X1.entropy(), X2.entropy(), rtol=5e-6)
|
1344
|
+
assert_allclose(X1.median(), X2.median())
|
1345
|
+
assert_allclose(X1.logpdf(x), X2.logpdf(x))
|
1346
|
+
assert_allclose(X1.pdf(x), X2.pdf(x))
|
1347
|
+
assert_allclose(X1.logcdf(x), X2.logcdf(x))
|
1348
|
+
assert_allclose(X1.cdf(x), X2.cdf(x))
|
1349
|
+
assert_allclose(X1.logccdf(x), X2.logccdf(x))
|
1350
|
+
assert_allclose(X1.ccdf(x), X2.ccdf(x))
|
1351
|
+
assert_allclose(X1.icdf(p), X2.icdf(p))
|
1352
|
+
assert_allclose(X1.iccdf(p), X2.iccdf(p))
|
1353
|
+
|
1354
|
+
@pytest.mark.slow
|
1355
|
+
@pytest.mark.parametrize("a", [0.5, np.asarray([0.5, 1.0, 2.0, 4.0, 8.0])])
|
1356
|
+
@pytest.mark.parametrize("b", [0.5, np.asarray([0.5, 1.0, 2.0, 4.0, 8.0])])
|
1357
|
+
def test_custom_multiple_parameterizations(self, a, b):
|
1358
|
+
rng = np.random.default_rng(7548723590230982)
|
1359
|
+
class MyBeta:
|
1360
|
+
@property
|
1361
|
+
def __make_distribution_version__(self):
|
1362
|
+
return "1.16.0"
|
1363
|
+
|
1364
|
+
@property
|
1365
|
+
def parameters(self):
|
1366
|
+
return (
|
1367
|
+
{"a": (0, np.inf), "b": (0, np.inf)},
|
1368
|
+
{"mu": (0, 1), "nu": (0, np.inf)},
|
1369
|
+
)
|
1370
|
+
|
1371
|
+
def process_parameters(self, a=None, b=None, mu=None, nu=None):
|
1372
|
+
if a is not None and b is not None and mu is None and nu is None:
|
1373
|
+
nu = a + b
|
1374
|
+
mu = a / nu
|
1375
|
+
else:
|
1376
|
+
a = mu * nu
|
1377
|
+
b = nu - a
|
1378
|
+
return {"a": a, "b": b, "mu": mu, "nu": nu}
|
1379
|
+
|
1380
|
+
@property
|
1381
|
+
def support(self):
|
1382
|
+
return {'endpoints': (0, 1)}
|
1383
|
+
|
1384
|
+
def pdf(self, x, a, b, mu, nu):
|
1385
|
+
return special._ufuncs._beta_pdf(x, a, b)
|
1386
|
+
|
1387
|
+
def cdf(self, x, a, b, mu, nu):
|
1388
|
+
return special.betainc(a, b, x)
|
1389
|
+
|
1390
|
+
Beta = stats.make_distribution(stats.beta)
|
1391
|
+
MyBeta = stats.make_distribution(MyBeta())
|
1392
|
+
|
1393
|
+
mu = a / (a + b)
|
1394
|
+
nu = a + b
|
1395
|
+
|
1396
|
+
X = MyBeta(a=a, b=b)
|
1397
|
+
Y = MyBeta(mu=mu, nu=nu)
|
1398
|
+
Z = Beta(a=a, b=b)
|
1399
|
+
|
1400
|
+
x = Z.sample(shape=10, rng=rng)
|
1401
|
+
p = Z.cdf(x)
|
1402
|
+
|
1403
|
+
assert_allclose(X.support(), Z.support())
|
1404
|
+
assert_allclose(X.median(), Z.median())
|
1405
|
+
assert_allclose(X.pdf(x), Z.pdf(x))
|
1406
|
+
assert_allclose(X.cdf(x), Z.cdf(x))
|
1407
|
+
assert_allclose(X.ccdf(x), Z.ccdf(x))
|
1408
|
+
assert_allclose(X.icdf(p), Z.icdf(p))
|
1409
|
+
assert_allclose(X.iccdf(p), Z.iccdf(p))
|
1410
|
+
|
1411
|
+
assert_allclose(Y.support(), Z.support())
|
1412
|
+
assert_allclose(Y.median(), Z.median())
|
1413
|
+
assert_allclose(Y.pdf(x), Z.pdf(x))
|
1414
|
+
assert_allclose(Y.cdf(x), Z.cdf(x))
|
1415
|
+
assert_allclose(Y.ccdf(x), Z.ccdf(x))
|
1416
|
+
assert_allclose(Y.icdf(p), Z.icdf(p))
|
1417
|
+
assert_allclose(Y.iccdf(p), Z.iccdf(p))
|
1107
1418
|
|
1108
1419
|
def test_input_validation(self):
|
1109
1420
|
message = '`levy_stable` is not supported.'
|
@@ -1114,7 +1425,7 @@ class TestMakeDistribution:
|
|
1114
1425
|
with pytest.raises(NotImplementedError, match=message):
|
1115
1426
|
stats.make_distribution(stats.vonmises)
|
1116
1427
|
|
1117
|
-
message = "The argument must be an instance of
|
1428
|
+
message = "The argument must be an instance of..."
|
1118
1429
|
with pytest.raises(ValueError, match=message):
|
1119
1430
|
stats.make_distribution(object())
|
1120
1431
|
|
@@ -1138,7 +1449,14 @@ class TestMakeDistribution:
|
|
1138
1449
|
|
1139
1450
|
class TestTransforms:
|
1140
1451
|
|
1141
|
-
|
1452
|
+
def test_ContinuousDistribution_only(self):
|
1453
|
+
X = stats.Binomial(n=10, p=0.5)
|
1454
|
+
# This is applied at the top level TransformedDistribution,
|
1455
|
+
# so testing one subclass is enough
|
1456
|
+
message = "Transformations are currently only supported for continuous RVs."
|
1457
|
+
with pytest.raises(NotImplementedError, match=message):
|
1458
|
+
stats.exp(X)
|
1459
|
+
|
1142
1460
|
def test_truncate(self):
|
1143
1461
|
rng = np.random.default_rng(81345982345826)
|
1144
1462
|
lb = rng.random((3, 1))
|
@@ -1175,6 +1493,7 @@ class TestTransforms:
|
|
1175
1493
|
|
1176
1494
|
@pytest.mark.fail_slow(10)
|
1177
1495
|
@given(data=strategies.data(), seed=strategies.integers(min_value=0))
|
1496
|
+
@pytest.mark.thread_unsafe
|
1178
1497
|
def test_loc_scale(self, data, seed):
|
1179
1498
|
# Need tests with negative scale
|
1180
1499
|
rng = np.random.default_rng(seed)
|
@@ -1612,7 +1931,7 @@ class TestFullCoverage:
|
|
1612
1931
|
[(np.float16, np.float16),
|
1613
1932
|
(np.int16, np.float64)])
|
1614
1933
|
def test_RealParameter_uncommon_dtypes(self, dtype_in, dtype_out):
|
1615
|
-
domain =
|
1934
|
+
domain = _RealInterval((-1, 1))
|
1616
1935
|
parameter = _RealParameter('x', domain=domain)
|
1617
1936
|
|
1618
1937
|
x = np.asarray([0.5, 2.5], dtype=dtype_in)
|
@@ -1627,7 +1946,7 @@ class TestFullCoverage:
|
|
1627
1946
|
# to return the right shape and dytpe, but this would need to be
|
1628
1947
|
# configurable.
|
1629
1948
|
class TestDist(ContinuousDistribution):
|
1630
|
-
_variable = _RealParameter('x', domain=
|
1949
|
+
_variable = _RealParameter('x', domain=_RealInterval(endpoints=(0., 1.)))
|
1631
1950
|
def _logpdf_formula(self, x, *args, **kwargs):
|
1632
1951
|
return 0
|
1633
1952
|
|
@@ -1754,7 +2073,7 @@ class TestReprs:
|
|
1754
2073
|
|
1755
2074
|
|
1756
2075
|
class MixedDist(ContinuousDistribution):
|
1757
|
-
_variable = _RealParameter('x', domain=
|
2076
|
+
_variable = _RealParameter('x', domain=_RealInterval(endpoints=(-np.inf, np.inf)))
|
1758
2077
|
def _pdf_formula(self, x, *args, **kwargs):
|
1759
2078
|
return (0.4 * 1/(1.1 * np.sqrt(2*np.pi)) * np.exp(-0.5*((x+0.25)/1.1)**2)
|
1760
2079
|
+ 0.6 * 1/(0.9 * np.sqrt(2*np.pi)) * np.exp(-0.5*((x-0.5)/0.9)**2))
|