scipy 1.15.3__cp312-cp312-macosx_14_0_arm64.whl → 1.16.0rc2__cp312-cp312-macosx_14_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (628) hide show
  1. scipy/__config__.py +4 -4
  2. scipy/__init__.py +3 -6
  3. scipy/_cyutility.cpython-312-darwin.so +0 -0
  4. scipy/_lib/_array_api.py +486 -161
  5. scipy/_lib/_array_api_compat_vendor.py +9 -0
  6. scipy/_lib/_bunch.py +4 -0
  7. scipy/_lib/_ccallback_c.cpython-312-darwin.so +0 -0
  8. scipy/_lib/_docscrape.py +1 -1
  9. scipy/_lib/_elementwise_iterative_method.py +15 -26
  10. scipy/_lib/_sparse.py +41 -0
  11. scipy/_lib/_test_deprecation_call.cpython-312-darwin.so +0 -0
  12. scipy/_lib/_test_deprecation_def.cpython-312-darwin.so +0 -0
  13. scipy/_lib/_testutils.py +6 -2
  14. scipy/_lib/_util.py +222 -125
  15. scipy/_lib/array_api_compat/__init__.py +4 -4
  16. scipy/_lib/array_api_compat/_internal.py +19 -6
  17. scipy/_lib/array_api_compat/common/__init__.py +1 -1
  18. scipy/_lib/array_api_compat/common/_aliases.py +365 -193
  19. scipy/_lib/array_api_compat/common/_fft.py +94 -64
  20. scipy/_lib/array_api_compat/common/_helpers.py +413 -180
  21. scipy/_lib/array_api_compat/common/_linalg.py +116 -40
  22. scipy/_lib/array_api_compat/common/_typing.py +179 -10
  23. scipy/_lib/array_api_compat/cupy/__init__.py +1 -4
  24. scipy/_lib/array_api_compat/cupy/_aliases.py +61 -41
  25. scipy/_lib/array_api_compat/cupy/_info.py +16 -6
  26. scipy/_lib/array_api_compat/cupy/_typing.py +24 -39
  27. scipy/_lib/array_api_compat/dask/array/__init__.py +6 -3
  28. scipy/_lib/array_api_compat/dask/array/_aliases.py +267 -108
  29. scipy/_lib/array_api_compat/dask/array/_info.py +105 -34
  30. scipy/_lib/array_api_compat/dask/array/fft.py +5 -8
  31. scipy/_lib/array_api_compat/dask/array/linalg.py +21 -22
  32. scipy/_lib/array_api_compat/numpy/__init__.py +13 -15
  33. scipy/_lib/array_api_compat/numpy/_aliases.py +98 -49
  34. scipy/_lib/array_api_compat/numpy/_info.py +36 -16
  35. scipy/_lib/array_api_compat/numpy/_typing.py +27 -43
  36. scipy/_lib/array_api_compat/numpy/fft.py +11 -5
  37. scipy/_lib/array_api_compat/numpy/linalg.py +75 -22
  38. scipy/_lib/array_api_compat/torch/__init__.py +3 -5
  39. scipy/_lib/array_api_compat/torch/_aliases.py +262 -159
  40. scipy/_lib/array_api_compat/torch/_info.py +27 -16
  41. scipy/_lib/array_api_compat/torch/_typing.py +3 -0
  42. scipy/_lib/array_api_compat/torch/fft.py +17 -18
  43. scipy/_lib/array_api_compat/torch/linalg.py +16 -16
  44. scipy/_lib/array_api_extra/__init__.py +26 -3
  45. scipy/_lib/array_api_extra/_delegation.py +171 -0
  46. scipy/_lib/array_api_extra/_lib/__init__.py +1 -0
  47. scipy/_lib/array_api_extra/_lib/_at.py +463 -0
  48. scipy/_lib/array_api_extra/_lib/_backends.py +46 -0
  49. scipy/_lib/array_api_extra/_lib/_funcs.py +937 -0
  50. scipy/_lib/array_api_extra/_lib/_lazy.py +357 -0
  51. scipy/_lib/array_api_extra/_lib/_testing.py +278 -0
  52. scipy/_lib/array_api_extra/_lib/_utils/__init__.py +1 -0
  53. scipy/_lib/array_api_extra/_lib/_utils/_compat.py +74 -0
  54. scipy/_lib/array_api_extra/_lib/_utils/_compat.pyi +45 -0
  55. scipy/_lib/array_api_extra/_lib/_utils/_helpers.py +559 -0
  56. scipy/_lib/array_api_extra/_lib/_utils/_typing.py +10 -0
  57. scipy/_lib/array_api_extra/_lib/_utils/_typing.pyi +105 -0
  58. scipy/_lib/array_api_extra/testing.py +359 -0
  59. scipy/_lib/decorator.py +2 -2
  60. scipy/_lib/doccer.py +1 -7
  61. scipy/_lib/messagestream.cpython-312-darwin.so +0 -0
  62. scipy/_lib/pyprima/__init__.py +212 -0
  63. scipy/_lib/pyprima/cobyla/__init__.py +0 -0
  64. scipy/_lib/pyprima/cobyla/cobyla.py +559 -0
  65. scipy/_lib/pyprima/cobyla/cobylb.py +714 -0
  66. scipy/_lib/pyprima/cobyla/geometry.py +226 -0
  67. scipy/_lib/pyprima/cobyla/initialize.py +215 -0
  68. scipy/_lib/pyprima/cobyla/trustregion.py +492 -0
  69. scipy/_lib/pyprima/cobyla/update.py +289 -0
  70. scipy/_lib/pyprima/common/__init__.py +0 -0
  71. scipy/_lib/pyprima/common/_bounds.py +34 -0
  72. scipy/_lib/pyprima/common/_linear_constraints.py +46 -0
  73. scipy/_lib/pyprima/common/_nonlinear_constraints.py +54 -0
  74. scipy/_lib/pyprima/common/_project.py +173 -0
  75. scipy/_lib/pyprima/common/checkbreak.py +93 -0
  76. scipy/_lib/pyprima/common/consts.py +47 -0
  77. scipy/_lib/pyprima/common/evaluate.py +99 -0
  78. scipy/_lib/pyprima/common/history.py +38 -0
  79. scipy/_lib/pyprima/common/infos.py +30 -0
  80. scipy/_lib/pyprima/common/linalg.py +435 -0
  81. scipy/_lib/pyprima/common/message.py +290 -0
  82. scipy/_lib/pyprima/common/powalg.py +131 -0
  83. scipy/_lib/pyprima/common/preproc.py +277 -0
  84. scipy/_lib/pyprima/common/present.py +5 -0
  85. scipy/_lib/pyprima/common/ratio.py +54 -0
  86. scipy/_lib/pyprima/common/redrho.py +47 -0
  87. scipy/_lib/pyprima/common/selectx.py +296 -0
  88. scipy/_lib/tests/test__util.py +105 -121
  89. scipy/_lib/tests/test_array_api.py +166 -35
  90. scipy/_lib/tests/test_bunch.py +7 -0
  91. scipy/_lib/tests/test_ccallback.py +2 -10
  92. scipy/_lib/tests/test_public_api.py +13 -0
  93. scipy/cluster/_hierarchy.cpython-312-darwin.so +0 -0
  94. scipy/cluster/_optimal_leaf_ordering.cpython-312-darwin.so +0 -0
  95. scipy/cluster/_vq.cpython-312-darwin.so +0 -0
  96. scipy/cluster/hierarchy.py +393 -223
  97. scipy/cluster/tests/test_hierarchy.py +273 -335
  98. scipy/cluster/tests/test_vq.py +45 -61
  99. scipy/cluster/vq.py +39 -35
  100. scipy/conftest.py +263 -157
  101. scipy/constants/_constants.py +4 -1
  102. scipy/constants/tests/test_codata.py +2 -2
  103. scipy/constants/tests/test_constants.py +11 -18
  104. scipy/datasets/_download_all.py +15 -1
  105. scipy/datasets/_fetchers.py +7 -1
  106. scipy/datasets/_utils.py +1 -1
  107. scipy/differentiate/_differentiate.py +25 -25
  108. scipy/differentiate/tests/test_differentiate.py +24 -25
  109. scipy/fft/_basic.py +20 -0
  110. scipy/fft/_helper.py +3 -34
  111. scipy/fft/_pocketfft/helper.py +29 -1
  112. scipy/fft/_pocketfft/tests/test_basic.py +2 -4
  113. scipy/fft/_pocketfft/tests/test_real_transforms.py +4 -4
  114. scipy/fft/_realtransforms.py +13 -0
  115. scipy/fft/tests/test_basic.py +27 -25
  116. scipy/fft/tests/test_fftlog.py +16 -7
  117. scipy/fft/tests/test_helper.py +18 -34
  118. scipy/fft/tests/test_real_transforms.py +8 -10
  119. scipy/fftpack/convolve.cpython-312-darwin.so +0 -0
  120. scipy/fftpack/tests/test_basic.py +2 -4
  121. scipy/fftpack/tests/test_real_transforms.py +8 -9
  122. scipy/integrate/_bvp.py +9 -3
  123. scipy/integrate/_cubature.py +3 -2
  124. scipy/integrate/_dop.cpython-312-darwin.so +0 -0
  125. scipy/integrate/_lsoda.cpython-312-darwin.so +0 -0
  126. scipy/integrate/_ode.py +9 -2
  127. scipy/integrate/_odepack.cpython-312-darwin.so +0 -0
  128. scipy/integrate/_quad_vec.py +21 -29
  129. scipy/integrate/_quadpack.cpython-312-darwin.so +0 -0
  130. scipy/integrate/_quadpack_py.py +11 -7
  131. scipy/integrate/_quadrature.py +3 -3
  132. scipy/integrate/_rules/_base.py +2 -2
  133. scipy/integrate/_tanhsinh.py +48 -47
  134. scipy/integrate/_test_odeint_banded.cpython-312-darwin.so +0 -0
  135. scipy/integrate/_vode.cpython-312-darwin.so +0 -0
  136. scipy/integrate/tests/test__quad_vec.py +0 -6
  137. scipy/integrate/tests/test_banded_ode_solvers.py +85 -0
  138. scipy/integrate/tests/test_cubature.py +21 -35
  139. scipy/integrate/tests/test_quadrature.py +6 -8
  140. scipy/integrate/tests/test_tanhsinh.py +56 -48
  141. scipy/interpolate/__init__.py +70 -58
  142. scipy/interpolate/_bary_rational.py +22 -22
  143. scipy/interpolate/_bsplines.py +119 -66
  144. scipy/interpolate/_cubic.py +65 -50
  145. scipy/interpolate/_dfitpack.cpython-312-darwin.so +0 -0
  146. scipy/interpolate/_dierckx.cpython-312-darwin.so +0 -0
  147. scipy/interpolate/_fitpack.cpython-312-darwin.so +0 -0
  148. scipy/interpolate/_fitpack2.py +9 -6
  149. scipy/interpolate/_fitpack_impl.py +32 -26
  150. scipy/interpolate/_fitpack_repro.py +23 -19
  151. scipy/interpolate/_interpnd.cpython-312-darwin.so +0 -0
  152. scipy/interpolate/_interpolate.py +30 -12
  153. scipy/interpolate/_ndbspline.py +13 -18
  154. scipy/interpolate/_ndgriddata.py +5 -8
  155. scipy/interpolate/_polyint.py +95 -31
  156. scipy/interpolate/_ppoly.cpython-312-darwin.so +0 -0
  157. scipy/interpolate/_rbf.py +2 -2
  158. scipy/interpolate/_rbfinterp.py +1 -1
  159. scipy/interpolate/_rbfinterp_pythran.cpython-312-darwin.so +0 -0
  160. scipy/interpolate/_rgi.py +31 -26
  161. scipy/interpolate/_rgi_cython.cpython-312-darwin.so +0 -0
  162. scipy/interpolate/dfitpack.py +0 -20
  163. scipy/interpolate/interpnd.py +1 -2
  164. scipy/interpolate/tests/test_bary_rational.py +2 -2
  165. scipy/interpolate/tests/test_bsplines.py +97 -1
  166. scipy/interpolate/tests/test_fitpack2.py +39 -1
  167. scipy/interpolate/tests/test_interpnd.py +32 -20
  168. scipy/interpolate/tests/test_interpolate.py +48 -4
  169. scipy/interpolate/tests/test_rgi.py +2 -1
  170. scipy/io/_fast_matrix_market/__init__.py +2 -0
  171. scipy/io/_harwell_boeing/_fortran_format_parser.py +19 -16
  172. scipy/io/_harwell_boeing/hb.py +7 -11
  173. scipy/io/_idl.py +5 -7
  174. scipy/io/_netcdf.py +15 -5
  175. scipy/io/_test_fortran.cpython-312-darwin.so +0 -0
  176. scipy/io/arff/tests/test_arffread.py +3 -3
  177. scipy/io/matlab/__init__.py +5 -3
  178. scipy/io/matlab/_mio.py +4 -1
  179. scipy/io/matlab/_mio5.py +19 -13
  180. scipy/io/matlab/_mio5_utils.cpython-312-darwin.so +0 -0
  181. scipy/io/matlab/_mio_utils.cpython-312-darwin.so +0 -0
  182. scipy/io/matlab/_miobase.py +4 -1
  183. scipy/io/matlab/_streams.cpython-312-darwin.so +0 -0
  184. scipy/io/matlab/tests/test_mio.py +46 -18
  185. scipy/io/matlab/tests/test_mio_funcs.py +1 -1
  186. scipy/io/tests/test_mmio.py +7 -1
  187. scipy/io/tests/test_wavfile.py +41 -0
  188. scipy/io/wavfile.py +57 -10
  189. scipy/linalg/_basic.py +113 -86
  190. scipy/linalg/_cythonized_array_utils.cpython-312-darwin.so +0 -0
  191. scipy/linalg/_decomp.py +22 -9
  192. scipy/linalg/_decomp_cholesky.py +28 -13
  193. scipy/linalg/_decomp_cossin.py +45 -30
  194. scipy/linalg/_decomp_interpolative.cpython-312-darwin.so +0 -0
  195. scipy/linalg/_decomp_ldl.py +4 -1
  196. scipy/linalg/_decomp_lu.py +18 -6
  197. scipy/linalg/_decomp_lu_cython.cpython-312-darwin.so +0 -0
  198. scipy/linalg/_decomp_polar.py +2 -0
  199. scipy/linalg/_decomp_qr.py +6 -2
  200. scipy/linalg/_decomp_qz.py +3 -0
  201. scipy/linalg/_decomp_schur.py +3 -1
  202. scipy/linalg/_decomp_svd.py +13 -2
  203. scipy/linalg/_decomp_update.cpython-312-darwin.so +0 -0
  204. scipy/linalg/_expm_frechet.py +4 -0
  205. scipy/linalg/_fblas.cpython-312-darwin.so +0 -0
  206. scipy/linalg/_flapack.cpython-312-darwin.so +0 -0
  207. scipy/linalg/_linalg_pythran.cpython-312-darwin.so +0 -0
  208. scipy/linalg/_matfuncs.py +187 -4
  209. scipy/linalg/_matfuncs_expm.cpython-312-darwin.so +0 -0
  210. scipy/linalg/_matfuncs_schur_sqrtm.cpython-312-darwin.so +0 -0
  211. scipy/linalg/_matfuncs_sqrtm.py +1 -99
  212. scipy/linalg/_matfuncs_sqrtm_triu.cpython-312-darwin.so +0 -0
  213. scipy/linalg/_procrustes.py +2 -0
  214. scipy/linalg/_sketches.py +17 -6
  215. scipy/linalg/_solve_toeplitz.cpython-312-darwin.so +0 -0
  216. scipy/linalg/_solvers.py +7 -2
  217. scipy/linalg/_special_matrices.py +26 -36
  218. scipy/linalg/cython_blas.cpython-312-darwin.so +0 -0
  219. scipy/linalg/cython_lapack.cpython-312-darwin.so +0 -0
  220. scipy/linalg/lapack.py +22 -2
  221. scipy/linalg/tests/_cython_examples/meson.build +7 -0
  222. scipy/linalg/tests/test_basic.py +31 -16
  223. scipy/linalg/tests/test_batch.py +588 -0
  224. scipy/linalg/tests/test_cythonized_array_utils.py +0 -2
  225. scipy/linalg/tests/test_decomp.py +40 -3
  226. scipy/linalg/tests/test_decomp_cossin.py +14 -0
  227. scipy/linalg/tests/test_decomp_ldl.py +1 -1
  228. scipy/linalg/tests/test_lapack.py +115 -7
  229. scipy/linalg/tests/test_matfuncs.py +157 -102
  230. scipy/linalg/tests/test_procrustes.py +0 -7
  231. scipy/linalg/tests/test_solve_toeplitz.py +1 -1
  232. scipy/linalg/tests/test_special_matrices.py +1 -5
  233. scipy/ndimage/__init__.py +1 -0
  234. scipy/ndimage/_cytest.cpython-312-darwin.so +0 -0
  235. scipy/ndimage/_delegators.py +8 -2
  236. scipy/ndimage/_filters.py +453 -5
  237. scipy/ndimage/_interpolation.py +36 -6
  238. scipy/ndimage/_measurements.py +4 -2
  239. scipy/ndimage/_morphology.py +5 -0
  240. scipy/ndimage/_nd_image.cpython-312-darwin.so +0 -0
  241. scipy/ndimage/_ni_docstrings.py +5 -1
  242. scipy/ndimage/_ni_label.cpython-312-darwin.so +0 -0
  243. scipy/ndimage/_ni_support.py +1 -5
  244. scipy/ndimage/_rank_filter_1d.cpython-312-darwin.so +0 -0
  245. scipy/ndimage/_support_alternative_backends.py +18 -6
  246. scipy/ndimage/tests/test_filters.py +370 -259
  247. scipy/ndimage/tests/test_fourier.py +7 -9
  248. scipy/ndimage/tests/test_interpolation.py +68 -61
  249. scipy/ndimage/tests/test_measurements.py +18 -35
  250. scipy/ndimage/tests/test_morphology.py +143 -131
  251. scipy/ndimage/tests/test_splines.py +1 -3
  252. scipy/odr/__odrpack.cpython-312-darwin.so +0 -0
  253. scipy/optimize/_basinhopping.py +13 -7
  254. scipy/optimize/_bglu_dense.cpython-312-darwin.so +0 -0
  255. scipy/optimize/_bracket.py +17 -24
  256. scipy/optimize/_chandrupatla.py +9 -10
  257. scipy/optimize/_cobyla_py.py +104 -123
  258. scipy/optimize/_constraints.py +14 -10
  259. scipy/optimize/_differentiable_functions.py +371 -230
  260. scipy/optimize/_differentialevolution.py +4 -3
  261. scipy/optimize/_direct.cpython-312-darwin.so +0 -0
  262. scipy/optimize/_dual_annealing.py +1 -1
  263. scipy/optimize/_elementwise.py +1 -4
  264. scipy/optimize/_group_columns.cpython-312-darwin.so +0 -0
  265. scipy/optimize/_lbfgsb.cpython-312-darwin.so +0 -0
  266. scipy/optimize/_lbfgsb_py.py +57 -16
  267. scipy/optimize/_linprog_doc.py +2 -2
  268. scipy/optimize/_linprog_highs.py +2 -2
  269. scipy/optimize/_linprog_ip.py +25 -10
  270. scipy/optimize/_linprog_util.py +14 -16
  271. scipy/optimize/_lsap.cpython-312-darwin.so +0 -0
  272. scipy/optimize/_lsq/common.py +3 -3
  273. scipy/optimize/_lsq/dogbox.py +16 -2
  274. scipy/optimize/_lsq/givens_elimination.cpython-312-darwin.so +0 -0
  275. scipy/optimize/_lsq/least_squares.py +198 -126
  276. scipy/optimize/_lsq/lsq_linear.py +6 -6
  277. scipy/optimize/_lsq/trf.py +35 -8
  278. scipy/optimize/_milp.py +3 -1
  279. scipy/optimize/_minimize.py +105 -36
  280. scipy/optimize/_minpack.cpython-312-darwin.so +0 -0
  281. scipy/optimize/_minpack_py.py +21 -14
  282. scipy/optimize/_moduleTNC.cpython-312-darwin.so +0 -0
  283. scipy/optimize/_nnls.py +20 -21
  284. scipy/optimize/_nonlin.py +34 -3
  285. scipy/optimize/_numdiff.py +288 -110
  286. scipy/optimize/_optimize.py +86 -48
  287. scipy/optimize/_pava_pybind.cpython-312-darwin.so +0 -0
  288. scipy/optimize/_remove_redundancy.py +5 -5
  289. scipy/optimize/_root_scalar.py +1 -1
  290. scipy/optimize/_shgo.py +6 -0
  291. scipy/optimize/_shgo_lib/_complex.py +1 -1
  292. scipy/optimize/_slsqp_py.py +216 -124
  293. scipy/optimize/_slsqplib.cpython-312-darwin.so +0 -0
  294. scipy/optimize/_spectral.py +1 -1
  295. scipy/optimize/_tnc.py +8 -1
  296. scipy/optimize/_trlib/_trlib.cpython-312-darwin.so +0 -0
  297. scipy/optimize/_trustregion.py +20 -6
  298. scipy/optimize/_trustregion_constr/canonical_constraint.py +7 -7
  299. scipy/optimize/_trustregion_constr/equality_constrained_sqp.py +1 -1
  300. scipy/optimize/_trustregion_constr/minimize_trustregion_constr.py +11 -3
  301. scipy/optimize/_trustregion_constr/projections.py +12 -8
  302. scipy/optimize/_trustregion_constr/qp_subproblem.py +9 -9
  303. scipy/optimize/_trustregion_constr/tests/test_projections.py +7 -7
  304. scipy/optimize/_trustregion_constr/tests/test_qp_subproblem.py +77 -77
  305. scipy/optimize/_trustregion_constr/tr_interior_point.py +5 -5
  306. scipy/optimize/_trustregion_exact.py +0 -1
  307. scipy/optimize/_zeros.cpython-312-darwin.so +0 -0
  308. scipy/optimize/_zeros_py.py +97 -17
  309. scipy/optimize/cython_optimize/_zeros.cpython-312-darwin.so +0 -0
  310. scipy/optimize/slsqp.py +0 -1
  311. scipy/optimize/tests/test__basinhopping.py +1 -1
  312. scipy/optimize/tests/test__differential_evolution.py +4 -4
  313. scipy/optimize/tests/test__linprog_clean_inputs.py +5 -3
  314. scipy/optimize/tests/test__numdiff.py +66 -22
  315. scipy/optimize/tests/test__remove_redundancy.py +2 -2
  316. scipy/optimize/tests/test__shgo.py +9 -1
  317. scipy/optimize/tests/test_bracket.py +36 -46
  318. scipy/optimize/tests/test_chandrupatla.py +133 -135
  319. scipy/optimize/tests/test_cobyla.py +74 -45
  320. scipy/optimize/tests/test_constraints.py +1 -1
  321. scipy/optimize/tests/test_differentiable_functions.py +226 -6
  322. scipy/optimize/tests/test_lbfgsb_hessinv.py +22 -0
  323. scipy/optimize/tests/test_least_squares.py +125 -13
  324. scipy/optimize/tests/test_linear_assignment.py +3 -3
  325. scipy/optimize/tests/test_linprog.py +3 -3
  326. scipy/optimize/tests/test_lsq_linear.py +6 -6
  327. scipy/optimize/tests/test_minimize_constrained.py +2 -2
  328. scipy/optimize/tests/test_minpack.py +4 -4
  329. scipy/optimize/tests/test_nnls.py +43 -3
  330. scipy/optimize/tests/test_nonlin.py +36 -0
  331. scipy/optimize/tests/test_optimize.py +95 -17
  332. scipy/optimize/tests/test_slsqp.py +36 -4
  333. scipy/optimize/tests/test_zeros.py +34 -1
  334. scipy/signal/__init__.py +12 -23
  335. scipy/signal/_delegators.py +568 -0
  336. scipy/signal/_filter_design.py +459 -241
  337. scipy/signal/_fir_filter_design.py +262 -90
  338. scipy/signal/_lti_conversion.py +3 -2
  339. scipy/signal/_ltisys.py +118 -91
  340. scipy/signal/_max_len_seq_inner.cpython-312-darwin.so +0 -0
  341. scipy/signal/_peak_finding_utils.cpython-312-darwin.so +0 -0
  342. scipy/signal/_polyutils.py +172 -0
  343. scipy/signal/_short_time_fft.py +519 -70
  344. scipy/signal/_signal_api.py +30 -0
  345. scipy/signal/_signaltools.py +719 -399
  346. scipy/signal/_sigtools.cpython-312-darwin.so +0 -0
  347. scipy/signal/_sosfilt.cpython-312-darwin.so +0 -0
  348. scipy/signal/_spectral_py.py +230 -50
  349. scipy/signal/_spline.cpython-312-darwin.so +0 -0
  350. scipy/signal/_spline_filters.py +108 -68
  351. scipy/signal/_support_alternative_backends.py +73 -0
  352. scipy/signal/_upfirdn.py +4 -1
  353. scipy/signal/_upfirdn_apply.cpython-312-darwin.so +0 -0
  354. scipy/signal/_waveforms.py +2 -11
  355. scipy/signal/_wavelets.py +1 -1
  356. scipy/signal/fir_filter_design.py +1 -0
  357. scipy/signal/spline.py +4 -11
  358. scipy/signal/tests/_scipy_spectral_test_shim.py +2 -171
  359. scipy/signal/tests/test_bsplines.py +114 -79
  360. scipy/signal/tests/test_cont2discrete.py +9 -2
  361. scipy/signal/tests/test_filter_design.py +721 -481
  362. scipy/signal/tests/test_fir_filter_design.py +332 -140
  363. scipy/signal/tests/test_savitzky_golay.py +4 -3
  364. scipy/signal/tests/test_short_time_fft.py +221 -3
  365. scipy/signal/tests/test_signaltools.py +2144 -1348
  366. scipy/signal/tests/test_spectral.py +50 -6
  367. scipy/signal/tests/test_splines.py +161 -96
  368. scipy/signal/tests/test_upfirdn.py +84 -50
  369. scipy/signal/tests/test_waveforms.py +20 -0
  370. scipy/signal/tests/test_windows.py +607 -466
  371. scipy/signal/windows/_windows.py +287 -148
  372. scipy/sparse/__init__.py +23 -4
  373. scipy/sparse/_base.py +270 -108
  374. scipy/sparse/_bsr.py +7 -4
  375. scipy/sparse/_compressed.py +59 -231
  376. scipy/sparse/_construct.py +90 -38
  377. scipy/sparse/_coo.py +115 -181
  378. scipy/sparse/_csc.py +4 -4
  379. scipy/sparse/_csparsetools.cpython-312-darwin.so +0 -0
  380. scipy/sparse/_csr.py +2 -2
  381. scipy/sparse/_data.py +48 -48
  382. scipy/sparse/_dia.py +105 -18
  383. scipy/sparse/_dok.py +0 -23
  384. scipy/sparse/_index.py +4 -4
  385. scipy/sparse/_matrix.py +23 -0
  386. scipy/sparse/_sparsetools.cpython-312-darwin.so +0 -0
  387. scipy/sparse/_sputils.py +37 -22
  388. scipy/sparse/base.py +0 -9
  389. scipy/sparse/bsr.py +0 -14
  390. scipy/sparse/compressed.py +0 -23
  391. scipy/sparse/construct.py +0 -6
  392. scipy/sparse/coo.py +0 -14
  393. scipy/sparse/csc.py +0 -3
  394. scipy/sparse/csgraph/_flow.cpython-312-darwin.so +0 -0
  395. scipy/sparse/csgraph/_matching.cpython-312-darwin.so +0 -0
  396. scipy/sparse/csgraph/_min_spanning_tree.cpython-312-darwin.so +0 -0
  397. scipy/sparse/csgraph/_reordering.cpython-312-darwin.so +0 -0
  398. scipy/sparse/csgraph/_shortest_path.cpython-312-darwin.so +0 -0
  399. scipy/sparse/csgraph/_tools.cpython-312-darwin.so +0 -0
  400. scipy/sparse/csgraph/_traversal.cpython-312-darwin.so +0 -0
  401. scipy/sparse/csgraph/tests/test_matching.py +14 -2
  402. scipy/sparse/csgraph/tests/test_pydata_sparse.py +4 -1
  403. scipy/sparse/csgraph/tests/test_shortest_path.py +83 -27
  404. scipy/sparse/csr.py +0 -5
  405. scipy/sparse/data.py +1 -6
  406. scipy/sparse/dia.py +0 -7
  407. scipy/sparse/dok.py +0 -10
  408. scipy/sparse/linalg/_dsolve/_superlu.cpython-312-darwin.so +0 -0
  409. scipy/sparse/linalg/_dsolve/linsolve.py +9 -0
  410. scipy/sparse/linalg/_dsolve/tests/test_linsolve.py +35 -28
  411. scipy/sparse/linalg/_eigen/arpack/_arpack.cpython-312-darwin.so +0 -0
  412. scipy/sparse/linalg/_eigen/arpack/arpack.py +23 -17
  413. scipy/sparse/linalg/_eigen/lobpcg/lobpcg.py +6 -6
  414. scipy/sparse/linalg/_interface.py +17 -18
  415. scipy/sparse/linalg/_isolve/_gcrotmk.py +4 -4
  416. scipy/sparse/linalg/_isolve/iterative.py +51 -45
  417. scipy/sparse/linalg/_isolve/lgmres.py +6 -6
  418. scipy/sparse/linalg/_isolve/minres.py +5 -5
  419. scipy/sparse/linalg/_isolve/tfqmr.py +7 -7
  420. scipy/sparse/linalg/_isolve/utils.py +2 -8
  421. scipy/sparse/linalg/_matfuncs.py +1 -1
  422. scipy/sparse/linalg/_norm.py +1 -1
  423. scipy/sparse/linalg/_propack/_cpropack.cpython-312-darwin.so +0 -0
  424. scipy/sparse/linalg/_propack/_dpropack.cpython-312-darwin.so +0 -0
  425. scipy/sparse/linalg/_propack/_spropack.cpython-312-darwin.so +0 -0
  426. scipy/sparse/linalg/_propack/_zpropack.cpython-312-darwin.so +0 -0
  427. scipy/sparse/linalg/_special_sparse_arrays.py +39 -38
  428. scipy/sparse/linalg/tests/test_pydata_sparse.py +14 -0
  429. scipy/sparse/tests/test_arithmetic1d.py +5 -2
  430. scipy/sparse/tests/test_base.py +214 -42
  431. scipy/sparse/tests/test_common1d.py +7 -7
  432. scipy/sparse/tests/test_construct.py +1 -1
  433. scipy/sparse/tests/test_coo.py +272 -4
  434. scipy/sparse/tests/test_sparsetools.py +5 -0
  435. scipy/sparse/tests/test_sputils.py +36 -7
  436. scipy/spatial/_ckdtree.cpython-312-darwin.so +0 -0
  437. scipy/spatial/_distance_pybind.cpython-312-darwin.so +0 -0
  438. scipy/spatial/_distance_wrap.cpython-312-darwin.so +0 -0
  439. scipy/spatial/_hausdorff.cpython-312-darwin.so +0 -0
  440. scipy/spatial/_qhull.cpython-312-darwin.so +0 -0
  441. scipy/spatial/_voronoi.cpython-312-darwin.so +0 -0
  442. scipy/spatial/distance.py +49 -42
  443. scipy/spatial/tests/test_distance.py +15 -1
  444. scipy/spatial/tests/test_kdtree.py +1 -0
  445. scipy/spatial/tests/test_qhull.py +7 -2
  446. scipy/spatial/transform/__init__.py +5 -3
  447. scipy/spatial/transform/_rigid_transform.cpython-312-darwin.so +0 -0
  448. scipy/spatial/transform/_rotation.cpython-312-darwin.so +0 -0
  449. scipy/spatial/transform/tests/test_rigid_transform.py +1221 -0
  450. scipy/spatial/transform/tests/test_rotation.py +1213 -832
  451. scipy/spatial/transform/tests/test_rotation_groups.py +3 -3
  452. scipy/spatial/transform/tests/test_rotation_spline.py +29 -8
  453. scipy/special/__init__.py +1 -47
  454. scipy/special/_add_newdocs.py +34 -772
  455. scipy/special/_basic.py +22 -25
  456. scipy/special/_comb.cpython-312-darwin.so +0 -0
  457. scipy/special/_ellip_harm_2.cpython-312-darwin.so +0 -0
  458. scipy/special/_gufuncs.cpython-312-darwin.so +0 -0
  459. scipy/special/_logsumexp.py +67 -58
  460. scipy/special/_orthogonal.pyi +1 -1
  461. scipy/special/_specfun.cpython-312-darwin.so +0 -0
  462. scipy/special/_special_ufuncs.cpython-312-darwin.so +0 -0
  463. scipy/special/_spherical_bessel.py +4 -4
  464. scipy/special/_support_alternative_backends.py +212 -119
  465. scipy/special/_test_internal.cpython-312-darwin.so +0 -0
  466. scipy/special/_testutils.py +4 -4
  467. scipy/special/_ufuncs.cpython-312-darwin.so +0 -0
  468. scipy/special/_ufuncs.pyi +1 -0
  469. scipy/special/_ufuncs.pyx +215 -1400
  470. scipy/special/_ufuncs_cxx.cpython-312-darwin.so +0 -0
  471. scipy/special/_ufuncs_cxx.pxd +2 -15
  472. scipy/special/_ufuncs_cxx.pyx +5 -44
  473. scipy/special/_ufuncs_cxx_defs.h +2 -16
  474. scipy/special/_ufuncs_defs.h +0 -8
  475. scipy/special/cython_special.cpython-312-darwin.so +0 -0
  476. scipy/special/cython_special.pxd +1 -1
  477. scipy/special/tests/_cython_examples/meson.build +10 -1
  478. scipy/special/tests/test_basic.py +153 -20
  479. scipy/special/tests/test_boost_ufuncs.py +3 -0
  480. scipy/special/tests/test_cdflib.py +35 -11
  481. scipy/special/tests/test_gammainc.py +16 -0
  482. scipy/special/tests/test_hyp2f1.py +2 -2
  483. scipy/special/tests/test_log1mexp.py +85 -0
  484. scipy/special/tests/test_logsumexp.py +206 -64
  485. scipy/special/tests/test_mpmath.py +1 -0
  486. scipy/special/tests/test_nan_inputs.py +1 -1
  487. scipy/special/tests/test_orthogonal.py +17 -18
  488. scipy/special/tests/test_sf_error.py +3 -2
  489. scipy/special/tests/test_sph_harm.py +6 -7
  490. scipy/special/tests/test_support_alternative_backends.py +211 -76
  491. scipy/stats/__init__.py +4 -1
  492. scipy/stats/_ansari_swilk_statistics.cpython-312-darwin.so +0 -0
  493. scipy/stats/_axis_nan_policy.py +5 -12
  494. scipy/stats/_biasedurn.cpython-312-darwin.so +0 -0
  495. scipy/stats/_continued_fraction.py +387 -0
  496. scipy/stats/_continuous_distns.py +277 -310
  497. scipy/stats/_correlation.py +1 -1
  498. scipy/stats/_covariance.py +6 -3
  499. scipy/stats/_discrete_distns.py +39 -32
  500. scipy/stats/_distn_infrastructure.py +39 -12
  501. scipy/stats/_distribution_infrastructure.py +900 -238
  502. scipy/stats/_entropy.py +9 -10
  503. scipy/{_lib → stats}/_finite_differences.py +1 -1
  504. scipy/stats/_hypotests.py +83 -50
  505. scipy/stats/_kde.py +53 -49
  506. scipy/stats/_ksstats.py +1 -1
  507. scipy/stats/_levy_stable/__init__.py +7 -15
  508. scipy/stats/_levy_stable/levyst.cpython-312-darwin.so +0 -0
  509. scipy/stats/_morestats.py +118 -73
  510. scipy/stats/_mstats_basic.py +13 -17
  511. scipy/stats/_mstats_extras.py +8 -8
  512. scipy/stats/_multivariate.py +89 -113
  513. scipy/stats/_new_distributions.py +97 -20
  514. scipy/stats/_page_trend_test.py +12 -5
  515. scipy/stats/_probability_distribution.py +265 -43
  516. scipy/stats/_qmc.py +14 -9
  517. scipy/stats/_qmc_cy.cpython-312-darwin.so +0 -0
  518. scipy/stats/_qmvnt.py +16 -95
  519. scipy/stats/_qmvnt_cy.cpython-312-darwin.so +0 -0
  520. scipy/stats/_quantile.py +335 -0
  521. scipy/stats/_rcont/rcont.cpython-312-darwin.so +0 -0
  522. scipy/stats/_resampling.py +4 -29
  523. scipy/stats/_sampling.py +1 -1
  524. scipy/stats/_sobol.cpython-312-darwin.so +0 -0
  525. scipy/stats/_stats.cpython-312-darwin.so +0 -0
  526. scipy/stats/_stats_mstats_common.py +21 -2
  527. scipy/stats/_stats_py.py +550 -476
  528. scipy/stats/_stats_pythran.cpython-312-darwin.so +0 -0
  529. scipy/stats/_unuran/unuran_wrapper.cpython-312-darwin.so +0 -0
  530. scipy/stats/_unuran/unuran_wrapper.pyi +2 -1
  531. scipy/stats/_variation.py +6 -8
  532. scipy/stats/_wilcoxon.py +13 -7
  533. scipy/stats/tests/common_tests.py +6 -4
  534. scipy/stats/tests/test_axis_nan_policy.py +62 -24
  535. scipy/stats/tests/test_continued_fraction.py +173 -0
  536. scipy/stats/tests/test_continuous.py +379 -60
  537. scipy/stats/tests/test_continuous_basic.py +18 -12
  538. scipy/stats/tests/test_discrete_basic.py +14 -8
  539. scipy/stats/tests/test_discrete_distns.py +16 -16
  540. scipy/stats/tests/test_distributions.py +95 -75
  541. scipy/stats/tests/test_entropy.py +40 -48
  542. scipy/stats/tests/test_fit.py +4 -3
  543. scipy/stats/tests/test_hypotests.py +153 -24
  544. scipy/stats/tests/test_kdeoth.py +109 -41
  545. scipy/stats/tests/test_marray.py +289 -0
  546. scipy/stats/tests/test_morestats.py +79 -47
  547. scipy/stats/tests/test_mstats_basic.py +3 -3
  548. scipy/stats/tests/test_multivariate.py +434 -83
  549. scipy/stats/tests/test_qmc.py +13 -10
  550. scipy/stats/tests/test_quantile.py +199 -0
  551. scipy/stats/tests/test_rank.py +119 -112
  552. scipy/stats/tests/test_resampling.py +47 -56
  553. scipy/stats/tests/test_sampling.py +9 -4
  554. scipy/stats/tests/test_stats.py +799 -939
  555. scipy/stats/tests/test_variation.py +8 -6
  556. scipy/version.py +2 -2
  557. {scipy-1.15.3.dist-info → scipy-1.16.0rc2.dist-info}/LICENSE.txt +4 -4
  558. {scipy-1.15.3.dist-info → scipy-1.16.0rc2.dist-info}/METADATA +11 -11
  559. {scipy-1.15.3.dist-info → scipy-1.16.0rc2.dist-info}/RECORD +560 -567
  560. scipy-1.16.0rc2.dist-info/WHEEL +6 -0
  561. scipy/_lib/array_api_extra/_funcs.py +0 -484
  562. scipy/_lib/array_api_extra/_typing.py +0 -8
  563. scipy/interpolate/_bspl.cpython-312-darwin.so +0 -0
  564. scipy/optimize/_cobyla.cpython-312-darwin.so +0 -0
  565. scipy/optimize/_cython_nnls.cpython-312-darwin.so +0 -0
  566. scipy/optimize/_slsqp.cpython-312-darwin.so +0 -0
  567. scipy/spatial/qhull_src/COPYING.txt +0 -38
  568. scipy/special/libsf_error_state.dylib +0 -0
  569. scipy/special/tests/test_log_softmax.py +0 -109
  570. scipy/special/tests/test_xsf_cuda.py +0 -114
  571. scipy/special/xsf/binom.h +0 -89
  572. scipy/special/xsf/cdflib.h +0 -100
  573. scipy/special/xsf/cephes/airy.h +0 -307
  574. scipy/special/xsf/cephes/besselpoly.h +0 -51
  575. scipy/special/xsf/cephes/beta.h +0 -257
  576. scipy/special/xsf/cephes/cbrt.h +0 -131
  577. scipy/special/xsf/cephes/chbevl.h +0 -85
  578. scipy/special/xsf/cephes/chdtr.h +0 -193
  579. scipy/special/xsf/cephes/const.h +0 -87
  580. scipy/special/xsf/cephes/ellie.h +0 -293
  581. scipy/special/xsf/cephes/ellik.h +0 -251
  582. scipy/special/xsf/cephes/ellpe.h +0 -107
  583. scipy/special/xsf/cephes/ellpk.h +0 -117
  584. scipy/special/xsf/cephes/expn.h +0 -260
  585. scipy/special/xsf/cephes/gamma.h +0 -398
  586. scipy/special/xsf/cephes/hyp2f1.h +0 -596
  587. scipy/special/xsf/cephes/hyperg.h +0 -361
  588. scipy/special/xsf/cephes/i0.h +0 -149
  589. scipy/special/xsf/cephes/i1.h +0 -158
  590. scipy/special/xsf/cephes/igam.h +0 -421
  591. scipy/special/xsf/cephes/igam_asymp_coeff.h +0 -195
  592. scipy/special/xsf/cephes/igami.h +0 -313
  593. scipy/special/xsf/cephes/j0.h +0 -225
  594. scipy/special/xsf/cephes/j1.h +0 -198
  595. scipy/special/xsf/cephes/jv.h +0 -715
  596. scipy/special/xsf/cephes/k0.h +0 -164
  597. scipy/special/xsf/cephes/k1.h +0 -163
  598. scipy/special/xsf/cephes/kn.h +0 -243
  599. scipy/special/xsf/cephes/lanczos.h +0 -112
  600. scipy/special/xsf/cephes/ndtr.h +0 -275
  601. scipy/special/xsf/cephes/poch.h +0 -85
  602. scipy/special/xsf/cephes/polevl.h +0 -167
  603. scipy/special/xsf/cephes/psi.h +0 -194
  604. scipy/special/xsf/cephes/rgamma.h +0 -111
  605. scipy/special/xsf/cephes/scipy_iv.h +0 -811
  606. scipy/special/xsf/cephes/shichi.h +0 -248
  607. scipy/special/xsf/cephes/sici.h +0 -224
  608. scipy/special/xsf/cephes/sindg.h +0 -221
  609. scipy/special/xsf/cephes/tandg.h +0 -139
  610. scipy/special/xsf/cephes/trig.h +0 -58
  611. scipy/special/xsf/cephes/unity.h +0 -186
  612. scipy/special/xsf/cephes/zeta.h +0 -172
  613. scipy/special/xsf/config.h +0 -304
  614. scipy/special/xsf/digamma.h +0 -205
  615. scipy/special/xsf/error.h +0 -57
  616. scipy/special/xsf/evalpoly.h +0 -47
  617. scipy/special/xsf/expint.h +0 -266
  618. scipy/special/xsf/hyp2f1.h +0 -694
  619. scipy/special/xsf/iv_ratio.h +0 -173
  620. scipy/special/xsf/lambertw.h +0 -150
  621. scipy/special/xsf/loggamma.h +0 -163
  622. scipy/special/xsf/sici.h +0 -200
  623. scipy/special/xsf/tools.h +0 -427
  624. scipy/special/xsf/trig.h +0 -164
  625. scipy/special/xsf/wright_bessel.h +0 -843
  626. scipy/special/xsf/zlog1.h +0 -35
  627. scipy/stats/_mvn.cpython-312-darwin.so +0 -0
  628. scipy-1.15.3.dist-info/WHEEL +0 -4
@@ -1,18 +1,23 @@
1
+ import math
1
2
  import numpy as np
3
+
2
4
  from numpy.testing import assert_warns
3
- from scipy._lib._array_api import (
4
- xp_assert_close, xp_assert_equal,
5
- assert_almost_equal, assert_array_almost_equal,
6
- )
7
5
  from pytest import raises as assert_raises
8
6
  import pytest
9
7
 
10
- from scipy.fft import fft
11
- from scipy.special import sinc
8
+ import scipy._lib.array_api_extra as xpx
9
+ from scipy._lib._array_api import (
10
+ xp_assert_close, xp_assert_equal, assert_almost_equal, assert_array_almost_equal,
11
+ array_namespace, xp_default_dtype
12
+ )
13
+ from scipy.fft import fft, fft2
12
14
  from scipy.signal import (kaiser_beta, kaiser_atten, kaiserord,
13
- firwin, firwin2, freqz, remez, firls, minimum_phase
15
+ firwin, firwin2, freqz, remez, firls, minimum_phase, convolve2d, firwin_2d
14
16
  )
15
17
 
18
+ skip_xp_backends = pytest.mark.skip_xp_backends
19
+ xfail_xp_backends = pytest.mark.xfail_xp_backends
20
+
16
21
 
17
22
  def test_kaiser_beta():
18
23
  b = kaiser_beta(58.7)
@@ -41,17 +46,19 @@ def test_kaiserord():
41
46
  class TestFirwin:
42
47
 
43
48
  def check_response(self, h, expected_response, tol=.05):
44
- N = len(h)
49
+ xp = array_namespace(h)
50
+ N = h.shape[0]
45
51
  alpha = 0.5 * (N-1)
46
- m = np.arange(0,N) - alpha # time indices of taps
52
+ m = xp.arange(0, N) - alpha # time indices of taps
47
53
  for freq, expected in expected_response:
48
- actual = abs(np.sum(h*np.exp(-1.j*np.pi*m*freq)))
49
- mse = abs(actual-expected)**2
54
+ actual = abs(xp.sum(h * xp.exp(-1j * xp.pi * m * freq)))
55
+ mse = abs(actual - expected)**2
50
56
  assert mse < tol, f'response not as expected, mse={mse:g} > {tol:g}'
51
57
 
52
- def test_response(self):
58
+ def test_response(self, xp):
53
59
  N = 51
54
60
  f = .5
61
+
55
62
  # increase length just to try even/odd
56
63
  h = firwin(N, f) # low-pass from 0 to f
57
64
  self.check_response(h, [(.25,1), (.75,0)])
@@ -97,7 +104,7 @@ class TestFirwin:
97
104
  mse = np.mean(abs(abs(H)-Hideal)**2)
