aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2024-09-27 16:26:14 +0200
committerhachem <im@hachem.wtf>2024-09-27 16:26:14 +0200
commit82e938a96cc6b38ac1a75215cae56f100d1e7bb8 (patch)
treee7d1536731e607ac5cf2c7675817d1bd2986764b
parent1070a7ee073471af8442826cec54e720be266c7c (diff)
BasicRT first implementation
-rw-r--r--Cargo.toml2
-rw-r--r--libpsi-core/Cargo.toml1
-rw-r--r--libpsi-core/src/core/circuit.rs25
-rw-r--r--libpsi-core/src/core/component.rs26
-rw-r--r--libpsi-core/src/core/runtime.rs4
-rw-r--r--libpsi-core/src/runtimes/basic_rt.rs90
-rw-r--r--libpsi-tester/src/main.rs34
7 files changed, 162 insertions, 20 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 05cf0fd..bba566d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,4 +3,4 @@ resolver = "2"
members = [
"libpsi-core",
"libpsi-tester"
-] \ No newline at end of file
+]
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<usize>,
- control_indices: Vec<usize>,
- gate: QuantumGate,
+#[derive(Clone)]
+pub struct QuantumCircuitInstruction {
+ pub target_indices: Vec<usize>,
+ pub control_indices: Vec<usize>,
+ pub gate: QuantumGate,
}
-#[allow(dead_code)]
pub struct QuantumCircuit {
quantum_bits: Vec<QuantumBit>,
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<QuantumBit> {
+ self.quantum_bits.clone()
+ }
+
+ pub fn get_classical_registers(&self) -> ClassicalRegister {
+ self.classical_register.clone()
+ }
+
+ pub fn get_instructions(&self) -> Vec<QuantumCircuitInstruction> {
+ 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<i32>,
}
@@ -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<i32>) {
self.bits = bits;
}
+
+ pub fn get_bits(&self) -> Vec<i32> {
+ 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<Complex<f64>> = self.state.mul_matrix(gate).unwrap();
- self.qubits[index] = result;
- self.update();
+ pub fn get_bits(&self) -> Vec<QuantumBit> {
+ self.qubits.clone()
+ }
+
+ pub fn get_state(&self) -> ColumnVector<Complex<f64>> {
+ 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<QuantumBit>,
- classical_states: ClassicalRegister,
+ pub quantum_states: Vec<QuantumBit>,
+ 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<Complex<f64>>, 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<Complex<f64>>, 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<ExecutationData> {
let mut result: Vec<ExecutationData> = 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<QuantumBit> = Vec::new();
+ let mut target_bits: Vec<QuantumBit> = Vec::new();
+ let mut quantum_bits: Vec<QuantumBit> = 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
diff --git a/libpsi-tester/src/main.rs b/libpsi-tester/src/main.rs
index 2de001b..180df98 100644
--- a/libpsi-tester/src/main.rs
+++ b/libpsi-tester/src/main.rs
@@ -1,9 +1,37 @@
use libpsi_core::*;
+fn count_qubit_states(measurements: &[Vec<i32>], num_qubits: usize) -> Vec<i32> {
+ let mut counts = vec![0; num_qubits * 2];
+ for measurement in measurements {
+ for (i, &state) in measurement.iter().enumerate() {
+ if state == 0 {
+ counts[i] += 1;
+ } else {
+ counts[num_qubits + i] += 1;
+ }
+ }
+ }
+ counts
+}
+
fn main() {
- let mut circuit = QuantumCircuit::new(2, 2);
- circuit.apply(&gates::CNOT, &[0], &[1]);
+ let mut circuit = QuantumCircuit::new(1, 1);
+ circuit.apply(&gates::HADAMARD, &[], &[0]);
let runtime = BasicRT::new(circuit);
- runtime.execute(1024);
+ let execution_count = 1024;
+ let executions = runtime.execute(execution_count);
+
+ let mut measurements = Vec::new();
+ for execution in executions {
+ let bits = execution.classical_states.get_bits();
+ measurements.push(bits.clone());
+ }
+
+ let counts = count_qubit_states(&measurements, 1);
+ println!(
+ "{:.2} * |0> + {:.2} * |1>",
+ (counts[0] as f32) / execution_count as f32,
+ (counts[1] as f32) / execution_count as f32
+ );
}