blob: a0b3b07de4a3328e53d9f38bf562d88bc5cca6ba [file] [log] [blame]
use matrix::{Matrix, BaseMatrix, BaseMatrixMut, MatrixSlice, MatrixSliceMut};
use error::{Error, ErrorKind};
use std::any::Any;
use std::vec::*;
use libnum::{Float};
impl<T: Any + Float> Matrix<T> {
/// Returns H, where H is the upper hessenberg form.
///
/// If the transformation matrix is also required, you should
/// use `upper_hess_decomp`.
///
/// # Examples
///
/// ```
/// # #[macro_use] extern crate rulinalg; fn main() {
/// use rulinalg::matrix::Matrix;
///
/// let a = matrix![2., 0., 1., 1.;
/// 2., 0., 1., 2.;
/// 1., 2., 0., 0.;
/// 2., 0., 1., 1.];
/// let h = a.upper_hessenberg();
///
/// println!("{:}", h.expect("Could not get upper Hessenberg form."));
/// # }
/// ```
///
/// # Panics
///
/// - The matrix is not square.
///
/// # Failures
///
/// - The matrix cannot be reduced to upper hessenberg form.
pub fn upper_hessenberg(mut self) -> Result<Matrix<T>, Error> {
let n = self.rows;
assert!(n == self.cols,
"Matrix must be square to produce upper hessenberg.");
for i in 0..n - 2 {
let h_holder_vec: Matrix<T>;
{
let lower_slice = MatrixSlice::from_matrix(&self, [i + 1, i], n - i - 1, 1);
// Try to get the house holder transform - else map error and pass up.
h_holder_vec = try!(Matrix::make_householder_vec(&lower_slice.iter()
.cloned()
.collect::<Vec<_>>())
.map_err(|_| {
Error::new(ErrorKind::DecompFailure,
"Cannot compute upper Hessenberg form.")
}));
}
{
// Apply holder on the left
let mut block =
MatrixSliceMut::from_matrix(&mut self, [i + 1, i], n - i - 1, n - i);
block -= &h_holder_vec * (h_holder_vec.transpose() * &block) *
(T::one() + T::one());
}
{
// Apply holder on the right
let mut block = MatrixSliceMut::from_matrix(&mut self, [0, i + 1], n, n - i - 1);
block -= (&block * &h_holder_vec) * h_holder_vec.transpose() *
(T::one() + T::one());
}
}
// Enforce upper hessenberg
for i in 0..self.cols - 2 {
for j in i + 2..self.rows {
unsafe {
*self.get_unchecked_mut([j, i]) = T::zero();
}
}
}
Ok(self)
}
/// Returns (U,H), where H is the upper hessenberg form
/// and U is the unitary transform matrix.
///
/// Note: The current transform matrix seems broken...
///
/// # Examples
///
/// ```
/// # #[macro_use] extern crate rulinalg; fn main() {
/// use rulinalg::matrix::BaseMatrix;
///
/// let a = matrix![1., 2., 3.;
/// 4., 5., 6.;
/// 7., 8., 9.];
///
/// // u is the transform, h is the upper hessenberg form.
/// let (u, h) = a.clone().upper_hess_decomp().expect("This matrix should decompose!");
///
/// assert_matrix_eq!(h, u.transpose() * a * u, comp = abs, tol = 1e-12);
/// # }
/// ```
///
/// # Panics
///
/// - The matrix is not square.
///
/// # Failures
///
/// - The matrix cannot be reduced to upper hessenberg form.
pub fn upper_hess_decomp(self) -> Result<(Matrix<T>, Matrix<T>), Error> {
let n = self.rows;
assert!(n == self.cols,
"Matrix must be square to produce upper hessenberg.");
// First we form the transformation.
let mut transform = Matrix::identity(n);
for i in (0..n - 2).rev() {
let h_holder_vec: Matrix<T>;
{
let lower_slice = MatrixSlice::from_matrix(&self, [i + 1, i], n - i - 1, 1);
h_holder_vec = try!(Matrix::make_householder_vec(&lower_slice.iter()
.cloned()
.collect::<Vec<_>>())
.map_err(|_| {
Error::new(ErrorKind::DecompFailure, "Could not compute eigenvalues.")
}));
}
let mut trans_block =
MatrixSliceMut::from_matrix(&mut transform, [i + 1, i + 1], n - i - 1, n - i - 1);
trans_block -= &h_holder_vec * (h_holder_vec.transpose() * &trans_block) *
(T::one() + T::one());
}
// Now we reduce to upper hessenberg
Ok((transform, try!(self.upper_hessenberg())))
}
}
#[cfg(test)]
mod tests {
use matrix::Matrix;
#[test]
#[should_panic]
fn test_non_square_upper_hessenberg() {
let a: Matrix<f64> = Matrix::ones(2, 3);
let _ = a.upper_hessenberg();
}
#[test]
#[should_panic]
fn test_non_square_upper_hess_decomp() {
let a: Matrix<f64> = Matrix::ones(2, 3);
let _ = a.upper_hess_decomp();
}
}