## `eigenkit.reservoir.policies`

Reservoir policies — how each timestep maps the carried state and the current input to the circuit's `(initial_state, gate_inputs)`.

Two execution shapes, because they are genuinely different computations:

- **Sequential (a fold over time).** The quantum state *is* the memory: `$\psi_t$` depends on `$\psi_{t-1}$`, so timesteps must run in order. These policies implement `initial` / `inject` / `advance` (Carry, LeakyCarry).
- **Parallel (a map over time).** The quantum state carries nothing between steps — each step's input is a pure function of the raw input sequence (e.g. a sliding window). These policies expose `expand_inputs(sequences)` and the driver runs all `B·T` evaluations in **one batched sweep** instead of a Python timestep loop (Stateless).

The driver prefers `expand_inputs` when a policy has it (idiomatic optional method, like the backends' `statevector` / `probabilities`).

### `Carry`

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 (B, F). | *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 ReservoirState. |

#### `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 (B, F).   | *required* |
| `state` | `ReservoirState` | The state carried over from the previous step. | *required* |

Returns:

| Name            | Type      | Description                                     |
| --------------- | --------- | ----------------------------------------------- |
| `initial_state` | \`ndarray | None\`                                          |
| `gate_inputs`   | `ndarray` | The values to pass to the gates of the circuit. |

### `LeakyCarry`

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 [0, 1]. Lower values forget faster, and 1 keeps everything, which is exactly Carry. |
| `reset` | \`ndarray | None\`                                                                                                                         |

#### `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 (B, F). | *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 ReservoirState. |

#### `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 (B, F).   | *required* |
| `state` | `ReservoirState` | The state carried over from the previous step. | *required* |

Returns:

| Name            | Type      | Description                                     |
| --------------- | --------- | ----------------------------------------------- |
| `initial_state` | \`ndarray | None\`                                          |
| `gate_inputs`   | `ndarray` | The values to pass to the gates of the circuit. |

### `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 (B, F). | *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 ReservoirState. |

#### `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 (B, F).   | *required* |
| `state` | `ReservoirState` | The state carried over from the previous step. | *required* |

Returns:

| Name            | Type      | Description                                     |
| --------------- | --------- | ----------------------------------------------- |
| `initial_state` | \`ndarray | None\`                                          |
| `gate_inputs`   | `ndarray` | The values to pass to the gates of the circuit. |

### `ReservoirState`

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\`      |
| `history` | \`ndarray | None\`      |

### `Stateless`

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. 1 means no memory: only the current input is encoded. Whatever the value, the circuit's n_inputs must equal window * F. The default is 1. |

#### `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 (B, T, F). | *required* |

Returns:

| Type      | Description                                                      |
| --------- | ---------------------------------------------------------------- |
| `ndarray` | The gate inputs for every timestep, of shape (B, T, window * F). |
