home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / mesch12a.zip / arnoldi.c next >
C/C++ Source or Header  |  1994-01-13  |  5KB  |  188 lines

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