use super::*;
use crate::circuit::{Qubit, StandardGate};
use crate::qis::hamiltonian::Hamiltonian;
use crate::qis::pauli::{Pauli, PauliString};
use num_complex::Complex64;
use std::f64::consts::{FRAC_1_SQRT_2, PI};
const EPSILON: f64 = 1e-10;
fn c(re: f64, im: f64) -> Complex64 {
Complex64::new(re, im)
}
fn assert_complex_eq(a: Complex64, b: Complex64, msg: &str) {
assert!(
(a - b).norm() < EPSILON,
"{}: expected {:?}, got {:?}, diff = {:?}",
msg,
b,
a,
(a - b).norm()
);
}
fn assert_normalized(sv: &Statevector) {
let norm: f64 = sv.data.iter().map(|c| c.norm_sqr()).sum();
assert!(
(norm - 1.0).abs() < EPSILON,
"Statevector not normalized: norm = {}",
norm
);
}
#[test]
fn test_new_initialization() {
let sv = Statevector::new(3);
assert_eq!(sv.num_qubits, 3);
assert_eq!(sv.data.len(), 8);
assert_complex_eq(sv.data[0], c(1.0, 0.0), "First element should be |000⟩");
for i in 1..8 {
assert_complex_eq(
sv.data[i],
c(0.0, 0.0),
&format!("Element {} should be 0", i),
);
}
}
#[test]
fn test_probabilities() {
let mut sv = Statevector::new(2);
let h_matrix = [
[c(FRAC_1_SQRT_2, 0.0), c(FRAC_1_SQRT_2, 0.0)],
[c(FRAC_1_SQRT_2, 0.0), c(-FRAC_1_SQRT_2, 0.0)],
];
sv.apply_single_qubit_gate(0, h_matrix).unwrap();
let probs = sv.probabilities();
assert_eq!(probs.len(), 4);
assert!((probs[0] - 0.5).abs() < EPSILON, "P(|00⟩) should be 0.5");
assert!((probs[1] - 0.5).abs() < EPSILON, "P(|01⟩) should be 0.5");
assert!(probs[2].abs() < EPSILON, "P(|10⟩) should be 0");
assert!(probs[3].abs() < EPSILON, "P(|11⟩) should be 0");
}
#[test]
fn test_apply_x() {
let mut sv = Statevector::new(1);
sv.apply_x(0).unwrap();
assert_complex_eq(sv.data[0], c(0.0, 0.0), "X|0⟩[0] should be 0");
assert_complex_eq(sv.data[1], c(1.0, 0.0), "X|0⟩[1] should be 1");
let mut sv2 = Statevector::new(2);
sv2.apply_x(0).unwrap();
sv2.apply_x(0).unwrap();
assert_complex_eq(sv2.data[0], c(1.0, 0.0), "XX|00⟩ should be |00⟩");
let mut sv3 = Statevector::new(2);
sv3.apply_x(1).unwrap(); assert_complex_eq(sv3.data[0], c(0.0, 0.0), "X[1]|00⟩[0] should be 0");
assert_complex_eq(sv3.data[1], c(0.0, 0.0), "X[1]|00⟩[1] should be 0");
assert_complex_eq(sv3.data[2], c(1.0, 0.0), "X[1]|00⟩[2] should be 1");
assert_complex_eq(sv3.data[3], c(0.0, 0.0), "X[1]|00⟩[3] should be 0");
}
#[test]
fn test_apply_y() {
let mut sv = Statevector::new(1);
sv.apply_y(0).unwrap();
assert_complex_eq(sv.data[0], c(0.0, 0.0), "Y|0⟩[0] should be 0");
assert_complex_eq(sv.data[1], c(0.0, 1.0), "Y|0⟩[1] should be i");
let mut sv2 = Statevector::new(1);
for _ in 0..4 {
sv2.apply_y(0).unwrap();
}
assert_complex_eq(sv2.data[0], c(1.0, 0.0), "Y^4|0⟩ should be |0⟩");
assert_complex_eq(sv2.data[1], c(0.0, 0.0), "Y^4|0⟩[1] should be 0");
}
#[test]
fn test_apply_z() {
let mut sv = Statevector::new(1);
sv.apply_z(0).unwrap();
assert_complex_eq(sv.data[0], c(1.0, 0.0), "Z|0⟩ should be |0⟩");
assert_complex_eq(sv.data[1], c(0.0, 0.0), "Z|0⟩[1] should be 0");
let mut sv2 = Statevector::new(1);
sv2.apply_x(0).unwrap();
sv2.apply_z(0).unwrap();
assert_complex_eq(sv2.data[0], c(0.0, 0.0), "ZX|0⟩[0] should be 0");
assert_complex_eq(sv2.data[1], c(-1.0, 0.0), "ZX|0⟩ should be -|1⟩");
let mut sv3 = Statevector::new(2);
sv3.apply_x(0).unwrap();
sv3.apply_z(0).unwrap();
sv3.apply_z(0).unwrap();
assert_complex_eq(sv3.data[1], c(1.0, 0.0), "Z^2|01⟩ should be |01⟩");
}
#[test]
fn test_apply_hadamard() {
let h_matrix = [
[c(FRAC_1_SQRT_2, 0.0), c(FRAC_1_SQRT_2, 0.0)],
[c(FRAC_1_SQRT_2, 0.0), c(-FRAC_1_SQRT_2, 0.0)],
];
let mut sv = Statevector::new(1);
sv.apply_single_qubit_gate(0, h_matrix).unwrap();
assert_complex_eq(sv.data[0], c(FRAC_1_SQRT_2, 0.0), "H|0⟩[0] should be 1/√2");
assert_complex_eq(sv.data[1], c(FRAC_1_SQRT_2, 0.0), "H|0⟩[1] should be 1/√2");
let mut sv2 = Statevector::new(1);
sv2.apply_x(0).unwrap();
sv2.apply_single_qubit_gate(0, h_matrix).unwrap();
assert_complex_eq(sv2.data[0], c(FRAC_1_SQRT_2, 0.0), "H|1⟩[0] should be 1/√2");
assert_complex_eq(
sv2.data[1],
c(-FRAC_1_SQRT_2, 0.0),
"H|1⟩[1] should be -1/√2",
);
let mut sv3 = Statevector::new(1);
sv3.apply_single_qubit_gate(0, h_matrix).unwrap();
sv3.apply_single_qubit_gate(0, h_matrix).unwrap();
assert_complex_eq(sv3.data[0], c(1.0, 0.0), "H^2|0⟩ should be |0⟩");
assert_complex_eq(sv3.data[1], c(0.0, 0.0), "H^2|0⟩[1] should be 0");
}
#[test]
fn test_apply_s_gate() {
let mut sv = Statevector::new(1);
sv.apply_s(0).unwrap();
assert_complex_eq(sv.data[0], c(1.0, 0.0), "S|0⟩ should be |0⟩");
let mut sv2 = Statevector::new(1);
sv2.apply_x(0).unwrap();
sv2.apply_s(0).unwrap();
assert_complex_eq(sv2.data[1], c(0.0, 1.0), "S|1⟩ should be i|1⟩");
let mut sv3 = Statevector::new(1);
sv3.apply_x(0).unwrap();
sv3.apply_s(0).unwrap();
sv3.apply_s(0).unwrap();
assert_complex_eq(sv3.data[1], c(-1.0, 0.0), "S^2|1⟩ should be -|1⟩");
}
#[test]
fn test_apply_t_gate() {
let mut sv = Statevector::new(1);
sv.apply_t(0).unwrap();
assert_complex_eq(sv.data[0], c(1.0, 0.0), "T|0⟩ should be |0⟩");
let mut sv2 = Statevector::new(1);
sv2.apply_x(0).unwrap();
sv2.apply_t(0).unwrap();
let expected_phase = c(FRAC_1_SQRT_2, FRAC_1_SQRT_2);
assert_complex_eq(sv2.data[1], expected_phase, "T|1⟩ should be e^(iπ/4)|1⟩");
let mut sv3 = Statevector::new(1);
sv3.apply_x(0).unwrap();
sv3.apply_t(0).unwrap();
sv3.apply_t(0).unwrap();
assert_complex_eq(sv3.data[1], c(0.0, 1.0), "T^2|1⟩ should be i|1⟩ = S|1⟩");
}
#[test]
fn test_apply_rx() {
let mut sv = Statevector::new(1);
sv.apply_rx(0, PI).unwrap();
assert_complex_eq(sv.data[0], c(0.0, 0.0), "Rx(π)|0⟩[0] should be 0");
assert_complex_eq(sv.data[1], c(0.0, -1.0), "Rx(π)|0⟩ should be -i|1⟩");
let mut sv2 = Statevector::new(1);
sv2.apply_rx(0, 2.0 * PI).unwrap();
assert_complex_eq(sv2.data[0], c(-1.0, 0.0), "Rx(2π)|0⟩ should be -|0⟩");
let mut sv3 = Statevector::new(1);
sv3.apply_rx(0, 0.0).unwrap();
assert_complex_eq(sv3.data[0], c(1.0, 0.0), "Rx(0)|0⟩ should be |0⟩");
}
#[test]
fn test_apply_ry() {
let mut sv = Statevector::new(1);
sv.apply_ry(0, PI).unwrap();
assert_complex_eq(sv.data[0], c(0.0, 0.0), "Ry(π)|0⟩[0] should be 0");
assert_complex_eq(sv.data[1], c(1.0, 0.0), "Ry(π)|0⟩ should be |1⟩");
let mut sv2 = Statevector::new(1);
sv2.apply_ry(0, PI / 2.0).unwrap();
assert_complex_eq(
sv2.data[0],
c(FRAC_1_SQRT_2, 0.0),
"Ry(π/2)|0⟩[0] should be 1/√2",
);
assert_complex_eq(
sv2.data[1],
c(FRAC_1_SQRT_2, 0.0),
"Ry(π/2)|0⟩[1] should be 1/√2",
);
}
#[test]
fn test_apply_rz() {
let mut sv = Statevector::new(1);
sv.apply_rz(0, PI).unwrap();
assert_complex_eq(sv.data[0], c(0.0, -1.0), "Rz(π)|0⟩ should be -i|0⟩");
let mut sv2 = Statevector::new(1);
sv2.apply_x(0).unwrap();
sv2.apply_rz(0, PI).unwrap();
assert_complex_eq(sv2.data[1], c(0.0, 1.0), "Rz(π)|1⟩ should be i|1⟩");
let mut sv3 = Statevector::new(1);
sv3.apply_rz(0, 2.0 * PI).unwrap();
assert_complex_eq(sv3.data[0], c(-1.0, 0.0), "Rz(2π)|0⟩ should be -|0⟩");
}
#[test]
fn test_y2p_y2m() {
let mut sv1 = Statevector::new(1);
sv1.apply_y2p(0).unwrap();
let mut sv2 = Statevector::new(1);
sv2.apply_ry(0, PI / 2.0).unwrap();
assert_complex_eq(sv1.data[0], sv2.data[0], "Y2P[0] should equal Ry(Ï€/2)[0]");
assert_complex_eq(sv1.data[1], sv2.data[1], "Y2P[1] should equal Ry(Ï€/2)[1]");
let mut sv3 = Statevector::new(1);
sv3.apply_y2p(0).unwrap();
sv3.apply_y2m(0).unwrap();
assert_complex_eq(sv3.data[0], c(1.0, 0.0), "Y2P * Y2M should be I");
}
#[test]
fn test_x2p_x2m() {
let mut sv1 = Statevector::new(1);
sv1.apply_x2p(0).unwrap();
let mut sv2 = Statevector::new(1);
sv2.apply_rx(0, PI / 2.0).unwrap();
assert_complex_eq(sv1.data[0], sv2.data[0], "X2P[0] should equal Rx(Ï€/2)[0]");
assert_complex_eq(sv1.data[1], sv2.data[1], "X2P[1] should equal Rx(Ï€/2)[1]");
let mut sv3 = Statevector::new(1);
sv3.apply_x2p(0).unwrap();
sv3.apply_x2m(0).unwrap();
assert_complex_eq(sv3.data[0], c(1.0, 0.0), "X2P * X2M should be I");
}
#[test]
fn test_apply_p_gate() {
let mut sv1 = Statevector::new(1);
sv1.apply_phase(0, 0.0).unwrap();
assert_complex_eq(sv1.data[0], c(1.0, 0.0), "P(0)|0⟩ should be |0⟩");
let mut sv2 = Statevector::new(1);
sv2.apply_x(0).unwrap();
sv2.apply_phase(0, PI).unwrap();
assert_complex_eq(sv2.data[1], c(-1.0, 0.0), "P(π)|1⟩ should be -|1⟩");
let mut sv3 = Statevector::new(1);
sv3.apply_x(0).unwrap();
sv3.apply_phase(0, PI / 2.0).unwrap();
assert_complex_eq(sv3.data[1], c(0.0, 1.0), "P(π/2)|1⟩ should be i|1⟩");
}
#[test]
fn test_cx_control_lt_target() {
let mut sv = Statevector::new(2);
sv.apply_x(1).unwrap(); sv.apply_cx(0, 1).unwrap();
assert_complex_eq(sv.data[2], c(1.0, 0.0), "CX(0,1)|10⟩ should be |10⟩");
let mut sv2 = Statevector::new(2);
sv2.apply_x(0).unwrap(); sv2.apply_cx(0, 1).unwrap();
assert_complex_eq(sv2.data[0], c(0.0, 0.0), "CX(0,1)|01⟩[0] should be 0");
assert_complex_eq(sv2.data[1], c(0.0, 0.0), "CX(0,1)|01⟩[1] should be 0");
assert_complex_eq(sv2.data[2], c(0.0, 0.0), "CX(0,1)|01⟩[2] should be 0");
assert_complex_eq(sv2.data[3], c(1.0, 0.0), "CX(0,1)|01⟩ should be |11⟩");
}
#[test]
fn test_cx_control_gt_target() {
let mut sv = Statevector::new(2);
sv.apply_x(0).unwrap(); sv.apply_cx(1, 0).unwrap();
assert_complex_eq(sv.data[1], c(1.0, 0.0), "CX(1,0)|01⟩ should be |01⟩");
let mut sv2 = Statevector::new(2);
sv2.apply_x(1).unwrap(); sv2.apply_cx(1, 0).unwrap();
assert_complex_eq(sv2.data[3], c(1.0, 0.0), "CX(1,0)|10⟩ should be |11⟩");
}
#[test]
fn test_cx_bell_state() {
let mut sv = Statevector::new(2);
let h_matrix = [
[c(FRAC_1_SQRT_2, 0.0), c(FRAC_1_SQRT_2, 0.0)],
[c(FRAC_1_SQRT_2, 0.0), c(-FRAC_1_SQRT_2, 0.0)],
];
sv.apply_single_qubit_gate(0, h_matrix).unwrap();
sv.apply_cx(0, 1).unwrap();
assert_complex_eq(sv.data[0], c(FRAC_1_SQRT_2, 0.0), "Bell state |00⟩ amp");
assert_complex_eq(sv.data[1], c(0.0, 0.0), "Bell state |01⟩ amp should be 0");
assert_complex_eq(sv.data[2], c(0.0, 0.0), "Bell state |10⟩ amp should be 0");
assert_complex_eq(sv.data[3], c(FRAC_1_SQRT_2, 0.0), "Bell state |11⟩ amp");
assert_normalized(&sv);
}
#[test]
fn test_cx_cx_identity() {
let mut sv = Statevector::new(2);
sv.apply_x(0).unwrap();
sv.apply_cx(0, 1).unwrap();
sv.apply_cx(0, 1).unwrap();
assert_complex_eq(sv.data[1], c(1.0, 0.0), "CX^2 should be I");
}
#[test]
fn test_cz_symmetric() {
let mut sv1 = Statevector::new(2);
sv1.apply_x(0).unwrap();
sv1.apply_x(1).unwrap();
sv1.apply_cz(0, 1).unwrap();
let mut sv2 = Statevector::new(2);
sv2.apply_x(0).unwrap();
sv2.apply_x(1).unwrap();
sv2.apply_cz(1, 0).unwrap();
assert_complex_eq(sv1.data[3], sv2.data[3], "CZ should be symmetric");
assert_complex_eq(sv1.data[3], c(-1.0, 0.0), "CZ|11⟩ should be -|11⟩");
}
#[test]
fn test_cz_phases() {
for i in 0..4 {
let mut sv = Statevector::new(2);
if i & 1 != 0 {
sv.apply_x(0).unwrap();
}
if i & 2 != 0 {
sv.apply_x(1).unwrap();
}
sv.apply_cz(0, 1).unwrap();
let expected_phase = if i == 3 { c(-1.0, 0.0) } else { c(1.0, 0.0) };
assert_complex_eq(sv.data[i], expected_phase, &format!("CZ|{:02b}⟩", i));
}
}
#[test]
fn test_swap() {
let mut sv = Statevector::new(2);
sv.apply_x(0).unwrap(); sv.apply_swap(0, 1).unwrap();
assert_complex_eq(sv.data[2], c(1.0, 0.0), "SWAP|01⟩ should be |10⟩");
let mut sv2 = Statevector::new(2);
sv2.apply_x(1).unwrap(); sv2.apply_swap(0, 1).unwrap();
assert_complex_eq(sv2.data[1], c(1.0, 0.0), "SWAP|10⟩ should be |01⟩");
let mut sv3 = Statevector::new(2);
sv3.apply_x(0).unwrap();
sv3.apply_x(1).unwrap(); sv3.apply_swap(0, 1).unwrap();
assert_complex_eq(sv3.data[3], c(1.0, 0.0), "SWAP|11⟩ should be |11⟩");
let mut sv4 = Statevector::new(2);
sv4.apply_x(0).unwrap();
sv4.apply_swap(0, 1).unwrap();
sv4.apply_swap(0, 1).unwrap();
assert_complex_eq(sv4.data[1], c(1.0, 0.0), "SWAP^2 should be I");
}
#[test]
#[should_panic(expected = "InvalidParameterValue")]
fn test_swap_same_qubit() {
let mut sv = Statevector::new(2);
sv.apply_x(0).unwrap();
sv.apply_swap(0, 0).unwrap();
}
#[test]
fn test_cy() {
let mut sv = Statevector::new(2);
sv.apply_x(0).unwrap();
sv.apply_x(1).unwrap(); sv.apply_cy(0, 1).unwrap();
assert_complex_eq(sv.data[3], c(0.0, 0.0), "CY|11⟩[11] should be 0");
assert_complex_eq(sv.data[1], c(0.0, -1.0), "CY(0,1)|11⟩ should be -i|01⟩");
let mut sv3 = Statevector::new(2);
sv3.apply_x(0).unwrap(); sv3.apply_cy(0, 1).unwrap();
assert_complex_eq(sv3.data[3], c(0.0, 1.0), "CY(0,1)|01⟩ should be i|11⟩");
let mut sv2 = Statevector::new(2);
sv2.apply_x(1).unwrap(); sv2.apply_cy(0, 1).unwrap();
assert_complex_eq(sv2.data[2], c(1.0, 0.0), "CY|10⟩ should be unchanged");
}
#[test]
fn test_cy_control_gt_target() {
let mut sv = Statevector::new(2);
sv.apply_x(1).unwrap(); sv.apply_cy(1, 0).unwrap();
assert_complex_eq(sv.data[3], c(0.0, 1.0), "CY(1,0)|10⟩ should be i|11⟩");
}
#[test]
fn test_double_qubit_gate_cnot() {
let cnot_matrix = [
[c(1.0, 0.0), c(0.0, 0.0), c(0.0, 0.0), c(0.0, 0.0)],
[c(0.0, 0.0), c(1.0, 0.0), c(0.0, 0.0), c(0.0, 0.0)],
[c(0.0, 0.0), c(0.0, 0.0), c(0.0, 0.0), c(1.0, 0.0)],
[c(0.0, 0.0), c(0.0, 0.0), c(1.0, 0.0), c(0.0, 0.0)],
];
let mut sv1 = Statevector::new(2);
sv1.apply_x(0).unwrap(); sv1.apply_two_qubit_gate(0, 1, cnot_matrix).unwrap();
assert_complex_eq(
sv1.data[3],
c(1.0, 0.0),
"CNOT matrix (0,1)|01⟩ should be |11⟩",
);
let mut sv2 = Statevector::new(2);
sv2.apply_x(1).unwrap(); sv2.apply_two_qubit_gate(1, 0, cnot_matrix).unwrap();
assert_complex_eq(
sv2.data[3],
c(1.0, 0.0),
"CNOT matrix (1,0)|10⟩ should be |11⟩",
);
}
#[test]
fn test_three_qubit_cx() {
let mut sv = Statevector::new(3);
sv.apply_x(0).unwrap(); sv.apply_cx(0, 2).unwrap();
assert_complex_eq(sv.data[5], c(1.0, 0.0), "CX(0,2)|001⟩ should be |101⟩");
let mut sv2 = Statevector::new(3);
sv2.apply_x(2).unwrap(); sv2.apply_cx(2, 0).unwrap();
assert_complex_eq(sv2.data[5], c(1.0, 0.0), "CX(2,0)|100⟩ should be |101⟩");
}
#[test]
fn test_three_qubit_swap() {
let mut sv = Statevector::new(3);
sv.apply_x(0).unwrap(); sv.apply_swap(0, 2).unwrap();
assert_complex_eq(sv.data[4], c(1.0, 0.0), "SWAP(0,2)|001⟩ should be |100⟩");
}
#[test]
fn test_ghz_state() {
let mut sv = Statevector::new(3);
let h_matrix = [
[c(FRAC_1_SQRT_2, 0.0), c(FRAC_1_SQRT_2, 0.0)],
[c(FRAC_1_SQRT_2, 0.0), c(-FRAC_1_SQRT_2, 0.0)],
];
sv.apply_single_qubit_gate(0, h_matrix).unwrap();
sv.apply_cx(0, 1).unwrap();
sv.apply_cx(0, 2).unwrap();
assert_complex_eq(sv.data[0], c(FRAC_1_SQRT_2, 0.0), "GHZ |000⟩ amp");
assert_complex_eq(sv.data[7], c(FRAC_1_SQRT_2, 0.0), "GHZ |111⟩ amp");
for i in 1..7 {
assert_complex_eq(
sv.data[i],
c(0.0, 0.0),
&format!("GHZ |{:03b}⟩ should be 0", i),
);
}
assert_normalized(&sv);
}
#[test]
#[should_panic(expected = "IndexOutOfBounds")]
fn test_single_qubit_out_of_bounds() {
let mut sv = Statevector::new(2); let h_matrix = [
[c(FRAC_1_SQRT_2, 0.0), c(FRAC_1_SQRT_2, 0.0)],
[c(FRAC_1_SQRT_2, 0.0), c(-FRAC_1_SQRT_2, 0.0)],
];
sv.apply_single_qubit_gate(2, h_matrix).unwrap();
}
#[test]
#[should_panic(expected = "InvalidParameterValue")]
fn test_cx_same_qubit() {
let mut sv = Statevector::new(2);
sv.apply_cx(0, 0).unwrap();
}
#[test]
#[should_panic(expected = "InvalidParameterValue")]
fn test_cy_same_qubit() {
let mut sv = Statevector::new(2);
sv.apply_cy(0, 0).unwrap();
}
#[test]
#[should_panic(expected = "InvalidParameterValue")]
fn test_cz_same_qubit() {
let mut sv = Statevector::new(2);
sv.apply_cz(0, 0).unwrap();
}
#[test]
fn test_hadamard_unitary() {
let h_matrix = [
[c(FRAC_1_SQRT_2, 0.0), c(FRAC_1_SQRT_2, 0.0)],
[c(FRAC_1_SQRT_2, 0.0), c(-FRAC_1_SQRT_2, 0.0)],
];
let mut sv = Statevector::new(2);
sv.apply_ry(0, 0.7).unwrap();
sv.apply_rx(1, 1.2).unwrap();
let original: Vec<Complex64> = sv.data.to_vec();
sv.apply_single_qubit_gate(0, h_matrix).unwrap();
sv.apply_single_qubit_gate(0, h_matrix).unwrap();
for (i, (a, b)) in sv.data.iter().zip(original.iter()).enumerate() {
assert_complex_eq(*a, *b, &format!("H^2 should be I at index {}", i));
}
}
#[test]
fn test_cz_unitary() {
let mut sv = Statevector::new(2);
sv.apply_x(0).unwrap();
sv.apply_x(1).unwrap();
sv.apply_cz(0, 1).unwrap();
sv.apply_cz(0, 1).unwrap();
assert_complex_eq(sv.data[3], c(1.0, 0.0), "CZ^2 should be I");
}
#[test]
fn test_rx_ry_rz_unitarity() {
let mut sv = Statevector::new(3);
sv.apply_rx(0, 1.23).unwrap();
sv.apply_ry(1, 2.34).unwrap();
sv.apply_rz(2, 3.45).unwrap();
sv.apply_cx(0, 1).unwrap();
sv.apply_cz(1, 2).unwrap();
sv.apply_swap(0, 2).unwrap();
assert_normalized(&sv);
}
#[test]
fn test_sdg_gate() {
let mut sv = Statevector::new(1);
sv.apply_x(0).unwrap();
sv.apply_s(0).unwrap();
sv.apply_sdg(0).unwrap();
assert_complex_eq(sv.data[1], c(1.0, 0.0), "S†S|1⟩ should be |1⟩");
}
#[test]
fn test_tdg_gate() {
let mut sv = Statevector::new(1);
sv.apply_x(0).unwrap();
sv.apply_t(0).unwrap();
sv.apply_tdg(0).unwrap();
assert_complex_eq(sv.data[1], c(1.0, 0.0), "T†T|1⟩ should be |1⟩");
}
#[test]
fn test_xy2p_xy2m() {
let mut sv = Statevector::new(1);
sv.apply_ry(0, 0.5).unwrap(); sv.apply_xy2p(0, 1.0).unwrap();
sv.apply_xy2m(0, 1.0).unwrap();
let mut sv2 = Statevector::new(1);
sv2.apply_x(0).unwrap();
let original = sv2.data.clone();
sv2.apply_xy2p(0, 0.5).unwrap();
sv2.apply_xy2m(0, 0.5).unwrap();
assert_complex_eq(sv2.data[1], original[1], "XY2M should invert XY2P");
}
#[test]
fn test_rxy_gate() {
let mut sv1 = Statevector::new(1);
sv1.apply_rxy(0, PI / 2.0, 0.0).unwrap();
let mut sv2 = Statevector::new(1);
sv2.apply_rx(0, PI / 2.0).unwrap();
assert_complex_eq(
sv1.data[0],
sv2.data[0],
"RXY(θ,0)[0] should equal Rx(θ)[0]",
);
assert_complex_eq(
sv1.data[1],
sv2.data[1],
"RXY(θ,0)[1] should equal Rx(θ)[1]",
);
let mut sv3 = Statevector::new(1);
sv3.apply_rxy(0, PI / 2.0, PI / 2.0).unwrap();
let mut sv4 = Statevector::new(1);
sv4.apply_ry(0, PI / 2.0).unwrap();
assert_complex_eq(
sv3.data[0],
sv4.data[0],
"RXY(θ,π/2)[0] should equal Ry(θ)[0]",
);
assert_complex_eq(
sv3.data[1],
sv4.data[1],
"RXY(θ,π/2)[1] should equal Ry(θ)[1]",
);
let mut sv5 = Statevector::new(1);
sv5.apply_rxy(0, PI / 2.0, PI / 4.0).unwrap();
assert_normalized(&sv5);
}
#[test]
fn test_cascade_cx() {
let mut sv = Statevector::new(3);
sv.apply_x(0).unwrap();
sv.apply_x(1).unwrap(); sv.apply_cx(0, 1).unwrap();
sv.apply_cx(1, 2).unwrap();
assert_complex_eq(sv.data[1], c(1.0, 0.0), "Cascade CX result should be |001⟩");
}
#[test]
fn test_single_qubit_system() {
let mut sv = Statevector::new(1);
let h_matrix = [
[c(FRAC_1_SQRT_2, 0.0), c(FRAC_1_SQRT_2, 0.0)],
[c(FRAC_1_SQRT_2, 0.0), c(-FRAC_1_SQRT_2, 0.0)],
];
sv.apply_single_qubit_gate(0, h_matrix).unwrap();
sv.apply_x(0).unwrap();
assert_complex_eq(sv.data[0], c(FRAC_1_SQRT_2, 0.0), "XH|0⟩[0] should be 1/√2");
assert_complex_eq(sv.data[1], c(FRAC_1_SQRT_2, 0.0), "XH|0⟩[1] should be 1/√2");
}
#[test]
fn test_max_qubits_edge_case() {
let mut sv = Statevector::new(4);
sv.apply_ry(3, PI / 2.0).unwrap();
assert_normalized(&sv);
sv.apply_cx(3, 0).unwrap();
assert_normalized(&sv);
}
#[test]
fn test_zero_angle_rotations() {
let mut sv = Statevector::new(2);
sv.apply_x(0).unwrap();
sv.apply_rx(0, 0.0).unwrap();
sv.apply_ry(0, 0.0).unwrap();
sv.apply_rz(0, 0.0).unwrap();
sv.apply_phase(0, 0.0).unwrap();
sv.apply_rxy(0, 0.0, 1.0).unwrap();
assert_complex_eq(sv.data[1], c(1.0, 0.0), "Zero angle rotations should be I");
}
#[test]
fn test_global_phase() {
let mut sv = Statevector::new(1);
sv.apply_rz(0, 2.0 * PI).unwrap();
assert_complex_eq(sv.data[0], c(-1.0, 0.0), "Rz(2π)|0⟩ should be -|0⟩");
let probs = sv.probabilities();
assert!(
(probs[0] - 1.0).abs() < EPSILON,
"Probability should be 1 despite global phase"
);
}
#[test]
fn circuit_evolution_applies_global_phase_including_small_residuals() {
use crate::circuit::Parameter;
for num_qubits in [0, 1] {
for angle in [0.3, 1e-12, 1e-20] {
let mut circuit = Circuit::new(num_qubits);
circuit.set_global_phase(Parameter::from(angle));
let state = Statevector::from_circuit(&circuit).unwrap();
let expected = Complex64::from_polar(1.0, angle);
assert_eq!(state.data[0], expected);
let mut incremental = Statevector::new(num_qubits);
incremental.apply_circuit(&circuit).unwrap();
assert_eq!(incremental.data[0], expected);
}
}
}
#[test]
fn circuit_evolution_rejects_unbound_global_phase_before_mutating() {
use crate::circuit::Parameter;
let mut circuit = Circuit::new(1);
circuit.x(Qubit::new(0)).unwrap();
circuit.set_global_phase(Parameter::symbol("phi"));
let mut state = Statevector::new(1);
let before = state.data.clone();
assert!(state.apply_circuit(&circuit).is_err());
assert_eq!(&state.data[..], &before[..]);
}
#[test]
fn test_relative_phase() {
let mut sv = Statevector::new(1);
let h_matrix = [
[c(FRAC_1_SQRT_2, 0.0), c(FRAC_1_SQRT_2, 0.0)],
[c(FRAC_1_SQRT_2, 0.0), c(-FRAC_1_SQRT_2, 0.0)],
];
sv.apply_single_qubit_gate(0, h_matrix).unwrap();
sv.apply_s(0).unwrap();
assert_complex_eq(sv.data[0], c(FRAC_1_SQRT_2, 0.0), "SH|0⟩[0] should be 1/√2");
assert_complex_eq(sv.data[1], c(0.0, FRAC_1_SQRT_2), "SH|0⟩[1] should be i/√2");
let probs = sv.probabilities();
assert!((probs[0] - 0.5).abs() < EPSILON, "P(|0⟩) should be 0.5");
assert!((probs[1] - 0.5).abs() < EPSILON, "P(|1⟩) should be 0.5");
}
#[test]
fn test_apply_h() {
let mut sv = Statevector::new(1);
sv.apply_h(0).unwrap();
assert_complex_eq(sv.data[0], c(FRAC_1_SQRT_2, 0.0), "H|0⟩[0] should be 1/√2");
assert_complex_eq(sv.data[1], c(FRAC_1_SQRT_2, 0.0), "H|0⟩[1] should be 1/√2");
let mut sv2 = Statevector::new(1);
sv2.apply_x(0).unwrap();
sv2.apply_h(0).unwrap();
assert_complex_eq(sv2.data[0], c(FRAC_1_SQRT_2, 0.0), "H|1⟩[0] should be 1/√2");
assert_complex_eq(
sv2.data[1],
c(-FRAC_1_SQRT_2, 0.0),
"H|1⟩[1] should be -1/√2",
);
let mut sv3 = Statevector::new(1);
sv3.apply_h(0).unwrap();
sv3.apply_h(0).unwrap();
assert_complex_eq(sv3.data[0], c(1.0, 0.0), "H^2|0⟩ should be |0⟩");
assert_complex_eq(sv3.data[1], c(0.0, 0.0), "H^2|0⟩[1] should be 0");
}
#[test]
fn test_apply_u() {
let mut sv1 = Statevector::new(1);
sv1.apply_u(0, PI, 0.0, 0.0).unwrap();
let mut sv2 = Statevector::new(1);
sv2.apply_ry(0, PI).unwrap();
assert_complex_eq(sv1.data[0], sv2.data[0], "U(Ï€,0,0) should equal Ry(Ï€)[0]");
assert_complex_eq(sv1.data[1], sv2.data[1], "U(Ï€,0,0) should equal Ry(Ï€)[1]");
let mut sv3 = Statevector::new(1);
sv3.apply_x(0).unwrap();
sv3.apply_u(0, 0.0, 0.0, PI / 2.0).unwrap();
let mut sv4 = Statevector::new(1);
sv4.apply_x(0).unwrap();
sv4.apply_phase(0, PI / 2.0).unwrap();
assert_complex_eq(sv3.data[1], sv4.data[1], "U(0,0,λ)|1⟩ should equal P(λ)|1⟩");
let mut sv5 = Statevector::new(1);
sv5.apply_u(0, PI / 2.0, 0.0, 0.0).unwrap();
let mut sv6 = Statevector::new(1);
sv6.apply_ry(0, PI / 2.0).unwrap();
assert_complex_eq(
sv5.data[0],
sv6.data[0],
"U(Ï€/2,0,0) should equal Ry(Ï€/2)[0]",
);
assert_complex_eq(
sv5.data[1],
sv6.data[1],
"U(Ï€/2,0,0) should equal Ry(Ï€/2)[1]",
);
let mut sv7 = Statevector::new(1);
sv7.apply_u(0, PI, -PI / 2.0, PI / 2.0).unwrap();
let mut sv8 = Statevector::new(1);
sv8.apply_rx(0, PI).unwrap();
assert_complex_eq(
sv7.data[0],
sv8.data[0],
"U(Ï€,-Ï€/2,Ï€/2) should equal Rx(Ï€)[0]",
);
assert_complex_eq(
sv7.data[1],
sv8.data[1],
"U(Ï€,-Ï€/2,Ï€/2) should equal Rx(Ï€)[1]",
);
let mut sv9 = Statevector::new(2);
sv9.apply_ry(0, 0.7).unwrap();
sv9.apply_u(1, 1.2, 0.5, 0.3).unwrap();
assert_normalized(&sv9);
}
#[test]
fn test_apply_ccx() {
let mut sv = Statevector::new(3);
sv.apply_x(1).unwrap();
sv.apply_x(2).unwrap(); sv.apply_ccx(1, 2, 0).unwrap();
assert_complex_eq(sv.data[7], c(1.0, 0.0), "CCX|110⟩ should be |111⟩");
let mut sv2 = Statevector::new(3);
sv2.apply_x(0).unwrap();
sv2.apply_x(1).unwrap();
sv2.apply_x(2).unwrap(); sv2.apply_ccx(0, 1, 2).unwrap();
assert_complex_eq(
sv2.data[3],
c(1.0, 0.0),
"CCX|111⟩ should be |011⟩ when target is highest",
);
let mut sv3 = Statevector::new(3);
sv3.apply_x(0).unwrap();
sv3.apply_x(2).unwrap(); sv3.apply_ccx(0, 1, 2).unwrap();
assert_complex_eq(sv3.data[5], c(1.0, 0.0), "CCX|101⟩ should be unchanged");
let mut sv4 = Statevector::new(3);
sv4.apply_x(0).unwrap();
sv4.apply_x(1).unwrap(); sv4.apply_ccx(1, 2, 0).unwrap();
assert_complex_eq(sv4.data[3], c(1.0, 0.0), "CCX|011⟩ should be unchanged");
let mut sv5 = Statevector::new(3);
sv5.apply_x(0).unwrap();
sv5.apply_x(1).unwrap(); sv5.apply_ccx(0, 1, 2).unwrap();
sv5.apply_ccx(0, 1, 2).unwrap();
assert_complex_eq(sv5.data[3], c(1.0, 0.0), "CCX^2 should be I");
}
#[test]
fn test_apply_rxx() {
let mut sv1 = Statevector::new(2);
sv1.apply_rxx(0, 1, 0.0).unwrap();
assert_complex_eq(sv1.data[0], c(1.0, 0.0), "RXX(0) should be I");
let mut sv2 = Statevector::new(2);
sv2.apply_rxx(0, 1, PI).unwrap();
assert_complex_eq(sv2.data[0], c(0.0, 0.0), "RXX(π)|00⟩[0] should be 0");
assert_complex_eq(sv2.data[3], c(0.0, -1.0), "RXX(π)|00⟩ should be -i|11⟩");
let mut sv3 = Statevector::new(2);
sv3.apply_x(0).unwrap(); sv3.apply_rxx(0, 1, PI).unwrap();
sv3.apply_rxx(0, 1, PI).unwrap();
assert_complex_eq(sv3.data[1], c(-1.0, 0.0), "RXX(Ï€)^2 should be -I");
let mut sv4 = Statevector::new(3);
sv4.apply_h(0).unwrap();
sv4.apply_rxx(0, 2, 0.7).unwrap();
assert_normalized(&sv4);
}
#[test]
fn test_apply_ryy() {
let mut sv1 = Statevector::new(2);
sv1.apply_ryy(0, 1, 0.0).unwrap();
assert_complex_eq(sv1.data[0], c(1.0, 0.0), "RYY(0) should be I");
let mut sv2 = Statevector::new(2);
sv2.apply_ryy(0, 1, PI).unwrap();
assert_complex_eq(sv2.data[0], c(0.0, 0.0), "RYY(π)|00⟩[0] should be 0");
assert_complex_eq(sv2.data[3], c(0.0, 1.0), "RYY(π)|00⟩ should be i|11⟩");
let mut sv3 = Statevector::new(3);
sv3.apply_h(0).unwrap();
sv3.apply_ryy(1, 2, 0.7).unwrap();
assert_normalized(&sv3);
}
#[test]
fn test_apply_rzz() {
let mut sv1 = Statevector::new(2);
sv1.apply_rzz(0, 1, 0.0).unwrap();
assert_complex_eq(sv1.data[0], c(1.0, 0.0), "RZZ(0) should be I");
let mut sv2 = Statevector::new(2);
sv2.apply_rzz(0, 1, PI).unwrap();
assert_complex_eq(sv2.data[0], c(0.0, -1.0), "RZZ(π)|00⟩ should be -i|00⟩");
let mut sv3 = Statevector::new(2);
sv3.apply_x(0).unwrap();
sv3.apply_rzz(0, 1, PI).unwrap();
assert_complex_eq(sv3.data[1], c(0.0, 1.0), "RZZ(π)|01⟩ should be i|01⟩");
let mut sv4 = Statevector::new(3);
sv4.apply_h(0).unwrap();
sv4.apply_rzz(0, 2, 0.7).unwrap();
assert_normalized(&sv4);
}
#[test]
fn test_apply_rzx() {
let mut sv1 = Statevector::new(2);
sv1.apply_rzx(0, 1, 0.0).unwrap();
assert_complex_eq(sv1.data[0], c(1.0, 0.0), "RZX(0) should be I");
let mut sv2 = Statevector::new(2);
sv2.apply_rzx(0, 1, PI).unwrap();
assert_complex_eq(sv2.data[0], c(0.0, 0.0), "RZX(π)|00⟩[0]");
assert_complex_eq(sv2.data[2], c(0.0, -1.0), "RZX(π)|00⟩ should be -i|10⟩");
let mut sv3 = Statevector::new(3);
sv3.apply_h(0).unwrap();
sv3.apply_rzx(0, 2, 0.7).unwrap();
assert_normalized(&sv3);
let mut sv4 = Statevector::new(2);
sv4.apply_rzx(1, 0, PI).unwrap();
assert_complex_eq(sv4.data[0], c(0.0, 0.0), "RZX(π, rev)|00⟩[0]");
assert_complex_eq(
sv4.data[1],
c(0.0, -1.0),
"RZX(π, rev)|00⟩ should be -i|01⟩",
);
}
#[test]
fn test_apply_crx() {
let mut sv1 = Statevector::new(2);
sv1.apply_crx(0, 1, 0.0).unwrap();
assert_complex_eq(sv1.data[0], c(1.0, 0.0), "CRX(0) should be I");
let mut sv2 = Statevector::new(2);
sv2.apply_x(0).unwrap();
sv2.apply_x(1).unwrap(); sv2.apply_crx(0, 1, PI).unwrap();
assert_complex_eq(sv2.data[3], c(0.0, 0.0), "CRX(π)|11⟩[11] should be 0");
assert_complex_eq(sv2.data[1], c(0.0, -1.0), "CRX(π)|11⟩ should be -i|01⟩");
let mut sv2b = Statevector::new(2);
sv2b.apply_x(1).unwrap(); sv2b.apply_crx(0, 1, PI).unwrap();
assert_complex_eq(
sv2b.data[2],
c(1.0, 0.0),
"CRX(π)|10⟩ should be unchanged (control=0)",
);
let mut sv3 = Statevector::new(2);
sv3.apply_x(0).unwrap(); sv3.apply_crx(0, 1, PI).unwrap();
assert_complex_eq(sv3.data[1], c(0.0, 0.0), "CRX(π)|01⟩[01] should be 0");
assert_complex_eq(sv3.data[3], c(0.0, -1.0), "CRX(π)|01⟩ should be -i|11⟩");
let mut sv4 = Statevector::new(3);
sv4.apply_h(0).unwrap();
sv4.apply_crx(0, 2, 0.7).unwrap();
assert_normalized(&sv4);
let mut sv5 = Statevector::new(2);
sv5.apply_x(1).unwrap(); sv5.apply_crx(0, 1, PI).unwrap();
assert_complex_eq(
sv5.data[2],
c(1.0, 0.0),
"CRX(0,1,π)|10⟩ should be unchanged (control=0)",
);
let mut sv6 = Statevector::new(2);
sv6.apply_x(1).unwrap(); sv6.apply_crx(1, 0, PI).unwrap(); assert_complex_eq(sv6.data[2], c(0.0, 0.0), "CRX(1,0,π)|10⟩[10] should be 0");
assert!((sv6.data[3].re.abs() < EPSILON), "Real part should be 0");
assert!(
(sv6.data[3].im + 1.0).abs() < EPSILON,
"Imag part should be -1"
);
}
#[test]
fn test_apply_cry() {
let mut sv1 = Statevector::new(2);
sv1.apply_cry(0, 1, 0.0).unwrap();
assert_complex_eq(sv1.data[0], c(1.0, 0.0), "CRY(0) should be I");
let mut sv2 = Statevector::new(2);
sv2.apply_x(0).unwrap();
sv2.apply_x(1).unwrap(); sv2.apply_cry(0, 1, PI).unwrap();
assert_complex_eq(sv2.data[3], c(0.0, 0.0), "CRY(π)|11⟩[11] should be 0");
assert_complex_eq(sv2.data[1], c(-1.0, 0.0), "CRY(π)|11⟩ should be -|01⟩");
let mut sv2b = Statevector::new(2);
sv2b.apply_x(1).unwrap(); sv2b.apply_cry(0, 1, PI).unwrap();
assert_complex_eq(sv2b.data[2], c(1.0, 0.0), "CRY(π)|10⟩ should be unchanged");
let mut sv3 = Statevector::new(2);
sv3.apply_x(0).unwrap(); sv3.apply_cry(0, 1, PI).unwrap();
assert_complex_eq(sv3.data[1], c(0.0, 0.0), "CRY(π)|01⟩[01] should be 0");
assert_complex_eq(sv3.data[3], c(1.0, 0.0), "CRY(π)|01⟩ should be |11⟩");
let mut sv4 = Statevector::new(3);
sv4.apply_h(0).unwrap();
sv4.apply_cry(0, 2, 0.7).unwrap();
assert_normalized(&sv4);
let mut sv5 = Statevector::new(2);
sv5.apply_x(0).unwrap();
sv5.apply_x(1).unwrap(); sv5.apply_cry(1, 0, PI).unwrap();
assert_complex_eq(sv5.data[3], c(0.0, 0.0), "CRY(1,0,π)|11⟩[11] should be 0");
assert_complex_eq(sv5.data[2], c(-1.0, 0.0), "CRY(1,0,π)|11⟩ should be -|10⟩");
}
#[test]
fn test_apply_crz() {
let mut sv1 = Statevector::new(2);
sv1.apply_crz(0, 1, 0.0).unwrap();
assert_complex_eq(sv1.data[0], c(1.0, 0.0), "CRZ(0) should be I");
let mut sv2 = Statevector::new(2);
sv2.apply_x(0).unwrap();
sv2.apply_x(1).unwrap(); sv2.apply_crz(0, 1, PI).unwrap();
assert_complex_eq(sv2.data[3], c(0.0, 1.0), "CRZ(π)|11⟩ should be i|11⟩");
let mut sv2b = Statevector::new(2);
sv2b.apply_x(1).unwrap(); sv2b.apply_crz(0, 1, PI).unwrap();
assert_complex_eq(
sv2b.data[2],
c(1.0, 0.0),
"CRZ(π)|10⟩ should be unchanged (control=0)",
);
let mut sv3 = Statevector::new(2);
sv3.apply_x(0).unwrap(); sv3.apply_crz(0, 1, PI).unwrap();
assert_complex_eq(sv3.data[1], c(0.0, -1.0), "CRZ(π)|01⟩ should be -i|01⟩");
let mut sv4 = Statevector::new(2);
sv4.apply_crz(0, 1, PI).unwrap();
assert_complex_eq(sv4.data[0], c(1.0, 0.0), "CRZ(π)|00⟩ should be unchanged");
let mut sv5 = Statevector::new(3);
sv5.apply_h(0).unwrap();
sv5.apply_crz(0, 2, 0.7).unwrap();
assert_normalized(&sv5);
let mut sv6 = Statevector::new(2);
sv6.apply_x(1).unwrap(); sv6.apply_crz(1, 0, PI).unwrap();
assert_complex_eq(sv6.data[2], c(0.0, -1.0), "CRZ(1,0,π)|10⟩ should be -i|10⟩");
}
#[test]
fn test_apply_fsim() {
let mut sv1 = Statevector::new(2);
sv1.apply_fsim(0, 1, 0.0, 0.0).unwrap();
assert_complex_eq(sv1.data[0], c(1.0, 0.0), "fSim(0,0) should be I");
let mut sv2 = Statevector::new(2);
sv2.apply_x(0).unwrap(); sv2.apply_fsim(0, 1, PI / 2.0, 0.0).unwrap();
assert_complex_eq(sv2.data[1], c(0.0, 0.0), "fSim(π/2,0)|01⟩[01] should be 0");
assert_complex_eq(
sv2.data[2],
c(0.0, -1.0),
"fSim(π/2,0)|01⟩ should be -i|10⟩",
);
let mut sv3 = Statevector::new(2);
sv3.apply_x(0).unwrap();
sv3.apply_x(1).unwrap(); sv3.apply_fsim(0, 1, 0.0, PI / 2.0).unwrap();
assert_complex_eq(
sv3.data[3],
c(0.0, -1.0),
"fSim(0,π/2)|11⟩ should be -i|11⟩",
);
let mut sv4 = Statevector::new(3);
sv4.apply_h(0).unwrap();
sv4.apply_fsim(0, 2, 0.5, 0.3).unwrap();
assert_normalized(&sv4);
}
#[test]
fn test_apply_gphase() {
let mut sv1 = Statevector::new(2);
sv1.apply_h(0).unwrap();
sv1.apply_gphase(PI).unwrap();
let probs1 = sv1.probabilities();
assert!((probs1[0] - 0.5).abs() < EPSILON, "P(|00⟩) should be 0.5");
assert!((probs1[1] - 0.5).abs() < EPSILON, "P(|01⟩) should be 0.5");
let mut sv2 = Statevector::new(1);
sv2.apply_gphase(PI).unwrap();
assert_complex_eq(sv2.data[0], c(-1.0, 0.0), "GPhase(π)|0⟩ should be -|0⟩");
let mut sv3 = Statevector::new(1);
sv3.apply_x(0).unwrap();
sv3.apply_gphase(2.0 * PI).unwrap();
assert_complex_eq(sv3.data[1], c(1.0, 0.0), "GPhase(2Ï€) should be I");
}
#[test]
fn test_from_state() {
let initial_state = vec![c(FRAC_1_SQRT_2, 0.0), c(FRAC_1_SQRT_2, 0.0)];
let sv = Statevector::from_state(1, initial_state).unwrap();
assert_eq!(sv.num_qubits, 1);
assert_eq!(sv.data.len(), 2);
assert_complex_eq(sv.data[0], c(FRAC_1_SQRT_2, 0.0), "|+⟩[0] should be 1/√2");
assert_complex_eq(sv.data[1], c(FRAC_1_SQRT_2, 0.0), "|+⟩[1] should be 1/√2");
let bell_state = vec![
c(FRAC_1_SQRT_2, 0.0),
c(0.0, 0.0),
c(0.0, 0.0),
c(FRAC_1_SQRT_2, 0.0),
];
let sv2 = Statevector::from_state(2, bell_state).unwrap();
assert_eq!(sv2.num_qubits, 2);
assert_eq!(sv2.data.len(), 4);
assert_complex_eq(sv2.data[0], c(FRAC_1_SQRT_2, 0.0), "Bell |00⟩ amp");
assert_complex_eq(sv2.data[3], c(FRAC_1_SQRT_2, 0.0), "Bell |11⟩ amp");
let i_state = vec![c(FRAC_1_SQRT_2, 0.0), c(0.0, FRAC_1_SQRT_2)];
let sv3 = Statevector::from_state(1, i_state).unwrap();
assert_complex_eq(sv3.data[1], c(0.0, FRAC_1_SQRT_2), "|i⟩[1] should be i/√2");
}
#[test]
fn test_from_state_wrong_length() {
let state = vec![c(1.0, 0.0), c(0.0, 0.0), c(0.0, 0.0)]; let result = Statevector::from_state(2, state);
assert!(result.is_err());
}
#[test]
fn test_from_state_not_normalized() {
let state = vec![c(1.0, 0.0), c(1.0, 0.0)]; let result = Statevector::from_state(1, state);
assert!(result.is_err());
}
#[test]
fn test_from_circuit() {
use crate::circuit::Circuit;
let mut circuit = Circuit::new(1);
circuit.h(Qubit::new(0)).unwrap();
let sv = Statevector::from_circuit(&circuit).unwrap();
assert_eq!(sv.num_qubits, 1);
assert_complex_eq(sv.data[0], c(FRAC_1_SQRT_2, 0.0), "H|0⟩[0] should be 1/√2");
assert_complex_eq(sv.data[1], c(FRAC_1_SQRT_2, 0.0), "H|0⟩[1] should be 1/√2");
let mut circuit2 = Circuit::new(2);
circuit2.h(Qubit::new(0)).unwrap();
circuit2.cx(Qubit::new(0), Qubit::new(1)).unwrap();
let sv2 = Statevector::from_circuit(&circuit2).unwrap();
assert_eq!(sv2.num_qubits, 2);
assert_complex_eq(sv2.data[0], c(FRAC_1_SQRT_2, 0.0), "Bell |00⟩ amp");
assert_complex_eq(sv2.data[1], c(0.0, 0.0), "Bell |01⟩ amp should be 0");
assert_complex_eq(sv2.data[2], c(0.0, 0.0), "Bell |10⟩ amp should be 0");
assert_complex_eq(sv2.data[3], c(FRAC_1_SQRT_2, 0.0), "Bell |11⟩ amp");
let mut circuit3 = Circuit::new(1);
circuit3.rx(Qubit::new(0), PI).unwrap();
let sv3 = Statevector::from_circuit(&circuit3).unwrap();
assert_complex_eq(sv3.data[0], c(0.0, 0.0), "RX(π)|0⟩[0] should be 0");
assert_complex_eq(sv3.data[1], c(0.0, -1.0), "RX(π)|0⟩[1] should be -i");
}
#[test]
fn test_from_circuit_3qubit_ghz() {
use crate::circuit::Circuit;
let mut circuit = Circuit::new(3);
circuit.h(Qubit::new(0)).unwrap();
circuit.cx(Qubit::new(0), Qubit::new(1)).unwrap();
circuit.cx(Qubit::new(0), Qubit::new(2)).unwrap();
let sv = Statevector::from_circuit(&circuit).unwrap();
assert_eq!(sv.num_qubits, 3);
assert_complex_eq(sv.data[0], c(FRAC_1_SQRT_2, 0.0), "GHZ |000⟩ amp");
assert_complex_eq(sv.data[7], c(FRAC_1_SQRT_2, 0.0), "GHZ |111⟩ amp");
for i in 1..7 {
assert_complex_eq(
sv.data[i],
c(0.0, 0.0),
&format!("GHZ |{:03b}⟩ should be 0", i),
);
}
assert_normalized(&sv);
}
#[test]
fn test_from_circuit_ignores_terminal_measurement_declarations() {
use crate::circuit::{Circuit, Qubit};
use crate::device::Outcome;
let mut circuit = Circuit::new(2);
circuit.h(Qubit::new(0)).unwrap();
circuit.cx(Qubit::new(0), Qubit::new(1)).unwrap();
let out = circuit
.measure_bits([Qubit::new(1), Qubit::new(0)])
.unwrap();
let sv = Statevector::from_circuit(&circuit).unwrap();
let probs = sv.probs(&out).unwrap();
assert_eq!(probs.len(), 2);
assert!((probs[&Outcome::from_bitstring("00").unwrap()] - 0.5).abs() < EPSILON);
assert!((probs[&Outcome::from_bitstring("11").unwrap()] - 0.5).abs() < EPSILON);
}
#[test]
fn test_ccx_target_middle() {
let mut sv = Statevector::new(3);
sv.apply_x(0).unwrap();
sv.apply_x(2).unwrap();
sv.apply_ccx(0, 2, 1).unwrap();
assert_complex_eq(
sv.data[5],
c(0.0, 0.0),
"CCX(0,2,1)|101⟩ original should be 0",
);
assert_complex_eq(
sv.data[7],
c(1.0, 0.0),
"CCX(0,2,1)|101⟩ should flip to |111⟩",
);
}
#[test]
fn test_apply_unitary_asymmetric() {
use ndarray::Array2;
let matrix = Array2::from_shape_vec(
(4, 4),
vec![
c(1.0, 0.0),
c(0.0, 0.0),
c(0.0, 0.0),
c(0.0, 0.0), c(0.0, 0.0),
c(0.0, 0.0),
c(1.0, 0.0),
c(0.0, 0.0), c(0.0, 0.0),
c(0.0, 1.0),
c(0.0, 0.0),
c(0.0, 0.0), c(0.0, 0.0),
c(0.0, 0.0),
c(0.0, 0.0),
c(1.0, 0.0), ],
)
.unwrap();
let mut sv = Statevector::new(2);
sv.apply_x(0).unwrap();
sv.apply_unitary_gate(&[1, 0], &matrix).unwrap();
assert_complex_eq(sv.data[1], c(0.0, 0.0), "Old state |01⟩ should be empty");
assert_complex_eq(sv.data[2], c(0.0, 1.0), "New state should be i|10⟩");
}
#[test]
fn test_expectation_z_on_zero() {
let sv = Statevector::new(1);
let mut ps = PauliString::new(1);
ps.set_pauli(0, Pauli::Z);
let h = Hamiltonian::from_pauli(ps);
let exp = sv.expectation(&h).unwrap();
assert!(
(exp - 1.0).abs() < EPSILON,
"<0|Z|0> should be 1, got {}",
exp
);
}
#[test]
fn test_expectation_z_on_one() {
let mut sv = Statevector::new(1);
sv.apply_x(0).unwrap();
let mut ps = PauliString::new(1);
ps.set_pauli(0, Pauli::Z);
let h = Hamiltonian::from_pauli(ps);
let exp = sv.expectation(&h).unwrap();
assert!(
(exp + 1.0).abs() < EPSILON,
"<1|Z|1> should be -1, got {}",
exp
);
}
#[test]
fn test_expectation_x_on_plus() {
let mut sv = Statevector::new(1);
sv.apply_h(0).unwrap();
let mut ps = PauliString::new(1);
ps.set_pauli(0, Pauli::X);
let h = Hamiltonian::from_pauli(ps);
let exp = sv.expectation(&h).unwrap();
assert!(
(exp - 1.0).abs() < EPSILON,
"<+|X|+> should be 1, got {}",
exp
);
}
#[test]
fn test_expectation_multi_qubit() {
let mut sv = Statevector::new(2);
sv.apply_h(0).unwrap();
sv.apply_cx(0, 1).unwrap();
let mut ps = PauliString::new(2);
ps.set_pauli(0, Pauli::Z); let h = Hamiltonian::from_pauli(ps);
let exp = sv.expectation(&h).unwrap();
assert!(exp.abs() < EPSILON, "<Φ+|Z⊗I|Φ+> should be 0, got {}", exp);
}
#[test]
fn test_expectation_zz_on_bell() {
let mut sv = Statevector::new(2);
sv.apply_h(0).unwrap();
sv.apply_cx(0, 1).unwrap();
let mut ps = PauliString::new(2);
ps.set_pauli(0, Pauli::Z);
ps.set_pauli(1, Pauli::Z);
let h = Hamiltonian::from_pauli(ps);
let exp = sv.expectation(&h).unwrap();
assert!(
(exp - 1.0).abs() < EPSILON,
"<Φ+|ZZ|Φ+> should be 1, got {}",
exp
);
}
#[test]
fn test_expectation_with_coefficient() {
let sv = Statevector::new(1);
let mut ps = PauliString::new(1);
ps.set_pauli(0, Pauli::Z);
let h = Hamiltonian::from_list(vec![(ps, Complex64::new(2.0, 0.0))]).unwrap();
let exp = sv.expectation(&h).unwrap();
assert!(
(exp - 2.0).abs() < EPSILON,
"<0|2Z|0> should be 2, got {}",
exp
);
}
#[test]
fn test_expectation_qubit_mismatch() {
let sv = Statevector::new(1);
let h = Hamiltonian::new(2);
let result = sv.expectation(&h);
assert!(result.is_err(), "Should error on qubit mismatch");
}
#[test]
fn test_sqg_avx2_complex_phase_gate() {
let mut sv = Statevector::new(1);
sv.apply_h(0).unwrap();
let i = Complex64::new(0.0, 1.0);
let s_matrix = [
[Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)],
[Complex64::new(0.0, 0.0), i],
];
sv.apply_single_qubit_gate(0, s_matrix).unwrap();
let inv_sqrt2 = 1.0 / 2.0_f64.sqrt();
let d = sv.data();
assert!(
(d[0].re - inv_sqrt2).abs() < EPSILON,
"Re(|0⟩) should be 1/√2, got {}",
d[0].re
);
assert!(d[0].im.abs() < EPSILON, "Im(|0⟩) should be 0");
assert!(d[1].re.abs() < EPSILON, "Re(|1⟩) should be 0");
assert!(
(d[1].im - inv_sqrt2).abs() < EPSILON,
"Im(|1⟩) should be 1/√2, got {}",
d[1].im
);
}
#[test]
fn test_sqg_avx2_larger_state() {
use std::f64::consts::FRAC_PI_4;
let n = 5;
let mut sv = Statevector::new(n);
for q in 0..n {
sv.apply_h(q).unwrap();
}
let phase = Complex64::from_polar(1.0, FRAC_PI_4);
let t_matrix = [
[Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)],
[Complex64::new(0.0, 0.0), phase],
];
sv.apply_single_qubit_gate(2, t_matrix).unwrap();
let base_amp = 1.0 / (2.0_f64.powi(n as i32)).sqrt();
let d = sv.data();
for (idx, &) in d.iter().enumerate() {
let qubit2_is_one = (idx >> 2) & 1 == 1;
let expected = if qubit2_is_one {
phase * base_amp
} else {
Complex64::new(base_amp, 0.0)
};
assert!(
(amp - expected).norm() < EPSILON,
"idx={}: expected {:?}, got {:?}",
idx,
expected,
amp
);
}
}
#[test]
fn test_statevector_data_alignment() {
let sv = Statevector::new(10);
let ptr = sv.data().as_ptr() as usize;
assert_eq!(
ptr % 64,
0,
"Statevector::data must be 64-byte aligned for AVX2/AVX-512; got alignment {}",
ptr % 64
);
}
#[test]
fn test_apply_circuit_bell_state() {
let mut circuit = Circuit::new(2);
circuit.h(Qubit::new(0)).unwrap();
circuit.cx(Qubit::new(0), Qubit::new(1)).unwrap();
let mut sv = Statevector::new(2);
sv.apply_circuit(&circuit).unwrap();
assert_complex_eq(sv.data[0], c(FRAC_1_SQRT_2, 0.0), "Bell |00⟩ amp");
assert_complex_eq(sv.data[1], c(0.0, 0.0), "Bell |01⟩ amp should be 0");
assert_complex_eq(sv.data[2], c(0.0, 0.0), "Bell |10⟩ amp should be 0");
assert_complex_eq(sv.data[3], c(FRAC_1_SQRT_2, 0.0), "Bell |11⟩ amp");
assert_normalized(&sv);
}
#[test]
fn test_apply_circuit_parameterized() {
let mut circuit = Circuit::new(1);
circuit.rx(Qubit::new(0), PI / 2.0).unwrap();
let mut sv = Statevector::new(1);
sv.apply_circuit(&circuit).unwrap();
let inv_sqrt2 = FRAC_1_SQRT_2;
assert_complex_eq(
sv.data[0],
c(inv_sqrt2, 0.0),
"RX(π/2)|0⟩[0] should be 1/√2",
);
assert_complex_eq(
sv.data[1],
c(0.0, -inv_sqrt2),
"RX(π/2)|0⟩[1] should be -i/√2",
);
assert_normalized(&sv);
}
#[test]
fn test_apply_circuit_toffoli() {
let mut circuit = Circuit::new(3);
circuit.x(Qubit::new(0)).unwrap();
circuit.x(Qubit::new(1)).unwrap();
circuit
.ccx(Qubit::new(0), Qubit::new(1), Qubit::new(2))
.unwrap();
let mut sv = Statevector::new(3);
sv.apply_circuit(&circuit).unwrap();
for i in 0..7 {
assert_complex_eq(
sv.data[i],
c(0.0, 0.0),
&format!(" amplitude |{:03b}⟩ should be 0", i),
);
}
assert_complex_eq(sv.data[7], c(1.0, 0.0), "CCX|110⟩ should be |111⟩");
assert_normalized(&sv);
}
#[test]
fn test_apply_circuit_incremental() {
let mut h_circuit = Circuit::new(1);
h_circuit.h(Qubit::new(0)).unwrap();
let mut z_circuit = Circuit::new(1);
z_circuit.z(Qubit::new(0)).unwrap();
let mut sv = Statevector::new(1);
sv.apply_circuit(&h_circuit).unwrap();
sv.apply_circuit(&z_circuit).unwrap();
assert_complex_eq(sv.data[0], c(FRAC_1_SQRT_2, 0.0), "ZH|0⟩[0] should be 1/√2");
assert_complex_eq(
sv.data[1],
c(-FRAC_1_SQRT_2, 0.0),
"ZH|0⟩[1] should be -1/√2",
);
assert_normalized(&sv);
}
#[test]
fn test_apply_circuit_dimension_mismatch() {
let mut circuit = Circuit::new(2);
circuit.h(Qubit::new(0)).unwrap();
let mut sv = Statevector::new(1);
let result = sv.apply_circuit(&circuit);
assert!(
matches!(result, Err(QisError::InvalidStateDimension(2))),
"Should error on dimension mismatch"
);
}
#[test]
fn test_apply_circuit_reset_directive() {
let mut circuit = Circuit::new(1);
circuit.x(Qubit::new(0)).unwrap();
circuit.reset(Qubit::new(0)).unwrap();
let mut sv = Statevector::new(1);
sv.apply_circuit(&circuit).unwrap();
assert_complex_eq(sv.data[0], c(1.0, 0.0), "X then reset should return |0>");
assert_complex_eq(sv.data[1], c(0.0, 0.0), "X then reset should clear |1>");
}
#[test]
fn test_apply_circuit_classical_control_flow_error() {
use crate::circuit::ClassicalExpr;
let mut circuit = Circuit::new(1);
circuit
.if_(ClassicalExpr::bool_literal(true), |body| {
body.x(Qubit::new(0))?;
Ok(())
})
.unwrap();
let mut sv = Statevector::new(1);
assert!(matches!(
sv.apply_circuit(&circuit),
Err(QisError::UnsupportedOperation(_))
));
}
#[test]
fn test_apply_standard_gate_arity_mismatch() {
let mut sv = Statevector::new(2);
let result = sv.apply_standard_gate(StandardGate::CX, &[0], &[]);
assert!(
result.is_err(),
"CX with 1 qubit should fail, got {:?}",
result
);
}
#[test]
fn test_measure_out_of_bounds() {
let mut sv = Statevector::new(2);
let result = sv.measure(99);
assert!(
result.is_err(),
"measure on out-of-bounds qubit should fail, got {:?}",
result
);
}
#[test]
fn test_measure_deterministic_zero_and_one() {
let mut zero = Statevector::new(1);
assert!(!zero.measure(0).unwrap());
assert_complex_eq(zero.data[0], c(1.0, 0.0), "|0> remains |0>");
assert_complex_eq(zero.data[1], c(0.0, 0.0), "|1> amplitude remains zero");
let mut one = Statevector::new(1);
one.apply_x(0).unwrap();
assert!(one.measure(0).unwrap());
assert_complex_eq(one.data[0], c(0.0, 0.0), "|0> amplitude remains zero");
assert_complex_eq(one.data[1], c(1.0, 0.0), "|1> remains |1>");
}
#[test]
fn test_measure_plus_statistics_and_collapse() {
let shots = 1000;
let mut ones = 0;
for _ in 0..shots {
let mut sv = Statevector::new(1);
sv.apply_h(0).unwrap();
let outcome = sv.measure(0).unwrap();
if outcome {
ones += 1;
assert_complex_eq(sv.data[0], c(0.0, 0.0), "collapsed |0> amp");
assert_complex_eq(sv.data[1], c(1.0, 0.0), "collapsed |1> amp");
} else {
assert_complex_eq(sv.data[0], c(1.0, 0.0), "collapsed |0> amp");
assert_complex_eq(sv.data[1], c(0.0, 0.0), "collapsed |1> amp");
}
}
assert!(
(350..=650).contains(&ones),
"|+> measurement should be near 50/50; ones={ones}/{shots}"
);
}
#[test]
fn test_measure_with_rng_is_reproducible() {
use rand::SeedableRng;
use rand::rngs::SmallRng;
let shots = 64;
let mut rng_a = SmallRng::seed_from_u64(1234);
let mut rng_b = SmallRng::seed_from_u64(1234);
let outcomes_a: Vec<bool> = (0..shots)
.map(|_| {
let mut sv = Statevector::new(1);
sv.apply_h(0).unwrap();
sv.measure_with_rng(0, &mut rng_a).unwrap()
})
.collect();
let outcomes_b: Vec<bool> = (0..shots)
.map(|_| {
let mut sv = Statevector::new(1);
sv.apply_h(0).unwrap();
sv.measure_with_rng(0, &mut rng_b).unwrap()
})
.collect();
assert_eq!(outcomes_a, outcomes_b);
assert!(
outcomes_a.iter().any(|&b| b) && outcomes_a.iter().any(|&b| !b),
"seeded |+> samples should include both outcomes"
);
}
#[test]
fn test_zero_qubit_measure_boundary() {
let mut sv = Statevector::new(0);
assert_eq!(sv.num_qubits, 0);
assert_eq!(sv.data.len(), 1);
assert_complex_eq(sv.data[0], c(1.0, 0.0), "0-qubit scalar state");
assert!(sv.measure(0).is_err());
assert_eq!(sv.probabilities(), vec![1.0]);
}
#[test]
fn test_zero_qubit_validate_error_message() {
let mut sv = Statevector::new(0);
let err = sv.apply_x(0).unwrap_err();
assert!(
matches!(&err, QisError::InvalidParameterValue(msg) if msg.contains("zero-qubit")),
"Expected InvalidParameterValue with zero-qubit message, got {:?}",
err
);
}
#[test]
fn test_measure_all_bit_packing() {
let mut sv = Statevector::new(4);
sv.apply_x(0).unwrap();
sv.apply_x(2).unwrap();
let outcome = sv.measure_all();
assert!(outcome.is_one(0));
assert!(!outcome.is_one(1));
assert!(outcome.is_one(2));
assert!(!outcome.is_one(3));
}
#[test]
fn test_sample_shots_zero_and_bell_distribution() {
let mut sv = Statevector::new(2);
sv.apply_h(0).unwrap();
sv.apply_cx(0, 1).unwrap();
assert!(sv.sample_shots(0).is_empty());
let shots = sv.sample_shots(1000);
assert_eq!(shots.len(), 1000);
let ones = shots
.iter()
.filter(|outcome| outcome.is_one(0) && outcome.is_one(1))
.count();
assert!(
shots
.iter()
.all(|outcome| outcome.is_one(0) == outcome.is_one(1))
);
assert!(
(350..=650).contains(&ones),
"Bell samples should be near 50/50 between 00 and 11; ones={ones}"
);
}
#[test]
fn test_sample_uses_measurement_qubit_order() {
use crate::circuit::{Circuit, Qubit};
use crate::device::{Outcome, Status};
let mut circuit = Circuit::new(2);
circuit.x(Qubit::new(0)).unwrap();
let out = circuit
.measure_bits([Qubit::new(1), Qubit::new(0)])
.unwrap();
let sv = Statevector::from_circuit(&circuit).unwrap();
let result = sv.sample(&out, 16).unwrap();
assert_eq!(result.shots(), 16);
assert_eq!(result.num_qubits(), 2);
assert_eq!(result.qubits(), &vec![Qubit::new(1), Qubit::new(0)]);
assert_eq!(result.status(), &Status::Completed);
assert_eq!(
result.counts().get(&Outcome::from_bitstring("10").unwrap()),
Some(&16)
);
assert_eq!(
result.probabilities().as_ref().unwrap()[&Outcome::from_bitstring("10").unwrap()],
1.0
);
}
#[test]
fn test_probs_marginalizes_unmeasured_qubits() {
use crate::circuit::Circuit;
use crate::device::Outcome;
let mut circuit = Circuit::new(2);
circuit.h(Qubit::new(0)).unwrap();
circuit.cx(Qubit::new(0), Qubit::new(1)).unwrap();
let out = circuit.measure(Qubit::new(0)).unwrap();
let sv = Statevector::from_circuit(&circuit).unwrap();
let probs = sv.probs(&out).unwrap();
assert_eq!(probs.len(), 2);
assert!((probs[&Outcome::from_bitstring("0").unwrap()] - 0.5).abs() < EPSILON);
assert!((probs[&Outcome::from_bitstring("1").unwrap()] - 0.5).abs() < EPSILON);
}
#[test]
fn test_sample_rejects_measurement_qubit_outside_state() {
use crate::circuit::Circuit;
let sv = Statevector::new(1);
let mut circuit = Circuit::new(3);
let measurement = circuit.measure(Qubit::new(2)).unwrap();
assert!(matches!(
sv.sample(&measurement, 1),
Err(QisError::IndexOutOfBounds { index: 2, max: 0 })
));
}
#[test]
fn test_apply_unitary_gate_duplicate_qubits() {
let mut sv = Statevector::new(2);
let identity = ndarray::Array2::eye(4);
let result = sv.apply_unitary_gate(&[0, 0], &identity);
assert!(
result.is_err(),
"duplicate target qubits should be rejected, got {:?}",
result
);
}
#[test]
fn test_probabilities_parallel_threshold_14_qubits() {
let n = 14;
let mut sv = Statevector::new(n);
for q in 0..n {
sv.apply_h(q).unwrap();
}
let probs = sv.probabilities();
assert_eq!(probs.len(), 1 << n);
let expected = 1.0 / (1 << n) as f64;
let sum: f64 = probs.iter().sum();
assert!((sum - 1.0).abs() < 1e-10);
assert!(probs.iter().all(|p| (p - expected).abs() < 1e-10));
}
#[test]
fn test_probabilities_large_20_qubit_uniform_superposition() {
let n = 20;
let mut sv = Statevector::new(n);
for q in 0..n {
sv.apply_h(q).unwrap();
}
let probs = sv.probabilities();
assert_eq!(probs.len(), 1 << n);
let expected = 1.0 / (1 << n) as f64;
let sum: f64 = probs.iter().sum();
assert!((sum - 1.0).abs() < 1e-9);
assert!((probs[0] - expected).abs() < 1e-12);
assert!((probs[(1 << n) - 1] - expected).abs() < 1e-12);
}
#[test]
fn test_apply_pauli_rotation_matches_gate_decomposition() {
use crate::qis::pauli::{Pauli, PauliString};
let mut native = Statevector::new(4);
native.apply_h(0).unwrap();
native.apply_rx(1, 0.37).unwrap();
native.apply_ry(2, -0.21).unwrap();
native.apply_cx(0, 3).unwrap();
let mut decomposed = native.clone();
let mut pauli = PauliString::new(4);
pauli.set_pauli(0, Pauli::X);
pauli.set_pauli(1, Pauli::Y);
pauli.set_pauli(3, Pauli::Z);
let theta = 0.413;
native.apply_pauli_rotation(&pauli, theta).unwrap();
decomposed.apply_h(0).unwrap();
decomposed.apply_rx(1, std::f64::consts::FRAC_PI_2).unwrap();
decomposed.apply_cx(0, 1).unwrap();
decomposed.apply_cx(1, 3).unwrap();
decomposed.apply_rz(3, theta).unwrap();
decomposed.apply_cx(1, 3).unwrap();
decomposed.apply_cx(0, 1).unwrap();
decomposed.apply_h(0).unwrap();
decomposed
.apply_rx(1, -std::f64::consts::FRAC_PI_2)
.unwrap();
for (actual, expected) in native.data().iter().zip(decomposed.data()) {
assert!(
(actual - expected).norm() < 1e-12,
"{actual:?} != {expected:?}"
);
}
}
#[test]
fn test_apply_pauli_rotation_rejects_imaginary_global_phase() {
use crate::qis::pauli::{PauliString, Phase};
let mut state = Statevector::new(1);
let mut pauli = PauliString::new(1);
pauli.phase = Phase::I;
assert!(state.apply_pauli_rotation(&pauli, 0.2).is_err());
}
#[test]
fn controlled_gphase_circuit_evolution() {
for ids in [[0, 1, 2], [12, 5, 31]] {
let qubits = ids.map(Qubit::new);
for controls in [
vec![qubits[2]],
vec![qubits[2], qubits[0]],
vec![qubits[0], qubits[2]],
] {
for theta in [0.0, 0.37, -0.51, PI] {
let mut preparation = Circuit::from_qubits(qubits.to_vec()).unwrap();
for qubit in qubits {
preparation.h(qubit).unwrap();
}
preparation.s(qubits[1]).unwrap();
let mut phase = Circuit::from_qubits(qubits.to_vec()).unwrap();
phase
.multi_control(
StandardGate::GPhase,
controls.clone(),
Vec::<Qubit>::new(),
[theta.into()],
)
.unwrap();
let mut circuit = preparation.clone();
circuit
.multi_control(
StandardGate::GPhase,
controls.clone(),
Vec::<Qubit>::new(),
[theta.into()],
)
.unwrap();
let mask = controls.iter().fold(0usize, |mask, q| {
mask | (1 << qubits.iter().position(|candidate| candidate == q).unwrap())
});
let expected: Vec<Complex64> = (0..8)
.map(|index| {
let amplitude = if index & 2 == 0 {
Complex64::new(1.0, 0.0)
} else {
Complex64::new(0.0, 1.0)
} / 8.0_f64.sqrt();
if index & mask == mask {
amplitude * Complex64::from_polar(1.0, theta)
} else {
amplitude
}
})
.collect();
let expected_data = expected.clone();
let actual = Statevector::from_circuit(&circuit).unwrap();
let mut incremental = Statevector::new(3);
incremental.apply_circuit(&preparation).unwrap();
incremental.apply_circuit(&phase).unwrap();
for values in [actual.data(), incremental.data()] {
for (actual, expected) in values.iter().zip(&expected_data) {
assert!(
(actual - expected).norm() < 1e-12,
"{actual:?} != {expected:?}"
);
}
}
let mut inverse = Circuit::from_qubits(qubits.to_vec()).unwrap();
inverse
.multi_control(
StandardGate::GPhase,
controls.clone(),
Vec::<Qubit>::new(),
[(-theta).into()],
)
.unwrap();
incremental.apply_circuit(&inverse).unwrap();
let baseline = Statevector::from_circuit(&preparation).unwrap();
for (actual, expected) in incremental.data().iter().zip(baseline.data()) {
assert!((actual - expected).norm() < 1e-12);
}
}
}
}
}
#[test]
fn zero_control_gphase_circuit_evolution() {
use crate::circuit::gate::{Instruction, MCGate};
for num_qubits in [0, 1, 3] {
for theta in [0.0, 0.37, -0.51, PI] {
let mut circuit = Circuit::new(num_qubits);
if num_qubits > 0 {
circuit.h(Qubit::new(0)).unwrap();
}
circuit
.append(
Instruction::McGate(Box::new(MCGate::new(0, StandardGate::GPhase))),
Vec::<Qubit>::new(),
[theta.into()],
None,
)
.unwrap();
let actual = Statevector::from_circuit(&circuit).unwrap();
let mut amplitudes = vec![Complex64::new(0.0, 0.0); 1 << num_qubits];
amplitudes[0] = Complex64::from_polar(1.0, theta);
if num_qubits > 0 {
amplitudes[0] /= 2.0_f64.sqrt();
amplitudes[1] = amplitudes[0];
}
let expected = amplitudes;
for (actual, expected) in actual.data().iter().zip(&expected) {
assert!((actual - expected).norm() < 1e-12);
}
}
}
}