Implement reduced row echelon form function
This commit is contained in:
parent
f404bcbd6d
commit
6560411879
|
@ -0,0 +1,34 @@
|
||||||
|
use na::rref;
|
||||||
|
|
||||||
|
use std::cmp;
|
||||||
|
|
||||||
|
use na::{DMatrix, DVector, Matrix4x3, Vector4};
|
||||||
|
use nl::Cholesky;
|
||||||
|
|
||||||
|
use crate::proptest::*;
|
||||||
|
use proptest::{prop_assert, proptest};
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
pub fn rref_test() {
|
||||||
|
let mat: Mat4 = Mat4::Identity();
|
||||||
|
let res = rref(&mat);
|
||||||
|
|
||||||
|
assert_eq!(mat, res);
|
||||||
|
|
||||||
|
let m = Matrix3x4::<f64>::new(
|
||||||
|
1.0, 2.0, -1.0, -4.0,
|
||||||
|
2.0, 3.0, -1.0, -11.0,
|
||||||
|
-2.0, 0.0, -3.0, 22.0,
|
||||||
|
);
|
||||||
|
|
||||||
|
let expected = Matrix3x4::<f64>::new(
|
||||||
|
1.0, 0.0, -1.0, -8.0,
|
||||||
|
0.0, 1.0, 0.0, 1.0,
|
||||||
|
0.0, 0.0, 1.0, -2.0,
|
||||||
|
);
|
||||||
|
|
||||||
|
let res = rref(&mat);
|
||||||
|
prop_assert!(relative_eq!(res, expected, epsilon = 1.0e-5));
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ mod lu;
|
||||||
mod permutation_sequence;
|
mod permutation_sequence;
|
||||||
mod pow;
|
mod pow;
|
||||||
mod qr;
|
mod qr;
|
||||||
|
mod rref;
|
||||||
mod schur;
|
mod schur;
|
||||||
mod solve;
|
mod solve;
|
||||||
mod svd;
|
mod svd;
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
//! Functions for computing the rref of a matrix.
|
||||||
|
|
||||||
|
use core::ops::{Mul, Sub, SubAssign};
|
||||||
|
use simba::scalar::{ClosedMul, RealField};
|
||||||
|
use std::ops::{DivAssign, MulAssign};
|
||||||
|
|
||||||
|
use crate::allocator::Allocator;
|
||||||
|
use crate::base::dimension::Dim;
|
||||||
|
use crate::base::{Const, DefaultAllocator, OMatrix, OVector, Scalar};
|
||||||
|
|
||||||
|
// Implementation of:
|
||||||
|
// https://rosettacode.org/wiki/Reduced_row_echelon_form
|
||||||
|
/// Compute the reduced row echelon form of a matrix.
|
||||||
|
pub fn rref<T: RealField, D: Dim>(matrix: &OMatrix<T, D, D>) -> OMatrix<T, D, D>
|
||||||
|
where
|
||||||
|
DefaultAllocator: Allocator<T, D, D> + Allocator<T, D>,
|
||||||
|
DefaultAllocator: Allocator<T, crate::base::dimension::Const<1>, D> + Allocator<T, D>,
|
||||||
|
T: Scalar + ClosedMul,
|
||||||
|
{
|
||||||
|
let mut matrix = matrix.clone();
|
||||||
|
let mut lead = 0;
|
||||||
|
let row_count = matrix.nrows();
|
||||||
|
let column_count = matrix.ncols();
|
||||||
|
|
||||||
|
for r in 0..row_count {
|
||||||
|
if column_count <= lead {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut i = r;
|
||||||
|
|
||||||
|
// Should this have an epsilon comparison instead?
|
||||||
|
while matrix[(i, lead)] == crate::convert(0.0) {
|
||||||
|
i += 1;
|
||||||
|
if row_count == i {
|
||||||
|
i = r;
|
||||||
|
lead += 1;
|
||||||
|
if column_count == lead {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
matrix.swap_rows(i, r);
|
||||||
|
|
||||||
|
if matrix[(r, lead)] > T::default_epsilon() {
|
||||||
|
let t = matrix[(r, lead)].clone();
|
||||||
|
matrix.row_mut(r).div_assign(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..row_count {
|
||||||
|
if i != r {
|
||||||
|
let lv = -matrix[(i, lead)].clone();
|
||||||
|
let r_row = matrix.row(r).clone() * lv;
|
||||||
|
|
||||||
|
matrix.row_mut(i).sub_assign(r_row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lead += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
matrix
|
||||||
|
}
|
Loading…
Reference in New Issue