ruqu 0.1.32

Classical nervous system for quantum machines - real-time coherence assessment via dynamic min-cut
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
//! 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);
    }
}