98
105
  return mse
99
106
 
100
- def test_scaling(self):
107
+ def test_scaling(self, xp):
101
108
  """
102
109
  For one lowpass, bandpass, and highpass example filter, this test
103
110
  checks two things:
@@ -133,110 +140,130 @@ class TestFirwin:
133
140
  class TestFirWinMore:
134
141
  """Different author, different style, different tests..."""
135
142
 
136
- def test_lowpass(self):
143
+ def test_lowpass(self, xp):
137
144
  width = 0.04
138
145
  ntaps, beta = kaiserord(120, width)
139
- kwargs = dict(cutoff=0.5, window=('kaiser', beta), scale=False)
146
+ cutoff = xp.asarray(0.5)
147
+ kwargs = dict(cutoff=cutoff, window=('kaiser', beta), scale=False)
140
148
  taps = firwin(ntaps, **kwargs)
141
149
 
142
150
  # Check the symmetry of taps.
143
- assert_array_almost_equal(taps[:ntaps//2], taps[ntaps:ntaps-ntaps//2-1:-1])
151
+ assert_array_almost_equal(taps[:ntaps//2], xp.flip(taps)[:ntaps//2])
144
152
 
145
153
  # Check the gain at a few samples where
146
154
  # we know it should be approximately 0 or 1.
147
- freq_samples = np.array([0.0, 0.25, 0.5-width/2, 0.5+width/2, 0.75, 1.0])
148
- freqs, response = freqz(taps, worN=np.pi*freq_samples)
149
- assert_array_almost_equal(np.abs(response),
150
- [1.0, 1.0, 1.0, 0.0, 0.0, 0.0], decimal=5)
155
+ freq_samples = xp.asarray([0.0, 0.25, 0.5-width/2, 0.5+width/2, 0.75, 1.0])
156
+ freqs, response = freqz(taps, worN=xp.pi*freq_samples)
157
+
158
+ assert_array_almost_equal(
159
+ xp.abs(response),
160
+ xp.asarray([1.0, 1.0, 1.0, 0.0, 0.0, 0.0]), decimal=5
161
+ )
151
162
 
152
163
  taps_str = firwin(ntaps, pass_zero='lowpass', **kwargs)
153
164
  xp_assert_close(taps, taps_str)
154
165
 
155
- def test_highpass(self):
166
+ def test_highpass(self, xp):
156
167
  width = 0.04
157
168
  ntaps, beta = kaiserord(120, width)
158
169
 
159
170
  # Ensure that ntaps is odd.
160
171
  ntaps |= 1
161
172
 
162
- kwargs = dict(cutoff=0.5, window=('kaiser', beta), scale=False)
173
+ cutoff = xp.asarray(0.5)
174
+ kwargs = dict(cutoff=cutoff, window=('kaiser', beta), scale=False)
163
175
  taps = firwin(ntaps, pass_zero=False, **kwargs)
164
176
 
165
177
  # Check the symmetry of taps.
166
- assert_array_almost_equal(taps[:ntaps//2], taps[ntaps:ntaps-ntaps//2-1:-1])
178
+ assert_array_almost_equal(taps[:ntaps//2], xp.flip(taps)[:ntaps//2])
167
179
 
168
180
  # Check the gain at a few samples where
169
181
  # we know it should be approximately 0 or 1.
170
- freq_samples = np.array([0.0, 0.25, 0.5-width/2, 0.5+width/2, 0.75, 1.0])
182
+ freq_samples = xp.asarray([0.0, 0.25, 0.5 - width/2, 0.5 + width/2, 0.75, 1.0])
171
183
  freqs, response = freqz(taps, worN=np.pi*freq_samples)
172
- assert_array_almost_equal(np.abs(response),
173
- [0.0, 0.0, 0.0, 1.0, 1.0, 1.0], decimal=5)
184
+
185
+ assert_array_almost_equal(xp.abs(response),
186
+ xp.asarray([0.0, 0.0, 0.0, 1.0, 1.0, 1.0]), decimal=5)
174
187
 
175
188
  taps_str = firwin(ntaps, pass_zero='highpass', **kwargs)
176
189
  xp_assert_close(taps, taps_str)
177
190
 
178
- def test_bandpass(self):
191
+ def test_bandpass(self, xp):
179
192
  width = 0.04
180
193
  ntaps, beta = kaiserord(120, width)
181
- kwargs = dict(cutoff=[0.3, 0.7], window=('kaiser', beta), scale=False)
194
+ kwargs = dict(
195
+ cutoff=xp.asarray([0.3, 0.7]), window=('kaiser', beta), scale=False
196
+ )
182
197
  taps = firwin(ntaps, pass_zero=False, **kwargs)
183
198
 
184
199
  # Check the symmetry of taps.
185
- assert_array_almost_equal(taps[:ntaps//2], taps[ntaps:ntaps-ntaps//2-1:-1])
200
+ assert_array_almost_equal(taps[:ntaps//2], xp.flip(taps)[:ntaps//2])
186
201
 
187
202
  # Check the gain at a few samples where
188
203
  # we know it should be approximately 0 or 1.
189
- freq_samples = np.array([0.0, 0.2, 0.3-width/2, 0.3+width/2, 0.5,
190
- 0.7-width/2, 0.7+width/2, 0.8, 1.0])
204
+ freq_samples = xp.asarray([0.0, 0.2, 0.3 - width/2, 0.3 + width/2, 0.5,
205
+ 0.7 - width/2, 0.7 + width/2, 0.8, 1.0])
191
206
  freqs, response = freqz(taps, worN=np.pi*freq_samples)
192
- assert_array_almost_equal(np.abs(response),
193
- [0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0], decimal=5)
207
+
208
+ assert_array_almost_equal(xp.abs(response),
209
+ xp.asarray([0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0]), decimal=5)
194
210
 
195
211
  taps_str = firwin(ntaps, pass_zero='bandpass', **kwargs)
196
212
  xp_assert_close(taps, taps_str)
197
213
 
198
- def test_bandstop_multi(self):
214
+ def test_bandstop_multi(self, xp):
199
215
  width = 0.04
200
216
  ntaps, beta = kaiserord(120, width)
201
- kwargs = dict(cutoff=[0.2, 0.5, 0.8], window=('kaiser', beta),
217
+ kwargs = dict(cutoff=xp.asarray([0.2, 0.5, 0.8]), window=('kaiser', beta),
202
218
  scale=False)
203
219
  taps = firwin(ntaps, **kwargs)
204
220
 
205
221
  # Check the symmetry of taps.
206
- assert_array_almost_equal(taps[:ntaps//2], taps[ntaps:ntaps-ntaps//2-1:-1])
222
+ assert_array_almost_equal(taps[:ntaps//2], xp.flip(taps)[:ntaps//2])
207
223
 
208
224
  # Check the gain at a few samples where
209
225
  # we know it should be approximately 0 or 1.
210
- freq_samples = np.array([0.0, 0.1, 0.2-width/2, 0.2+width/2, 0.35,
211
- 0.5-width/2, 0.5+width/2, 0.65,
212
- 0.8-width/2, 0.8+width/2, 0.9, 1.0])
226
+ freq_samples = xp.asarray([0.0, 0.1, 0.2 - width/2, 0.2 + width/2, 0.35,
227
+ 0.5 - width/2, 0.5 + width/2, 0.65,
228
+ 0.8 - width/2, 0.8 + width/2, 0.9, 1.0])
213
229
  freqs, response = freqz(taps, worN=np.pi*freq_samples)
214
- assert_array_almost_equal(np.abs(response),
215
- [1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0],
216
- decimal=5)
230
+
231
+ assert_array_almost_equal(
232
+ xp.abs(response),
233
+ xp.asarray([1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0]),
234
+ decimal=5
235
+ )
217
236
 
218
237
  taps_str = firwin(ntaps, pass_zero='bandstop', **kwargs)
219
238
  xp_assert_close(taps, taps_str)
220
239
 
221
- def test_fs_nyq(self):
240
+ def test_fs_nyq(self, xp):
222
241
  """Test the fs and nyq keywords."""
223
242
  nyquist = 1000
224
243
  width = 40.0
225
244
  relative_width = width/nyquist
226
245
  ntaps, beta = kaiserord(120, relative_width)
227
- taps = firwin(ntaps, cutoff=[300, 700], window=('kaiser', beta),
246
+ taps = firwin(ntaps, cutoff=xp.asarray([300, 700]), window=('kaiser', beta),
228
247
  pass_zero=False, scale=False, fs=2*nyquist)
229
248
 
230
249
  # Check the symmetry of taps.
231
- assert_array_almost_equal(taps[:ntaps//2], taps[ntaps:ntaps-ntaps//2-1:-1])
250
+ assert_array_almost_equal(taps[:ntaps//2], xp.flip(taps)[:ntaps//2])
232
251
 
233
252
  # Check the gain at a few samples where
234
253
  # we know it should be approximately 0 or 1.
235
- freq_samples = np.array([0.0, 200, 300-width/2, 300+width/2, 500,
236
- 700-width/2, 700+width/2, 800, 1000])
254
+ freq_samples = xp.asarray([0.0, 200, 300 - width/2, 300 + width/2, 500,
255
+ 700 - width/2, 700 + width/2, 800, 1000])
237
256
  freqs, response = freqz(taps, worN=np.pi*freq_samples/nyquist)
238
- assert_array_almost_equal(np.abs(response),
239
- [0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0], decimal=5)
257
+
258
+ assert_array_almost_equal(xp.abs(response),
259
+ xp.asarray([0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0]), decimal=5)
260
+
261
+ def test_array_cutoff(self, xp):
262
+ taps = firwin(3, xp.asarray([.1, .2]))
263
+ # smoke test against the value computed by scipy==1.5.2
264
+ xp_assert_close(
265
+ taps, xp.asarray([-0.00801395, 1.0160279, -0.00801395]), atol=1e-8
266
+ )
240
267
 
241
268
  def test_bad_cutoff(self):
242
269
  """Test that invalid cutoff argument raises ValueError."""
@@ -265,9 +292,9 @@ class TestFirWinMore:
265
292
 
266
293
  def test_bad_pass_zero(self):
267
294
  """Test degenerate pass_zero cases."""
268
- with assert_raises(ValueError, match='pass_zero must be'):
295
+ with assert_raises(ValueError, match="^Parameter pass_zero='foo' not in "):
269
296
  firwin(41, 0.5, pass_zero='foo')
270
- with assert_raises(TypeError, match='cannot be interpreted'):
297
+ with assert_raises(ValueError, match="^Parameter pass_zero=1.0 not in "):
271
298
  firwin(41, 0.5, pass_zero=1.)
272
299
  for pass_zero in ('lowpass', 'highpass'):
273
300
  with assert_raises(ValueError, match='cutoff must have one'):
@@ -281,6 +308,7 @@ class TestFirWinMore:
281
308
  firwin2(51, .5, 1, fs=np.array([10, 20]))
282
309
 
283
310
 
311
+ @skip_xp_backends(cpu_only=True, reason="firwin2 uses np.interp")
284
312
  class TestFirwin2:
285
313
 
286
314
  def test_invalid_args(self):
@@ -330,90 +358,117 @@ class TestFirwin2:
330
358
  with assert_raises(ValueError, match='Type IV filter'):
331
359
  firwin2(16, [0.0, 0.5, 1.0], [1.0, 1.0, 0.0], antisymmetric=True)
332
360
 
333
- def test01(self):
361
+ def test01(self, xp):
334
362
  width = 0.04
335
363
  beta = 12.0
336
364
  ntaps = 400
337
365
  # Filter is 1 from w=0 to w=0.5, then decreases linearly from 1 to 0 as w
338
366
  # increases from w=0.5 to w=1 (w=1 is the Nyquist frequency).
339
- freq = [0.0, 0.5, 1.0]
340
- gain = [1.0, 1.0, 0.0]
367
+ freq = xp.asarray([0.0, 0.5, 1.0])
368
+ gain = xp.asarray([1.0, 1.0, 0.0])
341
369
  taps = firwin2(ntaps, freq, gain, window=('kaiser', beta))
342
- freq_samples = np.array([0.0, 0.25, 0.5-width/2, 0.5+width/2,
343
- 0.75, 1.0-width/2])
370
+ freq_samples = xp.asarray([0.0, 0.25, 0.5 - width/2, 0.5 + width/2,
371
+ 0.75, 1.0 - width/2])
344
372
  freqs, response = freqz(taps, worN=np.pi*freq_samples)
345
- assert_array_almost_equal(np.abs(response),
346
- [1.0, 1.0, 1.0, 1.0-width, 0.5, width], decimal=5)
347
-
348
- def test02(self):
373
+ freqs, response = xp.asarray(freqs), xp.asarray(response)
374
+ assert_array_almost_equal(
375
+ xp.abs(response),
376
+ xp.asarray([1.0, 1.0, 1.0, 1.0 - width, 0.5, width]), decimal=5
377
+ )
378
+
379
+ @skip_xp_backends("jax.numpy", reason="immutable arrays")
380
+ def test02(self, xp):
349
381
  width = 0.04
350
382
  beta = 12.0
351
383
  # ntaps must be odd for positive gain at Nyquist.
352
384
  ntaps = 401
353
385
  # An ideal highpass filter.
354
- freq = [0.0, 0.5, 0.5, 1.0]
355
- gain = [0.0, 0.0, 1.0, 1.0]
386
+ freq = xp.asarray([0.0, 0.5, 0.5, 1.0])
387
+ gain = xp.asarray([0.0, 0.0, 1.0, 1.0])
356
388
  taps = firwin2(ntaps, freq, gain, window=('kaiser', beta))
357
- freq_samples = np.array([0.0, 0.25, 0.5-width, 0.5+width, 0.75, 1.0])
389
+ freq_samples = np.array([0.0, 0.25, 0.5 - width, 0.5 + width, 0.75, 1.0])
358
390
  freqs, response = freqz(taps, worN=np.pi*freq_samples)
359
- assert_array_almost_equal(np.abs(response),
360
- [0.0, 0.0, 0.0, 1.0, 1.0, 1.0], decimal=5)
361
-
362
- def test03(self):
391
+ freqs, response = xp.asarray(freqs), xp.asarray(response)
392
+ assert_array_almost_equal(
393
+ xp.abs(response),
394
+ xp.asarray([0.0, 0.0, 0.0, 1.0, 1.0, 1.0]), decimal=5
395
+ )
396
+
397
+ @skip_xp_backends("jax.numpy", reason="immutable arrays")
398
+ def test03(self, xp):
363
399
  width = 0.02
364
400
  ntaps, beta = kaiserord(120, width)
365
401
  # ntaps must be odd for positive gain at Nyquist.
366
402
  ntaps = int(ntaps) | 1
367
- freq = [0.0, 0.4, 0.4, 0.5, 0.5, 1.0]
368
- gain = [1.0, 1.0, 0.0, 0.0, 1.0, 1.0]
403
+ freq = xp.asarray([0.0, 0.4, 0.4, 0.5, 0.5, 1.0])
404
+ gain = xp.asarray([1.0, 1.0, 0.0, 0.0, 1.0, 1.0])
369
405
  taps = firwin2(ntaps, freq, gain, window=('kaiser', beta))
370
- freq_samples = np.array([0.0, 0.4-width, 0.4+width, 0.45,
371
- 0.5-width, 0.5+width, 0.75, 1.0])
406
+ freq_samples = np.array([0.0, 0.4 - width, 0.4 + width, 0.45,
407
+ 0.5 - width, 0.5 + width, 0.75, 1.0])
372
408
  freqs, response = freqz(taps, worN=np.pi*freq_samples)
373
- assert_array_almost_equal(np.abs(response),
374
- [1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0], decimal=5)
375
-
376
- def test04(self):
409
+ freqs, response = xp.asarray(freqs), xp.asarray(response)
410
+ assert_array_almost_equal(
411
+ xp.abs(response),
412
+ xp.asarray([1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0]), decimal=5
413
+ )
414
+
415
+ @skip_xp_backends("jax.numpy", reason="immutable arrays")
416
+ def test04(self, xp):
377
417
  """Test firwin2 when window=None."""
378
418
  ntaps = 5
379
419
  # Ideal lowpass: gain is 1 on [0,0.5], and 0 on [0.5, 1.0]
380
- freq = [0.0, 0.5, 0.5, 1.0]
381
- gain = [1.0, 1.0, 0.0, 0.0]
420
+ freq = xp.asarray([0.0, 0.5, 0.5, 1.0])
421
+ gain = xp.asarray([1.0, 1.0, 0.0, 0.0])
422
+
382
423
  taps = firwin2(ntaps, freq, gain, window=None, nfreqs=8193)
383
424
  alpha = 0.5 * (ntaps - 1)
384
- m = np.arange(0, ntaps) - alpha
385
- h = 0.5 * sinc(0.5 * m)
425
+ m = xp.arange(0, ntaps, dtype=freq.dtype) - alpha
426
+ h = 0.5 * xpx.sinc(0.5 * m)
386
427
  assert_array_almost_equal(h, taps)
387
428
 
388
- def test05(self):
429
+ def test05(self, xp):
389
430
  """Test firwin2 for calculating Type IV filters"""
390
431
  ntaps = 1500
391
432
 
392
- freq = [0.0, 1.0]
393
- gain = [0.0, 1.0]
433
+ freq = xp.asarray([0.0, 1.0])
434
+ gain = xp.asarray([0.0, 1.0])
394
435
  taps = firwin2(ntaps, freq, gain, window=None, antisymmetric=True)
395
- assert_array_almost_equal(taps[: ntaps // 2], -taps[ntaps // 2:][::-1])
396
436
 
397
- freqs, response = freqz(taps, worN=2048)
398
- assert_array_almost_equal(abs(response), freqs / np.pi, decimal=4)
437
+ flip = array_namespace(freq).flip
438
+ dec = {'decimal': 4.5} if xp_default_dtype(xp) == xp.float32 else {}
439
+ assert_array_almost_equal(taps[: ntaps // 2], flip(-taps[ntaps // 2:]), **dec)
399
440
 
400
- def test06(self):
441
+ freqs, response = freqz(np.asarray(taps), worN=2048) # XXX convert freqz
442
+ assert_array_almost_equal(abs(xp.asarray(response)),
443
+ xp.asarray(freqs / np.pi), decimal=4)
444
+
445
+ @skip_xp_backends("jax.numpy", reason="immutable arrays")
446
+ def test06(self, xp):
401
447
  """Test firwin2 for calculating Type III filters"""
402
448
  ntaps = 1501
403
449
 
404
- freq = [0.0, 0.5, 0.55, 1.0]
405
- gain = [0.0, 0.5, 0.0, 0.0]
450
+ freq = xp.asarray([0.0, 0.5, 0.55, 1.0])
451
+ gain = xp.asarray([0.0, 0.5, 0.0, 0.0])
406
452
  taps = firwin2(ntaps, freq, gain, window=None, antisymmetric=True)
407
453
  assert taps[ntaps // 2] == 0.0
408
- assert_array_almost_equal(taps[: ntaps // 2], -taps[ntaps // 2 + 1:][::-1])
409
454
 
410
- freqs, response1 = freqz(taps, worN=2048)
411
- response2 = np.interp(freqs / np.pi, freq, gain)
455
+ flip = array_namespace(freq).flip
456
+ dec = {'decimal': 4.5} if xp_default_dtype(xp) == xp.float32 else {}
457
+ assert_array_almost_equal(taps[: ntaps // 2],
458
+ flip(-taps[ntaps // 2 + 1:]), **dec
459
+ )
460
+
461
+ freqs, response1 = freqz(np.asarray(taps), worN=2048) # XXX convert freqz
462
+ response1 = xp.asarray(response1)
463
+ response2 = xp.asarray(
464
+ np.interp(np.asarray(freqs) / np.pi, np.asarray(freq), np.asarray(gain))
465
+ )
412
466
  assert_array_almost_equal(abs(response1), response2, decimal=3)
413
467
 
414
- def test_fs_nyq(self):
415
- taps1 = firwin2(80, [0.0, 0.5, 1.0], [1.0, 1.0, 0.0])
416
- taps2 = firwin2(80, [0.0, 30.0, 60.0], [1.0, 1.0, 0.0], fs=120.0)
468
+ def test_fs_nyq(self, xp):
469
+ taps1 = firwin2(80, xp.asarray([0.0, 0.5, 1.0]), xp.asarray([1.0, 1.0, 0.0]))
470
+ taps2 = firwin2(80, xp.asarray([0.0, 30.0, 60.0]), xp.asarray([1.0, 1.0, 0.0]),
471
+ fs=120.0)
417
472
  assert_array_almost_equal(taps1, taps2)
418
473
 
419
474
  def test_tuple(self):
@@ -421,13 +476,15 @@ class TestFirwin2:
421
476
  taps2 = firwin2(150, [0.0, 0.5, 0.5, 1.0], [1.0, 1.0, 0.0, 0.0])
422
477
  assert_array_almost_equal(taps1, taps2)
423
478
 
424
- def test_input_modyfication(self):
425
- freq1 = np.array([0.0, 0.5, 0.5, 1.0])
426
- freq2 = np.array(freq1)
427
- firwin2(80, freq1, [1.0, 1.0, 0.0, 0.0])
479
+ @skip_xp_backends("jax.numpy", reason="immutable arrays")
480
+ def test_input_modyfication(self, xp):
481
+ freq1 = xp.asarray([0.0, 0.5, 0.5, 1.0])
482
+ freq2 = xp.asarray(freq1)
483
+ firwin2(80, freq1, xp.asarray([1.0, 1.0, 0.0, 0.0]))
428
484
  xp_assert_equal(freq1, freq2)
429
485
 
430
486
 
487
+ @skip_xp_backends(cpu_only=True)
431
488
  class TestRemez:
432
489
 
433
490
  def test_bad_args(self):
@@ -462,14 +519,15 @@ class TestRemez:
462
519
  idx = np.logical_and(f > a, f < 0.5-a)
463
520
  assert (abs(Hmag[idx] - 1) < 0.015).all(), "Pass Band Close To Unity"
464
521
 
465
- def test_compare(self):
522
+ def test_compare(self, xp):
466
523
  # test comparison to MATLAB
467
524
  k = [0.024590270518440, -0.041314581814658, -0.075943803756711,
468
525
  -0.003530911231040, 0.193140296954975, 0.373400753484939,
469
526
  0.373400753484939, 0.193140296954975, -0.003530911231040,
470
527
  -0.075943803756711, -0.041314581814658, 0.024590270518440]
471
- h = remez(12, [0, 0.3, 0.5, 1], [1, 0], fs=2.)
472
- xp_assert_close(h, k)
528
+ h = remez(12, xp.asarray([0, 0.3, 0.5, 1]), xp.asarray([1, 0]), fs=2.)
529
+ atol_arg = {'atol': 1e-8} if xp_default_dtype(xp) == xp.float32 else {}
530
+ xp_assert_close(h, xp.asarray(k, dtype=xp.float64), **atol_arg)
473
531
 
474
532
  h = [-0.038976016082299, 0.018704846485491, -0.014644062687875,
475
533
  0.002879152556419, 0.016849978528150, -0.043276706138248,
@@ -478,12 +536,19 @@ class TestRemez:
478
536
  0.129770906801075, -0.103908158578635, 0.073641298245579,
479
537
  -0.043276706138248, 0.016849978528150, 0.002879152556419,
480
538
  -0.014644062687875, 0.018704846485491, -0.038976016082299]
481
- xp_assert_close(remez(21, [0, 0.8, 0.9, 1], [0, 1], fs=2.), h)
539
+ atol_arg = {'atol': 3e-8} if xp_default_dtype(xp) == xp.float32 else {}
540
+ xp_assert_close(
541
+ remez(21, xp.asarray([0, 0.8, 0.9, 1]), xp.asarray([0, 1]), fs=2.),
542
+ xp.asarray(h, dtype=xp.float64), **atol_arg
543
+ )
482
544
 
483
545
  def test_fs_validation(self):
484
546
  with pytest.raises(ValueError, match="Sampling.*single scalar"):
485
547
  remez(11, .1, 1, fs=np.array([10, 20]))
486
548
 
549
+
550
+
551
+ @skip_xp_backends(cpu_only=True, reason="lstsq")
487
552
  class TestFirls:
488
553
 
489
554
  def test_bad_args(self):
@@ -505,105 +570,121 @@ class TestFirls:
505
570
  # negative weight
506
571
  assert_raises(ValueError, firls, 11, [0.1, 0.2], [0, 0], weight=[-1])
507
572
 
508
- def test_firls(self):
573
+ @skip_xp_backends("dask.array", reason="dask fancy indexing shape=(nan,)")
574
+ def test_firls(self, xp):
509
575
  N = 11 # number of taps in the filter
510
576
  a = 0.1 # width of the transition band
511
577
 
512
578
  # design a halfband symmetric low-pass filter
513
- h = firls(11, [0, a, 0.5-a, 0.5], [1, 1, 0, 0], fs=1.0)
579
+ h = firls(11, xp.asarray([0, a, 0.5 - a, 0.5]), xp.asarray([1, 1, 0, 0]),
580
+ fs=1.0)
514
581
 
515
582
  # make sure the filter has correct # of taps
516
583
  assert h.shape[0] == N
517
584
 
518
585
  # make sure it is symmetric
519
586
  midx = (N-1) // 2
520
- assert_array_almost_equal(h[:midx], h[:-midx-1:-1])
587
+ flip = array_namespace(h).flip
588
+ assert_array_almost_equal(h[:midx], flip(h[midx+1:])) # h[:-midx-1:-1])
521
589
 
522
590
  # make sure the center tap is 0.5
523
- assert_almost_equal(h[midx], 0.5)
591
+ assert math.isclose(h[midx], 0.5, abs_tol=1e-8)
524
592
 
525
593
  # For halfband symmetric, odd coefficients (except the center)
526
594
  # should be zero (really small)
527
- hodd = np.hstack((h[1:midx:2], h[-midx+1::2]))
528
- assert_array_almost_equal(hodd, np.zeros_like(hodd))
595
+ hodd = xp.stack((h[1:midx:2], h[-midx+1::2]))
596
+ assert_array_almost_equal(hodd, xp.zeros_like(hodd))
529
597
 
530
598
  # now check the frequency response
531
- w, H = freqz(h, 1)
532
- f = w/2/np.pi
533
- Hmag = np.abs(H)
599
+ w, H = freqz(np.asarray(h), 1)
600
+ w, H = xp.asarray(w), xp.asarray(H)
601
+ f = w/2/xp.pi
602
+ Hmag = xp.abs(H)
534
603
 
535
604
  # check that the pass band is close to unity
536
- idx = np.logical_and(f > 0, f < a)
537
- assert_array_almost_equal(Hmag[idx], np.ones_like(Hmag[idx]), decimal=3)
605
+ idx = xp.logical_and(f > 0, f < a)
606
+ assert_array_almost_equal(Hmag[idx], xp.ones_like(Hmag[idx]), decimal=3)
538
607
 
539
608
  # check that the stop band is close to zero
540
- idx = np.logical_and(f > 0.5-a, f < 0.5)
541
- assert_array_almost_equal(Hmag[idx], np.zeros_like(Hmag[idx]), decimal=3)
609
+ idx = xp.logical_and(f > 0.5 - a, f < 0.5)
610
+ assert_array_almost_equal(Hmag[idx], xp.zeros_like(Hmag[idx]), decimal=3)
542
611
 
543
- def test_compare(self):
612
+ def test_compare(self, xp):
544
613
  # compare to OCTAVE output
545
- taps = firls(9, [0, 0.5, 0.55, 1], [1, 1, 0, 0], weight=[1, 2])
614
+ taps = firls(9, xp.asarray([0, 0.5, 0.55, 1]),
615
+ xp.asarray([1, 1, 0, 0]), weight=xp.asarray([1, 2]))
546
616
  # >> taps = firls(8, [0 0.5 0.55 1], [1 1 0 0], [1, 2]);
547
617
  known_taps = [-6.26930101730182e-04, -1.03354450635036e-01,
548
618
  -9.81576747564301e-03, 3.17271686090449e-01,
549
619
  5.11409425599933e-01, 3.17271686090449e-01,
550
620
  -9.81576747564301e-03, -1.03354450635036e-01,
551
621
  -6.26930101730182e-04]
552
- xp_assert_close(taps, known_taps)
622
+ atol_arg = {'atol': 5e-8} if xp_default_dtype(xp) == xp.float32 else {}
623
+ known_taps = xp.asarray(known_taps, dtype=xp.float64)
624
+ xp_assert_close(taps, known_taps, **atol_arg)
553
625
 
554
626
  # compare to MATLAB output
555
- taps = firls(11, [0, 0.5, 0.5, 1], [1, 1, 0, 0], weight=[1, 2])
627
+ taps = firls(11, xp.asarray([0, 0.5, 0.5, 1]),
628
+ xp.asarray([1, 1, 0, 0]), weight=xp.asarray([1, 2]))
556
629
  # >> taps = firls(10, [0 0.5 0.5 1], [1 1 0 0], [1, 2]);
557
630
  known_taps = [
558
631
  0.058545300496815, -0.014233383714318, -0.104688258464392,
559
632
  0.012403323025279, 0.317930861136062, 0.488047220029700,
560
633
  0.317930861136062, 0.012403323025279, -0.104688258464392,
561
634
  -0.014233383714318, 0.058545300496815]
562
- xp_assert_close(taps, known_taps)
635
+ known_taps = xp.asarray(known_taps, dtype=xp.float64)
636
+ atol_arg = {'atol': 3e-8} if xp_default_dtype(xp) == xp.float32 else {}
637
+ xp_assert_close(taps, known_taps, **atol_arg)
563
638
 
564
639
  # With linear changes:
565
- taps = firls(7, (0, 1, 2, 3, 4, 5), [1, 0, 0, 1, 1, 0], fs=20)
640
+ taps = firls(7, xp.asarray((0, 1, 2, 3, 4, 5)),
641
+ xp.asarray([1, 0, 0, 1, 1, 0]), fs=20)
566
642
  # >> taps = firls(6, [0, 0.1, 0.2, 0.3, 0.4, 0.5], [1, 0, 0, 1, 1, 0])
567
643
  known_taps = [
568
644
  1.156090832768218, -4.1385894727395849, 7.5288619164321826,
569
645
  -8.5530572592947856, 7.5288619164321826, -4.1385894727395849,
570
646
  1.156090832768218]
647
+ known_taps = xp.asarray(known_taps, dtype=xp.float64)
571
648
  xp_assert_close(taps, known_taps)
572
649
 
573
- def test_rank_deficient(self):
650
+ def test_rank_deficient(self, xp):
574
651
  # solve() runs but warns (only sometimes, so here we don't use match)
575
- x = firls(21, [0, 0.1, 0.9, 1], [1, 1, 0, 0])
576
- w, h = freqz(x, fs=2.)
577
- absh2 = np.abs(h[:2])
578
- xp_assert_close(absh2, np.ones_like(absh2), atol=1e-5)
579
- absh2 = np.abs(h[-2:])
580
- xp_assert_close(absh2, np.zeros_like(absh2), atol=1e-6, rtol=1e-7)
652
+ x = firls(21, xp.asarray([0, 0.1, 0.9, 1]), xp.asarray([1, 1, 0, 0]))
653
+ w, h = freqz(np.asarray(x), fs=2.)
654
+ w, h = map(xp.asarray, (w, h)) # XXX convert freqz
655
+ absh2 = xp.abs(h[:2])
656
+ xp_assert_close(absh2, xp.ones_like(absh2), atol=1e-5)
657
+ absh2 = xp.abs(h[-2:])
658
+ xp_assert_close(absh2, xp.zeros_like(absh2), atol=1e-6, rtol=1e-7)
581
659
  # switch to pinvh (tolerances could be higher with longer
582
660
  # filters, but using shorter ones is faster computationally and
583
661
  # the idea is the same)
584
- x = firls(101, [0, 0.01, 0.99, 1], [1, 1, 0, 0])
585
- w, h = freqz(x, fs=2.)
586
- mask = w < 0.01
587
- assert mask.sum() > 3
588
- habs = np.abs(h[mask])
589
- xp_assert_close(habs, np.ones_like(habs), atol=1e-4)
590
- mask = w > 0.99
591
- assert mask.sum() > 3
592
- habs = np.abs(h[mask])
593
- xp_assert_close(habs, np.zeros_like(habs), atol=1e-4)
662
+ x = firls(101, xp.asarray([0, 0.01, 0.99, 1]), xp.asarray([1, 1, 0, 0]))
663
+ w, h = freqz(np.asarray(x), fs=2.)
664
+ w, h = map(xp.asarray, (w, h)) # XXX convert freqz
665
+ mask = xp.asarray(w < 0.01)
666
+ h = xp.asarray(h)
667
+ assert xp.sum(xp.astype(mask, xp.int64)) > 3
668
+ habs = xp.abs(h[mask])
669
+ xp_assert_close(habs, xp.ones_like(habs), atol=1e-4)
670
+ mask = xp.asarray(w > 0.99)
671
+ assert xp.sum(xp.astype(mask, xp.int64)) > 3
672
+ habs = xp.abs(h[mask])
673
+ xp_assert_close(habs, xp.zeros_like(habs), atol=1e-4)
594
674
 
595
675
  def test_fs_validation(self):
596
676
  with pytest.raises(ValueError, match="Sampling.*single scalar"):
597
677
  firls(11, .1, 1, fs=np.array([10, 20]))
598
678
 
599
679
  class TestMinimumPhase:
680
+
600
681
  @pytest.mark.thread_unsafe
601
682
  def test_bad_args(self):
602
683
  # not enough taps
603
684
  assert_raises(ValueError, minimum_phase, [1.])
604
685
  assert_raises(ValueError, minimum_phase, [1., 1.])
605
686
  assert_raises(ValueError, minimum_phase, np.full(10, 1j))
606
- assert_raises(ValueError, minimum_phase, 'foo')
687
+ assert_raises((ValueError, TypeError), minimum_phase, 'foo')
607
688
  assert_raises(ValueError, minimum_phase, np.ones(10), n_fft=8)
608
689
  assert_raises(ValueError, minimum_phase, np.ones(10), method='foo')
609
690
  assert_warns(RuntimeWarning, minimum_phase, np.arange(3))
@@ -630,7 +711,9 @@ class TestMinimumPhase:
630
711
  assert len(h_linear) == len(h_new)
631
712
  xp_assert_close(np.abs(fft(h_new)), np.abs(fft(h_linear)), rtol=1e-4)
632
713
 
633
- def test_hilbert(self):
714
+ @skip_xp_backends("dask.array", reason="too slow")
715
+ @skip_xp_backends("jax.numpy", reason="immutable arrays")
716
+ def test_hilbert(self, xp):
634
717
  # compare to MATLAB output of reference implementation
635
718
 
636
719
  # f=[0 0.3 0.5 1];
@@ -639,6 +722,8 @@ class TestMinimumPhase:
639
722
  h = remez(12, [0, 0.3, 0.5, 1], [1, 0], fs=2.)
640
723
  k = [0.349585548646686, 0.373552164395447, 0.326082685363438,
641
724
  0.077152207480935, -0.129943946349364, -0.059355880509749]
725
+ h = xp.asarray(h)
726
+ k = xp.asarray(k, dtype=xp.float64)
642
727
  m = minimum_phase(h, 'hilbert')
643
728
  xp_assert_close(m, k, rtol=5e-3)
644
729
 
@@ -650,5 +735,112 @@ class TestMinimumPhase:
650
735
  -0.157957283165866, 0.151739294892963, -0.129293146705090,
651
736
  0.100787844523204, -0.065832656741252, 0.035361328741024,
652
737
  -0.014977068692269, -0.158416139047557]
738
+ h = xp.asarray(h)
739
+ k = xp.asarray(k, dtype=xp.float64)
653
740
  m = minimum_phase(h, 'hilbert', n_fft=2**19)
654
741
  xp_assert_close(m, k, rtol=2e-3)
742
+
743
+
744
+ class Testfirwin_2d:
745
+ def test_invalid_args(self):
746
+ with pytest.raises(ValueError,
747
+ match="hsize must be a 2-element tuple or list"):
748
+ firwin_2d((50,), window=(("kaiser", 5.0), "boxcar"), fc=0.4)
749
+
750
+ with pytest.raises(ValueError,
751
+ match="window must be a 2-element tuple or list"):
752
+ firwin_2d((51, 51), window=("hamming",), fc=0.5)
753
+
754
+ with pytest.raises(ValueError,
755
+ match="window must be a 2-element tuple or list"):
756
+ firwin_2d((51, 51), window="invalid_window", fc=0.5)
757
+
758
+ def test_filter_design(self):
759
+ hsize = (51, 51)
760
+ window = (("kaiser", 8.0), ("kaiser", 8.0))
761
+ fc = 0.4
762
+ taps_kaiser = firwin_2d(hsize, window, fc=fc)
763
+ assert taps_kaiser.shape == (51, 51)
764
+
765
+ window = ("hamming", "hamming")
766
+ taps_hamming = firwin_2d(hsize, window, fc=fc)
767
+ assert taps_hamming.shape == (51, 51)
768
+
769
+ def test_impulse_response(self):
770
+ hsize = (31, 31)
771
+ window = ("hamming", "hamming")
772
+ fc = 0.4
773
+ taps = firwin_2d(hsize, window, fc=fc)
774
+
775
+ impulse = np.zeros((63, 63))
776
+ impulse[31, 31] = 1
777
+
778
+ response = convolve2d(impulse, taps, mode='same')
779
+
780
+ expected_response = taps
781
+ xp_assert_close(response[16:47, 16:47], expected_response, rtol=1e-5)
782
+
783
+ def test_frequency_response(self):
784
+ """Compare 1d and 2d frequency response. """
785
+ hsize = (31, 31)
786
+ windows = ("hamming", "hamming")
787
+ fc = 0.4
788
+ taps_1d = firwin(numtaps=hsize[0], cutoff=fc, window=windows[0])
789
+ taps_2d = firwin_2d(hsize, windows, fc=fc)
790
+
791
+ f_resp_1d = fft(taps_1d)
792
+ f_resp_2d = fft2(taps_2d)
793
+
794
+ xp_assert_close(f_resp_2d[0, :], f_resp_1d,
795
+ err_msg='DC Gain at (0, f1) is not unity!')
796
+ xp_assert_close(f_resp_2d[:, 0], f_resp_1d,
797
+ err_msg='DC Gain at (f0, 0) is not unity!')
798
+ xp_assert_close(f_resp_2d, np.outer(f_resp_1d, f_resp_1d),
799
+ atol=np.finfo(f_resp_2d.dtype).resolution,
800
+ err_msg='2d frequency response is not product of 1d responses')
801
+
802
+ def test_symmetry(self):
803
+ hsize = (51, 51)
804
+ window = ("hamming", "hamming")
805
+ fc = 0.4
806
+ taps = firwin_2d(hsize, window, fc=fc)
807
+ xp_assert_close(taps, np.flip(taps), rtol=1e-5)
808
+
809
+ def test_circular_symmetry(self):
810
+ hsize = (51, 51)
811
+ window = "hamming"
812
+ taps = firwin_2d(hsize, window, circular=True, fc=0.5)
813
+ center = hsize[0] // 2
814
+ for i in range(hsize[0]):
815
+ for j in range(hsize[1]):
816
+ xp_assert_close(taps[i, j],
817
+ taps[center - (i - center), center - (j - center)],
818
+ rtol=1e-5)
819
+
820
+ def test_edge_case_circular(self):
821
+ hsize = (3, 3)
822
+ window = "hamming"
823
+ taps_small = firwin_2d(hsize, window, circular=True, fc=0.5)
824
+ assert taps_small.shape == (3, 3)
825
+
826
+ hsize = (101, 101)
827
+ taps_large = firwin_2d(hsize, window, circular=True, fc=0.5)
828
+ assert taps_large.shape == (101, 101)
829
+
830
+ def test_known_result(self):
831
+ hsize = (5, 5)
832
+ window = ('kaiser', 8.0)
833
+ fc = 0.1
834
+ fs = 2
835
+
836
+ row_filter = firwin(hsize[0], cutoff=fc, window=window, fs=fs)
837
+ col_filter = firwin(hsize[1], cutoff=fc, window=window, fs=fs)
838
+ known_result = np.outer(row_filter, col_filter)
839
+
840
+ taps = firwin_2d(hsize, (window, window), fc=fc)
841
+ assert taps.shape == known_result.shape, (
842
+ f"Shape mismatch: {taps.shape} vs {known_result.shape}"
843
+ )
844
+ assert np.allclose(taps, known_result, rtol=1e-1), (
845
+ f"Filter shape mismatch: {taps} vs {known_result}"
846
+ )