use crate::{Error, KrausChannel, Matrix, Result};
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[serde(try_from = "[f64; 2]", into = "[f64; 2]")]
pub struct RailTransmission([f64; 2]);
impl RailTransmission {
pub const IDEAL: Self = Self([1., 1.]);
pub fn new(zero: f64, one: f64) -> Result<Self> {
if [zero, one]
.iter()
.any(|p| !p.is_finite() || !(0.0..=1.0).contains(p))
{
return Err(Error::InvalidValue(
"rail transmission must be finite and in [0,1]".into(),
));
}
Ok(Self([zero, one]))
}
pub fn uniform(value: f64) -> Result<Self> {
Self::new(value, value)
}
pub fn values(self) -> [f64; 2] {
self.0
}
pub fn then(self, next: Self) -> Self {
Self([self.0[0] * next.0[0], self.0[1] * next.0[1]])
}
pub fn over_ticks(self, mut ticks: u64) -> Self {
let mut out = Self::IDEAL;
let mut factor = self;
while ticks > 0 {
if ticks & 1 == 1 {
out = out.then(factor);
}
factor = factor.then(factor);
ticks >>= 1;
}
out
}
pub fn channel(self) -> Result<KrausChannel> {
let [a, b] = self.0;
KrausChannel::new(vec![
Matrix::real(3, vec![a.sqrt(), 0., 0., 0., b.sqrt(), 0., 0., 0., 1.])?,
Matrix::real(3, vec![0., 0., 0., 0., 0., 0., (1. - a).sqrt(), 0., 0.])?,
Matrix::real(3, vec![0., 0., 0., 0., 0., 0., 0., (1. - b).sqrt(), 0.])?,
])
}
}
impl TryFrom<[f64; 2]> for RailTransmission {
type Error = Error;
fn try_from(v: [f64; 2]) -> Result<Self> {
Self::new(v[0], v[1])
}
}
impl From<RailTransmission> for [f64; 2] {
fn from(v: RailTransmission) -> Self {
v.0
}
}