scipy 1.15.3__cp313-cp313t-macosx_14_0_arm64.whl → 1.16.0rc2__cp313-cp313t-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 (627) hide show
  1. scipy/__config__.py +3 -3
  2. scipy/__init__.py +3 -6
  3. scipy/_cyutility.cpython-313t-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-313t-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-313t-darwin.so +0 -0
  12. scipy/_lib/_testutils.py +6 -2
  13. scipy/_lib/_util.py +222 -125
  14. scipy/_lib/array_api_compat/__init__.py +4 -4
  15. scipy/_lib/array_api_compat/_internal.py +19 -6
  16. scipy/_lib/array_api_compat/common/__init__.py +1 -1
  17. scipy/_lib/array_api_compat/common/_aliases.py +365 -193
  18. scipy/_lib/array_api_compat/common/_fft.py +94 -64
  19. scipy/_lib/array_api_compat/common/_helpers.py +413 -180
  20. scipy/_lib/array_api_compat/common/_linalg.py +116 -40
  21. scipy/_lib/array_api_compat/common/_typing.py +179 -10
  22. scipy/_lib/array_api_compat/cupy/__init__.py +1 -4
  23. scipy/_lib/array_api_compat/cupy/_aliases.py +61 -41
  24. scipy/_lib/array_api_compat/cupy/_info.py +16 -6
  25. scipy/_lib/array_api_compat/cupy/_typing.py +24 -39
  26. scipy/_lib/array_api_compat/dask/array/__init__.py +6 -3
  27. scipy/_lib/array_api_compat/dask/array/_aliases.py +267 -108
  28. scipy/_lib/array_api_compat/dask/array/_info.py +105 -34
  29. scipy/_lib/array_api_compat/dask/array/fft.py +5 -8
  30. scipy/_lib/array_api_compat/dask/array/linalg.py +21 -22
  31. scipy/_lib/array_api_compat/numpy/__init__.py +13 -15
  32. scipy/_lib/array_api_compat/numpy/_aliases.py +98 -49
  33. scipy/_lib/array_api_compat/numpy/_info.py +36 -16
  34. scipy/_lib/array_api_compat/numpy/_typing.py +27 -43
  35. scipy/_lib/array_api_compat/numpy/fft.py +11 -5
  36. scipy/_lib/array_api_compat/numpy/linalg.py +75 -22
  37. scipy/_lib/array_api_compat/torch/__init__.py +3 -5
  38. scipy/_lib/array_api_compat/torch/_aliases.py +262 -159
  39. scipy/_lib/array_api_compat/torch/_info.py +27 -16
  40. scipy/_lib/array_api_compat/torch/_typing.py +3 -0
  41. scipy/_lib/array_api_compat/torch/fft.py +17 -18
  42. scipy/_lib/array_api_compat/torch/linalg.py +16 -16
  43. scipy/_lib/array_api_extra/__init__.py +26 -3
  44. scipy/_lib/array_api_extra/_delegation.py +171 -0
  45. scipy/_lib/array_api_extra/_lib/__init__.py +1 -0
  46. scipy/_lib/array_api_extra/_lib/_at.py +463 -0
  47. scipy/_lib/array_api_extra/_lib/_backends.py +46 -0
  48. scipy/_lib/array_api_extra/_lib/_funcs.py +937 -0
  49. scipy/_lib/array_api_extra/_lib/_lazy.py +357 -0
  50. scipy/_lib/array_api_extra/_lib/_testing.py +278 -0
  51. scipy/_lib/array_api_extra/_lib/_utils/__init__.py +1 -0
  52. scipy/_lib/array_api_extra/_lib/_utils/_compat.py +74 -0
  53. scipy/_lib/array_api_extra/_lib/_utils/_compat.pyi +45 -0
  54. scipy/_lib/array_api_extra/_lib/_utils/_helpers.py +559 -0
  55. scipy/_lib/array_api_extra/_lib/_utils/_typing.py +10 -0
  56. scipy/_lib/array_api_extra/_lib/_utils/_typing.pyi +105 -0
  57. scipy/_lib/array_api_extra/testing.py +359 -0
  58. scipy/_lib/decorator.py +2 -2
  59. scipy/_lib/doccer.py +1 -7
  60. scipy/_lib/messagestream.cpython-313t-darwin.so +0 -0
  61. scipy/_lib/pyprima/__init__.py +212 -0
  62. scipy/_lib/pyprima/cobyla/__init__.py +0 -0
  63. scipy/_lib/pyprima/cobyla/cobyla.py +559 -0
  64. scipy/_lib/pyprima/cobyla/cobylb.py +714 -0
  65. scipy/_lib/pyprima/cobyla/geometry.py +226 -0
  66. scipy/_lib/pyprima/cobyla/initialize.py +215 -0
  67. scipy/_lib/pyprima/cobyla/trustregion.py +492 -0
  68. scipy/_lib/pyprima/cobyla/update.py +289 -0
  69. scipy/_lib/pyprima/common/__init__.py +0 -0
  70. scipy/_lib/pyprima/common/_bounds.py +34 -0
  71. scipy/_lib/pyprima/common/_linear_constraints.py +46 -0
  72. scipy/_lib/pyprima/common/_nonlinear_constraints.py +54 -0
  73. scipy/_lib/pyprima/common/_project.py +173 -0
  74. scipy/_lib/pyprima/common/checkbreak.py +93 -0
  75. scipy/_lib/pyprima/common/consts.py +47 -0
  76. scipy/_lib/pyprima/common/evaluate.py +99 -0
  77. scipy/_lib/pyprima/common/history.py +38 -0
  78. scipy/_lib/pyprima/common/infos.py +30 -0
  79. scipy/_lib/pyprima/common/linalg.py +435 -0
  80. scipy/_lib/pyprima/common/message.py +290 -0
  81. scipy/_lib/pyprima/common/powalg.py +131 -0
  82. scipy/_lib/pyprima/common/preproc.py +277 -0
  83. scipy/_lib/pyprima/common/present.py +5 -0
  84. scipy/_lib/pyprima/common/ratio.py +54 -0
  85. scipy/_lib/pyprima/common/redrho.py +47 -0
  86. scipy/_lib/pyprima/common/selectx.py +296 -0
  87. scipy/_lib/tests/test__util.py +105 -121
  88. scipy/_lib/tests/test_array_api.py +166 -35
  89. scipy/_lib/tests/test_bunch.py +7 -0
  90. scipy/_lib/tests/test_ccallback.py +2 -10
  91. scipy/_lib/tests/test_public_api.py +13 -0
  92. scipy/cluster/_hierarchy.cpython-313t-darwin.so +0 -0
  93. scipy/cluster/_optimal_leaf_ordering.cpython-313t-darwin.so +0 -0
  94. scipy/cluster/_vq.cpython-313t-darwin.so +0 -0
  95. scipy/cluster/hierarchy.py +393 -223
  96. scipy/cluster/tests/test_hierarchy.py +273 -335
  97. scipy/cluster/tests/test_vq.py +45 -61
  98. scipy/cluster/vq.py +39 -35
  99. scipy/conftest.py +263 -157
  100. scipy/constants/_constants.py +4 -1
  101. scipy/constants/tests/test_codata.py +2 -2
  102. scipy/constants/tests/test_constants.py +11 -18
  103. scipy/datasets/_download_all.py +15 -1
  104. scipy/datasets/_fetchers.py +7 -1
  105. scipy/datasets/_utils.py +1 -1
  106. scipy/differentiate/_differentiate.py +25 -25
  107. scipy/differentiate/tests/test_differentiate.py +24 -25
  108. scipy/fft/_basic.py +20 -0
  109. scipy/fft/_helper.py +3 -34
  110. scipy/fft/_pocketfft/helper.py +29 -1
  111. scipy/fft/_pocketfft/tests/test_basic.py +2 -4
  112. scipy/fft/_pocketfft/tests/test_real_transforms.py +4 -4
  113. scipy/fft/_realtransforms.py +13 -0
  114. scipy/fft/tests/test_basic.py +27 -25
  115. scipy/fft/tests/test_fftlog.py +16 -7
  116. scipy/fft/tests/test_helper.py +18 -34
  117. scipy/fft/tests/test_real_transforms.py +8 -10
  118. scipy/fftpack/convolve.cpython-313t-darwin.so +0 -0
  119. scipy/fftpack/tests/test_basic.py +2 -4
  120. scipy/fftpack/tests/test_real_transforms.py +8 -9
  121. scipy/integrate/_bvp.py +9 -3
  122. scipy/integrate/_cubature.py +3 -2
  123. scipy/integrate/_dop.cpython-313t-darwin.so +0 -0
  124. scipy/integrate/_lsoda.cpython-313t-darwin.so +0 -0
  125. scipy/integrate/_ode.py +9 -2
  126. scipy/integrate/_odepack.cpython-313t-darwin.so +0 -0
  127. scipy/integrate/_quad_vec.py +21 -29
  128. scipy/integrate/_quadpack.cpython-313t-darwin.so +0 -0
  129. scipy/integrate/_quadpack_py.py +11 -7
  130. scipy/integrate/_quadrature.py +3 -3
  131. scipy/integrate/_rules/_base.py +2 -2
  132. scipy/integrate/_tanhsinh.py +48 -47
  133. scipy/integrate/_test_odeint_banded.cpython-313t-darwin.so +0 -0
  134. scipy/integrate/_vode.cpython-313t-darwin.so +0 -0
  135. scipy/integrate/tests/test__quad_vec.py +0 -6
  136. scipy/integrate/tests/test_banded_ode_solvers.py +85 -0
  137. scipy/integrate/tests/test_cubature.py +21 -35
  138. scipy/integrate/tests/test_quadrature.py +6 -8
  139. scipy/integrate/tests/test_tanhsinh.py +56 -48
  140. scipy/interpolate/__init__.py +70 -58
  141. scipy/interpolate/_bary_rational.py +22 -22
  142. scipy/interpolate/_bsplines.py +119 -66
  143. scipy/interpolate/_cubic.py +65 -50
  144. scipy/interpolate/_dfitpack.cpython-313t-darwin.so +0 -0
  145. scipy/interpolate/_dierckx.cpython-313t-darwin.so +0 -0
  146. scipy/interpolate/_fitpack.cpython-313t-darwin.so +0 -0
  147. scipy/interpolate/_fitpack2.py +9 -6
  148. scipy/interpolate/_fitpack_impl.py +32 -26
  149. scipy/interpolate/_fitpack_repro.py +23 -19
  150. scipy/interpolate/_interpnd.cpython-313t-darwin.so +0 -0
  151. scipy/interpolate/_interpolate.py +30 -12
  152. scipy/interpolate/_ndbspline.py +13 -18
  153. scipy/interpolate/_ndgriddata.py +5 -8
  154. scipy/interpolate/_polyint.py +95 -31
  155. scipy/interpolate/_ppoly.cpython-313t-darwin.so +0 -0
  156. scipy/interpolate/_rbf.py +2 -2
  157. scipy/interpolate/_rbfinterp.py +1 -1
  158. scipy/interpolate/_rbfinterp_pythran.cpython-313t-darwin.so +0 -0
  159. scipy/interpolate/_rgi.py +31 -26
  160. scipy/interpolate/_rgi_cython.cpython-313t-darwin.so +0 -0
  161. scipy/interpolate/dfitpack.py +0 -20
  162. scipy/interpolate/interpnd.py +1 -2
  163. scipy/interpolate/tests/test_bary_rational.py +2 -2
  164. scipy/interpolate/tests/test_bsplines.py +97 -1
  165. scipy/interpolate/tests/test_fitpack2.py +39 -1
  166. scipy/interpolate/tests/test_interpnd.py +32 -20
  167. scipy/interpolate/tests/test_interpolate.py +48 -4
  168. scipy/interpolate/tests/test_rgi.py +2 -1
  169. scipy/io/_fast_matrix_market/__init__.py +2 -0
  170. scipy/io/_harwell_boeing/_fortran_format_parser.py +19 -16
  171. scipy/io/_harwell_boeing/hb.py +7 -11
  172. scipy/io/_idl.py +5 -7
  173. scipy/io/_netcdf.py +15 -5
  174. scipy/io/_test_fortran.cpython-313t-darwin.so +0 -0
  175. scipy/io/arff/tests/test_arffread.py +3 -3
  176. scipy/io/matlab/__init__.py +5 -3
  177. scipy/io/matlab/_mio.py +4 -1
  178. scipy/io/matlab/_mio5.py +19 -13
  179. scipy/io/matlab/_mio5_utils.cpython-313t-darwin.so +0 -0
  180. scipy/io/matlab/_mio_utils.cpython-313t-darwin.so +0 -0
  181. scipy/io/matlab/_miobase.py +4 -1
  182. scipy/io/matlab/_streams.cpython-313t-darwin.so +0 -0
  183. scipy/io/matlab/tests/test_mio.py +46 -18
  184. scipy/io/matlab/tests/test_mio_funcs.py +1 -1
  185. scipy/io/tests/test_mmio.py +7 -1
  186. scipy/io/tests/test_wavfile.py +41 -0
  187. scipy/io/wavfile.py +57 -10
  188. scipy/linalg/_basic.py +113 -86
  189. scipy/linalg/_cythonized_array_utils.cpython-313t-darwin.so +0 -0
  190. scipy/linalg/_decomp.py +22 -9
  191. scipy/linalg/_decomp_cholesky.py +28 -13
  192. scipy/linalg/_decomp_cossin.py +45 -30
  193. scipy/linalg/_decomp_interpolative.cpython-313t-darwin.so +0 -0
  194. scipy/linalg/_decomp_ldl.py +4 -1
  195. scipy/linalg/_decomp_lu.py +18 -6
  196. scipy/linalg/_decomp_lu_cython.cpython-313t-darwin.so +0 -0
  197. scipy/linalg/_decomp_polar.py +2 -0
  198. scipy/linalg/_decomp_qr.py +6 -2
  199. scipy/linalg/_decomp_qz.py +3 -0
  200. scipy/linalg/_decomp_schur.py +3 -1
  201. scipy/linalg/_decomp_svd.py +13 -2
  202. scipy/linalg/_decomp_update.cpython-313t-darwin.so +0 -0
  203. scipy/linalg/_expm_frechet.py +4 -0
  204. scipy/linalg/_fblas.cpython-313t-darwin.so +0 -0
  205. scipy/linalg/_flapack.cpython-313t-darwin.so +0 -0
  206. scipy/linalg/_linalg_pythran.cpython-313t-darwin.so +0 -0
  207. scipy/linalg/_matfuncs.py +187 -4
  208. scipy/linalg/_matfuncs_expm.cpython-313t-darwin.so +0 -0
  209. scipy/linalg/_matfuncs_schur_sqrtm.cpython-313t-darwin.so +0 -0
  210. scipy/linalg/_matfuncs_sqrtm.py +1 -99
  211. scipy/linalg/_matfuncs_sqrtm_triu.cpython-313t-darwin.so +0 -0
  212. scipy/linalg/_procrustes.py +2 -0
  213. scipy/linalg/_sketches.py +17 -6
  214. scipy/linalg/_solve_toeplitz.cpython-313t-darwin.so +0 -0
  215. scipy/linalg/_solvers.py +7 -2
  216. scipy/linalg/_special_matrices.py +26 -36
  217. scipy/linalg/cython_blas.cpython-313t-darwin.so +0 -0
  218. scipy/linalg/cython_lapack.cpython-313t-darwin.so +0 -0
  219. scipy/linalg/lapack.py +22 -2
  220. scipy/linalg/tests/_cython_examples/meson.build +7 -0
  221. scipy/linalg/tests/test_basic.py +31 -16
  222. scipy/linalg/tests/test_batch.py +588 -0
  223. scipy/linalg/tests/test_cythonized_array_utils.py +0 -2
  224. scipy/linalg/tests/test_decomp.py +40 -3
  225. scipy/linalg/tests/test_decomp_cossin.py +14 -0
  226. scipy/linalg/tests/test_decomp_ldl.py +1 -1
  227. scipy/linalg/tests/test_lapack.py +115 -7
  228. scipy/linalg/tests/test_matfuncs.py +157 -102
  229. scipy/linalg/tests/test_procrustes.py +0 -7
  230. scipy/linalg/tests/test_solve_toeplitz.py +1 -1
  231. scipy/linalg/tests/test_special_matrices.py +1 -5
  232. scipy/ndimage/__init__.py +1 -0
  233. scipy/ndimage/_cytest.cpython-313t-darwin.so +0 -0
  234. scipy/ndimage/_delegators.py +8 -2
  235. scipy/ndimage/_filters.py +453 -5
  236. scipy/ndimage/_interpolation.py +36 -6
  237. scipy/ndimage/_measurements.py +4 -2
  238. scipy/ndimage/_morphology.py +5 -0
  239. scipy/ndimage/_nd_image.cpython-313t-darwin.so +0 -0
  240. scipy/ndimage/_ni_docstrings.py +5 -1
  241. scipy/ndimage/_ni_label.cpython-313t-darwin.so +0 -0
  242. scipy/ndimage/_ni_support.py +1 -5
  243. scipy/ndimage/_rank_filter_1d.cpython-313t-darwin.so +0 -0
  244. scipy/ndimage/_support_alternative_backends.py +18 -6
  245. scipy/ndimage/tests/test_filters.py +370 -259
  246. scipy/ndimage/tests/test_fourier.py +7 -9
  247. scipy/ndimage/tests/test_interpolation.py +68 -61
  248. scipy/ndimage/tests/test_measurements.py +18 -35
  249. scipy/ndimage/tests/test_morphology.py +143 -131
  250. scipy/ndimage/tests/test_splines.py +1 -3
  251. scipy/odr/__odrpack.cpython-313t-darwin.so +0 -0
  252. scipy/optimize/_basinhopping.py +13 -7
  253. scipy/optimize/_bglu_dense.cpython-313t-darwin.so +0 -0
  254. scipy/optimize/_bracket.py +17 -24
  255. scipy/optimize/_chandrupatla.py +9 -10
  256. scipy/optimize/_cobyla_py.py +104 -123
  257. scipy/optimize/_constraints.py +14 -10
  258. scipy/optimize/_differentiable_functions.py +371 -230
  259. scipy/optimize/_differentialevolution.py +4 -3
  260. scipy/optimize/_direct.cpython-313t-darwin.so +0 -0
  261. scipy/optimize/_dual_annealing.py +1 -1
  262. scipy/optimize/_elementwise.py +1 -4
  263. scipy/optimize/_group_columns.cpython-313t-darwin.so +0 -0
  264. scipy/optimize/_lbfgsb.cpython-313t-darwin.so +0 -0
  265. scipy/optimize/_lbfgsb_py.py +57 -16
  266. scipy/optimize/_linprog_doc.py +2 -2
  267. scipy/optimize/_linprog_highs.py +2 -2
  268. scipy/optimize/_linprog_ip.py +25 -10
  269. scipy/optimize/_linprog_util.py +14 -16
  270. scipy/optimize/_lsap.cpython-313t-darwin.so +0 -0
  271. scipy/optimize/_lsq/common.py +3 -3
  272. scipy/optimize/_lsq/dogbox.py +16 -2
  273. scipy/optimize/_lsq/givens_elimination.cpython-313t-darwin.so +0 -0
  274. scipy/optimize/_lsq/least_squares.py +198 -126
  275. scipy/optimize/_lsq/lsq_linear.py +6 -6
  276. scipy/optimize/_lsq/trf.py +35 -8
  277. scipy/optimize/_milp.py +3 -1
  278. scipy/optimize/_minimize.py +105 -36
  279. scipy/optimize/_minpack.cpython-313t-darwin.so +0 -0
  280. scipy/optimize/_minpack_py.py +21 -14
  281. scipy/optimize/_moduleTNC.cpython-313t-darwin.so +0 -0
  282. scipy/optimize/_nnls.py +20 -21
  283. scipy/optimize/_nonlin.py +34 -3
  284. scipy/optimize/_numdiff.py +288 -110
  285. scipy/optimize/_optimize.py +86 -48
  286. scipy/optimize/_pava_pybind.cpython-313t-darwin.so +0 -0
  287. scipy/optimize/_remove_redundancy.py +5 -5
  288. scipy/optimize/_root_scalar.py +1 -1
  289. scipy/optimize/_shgo.py +6 -0
  290. scipy/optimize/_shgo_lib/_complex.py +1 -1
  291. scipy/optimize/_slsqp_py.py +216 -124
  292. scipy/optimize/_slsqplib.cpython-313t-darwin.so +0 -0
  293. scipy/optimize/_spectral.py +1 -1
  294. scipy/optimize/_tnc.py +8 -1
  295. scipy/optimize/_trlib/_trlib.cpython-313t-darwin.so +0 -0
  296. scipy/optimize/_trustregion.py +20 -6
  297. scipy/optimize/_trustregion_constr/canonical_constraint.py +7 -7
  298. scipy/optimize/_trustregion_constr/equality_constrained_sqp.py +1 -1
  299. scipy/optimize/_trustregion_constr/minimize_trustregion_constr.py +11 -3
  300. scipy/optimize/_trustregion_constr/projections.py +12 -8
  301. scipy/optimize/_trustregion_constr/qp_subproblem.py +9 -9
  302. scipy/optimize/_trustregion_constr/tests/test_projections.py +7 -7
  303. scipy/optimize/_trustregion_constr/tests/test_qp_subproblem.py +77 -77
  304. scipy/optimize/_trustregion_constr/tr_interior_point.py +5 -5
  305. scipy/optimize/_trustregion_exact.py +0 -1
  306. scipy/optimize/_zeros.cpython-313t-darwin.so +0 -0
  307. scipy/optimize/_zeros_py.py +97 -17
  308. scipy/optimize/cython_optimize/_zeros.cpython-313t-darwin.so +0 -0
  309. scipy/optimize/slsqp.py +0 -1
  310. scipy/optimize/tests/test__basinhopping.py +1 -1
  311. scipy/optimize/tests/test__differential_evolution.py +4 -4
  312. scipy/optimize/tests/test__linprog_clean_inputs.py +5 -3
  313. scipy/optimize/tests/test__numdiff.py +66 -22
  314. scipy/optimize/tests/test__remove_redundancy.py +2 -2
  315. scipy/optimize/tests/test__shgo.py +9 -1
  316. scipy/optimize/tests/test_bracket.py +36 -46
  317. scipy/optimize/tests/test_chandrupatla.py +133 -135
  318. scipy/optimize/tests/test_cobyla.py +74 -45
  319. scipy/optimize/tests/test_constraints.py +1 -1
  320. scipy/optimize/tests/test_differentiable_functions.py +226 -6
  321. scipy/optimize/tests/test_lbfgsb_hessinv.py +22 -0
  322. scipy/optimize/tests/test_least_squares.py +125 -13
  323. scipy/optimize/tests/test_linear_assignment.py +3 -3
  324. scipy/optimize/tests/test_linprog.py +3 -3
  325. scipy/optimize/tests/test_lsq_linear.py +6 -6
  326. scipy/optimize/tests/test_minimize_constrained.py +2 -2
  327. scipy/optimize/tests/test_minpack.py +4 -4
  328. scipy/optimize/tests/test_nnls.py +43 -3
  329. scipy/optimize/tests/test_nonlin.py +36 -0
  330. scipy/optimize/tests/test_optimize.py +95 -17
  331. scipy/optimize/tests/test_slsqp.py +36 -4
  332. scipy/optimize/tests/test_zeros.py +34 -1
  333. scipy/signal/__init__.py +12 -23
  334. scipy/signal/_delegators.py +568 -0
  335. scipy/signal/_filter_design.py +459 -241
  336. scipy/signal/_fir_filter_design.py +262 -90
  337. scipy/signal/_lti_conversion.py +3 -2
  338. scipy/signal/_ltisys.py +118 -91
  339. scipy/signal/_max_len_seq_inner.cpython-313t-darwin.so +0 -0
  340. scipy/signal/_peak_finding_utils.cpython-313t-darwin.so +0 -0
  341. scipy/signal/_polyutils.py +172 -0
  342. scipy/signal/_short_time_fft.py +519 -70
  343. scipy/signal/_signal_api.py +30 -0
  344. scipy/signal/_signaltools.py +719 -399
  345. scipy/signal/_sigtools.cpython-313t-darwin.so +0 -0
  346. scipy/signal/_sosfilt.cpython-313t-darwin.so +0 -0
  347. scipy/signal/_spectral_py.py +230 -50
  348. scipy/signal/_spline.cpython-313t-darwin.so +0 -0
  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-313t-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 +2 -171
  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 +221 -3
  364. scipy/signal/tests/test_signaltools.py +2144 -1348
  365. scipy/signal/tests/test_spectral.py +50 -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 +270 -108
  373. scipy/sparse/_bsr.py +7 -4
  374. scipy/sparse/_compressed.py +59 -231
  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-313t-darwin.so +0 -0
  379. scipy/sparse/_csr.py +2 -2
  380. scipy/sparse/_data.py +48 -48
  381. scipy/sparse/_dia.py +105 -18
  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-313t-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-313t-darwin.so +0 -0
  394. scipy/sparse/csgraph/_matching.cpython-313t-darwin.so +0 -0
  395. scipy/sparse/csgraph/_min_spanning_tree.cpython-313t-darwin.so +0 -0
  396. scipy/sparse/csgraph/_reordering.cpython-313t-darwin.so +0 -0
  397. scipy/sparse/csgraph/_shortest_path.cpython-313t-darwin.so +0 -0
  398. scipy/sparse/csgraph/_tools.cpython-313t-darwin.so +0 -0
  399. scipy/sparse/csgraph/_traversal.cpython-313t-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-313t-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-313t-darwin.so +0 -0
  411. scipy/sparse/linalg/_eigen/arpack/arpack.py +23 -17
  412. scipy/sparse/linalg/_eigen/lobpcg/lobpcg.py +6 -6
  413. scipy/sparse/linalg/_interface.py +17 -18
  414. scipy/sparse/linalg/_isolve/_gcrotmk.py +4 -4
  415. scipy/sparse/linalg/_isolve/iterative.py +51 -45
  416. scipy/sparse/linalg/_isolve/lgmres.py +6 -6
  417. scipy/sparse/linalg/_isolve/minres.py +5 -5
  418. scipy/sparse/linalg/_isolve/tfqmr.py +7 -7
  419. scipy/sparse/linalg/_isolve/utils.py +2 -8
  420. scipy/sparse/linalg/_matfuncs.py +1 -1
  421. scipy/sparse/linalg/_norm.py +1 -1
  422. scipy/sparse/linalg/_propack/_cpropack.cpython-313t-darwin.so +0 -0
  423. scipy/sparse/linalg/_propack/_dpropack.cpython-313t-darwin.so +0 -0
  424. scipy/sparse/linalg/_propack/_spropack.cpython-313t-darwin.so +0 -0
  425. scipy/sparse/linalg/_propack/_zpropack.cpython-313t-darwin.so +0 -0
  426. scipy/sparse/linalg/_special_sparse_arrays.py +39 -38
  427. scipy/sparse/linalg/tests/test_pydata_sparse.py +14 -0
  428. scipy/sparse/tests/test_arithmetic1d.py +5 -2
  429. scipy/sparse/tests/test_base.py +214 -42
  430. scipy/sparse/tests/test_common1d.py +7 -7
  431. scipy/sparse/tests/test_construct.py +1 -1
  432. scipy/sparse/tests/test_coo.py +272 -4
  433. scipy/sparse/tests/test_sparsetools.py +5 -0
  434. scipy/sparse/tests/test_sputils.py +36 -7
  435. scipy/spatial/_ckdtree.cpython-313t-darwin.so +0 -0
  436. scipy/spatial/_distance_pybind.cpython-313t-darwin.so +0 -0
  437. scipy/spatial/_distance_wrap.cpython-313t-darwin.so +0 -0
  438. scipy/spatial/_hausdorff.cpython-313t-darwin.so +0 -0
  439. scipy/spatial/_qhull.cpython-313t-darwin.so +0 -0
  440. scipy/spatial/_voronoi.cpython-313t-darwin.so +0 -0
  441. scipy/spatial/distance.py +49 -42
  442. scipy/spatial/tests/test_distance.py +15 -1
  443. scipy/spatial/tests/test_kdtree.py +1 -0
  444. scipy/spatial/tests/test_qhull.py +7 -2
  445. scipy/spatial/transform/__init__.py +5 -3
  446. scipy/spatial/transform/_rigid_transform.cpython-313t-darwin.so +0 -0
  447. scipy/spatial/transform/_rotation.cpython-313t-darwin.so +0 -0
  448. scipy/spatial/transform/tests/test_rigid_transform.py +1221 -0
  449. scipy/spatial/transform/tests/test_rotation.py +1213 -832
  450. scipy/spatial/transform/tests/test_rotation_groups.py +3 -3
  451. scipy/spatial/transform/tests/test_rotation_spline.py +29 -8
  452. scipy/special/__init__.py +1 -47
  453. scipy/special/_add_newdocs.py +34 -772
  454. scipy/special/_basic.py +22 -25
  455. scipy/special/_comb.cpython-313t-darwin.so +0 -0
  456. scipy/special/_ellip_harm_2.cpython-313t-darwin.so +0 -0
  457. scipy/special/_gufuncs.cpython-313t-darwin.so +0 -0
  458. scipy/special/_logsumexp.py +67 -58
  459. scipy/special/_orthogonal.pyi +1 -1
  460. scipy/special/_specfun.cpython-313t-darwin.so +0 -0
  461. scipy/special/_special_ufuncs.cpython-313t-darwin.so +0 -0
  462. scipy/special/_spherical_bessel.py +4 -4
  463. scipy/special/_support_alternative_backends.py +212 -119
  464. scipy/special/_test_internal.cpython-313t-darwin.so +0 -0
  465. scipy/special/_testutils.py +4 -4
  466. scipy/special/_ufuncs.cpython-313t-darwin.so +0 -0
  467. scipy/special/_ufuncs.pyi +1 -0
  468. scipy/special/_ufuncs.pyx +215 -1400
  469. scipy/special/_ufuncs_cxx.cpython-313t-darwin.so +0 -0
  470. scipy/special/_ufuncs_cxx.pxd +2 -15
  471. scipy/special/_ufuncs_cxx.pyx +5 -44
  472. scipy/special/_ufuncs_cxx_defs.h +2 -16
  473. scipy/special/_ufuncs_defs.h +0 -8
  474. scipy/special/cython_special.cpython-313t-darwin.so +0 -0
  475. scipy/special/cython_special.pxd +1 -1
  476. scipy/special/tests/_cython_examples/meson.build +10 -1
  477. scipy/special/tests/test_basic.py +153 -20
  478. scipy/special/tests/test_boost_ufuncs.py +3 -0
  479. scipy/special/tests/test_cdflib.py +35 -11
  480. scipy/special/tests/test_gammainc.py +16 -0
  481. scipy/special/tests/test_hyp2f1.py +2 -2
  482. scipy/special/tests/test_log1mexp.py +85 -0
  483. scipy/special/tests/test_logsumexp.py +206 -64
  484. scipy/special/tests/test_mpmath.py +1 -0
  485. scipy/special/tests/test_nan_inputs.py +1 -1
  486. scipy/special/tests/test_orthogonal.py +17 -18
  487. scipy/special/tests/test_sf_error.py +3 -2
  488. scipy/special/tests/test_sph_harm.py +6 -7
  489. scipy/special/tests/test_support_alternative_backends.py +211 -76
  490. scipy/stats/__init__.py +4 -1
  491. scipy/stats/_ansari_swilk_statistics.cpython-313t-darwin.so +0 -0
  492. scipy/stats/_axis_nan_policy.py +5 -12
  493. scipy/stats/_biasedurn.cpython-313t-darwin.so +0 -0
  494. scipy/stats/_continued_fraction.py +387 -0
  495. scipy/stats/_continuous_distns.py +277 -310
  496. scipy/stats/_correlation.py +1 -1
  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 +9 -10
  502. scipy/{_lib → stats}/_finite_differences.py +1 -1
  503. scipy/stats/_hypotests.py +83 -50
  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-313t-darwin.so +0 -0
  508. scipy/stats/_morestats.py +118 -73
  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-313t-darwin.so +0 -0
  517. scipy/stats/_qmvnt.py +16 -95
  518. scipy/stats/_qmvnt_cy.cpython-313t-darwin.so +0 -0
  519. scipy/stats/_quantile.py +335 -0
  520. scipy/stats/_rcont/rcont.cpython-313t-darwin.so +0 -0
  521. scipy/stats/_resampling.py +4 -29
  522. scipy/stats/_sampling.py +1 -1
  523. scipy/stats/_sobol.cpython-313t-darwin.so +0 -0
  524. scipy/stats/_stats.cpython-313t-darwin.so +0 -0
  525. scipy/stats/_stats_mstats_common.py +21 -2
  526. scipy/stats/_stats_py.py +550 -476
  527. scipy/stats/_stats_pythran.cpython-313t-darwin.so +0 -0
  528. scipy/stats/_unuran/unuran_wrapper.cpython-313t-darwin.so +0 -0
  529. scipy/stats/_unuran/unuran_wrapper.pyi +2 -1
  530. scipy/stats/_variation.py +6 -8
  531. scipy/stats/_wilcoxon.py +13 -7
  532. scipy/stats/tests/common_tests.py +6 -4
  533. scipy/stats/tests/test_axis_nan_policy.py +62 -24
  534. scipy/stats/tests/test_continued_fraction.py +173 -0
  535. scipy/stats/tests/test_continuous.py +379 -60
  536. scipy/stats/tests/test_continuous_basic.py +18 -12
  537. scipy/stats/tests/test_discrete_basic.py +14 -8
  538. scipy/stats/tests/test_discrete_distns.py +16 -16
  539. scipy/stats/tests/test_distributions.py +95 -75
  540. scipy/stats/tests/test_entropy.py +40 -48
  541. scipy/stats/tests/test_fit.py +4 -3
  542. scipy/stats/tests/test_hypotests.py +153 -24
  543. scipy/stats/tests/test_kdeoth.py +109 -41
  544. scipy/stats/tests/test_marray.py +289 -0
  545. scipy/stats/tests/test_morestats.py +79 -47
  546. scipy/stats/tests/test_mstats_basic.py +3 -3
  547. scipy/stats/tests/test_multivariate.py +434 -83
  548. scipy/stats/tests/test_qmc.py +13 -10
  549. scipy/stats/tests/test_quantile.py +199 -0
  550. scipy/stats/tests/test_rank.py +119 -112
  551. scipy/stats/tests/test_resampling.py +47 -56
  552. scipy/stats/tests/test_sampling.py +9 -4
  553. scipy/stats/tests/test_stats.py +799 -939
  554. scipy/stats/tests/test_variation.py +8 -6
  555. scipy/version.py +2 -2
  556. {scipy-1.15.3.dist-info → scipy-1.16.0rc2.dist-info}/LICENSE.txt +4 -4
  557. {scipy-1.15.3.dist-info → scipy-1.16.0rc2.dist-info}/METADATA +11 -11
  558. {scipy-1.15.3.dist-info → scipy-1.16.0rc2.dist-info}/RECORD +559 -566
  559. scipy-1.16.0rc2.dist-info/WHEEL +6 -0
  560. scipy/_lib/array_api_extra/_funcs.py +0 -484
  561. scipy/_lib/array_api_extra/_typing.py +0 -8
  562. scipy/interpolate/_bspl.cpython-313t-darwin.so +0 -0
  563. scipy/optimize/_cobyla.cpython-313t-darwin.so +0 -0
  564. scipy/optimize/_cython_nnls.cpython-313t-darwin.so +0 -0
  565. scipy/optimize/_slsqp.cpython-313t-darwin.so +0 -0
  566. scipy/spatial/qhull_src/COPYING.txt +0 -38
  567. scipy/special/libsf_error_state.dylib +0 -0
  568. scipy/special/tests/test_log_softmax.py +0 -109
  569. scipy/special/tests/test_xsf_cuda.py +0 -114
  570. scipy/special/xsf/binom.h +0 -89
  571. scipy/special/xsf/cdflib.h +0 -100
  572. scipy/special/xsf/cephes/airy.h +0 -307
  573. scipy/special/xsf/cephes/besselpoly.h +0 -51
  574. scipy/special/xsf/cephes/beta.h +0 -257
  575. scipy/special/xsf/cephes/cbrt.h +0 -131
  576. scipy/special/xsf/cephes/chbevl.h +0 -85
  577. scipy/special/xsf/cephes/chdtr.h +0 -193
  578. scipy/special/xsf/cephes/const.h +0 -87
  579. scipy/special/xsf/cephes/ellie.h +0 -293
  580. scipy/special/xsf/cephes/ellik.h +0 -251
  581. scipy/special/xsf/cephes/ellpe.h +0 -107
  582. scipy/special/xsf/cephes/ellpk.h +0 -117
  583. scipy/special/xsf/cephes/expn.h +0 -260
  584. scipy/special/xsf/cephes/gamma.h +0 -398
  585. scipy/special/xsf/cephes/hyp2f1.h +0 -596
  586. scipy/special/xsf/cephes/hyperg.h +0 -361
  587. scipy/special/xsf/cephes/i0.h +0 -149
  588. scipy/special/xsf/cephes/i1.h +0 -158
  589. scipy/special/xsf/cephes/igam.h +0 -421
  590. scipy/special/xsf/cephes/igam_asymp_coeff.h +0 -195
  591. scipy/special/xsf/cephes/igami.h +0 -313
  592. scipy/special/xsf/cephes/j0.h +0 -225
  593. scipy/special/xsf/cephes/j1.h +0 -198
  594. scipy/special/xsf/cephes/jv.h +0 -715
  595. scipy/special/xsf/cephes/k0.h +0 -164
  596. scipy/special/xsf/cephes/k1.h +0 -163
  597. scipy/special/xsf/cephes/kn.h +0 -243
  598. scipy/special/xsf/cephes/lanczos.h +0 -112
  599. scipy/special/xsf/cephes/ndtr.h +0 -275
  600. scipy/special/xsf/cephes/poch.h +0 -85
  601. scipy/special/xsf/cephes/polevl.h +0 -167
  602. scipy/special/xsf/cephes/psi.h +0 -194
  603. scipy/special/xsf/cephes/rgamma.h +0 -111
  604. scipy/special/xsf/cephes/scipy_iv.h +0 -811
  605. scipy/special/xsf/cephes/shichi.h +0 -248
  606. scipy/special/xsf/cephes/sici.h +0 -224
  607. scipy/special/xsf/cephes/sindg.h +0 -221
  608. scipy/special/xsf/cephes/tandg.h +0 -139
  609. scipy/special/xsf/cephes/trig.h +0 -58
  610. scipy/special/xsf/cephes/unity.h +0 -186
  611. scipy/special/xsf/cephes/zeta.h +0 -172
  612. scipy/special/xsf/config.h +0 -304
  613. scipy/special/xsf/digamma.h +0 -205
  614. scipy/special/xsf/error.h +0 -57
  615. scipy/special/xsf/evalpoly.h +0 -47
  616. scipy/special/xsf/expint.h +0 -266
  617. scipy/special/xsf/hyp2f1.h +0 -694
  618. scipy/special/xsf/iv_ratio.h +0 -173
  619. scipy/special/xsf/lambertw.h +0 -150
  620. scipy/special/xsf/loggamma.h +0 -163
  621. scipy/special/xsf/sici.h +0 -200
  622. scipy/special/xsf/tools.h +0 -427
  623. scipy/special/xsf/trig.h +0 -164
  624. scipy/special/xsf/wright_bessel.h +0 -843
  625. scipy/special/xsf/zlog1.h +0 -35
  626. scipy/stats/_mvn.cpython-313t-darwin.so +0 -0
  627. scipy-1.15.3.dist-info/WHEEL +0 -4
@@ -1,10 +1,14 @@
1
1
  """The suite of window functions."""
2
2
 
3
+ import math
3
4
  import operator
4
5
  import warnings
6
+ from scipy._lib import doccer
5
7
 
6
- import numpy as np
7
8
  from scipy import linalg, special, fft as sp_fft
9
+ from scipy._lib.array_api_compat import numpy as np_compat
10
+ from scipy._lib._array_api import array_namespace, xp_device
11
+ from scipy._lib import array_api_extra as xpx
8
12
 
9
13
  __all__ = ['boxcar', 'triang', 'parzen', 'bohman', 'blackman', 'nuttall',
10
14
  'blackmanharris', 'flattop', 'bartlett', 'barthann',
@@ -37,6 +41,28 @@ def _truncate(w, needed):
37
41
  return w
38
42
 
39
43
 
44
+ def _namespace(xp):
45
+ """A shim for the `device` arg of `np.asarray(x, device=device)` and acos/arccos.
46
+
47
+ Will be able to replace with `np_compat if xp is None else xp` when we drop
48
+ support for numpy 1.x and cupy 13.x
49
+ """
50
+ return np_compat if xp is None else array_namespace(xp.empty(0))
51
+
52
+
53
+ def _general_cosine_impl(M, a, xp, device, sym=True):
54
+ if _len_guards(M):
55
+ return xp.ones(M, dtype=xp.float64, device=device)
56
+ M, needs_trunc = _extend(M, sym)
57
+
58
+ fac = xp.linspace(-xp.pi, xp.pi, M, dtype=xp.float64, device=device)
59
+ w = xp.zeros(M, dtype=xp.float64, device=device)
60
+ for k in range(a.shape[0]):
61
+ w += a[k] * xp.cos(k * fac)
62
+
63
+ return _truncate(w, needs_trunc)
64
+
65
+
40
66
  def general_cosine(M, a, sym=True):
41
67
  r"""
42
68
  Generic weighted sum of cosine terms window
@@ -113,19 +139,13 @@ def general_cosine(M, a, sym=True):
113
139
  >>> plt.axhline(-90.2, color='red')
114
140
  >>> plt.show()
115
141
  """
116
- if _len_guards(M):
117
- return np.ones(M)
118
- M, needs_trunc = _extend(M, sym)
119
-
120
- fac = np.linspace(-np.pi, np.pi, M)
121
- w = np.zeros(M)
122
- for k in range(len(a)):
123
- w += a[k] * np.cos(k * fac)
124
-
125
- return _truncate(w, needs_trunc)
142
+ xp = array_namespace(a)
143
+ a = xp.asarray(a)
144
+ device = xp_device(a)
145
+ return _general_cosine_impl(M, a, xp, device, sym=sym)
126
146
 
127
147
 
128
- def boxcar(M, sym=True):
148
+ def boxcar(M, sym=True, *, xp=None, device=None):
129
149
  """Return a boxcar or rectangular window.
130
150
 
131
151
  Also known as a rectangular window or Dirichlet window, this is equivalent
@@ -138,6 +158,7 @@ def boxcar(M, sym=True):
138
158
  is returned. An exception is thrown when it is negative.
139
159
  sym : bool, optional
140
160
  Whether the window is symmetric. (Has no effect for boxcar.)
161
+ %(xp_device_snippet)s
141
162
 
142
163
  Returns
143
164
  -------
@@ -170,16 +191,18 @@ def boxcar(M, sym=True):
170
191
  >>> plt.xlabel("Normalized frequency [cycles per sample]")
171
192
 
172
193
  """
194
+ xp = _namespace(xp)
195
+
173
196
  if _len_guards(M):
174
- return np.ones(M)
197
+ return xp.ones(M, dtype=xp.float64, device=device)
175
198
  M, needs_trunc = _extend(M, sym)
176
199
 
177
- w = np.ones(M, float)
200
+ w = xp.ones(M, dtype=xp.float64, device=device)
178
201
 
179
202
  return _truncate(w, needs_trunc)
180
203
 
181
204
 
182
- def triang(M, sym=True):
205
+ def triang(M, sym=True, *, xp=None, device=None):
183
206
  """Return a triangular window.
184
207
 
185
208
  Parameters
@@ -191,6 +214,7 @@ def triang(M, sym=True):
191
214
  When True (default), generates a symmetric window, for use in filter
192
215
  design.
193
216
  When False, generates a periodic window, for use in spectral analysis.
217
+ %(xp_device_snippet)s
194
218
 
195
219
  Returns
196
220
  -------
@@ -229,22 +253,24 @@ def triang(M, sym=True):
229
253
  >>> plt.xlabel("Normalized frequency [cycles per sample]")
230
254
 
231
255
  """
256
+ xp = _namespace(xp)
257
+
232
258
  if _len_guards(M):
233
- return np.ones(M)
259
+ return xp.ones(M, dtype=xp.float64, device=device)
234
260
  M, needs_trunc = _extend(M, sym)
235
261
 
236
- n = np.arange(1, (M + 1) // 2 + 1)
262
+ n = xp.arange(1, (M + 1) // 2 + 1, dtype=xp.float64, device=device)
237
263
  if M % 2 == 0:
238
264
  w = (2 * n - 1.0) / M
239
- w = np.r_[w, w[::-1]]
265
+ w = xp.concat([w, xp.flip(w)])
240
266
  else:
241
267
  w = 2 * n / (M + 1.0)
242
- w = np.r_[w, w[-2::-1]]
268
+ w = xp.concat([w, xp.flip(w[:-1])])
243
269
 
244
270
  return _truncate(w, needs_trunc)
245
271
 
246
272
 
247
- def parzen(M, sym=True):
273
+ def parzen(M, sym=True, *, xp=None, device=None):
248
274
  """Return a Parzen window.
249
275
 
250
276
  Parameters
@@ -256,6 +282,7 @@ def parzen(M, sym=True):
256
282
  When True (default), generates a symmetric window, for use in filter
257
283
  design.
258
284
  When False, generates a periodic window, for use in spectral analysis.
285
+ %(xp_device_snippet)s
259
286
 
260
287
  Returns
261
288
  -------
@@ -294,22 +321,22 @@ def parzen(M, sym=True):
294
321
  >>> plt.xlabel("Normalized frequency [cycles per sample]")
295
322
 
296
323
  """
324
+ xp = _namespace(xp)
325
+
297
326
  if _len_guards(M):
298
- return np.ones(M)
327
+ return xp.ones(M, dtype=xp.float64, device=device)
299
328
  M, needs_trunc = _extend(M, sym)
300
329
 
301
- n = np.arange(-(M - 1) / 2.0, (M - 1) / 2.0 + 0.5, 1.0)
302
- na = np.extract(n < -(M - 1) / 4.0, n)
303
- nb = np.extract(abs(n) <= (M - 1) / 4.0, n)
304
- wa = 2 * (1 - np.abs(na) / (M / 2.0)) ** 3.0
305
- wb = (1 - 6 * (np.abs(nb) / (M / 2.0)) ** 2.0 +
306
- 6 * (np.abs(nb) / (M / 2.0)) ** 3.0)
307
- w = np.r_[wa, wb, wa[::-1]]
308
-
330
+ n = xp.arange(-(M - 1) / 2.0, (M - 1) / 2.0 + 0.5, 1.0,
331
+ dtype=xp.float64, device=device)
332
+ w = xp.where(abs(n) <= (M - 1) / 4.0,
333
+ (1 - 6 * (abs(n) / (M / 2.0)) ** 2.0 +
334
+ 6 * (abs(n) / (M / 2.0)) ** 3.0),
335
+ 2 * (1 - abs(n) / (M / 2.0)) ** 3.0)
309
336
  return _truncate(w, needs_trunc)
310
337
 
311
338
 
312
- def bohman(M, sym=True):
339
+ def bohman(M, sym=True, *, xp=None, device=None):
313
340
  """Return a Bohman window.
314
341
 
315
342
  Parameters
@@ -321,6 +348,7 @@ def bohman(M, sym=True):
321
348
  When True (default), generates a symmetric window, for use in filter
322
349
  design.
323
350
  When False, generates a periodic window, for use in spectral analysis.
351
+ %(xp_device_snippet)s
324
352
 
325
353
  Returns
326
354
  -------
@@ -354,18 +382,21 @@ def bohman(M, sym=True):
354
382
  >>> plt.xlabel("Normalized frequency [cycles per sample]")
355
383
 
356
384
  """
385
+ xp = _namespace(xp)
386
+
357
387
  if _len_guards(M):
358
- return np.ones(M)
388
+ return xp.ones(M, dtype=xp.float64, device=device)
359
389
  M, needs_trunc = _extend(M, sym)
360
390
 
361
- fac = np.abs(np.linspace(-1, 1, M)[1:-1])
362
- w = (1 - fac) * np.cos(np.pi * fac) + 1.0 / np.pi * np.sin(np.pi * fac)
363
- w = np.r_[0, w, 0]
391
+ fac = abs(xp.linspace(-1, 1, M, dtype=xp.float64, device=device)[1:-1])
392
+ w = (1 - fac) * xp.cos(xp.pi * fac) + 1.0 / xp.pi * xp.sin(xp.pi * fac)
393
+ one = xp.zeros(1, dtype=xp.float64, device=device)
394
+ w = xp.concat([one, w, one])
364
395
 
365
396
  return _truncate(w, needs_trunc)
366
397
 
367
398
 
368
- def blackman(M, sym=True):
399
+ def blackman(M, sym=True, *, xp=None, device=None):
369
400
  r"""
370
401
  Return a Blackman window.
371
402
 
@@ -383,6 +414,7 @@ def blackman(M, sym=True):
383
414
  When True (default), generates a symmetric window, for use in filter
384
415
  design.
385
416
  When False, generates a periodic window, for use in spectral analysis.
417
+ %(xp_device_snippet)s
386
418
 
387
419
  Returns
388
420
  -------
@@ -448,10 +480,13 @@ def blackman(M, sym=True):
448
480
 
449
481
  """
450
482
  # Docstring adapted from NumPy's blackman function
451
- return general_cosine(M, [0.42, 0.50, 0.08], sym)
483
+ xp = _namespace(xp)
484
+ a = xp.asarray([0.42, 0.50, 0.08], dtype=xp.float64, device=device)
485
+ device = xp_device(a)
486
+ return _general_cosine_impl(M, a, xp, device, sym=sym)
452
487
 
453
488
 
454
- def nuttall(M, sym=True):
489
+ def nuttall(M, sym=True, *, xp=None, device=None):
455
490
  """Return a minimum 4-term Blackman-Harris window according to Nuttall.
456
491
 
457
492
  This variation is called "Nuttall4c" by Heinzel. [2]_
@@ -465,6 +500,7 @@ def nuttall(M, sym=True):
465
500
  When True (default), generates a symmetric window, for use in filter
466
501
  design.
467
502
  When False, generates a periodic window, for use in spectral analysis.
503
+ %(xp_device_snippet)s
468
504
 
469
505
  Returns
470
506
  -------
@@ -508,10 +544,15 @@ def nuttall(M, sym=True):
508
544
  >>> plt.xlabel("Normalized frequency [cycles per sample]")
509
545
 
510
546
  """
511
- return general_cosine(M, [0.3635819, 0.4891775, 0.1365995, 0.0106411], sym)
547
+ xp = _namespace(xp)
548
+ a = xp.asarray(
549
+ [0.3635819, 0.4891775, 0.1365995, 0.0106411], dtype=xp.float64, device=device
550
+ )
551
+ device = xp_device(a)
552
+ return _general_cosine_impl(M, a, xp, device, sym=sym)
512
553
 
513
554
 
514
- def blackmanharris(M, sym=True):
555
+ def blackmanharris(M, sym=True, *, xp=None, device=None):
515
556
  """Return a minimum 4-term Blackman-Harris window.
516
557
 
517
558
  Parameters
@@ -523,6 +564,7 @@ def blackmanharris(M, sym=True):
523
564
  When True (default), generates a symmetric window, for use in filter
524
565
  design.
525
566
  When False, generates a periodic window, for use in spectral analysis.
567
+ %(xp_device_snippet)s
526
568
 
527
569
  Returns
528
570
  -------
@@ -556,10 +598,15 @@ def blackmanharris(M, sym=True):
556
598
  >>> plt.xlabel("Normalized frequency [cycles per sample]")
557
599
 
558
600
  """
559
- return general_cosine(M, [0.35875, 0.48829, 0.14128, 0.01168], sym)
601
+ xp = _namespace(xp)
602
+ a = xp.asarray(
603
+ [0.35875, 0.48829, 0.14128, 0.01168], dtype=xp.float64, device=device
604
+ )
605
+ device = xp_device(a)
606
+ return _general_cosine_impl(M, a, xp, device, sym=sym)
560
607
 
561
608
 
562
- def flattop(M, sym=True):
609
+ def flattop(M, sym=True, *, xp=None, device=None):
563
610
  """Return a flat top window.
564
611
 
565
612
  Parameters
@@ -571,6 +618,7 @@ def flattop(M, sym=True):
571
618
  When True (default), generates a symmetric window, for use in filter
572
619
  design.
573
620
  When False, generates a periodic window, for use in spectral analysis.
621
+ %(xp_device_snippet)s
574
622
 
575
623
  Returns
576
624
  -------
@@ -618,11 +666,16 @@ def flattop(M, sym=True):
618
666
  >>> plt.xlabel("Normalized frequency [cycles per sample]")
619
667
 
620
668
  """
621
- a = [0.21557895, 0.41663158, 0.277263158, 0.083578947, 0.006947368]
622
- return general_cosine(M, a, sym)
669
+ xp = _namespace(xp)
670
+ a = xp.asarray(
671
+ [0.21557895, 0.41663158, 0.277263158, 0.083578947, 0.006947368],
672
+ dtype=xp.float64, device=device
673
+ )
674
+ device = xp_device(a)
675
+ return _general_cosine_impl(M, a, xp, device, sym=sym)
623
676
 
624
677
 
625
- def bartlett(M, sym=True):
678
+ def bartlett(M, sym=True, *, xp=None, device=None):
626
679
  r"""
627
680
  Return a Bartlett window.
628
681
 
@@ -640,6 +693,7 @@ def bartlett(M, sym=True):
640
693
  When True (default), generates a symmetric window, for use in filter
641
694
  design.
642
695
  When False, generates a periodic window, for use in spectral analysis.
696
+ %(xp_device_snippet)s
643
697
 
644
698
  Returns
645
699
  -------
@@ -710,18 +764,22 @@ def bartlett(M, sym=True):
710
764
 
711
765
  """
712
766
  # Docstring adapted from NumPy's bartlett function
767
+ xp = _namespace(xp)
768
+
713
769
  if _len_guards(M):
714
- return np.ones(M)
770
+ return xp.ones(M, dtype=xp.float64, device=device)
715
771
  M, needs_trunc = _extend(M, sym)
716
772
 
717
- n = np.arange(0, M)
718
- w = np.where(np.less_equal(n, (M - 1) / 2.0),
773
+ n = xp.arange(0, M, dtype=xp.float64, device=device)
774
+
775
+ # cf https://github.com/data-apis/array-api-strict/issues/77
776
+ w = xp.where(n <= (M - 1) / 2.0,
719
777
  2.0 * n / (M - 1), 2.0 - 2.0 * n / (M - 1))
720
778
 
721
779
  return _truncate(w, needs_trunc)
722
780
 
723
781
 
724
- def hann(M, sym=True):
782
+ def hann(M, sym=True, *, xp=None, device=None):
725
783
  r"""
726
784
  Return a Hann window.
727
785
 
@@ -737,6 +795,7 @@ def hann(M, sym=True):
737
795
  When True (default), generates a symmetric window, for use in filter
738
796
  design.
739
797
  When False, generates a periodic window, for use in spectral analysis.
798
+ %(xp_device_snippet)s
740
799
 
741
800
  Returns
742
801
  -------
@@ -801,10 +860,10 @@ def hann(M, sym=True):
801
860
 
802
861
  """
803
862
  # Docstring adapted from NumPy's hanning function
804
- return general_hamming(M, 0.5, sym)
863
+ return general_hamming(M, 0.5, sym, xp=xp, device=device)
805
864
 
806
865
 
807
- def tukey(M, alpha=0.5, sym=True):
866
+ def tukey(M, alpha=0.5, sym=True, *, xp=None, device=None):
808
867
  r"""Return a Tukey window, also known as a tapered cosine window.
809
868
 
810
869
  Parameters
@@ -821,6 +880,7 @@ def tukey(M, alpha=0.5, sym=True):
821
880
  When True (default), generates a symmetric window, for use in filter
822
881
  design.
823
882
  When False, generates a periodic window, for use in spectral analysis.
883
+ %(xp_device_snippet)s
824
884
 
825
885
  Returns
826
886
  -------
@@ -863,32 +923,34 @@ def tukey(M, alpha=0.5, sym=True):
863
923
  >>> plt.xlabel("Normalized frequency [cycles per sample]")
864
924
 
865
925
  """
926
+ xp = _namespace(xp)
927
+
866
928
  if _len_guards(M):
867
- return np.ones(M)
929
+ return xp.ones(M, dtype=xp.float64, device=device)
868
930
 
869
931
  if alpha <= 0:
870
- return np.ones(M, 'd')
932
+ return xp.ones(M, dtype=xp.float64, device=device)
871
933
  elif alpha >= 1.0:
872
- return hann(M, sym=sym)
934
+ return hann(M, sym=sym, xp=xp, device=device)
873
935
 
874
936
  M, needs_trunc = _extend(M, sym)
875
937
 
876
- n = np.arange(0, M)
877
- width = int(np.floor(alpha*(M-1)/2.0))
938
+ n = xp.arange(0, M, dtype=xp.float64, device=device)
939
+ width = int(math.floor(alpha*(M-1)/2.0))
878
940
  n1 = n[0:width+1]
879
941
  n2 = n[width+1:M-width-1]
880
942
  n3 = n[M-width-1:]
881
943
 
882
- w1 = 0.5 * (1 + np.cos(np.pi * (-1 + 2.0*n1/alpha/(M-1))))
883
- w2 = np.ones(n2.shape)
884
- w3 = 0.5 * (1 + np.cos(np.pi * (-2.0/alpha + 1 + 2.0*n3/alpha/(M-1))))
944
+ w1 = 0.5 * (1 + xp.cos(xp.pi * (-1 + 2.0*n1/alpha/(M-1))))
945
+ w2 = xp.ones(n2.shape, device=device)
946
+ w3 = 0.5 * (1 + xp.cos(xp.pi * (-2.0/alpha + 1 + 2.0*n3/alpha/(M-1))))
885
947
 
886
- w = np.concatenate((w1, w2, w3))
948
+ w = xp.concat((w1, w2, w3))
887
949
 
888
950
  return _truncate(w, needs_trunc)
889
951
 
890
952
 
891
- def barthann(M, sym=True):
953
+ def barthann(M, sym=True, *, xp=None, device=None):
892
954
  """Return a modified Bartlett-Hann window.
893
955
 
894
956
  Parameters
@@ -900,6 +962,7 @@ def barthann(M, sym=True):
900
962
  When True (default), generates a symmetric window, for use in filter
901
963
  design.
902
964
  When False, generates a periodic window, for use in spectral analysis.
965
+ %(xp_device_snippet)s
903
966
 
904
967
  Returns
905
968
  -------
@@ -933,18 +996,20 @@ def barthann(M, sym=True):
933
996
  >>> plt.xlabel("Normalized frequency [cycles per sample]")
934
997
 
935
998
  """
999
+ xp = _namespace(xp)
1000
+
936
1001
  if _len_guards(M):
937
- return np.ones(M)
1002
+ return xp.ones(M, dtype=xp.float64, device=device)
938
1003
  M, needs_trunc = _extend(M, sym)
939
1004
 
940
- n = np.arange(0, M)
941
- fac = np.abs(n / (M - 1.0) - 0.5)
942
- w = 0.62 - 0.48 * fac + 0.38 * np.cos(2 * np.pi * fac)
1005
+ n = xp.arange(0, M, dtype=xp.float64, device=device)
1006
+ fac = abs(n / (M - 1.0) - 0.5)
1007
+ w = 0.62 - 0.48 * fac + 0.38 * xp.cos(2 * xp.pi * fac)
943
1008
 
944
1009
  return _truncate(w, needs_trunc)
945
1010
 
946
1011
 
947
- def general_hamming(M, alpha, sym=True):
1012
+ def general_hamming(M, alpha, sym=True, *, xp=None, device=None):
948
1013
  r"""Return a generalized Hamming window.
949
1014
 
950
1015
  The generalized Hamming window is constructed by multiplying a rectangular
@@ -961,6 +1026,7 @@ def general_hamming(M, alpha, sym=True):
961
1026
  When True (default), generates a symmetric window, for use in filter
962
1027
  design.
963
1028
  When False, generates a periodic window, for use in spectral analysis.
1029
+ %(xp_device_snippet)s
964
1030
 
965
1031
  Returns
966
1032
  -------
@@ -1030,10 +1096,13 @@ def general_hamming(M, alpha, sym=True):
1030
1096
  >>> spatial_plot.legend(loc="upper right")
1031
1097
 
1032
1098
  """
1033
- return general_cosine(M, [alpha, 1. - alpha], sym)
1099
+ xp = _namespace(xp)
1100
+ a = xp.asarray([alpha, 1. - alpha], dtype=xp.float64, device=device)
1101
+ device = xp_device(a)
1102
+ return _general_cosine_impl(M, a, xp, device, sym=sym)
1034
1103
 
1035
1104
 
1036
- def hamming(M, sym=True):
1105
+ def hamming(M, sym=True, *, xp=None, device=None):
1037
1106
  r"""Return a Hamming window.
1038
1107
 
1039
1108
  The Hamming window is a taper formed by using a raised cosine with
@@ -1048,6 +1117,7 @@ def hamming(M, sym=True):
1048
1117
  When True (default), generates a symmetric window, for use in filter
1049
1118
  design.
1050
1119
  When False, generates a periodic window, for use in spectral analysis.
1120
+ %(xp_device_snippet)s
1051
1121
 
1052
1122
  Returns
1053
1123
  -------
@@ -1109,10 +1179,10 @@ def hamming(M, sym=True):
1109
1179
 
1110
1180
  """
1111
1181
  # Docstring adapted from NumPy's hamming function
1112
- return general_hamming(M, 0.54, sym)
1182
+ return general_hamming(M, 0.54, sym, xp=xp, device=device)
1113
1183
 
1114
1184
 
1115
- def kaiser(M, beta, sym=True):
1185
+ def kaiser(M, beta, sym=True, *, xp=None, device=None):
1116
1186
  r"""Return a Kaiser window.
1117
1187
 
1118
1188
  The Kaiser window is a taper formed by using a Bessel function.
@@ -1129,6 +1199,7 @@ def kaiser(M, beta, sym=True):
1129
1199
  When True (default), generates a symmetric window, for use in filter
1130
1200
  design.
1131
1201
  When False, generates a periodic window, for use in spectral analysis.
1202
+ %(xp_device_snippet)s
1132
1203
 
1133
1204
  Returns
1134
1205
  -------
@@ -1218,20 +1289,22 @@ def kaiser(M, beta, sym=True):
1218
1289
  >>> plt.xlabel("Normalized frequency [cycles per sample]")
1219
1290
 
1220
1291
  """
1292
+ xp = _namespace(xp)
1293
+
1221
1294
  # Docstring adapted from NumPy's kaiser function
1222
1295
  if _len_guards(M):
1223
- return np.ones(M)
1296
+ return xp.ones(M, dtype=xp.float64, device=device)
1224
1297
  M, needs_trunc = _extend(M, sym)
1225
1298
 
1226
- n = np.arange(0, M)
1299
+ n = xp.arange(0, M, dtype=xp.float64, device=device)
1227
1300
  alpha = (M - 1) / 2.0
1228
- w = (special.i0(beta * np.sqrt(1 - ((n - alpha) / alpha) ** 2.0)) /
1229
- special.i0(beta))
1301
+ w = (special.i0(beta * xp.sqrt(1 - ((n - alpha) / alpha) ** 2.0)) /
1302
+ special.i0(xp.asarray(beta, dtype=xp.float64)))
1230
1303
 
1231
1304
  return _truncate(w, needs_trunc)
1232
1305
 
1233
1306
 
1234
- def kaiser_bessel_derived(M, beta, *, sym=True):
1307
+ def kaiser_bessel_derived(M, beta, *, sym=True, xp=None, device=None):
1235
1308
  """Return a Kaiser-Bessel derived window.
1236
1309
 
1237
1310
  Parameters
@@ -1248,6 +1321,7 @@ def kaiser_bessel_derived(M, beta, *, sym=True):
1248
1321
  the other window functions and to be callable by `get_window`.
1249
1322
  When True (default), generates a symmetric window, for use in filter
1250
1323
  design.
1324
+ %(xp_device_snippet)s
1251
1325
 
1252
1326
  Returns
1253
1327
  -------
@@ -1297,27 +1371,29 @@ def kaiser_bessel_derived(M, beta, *, sym=True):
1297
1371
  >>> fig.tight_layout()
1298
1372
  >>> fig.show()
1299
1373
  """
1374
+ xp = _namespace(xp)
1375
+
1300
1376
  if not sym:
1301
1377
  raise ValueError(
1302
1378
  "Kaiser-Bessel Derived windows are only defined for symmetric "
1303
1379
  "shapes"
1304
1380
  )
1305
1381
  elif M < 1:
1306
- return np.array([])
1382
+ return xp.asarray([])
1307
1383
  elif M % 2:
1308
1384
  raise ValueError(
1309
1385
  "Kaiser-Bessel Derived windows are only defined for even number "
1310
1386
  "of points"
1311
1387
  )
1312
1388
 
1313
- kaiser_window = kaiser(M // 2 + 1, beta)
1314
- csum = np.cumsum(kaiser_window)
1315
- half_window = np.sqrt(csum[:-1] / csum[-1])
1316
- w = np.concatenate((half_window, half_window[::-1]), axis=0)
1317
- return w
1389
+ kaiser_window = kaiser(M // 2 + 1, beta, xp=xp, device=device)
1390
+ csum = xp.cumulative_sum(kaiser_window)
1391
+ half_window = xp.sqrt(csum[:-1] / csum[-1])
1392
+ w = xp.concat((half_window, xp.flip(half_window)), axis=0)
1393
+ return xp.asarray(w, device=device)
1318
1394
 
1319
1395
 
1320
- def gaussian(M, std, sym=True):
1396
+ def gaussian(M, std, sym=True, *, xp=None, device=None):
1321
1397
  r"""Return a Gaussian window.
1322
1398
 
1323
1399
  Parameters
@@ -1331,6 +1407,7 @@ def gaussian(M, std, sym=True):
1331
1407
  When True (default), generates a symmetric window, for use in filter
1332
1408
  design.
1333
1409
  When False, generates a periodic window, for use in spectral analysis.
1410
+ %(xp_device_snippet)s
1334
1411
 
1335
1412
  Returns
1336
1413
  -------
@@ -1370,18 +1447,20 @@ def gaussian(M, std, sym=True):
1370
1447
  >>> plt.xlabel("Normalized frequency [cycles per sample]")
1371
1448
 
1372
1449
  """
1450
+ xp = _namespace(xp)
1451
+
1373
1452
  if _len_guards(M):
1374
- return np.ones(M)
1453
+ return xp.ones(M, dtype=xp.float64, device=device)
1375
1454
  M, needs_trunc = _extend(M, sym)
1376
1455
 
1377
- n = np.arange(0, M) - (M - 1.0) / 2.0
1456
+ n = xp.arange(0, M, dtype=xp.float64, device=device) - (M - 1.0) / 2.0
1378
1457
  sig2 = 2 * std * std
1379
- w = np.exp(-n ** 2 / sig2)
1458
+ w = xp.exp(-n ** 2 / sig2)
1380
1459
 
1381
1460
  return _truncate(w, needs_trunc)
1382
1461
 
1383
1462
 
1384
- def general_gaussian(M, p, sig, sym=True):
1463
+ def general_gaussian(M, p, sig, sym=True, *, xp=None, device=None):
1385
1464
  r"""Return a window with a generalized Gaussian shape.
1386
1465
 
1387
1466
  Parameters
@@ -1398,6 +1477,7 @@ def general_gaussian(M, p, sig, sym=True):
1398
1477
  When True (default), generates a symmetric window, for use in filter
1399
1478
  design.
1400
1479
  When False, generates a periodic window, for use in spectral analysis.
1480
+ %(xp_device_snippet)s
1401
1481
 
1402
1482
  Returns
1403
1483
  -------
@@ -1442,18 +1522,20 @@ def general_gaussian(M, p, sig, sym=True):
1442
1522
  >>> plt.xlabel("Normalized frequency [cycles per sample]")
1443
1523
 
1444
1524
  """
1525
+ xp = _namespace(xp)
1526
+
1445
1527
  if _len_guards(M):
1446
- return np.ones(M)
1528
+ return xp.ones(M, dtype=xp.float64, device=device)
1447
1529
  M, needs_trunc = _extend(M, sym)
1448
1530
 
1449
- n = np.arange(0, M) - (M - 1.0) / 2.0
1450
- w = np.exp(-0.5 * np.abs(n / sig) ** (2 * p))
1531
+ n = xp.arange(0, M, dtype=xp.float64, device=device) - (M - 1.0) / 2.0
1532
+ w = xp.exp(-0.5 * abs(n / sig) ** (2 * p))
1451
1533
 
1452
1534
  return _truncate(w, needs_trunc)
1453
1535
 
1454
1536
 
1455
1537
  # `chebwin` contributed by Kumar Appaiah.
1456
- def chebwin(M, at, sym=True):
1538
+ def chebwin(M, at, sym=True, *, xp=None, device=None):
1457
1539
  r"""Return a Dolph-Chebyshev window.
1458
1540
 
1459
1541
  Parameters
@@ -1467,6 +1549,7 @@ def chebwin(M, at, sym=True):
1467
1549
  When True (default), generates a symmetric window, for use in filter
1468
1550
  design.
1469
1551
  When False, generates a periodic window, for use in spectral analysis.
1552
+ %(xp_device_snippet)s
1470
1553
 
1471
1554
  Returns
1472
1555
  -------
@@ -1539,7 +1622,9 @@ def chebwin(M, at, sym=True):
1539
1622
  >>> plt.xlabel("Normalized frequency [cycles per sample]")
1540
1623
 
1541
1624
  """
1542
- if np.abs(at) < 45:
1625
+ xp = _namespace(xp)
1626
+
1627
+ if abs(at) < 45:
1543
1628
  warnings.warn("This window is not suitable for spectral analysis "
1544
1629
  "for attenuation values lower than about 45dB because "
1545
1630
  "the equivalent noise bandwidth of a Chebyshev window "
@@ -1548,40 +1633,41 @@ def chebwin(M, at, sym=True):
1548
1633
  "about 45 dB.",
1549
1634
  stacklevel=2)
1550
1635
  if _len_guards(M):
1551
- return np.ones(M)
1636
+ return xp.ones(M, dtype=xp.float64, device=device)
1552
1637
  M, needs_trunc = _extend(M, sym)
1553
1638
 
1554
1639
  # compute the parameter beta
1555
1640
  order = M - 1.0
1556
- beta = np.cosh(1.0 / order * np.arccosh(10 ** (np.abs(at) / 20.)))
1557
- k = np.r_[0:M] * 1.0
1558
- x = beta * np.cos(np.pi * k / M)
1641
+ _val = xp.asarray(10 ** (abs(at) / 20.), dtype=xp.float64, device=device)
1642
+ beta = xp.cosh(1.0 / order * xp.acosh(_val))
1643
+ k = xp.arange(M, dtype=xp.float64, device=device)
1644
+ x = beta * xp.cos(xp.pi * k / M)
1559
1645
  # Find the window's DFT coefficients
1560
1646
  # Use analytic definition of Chebyshev polynomial instead of expansion
1561
1647
  # from scipy.special. Using the expansion in scipy.special leads to errors.
1562
- p = np.zeros(x.shape)
1563
- p[x > 1] = np.cosh(order * np.arccosh(x[x > 1]))
1564
- p[x < -1] = (2 * (M % 2) - 1) * np.cosh(order * np.arccosh(-x[x < -1]))
1565
- p[np.abs(x) <= 1] = np.cos(order * np.arccos(x[np.abs(x) <= 1]))
1648
+ p = xp.zeros_like(x)
1649
+ p[x > 1] = xp.cosh(order * xp.acosh(x[x > 1]))
1650
+ p[x < -1] = (2 * (M % 2) - 1) * xp.cosh(order * xp.acosh(-x[x < -1]))
1651
+ p[abs(x) <= 1] = xp.cos(order * xp.acos(x[abs(x) <= 1]))
1566
1652
 
1567
1653
  # Appropriate IDFT and filling up
1568
1654
  # depending on even/odd M
1569
1655
  if M % 2:
1570
- w = np.real(sp_fft.fft(p))
1656
+ w = xp.real(sp_fft.fft(p))
1571
1657
  n = (M + 1) // 2
1572
1658
  w = w[:n]
1573
- w = np.concatenate((w[n - 1:0:-1], w))
1659
+ w = xp.concat((xp.flip(w[1:n]), w))
1574
1660
  else:
1575
- p = p * np.exp(1.j * np.pi / M * np.r_[0:M])
1576
- w = np.real(sp_fft.fft(p))
1661
+ p = p * xp.exp(1j * xp.pi / M * xp.arange(M, dtype=xp.float64, device=device))
1662
+ w = xp.real(sp_fft.fft(p))
1577
1663
  n = M // 2 + 1
1578
- w = np.concatenate((w[n - 1:0:-1], w[1:n]))
1579
- w = w / max(w)
1664
+ w = xp.concat((xp.flip(w[1:n]), w[1:n]))
1665
+ w = w / xp.max(w)
1580
1666
 
1581
1667
  return _truncate(w, needs_trunc)
1582
1668
 
1583
1669
 
1584
- def cosine(M, sym=True):
1670
+ def cosine(M, sym=True, *, xp=None, device=None):
1585
1671
  """Return a window with a simple cosine shape.
1586
1672
 
1587
1673
  Parameters
@@ -1593,6 +1679,7 @@ def cosine(M, sym=True):
1593
1679
  When True (default), generates a symmetric window, for use in filter
1594
1680
  design.
1595
1681
  When False, generates a periodic window, for use in spectral analysis.
1682
+ %(xp_device_snippet)s
1596
1683
 
1597
1684
  Returns
1598
1685
  -------
@@ -1632,16 +1719,18 @@ def cosine(M, sym=True):
1632
1719
  >>> plt.show()
1633
1720
 
1634
1721
  """
1722
+ xp = _namespace(xp)
1723
+
1635
1724
  if _len_guards(M):
1636
- return np.ones(M)
1725
+ return xp.ones(M, dtype=xp.float64, device=device)
1637
1726
  M, needs_trunc = _extend(M, sym)
1638
1727
 
1639
- w = np.sin(np.pi / M * (np.arange(0, M) + .5))
1728
+ w = xp.sin(xp.pi / M * (xp.arange(M, dtype=xp.float64, device=device) + .5))
1640
1729
 
1641
1730
  return _truncate(w, needs_trunc)
1642
1731
 
1643
1732
 
1644
- def exponential(M, center=None, tau=1., sym=True):
1733
+ def exponential(M, center=None, tau=1., sym=True, *, xp=None, device=None):
1645
1734
  r"""Return an exponential (or Poisson) window.
1646
1735
 
1647
1736
  Parameters
@@ -1661,6 +1750,7 @@ def exponential(M, center=None, tau=1., sym=True):
1661
1750
  When True (default), generates a symmetric window, for use in filter
1662
1751
  design.
1663
1752
  When False, generates a periodic window, for use in spectral analysis.
1753
+ %(xp_device_snippet)s
1664
1754
 
1665
1755
  Returns
1666
1756
  -------
@@ -1715,22 +1805,24 @@ def exponential(M, center=None, tau=1., sym=True):
1715
1805
  >>> plt.ylabel("Amplitude")
1716
1806
  >>> plt.xlabel("Sample")
1717
1807
  """
1808
+ xp = _namespace(xp)
1809
+
1718
1810
  if sym and center is not None:
1719
1811
  raise ValueError("If sym==True, center must be None.")
1720
1812
  if _len_guards(M):
1721
- return np.ones(M)
1813
+ return xp.ones(M, dtype=xp.float64, device=device)
1722
1814
  M, needs_trunc = _extend(M, sym)
1723
1815
 
1724
1816
  if center is None:
1725
1817
  center = (M-1) / 2
1726
1818
 
1727
- n = np.arange(0, M)
1728
- w = np.exp(-np.abs(n-center) / tau)
1819
+ n = xp.arange(0, M, dtype=xp.float64, device=device)
1820
+ w = xp.exp(-abs(n-center) / tau)
1729
1821
 
1730
1822
  return _truncate(w, needs_trunc)
1731
1823
 
1732
1824
 
1733
- def taylor(M, nbar=4, sll=30, norm=True, sym=True):
1825
+ def taylor(M, nbar=4, sll=30, norm=True, sym=True, *, xp=None, device=None):
1734
1826
  """
1735
1827
  Return a Taylor window.
1736
1828
 
@@ -1763,6 +1855,7 @@ def taylor(M, nbar=4, sll=30, norm=True, sym=True):
1763
1855
  When True (default), generates a symmetric window, for use in filter
1764
1856
  design.
1765
1857
  When False, generates a periodic window, for use in spectral analysis.
1858
+ %(xp_device_snippet)s
1766
1859
 
1767
1860
  Returns
1768
1861
  -------
@@ -1810,33 +1903,35 @@ def taylor(M, nbar=4, sll=30, norm=True, sym=True):
1810
1903
  >>> plt.xlabel("Normalized frequency [cycles per sample]")
1811
1904
 
1812
1905
  """ # noqa: E501
1906
+ xp = _namespace(xp)
1907
+
1813
1908
  if _len_guards(M):
1814
- return np.ones(M)
1909
+ return xp.ones(M, dtype=xp.float64, device=device)
1815
1910
  M, needs_trunc = _extend(M, sym)
1816
1911
 
1817
1912
  # Original text uses a negative sidelobe level parameter and then negates
1818
1913
  # it in the calculation of B. To keep consistent with other methods we
1819
1914
  # assume the sidelobe level parameter to be positive.
1820
- B = 10**(sll / 20)
1821
- A = np.arccosh(B) / np.pi
1915
+ B = xp.asarray(10**(sll / 20), device=device)
1916
+ A = xp.acosh(B) / xp.pi
1822
1917
  s2 = nbar**2 / (A**2 + (nbar - 0.5)**2)
1823
- ma = np.arange(1, nbar)
1918
+ ma = xp.arange(1, nbar, dtype=xp.float64, device=device)
1824
1919
 
1825
- Fm = np.empty(nbar-1)
1826
- signs = np.empty_like(ma)
1920
+ Fm = xp.empty(nbar - 1, dtype=xp.float64, device=device)
1921
+ signs = xp.empty_like(ma)
1827
1922
  signs[::2] = 1
1828
1923
  signs[1::2] = -1
1829
1924
  m2 = ma*ma
1830
1925
  for mi, m in enumerate(ma):
1831
- numer = signs[mi] * np.prod(1 - m2[mi]/s2/(A**2 + (ma - 0.5)**2))
1832
- denom = 2 * np.prod(1 - m2[mi]/m2[:mi]) * np.prod(1 - m2[mi]/m2[mi+1:])
1926
+ numer = signs[mi] * xp.prod(1 - m2[mi]/s2/(A**2 + (ma - 0.5)**2))
1927
+ denom = 2 * xp.prod(1 - m2[mi]/m2[:mi]) * xp.prod(1 - m2[mi]/m2[mi+1:])
1833
1928
  Fm[mi] = numer / denom
1834
1929
 
1835
1930
  def W(n):
1836
- return 1 + 2*np.dot(Fm, np.cos(
1837
- 2*np.pi*ma[:, np.newaxis]*(n-M/2.+0.5)/M))
1931
+ return 1 + 2*xp.matmul(Fm, xp.cos(
1932
+ 2*xp.pi*ma[:, xp.newaxis]*(n-M/2.+0.5)/M))
1838
1933
 
1839
- w = W(np.arange(M))
1934
+ w = W(xp.arange(M, dtype=xp.float64, device=device))
1840
1935
 
1841
1936
  # normalize (Note that this is not described in the original text [1])
1842
1937
  if norm:
@@ -1846,7 +1941,8 @@ def taylor(M, nbar=4, sll=30, norm=True, sym=True):
1846
1941
  return _truncate(w, needs_trunc)
1847
1942
 
1848
1943
 
1849
- def dpss(M, NW, Kmax=None, sym=True, norm=None, return_ratios=False):
1944
+ def dpss(M, NW, Kmax=None, sym=True, norm=None, return_ratios=False,
1945
+ *, xp=None, device=None):
1850
1946
  """
1851
1947
  Compute the Discrete Prolate Spheroidal Sequences (DPSS).
1852
1948
 
@@ -1880,6 +1976,7 @@ def dpss(M, NW, Kmax=None, sym=True, norm=None, return_ratios=False):
1880
1976
  return_ratios : bool, optional
1881
1977
  If True, also return the concentration ratios in addition to the
1882
1978
  windows.
1979
+ %(xp_device_snippet)s
1883
1980
 
1884
1981
  Returns
1885
1982
  -------
@@ -1937,12 +2034,12 @@ def dpss(M, NW, Kmax=None, sym=True, norm=None, return_ratios=False):
1937
2034
  ... for win, c in ((win_dpss, 'k'), (win_kaiser, 'r')):
1938
2035
  ... win /= win.sum()
1939
2036
  ... axes[ai, 0].plot(win, color=c, lw=1.)
1940
- ... axes[ai, 0].set(xlim=[0, M-1], title=r'$\\alpha$ = %s' % alpha,
2037
+ ... axes[ai, 0].set(xlim=[0, M-1], title=rf'$\\alpha$ = {alpha}',
1941
2038
  ... ylabel='Amplitude')
1942
2039
  ... w, h = freqz(win)
1943
2040
  ... axes[ai, 1].plot(w, 20 * np.log10(np.abs(h)), color=c, lw=1.)
1944
2041
  ... axes[ai, 1].set(xlim=[0, np.pi],
1945
- ... title=r'$\\beta$ = %0.2f' % beta,
2042
+ ... title=rf'$\\beta$ = {beta:0.2f}',
1946
2043
  ... ylabel='Magnitude (dB)')
1947
2044
  >>> for ax in axes.ravel():
1948
2045
  ... ax.grid(True)
@@ -1959,8 +2056,8 @@ def dpss(M, NW, Kmax=None, sym=True, norm=None, return_ratios=False):
1959
2056
  >>> fig, ax = plt.subplots(1)
1960
2057
  >>> ax.plot(win.T, linewidth=1.)
1961
2058
  >>> ax.set(xlim=[0, M-1], ylim=[-0.1, 0.1], xlabel='Samples',
1962
- ... title='DPSS, M=%d, NW=%0.1f' % (M, NW))
1963
- >>> ax.legend(['win[%d] (%0.4f)' % (ii, ratio)
2059
+ ... title=f'DPSS, {M:d}, {NW:0.1f}')
2060
+ >>> ax.legend([f'win[{ii}] ({ratio:0.4f})'
1964
2061
  ... for ii, ratio in enumerate(eigvals)])
1965
2062
  >>> fig.tight_layout()
1966
2063
  >>> plt.show()
@@ -2009,8 +2106,8 @@ def dpss(M, NW, Kmax=None, sym=True, norm=None, return_ratios=False):
2009
2106
  >>> fig.tight_layout()
2010
2107
 
2011
2108
  """
2012
- if _len_guards(M):
2013
- return np.ones(M)
2109
+ xp = _namespace(xp)
2110
+
2014
2111
  if norm is None:
2015
2112
  norm = 'approximate' if Kmax is None else 2
2016
2113
  known_norms = (2, 'approximate', 'subsample')
@@ -2021,6 +2118,13 @@ def dpss(M, NW, Kmax=None, sym=True, norm=None, return_ratios=False):
2021
2118
  Kmax = 1
2022
2119
  else:
2023
2120
  singleton = False
2121
+ if _len_guards(M):
2122
+ if not return_ratios:
2123
+ return xp.ones(M, dtype=xp.float64)
2124
+ elif singleton:
2125
+ return xp.ones(M, dtype=xp.float64), 1.
2126
+ else:
2127
+ return xp.ones(M, dtype=xp.float64), xp.ones(1, dtype=xp.float64)
2024
2128
  Kmax = operator.index(Kmax)
2025
2129
  if not 0 < Kmax <= M:
2026
2130
  raise ValueError('Kmax must be greater than 0 and less than M')
@@ -2030,7 +2134,7 @@ def dpss(M, NW, Kmax=None, sym=True, norm=None, return_ratios=False):
2030
2134
  raise ValueError('NW must be positive')
2031
2135
  M, needs_trunc = _extend(M, sym)
2032
2136
  W = float(NW) / M
2033
- nidx = np.arange(M)
2137
+ nidx = xp.arange(M, dtype=xp.float64, device=device)
2034
2138
 
2035
2139
  # Here we want to set up an optimization problem to find a sequence
2036
2140
  # whose energy is maximally concentrated within band [-W,W].
@@ -2050,7 +2154,7 @@ def dpss(M, NW, Kmax=None, sym=True, norm=None, return_ratios=False):
2050
2154
  # the main diagonal = ([M-1-2*t]/2)**2 cos(2PIW), t=[0,1,2,...,M-1]
2051
2155
  # and the first off-diagonal = t(M-t)/2, t=[1,2,...,M-1]
2052
2156
  # [see Percival and Walden, 1993]
2053
- d = ((M - 1 - 2 * nidx) / 2.) ** 2 * np.cos(2 * np.pi * W)
2157
+ d = ((M - 1 - 2 * nidx) / 2.) ** 2 * xp.cos(xp.asarray(2 * xp.pi * W))
2054
2158
  e = nidx[1:] * (M - nidx[1:]) / 2.
2055
2159
 
2056
2160
  # only calculate the highest Kmax eigenvalues
@@ -2061,7 +2165,7 @@ def dpss(M, NW, Kmax=None, sym=True, norm=None, return_ratios=False):
2061
2165
 
2062
2166
  # By convention (Percival and Walden, 1993 pg 379)
2063
2167
  # * symmetric tapers (k=0,2,4,...) should have a positive average.
2064
- fix_even = (windows[::2].sum(axis=1) < 0)
2168
+ fix_even = (windows[::2, ...].sum(axis=1) < 0)
2065
2169
  for i, f in enumerate(fix_even):
2066
2170
  if f:
2067
2171
  windows[2 * i] *= -1
@@ -2072,19 +2176,20 @@ def dpss(M, NW, Kmax=None, sym=True, norm=None, return_ratios=False):
2072
2176
  # algorithm that uses max(abs(w)), which is susceptible to numerical
2073
2177
  # noise problems)
2074
2178
  thresh = max(1e-7, 1. / M)
2075
- for i, w in enumerate(windows[1::2]):
2179
+ for i, w in enumerate(windows[1::2, ...]):
2076
2180
  if w[w * w > thresh][0] < 0:
2077
2181
  windows[2 * i + 1] *= -1
2078
2182
 
2079
2183
  # Now find the eigenvalues of the original spectral concentration problem
2080
2184
  # Use the autocorr sequence technique from Percival and Walden, 1993 pg 390
2081
2185
  if return_ratios:
2082
- dpss_rxx = _fftautocorr(windows)
2083
- r = 4 * W * np.sinc(2 * W * nidx)
2186
+ dpss_rxx = _fftautocorr(xp.asarray(windows))
2187
+ r = 4 * W * xpx.sinc(xp.asarray(2 * W * nidx), xp=xp)
2084
2188
  r[0] = 2 * W
2085
- ratios = np.dot(dpss_rxx, r)
2189
+ ratios = xp.matmul(dpss_rxx, r)
2086
2190
  if singleton:
2087
2191
  ratios = ratios[0]
2192
+ ratios = xp.asarray(ratios, device=device)
2088
2193
  # Deal with sym and Kmax=None
2089
2194
  if norm != 2:
2090
2195
  windows /= windows.max()
@@ -2093,8 +2198,8 @@ def dpss(M, NW, Kmax=None, sym=True, norm=None, return_ratios=False):
2093
2198
  correction = M**2 / float(M**2 + NW)
2094
2199
  else:
2095
2200
  s = sp_fft.rfft(windows[0])
2096
- shift = -(1 - 1./M) * np.arange(1, M//2 + 1)
2097
- s[1:] *= 2 * np.exp(-1j * np.pi * shift)
2201
+ shift = -(1 - 1./M) * xp.arange(1, M//2 + 1, dtype=xp.float64)
2202
+ s[1:] *= 2 * xp.exp(-1j * xp.pi * shift)
2098
2203
  correction = M / s.real.sum()
2099
2204
  windows *= correction
2100
2205
  # else we're already l2 normed, so do nothing
@@ -2102,10 +2207,11 @@ def dpss(M, NW, Kmax=None, sym=True, norm=None, return_ratios=False):
2102
2207
  windows = windows[:, :-1]
2103
2208
  if singleton:
2104
2209
  windows = windows[0]
2210
+ windows = xp.asarray(windows, device=device)
2105
2211
  return (windows, ratios) if return_ratios else windows
2106
2212
 
2107
2213
 
2108
- def lanczos(M, *, sym=True):
2214
+ def lanczos(M, *, sym=True, xp=None, device=None):
2109
2215
  r"""Return a Lanczos window also known as a sinc window.
2110
2216
 
2111
2217
  Parameters
@@ -2117,6 +2223,7 @@ def lanczos(M, *, sym=True):
2117
2223
  When True (default), generates a symmetric window, for use in filter
2118
2224
  design.
2119
2225
  When False, generates a periodic window, for use in spectral analysis.
2226
+ %(xp_device_snippet)s
2120
2227
 
2121
2228
  Returns
2122
2229
  -------
@@ -2183,22 +2290,24 @@ def lanczos(M, *, sym=True):
2183
2290
  >>> fig.tight_layout()
2184
2291
  >>> plt.show()
2185
2292
  """
2293
+ xp = _namespace(xp)
2294
+
2186
2295
  if _len_guards(M):
2187
- return np.ones(M)
2296
+ return xp.ones(M, dtype=xp.float64, device=device)
2188
2297
  M, needs_trunc = _extend(M, sym)
2189
2298
 
2190
2299
  # To make sure that the window is symmetric, we concatenate the right hand
2191
2300
  # half of the window and the flipped one which is the left hand half of
2192
2301
  # the window.
2193
2302
  def _calc_right_side_lanczos(n, m):
2194
- return np.sinc(2. * np.arange(n, m) / (m - 1) - 1.0)
2303
+ return xpx.sinc(2. * xp.arange(n, m, dtype=xp.float64) / (m - 1) - 1.0, xp=xp)
2195
2304
 
2196
2305
  if M % 2 == 0:
2197
2306
  wh = _calc_right_side_lanczos(M/2, M)
2198
- w = np.r_[np.flip(wh), wh]
2307
+ w = xp.concat([xp.flip(wh), wh])
2199
2308
  else:
2200
2309
  wh = _calc_right_side_lanczos((M+1)/2, M)
2201
- w = np.r_[np.flip(wh), 1.0, wh]
2310
+ w = xp.concat([xp.flip(wh), xp.ones(1), wh])
2202
2311
 
2203
2312
  return _truncate(w, needs_trunc)
2204
2313
 
@@ -2210,8 +2319,8 @@ def _fftautocorr(x):
2210
2319
  x_fft = sp_fft.rfft(x, use_N, axis=-1)
2211
2320
  cxy = sp_fft.irfft(x_fft * x_fft.conj(), n=use_N)[:, :N]
2212
2321
  # Or equivalently (but in most cases slower):
2213
- # cxy = np.array([np.convolve(xx, yy[::-1], mode='full')
2214
- # for xx, yy in zip(x, x)])[:, N-1:2*N-1]
2322
+ # cxy = xp.asarray([xp.convolve(xx, yy[::-1], mode='full')
2323
+ # for xx, yy in zip(x, x)])[:, N-1:2*N-1]
2215
2324
  return cxy
2216
2325
 
2217
2326
 
@@ -2258,7 +2367,7 @@ for k, v in _win_equiv_raw.items():
2258
2367
  _needs_param.update(k)
2259
2368
 
2260
2369
 
2261
- def get_window(window, Nx, fftbins=True):
2370
+ def get_window(window, Nx, fftbins=True, *, xp=None, device=None):
2262
2371
  """
2263
2372
  Return a window of a given length and type.
2264
2373
 
@@ -2273,6 +2382,7 @@ def get_window(window, Nx, fftbins=True):
2273
2382
  `ifftshift` and be multiplied by the result of an FFT (see also
2274
2383
  :func:`~scipy.fft.fftfreq`).
2275
2384
  If False, create a "symmetric" window, for use in filter design.
2385
+ %(xp_device_snippet)s
2276
2386
 
2277
2387
  Returns
2278
2388
  -------
@@ -2358,6 +2468,11 @@ def get_window(window, Nx, fftbins=True):
2358
2468
  raise ValueError(
2359
2469
  f"{str(type(window))} as window type is not supported.") from e
2360
2470
 
2471
+ if winstr == 'general_cosine' and (xp is not None or device is not None):
2472
+ raise ValueError(
2473
+ 'general_cosine window does not accept xp and device kwargs '
2474
+ )
2475
+
2361
2476
  try:
2362
2477
  winfunc = _win_equiv[winstr]
2363
2478
  except KeyError as e:
@@ -2371,4 +2486,28 @@ def get_window(window, Nx, fftbins=True):
2371
2486
  winfunc = kaiser
2372
2487
  params = (Nx, beta)
2373
2488
 
2374
- return winfunc(*params, sym=sym)
2489
+ if winfunc == general_cosine:
2490
+ return winfunc(*params, sym=sym)
2491
+ else:
2492
+ return winfunc(*params, sym=sym, xp=xp, device=device)
2493
+
2494
+
2495
+ ########## complete the docstrings, on import
2496
+ _xp_device_snippet = {'xp_device_snippet':
2497
+ """\
2498
+ xp : array_namespace, optional
2499
+ Optional array namespace.
2500
+ Should be compatible with the array API standard, or supported by array-api-compat.
2501
+ Default: ``numpy``
2502
+ device: any
2503
+ optional device specification for output. Should match one of the
2504
+ supported device specification in ``xp``.
2505
+ """
2506
+ }
2507
+
2508
+
2509
+ _names = [x for x in __all__ if x != 'general_cosine']
2510
+ for name in _names:
2511
+ window = vars()[name]
2512
+ window.__doc__ = doccer.docformat(window.__doc__, _xp_device_snippet)
2513
+