mv.h

来自「C++ source code for book-C++ and Object 」· C头文件 代码 · 共 1,506 行 · 第 1/4 页

H
1,506
字号
}

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.size());
  for (int i = 0; i < vec.size(); i++) tm[i] = scalar*vec[i]; 
  return tm;
}

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

template<class T> 
Vcr<T> operator*(const Vcr<T> & vec1, const Vcr<T> & vec2) {
  int size = vec1.size();
  if (size != vec2.size()) error("bad vector sizes in vector multiply");
  Vcr<T> tm(size);
  for (int i = 0; i < size; 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.size());
  for (int i = 0; i < vec.size(); i++) tm[i] = vec[i]/scalar; 
  return tm; 
}

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

// function for dot product for real numbers
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 for members in class Vcr< complex<T> >.

template<class T>    // constructor
Vcr< complex<T> >::Vcr(int n, const complex<T>* const abd) {
  vr = new complex<T> [lenth =n]; 
  for (int i = 0; i < lenth; i++)  vr[i]= *(abd +i);
}

template<class T>
Vcr< complex<T> >::Vcr(int n, complex<T> abd) { // constructor
  vr = new complex<T> [lenth =n]; 
  for (int i = 0; i < lenth; i++)  vr[i]= abd;
}

template<class T>
Vcr< complex<T> >::Vcr(const Vcr & vec) {  //copy constructor
  vr = new complex<T> [lenth = vec.lenth]; 
  for (int i = 0; i < lenth; i++)  vr[i] = vec[i]; 
}
template<class T>          
T Vcr< complex<T> >::maxnorm() const {                  // maximum norm
  T nm = abs(vr[0]);
  for (int i = 1; i < lenth; i++) 
    nm = max(nm, abs(vr[i]));                           // #include <algorithm>
  return nm;
}

template<class T>          
T Vcr< complex<T> >::twonorm() const {                  // two norm
  T nm = pow(abs(vr[0]), 2);
  for (int i = 1; i < lenth; i++) nm += pow(abs(vr[i]),2);
  return sqrt(nm);
}

template<class T>
void Vcr< complex<T> >::reset(complex<T> a = 0) {
 for (int i = 0; i < lenth; i++)  vr[i] = a;
}

template<class T> Vcr<complex<T> >& 
Vcr<complex<T> >::operator=(const Vcr<complex<T> >& v) {
  if (this != &v) {
    if (lenth != v.lenth) error("bad vector sizes in assigment");
    for (int i = 0; i < lenth; i++) vr[i] = v[i];
  }
  return *this;
}

template<class T> Vcr<complex<T> >& 
Vcr<complex<T> >::operator+=(const Vcr<complex<T> >& v) {
  if (lenth != v.lenth) error("bad vector sizes in addition");
  for (int i = 0; i < lenth; i++) vr[i] += v[i];
  return *this;
}

template<class T> Vcr<complex<T> >& 
Vcr<complex<T> >::operator-=(const Vcr<complex<T> >& v) {
  if (lenth != v.lenth) error("bad vector sizes in subtract");
  for (int i = 0; i < lenth; i++) vr[i] -= v[i];
  return *this;
}

template<class T> 
Vcr<complex<T> > operator+(const Vcr<complex<T> >& v) {
  return v;                 // usage: u = + v;
}

template<class T>           // usage: vec1 = - vec2;
Vcr<complex<T> > operator-(const Vcr<complex<T> >& v) {
  Vcr< complex<T> > minus = v;
  for (int i = 0; i < v.size(); i++) minus[i] = - v[i];
  return minus;
}

template<class T> Vcr<complex<T> >       // w=u+v
operator+(const Vcr<complex<T> >& u, const Vcr<complex<T> >& v) {
  if (u.size()!= v.size()) error("bad vector sizes in addition");
  Vcr< complex<T> > sum = u;
  sum += v;
  return sum;
}

template<class T> Vcr<complex<T> >       // w=u-v
operator-(const Vcr<complex<T> >& u, const Vcr<complex<T> >& v) {
  if (u.size() != v.size()) error("bad vector sizes in addition");
  Vcr< complex<T> > minus = u;
  minus -= v;
  return minus;
}

template<class T> Vcr<complex<T> >       // w=a*v
operator*(complex<T> scalar, const Vcr<complex<T> >& v) {
  Vcr< complex<T> > tm(v.size());
  for (int i = 0; i < v.size(); i++) tm[i] = scalar*v[i];
  return tm;
}

template<class T> Vcr<complex<T> >       // w=a*v
operator*(const Vcr<complex<T> >& v, complex<T> scalar) {
  Vcr< complex<T> > tm(v.size());
  for (int i = 0; i < v.size(); i++) tm[i] = scalar*v[i];
  return tm;
}

template<class T> Vcr<complex<T> >       // w=a*v
operator/(const Vcr<complex<T> >& v, complex<T> scalar) {
  Vcr< complex<T> > tm(v.size());
  for (int i = 0; i < v.size(); i++) tm[i] = v[i]/scalar;
  return tm;
}


template<class T> Vcr<complex<T> >       // w=a*v
operator*(const Vcr<complex<T> >& u, const Vcr<complex<T> >& v) {
  int size = u.size();
  if (size != v.size()) error("bad vector sizes in multiply");
  Vcr< complex<T> > tm(size);
  for (int i = 0; i < size; i++) tm[i] = u[i]*v[i];
  return tm;
}


template<class T>                                       // dot product
complex<T> dot(const Vcr<complex<T> >& u, const Vcr<complex<T> >& v) {
  int size = u.size();
  if (size != v.size()) cout<< "bad vector sizes";
  complex<T> tm = u[0]*conj(v[0]);       // conjugation is needed
  for (int i = 1; i < size; i++) tm += u[i]*conj(v[i]);
  return tm;
}

template<class T>      
ostream& operator<<(ostream& s, const Vcr< complex<T> >&v) {
  for (int i =0; i < v.size(); i++) {
    s << v[i] << "  ";
    if (i%10 == 9) s << '\n';
  }
  return s;
}

                           // output operator

// function for dot product for complex numbers
template<class T> 
complex<T> dot(complex<T>* a, complex<T>* b, int k) {
  complex<T> init = 0;
  for (int i = 0; i < k; i++) init += *a++ * conj(*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 pcn) {
    // Preconditioned conjugate gradient method for Ax = b
    // It returns 0 for sucessful return and 1 if breakdown
    // A: Hermitian positive definite coefficient matrix
    // x:  on entry:  initial guess;
    //     on return: approximate solution
    // b:  right side vector 
    // eps: on entry:  stopping criterion, epsilon
    //      on return: absolute residual in two-norm for 
    //                 approximate solution
    // iter: on entry:  max number of iterations allowed
    //       on return: actual number of iterations taken
    // pcn: = 0 if no preconditioner, = 1 if diag precond
    //      = 2 if SSOR preconditioner

  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, pcn);   // solve precondit 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 initial guess is true
    eps = 0.0;                // solution, return. Otherwise
    iter = 0;                 // division by zero would occur
    return 0; 
  }

  for (iter = 0; iter < maxiter; iter++) {     // main loop
    Vcr<T> mp = (*this)*p;    // one matrix-vector multiply
    T pap = dot(mp,p);        // one inner product
    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 converged
    z = preconding(r,pcn);   // preconditioning
    T zrold = zr;
    zr = dot(z,r);            // the other inner product
    T beta= zr/zrold;         // zrold = 0 only when r = 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) 
        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) {
        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];
    }

⌨️ 快捷键说明

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