Conceptors

Conceptors after Jaeger (2014), (Jaeger, 2014). See the Morphing patterns with conceptors example for an end-to-end walkthrough.

Conceptor matrices

ReservoirComputing.conceptor_matrixFunction
conceptor_matrix(correlation, aperture) -> Matrix

Conceptor derived from a correlation matrix and the given aperture (Jaeger, 2014). The result is symmetric positive semidefinite with singular values in $[0, 1)$.

Arguments

  • correlation::AbstractMatrix{<:Real}: Symmetric state correlation matrix.
  • aperture::Real: Finite positive aperture. Larger values admit more state-space directions; smaller values suppress more directions.

Returns

  • A dense conceptor matrix with the floating-point element type of correlation.

Throws

  • ArgumentError: If aperture is not finite and positive, or if correlation is not symmetric.
  • DimensionMismatch: If correlation is not square.

Example

correlation = correlation_matrix(states)
conceptor = conceptor_matrix(correlation, 10)
source
ReservoirComputing.correlation_matrixFunction
correlation_matrix(states) -> Matrix

State correlation matrix $R = X X^\top / L$ for a reservoir state collection states of size $N \times L$ (one state per column). This is the matrix whose regularized-identity map defines a conceptor.

Arguments

  • states::AbstractMatrix{<:Real}: Reservoir states arranged as (reservoir_dimension, sample_count).

Returns

  • A dense square matrix with the floating-point element type inferred from states.

Throws

  • ArgumentError: If states has no elements.

Example

states = rand(Float32, 50, 1_000)
correlation = correlation_matrix(states)
source
ReservoirComputing.conceptor_from_statesFunction
conceptor_from_states(states, aperture) -> Matrix

Convenience composition of correlation_matrix and conceptor_matrix: the conceptor characterizing a reservoir state cloud states (size N × L) at the given aperture.

Arguments

  • states::AbstractMatrix{<:Real}: Reservoir states, one state per column.
  • aperture::Real: Finite positive aperture.

Returns

  • The conceptor associated with the sample correlation of states.

Example

conceptor = conceptor_from_states(states, 10)
source
ReservoirComputing.conceptor_singular_valuesFunction
conceptor_singular_values(conceptor) -> Vector

Singular values of a (symmetric) conceptor matrix C, in descending order. For a conceptor these coincide with its eigenvalues and lie in [0, 1].

Arguments

  • conceptor::AbstractMatrix{<:Real}: Square conceptor matrix.

Returns

  • A vector of singular values in descending order.

Throws

  • DimensionMismatch: If conceptor is not square.
source
ReservoirComputing.quotaFunction
quota(conceptor) -> Real

Mean singular value of a conceptor, tr(C) / N. Jaeger's "quota" measures the fraction of reservoir state space the conceptor leaves open (0 = point, 1 = all).

Arguments

  • conceptor::AbstractMatrix{<:Real}: Square conceptor matrix.

Returns

  • The mean singular value. Values near zero indicate a restrictive conceptor; values near one indicate a permissive conceptor.
source

Aperture adaptation

ReservoirComputing.aperture_adaptFunction
aperture_adapt(conceptor, aperture_factor) -> Matrix

Aperture adaptation of a conceptor by a nonnegative aperture_factor (Jaeger, 2014). This is equivalent to multiplying its aperture by the supplied factor. Zero and infinite factors are handled exactly.

Arguments

  • conceptor::AbstractMatrix{<:Real}: Symmetric square conceptor matrix.
  • aperture_factor::Real: Nonnegative aperture multiplier.

Returns

  • A conceptor with the same principal directions and adapted singular values.

Throws

  • ArgumentError: If the factor is negative or conceptor is not symmetric.
  • DimensionMismatch: If conceptor is not square.

Example

wider_conceptor = aperture_adapt(conceptor, 2)
projector = aperture_adapt(conceptor, Inf)
source
ReservoirComputing.adapt_singular_valueFunction
adapt_singular_value(singular_value, aperture_factor) -> Real

Aperture-adapted value for an input singular_value in [0, 1] and a nonnegative aperture_factor (Jaeger, 2014). The boundary values zero and one are fixed points.

