use crate::complex::Complex64;
use crate::density::KrausOp;
#[derive(Clone, Debug, Default)]
pub struct NoiseModel {
pub after_1q: Option<Channel>,
pub after_2q: Option<Channel>,
pub readout_error: f64,
}
impl NoiseModel {
#[must_use]
pub fn ideal() -> Self {
Self::default()
}
#[must_use]
pub fn uniform_depolarizing(p: f64) -> Self {
assert!(
(0.0..=1.0).contains(&p),
"depolarizing probability {p} not in [0, 1]"
);
let ch = Channel::Depolarizing(p);
Self {
after_1q: Some(ch.clone()),
after_2q: Some(ch),
readout_error: 0.0,
}
}
#[must_use]
pub fn amplitude_damping(gamma: f64) -> Self {
assert!((0.0..=1.0).contains(&gamma), "gamma {gamma} not in [0, 1]");
let ch = Channel::AmplitudeDamping(gamma);
Self {
after_1q: Some(ch.clone()),
after_2q: Some(ch),
readout_error: 0.0,
}
}
#[must_use]
pub fn phase_damping(lambda: f64) -> Self {
assert!(
(0.0..=1.0).contains(&lambda),
"lambda {lambda} not in [0, 1]"
);
let ch = Channel::PhaseDamping(lambda);
Self {
after_1q: Some(ch),
after_2q: None,
readout_error: 0.0,
}
}
#[must_use]
pub fn bit_flip(p: f64) -> Self {
assert!(
(0.0..=1.0).contains(&p),
"bit-flip probability {p} not in [0, 1]"
);
let ch = Channel::BitFlip(p);
Self {
after_1q: Some(ch),
after_2q: None,
readout_error: 0.0,
}
}
#[must_use]
pub fn dephasing(p: f64) -> Self {
assert!(
(0.0..=1.0).contains(&p),
"dephasing probability {p} not in [0, 1]"
);
let ch = Channel::Dephasing(p);
Self {
after_1q: Some(ch),
after_2q: None,
readout_error: 0.0,
}
}
}
#[derive(Clone, Debug)]
pub enum Channel {
Depolarizing(f64),
AmplitudeDamping(f64),
PhaseDamping(f64),
BitFlip(f64),
Dephasing(f64),
Custom(Vec<KrausOp>),
}
impl Channel {
#[must_use]
pub fn kraus_ops(&self) -> Vec<KrausOp> {
let c = |re, im| Complex64::new(re, im);
match *self {
Self::Depolarizing(p) => {
let a = (1.0 - p).sqrt();
let b = (p / 3.0).sqrt();
vec![
KrausOp([c(a, 0.0), c(0.0, 0.0), c(0.0, 0.0), c(a, 0.0)]),
KrausOp([c(0.0, 0.0), c(b, 0.0), c(b, 0.0), c(0.0, 0.0)]),
KrausOp([c(0.0, 0.0), c(0.0, -b), c(0.0, b), c(0.0, 0.0)]),
KrausOp([c(b, 0.0), c(0.0, 0.0), c(0.0, 0.0), c(-b, 0.0)]),
]
}
Self::AmplitudeDamping(gamma) => {
let k0_11 = (1.0 - gamma).sqrt();
let k1_01 = gamma.sqrt();
vec![
KrausOp([c(1.0, 0.0), c(0.0, 0.0), c(0.0, 0.0), c(k0_11, 0.0)]),
KrausOp([c(0.0, 0.0), c(k1_01, 0.0), c(0.0, 0.0), c(0.0, 0.0)]),
]
}
Self::PhaseDamping(lambda) => {
let k0_11 = (1.0 - lambda).sqrt();
let k1_11 = lambda.sqrt();
vec![
KrausOp([c(1.0, 0.0), c(0.0, 0.0), c(0.0, 0.0), c(k0_11, 0.0)]),
KrausOp([c(0.0, 0.0), c(0.0, 0.0), c(0.0, 0.0), c(k1_11, 0.0)]),
]
}
Self::BitFlip(p) => {
let a = (1.0 - p).sqrt();
let b = p.sqrt();
vec![
KrausOp([c(a, 0.0), c(0.0, 0.0), c(0.0, 0.0), c(a, 0.0)]),
KrausOp([c(0.0, 0.0), c(b, 0.0), c(b, 0.0), c(0.0, 0.0)]),
]
}
Self::Dephasing(p) => {
let a = (1.0 - p).sqrt();
let b = p.sqrt();
vec![
KrausOp([c(a, 0.0), c(0.0, 0.0), c(0.0, 0.0), c(a, 0.0)]),
KrausOp([c(b, 0.0), c(0.0, 0.0), c(0.0, 0.0), c(-b, 0.0)]),
]
}
Self::Custom(ref ops) => ops.clone(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn kraus_complete(ops: &[KrausOp]) -> bool {
let mut sum = [Complex64::ZERO; 4]; for k in ops {
let m = &k.0;
for i in 0..2 {
for j in 0..2 {
for l in 0..2 {
sum[i * 2 + j] += m[l * 2 + i].conj() * m[l * 2 + j];
}
}
}
}
let identity = [
Complex64::ONE,
Complex64::ZERO,
Complex64::ZERO,
Complex64::ONE,
];
sum.iter()
.zip(&identity)
.all(|(a, b)| (*a - *b).norm() < 1e-12)
}
#[test]
fn depolarizing_kraus_complete() {
for p in [0.0, 0.01, 0.1, 0.3, 0.75] {
let ops = Channel::Depolarizing(p).kraus_ops();
assert!(kraus_complete(&ops), "depolarizing p={p} not complete");
}
}
#[test]
fn amplitude_damping_kraus_complete() {
for gamma in [0.0, 0.05, 0.5, 1.0] {
let ops = Channel::AmplitudeDamping(gamma).kraus_ops();
assert!(
kraus_complete(&ops),
"amplitude_damping gamma={gamma} not complete"
);
}
}
#[test]
fn phase_damping_kraus_complete() {
for lambda in [0.0, 0.1, 0.9, 1.0] {
let ops = Channel::PhaseDamping(lambda).kraus_ops();
assert!(
kraus_complete(&ops),
"phase_damping lambda={lambda} not complete"
);
}
}
#[test]
fn bit_flip_kraus_complete() {
for p in [0.0, 0.2, 0.5, 1.0] {
let ops = Channel::BitFlip(p).kraus_ops();
assert!(kraus_complete(&ops), "bit_flip p={p} not complete");
}
}
#[test]
fn dephasing_kraus_complete() {
for p in [0.0, 0.3, 1.0] {
let ops = Channel::Dephasing(p).kraus_ops();
assert!(kraus_complete(&ops), "dephasing p={p} not complete");
}
}
}