int solver_gauss(void *A, void *B) { void *X; if(dim1(A) != dim1(B)) return 0; { static int **Y; if(-1 == dim2(B)){ ary2(Y,2,1); if(NULL == Y) return 0; cp(B,Y[1]); cp(Y,X); }else cp(B,X); } if(siz(A) == sizeof(float) && siz(B) == sizeof(float)){ float **a,*api,s,**x,*b,bpi; #include "solver/fb.c" }else if(siz(A) == sizeof(float) && siz(B) == sizeof(double)){ float **a,*api;double s,**x,*b,bpi; #include "solver/fb.c" }else if(siz(A) == sizeof(double) && siz(B) == sizeof(float)){ double **a,*api,s;float **x,*b,bpi; #include "solver/fb.c" }else if(siz(A) == sizeof(double) && siz(B) == sizeof(double)){ double **a,*api,s,**x,*b,bpi; #include "solver/fb.c" }else{ fprintf(stderr,"solver_gauss: not supported\n"); exit(1);} return 0; }
/* function invert */ static double invert(Matrix A,Vector x,double tol,int n,int *itr) { static Matrix L; static Matrix U; static Vector y; static Vector s; double c, d, xmin,lambda; int m, i; ary2(L,n+1,n+1); ary2(U,n+1,n+1); ary1(y,n+1); ary1(s,n+1); lu(A,L,U,tol,n); // AをLU分解する。結果はLとUに入れる for (m=1; m<=itr[0]; m++){ for (i=1; i<=n; i++) s[i]=x[i]; subs(L,U,s,y,tol,n); // LUy = s の解yを求める処理。 c=0; d=0; for (i=1; i<=n; i++){ c+=y[i]*x[i]; d+=y[i]*y[i]; } lambda =c/d; itr[1]=m; if (fabs(xmin-lambda)<tol){ return lambda; /* 収束した */ } xmin=lambda; for (i=1; i<=n; i++) x[i]=y[i]/sqrt(d); // xにyを正規化して代入 } itr[1]=m; return lambda; //Itr回では収束しなかった }
int main(int argc, char **argv) { static xyc *Z; static nde *N; static double **A, *u; initop(argc, argv); fp2mesh(stdfp(),Z,N); ary2(A,dim1(Z)+1, dim1(Z)+1); ary1(u,dim1(Z)+1); set_A(Z,N,A); set_u(Z,u); esolver(A,u); plt(NULL,NULL,Z,N,u); sleep(1000); return 0; }
int estiva_pcgssolver(void* pA, double* x, double* b) { /* (i) 引数の型と種類 */ D_ D, B ;/* D 一次元配列 D(N), B(N) */ D__ A ;/* D 二次元配列 A(N1, 2 * NL) */ I__ IA ;/* I 二次元配列 IA(N1, 2 * NL) */ D_ R ;/* D 一次元配列 R(N) */ long NL, N1, N, ITR, IER ; double EPS, S ; D_ X, DD, P, Q ;/* D 一次元配列で, 要素は 0〜N */ I_ M ;/* I 一次元配列 M(2 * N) 作業用 */ /*-- DからRまでと, EPSからSまでの引数は, サブルーチンPCGと同じ --*/ D_ R0, E, H ;/* D 一次元配列 要素数はN */ D_ W ;/* D 一次元配列 W(0:N) */ long i, j, k ; N = dim1(b) ; NL = count_NL(pA,N); ary1( D, N ) ; ary2( A, 2*NL, N+2*NL ); ary2( IA, 2*NL, N+2*NL ); ary1( R, N ) ; ary1( X, N+1 ) ; ary1( DD, N+1 ); ary1( P, N+1 ); ary1( Q, N+1 ); ary1( M, 2*N ) ; ary1( R0, N ) ; ary1( E, N ); ary1( H, N ); ary1( W, N+1 ) ; /* (ii) 主プログラム → サブルーチン */ /* サブルーチンをCALLするときには, つぎの値を与える. */ /* D : 配列Dの第1〜第n位置に行列Aの対角要素を入れておく */ /* N : 行列Aの行数を入れておく. */ /* N1 : 配列Aの行数を入れておく. N1≧N+2*NL でないといけない. */ /* NL : 行列Aの各行における非ゼロ要素数の最大値を入れておく. */ /* B : 連立一次方程式の右辺を入れておく. */ /* EPS : 収束判定置を入れておく. ふつうは 1.×10^(-7) */ /* ITR : 打切りまでの最大繰返し回数を入れておく. */ /*-- D, N, N1, NL, B, EPS, ITR については, サブルーチンPCGと同じ --*/ /* A : 配列Aの各行1〜NL要素は, 行列Aの下三角部分の各行の非ゼロ */ /* 要素を入れる. また, 各行のNL+1〜2*NL要素は, 上三角部分 */ /* の各行の非ゼロ要素を入れる. ただし, 各行の対角要素は配列Dに */ /* 入れる. */ /* IA : 配列Aに入れた要素の列番号を, 対応する位置に入れておく. */ /* S : LUCGS法のとき 0., MLUCG法のときσ(>0)を入れておく. */ for(i=1; i<=N; i++) D[i-1] = mx(pA,i,i); for(i=1; i<=N; i++)for(k=0, j=1; j<i; j++)if(mx(pA,i,j) != 0.0){ A[k][i-1] = mx(pA,i,j) ; IA[k][i-1] = j ; k++ ; } for(i=1; i<=N; i++)for(k=NL, j=i+1; j<=N; j++)if(mx(pA,i,j) != 0.0){ A[k][i-1] = mx(pA,i,j) ; IA[k][i-1] = j ; k++ ; } N1 = N+2*NL; B = &b[1] ; EPS = 1.0e-7 ; ITR = N ; S = 0. ; /* (a) リンクの方法 */ /* CALL PCGS(D,A,IA,N,N1,NL,B,EPS,ITR,S,X,DD,P,Q,R,R0,E,H,W,M,IER) */ pcgs(D,A[0],IA[0],&N,&N1,&NL,B,&EPS,&ITR, &S,X,DD,P,Q,R,R0,E,H,W,M,&IER); B = &x[1] ; for(i=0; i<N; i++) B[i] = X[i+1]; return IER; }