scipy 1.15.2__cp312-cp312-win_amd64.whl → 1.15.3__cp312-cp312-win_amd64.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 (280) hide show
  1. scipy/__config__.py +6 -6
  2. scipy/__init__.py +3 -3
  3. scipy/_lib/_array_api.py +11 -0
  4. scipy/_lib/_ccallback_c.cp312-win_amd64.dll.a +0 -0
  5. scipy/_lib/_ccallback_c.cp312-win_amd64.pyd +0 -0
  6. scipy/_lib/_fpumode.cp312-win_amd64.dll.a +0 -0
  7. scipy/_lib/_fpumode.cp312-win_amd64.pyd +0 -0
  8. scipy/_lib/_test_ccallback.cp312-win_amd64.dll.a +0 -0
  9. scipy/_lib/_test_ccallback.cp312-win_amd64.pyd +0 -0
  10. scipy/_lib/_test_deprecation_call.cp312-win_amd64.dll.a +0 -0
  11. scipy/_lib/_test_deprecation_call.cp312-win_amd64.pyd +0 -0
  12. scipy/_lib/_test_deprecation_def.cp312-win_amd64.dll.a +0 -0
  13. scipy/_lib/_test_deprecation_def.cp312-win_amd64.pyd +0 -0
  14. scipy/_lib/_uarray/_uarray.cp312-win_amd64.dll.a +0 -0
  15. scipy/_lib/_uarray/_uarray.cp312-win_amd64.pyd +0 -0
  16. scipy/_lib/messagestream.cp312-win_amd64.dll.a +0 -0
  17. scipy/_lib/messagestream.cp312-win_amd64.pyd +0 -0
  18. scipy/_lib/tests/test_array_api.py +5 -1
  19. scipy/cluster/_hierarchy.cp312-win_amd64.dll.a +0 -0
  20. scipy/cluster/_hierarchy.cp312-win_amd64.pyd +0 -0
  21. scipy/cluster/_optimal_leaf_ordering.cp312-win_amd64.dll.a +0 -0
  22. scipy/cluster/_optimal_leaf_ordering.cp312-win_amd64.pyd +0 -0
  23. scipy/cluster/_vq.cp312-win_amd64.dll.a +0 -0
  24. scipy/cluster/_vq.cp312-win_amd64.pyd +0 -0
  25. scipy/fft/_pocketfft/pypocketfft.cp312-win_amd64.dll.a +0 -0
  26. scipy/fft/_pocketfft/pypocketfft.cp312-win_amd64.pyd +0 -0
  27. scipy/fftpack/convolve.cp312-win_amd64.dll.a +0 -0
  28. scipy/fftpack/convolve.cp312-win_amd64.pyd +0 -0
  29. scipy/integrate/_dop.cp312-win_amd64.dll.a +0 -0
  30. scipy/integrate/_dop.cp312-win_amd64.pyd +0 -0
  31. scipy/integrate/_ivp/common.py +3 -3
  32. scipy/integrate/_ivp/ivp.py +9 -2
  33. scipy/integrate/_ivp/tests/test_ivp.py +19 -0
  34. scipy/integrate/_lsoda.cp312-win_amd64.dll.a +0 -0
  35. scipy/integrate/_lsoda.cp312-win_amd64.pyd +0 -0
  36. scipy/integrate/_odepack.cp312-win_amd64.dll.a +0 -0
  37. scipy/integrate/_odepack.cp312-win_amd64.pyd +0 -0
  38. scipy/integrate/_quadpack.cp312-win_amd64.dll.a +0 -0
  39. scipy/integrate/_quadpack.cp312-win_amd64.pyd +0 -0
  40. scipy/integrate/_tanhsinh.py +14 -12
  41. scipy/integrate/_test_multivariate.cp312-win_amd64.dll.a +0 -0
  42. scipy/integrate/_test_multivariate.cp312-win_amd64.pyd +0 -0
  43. scipy/integrate/_test_odeint_banded.cp312-win_amd64.dll.a +0 -0
  44. scipy/integrate/_test_odeint_banded.cp312-win_amd64.pyd +0 -0
  45. scipy/integrate/_vode.cp312-win_amd64.dll.a +0 -0
  46. scipy/integrate/_vode.cp312-win_amd64.pyd +0 -0
  47. scipy/integrate/tests/test_tanhsinh.py +10 -0
  48. scipy/interpolate/_bspl.cp312-win_amd64.dll.a +0 -0
  49. scipy/interpolate/_bspl.cp312-win_amd64.pyd +0 -0
  50. scipy/interpolate/_dfitpack.cp312-win_amd64.dll.a +0 -0
  51. scipy/interpolate/_dfitpack.cp312-win_amd64.pyd +0 -0
  52. scipy/interpolate/_dierckx.cp312-win_amd64.dll.a +0 -0
  53. scipy/interpolate/_dierckx.cp312-win_amd64.pyd +0 -0
  54. scipy/interpolate/_fitpack.cp312-win_amd64.dll.a +0 -0
  55. scipy/interpolate/_fitpack.cp312-win_amd64.pyd +0 -0
  56. scipy/interpolate/_interpnd.cp312-win_amd64.dll.a +0 -0
  57. scipy/interpolate/_interpnd.cp312-win_amd64.pyd +0 -0
  58. scipy/interpolate/_ppoly.cp312-win_amd64.dll.a +0 -0
  59. scipy/interpolate/_ppoly.cp312-win_amd64.pyd +0 -0
  60. scipy/interpolate/_rbfinterp_pythran.cp312-win_amd64.dll.a +0 -0
  61. scipy/interpolate/_rbfinterp_pythran.cp312-win_amd64.pyd +0 -0
  62. scipy/interpolate/_rgi_cython.cp312-win_amd64.dll.a +0 -0
  63. scipy/interpolate/_rgi_cython.cp312-win_amd64.pyd +0 -0
  64. scipy/io/_fast_matrix_market/_fmm_core.cp312-win_amd64.dll.a +0 -0
  65. scipy/io/_fast_matrix_market/_fmm_core.cp312-win_amd64.pyd +0 -0
  66. scipy/io/_test_fortran.cp312-win_amd64.dll.a +0 -0
  67. scipy/io/_test_fortran.cp312-win_amd64.pyd +0 -0
  68. scipy/io/matlab/_mio5_utils.cp312-win_amd64.dll.a +0 -0
  69. scipy/io/matlab/_mio5_utils.cp312-win_amd64.pyd +0 -0
  70. scipy/io/matlab/_mio_utils.cp312-win_amd64.dll.a +0 -0
  71. scipy/io/matlab/_mio_utils.cp312-win_amd64.pyd +0 -0
  72. scipy/io/matlab/_streams.cp312-win_amd64.dll.a +0 -0
  73. scipy/io/matlab/_streams.cp312-win_amd64.pyd +0 -0
  74. scipy/linalg/_cythonized_array_utils.cp312-win_amd64.dll.a +0 -0
  75. scipy/linalg/_cythonized_array_utils.cp312-win_amd64.pyd +0 -0
  76. scipy/linalg/_decomp_interpolative.cp312-win_amd64.dll.a +0 -0
  77. scipy/linalg/_decomp_interpolative.cp312-win_amd64.pyd +0 -0
  78. scipy/linalg/_decomp_lu_cython.cp312-win_amd64.dll.a +0 -0
  79. scipy/linalg/_decomp_lu_cython.cp312-win_amd64.pyd +0 -0
  80. scipy/linalg/_decomp_update.cp312-win_amd64.dll.a +0 -0
  81. scipy/linalg/_decomp_update.cp312-win_amd64.pyd +0 -0
  82. scipy/linalg/_fblas.cp312-win_amd64.dll.a +0 -0
  83. scipy/linalg/_fblas.cp312-win_amd64.pyd +0 -0
  84. scipy/linalg/_flapack.cp312-win_amd64.dll.a +0 -0
  85. scipy/linalg/_flapack.cp312-win_amd64.pyd +0 -0
  86. scipy/linalg/_linalg_pythran.cp312-win_amd64.dll.a +0 -0
  87. scipy/linalg/_linalg_pythran.cp312-win_amd64.pyd +0 -0
  88. scipy/linalg/_matfuncs_expm.cp312-win_amd64.dll.a +0 -0
  89. scipy/linalg/_matfuncs_expm.cp312-win_amd64.pyd +0 -0
  90. scipy/linalg/_matfuncs_sqrtm_triu.cp312-win_amd64.dll.a +0 -0
  91. scipy/linalg/_matfuncs_sqrtm_triu.cp312-win_amd64.pyd +0 -0
  92. scipy/linalg/_solve_toeplitz.cp312-win_amd64.dll.a +0 -0
  93. scipy/linalg/_solve_toeplitz.cp312-win_amd64.pyd +0 -0
  94. scipy/linalg/cython_blas.cp312-win_amd64.dll.a +0 -0
  95. scipy/linalg/cython_blas.cp312-win_amd64.pyd +0 -0
  96. scipy/linalg/cython_lapack.cp312-win_amd64.dll.a +0 -0
  97. scipy/linalg/cython_lapack.cp312-win_amd64.pyd +0 -0
  98. scipy/linalg/tests/test_interpolative.py +17 -0
  99. scipy/ndimage/_ctest.cp312-win_amd64.dll.a +0 -0
  100. scipy/ndimage/_ctest.cp312-win_amd64.pyd +0 -0
  101. scipy/ndimage/_cytest.cp312-win_amd64.dll.a +0 -0
  102. scipy/ndimage/_cytest.cp312-win_amd64.pyd +0 -0
  103. scipy/ndimage/_nd_image.cp312-win_amd64.dll.a +0 -0
  104. scipy/ndimage/_nd_image.cp312-win_amd64.pyd +0 -0
  105. scipy/ndimage/_ndimage_api.py +2 -1
  106. scipy/ndimage/_ni_label.cp312-win_amd64.dll.a +0 -0
  107. scipy/ndimage/_ni_label.cp312-win_amd64.pyd +0 -0
  108. scipy/ndimage/_rank_filter_1d.cp312-win_amd64.dll.a +0 -0
  109. scipy/ndimage/_rank_filter_1d.cp312-win_amd64.pyd +0 -0
  110. scipy/ndimage/tests/test_filters.py +14 -0
  111. scipy/odr/__odrpack.cp312-win_amd64.dll.a +0 -0
  112. scipy/odr/__odrpack.cp312-win_amd64.pyd +0 -0
  113. scipy/optimize/_bglu_dense.cp312-win_amd64.dll.a +0 -0
  114. scipy/optimize/_bglu_dense.cp312-win_amd64.pyd +0 -0
  115. scipy/optimize/_bracket.py +35 -8
  116. scipy/optimize/_cobyla.cp312-win_amd64.dll.a +0 -0
  117. scipy/optimize/_cobyla.cp312-win_amd64.pyd +0 -0
  118. scipy/optimize/_cython_nnls.cp312-win_amd64.dll.a +0 -0
  119. scipy/optimize/_cython_nnls.cp312-win_amd64.pyd +0 -0
  120. scipy/optimize/_direct.cp312-win_amd64.dll.a +0 -0
  121. scipy/optimize/_direct.cp312-win_amd64.pyd +0 -0
  122. scipy/optimize/_group_columns.cp312-win_amd64.dll.a +0 -0
  123. scipy/optimize/_group_columns.cp312-win_amd64.pyd +0 -0
  124. scipy/optimize/_highspy/_core.cp312-win_amd64.dll.a +0 -0
  125. scipy/optimize/_highspy/_core.cp312-win_amd64.pyd +0 -0
  126. scipy/optimize/_highspy/_highs_options.cp312-win_amd64.dll.a +0 -0
  127. scipy/optimize/_highspy/_highs_options.cp312-win_amd64.pyd +0 -0
  128. scipy/optimize/_highspy/_highs_wrapper.py +6 -4
  129. scipy/optimize/_lbfgsb.cp312-win_amd64.dll.a +0 -0
  130. scipy/optimize/_lbfgsb.cp312-win_amd64.pyd +0 -0
  131. scipy/optimize/_linprog_highs.py +9 -9
  132. scipy/optimize/_linprog_util.py +4 -3
  133. scipy/optimize/_lsap.cp312-win_amd64.dll.a +0 -0
  134. scipy/optimize/_lsap.cp312-win_amd64.pyd +0 -0
  135. scipy/optimize/_lsq/givens_elimination.cp312-win_amd64.dll.a +0 -0
  136. scipy/optimize/_lsq/givens_elimination.cp312-win_amd64.pyd +0 -0
  137. scipy/optimize/_minpack.cp312-win_amd64.dll.a +0 -0
  138. scipy/optimize/_minpack.cp312-win_amd64.pyd +0 -0
  139. scipy/optimize/_moduleTNC.cp312-win_amd64.dll.a +0 -0
  140. scipy/optimize/_moduleTNC.cp312-win_amd64.pyd +0 -0
  141. scipy/optimize/_pava_pybind.cp312-win_amd64.dll.a +0 -0
  142. scipy/optimize/_pava_pybind.cp312-win_amd64.pyd +0 -0
  143. scipy/optimize/_slsqp.cp312-win_amd64.dll.a +0 -0
  144. scipy/optimize/_slsqp.cp312-win_amd64.pyd +0 -0
  145. scipy/optimize/_trlib/_trlib.cp312-win_amd64.dll.a +0 -0
  146. scipy/optimize/_trlib/_trlib.cp312-win_amd64.pyd +0 -0
  147. scipy/optimize/_zeros.cp312-win_amd64.dll.a +0 -0
  148. scipy/optimize/_zeros.cp312-win_amd64.pyd +0 -0
  149. scipy/optimize/cython_optimize/_zeros.cp312-win_amd64.dll.a +0 -0
  150. scipy/optimize/cython_optimize/_zeros.cp312-win_amd64.pyd +0 -0
  151. scipy/optimize/tests/test_bracket.py +35 -0
  152. scipy/signal/_max_len_seq_inner.cp312-win_amd64.dll.a +0 -0
  153. scipy/signal/_max_len_seq_inner.cp312-win_amd64.pyd +0 -0
  154. scipy/signal/_peak_finding_utils.cp312-win_amd64.dll.a +0 -0
  155. scipy/signal/_peak_finding_utils.cp312-win_amd64.pyd +0 -0
  156. scipy/signal/_short_time_fft.py +34 -6
  157. scipy/signal/_signaltools.py +4 -1
  158. scipy/signal/_sigtools.cp312-win_amd64.dll.a +0 -0
  159. scipy/signal/_sigtools.cp312-win_amd64.pyd +0 -0
  160. scipy/signal/_sosfilt.cp312-win_amd64.dll.a +0 -0
  161. scipy/signal/_sosfilt.cp312-win_amd64.pyd +0 -0
  162. scipy/signal/_spline.cp312-win_amd64.dll.a +0 -0
  163. scipy/signal/_spline.cp312-win_amd64.pyd +0 -0
  164. scipy/signal/_upfirdn_apply.cp312-win_amd64.dll.a +0 -0
  165. scipy/signal/_upfirdn_apply.cp312-win_amd64.pyd +0 -0
  166. scipy/signal/tests/_scipy_spectral_test_shim.py +3 -11
  167. scipy/signal/tests/test_short_time_fft.py +10 -2
  168. scipy/signal/tests/test_signaltools.py +5 -0
  169. scipy/sparse/_base.py +2 -15
  170. scipy/sparse/_compressed.py +0 -3
  171. scipy/sparse/_csparsetools.cp312-win_amd64.dll.a +0 -0
  172. scipy/sparse/_csparsetools.cp312-win_amd64.pyd +0 -0
  173. scipy/sparse/_dia.py +0 -3
  174. scipy/sparse/_sparsetools.cp312-win_amd64.dll.a +0 -0
  175. scipy/sparse/_sparsetools.cp312-win_amd64.pyd +0 -0
  176. scipy/sparse/csgraph/_flow.cp312-win_amd64.dll.a +0 -0
  177. scipy/sparse/csgraph/_flow.cp312-win_amd64.pyd +0 -0
  178. scipy/sparse/csgraph/_matching.cp312-win_amd64.dll.a +0 -0
  179. scipy/sparse/csgraph/_matching.cp312-win_amd64.pyd +0 -0
  180. scipy/sparse/csgraph/_min_spanning_tree.cp312-win_amd64.dll.a +0 -0
  181. scipy/sparse/csgraph/_min_spanning_tree.cp312-win_amd64.pyd +0 -0
  182. scipy/sparse/csgraph/_reordering.cp312-win_amd64.dll.a +0 -0
  183. scipy/sparse/csgraph/_reordering.cp312-win_amd64.pyd +0 -0
  184. scipy/sparse/csgraph/_shortest_path.cp312-win_amd64.dll.a +0 -0
  185. scipy/sparse/csgraph/_shortest_path.cp312-win_amd64.pyd +0 -0
  186. scipy/sparse/csgraph/_tools.cp312-win_amd64.dll.a +0 -0
  187. scipy/sparse/csgraph/_tools.cp312-win_amd64.pyd +0 -0
  188. scipy/sparse/csgraph/_traversal.cp312-win_amd64.dll.a +0 -0
  189. scipy/sparse/csgraph/_traversal.cp312-win_amd64.pyd +0 -0
  190. scipy/sparse/linalg/_dsolve/_superlu.cp312-win_amd64.dll.a +0 -0
  191. scipy/sparse/linalg/_dsolve/_superlu.cp312-win_amd64.pyd +0 -0
  192. scipy/sparse/linalg/_eigen/arpack/_arpack.cp312-win_amd64.dll.a +0 -0
  193. scipy/sparse/linalg/_eigen/arpack/_arpack.cp312-win_amd64.pyd +0 -0
  194. scipy/sparse/linalg/_eigen/arpack/arpack.py +5 -3
  195. scipy/sparse/linalg/_expm_multiply.py +8 -3
  196. scipy/sparse/linalg/_interface.py +12 -8
  197. scipy/sparse/linalg/_isolve/_gcrotmk.py +2 -1
  198. scipy/sparse/linalg/_propack/_cpropack.cp312-win_amd64.dll.a +0 -0
  199. scipy/sparse/linalg/_propack/_cpropack.cp312-win_amd64.pyd +0 -0
  200. scipy/sparse/linalg/_propack/_dpropack.cp312-win_amd64.dll.a +0 -0
  201. scipy/sparse/linalg/_propack/_dpropack.cp312-win_amd64.pyd +0 -0
  202. scipy/sparse/linalg/_propack/_spropack.cp312-win_amd64.dll.a +0 -0
  203. scipy/sparse/linalg/_propack/_spropack.cp312-win_amd64.pyd +0 -0
  204. scipy/sparse/linalg/_propack/_zpropack.cp312-win_amd64.dll.a +0 -0
  205. scipy/sparse/linalg/_propack/_zpropack.cp312-win_amd64.pyd +0 -0
  206. scipy/sparse/linalg/tests/test_expm_multiply.py +10 -0
  207. scipy/sparse/linalg/tests/test_interface.py +35 -0
  208. scipy/sparse/linalg/tests/test_pydata_sparse.py +4 -0
  209. scipy/sparse/tests/test_base.py +12 -0
  210. scipy/sparse/tests/test_common1d.py +11 -6
  211. scipy/spatial/_ckdtree.cp312-win_amd64.dll.a +0 -0
  212. scipy/spatial/_ckdtree.cp312-win_amd64.pyd +0 -0
  213. scipy/spatial/_distance_pybind.cp312-win_amd64.dll.a +0 -0
  214. scipy/spatial/_distance_pybind.cp312-win_amd64.pyd +0 -0
  215. scipy/spatial/_distance_wrap.cp312-win_amd64.dll.a +0 -0
  216. scipy/spatial/_distance_wrap.cp312-win_amd64.pyd +0 -0
  217. scipy/spatial/_hausdorff.cp312-win_amd64.dll.a +0 -0
  218. scipy/spatial/_hausdorff.cp312-win_amd64.pyd +0 -0
  219. scipy/spatial/_qhull.cp312-win_amd64.dll.a +0 -0
  220. scipy/spatial/_qhull.cp312-win_amd64.pyd +0 -0
  221. scipy/spatial/_voronoi.cp312-win_amd64.dll.a +0 -0
  222. scipy/spatial/_voronoi.cp312-win_amd64.pyd +0 -0
  223. scipy/spatial/tests/test_qhull.py +99 -0
  224. scipy/spatial/transform/_rotation.cp312-win_amd64.dll.a +0 -0
  225. scipy/spatial/transform/_rotation.cp312-win_amd64.pyd +0 -0
  226. scipy/spatial/transform/tests/test_rotation.py +181 -10
  227. scipy/special/_comb.cp312-win_amd64.dll.a +0 -0
  228. scipy/special/_comb.cp312-win_amd64.pyd +0 -0
  229. scipy/special/_ellip_harm_2.cp312-win_amd64.dll.a +0 -0
  230. scipy/special/_ellip_harm_2.cp312-win_amd64.pyd +0 -0
  231. scipy/special/_gufuncs.cp312-win_amd64.dll.a +0 -0
  232. scipy/special/_gufuncs.cp312-win_amd64.pyd +0 -0
  233. scipy/special/_logsumexp.py +21 -16
  234. scipy/special/_specfun.cp312-win_amd64.dll.a +0 -0
  235. scipy/special/_specfun.cp312-win_amd64.pyd +0 -0
  236. scipy/special/_special_ufuncs.cp312-win_amd64.dll.a +0 -0
  237. scipy/special/_special_ufuncs.cp312-win_amd64.pyd +0 -0
  238. scipy/special/_test_internal.cp312-win_amd64.dll.a +0 -0
  239. scipy/special/_test_internal.cp312-win_amd64.pyd +0 -0
  240. scipy/special/_ufuncs.cp312-win_amd64.dll.a +0 -0
  241. scipy/special/_ufuncs.cp312-win_amd64.pyd +0 -0
  242. scipy/special/_ufuncs_cxx.cp312-win_amd64.dll.a +0 -0
  243. scipy/special/_ufuncs_cxx.cp312-win_amd64.pyd +0 -0
  244. scipy/special/cython_special.cp312-win_amd64.dll.a +0 -0
  245. scipy/special/cython_special.cp312-win_amd64.pyd +0 -0
  246. scipy/special/libsf_error_state.dll +0 -0
  247. scipy/special/libsf_error_state.dll.a +0 -0
  248. scipy/special/tests/test_hyp2f1.py +21 -0
  249. scipy/special/tests/test_logsumexp.py +14 -0
  250. scipy/special/xsf/hyp2f1.h +3 -3
  251. scipy/stats/_ansari_swilk_statistics.cp312-win_amd64.dll.a +0 -0
  252. scipy/stats/_ansari_swilk_statistics.cp312-win_amd64.pyd +0 -0
  253. scipy/stats/_biasedurn.cp312-win_amd64.dll.a +0 -0
  254. scipy/stats/_biasedurn.cp312-win_amd64.pyd +0 -0
  255. scipy/stats/_continuous_distns.py +25 -15
  256. scipy/stats/_levy_stable/levyst.cp312-win_amd64.dll.a +0 -0
  257. scipy/stats/_levy_stable/levyst.cp312-win_amd64.pyd +0 -0
  258. scipy/stats/_mvn.cp312-win_amd64.dll.a +0 -0
  259. scipy/stats/_mvn.cp312-win_amd64.pyd +0 -0
  260. scipy/stats/_qmc_cy.cp312-win_amd64.dll.a +0 -0
  261. scipy/stats/_qmc_cy.cp312-win_amd64.pyd +0 -0
  262. scipy/stats/_rcont/rcont.cp312-win_amd64.dll.a +0 -0
  263. scipy/stats/_rcont/rcont.cp312-win_amd64.pyd +0 -0
  264. scipy/stats/_sobol.cp312-win_amd64.dll.a +0 -0
  265. scipy/stats/_sobol.cp312-win_amd64.pyd +0 -0
  266. scipy/stats/_stats.cp312-win_amd64.dll.a +0 -0
  267. scipy/stats/_stats.cp312-win_amd64.pyd +0 -0
  268. scipy/stats/_stats_pythran.cp312-win_amd64.dll.a +0 -0
  269. scipy/stats/_stats_pythran.cp312-win_amd64.pyd +0 -0
  270. scipy/stats/_unuran/unuran_wrapper.cp312-win_amd64.dll.a +0 -0
  271. scipy/stats/_unuran/unuran_wrapper.cp312-win_amd64.pyd +0 -0
  272. scipy/stats/tests/test_distributions.py +22 -0
  273. scipy/version.py +2 -2
  274. scipy-1.15.3.dist-info/DELVEWHEEL +2 -0
  275. {scipy-1.15.2.dist-info → scipy-1.15.3.dist-info}/METADATA +2 -2
  276. {scipy-1.15.2.dist-info → scipy-1.15.3.dist-info}/RECORD +279 -279
  277. scipy-1.15.2.dist-info/DELVEWHEEL +0 -2
  278. /scipy-1.15.2-cp312-cp312-win_amd64.whl → /scipy-1.15.3-cp312-cp312-win_amd64.whl +0 -0
  279. {scipy-1.15.2.dist-info → scipy-1.15.3.dist-info}/LICENSE.txt +0 -0
  280. {scipy-1.15.2.dist-info → scipy-1.15.3.dist-info}/WHEEL +0 -0
@@ -115,7 +115,7 @@ def expm_multiply(A, B, start=None, stop=None, num=None,
115
115
  ----------
116
116
  A : transposable linear operator
117
117
  The operator whose exponential is of interest.
118
- B : ndarray
118
+ B : ndarray, sparse array
119
119
  The matrix or vector to be multiplied by the matrix exponential of A.
120
120
  start : scalar, optional
121
121
  The starting time point of the sequence.
@@ -443,7 +443,7 @@ class LazyOperatorNormInfo:
443
443
 
444
444
  def d(self, p):
445
445
  """
446
- Lazily estimate :math:`d_p(A) ~= || A^p ||^(1/p)`
446
+ Lazily estimate :math:`d_p(A) ~= || A^p ||^(1/p)`
447
447
  where :math:`||.||` is the 1-norm.
448
448
  """
449
449
  if p not in self._d:
@@ -702,7 +702,12 @@ def _expm_multiply_interval(A, B, start=None, stop=None, num=None,
702
702
  m_star, s = _fragment_3_1(norm_info, n0, tol, ell=ell)
703
703
 
704
704
  # Compute the expm action up to the initial time point.
705
- X[0] = _expm_multiply_simple_core(A, B, t_0, mu, m_star, s)
705
+ action_t0 = _expm_multiply_simple_core(A, B, t_0, mu, m_star, s)
706
+ if scipy.sparse.issparse(action_t0):
707
+ action_t0 = action_t0.toarray()
708
+ elif is_pydata_spmatrix(action_t0):
709
+ action_t0 = action_t0.todense()
710
+ X[0] = action_t0
706
711
 
707
712
  # Compute the expm action at the rest of the time points.
708
713
  if q <= s:
@@ -322,6 +322,10 @@ class LinearOperator:
322
322
  """Default implementation of _rmatvec; defers to adjoint."""
323
323
  if type(self)._adjoint == LinearOperator._adjoint:
324
324
  # _adjoint not overridden, prevent infinite recursion
325
+ if (hasattr(self, "_rmatmat")
326
+ and type(self)._rmatmat != LinearOperator._rmatmat):
327
+ # Try to use _rmatmat as a fallback
328
+ return self._rmatmat(x.reshape(-1, 1)).reshape(-1)
325
329
  raise NotImplementedError
326
330
  else:
327
331
  return self.H.matvec(x)
@@ -822,22 +826,22 @@ class MatrixLinearOperator(LinearOperator):
822
826
 
823
827
  def _adjoint(self):
824
828
  if self.__adj is None:
825
- self.__adj = _AdjointMatrixOperator(self)
829
+ self.__adj = _AdjointMatrixOperator(self.A)
826
830
  return self.__adj
827
831
 
832
+
828
833
  class _AdjointMatrixOperator(MatrixLinearOperator):
829
- def __init__(self, adjoint):
830
- self.A = adjoint.A.T.conj()
831
- self.__adjoint = adjoint
832
- self.args = (adjoint,)
833
- self.shape = adjoint.shape[1], adjoint.shape[0]
834
+ def __init__(self, adjoint_array):
835
+ self.A = adjoint_array.T.conj()
836
+ self.args = (adjoint_array,)
837
+ self.shape = adjoint_array.shape[1], adjoint_array.shape[0]
834
838
 
835
839
  @property
836
840
  def dtype(self):
837
- return self.__adjoint.dtype
841
+ return self.args[0].dtype
838
842
 
839
843
  def _adjoint(self):
840
- return self.__adjoint
844
+ return MatrixLinearOperator(self.args[0])
841
845
 
842
846
 
843
847
  class IdentityOperator(LinearOperator):
@@ -433,7 +433,8 @@ def gcrotmk(A, b, x0=None, *, rtol=1e-5, atol=0., maxiter=1000, M=None, callback
433
433
  ux = axpy(u, ux, ux.shape[0], -byc) # ux -= u*byc
434
434
 
435
435
  # cx := V H y
436
- hy = Q.dot(R.dot(y))
436
+ with np.errstate(invalid="ignore"):
437
+ hy = Q.dot(R.dot(y))
437
438
  cx = vs[0] * hy[0]
438
439
  for v, hyc in zip(vs[1:], hy[1:]):
439
440
  cx = axpy(v, cx, cx.shape[0], hyc) # cx += v*hyc
@@ -7,6 +7,7 @@ import pytest
7
7
  from numpy.testing import (assert_allclose, assert_, assert_equal,
8
8
  suppress_warnings)
9
9
  from scipy.sparse import SparseEfficiencyWarning
10
+ import scipy.sparse
10
11
  from scipy.sparse.linalg import aslinearoperator
11
12
  import scipy.linalg
12
13
  from scipy.sparse.linalg import expm as sp_expm
@@ -260,19 +261,28 @@ class TestExpmActionInterval:
260
261
  A = scipy.sparse.diags_array(np.arange(5),format='csr', dtype=int)
261
262
  B = np.ones(5, dtype=int)
262
263
  Aexpm = scipy.sparse.diags_array(np.exp(np.arange(5)),format='csr')
264
+ BI = np.identity(5, dtype=int)
265
+ BI_sparse = scipy.sparse.csr_array(BI)
263
266
  assert_allclose(expm_multiply(A,B,0,1)[-1], Aexpm.dot(B))
267
+ assert_allclose(np.diag(expm_multiply(A, BI_sparse, 0, 1)[-1]), Aexpm.dot(B))
264
268
 
265
269
  # Test A complex, B int
266
270
  A = scipy.sparse.diags_array(-1j*np.arange(5),format='csr', dtype=complex)
267
271
  B = np.ones(5, dtype=int)
268
272
  Aexpm = scipy.sparse.diags_array(np.exp(-1j*np.arange(5)),format='csr')
269
273
  assert_allclose(expm_multiply(A,B,0,1)[-1], Aexpm.dot(B))
274
+ assert_allclose(np.diag(expm_multiply(A, BI_sparse, 0, 1)[-1]), Aexpm.dot(B))
270
275
 
271
276
  # Test A int, B complex
272
277
  A = scipy.sparse.diags_array(np.arange(5),format='csr', dtype=int)
273
278
  B = np.full(5, 1j, dtype=complex)
274
279
  Aexpm = scipy.sparse.diags_array(np.exp(np.arange(5)),format='csr')
275
280
  assert_allclose(expm_multiply(A,B,0,1)[-1], Aexpm.dot(B))
281
+ BI = np.identity(5, dtype=complex)*1j
282
+ assert_allclose(
283
+ np.diag(expm_multiply(A, scipy.sparse.csr_array(BI), 0, 1)[-1]),
284
+ Aexpm.dot(B)
285
+ )
276
286
 
277
287
  def test_expm_multiply_interval_status_0(self):
278
288
  self._help_test_specific_expm_interval_status(0)
@@ -13,6 +13,7 @@ import scipy.sparse as sparse
13
13
 
14
14
  import scipy.sparse.linalg._interface as interface
15
15
  from scipy.sparse._sputils import matrix
16
+ from scipy._lib._gcutils import assert_deallocated, IS_PYPY
16
17
 
17
18
 
18
19
  class TestLinearOperator:
@@ -512,6 +513,30 @@ def test_transpose_noconjugate():
512
513
  assert_equal(B.dot(v), Y.dot(v))
513
514
  assert_equal(B.T.dot(v), Y.T.dot(v))
514
515
 
516
+ def test_transpose_multiplication():
517
+ class MyMatrix(interface.LinearOperator):
518
+ def __init__(self, A):
519
+ super().__init__(A.dtype, A.shape)
520
+ self.A = A
521
+ def _matmat(self, other): return self.A @ other
522
+ def _rmatmat(self, other): return self.A.T @ other
523
+
524
+ A = MyMatrix(np.array([[1, 2], [3, 4]]))
525
+ X = np.array([1, 2])
526
+ B = np.array([[10, 20], [30, 40]])
527
+ X2 = X.reshape(-1, 1)
528
+ Y = np.array([[1, 2], [3, 4]])
529
+
530
+ assert_equal(A @ B, Y @ B)
531
+ assert_equal(B.T @ A, B.T @ Y)
532
+ assert_equal(A.T @ B, Y.T @ B)
533
+ assert_equal(A @ X, Y @ X)
534
+ assert_equal(X.T @ A, X.T @ Y)
535
+ assert_equal(A.T @ X, Y.T @ X)
536
+ assert_equal(A @ X2, Y @ X2)
537
+ assert_equal(X2.T @ A, X2.T @ Y)
538
+ assert_equal(A.T @ X2, Y.T @ X2)
539
+
515
540
  def test_sparse_matmat_exception():
516
541
  A = interface.LinearOperator((2, 2), matvec=lambda x: x)
517
542
  B = sparse.eye_array(2)
@@ -524,3 +549,13 @@ def test_sparse_matmat_exception():
524
549
  A @ np.identity(4)
525
550
  with assert_raises(ValueError):
526
551
  np.identity(4) @ A
552
+
553
+
554
+ @pytest.mark.skipif(IS_PYPY, reason="Test not meaningful on PyPy")
555
+ def test_MatrixLinearOperator_refcycle():
556
+ # gh-10634
557
+ # Test that MatrixLinearOperator can be automatically garbage collected
558
+ A = np.eye(2)
559
+ with assert_deallocated(interface.MatrixLinearOperator, A) as op:
560
+ op.adjoint()
561
+ del op
@@ -239,6 +239,10 @@ def test_expm_multiply(matrices):
239
239
  x = splin.expm_multiply(A_sparse, b)
240
240
  assert_allclose(x, x0)
241
241
 
242
+ x0 = splin.expm_multiply(A_dense, A_dense)
243
+ x = splin.expm_multiply(A_sparse, A_sparse)
244
+ assert_allclose(x.todense(), x0)
245
+
242
246
 
243
247
  def test_eq(same_matrix):
244
248
  sp_sparse, pd_sparse = same_matrix
@@ -1087,6 +1087,12 @@ class _TestCommon:
1087
1087
  datsp.sum(axis=1, out=datsp_out)
1088
1088
  assert_array_almost_equal(dat_out, datsp_out)
1089
1089
 
1090
+ # check that wrong shape out parameter raises
1091
+ with assert_raises(ValueError, match="output parameter.*wrong.*dimension"):
1092
+ datsp.sum(out=array([0]))
1093
+ with assert_raises(ValueError, match="output parameter.*wrong.*dimension"):
1094
+ datsp.sum(out=array([[0]] if self.is_array_test else 0))
1095
+
1090
1096
  def test_numpy_sum(self):
1091
1097
  # See gh-5987
1092
1098
  dat = array([[0, 1, 2],
@@ -1184,6 +1190,12 @@ class _TestCommon:
1184
1190
  datsp.mean(axis=1, out=datsp_out)
1185
1191
  assert_array_almost_equal(dat_out, datsp_out)
1186
1192
 
1193
+ # check that wrong shape out parameter raises
1194
+ with assert_raises(ValueError, match="output parameter.*wrong.*dimension"):
1195
+ datsp.mean(out=array([0]))
1196
+ with assert_raises(ValueError, match="output parameter.*wrong.*dimension"):
1197
+ datsp.mean(out=array([[0]] if self.is_array_test else 0))
1198
+
1187
1199
  def test_numpy_mean(self):
1188
1200
  # See gh-5987
1189
1201
  dat = array([[0, 1, 2],
@@ -142,7 +142,7 @@ class TestCommon1D:
142
142
  datsp.sum(axis=(0, 1))
143
143
  with pytest.raises(TypeError, match='axis must be an integer'):
144
144
  datsp.sum(axis=1.5)
145
- with pytest.raises(ValueError, match='dimensions do not match'):
145
+ with pytest.raises(ValueError, match='output parameter.*wrong.*dimension'):
146
146
  datsp.sum(axis=0, out=out)
147
147
 
148
148
  def test_numpy_sum(self, spcreator):
@@ -180,7 +180,7 @@ class TestCommon1D:
180
180
  datsp.mean(axis=(0, 1))
181
181
  with pytest.raises(TypeError, match='axis must be an integer'):
182
182
  datsp.mean(axis=1.5)
183
- with pytest.raises(ValueError, match='dimensions do not match'):
183
+ with pytest.raises(ValueError, match='output parameter.*wrong.*dimension'):
184
184
  datsp.mean(axis=1, out=out)
185
185
 
186
186
  def test_sum_dtype(self, spcreator):
@@ -209,17 +209,22 @@ class TestCommon1D:
209
209
  dat = np.array([0, 1, 2])
210
210
  datsp = spcreator(dat)
211
211
 
212
- dat_out = np.array([0])
213
- datsp_out = np.array([0])
212
+ dat_out = np.array(0)
213
+ datsp_out = np.array(0)
214
214
 
215
- dat.mean(out=dat_out, keepdims=True)
215
+ dat.mean(out=dat_out)
216
216
  datsp.mean(out=datsp_out)
217
217
  assert_allclose(dat_out, datsp_out)
218
218
 
219
- dat.mean(axis=0, out=dat_out, keepdims=True)
219
+ dat.mean(axis=0, out=dat_out)
220
220
  datsp.mean(axis=0, out=datsp_out)
221
221
  assert_allclose(dat_out, datsp_out)
222
222
 
223
+ with pytest.raises(ValueError, match="output parameter.*dimension"):
224
+ datsp.mean(out=np.array([0]))
225
+ with pytest.raises(ValueError, match="output parameter.*dimension"):
226
+ datsp.mean(out=np.array([[0]]))
227
+
223
228
  def test_numpy_mean(self, spcreator):
224
229
  dat = np.array([0, 1, 2])
225
230
  datsp = spcreator(dat)
Binary file
Binary file
Binary file
Binary file
@@ -1181,6 +1181,105 @@ class Test_HalfspaceIntersection:
1181
1181
 
1182
1182
  assert_allclose(hs.dual_points, qhalf_points)
1183
1183
 
1184
+ @pytest.mark.parametrize("k", range(1,4))
1185
+ def test_halfspace_batch(self, k):
1186
+ # Test that we can add halfspaces a few at a time
1187
+ big_square = np.array([[ 1., 0., -2.],
1188
+ [-1., 0., -2.],
1189
+ [ 0., 1., -2.],
1190
+ [ 0., -1., -2.]])
1191
+
1192
+ small_square = np.array([[ 1., 0., -1.],
1193
+ [-1., 0., -1.],
1194
+ [ 0., 1., -1.],
1195
+ [ 0., -1., -1.]])
1196
+
1197
+ hs = qhull.HalfspaceIntersection(big_square,
1198
+ np.array([0.3141, 0.2718]),
1199
+ incremental=True)
1200
+
1201
+ hs.add_halfspaces(small_square[0:k,:])
1202
+ hs.add_halfspaces(small_square[k:4,:])
1203
+ hs.close()
1204
+
1205
+ # Check the intersections are correct (they are the corners of the small square)
1206
+ expected_intersections = np.array([[1., 1.],
1207
+ [1., -1.],
1208
+ [-1., 1.],
1209
+ [-1., -1.]])
1210
+ actual_intersections = hs.intersections
1211
+ # They may be in any order, so just check that under some permutation
1212
+ # expected=actual.
1213
+
1214
+ ind1 = np.lexsort((actual_intersections[:, 1], actual_intersections[:, 0]))
1215
+ ind2 = np.lexsort((expected_intersections[:, 1], expected_intersections[:, 0]))
1216
+ assert_allclose(actual_intersections[ind1], expected_intersections[ind2])
1217
+
1218
+
1219
+ @pytest.mark.parametrize("halfspaces", [
1220
+ (np.array([-0.70613882, -0.45589431, 0.04178256])),
1221
+ (np.array([[-0.70613882, -0.45589431, 0.04178256],
1222
+ [0.70807342, -0.45464871, -0.45969769],
1223
+ [0., 0.76515026, -0.35614825]])),
1224
+ ])
1225
+ def test_gh_19865(self, halfspaces):
1226
+ # starting off with a feasible interior point and
1227
+ # adding halfspaces for which it is no longer feasible
1228
+ # should result in an error rather than a problematic
1229
+ # intersection polytope
1230
+ initial_square = np.array(
1231
+ [[1, 0, -1], [0, 1, -1], [-1, 0, -1], [0, -1, -1]]
1232
+ )
1233
+ incremental_intersector = qhull.HalfspaceIntersection(initial_square,
1234
+ np.zeros(2),
1235
+ incremental=True)
1236
+ with pytest.raises(qhull.QhullError, match="feasible.*-0.706.*"):
1237
+ incremental_intersector.add_halfspaces(halfspaces)
1238
+
1239
+
1240
+ def test_gh_19865_3d(self):
1241
+ # 3d case where closed half space is enforced for
1242
+ # feasibility
1243
+ halfspaces = np.array([[1, 1, 1, -1], # doesn't exclude origin
1244
+ [-1, -1, -1, -1], # doesn't exclude origin
1245
+ [1, 0, 0, 0]]) # the origin is on the line
1246
+ initial_cube = np.array([[1, 0, 0, -1],
1247
+ [-1, 0, 0, -1],
1248
+ [0, 1, 0, -1],
1249
+ [0, -1, 0, -1],
1250
+ [0, 0, 1, -1],
1251
+ [0, 0, -1, -1]])
1252
+ incremental_intersector = qhull.HalfspaceIntersection(initial_cube,
1253
+ np.zeros(3),
1254
+ incremental=True)
1255
+ with pytest.raises(qhull.QhullError, match="feasible.*[1 0 0 0]"):
1256
+ incremental_intersector.add_halfspaces(halfspaces)
1257
+
1258
+
1259
+ def test_2d_add_halfspace_input(self):
1260
+ # incrementally added halfspaces should respect the 2D
1261
+ # array shape requirement
1262
+ initial_square = np.array(
1263
+ [[1, 0, -1], [0, 1, -1], [-1, 0, -1], [0, -1, -1]]
1264
+ )
1265
+ incremental_intersector = qhull.HalfspaceIntersection(initial_square,
1266
+ np.zeros(2),
1267
+ incremental=True)
1268
+ with pytest.raises(ValueError, match="2D array"):
1269
+ incremental_intersector.add_halfspaces(np.ones((4, 4, 4)))
1270
+
1271
+ def test_1d_add_halfspace_input(self):
1272
+ # we do allow 1D `halfspaces` input to add_halfspaces()
1273
+ initial_square = np.array(
1274
+ [[1, 0, -1], [0, 1, -1], [-1, 0, -1], [0, -1, -1]]
1275
+ )
1276
+ incremental_intersector = qhull.HalfspaceIntersection(initial_square,
1277
+ np.zeros(2),
1278
+ incremental=True)
1279
+ assert_allclose(incremental_intersector.dual_vertices, np.arange(4))
1280
+ incremental_intersector.add_halfspaces(np.array([2, 2, -1]))
1281
+ assert_allclose(incremental_intersector.dual_vertices, np.arange(5))
1282
+
1184
1283
 
1185
1284
  @pytest.mark.parametrize("diagram_type", [Voronoi, qhull.Delaunay])
1186
1285
  def test_gh_20623(diagram_type):
@@ -168,10 +168,6 @@ def test_from_quat_wrong_shape():
168
168
  [[4, 5, 6, 7]]
169
169
  ]))
170
170
 
171
- # 0-length 2d array
172
- with pytest.raises(ValueError, match='Expected `quat` to have shape'):
173
- Rotation.from_quat(np.array([]).reshape((0, 4)))
174
-
175
171
 
176
172
  def test_zero_norms_from_quat():
177
173
  x = np.array([
@@ -1611,18 +1607,23 @@ def test_slerp_rot_is_rotation():
1611
1607
  t = np.array([0, 1])
1612
1608
  Slerp(t, r)
1613
1609
 
1610
+ SLERP_EXCEPTION_MESSAGE = "must be a sequence of at least 2 rotations"
1614
1611
 
1615
1612
  def test_slerp_single_rot():
1616
- msg = "must be a sequence of at least 2 rotations"
1617
- with pytest.raises(ValueError, match=msg):
1618
- r = Rotation.from_quat([1, 2, 3, 4])
1613
+ r = Rotation.from_quat([1, 2, 3, 4])
1614
+ with pytest.raises(ValueError, match=SLERP_EXCEPTION_MESSAGE):
1619
1615
  Slerp([1], r)
1620
1616
 
1621
1617
 
1618
+ def test_slerp_rot_len0():
1619
+ r = Rotation.random()
1620
+ with pytest.raises(ValueError, match=SLERP_EXCEPTION_MESSAGE):
1621
+ Slerp([], r)
1622
+
1623
+
1622
1624
  def test_slerp_rot_len1():
1623
- msg = "must be a sequence of at least 2 rotations"
1624
- with pytest.raises(ValueError, match=msg):
1625
- r = Rotation.from_quat([[1, 2, 3, 4]])
1625
+ r = Rotation.random(1)
1626
+ with pytest.raises(ValueError, match=SLERP_EXCEPTION_MESSAGE):
1626
1627
  Slerp([1], r)
1627
1628
 
1628
1629
 
@@ -2015,3 +2016,173 @@ def test_compare_as_davenport_as_euler():
2015
2016
  eul = rot.as_euler(seq)
2016
2017
  dav = rot.as_davenport(ax, order)
2017
2018
  assert_allclose(eul, dav, rtol=1e-12)
2019
+
2020
+
2021
+ def test_zero_rotation_construction():
2022
+ r = Rotation.random(num=0)
2023
+ assert len(r) == 0
2024
+
2025
+ r_ide = Rotation.identity(num=0)
2026
+ assert len(r_ide) == 0
2027
+
2028
+ r_get = Rotation.random(num=3)[[]]
2029
+ assert len(r_get) == 0
2030
+
2031
+ r_quat = Rotation.from_quat(np.zeros((0, 4)))
2032
+ assert len(r_quat) == 0
2033
+
2034
+ r_matrix = Rotation.from_matrix(np.zeros((0, 3, 3)))
2035
+ assert len(r_matrix) == 0
2036
+
2037
+ r_euler = Rotation.from_euler("xyz", np.zeros((0, 3)))
2038
+ assert len(r_euler) == 0
2039
+
2040
+ r_vec = Rotation.from_rotvec(np.zeros((0, 3)))
2041
+ assert len(r_vec) == 0
2042
+
2043
+ r_dav = Rotation.from_davenport(np.eye(3), "extrinsic", np.zeros((0, 3)))
2044
+ assert len(r_dav) == 0
2045
+
2046
+ r_mrp = Rotation.from_mrp(np.zeros((0, 3)))
2047
+ assert len(r_mrp) == 0
2048
+
2049
+
2050
+ def test_zero_rotation_representation():
2051
+ r = Rotation.random(num=0)
2052
+ assert r.as_quat().shape == (0, 4)
2053
+ assert r.as_matrix().shape == (0, 3, 3)
2054
+ assert r.as_euler("xyz").shape == (0, 3)
2055
+ assert r.as_rotvec().shape == (0, 3)
2056
+ assert r.as_mrp().shape == (0, 3)
2057
+ assert r.as_davenport(np.eye(3), "extrinsic").shape == (0, 3)
2058
+
2059
+
2060
+ def test_zero_rotation_array_rotation():
2061
+ r = Rotation.random(num=0)
2062
+
2063
+ v = np.array([1, 2, 3])
2064
+ v_rotated = r.apply(v)
2065
+ assert v_rotated.shape == (0, 3)
2066
+
2067
+ v0 = np.zeros((0, 3))
2068
+ v0_rot = r.apply(v0)
2069
+ assert v0_rot.shape == (0, 3)
2070
+
2071
+ v2 = np.ones((2, 3))
2072
+ with pytest.raises(
2073
+ ValueError, match="Expected equal numbers of rotations and vectors"):
2074
+ r.apply(v2)
2075
+
2076
+
2077
+ def test_zero_rotation_multiplication():
2078
+ r = Rotation.random(num=0)
2079
+
2080
+ r_single = Rotation.random()
2081
+ r_mult_left = r * r_single
2082
+ assert len(r_mult_left) == 0
2083
+
2084
+ r_mult_right = r_single * r
2085
+ assert len(r_mult_right) == 0
2086
+
2087
+ r0 = Rotation.random(0)
2088
+ r_mult = r * r0
2089
+ assert len(r_mult) == 0
2090
+
2091
+ msg_rotation_error = "Expected equal number of rotations"
2092
+ r2 = Rotation.random(2)
2093
+ with pytest.raises(ValueError, match=msg_rotation_error):
2094
+ r0 * r2
2095
+
2096
+ with pytest.raises(ValueError, match=msg_rotation_error):
2097
+ r2 * r0
2098
+
2099
+
2100
+ def test_zero_rotation_concatentation():
2101
+ r = Rotation.random(num=0)
2102
+
2103
+ r0 = Rotation.concatenate([r, r])
2104
+ assert len(r0) == 0
2105
+
2106
+ r1 = r.concatenate([Rotation.random(), r])
2107
+ assert len(r1) == 1
2108
+
2109
+ r3 = r.concatenate([Rotation.random(3), r])
2110
+ assert len(r3) == 3
2111
+
2112
+ r4 = r.concatenate([r, Rotation.random(4)])
2113
+ assert len(r4) == 4
2114
+
2115
+
2116
+ def test_zero_rotation_power():
2117
+ r = Rotation.random(num=0)
2118
+ for pp in [-1.5, -1, 0, 1, 1.5]:
2119
+ pow0 = r**pp
2120
+ assert len(pow0) == 0
2121
+
2122
+
2123
+ def test_zero_rotation_inverse():
2124
+ r = Rotation.random(num=0)
2125
+ r_inv = r.inv()
2126
+ assert len(r_inv) == 0
2127
+
2128
+
2129
+ def test_zero_rotation_magnitude():
2130
+ r = Rotation.random(num=0)
2131
+ magnitude = r.magnitude()
2132
+ assert magnitude.shape == (0,)
2133
+
2134
+
2135
+ def test_zero_rotation_mean():
2136
+ r = Rotation.random(num=0)
2137
+ with pytest.raises(ValueError, match="Mean of an empty rotation set is undefined."):
2138
+ r.mean()
2139
+
2140
+
2141
+ def test_zero_rotation_approx_equal():
2142
+ r = Rotation.random(0)
2143
+ assert r.approx_equal(Rotation.random(0)).shape == (0,)
2144
+ assert r.approx_equal(Rotation.random()).shape == (0,)
2145
+ assert Rotation.random().approx_equal(r).shape == (0,)
2146
+
2147
+ approx_msg = "Expected equal number of rotations"
2148
+ r3 = Rotation.random(2)
2149
+ with pytest.raises(ValueError, match=approx_msg):
2150
+ r.approx_equal(r3)
2151
+
2152
+ with pytest.raises(ValueError, match=approx_msg):
2153
+ r3.approx_equal(r)
2154
+
2155
+
2156
+ def test_zero_rotation_get_set():
2157
+ r = Rotation.random(0)
2158
+
2159
+ r_get = r[[]]
2160
+ assert len(r_get) == 0
2161
+
2162
+ r_slice = r[:0]
2163
+ assert len(r_slice) == 0
2164
+
2165
+ with pytest.raises(IndexError):
2166
+ r[[0]]
2167
+
2168
+ with pytest.raises(IndexError):
2169
+ r[[True]]
2170
+
2171
+ with pytest.raises(IndexError):
2172
+ r[0] = Rotation.random()
2173
+
2174
+
2175
+ def test_boolean_indexes():
2176
+ r = Rotation.random(3)
2177
+
2178
+ r0 = r[[False, False, False]]
2179
+ assert len(r0) == 0
2180
+
2181
+ r1 = r[[False, True, False]]
2182
+ assert len(r1) == 1
2183
+
2184
+ r3 = r[[True, True, True]]
2185
+ assert len(r3) == 3
2186
+
2187
+ with pytest.raises(IndexError):
2188
+ r[[True, True]]
Binary file
Binary file
Binary file