"""FilterSet container for matched filter collections."""
from __future__ import annotations
from dataclasses import dataclass, field
import numpy as np
[docs]
@dataclass
class FilterSet:
"""Container for per-qubit matched filter envelopes and thresholds.
Attributes:
num_qubits: Number of qubits.
num_levels: Energy levels per qubit (2 for qubit, 3 for qutrit).
filters: Nested dict ``filters[qubit][filter_name]`` -> ndarray.
thresholds: Nested dict ``thresholds[qubit][filter_name]`` -> float.
trace_length: Number of time steps the filters were computed for.
"""
num_qubits: int
num_levels: int
filters: dict[int, dict[str, np.ndarray]] = field(default_factory=dict)
thresholds: dict[int, dict[str, float]] = field(default_factory=dict)
trace_length: int | None = None
[docs]
def get(self, qubit: int, name: str) -> tuple[np.ndarray, float]:
"""Return ``(envelope, threshold)`` for one filter."""
return self.filters[qubit][name], self.thresholds[qubit][name]
[docs]
def filter_names(self, qubit: int) -> list[str]:
"""List all filter names for a given qubit."""
return list(self.filters.get(qubit, {}).keys())
@property
def total_features(self) -> int:
"""Total scalar features produced by ``apply_filters``."""
return sum(len(d) for d in self.filters.values())
[docs]
def qubit_feature_slices(self) -> dict[int, slice]:
"""Map each qubit to its column slice in the feature matrix."""
slices: dict[int, slice] = {}
col = 0
for q in sorted(self.filters.keys()):
n = len(self.filters[q])
slices[q] = slice(col, col + n)
col += n
return slices