Skip to content

Legendre delay memory

LegendreDelayLayer compresses recent signal history into Legendre polynomial coefficients. Its memory dynamics are fixed and linear; you can fit an ordinary readout on top or combine it with a nonlinear reservoir.

from resdag import LegendreDelayLayer

memory = LegendreDelayLayer(order=8, feedback_size=2, theta=50.0, dt=1.0)
# Input: (batch, time, 2). Output: (batch, time, 16).

order controls coefficients per channel, not total layer width. By default, every feedback/driver feature gets its own memory channel. In the example, two channels times eight coefficients gives 16 features. memory_channels= instead chooses a projected channel count; use feedback_initializer and input_initializer to customize the input encoders.

theta is the nominal history window in the same units as dt. With samples one second apart, theta=50, dt=1 targets roughly 50 seconds of history. Increasing order improves the representation within that window at the cost of a larger state. A finite-order delay network approximates a sliding history; it does not store every past sample exactly.

The continuous Legendre matrices are discretized with an augmented matrix exponential under a zero-order-held input. They are registered buffers, move with .to(), and are saved with state_dict(). Their native spectrum is part of the memory definition, so there is no arbitrary spectral_radius knob. trainable=True allows input encoders to train while leaving the analytical memory dynamics fixed.

The state and output share width order * memory_channels. Coefficients are packed channel by channel. Both standard and explicit-state sequence paths work, as do downstream readout fitting and checkpointing.

This is the fixed Legendre delay-network memory described in the Legendre Memory Unit paper. It implements the memory component; a learned nonlinear hidden unit is a separate component you can compose around it.

See layer composition, training, and API reference.