From 882341febd740e3cf4036bfd6da7d43e76197b52 Mon Sep 17 00:00:00 2001 From: Mathieu Groenen Date: Sun, 23 Mar 2025 18:46:20 +0100 Subject: [PATCH 1/2] Added non functioning generic implementation for array types --- Cargo.toml | 3 ++ src/lib.rs | 5 ++-- src/linalg.rs | 1 + src/linalg/numeric_trait.rs | 11 +++++++ src/linalg/rarray.rs | 53 ++++++++++++++++----------------- src/linalg/rarray1d_create.rs | 55 ++++++++++++++++++++--------------- src/linalg/rarray1d_impl.rs | 37 +++++++++++++---------- src/linalg/rarray1d_ops.rs | 30 ++++++++++--------- src/linalg/rarray2d_impl.rs | 49 ++++++++++++++++++------------- src/linalg/rarray_impl.rs | 11 +++---- 10 files changed, 149 insertions(+), 106 deletions(-) create mode 100644 src/linalg/numeric_trait.rs diff --git a/Cargo.toml b/Cargo.toml index 37bf86f..9b1bf1d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,5 +6,8 @@ edition = "2021" [dependencies] rand="0.9.0" +num-traits = "0.2" + + [dev-dependencies] rstest = "0.25.0" diff --git a/src/lib.rs b/src/lib.rs index 8226c85..dd73a44 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,5 @@ extern crate core; -pub mod linalg; - - +use crate::linalg::rarray::{Dim, Rarray}; +pub mod linalg; \ No newline at end of file diff --git a/src/linalg.rs b/src/linalg.rs index e1eaef7..524eceb 100644 --- a/src/linalg.rs +++ b/src/linalg.rs @@ -8,3 +8,4 @@ pub mod rarray1d_create; mod rarray2d_impl; pub mod rarray2d_ops; mod dimension; +mod numeric_trait; diff --git a/src/linalg/numeric_trait.rs b/src/linalg/numeric_trait.rs new file mode 100644 index 0000000..4dcd7ba --- /dev/null +++ b/src/linalg/numeric_trait.rs @@ -0,0 +1,11 @@ +use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; + +pub trait Numeric: Add + AddAssign + Sub + SubAssign + Div + DivAssign + Mul + MulAssign + Copy + Default {} + +impl Numeric for T where + T: + Add + AddAssign + + Sub + SubAssign + + Div + DivAssign + + Mul + MulAssign + + Copy + Default {} \ No newline at end of file diff --git a/src/linalg/rarray.rs b/src/linalg/rarray.rs index bf2b09d..53997f0 100644 --- a/src/linalg/rarray.rs +++ b/src/linalg/rarray.rs @@ -1,8 +1,9 @@ use std::fmt::Debug; -use std::ops::{Add, Mul, MulAssign, Sub}; +use std::ops::{Add, AddAssign, Mul, MulAssign, Sub}; use std::usize; +use num_traits::Num; use rand::seq::IndexedRandom; - +use crate::linalg::numeric_trait::Numeric; pub(crate) use super::dimension::{Dim, D1, D2, D3}; // Base array struct @@ -13,9 +14,9 @@ pub struct Rarray { } // Specific implementations -pub type Rarray1D = Rarray; -pub type Rarray2D = Rarray; -pub type Rarray3D = Rarray; +pub type Rarray1D = Rarray; +pub type Rarray2D = Rarray; +pub type Rarray3D = Rarray; pub trait RarrayCreate { fn new(data: &V) -> Self; @@ -40,9 +41,11 @@ pub trait RarraySub { fn sub(one: &T, other: &V) -> S; } -impl RarrayMul for Rarray2D { +impl RarrayMul, Rarray2D, Rarray1D> for Rarray2D where + T: Numeric +{ /// Performs (1 x n) x (n x m) matrix multiplication - fn mul(one: &Rarray1D, other: &Rarray2D) -> Rarray1D { + fn mul(one: &Rarray1D, other: &Rarray2D) -> Rarray1D { let mut major: usize = 1; if one.shape.width > one.shape.height { assert_eq!(one.shape.width, other.shape.height, "Rarray shape mismatch"); @@ -54,24 +57,24 @@ impl RarrayMul for Rarray2D { let mut result = Rarray1D { shape: D1 { width: one.shape.width, height: 1 }, - data: vec![0.; major] + data: vec![T::default(); major] }; for i in 0..one.shape.width { - let mut sum: f64 = 0.; for j in 0..major { - sum += one[j] * other[[i, j]]; + result[i] += one[j] * other[[i, j]]; } - result[i] = sum; } result } } -impl RarrayMul for Rarray2D { +impl RarrayMul, Rarray1D, Rarray1D> for Rarray2D where + T: Numeric +{ /// Performs (n x m) x (m x 1) matrix multiplication - fn mul(one: &Rarray2D, other: &Rarray1D) -> Rarray1D { + fn mul(one: &Rarray2D, other: &Rarray1D) -> Rarray1D { let mut major: usize = 1; if one.shape.width > one.shape.height { assert_eq!(one.shape.width, other.shape.height, "Rarray shape mismatch"); @@ -83,38 +86,36 @@ impl RarrayMul for Rarray2D { let mut result = Rarray1D { shape: D1 { width: one.shape.height, height: 1 }, - data: vec![0.; major] + data: vec![T::default(); major] }; for i in 0..one.shape.height { - let mut sum: f64 = 0.; for j in 0..major { - sum += one[[i, j]] * other[j]; + result[i] += one[[i, j]] * other[j]; } - result[i] = sum; } result } } -impl RarrayMul for Rarray2D { +impl RarrayMul, Rarray2D, Rarray2D> for Rarray2D where + T: Numeric +{ /// Performs (n x m) x (m x l) matrix multiplication - fn mul(one: &Rarray2D, other: &Rarray2D) -> Rarray2D { + fn mul(one: &Rarray2D, other: &Rarray2D) -> Rarray2D { assert_eq!(one.shape.height, other.shape.width, "Rarray shape mismatch"); let mut result = Rarray2D { shape: D2 { height: one.shape.height, width: other.shape.width }, - data: vec![0.; one.shape.height * other.shape.width] + data: vec![T::default(); one.shape.height * other.shape.width] }; for i in 0..one.shape.height { for j in 0..other.shape.width { - let mut sum: f64 = 0.; for k in 0..one.shape.width { - sum += one.data[i * one.shape.width + k] * other.data[j * other.shape.height + k]; + result.data[i * result.shape.width + j * result.shape.height] += one.data[i * one.shape.width + k] * other.data[j * other.shape.height + k]; } - result.data[i * result.shape.width + j * result.shape.height] = sum; } } @@ -123,7 +124,7 @@ impl RarrayMul for Rarray2D { } impl RarrayScalMul> for Rarray where - T: Copy + MulAssign, + T: Numeric, D : Copy + Dim + Debug, { fn scal_mul(scal: T, rarray: &Rarray) -> Rarray { @@ -141,7 +142,7 @@ impl RarrayScalMul> for Rarray where } impl RarrayAdd, Rarray, Rarray> for Rarray where - T : Copy + Add + Default, + T : Numeric, D : Copy + Dim + Debug + Eq { fn add(one: &Rarray, other: &Rarray) -> Rarray { @@ -161,7 +162,7 @@ impl RarrayAdd, Rarray, Rarray> for Rarray } impl RarraySub, Rarray, Rarray> for Rarray where - T : Copy + Sub + Default, + T : Numeric, D : Copy + Dim + Debug + Eq { fn sub(one: &Rarray, other: &Rarray) -> Rarray { diff --git a/src/linalg/rarray1d_create.rs b/src/linalg/rarray1d_create.rs index 0b5a41c..805bf7a 100644 --- a/src/linalg/rarray1d_create.rs +++ b/src/linalg/rarray1d_create.rs @@ -1,9 +1,13 @@ use std::cmp::max; +use num_traits::Num; use crate::linalg::dimension::{D1, D2}; +use crate::linalg::numeric_trait::Numeric; use crate::linalg::rarray::{Rarray1D, Rarray2D, RarrayCreate}; // Creation -impl RarrayCreate, f64> for Rarray1D { +impl RarrayCreate, T> for Rarray1D where + T: Numeric +{ /// Create rarray1D vector using Vec /// /// # Examples @@ -12,16 +16,17 @@ impl RarrayCreate, f64> for Rarray1D { /// use rumpy::linalg::rarray::Rarray1D; /// use crate::rumpy::linalg::rarray::RarrayCreate; /// - /// let v = Rarray1D::new(&vec![1., 1., 1.]); + /// let v = Rarray1D::::new(&vec![1., 1., 1.]); /// println!("{}", v); /// ``` - fn new(data: &Vec) -> Self { + fn new(data: &Vec) -> Self { Rarray1D { - shape : D1 { width: data.len() as usize, height: 1 }, + shape : D1 { width: data.len(), height: 1 }, data: data.clone() } } + //TODO: Constraint to numeric values /// Create rarra1d vector of length `shape` filled with zeros /// /// # Examples @@ -36,7 +41,7 @@ impl RarrayCreate, f64> for Rarray1D { fn zeros(shape: usize) -> Self { Rarray1D { shape: D1 { width: shape, height: 1}, - data: vec![0.; shape] + data: vec![T::default(); shape] } } @@ -52,9 +57,9 @@ impl RarrayCreate, f64> for Rarray1D { /// println!("{}", v); /// ``` fn random(shape: usize) -> Self { - let mut data = Vec::::with_capacity(shape); + let mut data = Vec::::with_capacity(shape); for _ in 0..shape { - data.push(rand::random::()); + data.push(rand::random::()); } @@ -75,7 +80,7 @@ impl RarrayCreate, f64> for Rarray1D { /// let v = Rarray1D::fill(4., 3); /// println!("{}", v); /// ``` - fn fill(value: f64, shape: usize) -> Self { + fn fill(value: T, shape: usize) -> Self { Rarray1D { shape: D1 { width: shape, height: 1}, data: vec![value; shape] @@ -83,7 +88,9 @@ impl RarrayCreate, f64> for Rarray1D { } } -impl RarrayCreate<(usize, usize), Vec>, f64> for Rarray1D { +impl RarrayCreate<(usize, usize), Vec>, T> for Rarray1D where + T: Numeric +{ /// Create vector using Vec /// /// # Examples @@ -92,14 +99,14 @@ impl RarrayCreate<(usize, usize), Vec>, f64> for Rarray1D { /// use rumpy::linalg::rarray::Rarray1D; /// use crate::rumpy::linalg::rarray::RarrayCreate; /// - /// let v = Rarray1D::new(&vec![vec![0.], vec![0.], vec![0.]]); + /// let v = Rarray1D::::new(&vec![vec![0.], vec![0.], vec![0.]]); /// println!("{}", v); /// ``` /// /// # Panics /// /// If rows aren't of same length - fn new(data: &Vec>) -> Self { + fn new(data: &Vec>) -> Self { let row = data.len(); let col = data[0].len(); for i in 0..row { @@ -131,7 +138,7 @@ impl RarrayCreate<(usize, usize), Vec>, f64> for Rarray1D { assert!(shape.0 == 1 || shape.1 == 1, "Cannot create 2D array using 1D array type"); Rarray1D { shape: D1 { width: shape.1, height: shape.0}, - data: vec![0.; shape.0 * shape.1] + data: vec![T::default(); shape.0 * shape.1] } } @@ -151,9 +158,9 @@ impl RarrayCreate<(usize, usize), Vec>, f64> for Rarray1D { /// If (x, y) with x > 1 and y > 1 fn random(shape: (usize, usize)) -> Self { assert!(shape.0 == 1 || shape.1 == 1, "Cannot create 2D array using 1D array type"); - let mut data = Vec::::with_capacity(shape.0 * shape.1); + let mut data = Vec::::with_capacity(shape.0 * shape.1); for _ in 0..(shape.0 * shape.1) { - data.push(rand::random::()); + data.push(rand::random::()); } @@ -171,13 +178,13 @@ impl RarrayCreate<(usize, usize), Vec>, f64> for Rarray1D { /// use rumpy::linalg::rarray::Rarray1D; /// use crate::rumpy::linalg::rarray::RarrayCreate; /// - /// let v = Rarray1D::fill(4., (3, 1)); + /// let v = Rarray1D::::fill(4., (3, 1)); /// println!("{}", v); /// ``` /// # Panics /// /// If (x, y) with x > 1 and y > 1 - fn fill(value: f64, shape: (usize, usize)) -> Self { + fn fill(value: T, shape: (usize, usize)) -> Self { assert!(shape.0 == 1 || shape.1 == 1, "Cannot create 2D array using 1D array type"); Rarray1D { shape: D1 { width: shape.1, height: shape.0}, @@ -186,7 +193,9 @@ impl RarrayCreate<(usize, usize), Vec>, f64> for Rarray1D { } } -impl Rarray1D { +impl Rarray1D where + T: Numeric +{ /// Create matrix where given vector are the diagonal elements /// /// # Examples @@ -200,12 +209,12 @@ impl Rarray1D { /// println!("{}", res); /// // >> Rarray2D([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]]) /// ``` - pub fn diag(&self) -> Rarray2D { + pub fn diag(&self) -> Rarray2D { let major = max(self.shape.height, self.shape.width); let mut result = Rarray2D { shape: D2 { height: major, width: major}, - data: vec![0.; major * major] + data: vec![T::default(); major * major] }; for i in 0..major { @@ -222,19 +231,19 @@ impl Rarray1D { /// ``` /// use rumpy::linalg::rarray::Rarray1D; /// - /// let a = Rarray1D::range(0, 10, 2); + /// let a = Rarray1D::::range(0, 10, 2); /// println!("{}", a); /// // >> Rarray1D([0., 2., 4., 6., 8.]) /// ``` - pub fn range(start: usize, stop: usize, step: usize) -> Rarray1D { + pub fn range(start: usize, stop: usize, step: usize) -> Rarray1D { let shape = (stop - start) / step; let mut result = Rarray1D { shape: D1 { height: 1, width: shape }, - data: Vec::::with_capacity(shape) + data: Vec::::with_capacity(shape) }; for i in (start..stop).step_by(step) { - result.data.push(i as f64); + result.data.push(i); } result diff --git a/src/linalg/rarray1d_impl.rs b/src/linalg/rarray1d_impl.rs index 75f7b8c..3c37768 100644 --- a/src/linalg/rarray1d_impl.rs +++ b/src/linalg/rarray1d_impl.rs @@ -5,12 +5,13 @@ use core::fmt; use std::ops::{Index, IndexMut, Mul, MulAssign}; - +use num_traits::Num; use crate::linalg::dimension::D1; +use crate::linalg::numeric_trait::Numeric; use super::rarray::{Rarray, Rarray1D, RarrayCreate, RarrayScalMul}; -impl Index for Rarray1D { - type Output = f64; +impl Index for Rarray1D { + type Output = T; fn index(&self, index: usize) -> &Self::Output { if self.shape[0] < self.shape[1] { @@ -24,8 +25,8 @@ impl Index for Rarray1D { } } -impl IndexMut for Rarray1D { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { +impl IndexMut for Rarray1D { + fn index_mut(&mut self, index: usize) -> &mut T { if self.shape[0] < self.shape[1] { assert!(index < self.shape[1], "Index out of bounds"); } @@ -37,31 +38,37 @@ impl IndexMut for Rarray1D { } } -impl Mul for &Rarray1D { - type Output = Rarray1D; +impl Mul for &Rarray1D where + T: Numeric +{ + type Output = Rarray1D; - fn mul(self, rhs: f64) -> Self::Output { + fn mul(self, rhs: T) -> Self::Output { Rarray::scal_mul(rhs, self) } } -impl MulAssign for Rarray1D { - fn mul_assign(&mut self, rhs: f64) { +impl MulAssign for Rarray1D where + T: Numeric +{ + fn mul_assign(&mut self, rhs: T) { self.data = Rarray::scal_mul(rhs, self).data; } } -impl Mul<&Rarray1D> for &Rarray1D { - type Output = f64; +impl Mul<&Rarray1D> for &Rarray1D + where T: Numeric +{ + type Output = T; - fn mul(self, rhs: &Rarray1D) -> Self::Output { + fn mul(self, rhs: &Rarray1D) -> Self::Output { assert_eq!(self.shape.width, rhs.shape.height, "Rarray shape mismatch"); Rarray1D::dot(self, rhs) } } -impl fmt::Display for Rarray1D { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Display for Rarray1D { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut formatted_string: String = String::new(); for i in 0..self.shape.width { formatted_string.push_str(&self.data[i].to_string()); diff --git a/src/linalg/rarray1d_ops.rs b/src/linalg/rarray1d_ops.rs index 90f7a29..b3307cc 100644 --- a/src/linalg/rarray1d_ops.rs +++ b/src/linalg/rarray1d_ops.rs @@ -1,9 +1,11 @@ use std::cmp::max; use std::iter::zip; - +use std::ops::AddAssign; +use num_traits::Num; +use crate::linalg::numeric_trait::Numeric; use super::rarray::{Rarray1D, Rarray2D, RarrayCreate, D1, D2}; -impl Rarray1D { +impl Rarray1D { /// Tranpose 1D matrix pub fn transpose(&self) -> Self { Rarray1D { @@ -18,7 +20,9 @@ impl Rarray1D { } } -impl Rarray1D { +impl Rarray1D where + T: Numeric +{ /// Calculate dot product of two vectors /// /// # Examples @@ -37,11 +41,11 @@ impl Rarray1D { /// # Panics /// /// If vectors aren't of same length - pub fn dot(a: &Self, b: &Self) -> f64 { + pub fn dot(a: &Self, b: &Self) -> T { assert_eq!(a.data.len(), b.data.len(), "Vectors not of same size"); - let mut result: f64 = 0.; - for (x, y) in zip(&a.data, &b.data) { - result += x * y; + let mut result: T = T::default(); + for i in 0..a.data.len() { + result += a.data[i] * b.data[i]; } result } @@ -54,13 +58,13 @@ impl Rarray1D { /// use rumpy::linalg::rarray::Rarray1D; /// use rumpy::linalg::rarray::RarrayCreate; /// - /// let a = Rarray1D::new(&vec![1., 1., 1.]); - /// let b = Rarray1D::new(&vec![1., 1., 1.]); + /// let a = Rarray1D::::new(&vec![1., 1., 1.]); + /// let b = Rarray1D::::new(&vec![1., 1., 1.]); /// let res = Rarray1D::outer(&a, &b); /// println!("{}", res); /// // >> Rarray2D([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]]) /// ``` - pub fn outer(a: &Self, b: &Self) -> Rarray2D { + pub fn outer(a: &Self, b: &Self) -> Rarray2D { let mut row = a.shape.height; if a.shape.width > row { row = a.shape.width; @@ -71,9 +75,9 @@ impl Rarray1D { col = b.shape.width; } - let mut result: Rarray2D = Rarray2D { + let mut result: Rarray2D = Rarray2D { shape: D2 { height: row, width: col }, - data: vec![0.; row * col] + data: vec![T::default(); row * col] }; for i in 0..row { @@ -86,7 +90,7 @@ impl Rarray1D { } /// Sum values of array - pub fn sum(&self) -> f64 { + pub fn sum(&self) -> T { self.data.iter().sum() } diff --git a/src/linalg/rarray2d_impl.rs b/src/linalg/rarray2d_impl.rs index 7d5ed15..b378f48 100644 --- a/src/linalg/rarray2d_impl.rs +++ b/src/linalg/rarray2d_impl.rs @@ -5,11 +5,12 @@ use core::fmt; use std::ops::{Mul, MulAssign, Index, IndexMut}; - +use num_traits::Num; +use crate::linalg::numeric_trait::Numeric; use super::rarray::{Rarray2D, RarrayCreate, RarrayMul, D2}; -impl Index<[usize; 2]> for Rarray2D { - type Output = f64; +impl Index<[usize; 2]> for Rarray2D { + type Output = T; fn index(&self, index: [usize; 2]) -> &Self::Output { assert!((index[0] < self.shape[0]) && index[1] < self.shape[1], "Index out of bounds"); @@ -17,28 +18,30 @@ impl Index<[usize; 2]> for Rarray2D { } } -impl IndexMut<[usize; 2]> for Rarray2D { +impl IndexMut<[usize; 2]> for Rarray2D { fn index_mut(&mut self, index: [usize; 2]) -> &mut Self::Output { assert!((index[0] < self.shape[0]) && index[1] < self.shape[1], "Index out of bounds"); &mut self.data[index[0] * self.shape[0] + index[1]] } } -impl Mul<&Rarray2D> for &Rarray2D { - type Output = Rarray2D; +impl Mul<&Rarray2D> for &Rarray2D { + type Output = Rarray2D; - fn mul(self, rhs: &Rarray2D) -> Self::Output { + fn mul(self, rhs: &Rarray2D) -> Self::Output { Rarray2D::mul(self, rhs) } } -impl MulAssign<&Rarray2D> for Rarray2D { - fn mul_assign(&mut self, rhs: &Rarray2D) { +impl MulAssign<&Rarray2D> for Rarray2D where + T: Numeric +{ + fn mul_assign(&mut self, rhs: &Rarray2D) { self.data = Rarray2D::mul(self, rhs).data; } } -impl fmt::Display for Rarray2D { +impl fmt::Display for Rarray2D { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut formatted_string: String = String::new(); for i in 0..self.shape.height { @@ -55,7 +58,9 @@ impl fmt::Display for Rarray2D { } } -impl RarrayCreate<(usize, usize), Vec>, f64> for Rarray2D { +impl RarrayCreate<(usize, usize), Vec>, T> for Rarray2D where + T: Numeric +{ /// Create 2D matrix using Vec /// /// # Examples @@ -64,7 +69,7 @@ impl RarrayCreate<(usize, usize), Vec>, f64> for Rarray2D { ///use rumpy::linalg::rarray::Rarray2D; ///use crate::rumpy::linalg::rarray::RarrayCreate; /// - ///let m = Rarray2D::new(&vec![ + ///let m = Rarray2D::::new(&vec![ /// vec![1., 1., 1.], /// vec![1., 1., 1.], /// vec![1., 1., 1.] @@ -76,7 +81,7 @@ impl RarrayCreate<(usize, usize), Vec>, f64> for Rarray2D { /// # Panics /// /// If not all rows are of same length - fn new(data: &Vec>) -> Self { + fn new(data: &Vec>) -> Self { let row = data.len(); let col = data[0].len(); for i in 0..row { @@ -97,14 +102,14 @@ impl RarrayCreate<(usize, usize), Vec>, f64> for Rarray2D { /// use rumpy::linalg::rarray::Rarray2D; /// use crate::rumpy::linalg::rarray::RarrayCreate; /// - /// let m = Rarray2D::zeros((3, 3)); + /// let m = Rarray2D::::zeros((3, 3)); /// println!("{}", m); /// // >> Rarray2D([0., 0., 0.], [0., 0., 0.], [0., 0., 0.]) /// ``` fn zeros(shape: (usize, usize)) -> Self { Rarray2D { shape: D2 { height: shape.0, width: shape.1 }, - data: vec![0.; shape.0 * shape.1] + data: vec![T::default(); shape.0 * shape.1] } } @@ -121,9 +126,9 @@ impl RarrayCreate<(usize, usize), Vec>, f64> for Rarray2D { /// // >> Rarray2D([]) /// ``` fn random(shape: (usize, usize)) -> Self { - let mut data = Vec::::with_capacity(shape.0 * shape.1); + let mut data = Vec::::with_capacity(shape.0 * shape.1); for _ in 0..(shape.0 * shape.1) { - data.push(rand::random::()); + data.push(rand::random::()); } Rarray2D { @@ -144,7 +149,7 @@ impl RarrayCreate<(usize, usize), Vec>, f64> for Rarray2D { /// println!("{}", m); /// // >> Rarray2D([[4., 4., 4.], [4., 4., 4.], [4., 4., 4.]]) /// ``` - fn fill(value: f64, shape: (usize, usize)) -> Self { + fn fill(value: T, shape: (usize, usize)) -> Self { Rarray2D { shape: D2 { height: shape.0, width: shape.1 }, data: vec![value; shape.0 * shape.1] @@ -152,7 +157,9 @@ impl RarrayCreate<(usize, usize), Vec>, f64> for Rarray2D { } } -impl Rarray2D { +impl Rarray2D where + T: Numeric +{ /// Create 2D matrix of shape `m x n` filled with `value` /// /// # Examples @@ -167,11 +174,11 @@ impl Rarray2D { pub fn ones(shape: usize) -> Self { let mut result = Rarray2D { shape: D2 { height: shape, width: shape }, - data: vec![0.; shape * shape] + data: vec![T::default(); shape * shape] }; for i in 0..shape { - result.data[shape * i + i] = 1. + result.data[shape * i + i]; } result diff --git a/src/linalg/rarray_impl.rs b/src/linalg/rarray_impl.rs index 0a5a3a2..3fd91fc 100644 --- a/src/linalg/rarray_impl.rs +++ b/src/linalg/rarray_impl.rs @@ -1,8 +1,9 @@ use super::rarray::{Rarray, Rarray1D, RarrayAdd, RarraySub}; use std::{ops::{Add, AddAssign, Index, IndexMut, Mul, MulAssign, Sub, SubAssign}, usize}; use std::fmt::Debug; -use std::process::Output; +use std::ops::Neg; use crate::linalg::dimension::Dim; +use crate::linalg::numeric_trait::Numeric; impl Rarray { /// Return shape of array @@ -17,7 +18,7 @@ impl Rarray { // Base operations for the Rarray abstract struct impl Add<&Rarray> for &Rarray where - T : Add + Copy + Default, + T : Numeric, D : Copy + Dim + Debug + Eq { type Output = Rarray; @@ -28,7 +29,7 @@ impl Add<&Rarray> for &Rarray where } impl AddAssign<&Rarray> for Rarray where - T: Add + Copy + Default, + T: Numeric, D: Copy + Dim + Debug + Eq { fn add_assign(&mut self, rhs: &Rarray) { @@ -38,7 +39,7 @@ impl AddAssign<&Rarray> for Rarray where impl Sub<&Rarray> for &Rarray where - T : Sub + Copy + Default, + T : Numeric, D : Copy + Dim + Debug + Eq { type Output = Rarray; @@ -50,7 +51,7 @@ impl Sub<&Rarray> for &Rarray where impl SubAssign<&Rarray> for Rarray where - T : Sub + Copy + Default, + T : Numeric, D : Copy + Dim + Debug + Eq { fn sub_assign(&mut self, rhs: &Rarray) { From bbe68a06848db351786f7d71ef73db03c02480b9 Mon Sep 17 00:00:00 2001 From: Mathieu Groenen Date: Sun, 23 Mar 2025 23:20:04 +0100 Subject: [PATCH 2/2] Finished basic implementation for generic arrays --- Cargo.toml | 3 -- src/linalg/dimension.rs | 6 ++-- src/linalg/numeric_trait.rs | 20 ++++++++++-- src/linalg/rarray.rs | 12 +++---- src/linalg/rarray1d_create.rs | 60 +++-------------------------------- src/linalg/rarray1d_impl.rs | 6 ++-- src/linalg/rarray1d_ops.rs | 12 +++---- src/linalg/rarray2d_impl.rs | 37 +++++---------------- src/linalg/rarray_impl.rs | 8 ++--- tests/rarray1d_create_test.rs | 13 +++----- 10 files changed, 53 insertions(+), 124 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9b1bf1d..37bf86f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,8 +6,5 @@ edition = "2021" [dependencies] rand="0.9.0" -num-traits = "0.2" - - [dev-dependencies] rstest = "0.25.0" diff --git a/src/linalg/dimension.rs b/src/linalg/dimension.rs index 96dba59..63a01b4 100644 --- a/src/linalg/dimension.rs +++ b/src/linalg/dimension.rs @@ -29,7 +29,7 @@ impl PartialEq for D1 { } fn ne(&self, other: &Self) -> bool { - self.width == other.width || self.height == other.height + self.width != other.width || self.height != other.height } } @@ -60,7 +60,7 @@ impl PartialEq for D2 { } fn ne(&self, other: &Self) -> bool { - self.width == other.width || self.height == other.height + self.width != other.width || self.height != other.height } } @@ -93,7 +93,7 @@ impl PartialEq for D3 { } fn ne(&self, other: &Self) -> bool { - self.width == other.width || self.height == other.height || self.depth == other.depth + self.width != other.width || self.height != other.height || self.depth != other.depth } } diff --git a/src/linalg/numeric_trait.rs b/src/linalg/numeric_trait.rs index 4dcd7ba..d4fb05e 100644 --- a/src/linalg/numeric_trait.rs +++ b/src/linalg/numeric_trait.rs @@ -1,11 +1,25 @@ use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; -pub trait Numeric: Add + AddAssign + Sub + SubAssign + Div + DivAssign + Mul + MulAssign + Copy + Default {} +/// Specifies that a generic type is a numerical type +pub trait Numeric: + Add + + AddAssign + + Sub + + SubAssign + + Div + + DivAssign + + Mul + + MulAssign + + Copy + + Default + + ToString + + From + {} impl Numeric for T where T: Add + AddAssign + Sub + SubAssign + Div + DivAssign + - Mul + MulAssign + - Copy + Default {} \ No newline at end of file + Mul + MulAssign + + ToString + Copy + Default + From {} \ No newline at end of file diff --git a/src/linalg/rarray.rs b/src/linalg/rarray.rs index 53997f0..d47ebc3 100644 --- a/src/linalg/rarray.rs +++ b/src/linalg/rarray.rs @@ -1,14 +1,13 @@ use std::fmt::Debug; -use std::ops::{Add, AddAssign, Mul, MulAssign, Sub}; +use std::ops::Neg; use std::usize; -use num_traits::Num; -use rand::seq::IndexedRandom; use crate::linalg::numeric_trait::Numeric; pub(crate) use super::dimension::{Dim, D1, D2, D3}; -// Base array struct +/// Base array struct +/// Consists of data field which is a 1 dimensional `Vec` and of a shape field which is of type `Dim` #[derive(Debug)] -pub struct Rarray { +pub struct Rarray { pub(crate) data: Vec, pub(crate) shape: D } @@ -21,7 +20,6 @@ pub type Rarray3D = Rarray; pub trait RarrayCreate { fn new(data: &V) -> Self; fn zeros(shape: T) -> Self; - fn random(shape: T) -> Self; fn fill(value: S, shape: T) -> Self; } @@ -179,4 +177,4 @@ impl RarraySub, Rarray, Rarray> for Rarray result } -} +} \ No newline at end of file diff --git a/src/linalg/rarray1d_create.rs b/src/linalg/rarray1d_create.rs index 805bf7a..2757435 100644 --- a/src/linalg/rarray1d_create.rs +++ b/src/linalg/rarray1d_create.rs @@ -1,5 +1,4 @@ use std::cmp::max; -use num_traits::Num; use crate::linalg::dimension::{D1, D2}; use crate::linalg::numeric_trait::Numeric; use crate::linalg::rarray::{Rarray1D, Rarray2D, RarrayCreate}; @@ -35,7 +34,7 @@ impl RarrayCreate, T> for Rarray1D where ///use rumpy::linalg::rarray::Rarray1D; ///use crate::rumpy::linalg::rarray::RarrayCreate; /// - /// let v = Rarray1D::zeros(3); + /// let v = Rarray1D::::zeros(3); /// println!("{}", v); /// ``` fn zeros(shape: usize) -> Self { @@ -45,30 +44,6 @@ impl RarrayCreate, T> for Rarray1D where } } - /// Create rarray1D vector of length `shape` filled with random numbers - /// - /// # Examples - /// - /// ``` - /// use rumpy::linalg::rarray::Rarray1D; - /// use crate::rumpy::linalg::rarray::RarrayCreate; - /// - /// let v = Rarray1D::random(3); - /// println!("{}", v); - /// ``` - fn random(shape: usize) -> Self { - let mut data = Vec::::with_capacity(shape); - for _ in 0..shape { - data.push(rand::random::()); - } - - - Rarray1D { - shape: D1 { width: shape, height: 1 }, - data - } - } - /// Create rarray1D vector of length `shape` filled with `value` /// /// # Examples @@ -127,7 +102,7 @@ impl RarrayCreate<(usize, usize), Vec>, T> for Rarray1D where /// use rumpy::linalg::rarray::Rarray1D; /// use crate::rumpy::linalg::rarray::RarrayCreate; /// - ///let v = Rarray1D::zeros((3, 1)); + ///let v = Rarray1D::::zeros((3, 1)); /// println!("{}", v); /// ``` /// @@ -142,34 +117,6 @@ impl RarrayCreate<(usize, usize), Vec>, T> for Rarray1D where } } - /// Create vector of shape` filled with random numbers - /// - /// # Examples - /// - /// ``` - /// use rumpy::linalg::rarray::Rarray1D; - /// use crate::rumpy::linalg::rarray::RarrayCreate; - /// - /// let v = Rarray1D::random((3, 1)); - /// println!("{}", v); - /// ``` - /// # Panics - /// - /// If (x, y) with x > 1 and y > 1 - fn random(shape: (usize, usize)) -> Self { - assert!(shape.0 == 1 || shape.1 == 1, "Cannot create 2D array using 1D array type"); - let mut data = Vec::::with_capacity(shape.0 * shape.1); - for _ in 0..(shape.0 * shape.1) { - data.push(rand::random::()); - } - - - Rarray1D { - shape: D1 { width: shape.1, height: shape.0 }, - data - } - } - /// Create vector of shape `m x 1` filled with `value` /// /// # Examples @@ -224,6 +171,7 @@ impl Rarray1D where result } + /// Create vector filled with values in given range with step size /// /// # Examples @@ -243,7 +191,7 @@ impl Rarray1D where }; for i in (start..stop).step_by(step) { - result.data.push(i); + result.data.push(T::from(i as i32)); } result diff --git a/src/linalg/rarray1d_impl.rs b/src/linalg/rarray1d_impl.rs index 3c37768..5821539 100644 --- a/src/linalg/rarray1d_impl.rs +++ b/src/linalg/rarray1d_impl.rs @@ -5,8 +5,6 @@ use core::fmt; use std::ops::{Index, IndexMut, Mul, MulAssign}; -use num_traits::Num; -use crate::linalg::dimension::D1; use crate::linalg::numeric_trait::Numeric; use super::rarray::{Rarray, Rarray1D, RarrayCreate, RarrayScalMul}; @@ -67,7 +65,9 @@ impl Mul<&Rarray1D> for &Rarray1D } } -impl fmt::Display for Rarray1D { +impl fmt::Display for Rarray1D where + T: Numeric +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut formatted_string: String = String::new(); for i in 0..self.shape.width { diff --git a/src/linalg/rarray1d_ops.rs b/src/linalg/rarray1d_ops.rs index b3307cc..5e370b6 100644 --- a/src/linalg/rarray1d_ops.rs +++ b/src/linalg/rarray1d_ops.rs @@ -1,11 +1,9 @@ -use std::cmp::max; -use std::iter::zip; -use std::ops::AddAssign; -use num_traits::Num; use crate::linalg::numeric_trait::Numeric; -use super::rarray::{Rarray1D, Rarray2D, RarrayCreate, D1, D2}; +use super::rarray::{Rarray1D, Rarray2D, D1, D2}; -impl Rarray1D { +impl Rarray1D where + T: Numeric +{ /// Tranpose 1D matrix pub fn transpose(&self) -> Self { Rarray1D { @@ -89,13 +87,13 @@ impl Rarray1D where result } + /* /// Sum values of array pub fn sum(&self) -> T { self.data.iter().sum() } // TODO: yet to implement functionality - /* pub fn unique(&self) -> Rarray1D { } diff --git a/src/linalg/rarray2d_impl.rs b/src/linalg/rarray2d_impl.rs index b378f48..03a4bab 100644 --- a/src/linalg/rarray2d_impl.rs +++ b/src/linalg/rarray2d_impl.rs @@ -5,7 +5,6 @@ use core::fmt; use std::ops::{Mul, MulAssign, Index, IndexMut}; -use num_traits::Num; use crate::linalg::numeric_trait::Numeric; use super::rarray::{Rarray2D, RarrayCreate, RarrayMul, D2}; @@ -25,7 +24,9 @@ impl IndexMut<[usize; 2]> for Rarray2D { } } -impl Mul<&Rarray2D> for &Rarray2D { +impl Mul<&Rarray2D> for &Rarray2D where + T: Numeric +{ type Output = Rarray2D; fn mul(self, rhs: &Rarray2D) -> Self::Output { @@ -41,7 +42,9 @@ impl MulAssign<&Rarray2D> for Rarray2D where } } -impl fmt::Display for Rarray2D { +impl fmt::Display for Rarray2D where + T: Numeric +{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut formatted_string: String = String::new(); for i in 0..self.shape.height { @@ -112,30 +115,6 @@ impl RarrayCreate<(usize, usize), Vec>, T> for Rarray2D where data: vec![T::default(); shape.0 * shape.1] } } - - /// Create 2D matrix of shape `m x n` filled with random numbers - /// - /// # Examples - /// - /// ``` - /// use rumpy::linalg::rarray::Rarray2D; - /// use crate::rumpy::linalg::rarray::RarrayCreate; - /// - /// let m = Rarray2D::random((3, 3)); - /// println!("{}", m); - /// // >> Rarray2D([]) - /// ``` - fn random(shape: (usize, usize)) -> Self { - let mut data = Vec::::with_capacity(shape.0 * shape.1); - for _ in 0..(shape.0 * shape.1) { - data.push(rand::random::()); - } - - Rarray2D { - shape: D2 { height: shape.0, width: shape.1 }, - data - } - } /// Create 2D matrix of shape `m x n` filled with `value` /// @@ -167,7 +146,7 @@ impl Rarray2D where /// ``` /// use rumpy::linalg::rarray::Rarray2D; /// - /// let m = Rarray2D::ones(3); + /// let m = Rarray2D::::ones(3); /// println!("{}", m); /// // >> Rarray2D([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]]) /// ``` @@ -178,7 +157,7 @@ impl Rarray2D where }; for i in 0..shape { - result.data[shape * i + i]; + result.data[shape * i + i] = T::from(1); } result diff --git a/src/linalg/rarray_impl.rs b/src/linalg/rarray_impl.rs index 3fd91fc..db39955 100644 --- a/src/linalg/rarray_impl.rs +++ b/src/linalg/rarray_impl.rs @@ -5,15 +5,13 @@ use std::ops::Neg; use crate::linalg::dimension::Dim; use crate::linalg::numeric_trait::Numeric; -impl Rarray { +impl Rarray where + D: Dim +{ /// Return shape of array pub fn get_shape(&self) -> &D { &self.shape } - // TODO: Implement following functions - - /// Move ownership of array - pub fn to_owned(self) {} } // Base operations for the Rarray abstract struct diff --git a/tests/rarray1d_create_test.rs b/tests/rarray1d_create_test.rs index 2cf6f3b..aa2d18f 100644 --- a/tests/rarray1d_create_test.rs +++ b/tests/rarray1d_create_test.rs @@ -1,16 +1,13 @@ mod test { - use std::alloc::handle_alloc_error; - use std::env::var; use rstest::rstest; - use rumpy::linalg::rarray; - use rumpy::linalg::rarray::{Rarray1D, Rarray2D, RarrayCreate}; + use rumpy::linalg::rarray::{Rarray1D, RarrayCreate}; #[rstest] #[case(vec![1., 1., 1.])] #[case(vec![0.])] #[case(vec![2.4, 2., 1., 0.4, 6.,])] fn rarray1d_new_hor(#[case] a: Vec){ - let rarray_a = Rarray1D::new(&a); + let rarray_a = Rarray1D::::new(&a); for i in 0..a.len() { assert_eq!(a[i], rarray_a[i]); } @@ -21,7 +18,7 @@ mod test { #[case(vec![vec![0.]])] #[case(vec![vec![2.4], vec![2.], vec![1.], vec![0.4], vec![6.]])] fn rarray1d_new_ver(#[case] a: Vec>){ - let rarray_a = Rarray1D::new(&a); + let rarray_a = Rarray1D::::new(&a); for i in 0..a[0].len() { assert_eq!(a[0][i], rarray_a[i]); } @@ -32,7 +29,7 @@ mod test { #[case(1)] #[case(10)] fn rarray1d_zeros_hor(#[case] shape: usize){ - let rarray_zeros = Rarray1D::zeros(shape); + let rarray_zeros = Rarray1D::::zeros(shape); for i in 0..shape { assert_eq!(rarray_zeros[i], 0.); } @@ -43,7 +40,7 @@ mod test { #[case(1, 1)] #[case(10, 1)] fn rarray1d_zeros_ver(#[case] height: usize, #[case] width: usize){ - let rarray_zeros = Rarray1D::zeros((height, width)); + let rarray_zeros = Rarray1D::::zeros((height, width)); for i in 0..height { assert_eq!(rarray_zeros[i], 0.); }