Developer Interfaces

Warning

These interfaces describe implementation contracts used to maintain and extend ReservoirComputing.jl. They are versioned and tested, but they are not ordinary end-user model constructors. Prefer the documented concrete models, cells, and ReservoirComputer composition API unless you are implementing a new reservoir family.

Reservoir Containers

ReservoirComputing.AbstractReservoirComputerType
AbstractReservoirComputer{Fields} <: AbstractLuxContainerLayer{Fields}

Developer interface for a Lux-compatible reservoir-computing container.

Type parameters

  • Fields: the Tuple of container field names reported to Lux. Reservoir containers use (:reservoir, :state_modifiers, :readout).

Required fields

Subtypes using the generic ReservoirComputing implementation must provide:

  • reservoir: a Lux-compatible layer that produces reservoir features.
  • state_modifiers: a Tuple of Lux-compatible layers applied in order to those features. Use () when no modifiers are required.
  • readout: a Lux-compatible layer that maps features to model outputs.

Extension contract

Implement the fields above and the ordinary Lux layer call contract. The generic LuxCore.initialparameters, LuxCore.initialstates, function-call, and collectstates methods then compose the three components. Each component must accept its matching parameter and state entry and return (output, updated_state) through LuxCore.apply.

Ordinary state_modifiers receive the current feature array. An Extend modifier additionally receives the input to the model, or the input to the current layer of a deep model, and prepends that input to the wrapped modifier's output. High-level model constructors account for this extra width automatically when the operation wrapped by Extend preserves the feature width. Pass readout_in_dims when a custom modifier changes the feature width in another way. Parameter and state containers returned by the Lux generic functions have the named fields reservoir, state_modifiers, and readout in that order.

Example

struct MyReservoirComputer <: AbstractReservoirComputer{
        (:reservoir, :state_modifiers, :readout)}
    reservoir
    state_modifiers
    readout
end

Use ReservoirComputer unless a new model type needs its own construction or presentation API.

source
ReservoirComputing.AbstractEchoStateNetworkType
AbstractEchoStateNetwork{Fields} <: AbstractReservoirComputer{Fields}

Developer interface for an echo-state-network model container.

Type parameters

  • Fields: the Lux container field tuple. Most ESN models use (:reservoir, :state_modifiers, :readout).

Required fields

Subtypes follow the AbstractReservoirComputer field contract. Their reservoir must be a Lux-compatible reservoir layer, normally a StatefulLayer around an AbstractEchoStateNetworkCell. state_modifiers is a tuple of feature transforms and readout is the final Lux-compatible mapping.

Extension contract

This type adds ESN semantics to the generic reservoir-container contract; it does not introduce a separate dispatch hook. Subtypes inherit the generic LuxCore.initialparameters, LuxCore.initialstates, function-call, and collectstates behavior when their fields obey the container invariants. The reservoir must produce a consistent feature shape at every time step, and the readout must consume that shape after all modifiers.

Example

struct MyESN <: AbstractEchoStateNetwork{(:reservoir, :state_modifiers, :readout)}
    reservoir
    state_modifiers
    readout
end
source

Recurrent Cells

ReservoirComputing.AbstractReservoirRecurrentCellType
AbstractReservoirRecurrentCell <: AbstractLuxLayer

Developer interface for a recurrent reservoir cell used by StatefulLayer.

Extension contract

Subtypes implement the Lux initialization functions and both recurrent call forms below:

  • cell(x, ps, st) -> ((output, (carry,)), st_new) initializes a carry when none is supplied.
  • cell((x, (carry,)), ps, st) -> ((output, (carry_new,)), st_new) advances an existing carry.

StatefulLayer invokes these through LuxCore.apply. The returned carry must have the shape and element type accepted by the second form on the next call; the output may equal the carry but need not do so. The parameter and state objects are owned by the subtype's LuxCore.initialparameters and LuxCore.initialstates implementations.

Example

struct MyCell <: AbstractReservoirRecurrentCell end
source
ReservoirComputing.AbstractEchoStateNetworkCellType
AbstractEchoStateNetworkCell <: AbstractReservoirRecurrentCell

Developer interface for an echo-state-network recurrent cell with the shared ESN parameter and state initialization implementation.

Required fields

The generic methods require these fields:

  • in_dims: input feature dimension.
  • out_dims: reservoir-state dimension.
  • init_input(rng, out_dims, in_dims): input-matrix initializer.
  • init_reservoir(rng, out_dims, out_dims): recurrent-matrix initializer.
  • init_state(rng, out_dims, batch_size): initial hidden-state initializer.
  • use_bias: Static.True() or Static.False(). When true, init_bias(rng, out_dims) is also required.

Extension contract

Subtypes inherit LuxCore.initialparameters and LuxCore.initialstates from this interface. Those methods create input_matrix and reservoir_matrix, an optional bias, and a replicated RNG state. Implement the recurrent call form from AbstractReservoirRecurrentCell: given (x, (carry,)), return ((output, (next_carry,)), st_new). The generic one-input method initializes a hidden state with init_state and delegates to that form.

