Fixed bug in Bi-CGSTAB solver when omega==0, which may happen for small linear systems.

Added traces.
This commit is contained in:
Laurent Saboret 2008-08-25 15:26:38 +00:00
parent f524fb618e
commit e5db27afdc
1 changed files with 62 additions and 28 deletions

View File

@ -26,10 +26,10 @@
* URL=http://www.loria.fr/~levy/php/article.php?pub=../publications/papers/2005/Numerics
* }
*
* Laurent Saboret 2005-2006: Changes for CGAL:
* Laurent Saboret 2005-2008: Changes for CGAL:
* - Added OpenNL namespace
* - solve() returns true on success
* - test divisions by zero with IsZero() method
* - check divisions by zero
* - added comments and traces
* - copied BICGSTAB algorithm WITH preconditioner from Graphite 1.9 code
*/
@ -88,6 +88,9 @@ public:
// 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
@ -106,21 +109,20 @@ public:
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) ; // Current residue r=A*x-b
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( ! IsZero( BLAS<Vector>::dot(rT,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); // Current error rTr = (r|r)
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);
if (IsZero(rTAd))
break; // stop if bad conditioning
CGAL_assertion(rTAd != 0.0);
alpha=rTh/rTAd;
BLAS<Vector>::axpy(-alpha,Ad,r);
BLAS<Vector>::copy(h,s);
@ -130,24 +132,36 @@ public:
BLAS<Vector>::scal(alpha,u);
st=BLAS<Vector>::dot(s,t);
tt=BLAS<Vector>::dot(t,t);
if ( IsZero(st) || IsZero(tt) )
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 (IsZero(omega))
break; // stop if bad conditioning
if (IsZero(rTh))
break; // stop if bad conditioning
beta=(alpha/omega)/rTh; rTh=BLAS<Vector>::dot(rT,h); beta*=rTh;
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);
rTr=BLAS<Vector>::dot(r,r);
++its;
}
@ -215,6 +229,9 @@ public:
// 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
@ -234,22 +251,27 @@ public:
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) ; // Current residue r=A*x-b
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( ! IsZero( BLAS<Vector>::dot(rT,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); // Current error rTr = (r|r)
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 (IsZero(rTSd))
break; // stop if bad conditioning
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);
@ -260,24 +282,36 @@ public:
BLAS<Vector>::scal(alpha,u);
st=BLAS<Vector>::dot(s,t);
tt=BLAS<Vector>::dot(t,t);
if ( IsZero(st) || IsZero(tt) )
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 (IsZero(omega))
break; // stop if bad conditioning
if (IsZero(rTh))
break; // stop if bad conditioning
beta=(alpha/omega)/rTh; rTh=BLAS<Vector>::dot(rT,h); beta*=rTh;
BLAS<Vector>::scal(beta,d);
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);
rTr=BLAS<Vector>::dot(r,r);
++its;
}