-
Notifications
You must be signed in to change notification settings - Fork 58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added LU decomposition with complete pivoting #160
Changes from 1 commit
59c268f
4244708
9376d7d
daaf922
f0be956
7d0c67b
2ffb026
572d45f
aeeb09c
ad9cdc4
e340619
337405e
5b54687
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -477,8 +477,12 @@ impl<T> FullPivLu<T> where T: Any + Float { | |
let mut inv = Matrix::zeros(n, n); | ||
let mut e = Vector::zeros(n); | ||
|
||
// "solve" will return an error if the matrix is | ||
// singular, so no need to check for singularity here | ||
if self.is_singular() { | ||
return Err( | ||
Error::new( | ||
ErrorKind::DivByZero, | ||
"Singular matrix found while attempting inversion.")); | ||
} | ||
|
||
for i in 0 .. n { | ||
e[i] = T::one(); | ||
|
@@ -514,10 +518,63 @@ impl<T> FullPivLu<T> where T: Any + Float { | |
} | ||
|
||
/// Computes the rank of the decomposed matrix. | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// # #[macro_use] extern crate rulinalg; | ||
/// # use rulinalg::matrix::decomposition::FullPivLu; | ||
/// # use rulinalg::matrix::Matrix; | ||
/// # fn main() { | ||
/// let x = matrix![1.0, 2.0, 3.0; | ||
/// 4.0, 5.0, 6.0; | ||
/// 5.0, 7.0, 9.0]; | ||
/// let lu = FullPivLu::decompose(x).unwrap(); | ||
/// assert_eq!(lu.rank(), 2); | ||
/// # } | ||
/// ``` | ||
pub fn rank(&self) -> usize { | ||
self.lu.diag().fold( | ||
0 as usize, | ||
|x, &y| if y.abs() > T::epsilon() { x + 1 } else { x } ) | ||
let eps = self.epsilon(); | ||
let mut rank = 0; | ||
|
||
for d in self.lu.diag() { | ||
if d.abs() > eps { | ||
rank = rank + 1; | ||
} else { | ||
break; | ||
} | ||
} | ||
|
||
rank | ||
} | ||
|
||
/// Returns whether the matrix is singular. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// # #[macro_use] extern crate rulinalg; | ||
/// # use rulinalg::matrix::decomposition::FullPivLu; | ||
/// # use rulinalg::matrix::Matrix; | ||
/// # fn main() { | ||
/// let x = Matrix::<f64>::identity(4); | ||
/// let lu = FullPivLu::decompose(x).unwrap(); | ||
/// assert!(!lu.is_singular()); | ||
/// | ||
/// let y = matrix![1.0, 2.0, 3.0; | ||
/// 4.0, 5.0, 6.0; | ||
/// 5.0, 7.0, 9.0]; | ||
/// let lu = FullPivLu::decompose(y).unwrap(); | ||
/// assert!(lu.is_singular()); | ||
/// # } | ||
/// ``` | ||
pub fn is_singular(&self) -> bool { | ||
let diag_size = cmp::min(self.lu.rows(), self.lu.cols()); | ||
|
||
self.rank() != diag_size | ||
} | ||
|
||
fn epsilon(&self) -> T { | ||
self.lu[[0, 0]].abs() * T::epsilon() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We actually need to take into account the corner case of empty matrices here (in which case accessing [0, 0] will panic). The easiest is probably to use i.e. let max_element = self.lu.diag().next().unwrap_or(T::one());
max_element.abs() * T::epsilon() There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, the simplest is probably to use |
||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think perhaps the name
is_singular
is a little unfortunate if we wish to move forward with our plans of extending LU to rectangular matrices. In general, one only talks about singular matrices if they are also square. Hence, it would be a little strange to refer to a rectangular matrix as 'singular'. More precisely, is a rectangular matrix of full row/col rank singular, or non-singular? But if it's non-singular it's still not invertible!The benefit of flipping it around and instead using
is_invertible
is that a matrix is invertible if and only if it is square and has no zeros on the diagonal of U. Thus it extends also nicely to rectangular matrices since they can never be invertible (and will always returnfalse
).Did this make any sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, a relatively minor thing, but it is sufficient to check the last diagonal of
U
: