use ndarray::Array2;
use num::Complex;
use rand::{distributions::WeightedIndex, prelude::Distribution, rngs::ThreadRng, Rng};
use crate::{
circuit::Circuit,
counts::Counts,
instruction::{Instruction, PauliKind},
};
pub trait Simulator {
fn execute_instruction(&mut self, ins: &Instruction);
fn execute_circuit(&mut self, circuit: &Circuit);
fn get_counts(&self, circuit: &Circuit, n: usize) -> Counts;
fn get_random(&mut self) -> &mut ThreadRng;
fn apply_local_depolarizing_noise(&mut self, target: usize, p: f32) {
let rng = self.get_random();
let pauli_kinds = [
None,
Some(PauliKind::X),
Some(PauliKind::Y),
Some(PauliKind::Z),
];
let weights = [1.0 - p, p / 3.0, p / 3.0, p / 3.0];
let dist = WeightedIndex::new(weights).unwrap();
let op = pauli_kinds[dist.sample(rng)];
if let Some(k) = op {
self.execute_instruction(&Instruction::Pauli { kind: k, target });
}
}
fn apply_amplitude_damping(&mut self, target: usize, gamma: f32) {
let e0 = Array2::from_shape_vec(
(2, 2),
vec![
Complex::new(1.0, 0.0),
Complex::new(0.0, 0.0),
Complex::new(0.0, 0.0),
Complex::new((1.0 - gamma).sqrt(), 0.0),
],
)
.unwrap();
let e1 = Array2::from_shape_vec(
(2, 2),
vec![
Complex::new(0.0, 0.0),
Complex::new(gamma.sqrt(), 0.0),
Complex::new(0.0, 0.0),
Complex::new(0.0, 0.0),
],
)
.unwrap();
let k = self.get_random().gen_range(0.0..1.0);
self.execute_instruction(&Instruction::Gate {
matrix: std::borrow::Cow::Owned(if k < gamma { e1 } else { e0 }),
indices: vec![target],
kind: None,
});
}
}