use crate::error::QuantumResult;
use crate::gates::controlled::apply_cnot;
use crate::gates::hadamard::gate_h;
use crate::gates::pauli::{gate_x, gate_z};
use crate::statevec::apply_1q::apply_1q_inplace;
use crate::statevec::state::StateVector;
#[derive(Debug, Clone)]
pub struct SuperdenseResult {
pub decoded: (bool, bool),
pub probability: f32,
}
pub fn superdense_decode(b0: bool, b1: bool) -> QuantumResult<SuperdenseResult> {
let mut sv = StateVector::new_zero_state(2)?;
apply_1q_inplace(&mut sv, 0, &gate_h())?;
apply_cnot(&mut sv, 0, 1)?;
if b1 {
apply_1q_inplace(&mut sv, 0, &gate_x())?;
}
if b0 {
apply_1q_inplace(&mut sv, 0, &gate_z())?;
}
apply_cnot(&mut sv, 0, 1)?;
apply_1q_inplace(&mut sv, 0, &gate_h())?;
let mut best_idx = 0usize;
let mut best = f32::NEG_INFINITY;
for (i, a) in sv.amps.iter().enumerate() {
let p = a.norm_sqr();
if p > best {
best = p;
best_idx = i;
}
}
let decoded_b0 = (best_idx & 1) != 0;
let decoded_b1 = (best_idx & 2) != 0;
Ok(SuperdenseResult {
decoded: (decoded_b0, decoded_b1),
probability: best,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn decodes_zero_zero() {
let res = superdense_decode(false, false)
.expect("superdense decode of (false, false) should succeed");
assert_eq!(res.decoded, (false, false));
assert!(res.probability > 0.999, "p={}", res.probability);
}
#[test]
fn decodes_zero_one() {
let res = superdense_decode(false, true)
.expect("superdense decode of (false, true) should succeed");
assert_eq!(res.decoded, (false, true));
assert!(res.probability > 0.999, "p={}", res.probability);
}
#[test]
fn decodes_one_zero() {
let res = superdense_decode(true, false)
.expect("superdense decode of (true, false) should succeed");
assert_eq!(res.decoded, (true, false));
assert!(res.probability > 0.999, "p={}", res.probability);
}
#[test]
fn decodes_one_one() {
let res = superdense_decode(true, true)
.expect("superdense decode of (true, true) should succeed");
assert_eq!(res.decoded, (true, true));
assert!(res.probability > 0.999, "p={}", res.probability);
}
#[test]
fn all_messages_round_trip() {
for &(b0, b1) in &[(false, false), (false, true), (true, false), (true, true)] {
let res = superdense_decode(b0, b1)
.expect("superdense decode should succeed for all two-bit messages");
assert_eq!(res.decoded, (b0, b1), "failed for ({b0},{b1})");
assert!(res.probability > 0.999, "({b0},{b1}) p={}", res.probability);
}
}
#[test]
fn encodings_are_orthogonal() {
let mut seen = std::collections::HashSet::new();
for &(b0, b1) in &[(false, false), (false, true), (true, false), (true, true)] {
let res = superdense_decode(b0, b1)
.expect("superdense decode should succeed for orthogonality check");
let idx = usize::from(res.decoded.0) | (usize::from(res.decoded.1) << 1);
assert!(seen.insert(idx), "collision at message ({b0},{b1})");
}
assert_eq!(seen.len(), 4);
}
#[test]
fn probability_is_deterministic() {
let a = superdense_decode(true, false)
.expect("superdense decode (true, false) first call should succeed");
let b = superdense_decode(true, false)
.expect("superdense decode (true, false) second call should succeed");
assert_eq!(a.decoded, b.decoded);
assert!((a.probability - b.probability).abs() < 1e-7);
}
#[test]
fn probability_finite_and_in_range() {
let res = superdense_decode(true, true)
.expect("superdense decode of (true, true) should succeed");
assert!(res.probability.is_finite());
assert!((0.0..=1.0 + 1e-5).contains(&res.probability));
}
#[test]
fn decoded_state_is_normalized() {
let mut sv = StateVector::new_zero_state(2).expect("valid 2-qubit zero state");
apply_1q_inplace(&mut sv, 0, &gate_h()).expect("H gate on qubit 0 should succeed");
apply_cnot(&mut sv, 0, 1).expect("CNOT on qubits 0 to 1 should succeed");
apply_1q_inplace(&mut sv, 0, &gate_x()).expect("X gate on qubit 0 should succeed");
apply_1q_inplace(&mut sv, 0, &gate_z()).expect("Z gate on qubit 0 should succeed");
apply_cnot(&mut sv, 0, 1).expect("CNOT on qubits 0 to 1 (decode step) should succeed");
apply_1q_inplace(&mut sv, 0, &gate_h())
.expect("H gate on qubit 0 (decode step) should succeed");
assert!((sv.norm_sq() - 1.0).abs() < 1e-5, "norm={}", sv.norm_sq());
}
}