use std::ops::{Add, Sub, Mul, Neg, Div};
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};
pub mod iterators;
pub mod slices;
mod errors;
pub use errors::ScalarConversionError;
use crate::matrices::iterators::{
ColumnIterator, RowIterator,
ColumnMajorIterator, RowMajorIterator,
ColumnReferenceIterator, RowReferenceIterator,
ColumnMajorReferenceIterator, RowMajorReferenceIterator};
use crate::matrices::slices::Slice2D;
use crate::numeric::{Numeric, NumericRef};
use crate::numeric::extra::{Real, RealRef};
use crate::linear_algebra;
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Matrix<T> {
data: Vec<T>,
rows: Row,
columns: Column,
}
pub type Row = usize;
pub type Column = usize;
impl <T> Matrix<T> {
pub fn from_scalar(value: T) -> Matrix<T> {
Matrix {
data: vec![value],
rows: 1,
columns: 1,
}
}
pub fn row(values: Vec<T>) -> Matrix<T> {
Matrix {
columns: values.len(),
data: values,
rows: 1,
}
}
pub fn column(values: Vec<T>) -> Matrix<T> {
Matrix {
rows: values.len(),
data: values,
columns: 1,
}
}
#[track_caller]
pub fn from(mut values: Vec<Vec<T>>) -> Matrix<T> {
assert!(!values.is_empty(), "No rows defined");
assert!(!values[0].is_empty(), "No column defined");
assert!(values.iter().map(|x| x.len()).all(|x| x == values[0].len()), "Inconsistent size");
let rows = values.len();
let columns = values[0].len();
let mut data = Vec::with_capacity(rows * columns);
let mut value_stream = values.drain(..);
for _ in 0..rows {
let mut value_row_stream = value_stream.next().unwrap();
let mut row_of_values = value_row_stream.drain(..);
for _ in 0..columns {
data.push(row_of_values.next().unwrap());
}
}
Matrix {
data,
rows,
columns,
}
}
#[track_caller]
pub fn from_flat_row_major(size: (Row, Column), values: Vec<T>) -> Matrix<T> {
assert!(size.0 * size.1 == values.len(),
"Inconsistent size, attempted to construct a {}x{} matrix but provided with {} elements.",
size.0, size.1, values.len());
Matrix {
data: values,
rows: size.0,
columns: size.1,
}
}
#[deprecated(since="1.1.0", note="Incorrect use of terminology, a unit matrix is another term for an identity matrix, please use `from_scalar` instead")]
pub fn unit(value: T) -> Matrix<T> {
Matrix::from_scalar(value)
}
pub fn size(&self) -> (Row, Column) {
(self.rows, self.columns)
}
pub fn rows(&self) -> Row {
self.rows
}
pub fn columns(&self) -> Column {
self.columns
}
fn get_index(&self, row: Row, column: Column) -> usize {
column + (row * self.columns())
}
#[allow(dead_code)]
fn get_row_column(&self, index: usize) -> (Row, Column) {
(index / self.columns(), index % self.columns())
}
#[track_caller]
pub fn get_reference(&self, row: Row, column: Column) -> &T {
assert!(row < self.rows(), "Row out of index");
assert!(column < self.columns(), "Column out of index");
&self.data[self.get_index(row, column)]
}
#[track_caller]
pub fn set(&mut self, row: Row, column: Column, value: T) {
assert!(row < self.rows(), "Row out of index");
assert!(column < self.columns(), "Column out of index");
let columns = self.columns();
self.data[column + (row * columns)] = value;
}
#[track_caller]
pub fn remove_row(&mut self, row: Row) {
assert!(self.rows() > 1);
let mut r = 0;
let mut c = 0;
let columns = self.columns();
self.data.retain(|_| {
let keep = r != row;
if c < (columns - 1) {
c += 1;
} else {
r += 1;
c = 0;
}
keep
});
self.rows -= 1;
}
#[track_caller]
pub fn remove_column(&mut self, column: Column) {
assert!(self.columns() > 1);
let mut r = 0;
let mut c = 0;
let columns = self.columns();
self.data.retain(|_| {
let keep = c != column;
if c < (columns - 1) {
c += 1;
} else {
r += 1;
c = 0;
}
keep
});
self.columns -= 1;
}
pub fn column_reference_iter(&self, column: Column) -> ColumnReferenceIterator<T> {
ColumnReferenceIterator::new(self, column)
}
pub fn row_reference_iter(&self, row: Row) -> RowReferenceIterator<T> {
RowReferenceIterator::new(self, row)
}
pub fn column_major_reference_iter(&self) -> ColumnMajorReferenceIterator<T> {
ColumnMajorReferenceIterator::new(self)
}
pub fn row_major_reference_iter(&self) -> RowMajorReferenceIterator<T> {
RowMajorReferenceIterator::new(self)
}
#[track_caller]
pub fn retain_mut(&mut self, slice: Slice2D) {
let mut r = 0;
let mut c = 0;
let columns = self.columns();
self.data.retain(|_| {
let keep = slice.accepts(r, c);
if c < (columns - 1) {
c += 1;
} else {
r += 1;
c = 0;
}
keep
});
let remaining_rows = {
let mut accepted = 0;
for i in 0..self.rows() {
if slice.rows.accepts(i) {
accepted += 1;
}
}
accepted
};
let remaining_columns = {
let mut accepted = 0;
for i in 0..self.columns() {
if slice.columns.accepts(i) {
accepted += 1;
}
}
accepted
};
assert!(
remaining_rows > 0,
"Provided slice must leave at least 1 row in the retained matrix");
assert!(
remaining_columns > 0,
"Provided slice must leave at least 1 column in the retained matrix");
assert!(
!self.data.is_empty(),
"Provided slice must leave at least 1 row and 1 column in the retained matrix");
self.rows = remaining_rows;
self.columns = remaining_columns
}
pub fn try_into_scalar(self) -> Result<T, ScalarConversionError> {
if self.size() == (1,1) {
Ok(self.data.into_iter().next().unwrap())
} else {
Err(ScalarConversionError {})
}
}
}
impl <T: Clone> Matrix<T> {
pub fn transpose(&self) -> Matrix<T> {
let mut result = Matrix::empty(self.get(0, 0), (self.columns(), self.rows()));
for i in 0..self.columns() {
for j in 0..self.rows() {
result.set(i, j, self.get(j, i).clone());
}
}
result
}
pub fn transpose_mut(&mut self) {
for i in 0..self.rows() {
for j in 0..self.columns() {
if i > j {
continue;
}
let temp = self.get(i, j);
self.set(i, j, self.get(j, i));
self.set(j, i, temp);
}
}
let rows = self.rows();
self.rows = self.columns();
self.columns = rows;
}
pub fn column_iter(&self, column: Column) -> ColumnIterator<T> {
ColumnIterator::new(self, column)
}
pub fn row_iter(&self, row: Row) -> RowIterator<T> {
RowIterator::new(self, row)
}
pub fn column_major_iter(&self) -> ColumnMajorIterator<T> {
ColumnMajorIterator::new(self)
}
pub fn row_major_iter(&self) -> RowMajorIterator<T> {
RowMajorIterator::new(self)
}
pub fn empty(value: T, size: (Row, Column)) -> Matrix<T> {
Matrix {
data: vec![value; size.0 * size.1],
rows: size.0,
columns: size.1,
}
}
#[track_caller]
pub fn get(&self, row: Row, column: Column) -> T {
assert!(row < self.rows(),
"Row out of index, only have {} rows", self.rows());
assert!(column < self.columns(),
"Column out of index, only have {} columns", self.columns());
self.data[self.get_index(row, column)].clone()
}
#[track_caller]
pub fn scalar(&self) -> T {
assert!(self.rows() == 1, "Cannot treat matrix as scalar as it has more than one row");
assert!(self.columns() == 1, "Cannot treat matrix as scalar as it has more than one column");
self.get(0, 0)
}
pub fn map_mut(&mut self, mapping_function: impl Fn(T) -> T) {
for value in self.data.iter_mut() {
*value = mapping_function(value.clone());
}
}
pub fn map_mut_with_index(&mut self, mapping_function: impl Fn(T, Row, Column) -> T) {
for i in 0..self.rows() {
for j in 0..self.columns() {
self.set(i, j, mapping_function(self.get(i, j), i, j));
}
}
}
pub fn map<U>(&self, mapping_function: impl Fn(T) -> U) -> Matrix<U>
where U: Clone {
let mapped = self.data.iter().map(|x| mapping_function(x.clone())).collect();
Matrix::from_flat_row_major(self.size(), mapped)
}
pub fn map_with_index<U>(&self, mapping_function: impl Fn(T, Row, Column) -> U) -> Matrix<U>
where U: Clone {
let first_value: U = mapping_function(self.get(0, 0), 0, 0);
let mut mapped = Matrix::empty(first_value, self.size());
for i in 0..self.rows() {
for j in 0..self.columns() {
mapped.set(i, j, mapping_function(self.get(i, j), i, j));
}
}
mapped
}
#[track_caller]
pub fn insert_row(&mut self, row: Row, value: T) {
assert!(row <= self.rows(), "Row to insert must be <= to {}", self.rows());
for column in 0..self.columns() {
self.data.insert(self.get_index(row, column), value.clone());
}
self.rows += 1;
}
#[track_caller]
pub fn insert_row_with<I>(&mut self, row: Row, mut values: I)
where I: Iterator<Item = T> {
assert!(row <= self.rows(), "Row to insert must be <= to {}", self.rows());
for column in 0..self.columns() {
self.data.insert(
self.get_index(row, column),
values.next()
.unwrap_or_else(|| panic!(
"At least {} values must be provided",
self.columns()
))
);
}
self.rows += 1;
}
#[track_caller]
pub fn insert_column(&mut self, column: Column, value: T) {
assert!(column <= self.columns(), "Column to insert must be <= to {}", self.columns());
for row in (0..self.rows()).rev() {
self.data.insert(self.get_index(row, column), value.clone());
}
self.columns += 1;
}
#[track_caller]
pub fn insert_column_with<I>(&mut self, column: Column, values: I)
where I: Iterator<Item = T> {
assert!(column <= self.columns(), "Column to insert must be <= to {}", self.columns());
let mut array_values = values.collect::<Vec<T>>();
assert!(array_values.len() >= self.rows(),
"At least {} values must be provided", self.rows());
for row in (0..self.rows()).rev() {
self.data.insert(
self.get_index(row, column),
array_values.pop().unwrap());
}
self.columns += 1;
}
pub fn retain(&self, slice: Slice2D) -> Matrix<T> {
let mut retained = self.clone();
retained.retain_mut(slice);
retained
}
}
impl <T: Clone> Clone for Matrix<T> {
fn clone(&self) -> Self {
self.map(|element| element)
}
}
impl <T: std::fmt::Display + Clone> std::fmt::Display for Matrix<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "[ ")?;
for row in 0..self.rows() {
if row > 0 {
write!(f, " ")?;
}
for column in 0..self.columns() {
write!(f, "{:.*}", f.precision().unwrap_or(3), self.get(row, column))?;
if column < self.columns() - 1 {
write!(f, ", ")?;
}
}
if row < self.rows() - 1 {
writeln!(f)?;
}
}
write!(f, " ]")
}
}
impl <T: Numeric> Matrix<T>
where for<'a> &'a T: NumericRef<T> {
pub fn determinant(&self) -> Option<T> {
linear_algebra::determinant::<T>(self)
}
pub fn inverse(&self) -> Option<Matrix<T>>
where T: Add<Output = T> + Mul<Output = T> + Sub<Output = T> + Div<Output = T> {
linear_algebra::inverse::<T>(self)
}
pub fn covariance_column_features(&self) -> Matrix<T> {
linear_algebra::covariance_column_features::<T>(self)
}
pub fn covariance_row_features(&self) -> Matrix<T> {
linear_algebra::covariance_row_features::<T>(self)
}
}
impl <T: Numeric + Real> Matrix<T>
where for<'a> &'a T: NumericRef<T> + RealRef<T> {
#[track_caller]
pub fn euclidean_length(&self) -> T {
if self.columns() == 1 {
(self.transpose() * self).scalar().sqrt()
} else if self.rows() == 1 {
(self * self.transpose()).scalar().sqrt()
} else {
panic!("Cannot compute unit vector of a non vector, rows: {}, columns: {}",
self.rows(), self.columns());
}
}
}
impl <T: Numeric> Matrix<T> {
#[track_caller]
pub fn diagonal(value: T, size: (Row, Column)) -> Matrix<T> {
assert!(size.0 == size.1);
let mut matrix = Matrix::empty(T::zero(), size);
for i in 0..size.0 {
matrix.set(i, i, value.clone());
}
matrix
}
}
impl <T: PartialEq> PartialEq for Matrix<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
if self.rows() != other.rows() {
return false;
}
if self.columns() != other.columns() {
return false;
}
self.data.iter()
.zip(other.data.iter())
.all(|(x, y)| x == y)
}
}
impl <T: Numeric> Mul for &Matrix<T>
where for<'a> &'a T: NumericRef<T> {
type Output = Matrix<T>;
#[track_caller]
#[inline]
fn mul(self, rhs: Self) -> Self::Output {
assert!(self.columns() == rhs.rows(),
"Mismatched Matrices, left is {}x{}, right is {}x{}, * is only defined for MxN * NxL",
self.rows(), self.columns(), rhs.rows(), rhs.columns());
let mut result = Matrix::empty(self.get(0, 0), (self.rows(), rhs.columns()));
for i in 0..self.rows() {
for j in 0..rhs.columns() {
result.set(i, j,
self.row_reference_iter(i)
.zip(rhs.column_reference_iter(j))
.map(|(x, y)| x * y)
.sum());
}
}
result
}
}
impl <T: Numeric> Mul for Matrix<T>
where for<'a> &'a T: NumericRef<T> {
type Output = Matrix<T>;
#[track_caller]
#[inline]
fn mul(self, rhs: Self) -> Self::Output {
&self * &rhs
}
}
impl <T: Numeric> Mul<&Matrix<T>> for Matrix<T>
where for<'a> &'a T: NumericRef<T> {
type Output = Matrix<T>;
#[track_caller]
#[inline]
fn mul(self, rhs: &Self) -> Self::Output {
&self * rhs
}
}
impl <T: Numeric> Mul<Matrix<T>> for &Matrix<T>
where for<'a> &'a T: NumericRef<T> {
type Output = Matrix<T>;
#[track_caller]
#[inline]
fn mul(self, rhs: Matrix<T>) -> Self::Output {
self * &rhs
}
}
impl <T: Numeric> Add for &Matrix<T>
where for<'a> &'a T: NumericRef<T> {
type Output = Matrix<T>;
#[track_caller]
#[inline]
fn add(self, rhs: Self) -> Self::Output {
assert!(self.size() == rhs.size(),
"Mismatched Matrices, left is {}x{}, right is {}x{}, + is only defined for MxN + MxN",
self.rows(), self.columns(), rhs.rows(), rhs.columns());
let values = self.data
.iter()
.zip(rhs.data.iter())
.map(|(x, y)| x + y)
.collect();
Matrix::from_flat_row_major(self.size(), values)
}
}
impl <T: Numeric> Add for Matrix<T>
where for<'a> &'a T: NumericRef<T> {
type Output = Matrix<T>;
#[track_caller]
#[inline]
fn add(self, rhs: Self) -> Self::Output {
&self + &rhs
}
}
impl <T: Numeric> Add<&Matrix<T>> for Matrix<T>
where for<'a> &'a T: NumericRef<T> {
type Output = Matrix<T>;
#[track_caller]
#[inline]
fn add(self, rhs: &Self) -> Self::Output {
&self + rhs
}
}
impl <T: Numeric> Add<Matrix<T>> for &Matrix<T>
where for<'a> &'a T: NumericRef<T> {
type Output = Matrix<T>;
#[track_caller]
#[inline]
fn add(self, rhs: Matrix<T>) -> Self::Output {
self + &rhs
}
}
impl <T: Numeric> Sub for &Matrix<T>
where for<'a> &'a T: NumericRef<T> {
type Output = Matrix<T>;
#[track_caller]
#[inline]
fn sub(self, rhs: Self) -> Self::Output {
assert!(self.size() == rhs.size(),
"Mismatched Matrices, left is {}x{}, right is {}x{}, - is only defined for MxN - MxN",
self.rows(), self.columns(), rhs.rows(), rhs.columns());
let values = self.data
.iter()
.zip(rhs.data.iter())
.map(|(x, y)| x - y)
.collect();
Matrix::from_flat_row_major(self.size(), values)
}
}
impl <T: Numeric> Sub for Matrix<T>
where for<'a> &'a T: NumericRef<T> {
type Output = Matrix<T>;
#[track_caller]
#[inline]
fn sub(self, rhs: Self) -> Self::Output {
&self - &rhs
}
}
impl <T: Numeric> Sub<&Matrix<T>> for Matrix<T>
where for<'a> &'a T: NumericRef<T> {
type Output = Matrix<T>;
#[track_caller]
#[inline]
fn sub(self, rhs: &Self) -> Self::Output {
&self - rhs
}
}
impl <T: Numeric> Sub<Matrix<T>> for &Matrix<T>
where for<'a> &'a T: NumericRef<T> {
type Output = Matrix<T>;
#[track_caller]
#[inline]
fn sub(self, rhs: Matrix<T>) -> Self::Output {
self - &rhs
}
}
impl <T: Numeric> Neg for &Matrix<T>
where for<'a> &'a T: NumericRef<T> {
type Output = Matrix<T>;
#[inline]
fn neg(self) -> Self::Output {
self.map(|v| -v)
}
}
impl <T: Numeric> Neg for Matrix<T>
where for<'a> &'a T: NumericRef<T> {
type Output = Matrix<T>;
#[inline]
fn neg(self) -> Self::Output {
- &self
}
}
macro_rules! matrix_scalar_reference_reference {
(impl $op:tt for Matrix { fn $method:ident }) => {
impl <T: Numeric> $op<&T> for &Matrix<T>
where for<'a> &'a T: NumericRef<T> {
type Output = Matrix<T>;
#[inline]
fn $method(self, rhs: &T) -> Self::Output {
self.map(|x| (x).$method(rhs.clone()))
}
}
}
}
macro_rules! matrix_scalar_value_value {
(impl $op:tt for Matrix { fn $method:ident }) => {
impl <T: Numeric> $op<T> for Matrix<T>
where for<'a> &'a T: NumericRef<T> {
type Output = Matrix<T>;
#[inline]
fn $method(self, rhs: T) -> Self::Output {
self.map(|x| (x).$method(rhs.clone()))
}
}
}
}
macro_rules! matrix_scalar_value_reference {
(impl $op:tt for Matrix { fn $method:ident }) => {
impl <T: Numeric> $op<&T> for Matrix<T>
where for<'a> &'a T: NumericRef<T> {
type Output = Matrix<T>;
#[inline]
fn $method(self, rhs: &T) -> Self::Output {
self.map(|x| (x).$method(rhs.clone()))
}
}
}
}
macro_rules! matrix_scalar_reference_value {
(impl $op:tt for Matrix { fn $method:ident }) => {
impl <T: Numeric> $op<T> for &Matrix<T>
where for<'a> &'a T: NumericRef<T> {
type Output = Matrix<T>;
#[inline]
fn $method(self, rhs: T) -> Self::Output {
self.map(|x| (x).$method(rhs.clone()))
}
}
}
}
matrix_scalar_reference_reference!(impl Add for Matrix { fn add });
matrix_scalar_value_reference!(impl Add for Matrix { fn add });
matrix_scalar_reference_value!(impl Add for Matrix { fn add });
matrix_scalar_value_value!(impl Add for Matrix { fn add });
matrix_scalar_reference_reference!(impl Sub for Matrix { fn sub });
matrix_scalar_value_reference!(impl Sub for Matrix { fn sub });
matrix_scalar_reference_value!(impl Sub for Matrix { fn sub });
matrix_scalar_value_value!(impl Sub for Matrix { fn sub });
matrix_scalar_reference_reference!(impl Mul for Matrix { fn mul });
matrix_scalar_value_reference!(impl Mul for Matrix { fn mul });
matrix_scalar_reference_value!(impl Mul for Matrix { fn mul });
matrix_scalar_value_value!(impl Mul for Matrix { fn mul });
matrix_scalar_reference_reference!(impl Div for Matrix { fn div });
matrix_scalar_value_reference!(impl Div for Matrix { fn div });
matrix_scalar_reference_value!(impl Div for Matrix { fn div });
matrix_scalar_value_value!(impl Div for Matrix { fn div });
#[test]
fn test_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<Matrix<f64>>();
}
#[test]
fn test_send() {
fn assert_send<T: Send>() {}
assert_send::<Matrix<f64>>();
}
#[cfg(feature = "serde")]
#[test]
fn test_serialize() {
fn assert_serialize<T: Serialize>() {}
assert_serialize::<Matrix<f64>>();
}
#[cfg(feature = "serde")]
#[test]
fn test_deserialize() {
fn assert_deserialize<'de, T: Deserialize<'de>>() {}
assert_deserialize::<Matrix<f64>>();
}
#[test]
fn test_indexing() {
let a = Matrix::from(vec![vec![1, 2], vec![3, 4]]);
assert_eq!(a.get_index(0, 1), 1);
assert_eq!(a.get_row_column(1), (0, 1));
assert_eq!(a.get(0, 1), 2);
let b = Matrix::from(vec![vec![1, 2, 3], vec![5, 6, 7]]);
assert_eq!(b.get_index(1, 2), 5);
assert_eq!(b.get_row_column(5), (1, 2));
assert_eq!(b.get(1, 2), 7);
assert_eq!(
Matrix::from(vec![
vec![0, 0],
vec![0, 0],
vec![0, 0]
])
.map_with_index(|_, r, c| format!("{:?}x{:?}", r, c)),
Matrix::from(vec![
vec!["0x0", "0x1"],
vec!["1x0", "1x1"],
vec!["2x0", "2x1"]
])
.map(|x| x.to_owned())
);
}