Reference documentation for deal.II version 9.1.0-pre
solver_gmres.h
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1998 - 2018 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #ifndef dealii_solver_gmres_h
17 #define dealii_solver_gmres_h
18 
19 
20 
21 #include <deal.II/base/config.h>
22 
23 #include <deal.II/base/logstream.h>
24 #include <deal.II/base/std_cxx14/memory.h>
25 #include <deal.II/base/subscriptor.h>
26 
27 #include <deal.II/lac/full_matrix.h>
28 #include <deal.II/lac/householder.h>
29 #include <deal.II/lac/lapack_full_matrix.h>
30 #include <deal.II/lac/solver.h>
31 #include <deal.II/lac/solver_control.h>
32 #include <deal.II/lac/vector.h>
33 
34 #include <algorithm>
35 #include <cmath>
36 #include <vector>
37 
38 DEAL_II_NAMESPACE_OPEN
39 
42 
43 namespace internal
44 {
48  namespace SolverGMRESImplementation
49  {
58  template <typename VectorType>
59  class TmpVectors
60  {
61  public:
66  TmpVectors(const unsigned int max_size, VectorMemory<VectorType> &vmem);
67 
71  ~TmpVectors() = default;
72 
77  VectorType &operator[](const unsigned int i) const;
78 
85  VectorType &
86  operator()(const unsigned int i, const VectorType &temp);
87 
92  unsigned int
93  size() const;
94 
95 
96  private:
101 
105  std::vector<typename VectorMemory<VectorType>::Pointer> data;
106  };
107  } // namespace SolverGMRESImplementation
108 } // namespace internal
109 
177 template <class VectorType = Vector<double>>
178 class SolverGMRES : public Solver<VectorType>
179 {
180 public:
185  {
192  explicit AdditionalData(const unsigned int max_n_tmp_vectors = 30,
193  const bool right_preconditioning = false,
194  const bool use_default_residual = true,
195  const bool force_re_orthogonalization = false);
196 
203  unsigned int max_n_tmp_vectors;
204 
213 
218 
226  };
227 
233  const AdditionalData & data = AdditionalData());
234 
240 
244  template <typename MatrixType, typename PreconditionerType>
245  void
246  solve(const MatrixType & A,
247  VectorType & x,
248  const VectorType & b,
249  const PreconditionerType &preconditioner);
250 
257  boost::signals2::connection
258  connect_condition_number_slot(const std::function<void(double)> &slot,
259  const bool every_iteration = false);
260 
267  boost::signals2::connection
268  connect_eigenvalues_slot(
269  const std::function<void(const std::vector<std::complex<double>> &)> &slot,
270  const bool every_iteration = false);
271 
279  boost::signals2::connection
280  connect_hessenberg_slot(
281  const std::function<void(const FullMatrix<double> &)> &slot,
282  const bool every_iteration = true);
283 
290  boost::signals2::connection
291  connect_krylov_space_slot(
292  const std::function<
294  &slot);
295 
296 
301  boost::signals2::connection
302  connect_re_orthogonalization_slot(const std::function<void(int)> &slot);
303 
304 
305  DeclException1(ExcTooFewTmpVectors,
306  int,
307  << "The number of temporary vectors you gave (" << arg1
308  << ") is too small. It should be at least 10 for "
309  << "any results, and much more for reasonable ones.");
310 
311 protected:
316 
321  boost::signals2::signal<void(double)> condition_number_signal;
322 
327  boost::signals2::signal<void(double)> all_condition_numbers_signal;
328 
333  boost::signals2::signal<void(const std::vector<std::complex<double>> &)>
334  eigenvalues_signal;
335 
340  boost::signals2::signal<void(const std::vector<std::complex<double>> &)>
341  all_eigenvalues_signal;
342 
347  boost::signals2::signal<void(const FullMatrix<double> &)> hessenberg_signal;
348 
353  boost::signals2::signal<void(const FullMatrix<double> &)>
354  all_hessenberg_signal;
355 
360  boost::signals2::signal<void(
363 
368  boost::signals2::signal<void(int)> re_orthogonalize_signal;
369 
373  virtual double
374  criterion();
375 
380  void
381  givens_rotation(Vector<double> &h,
382  Vector<double> &b,
383  Vector<double> &ci,
384  Vector<double> &si,
385  int col) const;
386 
397  static double
398  modified_gram_schmidt(
400  & orthogonal_vectors,
401  const unsigned int dim,
402  const unsigned int accumulated_iterations,
403  VectorType & vv,
404  Vector<double> & h,
405  bool & re_orthogonalize,
406  const boost::signals2::signal<void(int)> &re_orthogonalize_signal =
407  boost::signals2::signal<void(int)>());
408 
415  static void
416  compute_eigs_and_cond(
417  const FullMatrix<double> &H_orig,
418  const unsigned int dim,
419  const boost::signals2::signal<
420  void(const std::vector<std::complex<double>> &)> &eigenvalues_signal,
421  const boost::signals2::signal<void(const FullMatrix<double> &)>
422  & hessenberg_signal,
423  const boost::signals2::signal<void(double)> &cond_signal);
424 
429 
434 
435 
436 private:
441 };
442 
464 template <class VectorType = Vector<double>>
465 class SolverFGMRES : public Solver<VectorType>
466 {
467 public:
472  {
476  explicit AdditionalData(const unsigned int max_basis_size = 30,
477  const bool /*use_default_residual*/ = true)
478  : max_basis_size(max_basis_size)
479  {}
480 
484  unsigned int max_basis_size;
485  };
486 
492  const AdditionalData & data = AdditionalData());
493 
499  const AdditionalData &data = AdditionalData());
500 
504  template <typename MatrixType, typename PreconditionerType>
505  void
506  solve(const MatrixType & A,
507  VectorType & x,
508  const VectorType & b,
509  const PreconditionerType &preconditioner);
510 
511 private:
516 
521 
526 };
527 
529 /* --------------------- Inline and template functions ------------------- */
530 
531 
532 #ifndef DOXYGEN
533 namespace internal
534 {
535  namespace SolverGMRESImplementation
536  {
537  template <class VectorType>
538  inline TmpVectors<VectorType>::TmpVectors(const unsigned int max_size,
540  : mem(vmem)
541  , data(max_size)
542  {}
543 
544 
545 
546  template <class VectorType>
547  inline VectorType &TmpVectors<VectorType>::
548  operator[](const unsigned int i) const
549  {
550  Assert(i < data.size(), ExcIndexRange(i, 0, data.size()));
551 
552  Assert(data[i] != nullptr, ExcNotInitialized());
553  return *data[i];
554  }
555 
556 
557 
558  template <class VectorType>
559  inline VectorType &
560  TmpVectors<VectorType>::operator()(const unsigned int i,
561  const VectorType & temp)
562  {
563  Assert(i < data.size(), ExcIndexRange(i, 0, data.size()));
564  if (data[i] == nullptr)
565  {
566  data[i] = std::move(typename VectorMemory<VectorType>::Pointer(mem));
567  data[i]->reinit(temp);
568  }
569  return *data[i];
570  }
571 
572 
573 
574  template <class VectorType>
575  unsigned int
577  {
578  return (data.size() > 0 ? data.size() - 1 : 0);
579  }
580 
581 
582 
583  // A comparator for better printing eigenvalues
584  inline bool
585  complex_less_pred(const std::complex<double> &x,
586  const std::complex<double> &y)
587  {
588  return x.real() < y.real() ||
589  (x.real() == y.real() && x.imag() < y.imag());
590  }
591  } // namespace SolverGMRESImplementation
592 } // namespace internal
593 
594 
595 
596 template <class VectorType>
598  const unsigned int max_n_tmp_vectors,
599  const bool right_preconditioning,
600  const bool use_default_residual,
601  const bool force_re_orthogonalization)
602  : max_n_tmp_vectors(max_n_tmp_vectors)
603  , right_preconditioning(right_preconditioning)
604  , use_default_residual(use_default_residual)
605  , force_re_orthogonalization(force_re_orthogonalization)
606 {
607  Assert(3 <= max_n_tmp_vectors,
608  ExcMessage("SolverGMRES needs at least three "
609  "temporary vectors."));
610 }
611 
612 
613 
614 template <class VectorType>
617  const AdditionalData & data)
618  : Solver<VectorType>(cn, mem)
619  , additional_data(data)
620 {}
621 
622 
623 
624 template <class VectorType>
626  const AdditionalData &data)
627  : Solver<VectorType>(cn)
628  , additional_data(data)
629 {}
630 
631 
632 
633 template <class VectorType>
634 inline void
636  Vector<double> &b,
637  Vector<double> &ci,
638  Vector<double> &si,
639  int col) const
640 {
641  for (int i = 0; i < col; i++)
642  {
643  const double s = si(i);
644  const double c = ci(i);
645  const double dummy = h(i);
646  h(i) = c * dummy + s * h(i + 1);
647  h(i + 1) = -s * dummy + c * h(i + 1);
648  };
649 
650  const double r = 1. / std::sqrt(h(col) * h(col) + h(col + 1) * h(col + 1));
651  si(col) = h(col + 1) * r;
652  ci(col) = h(col) * r;
653  h(col) = ci(col) * h(col) + si(col) * h(col + 1);
654  b(col + 1) = -si(col) * b(col);
655  b(col) *= ci(col);
656 }
657 
658 
659 
660 template <class VectorType>
661 inline double
664  & orthogonal_vectors,
665  const unsigned int dim,
666  const unsigned int accumulated_iterations,
667  VectorType & vv,
668  Vector<double> & h,
669  bool & reorthogonalize,
670  const boost::signals2::signal<void(int)> &reorthogonalize_signal)
671 {
672  Assert(dim > 0, ExcInternalError());
673  const unsigned int inner_iteration = dim - 1;
674 
675  // need initial norm for detection of re-orthogonalization, see below
676  double norm_vv_start = 0;
677  const bool consider_reorthogonalize =
678  (reorthogonalize == false) && (inner_iteration % 5 == 4);
679  if (consider_reorthogonalize)
680  norm_vv_start = vv.l2_norm();
681 
682  // Orthogonalization
683  h(0) = vv * orthogonal_vectors[0];
684  for (unsigned int i = 1; i < dim; ++i)
685  h(i) = vv.add_and_dot(-h(i - 1),
686  orthogonal_vectors[i - 1],
687  orthogonal_vectors[i]);
688  double norm_vv =
689  std::sqrt(vv.add_and_dot(-h(dim - 1), orthogonal_vectors[dim - 1], vv));
690 
691  // Re-orthogonalization if loss of orthogonality detected. For the test, use
692  // a strategy discussed in C. T. Kelley, Iterative Methods for Linear and
693  // Nonlinear Equations, SIAM, Philadelphia, 1995: Compare the norm of vv
694  // after orthogonalization with its norm when starting the
695  // orthogonalization. If vv became very small (here: less than the square
696  // root of the machine precision times 10), it is almost in the span of the
697  // previous vectors, which indicates loss of precision.
698  if (consider_reorthogonalize)
699  {
700  if (norm_vv >
701  10. * norm_vv_start *
702  std::sqrt(
703  std::numeric_limits<typename VectorType::value_type>::epsilon()))
704  return norm_vv;
705 
706  else
707  {
708  reorthogonalize = true;
709  if (!reorthogonalize_signal.empty())
710  reorthogonalize_signal(accumulated_iterations);
711  }
712  }
713 
714  if (reorthogonalize == true)
715  {
716  double htmp = vv * orthogonal_vectors[0];
717  h(0) += htmp;
718  for (unsigned int i = 1; i < dim; ++i)
719  {
720  htmp = vv.add_and_dot(-htmp,
721  orthogonal_vectors[i - 1],
722  orthogonal_vectors[i]);
723  h(i) += htmp;
724  }
725  norm_vv =
726  std::sqrt(vv.add_and_dot(-htmp, orthogonal_vectors[dim - 1], vv));
727  }
728 
729  return norm_vv;
730 }
731 
732 
733 
734 template <class VectorType>
735 inline void
737  const FullMatrix<double> &H_orig,
738  const unsigned int dim,
739  const boost::signals2::signal<void(const std::vector<std::complex<double>> &)>
740  &eigenvalues_signal,
741  const boost::signals2::signal<void(const FullMatrix<double> &)>
742  & hessenberg_signal,
743  const boost::signals2::signal<void(double)> &cond_signal)
744 {
745  // Avoid copying the Hessenberg matrix if it isn't needed.
746  if ((!eigenvalues_signal.empty() || !hessenberg_signal.empty() ||
747  !cond_signal.empty()) &&
748  dim > 0)
749  {
750  LAPACKFullMatrix<double> mat(dim, dim);
751  for (unsigned int i = 0; i < dim; ++i)
752  for (unsigned int j = 0; j < dim; ++j)
753  mat(i, j) = H_orig(i, j);
754  hessenberg_signal(H_orig);
755  // Avoid computing eigenvalues if they are not needed.
756  if (!eigenvalues_signal.empty())
757  {
758  // Copy mat so that we can compute svd below. Necessary since
759  // compute_eigenvalues will leave mat in state
760  // LAPACKSupport::unusable.
761  LAPACKFullMatrix<double> mat_eig(mat);
762  mat_eig.compute_eigenvalues();
763  std::vector<std::complex<double>> eigenvalues(dim);
764  for (unsigned int i = 0; i < mat_eig.n(); ++i)
765  eigenvalues[i] = mat_eig.eigenvalue(i);
766  // Sort eigenvalues for nicer output.
767  std::sort(eigenvalues.begin(),
768  eigenvalues.end(),
769  internal::SolverGMRESImplementation::complex_less_pred);
770  eigenvalues_signal(eigenvalues);
771  }
772  // Calculate condition number, avoid calculating the svd if a slot
773  // isn't connected. Need at least a 2-by-2 matrix to do the estimate.
774  if (!cond_signal.empty() && (mat.n() > 1))
775  {
776  mat.compute_svd();
777  double condition_number =
778  mat.singular_value(0) / mat.singular_value(mat.n() - 1);
779  cond_signal(condition_number);
780  }
781  }
782 }
783 
784 
785 
786 template <class VectorType>
787 template <typename MatrixType, typename PreconditionerType>
788 void
789 SolverGMRES<VectorType>::solve(const MatrixType & A,
790  VectorType & x,
791  const VectorType & b,
792  const PreconditionerType &preconditioner)
793 {
794  // TODO:[?] Check, why there are two different start residuals.
795  // TODO:[GK] Make sure the parameter in the constructor means maximum basis
796  // size
797 
798  LogStream::Prefix prefix("GMRES");
799 
800  // extra call to std::max to placate static analyzers: coverity rightfully
801  // complains that data.max_n_tmp_vectors - 2 may overflow
802  const unsigned int n_tmp_vectors =
803  std::max(additional_data.max_n_tmp_vectors, 3u);
804 
805  // Generate an object where basis vectors are stored.
807  n_tmp_vectors, this->memory);
808 
809  // number of the present iteration; this
810  // number is not reset to zero upon a
811  // restart
812  unsigned int accumulated_iterations = 0;
813 
814  const bool do_eigenvalues =
815  !condition_number_signal.empty() || !all_condition_numbers_signal.empty() ||
816  !eigenvalues_signal.empty() || !all_eigenvalues_signal.empty() ||
817  !hessenberg_signal.empty() || !all_hessenberg_signal.empty();
818  // for eigenvalue computation, need to collect the Hessenberg matrix (before
819  // applying Givens rotations)
820  FullMatrix<double> H_orig;
821  if (do_eigenvalues)
822  H_orig.reinit(n_tmp_vectors, n_tmp_vectors - 1);
823 
824  // matrix used for the orthogonalization process later
825  H.reinit(n_tmp_vectors, n_tmp_vectors - 1);
826 
827  // some additional vectors, also used in the orthogonalization
828  ::Vector<double> gamma(n_tmp_vectors), ci(n_tmp_vectors - 1),
829  si(n_tmp_vectors - 1), h(n_tmp_vectors - 1);
830 
831 
832  unsigned int dim = 0;
833 
835  double last_res = -std::numeric_limits<double>::max();
836 
837  // switch to determine whether we want a left or a right preconditioner. at
838  // present, left is default, but both ways are implemented
839  const bool left_precondition = !additional_data.right_preconditioning;
840 
841  // Per default the left preconditioned GMRes uses the preconditioned
842  // residual and the right preconditioned GMRes uses the unpreconditioned
843  // residual as stopping criterion.
844  const bool use_default_residual = additional_data.use_default_residual;
845 
846  // define two aliases
847  VectorType &v = tmp_vectors(0, x);
848  VectorType &p = tmp_vectors(n_tmp_vectors - 1, x);
849 
850  // Following vectors are needed when we are not using the default residuals
851  // as stopping criterion
854  std::unique_ptr<::Vector<double>> gamma_;
855  if (!use_default_residual)
856  {
857  r = std::move(typename VectorMemory<VectorType>::Pointer(this->memory));
858  x_ = std::move(typename VectorMemory<VectorType>::Pointer(this->memory));
859  r->reinit(x);
860  x_->reinit(x);
861 
862  gamma_ = std_cxx14::make_unique<::Vector<double>>(gamma.size());
863  }
864 
865  bool re_orthogonalize = additional_data.force_re_orthogonalization;
866 
868  // outer iteration: loop until we either reach convergence or the maximum
869  // number of iterations is exceeded. each cycle of this loop amounts to one
870  // restart
871  do
872  {
873  // reset this vector to the right size
874  h.reinit(n_tmp_vectors - 1);
875 
876  if (left_precondition)
877  {
878  A.vmult(p, x);
879  p.sadd(-1., 1., b);
880  preconditioner.vmult(v, p);
881  }
882  else
883  {
884  A.vmult(v, x);
885  v.sadd(-1., 1., b);
886  };
887 
888  double rho = v.l2_norm();
889 
890  // check the residual here as well since it may be that we got the exact
891  // (or an almost exact) solution vector at the outset. if we wouldn't
892  // check here, the next scaling operation would produce garbage
893  if (use_default_residual)
894  {
895  last_res = rho;
896  iteration_state =
897  this->iteration_status(accumulated_iterations, rho, x);
898 
899  if (iteration_state != SolverControl::iterate)
900  break;
901  }
902  else
903  {
904  deallog << "default_res=" << rho << std::endl;
905 
906  if (left_precondition)
907  {
908  A.vmult(*r, x);
909  r->sadd(-1., 1., b);
910  }
911  else
912  preconditioner.vmult(*r, v);
913 
914  double res = r->l2_norm();
915  last_res = res;
916  iteration_state =
917  this->iteration_status(accumulated_iterations, res, x);
918 
919  if (iteration_state != SolverControl::iterate)
920  break;
921  }
922 
923  gamma(0) = rho;
924 
925  v *= 1. / rho;
926 
927  // inner iteration doing at most as many steps as there are temporary
928  // vectors. the number of steps actually been done is propagated outside
929  // through the @p dim variable
930  for (unsigned int inner_iteration = 0;
931  ((inner_iteration < n_tmp_vectors - 2) &&
932  (iteration_state == SolverControl::iterate));
933  ++inner_iteration)
934  {
935  ++accumulated_iterations;
936  // yet another alias
937  VectorType &vv = tmp_vectors(inner_iteration + 1, x);
938 
939  if (left_precondition)
940  {
941  A.vmult(p, tmp_vectors[inner_iteration]);
942  preconditioner.vmult(vv, p);
943  }
944  else
945  {
946  preconditioner.vmult(p, tmp_vectors[inner_iteration]);
947  A.vmult(vv, p);
948  }
949 
950  dim = inner_iteration + 1;
951 
952  const double s = modified_gram_schmidt(tmp_vectors,
953  dim,
954  accumulated_iterations,
955  vv,
956  h,
957  re_orthogonalize,
958  re_orthogonalize_signal);
959  h(inner_iteration + 1) = s;
960 
961  // s=0 is a lucky breakdown, the solver will reach convergence,
962  // but we must not divide by zero here.
963  if (s != 0)
964  vv *= 1. / s;
965 
966  // for eigenvalues, get the resulting coefficients from the
967  // orthogonalization process
968  if (do_eigenvalues)
969  for (unsigned int i = 0; i < dim + 1; ++i)
970  H_orig(i, inner_iteration) = h(i);
971 
972  // Transformation into tridiagonal structure
973  givens_rotation(h, gamma, ci, si, inner_iteration);
974 
975  // append vector on matrix
976  for (unsigned int i = 0; i < dim; ++i)
977  H(i, inner_iteration) = h(i);
978 
979  // default residual
980  rho = std::fabs(gamma(dim));
981 
982  if (use_default_residual)
983  {
984  last_res = rho;
985  iteration_state =
986  this->iteration_status(accumulated_iterations, rho, x);
987  }
988  else
989  {
990  deallog << "default_res=" << rho << std::endl;
991 
992  ::Vector<double> h_(dim);
993  *x_ = x;
994  *gamma_ = gamma;
995  H1.reinit(dim + 1, dim);
996 
997  for (unsigned int i = 0; i < dim + 1; ++i)
998  for (unsigned int j = 0; j < dim; ++j)
999  H1(i, j) = H(i, j);
1000 
1001  H1.backward(h_, *gamma_);
1002 
1003  if (left_precondition)
1004  for (unsigned int i = 0; i < dim; ++i)
1005  x_->add(h_(i), tmp_vectors[i]);
1006  else
1007  {
1008  p = 0.;
1009  for (unsigned int i = 0; i < dim; ++i)
1010  p.add(h_(i), tmp_vectors[i]);
1011  preconditioner.vmult(*r, p);
1012  x_->add(1., *r);
1013  };
1014  A.vmult(*r, *x_);
1015  r->sadd(-1., 1., b);
1016  // Now *r contains the unpreconditioned residual!!
1017  if (left_precondition)
1018  {
1019  const double res = r->l2_norm();
1020  last_res = res;
1021 
1022  iteration_state =
1023  this->iteration_status(accumulated_iterations, res, x);
1024  }
1025  else
1026  {
1027  preconditioner.vmult(*x_, *r);
1028  const double preconditioned_res = x_->l2_norm();
1029  last_res = preconditioned_res;
1030 
1031  iteration_state =
1032  this->iteration_status(accumulated_iterations,
1033  preconditioned_res,
1034  x);
1035  }
1036  }
1037  };
1038  // end of inner iteration. now calculate the solution from the temporary
1039  // vectors
1040  h.reinit(dim);
1041  H1.reinit(dim + 1, dim);
1042 
1043  for (unsigned int i = 0; i < dim + 1; ++i)
1044  for (unsigned int j = 0; j < dim; ++j)
1045  H1(i, j) = H(i, j);
1046 
1047  compute_eigs_and_cond(H_orig,
1048  dim,
1049  all_eigenvalues_signal,
1050  all_hessenberg_signal,
1051  condition_number_signal);
1052 
1053  H1.backward(h, gamma);
1054 
1055  if (left_precondition)
1056  for (unsigned int i = 0; i < dim; ++i)
1057  x.add(h(i), tmp_vectors[i]);
1058  else
1059  {
1060  p = 0.;
1061  for (unsigned int i = 0; i < dim; ++i)
1062  p.add(h(i), tmp_vectors[i]);
1063  preconditioner.vmult(v, p);
1064  x.add(1., v);
1065  };
1066  // end of outer iteration. restart if no convergence and the number of
1067  // iterations is not exceeded
1068  }
1069  while (iteration_state == SolverControl::iterate);
1070 
1071  compute_eigs_and_cond(H_orig,
1072  dim,
1073  eigenvalues_signal,
1074  hessenberg_signal,
1075  condition_number_signal);
1076 
1077  if (!krylov_space_signal.empty())
1078  krylov_space_signal(tmp_vectors);
1079 
1080  // in case of failure: throw exception
1081  AssertThrow(iteration_state == SolverControl::success,
1082  SolverControl::NoConvergence(accumulated_iterations, last_res));
1083 }
1084 
1085 
1086 
1087 template <class VectorType>
1088 boost::signals2::connection
1090  const std::function<void(double)> &slot,
1091  const bool every_iteration)
1092 {
1093  if (every_iteration)
1094  {
1095  return all_condition_numbers_signal.connect(slot);
1096  }
1097  else
1098  {
1099  return condition_number_signal.connect(slot);
1100  }
1101 }
1102 
1103 
1104 
1105 template <class VectorType>
1106 boost::signals2::connection
1108  const std::function<void(const std::vector<std::complex<double>> &)> &slot,
1109  const bool every_iteration)
1110 {
1111  if (every_iteration)
1112  {
1113  return all_eigenvalues_signal.connect(slot);
1114  }
1115  else
1116  {
1117  return eigenvalues_signal.connect(slot);
1118  }
1119 }
1120 
1121 
1122 
1123 template <class VectorType>
1124 boost::signals2::connection
1126  const std::function<void(const FullMatrix<double> &)> &slot,
1127  const bool every_iteration)
1128 {
1129  if (every_iteration)
1130  {
1131  return all_hessenberg_signal.connect(slot);
1132  }
1133  else
1134  {
1135  return hessenberg_signal.connect(slot);
1136  }
1137 }
1138 
1139 
1140 
1141 template <class VectorType>
1142 boost::signals2::connection
1144  const std::function<void(
1146 {
1147  return krylov_space_signal.connect(slot);
1148 }
1149 
1150 
1151 
1152 template <class VectorType>
1153 boost::signals2::connection
1155  const std::function<void(int)> &slot)
1156 {
1157  return re_orthogonalize_signal.connect(slot);
1158 }
1159 
1160 
1161 
1162 template <class VectorType>
1163 double
1165 {
1166  // dummy implementation. this function is not needed for the present
1167  // implementation of gmres
1168  Assert(false, ExcInternalError());
1169  return 0;
1170 }
1171 
1172 
1173 //----------------------------------------------------------------------//
1174 
1175 template <class VectorType>
1178  const AdditionalData & data)
1179  : Solver<VectorType>(cn, mem)
1180  , additional_data(data)
1181 {}
1182 
1183 
1184 
1185 template <class VectorType>
1187  const AdditionalData &data)
1188  : Solver<VectorType>(cn)
1189  , additional_data(data)
1190 {}
1191 
1192 
1193 
1194 template <class VectorType>
1195 template <typename MatrixType, typename PreconditionerType>
1196 void
1197 SolverFGMRES<VectorType>::solve(const MatrixType & A,
1198  VectorType & x,
1199  const VectorType & b,
1200  const PreconditionerType &preconditioner)
1201 {
1202  LogStream::Prefix prefix("FGMRES");
1203 
1204  SolverControl::State iteration_state = SolverControl::iterate;
1205 
1206  const unsigned int basis_size = additional_data.max_basis_size;
1207 
1208  // Generate an object where basis vectors are stored.
1210  basis_size, this->memory);
1212  basis_size, this->memory);
1213 
1214  // number of the present iteration; this number is not reset to zero upon a
1215  // restart
1216  unsigned int accumulated_iterations = 0;
1217 
1218  // matrix used for the orthogonalization process later
1219  H.reinit(basis_size + 1, basis_size);
1220 
1221  // Vectors for projected system
1222  Vector<double> projected_rhs;
1223  Vector<double> y;
1224 
1225  // Iteration starts here
1226  double res = -std::numeric_limits<double>::max();
1227 
1228  typename VectorMemory<VectorType>::Pointer aux(this->memory);
1229  aux->reinit(x);
1230  do
1231  {
1232  A.vmult(*aux, x);
1233  aux->sadd(-1., 1., b);
1234 
1235  double beta = aux->l2_norm();
1236  res = beta;
1237  iteration_state = this->iteration_status(accumulated_iterations, res, x);
1238  if (iteration_state == SolverControl::success)
1239  break;
1240 
1241  H.reinit(basis_size + 1, basis_size);
1242  double a = beta;
1243 
1244  for (unsigned int j = 0; j < basis_size; ++j)
1245  {
1246  if (a != 0) // treat lucky breakdown
1247  v(j, x).equ(1. / a, *aux);
1248  else
1249  v(j, x) = 0.;
1250 
1251 
1252  preconditioner.vmult(z(j, x), v[j]);
1253  A.vmult(*aux, z[j]);
1254 
1255  // Gram-Schmidt
1256  H(0, j) = *aux * v[0];
1257  for (unsigned int i = 1; i <= j; ++i)
1258  H(i, j) = aux->add_and_dot(-H(i - 1, j), v[i - 1], v[i]);
1259  H(j + 1, j) = a = std::sqrt(aux->add_and_dot(-H(j, j), v[j], *aux));
1260 
1261  // Compute projected solution
1262 
1263  if (j > 0)
1264  {
1265  H1.reinit(j + 1, j);
1266  projected_rhs.reinit(j + 1);
1267  y.reinit(j);
1268  projected_rhs(0) = beta;
1269  H1.fill(H);
1270 
1271  // check convergence. note that the vector 'x' we pass to the
1272  // criterion is not the final solution we compute if we
1273  // decide to jump out of the iteration (we update 'x' again
1274  // right after the current loop)
1275  Householder<double> house(H1);
1276  res = house.least_squares(y, projected_rhs);
1277  iteration_state =
1278  this->iteration_status(++accumulated_iterations, res, x);
1279  if (iteration_state != SolverControl::iterate)
1280  break;
1281  }
1282  }
1283 
1284  // Update solution vector
1285  for (unsigned int j = 0; j < y.size(); ++j)
1286  x.add(y(j), z[j]);
1287  }
1288  while (iteration_state == SolverControl::iterate);
1289 
1290  // in case of failure: throw exception
1291  if (iteration_state != SolverControl::success)
1292  AssertThrow(false,
1293  SolverControl::NoConvergence(accumulated_iterations, res));
1294 }
1295 
1296 #endif // DOXYGEN
1297 
1298 DEAL_II_NAMESPACE_CLOSE
1299 
1300 #endif
SolverFGMRES(SolverControl &cn, VectorMemory< VectorType > &mem, const AdditionalData &data=AdditionalData())
Number add_and_dot(const Number a, const Vector< Number > &V, const Vector< Number > &W)
size_type n() const
TmpVectors(const unsigned int max_size, VectorMemory< VectorType > &vmem)
number singular_value(const size_type i) const
boost::signals2::connection connect_condition_number_slot(const std::function< void(double)> &slot, const bool every_iteration=false)
Continue iteration.
std::array< Number, 1 > eigenvalues(const SymmetricTensor< 2, 1, Number > &T)
boost::signals2::signal< void(const internal::SolverGMRESImplementation::TmpVectors< VectorType > &)> krylov_space_signal
Definition: solver_gmres.h:362
size_type size() const
void solve(const MatrixType &A, VectorType &x, const VectorType &b, const PreconditionerType &preconditioner)
boost::signals2::connection connect_re_orthogonalization_slot(const std::function< void(int)> &slot)
FullMatrix< double > H1
Definition: solver_gmres.h:525
boost::signals2::signal< void(double)> condition_number_signal
Definition: solver_gmres.h:321
AdditionalData additional_data
Definition: solver_gmres.h:315
static::ExceptionBase & ExcNotInitialized()
std::vector< typename VectorMemory< VectorType >::Pointer > data
Definition: solver_gmres.h:105
#define AssertThrow(cond, exc)
Definition: exceptions.h:1329
static::ExceptionBase & ExcIndexRange(int arg1, int arg2, int arg3)
AdditionalData additional_data
Definition: solver_gmres.h:515
FullMatrix< double > H1
Definition: solver_gmres.h:433
VectorType & operator()(const unsigned int i, const VectorType &temp)
boost::signals2::signal< void(int)> re_orthogonalize_signal
Definition: solver_gmres.h:368
FullMatrix< double > H
Definition: solver_gmres.h:428
void solve(const MatrixType &A, VectorType &x, const VectorType &b, const PreconditionerType &preconditioner)
static::ExceptionBase & ExcMessage(std::string arg1)
VectorType & operator[](const unsigned int i) const
AdditionalData(const unsigned int max_n_tmp_vectors=30, const bool right_preconditioning=false, const bool use_default_residual=true, const bool force_re_orthogonalization=false)
#define DeclException1(Exception1, type1, outsequence)
Definition: exceptions.h:408
Stop iteration, goal reached.
void reinit(const TableIndices< N > &new_size, const bool omit_default_initialization=false)
#define Assert(cond, exc)
Definition: exceptions.h:1227
boost::signals2::connection connect_krylov_space_slot(const std::function< void(const internal::SolverGMRESImplementation::TmpVectors< VectorType > &)> &slot)
static double modified_gram_schmidt(const internal::SolverGMRESImplementation::TmpVectors< VectorType > &orthogonal_vectors, const unsigned int dim, const unsigned int accumulated_iterations, VectorType &vv, Vector< double > &h, bool &re_orthogonalize, const boost::signals2::signal< void(int)> &re_orthogonalize_signal=boost::signals2::signal< void(int)>())
void givens_rotation(Vector< double > &h, Vector< double > &b, Vector< double > &ci, Vector< double > &si, int col) const
Definition: solver.h:328
virtual double criterion()
virtual void reinit(const size_type N, const bool omit_zeroing_entries=false)
void compute_eigenvalues(const bool right_eigenvectors=false, const bool left_eigenvectors=false)
std::complex< number > eigenvalue(const size_type i) const
double least_squares(Vector< number2 > &dst, const Vector< number2 > &src) const
boost::signals2::connection connect_hessenberg_slot(const std::function< void(const FullMatrix< double > &)> &slot, const bool every_iteration=true)
FullMatrix< double > H
Definition: solver_gmres.h:520
AdditionalData(const unsigned int max_basis_size=30, const bool=true)
Definition: solver_gmres.h:476
SolverGMRES(SolverControl &cn, VectorMemory< VectorType > &mem, const AdditionalData &data=AdditionalData())
boost::signals2::connection connect_eigenvalues_slot(const std::function< void(const std::vector< std::complex< double >> &)> &slot, const bool every_iteration=false)
static void compute_eigs_and_cond(const FullMatrix< double > &H_orig, const unsigned int dim, const boost::signals2::signal< void(const std::vector< std::complex< double >> &)> &eigenvalues_signal, const boost::signals2::signal< void(const FullMatrix< double > &)> &hessenberg_signal, const boost::signals2::signal< void(double)> &cond_signal)
boost::signals2::signal< void(double)> all_condition_numbers_signal
Definition: solver_gmres.h:327
static::ExceptionBase & ExcInternalError()