spacecore 0.3.2__tar.gz → 0.4.1__tar.gz

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 (444) hide show
  1. spacecore-0.4.1/CHANGELOG.md +637 -0
  2. {spacecore-0.3.2 → spacecore-0.4.1}/MANIFEST.in +0 -1
  3. spacecore-0.4.1/PKG-INFO +342 -0
  4. spacecore-0.4.1/README.md +296 -0
  5. spacecore-0.4.1/docs/dev/0.4.1-bench-surface.md +159 -0
  6. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/adr/003_space_hierarchy.md +2 -2
  7. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/adr/005_space_subclasses_and_capabilities.md +2 -2
  8. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/adr/008_linop_subclasses.md +2 -2
  9. spacecore-0.4.1/docs/dev/adr/013_tree_structured_spaces.md +54 -0
  10. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/adr/014_check_policy.md +10 -2
  11. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/adr/015_dtype_default_vs_scalar_field.md +5 -3
  12. spacecore-0.4.1/docs/dev/adr/016_kernel_layers.md +242 -0
  13. spacecore-0.4.1/docs/dev/adr/017_tensor_product_spaces.md +131 -0
  14. spacecore-0.4.1/docs/dev/adr/018_external_optimizer_adapters.md +111 -0
  15. spacecore-0.4.1/docs/dev/adr/019_everyday_toolbox.md +159 -0
  16. spacecore-0.4.1/docs/dev/adr/020_sets_and_projection.md +108 -0
  17. spacecore-0.4.1/docs/dev/adr/021_lazy_operator_algebra_and_simplification.md +131 -0
  18. spacecore-0.4.1/docs/dev/adr/022_caching.md +156 -0
  19. spacecore-0.4.1/docs/dev/adr/023_benchmark_framework.md +415 -0
  20. spacecore-0.4.1/docs/dev/adr/README.md +77 -0
  21. spacecore-0.4.1/docs/dev/adr/template.md +33 -0
  22. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/contributing/architecture.md +8 -10
  23. spacecore-0.4.1/docs/dev/contributing/linop_generators.md +47 -0
  24. spacecore-0.4.1/docs/dev/current.md +156 -0
  25. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/api/context.rst +3 -0
  26. spacecore-0.4.1/docs/source/api/functionals.rst +160 -0
  27. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/api/index.rst +1 -0
  28. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/api/linops.rst +21 -7
  29. spacecore-0.4.1/docs/source/api/optimize.rst +59 -0
  30. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/api/spaces.rst +17 -26
  31. spacecore-0.4.1/docs/source/design/backend_conformance.rst +452 -0
  32. spacecore-0.4.1/docs/source/design/backend_deviations.rst +138 -0
  33. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/design/batching.rst +6 -0
  34. spacecore-0.4.1/docs/source/design/batching_test_policy.rst +78 -0
  35. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/design/capability_dispatch.rst +2 -2
  36. spacecore-0.4.1/docs/source/design/checking_policy.rst +100 -0
  37. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/design/context_ownership.rst +14 -10
  38. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/design/conversion_policy.rst +3 -3
  39. spacecore-0.4.1/docs/source/design/dtype_policy.rst +92 -0
  40. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/design/index.rst +5 -0
  41. spacecore-0.4.1/docs/source/design/kernels_policy.rst +218 -0
  42. spacecore-0.4.1/docs/source/design/tree_spaces.rst +192 -0
  43. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/dev/contributing.rst +6 -0
  44. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/index.rst +8 -4
  45. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/release_notes.rst +154 -0
  46. spacecore-0.4.1/docs/source/tutorials/01_backend_and_context.rst +349 -0
  47. spacecore-0.4.1/docs/source/tutorials/02_linear_algebra.rst +289 -0
  48. spacecore-0.4.1/docs/source/tutorials/03_functionals.rst +270 -0
  49. spacecore-0.4.1/docs/source/tutorials/04_tree_spaces.rst +302 -0
  50. spacecore-0.4.1/docs/source/tutorials/05_weighted_tikhonov.rst +285 -0
  51. spacecore-0.4.1/docs/source/tutorials/06_optimal_transport.rst +263 -0
  52. spacecore-0.4.1/docs/source/tutorials/07_manifold_descent.rst +235 -0
  53. spacecore-0.4.1/docs/source/tutorials/08_pdhg_conic_program.rst +257 -0
  54. spacecore-0.4.1/docs/source/tutorials/09_kernels_and_fusion.rst +531 -0
  55. spacecore-0.4.1/docs/source/tutorials/index.rst +42 -0
  56. {spacecore-0.3.2 → spacecore-0.4.1}/pyproject.toml +20 -1
  57. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/__init__.py +49 -17
  58. spacecore-0.4.1/spacecore/_batching.py +59 -0
  59. spacecore-0.4.1/spacecore/_check_policy.py +88 -0
  60. spacecore-0.4.1/spacecore/_checks.py +137 -0
  61. spacecore-0.4.1/spacecore/_contextual/_bound.py +173 -0
  62. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/_contextual/_state.py +84 -27
  63. spacecore-0.4.1/spacecore/_repr.py +150 -0
  64. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/_version.py +1 -1
  65. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/backend/__init__.py +3 -0
  66. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/backend/_context.py +59 -21
  67. spacecore-0.4.1/spacecore/backend/_eager.py +178 -0
  68. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/backend/_ops.py +227 -11
  69. spacecore-0.4.1/spacecore/backend/cupy/_ops.py +154 -0
  70. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/backend/jax/_ops.py +31 -19
  71. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/backend/jax/_pytree.py +1 -1
  72. spacecore-0.4.1/spacecore/backend/numpy/_ops.py +298 -0
  73. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/backend/torch/_ops.py +33 -205
  74. spacecore-0.4.1/spacecore/functional/__init__.py +52 -0
  75. spacecore-0.4.1/spacecore/functional/_base.py +161 -0
  76. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/functional/_composed.py +11 -6
  77. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/functional/_linear.py +48 -54
  78. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/functional/_quadratic.py +16 -34
  79. spacecore-0.4.1/spacecore/functional/tools/__init__.py +29 -0
  80. spacecore-0.4.1/spacecore/functional/tools/_coordinate.py +72 -0
  81. spacecore-0.4.1/spacecore/functional/tools/_entropy.py +148 -0
  82. spacecore-0.4.1/spacecore/functional/tools/_huber.py +79 -0
  83. spacecore-0.4.1/spacecore/functional/tools/_least_squares.py +114 -0
  84. spacecore-0.4.1/spacecore/functional/tools/_norms.py +157 -0
  85. spacecore-0.4.1/spacecore/functional/tools/_proximal.py +226 -0
  86. spacecore-0.4.1/spacecore/functional/tools/_spectral.py +126 -0
  87. spacecore-0.4.1/spacecore/kernels/__init__.py +81 -0
  88. spacecore-0.4.1/spacecore/kernels/core/__init__.py +36 -0
  89. spacecore-0.4.1/spacecore/kernels/core/_rules.py +154 -0
  90. spacecore-0.4.1/spacecore/kernels/core/algebra.py +245 -0
  91. spacecore-0.4.1/spacecore/kernels/core/dense.py +114 -0
  92. spacecore-0.4.1/spacecore/kernels/core/diagonal.py +114 -0
  93. spacecore-0.4.1/spacecore/kernels/core/functional.py +153 -0
  94. spacecore-0.4.1/spacecore/kernels/core/sparse.py +123 -0
  95. spacecore-0.4.1/spacecore/kernels/specs/__init__.py +66 -0
  96. spacecore-0.4.1/spacecore/kernels/specs/_batched.py +234 -0
  97. spacecore-0.4.1/spacecore/kernels/specs/_dispatch.py +289 -0
  98. spacecore-0.4.1/spacecore/kernels/specs/_policy.py +209 -0
  99. spacecore-0.4.1/spacecore/kernels/specs/_registry.py +117 -0
  100. spacecore-0.4.1/spacecore/kernels/specs/block_batched.py +358 -0
  101. spacecore-0.4.1/spacecore/kernels/specs/block_diagonal.py +91 -0
  102. spacecore-0.4.1/spacecore/kernels/specs/composed.py +90 -0
  103. spacecore-0.4.1/spacecore/kernels/specs/composed_simplify.py +140 -0
  104. spacecore-0.4.1/spacecore/kernels/specs/stacked_batched.py +167 -0
  105. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/linalg/_cg.py +46 -16
  106. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/linalg/_lanczos.py +10 -8
  107. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/linalg/_lsqr.py +27 -20
  108. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/linalg/_power.py +19 -15
  109. spacecore-0.4.1/spacecore/linalg/_utils.py +211 -0
  110. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/linop/__init__.py +3 -2
  111. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/linop/_algebra.py +316 -161
  112. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/linop/_base.py +80 -13
  113. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/linop/_dense.py +24 -103
  114. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/linop/_diagonal.py +18 -102
  115. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/linop/_metric.py +3 -3
  116. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/linop/_sparse.py +53 -110
  117. spacecore-0.4.1/spacecore/linop/tree/__init__.py +14 -0
  118. {spacecore-0.3.2/spacecore/linop/product → spacecore-0.4.1/spacecore/linop/tree}/_base.py +27 -18
  119. spacecore-0.4.1/spacecore/linop/tree/_block.py +482 -0
  120. {spacecore-0.3.2/spacecore/linop/product → spacecore-0.4.1/spacecore/linop/tree}/_from_single.py +52 -23
  121. {spacecore-0.3.2/spacecore/linop/product → spacecore-0.4.1/spacecore/linop/tree}/_to_single.py +51 -22
  122. spacecore-0.4.1/spacecore/optimize/__init__.py +20 -0
  123. spacecore-0.4.1/spacecore/optimize/_common.py +71 -0
  124. spacecore-0.4.1/spacecore/optimize/_optax.py +154 -0
  125. spacecore-0.4.1/spacecore/optimize/_scipy.py +260 -0
  126. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/space/__init__.py +8 -12
  127. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/space/base/_coordinate.py +12 -4
  128. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/space/base/_inner_product.py +18 -1
  129. spacecore-0.4.1/spacecore/space/base/_space.py +137 -0
  130. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/space/checks/__init__.py +2 -4
  131. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/space/checks/_base.py +39 -81
  132. spacecore-0.4.1/spacecore/space/checks/_coordinate.py +10 -0
  133. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/space/concrete/__init__.py +4 -3
  134. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/space/concrete/_dense_coordinate.py +51 -17
  135. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/space/concrete/_dense_vector.py +23 -22
  136. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/space/concrete/_hermitian.py +22 -19
  137. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/space/concrete/_stacked.py +79 -38
  138. spacecore-0.4.1/spacecore/space/concrete/_tree_space.py +930 -0
  139. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/types/_array.py +2 -0
  140. spacecore-0.4.1/spacecore.egg-info/PKG-INFO +342 -0
  141. spacecore-0.4.1/spacecore.egg-info/SOURCES.txt +346 -0
  142. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore.egg-info/requires.txt +7 -1
  143. spacecore-0.4.1/tests/_conformance.py +318 -0
  144. spacecore-0.4.1/tests/backend/_conformance.py +41 -0
  145. spacecore-0.4.1/tests/backend/_references.py +731 -0
  146. spacecore-0.4.1/tests/backend/conftest.py +80 -0
  147. spacecore-0.4.1/tests/backend/test_backend_family.py +79 -0
  148. spacecore-0.4.1/tests/backend/test_context.py +435 -0
  149. spacecore-0.4.1/tests/backend/test_cupy_ops.py +153 -0
  150. spacecore-0.4.1/tests/backend/test_jax_ops.py +299 -0
  151. spacecore-0.4.1/tests/backend/test_jax_pytree_class.py +165 -0
  152. spacecore-0.4.1/tests/backend/test_lazy_namespace.py +59 -0
  153. spacecore-0.4.1/tests/backend/test_numpy_ops.py +191 -0
  154. spacecore-0.4.1/tests/backend/test_operations.py +1388 -0
  155. spacecore-0.4.1/tests/backend/test_torch_ops.py +223 -0
  156. spacecore-0.4.1/tests/backend/test_types_protocols.py +251 -0
  157. spacecore-0.4.1/tests/bench/test_bare_baseline.py +49 -0
  158. spacecore-0.4.1/tests/bench/test_bench_smoke.py +581 -0
  159. spacecore-0.4.1/tests/bench/test_macro_aggregate.py +140 -0
  160. spacecore-0.4.1/tests/bench/test_macro_dashboard.py +200 -0
  161. spacecore-0.4.1/tests/bench/test_macro_runner_smoke.py +220 -0
  162. spacecore-0.4.1/tests/bench/test_macro_schema.py +162 -0
  163. spacecore-0.4.1/tests/bench/test_regimes.py +131 -0
  164. spacecore-0.4.1/tests/context/conftest.py +26 -0
  165. spacecore-0.4.1/tests/context/test_check_policy.py +187 -0
  166. spacecore-0.4.1/tests/context/test_check_policy_helpers.py +147 -0
  167. spacecore-0.4.1/tests/context/test_checked_method.py +256 -0
  168. spacecore-0.4.1/tests/context/test_compatibility.py +254 -0
  169. spacecore-0.4.1/tests/context/test_context_bound.py +209 -0
  170. {spacecore-0.3.2 → spacecore-0.4.1}/tests/context/test_enable_checks.py +10 -8
  171. spacecore-0.4.1/tests/context/test_policies_errors.py +183 -0
  172. spacecore-0.4.1/tests/context/test_state_free_functions.py +331 -0
  173. spacecore-0.4.1/tests/functional/conftest.py +46 -0
  174. spacecore-0.4.1/tests/functional/test_composed_functional.py +222 -0
  175. spacecore-0.4.1/tests/functional/test_functional_base.py +254 -0
  176. spacecore-0.4.1/tests/functional/test_generated_functionals.py +266 -0
  177. spacecore-0.4.1/tests/functional/test_inner_product_functional.py +182 -0
  178. spacecore-0.4.1/tests/functional/test_linear_functional.py +82 -0
  179. spacecore-0.4.1/tests/functional/test_linop_quadratic_form.py +190 -0
  180. spacecore-0.4.1/tests/functional/test_matrix_free_linear_functional.py +170 -0
  181. {spacecore-0.3.2 → spacecore-0.4.1}/tests/functional/test_metric_gradient.py +7 -21
  182. spacecore-0.4.1/tests/functional/test_quadratic_form.py +117 -0
  183. spacecore-0.4.1/tests/functional/tools/test_battery_functionals.py +271 -0
  184. spacecore-0.4.1/tests/functional/tools/test_least_squares.py +107 -0
  185. spacecore-0.4.1/tests/functional/tools/test_proximal.py +269 -0
  186. spacecore-0.4.1/tests/functional/tools/test_spectral.py +137 -0
  187. spacecore-0.4.1/tests/generators/__init__.py +82 -0
  188. spacecore-0.4.1/tests/generators/_arrays.py +108 -0
  189. spacecore-0.4.1/tests/generators/_contexts.py +102 -0
  190. spacecore-0.4.1/tests/generators/_hermitian.py +77 -0
  191. spacecore-0.4.1/tests/generators/_metrics.py +79 -0
  192. spacecore-0.4.1/tests/generators/_params.py +60 -0
  193. spacecore-0.4.1/tests/generators/_protocol.py +18 -0
  194. spacecore-0.4.1/tests/generators/_seed.py +28 -0
  195. spacecore-0.4.1/tests/generators/_trees.py +108 -0
  196. spacecore-0.4.1/tests/generators/functionals.py +444 -0
  197. spacecore-0.4.1/tests/generators/linops.py +552 -0
  198. spacecore-0.4.1/tests/generators/spaces.py +590 -0
  199. spacecore-0.4.1/tests/generators/test_registry_completeness.py +155 -0
  200. spacecore-0.4.1/tests/generators/test_smoke.py +89 -0
  201. {spacecore-0.3.2 → spacecore-0.4.1}/tests/integration/test_imports.py +1 -1
  202. {spacecore-0.3.2 → spacecore-0.4.1}/tests/integration/test_public_api.py +36 -10
  203. {spacecore-0.3.2 → spacecore-0.4.1}/tests/integration/test_smoke_numpy.py +1 -1
  204. spacecore-0.4.1/tests/integration/test_smoke_torch.py +63 -0
  205. spacecore-0.4.1/tests/kernels/conftest.py +22 -0
  206. spacecore-0.4.1/tests/kernels/test_core_kernel_dispatch.py +251 -0
  207. spacecore-0.4.1/tests/kernels/test_kernel_dispatch.py +574 -0
  208. spacecore-0.4.1/tests/kernels/test_kernel_registry.py +143 -0
  209. spacecore-0.4.1/tests/kernels/test_kernel_spec.py +109 -0
  210. spacecore-0.4.1/tests/kernels/test_kernels_match_generic.py +506 -0
  211. spacecore-0.4.1/tests/kernels/test_materialized_cache.py +266 -0
  212. spacecore-0.4.1/tests/linalg/_helpers.py +74 -0
  213. spacecore-0.4.1/tests/linalg/conftest.py +19 -0
  214. spacecore-0.4.1/tests/linalg/test_cg.py +282 -0
  215. spacecore-0.4.1/tests/linalg/test_core_resolution.py +110 -0
  216. spacecore-0.4.1/tests/linalg/test_expm_multiply.py +193 -0
  217. spacecore-0.4.1/tests/linalg/test_generated_solver_matrix.py +129 -0
  218. spacecore-0.4.1/tests/linalg/test_lanczos.py +260 -0
  219. spacecore-0.4.1/tests/linalg/test_lsqr.py +236 -0
  220. spacecore-0.4.1/tests/linalg/test_power_iteration.py +377 -0
  221. spacecore-0.4.1/tests/linalg/test_result_types.py +117 -0
  222. spacecore-0.4.1/tests/linalg/test_solver_contracts.py +114 -0
  223. spacecore-0.4.1/tests/linalg/test_utils.py +186 -0
  224. spacecore-0.4.1/tests/linops/conftest.py +35 -0
  225. spacecore-0.4.1/tests/linops/test_algebra_factories.py +354 -0
  226. spacecore-0.4.1/tests/linops/test_algebra_linops.py +986 -0
  227. spacecore-0.4.1/tests/linops/test_block_diagonal_linop.py +378 -0
  228. spacecore-0.4.1/tests/linops/test_block_matrix_linop.py +156 -0
  229. spacecore-0.4.1/tests/linops/test_dense_linop.py +516 -0
  230. spacecore-0.4.1/tests/linops/test_diagonal_linop.py +327 -0
  231. spacecore-0.4.1/tests/linops/test_fuse.py +323 -0
  232. spacecore-0.4.1/tests/linops/test_fused_algebra_overhead.py +224 -0
  233. spacecore-0.4.1/tests/linops/test_generated_linop_laws.py +149 -0
  234. spacecore-0.4.1/tests/linops/test_linop_base.py +386 -0
  235. spacecore-0.4.1/tests/linops/test_linop_jit.py +201 -0
  236. spacecore-0.4.1/tests/linops/test_metric_helpers.py +255 -0
  237. spacecore-0.4.1/tests/linops/test_sparse_linop.py +359 -0
  238. spacecore-0.4.1/tests/linops/test_stacked_linop.py +289 -0
  239. spacecore-0.4.1/tests/linops/test_sum_to_single_linop.py +290 -0
  240. spacecore-0.4.1/tests/linops/test_tree_helpers.py +100 -0
  241. spacecore-0.4.1/tests/linops/test_tree_linop_base.py +85 -0
  242. spacecore-0.4.1/tests/optim/test_cached_member_checks.py +157 -0
  243. spacecore-0.4.1/tests/optimize/__init__.py +0 -0
  244. spacecore-0.4.1/tests/optimize/_helpers.py +54 -0
  245. spacecore-0.4.1/tests/optimize/test_contracts.py +126 -0
  246. spacecore-0.4.1/tests/optimize/test_line_search_scipy.py +89 -0
  247. spacecore-0.4.1/tests/optimize/test_metric_handoff.py +63 -0
  248. spacecore-0.4.1/tests/optimize/test_minimize_optax.py +113 -0
  249. spacecore-0.4.1/tests/optimize/test_minimize_scipy.py +133 -0
  250. spacecore-0.4.1/tests/spaces/__init__.py +0 -0
  251. spacecore-0.4.1/tests/spaces/_generated_helpers.py +52 -0
  252. spacecore-0.4.1/tests/spaces/conftest.py +40 -0
  253. spacecore-0.4.1/tests/spaces/test_check_batched.py +181 -0
  254. spacecore-0.4.1/tests/spaces/test_coordinate_space_base.py +113 -0
  255. spacecore-0.4.1/tests/spaces/test_dense_coordinate_space.py +189 -0
  256. spacecore-0.4.1/tests/spaces/test_dense_vector_space.py +70 -0
  257. spacecore-0.4.1/tests/spaces/test_elementwise_jordan_spaces.py +135 -0
  258. spacecore-0.4.1/tests/spaces/test_generated_dense_coordinate.py +132 -0
  259. spacecore-0.4.1/tests/spaces/test_generated_dense_vector.py +60 -0
  260. spacecore-0.4.1/tests/spaces/test_generated_inner_product.py +96 -0
  261. spacecore-0.4.1/tests/spaces/test_generated_jordan_space.py +111 -0
  262. spacecore-0.4.1/tests/spaces/test_generated_space_laws.py +34 -0
  263. spacecore-0.4.1/tests/spaces/test_generated_tree_space.py +105 -0
  264. spacecore-0.4.1/tests/spaces/test_hermitian_space.py +192 -0
  265. spacecore-0.4.1/tests/spaces/test_inner_product.py +164 -0
  266. spacecore-0.4.1/tests/spaces/test_inner_product_space_base.py +114 -0
  267. spacecore-0.4.1/tests/spaces/test_jordan_algebra_spaces.py +182 -0
  268. spacecore-0.4.1/tests/spaces/test_space_base.py +149 -0
  269. spacecore-0.4.1/tests/spaces/test_space_checks.py +392 -0
  270. spacecore-0.4.1/tests/spaces/test_stacked_space.py +335 -0
  271. spacecore-0.4.1/tests/spaces/test_star_space_base.py +80 -0
  272. spacecore-0.4.1/tests/spaces/test_tree_space.py +488 -0
  273. spacecore-0.4.1/tests/spaces/test_tree_spectral_decomposition.py +79 -0
  274. spacecore-0.4.1/tests/spaces/test_vector_space_base.py +82 -0
  275. spacecore-0.4.1/tests/test_repr.py +433 -0
  276. spacecore-0.4.1/tests/test_weighted_tikhonov.py +80 -0
  277. spacecore-0.4.1/tutorials/01_backend_and_context.ipynb +564 -0
  278. spacecore-0.4.1/tutorials/02_linear_algebra.ipynb +502 -0
  279. spacecore-0.4.1/tutorials/03_functionals.ipynb +426 -0
  280. spacecore-0.4.1/tutorials/04_tree_spaces.ipynb +501 -0
  281. spacecore-0.4.1/tutorials/05_weighted_tikhonov.ipynb +476 -0
  282. spacecore-0.4.1/tutorials/06_optimal_transport.ipynb +445 -0
  283. spacecore-0.4.1/tutorials/07_manifold_descent.ipynb +354 -0
  284. spacecore-0.4.1/tutorials/08_pdhg_conic_program.ipynb +416 -0
  285. spacecore-0.4.1/tutorials/09_kernels_and_fusion.ipynb +810 -0
  286. spacecore-0.4.1/tutorials/README.md +50 -0
  287. spacecore-0.3.2/CHANGELOG.md +0 -315
  288. spacecore-0.3.2/PKG-INFO +0 -206
  289. spacecore-0.3.2/README.md +0 -165
  290. spacecore-0.3.2/docs/dev/adr/013_tree_structured_spaces.md +0 -36
  291. spacecore-0.3.2/docs/dev/adr/README.md +0 -71
  292. spacecore-0.3.2/docs/dev/current.md +0 -32
  293. spacecore-0.3.2/docs/source/api/functionals.rst +0 -80
  294. spacecore-0.3.2/docs/source/design/checking_policy.rst +0 -69
  295. spacecore-0.3.2/docs/source/design/dtype_policy.rst +0 -62
  296. spacecore-0.3.2/docs/source/tutorials/backend_ops.rst +0 -104
  297. spacecore-0.3.2/docs/source/tutorials/context.rst +0 -103
  298. spacecore-0.3.2/docs/source/tutorials/conversion_policy.rst +0 -102
  299. spacecore-0.3.2/docs/source/tutorials/index.rst +0 -88
  300. spacecore-0.3.2/docs/source/tutorials/linops.rst +0 -139
  301. spacecore-0.3.2/docs/source/tutorials/regularized_ot.rst +0 -662
  302. spacecore-0.3.2/docs/source/tutorials/spaces.rst +0 -124
  303. spacecore-0.3.2/docs/source/tutorials/weighted_tikhonov.rst +0 -194
  304. spacecore-0.3.2/examples/weighted_tikhonov.py +0 -267
  305. spacecore-0.3.2/spacecore/_batching.py +0 -18
  306. spacecore-0.3.2/spacecore/_checks.py +0 -95
  307. spacecore-0.3.2/spacecore/_contextual/_bound.py +0 -57
  308. spacecore-0.3.2/spacecore/_tree.py +0 -26
  309. spacecore-0.3.2/spacecore/backend/cupy/_ops.py +0 -290
  310. spacecore-0.3.2/spacecore/backend/numpy/_ops.py +0 -514
  311. spacecore-0.3.2/spacecore/functional/__init__.py +0 -17
  312. spacecore-0.3.2/spacecore/functional/_base.py +0 -138
  313. spacecore-0.3.2/spacecore/linalg/_utils.py +0 -122
  314. spacecore-0.3.2/spacecore/linop/product/__init__.py +0 -13
  315. spacecore-0.3.2/spacecore/linop/product/_block.py +0 -125
  316. spacecore-0.3.2/spacecore/space/_structure.py +0 -117
  317. spacecore-0.3.2/spacecore/space/base/_space.py +0 -49
  318. spacecore-0.3.2/spacecore/space/checks/_coordinate.py +0 -3
  319. spacecore-0.3.2/spacecore/space/checks/_product.py +0 -3
  320. spacecore-0.3.2/spacecore/space/concrete/_product.py +0 -686
  321. spacecore-0.3.2/spacecore.egg-info/PKG-INFO +0 -206
  322. spacecore-0.3.2/spacecore.egg-info/SOURCES.txt +0 -219
  323. spacecore-0.3.2/tests/backend/test_backend_consistency.py +0 -142
  324. spacecore-0.3.2/tests/backend/test_backend_loops.py +0 -119
  325. spacecore-0.3.2/tests/backend/test_backend_ops_delegation.py +0 -257
  326. spacecore-0.3.2/tests/backend/test_backend_registry.py +0 -102
  327. spacecore-0.3.2/tests/backend/test_cupy_ops.py +0 -66
  328. spacecore-0.3.2/tests/backend/test_jax_ops.py +0 -43
  329. spacecore-0.3.2/tests/backend/test_numpy_ops.py +0 -39
  330. spacecore-0.3.2/tests/backend/test_torch_consistency.py +0 -51
  331. spacecore-0.3.2/tests/backend/test_torch_ops.py +0 -108
  332. spacecore-0.3.2/tests/context/test_checked_method.py +0 -133
  333. spacecore-0.3.2/tests/context/test_context.py +0 -34
  334. spacecore-0.3.2/tests/context/test_context_manager.py +0 -46
  335. spacecore-0.3.2/tests/context/test_context_resolution.py +0 -115
  336. spacecore-0.3.2/tests/context/test_errors.py +0 -46
  337. spacecore-0.3.2/tests/examples/test_weighted_tikhonov.py +0 -109
  338. spacecore-0.3.2/tests/functional/test_functional.py +0 -243
  339. spacecore-0.3.2/tests/integration/test_smoke_torch.py +0 -34
  340. spacecore-0.3.2/tests/linalg/test_expm.py +0 -255
  341. spacecore-0.3.2/tests/linalg/test_krylov.py +0 -939
  342. spacecore-0.3.2/tests/linalg/test_metric_solvers.py +0 -68
  343. spacecore-0.3.2/tests/linops/test_adjoint_identity.py +0 -844
  344. spacecore-0.3.2/tests/linops/test_algebra.py +0 -533
  345. spacecore-0.3.2/tests/linops/test_algebra_linop.py +0 -242
  346. spacecore-0.3.2/tests/linops/test_batched_apply.py +0 -79
  347. spacecore-0.3.2/tests/linops/test_batched_lifting.py +0 -181
  348. spacecore-0.3.2/tests/linops/test_block_diagonal_linop.py +0 -27
  349. spacecore-0.3.2/tests/linops/test_conversion_linops.py +0 -62
  350. spacecore-0.3.2/tests/linops/test_dense_linop.py +0 -322
  351. spacecore-0.3.2/tests/linops/test_diagonal_linop.py +0 -162
  352. spacecore-0.3.2/tests/linops/test_linop_jit.py +0 -166
  353. spacecore-0.3.2/tests/linops/test_product_linop_batching.py +0 -201
  354. spacecore-0.3.2/tests/linops/test_product_structure.py +0 -231
  355. spacecore-0.3.2/tests/linops/test_sparse_linop.py +0 -345
  356. spacecore-0.3.2/tests/linops/test_stacked_linop.py +0 -18
  357. spacecore-0.3.2/tests/linops/test_sum_to_single_linop.py +0 -18
  358. spacecore-0.3.2/tests/linops/test_to_dense.py +0 -277
  359. spacecore-0.3.2/tests/spaces/test_conversion_spaces.py +0 -45
  360. spacecore-0.3.2/tests/spaces/test_geometry.py +0 -243
  361. spacecore-0.3.2/tests/spaces/test_hermitian_space.py +0 -54
  362. spacecore-0.3.2/tests/spaces/test_product_space.py +0 -68
  363. spacecore-0.3.2/tests/spaces/test_product_structure.py +0 -268
  364. spacecore-0.3.2/tests/spaces/test_space_apply.py +0 -159
  365. spacecore-0.3.2/tests/spaces/test_space_checks.py +0 -164
  366. spacecore-0.3.2/tests/spaces/test_space_hierarchy.py +0 -654
  367. spacecore-0.3.2/tests/spaces/test_spectrum.py +0 -237
  368. spacecore-0.3.2/tests/spaces/test_stacked_space.py +0 -156
  369. spacecore-0.3.2/tests/spaces/test_vector_space.py +0 -55
  370. spacecore-0.3.2/tests/spaces/test_vectorized_checks.py +0 -145
  371. spacecore-0.3.2/tests/test_backend_ops_complex.py +0 -41
  372. spacecore-0.3.2/tutorials/1_BackendOps.ipynb +0 -628
  373. spacecore-0.3.2/tutorials/2_Context.ipynb +0 -602
  374. spacecore-0.3.2/tutorials/3_Space.ipynb +0 -821
  375. spacecore-0.3.2/tutorials/4_LinOp.ipynb +0 -951
  376. spacecore-0.3.2/tutorials/5_Conversion_Policy.ipynb +0 -208
  377. spacecore-0.3.2/tutorials/6_Regularized_Opt_Transport.ipynb +0 -789
  378. spacecore-0.3.2/tutorials/7_Quadratic_Program.ipynb +0 -320
  379. spacecore-0.3.2/tutorials/8_Linalg_MatrixFree.ipynb +0 -560
  380. spacecore-0.3.2/tutorials/9_Linalg_Comparison.ipynb +0 -558
  381. spacecore-0.3.2/tutorials/README.md +0 -33
  382. spacecore-0.3.2/tutorials/weighted_tikhonov.ipynb +0 -539
  383. {spacecore-0.3.2 → spacecore-0.4.1}/CONTRIBUTING.md +0 -0
  384. {spacecore-0.3.2 → spacecore-0.4.1}/LICENSE +0 -0
  385. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/0.3.1-docs-inventory.md +0 -0
  386. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/0.3.1-docstring-audit.md +0 -0
  387. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/adr/001_backend_layer.md +0 -0
  388. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/adr/002_context_and_conversion.md +0 -0
  389. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/adr/004_inner_product_and_geometry.md +0 -0
  390. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/adr/006_current_batching_model.md +0 -0
  391. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/adr/007_linop_contract.md +0 -0
  392. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/adr/009_metric_adjoint.md +0 -0
  393. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/adr/010_functional_contract.md +0 -0
  394. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/adr/011_linalg_contract.md +0 -0
  395. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/adr/012_jordan_spectrum.md +0 -0
  396. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/contributing/labels.md +0 -0
  397. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/contributing/prerequisites.md +0 -0
  398. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/contributing/process.md +0 -0
  399. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/contributing/setup.md +0 -0
  400. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/docstring_style.md +0 -0
  401. {spacecore-0.3.2 → spacecore-0.4.1}/docs/dev/vision.md +0 -0
  402. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/_static/custom.css +0 -0
  403. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/api/backend.rst +0 -0
  404. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/api/linalg.rst +0 -0
  405. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/conf.py +0 -0
  406. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/design/backend_ops_array_api.rst +0 -0
  407. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/design/geometry.rst +0 -0
  408. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/design/jax_integration.rst +0 -0
  409. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/design/performance.rst +0 -0
  410. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/dev/adr.rst +0 -0
  411. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/dev/index.rst +0 -0
  412. {spacecore-0.3.2 → spacecore-0.4.1}/docs/source/dev/vision.rst +0 -0
  413. {spacecore-0.3.2 → spacecore-0.4.1}/setup.cfg +0 -0
  414. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/_contextual/__init__.py +0 -0
  415. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/_contextual/_policies.py +0 -0
  416. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/backend/_family.py +0 -0
  417. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/backend/cupy/__init__.py +0 -0
  418. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/backend/jax/__init__.py +0 -0
  419. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/backend/numpy/__init__.py +0 -0
  420. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/backend/torch/__init__.py +0 -0
  421. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/linalg/__init__.py +0 -0
  422. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/linalg/_expm.py +0 -0
  423. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/space/base/__init__.py +0 -0
  424. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/space/base/_jordan.py +0 -0
  425. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/space/base/_star.py +0 -0
  426. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/space/base/_vector.py +0 -0
  427. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/types/__init__.py +0 -0
  428. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/types/_dtype.py +0 -0
  429. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore/types/_misc.py +0 -0
  430. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore.egg-info/dependency_links.txt +0 -0
  431. {spacecore-0.3.2 → spacecore-0.4.1}/spacecore.egg-info/top_level.txt +0 -0
  432. {spacecore-0.3.2/examples → spacecore-0.4.1/tests}/__init__.py +0 -0
  433. {spacecore-0.3.2 → spacecore-0.4.1}/tests/_helpers.py +0 -0
  434. {spacecore-0.3.2/tests → spacecore-0.4.1/tests/backend}/__init__.py +0 -0
  435. {spacecore-0.3.2/tests/backend → spacecore-0.4.1/tests/bench}/__init__.py +0 -0
  436. {spacecore-0.3.2 → spacecore-0.4.1}/tests/conftest.py +0 -0
  437. {spacecore-0.3.2 → spacecore-0.4.1}/tests/context/__init__.py +0 -0
  438. {spacecore-0.3.2/tests/examples → spacecore-0.4.1/tests/integration}/__init__.py +0 -0
  439. {spacecore-0.3.2 → spacecore-0.4.1}/tests/integration/test_github_labels.py +0 -0
  440. {spacecore-0.3.2 → spacecore-0.4.1}/tests/integration/test_smoke_jax.py +0 -0
  441. {spacecore-0.3.2/tests/integration → spacecore-0.4.1/tests/kernels}/__init__.py +0 -0
  442. {spacecore-0.3.2 → spacecore-0.4.1}/tests/linalg/__init__.py +0 -0
  443. {spacecore-0.3.2 → spacecore-0.4.1}/tests/linops/__init__.py +0 -0
  444. {spacecore-0.3.2/tests/spaces → spacecore-0.4.1/tests/optim}/__init__.py +0 -0
