00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #ifndef ITL_QMR_INCLUDE
00016 #define ITL_QMR_INCLUDE
00017
00018 #include <boost/numeric/mtl/concept/collection.hpp>
00019 #include <boost/numeric/mtl/operation/trans.hpp>
00020
00021 namespace itl {
00022
00023
00024
00025
00026 template < typename Matrix, typename Vector,typename LeftPreconditioner,
00027 typename RightPreconditioner, typename Iteration >
00028 int qmr(const Matrix& A, Vector& x, const Vector& b, LeftPreconditioner& L,
00029 const RightPreconditioner& R, Iteration& iter)
00030 {
00031
00032 typedef typename mtl::Collection<Vector>::value_type Scalar;
00033 typedef typename mtl::Collection<Vector>::size_type Size;
00034
00035 if (size(b) == 0) throw mtl::logic_error("empty rhs vector");
00036
00037 const Scalar zero= math::zero(b[0]), one= math::one(b[0]);
00038 Scalar rho_1, gamma(one), gamma_1, theta(zero), theta_1,
00039 eta(-one), delta, ep(one), beta;
00040 Size n(size(x));
00041 Vector r(b - A * x), v_tld(r), y(solve(L, v_tld)), w_tld(r), z(adjoint_solve(R,w_tld)), v(n),
00042 w(n), y_tld(n), z_tld, p, q, p_tld, d, s;
00043
00044 if (iter.finished(r))
00045 return iter;
00046
00047 Scalar rho = two_norm(y), xi = two_norm(z);
00048
00049 while(! iter.finished(rho)) {
00050
00051 if (rho == zero)
00052 return iter.fail(1, "qmr breakdown, rho=0 #1");
00053 if (xi == zero)
00054 return iter.fail(2, "qmr breakdown, xi=0 #2");
00055
00056 v= v_tld / rho;
00057 y/= rho;
00058 w= w_tld / xi;
00059 z/= xi;
00060
00061 delta = dot(z,y);
00062 if (delta == zero)
00063 return iter.fail(3, "qmr breakdown, delta=0 #3");
00064
00065 y_tld = solve(R,y);
00066 z_tld = adjoint_solve(L,z);
00067
00068 if (iter.first()) {
00069 p = y_tld;
00070 q = z_tld;
00071 } else {
00072 p = y_tld - ((xi * delta) / ep) * p;
00073 q = z_tld - ((rho* delta) / ep) * q;
00074 }
00075
00076 p_tld = A * p;
00077 ep = dot(q, p_tld);
00078 if (ep == zero)
00079 return iter.fail(4, "qmr breakdown ep=0 #4");
00080 beta= ep / delta;
00081 if (beta == zero)
00082 return iter.fail(5, "qmr breakdown beta=0 #5");
00083 v_tld = p_tld - beta * v;
00084 y = solve(L,v_tld);
00085 rho_1 = rho = two_norm(y);
00086 w_tld= trans(A)*q - beta*w;
00087 z = adjoint_solve(R, w_tld);
00088 xi = two_norm(z);
00089 gamma_1 = gamma;
00090 theta_1 = theta;
00091 theta = rho / (gamma_1 * beta);
00092 gamma = one / (sqrt(one + theta * theta));
00093
00094 if (gamma == zero)
00095 return iter.fail(6, "qmr breakdown gamma=0 #6");
00096
00097 eta= -eta * rho_1 * gamma * gamma / (beta * gamma_1 * gamma_1);
00098 if (iter.first()) {
00099 d= eta * p;
00100 s= eta * p_tld;
00101 } else {
00102 d= eta * p + (theta_1 * theta_1 * gamma * gamma) * d;
00103 s= eta * p_tld + (theta_1 * theta_1 * gamma * gamma) * s;
00104 }
00105 x += d;
00106 r -= s;
00107 ++iter;
00108 }
00109 return iter;
00110 }
00111 }
00112
00113 #endif // ITL_QMR_INCLUDE
00114