arnoldi.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /**************************************************************************
  2. **
  3. ** Copyright (C) 1993 David E. Steward & Zbigniew Leyk, all rights reserved.
  4. **
  5. ** Meschach Library
  6. **
  7. ** This Meschach Library is provided "as is" without any express
  8. ** or implied warranty of any kind with respect to this software.
  9. ** In particular the authors shall not be liable for any direct,
  10. ** indirect, special, incidental or consequential damages arising
  11. ** in any way from use of the software.
  12. **
  13. ** Everyone is granted permission to copy, modify and redistribute this
  14. ** Meschach Library, provided:
  15. ** 1. All copies contain this copyright notice.
  16. ** 2. All modified copies shall carry a notice stating who
  17. ** made the last modification and the date of such modification.
  18. ** 3. No charge is made for this software or works derived from it.
  19. ** This clause shall not be construed as constraining other software
  20. ** distributed on the same medium as this software, nor is a
  21. ** distribution fee considered a charge.
  22. **
  23. ***************************************************************************/
  24. /*
  25. Arnoldi method for finding eigenvalues of large non-symmetric
  26. matrices
  27. */
  28. #include <stdio.h>
  29. #include <math.h>
  30. #include "matrix.h"
  31. #include "matrix2.h"
  32. #include "sparse.h"
  33. static char rcsid[] = "$Id: arnoldi.c,v 1.3 1994/01/13 05:45:40 des Exp $";
  34. /* arnoldi -- an implementation of the Arnoldi method */
  35. MAT *arnoldi(A,A_param,x0,m,h_rem,Q,H)
  36. VEC *(*A)();
  37. void *A_param;
  38. VEC *x0;
  39. int m;
  40. Real *h_rem;
  41. MAT *Q, *H;
  42. {
  43. STATIC VEC *v=VNULL, *u=VNULL, *r=VNULL, *s=VNULL, *tmp=VNULL;
  44. int i;
  45. Real h_val;
  46. if ( ! A || ! Q || ! x0 )
  47. error(E_NULL,"arnoldi");
  48. if ( m <= 0 )
  49. error(E_BOUNDS,"arnoldi");
  50. if ( Q->n != x0->dim || Q->m != m )
  51. error(E_SIZES,"arnoldi");
  52. m_zero(Q);
  53. H = m_resize(H,m,m);
  54. m_zero(H);
  55. u = v_resize(u,x0->dim);
  56. v = v_resize(v,x0->dim);
  57. r = v_resize(r,m);
  58. s = v_resize(s,m);
  59. tmp = v_resize(tmp,x0->dim);
  60. MEM_STAT_REG(u,TYPE_VEC);
  61. MEM_STAT_REG(v,TYPE_VEC);
  62. MEM_STAT_REG(r,TYPE_VEC);
  63. MEM_STAT_REG(s,TYPE_VEC);
  64. MEM_STAT_REG(tmp,TYPE_VEC);
  65. sv_mlt(1.0/v_norm2(x0),x0,v);
  66. for ( i = 0; i < m; i++ )
  67. {
  68. set_row(Q,i,v);
  69. u = (*A)(A_param,v,u);
  70. r = mv_mlt(Q,u,r);
  71. tmp = vm_mlt(Q,r,tmp);
  72. v_sub(u,tmp,u);
  73. h_val = v_norm2(u);
  74. /* if u == 0 then we have an exact subspace */
  75. if ( h_val == 0.0 )
  76. {
  77. *h_rem = h_val;
  78. return H;
  79. }
  80. /* iterative refinement -- ensures near orthogonality */
  81. do {
  82. s = mv_mlt(Q,u,s);
  83. tmp = vm_mlt(Q,s,tmp);
  84. v_sub(u,tmp,u);
  85. v_add(r,s,r);
  86. } while ( v_norm2(s) > 0.1*(h_val = v_norm2(u)) );
  87. /* now that u is nearly orthogonal to Q, update H */
  88. set_col(H,i,r);
  89. if ( i == m-1 )
  90. {
  91. *h_rem = h_val;
  92. continue;
  93. }
  94. /* H->me[i+1][i] = h_val; */
  95. m_set_val(H,i+1,i,h_val);
  96. sv_mlt(1.0/h_val,u,v);
  97. }
  98. #ifdef THREADSAFE
  99. V_FREE(v); V_FREE(u); V_FREE(r);
  100. V_FREE(r); V_FREE(s); V_FREE(tmp);
  101. #endif
  102. return H;
  103. }
  104. /* sp_arnoldi -- uses arnoldi() with an explicit representation of A */
  105. MAT *sp_arnoldi(A,x0,m,h_rem,Q,H)
  106. SPMAT *A;
  107. VEC *x0;
  108. int m;
  109. Real *h_rem;
  110. MAT *Q, *H;
  111. { return arnoldi(sp_mv_mlt,A,x0,m,h_rem,Q,H); }
  112. /* gmres -- generalised minimum residual algorithm of Saad & Schultz
  113. SIAM J. Sci. Stat. Comp. v.7, pp.856--869 (1986)
  114. -- y is overwritten with the solution */
  115. VEC *gmres(A,A_param,m,Q,R,b,tol,x)
  116. VEC *(*A)();
  117. void *A_param;
  118. VEC *b, *x;
  119. int m;
  120. MAT *Q, *R;
  121. double tol;
  122. {
  123. STATIC VEC *v=VNULL, *u=VNULL, *r=VNULL, *tmp=VNULL, *rhs=VNULL;
  124. STATIC VEC *diag=VNULL, *beta=VNULL;
  125. int i;
  126. Real h_val, norm_b;
  127. if ( ! A || ! Q || ! b || ! R )
  128. error(E_NULL,"gmres");
  129. if ( m <= 0 )
  130. error(E_BOUNDS,"gmres");
  131. if ( Q->n != b->dim || Q->m != m )
  132. error(E_SIZES,"gmres");
  133. x = v_copy(b,x);
  134. m_zero(Q);
  135. R = m_resize(R,m+1,m);
  136. m_zero(R);
  137. u = v_resize(u,x->dim);
  138. v = v_resize(v,x->dim);
  139. tmp = v_resize(tmp,x->dim);
  140. rhs = v_resize(rhs,m+1);
  141. MEM_STAT_REG(u,TYPE_VEC);
  142. MEM_STAT_REG(v,TYPE_VEC);
  143. MEM_STAT_REG(r,TYPE_VEC);
  144. MEM_STAT_REG(tmp,TYPE_VEC);
  145. MEM_STAT_REG(rhs,TYPE_VEC);
  146. norm_b = v_norm2(x);
  147. if ( norm_b == 0.0 )
  148. error(E_RANGE,"gmres");
  149. sv_mlt(1.0/norm_b,x,v);
  150. for ( i = 0; i < m; i++ )
  151. {
  152. set_row(Q,i,v);
  153. tracecatch(u = (*A)(A_param,v,u),"gmres");
  154. r = mv_mlt(Q,u,r);
  155. tmp = vm_mlt(Q,r,tmp);
  156. v_sub(u,tmp,u);
  157. h_val = v_norm2(u);
  158. set_col(R,i,r);
  159. R->me[i+1][i] = h_val;
  160. sv_mlt(1.0/h_val,u,v);
  161. }
  162. /* use i x i submatrix of R */
  163. R = m_resize(R,i+1,i);
  164. rhs = v_resize(rhs,i+1);
  165. v_zero(rhs);
  166. rhs->ve[0] = norm_b;
  167. tmp = v_resize(tmp,i);
  168. diag = v_resize(diag,i+1);
  169. beta = v_resize(beta,i+1);
  170. MEM_STAT_REG(beta,TYPE_VEC);
  171. MEM_STAT_REG(diag,TYPE_VEC);
  172. QRfactor(R,diag /* ,beta */);
  173. tmp = QRsolve(R,diag, /* beta, */ rhs,tmp);
  174. v_resize(tmp,m);
  175. vm_mlt(Q,tmp,x);
  176. #ifdef THREADSAFE
  177. V_FREE(v); V_FREE(u); V_FREE(r);
  178. V_FREE(tmp); V_FREE(rhs);
  179. V_FREE(diag); V_FREE(beta);
  180. #endif
  181. return x;
  182. }