use serde::{Deserialize, Serialize};
use std::f64::consts::{PI, SQRT_2};
use thiserror::Error;
use super::continuous_variable::{CVError, CVResult, Complex, GaussianState};
#[derive(Error, Debug)]
pub enum CVGateError {
#[error("Invalid gate parameter: {0}")]
InvalidParameter(String),
#[error("Gate not supported: {0}")]
UnsupportedGate(String),
#[error("Mode index out of bounds: {0}")]
ModeOutOfBounds(usize),
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum CVGateType {
Displacement,
Squeezing,
TwoModeSqueezing,
Beamsplitter,
PhaseRotation,
Kerr,
CrossKerr,
CubicPhase,
PositionMeasurement,
MomentumMeasurement,
HomodyneMeasurement,
HeterodyneMeasurement,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CVGateParams {
pub gate_type: CVGateType,
pub modes: Vec<usize>,
pub params: Vec<f64>,
pub complex_params: Vec<Complex>,
pub duration: Option<f64>,
pub fidelity: Option<f64>,
}
pub struct DisplacementGate {
pub alpha: Complex,
pub mode: usize,
}
impl DisplacementGate {
pub const fn new(alpha: Complex, mode: usize) -> Self {
Self { alpha, mode }
}
pub fn apply(&self, state: &mut GaussianState) -> CVResult<()> {
state.displace(self.alpha, self.mode)
}
pub fn matrix(&self, cutoff: usize) -> Vec<Vec<Complex>> {
let mut matrix = vec![vec![Complex::new(0.0, 0.0); cutoff]; cutoff];
for n in 0..cutoff {
for m in 0..cutoff {
let element = self.displacement_matrix_element(m, n, cutoff);
matrix[m][n] = element;
}
}
matrix
}
const fn displacement_matrix_element(&self, m: usize, n: usize, cutoff: usize) -> Complex {
if m == n {
Complex::new(1.0, 0.0)
} else {
Complex::new(0.0, 0.0)
}
}
#[must_use]
pub fn inverse(&self) -> Self {
Self {
alpha: Complex::new(-self.alpha.real, -self.alpha.imag),
mode: self.mode,
}
}
}
pub struct SqueezingGate {
pub r: f64,
pub phi: f64,
pub mode: usize,
}
impl SqueezingGate {
pub fn new(r: f64, phi: f64, mode: usize) -> Result<Self, CVGateError> {
if r.abs() > 20.0 {
return Err(CVGateError::InvalidParameter(
"Squeezing parameter too large".to_string(),
));
}
Ok(Self { r, phi, mode })
}
pub fn apply(&self, state: &mut GaussianState) -> CVResult<()> {
state.squeeze(self.r, self.phi, self.mode)
}
pub fn squeezing_db(&self) -> f64 {
10.0 * self.r.abs() / 2.0_f64.log(10.0_f64)
}
pub fn amplitude_squeezing(r: f64, mode: usize) -> Result<Self, CVGateError> {
Self::new(r, 0.0, mode)
}
pub fn phase_squeezing(r: f64, mode: usize) -> Result<Self, CVGateError> {
Self::new(r, PI / 2.0, mode)
}
}
pub struct TwoModeSqueezingGate {
pub r: f64,
pub phi: f64,
pub mode1: usize,
pub mode2: usize,
}
impl TwoModeSqueezingGate {
pub fn new(r: f64, phi: f64, mode1: usize, mode2: usize) -> Result<Self, CVGateError> {
if mode1 == mode2 {
return Err(CVGateError::InvalidParameter(
"Two-mode squeezing requires different modes".to_string(),
));
}
if r.abs() > 20.0 {
return Err(CVGateError::InvalidParameter(
"Squeezing parameter too large".to_string(),
));
}
Ok(Self {
r,
phi,
mode1,
mode2,
})
}
pub fn apply(&self, state: &mut GaussianState) -> CVResult<()> {
state.two_mode_squeeze(self.r, self.phi, self.mode1, self.mode2)
}
pub fn entanglement_strength(&self) -> f64 {
2.0 * self.r.abs()
}
}
pub struct BeamsplitterGate {
pub theta: f64,
pub phi: f64,
pub mode1: usize,
pub mode2: usize,
}
impl BeamsplitterGate {
pub fn new(theta: f64, phi: f64, mode1: usize, mode2: usize) -> Result<Self, CVGateError> {
if mode1 == mode2 {
return Err(CVGateError::InvalidParameter(
"Beamsplitter requires different modes".to_string(),
));
}
Ok(Self {
theta,
phi,
mode1,
mode2,
})
}
pub fn apply(&self, state: &mut GaussianState) -> CVResult<()> {
state.beamsplitter(self.theta, self.phi, self.mode1, self.mode2)
}
pub fn fifty_fifty(mode1: usize, mode2: usize) -> Result<Self, CVGateError> {
Self::new(PI / 4.0, 0.0, mode1, mode2)
}
pub fn transmission(&self) -> f64 {
self.theta.cos().powi(2)
}
pub fn reflection(&self) -> f64 {
self.theta.sin().powi(2)
}
pub fn with_transmission(
transmission: f64,
phi: f64,
mode1: usize,
mode2: usize,
) -> Result<Self, CVGateError> {
if !(0.0..=1.0).contains(&transmission) {
return Err(CVGateError::InvalidParameter(
"Transmission must be between 0 and 1".to_string(),
));
}
let theta = transmission.sqrt().acos();
Self::new(theta, phi, mode1, mode2)
}
}
pub struct PhaseRotationGate {
pub phi: f64,
pub mode: usize,
}
impl PhaseRotationGate {
pub const fn new(phi: f64, mode: usize) -> Self {
Self { phi, mode }
}
pub fn apply(&self, state: &mut GaussianState) -> CVResult<()> {
state.phase_rotation(self.phi, self.mode)
}
pub fn normalized_phase(&self) -> f64 {
self.phi.rem_euclid(2.0 * PI)
}
}
pub struct KerrGate {
pub kappa: f64,
pub mode: usize,
pub time: f64,
}
impl KerrGate {
pub const fn new(kappa: f64, mode: usize, time: f64) -> Self {
Self { kappa, mode, time }
}
pub fn apply(&self, state: &mut GaussianState) -> CVResult<()> {
let n_avg = state.average_photon_number(self.mode)?;
let phase_shift = self.kappa * n_avg * self.time;
state.phase_rotation(phase_shift, self.mode)
}
pub fn phase_shift(&self, photon_number: f64) -> f64 {
self.kappa * photon_number * self.time
}
}
pub struct CrossKerrGate {
pub kappa: f64,
pub mode1: usize,
pub mode2: usize,
pub time: f64,
}
impl CrossKerrGate {
pub fn new(kappa: f64, mode1: usize, mode2: usize, time: f64) -> Result<Self, CVGateError> {
if mode1 == mode2 {
return Err(CVGateError::InvalidParameter(
"Cross-Kerr requires different modes".to_string(),
));
}
Ok(Self {
kappa,
mode1,
mode2,
time,
})
}
pub fn apply(&self, state: &mut GaussianState) -> CVResult<()> {
let n1 = state.average_photon_number(self.mode1)?;
let n2 = state.average_photon_number(self.mode2)?;
let phase_shift1 = self.kappa * n2 * self.time;
let phase_shift2 = self.kappa * n1 * self.time;
state.phase_rotation(phase_shift1, self.mode1)?;
state.phase_rotation(phase_shift2, self.mode2)?;
Ok(())
}
pub fn conditional_phase_shift(&self, control_photons: f64) -> f64 {
self.kappa * control_photons * self.time
}
}
pub struct CubicPhaseGate {
pub gamma: f64,
pub mode: usize,
}
impl CubicPhaseGate {
pub const fn new(gamma: f64, mode: usize) -> Self {
Self { gamma, mode }
}
pub fn apply(&self, _state: &mut GaussianState) -> CVResult<()> {
Err(CVError::IncompatibleOperation(
"Cubic phase gate is non-Gaussian and not supported for Gaussian states".to_string(),
))
}
}
pub struct CVGateSequence {
pub gates: Vec<CVGateParams>,
pub num_modes: usize,
}
impl CVGateSequence {
pub const fn new(num_modes: usize) -> Self {
Self {
gates: Vec::new(),
num_modes,
}
}
pub fn displacement(&mut self, alpha: Complex, mode: usize) -> Result<&mut Self, CVGateError> {
if mode >= self.num_modes {
return Err(CVGateError::ModeOutOfBounds(mode));
}
self.gates.push(CVGateParams {
gate_type: CVGateType::Displacement,
modes: vec![mode],
params: vec![],
complex_params: vec![alpha],
duration: None,
fidelity: Some(0.99),
});
Ok(self)
}
pub fn squeezing(&mut self, r: f64, phi: f64, mode: usize) -> Result<&mut Self, CVGateError> {
if mode >= self.num_modes {
return Err(CVGateError::ModeOutOfBounds(mode));
}
self.gates.push(CVGateParams {
gate_type: CVGateType::Squeezing,
modes: vec![mode],
params: vec![r, phi],
complex_params: vec![],
duration: None,
fidelity: Some(0.98),
});
Ok(self)
}
pub fn two_mode_squeezing(
&mut self,
r: f64,
phi: f64,
mode1: usize,
mode2: usize,
) -> Result<&mut Self, CVGateError> {
if mode1 >= self.num_modes || mode2 >= self.num_modes {
return Err(CVGateError::ModeOutOfBounds(mode1.max(mode2)));
}
self.gates.push(CVGateParams {
gate_type: CVGateType::TwoModeSqueezing,
modes: vec![mode1, mode2],
params: vec![r, phi],
complex_params: vec![],
duration: None,
fidelity: Some(0.97),
});
Ok(self)
}
pub fn beamsplitter(
&mut self,
theta: f64,
phi: f64,
mode1: usize,
mode2: usize,
) -> Result<&mut Self, CVGateError> {
if mode1 >= self.num_modes || mode2 >= self.num_modes {
return Err(CVGateError::ModeOutOfBounds(mode1.max(mode2)));
}
self.gates.push(CVGateParams {
gate_type: CVGateType::Beamsplitter,
modes: vec![mode1, mode2],
params: vec![theta, phi],
complex_params: vec![],
duration: None,
fidelity: Some(0.995),
});
Ok(self)
}
pub fn phase_rotation(&mut self, phi: f64, mode: usize) -> Result<&mut Self, CVGateError> {
if mode >= self.num_modes {
return Err(CVGateError::ModeOutOfBounds(mode));
}
self.gates.push(CVGateParams {
gate_type: CVGateType::PhaseRotation,
modes: vec![mode],
params: vec![phi],
complex_params: vec![],
duration: None,
fidelity: Some(0.999),
});
Ok(self)
}
pub fn apply(&self, state: &mut GaussianState) -> CVResult<()> {
for gate in &self.gates {
match gate.gate_type {
CVGateType::Displacement => {
if let (Some(alpha), Some(&mode)) =
(gate.complex_params.first(), gate.modes.first())
{
state.displace(*alpha, mode)?;
}
}
CVGateType::Squeezing => {
if let (Some(&r), Some(&phi), Some(&mode)) =
(gate.params.first(), gate.params.get(1), gate.modes.first())
{
state.squeeze(r, phi, mode)?;
}
}
CVGateType::TwoModeSqueezing => {
if let (Some(&r), Some(&phi), Some(&mode1), Some(&mode2)) = (
gate.params.first(),
gate.params.get(1),
gate.modes.first(),
gate.modes.get(1),
) {
state.two_mode_squeeze(r, phi, mode1, mode2)?;
}
}
CVGateType::Beamsplitter => {
if let (Some(&theta), Some(&phi), Some(&mode1), Some(&mode2)) = (
gate.params.first(),
gate.params.get(1),
gate.modes.first(),
gate.modes.get(1),
) {
state.beamsplitter(theta, phi, mode1, mode2)?;
}
}
CVGateType::PhaseRotation => {
if let (Some(&phi), Some(&mode)) = (gate.params.first(), gate.modes.first()) {
state.phase_rotation(phi, mode)?;
}
}
_ => {
return Err(CVError::IncompatibleOperation(format!(
"Gate type {:?} not yet implemented",
gate.gate_type
)));
}
}
}
Ok(())
}
pub fn total_fidelity(&self) -> f64 {
self.gates
.iter()
.map(|gate| gate.fidelity.unwrap_or(1.0))
.product()
}
pub fn gate_count(&self, gate_type: CVGateType) -> usize {
self.gates
.iter()
.filter(|gate| gate.gate_type == gate_type)
.count()
}
pub fn optimize(&mut self) -> Result<(), CVGateError> {
self.gates.retain(|gate| match gate.gate_type {
CVGateType::PhaseRotation => {
if let Some(&phi) = gate.params.first() {
(phi % (2.0 * PI)).abs() > 1e-10
} else {
true
}
}
CVGateType::Displacement => gate
.complex_params
.first()
.map_or(true, |alpha| alpha.magnitude() > 1e-10),
_ => true,
});
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::photonic::continuous_variable::GaussianState;
#[test]
fn test_displacement_gate() {
let alpha = Complex::new(1.0, 0.5);
let gate = DisplacementGate::new(alpha, 0);
let mut state = GaussianState::vacuum(1);
gate.apply(&mut state)
.expect("Displacement gate application should succeed");
assert!((state.mean[0] - alpha.real * SQRT_2).abs() < 1e-10);
assert!((state.mean[1] - alpha.imag * SQRT_2).abs() < 1e-10);
}
#[test]
fn test_squeezing_gate() {
let gate = SqueezingGate::new(1.0, 0.0, 0).expect("Squeezing gate creation should succeed");
let mut state = GaussianState::vacuum(1);
gate.apply(&mut state)
.expect("Squeezing gate application should succeed");
assert!(state.covariance[0][0] < 0.5);
assert!(state.covariance[1][1] > 0.5);
}
#[test]
fn test_beamsplitter_gate() {
let gate = BeamsplitterGate::fifty_fifty(0, 1)
.expect("50:50 beamsplitter creation should succeed");
let mut state = GaussianState::coherent(Complex::new(2.0, 0.0), 0, 2)
.expect("Coherent state creation should succeed");
gate.apply(&mut state)
.expect("Beamsplitter gate application should succeed");
assert!(state.mean[0].abs() > 0.0);
assert!(state.mean[2].abs() > 0.0);
assert!((state.mean[0].abs() - state.mean[2].abs()).abs() < 1e-10);
}
#[test]
fn test_gate_sequence() {
let mut sequence = CVGateSequence::new(2);
sequence
.displacement(Complex::new(1.0, 0.0), 0)
.expect("Adding displacement gate should succeed")
.squeezing(0.5, 0.0, 0)
.expect("Adding squeezing gate should succeed")
.beamsplitter(PI / 4.0, 0.0, 0, 1)
.expect("Adding beamsplitter gate should succeed");
assert_eq!(sequence.gates.len(), 3);
assert_eq!(sequence.gate_count(CVGateType::Displacement), 1);
assert_eq!(sequence.gate_count(CVGateType::Squeezing), 1);
assert_eq!(sequence.gate_count(CVGateType::Beamsplitter), 1);
}
#[test]
fn test_sequence_application() {
let mut sequence = CVGateSequence::new(1);
sequence
.displacement(Complex::new(1.0, 0.0), 0)
.expect("Adding displacement gate should succeed")
.phase_rotation(PI / 2.0, 0)
.expect("Adding phase rotation gate should succeed");
let mut state = GaussianState::vacuum(1);
sequence
.apply(&mut state)
.expect("Gate sequence application should succeed");
assert!(state.mean[0].abs() > 0.0 || state.mean[1].abs() > 0.0);
}
#[test]
fn test_sequence_optimization() {
let mut sequence = CVGateSequence::new(1);
sequence
.displacement(Complex::new(0.0, 0.0), 0)
.expect("Adding zero displacement should succeed") .phase_rotation(0.0, 0)
.expect("Adding zero phase rotation should succeed");
sequence
.optimize()
.expect("Gate sequence optimization should succeed");
assert_eq!(sequence.gates.len(), 0);
}
}