use super::*;
use crate::circuit::Qubit;
use crate::circuit::ansatz::Ansatz;
#[test]
fn test_qaoa_ansatz_default_mixer() {
let mut h_c = Hamiltonian::new(2);
h_c.add_term("ZZ".parse().unwrap(), 0.5.into()).unwrap();
let ansatz = QAOAAnsatz::new(h_c).unwrap().reps(2);
assert_eq!(ansatz.num_qubits(), 2);
assert_eq!(ansatz.num_parameters(), 4);
let circuit = ansatz.build_circuit("p").unwrap();
assert_eq!(circuit.parameters().len(), 4);
let syms = circuit.symbols();
assert!(syms.contains("p_gamma_0"));
assert!(syms.contains("p_beta_0"));
assert!(syms.contains("p_gamma_1"));
assert!(syms.contains("p_beta_1"));
let ops = circuit.operations();
assert_eq!(ops.len(), 20);
}
#[test]
fn test_qaoa_non_finite_scale_factor_returns_error() {
let mut h = Hamiltonian::new(1);
for _ in 0..2 {
h.add_term("Z".parse().unwrap(), f64::MAX.into()).unwrap();
}
for strategy in [
EvolutionStrategy::Exact,
EvolutionStrategy::Auto { steps: 2 },
EvolutionStrategy::Trotter {
mode: TrotterMode::FirstOrder,
steps: 2,
},
EvolutionStrategy::Trotter {
mode: TrotterMode::SecondOrder,
steps: 2,
},
EvolutionStrategy::Trotter {
mode: TrotterMode::Randomized(42),
steps: 2,
},
] {
let result = QAOAAnsatz::new(h.clone())
.unwrap()
.evolution_strategy(strategy)
.build_circuit("p");
assert!(matches!(
result,
Err(CircuitError::InvalidOperation(message)) if message.contains("scale factor")
));
}
}
#[test]
fn test_qaoa_custom_mixer() {
let mut h_c = Hamiltonian::new(2);
h_c.add_term("ZZ".parse().unwrap(), 0.5.into()).unwrap();
let mut h_b = Hamiltonian::new(2);
h_b.add_term("XX".parse().unwrap(), 1.0.into()).unwrap();
let ansatz = QAOAAnsatz::new(h_c).unwrap().mixer(h_b).unwrap().reps(1);
let circuit = ansatz.build_circuit("p").unwrap();
assert_eq!(circuit.operations().len(), 12);
}
#[test]
fn test_qaoa_mixer_mismatch_error() {
let mut h_c = Hamiltonian::new(2); h_c.add_term("ZZ".parse().unwrap(), 0.5.into()).unwrap();
let mut h_b = Hamiltonian::new(3); h_b.add_term("XXX".parse().unwrap(), 1.0.into()).unwrap();
let result = QAOAAnsatz::new(h_c).unwrap().mixer(h_b);
assert!(result.is_err());
assert!(matches!(
result.unwrap_err(),
CircuitError::QubitCountMismatch {
expected: 2,
actual: 3
}
));
}
#[test]
fn test_qaoa_custom_initial_state() {
let mut h_c = Hamiltonian::new(2);
h_c.add_term("ZI".parse().unwrap(), 1.0.into()).unwrap();
h_c.add_term("IZ".parse().unwrap(), 1.0.into()).unwrap();
let mut initial_circuit = Circuit::new(2);
initial_circuit.x(Qubit::new(1)).unwrap();
let ansatz = QAOAAnsatz::new(h_c)
.unwrap()
.initial_state(initial_circuit.clone())
.unwrap()
.reps(1);
assert_eq!(ansatz.num_qubits(), 2);
assert_eq!(ansatz.num_parameters(), 2);
let circuit = ansatz.build_circuit("p").unwrap();
let ops = circuit.operations();
assert_eq!(ops.len(), 9);
let first_op = &ops[0];
assert!(format!("{:?}", first_op).contains("X"));
}
#[test]
fn test_qaoa_initial_state_mismatch_error() {
let mut h_c = Hamiltonian::new(2); h_c.add_term("ZZ".parse().unwrap(), 0.5.into()).unwrap();
let mut initial_circuit = Circuit::new(3);
initial_circuit.h(Qubit::new(0)).unwrap();
let result = QAOAAnsatz::new(h_c).unwrap().initial_state(initial_circuit);
assert!(result.is_err());
assert!(matches!(
result.unwrap_err(),
CircuitError::QubitCountMismatch {
expected: 2,
actual: 3
}
));
}
#[test]
fn test_qaoa_zero_reps() {
let mut h_c = Hamiltonian::new(2);
h_c.add_term("ZZ".parse().unwrap(), 0.5.into()).unwrap();
let ansatz = QAOAAnsatz::new(h_c).unwrap().reps(0);
assert_eq!(ansatz.num_parameters(), 0);
let circuit = ansatz.build_circuit("p").unwrap();
let ops = circuit.operations();
assert_eq!(ops.len(), 2);
assert_eq!(circuit.parameters().len(), 0);
}
#[test]
fn test_qaoa_multi_qubit_parameter_naming() {
let mut h_c = Hamiltonian::new(4);
h_c.add_term("ZZII".parse().unwrap(), 1.0.into()).unwrap();
h_c.add_term("IZZI".parse().unwrap(), 1.0.into()).unwrap();
h_c.add_term("IIZZ".parse().unwrap(), 1.0.into()).unwrap();
let ansatz = QAOAAnsatz::new(h_c).unwrap().reps(3);
assert_eq!(ansatz.num_parameters(), 6);
let circuit = ansatz.build_circuit("theta").unwrap();
let syms = circuit.symbols();
assert!(syms.contains("theta_gamma_0"));
assert!(syms.contains("theta_beta_0"));
assert!(syms.contains("theta_gamma_1"));
assert!(syms.contains("theta_beta_1"));
assert!(syms.contains("theta_gamma_2"));
assert!(syms.contains("theta_beta_2"));
assert!(!syms.contains("theta_gamma_3"));
assert!(!syms.contains("theta_beta_3"));
}
#[test]
fn test_qaoa_complex_coefficient_error() {
use num_complex::Complex64;
let mut h_c = Hamiltonian::new(2);
h_c.add_term("ZZ".parse().unwrap(), Complex64::new(0.5, 0.3))
.unwrap();
let ansatz = QAOAAnsatz::new(h_c).unwrap().reps(1);
let result = ansatz.build_circuit("p");
assert!(result.is_err());
assert!(matches!(
&result.unwrap_err(),
CircuitError::InvalidOperation(msg) if msg.contains("non-zero imaginary part")
));
}
#[test]
fn test_qaoa_complex_mixer_coefficient_error() {
use num_complex::Complex64;
let mut h_c = Hamiltonian::new(2);
h_c.add_term("ZZ".parse().unwrap(), 0.5.into()).unwrap();
let mut h_b = Hamiltonian::new(2);
h_b.add_term("XX".parse().unwrap(), Complex64::new(1.0, 0.5))
.unwrap();
let ansatz = QAOAAnsatz::new(h_c).unwrap().mixer(h_b).unwrap().reps(1);
let result = ansatz.build_circuit("p");
assert!(result.is_err());
assert!(matches!(
&result.unwrap_err(),
CircuitError::InvalidOperation(msg) if msg.contains("non-zero imaginary part")
));
}