home *** CD-ROM | disk | FTP | other *** search
-
- /**************************************************************************
- **
- ** 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.
- **
- ***************************************************************************/
-
-
- /* ivecop.c */
-
- #include <stdio.h>
- #include "matrix.h"
-
- static char rcsid[] = "$Id: ivecop.c,v 1.5 1994/01/13 05:45:30 des Exp $";
-
- static char line[MAXLINE];
-
-
-
- /* iv_get -- get integer vector -- see also memory.c */
- IVEC *iv_get(dim)
- int dim;
- {
- IVEC *iv;
- /* u_int i; */
-
- if (dim < 0)
- error(E_NEG,"iv_get");
-
- if ((iv=NEW(IVEC)) == IVNULL )
- error(E_MEM,"iv_get");
- else if (mem_info_is_on()) {
- mem_bytes(TYPE_IVEC,0,sizeof(IVEC));
- mem_numvar(TYPE_IVEC,1);
- }
-
- iv->dim = iv->max_dim = dim;
- if ((iv->ive = NEW_A(dim,int)) == (int *)NULL )
- error(E_MEM,"iv_get");
- else if (mem_info_is_on()) {
- mem_bytes(TYPE_IVEC,0,dim*sizeof(int));
- }
-
- return (iv);
- }
-
- /* iv_free -- returns iv & asoociated memory back to memory heap */
- int iv_free(iv)
- IVEC *iv;
- {
- if ( iv==IVNULL || iv->dim > MAXDIM )
- /* don't trust it */
- return (-1);
-
- if ( iv->ive == (int *)NULL ) {
- if (mem_info_is_on()) {
- mem_bytes(TYPE_IVEC,sizeof(IVEC),0);
- mem_numvar(TYPE_IVEC,-1);
- }
- free((char *)iv);
- }
- else
- {
- if (mem_info_is_on()) {
- mem_bytes(TYPE_IVEC,sizeof(IVEC)+iv->max_dim*sizeof(int),0);
- mem_numvar(TYPE_IVEC,-1);
- }
- free((char *)iv->ive);
- free((char *)iv);
- }
-
- return (0);
- }
-
- /* iv_resize -- returns the IVEC with dimension new_dim
- -- iv is set to the zero vector */
- IVEC *iv_resize(iv,new_dim)
- IVEC *iv;
- int new_dim;
- {
- int i;
-
- if (new_dim < 0)
- error(E_NEG,"iv_resize");
-
- if ( ! iv )
- return iv_get(new_dim);
-
- if (new_dim == iv->dim)
- return iv;
-
- if ( new_dim > iv->max_dim )
- {
- if (mem_info_is_on()) {
- mem_bytes(TYPE_IVEC,iv->max_dim*sizeof(int),
- new_dim*sizeof(int));
- }
- iv->ive = RENEW(iv->ive,new_dim,int);
- if ( ! iv->ive )
- error(E_MEM,"iv_resize");
- iv->max_dim = new_dim;
- }
- if ( iv->dim <= new_dim )
- for ( i = iv->dim; i < new_dim; i++ )
- iv->ive[i] = 0;
- iv->dim = new_dim;
-
- return iv;
- }
-
- /* iv_copy -- copy integer vector in to out
- -- out created/resized if necessary */
- IVEC *iv_copy(in,out)
- IVEC *in, *out;
- {
- int i;
-
- if ( ! in )
- error(E_NULL,"iv_copy");
- out = iv_resize(out,in->dim);
- for ( i = 0; i < in->dim; i++ )
- out->ive[i] = in->ive[i];
-
- 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->