⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 matvec.h

📁 C++ source code for book-C++ and Object Oriented Numeric computing for scientists and engineers
💻 H
📖 第 1 页 / 共 4 页
字号:
    }
  } 
  return nm;
}

template<class T> T Vcr<T>::maxnorm() const {
  T nm = abs(vr[0]);
  for (int i = 1; i < lenth; i++) {
    T vi = abs(vr[i]);
    if (nm < vi) nm = vi;
  }
  return nm;
}

template<class T> 
Vcr<T> operator*(T scalar, const Vcr<T> & vec) {
  Vcr<T> tm(vec.lenth);
  for (int i = 0; i < vec.lenth; i++) tm[i] = scalar*vec[i]; 
  return tm;
}

template<class T> 
Vcr<T> operator*(const Vcr<T>& vec, T scalar) {
  Vcr<T> tm(vec.lenth);
  for (int i = 0; i < vec.lenth; i++) tm[i] = scalar*vec[i]; 
  return tm;
}

template<class T> 
Vcr<T> operator*(const Vcr<T> & vec1, const Vcr<T> & vec2) {
  if (vec1.lenth != vec2.lenth ) error("bad vector sizes in vector multiply");
  Vcr<T> tm(vec1.lenth);
  for (int i = 0; i < vec1.lenth; i++) tm[i] = vec1[i]*vec2[i]; 
  return tm;
}

template<class T> 
Vcr<T> operator/(const Vcr<T> & vec, T scalar) {
  if (scalar == 0) error("divisor is zero in vector-scalar division");
  Vcr<T> tm(vec.lenth);
  for (int i = 0; i < vec.lenth; i++) tm[i] = vec[i]/scalar; 
  return tm; 
}

template<class T> 
T dot(const Vcr<T> & v1, const Vcr<T> & v2) {
  if (v1.lenth != v2.lenth ) error("bad vector sizes in dot product");
  T tm = v1[0]*v2[0];
  for (int i = 1; i < v1.lenth; i++) tm += v1[i]*v2[i];
  return tm;
}

template<class T> T dot(T* a, T* b, int n) {
  T init = 0;
  for (int i = 0; i < n; i++) init += *a++ * *b++;
  return init;
}

// *** definitions of iterative solvers for AbsMtx

template<class T>
int AbsMtx<T>::CG(Vcr<T>& x, const Vcr<T>& b, double& eps,  
	                       int& iter, int prec) {
// Conjugate gradient method. 
// x: on entry, initial guess; on retrun: approximate solution 
// b: right hand side vector as in A x = b;
// eps:  on entry, tolerance; on retrun: absolute residual in Euclid norm 
// iter: on entry, max number of iterations allowed; 
//       on return, actual number of iterations used 
// prec= 0 if no preconditioning, 1 if diag prec, 2 if SSOR prec

  if (nrows != b.size()) error("matrix and vector sizes do not match");
  const int maxiter = iter;
  Vcr<T> r = b - (*this)*x;                   // initial residual 
  Vcr<T> z = preconding(r,prec);              // solve the precond system
  Vcr<T> p = z;                               // p: search direction
  T zr = dot(z,r);                            // inner prod of z and r
  const double stp = eps*b.twonorm();         // stopping criterion

  if (r.maxnorm() == 0.0) {                   // if intial guess is true soln, 
    eps = 0.0;                                // return. Otherwise division by 
    iter = 0;                                 // zero would occur.
    return 0; 
  }

  for (iter = 0; iter < maxiter; iter++) {     // main loop of CG method
    Vcr<T> mp = (*this)*p;                     // one matrix-vector multiply
    T pap = dot(mp,p);                         // one of two inner products
    T alpha = zr/pap;                          // pap is 0 only when r is 0
    x += alpha*p;                              // update the iterative soln
    r -= alpha*mp;                             // update residual 
    if (r.twonorm() <= stp) break;             // stop if convergence achieved
    z = preconding(r,prec);                    // preconditioning
    T zrold = zr;
    zr = dot(z,r);                             // another of two inner products
    T beta= zr/zrold;                          // zrold = 0 only when r is 0
    p = z + beta*p;                            // update search direction
  } 

  eps = r.twonorm();
  if (iter == maxiter) return 1;
  else return 0;
} // end CG()

