-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathek_krylov.m
154 lines (119 loc) · 3.43 KB
/
ek_krylov.m
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
function [V, K, H, params] = ek_krylov(varargin)
%EK_KRYLOV Extended Krylov projection of a matrix A.
%
% [V, K, H, params] = EK_KRYLOV(A, B) construct the extended Krylov
% subspace spanned by [B, A*B, A\B]. The matrix V is an orthogonal
% basis for this space, and K and H are block upper Hessenberg
% rectangular matrices satisfying
%
% A * V * K = V * H (1)
%
% [V, K, H, params] = EK_KRYLOV(V, K, H, PARAMS) enlarges an extended
% Krylov subspace generated with a previous call to EK_KRYLOV by adding
% another zero / infinity pole pair. The resulting space will satisfy
% the same relation (1).
%
% Note: the poles are added as [0, inf] (in this order).
if nargin ~= 2 && nargin ~= 4
error('Called with the wrong number of arguments');
end
if nargin == 2
% Start to construct the extended Krylov space
[V, K, H, params] = ek_krylov_start(varargin{:});
else
% Enlarge the space that was previously built
[V, K, H, params] = ek_krylov_extend(varargin{:});
end
end
function [V, K, H, params] = ek_krylov_start(A, b)
if ~isstruct(A)
m = size(A, 1);
n = size(A, 2);
if m ~= n
error('The matrix A should be square');
end
if n ~= size(b, 1)
error('The block vector b has wrong number of rows');
end
end
bs = size(b, 2);
% Construct a basis for the column span of b
[V, ~] = qr(b, 0);
H = zeros(bs, 0);
K = zeros(bs, 0);
[V, K, H, w] = add_zero_pole(V, K, H, A, V);
[V, K, H, w] = add_inf_pole (V, K, H, A, w);
% Save parameters for the next call
params = struct();
params.last = w;
params.A = A;
end
function [V, K, H, params] = ek_krylov_extend(V, K, H, params)
w = params.last;
A = params.A;
[V, K, H, w] = add_zero_pole(V, K, H, A, w);
[V, K, H, w] = add_inf_pole (V, K, H, A, w);
params.last = w;
end
%
% Utility routine that adds a zero pole to the space. The vector w is
% the continuation vector.
%
function [V, K, H, w] = add_zero_pole(V, K, H, A, w)
bs = size(w, 2);
if isstruct(A)
w = A.solve(1.0, 0.0, w);
else
w = A \ w;
end
% Perform orthogonalization with modified Gram-Schimidt
[w, h] = mgs_orthogonalize(V, w);
% Enlarge H and K
H(size(H, 1) + bs, size(H, 2) + bs) = 0;
K(size(K, 1) + bs, size(K, 2) + bs) = 0;
K(1:end-bs, end-bs+1:end) = h;
H(end-2*bs+1:end-bs, end-bs+1:end) = eye(bs);
[w, r] = qr(w, 0);
% Reorthogonalize
[w, hh] = mgs_orthogonalize(V, w);
[w, rr] = qr(w, 0);
K(1:end-bs, end-bs+1:end) = K(1:end-bs, end-bs+1:end) + hh * r;
K(end-bs+1:end, end-bs+1:end) = rr * r;
V = [V, w];
end
%
% Utility routine that adds an infinity pole to the space. The vector w is
% the continuation vector.
%
function [V, K, H, w] = add_inf_pole(V, K, H, A, w)
bs = size(w, 2);
if isstruct(A)
w = A.multiply(1.0, 0.0, w);
else
w = A * w;
end
% Perform orthogonalization with modified Gram-Schimidt
[w, h] = mgs_orthogonalize(V, w);
% Enlarge H and K
H(size(H, 1) + bs, size(H, 2) + bs) = 0;
K(size(K, 1) + bs, size(K, 2) + bs) = 0;
H(1:end-bs, end-bs+1:end) = h;
K(end-2*bs+1:end-bs, end-bs+1:end) = eye(bs);
[w, r] = qr(w, 0);
% Reorthogonalize
[w, hh] = mgs_orthogonalize(V, w);
[w, rr] = qr(w, 0);
H(1:end-bs, end-bs+1:end) = H(1:end-bs, end-bs+1:end) + hh * r ;
H(end-bs+1:end, end-bs+1:end) = rr * r;
V = [V, w];
end
%
% Gram-Schmidt orthogonalization procedure.
%
function [w, h] = mgs_orthogonalize(V, w)
h = V' * w;
w = w - V * h;
%h1 = V' * w;
%h = h + h1;
%w = w - V * h1;
end