scipy 1.15.3__cp312-cp312-musllinux_1_2_aarch64.whl → 1.16.0rc1__cp312-cp312-musllinux_1_2_aarch64.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 (640) hide show
  1. scipy/__config__.py +9 -9
  2. scipy/__init__.py +3 -6
  3. scipy/_cyutility.cpython-312-aarch64-linux-musl.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-aarch64-linux-musl.so +0 -0
  8. scipy/_lib/_docscrape.py +1 -1
  9. scipy/_lib/_elementwise_iterative_method.py +15 -26
  10. scipy/_lib/_fpumode.cpython-312-aarch64-linux-musl.so +0 -0
  11. scipy/_lib/_sparse.py +41 -0
  12. scipy/_lib/_test_ccallback.cpython-312-aarch64-linux-musl.so +0 -0
  13. scipy/_lib/_test_deprecation_call.cpython-312-aarch64-linux-musl.so +0 -0
  14. scipy/_lib/_test_deprecation_def.cpython-312-aarch64-linux-musl.so +0 -0
  15. scipy/_lib/_testutils.py +6 -2
  16. scipy/_lib/_uarray/_uarray.cpython-312-aarch64-linux-musl.so +0 -0
  17. scipy/_lib/_util.py +222 -125
  18. scipy/_lib/array_api_compat/__init__.py +4 -4
  19. scipy/_lib/array_api_compat/_internal.py +19 -6
  20. scipy/_lib/array_api_compat/common/__init__.py +1 -1
  21. scipy/_lib/array_api_compat/common/_aliases.py +365 -193
  22. scipy/_lib/array_api_compat/common/_fft.py +94 -64
  23. scipy/_lib/array_api_compat/common/_helpers.py +413 -180
  24. scipy/_lib/array_api_compat/common/_linalg.py +116 -40
  25. scipy/_lib/array_api_compat/common/_typing.py +179 -10
  26. scipy/_lib/array_api_compat/cupy/__init__.py +1 -4
  27. scipy/_lib/array_api_compat/cupy/_aliases.py +61 -41
  28. scipy/_lib/array_api_compat/cupy/_info.py +16 -6
  29. scipy/_lib/array_api_compat/cupy/_typing.py +24 -39
  30. scipy/_lib/array_api_compat/dask/array/__init__.py +6 -3
  31. scipy/_lib/array_api_compat/dask/array/_aliases.py +267 -108
  32. scipy/_lib/array_api_compat/dask/array/_info.py +105 -34
  33. scipy/_lib/array_api_compat/dask/array/fft.py +5 -8
  34. scipy/_lib/array_api_compat/dask/array/linalg.py +21 -22
  35. scipy/_lib/array_api_compat/numpy/__init__.py +13 -15
  36. scipy/_lib/array_api_compat/numpy/_aliases.py +98 -49
  37. scipy/_lib/array_api_compat/numpy/_info.py +36 -16
  38. scipy/_lib/array_api_compat/numpy/_typing.py +27 -43
  39. scipy/_lib/array_api_compat/numpy/fft.py +11 -5
  40. scipy/_lib/array_api_compat/numpy/linalg.py +75 -22
  41. scipy/_lib/array_api_compat/torch/__init__.py +3 -5
  42. scipy/_lib/array_api_compat/torch/_aliases.py +262 -159
  43. scipy/_lib/array_api_compat/torch/_info.py +27 -16
  44. scipy/_lib/array_api_compat/torch/_typing.py +3 -0
  45. scipy/_lib/array_api_compat/torch/fft.py +17 -18
  46. scipy/_lib/array_api_compat/torch/linalg.py +16 -16
  47. scipy/_lib/array_api_extra/__init__.py +26 -3
  48. scipy/_lib/array_api_extra/_delegation.py +171 -0
  49. scipy/_lib/array_api_extra/_lib/__init__.py +1 -0
  50. scipy/_lib/array_api_extra/_lib/_at.py +463 -0
  51. scipy/_lib/array_api_extra/_lib/_backends.py +46 -0
  52. scipy/_lib/array_api_extra/_lib/_funcs.py +937 -0
  53. scipy/_lib/array_api_extra/_lib/_lazy.py +357 -0
  54. scipy/_lib/array_api_extra/_lib/_testing.py +278 -0
  55. scipy/_lib/array_api_extra/_lib/_utils/__init__.py +1 -0
  56. scipy/_lib/array_api_extra/_lib/_utils/_compat.py +74 -0
  57. scipy/_lib/array_api_extra/_lib/_utils/_compat.pyi +45 -0
  58. scipy/_lib/array_api_extra/_lib/_utils/_helpers.py +559 -0
  59. scipy/_lib/array_api_extra/_lib/_utils/_typing.py +10 -0
  60. scipy/_lib/array_api_extra/_lib/_utils/_typing.pyi +105 -0
  61. scipy/_lib/array_api_extra/testing.py +359 -0
  62. scipy/_lib/decorator.py +2 -2
  63. scipy/_lib/doccer.py +1 -7
  64. scipy/_lib/messagestream.cpython-312-aarch64-linux-musl.so +0 -0
  65. scipy/_lib/pyprima/__init__.py +212 -0
  66. scipy/_lib/pyprima/cobyla/__init__.py +0 -0
  67. scipy/_lib/pyprima/cobyla/cobyla.py +559 -0
  68. scipy/_lib/pyprima/cobyla/cobylb.py +714 -0
  69. scipy/_lib/pyprima/cobyla/geometry.py +226 -0
  70. scipy/_lib/pyprima/cobyla/initialize.py +215 -0
  71. scipy/_lib/pyprima/cobyla/trustregion.py +492 -0
  72. scipy/_lib/pyprima/cobyla/update.py +289 -0
  73. scipy/_lib/pyprima/common/__init__.py +0 -0
  74. scipy/_lib/pyprima/common/_bounds.py +34 -0
  75. scipy/_lib/pyprima/common/_linear_constraints.py +46 -0
  76. scipy/_lib/pyprima/common/_nonlinear_constraints.py +54 -0
  77. scipy/_lib/pyprima/common/_project.py +173 -0
  78. scipy/_lib/pyprima/common/checkbreak.py +93 -0
  79. scipy/_lib/pyprima/common/consts.py +47 -0
  80. scipy/_lib/pyprima/common/evaluate.py +99 -0
  81. scipy/_lib/pyprima/common/history.py +38 -0
  82. scipy/_lib/pyprima/common/infos.py +30 -0
  83. scipy/_lib/pyprima/common/linalg.py +435 -0
  84. scipy/_lib/pyprima/common/message.py +290 -0
  85. scipy/_lib/pyprima/common/powalg.py +131 -0
  86. scipy/_lib/pyprima/common/preproc.py +277 -0
  87. scipy/_lib/pyprima/common/present.py +5 -0
  88. scipy/_lib/pyprima/common/ratio.py +54 -0
  89. scipy/_lib/pyprima/common/redrho.py +47 -0
  90. scipy/_lib/pyprima/common/selectx.py +296 -0
  91. scipy/_lib/tests/test__util.py +105 -121
  92. scipy/_lib/tests/test_array_api.py +166 -35
  93. scipy/_lib/tests/test_bunch.py +7 -0
  94. scipy/_lib/tests/test_ccallback.py +2 -10
  95. scipy/_lib/tests/test_public_api.py +13 -0
  96. scipy/cluster/_hierarchy.cpython-312-aarch64-linux-musl.so +0 -0
  97. scipy/cluster/_optimal_leaf_ordering.cpython-312-aarch64-linux-musl.so +0 -0
  98. scipy/cluster/_vq.cpython-312-aarch64-linux-musl.so +0 -0
  99. scipy/cluster/hierarchy.py +393 -223
  100. scipy/cluster/tests/test_hierarchy.py +273 -335
  101. scipy/cluster/tests/test_vq.py +45 -61
  102. scipy/cluster/vq.py +39 -35
  103. scipy/conftest.py +263 -157
  104. scipy/constants/_constants.py +4 -1
  105. scipy/constants/tests/test_codata.py +2 -2
  106. scipy/constants/tests/test_constants.py +11 -18
  107. scipy/datasets/_download_all.py +15 -1
  108. scipy/datasets/_fetchers.py +7 -1
  109. scipy/datasets/_utils.py +1 -1
  110. scipy/differentiate/_differentiate.py +25 -25
  111. scipy/differentiate/tests/test_differentiate.py +24 -25
  112. scipy/fft/_basic.py +20 -0
  113. scipy/fft/_helper.py +3 -34
  114. scipy/fft/_pocketfft/helper.py +29 -1
  115. scipy/fft/_pocketfft/pypocketfft.cpython-312-aarch64-linux-musl.so +0 -0
  116. scipy/fft/_pocketfft/tests/test_basic.py +2 -4
  117. scipy/fft/_pocketfft/tests/test_real_transforms.py +4 -4
  118. scipy/fft/_realtransforms.py +13 -0
  119. scipy/fft/tests/test_basic.py +27 -25
  120. scipy/fft/tests/test_fftlog.py +16 -7
  121. scipy/fft/tests/test_helper.py +18 -34
  122. scipy/fft/tests/test_real_transforms.py +8 -10
  123. scipy/fftpack/convolve.cpython-312-aarch64-linux-musl.so +0 -0
  124. scipy/fftpack/tests/test_basic.py +2 -4
  125. scipy/fftpack/tests/test_real_transforms.py +8 -9
  126. scipy/integrate/_bvp.py +9 -3
  127. scipy/integrate/_cubature.py +3 -2
  128. scipy/integrate/_dop.cpython-312-aarch64-linux-musl.so +0 -0
  129. scipy/integrate/_lsoda.cpython-312-aarch64-linux-musl.so +0 -0
  130. scipy/integrate/_ode.py +9 -2
  131. scipy/integrate/_odepack.cpython-312-aarch64-linux-musl.so +0 -0
  132. scipy/integrate/_quad_vec.py +21 -29
  133. scipy/integrate/_quadpack.cpython-312-aarch64-linux-musl.so +0 -0
  134. scipy/integrate/_quadpack_py.py +11 -7
  135. scipy/integrate/_quadrature.py +3 -3
  136. scipy/integrate/_rules/_base.py +2 -2
  137. scipy/integrate/_tanhsinh.py +48 -47
  138. scipy/integrate/_test_multivariate.cpython-312-aarch64-linux-musl.so +0 -0
  139. scipy/integrate/_test_odeint_banded.cpython-312-aarch64-linux-musl.so +0 -0
  140. scipy/integrate/_vode.cpython-312-aarch64-linux-musl.so +0 -0
  141. scipy/integrate/tests/test__quad_vec.py +0 -6
  142. scipy/integrate/tests/test_banded_ode_solvers.py +85 -0
  143. scipy/integrate/tests/test_cubature.py +21 -35
  144. scipy/integrate/tests/test_quadrature.py +6 -8
  145. scipy/integrate/tests/test_tanhsinh.py +56 -48
  146. scipy/interpolate/__init__.py +70 -58
  147. scipy/interpolate/_bary_rational.py +22 -22
  148. scipy/interpolate/_bsplines.py +119 -66
  149. scipy/interpolate/_cubic.py +65 -50
  150. scipy/interpolate/_dfitpack.cpython-312-aarch64-linux-musl.so +0 -0
  151. scipy/interpolate/_dierckx.cpython-312-aarch64-linux-musl.so +0 -0
  152. scipy/interpolate/_fitpack.cpython-312-aarch64-linux-musl.so +0 -0
  153. scipy/interpolate/_fitpack2.py +9 -6
  154. scipy/interpolate/_fitpack_impl.py +32 -26
  155. scipy/interpolate/_fitpack_repro.py +23 -19
  156. scipy/interpolate/_interpnd.cpython-312-aarch64-linux-musl.so +0 -0
  157. scipy/interpolate/_interpolate.py +30 -12
  158. scipy/interpolate/_ndbspline.py +13 -18
  159. scipy/interpolate/_ndgriddata.py +5 -8
  160. scipy/interpolate/_polyint.py +95 -31
  161. scipy/interpolate/_ppoly.cpython-312-aarch64-linux-musl.so +0 -0
  162. scipy/interpolate/_rbf.py +2 -2
  163. scipy/interpolate/_rbfinterp.py +1 -1
  164. scipy/interpolate/_rbfinterp_pythran.cpython-312-aarch64-linux-musl.so +0 -0
  165. scipy/interpolate/_rgi.py +31 -26
  166. scipy/interpolate/_rgi_cython.cpython-312-aarch64-linux-musl.so +0 -0
  167. scipy/interpolate/dfitpack.py +0 -20
  168. scipy/interpolate/interpnd.py +1 -2
  169. scipy/interpolate/tests/test_bary_rational.py +2 -2
  170. scipy/interpolate/tests/test_bsplines.py +97 -1
  171. scipy/interpolate/tests/test_fitpack2.py +39 -1
  172. scipy/interpolate/tests/test_interpnd.py +32 -20
  173. scipy/interpolate/tests/test_interpolate.py +48 -4
  174. scipy/interpolate/tests/test_rgi.py +2 -1
  175. scipy/io/_fast_matrix_market/__init__.py +2 -0
  176. scipy/io/_fast_matrix_market/_fmm_core.cpython-312-aarch64-linux-musl.so +0 -0
  177. scipy/io/_harwell_boeing/_fortran_format_parser.py +19 -16
  178. scipy/io/_harwell_boeing/hb.py +7 -11
  179. scipy/io/_idl.py +5 -7
  180. scipy/io/_netcdf.py +15 -5
  181. scipy/io/_test_fortran.cpython-312-aarch64-linux-musl.so +0 -0
  182. scipy/io/arff/tests/test_arffread.py +3 -3
  183. scipy/io/matlab/__init__.py +5 -3
  184. scipy/io/matlab/_mio.py +4 -1
  185. scipy/io/matlab/_mio5.py +19 -13
  186. scipy/io/matlab/_mio5_utils.cpython-312-aarch64-linux-musl.so +0 -0
  187. scipy/io/matlab/_mio_utils.cpython-312-aarch64-linux-musl.so +0 -0
  188. scipy/io/matlab/_miobase.py +4 -1
  189. scipy/io/matlab/_streams.cpython-312-aarch64-linux-musl.so +0 -0
  190. scipy/io/matlab/tests/test_mio.py +46 -18
  191. scipy/io/matlab/tests/test_mio_funcs.py +1 -1
  192. scipy/io/tests/test_mmio.py +7 -1
  193. scipy/io/tests/test_wavfile.py +41 -0
  194. scipy/io/wavfile.py +57 -10
  195. scipy/linalg/_basic.py +113 -86
  196. scipy/linalg/_cythonized_array_utils.cpython-312-aarch64-linux-musl.so +0 -0
  197. scipy/linalg/_decomp.py +22 -9
  198. scipy/linalg/_decomp_cholesky.py +28 -13
  199. scipy/linalg/_decomp_cossin.py +45 -30
  200. scipy/linalg/_decomp_interpolative.cpython-312-aarch64-linux-musl.so +0 -0
  201. scipy/linalg/_decomp_ldl.py +4 -1
  202. scipy/linalg/_decomp_lu.py +18 -6
  203. scipy/linalg/_decomp_lu_cython.cpython-312-aarch64-linux-musl.so +0 -0
  204. scipy/linalg/_decomp_polar.py +2 -0
  205. scipy/linalg/_decomp_qr.py +6 -2
  206. scipy/linalg/_decomp_qz.py +3 -0
  207. scipy/linalg/_decomp_schur.py +3 -1
  208. scipy/linalg/_decomp_svd.py +13 -2
  209. scipy/linalg/_decomp_update.cpython-312-aarch64-linux-musl.so +0 -0
  210. scipy/linalg/_expm_frechet.py +4 -0
  211. scipy/linalg/_fblas.cpython-312-aarch64-linux-musl.so +0 -0
  212. scipy/linalg/_flapack.cpython-312-aarch64-linux-musl.so +0 -0
  213. scipy/linalg/_linalg_pythran.cpython-312-aarch64-linux-musl.so +0 -0
  214. scipy/linalg/_matfuncs.py +187 -4
  215. scipy/linalg/_matfuncs_expm.cpython-312-aarch64-linux-musl.so +0 -0
  216. scipy/linalg/_matfuncs_schur_sqrtm.cpython-312-aarch64-linux-musl.so +0 -0
  217. scipy/linalg/_matfuncs_sqrtm.py +1 -99
  218. scipy/linalg/_matfuncs_sqrtm_triu.cpython-312-aarch64-linux-musl.so +0 -0
  219. scipy/linalg/_procrustes.py +2 -0
  220. scipy/linalg/_sketches.py +17 -6
  221. scipy/linalg/_solve_toeplitz.cpython-312-aarch64-linux-musl.so +0 -0
  222. scipy/linalg/_solvers.py +7 -2
  223. scipy/linalg/_special_matrices.py +26 -36
  224. scipy/linalg/cython_blas.cpython-312-aarch64-linux-musl.so +0 -0
  225. scipy/linalg/cython_lapack.cpython-312-aarch64-linux-musl.so +0 -0
  226. scipy/linalg/lapack.py +22 -2
  227. scipy/linalg/tests/_cython_examples/meson.build +7 -0
  228. scipy/linalg/tests/test_basic.py +31 -16
  229. scipy/linalg/tests/test_batch.py +588 -0
  230. scipy/linalg/tests/test_cythonized_array_utils.py +0 -2
  231. scipy/linalg/tests/test_decomp.py +40 -3
  232. scipy/linalg/tests/test_decomp_cossin.py +14 -0
  233. scipy/linalg/tests/test_decomp_ldl.py +1 -1
  234. scipy/linalg/tests/test_lapack.py +115 -7
  235. scipy/linalg/tests/test_matfuncs.py +157 -102
  236. scipy/linalg/tests/test_procrustes.py +0 -7
  237. scipy/linalg/tests/test_solve_toeplitz.py +1 -1
  238. scipy/linalg/tests/test_special_matrices.py +1 -5
  239. scipy/ndimage/__init__.py +1 -0
  240. scipy/ndimage/_ctest.cpython-312-aarch64-linux-musl.so +0 -0
  241. scipy/ndimage/_cytest.cpython-312-aarch64-linux-musl.so +0 -0
  242. scipy/ndimage/_delegators.py +8 -2
  243. scipy/ndimage/_filters.py +433 -5
  244. scipy/ndimage/_interpolation.py +36 -6
  245. scipy/ndimage/_measurements.py +4 -2
  246. scipy/ndimage/_morphology.py +5 -0
  247. scipy/ndimage/_nd_image.cpython-312-aarch64-linux-musl.so +0 -0
  248. scipy/ndimage/_ni_docstrings.py +5 -1
  249. scipy/ndimage/_ni_label.cpython-312-aarch64-linux-musl.so +0 -0
  250. scipy/ndimage/_ni_support.py +1 -5
  251. scipy/ndimage/_rank_filter_1d.cpython-312-aarch64-linux-musl.so +0 -0
  252. scipy/ndimage/_support_alternative_backends.py +18 -6
  253. scipy/ndimage/tests/test_filters.py +337 -259
  254. scipy/ndimage/tests/test_fourier.py +7 -9
  255. scipy/ndimage/tests/test_interpolation.py +68 -61
  256. scipy/ndimage/tests/test_measurements.py +18 -35
  257. scipy/ndimage/tests/test_morphology.py +143 -131
  258. scipy/ndimage/tests/test_splines.py +1 -3
  259. scipy/odr/__odrpack.cpython-312-aarch64-linux-musl.so +0 -0
  260. scipy/optimize/_basinhopping.py +13 -7
  261. scipy/optimize/_bglu_dense.cpython-312-aarch64-linux-musl.so +0 -0
  262. scipy/optimize/_bracket.py +17 -24
  263. scipy/optimize/_chandrupatla.py +9 -10
  264. scipy/optimize/_cobyla_py.py +104 -123
  265. scipy/optimize/_constraints.py +14 -10
  266. scipy/optimize/_differentiable_functions.py +371 -230
  267. scipy/optimize/_differentialevolution.py +4 -3
  268. scipy/optimize/_direct.cpython-312-aarch64-linux-musl.so +0 -0
  269. scipy/optimize/_dual_annealing.py +1 -1
  270. scipy/optimize/_elementwise.py +1 -4
  271. scipy/optimize/_group_columns.cpython-312-aarch64-linux-musl.so +0 -0
  272. scipy/optimize/_highspy/_core.cpython-312-aarch64-linux-musl.so +0 -0
  273. scipy/optimize/_highspy/_highs_options.cpython-312-aarch64-linux-musl.so +0 -0
  274. scipy/optimize/_lbfgsb.cpython-312-aarch64-linux-musl.so +0 -0
  275. scipy/optimize/_lbfgsb_py.py +57 -16
  276. scipy/optimize/_linprog_doc.py +2 -2
  277. scipy/optimize/_linprog_highs.py +2 -2
  278. scipy/optimize/_linprog_ip.py +25 -10
  279. scipy/optimize/_linprog_util.py +14 -16
  280. scipy/optimize/_lsap.cpython-312-aarch64-linux-musl.so +0 -0
  281. scipy/optimize/_lsq/common.py +3 -3
  282. scipy/optimize/_lsq/dogbox.py +16 -2
  283. scipy/optimize/_lsq/givens_elimination.cpython-312-aarch64-linux-musl.so +0 -0
  284. scipy/optimize/_lsq/least_squares.py +198 -126
  285. scipy/optimize/_lsq/lsq_linear.py +6 -6
  286. scipy/optimize/_lsq/trf.py +35 -8
  287. scipy/optimize/_milp.py +3 -1
  288. scipy/optimize/_minimize.py +105 -36
  289. scipy/optimize/_minpack.cpython-312-aarch64-linux-musl.so +0 -0
  290. scipy/optimize/_minpack_py.py +21 -14
  291. scipy/optimize/_moduleTNC.cpython-312-aarch64-linux-musl.so +0 -0
  292. scipy/optimize/_nnls.py +20 -21
  293. scipy/optimize/_nonlin.py +34 -3
  294. scipy/optimize/_numdiff.py +288 -110
  295. scipy/optimize/_optimize.py +86 -48
  296. scipy/optimize/_pava_pybind.cpython-312-aarch64-linux-musl.so +0 -0
  297. scipy/optimize/_remove_redundancy.py +5 -5
  298. scipy/optimize/_root_scalar.py +1 -1
  299. scipy/optimize/_shgo.py +6 -0
  300. scipy/optimize/_shgo_lib/_complex.py +1 -1
  301. scipy/optimize/_slsqp_py.py +216 -124
  302. scipy/optimize/_slsqplib.cpython-312-aarch64-linux-musl.so +0 -0
  303. scipy/optimize/_spectral.py +1 -1
  304. scipy/optimize/_tnc.py +8 -1
  305. scipy/optimize/_trlib/_trlib.cpython-312-aarch64-linux-musl.so +0 -0
  306. scipy/optimize/_trustregion.py +20 -6
  307. scipy/optimize/_trustregion_constr/canonical_constraint.py +7 -7
  308. scipy/optimize/_trustregion_constr/equality_constrained_sqp.py +1 -1
  309. scipy/optimize/_trustregion_constr/minimize_trustregion_constr.py +11 -3
  310. scipy/optimize/_trustregion_constr/projections.py +12 -8
  311. scipy/optimize/_trustregion_constr/qp_subproblem.py +9 -9
  312. scipy/optimize/_trustregion_constr/tests/test_projections.py +7 -7
  313. scipy/optimize/_trustregion_constr/tests/test_qp_subproblem.py +77 -77
  314. scipy/optimize/_trustregion_constr/tr_interior_point.py +5 -5
  315. scipy/optimize/_trustregion_exact.py +0 -1
  316. scipy/optimize/_zeros.cpython-312-aarch64-linux-musl.so +0 -0
  317. scipy/optimize/_zeros_py.py +97 -17
  318. scipy/optimize/cython_optimize/_zeros.cpython-312-aarch64-linux-musl.so +0 -0
  319. scipy/optimize/slsqp.py +0 -1
  320. scipy/optimize/tests/test__basinhopping.py +1 -1
  321. scipy/optimize/tests/test__differential_evolution.py +4 -4
  322. scipy/optimize/tests/test__linprog_clean_inputs.py +5 -3
  323. scipy/optimize/tests/test__numdiff.py +66 -22
  324. scipy/optimize/tests/test__remove_redundancy.py +2 -2
  325. scipy/optimize/tests/test__shgo.py +9 -1
  326. scipy/optimize/tests/test_bracket.py +36 -46
  327. scipy/optimize/tests/test_chandrupatla.py +133 -135
  328. scipy/optimize/tests/test_cobyla.py +74 -45
  329. scipy/optimize/tests/test_constraints.py +1 -1
  330. scipy/optimize/tests/test_differentiable_functions.py +226 -6
  331. scipy/optimize/tests/test_lbfgsb_hessinv.py +22 -0
  332. scipy/optimize/tests/test_least_squares.py +125 -13
  333. scipy/optimize/tests/test_linear_assignment.py +3 -3
  334. scipy/optimize/tests/test_linprog.py +3 -3
  335. scipy/optimize/tests/test_lsq_linear.py +5 -5
  336. scipy/optimize/tests/test_minimize_constrained.py +2 -2
  337. scipy/optimize/tests/test_minpack.py +4 -4
  338. scipy/optimize/tests/test_nnls.py +43 -3
  339. scipy/optimize/tests/test_nonlin.py +36 -0
  340. scipy/optimize/tests/test_optimize.py +95 -17
  341. scipy/optimize/tests/test_slsqp.py +36 -4
  342. scipy/optimize/tests/test_zeros.py +34 -1
  343. scipy/signal/__init__.py +12 -23
  344. scipy/signal/_delegators.py +568 -0
  345. scipy/signal/_filter_design.py +459 -241
  346. scipy/signal/_fir_filter_design.py +262 -90
  347. scipy/signal/_lti_conversion.py +3 -2
  348. scipy/signal/_ltisys.py +118 -91
  349. scipy/signal/_max_len_seq_inner.cpython-312-aarch64-linux-musl.so +0 -0
  350. scipy/signal/_peak_finding_utils.cpython-312-aarch64-linux-musl.so +0 -0
  351. scipy/signal/_polyutils.py +172 -0
  352. scipy/signal/_short_time_fft.py +519 -70
  353. scipy/signal/_signal_api.py +30 -0
  354. scipy/signal/_signaltools.py +719 -399
  355. scipy/signal/_sigtools.cpython-312-aarch64-linux-musl.so +0 -0
  356. scipy/signal/_sosfilt.cpython-312-aarch64-linux-musl.so +0 -0
  357. scipy/signal/_spectral_py.py +221 -50
  358. scipy/signal/_spline.cpython-312-aarch64-linux-musl.so +0 -0
  359. scipy/signal/_spline_filters.py +108 -68
  360. scipy/signal/_support_alternative_backends.py +73 -0
  361. scipy/signal/_upfirdn.py +4 -1
  362. scipy/signal/_upfirdn_apply.cpython-312-aarch64-linux-musl.so +0 -0
  363. scipy/signal/_waveforms.py +2 -11
  364. scipy/signal/_wavelets.py +1 -1
  365. scipy/signal/fir_filter_design.py +1 -0
  366. scipy/signal/spline.py +4 -11
  367. scipy/signal/tests/_scipy_spectral_test_shim.py +2 -171
  368. scipy/signal/tests/test_bsplines.py +114 -79
  369. scipy/signal/tests/test_cont2discrete.py +9 -2
  370. scipy/signal/tests/test_filter_design.py +721 -481
  371. scipy/signal/tests/test_fir_filter_design.py +332 -140
  372. scipy/signal/tests/test_savitzky_golay.py +4 -3
  373. scipy/signal/tests/test_short_time_fft.py +221 -3
  374. scipy/signal/tests/test_signaltools.py +2144 -1348
  375. scipy/signal/tests/test_spectral.py +19 -6
  376. scipy/signal/tests/test_splines.py +161 -96
  377. scipy/signal/tests/test_upfirdn.py +84 -50
  378. scipy/signal/tests/test_waveforms.py +20 -0
  379. scipy/signal/tests/test_windows.py +607 -466
  380. scipy/signal/windows/_windows.py +287 -148
  381. scipy/sparse/__init__.py +23 -4
  382. scipy/sparse/_base.py +270 -108
  383. scipy/sparse/_bsr.py +7 -4
  384. scipy/sparse/_compressed.py +59 -231
  385. scipy/sparse/_construct.py +90 -38
  386. scipy/sparse/_coo.py +115 -181
  387. scipy/sparse/_csc.py +4 -4
  388. scipy/sparse/_csparsetools.cpython-312-aarch64-linux-musl.so +0 -0
  389. scipy/sparse/_csr.py +2 -2
  390. scipy/sparse/_data.py +48 -48
  391. scipy/sparse/_dia.py +105 -18
  392. scipy/sparse/_dok.py +0 -23
  393. scipy/sparse/_index.py +4 -4
  394. scipy/sparse/_matrix.py +23 -0
  395. scipy/sparse/_sparsetools.cpython-312-aarch64-linux-musl.so +0 -0
  396. scipy/sparse/_sputils.py +37 -22
  397. scipy/sparse/base.py +0 -9
  398. scipy/sparse/bsr.py +0 -14
  399. scipy/sparse/compressed.py +0 -23
  400. scipy/sparse/construct.py +0 -6
  401. scipy/sparse/coo.py +0 -14
  402. scipy/sparse/csc.py +0 -3
  403. scipy/sparse/csgraph/_flow.cpython-312-aarch64-linux-musl.so +0 -0
  404. scipy/sparse/csgraph/_matching.cpython-312-aarch64-linux-musl.so +0 -0
  405. scipy/sparse/csgraph/_min_spanning_tree.cpython-312-aarch64-linux-musl.so +0 -0
  406. scipy/sparse/csgraph/_reordering.cpython-312-aarch64-linux-musl.so +0 -0
  407. scipy/sparse/csgraph/_shortest_path.cpython-312-aarch64-linux-musl.so +0 -0
  408. scipy/sparse/csgraph/_tools.cpython-312-aarch64-linux-musl.so +0 -0
  409. scipy/sparse/csgraph/_traversal.cpython-312-aarch64-linux-musl.so +0 -0
  410. scipy/sparse/csgraph/tests/test_matching.py +14 -2
  411. scipy/sparse/csgraph/tests/test_pydata_sparse.py +4 -1
  412. scipy/sparse/csgraph/tests/test_shortest_path.py +83 -27
  413. scipy/sparse/csr.py +0 -5
  414. scipy/sparse/data.py +1 -6
  415. scipy/sparse/dia.py +0 -7
  416. scipy/sparse/dok.py +0 -10
  417. scipy/sparse/linalg/_dsolve/_superlu.cpython-312-aarch64-linux-musl.so +0 -0
  418. scipy/sparse/linalg/_dsolve/linsolve.py +9 -0
  419. scipy/sparse/linalg/_dsolve/tests/test_linsolve.py +35 -28
  420. scipy/sparse/linalg/_eigen/arpack/_arpack.cpython-312-aarch64-linux-musl.so +0 -0
  421. scipy/sparse/linalg/_eigen/arpack/arpack.py +23 -17
  422. scipy/sparse/linalg/_eigen/lobpcg/lobpcg.py +6 -6
  423. scipy/sparse/linalg/_interface.py +17 -18
  424. scipy/sparse/linalg/_isolve/_gcrotmk.py +4 -4
  425. scipy/sparse/linalg/_isolve/iterative.py +51 -45
  426. scipy/sparse/linalg/_isolve/lgmres.py +6 -6
  427. scipy/sparse/linalg/_isolve/minres.py +5 -5
  428. scipy/sparse/linalg/_isolve/tfqmr.py +7 -7
  429. scipy/sparse/linalg/_isolve/utils.py +2 -8
  430. scipy/sparse/linalg/_matfuncs.py +1 -1
  431. scipy/sparse/linalg/_norm.py +1 -1
  432. scipy/sparse/linalg/_propack/_cpropack.cpython-312-aarch64-linux-musl.so +0 -0
  433. scipy/sparse/linalg/_propack/_dpropack.cpython-312-aarch64-linux-musl.so +0 -0
  434. scipy/sparse/linalg/_propack/_spropack.cpython-312-aarch64-linux-musl.so +0 -0
  435. scipy/sparse/linalg/_propack/_zpropack.cpython-312-aarch64-linux-musl.so +0 -0
  436. scipy/sparse/linalg/_special_sparse_arrays.py +39 -38
  437. scipy/sparse/linalg/tests/test_pydata_sparse.py +14 -0
  438. scipy/sparse/tests/test_arithmetic1d.py +5 -2
  439. scipy/sparse/tests/test_base.py +207 -42
  440. scipy/sparse/tests/test_common1d.py +7 -7
  441. scipy/sparse/tests/test_construct.py +1 -1
  442. scipy/sparse/tests/test_coo.py +272 -4
  443. scipy/sparse/tests/test_sparsetools.py +5 -0
  444. scipy/sparse/tests/test_sputils.py +36 -7
  445. scipy/spatial/_ckdtree.cpython-312-aarch64-linux-musl.so +0 -0
  446. scipy/spatial/_distance_pybind.cpython-312-aarch64-linux-musl.so +0 -0
  447. scipy/spatial/_distance_wrap.cpython-312-aarch64-linux-musl.so +0 -0
  448. scipy/spatial/_hausdorff.cpython-312-aarch64-linux-musl.so +0 -0
  449. scipy/spatial/_qhull.cpython-312-aarch64-linux-musl.so +0 -0
  450. scipy/spatial/_voronoi.cpython-312-aarch64-linux-musl.so +0 -0
  451. scipy/spatial/distance.py +49 -42
  452. scipy/spatial/tests/test_distance.py +3 -1
  453. scipy/spatial/tests/test_kdtree.py +1 -0
  454. scipy/spatial/tests/test_qhull.py +7 -2
  455. scipy/spatial/transform/__init__.py +5 -3
  456. scipy/spatial/transform/_rigid_transform.cpython-312-aarch64-linux-musl.so +0 -0
  457. scipy/spatial/transform/_rotation.cpython-312-aarch64-linux-musl.so +0 -0
  458. scipy/spatial/transform/tests/test_rigid_transform.py +1221 -0
  459. scipy/spatial/transform/tests/test_rotation.py +1213 -832
  460. scipy/spatial/transform/tests/test_rotation_groups.py +3 -3
  461. scipy/spatial/transform/tests/test_rotation_spline.py +29 -8
  462. scipy/special/__init__.py +1 -47
  463. scipy/special/_add_newdocs.py +34 -772
  464. scipy/special/_basic.py +22 -25
  465. scipy/special/_comb.cpython-312-aarch64-linux-musl.so +0 -0
  466. scipy/special/_ellip_harm_2.cpython-312-aarch64-linux-musl.so +0 -0
  467. scipy/special/_gufuncs.cpython-312-aarch64-linux-musl.so +0 -0
  468. scipy/special/_logsumexp.py +67 -58
  469. scipy/special/_orthogonal.pyi +1 -1
  470. scipy/special/_specfun.cpython-312-aarch64-linux-musl.so +0 -0
  471. scipy/special/_special_ufuncs.cpython-312-aarch64-linux-musl.so +0 -0
  472. scipy/special/_spherical_bessel.py +4 -4
  473. scipy/special/_support_alternative_backends.py +212 -119
  474. scipy/special/_test_internal.cpython-312-aarch64-linux-musl.so +0 -0
  475. scipy/special/_testutils.py +4 -4
  476. scipy/special/_ufuncs.cpython-312-aarch64-linux-musl.so +0 -0
  477. scipy/special/_ufuncs.pyi +1 -0
  478. scipy/special/_ufuncs.pyx +215 -1400
  479. scipy/special/_ufuncs_cxx.cpython-312-aarch64-linux-musl.so +0 -0
  480. scipy/special/_ufuncs_cxx.pxd +2 -15
  481. scipy/special/_ufuncs_cxx.pyx +5 -44
  482. scipy/special/_ufuncs_cxx_defs.h +2 -16
  483. scipy/special/_ufuncs_defs.h +0 -8
  484. scipy/special/cython_special.cpython-312-aarch64-linux-musl.so +0 -0
  485. scipy/special/cython_special.pxd +1 -1
  486. scipy/special/tests/_cython_examples/meson.build +10 -1
  487. scipy/special/tests/test_basic.py +153 -20
  488. scipy/special/tests/test_boost_ufuncs.py +3 -0
  489. scipy/special/tests/test_cdflib.py +35 -11
  490. scipy/special/tests/test_gammainc.py +16 -0
  491. scipy/special/tests/test_hyp2f1.py +2 -2
  492. scipy/special/tests/test_log1mexp.py +85 -0
  493. scipy/special/tests/test_logsumexp.py +206 -64
  494. scipy/special/tests/test_mpmath.py +1 -0
  495. scipy/special/tests/test_nan_inputs.py +1 -1
  496. scipy/special/tests/test_orthogonal.py +17 -18
  497. scipy/special/tests/test_sf_error.py +3 -2
  498. scipy/special/tests/test_sph_harm.py +6 -7
  499. scipy/special/tests/test_support_alternative_backends.py +211 -76
  500. scipy/stats/__init__.py +4 -1
  501. scipy/stats/_ansari_swilk_statistics.cpython-312-aarch64-linux-musl.so +0 -0
  502. scipy/stats/_axis_nan_policy.py +4 -3
  503. scipy/stats/_biasedurn.cpython-312-aarch64-linux-musl.so +0 -0
  504. scipy/stats/_continued_fraction.py +387 -0
  505. scipy/stats/_continuous_distns.py +277 -310
  506. scipy/stats/_covariance.py +6 -3
  507. scipy/stats/_discrete_distns.py +39 -32
  508. scipy/stats/_distn_infrastructure.py +39 -12
  509. scipy/stats/_distribution_infrastructure.py +900 -238
  510. scipy/stats/_entropy.py +7 -8
  511. scipy/{_lib → stats}/_finite_differences.py +1 -1
  512. scipy/stats/_hypotests.py +82 -49
  513. scipy/stats/_kde.py +53 -49
  514. scipy/stats/_ksstats.py +1 -1
  515. scipy/stats/_levy_stable/__init__.py +7 -15
  516. scipy/stats/_levy_stable/levyst.cpython-312-aarch64-linux-musl.so +0 -0
  517. scipy/stats/_morestats.py +112 -67
  518. scipy/stats/_mstats_basic.py +13 -17
  519. scipy/stats/_mstats_extras.py +8 -8
  520. scipy/stats/_multivariate.py +89 -113
  521. scipy/stats/_new_distributions.py +97 -20
  522. scipy/stats/_page_trend_test.py +12 -5
  523. scipy/stats/_probability_distribution.py +265 -43
  524. scipy/stats/_qmc.py +14 -9
  525. scipy/stats/_qmc_cy.cpython-312-aarch64-linux-musl.so +0 -0
  526. scipy/stats/_qmvnt.py +16 -95
  527. scipy/stats/_qmvnt_cy.cpython-312-aarch64-linux-musl.so +0 -0
  528. scipy/stats/_quantile.py +335 -0
  529. scipy/stats/_rcont/rcont.cpython-312-aarch64-linux-musl.so +0 -0
  530. scipy/stats/_resampling.py +4 -29
  531. scipy/stats/_sampling.py +1 -1
  532. scipy/stats/_sobol.cpython-312-aarch64-linux-musl.so +0 -0
  533. scipy/stats/_stats.cpython-312-aarch64-linux-musl.so +0 -0
  534. scipy/stats/_stats_mstats_common.py +19 -2
  535. scipy/stats/_stats_py.py +534 -460
  536. scipy/stats/_stats_pythran.cpython-312-aarch64-linux-musl.so +0 -0
  537. scipy/stats/_unuran/unuran_wrapper.cpython-312-aarch64-linux-musl.so +0 -0
  538. scipy/stats/_unuran/unuran_wrapper.pyi +2 -1
  539. scipy/stats/_variation.py +5 -7
  540. scipy/stats/_wilcoxon.py +13 -7
  541. scipy/stats/tests/common_tests.py +6 -4
  542. scipy/stats/tests/test_axis_nan_policy.py +62 -24
  543. scipy/stats/tests/test_continued_fraction.py +173 -0
  544. scipy/stats/tests/test_continuous.py +379 -60
  545. scipy/stats/tests/test_continuous_basic.py +18 -12
  546. scipy/stats/tests/test_discrete_basic.py +14 -8
  547. scipy/stats/tests/test_discrete_distns.py +16 -16
  548. scipy/stats/tests/test_distributions.py +95 -75
  549. scipy/stats/tests/test_entropy.py +40 -48
  550. scipy/stats/tests/test_fit.py +4 -3
  551. scipy/stats/tests/test_hypotests.py +153 -24
  552. scipy/stats/tests/test_kdeoth.py +109 -41
  553. scipy/stats/tests/test_marray.py +289 -0
  554. scipy/stats/tests/test_morestats.py +79 -47
  555. scipy/stats/tests/test_mstats_basic.py +3 -3
  556. scipy/stats/tests/test_multivariate.py +434 -83
  557. scipy/stats/tests/test_qmc.py +13 -10
  558. scipy/stats/tests/test_quantile.py +199 -0
  559. scipy/stats/tests/test_rank.py +119 -112
  560. scipy/stats/tests/test_resampling.py +47 -56
  561. scipy/stats/tests/test_sampling.py +9 -4
  562. scipy/stats/tests/test_stats.py +799 -939
  563. scipy/stats/tests/test_variation.py +8 -6
  564. scipy/version.py +2 -2
  565. {scipy-1.15.3.dist-info → scipy-1.16.0rc1.dist-info}/LICENSE.txt +1 -1
  566. {scipy-1.15.3.dist-info → scipy-1.16.0rc1.dist-info}/METADATA +8 -8
  567. {scipy-1.15.3.dist-info → scipy-1.16.0rc1.dist-info}/RECORD +1262 -1269
  568. scipy.libs/libgcc_s-69c45f16.so.1 +0 -0
  569. scipy.libs/libgfortran-db0b6589.so.5.0.0 +0 -0
  570. scipy.libs/{libstdc++-1b614e01.so.6.0.32 → libstdc++-1f1a71be.so.6.0.33} +0 -0
  571. scipy/_lib/array_api_extra/_funcs.py +0 -484
  572. scipy/_lib/array_api_extra/_typing.py +0 -8
  573. scipy/interpolate/_bspl.cpython-312-aarch64-linux-musl.so +0 -0
  574. scipy/optimize/_cobyla.cpython-312-aarch64-linux-musl.so +0 -0
  575. scipy/optimize/_cython_nnls.cpython-312-aarch64-linux-musl.so +0 -0
  576. scipy/optimize/_slsqp.cpython-312-aarch64-linux-musl.so +0 -0
  577. scipy/spatial/qhull_src/COPYING.txt +0 -38
  578. scipy/special/libsf_error_state.so +0 -0
  579. scipy/special/tests/test_log_softmax.py +0 -109
  580. scipy/special/tests/test_xsf_cuda.py +0 -114
  581. scipy/special/xsf/binom.h +0 -89
  582. scipy/special/xsf/cdflib.h +0 -100
  583. scipy/special/xsf/cephes/airy.h +0 -307
  584. scipy/special/xsf/cephes/besselpoly.h +0 -51
  585. scipy/special/xsf/cephes/beta.h +0 -257
  586. scipy/special/xsf/cephes/cbrt.h +0 -131
  587. scipy/special/xsf/cephes/chbevl.h +0 -85
  588. scipy/special/xsf/cephes/chdtr.h +0 -193
  589. scipy/special/xsf/cephes/const.h +0 -87
  590. scipy/special/xsf/cephes/ellie.h +0 -293
  591. scipy/special/xsf/cephes/ellik.h +0 -251
  592. scipy/special/xsf/cephes/ellpe.h +0 -107
  593. scipy/special/xsf/cephes/ellpk.h +0 -117
  594. scipy/special/xsf/cephes/expn.h +0 -260
  595. scipy/special/xsf/cephes/gamma.h +0 -398
  596. scipy/special/xsf/cephes/hyp2f1.h +0 -596
  597. scipy/special/xsf/cephes/hyperg.h +0 -361
  598. scipy/special/xsf/cephes/i0.h +0 -149
  599. scipy/special/xsf/cephes/i1.h +0 -158
  600. scipy/special/xsf/cephes/igam.h +0 -421
  601. scipy/special/xsf/cephes/igam_asymp_coeff.h +0 -195
  602. scipy/special/xsf/cephes/igami.h +0 -313
  603. scipy/special/xsf/cephes/j0.h +0 -225
  604. scipy/special/xsf/cephes/j1.h +0 -198
  605. scipy/special/xsf/cephes/jv.h +0 -715
  606. scipy/special/xsf/cephes/k0.h +0 -164
  607. scipy/special/xsf/cephes/k1.h +0 -163
  608. scipy/special/xsf/cephes/kn.h +0 -243
  609. scipy/special/xsf/cephes/lanczos.h +0 -112
  610. scipy/special/xsf/cephes/ndtr.h +0 -275
  611. scipy/special/xsf/cephes/poch.h +0 -85
  612. scipy/special/xsf/cephes/polevl.h +0 -167
  613. scipy/special/xsf/cephes/psi.h +0 -194
  614. scipy/special/xsf/cephes/rgamma.h +0 -111
  615. scipy/special/xsf/cephes/scipy_iv.h +0 -811
  616. scipy/special/xsf/cephes/shichi.h +0 -248
  617. scipy/special/xsf/cephes/sici.h +0 -224
  618. scipy/special/xsf/cephes/sindg.h +0 -221
  619. scipy/special/xsf/cephes/tandg.h +0 -139
  620. scipy/special/xsf/cephes/trig.h +0 -58
  621. scipy/special/xsf/cephes/unity.h +0 -186
  622. scipy/special/xsf/cephes/zeta.h +0 -172
  623. scipy/special/xsf/config.h +0 -304
  624. scipy/special/xsf/digamma.h +0 -205
  625. scipy/special/xsf/error.h +0 -57
  626. scipy/special/xsf/evalpoly.h +0 -47
  627. scipy/special/xsf/expint.h +0 -266
  628. scipy/special/xsf/hyp2f1.h +0 -694
  629. scipy/special/xsf/iv_ratio.h +0 -173
  630. scipy/special/xsf/lambertw.h +0 -150
  631. scipy/special/xsf/loggamma.h +0 -163
  632. scipy/special/xsf/sici.h +0 -200
  633. scipy/special/xsf/tools.h +0 -427
  634. scipy/special/xsf/trig.h +0 -164
  635. scipy/special/xsf/wright_bessel.h +0 -843
  636. scipy/special/xsf/zlog1.h +0 -35
  637. scipy/stats/_mvn.cpython-312-aarch64-linux-musl.so +0 -0
  638. scipy.libs/libgcc_s-7393e603.so.1 +0 -0
  639. scipy.libs/libgfortran-eb933d8e.so.5.0.0 +0 -0
  640. {scipy-1.15.3.dist-info → scipy-1.16.0rc1.dist-info}/WHEEL +0 -0