template<class T>
int AbsMtx<T>::GMRES(Vcr<T>& x, const Vcr<T>& b, double& eps,
                     int& iter, int pcn, int m) {  
    // Restarted GMRES for solving Ax = b, called GMRES(m) 
    // Return 0 if sucessful and 1 if breakdown
    // It outputs the approximate solution, residual, and 
    // number of iterations taken. 
    //
    // A: any nonsingular matrix, may not be symmetric
    // x: on entry:  initial guess
    //    on return: approximate solution
    // b: right side vector
    // eps: on input, stopping criterion,
    //      on return, absolute two-norm residual
    // iter: on input, max number of iterations allowed 
    //       on return, actual number of iterations taken.
    // pcn: = 0 if no preconditioner, = 1 if diag precond, 
    //      = 2 if SSOR precond
    // m: number of iterations for restarting GMRES

  const int maxiter = iter;
  const double stp = (preconding(b, pcn)).twonorm() * eps;
  Vcr<T> r = preconding(b - (*this) * x, pcn);
  T beta = r.twonorm();             // T may be complex<C>
  bool conv = false;
  if (m > nrows) 
    error("In GMRES(m), m is bigger than number of rows");
  if (abs(beta) <= stp) {    // return if initial guess 
    eps = abs(beta);         // is true solution
    iter = 0;
    return 0;
  }

  // orthonormal basis for Krylov space,
  // v[i] is a pointer to ith basis vector
  Vcr<T>** v = new Vcr<T>* [m+1];    
  for (int i = 0; i <= m; i++) 
    v[i] = new Vcr<T>(nrows);  // ith orthonormal basis

  // Hessenburg matrix h, (m+1) by m;
  // h[i] stores ith column of h that has i+2 entries.
  // Only non-zero part of h is stored
  T** h = new T* [m];     
  for (int i = 0; i < m; i++) h[i] = new T [i+2];              

  iter = 1;
  while (iter  <= maxiter) {  // iterations for gmres(m)
    *v[0] = r / beta;  
    Vcr<T> g(m+1);    // vector in least squares problem
    g[0] = beta;

    Vcr<T> cs(m), sn(m);      // Givens rotations
    int k;  
    for (k = 0; k < m && iter <= maxiter; k++, iter++) {

      // orthogonalization
      Vcr<T> w = preconding((*this) * (*v[k]), pcn);
      T nmw = w.twonorm();
      for (int i = 0; i <= k; i++) {     
        h[k][i] = dot(w, *v[i]);
        w -= h[k][i] * (*v[i]);
      }
      h[k][k+1] = w.twonorm();
      // if h[k][k+1] is small, do reorthogonalization
      if (nmw + 1.0e-4*h[k][k+1] == nmw) {
        for (int i = 0; i <= k; i++) { 
          T hri = dot(w, *v[i]);   // re-orthogonalization
          h[k][i] += hri;
          w -= hri * (*v[i]);
        }
        h[k][k+1] = w.twonorm();
      }
      if (h[k][k+1] == 0.0) 
        error("unexpected zero-divisor in GMRES()");
      *v[k+1] = w / h[k][k+1]; 

      // apply Givens G_0, G_1, ...,G_{k-1} to column k of h
      for (int i = 0; i < k; i++) { 
        // T tmp = conj(cs[i])*h[k][i] + conj(sn[i])*h[k][i+1];
        T tv[2] = { cs[i], sn[i] };
        T tmp = dot(&h[k][i], tv, 2);
        h[k][i+1] = - sn[i]*h[k][i] + cs[i]*h[k][i+1];
        h[k][i] = tmp;
      }

      // generate Givens rotation G_k from kth column of h
      if (h[k][k+1] == 0.0) {
        cs[k] = 1;
        sn[k] = 0;
      } else {
        T tpm = sqrt(dot(&h[k][k], &h[k][k], 2));
        cs[k] = h[k][k]/tpm;
        sn[k] = h[k][k+1]/tpm;
      }

      // apply Givens rotation G_k to kth column of h and to g
      T tv[2] = { cs[k], sn[k] };
      h[k][k] = dot(&h[k][k], tv, 2);
      T tmp = dot(&g[k], tv, 2);
      g[k+1] = - sn[k]*g[k] + cs[k]*g[k+1];
      g[k] = tmp;

      if (abs(g[k+1]) <= stp) { // stop if residual small
        k++;
        break;
      }
    }

    // back solve the upper triangular system
    for (int i = k-1; i >= 0; i--){
      for (int j = i+1; j < k; j++) g[i] -= h[j][i]*g[j];
      g[i] /= h[i][i];
    }

    // update the solution x = x0 + sum v[i]*y[i]
    for (int i = 0; i < k; i++) x += (*v[i])*g[i];

    // calculate residual and check for convergence
    r = preconding(b - (*this) * x, pcn);
    beta = r.twonorm();
    if (abs(beta) <= stp ) {    // stop if residual small
      conv = true;
      break;
    }
  }

  eps =  (b - (*this) * x).twonorm();  // get final residual

  // deallocate space for v and h
  for (int i = 0; i <= m; i++ ) delete v[i];
  delete[] v;
  for (int i = 0; i < m; i++) delete[] h[i];
  delete[] h;

  if (conv) return 0;
  else return 1;
}   // end of gmres(m)


