ETraceConfig#

class braintrace.ETraceConfig#

A point in the learning-rule axis space.

Six categorical axes carry the coordinate; four numeric fields carry the coefficients. Instances are canonicalised and validated at construction, so a coordinate has exactly one spelling and an illegal combination cannot be built at all.

Parameters:
  • trace_factorization (str, default ‘per_param’) – How the eligibility trace is stored, and therefore which engine runs it. 'per_param' keeps a trace per parameter element (ParamDimVjpAlgorithm, O(P*H)); 'io_factorized' keeps an input-side and an output-side factor (IODimVjpAlgorithm, O(I+O)); 'random_projection' keeps a rank-1 (hidden, parameter) factor pair carrying UORO’s unbiased estimator (RandomProjectionVjpAlgorithm, O(|theta| + P*S) of carrier storage). It is the only coordinate whose trace is unbiased, and it requires recurrence_scope='coupled' – see rule 11.

  • temporal_recursion (str or tuple of str, default ‘jacobian’) – The structural operator R in the trace recurrence. 'jacobian' uses the hidden-to-hidden Jacobian D, 'scalar_leak' replaces it with decay * I, 'none' with 0. Under 'io_factorized' this is a (x_side, f_side) pair; a scalar expands to both sides, with an x-side 'jacobian' demoted to 'scalar_leak' because the input-side trace never involves a Jacobian.

  • recurrence_scope (str, default ‘diagonal’) – How much hidden-to-hidden coupling enters D. 'diagonal' keeps only each state’s own recurrence; 'coupled' traces recurrent mixing between states of a hidden group; 'sparse_n' retains influence over an n-step neighbourhood derived from the model’s own transition (SnAp-n), with n supplied as sparse_n. The last two form one scale: SnAp-1 is 'coupled' (the instantaneous pattern propagated zero times), and sparse_n=1 canonicalises onto it. 'diagonal' sits below the scale – it drops the recurrent mixing primitive from the transition before differentiating – so no n reaches it.

  • learning_signal (str, default ‘symmetric’) – Where the per-hidden-group signal comes from. 'symmetric' uses the true dL/dh; 'random_feedback' projects it through a fixed random matrix (feedback alignment); 'modulatory' replaces it with a user-supplied neuromodulator (three-factor learning – one array expanded to every group, never a per-group sequence, and single-step only); 'bootstrapped' leaves it alone and instead injects a learned estimate of the future-loss gradient at the window’s exit cotangent (DNI), which reaches the plain parameters only – the eligibility trace already carries the ETP parameters’ cross-window credit.

  • trace_filter (str, default ‘none’) – Optional low-pass on the trace. 'kappa' applies e_bar <- kappa * e_bar + e, e-prop’s filter.

  • update_schedule (str, default ‘per_step’) – When the weight gradient is emitted.

  • decay (float or tuple of float, optional) – Per-step discount of the previous trace. Required by 'io_factorized' (where it is a (x, f) pair, a scalar expanding to both sides) and by 'per_param' with 'scalar_leak'. Must lie in [0, 1).

  • kappa (float, optional) – Coefficient of trace_filter='kappa', in [0, 1).

  • sparse_n (int, optional) – Coefficient of recurrence_scope='sparse_n': the SnAp order, an integer >= 1. Any order at or above a hidden group’s diameter saturates to full within-group RTRL, so there is no “infinity” spelling – saturation is a property of the model, not the vocabulary.

  • window_size (int, optional) – Coefficient of update_schedule='window'.

Raises:
  • ValueError – If a field carries a value outside its vocabulary, a coefficient is out of range, or the combination is rejected by the compatibility matrix.

  • TypeError – If a coefficient is not a number.

Notes

Canonicalisation runs before validation, so no rule ever fires on a spelling that canonicalisation would have removed:

  • 'scalar_leak' with decay == 0 becomes 'none' — they are one rule — and 'none' pins its decay side to 0.0.

  • Under 'io_factorized' a scalar temporal_recursion / decay expands to a pair.

  • trace_filter='kappa' with kappa == 0 becomes 'none', matching EProp(kappa_filter_decay=0)’s documented reduction to D_RTRL.

  • recurrence_scope='sparse_n' with sparse_n == 1 becomes 'coupled' with no coefficient — SnAp-1 and the block-diagonal recursion are one rule.

Examples

>>> import braintrace
>>> braintrace.ETraceConfig().trace_factorization
'per_param'
>>> # pp_prop's coordinate: a leaky input trace, a Jacobian output trace
>>> cfg = braintrace.ETraceConfig(
...     trace_factorization='io_factorized', decay=0.9)
>>> cfg.temporal_recursion
('scalar_leak', 'jacobian')
>>> # a coefficient with no category is a typo, not a configuration
>>> braintrace.ETraceConfig(kappa=0.5)
Traceback (most recent call last):
ValueError: `kappa=0.5` is set but `trace_filter` is 'none'...
property decay_f#

The f-side smoothing coefficient. io_factorized only.

property decay_x#

The x-side smoothing coefficient. io_factorized only.

describe()#

One-line human-readable coordinate, for reports and error messages.

Returns:

str – The non-default axes, or 'default' when the config is the default coordinate.

property include_recurrent_mixing#

Whether the compiler should trace hidden-to-hidden ETP mixing.

The graph executor’s spelling of recurrence_scope.

True for both non-diagonal scopes: 'coupled' needs the coupled transition to take its per-position block diagonal, and 'sparse_n' needs the same transition to gather its widened operator out of.

property is_factorized#

Whether the trace is stored as an input/output factor pair.

property recursion_f#

The f-side (output factor) recursion. io_factorized only.

property recursion_x#

The x-side (input factor) recursion. io_factorized only.

replace(**changes)#

Return a copy with changes applied, re-canonicalised and re-checked.

Parameters:

**changes – Field values to override.

Returns:

ETraceConfig – The new configuration.

Notes

The receiver is already canonical, so a field left unchanged is passed on in canonical form. That is only lossless because canonicalisation is idempotent — a canonical value always canonicalises to itself.

ETraceConfig.__init__(trace_factorization='per_param', temporal_recursion='jacobian', recurrence_scope='diagonal', learning_signal='symmetric', trace_filter='none', update_schedule='per_step', decay=None, kappa=None, sparse_n=None, window_size=None)#