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