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