Skip to content

Commit 88889c1

Browse files
committed
arnodli_{mgs,householder}
1 parent 12340b2 commit 88889c1

File tree

1 file changed

+71
-9
lines changed

1 file changed

+71
-9
lines changed

src/krylov/arnoldi.rs

Lines changed: 71 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use super::*;
2+
use crate::norm::Norm;
3+
use num_traits::One;
24
use std::iter::Fuse;
35

46
pub struct Arnoldi<A, S, F, Ortho>
@@ -15,14 +17,25 @@ where
1517

1618
impl<A, S, F, Ortho> Arnoldi<A, S, F, Ortho>
1719
where
18-
A: Scalar,
20+
A: Scalar + Lapack,
1921
S: DataMut<Elem = A>,
2022
F: Fn(&mut ArrayBase<S, Ix1>),
2123
Ortho: Orthogonalizer<Elem = A>,
2224
{
23-
pub fn new(a: F, v: ArrayBase<S, Ix1>, ortho: Ortho) -> Fuse<Self> {
25+
pub fn new(a: F, mut v: ArrayBase<S, Ix1>, mut ortho: Ortho) -> Fuse<Self> {
26+
assert_eq!(ortho.len(), 0);
27+
assert!(ortho.tolerance() < One::one());
28+
// normalize before append because |v| may be smaller than ortho.tolerance()
29+
let norm = v.norm_l2();
30+
azip!(mut v(&mut v) in { *v = v.div_real(norm) });
31+
ortho.append(v.view());
2432
Iterator::fuse(Arnoldi { a, v, ortho })
2533
}
34+
35+
/// Dimension of Krylov subspace
36+
pub fn krylov_dimension(&self) -> usize {
37+
self.ortho.len()
38+
}
2639
}
2740

2841
impl<A, S, F, Ortho> Iterator for Arnoldi<A, S, F, Ortho>
@@ -36,13 +49,62 @@ where
3649

3750
fn next(&mut self) -> Option<Self::Item> {
3851
(self.a)(&mut self.v);
39-
match self.ortho.div_append(&mut self.v) {
40-
AppendResult::Added(coef) => {
41-
let norm = coef[coef.len() - 1].abs();
42-
azip!(mut a(&mut self.v) in { *a = a.div_real(norm) });
43-
Some(coef)
44-
}
45-
AppendResult::Dependent(_) => None,
52+
let result = self.ortho.div_append(&mut self.v);
53+
azip!(mut v(&mut self.v) in { *v = v.div_real(result.residual_norm()) });
54+
if result.is_dependent() {
55+
None
56+
} else {
57+
Some(result.into_coeff())
4658
}
4759
}
4860
}
61+
62+
pub fn arnoldi_householder<A, S1, S2>(
63+
a: ArrayBase<S1, Ix2>,
64+
v: ArrayBase<S2, Ix1>,
65+
tol: A::Real,
66+
) -> impl Iterator<Item = Array1<A>>
67+
where
68+
A: Scalar + Lapack,
69+
S1: Data<Elem = A>,
70+
S2: DataMut<Elem = A>,
71+
{
72+
let (n, m) = a.dim();
73+
assert_eq!(n, m, "Input matrix must be square");
74+
assert_eq!(m, v.len(), "Input matrix and vector sizes mismach");
75+
76+
let householder = Householder::new(n, tol);
77+
Arnoldi::new(
78+
move |x| {
79+
let ax = a.dot(x);
80+
azip!(mut x(x), ax in { *x = ax });
81+
},
82+
v,
83+
householder,
84+
)
85+
}
86+
87+
pub fn arnoldi_mgs<A, S1, S2>(
88+
a: ArrayBase<S1, Ix2>,
89+
v: ArrayBase<S2, Ix1>,
90+
tol: A::Real,
91+
) -> impl Iterator<Item = Array1<A>>
92+
where
93+
A: Scalar + Lapack,
94+
S1: Data<Elem = A>,
95+
S2: DataMut<Elem = A>,
96+
{
97+
let (n, m) = a.dim();
98+
assert_eq!(n, m, "Input matrix must be square");
99+
assert_eq!(m, v.len(), "Input matrix and vector sizes mismach");
100+
101+
let mgs = MGS::new(n, tol);
102+
Arnoldi::new(
103+
move |x| {
104+
let ax = a.dot(x);
105+
azip!(mut x(x), ax in { *x = ax });
106+
},
107+
v,
108+
mgs,
109+
)
110+
}

0 commit comments

Comments
 (0)