/* LA: linear algebra C++ interface library Copyright (C) 2008 Jiri Pittner or based on a routine originally written by Markus Warken This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef _GMRES_H #define _GMRES_H #include "vec.h" #include "smat.h" #include "mat.h" #include "sparsemat.h" #include "nonclass.h" #include #include "auxstorage.h" namespace LA { //GMRES solution of a linear system //matrix can be any class which has nrows(), ncols(), diagonalof() and gemv() available //does not even have to be explicitly stored /* GMRES-Algorithmus nach Schwarz, S. 552, original impl. M. Warken */ /* allows zeilen!= spalten*/ /* Matrix can be any class which provides nrows(), ncols(), gemv(), and diagonalof(), does not have to store elements explicitly */ template void gmres_backsubstitute(const NRMat &R, NRVec &c, const NRVec &d, const int k) { c.copyonwrite(); if(R(k,k)==0.) laerror("singular matrix in gmres triangular solution"); c[k] = d[k]/R(k,k); for (int i=k-1;i>=0;i--) c[i] = (d[i]-xdot(k-i,&R(i,i+1),1,&c[i+1],1)) / R(i,i); } //x contains ev. initial guess and on return the solution template bool gmres(const Matrix &bigmat, const NRVec &b, NRVec &x, const bool doguess=1, const double eps=1e-7, const int MAXIT=50, const bool verbose=1, bool square=1,const bool precondition=1, int neustart=0, const int incore=1) { int zeilen=bigmat.nrows(); int spalten=bigmat.ncols(); if(spalten==1) laerror("gmres does not work for n==1, use conjgrad if you need this trivial case"); if(x.size()!=spalten || b.size() != zeilen) laerror("incompatible vectors and matrix sizes in GMRES"); if(zeilen!=spalten) square=0; if(!neustart) neustart = zeilen/10; if (neustart < 10) neustart = 10; x.copyonwrite(); bool flag; double beta,beta_0; double d_alt=0; AuxStorage *st; NRVec *v; NRVec r_k(spalten),z(spalten); NRVec cci(MAXIT+1),ssi(MAXIT+1),c(MAXIT+1),d(MAXIT+1); NRMat H(MAXIT+1,MAXIT+1); T ci,si; v = new NRVec[incore?MAXIT+1:1]; st = incore?NULL:new AuxStorage; if(doguess) { bigmat.gemv(0,x,'t',-1.,b); //x.gemv(0,bigmat,'t',-1.,b); if(precondition) bigmat.diagonalof(x,true); x.normalize(); } neustart: for (int l=0;l dum(zeilen); bigmat.gemv(0,dum,'n',1,x); //dum.gemv(0,bigmat,'n',1,x); bigmat.gemv(0,r_k,'t',1,dum); //r_k.gemv(0,bigmat,'t',1,dum); bigmat.gemv(0,z,'t',-1.,b); //z.gemv(0,bigmat,'t',-1.,b); r_k += z; } if(precondition) bigmat.diagonalof(r_k,true); beta = r_k.norm(); if(l==0) beta_0 = beta; v[0] = r_k* (1./beta); if(!incore) st->put(v[0],0); // Iteration for (int k=0;k0) fprintf(stderr,"gmres: restart %d\n",l); // Schritt 1 if(!incore) st->get(v[0],k); if(square) { bigmat.gemv(0,z,'n',1,v[incore?k:0]); //z.gemv(0,bigmat,'n',1,v[incore?k:0]); } else { NRVec dum(zeilen); bigmat.gemv(0,dum,'n',1,v[incore?k:0]); //dum.gemv(0,bigmat,'n',1,v[incore?k:0]); bigmat.gemv(0,z,'t',1,dum); //z.gemv(0,bigmat,'t',1,dum); } if(precondition) bigmat.diagonalof(z,true); //Schritte 2 und 3 for (int i=0;i<=k;i++) { if(!incore) st->get(v[0],i); H(i,k) = z*v[incore?i:0]; z.axpy(-H(i,k),v[incore?i:0]); } //Schritt 4 double tmp; H(k+1,k) = tmp= z.norm(); if(tmp < 1.e-2*eps ) { if(verbose) std::cerr <<("gmres restart performed\n"); // Abbruchbedingung, konstruiere x_k for (int i=0;iget(v[0],i); x.axpy(c[i],v[incore?i:0]); } flag=0; goto neustart; } // Ende Abbruch v[incore?k+1:0] = z * (1./H(k+1,k)); if(!incore) st->put(v[0],k+1); // Schritt 5 - berechne Phi_k for (int j=0;jget(v[0],i); x.axpy(c[i],v[incore?i:0]); } flag=0; goto myreturn; } } // k-Schleife // zum Neustart: Konstruiere R_k for (int i=0;iget(v[0],i); x.axpy(c[i],v[incore?i:0]); } } // l schleife flag=1; myreturn: delete[] v; if(!incore) delete st; return !flag; } }//namespace #endif