Files
rmath/src/hmatrix.rs
2024-01-27 20:53:15 +08:00

1058 lines
27 KiB
Rust

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<TYPE> {
rows: usize,
columns: usize,
values: Vec<TYPE>,
}
impl<TYPE> Index<(usize, usize)> for HMatrix<TYPE> {
fn index(&self, index: (usize, usize)) -> &TYPE {
&self.values[self.columns * index.0 + index.1]
}
type Output = TYPE;
}
impl<TYPE> IndexMut<(usize, usize)> for HMatrix<TYPE> {
fn index_mut(&mut self, index: (usize, usize)) -> &mut TYPE {
&mut self.values[self.columns * index.0 + index.1]
}
}
impl<TYPE> Default for HMatrix<TYPE> {
fn default() -> Self {
HMatrix {
rows: 0,
columns: 0,
values: vec![],
}
}
}
impl<TYPE> Display for HMatrix<TYPE>
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<TYPE> Clone for HMatrix<TYPE>
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<TYPE>
where
TYPE: 'a,
{
type IteratorType = HMatrixIterator<TYPE>;
type RefIteratorType<'b> = HMatrixIteratorRef<'a, TYPE>;
type MutRefIteratorType<'b> = HMatrixIteratorMut<'a, TYPE>;
}
impl<'a, TYPE> Matrix<TYPE> for HMatrix<TYPE>
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<Self, crate::SizeError> {
let columns = self.columns();
let rows = self.rows();
let mut tmp = Vec::<TYPE>::new();
for (_, _, value) in self {
tmp.push(value);
}
let mut it = tmp.into_iter().rev();
Ok(Self::new(columns, rows, |_| it.next().unwrap()))
}
}
impl<TYPE> Add for HMatrix<TYPE>
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<TYPE> Add for &HMatrix<TYPE>
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<TYPE>;
}
impl<TYPE> Sub for HMatrix<TYPE>
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<TYPE> Sub for &HMatrix<TYPE>
where
TYPE: Sub<Output = TYPE> + 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<TYPE>;
}
#[opimps::impl_ops(Mul)]
fn mul<TYPE>(self: HMatrix<TYPE>, other: HMatrix<TYPE>) -> HMatrix<TYPE>
where
TYPE: Zero + AddAssign<TYPE>,
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<TYPE> = 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<TYPE> HMatrix<TYPE> {
pub fn new<INITIALIZER>(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<TYPE> HMatrix<TYPE> where TYPE : One + Zero {
// pub fn identity(size : usize) -> HMatrix<TYPE> {
// HMatrix::new(size, size, |(i, j)| if i == j {
// TYPE::one()
// } else {
// TYPE::zero()
// })
// }
// }
pub struct HMatrixIterator<TYPE> {
it: Enumerate<<Vec<TYPE> as IntoIterator>::IntoIter>,
columns: usize,
}
impl<TYPE> Iterator for HMatrixIterator<TYPE> {
fn next(&mut self) -> Option<Self::Item> {
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<TYPE> as IntoIterator>::IntoIter>,
columns: usize,
}
impl<'a, TYPE> Iterator for HMatrixIteratorRef<'a, TYPE> {
fn next(&mut self) -> Option<Self::Item> {
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<TYPE> as IntoIterator>::IntoIter>,
columns: usize,
}
impl<'a, TYPE> Iterator for HMatrixIteratorMut<'a, TYPE> {
fn next(&mut self) -> Option<Self::Item> {
self.it
.next()
.map(|(index, value)| (index / self.columns, index % self.columns, value))
}
type Item = (usize, usize, &'a mut TYPE);
}
impl<TYPE> IntoIterator for HMatrix<TYPE> {
type Item = (usize, usize, TYPE);
type IntoIter = HMatrixIterator<TYPE>;
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> {
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> {
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<TYPE> PartialEq for HMatrix<TYPE>
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<TYPE> Debug for HMatrix<TYPE>
where
TYPE: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
debug_fmt(self, f)
}
}
impl<TYPE> Zero for HMatrix<TYPE>
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<TYPE> One for HMatrix<TYPE>
where
TYPE: One + Zero + PartialEq + AddAssign<TYPE>,
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<TYPE>> for HMatrix<TYPE>
where
for<'b> TYPE: Zero
+ One
+ Clone
+ PartialEq
+ PartialOrd
+ SubAssign<TYPE>
+ SubAssign<&'b TYPE>
+ Div<TYPE, Output = TYPE>
+ MulAssign<&'b TYPE>
+ DivAssign<TYPE>
+ DivAssign<&'b TYPE>
+ Neg<Output = TYPE>
+ 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<Output = TYPE>,
TYPE: 'a,
Self: Sized
+ Index<(usize, usize), Output = TYPE>
+ IndexMut<(usize, usize), Output = TYPE>
+ IntoIterator<Item = (usize, usize, TYPE), IntoIter = Self::IteratorType>
+ 'a,
&'a Self: IntoIterator<Item = (usize, usize, &'a TYPE), IntoIter = Self::RefIteratorType<'a>>,
&'a mut Self:
IntoIterator<Item = (usize, usize, &'a mut TYPE), IntoIter = Self::MutRefIteratorType<'a>>,
Self::IteratorType: Iterator<Item = (usize, usize, TYPE)>,
Self::RefIteratorType<'a>: Iterator<Item = (usize, usize, &'a TYPE)>,
Self::MutRefIteratorType<'a>: Iterator<Item = (usize, usize, &'a mut TYPE)>,
{
fn identity(size: usize) -> HMatrix<TYPE> {
HMatrix::new(
size,
size,
|(i, j)| if i == j { TYPE::one() } else { TYPE::zero() },
)
}
}
impl<TYPE> NumericalMatrix<TYPE, HPivot, HLUDecomposition<TYPE>> for HMatrix<TYPE>
where
for<'b> TYPE: Clone
+ 'b
+ Zero
+ One
+ PartialEq
+ PartialOrd
+ Neg<Output = TYPE>
+ Add<&'b TYPE, Output = TYPE>
+ Div<Output = TYPE>
+ SubAssign<TYPE>
+ SubAssign<&'b TYPE>
+ DivAssign<TYPE>
+ DivAssign<&'b TYPE>
+ MulAssign<&'b TYPE>,
for<'c> &'c TYPE:
Mul<Output = TYPE> + Add<Output = TYPE> + Div<Output = TYPE> + Neg<Output = TYPE>,
{
fn identity(size: usize) -> Self {
NumericalMatrixImpl::<TYPE, HPivot, HLUDecomposition<TYPE>>::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::<TYPE, HPivot, HLUDecomposition<TYPE>>::gauss_jordan_high(
&mut self, &mut pivot,
);
self
}
fn gauss_jordan_low(mut self) -> Self {
let mut pivot = HPivot::new(self.rows());
NumericalMatrixImpl::<TYPE, HPivot, HLUDecomposition<TYPE>>::gauss_jordan_low(
&mut self, &mut pivot,
);
self
}
fn det(self) -> TYPE {
let pivot = HPivot::new(self.rows());
NumericalMatrixImpl::<TYPE, HPivot, HLUDecomposition<TYPE>>::det(self, pivot)
}
fn invert(&mut self) -> Self {
let mut result =
NumericalMatrixImpl::<TYPE, HPivot, HLUDecomposition<TYPE>>::identity(self.rows());
let mut pivot = HPivot::new(self.rows());
NumericalMatrixImpl::<TYPE, HPivot, HLUDecomposition<TYPE>>::invert(
self,
&mut pivot,
&mut result,
);
result
}
fn lup(mut self) -> Result<HLUDecomposition<TYPE>, SingularMatrixError> {
let mut pivot = HPivot::new(self.columns());
NumericalMatrixImpl::<TYPE, HPivot, HLUDecomposition<TYPE>>::lup(&mut self, &mut pivot)?;
Ok(HLUDecomposition::<TYPE>::new(self, Some(pivot)))
}
fn lu(mut self) -> Result<HLUDecomposition<TYPE>, SingularMatrixError> {
NumericalMatrixImpl::<TYPE, HPivot, HLUDecomposition<TYPE>>::lu(&mut self)?;
Ok(HLUDecomposition::<TYPE>::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::<i32>::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::<i32>::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::<i32>::new(3, 5, |_| {
let res = idx;
idx += 1;
res
});
let m2 = HMatrix::<i32>::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::<i32>::new(3, 5, |_| {
let res = idx;
idx += 1;
res
});
let m2 = HMatrix::<i32>::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::<i32>::new(3, 5, |_| {
let res = idx;
idx += 1;
res
});
idx = 0;
let m2 = HMatrix::<i32>::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::<i32>::new(3, 2, |_| {
let res = values[idx];
idx += 1;
res
})
};
assert!(expected == m3);
}
#[test]
fn test_one() {
let mut idx = 0;
let m1 = HMatrix::<i32>::new(5, 5, |_| {
let res = idx;
idx += 1;
res
});
let m2 = HMatrix::<i32>::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::<Rational<i64>>::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::<Rational<i64>>::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::<i64>::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::<i64>::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::<Rational<i64>>::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::<Rational<i64>>::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::<Rational<i32>>::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::<BigInt>::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::<BigInt>::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::<BigInt>::new(3, 5, |_| {
let res = BigInt::from(idx);
idx += 1;
res
});
let m2 = HMatrix::<BigInt>::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::<BigInt>::new(3, 5, |_| {
let res = BigInt::from(idx);
idx += 1;
res
});
let m2 = HMatrix::<BigInt>::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::<BigInt>::new(3, 5, |_| {
let res = BigInt::from(idx);
idx += 1;
res
});
idx = 0;
let m2 = HMatrix::<BigInt>::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::<BigInt>::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::<BigInt>::new(5, 5, |_| {
let res = BigInt::from(idx);
idx += 1;
res
});
let m2 = HMatrix::<BigInt>::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::<Rational<BigInt>>::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::<Rational<BigInt>>::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::<BigInt>::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::<BigInt>::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::<Rational<i64>>::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::<Rational<i64>>::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::<Rational<BigInt>>::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());
}
}