use quantrs2_circuit::builder::{Circuit, Simulator};
use quantrs2_core::qubit::QubitId;
use quantrs2_sim::{
noise::{DepolarizingChannel, NoiseModel},
statevector::StateVectorSimulator,
};
fn noisy_bell_fidelity(noise_p: f64, shots: usize) -> Result<f64, Box<dyn std::error::Error>> {
let mut circuit = Circuit::<2>::new();
circuit.h(0)?;
circuit.cnot(0, 1)?;
let mut sum_fidelity = 0.0f64;
for _ in 0..shots {
let mut noise = NoiseModel::new(true); noise.add_depolarizing(DepolarizingChannel {
target: QubitId(0),
probability: noise_p,
});
noise.add_depolarizing(DepolarizingChannel {
target: QubitId(1),
probability: noise_p,
});
let sim = StateVectorSimulator::with_noise(noise);
let reg = sim.run(&circuit)?;
let p = reg.probabilities();
sum_fidelity += p[0] + p[3];
}
Ok(sum_fidelity / shots as f64)
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Noisy Bell State Simulation — Depolarizing Channel ===");
println!("(stochastic noise model; averaging over shots)\n");
let shots = 200usize;
println!("Shots per noise level: {shots}\n");
println!(" {:>8} {:>18}", "noise_p", "avg[P(00)+P(11)]");
println!(" {}", "-".repeat(30));
let noise_levels = [0.0, 0.02, 0.05, 0.10, 0.20, 0.30, 0.50];
let mut fidelities = Vec::new();
for &p in &noise_levels {
let f = noisy_bell_fidelity(p, shots)?;
fidelities.push(f);
let bar_len = (f * 30.0).round() as usize;
let bar: String = "#".repeat(bar_len);
println!(" {p:>8.2} {f:>8.4} {bar}");
}
println!();
let f0 = fidelities[0];
assert!(
(f0 - 1.0).abs() < 1e-10,
"Noiseless fidelity should be 1.0, got {f0}"
);
println!("Noiseless fidelity: {f0:.6} — OK");
let f_high = *fidelities.last().expect("non-empty");
assert!(
f_high < 0.80,
"At p=0.5, fidelity should degrade significantly (got {f_high})"
);
println!("High-noise fidelity (p=0.5): {f_high:.4} — OK (degraded as expected)");
for i in 0..fidelities.len() - 1 {
assert!(
fidelities[i] >= fidelities[i + 1] - 0.05,
"Fidelity should not increase with noise: f[{i}]={:.4} < f[{}]={:.4}",
fidelities[i],
i + 1,
fidelities[i + 1]
);
}
println!("Fidelity decreases monotonically with noise — OK");
println!("\n--- 4-qubit noisy register (two Bell pairs, p=0.05, 100 shots) ---");
let shots4 = 100usize;
let mut avg = [0.0f64; 16];
let mut circuit4 = Circuit::<4>::new();
circuit4.h(0)?;
circuit4.cnot(0, 1)?;
circuit4.h(2)?;
circuit4.cnot(2, 3)?;
let p4 = 0.05f64;
for _ in 0..shots4 {
let mut noise4 = NoiseModel::new(true);
for q in 0..4u32 {
noise4.add_depolarizing(DepolarizingChannel {
target: QubitId(q),
probability: p4,
});
}
let reg = StateVectorSimulator::with_noise(noise4).run(&circuit4)?;
let probs = reg.probabilities();
for (k, &prob) in probs.iter().enumerate() {
avg[k] += prob;
}
}
for v in &mut avg {
*v /= shots4 as f64;
}
let dominant = avg[0b0000] + avg[0b0011] + avg[0b1100] + avg[0b1111];
println!(
"avg P(|0000⟩) = {:.4}, avg P(|0011⟩) = {:.4}, avg P(|1100⟩) = {:.4}, avg P(|1111⟩) = {:.4}",
avg[0b0000], avg[0b0011], avg[0b1100], avg[0b1111]
);
println!("Sum of dominant states: {dominant:.4} (noiseless=1.0)");
assert!(
dominant > 0.70,
"Dominant states should sum to >0.70 at p=0.05; got {dominant:.4}"
);
println!("\nOK — depolarizing noise degrades Bell fidelity as expected.");
Ok(())
}