#[cfg(feature = "mps")]
use quantrs2_core::gate::{multi::CNOT, single::Hadamard};
#[cfg(feature = "mps")]
use quantrs2_core::qubit::QubitId;
#[cfg(feature = "mps")]
use quantrs2_sim::mps_enhanced::{EnhancedMPS, MPSConfig};
#[cfg(feature = "mps")]
use std::time::Instant;
#[cfg(feature = "mps")]
fn build_ghz_mps(n: usize, config: MPSConfig) -> Result<EnhancedMPS, Box<dyn std::error::Error>> {
let mut mps = EnhancedMPS::new(n, config);
mps.apply_gate(&Hadamard { target: QubitId(0) })?;
for i in 0..(n - 1) {
mps.apply_gate(&CNOT {
control: QubitId(i as u32),
target: QubitId((i + 1) as u32),
})?;
}
Ok(mps)
}
#[cfg(feature = "mps")]
fn run() -> Result<(), Box<dyn std::error::Error>> {
println!("=== 20-Qubit GHZ State via MPS Simulator ===\n");
let n = 20usize;
let config = MPSConfig {
max_bond_dim: 4, svd_threshold: 1e-12,
use_randomized_svd: false, auto_canonicalize: false, seed: None,
};
let start = Instant::now();
let mut mps = build_ghz_mps(n, config.clone())?;
let elapsed = start.elapsed();
println!("Qubits : {n}");
println!("Runtime: {elapsed:.2?}");
let mps_approx_bytes = n * 2 * 2 * 16; let sv_bytes = (1usize << n) * 16; println!("MPS memory : ≈ {mps_approx_bytes} bytes");
println!(
"SV memory : ≈ {} MB (infeasible on most machines)",
sv_bytes / (1024 * 1024)
);
let all_zeros: Vec<bool> = vec![false; n];
let all_ones: Vec<bool> = vec![true; n];
let amp0 = mps.get_amplitude(&all_zeros)?;
let amp1 = mps.get_amplitude(&all_ones)?;
let p0 = amp0.norm_sqr();
let p1 = amp1.norm_sqr();
println!("\nAmplitudes:");
println!(" |{:0>20}⟩ : |amp|² = {p0:.6} (expected 0.5)", 0);
println!(" |{:1>20}⟩ : |amp|² = {p1:.6} (expected 0.5)", 1);
let entropy = mps.entanglement_entropy(n / 2)?;
println!(
"\nEntanglement entropy (cut at qubit {}): {entropy:.6} (expected ln2 ≈ 0.6931)",
n / 2
);
let bonds = mps.bond_dimensions();
let max_bond = mps.max_bond_dimension();
println!("\nBond dimensions: {bonds:?}");
println!("Max bond dim : {max_bond} (χ=2 is exact for GHZ)");
println!("\n--- GHZ scaling ---");
println!(
" {:>4} {:>12} {:>12} {:>14}",
"N", "runtime", "MPS mem (B)", "SV mem (MB)"
);
for &n_small in &[5usize, 8, 10, 12] {
let t = Instant::now();
let _m = build_ghz_mps(n_small, config.clone())?;
let dur = t.elapsed();
let mps_b = n_small * 2 * 2 * 16;
let sv_mb = (1usize << n_small) * 16 / (1024 * 1024);
println!(" {n_small:>4} {dur:>12.2?} {mps_b:>12} {sv_mb:>14}");
}
assert!(
(p0 - 0.5).abs() < 1e-5,
"GHZ |0..0⟩ probability should be 0.5; got {p0}"
);
assert!(
(p1 - 0.5).abs() < 1e-5,
"GHZ |1..1⟩ probability should be 0.5; got {p1}"
);
assert!(
(entropy - std::f64::consts::LN_2).abs() < 0.05,
"Entanglement entropy should be ln(2) ≈ 0.6931; got {entropy}"
);
println!("\nOK — 20-qubit GHZ state verified via MPS simulator.");
Ok(())
}
fn main() {
#[cfg(feature = "mps")]
run().expect("mps_ghz example failed");
#[cfg(not(feature = "mps"))]
{
println!("This example requires the 'mps' feature.");
println!("Run with: cargo run --example mps_ghz -p quantrs2-sim --features mps");
}
}