symmeig.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  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. File containing routines for symmetric eigenvalue problems
  26. */
  27. #include <stdio.h>
  28. #include <math.h>
  29. #include "matrix.h"
  30. #include "matrix2.h"
  31. static char rcsid[] = "$Id: symmeig.c,v 1.6 1995/03/27 15:45:55 des Exp $";
  32. #define SQRT2 1.4142135623730949
  33. #define sgn(x) ( (x) >= 0 ? 1 : -1 )
  34. /* trieig -- finds eigenvalues of symmetric tridiagonal matrices
  35. -- matrix represented by a pair of vectors a (diag entries)
  36. and b (sub- & super-diag entries)
  37. -- eigenvalues in a on return */
  38. #ifndef ANSI_C
  39. VEC *trieig(a,b,Q)
  40. VEC *a, *b;
  41. MAT *Q;
  42. #else
  43. VEC *trieig(VEC *a, VEC *b, MAT *Q)
  44. #endif
  45. {
  46. int i, i_min, i_max, n, split;
  47. Real *a_ve, *b_ve;
  48. Real b_sqr, bk, ak1, bk1, ak2, bk2, z;
  49. Real c, c2, cs, s, s2, d, mu;
  50. if ( ! a || ! b )
  51. error(E_NULL,"trieig");
  52. if ( a->dim != b->dim + 1 || ( Q && Q->m != a->dim ) )
  53. error(E_SIZES,"trieig");
  54. if ( Q && Q->m != Q->n )
  55. error(E_SQUARE,"trieig");
  56. n = a->dim;
  57. a_ve = a->ve; b_ve = b->ve;
  58. i_min = 0;
  59. while ( i_min < n ) /* outer while loop */
  60. {
  61. /* find i_max to suit;
  62. submatrix i_min..i_max should be irreducible */
  63. i_max = n-1;
  64. for ( i = i_min; i < n-1; i++ )
  65. if ( b_ve[i] == 0.0 )
  66. { i_max = i; break; }
  67. if ( i_max <= i_min )
  68. {
  69. /* printf("# i_min = %d, i_max = %d\n",i_min,i_max); */
  70. i_min = i_max + 1;
  71. continue; /* outer while loop */
  72. }
  73. /* printf("# i_min = %d, i_max = %d\n",i_min,i_max); */
  74. /* repeatedly perform QR method until matrix splits */
  75. split = FALSE;
  76. while ( ! split ) /* inner while loop */
  77. {
  78. /* find Wilkinson shift */
  79. d = (a_ve[i_max-1] - a_ve[i_max])/2;
  80. b_sqr = b_ve[i_max-1]*b_ve[i_max-1];
  81. mu = a_ve[i_max] - b_sqr/(d + sgn(d)*sqrt(d*d+b_sqr));
  82. /* printf("# Wilkinson shift = %g\n",mu); */
  83. /* initial Givens' rotation */
  84. givens(a_ve[i_min]-mu,b_ve[i_min],&c,&s);
  85. s = -s;
  86. /* printf("# c = %g, s = %g\n",c,s); */
  87. if ( fabs(c) < SQRT2 )
  88. { c2 = c*c; s2 = 1-c2; }
  89. else
  90. { s2 = s*s; c2 = 1-s2; }
  91. cs = c*s;
  92. ak1 = c2*a_ve[i_min]+s2*a_ve[i_min+1]-2*cs*b_ve[i_min];
  93. bk1 = cs*(a_ve[i_min]-a_ve[i_min+1]) +
  94. (c2-s2)*b_ve[i_min];
  95. ak2 = s2*a_ve[i_min]+c2*a_ve[i_min+1]+2*cs*b_ve[i_min];
  96. bk2 = ( i_min < i_max-1 ) ? c*b_ve[i_min+1] : 0.0;
  97. z = ( i_min < i_max-1 ) ? -s*b_ve[i_min+1] : 0.0;
  98. a_ve[i_min] = ak1;
  99. a_ve[i_min+1] = ak2;
  100. b_ve[i_min] = bk1;
  101. if ( i_min < i_max-1 )
  102. b_ve[i_min+1] = bk2;
  103. if ( Q )
  104. rot_cols(Q,i_min,i_min+1,c,-s,Q);
  105. /* printf("# z = %g\n",z); */
  106. /* printf("# a [temp1] =\n"); v_output(a); */
  107. /* printf("# b [temp1] =\n"); v_output(b); */
  108. for ( i = i_min+1; i < i_max; i++ )
  109. {
  110. /* get Givens' rotation for sub-block -- k == i-1 */
  111. givens(b_ve[i-1],z,&c,&s);
  112. s = -s;
  113. /* printf("# c = %g, s = %g\n",c,s); */
  114. /* perform Givens' rotation on sub-block */
  115. if ( fabs(c) < SQRT2 )
  116. { c2 = c*c; s2 = 1-c2; }
  117. else
  118. { s2 = s*s; c2 = 1-s2; }
  119. cs = c*s;
  120. bk = c*b_ve[i-1] - s*z;
  121. ak1 = c2*a_ve[i]+s2*a_ve[i+1]-2*cs*b_ve[i];
  122. bk1 = cs*(a_ve[i]-a_ve[i+1]) +
  123. (c2-s2)*b_ve[i];
  124. ak2 = s2*a_ve[i]+c2*a_ve[i+1]+2*cs*b_ve[i];
  125. bk2 = ( i+1 < i_max ) ? c*b_ve[i+1] : 0.0;
  126. z = ( i+1 < i_max ) ? -s*b_ve[i+1] : 0.0;
  127. a_ve[i] = ak1; a_ve[i+1] = ak2;
  128. b_ve[i] = bk1;
  129. if ( i < i_max-1 )
  130. b_ve[i+1] = bk2;
  131. if ( i > i_min )
  132. b_ve[i-1] = bk;
  133. if ( Q )
  134. rot_cols(Q,i,i+1,c,-s,Q);
  135. /* printf("# a [temp2] =\n"); v_output(a); */
  136. /* printf("# b [temp2] =\n"); v_output(b); */
  137. }
  138. /* test to see if matrix should be split */
  139. for ( i = i_min; i < i_max; i++ )
  140. if ( fabs(b_ve[i]) < MACHEPS*
  141. (fabs(a_ve[i])+fabs(a_ve[i+1])) )
  142. { b_ve[i] = 0.0; split = TRUE; }
  143. /* printf("# a =\n"); v_output(a); */
  144. /* printf("# b =\n"); v_output(b); */
  145. }
  146. }
  147. return a;
  148. }
  149. /* symmeig -- computes eigenvalues of a dense symmetric matrix
  150. -- A **must** be symmetric on entry
  151. -- eigenvalues stored in out
  152. -- Q contains orthogonal matrix of eigenvectors
  153. -- returns vector of eigenvalues */
  154. #ifndef ANSI_C
  155. VEC *symmeig(A,Q,out)
  156. MAT *A, *Q;
  157. VEC *out;
  158. #else
  159. VEC *symmeig(const MAT *A, MAT *Q, VEC *out)
  160. #endif
  161. {
  162. int i;
  163. STATIC MAT *tmp = MNULL;
  164. STATIC VEC *b = VNULL, *diag = VNULL, *beta = VNULL;
  165. if ( ! A )
  166. error(E_NULL,"symmeig");
  167. if ( A->m != A->n )
  168. error(E_SQUARE,"symmeig");
  169. if ( ! out || out->dim != A->m )
  170. out = v_resize(out,A->m);
  171. tmp = m_resize(tmp,A->m,A->n);
  172. tmp = m_copy(A,tmp);
  173. b = v_resize(b,A->m - 1);
  174. diag = v_resize(diag,(unsigned int)A->m);
  175. beta = v_resize(beta,(unsigned int)A->m);
  176. MEM_STAT_REG(tmp,TYPE_MAT);
  177. MEM_STAT_REG(b,TYPE_VEC);
  178. MEM_STAT_REG(diag,TYPE_VEC);
  179. MEM_STAT_REG(beta,TYPE_VEC);
  180. Hfactor(tmp,diag,beta);
  181. if ( Q )
  182. makeHQ(tmp,diag,beta,Q);
  183. for ( i = 0; i < A->m - 1; i++ )
  184. {
  185. out->ve[i] = tmp->me[i][i];
  186. b->ve[i] = tmp->me[i][i+1];
  187. }
  188. out->ve[i] = tmp->me[i][i];
  189. trieig(out,b,Q);
  190. #ifdef THREADSAFE
  191. M_FREE(tmp); V_FREE(b); V_FREE(diag); V_FREE(beta);
  192. #endif
  193. return out;
  194. }