Arguments

  • singular_value::Real: Value to adapt, normally in [0, 1].
  • aperture_factor::Real: Nonnegative factor applied to the aperture.

Returns

  • The adapted singular value, using the floating-point type inferred from singular_value.

Throws

  • ArgumentError: If aperture_factor is negative.
source
ReservoirComputing.reapertureFunction
reaperture(conceptor, from_aperture, to_aperture) -> Matrix

Re-express a conceptor C that currently has aperture from_aperture so that it has aperture to_aperture (Jaeger, 2014).

Arguments

  • conceptor::AbstractMatrix{<:Real}: Conceptor formed at from_aperture.
  • from_aperture::Real: Finite positive current aperture.
  • to_aperture::Real: Nonnegative target aperture; Inf is allowed.

Returns

  • The aperture-adapted conceptor.
source
ReservoirComputing.attenuationFunction
attenuation(concept, ps, st; conceptor, steps=500, washout=200,
            init_state=nothing, rng=Random.default_rng()) -> Real

Attenuation $a_C = E[\|z(n) - x(n)\|^2] / E[\|z(n)\|^2]$ of the loaded reservoir wrapped by concept run autonomously under conceptor (Jaeger, 2014), where $z(n) = f(x(n-1))$ is the unconstrained update of the wrapped model's reservoir cell (zero input, same convention as generate) and $x(n) = C z(n)$ is the conceptor-constrained state. The attenuation is the fraction of reservoir signal energy suppressed by C; as a function of aperture it passes through a minimum at the best-reconstructing aperture.

Arguments

  • concept::Conceptor: Loaded conceptor model.
  • ps::NamedTuple: Parameters returned by loadpatterns.
  • st::NamedTuple: Current states.

Keywords

  • conceptor: Stored conceptor name or an explicit square conceptor matrix.
  • steps::Int = 500: Number of samples included in the energy ratio.
  • washout::Int = 200: Initial autonomous steps excluded from the ratio.
  • init_state = nothing: Optional initial reservoir state.
  • rng = Random.default_rng(): Random number generator used when init_state is omitted.

Returns

  • The fraction of unconstrained reservoir energy suppressed by the conceptor.
source
ReservoirComputing.optimal_apertureFunction
optimal_aperture(concept, correlation, apertures, ps, st; kwargs...)

Select the aperture minimizing the attenuation criterion over a grid apertures. For each candidate aperture, its conceptor is formed from correlation and the loaded reservoir wrapped by concept is run autonomously to measure its attenuation. Returns the minimizing aperture together with the full vector of attenuations (aligned with apertures) so the characteristic trough can be inspected. kwargs are forwarded to attenuation.

Arguments

  • concept::Conceptor: Loaded conceptor model.
  • correlation: Symmetric state correlation matrix.
  • apertures: Nonempty vector of finite positive candidate apertures.
  • ps::NamedTuple: Parameters returned by loadpatterns.
  • st::NamedTuple: Current states.

Returns

  • (best_aperture, attenuations), where attenuations follows the order of apertures.
source

Boolean algebra

ReservoirComputing.conceptor_notFunction
conceptor_not(conceptor) -> Matrix

Logical negation of a conceptor (Jaeger, 2014). Exchanges the roles of the directions the conceptor admits and suppresses.

Arguments

  • conceptor::AbstractMatrix{<:Real}: Square conceptor matrix.

Returns

  • The complementary conceptor. Its singular values are one minus those of conceptor.
source
ReservoirComputing.conceptor_andFunction
conceptor_and(first_conceptor, second_conceptor) -> Matrix

Logical conjunction of two conceptors (Jaeger, 2014). For full-rank conceptors this equals $(C^{-1} + B^{-1} - I)^{-1}$; the implementation uses the range-intersection projector form so that singular conceptors are handled robustly. The result admits exactly the reservoir directions admitted by bothC and B.

Arguments

  • first_conceptor::AbstractMatrix{<:Real}: First symmetric conceptor.
  • second_conceptor::AbstractMatrix{<:Real}: Second symmetric conceptor of the same size.

