compile_etrace_graph#
- class braintrace.compile_etrace_graph(model, *model_args, include_hidden_perturb=True, include_recurrent_mixing=False, control_flow=None)[source]#
Construct the eligibility-trace graph for a given model and inputs.
This is the primary entry point of the ETrace compiler. It builds the graph for the model, tracking the relationship between the eligibility-trace weights (
ParamState), the eligibility-trace states (HiddenState), and the eligibility-trace operations (ETP primitives). These relationships are later used to compute the weight spatial gradients, the hidden-state Jacobian, and the hidden-state-to-weight Jacobian.- Parameters:
model (
Module) – The model for which the eligibility-trace graph is built.*model_args (
Tuple) – The positional arguments required by the model.include_hidden_perturb (
bool) – Whether to include hidden perturbations in the graph. DefaultTrue.include_recurrent_mixing (
bool) – Hidden-group grouping mode for the hidden-to-hidden transition. WhenFalse(default, “without recurrence”), recurrent ETP mixing primitives (e.g. the recurrentetp_mv/etp_mm) are treated as boundaries and excluded from the transition jaxpr, so the transition is element-wise and the per-position recurrent Jacobian is diagonal (the bounded D-RTRL / e-prop approximation). WhenTrue(“with recurrence”), those primitives are traced into the transition, the recurrence becomes coupled, and the true per-position block-diagonal Jacobian is extracted (RTRL-exact temporal credit, e.g. forOSTLRecurrent/OSTTP).control_flow (
ControlFlowPolicy|None) –Policy governing control-flow canonicalization and downstream handling, forwarded to
extract_module_info()and (viaModuleInfo.control_flow) to every later compiler pass.None(default) uses the default policy, which:if-converts every ETP-relevant
condinto inlined branches +select_n(both branches then execute every step); passControlFlowPolicy(cond='opaque')to restore the previous behavior (weights insidecondraiseNotImplementedError);unrolls every ETP-relevant
scanof static length at mostscan_unroll_limit(default 16);applies structured scan descent (
scan_descent='auto') to ETP-relevant scans above the unroll limit: relations and hidden groups are discovered inside the scan body, the equation is rewritten to emit stacked per-substep values as extra ys, and the eligibility trace is folded over the substep axis at runtime — compile size stays independent of the scan length. PassControlFlowPolicy(scan_descent='off')to restore the pre-Phase-4 error. Seebraintrace._compiler.scan_descent;keeps a weight-free
whilethat reads/updates hidden state as an opaque forward node (while_hidden='opaque-fwd'): hidden-to-hidden Jacobians for groups whose transition crosses the loop are extracted in forward mode, and the perturbation pass detaches the loop’s inputs withstop_gradientso the perturbed jaxpr stays reverse-traceable. PassControlFlowPolicy(while_hidden='error')to reject such loops instead. A weight used through an ETP primitive inside awhileis always a hard error;raises on ETP primitives left inside a control-flow body the canonicalizer could not flatten (
etp_in_control_flow='error'); passControlFlowPolicy(etp_in_control_flow='exclude')to restore the warn-and-exclude behavior.
- Returns:
The compiled eligibility-trace graph containing module information, hidden groups, hidden parameter-operation relations, and optional hidden perturbations.
- Return type:
- Raises:
NotImplementedError – If a recursive call to the compiler is detected.
See also
ETraceGraphThe returned compiled-graph data structure.
Examples
>>> import brainstate >>> import braintrace >>> gru = braintrace.nn.GRUCell(3, 4) >>> _ = brainstate.nn.init_all_states(gru) >>> inputs = brainstate.random.randn(3) >>> graph = braintrace.compile_etrace_graph(gru, inputs) >>> len(graph.hidden_groups) 1