strange bicg vs. bicgstab behaviour for same matrix
david moloney <[email protected]> Tue, 09 Nov 2004 15:02:49 +0000
| Newsgroups | gmane.comp.lib.mtl.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi all, I am using a number of Matrix-Market matrices as test cases for some work I am doing using mtl and itl. I have found that a number of these matrices produce QNaNs from the two_norm() function in mtl when bicgstab is used and behave correctly when the bicg solver from itl is used. The only way that a QNaN can be produced from mtl::two_norm() according to the IEEE standard, is if the square-root of a negative number is taken. This however is impossible as two_norm() is the sum of the squares of the elements of a vector b and all of the elements of b are set to 1 initially. On the first iteration the result returned by two_norm should be sqrt(822), where 822 is the numbers of columns and rows in the A matrix. Incidentally sqrt(822) = 28.67054 as can be seen in the first iteration of both versions of the program below. The summation on the other hand can produce a QNaN if one or other element of b when squared is infinity, but the fact that bicgstab succeeds suggests this is not the case. The matrix used is bp__1600.mtx from the matrix-market test-suite (http://math.nist.gov/MatrixMarket/data/Harwell-Boeing/smtape/bp__1600.html) and the code (modified from itl example code) is attached. Any opinions welcome, - David ************************************************************************************** bicg results ************************************************************************************** iteration 0: resid 28.6705 finished! error code = 2 0 iterations 28.6705 is actual final residual. 1 is actual relative tolerance achieved. Relative tol: 1e-006 Absolute tol: 0 Solving bp__1600.mtx using itl/bicg Summary of results for bp__1600.mtx ----------------------------------------- converged Y # iterations 0 normb 28.6705 final residual 28.6705 True Residual 28.6705 Target relative tolerance 1e-006 Target absolute tolerance 0 Achieved relative tolerance 1 ----------------------------------------- ************************************************************************************** bicgstab results ************************************************************************************** normr_ = 28.6705 resid_[1] = r[28.6705]/normb[28.6705] iteration 0: resid 28.6705 normr_ = 1.#QNAN resid_[1.#QNAN] = r[1.#QNAN]/normb[28.6705] iteration 0: resid 1.#QNAN finished! error code = 0 0 iterations 1.#QNAN is actual final residual. 1.#QNAN is actual relative tolerance achieved. Relative tol: 1e-006 Absolute tol: 0 Solving bp__1600.mtx using itl/bicgstab Summary of results for bp__1600.mtx ---------------------------------------- converged N # iterations 0 normb 28.6705 final residual 1.#QNAN True Residual 1.#QNAN Target relative tolerance 1e-006 Target absolute tolerance 0 Achieved relative tolerance 1.#QNAN ----------------------------------------- _______________________________________________ This list is archived at http://www.osl.iu.edu/MailArchives/mtl-devel/
parser.cpp
(text/plain, 7.4 KB)
//==========================================================================
// CVS Information:
//
// $RCSfile: parser.cpp,v $ $Revision: 1.3 $ $State: Exp $
// $Author: llee $ $Date: 2001/10/26 14:28:24 $
// $Locker: $
//---------------------------------------------------------------------------
//
// DESCRIPTION
//
//---------------------------------------------------------------------------
//
// LICENSE AGREEMENT
// $COPYRIGHT$
//---------------------------------------------------------------------------
//
// REVISION HISTORY:
//
// $Log: parser.cpp,v $
// Revision 1.3 2001/10/26 14:28:24 llee
// *** empty log message ***
//
// Revision 1.2 2001/07/05 22:28:58 llee1
// gcc 3.0 fix
//
// Revision 1.1 2000/07/26 21:49:58 llee1
// change file extension from .cc to .cpp
//
// Revision 1.3 2000/07/18 14:30:44 llee1
// *** empty log message ***
//
// Revision 1.2 2000/07/17 15:44:06 llee1
// *** empty log message ***
//
//
//===========================================================================
#include <iostream>
#include "parser.h"
#if defined ITL_NO_SSTREAM
#include <stdio.h>
#else
#include <sstream>
#endif
#include <assert.h>
namespace std {
parser::parser(int argc, char* argv[], const string& delim) {
string raw_data;
//copy argv to raw_data;
for (int i=1; i<argc; ++i) {
raw_data += argv[i];
raw_data += " ";
}
remove_special_character(raw_data, '=');
split(delim, raw_data);
}
void parser::register_flag (const string& flag, int i, const string& mesg) {
registers[flag] = i;
messages[flag] = mesg;
}
bool parser::flags_coexist (const string& flag1, const string& flag2,
bool coexist) {
bool found1 = seg.find(flag1) != seg.end();
bool found2 = seg.find(flag2) != seg.end();
if ( coexist ) {
if ( found1 != found2 ) {
cerr << flag1 << " and " << flag2
<< " must be both in the comand line. Exiting ..." << endl;
assert(false);
}
} else if ( found1 && found2 ) {
cerr << flag1 << " and " << flag2
<< " cannot be both in the comand line. Exiting ..." << endl;
//exit
assert(false);
}
return found1 && found2 != coexist;
}
#if defined ITL_NO_SSTREAM
void parser::get(const string& flag, double& value, double d) {
if ( registers.find(flag) == registers.end() ) {
cerr << flag << " is not registered! Exiting..." << endl;
assert(false);
}
map<string,string>::iterator i = seg.find(flag);
if ( i == seg.end() )
value = d;
else {
if ( registers[flag] == 0 )
value = ! d; //not the default
else if ((*i).second.size()==0) {
cerr << flag << " requires a value." << endl
<< " Please provid it right after the flag with whitespace "
<< endl << " or equal sign between flag and value." << endl;
assert(false);
} else {
sscanf((*i).second.data(), "%lf", &value);
}
}
}
void parser::get(const string& flag, int& value, int d) {
if ( registers.find(flag) == registers.end() ) {
cerr << flag << " is not registered! Exiting..." << endl;
assert(false);
}
map<string,string>::iterator i = seg.find(flag);
if ( i == seg.end() )
value = d;
else {
if ( registers[flag] == 0 )
value = ! d; //not the default
else if ((*i).second.size()==0) {
cerr << flag << " requires a value." << endl
<< " Please provid it right after the flag with whitespace "
<< endl << " or equal sign between flag and value." << endl;
assert(false);
} else {
sscanf((*i).second.data(), "%d", &value);
}
}
}
//
// Added by David Moloney to allow string arguments to be extracted
// from argv[] ... for example filenames
//
void parser::get(const string& flag, char*& value, char* d) {
if ( registers.find(flag) == registers.end() ) {
cerr << flag << " is not registered! Exiting..." << endl;
assert(false);
}
map<string,string>::iterator i = seg.find(flag);
if (i==seg.end()) value = d;
else {
if (registers[flag]==0)
value = d; //not the default
else if ((*i).second.size()==0) {
cerr << flag << " requires a value." << endl
<< " Please provid it right after the flag with whitespace "
<< endl << " or equal sign between flag and value." << endl;
assert(false);
}
else {
sscanf((*i).second.data(), "%s", value);
}
}
}
#else
template <typename T>
void parser::get(const string& flag, T& value, const T& d) {
if ( registers.find(flag) == registers.end() ) {
cerr << flag << " is not registered! Exiting..." << endl;
assert(false);
}
map<string,string>::iterator i = seg.find(flag);
if ( i == seg.end() )
value = d;
else {
if ( registers[flag] == 0 )
value = ! d; //not the default
else if ((*i).second.size()==0) {
cerr << flag << " requires a value." << endl
<< " Please provid it right after the flag with whitespace " << endl
<< " or equal sign between flag and value." << endl;
assert(false);
} else {
istringstream iss((*i).second);
iss >> value;
if (iss.fail()) {
cerr << flag << " has an invalid value. Exit..." << endl;
//exit
assert(false);
}
}
}
}
#endif
void parser::help(char *msg) {
string h("--help");
bool found = seg.find(h) != seg.end();
if ( found ) {
cout << endl << endl;
cout << msg << " Usage of flags: " << endl << endl;
for ( map<string,int>::iterator i = registers.begin();
i != registers.end(); ++i) {
cout << " " << (*i).first;
if ( (*i).second )
cout << " <value> ";
cout << ": " << messages[(*i).first] << endl;
}
cout << endl << endl;
}
}
void parser::remove_special_character(string& raw_data, char c) {
char * temp = const_cast<char*>(raw_data.c_str());
for (string::size_type i=0; i<raw_data.size(); ++i)
if ( temp[i] == c )
temp[i] = ' ';
}
void parser::split(const string& delim, const string& raw_data) {
string::size_type pos = 0;
bool cond = true;
while ( cond ) {
string::size_type prev = pos+2;
pos = raw_data.find(delim, prev);
if ( pos == string::npos ) {
pos = raw_data.size();
cond = false;
}
string::size_type s = pos - prev + 2;
halve( raw_data.substr(prev-2, s) );
}
}
//str is one unit include a flag and its (possible) value(s)
//it is not allowed that str is started " "
void parser::halve(const string& str) {
string::size_type pos = str.find(" ");
if ( pos == string::npos )
seg[str] = "";
else
seg[str.substr(0,pos)] = str.substr(pos, str.size());
}
#if !defined ITL_NO_SSTREAM
template
void parser::get(const string& flag, int& value, const int& d);
template
void parser::get(const string& flag, double& value, const double& d);
template
void parser::get(const string& flag, bool& value, const bool& d);
#endif
}
bicg_fail.cpp
(text/plain, 4.4 KB)
#include "mtl/matrix.h"
#include "mtl/mtl.h"
#include "mtl/utils.h"
#include <itl/interface/mtl.h>
#define __DEBUG__ // itl debug on
#define __BICGSTAB__ // Bi-Conjugate Gradient Stablilised Method
#ifdef __BICGSTAB__
#include "itl/preconditioner/ilu.h"
#include "itl/krylov/bicgstab.h"
#endif
//#define __BICG__ // Bi-Conjugate Gradient Method
#ifdef __BICG__
#include "itl/preconditioner/ilu.h"
#include "itl/krylov/bicg.h"
#endif
//#define __CG__ // Conjugate Gradient Method
#ifdef __CG__
#include "itl/preconditioner/cholesky.h"
#include "itl/krylov/cg.h"
#endif
#include "laplacian.h"
#include "parser.h"
using namespace mtl;
using namespace itl;
#include "mtl/matrix_market_stream.h"
#include <iostream>
#include <fstream>
#include <stdio.h>
using std::cin;
using std::ios;
using std::ofstream;
using std::ifstream;
using std::cerr;
using std::cout;
using std::endl;
using std::parser;
typedef double Type;
typedef matrix< Type, rectangle<>, array< compressed<> >, row_major >::type Matrix;
int main (int argc, char* argv[]) {
int converged;
int mx, my, max_it;
double ksp_atol, ksp_rtol;
int N;
int jj;
char *mtxfilename;
if ( argc == 1 ) {
cout << argv[0] << " --help will get your the usage of flags." << endl;
}
parser myparser(argc, argv);
myparser.register_flag("-file", 1, "name of Matrix Market format input file");
myparser.register_flag("-mx", 1, "number of points in x axis in the mesh");
myparser.register_flag("-my", 1, "number of points in y axis in the mesh");
myparser.register_flag("-max_it", 1, "maximal iteration allowed");
myparser.register_flag("-ksp_atol", 1, "Absolute tolerance in KSP iteration");
myparser.register_flag("-ksp_rtol", 1, "Relative tolerance in KSP iteration");
myparser.help(argv[0]);
myparser.get("-file", mtxfilename, "bp__1600.mtx");
myparser.get("-mx", mx, 16 );
myparser.get("-my", my, mx );
myparser.get("-max_it", max_it, 60 );
myparser.get("-ksp_atol", ksp_atol );
myparser.get("-ksp_rtol", ksp_rtol, 1.0e-6 );
N = mx * my;
matrix_market_stream<Type> mms(mtxfilename);
Matrix A(mms);
generate_laplacian_2D(A, mx, my);
dense1D<Type> x(A.nrows(), Type(0));
dense1D<Type> b(A.ncols());
for (dense1D<Type>::iterator i=b.begin(); i!=b.end(); i++)
*i = 1; // initialize all elements of b vector to 1
#ifdef __BICG__
ILU<Matrix> precond(A);
noisy_iteration<Type> iter(b, max_it, ksp_rtol, ksp_atol);
converged = bicg(A, x, b, precond(), iter); //gmres algorithm
cout << endl << " Solving " << mtxfilename << " using itl/bicg" << endl;
#endif // __BICG__
#ifdef __CG__
cholesky<Matrix> precond(A);
cholesky<Matrix>::Precond p = precond(); // identity_preconditioner p;
noisy_iteration<double> iter(b, max_it, ksp_rtol, ksp_atol);
converged = cg(A, x, b, p, iter); //gmres algorithm
cout << endl << " Solving " << mtxfilename << " using itl/cg" << endl;
#endif // __CG__
#ifdef __BICGSTAB__
ILU<Matrix> precond(A);
noisy_iteration<double> iter(b, max_it, ksp_rtol, ksp_atol);
converged = bicgstab(A, x, b, precond(), iter); //gmres algorithm
cout << endl << " Solving " << mtxfilename << " using itl/bicgstab" << endl;
#endif // __BICGSTAB__
//verify the result
//
dense1D<Type> b1(A.ncols());
itl::mult(A, x, b1);
itl::add(b1, itl::scaled(b, -1.), b1);
// report results on VDU
//
cout << endl;
cout << " Summary of results for " << mtxfilename << endl;
cout << "-------------------------------------------------------- " << endl;
cout << " converged " << (converged ? "Y" : "N") << endl;
cout << " # iterations " << iter.iterations() << endl;
cout << " normb " << iter.normb() << endl;
cout << " final residual " << iter.resid() << endl;
cout << " True Residual " << itl::two_norm(b1) << endl;
cout << " Target relative tolerance " << ksp_rtol << endl;
cout << " Target absolute tolerance " << ksp_atol << endl;
cout << " Achieved relative tolerance " << iter.resid()/iter.normb() << endl;
cout << "-------------------------------------------------------- " << endl;
cout << endl;
return 0;
}