1
+ import Base: start, next, done
2
+
1
3
# Simple methods
2
4
export powm, invpowm
3
5
4
- # ###################
5
- # API method calls #
6
- # ###################
6
+ type PowerMethodIterable{matT, vecT <: AbstractVector , numT <: Number , eigvalT <: Number }
7
+ A:: matT
8
+ x:: vecT
9
+ tol:: numT
10
+ maxiter:: Int
11
+ θ:: eigvalT
12
+ r:: vecT
13
+ Ax:: vecT
14
+ residual:: numT
15
+ end
7
16
8
- function powm (A;
9
- x= nothing , tol:: Real = eps (real (eltype (A)))* size (A,2 )^ 3 , maxiter:: Int = size (A,2 ),
10
- log:: Bool = false , kwargs...
11
- )
12
- K = KrylovSubspace (A, 1 )
13
- x== nothing ? initrand! (K) : init! (K, x/ norm (x))
14
17
15
- history = ConvergenceHistory (partial= ! log)
16
- history[:tol ] = tol
17
- reserve! (history,:resnorm , maxiter)
18
- eig, v = powm_method! (history, K; tol= tol, maxiter= maxiter, kwargs... )
19
- log && shrink! (history)
20
- log ? (eig, v, history) : (eig, v)
18
+ # #
19
+ # # Iterators
20
+ # #
21
+
22
+ @inline converged (p:: PowerMethodIterable ) = p. residual ≤ p. tol
23
+
24
+ @inline start (p:: PowerMethodIterable ) = 0
25
+
26
+ @inline done (p:: PowerMethodIterable , iteration:: Int ) = iteration > p. maxiter || converged (p)
27
+
28
+ function next (p:: PowerMethodIterable , iteration:: Int )
29
+
30
+ A_mul_B! (p. Ax, p. A, p. x)
31
+
32
+ # Rayleigh quotient θ = x'Ax
33
+ p. θ = dot (p. x, p. Ax)
34
+
35
+ # (Previous) residual vector r = Ax - λx
36
+ copy! (p. r, p. Ax)
37
+ BLAS. axpy! (- p. θ, p. x, p. r)
38
+
39
+ # Normed residual
40
+ p. residual = norm (p. r)
41
+
42
+ # Normalize the next approximation
43
+ copy! (p. x, p. Ax)
44
+ scale! (p. x, one (eltype (p. x)) / norm (p. x))
45
+
46
+ p. residual, iteration + 1
21
47
end
22
48
23
- # ########################
24
- # Method Implementation #
25
- # ########################
26
-
27
- function powm_method! {T} (log:: ConvergenceHistory , K:: KrylovSubspace{T} ;
28
- tol:: Real = eps (real (T))* K. n^ 3 , maxiter:: Int = K. n, verbose:: Bool = false
29
- )
30
- verbose && @printf (" === powm ===\n %4s\t %7s\n " ," iter" ," resnorm" )
31
- θ = zero (T)
32
- v = Array (T, K. n)
33
- for iter= 1 : maxiter
34
- nextiter! (log,mvps= 1 )
35
- v = lastvec (K)
36
- y = nextvec (K)
37
- θ = dot (v, y)
38
- resnorm = real (norm (y - θ* v))
39
- push! (log, :resnorm , resnorm)
40
- verbose && @printf (" %3d\t %1.2e\n " ,iter,resnorm)
41
- resnorm <= tol* abs (θ) && (setconv (log, resnorm >= 0 ); break )
42
- appendunit! (K, y)
43
- end
44
- verbose && @printf (" \n " )
45
- θ, v
49
+ # Transforms the eigenvalue back whether shifted or inversed
50
+ @inline transform_eigenvalue (θ, inverse:: Bool , σ) = σ + (inverse ? inv (θ) : θ)
51
+
52
+ function powm_iterable! (A, x; tol = eps (real (eltype (A))) * size (A, 2 ) ^ 3 , maxiter = size (A, 1 ))
53
+ T = eltype (x)
54
+ PowerMethodIterable (A, x, tol, maxiter, zero (T), similar (x), similar (x), realmax (real (T)))
55
+ end
56
+
57
+ function powm_iterable (A; kwargs... )
58
+ x0 = rand (Complex{real (eltype (A))}, size (A, 1 ))
59
+ scale! (x0, one (eltype (A)) / norm (x0))
60
+ powm_iterable! (A, x0; kwargs... )
46
61
end
47
62
48
63
# ###################
49
64
# API method calls #
50
65
# ###################
51
66
52
- function invpowm (A;
53
- x= nothing , shift:: Number = 0 , tol:: Real = eps (real (eltype (A)))* size (A,2 )^ 3 ,
54
- maxiter:: Int = size (A,2 ), log:: Bool = false , kwargs...
55
- )
56
- K = KrylovSubspace (A, 1 )
57
- x== nothing ? initrand! (K) : init! (K, x/ norm (x))
67
+ function powm (A; kwargs... )
68
+ x0 = rand (Complex{real (eltype (A))}, size (A, 1 ))
69
+ scale! (x0, one (eltype (A)) / norm (x0))
70
+ powm! (A, x0; kwargs... )
71
+ end
58
72
59
- history = ConvergenceHistory (partial= ! log)
73
+ function powm! (A, x;
74
+ tol = eps (real (eltype (A))) * size (A, 2 ) ^ 3 ,
75
+ maxiter = size (A, 1 ),
76
+ shift = zero (eltype (A)),
77
+ inverse:: Bool = false ,
78
+ log:: Bool = false ,
79
+ verbose:: Bool = false
80
+ )
81
+ history = ConvergenceHistory (partial = ! log)
60
82
history[:tol ] = tol
61
- reserve! (history,:resnorm , maxiter)
62
- eig, v = invpowm_method! (history, K, shift; tol= tol, maxiter= maxiter, kwargs... )
83
+ reserve! (history, :resnorm , maxiter)
84
+ verbose && @printf (" === powm ===\n %4s\t %7s\n " , " iter" , " resnorm" )
85
+
86
+ iterable = powm_iterable! (A, x, tol = tol, maxiter = maxiter)
87
+
88
+ for (iteration, residual) = enumerate (iterable)
89
+ nextiter! (history, mvps = 1 )
90
+ verbose && @printf (" %3d\t %1.2e\n " , iteration, residual)
91
+ end
92
+
93
+ setconv (history, converged (iterable))
94
+
95
+ verbose && println ()
96
+
63
97
log && shrink! (history)
64
- log ? (eig, v, history) : (eig, v)
98
+
99
+ λ = transform_eigenvalue (iterable. θ, inverse, shift)
100
+ x = iterable. x
101
+
102
+ log ? (λ, x, history) : (λ, x)
65
103
end
66
104
67
- # ########################
68
- # Method Implementation #
69
- # ########################
70
-
71
- function invpowm_method! {T} (log:: ConvergenceHistory , K:: KrylovSubspace{T} , σ:: Number = zero (T);
72
- tol:: Real = eps (real (T))* K. n^ 3 , maxiter:: Int = K. n, verbose:: Bool = false
73
- )
74
- verbose && @printf (" === invpowm ===\n %4s\t %7s\n " ," iter" ," resnorm" )
75
- θ = zero (T)
76
- v = Array (T, K. n)
77
- y = Array (T, K. n)
78
- σ = convert (T, σ)
79
- for iter= 1 : maxiter
80
- nextiter! (log,mvps= 1 )
81
- v = lastvec (K)
82
- y = (K. A- σ* eye (K))\ v
83
- θ = dot (v, y)
84
- resnorm = norm (y - θ* v)
85
- push! (log, :resnorm , resnorm)
86
- verbose && @printf (" %3d\t %1.2e\n " ,iter,resnorm)
87
- resnorm <= tol* abs (θ) && (setconv (log, resnorm >= 0 ); break )
88
- appendunit! (K, y)
89
- end
90
- verbose && @printf (" \n " )
91
- σ+ 1 / θ, y/ θ
105
+ function invpowm (B; kwargs... )
106
+ x0 = rand (Complex{real (eltype (B))}, size (B, 1 ))
107
+ scale! (x0, one (eltype (B)) / norm (x0))
108
+ invpowm! (B, x0; kwargs... )
92
109
end
93
110
111
+ invpowm! (B, x0; kwargs... ) = powm! (B, x0; inverse = true , kwargs... )
112
+
94
113
# ################
95
114
# Documentation #
96
115
# ################
99
118
# Initialize parameters
100
119
doc1_call = """ powm(A)
101
120
"""
102
- doc2_call = """ invpowm(A )
121
+ doc2_call = """ invpowm(B )
103
122
"""
104
- doc1_msg = """ Find biggest eigenvalue of `A` and its associated eigenvector
123
+ doc1_msg = """ Find the largest eigenvalue `λ` (in absolute value) of `A` and its associated eigenvector `x`
105
124
using the power method.
106
125
"""
107
- doc2_msg = """ Find closest eigenvalue of `A` to `shift` and its associated eigenvector
108
- using the inverse power iteration method.
126
+ doc2_msg = """ For an eigenvalue problem Ax = λx, find the closest eigenvalue in the complex plane to `shift`
127
+ together with its associated eigenvector `x`. The first argument `B` should be a mapping that has
128
+ the effect of B * x = inv(A - shift * I) * x and should support the `A_mul_B!` operation.
129
+
130
+ # Examples
131
+
132
+ ```julia
133
+ using LinearMaps
134
+ σ = 1.0 + 1.3im
135
+ A = rand(Complex128, 50, 50)
136
+ F = lufact(A - UniformScaling(σ))
137
+ Fmap = LinearMap((y, x) -> A_ldiv_B!(y, F, x), 50, Complex128, ismutating = true)
138
+ λ, x = invpowm(Fmap, shift = σ, tol = 1e-4, maxiter = 200)
139
+ ```
109
140
"""
110
141
doc1_karg = " "
111
142
doc2_karg = " `shift::Number=0`: shift to be applied to matrix A."
@@ -124,13 +155,11 @@ $call
124
155
125
156
$msg
126
157
127
- If `log` is set to `true` is given, method will output a tuple `eig, v , ch`. Where
128
- `ch` is a `ConvergenceHistory` object. Otherwise it will only return `eig, v `.
158
+ If `log` is set to `true` is given, method will output a tuple `λ, x , ch`. Where
159
+ `ch` is a `ConvergenceHistory` object. Otherwise it will only return `λ, x `.
129
160
130
161
# Arguments
131
162
132
- `K::KrylovSubspace`: krylov subspace.
133
-
134
163
`A`: linear operator.
135
164
136
165
## Keywords
@@ -152,15 +181,15 @@ containing extra information of the method execution.
152
181
153
182
**if `log` is `false`**
154
183
155
- `eig::Real `: eigen value
184
+ `λ::Number `: eigenvalue
156
185
157
- `v ::Vector`: eigen vector
186
+ `x ::Vector`: eigenvector
158
187
159
188
**if `log` is `true`**
160
189
161
- `eig::Real`: eigen value
190
+ `eig::Real`: eigenvalue
162
191
163
- `v ::Vector`: eigen vector
192
+ `x ::Vector`: eigenvector
164
193
165
194
`ch`: convergence history.
166
195
0 commit comments