input_matrix must have shape (out_dims, in_dims), reservoir_matrix must have shape (out_dims, out_dims), and every carry must be compatible with the chosen out_dims and batch dimension.

Example

struct MyESNCell <: AbstractEchoStateNetworkCell
    in_dims
    out_dims
    init_input
    init_reservoir
    init_bias
    init_state
    use_bias
end
source
ReservoirComputing.AbstractReservoirCollectionLayerType
AbstractReservoirCollectionLayer <: AbstractLuxLayer

Developer marker interface for a layer whose output is recorded by collectstates.

Extension contract

Subtypes implement the ordinary Lux layer contract through LuxCore.initialparameters, LuxCore.initialstates, and a call returning (output, updated_state). When a reservoir chain is collected, the output of each such layer is included in the feature vector. It must therefore be a vector or array that can be copied and concatenated with vcat with other collection-layer outputs at the same time step.

Do not use this marker for an ordinary transform merely because it is located before a readout: it changes the training features. A collection layer should preserve stable feature dimensions across all time steps.

Example

struct MyCollect <: AbstractReservoirCollectionLayer end
(layer::MyCollect)(x, ps, st) = (x, st)
source
ReservoirComputing.AbstractReservoirTrainableLayerType
AbstractReservoirTrainableLayer <: AbstractLuxLayer

Developer marker interface for the first trainable/readout layer in a reservoir chain.

Extension contract

Subtypes implement the usual Lux initialization and call contracts. During collectstates, this marker stops the reservoir-feature traversal: the marked layer and subsequent layers are not executed while generating training features. Mark only a layer that consumes the collected features, and ensure its input dimension matches the stable feature dimension produced before it.

Example

struct MyReadout <: AbstractReservoirTrainableLayer end
(layer::MyReadout)(x, ps, st) = (x, st)
source

Continuous and Cellular Automata Reservoirs

ReservoirComputing.AbstractSciMLProblemReservoirType
AbstractSciMLProblemReservoir <: AbstractLuxLayer

Developer interface for a Lux layer whose dynamics are defined by an AbstractSciMLProblem (typically ODEProblem, SDEProblem, or DDEProblem).

Required fields

Concrete subtypes used with the built-in continuous-reservoir extension should provide:

  • prob: the SciML problem template;
  • sampler: an AbstractSampler;
  • tspan: the integration interval used for each input sequence;
  • args: positional solver arguments; and
  • kwargs: keyword solver arguments that do not conflict with the sampling machinery.

Extension contract

Implement LuxCore.initialparameters and LuxCore.initialstates for any additional layer parameters or state. The continuous-reservoir extension then dispatches the following developer hooks:

  • __collectstates(res, rc, data, ps, st) -> (states, st′), where states is an (state_dimension, n_samples) matrix;
  • __predict(res, rc, data, ps, st) -> (outputs, st′) for teacher-forced prediction; and
  • __predict(res, rc, steps, ps, st; initialdata) -> (outputs, st′) for autoregressive prediction.

The hooks must preserve the parameter/state layout expected by the enclosing AbstractReservoirComputer. Subtyping this type without implementing the hooks only provides the default empty Lux parameter/state containers; it does not make a new reservoir solvable.

Example

struct MyContinuousReservoir <: AbstractSciMLProblemReservoir
    prob
    sampler
    tspan
    args
    kwargs
end

The continuous-time __collectstates implementation lives in the RCODEReservoirExt package extension and requires SciMLBase and DataInterpolations to be loaded. Pick any concrete solver package separately (e.g. OrdinaryDiffEqTsit5, OrdinaryDiffEq) — its solver types are what SciMLProblemReservoir's args[1] consumes.

source
ReservoirComputing.AbstractSamplerType
AbstractSampler

Developer interface for a sampler that extracts a discrete state matrix from a continuous-time reservoir trajectory.

Fields

The marker itself requires no fields. A sampler may carry configuration such as a window statistic or a within-window sampling rule.

Extension contract

The continuous-reservoir extension calls __sample(sampler, sol) after solving with one saved endpoint per input column. A concrete method must return an AbstractMatrix with one column per saved sample and a stable row dimension for the readout. It may inspect the SciML solution object, but it must not change the solution or the input data.

Subtyping AbstractSampler alone is not enough: the matching __sample method must be defined in the extension that owns the continuous-reservoir implementation. This is a developer hook; ordinary users should use TerminalStateSampling.

Example

struct WindowMean <: AbstractSampler
    width::Int
end

# Define `__sample(::WindowMean, sol)` in the continuous-reservoir extension.
source
ReservoirComputing.AbstractInputEncodingType
AbstractInputEncoding

Developer marker interface for a cellular-automata input-encoding specification.

