Conceptors
Conceptors after Jaeger (2014), (Jaeger, 2014). See the Morphing patterns with conceptors example for an end-to-end walkthrough.
Conceptor matrices
ReservoirComputing.conceptor_matrix — Function
conceptor_matrix(correlation, aperture) -> MatrixConceptor 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: Ifapertureis not finite and positive, or ifcorrelationis not symmetric.DimensionMismatch: Ifcorrelationis not square.
Example
correlation = correlation_matrix(states)
conceptor = conceptor_matrix(correlation, 10)ReservoirComputing.correlation_matrix — Function
correlation_matrix(states) -> MatrixState 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: Ifstateshas no elements.
Example
states = rand(Float32, 50, 1_000)
correlation = correlation_matrix(states)ReservoirComputing.conceptor_from_states — Function
conceptor_from_states(states, aperture) -> MatrixConvenience 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)ReservoirComputing.conceptor_singular_values — Function
conceptor_singular_values(conceptor) -> VectorSingular 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: Ifconceptoris not square.
ReservoirComputing.quota — Function
quota(conceptor) -> RealMean 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.
Aperture adaptation
ReservoirComputing.aperture_adapt — Function
aperture_adapt(conceptor, aperture_factor) -> MatrixAperture 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 orconceptoris not symmetric.DimensionMismatch: Ifconceptoris not square.
Example
wider_conceptor = aperture_adapt(conceptor, 2)
projector = aperture_adapt(conceptor, Inf)ReservoirComputing.adapt_singular_value — Function
adapt_singular_value(singular_value, aperture_factor) -> RealAperture-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: Ifaperture_factoris negative.
ReservoirComputing.reaperture — Function
reaperture(conceptor, from_aperture, to_aperture) -> MatrixRe-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 atfrom_aperture.from_aperture::Real: Finite positive current aperture.to_aperture::Real: Nonnegative target aperture;Infis allowed.
Returns
- The aperture-adapted conceptor.
ReservoirComputing.attenuation — Function
attenuation(concept, ps, st; conceptor, steps=500, washout=200,
init_state=nothing, rng=Random.default_rng()) -> RealAttenuation $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 byloadpatterns.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 wheninit_stateis omitted.
Returns
- The fraction of unconstrained reservoir energy suppressed by the conceptor.
ReservoirComputing.optimal_aperture — Function
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 byloadpatterns.st::NamedTuple: Current states.
Returns
(best_aperture, attenuations), whereattenuationsfollows the order ofapertures.
Boolean algebra
ReservoirComputing.conceptor_not — Function
conceptor_not(conceptor) -> MatrixLogical 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.
ReservoirComputing.conceptor_and — Function
conceptor_and(first_conceptor, second_conceptor) -> MatrixLogical 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.nothinguses 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.
ReservoirComputing.conceptor_or — Function
conceptor_or(first_conceptor, second_conceptor) -> MatrixLogical 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.
The Conceptor wrapper and its library
ReservoirComputing.Conceptor — Type
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, andgenerate.
Example
model = Conceptor(ESN(1, 100, 1; use_bias = true))
parameters = initialparameters(rng, model)
states = initialstates(rng, model)ReservoirComputing.has_conceptor — Function
has_conceptor(st, name) -> BoolWhether a conceptor called name has been stored in the state st.
Returns true when name is present and false otherwise.
ReservoirComputing.get_conceptor — Function
get_conceptor(st, name) -> Matrix or nothingThe stored conceptor matrix called name, or nothing if it is absent.
Use has_conceptor when absence should be checked separately.
ReservoirComputing.store_conceptor — Function
store_conceptor(st, name, conceptor, aperture) -> stRecord 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 byinitialstatesfor aConceptor.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.
ReservoirComputing.set_active_conceptor — Function
set_active_conceptor(st, name) -> stMark 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.
ReservoirComputing.active_conceptor — Function
active_conceptor(st) -> MatrixThe currently active conceptor matrix. Throws if none has been set.
Use set_active_conceptor to select or clear the active conceptor.
Loading, generation, and morphing
ReservoirComputing.loadpatterns — Function
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
Wand readoutW_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 ofSymbol => signalpairs. 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 aSymbol, an aperture is missing, or washout is not in1:(signal length - 1).
ReservoirComputing.generate — Function
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 byloadpatterns.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: Ifstepsis not positive,washoutis 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
)ReservoirComputing.morph_conceptor — Function
morph_conceptor(st, weights) -> MatrixLinearly 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: Ifweightsis empty.
Conceptor-filtered training
ReservoirComputing.store_conceptors — Function
store_conceptors(rng, concept, named_signals, ps, st;
aperture=1.0, init_carry=nothing) -> stDerive 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