scipy 1.15.3__cp313-cp313-macosx_12_0_arm64.whl → 1.16.0rc2__cp313-cp313-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.
Files changed (629) hide show
  1. scipy/.dylibs/libscipy_openblas.dylib +0 -0
  2. scipy/__config__.py +8 -8
  3. scipy/__init__.py +3 -6
  4. scipy/_cyutility.cpython-313-darwin.so +0 -0
  5. scipy/_lib/_array_api.py +486 -161
  6. scipy/_lib/_array_api_compat_vendor.py +9 -0
  7. scipy/_lib/_bunch.py +4 -0
  8. scipy/_lib/_ccallback_c.cpython-313-darwin.so +0 -0
  9. scipy/_lib/_docscrape.py +1 -1
  10. scipy/_lib/_elementwise_iterative_method.py +15 -26
  11. scipy/_lib/_sparse.py +41 -0
  12. scipy/_lib/_test_deprecation_call.cpython-313-darwin.so +0 -0
  13. scipy/_lib/_test_deprecation_def.cpython-313-darwin.so +0 -0
  14. scipy/_lib/_testutils.py +6 -2
  15. scipy/_lib/_util.py +222 -125
  16. scipy/_lib/array_api_compat/__init__.py +4 -4
  17. scipy/_lib/array_api_compat/_internal.py +19 -6
  18. scipy/_lib/array_api_compat/common/__init__.py +1 -1
  19. scipy/_lib/array_api_compat/common/_aliases.py +365 -193
  20. scipy/_lib/array_api_compat/common/_fft.py +94 -64
  21. scipy/_lib/array_api_compat/common/_helpers.py +413 -180
  22. scipy/_lib/array_api_compat/common/_linalg.py +116 -40
  23. scipy/_lib/array_api_compat/common/_typing.py +179 -10
  24. scipy/_lib/array_api_compat/cupy/__init__.py +1 -4
  25. scipy/_lib/array_api_compat/cupy/_aliases.py +61 -41
  26. scipy/_lib/array_api_compat/cupy/_info.py +16 -6
  27. scipy/_lib/array_api_compat/cupy/_typing.py +24 -39
  28. scipy/_lib/array_api_compat/dask/array/__init__.py +6 -3
  29. scipy/_lib/array_api_compat/dask/array/_aliases.py +267 -108
  30. scipy/_lib/array_api_compat/dask/array/_info.py +105 -34
  31. scipy/_lib/array_api_compat/dask/array/fft.py +5 -8
  32. scipy/_lib/array_api_compat/dask/array/linalg.py +21 -22
  33. scipy/_lib/array_api_compat/numpy/__init__.py +13 -15
  34. scipy/_lib/array_api_compat/numpy/_aliases.py +98 -49
  35. scipy/_lib/array_api_compat/numpy/_info.py +36 -16
  36. scipy/_lib/array_api_compat/numpy/_typing.py +27 -43
  37. scipy/_lib/array_api_compat/numpy/fft.py +11 -5
  38. scipy/_lib/array_api_compat/numpy/linalg.py +75 -22
  39. scipy/_lib/array_api_compat/torch/__init__.py +3 -5
  40. scipy/_lib/array_api_compat/torch/_aliases.py +262 -159
  41. scipy/_lib/array_api_compat/torch/_info.py +27 -16
  42. scipy/_lib/array_api_compat/torch/_typing.py +3 -0
  43. scipy/_lib/array_api_compat/torch/fft.py +17 -18
  44. scipy/_lib/array_api_compat/torch/linalg.py +16 -16
  45. scipy/_lib/array_api_extra/__init__.py +26 -3
  46. scipy/_lib/array_api_extra/_delegation.py +171 -0
  47. scipy/_lib/array_api_extra/_lib/__init__.py +1 -0
  48. scipy/_lib/array_api_extra/_lib/_at.py +463 -0
  49. scipy/_lib/array_api_extra/_lib/_backends.py +46 -0
  50. scipy/_lib/array_api_extra/_lib/_funcs.py +937 -0
  51. scipy/_lib/array_api_extra/_lib/_lazy.py +357 -0
  52. scipy/_lib/array_api_extra/_lib/_testing.py +278 -0
  53. scipy/_lib/array_api_extra/_lib/_utils/__init__.py +1 -0
  54. scipy/_lib/array_api_extra/_lib/_utils/_compat.py +74 -0
  55. scipy/_lib/array_api_extra/_lib/_utils/_compat.pyi +45 -0
  56. scipy/_lib/array_api_extra/_lib/_utils/_helpers.py +559 -0
  57. scipy/_lib/array_api_extra/_lib/_utils/_typing.py +10 -0
  58. scipy/_lib/array_api_extra/_lib/_utils/_typing.pyi +105 -0
  59. scipy/_lib/array_api_extra/testing.py +359 -0
  60. scipy/_lib/decorator.py +2 -2
  61. scipy/_lib/doccer.py +1 -7
  62. scipy/_lib/messagestream.cpython-313-darwin.so +0 -0
  63. scipy/_lib/pyprima/__init__.py +212 -0
  64. scipy/_lib/pyprima/cobyla/__init__.py +0 -0
  65. scipy/_lib/pyprima/cobyla/cobyla.py +559 -0
  66. scipy/_lib/pyprima/cobyla/cobylb.py +714 -0
  67. scipy/_lib/pyprima/cobyla/geometry.py +226 -0
  68. scipy/_lib/pyprima/cobyla/initialize.py +215 -0
  69. scipy/_lib/pyprima/cobyla/trustregion.py +492 -0
  70. scipy/_lib/pyprima/cobyla/update.py +289 -0
  71. scipy/_lib/pyprima/common/__init__.py +0 -0
  72. scipy/_lib/pyprima/common/_bounds.py +34 -0
  73. scipy/_lib/pyprima/common/_linear_constraints.py +46 -0
  74. scipy/_lib/pyprima/common/_nonlinear_constraints.py +54 -0
  75. scipy/_lib/pyprima/common/_project.py +173 -0
  76. scipy/_lib/pyprima/common/checkbreak.py +93 -0
  77. scipy/_lib/pyprima/common/consts.py +47 -0
  78. scipy/_lib/pyprima/common/evaluate.py +99 -0
  79. scipy/_lib/pyprima/common/history.py +38 -0
  80. scipy/_lib/pyprima/common/infos.py +30 -0
  81. scipy/_lib/pyprima/common/linalg.py +435 -0
  82. scipy/_lib/pyprima/common/message.py +290 -0
  83. scipy/_lib/pyprima/common/powalg.py +131 -0
  84. scipy/_lib/pyprima/common/preproc.py +277 -0
  85. scipy/_lib/pyprima/common/present.py +5 -0
  86. scipy/_lib/pyprima/common/ratio.py +54 -0
  87. scipy/_lib/pyprima/common/redrho.py +47 -0
  88. scipy/_lib/pyprima/common/selectx.py +296 -0
  89. scipy/_lib/tests/test__util.py +105 -121
  90. scipy/_lib/tests/test_array_api.py +166 -35
  91. scipy/_lib/tests/test_bunch.py +7 -0
  92. scipy/_lib/tests/test_ccallback.py +2 -10
  93. scipy/_lib/tests/test_public_api.py +13 -0
  94. scipy/cluster/_hierarchy.cpython-313-darwin.so +0 -0
  95. scipy/cluster/_optimal_leaf_ordering.cpython-313-darwin.so +0 -0
  96. scipy/cluster/_vq.cpython-313-darwin.so +0 -0
  97. scipy/cluster/hierarchy.py +393 -223
  98. scipy/cluster/tests/test_hierarchy.py +273 -335
  99. scipy/cluster/tests/test_vq.py +45 -61
  100. scipy/cluster/vq.py +39 -35
  101. scipy/conftest.py +263 -157
  102. scipy/constants/_constants.py +4 -1
  103. scipy/constants/tests/test_codata.py +2 -2
  104. scipy/constants/tests/test_constants.py +11 -18
  105. scipy/datasets/_download_all.py +15 -1
  106. scipy/datasets/_fetchers.py +7 -1
  107. scipy/datasets/_utils.py +1 -1
  108. scipy/differentiate/_differentiate.py +25 -25
  109. scipy/differentiate/tests/test_differentiate.py +24 -25
  110. scipy/fft/_basic.py +20 -0
  111. scipy/fft/_helper.py +3 -34
  112. scipy/fft/_pocketfft/helper.py +29 -1
  113. scipy/fft/_pocketfft/tests/test_basic.py +2 -4
  114. scipy/fft/_pocketfft/tests/test_real_transforms.py +4 -4
  115. scipy/fft/_realtransforms.py +13 -0
  116. scipy/fft/tests/test_basic.py +27 -25
  117. scipy/fft/tests/test_fftlog.py +16 -7
  118. scipy/fft/tests/test_helper.py +18 -34
  119. scipy/fft/tests/test_real_transforms.py +8 -10
  120. scipy/fftpack/convolve.cpython-313-darwin.so +0 -0
  121. scipy/fftpack/tests/test_basic.py +2 -4
  122. scipy/fftpack/tests/test_real_transforms.py +8 -9
  123. scipy/integrate/_bvp.py +9 -3
  124. scipy/integrate/_cubature.py +3 -2
  125. scipy/integrate/_dop.cpython-313-darwin.so +0 -0
  126. scipy/integrate/_lsoda.cpython-313-darwin.so +0 -0
  127. scipy/integrate/_ode.py +9 -2
  128. scipy/integrate/_odepack.cpython-313-darwin.so +0 -0
  129. scipy/integrate/_quad_vec.py +21 -29
  130. scipy/integrate/_quadpack.cpython-313-darwin.so +0 -0
  131. scipy/integrate/_quadpack_py.py +11 -7
  132. scipy/integrate/_quadrature.py +3 -3
  133. scipy/integrate/_rules/_base.py +2 -2
  134. scipy/integrate/_tanhsinh.py +48 -47
  135. scipy/integrate/_test_odeint_banded.cpython-313-darwin.so +0 -0
  136. scipy/integrate/_vode.cpython-313-darwin.so +0 -0
  137. scipy/integrate/tests/test__quad_vec.py +0 -6
  138. scipy/integrate/tests/test_banded_ode_solvers.py +85 -0
  139. scipy/integrate/tests/test_cubature.py +21 -35
  140. scipy/integrate/tests/test_quadrature.py +6 -8
  141. scipy/integrate/tests/test_tanhsinh.py +56 -48
  142. scipy/interpolate/__init__.py +70 -58
  143. scipy/interpolate/_bary_rational.py +22 -22
  144. scipy/interpolate/_bsplines.py +119 -66
  145. scipy/interpolate/_cubic.py +65 -50
  146. scipy/interpolate/_dfitpack.cpython-313-darwin.so +0 -0
  147. scipy/interpolate/_dierckx.cpython-313-darwin.so +0 -0
  148. scipy/interpolate/_fitpack.cpython-313-darwin.so +0 -0
  149. scipy/interpolate/_fitpack2.py +9 -6
  150. scipy/interpolate/_fitpack_impl.py +32 -26
  151. scipy/interpolate/_fitpack_repro.py +23 -19
  152. scipy/interpolate/_interpnd.cpython-313-darwin.so +0 -0
  153. scipy/interpolate/_interpolate.py +30 -12
  154. scipy/interpolate/_ndbspline.py +13 -18
  155. scipy/interpolate/_ndgriddata.py +5 -8
  156. scipy/interpolate/_polyint.py +95 -31
  157. scipy/interpolate/_ppoly.cpython-313-darwin.so +0 -0
  158. scipy/interpolate/_rbf.py +2 -2
  159. scipy/interpolate/_rbfinterp.py +1 -1
  160. scipy/interpolate/_rbfinterp_pythran.cpython-313-darwin.so +0 -0
  161. scipy/interpolate/_rgi.py +31 -26
  162. scipy/interpolate/_rgi_cython.cpython-313-darwin.so +0 -0
  163. scipy/interpolate/dfitpack.py +0 -20
  164. scipy/interpolate/interpnd.py +1 -2
  165. scipy/interpolate/tests/test_bary_rational.py +2 -2
  166. scipy/interpolate/tests/test_bsplines.py +97 -1
  167. scipy/interpolate/tests/test_fitpack2.py +39 -1
  168. scipy/interpolate/tests/test_interpnd.py +32 -20
  169. scipy/interpolate/tests/test_interpolate.py +48 -4
  170. scipy/interpolate/tests/test_rgi.py +2 -1
  171. scipy/io/_fast_matrix_market/__init__.py +2 -0
  172. scipy/io/_harwell_boeing/_fortran_format_parser.py +19 -16
  173. scipy/io/_harwell_boeing/hb.py +7 -11
  174. scipy/io/_idl.py +5 -7
  175. scipy/io/_netcdf.py +15 -5
  176. scipy/io/_test_fortran.cpython-313-darwin.so +0 -0
  177. scipy/io/arff/tests/test_arffread.py +3 -3
  178. scipy/io/matlab/__init__.py +5 -3
  179. scipy/io/matlab/_mio.py +4 -1
  180. scipy/io/matlab/_mio5.py +19 -13
  181. scipy/io/matlab/_mio5_utils.cpython-313-darwin.so +0 -0
  182. scipy/io/matlab/_mio_utils.cpython-313-darwin.so +0 -0
  183. scipy/io/matlab/_miobase.py +4 -1
  184. scipy/io/matlab/_streams.cpython-313-darwin.so +0 -0
  185. scipy/io/matlab/tests/test_mio.py +46 -18
  186. scipy/io/matlab/tests/test_mio_funcs.py +1 -1
  187. scipy/io/tests/test_mmio.py +7 -1
  188. scipy/io/tests/test_wavfile.py +41 -0
  189. scipy/io/wavfile.py +57 -10
  190. scipy/linalg/_basic.py +113 -86
  191. scipy/linalg/_cythonized_array_utils.cpython-313-darwin.so +0 -0
  192. scipy/linalg/_decomp.py +22 -9
  193. scipy/linalg/_decomp_cholesky.py +28 -13
  194. scipy/linalg/_decomp_cossin.py +45 -30
  195. scipy/linalg/_decomp_interpolative.cpython-313-darwin.so +0 -0
  196. scipy/linalg/_decomp_ldl.py +4 -1
  197. scipy/linalg/_decomp_lu.py +18 -6
  198. scipy/linalg/_decomp_lu_cython.cpython-313-darwin.so +0 -0
  199. scipy/linalg/_decomp_polar.py +2 -0
  200. scipy/linalg/_decomp_qr.py +6 -2
  201. scipy/linalg/_decomp_qz.py +3 -0
  202. scipy/linalg/_decomp_schur.py +3 -1
  203. scipy/linalg/_decomp_svd.py +13 -2
  204. scipy/linalg/_decomp_update.cpython-313-darwin.so +0 -0
  205. scipy/linalg/_expm_frechet.py +4 -0
  206. scipy/linalg/_fblas.cpython-313-darwin.so +0 -0
  207. scipy/linalg/_flapack.cpython-313-darwin.so +0 -0
  208. scipy/linalg/_linalg_pythran.cpython-313-darwin.so +0 -0
  209. scipy/linalg/_matfuncs.py +187 -4
  210. scipy/linalg/_matfuncs_expm.cpython-313-darwin.so +0 -0
  211. scipy/linalg/_matfuncs_schur_sqrtm.cpython-313-darwin.so +0 -0
  212. scipy/linalg/_matfuncs_sqrtm.py +1 -99
  213. scipy/linalg/_matfuncs_sqrtm_triu.cpython-313-darwin.so +0 -0
  214. scipy/linalg/_procrustes.py +2 -0
  215. scipy/linalg/_sketches.py +17 -6
  216. scipy/linalg/_solve_toeplitz.cpython-313-darwin.so +0 -0
  217. scipy/linalg/_solvers.py +7 -2
  218. scipy/linalg/_special_matrices.py +26 -36
  219. scipy/linalg/cython_blas.cpython-313-darwin.so +0 -0
  220. scipy/linalg/cython_lapack.cpython-313-darwin.so +0 -0
  221. scipy/linalg/lapack.py +22 -2
  222. scipy/linalg/tests/_cython_examples/meson.build +7 -0
  223. scipy/linalg/tests/test_basic.py +31 -16
  224. scipy/linalg/tests/test_batch.py +588 -0
  225. scipy/linalg/tests/test_cythonized_array_utils.py +0 -2
  226. scipy/linalg/tests/test_decomp.py +40 -3
  227. scipy/linalg/tests/test_decomp_cossin.py +14 -0
  228. scipy/linalg/tests/test_decomp_ldl.py +1 -1
  229. scipy/linalg/tests/test_lapack.py +115 -7
  230. scipy/linalg/tests/test_matfuncs.py +157 -102
  231. scipy/linalg/tests/test_procrustes.py +0 -7
  232. scipy/linalg/tests/test_solve_toeplitz.py +1 -1
  233. scipy/linalg/tests/test_special_matrices.py +1 -5
  234. scipy/ndimage/__init__.py +1 -0
  235. scipy/ndimage/_cytest.cpython-313-darwin.so +0 -0
  236. scipy/ndimage/_delegators.py +8 -2
  237. scipy/ndimage/_filters.py +453 -5
  238. scipy/ndimage/_interpolation.py +36 -6
  239. scipy/ndimage/_measurements.py +4 -2
  240. scipy/ndimage/_morphology.py +5 -0
  241. scipy/ndimage/_nd_image.cpython-313-darwin.so +0 -0
  242. scipy/ndimage/_ni_docstrings.py +5 -1
  243. scipy/ndimage/_ni_label.cpython-313-darwin.so +0 -0
  244. scipy/ndimage/_ni_support.py +1 -5
  245. scipy/ndimage/_rank_filter_1d.cpython-313-darwin.so +0 -0
  246. scipy/ndimage/_support_alternative_backends.py +18 -6
  247. scipy/ndimage/tests/test_filters.py +370 -259
  248. scipy/ndimage/tests/test_fourier.py +7 -9
  249. scipy/ndimage/tests/test_interpolation.py +68 -61
  250. scipy/ndimage/tests/test_measurements.py +18 -35
  251. scipy/ndimage/tests/test_morphology.py +143 -131
  252. scipy/ndimage/tests/test_splines.py +1 -3
  253. scipy/odr/__odrpack.cpython-313-darwin.so +0 -0
  254. scipy/optimize/_basinhopping.py +13 -7
  255. scipy/optimize/_bglu_dense.cpython-313-darwin.so +0 -0
  256. scipy/optimize/_bracket.py +17 -24
  257. scipy/optimize/_chandrupatla.py +9 -10
  258. scipy/optimize/_cobyla_py.py +104 -123
  259. scipy/optimize/_constraints.py +14 -10
  260. scipy/optimize/_differentiable_functions.py +371 -230
  261. scipy/optimize/_differentialevolution.py +4 -3
  262. scipy/optimize/_direct.cpython-313-darwin.so +0 -0
  263. scipy/optimize/_dual_annealing.py +1 -1
  264. scipy/optimize/_elementwise.py +1 -4
  265. scipy/optimize/_group_columns.cpython-313-darwin.so +0 -0
  266. scipy/optimize/_lbfgsb.cpython-313-darwin.so +0 -0
  267. scipy/optimize/_lbfgsb_py.py +57 -16
  268. scipy/optimize/_linprog_doc.py +2 -2
  269. scipy/optimize/_linprog_highs.py +2 -2
  270. scipy/optimize/_linprog_ip.py +25 -10
  271. scipy/optimize/_linprog_util.py +14 -16
  272. scipy/optimize/_lsap.cpython-313-darwin.so +0 -0
  273. scipy/optimize/_lsq/common.py +3 -3
  274. scipy/optimize/_lsq/dogbox.py +16 -2
  275. scipy/optimize/_lsq/givens_elimination.cpython-313-darwin.so +0 -0
  276. scipy/optimize/_lsq/least_squares.py +198 -126
  277. scipy/optimize/_lsq/lsq_linear.py +6 -6
  278. scipy/optimize/_lsq/trf.py +35 -8
  279. scipy/optimize/_milp.py +3 -1
  280. scipy/optimize/_minimize.py +105 -36
  281. scipy/optimize/_minpack.cpython-313-darwin.so +0 -0
  282. scipy/optimize/_minpack_py.py +21 -14
  283. scipy/optimize/_moduleTNC.cpython-313-darwin.so +0 -0
  284. scipy/optimize/_nnls.py +20 -21
  285. scipy/optimize/_nonlin.py +34 -3
  286. scipy/optimize/_numdiff.py +288 -110
  287. scipy/optimize/_optimize.py +86 -48
  288. scipy/optimize/_pava_pybind.cpython-313-darwin.so +0 -0
  289. scipy/optimize/_remove_redundancy.py +5 -5
  290. scipy/optimize/_root_scalar.py +1 -1
  291. scipy/optimize/_shgo.py +6 -0
  292. scipy/optimize/_shgo_lib/_complex.py +1 -1
  293. scipy/optimize/_slsqp_py.py +216 -124
  294. scipy/optimize/_slsqplib.cpython-313-darwin.so +0 -0
  295. scipy/optimize/_spectral.py +1 -1
  296. scipy/optimize/_tnc.py +8 -1
  297. scipy/optimize/_trlib/_trlib.cpython-313-darwin.so +0 -0
  298. scipy/optimize/_trustregion.py +20 -6
  299. scipy/optimize/_trustregion_constr/canonical_constraint.py +7 -7
  300. scipy/optimize/_trustregion_constr/equality_constrained_sqp.py +1 -1
  301. scipy/optimize/_trustregion_constr/minimize_trustregion_constr.py +11 -3
  302. scipy/optimize/_trustregion_constr/projections.py +12 -8
  303. scipy/optimize/_trustregion_constr/qp_subproblem.py +9 -9
  304. scipy/optimize/_trustregion_constr/tests/test_projections.py +7 -7
  305. scipy/optimize/_trustregion_constr/tests/test_qp_subproblem.py +77 -77
  306. scipy/optimize/_trustregion_constr/tr_interior_point.py +5 -5
  307. scipy/optimize/_trustregion_exact.py +0 -1
  308. scipy/optimize/_zeros.cpython-313-darwin.so +0 -0
  309. scipy/optimize/_zeros_py.py +97 -17
  310. scipy/optimize/cython_optimize/_zeros.cpython-313-darwin.so +0 -0
  311. scipy/optimize/slsqp.py +0 -1
  312. scipy/optimize/tests/test__basinhopping.py +1 -1
  313. scipy/optimize/tests/test__differential_evolution.py +4 -4
  314. scipy/optimize/tests/test__linprog_clean_inputs.py +5 -3
  315. scipy/optimize/tests/test__numdiff.py +66 -22
  316. scipy/optimize/tests/test__remove_redundancy.py +2 -2
  317. scipy/optimize/tests/test__shgo.py +9 -1
  318. scipy/optimize/tests/test_bracket.py +36 -46
  319. scipy/optimize/tests/test_chandrupatla.py +133 -135
  320. scipy/optimize/tests/test_cobyla.py +74 -45
  321. scipy/optimize/tests/test_constraints.py +1 -1
  322. scipy/optimize/tests/test_differentiable_functions.py +226 -6
  323. scipy/optimize/tests/test_lbfgsb_hessinv.py +22 -0
  324. scipy/optimize/tests/test_least_squares.py +125 -13
  325. scipy/optimize/tests/test_linear_assignment.py +3 -3
  326. scipy/optimize/tests/test_linprog.py +3 -3
  327. scipy/optimize/tests/test_lsq_linear.py +6 -6
  328. scipy/optimize/tests/test_minimize_constrained.py +2 -2
  329. scipy/optimize/tests/test_minpack.py +4 -4
  330. scipy/optimize/tests/test_nnls.py +43 -3
  331. scipy/optimize/tests/test_nonlin.py +36 -0
  332. scipy/optimize/tests/test_optimize.py +95 -17
  333. scipy/optimize/tests/test_slsqp.py +36 -4
  334. scipy/optimize/tests/test_zeros.py +34 -1
  335. scipy/signal/__init__.py +12 -23
  336. scipy/signal/_delegators.py +568 -0
  337. scipy/signal/_filter_design.py +459 -241
  338. scipy/signal/_fir_filter_design.py +262 -90
  339. scipy/signal/_lti_conversion.py +3 -2
  340. scipy/signal/_ltisys.py +118 -91
  341. scipy/signal/_max_len_seq_inner.cpython-313-darwin.so +0 -0
  342. scipy/signal/_peak_finding_utils.cpython-313-darwin.so +0 -0
  343. scipy/signal/_polyutils.py +172 -0
  344. scipy/signal/_short_time_fft.py +519 -70
  345. scipy/signal/_signal_api.py +30 -0
  346. scipy/signal/_signaltools.py +719 -399
  347. scipy/signal/_sigtools.cpython-313-darwin.so +0 -0
  348. scipy/signal/_sosfilt.cpython-313-darwin.so +0 -0
  349. scipy/signal/_spectral_py.py +230 -50
  350. scipy/signal/_spline.cpython-313-darwin.so +0 -0
  351. scipy/signal/_spline_filters.py +108 -68
  352. scipy/signal/_support_alternative_backends.py +73 -0
  353. scipy/signal/_upfirdn.py +4 -1
  354. scipy/signal/_upfirdn_apply.cpython-313-darwin.so +0 -0
  355. scipy/signal/_waveforms.py +2 -11
  356. scipy/signal/_wavelets.py +1 -1
  357. scipy/signal/fir_filter_design.py +1 -0
  358. scipy/signal/spline.py +4 -11
  359. scipy/signal/tests/_scipy_spectral_test_shim.py +2 -171
  360. scipy/signal/tests/test_bsplines.py +114 -79
  361. scipy/signal/tests/test_cont2discrete.py +9 -2
  362. scipy/signal/tests/test_filter_design.py +721 -481
  363. scipy/signal/tests/test_fir_filter_design.py +332 -140
  364. scipy/signal/tests/test_savitzky_golay.py +4 -3
  365. scipy/signal/tests/test_short_time_fft.py +221 -3
  366. scipy/signal/tests/test_signaltools.py +2144 -1348
  367. scipy/signal/tests/test_spectral.py +50 -6
  368. scipy/signal/tests/test_splines.py +161 -96
  369. scipy/signal/tests/test_upfirdn.py +84 -50
  370. scipy/signal/tests/test_waveforms.py +20 -0
  371. scipy/signal/tests/test_windows.py +607 -466
  372. scipy/signal/windows/_windows.py +287 -148
  373. scipy/sparse/__init__.py +23 -4
  374. scipy/sparse/_base.py +270 -108
  375. scipy/sparse/_bsr.py +7 -4
  376. scipy/sparse/_compressed.py +59 -231
  377. scipy/sparse/_construct.py +90 -38
  378. scipy/sparse/_coo.py +115 -181
  379. scipy/sparse/_csc.py +4 -4
  380. scipy/sparse/_csparsetools.cpython-313-darwin.so +0 -0
  381. scipy/sparse/_csr.py +2 -2
  382. scipy/sparse/_data.py +48 -48
  383. scipy/sparse/_dia.py +105 -18
  384. scipy/sparse/_dok.py +0 -23
  385. scipy/sparse/_index.py +4 -4
  386. scipy/sparse/_matrix.py +23 -0
  387. scipy/sparse/_sparsetools.cpython-313-darwin.so +0 -0
  388. scipy/sparse/_sputils.py +37 -22
  389. scipy/sparse/base.py +0 -9
  390. scipy/sparse/bsr.py +0 -14
  391. scipy/sparse/compressed.py +0 -23
  392. scipy/sparse/construct.py +0 -6
  393. scipy/sparse/coo.py +0 -14
  394. scipy/sparse/csc.py +0 -3
  395. scipy/sparse/csgraph/_flow.cpython-313-darwin.so +0 -0
  396. scipy/sparse/csgraph/_matching.cpython-313-darwin.so +0 -0
  397. scipy/sparse/csgraph/_min_spanning_tree.cpython-313-darwin.so +0 -0
  398. scipy/sparse/csgraph/_reordering.cpython-313-darwin.so +0 -0
  399. scipy/sparse/csgraph/_shortest_path.cpython-313-darwin.so +0 -0
  400. scipy/sparse/csgraph/_tools.cpython-313-darwin.so +0 -0
  401. scipy/sparse/csgraph/_traversal.cpython-313-darwin.so +0 -0
  402. scipy/sparse/csgraph/tests/test_matching.py +14 -2
  403. scipy/sparse/csgraph/tests/test_pydata_sparse.py +4 -1
  404. scipy/sparse/csgraph/tests/test_shortest_path.py +83 -27
  405. scipy/sparse/csr.py +0 -5
  406. scipy/sparse/data.py +1 -6
  407. scipy/sparse/dia.py +0 -7
  408. scipy/sparse/dok.py +0 -10
  409. scipy/sparse/linalg/_dsolve/_superlu.cpython-313-darwin.so +0 -0
  410. scipy/sparse/linalg/_dsolve/linsolve.py +9 -0
  411. scipy/sparse/linalg/_dsolve/tests/test_linsolve.py +35 -28
  412. scipy/sparse/linalg/_eigen/arpack/_arpack.cpython-313-darwin.so +0 -0
  413. scipy/sparse/linalg/_eigen/arpack/arpack.py +23 -17
  414. scipy/sparse/linalg/_eigen/lobpcg/lobpcg.py +6 -6
  415. scipy/sparse/linalg/_interface.py +17 -18
  416. scipy/sparse/linalg/_isolve/_gcrotmk.py +4 -4
  417. scipy/sparse/linalg/_isolve/iterative.py +51 -45
  418. scipy/sparse/linalg/_isolve/lgmres.py +6 -6
  419. scipy/sparse/linalg/_isolve/minres.py +5 -5
  420. scipy/sparse/linalg/_isolve/tfqmr.py +7 -7
  421. scipy/sparse/linalg/_isolve/utils.py +2 -8
  422. scipy/sparse/linalg/_matfuncs.py +1 -1
  423. scipy/sparse/linalg/_norm.py +1 -1
  424. scipy/sparse/linalg/_propack/_cpropack.cpython-313-darwin.so +0 -0
  425. scipy/sparse/linalg/_propack/_dpropack.cpython-313-darwin.so +0 -0
  426. scipy/sparse/linalg/_propack/_spropack.cpython-313-darwin.so +0 -0
  427. scipy/sparse/linalg/_propack/_zpropack.cpython-313-darwin.so +0 -0
  428. scipy/sparse/linalg/_special_sparse_arrays.py +39 -38
  429. scipy/sparse/linalg/tests/test_pydata_sparse.py +14 -0
  430. scipy/sparse/tests/test_arithmetic1d.py +5 -2
  431. scipy/sparse/tests/test_base.py +214 -42
  432. scipy/sparse/tests/test_common1d.py +7 -7
  433. scipy/sparse/tests/test_construct.py +1 -1
  434. scipy/sparse/tests/test_coo.py +272 -4
  435. scipy/sparse/tests/test_sparsetools.py +5 -0
  436. scipy/sparse/tests/test_sputils.py +36 -7
  437. scipy/spatial/_ckdtree.cpython-313-darwin.so +0 -0
  438. scipy/spatial/_distance_pybind.cpython-313-darwin.so +0 -0
  439. scipy/spatial/_distance_wrap.cpython-313-darwin.so +0 -0
  440. scipy/spatial/_hausdorff.cpython-313-darwin.so +0 -0
  441. scipy/spatial/_qhull.cpython-313-darwin.so +0 -0
  442. scipy/spatial/_voronoi.cpython-313-darwin.so +0 -0
  443. scipy/spatial/distance.py +49 -42
  444. scipy/spatial/tests/test_distance.py +15 -1
  445. scipy/spatial/tests/test_kdtree.py +1 -0
  446. scipy/spatial/tests/test_qhull.py +7 -2
  447. scipy/spatial/transform/__init__.py +5 -3
  448. scipy/spatial/transform/_rigid_transform.cpython-313-darwin.so +0 -0
  449. scipy/spatial/transform/_rotation.cpython-313-darwin.so +0 -0
  450. scipy/spatial/transform/tests/test_rigid_transform.py +1221 -0
  451. scipy/spatial/transform/tests/test_rotation.py +1213 -832
  452. scipy/spatial/transform/tests/test_rotation_groups.py +3 -3
  453. scipy/spatial/transform/tests/test_rotation_spline.py +29 -8
  454. scipy/special/__init__.py +1 -47
  455. scipy/special/_add_newdocs.py +34 -772
  456. scipy/special/_basic.py +22 -25
  457. scipy/special/_comb.cpython-313-darwin.so +0 -0
  458. scipy/special/_ellip_harm_2.cpython-313-darwin.so +0 -0
  459. scipy/special/_gufuncs.cpython-313-darwin.so +0 -0
  460. scipy/special/_logsumexp.py +67 -58
  461. scipy/special/_orthogonal.pyi +1 -1
  462. scipy/special/_specfun.cpython-313-darwin.so +0 -0
  463. scipy/special/_special_ufuncs.cpython-313-darwin.so +0 -0
  464. scipy/special/_spherical_bessel.py +4 -4
  465. scipy/special/_support_alternative_backends.py +212 -119
  466. scipy/special/_test_internal.cpython-313-darwin.so +0 -0
  467. scipy/special/_testutils.py +4 -4
  468. scipy/special/_ufuncs.cpython-313-darwin.so +0 -0
  469. scipy/special/_ufuncs.pyi +1 -0
  470. scipy/special/_ufuncs.pyx +215 -1400
  471. scipy/special/_ufuncs_cxx.cpython-313-darwin.so +0 -0
  472. scipy/special/_ufuncs_cxx.pxd +2 -15
  473. scipy/special/_ufuncs_cxx.pyx +5 -44
  474. scipy/special/_ufuncs_cxx_defs.h +2 -16
  475. scipy/special/_ufuncs_defs.h +0 -8
  476. scipy/special/cython_special.cpython-313-darwin.so +0 -0
  477. scipy/special/cython_special.pxd +1 -1
  478. scipy/special/tests/_cython_examples/meson.build +10 -1
  479. scipy/special/tests/test_basic.py +153 -20
  480. scipy/special/tests/test_boost_ufuncs.py +3 -0
  481. scipy/special/tests/test_cdflib.py +35 -11
  482. scipy/special/tests/test_gammainc.py +16 -0
  483. scipy/special/tests/test_hyp2f1.py +2 -2
  484. scipy/special/tests/test_log1mexp.py +85 -0
  485. scipy/special/tests/test_logsumexp.py +206 -64
  486. scipy/special/tests/test_mpmath.py +1 -0
  487. scipy/special/tests/test_nan_inputs.py +1 -1
  488. scipy/special/tests/test_orthogonal.py +17 -18
  489. scipy/special/tests/test_sf_error.py +3 -2
  490. scipy/special/tests/test_sph_harm.py +6 -7
  491. scipy/special/tests/test_support_alternative_backends.py +211 -76
  492. scipy/stats/__init__.py +4 -1
  493. scipy/stats/_ansari_swilk_statistics.cpython-313-darwin.so +0 -0
  494. scipy/stats/_axis_nan_policy.py +5 -12
  495. scipy/stats/_biasedurn.cpython-313-darwin.so +0 -0
  496. scipy/stats/_continued_fraction.py +387 -0
  497. scipy/stats/_continuous_distns.py +277 -310
  498. scipy/stats/_correlation.py +1 -1
  499. scipy/stats/_covariance.py +6 -3
  500. scipy/stats/_discrete_distns.py +39 -32
  501. scipy/stats/_distn_infrastructure.py +39 -12
  502. scipy/stats/_distribution_infrastructure.py +900 -238
  503. scipy/stats/_entropy.py +9 -10
  504. scipy/{_lib → stats}/_finite_differences.py +1 -1
  505. scipy/stats/_hypotests.py +83 -50
  506. scipy/stats/_kde.py +53 -49
  507. scipy/stats/_ksstats.py +1 -1
  508. scipy/stats/_levy_stable/__init__.py +7 -15
  509. scipy/stats/_levy_stable/levyst.cpython-313-darwin.so +0 -0
  510. scipy/stats/_morestats.py +118 -73
  511. scipy/stats/_mstats_basic.py +13 -17
  512. scipy/stats/_mstats_extras.py +8 -8
  513. scipy/stats/_multivariate.py +89 -113
  514. scipy/stats/_new_distributions.py +97 -20
  515. scipy/stats/_page_trend_test.py +12 -5
  516. scipy/stats/_probability_distribution.py +265 -43
  517. scipy/stats/_qmc.py +14 -9
  518. scipy/stats/_qmc_cy.cpython-313-darwin.so +0 -0
  519. scipy/stats/_qmvnt.py +16 -95
  520. scipy/stats/_qmvnt_cy.cpython-313-darwin.so +0 -0
  521. scipy/stats/_quantile.py +335 -0
  522. scipy/stats/_rcont/rcont.cpython-313-darwin.so +0 -0
  523. scipy/stats/_resampling.py +4 -29
  524. scipy/stats/_sampling.py +1 -1
  525. scipy/stats/_sobol.cpython-313-darwin.so +0 -0
  526. scipy/stats/_stats.cpython-313-darwin.so +0 -0
  527. scipy/stats/_stats_mstats_common.py +21 -2
  528. scipy/stats/_stats_py.py +550 -476
  529. scipy/stats/_stats_pythran.cpython-313-darwin.so +0 -0
  530. scipy/stats/_unuran/unuran_wrapper.cpython-313-darwin.so +0 -0
  531. scipy/stats/_unuran/unuran_wrapper.pyi +2 -1
  532. scipy/stats/_variation.py +6 -8
  533. scipy/stats/_wilcoxon.py +13 -7
  534. scipy/stats/tests/common_tests.py +6 -4
  535. scipy/stats/tests/test_axis_nan_policy.py +62 -24
  536. scipy/stats/tests/test_continued_fraction.py +173 -0
  537. scipy/stats/tests/test_continuous.py +379 -60
  538. scipy/stats/tests/test_continuous_basic.py +18 -12
  539. scipy/stats/tests/test_discrete_basic.py +14 -8
  540. scipy/stats/tests/test_discrete_distns.py +16 -16
  541. scipy/stats/tests/test_distributions.py +95 -75
  542. scipy/stats/tests/test_entropy.py +40 -48
  543. scipy/stats/tests/test_fit.py +4 -3
  544. scipy/stats/tests/test_hypotests.py +153 -24
  545. scipy/stats/tests/test_kdeoth.py +109 -41
  546. scipy/stats/tests/test_marray.py +289 -0
  547. scipy/stats/tests/test_morestats.py +79 -47
  548. scipy/stats/tests/test_mstats_basic.py +3 -3
  549. scipy/stats/tests/test_multivariate.py +434 -83
  550. scipy/stats/tests/test_qmc.py +13 -10
  551. scipy/stats/tests/test_quantile.py +199 -0
  552. scipy/stats/tests/test_rank.py +119 -112
  553. scipy/stats/tests/test_resampling.py +47 -56
  554. scipy/stats/tests/test_sampling.py +9 -4
  555. scipy/stats/tests/test_stats.py +799 -939
  556. scipy/stats/tests/test_variation.py +8 -6
  557. scipy/version.py +2 -2
  558. {scipy-1.15.3.dist-info → scipy-1.16.0rc2.dist-info}/LICENSE.txt +4 -4
  559. {scipy-1.15.3.dist-info → scipy-1.16.0rc2.dist-info}/METADATA +11 -11
  560. {scipy-1.15.3.dist-info → scipy-1.16.0rc2.dist-info}/RECORD +561 -568
  561. scipy-1.16.0rc2.dist-info/WHEEL +6 -0
  562. scipy/_lib/array_api_extra/_funcs.py +0 -484
  563. scipy/_lib/array_api_extra/_typing.py +0 -8
  564. scipy/interpolate/_bspl.cpython-313-darwin.so +0 -0
  565. scipy/optimize/_cobyla.cpython-313-darwin.so +0 -0
  566. scipy/optimize/_cython_nnls.cpython-313-darwin.so +0 -0
  567. scipy/optimize/_slsqp.cpython-313-darwin.so +0 -0
  568. scipy/spatial/qhull_src/COPYING.txt +0 -38
  569. scipy/special/libsf_error_state.dylib +0 -0
  570. scipy/special/tests/test_log_softmax.py +0 -109
  571. scipy/special/tests/test_xsf_cuda.py +0 -114
  572. scipy/special/xsf/binom.h +0 -89
  573. scipy/special/xsf/cdflib.h +0 -100
  574. scipy/special/xsf/cephes/airy.h +0 -307
  575. scipy/special/xsf/cephes/besselpoly.h +0 -51
  576. scipy/special/xsf/cephes/beta.h +0 -257
  577. scipy/special/xsf/cephes/cbrt.h +0 -131
  578. scipy/special/xsf/cephes/chbevl.h +0 -85
  579. scipy/special/xsf/cephes/chdtr.h +0 -193
  580. scipy/special/xsf/cephes/const.h +0 -87
  581. scipy/special/xsf/cephes/ellie.h +0 -293
  582. scipy/special/xsf/cephes/ellik.h +0 -251
  583. scipy/special/xsf/cephes/ellpe.h +0 -107
  584. scipy/special/xsf/cephes/ellpk.h +0 -117
  585. scipy/special/xsf/cephes/expn.h +0 -260
  586. scipy/special/xsf/cephes/gamma.h +0 -398
  587. scipy/special/xsf/cephes/hyp2f1.h +0 -596
  588. scipy/special/xsf/cephes/hyperg.h +0 -361
  589. scipy/special/xsf/cephes/i0.h +0 -149
  590. scipy/special/xsf/cephes/i1.h +0 -158
  591. scipy/special/xsf/cephes/igam.h +0 -421
  592. scipy/special/xsf/cephes/igam_asymp_coeff.h +0 -195
  593. scipy/special/xsf/cephes/igami.h +0 -313
  594. scipy/special/xsf/cephes/j0.h +0 -225
  595. scipy/special/xsf/cephes/j1.h +0 -198
  596. scipy/special/xsf/cephes/jv.h +0 -715
  597. scipy/special/xsf/cephes/k0.h +0 -164
  598. scipy/special/xsf/cephes/k1.h +0 -163
  599. scipy/special/xsf/cephes/kn.h +0 -243
  600. scipy/special/xsf/cephes/lanczos.h +0 -112
  601. scipy/special/xsf/cephes/ndtr.h +0 -275
  602. scipy/special/xsf/cephes/poch.h +0 -85
  603. scipy/special/xsf/cephes/polevl.h +0 -167
  604. scipy/special/xsf/cephes/psi.h +0 -194
  605. scipy/special/xsf/cephes/rgamma.h +0 -111
  606. scipy/special/xsf/cephes/scipy_iv.h +0 -811
  607. scipy/special/xsf/cephes/shichi.h +0 -248
  608. scipy/special/xsf/cephes/sici.h +0 -224
  609. scipy/special/xsf/cephes/sindg.h +0 -221
  610. scipy/special/xsf/cephes/tandg.h +0 -139
  611. scipy/special/xsf/cephes/trig.h +0 -58
  612. scipy/special/xsf/cephes/unity.h +0 -186
  613. scipy/special/xsf/cephes/zeta.h +0 -172
  614. scipy/special/xsf/config.h +0 -304
  615. scipy/special/xsf/digamma.h +0 -205
  616. scipy/special/xsf/error.h +0 -57
  617. scipy/special/xsf/evalpoly.h +0 -47
  618. scipy/special/xsf/expint.h +0 -266
  619. scipy/special/xsf/hyp2f1.h +0 -694
  620. scipy/special/xsf/iv_ratio.h +0 -173
  621. scipy/special/xsf/lambertw.h +0 -150
  622. scipy/special/xsf/loggamma.h +0 -163
  623. scipy/special/xsf/sici.h +0 -200
  624. scipy/special/xsf/tools.h +0 -427
  625. scipy/special/xsf/trig.h +0 -164
  626. scipy/special/xsf/wright_bessel.h +0 -843
  627. scipy/special/xsf/zlog1.h +0 -35
  628. scipy/stats/_mvn.cpython-313-darwin.so +0 -0
  629. 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