Extension contract

This package currently provides no generic public function that consumes every AbstractInputEncoding subtype. An external encoding is therefore usable only with a concrete cellular-automata integration that documents how it consumes that type. Do not assume that merely subtyping this interface makes a value accepted by RECACell or RECA; those constructors presently use the concrete RandomMapping / RandomMaps workflow.

Use this marker to communicate an encoding specification in an extension API, and document the fields and conversion operation required by that extension.

Example

struct MyEncoding <: AbstractInputEncoding
    width::Int
end
source
ReservoirComputing.AbstractEncodingDataType
AbstractEncodingData

Developer marker interface for precomputed cellular-automata encoding data.

Extension contract

This package currently has no public generic operation over all AbstractEncodingData subtypes. A concrete cellular-automata layer must state the fields it reads and implement its own conversion from an AbstractInputEncoding. In particular, RECACell currently requires RandomMaps, so arbitrary subtypes are not interchangeable with it.

Use this marker only when defining a paired extension interface and document the feature size, lattice size, and mapping invariants required by that extension.

Example

struct MyEncodingData <: AbstractEncodingData
    states_size::Int
end
source

Spiking Reservoirs

ReservoirComputing.AbstractSpikingNeuronType
AbstractSpikingNeuron

Developer marker for a neuron model used by the spiking reservoir interface.

Fields

The marker itself requires no fields. A concrete neuron type must document the state variables, parameter fields, and differential equations that its extension uses.

Extension contract

The current LSM implementation accepts only LIFNeuron. Subtyping AbstractSpikingNeuron does not by itself make a neuron valid for LSMCell: an extension must add the solver right-hand side, event handling, and feature extraction methods for the new neuron. Those hooks are developer APIs, not generic end-user dispatches.

Example

struct MyNeuron <: AbstractSpikingNeuron
    tau_m::Float64
end

The example is only a type declaration; it is not accepted by LSMCell until the corresponding extension contract is implemented.

source
ReservoirComputing.AbstractInputEncoderType
AbstractInputEncoder

Developer marker for an input-to-spike encoding used by LSMCell.

Fields

The marker itself requires no fields. A concrete encoder owns the parameters needed to turn an input vector into the external current or event process consumed by the neuron model.

Extension contract

The current implementation accepts CurrentInjection and PoissonRateEncoder only. A custom subtype must be integrated by an extension that defines its encoder state initialization, input/event generation, and solver callback behavior. Subtyping this marker alone does not make the encoder accepted by LSMCell.

Example

struct MyEncoder <: AbstractInputEncoder
    scale::Float64
end
source
ReservoirComputing.AbstractSpikeFeatureType
AbstractSpikeFeature

Developer marker for a feature map that converts a spiking trajectory into reservoir features for LSMCell.

Fields

The marker itself requires no fields. A concrete feature map should document its state, output feature dimension, and how each sample window is computed.

Extension contract

The current implementation accepts SpikeCountFeatures, ExponentialSpikeFilter, and MembraneVoltageFeature. A custom feature map must provide extension methods for its feature dimension, autoregressive support, and sampled feature calculation. The extension passes the spike times and unit indices together with the requested sample times; the implementation must return one feature column per sample time. Subtyping this marker alone does not add a feature map to LSMCell.

Example

struct MySpikeFeature <: AbstractSpikeFeature
    window::Float64
end
source

Training

ReservoirComputing.AbstractReservoirComputingSolverType
AbstractReservoirComputingSolver

Developer marker for the package's legacy reservoir-training solver family.

Extension contract

QRSolver is the only built-in subtype. The public train API also accepts LinearSolve.jl algorithms directly. There is currently no public generic extension point for arbitrary AbstractReservoirComputingSolver subtypes: a new subtype is rejected by ridge training unless ReservoirComputing adds a corresponding implementation itself.

For a custom solver, implement the documented LinearSolve.jl algorithm interface and pass that algorithm to train(...; solver=...). Do not extend private training helpers from another package.

Example

weights = train(RidgeRegression(1.0e-3), states, targets;
    solver = QRFactorization())
source

Initializer Output Extensions

ReservoirComputing.return_init_asFunction
return_init_as(::Val{return_sparse}, initializer_output)

Convert an initializer output according to its return_sparse request.

Developer interface

This dispatch hook is for ReservoirComputing extension authors. End users should request sparse output through an initializer's return_sparse keyword rather than calling this function directly.

Arguments

  • return_sparse: Val(false) for the built-in dense path or Val(true) for an extension-provided sparse representation.
  • initializer_output: an initializer result to return or convert.

Extension contract

An extension that provides a sparse representation must define ReservoirComputing.return_init_as(::Val{true}, output) for the output types it supports. The method must return a representation with the same shape and values. The built-in Val(false) method returns its input unchanged.

Example

ReservoirComputing.return_init_as(Val(false), ones(2, 2)) == ones(2, 2)
source