braintrace 0.2.0__tar.gz → 0.2.2__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 (127) hide show
  1. {braintrace-0.2.0 → braintrace-0.2.2}/PKG-INFO +6 -4
  2. {braintrace-0.2.0 → braintrace-0.2.2}/README.md +1 -0
  3. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/__init__.py +5 -3
  4. braintrace-0.2.0/braintrace/api_contract_test.py → braintrace-0.2.2/braintrace/__init___test.py +65 -19
  5. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/_common.py +8 -6
  6. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/_common_test.py +2 -2
  7. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/base.py +67 -13
  8. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/base_test.py +25 -2
  9. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/d_rtrl_test.py +80 -228
  10. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/e_prop.py +3 -6
  11. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/e_prop_test.py +32 -6
  12. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/graph_executor.py +20 -58
  13. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/graph_executor_test.py +1 -1
  14. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/io_dim_vjp.py +28 -10
  15. braintrace-0.2.2/braintrace/_algorithm/io_dim_vjp_test.py +423 -0
  16. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/oracle.py +3 -1
  17. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/oracle_test.py +29 -13
  18. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/ostl.py +10 -7
  19. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/ostl_test.py +44 -8
  20. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/osttp.py +8 -4
  21. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/osttp_test.py +33 -5
  22. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/otpe.py +5 -6
  23. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/otpe_test.py +30 -4
  24. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/ottt.py +5 -6
  25. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/ottt_test.py +30 -4
  26. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/param_dim_vjp.py +87 -72
  27. braintrace-0.2.2/braintrace/_algorithm/param_dim_vjp_test.py +459 -0
  28. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/pp_prop.py +2 -3
  29. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/pp_prop_test.py +31 -5
  30. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm/tests}/approx_correctness_test.py +2 -2
  31. braintrace-0.2.2/braintrace/_algorithm/tests/conv_vmap_correctness_test.py +327 -0
  32. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm/tests}/cross_check_test.py +3 -3
  33. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm/tests}/diagnostic_exploration_test.py +2 -5
  34. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm/tests}/exact_correctness_test.py +2 -2
  35. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm/tests}/public_api_test.py +1 -1
  36. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm/tests}/scan_fusion_test.py +2 -2
  37. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm/tests}/transform_correctness_test.py +3 -3
  38. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/vjp_base.py +14 -2
  39. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/vjp_base_test.py +5 -5
  40. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/vjp_graph_executor.py +35 -32
  41. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/vjp_graph_executor_test.py +1 -1
  42. braintrace-0.2.2/braintrace/_compile.py +300 -0
  43. braintrace-0.2.2/braintrace/_compile_test.py +435 -0
  44. {braintrace-0.2.0/braintrace/_etrace_compiler → braintrace-0.2.2/braintrace/_compiler}/__init__.py +10 -7
  45. {braintrace-0.2.0/braintrace/_etrace_compiler → braintrace-0.2.2/braintrace/_compiler}/base.py +2 -2
  46. {braintrace-0.2.0/braintrace/_etrace_compiler → braintrace-0.2.2/braintrace/_compiler}/base_test.py +13 -9
  47. {braintrace-0.2.0/braintrace/_etrace_compiler → braintrace-0.2.2/braintrace/_compiler}/diagnostics_test.py +1 -1
  48. {braintrace-0.2.0/braintrace/_etrace_compiler → braintrace-0.2.2/braintrace/_compiler}/graph.py +15 -1
  49. {braintrace-0.2.0/braintrace/_etrace_compiler → braintrace-0.2.2/braintrace/_compiler}/graph_test.py +1 -1
  50. {braintrace-0.2.0/braintrace/_etrace_compiler → braintrace-0.2.2/braintrace/_compiler}/hid_param_op.py +4 -1
  51. {braintrace-0.2.0/braintrace/_etrace_compiler → braintrace-0.2.2/braintrace/_compiler}/hid_param_op_test.py +6 -6
  52. {braintrace-0.2.0/braintrace/_etrace_compiler → braintrace-0.2.2/braintrace/_compiler}/hidden_group.py +274 -13
  53. {braintrace-0.2.0/braintrace/_etrace_compiler → braintrace-0.2.2/braintrace/_compiler}/hidden_group_test.py +276 -12
  54. {braintrace-0.2.0/braintrace/_etrace_compiler → braintrace-0.2.2/braintrace/_compiler}/hidden_pertubation.py +3 -2
  55. {braintrace-0.2.0/braintrace/_etrace_compiler → braintrace-0.2.2/braintrace/_compiler}/hidden_pertubation_test.py +4 -4
  56. {braintrace-0.2.0/braintrace/_etrace_compiler → braintrace-0.2.2/braintrace/_compiler}/model4test.py +1 -1
  57. {braintrace-0.2.0/braintrace/_etrace_compiler → braintrace-0.2.2/braintrace/_compiler}/module_info.py +9 -5
  58. {braintrace-0.2.0/braintrace/_etrace_compiler → braintrace-0.2.2/braintrace/_compiler}/module_info_test.py +3 -3
  59. braintrace-0.2.2/braintrace/_compiler/report.py +231 -0
  60. braintrace-0.2.2/braintrace/_compiler/report_test.py +53 -0
  61. {braintrace-0.2.0/braintrace/_etrace_compiler → braintrace-0.2.2/braintrace/_compiler}/scenario_catalog_test.py +4 -4
  62. {braintrace-0.2.0/braintrace/_etrace_compiler → braintrace-0.2.2/braintrace/_compiler/tests}/cell_relation_guardrail_test.py +1 -1
  63. {braintrace-0.2.0/braintrace/_etrace_compiler → braintrace-0.2.2/braintrace/_compiler/tests}/compiler_oracle_test.py +1 -1
  64. {braintrace-0.2.0/braintrace/_etrace_compiler → braintrace-0.2.2/braintrace/_compiler/tests}/compiler_property_test.py +2 -2
  65. braintrace-0.2.2/braintrace/_docs_examples_test.py +247 -0
  66. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/_etrace_model_test.py +1 -1
  67. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/_grad_exponential.py +9 -7
  68. braintrace-0.2.2/braintrace/_grad_exponential_test.py +82 -0
  69. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/_legacy/_ops.py +5 -5
  70. braintrace-0.2.2/braintrace/_legacy/_ops_test.py +185 -0
  71. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/_legacy/_params.py +7 -7
  72. braintrace-0.2.0/braintrace/_legacy/_legacy_test.py → braintrace-0.2.2/braintrace/_legacy/_params_test.py +6 -134
  73. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/_misc.py +1 -1
  74. braintrace-0.2.2/braintrace/_misc_test.py +163 -0
  75. {braintrace-0.2.0/braintrace/_etrace_op → braintrace-0.2.2/braintrace/_op}/__init__.py +2 -2
  76. {braintrace-0.2.0/braintrace/_etrace_op → braintrace-0.2.2/braintrace/_op}/_primitive_test.py +1 -1
  77. {braintrace-0.2.0/braintrace/_etrace_op → braintrace-0.2.2/braintrace/_op}/_registries_test.py +4 -4
  78. {braintrace-0.2.0/braintrace/_etrace_op → braintrace-0.2.2/braintrace/_op}/conv.py +2 -2
  79. {braintrace-0.2.0/braintrace/_etrace_op → braintrace-0.2.2/braintrace/_op}/conv_test.py +5 -5
  80. {braintrace-0.2.0/braintrace/_etrace_op → braintrace-0.2.2/braintrace/_op}/dense.py +1 -1
  81. {braintrace-0.2.0/braintrace/_etrace_op → braintrace-0.2.2/braintrace/_op}/dense_test.py +8 -8
  82. {braintrace-0.2.0/braintrace/_etrace_op → braintrace-0.2.2/braintrace/_op}/elemwise.py +26 -10
  83. {braintrace-0.2.0/braintrace/_etrace_op → braintrace-0.2.2/braintrace/_op}/elemwise_test.py +6 -6
  84. {braintrace-0.2.0/braintrace/_etrace_op → braintrace-0.2.2/braintrace/_op}/lora.py +1 -1
  85. {braintrace-0.2.0/braintrace/_etrace_op → braintrace-0.2.2/braintrace/_op}/lora_test.py +4 -4
  86. {braintrace-0.2.0/braintrace/_etrace_op → braintrace-0.2.2/braintrace/_op}/op_rule_oracle_test.py +7 -7
  87. {braintrace-0.2.0/braintrace/_etrace_op → braintrace-0.2.2/braintrace/_op}/sparse.py +2 -2
  88. {braintrace-0.2.0/braintrace/_etrace_op → braintrace-0.2.2/braintrace/_op}/sparse_test.py +7 -7
  89. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/_state_managment.py +12 -13
  90. braintrace-0.2.2/braintrace/_state_managment_test.py +108 -0
  91. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/_typing.py +26 -0
  92. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/_version.py +1 -1
  93. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/nn/_conv.py +4 -4
  94. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/nn/_conv_test.py +7 -7
  95. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/nn/_linear.py +33 -10
  96. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/nn/_linear_test.py +119 -1
  97. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/nn/_readout.py +9 -10
  98. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/nn/_readout_test.py +1 -1
  99. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/nn/_rnn.py +70 -70
  100. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/nn/_rnn_test.py +2 -2
  101. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace.egg-info/PKG-INFO +6 -4
  102. braintrace-0.2.2/braintrace.egg-info/SOURCES.txt +121 -0
  103. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace.egg-info/requires.txt +4 -3
  104. {braintrace-0.2.0 → braintrace-0.2.2}/pyproject.toml +49 -7
  105. braintrace-0.2.0/braintrace/_compile.py +0 -153
  106. braintrace-0.2.0/braintrace/_compile_test.py +0 -125
  107. braintrace-0.2.0/braintrace/legacy_deprecation_test.py +0 -53
  108. braintrace-0.2.0/braintrace.egg-info/SOURCES.txt +0 -112
  109. {braintrace-0.2.0 → braintrace-0.2.2}/LICENSE +0 -0
  110. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/__init__.py +0 -0
  111. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/d_rtrl.py +0 -0
  112. {braintrace-0.2.0/braintrace/_etrace_algorithms → braintrace-0.2.2/braintrace/_algorithm}/oracle_models.py +0 -0
  113. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/_compatible_imports.py +0 -0
  114. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/_compatible_imports_test.py +0 -0
  115. {braintrace-0.2.0/braintrace/_etrace_compiler → braintrace-0.2.2/braintrace/_compiler}/diagnostics.py +0 -0
  116. {braintrace-0.2.0/braintrace/_etrace_compiler → braintrace-0.2.2/braintrace/_compiler}/scenario_catalog.py +0 -0
  117. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/_input_data.py +0 -0
  118. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/_input_data_test.py +0 -0
  119. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/_legacy/__init__.py +0 -0
  120. {braintrace-0.2.0/braintrace/_etrace_op → braintrace-0.2.2/braintrace/_op}/_primitive.py +0 -0
  121. {braintrace-0.2.0/braintrace/_etrace_op → braintrace-0.2.2/braintrace/_op}/_registries.py +0 -0
  122. {braintrace-0.2.0/braintrace/_etrace_op → braintrace-0.2.2/braintrace/_op}/op_rule_oracle.py +0 -0
  123. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/nn/__init__.py +0 -0
  124. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace/py.typed +0 -0
  125. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace.egg-info/dependency_links.txt +0 -0
  126. {braintrace-0.2.0 → braintrace-0.2.2}/braintrace.egg-info/top_level.txt +0 -0
  127. {braintrace-0.2.0 → braintrace-0.2.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braintrace
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Enabling Scalable Online Learning for Brain Dynamics.
5
5
  Author-email: BrainTrace Developers <chao.brain@qq.com>
6
6
  License: Apache-2.0 license
@@ -26,10 +26,9 @@ Classifier: Topic :: Software Development :: Libraries
26
26
  Requires-Python: >=3.11
27
27
  Description-Content-Type: text/markdown
28
28
  License-File: LICENSE
29
- Requires-Dist: brainstate>=0.2.2
29
+ Requires-Dist: brainstate>=0.5.2
30
30
  Requires-Dist: brainunit
31
- Requires-Dist: brainstate
32
- Requires-Dist: brainpy-state
31
+ Requires-Dist: brainpy.state
33
32
  Requires-Dist: braintools
34
33
  Provides-Extra: cpu
35
34
  Requires-Dist: jax[cpu]; extra == "cpu"
@@ -41,10 +40,12 @@ Provides-Extra: tpu
41
40
  Requires-Dist: jax[tpu]; extra == "tpu"
42
41
  Provides-Extra: testing
43
42
  Requires-Dist: pytest; extra == "testing"
43
+ Requires-Dist: pytest-cov; extra == "testing"
44
44
  Requires-Dist: jax[cpu]; extra == "testing"
45
45
  Requires-Dist: hypothesis; extra == "testing"
46
46
  Provides-Extra: dev
47
47
  Requires-Dist: pytest; extra == "dev"
48
+ Requires-Dist: pytest-cov; extra == "dev"
48
49
  Requires-Dist: jax[cpu]; extra == "dev"
49
50
  Requires-Dist: hypothesis; extra == "dev"
50
51
  Requires-Dist: mypy>=1.8; extra == "dev"
@@ -64,6 +65,7 @@ Dynamic: license-file
64
65
  <a href="https://brainx.chaobrain.com/braintrace/"><img alt="Documentation" src="https://readthedocs.org/projects/braintrace/badge/?version=latest"></a>
65
66
  <a href="https://badge.fury.io/py/braintrace"><img alt="PyPI version" src="https://badge.fury.io/py/braintrace.svg"></a>
66
67
  <a href="https://github.com/chaobrain/braintrace/actions/workflows/CI.yml"><img alt="Continuous Integration" src="https://github.com/chaobrain/braintrace/actions/workflows/CI.yml/badge.svg"></a>
68
+ <a href="https://codecov.io/gh/chaobrain/braintrace"><img alt="Code Coverage" src="https://codecov.io/gh/chaobrain/braintrace/branch/main/graph/badge.svg"></a>
67
69
  </p>
68
70
 
69
71
  [``braintrace``](https://github.com/chaobrain/braintrace) provides online learning algorithms for biological neural networks.
@@ -11,6 +11,7 @@
11
11
  <a href="https://brainx.chaobrain.com/braintrace/"><img alt="Documentation" src="https://readthedocs.org/projects/braintrace/badge/?version=latest"></a>
12
12
  <a href="https://badge.fury.io/py/braintrace"><img alt="PyPI version" src="https://badge.fury.io/py/braintrace.svg"></a>
13
13
  <a href="https://github.com/chaobrain/braintrace/actions/workflows/CI.yml"><img alt="Continuous Integration" src="https://github.com/chaobrain/braintrace/actions/workflows/CI.yml/badge.svg"></a>
14
+ <a href="https://codecov.io/gh/chaobrain/braintrace"><img alt="Code Coverage" src="https://codecov.io/gh/chaobrain/braintrace/branch/main/graph/badge.svg"></a>
14
15
  </p>
15
16
 
16
17
  [``braintrace``](https://github.com/chaobrain/braintrace) provides online learning algorithms for biological neural networks.
@@ -70,7 +70,7 @@ from typing import TYPE_CHECKING
70
70
 
71
71
  from . import nn
72
72
  from ._compile import compile
73
- from ._etrace_algorithms import (
73
+ from ._algorithm import (
74
74
  ETraceAlgorithm,
75
75
  EligibilityTrace,
76
76
  ETraceGraphExecutor,
@@ -91,7 +91,7 @@ from ._etrace_algorithms import (
91
91
  KappaFilter,
92
92
  PresynapticTrace,
93
93
  )
94
- from ._etrace_compiler import (
94
+ from ._compiler import (
95
95
  ETraceGraph,
96
96
  compile_etrace_graph,
97
97
  HiddenParamOpRelation,
@@ -106,10 +106,11 @@ from ._etrace_compiler import (
106
106
  ModuleInfo,
107
107
  extract_module_info,
108
108
  CompilationRecord,
109
+ CompilationReport,
109
110
  DiagnosticKind,
110
111
  DiagnosticLevel,
111
112
  )
112
- from ._etrace_op import (
113
+ from ._op import (
113
114
  ETPPrimitive,
114
115
  matmul,
115
116
  element_wise,
@@ -198,6 +199,7 @@ __all__ = [
198
199
 
199
200
  # compiler diagnostics
200
201
  'CompilationRecord',
202
+ 'CompilationReport',
201
203
  'DiagnosticKind',
202
204
  'DiagnosticLevel',
203
205
 
@@ -13,10 +13,18 @@
13
13
  # limitations under the License.
14
14
  # ==============================================================================
15
15
 
16
- """L0 public-API contract: every ``braintrace.__all__`` symbol resolves to a
17
- usable object; public algorithms run a minimal end-to-end step; documented error
18
- paths fire on their real triggers; legacy/nn deprecations warn. Also pins the
19
- implementation facts that drifted from CLAUDE.md (F-17)."""
16
+ """Tests for the ``braintrace`` package root (``braintrace/__init__.py``).
17
+
18
+ Two concerns, both owned by the package root:
19
+
20
+ * **Public-API contract** — every ``braintrace.__all__`` symbol resolves to a
21
+ usable object; public algorithms run a minimal end-to-end step; documented
22
+ error paths fire on their real triggers; legacy/nn deprecations warn; and the
23
+ implementation facts that drifted from CLAUDE.md (F-17) stay pinned.
24
+ * **Legacy deprecation forwarding** — the v0.1.x shims served lazily by
25
+ ``__getattr__`` warn on access, stay out of ``__all__``, and appear in
26
+ ``__dir__``.
27
+ """
20
28
 
21
29
  import brainstate
22
30
  import jax
@@ -24,8 +32,13 @@ import jax.numpy as jnp
24
32
  import pytest
25
33
 
26
34
  import braintrace
27
- from braintrace._etrace_algorithms.oracle_models import tanh_rnn
35
+ import braintrace._legacy as legacy
36
+ from braintrace._algorithm.oracle_models import tanh_rnn
37
+
28
38
 
39
+ # ===========================================================================
40
+ # Public-API contract
41
+ # ===========================================================================
29
42
 
30
43
  # --- Task 1: every __all__ symbol resolves to a non-None object --------------
31
44
 
@@ -130,18 +143,12 @@ def test_dynamic_weight_assignment_raises_not_supported():
130
143
 
131
144
  # --- Task 5: weight inside control flow raises NotImplementedError -----------
132
145
 
133
- @pytest.mark.xfail(
134
- strict=True,
135
- reason="F-SCAN-WEIGHT: the weight-in-control-flow guard intends to raise "
136
- "NotImplementedError, but its error-message construction at "
137
- "base.py:133 indexes invar_to_hidden_path with the *weight* var "
138
- "(absent from that hidden-path map), so a KeyError escapes instead. "
139
- "The guard fires, but the wrong exception type surfaces.",
140
- )
141
146
  def test_weight_used_inside_scan_raises_not_implemented():
142
- """check_unsupported_op should raise NotImplementedError when a weight var is
143
- used within a control-flow op. Today it raises KeyError while building the
144
- message (F-SCAN-WEIGHT) — this test pins the intended contract via xfail."""
147
+ """check_unsupported_op raises NotImplementedError when a weight var is used
148
+ within a control-flow op. Previously (F-SCAN-WEIGHT) the message construction
149
+ indexed the hidden-path map with the weight var and a KeyError escaped instead;
150
+ the message now renders the weight variable directly, so the intended
151
+ NotImplementedError surfaces."""
145
152
 
146
153
  class ScanModel(brainstate.nn.Module):
147
154
  def __init__(self):
@@ -193,8 +200,8 @@ def test_nn_unknown_name_raises_attribute_error():
193
200
  # --- Task 7: lock the drifted implementation facts (F-17) --------------------
194
201
 
195
202
  def test_ostl_is_two_classes_not_a_factory():
196
- from braintrace._etrace_algorithms.param_dim_vjp import ParamDimVjpAlgorithm
197
- from braintrace._etrace_algorithms.io_dim_vjp import IODimVjpAlgorithm
203
+ from braintrace._algorithm.param_dim_vjp import ParamDimVjpAlgorithm
204
+ from braintrace._algorithm.io_dim_vjp import IODimVjpAlgorithm
198
205
  assert isinstance(braintrace.OSTLRecurrent, type)
199
206
  assert isinstance(braintrace.OSTLFeedforward, type)
200
207
  assert issubclass(braintrace.OSTLRecurrent, ParamDimVjpAlgorithm)
@@ -202,7 +209,7 @@ def test_ostl_is_two_classes_not_a_factory():
202
209
 
203
210
 
204
211
  def test_iodim_lives_in_io_dim_vjp_module():
205
- from braintrace._etrace_algorithms.io_dim_vjp import IODimVjpAlgorithm
212
+ from braintrace._algorithm.io_dim_vjp import IODimVjpAlgorithm
206
213
  assert braintrace.IODimVjpAlgorithm is IODimVjpAlgorithm
207
214
  assert braintrace.pp_prop is braintrace.ES_D_RTRL # aliases
208
215
 
@@ -212,3 +219,42 @@ def test_expected_rnn_cells_exist():
212
219
  for cell in ('ValinaRNNCell', 'GRUCell', 'MGUCell', 'LSTMCell', 'URLSTMCell',
213
220
  'MinimalRNNCell', 'MiniGRU', 'MiniLSTM', 'LRUCell'):
214
221
  assert hasattr(nn, cell), f"missing cell: {cell}"
222
+
223
+
224
+ # ===========================================================================
225
+ # Legacy v0.1.x deprecation forwarding
226
+ # ===========================================================================
227
+
228
+ _LEGACY_NAMES = [
229
+ 'ETraceOp', 'MatMulOp', 'ElemWiseOp', 'ConvOp', 'SpMatMulOp', 'LoraOp',
230
+ 'ETraceParam', 'ElemWiseParam', 'NonTempParam',
231
+ 'FakeETraceParam', 'FakeElemWiseParam',
232
+ ]
233
+
234
+
235
+ @pytest.mark.parametrize('name', _LEGACY_NAMES)
236
+ def test_legacy_access_warns_and_returns_class(name):
237
+ with pytest.warns(DeprecationWarning):
238
+ obj = getattr(braintrace, name)
239
+ assert obj is getattr(legacy, name)
240
+
241
+
242
+ @pytest.mark.parametrize('name', _LEGACY_NAMES)
243
+ def test_legacy_names_not_in_all(name):
244
+ assert name not in braintrace.__all__
245
+
246
+
247
+ def test_from_import_warns():
248
+ with pytest.warns(DeprecationWarning):
249
+ from braintrace import MatMulOp # noqa: F401
250
+
251
+
252
+ def test_unknown_attribute_raises_attribute_error():
253
+ with pytest.raises(AttributeError):
254
+ _ = braintrace.ThisNameDoesNotExist
255
+
256
+
257
+ def test_legacy_names_in_dir():
258
+ d = dir(braintrace)
259
+ for name in _LEGACY_NAMES:
260
+ assert name in d
@@ -21,7 +21,9 @@ from typing import Any, Dict, Optional
21
21
  import brainstate
22
22
  import jax
23
23
  import jax.numpy as jnp
24
- import saiunit as u
24
+ import brainunit as u
25
+
26
+ from braintrace._typing import PyTree
25
27
 
26
28
  __all__ = [
27
29
  'PresynapticTrace',
@@ -388,7 +390,7 @@ def _unit_safe_add(a, b):
388
390
  return u.math.add(a, b)
389
391
 
390
392
 
391
- def _extract_leaf(pytree_val: brainstate.typing.PyTree, leaf_idx: int):
393
+ def _extract_leaf(pytree_val: PyTree, leaf_idx: int):
392
394
  """Return the leaf at ``leaf_idx`` in ``jax.tree.leaves(pytree_val)``.
393
395
 
394
396
  Bare arrays (treedef with a single leaf) return the array unchanged.
@@ -405,7 +407,7 @@ def _extract_leaf(pytree_val: brainstate.typing.PyTree, leaf_idx: int):
405
407
 
406
408
 
407
409
  def _wrap_leaves_as_pytree(
408
- reference_pytree: brainstate.typing.PyTree,
410
+ reference_pytree: PyTree,
409
411
  leaf_grads: Dict[int, jax.Array],
410
412
  ):
411
413
  """Build a pytree matching ``reference_pytree`` with ``leaf_grads``
@@ -441,8 +443,8 @@ def _wrap_leaves_as_pytree(
441
443
  def _route_grads_by_path(
442
444
  relation,
443
445
  per_key_grads: Dict[str, jax.Array],
444
- weight_vals: Dict[Any, brainstate.typing.PyTree],
445
- target_dict: Dict[Any, brainstate.typing.PyTree],
446
+ weight_vals: Dict[Any, PyTree],
447
+ target_dict: Dict[Any, PyTree],
446
448
  ) -> None:
447
449
  """Route per-key gradients from a dict-API rule into per-path pytrees.
448
450
 
@@ -474,7 +476,7 @@ def _route_grads_by_path(
474
476
  def _update_dict(
475
477
  the_dict: Dict,
476
478
  key: Any,
477
- value: brainstate.typing.PyTree,
479
+ value: PyTree,
478
480
  error_when_no_key: Optional[bool] = False
479
481
  ):
480
482
  """Update the dictionary.
@@ -20,9 +20,9 @@ import jax
20
20
  import jax.numpy as jnp
21
21
  import numpy.testing as npt
22
22
  import pytest
23
- import saiunit as u
23
+ import brainunit as u
24
24
 
25
- from braintrace._etrace_algorithms._common import (
25
+ from braintrace._algorithm._common import (
26
26
  FixedRandomFeedback,
27
27
  KappaFilter,
28
28
  PresynapticTrace,
@@ -23,7 +23,7 @@ from typing import Dict, Any, Optional
23
23
 
24
24
  import brainstate
25
25
 
26
- from braintrace._etrace_compiler import ETraceGraph
26
+ from braintrace._compiler import ETraceGraph, CompilationReport
27
27
  from .graph_executor import ETraceGraphExecutor
28
28
  from .._typing import Path
29
29
 
@@ -90,7 +90,7 @@ class ETraceAlgorithm(brainstate.nn.Module):
90
90
  graph_executor: ETraceGraphExecutor,
91
91
  name: Optional[str] = None,
92
92
  ):
93
- super().__init__(name=name)
93
+ super().__init__(name=name) # type: ignore[call-arg] # brainstate hides Module.__init__ from type checkers
94
94
 
95
95
  # the model
96
96
  if not isinstance(model, brainstate.nn.Module):
@@ -115,9 +115,9 @@ class ETraceAlgorithm(brainstate.nn.Module):
115
115
  self.running_index = brainstate.LongTermState(0)
116
116
 
117
117
  # other states
118
- self._param_states = None
119
- self._hidden_states = None
120
- self._other_states = None
118
+ self._param_states: Optional[brainstate.util.FlattedDict] = None
119
+ self._hidden_states: Optional[brainstate.util.FlattedDict] = None
120
+ self._other_states: Optional[brainstate.util.FlattedDict] = None
121
121
 
122
122
  @property
123
123
  def graph(self) -> ETraceGraph:
@@ -131,6 +131,28 @@ class ETraceAlgorithm(brainstate.nn.Module):
131
131
  """
132
132
  return self.graph_executor.graph
133
133
 
134
+ @property
135
+ def report(self) -> CompilationReport:
136
+ """Structured, read-only report of the compiled eligibility-trace graph.
137
+
138
+ Returns
139
+ -------
140
+ CompilationReport
141
+ A view over :attr:`graph`.
142
+
143
+ Raises
144
+ ------
145
+ RuntimeError
146
+ If accessed before the graph has been compiled.
147
+ """
148
+ if not self.is_compiled:
149
+ raise RuntimeError(
150
+ 'The eligibility-trace graph is not compiled yet. Build the '
151
+ 'learner with braintrace.compile(...) (or call .compile_graph(...)) '
152
+ 'before accessing .report.'
153
+ )
154
+ return CompilationReport(self.graph)
155
+
134
156
  @property
135
157
  def executor(self) -> ETraceGraphExecutor:
136
158
  """
@@ -144,7 +166,7 @@ class ETraceAlgorithm(brainstate.nn.Module):
144
166
  return self.graph_executor
145
167
 
146
168
  @property
147
- def param_states(self) -> brainstate.util.FlattedDict[Path, brainstate.ParamState]:
169
+ def param_states(self) -> brainstate.util.FlattedDict:
148
170
  """
149
171
  Get the parameter weight states.
150
172
 
@@ -155,10 +177,11 @@ class ETraceAlgorithm(brainstate.nn.Module):
155
177
  """
156
178
  if self._param_states is None:
157
179
  self._split_state()
180
+ assert self._param_states is not None
158
181
  return self._param_states
159
182
 
160
183
  @property
161
- def hidden_states(self) -> brainstate.util.FlattedDict[Path, brainstate.HiddenState]:
184
+ def hidden_states(self) -> brainstate.util.FlattedDict:
162
185
  """
163
186
  Get the hidden states.
164
187
 
@@ -169,10 +192,11 @@ class ETraceAlgorithm(brainstate.nn.Module):
169
192
  """
170
193
  if self._hidden_states is None:
171
194
  self._split_state()
195
+ assert self._hidden_states is not None
172
196
  return self._hidden_states
173
197
 
174
198
  @property
175
- def other_states(self) -> brainstate.util.FlattedDict[Path, brainstate.State]:
199
+ def other_states(self) -> brainstate.util.FlattedDict:
176
200
  """
177
201
  Get the other states.
178
202
 
@@ -183,6 +207,7 @@ class ETraceAlgorithm(brainstate.nn.Module):
183
207
  """
184
208
  if self._other_states is None:
185
209
  self._split_state()
210
+ assert self._other_states is not None
186
211
  return self._other_states
187
212
 
188
213
  def _split_state(self):
@@ -219,6 +244,18 @@ class ETraceAlgorithm(brainstate.nn.Module):
219
244
  The input arguments.
220
245
  """
221
246
 
247
+ # ``vmap_new_states`` / ``vmap2_new_states`` run an eager *discovery
248
+ # probe* that executes the surrounding ``init`` (including this call)
249
+ # once against throwaway, un-batched states before the real mapped
250
+ # pass. Compiling there would bind the executor to those probe states
251
+ # (which are discarded and left untagged), so the subsequent
252
+ # ``brainstate.nn.Vmap(..., vmap_states='new')`` would not cover them
253
+ # and writing a batched value raises ``BatchAxisError``. Defer to the
254
+ # real mapped pass, which creates the 'new'-tagged batched states.
255
+ _in_probe = getattr(brainstate.transform, 'in_new_state_probe', None)
256
+ if _in_probe is not None and _in_probe():
257
+ return
258
+
222
259
  if not self.is_compiled:
223
260
  # --- invalidate cached state splits --- #
224
261
  self._param_states = None
@@ -235,7 +272,7 @@ class ETraceAlgorithm(brainstate.nn.Module):
235
272
  self.is_compiled = True
236
273
 
237
274
  @property
238
- def path_to_states(self) -> brainstate.util.FlattedDict[Path, brainstate.State]:
275
+ def path_to_states(self) -> brainstate.util.FlattedDict:
239
276
  """
240
277
  Get the path to the states.
241
278
 
@@ -258,11 +295,28 @@ class ETraceAlgorithm(brainstate.nn.Module):
258
295
  """
259
296
  return self.graph_executor.state_id_to_path
260
297
 
261
- def show_graph(self) -> None:
262
- """
263
- Show the etrace graph.
298
+ def show_graph(
299
+ self,
300
+ verbose: bool = True,
301
+ return_msg: bool = False,
302
+ ) -> None | str:
303
+ """Display the eligibility-trace graph.
304
+
305
+ Delegates to :meth:`ETraceGraphExecutor.show_graph`.
306
+
307
+ Parameters
308
+ ----------
309
+ verbose : bool, optional
310
+ If True (default), print the summary to stdout.
311
+ return_msg : bool, optional
312
+ If True, return the summary string. Default False.
313
+
314
+ Returns
315
+ -------
316
+ None or str
317
+ The summary string if ``return_msg`` is True, else None.
264
318
  """
265
- self.graph_executor.show_graph()
319
+ return self.graph_executor.show_graph(verbose=verbose, return_msg=return_msg)
266
320
 
267
321
  def __call__(self, *args) -> Any:
268
322
  """
@@ -21,8 +21,8 @@ import brainstate
21
21
  import jax.numpy as jnp
22
22
 
23
23
  import braintrace
24
- from braintrace._etrace_algorithms import ETraceAlgorithm, EligibilityTrace
25
- from braintrace._etrace_algorithms.graph_executor import ETraceGraphExecutor
24
+ from braintrace._algorithm import ETraceAlgorithm, EligibilityTrace
25
+ from braintrace._algorithm.graph_executor import ETraceGraphExecutor
26
26
 
27
27
 
28
28
  # ---------------------------------------------------------------------------
@@ -580,5 +580,28 @@ class TestETraceAlgorithmTwoLayerIntegration(unittest.TestCase):
580
580
  self.assertGreaterEqual(len(algo.hidden_states), 2)
581
581
 
582
582
 
583
+ def test_report_before_compile_raises():
584
+ import brainstate, pytest, braintrace
585
+ from braintrace._algorithm.oracle_models import tanh_rnn
586
+ model = tanh_rnn(n_in=3, n_rec=4, seed=0).factory()
587
+ brainstate.nn.init_all_states(model, batch_size=1)
588
+ algo = braintrace.D_RTRL(model)
589
+ with pytest.raises(RuntimeError):
590
+ _ = algo.report
591
+
592
+
593
+ def test_report_after_compile_matches_show_graph():
594
+ import brainstate, jax.numpy as jnp, braintrace
595
+ from braintrace import CompilationReport
596
+ from braintrace._algorithm.oracle_models import tanh_rnn
597
+ model = tanh_rnn(n_in=3, n_rec=4, seed=0).factory()
598
+ brainstate.nn.init_all_states(model, batch_size=1)
599
+ algo = braintrace.D_RTRL(model)
600
+ algo.compile_graph(jnp.ones((3,), 'float32'))
601
+ assert isinstance(algo.report, CompilationReport)
602
+ # show_graph(return_msg=True) is exactly report.to_str(1)
603
+ assert algo.show_graph(verbose=False, return_msg=True) == algo.report.to_str(1)
604
+
605
+
583
606
  if __name__ == '__main__':
584
607
  unittest.main()