use num_traits::One; use num_traits::Zero; use std::fmt::Debug; use std::fmt::Display; use std::iter::Enumerate; use std::ops::Add; use std::ops::AddAssign; use std::ops::Div; use std::ops::DivAssign; use std::ops::FnMut; use std::ops::Index; use std::ops::IndexMut; use std::ops::Mul; use std::ops::MulAssign; use std::ops::Neg; use std::ops::Sub; use std::ops::SubAssign; use super::matrix::MatrixImpl; use super::matrix::NumericalMatrixImpl; use super::misc::debug_fmt; use super::NumericalMatrix; use crate::SingularMatrixError; use super::hludecomposition::HLUDecomposition; use super::Matrix; use super::Pivot; use super::hpivot::HPivot; pub struct HMatrix { rows: usize, columns: usize, values: Vec, } impl Index<(usize, usize)> for HMatrix { fn index(&self, index: (usize, usize)) -> &TYPE { &self.values[self.columns * index.0 + index.1] } type Output = TYPE; } impl IndexMut<(usize, usize)> for HMatrix { fn index_mut(&mut self, index: (usize, usize)) -> &mut TYPE { &mut self.values[self.columns * index.0 + index.1] } } impl Default for HMatrix { fn default() -> Self { HMatrix { rows: 0, columns: 0, values: vec![], } } } impl Display for HMatrix where TYPE: Display, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let lim = self.rows() * self.columns() - 1; writeln!(f, "[")?; for i in 0..self.rows() { write!(f, " ")?; for j in 0..self.columns() { let index = i * self.columns() + j; write!(f, "{}", self[(i, j)])?; if index < lim { write!(f, ", ")?; } } writeln!(f)?; } write!(f, "]") } } impl Clone for HMatrix where TYPE: Clone, { fn clone(&self) -> Self { HMatrix::new(self.rows(), self.columns(), |position| { self[position].clone() }) } } impl<'a, TYPE> MatrixImpl<'a, TYPE> for HMatrix where TYPE: 'a, { type IteratorType = HMatrixIterator; type RefIteratorType<'b> = HMatrixIteratorRef<'a, TYPE>; type MutRefIteratorType<'b> = HMatrixIteratorMut<'a, TYPE>; } impl<'a, TYPE> Matrix for HMatrix where TYPE: 'a, { fn columns(&self) -> usize { self.columns } fn rows(&self) -> usize { self.rows } fn size(&self) -> (usize, usize) { (self.rows(), self.columns()) } fn transpose(self) -> Result { let columns = self.columns(); let rows = self.rows(); let mut tmp = Vec::::new(); for (_, _, value) in self { tmp.push(value); } let mut it = tmp.into_iter().rev(); Ok(Self::new(columns, rows, |_| it.next().unwrap())) } } impl Add for HMatrix where for<'a> TYPE: AddAssign<&'a TYPE>, { fn add(self, rhs: Self) -> Self::Output { if self.size() != rhs.size() { panic!( "Trying to add matrix with size {:?} to matrix with size {:?}, {}", self.size(), rhs.size(), "matrixes need to have the same size in order to perform addition" ); } let mut result = HMatrix { rows: self.rows(), columns: self.columns(), values: self.values, }; for (i, j, v) in &mut result { *v += &rhs[(i, j)] } result } type Output = Self; } impl Add for &HMatrix where for<'a> &'a TYPE: Add<&'a TYPE, Output = TYPE>, { fn add(self, rhs: Self) -> Self::Output { if self.size() != rhs.size() { panic!( "Trying to add matrix with size {:?} to matrix with size {:?}, {}", self.size(), rhs.size(), "matrixes need to have the same size in order to perform addition" ); } HMatrix::new(self.rows(), self.columns(), |position| { &self[position] + &rhs[position] }) } type Output = HMatrix; } impl Sub for HMatrix where for<'a> TYPE: SubAssign<&'a TYPE>, { fn sub(self, rhs: Self) -> Self::Output { if self.size() != rhs.size() { panic!( "Trying to subtract matrix with size {:?} to matrix with size {:?}, {}", self.size(), rhs.size(), "matrixes need to have the same size in order to perform subtraction" ); } let mut result = HMatrix { rows: self.rows(), columns: self.columns(), values: self.values, }; for (i, j, v) in &mut result { *v -= &rhs[(i, j)] } result } type Output = Self; } impl Sub for &HMatrix where TYPE: Sub + Clone, for<'a> &'a TYPE: Sub<&'a TYPE, Output = TYPE>, { fn sub(self, rhs: Self) -> Self::Output { if self.size() != rhs.size() { panic!( "Trying to subtract matrix with size {:?} to matrix with size {:?}, {}", self.size(), rhs.size(), "matrixes need to have the same size in order to perform subtraction" ); } HMatrix::new(self.rows(), self.columns(), |position| { &self[position] - &rhs[position] }) } type Output = HMatrix; } #[opimps::impl_ops(Mul)] fn mul(self: HMatrix, other: HMatrix) -> HMatrix where TYPE: Zero + AddAssign, for<'a> &'a TYPE: Mul<&'a TYPE, Output = TYPE>, { if self.columns() != other.rows() { panic!( "Trying to multiply matrix with size {:?} to matrix with size {:?}, {} {}", self.size(), other.size(), "the number of columns of the first matrix need be equal to the number of rows", "of the second matrix in order to perform matrix multiplication" ); } let mut result: HMatrix = HMatrix::new(self.rows(), other.columns(), |_| TYPE::zero()); for i in 0..result.rows() { for j in 0..result.columns() { for k in 0..self.columns() { result[(i, j)] += &self[(i, k)] * &other[(k, j)] } } } result } impl HMatrix { pub fn new(rows: usize, columns: usize, mut cb: INITIALIZER) -> Self where INITIALIZER: FnMut((usize, usize)) -> TYPE, { let mut values = Vec::with_capacity(rows * columns); for i in 0..rows { for j in 0..columns { values.push(cb((i, j))); } } HMatrix { rows, columns, values, } } } // impl HMatrix where TYPE : One + Zero { // pub fn identity(size : usize) -> HMatrix { // HMatrix::new(size, size, |(i, j)| if i == j { // TYPE::one() // } else { // TYPE::zero() // }) // } // } pub struct HMatrixIterator { it: Enumerate< as IntoIterator>::IntoIter>, columns: usize, } impl Iterator for HMatrixIterator { fn next(&mut self) -> Option { self.it .next() .map(|(index, value)| (index / self.columns, index % self.columns, value)) } type Item = (usize, usize, TYPE); } pub struct HMatrixIteratorRef<'a, TYPE> { it: Enumerate<<&'a Vec as IntoIterator>::IntoIter>, columns: usize, } impl<'a, TYPE> Iterator for HMatrixIteratorRef<'a, TYPE> { fn next(&mut self) -> Option { self.it .next() .map(|(index, value)| (index / self.columns, index % self.columns, value)) } type Item = (usize, usize, &'a TYPE); } pub struct HMatrixIteratorMut<'a, TYPE> { it: Enumerate<<&'a mut Vec as IntoIterator>::IntoIter>, columns: usize, } impl<'a, TYPE> Iterator for HMatrixIteratorMut<'a, TYPE> { fn next(&mut self) -> Option { self.it .next() .map(|(index, value)| (index / self.columns, index % self.columns, value)) } type Item = (usize, usize, &'a mut TYPE); } impl IntoIterator for HMatrix { type Item = (usize, usize, TYPE); type IntoIter = HMatrixIterator; fn into_iter(self) -> Self::IntoIter { let columns = self.columns(); HMatrixIterator { it: self.values.into_iter().enumerate(), columns, } } } impl<'a, TYPE> IntoIterator for &'a HMatrix { type Item = (usize, usize, &'a TYPE); type IntoIter = HMatrixIteratorRef<'a, TYPE>; fn into_iter(self) -> Self::IntoIter { HMatrixIteratorRef { it: self.values.iter().enumerate(), columns: self.columns(), } } } impl<'a, TYPE> IntoIterator for &'a mut HMatrix { type Item = (usize, usize, &'a mut TYPE); type IntoIter = HMatrixIteratorMut<'a, TYPE>; fn into_iter(self) -> Self::IntoIter { let columns = self.columns(); HMatrixIteratorMut { it: self.values.iter_mut().enumerate(), columns, } } } impl PartialEq for HMatrix where TYPE: PartialEq, { fn eq(&self, other: &Self) -> bool { self.rows() == other.rows() && self.columns() == other.columns() && (0..self.rows()) .flat_map(|i| (0..self.columns()).map(move |j| (i, j))) .all(|index| self[index] == other[index]) } } impl Debug for HMatrix where TYPE: Debug, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { debug_fmt(self, f) } } impl Zero for HMatrix where TYPE: Zero, for<'a> TYPE: AddAssign<&'a TYPE>, { fn zero() -> Self { HMatrix::new(1, 1, |_| TYPE::zero()) } fn is_zero(&self) -> bool { self.into_iter().all(|(_, _, value)| value.is_zero()) } fn set_zero(&mut self) { for (_, _, value) in self { *value = TYPE::zero(); } } } impl One for HMatrix where TYPE: One + Zero + PartialEq + AddAssign, for<'a> &'a TYPE: Mul<&'a TYPE, Output = TYPE>, { fn one() -> Self { HMatrix::new(1, 1, |_| TYPE::one()) } fn is_one(&self) -> bool { self.into_iter().all(|(i, j, value)| { if i == j { value.is_one() } else { value.is_zero() } }) } fn set_one(&mut self) { for (i, j, value) in self { if i == j { *value = TYPE::one(); } else { *value = TYPE::zero(); } } } } impl<'a, TYPE> NumericalMatrixImpl<'a, TYPE, HPivot, HLUDecomposition> for HMatrix where for<'b> TYPE: Zero + One + Clone + PartialEq + PartialOrd + SubAssign + SubAssign<&'b TYPE> + Div + MulAssign<&'b TYPE> + DivAssign + DivAssign<&'b TYPE> + Neg + Add<&'b TYPE, Output = TYPE> + 'b, for<'c> &'c TYPE: Mul<&'c TYPE, Output = TYPE> + Add<&'c TYPE, Output = TYPE> + Div<&'c TYPE, Output = TYPE> + Neg, TYPE: 'a, Self: Sized + Index<(usize, usize), Output = TYPE> + IndexMut<(usize, usize), Output = TYPE> + IntoIterator + 'a, &'a Self: IntoIterator>, &'a mut Self: IntoIterator>, Self::IteratorType: Iterator, Self::RefIteratorType<'a>: Iterator, Self::MutRefIteratorType<'a>: Iterator, { fn identity(size: usize) -> HMatrix { HMatrix::new( size, size, |(i, j)| if i == j { TYPE::one() } else { TYPE::zero() }, ) } } impl NumericalMatrix> for HMatrix where for<'b> TYPE: Clone + 'b + Zero + One + PartialEq + PartialOrd + Neg + Add<&'b TYPE, Output = TYPE> + Div + SubAssign + SubAssign<&'b TYPE> + DivAssign + DivAssign<&'b TYPE> + MulAssign<&'b TYPE>, for<'c> &'c TYPE: Mul + Add + Div + Neg, { fn identity(size: usize) -> Self { NumericalMatrixImpl::>::identity(size) } fn tril(mut self) -> Self { self.tril_impl(None); self } fn triu(mut self) -> Self { self.triu_impl(None); self } fn tril_replace(mut self, diag_replacement: TYPE) -> Self { self.tril_impl(Some(diag_replacement)); self } fn triu_replace(mut self, diag_replacement: TYPE) -> Self { self.triu_impl(Some(diag_replacement)); self } fn gauss_jordan_high(mut self) -> Self { let mut pivot = HPivot::new(self.rows()); NumericalMatrixImpl::>::gauss_jordan_high( &mut self, &mut pivot, ); self } fn gauss_jordan_low(mut self) -> Self { let mut pivot = HPivot::new(self.rows()); NumericalMatrixImpl::>::gauss_jordan_low( &mut self, &mut pivot, ); self } fn det(self) -> TYPE { let pivot = HPivot::new(self.rows()); NumericalMatrixImpl::>::det(self, pivot) } fn invert(&mut self) -> Self { let mut result = NumericalMatrixImpl::>::identity(self.rows()); let mut pivot = HPivot::new(self.rows()); NumericalMatrixImpl::>::invert( self, &mut pivot, &mut result, ); result } fn lup(mut self) -> Result, SingularMatrixError> { let mut pivot = HPivot::new(self.columns()); NumericalMatrixImpl::>::lup(&mut self, &mut pivot)?; Ok(HLUDecomposition::::new(self, Some(pivot))) } fn lu(mut self) -> Result, SingularMatrixError> { NumericalMatrixImpl::>::lu(&mut self)?; Ok(HLUDecomposition::::new(self, None)) } } #[cfg(test)] mod tests { use crate::HMatrix; use crate::LUDecomposition; use crate::Matrix; use crate::NumericalMatrix; use crate::Rational; use num_traits::One; use num_traits::Zero; #[test] fn test_new() { let mut idx = 0; let m1 = HMatrix::::new(3, 5, |_| { let res = idx; idx += 1; res }); idx = 0; for (_, _, value) in m1 { assert_eq!(idx, value); idx += 1; } } #[test] fn test_eq() { let mut idx = 0; let m1 = HMatrix::::new(3, 5, |_| { let res = idx; idx += 1; res }); idx = 0; for (_, _, value) in &m1 { assert_eq!(idx, *value); idx += 1; } let m2 = m1.clone(); assert!(m1 == m2); } #[test] fn test_sum() { let mut idx = 0; let m1 = HMatrix::::new(3, 5, |_| { let res = idx; idx += 1; res }); let m2 = HMatrix::::new(3, 5, |_| { let res = idx; idx += 1; res }); let m3 = &m1 + &m2; for i in 0..m1.rows() { for j in 0..m1.columns() { assert_eq!(m3[(i, j)], m1[(i, j)] + m2[(i, j)]); } } } #[test] fn test_sub() { let mut idx = 0; let m1 = HMatrix::::new(3, 5, |_| { let res = idx; idx += 1; res }); let m2 = HMatrix::::new(3, 5, |_| { let res = idx; idx += 1; res }); let m3 = &m1 - &m2; for i in 0..m1.rows() { for j in 0..m1.columns() { assert_eq!(m3[(i, j)], m1[(i, j)] - m2[(i, j)]); } } } #[test] fn test_mul() { let mut idx = 0; let m1 = HMatrix::::new(3, 5, |_| { let res = idx; idx += 1; res }); idx = 0; let m2 = HMatrix::::new(5, 2, |_| { let res = idx; idx += 1; res }); let m3 = &m1 * &m2; let expected = { let mut idx = 0; let values = [60, 70, 160, 195, 260, 320]; HMatrix::::new(3, 2, |_| { let res = values[idx]; idx += 1; res }) }; assert!(expected == m3); } #[test] fn test_one() { let mut idx = 0; let m1 = HMatrix::::new(5, 5, |_| { let res = idx; idx += 1; res }); let m2 = HMatrix::::identity(5); let m3 = &m1 * &m2; assert!(m1 == m3); } #[test] fn test_inv() { let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9]; let mut idx = 0; let m1 = HMatrix::>::new(3, 3, |_| { let res = Rational::new(arr[idx], i64::one()); idx += 1; res }); let m2 = NumericalMatrix::invert(&mut m1.clone()); let m3 = &m1 * &m2; assert!(m3.is_one()); } #[test] fn test_det() { let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9]; let mut idx = 0; let m1 = HMatrix::>::new(3, 3, |_| { let res = Rational::new(arr[idx], 1); idx += 1; res }); assert_eq!(Rational::new(-9, 1), NumericalMatrix::det(m1)); } #[test] fn test_tril() { let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9]; let mut idx = 0; let m1 = HMatrix::::new(3, 3, |_| { let res = arr[idx]; idx += 1; res }); let diag_value = 42; let lt = m1.tril_replace(diag_value); for (i, j, value) in lt { if i == j { assert_eq!(value, diag_value); } else if i < j { assert_eq!(value, i64::zero()) } else { assert_eq!(value, i64::from(arr[i * 3 + j])) } } } #[test] fn test_triu() { let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9]; let mut idx = 0; let m1 = HMatrix::::new(3, 3, |_| { let res = arr[idx]; idx += 1; res }); let diag_value = 42; let lt = m1.triu_replace(diag_value); for (i, j, value) in lt { if i == j { assert_eq!(value, diag_value); } else if i > j { assert_eq!(value, i64::zero()) } else { assert_eq!(value, i64::from(arr[i * 3 + j])) } } } #[test] fn test_lu_decomposition() { let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9]; let mut idx = 0; let orig = HMatrix::>::new(3, 3, |_| { let res = Rational::new(arr[idx], i64::one()); idx += 1; res }); let m1 = orig.clone(); let lu = m1.lup().unwrap(); let l = lu.l(); let u = lu.u(); let m2 = lu.pivot(l * u); assert_eq!(orig, m2); } #[test] fn test_lu_invert() { let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9]; let mut idx = 0; let orig = HMatrix::>::new(3, 3, |_| { let res = Rational::new(arr[idx], i64::one()); idx += 1; res }); let m1 = orig.clone(); let lu = m1.lup().unwrap(); let m2 = lu.invert(); let m3 = orig * m2; assert!(m3.is_one()); } #[test] fn test_lu_det() { let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9]; let mut idx = 0; let m1 = HMatrix::>::new(3, 3, |_| { let res = Rational::new(arr[idx], i32::one()); idx += 1; res }); let lu = m1.clone().lup().unwrap(); assert_eq!(Rational::new(-9, i32::one()), lu.det()); } } #[cfg(test)] mod big_int_tests { use num_bigint::BigInt; use crate::HMatrix; use crate::LUDecomposition; use crate::Matrix; use crate::NumericalMatrix; use crate::Rational; use num_traits::One; use num_traits::Zero; #[test] fn test_new() { let mut idx = 0; let m1 = HMatrix::::new(3, 5, |_| { let res = BigInt::from(idx); idx += 1; res }); idx = 0; for (_, _, value) in m1 { assert_eq!(BigInt::from(idx), value); idx += 1; } } #[test] fn test_eq() { let mut idx = 0; let m1 = HMatrix::::new(3, 5, |_| { let res = BigInt::from(idx); idx += 1; res }); idx = 0; let m2 = m1.clone(); assert!(m1 == m2); for (_, _, value) in &m1 { assert_eq!(BigInt::from(idx), *value); idx += 1; } } #[test] fn test_sum() { let mut idx = 0; let m1 = HMatrix::::new(3, 5, |_| { let res = BigInt::from(idx); idx += 1; res }); let m2 = HMatrix::::new(3, 5, |_| { let res = BigInt::from(idx); idx += 1; res }); let m3 = &m1 + &m2; for i in 0..m1.rows() { for j in 0..m1.columns() { assert_eq!(m3[(i, j)], &m1[(i, j)] + &m2[(i, j)]); } } } #[test] fn test_sub() { let mut idx = 0; let m1 = HMatrix::::new(3, 5, |_| { let res = BigInt::from(idx); idx += 1; res }); let m2 = HMatrix::::new(3, 5, |_| { let res = BigInt::from(idx); idx += 1; res }); let m3 = &m1 - &m2; for i in 0..m1.rows() { for j in 0..m1.columns() { assert_eq!(m3[(i, j)], &m1[(i, j)] - &m2[(i, j)]); } } } #[test] fn test_mul() { let mut idx = 0; let m1 = HMatrix::::new(3, 5, |_| { let res = BigInt::from(idx); idx += 1; res }); idx = 0; let m2 = HMatrix::::new(5, 2, |_| { let res = BigInt::from(idx); idx += 1; res }); let m3 = m1 * m2; let expected = { let mut idx = 0; let values = [60, 70, 160, 195, 260, 320]; HMatrix::::new(3, 2, |_| { let res = BigInt::from(values[idx]); idx += 1; res }) }; assert!(expected == m3); } #[test] fn test_one() { let mut idx = 0; let m1 = HMatrix::::new(5, 5, |_| { let res = BigInt::from(idx); idx += 1; res }); let m2 = HMatrix::::identity(5); let m3 = &m1 * &m2; assert!(m1 == m3); } #[test] fn test_inv() { let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9]; let mut idx = 0; let m1 = HMatrix::>::new(3, 3, |_| { let res = Rational::new(BigInt::from(arr[idx]), BigInt::one()); idx += 1; res }); let m2 = NumericalMatrix::invert(&mut m1.clone()); let m3 = m1 * m2; assert!(m3.is_one()); } #[test] fn test_det() { let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9]; let mut idx = 0; let m1 = HMatrix::>::new(3, 3, |_| { let res = Rational::new(BigInt::from(arr[idx]), BigInt::one()); idx += 1; res }); assert_eq!( Rational::new(BigInt::from(9), -BigInt::one()), NumericalMatrix::det(m1) ); } #[test] fn test_tril() { let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9]; let mut idx = 0; let m1 = HMatrix::::new(3, 3, |_| { let res = BigInt::from(arr[idx]); idx += 1; res }); let diag_value = BigInt::from(42); let lt = m1.tril_replace(diag_value.clone()); for (i, j, value) in lt { if i == j { assert_eq!(value, diag_value); } else if i < j { assert_eq!(value, BigInt::zero()) } else { assert_eq!(value, BigInt::from(arr[i * 3 + j])) } } } #[test] fn test_triu() { let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9]; let mut idx = 0; let m1 = HMatrix::::new(3, 3, |_| { let res = BigInt::from(arr[idx]); idx += 1; res }); let diag_value = BigInt::from(42); let lt = m1.triu_replace(diag_value.clone()); for (i, j, value) in lt { if i == j { assert_eq!(value, diag_value); } else if i > j { assert_eq!(value, BigInt::zero()) } else { assert_eq!(value, BigInt::from(arr[i * 3 + j])) } } } #[test] fn test_lu_decomposition() { let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9]; let mut idx = 0; let orig = HMatrix::>::new(3, 3, |_| { let res = Rational::new(arr[idx], i64::one()); idx += 1; res }); let m1 = orig.clone(); let lu = m1.lup().unwrap(); let tril = lu.l(); let triu = lu.u(); let m2 = lu.pivot(tril * triu); assert_eq!(orig, m2); } #[test] fn test_lu_invert() { let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9]; let mut idx = 0; let orig = HMatrix::>::new(3, 3, |_| { let res = Rational::new(arr[idx], i64::one()); idx += 1; res }); let m1 = orig.clone(); let lu = m1.lup().unwrap(); let m2 = lu.invert(); let m3 = orig * m2; assert!(m3.is_one()); } #[test] fn test_lu_det() { let arr = [1, 2, 3, 4, 5, 6, 8, 7, 9]; let mut idx = 0; let m1 = HMatrix::>::new(3, 3, |_| { let res = Rational::new(BigInt::from(arr[idx]), BigInt::one()); idx += 1; res }); let lu = m1.clone().lup().unwrap(); assert_eq!(Rational::new(BigInt::from(-9), BigInt::one()), lu.det()); } }