scipy 1.15.2__cp311-cp311-macosx_12_0_arm64.whl → 1.16.0rc1__cp311-cp311-macosx_12_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (626) hide show
  1. scipy/.dylibs/libscipy_openblas.dylib +0 -0
  2. scipy/__config__.py +7 -7
  3. scipy/__init__.py +3 -6
  4. scipy/_cyutility.cpython-311-darwin.so +0 -0
  5. scipy/_lib/_array_api.py +497 -161
  6. scipy/_lib/_array_api_compat_vendor.py +9 -0
  7. scipy/_lib/_bunch.py +4 -0
  8. scipy/_lib/_ccallback_c.cpython-311-darwin.so +0 -0
  9. scipy/_lib/_docscrape.py +1 -1
  10. scipy/_lib/_elementwise_iterative_method.py +15 -26
  11. scipy/_lib/_sparse.py +41 -0
  12. scipy/_lib/_test_ccallback.cpython-311-darwin.so +0 -0
  13. scipy/_lib/_test_deprecation_call.cpython-311-darwin.so +0 -0
  14. scipy/_lib/_test_deprecation_def.cpython-311-darwin.so +0 -0
  15. scipy/_lib/_testutils.py +6 -2
  16. scipy/_lib/_util.py +222 -125
  17. scipy/_lib/array_api_compat/__init__.py +4 -4
  18. scipy/_lib/array_api_compat/_internal.py +19 -6
  19. scipy/_lib/array_api_compat/common/__init__.py +1 -1
  20. scipy/_lib/array_api_compat/common/_aliases.py +365 -193
  21. scipy/_lib/array_api_compat/common/_fft.py +94 -64
  22. scipy/_lib/array_api_compat/common/_helpers.py +413 -180
  23. scipy/_lib/array_api_compat/common/_linalg.py +116 -40
  24. scipy/_lib/array_api_compat/common/_typing.py +179 -10
  25. scipy/_lib/array_api_compat/cupy/__init__.py +1 -4
  26. scipy/_lib/array_api_compat/cupy/_aliases.py +61 -41
  27. scipy/_lib/array_api_compat/cupy/_info.py +16 -6
  28. scipy/_lib/array_api_compat/cupy/_typing.py +24 -39
  29. scipy/_lib/array_api_compat/dask/array/__init__.py +6 -3
  30. scipy/_lib/array_api_compat/dask/array/_aliases.py +267 -108
  31. scipy/_lib/array_api_compat/dask/array/_info.py +105 -34
  32. scipy/_lib/array_api_compat/dask/array/fft.py +5 -8
  33. scipy/_lib/array_api_compat/dask/array/linalg.py +21 -22
  34. scipy/_lib/array_api_compat/numpy/__init__.py +13 -15
  35. scipy/_lib/array_api_compat/numpy/_aliases.py +98 -49
  36. scipy/_lib/array_api_compat/numpy/_info.py +36 -16
  37. scipy/_lib/array_api_compat/numpy/_typing.py +27 -43
  38. scipy/_lib/array_api_compat/numpy/fft.py +11 -5
  39. scipy/_lib/array_api_compat/numpy/linalg.py +75 -22
  40. scipy/_lib/array_api_compat/torch/__init__.py +3 -5
  41. scipy/_lib/array_api_compat/torch/_aliases.py +262 -159
  42. scipy/_lib/array_api_compat/torch/_info.py +27 -16
  43. scipy/_lib/array_api_compat/torch/_typing.py +3 -0
  44. scipy/_lib/array_api_compat/torch/fft.py +17 -18
  45. scipy/_lib/array_api_compat/torch/linalg.py +16 -16
  46. scipy/_lib/array_api_extra/__init__.py +26 -3
  47. scipy/_lib/array_api_extra/_delegation.py +171 -0
  48. scipy/_lib/array_api_extra/_lib/__init__.py +1 -0
  49. scipy/_lib/array_api_extra/_lib/_at.py +463 -0
  50. scipy/_lib/array_api_extra/_lib/_backends.py +46 -0
  51. scipy/_lib/array_api_extra/_lib/_funcs.py +937 -0
  52. scipy/_lib/array_api_extra/_lib/_lazy.py +357 -0
  53. scipy/_lib/array_api_extra/_lib/_testing.py +278 -0
  54. scipy/_lib/array_api_extra/_lib/_utils/__init__.py +1 -0
  55. scipy/_lib/array_api_extra/_lib/_utils/_compat.py +74 -0
  56. scipy/_lib/array_api_extra/_lib/_utils/_compat.pyi +45 -0
  57. scipy/_lib/array_api_extra/_lib/_utils/_helpers.py +559 -0
  58. scipy/_lib/array_api_extra/_lib/_utils/_typing.py +10 -0
  59. scipy/_lib/array_api_extra/_lib/_utils/_typing.pyi +105 -0
  60. scipy/_lib/array_api_extra/testing.py +359 -0
  61. scipy/_lib/decorator.py +2 -2
  62. scipy/_lib/doccer.py +1 -7
  63. scipy/_lib/messagestream.cpython-311-darwin.so +0 -0
  64. scipy/_lib/pyprima/__init__.py +212 -0
  65. scipy/_lib/pyprima/cobyla/__init__.py +0 -0
  66. scipy/_lib/pyprima/cobyla/cobyla.py +559 -0
  67. scipy/_lib/pyprima/cobyla/cobylb.py +714 -0
  68. scipy/_lib/pyprima/cobyla/geometry.py +226 -0
  69. scipy/_lib/pyprima/cobyla/initialize.py +215 -0
  70. scipy/_lib/pyprima/cobyla/trustregion.py +492 -0
  71. scipy/_lib/pyprima/cobyla/update.py +289 -0
  72. scipy/_lib/pyprima/common/__init__.py +0 -0
  73. scipy/_lib/pyprima/common/_bounds.py +34 -0
  74. scipy/_lib/pyprima/common/_linear_constraints.py +46 -0
  75. scipy/_lib/pyprima/common/_nonlinear_constraints.py +54 -0
  76. scipy/_lib/pyprima/common/_project.py +173 -0
  77. scipy/_lib/pyprima/common/checkbreak.py +93 -0
  78. scipy/_lib/pyprima/common/consts.py +47 -0
  79. scipy/_lib/pyprima/common/evaluate.py +99 -0
  80. scipy/_lib/pyprima/common/history.py +38 -0
  81. scipy/_lib/pyprima/common/infos.py +30 -0
  82. scipy/_lib/pyprima/common/linalg.py +435 -0
  83. scipy/_lib/pyprima/common/message.py +290 -0
  84. scipy/_lib/pyprima/common/powalg.py +131 -0
  85. scipy/_lib/pyprima/common/preproc.py +277 -0
  86. scipy/_lib/pyprima/common/present.py +5 -0
  87. scipy/_lib/pyprima/common/ratio.py +54 -0
  88. scipy/_lib/pyprima/common/redrho.py +47 -0
  89. scipy/_lib/pyprima/common/selectx.py +296 -0
  90. scipy/_lib/tests/test__util.py +105 -121
  91. scipy/_lib/tests/test_array_api.py +169 -34
  92. scipy/_lib/tests/test_bunch.py +7 -0
  93. scipy/_lib/tests/test_ccallback.py +2 -10
  94. scipy/_lib/tests/test_public_api.py +13 -0
  95. scipy/cluster/_hierarchy.cpython-311-darwin.so +0 -0
  96. scipy/cluster/_optimal_leaf_ordering.cpython-311-darwin.so +0 -0
  97. scipy/cluster/_vq.cpython-311-darwin.so +0 -0
  98. scipy/cluster/hierarchy.py +393 -223
  99. scipy/cluster/tests/test_hierarchy.py +273 -335
  100. scipy/cluster/tests/test_vq.py +45 -61
  101. scipy/cluster/vq.py +39 -35
  102. scipy/conftest.py +263 -157
  103. scipy/constants/_constants.py +4 -1
  104. scipy/constants/tests/test_codata.py +2 -2
  105. scipy/constants/tests/test_constants.py +11 -18
  106. scipy/datasets/_download_all.py +15 -1
  107. scipy/datasets/_fetchers.py +7 -1
  108. scipy/datasets/_utils.py +1 -1
  109. scipy/differentiate/_differentiate.py +25 -25
  110. scipy/differentiate/tests/test_differentiate.py +24 -25
  111. scipy/fft/_basic.py +20 -0
  112. scipy/fft/_helper.py +3 -34
  113. scipy/fft/_pocketfft/helper.py +29 -1
  114. scipy/fft/_pocketfft/tests/test_basic.py +2 -4
  115. scipy/fft/_pocketfft/tests/test_real_transforms.py +4 -4
  116. scipy/fft/_realtransforms.py +13 -0
  117. scipy/fft/tests/test_basic.py +27 -25
  118. scipy/fft/tests/test_fftlog.py +16 -7
  119. scipy/fft/tests/test_helper.py +18 -34
  120. scipy/fft/tests/test_real_transforms.py +8 -10
  121. scipy/fftpack/convolve.cpython-311-darwin.so +0 -0
  122. scipy/fftpack/tests/test_basic.py +2 -4
  123. scipy/fftpack/tests/test_real_transforms.py +8 -9
  124. scipy/integrate/_bvp.py +9 -3
  125. scipy/integrate/_cubature.py +3 -2
  126. scipy/integrate/_dop.cpython-311-darwin.so +0 -0
  127. scipy/integrate/_ivp/common.py +3 -3
  128. scipy/integrate/_ivp/ivp.py +9 -2
  129. scipy/integrate/_ivp/tests/test_ivp.py +19 -0
  130. scipy/integrate/_lsoda.cpython-311-darwin.so +0 -0
  131. scipy/integrate/_ode.py +9 -2
  132. scipy/integrate/_odepack.cpython-311-darwin.so +0 -0
  133. scipy/integrate/_quad_vec.py +21 -29
  134. scipy/integrate/_quadpack.cpython-311-darwin.so +0 -0
  135. scipy/integrate/_quadpack_py.py +11 -7
  136. scipy/integrate/_quadrature.py +3 -3
  137. scipy/integrate/_rules/_base.py +2 -2
  138. scipy/integrate/_tanhsinh.py +57 -54
  139. scipy/integrate/_test_odeint_banded.cpython-311-darwin.so +0 -0
  140. scipy/integrate/_vode.cpython-311-darwin.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 +61 -43
  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-311-darwin.so +0 -0
  151. scipy/interpolate/_dierckx.cpython-311-darwin.so +0 -0
  152. scipy/interpolate/_fitpack2.py +9 -6
  153. scipy/interpolate/_fitpack_impl.py +32 -26
  154. scipy/interpolate/_fitpack_repro.py +23 -19
  155. scipy/interpolate/_interpnd.cpython-311-darwin.so +0 -0
  156. scipy/interpolate/_interpolate.py +30 -12
  157. scipy/interpolate/_ndbspline.py +13 -18
  158. scipy/interpolate/_ndgriddata.py +5 -8
  159. scipy/interpolate/_polyint.py +95 -31
  160. scipy/interpolate/_ppoly.cpython-311-darwin.so +0 -0
  161. scipy/interpolate/_rbf.py +2 -2
  162. scipy/interpolate/_rbfinterp.py +1 -1
  163. scipy/interpolate/_rgi.py +31 -26
  164. scipy/interpolate/_rgi_cython.cpython-311-darwin.so +0 -0
  165. scipy/interpolate/dfitpack.py +0 -20
  166. scipy/interpolate/interpnd.py +1 -2
  167. scipy/interpolate/tests/test_bary_rational.py +2 -2
  168. scipy/interpolate/tests/test_bsplines.py +97 -1
  169. scipy/interpolate/tests/test_fitpack2.py +39 -1
  170. scipy/interpolate/tests/test_interpnd.py +32 -20
  171. scipy/interpolate/tests/test_interpolate.py +48 -4
  172. scipy/interpolate/tests/test_rgi.py +2 -1
  173. scipy/io/_fast_matrix_market/__init__.py +2 -0
  174. scipy/io/_harwell_boeing/_fortran_format_parser.py +19 -16
  175. scipy/io/_harwell_boeing/hb.py +7 -11
  176. scipy/io/_idl.py +5 -7
  177. scipy/io/_netcdf.py +15 -5
  178. scipy/io/_test_fortran.cpython-311-darwin.so +0 -0
  179. scipy/io/arff/tests/test_arffread.py +3 -3
  180. scipy/io/matlab/__init__.py +5 -3
  181. scipy/io/matlab/_mio.py +4 -1
  182. scipy/io/matlab/_mio5.py +19 -13
  183. scipy/io/matlab/_mio5_utils.cpython-311-darwin.so +0 -0
  184. scipy/io/matlab/_mio_utils.cpython-311-darwin.so +0 -0
  185. scipy/io/matlab/_miobase.py +4 -1
  186. scipy/io/matlab/_streams.cpython-311-darwin.so +0 -0
  187. scipy/io/matlab/tests/test_mio.py +46 -18
  188. scipy/io/matlab/tests/test_mio_funcs.py +1 -1
  189. scipy/io/tests/test_mmio.py +7 -1
  190. scipy/io/tests/test_wavfile.py +41 -0
  191. scipy/io/wavfile.py +57 -10
  192. scipy/linalg/_basic.py +113 -86
  193. scipy/linalg/_cythonized_array_utils.cpython-311-darwin.so +0 -0
  194. scipy/linalg/_decomp.py +22 -9
  195. scipy/linalg/_decomp_cholesky.py +28 -13
  196. scipy/linalg/_decomp_cossin.py +45 -30
  197. scipy/linalg/_decomp_interpolative.cpython-311-darwin.so +0 -0
  198. scipy/linalg/_decomp_ldl.py +4 -1
  199. scipy/linalg/_decomp_lu.py +18 -6
  200. scipy/linalg/_decomp_lu_cython.cpython-311-darwin.so +0 -0
  201. scipy/linalg/_decomp_polar.py +2 -0
  202. scipy/linalg/_decomp_qr.py +6 -2
  203. scipy/linalg/_decomp_qz.py +3 -0
  204. scipy/linalg/_decomp_schur.py +3 -1
  205. scipy/linalg/_decomp_svd.py +13 -2
  206. scipy/linalg/_decomp_update.cpython-311-darwin.so +0 -0
  207. scipy/linalg/_expm_frechet.py +4 -0
  208. scipy/linalg/_fblas.cpython-311-darwin.so +0 -0
  209. scipy/linalg/_flapack.cpython-311-darwin.so +0 -0
  210. scipy/linalg/_matfuncs.py +187 -4
  211. scipy/linalg/_matfuncs_expm.cpython-311-darwin.so +0 -0
  212. scipy/linalg/_matfuncs_schur_sqrtm.cpython-311-darwin.so +0 -0
  213. scipy/linalg/_matfuncs_sqrtm.py +1 -99
  214. scipy/linalg/_matfuncs_sqrtm_triu.cpython-311-darwin.so +0 -0
  215. scipy/linalg/_procrustes.py +2 -0
  216. scipy/linalg/_sketches.py +17 -6
  217. scipy/linalg/_solve_toeplitz.cpython-311-darwin.so +0 -0
  218. scipy/linalg/_solvers.py +7 -2
  219. scipy/linalg/_special_matrices.py +26 -36
  220. scipy/linalg/cython_blas.cpython-311-darwin.so +0 -0
  221. scipy/linalg/cython_lapack.cpython-311-darwin.so +0 -0
  222. scipy/linalg/lapack.py +22 -2
  223. scipy/linalg/tests/_cython_examples/meson.build +7 -0
  224. scipy/linalg/tests/test_basic.py +31 -16
  225. scipy/linalg/tests/test_batch.py +588 -0
  226. scipy/linalg/tests/test_cythonized_array_utils.py +0 -2
  227. scipy/linalg/tests/test_decomp.py +40 -3
  228. scipy/linalg/tests/test_decomp_cossin.py +14 -0
  229. scipy/linalg/tests/test_decomp_ldl.py +1 -1
  230. scipy/linalg/tests/test_interpolative.py +17 -0
  231. scipy/linalg/tests/test_lapack.py +115 -7
  232. scipy/linalg/tests/test_matfuncs.py +157 -102
  233. scipy/linalg/tests/test_procrustes.py +0 -7
  234. scipy/linalg/tests/test_solve_toeplitz.py +1 -1
  235. scipy/linalg/tests/test_special_matrices.py +1 -5
  236. scipy/ndimage/__init__.py +1 -0
  237. scipy/ndimage/_cytest.cpython-311-darwin.so +0 -0
  238. scipy/ndimage/_delegators.py +8 -2
  239. scipy/ndimage/_filters.py +433 -5
  240. scipy/ndimage/_interpolation.py +36 -6
  241. scipy/ndimage/_measurements.py +4 -2
  242. scipy/ndimage/_morphology.py +5 -0
  243. scipy/ndimage/_nd_image.cpython-311-darwin.so +0 -0
  244. scipy/ndimage/_ndimage_api.py +2 -1
  245. scipy/ndimage/_ni_docstrings.py +5 -1
  246. scipy/ndimage/_ni_label.cpython-311-darwin.so +0 -0
  247. scipy/ndimage/_ni_support.py +1 -5
  248. scipy/ndimage/_rank_filter_1d.cpython-311-darwin.so +0 -0
  249. scipy/ndimage/_support_alternative_backends.py +18 -6
  250. scipy/ndimage/tests/test_filters.py +351 -259
  251. scipy/ndimage/tests/test_fourier.py +7 -9
  252. scipy/ndimage/tests/test_interpolation.py +68 -61
  253. scipy/ndimage/tests/test_measurements.py +18 -35
  254. scipy/ndimage/tests/test_morphology.py +143 -131
  255. scipy/ndimage/tests/test_splines.py +1 -3
  256. scipy/odr/__odrpack.cpython-311-darwin.so +0 -0
  257. scipy/optimize/_basinhopping.py +13 -7
  258. scipy/optimize/_bglu_dense.cpython-311-darwin.so +0 -0
  259. scipy/optimize/_bracket.py +46 -26
  260. scipy/optimize/_chandrupatla.py +9 -10
  261. scipy/optimize/_cobyla_py.py +104 -123
  262. scipy/optimize/_constraints.py +14 -10
  263. scipy/optimize/_differentiable_functions.py +371 -230
  264. scipy/optimize/_differentialevolution.py +4 -3
  265. scipy/optimize/_dual_annealing.py +1 -1
  266. scipy/optimize/_elementwise.py +1 -4
  267. scipy/optimize/_highspy/_highs_wrapper.py +6 -4
  268. scipy/optimize/_lbfgsb.cpython-311-darwin.so +0 -0
  269. scipy/optimize/_lbfgsb_py.py +57 -16
  270. scipy/optimize/_linprog_doc.py +2 -2
  271. scipy/optimize/_linprog_highs.py +11 -11
  272. scipy/optimize/_linprog_ip.py +25 -10
  273. scipy/optimize/_linprog_util.py +18 -19
  274. scipy/optimize/_lsq/common.py +3 -3
  275. scipy/optimize/_lsq/dogbox.py +16 -2
  276. scipy/optimize/_lsq/givens_elimination.cpython-311-darwin.so +0 -0
  277. scipy/optimize/_lsq/least_squares.py +198 -126
  278. scipy/optimize/_lsq/lsq_linear.py +6 -6
  279. scipy/optimize/_lsq/trf.py +35 -8
  280. scipy/optimize/_milp.py +3 -1
  281. scipy/optimize/_minimize.py +105 -36
  282. scipy/optimize/_minpack.cpython-311-darwin.so +0 -0
  283. scipy/optimize/_minpack_py.py +21 -14
  284. scipy/optimize/_moduleTNC.cpython-311-darwin.so +0 -0
  285. scipy/optimize/_nnls.py +20 -21
  286. scipy/optimize/_nonlin.py +34 -3
  287. scipy/optimize/_numdiff.py +288 -110
  288. scipy/optimize/_optimize.py +86 -48
  289. scipy/optimize/_remove_redundancy.py +5 -5
  290. scipy/optimize/_root_scalar.py +1 -1
  291. scipy/optimize/_shgo.py +6 -0
  292. scipy/optimize/_shgo_lib/_complex.py +1 -1
  293. scipy/optimize/_slsqp_py.py +216 -124
  294. scipy/optimize/_slsqplib.cpython-311-darwin.so +0 -0
  295. scipy/optimize/_spectral.py +1 -1
  296. scipy/optimize/_tnc.py +8 -1
  297. scipy/optimize/_trlib/_trlib.cpython-311-darwin.so +0 -0
  298. scipy/optimize/_trustregion.py +20 -6
  299. scipy/optimize/_trustregion_constr/canonical_constraint.py +7 -7
  300. scipy/optimize/_trustregion_constr/equality_constrained_sqp.py +1 -1
  301. scipy/optimize/_trustregion_constr/minimize_trustregion_constr.py +11 -3
  302. scipy/optimize/_trustregion_constr/projections.py +12 -8
  303. scipy/optimize/_trustregion_constr/qp_subproblem.py +9 -9
  304. scipy/optimize/_trustregion_constr/tests/test_projections.py +7 -7
  305. scipy/optimize/_trustregion_constr/tests/test_qp_subproblem.py +77 -77
  306. scipy/optimize/_trustregion_constr/tr_interior_point.py +5 -5
  307. scipy/optimize/_trustregion_exact.py +0 -1
  308. scipy/optimize/_zeros.cpython-311-darwin.so +0 -0
  309. scipy/optimize/_zeros_py.py +97 -17
  310. scipy/optimize/cython_optimize/_zeros.cpython-311-darwin.so +0 -0
  311. scipy/optimize/slsqp.py +0 -1
  312. scipy/optimize/tests/test__basinhopping.py +1 -1
  313. scipy/optimize/tests/test__differential_evolution.py +4 -4
  314. scipy/optimize/tests/test__linprog_clean_inputs.py +5 -3
  315. scipy/optimize/tests/test__numdiff.py +66 -22
  316. scipy/optimize/tests/test__remove_redundancy.py +2 -2
  317. scipy/optimize/tests/test__shgo.py +9 -1
  318. scipy/optimize/tests/test_bracket.py +71 -46
  319. scipy/optimize/tests/test_chandrupatla.py +133 -135
  320. scipy/optimize/tests/test_cobyla.py +74 -45
  321. scipy/optimize/tests/test_constraints.py +1 -1
  322. scipy/optimize/tests/test_differentiable_functions.py +226 -6
  323. scipy/optimize/tests/test_lbfgsb_hessinv.py +22 -0
  324. scipy/optimize/tests/test_least_squares.py +125 -13
  325. scipy/optimize/tests/test_linear_assignment.py +3 -3
  326. scipy/optimize/tests/test_linprog.py +3 -3
  327. scipy/optimize/tests/test_lsq_linear.py +5 -5
  328. scipy/optimize/tests/test_minimize_constrained.py +2 -2
  329. scipy/optimize/tests/test_minpack.py +4 -4
  330. scipy/optimize/tests/test_nnls.py +43 -3
  331. scipy/optimize/tests/test_nonlin.py +36 -0
  332. scipy/optimize/tests/test_optimize.py +95 -17
  333. scipy/optimize/tests/test_slsqp.py +36 -4
  334. scipy/optimize/tests/test_zeros.py +34 -1
  335. scipy/signal/__init__.py +12 -23
  336. scipy/signal/_delegators.py +568 -0
  337. scipy/signal/_filter_design.py +459 -241
  338. scipy/signal/_fir_filter_design.py +262 -90
  339. scipy/signal/_lti_conversion.py +3 -2
  340. scipy/signal/_ltisys.py +118 -91
  341. scipy/signal/_peak_finding_utils.cpython-311-darwin.so +0 -0
  342. scipy/signal/_polyutils.py +172 -0
  343. scipy/signal/_short_time_fft.py +553 -76
  344. scipy/signal/_signal_api.py +30 -0
  345. scipy/signal/_signaltools.py +719 -396
  346. scipy/signal/_sigtools.cpython-311-darwin.so +0 -0
  347. scipy/signal/_sosfilt.cpython-311-darwin.so +0 -0
  348. scipy/signal/_spectral_py.py +221 -50
  349. scipy/signal/_spline_filters.py +108 -68
  350. scipy/signal/_support_alternative_backends.py +73 -0
  351. scipy/signal/_upfirdn.py +4 -1
  352. scipy/signal/_upfirdn_apply.cpython-311-darwin.so +0 -0
  353. scipy/signal/_waveforms.py +2 -11
  354. scipy/signal/_wavelets.py +1 -1
  355. scipy/signal/fir_filter_design.py +1 -0
  356. scipy/signal/spline.py +4 -11
  357. scipy/signal/tests/_scipy_spectral_test_shim.py +5 -182
  358. scipy/signal/tests/test_bsplines.py +114 -79
  359. scipy/signal/tests/test_cont2discrete.py +9 -2
  360. scipy/signal/tests/test_filter_design.py +721 -481
  361. scipy/signal/tests/test_fir_filter_design.py +332 -140
  362. scipy/signal/tests/test_savitzky_golay.py +4 -3
  363. scipy/signal/tests/test_short_time_fft.py +231 -5
  364. scipy/signal/tests/test_signaltools.py +2149 -1348
  365. scipy/signal/tests/test_spectral.py +19 -6
  366. scipy/signal/tests/test_splines.py +161 -96
  367. scipy/signal/tests/test_upfirdn.py +84 -50
  368. scipy/signal/tests/test_waveforms.py +20 -0
  369. scipy/signal/tests/test_windows.py +607 -466
  370. scipy/signal/windows/_windows.py +287 -148
  371. scipy/sparse/__init__.py +23 -4
  372. scipy/sparse/_base.py +269 -120
  373. scipy/sparse/_bsr.py +7 -4
  374. scipy/sparse/_compressed.py +59 -234
  375. scipy/sparse/_construct.py +90 -38
  376. scipy/sparse/_coo.py +115 -181
  377. scipy/sparse/_csc.py +4 -4
  378. scipy/sparse/_csparsetools.cpython-311-darwin.so +0 -0
  379. scipy/sparse/_csr.py +2 -2
  380. scipy/sparse/_data.py +48 -48
  381. scipy/sparse/_dia.py +105 -21
  382. scipy/sparse/_dok.py +0 -23
  383. scipy/sparse/_index.py +4 -4
  384. scipy/sparse/_matrix.py +23 -0
  385. scipy/sparse/_sparsetools.cpython-311-darwin.so +0 -0
  386. scipy/sparse/_sputils.py +37 -22
  387. scipy/sparse/base.py +0 -9
  388. scipy/sparse/bsr.py +0 -14
  389. scipy/sparse/compressed.py +0 -23
  390. scipy/sparse/construct.py +0 -6
  391. scipy/sparse/coo.py +0 -14
  392. scipy/sparse/csc.py +0 -3
  393. scipy/sparse/csgraph/_flow.cpython-311-darwin.so +0 -0
  394. scipy/sparse/csgraph/_matching.cpython-311-darwin.so +0 -0
  395. scipy/sparse/csgraph/_min_spanning_tree.cpython-311-darwin.so +0 -0
  396. scipy/sparse/csgraph/_reordering.cpython-311-darwin.so +0 -0
  397. scipy/sparse/csgraph/_shortest_path.cpython-311-darwin.so +0 -0
  398. scipy/sparse/csgraph/_tools.cpython-311-darwin.so +0 -0
  399. scipy/sparse/csgraph/_traversal.cpython-311-darwin.so +0 -0
  400. scipy/sparse/csgraph/tests/test_matching.py +14 -2
  401. scipy/sparse/csgraph/tests/test_pydata_sparse.py +4 -1
  402. scipy/sparse/csgraph/tests/test_shortest_path.py +83 -27
  403. scipy/sparse/csr.py +0 -5
  404. scipy/sparse/data.py +1 -6
  405. scipy/sparse/dia.py +0 -7
  406. scipy/sparse/dok.py +0 -10
  407. scipy/sparse/linalg/_dsolve/_superlu.cpython-311-darwin.so +0 -0
  408. scipy/sparse/linalg/_dsolve/linsolve.py +9 -0
  409. scipy/sparse/linalg/_dsolve/tests/test_linsolve.py +35 -28
  410. scipy/sparse/linalg/_eigen/arpack/_arpack.cpython-311-darwin.so +0 -0
  411. scipy/sparse/linalg/_eigen/arpack/arpack.py +28 -20
  412. scipy/sparse/linalg/_eigen/lobpcg/lobpcg.py +6 -6
  413. scipy/sparse/linalg/_expm_multiply.py +8 -3
  414. scipy/sparse/linalg/_interface.py +29 -26
  415. scipy/sparse/linalg/_isolve/_gcrotmk.py +6 -5
  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-311-darwin.so +0 -0
  424. scipy/sparse/linalg/_propack/_dpropack.cpython-311-darwin.so +0 -0
  425. scipy/sparse/linalg/_propack/_spropack.cpython-311-darwin.so +0 -0
  426. scipy/sparse/linalg/_propack/_zpropack.cpython-311-darwin.so +0 -0
  427. scipy/sparse/linalg/_special_sparse_arrays.py +39 -38
  428. scipy/sparse/linalg/tests/test_expm_multiply.py +10 -0
  429. scipy/sparse/linalg/tests/test_interface.py +35 -0
  430. scipy/sparse/linalg/tests/test_pydata_sparse.py +18 -0
  431. scipy/sparse/tests/test_arithmetic1d.py +5 -2
  432. scipy/sparse/tests/test_base.py +217 -40
  433. scipy/sparse/tests/test_common1d.py +17 -12
  434. scipy/sparse/tests/test_construct.py +1 -1
  435. scipy/sparse/tests/test_coo.py +272 -4
  436. scipy/sparse/tests/test_sparsetools.py +5 -0
  437. scipy/sparse/tests/test_sputils.py +36 -7
  438. scipy/spatial/_ckdtree.cpython-311-darwin.so +0 -0
  439. scipy/spatial/_hausdorff.cpython-311-darwin.so +0 -0
  440. scipy/spatial/_qhull.cpython-311-darwin.so +0 -0
  441. scipy/spatial/_voronoi.cpython-311-darwin.so +0 -0
  442. scipy/spatial/distance.py +49 -42
  443. scipy/spatial/tests/test_distance.py +3 -1
  444. scipy/spatial/tests/test_kdtree.py +1 -0
  445. scipy/spatial/tests/test_qhull.py +106 -2
  446. scipy/spatial/transform/__init__.py +5 -3
  447. scipy/spatial/transform/_rigid_transform.cpython-311-darwin.so +0 -0
  448. scipy/spatial/transform/_rotation.cpython-311-darwin.so +0 -0
  449. scipy/spatial/transform/tests/test_rigid_transform.py +1221 -0
  450. scipy/spatial/transform/tests/test_rotation.py +1342 -790
  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-311-darwin.so +0 -0
  457. scipy/special/_ellip_harm_2.cpython-311-darwin.so +0 -0
  458. scipy/special/_gufuncs.cpython-311-darwin.so +0 -0
  459. scipy/special/_logsumexp.py +83 -69
  460. scipy/special/_orthogonal.pyi +1 -1
  461. scipy/special/_specfun.cpython-311-darwin.so +0 -0
  462. scipy/special/_special_ufuncs.cpython-311-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-311-darwin.so +0 -0
  466. scipy/special/_testutils.py +4 -4
  467. scipy/special/_ufuncs.cpython-311-darwin.so +0 -0
  468. scipy/special/_ufuncs.pyi +1 -0
  469. scipy/special/_ufuncs.pyx +215 -1400
  470. scipy/special/_ufuncs_cxx.cpython-311-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-311-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 +23 -2
  483. scipy/special/tests/test_log1mexp.py +85 -0
  484. scipy/special/tests/test_logsumexp.py +220 -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-311-darwin.so +0 -0
  493. scipy/stats/_axis_nan_policy.py +4 -3
  494. scipy/stats/_biasedurn.cpython-311-darwin.so +0 -0
  495. scipy/stats/_continued_fraction.py +387 -0
  496. scipy/stats/_continuous_distns.py +296 -319
  497. scipy/stats/_covariance.py +6 -3
  498. scipy/stats/_discrete_distns.py +39 -32
  499. scipy/stats/_distn_infrastructure.py +39 -12
  500. scipy/stats/_distribution_infrastructure.py +900 -238
  501. scipy/stats/_entropy.py +7 -8
  502. scipy/{_lib → stats}/_finite_differences.py +1 -1
  503. scipy/stats/_hypotests.py +82 -49
  504. scipy/stats/_kde.py +53 -49
  505. scipy/stats/_ksstats.py +1 -1
  506. scipy/stats/_levy_stable/__init__.py +7 -15
  507. scipy/stats/_levy_stable/levyst.cpython-311-darwin.so +0 -0
  508. scipy/stats/_morestats.py +112 -67
  509. scipy/stats/_mstats_basic.py +13 -17
  510. scipy/stats/_mstats_extras.py +8 -8
  511. scipy/stats/_multivariate.py +89 -113
  512. scipy/stats/_new_distributions.py +97 -20
  513. scipy/stats/_page_trend_test.py +12 -5
  514. scipy/stats/_probability_distribution.py +265 -43
  515. scipy/stats/_qmc.py +14 -9
  516. scipy/stats/_qmc_cy.cpython-311-darwin.so +0 -0
  517. scipy/stats/_qmvnt.py +16 -95
  518. scipy/stats/_qmvnt_cy.cpython-311-darwin.so +0 -0
  519. scipy/stats/_quantile.py +335 -0
  520. scipy/stats/_rcont/rcont.cpython-311-darwin.so +0 -0
  521. scipy/stats/_resampling.py +4 -29
  522. scipy/stats/_sampling.py +1 -1
  523. scipy/stats/_sobol.cpython-311-darwin.so +0 -0
  524. scipy/stats/_stats.cpython-311-darwin.so +0 -0
  525. scipy/stats/_stats_mstats_common.py +19 -2
  526. scipy/stats/_stats_py.py +534 -460
  527. scipy/stats/_unuran/unuran_wrapper.cpython-311-darwin.so +0 -0
  528. scipy/stats/_unuran/unuran_wrapper.pyi +2 -1
  529. scipy/stats/_variation.py +5 -7
  530. scipy/stats/_wilcoxon.py +13 -7
  531. scipy/stats/tests/common_tests.py +6 -4
  532. scipy/stats/tests/test_axis_nan_policy.py +62 -24
  533. scipy/stats/tests/test_continued_fraction.py +173 -0
  534. scipy/stats/tests/test_continuous.py +379 -60
  535. scipy/stats/tests/test_continuous_basic.py +18 -12
  536. scipy/stats/tests/test_discrete_basic.py +14 -8
  537. scipy/stats/tests/test_discrete_distns.py +16 -16
  538. scipy/stats/tests/test_distributions.py +117 -75
  539. scipy/stats/tests/test_entropy.py +40 -48
  540. scipy/stats/tests/test_fit.py +4 -3
  541. scipy/stats/tests/test_hypotests.py +153 -24
  542. scipy/stats/tests/test_kdeoth.py +109 -41
  543. scipy/stats/tests/test_marray.py +289 -0
  544. scipy/stats/tests/test_morestats.py +79 -47
  545. scipy/stats/tests/test_mstats_basic.py +3 -3
  546. scipy/stats/tests/test_multivariate.py +434 -83
  547. scipy/stats/tests/test_qmc.py +13 -10
  548. scipy/stats/tests/test_quantile.py +199 -0
  549. scipy/stats/tests/test_rank.py +119 -112
  550. scipy/stats/tests/test_resampling.py +47 -56
  551. scipy/stats/tests/test_sampling.py +9 -4
  552. scipy/stats/tests/test_stats.py +799 -939
  553. scipy/stats/tests/test_variation.py +8 -6
  554. scipy/version.py +2 -2
  555. {scipy-1.15.2.dist-info → scipy-1.16.0rc1.dist-info}/LICENSE.txt +1 -1
  556. {scipy-1.15.2.dist-info → scipy-1.16.0rc1.dist-info}/METADATA +9 -9
  557. {scipy-1.15.2.dist-info → scipy-1.16.0rc1.dist-info}/RECORD +558 -565
  558. scipy-1.16.0rc1.dist-info/WHEEL +6 -0
  559. scipy/_lib/array_api_extra/_funcs.py +0 -484
  560. scipy/_lib/array_api_extra/_typing.py +0 -8
  561. scipy/interpolate/_bspl.cpython-311-darwin.so +0 -0
  562. scipy/optimize/_cobyla.cpython-311-darwin.so +0 -0
  563. scipy/optimize/_cython_nnls.cpython-311-darwin.so +0 -0
  564. scipy/optimize/_slsqp.cpython-311-darwin.so +0 -0
  565. scipy/spatial/qhull_src/COPYING.txt +0 -38
  566. scipy/special/libsf_error_state.dylib +0 -0
  567. scipy/special/tests/test_log_softmax.py +0 -109
  568. scipy/special/tests/test_xsf_cuda.py +0 -114
  569. scipy/special/xsf/binom.h +0 -89
  570. scipy/special/xsf/cdflib.h +0 -100
  571. scipy/special/xsf/cephes/airy.h +0 -307
  572. scipy/special/xsf/cephes/besselpoly.h +0 -51
  573. scipy/special/xsf/cephes/beta.h +0 -257
  574. scipy/special/xsf/cephes/cbrt.h +0 -131
  575. scipy/special/xsf/cephes/chbevl.h +0 -85
  576. scipy/special/xsf/cephes/chdtr.h +0 -193
  577. scipy/special/xsf/cephes/const.h +0 -87
  578. scipy/special/xsf/cephes/ellie.h +0 -293
  579. scipy/special/xsf/cephes/ellik.h +0 -251
  580. scipy/special/xsf/cephes/ellpe.h +0 -107
  581. scipy/special/xsf/cephes/ellpk.h +0 -117
  582. scipy/special/xsf/cephes/expn.h +0 -260
  583. scipy/special/xsf/cephes/gamma.h +0 -398
  584. scipy/special/xsf/cephes/hyp2f1.h +0 -596
  585. scipy/special/xsf/cephes/hyperg.h +0 -361
  586. scipy/special/xsf/cephes/i0.h +0 -149
  587. scipy/special/xsf/cephes/i1.h +0 -158
  588. scipy/special/xsf/cephes/igam.h +0 -421
  589. scipy/special/xsf/cephes/igam_asymp_coeff.h +0 -195
  590. scipy/special/xsf/cephes/igami.h +0 -313
  591. scipy/special/xsf/cephes/j0.h +0 -225
  592. scipy/special/xsf/cephes/j1.h +0 -198
  593. scipy/special/xsf/cephes/jv.h +0 -715
  594. scipy/special/xsf/cephes/k0.h +0 -164
  595. scipy/special/xsf/cephes/k1.h +0 -163
  596. scipy/special/xsf/cephes/kn.h +0 -243
  597. scipy/special/xsf/cephes/lanczos.h +0 -112
  598. scipy/special/xsf/cephes/ndtr.h +0 -275
  599. scipy/special/xsf/cephes/poch.h +0 -85
  600. scipy/special/xsf/cephes/polevl.h +0 -167
  601. scipy/special/xsf/cephes/psi.h +0 -194
  602. scipy/special/xsf/cephes/rgamma.h +0 -111
  603. scipy/special/xsf/cephes/scipy_iv.h +0 -811
  604. scipy/special/xsf/cephes/shichi.h +0 -248
  605. scipy/special/xsf/cephes/sici.h +0 -224
  606. scipy/special/xsf/cephes/sindg.h +0 -221
  607. scipy/special/xsf/cephes/tandg.h +0 -139
  608. scipy/special/xsf/cephes/trig.h +0 -58
  609. scipy/special/xsf/cephes/unity.h +0 -186
  610. scipy/special/xsf/cephes/zeta.h +0 -172
  611. scipy/special/xsf/config.h +0 -304
  612. scipy/special/xsf/digamma.h +0 -205
  613. scipy/special/xsf/error.h +0 -57
  614. scipy/special/xsf/evalpoly.h +0 -47
  615. scipy/special/xsf/expint.h +0 -266
  616. scipy/special/xsf/hyp2f1.h +0 -694
  617. scipy/special/xsf/iv_ratio.h +0 -173
  618. scipy/special/xsf/lambertw.h +0 -150
  619. scipy/special/xsf/loggamma.h +0 -163
  620. scipy/special/xsf/sici.h +0 -200
  621. scipy/special/xsf/tools.h +0 -427
  622. scipy/special/xsf/trig.h +0 -164
  623. scipy/special/xsf/wright_bessel.h +0 -843
  624. scipy/special/xsf/zlog1.h +0 -35
  625. scipy/stats/_mvn.cpython-311-darwin.so +0 -0
  626. scipy-1.15.2.dist-info/WHEEL +0 -4
