Skip to content

Commit e79d4b9

Browse files
committed
Add Orthogonalizer trait and general impl of online QR decomposition
1 parent 252b70e commit e79d4b9

File tree

1 file changed

+90
-0
lines changed

1 file changed

+90
-0
lines changed

src/krylov/mod.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,59 @@ pub type Q<A> = Array2<A>;
2121
///
2222
pub type R<A> = Array2<A>;
2323

24+
pub trait Orthogonalizer {
25+
type Elem: Scalar;
26+
27+
/// Dimension of input array
28+
fn dim(&self) -> usize;
29+
30+
/// Number of cached basis
31+
fn len(&self) -> usize;
32+
33+
/// check if the basis spans entire space
34+
fn is_full(&self) -> bool {
35+
self.len() == self.dim()
36+
}
37+
38+
fn is_empty(&self) -> bool {
39+
self.len() == 0
40+
}
41+
42+
/// Orthogonalize given vector using current basis
43+
///
44+
/// Panic
45+
/// -------
46+
/// - if the size of the input array mismatches to the dimension
47+
///
48+
fn orthogonalize<S>(&self, a: &mut ArrayBase<S, Ix1>) -> Array1<Self::Elem>
49+
where
50+
S: DataMut<Elem = Self::Elem>;
51+
52+
/// Add new vector if the residual is larger than relative tolerance
53+
///
54+
/// Returns
55+
/// --------
56+
/// Coefficients to the `i`-th Q-vector
57+
///
58+
/// - The size of array must be `self.len() + 1`
59+
/// - The last element is the residual norm of input vector
60+
///
61+
/// Panic
62+
/// -------
63+
/// - if the size of the input array mismatches to the dimension
64+
///
65+
fn append<S>(
66+
&mut self,
67+
a: ArrayBase<S, Ix1>,
68+
rtol: <Self::Elem as Scalar>::Real,
69+
) -> Result<Array1<Self::Elem>, Array1<Self::Elem>>
70+
where
71+
S: DataMut<Elem = Self::Elem>;
72+
73+
/// Get Q-matrix of generated basis
74+
fn get_q(&self) -> Q<Self::Elem>;
75+
}
76+
2477
/// Strategy for linearly dependent vectors appearing in iterative QR decomposition
2578
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2679
pub enum Strategy {
@@ -41,3 +94,40 @@ pub enum Strategy {
4194
/// ```
4295
Full,
4396
}
97+
98+
/// Online QR decomposition using arbitrary orthogonalizer
99+
pub fn qr<A, S>(
100+
iter: impl Iterator<Item = ArrayBase<S, Ix1>>,
101+
mut ortho: impl Orthogonalizer<Elem = A>,
102+
rtol: A::Real,
103+
strategy: Strategy,
104+
) -> (Q<A>, R<A>)
105+
where
106+
A: Scalar + Lapack,
107+
S: Data<Elem = A>,
108+
{
109+
assert_eq!(ortho.len(), 0);
110+
111+
let mut coefs = Vec::new();
112+
for a in iter {
113+
match ortho.append(a.into_owned(), rtol) {
114+
Ok(coef) => coefs.push(coef),
115+
Err(coef) => match strategy {
116+
Strategy::Terminate => break,
117+
Strategy::Skip => continue,
118+
Strategy::Full => coefs.push(coef),
119+
},
120+
}
121+
}
122+
let n = ortho.len();
123+
let m = coefs.len();
124+
let mut r = Array2::zeros((n, m).f());
125+
for j in 0..m {
126+
for i in 0..n {
127+
if i < coefs[j].len() {
128+
r[(i, j)] = coefs[j][i];
129+
}
130+
}
131+
}
132+
(ortho.get_q(), r)
133+
}

0 commit comments

Comments
 (0)