📄 itersym.c
字号:
/**************************************************************************
**
** Copyright (C) 1993 David E. Stewart & 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.2 1995/01/30 14:55:54 des Exp $";
#ifdef ANSI_C
VEC *spCHsolve(const 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.
*/
#ifndef ANSI_C
VEC *iter_spcg(A,LLT,b,eps,x,limit,steps)
SPMAT *A, *LLT;
VEC *b, *x;
double eps;
int *steps, limit;
#else
VEC *iter_spcg(SPMAT *A, SPMAT *LLT, VEC *b, double eps, VEC *x,
int limit, int *steps)
#endif
{
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;
*/
#ifndef ANSI_C
VEC *iter_cg(ip)
ITER *ip;
#else
VEC *iter_cg(ITER *ip)
#endif
{
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->steps == 0) ip->init_res = nres;
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 = in_prod(p,q);
if (sqrt(fabs(alpha)) <= MACHEPS*ip->init_res)
error(E_BREAKDOWN,"iter_cg");
alpha = inner/alpha;
v_mltadd(ip->x,p,alpha,ip->x);
v_mltadd(r,q,-alpha,r);
old_inner = inner;
}
#ifdef THREADSAFE
V_FREE(r); V_FREE(p); V_FREE(q); V_FREE(z);
#endif
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 */
#ifndef ANSI_C
void iter_lanczos(ip,a,b,beta2,Q)
ITER *ip;
VEC *a, *b;
Real *beta2;
MAT *Q;
#else
void iter_lanczos(ITER *ip, VEC *a, VEC *b, Real *beta2, MAT *Q)
#endif
{
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,(unsigned int)ip->k);
b = v_resize(b,(unsigned 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;
#ifdef THREADSAFE
V_FREE(v); V_FREE(w); V_FREE(tmp);
#endif
}
/* iter_splanczos -- version that uses sparse matrix data structure */
#ifndef ANSI_C
void iter_splanczos(A,m,x0,a,b,beta2,Q)
SPMAT *A;
int m;
VEC *x0, *a, *b;
Real *beta2;
MAT *Q;
#else
void iter_splanczos(SPMAT *A, int m, VEC *x0,
VEC *a, VEC *b, Real *beta2, MAT *Q)
#endif
{
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 */
}
#ifndef ANSI_C
extern double frexp(), ldexp();
#else
extern double frexp(double num, int *exponent),
ldexp(double num, int exponent);
#endif
/* product -- returns the product of a long list of numbers
-- answer stored in mant (mantissa) and expt (exponent) */
#ifndef ANSI_C
static double product(a,offset,expt)
VEC *a;
double offset;
int *expt;
#else
static double product(VEC *a, double offset, int *expt)
#endif
{
Real mant, tmp_fctr;
int i, tmp_expt;
if ( ! a )
error(E_NULL,"product");
mant = 1.0;
*expt = 0;
if ( offset == 0.0 )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -