home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-02-02 | 29.4 KB | 1,237 lines |
-
- /**************************************************************************
- **
- ** Copyright (C) 1993 David E. Steward & Zbigniew Leyk, all rights reserved.
- **
- ** Meschach Library
- **
- ** This Meschach Library is provided "as is" without any express
- ** or implied warranty of any kind with respect to this software.
- ** In particular the authors shall not be liable for any direct,
- ** indirect, special, incidental or consequential damages arising
- ** in any way from use of the software.
- **
- ** Everyone is granted permission to copy, modify and redistribute this
- ** Meschach Library, provided:
- ** 1. All copies contain this copyright notice.
- ** 2. All modified copies shall carry a notice stating who
- ** made the last modification and the date of such modification.
- ** 3. No charge is made for this software or works derived from it.
- ** This clause shall not be construed as constraining other software
- ** distributed on the same medium as this software, nor is a
- ** distribution fee considered a charge.
- **
- ***************************************************************************/
-
-
- /* iter.c 17/09/93 */
-
- /*
- ITERATIVE METHODS - implementation of several iterative methods;
- see also iter0.c
- */
-
- #include <stdio.h>
- #include <math.h>
- #include "matrix.h"
- #include "matrix2.h"
- #include "sparse.h"
- #include "iter.h"
-
- static char rcsid[] = "$Id: iternsym.c,v 1.2 1994/02/02 06:02:20 des Exp $";
-
-
- #ifdef ANSI_C
- VEC *spCHsolve(SPMAT *,VEC *,VEC *);
- #else
- VEC *spCHsolve();
- #endif
-
-
- /*
- iter_cgs -- uses CGS to compute a solution x to A.x=b
- */
-
- VEC *iter_cgs(ip,r0)
- ITER *ip;
- VEC *r0;
- {
- static VEC *p = VNULL, *q = VNULL, *r = VNULL, *u = VNULL;
- static VEC *v = VNULL, *z = VNULL;
- VEC *tmp;
- Real alpha, beta, nres, rho, old_rho, sigma, inner;
-
- if (ip == INULL)
- error(E_NULL,"iter_cgs");
- if (!ip->Ax || !ip->b || !r0)
- error(E_NULL,"iter_cgs");
- if ( ip->x == ip->b )
- error(E_INSITU,"iter_cgs");
- if (!ip->stop_crit)
- error(E_NULL,"iter_cgs");
- if ( r0->dim != ip->b->dim )
- error(E_SIZES,"iter_cgs");
-
- if ( ip->eps <= 0.0 )
- ip->eps = MACHEPS;
-
- p = v_resize(p,ip->b->dim);
- q = v_resize(q,ip->b->dim);
- r = v_resize(r,ip->b->dim);
- u = v_resize(u,ip->b->dim);
- v = v_resize(v,ip->b->dim);
-
- MEM_STAT_REG(p,TYPE_VEC);
- MEM_STAT_REG(q,TYPE_VEC);
- MEM_STAT_REG(r,TYPE_VEC);
- MEM_STAT_REG(u,TYPE_VEC);
- MEM_STAT_REG(v,TYPE_VEC);
-
- if (ip->Bx) {
- z = v_resize(z,ip->b->dim);
- MEM_STAT_REG(z,TYPE_VEC);
- }
-
- if (ip->x != VNULL) {
- if (ip->x->dim != ip->b->dim)
- error(E_SIZES,"iter_cgs");
- ip->Ax(ip->A_par,ip->x,v); /* v = A*x */
- if (ip->Bx) {
- v_sub(ip->b,v,v); /* v = b - A*x */
- (ip->Bx)(ip->B_par,v,r); /* r = B*(b-A*x) */
- }
- else v_sub(ip->b,v,r); /* r = b-A*x */
- }
- else { /* ip->x == 0 */
- ip->x = v_get(ip->b->dim); /* x == 0 */
- ip->shared_x = FALSE;
- if (ip->Bx) (ip->Bx)(ip->B_par,ip->b,r); /* r = B*b */
- else v_copy(ip->b,r); /* r = b */
- }
-
- v_zero(p);
- v_zero(q);
- old_rho = 1.0;
-
- for (ip->steps = 0; ip->steps <= ip->limit; ip->steps++) {
-
- inner = in_prod(r,r);
- nres = sqrt(fabs(inner));
-
- if (ip->info) ip->info(ip,nres,r,VNULL);
- if ( ip->stop_crit(ip,nres,r,VNULL) ) break;
-
- rho = in_prod(r0,r);
- if ( old_rho == 0.0 )
- error(E_SING,"iter_cgs");
- beta = rho/old_rho;
- v_mltadd(r,q,beta,u);
- v_mltadd(q,p,beta,v);
- v_mltadd(u,v,beta,p);
-
- (ip->Ax)(ip->A_par,p,q);
- if (ip->Bx) {
- (ip->Bx)(ip->B_par,q,z);
- tmp = z;
- }
- else tmp = q;
-
- sigma = in_prod(r0,tmp);
- if ( sigma == 0.0 )
- error(E_SING,"iter_cgs");
- alpha = rho/sigma;
- v_mltadd(u,tmp,-alpha,q);
- v_add(u,q,v);
-
- (ip->Ax)(ip->A_par,v,u);
- if (ip->Bx) {
- (ip->Bx)(ip->B_par,u,z);
- tmp = z;
- }
- else tmp = u;
-
- v_mltadd(r,tmp,-alpha,r);
- v_mltadd(ip->x,v,alpha,ip->x);
-
- old_rho = rho;
- }
-
- return ip->x;
- }
-
-
-
- /* iter_spcgs -- simple interface for SPMAT data structures
- use always as follows:
- x = iter_spcgs(A,B,b,r0,tol,x,limit,steps);
- or
- x = iter_spcgs(A,B,b,r0,tol,VNULL,limit,steps);
- In the second case the solution vector is created.
- If B is not NULL then it is a preconditioner.
- */
- VEC *iter_spcgs(A,B,b,r0,tol,x,limit,steps)
- SPMAT *A, *B;
- VEC *b, *r0, *x;
- double tol;
- int *steps,limit;
- {
- ITER *ip;
-
- ip = iter_get(0,0);
- ip->Ax = (Fun_Ax) sp_mv_mlt;
- ip->A_par = (void *) A;
- if (B) {
- ip->Bx = (Fun_Ax) sp_mv_mlt;
- ip->B_par = (void *) B;
- }
- else {
- ip->Bx = (Fun_Ax) NULL;
- ip->B_par = NULL;
- }
- ip->info = (Fun_info) NULL;
- ip->limit = limit;
- ip->b = b;
- ip->eps = tol;
- ip->x = x;
- iter_cgs(ip,r0);
- x = ip->x;
- if (steps) *steps = ip->steps;
- ip->shared_x = ip->shared_b = TRUE;
- iter_free(ip); /* release only ITER structure */
- return x;
-
- }
-
- /*
- Routine for performing LSQR -- the least squares QR algorithm
- of Paige and Saunders:
- "LSQR: an algorithm for sparse linear equations and
- sparse least squares", ACM Trans. Math. Soft., v. 8
- pp. 43--71 (1982)
- */
- /* lsqr -- sparse CG-like least squares routine:
- -- finds min_x ||A.x-b||_2 using A defined through A & AT
- -- returns x (if x != NULL) */
- VEC *iter_lsqr(ip)
- ITER *ip;
- {
- static VEC *u = VNULL, *v = VNULL, *w = VNULL, *tmp = VNULL;
- Real alpha, beta, phi, phi_bar;
- Real rho, rho_bar, rho_max, theta, nres;
- Real s, c; /* for Givens' rotations */
- int m, n;
-
- if ( ! ip || ! ip->b || !ip->Ax || !ip->ATx )
- error(E_NULL,"iter_lsqr");
- if ( ip->x == ip->b )
- error(E_INSITU,"iter_lsqr");
- if (!ip->stop_crit || !ip->x)
- error(E_NULL,"iter_lsqr");
-
- if ( ip->eps <= 0.0 )
- ip->eps = MACHEPS;
-
- m = ip->b->dim;
- n = ip->x->dim;
-
- u = v_resize(u,(u_int)m);
- v = v_resize(v,(u_int)n);
- w = v_resize(w,(u_int)n);
- tmp = v_resize(tmp,(u_int)n);
-
- MEM_STAT_REG(u,TYPE_VEC);
- MEM_STAT_REG(v,TYPE_VEC);
- MEM_STAT_REG(w,TYPE_VEC);
- MEM_STAT_REG(tmp,TYPE_VEC);
-
- if (ip->x != VNULL) {
- ip->Ax(ip->A_par,ip->x,u); /* u = A*x */
- v_sub(ip->b,u,u); /* u = b-A*x */
- }
- else { /* ip->x == 0 */
- ip->x = v_get(ip->b->dim);
- ip->shared_x = FALSE;
- v_copy(ip->b,u); /* u = b */
- }
-
- beta = v_norm2(u);
- if ( beta == 0.0 )
- return ip->x;
- sv_mlt(1.0/beta,u,u);
- (ip->ATx)(ip->AT_par,u,v);
- alpha = v_norm2(v);
- if ( alpha == 0.0 )
- return ip->x;
- sv_mlt(1.0/alpha,v,v);
- v_copy(v,w);
- phi_bar = beta;
- rho_bar = alpha;
-
- rho_max = 1.0;
- for (ip->steps = 0; ip->steps <= ip->limit; ip->steps++) {
-
- tmp = v_resize(tmp,m);
- (ip->Ax)(ip->A_par,v,tmp);
-
- v_mltadd(tmp,u,-alpha,u);
- beta = v_norm2(u);
- sv_mlt(1.0/beta,u,u);
-
- tmp = v_resize(tmp,n);
- (ip->ATx)(ip->AT_par,u,tmp);
- v_mltadd(tmp,v,-beta,v);
- alpha = v_norm2(v);
- sv_mlt(1.0/alpha,v,v);
-
- rho = sqrt(rho_bar*rho_bar+beta*beta);
- if ( rho > rho_max )
- rho_max = rho;
- c = rho_bar/rho;
- s = beta/rho;
- theta = s*alpha;
- rho_bar = -c*alpha;
- phi = c*phi_bar;
- phi_bar = s*phi_bar;
-
- /* update ip->x & w */
- if ( rho == 0.0 )
- error(E_SING,"iter_lsqr");
- v_mltadd(ip->x,w,phi/rho,ip->x);
- v_mltadd(v,w,-theta/rho,w);
-
- nres = fabs(phi_bar*alpha*c)*rho_max;
-
- if (ip->info) ip->info(ip,nres,w,VNULL);
- if ( ip->stop_crit(ip,nres,w,VNULL) ) break;
- }
-
- return ip->x;
- }
-
- /* iter_splsqr -- simple interface for SPMAT data structures */
- VEC *iter_splsqr(A,b,tol,x,limit,steps)
- SPMAT *A;
- VEC *b, *x;
- double tol;
- int *steps,limit;
- {
- ITER *ip;
-
- ip = iter_get(0,0);
- ip->Ax = (Fun_Ax) sp_mv_mlt;
- ip->A_par = (void *) A;
- ip->ATx = (Fun_Ax) sp_vm_mlt;
- ip->AT_par = (void *) A;
- ip->Bx = (Fun_Ax) NULL;
- ip->B_par = NULL;
-
- ip->info = (Fun_info) NULL;
- ip->limit = limit;
- ip->b = b;
- ip->eps = tol;
- ip->x = x;
- iter_lsqr(ip);
- x = ip->x;
- if (steps) *steps = ip->steps;
- ip->shared_x = ip->shared_b = TRUE;
- iter_free(ip); /* release only ITER structure */
- return x;
- }
-
-
-
- /* iter_arnoldi -- an implementation of the Arnoldi method;
- iterative refinement is applied.
- */
- MAT *iter_arnoldi_iref(ip,h_rem,Q,H)
- ITER *ip;
- Real *h_rem;
- MAT *Q, *H;
- {
- static VEC *u=VNULL, *r=VNULL, *s=VNULL, *tmp=VNULL;
- VEC v; /* auxiliary vector */
- int i,j;
- Real h_val, c;
-
- if (ip == INULL)
- error(E_NULL,"iter_arnoldi_iref");
- if ( ! ip->Ax || ! Q || ! ip->x )
- error(E_NULL,"iter_arnoldi_iref");
- if ( ip->k <= 0 )
- error(E_BOUNDS,"iter_arnoldi_iref");
- if ( Q->n != ip->x->dim || Q->m != ip->k )
- error(E_SIZES,"iter_arnoldi_iref");
-
- m_zero(Q);
- H = m_resize(H,ip->k,ip->k);
- m_zero(H);
-
- u = v_resize(u,ip->x->dim);
- tmp = v_resize(tmp,ip->x->dim);
- r = v_resize(r,ip->k);
- s = v_resize(s,ip->k);
- MEM_STAT_REG(u,TYPE_VEC);
- MEM_STAT_REG(tmp,TYPE_VEC);
- MEM_STAT_REG(r,TYPE_VEC);
- MEM_STAT_REG(s,TYPE_VEC);
-
- v.dim = v.max_dim = ip->x->dim;
-
- c = v_norm2(ip->x);
- if ( c <= 0.0)
- return H;
- else {
- v.ve = Q->me[0];
- sv_mlt(1.0/c,ip->x,&v);
- }
-
- v_zero(r);
- v_zero(s);
- for ( i = 0; i < ip->k; i++ )
- {
- v.ve = Q->me[i];
- u = (ip->Ax)(ip->A_par,&v,u);
- v_zero(tmp);
- for (j = 0; j <= i; j++) {
- v.ve = Q->me[j];
- r->ve[j] = in_prod(&v,u);
- v_mltadd(tmp,&v,r->ve[j],tmp);
- }
- v_sub(u,tmp,u);
- h_val = v_norm2(u);
- /* if u == 0 then we have an exact subspace */
- if ( h_val <= 0.0 )
- {
- *h_rem = h_val;
- return H;
- }
- /* iterative refinement -- ensures near orthogonality */
- do {
- v_zero(tmp);
- for (j = 0; j <= i; j++) {
- v.ve = Q->me[j];
- s->ve[j] = in_prod(&v,u);
- v_mltadd(tmp,&v,s->ve[j],tmp);
- }
- v_sub(u,tmp,u);
- v_add(r,s,r);
- } while ( v_norm2(s) > 0.1*(h_val = v_norm2(u)) );
- /* now that u is nearly orthogonal to Q, update H */
- set_col(H,i,r);
- /* check once again if h_val is zero */
- if ( h_val <= 0.0 )
- {
- *h_rem = h_val;
- return H;
- }
- if ( i == ip->k-1 Also the member ip->init_res is updated indirectly by
- ip->stop_crit.
- */
- if (ip->steps == 0) { /* information for a user */
- if (ip->info) (*ip->info)(ip,nres,As,rr);
- if ( (*ip->stop_crit)(ip,nres,As,rr) ) {
- /* iterative process is finished */
- done = TRUE;
- break;
- }
- }
- else if (nres <= 0.0)
- break; /* residual is zero -> finish the process */
-
- /* save this residual in the first row of N */
- v.ve = N->me[0];
- v_copy(rr,&v);
-
- for (i = 0; i < ip->k && ip->steps <= ip->limit; i++) {
- ip->steps++;
- v.ve = N->me[i]; /* pointer to a row of N (=s_i) */
- /* note that we must use here &v, not v */
- (*ip->Ax)(ip->A_par,&v,As);
- rr = As; /* As = A*s_i */
- if (ip->Bx) {
- (*ip->Bx)(ip->B_par,As,z); /* z = B*A*s_i */
- rr = z;
- }
-
- if (i < ip->k - 1) {
- s.ve = N->me[i+1]; /* pointer to a row of N (=s_{i+1}) */
- v_copy(rr,&s); /* s_{i+1} = B*A*s_i */
- for (j = 0; j <= i-1; j++) {
- v.ve = N->me[j+1]; /* pointer to a row of N (=s_{j+1}) */
- beta->ve[j] = in_prod(&v,rr); /* beta_{j,i} */
- /* s_{i+1} -= beta_{j,i}*s_{j+1} */
- v_mltadd(&s,&v,- beta->ve[j],&s);
- }
-
- /* beta_{i,i} = ||s_{i+1}||_2 */
- beta->ve[i] = nres = v_norm2(&s);
- if ( nres <= 0.0) break; /* if s_{i+1} == 0 then finish */
- sv_mlt(1.0/nres,&s,&s); /* normalize s_{i+1} */
-
- v.ve = N->me[0];
- alpha->ve[i] = in_prod(&v,&s); /* alpha_i = (s_0 , s_{i+1}) */
-
- }
- else {
- for (j = 0; j <= i-1; j++) {
- v.ve = N->me[j+1]; /* pointer to a row of N (=s_{j+1}) */
- beta->ve[j] = in_prod(&v,rr); /* beta_{j,i} */
- }
-
- nres = in_prod(rr,rr); /* rr = B*A*s_{k-1} */
- for (j = 0; j <= i-1; j++)
- nres -= beta->ve[j]*beta->ve[j];
- if (nres <= 0.0) break; /* s_k is zero */
- else beta->ve[i] = sqrt(nres); /* beta_{k-1,k-1} */
-
- v.ve = N->me[0];
- alpha->ve[i] = in_prod(&v,rr);
- for (j = 0; j <= i-1; j++)
- alpha->ve[i] -= beta->ve[j]*alpha->ve[j];
- alpha->ve[i] /= beta->ve[i]; /* alpha_{k-1} */
-
- }
-
- set_col(H,i,beta);
-
- dd -= alpha->ve[i]*alpha->ve[i];
- nres = sqrt(fabs((double) dd));
- if (dd < 0.0) { /* do restart */
- if (ip->info) (*ip->info)(ip,-nres,VNULL,VNULL);
- break;
- }
-
- if (ip->info) (*ip->info)(ip,nres,VNULL,VNULL);
- if ( ip->stop_crit(ip,nres,VNULL,VNULL) ) {
- /* stopping criterion is satisfied */
- done = TRUE;
- break;
- }
-
- } /* end of for */
-
- if (nres <= 0.0) {
- i--;
- done = TRUE;
- }
- if (i >= ip->k) i = ip->k - 1;
-
- /* use (i+1) by (i+1) submatrix of H */
- H = m_resize(H,i+1,i+1);
- alpha = v_resize(alpha,i+1);
- Usolve(H,alpha,alpha,0.0); /* c_i is saved in alpha */
-
- for (j = 0; j <= i; j++) {
- v.ve = N->me[j];
- v_mltadd(ip->x,&v,alpha->ve[j],ip->x);
- }
-
-
- if (done) break; /* stop the iterative process */
- alpha = v_resize(alpha,ip->k);
- H = m_resize(H,ip->k,ip->k);
-
- } /* end of while */
-
- return ip->x; /* return the solution */
- }
-
-
-
- /* iter_spmgcr - a simple interface to iter_mgcr */
- /* no preconditioner */
- VEC *iter_spmgcr(A,B,b,tol,x,k,limit,steps)
- SPMAT *A, *B;
- VEC *b, *x;
- double tol;
- int *steps,k,limit;
- {
- ITER *ip;
-
- ip = iter_get(0,0);
- ip->Ax = (Fun_Ax) sp_mv_mlt;
- ip->A_par = (void *) A;
- if (B) {
- ip->Bx = (Fun_Ax) sp_mv_mlt;
- ip->B_par = (void *) B;
- }
- else {
- ip->Bx = (Fun_Ax) NULL;
- ip->B_par = NULL;
- }
-
- ip->k = k;
- ip->limit = limit;
- ip->info = (Fun_info) NULL;
- ip->b = b;
- ip->eps = tol;
- ip->x = x;
- iter_mgcr(ip);
- x = ip->x;
- if (steps) *steps = ip->steps;
- ip->shared_x = ip->shared_b = TRUE;
- iter_free(ip); /* release only ITER structure */
- return x;
- }
-
-
-
- /*
- Conjugate gradients method for a normal equation
- a preconditioner B must be symmetric !!
- */
- VEC *iter_cgne(ip)
- ITER *ip;
- {
- static VEC *r = VNULL, *p = VNULL, *q = VNULL, *z = VNULL;
- Real alpha, beta, inner, old_inner, nres;
- VEC *rr1; /* pointer only */
-
- if (ip == INULL)
- error(E_NULL,"iter_cgne");
- if (!ip->Ax || ! ip->ATx || !ip->b)
- error(E_NULL,"iter_cgne");
- if ( ip->x == ip->b )
- error(E_INSITU,"iter_cgne");
- if (!ip->stop_crit)
- error(E_NULL,"iter_cgne");
-
- if ( ip->eps <= 0.0 )
- ip->eps = MACHEPS;
-
- r = v_resize(r,ip->b->dim);
- p = v_resize(p,ip->b->dim);
- q = v_resize(q,ip->b->dim);
-
- MEM_STAT_REG(r,TYPE_VEC);
- MEM_STAT_REG(p,TYPE_VEC);
- MEM_STAT_REG(q,TYPE_VEC);
-
- z = v_resize(z,ip->b->dim);
- MEM_STAT_REG(z,TYPE_VEC);
-
- if (ip->x) {
- if (ip->x->dim != ip->b->dim)
- error(E_SIZES,"iter_cgne");
- ip->Ax(ip->A_par,ip->x,p); /* p = A*x */
- v_sub(ip->b,p,z); /* z = b - A*x */
- }
- else { /* ip->x == 0 */
- ip->x = v_get(ip->b->dim);
- ip->shared_x = FALSE;
- v_copy(ip->b,z);
- }
- rr1 = z;
- if (ip->Bx) {
- (ip->Bx)(ip->B_par,rr1,p);
- rr1 = p;
- }
- (ip->ATx)(ip->AT_par,rr1,r); /* r = A^T*B*(b-A*x) */
-
-
- old_inner = 0.0;
- for ( ip->steps = 0; ip->steps <= ip->limit; ip->steps++ )
- {
- rr1 = r;
- if ( ip->Bx ) {
- (ip->Bx)(ip->B_par,r,z); /* rr = B*r */
- rr1 = z;
- }
-
- inner = in_prod(r,rr1);
- nres = sqrt(fabs(inner));
- if (ip->info) ip->info(ip,nres,r,rr1);
- if ( ip->stop_crit(ip,nres,r,rr1) ) break;
-
- if ( ip->steps ) /* if ( ip->steps > 0 ) ... */
- {
- beta = inner/old_inner;
- p = v_mltadd(rr1,p,beta,p);
- }
- else /* if ( ip->steps == 0 ) ... */
- {
- beta = 0.0;
- p = v_copy(rr1,p);
- old_inner = 0.0;
- }
- (ip->Ax)(ip->A_par,p,q); /* q = A*p */
- if (ip->Bx) {
- (ip->Bx)(ip->B_par,q,z);
- (ip->ATx)(ip->AT_par,z,q);
- rr1 = q; /* q = A^T*B*A*p */
- }
- else {
- (ip->ATx)(ip->AT_par,q,z); /* z = A^T*A*p */
- rr1 = z;
- }
-
- alpha = inner/in_prod(rr1,p);
- v_mltadd(ip->x,p,alpha,ip->x);
- v_mltadd(r,rr1,-alpha,r);
- old_inner = inner;
- }
-
- return ip->x;
- }
-
- /* iter_spcgne -- a simple interface to iter_cgne() which
- uses sparse matrix data structures
- -- assumes that B contains an actual preconditioner (or NULL)
- use always as follows:
- x = iter_spcgne(A,B,b,eps,x,limit,steps);
- or
- x = iter_spcgne(A,B,b,eps,VNULL,limit,steps);
- In the second case the solution vector is created.
- */
- VEC *iter_spcgne(A,B,b,eps,x,limit,steps)
- SPMAT *A, *B;
- VEC *b, *x;
- double eps;
- int *steps, limit;
- {
- ITER *ip;
-
- ip = iter_get(0,0);
- ip->Ax = (Fun_Ax) sp_mv_mlt;
- ip->A_par = (void *)A;
- ip->ATx = (Fun_Ax) sp_vm_mlt;
- ip->AT_par = (void *)A;
- if (B) {
- ip->Bx = (Fun_Ax) sp_mv_mlt;
- ip->B_par = (void *)B;
- }
- else {
- ip->Bx = (Fun_Ax) NULL;
- ip->B_par = NULL;
- }
- ip->info = (Fun_info) NULL;
- ip->b = b;
- ip->eps = eps;
- ip->limit = limit;
- ip->x = x;
- iter_cgne(ip);
- x = ip->x;
- if (steps) *steps = ip->steps;
- ip->shared_x = ip->shared_b = TRUE;
- iter_free(ip); /* release only ITER structure */
- return x;
- }
-
-
-
-
- FileDataŵitersym 6 Eÿÿÿ8S@ V´
- /**************************************************************************
- **
- ** Copyright (C) 1993 David E. Steward & Zbigniew Leyk, all rights reserved.
- **
- ** Meschach Library
- **
- ** This Meschach Library is provided "as is" without any express
- ** or implied warranty of any kind with respect to this software.
- ** In particular the authors shall not be liable for any direct,
- ** indirect, special, incidental or consequential damages arising
- ** in any way from use of the software.
- **
- ** Everyone is granted permission to copy, modify and redistribute this
- ** Meschach Library, provided:
- ** 1. All copies contain this copyright notice.
- ** 2. All modified copies shall carry a notice stating who
- ** made the last modification and the date of such modification.
- ** 3. No charge is made for this software or works derived from it.
- ** This clause shall not be construed as constraining other software
- ** distributed on the same medium as this software, nor is a
- ** distribution fee considered a charge.
- **
- ***************************************************************************/
-
-
- /* itersym.c 17/09/93 */
-
-
- /*
- ITERATIVE METHODS - implementation of several iterative methods;
- see also iter0.c
- */
-
- #include <stdio.h>
- #include <math.h>
- #include "matrix.h"
- #include "matrix2.h"
- #include "sparse.h"
- #include "iter.h"
-
- static char rcsid[] = "$Id: itersym.c,v 1.1 1994/01/13 05:38:59 des Exp $";
-
-
- #ifdef ANSI_C
- VEC *spCHsolve(SPMAT *,VEC *,VEC *);
- VEC *trieig(VEC *,VEC *,MAT *);
- #else
- VEC *spCHsolve();
- VEC *trieig();
- #endif
-
-
-
- /* iter_spcg -- a simple interface to iter_cg() which uses sparse matrix
- data structures
- -- assumes that LLT contains the Cholesky factorisation of the
- actual preconditioner;
- use always as follows:
- x = iter_spcg(A,LLT,b,eps,x,limit,steps);
- or
- x = iter_spcg(A,LLT,b,eps,VNULL,limit,steps);
- In the second case the solution vector is created.
- */
- VEC *iter_spcg(A,LLT,b,eps,x,limit,steps)
- SPMAT *A, *LLT;
- VEC *b, *x;
- double eps;
- int *steps, limit;
- {
- ITER *ip;
-
- ip = iter_get(0,0);
- ip->Ax = (Fun_Ax) sp_mv_mlt;
- ip->A_par = (void *)A;
- ip->Bx = (Fun_Ax) spCHsolve;
- ip->B_par = (void *)LLT;
- ip->info = (Fun_info) NULL;
- ip->b = b;
- ip->eps = eps;
- ip->limit = limit;
- ip->x = x;
- iter_cg(ip);
- x = ip->x;
- if (steps) *steps = ip->steps;
- ip->shared_x = ip->shared_b = TRUE;
- iter_free(ip); /* release only ITER structure */
- return x;
- }
-
- /*
- Conjugate gradients method;
- */
- VEC *iter_cg(ip)
- ITER *ip;
- {
- static VEC *r = VNULL, *p = VNULL, *q = VNULL, *z = VNULL;
- Real alpha, beta, inner, old_inner, nres;
- VEC *rr; /* rr == r or rr == z */
-
- if (ip == INULL)
- error(E_NULL,"iter_cg");
- if (!ip->Ax || !ip->b)
- error(E_NULL,"iter_cg");
- if ( ip->x == ip->b )
- error(E_INSITU,"iter_cg");
- if (!ip->stop_crit)
- error(E_NULL,"iter_cg");
-
- if ( ip->eps <= 0.0 )
- ip->eps = MACHEPS;
-
- r = v_resize(r,ip->b->dim);
- p = v_resize(p,ip->b->dim);
- q = v_resize(q,ip->b->dim);
-
- MEM_STAT_REG(r,TYPE_VEC);
- MEM_STAT_REG(p,TYPE_VEC);
- MEM_STAT_REG(q,TYPE_VEC);
-
- if (ip->Bx != (Fun_Ax)NULL) {
- z = v_resize(z,ip->b->dim);
- MEM_STAT_REG(z,TYPE_VEC);
- rr = z;
- }
- else rr = r;
-
- if (ip->x != VNULL) {
- if (ip->x->dim != ip->b->dim)
- error(E_SIZES,"iter_cg");
- ip->Ax(ip->A_par,ip->x,p); /* p = A*x */
- v_sub(ip->b,p,r); /* r = b - A*x */
- }
- else { /* ip->x == 0 */
- ip->x = v_get(ip->b->dim);
- ip->shared_x = FALSE;
- v_copy(ip->b,r);
- }
-
- old_inner = 0.0;
- for ( ip->steps = 0; ip->steps <= ip->limit; ip->steps++ )
- {
- if ( ip->Bx )
- (ip->Bx)(ip->B_par,r,rr); /* rr = B*r */
-
- inner = in_prod(rr,r);
- nres = sqrt(fabs(inner));
- if (ip->info) ip->info(ip,nres,r,rr);
- if ( ip->stop_crit(ip,nres,r,rr) ) break;
-
- if ( ip->steps ) /* if ( ip->steps > 0 ) ... */
- {
- beta = inner/old_inner;
- p = v_mltadd(rr,p,beta,p);
- }
- else /* if ( ip->steps == 0 ) ... */
- {
- beta = 0.0;
- p = v_copy(rr,p);
- old_inner = 0.0;
- }
- (ip->Ax)(ip->A_par,p,q); /* q = A*p */
- alpha = inner/in_prod(p,q);
- v_mltadd(ip->x,p,alpha,ip->x);
- v_mltadd(r,q,-alpha,r);
- old_inner = inner;
- }
-
- return ip->x;
- }
-
-
-
- /* iter_lanczos -- raw lanczos algorithm -- no re-orthogonalisation
- -- creates T matrix of size == m,
- but no larger than before beta_k == 0
- -- uses passed routine to do matrix-vector multiplies */
- void iter_lanczos(ip,a,b,beta2,Q)
- ITER *ip;
- VEC *a, *b;
- Real *beta2;
- MAT *Q;
- {
- int j;
- static VEC *v = VNULL, *w = VNULL, *tmp = VNULL;
- Real alpha, beta, c;
-
- if ( ! ip )
- error(E_NULL,"iter_lanczos");
- if ( ! ip->Ax || ! ip->x || ! a || ! b )
- error(E_NULL,"iter_lanczos");
- if ( ip->k <= 0 )
- error(E_BOUNDS,"iter_lanczos");
- if ( Q && ( Q->n < ip->x->dim || Q->m < ip->k ) )
- error(E_SIZES,"iter_lanczos");
-
- a = v_resize(a,(u_int)ip->k);
- b = v_resize(b,(u_int)(ip->k-1));
- v = v_resize(v,ip->x->dim);
- w = v_resize(w,ip->x->dim);
- tmp = v_resize(tmp,ip->x->dim);
- MEM_STAT_REG(v,TYPE_VEC);
- MEM_STAT_REG(w,TYPE_VEC);
- MEM_STAT_REG(tmp,TYPE_VEC);
-
- beta = 1.0;
- v_zero(a);
- v_zero(b);
- if (Q) m_zero(Q);
-
- /* normalise x as w */
- c = v_norm2(ip->x);
- if (c <= MACHEPS) { /* ip->x == 0 */
- *beta2 = 0.0;
- return;
- }
- else
- sv_mlt(1.0/c,ip->x,w);
-
- (ip->Ax)(ip->A_par,w,v);
-
- for ( j = 0; j < ip->k; j++ )
- {
- /* store w in Q if Q not NULL */
- if ( Q ) set_row(Q,j,w);
-
- alpha = in_prod(w,v);
- a->ve[j] = alpha;
- v_mltadd(v,w,-alpha,v);
- beta = v_norm2(v);
- if ( beta == 0.0 )
- {
- *beta2 = 0.0;
- return;
- }
-
- if ( j < ip->k-1 )
- b->ve[j] = beta;
- v_copy(w,tmp);
- sv_mlt(1/beta,v,w);
- sv_mlt(-beta,tmp,v);
- (ip->Ax)(ip->A_par,w,tmp);
- v_add(v,tmp,v);
- }
- *beta2 = beta;
-
- }
-
- /* iter_splanczos -- version that uses sparse matrix data structure */
- void iter_splanczos(A,m,x0,a,b,beta2,Q)
- SPMAT *A;
- int m;
- VEC *x0, *a, *b;
- Real *beta2;
- MAT *Q;
- {
- ITER *ip;
-
- ip = iter_get(0,0);
- ip->shared_x = ip->shared_b = TRUE;
- ip->Ax = (Fun_Ax) sp_mv_mlt;
- ip->A_par = (void *) A;
- ip->x = x0;
- ip->k = m;
- iter_lanczos(ip,a,b,beta2,Q);
- iter_free(ip); /* release only ITER structure */
- }
-
-
-
- extern double frexp(), ldexp();
-
- /* product -- returns the product of a long list of numbers
- -- answer stored in mant (mantissa) and expt (exponent) */
- static double product(a,offset,expt)
- VEC *a;
- double offset;
- int *expt;
- {
- Real mant, tmp_fctr;
- int i, tmp_expt;
-
- if ( ! a )
- error(E_NULL,"product");
-
- mant = 1.0;
- *expt = 0;
- if ( offset == 0.0 )
- for ( i = 0; i < a->dim; i++ )
- {
- mant *= frexp(a->ve[i],&tmp_expt);
- *expt += tmp_expt;
- if ( ! (i % 10) )
- {
- mant = frexp(mant,&tmp_expt);
- *expt += tmp_expt;
- }
- }
- else
- for ( i = 0; i < a->dim; i++ )
- {
- tmp_fctr = a->ve[i] - offset;
- tmp_fctr += (tmp_fctr > 0.0 ) ? -MACHEPS*offset :
- MACHEPS*offset;
- mant *= frexp(tmp_fctr,&tmp_expt);
- *expt += tmp_expt;
- if ( ! (i % 10) )
- {
- mant = frexp(mant,&tmp_expt);
- *expt += tmp_expt;
- }
- }
-
- mant = frexp(mant,&tmp_expt);
- *expt += tmp_expt;
-
- return mant;
- }
-
- /* product2 -- returns the product of a long list of numbers
- -- answer stored in mant (mantissa) and expt (exponent) */
- static double product2(a,k,expt)
- VEC *a;
- int k; /* entry of a to leave out */
- int *expt;
- {
- Real mant, mu, tmp_fctr;
- int i, tmp_expt;
-
- if ( ! a )
- error(E_NULL,"product2");
- if ( k < 0 || k >= a->dim )
- error(E_BOUNDS,"product2");
-
- mant = 1.0;
- *expt = 0;
- mu = a->ve[k];
- for ( i = 0; i < a->dim; i++ )
- {
- if ( i == k )
- continue;
- tmp_fctr = a->ve[i] - mu;
- tmp_fctr += ( tmp_fctr > 0.0 ) ? -MACHEPS*mu : MACHEPS*mu;
- mant *= frexp(tmp_fctr,&tmp_expt);
- *expt += tmp_expt;
- if ( ! (i % 10) )
- {
- mant = frexp(mant,&tmp_expt);
- *expt += tmp_expt;
- }
- }
- mant = frexp(mant,&tmp_expt);
- *expt += tmp_expt;
-
- return mant;
- }
-
- /* dbl_cmp -- comparison function to pass to qsort() */
- static int dbl_cmp(x,y)
- Real *x, *y;
- {
- Real tmp;
-
- tmp = *x - *y;
- return (tmp > 0 ? 1 : tmp < 0 ? -1: 0);
- }
-
- /* iter_lanczos2 -- lanczos + error estimate for every e-val
- -- uses Cullum & Willoughby approach, Sparse Matrix Proc. 1978
- -- returns multiple e-vals where multiple e-vals may not exist
- -- returns evals vector */
- VEC *iter_lanczos2(ip,evals,err_est)
- ITER *ip; /* ITER structure */
- VEC *evals; /* eigenvalue vector */
- VEC *err_est; /* error estimates of eigenvalues */
- {
- VEC *a;
- static VEC *b=VNULL, *a2=VNULL, *b2=VNULL;
- Real beta, pb_mant, det_mant, det_mant1, det_mant2;
- int i, pb_expt, det_expt, det_expt1, det_expt2;
-
- if ( ! ip )
- error(E_NULL,"iter_lanczos2");
- if ( ! ip->Ax || ! ip->x )
- error(E_NULL,"iter_lanczos2");
- if ( ip->k <= 0 )
- error(E_RANGE,"iter_lanczos2");
-
- a = evals;
- a = v_resize(a,(u_int)ip->k);
- b = v_resize(b,(u_int)(ip->k-1));
- MEM_STAT_REG(b,TYPE_VEC);
-
- iter_lanczos(ip,a,b,&beta,MNULL);
-
- /* printf("# beta =%g\n",beta); */
- pb_mant = 0.0;
- if ( err_est )
- {
- pb_mant = product(b,(double)0.0,&pb_expt);
- /* printf("# pb_mant = %g, pb_expt = %d\n",pb_mant, pb_expt); */
- }
-
- /* printf("# diags =\n"); v_output(a); */
- /* printf("# off diags =\n"); v_output(b); */
- a2 = v_resize(a2,a->dim - 1);
- b2 = v_resize(b2,b->dim - 1);
- MEM_STAT_REG(a2,TYPE_VEC);
- MEM_STAT_REG(b2,TYPE_VEC);
- for ( i = 0; i < a2->dim - 1; i++ )
- {
- a2->ve[i] = a->ve[i+1];
- b2->ve[i] = b->ve[i+1];
- }
- a2->ve[a2->dim-1] = a->ve[a2->dim];
-
- trieig(a,b,MNULL);
-
- /* sort evals as a courtesy */
- qsort((void *)(a->ve),(int)(a->dim),sizeof(Real),(int (*)())dbl_cmp);
-
- /* error estimates */
- if ( err_est )
- {
- err_est = v_resize(err_est,(u_int)ip->k);
-
- trieig(a2,b2,MNULL);
- /* printf("# a =\n"); v_output(a); */
- /* printf("# a2 =\n"); v_output(a2); */
-
- for ( i = 0; i < a->dim; i++ )
- {
- det_mant1 = product2(a,i,&det_expt1);
- det_mant2 = product(a2,(double)a->ve[i],&det_expt2);
- /*0 ,k+1,tmp1,v_entry(beta,k));
- /* printf("A = "); m_output(A); */
- }
-
- return (A);
- }
-
- /* makeHQ -- construct the Hessenberg orthogonalising matrix Q;
- -- i.e. Hess M = Q.M.Q' */
- MAT *makeHQ(H, diag, beta, Qout)
- MAT *H, *Qout;
- VEC *diag, *beta;
- {
- int i, j, limit;
- static VEC *tmp1 = VNULL, *tmp2 = VNULL;
-
- if ( H==(MAT *)NULL || diag==(VEC *)NULL || beta==(VEC *)NULL )
- error(E_NULL,"makeHQ");
- limit = H->m - 1;
- if ( diag->dim < limit || beta->dim < limit )
- error(E_SIZES,"makeHQ");
- if ( H->m != H->n )
- error(E_SQUARE,"makeHQ");
- Qout = m_resize(Qout,H->m,H->m);
-
- tmp1 = v_resize(tmp1,H->m);
- tmp2 = v_resize(tmp2,H->m);
- MEM_STAT_REG(tmp1,TYPE_VEC);
- MEM_STAT_REG(tmp2,TYPE_VEC);
-
- for ( i = 0; i < H->m; i++ )
- {
- /* tmp1 = i'th basis vector */
- for ( j = 0; j < H->m; j++ )
- /* tmp1->ve[j] = 0.0; */
- v_set_val(tmp1,j,0.0);
- /* tmp1->ve[i] = 1.0; */
- v_set_val(tmp1,i,1.0);
-
- /* apply H/h transforms in reverse order */
- for ( j = limit-1; j >= 0; j-- )
- {
- get_col(H,(u_int)j,tmp2);
- /* tmp2->ve[j+1] = diag->ve[j]; */
- v_set_val(tmp2,j+1,v_entry(diag,j));
- hhtrvec(tmp2,beta->ve[j],j+1,tmp1,tmp1);
- }
-
- /* insert into Qout */
- set_col(Qout,(u_int)i,tmp1);
- }
-
- return (Qout);
- }
-
- /* makeH -- construct actual Hessenberg matrix */
- MAT *makeH(H,Hout)
- MAT *H, *Hout;
- {
- int i, j, limit;
-
- if ( H==(MAT *)NULL )
- error(E_NULL,"makeH");
- if ( H->m != H->n )
- error(E_SQUARE,"makeH");
- Hout = m_resize(Hout,H->m,H->m);
- Hout = m_copy(H,Hout);
-
- limit = H->m;
- for ( i = 1; i < limit; i++ )
- for ( j = 0; j < i-1; j++ )
- /* Hout->me[i][j] = 0.0;*/
- m_set_val(Hout,i,j,0.0);
-
- return (Hout);
- }
-
- FileDataŵhsehldr Eÿÿÿä@ ï²
- /**************************************************************************
- **
- ** Copyright (C) 19