#![doc = include_str!("../README.md")]
pub mod circuit;
pub mod counts;
pub mod instruction;
pub mod matrix_product_state;
pub mod prelude;
pub mod rayon_cond;
pub mod simulator_traits;
pub mod sparse_mat;
pub mod sparse_quantum_state;
pub mod stabilizer;
pub mod state_vector;
pub use ndarray;
pub use num;
pub use rand;
pub use rayon;
#[cfg(test)]
mod tests {
use ndarray::Array2;
use num::Complex;
use crate::circuit::Circuit;
use crate::instruction::quantum_fourier_transform;
use crate::instruction::Instruction;
use crate::instruction::PauliKind;
use crate::matrix_product_state::MPS;
use crate::simulator_traits::Simulator;
use crate::stabilizer::Stabilizer;
use crate::state_vector::QuantumStateVector;
use num::complex::ComplexFloat;
#[macro_export]
macro_rules! assert_approx_eq {
($a:expr, $b:expr) => {{
let eps = 1.0e-6;
let (a, b) = (&$a, &$b);
assert!(
(*a - *b).abs() < eps,
"assertion failed: `(left !== right)`
(left: `{:?}`, right: `{:?}`, expect diff: `{:?}`, real diff: `{:?}`)",
*a,
*b,
eps,
(*a - *b).abs()
);
}};
($a:expr, $b:expr, $eps:expr) => {{
let (a, b) = (&$a, &$b);
let eps = $eps;
assert!(
(*a - *b).abs() < eps,
"assertion failed: `(left !== right)`
(left: `{:?}`, right: `{:?}`, expect diff: `{:?}`, real diff: `{:?}`)",
*a,
*b,
eps,
(*a - *b).abs()
);
}};
}
#[test]
fn sparse() {
QuantumStateVector::new(31);
}
#[test]
fn bell() {
let circuit = Circuit {
ins: vec![
Instruction::hadamard(0),
Instruction::cnot([0, 1]),
Instruction::Measure {
indices: vec![0, 1],
},
],
n: 2,
};
let machine = QuantumStateVector::new(2);
let counts: Vec<i32> = machine
.get_counts(&circuit, 1000)
.data
.values()
.cloned()
.collect();
assert!((counts[0] - 500).abs() + (counts[1] - 500).abs() < 50);
let machine = Stabilizer::new(2);
let counts: Vec<i32> = machine
.get_counts(&circuit, 1000)
.data
.values()
.cloned()
.collect();
assert!((counts[0] - 500).abs() + (counts[1] - 500).abs() < 50);
}
#[test]
fn statevec_pauli() {
let mut machine = QuantumStateVector::new(1);
machine.execute_instruction(&Instruction::not(0));
assert_eq!(machine.state.get(0), Complex::new(0.0, 0.0)); assert_eq!(machine.state.get(1), Complex::new(1.0, 0.0));
let mut machine = QuantumStateVector::new(1);
machine.execute_instruction(&Instruction::Pauli {
kind: PauliKind::Y,
target: 0,
});
assert_eq!(machine.state.get(1), Complex::new(0.0, 1.0));
let mut machine = QuantumStateVector::new(1);
machine.state.set(0, Complex::new(1.0 / 2.0.sqrt(), 0.0));
machine.state.set(1, Complex::new(1.0 / 2.0.sqrt(), 0.0));
machine.execute_instruction(&Instruction::Pauli {
kind: PauliKind::Z,
target: 0,
});
assert_approx_eq!(machine.state.get(0), Complex::new(1.0 / 2.0.sqrt(), 0.0));
assert_approx_eq!(machine.state.get(1), Complex::new(-1.0 / 2.0.sqrt(), 0.0));
}
#[test]
fn deutsch() {
let circuit = Circuit {
ins: vec![
Instruction::not(1),
Instruction::hadamard(0),
Instruction::hadamard(1),
Instruction::cnot([0, 1]),
Instruction::hadamard(0),
Instruction::Measure { indices: vec![0] },
],
n: 2,
};
let machine = QuantumStateVector::new(2);
let counts: Vec<i32> = machine
.get_counts(&circuit, 1000)
.data
.values()
.cloned()
.collect();
assert_eq!(counts[0], 999);
let machine = Stabilizer::new(2);
let counts: Vec<i32> = machine
.get_counts(&circuit, 1000)
.data
.values()
.cloned()
.collect();
assert_eq!(counts[0], 999);
}
#[test]
fn qft() {
let machine = QuantumStateVector::new(1);
let hadamard = {
let mut c = machine.clone();
c.execute_instruction(&Instruction::hadamard(0));
c
};
let quantumft = {
let mut k = machine.clone();
let c = quantum_fourier_transform(1);
k.execute_circuit(&c);
k
};
assert_eq!(hadamard.state.to_vec(), quantumft.state.to_vec())
}
#[test]
fn rng() {
let n = 8;
let machine = QuantumStateVector::new(n);
let mut h: Vec<Instruction> = (0..n).map(|x| Instruction::hadamard(x)).collect();
h.push(Instruction::Measure {
indices: (0..n).collect(),
});
h.push(Instruction::MeasureState);
let ci = Circuit { ins: h, n };
let co = machine.get_counts(&ci, 1).data;
let k = co.keys().nth(0).unwrap();
assert!(u8::from_str_radix(k, 2).is_ok());
}
#[test]
fn mps() {
let pauli_z = Array2::from_shape_vec((2, 2), vec![1.0_f32, 0.0, 0.0, -1.0])
.unwrap()
.mapv(|x| Complex::new(x, 0.0));
let pauli_x = Array2::from_shape_vec((2, 2), vec![0.0_f32, 1.0, 1.0, 0.0])
.unwrap()
.mapv(|x| Complex::new(x, 0.0));
let pauli_y = Array2::from_shape_vec((2, 2), vec![0.0_f32, -1.0, 1.0, 0.0])
.unwrap()
.mapv(|x| Complex::new(0.0, x));
let mut mps = MPS::new(5, 1);
mps.execute_instruction(&Instruction::not(0));
let expe = mps.expectation_value_sq(&pauli_z, 0);
assert_approx_eq!(expe.re, -1.0);
let expe = mps.expectation_value_sq(&pauli_z, 1);
assert_approx_eq!(expe.re, 1.0);
mps.execute_instruction(&Instruction::hadamard(2));
let expe = mps.expectation_value_sq(&pauli_x, 2);
assert_approx_eq!(expe.re, 1.0);
mps.execute_instruction(&Instruction::not(3));
mps.execute_instruction(&Instruction::hadamard(3));
let expe = mps.expectation_value_sq(&pauli_x, 3);
assert_approx_eq!(expe.re, -1.0);
mps.execute_instruction(&Instruction::hadamard(4));
mps.execute_instruction(&Instruction::s_gate(4));
let expe = mps.expectation_value_sq(&pauli_y, 4);
assert_approx_eq!(expe, 1.0);
}
#[test]
pub fn mps_hadamard() {
let mut mps = MPS::new(1, 1);
mps.execute_instruction(&Instruction::hadamard(0));
mps.measure_state();
assert!(mps.reg == 0 || mps.reg == 1)
}
#[test]
pub fn test_no_depolarization() {
let mut machine = QuantumStateVector::new(1);
let not_applied = machine.clone();
machine.apply_local_depolarizing_noise(0, 0.0);
assert_eq!(machine.state.to_vec(), not_applied.state.to_vec());
}
#[test]
pub fn test_full_depolarization() {
let mut machine = QuantumStateVector::new(1);
machine.apply_local_depolarizing_noise(0, 1.0);
}
#[test]
pub fn test_conditional() {
let mut machine = QuantumStateVector::new(2);
machine.execute_instruction(&Instruction::Pauli {
kind: PauliKind::X,
target: 0,
});
machine.measure_qubits(&[0], 0.0);
machine.execute_instruction(&Instruction::ConditionalInstruction {
indices: vec![0],
condition: |a| a[0],
inst: Box::new([Instruction::Pauli {
kind: PauliKind::X,
target: 1,
}]),
});
machine.measure_qubits(&[1], 0.0);
assert_eq!(machine.reg, 0b11);
}
#[test]
pub fn circuit_to_gate() {
let pure_circuit = Circuit {
ins: vec![
Instruction::not(1),
Instruction::hadamard(0),
Instruction::hadamard(1),
Instruction::cnot([0, 1]),
Instruction::hadamard(0),
],
n: 2,
};
let gate = pure_circuit.to_gate().unwrap();
let circuit = Circuit {
ins: vec![gate, Instruction::Measure { indices: vec![0] }],
n: 2,
};
let machine = QuantumStateVector::new(2);
let counts: Vec<i32> = machine
.get_counts(&circuit, 1000)
.data
.values()
.cloned()
.collect();
assert_eq!(counts[0], 999);
}
}