scipy/ndimage/_filters.py CHANGED
@@ -33,8 +33,10 @@ import numbers
33
33
  import warnings
34
34
  import numpy as np
35
35
  import operator
36
+ import math
36
37
 
37
38
  from scipy._lib._util import normalize_axis_index
39
+ from scipy._lib._array_api import array_namespace, is_cupy, xp_size
38
40
  from . import _ni_support
39
41
  from . import _nd_image
40
42
  from . import _ni_docstrings
@@ -47,7 +49,413 @@ __all__ = ['correlate1d', 'convolve1d', 'gaussian_filter1d', 'gaussian_filter',
47
49
  'uniform_filter1d', 'uniform_filter', 'minimum_filter1d',
48
50
  'maximum_filter1d', 'minimum_filter', 'maximum_filter',
49
51
  'rank_filter', 'median_filter', 'percentile_filter',
50
- 'generic_filter1d', 'generic_filter']
52
+ 'generic_filter1d', 'generic_filter', 'vectorized_filter']
53
+
54
+
55
+ def _vectorized_filter_iv(input, function, size, footprint, output, mode, cval, origin,
56
+ axes, batch_memory):
57
+ xp = array_namespace(input, footprint, output)
58
+
59
+ # vectorized_filter input validation and standardization
60
+ input = xp.asarray(input)
61
+
62
+ if not callable(function):
63
+ raise ValueError("`function` must be a callable.")
64
+
65
+ if size is None and footprint is None:
66
+ raise ValueError("Either `size` or `footprint` must be provided.")
67
+
68
+ if size is not None and footprint is not None:
69
+ raise ValueError("Either `size` or `footprint` may be provided, not both.")
70
+
71
+ # Either footprint or size must be provided, and these determine the core
72
+ # dimensionality...
73
+ footprinted_function = function
74
+ if size is not None:
75
+ # If provided, size must be an integer or tuple of integers.
76
+ size = (size,)*input.ndim if np.isscalar(size) else tuple(size)
77
+ valid = [xp.isdtype(xp.asarray(i).dtype, 'integral') and i > 0 for i in size]
78
+ if not all(valid):
79
+ raise ValueError("All elements of `size` must be positive integers.")
80
+ else:
81
+ # If provided, `footprint` must be array-like
82
+ footprint = xp.asarray(footprint, dtype=xp.bool)
83
+ size = footprint.shape
84
+ def footprinted_function(input, *args, axis=-1, **kwargs):
85
+ return function(input[..., footprint], *args, axis=-1, **kwargs)
86
+
87
+ n_axes = len(size)
88
+ n_batch = input.ndim - n_axes
89
+
90
+ # ...which can't exceed the dimensionality of `input`.
91
+ if n_axes > input.ndim:
92
+ message = ("The dimensionality of the window (`len(size)` or `footprint.ndim`) "
93
+ "may not exceed the number of axes of `input` (`input.ndim`).")
94
+ raise ValueError(message)
95
+
96
+ # If this is not *equal* to the dimensionality of `input`, then `axes`
97
+ # must be a provided tuple, and its length must equal the core dimensionality.
98
+ elif n_axes < input.ndim:
99
+ if axes is None:
100
+ message = ("`axes` must be provided if the dimensionality of the window "
101
+ "(`len(size)` or `footprint.ndim`) does not equal the number "
102
+ "of axes of `input` (`input.ndim`).")
103
+ raise ValueError(message)
104
+ axes = (axes,) if np.isscalar(axes) else axes
105
+ else:
106
+ axes = tuple(range(-n_axes, 0))
107
+
108
+ # If `origin` is provided, then it must be "broadcastable" to a tuple with length
109
+ # equal to the core dimensionality.
110
+ if origin is None:
111
+ origin = (0,) * n_axes
112
+ else:
113
+ origin = (origin,)*n_axes if np.isscalar(origin) else tuple(origin)
114
+ integral = [xp.isdtype(xp.asarray(i).dtype, 'integral') for i in origin]
115
+ if not all(integral):
116
+ raise ValueError("All elements of `origin` must be integers.")
117
+ if not len(origin) == n_axes:
118
+ message = ("`origin` must be an integer or tuple of integers with length "
119
+ "equal to the number of axes.")
120
+ raise ValueError(message)
121
+
122
+ # mode must be one of the allowed strings, and we should convert it to the
123
+ # value required by `np.pad`/`cp.pad` here.
124
+ valid_modes = {'reflect', 'constant', 'nearest', 'mirror', 'wrap',
125
+ 'grid-mirror', 'grid-constant', 'grid-wrap', 'valid'}
126
+ if mode not in valid_modes:
127
+ raise ValueError(f"`mode` must be one of {valid_modes}.")
128
+ mode_map = {'nearest': 'edge', 'reflect': 'symmetric', 'mirror': 'reflect',
129
+ 'grid-mirror': 'reflect', 'grid-constant': 'constant',
130
+ 'grid-wrap': 'wrap'}
131
+ mode = mode_map.get(mode, mode)
132
+
133
+ if mode == 'valid' and any(origin):
134
+ raise ValueError("`mode='valid'` is incompatible with use of `origin`.")
135
+
136
+ if cval is None:
137
+ cval = 0.0
138
+ elif mode != 'constant':
139
+ raise ValueError("Use of `cval` is compatible only with `mode='constant'`.")
140
+
141
+ # `cval` must be a scalar or "broadcastable" to a tuple with the same
142
+ # dimensionality of `input`. (Full input validation done by `np.pad`/`cp.pad`.)
143
+ if not xp.isdtype(xp.asarray(cval).dtype, 'numeric'):
144
+ raise ValueError("`cval` must include only numbers.")
145
+
146
+ # `batch_memory` must be a positive number.
147
+ temp = xp.asarray(batch_memory)
148
+ if temp.ndim != 0 or (not xp.isdtype(temp.dtype, 'numeric')) or temp <= 0:
149
+ raise ValueError("`batch_memory` must be positive number.")
150
+
151
+ # For simplicity, work with `axes` at the end.
152
+ working_axes = tuple(range(-n_axes, 0))
153
+ if axes is not None:
154
+ input = xp.moveaxis(input, axes, working_axes)
155
+ output = (xp.moveaxis(output, axes, working_axes)
156
+ if output is not None else output)
157
+
158
+ # Wrap the function to limit maximum memory usage, deal with `footprint`,
159
+ # and populate `output`. The latter requires some verbosity because we
160
+ # don't know the output dtype.
161
+ def wrapped_function(view, output=output):
162
+ kwargs = {'axis': working_axes}
163
+
164
+ if working_axes == ():
165
+ return footprinted_function(xp.asarray(view), **kwargs)
166
+
167
+ # for now, assume we only have to iterate over zeroth axis
168
+ chunk_size = math.prod(view.shape[1:]) * view.dtype.itemsize
169
+ slices_per_batch = min(view.shape[0], batch_memory // chunk_size)
170
+ if slices_per_batch < 1:
171
+ raise ValueError("`batch_memory` is insufficient for minimum chunk size.")
172
+
173
+ elif slices_per_batch == view.shape[0]:
174
+ if output is None:
175
+ return footprinted_function(xp.asarray(view), **kwargs)
176
+ else:
177
+ output[...] = footprinted_function(xp.asarray(view), **kwargs)
178
+ return output
179
+
180
+ for i in range(0, view.shape[0], slices_per_batch):
181
+ i2 = min(i + slices_per_batch, view.shape[0])
182
+ if output is None:
183
+ # Look at the dtype before allocating the array. (In a follow-up, we
184
+ # can also look at the shape to support non-scalar elements.)
185
+ temp = footprinted_function(xp.asarray(view[i:i2]), **kwargs)
186
+ output = xp.empty(view.shape[:-n_axes], dtype=temp.dtype)
187
+ output[i:i2, ...] = temp
188
+ else:
189
+ output[i:i2, ...] = footprinted_function(xp.asarray(view[i:i2]),
190
+ **kwargs)
191
+ return output
192
+
193
+ return (input, wrapped_function, size, mode, cval,
194
+ origin, working_axes, n_axes, n_batch, xp)
195
+
196
+
197
+ @_ni_docstrings.docfiller
198
+ def vectorized_filter(input, function, *, size=None, footprint=None, output=None,
199
+ mode='reflect', cval=None, origin=None, axes=None,
200
+ batch_memory=2**30):
201
+ """Filter an array with a vectorized Python callable as the kernel
202
+
203
+ Parameters
204
+ ----------
205
+ %(input)s
206
+ function : callable
207
+ Kernel to apply over a window centered at each element of `input`.
208
+ Callable must have signature::
209
+
210
+ function(window: ndarray, *, axis: int | tuple) -> scalar
211
+
212
+ where ``axis`` specifies the axis (or axes) of ``window`` along which
213
+ the filter function is evaluated.
214
+ %(size_foot)s
215
+ %(output)s
216
+ mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional
217
+ The `mode` parameter determines how the input array is extended
218
+ beyond its boundaries. Default is 'reflect'. Behavior for each valid
219
+ value is as follows:
220
+
221
+ 'reflect' (`d c b a | a b c d | d c b a`)
222
+ The input is extended by reflecting about the edge of the last
223
+ pixel. This mode is also sometimes referred to as half-sample
224
+ symmetric.
225
+
226
+ 'constant' (`k k k k | a b c d | k k k k`)
227
+ The input is extended by filling all values beyond the edge with
228
+ the same constant value, defined by the `cval` parameter.
229
+
230
+ 'nearest' (`a a a a | a b c d | d d d d`)
231
+ The input is extended by replicating the last pixel.
232
+
233
+ 'mirror' (`d c b | a b c d | c b a`)
234
+ The input is extended by reflecting about the center of the last
235
+ pixel. This mode is also sometimes referred to as whole-sample
236
+ symmetric.
237
+
238
+ 'wrap' (`a b c d | a b c d | a b c d`)
239
+ The input is extended by wrapping around to the opposite edge.
240
+
241
+ 'valid' (`| a b c d |`)
242
+ The input is not extended; rather, the output shape is reduced depending
243
+ on the window size according to the following calculation::
244
+
245
+ window_size = np.asarray(size if size is not None else footprint.shape)
246
+ output_shape = np.asarray(input.shape)
247
+ output_shape[np.asarray(axes)] -= (window_size - 1)
248
+
249
+ %(cval)s
250
+ %(origin_multiple)s
251
+ axes : tuple of int, optional
252
+ If None, `input` is filtered along all axes. Otherwise, `input` is filtered
253
+ along the specified axes. When `axes` is specified, the dimensionality of
254
+ `footprint` and the length of any tuples used for `size` or `origin` must
255
+ match the length of `axes`. The ith axis of `footprint` and the ith element
256
+ in these tuples corresponds to the ith element of `axes`.
257
+ batch_memory : int, default: 2**30
258
+ The maximum number of bytes occupied by data in the ``window``
259
+ array passed to ``function``.
260
+
261
+ Returns
262
+ -------
263
+ output : ndarray
264
+ Filtered array. The dtype is the output dtype of `function`. If `function` is
265
+ scalar-valued when applied to a single window, the shape of the output is that
266
+ of `input` (unless ``mode=='valid'``; see `mode` documentation). If `function`
267
+ is multi-valued when applied to a single window, the placement of the
268
+ corresponding dimensions within the output shape depends entirely on the
269
+ behavior of `function`; see Examples.
270
+
271
+ See Also
272
+ --------
273
+ scipy.ndimage.generic_filter
274
+
275
+ Notes
276
+ -----
277
+ This function works by padding `input` according to `mode`, then calling the
278
+ provided `function` on chunks of a sliding window view over the padded array.
279
+ This approach is very simple and flexible, and so the function has many features
280
+ not offered by some other filter functions (e.g. memory control, ``float16``
281
+ and complex dtype support, and any NaN-handling features provided by the
282
+ `function` argument).
283
+
284
+ However, this brute-force approach may perform considerable redundant work.
285
+ Use a specialized filter (e.g. `minimum_filter` instead of this function with
286
+ `numpy.min` as the callable; `uniform_filter` instead of this function with
287
+ `numpy.mean` as the callable) when possible, as it may use a more efficient
288
+ algorithm.
289
+
290
+ When a specialized filter is not available, this function is ideal when `function`
291
+ is a vectorized, pure-Python callable. Even better performance may be possible
292
+ by passing a `scipy.LowLevelCallable` to `generic_filter`. `generic_filter` may
293
+ also be preferred for expensive callables with large filter footprints and
294
+ callables that are not vectorized (i.e. those without ``axis`` support).
295
+
296
+ This function does not provide the ``extra_arguments`` or ``extra_keywords``
297
+ arguments provided by some `ndimage` functions. There are two reasons:
298
+
299
+ - The passthrough functionality can be achieved by the user: simply wrap the
300
+ original callable in another function that provides the required arguments;
301
+ e.g., ``function=lambda input, axis: function(input, *extra_arguments, axis=axis, **extra_keywords)``.
302
+ - There are use cases for `function` to be passed additional *sliding-window data*
303
+ to `function` besides `input`. This is not yet implemented, but we reserve
304
+ these argument names for such a feature, which would add capability rather than
305
+ providing a duplicate interface to existing capability.
306
+
307
+ Examples
308
+ --------
309
+ Suppose we wish to perform a median filter with even window size on a ``float16``
310
+ image. Furthermore, the image has NaNs that we wish to be ignored (and effectively
311
+ removed by the filter). `median_filter` does not support ``float16`` data, its
312
+ behavior when NaNs are present is not defined, and for even window sizes, it does
313
+ not return the usual sample median - the average of the two middle elements. This
314
+ would be an excellent use case for `vectorized_filter` with
315
+ ``function=np.nanmedian``, which supports the required interface: it accepts a
316
+ data array of any shape as the first positional argument, and tuple of axes as
317
+ keyword argument ``axis``.
318
+
319
+ >>> import numpy as np
320
+ >>> from scipy import datasets, ndimage
321
+ >>> from scipy.ndimage import vectorized_filter
322
+ >>> import matplotlib.pyplot as plt
323
+ >>> ascent = ndimage.zoom(datasets.ascent(), 0.5).astype(np.float16)
324
+ >>> ascent[::16, ::16] = np.nan
325
+ >>> result = vectorized_filter(ascent, function=np.nanmedian, size=4)
326
+
327
+ Plot the original and filtered images.
328
+
329
+ >>> fig = plt.figure()
330
+ >>> plt.gray() # show the filtered result in grayscale
331
+ >>> ax1 = fig.add_subplot(121) # left side
332
+ >>> ax2 = fig.add_subplot(122) # right side
333
+ >>> ax1.imshow(ascent)
334
+ >>> ax2.imshow(result)
335
+ >>> fig.tight_layout()
336
+ >>> plt.show()
337
+
338
+ Another need satisfied by `vectorized_filter` is to perform multi-output
339
+ filters. For instance, suppose we wish to filter an image according to the 25th
340
+ and 75th percentiles in addition to the median. We could perform the three
341
+ filters separately.
342
+
343
+ >>> ascent = ndimage.zoom(datasets.ascent(), 0.5)
344
+ >>> def get_quantile_fun(p):
345
+ ... return lambda x, axis: np.quantile(x, p, axis=axis)
346
+ >>> ref1 = vectorized_filter(ascent, get_quantile_fun(0.25), size=4)
347
+ >>> ref2 = vectorized_filter(ascent, get_quantile_fun(0.50), size=4)
348
+ >>> ref3 = vectorized_filter(ascent, get_quantile_fun(0.75), size=4)
349
+ >>> ref = np.stack([ref1, ref2, ref3])
350
+
351
+ However, `vectorized_filter` also supports filters that return multiple outputs
352
+ as long as `output` is unspecified and `batch_memory` is sufficiently high to
353
+ perform the calculation in a single chunk.
354
+
355
+ >>> def quartiles(x, axis):
356
+ ... return np.quantile(x, [0.25, 0.50, 0.75], axis=axis)
357
+ >>> res = vectorized_filter(ascent, quartiles, size=4, batch_memory=np.inf)
358
+ >>> np.all(np.isclose(res, ref))
359
+ np.True_
360
+
361
+ The placement of the additional dimension(s) corresponding with multiple outputs
362
+ is at the discretion of `function`. `quartiles` happens to prepend one dimension
363
+ corresponding with the three outputs simply because that is the behavior of
364
+ `np.quantile`:
365
+
366
+ >>> res.shape == (3,) + ascent.shape
367
+ True
368
+
369
+ If we wished for this dimension to be appended:
370
+
371
+ >>> def quartiles(x, axis):
372
+ ... return np.moveaxis(np.quantile(x, [0.25, 0.50, 0.75], axis=axis), 0, -1)
373
+ >>> res = vectorized_filter(ascent, quartiles, size=4, batch_memory=np.inf)
374
+ >>> res.shape == ascent.shape + (3,)
375
+ True
376
+
377
+ Suppose we wish to implment a "mode" filter - a filter that selects the most
378
+ frequently occuring value within the window. A simple (but rather slow)
379
+ approach is to use `generic_filter` with `scipy.stats.mode`.
380
+
381
+ >>> from scipy import stats
382
+ >>> rng = np.random.default_rng(3195824598724609246)
383
+ >>> input = rng.integers(255, size=(50, 50)).astype(np.uint8)
384
+ >>> def simple_mode(input):
385
+ ... return stats.mode(input, axis=None).mode
386
+ >>> ref = ndimage.generic_filter(input, simple_mode, size=5)
387
+
388
+ If speed is important, `vectorized_filter` can take advantage of the performance
389
+ benefit of a vectorized callable.
390
+
391
+ >>> def vectorized_mode(x, axis=(-1,)):
392
+ ... n_axes = 1 if np.isscalar(axis) else len(axis)
393
+ ... x = np.moveaxis(x, axis, tuple(range(-n_axes, 0)))
394
+ ... x = np.reshape(x, x.shape[:-n_axes] + (-1,))
395
+ ... y = np.sort(x, axis=-1)
396
+ ... i = np.concatenate([np.ones(y.shape[:-1] + (1,), dtype=bool),
397
+ ... y[..., :-1] != y[..., 1:]], axis=-1)
398
+ ... indices = np.arange(y.size)[i.ravel()]
399
+ ... counts = np.diff(indices, append=y.size)
400
+ ... counts = np.reshape(np.repeat(counts, counts), y.shape)
401
+ ... k = np.argmax(counts, axis=-1, keepdims=True)
402
+ ... return np.take_along_axis(y, k, axis=-1)[..., 0]
403
+ >>> res = vectorized_filter(input, vectorized_mode, size=5)
404
+ >>> np.all(res == ref)
405
+ np.True_
406
+
407
+ Depending on the machine, the `vectorized_filter` version may be as much as
408
+ 100x faster.
409
+
410
+ """ # noqa: E501
411
+
412
+ (input, function, size, mode, cval, origin, working_axes, n_axes, n_batch, xp
413
+ ) = _vectorized_filter_iv(input, function, size, footprint, output, mode, cval,
414
+ origin, axes, batch_memory)
415
+
416
+ # `np.pad`/`cp.pad` raises with these sorts of cases, but the best result is
417
+ # probably to return the original array. It could be argued that we should call
418
+ # the function on the empty array with `axis=None` just to determine the output
419
+ # dtype, but I can also see rationale against that.
420
+ if xp_size(input) == 0:
421
+ return xp.asarray(input)
422
+
423
+ # This seems to be defined.
424
+ if input.ndim == 0 and size == ():
425
+ return xp.asarray(function(input) if footprint is None
426
+ else function(input[footprint]))
427
+
428
+ if is_cupy(xp):
429
+ # CuPy is the only GPU backend that has `pad` (with all modes)
430
+ # and `sliding_window_view`. An enhancement would be to use
431
+ # no-copy conversion to CuPy whenever the data is on the GPU.
432
+ cp = xp # let there be no ambiguity!
433
+ swv = cp.lib.stride_tricks.sliding_window_view
434
+ pad = cp.pad
435
+ else:
436
+ # Try to perform no-copy conversion to NumPy for padding and
437
+ # `sliding_window_view`. (If that fails, fine - for now, the only
438
+ # GPU backend we support is CuPy.)
439
+ swv = np.lib.stride_tricks.sliding_window_view
440
+ pad = np.pad
441
+ input = np.asarray(input)
442
+ cval = np.asarray(cval)[()] if mode == 'constant' else None
443
+
444
+ # Border the image according to `mode` and `offset`.
445
+ if mode != 'valid':
446
+ kwargs = {'constant_values': cval} if mode == 'constant' else {}
447
+ borders = tuple((i//2 + j, (i-1)//2 - j) for i, j in zip(size, origin))
448
+ bordered_input = pad(input, ((0, 0),)*n_batch + borders, mode=mode, **kwargs)
449
+ else:
450
+ bordered_input = input
451
+
452
+ # Evaluate function with sliding window view. Function is already wrapped to
453
+ # manage memory, deal with `footprint`, populate `output`, etc.
454
+ view = swv(bordered_input, size, working_axes)
455
+ res = function(view)
456
+
457
+ # move working_axes back to original positions
458
+ return xp.moveaxis(res, working_axes, axes) if axes is not None else res
51
459
 
52
460
 
53
461
  def _invalid_origin(origin, lenw):
@@ -738,7 +1146,7 @@ def generic_gradient_magnitude(input, derivative, output=None,
738
1146
 
739
1147
  Returns
740
1148
  -------
741
- generic_gradient_matnitude : ndarray
1149
+ generic_gradient_magnitude : ndarray
742
1150
  Filtered array. Has the same shape as `input`.
743
1151
 
744
1152
  """
@@ -1152,6 +1560,8 @@ def uniform_filter(input, size=3, output=None, mode="reflect",
1152
1560
  with a limited precision, the results may be imprecise because
1153
1561
  intermediate results may be stored with insufficient precision.
1154
1562
 
1563
+ %(nan)s
1564
+
1155
1565
  Examples
1156
1566
  --------
1157
1567
  >>> from scipy import ndimage, datasets
@@ -1469,6 +1879,8 @@ def maximum_filter(input, size=None, footprint=None, output=None,
1469
1879
  A sequence of modes (one per axis) is only supported when the footprint is
1470
1880
  separable. Otherwise, a single mode string must be provided.
1471
1881
 
1882
+ %(nan)s
1883
+
1472
1884
  Examples
1473
1885
  --------
1474
1886
  >>> from scipy import ndimage, datasets
@@ -1667,6 +2079,15 @@ def median_filter(input, size=None, footprint=None, output=None,
1667
2079
  the specialised function `scipy.signal.medfilt2d` may be faster. It is
1668
2080
  however limited to constant mode with ``cval=0``.
1669
2081
 
2082
+ The filter always returns the argument that would appear at index ``n // 2`` in
2083
+ a sorted array, where ``n`` is the number of elements in the footprint of the
2084
+ filter. Note that this differs from the conventional definition of the median
2085
+ when ``n`` is even. Also, this function does not support the ``float16`` dtype,
2086
+ behavior in the presence of NaNs is undefined, and memory consumption scales with
2087
+ ``n**4``. For ``float16`` support, greater control over the definition of the
2088
+ filter, and to limit memory usage, consider using `vectorized_filter` with
2089
+ NumPy functions `np.median` or `np.nanmedian`.
2090
+
1670
2091
  Examples
1671
2092
  --------
1672
2093
  >>> from scipy import ndimage, datasets
@@ -1851,13 +2272,20 @@ def generic_filter(input, function, size=None, footprint=None,
1851
2272
 
1852
2273
  Returns
1853
2274
  -------
1854
- generic_filter : ndarray
2275
+ output : ndarray
1855
2276
  Filtered array. Has the same shape as `input`.
1856
2277
 
2278
+ See Also
2279
+ --------
2280
+ vectorized_filter : similar functionality, but optimized for vectorized callables
2281
+
1857
2282
  Notes
1858
2283
  -----
1859
- This function also accepts low-level callback functions with one of
1860
- the following signatures and wrapped in `scipy.LowLevelCallable`:
2284
+ This function is ideal for use with instances of `scipy.LowLevelCallable`;
2285
+ for vectorized, pure-Python callables, consider `vectorized_filter` for improved
2286
+ performance.
2287
+
2288
+ Low-level callback functions must have one of the following signatures:
1861
2289
 
1862
2290
  .. code:: c
1863
2291
 
@@ -33,6 +33,7 @@ import warnings
33
33
 
34
34
  import numpy as np
35
35
  from scipy._lib._util import normalize_axis_index
36
+ from scipy._lib import array_api_extra as xpx
36
37
 
37
38
  from scipy import special
38
39
  from . import _ni_support
@@ -533,6 +534,35 @@ def affine_transform(input, matrix, offset=0.0, output_shape=None,
533
534
  affine_transform : ndarray
534
535
  The transformed input.
535
536
 
537
+ Examples
538
+ --------
539
+ Use `affine_transform` to stretch an image::
540
+
541
+ >>> from scipy.ndimage import affine_transform
542
+ >>> from scipy.datasets import face
543
+ >>> from matplotlib import pyplot as plt
544
+ >>> import numpy as np
545
+ >>> im = face(gray=True)
546
+ >>> matrix = (0.5, 2)
547
+ >>> im2 = affine_transform(im, matrix)
548
+ >>> plt.imshow(im2)
549
+ >>> plt.show()
550
+
551
+ Rotate an image by 90 degrees and project it onto an expanded canvas::
552
+
553
+ >>> matrix = ((0, 1), (1, 0))
554
+ >>> im3 = affine_transform(im, matrix, output_shape=(1024, 1024))
555
+ >>> plt.imshow(im3)
556
+ >>> plt.show()
557
+
558
+ Offset the rotation so that the image is centred::
559
+
560
+ >>> output_shape = (1200, 1200)
561
+ >>> offset = (np.array(im.shape) - output_shape) / 2
562
+ >>> im4 = affine_transform(im, matrix, offset=offset, output_shape=output_shape)
563
+ >>> plt.imshow(im4)
564
+ >>> plt.show()
565
+
536
566
  Notes
537
567
  -----
538
568
  The given matrix and offset are used to find for each point in the
@@ -616,12 +646,6 @@ def affine_transform(input, matrix, offset=0.0, output_shape=None,
616
646
  if not offset.flags.contiguous:
617
647
  offset = offset.copy()
618
648
  if matrix.ndim == 1:
619
- warnings.warn(
620
- "The behavior of affine_transform with a 1-D "
621
- "array supplied for the matrix parameter has changed in "
622
- "SciPy 0.18.0.",
623
- stacklevel=2
624
- )
625
649
  _nd_image.zoom_shift(filtered, matrix, offset/matrix, output, order,
626
650
  mode, cval, npad, False)
627
651
  else:
@@ -818,6 +842,12 @@ def zoom(input, zoom, output=None, order=3, mode='constant', cval=0.0,
818
842
  complex_output = np.iscomplexobj(input)
819
843
  output = _ni_support._get_output(output, input, shape=output_shape,
820
844
  complex_output=complex_output)
845
+ if all(z == 1 for z in zoom) and prefilter: # early exit for gh-20999
846
+ # zoom 1 means "return original image". If `prefilter=False`,
847
+ # `input` is *not* the original image; processing is still needed
848
+ # to undo the filter. So we only early exit if `prefilter`.
849
+ output = xpx.at(output)[...].set(input)
850
+ return output
821
851
  if complex_output:
822
852
  # import under different name to avoid confusion with zoom parameter
823
853
  from scipy.ndimage._interpolation import zoom as _zoom
@@ -630,6 +630,7 @@ def _stats(input, labels=None, index=None, centered=False):
630
630
  if labels is None:
631
631
  return single_group(input)
632
632
 
633
+ labels = np.asarray(labels)
633
634
  # ensure input and labels match sizes
634
635
  input, labels = np.broadcast_arrays(input, labels)
635
636
 
@@ -944,6 +945,7 @@ def _select(input, labels=None, index=None, find_min=False, find_max=False,
944
945
  if labels is None:
945
946
  return single_group(input, positions)
946
947
 
948
+ labels = np.asarray(labels)
947
949
  # ensure input and labels match sizes
948
950
  input, labels = np.broadcast_arrays(input, labels)
949
951
 
@@ -1053,7 +1055,7 @@ def minimum(input, labels=None, index=None):
1053
1055
 
1054
1056
  Returns
1055
1057
  -------
1056
- minimum : float or list of floats
1058
+ output : a scalar or list of integers or floats based on input type.
1057
1059
  List of minima of `input` over the regions determined by `labels` and
1058
1060
  whose index is in `index`. If `index` or `labels` are not specified, a
1059
1061
  float is returned: the minimal value of `input` if `labels` is None,
@@ -1116,7 +1118,7 @@ def maximum(input, labels=None, index=None):
1116
1118
 
1117
1119
  Returns
1118
1120
  -------
1119
- output : float or list of floats
1121
+ output : a scalar or list of integers or floats based on input type.
1120
1122
  List of maxima of `input` over the regions determined by `labels` and
1121
1123
  whose index is in `index`. If `index` or `labels` are not specified, a
1122
1124
  float is returned: the maximal value of `input` if `labels` is None,
@@ -221,6 +221,10 @@ def _binary_erosion(input, structure, iterations, mask, output,
221
221
  raise TypeError('iterations parameter should be an integer') from e
222
222
 
223
223
  input = np.asarray(input)
224
+ # The Cython code can't cope with broadcasted inputs
225
+ if not input.flags.c_contiguous and not input.flags.f_contiguous:
226
+ input = np.ascontiguousarray(input)
227
+
224
228
  ndim = input.ndim
225
229
  if np.iscomplexobj(input):
226
230
  raise TypeError('Complex type not supported')
@@ -1791,6 +1795,7 @@ def morphological_laplace(input, size=None, footprint=None, structure=None,
1791
1795
  Output
1792
1796
 
1793
1797
  """
1798
+ input = np.asarray(input)
1794
1799
  tmp1 = grey_dilation(input, size, footprint, structure, None, mode,
1795
1800
  cval, origin, axes=axes)
1796
1801
  if isinstance(output, np.ndarray):
@@ -17,6 +17,9 @@ _output_doc = (
17
17
  The array in which to place the output, or the dtype of the
18
18
  returned array. By default an array of the same dtype as input
19
19
  will be created.""")
20
+ _nan_doc = (
21
+ """The behavior of this function with NaN elements is undefined. To control
22
+ behavior in the presence of NaNs, consider using `vectorized_filter`.""")
20
23
  _size_foot_doc = (
21
24
  """size : scalar or tuple, optional
22
25
  See footprint, below. Ignored if footprint is given.
@@ -204,7 +207,8 @@ docdict = {
204
207
  'origin_multiple': _origin_multiple_doc,
205
208
  'extra_arguments': _extra_arguments_doc,
206
209
  'extra_keywords': _extra_keywords_doc,
207
- 'prefilter': _prefilter_doc
210
+ 'prefilter': _prefilter_doc,
211
+ 'nan': _nan_doc,
208
212
  }
209
213
 
210
214
  docfiller: Final = doccer.filldoc(docdict)
@@ -84,7 +84,7 @@ def _get_output(output, input, shape=None, complex_output=False):
84
84
  else:
85
85
  complex_type = np.promote_types(input.dtype, np.complex64)
86
86
  output = np.zeros(shape, dtype=complex_type)
87
- elif isinstance(output, (type, np.dtype)):
87
+ elif isinstance(output, type | np.dtype):
88
88
  # Classes (like `np.float32`) and dtypes are interpreted as dtype
89
89
  if complex_output and np.dtype(output).kind != 'c':
90
90
  warnings.warn("promoting specified output dtype to complex", stacklevel=3)
@@ -137,7 +137,3 @@ def _skip_if_dtype(arg):
137
137
  return None if issubclass(arg, np.generic) else arg
138
138
  else:
139
139
  return None if isinstance(arg, np.dtype) else arg
140
-
141
-
142
- def _skip_if_int(arg):
143
- return None if (arg is None or isinstance(arg, int)) else arg