Skip to content

Commit d48e215

Browse files
committed
Householder reflection
1 parent 59c390d commit d48e215

File tree

3 files changed

+90
-4
lines changed

3 files changed

+90
-4
lines changed

src/arnoldi.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,6 @@ impl<A: Scalar> MGS<A> {
6565

6666
/// Add new vector if the residual is larger than relative tolerance
6767
///
68-
/// Panic
69-
/// -------
70-
/// - if the size of the input array mismaches to the dimension
71-
///
7268
/// ```rust
7369
/// # use ndarray::*;
7470
/// # use ndarray_linalg::*;
@@ -85,6 +81,11 @@ impl<A: Scalar> MGS<A> {
8581
/// close_l2(&coef, &array![2.0, 1.0, 0.0], 1e-9).unwrap(); // You can get coefficients of dependent vector
8682
/// }
8783
/// ```
84+
///
85+
/// Panic
86+
/// -------
87+
/// - if the size of the input array mismaches to the dimension
88+
///
8889
pub fn append<S>(&mut self, a: ArrayBase<S, Ix1>, rtol: A::Real) -> Result<Array1<A>, Array1<A>>
8990
where
9091
A: Lapack,

src/householder.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
use crate::{inner::*, norm::*, types::*};
2+
use ndarray::*;
3+
4+
/// Iterative orthogonalizer using Householder reflection
5+
#[derive(Debug, Clone)]
6+
pub struct Householder<A> {
7+
dim: usize,
8+
v: Vec<Array1<A>>,
9+
}
10+
11+
impl<A: Scalar> Householder<A> {
12+
pub fn new(dim: usize) -> Self {
13+
Householder { dim, v: Vec::new() }
14+
}
15+
16+
pub fn len(&self) -> usize {
17+
self.v.len()
18+
}
19+
20+
/// Take a Reflection `P = I - 2ww^T`
21+
fn reflect<S: DataMut<Elem = A>>(&self, k: usize, a: &mut ArrayBase<S, Ix1>) {
22+
assert!(k < self.v.len());
23+
assert_eq!(a.len(), self.dim);
24+
let w = self.v[k].slice(s![k..]);
25+
let c = A::from(2.0).unwrap() * w.inner(&a.slice(s![k..]));
26+
for l in k..self.dim {
27+
a[l] -= c * w[l];
28+
}
29+
}
30+
31+
/// Orghotonalize input vector by reflectors
32+
///
33+
/// Panic
34+
/// -------
35+
/// - if the size of the input array mismaches to the dimension
36+
pub fn orthogonalize<S>(&self, a: &mut ArrayBase<S, Ix1>) -> A::Real
37+
where
38+
A: Lapack,
39+
S: DataMut<Elem = A>,
40+
{
41+
for k in 0..self.len() {
42+
self.reflect(k, a);
43+
}
44+
// residual norm
45+
a.slice(s![self.len()..]).norm_l2()
46+
}
47+
48+
/// Orghotonalize input vector by reflectors
49+
///
50+
/// ```rust
51+
/// # use ndarray::*;
52+
/// # use ndarray_linalg::*;
53+
/// let mut mgs = arnoldi::MGS::new(3);
54+
/// let coef = mgs.append(array![0.0, 1.0, 0.0], 1e-9).unwrap();
55+
/// close_l2(&coef, &array![1.0], 1e-9).unwrap();
56+
///
57+
/// let coef = mgs.append(array![1.0, 1.0, 0.0], 1e-9).unwrap();
58+
/// close_l2(&coef, &array![1.0, 1.0], 1e-9).unwrap();
59+
///
60+
/// assert!(mgs.append(array![1.0, 2.0, 0.0], 1e-9).is_err()); // Fail if the vector is linearly dependend
61+
///
62+
/// if let Err(coef) = mgs.append(array![1.0, 2.0, 0.0], 1e-9) {
63+
/// close_l2(&coef, &array![2.0, 1.0, 0.0], 1e-9).unwrap(); // You can get coefficients of dependent vector
64+
/// }
65+
/// ```
66+
///
67+
/// Panic
68+
/// -------
69+
/// - if the size of the input array mismaches to the dimension
70+
///
71+
pub fn append<S>(&mut self, mut a: ArrayBase<S, Ix1>, rtol: A::Real) -> Result<Array1<A>, Array1<A>>
72+
where
73+
A: Lapack,
74+
S: DataMut<Elem = A>,
75+
{
76+
let residual = self.orthogonalize(&mut a);
77+
let coef = a.slice(s![..self.len()]).into_owned();
78+
if residual < rtol {
79+
return Err(coef);
80+
}
81+
self.v.push(a.into_owned());
82+
Ok(coef)
83+
}
84+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub mod diagonal;
2525
pub mod eigh;
2626
pub mod error;
2727
pub mod generate;
28+
pub mod householder;
2829
pub mod inner;
2930
pub mod lapack;
3031
pub mod layout;

0 commit comments

Comments
 (0)