eigens.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /* eigens.c
  2. *
  3. * Eigenvalues and eigenvectors of a real symmetric matrix
  4. *
  5. *
  6. *
  7. * SYNOPSIS:
  8. *
  9. * int n;
  10. * double A[n*(n+1)/2], EV[n*n], E[n];
  11. * void eigens( A, EV, E, n );
  12. *
  13. *
  14. *
  15. * DESCRIPTION:
  16. *
  17. * The algorithm is due to J. vonNeumann.
  18. *
  19. * A[] is a symmetric matrix stored in lower triangular form.
  20. * That is, A[ row, column ] = A[ (row*row+row)/2 + column ]
  21. * or equivalently with row and column interchanged. The
  22. * indices row and column run from 0 through n-1.
  23. *
  24. * EV[] is the output matrix of eigenvectors stored columnwise.
  25. * That is, the elements of each eigenvector appear in sequential
  26. * memory order. The jth element of the ith eigenvector is
  27. * EV[ n*i+j ] = EV[i][j].
  28. *
  29. * E[] is the output matrix of eigenvalues. The ith element
  30. * of E corresponds to the ith eigenvector (the ith row of EV).
  31. *
  32. * On output, the matrix A will have been diagonalized and its
  33. * orginal contents are destroyed.
  34. *
  35. * ACCURACY:
  36. *
  37. * The error is controlled by an internal parameter called RANGE
  38. * which is set to 1e-10. After diagonalization, the
  39. * off-diagonal elements of A will have been reduced by
  40. * this factor.
  41. *
  42. * ERROR MESSAGES:
  43. *
  44. * None.
  45. *
  46. */
  47. #include <math.h>
  48. #ifdef ANSIPROT
  49. extern double sqrt ( double );
  50. extern double fabs ( double );
  51. #else
  52. double sqrt(), fabs();
  53. #endif
  54. void eigens( A, RR, E, N )
  55. double A[], RR[], E[];
  56. int N;
  57. {
  58. int IND, L, LL, LM, M, MM, MQ, I, J, IA, LQ;
  59. int IQ, IM, IL, NLI, NMI;
  60. double ANORM, ANORMX, AIA, THR, ALM, ALL, AMM, X, Y;
  61. double SINX, SINX2, COSX, COSX2, SINCS, AIL, AIM;
  62. double RLI, RMI;
  63. static double RANGE = 1.0e-10; /*3.0517578e-5;*/
  64. /* Initialize identity matrix in RR[] */
  65. for( J=0; J<N*N; J++ )
  66. RR[J] = 0.0;
  67. MM = 0;
  68. for( J=0; J<N; J++ )
  69. {
  70. RR[MM + J] = 1.0;
  71. MM += N;
  72. }
  73. ANORM=0.0;
  74. for( I=0; I<N; I++ )
  75. {
  76. for( J=0; J<N; J++ )
  77. {
  78. if( I != J )
  79. {
  80. IA = I + (J*J+J)/2;
  81. AIA = A[IA];
  82. ANORM += AIA * AIA;
  83. }
  84. }
  85. }
  86. if( ANORM <= 0.0 )
  87. goto done;
  88. ANORM = sqrt( ANORM + ANORM );
  89. ANORMX = ANORM * RANGE / N;
  90. THR = ANORM;
  91. while( THR > ANORMX )
  92. {
  93. THR=THR/N;
  94. do
  95. { /* while IND != 0 */
  96. IND = 0;
  97. for( L=0; L<N-1; L++ )
  98. {
  99. for( M=L+1; M<N; M++ )
  100. {
  101. MQ=(M*M+M)/2;
  102. LM=L+MQ;
  103. ALM=A[LM];
  104. if( fabs(ALM) < THR )
  105. continue;
  106. IND=1;
  107. LQ=(L*L+L)/2;
  108. LL=L+LQ;
  109. MM=M+MQ;
  110. ALL=A[LL];
  111. AMM=A[MM];
  112. X=(ALL-AMM)/2.0;
  113. Y=-ALM/sqrt(ALM*ALM+X*X);
  114. if(X < 0.0)
  115. Y=-Y;
  116. SINX = Y / sqrt( 2.0 * (1.0 + sqrt( 1.0-Y*Y)) );
  117. SINX2=SINX*SINX;
  118. COSX=sqrt(1.0-SINX2);
  119. COSX2=COSX*COSX;
  120. SINCS=SINX*COSX;
  121. /* ROTATE L AND M COLUMNS */
  122. for( I=0; I<N; I++ )
  123. {
  124. IQ=(I*I+I)/2;
  125. if( (I != M) && (I != L) )
  126. {
  127. if(I > M)
  128. IM=M+IQ;
  129. else
  130. IM=I+MQ;
  131. if(I >= L)
  132. IL=L+IQ;
  133. else
  134. IL=I+LQ;
  135. AIL=A[IL];
  136. AIM=A[IM];
  137. X=AIL*COSX-AIM*SINX;
  138. A[IM]=AIL*SINX+AIM*COSX;
  139. A[IL]=X;
  140. }
  141. NLI = N*L + I;
  142. NMI = N*M + I;
  143. RLI = RR[ NLI ];
  144. RMI = RR[ NMI ];
  145. RR[NLI]=RLI*COSX-RMI*SINX;
  146. RR[NMI]=RLI*SINX+RMI*COSX;
  147. }
  148. X=2.0*ALM*SINCS;
  149. A[LL]=ALL*COSX2+AMM*SINX2-X;
  150. A[MM]=ALL*SINX2+AMM*COSX2+X;
  151. A[LM]=(ALL-AMM)*SINCS+ALM*(COSX2-SINX2);
  152. } /* for M=L+1 to N-1 */
  153. } /* for L=0 to N-2 */
  154. }
  155. while( IND != 0 );
  156. } /* while THR > ANORMX */
  157. done: ;
  158. /* Extract eigenvalues from the reduced matrix */
  159. L=0;
  160. for( J=1; J<=N; J++ )
  161. {
  162. L=L+J;
  163. E[J-1]=A[L-1];
  164. }
  165. }