Keywords

  • tolerance::Union{Real, Nothing} = nothing: Relative rank tolerance (rtol) used for the internal nullspace/pseudoinverse computations. nothing uses the stdlib default for each matrix; Jaeger notes this tolerance can matter for near-singular conceptors (Jaeger 2014, p.53).

Returns

  • The conjunction of the two conceptors, including when either input is rank-deficient.

Throws

  • DimensionMismatch: If the conceptors are not square or have different sizes.
  • ArgumentError: If either conceptor is not symmetric.
source
ReservoirComputing.conceptor_orFunction
conceptor_or(first_conceptor, second_conceptor) -> Matrix

Logical disjunction of two conceptors (Jaeger, 2014), defined via De Morgan's law. The result admits every reservoir direction admitted by C or by B.

Arguments

  • first_conceptor::AbstractMatrix{<:Real}: First symmetric conceptor.
  • second_conceptor::AbstractMatrix{<:Real}: Second symmetric conceptor of the same size.

Returns

  • The disjunction of the two conceptors.
source

The Conceptor wrapper and its library

ReservoirComputing.ConceptorType
Conceptor(model)

Wrap a ReservoirComputing model (e.g. an ESN) so that conceptor matrices can be derived from it, stored by name, combined with the conceptor algebra, and used to constrain autonomous generation (Jaeger, 2014).

The wrapped model provides the reservoir update; the Conceptor adds a conceptor library to the model state. Parameters and states are nested under the model field, leaving room for conceptor bookkeeping at the top level.

Arguments

  • model: Reservoir computer to wrap. Pattern loading expects an ESN-compatible parameter layout with reservoir, input, bias, and readout weights.

Returns

  • A conceptor-enabled reservoir computer used with initialparameters, initialstates, loadpatterns, and generate.

Example

model = Conceptor(ESN(1, 100, 1; use_bias = true))
parameters = initialparameters(rng, model)
states = initialstates(rng, model)
source
ReservoirComputing.has_conceptorFunction
has_conceptor(st, name) -> Bool

Whether a conceptor called name has been stored in the state st.

Returns true when name is present and false otherwise.

source
ReservoirComputing.store_conceptorFunction
store_conceptor(st, name, conceptor, aperture) -> st

Record conceptor matrix C (formed at aperture) under name in the state's conceptor library. The input state is left untouched; an updated state is returned.

Arguments

  • st::NamedTuple: State returned by initialstates for a Conceptor.
  • name::Symbol: Name used to retrieve the conceptor later.
  • conceptor::AbstractMatrix{<:Real}: Square conceptor matrix.
  • aperture::Real: Finite positive aperture associated with the matrix.

Returns

  • A state with the conceptor and aperture recorded in its library.
source
ReservoirComputing.set_active_conceptorFunction
set_active_conceptor(st, name) -> st

Mark the conceptor name (or nothing) as the active one, returning an updated state. The active conceptor is the default constraint for generation.

Passing nothing clears the active selection. A KeyError is thrown when a nonexistent name is selected.

source

Loading, generation, and morphing

ReservoirComputing.loadpatternsFunction
loadpatterns(rng, concept, named_signals, ps, st;
      aperture=10.0, washout=500, reg_recurrent=1e-4, reg_readout=1e-2)

Load named driving patterns into the reservoir wrapped by concept (Jaeger, 2014). For each name => signal pair the reservoir is run from a cleared carry, the first washout states are discarded, and the remaining states are used to

  • derive and store a conceptor from the state correlation matrix, and
  • accumulate data for a single shared input-internalizing recurrent matrix W and readout W_out.

W is fitted (ridge, reg_recurrent) so that $W x(n-1) \approx W^* x(n-1) + W_\text{in} p(n)$, absorbing the input drive into the recurrent weights; W_out is fitted (ridge, reg_readout) so that $W_\text{out} x(n) \approx p(n)$ across all patterns. aperture is either a scalar or a dictionary mapping each name to an aperture.

Returns (ps, st) with reservoir_matrix and readout.weight replaced and the conceptor library populated.

Arguments

  • rng::AbstractRNG: Random number generator used when reservoir carries reset.
  • concept::Conceptor: Conceptor-wrapped reservoir.
  • named_signals: Iterable of Symbol => signal pairs. A vector signal is treated as one-dimensional; a matrix has one input channel per row and time per column.
  • ps::NamedTuple: Current parameters.
  • st::NamedTuple: Current states.

Keywords

  • aperture = 10.0: One aperture for every pattern, or a dictionary keyed by pattern name.
  • washout::Int = 500: Initial samples excluded from fitting; at least 1 and shorter than every signal.
  • reg_recurrent::Real = 1.0e-4: Ridge penalty for recurrent weights.
  • reg_readout::Real = 1.0e-2: Ridge penalty for readout weights.

Returns

  • (parameters, states): Updated parameters and a state containing one conceptor per named signal.

Throws

  • ArgumentError: If a name is not a Symbol, an aperture is missing, or washout is not in 1:(signal length - 1).
source
ReservoirComputing.generateFunction
generate(concept, ps, st; conceptor, steps, washout=200,
         init_state=nothing, rng=Random.default_rng()) -> (Y, X)

Run the loaded reservoir autonomously under conceptor and read out the observer signal:

\[x(n) = C \, f(x(n-1)), \qquad y(n) = W_\text{out} x(n),\]

where $f$ is one update of the wrapped model's reservoir cell driven with a zero input, so the cell's own activation, leak coefficient, and bias are used (for a default ESN this is $f(x) = \tanh(W x + b)$), and the readout is the wrapped model's readout layer.

conceptor is either a stored conceptor Symbol or an explicit conceptor matrix (e.g. the output of morph_conceptor or the Boolean operations). The first washout steps let the autonomous orbit settle and are discarded. Returns (Y, X): the post-washout observer outputs (out_dims × steps) and reservoir states (res_dims × steps). The rollout uses the element type of the reservoir parameters.

Arguments

  • concept::Conceptor: Loaded conceptor model.
  • ps::NamedTuple: Parameters returned by loadpatterns.
  • st::NamedTuple: State containing the requested conceptor.

Keywords

  • conceptor: Stored conceptor name or an explicit square conceptor matrix.
  • steps::Int: Number of returned time steps; must be positive.
  • washout::Int = 200: Autonomous steps discarded before recording.
  • init_state = nothing: Optional reservoir state vector. A random state is used when omitted.
  • rng = Random.default_rng(): Random number generator for the initial state.

Returns

  • (outputs, states): Observer outputs and reservoir states, with time along columns.

Throws

  • KeyError: If a requested conceptor name is absent.
  • DimensionMismatch: If the conceptor or initial state does not match the reservoir dimension.
  • ArgumentError: If steps is not positive, washout is negative, or the wrapped model has state modifiers or a multi-state reservoir cell.

Example

outputs, states = generate(
    concept, parameters, model_state;
    conceptor = :sine, steps = 500, washout = 100, rng
)
source
ReservoirComputing.morph_conceptorFunction
morph_conceptor(st, weights) -> Matrix

Linearly combine stored conceptors into a morphed conceptor (Jaeger, 2014). weights is an iterable of name-to-weight pairs, a NamedTuple, or a Dict{Symbol,<:Real}. Coefficients summing to one interpolate between the named prototypes; coefficients outside [0, 1] extrapolate.

Arguments

  • st::NamedTuple: State containing stored conceptors.
  • weights: Named tuple, dictionary, or iterable of name-to-weight pairs.

Returns

  • The weighted sum of the named conceptors.

Throws

  • KeyError: If a named conceptor is absent.
  • ArgumentError: If weights is empty.
source

Conceptor-filtered training

ReservoirComputing.store_conceptorsFunction
store_conceptors(rng, concept, named_signals, ps, st;
                  aperture=1.0, init_carry=nothing) -> st

Derive and store one conceptor per named signal without modifying the reservoir weights. For each name => signal the reservoir is run from a cleared carry and the conceptor of its state cloud is stored. Use this to build a conceptor library for classification, where each class pattern gets its own conceptor. aperture is a scalar or a dictionary keyed by name.

Returns

  • The updated state. Reservoir parameters are unchanged.

See also

loadpatterns, train!, store_conceptor

source