linear_solver.h

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

H
483
字号
/* * 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 *      - DefaultLinearSolverTraits is now a model of the SparseLinearAlgebraTraits_d concept *      - Added SymmetricLinearSolverTraits *      - copied Jacobi preconditioner from Graphite 1.9 code */#ifndef __OPENNL_LINEAR_SOLVER__#define __OPENNL_LINEAR_SOLVER__#include <CGAL/OpenNL/conjugate_gradient.h>#include <CGAL/OpenNL/bicgstab.h>#include <CGAL/OpenNL/preconditioner.h>#include <CGAL/OpenNL/sparse_matrix.h>#include <CGAL/OpenNL/full_vector.h>#include <vector>#include <iostream>#include <cassert>#include <cstdlib>namespace OpenNL {// Class DefaultLinearSolverTraits// is a traits class for solving general sparse linear systems.// It uses BICGSTAB solver with Jacobi preconditioner.//// Concept: Model of the SparseLinearAlgebraTraits_d concept.template<    class COEFFTYPE,                        // type of matrix and vector coefficients    class MATRIX = SparseMatrix<COEFFTYPE>, // model of SparseLinearSolverTraits_d::Matrix    class VECTOR = FullVector<COEFFTYPE>    // model of SparseLinearSolverTraits_d::Vector>class DefaultLinearSolverTraits{// Public typespublic:    typedef COEFFTYPE                       CoeffType ;    typedef COEFFTYPE                       NT;    typedef MATRIX                          Matrix ;    typedef VECTOR                          Vector ;    // Private typesprivate:    typedef Jacobi_Preconditioner<NT>       Preconditioner ;    typedef Solver_preconditioned_BICGSTAB<Matrix, Preconditioner, Vector>                                              Preconditioned_solver ;    typedef Solver_BICGSTAB<Matrix, Vector> Solver ;// Public operationspublic:    // Default contructor, copy constructor, operator=() and destructor are fine    // Solve the sparse linear system "A*X = B"    // Return true on success. The solution is then (1/D) * X.    //    // Preconditions:    // - A.row_dimension()    == B.dimension()    // - A.column_dimension() == X.dimension()    bool linear_solver (const Matrix& A, const Vector& B, Vector& X, NT& D)    {        D = 1;              // OpenNL does not support homogeneous coordinates                // Solve using BICGSTAB solver with preconditioner        Preconditioned_solver preconditioned_solver ;        NT omega = 1.5;        Preconditioner C(A, omega);        X = B;          if (preconditioned_solver.solve(A, C, B, X))            return true;        // On error, solve using BICGSTAB solver without preconditioner#ifndef NDEBUG        std::cerr << "Failure of BICGSTAB solver with Jacobi preconditioner. "                  << "Trying BICGSTAB." << std::endl;#endif        Solver solver ;        X = B;          return solver.solve(A, B, X) ;    }} ;// Class SymmetricLinearSolverTraits// is a traits class for solving symmetric positive definite sparse linear systems.// It uses Conjugate Gradient solver with Jacobi preconditioner.//// Concept: Model of the SparseLinearAlgebraTraits_d concept.template<    class COEFFTYPE,                        // type of matrix and vector coefficients    class MATRIX = SparseMatrix<COEFFTYPE>, // model of SparseLinearSolverTraits_d::Matrix    class VECTOR = FullVector<COEFFTYPE>    // model of SparseLinearSolverTraits_d::Vector>class SymmetricLinearSolverTraits{// Public typespublic:    typedef COEFFTYPE                       CoeffType ;    typedef COEFFTYPE                       NT;    typedef MATRIX                          Matrix ;    typedef VECTOR                          Vector ;    // Private typesprivate:    typedef Jacobi_Preconditioner<NT>       Preconditioner ;    typedef Solver_preconditioned_CG<Matrix, Preconditioner, Vector>                                              Preconditioned_solver ;    typedef Solver_CG<Matrix, Vector>       Solver ;// Public operationspublic:    // Default contructor, copy constructor, operator=() and destructor are fine    // Solve the sparse linear system "A*X = B"    // Return true on success. The solution is then (1/D) * X.    //    // Preconditions:    // - A.row_dimension()    == B.dimension()    // - A.column_dimension() == X.dimension()    bool linear_solver (const Matrix& A, const Vector& B, Vector& X, NT& D)    {        D = 1;              // OpenNL does not support homogeneous coordinates                // Solve using Conjugate Gradient solver with preconditioner        Preconditioned_solver preconditioned_solver ;        NT omega = 1.5;        Preconditioner C(A, omega);        X = B;          if (preconditioned_solver.solve(A, C, B, X))            return true;        // On error, solve using Conjugate Gradient solver without preconditioner#ifndef NDEBUG        std::cerr << "Failure of Conjugate Gradient solver with Jacobi preconditioner. "                  << "Trying Conjugate Gradient." << std::endl;#endif        Solver solver ;        X = B;          return solver.solve(A, B, X) ;    }};/* * Solves a linear system or minimizes a quadratic form. * * Requirements for its traits class: must be a model of SparseLinearSolverTraits_d concept */template <class TRAITS>class LinearSolver{protected:    enum State {        INITIAL, IN_SYSTEM, IN_ROW, CONSTRUCTED, SOLVED    } ;public:    typedef TRAITS Traits ;    typedef typename Traits::Matrix Matrix ;    typedef typename Traits::Vector Vector ;    typedef typename Traits::NT CoeffType ;    class Variable {    public:        Variable() : x_(0), index_(-1), locked_(false) { }        double value() const { return x_; }        void set_value(double x_in) { x_ = x_in ; }        void lock()   { locked_ = true ; }        void unlock() { locked_ = false ; }        bool is_locked() const { return locked_ ; }        unsigned int index() const {            assert(index_ != -1) ;            return (unsigned int)(index_) ;        }        void set_index(unsigned int index_in) {            index_ = index_in ;        }    private:        CoeffType x_ ;        int index_ ;        bool locked_ ;    }  ;    LinearSolver(unsigned int nb_variables) {        state_ = INITIAL ;        least_squares_ = false ;        nb_variables_ = nb_variables ;        variable_ = new Variable[nb_variables] ;        A_ = NULL ;        x_ = NULL ;        b_ = NULL ;    }    ~LinearSolver() {        delete[] variable_ ;        delete A_ ;        delete x_ ;        delete b_ ;    }    // __________________ Parameters ________________________    void set_least_squares(bool x) { least_squares_ = x ; }    // __________________ Access ____________________________    int nb_variables() const { return nb_variables_ ; }    Variable& variable(unsigned int idx) {        assert(idx < nb_variables_) ;        return variable_[idx] ;    }    const Variable& variable(unsigned int idx) const {        assert(idx < nb_variables_) ;        return variable_[idx] ;    }    // _________________ Construction _______________________    void begin_system() {        current_row_ = 0 ;        transition(INITIAL, IN_SYSTEM) ;        // Enumerate free variables.        unsigned int index = 0 ;        for(int ii=0; ii < nb_variables() ; ii++) {            Variable& v = variable(ii) ;            if(!v.is_locked()) {                v.set_index(index) ;                index++ ;            }        }        unsigned int n = index ;        A_ = new Matrix(n) ;        x_ = new Vector(n) ;        b_ = new Vector(n) ;        for(unsigned int i=0; i<n; i++) {            (*x_)[i] = 0 ;            (*b_)[i] = 0 ;        }        variables_to_vector() ;    }    void begin_row() {        transition(IN_SYSTEM, IN_ROW) ;        af_.clear() ;        if_.clear() ;        al_.clear() ;        xl_.clear() ;        bk_ = 0 ;    }    void set_right_hand_side(double b) {        check_state(IN_ROW) ;        bk_ = b ;    }    void add_coefficient(unsigned int iv, double a) {        check_state(IN_ROW) ;        Variable& v = variable(iv) ;        if(v.is_locked()) {            al_.push_back(a) ;            xl_.push_back(v.value()) ;        } else {            af_.push_back(a) ;            if_.push_back(v.index()) ;        }    }    void normalize_row(CoeffType weight = 1) {        check_state(IN_ROW) ;        CoeffType norm = 0.0 ;        unsigned int nf = af_.size() ;        for(unsigned int i=0; i<nf; i++) {            norm += af_[i] * af_[i] ;        }        unsigned int nl = al_.size() ;        for(unsigned int i=0; i<nl; i++) {            norm += al_[i] * al_[i] ;        }        norm = sqrt(norm) ;        assert( fabs(norm)>1e-40 );        scale_row(weight / norm) ;    }    void scale_row(CoeffType s) {        check_state(IN_ROW) ;        unsigned int nf = af_.size() ;         for(unsigned int i=0; i<nf; i++) {             af_[i] *= s ;         }         unsigned int nl = al_.size() ;         for(unsigned int i=0; i<nl; i++) {             al_[i] *= s ;         }         bk_ *= s ;    }    void end_row() {        if(least_squares_) {            unsigned int nf = af_.size() ;            unsigned int nl = al_.size() ;            for(unsigned int i=0; i<nf; i++) {                for(unsigned int j=0; j<nf; j++) {                    A_->add_coef(if_[i], if_[j], af_[i] * af_[j]) ;                }            }            CoeffType S = - bk_ ;            for(unsigned int j=0; j<nl; j++) {                S += al_[j] * xl_[j] ;            }            for(unsigned int i=0; i<nf; i++) {                (*b_)[if_[i]] -= af_[i] * S ;            }        } else {            unsigned int nf = af_.size() ;            unsigned int nl = al_.size() ;            for(unsigned int i=0; i<nf; i++) {                A_->add_coef(current_row_, if_[i], af_[i]) ;            }            (*b_)[current_row_] = bk_ ;            for(unsigned int i=0; i<nl; i++) {                (*b_)[current_row_] -= al_[i] * xl_[i] ;            }        }        current_row_++ ;        transition(IN_ROW, IN_SYSTEM) ;    }    void end_system() {        transition(IN_SYSTEM, CONSTRUCTED) ;    }    // ----------------------------- Solver -------------------------------    // Solves a linear system or minimizes a quadratic form.    // Return true on success.    // (modified for SparseLinearAlgebraTraits_d concept)    bool solve()    {        check_state(CONSTRUCTED) ;        // Solve the sparse linear system "A*X = B". On success, the solution is (1/D) * X.        Traits solver_traits;        CoeffType D;        bool success = solver_traits.linear_solver(*A_, *b_, *x_, D) ;        assert(D == 1.0);   // WARNING: this library does not support homogeneous coordinates!        vector_to_variables() ;        transition(CONSTRUCTED, SOLVED) ;        delete A_ ; A_ = NULL ;        delete b_ ; b_ = NULL ;        delete x_ ; x_ = NULL ;        return success;    }protected:    // ----------- Converting between user representation and the internal representation -----    void vector_to_variables() {        for(int ii=0; ii < nb_variables(); ii++) {            Variable& v = variable(ii) ;            if(!v.is_locked()) {                v.set_value( (*x_)[v.index()] ) ;            }        }    }    void variables_to_vector() {        for(int ii=0; ii < nb_variables(); ii++) {            Variable& v = variable(ii) ;            if(!v.is_locked()) {                (*x_)[v.index()] = v.value() ;            }        }    }    // ----------- Finite state automaton (checks that calling sequence is respected) ---------    std::string state_to_string(State s) {            switch(s) {            case INITIAL:                return "initial" ;            case IN_SYSTEM:                return "in system" ;            case IN_ROW:                return "in row" ;            case CONSTRUCTED:                return "constructed" ;            case SOLVED:                return "solved" ;            }            // Should not go there.            assert(false) ;            return "undefined" ;    }    void check_state(State s) {            if(state_ != s) {                std::cerr << "Wrong state, expected: "                     << state_to_string(s)                     << " got:"                     << state_to_string(state_)                     << std::endl ;                std::cerr << "exiting ..." << std::endl ;            }            assert(state_ == s) ;    }    void transition(State from, State to) {            check_state(from) ;            state_ = to ;    }private:    // --------------- parameters --------------------------    bool least_squares_ ;    // --------------- user representation --------------    unsigned int nb_variables_ ;    Variable* variable_ ;    // --------------- construction -----------------------    State state_ ;    unsigned int current_row_ ;    std::vector<CoeffType> af_ ;    std::vector<unsigned int> if_ ;    std::vector<CoeffType> al_ ;    std::vector<CoeffType> xl_ ;    double bk_ ;    // --------------- internal representation ---------    Matrix* A_ ;    Vector* x_ ;    Vector* b_ ;} ;}; // namespace OpenNL#endif

⌨️ 快捷键说明

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