dust3d/thirdparty/cgal/CGAL-4.13/include/CGAL/OpenNL/bicgstab.h

345 lines
12 KiB
C
Raw Normal View History

// Copyright (c) 2005-2008 Inria Loria (France).
/*
* 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 as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* 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-2008: Changes for CGAL:
* - Added OpenNL namespace
* - solve() returns true on success
* - check divisions by zero
* - added comments and traces
* - copied BICGSTAB algorithm WITH preconditioner from Graphite 1.9 code
*
* $URL$
* $Id$
* SPDX-License-Identifier: LGPL-3.0+
*/
#ifndef __OPENNL_BICGSTAB__
#define __OPENNL_BICGSTAB__
#include <CGAL/OpenNL/blas.h>
#include <CGAL/assertions.h>
#include <cmath>
#include <cfloat>
#include <climits>
#include <limits>
namespace OpenNL {
/**
* The BICGSTAB 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_BICGSTAB {
public:
typedef MATRIX Matrix ;
typedef VECTOR Vector ;
typedef typename Vector::CoeffType CoeffType ;
public:
Solver_BICGSTAB() {
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". Return true on success.
bool solve(const MATRIX &A, const VECTOR& b, VECTOR& x)
{
#ifdef DEBUG_TRACE
std::cerr << " Call BICGSTAB" << std::endl;
#endif
CGAL_assertion(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 rT(n) ; // Initial residue rT=Ax-b
Vector d(n) ;
Vector h(n) ;
Vector u(n) ;
Vector Ad(n) ;
Vector t(n) ;
Vector& s = h ;
CoeffType rTh, rTAd, rTr, alpha, beta, omega, st, tt;
unsigned int its=0; // Loop counter
CoeffType err=epsilon_*epsilon_*BLAS<Vector>::dot(b,b); // Error to reach
Vector r(n) ; // residue r=A*x-b
mult(A,x,r);
BLAS<Vector>::axpy(-1,b,r);
BLAS<Vector>::copy(r,d);
BLAS<Vector>::copy(d,h);
BLAS<Vector>::copy(h,rT);
//CGAL_assertion(BLAS<Vector>::dot(rT,rT) == 0.0); // may happen for small systems
rTh=BLAS<Vector>::dot(rT,h); // rTh = (rT|h)
rTr=BLAS<Vector>::dot(r,r); // error rTr = (r|r)
while ( rTr>err && its < max_iter) {
mult(A,d,Ad);
rTAd=BLAS<Vector>::dot(rT,Ad);
CGAL_assertion(rTAd != 0.0);
alpha=rTh/rTAd;
BLAS<Vector>::axpy(-alpha,Ad,r);
BLAS<Vector>::copy(h,s);
BLAS<Vector>::axpy(-alpha,Ad,s);
mult(A,s,t);
BLAS<Vector>::axpy(1,t,u);
BLAS<Vector>::scal(alpha,u);
st=BLAS<Vector>::dot(s,t);
tt=BLAS<Vector>::dot(t,t);
if (st == 0.0 || tt == 0.0)
omega = 0 ;
else
omega = st/tt;
BLAS<Vector>::axpy(-omega,t,r);
BLAS<Vector>::axpy(-alpha,d,x);
BLAS<Vector>::axpy(-omega,s,x);
rTr=BLAS<Vector>::dot(r,r);
BLAS<Vector>::copy(s,h);
BLAS<Vector>::axpy(-omega,t,h);
if (omega == 0.0) // stop if omega==0 (success)
{
#ifdef DEBUG_TRACE
std::cerr << " BICGSTAB: omega=0" << std::endl;
#endif
break;
}
if (rTh == 0.0) // stop if rTh==0 (failure)
{
#ifdef DEBUG_TRACE
std::cerr << " BICGSTAB: rTh=0" << std::endl;
#endif
break;
}
beta=(alpha/omega)/rTh; // beta = (rTh/"old rTh") * (alpha/omega)
rTh=BLAS<Vector>::dot(rT,h);
beta*=rTh;
BLAS<Vector>::scal(beta,d);
BLAS<Vector>::axpy(1,h,d);
BLAS<Vector>::axpy(-beta*omega,Ad,d);
++its;
}
bool success = (rTr <= err);
return success;
}
private:
// Test if a floating point number is (close to) 0.0
static bool IsZero(CoeffType a)
{
return (std::fabs(a) < 10.0 * (std::numeric_limits<CoeffType>::min)());
}
private:
CoeffType epsilon_ ;
unsigned int max_iter_ ;
} ;
/**
* The BICGSTAB 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_BICGSTAB
{
public:
typedef MATRIX Matrix ;
typedef PC_MATRIX Preconditioner ;
typedef VECTOR Vector ;
typedef typename Vector::CoeffType CoeffType ;
public:
Solver_preconditioned_BICGSTAB() {
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". Return true on success.
bool solve(const MATRIX &A, const PC_MATRIX &C, const VECTOR& b, VECTOR& x)
{
#ifdef DEBUG_TRACE
std::cerr << " Call BICGSTAB with preconditioner" << std::endl;
#endif
CGAL_assertion(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 rT(n) ; // Initial residue rT=Ax-b
Vector d(n) ;
Vector h(n) ;
Vector u(n) ;
Vector Sd(n) ;
Vector t(n) ;
Vector aux(n) ;
Vector& s = h ;
CoeffType rTh, rTSd, rTr, alpha, beta, omega, st, tt;
unsigned int its=0; // Loop counter
CoeffType err=epsilon_*epsilon_*BLAS<Vector>::dot(b,b); // Error to reach
Vector r(n) ; // residue r=A*x-b
mult(A,x,r);
BLAS<Vector>::axpy(-1,b,r);
mult(C,r,d);
BLAS<Vector>::copy(d,h);
BLAS<Vector>::copy(h,rT);
//CGAL_assertion(BLAS<Vector>::dot(rT,rT) == 0.0); // may happen for small systems
rTh=BLAS<Vector>::dot(rT,h); // rTh = (rT|h)
rTr=BLAS<Vector>::dot(r,r); // error rTr = (r|r)
while (rTr>err && its < max_iter) {
mult(A,d,aux);
mult(C,aux,Sd);
rTSd=BLAS<Vector>::dot(rT,Sd);
if (rTSd == 0.0) // stop if rTSd==0 (failure)
{
#ifdef DEBUG_TRACE
std::cerr << " BICGSTAB with preconditioner: rTSd=0" << std::endl;
#endif
break;
}
alpha=rTh/rTSd;
BLAS<Vector>::axpy(-alpha,aux,r);
BLAS<Vector>::copy(h,s);
BLAS<Vector>::axpy(-alpha,Sd,s);
mult(A,s,aux);
mult(C,aux,t);
BLAS<Vector>::axpy(1,t,u);
BLAS<Vector>::scal(alpha,u);
st=BLAS<Vector>::dot(s,t);
tt=BLAS<Vector>::dot(t,t);
if (st == 0.0 || tt == 0.0)
omega = 0 ;
else
omega = st/tt;
BLAS<Vector>::axpy(-omega,aux,r);
BLAS<Vector>::axpy(-alpha,d,x);
BLAS<Vector>::axpy(-omega,s,x);
rTr=BLAS<Vector>::dot(r,r);
BLAS<Vector>::copy(s,h);
BLAS<Vector>::axpy(-omega,t,h);
if (omega == 0.0) // stop if omega==0 (success)
{
#ifdef DEBUG_TRACE
std::cerr << " BICGSTAB with preconditioner: omega=0" << std::endl;
#endif
break;
}
if (rTh == 0.0) // stop if rTh==0 (failure)
{
#ifdef DEBUG_TRACE
std::cerr << " BICGSTAB with preconditioner: rTh=0" << std::endl;
#endif
break;
}
beta=(alpha/omega)/rTh; // beta = (rTh/"old rTh") * (alpha/omega)
rTh=BLAS<Vector>::dot(rT,h);
beta*=rTh;
BLAS<Vector>::scal(beta,d); // d = h + beta * (d - omega * Sd);
BLAS<Vector>::axpy(1,h,d);
BLAS<Vector>::axpy(-beta*omega,Sd,d);
++its;
}
bool success = (rTr <= err);
return success;
}
private:
// Test if a floating point number is (close to) 0.0
static bool IsZero(CoeffType a)
{
return (std::fabs(a) < 10.0 * (std::numeric_limits<CoeffType>::min)());
}
private:
CoeffType epsilon_ ;
unsigned int max_iter_ ;
} ;
} // namespace OpenNL
#endif // __OPENNL_BICGSTAB__