1058 lines
27 KiB
Rust
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());
|
|
}
|
|
}
|