#![allow(clippy::doc_markdown)]
use crate::circuit::Circuit;
#[must_use]
pub fn trotter_single_z(t: f64, steps: usize) -> Circuit {
let mut c = Circuit::new(1);
let dt = t / steps as f64;
for _ in 0..steps {
c.rz(0, 2.0 * dt);
}
c
}
#[must_use]
pub fn trotter_tfim(n: usize, jzz: f64, hx: f64, t: f64, steps: usize) -> Circuit {
assert!(n >= 1);
let mut c = Circuit::new(n);
let dt = t / steps as f64;
for _ in 0..steps {
let rx_angle = -2.0 * hx * dt;
for i in 0..n {
c.rx(i, rx_angle);
}
let zz_angle = -2.0 * jzz * dt;
for i in 0..n - 1 {
c.cnot(i, i + 1);
c.rz(i + 1, zz_angle);
c.cnot(i, i + 1);
}
}
c
}
#[cfg(test)]
mod tests {
use super::*;
use crate::StateVectorBackend;
use crate::circuit::Circuit;
use crate::state::State;
fn run(c: &Circuit) -> State {
StateVectorBackend::run(c).unwrap().into_state()
}
#[test]
fn single_z_norm_preserved() {
for steps in [1, 5, 20] {
let state = run(&trotter_single_z(1.2, steps));
assert!((state.norm_sqr() - 1.0).abs() < 1e-12, "steps={steps}");
}
}
#[test]
fn pure_x_field_matches_exact_rx() {
let hx = 0.8;
let t = 0.5;
let steps = 200;
let trotter_state = run(&trotter_tfim(1, 0.0, hx, t, steps));
let mut exact = Circuit::new(1);
exact.rx(0, -2.0 * hx * t);
let exact_state = run(&exact);
assert!(
trotter_state.fidelity(&exact_state) > 0.999,
"fidelity = {}",
trotter_state.fidelity(&exact_state)
);
}
#[test]
fn tfim_norm_preserved() {
let state = run(&trotter_tfim(4, 1.0, 0.5, 1.0, 100));
assert!((state.norm_sqr() - 1.0).abs() < 1e-12);
}
#[test]
fn trotter_converges_as_steps_increase() {
let (jzz, hx, t) = (0.5, 1.0, 0.3);
let coarse = run(&trotter_tfim(2, jzz, hx, t, 10));
let fine = run(&trotter_tfim(2, jzz, hx, t, 500));
let f = coarse.fidelity(&fine);
assert!(f > 0.99, "fidelity coarse vs fine = {f}");
}
}