Skip to content

Memory capacity metric (Dambre et al. 2012) in package #6

Description

@rosspeili

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:

  1. Inject scalar impulse input at delay k (standard RC protocol): u(t) = delta(t - k) or equivalent normalized impulse sequence
  2. Collect reservoir features X(t) over the run (with washout)
  3. Train linear readout to predict u(t - k) from X(t) — Ridge regression
  4. 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)
  5. 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

  • memory.py with impulse generation, delay_capacity, memory_capacity, qrc_memory_capacity
  • esn_memory_capacity if Issue Classical Echo State Network baseline module + unit tests #5 merged (otherwise stub with skip in tests)
  • tests/test_memory.py >= 4 tests passing
  • total_mc reproducible with fixed seed
  • docs/api.md and docs/physics.md updated

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions