00001
00011 #include <stdio.h>
00012 #include <math.h>
00013 #include "ilsi.h"
00014 #include "ilsi_vec.h"
00015
00016 class cgSolver {
00017 int n;
00018 const real *b;
00019 real *x_k;
00020 allocVector r_k;
00021 allocVector s_k;
00022 allocVector tmp;
00023 ILSI_Comm &comm;
00024 double residualMagSq;
00025
00026 public:
00027
00028 cgSolver(int n,real *x,const real *b,ILSI_Comm &comm_);
00029
00030
00031 real *getSolution(void) {
00032 return x_k;
00033 }
00034
00035
00036 double getResidual(void) const { return sqrt(residualMagSq); }
00037
00038
00039 void iterate(void);
00040 };
00041
00042 cgSolver::cgSolver(int n_,real *x_,const real *b_,ILSI_Comm &comm_)
00043 :n(n_), b(b_), x_k(x_), r_k(n), s_k(n), tmp(n), comm(comm_)
00044 {
00045 residualMagSq=1.0e20;
00046 comm.matrixVectorProduct(x_k, tmp);
00047 sub(n,r_k, b,tmp);
00048 residualMagSq=comm.dotProduct(r_k,r_k);
00049 copy(n,s_k, r_k);
00050 }
00051
00052
00053
00054 void cgSolver::iterate(void)
00055 {
00056
00057 comm.matrixVectorProduct(s_k,tmp);
00058 double s_kDot;
00059 s_kDot=comm.dotProduct(s_k,tmp);
00060 double alpha=residualMagSq/s_kDot;
00061
00062
00063 fma(n,x_k, x_k,alpha,s_k);
00064
00065
00066 double oldMagSq=residualMagSq;
00067 fma(n,r_k, r_k,-alpha,tmp);
00068 residualMagSq=comm.dotProduct(r_k,r_k);
00069
00070
00071
00072
00073
00074 double beta=residualMagSq/oldMagSq;
00075 fma(n,s_k, r_k,beta,s_k);
00076 }
00077
00078 CLINKAGE void ILSI_CG_Solver(ILSI_Param *param, ILSI_Comm *comm,
00079 int n, const real *b, real *x)
00080 {
00081 int maxIterations=1000000000;
00082 if (param->maxIterations>=1) maxIterations=(int)param->maxIterations;
00083 int nIterations=0;
00084 cgSolver cg(n,x,b,*comm);
00085 while (cg.getResidual()>param->maxResidual) {
00086 cg.iterate();
00087 nIterations++;
00088 if (nIterations>=maxIterations) break;
00089 }
00090 param->residual=cg.getResidual();
00091 param->iterations=nIterations;
00092 }
00093
00094
00095 FORTRAN_NAME_SOLVER(ILSI_CG_SOLVER,ILSI_CG_Solver,ilsi_cg_solver)
00096