// *** definitions for members of class BandMtx

template<class T>
BandMtx<T>::BandMtx(int n, int p, int r, T** t) {
  nrows = n;                                 // number of rows
  bwleft = p;                                // left bandwidth
  bwrit = r;                                 // right bandwidth
  bdmx = new T* [nrows]; 
  for (int i = 0; i < nrows; i++) {
   bdmx[i] = new T [bwleft + bwrit + 1];
   bdmx[i] += bwleft;                              
  }
  for (int i = 0; i < nrows; i++) 
    for (int j = - bwleft; j <= bwrit; j++) bdmx[i][j] = t[i][j];
}

template<class T>
BandMtx<T>::BandMtx(int n, int p, int r, T t = 0) {
  nrows = n;
  bwleft = p;
  bwrit = r;
  bdmx = new T* [nrows]; 
  for (int i = 0; i < nrows; i++) {
   bdmx[i] = new T [bwleft + bwrit + 1];
   bdmx[i] += bwleft;                              
  }
  for (int i = 0; i < nrows; i++) 
    for (int j = - bwleft; j <= bwrit; j++) bdmx[i][j] = t;
}

template<class T>
BandMtx<T>::BandMtx(const BandMtx & bd) {
  nrows = bd.nrows;
  bwleft = bd.bwleft;
  bwrit = bd.bwrit;
  bdmx = new T* [nrows]; 
  for (int i = 0; i < nrows; i++) {
   bdmx[i] = new T [bwleft + bwrit + 1];
   bdmx[i] += bwleft;                              
  }
  for (int i = 0; i < nrows; i++) 
    for (int j = - bwleft; j <= bwrit; j++) bdmx[i][j] = bd[i][j];
}


template<class T>
BandMtx<T>::BandMtx(int n, int p, int r, const FullMtx<T>& fm) {
  nrows = n;
  bwleft = p;
  bwrit = r;
  bdmx = new T* [nrows]; 
  for (int i = 0; i < nrows; i++) {
   bdmx[i] = new T [bwleft + bwrit + 1];
   bdmx[i] += bwleft;                              
  }
  for (int i = 0; i< nrows; i++) {
    for (int j = - bwleft; j <= bwrit; j++) 
    bdmx[i][j] = 0;
  }
  for (int i = 0; i< nrows; i++) {                   // fm may be non-symmetric
    int ip = max(i-bwleft, 0); 
    int ir = min(i+bwrit, nrows -1); 
    for (int j = ip; j <= ir; j++) bdmx[i][j-i] = fm[i][j];
  }
}

