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