| //! Example: Complete Phase 2 Quantum Backend Setup & Noise Application | |
| //! | |
| //! Demonstrates: | |
| //! 1. Backend contract creation (5-qubit device) | |
| //! 2. Calibration binding with WORM hash | |
| //! 3. Topology queries | |
| //! 4. Noise channel application | |
| //! 5. Trace/PSD verification | |
| use phase2_quantum_backend::backend_contract::*; | |
| use phase2_quantum_backend::noise_channel::*; | |
| use phase2_quantum_backend::topology::*; | |
| use std::collections::{BTreeMap, HashMap}; | |
| use tch::{Device, Kind, Tensor}; | |
| fn main() { | |
| println!("=== Phase 2 Quantum Backend Example ===\n"); | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // STEP 1: Define 5-Qubit Linear Topology | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| println!("Step 1: Create 5-qubit linear topology"); | |
| let mut connectivity = vec![vec![false; 5]; 5]; | |
| for i in 0..5 { | |
| connectivity[i][i] = true; // self-loops | |
| if i + 1 < 5 { | |
| connectivity[i][i + 1] = true; | |
| connectivity[i + 1][i] = true; | |
| } | |
| } | |
| let coupling_graph = CouplingGraph::new(connectivity).unwrap(); | |
| println!("β Linear topology: 0-1-2-3-4\n"); | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // STEP 2: Create Per-Qubit Calibrations | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| println!("Step 2: Create per-qubit calibrations"); | |
| let mut qubit_cals = BTreeMap::new(); | |
| for q in 0..5 { | |
| let cal = QubitCalibration::new( | |
| q, | |
| 5.0 + q as f64 * 0.05, // frequency: 5.0-5.2 GHz | |
| 100.0, // T1: 100 ΞΌs | |
| 50.0, // T2: 50 ΞΌs (T2 < T1 β) | |
| 0.001, // 1-qubit error: 0.1% | |
| 0.01, // 2-qubit error: 1% | |
| 0.02, // readout 0β1: 2% | |
| 0.01, // readout 1β0: 1% | |
| ).unwrap(); | |
| qubit_cals.insert(q, cal); | |
| } | |
| println!("β Calibrated {} qubits\n", qubit_cals.len()); | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // STEP 3: Create Calibration Snapshot with Hash | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| println!("Step 3: Create calibration snapshot (WORM binding)"); | |
| let calibration = CalibrationSnapshot::new( | |
| "ibm_fake_device_5q".to_string(), | |
| 1234567890, | |
| qubit_cals, | |
| BTreeMap::new(), | |
| ).unwrap(); | |
| println!("β Device: {}", calibration.device_id); | |
| println!("β Calibration hash: {}\n", &calibration.calibration_hash[..16]); | |
| let cal_hash = calibration.calibration_hash.clone(); | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // STEP 4: Define Native Gates & Timing | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| println!("Step 4: Define native gates and timing constraints"); | |
| let native_gates = vec![ | |
| NativeGate::H, | |
| NativeGate::X, | |
| NativeGate::Y, | |
| NativeGate::Z, | |
| NativeGate::Rx, | |
| NativeGate::CX, | |
| NativeGate::CZ, | |
| ]; | |
| let timing = TimingConstraints::new( | |
| 10.0, // min gate duration: 10 ns | |
| 100.0, // max gate duration: 100 ns | |
| 200.0, // measurement window: 200 ns | |
| 500.0, // reset time: 500 ns | |
| 10000.0, // coherence limit: 10000 ns (10 ΞΌs) | |
| ).unwrap(); | |
| println!("β Native gates: {:?}", native_gates); | |
| println!("β Timing: [{:.0}, {:.0}] ns\n", 10.0, 100.0); | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // STEP 5: Construct Full Backend Contract | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| println!("Step 5: Construct full backend contract"); | |
| let backend = QuantumBackend::new( | |
| 5, | |
| coupling_graph, | |
| native_gates, | |
| HashMap::new(), | |
| calibration, | |
| timing, | |
| ).unwrap(); | |
| println!("β Backend hash: {}", &backend.backend_hash[..16]); | |
| println!("β Contract validated β\n"); | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // STEP 6: Topology Queries | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| println!("Step 6: Topology analysis"); | |
| let is_linear = TopologyAnalyzer::is_linear(&backend.coupling_graph).unwrap(); | |
| println!("β Is linear: {}", is_linear); | |
| let diameter = TopologyAnalyzer::diameter(&backend.coupling_graph).unwrap(); | |
| println!("β Diameter: {}", diameter); | |
| let path = TopologyAnalyzer::shortest_path(&backend.coupling_graph, 0, 4).unwrap(); | |
| println!("β Shortest path (0β4): {:?}", path); | |
| let avg_degree = TopologyAnalyzer::average_degree(&backend.coupling_graph).unwrap(); | |
| println!("β Average degree: {:.2}\n", avg_degree); | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // STEP 7: Apply Noise Channels | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| println!("Step 7: Apply noise channels"); | |
| // Create maximally mixed initial state | |
| let rho_init = Tensor::eye(2, (Kind::Double, Device::Cpu)) * 0.5; | |
| println!("β Initial state: maximally mixed I/2"); | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // 7a. Depolarizing noise | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| let depo_channel = DepolarizingChannel::new(0.01).unwrap(); | |
| let rho_depo = depo_channel.apply(&rho_init).unwrap(); | |
| let trace_depo: f64 = rho_depo.trace().double_value(&[]); | |
| println!("\n7a. Depolarizing (p=0.01):"); | |
| println!(" Trace: {:.15}", trace_depo); | |
| println!(" β Trace β 1 (error: {:.2e})", (trace_depo - 1.0).abs()); | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // 7b. Amplitude damping | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| let amp_channel = AmplitudeDampingChannel::new(0.05).unwrap(); | |
| let rho_amp = amp_channel.apply(&rho_init).unwrap(); | |
| let trace_amp: f64 = rho_amp.trace().double_value(&[]); | |
| println!("\n7b. Amplitude damping (Ξ³=0.05):"); | |
| println!(" Trace: {:.15}", trace_amp); | |
| println!(" β Trace β 1 (error: {:.2e})", (trace_amp - 1.0).abs()); | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // 7c. Phase damping | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| let phase_channel = PhaseDampingChannel::new(0.03).unwrap(); | |
| let rho_phase = phase_channel.apply(&rho_init).unwrap(); | |
| let trace_phase: f64 = rho_phase.trace().double_value(&[]); | |
| println!("\n7c. Phase damping (Ξ³=0.03):"); | |
| println!(" Trace: {:.15}", trace_phase); | |
| println!(" β Trace β 1 (error: {:.2e})", (trace_phase - 1.0).abs()); | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // 7d. Readout error | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| let readout_channel = ReadoutErrorChannel::new(0.02, 0.01).unwrap(); | |
| let rho_readout = readout_channel.apply(&rho_init).unwrap(); | |
| let trace_readout: f64 = rho_readout.trace().double_value(&[]); | |
| println!("\n7d. Readout error (p_01=0.02, p_10=0.01):"); | |
| println!(" Trace: {:.15}", trace_readout); | |
| println!(" β Trace β 1 (error: {:.2e})", (trace_readout - 1.0).abs()); | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // 7e. Pauli channel | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| let pauli_channel = PauliChannel::new(0.01, 0.01, 0.02).unwrap(); | |
| let rho_pauli = pauli_channel.apply(&rho_init).unwrap(); | |
| let trace_pauli: f64 = rho_pauli.trace().double_value(&[]); | |
| println!("\n7e. Pauli channel (px=0.01, py=0.01, pz=0.02):"); | |
| println!(" Trace: {:.15}", trace_pauli); | |
| println!(" β Trace β 1 (error: {:.2e})", (trace_pauli - 1.0).abs()); | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // STEP 8: Verify PSD (Positive Semi-Definiteness) | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| println!("\n\nStep 8: Verify positive semi-definiteness"); | |
| let verify_psd = |name: &str, rho: &Tensor| { | |
| let (evals, _) = rho.linalg_eigh("L"); | |
| let min_eval: f64 = evals.min().double_value(&[]); | |
| println!("{}: min eigenvalue = {:.2e}", name, min_eval); | |
| assert!( | |
| min_eval >= -1e-10, | |
| "PSD violated for {}", | |
| name | |
| ); | |
| println!(" β PSD preserved"); | |
| }; | |
| verify_psd("Depolarizing", &rho_depo); | |
| verify_psd("Amplitude damping", &rho_amp); | |
| verify_psd("Phase damping", &rho_phase); | |
| verify_psd("Readout error", &rho_readout); | |
| verify_psd("Pauli", &rho_pauli); | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // STEP 9: Verify Kraus Trace Preservation | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| println!("\n\nStep 9: Verify Kraus trace preservation (Ξ£ E_kβ E_k = I)"); | |
| depo_channel.verify_trace_preservation().unwrap(); | |
| println!("β Depolarizing: Ξ£ E_kβ E_k = I"); | |
| amp_channel.verify_trace_preservation().unwrap(); | |
| println!("β Amplitude damping: Ξ£ E_kβ E_k = I"); | |
| phase_channel.verify_trace_preservation().unwrap(); | |
| println!("β Phase damping: Ξ£ E_kβ E_k = I"); | |
| readout_channel.verify_trace_preservation().unwrap(); | |
| println!("β Readout error: Ξ£ E_kβ E_k = I"); | |
| pauli_channel.verify_trace_preservation().unwrap(); | |
| println!("β Pauli channel: Ξ£ E_kβ E_k = I"); | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // SUMMARY | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| println!("\n\n=== Summary ==="); | |
| println!("β Backend contract created & validated"); | |
| println!("β Calibration snapshot: {} hash", &cal_hash[..16]); | |
| println!("β Topology: {} qubits, linear path", 5); | |
| println!("β All 5 noise channels working"); | |
| println!("β Trace preservation: 100%"); | |
| println!("β PSD preservation: 100%"); | |
| println!("β Kraus trace condition: All verified β"); | |
| println!("\n=== Phase 2 Complete ==="); | |
| } | |