aboutsummaryrefslogtreecommitdiff
path: root/libpsi/src
diff options
context:
space:
mode:
Diffstat (limited to 'libpsi/src')
-rw-r--r--libpsi/src/core/component.rs51
-rw-r--r--libpsi/src/core/mod.rs1
-rw-r--r--libpsi/src/lib.rs9
-rw-r--r--libpsi/src/maths/complex.rs219
-rw-r--r--libpsi/src/maths/matrix.rs245
-rw-r--r--libpsi/src/maths/mod.rs8
-rw-r--r--libpsi/src/maths/numeric_types.rs152
-rw-r--r--libpsi/src/maths/vector.rs374
8 files changed, 1059 insertions, 0 deletions
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<Complex<f64>>;
+pub type QuantumBit = ColumnVector<Complex<f64>>;
+
+#[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<Matrix<Complex<f64>>> = 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<T: Float> {
+ pub real: T,
+ pub imaginary: T,
+}
+
+impl<T: Float + fmt::Debug> fmt::Debug for Complex<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "Complex {{ real: {:?}, imaginary: {:?} }}",
+ self.real, self.imaginary
+ )
+ }
+}
+
+impl<T: Float + fmt::Display> fmt::Display for Complex<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{} + {}i", self.real, self.imaginary)
+ }
+}
+
+impl<T: Float> Complex<T> {
+ pub fn new(real: T, imaginary: T) -> Complex<T> {
+ Complex { real, imaginary }
+ }
+
+ pub fn get_conjugate(&self) -> Complex<T> {
+ 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<T: Float> ops::Neg for Complex<T> {
+ type Output = Complex<T>;
+
+ fn neg(self) -> Complex<T> {
+ Complex {
+ real: -self.real,
+ imaginary: -self.imaginary,
+ }
+ }
+}
+
+impl<T: Float> ops::Add for Complex<T> {
+ type Output = Complex<T>;
+
+ fn add(self, other: Complex<T>) -> Complex<T> {
+ Complex {
+ real: self.real + other.real,
+ imaginary: self.imaginary + other.imaginary,
+ }
+ }
+}
+
+impl<T: Float> ops::Sub for Complex<T> {
+ type Output = Complex<T>;
+
+ fn sub(self, other: Complex<T>) -> Complex<T> {
+ Complex {
+ real: self.real - other.real,
+ imaginary: self.imaginary - other.imaginary,
+ }
+ }
+}
+
+impl<T: Float> ops::Mul for Complex<T> {
+ type Output = Complex<T>;
+
+ fn mul(self, other: Complex<T>) -> Complex<T> {
+ Complex {
+ real: self.real * other.real - self.imaginary * other.imaginary,
+ imaginary: self.real * other.imaginary + self.imaginary * other.real,
+ }
+ }
+}
+
+impl<T: Float> ops::Div for Complex<T> {
+ type Output = Complex<T>;
+
+ fn div(self, other: Complex<T>) -> Complex<T> {
+ 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<T: Float> ops::Add<T> for Complex<T> {
+ type Output = Complex<T>;
+
+ fn add(self, other: T) -> Complex<T> {
+ Complex {
+ real: self.real + other,
+ imaginary: self.imaginary,
+ }
+ }
+}
+
+impl<T: Float> ops::Sub<T> for Complex<T> {
+ type Output = Complex<T>;
+
+ fn sub(self, other: T) -> Complex<T> {
+ Complex {
+ real: self.real - other,
+ imaginary: self.imaginary,
+ }
+ }
+}
+
+impl<T: Float> ops::Mul<T> for Complex<T> {
+ type Output = Complex<T>;
+
+ fn mul(self, other: T) -> Complex<T> {
+ Complex {
+ real: self.real * other,
+ imaginary: self.imaginary * other,
+ }
+ }
+}
+
+impl<T: Float> ops::Div<T> for Complex<T> {
+ type Output = Complex<T>;
+
+ fn div(self, other: T) -> Complex<T> {
+ Complex {
+ real: self.real / other,
+ imaginary: self.imaginary / other,
+ }
+ }
+}
+
+impl<T: Float> ops::AddAssign for Complex<T> {
+ fn add_assign(&mut self, other: Complex<T>) {
+ self.real += other.real;
+ self.imaginary += other.imaginary;
+ }
+}
+
+impl<T: Float> ops::SubAssign for Complex<T> {
+ fn sub_assign(&mut self, other: Complex<T>) {
+ self.real -= other.real;
+ self.imaginary -= other.imaginary;
+ }
+}
+
+impl<T: Float> ops::MulAssign for Complex<T> {
+ fn mul_assign(&mut self, other: Complex<T>) {
+ 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<T: Float> ops::DivAssign for Complex<T> {
+ fn div_assign(&mut self, other: Complex<T>) {
+ 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<T: Float> ops::AddAssign<T> for Complex<T> {
+ fn add_assign(&mut self, other: T) {
+ self.real += other;
+ }
+}
+
+impl<T: Float> ops::SubAssign<T> for Complex<T> {
+ fn sub_assign(&mut self, other: T) {
+ self.real -= other;
+ }
+}
+
+impl<T: Float> ops::MulAssign<T> for Complex<T> {
+ fn mul_assign(&mut self, other: T) {
+ self.real *= other;
+ self.imaginary *= other;
+ }
+}
+
+impl<T: Float> ops::DivAssign<T> for Complex<T> {
+ 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<T: Float> {
+ pub data: Vec<T>,
+ pub rows: usize,
+ pub cols: usize,
+}
+
+impl<T: Float> Matrix<T> {
+ pub fn new(rows: usize, cols: usize, data: Vec<T>) -> 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<Matrix<T>> {
+ 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<T> {
+ 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<T> {
+ 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<Matrix<T>> {
+ 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<Matrix<T>> {
+ 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<T> {
+ 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<T: Float> ops::Index<(usize, usize)> for Matrix<T> {
+ type Output = T;
+
+ fn index(&self, index: (usize, usize)) -> &Self::Output {
+ &self.data[index.0 * self.cols + index.1]
+ }
+}
+
+impl<T: Float> ops::IndexMut<(usize, usize)> for Matrix<T> {
+ fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
+ &mut self.data[index.0 * self.cols + index.1]
+ }
+}
+
+impl<T: Float + fmt::Debug> fmt::Debug for Matrix<T> {
+ 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<T: Float + fmt::Display> fmt::Display for Matrix<T> {
+ 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<T: Float> ops::Add<&Matrix<T>> for Matrix<T> {
+ type Output = Option<Matrix<T>>;
+
+ fn add(self, other: &Matrix<T>) -> Self::Output {
+ self.add_to(other)
+ }
+}
+
+impl<T: Float> ops::Sub<&Matrix<T>> for Matrix<T> {
+ type Output = Option<Matrix<T>>;
+
+ fn sub(self, other: &Matrix<T>) -> Self::Output {
+ self.subtract(other)
+ }
+}
+
+impl<T: Float> ops::Mul<T> for Matrix<T> {
+ type Output = Matrix<T>;
+
+ fn mul(self, scalar: T) -> Self::Output {
+ self.scale(scalar)
+ }
+}
+
+impl<T: Float> ops::Div<T> for Matrix<T> {
+ type Output = Matrix<T>;
+
+ fn div(self, scalar: T) -> Self::Output {
+ self.scale(T::one() / scalar)
+ }
+}
+
+impl<T: Float> ops::AddAssign<&Matrix<T>> for Matrix<T> {
+ fn add_assign(&mut self, other: &Matrix<T>) {
+ if let Some(result) = self.add_to(other) {
+ *self = result;
+ }
+ }
+}
+
+impl<T: Float> ops::SubAssign<&Matrix<T>> for Matrix<T> {
+ fn sub_assign(&mut self, other: &Matrix<T>) {
+ if let Some(result) = self.subtract(other) {
+ *self = result;
+ }
+ }
+}
+
+impl<T: Float> ops::MulAssign<T> for Matrix<T> {
+ fn mul_assign(&mut self, scalar: T) {
+ *self = self.scale(scalar);
+ }
+}
+
+impl<T: Float> ops::DivAssign<T> for Matrix<T> {
+ 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<Output = Self>
+ + ops::Mul<Output = Self>
+ + ops::Sub<Output = Self>
+ + ops::Div<Output = Self>
+ + ops::Neg<Output = Self>
+ + 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<f32> {
+ 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<f64> {
+ 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<f32> {
+ fn zero() -> Self {
+ Complex::new(0.0, 0.0)
+ }
+
+ fn one() -> Self {
+ Complex::new(1.0, 0.0)
+ }
+}
+
+impl Numeric for Complex<f64> {
+ 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<T: Float> {
+ fn new(data: Vec<T>) -> 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<T: Float> {
+ fn from_matrix(matrix: &Matrix<T>) -> Self;
+ fn to_matrix(&self) -> Matrix<T>;
+}
+
+pub struct VectorImpl<T: Float, const ROWS: usize, const COLS: usize>(Vec<T>);
+pub type RowVector<T> = VectorImpl<T, 1, 0>;
+pub type ColumnVector<T> = VectorImpl<T, 0, 1>;
+
+impl<T: Float> ColumnVector<T> {
+ pub fn mul_matrix(&self, matrix: &Matrix<T>) -> Option<ColumnVector<T>> {
+ 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<T> {
+ RowVector::new(self.0.clone())
+ }
+}
+
+impl<T: Float> RowVector<T> {
+ pub fn mul_matrix(&self, matrix: &Matrix<T>) -> Option<RowVector<T>> {
+ 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<T> {
+ ColumnVector::new(self.0.clone())
+ }
+}
+
+impl<T: Float, const ROWS: usize, const COLS: usize> Vector<T> for VectorImpl<T, ROWS, COLS> {
+ fn new(data: Vec<T>) -> 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<T: Float, const ROWS: usize, const COLS: usize> VectorImpl<T, ROWS, COLS> {
+ pub fn add_to(&self, other: &Self) -> Option<VectorImpl<T, ROWS, COLS>> {
+ 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<VectorImpl<T, ROWS, COLS>> {
+ 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<T, ROWS, COLS> {
+ 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<T: Float, const ROWS: usize, const COLS: usize> ops::Index<usize>
+ for VectorImpl<T, ROWS, COLS>
+{
+ type Output = T;
+
+ fn index(&self, index: usize) -> &Self::Output {
+ &self.0[index]
+ }
+}
+
+impl<T: Float, const ROWS: usize, const COLS: usize> ops::IndexMut<usize>
+ for VectorImpl<T, ROWS, COLS>
+{
+ fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+ &mut self.0[index]
+ }
+}
+
+impl<T: Float, const ROWS: usize, const COLS: usize> ops::Add<&VectorImpl<T, ROWS, COLS>>
+ for VectorImpl<T, ROWS, COLS>
+{
+ type Output = Option<VectorImpl<T, ROWS, COLS>>;
+
+ fn add(self, other: &VectorImpl<T, ROWS, COLS>) -> Self::Output {
+ self.add_to(other)
+ }
+}
+
+impl<T: Float, const ROWS: usize, const COLS: usize> ops::Sub<&VectorImpl<T, ROWS, COLS>>
+ for VectorImpl<T, ROWS, COLS>
+{
+ type Output = Option<VectorImpl<T, ROWS, COLS>>;
+
+ fn sub(self, other: &VectorImpl<T, ROWS, COLS>) -> Self::Output {
+ self.subtract(other)
+ }
+}
+
+impl<T: Float, const ROWS: usize, const COLS: usize> ops::Mul<T> for VectorImpl<T, ROWS, COLS> {
+ type Output = VectorImpl<T, ROWS, COLS>;
+
+ fn mul(self, scalar: T) -> Self::Output {
+ self.scale(scalar)
+ }
+}
+
+impl<T: Float, const ROWS: usize, const COLS: usize> ops::Div<T> for VectorImpl<T, ROWS, COLS> {
+ type Output = VectorImpl<T, ROWS, COLS>;
+
+ fn div(self, scalar: T) -> Self::Output {
+ self.scale(T::one() / scalar)
+ }
+}
+
+impl<T: Float, const ROWS: usize, const COLS: usize> ops::AddAssign<VectorImpl<T, ROWS, COLS>>
+ for VectorImpl<T, ROWS, COLS>
+{
+ fn add_assign(&mut self, other: VectorImpl<T, ROWS, COLS>) {
+ if let Some(result) = self.add_to(&other) {
+ *self = result;
+ }
+ }
+}
+
+impl<T: Float, const ROWS: usize, const COLS: usize> ops::SubAssign<VectorImpl<T, ROWS, COLS>>
+ for VectorImpl<T, ROWS, COLS>
+{
+ fn sub_assign(&mut self, other: VectorImpl<T, ROWS, COLS>) {
+ if let Some(result) = self.subtract(&other) {
+ *self = result;
+ }
+ }
+}
+
+impl<T: Float, const ROWS: usize, const COLS: usize> ops::MulAssign<T>
+ for VectorImpl<T, ROWS, COLS>
+{
+ fn mul_assign(&mut self, scalar: T) {
+ *self = self.scale(scalar);
+ }
+}
+
+impl<T: Float, const ROWS: usize, const COLS: usize> ops::DivAssign<T>
+ for VectorImpl<T, ROWS, COLS>
+{
+ fn div_assign(&mut self, scalar: T) {
+ *self = self.scale(T::one() / scalar);
+ }
+}
+
+impl<T: Float> VectorMatrix<T> for RowVector<T> {
+ fn to_matrix(&self) -> Matrix<T> {
+ Matrix::new(1, self.size(), self.0.clone())
+ }
+
+ fn from_matrix(matrix: &Matrix<T>) -> Self {
+ Self::new(matrix.data.clone())
+ }
+}
+
+impl<T: Float> VectorMatrix<T> for ColumnVector<T> {
+ fn to_matrix(&self) -> Matrix<T> {
+ Matrix::new(self.size(), 1, self.0.clone())
+ }
+
+ fn from_matrix(matrix: &Matrix<T>) -> Self {
+ Self::new(matrix.data.clone())
+ }
+}
+
+impl<T: Float> ops::Mul<&Matrix<T>> for RowVector<T> {
+ type Output = Option<RowVector<T>>;
+
+ fn mul(self, matrix: &Matrix<T>) -> Self::Output {
+ self.mul_matrix(matrix)
+ }
+}
+
+impl<T: Float> ops::Mul<&Matrix<T>> for ColumnVector<T> {
+ type Output = Option<ColumnVector<T>>;
+
+ fn mul(self, matrix: &Matrix<T>) -> Self::Output {
+ self.mul_matrix(matrix)
+ }
+}
+
+impl<T: Float> ops::MulAssign<&Matrix<T>> for RowVector<T> {
+ fn mul_assign(&mut self, matrix: &Matrix<T>) {
+ if let Some(result) = self.mul_matrix(matrix) {
+ *self = result;
+ }
+ }
+}
+
+impl<T: Float> ops::MulAssign<&Matrix<T>> for ColumnVector<T> {
+ fn mul_assign(&mut self, matrix: &Matrix<T>) {
+ if let Some(result) = self.mul_matrix(matrix) {
+ *self = result;
+ }
+ }
+}
+
+impl<T: Float + fmt::Debug> fmt::Debug for RowVector<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "RowVector({:?})", self.0)
+ }
+}
+
+impl<T: Float + fmt::Debug> fmt::Debug for ColumnVector<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "ColumnVector({:?})", self.0)
+ }
+}
+
+impl<T: Float + fmt::Display> fmt::Display for RowVector<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "[{}]",
+ self.0
+ .iter()
+ .map(|x| x.to_string())
+ .collect::<Vec<String>>()
+ .join(", ")
+ )
+ }
+}
+
+impl<T: Float + fmt::Display> fmt::Display for ColumnVector<T> {
+ 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, "]")
+ }
+}