vrcore  0.45
visuReal Messkern
 All Classes Files Functions Variables
orthogonal.hpp
Go to the documentation of this file.
1 
3 // Copyright Gunter Winkler 2004 - 2007.
4 // Distributed under the Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 
8 // authors: Gunter Winkler <guwi17 at gmx dot de>
9 // Konstantin Kutzkow
10 
11 
12 #ifndef __INCLUDE_ORTHOGONAL_HPP__
13 #define __INCLUDE_ORTHOGONAL_HPP__
14 
15 #include <boost/numeric/ublas/vector.hpp>
16 #include <boost/numeric/ublas/vector_proxy.hpp>
17 #include <boost/numeric/ublas/vector_of_vector.hpp>
18 #include <boost/numeric/ublas/vector_expression.hpp>
19 #include <boost/numeric/ublas/io.hpp>
20 
21 #include <boost/numeric/ublas/matrix.hpp>
22 #include <boost/numeric/ublas/matrix_proxy.hpp>
23 #include <boost/numeric/ublas/operation.hpp>
24 #include <boost/numeric/ublas/operation_sparse.hpp>
25 
26 #include <boost/numeric/ublas/matrix_sparse.hpp>
27 #include <boost/numeric/ublas/banded.hpp>
28 #include <boost/numeric/ublas/io.hpp>
29 
30 
31 using namespace std;
32 namespace ublas = boost::numeric::ublas;
33 
34 
38 template <class Vector>
39 std::vector< Vector > orthogonal_system(std::vector< Vector > & basis){
40 
41  ublas::matrix<double> r (basis.size(), basis.size());
42  std::vector< Vector > q(basis.size());
43 
44  for (int i = 0; i < basis.size(); ++i){
45 
46  r(i, i) = ublas::norm_2(basis[i]);
47  q[i] = basis[i]/r(i, i);
48 
49  for (int j = i+1; j < basis.size(); ++j){
50  r(i, j) = ublas::inner_prod(q[i], basis[j]);
51  basis[j] -= r(i, j)*q[i];
52  }
53 
54  }
55 
56  return q;
57 }
58 
62 template <class Vector>
63 Vector orthogonal_vector(std::vector< Vector > & basis, Vector & v){
64 
65  for (int i = 0; i < basis.size(); ++i){
66  double r = ublas::inner_prod(basis[i], v);
67  v -= r*basis[i];
68  }
69  return v/ublas::norm_2(v);
70 }
71 
77 template <class Matrix, class Vector>
78 Vector arnoldi_step (std::vector< Vector > & q, Matrix & A, Matrix & H, int n){
79  Vector v = ublas::prod(A, q[n]);
80 
81  for (int j = 0; j <= n; ++j){
82  H(j, n) = ublas::inner_prod(q[j], v);
83  v -= H(j, n)*q[j];
84  }
85  H(n+1, n) = ublas::norm_2(v);
86  q[n+1] = v/H(n+1, n);
87 
88  return q[n+1];
89 
90 }
91 
97 template <class Matrix, class Vector>
98 void gmres (const Matrix & A, Vector & x, const Vector & b, double tol){
99 
100  const std::size_t image_size = A.size1();//orig: A.image_size();
101  const std::size_t preimage_size = A.size1();//preimage_size();
102  /*aus lin_op.hpp: std::size_t preimage_size() const {
103  return A.size2();
104  }
105 erstens offensichtlich nich ausprobiert zweitens sowieso sinnlos. Danke ihr Pisser.*/
106  Matrix Q(image_size, preimage_size+1);
107  Matrix H(image_size, preimage_size);
108 
109 
110  Vector v(image_size);
111  Vector c(image_size+1);
112  Vector s(image_size+1);
113  Vector z(image_size+1);
114 
115 
116  v = b - ublas::prod<Matrix>(A, x);
117  column(Q, 0) = v/ublas::norm_2(v);
118 
119  z(0) = ublas::norm_2(v);
120 
121  double z_0 = z(0);
122 
123  double t = tol + 1;
124 
125  int k = 0;
126 
127 
128  while (k < image_size && t > tol){
129  v = ublas::prod(A, column(Q, k));
130 
131  Vector h = column(H, k);
132 
133  Vector q;
134 
135  for (int j = 0; j <= k; ++j){
136  q = column(Q, j);
137  h(j) = ublas::inner_prod(q, v);
138  v -= h(j)*q;
139  }
140 
141  h(k+1) = ublas::norm_2(v);
142  column(Q, k+1) = v/h(k+1);
143 
144  for (int i = 0; i < k; ++i){
145  double h_i = h(i);
146  h(i) = c(i+1)*h(i) + s(i+1)*h(i+1);
147  h(i+1) = s(i+1)*h_i - c(i+1)*h(i+1);
148  }
149 
150  double h_kk = h(k);
151  double h_k1k = h(k+1);
152  double alpha = sqrt(h_kk*h_kk + h_k1k*h_k1k);
153  s(k+1) = h_k1k/alpha;
154  c(k+1) = h_kk/alpha;
155  h(k) = alpha;
156 
157  column(H, k) = h;
158 
159  z(k+1) = s(k+1)*z(k);
160  z(k) = c(k+1)*z(k);
161 
162 
163  t= z(k+1)/z_0;
164  ++k;
165 
166  if (0) {
167  Vector s(x);
168  Vector c(k+1);
169  for (int i = k; i >= 0; --i)
170  c(i) = (z(i) - inner_prod(project(row(H, i), ublas::range(i+1, k+1) ), project( c, ublas::range(i+1, k+1) )))/H(i, i);
171  for (int i = 0; i < k; ++i)
172  s += c(i)*column(Q, i);
173  cout << norm_2(prod(A,s)-b) << endl;
174  }
175 
176  }
177 
178 
179  c.clear();
180 
181  for (int i = k; i >= 0; --i)
182  c(i) = (z(i) - inner_prod(project(row(H, i), ublas::range(i+1, k+1) ), project( c, ublas::range(i+1, k+1) )))/H(i, i);
183 
184 
185  for (int i = 0; i < k; ++i)
186  x += c(i)*column(Q, i);
187 
188 }
189 
198 template <class Matrix, class LinOp, class Vector, class Precond>
199 unsigned int gmres_step ( LinOp const & A,
200  Vector & x,
201  const Vector & b,
202  Precond const & B,
203  unsigned int const maxiter,
204  double const tol)
205 {
206 
207  unsigned int size = A.image_size();
208 
209  Matrix Q(size, maxiter + 1);
210  Matrix H(size, maxiter + 1);
211 
212  Q.clear();
213  H.clear();
214 
215  Vector v(size);
216  Vector g(size);
217 
218  Vector c(maxiter + 1);
219  Vector s(maxiter + 1);
220  Vector z(maxiter + 1);
221 
222  Vector h(size); // working column of H
223 
224  A.residuum(x, b, v); //v = b - prod(A, x);
225 
226  B.apply(v, g);
227 
228  column(Q, 0) = g/ublas::norm_2(g);
229 
230  z(0) = ublas::norm_2(g);
231 
232  double z_0 = z(0);
233 
234  double t = tol + 1;
235 
236  unsigned int k = 0;
237 
238 
239  h.clear();
240  while (k < maxiter && t > tol){
241 
242  A.mult ( column(Q, k), v );
243  B.apply(v, g);
244 
245  for (unsigned int j = 0; j <= k; ++j) {
246  ublas::matrix_column<Matrix> q = column(Q, j);
247  h(j) = ublas::inner_prod(q, g);
248  g -= h(j)*q;
249  }
250 
251  for (unsigned int i = 0; i < k; ++i) {
252  double h_i = c(i+1)*h(i) + s(i+1)*h(i+1);
253  double h_i1 = s(i+1)*h(i) - c(i+1)*h(i+1);
254  h(i) = h_i;
255  h(i+1) = h_i1;
256  }
257 
258  h(k+1) = ublas::norm_2(g);
259  column(Q, k+1) = g/h(k+1);
260 
261  double h_kk = h(k);
262  double h_k1k = h(k+1);
263  double alpha = sqrt(h_kk*h_kk + h_k1k*h_k1k);
264  s(k+1) = h_k1k/alpha;
265  c(k+1) = h_kk/alpha;
266  h(k) = alpha;
267 
268  column(H, k) = h;
269 
270  z(k+1) = s(k+1)*z(k);
271  z(k) = c(k+1)*z(k);
272 
273  t= z(k+1)/z_0;
274 
275 
276 
277  ++k;
278 
279  if (0) {
280  Vector c(maxiter + 1);
281  c.clear();
282 
283  if (k>0) {
284  unsigned int i = k;
285  while ( (i--) > 0 ) {
286  c(i) = (z(i) - inner_prod(project(row(H, i), ublas::range(i+1, k+1) ), project( c, ublas::range(i+1, k+1) )))/H(i, i);
287  }
288  }
289 
290  Vector current_x(x);
291  current_x += prod(project(Q, ublas::range::all(), ublas::range(0, k)), project(c, ublas::range(0, k) ) );
292 
293  std::cout << k << " " << current_x << "\n";
294  }
295  }
296 
297  c.clear();
298 
299  if (k>0) {
300  unsigned int i = k;
301  while ( (i--) > 0 ) {
302  c(i) = (z(i) - inner_prod(project(row(H, i), ublas::range(i+1, k+1) ), project( c, ublas::range(i+1, k+1) )))/H(i, i);
303  }
304  }
305 
306  /*
307  The above for-cycle can be replaced by a triangular solver. One
308  needs to assure that the solver doesn't consider the
309  underdiagonal elements of the Hessenberg matrix and works only
310  with the first k rows and columns. for (int i = 0; i < k; ++i)
311  H(i+1, i) = 0;
312 
313  dusolve_gmres(H, c, z);
314  */
315 
316  x += prod(project(Q, ublas::range::all(), ublas::range(0, k)), project(c, ublas::range(0, k) ) );
317 
318  return k;
319 
320 }
321 
322 
330 template <class Matrix, class LinOp, class Vector, class Precond>
331 int gmres_restarts (LinOp const & A,
332  Vector & x,
333  const Vector & b,
334  Precond const & B,
335  unsigned int const maxiter,
336  unsigned int const nrestarts,
337  double const tol)
338 {
339  unsigned int i = 0;
340  unsigned int iter = 0;
341  bool converged = false;
342 
343  Vector resid( b.size() );
344  //verursacht Haenger. Warum, ist unklar.
345  A.residuum(x,b,resid);
346  //resid = prod(A,x) - b;
347  double z_0 = norm_2(resid);
348 
349  while (i <= nrestarts && ! converged) {
350  unsigned int ret = gmres_step< Matrix > (A, x, b, B, maxiter, tol);
351 // double nrmc= boost::numeric::ublas::norm_1 ( x);
352  A.residuum(x,b,resid);
353  double t = (norm_2(resid) / z_0);
354  converged = ( t < tol);
355  iter += ret;
356  ++i;
357  }
358 
359  return iter;
360 }
361 
370 template <class Matrix, class LinOp, class Vector, class Precond>
371 int gmres_short (LinOp const & A,
372  Vector & x,
373  const Vector & b,
374  Precond const & B,
375  int number,
376  int maxiter,
377  double tol)
378 {
379 
380  int size = A.image_size();
381 
382  Matrix Q(size, number+1); Q.clear();
383  Matrix P(size, number); P.clear();
384 
385  Vector v(size);
386  Vector v2(size);
387  Vector g(size);
388  Vector c(number+1);
389  Vector s(number+1);
390 
391  Vector sum(size);
392  Vector h(number + 1);
393 
394  A.residuum(x, b, v);
395  B.apply(v, g);
396 
397  column(Q, 0) = g/ublas::norm_2(g);
398 
399  double z_0 = ublas::norm_2(g);
400  double t = tol + 1;
401  int k = 0;
402 
403  double z_1 = z_0;
404  double z_2 = z_0;
405 
406  bool end = false;
407 
408  while (k < maxiter && !end){
409 
410  z_1 = z_2;
411  z_2 = 0;
412 
413  A.mult ( column(Q, k % (number + 1)), v );
414  B.apply(v, g);
415 
416  int lower = max<int>(0, k-number);
417 
418  for (int j = lower; j <= k; ++j) {
419  ublas::matrix_column<Matrix> q = column(Q, j % (number+1));
420  h(j % (number + 1)) = ublas::inner_prod(q, g);
421  g -= h(j % (number + 1))*q;
422  }
423 
424  for (int i = lower; i < k; ++i) {
425  double h_i = c((i+1) % (number + 1))*h(i % (number + 1)) + s((i+1) % (number + 1))*h((i+1) % (number + 1));
426  double h_i1 = s((i+1) % (number + 1))*h(i % (number + 1)) - c((i+1) % (number + 1))*h((i+1) % (number + 1));
427  h(i % (number + 1)) = h_i;
428  h((i+1) % (number + 1)) = h_i1;
429  }
430 
431  double h_k1 = ublas::norm_2(g);
432  column(Q, (k+1) % (number+1)) = g/h_k1;
433 
434  double h_kk = h(k % (number + 1));
435 
436  double alpha = sqrt(h_kk*h_kk + h_k1*h_k1);
437  s((k+1) % (number + 1)) = h_k1/alpha;
438  c((k+1) % (number + 1)) = h_kk/alpha;
439  h(k % (number + 1)) = alpha;
440 
441 
442  z_2 = s((k+1) % (number + 1))*z_1;
443  z_1 = c((k+1) % (number + 1))*z_1;
444 
445  sum = h(lower % (number + 1))*column(P, lower % number);
446  for (int i=lower+1; i < k; ++i){
447  sum += h(i % (number + 1))*column(P, i%number);
448  }
449 
450  column(P, k % number) = (column(Q, k % (number +1)) - sum)/h(k % (number + 1));
451 
452  x += z_1 * column(P, k % number);
453 
454  h((k+1) % (number + 1) ) = h_k1;
455 
456  t = sqrt((double)k+1) * (z_2/z_0);
457 
458  if (t < tol) {
459  end = true;
460  }
461 
462  ++k;
463 
464  // std::cout << k << " " << x << "\n";
465 
466  }
467 
468  return k;
469 }
470 
471 
472 
473 
474 #endif
void residuum(const VEC1 &x, const VEC2 &b, VEC3 &y) const
compute y <- b - Ax
Definition: lin_op.hpp:37
int gmres_short(LinOp const &A, Vector &x, const Vector &b, Precond const &B, int number, int maxiter, double tol)
/QGMRES. Only the last "number" vectors are taken into account, i.e. the orthogonalization depends on...
Definition: orthogonal.hpp:371
Vector arnoldi_step(std::vector< Vector > &q, Matrix &A, Matrix &H, int n)
preforms the orthogonalization of a given vector to a given basis using the arnoldi approach the basi...
Definition: orthogonal.hpp:78
unsigned int gmres_step(LinOp const &A, Vector &x, const Vector &b, Precond const &B, unsigned int const maxiter, double const tol)
a single step of the gmres algorithm, one iteration. Returns true if the approach converges...
Definition: orthogonal.hpp:199
a matrix based linear operator mapping a vector x (preimage) to a vector y (image).
Definition: lin_op.hpp:18
int gmres_restarts(LinOp const &A, Vector &x, const Vector &b, Precond const &B, unsigned int const maxiter, unsigned int const nrestarts, double const tol)
the gmres algorithm restarting after maxiter steps. nrestarts is the number of the allowed restarts ...
Definition: orthogonal.hpp:331
std::vector< Vector > orthogonal_system(std::vector< Vector > &basis)
returns the orthogonal system of a given set of vectors
Definition: orthogonal.hpp:39
void gmres(const Matrix &A, Vector &x, const Vector &b, double tol)
the standard gmres algorithm, without linear operator or any improvements
Definition: orthogonal.hpp:98
void mult(const VEC1 &x, VEC2 &y) const
compute y <- Ax
Definition: lin_op.hpp:31
Vector orthogonal_vector(std::vector< Vector > &basis, Vector &v)
preforms the orthogonalization of a given vector to a given basis using the arnoldi approach ...
Definition: orthogonal.hpp:63