From 82e938a96cc6b38ac1a75215cae56f100d1e7bb8 Mon Sep 17 00:00:00 2001 From: hachem Date: Fri, 27 Sep 2024 16:26:14 +0200 Subject: BasicRT first implementation --- libpsi-core/Cargo.toml | 1 + libpsi-core/src/core/circuit.rs | 25 +++++++--- libpsi-core/src/core/component.rs | 26 +++++++++-- libpsi-core/src/core/runtime.rs | 4 +- libpsi-core/src/runtimes/basic_rt.rs | 90 +++++++++++++++++++++++++++++++++++- 5 files changed, 130 insertions(+), 16 deletions(-) (limited to 'libpsi-core') diff --git a/libpsi-core/Cargo.toml b/libpsi-core/Cargo.toml index 2657d02..6e73d65 100644 --- a/libpsi-core/Cargo.toml +++ b/libpsi-core/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" [dependencies] lazy_static = "1.5.0" libm = "0.2.8" +rand = "0.8.5" diff --git a/libpsi-core/src/core/circuit.rs b/libpsi-core/src/core/circuit.rs index 43f51d0..183c4a2 100644 --- a/libpsi-core/src/core/circuit.rs +++ b/libpsi-core/src/core/circuit.rs @@ -1,13 +1,12 @@ use super::{ClassicalRegister, QuantumBit, QuantumGate}; -#[allow(dead_code)] -struct QuantumCircuitInstruction { - target_indices: Vec, - control_indices: Vec, - gate: QuantumGate, +#[derive(Clone)] +pub struct QuantumCircuitInstruction { + pub target_indices: Vec, + pub control_indices: Vec, + pub gate: QuantumGate, } -#[allow(dead_code)] pub struct QuantumCircuit { quantum_bits: Vec, classical_register: ClassicalRegister, @@ -17,7 +16,7 @@ pub struct QuantumCircuit { impl QuantumCircuit { pub fn new(quantum_bit_count: usize, classical_bit_count: usize) -> QuantumCircuit { QuantumCircuit { - quantum_bits: Vec::with_capacity(quantum_bit_count), + quantum_bits: vec![QuantumBit::state_0(); quantum_bit_count], classical_register: ClassicalRegister::new(classical_bit_count), instructions: Vec::new(), } @@ -30,4 +29,16 @@ impl QuantumCircuit { control_indices: control_bits.to_vec(), }); } + + pub fn get_quantum_bits(&self) -> Vec { + self.quantum_bits.clone() + } + + pub fn get_classical_registers(&self) -> ClassicalRegister { + self.classical_register.clone() + } + + pub fn get_instructions(&self) -> Vec { + self.instructions.clone() + } } diff --git a/libpsi-core/src/core/component.rs b/libpsi-core/src/core/component.rs index 00462e5..09095ec 100644 --- a/libpsi-core/src/core/component.rs +++ b/libpsi-core/src/core/component.rs @@ -1,3 +1,5 @@ +use rand::Rng; + use crate::{complex, ColumnVector, Complex, Matrix, Vector, VectorMatrix}; use core::ops; @@ -34,6 +36,7 @@ macro_rules! quantum_register { }; } +#[derive(Clone)] pub struct ClassicalRegister { bits: Vec, } @@ -51,7 +54,10 @@ impl QuantumBit { let alpha_norm = alpha_abs * alpha_abs; let beta_norm = beta_abs * beta_abs; - if alpha_norm > beta_norm { + let mut rng = rand::thread_rng(); + let random_value = rng.gen_range(0.0..(alpha_norm as f32 + beta_norm as f32)); + + if random_value < alpha_norm as f32 { 0 } else { 1 @@ -77,6 +83,10 @@ impl ClassicalRegister { pub fn set_bits(&mut self, bits: Vec) { self.bits = bits; } + + pub fn get_bits(&self) -> Vec { + self.bits.clone() + } } impl QuantumRegister { @@ -105,10 +115,16 @@ impl QuantumRegister { classical_register.set_bits(self.qubits.iter().map(|qubit| qubit.measure()).collect()); } - pub fn apply(&mut self, gate: &QuantumGate, index: usize) { - let result: ColumnVector> = self.state.mul_matrix(gate).unwrap(); - self.qubits[index] = result; - self.update(); + pub fn get_bits(&self) -> Vec { + self.qubits.clone() + } + + pub fn get_state(&self) -> ColumnVector> { + self.state.clone() + } + + pub fn apply(&self, gate: &QuantumGate) -> QuantumBit { + self.state.mul_matrix(gate).unwrap() } } diff --git a/libpsi-core/src/core/runtime.rs b/libpsi-core/src/core/runtime.rs index f699d54..5b0a45f 100644 --- a/libpsi-core/src/core/runtime.rs +++ b/libpsi-core/src/core/runtime.rs @@ -2,8 +2,8 @@ use super::{ClassicalRegister, QuantumBit, QuantumCircuit}; #[allow(unused)] pub struct ExecutationData { - quantum_states: Vec, - classical_states: ClassicalRegister, + pub quantum_states: Vec, + pub classical_states: ClassicalRegister, } impl ExecutationData { diff --git a/libpsi-core/src/runtimes/basic_rt.rs b/libpsi-core/src/runtimes/basic_rt.rs index 78d6122..ed16205 100644 --- a/libpsi-core/src/runtimes/basic_rt.rs +++ b/libpsi-core/src/runtimes/basic_rt.rs @@ -1,4 +1,7 @@ -use crate::{ClassicalRegister, ExecutationData, QuantumCircuit, Runtime, RuntimeBase}; +use crate::{ + ColumnVector, Complex, ExecutationData, Numeric, QuantumBit, QuantumCircuit, QuantumRegister, + Runtime, RuntimeBase, Vector, +}; pub struct BasicRT { circuit: QuantumCircuit, @@ -10,6 +13,45 @@ impl RuntimeBase for BasicRT { } } +impl BasicRT { + fn calculate_state(state: &ColumnVector>, n: usize) -> QuantumBit { + let num_states = 1 << n; + let half_states = num_states >> 1; + + let mut alpha = Complex::zero(); + let mut beta = Complex::zero(); + + for i in 0..num_states { + if i < half_states { + alpha += state[i]; + } else { + beta += state[i]; + } + } + + QuantumBit::new(vec![alpha, beta]) + } + + fn calculate_probabilities(state: &ColumnVector>, n: usize) -> (f64, f64) { + let num_states = 1 << n; + let half_states = num_states >> 1; + + let mut state_0 = 0.0; + let mut state_1 = 0.0; + + for i in 0..num_states { + let prob = state[i].norm() * state[i].norm(); + if i < half_states { + state_0 += prob; + } else { + state_1 += prob; + } + } + + (state_0, state_1) + } +} + impl Runtime for BasicRT { fn new(circuit: QuantumCircuit) -> BasicRT { BasicRT { circuit } @@ -18,7 +60,51 @@ impl Runtime for BasicRT { fn execute(&self, repeat: usize) -> Vec { let mut result: Vec = Vec::with_capacity(repeat); for _ in 0..repeat { - let executation_data = ExecutationData::new(Vec::new(), ClassicalRegister::new(1)); + let mut executation_data = ExecutationData::new( + self.circuit.get_quantum_bits(), + self.circuit.get_classical_registers(), + ); + + for instruction in self.circuit.get_instructions() { + let mut control_bits: Vec = Vec::new(); + let mut target_bits: Vec = Vec::new(); + let mut quantum_bits: Vec = Vec::new(); + + for index in instruction.control_indices.clone() { + control_bits.push(executation_data.quantum_states.clone()[index].clone()); + quantum_bits.push(executation_data.quantum_states.clone()[index].clone()); + } + + for index in instruction.target_indices.clone() { + target_bits.push(executation_data.quantum_states.clone()[index].clone()); + quantum_bits.push(executation_data.quantum_states.clone()[index].clone()); + } + + if control_bits.len() > 0 { + let control_register = QuantumRegister::from(&mut control_bits); + let control_register_state_vector = control_register.get_state(); + let (control_register_state_0, control_register_state_1) = + BasicRT::calculate_probabilities( + &control_register_state_vector, + control_register.get_bits().len(), + ); + + if control_register_state_0 > control_register_state_1 { + continue; + } + } + + let target_register = QuantumRegister::from(&mut quantum_bits); + let target_state_vector = target_register.apply(&instruction.gate); + let target_state = + BasicRT::calculate_state(&target_state_vector, quantum_bits.len()); + executation_data.quantum_states[instruction.target_indices.clone()[0]] = + target_state; + } + + let final_quantum_register = + QuantumRegister::from(&mut executation_data.quantum_states.clone()); + final_quantum_register.measure(&mut executation_data.classical_states); result.push(executation_data); } result -- cgit v1.3