summaryrefslogtreecommitdiff
path: root/modules/sparse/macros/qmr.sci
diff options
context:
space:
mode:
Diffstat (limited to 'modules/sparse/macros/qmr.sci')
-rwxr-xr-xmodules/sparse/macros/qmr.sci491
1 files changed, 491 insertions, 0 deletions
diff --git a/modules/sparse/macros/qmr.sci b/modules/sparse/macros/qmr.sci
new file mode 100755
index 000000000..739058377
--- /dev/null
+++ b/modules/sparse/macros/qmr.sci
@@ -0,0 +1,491 @@
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) XXXX-2008 - INRIA
+// Copyright (C) 2005 - IRISA - Sage Group
+
+//
+// This file must be used under the terms of the CeCILL.
+// This source file is licensed as described in the file COPYING, which
+// you should have received as part of this distribution. The terms
+// are also available at
+// http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+
+
+// [x, flag, err, iter, res] = qmr( A, Ap, b, x, M1, M1p, M2, M2p, max_it, tol )
+//
+// QMR solves the linear system Ax=b using the
+// Quasi Minimal Residual method with preconditioning.
+//
+// input A REAL matrix or function
+// x REAL initial guess vector
+// b REAL right hand side vector
+// M1 REAL left preconditioner matrix
+// M2 REAL right preconditioner matrix
+// max_it INTEGER maximum number of iterations
+// tol REAL error tolerance
+//
+// output x REAL solution vector
+// flag INTEGER: 0: solution found to tolerance
+// 1: no convergence given max_it
+// breakdown:
+// -1: rho
+// -2: Beta
+// -3: gam
+// -4: delta
+// -5: ep
+// -6: xi
+// err REAL final residual norm
+// iter INTEGER number of iterations performed
+// res REAL residual vector
+
+// Details of this algorithm are described in
+//
+// "Templates for the Solution of Linear Systems: Building Blocks
+// for Iterative Methods",
+// Barrett, Berry, Chan, Demmel, Donato, Dongarra, Eijkhout,
+// Pozo, Romine, and Van der Vorst, SIAM Publications, 1993
+// (ftp netlib2.cs.utk.edu; cd linalg; get templates.ps).
+//
+// "Iterative Methods for Sparse Linear Systems, Second Edition"
+// Saad, SIAM Publications, 2003
+// (ftp ftp.cs.umn.edu; cd dept/users/saad/PS; get all_ps.zip).
+
+// Sage Group (IRISA, 2005)
+
+function [x, flag, err, iter, res] = qmr( A, varargin)
+
+ // -----------------------
+ // Parsing input arguments
+ // -----------------------
+ [lhs,rhs]=argn(0);
+ if ( rhs < 2 ),
+ error(msprintf(gettext("%s: Wrong number of input arguments: At least %d expected.\n"),"qmr",2));
+ end
+
+ // Parsing the matrix A
+ select type(A)
+ case 1 then
+ cpt=1;
+ case 5 then
+ cpt=1;
+ case 13 then
+ cpt=0;
+ else
+ error(msprintf(gettext("%s: Wrong type for input argument #%d : A real or complex matrix or a sparse matrix or a function expected.\n"),"qmr",1));
+ end
+
+ // If A is a matrix (dense or sparse)
+ if (cpt==1),
+ if (size(A,1) ~= size(A,2)),
+ error(msprintf(gettext("%s: Wrong size for input argument #%d: Square matrix expected.\n"),"qmr",1));
+ end
+ fct=0;
+ cptmat = 1;
+ end
+
+ // If A is a function
+ if (cpt==0),
+ fct = 0;
+ if rhs >= 2,
+ funcorvec=varargin(1);
+ if and(type(funcorvec) <> [1 5 13]) then
+ error(msprintf(gettext("%s: Wrong value for input argument #%d: Transpose of the function %s expected.\n"),"qmr",2,"A"));
+ // if the following input argument is a sparse or dense matrix
+ elseif or(type(funcorvec) == [1 5]) then
+ if size(getfield(1,macrovar(A)),"*") == 1 then
+ error(msprintf(gettext("%s: Wrong type for input argument #%d: A transpose of the function %s expected.\n"), "qmr", 2, "A"));
+ end
+ matvec = A;
+ cptmat = 1;
+ // if the following input argument is a function
+ else
+ matvec = A;
+ matvecp = funcorvec;
+ cptmat = 2;
+ fct = 1;
+ warning(msprintf(gettext("%s : Calling qmr(A,Ap) is deprecated. Please see qmr documentation for more details.\n"),"qmr"));
+ end
+ end
+ end
+
+ // Parsing right hand side b
+ if ( rhs >= fct+2 ),
+ b=varargin(fct+1);
+ // if b is not constant or sparse
+ if and(type(b) <> [1 5]) then
+ error(msprintf(gettext("%s: Wrong type for input argument #%d: A real or complex, full or sparse column vector expected.\n"), "qmr", fct+2));
+ end
+ if ( size(b,2) ~= 1),
+ error(msprintf(gettext("%s: Wrong size for input argument #%d: Column vector expected.\n"),"qmr",fct+2));
+ end
+ end
+
+ // Parsing initial vector x
+ if ( rhs >= fct+3),
+ x=varargin(fct+2);
+ // if x is not constant or sparse
+ if and(type(x) <> [1 5]) then
+ error(msprintf(gettext("%s: Wrong type for input argument #%d: A real or complex, full or sparse column vector expected.\n"), "qmr", fct + 3));
+ end
+ if (size(x,2) ~= 1),
+ error(msprintf(gettext("%s: Wrong size for input argument #%d: Column vector expected.\n"),"qmr",fct+3));
+ end
+ if ( size(x,1) ~= size(b,1)),
+ error(msprintf(gettext("%s: Wrong size for input argument #%d: Same size as input argument #%d expected.\n"),"qmr",fct+3,fct+2));
+ end
+ // By default
+ else
+ x=zeros(size(b,1),1);
+ end
+
+ //--------------------------------------------------------
+ // Parsing of the preconditioner matrix M1
+ //--------------------------------------------------------
+ if (rhs >=fct+4),
+ Prec_g=varargin(fct+3);
+ select type(Prec_g)
+ case 1 then
+ cpt=1;
+ case 5 then
+ cpt=1;
+ case 13 then
+ cpt=0;
+ else
+ error(msprintf(gettext("%s: Wrong type for input argument #%d: A real or complex, full or sparse, square matrix or a function expected.\n"), "qmr", fct + 4));
+ end
+
+ // if M1 is a matrix
+ if ( cpt==1 ),
+ if (size(Prec_g,1) ~= size(Prec_g,2)),
+ error(msprintf(gettext("%s: Wrong size for input argument #%d: Square matrix expected.\n"),"qmr",fct+4));
+ end
+ if (size(Prec_g,1)~=size(b,1)),
+ error(msprintf(gettext("%s: Wrong size for input argument #%d: Same size as input argument #%d expected.\n"),"qmr",fct+4,fct+2));
+ end
+ cptmatM1 = 1;
+ end
+
+ // if M1 is a function
+ if ( cpt==0 ),
+ precond_g = Prec_g;
+ cptmatM1 = 1;
+ if ( rhs >= fct+5 & size(getfield(1,macrovar(precond_g)),"*") == 1),
+ Precp_g = varargin(fct+4);
+ if (type(Precp_g) == 13 & size(getfield(1,macrovar(Precp_g)),"*")==1) then
+ //precond_g = Prec_g;
+ precondp_g = Precp_g;
+ cptmatM1 = 2;
+ fct = fct+1;
+ warning(msprintf(gettext("%s : Calling qmr(...,M1,M1p) is deprecated. Please see qmr documentation for more details.\n"),"qmr"));
+ else
+ error(msprintf(gettext("%s: Wrong type for input argument #%d: A transpose of the function expected.\n"), "qmr", fct + 5));
+ end
+ elseif rhs < fct+5 & size(getfield(1, macrovar(precond_g)), "*") == 1 then
+ error(msprintf(gettext("%s: Wrong prototype of input argument #%d: If M1 is function, use the header M1(x,t) instead M1(x).\n"), "qmr", fct+4));
+ end
+ end
+ // By default
+ else
+ deff("y=precond_g(x)","y=x");
+ deff("y=precondp_g(x)","y=x");
+ cptmatM1 = 2;
+ end
+
+ //--------------------------------------------------------
+ // Parsing of the preconditioner matrix M2
+ //--------------------------------------------------------
+ if (rhs >=fct+5),
+ Prec_d=varargin(fct+4);
+ select type(Prec_d)
+ case 1 then
+ cpt=1;
+ case 5 then
+ cpt=1;
+ case 13 then
+ cpt=0;
+ else
+ error(msprintf(gettext("%s: Wrong type for input argument #%d: A real or complex, full or sparse, square matrix or a function expected.\n"), "qmr", fct + 5));
+ end
+
+ // M2 matrix
+ if ( cpt==1 ),
+
+ if (size(Prec_d,1) ~= size(Prec_d,2)),
+ error(msprintf(gettext("%s: Wrong size for input argument #%d: Square matrix expected.\n"),"qmr",fct+5));
+ end
+ if (size(Prec_d,1)~=size(b,1)),
+ error(msprintf(gettext("%s: Wrong size for input argument #%d: Same size as input argument #%d expected.\n"),"qmr",fct+5,fct+2));
+ end
+ cptmatM2 = 1;
+
+ end
+
+ // M2 function
+ if ( cpt==0 )
+ precond_d = Prec_d;
+ cptmatM2 = 1;
+ if ( rhs >= fct+6 & size(getfield(1,macrovar(precond_d)),"*") == 1),
+ Precp_d=varargin(fct+5);
+ if (type(Precp_d) == 13 & size(getfield(1,macrovar(Precp_d)),"*") == 1) then
+ precond_d = Prec_d;
+ precondp_d = Precp_d;
+ cptmatM2 = 2;
+ fct = fct+1;
+ warning(msprintf(gettext("%s : Calling qmr(...,M2,M2p) is deprecated. Please see qmr documentation for more details.\n"),"qmr"));
+ else
+ error(msprintf(gettext("%s: Wrong type for input argument #%d: A transpose of the function expected.\n"), "qmr", fct + 6));
+ end
+ elseif rhs < fct+6 & size(getfield(1, macrovar(precond_d)), "*") == 1 then
+ error(msprintf(gettext("%s: Wrong prototype of input argument #%d: If M2 is function, use the header M2(x,t) instead M2(x).\n"), "qmr", fct+5));
+ end
+ end
+ // By default
+ else
+ deff("y=precond_d(x)","y=x");
+ deff("y=precondp_d(x)","y=x");
+ cptmatM2 = 2;
+ end
+
+ //--------------------------------------------------------
+ // Parsing of the maximum number of iterations max_it
+ //--------------------------------------------------------
+ if (rhs >= fct+6),
+ max_it=varargin(fct+5);
+ // if max_it is not constant
+ if type(max_it) <> 1 then
+ error(msprintf(gettext("%s: Wrong type for input argument #%d: Scalar expected.\n"),"qmr",fct + 6));
+ end
+
+ if ~isreal(max_it) then
+ error(msprintf(gettext("%s: Wrong type for input argument #%d: A real scalar expected.\n"),"qmr",fct + 6));
+ end
+
+ if (size(max_it,1) ~= 1 | size(max_it,2) ~=1),
+ error(msprintf(gettext("%s: Wrong size for input argument #%d: Scalar expected.\n"),"qmr",fct+6));
+ end
+ // By default
+ else
+ max_it=size(b,1);
+ end
+
+ //--------------------------------------------------------
+ // Parsing of the error tolerance tol
+ //--------------------------------------------------------
+ if (rhs == fct+7),
+ tol=varargin(fct+6);
+ // if tol is not constant
+ if type(tol) <> 1 then
+ error(msprintf(gettext("%s: Wrong type for input argument #%d: Scalar expected.\n"),"qmr",fct + 7));
+ end
+
+ if ~isreal(tol) then
+ error(msprintf(gettext("%s: Wrong type for input argument #%d: A real scalar expected.\n"),"qmr",fct + 7));
+ end
+
+ if (size(tol,1) ~= 1 | size(tol,2) ~=1),
+ error(msprintf(gettext("%s: Wrong size for input argument #%d: Scalar expected.\n"),"qmr",fct+7));
+ end
+ // By default
+ else
+ tol=1000*%eps;
+ end
+
+ //--------------------------------------------------------
+ // test about input arguments number
+ //--------------------------------------------------------
+ if (rhs > fct+7),
+ error(msprintf(gettext("%s: Wrong number of input arguments: %d to %d expected.\n"),"qmr",2,fct+7));
+ end
+
+ // ------------
+ // Computations
+ // ------------
+
+ // initialization
+ i = 0;
+ flag = 0;
+ iter = 0;
+ bnrm2 = norm( b );
+ if (bnrm2 == 0.0),
+ bnrm2 = 1.0;
+ end
+
+ // r = b - A*x;
+ if (cptmat == 1) then
+ r = b - matvec(x,"notransp");
+ elseif (cptmat==2) then // If A is a function
+ r = b - matvec(x);
+ end
+
+ err = norm( r ) / bnrm2;
+ res = err;
+ if ( err < tol ), return; end
+
+ // [M1,M2] = lu( M );
+ v_tld = r;
+
+ // y = M1 \ v_tld;
+ if (cptmatM1 == 1) then
+ y = precond_g(v_tld,"notransp");
+ elseif (cptmatM1==2) then
+ y = precond_g(v_tld);
+ end
+
+ rho = norm( y );
+
+ w_tld = r;
+ // z = M2' \ w_tld;
+ if (cptmatM2 == 1) then
+ z = precond_d(w_tld,"transp");
+ elseif (cptmatM2 == 2) then
+ z = precondp_d(w_tld);
+ end
+
+ xi = norm( z );
+
+ gam = 1.0;
+ eta = -1.0;
+ theta = 0.0;
+
+ for i = 1:max_it, // begin iteration
+ if ( rho == 0.0 | xi == 0.0 ), iter=i; break; end
+ v = v_tld / rho;
+ y = y / rho;
+
+ w = w_tld / xi;
+ z = z / xi;
+
+ delta = z'*y;
+ if ( delta == 0.0 ), iter=i; break; end
+
+ // y_tld = M2 \ y;
+ if (cptmatM2 == 1) then
+ y_tld = precond_d(y,"notransp");
+ elseif (cptmatM2 == 2) then
+ y_tld = precond_d(y);
+ end
+
+ // z_tld = M1'\ z;
+ if (cptmatM1 == 1) then
+ z_tld = precond_g(z,"transp");
+ elseif (cptmatM1 == 2) then
+ z_tld = precondp_g(z);
+ end
+
+ if ( i > 1 ), // direction vector
+ p = y_tld - ( xi*delta / ep )*p;
+ q = z_tld - ( rho*delta / ep )*q;
+ else
+ p = y_tld;
+ q = z_tld;
+ end
+
+ // p_tld = A*p;
+ if (cptmat == 1) then
+ p_tld = matvec(p,"notransp");
+ elseif (cptmat == 2) then
+ p_tld = matvec(p);
+ end
+
+ ep = q'*p_tld;
+ if ( ep == 0.0 ), iter=i; break; end
+
+ Beta = ep / delta;
+ if ( Beta == 0.0 ), iter=i; break; end
+
+ v_tld = p_tld - Beta*v;
+
+ // y = M1 \ v_tld;
+ if (cptmatM1 == 1) then
+ y = precond_g(v_tld,"notransp");
+ elseif (cptmatM1==2) then
+ y = precond_g(v_tld);
+ end
+
+ rho_1 = rho;
+ rho = norm( y );
+
+ // w_tld = ( A'*q ) - ( Beta*w );
+ if (cptmat == 1) then
+ w_tld = ( matvec(q,"transp") ) - ( Beta*w );
+ elseif (cptmat == 2) then
+ w_tld = ( matvecp(q) ) - ( Beta*w );
+ end
+
+ // z = M2' \ w_tld;
+ if (cptmatM2 == 1) then
+ z = precond_d(w_tld,"transp");
+ elseif (cptmatM2 == 2) then
+ z = precondp_d(w_tld);
+ end
+
+ xi = norm( z );
+ gamma_1 = gam;
+ theta_1 = theta;
+ theta = rho / ( gamma_1*Beta );
+ gam = 1.0 / sqrt( 1.0 + (theta^2) );
+ if ( gam == 0.0 ), iter=i; break; end
+
+ eta = -eta*rho_1*(gam^2) / ( Beta*(gamma_1^2) );
+
+ if ( i > 1 ), // compute adjustment
+ d = eta*p + (( theta_1*gam )^2)*d;
+ s = eta*p_tld + (( theta_1*gam )^2)*s;
+ else
+ d = eta*p;
+ s = eta*p_tld;
+ end
+ x = x + d; // update approximation
+
+ r = r - s; // update residual
+ err = norm( r ) / bnrm2; // check convergence
+ res = [res;err];
+
+ if ( err <= tol ), iter=i; break; end
+
+ if ( i == max_it ), iter=i; end
+ end
+
+ if ( err <= tol ), // converged
+ flag = 0;
+ elseif ( rho == 0.0 ), // breakdown
+ flag = -1;
+ elseif ( Beta == 0.0 ),
+ flag = -2;
+ elseif ( gam == 0.0 ),
+ flag = -3;
+ elseif ( delta == 0.0 ),
+ flag = -4;
+ elseif ( ep == 0.0 ),
+ flag = -5;
+ elseif ( xi == 0.0 ),
+ flag = -6;
+ else // no convergence
+ flag = 1;
+ end
+
+endfunction
+
+function y = matvec(x,t)
+ if (t=="notransp") then
+ y = A*x;
+ elseif (t=="transp") then
+ y = A'*x;
+ end
+endfunction
+
+function y = precond_g(x,t)
+ if (t=="notransp") then
+ y = Prec_g*x;
+ elseif (t=="transp") then
+ y = Prec_g'*x;
+ end
+endfunction
+
+function y = precond_d(x,t)
+ if (t=="notransp") then
+ y = Prec_d*x;
+ elseif (t=="transp") then
+ y = Prec_d'*x;
+ end
+endfunction
+