braintrace 0.2.5__tar.gz → 0.2.6__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 (158) hide show
  1. {braintrace-0.2.5 → braintrace-0.2.6}/PKG-INFO +1 -1
  2. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/vjp_graph_executor.py +2 -2
  3. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compatible_imports.py +133 -1
  4. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compatible_imports_test.py +74 -0
  5. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/graph.py +2 -1
  6. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/hid_param_op.py +4 -1
  7. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/hid_param_op_test.py +29 -0
  8. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/hidden_group.py +14 -2
  9. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/hidden_group_test.py +43 -0
  10. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/scan_descent.py +2 -1
  11. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/scan_descent_test.py +14 -4
  12. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/tests/compiler_oracle_test.py +5 -1
  13. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_version.py +1 -1
  14. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace.egg-info/PKG-INFO +1 -1
  15. {braintrace-0.2.5 → braintrace-0.2.6}/LICENSE +0 -0
  16. {braintrace-0.2.5 → braintrace-0.2.6}/README.md +0 -0
  17. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/__init__.py +0 -0
  18. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/__init___test.py +0 -0
  19. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/__init__.py +0 -0
  20. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/_common.py +0 -0
  21. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/_common_test.py +0 -0
  22. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/axes.py +0 -0
  23. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/axes_test.py +0 -0
  24. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/base.py +0 -0
  25. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/base_test.py +0 -0
  26. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/d_rtrl.py +0 -0
  27. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/d_rtrl_test.py +0 -0
  28. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/dni.py +0 -0
  29. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/dni_test.py +0 -0
  30. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/e_prop.py +0 -0
  31. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/e_prop_test.py +0 -0
  32. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/graph_executor.py +0 -0
  33. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/graph_executor_test.py +0 -0
  34. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/io_dim_vjp.py +0 -0
  35. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/io_dim_vjp_test.py +0 -0
  36. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/ostl.py +0 -0
  37. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/ostl_test.py +0 -0
  38. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/param_dim_vjp.py +0 -0
  39. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/param_dim_vjp_test.py +0 -0
  40. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/pp_prop.py +0 -0
  41. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/pp_prop_test.py +0 -0
  42. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/random_projection_vjp.py +0 -0
  43. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/random_projection_vjp_test.py +0 -0
  44. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/sequence.py +0 -0
  45. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/sequence_test.py +0 -0
  46. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/snap_n.py +0 -0
  47. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/snap_n_test.py +0 -0
  48. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/tests/approx_correctness_test.py +0 -0
  49. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/tests/axis_acceptance_test.py +0 -0
  50. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/tests/axis_discrimination_test.py +0 -0
  51. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/tests/axis_golden_test.py +0 -0
  52. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/tests/conv_vmap_correctness_test.py +0 -0
  53. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/tests/cross_check_test.py +0 -0
  54. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/tests/diagnostic_exploration_test.py +0 -0
  55. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/tests/exact_correctness_test.py +0 -0
  56. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/tests/public_api_test.py +0 -0
  57. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/tests/scan_descent_support_test.py +0 -0
  58. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/tests/scan_fusion_test.py +0 -0
  59. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/tests/snn_model_correctness_test.py +0 -0
  60. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/tests/transform_correctness_test.py +0 -0
  61. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/tests/while_support_test.py +0 -0
  62. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/three_factor.py +0 -0
  63. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/three_factor_test.py +0 -0
  64. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/uoro.py +0 -0
  65. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/uoro_test.py +0 -0
  66. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/vjp_base.py +0 -0
  67. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/vjp_base_test.py +0 -0
  68. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_algorithm/vjp_graph_executor_test.py +0 -0
  69. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compile.py +0 -0
  70. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compile_test.py +0 -0
  71. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/__init__.py +0 -0
  72. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/base.py +0 -0
  73. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/base_test.py +0 -0
  74. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/canonicalize.py +0 -0
  75. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/canonicalize_test.py +0 -0
  76. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/diagnostics.py +0 -0
  77. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/diagnostics_test.py +0 -0
  78. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/graph_test.py +0 -0
  79. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/hidden_pertubation.py +0 -0
  80. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/hidden_pertubation_test.py +0 -0
  81. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/jaxpr_graph.py +0 -0
  82. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/jaxpr_graph_test.py +0 -0
  83. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/module_info.py +0 -0
  84. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/module_info_test.py +0 -0
  85. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/position_graph.py +0 -0
  86. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/position_graph_test.py +0 -0
  87. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/report.py +0 -0
  88. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/report_test.py +0 -0
  89. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/tests/cell_relation_guardrail_test.py +0 -0
  90. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_compiler/tests/compiler_property_test.py +0 -0
  91. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_grad_exponential.py +0 -0
  92. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_grad_exponential_test.py +0 -0
  93. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_input_data.py +0 -0
  94. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_input_data_test.py +0 -0
  95. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_legacy/__init__.py +0 -0
  96. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_legacy/_ops.py +0 -0
  97. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_legacy/_ops_test.py +0 -0
  98. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_legacy/_params.py +0 -0
  99. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_legacy/_params_test.py +0 -0
  100. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_misc.py +0 -0
  101. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_misc_test.py +0 -0
  102. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/__init__.py +0 -0
  103. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/_primitive.py +0 -0
  104. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/_primitive_test.py +0 -0
  105. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/_registries.py +0 -0
  106. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/_registries_test.py +0 -0
  107. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/conv.py +0 -0
  108. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/conv_test.py +0 -0
  109. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/dense.py +0 -0
  110. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/dense_test.py +0 -0
  111. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/einsum.py +0 -0
  112. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/einsum_test.py +0 -0
  113. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/elemwise.py +0 -0
  114. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/elemwise_test.py +0 -0
  115. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/embedding.py +0 -0
  116. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/embedding_test.py +0 -0
  117. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/grouped.py +0 -0
  118. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/grouped_test.py +0 -0
  119. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/lora.py +0 -0
  120. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/lora_test.py +0 -0
  121. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/op_rule_oracle.py +0 -0
  122. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/op_rule_oracle_test.py +0 -0
  123. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/sparse.py +0 -0
  124. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_op/sparse_test.py +0 -0
  125. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_state_management.py +0 -0
  126. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_state_management_test.py +0 -0
  127. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_testing/__init__.py +0 -0
  128. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_testing/compiler_models.py +0 -0
  129. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_testing/models.py +0 -0
  130. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_testing/oracle.py +0 -0
  131. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_testing/oracle_models.py +0 -0
  132. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_testing/oracle_models_test.py +0 -0
  133. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_testing/oracle_test.py +0 -0
  134. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_testing/scenario_catalog.py +0 -0
  135. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_testing/scenario_catalog_test.py +0 -0
  136. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_typing.py +0 -0
  137. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_typing_test.py +0 -0
  138. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/_version_test.py +0 -0
  139. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/nn/__init__.py +0 -0
  140. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/nn/__init___test.py +0 -0
  141. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/nn/_conv.py +0 -0
  142. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/nn/_conv_test.py +0 -0
  143. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/nn/_embedding.py +0 -0
  144. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/nn/_embedding_test.py +0 -0
  145. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/nn/_linear.py +0 -0
  146. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/nn/_linear_test.py +0 -0
  147. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/nn/_readout.py +0 -0
  148. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/nn/_readout_test.py +0 -0
  149. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/nn/_rnn.py +0 -0
  150. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/nn/_rnn_test.py +0 -0
  151. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace/py.typed +0 -0
  152. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace.egg-info/SOURCES.txt +0 -0
  153. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace.egg-info/dependency_links.txt +0 -0
  154. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace.egg-info/requires.txt +0 -0
  155. {braintrace-0.2.5 → braintrace-0.2.6}/braintrace.egg-info/top_level.txt +0 -0
  156. {braintrace-0.2.5 → braintrace-0.2.6}/pyproject.toml +0 -0
  157. {braintrace-0.2.5 → braintrace-0.2.6}/setup.cfg +0 -0
  158. {braintrace-0.2.5 → braintrace-0.2.6}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braintrace
