File size: 13,877 Bytes
9425aed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
//! 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 ===");
}