Skip to content

Commit 54ff3b1

Browse files
committed
Import householder reflection from 'arnoldi' branch
1 parent 80ab252 commit 54ff3b1

File tree

1 file changed

+107
-0
lines changed

1 file changed

+107
-0
lines changed

src/krylov/householder.rs

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
use super::*;
2+
use crate::{inner::*, norm::*};
3+
use num_traits::Zero;
4+
5+
/// Iterative orthogonalizer using Householder reflection
6+
#[derive(Debug, Clone)]
7+
pub struct Householder<A: Scalar> {
8+
/// Dimension of orthogonalizer
9+
dim: usize,
10+
11+
/// Store Householder reflector.
12+
///
13+
/// The coefficient is copied into another array, and this does not contain
14+
v: Vec<Array1<A>>,
15+
}
16+
17+
impl<A: Scalar> Householder<A> {
18+
/// Create a new orthogonalizer
19+
pub fn new(dim: usize) -> Self {
20+
Householder { dim, v: Vec::new() }
21+
}
22+
23+
/// Take a Reflection `P = I - 2ww^T`
24+
fn reflect<S: DataMut<Elem = A>>(&self, k: usize, a: &mut ArrayBase<S, Ix1>) {
25+
assert!(k < self.v.len());
26+
assert_eq!(a.len(), self.dim, "Input array size mismaches to the dimension");
27+
28+
let w = self.v[k].slice(s![k..]);
29+
let mut a_slice = a.slice_mut(s![k..]);
30+
let c = A::from(2.0).unwrap() * w.inner(&a_slice);
31+
for l in 0..self.dim - k {
32+
a_slice[l] -= c * w[l];
33+
}
34+
}
35+
}
36+
37+
impl<A: Scalar + Lapack> Orthogonalizer for Householder<A> {
38+
type Elem = A;
39+
40+
fn dim(&self) -> usize {
41+
self.dim
42+
}
43+
44+
fn len(&self) -> usize {
45+
self.v.len()
46+
}
47+
48+
fn orthogonalize<S>(&self, a: &mut ArrayBase<S, Ix1>) -> A::Real
49+
where
50+
S: DataMut<Elem = A>,
51+
{
52+
for k in 0..self.len() {
53+
self.reflect(k, a);
54+
}
55+
if self.is_full() {
56+
return Zero::zero();
57+
}
58+
// residual norm
59+
a.slice(s![self.len()..]).norm_l2()
60+
}
61+
62+
fn append<S>(&mut self, mut a: ArrayBase<S, Ix1>, rtol: A::Real) -> Result<Array1<A>, Array1<A>>
63+
where
64+
S: DataMut<Elem = A>,
65+
{
66+
assert_eq!(a.len(), self.dim);
67+
let k = self.len();
68+
let alpha = self.orthogonalize(&mut a);
69+
let mut coef = Array::zeros(k + 1);
70+
for i in 0..k {
71+
coef[i] = a[i];
72+
}
73+
if alpha < rtol {
74+
// linearly dependent
75+
coef[k] = A::from_real(alpha);
76+
return Err(coef);
77+
}
78+
79+
// Add reflector
80+
assert!(k < a.len()); // this must hold because `alpha == 0` if k >= a.len()
81+
let alpha = if a[k].abs() > Zero::zero() {
82+
a[k].mul_real(alpha / a[k].abs())
83+
} else {
84+
A::from_real(alpha)
85+
};
86+
coef[k] = alpha;
87+
88+
a[k] -= alpha;
89+
let norm = a.slice(s![k..]).norm_l2();
90+
azip!(mut a (a.slice_mut(s![..k])) in { *a = Zero::zero() }); // this can be omitted
91+
azip!(mut a (a.slice_mut(s![k..])) in { *a = a.div_real(norm) });
92+
self.v.push(a.into_owned());
93+
Ok(coef)
94+
}
95+
96+
fn get_q(&self) -> Q<A> {
97+
assert!(self.len() > 0);
98+
let mut a = Array::zeros((self.dim(), self.len()));
99+
for (i, mut col) in a.axis_iter_mut(Axis(1)).enumerate() {
100+
col[i] = A::one();
101+
for l in (0..self.len()).rev() {
102+
self.reflect(l, &mut col);
103+
}
104+
}
105+
a
106+
}
107+
}

0 commit comments

Comments
 (0)