use std::time::Instant;
use crate::error::{Result, RuQuError};
use crate::filters::{FilterConfig, FilterPipeline, FilterResults, SystemState, Verdict};
use crate::syndrome::SyndromeRound;
use crate::tile::{
GateDecision as TileGateDecision, GateThresholds, ReceiptLog, TileReport, TileZero, WorkerTile,
};
use crate::types::{GateDecision, RegionMask, SequenceId};
use crate::{DEFAULT_BUFFER_CAPACITY, TILE_COUNT, WORKER_TILE_COUNT};
#[derive(Debug, Clone)]
pub struct TileAssignment {
pub tile_id: u8,
pub vertices: Vec<u64>,
pub boundary_vertices: Vec<u64>,
pub neighbors: Vec<u8>,
}
impl TileAssignment {
pub fn new(tile_id: u8) -> Self {
Self {
tile_id,
vertices: Vec::new(),
boundary_vertices: Vec::new(),
neighbors: Vec::new(),
}
}
pub fn add_vertex(&mut self, vertex_id: u64) {
self.vertices.push(vertex_id);
}
pub fn add_boundary(&mut self, vertex_id: u64) {
self.boundary_vertices.push(vertex_id);
}
pub fn add_neighbor(&mut self, tile_id: u8) {
if !self.neighbors.contains(&tile_id) {
self.neighbors.push(tile_id);
}
}
pub fn vertex_count(&self) -> usize {
self.vertices.len() + self.boundary_vertices.len()
}
}
#[derive(Debug, Clone)]
pub struct PatchMap {
pub name: String,
pub qubit_count: usize,
pub tile_assignments: Vec<TileAssignment>,
pub distance: Option<usize>,
pub detector_count: usize,
}
impl PatchMap {
pub fn new(name: impl Into<String>, qubit_count: usize) -> Self {
Self {
name: name.into(),
qubit_count,
tile_assignments: Vec::new(),
distance: None,
detector_count: qubit_count, }
}
pub fn with_distance(mut self, d: usize) -> Self {
self.distance = Some(d);
self
}
pub fn with_detectors(mut self, count: usize) -> Self {
self.detector_count = count;
self
}
pub fn add_assignment(&mut self, assignment: TileAssignment) {
self.tile_assignments.push(assignment);
}
pub fn tile_count(&self) -> usize {
self.tile_assignments.len()
}
pub fn get_assignment(&self, tile_id: u8) -> Option<&TileAssignment> {
self.tile_assignments.iter().find(|a| a.tile_id == tile_id)
}
pub fn find_tile_for_vertex(&self, vertex_id: u64) -> Option<u8> {
for assignment in &self.tile_assignments {
if assignment.vertices.contains(&vertex_id) {
return Some(assignment.tile_id);
}
}
None
}
pub fn validate(&self) -> Result<()> {
if self.qubit_count == 0 {
return Err(RuQuError::InvalidFabricConfig(
"PatchMap has zero qubits".to_string(),
));
}
if self.tile_assignments.is_empty() {
return Err(RuQuError::InvalidFabricConfig(
"PatchMap has no tile assignments".to_string(),
));
}
let mut seen_ids = std::collections::HashSet::new();
for assignment in &self.tile_assignments {
if assignment.tile_id == 0 {
return Err(RuQuError::InvalidFabricConfig(
"TileId 0 is reserved for TileZero".to_string(),
));
}
if !seen_ids.insert(assignment.tile_id) {
return Err(RuQuError::InvalidFabricConfig(format!(
"Duplicate tile ID: {}",
assignment.tile_id
)));
}
}
Ok(())
}
}
pub fn surface_code_d7() -> PatchMap {
surface_code(7)
}
pub fn surface_code(distance: usize) -> PatchMap {
assert!(distance >= 3, "Surface code distance must be >= 3");
assert!(distance % 2 == 1, "Surface code distance must be odd");
let qubit_count = 2 * distance * distance;
let detector_count = 2 * (distance - 1) * (distance - 1);
let mut patch_map = PatchMap::new(format!("surface_code_d{}", distance), qubit_count)
.with_distance(distance)
.with_detectors(detector_count);
let qubits_per_tile = (qubit_count as f64).sqrt().ceil() as usize;
let num_tiles = (qubit_count + qubits_per_tile - 1) / qubits_per_tile;
let num_tiles = num_tiles.min(WORKER_TILE_COUNT);
for tile_idx in 0..num_tiles {
let tile_id = (tile_idx + 1) as u8; let mut assignment = TileAssignment::new(tile_id);
let start_qubit = tile_idx * qubits_per_tile;
let end_qubit = ((tile_idx + 1) * qubits_per_tile).min(qubit_count);
for qubit in start_qubit..end_qubit {
assignment.add_vertex(qubit as u64);
}
if tile_idx > 0 {
assignment.add_neighbor(tile_idx as u8);
}
if tile_idx < num_tiles - 1 {
assignment.add_neighbor((tile_idx + 2) as u8);
}
if tile_idx > 0 {
assignment.add_boundary(start_qubit as u64);
}
if tile_idx < num_tiles - 1 && end_qubit > start_qubit {
assignment.add_boundary((end_qubit - 1) as u64);
}
patch_map.add_assignment(assignment);
}
patch_map
}
pub fn linear_patch_map(qubit_count: usize, tiles: usize) -> PatchMap {
let tiles = tiles.min(WORKER_TILE_COUNT).max(1);
let mut patch_map = PatchMap::new("linear", qubit_count);
let qubits_per_tile = (qubit_count + tiles - 1) / tiles;
for tile_idx in 0..tiles {
let tile_id = (tile_idx + 1) as u8;
let mut assignment = TileAssignment::new(tile_id);
let start = tile_idx * qubits_per_tile;
let end = ((tile_idx + 1) * qubits_per_tile).min(qubit_count);
for qubit in start..end {
assignment.add_vertex(qubit as u64);
}
patch_map.add_assignment(assignment);
}
patch_map
}
#[derive(Debug, Clone)]
pub struct FabricConfig {
pub tile_count: usize,
pub buffer_size: usize,
pub thresholds: GateThresholds,
pub filter_config: FilterConfig,
pub enable_receipts: bool,
pub decision_budget_ns: u64,
}
impl Default for FabricConfig {
fn default() -> Self {
Self {
tile_count: TILE_COUNT,
buffer_size: DEFAULT_BUFFER_CAPACITY,
thresholds: GateThresholds::default(),
filter_config: FilterConfig::default(),
enable_receipts: true,
decision_budget_ns: 4_000, }
}
}
impl FabricConfig {
pub fn validate(&self) -> Result<()> {
if self.tile_count == 0 || self.tile_count > TILE_COUNT {
return Err(RuQuError::InvalidFabricConfig(format!(
"tile_count must be 1-{}, got {}",
TILE_COUNT, self.tile_count
)));
}
if self.buffer_size == 0 {
return Err(RuQuError::InvalidFabricConfig(
"buffer_size must be positive".to_string(),
));
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct FabricState {
pub tick: u64,
pub syndromes_ingested: u64,
pub active_tiles: usize,
pub last_decision: GateDecision,
pub quarantine_mask: RegionMask,
pub avg_latency_ns: u64,
pub peak_latency_ns: u64,
pub permit_count: u64,
pub defer_count: u64,
pub deny_count: u64,
}
impl Default for FabricState {
fn default() -> Self {
Self {
tick: 0,
syndromes_ingested: 0,
active_tiles: 0,
last_decision: GateDecision::Cautious,
quarantine_mask: RegionMask::none(),
avg_latency_ns: 0,
peak_latency_ns: 0,
permit_count: 0,
defer_count: 0,
deny_count: 0,
}
}
}
impl FabricState {
pub fn total_decisions(&self) -> u64 {
self.permit_count + self.defer_count + self.deny_count
}
pub fn permit_rate(&self) -> f64 {
let total = self.total_decisions();
if total == 0 {
return 0.0;
}
self.permit_count as f64 / total as f64
}
}
#[derive(Debug, Clone)]
pub struct WitnessReceipt {
pub sequence: SequenceId,
pub timestamp: u64,
pub decision: GateDecision,
pub input_hash: [u8; 32],
pub filter_summary: FilterSummary,
pub previous_hash: [u8; 32],
pub hash: [u8; 32],
}
#[derive(Debug, Clone, Default)]
pub struct FilterSummary {
pub cut_value: f64,
pub shift_pressure: f64,
pub e_value: f64,
pub affected_regions: u32,
}
#[derive(Debug)]
pub struct CoherenceGate {
pipeline: FilterPipeline,
state: SystemState,
sequence: SequenceId,
last_receipt_hash: [u8; 32],
}
impl CoherenceGate {
pub fn new(config: FilterConfig) -> Self {
Self {
pipeline: FilterPipeline::new(config),
state: SystemState::new(0),
sequence: 0,
last_receipt_hash: [0u8; 32],
}
}
pub fn with_defaults() -> Self {
Self::new(FilterConfig::default())
}
pub fn evaluate(&self) -> Result<GateDecision> {
let results = self.pipeline.evaluate(&self.state);
let decision = match results.verdict {
Some(Verdict::Permit) => GateDecision::Safe,
Some(Verdict::Deny) => GateDecision::Unsafe,
Some(Verdict::Defer) | None => GateDecision::Cautious,
};
Ok(decision)
}
pub fn evaluate_detailed(&self) -> FilterResults {
self.pipeline.evaluate(&self.state)
}
pub fn receipt(&self) -> Option<WitnessReceipt> {
if self.sequence == 0 {
return None;
}
let results = self.pipeline.evaluate(&self.state);
let summary = FilterSummary {
cut_value: results.structural.cut_value,
shift_pressure: results.shift.pressure,
e_value: results.evidence.e_value,
affected_regions: results.affected_regions.count(),
};
let mut hash = [0u8; 32];
hash[0..8].copy_from_slice(&self.sequence.to_le_bytes());
hash[8..16].copy_from_slice(&summary.cut_value.to_le_bytes());
Some(WitnessReceipt {
sequence: self.sequence,
timestamp: std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_nanos() as u64)
.unwrap_or(0),
decision: self.evaluate().unwrap_or(GateDecision::Cautious),
input_hash: self.last_receipt_hash,
filter_summary: summary,
previous_hash: self.last_receipt_hash,
hash,
})
}
pub fn update_state(&mut self, state: SystemState) {
self.state = state;
}
pub fn pipeline_mut(&mut self) -> &mut FilterPipeline {
&mut self.pipeline
}
pub fn pipeline(&self) -> &FilterPipeline {
&self.pipeline
}
pub fn state(&self) -> &SystemState {
&self.state
}
pub(crate) fn increment_sequence(&mut self) {
self.sequence += 1;
}
}
#[derive(Debug)]
pub struct FabricBuilder {
tile_count: usize,
patch_map: Option<PatchMap>,
buffer_size: usize,
thresholds: GateThresholds,
filter_config: FilterConfig,
enable_receipts: bool,
}
impl Default for FabricBuilder {
fn default() -> Self {
Self::new()
}
}
impl FabricBuilder {
pub fn new() -> Self {
Self {
tile_count: TILE_COUNT,
patch_map: None,
buffer_size: DEFAULT_BUFFER_CAPACITY,
thresholds: GateThresholds::default(),
filter_config: FilterConfig::default(),
enable_receipts: true,
}
}
pub fn tiles(mut self, count: usize) -> Self {
self.tile_count = count.min(TILE_COUNT);
self
}
pub fn patch_map(mut self, map: PatchMap) -> Self {
self.patch_map = Some(map);
self
}
pub fn syndrome_buffer(mut self, size: usize) -> Self {
self.buffer_size = size.max(1);
self
}
pub fn thresholds(mut self, t: GateThresholds) -> Self {
self.thresholds = t;
self
}
pub fn filter_config(mut self, config: FilterConfig) -> Self {
self.filter_config = config;
self
}
pub fn enable_receipts(mut self, enable: bool) -> Self {
self.enable_receipts = enable;
self
}
pub fn build(self) -> Result<QuantumFabric> {
if let Some(ref map) = self.patch_map {
map.validate()?;
}
let config = FabricConfig {
tile_count: self.tile_count,
buffer_size: self.buffer_size,
thresholds: self.thresholds.clone(),
filter_config: self.filter_config.clone(),
enable_receipts: self.enable_receipts,
..Default::default()
};
config.validate()?;
let worker_count = if let Some(ref map) = self.patch_map {
map.tile_count().min(WORKER_TILE_COUNT)
} else {
(self.tile_count - 1).min(WORKER_TILE_COUNT)
};
let mut tiles: Vec<WorkerTile> = Vec::with_capacity(worker_count);
for i in 0..worker_count {
let tile_id = (i + 1) as u8; tiles.push(WorkerTile::new(tile_id));
}
let tile_zero = TileZero::new(self.thresholds);
let gate = CoherenceGate::new(self.filter_config);
let patch_map = self.patch_map.unwrap_or_else(|| {
linear_patch_map(64, worker_count) });
Ok(QuantumFabric {
tiles,
tile_zero,
config,
patch_map,
gate,
state: FabricState::default(),
receipt_log: ReceiptLog::new(),
})
}
}
#[derive(Debug)]
pub struct QuantumFabric {
tiles: Vec<WorkerTile>,
tile_zero: TileZero,
config: FabricConfig,
patch_map: PatchMap,
pub gate: CoherenceGate,
state: FabricState,
receipt_log: ReceiptLog,
}
impl QuantumFabric {
pub fn builder() -> FabricBuilder {
FabricBuilder::new()
}
pub fn ingest_syndromes(&mut self, batch: &[SyndromeRound]) -> Result<()> {
for round in batch {
self.state.syndromes_ingested += 1;
let tile_id = round.source_tile;
if tile_id == 0 || tile_id as usize > self.tiles.len() {
for tile in &mut self.tiles {
let delta = crate::tile::SyndromeDelta::new(
0,
0,
round.fired_count() as u16,
);
tile.tick(&delta);
}
} else {
let tile_idx = (tile_id - 1) as usize;
if tile_idx < self.tiles.len() {
let delta = crate::tile::SyndromeDelta::new(
0,
0,
round.fired_count() as u16,
);
self.tiles[tile_idx].tick(&delta);
}
}
}
Ok(())
}
pub fn tick(&mut self) -> Result<GateDecision> {
let start = Instant::now();
self.state.tick += 1;
let mut reports: Vec<TileReport> = Vec::with_capacity(self.tiles.len());
for tile in &self.tiles {
let report = TileReport::new(tile.tile_id);
let mut report = report;
report.local_cut = tile.local_cut_state.cut_value;
report.shift_score = 0.1; report.e_value = tile.evidence.e_value();
report.num_vertices = tile.patch_graph.num_vertices;
report.num_edges = tile.patch_graph.num_edges;
reports.push(report);
}
let tile_decision = self.tile_zero.merge_reports(reports);
let decision = match tile_decision {
TileGateDecision::Permit => GateDecision::Safe,
TileGateDecision::Defer => GateDecision::Cautious,
TileGateDecision::Deny => GateDecision::Unsafe,
};
self.state.last_decision = decision;
self.state.active_tiles = self.tiles.len();
match decision {
GateDecision::Safe => self.state.permit_count += 1,
GateDecision::Cautious => self.state.defer_count += 1,
GateDecision::Unsafe => self.state.deny_count += 1,
}
let elapsed = start.elapsed().as_nanos() as u64;
self.state.peak_latency_ns = self.state.peak_latency_ns.max(elapsed);
let n = self.state.total_decisions();
if n > 0 {
self.state.avg_latency_ns =
(self.state.avg_latency_ns * (n - 1) + elapsed) / n;
}
if elapsed > self.config.decision_budget_ns {
}
self.gate.increment_sequence();
if self.config.enable_receipts {
let witness_hash = [0u8; 32]; self.receipt_log.append(
tile_decision,
self.state.tick,
elapsed,
witness_hash,
);
}
Ok(decision)
}
pub fn current_state(&self) -> &FabricState {
&self.state
}
pub fn state_snapshot(&self) -> FabricState {
self.state.clone()
}
pub fn patch_map(&self) -> &PatchMap {
&self.patch_map
}
pub fn config(&self) -> &FabricConfig {
&self.config
}
pub fn worker_count(&self) -> usize {
self.tiles.len()
}
pub fn get_tile(&self, tile_id: u8) -> Option<&WorkerTile> {
if tile_id == 0 || tile_id as usize > self.tiles.len() {
return None;
}
Some(&self.tiles[(tile_id - 1) as usize])
}
pub fn get_tile_mut(&mut self, tile_id: u8) -> Option<&mut WorkerTile> {
if tile_id == 0 || tile_id as usize > self.tiles.len() {
return None;
}
Some(&mut self.tiles[(tile_id - 1) as usize])
}
pub fn tile_zero(&self) -> &TileZero {
&self.tile_zero
}
pub fn receipt_log(&self) -> &ReceiptLog {
&self.receipt_log
}
pub fn reset(&mut self) {
for tile in &mut self.tiles {
tile.reset();
}
self.state = FabricState::default();
self.receipt_log = ReceiptLog::new();
}
pub fn decision_stats(&self) -> DecisionStats {
DecisionStats {
total: self.state.total_decisions(),
permits: self.state.permit_count,
defers: self.state.defer_count,
denies: self.state.deny_count,
permit_rate: self.state.permit_rate(),
avg_latency_ns: self.state.avg_latency_ns,
peak_latency_ns: self.state.peak_latency_ns,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct DecisionStats {
pub total: u64,
pub permits: u64,
pub defers: u64,
pub denies: u64,
pub permit_rate: f64,
pub avg_latency_ns: u64,
pub peak_latency_ns: u64,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::syndrome::DetectorBitmap;
#[test]
fn test_surface_code_d7() {
let patch_map = surface_code_d7();
assert_eq!(patch_map.name, "surface_code_d7");
assert_eq!(patch_map.distance, Some(7));
assert!(patch_map.qubit_count > 0);
assert!(patch_map.tile_count() > 0);
assert!(patch_map.validate().is_ok());
}
#[test]
fn test_surface_code_various_distances() {
for d in [3, 5, 7, 9, 11] {
let patch_map = surface_code(d);
assert_eq!(patch_map.distance, Some(d));
assert!(patch_map.validate().is_ok());
}
}
#[test]
fn test_linear_patch_map() {
let patch_map = linear_patch_map(100, 10);
assert_eq!(patch_map.name, "linear");
assert_eq!(patch_map.qubit_count, 100);
assert_eq!(patch_map.tile_count(), 10);
assert!(patch_map.validate().is_ok());
}
#[test]
fn test_fabric_builder_default() {
let fabric = QuantumFabric::builder().build();
assert!(fabric.is_ok());
let fabric = fabric.unwrap();
assert!(fabric.worker_count() > 0);
}
#[test]
fn test_fabric_builder_with_options() {
let fabric = QuantumFabric::builder()
.tiles(16)
.patch_map(surface_code_d7())
.syndrome_buffer(512)
.enable_receipts(true)
.build();
assert!(fabric.is_ok());
let fabric = fabric.unwrap();
assert!(fabric.worker_count() <= 15);
}
#[test]
fn test_fabric_ingest_syndromes() {
let mut fabric = QuantumFabric::builder()
.tiles(4)
.build()
.unwrap();
let rounds: Vec<SyndromeRound> = (0..10)
.map(|i| {
SyndromeRound::new(
i,
i,
i * 1000,
DetectorBitmap::new(64),
0,
)
})
.collect();
let result = fabric.ingest_syndromes(&rounds);
assert!(result.is_ok());
assert_eq!(fabric.current_state().syndromes_ingested, 10);
}
#[test]
fn test_fabric_tick() {
let mut fabric = QuantumFabric::builder()
.tiles(4)
.build()
.unwrap();
let result = fabric.tick();
assert!(result.is_ok());
let state = fabric.current_state();
assert_eq!(state.tick, 1);
assert_eq!(state.total_decisions(), 1);
}
#[test]
fn test_fabric_multiple_ticks() {
let mut fabric = QuantumFabric::builder()
.tiles(8)
.build()
.unwrap();
for _ in 0..100 {
let _ = fabric.tick();
}
let state = fabric.current_state();
assert_eq!(state.tick, 100);
assert_eq!(state.total_decisions(), 100);
}
#[test]
fn test_fabric_get_tile() {
let fabric = QuantumFabric::builder()
.tiles(4)
.build()
.unwrap();
assert!(fabric.get_tile(0).is_none());
assert!(fabric.get_tile(1).is_some());
assert!(fabric.get_tile(2).is_some());
assert!(fabric.get_tile(3).is_some());
assert!(fabric.get_tile(100).is_none());
}
#[test]
fn test_fabric_reset() {
let mut fabric = QuantumFabric::builder()
.tiles(4)
.build()
.unwrap();
for _ in 0..10 {
let _ = fabric.tick();
}
assert_eq!(fabric.current_state().tick, 10);
fabric.reset();
assert_eq!(fabric.current_state().tick, 0);
assert_eq!(fabric.current_state().total_decisions(), 0);
}
#[test]
fn test_fabric_decision_stats() {
let mut fabric = QuantumFabric::builder()
.tiles(4)
.build()
.unwrap();
for _ in 0..50 {
let _ = fabric.tick();
}
let stats = fabric.decision_stats();
assert_eq!(stats.total, 50);
assert!(stats.permits + stats.defers + stats.denies == 50);
}
#[test]
fn test_coherence_gate_evaluate() {
let gate = CoherenceGate::with_defaults();
let decision = gate.evaluate();
assert!(decision.is_ok());
}
#[test]
fn test_coherence_gate_receipt() {
let mut gate = CoherenceGate::with_defaults();
assert!(gate.receipt().is_none());
gate.increment_sequence();
let receipt = gate.receipt();
assert!(receipt.is_some());
}
#[test]
fn test_patch_map_find_tile() {
let patch_map = surface_code_d7();
let tile = patch_map.find_tile_for_vertex(0);
assert!(tile.is_some());
let tile = patch_map.find_tile_for_vertex(999999);
assert!(tile.is_none());
}
#[test]
fn test_tile_assignment() {
let mut assignment = TileAssignment::new(1);
assignment.add_vertex(0);
assignment.add_vertex(1);
assignment.add_vertex(2);
assignment.add_boundary(0);
assignment.add_neighbor(2);
assignment.add_neighbor(2);
assert_eq!(assignment.vertices.len(), 3);
assert_eq!(assignment.boundary_vertices.len(), 1);
assert_eq!(assignment.neighbors.len(), 1);
assert_eq!(assignment.vertex_count(), 4);
}
#[test]
fn test_fabric_config_validate() {
let config = FabricConfig::default();
assert!(config.validate().is_ok());
let mut config = FabricConfig::default();
config.tile_count = 0;
assert!(config.validate().is_err());
let mut config = FabricConfig::default();
config.tile_count = 1000;
assert!(config.validate().is_err());
let mut config = FabricConfig::default();
config.buffer_size = 0;
assert!(config.validate().is_err());
}
#[test]
fn test_fabric_state_metrics() {
let mut state = FabricState::default();
assert_eq!(state.total_decisions(), 0);
assert_eq!(state.permit_rate(), 0.0);
state.permit_count = 80;
state.defer_count = 15;
state.deny_count = 5;
assert_eq!(state.total_decisions(), 100);
assert!((state.permit_rate() - 0.8).abs() < 0.001);
}
#[test]
fn test_witness_receipt_creation() {
let mut gate = CoherenceGate::with_defaults();
gate.increment_sequence();
let receipt = gate.receipt();
assert!(receipt.is_some());
let receipt = receipt.unwrap();
assert_eq!(receipt.sequence, 1);
}
}