@@ -2,10 +2,14 @@
2
2
  import functools
3
3
  import itertools
4
4
  import re
5
+ import contextlib
5
6
 
6
7
  import numpy as np
7
8
  import pytest
8
9
  from numpy.testing import suppress_warnings, assert_allclose, assert_array_equal
10
+ from hypothesis import strategies as st
11
+ from hypothesis import given
12
+ import hypothesis.extra.numpy as npst
9
13
  from pytest import raises as assert_raises
10
14
  from scipy import ndimage
11
15
  from scipy._lib._array_api import (
@@ -14,8 +18,8 @@ from scipy._lib._array_api import (
14
18
  xp_assert_close,
15
19
  xp_assert_equal,
16
20
  )
17
- from scipy._lib._array_api import is_cupy, is_numpy, is_torch, array_namespace
18
- from scipy.conftest import array_api_compatible
21
+ from scipy._lib._array_api import (is_cupy, is_torch, is_dask, is_jax, array_namespace,
22
+ is_array_api_strict, xp_copy)
19
23
  from scipy.ndimage._filters import _gaussian_kernel1d
20
24
 
21
25
  from . import types, float_types, complex_types
@@ -23,9 +27,18 @@ from . import types, float_types, complex_types
23
27
 
24
28
  skip_xp_backends = pytest.mark.skip_xp_backends
25
29
  xfail_xp_backends = pytest.mark.xfail_xp_backends
26
- pytestmark = [array_api_compatible, pytest.mark.usefixtures("skip_xp_backends"),
27
- pytest.mark.usefixtures("xfail_xp_backends"),
28
- skip_xp_backends(cpu_only=True, exceptions=['cupy', 'jax.numpy']),]
30
+ pytestmark = [skip_xp_backends(cpu_only=True, exceptions=['cupy', 'jax.numpy'])]
31
+
32
+ uses_output_dtype = skip_xp_backends(
33
+ np_only=True, exceptions=["cupy"],
34
+ reason="output=dtype is numpy-specific"
35
+ )
36
+
37
+
38
+ def uses_output_array(f):
39
+ return skip_xp_backends("dask.array", reason="output=array requires buffer view")(
40
+ skip_xp_backends("jax.numpy", reason="output=array requires buffer view")(f))
41
+
29
42
 
30
43
 
31
44
  def sumsq(a, b, xp=None):
@@ -41,9 +54,8 @@ def _complex_correlate(xp, array, kernel, real_dtype, convolve=False,
41
54
  """
42
55
  array = xp.asarray(array)
43
56
  kernel = xp.asarray(kernel)
44
- isdtype = array_namespace(array, kernel).isdtype
45
- complex_array = isdtype(array.dtype, 'complex floating')
46
- complex_kernel = isdtype(kernel.dtype, 'complex floating')
57
+ complex_array = xp.isdtype(array.dtype, 'complex floating')
58
+ complex_kernel = xp.isdtype(kernel.dtype, 'complex floating')
47
59
  if array.ndim == 1:
48
60
  func = ndimage.convolve1d if convolve else ndimage.correlate1d
49
61
  else:
@@ -194,7 +206,7 @@ class TestNdimageFilters:
194
206
  assert_array_almost_equal(output, expected)
195
207
 
196
208
  @xfail_xp_backends('cupy', reason="Differs by a factor of two?")
197
- @skip_xp_backends("jax.numpy", reason="output array is read-only.")
209
+ @uses_output_array
198
210
  def test_correlate01_overlap(self, xp):
199
211
  array = xp.reshape(xp.arange(256), (16, 16))
200
212
  weights = xp.asarray([2])
@@ -345,9 +357,7 @@ class TestNdimageFilters:
345
357
  output = ndimage.convolve(array, kernel)
346
358
  assert_array_almost_equal(xp.asarray([[6, 8, 9], [9, 11, 12]]), output)
347
359
 
348
- @xfail_xp_backends(np_only=True,
349
- reason="output=dtype is numpy-specific",
350
- exceptions=['cupy'],)
360
+ @uses_output_dtype
351
361
  @pytest.mark.parametrize('dtype_array', types)
352
362
  @pytest.mark.parametrize('dtype_kernel', types)
353
363
  def test_correlate13(self, dtype_array, dtype_kernel, xp):
@@ -367,9 +377,7 @@ class TestNdimageFilters:
367
377
  assert_array_almost_equal(xp.asarray([[6, 8, 9], [9, 11, 12]]), output)
368
378
  assert output.dtype.type == dtype_kernel
369
379
 
370
- @xfail_xp_backends(np_only=True,
371
- reason="output=dtype is numpy-specific",
372
- exceptions=['cupy'],)
380
+ @uses_output_array
373
381
  @pytest.mark.parametrize('dtype_array', types)
374
382
  @pytest.mark.parametrize('dtype_output', types)
375
383
  def test_correlate14(self, dtype_array, dtype_output, xp):
@@ -383,15 +391,13 @@ class TestNdimageFilters:
383
391
  output = xp.zeros(array.shape, dtype=dtype_output)
384
392
  ndimage.correlate(array, kernel, output=output)
385
393
  assert_array_almost_equal(xp.asarray([[2, 3, 5], [5, 6, 8]]), output)
386
- assert output.dtype.type == dtype_output
394
+ assert output.dtype == dtype_output
387
395
 
388
396
  ndimage.convolve(array, kernel, output=output)
389
397
  assert_array_almost_equal(xp.asarray([[6, 8, 9], [9, 11, 12]]), output)
390
- assert output.dtype.type == dtype_output
398
+ assert output.dtype == dtype_output
391
399
 
392
- @xfail_xp_backends(np_only=True,
393
- reason="output=dtype is numpy-specific",
394
- exceptions=['cupy'],)
400
+ @uses_output_dtype
395
401
  @pytest.mark.parametrize('dtype_array', types)
396
402
  def test_correlate15(self, dtype_array, xp):
397
403
  dtype_array = getattr(xp, dtype_array)
@@ -408,9 +414,7 @@ class TestNdimageFilters:
408
414
  assert_array_almost_equal(xp.asarray([[6, 8, 9], [9, 11, 12]]), output)
409
415
  assert output.dtype.type == xp.float32
410
416
 
411
- @xfail_xp_backends(np_only=True,
412
- reason="output=dtype is numpy-specific",
413
- exceptions=['cupy'],)
417
+ @uses_output_dtype
414
418
  @pytest.mark.parametrize('dtype_array', types)
415
419
  def test_correlate16(self, dtype_array, xp):
416
420
  dtype_array = getattr(xp, dtype_array)
@@ -440,9 +444,7 @@ class TestNdimageFilters:
440
444
  output = ndimage.convolve1d(array, kernel, origin=-1)
441
445
  assert_array_almost_equal(tcov, output)
442
446
 
443
- @xfail_xp_backends(np_only=True,
444
- reason="output=dtype is numpy-specific",
445
- exceptions=['cupy'],)
447
+ @uses_output_dtype
446
448
  @pytest.mark.parametrize('dtype_array', types)
447
449
  def test_correlate18(self, dtype_array, xp):
448
450
  dtype_array = getattr(xp, dtype_array)
@@ -471,9 +473,7 @@ class TestNdimageFilters:
471
473
  with assert_raises(RuntimeError):
472
474
  ndimage.convolve(array, kernel, mode=['nearest', 'reflect'])
473
475
 
474
- @xfail_xp_backends(np_only=True,
475
- reason="output=dtype is numpy-specific",
476
- exceptions=['cupy'],)
476
+ @uses_output_dtype
477
477
  @pytest.mark.parametrize('dtype_array', types)
478
478
  def test_correlate19(self, dtype_array, xp):
479
479
  dtype_array = getattr(xp, dtype_array)
@@ -494,9 +494,7 @@ class TestNdimageFilters:
494
494
  assert_array_almost_equal(xp.asarray([[3, 5, 6], [6, 8, 9]]), output)
495
495
  assert output.dtype.type == xp.float32
496
496
 
497
- @xfail_xp_backends(np_only=True,
498
- reason="output=dtype is numpy-specific",
499
- exceptions=['cupy'],)
497
+ @uses_output_array
500
498
  @pytest.mark.parametrize('dtype_array', types)
501
499
  @pytest.mark.parametrize('dtype_output', types)
502
500
  def test_correlate20(self, dtype_array, dtype_output, xp):
@@ -523,9 +521,7 @@ class TestNdimageFilters:
523
521
  output = ndimage.convolve1d(array, weights, axis=0)
524
522
  assert_array_almost_equal(output, expected)
525
523
 
526
- @xfail_xp_backends(np_only=True,
527
- reason="output=dtype is numpy-specific",
528
- exceptions=['cupy'],)
524
+ @uses_output_array
529
525
  @pytest.mark.parametrize('dtype_array', types)
530
526
  @pytest.mark.parametrize('dtype_output', types)
531
527
  def test_correlate22(self, dtype_array, dtype_output, xp):
@@ -544,7 +540,7 @@ class TestNdimageFilters:
544
540
  mode='wrap', output=output)
545
541
  assert_array_almost_equal(output, expected)
546
542
 
547
- @skip_xp_backends("jax.numpy", reason="output array is read-only.")
543
+ @uses_output_array
548
544
  @pytest.mark.parametrize('dtype_array', types)
549
545
  @pytest.mark.parametrize('dtype_output', types)
550
546
  def test_correlate23(self, dtype_array, dtype_output, xp):
@@ -563,7 +559,7 @@ class TestNdimageFilters:
563
559
  mode='nearest', output=output)
564
560
  assert_array_almost_equal(output, expected)
565
561
 
566
- @skip_xp_backends("jax.numpy", reason="output array is read-only.")
562
+ @uses_output_array
567
563
  @pytest.mark.parametrize('dtype_array', types)
568
564
  @pytest.mark.parametrize('dtype_output', types)
569
565
  def test_correlate24(self, dtype_array, dtype_output, xp):
@@ -583,7 +579,7 @@ class TestNdimageFilters:
583
579
  mode='nearest', output=output, origin=-1)
584
580
  assert_array_almost_equal(output, tcov)
585
581
 
586
- @skip_xp_backends("jax.numpy", reason="output array is read-only.")
582
+ @uses_output_array
587
583
  @pytest.mark.parametrize('dtype_array', types)
588
584
  @pytest.mark.parametrize('dtype_output', types)
589
585
  def test_correlate25(self, dtype_array, dtype_output, xp):
@@ -611,9 +607,7 @@ class TestNdimageFilters:
611
607
  y = ndimage.correlate1d(xp.ones(1), xp.ones(5), mode='mirror')
612
608
  xp_assert_equal(y, xp.asarray([5.]))
613
609
 
614
- @xfail_xp_backends(np_only=True,
615
- reason="output=dtype is numpy-specific",
616
- exceptions=['cupy'],)
610
+ @uses_output_dtype
617
611
  @pytest.mark.parametrize('dtype_kernel', complex_types)
618
612
  @pytest.mark.parametrize('dtype_input', types)
619
613
  @pytest.mark.parametrize('dtype_output', complex_types)
@@ -630,9 +624,7 @@ class TestNdimageFilters:
630
624
  self._validate_complex(xp, array, kernel, dtype_output,
631
625
  check_warnings=num_parallel_threads == 1)
632
626
 
633
- @xfail_xp_backends(np_only=True,
634
- reason="output=dtype is numpy-specific",
635
- exceptions=['cupy'],)
627
+ @uses_output_dtype
636
628
  @pytest.mark.parametrize('dtype_kernel', complex_types)
637
629
  @pytest.mark.parametrize('dtype_input', types)
638
630
  @pytest.mark.parametrize('dtype_output', complex_types)
@@ -645,7 +637,7 @@ class TestNdimageFilters:
645
637
  dtype_output = getattr(xp, dtype_output)
646
638
 
647
639
  if is_cupy(xp) and mode == 'grid-constant':
648
- pytest.xfail('https://github.com/cupy/cupy/issues/8404')
640
+ pytest.xfail('cupy/cupy#8404')
649
641
 
650
642
  # test use of non-zero cval with complex inputs
651
643
  # also verifies that mode 'grid-constant' does not segfault
@@ -677,7 +669,7 @@ class TestNdimageFilters:
677
669
  func(array, kernel, mode='constant', cval=5.0 + 1.0j,
678
670
  output=xp.complex64)
679
671
 
680
- @skip_xp_backends(np_only=True, reason='output=dtype is numpy-specific')
672
+ @uses_output_dtype
681
673
  @pytest.mark.parametrize('dtype_kernel', complex_types)
682
674
  @pytest.mark.parametrize('dtype_input', types)
683
675
  @pytest.mark.parametrize('dtype_output', complex_types)
@@ -692,7 +684,7 @@ class TestNdimageFilters:
692
684
  self._validate_complex(xp, array, kernel, dtype_output,
693
685
  check_warnings=num_parallel_threads == 1)
694
686
 
695
- @skip_xp_backends(np_only=True, reason='output=dtype is numpy-specific')
687
+ @uses_output_dtype
696
688
  @pytest.mark.parametrize('dtype_kernel', complex_types)
697
689
  @pytest.mark.parametrize('dtype_input', types)
698
690
  @pytest.mark.parametrize('dtype_output', complex_types)
@@ -709,7 +701,7 @@ class TestNdimageFilters:
709
701
  cval=5.0,
710
702
  check_warnings=num_parallel_threads == 1)
711
703
 
712
- @skip_xp_backends(np_only=True, reason='output=dtype is numpy-specific')
704
+ @uses_output_dtype
713
705
  @pytest.mark.parametrize('dtype_kernel', types)
714
706
  @pytest.mark.parametrize('dtype_input', complex_types)
715
707
  @pytest.mark.parametrize('dtype_output', complex_types)
@@ -726,7 +718,7 @@ class TestNdimageFilters:
726
718
  self._validate_complex(xp, array, kernel, dtype_output,
727
719
  check_warnings=num_parallel_threads == 1)
728
720
 
729
- @skip_xp_backends(np_only=True, reason='output=dtype is numpy-specific')
721
+ @uses_output_dtype
730
722
  @pytest.mark.parametrize('dtype_kernel', types)
731
723
  @pytest.mark.parametrize('dtype_input', complex_types)
732
724
  @pytest.mark.parametrize('dtype_output', complex_types)
@@ -741,10 +733,8 @@ class TestNdimageFilters:
741
733
  self._validate_complex(xp, array, kernel, dtype_output,
742
734
  check_warnings=num_parallel_threads == 1)
743
735
 
744
- @xfail_xp_backends('cupy', reason="cupy/cupy#8405")
745
- @skip_xp_backends(np_only=True,
746
- reason='output=dtype is numpy-specific',
747
- exceptions=['cupy'])
736
+ @uses_output_dtype
737
+ @xfail_xp_backends("cupy", reason="cupy/cupy#8405")
748
738
  @pytest.mark.parametrize('dtype_kernel', types)
749
739
  @pytest.mark.parametrize('dtype_input', complex_types)
750
740
  @pytest.mark.parametrize('dtype_output', complex_types)
@@ -761,7 +751,8 @@ class TestNdimageFilters:
761
751
  cval=5 - 3j,
762
752
  check_warnings=num_parallel_threads == 1)
763
753
 
764
- @skip_xp_backends(np_only=True, reason='output=dtype is numpy-specific')
754
+ @uses_output_dtype
755
+ @xfail_xp_backends("cupy", reason="unhashable type: 'ndarray'")
765
756
  @pytest.mark.parametrize('dtype', complex_types)
766
757
  @pytest.mark.parametrize('dtype_output', complex_types)
767
758
  def test_correlate_complex_input_and_kernel(self, dtype, dtype_output, xp,
@@ -776,10 +767,8 @@ class TestNdimageFilters:
776
767
  self._validate_complex(xp, array, kernel, dtype_output,
777
768
  check_warnings=num_parallel_threads == 1)
778
769
 
779
- @xfail_xp_backends('cupy', reason="cupy/cupy#8405")
780
- @skip_xp_backends(np_only=True,
781
- reason="output=dtype is numpy-specific",
782
- exceptions=['cupy'],)
770
+ @uses_output_dtype
771
+ @xfail_xp_backends("cupy", reason="cupy/cupy#8405")
783
772
  @pytest.mark.parametrize('dtype', complex_types)
784
773
  @pytest.mark.parametrize('dtype_output', complex_types)
785
774
  def test_correlate_complex_input_and_kernel_cval(self, dtype,
@@ -796,7 +785,8 @@ class TestNdimageFilters:
796
785
  cval=5.0 + 2.0j,
797
786
  check_warnings=num_parallel_threads == 1)
798
787
 
799
- @skip_xp_backends(np_only=True, reason="output=dtype is numpy-specific")
788
+ @uses_output_dtype
789
+ @xfail_xp_backends("cupy", reason="unhashable type: 'ndarray'")
800
790
  @pytest.mark.parametrize('dtype', complex_types)
801
791
  @pytest.mark.parametrize('dtype_output', complex_types)
802
792
  @pytest.mark.thread_unsafe
@@ -810,20 +800,17 @@ class TestNdimageFilters:
810
800
  self._validate_complex(xp, array, kernel, dtype_output,
811
801
  check_warnings=num_parallel_threads == 1)
812
802
 
803
+ @uses_output_dtype
804
+ @xfail_xp_backends("cupy", reason="cupy/cupy#8405")
813
805
  @pytest.mark.parametrize('dtype', complex_types)
814
806
  @pytest.mark.parametrize('dtype_output', complex_types)
815
807
  def test_correlate1d_complex_input_and_kernel_cval(self, dtype,
816
808
  dtype_output, xp,
817
809
  num_parallel_threads):
818
- if not (is_numpy(xp) or is_cupy(xp)):
819
- pytest.xfail("output=dtype is numpy-specific")
820
810
 
821
811
  dtype = getattr(xp, dtype)
822
812
  dtype_output = getattr(xp, dtype_output)
823
813
 
824
- if is_cupy(xp):
825
- pytest.xfail("https://github.com/cupy/cupy/issues/8405")
826
-
827
814
  kernel = xp.asarray([1, 1 + 1j], dtype=dtype)
828
815
  array = xp.asarray([1, 2j, 3, 1 + 4j, 5, 6j], dtype=dtype)
829
816
  self._validate_complex(xp, array, kernel, dtype_output, mode='constant',
@@ -843,10 +830,8 @@ class TestNdimageFilters:
843
830
  assert input.dtype == output.dtype
844
831
  assert input.shape == output.shape
845
832
 
833
+ @xfail_xp_backends("cupy", reason="cupy/cupy#8403")
846
834
  def test_gauss03(self, xp):
847
- if is_cupy(xp):
848
- pytest.xfail("https://github.com/cupy/cupy/issues/8403")
849
-
850
835
  # single precision data
851
836
  input = xp.arange(100 * 100, dtype=xp.float32)
852
837
  input = xp.reshape(input, (100, 100))
@@ -862,10 +847,8 @@ class TestNdimageFilters:
862
847
  assert_almost_equal(o_sum, i_sum, decimal=0)
863
848
  assert sumsq(input, output) > 1.0
864
849
 
850
+ @uses_output_dtype
865
851
  def test_gauss04(self, xp):
866
- if not (is_numpy(xp) or is_cupy(xp)):
867
- pytest.xfail("output=dtype is numpy-specific")
868
-
869
852
  input = xp.arange(100 * 100, dtype=xp.float32)
870
853
  input = xp.reshape(input, (100, 100))
871
854
  otype = xp.float64
@@ -874,10 +857,8 @@ class TestNdimageFilters:
874
857
  assert input.shape == output.shape
875
858
  assert sumsq(input, output) > 1.0
876
859
 
860
+ @uses_output_dtype
877
861
  def test_gauss05(self, xp):
878
- if not (is_numpy(xp) or is_cupy(xp)):
879
- pytest.xfail("output=dtype is numpy-specific")
880
-
881
862
  input = xp.arange(100 * 100, dtype=xp.float32)
882
863
  input = xp.reshape(input, (100, 100))
883
864
  otype = xp.float64
@@ -887,10 +868,8 @@ class TestNdimageFilters:
887
868
  assert input.shape == output.shape
888
869
  assert sumsq(input, output) > 1.0
889
870
 
871
+ @uses_output_dtype
890
872
  def test_gauss06(self, xp):
891
- if not (is_numpy(xp) or is_cupy(xp)):
892
- pytest.xfail("output=dtype is numpy-specific")
893
-
894
873
  input = xp.arange(100 * 100, dtype=xp.float32)
895
874
  input = xp.reshape(input, (100, 100))
896
875
  otype = xp.float64
@@ -898,7 +877,7 @@ class TestNdimageFilters:
898
877
  output2 = ndimage.gaussian_filter(input, 1.0, output=otype)
899
878
  assert_array_almost_equal(output1, output2)
900
879
 
901
- @skip_xp_backends("jax.numpy", reason="output array is read-only.")
880
+ @uses_output_array
902
881
  def test_gauss_memory_overlap(self, xp):
903
882
  input = xp.arange(100 * 100, dtype=xp.float32)
904
883
  input = xp.reshape(input, (100, 100))
@@ -906,6 +885,7 @@ class TestNdimageFilters:
906
885
  ndimage.gaussian_filter(input, 1.0, output=input)
907
886
  assert_array_almost_equal(output1, input)
908
887
 
888
+ @xfail_xp_backends("cupy", reason="https://github.com/cupy/cupy/pull/8339")
909
889
  @pytest.mark.parametrize(('filter_func', 'extra_args', 'size0', 'size'),
910
890
  [(ndimage.gaussian_filter, (), 0, 1.0),
911
891
  (ndimage.uniform_filter, (), 1, 3),
@@ -920,9 +900,6 @@ class TestNdimageFilters:
920
900
  + tuple(itertools.combinations(range(-3, 3), 2))
921
901
  + ((0, 1, 2),))
922
902
  def test_filter_axes(self, filter_func, extra_args, size0, size, axes, xp):
923
- if is_cupy(xp):
924
- pytest.xfail("https://github.com/cupy/cupy/pull/8339")
925
-
926
903
  # Note: `size` is called `sigma` in `gaussian_filter`
927
904
  array = xp.arange(6 * 8 * 12, dtype=xp.float64)
928
905
  array = xp.reshape(array, (6, 8, 12))
@@ -942,8 +919,7 @@ class TestNdimageFilters:
942
919
  xp_assert_close(output, expected)
943
920
 
944
921
  @skip_xp_backends("cupy",
945
- reason="these filters do not yet have axes support",
946
- )
922
+ reason="these filters do not yet have axes support")
947
923
  @pytest.mark.parametrize(('filter_func', 'kwargs'),
948
924
  [(ndimage.laplace, {}),
949
925
  (ndimage.gaussian_gradient_magnitude,
@@ -984,8 +960,7 @@ class TestNdimageFilters:
984
960
  xp_assert_close(output, expected)
985
961
 
986
962
  @skip_xp_backends("cupy",
987
- reason="generic_filter does not yet have axes support",
988
- )
963
+ reason="generic_filter does not yet have axes support")
989
964
  @pytest.mark.parametrize(
990
965
  'axes',
991
966
  tuple(itertools.combinations(range(-3, 3), 1))
@@ -1007,8 +982,7 @@ class TestNdimageFilters:
1007
982
  xp_assert_close(output, expected)
1008
983
 
1009
984
  @skip_xp_backends("cupy",
1010
- reason="https://github.com/cupy/cupy/pull/8339",
1011
- )
985
+ reason="https://github.com/cupy/cupy/pull/8339")
1012
986
  @pytest.mark.parametrize('func', [ndimage.correlate, ndimage.convolve])
1013
987
  @pytest.mark.parametrize(
1014
988
  'dtype', [np.float32, np.float64, np.complex64, np.complex128]
@@ -1048,9 +1022,7 @@ class TestNdimageFilters:
1048
1022
  mode=['reflect', 'nearest', 'constant'])
1049
1023
  kwargs_rank = dict(origin=(-1, 0, 1))
1050
1024
 
1051
- @skip_xp_backends("array_api_strict",
1052
- reason="fancy indexing is only available in 2024 version",
1053
- )
1025
+ @xfail_xp_backends("cupy", reason="https://github.com/cupy/cupy/pull/8339")
1054
1026
  @pytest.mark.parametrize("filter_func, size0, size, kwargs",
1055
1027
  [(ndimage.gaussian_filter, 0, 1.0, kwargs_gauss),
1056
1028
  (ndimage.uniform_filter, 1, 3, kwargs_other),
@@ -1061,10 +1033,6 @@ class TestNdimageFilters:
1061
1033
  (ndimage.percentile_filter, 1, 3, kwargs_rank)])
1062
1034
  @pytest.mark.parametrize('axes', itertools.combinations(range(-3, 3), 2))
1063
1035
  def test_filter_axes_kwargs(self, filter_func, size0, size, kwargs, axes, xp):
1064
-
1065
- if is_cupy(xp):
1066
- pytest.xfail("https://github.com/cupy/cupy/pull/8339")
1067
-
1068
1036
  array = xp.arange(6 * 8 * 12, dtype=xp.float64)
1069
1037
  array = xp.reshape(array, (6, 8, 12))
1070
1038
 
@@ -1105,6 +1073,7 @@ class TestNdimageFilters:
1105
1073
  xp_assert_close(output, expected)
1106
1074
 
1107
1075
 
1076
+ @xfail_xp_backends("cupy", reason="https://github.com/cupy/cupy/pull/8339")
1108
1077
  @pytest.mark.parametrize("filter_func, kwargs",
1109
1078
  [(ndimage.convolve, {}),
1110
1079
  (ndimage.correlate, {}),
@@ -1114,9 +1083,6 @@ class TestNdimageFilters:
1114
1083
  (ndimage.rank_filter, {"rank": 1}),
1115
1084
  (ndimage.percentile_filter, {"percentile": 30})])
1116
1085
  def test_filter_weights_subset_axes_origins(self, filter_func, kwargs, xp):
1117
- if is_cupy(xp):
1118
- pytest.xfail("https://github.com/cupy/cupy/pull/8339")
1119
-
1120
1086
  axes = (-2, -1)
1121
1087
  origins = (0, 1)
1122
1088
  array = xp.arange(6 * 8 * 12, dtype=xp.float64)
@@ -1149,6 +1115,7 @@ class TestNdimageFilters:
1149
1115
  output[:, :, origins[1]:], output0[:, :, :-origins[1]])
1150
1116
 
1151
1117
 
1118
+ @xfail_xp_backends("cupy", reason="https://github.com/cupy/cupy/pull/8339")
1152
1119
  @pytest.mark.parametrize(
1153
1120
  'filter_func, args',
1154
1121
  [(ndimage.convolve, (np.ones((3, 3, 3)),)), # args = (weights,)
@@ -1164,9 +1131,6 @@ class TestNdimageFilters:
1164
1131
  'axes', [(1.5,), (0, 1, 2, 3), (3,), (-4,)]
1165
1132
  )
1166
1133
  def test_filter_invalid_axes(self, filter_func, args, axes, xp):
1167
- if is_cupy(xp):
1168
- pytest.xfail("https://github.com/cupy/cupy/pull/8339")
1169
-
1170
1134
  array = xp.arange(6 * 8 * 12, dtype=xp.float64)
1171
1135
  array = xp.reshape(array, (6, 8, 12))
1172
1136
  args = [
@@ -1182,6 +1146,7 @@ class TestNdimageFilters:
1182
1146
  with pytest.raises(error_class, match=match):
1183
1147
  filter_func(array, *args, axes=axes)
1184
1148
 
1149
+ @xfail_xp_backends("cupy", reason="https://github.com/cupy/cupy/pull/8339")
1185
1150
  @pytest.mark.parametrize(
1186
1151
  'filter_func, kwargs',
1187
1152
  [(ndimage.convolve, {}),
@@ -1197,9 +1162,6 @@ class TestNdimageFilters:
1197
1162
  @pytest.mark.parametrize('separable_footprint', [False, True])
1198
1163
  def test_filter_invalid_footprint_ndim(self, filter_func, kwargs, axes,
1199
1164
  separable_footprint, xp):
1200
- if is_cupy(xp):
1201
- pytest.xfail("https://github.com/cupy/cupy/pull/8339")
1202
-
1203
1165
  array = xp.arange(6 * 8 * 12, dtype=xp.float64)
1204
1166
  array = xp.reshape(array, (6, 8, 12))
1205
1167
  # create a footprint with one too many dimensions
@@ -1223,14 +1185,12 @@ class TestNdimageFilters:
1223
1185
  with pytest.raises(RuntimeError, match=match):
1224
1186
  filter_func(array, axes=axes, **kwargs)
1225
1187
 
1188
+ @xfail_xp_backends("cupy", reason="https://github.com/cupy/cupy/pull/8339")
1226
1189
  @pytest.mark.parametrize('n_mismatch', [1, 3])
1227
1190
  @pytest.mark.parametrize('filter_func, kwargs, key, val',
1228
1191
  _cases_axes_tuple_length_mismatch())
1229
1192
  def test_filter_tuple_length_mismatch(self, n_mismatch, filter_func,
1230
1193
  kwargs, key, val, xp):
1231
- if is_cupy(xp):
1232
- pytest.xfail("https://github.com/cupy/cupy/pull/8339")
1233
-
1234
1194
  # Test for the intended RuntimeError when a kwargs has an invalid size
1235
1195
  array = xp.arange(6 * 8 * 12, dtype=xp.float64)
1236
1196
  array = xp.reshape(array, (6, 8, 12))
@@ -1245,9 +1205,6 @@ class TestNdimageFilters:
1245
1205
 
1246
1206
  @pytest.mark.parametrize('dtype', types + complex_types)
1247
1207
  def test_prewitt01(self, dtype, xp):
1248
- if is_torch(xp) and dtype in ("uint16", "uint32", "uint64"):
1249
- pytest.xfail("https://github.com/pytorch/pytorch/issues/58734")
1250
-
1251
1208
  dtype = getattr(xp, dtype)
1252
1209
  array = xp.asarray([[3, 2, 5, 1, 4],
1253
1210
  [5, 8, 3, 7, 1],
@@ -1257,12 +1214,9 @@ class TestNdimageFilters:
1257
1214
  output = ndimage.prewitt(array, 0)
1258
1215
  assert_array_almost_equal(t, output)
1259
1216
 
1260
- @skip_xp_backends("jax.numpy", reason="output array is read-only.")
1217
+ @uses_output_array
1261
1218
  @pytest.mark.parametrize('dtype', types + complex_types)
1262
1219
  def test_prewitt02(self, dtype, xp):
1263
- if is_torch(xp) and dtype in ("uint16", "uint32", "uint64"):
1264
- pytest.xfail("https://github.com/pytorch/pytorch/issues/58734")
1265
-
1266
1220
  dtype = getattr(xp, dtype)
1267
1221
  array = xp.asarray([[3, 2, 5, 1, 4],
1268
1222
  [5, 8, 3, 7, 1],
@@ -1275,14 +1229,9 @@ class TestNdimageFilters:
1275
1229
 
1276
1230
  @pytest.mark.parametrize('dtype', types + complex_types)
1277
1231
  def test_prewitt03(self, dtype, xp):
1278
- if is_torch(xp) and dtype in ("uint16", "uint32", "uint64"):
1279
- pytest.xfail("https://github.com/pytorch/pytorch/issues/58734")
1280
-
1281
1232
  dtype = getattr(xp, dtype)
1282
1233
  if is_cupy(xp) and dtype in [xp.uint32, xp.uint64]:
1283
1234
  pytest.xfail("uint UB? XXX")
1284
- if is_torch(xp) and dtype in ("uint16", "uint32", "uint64"):
1285
- pytest.xfail("https://github.com/pytorch/pytorch/issues/58734")
1286
1235
 
1287
1236
  array = xp.asarray([[3, 2, 5, 1, 4],
1288
1237
  [5, 8, 3, 7, 1],
@@ -1294,9 +1243,6 @@ class TestNdimageFilters:
1294
1243
 
1295
1244
  @pytest.mark.parametrize('dtype', types + complex_types)
1296
1245
  def test_prewitt04(self, dtype, xp):
1297
- if is_torch(xp) and dtype in ("uint16", "uint32", "uint64"):
1298
- pytest.xfail("https://github.com/pytorch/pytorch/issues/58734")
1299
-
1300
1246
  dtype = getattr(xp, dtype)
1301
1247
  array = xp.asarray([[3, 2, 5, 1, 4],
1302
1248
  [5, 8, 3, 7, 1],
@@ -1307,9 +1253,6 @@ class TestNdimageFilters:
1307
1253
 
1308
1254
  @pytest.mark.parametrize('dtype', types + complex_types)
1309
1255
  def test_sobel01(self, dtype, xp):
1310
- if is_torch(xp) and dtype in ("uint16", "uint32", "uint64"):
1311
- pytest.xfail("https://github.com/pytorch/pytorch/issues/58734")
1312
-
1313
1256
  dtype = getattr(xp, dtype)
1314
1257
  array = xp.asarray([[3, 2, 5, 1, 4],
1315
1258
  [5, 8, 3, 7, 1],
@@ -1319,12 +1262,9 @@ class TestNdimageFilters:
1319
1262
  output = ndimage.sobel(array, 0)
1320
1263
  assert_array_almost_equal(t, output)
1321
1264
 
1322
- @skip_xp_backends("jax.numpy", reason="output array is read-only.",)
1265
+ @uses_output_array
1323
1266
  @pytest.mark.parametrize('dtype', types + complex_types)
1324
1267
  def test_sobel02(self, dtype, xp):
1325
- if is_torch(xp) and dtype in ("uint16", "uint32", "uint64"):
1326
- pytest.xfail("https://github.com/pytorch/pytorch/issues/58734")
1327
-
1328
1268
  dtype = getattr(xp, dtype)
1329
1269
  array = xp.asarray([[3, 2, 5, 1, 4],
1330
1270
  [5, 8, 3, 7, 1],
@@ -1339,8 +1279,6 @@ class TestNdimageFilters:
1339
1279
  def test_sobel03(self, dtype, xp):
1340
1280
  if is_cupy(xp) and dtype in ["uint32", "uint64"]:
1341
1281
  pytest.xfail("uint UB? XXX")
1342
- if is_torch(xp) and dtype in ("uint16", "uint32", "uint64"):
1343
- pytest.xfail("https://github.com/pytorch/pytorch/issues/58734")
1344
1282
 
1345
1283
  dtype = getattr(xp, dtype)
1346
1284
  array = xp.asarray([[3, 2, 5, 1, 4],
@@ -1354,9 +1292,6 @@ class TestNdimageFilters:
1354
1292
 
1355
1293
  @pytest.mark.parametrize('dtype', types + complex_types)
1356
1294
  def test_sobel04(self, dtype, xp):
1357
- if is_torch(xp) and dtype in ("uint16", "uint32", "uint64"):
1358
- pytest.xfail("https://github.com/pytorch/pytorch/issues/58734")
1359
-
1360
1295
  dtype = getattr(xp, dtype)
1361
1296
  array = xp.asarray([[3, 2, 5, 1, 4],
1362
1297
  [5, 8, 3, 7, 1],
@@ -1379,7 +1314,7 @@ class TestNdimageFilters:
1379
1314
  output = ndimage.laplace(array)
1380
1315
  assert_array_almost_equal(tmp1 + tmp2, output)
1381
1316
 
1382
- @skip_xp_backends("jax.numpy", reason="output array is read-only",)
1317
+ @uses_output_array
1383
1318
  @pytest.mark.parametrize('dtype',
1384
1319
  ["int32", "float32", "float64",
1385
1320
  "complex64", "complex128"])
@@ -1409,7 +1344,7 @@ class TestNdimageFilters:
1409
1344
  output = ndimage.gaussian_laplace(array, 1.0)
1410
1345
  assert_array_almost_equal(tmp1 + tmp2, output)
1411
1346
 
1412
- @skip_xp_backends("jax.numpy", reason="output array is read-only")
1347
+ @uses_output_array
1413
1348
  @pytest.mark.parametrize('dtype',
1414
1349
  ["int32", "float32", "float64",
1415
1350
  "complex64", "complex128"])
@@ -1425,12 +1360,9 @@ class TestNdimageFilters:
1425
1360
  ndimage.gaussian_laplace(array, 1.0, output)
1426
1361
  assert_array_almost_equal(tmp1 + tmp2, output)
1427
1362
 
1428
- @skip_xp_backends("jax.numpy", reason="output array is read-only.")
1363
+ @uses_output_array
1429
1364
  @pytest.mark.parametrize('dtype', types + complex_types)
1430
1365
  def test_generic_laplace01(self, dtype, xp):
1431
- if is_torch(xp) and dtype in ("uint16", "uint32", "uint64"):
1432
- pytest.xfail("https://github.com/pytorch/pytorch/issues/58734")
1433
-
1434
1366
  def derivative2(input, axis, output, mode, cval, a, b):
1435
1367
  sigma = np.asarray([a, b / 2.0])
1436
1368
  order = [0] * input.ndim
@@ -1450,7 +1382,6 @@ class TestNdimageFilters:
1450
1382
  ndimage.gaussian_laplace(array, 1.0, output)
1451
1383
  assert_array_almost_equal(tmp, output)
1452
1384
 
1453
- @skip_xp_backends("jax.numpy", reason="output array is read-only")
1454
1385
  @pytest.mark.parametrize('dtype',
1455
1386
  ["int32", "float32", "float64",
1456
1387
  "complex64", "complex128"])
@@ -1466,12 +1397,11 @@ class TestNdimageFilters:
1466
1397
  output = ndimage.gaussian_gradient_magnitude(array, 1.0)
1467
1398
  expected = tmp1 * tmp1 + tmp2 * tmp2
1468
1399
 
1469
- astype = array_namespace(expected).astype
1470
- expected_float = astype(expected, xp.float64) if is_int_dtype else expected
1471
- expected = astype(xp.sqrt(expected_float), dtype)
1400
+ expected_float = xp.astype(expected, xp.float64) if is_int_dtype else expected
1401
+ expected = xp.astype(xp.sqrt(expected_float), dtype)
1472
1402
  xp_assert_close(output, expected, rtol=1e-6, atol=1e-6)
1473
1403
 
1474
- @skip_xp_backends("jax.numpy", reason="output array is read-only")
1404
+ @uses_output_array
1475
1405
  @pytest.mark.parametrize('dtype',
1476
1406
  ["int32", "float32", "float64",
1477
1407
  "complex64", "complex128"])
@@ -1488,10 +1418,9 @@ class TestNdimageFilters:
1488
1418
  ndimage.gaussian_gradient_magnitude(array, 1.0, output)
1489
1419
  expected = tmp1 * tmp1 + tmp2 * tmp2
1490
1420
 
1491
- astype = array_namespace(expected).astype
1492
- fl_expected = astype(expected, xp.float64) if is_int_dtype else expected
1421
+ fl_expected = xp.astype(expected, xp.float64) if is_int_dtype else expected
1493
1422
 
1494
- expected = astype(xp.sqrt(fl_expected), dtype)
1423
+ expected = xp.astype(xp.sqrt(fl_expected), dtype)
1495
1424
  xp_assert_close(output, expected, rtol=1e-6, atol=1e-6)
1496
1425
 
1497
1426
  def test_generic_gradient_magnitude01(self, xp):
@@ -1511,18 +1440,12 @@ class TestNdimageFilters:
1511
1440
  extra_keywords={'b': 2.0})
1512
1441
  assert_array_almost_equal(tmp1, tmp2)
1513
1442
 
1514
- @skip_xp_backends("cupy",
1515
- reason="https://github.com/cupy/cupy/pull/8430",
1516
- )
1517
1443
  def test_uniform01(self, xp):
1518
1444
  array = xp.asarray([2, 4, 6])
1519
1445
  size = 2
1520
1446
  output = ndimage.uniform_filter1d(array, size, origin=-1)
1521
1447
  assert_array_almost_equal(xp.asarray([3, 5, 6]), output)
1522
1448
 
1523
- @skip_xp_backends("cupy",
1524
- reason="https://github.com/cupy/cupy/pull/8430",
1525
- )
1526
1449
  def test_uniform01_complex(self, xp):
1527
1450
  array = xp.asarray([2 + 1j, 4 + 2j, 6 + 3j], dtype=xp.complex128)
1528
1451
  size = 2
@@ -1542,9 +1465,6 @@ class TestNdimageFilters:
1542
1465
  output = ndimage.uniform_filter(array, filter_shape)
1543
1466
  assert_array_almost_equal(array, output)
1544
1467
 
1545
- @skip_xp_backends("cupy",
1546
- reason="https://github.com/cupy/cupy/pull/8430",
1547
- )
1548
1468
  def test_uniform04(self, xp):
1549
1469
  array = xp.asarray([2, 4, 6])
1550
1470
  filter_shape = [2]
@@ -1557,15 +1477,10 @@ class TestNdimageFilters:
1557
1477
  output = ndimage.uniform_filter(array, filter_shape)
1558
1478
  assert_array_almost_equal(xp.asarray([]), output)
1559
1479
 
1560
- @skip_xp_backends("cupy",
1561
- reason="https://github.com/cupy/cupy/pull/8430",
1562
- )
1480
+ @uses_output_dtype
1563
1481
  @pytest.mark.parametrize('dtype_array', types)
1564
1482
  @pytest.mark.parametrize('dtype_output', types)
1565
1483
  def test_uniform06(self, dtype_array, dtype_output, xp):
1566
- if not (is_numpy(xp) or is_cupy(xp)):
1567
- pytest.xfail("output=dtype is numpy-specific")
1568
-
1569
1484
  dtype_array = getattr(xp, dtype_array)
1570
1485
  dtype_output = getattr(xp, dtype_output)
1571
1486
 
@@ -1577,15 +1492,10 @@ class TestNdimageFilters:
1577
1492
  assert_array_almost_equal(xp.asarray([[4, 6, 10], [10, 12, 16]]), output)
1578
1493
  assert output.dtype.type == dtype_output
1579
1494
 
1580
- @skip_xp_backends("cupy",
1581
- reason="https://github.com/cupy/cupy/pull/8430",
1582
- )
1495
+ @uses_output_dtype
1583
1496
  @pytest.mark.parametrize('dtype_array', complex_types)
1584
1497
  @pytest.mark.parametrize('dtype_output', complex_types)
1585
1498
  def test_uniform06_complex(self, dtype_array, dtype_output, xp):
1586
- if not (is_numpy(xp) or is_cupy(xp)):
1587
- pytest.xfail("output=dtype is numpy-specific")
1588
-
1589
1499
  dtype_array = getattr(xp, dtype_array)
1590
1500
  dtype_output = getattr(xp, dtype_output)
1591
1501
 
@@ -1631,7 +1541,7 @@ class TestNdimageFilters:
1631
1541
  [2, 2, 1, 1, 1],
1632
1542
  [5, 3, 3, 1, 1]]), output)
1633
1543
 
1634
- @skip_xp_backends("jax.numpy", reason="assignment destination is read-only")
1544
+ @uses_output_array
1635
1545
  def test_minimum_filter05_overlap(self, xp):
1636
1546
  array = xp.asarray([[3, 2, 5, 1, 4],
1637
1547
  [7, 6, 9, 3, 5],
@@ -1773,6 +1683,7 @@ class TestNdimageFilters:
1773
1683
  [7, 9, 8, 9, 7],
1774
1684
  [8, 8, 8, 7, 7]]), output)
1775
1685
 
1686
+ @xfail_xp_backends("cupy", reason="https://github.com/cupy/cupy/pull/8339")
1776
1687
  @pytest.mark.parametrize(
1777
1688
  'axes', tuple(itertools.combinations(range(-3, 3), 2))
1778
1689
  )
@@ -1785,9 +1696,6 @@ class TestNdimageFilters:
1785
1696
  (ndimage.percentile_filter, dict(percentile=60))]
1786
1697
  )
1787
1698
  def test_minmax_nonseparable_axes(self, filter_func, axes, kwargs, xp):
1788
- if is_cupy(xp):
1789
- pytest.xfail("https://github.com/cupy/cupy/pull/8339")
1790
-
1791
1699
  array = xp.arange(6 * 8 * 12, dtype=xp.float32)
1792
1700
  array = xp.reshape(array, (6, 8, 12))
1793
1701
  # use 2D triangular footprint because it is non-separable
@@ -1803,8 +1711,7 @@ class TestNdimageFilters:
1803
1711
 
1804
1712
  missing_axis = tuple(set(range(3)) - set(axes % array.ndim))[0]
1805
1713
 
1806
- expand_dims = array_namespace(footprint).expand_dims
1807
- footprint_3d = expand_dims(footprint, axis=missing_axis)
1714
+ footprint_3d = xp.expand_dims(footprint, axis=missing_axis)
1808
1715
  expected = filter_func(array, footprint=footprint_3d, **kwargs)
1809
1716
  xp_assert_close(output, expected)
1810
1717
 
@@ -1862,18 +1769,14 @@ class TestNdimageFilters:
1862
1769
  output = ndimage.percentile_filter(array, 17, size=(2, 3))
1863
1770
  xp_assert_equal(expected, output)
1864
1771
 
1865
- @skip_xp_backends("jax.numpy",
1866
- reason="assignment destination is read-only",
1867
- )
1772
+ @xfail_xp_backends("cupy", reason="cupy/cupy#8406")
1773
+ @uses_output_array
1868
1774
  def test_rank06_overlap(self, xp):
1869
- if is_cupy(xp):
1870
- pytest.xfail("https://github.com/cupy/cupy/issues/8406")
1871
1775
  array = xp.asarray([[3, 2, 5, 1, 4],
1872
1776
  [5, 8, 3, 7, 1],
1873
1777
  [5, 6, 9, 3, 5]])
1874
1778
 
1875
- asarray = array_namespace(array).asarray
1876
- array_copy = asarray(array, copy=True)
1779
+ array_copy = xp.asarray(array, copy=True)
1877
1780
  expected = [[2, 2, 1, 1, 1],
1878
1781
  [3, 3, 2, 1, 1],
1879
1782
  [5, 5, 3, 3, 1]]
@@ -1966,9 +1869,6 @@ class TestNdimageFilters:
1966
1869
 
1967
1870
  @pytest.mark.parametrize('dtype', types)
1968
1871
  def test_rank12(self, dtype, xp):
1969
- if is_torch(xp) and dtype in ("uint16", "uint32", "uint64"):
1970
- pytest.xfail("https://github.com/pytorch/pytorch/issues/58734")
1971
-
1972
1872
  dtype = getattr(xp, dtype)
1973
1873
  expected = [[3, 3, 2, 4, 4],
1974
1874
  [3, 5, 2, 5, 1],
@@ -1988,9 +1888,6 @@ class TestNdimageFilters:
1988
1888
 
1989
1889
  @pytest.mark.parametrize('dtype', types)
1990
1890
  def test_rank13(self, dtype, xp):
1991
- if is_torch(xp) and dtype in ("uint16", "uint32", "uint64"):
1992
- pytest.xfail("https://github.com/pytorch/pytorch/issues/58734")
1993
-
1994
1891
  dtype = getattr(xp, dtype)
1995
1892
  expected = [[5, 2, 5, 1, 1],
1996
1893
  [5, 8, 3, 5, 5],
@@ -2006,9 +1903,6 @@ class TestNdimageFilters:
2006
1903
 
2007
1904
  @pytest.mark.parametrize('dtype', types)
2008
1905
  def test_rank14(self, dtype, xp):
2009
- if is_torch(xp) and dtype in ("uint16", "uint32", "uint64"):
2010
- pytest.xfail("https://github.com/pytorch/pytorch/issues/58734")
2011
-
2012
1906
  dtype = getattr(xp, dtype)
2013
1907
  expected = [[3, 5, 2, 5, 1],
2014
1908
  [5, 5, 8, 3, 5],
@@ -2024,9 +1918,6 @@ class TestNdimageFilters:
2024
1918
 
2025
1919
  @pytest.mark.parametrize('dtype', types)
2026
1920
  def test_rank15(self, dtype, xp):
2027
- if is_torch(xp) and dtype in ("uint16", "uint32", "uint64"):
2028
- pytest.xfail("https://github.com/pytorch/pytorch/issues/58734")
2029
-
2030
1921
  dtype = getattr(xp, dtype)
2031
1922
  expected = [[2, 3, 1, 4, 1],
2032
1923
  [5, 3, 7, 1, 1],
@@ -2040,7 +1931,8 @@ class TestNdimageFilters:
2040
1931
  origin=[-1, 0])
2041
1932
  xp_assert_equal(expected, output)
2042
1933
 
2043
- def test_rank16(self, xp):
1934
+ # NumPy-only because test is for list input
1935
+ def test_rank16(self):
2044
1936
  # test that lists are accepted and interpreted as numpy arrays
2045
1937
  array = [3, 2, 5, 1, 4]
2046
1938
  # expected values are: median(3, 2, 5) = 3, median(2, 5, 1) = 2, etc
@@ -2077,20 +1969,20 @@ class TestNdimageFilters:
2077
1969
  y = ndimage.rank_filter(x, -2, size=3)
2078
1970
  assert y.dtype == x.dtype
2079
1971
 
2080
- @skip_xp_backends(np_only=True, reason="off-by-ones on alt backends")
1972
+ @skip_xp_backends(np_only=True, exceptions=["cupy"],
1973
+ reason="off-by-ones on alt backends")
1974
+ @xfail_xp_backends("cupy", reason="does not support extra_arguments")
2081
1975
  @pytest.mark.parametrize('dtype', types)
2082
1976
  def test_generic_filter1d01(self, dtype, xp):
2083
1977
  weights = xp.asarray([1.1, 2.2, 3.3])
2084
1978
 
2085
- if is_cupy(xp):
2086
- pytest.xfail("CuPy does not support extra_arguments")
2087
-
2088
1979
  def _filter_func(input, output, fltr, total):
2089
1980
  fltr = fltr / total
2090
1981
  for ii in range(input.shape[0] - 2):
2091
1982
  output[ii] = input[ii] * fltr[0]
2092
1983
  output[ii] += input[ii + 1] * fltr[1]
2093
1984
  output[ii] += input[ii + 2] * fltr[2]
1985
+
2094
1986
  a = np.arange(12, dtype=dtype).reshape(3, 4)
2095
1987
  a = xp.asarray(a)
2096
1988
  dtype = getattr(xp, dtype)
@@ -2102,10 +1994,9 @@ class TestNdimageFilters:
2102
1994
  extra_keywords={'total': xp.sum(weights)})
2103
1995
  assert_array_almost_equal(r1, r2)
2104
1996
 
1997
+ @xfail_xp_backends("cupy", reason="does not support extra_arguments")
2105
1998
  @pytest.mark.parametrize('dtype', types)
2106
1999
  def test_generic_filter01(self, dtype, xp):
2107
- if is_cupy(xp):
2108
- pytest.xfail("CuPy does not support extra_arguments")
2109
2000
  if is_torch(xp) and dtype in ("uint16", "uint32", "uint64"):
2110
2001
  pytest.xfail("https://github.com/pytorch/pytorch/issues/58734")
2111
2002
 
@@ -2294,10 +2185,8 @@ class TestNdimageFilters:
2294
2185
  xp_assert_equal(output, expected_value)
2295
2186
 
2296
2187
 
2188
+ @xfail_xp_backends("cupy", reason="TypeError")
2297
2189
  def test_ticket_701(xp):
2298
- if is_cupy(xp):
2299
- pytest.xfail("CuPy raises a TypeError.")
2300
-
2301
2190
  # Test generic filter sizes
2302
2191
  arr = xp.asarray(np.arange(4).reshape(2, 2))
2303
2192
  def func(x):
@@ -2337,9 +2226,8 @@ def test_gh_5430():
2337
2226
  ndimage._ni_support._normalize_sequence(x, 0)
2338
2227
 
2339
2228
 
2229
+ @skip_xp_backends("cupy", reason="tests a private scipy utility")
2340
2230
  def test_gaussian_kernel1d(xp):
2341
- if is_cupy(xp):
2342
- pytest.skip("This test tests a private scipy utility.")
2343
2231
  radius = 10
2344
2232
  sigma = 2
2345
2233
  sigma2 = sigma * sigma
@@ -2370,13 +2258,12 @@ def test_orders_gauss(xp):
2370
2258
  assert_raises(ValueError, ndimage.gaussian_filter1d, arr, 1, -1, -1)
2371
2259
 
2372
2260
 
2261
+ @xfail_xp_backends("cupy", reason="TypeError")
2373
2262
  def test_valid_origins(xp):
2374
2263
  """Regression test for #1311."""
2375
- if is_cupy(xp):
2376
- pytest.xfail("CuPy raises a TypeError.")
2377
-
2378
2264
  def func(x):
2379
2265
  return xp.mean(x)
2266
+
2380
2267
  data = xp.asarray([1, 2, 3, 4, 5], dtype=xp.float64)
2381
2268
  assert_raises(ValueError, ndimage.generic_filter, data, func, size=3,
2382
2269
  origin=2)
@@ -2415,9 +2302,7 @@ def test_bad_convolve_and_correlate_origins(xp):
2415
2302
  assert_raises(ValueError, ndimage.convolve,
2416
2303
  xp.ones((3, 5)), xp.ones((2, 2)), origin=[0, -2])
2417
2304
 
2418
- @skip_xp_backends("cupy",
2419
- reason="https://github.com/cupy/cupy/pull/8430",
2420
- )
2305
+ @skip_xp_backends("cupy", reason="https://github.com/cupy/cupy/pull/8430")
2421
2306
  def test_multiple_modes(xp):
2422
2307
  # Test that the filters with multiple mode capabilities for different
2423
2308
  # dimensions give the same result as applying a single mode.
@@ -2449,14 +2334,13 @@ def test_multiple_modes(xp):
2449
2334
 
2450
2335
 
2451
2336
  @skip_xp_backends("cupy", reason="https://github.com/cupy/cupy/pull/8430")
2452
- @skip_xp_backends("jax.numpy", reason="output array is read-only.")
2453
2337
  def test_multiple_modes_sequentially(xp):
2454
2338
  # Test that the filters with multiple mode capabilities for different
2455
2339
  # dimensions give the same result as applying the filters with
2456
2340
  # different modes sequentially
2457
2341
  arr = xp.asarray([[1., 0., 0.],
2458
- [1., 1., 0.],
2459
- [0., 0., 0.]])
2342
+ [1., 1., 0.],
2343
+ [0., 0., 0.]])
2460
2344
 
2461
2345
  modes = ['reflect', 'wrap']
2462
2346
 
@@ -2564,9 +2448,7 @@ def test_multiple_modes_gaussian_gradient_magnitude(xp):
2564
2448
 
2565
2449
  assert_almost_equal(expected, calculated)
2566
2450
 
2567
- @skip_xp_backends("cupy",
2568
- reason="https://github.com/cupy/cupy/pull/8430",
2569
- )
2451
+ @skip_xp_backends("cupy", reason="https://github.com/cupy/cupy/pull/8430")
2570
2452
  def test_multiple_modes_uniform(xp):
2571
2453
  # Test uniform filter for multiple extrapolation modes
2572
2454
  arr = xp.asarray([[1., 0., 0.],
@@ -2607,8 +2489,6 @@ def test_gaussian_truncate(xp):
2607
2489
  )
2608
2490
  assert num_nonzeros_5 == 51**2
2609
2491
 
2610
- nnz_kw = {'as_tuple': True} if is_torch(xp) else {}
2611
-
2612
2492
  # Test truncate when sigma is a sequence.
2613
2493
  f = ndimage.gaussian_filter(arr, [0.5, 2.5], truncate=3.5)
2614
2494
  fpos = f > 0
@@ -2627,22 +2507,20 @@ def test_gaussian_truncate(xp):
2627
2507
 
2628
2508
  # Test gaussian_laplace
2629
2509
  y = ndimage.gaussian_laplace(x, sigma=2, truncate=3.5)
2630
- nonzero_indices = xp.nonzero(y != 0, **nnz_kw)[0]
2510
+ nonzero_indices = xp.nonzero(y != 0)[0]
2631
2511
 
2632
2512
  n = xp.max(nonzero_indices) - xp.min(nonzero_indices) + 1
2633
2513
  assert n == 15
2634
2514
 
2635
2515
  # Test gaussian_gradient_magnitude
2636
2516
  y = ndimage.gaussian_gradient_magnitude(x, sigma=2, truncate=3.5)
2637
- nonzero_indices = xp.nonzero(y != 0, **nnz_kw)[0]
2517
+ nonzero_indices = xp.nonzero(y != 0)[0]
2638
2518
  n = xp.max(nonzero_indices) - xp.min(nonzero_indices) + 1
2639
2519
  assert n == 15
2640
2520
 
2641
2521
 
2522
+ @xfail_xp_backends("cupy", reason="cupy/cupy#8402")
2642
2523
  def test_gaussian_radius(xp):
2643
- if is_cupy(xp):
2644
- pytest.xfail("https://github.com/cupy/cupy/issues/8402")
2645
-
2646
2524
  # Test that Gaussian filters with radius argument produce the same
2647
2525
  # results as the filters with corresponding truncate argument.
2648
2526
  # radius = int(truncate * sigma + 0.5)
@@ -2671,10 +2549,8 @@ def test_gaussian_radius(xp):
2671
2549
  xp_assert_equal(f1, f2)
2672
2550
 
2673
2551
 
2552
+ @xfail_xp_backends("cupy", reason="cupy/cupy#8402")
2674
2553
  def test_gaussian_radius_invalid(xp):
2675
- if is_cupy(xp):
2676
- pytest.xfail("https://github.com/cupy/cupy/issues/8402")
2677
-
2678
2554
  # radius must be a nonnegative integer
2679
2555
  with assert_raises(ValueError):
2680
2556
  ndimage.gaussian_filter1d(xp.zeros(8), sigma=1, radius=-1)
@@ -2682,7 +2558,7 @@ def test_gaussian_radius_invalid(xp):
2682
2558
  ndimage.gaussian_filter1d(xp.zeros(8), sigma=1, radius=1.1)
2683
2559
 
2684
2560
 
2685
- @skip_xp_backends("jax.numpy", reason="output array is read-only")
2561
+ @uses_output_array
2686
2562
  class TestThreading:
2687
2563
  def check_func_thread(self, n, fun, args, out):
2688
2564
  from threading import Thread
@@ -2695,10 +2571,9 @@ class TestThreading:
2695
2571
  for i in range(n):
2696
2572
  fun(*args, output=out[i, ...])
2697
2573
 
2574
+ @xfail_xp_backends("cupy",
2575
+ reason="XXX thread exception; cannot repro outside of pytest")
2698
2576
  def test_correlate1d(self, xp):
2699
- if is_cupy(xp):
2700
- pytest.xfail("XXX thread exception; cannot repro outside of pytest")
2701
-
2702
2577
  d = np.random.randn(5000)
2703
2578
  os = np.empty((4, d.size))
2704
2579
  ot = np.empty_like(os)
@@ -2710,10 +2585,9 @@ class TestThreading:
2710
2585
  self.check_func_thread(4, ndimage.correlate1d, (d, k), ot)
2711
2586
  xp_assert_equal(os, ot)
2712
2587
 
2588
+ @xfail_xp_backends("cupy",
2589
+ reason="XXX thread exception; cannot repro outside of pytest")
2713
2590
  def test_correlate(self, xp):
2714
- if is_cupy(xp):
2715
- pytest.xfail("XXX thread exception; cannot repro outside of pytest")
2716
-
2717
2591
  d = xp.asarray(np.random.randn(500, 500))
2718
2592
  k = xp.asarray(np.random.randn(10, 10))
2719
2593
  os = xp.empty([4] + list(d.shape))
@@ -2722,10 +2596,9 @@ class TestThreading:
2722
2596
  self.check_func_thread(4, ndimage.correlate, (d, k), ot)
2723
2597
  xp_assert_equal(os, ot)
2724
2598
 
2599
+ @xfail_xp_backends("cupy",
2600
+ reason="XXX thread exception; cannot repro outside of pytest")
2725
2601
  def test_median_filter(self, xp):
2726
- if is_cupy(xp):
2727
- pytest.xfail("XXX thread exception; cannot repro outside of pytest")
2728
-
2729
2602
  d = xp.asarray(np.random.randn(500, 500))
2730
2603
  os = xp.empty([4] + list(d.shape))
2731
2604
  ot = xp.empty_like(os)
@@ -2733,10 +2606,9 @@ class TestThreading:
2733
2606
  self.check_func_thread(4, ndimage.median_filter, (d, 3), ot)
2734
2607
  xp_assert_equal(os, ot)
2735
2608
 
2609
+ @xfail_xp_backends("cupy",
2610
+ reason="XXX thread exception; cannot repro outside of pytest")
2736
2611
  def test_uniform_filter1d(self, xp):
2737
- if is_cupy(xp):
2738
- pytest.xfail("XXX thread exception; cannot repro outside of pytest")
2739
-
2740
2612
  d = np.random.randn(5000)
2741
2613
  os = np.empty((4, d.size))
2742
2614
  ot = np.empty_like(os)
@@ -2747,10 +2619,9 @@ class TestThreading:
2747
2619
  self.check_func_thread(4, ndimage.uniform_filter1d, (d, 5), ot)
2748
2620
  xp_assert_equal(os, ot)
2749
2621
 
2622
+ @xfail_xp_backends("cupy",
2623
+ reason="XXX thread exception; cannot repro outside of pytest")
2750
2624
  def test_minmax_filter(self, xp):
2751
- if is_cupy(xp):
2752
- pytest.xfail("XXX thread exception; cannot repro outside of pytest")
2753
-
2754
2625
  d = xp.asarray(np.random.randn(500, 500))
2755
2626
  os = xp.empty([4] + list(d.shape))
2756
2627
  ot = xp.empty_like(os)
@@ -2791,9 +2662,8 @@ def test_minmaximum_filter1d(xp):
2791
2662
  xp_assert_equal(xp.asarray([9, 9, 4, 5, 6, 7, 8, 9, 9, 9]), out)
2792
2663
 
2793
2664
 
2665
+ @xfail_xp_backends("cupy", reason="cupy/cupy#8401")
2794
2666
  def test_uniform_filter1d_roundoff_errors(xp):
2795
- if is_cupy(xp):
2796
- pytest.xfail("https://github.com/cupy/cupy/issues/8401")
2797
2667
  # gh-6930
2798
2668
  in_ = np.repeat([0, 1, 0], [9, 9, 9])
2799
2669
  in_ = xp.asarray(in_)
@@ -2811,14 +2681,10 @@ def test_footprint_all_zeros(xp):
2811
2681
  ndimage.maximum_filter(arr, footprint=kernel)
2812
2682
 
2813
2683
 
2814
- def test_gaussian_filter(xp):
2815
- if is_cupy(xp):
2816
- pytest.xfail("CuPy does not raise")
2817
-
2818
- if not hasattr(xp, "float16"):
2819
- pytest.xfail(f"{xp} does not have float16")
2820
-
2821
- # Test gaussian filter with xp.float16
2684
+ @xfail_xp_backends("cupy", reason="does not raise")
2685
+ @skip_xp_backends("array_api_strict", reason="no float16")
2686
+ @skip_xp_backends("dask.array", reason="no float16")
2687
+ def test_gaussian_filter_float16(xp):
2822
2688
  # gh-8207
2823
2689
  data = xp.asarray([1], dtype=xp.float16)
2824
2690
  sigma = 1.0
@@ -2826,10 +2692,8 @@ def test_gaussian_filter(xp):
2826
2692
  ndimage.gaussian_filter(data, sigma)
2827
2693
 
2828
2694
 
2695
+ @xfail_xp_backends("cupy", reason="does not raise")
2829
2696
  def test_rank_filter_noninteger_rank(xp):
2830
- if is_cupy(xp):
2831
- pytest.xfail("CuPy does not raise")
2832
-
2833
2697
  # regression test for issue 9388: ValueError for
2834
2698
  # non integer rank when performing rank_filter
2835
2699
  arr = xp.asarray(np.random.random((10, 20, 30)))
@@ -2851,12 +2715,12 @@ def test_size_footprint_both_set(xp):
2851
2715
  )
2852
2716
 
2853
2717
 
2854
- @skip_xp_backends(np_only=True, reason='byteorder is numpy-specific')
2855
- def test_byte_order_median(xp):
2718
+ # NumPy-only because 'byteorder is numpy-specific'
2719
+ def test_byte_order_median():
2856
2720
  """Regression test for #413: median_filter does not handle bytes orders."""
2857
- a = xp.arange(9, dtype='<f4').reshape(3, 3)
2721
+ a = np.arange(9, dtype='<f4').reshape(3, 3)
2858
2722
  ref = ndimage.median_filter(a, (3, 3))
2859
- b = xp.arange(9, dtype='>f4').reshape(3, 3)
2723
+ b = np.arange(9, dtype='>f4').reshape(3, 3)
2860
2724
  t = ndimage.median_filter(b, (3, 3))
2861
2725
  assert_array_almost_equal(ref, t)
2862
2726
 
@@ -2904,3 +2768,231 @@ def test_gh_22333():
2904
2768
  expected = [58, 67, 87, 108, 163, 108, 108, 108, 87]
2905
2769
  actual = ndimage.median_filter(x, size=9, mode='constant')
2906
2770
  assert_array_equal(actual, expected)
2771
+
2772
+
2773
+ @pytest.mark.filterwarnings("ignore:The given NumPy array is not writable:UserWarning")
2774
+ @pytest.mark.skip_xp_backends(cpu_only=True, exceptions=['cupy'])
2775
+ class TestVectorizedFilter:
2776
+ @pytest.mark.parametrize("axes, size",
2777
+ [(None, (3, 4, 5)), ((0, 2), (3, 4)), ((-1,), (5,))])
2778
+ @pytest.mark.parametrize("origin", [-1, 0, 1])
2779
+ @pytest.mark.parametrize("mode",
2780
+ ['reflect', 'nearest', 'mirror', 'wrap', 'constant'])
2781
+ @pytest.mark.parametrize("use_output", [False, True])
2782
+ def test_against_generic_filter(self, axes, size, origin, mode, use_output, xp):
2783
+ rng = np.random.default_rng(435982456983456987356)
2784
+
2785
+ if use_output and (is_dask(xp) or is_jax(xp)):
2786
+ pytest.skip("Requires mutable arrays.")
2787
+
2788
+ input = rng.random(size=(11, 12, 13))
2789
+ input_copy = input.copy() # check that it is not modified
2790
+ output = xp.zeros(input.shape) if use_output else None
2791
+
2792
+ kwargs = dict(axes=axes, size=size, origin=origin, mode=mode)
2793
+ ref = ndimage.generic_filter(input, np.mean, **kwargs)
2794
+ kwargs['output'] = output
2795
+ res = ndimage.vectorized_filter(xp.asarray(input.tolist()),
2796
+ xp.mean, **kwargs)
2797
+ xp_assert_close(res, xp.asarray(ref.tolist()), atol=1e-15)
2798
+ if use_output:
2799
+ xp_assert_equal(output, res)
2800
+
2801
+ if not (is_array_api_strict(xp) or is_dask(xp)):
2802
+ # currently requires support for [..., mask] indexing
2803
+ kwargs.pop('size')
2804
+ kwargs.pop('output')
2805
+ kwargs['footprint'] = rng.random(size=size or input.shape) > 0.5
2806
+ ref = ndimage.generic_filter(input, np.mean, **kwargs)
2807
+ kwargs['footprint'] = xp.asarray(kwargs['footprint'])
2808
+ kwargs['output'] = output
2809
+ res = ndimage.vectorized_filter(xp.asarray(input.tolist()),
2810
+ xp.mean, **kwargs)
2811
+ xp_assert_close(res, xp.asarray(ref.tolist()), atol=1e-15)
2812
+ if use_output:
2813
+ xp_assert_equal(output, res)
2814
+
2815
+ xp_assert_equal(xp.asarray(input), xp.asarray(input_copy))
2816
+
2817
+ @pytest.mark.parametrize("dtype",
2818
+ ["uint8", "uint16", "uint32", "uint64",
2819
+ "int8", "int16", "int32", "int64",
2820
+ "float32", "float64", "complex64", "complex128"])
2821
+ @pytest.mark.parametrize("batch_memory", [1, 16*3, np.inf])
2822
+ @pytest.mark.parametrize("use_footprint", [False, True])
2823
+ def test_dtype_batch_memory(self, dtype, batch_memory, use_footprint, xp):
2824
+ rng = np.random.default_rng(435982456983456987356)
2825
+ w = 3
2826
+
2827
+ if is_jax(xp) and not (batch_memory == 1):
2828
+ pytest.skip("Requires mutable array.")
2829
+ if is_torch(xp) and dtype in {'uint16', 'uint32', 'uint64'}:
2830
+ pytest.skip("Needs uint support.")
2831
+
2832
+ dtype = getattr(xp, dtype)
2833
+
2834
+ if use_footprint:
2835
+ if (is_dask(xp) or is_array_api_strict(xp)):
2836
+ pytest.skip("Requires [..., mask] indexing.")
2837
+ footprint = xp.asarray([True, False, True])
2838
+ kwargs = dict(footprint=footprint, batch_memory=batch_memory)
2839
+ else:
2840
+ footprint = xp.asarray([True, True, True])
2841
+ kwargs = dict(size=w, batch_memory=batch_memory)
2842
+
2843
+ # The intent here is to exercise all the code paths involved in `batch_memory`
2844
+ # and `output` handling. To test the limited-memory case, `batch_memory=16*3`
2845
+ # is chosen to be just large enough for a *single* window of `complex128` to
2846
+ # fit, and `n` is large enough that a whole sliding window view of `uint8`s
2847
+ # *won't* fit.
2848
+ n = 16*3 + 1
2849
+ input = rng.integers(0, 42, size=(n,))
2850
+ input = input + input*1j if xp.isdtype(dtype, 'complex floating') else input
2851
+ input_padded = xp.asarray(np.pad(input, [(1, 1)], mode='symmetric'),
2852
+ dtype=dtype)
2853
+ input = xp.asarray(input, dtype=dtype)
2854
+
2855
+ ref = [xp.sum(input_padded[i: i + w][footprint]) for i in range(n)]
2856
+ sum_dtype = xp.sum(input_padded).dtype
2857
+
2858
+ message = "`batch_memory` is insufficient for minimum chunk size."
2859
+ context = (pytest.raises(ValueError, match=message)
2860
+ if batch_memory == 1 else contextlib.nullcontext())
2861
+ with context:
2862
+ res = ndimage.vectorized_filter(input, xp.sum, **kwargs)
2863
+ xp_assert_close(res, xp.astype(xp.stack(ref), sum_dtype))
2864
+ assert res.dtype == sum_dtype
2865
+
2866
+ output = xp.empty_like(input)
2867
+ res = ndimage.vectorized_filter(input, xp.sum, output=output, **kwargs)
2868
+ xp_assert_close(res, xp.astype(xp.stack(ref), dtype))
2869
+ assert res.dtype == dtype
2870
+
2871
+ def test_mode_valid(self, xp):
2872
+ rng = np.random.default_rng(435982456983456987356)
2873
+ input = rng.random(size=(10, 11))
2874
+ input_xp = xp.asarray(input)
2875
+ input_xp_copy = xp_copy(input_xp) # check that it is not modified
2876
+ size = (3, 5)
2877
+
2878
+ res = ndimage.vectorized_filter(input_xp, xp.mean, size=size, mode='valid')
2879
+
2880
+ view = np.lib.stride_tricks.sliding_window_view(input, size)
2881
+ ref = np.mean(view, axis=(-2, -1))
2882
+
2883
+ xp_assert_close(res, xp.asarray(ref))
2884
+ assert res.shape == tuple(input.shape - np.asarray(size) + 1)
2885
+ xp_assert_equal(input_xp, input_xp_copy)
2886
+
2887
+ def test_input_validation(self, xp):
2888
+ input = xp.ones((10, 10))
2889
+ function = xp.mean
2890
+ size = 2
2891
+ footprint = xp.ones((2, 2))
2892
+
2893
+ message = "`function` must be a callable."
2894
+ with pytest.raises(ValueError, match=message):
2895
+ ndimage.vectorized_filter(input, "eggplant", size=size)
2896
+
2897
+ message = "Either `size` or `footprint` must be provided."
2898
+ with pytest.raises(ValueError, match=message):
2899
+ ndimage.vectorized_filter(input, function)
2900
+
2901
+ message = "Either `size` or `footprint` may be provided, not both."
2902
+ with pytest.raises(ValueError, match=message):
2903
+ ndimage.vectorized_filter(input, function, size=size, footprint=footprint)
2904
+
2905
+ message = "All elements of `size` must be positive integers."
2906
+ with pytest.raises(ValueError, match=message):
2907
+ ndimage.vectorized_filter(input, function, size=(1, -1))
2908
+ with pytest.raises(ValueError, match=message):
2909
+ ndimage.vectorized_filter(input, function, size=0)
2910
+
2911
+ message = "The dimensionality of the window"
2912
+ with pytest.raises(ValueError, match=message):
2913
+ ndimage.vectorized_filter(input, function, size=(1, 2, 3))
2914
+ with pytest.raises(ValueError, match=message):
2915
+ ndimage.vectorized_filter(input, function, footprint=xp.ones((2, 2, 2)))
2916
+
2917
+ message = "`axes` must be provided if the dimensionality..."
2918
+ with pytest.raises(ValueError, match=message):
2919
+ ndimage.vectorized_filter(input, function, size=(1,))
2920
+
2921
+ message = "All elements of `origin` must be integers"
2922
+ with pytest.raises(ValueError, match=message):
2923
+ ndimage.vectorized_filter(input, function, size=size, origin=(1, 1.5))
2924
+
2925
+ message = "`origin` must be an integer or tuple of integers with length..."
2926
+ with pytest.raises(ValueError, match=message):
2927
+ ndimage.vectorized_filter(input, function, size=size, origin=(1, 2, 3))
2928
+
2929
+ message = "`mode` must be one of..."
2930
+ with pytest.raises(ValueError, match=message):
2931
+ ndimage.vectorized_filter(input, function, size=size, mode='coconut')
2932
+
2933
+ message = "`mode='valid'` is incompatible with use of `origin`."
2934
+ with pytest.raises(ValueError, match=message):
2935
+ ndimage.vectorized_filter(input, function, size=size,
2936
+ mode='valid', origin=1)
2937
+
2938
+ message = "Use of `cval` is compatible only with `mode='constant'`."
2939
+ with pytest.raises(ValueError, match=message):
2940
+ ndimage.vectorized_filter(input, function, size=size, mode='valid', cval=1)
2941
+
2942
+ other_messages = "|Unsupported|The array_api_strict|new|Value 'a duck'"
2943
+ message = "`cval` must include only numbers." + other_messages
2944
+ with pytest.raises((ValueError, TypeError), match=message):
2945
+ ndimage.vectorized_filter(input, function, size=size,
2946
+ mode='constant', cval='a duck')
2947
+
2948
+ message = "`batch_memory` must be positive number." + other_messages
2949
+ with pytest.raises(ValueError, match=message):
2950
+ ndimage.vectorized_filter(input, function, size=size, batch_memory=0)
2951
+ with pytest.raises(ValueError, match=message):
2952
+ ndimage.vectorized_filter(input, function, size=size, batch_memory=(1, 2))
2953
+ with pytest.raises((ValueError, TypeError), match=message):
2954
+ ndimage.vectorized_filter(input, function, size=size, batch_memory="a duck")
2955
+
2956
+ @pytest.mark.parametrize('shape', [(0,), (1, 0), (0, 1, 0)])
2957
+ def test_zero_size(self, shape, xp):
2958
+ input = xp.empty(shape)
2959
+ res = ndimage.vectorized_filter(input, xp.mean, size=1)
2960
+ xp_assert_equal(res, input)
2961
+
2962
+ @pytest.mark.filterwarnings("ignore:Mean of empty slice.:RuntimeWarning")
2963
+ def test_edge_cases(self, xp):
2964
+ rng = np.random.default_rng(4835982345234982)
2965
+ function = xp.mean
2966
+
2967
+ # 0-D input
2968
+ input = xp.asarray(1.)
2969
+ res = ndimage.vectorized_filter(input, function, size=())
2970
+ xp_assert_equal(res, xp.asarray(function(input, axis=())))
2971
+
2972
+ if not (is_array_api_strict(xp) or is_dask(xp)):
2973
+ res = ndimage.vectorized_filter(input, function, footprint=True)
2974
+ xp_assert_equal(res, xp.asarray(function(input[True], axis=())))
2975
+
2976
+ res = ndimage.vectorized_filter(input, function, footprint=False)
2977
+ xp_assert_equal(res, xp.asarray(function(input[False], axis=())))
2978
+
2979
+ # 1x1 window
2980
+ input = xp.asarray(rng.random((5, 5)))
2981
+ res = ndimage.vectorized_filter(input, function, size=1)
2982
+ xp_assert_equal(res, input)
2983
+
2984
+ # window is bigger than input shouldn't be a problem
2985
+ res = ndimage.vectorized_filter(input, function, size=21)
2986
+ ref = ndimage.vectorized_filter(input, function, size=21)
2987
+ xp_assert_close(res, ref)
2988
+
2989
+
2990
+ @given(x=npst.arrays(dtype=np.float64,
2991
+ shape=st.integers(min_value=1, max_value=1000)),
2992
+ size=st.integers(min_value=1, max_value=50),
2993
+ mode=st.sampled_from(["constant", "mirror", "wrap", "reflect",
2994
+ "nearest"]),
2995
+ )
2996
+ def test_gh_22586_crash_property(x, size, mode):
2997
+ # property-based test for median_filter resilience to hard crashing
2998
+ ndimage.median_filter(x, size=size, mode=mode)