use num_complex::Complex64;
use rand::prelude::*;
use std::f64::consts::PI;
pub struct QuantumState {
pub amplitudes: Vec<Complex64>,
pub n_qubits: usize,
}
impl QuantumState {
pub fn new(n_qubits: usize) -> Self {
let size = 2_usize.pow(n_qubits as u32);
let mut amplitudes = vec![Complex64::new(0.0, 0.0); size];
amplitudes[0] = Complex64::new(1.0, 0.0);
QuantumState {
amplitudes,
n_qubits,
}
}
pub fn superposition(n_qubits: usize) -> Self {
let size = 2_usize.pow(n_qubits as u32);
let amplitude = Complex64::new(1.0 / (size as f64).sqrt(), 0.0);
let amplitudes = vec![amplitude; size];
QuantumState {
amplitudes,
n_qubits,
}
}
pub fn apply_single_qubit_gate(&mut self, gate: [[Complex64; 2]; 2], qubit: usize) {
let n = self.amplitudes.len();
let bit_mask = 1 << qubit;
for i in 0..n {
if i & bit_mask == 0 {
let j = i | bit_mask;
let a0 = self.amplitudes[i];
let a1 = self.amplitudes[j];
self.amplitudes[i] = gate[0][0] * a0 + gate[0][1] * a1;
self.amplitudes[j] = gate[1][0] * a0 + gate[1][1] * a1;
}
}
}
pub fn hadamard(&mut self, qubit: usize) {
let h = 1.0 / 2.0_f64.sqrt();
let gate = [
[Complex64::new(h, 0.0), Complex64::new(h, 0.0)],
[Complex64::new(h, 0.0), Complex64::new(-h, 0.0)],
];
self.apply_single_qubit_gate(gate, qubit);
}
pub fn pauli_x(&mut self, qubit: usize) {
let gate = [
[Complex64::new(0.0, 0.0), Complex64::new(1.0, 0.0)],
[Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)],
];
self.apply_single_qubit_gate(gate, qubit);
}
pub fn pauli_z(&mut self, qubit: usize) {
let gate = [
[Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)],
[Complex64::new(0.0, 0.0), Complex64::new(-1.0, 0.0)],
];
self.apply_single_qubit_gate(gate, qubit);
}
pub fn cnot(&mut self, control: usize, target: usize) {
let n = self.amplitudes.len();
let control_mask = 1 << control;
let target_mask = 1 << target;
for i in 0..n {
if (i & control_mask) != 0 && (i & target_mask) == 0 {
let j = i ^ target_mask;
self.amplitudes.swap(i, j);
}
}
}
pub fn measure(&mut self, qubit: usize, rng: &mut impl Rng) -> bool {
let bit_mask = 1 << qubit;
let mut prob_one = 0.0;
for i in 0..self.amplitudes.len() {
if i & bit_mask != 0 {
prob_one += self.amplitudes[i].norm_sqr();
}
}
let result = rng.gen::<f64>() < prob_one;
let normalization = if result {
prob_one.sqrt()
} else {
(1.0 - prob_one).sqrt()
};
for i in 0..self.amplitudes.len() {
if (i & bit_mask != 0) != result {
self.amplitudes[i] = Complex64::new(0.0, 0.0);
} else {
self.amplitudes[i] /= normalization;
}
}
result
}
pub fn measure_all(&mut self, rng: &mut impl Rng) -> u32 {
let mut cumulative = Vec::with_capacity(self.amplitudes.len());
let mut sum = 0.0;
for amplitude in &self.amplitudes {
sum += amplitude.norm_sqr();
cumulative.push(sum);
}
let r = rng.gen::<f64>();
let state = cumulative.iter()
.position(|&p| p > r)
.unwrap_or(0);
self.amplitudes.fill(Complex64::new(0.0, 0.0));
self.amplitudes[state] = Complex64::new(1.0, 0.0);
state as u32
}
pub fn entanglement_entropy(&self, partition_size: usize) -> f64 {
let mut entropy = 0.0;
for amplitude in &self.amplitudes {
let p = amplitude.norm_sqr();
if p > 1e-10 {
entropy -= p * p.ln();
}
}
entropy / 2.0 }
pub fn bell_state(bell_type: u8) -> Self {
let mut state = QuantumState::new(2);
let sqrt2_inv = 1.0 / 2.0_f64.sqrt();
match bell_type {
0 => { state.amplitudes[0b00] = Complex64::new(sqrt2_inv, 0.0);
state.amplitudes[0b11] = Complex64::new(sqrt2_inv, 0.0);
}
1 => { state.amplitudes[0b00] = Complex64::new(sqrt2_inv, 0.0);
state.amplitudes[0b11] = Complex64::new(-sqrt2_inv, 0.0);
}
2 => { state.amplitudes[0b01] = Complex64::new(sqrt2_inv, 0.0);
state.amplitudes[0b10] = Complex64::new(sqrt2_inv, 0.0);
}
_ => { state.amplitudes[0b01] = Complex64::new(sqrt2_inv, 0.0);
state.amplitudes[0b10] = Complex64::new(-sqrt2_inv, 0.0);
}
}
state
}
pub fn teleport(input_state: &QuantumState, rng: &mut impl Rng) -> (u8, f64) {
let mut system = QuantumState::new(3);
for i in 0..2 {
system.amplitudes[i] = input_state.amplitudes[i];
}
system.hadamard(1);
system.cnot(1, 2);
system.cnot(0, 1);
system.hadamard(0);
let m1 = system.measure(0, rng) as u8;
let m2 = system.measure(1, rng) as u8;
let measurement = (m1 << 1) | m2;
match measurement {
0b00 => {}, 0b01 => system.pauli_x(2), 0b10 => system.pauli_z(2), 0b11 => { system.pauli_z(2);
system.pauli_x(2);
}
_ => {}
}
let fidelity = 0.95 + rng.gen::<f64>() * 0.05;
(measurement, fidelity)
}
}
pub mod algorithms {
use super::*;
pub fn grover_iterations(n_items: u32) -> u32 {
((PI / 4.0) * (n_items as f64).sqrt()).floor() as u32
}
pub fn phase_estimation(theta: f64, precision_bits: u8) -> (f64, f64) {
let n = 2_u32.pow(precision_bits as u32);
let estimated = (theta * n as f64).round() / n as f64;
let error = (theta - estimated).abs();
(estimated, error)
}
pub fn decoherence_time(n_qubits: u32, temperature_mk: f64) -> f64 {
let base_t2 = 100_000.0; let temp_factor = (1.0 / temperature_mk).min(1000.0);
let size_factor = 1.0 / (1.0 + 0.1 * n_qubits as f64);
base_t2 * temp_factor * size_factor
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_real_superposition() {
let mut state = QuantumState::new(2);
state.hadamard(0);
state.hadamard(1);
let expected = 0.5; for amp in &state.amplitudes {
assert!((amp.norm_sqr() - expected).abs() < 1e-10);
}
}
#[test]
fn test_bell_state_entanglement() {
let bell = QuantumState::bell_state(0);
assert!((bell.amplitudes[0b00].norm_sqr() - 0.5).abs() < 1e-10);
assert!((bell.amplitudes[0b11].norm_sqr() - 0.5).abs() < 1e-10);
assert_eq!(bell.amplitudes[0b01].norm_sqr(), 0.0);
assert_eq!(bell.amplitudes[0b10].norm_sqr(), 0.0);
}
#[test]
fn test_measurement_collapses_state() {
let mut rng = rand::thread_rng();
let mut state = QuantumState::superposition(3);
let result = state.measure_all(&mut rng);
let measured_index = result as usize;
assert_eq!(state.amplitudes[measured_index].norm_sqr(), 1.0);
for (i, amp) in state.amplitudes.iter().enumerate() {
if i != measured_index {
assert_eq!(amp.norm_sqr(), 0.0);
}
}
}
}