use num_complex::Complex;
use crate::error::{QuantumError, QuantumResult};
use crate::gates::controlled::apply_cnot;
use crate::gates::hadamard::gate_h;
use crate::gates::pauli::{gate_x, gate_z};
use crate::handle::LcgRng;
use crate::midcircuit::measurement::{ClassicalRegister, apply_if, measure_and_collapse};
use crate::statevec::apply_1q::apply_1q_inplace;
use crate::statevec::state::StateVector;
type Complex32 = Complex<f32>;
#[derive(Debug, Clone)]
pub struct TeleportResult {
pub classical_bits: (bool, bool),
pub bob_amplitudes: (Complex32, Complex32),
pub fidelity: f32,
}
pub fn teleport(
alpha: Complex32,
beta: Complex32,
rng: &mut LcgRng,
) -> QuantumResult<TeleportResult> {
let norm = (alpha.norm_sqr() + beta.norm_sqr()).sqrt();
if norm < 1e-12 {
return Err(QuantumError::InvalidParameter {
name: "input state amplitudes are both zero".into(),
});
}
let a = alpha / norm;
let b = beta / norm;
let mut amps = vec![Complex32::new(0.0, 0.0); 8];
amps[0b000] = a; amps[0b001] = b; let mut sv = StateVector { amps, n_qubits: 3 };
apply_1q_inplace(&mut sv, 1, &gate_h())?;
apply_cnot(&mut sv, 1, 2)?;
apply_cnot(&mut sv, 0, 1)?;
apply_1q_inplace(&mut sv, 0, &gate_h())?;
let mut creg = ClassicalRegister::new(2);
let m0 = measure_and_collapse(&mut sv, 0, rng, &mut creg, 0)?;
let m1 = measure_and_collapse(&mut sv, 1, rng, &mut creg, 1)?;
apply_if(&mut sv, &creg, &[(1, true)], &gate_x(), 2)?;
apply_if(&mut sv, &creg, &[(0, true)], &gate_z(), 2)?;
let base = (usize::from(m0)) | (usize::from(m1) << 1);
let bob0 = sv.amps[base]; let bob1 = sv.amps[base | (1 << 2)];
let overlap = a.conj() * bob0 + b.conj() * bob1;
let fidelity = overlap.norm_sqr();
Ok(TeleportResult {
classical_bits: (m0, m1),
bob_amplitudes: (bob0, bob1),
fidelity,
})
}
#[cfg(test)]
mod tests {
use super::*;
use std::f32::consts::FRAC_1_SQRT_2;
#[test]
fn teleports_zero_state() {
let mut rng = LcgRng::new(1);
let res = teleport(Complex32::new(1.0, 0.0), Complex32::new(0.0, 0.0), &mut rng)
.expect("teleportation of |0⟩ state with normalized input");
assert!(res.fidelity > 0.999, "fidelity={}", res.fidelity);
assert!((res.bob_amplitudes.0.norm() - 1.0).abs() < 1e-4);
assert!(res.bob_amplitudes.1.norm() < 1e-4);
}
#[test]
fn teleports_one_state() {
let mut rng = LcgRng::new(2);
let res = teleport(Complex32::new(0.0, 0.0), Complex32::new(1.0, 0.0), &mut rng)
.expect("non-zero |1⟩ state is a valid teleportation input");
assert!(res.fidelity > 0.999, "fidelity={}", res.fidelity);
assert!(res.bob_amplitudes.0.norm() < 1e-4);
assert!((res.bob_amplitudes.1.norm() - 1.0).abs() < 1e-4);
}
#[test]
fn teleports_plus_state() {
let mut rng = LcgRng::new(3);
let res = teleport(
Complex32::new(FRAC_1_SQRT_2, 0.0),
Complex32::new(FRAC_1_SQRT_2, 0.0),
&mut rng,
)
.expect("normalized |+⟩ state is a valid teleportation input");
assert!(res.fidelity > 0.999, "fidelity={}", res.fidelity);
}
#[test]
fn teleports_complex_superposition() {
let mut rng = LcgRng::new(4);
let res = teleport(Complex32::new(0.6, 0.0), Complex32::new(0.0, 0.8), &mut rng)
.expect("non-zero complex superposition is a valid teleportation input");
assert!(res.fidelity > 0.999, "fidelity={}", res.fidelity);
}
#[test]
fn fidelity_high_across_many_seeds() {
for seed in 0..32u64 {
let mut rng = LcgRng::new(seed);
let res = teleport(Complex32::new(0.6, 0.0), Complex32::new(0.8, 0.0), &mut rng)
.expect("non-zero (0.6, 0.8) real state is a valid teleportation input");
assert!(res.fidelity > 0.99, "seed={seed} fidelity={}", res.fidelity);
}
}
#[test]
fn unnormalized_input_is_accepted() {
let mut rng = LcgRng::new(5);
let res = teleport(Complex32::new(2.0, 0.0), Complex32::new(0.0, 0.0), &mut rng)
.expect("unnormalized (2, 0) is non-zero and renormalized internally");
assert!(res.fidelity > 0.999, "fidelity={}", res.fidelity);
}
#[test]
fn zero_input_errors() {
let mut rng = LcgRng::new(6);
assert!(teleport(Complex32::new(0.0, 0.0), Complex32::new(0.0, 0.0), &mut rng).is_err());
}
#[test]
fn classical_bits_are_booleans() {
let mut rng = LcgRng::new(7);
let res = teleport(
Complex32::new(0.5, 0.5),
Complex32::new(0.5, -0.5),
&mut rng,
)
.expect("complex superposition with non-zero norm is a valid teleportation input");
let (m0, m1) = res.classical_bits;
let _ = m0 & m1;
assert!(res.fidelity > 0.99, "fidelity={}", res.fidelity);
}
#[test]
fn bob_amplitudes_match_input_up_to_branch() {
let mut rng = LcgRng::new(11);
let a = Complex32::new(0.6, 0.0);
let b = Complex32::new(0.0, 0.8);
let res = teleport(a, b, &mut rng)
.expect("non-zero (0.6, 0.8i) state is a valid teleportation input");
assert!(
(res.bob_amplitudes.0 - a).norm() < 1e-4,
"bob0={:?}",
res.bob_amplitudes.0
);
assert!(
(res.bob_amplitudes.1 - b).norm() < 1e-4,
"bob1={:?}",
res.bob_amplitudes.1
);
}
#[test]
fn fidelity_is_finite_and_in_range() {
let mut rng = LcgRng::new(13);
let res = teleport(Complex32::new(0.6, 0.2), Complex32::new(0.3, 0.7), &mut rng)
.expect("non-zero complex state (0.6+0.2i, 0.3+0.7i) is a valid teleportation input");
assert!(res.fidelity.is_finite());
assert!((0.0..=1.0 + 1e-4).contains(&res.fidelity));
}
}