qmatvec.cpp

来自「算断裂的」· C++ 代码 · 共 306 行

CPP
306
字号
// ------------------------------------------------------------------// qmatvec.cpp//// This file contains member functions for Matrix.// ------------------------------------------------------------------// Author: Stephen A. Vavasis// Copyright (c) 1999 by Cornell University.  All rights reserved.// // See the accompanying file 'Copyright' for authorship information,// the terms of the license governing this software, and disclaimers// concerning this software.// ------------------------------------------------------------------// This file is part of the QMG software.  // Version 2.0 of QMG, release date September 3, 1999.// ------------------------------------------------------------------#include "qmatvec.h"// Solve a linear system in place; return estimate of inverse norm.QMG::Real QMG::Matrix::linear_solve(Real rhs[], Real x[]) {  Matrix& m = *this;  int n = m.numrows_;  #ifdef DEBUGGING  if (n != m.numcols_ || n == 0) {    throw_error("Attempt to solve nonsquare or empty system");    return 0.0;  }#endif      // If dim = 1 solve directly.    if (n == 1) {    if (m(0,0) == 0.0)      return BIG_REAL;    x[0] = rhs[0] / m(0,0);    return 1.0 / fabs(m(0,0));  }  else if (n == 2) {    // Use Cramer's rule for x[1] and backsub for x[0].    Real det = m(0,0) * m(1,1) - m(1,0) * m(0,1);    if (det == 0.0)       return BIG_REAL;    x[1] = (m(0,0) * rhs[1] - m(1,0) * rhs[0]) / det;    if (fabs(m(0,0)) >= fabs(m(1,0))) {      x[0] = (rhs[0] - m(0,1) * x[1]) / m(0,0);    }    else {      x[0] = (rhs[1] - m(1,1) * x[1]) / m(1,0);    }    return fabs(sqrt(m(0,0) * m(0,0) + m(0,1) * m(0,1)      + m(1,0) * m(1,0) + m(1,1) * m(1,1)) / det);  }    // Use GEPP with partial pivoting.    {    for (int i = 0; i < n - 1; ++i) {      // Scan for the pivot in col j.      Real piv = m(i,i);      Real abspiv = fabs(piv);      int pivrow = i;      {        for (int i1 = i + 1; i1 < n; ++i1) {          if (fabs(m(i1,i)) > abspiv) {            pivrow  = i1;            piv = m(i1,i);            abspiv = fabs(piv);          }        }      }      if (piv == 0.0)        return BIG_REAL;      if (pivrow != i) {        Real tmp;        for (int j = i; j < n; ++j) {          tmp = m(i,j);          m(i,j) = m(pivrow,j);          m(pivrow,j) = tmp;        }        tmp = rhs[i];        rhs[i] = rhs[pivrow];        rhs[pivrow] = tmp;      }      Real mult;      {        for (int i1 = i + 1; i1 < n; ++i1) {          mult = m(i1,i) / piv;          for (int j = i + 1; j < n; ++j) {            m(i1,j) -= m(i,j) * mult;          }          rhs[i1] = rhs[i1] - rhs[i] * mult;        }      }    }    if (m(n-1, n-1) == 0.0)      return BIG_REAL;  }    // Backsubstitution to get x.  {        for (int i = n - 1; i >= 0; --i) {      Real t = rhs[i];      for (int j = i + 1; j < n; ++j) {        t -= m(i,j) * x[j];      }      x[i] = t / m(i,i);    }  }  // Assume norm(inv(A)) == n * norminv(U) using backsubstitution.    Real norminvU = 0.0;    // Solve Ux = e_k  // Store answer in rhs[j],  {    for (int k = 0; k < n; ++k) {      Real t = 1.0;      {        for (int i = k; i >= 0; --i) {          for (int j = i + 1; j <= k; ++j) {            t -= m(i,j) * rhs[j];          }          rhs[i] = t / m(i,i);          t = 0.0;        }      }      {        for (int i = 0; i <= k; ++i)          norminvU += rhs[i] * rhs[i];      }    }    // Now compute norm(U).  }  return n * sqrt(norminvU);}// Compute the determinant of a matrix.QMG::RealQMG::Matrix::determinant() const {  const Matrix& a = *this;  int n = a.numrows_;#ifdef DEBUGGING  if (n == 0 || n != a.numcols_) {    throw_error("Nonsquare or zero matrix for determinant");    return 0;  }#endif  if (n == 1)    return a(0,0);  else if (n == 2)    return a(0,0) * a(1,1) - a(1,0) * a(0,1);  else if (n == 3)    return a(0,0) * (a(1,1) * a(2,2) - a(1,2) * a(2,1)) +     a(1,0) * (a(0,2) * a(2,1) - a(0,1) * a(2,2)) +    a(2,0) * (a(0,1) * a(1,2) - a(0,2) * a(1,1));  // Do GEPP for the remaining cases.  Must make a temp copy of  // a since we promised not to overwite a.  Matrix m(n,n);  {  for (int i = 0; i < n; ++i) {    for (int j = 0; j < n; ++j) {      m(i,j) = a(i,j);    }  }  }  Real det = 1.0;  // Use GEPP with partial pivoting.  {    for (int i = 0; i < n; ++i) {      // Scan for the pivot in col j.      Real piv = m(i,i);      Real abspiv = fabs(piv);      int pivrow = i;      {        for (int i1 = i + 1; i1 < n; ++i1) {          if (fabs(m(i1,i)) > abspiv) {            pivrow  = i1;            piv = m(i1,i);            abspiv = fabs(piv);          }        }      }      if (pivrow != i) {        Real tmp;        for (int j = i; j < n; ++j) {          tmp = m(i,j);          m(i,j) = m(pivrow,j);          m(pivrow,j) = tmp;        }        det *= -1.0;      }      Real mult;      {        for (int i1 = i + 1; i1 < n; ++i1) {          mult = m(i1,i) / piv;          for (int j = i + 1; j < n; ++j) {            m(i1,j) -= m(i,j) * mult;          }        }      }      det *= piv;    }  }  return det;}QMG::ostream& operator<<(QMG::ostream& os, const QMG::Matrix& mtx) {  os << '[';  for (int i = 0; i < mtx.numrows(); ++i) {    for (int j = 0; j < mtx.numcols(); ++j) {      os << mtx(i,j);      if (j < mtx.numcols() - 1)        os << ',';    }    if (i < mtx.numrows() - 1)      os << ';';  }  return os << ']';}// Copying copies a pointer for heap arrays and sets the source to zero.// (Like autoptr).void QMG::Matrix::init_from_mtx_(Matrix& m) {  if (m.heap_allocated_) {    entries_ = m.entries_;    numrows_ = m.numrows_;    numcols_ = m.numcols_;    heap_allocated_ = true;    m.entries_ = 0;    m.numrows_ = 0;    m.entries_ = 0;    m.heap_allocated_ = false;  }  else {    entries_ = new Real[m.numrows_ * m.numcols_];    numrows_ = m.numrows_;    numcols_ = m.numcols_;    heap_allocated_ = true;    for (int i = 0; i < m.numrows_; ++i)      for (int j = 0; j < m.numcols_; ++j)        (*this)(i,j) = m(i,j);  }}voidQMG::IntMatrix::init_from_mtx_(IntMatrix& m) {  if (m.heap_allocated_) {    entries_ = m.entries_;    numrows_ = m.numrows_;    numcols_ = m.numcols_;    heap_allocated_ = true;    m.entries_ = 0;    m.numrows_ = 0;    m.entries_ = 0;    m.heap_allocated_ = false;  }  else {    entries_ = new int[m.numrows_ * m.numcols_];    numrows_ = m.numrows_;    numcols_ = m.numcols_;    heap_allocated_ = true;    for (int i = 0; i < m.numrows_; ++i)      for (int j = 0; j < m.numcols_; ++j)        (*this)(i,j) = m(i,j);  }}// Compute a householder transform that zeros out entries// 2..n of the input vector vec.  Put result in hhtrans.QMG::Real QMG::Matrix::compute_hh_transform(Real* hhtrans,                                             const Real* vec,                                             int vec_stride,                                             int n) {  Real sigma = 0.0;  for (int i = 1; i < n; ++i) {    hhtrans[i] = vec[i * vec_stride];    sigma += hhtrans[i] * hhtrans[i];  }  Real beta;  if (sigma == 0.0) {    hhtrans[0] = 0.0;    beta = 0.0;  }  else {    Real mu = sqrt(vec[0] * vec[0] + sigma);    if (vec[0] < 0.0)      hhtrans[0] = vec[0] - mu;    else      hhtrans[0] = -sigma / (vec[0] + mu);    beta = -1.0 / (mu * hhtrans[0]);  }  return beta;}

⌨️ 快捷键说明

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