conjugate_gradient.h

来自「很多二维 三维几何计算算法 C++ 类库」· C头文件 代码 · 共 278 行

H
278
字号
/* * author:  Bruno Levy, INRIA, project ALICE * website: http://www.loria.fr/~levy/software *  * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation *  * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA * * Scientific work that use this software can reference the website and * the following publication: * * @INPROCEEDINGS {levy:NMDGP:05, *    AUTHOR = Bruno Levy, *    TITLE  = Numerical Methods for Digital Geometry Processing, *    BOOKTITLE =Israel Korea Bi-National Conference, *    YEAR=November 2005, *    URL=http://www.loria.fr/~levy/php/article.php?pub=../publications/papers/2005/Numerics * } * *  Laurent Saboret 2005-2006: Changes for CGAL: *      - Added OpenNL namespace *      - solve() returns true on success *      - test divisions by zero with IsZero() method *      - added comments *      - copied Conjugate Gradient algorithm WITH preconditioner from Graphite 1.9 code */#ifndef __OPENNL_CONJUGATE_GRADIENT__#define __OPENNL_CONJUGATE_GRADIENT__#include <CGAL/OpenNL/blas.h>#include <cmath>#include <cfloat>#include <climits>#include <cassert>namespace OpenNL {/** *  The Conjugate Gradient algorithm WITHOUT preconditioner: *  Ashby, Manteuffel, Saylor *     A taxononmy for conjugate gradient methods *     SIAM J Numer Anal 27, 1542-1568 (1990) * * This implementation is inspired by the lsolver library, * by Christian Badura, available from: * http://www.mathematik.uni-freiburg.de/IAM/Research/projectskr/lin_solver/ * * @param A generic square matrix; a function *   mult(const MATRIX& M, const double* x, double* y) * and a member function  *   int dimension() const * must to be defined. * @param b right hand side of the system. * @param x initial value. * @param eps threshold for the residual. * @param max_iter maximum number of iterations. */template<class MATRIX, class VECTOR> class Solver_CG {public:    typedef MATRIX Matrix ;    typedef VECTOR Vector ;    typedef typename Vector::CoeffType CoeffType ;public:    Solver_CG() {        epsilon_ = 1e-6 ;        max_iter_ = 0 ;    }    // Default copy constructor, operator =() and destructor are fine    void set_epsilon(CoeffType eps) { epsilon_ = eps ; }    void set_max_iter(unsigned int max_iter) { max_iter_ = max_iter ; }    // Solve the sparse linear system "A*x = b" for A symmetric positive definite    // Return true on success    bool solve(const MATRIX &A, const VECTOR& b, VECTOR& x)     {        assert(A.dimension() > 0);        unsigned int n = A.dimension() ;                        // (Square) matrix dimension        unsigned int max_iter = max_iter_ ;                     // Max number of iterations        if(max_iter == 0) {            max_iter = 5 * n ;        }        Vector g(n) ;        Vector r(n) ;        Vector p(n) ;        unsigned int its=0;                                     // Loop counter        CoeffType t, tau, sig, rho, gam;        CoeffType bnorm2 = BLAS<Vector>::dot(b,b) ;        CoeffType err=epsilon_*epsilon_*bnorm2 ;                // Error to reach        // Current residue g=b-A*x        mult(A,x,g);        BLAS<Vector>::axpy(-1,b,g);        BLAS<Vector>::scal(-1,g);        // Initially, r=g=b-A*x        BLAS<Vector>::copy(g,r);                                // r = g        CoeffType gg=BLAS<Vector>::dot(g,g);                    // Current error gg = (g|g)        while ( gg>err && its < max_iter) {            mult(A,r,p);            rho=BLAS<Vector>::dot(p,p);            sig=BLAS<Vector>::dot(r,p);            tau=BLAS<Vector>::dot(g,r);            if (IsZero(sig))                break;                                          // stop if bad conditioning            t=tau/sig;            BLAS<Vector>::axpy(t,r,x);            BLAS<Vector>::axpy(-t,p,g);            if (IsZero(tau))                break;                                          // stop if bad conditioning            gam=(t*t*rho-tau)/tau;            BLAS<Vector>::scal(gam,r);            BLAS<Vector>::axpy(1,g,r);            gg=BLAS<Vector>::dot(g,g);                          // Update error gg = (g|g)            ++its;        }        bool success = (gg <= err);        return success;    }private:    // Test if a floating point number is (close to) 0.0    static bool IsZero(CoeffType a)    {        return (fabs(a) < 10.0 * (std::numeric_limits<CoeffType>::min)());    }    // Test if 2 floating point numbers are very close    static inline bool AreEqual(CoeffType a, CoeffType b)    {        if (IsZero(a))            return IsZero(b);        else            return IsZero(b/a - 1.0);    }private:    CoeffType epsilon_ ;    unsigned int max_iter_ ;} ;/** *  The Conjugate Gradient algorithm WITH preconditioner: *  Ashby, Manteuffel, Saylor *     A taxononmy for conjugate gradient methods *     SIAM J Numer Anal 27, 1542-1568 (1990) * * This implementation is inspired by the lsolver library, * by Christian Badura, available from: * http://www.mathematik.uni-freiburg.de/IAM/Research/projectskr/lin_solver/ * * @param A generic square matrix; a function *   mult(const MATRIX& M, const double* x, double* y) * and a member function  *   int dimension() const * must to be defined. * @param C preconditioner; a function *   mult(const PC_MATRIX& C, const double* x, double* y) * needs to be defined. * @param b right hand side of the system. * @param x initial value. * @param eps threshold for the residual. * @param max_iter maximum number of iterations. */template< class MATRIX, class PC_MATRIX, class VECTOR > class Solver_preconditioned_CG {public:    typedef MATRIX Matrix ;    typedef PC_MATRIX Preconditioner ;    typedef VECTOR Vector ;    typedef typename Vector::CoeffType CoeffType ;public:    Solver_preconditioned_CG() {        epsilon_ = 1e-6 ;        max_iter_ = 0 ;    }    // Default copy constructor, operator =() and destructor are fine    void set_epsilon(CoeffType eps) { epsilon_ = eps ; }    void set_max_iter(unsigned int max_iter) { max_iter_ = max_iter ; }    // Solve the sparse linear system "A*x = b" for A symmetric positive definite    // Return true on success    bool solve(const MATRIX &A, const PC_MATRIX &C, const VECTOR& b, VECTOR& x)     {        assert (A.dimension() > 0);        unsigned int n = A.dimension() ;                        // (Square) matrix dimension        unsigned int max_iter = max_iter_ ;                     // Max number of iterations        if(max_iter == 0) {            max_iter = 5 * n ;        }        Vector r(n) ;        Vector d(n) ;        Vector h(n) ;        Vector Ad = h ;        unsigned int its=0;                                     // Loop counter        CoeffType rh, alpha, beta;        CoeffType bnorm2 = BLAS<Vector>::dot(b,b) ;        CoeffType err=epsilon_*epsilon_*bnorm2 ;                // Error to reach        // Current residue r=A*x-b        mult(A,x,r);        BLAS<Vector>::axpy(-1,b,r);        mult(C,r,d);        BLAS<Vector>::copy(d,h);        rh=BLAS<Vector>::dot(r,h);        CoeffType rr=BLAS<Vector>::dot(r,r);                    // Current error rr = (r|r)        while ( rr>err && its < max_iter) {            mult(A,d,Ad);            assert( ! IsZero( BLAS<Vector>::dot(d,Ad) ) );            alpha=rh/BLAS<Vector>::dot(d,Ad);            BLAS<Vector>::axpy(-alpha,d,x);            BLAS<Vector>::axpy(-alpha,Ad,r);            mult(C,r,h);            if (IsZero(rh))                break;                                          // stop if bad conditioning            beta=1/rh; rh=BLAS<Vector>::dot(r,h); beta*=rh;            BLAS<Vector>::scal(beta,d);            BLAS<Vector>::axpy(1,h,d);            rr=BLAS<Vector>::dot(r,r);                          // Update error rr = (r|r)            ++its;        }        bool success = (rr <= err);        return success;    }private:    // Test if a floating point number is (close to) 0.0    static bool IsZero(CoeffType a)    {        return (fabs(a) < 10.0 * (std::numeric_limits<CoeffType>::min)());    }    // Test if 2 floating point numbers are very close    static inline bool AreEqual(CoeffType a, CoeffType b)    {        if (IsZero(a))            return IsZero(b);        else            return IsZero(b/a - 1.0);    }private:    CoeffType epsilon_ ;    unsigned int max_iter_ ;} ;}; // namespace OpenNL#endif // __OPENNL_CONJUGATE_GRADIENT__

⌨️ 快捷键说明

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