3
- Version: 0.2.5
3
+ Version: 0.2.6
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
@@ -49,7 +49,7 @@ from brainstate._compatible_import import get_aval
49
49
  from jax.interpreters import partial_eval as pe
50
50
  from jax.tree_util import register_pytree_node_class
51
51
 
52
- from braintrace._compatible_imports import Var, wrap_init
52
+ from braintrace._compatible_imports import Var, jaxpr_constvars, wrap_init
53
53
  from braintrace._compiler import (
54
54
  ControlFlowPolicy,
55
55
  DEFAULT_MAX_JACOBIAN_ELEMENTS,
@@ -341,7 +341,7 @@ class ETraceVjpGraphExecutor(ETraceGraphExecutor):
341
341
  y_stack = intermediate_values[m[relation.y_var]]
342
342
  cvars = list(dict.fromkeys(
343
343
  v for j in relation.y_to_hidden_group_jaxprs
344
- for v in j.constvars))
344
+ for v in jaxpr_constvars(j, 1)))
345
345
  c_stacks = tuple(intermediate_values[m[v]] for v in cvars)
346
346
 
347
347
  def _one_substep(
@@ -32,9 +32,12 @@ __all__ = [
32
32
  'scan_num_consts_carry',
33
33
  'scan_params_add_ys',
34
34
  'wrap_init',
35
+ 'jaxpr_all_invars',
36
+ 'split_jaxpr_invars',
37
+ 'jaxpr_constvars',
35
38
  ]
36
39
 
37
- from typing import Any, Dict, Tuple
40
+ from typing import Any, Dict, List, Tuple
38
41
 
39
42
  from brainstate._compatible_import import Primitive, Var, JaxprEqn, Jaxpr, ClosedJaxpr, Literal, wrap_init
40
43
 
@@ -146,3 +149,132 @@ def scan_params_add_ys(params: Dict, n_extra: int) -> Dict:
146
149
  carry_ft, ys_ft = params['ft_out'].unpack()
147
150
  new_ft_out = _ft.pack((carry_ft, _ft.pack((ys_ft, _ft.nones(n_extra)))))
148
151
  return {**params, 'ft_out': new_ft_out}
152
+
153
+
154
+ def jaxpr_all_invars(jaxpr: Jaxpr) -> List[Var]:
155
+ """Return every positional input of *jaxpr*, constvars first.
156
+
157
+ This is the argument order :func:`jax.core.eval_jaxpr` expects: it writes
158
+ ``[*consts, *args]`` against exactly this list.
159
+
160
+ JAX 0.11 merged ``ClosedJaxpr`` into ``Jaxpr`` and now derives the
161
+ ``constvars`` / ``invars`` boundary from how many const *values* are
162
+ attached, rather than storing it with the symbols. An open jaxpr built with
163
+ symbolic constvars and no attached values therefore reports
164
+ ``constvars == []`` and ``invars == [*constvars, *invars]``. Their
165
+ concatenation is stable across every supported JAX version, which is why
166
+ every split in this module is derived from it.
167
+
168
+ Parameters
169
+ ----------
170
+ jaxpr : Jaxpr
171
+ The jaxpr to inspect.
172
+
173
+ Returns
174
+ -------
175
+ list of Var
176
+ The concatenation ``[*jaxpr.constvars, *jaxpr.invars]``.
177
+
178
+ Examples
179
+ --------
180
+ .. code-block:: python
181
+
182
+ >>> import jax
183
+ >>> import jax.numpy as jnp
184
+ >>> from braintrace._compatible_imports import jaxpr_all_invars
185
+ >>> jaxpr = jax.make_jaxpr(lambda x, y: x * y)(jnp.ones(3), jnp.ones(3))
186
+ >>> len(jaxpr_all_invars(jaxpr.jaxpr))
187
+ 2
188
+ """
189
+ return [*jaxpr.constvars, *jaxpr.invars]
190
+
191
+
192
+ def split_jaxpr_invars(jaxpr: Jaxpr, num_invars: int) -> Tuple[List[Var], List[Var]]:
193
+ """Split *jaxpr*'s positional inputs into ``(constvars, invars)``.
194
+
195
+ The compiler builds transition jaxprs whose ``invars`` are the
196
+ differentiated inputs and whose ``constvars`` are surrounding intermediates
197
+ bound at execution time. Since JAX 0.11 that boundary cannot be read back
198
+ off the jaxpr (see :func:`jaxpr_all_invars`), so it is recovered from the
199
+ invar count, which every caller already knows -- the invars are what it is
200
+ about to feed in.
201
+
202
+ Parameters
203
+ ----------
204
+ jaxpr : Jaxpr
205
+ The jaxpr to split.
206
+ num_invars : int
207
+ The number of trailing positional inputs that are ``invars``. The
208
+ leading remainder are the ``constvars``.
209
+
210
+ Returns
211
+ -------
212
+ tuple of (list of Var, list of Var)
213
+ ``(constvars, invars)``.
214
+
215
+ Raises
216
+ ------
217
+ ValueError
218
+ If *num_invars* is negative or exceeds the number of positional inputs.
219
+
220
+ Examples
221
+ --------
222
+ .. code-block:: python
223
+
224
+ >>> import jax
225
+ >>> import jax.numpy as jnp
226
+ >>> from braintrace._compatible_imports import split_jaxpr_invars
227
+ >>> jaxpr = jax.make_jaxpr(lambda x, y: x * y)(jnp.ones(3), jnp.ones(3))
228
+ >>> constvars, invars = split_jaxpr_invars(jaxpr.jaxpr, 1)
229
+ >>> len(constvars), len(invars)
230
+ (1, 1)
231
+ """
232
+ all_invars = jaxpr_all_invars(jaxpr)
233
+ if not 0 <= num_invars <= len(all_invars):
234
+ raise ValueError(
235
+ f'Cannot split a jaxpr with {len(all_invars)} positional inputs at '
236
+ f'num_invars={num_invars}. This means the caller and the jaxpr '
237
+ f'disagree about the transition signature; evaluating it would '
238
+ f'misalign the eval_jaxpr argument list.'
239
+ )
240
+ boundary = len(all_invars) - num_invars
241
+ return all_invars[:boundary], all_invars[boundary:]
242
+
243
+
244
+ def jaxpr_constvars(jaxpr: Jaxpr, num_invars: int) -> List[Var]:
245
+ """Return only the ``constvars`` of *jaxpr*, given its invar count.
246
+
247
+ Thin wrapper over :func:`split_jaxpr_invars` for the common case where the
248
+ caller needs the const values to pass to :func:`jax.core.eval_jaxpr` and
249
+ already holds the invars.
250
+
251
+ Parameters
252
+ ----------
253
+ jaxpr : Jaxpr
254
+ The jaxpr to inspect.
255
+ num_invars : int
256
+ The number of trailing positional inputs that are ``invars``.
257
+
258
+ Returns
259
+ -------
260
+ list of Var
261
+ The leading ``constvars``.
262
+
263
+ Raises
264
+ ------
265
+ ValueError
266
+ If *num_invars* is negative or exceeds the number of positional inputs.
267
+
268
+ Examples
269
+ --------
270
+ .. code-block:: python
271
+
272
+ >>> import jax
273
+ >>> import jax.numpy as jnp
274
+ >>> from braintrace._compatible_imports import jaxpr_constvars
275
+ >>> jaxpr = jax.make_jaxpr(lambda x, y: x * y)(jnp.ones(3), jnp.ones(3))
276
+ >>> len(jaxpr_constvars(jaxpr.jaxpr, 1))
277
+ 1
278
+ """
279
+ constvars, _ = split_jaxpr_invars(jaxpr, num_invars)
280
+ return constvars
@@ -15,12 +15,16 @@
15
15
 
16
16
  import types
17
17
 
18
+ import jax
18
19
  import jax.numpy as jnp
20
+ import pytest
19
21
  from jax import jit, make_jaxpr, lax
20
22
 
21
23
  from braintrace._compatible_imports import (
24
+ Jaxpr,
22
25
  is_jit_primitive, is_scan_primitive, is_while_primitive,
23
26
  is_cond_primitive, scan_num_consts_carry, scan_params_add_ys,
27
+ jaxpr_all_invars, split_jaxpr_invars, jaxpr_constvars,
24
28
  )
25
29
 
26
30
 
@@ -81,6 +85,76 @@ class TestScanAddYs:
81
85
  assert len(new_ys) == len(old_ys) + 2 # ys grew by 2
82
86
 
83
87
 
88
+ def _open_jaxpr_with_split(num_constvars: int):
89
+ """An open jaxpr built the way the compiler builds transition jaxprs.
90
+
91
+ Symbolic ``constvars`` with no attached const *values* -- the shape JAX
92
+ 0.11 no longer records a boundary for. Returns ``(jaxpr, constvars,
93
+ invars)`` so a test can compare against the intended split rather than
94
+ whatever the object reports.
95
+ """
96
+
97
+ def f(a, b, h):
98
+ return a * h + b
99
+
100
+ traced = make_jaxpr(f)(jnp.ones(3), jnp.ones(3), jnp.ones(3)).jaxpr
101
+ all_in = jaxpr_all_invars(traced)
102
+ constvars, invars = all_in[:num_constvars], all_in[num_constvars:]
103
+ jaxpr = Jaxpr(
104
+ constvars=constvars,
105
+ invars=invars,
106
+ outvars=traced.outvars,
107
+ eqns=traced.eqns,
108
+ debug_info=traced.debug_info,
109
+ )
110
+ return jaxpr, constvars, invars
111
+
112
+
113
+ class TestJaxprInvarSplit:
114
+ """The const/invar split of a value-less open jaxpr survives JAX 0.11.
115
+
116
+ JAX 0.11 merged ``ClosedJaxpr`` into ``Jaxpr`` and derives
117
+ ``constvars``/``invars`` from how many const *values* are attached, so an
118
+ open jaxpr built with symbolic constvars reports ``constvars == []``. These
119
+ helpers recover the boundary from the known invar count instead.
120
+ """
121
+
122
+ def test_all_invars_is_the_eval_jaxpr_argument_order(self):
123
+ jaxpr, constvars, invars = _open_jaxpr_with_split(2)
124
+ assert jaxpr_all_invars(jaxpr) == [*constvars, *invars]
125
+
126
+ def test_split_recovers_the_intended_boundary(self):
127
+ jaxpr, constvars, invars = _open_jaxpr_with_split(2)
128
+ assert split_jaxpr_invars(jaxpr, len(invars)) == (constvars, invars)
129
+ assert jaxpr_constvars(jaxpr, len(invars)) == constvars
130
+
131
+ def test_the_recovered_consts_actually_evaluate(self):
132
+ # The regression that broke the whole suite on jaxlib 0.11.1: reading
133
+ # ``jaxpr.constvars`` back handed eval_jaxpr too few values.
134
+ jaxpr, _, invars = _open_jaxpr_with_split(2)
135
+ consts = [jnp.full((3,), 2.0), jnp.full((3,), 5.0)]
136
+ out = jax.core.eval_jaxpr(jaxpr, consts, jnp.full((3,), 3.0))
137
+ assert jnp.allclose(out[0], 2.0 * 3.0 + 5.0)
138
+
139
+ def test_zero_constvars_edge(self):
140
+ jaxpr, constvars, invars = _open_jaxpr_with_split(0)
141
+ assert constvars == []
142
+ assert jaxpr_constvars(jaxpr, len(invars)) == []
143
+
144
+ def test_all_constvars_edge(self):
145
+ jaxpr, constvars, invars = _open_jaxpr_with_split(3)
146
+ assert invars == []
147
+ assert jaxpr_constvars(jaxpr, 0) == constvars
148
+
149
+ @pytest.mark.parametrize('num_invars', [-1, 4])
150
+ def test_out_of_range_num_invars_raises(self, num_invars):
151
+ # A miscounted call must fail at the compiler boundary, not silently
152
+ # produce a misaligned eval_jaxpr argument list.
153
+ jaxpr, _, _ = _open_jaxpr_with_split(1)
154
+ with pytest.raises(ValueError, match='positional inputs'):
155
+ split_jaxpr_invars(jaxpr, num_invars)
156
+
157
+
84
158
  class TestPrimitive:
85
159
  def test_jit(self):
86
160
  @jit
@@ -22,6 +22,7 @@ import brainstate
22
22
  import jax
23
23
  import numpy as np
24
24
 
25
+ from braintrace._compatible_imports import jaxpr_all_invars
25
26
  from braintrace._misc import NotSupportedError
26
27
  from braintrace._typing import (
27
28
  ETraceVals,
@@ -571,7 +572,7 @@ def compile_etrace_graph(
571
572
  if relation.control_flow_context is not None:
572
573
  continue
573
574
  for hpo_jaxpr in relation.y_to_hidden_group_jaxprs:
574
- for v in hpo_jaxpr.invars + hpo_jaxpr.constvars:
575
+ for v in jaxpr_all_invars(hpo_jaxpr):
575
576
  out_wy2hid_jaxvars_dict[v] = None
576
577
  out_wy2hid_jaxvars = list(out_wy2hid_jaxvars_dict)
577
578
 
@@ -63,6 +63,7 @@ from braintrace._compatible_imports import (
63
63
  is_scan_primitive,
64
64
  is_while_primitive,
65
65
  is_cond_primitive,
66
+ jaxpr_constvars,
66
67
  )
67
68
  from braintrace._op import (
68
69
  get_trainable_invars,
@@ -248,7 +249,9 @@ class HiddenParamOpRelation(NamedTuple):
248
249
  """
249
250
  vals_of_hidden_groups = []
250
251
  for jaxpr, group in zip(self.y_to_hidden_group_jaxprs, self.hidden_groups):
251
- consts = [const_vals[var] for var in jaxpr.constvars]
252
+ # ``y`` is the jaxpr's only invar (see ``_build_transition_jaxpr``);
253
+ # everything ahead of it is a constvar bound from the forward pass.
254
+ consts = [const_vals[var] for var in jaxpr_constvars(jaxpr, 1)]
252
255
  # ``list[Array]`` before concatenation, a single ``Array`` after.
253
256
  hidden_vals: Any = jax.core.eval_jaxpr(jaxpr, consts, y_val)
254
257
  if concat_hidden_vals:
@@ -195,3 +195,32 @@ class TestTrainableInvarsPopulatedForDense:
195
195
  assert r.trainable_leaf_indices['weight'] == 0
196
196
  assert r.trainable_processing_chains['weight'] == ()
197
197
  assert r.trainable_param_states['weight'] is not None
198
+
199
+
200
+ class TestYToHiddenJaxprConstvarSplit:
201
+ """The ``y -> hidden group`` jaxprs keep a recoverable const/invar split.
202
+
203
+ Since JAX 0.11 an open jaxpr with symbolic-only constvars reports
204
+ ``constvars == []``, so the split is recovered from the invar count instead:
205
+ these jaxprs take exactly one invar, the relation's ``y_var``. The
206
+ executable counterpart of this assertion lives in
207
+ ``_testing/scenario_catalog_test.py::test_gru_y_to_hidden_groups_executes``.
208
+ """
209
+
210
+ def test_y_is_the_sole_invar_and_the_rest_are_constvars(self):
211
+ import jax.numpy as jnp
212
+ from braintrace._compatible_imports import jaxpr_all_invars, split_jaxpr_invars
213
+
214
+ gru = braintrace.nn.GRUCell(3, 4)
215
+ brainstate.nn.init_all_states(gru)
216
+ relations = find_hidden_param_op_relations_from_module(gru, jnp.zeros(3))
217
+
218
+ assert len(relations) > 0
219
+ checked = 0
220
+ for r in relations:
221
+ for jaxpr in r.y_to_hidden_group_jaxprs:
222
+ constvars, invars = split_jaxpr_invars(jaxpr, 1)
223
+ assert invars == [r.y_var]
224
+ assert constvars == jaxpr_all_invars(jaxpr)[:-1]
225
+ checked += 1
226
+ assert checked > 0
@@ -63,6 +63,7 @@ from braintrace._compatible_imports import (
63
63
  is_scan_primitive,
64
64
  is_while_primitive,
65
65
  is_cond_primitive,
66
+ jaxpr_constvars,
66
67
  scan_num_consts_carry,
67
68
  )
68
69
  from braintrace._op import is_etp_primitive, is_etp_enable_gradient_primitive
@@ -1621,6 +1622,11 @@ class JaxprEvalForHiddenGroup(JaxprEvaluation):
1621
1622
  pattern = build_snap_pattern(
1622
1623
  group.transition_jaxpr, group.varshape, self.sparse_n,
1623
1624
  num_state=group.num_state,
1625
+ # Seed the adjacency walk from the hidden invars explicitly. Since
1626
+ # JAX 0.11 the jaxpr's own ``invars`` also lists the constvars, so
1627
+ # the implicit default would widen the seed set and inflate the
1628
+ # derived pattern (usually all the way to conservative).
1629
+ hidden_invars=group.hidden_invars,
1624
1630
  max_jacobian_elements=self.snap_max_jacobian_elements,
1625
1631
  )
1626
1632
  if pattern.conservative:
@@ -1764,7 +1770,10 @@ class JaxprEvalForHiddenGroup(JaxprEvaluation):
1764
1770
  for outvar in hidden_outvars
1765
1771
  ],
1766
1772
  transition_jaxpr=jaxpr,
1767
- transition_jaxpr_constvars=list(jaxpr.constvars),
1773
+ # ``write_jaxpr_of_hidden_group_transition`` gives the jaxpr one
1774
+ # invar per hidden state; the leading remainder are the
1775
+ # constvars bound from the forward pass.
1776
+ transition_jaxpr_constvars=jaxpr_constvars(jaxpr, len(hidden_invars)),
1768
1777
  is_diagonal_recurrence=not self.include_recurrent_mixing,
1769
1778
  )
1770
1779
  group = self._attach_snap_pattern(group)
@@ -1832,7 +1841,10 @@ class JaxprEvalForHiddenGroup(JaxprEvaluation):
1832
1841
  hidden_paths=[self.outvar_to_hidden_path[outvar]],
1833
1842
  hidden_states=[self.path_to_state[self.outvar_to_hidden_path[outvar]]],
1834
1843
  transition_jaxpr=zero_jaxpr,
1835
- transition_jaxpr_constvars=list(zero_jaxpr.constvars),
1844
+ # Mirrors ``zero_jaxpr``'s ``constvars=[outvar], invars=[invar]``
1845
+ # above -- read literally, not back off the jaxpr, which since
1846
+ # JAX 0.11 no longer records the boundary for a value-less split.
1847
+ transition_jaxpr_constvars=[outvar],
1836
1848
  # A zero-recurrence transition (``D^t = 0``) is trivially diagonal;
1837
1849
  # keep the flag mode-derived for uniformity (this fallback only
1838
1850
  # fires in the default mode in practice).
@@ -1975,3 +1975,46 @@ class TestSplitHiddenWidthGuard:
1975
1975
  assert len(parts) == 2
1976
1976
  np.testing.assert_array_equal(np.asarray(parts[0]), np.ones((2, 3)))
1977
1977
  np.testing.assert_array_equal(np.asarray(parts[1]), np.full((2, 3), 2.0))
1978
+
1979
+
1980
+ from braintrace._compatible_imports import jaxpr_all_invars
1981
+
1982
+
1983
+ class TestTransitionJaxprConstvarSplit:
1984
+ """A compiled group's const/invar split stays intact on every JAX version.
1985
+
1986
+ JAX 0.11 merged ``ClosedJaxpr`` into ``Jaxpr`` and stopped recording the
1987
+ boundary for an open jaxpr with symbolic-only constvars, which is exactly
1988
+ what the compiler builds here. ``transition_jaxpr_constvars`` must therefore
1989
+ be carried explicitly rather than read back off the jaxpr.
1990
+ """
1991
+
1992
+ def _gru_group(self):
1993
+ gru = braintrace.nn.GRUCell(3, 4)
1994
+ brainstate.nn.init_all_states(gru)
1995
+ groups, _ = find_hidden_groups_from_module(gru, brainstate.random.randn(3))
1996
+ assert len(groups) == 1
1997
+ return groups[0]
1998
+
1999
+ def test_constvars_are_the_leading_positional_inputs(self):
2000
+ group = self._gru_group()
2001
+ all_in = jaxpr_all_invars(group.transition_jaxpr)
2002
+ n_const = len(all_in) - len(group.hidden_invars)
2003
+ # A non-trivial split: reading ``.constvars`` back would give [] on 0.11.
2004
+ assert n_const > 0
2005
+ assert group.transition_jaxpr_constvars == all_in[:n_const]
2006
+ assert list(group.hidden_invars) == all_in[n_const:]
2007
+
2008
+ def test_the_transition_evaluates_with_those_constvars(self):
2009
+ # The arity failure that broke the suite on jaxlib 0.11.1 surfaces here.
2010
+ group = self._gru_group()
2011
+ input_vals = [
2012
+ jnp.zeros(v.aval.shape, v.aval.dtype)
2013
+ for v in group.transition_jaxpr_constvars
2014
+ ]
2015
+ hidden_vals = [
2016
+ jnp.zeros(v.aval.shape, v.aval.dtype)
2017
+ for v in group.hidden_invars
2018
+ ]
2019
+ out = group.transition(hidden_vals, input_vals)
2020
+ assert len(out) == len(group.hidden_outvars)
@@ -64,6 +64,7 @@ from braintrace._compatible_imports import (
64
64
  is_cond_primitive,
65
65
  is_scan_primitive,
66
66
  is_while_primitive,
67
+ jaxpr_all_invars,
67
68
  new_var,
68
69
  scan_num_consts_carry,
69
70
  scan_params_add_ys,
@@ -443,7 +444,7 @@ def analyze_and_rewrite_scan(eqn: JaxprEqn, minfo: 'ModuleInfo') -> Optional[Sca
443
444
  if r.x_var is not None:
444
445
  hoist_seen[r.x_var] = None
445
446
  for j in r.y_to_hidden_group_jaxprs:
446
- for v in list(j.invars) + list(j.constvars):
447
+ for v in jaxpr_all_invars(j):
447
448
  hoist_seen[v] = None
448
449
  for g in body_groups:
449
450
  for v in list(g.hidden_invars) + list(g.transition_jaxpr_constvars):
@@ -13,7 +13,12 @@ import pytest
13
13
 
14
14
  import braintrace
15
15
  from braintrace import ControlFlowPolicy
16
- from braintrace._compatible_imports import is_scan_primitive, scan_num_consts_carry
16
+ from braintrace._compatible_imports import (
17
+ is_scan_primitive,
18
+ jaxpr_constvars,
19
+ scan_num_consts_carry,
20
+ split_jaxpr_invars,
21
+ )
17
22
  from braintrace._compiler.module_info import extract_module_info
18
23
  from braintrace._compiler.scan_descent import (
19
24
  _descent_blockers,
@@ -219,8 +224,13 @@ class TestAnalyzeAndRewriteScan:
219
224
  # outer-facing hidden vars are the scan carry vars, known to minfo
220
225
  assert g.hidden_outvars[0] in minfo.outvar_to_hidden_path
221
226
  assert g.hidden_invars[0] in minfo.invar_to_hidden_path
222
- # body-scoped transition: one substep, invars == descent.body_hidden_invars
223
- assert list(g.transition_jaxpr.invars) == list(g.descent.body_hidden_invars)
227
+ # body-scoped transition: one substep, invars == descent.body_hidden_invars.
228
+ # Split by invar count rather than reading ``.invars`` -- since JAX 0.11
229
+ # that also lists the constvars for a value-less open jaxpr.
230
+ _, transition_invars = split_jaxpr_invars(
231
+ g.transition_jaxpr, len(g.descent.body_hidden_invars)
232
+ )
233
+ assert list(transition_invars) == list(g.descent.body_hidden_invars)
224
234
 
225
235
  assert len(bundle.relations) == 1
226
236
  r = bundle.relations[0]
@@ -231,7 +241,7 @@ class TestAnalyzeAndRewriteScan:
231
241
  m = bundle.info.stacked_var_map
232
242
  assert r.x_var in m and r.y_var in m
233
243
  for j in r.y_to_hidden_group_jaxprs:
234
- assert all(v in m for v in j.constvars)
244
+ assert all(v in m for v in jaxpr_constvars(j, 1))
235
245
  assert all(v in m for v in g.descent.body_hidden_invars)
236
246
  assert all(v in m for v in g.transition_jaxpr_constvars)
237
247
  # stacked avals carry the substep axis
@@ -47,6 +47,7 @@ import jax.numpy as jnp
47
47
  import numpy as np
48
48
 
49
49
  from braintrace import compile_etrace_graph
50
+ from braintrace._compatible_imports import jaxpr_constvars
50
51
  from braintrace._testing.scenario_catalog import (
51
52
  ElemwiseOnlyRNN,
52
53
  PartialPathRNN,
@@ -67,8 +68,11 @@ def _transition_callable(rel, group, const_vals):
67
68
  The returned callable takes ``y_val`` and returns the *concatenated*
68
69
  hidden state value for the matching group.
69
70
  """
70
- consts = [const_vals[v] for v in rel.y_to_hidden_group_jaxprs[0].constvars]
71
71
  jaxpr = rel.y_to_hidden_group_jaxprs[0]
72
+ # ``y`` is the jaxpr's sole invar; everything ahead of it is a constvar.
73
+ # Read via the helper, not ``jaxpr.constvars`` -- since JAX 0.11 an open
74
+ # jaxpr with symbolic-only constvars reports that as empty.
75
+ consts = [const_vals[v] for v in jaxpr_constvars(jaxpr, 1)]
72
76
 
73
77
  def f(y_val):
74
78
  out = jax.core.eval_jaxpr(jaxpr, consts, y_val)
@@ -13,5 +13,5 @@
13
13
  # limitations under the License.
14
14
  # ==============================================================================
15
15
 
16
- __version__ = "0.2.5"
16
+ __version__ = "0.2.6"
17
17
  __version_info__ = tuple(map(int, __version__.split('.')))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braintrace
3
- Version: 0.2.5
3
+ Version: 0.2.6
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
File without changes
File without changes
File without changes
File without changes
File without changes