scipy 1.15.3__cp312-cp312-macosx_14_0_arm64.whl → 1.16.0rc2__cp312-cp312-macosx_14_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/__config__.py +4 -4
- 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 +560 -567
- 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
@@ -0,0 +1,937 @@
|
|
1
|
+
"""Array-agnostic implementations for the public API."""
|
2
|
+
|
3
|
+
import math
|
4
|
+
import warnings
|
5
|
+
from collections.abc import Callable, Sequence
|
6
|
+
from types import ModuleType, NoneType
|
7
|
+
from typing import cast, overload
|
8
|
+
|
9
|
+
from ._at import at
|
10
|
+
from ._utils import _compat, _helpers
|
11
|
+
from ._utils._compat import array_namespace, is_dask_namespace, is_jax_array
|
12
|
+
from ._utils._helpers import (
|
13
|
+
asarrays,
|
14
|
+
capabilities,
|
15
|
+
eager_shape,
|
16
|
+
meta_namespace,
|
17
|
+
ndindex,
|
18
|
+
)
|
19
|
+
from ._utils._typing import Array
|
20
|
+
|
21
|
+
__all__ = [
|
22
|
+
"apply_where",
|
23
|
+
"atleast_nd",
|
24
|
+
"broadcast_shapes",
|
25
|
+
"cov",
|
26
|
+
"create_diagonal",
|
27
|
+
"expand_dims",
|
28
|
+
"kron",
|
29
|
+
"nunique",
|
30
|
+
"pad",
|
31
|
+
"setdiff1d",
|
32
|
+
"sinc",
|
33
|
+
]
|
34
|
+
|
35
|
+
|
36
|
+
@overload
|
37
|
+
def apply_where( # type: ignore[explicit-any,decorated-any] # numpydoc ignore=GL08
|
38
|
+
cond: Array,
|
39
|
+
args: Array | tuple[Array, ...],
|
40
|
+
f1: Callable[..., Array],
|
41
|
+
f2: Callable[..., Array],
|
42
|
+
/,
|
43
|
+
*,
|
44
|
+
xp: ModuleType | None = None,
|
45
|
+
) -> Array: ...
|
46
|
+
|
47
|
+
|
48
|
+
@overload
|
49
|
+
def apply_where( # type: ignore[explicit-any,decorated-any] # numpydoc ignore=GL08
|
50
|
+
cond: Array,
|
51
|
+
args: Array | tuple[Array, ...],
|
52
|
+
f1: Callable[..., Array],
|
53
|
+
/,
|
54
|
+
*,
|
55
|
+
fill_value: Array | complex,
|
56
|
+
xp: ModuleType | None = None,
|
57
|
+
) -> Array: ...
|
58
|
+
|
59
|
+
|
60
|
+
def apply_where( # type: ignore[explicit-any] # numpydoc ignore=PR01,PR02
|
61
|
+
cond: Array,
|
62
|
+
args: Array | tuple[Array, ...],
|
63
|
+
f1: Callable[..., Array],
|
64
|
+
f2: Callable[..., Array] | None = None,
|
65
|
+
/,
|
66
|
+
*,
|
67
|
+
fill_value: Array | complex | None = None,
|
68
|
+
xp: ModuleType | None = None,
|
69
|
+
) -> Array:
|
70
|
+
"""
|
71
|
+
Run one of two elementwise functions depending on a condition.
|
72
|
+
|
73
|
+
Equivalent to ``f1(*args) if cond else fill_value`` performed elementwise
|
74
|
+
when `fill_value` is defined, otherwise to ``f1(*args) if cond else f2(*args)``.
|
75
|
+
|
76
|
+
Parameters
|
77
|
+
----------
|
78
|
+
cond : array
|
79
|
+
The condition, expressed as a boolean array.
|
80
|
+
args : Array or tuple of Arrays
|
81
|
+
Argument(s) to `f1` (and `f2`). Must be broadcastable with `cond`.
|
82
|
+
f1 : callable
|
83
|
+
Elementwise function of `args`, returning a single array.
|
84
|
+
Where `cond` is True, output will be ``f1(arg0[cond], arg1[cond], ...)``.
|
85
|
+
f2 : callable, optional
|
86
|
+
Elementwise function of `args`, returning a single array.
|
87
|
+
Where `cond` is False, output will be ``f2(arg0[cond], arg1[cond], ...)``.
|
88
|
+
Mutually exclusive with `fill_value`.
|
89
|
+
fill_value : Array or scalar, optional
|
90
|
+
If provided, value with which to fill output array where `cond` is False.
|
91
|
+
It does not need to be scalar; it needs however to be broadcastable with
|
92
|
+
`cond` and `args`.
|
93
|
+
Mutually exclusive with `f2`. You must provide one or the other.
|
94
|
+
xp : array_namespace, optional
|
95
|
+
The standard-compatible namespace for `cond` and `args`. Default: infer.
|
96
|
+
|
97
|
+
Returns
|
98
|
+
-------
|
99
|
+
Array
|
100
|
+
An array with elements from the output of `f1` where `cond` is True and either
|
101
|
+
the output of `f2` or `fill_value` where `cond` is False. The returned array has
|
102
|
+
data type determined by type promotion rules between the output of `f1` and
|
103
|
+
either `fill_value` or the output of `f2`.
|
104
|
+
|
105
|
+
Notes
|
106
|
+
-----
|
107
|
+
``xp.where(cond, f1(*args), f2(*args))`` requires explicitly evaluating `f1` even
|
108
|
+
when `cond` is False, and `f2` when cond is True. This function evaluates each
|
109
|
+
function only for their matching condition, if the backend allows for it.
|
110
|
+
|
111
|
+
On Dask, `f1` and `f2` are applied to the individual chunks and should use functions
|
112
|
+
from the namespace of the chunks.
|
113
|
+
|
114
|
+
Examples
|
115
|
+
--------
|
116
|
+
>>> import array_api_strict as xp
|
117
|
+
>>> import array_api_extra as xpx
|
118
|
+
>>> a = xp.asarray([5, 4, 3])
|
119
|
+
>>> b = xp.asarray([0, 2, 2])
|
120
|
+
>>> def f(a, b):
|
121
|
+
... return a // b
|
122
|
+
>>> xpx.apply_where(b != 0, (a, b), f, fill_value=xp.nan)
|
123
|
+
array([ nan, 2., 1.])
|
124
|
+
"""
|
125
|
+
# Parse and normalize arguments
|
126
|
+
if (f2 is None) == (fill_value is None):
|
127
|
+
msg = "Exactly one of `fill_value` or `f2` must be given."
|
128
|
+
raise TypeError(msg)
|
129
|
+
args_ = list(args) if isinstance(args, tuple) else [args]
|
130
|
+
del args
|
131
|
+
|
132
|
+
xp = array_namespace(cond, fill_value, *args_) if xp is None else xp
|
133
|
+
|
134
|
+
if isinstance(fill_value, int | float | complex | NoneType):
|
135
|
+
cond, *args_ = xp.broadcast_arrays(cond, *args_)
|
136
|
+
else:
|
137
|
+
cond, fill_value, *args_ = xp.broadcast_arrays(cond, fill_value, *args_)
|
138
|
+
|
139
|
+
if is_dask_namespace(xp):
|
140
|
+
meta_xp = meta_namespace(cond, fill_value, *args_, xp=xp)
|
141
|
+
# map_blocks doesn't descend into tuples of Arrays
|
142
|
+
return xp.map_blocks(_apply_where, cond, f1, f2, fill_value, *args_, xp=meta_xp)
|
143
|
+
return _apply_where(cond, f1, f2, fill_value, *args_, xp=xp)
|
144
|
+
|
145
|
+
|
146
|
+
def _apply_where( # type: ignore[explicit-any] # numpydoc ignore=PR01,RT01
|
147
|
+
cond: Array,
|
148
|
+
f1: Callable[..., Array],
|
149
|
+
f2: Callable[..., Array] | None,
|
150
|
+
fill_value: Array | int | float | complex | bool | None,
|
151
|
+
*args: Array,
|
152
|
+
xp: ModuleType,
|
153
|
+
) -> Array:
|
154
|
+
"""Helper of `apply_where`. On Dask, this runs on a single chunk."""
|
155
|
+
|
156
|
+
if not capabilities(xp)["boolean indexing"]:
|
157
|
+
# jax.jit does not support assignment by boolean mask
|
158
|
+
return xp.where(cond, f1(*args), f2(*args) if f2 is not None else fill_value)
|
159
|
+
|
160
|
+
temp1 = f1(*(arr[cond] for arr in args))
|
161
|
+
|
162
|
+
if f2 is None:
|
163
|
+
dtype = xp.result_type(temp1, fill_value)
|
164
|
+
if isinstance(fill_value, int | float | complex):
|
165
|
+
out = xp.full_like(cond, dtype=dtype, fill_value=fill_value)
|
166
|
+
else:
|
167
|
+
out = xp.astype(fill_value, dtype, copy=True)
|
168
|
+
else:
|
169
|
+
ncond = ~cond
|
170
|
+
temp2 = f2(*(arr[ncond] for arr in args))
|
171
|
+
dtype = xp.result_type(temp1, temp2)
|
172
|
+
out = xp.empty_like(cond, dtype=dtype)
|
173
|
+
out = at(out, ncond).set(temp2)
|
174
|
+
|
175
|
+
return at(out, cond).set(temp1)
|
176
|
+
|
177
|
+
|
178
|
+
def atleast_nd(x: Array, /, *, ndim: int, xp: ModuleType | None = None) -> Array:
|
179
|
+
"""
|
180
|
+
Recursively expand the dimension of an array to at least `ndim`.
|
181
|
+
|
182
|
+
Parameters
|
183
|
+
----------
|
184
|
+
x : array
|
185
|
+
Input array.
|
186
|
+
ndim : int
|
187
|
+
The minimum number of dimensions for the result.
|
188
|
+
xp : array_namespace, optional
|
189
|
+
The standard-compatible namespace for `x`. Default: infer.
|
190
|
+
|
191
|
+
Returns
|
192
|
+
-------
|
193
|
+
array
|
194
|
+
An array with ``res.ndim`` >= `ndim`.
|
195
|
+
If ``x.ndim`` >= `ndim`, `x` is returned.
|
196
|
+
If ``x.ndim`` < `ndim`, `x` is expanded by prepending new axes
|
197
|
+
until ``res.ndim`` equals `ndim`.
|
198
|
+
|
199
|
+
Examples
|
200
|
+
--------
|
201
|
+
>>> import array_api_strict as xp
|
202
|
+
>>> import array_api_extra as xpx
|
203
|
+
>>> x = xp.asarray([1])
|
204
|
+
>>> xpx.atleast_nd(x, ndim=3, xp=xp)
|
205
|
+
Array([[[1]]], dtype=array_api_strict.int64)
|
206
|
+
|
207
|
+
>>> x = xp.asarray([[[1, 2],
|
208
|
+
... [3, 4]]])
|
209
|
+
>>> xpx.atleast_nd(x, ndim=1, xp=xp) is x
|
210
|
+
True
|
211
|
+
"""
|
212
|
+
if xp is None:
|
213
|
+
xp = array_namespace(x)
|
214
|
+
|
215
|
+
if x.ndim < ndim:
|
216
|
+
x = xp.expand_dims(x, axis=0)
|
217
|
+
x = atleast_nd(x, ndim=ndim, xp=xp)
|
218
|
+
return x
|
219
|
+
|
220
|
+
|
221
|
+
# `float` in signature to accept `math.nan` for Dask.
|
222
|
+
# `int`s are still accepted as `float` is a superclass of `int` in typing
|
223
|
+
def broadcast_shapes(*shapes: tuple[float | None, ...]) -> tuple[int | None, ...]:
|
224
|
+
"""
|
225
|
+
Compute the shape of the broadcasted arrays.
|
226
|
+
|
227
|
+
Duplicates :func:`numpy.broadcast_shapes`, with additional support for
|
228
|
+
None and NaN sizes.
|
229
|
+
|
230
|
+
This is equivalent to ``xp.broadcast_arrays(arr1, arr2, ...)[0].shape``
|
231
|
+
without needing to worry about the backend potentially deep copying
|
232
|
+
the arrays.
|
233
|
+
|
234
|
+
Parameters
|
235
|
+
----------
|
236
|
+
*shapes : tuple[int | None, ...]
|
237
|
+
Shapes of the arrays to broadcast.
|
238
|
+
|
239
|
+
Returns
|
240
|
+
-------
|
241
|
+
tuple[int | None, ...]
|
242
|
+
The shape of the broadcasted arrays.
|
243
|
+
|
244
|
+
See Also
|
245
|
+
--------
|
246
|
+
numpy.broadcast_shapes : Equivalent NumPy function.
|
247
|
+
array_api.broadcast_arrays : Function to broadcast actual arrays.
|
248
|
+
|
249
|
+
Notes
|
250
|
+
-----
|
251
|
+
This function accepts the Array API's ``None`` for unknown sizes,
|
252
|
+
as well as Dask's non-standard ``math.nan``.
|
253
|
+
Regardless of input, the output always contains ``None`` for unknown sizes.
|
254
|
+
|
255
|
+
Examples
|
256
|
+
--------
|
257
|
+
>>> import array_api_extra as xpx
|
258
|
+
>>> xpx.broadcast_shapes((2, 3), (2, 1))
|
259
|
+
(2, 3)
|
260
|
+
>>> xpx.broadcast_shapes((4, 2, 3), (2, 1), (1, 3))
|
261
|
+
(4, 2, 3)
|
262
|
+
"""
|
263
|
+
if not shapes:
|
264
|
+
return () # Match NumPy output
|
265
|
+
|
266
|
+
ndim = max(len(shape) for shape in shapes)
|
267
|
+
out: list[int | None] = []
|
268
|
+
for axis in range(-ndim, 0):
|
269
|
+
sizes = {shape[axis] for shape in shapes if axis >= -len(shape)}
|
270
|
+
# Dask uses NaN for unknown shape, which predates the Array API spec for None
|
271
|
+
none_size = None in sizes or math.nan in sizes
|
272
|
+
sizes -= {1, None, math.nan}
|
273
|
+
if len(sizes) > 1:
|
274
|
+
msg = (
|
275
|
+
"shape mismatch: objects cannot be broadcast to a single shape: "
|
276
|
+
f"{shapes}."
|
277
|
+
)
|
278
|
+
raise ValueError(msg)
|
279
|
+
out.append(None if none_size else cast(int, sizes.pop()) if sizes else 1)
|
280
|
+
|
281
|
+
return tuple(out)
|
282
|
+
|
283
|
+
|
284
|
+
def cov(m: Array, /, *, xp: ModuleType | None = None) -> Array:
|
285
|
+
"""
|
286
|
+
Estimate a covariance matrix.
|
287
|
+
|
288
|
+
Covariance indicates the level to which two variables vary together.
|
289
|
+
If we examine N-dimensional samples, :math:`X = [x_1, x_2, ... x_N]^T`,
|
290
|
+
then the covariance matrix element :math:`C_{ij}` is the covariance of
|
291
|
+
:math:`x_i` and :math:`x_j`. The element :math:`C_{ii}` is the variance
|
292
|
+
of :math:`x_i`.
|
293
|
+
|
294
|
+
This provides a subset of the functionality of ``numpy.cov``.
|
295
|
+
|
296
|
+
Parameters
|
297
|
+
----------
|
298
|
+
m : array
|
299
|
+
A 1-D or 2-D array containing multiple variables and observations.
|
300
|
+
Each row of `m` represents a variable, and each column a single
|
301
|
+
observation of all those variables.
|
302
|
+
xp : array_namespace, optional
|
303
|
+
The standard-compatible namespace for `m`. Default: infer.
|
304
|
+
|
305
|
+
Returns
|
306
|
+
-------
|
307
|
+
array
|
308
|
+
The covariance matrix of the variables.
|
309
|
+
|
310
|
+
Examples
|
311
|
+
--------
|
312
|
+
>>> import array_api_strict as xp
|
313
|
+
>>> import array_api_extra as xpx
|
314
|
+
|
315
|
+
Consider two variables, :math:`x_0` and :math:`x_1`, which
|
316
|
+
correlate perfectly, but in opposite directions:
|
317
|
+
|
318
|
+
>>> x = xp.asarray([[0, 2], [1, 1], [2, 0]]).T
|
319
|
+
>>> x
|
320
|
+
Array([[0, 1, 2],
|
321
|
+
[2, 1, 0]], dtype=array_api_strict.int64)
|
322
|
+
|
323
|
+
Note how :math:`x_0` increases while :math:`x_1` decreases. The covariance
|
324
|
+
matrix shows this clearly:
|
325
|
+
|
326
|
+
>>> xpx.cov(x, xp=xp)
|
327
|
+
Array([[ 1., -1.],
|
328
|
+
[-1., 1.]], dtype=array_api_strict.float64)
|
329
|
+
|
330
|
+
Note that element :math:`C_{0,1}`, which shows the correlation between
|
331
|
+
:math:`x_0` and :math:`x_1`, is negative.
|
332
|
+
|
333
|
+
Further, note how `x` and `y` are combined:
|
334
|
+
|
335
|
+
>>> x = xp.asarray([-2.1, -1, 4.3])
|
336
|
+
>>> y = xp.asarray([3, 1.1, 0.12])
|
337
|
+
>>> X = xp.stack((x, y), axis=0)
|
338
|
+
>>> xpx.cov(X, xp=xp)
|
339
|
+
Array([[11.71 , -4.286 ],
|
340
|
+
[-4.286 , 2.14413333]], dtype=array_api_strict.float64)
|
341
|
+
|
342
|
+
>>> xpx.cov(x, xp=xp)
|
343
|
+
Array(11.71, dtype=array_api_strict.float64)
|
344
|
+
|
345
|
+
>>> xpx.cov(y, xp=xp)
|
346
|
+
Array(2.14413333, dtype=array_api_strict.float64)
|
347
|
+
"""
|
348
|
+
if xp is None:
|
349
|
+
xp = array_namespace(m)
|
350
|
+
|
351
|
+
m = xp.asarray(m, copy=True)
|
352
|
+
dtype = (
|
353
|
+
xp.float64 if xp.isdtype(m.dtype, "integral") else xp.result_type(m, xp.float64)
|
354
|
+
)
|
355
|
+
|
356
|
+
m = atleast_nd(m, ndim=2, xp=xp)
|
357
|
+
m = xp.astype(m, dtype)
|
358
|
+
|
359
|
+
avg = _helpers.mean(m, axis=1, xp=xp)
|
360
|
+
|
361
|
+
m_shape = eager_shape(m)
|
362
|
+
fact = m_shape[1] - 1
|
363
|
+
|
364
|
+
if fact <= 0:
|
365
|
+
warnings.warn("Degrees of freedom <= 0 for slice", RuntimeWarning, stacklevel=2)
|
366
|
+
fact = 0
|
367
|
+
|
368
|
+
m -= avg[:, None]
|
369
|
+
m_transpose = m.T
|
370
|
+
if xp.isdtype(m_transpose.dtype, "complex floating"):
|
371
|
+
m_transpose = xp.conj(m_transpose)
|
372
|
+
c = m @ m_transpose
|
373
|
+
c /= fact
|
374
|
+
axes = tuple(axis for axis, length in enumerate(c.shape) if length == 1)
|
375
|
+
return xp.squeeze(c, axis=axes)
|
376
|
+
|
377
|
+
|
378
|
+
def create_diagonal(
|
379
|
+
x: Array, /, *, offset: int = 0, xp: ModuleType | None = None
|
380
|
+
) -> Array:
|
381
|
+
"""
|
382
|
+
Construct a diagonal array.
|
383
|
+
|
384
|
+
Parameters
|
385
|
+
----------
|
386
|
+
x : array
|
387
|
+
An array having shape ``(*batch_dims, k)``.
|
388
|
+
offset : int, optional
|
389
|
+
Offset from the leading diagonal (default is ``0``).
|
390
|
+
Use positive ints for diagonals above the leading diagonal,
|
391
|
+
and negative ints for diagonals below the leading diagonal.
|
392
|
+
xp : array_namespace, optional
|
393
|
+
The standard-compatible namespace for `x`. Default: infer.
|
394
|
+
|
395
|
+
Returns
|
396
|
+
-------
|
397
|
+
array
|
398
|
+
An array having shape ``(*batch_dims, k+abs(offset), k+abs(offset))`` with `x`
|
399
|
+
on the diagonal (offset by `offset`).
|
400
|
+
|
401
|
+
Examples
|
402
|
+
--------
|
403
|
+
>>> import array_api_strict as xp
|
404
|
+
>>> import array_api_extra as xpx
|
405
|
+
>>> x = xp.asarray([2, 4, 8])
|
406
|
+
|
407
|
+
>>> xpx.create_diagonal(x, xp=xp)
|
408
|
+
Array([[2, 0, 0],
|
409
|
+
[0, 4, 0],
|
410
|
+
[0, 0, 8]], dtype=array_api_strict.int64)
|
411
|
+
|
412
|
+
>>> xpx.create_diagonal(x, offset=-2, xp=xp)
|
413
|
+
Array([[0, 0, 0, 0, 0],
|
414
|
+
[0, 0, 0, 0, 0],
|
415
|
+
[2, 0, 0, 0, 0],
|
416
|
+
[0, 4, 0, 0, 0],
|
417
|
+
[0, 0, 8, 0, 0]], dtype=array_api_strict.int64)
|
418
|
+
"""
|
419
|
+
if xp is None:
|
420
|
+
xp = array_namespace(x)
|
421
|
+
|
422
|
+
if x.ndim == 0:
|
423
|
+
err_msg = "`x` must be at least 1-dimensional."
|
424
|
+
raise ValueError(err_msg)
|
425
|
+
|
426
|
+
x_shape = eager_shape(x)
|
427
|
+
batch_dims = x_shape[:-1]
|
428
|
+
n = x_shape[-1] + abs(offset)
|
429
|
+
diag = xp.zeros((*batch_dims, n**2), dtype=x.dtype, device=_compat.device(x))
|
430
|
+
|
431
|
+
target_slice = slice(
|
432
|
+
offset if offset >= 0 else abs(offset) * n,
|
433
|
+
min(n * (n - offset), diag.shape[-1]),
|
434
|
+
n + 1,
|
435
|
+
)
|
436
|
+
for index in ndindex(*batch_dims):
|
437
|
+
diag = at(diag)[(*index, target_slice)].set(x[(*index, slice(None))])
|
438
|
+
return xp.reshape(diag, (*batch_dims, n, n))
|
439
|
+
|
440
|
+
|
441
|
+
def expand_dims(
|
442
|
+
a: Array, /, *, axis: int | tuple[int, ...] = (0,), xp: ModuleType | None = None
|
443
|
+
) -> Array:
|
444
|
+
"""
|
445
|
+
Expand the shape of an array.
|
446
|
+
|
447
|
+
Insert (a) new axis/axes that will appear at the position(s) specified by
|
448
|
+
`axis` in the expanded array shape.
|
449
|
+
|
450
|
+
This is ``xp.expand_dims`` for `axis` an int *or a tuple of ints*.
|
451
|
+
Roughly equivalent to ``numpy.expand_dims`` for NumPy arrays.
|
452
|
+
|
453
|
+
Parameters
|
454
|
+
----------
|
455
|
+
a : array
|
456
|
+
Array to have its shape expanded.
|
457
|
+
axis : int or tuple of ints, optional
|
458
|
+
Position(s) in the expanded axes where the new axis (or axes) is/are placed.
|
459
|
+
If multiple positions are provided, they should be unique (note that a position
|
460
|
+
given by a positive index could also be referred to by a negative index -
|
461
|
+
that will also result in an error).
|
462
|
+
Default: ``(0,)``.
|
463
|
+
xp : array_namespace, optional
|
464
|
+
The standard-compatible namespace for `a`. Default: infer.
|
465
|
+
|
466
|
+
Returns
|
467
|
+
-------
|
468
|
+
array
|
469
|
+
`a` with an expanded shape.
|
470
|
+
|
471
|
+
Examples
|
472
|
+
--------
|
473
|
+
>>> import array_api_strict as xp
|
474
|
+
>>> import array_api_extra as xpx
|
475
|
+
>>> x = xp.asarray([1, 2])
|
476
|
+
>>> x.shape
|
477
|
+
(2,)
|
478
|
+
|
479
|
+
The following is equivalent to ``x[xp.newaxis, :]`` or ``x[xp.newaxis]``:
|
480
|
+
|
481
|
+
>>> y = xpx.expand_dims(x, axis=0, xp=xp)
|
482
|
+
>>> y
|
483
|
+
Array([[1, 2]], dtype=array_api_strict.int64)
|
484
|
+
>>> y.shape
|
485
|
+
(1, 2)
|
486
|
+
|
487
|
+
The following is equivalent to ``x[:, xp.newaxis]``:
|
488
|
+
|
489
|
+
>>> y = xpx.expand_dims(x, axis=1, xp=xp)
|
490
|
+
>>> y
|
491
|
+
Array([[1],
|
492
|
+
[2]], dtype=array_api_strict.int64)
|
493
|
+
>>> y.shape
|
494
|
+
(2, 1)
|
495
|
+
|
496
|
+
``axis`` may also be a tuple:
|
497
|
+
|
498
|
+
>>> y = xpx.expand_dims(x, axis=(0, 1), xp=xp)
|
499
|
+
>>> y
|
500
|
+
Array([[[1, 2]]], dtype=array_api_strict.int64)
|
501
|
+
|
502
|
+
>>> y = xpx.expand_dims(x, axis=(2, 0), xp=xp)
|
503
|
+
>>> y
|
504
|
+
Array([[[1],
|
505
|
+
[2]]], dtype=array_api_strict.int64)
|
506
|
+
"""
|
507
|
+
if xp is None:
|
508
|
+
xp = array_namespace(a)
|
509
|
+
|
510
|
+
if not isinstance(axis, tuple):
|
511
|
+
axis = (axis,)
|
512
|
+
ndim = a.ndim + len(axis)
|
513
|
+
if axis != () and (min(axis) < -ndim or max(axis) >= ndim):
|
514
|
+
err_msg = (
|
515
|
+
f"a provided axis position is out of bounds for array of dimension {a.ndim}"
|
516
|
+
)
|
517
|
+
raise IndexError(err_msg)
|
518
|
+
axis = tuple(dim % ndim for dim in axis)
|
519
|
+
if len(set(axis)) != len(axis):
|
520
|
+
err_msg = "Duplicate dimensions specified in `axis`."
|
521
|
+
raise ValueError(err_msg)
|
522
|
+
for i in sorted(axis):
|
523
|
+
a = xp.expand_dims(a, axis=i)
|
524
|
+
return a
|
525
|
+
|
526
|
+
|
527
|
+
def isclose(
|
528
|
+
a: Array | complex,
|
529
|
+
b: Array | complex,
|
530
|
+
*,
|
531
|
+
rtol: float = 1e-05,
|
532
|
+
atol: float = 1e-08,
|
533
|
+
equal_nan: bool = False,
|
534
|
+
xp: ModuleType,
|
535
|
+
) -> Array: # numpydoc ignore=PR01,RT01
|
536
|
+
"""See docstring in array_api_extra._delegation."""
|
537
|
+
a, b = asarrays(a, b, xp=xp)
|
538
|
+
|
539
|
+
a_inexact = xp.isdtype(a.dtype, ("real floating", "complex floating"))
|
540
|
+
b_inexact = xp.isdtype(b.dtype, ("real floating", "complex floating"))
|
541
|
+
if a_inexact or b_inexact:
|
542
|
+
# prevent warnings on NumPy and Dask on inf - inf
|
543
|
+
mxp = meta_namespace(a, b, xp=xp)
|
544
|
+
out = apply_where(
|
545
|
+
xp.isinf(a) | xp.isinf(b),
|
546
|
+
(a, b),
|
547
|
+
lambda a, b: mxp.isinf(a) & mxp.isinf(b) & (mxp.sign(a) == mxp.sign(b)), # pyright: ignore[reportUnknownArgumentType]
|
548
|
+
# Note: inf <= inf is True!
|
549
|
+
lambda a, b: mxp.abs(a - b) <= (atol + rtol * mxp.abs(b)), # pyright: ignore[reportUnknownArgumentType]
|
550
|
+
xp=xp,
|
551
|
+
)
|
552
|
+
if equal_nan:
|
553
|
+
out = xp.where(xp.isnan(a) & xp.isnan(b), True, out)
|
554
|
+
return out
|
555
|
+
|
556
|
+
if xp.isdtype(a.dtype, "bool") or xp.isdtype(b.dtype, "bool"):
|
557
|
+
if atol >= 1 or rtol >= 1:
|
558
|
+
return xp.ones_like(a == b)
|
559
|
+
return a == b
|
560
|
+
|
561
|
+
# integer types
|
562
|
+
atol = int(atol)
|
563
|
+
if rtol == 0:
|
564
|
+
return xp.abs(a - b) <= atol
|
565
|
+
|
566
|
+
# Don't rely on OverflowError, as it is not guaranteed by the Array API.
|
567
|
+
nrtol = int(1.0 / rtol)
|
568
|
+
if nrtol > xp.iinfo(b.dtype).max:
|
569
|
+
# rtol * max_int < 1, so it's inconsequential
|
570
|
+
return xp.abs(a - b) <= atol
|
571
|
+
return xp.abs(a - b) <= (atol + xp.abs(b) // nrtol)
|
572
|
+
|
573
|
+
|
574
|
+
def kron(
|
575
|
+
a: Array | complex,
|
576
|
+
b: Array | complex,
|
577
|
+
/,
|
578
|
+
*,
|
579
|
+
xp: ModuleType | None = None,
|
580
|
+
) -> Array:
|
581
|
+
"""
|
582
|
+
Kronecker product of two arrays.
|
583
|
+
|
584
|
+
Computes the Kronecker product, a composite array made of blocks of the
|
585
|
+
second array scaled by the first.
|
586
|
+
|
587
|
+
Equivalent to ``numpy.kron`` for NumPy arrays.
|
588
|
+
|
589
|
+
Parameters
|
590
|
+
----------
|
591
|
+
a, b : Array | int | float | complex
|
592
|
+
Input arrays or scalars. At least one must be an array.
|
593
|
+
xp : array_namespace, optional
|
594
|
+
The standard-compatible namespace for `a` and `b`. Default: infer.
|
595
|
+
|
596
|
+
Returns
|
597
|
+
-------
|
598
|
+
array
|
599
|
+
The Kronecker product of `a` and `b`.
|
600
|
+
|
601
|
+
Notes
|
602
|
+
-----
|
603
|
+
The function assumes that the number of dimensions of `a` and `b`
|
604
|
+
are the same, if necessary prepending the smallest with ones.
|
605
|
+
If ``a.shape = (r0,r1,..,rN)`` and ``b.shape = (s0,s1,...,sN)``,
|
606
|
+
the Kronecker product has shape ``(r0*s0, r1*s1, ..., rN*SN)``.
|
607
|
+
The elements are products of elements from `a` and `b`, organized
|
608
|
+
explicitly by::
|
609
|
+
|
610
|
+
kron(a,b)[k0,k1,...,kN] = a[i0,i1,...,iN] * b[j0,j1,...,jN]
|
611
|
+
|
612
|
+
where::
|
613
|
+
|
614
|
+
kt = it * st + jt, t = 0,...,N
|
615
|
+
|
616
|
+
In the common 2-D case (N=1), the block structure can be visualized::
|
617
|
+
|
618
|
+
[[ a[0,0]*b, a[0,1]*b, ... , a[0,-1]*b ],
|
619
|
+
[ ... ... ],
|
620
|
+
[ a[-1,0]*b, a[-1,1]*b, ... , a[-1,-1]*b ]]
|
621
|
+
|
622
|
+
Examples
|
623
|
+
--------
|
624
|
+
>>> import array_api_strict as xp
|
625
|
+
>>> import array_api_extra as xpx
|
626
|
+
>>> xpx.kron(xp.asarray([1, 10, 100]), xp.asarray([5, 6, 7]), xp=xp)
|
627
|
+
Array([ 5, 6, 7, 50, 60, 70, 500,
|
628
|
+
600, 700], dtype=array_api_strict.int64)
|
629
|
+
|
630
|
+
>>> xpx.kron(xp.asarray([5, 6, 7]), xp.asarray([1, 10, 100]), xp=xp)
|
631
|
+
Array([ 5, 50, 500, 6, 60, 600, 7,
|
632
|
+
70, 700], dtype=array_api_strict.int64)
|
633
|
+
|
634
|
+
>>> xpx.kron(xp.eye(2), xp.ones((2, 2)), xp=xp)
|
635
|
+
Array([[1., 1., 0., 0.],
|
636
|
+
[1., 1., 0., 0.],
|
637
|
+
[0., 0., 1., 1.],
|
638
|
+
[0., 0., 1., 1.]], dtype=array_api_strict.float64)
|
639
|
+
|
640
|
+
>>> a = xp.reshape(xp.arange(100), (2, 5, 2, 5))
|
641
|
+
>>> b = xp.reshape(xp.arange(24), (2, 3, 4))
|
642
|
+
>>> c = xpx.kron(a, b, xp=xp)
|
643
|
+
>>> c.shape
|
644
|
+
(2, 10, 6, 20)
|
645
|
+
>>> I = (1, 3, 0, 2)
|
646
|
+
>>> J = (0, 2, 1)
|
647
|
+
>>> J1 = (0,) + J # extend to ndim=4
|
648
|
+
>>> S1 = (1,) + b.shape
|
649
|
+
>>> K = tuple(xp.asarray(I) * xp.asarray(S1) + xp.asarray(J1))
|
650
|
+
>>> c[K] == a[I]*b[J]
|
651
|
+
Array(True, dtype=array_api_strict.bool)
|
652
|
+
"""
|
653
|
+
if xp is None:
|
654
|
+
xp = array_namespace(a, b)
|
655
|
+
a, b = asarrays(a, b, xp=xp)
|
656
|
+
|
657
|
+
singletons = (1,) * (b.ndim - a.ndim)
|
658
|
+
a = cast(Array, xp.broadcast_to(a, singletons + a.shape))
|
659
|
+
|
660
|
+
nd_b, nd_a = b.ndim, a.ndim
|
661
|
+
nd_max = max(nd_b, nd_a)
|
662
|
+
if nd_a == 0 or nd_b == 0:
|
663
|
+
return xp.multiply(a, b)
|
664
|
+
|
665
|
+
a_shape = eager_shape(a)
|
666
|
+
b_shape = eager_shape(b)
|
667
|
+
|
668
|
+
# Equalise the shapes by prepending smaller one with 1s
|
669
|
+
a_shape = (1,) * max(0, nd_b - nd_a) + a_shape
|
670
|
+
b_shape = (1,) * max(0, nd_a - nd_b) + b_shape
|
671
|
+
|
672
|
+
# Insert empty dimensions
|
673
|
+
a_arr = expand_dims(a, axis=tuple(range(nd_b - nd_a)), xp=xp)
|
674
|
+
b_arr = expand_dims(b, axis=tuple(range(nd_a - nd_b)), xp=xp)
|
675
|
+
|
676
|
+
# Compute the product
|
677
|
+
a_arr = expand_dims(a_arr, axis=tuple(range(1, nd_max * 2, 2)), xp=xp)
|
678
|
+
b_arr = expand_dims(b_arr, axis=tuple(range(0, nd_max * 2, 2)), xp=xp)
|
679
|
+
result = xp.multiply(a_arr, b_arr)
|
680
|
+
|
681
|
+
# Reshape back and return
|
682
|
+
res_shape = tuple(a_s * b_s for a_s, b_s in zip(a_shape, b_shape, strict=True))
|
683
|
+
return xp.reshape(result, res_shape)
|
684
|
+
|
685
|
+
|
686
|
+
def nunique(x: Array, /, *, xp: ModuleType | None = None) -> Array:
|
687
|
+
"""
|
688
|
+
Count the number of unique elements in an array.
|
689
|
+
|
690
|
+
Compatible with JAX and Dask, whose laziness would be otherwise
|
691
|
+
problematic.
|
692
|
+
|
693
|
+
Parameters
|
694
|
+
----------
|
695
|
+
x : Array
|
696
|
+
Input array.
|
697
|
+
xp : array_namespace, optional
|
698
|
+
The standard-compatible namespace for `x`. Default: infer.
|
699
|
+
|
700
|
+
Returns
|
701
|
+
-------
|
702
|
+
array: 0-dimensional integer array
|
703
|
+
The number of unique elements in `x`. It can be lazy.
|
704
|
+
"""
|
705
|
+
if xp is None:
|
706
|
+
xp = array_namespace(x)
|
707
|
+
|
708
|
+
if is_jax_array(x):
|
709
|
+
# size= is JAX-specific
|
710
|
+
# https://github.com/data-apis/array-api/issues/883
|
711
|
+
_, counts = xp.unique_counts(x, size=_compat.size(x))
|
712
|
+
return (counts > 0).sum()
|
713
|
+
|
714
|
+
# There are 3 general use cases:
|
715
|
+
# 1. backend has unique_counts and it returns an array with known shape
|
716
|
+
# 2. backend has unique_counts and it returns a None-sized array;
|
717
|
+
# e.g. Dask, ndonnx
|
718
|
+
# 3. backend does not have unique_counts; e.g. wrapped JAX
|
719
|
+
if capabilities(xp)["data-dependent shapes"]:
|
720
|
+
# xp has unique_counts; O(n) complexity
|
721
|
+
_, counts = xp.unique_counts(x)
|
722
|
+
n = _compat.size(counts)
|
723
|
+
if n is None:
|
724
|
+
return xp.sum(xp.ones_like(counts))
|
725
|
+
return xp.asarray(n, device=_compat.device(x))
|
726
|
+
|
727
|
+
# xp does not have unique_counts; O(n*logn) complexity
|
728
|
+
x = xp.reshape(x, (-1,))
|
729
|
+
x = xp.sort(x)
|
730
|
+
mask = x != xp.roll(x, -1)
|
731
|
+
default_int = xp.__array_namespace_info__().default_dtypes(
|
732
|
+
device=_compat.device(x)
|
733
|
+
)["integral"]
|
734
|
+
return xp.maximum(
|
735
|
+
# Special cases:
|
736
|
+
# - array is size 0
|
737
|
+
# - array has all elements equal to each other
|
738
|
+
xp.astype(xp.any(~mask), default_int),
|
739
|
+
xp.sum(xp.astype(mask, default_int)),
|
740
|
+
)
|
741
|
+
|
742
|
+
|
743
|
+
def pad(
|
744
|
+
x: Array,
|
745
|
+
pad_width: int | tuple[int, int] | Sequence[tuple[int, int]],
|
746
|
+
*,
|
747
|
+
constant_values: complex = 0,
|
748
|
+
xp: ModuleType,
|
749
|
+
) -> Array: # numpydoc ignore=PR01,RT01
|
750
|
+
"""See docstring in `array_api_extra._delegation.py`."""
|
751
|
+
# make pad_width a list of length-2 tuples of ints
|
752
|
+
if isinstance(pad_width, int):
|
753
|
+
pad_width_seq = [(pad_width, pad_width)] * x.ndim
|
754
|
+
elif (
|
755
|
+
isinstance(pad_width, tuple)
|
756
|
+
and len(pad_width) == 2
|
757
|
+
and all(isinstance(i, int) for i in pad_width)
|
758
|
+
):
|
759
|
+
pad_width_seq = [cast(tuple[int, int], pad_width)] * x.ndim
|
760
|
+
else:
|
761
|
+
pad_width_seq = cast(list[tuple[int, int]], list(pad_width))
|
762
|
+
|
763
|
+
# https://github.com/python/typeshed/issues/13376
|
764
|
+
slices: list[slice] = [] # type: ignore[explicit-any]
|
765
|
+
newshape: list[int] = []
|
766
|
+
for ax, w_tpl in enumerate(pad_width_seq):
|
767
|
+
if len(w_tpl) != 2:
|
768
|
+
msg = f"expect a 2-tuple (before, after), got {w_tpl}."
|
769
|
+
raise ValueError(msg)
|
770
|
+
|
771
|
+
sh = eager_shape(x)[ax]
|
772
|
+
|
773
|
+
if w_tpl[0] == 0 and w_tpl[1] == 0:
|
774
|
+
sl = slice(None, None, None)
|
775
|
+
else:
|
776
|
+
start, stop = w_tpl
|
777
|
+
stop = None if stop == 0 else -stop
|
778
|
+
|
779
|
+
sl = slice(start, stop, None)
|
780
|
+
sh += w_tpl[0] + w_tpl[1]
|
781
|
+
|
782
|
+
newshape.append(sh)
|
783
|
+
slices.append(sl)
|
784
|
+
|
785
|
+
padded = xp.full(
|
786
|
+
tuple(newshape),
|
787
|
+
fill_value=constant_values,
|
788
|
+
dtype=x.dtype,
|
789
|
+
device=_compat.device(x),
|
790
|
+
)
|
791
|
+
return at(padded, tuple(slices)).set(x)
|
792
|
+
|
793
|
+
|
794
|
+
def setdiff1d(
|
795
|
+
x1: Array | complex,
|
796
|
+
x2: Array | complex,
|
797
|
+
/,
|
798
|
+
*,
|
799
|
+
assume_unique: bool = False,
|
800
|
+
xp: ModuleType | None = None,
|
801
|
+
) -> Array:
|
802
|
+
"""
|
803
|
+
Find the set difference of two arrays.
|
804
|
+
|
805
|
+
Return the unique values in `x1` that are not in `x2`.
|
806
|
+
|
807
|
+
Parameters
|
808
|
+
----------
|
809
|
+
x1 : array | int | float | complex | bool
|
810
|
+
Input array.
|
811
|
+
x2 : array
|
812
|
+
Input comparison array.
|
813
|
+
assume_unique : bool
|
814
|
+
If ``True``, the input arrays are both assumed to be unique, which
|
815
|
+
can speed up the calculation. Default is ``False``.
|
816
|
+
xp : array_namespace, optional
|
817
|
+
The standard-compatible namespace for `x1` and `x2`. Default: infer.
|
818
|
+
|
819
|
+
Returns
|
820
|
+
-------
|
821
|
+
array
|
822
|
+
1D array of values in `x1` that are not in `x2`. The result
|
823
|
+
is sorted when `assume_unique` is ``False``, but otherwise only sorted
|
824
|
+
if the input is sorted.
|
825
|
+
|
826
|
+
Examples
|
827
|
+
--------
|
828
|
+
>>> import array_api_strict as xp
|
829
|
+
>>> import array_api_extra as xpx
|
830
|
+
|
831
|
+
>>> x1 = xp.asarray([1, 2, 3, 2, 4, 1])
|
832
|
+
>>> x2 = xp.asarray([3, 4, 5, 6])
|
833
|
+
>>> xpx.setdiff1d(x1, x2, xp=xp)
|
834
|
+
Array([1, 2], dtype=array_api_strict.int64)
|
835
|
+
"""
|
836
|
+
if xp is None:
|
837
|
+
xp = array_namespace(x1, x2)
|
838
|
+
# https://github.com/microsoft/pyright/issues/10103
|
839
|
+
x1_, x2_ = asarrays(x1, x2, xp=xp)
|
840
|
+
|
841
|
+
if assume_unique:
|
842
|
+
x1_ = xp.reshape(x1_, (-1,))
|
843
|
+
x2_ = xp.reshape(x2_, (-1,))
|
844
|
+
else:
|
845
|
+
x1_ = xp.unique_values(x1_)
|
846
|
+
x2_ = xp.unique_values(x2_)
|
847
|
+
|
848
|
+
return x1_[_helpers.in1d(x1_, x2_, assume_unique=True, invert=True, xp=xp)]
|
849
|
+
|
850
|
+
|
851
|
+
def sinc(x: Array, /, *, xp: ModuleType | None = None) -> Array:
|
852
|
+
r"""
|
853
|
+
Return the normalized sinc function.
|
854
|
+
|
855
|
+
The sinc function is equal to :math:`\sin(\pi x)/(\pi x)` for any argument
|
856
|
+
:math:`x\ne 0`. ``sinc(0)`` takes the limit value 1, making ``sinc`` not
|
857
|
+
only everywhere continuous but also infinitely differentiable.
|
858
|
+
|
859
|
+
.. note::
|
860
|
+
|
861
|
+
Note the normalization factor of ``pi`` used in the definition.
|
862
|
+
This is the most commonly used definition in signal processing.
|
863
|
+
Use ``sinc(x / xp.pi)`` to obtain the unnormalized sinc function
|
864
|
+
:math:`\sin(x)/x` that is more common in mathematics.
|
865
|
+
|
866
|
+
Parameters
|
867
|
+
----------
|
868
|
+
x : array
|
869
|
+
Array (possibly multi-dimensional) of values for which to calculate
|
870
|
+
``sinc(x)``. Must have a real floating point dtype.
|
871
|
+
xp : array_namespace, optional
|
872
|
+
The standard-compatible namespace for `x`. Default: infer.
|
873
|
+
|
874
|
+
Returns
|
875
|
+
-------
|
876
|
+
array
|
877
|
+
``sinc(x)`` calculated elementwise, which has the same shape as the input.
|
878
|
+
|
879
|
+
Notes
|
880
|
+
-----
|
881
|
+
The name sinc is short for "sine cardinal" or "sinus cardinalis".
|
882
|
+
|
883
|
+
The sinc function is used in various signal processing applications,
|
884
|
+
including in anti-aliasing, in the construction of a Lanczos resampling
|
885
|
+
filter, and in interpolation.
|
886
|
+
|
887
|
+
For bandlimited interpolation of discrete-time signals, the ideal
|
888
|
+
interpolation kernel is proportional to the sinc function.
|
889
|
+
|
890
|
+
References
|
891
|
+
----------
|
892
|
+
#. Weisstein, Eric W. "Sinc Function." From MathWorld--A Wolfram Web
|
893
|
+
Resource. https://mathworld.wolfram.com/SincFunction.html
|
894
|
+
#. Wikipedia, "Sinc function",
|
895
|
+
https://en.wikipedia.org/wiki/Sinc_function
|
896
|
+
|
897
|
+
Examples
|
898
|
+
--------
|
899
|
+
>>> import array_api_strict as xp
|
900
|
+
>>> import array_api_extra as xpx
|
901
|
+
>>> x = xp.linspace(-4, 4, 41)
|
902
|
+
>>> xpx.sinc(x, xp=xp)
|
903
|
+
Array([-3.89817183e-17, -4.92362781e-02,
|
904
|
+
-8.40918587e-02, -8.90384387e-02,
|
905
|
+
-5.84680802e-02, 3.89817183e-17,
|
906
|
+
6.68206631e-02, 1.16434881e-01,
|
907
|
+
1.26137788e-01, 8.50444803e-02,
|
908
|
+
-3.89817183e-17, -1.03943254e-01,
|
909
|
+
-1.89206682e-01, -2.16236208e-01,
|
910
|
+
-1.55914881e-01, 3.89817183e-17,
|
911
|
+
2.33872321e-01, 5.04551152e-01,
|
912
|
+
7.56826729e-01, 9.35489284e-01,
|
913
|
+
1.00000000e+00, 9.35489284e-01,
|
914
|
+
7.56826729e-01, 5.04551152e-01,
|
915
|
+
2.33872321e-01, 3.89817183e-17,
|
916
|
+
-1.55914881e-01, -2.16236208e-01,
|
917
|
+
-1.89206682e-01, -1.03943254e-01,
|
918
|
+
-3.89817183e-17, 8.50444803e-02,
|
919
|
+
1.26137788e-01, 1.16434881e-01,
|
920
|
+
6.68206631e-02, 3.89817183e-17,
|
921
|
+
-5.84680802e-02, -8.90384387e-02,
|
922
|
+
-8.40918587e-02, -4.92362781e-02,
|
923
|
+
-3.89817183e-17], dtype=array_api_strict.float64)
|
924
|
+
"""
|
925
|
+
if xp is None:
|
926
|
+
xp = array_namespace(x)
|
927
|
+
|
928
|
+
if not xp.isdtype(x.dtype, "real floating"):
|
929
|
+
err_msg = "`x` must have a real floating data type."
|
930
|
+
raise ValueError(err_msg)
|
931
|
+
# no scalars in `where` - array-api#807
|
932
|
+
y = xp.pi * xp.where(
|
933
|
+
xp.astype(x, xp.bool),
|
934
|
+
x,
|
935
|
+
xp.asarray(xp.finfo(x.dtype).eps, dtype=x.dtype, device=_compat.device(x)),
|
936
|
+
)
|
937
|
+
return xp.sin(y) / y
|