@@ -0,0 +1,637 @@
1
+ # Changelog
2
+
3
+ All notable changes to SpaceCore are documented in this file.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and the project adheres to [Semantic Versioning](https://semver.org/).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.4.1] — 2026-06-28
11
+
12
+ ### Added
13
+
14
+ - The **`bench` benchmark submodule** is brought under version control and
15
+ aligned to the agreed 0.4.1 micro-surface (ADR-023,
16
+ `docs/dev/0.4.1-bench-surface.md`): probes measure per-call SpaceCore overhead
17
+ against a hand-optimal pure-array-library bare, across `space` / `linop` /
18
+ `functional` only (linalg, the synthetic kernel-comparison probes,
19
+ `check_member`, tree-space, and generated-linop probes removed). New
20
+ **configuration-regime axis** (`baseline` / `dispatch` / `dispatch_cache` /
21
+ `verify`) times the same probe under the ADR-016 dispatch and ADR-022 caching
22
+ toggles, recording a within-run `regime_speedup`; block operators are measured
23
+ uniform **and** ragged. The interactive HTML dashboard gains a problem-size
24
+ range slider, a backend/family/status/size/check/search/speedup filter set
25
+ that drives a fully **filter-reactive** summary and diagnosis section, a
26
+ bottom-of-page tag legend, and zero-count-status hiding. Every backend runs in
27
+ float64 for a fair comparison against the NumPy reference (JAX via
28
+ `enable_jax_x64`, Torch via `enable_torch_x64`); the sole exception is Apple
29
+ MPS (float32-only hardware), where the device probe builds a float32 case and
30
+ the correctness gate widens accordingly. The float64-aware tolerance is shared
31
+ by the verdict and diagnosis layers. **JAX is benchmarked only at
32
+ `check_level="none"`** and **jits both the SpaceCore call and the bare
33
+ reference**, comparing their post-compile steady state (the warmup absorbs
34
+ compilation, so the speedup is jitted-vs-jitted with compilation excluded);
35
+ each side's compile latency is recorded and reported separately (two
36
+ `sc compile` / `bare compile` columns). The pair is resolved **symmetrically** —
37
+ if either side is not jittable, both are timed eagerly, so a comparison is never
38
+ eager-vs-jitted. Tooling only — `spacecore` never imports `bench`.
39
+ - ADR-016 optimized-kernel **dispatch** is accepted and implemented (off by
40
+ default). `KernelSpec` gains `dispatch_key`, `priority`, and an optional
41
+ shape-only `cost` estimator (`KernelCost`); a spec that names a `dispatch_key`
42
+ with `rtol == atol == 0` is *dispatch-eligible*. `KernelRegistry` indexes the
43
+ eligible specs by key (descending `priority`) and rejects two eligible specs
44
+ that share a key at equal priority (`DispatchAmbiguityError`). A single
45
+ `spacecore.kernels.dispatch(key, *args, generic=…, ctx=…)` entry point selects
46
+ the first applicable, affordable spec or runs the inline `generic` fallback.
47
+ `dispatch_mode` (`off`/`on`/`verify`) is settable process-globally
48
+ (`set_dispatch_mode`) and per-scope (`dispatch_mode(...)` context manager);
49
+ `check_level="strict"` implies `verify`. A materializing fast path is gated by
50
+ a memory budget computed from `BackendOps.free_memory_bytes()` and
51
+ `set_memory_budget_fraction` — no estimate or no budget means no fuse. The
52
+ composed apply chain (`linop.composed.apply`) and block-diagonal apply
53
+ (`linop.block_diagonal.apply`) call sites are wired through `dispatch`; with
54
+ dispatch off they are result-identical to the prior inline paths. The two
55
+ `0.4.0` catalog specs stay explicit-entry (no `dispatch_key`); activating a
56
+ routed spec under either key is a benchmark-gated follow-up.
57
+ - Three dispatch-eligible algebraic-optimization kernels (exact, `rtol=atol=0`):
58
+ `composed-zero-annihilation` (a chain containing a zero map collapses to
59
+ `codomain.zeros()`) and `composed-identity-elision` (skip identity leaves)
60
+ under `linop.composed.apply`, and `block-diagonal-uniform-dense-batched`
61
+ (uniform flat-dense blocks fold into one batched `matmul`) under
62
+ `linop.block_diagonal.apply`. The block kernel is *materializing*: it carries a
63
+ shape-only `KernelCost` and the dispatcher gates it on the memory budget. All
64
+ three route only under `dispatch_mode("on"/"verify")`; dispatch stays off by
65
+ default. Each has a correctness reference and a `python -m bench` probe.
66
+ - `NumpyOps.free_memory_bytes()` reports available system RAM via `psutil` (now a
67
+ required core dependency), so the dispatcher's memory gate can size
68
+ materializing fast paths on the CPU backend.
69
+ - Five more dispatch-eligible batched-matmul kernels (exact, `rtol=atol=0`,
70
+ NumPy-only until cross-backend bit-exactness is verified) extend the catalog to
71
+ the adjoint and batched directions, each wired through `dispatch` at its own new
72
+ key with a shape-only `KernelCost` and a `Class::method` correctness reference:
73
+ `block-diagonal-uniform-dense-batched-rapply` / `-vapply` / `-rvapply` (under
74
+ `linop.block_diagonal.rapply` / `.vapply` / `.rvapply`) and the broadcast-no-sum
75
+ folds `stacked-uniform-dense-batched-apply` /
76
+ `sum-to-single-uniform-dense-batched-rapply` (under `linop.stacked.apply` /
77
+ `linop.sum_to_single.rapply`). The adjoint folds exploit the Euclidean-flat
78
+ adjoint and so guard on `EUCLIDEAN_FLAT`; the batched folds use the dense core's
79
+ transpose-on-right orientation. All five reuse one shared
80
+ `spacecore.kernels.specs._batched` helper (stack uniform flat-dense matrices into
81
+ a single batched `matmul`) instead of duplicating the fold. The
82
+ `BlockDiagonalLinOp` (`rapply`/`vapply`/`rvapply`), `StackedLinOp` (`apply`) and
83
+ `SumToSingleLinOp` (`rapply`) call sites are wired through `dispatch`;
84
+ dispatch-off is result-identical to the prior inline paths. Off by default.
85
+ - `SparseLinOp` is confirmed to need no dispatch spec: every direction is already a
86
+ single optimal backend call — one SpMV for `apply`/`rapply` and one batched SpMV
87
+ over the stacked right-hand side for `vapply`/`rvapply` — so the reserved
88
+ `linop.matvec.sparse` key stays inert (a spec would add only dispatch overhead).
89
+ - ADR-021 **lazy-operator-algebra `fuse()`** (Tier-2 explicit simplification):
90
+ `LinOp.fuse(*, materialize=False)` collapses each maximal subtree of dense
91
+ operators into a single materialized `DenseLinOp` — a composition becomes the
92
+ matrix product `M_A @ M_B`, a scalar folds into the matrix, a sum of dense terms
93
+ is added into one matrix, an adjoint fuses its operand, and block/tree operators
94
+ fuse each component (so a composed-dense block becomes foldable by the
95
+ block-diagonal dispatch spec). It is mathematically equal to the original up to
96
+ floating-point rounding (fusion reassociates the arithmetic) and is
97
+ adjoint-consistent on any geometry — the shared middle-space Riesz maps cancel,
98
+ so fusion is not restricted to Euclidean spaces. A matrix-free operand is
99
+ **never** densified by the default `fuse()`; `fuse(materialize=True)` is the
100
+ explicit opt-in that densifies it (via the `to_dense` basis probe) so an
101
+ enclosing expression can collapse. Lives in `spacecore.linop`, separate from the
102
+ ADR-016 dispatch layer.
103
+ - ADR-022 **materialized-form cache** for the uniform batched folds: the
104
+ input-independent stacked block-matrix array `ops.stack([matrix(p) for p in
105
+ parts])` is now built once and reused across applies instead of re-stacked every
106
+ call. `BlockDiagonalLinOp`, `StackedLinOp`, and `SumToSingleLinOp` carry their
107
+ `parts` in a `spacecore.kernels.CachedStackParts` tuple that memoizes the stack
108
+ per matrix accessor (`_A2` apply, `_A2H` adjoint, `_A2T`/`_A2H.T` batched), so a
109
+ routed fold pays one `matmul` with no re-stack. The memo is built lazily on first
110
+ optimized use (NumPy-only, and only while dispatch is `on`/`verify`), so the
111
+ default `off` path is untouched. It is a derived value: excluded from operator
112
+ identity (`__eq__`/`__hash__`) and from the pytree (`tree_flatten` re-normalizes
113
+ `parts` to a plain tuple, so a round-trip rebuilds an empty cache), and a
114
+ matrix-free operand is never cache-materialized (the fold is inapplicable). The
115
+ dispatcher stays stateless. Dispatch-decision caching remains out of scope
116
+ (ADR-022 §"Decision caching").
117
+
118
+ ### Fixed
119
+
120
+ - Corrected stale `correctness_ref` node ids on two shipped `KernelSpec`s
121
+ (`composed-chain-apply`, `block-diagonal-dense-apply`) that named non-existent
122
+ module-level test nodes instead of the real `Class::method` ids (ADR-016
123
+ requires the reference pin an existing test).
124
+
125
+ ## [0.4.0] — 2026-06-24
126
+
127
+ SpaceCore 0.4.0 stabilizes the typed linear-algebra core as a validated
128
+ algebra of structured mathematical objects. It ships a public check-policy,
129
+ ADR-015 Stage 1 dtype/field contract, the `TreeSpace` finite direct-product
130
+ abstraction, block-structured LinOps on tree domains, an everyday functional
131
+ and proximal toolbox, external optimizer adapters, reusable test generators,
132
+ and a full backend conformance matrix with deviation catalog.
133
+
134
+ ### Added
135
+
136
+ - ADR-018 **external optimizer adapters** in the new `spacecore.optimize`
137
+ subpackage: `minimize_scipy(F, x0, *, method="L-BFGS-B", jac=True, **kw)` and
138
+ `line_search_scipy(F, x, d, **kw)` drive `scipy.optimize`, and
139
+ `minimize_optax(F, x0, optimizer, *, steps, callback=None)` runs the canonical
140
+ optax update loop with pytree pass-through. Each adapter evaluates the
141
+ objective through `F.value` and converts the metric (Riesz) gradient `F.grad`
142
+ to the coordinate gradient external optimizers expect with
143
+ `X.riesz(F.grad(x))` — the identity on a Euclidean space and mandatory on a
144
+ weighted one, defusing the study's silent metric-gradient trap once and
145
+ centrally. The external optimizer owns iteration, line search, and
146
+ convergence; the SciPy adapters reject complex domains and document the
147
+ structure/geometry/field lost at the boundary. `minimize_scipy` returns the
148
+ SciPy `OptimizeResult` with an added `x_element` field (the minimizer
149
+ unflattened into `F.domain`); `minimize_optax` requires a JAX-backed domain and
150
+ the optional `optax` extra (`pip install spacecore[optax]`). Per ADR-018,
151
+ jaxopt/BlackJAX/pymanopt seams stay as tutorials, not shipped adapters.
152
+ - ADR-019 everyday functional and proximal toolbox in the new
153
+ `spacecore.functional.tools` subpackage (re-exported from
154
+ `spacecore.functional` and the top-level `spacecore` namespace): named
155
+ constructors over the existing `Functional` machinery, with no new core type
156
+ hierarchy. `least_squares(A, b, *, weights=None, scale=0.5)` returns a
157
+ `LinOpQuadraticForm` for `scale·‖Ax−b‖²` (default `½‖Ax−b‖²`, with optional
158
+ diagonal residual weights). New battery functionals `SquaredL2NormFunctional`,
159
+ `LpNormFunctional`, `L1NormFunctional`, `NegativeEntropyFunctional`,
160
+ `KLDivergenceFunctional`, and `HuberFunctional` are coordinate objectives whose
161
+ gradients are the metric (Riesz) gradient under the domain geometry.
162
+ `SpectralLpNormFunctional` (with the `NuclearNormFunctional` wrapper) is the
163
+ spectral analogue — the Schatten-`p` norm of a Jordan spectrum (`HermitianSpace`
164
+ eigenvalues), a spectral function whose gradient is reconstructed through the
165
+ ADR-012 `from_spectrum` API; on an elementwise Jordan space it coincides with
166
+ `LpNormFunctional`. A closed-form proximal primitive
167
+ `generalized_shrinkage(X, *, c, x0, eps, lam=0.0, nonneg=False)` solves the
168
+ separable forward–backward subproblem in the space metric (per-coordinate
169
+ threshold `τᵢ = λ/(2 ε wᵢ)` on a diagonal metric; it **raises** on a
170
+ non-diagonal metric rather than returning a wrong separable answer), with the
171
+ named wrappers `prox_l1`, `prox_l2sq`, and `project_nonneg`. The
172
+ `IndicatorFunctional`/`project_C` surface reserved by ADR-019 is deferred to
173
+ ADR-020 (`Set`).
174
+ - `HermitianSpace.eig_to_dense` (and therefore `from_spectrum`, `psd_proj`, and
175
+ `spectral_apply`) now symmetrizes the `U diag(·) U^*` reconstruction before the
176
+ membership check, so a zero-tolerance Hermitian space no longer rejects its own
177
+ spectral reconstruction over a few-ULP floating-point skew.
178
+ - Public `check_level` policy literal (`"none"`, `"cheap"`, `"standard"`,
179
+ `"strict"`) with `CHECK_LEVELS` ordering and `_checks_at_least` dispatch
180
+ across spaces, LinOps, functionals, and solver preconditions.
181
+ - `Space.field` exposing a `Literal["real", "complex"]` mathematical
182
+ contract derived from the context dtype; capability guards now consult
183
+ `Space.field` instead of inspecting precision-bearing dtypes.
184
+ - `TreeSpace` finite direct-product space organized by an `optree`
185
+ definition; `TreeElement` ordered-leaf binding; `TreeSpace.from_leaf_spaces`
186
+ flat-tuple shortcut.
187
+ - `BlockDiagonalLinOp` and `BlockMatrixLinOp` over `TreeSpace` domains
188
+ including metric-adjoint behavior; `TreeLinOp` base class for tree-shaped
189
+ operators.
190
+ - Reusable test generators under `tests/generators/` for spaces, LinOps,
191
+ functionals, and linalg references; contributor guide at
192
+ `docs/dev/contributing/linop_generators.md`.
193
+ - `spacecore.kernels` subpackage with the optimized-kernel registration
194
+ policy. Two demonstration kernels ship in 0.4.0: `composed-chain-apply`
195
+ (skips the per-link `@checked_method` wrapper for a flat chain of LinOps)
196
+ and `block-diagonal-dense-apply` (tight ``ops.matmul`` loop over dense
197
+ block leaves). Both have correctness references and bench cases. No
198
+ dispatch or fusion is wired in 0.4.0: the ADR-016 dispatch mechanism is
199
+ implemented but ships **off by default** and dormant, with no production
200
+ routing (see Unreleased).
201
+ - Unified benchmark framework at `python -m bench` (subcommands `run`,
202
+ `compare`, `plot`, `summary`, `list`) with generator-driven probes in
203
+ `bench/_operations.py`, peak-memory recording in
204
+ `bench/harness.py:measure_peak_memory`, fixed seeds `(0, 1, 2, 3)`, and
205
+ a self-contained interactive Plotly dashboard at `bench/_dashboard.py`.
206
+ - Kernel policy doc at `docs/source/design/kernels_policy.rst`.
207
+ - Backend conformance matrix at `docs/source/design/backend_conformance.rst`
208
+ with per-op tolerance harness in `tests/backend/_conformance.py`,
209
+ systematic NumpyOps reference (`tests/backend/test_conformance_numpy.py`),
210
+ cross-backend parity (`tests/backend/test_conformance_cross_backend.py`),
211
+ and dedicated modules for optional args, conversion, dtype promotion,
212
+ field consistency, vmap, and JIT.
213
+ - Operator apply cores are organized as a *core-kernel* layer in the
214
+ `spacecore.kernels` subpackage instead of inline in each operator class. The
215
+ check-free cores of `apply`/`rapply`/`vapply`/`rvapply` for **every** operator
216
+ with a fast path — the composite algebra (`ComposedLinOp`, `ScaledLinOp`,
217
+ `SumLinOp`, the adjoint view, `IdentityLinOp`, `ZeroLinOp`, `MatrixFreeLinOp`)
218
+ and the concrete leaves (`DenseLinOp`, `DiagonalLinOp`, `SparseLinOp`) — now
219
+ live as concrete functions in the kernels subpackage (`kernels/algebra.py`,
220
+ `kernels/dense.py`, `kernels/diagonal.py`, `kernels/sparse.py`). Operators
221
+ bind them by declaring the `@core_kernels("...")` class decorator (rules in
222
+ `spacecore/kernels/_core.py`); the base `LinOp` cores remain the generic
223
+ fallback for operators without a registered kernel. Binding is static
224
+ (class-definition time), so routing through the kernel registry costs nothing
225
+ per call — leaf-operator apply latency is unchanged. The lazy-algebra cores
226
+ additionally validate membership only once at the boundary instead of
227
+ re-validating every intermediate link, and `ComposedLinOp` caches a flattened
228
+ `_apply_chain` at construction so a deep `A @ B @ C @ ...` runs one loop rather
229
+ than re-walking the binary tree (a depth-16 composition applies ~9x faster than
230
+ the per-link-checked path and scales flat with depth). All results are
231
+ numerically identical. Public API: `core_kernels`, `CoreKernelSet`,
232
+ `register_core_kernels`, `get_core_kernels`, `core_kernel_names` from
233
+ `spacecore.kernels`.
234
+ - Iterative linalg solvers (`cg`, `lanczos_smallest`, `lsqr`, `power_iteration`)
235
+ consume the check-free operator/space cores in their hot loops. They validate
236
+ the operator and right-hand side once, at entry, then run the iteration through
237
+ the resolved cores — eliminating the per-iteration membership validation that
238
+ dominated eager-backend runtime (CG at `check_level="standard"` is ~3.4x faster
239
+ on NumPy and now matches `check_level="none"`). Resolution is safe: a core is
240
+ used only when it is consistent with the public method (`linalg/_utils.py`
241
+ `resolve_core`/`SpaceCoreOps`), so a user space that overrides `inner` with a
242
+ custom geometry without overriding `_inner_core` keeps its override. Results are
243
+ numerically identical.
244
+ - The `spacecore.kernels` subpackage is reorganized into two subpackages by kind:
245
+ `spacecore.kernels.core` (the check-free apply/eval cores + the `core_kernels`
246
+ binding rules) and `spacecore.kernels.specs` (the benchmarked `KernelSpec`
247
+ layer). Public names are re-exported from `spacecore.kernels`, so
248
+ `spacecore.kernels.core_kernels`, `spacecore.kernels.CoreKernelSet`, and
249
+ `spacecore.kernels.KernelSpec`/`registry` resolve unchanged.
250
+ - The same core-kernel organization now covers the `spacecore.functional`
251
+ submodule. The check-free `value`/`grad`/`vvalue`/`vgrad` cores for
252
+ `InnerProductFunctional`, `MatrixFreeLinearFunctional`, `LinearFunctional`,
253
+ `LinOpQuadraticForm`, and `ComposedFunctional` live in
254
+ `spacecore/kernels/functional.py`; the functionals bind them via
255
+ `@core_kernels("...")`. `CoreKernelSet` gained `value`/`grad`/`vvalue`/`vgrad`
256
+ fields alongside the LinOp `apply`/`rapply`/`vapply`/`rvapply` ones, and the
257
+ base `Functional` carries the generic core fallbacks. Composite functionals now
258
+ reach their operands' cores instead of re-validating intermediates — e.g.
259
+ `LinOpQuadraticForm.value` validates its input once rather than once per
260
+ sub-term (`Q.apply` + `linear.value`), and `ComposedFunctional` evaluates
261
+ `F._value_core(A._apply_core(x))`. Results are numerically identical.
262
+ - `BackendOps.hstack`, `vstack`, `dstack`, and `column_stack` array-stacking
263
+ helpers delegating to the backend's native routines, alongside the existing
264
+ `stack`.
265
+ - `BackendOps.vectorize` for elementwise vectorization of a scalar Python
266
+ function over array arguments. Delegates to the backend's native
267
+ `vectorize` (NumPy, JAX, CuPy) and uses a portable Python-loop fallback on
268
+ backends without one (Torch). Closes the previously unimplemented
269
+ `ops.vectorize` fallback used by `spectral_apply`.
270
+ - Backend deviation catalog at `docs/source/design/backend_deviations.rst`.
271
+ - Batching test policy at `docs/source/design/batching_test_policy.rst`.
272
+
273
+ ### Changed
274
+
275
+ - Spaces, LinOps, and functionals dispatch optional checks via
276
+ `_checks_at_least`; `cheap` covers shape/dtype/backend/tree-structure,
277
+ `standard` adds membership and Hermitian checks, `strict` adds bounded
278
+ expensive probes (matrix-free adjoint identity, CG positive-curvature
279
+ probe).
280
+ - `Context.dtype` is documented as the representation default; `Space.field`
281
+ is the mathematical contract derived from it.
282
+
283
+ ### Removed
284
+
285
+ - `ProductSpace` was removed in favor of `TreeSpace`. Tuple-style products
286
+ use `TreeSpace.from_leaf_spaces((X1, X2, ...))`; nested / dict /
287
+ namedtuple structures use `TreeSpace(template, leaf_spaces)` or
288
+ `TreeSpace.from_template`.
289
+ - `ProductLinOp` was renamed to `TreeLinOp`. `ProductStructure`,
290
+ `TupleStructure`, `PytreeStructure`, `ProductStructureCheck`, and
291
+ `ProductComponentCheck` were removed; tree-structure handling and leaf
292
+ validation are owned by `TreeSpace`.
293
+ - Conversion (`ctx.asarray` and construction helpers) refuses silent
294
+ complex-to-real narrowing per ADR-015 Stage 1.
295
+
296
+ ### Deprecated
297
+
298
+ - `enable_checks=True/False` is deprecated in favor of `check_level`:
299
+ `True` maps to `"standard"`, `False` maps to `"none"`. Passing both
300
+ raises `TypeError`. `enable_checks` continues to work in 0.4.0 but will
301
+ be removed in a future release.
302
+
303
+ ### Fixed
304
+
305
+ - Corrected the matrix-free adjoint contract so `MatrixFreeLinOp` and its
306
+ adjoint view use user-supplied forward and reverse callables directly,
307
+ without applying matrix-backed Riesz-map adjoint corrections.
308
+ - `ComposedLinOp`, `ScaledLinOp`, and `SumLinOp` now implement structural
309
+ `is_hermitian()` inference. A Gram product `R.H @ R` (or `L @ L.H`) reports
310
+ `True` in any geometry, a real-scaled operator propagates its operand's
311
+ verdict, and a sum of provably-Hermitian terms reports `True`. The checks
312
+ are cheap, conservative, and never assert `False`, so the normal operator
313
+ `A.H @ A + lam * Identity` is now correctly recognized as self-adjoint
314
+ instead of reporting `None`.
315
+ - `cg` now rejects an operator that is *provably* non-self-adjoint in its
316
+ geometry (`A.is_hermitian() is False`) at entry with a clear `ValueError`,
317
+ matching the guard already used by `power_iteration`, `lanczos_smallest`,
318
+ and `expm_multiply`. Previously, at the default check level, `cg` would
319
+ silently accept (for example) a symmetric matrix on a weighted
320
+ inner-product space — which is not self-adjoint under the weighted inner
321
+ product — and return a confusing `converged=False` result. Operators with
322
+ unknown Hermiticity (`is_hermitian() is None`, e.g. matrix-free) are still
323
+ accepted unchecked.
324
+
325
+ ### Known limitations
326
+
327
+ - Iterative solvers (`cg`, `lsqr`, `lanczos_smallest`, `power_iteration`,
328
+ `expm_multiply`) remain unbatched. Batched-input invocations raise a
329
+ clear shape error; explicit batched solver entry points are deferred to
330
+ 0.5.0.
331
+ - ADR-015 Stage 2 (operand-dtype-preserving `Context.asarray`, opt-in
332
+ exact dtype membership, operand-dtype solver workspaces) is deferred to
333
+ 0.5.0.
334
+ - Strict check level currently inherits the standard space-membership
335
+ semantics; additional spectral / metric probes at the space layer are
336
+ deferred to 0.5.0.
337
+
338
+ ## [0.3.1] — 2026-06-10
339
+
340
+ SpaceCore 0.3.1 is a release-candidate stabilization release for the `0.3.x`
341
+ API. It focuses on documentation consistency, tutorial execution, release
342
+ artifact checks, and public API audit cleanup. It does not add new solver
343
+ families or SDPLab-specific downstream integration.
344
+
345
+ ### Documentation
346
+
347
+ - Reworked API reference landing pages for backend, context, spaces, linear
348
+ operators, functionals, and linalg.
349
+ - Added design notes for context ownership, batching, and capability dispatch.
350
+ - Clarified conversion and dtype policy documentation for explicit target
351
+ contexts.
352
+ - Clarified adjoint documentation to distinguish coordinate transpose,
353
+ Euclidean adjoint, and metric/Riesz-represented adjoint behavior.
354
+
355
+ ### Examples and Tutorials
356
+
357
+ - Added a SpaceCore-only weighted Tikhonov worked example demonstrating
358
+ weighted spaces, metric adjoints, lazy operator algebra, CG, and an
359
+ independent dense NumPy reference solve.
360
+ - Integrated the weighted Tikhonov example into tests and documentation.
361
+
362
+ ### Testing and CI
363
+
364
+ - Documentation CI now builds Sphinx with warnings as errors.
365
+ - Release-candidate checks include full tests, strict docs build, public API
366
+ audit, artifact build, `twine check`, clean wheel installation, and smoke
367
+ testing.
368
+
369
+ ### Known limitations
370
+
371
+ - Optional backend behavior depends on installed optional dependencies. CuPy is
372
+ not required for the core release-candidate gate.
373
+ - The advanced regularized OT tutorial is an illustrative SpaceCore/JAX/Optax
374
+ example, not a claim that SpaceCore ships a production OT solver.
375
+
376
+ ## [0.3.0]
377
+
378
+ SpaceCore 0.3.0 is a breaking release for the unstable `0.x` series. Space
379
+ capabilities are now derived from actual structure, dtype, and inner product,
380
+ and conversions rebuild spaces through public factories so stale capabilities
381
+ are not retained.
382
+
383
+ ### Migration
384
+
385
+ | 0.2.x | 0.3.0 |
386
+ | --- | --- |
387
+ | `space.eigh(x)` | `space.spectral_decompose(x)` for eigenvalues and frame |
388
+ | `space.eigh(x)` | `space.spectrum(x)` for eigenvalues only |
389
+ | `sc.VectorSpace((n,))` | `sc.DenseVectorSpace((n,))` |
390
+ | `sc.VectorSpace((d, d))` | `sc.DenseCoordinateSpace((d, d))` |
391
+ | `ProductInnerProductSpace(...)` | `ProductSpace(...)` |
392
+ | `ProductStarSpace(...)` | `ProductSpace(...)` |
393
+ | `ProductJordanAlgebraSpace(...)` | `ProductSpace(...)` |
394
+ | `ProductEuclideanJordanAlgebraSpace(...)` | `ProductSpace(...)` |
395
+ | `StackedInnerProductSpace(...)` | `StackedSpace(...)` |
396
+ | `StackedStarSpace(...)` | `StackedSpace(...)` |
397
+ | `StackedJordanAlgebraSpace(...)` | `StackedSpace(...)` |
398
+ | `StackedEuclideanJordanAlgebraSpace(...)` | `StackedSpace(...)` |
399
+ | `BatchSpace` and `space.batch(...)` | leading-axis batched arrays with `vapply(...)` / `rvapply(...)` |
400
+ | `op.vapply(xs, batch_space=...)` | `op.vapply(xs)` |
401
+ | global context conversion policies | explicit `Context` construction and `obj.convert(ctx)` |
402
+ | global dtype preservation policies | target-context dtype during explicit conversion |
403
+
404
+ Prominent `eigh` replacement:
405
+
406
+ ```python
407
+ space.eigh(x)
408
+ # -> space.spectral_decompose(x) # eigenvalues and frame
409
+ # -> space.spectrum(x) # eigenvalues only
410
+ ```
411
+
412
+ ### Added
413
+
414
+ - `spectrum`, `spectral_decompose`, and `from_spectrum` as the public spectral
415
+ contract for Jordan spaces.
416
+ - `ElementwiseJordanSpace` for real or complex elementwise Jordan algebras.
417
+ - `EuclideanElementwiseJordanSpace` for real Euclidean elementwise Jordan
418
+ algebras.
419
+ - Jordan capability hierarchy separating `JordanAlgebraSpace` from
420
+ `EuclideanJordanAlgebraSpace`.
421
+ - `ProductStructure`, `TupleStructure`, `PytreeStructure`, and
422
+ `ProductSpace.from_template` for structured product elements.
423
+ - `ProductSpectralDecomposition` for product spectral data independent of
424
+ product element structure.
425
+ - `StackedSpace` for leading-axis repeated leaf spaces.
426
+ - Vectorizable axis-aware validation checks.
427
+ - `InnerProduct.validate_for(space)` and construction-time validation for
428
+ `WeightedInnerProduct`.
429
+ - `scripts/api_audit.py` for repository and downstream migration audits.
430
+
431
+ ### Changed
432
+
433
+ - `VectorSpace` is an abstract linear-capability base.
434
+ - Previous concrete `VectorSpace` use cases moved to `DenseVectorSpace` for
435
+ one-dimensional dense vectors and `DenseCoordinateSpace` for generic dense
436
+ coordinate arrays.
437
+ - `DenseVectorSpace` is now a plain one-dimensional vector space with star and
438
+ no Jordan capability by default.
439
+ - Elementwise Euclidean-Jordan capability is selected only for real dtype with
440
+ `EuclideanInnerProduct`.
441
+ - `ProductSpace(...)` and `StackedSpace(...)` are the only public product and
442
+ stacked constructors; they auto-dispatch to private implementation classes.
443
+ - `convert()` for elementwise, product, and stacked spaces recomputes
444
+ capabilities through public factories.
445
+ - `ProductSpace.spectral_decompose` returns explicit product spectral data
446
+ rather than routing decompositions through element structure adapters.
447
+
448
+ ### Removed
449
+
450
+ - Removed `eigh` from spaces. Use `spectral_decompose` when both eigenvalues
451
+ and a reconstruction frame are needed, or `spectrum` for eigenvalues only.
452
+ - Removed public specialized product and stacked constructors from the public
453
+ API.
454
+ - Removed `BatchSpace`, `Space.batch`, and `batch_space=` arguments from public
455
+ batching APIs. Use leading-axis vectorization through `vapply` and `rvapply`.
456
+ - Removed global context-policy and dtype-policy APIs. Conversion now follows
457
+ the requested target `Context` directly.
458
+
459
+ ## [0.2.0]
460
+
461
+ SpaceCore 0.2.0 is a major API expansion. The backend layer now sits on the
462
+ Array API standard. Operators gained a lazy algebra with adjoint views,
463
+ composition, sums, and scaling. A new `Functional` hierarchy provides
464
+ scalar-valued maps with gradients and pull-backs. A new `spacecore.linalg`
465
+ module ships four JIT-compatible iterative solvers. Spaces, operators, and
466
+ functionals share a single validation pattern via `checked_method`, and the
467
+ public API is documented to numpydoc standard with doctest coverage.
468
+
469
+ This release introduces breaking changes; see [Migration](#migration-from-01x).
470
+
471
+ ### Added
472
+
473
+ #### Backend
474
+
475
+ - Migrated `BackendOps` to the Array API standard via `array-api-compat`.
476
+ - `CuPyOps` and the `cupy` backend family as an optional install
477
+ (`pip install 'spacecore[cupy]'`).
478
+ - `BackendOps.is_complex_dtype` for backend-aware complex detection.
479
+ - `BackendOps.real_dtype` for extracting the real dtype matching a complex one.
480
+ - Broadened backend coverage for array creation, dtype conversion, sparse
481
+ conversion, indexing, reductions, linear algebra, loop primitives
482
+ (`fori_loop`, `while_loop`, `cond`), tree helpers, and vectorized mapping.
483
+ - JAX pytree registration for operator, space, and functional types so they
484
+ pass through `jax.jit`, `jax.vmap`, and `jax.grad` boundaries.
485
+
486
+ #### Context and checking
487
+
488
+ - Public free-function API in `spacecore._contextual`: `set_context`,
489
+ `get_context`, `resolve_context_priority`, `register_ops`, and the
490
+ resolution-policy accessors.
491
+ - Extended `checked_method` to support validation against `self` and multiple
492
+ input argument positions.
493
+ - Reusable space-validation checks: backend, dtype, shape, Hermitian,
494
+ square-matrix, product-structure, and product-component checks. Documented
495
+ at `docs/source/design/checking_policy.rst`.
496
+
497
+ #### Spaces
498
+
499
+ - `BatchSpace` for batched elements with explicit batch shape and batch-axis
500
+ metadata.
501
+
502
+ #### Linear operators
503
+
504
+ - Lazy operator algebra:
505
+ - `A @ B` composes operators.
506
+ - `A + B` sums operators.
507
+ - `alpha * A` scales an operator.
508
+ - `A.H` returns a cached adjoint view satisfying `A.H.H is A`.
509
+ - Algebraic simplification eliminates `I`, `Zero`, `alpha = 0`, `alpha = 1`,
510
+ and flattens nested sums.
511
+ - New operator types: `IdentityLinOp`, `ZeroLinOp`, `MatrixFreeLinOp`,
512
+ `DiagonalLinOp`.
513
+ - Structural `LinOp.is_hermitian()` reporting `True`, `False`, or `None`
514
+ (unknown) without applying incorrect Euclidean assumptions for custom space
515
+ geometries.
516
+ - `LinOp.to_dense()` for materializing operators as backend arrays.
517
+ - Product-structured operators and batched lifting:
518
+ - `ProductLinOp`
519
+ - `BlockDiagonalLinOp`
520
+ - `StackedLinOp`
521
+ - `SumToSingleLinOp`
522
+ - `vapply` / `rvapply` paths for batched operator application.
523
+
524
+ #### Functionals
525
+
526
+ - `Functional` as an abstract base for scalar-valued maps on spaces, with
527
+ `value`, `grad`, `hess_apply`, and batched counterparts.
528
+ - Linear functionals: `LinearFunctional`, `InnerProductFunctional`,
529
+ `MatrixFreeLinearFunctional`.
530
+ - Quadratic forms: `QuadraticForm`, `LinOpQuadraticForm`.
531
+ - `Functional.compose` and `ComposedFunctional` for pull-backs along linear
532
+ operators, with specializations that preserve the concrete functional type
533
+ when possible.
534
+
535
+ #### Linear algebra
536
+
537
+ The `spacecore.linalg` module is new in 0.2.0. It provides JIT-compatible
538
+ iterative solvers and structured result types.
539
+
540
+ - Iterative solvers:
541
+ - `cg` for Hermitian positive-definite systems.
542
+ - `lsqr` for rectangular least-squares problems.
543
+ - `power_iteration` for dominant-eigenpair estimates of a `LinOp` or
544
+ `QuadraticForm`.
545
+ - `lanczos_smallest` for smallest-Ritz-eigenpair estimates of Hermitian
546
+ operators.
547
+ - `expm_multiply` for Krylov matrix-exponential actions `exp(t A) v` on
548
+ Hermitian operators, with complex `t` supported for Schrodinger-type
549
+ evolution.
550
+ - Structured result types `CGResult`, `LSQRResult`, `PowerIterationResult`,
551
+ `LanczosResult`, and `ExpmMultiplyResult`, each carrying convergence
552
+ diagnostics and a compact `__repr__`.
553
+ - Solvers are geometry-aware: norms, inner products, and the default initial
554
+ vector use `Space.inner` and `Space.norm` rather than assuming Euclidean
555
+ geometry. This makes the solvers correct on custom inner products such as
556
+ RKHS or weighted spaces.
557
+
558
+ #### Documentation
559
+
560
+ - Numpydoc-standard public docstrings with runnable doctests for solvers,
561
+ spaces, operators, functionals, backends, and contextual helpers.
562
+ - API reference pages for backend ops, spaces, linear operators, functionals,
563
+ and linear algebra.
564
+ - JAX integration design note at `docs/source/design/jax_integration.rst`
565
+ covering trace-time operator algebra and recommended JIT usage.
566
+ - Tutorials for backend operations, linear operators, and matrix-free linalg
567
+ workflows.
568
+
569
+ #### Tooling
570
+
571
+ - Optional dependency groups: `[jax]`, `[torch]`, `[cupy]`, `[examples]`,
572
+ `[docs]`, `[dev]`.
573
+ - Explicit `__all__` at the top level covering new backends, operators,
574
+ functionals, solvers, result types, validation checks, and contextual
575
+ helpers.
576
+ - CI runs a JIT-traceability audit in `--check` mode and enforces a 70%
577
+ coverage floor via `pytest-cov`.
578
+ - Cross-backend tests covering NumPy, JAX, Torch, and optional CuPy.
579
+
580
+ ### Changed
581
+
582
+ - Restructured `_contextual` to hide implementation details while preserving
583
+ the public API via free functions.
584
+ - Replaced manual `if self._enable_checks` guards with `checked_method` across
585
+ `Space`, `LinOp`, and `Functional`. Inline guards are now reserved for
586
+ non-membership checks such as dense-array assertions and custom output-shape
587
+ checks.
588
+ - Improved `VectorSpace`, `HermitianSpace`, and `ProductSpace` conversion
589
+ behavior, validation, batching support, and docstrings.
590
+ - Improved linear-operator equality, representation, conversion, and JAX
591
+ pytree behavior.
592
+ - `spacecore.__version__` now resolves from package metadata via
593
+ `importlib.metadata` instead of a hand-maintained constant.
594
+ - Bumped the package version to `0.2.0`.
595
+
596
+ ### Fixed
597
+
598
+ - `LinOp.__eq__` returns `NotImplemented` instead of raising
599
+ `NotImplementedError` on the base class, so `op == None` and
600
+ `op in some_list` no longer raise.
601
+ - `DenseLinOp.is_hermitian` and `SparseLinOp.is_hermitian` return `None` for
602
+ custom space geometries instead of applying an incorrect Euclidean
603
+ matrix-symmetry test.
604
+
605
+ ### Migration from 0.1.x
606
+
607
+ - `BackendOps.eps` is now a method `eps(dtype)` rather than a property.
608
+ Callers must pass a dtype, typically `ctx.dtype`.
609
+ - The implementation attribute `DenseLinOp.A` is now a `cached_property`
610
+ backed by `_A`. The public attribute access `op.A` is unchanged.
611
+ - `LinOp.__eq__` returns `NotImplemented` rather than raising; downstream code
612
+ relying on the exception should be updated to handle the new behavior.
613
+ - Several module-internal helpers in `spacecore._contextual` moved to private
614
+ modules. Use the public functions re-exported from `spacecore._contextual`
615
+ (`set_context`, `get_context`, `resolve_context_priority`, `register_ops`,
616
+ `set_resolution_policy`, and the dtype-policy accessors) rather than
617
+ importing from internal modules.
618
+
619
+ ### Known limitations
620
+
621
+ - `cg`, `lsqr`, and `power_iteration` do not structurally validate operator
622
+ properties (positive-definiteness, full Hermiticity) and may silently
623
+ produce incorrect results on inputs that violate their preconditions. See
624
+ each function's `Notes` section for details.
625
+ - Operator algebra runs Python-level simplification at construction time. For
626
+ maximum JIT efficiency, assemble operator expressions outside the
627
+ `jax.jit` boundary; see the JAX integration design note.
628
+ - `MatrixFreeLinOp` stores its callables in pytree auxiliary data.
629
+ Constructing one inside a JIT-traced function with a new lambda each call
630
+ triggers retracing. Construct outside the traced region with a stable
631
+ callable reference.
632
+ - The CuPy backend is provided as a preview. Coverage of non-standard
633
+ operations and sparse handling may evolve in a subsequent release.
634
+
635
+ [0.3.1]: https://github.com/Pavlo3P/SpaceCore/releases/tag/v0.3.1
636
+ [0.3.0]: https://github.com/Pavlo3P/SpaceCore/releases/tag/v0.3.0
637
+ [0.2.0]: https://github.com/Pavlo3P/SpaceCore/releases/tag/v0.2.0
@@ -3,7 +3,6 @@ include CONTRIBUTING.md
3
3
 
4
4
  recursive-include docs/source *.rst *.py *.css
5
5
  recursive-include docs/dev *.md
6
- recursive-include examples *.py
7
6
  recursive-include tests *.py
8
7
  recursive-include tutorials *.ipynb *.md
9
8