//! # Linear Algebra and Matrix Decomposition //! //! Most machine learning algorithms in SmartCore depend on linear algebra and matrix decomposition methods from this module. //! //! Traits [`BaseMatrix`](trait.BaseMatrix.html), [`Matrix`](trait.Matrix.html) and [`BaseVector`](trait.BaseVector.html) define //! abstract methods that can be implemented for any two-dimensional and one-dimentional arrays (matrix and vector). //! Functions from these traits are designed for SmartCore machine learning algorithms and should not be used directly in your code. //! If you still want to use functions from `BaseMatrix`, `Matrix` and `BaseVector` please be aware that methods defined in these //! traits might change in the future. //! //! One reason why linear algebra traits are public is to allow for different types of matrices and vectors to be plugged into SmartCore. //! Once all methods defined in `BaseMatrix`, `Matrix` and `BaseVector` are implemented for your favourite type of matrix and vector you //! should be able to run SmartCore algorithms on it. Please see `nalgebra_bindings` and `ndarray_bindings` modules for an example of how //! it is done for other libraries. //! //! You will also find verious matrix decomposition methods that work for any matrix that extends [`Matrix`](trait.Matrix.html). //! For example, to decompose matrix defined as [Vec](https://doc.rust-lang.org/std/vec/struct.Vec.html): //! //! ``` //! use smartcore::linalg::naive::dense_matrix::*; //! use smartcore::linalg::svd::*; //! //! let A = DenseMatrix::from_2d_array(&[ //! &[0.9000, 0.4000, 0.7000], //! &[0.4000, 0.5000, 0.3000], //! &[0.7000, 0.3000, 0.8000], //! ]); //! //! let svd = A.svd().unwrap(); //! //! let s: Vec = svd.s; //! let v: DenseMatrix = svd.V; //! let u: DenseMatrix = svd.U; //! ``` /// The matrix is represented in terms of its eigenvalues and eigenvectors. pub mod evd; /// Factors a matrix as the product of a lower triangular matrix and an upper triangular matrix. pub mod lu; /// Dense matrix with column-major order that wraps [Vec](https://doc.rust-lang.org/std/vec/struct.Vec.html). pub mod naive; /// [nalgebra](https://docs.rs/nalgebra/) bindings. #[cfg(feature = "nalgebra-bindings")] pub mod nalgebra_bindings; /// [ndarray](https://docs.rs/ndarray) bindings. #[cfg(feature = "ndarray-bindings")] pub mod ndarray_bindings; /// QR factorization that factors a matrix into a product of an orthogonal matrix and an upper triangular matrix. pub mod qr; /// Singular value decomposition. pub mod svd; use std::fmt::{Debug, Display}; use std::marker::PhantomData; use std::ops::Range; use crate::math::num::RealNumber; use evd::EVDDecomposableMatrix; use lu::LUDecomposableMatrix; use qr::QRDecomposableMatrix; use svd::SVDDecomposableMatrix; /// Column or row vector pub trait BaseVector: Clone + Debug { /// Get an element of a vector /// * `i` - index of an element fn get(&self, i: usize) -> T; /// Set an element at `i` to `x` /// * `i` - index of an element /// * `x` - new value fn set(&mut self, i: usize, x: T); /// Get number of elevemnt in the vector fn len(&self) -> usize; /// Return a vector with the elements of the one-dimensional array. fn to_vec(&self) -> Vec; /// Create new vector with zeros of size `len`. fn zeros(len: usize) -> Self; /// Create new vector with ones of size `len`. fn ones(len: usize) -> Self; /// Create new vector of size `len` where each element is set to `value`. fn fill(len: usize, value: T) -> Self; /// Vector dot product fn dot(&self, other: &Self) -> T; /// Returns True if matrices are element-wise equal within a tolerance `error`. fn approximate_eq(&self, other: &Self, error: T) -> bool; } /// Generic matrix type. pub trait BaseMatrix: Clone + Debug { /// Row vector that is associated with this matrix type, /// e.g. if we have an implementation of sparce matrix /// we should have an associated sparce vector type that /// represents a row in this matrix. type RowVector: BaseVector + Clone + Debug; /// Transforms row vector `vec` into a 1xM matrix. fn from_row_vector(vec: Self::RowVector) -> Self; /// Transforms 1-d matrix of 1xM into a row vector. fn to_row_vector(self) -> Self::RowVector; /// Get an element of the matrix. /// * `row` - row number /// * `col` - column number fn get(&self, row: usize, col: usize) -> T; /// Get a vector with elements of the `row`'th row /// * `row` - row number fn get_row_as_vec(&self, row: usize) -> Vec; /// Get the `row`'th row /// * `row` - row number fn get_row(&self, row: usize) -> Self::RowVector; /// Copies a vector with elements of the `row`'th row into `result` /// * `row` - row number /// * `result` - receiver for the row fn copy_row_as_vec(&self, row: usize, result: &mut Vec); /// Get a vector with elements of the `col`'th column /// * `col` - column number fn get_col_as_vec(&self, col: usize) -> Vec; /// Copies a vector with elements of the `col`'th column into `result` /// * `col` - column number /// * `result` - receiver for the col fn copy_col_as_vec(&self, col: usize, result: &mut Vec); /// Set an element at `col`, `row` to `x` fn set(&mut self, row: usize, col: usize, x: T); /// Create an identity matrix of size `size` fn eye(size: usize) -> Self; /// Create new matrix with zeros of size `nrows` by `ncols`. fn zeros(nrows: usize, ncols: usize) -> Self; /// Create new matrix with ones of size `nrows` by `ncols`. fn ones(nrows: usize, ncols: usize) -> Self; /// Create new matrix of size `nrows` by `ncols` where each element is set to `value`. fn fill(nrows: usize, ncols: usize, value: T) -> Self; /// Return the shape of an array. fn shape(&self) -> (usize, usize); /// Stack arrays in sequence vertically (row wise). /// ``` /// use smartcore::linalg::naive::dense_matrix::*; /// /// let a = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.]]); /// let b = DenseMatrix::from_2d_array(&[&[1., 2.], &[3., 4.]]); /// let expected = DenseMatrix::from_2d_array(&[ /// &[1., 2., 3., 1., 2.], /// &[4., 5., 6., 3., 4.] /// ]); /// /// assert_eq!(a.h_stack(&b), expected); /// ``` fn h_stack(&self, other: &Self) -> Self; /// Stack arrays in sequence horizontally (column wise). /// ``` /// use smartcore::linalg::naive::dense_matrix::*; /// /// let a = DenseMatrix::from_array(1, 3, &[1., 2., 3.]); /// let b = DenseMatrix::from_array(1, 3, &[4., 5., 6.]); /// let expected = DenseMatrix::from_2d_array(&[ /// &[1., 2., 3.], /// &[4., 5., 6.] /// ]); /// /// assert_eq!(a.v_stack(&b), expected); /// ``` fn v_stack(&self, other: &Self) -> Self; /// Matrix product. /// ``` /// use smartcore::linalg::naive::dense_matrix::*; /// /// let a = DenseMatrix::from_2d_array(&[&[1., 2.], &[3., 4.]]); /// let expected = DenseMatrix::from_2d_array(&[ /// &[7., 10.], /// &[15., 22.] /// ]); /// /// assert_eq!(a.matmul(&a), expected); /// ``` fn matmul(&self, other: &Self) -> Self; /// Vector dot product /// Both matrices should be of size _1xM_ /// ``` /// use smartcore::linalg::naive::dense_matrix::*; /// /// let a = DenseMatrix::from_array(1, 3, &[1., 2., 3.]); /// let b = DenseMatrix::from_array(1, 3, &[4., 5., 6.]); /// /// assert_eq!(a.dot(&b), 32.); /// ``` fn dot(&self, other: &Self) -> T; /// Return a slice of the matrix. /// * `rows` - range of rows to return /// * `cols` - range of columns to return /// ``` /// use smartcore::linalg::naive::dense_matrix::*; /// /// let m = DenseMatrix::from_2d_array(&[ /// &[1., 2., 3., 1.], /// &[4., 5., 6., 3.], /// &[7., 8., 9., 5.] /// ]); /// let expected = DenseMatrix::from_2d_array(&[&[2., 3.], &[5., 6.]]); /// let result = m.slice(0..2, 1..3); /// assert_eq!(result, expected); /// ``` fn slice(&self, rows: Range, cols: Range) -> Self; /// Returns True if matrices are element-wise equal within a tolerance `error`. fn approximate_eq(&self, other: &Self, error: T) -> bool; /// Add matrices, element-wise, overriding original matrix with result. fn add_mut(&mut self, other: &Self) -> &Self; /// Subtract matrices, element-wise, overriding original matrix with result. fn sub_mut(&mut self, other: &Self) -> &Self; /// Multiply matrices, element-wise, overriding original matrix with result. fn mul_mut(&mut self, other: &Self) -> &Self; /// Divide matrices, element-wise, overriding original matrix with result. fn div_mut(&mut self, other: &Self) -> &Self; /// Divide single element of the matrix by `x`, write result to original matrix. fn div_element_mut(&mut self, row: usize, col: usize, x: T); /// Multiply single element of the matrix by `x`, write result to original matrix. fn mul_element_mut(&mut self, row: usize, col: usize, x: T); /// Add single element of the matrix to `x`, write result to original matrix. fn add_element_mut(&mut self, row: usize, col: usize, x: T); /// Subtract `x` from single element of the matrix, write result to original matrix. fn sub_element_mut(&mut self, row: usize, col: usize, x: T); /// Add matrices, element-wise fn add(&self, other: &Self) -> Self { let mut r = self.clone(); r.add_mut(other); r } /// Subtract matrices, element-wise fn sub(&self, other: &Self) -> Self { let mut r = self.clone(); r.sub_mut(other); r } /// Multiply matrices, element-wise fn mul(&self, other: &Self) -> Self { let mut r = self.clone(); r.mul_mut(other); r } /// Divide matrices, element-wise fn div(&self, other: &Self) -> Self { let mut r = self.clone(); r.div_mut(other); r } /// Add `scalar` to the matrix, override original matrix with result. fn add_scalar_mut(&mut self, scalar: T) -> &Self; /// Subtract `scalar` from the elements of matrix, override original matrix with result. fn sub_scalar_mut(&mut self, scalar: T) -> &Self; /// Multiply `scalar` by the elements of matrix, override original matrix with result. fn mul_scalar_mut(&mut self, scalar: T) -> &Self; /// Divide elements of the matrix by `scalar`, override original matrix with result. fn div_scalar_mut(&mut self, scalar: T) -> &Self; /// Add `scalar` to the matrix. fn add_scalar(&self, scalar: T) -> Self { let mut r = self.clone(); r.add_scalar_mut(scalar); r } /// Subtract `scalar` from the elements of matrix. fn sub_scalar(&self, scalar: T) -> Self { let mut r = self.clone(); r.sub_scalar_mut(scalar); r } /// Multiply `scalar` by the elements of matrix. fn mul_scalar(&self, scalar: T) -> Self { let mut r = self.clone(); r.mul_scalar_mut(scalar); r } /// Divide elements of the matrix by `scalar`. fn div_scalar(&self, scalar: T) -> Self { let mut r = self.clone(); r.div_scalar_mut(scalar); r } /// Reverse or permute the axes of the matrix, return new matrix. fn transpose(&self) -> Self; /// Create new `nrows` by `ncols` matrix and populate it with random samples from a uniform distribution over [0, 1). fn rand(nrows: usize, ncols: usize) -> Self; /// Returns [L2 norm](https://en.wikipedia.org/wiki/Matrix_norm). fn norm2(&self) -> T; /// Returns [matrix norm](https://en.wikipedia.org/wiki/Matrix_norm) of order `p`. fn norm(&self, p: T) -> T; /// Returns the average of the matrix columns. fn column_mean(&self) -> Vec; /// Numerical negative, element-wise. Overrides original matrix. fn negative_mut(&mut self); /// Numerical negative, element-wise. fn negative(&self) -> Self { let mut result = self.clone(); result.negative_mut(); result } /// Returns new matrix of shape `nrows` by `ncols` with data copied from original matrix. /// ``` /// use smartcore::linalg::naive::dense_matrix::*; /// /// let a = DenseMatrix::from_array(1, 6, &[1., 2., 3., 4., 5., 6.]); /// let expected = DenseMatrix::from_2d_array(&[ /// &[1., 2., 3.], /// &[4., 5., 6.] /// ]); /// /// assert_eq!(a.reshape(2, 3), expected); /// ``` fn reshape(&self, nrows: usize, ncols: usize) -> Self; /// Copies content of `other` matrix. fn copy_from(&mut self, other: &Self); /// Calculate the absolute value element-wise. Overrides original matrix. fn abs_mut(&mut self) -> &Self; /// Calculate the absolute value element-wise. fn abs(&self) -> Self { let mut result = self.clone(); result.abs_mut(); result } /// Calculates sum of all elements of the matrix. fn sum(&self) -> T; /// Calculates max of all elements of the matrix. fn max(&self) -> T; /// Calculates min of all elements of the matrix. fn min(&self) -> T; /// Calculates max(|a - b|) of two matrices /// ``` /// use smartcore::linalg::naive::dense_matrix::*; /// /// let a = DenseMatrix::from_array(2, 3, &[1., 2., 3., 4., -5., 6.]); /// let b = DenseMatrix::from_array(2, 3, &[2., 3., 4., 1., 0., -12.]); /// /// assert_eq!(a.max_diff(&b), 18.); /// assert_eq!(b.max_diff(&b), 0.); /// ``` fn max_diff(&self, other: &Self) -> T { self.sub(other).abs().max() } /// Calculates [Softmax function](https://en.wikipedia.org/wiki/Softmax_function). Overrides the matrix with result. fn softmax_mut(&mut self); /// Raises elements of the matrix to the power of `p` fn pow_mut(&mut self, p: T) -> &Self; /// Returns new matrix with elements raised to the power of `p` fn pow(&mut self, p: T) -> Self { let mut result = self.clone(); result.pow_mut(p); result } /// Returns the indices of the maximum values in each row. /// ``` /// use smartcore::linalg::naive::dense_matrix::*; /// let a = DenseMatrix::from_array(2, 3, &[1., 2., 3., -5., -6., -7.]); /// /// assert_eq!(a.argmax(), vec![2, 0]); /// ``` fn argmax(&self) -> Vec; /// Returns vector with unique values from the matrix. /// ``` /// use smartcore::linalg::naive::dense_matrix::*; /// let a = DenseMatrix::from_array(3, 3, &[1., 2., 2., -2., -6., -7., 2., 3., 4.]); /// ///assert_eq!(a.unique(), vec![-7., -6., -2., 1., 2., 3., 4.]); /// ``` fn unique(&self) -> Vec; /// Calculates the covariance matrix fn cov(&self) -> Self; } /// Generic matrix with additional mixins like various factorization methods. pub trait Matrix: BaseMatrix + SVDDecomposableMatrix + EVDDecomposableMatrix + QRDecomposableMatrix + LUDecomposableMatrix + PartialEq + Display { } pub(crate) fn row_iter>(m: &M) -> RowIter { RowIter { m: m, pos: 0, max_pos: m.shape().0, phantom: PhantomData, } } pub(crate) struct RowIter<'a, T: RealNumber, M: BaseMatrix> { m: &'a M, pos: usize, max_pos: usize, phantom: PhantomData<&'a T>, } impl<'a, T: RealNumber, M: BaseMatrix> Iterator for RowIter<'a, T, M> { type Item = Vec; fn next(&mut self) -> Option> { let res; if self.pos < self.max_pos { res = Some(self.m.get_row_as_vec(self.pos)) } else { res = None } self.pos += 1; res } }