From 53287a755cc8bcef8b4c1324f1ed1f34224e15c4 Mon Sep 17 00:00:00 2001 From: hachem Date: Sun, 22 Sep 2024 10:11:02 +0200 Subject: rename project to psi --- Cargo.toml | 5 +- libmu/Cargo.toml | 7 - libmu/src/core/component.rs | 51 ------ libmu/src/core/mod.rs | 1 - libmu/src/lib.rs | 9 - libmu/src/maths/complex.rs | 219 ---------------------- libmu/src/maths/matrix.rs | 245 ------------------------- libmu/src/maths/mod.rs | 8 - libmu/src/maths/numeric_types.rs | 152 ---------------- libmu/src/maths/vector.rs | 374 -------------------------------------- libpsi-tester/Cargo.toml | 7 + libpsi-tester/src/main.rs | 8 + libpsi/Cargo.toml | 7 + libpsi/src/core/component.rs | 51 ++++++ libpsi/src/core/mod.rs | 1 + libpsi/src/lib.rs | 9 + libpsi/src/maths/complex.rs | 219 ++++++++++++++++++++++ libpsi/src/maths/matrix.rs | 245 +++++++++++++++++++++++++ libpsi/src/maths/mod.rs | 8 + libpsi/src/maths/numeric_types.rs | 152 ++++++++++++++++ libpsi/src/maths/vector.rs | 374 ++++++++++++++++++++++++++++++++++++++ mu/Cargo.toml | 7 - mu/src/main.rs | 8 - 23 files changed, 1084 insertions(+), 1083 deletions(-) delete mode 100644 libmu/Cargo.toml delete mode 100644 libmu/src/core/component.rs delete mode 100644 libmu/src/core/mod.rs delete mode 100644 libmu/src/lib.rs delete mode 100644 libmu/src/maths/complex.rs delete mode 100644 libmu/src/maths/matrix.rs delete mode 100644 libmu/src/maths/mod.rs delete mode 100644 libmu/src/maths/numeric_types.rs delete mode 100644 libmu/src/maths/vector.rs create mode 100644 libpsi-tester/Cargo.toml create mode 100644 libpsi-tester/src/main.rs create mode 100644 libpsi/Cargo.toml create mode 100644 libpsi/src/core/component.rs create mode 100644 libpsi/src/core/mod.rs create mode 100644 libpsi/src/lib.rs create mode 100644 libpsi/src/maths/complex.rs create mode 100644 libpsi/src/maths/matrix.rs create mode 100644 libpsi/src/maths/mod.rs create mode 100644 libpsi/src/maths/numeric_types.rs create mode 100644 libpsi/src/maths/vector.rs delete mode 100644 mu/Cargo.toml delete mode 100644 mu/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index 26ca50d..d82fbd0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] +resolver = "2" members = [ - "libmu", - "mu" + "libpsi", + "libpsi-tester" ] \ No newline at end of file diff --git a/libmu/Cargo.toml b/libmu/Cargo.toml deleted file mode 100644 index b495ce6..0000000 --- a/libmu/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "libmu" -version = "0.1.0" -edition = "2021" - -[dependencies] -libm = "0.2.8" diff --git a/libmu/src/core/component.rs b/libmu/src/core/component.rs deleted file mode 100644 index bd18b52..0000000 --- a/libmu/src/core/component.rs +++ /dev/null @@ -1,51 +0,0 @@ -use crate::{ColumnVector, Complex, Matrix, VectorMatrix}; - -pub type QuantumRegister = ColumnVector>; -pub type QuantumBit = ColumnVector>; - -#[macro_export] -macro_rules! count { - () => { 0 }; - ($head:expr $(,$tail:expr)*) => { 1 + count!($( $tail ),*) }; -} - -#[macro_export] -macro_rules! qubit { - ($(($re:expr, $im:expr)),*) => { - { - let mut vector = Vec::new(); - $( - vector.push(complex!($re, $im)); - )* - QuantumBit::new(vector) - } - }; -} - -#[macro_export] -macro_rules! quantum_register { - ($($bit:expr),*) => { - { - const N: usize = count!($($bit),*); - let bits: [QuantumBit; N] = [$($bit),*]; - QuantumRegister::from(&bits) - } - }; -} - -impl QuantumBit { - pub fn get_state(&self) -> i32 { - (self[1] != Complex::new(0.0, 0.0)) as i32 - } -} - -impl QuantumRegister { - pub fn from(bits: &[QuantumBit]) -> QuantumRegister { - let matrices: Vec>> = bits.iter().map(|bit| bit.to_matrix()).collect(); - let mut result = matrices[0].clone(); - for matrix in &matrices[1..] { - result = result.kronecker(matrix); - } - ColumnVector::from_matrix(&result) - } -} diff --git a/libmu/src/core/mod.rs b/libmu/src/core/mod.rs deleted file mode 100644 index 9cea807..0000000 --- a/libmu/src/core/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod component; diff --git a/libmu/src/lib.rs b/libmu/src/lib.rs deleted file mode 100644 index 9cbd644..0000000 --- a/libmu/src/lib.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod core; -mod maths; - -pub use maths::complex::*; -pub use maths::matrix::*; -pub use maths::numeric_types::*; -pub use maths::vector::*; - -pub use core::component::*; diff --git a/libmu/src/maths/complex.rs b/libmu/src/maths/complex.rs deleted file mode 100644 index 28a3121..0000000 --- a/libmu/src/maths/complex.rs +++ /dev/null @@ -1,219 +0,0 @@ -use crate::Float; -use core::{fmt, ops}; - -#[macro_export] -macro_rules! complex { - ($real:expr, $imaginary:expr) => { - $crate::Complex::new($real, $imaginary) - }; -} - -#[derive(Copy, Clone, PartialOrd, PartialEq)] -pub struct Complex { - pub real: T, - pub imaginary: T, -} - -impl fmt::Debug for Complex { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "Complex {{ real: {:?}, imaginary: {:?} }}", - self.real, self.imaginary - ) - } -} - -impl fmt::Display for Complex { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{} + {}i", self.real, self.imaginary) - } -} - -impl Complex { - pub fn new(real: T, imaginary: T) -> Complex { - Complex { real, imaginary } - } - - pub fn get_conjugate(&self) -> Complex { - Complex { - real: self.real, - imaginary: -self.imaginary, - } - } - - pub fn conjugate(&mut self) { - self.imaginary = -self.imaginary; - } - - pub fn phase(&self) -> T { - T::atan2(self.imaginary, self.real) - } - - pub fn norm(&self) -> T { - self.real * self.real + self.imaginary * self.imaginary - } - - pub fn abs(&self) -> T { - T::sqrt(self.norm()) - } -} - -impl ops::Neg for Complex { - type Output = Complex; - - fn neg(self) -> Complex { - Complex { - real: -self.real, - imaginary: -self.imaginary, - } - } -} - -impl ops::Add for Complex { - type Output = Complex; - - fn add(self, other: Complex) -> Complex { - Complex { - real: self.real + other.real, - imaginary: self.imaginary + other.imaginary, - } - } -} - -impl ops::Sub for Complex { - type Output = Complex; - - fn sub(self, other: Complex) -> Complex { - Complex { - real: self.real - other.real, - imaginary: self.imaginary - other.imaginary, - } - } -} - -impl ops::Mul for Complex { - type Output = Complex; - - fn mul(self, other: Complex) -> Complex { - Complex { - real: self.real * other.real - self.imaginary * other.imaginary, - imaginary: self.real * other.imaginary + self.imaginary * other.real, - } - } -} - -impl ops::Div for Complex { - type Output = Complex; - - fn div(self, other: Complex) -> Complex { - let denom = other.real * other.real + other.imaginary * other.imaginary; - Complex { - real: (self.real * other.real + self.imaginary * other.imaginary) / denom, - imaginary: (self.imaginary * other.real - self.real * other.imaginary) / denom, - } - } -} - -impl ops::Add for Complex { - type Output = Complex; - - fn add(self, other: T) -> Complex { - Complex { - real: self.real + other, - imaginary: self.imaginary, - } - } -} - -impl ops::Sub for Complex { - type Output = Complex; - - fn sub(self, other: T) -> Complex { - Complex { - real: self.real - other, - imaginary: self.imaginary, - } - } -} - -impl ops::Mul for Complex { - type Output = Complex; - - fn mul(self, other: T) -> Complex { - Complex { - real: self.real * other, - imaginary: self.imaginary * other, - } - } -} - -impl ops::Div for Complex { - type Output = Complex; - - fn div(self, other: T) -> Complex { - Complex { - real: self.real / other, - imaginary: self.imaginary / other, - } - } -} - -impl ops::AddAssign for Complex { - fn add_assign(&mut self, other: Complex) { - self.real += other.real; - self.imaginary += other.imaginary; - } -} - -impl ops::SubAssign for Complex { - fn sub_assign(&mut self, other: Complex) { - self.real -= other.real; - self.imaginary -= other.imaginary; - } -} - -impl ops::MulAssign for Complex { - fn mul_assign(&mut self, other: Complex) { - let new_real = self.real * other.real - self.imaginary * other.imaginary; - let new_imaginary = self.real * other.imaginary + self.imaginary * other.real; - self.real = new_real; - self.imaginary = new_imaginary; - } -} - -impl ops::DivAssign for Complex { - fn div_assign(&mut self, other: Complex) { - let denom = other.real * other.real + other.imaginary * other.imaginary; - let new_real = (self.real * other.real + self.imaginary * other.imaginary) / denom; - let new_imaginary = (self.imaginary * other.real - self.real * other.imaginary) / denom; - self.real = new_real; - self.imaginary = new_imaginary; - } -} - -impl ops::AddAssign for Complex { - fn add_assign(&mut self, other: T) { - self.real += other; - } -} - -impl ops::SubAssign for Complex { - fn sub_assign(&mut self, other: T) { - self.real -= other; - } -} - -impl ops::MulAssign for Complex { - fn mul_assign(&mut self, other: T) { - self.real *= other; - self.imaginary *= other; - } -} - -impl ops::DivAssign for Complex { - fn div_assign(&mut self, other: T) { - self.real /= other; - self.imaginary /= other; - } -} diff --git a/libmu/src/maths/matrix.rs b/libmu/src/maths/matrix.rs deleted file mode 100644 index 388f858..0000000 --- a/libmu/src/maths/matrix.rs +++ /dev/null @@ -1,245 +0,0 @@ -// TODO(Hachem): Refactor - -use super::Float; -use core::{fmt, ops}; - -#[macro_export] -macro_rules! matrix { - ( $( $( $x:expr ),* );* ) => {{ - let mut data = Vec::new(); - let mut rows = 0; - let mut cols = 0; - - $( - let row_data = $( $x )*; - if cols == 0 { - cols = row_data.len(); - } - assert_eq!(cols, row_data.len(), "All rows must have the same number of columns."); - data.extend(row_data); - rows += 1; - )* - - $crate::Matrix::new(rows, cols, data) - }}; -} - -#[derive(Clone)] -pub struct Matrix { - pub data: Vec, - pub rows: usize, - pub cols: usize, -} - -impl Matrix { - pub fn new(rows: usize, cols: usize, data: Vec) -> Self { - Matrix { data, rows, cols } - } - - pub fn get(&self, row: usize, col: usize) -> T { - self.data[row * self.cols + col] - } - - pub fn set(&mut self, row: usize, col: usize, value: T) { - self.data[row * self.cols + col] = value; - } - - pub fn dot(&self, other: &Self) -> Option> { - if self.cols != other.rows { - return None; - } - - let mut result = Matrix::new( - self.rows, - other.cols, - vec![T::zero(); self.rows * other.cols], - ); - for i in 0..self.rows { - for j in 0..other.cols { - let mut sum = T::zero(); - for k in 0..self.cols { - sum = sum + (self.get(i, k) * other.get(k, j)); - } - result.set(i, j, sum); - } - } - Some(result) - } - - pub fn kronecker(&self, other: &Self) -> Matrix { - let new_rows = self.rows * other.rows; - let new_cols = self.cols * other.cols; - - let mut result = Matrix::new(new_rows, new_cols, vec![T::zero(); new_rows * new_cols]); - - for i in 0..self.rows { - for j in 0..self.cols { - let self_val = self.get(i, j); - for k in 0..other.rows { - for l in 0..other.cols { - let result_row = i * other.rows + k; - let result_col = j * other.cols + l; - result.set(result_row, result_col, self_val.clone() * other.get(k, l)); - } - } - } - } - - result - } - - pub fn transpose(&self) -> Matrix { - let mut result = Matrix::new(self.cols, self.rows, vec![T::zero(); self.cols * self.rows]); - - for i in 0..self.rows { - for j in 0..self.cols { - let value = self.get(i, j); - result.set(j, i, value); - } - } - - result - } - - pub fn add_to(&self, other: &Self) -> Option> { - if self.rows != other.rows || self.cols != other.cols { - return None; - } - - let mut result = Matrix::new(self.rows, self.cols, vec![T::zero(); self.rows * self.cols]); - - for i in 0..self.rows { - for j in 0..self.cols { - let sum = self.get(i, j) + other.get(i, j); - result.set(i, j, sum); - } - } - Some(result) - } - - pub fn subtract(&self, other: &Self) -> Option> { - if self.rows != other.rows || self.cols != other.cols { - return None; - } - - let mut result = Matrix::new(self.rows, self.cols, vec![T::zero(); self.rows * self.cols]); - - for i in 0..self.rows { - for j in 0..self.cols { - let diff = self.get(i, j) - other.get(i, j); - result.set(i, j, diff); - } - } - Some(result) - } - - pub fn scale(&self, scalar: T) -> Matrix { - let mut result = Matrix::new(self.rows, self.cols, vec![T::zero(); self.rows * self.cols]); - - for i in 0..self.rows { - for j in 0..self.cols { - let scaled_value = self.get(i, j) * scalar; - result.set(i, j, scaled_value); - } - } - result - } -} - -impl ops::Index<(usize, usize)> for Matrix { - type Output = T; - - fn index(&self, index: (usize, usize)) -> &Self::Output { - &self.data[index.0 * self.cols + index.1] - } -} - -impl ops::IndexMut<(usize, usize)> for Matrix { - fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output { - &mut self.data[index.0 * self.cols + index.1] - } -} - -impl fmt::Debug for Matrix { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for i in 0..self.rows { - for j in 0..self.cols { - write!(f, "{:?} ", self.get(i, j))?; - } - writeln!(f)?; - } - Ok(()) - } -} - -impl fmt::Display for Matrix { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for i in 0..self.rows { - for j in 0..self.cols { - write!(f, "{:>8} ", self.get(i, j))?; - } - writeln!(f)?; - } - Ok(()) - } -} - -impl ops::Add<&Matrix> for Matrix { - type Output = Option>; - - fn add(self, other: &Matrix) -> Self::Output { - self.add_to(other) - } -} - -impl ops::Sub<&Matrix> for Matrix { - type Output = Option>; - - fn sub(self, other: &Matrix) -> Self::Output { - self.subtract(other) - } -} - -impl ops::Mul for Matrix { - type Output = Matrix; - - fn mul(self, scalar: T) -> Self::Output { - self.scale(scalar) - } -} - -impl ops::Div for Matrix { - type Output = Matrix; - - fn div(self, scalar: T) -> Self::Output { - self.scale(T::one() / scalar) - } -} - -impl ops::AddAssign<&Matrix> for Matrix { - fn add_assign(&mut self, other: &Matrix) { - if let Some(result) = self.add_to(other) { - *self = result; - } - } -} - -impl ops::SubAssign<&Matrix> for Matrix { - fn sub_assign(&mut self, other: &Matrix) { - if let Some(result) = self.subtract(other) { - *self = result; - } - } -} - -impl ops::MulAssign for Matrix { - fn mul_assign(&mut self, scalar: T) { - *self = self.scale(scalar); - } -} - -impl ops::DivAssign for Matrix { - fn div_assign(&mut self, scalar: T) { - *self = self.scale(T::one() / scalar); - } -} diff --git a/libmu/src/maths/mod.rs b/libmu/src/maths/mod.rs deleted file mode 100644 index 734cfb4..0000000 --- a/libmu/src/maths/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub mod complex; -pub mod matrix; -pub mod numeric_types; -pub mod vector; - -pub use complex::*; -pub use matrix::*; -pub use numeric_types::*; diff --git a/libmu/src/maths/numeric_types.rs b/libmu/src/maths/numeric_types.rs deleted file mode 100644 index f1355de..0000000 --- a/libmu/src/maths/numeric_types.rs +++ /dev/null @@ -1,152 +0,0 @@ -use super::Complex; -use core::ops; - -pub trait Numeric: - Copy - + PartialOrd - + ops::Add - + ops::Mul - + ops::Sub - + ops::Div - + ops::Neg - + ops::AddAssign - + ops::SubAssign - + ops::MulAssign - + ops::DivAssign -{ - fn zero() -> Self; - fn one() -> Self; -} - -pub trait Integer: Numeric {} -pub trait Float: Numeric { - fn sqrt(self) -> Self; - fn atan2(y: Self, x: Self) -> Self; -} - -impl Float for f32 { - fn sqrt(self) -> Self { - libm::sqrtf(self) - } - - fn atan2(y: Self, x: Self) -> Self { - libm::atan2f(y, x) - } -} - -impl Float for f64 { - fn sqrt(self) -> Self { - libm::sqrt(self) - } - - fn atan2(y: Self, x: Self) -> Self { - libm::atan2(y, x) - } -} - -impl Float for Complex { - fn sqrt(self) -> Self { - let r = self.abs(); - let theta = self.phase(); - - let sqrt_r = libm::sqrtf(r); - let sqrt_theta = theta / 2.0; - - Complex::new( - sqrt_r * libm::cosf(sqrt_theta), - sqrt_r * libm::sinf(sqrt_theta), - ) - } - - fn atan2(y: Self, x: Self) -> Self { - Complex::new( - libm::atan2f(y.real, x.real), - libm::atan2f(y.imaginary, x.imaginary), - ) - } -} - -impl Float for Complex { - fn sqrt(self) -> Self { - let r = self.abs(); - let theta = self.phase(); - - let sqrt_r = libm::sqrt(r); - let sqrt_theta = theta / 2.0; - - Complex::new( - sqrt_r * libm::cos(sqrt_theta), - sqrt_r * libm::sin(sqrt_theta), - ) - } - - fn atan2(y: Self, x: Self) -> Self { - Complex::new( - libm::atan2(y.real, x.real), - libm::atan2(y.imaginary, x.imaginary), - ) - } -} - -impl Integer for i64 {} -impl Integer for i32 {} - -impl Numeric for i32 { - fn zero() -> Self { - 0 - } - - fn one() -> Self { - 1 - } -} - -impl Numeric for i64 { - fn zero() -> Self { - 0 - } - - fn one() -> Self { - 1 - } -} - -impl Numeric for f32 { - fn zero() -> Self { - 0.0 - } - - fn one() -> Self { - 1.0 - } -} - -impl Numeric for f64 { - fn zero() -> Self { - 0.0 - } - - fn one() -> Self { - 1.0 - } -} - -impl Numeric for Complex { - fn zero() -> Self { - Complex::new(0.0, 0.0) - } - - fn one() -> Self { - Complex::new(1.0, 0.0) - } -} - -impl Numeric for Complex { - fn zero() -> Self { - Complex::new(0.0, 0.0) - } - - fn one() -> Self { - Complex::new(1.0, 0.0) - } -} diff --git a/libmu/src/maths/vector.rs b/libmu/src/maths/vector.rs deleted file mode 100644 index 0c13e4c..0000000 --- a/libmu/src/maths/vector.rs +++ /dev/null @@ -1,374 +0,0 @@ -// TODO(Hachem): Operators Matrix/Vector don't work -// TODO(Hachem): Refactor - -use super::{Float, Matrix}; -use core::{fmt, ops}; - -#[macro_export] -macro_rules! row_vector { - ($($x:expr),*) => { - RowVector::new(vec![$($x),*]) - }; - ($($x:expr,)*) => { - RowVector::new(vec![$($x),*]) - }; -} - -#[macro_export] -macro_rules! column_vector { - ($($x:expr),*) => { - ColumnVector::new(vec![$($x),*]) - }; - ($($x:expr,)*) => { - ColumnVector::new(vec![$($x),*]) - }; -} - -pub trait Vector { - fn new(data: Vec) -> Self; - fn get(&self, index: usize) -> T; - fn set(&mut self, index: usize, value: T); - fn size(&self) -> usize; - - fn dot(&self, other: &Self) -> T; - fn norm(&self) -> T; - - fn max(&self) -> T; - fn min(&self) -> T; - fn sum(&self) -> T; -} - -pub trait VectorMatrix { - fn from_matrix(matrix: &Matrix) -> Self; - fn to_matrix(&self) -> Matrix; -} - -pub struct VectorImpl(Vec); -pub type RowVector = VectorImpl; -pub type ColumnVector = VectorImpl; - -impl ColumnVector { - pub fn mul_matrix(&self, matrix: &Matrix) -> Option> { - if matrix.cols != self.size() { - return None; - } - - let mut result = ColumnVector::new(vec![T::zero(); matrix.rows]); - - for i in 0..matrix.rows { - let mut sum = T::zero(); - for j in 0..matrix.cols { - sum = sum + (matrix.get(i, j) * self.get(j)); - } - result.set(i, sum); - } - - Some(result) - } - - pub fn transpose(&self) -> RowVector { - RowVector::new(self.0.clone()) - } -} - -impl RowVector { - pub fn mul_matrix(&self, matrix: &Matrix) -> Option> { - if self.size() != matrix.rows { - return None; - } - - let mut result = RowVector::new(vec![T::zero(); matrix.cols]); - - for j in 0..matrix.cols { - let mut sum = T::zero(); - for i in 0..matrix.rows { - sum = sum + (self.get(i) * matrix.get(i, j)); - } - result.set(j, sum); - } - - Some(result) - } - - pub fn transpose(&self) -> ColumnVector { - ColumnVector::new(self.0.clone()) - } -} - -impl Vector for VectorImpl { - fn new(data: Vec) -> Self { - Self(data) - } - - fn get(&self, index: usize) -> T { - self.0[index] - } - - fn set(&mut self, index: usize, value: T) { - self.0[index] = value; - } - - fn size(&self) -> usize { - self.0.len() - } - - fn dot(&self, other: &Self) -> T { - self.0 - .iter() - .zip(other.0.iter()) - .map(|(a, b)| *a * *b) - .fold(T::zero(), |acc, x| acc + x) - } - - fn norm(&self) -> T { - self.0 - .iter() - .map(|x| *x * *x) - .fold(T::zero(), |acc, x| acc + x) - .sqrt() - } - - fn max(&self) -> T { - *self - .0 - .iter() - .max_by(|a, b| a.partial_cmp(b).unwrap()) - .unwrap_or(&T::zero()) - } - - fn min(&self) -> T { - *self - .0 - .iter() - .min_by(|a, b| a.partial_cmp(b).unwrap()) - .unwrap_or(&T::zero()) - } - - fn sum(&self) -> T { - self.0.iter().fold(T::zero(), |acc, x| acc + *x) - } -} - -impl VectorImpl { - pub fn add_to(&self, other: &Self) -> Option> { - if self.size() != other.size() { - return None; - } - - let mut result = VectorImpl::new(vec![T::zero(); ROWS * COLS]); - - for i in 0..self.size() { - let sum = self.get(i) + other.get(i); - result.set(i, sum); - } - - Some(result) - } - - pub fn subtract(&self, other: &Self) -> Option> { - if self.size() != other.size() { - return None; - } - - let mut result = VectorImpl::new(vec![T::zero(); ROWS * COLS]); - - for i in 0..self.size() { - let sum = self.get(i) - other.get(i); - result.set(i, sum); - } - - Some(result) - } - - pub fn scale(&self, scalar: T) -> VectorImpl { - let mut result = VectorImpl::new(vec![T::zero(); ROWS * COLS]); - - for i in 0..self.size() { - let product = self.get(i) * scalar; - result.set(i, product); - } - - result - } -} - -impl ops::Index - for VectorImpl -{ - type Output = T; - - fn index(&self, index: usize) -> &Self::Output { - &self.0[index] - } -} - -impl ops::IndexMut - for VectorImpl -{ - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.0[index] - } -} - -impl ops::Add<&VectorImpl> - for VectorImpl -{ - type Output = Option>; - - fn add(self, other: &VectorImpl) -> Self::Output { - self.add_to(other) - } -} - -impl ops::Sub<&VectorImpl> - for VectorImpl -{ - type Output = Option>; - - fn sub(self, other: &VectorImpl) -> Self::Output { - self.subtract(other) - } -} - -impl ops::Mul for VectorImpl { - type Output = VectorImpl; - - fn mul(self, scalar: T) -> Self::Output { - self.scale(scalar) - } -} - -impl ops::Div for VectorImpl { - type Output = VectorImpl; - - fn div(self, scalar: T) -> Self::Output { - self.scale(T::one() / scalar) - } -} - -impl ops::AddAssign> - for VectorImpl -{ - fn add_assign(&mut self, other: VectorImpl) { - if let Some(result) = self.add_to(&other) { - *self = result; - } - } -} - -impl ops::SubAssign> - for VectorImpl -{ - fn sub_assign(&mut self, other: VectorImpl) { - if let Some(result) = self.subtract(&other) { - *self = result; - } - } -} - -impl ops::MulAssign - for VectorImpl -{ - fn mul_assign(&mut self, scalar: T) { - *self = self.scale(scalar); - } -} - -impl ops::DivAssign - for VectorImpl -{ - fn div_assign(&mut self, scalar: T) { - *self = self.scale(T::one() / scalar); - } -} - -impl VectorMatrix for RowVector { - fn to_matrix(&self) -> Matrix { - Matrix::new(1, self.size(), self.0.clone()) - } - - fn from_matrix(matrix: &Matrix) -> Self { - Self::new(matrix.data.clone()) - } -} - -impl VectorMatrix for ColumnVector { - fn to_matrix(&self) -> Matrix { - Matrix::new(self.size(), 1, self.0.clone()) - } - - fn from_matrix(matrix: &Matrix) -> Self { - Self::new(matrix.data.clone()) - } -} - -impl ops::Mul<&Matrix> for RowVector { - type Output = Option>; - - fn mul(self, matrix: &Matrix) -> Self::Output { - self.mul_matrix(matrix) - } -} - -impl ops::Mul<&Matrix> for ColumnVector { - type Output = Option>; - - fn mul(self, matrix: &Matrix) -> Self::Output { - self.mul_matrix(matrix) - } -} - -impl ops::MulAssign<&Matrix> for RowVector { - fn mul_assign(&mut self, matrix: &Matrix) { - if let Some(result) = self.mul_matrix(matrix) { - *self = result; - } - } -} - -impl ops::MulAssign<&Matrix> for ColumnVector { - fn mul_assign(&mut self, matrix: &Matrix) { - if let Some(result) = self.mul_matrix(matrix) { - *self = result; - } - } -} - -impl fmt::Debug for RowVector { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "RowVector({:?})", self.0) - } -} - -impl fmt::Debug for ColumnVector { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "ColumnVector({:?})", self.0) - } -} - -impl fmt::Display for RowVector { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "[{}]", - self.0 - .iter() - .map(|x| x.to_string()) - .collect::>() - .join(", ") - ) - } -} - -impl fmt::Display for ColumnVector { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "[")?; - for (i, x) in self.0.iter().enumerate() { - if i > 0 { - write!(f, ",\n ")?; - } - write!(f, "{}", x)?; - } - write!(f, "]") - } -} diff --git a/libpsi-tester/Cargo.toml b/libpsi-tester/Cargo.toml new file mode 100644 index 0000000..6e6ae37 --- /dev/null +++ b/libpsi-tester/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "libpsi-tester" +version = "0.1.0" +edition = "2021" + +[dependencies] +libpsi = { path = "../libpsi" } \ No newline at end of file diff --git a/libpsi-tester/src/main.rs b/libpsi-tester/src/main.rs new file mode 100644 index 0000000..4aaa92d --- /dev/null +++ b/libpsi-tester/src/main.rs @@ -0,0 +1,8 @@ +use libpsi::*; + +fn main() { + let bit_1 = qubit![(1.0, 2.0), (1.0, 2.0)]; + let bit_2 = qubit![(1.0, 2.0), (1.0, 2.0)]; + let register: QuantumRegister = quantum_register![bit_1, bit_2]; + println!("{}", register); +} diff --git a/libpsi/Cargo.toml b/libpsi/Cargo.toml new file mode 100644 index 0000000..599537f --- /dev/null +++ b/libpsi/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "libpsi" +version = "0.1.0" +edition = "2021" + +[dependencies] +libm = "0.2.8" diff --git a/libpsi/src/core/component.rs b/libpsi/src/core/component.rs new file mode 100644 index 0000000..bd18b52 --- /dev/null +++ b/libpsi/src/core/component.rs @@ -0,0 +1,51 @@ +use crate::{ColumnVector, Complex, Matrix, VectorMatrix}; + +pub type QuantumRegister = ColumnVector>; +pub type QuantumBit = ColumnVector>; + +#[macro_export] +macro_rules! count { + () => { 0 }; + ($head:expr $(,$tail:expr)*) => { 1 + count!($( $tail ),*) }; +} + +#[macro_export] +macro_rules! qubit { + ($(($re:expr, $im:expr)),*) => { + { + let mut vector = Vec::new(); + $( + vector.push(complex!($re, $im)); + )* + QuantumBit::new(vector) + } + }; +} + +#[macro_export] +macro_rules! quantum_register { + ($($bit:expr),*) => { + { + const N: usize = count!($($bit),*); + let bits: [QuantumBit; N] = [$($bit),*]; + QuantumRegister::from(&bits) + } + }; +} + +impl QuantumBit { + pub fn get_state(&self) -> i32 { + (self[1] != Complex::new(0.0, 0.0)) as i32 + } +} + +impl QuantumRegister { + pub fn from(bits: &[QuantumBit]) -> QuantumRegister { + let matrices: Vec>> = bits.iter().map(|bit| bit.to_matrix()).collect(); + let mut result = matrices[0].clone(); + for matrix in &matrices[1..] { + result = result.kronecker(matrix); + } + ColumnVector::from_matrix(&result) + } +} diff --git a/libpsi/src/core/mod.rs b/libpsi/src/core/mod.rs new file mode 100644 index 0000000..9cea807 --- /dev/null +++ b/libpsi/src/core/mod.rs @@ -0,0 +1 @@ +pub mod component; diff --git a/libpsi/src/lib.rs b/libpsi/src/lib.rs new file mode 100644 index 0000000..9cbd644 --- /dev/null +++ b/libpsi/src/lib.rs @@ -0,0 +1,9 @@ +mod core; +mod maths; + +pub use maths::complex::*; +pub use maths::matrix::*; +pub use maths::numeric_types::*; +pub use maths::vector::*; + +pub use core::component::*; diff --git a/libpsi/src/maths/complex.rs b/libpsi/src/maths/complex.rs new file mode 100644 index 0000000..28a3121 --- /dev/null +++ b/libpsi/src/maths/complex.rs @@ -0,0 +1,219 @@ +use crate::Float; +use core::{fmt, ops}; + +#[macro_export] +macro_rules! complex { + ($real:expr, $imaginary:expr) => { + $crate::Complex::new($real, $imaginary) + }; +} + +#[derive(Copy, Clone, PartialOrd, PartialEq)] +pub struct Complex { + pub real: T, + pub imaginary: T, +} + +impl fmt::Debug for Complex { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "Complex {{ real: {:?}, imaginary: {:?} }}", + self.real, self.imaginary + ) + } +} + +impl fmt::Display for Complex { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{} + {}i", self.real, self.imaginary) + } +} + +impl Complex { + pub fn new(real: T, imaginary: T) -> Complex { + Complex { real, imaginary } + } + + pub fn get_conjugate(&self) -> Complex { + Complex { + real: self.real, + imaginary: -self.imaginary, + } + } + + pub fn conjugate(&mut self) { + self.imaginary = -self.imaginary; + } + + pub fn phase(&self) -> T { + T::atan2(self.imaginary, self.real) + } + + pub fn norm(&self) -> T { + self.real * self.real + self.imaginary * self.imaginary + } + + pub fn abs(&self) -> T { + T::sqrt(self.norm()) + } +} + +impl ops::Neg for Complex { + type Output = Complex; + + fn neg(self) -> Complex { + Complex { + real: -self.real, + imaginary: -self.imaginary, + } + } +} + +impl ops::Add for Complex { + type Output = Complex; + + fn add(self, other: Complex) -> Complex { + Complex { + real: self.real + other.real, + imaginary: self.imaginary + other.imaginary, + } + } +} + +impl ops::Sub for Complex { + type Output = Complex; + + fn sub(self, other: Complex) -> Complex { + Complex { + real: self.real - other.real, + imaginary: self.imaginary - other.imaginary, + } + } +} + +impl ops::Mul for Complex { + type Output = Complex; + + fn mul(self, other: Complex) -> Complex { + Complex { + real: self.real * other.real - self.imaginary * other.imaginary, + imaginary: self.real * other.imaginary + self.imaginary * other.real, + } + } +} + +impl ops::Div for Complex { + type Output = Complex; + + fn div(self, other: Complex) -> Complex { + let denom = other.real * other.real + other.imaginary * other.imaginary; + Complex { + real: (self.real * other.real + self.imaginary * other.imaginary) / denom, + imaginary: (self.imaginary * other.real - self.real * other.imaginary) / denom, + } + } +} + +impl ops::Add for Complex { + type Output = Complex; + + fn add(self, other: T) -> Complex { + Complex { + real: self.real + other, + imaginary: self.imaginary, + } + } +} + +impl ops::Sub for Complex { + type Output = Complex; + + fn sub(self, other: T) -> Complex { + Complex { + real: self.real - other, + imaginary: self.imaginary, + } + } +} + +impl ops::Mul for Complex { + type Output = Complex; + + fn mul(self, other: T) -> Complex { + Complex { + real: self.real * other, + imaginary: self.imaginary * other, + } + } +} + +impl ops::Div for Complex { + type Output = Complex; + + fn div(self, other: T) -> Complex { + Complex { + real: self.real / other, + imaginary: self.imaginary / other, + } + } +} + +impl ops::AddAssign for Complex { + fn add_assign(&mut self, other: Complex) { + self.real += other.real; + self.imaginary += other.imaginary; + } +} + +impl ops::SubAssign for Complex { + fn sub_assign(&mut self, other: Complex) { + self.real -= other.real; + self.imaginary -= other.imaginary; + } +} + +impl ops::MulAssign for Complex { + fn mul_assign(&mut self, other: Complex) { + let new_real = self.real * other.real - self.imaginary * other.imaginary; + let new_imaginary = self.real * other.imaginary + self.imaginary * other.real; + self.real = new_real; + self.imaginary = new_imaginary; + } +} + +impl ops::DivAssign for Complex { + fn div_assign(&mut self, other: Complex) { + let denom = other.real * other.real + other.imaginary * other.imaginary; + let new_real = (self.real * other.real + self.imaginary * other.imaginary) / denom; + let new_imaginary = (self.imaginary * other.real - self.real * other.imaginary) / denom; + self.real = new_real; + self.imaginary = new_imaginary; + } +} + +impl ops::AddAssign for Complex { + fn add_assign(&mut self, other: T) { + self.real += other; + } +} + +impl ops::SubAssign for Complex { + fn sub_assign(&mut self, other: T) { + self.real -= other; + } +} + +impl ops::MulAssign for Complex { + fn mul_assign(&mut self, other: T) { + self.real *= other; + self.imaginary *= other; + } +} + +impl ops::DivAssign for Complex { + fn div_assign(&mut self, other: T) { + self.real /= other; + self.imaginary /= other; + } +} diff --git a/libpsi/src/maths/matrix.rs b/libpsi/src/maths/matrix.rs new file mode 100644 index 0000000..388f858 --- /dev/null +++ b/libpsi/src/maths/matrix.rs @@ -0,0 +1,245 @@ +// TODO(Hachem): Refactor + +use super::Float; +use core::{fmt, ops}; + +#[macro_export] +macro_rules! matrix { + ( $( $( $x:expr ),* );* ) => {{ + let mut data = Vec::new(); + let mut rows = 0; + let mut cols = 0; + + $( + let row_data = $( $x )*; + if cols == 0 { + cols = row_data.len(); + } + assert_eq!(cols, row_data.len(), "All rows must have the same number of columns."); + data.extend(row_data); + rows += 1; + )* + + $crate::Matrix::new(rows, cols, data) + }}; +} + +#[derive(Clone)] +pub struct Matrix { + pub data: Vec, + pub rows: usize, + pub cols: usize, +} + +impl Matrix { + pub fn new(rows: usize, cols: usize, data: Vec) -> Self { + Matrix { data, rows, cols } + } + + pub fn get(&self, row: usize, col: usize) -> T { + self.data[row * self.cols + col] + } + + pub fn set(&mut self, row: usize, col: usize, value: T) { + self.data[row * self.cols + col] = value; + } + + pub fn dot(&self, other: &Self) -> Option> { + if self.cols != other.rows { + return None; + } + + let mut result = Matrix::new( + self.rows, + other.cols, + vec![T::zero(); self.rows * other.cols], + ); + for i in 0..self.rows { + for j in 0..other.cols { + let mut sum = T::zero(); + for k in 0..self.cols { + sum = sum + (self.get(i, k) * other.get(k, j)); + } + result.set(i, j, sum); + } + } + Some(result) + } + + pub fn kronecker(&self, other: &Self) -> Matrix { + let new_rows = self.rows * other.rows; + let new_cols = self.cols * other.cols; + + let mut result = Matrix::new(new_rows, new_cols, vec![T::zero(); new_rows * new_cols]); + + for i in 0..self.rows { + for j in 0..self.cols { + let self_val = self.get(i, j); + for k in 0..other.rows { + for l in 0..other.cols { + let result_row = i * other.rows + k; + let result_col = j * other.cols + l; + result.set(result_row, result_col, self_val.clone() * other.get(k, l)); + } + } + } + } + + result + } + + pub fn transpose(&self) -> Matrix { + let mut result = Matrix::new(self.cols, self.rows, vec![T::zero(); self.cols * self.rows]); + + for i in 0..self.rows { + for j in 0..self.cols { + let value = self.get(i, j); + result.set(j, i, value); + } + } + + result + } + + pub fn add_to(&self, other: &Self) -> Option> { + if self.rows != other.rows || self.cols != other.cols { + return None; + } + + let mut result = Matrix::new(self.rows, self.cols, vec![T::zero(); self.rows * self.cols]); + + for i in 0..self.rows { + for j in 0..self.cols { + let sum = self.get(i, j) + other.get(i, j); + result.set(i, j, sum); + } + } + Some(result) + } + + pub fn subtract(&self, other: &Self) -> Option> { + if self.rows != other.rows || self.cols != other.cols { + return None; + } + + let mut result = Matrix::new(self.rows, self.cols, vec![T::zero(); self.rows * self.cols]); + + for i in 0..self.rows { + for j in 0..self.cols { + let diff = self.get(i, j) - other.get(i, j); + result.set(i, j, diff); + } + } + Some(result) + } + + pub fn scale(&self, scalar: T) -> Matrix { + let mut result = Matrix::new(self.rows, self.cols, vec![T::zero(); self.rows * self.cols]); + + for i in 0..self.rows { + for j in 0..self.cols { + let scaled_value = self.get(i, j) * scalar; + result.set(i, j, scaled_value); + } + } + result + } +} + +impl ops::Index<(usize, usize)> for Matrix { + type Output = T; + + fn index(&self, index: (usize, usize)) -> &Self::Output { + &self.data[index.0 * self.cols + index.1] + } +} + +impl ops::IndexMut<(usize, usize)> for Matrix { + fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output { + &mut self.data[index.0 * self.cols + index.1] + } +} + +impl fmt::Debug for Matrix { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for i in 0..self.rows { + for j in 0..self.cols { + write!(f, "{:?} ", self.get(i, j))?; + } + writeln!(f)?; + } + Ok(()) + } +} + +impl fmt::Display for Matrix { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for i in 0..self.rows { + for j in 0..self.cols { + write!(f, "{:>8} ", self.get(i, j))?; + } + writeln!(f)?; + } + Ok(()) + } +} + +impl ops::Add<&Matrix> for Matrix { + type Output = Option>; + + fn add(self, other: &Matrix) -> Self::Output { + self.add_to(other) + } +} + +impl ops::Sub<&Matrix> for Matrix { + type Output = Option>; + + fn sub(self, other: &Matrix) -> Self::Output { + self.subtract(other) + } +} + +impl ops::Mul for Matrix { + type Output = Matrix; + + fn mul(self, scalar: T) -> Self::Output { + self.scale(scalar) + } +} + +impl ops::Div for Matrix { + type Output = Matrix; + + fn div(self, scalar: T) -> Self::Output { + self.scale(T::one() / scalar) + } +} + +impl ops::AddAssign<&Matrix> for Matrix { + fn add_assign(&mut self, other: &Matrix) { + if let Some(result) = self.add_to(other) { + *self = result; + } + } +} + +impl ops::SubAssign<&Matrix> for Matrix { + fn sub_assign(&mut self, other: &Matrix) { + if let Some(result) = self.subtract(other) { + *self = result; + } + } +} + +impl ops::MulAssign for Matrix { + fn mul_assign(&mut self, scalar: T) { + *self = self.scale(scalar); + } +} + +impl ops::DivAssign for Matrix { + fn div_assign(&mut self, scalar: T) { + *self = self.scale(T::one() / scalar); + } +} diff --git a/libpsi/src/maths/mod.rs b/libpsi/src/maths/mod.rs new file mode 100644 index 0000000..734cfb4 --- /dev/null +++ b/libpsi/src/maths/mod.rs @@ -0,0 +1,8 @@ +pub mod complex; +pub mod matrix; +pub mod numeric_types; +pub mod vector; + +pub use complex::*; +pub use matrix::*; +pub use numeric_types::*; diff --git a/libpsi/src/maths/numeric_types.rs b/libpsi/src/maths/numeric_types.rs new file mode 100644 index 0000000..f1355de --- /dev/null +++ b/libpsi/src/maths/numeric_types.rs @@ -0,0 +1,152 @@ +use super::Complex; +use core::ops; + +pub trait Numeric: + Copy + + PartialOrd + + ops::Add + + ops::Mul + + ops::Sub + + ops::Div + + ops::Neg + + ops::AddAssign + + ops::SubAssign + + ops::MulAssign + + ops::DivAssign +{ + fn zero() -> Self; + fn one() -> Self; +} + +pub trait Integer: Numeric {} +pub trait Float: Numeric { + fn sqrt(self) -> Self; + fn atan2(y: Self, x: Self) -> Self; +} + +impl Float for f32 { + fn sqrt(self) -> Self { + libm::sqrtf(self) + } + + fn atan2(y: Self, x: Self) -> Self { + libm::atan2f(y, x) + } +} + +impl Float for f64 { + fn sqrt(self) -> Self { + libm::sqrt(self) + } + + fn atan2(y: Self, x: Self) -> Self { + libm::atan2(y, x) + } +} + +impl Float for Complex { + fn sqrt(self) -> Self { + let r = self.abs(); + let theta = self.phase(); + + let sqrt_r = libm::sqrtf(r); + let sqrt_theta = theta / 2.0; + + Complex::new( + sqrt_r * libm::cosf(sqrt_theta), + sqrt_r * libm::sinf(sqrt_theta), + ) + } + + fn atan2(y: Self, x: Self) -> Self { + Complex::new( + libm::atan2f(y.real, x.real), + libm::atan2f(y.imaginary, x.imaginary), + ) + } +} + +impl Float for Complex { + fn sqrt(self) -> Self { + let r = self.abs(); + let theta = self.phase(); + + let sqrt_r = libm::sqrt(r); + let sqrt_theta = theta / 2.0; + + Complex::new( + sqrt_r * libm::cos(sqrt_theta), + sqrt_r * libm::sin(sqrt_theta), + ) + } + + fn atan2(y: Self, x: Self) -> Self { + Complex::new( + libm::atan2(y.real, x.real), + libm::atan2(y.imaginary, x.imaginary), + ) + } +} + +impl Integer for i64 {} +impl Integer for i32 {} + +impl Numeric for i32 { + fn zero() -> Self { + 0 + } + + fn one() -> Self { + 1 + } +} + +impl Numeric for i64 { + fn zero() -> Self { + 0 + } + + fn one() -> Self { + 1 + } +} + +impl Numeric for f32 { + fn zero() -> Self { + 0.0 + } + + fn one() -> Self { + 1.0 + } +} + +impl Numeric for f64 { + fn zero() -> Self { + 0.0 + } + + fn one() -> Self { + 1.0 + } +} + +impl Numeric for Complex { + fn zero() -> Self { + Complex::new(0.0, 0.0) + } + + fn one() -> Self { + Complex::new(1.0, 0.0) + } +} + +impl Numeric for Complex { + fn zero() -> Self { + Complex::new(0.0, 0.0) + } + + fn one() -> Self { + Complex::new(1.0, 0.0) + } +} diff --git a/libpsi/src/maths/vector.rs b/libpsi/src/maths/vector.rs new file mode 100644 index 0000000..0c13e4c --- /dev/null +++ b/libpsi/src/maths/vector.rs @@ -0,0 +1,374 @@ +// TODO(Hachem): Operators Matrix/Vector don't work +// TODO(Hachem): Refactor + +use super::{Float, Matrix}; +use core::{fmt, ops}; + +#[macro_export] +macro_rules! row_vector { + ($($x:expr),*) => { + RowVector::new(vec![$($x),*]) + }; + ($($x:expr,)*) => { + RowVector::new(vec![$($x),*]) + }; +} + +#[macro_export] +macro_rules! column_vector { + ($($x:expr),*) => { + ColumnVector::new(vec![$($x),*]) + }; + ($($x:expr,)*) => { + ColumnVector::new(vec![$($x),*]) + }; +} + +pub trait Vector { + fn new(data: Vec) -> Self; + fn get(&self, index: usize) -> T; + fn set(&mut self, index: usize, value: T); + fn size(&self) -> usize; + + fn dot(&self, other: &Self) -> T; + fn norm(&self) -> T; + + fn max(&self) -> T; + fn min(&self) -> T; + fn sum(&self) -> T; +} + +pub trait VectorMatrix { + fn from_matrix(matrix: &Matrix) -> Self; + fn to_matrix(&self) -> Matrix; +} + +pub struct VectorImpl(Vec); +pub type RowVector = VectorImpl; +pub type ColumnVector = VectorImpl; + +impl ColumnVector { + pub fn mul_matrix(&self, matrix: &Matrix) -> Option> { + if matrix.cols != self.size() { + return None; + } + + let mut result = ColumnVector::new(vec![T::zero(); matrix.rows]); + + for i in 0..matrix.rows { + let mut sum = T::zero(); + for j in 0..matrix.cols { + sum = sum + (matrix.get(i, j) * self.get(j)); + } + result.set(i, sum); + } + + Some(result) + } + + pub fn transpose(&self) -> RowVector { + RowVector::new(self.0.clone()) + } +} + +impl RowVector { + pub fn mul_matrix(&self, matrix: &Matrix) -> Option> { + if self.size() != matrix.rows { + return None; + } + + let mut result = RowVector::new(vec![T::zero(); matrix.cols]); + + for j in 0..matrix.cols { + let mut sum = T::zero(); + for i in 0..matrix.rows { + sum = sum + (self.get(i) * matrix.get(i, j)); + } + result.set(j, sum); + } + + Some(result) + } + + pub fn transpose(&self) -> ColumnVector { + ColumnVector::new(self.0.clone()) + } +} + +impl Vector for VectorImpl { + fn new(data: Vec) -> Self { + Self(data) + } + + fn get(&self, index: usize) -> T { + self.0[index] + } + + fn set(&mut self, index: usize, value: T) { + self.0[index] = value; + } + + fn size(&self) -> usize { + self.0.len() + } + + fn dot(&self, other: &Self) -> T { + self.0 + .iter() + .zip(other.0.iter()) + .map(|(a, b)| *a * *b) + .fold(T::zero(), |acc, x| acc + x) + } + + fn norm(&self) -> T { + self.0 + .iter() + .map(|x| *x * *x) + .fold(T::zero(), |acc, x| acc + x) + .sqrt() + } + + fn max(&self) -> T { + *self + .0 + .iter() + .max_by(|a, b| a.partial_cmp(b).unwrap()) + .unwrap_or(&T::zero()) + } + + fn min(&self) -> T { + *self + .0 + .iter() + .min_by(|a, b| a.partial_cmp(b).unwrap()) + .unwrap_or(&T::zero()) + } + + fn sum(&self) -> T { + self.0.iter().fold(T::zero(), |acc, x| acc + *x) + } +} + +impl VectorImpl { + pub fn add_to(&self, other: &Self) -> Option> { + if self.size() != other.size() { + return None; + } + + let mut result = VectorImpl::new(vec![T::zero(); ROWS * COLS]); + + for i in 0..self.size() { + let sum = self.get(i) + other.get(i); + result.set(i, sum); + } + + Some(result) + } + + pub fn subtract(&self, other: &Self) -> Option> { + if self.size() != other.size() { + return None; + } + + let mut result = VectorImpl::new(vec![T::zero(); ROWS * COLS]); + + for i in 0..self.size() { + let sum = self.get(i) - other.get(i); + result.set(i, sum); + } + + Some(result) + } + + pub fn scale(&self, scalar: T) -> VectorImpl { + let mut result = VectorImpl::new(vec![T::zero(); ROWS * COLS]); + + for i in 0..self.size() { + let product = self.get(i) * scalar; + result.set(i, product); + } + + result + } +} + +impl ops::Index + for VectorImpl +{ + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self.0[index] + } +} + +impl ops::IndexMut + for VectorImpl +{ + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.0[index] + } +} + +impl ops::Add<&VectorImpl> + for VectorImpl +{ + type Output = Option>; + + fn add(self, other: &VectorImpl) -> Self::Output { + self.add_to(other) + } +} + +impl ops::Sub<&VectorImpl> + for VectorImpl +{ + type Output = Option>; + + fn sub(self, other: &VectorImpl) -> Self::Output { + self.subtract(other) + } +} + +impl ops::Mul for VectorImpl { + type Output = VectorImpl; + + fn mul(self, scalar: T) -> Self::Output { + self.scale(scalar) + } +} + +impl ops::Div for VectorImpl { + type Output = VectorImpl; + + fn div(self, scalar: T) -> Self::Output { + self.scale(T::one() / scalar) + } +} + +impl ops::AddAssign> + for VectorImpl +{ + fn add_assign(&mut self, other: VectorImpl) { + if let Some(result) = self.add_to(&other) { + *self = result; + } + } +} + +impl ops::SubAssign> + for VectorImpl +{ + fn sub_assign(&mut self, other: VectorImpl) { + if let Some(result) = self.subtract(&other) { + *self = result; + } + } +} + +impl ops::MulAssign + for VectorImpl +{ + fn mul_assign(&mut self, scalar: T) { + *self = self.scale(scalar); + } +} + +impl ops::DivAssign + for VectorImpl +{ + fn div_assign(&mut self, scalar: T) { + *self = self.scale(T::one() / scalar); + } +} + +impl VectorMatrix for RowVector { + fn to_matrix(&self) -> Matrix { + Matrix::new(1, self.size(), self.0.clone()) + } + + fn from_matrix(matrix: &Matrix) -> Self { + Self::new(matrix.data.clone()) + } +} + +impl VectorMatrix for ColumnVector { + fn to_matrix(&self) -> Matrix { + Matrix::new(self.size(), 1, self.0.clone()) + } + + fn from_matrix(matrix: &Matrix) -> Self { + Self::new(matrix.data.clone()) + } +} + +impl ops::Mul<&Matrix> for RowVector { + type Output = Option>; + + fn mul(self, matrix: &Matrix) -> Self::Output { + self.mul_matrix(matrix) + } +} + +impl ops::Mul<&Matrix> for ColumnVector { + type Output = Option>; + + fn mul(self, matrix: &Matrix) -> Self::Output { + self.mul_matrix(matrix) + } +} + +impl ops::MulAssign<&Matrix> for RowVector { + fn mul_assign(&mut self, matrix: &Matrix) { + if let Some(result) = self.mul_matrix(matrix) { + *self = result; + } + } +} + +impl ops::MulAssign<&Matrix> for ColumnVector { + fn mul_assign(&mut self, matrix: &Matrix) { + if let Some(result) = self.mul_matrix(matrix) { + *self = result; + } + } +} + +impl fmt::Debug for RowVector { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "RowVector({:?})", self.0) + } +} + +impl fmt::Debug for ColumnVector { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "ColumnVector({:?})", self.0) + } +} + +impl fmt::Display for RowVector { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "[{}]", + self.0 + .iter() + .map(|x| x.to_string()) + .collect::>() + .join(", ") + ) + } +} + +impl fmt::Display for ColumnVector { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[")?; + for (i, x) in self.0.iter().enumerate() { + if i > 0 { + write!(f, ",\n ")?; + } + write!(f, "{}", x)?; + } + write!(f, "]") + } +} diff --git a/mu/Cargo.toml b/mu/Cargo.toml deleted file mode 100644 index 457443d..0000000 --- a/mu/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "mu" -version = "0.1.0" -edition = "2021" - -[dependencies] -libmu = { path = "../libmu" } \ No newline at end of file diff --git a/mu/src/main.rs b/mu/src/main.rs deleted file mode 100644 index 7bbc3e7..0000000 --- a/mu/src/main.rs +++ /dev/null @@ -1,8 +0,0 @@ -use libmu::*; - -fn main() { - let bit_1 = qubit![(1.0, 2.0), (1.0, 2.0)]; - let bit_2 = qubit![(1.0, 2.0), (1.0, 2.0)]; - let register: QuantumRegister = quantum_register![bit_1, bit_2]; - println!("{}", register); -} -- cgit v1.3