Context
Quantum memory capacity is a core deliverable in OVERVIEW.md Workstream B3 and the planned Notebook 04. docs/physics.md lists it as planned. The Dambre et al. (2012) framework measures how well a dynamical system recalls delayed versions of injected input signals via a linear readout.
tasks.py docstring already references the metric but no implementation exists. Issue #1 provides collect_features() for the quantum reservoir; Issue #5 provides collect_esn_features() for the classical baseline. This issue adds the metric layer on top of either feature source.
Goal
Add memory capacity computation to the package (suggested module name: memory.py) so Notebook 04 can sweep chain parameters without reimplementing the math.
Theory (implementation reference)
For delays k = 1, 2, ..., K_max:
- Inject scalar impulse input at delay k (standard RC protocol): u(t) = delta(t - k) or equivalent normalized impulse sequence
- Collect reservoir features X(t) over the run (with washout)
- Train linear readout to predict u(t - k) from X(t) — Ridge regression
- Per-delay capacity: MC_k = max correlation achievable (Dambre uses squared correlation between target and best linear readout; equivalent to R^2 for scalar output)
- Total memory capacity: MC = sum_k MC_k
For quantum vs classical comparison, use identical impulse protocol and K_max on QRC and ESN features.
Requirements
1. Configuration
@dataclass
class MemoryCapacityConfig:
k_max: int = 20 # maximum delay to probe
n_samples: int = 2000 # sequence length for impulse runs (excluding washout)
washout: int = 100
ridge_alpha: float = 1e-3
seed: int | None = 42
2. Impulse input generator
def impulse_inputs(k: int, length: int) -> np.ndarray:
"""
Build input sequence with impulse at delay k.
u(t) in [0, 1] or {-1, +1} — pick one convention, document it, use consistently.
"""
Also provide a batch helper that returns inputs for k = 1..k_max.
3. Per-delay capacity
def delay_capacity(
features: np.ndarray,
targets: np.ndarray,
) -> float:
"""
MC_k: squared Pearson correlation between targets and Ridge predictions,
clipped to [0, 1]. Equivalent to R^2 for scalar linear readout.
"""
Use train_ridge from trainer.py. Features and targets must be aligned in time (same length after washout).
4. Total memory capacity for a feature collector
def memory_capacity(
collect_fn: Callable[[np.ndarray, Any], np.ndarray],
collect_config: Any,
mc_config: MemoryCapacityConfig,
) -> MemoryCapacityResult:
"""
For each k in 1..k_max:
build impulse input -> collect_fn(inputs, collect_config) -> delay_capacity
Returns per-delay MC_k array and total MC = sum(MC_k).
"""
MemoryCapacityResult should contain:
- mc_per_delay: np.ndarray shape (k_max,)
- total_mc: float
- k_max: int
- config: MemoryCapacityConfig
collect_fn is the generic hook — pass pipeline.collect_features with QRCConfig, or esn.collect_esn_features with ESNConfig.
5. Convenience wrappers
def qrc_memory_capacity(
qrc_config: QRCConfig,
mc_config: MemoryCapacityConfig | None = None,
) -> MemoryCapacityResult: ...
def esn_memory_capacity(
esn_config: ESNConfig,
mc_config: MemoryCapacityConfig | None = None,
) -> MemoryCapacityResult: ...
Adjust type names to match Issues #1 and #5.
6. Tests — tests/test_memory.py
Keep fast: small k_max (5), short sequences (100), small reservoirs (N=4 / n_reservoir=50).
| Test |
Verifies |
| test_impulse_inputs_shape |
Correct length, single impulse at delay k |
| test_delay_capacity_bounds |
0 <= MC_k <= 1 |
| test_memory_capacity_sum |
total_mc == sum(mc_per_delay) |
| test_qrc_memory_capacity_smoke |
Runs on QRCConfig(n_sites=4, ...) without error |
| test_esn_memory_capacity_smoke |
Runs on ESNConfig(n_reservoir=30, ...) — skip if Issue #5 not merged |
Use pytest.importorskip or conditional skip if esn module absent.
7. Documentation
- docs/api.md — memory module section
- docs/physics.md — replace planned with implemented one-liner + link to memory.py
- REFERENCES.md already has Dambre M1 — cite in module docstring
Scope limits
- No Notebook 04 in this issue (separate issue or follow-up)
- No Optuna sweeps over (N, tau, W)
- No sine-wave recall task (optional extension later)
- K_max default 20 is fine for v1; notebook may use larger
Acceptance criteria
Files likely touched
- src/spintronic_qrc/memory.py (new)
- tests/test_memory.py (new)
- docs/api.md
- docs/physics.md
Depends on
Blocks
- Notebook 04 — memory capacity vs chain params
- benchmarks/ memory capacity scripts
- OVERVIEW validated results table (quantum MC vs ESN MC)
Context
Quantum memory capacity is a core deliverable in OVERVIEW.md Workstream B3 and the planned Notebook 04. docs/physics.md lists it as planned. The Dambre et al. (2012) framework measures how well a dynamical system recalls delayed versions of injected input signals via a linear readout.
tasks.py docstring already references the metric but no implementation exists. Issue #1 provides collect_features() for the quantum reservoir; Issue #5 provides collect_esn_features() for the classical baseline. This issue adds the metric layer on top of either feature source.
Goal
Add memory capacity computation to the package (suggested module name: memory.py) so Notebook 04 can sweep chain parameters without reimplementing the math.
Theory (implementation reference)
For delays k = 1, 2, ..., K_max:
For quantum vs classical comparison, use identical impulse protocol and K_max on QRC and ESN features.
Requirements
1. Configuration
2. Impulse input generator
Also provide a batch helper that returns inputs for k = 1..k_max.
3. Per-delay capacity
Use train_ridge from trainer.py. Features and targets must be aligned in time (same length after washout).
4. Total memory capacity for a feature collector
MemoryCapacityResult should contain:
collect_fn is the generic hook — pass pipeline.collect_features with QRCConfig, or esn.collect_esn_features with ESNConfig.
5. Convenience wrappers
Adjust type names to match Issues #1 and #5.
6. Tests — tests/test_memory.py
Keep fast: small k_max (5), short sequences (100), small reservoirs (N=4 / n_reservoir=50).
Use pytest.importorskip or conditional skip if esn module absent.
7. Documentation
Scope limits
Acceptance criteria
Files likely touched
Depends on
Blocks