template<class T>
BandMtx<T>& BandMtx<T>::operator=(const BandMtx & bd) {
  if (nrows != bd.nrows || bwleft != bd.bwleft || bwrit != bd.bwrit) 
    error("bad matrix size in BandMtx assignment");
  for (int j = 0; j < nrows; j++) 
    for (int k = -bwleft; k <= bwrit; k++) bdmx[j][k] = bd[j][k];
  return *this;
}

template<class T>                                     // matrix vector multiply 
Vcr<T> BandMtx<T>::operator*(const Vcr<T> & vec) const {    
  if (nrows != vec.size()) error("matrix and vector sizes do not match");
  Vcr<T> tm(nrows);
  for (int i = 0; i < nrows; i++) {
    int ip = max(i-bwleft, 0); 
    int ir = min(i+bwrit, nrows - 1);
    for (int j = ip; j <= ir; j++) tm[i] += bdmx[i][j-i]*vec[j]; 
  }
  return tm;
}

template<class T>                      // solve Pz = r, return z
Vcr<T> BandMtx<T>::preconding(const Vcr<T> & r, int precn) const {
  if (precn == 0) {                    // no preconditioning
    return r;
  } else if (precn == 1) {             // diagonal preconditioning
    Vcr<T> z(nrows);
    for (int i = 0; i < nrows; i++) z[i] = r[i]/bdmx[i][0];
    return z;
  } else if (precn == 2) {             // symmetric SOR preconditioning
    const T omega = 1;                 // SSOR parameter for preconditioning
    Vcr<T> z(nrows);
    for (int i = 0; i < nrows; i++) {
      T sum = 0;
      int ip = max(i-bwleft, 0);
      for (int j = ip; j < i; j++)  sum += omega*bdmx[i][j-i]*z[j];
      z[i] = (r[i] - sum)/bdmx[i][0];
    }
    for (int i = nrows -1; i >= 0; i--) {
      T sum = 0;
      int ir = min(i+bwrit, nrows -1); 
      for (int j = i+1; j <= ir; j++) sum += omega*bdmx[i][j-i]*z[j];
      z[i] -= sum/bdmx[i][0];
    }
    return z;
  } else {
    error("specified preconditioner in BandMtx::preconding() not implemented");
  }
}

// BandGauss
template<class T>
void BandMtx<T>::GaussElim(Vcr<T>& bb) const {
                           // Gauss elim without pivoting
  if (nrows != bb.size()) 
    error("matrix and vector sizes do not match");
  BandMtx<T> tmx = *this;

  // banded LU decomposition without pivoting
  const int nrowsmone = nrows - 1;
  for (int k = 0; k < nrowsmone; k++) {
    if (tmx[k][0] == 0.0) 
      error("pivot is zero in BandMtx::GaussElim()");
    int kbf = min(nrowsmone - k, bwleft);
    int kbr = min(nrowsmone - k, bwrit);
    for (int i = 1; i <= kbf; i++) {
      int kpi = k+i;
      if (tmx[kpi][-i] != 0.0) {   
        T dmul = tmx[kpi][-i]/tmx[k][0];
        tmx[kpi][-i] = dmul;  // tmx[k+i][-i] = a[k+i][k]
        for (int j = 1; j <= kbr; j++) 
          tmx[kpi][j-i] -= dmul*tmx[k][j];   
      }                       // a[k+i][k+j] = tmx[k+i][j-i]
    }
  }

  // Forward substitution
  for (int k = 1; k < nrows; k++) {
    int kf = min(k, bwleft);
    for (int j = 1; j <= kf; j++) 
      bb[k] -= tmx[k][-j]*bb[k-j];
  }                           // tmx[k][-j] = a[k][k-j]

  // Backward substitution
  for (int k = nrowsmone; k >= 0; k--) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -