Merge commit 'd803bfe2b1fe7f5e219e50ac20d6801a0a58ac75' as 'vendor/ruvector'
This commit is contained in:
468
vendor/ruvector/crates/ruQu/src/traits.rs
vendored
Normal file
468
vendor/ruvector/crates/ruQu/src/traits.rs
vendored
Normal file
@@ -0,0 +1,468 @@
|
||||
//! Standard Interface Traits for ruQu
|
||||
//!
|
||||
//! These traits define the pluggable interfaces for ruQu, allowing:
|
||||
//! - Different syndrome sources (simulators, hardware)
|
||||
//! - Different gate engines (min-cut, heuristic, ML)
|
||||
//! - Different action sinks (logging, hardware control)
|
||||
//!
|
||||
//! This keeps the core logic stable while data sources and backends change.
|
||||
|
||||
use crate::syndrome::DetectorBitmap;
|
||||
use std::time::Duration;
|
||||
|
||||
/// Error type for trait implementations
|
||||
#[derive(Debug, Clone, thiserror::Error)]
|
||||
pub enum TraitError {
|
||||
/// Source has no more data
|
||||
#[error("Source exhausted")]
|
||||
SourceExhausted,
|
||||
/// Hardware communication error
|
||||
#[error("Hardware error: {0}")]
|
||||
HardwareError(String),
|
||||
/// Configuration error
|
||||
#[error("Configuration error: {0}")]
|
||||
ConfigError(String),
|
||||
/// Operation timed out
|
||||
#[error("Timeout after {0:?}")]
|
||||
Timeout(Duration),
|
||||
}
|
||||
|
||||
/// Result type for trait operations
|
||||
pub type TraitResult<T> = Result<T, TraitError>;
|
||||
|
||||
// ============================================================================
|
||||
// SYNDROME SOURCE TRAIT
|
||||
// ============================================================================
|
||||
|
||||
/// A source of syndrome data (detector events)
|
||||
///
|
||||
/// Implementations can be:
|
||||
/// - Stim-based simulator
|
||||
/// - File replay
|
||||
/// - Hardware interface
|
||||
/// - Network stream
|
||||
pub trait SyndromeSource: Send {
|
||||
/// Sample the next syndrome round
|
||||
fn sample(&mut self) -> TraitResult<DetectorBitmap>;
|
||||
|
||||
/// Get the number of detectors per round
|
||||
fn num_detectors(&self) -> usize;
|
||||
|
||||
/// Get the code distance (if known)
|
||||
fn code_distance(&self) -> Option<usize> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Check if the source is exhausted (for finite sources)
|
||||
fn is_exhausted(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Reset the source to the beginning (if supported)
|
||||
fn reset(&mut self) -> TraitResult<()> {
|
||||
Err(TraitError::ConfigError("Reset not supported".into()))
|
||||
}
|
||||
|
||||
/// Get source metadata
|
||||
fn metadata(&self) -> SourceMetadata {
|
||||
SourceMetadata::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Metadata about a syndrome source
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct SourceMetadata {
|
||||
/// Human-readable name
|
||||
pub name: String,
|
||||
/// Code distance
|
||||
pub code_distance: Option<usize>,
|
||||
/// Error rate (if known)
|
||||
pub error_rate: Option<f64>,
|
||||
/// Number of rounds (if finite)
|
||||
pub total_rounds: Option<u64>,
|
||||
/// Source version/format
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// TELEMETRY SOURCE TRAIT
|
||||
// ============================================================================
|
||||
|
||||
/// A source of telemetry data (temperature, timing, etc.)
|
||||
pub trait TelemetrySource: Send {
|
||||
/// Get current telemetry snapshot
|
||||
fn snapshot(&self) -> TelemetrySnapshot;
|
||||
|
||||
/// Check if telemetry indicates a problem
|
||||
fn has_alert(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Telemetry data snapshot
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct TelemetrySnapshot {
|
||||
/// Timestamp in nanoseconds since epoch
|
||||
pub timestamp_ns: u64,
|
||||
/// Fridge temperature in Kelvin (if available)
|
||||
pub fridge_temp_k: Option<f64>,
|
||||
/// Qubit temperatures (per qubit, if available)
|
||||
pub qubit_temps: Vec<f64>,
|
||||
/// Readout fidelity estimates
|
||||
pub readout_fidelity: Vec<f64>,
|
||||
/// Gate error estimates
|
||||
pub gate_errors: Vec<f64>,
|
||||
/// Custom key-value pairs
|
||||
pub custom: Vec<(String, f64)>,
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// GATE ENGINE TRAIT
|
||||
// ============================================================================
|
||||
|
||||
/// A gate decision engine
|
||||
///
|
||||
/// Takes syndrome data and produces permit/defer/deny decisions.
|
||||
pub trait GateEngine: Send {
|
||||
/// Process a syndrome round and return a decision
|
||||
fn process(&mut self, syndrome: &DetectorBitmap) -> GateDecision;
|
||||
|
||||
/// Get the current risk assessment
|
||||
fn risk_assessment(&self) -> RiskAssessment;
|
||||
|
||||
/// Update thresholds or parameters
|
||||
fn update_config(&mut self, config: GateConfig) -> TraitResult<()>;
|
||||
|
||||
/// Get engine statistics
|
||||
fn statistics(&self) -> EngineStatistics;
|
||||
|
||||
/// Reset engine state
|
||||
fn reset(&mut self);
|
||||
}
|
||||
|
||||
/// Gate decision output
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum GateDecision {
|
||||
/// Permit the operation - low risk
|
||||
Permit {
|
||||
/// Confidence level (0.0 to 1.0)
|
||||
confidence: f64,
|
||||
/// Time-to-live in nanoseconds
|
||||
ttl_ns: u64,
|
||||
/// Optional explanation
|
||||
reason: Option<String>,
|
||||
},
|
||||
/// Defer - uncertain, need more data
|
||||
Defer {
|
||||
/// Suggested wait time in nanoseconds
|
||||
wait_ns: u64,
|
||||
/// Uncertainty level
|
||||
uncertainty: f64,
|
||||
},
|
||||
/// Deny - high risk detected
|
||||
Deny {
|
||||
/// Risk level (0.0 to 1.0)
|
||||
risk_level: f64,
|
||||
/// Recommended action
|
||||
recommended_action: String,
|
||||
/// Affected regions (bitmask or list)
|
||||
affected_regions: Vec<u32>,
|
||||
},
|
||||
}
|
||||
|
||||
impl Default for GateDecision {
|
||||
fn default() -> Self {
|
||||
GateDecision::Defer {
|
||||
wait_ns: 1000,
|
||||
uncertainty: 1.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Risk assessment from the gate engine
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct RiskAssessment {
|
||||
/// Overall risk level (0.0 = safe, 1.0 = critical)
|
||||
pub overall_risk: f64,
|
||||
/// Structural risk (from min-cut)
|
||||
pub structural_risk: f64,
|
||||
/// Temporal risk (from recent history)
|
||||
pub temporal_risk: f64,
|
||||
/// Spatial risk (from region clustering)
|
||||
pub spatial_risk: f64,
|
||||
/// Risk per region
|
||||
pub region_risks: Vec<(u32, f64)>,
|
||||
/// Confidence in assessment
|
||||
pub confidence: f64,
|
||||
}
|
||||
|
||||
/// Gate engine configuration
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GateConfig {
|
||||
/// Minimum cut threshold for permit
|
||||
pub min_cut_threshold: f64,
|
||||
/// Maximum shift for permit
|
||||
pub max_shift: f64,
|
||||
/// Permit tau threshold
|
||||
pub tau_permit: f64,
|
||||
/// Deny tau threshold
|
||||
pub tau_deny: f64,
|
||||
/// Permit time-to-live in ns
|
||||
pub permit_ttl_ns: u64,
|
||||
}
|
||||
|
||||
impl Default for GateConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
min_cut_threshold: 5.0,
|
||||
max_shift: 0.2,
|
||||
tau_permit: 0.3,
|
||||
tau_deny: 0.7,
|
||||
permit_ttl_ns: 100_000,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Statistics from the gate engine
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct EngineStatistics {
|
||||
/// Total rounds processed
|
||||
pub total_rounds: u64,
|
||||
/// Permits issued
|
||||
pub permits: u64,
|
||||
/// Defers issued
|
||||
pub defers: u64,
|
||||
/// Denies issued
|
||||
pub denies: u64,
|
||||
/// Average processing time in nanoseconds
|
||||
pub avg_process_ns: f64,
|
||||
/// P99 processing time in nanoseconds
|
||||
pub p99_process_ns: u64,
|
||||
/// P999 processing time in nanoseconds
|
||||
pub p999_process_ns: u64,
|
||||
/// Max processing time in nanoseconds
|
||||
pub max_process_ns: u64,
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// ACTION SINK TRAIT
|
||||
// ============================================================================
|
||||
|
||||
/// A sink for mitigation actions
|
||||
///
|
||||
/// Receives actions from the gate engine and executes them.
|
||||
pub trait ActionSink: Send {
|
||||
/// Execute an action
|
||||
fn execute(&mut self, action: &MitigationAction) -> TraitResult<ActionResult>;
|
||||
|
||||
/// Check if an action is supported
|
||||
fn supports(&self, action_type: ActionType) -> bool;
|
||||
|
||||
/// Get sink capabilities
|
||||
fn capabilities(&self) -> ActionCapabilities;
|
||||
}
|
||||
|
||||
/// Types of mitigation actions
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum ActionType {
|
||||
/// Quarantine a region
|
||||
QuarantineRegion,
|
||||
/// Increase syndrome measurement rounds
|
||||
IncreaseSyndromeRounds,
|
||||
/// Switch decoder mode
|
||||
SwitchDecodeMode,
|
||||
/// Trigger re-weighting
|
||||
TriggerReweight,
|
||||
/// Pause learning/writes
|
||||
PauseLearningWrites,
|
||||
/// Log event
|
||||
LogEvent,
|
||||
/// Alert operator
|
||||
AlertOperator,
|
||||
/// Inject test error
|
||||
InjectTestError,
|
||||
}
|
||||
|
||||
/// A mitigation action to execute
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MitigationAction {
|
||||
/// Action type
|
||||
pub action_type: ActionType,
|
||||
/// Target region(s)
|
||||
pub target_regions: Vec<u32>,
|
||||
/// Parameters (action-specific)
|
||||
pub parameters: ActionParameters,
|
||||
/// Priority (higher = more urgent)
|
||||
pub priority: u8,
|
||||
/// Preconditions that must be true
|
||||
pub preconditions: Vec<Precondition>,
|
||||
/// Estimated cost
|
||||
pub estimated_cost: ActionCost,
|
||||
/// Expected effect
|
||||
pub expected_effect: String,
|
||||
}
|
||||
|
||||
/// Action parameters
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct ActionParameters {
|
||||
/// Duration in nanoseconds (if applicable)
|
||||
pub duration_ns: Option<u64>,
|
||||
/// Intensity level (0.0 to 1.0)
|
||||
pub intensity: Option<f64>,
|
||||
/// Custom key-value pairs
|
||||
pub custom: Vec<(String, String)>,
|
||||
}
|
||||
|
||||
/// Precondition for an action
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Precondition {
|
||||
/// Risk level must be above threshold
|
||||
RiskAbove(f64),
|
||||
/// Risk level must be below threshold
|
||||
RiskBelow(f64),
|
||||
/// Region must be in specified state
|
||||
RegionState(u32, String),
|
||||
/// Time since last action of this type
|
||||
TimeSinceLastAction(ActionType, Duration),
|
||||
/// Custom condition
|
||||
Custom(String),
|
||||
}
|
||||
|
||||
/// Cost estimate for an action
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct ActionCost {
|
||||
/// Time cost in nanoseconds
|
||||
pub time_ns: u64,
|
||||
/// Qubit overhead (extra qubits needed)
|
||||
pub qubit_overhead: u32,
|
||||
/// Fidelity impact (0.0 = no impact, 1.0 = total loss)
|
||||
pub fidelity_impact: f64,
|
||||
/// Throughput impact (0.0 = no impact, 1.0 = total stop)
|
||||
pub throughput_impact: f64,
|
||||
}
|
||||
|
||||
/// Result of executing an action
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ActionResult {
|
||||
/// Whether the action succeeded
|
||||
pub success: bool,
|
||||
/// Actual cost incurred
|
||||
pub actual_cost: ActionCost,
|
||||
/// Any warnings or notes
|
||||
pub notes: Vec<String>,
|
||||
}
|
||||
|
||||
/// Capabilities of an action sink
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct ActionCapabilities {
|
||||
/// Supported action types
|
||||
pub supported_actions: Vec<ActionType>,
|
||||
/// Maximum concurrent actions
|
||||
pub max_concurrent: u32,
|
||||
/// Minimum action interval in nanoseconds
|
||||
pub min_interval_ns: u64,
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// CONVENIENCE IMPLEMENTATIONS
|
||||
// ============================================================================
|
||||
|
||||
/// Null syndrome source for testing
|
||||
pub struct NullSyndromeSource {
|
||||
num_detectors: usize,
|
||||
}
|
||||
|
||||
impl NullSyndromeSource {
|
||||
/// Create a new null syndrome source
|
||||
pub fn new(num_detectors: usize) -> Self {
|
||||
Self { num_detectors }
|
||||
}
|
||||
}
|
||||
|
||||
impl SyndromeSource for NullSyndromeSource {
|
||||
fn sample(&mut self) -> TraitResult<DetectorBitmap> {
|
||||
Ok(DetectorBitmap::new(self.num_detectors))
|
||||
}
|
||||
|
||||
fn num_detectors(&self) -> usize {
|
||||
self.num_detectors
|
||||
}
|
||||
}
|
||||
|
||||
/// Logging action sink
|
||||
pub struct LoggingActionSink {
|
||||
log_prefix: String,
|
||||
}
|
||||
|
||||
impl LoggingActionSink {
|
||||
/// Create a new logging action sink with given prefix
|
||||
pub fn new(prefix: &str) -> Self {
|
||||
Self {
|
||||
log_prefix: prefix.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ActionSink for LoggingActionSink {
|
||||
fn execute(&mut self, action: &MitigationAction) -> TraitResult<ActionResult> {
|
||||
println!(
|
||||
"{}: {:?} on regions {:?}",
|
||||
self.log_prefix, action.action_type, action.target_regions
|
||||
);
|
||||
Ok(ActionResult {
|
||||
success: true,
|
||||
actual_cost: ActionCost::default(),
|
||||
notes: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
fn supports(&self, _action_type: ActionType) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn capabilities(&self) -> ActionCapabilities {
|
||||
ActionCapabilities {
|
||||
supported_actions: vec![ActionType::LogEvent, ActionType::AlertOperator],
|
||||
max_concurrent: 100,
|
||||
min_interval_ns: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_null_syndrome_source() {
|
||||
let mut source = NullSyndromeSource::new(100);
|
||||
let syndrome = source.sample().unwrap();
|
||||
assert_eq!(syndrome.fired_count(), 0);
|
||||
assert_eq!(source.num_detectors(), 100);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gate_decision_default() {
|
||||
let decision = GateDecision::default();
|
||||
match decision {
|
||||
GateDecision::Defer { .. } => (),
|
||||
_ => panic!("Default should be Defer"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_logging_action_sink() {
|
||||
let mut sink = LoggingActionSink::new("[TEST]");
|
||||
let action = MitigationAction {
|
||||
action_type: ActionType::LogEvent,
|
||||
target_regions: vec![1, 2, 3],
|
||||
parameters: ActionParameters::default(),
|
||||
priority: 5,
|
||||
preconditions: vec![],
|
||||
estimated_cost: ActionCost::default(),
|
||||
expected_effect: "Log the event".into(),
|
||||
};
|
||||
let result = sink.execute(&action).unwrap();
|
||||
assert!(result.success);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user