reservoir
eigenkit.reservoir
Quantum reservoir computing (QRC).
A circuit with fixed weights, usually random, is driven over input sequences. The quantum state is carried from one timestep to the next, and classical features are read out from it.
The reservoir circuit is never trained; only a classical readout is. The
driver, the policies, the feature extractors and the ridge-regression readout
use only NumPy. Like optimization and chemistry, this package belongs to the
core of the library, so it needs neither PyTorch nor a backend package.
Three policies cover the common variants of QRC:
Statelessstarts every step from|0…0⟩and encodes a sliding window of inputs. All timesteps run in parallel, in one batched evaluation.Carrycarries the state from one step to the next with the circuit's unitary:ψ_t = U(x_t) ψ_{t-1}.LeakyCarrymixes the carried state with a reset state, and renormalises the result.
Example
from eigenkit import Circuit
from eigenkit.reservoir import (
run_reservoir, Carry, expectation_features, LinearReadout,
)
states = run_reservoir(circuit, Carry(), sequences, weights) # (B, T, 2**n)
feats = expectation_features(states, "Z0 + Z1 + 0.5 X0 X1") # (B, T, 1)
readout = LinearReadout(ridge=1e-4).fit(feats.reshape(B * T, -1), targets)
Carry
dataclass
Policy that applies the circuit to the carried state: ψ_t = U(x_t) ψ_{t-1}.
The quantum state is the memory of the reservoir, and the first step starts
from |0…0⟩. This policy is equivalent to LeakyCarry(alpha=1.0).
advance(x_t, evolved, state)
Build the state for the next timestep from the result of this step.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x_t
|
ndarray
|
The input of this timestep, of shape |
required |
evolved
|
ndarray
|
The statevector that the circuit produced. |
required |
state
|
ReservoirState
|
The state that went into this step. |
required |
Returns:
| Type | Description |
|---|---|
ReservoirState
|
The state for the next timestep. |
initial(batch)
Return the state carried into the first timestep.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
batch
|
int
|
The number of sequences that run in parallel. |
required |
Returns:
| Type | Description |
|---|---|
ReservoirState
|
The initial |
inject(x_t, state)
Turn the input of this timestep into the arguments of the circuit call.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x_t
|
ndarray
|
The input of this timestep, of shape |
required |
state
|
ReservoirState
|
The state carried over from the previous step. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
initial_state |
ndarray | None
|
The state to evaluate the circuit from, or |
gate_inputs |
ndarray
|
The values to pass to the gates of the circuit. |
LeakyCarry
dataclass
Policy that mixes the carried state with a reset state and renormalises it.
It approximates a leaky, dissipative reservoir with pure states:
ψ_t = normalise(α U(x_t) ψ_{t-1} + (1 − α) reset).
reset defaults to |0…0⟩ and should be a normalised statevector; this is not
checked. With alpha=1, the policy is exactly
Carry. This is not a true dissipative
channel, which would need density matrices that the pure-state backends do not
provide. It is an approximation that uses pure states only.
Attributes:
| Name | Type | Description |
|---|---|---|
alpha |
float
|
The mixing weight of the carried state, in |
reset |
ndarray | None
|
The state that is mixed in, a normalised statevector. |
advance(x_t, evolved, state)
Build the state for the next timestep from the result of this step.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x_t
|
ndarray
|
The input of this timestep, of shape |
required |
evolved
|
ndarray
|
The statevector that the circuit produced. |
required |
state
|
ReservoirState
|
The state that went into this step. |
required |
Returns:
| Type | Description |
|---|---|
ReservoirState
|
The state for the next timestep. |
initial(batch)
Return the state carried into the first timestep.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
batch
|
int
|
The number of sequences that run in parallel. |
required |
Returns:
| Type | Description |
|---|---|
ReservoirState
|
The initial |
inject(x_t, state)
Turn the input of this timestep into the arguments of the circuit call.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x_t
|
ndarray
|
The input of this timestep, of shape |
required |
state
|
ReservoirState
|
The state carried over from the previous step. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
initial_state |
ndarray | None
|
The state to evaluate the circuit from, or |
gate_inputs |
ndarray
|
The values to pass to the gates of the circuit. |
LinearReadout
Ridge regression in closed form, with a bias term.
It solves W = (XᵀX + λI)⁻¹ XᵀY, and the bias column is not regularised. Y
can have one output or several. ridge is the strength λ of the L2 penalty,
which adds λ‖W‖² to the squared error of the fit. A small positive value
also keeps the solution numerically stable when the reservoir features are
collinear.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ridge
|
float
|
The strength |
1e-06
|
fit(X, y)
Fit the readout to X and y.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ndarray
|
The samples, of shape |
required |
y
|
ndarray
|
The targets, of shape |
required |
Returns:
| Type | Description |
|---|---|
'LinearReadout'
|
This readout, so that calls can be chained. |
predict(X)
Predict the target for every sample in X.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ndarray
|
The samples, of shape |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
One prediction per sample, with one column per output when the readout was fitted on several outputs. |
ReservoirPolicy
Bases: Protocol
A reservoir policy that carries state from one timestep to the next.
Parallel policies, which carry no state, do not implement this protocol. They
provide expand_inputs(sequences), which returns the inputs of every timestep
with shape (B, T, n_inputs), and the driver evaluates all timesteps at once.
See Stateless.
advance(x_t, evolved, state)
Build the state for the next timestep from the result of this step.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x_t
|
ndarray
|
The input of this timestep, of shape |
required |
evolved
|
ndarray
|
The statevector that the circuit produced. |
required |
state
|
ReservoirState
|
The state that went into this step. |
required |
Returns:
| Type | Description |
|---|---|
ReservoirState
|
The state for the next timestep. |
initial(batch)
Return the state carried into the first timestep.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
batch
|
int
|
The number of sequences that run in parallel. |
required |
Returns:
| Type | Description |
|---|---|
ReservoirState
|
The initial |
inject(x_t, state)
Turn the input of this timestep into the arguments of the circuit call.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x_t
|
ndarray
|
The input of this timestep, of shape |
required |
state
|
ReservoirState
|
The state carried over from the previous step. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
initial_state |
ndarray | None
|
The state to evaluate the circuit from, or |
gate_inputs |
ndarray
|
The values to pass to the gates of the circuit. |
ReservoirState
dataclass
The state that sequential policies carry from one timestep to the next.
vector is the (B, 2**n) statevector to inject at the next step, and None
means that the step starts from |0…0⟩. history holds the recent raw inputs,
of shape (B, k, F), for a sequential policy that encodes a window of inputs.
Attributes:
| Name | Type | Description |
|---|---|---|
vector |
ndarray | None
|
The statevector to inject at the next step, of shape |
history |
ndarray | None
|
The last |
Stateless
dataclass
Parallel policy that carries no state.
Every step starts from |0…0⟩, and the last window inputs are encoded as
rotation angles of the circuit's gates. The memory is purely classical (the
window), and the quantum state carries nothing from one step to the next.
Every timestep is therefore independent, and the driver evaluates all of them
in one batched run. With window=1, the policy has no memory: it encodes only
the current input.
The circuit's n_inputs must equal window * F, where F is the number of
features per step, because each step passes the whole flattened window to the
encoding gates.
Attributes:
| Name | Type | Description |
|---|---|---|
window |
int
|
The number of consecutive inputs to encode at each step. |
expand_inputs(sequences)
Return the gate inputs of every timestep, with shape (B, T, window * F).
Step t encodes the inputs t - window + 1 to t. The first window - 1
steps are padded with zeros at the front. No quantum state is involved, so this
is only a reshaping of the input sequence.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sequences
|
ndarray
|
The whole input batch, of shape |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
The gate inputs for every timestep, of shape |
amplitude_features(states)
The raw statevector as real features: its real and imaginary parts, concatenated.
states is a complex array of shape (B, T, 2**n), and the result is a real
array of shape (B, T, 2 * 2**n). It exposes the full state, which only a
simulator can provide; it cannot be measured on hardware.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
states
|
ndarray
|
The trajectory of statevectors, of shape
|
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
The real and imaginary parts, concatenated, for each timestep. |
expectation_features(states, observables)
Expectation values ⟨ψ|H_k|ψ⟩ of each observable, over the whole trajectory.
states is a complex array of shape (B, T, 2**n), and the result is a real
array of shape (B, T, n_obs). observables can be an Observable, a
PauliExpr or a Hamiltonian string, or a sequence of these. These are the same
types that the rest of the library uses, so measuring an arbitrary Hamiltonian,
as QRC experiments often require, needs no manual handling of Pauli terms. A
single Hamiltonian string is one observable, and gives one feature.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
states
|
ndarray
|
The trajectory of statevectors, of shape
|
required |
observables
|
Sequence[Observable]
|
The observables to measure. |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
One feature per observable and per timestep. |
pauli_z_features(states)
The expectation value ⟨Z_q⟩ on each qubit, the usual default readout in QRC.
states has shape (B, T, 2**n), and the result has shape (B, T, n). The
values are computed with
expectation_features(),
so both functions share the same tested measurement code.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
states
|
ndarray
|
The trajectory of statevectors, of shape
|
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
One feature per qubit and per timestep. |
probability_features(states)
The measurement distribution over all 2**n basis states, |ψ|².
states is a complex array of shape (B, T, 2**n), and the result is a real
array of the same shape.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
states
|
ndarray
|
The trajectory of statevectors, of shape
|
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
The distribution over the basis states, for each timestep. |
run_reservoir(circuit, policy, sequences, weights)
Evolve circuit over sequences under policy, with frozen weights.
The result is the trajectory of statevectors, a complex array of shape
(B, T, 2**n).
sequences has shape (B, T, F): B independent series, T timesteps and
F features per step. weights is the fixed 1-D parameter vector of the
reservoir, shared by the whole batch. Features are extracted separately from
the returned trajectory (see the feature extractors), so the same run can
produce expectation, probability or amplitude features without evolving the
circuit again.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
circuit
|
Circuit
|
The reservoir circuit, run with frozen weights. |
required |
policy
|
Policy
|
How the state passes from one timestep to the next. |
required |
sequences
|
ndarray
|
The inputs, of shape |
required |
weights
|
ndarray
|
The frozen weights of the reservoir. |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
The trajectory of statevectors, of shape |