use crate::backend::factored::FactoredBackend;
use crate::backend::statevector::StatevectorBackend;
use crate::backend::Backend;
use crate::circuit::{smallvec, Circuit, ClassicalCondition, Instruction};
use crate::gates::Gate;
use crate::sim;
fn assert_probs_close(actual: &[f64], expected: &[f64], eps: f64) {
assert_eq!(
actual.len(),
expected.len(),
"probability vector length mismatch: got {}, expected {}",
actual.len(),
expected.len()
);
for (i, (a, e)) in actual.iter().zip(expected).enumerate() {
assert!(
(a - e).abs() < eps,
"prob[{i}]: expected {e}, got {a} (diff {})",
(a - e).abs()
);
}
}
fn compare_with_statevector(circuit: &Circuit, eps: f64) {
let mut sv = StatevectorBackend::new(42);
let sv_result = sim::run_on(&mut sv, circuit).unwrap();
let sv_probs = sv_result.probabilities.unwrap().to_vec();
let mut fac = FactoredBackend::new(42);
let fac_result = sim::run_on(&mut fac, circuit).unwrap();
let fac_probs = fac_result.probabilities.unwrap().to_vec();
assert_probs_close(&fac_probs, &sv_probs, eps);
}
#[test]
fn test_x_gate() {
let mut c = Circuit::new(1, 0);
c.add_gate(Gate::X, &[0]);
let mut b = FactoredBackend::new(42);
sim::run_on(&mut b, &c).unwrap();
assert_probs_close(&b.probabilities().unwrap(), &[0.0, 1.0], 1e-12);
}
#[test]
fn test_h_gate() {
let mut c = Circuit::new(1, 0);
c.add_gate(Gate::H, &[0]);
let mut b = FactoredBackend::new(42);
sim::run_on(&mut b, &c).unwrap();
assert_probs_close(&b.probabilities().unwrap(), &[0.5, 0.5], 1e-12);
}
#[test]
fn test_h_on_second_qubit() {
let mut c = Circuit::new(4, 0);
c.add_gate(Gate::H, &[2]);
compare_with_statevector(&c, 1e-10);
}
#[test]
fn test_diagonal_gates() {
let mut c = Circuit::new(2, 0);
c.add_gate(Gate::H, &[0]);
c.add_gate(Gate::T, &[0]);
c.add_gate(Gate::S, &[0]);
c.add_gate(Gate::Z, &[0]);
compare_with_statevector(&c, 1e-10);
}
#[test]
fn test_bell_state() {
let mut c = Circuit::new(2, 0);
c.add_gate(Gate::H, &[0]);
c.add_gate(Gate::Cx, &[0, 1]);
let mut b = FactoredBackend::new(42);
sim::run_on(&mut b, &c).unwrap();
assert_probs_close(&b.probabilities().unwrap(), &[0.5, 0.0, 0.0, 0.5], 1e-12);
}
#[test]
fn test_swap() {
let mut c = Circuit::new(2, 0);
c.add_gate(Gate::X, &[1]);
c.add_gate(Gate::Swap, &[0, 1]);
let mut b = FactoredBackend::new(42);
sim::run_on(&mut b, &c).unwrap();
assert_probs_close(&b.probabilities().unwrap(), &[0.0, 1.0, 0.0, 0.0], 1e-12);
}
#[test]
fn test_cz() {
let mut c = Circuit::new(2, 0);
c.add_gate(Gate::H, &[0]);
c.add_gate(Gate::H, &[1]);
c.add_gate(Gate::Cz, &[0, 1]);
compare_with_statevector(&c, 1e-10);
}
#[test]
fn test_independent_bell_pairs() {
let mut c = Circuit::new(4, 0);
c.add_gate(Gate::H, &[0]);
c.add_gate(Gate::Cx, &[0, 1]);
c.add_gate(Gate::H, &[2]);
c.add_gate(Gate::Cx, &[2, 3]);
compare_with_statevector(&c, 1e-10);
}
#[test]
fn test_independent_groups_stay_separate() {
let mut c = Circuit::new(6, 0);
c.add_gate(Gate::H, &[0]);
c.add_gate(Gate::Cx, &[0, 1]);
c.add_gate(Gate::H, &[2]);
c.add_gate(Gate::Cx, &[2, 3]);
c.add_gate(Gate::X, &[4]);
c.add_gate(Gate::Cx, &[4, 5]);
let mut b = FactoredBackend::new(42);
sim::run_on(&mut b, &c).unwrap();
let active_count = b.substates.iter().filter(|s| s.is_some()).count();
assert_eq!(active_count, 3);
compare_with_statevector(&c, 1e-10);
}
#[test]
fn test_cx_non_adjacent() {
let mut c = Circuit::new(4, 0);
c.add_gate(Gate::H, &[0]);
c.add_gate(Gate::Cx, &[0, 3]); compare_with_statevector(&c, 1e-10);
}
#[test]
fn test_progressive_merge() {
let mut c = Circuit::new(4, 0);
c.add_gate(Gate::H, &[0]);
c.add_gate(Gate::H, &[1]);
c.add_gate(Gate::H, &[2]);
c.add_gate(Gate::H, &[3]);
c.add_gate(Gate::Cx, &[0, 1]); c.add_gate(Gate::Cx, &[2, 3]); c.add_gate(Gate::Cx, &[1, 2]); compare_with_statevector(&c, 1e-10);
}
#[test]
fn test_cu_gate() {
let mut c = Circuit::new(3, 0);
c.add_gate(Gate::H, &[0]);
c.add_gate(Gate::H, &[1]);
let mat = Gate::H.matrix_2x2();
c.add_gate(Gate::Cu(Box::new(mat)), &[0, 2]);
compare_with_statevector(&c, 1e-10);
}
#[test]
fn test_cphase() {
let mut c = Circuit::new(3, 0);
c.add_gate(Gate::H, &[0]);
c.add_gate(Gate::H, &[1]);
c.add_gate(Gate::H, &[2]);
c.add_gate(Gate::cphase(std::f64::consts::FRAC_PI_4), &[0, 1]);
c.add_gate(Gate::cphase(std::f64::consts::FRAC_PI_2), &[1, 2]);
compare_with_statevector(&c, 1e-10);
}
#[test]
fn test_mcu_toffoli() {
use crate::gates::McuData;
let mut c = Circuit::new(3, 0);
c.add_gate(Gate::X, &[0]);
c.add_gate(Gate::X, &[1]);
c.add_gate(
Gate::Mcu(Box::new(McuData {
mat: Gate::X.matrix_2x2(),
num_controls: 2,
})),
&[0, 1, 2],
);
compare_with_statevector(&c, 1e-10);
}
#[test]
fn test_measurement() {
let mut c = Circuit::new(2, 2);
c.add_gate(Gate::X, &[0]);
c.add_measure(0, 0);
c.add_measure(1, 1);
let mut b = FactoredBackend::new(42);
sim::run_on(&mut b, &c).unwrap();
assert!(b.classical_results()[0]); assert!(!b.classical_results()[1]); }
#[test]
fn test_measurement_in_substate() {
let mut c = Circuit::new(4, 1);
c.add_gate(Gate::H, &[0]);
c.add_gate(Gate::Cx, &[0, 1]);
c.add_gate(Gate::X, &[2]); c.add_measure(0, 0);
let mut b = FactoredBackend::new(42);
sim::run_on(&mut b, &c).unwrap();
}
#[test]
fn test_golden_qft_8() {
let circuit = crate::circuits::qft_circuit(8);
compare_with_statevector(&circuit, 1e-10);
}
#[test]
fn test_golden_qft_12() {
let circuit = crate::circuits::qft_circuit(12);
compare_with_statevector(&circuit, 1e-10);
}
#[test]
fn test_golden_random_16() {
let circuit = crate::circuits::random_circuit(16, 10, 42);
compare_with_statevector(&circuit, 1e-10);
}
#[test]
fn test_golden_hea_8() {
let circuit = crate::circuits::hardware_efficient_ansatz(8, 3, 42);
compare_with_statevector(&circuit, 1e-10);
}
#[test]
fn test_golden_bell_pairs() {
let circuit = crate::circuits::independent_bell_pairs(6);
compare_with_statevector(&circuit, 1e-10);
}
#[test]
fn test_golden_independent_blocks() {
let circuit = crate::circuits::independent_random_blocks(4, 3, 5, 42);
compare_with_statevector(&circuit, 1e-10);
}
#[test]
fn test_golden_qpe() {
let circuit = crate::circuits::phase_estimation_circuit(6);
compare_with_statevector(&circuit, 1e-10);
}
#[test]
fn test_single_qubit_circuit() {
let mut c = Circuit::new(1, 0);
c.add_gate(Gate::H, &[0]);
c.add_gate(Gate::T, &[0]);
compare_with_statevector(&c, 1e-10);
}
#[test]
fn test_no_entanglement() {
let mut c = Circuit::new(4, 0);
c.add_gate(Gate::H, &[0]);
c.add_gate(Gate::X, &[1]);
c.add_gate(Gate::S, &[2]);
c.add_gate(Gate::T, &[3]);
compare_with_statevector(&c, 1e-10);
}
#[test]
fn test_immediate_full_merge() {
let mut c = Circuit::new(4, 0);
c.add_gate(Gate::H, &[0]);
c.add_gate(Gate::Cx, &[0, 3]);
c.add_gate(Gate::Cx, &[1, 2]);
c.add_gate(Gate::Cx, &[0, 2]); compare_with_statevector(&c, 1e-10);
}
#[test]
fn test_backend_kind_factored() {
use crate::sim::BackendKind;
let circuit = crate::circuits::independent_bell_pairs(4);
let result = sim::run_with(BackendKind::Factored, &circuit, 42).unwrap();
let probs = result.probabilities.unwrap().to_vec();
assert!((probs.iter().sum::<f64>() - 1.0).abs() < 1e-10);
}
#[test]
fn test_conditional_gate() {
let mut c = Circuit::new(2, 1);
c.add_gate(Gate::X, &[0]);
c.add_measure(0, 0);
c.instructions.push(Instruction::Conditional {
condition: ClassicalCondition::BitIsOne(0),
gate: Gate::X,
targets: smallvec![1],
});
let mut b = FactoredBackend::new(42);
sim::run_on(&mut b, &c).unwrap();
let probs = b.probabilities().unwrap();
assert!((probs[3] - 1.0).abs() < 1e-10); }
#[test]
fn test_factored_parallel_multifused_16q() {
let mut c = Circuit::new(16, 0);
for q in 0..16 {
c.add_gate(Gate::H, &[q]);
}
for q in 0..15 {
c.add_gate(Gate::Cx, &[q, q + 1]);
}
compare_with_statevector(&c, 1e-10);
}
#[test]
fn test_factored_parallel_cx_large_substate_16q() {
let mut c = Circuit::new(16, 0);
for q in 0..15 {
c.add_gate(Gate::Cx, &[q, q + 1]);
}
for q in (0..15).step_by(2) {
c.add_gate(Gate::H, &[q]);
c.add_gate(Gate::Cx, &[q, q + 1]);
}
compare_with_statevector(&c, 1e-10);
}
#[test]
fn test_factored_parallel_measure_16q() {
let mut c = Circuit::new(16, 1);
for q in 0..15 {
c.add_gate(Gate::Cx, &[q, q + 1]);
}
c.add_gate(Gate::X, &[0]);
c.add_measure(0, 0);
let mut fac = FactoredBackend::new(42);
sim::run_on(&mut fac, &c).unwrap();
let bits = fac.classical_results();
assert!(bits[0]);
}